Merge changes from topic "nat64"
* changes:
Catch ServiceSpecificException instead of IllegalStateException.
Manage NAT64 prefix discovery lifecycle in the framework.
Track NAT64 in the framework and start clatd iff NAT64 detected
Change Nat464Xlat lifecycle.
Minor improvements to verifyTcpBufferSizeChange.
diff --git a/core/java/android/net/NetworkMisc.java b/core/java/android/net/NetworkMisc.java
index daa2640..c0487b5 100644
--- a/core/java/android/net/NetworkMisc.java
+++ b/core/java/android/net/NetworkMisc.java
@@ -46,7 +46,7 @@
/**
* Set if the user desires to use this network even if it is unvalidated. This field has meaning
- * only if {#link explicitlySelected} is true. If it is, this field must also be set to the
+ * only if {@link explicitlySelected} is true. If it is, this field must also be set to the
* appropriate value based on previous user choice.
*/
public boolean acceptUnvalidated;
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 6efa5c1..446d186 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -2381,6 +2381,11 @@
pw.decreaseIndent();
}
+
+ pw.println();
+ pw.println("NetworkStackClient logs:");
+ pw.increaseIndent();
+ NetworkStackClient.getInstance().dump(pw);
}
private void dumpNetworks(IndentingPrintWriter pw) {
diff --git a/services/core/java/com/android/server/connectivity/PermissionMonitor.java b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
index 420b23e..d84a4d2 100644
--- a/services/core/java/com/android/server/connectivity/PermissionMonitor.java
+++ b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
@@ -19,10 +19,11 @@
import static android.Manifest.permission.CHANGE_NETWORK_STATE;
import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS;
+import static android.Manifest.permission.INTERNET;
import static android.Manifest.permission.NETWORK_STACK;
-import static android.content.pm.ApplicationInfo.FLAG_SYSTEM;
-import static android.content.pm.ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
+import static android.Manifest.permission.UPDATE_DEVICE_STATS;
import static android.content.pm.PackageManager.GET_PERMISSIONS;
+import static android.content.pm.PackageManager.MATCH_ANY_USER;
import static android.os.Process.INVALID_UID;
import static android.os.Process.SYSTEM_UID;
@@ -32,23 +33,31 @@
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.PackageManagerInternal;
import android.content.pm.UserInfo;
-import android.net.Uri;
+import android.net.INetd;
+import android.net.util.NetdService;
import android.os.Build;
import android.os.INetworkManagementService;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.Log;
+import android.util.Slog;
+import android.util.SparseIntArray;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.ArrayUtils;
+import com.android.server.LocalServices;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
-import java.util.Map.Entry;
import java.util.Map;
+import java.util.Map.Entry;
import java.util.Set;
/**
@@ -75,6 +84,59 @@
// Keys are App IDs. Values are true for SYSTEM permission and false for NETWORK permission.
private final Map<Integer, Boolean> mApps = new HashMap<>();
+ // Keys are App packageNames, Values are app uids. . We need to keep track of this information
+ // because PackageListObserver#onPackageRemoved does not pass the UID.
+ @GuardedBy("mPackageNameUidMap")
+ private final Map<String, Integer> mPackageNameUidMap = new HashMap<>();
+
+ private class PackageListObserver implements PackageManagerInternal.PackageListObserver {
+ @Override
+ public void onPackageAdded(String packageName) {
+ final PackageInfo app = getPackageInfo(packageName);
+ if (app == null) {
+ Slog.wtf(TAG, "Failed to get information of installed package: " + packageName);
+ return;
+ }
+ int uid = (app.applicationInfo != null) ? app.applicationInfo.uid : INVALID_UID;
+ if (uid == INVALID_UID) {
+ Slog.wtf(TAG, "Failed to get the uid of installed package: " + packageName
+ + "uid: " + uid);
+ return;
+ }
+ if (app.requestedPermissions == null) {
+ return;
+ }
+ sendPackagePermissionsForUid(uid,
+ filterPermission(Arrays.asList(app.requestedPermissions)));
+ synchronized (mPackageNameUidMap) {
+ mPackageNameUidMap.put(packageName, uid);
+ }
+ }
+
+ @Override
+ public void onPackageRemoved(String packageName) {
+ int uid;
+ synchronized (mPackageNameUidMap) {
+ if (!mPackageNameUidMap.containsKey(packageName)) {
+ return;
+ }
+ uid = mPackageNameUidMap.get(packageName);
+ mPackageNameUidMap.remove(packageName);
+ }
+ int permission = 0;
+ String[] packages = mPackageManager.getPackagesForUid(uid);
+ if (packages != null && packages.length > 0) {
+ for (String name : packages) {
+ final PackageInfo app = getPackageInfo(name);
+ if (app != null && app.requestedPermissions != null) {
+ permission |= filterPermission(Arrays.asList(app.requestedPermissions));
+ }
+ }
+ }
+ sendPackagePermissionsForUid(uid, permission);
+ }
+ }
+
public PermissionMonitor(Context context, INetworkManagementService netd) {
mContext = context;
mPackageManager = context.getPackageManager();
@@ -87,12 +149,21 @@
public synchronized void startMonitoring() {
log("Monitoring");
- List<PackageInfo> apps = mPackageManager.getInstalledPackages(GET_PERMISSIONS);
+ PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
+ if (pmi != null) {
+ pmi.getPackageList(new PackageListObserver());
+ } else {
+ loge("failed to get the PackageManagerInternal service");
+ }
+ List<PackageInfo> apps = mPackageManager.getInstalledPackages(GET_PERMISSIONS
+ | MATCH_ANY_USER);
if (apps == null) {
loge("No apps");
return;
}
+ SparseIntArray netdPermsUids = new SparseIntArray();
+
for (PackageInfo app : apps) {
int uid = app.applicationInfo != null ? app.applicationInfo.uid : INVALID_UID;
if (uid < 0) {
@@ -110,6 +181,17 @@
mApps.put(uid, hasRestrictedPermission);
}
}
+
+ //TODO: unify the management of the permissions into one codepath.
+ if (app.requestedPermissions != null) {
+ int otherNetdPerms = filterPermission(Arrays.asList(app.requestedPermissions));
+ if (otherNetdPerms != 0) {
+ netdPermsUids.put(uid, netdPermsUids.get(uid) | otherNetdPerms);
+ synchronized (mPackageNameUidMap) {
+ mPackageNameUidMap.put(app.applicationInfo.packageName, uid);
+ }
+ }
+ }
}
List<UserInfo> users = mUserManager.getUsers(true); // exclude dying users
@@ -121,6 +203,7 @@
log("Users: " + mUsers.size() + ", Apps: " + mApps.size());
update(mUsers, mApps, true);
+ sendPackagePermissionsToNetd(netdPermsUids);
}
@VisibleForTesting
@@ -339,6 +422,107 @@
}
}
+ private static int filterPermission(List<String> requestedPermissions) {
+ int permissions = 0;
+ if (requestedPermissions.contains(INTERNET)) {
+ permissions |= INetd.PERMISSION_INTERNET;
+ }
+ if (requestedPermissions.contains(UPDATE_DEVICE_STATS)) {
+ permissions |= INetd.PERMISSION_UPDATE_DEVICE_STATS;
+ }
+ return permissions;
+ }
+
+ private PackageInfo getPackageInfo(String packageName) {
+ try {
+ PackageInfo app = mPackageManager.getPackageInfo(packageName, GET_PERMISSIONS
+ | MATCH_ANY_USER);
+ return app;
+ } catch (NameNotFoundException e) {
+ // App not found.
+ loge("NameNotFoundException " + packageName);
+ return null;
+ }
+ }
+
+ /**
+ * Called by PackageListObserver when a package is installed/uninstalled. Send the updated
+ * permission information to netd.
+ *
+ * @param uid the app uid of the package installed
+ * @param permissions the permissions the app requested and netd cares about.
+ *
+ * @hide
+ */
+ private void sendPackagePermissionsForUid(int uid, int permissions) {
+ SparseIntArray netdPermissionsAppIds = new SparseIntArray();
+ netdPermissionsAppIds.put(uid, permissions);
+ sendPackagePermissionsToNetd(netdPermissionsAppIds);
+ }
+
+ /**
+ * Called by packageManagerService to send IPC to netd. Grant or revoke the INTERNET
+ * and/or UPDATE_DEVICE_STATS permission of the uids in array.
+ *
+ * @param netdPermissionsAppIds integer pairs of uids and the permission granted to it. If the
+ * permission is 0, revoke all permissions of that uid.
+ *
+ * @hide
+ */
+ private void sendPackagePermissionsToNetd(SparseIntArray netdPermissionsAppIds) {
+ INetd netdService = NetdService.getInstance();
+ if (netdService == null) {
+ Log.e(TAG, "Failed to get the netd service");
+ return;
+ }
+ ArrayList<Integer> allPermissionAppIds = new ArrayList<>();
+ ArrayList<Integer> internetPermissionAppIds = new ArrayList<>();
+ ArrayList<Integer> updateStatsPermissionAppIds = new ArrayList<>();
+ ArrayList<Integer> uninstalledAppIds = new ArrayList<>();
+ for (int i = 0; i < netdPermissionsAppIds.size(); i++) {
+ int permissions = netdPermissionsAppIds.valueAt(i);
+ switch(permissions) {
+ case (INetd.PERMISSION_INTERNET | INetd.PERMISSION_UPDATE_DEVICE_STATS):
+ allPermissionAppIds.add(netdPermissionsAppIds.keyAt(i));
+ break;
+ case INetd.PERMISSION_INTERNET:
+ internetPermissionAppIds.add(netdPermissionsAppIds.keyAt(i));
+ break;
+ case INetd.PERMISSION_UPDATE_DEVICE_STATS:
+ updateStatsPermissionAppIds.add(netdPermissionsAppIds.keyAt(i));
+ break;
+ case INetd.NO_PERMISSIONS:
+ uninstalledAppIds.add(netdPermissionsAppIds.keyAt(i));
+ break;
+ default:
+ Log.e(TAG, "unknown permission type: " + permissions + "for uid: "
+ + netdPermissionsAppIds.keyAt(i));
+ }
+ }
+ try {
+ // TODO: add a lock inside netd to protect IPC trafficSetNetPermForUids()
+ if (allPermissionAppIds.size() != 0) {
+ netdService.trafficSetNetPermForUids(
+ INetd.PERMISSION_INTERNET | INetd.PERMISSION_UPDATE_DEVICE_STATS,
+ ArrayUtils.convertToIntArray(allPermissionAppIds));
+ }
+ if (internetPermissionAppIds.size() != 0) {
+ netdService.trafficSetNetPermForUids(INetd.PERMISSION_INTERNET,
+ ArrayUtils.convertToIntArray(internetPermissionAppIds));
+ }
+ if (updateStatsPermissionAppIds.size() != 0) {
+ netdService.trafficSetNetPermForUids(INetd.PERMISSION_UPDATE_DEVICE_STATS,
+ ArrayUtils.convertToIntArray(updateStatsPermissionAppIds));
+ }
+ if (uninstalledAppIds.size() != 0) {
+ netdService.trafficSetNetPermForUids(INetd.NO_PERMISSIONS,
+ ArrayUtils.convertToIntArray(uninstalledAppIds));
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Pass appId list of special permission failed." + e);
+ }
+ }
+
private static void log(String s) {
if (DBG) {
Log.d(TAG, s);
diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java
index f169d6b..b5d1ff9 100644
--- a/tests/net/java/com/android/server/connectivity/VpnTest.java
+++ b/tests/net/java/com/android/server/connectivity/VpnTest.java
@@ -28,6 +28,7 @@
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkCapabilities.TRANSPORT_VPN;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
+import static android.net.RouteInfo.RTN_UNREACHABLE;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -89,6 +90,7 @@
import org.mockito.MockitoAnnotations;
import java.net.Inet4Address;
+import java.net.Inet6Address;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Arrays;
@@ -775,6 +777,16 @@
// V4 does not, but V6 has sufficient coverage again
lp.addRoute(new RouteInfo(new IpPrefix("::/1")));
assertTrue(Vpn.providesRoutesToMostDestinations(lp));
+
+ lp.clear();
+ // V4-unreachable route should not be treated as sufficient coverage
+ lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), RTN_UNREACHABLE));
+ assertFalse(Vpn.providesRoutesToMostDestinations(lp));
+
+ lp.clear();
+ // V6-unreachable route should not be treated as sufficient coverage
+ lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), RTN_UNREACHABLE));
+ assertFalse(Vpn.providesRoutesToMostDestinations(lp));
}
@Test