Merge "Remove ForceAllNetworkTypes from test"
diff --git a/framework/src/android/net/ConnectivityManager.java b/framework/src/android/net/ConnectivityManager.java
index eecd12c..7294ec9 100644
--- a/framework/src/android/net/ConnectivityManager.java
+++ b/framework/src/android/net/ConnectivityManager.java
@@ -2369,7 +2369,7 @@
             throw new IllegalArgumentException("Listener was not registered.");
         }
         try {
-            mService.registerNetworkActivityListener(rl);
+            mService.unregisterNetworkActivityListener(rl);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/framework/src/android/net/NetworkCapabilities.java b/framework/src/android/net/NetworkCapabilities.java
index 447f626..17fc3b4 100644
--- a/framework/src/android/net/NetworkCapabilities.java
+++ b/framework/src/android/net/NetworkCapabilities.java
@@ -852,7 +852,7 @@
             // SubIds are only allowed for Test Networks that only declare TRANSPORT_TEST.
             setSubscriptionIds(originalSubIds);
         } else {
-            // If the test transport is restricted, then it may declare any transport.
+            // If the test network is restricted, then it may declare any transport.
             mTransportTypes = (originalTransportTypes | (1 << TRANSPORT_TEST));
         }
         mNetworkCapabilities = originalCapabilities & TEST_NETWORKS_ALLOWED_CAPABILITIES;
diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java
index 1d5d8af..9f63191 100644
--- a/service/src/com/android/server/ConnectivityService.java
+++ b/service/src/com/android/server/ConnectivityService.java
@@ -2311,9 +2311,7 @@
         final ArrayList<NetworkStateSnapshot> result = new ArrayList<>();
         for (Network network : getAllNetworks()) {
             final NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network);
-            // TODO: Consider include SUSPENDED networks, which should be considered as
-            //  temporary shortage of connectivity of a connected network.
-            if (nai != null && nai.networkInfo.isConnected()) {
+            if (nai != null && nai.everConnected) {
                 // TODO (b/73321673) : NetworkStateSnapshot contains a copy of the
                 // NetworkCapabilities, which may contain UIDs of apps to which the
                 // network applies. Should the UIDs be cleared so as not to leak or
diff --git a/service/src/com/android/server/connectivity/PermissionMonitor.java b/service/src/com/android/server/connectivity/PermissionMonitor.java
index 7c0fb91..f596c4a 100755
--- a/service/src/com/android/server/connectivity/PermissionMonitor.java
+++ b/service/src/com/android/server/connectivity/PermissionMonitor.java
@@ -74,11 +74,10 @@
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
-import java.util.Map.Entry;
 import java.util.Set;
 
 /**
- * A utility class to inform Netd of UID permisisons.
+ * A utility class to inform Netd of UID permissions.
  * Does a mass update at boot and then monitors for app install/remove.
  *
  * @hide
@@ -86,8 +85,6 @@
 public class PermissionMonitor {
     private static final String TAG = "PermissionMonitor";
     private static final boolean DBG = true;
-    protected static final Boolean SYSTEM = Boolean.TRUE;
-    protected static final Boolean NETWORK = Boolean.FALSE;
     private static final int VERSION_Q = Build.VERSION_CODES.Q;
 
     private final PackageManager mPackageManager;
@@ -100,9 +97,9 @@
     @GuardedBy("this")
     private final Set<UserHandle> mUsers = new HashSet<>();
 
-    // Keys are app uids. Values are true for SYSTEM permission and false for NETWORK permission.
+    // Keys are appIds. Values are true for SYSTEM permission and false for NETWORK permission.
     @GuardedBy("this")
-    private final Map<Integer, Boolean> mApps = new HashMap<>();
+    private final SparseIntArray mApps = new SparseIntArray();
 
     // Keys are active non-bypassable and fully-routed VPN's interface name, Values are uid ranges
     // for apps under the VPN
@@ -194,6 +191,23 @@
         mContext = context;
     }
 
+    private int getPackageNetdNetworkPermission(@NonNull final PackageInfo app) {
+        if (hasRestrictedNetworkPermission(app)) {
+            return PERMISSION_SYSTEM;
+        }
+        if (hasNetworkPermission(app)) {
+            return PERMISSION_NETWORK;
+        }
+        return PERMISSION_NONE;
+    }
+
+    static boolean isHigherNetworkPermission(final int targetPermission,
+            final int currentPermission) {
+        // This is relied on strict order of network permissions (SYSTEM > NETWORK > NONE), and it
+        // is enforced in tests.
+        return targetPermission > currentPermission;
+    }
+
     // Intended to be called only once at startup, after the system is ready. Installs a broadcast
     // receiver to monitor ongoing UID changes, so this shouldn't/needn't be called again.
     public synchronized void startMonitoring() {
@@ -237,31 +251,25 @@
             return;
         }
 
-        SparseIntArray netdPermsUids = new SparseIntArray();
+        final SparseIntArray netdPermsAppIds = new SparseIntArray();
 
         for (PackageInfo app : apps) {
             int uid = app.applicationInfo != null ? app.applicationInfo.uid : INVALID_UID;
             if (uid < 0) {
                 continue;
             }
-            mAllApps.add(UserHandle.getAppId(uid));
+            final int appId = UserHandle.getAppId(uid);
+            mAllApps.add(appId);
 
-            boolean isNetwork = hasNetworkPermission(app);
-            boolean hasRestrictedPermission = hasRestrictedNetworkPermission(app);
-
-            if (isNetwork || hasRestrictedPermission) {
-                Boolean permission = mApps.get(UserHandle.getAppId(uid));
-                // If multiple packages share a UID (cf: android:sharedUserId) and ask for different
-                // permissions, don't downgrade (i.e., if it's already SYSTEM, leave it as is).
-                if (permission == null || permission == NETWORK) {
-                    mApps.put(UserHandle.getAppId(uid), hasRestrictedPermission);
-                }
+            final int permission = getPackageNetdNetworkPermission(app);
+            if (isHigherNetworkPermission(permission, mApps.get(appId, PERMISSION_NONE))) {
+                mApps.put(appId, permission);
             }
 
             //TODO: unify the management of the permissions into one codepath.
             int otherNetdPerms = getNetdPermissionMask(app.requestedPermissions,
                     app.requestedPermissionsFlags);
-            netdPermsUids.put(uid, netdPermsUids.get(uid) | otherNetdPerms);
+            netdPermsAppIds.put(appId, netdPermsAppIds.get(appId) | otherNetdPerms);
         }
 
         mUsers.addAll(mUserManager.getUserHandles(true /* excludeDying */));
@@ -275,13 +283,13 @@
             final int[] hasPermissionUids =
                     mSystemConfigManager.getSystemPermissionUids(systemPermission);
             for (int j = 0; j < hasPermissionUids.length; j++) {
-                final int uid = hasPermissionUids[j];
-                netdPermsUids.put(uid, netdPermsUids.get(uid) | netdPermission);
+                final int appId = UserHandle.getAppId(hasPermissionUids[j]);
+                netdPermsAppIds.put(appId, netdPermsAppIds.get(appId) | netdPermission);
             }
         }
         log("Users: " + mUsers.size() + ", Apps: " + mApps.size());
         update(mUsers, mApps, true);
-        sendPackagePermissionsToNetd(netdPermsUids);
+        sendPackagePermissionsToNetd(netdPermsAppIds);
     }
 
     @VisibleForTesting
@@ -352,25 +360,29 @@
         // networks. mApps contains the result of checks for both hasNetworkPermission and
         // hasRestrictedNetworkPermission. If uid is in the mApps list that means uid has one of
         // permissions at least.
-        return mApps.containsKey(UserHandle.getAppId(uid));
+        return mApps.get(UserHandle.getAppId(uid), PERMISSION_NONE) != PERMISSION_NONE;
     }
 
     /**
      * Returns whether the given uid has permission to use restricted networks.
      */
     public synchronized boolean hasRestrictedNetworksPermission(int uid) {
-        return Boolean.TRUE.equals(mApps.get(UserHandle.getAppId(uid)));
+        return PERMISSION_SYSTEM == mApps.get(UserHandle.getAppId(uid), PERMISSION_NONE);
     }
 
-    private void update(Set<UserHandle> users, Map<Integer, Boolean> apps, boolean add) {
+    private void update(Set<UserHandle> users, SparseIntArray apps, boolean add) {
         List<Integer> network = new ArrayList<>();
         List<Integer> system = new ArrayList<>();
-        for (Entry<Integer, Boolean> app : apps.entrySet()) {
-            List<Integer> list = app.getValue() ? system : network;
+        for (int i = 0; i < apps.size(); i++) {
+            final int permission = apps.valueAt(i);
+            if (PERMISSION_NONE == permission) {
+                continue; // Normally NONE is not stored in this map, but just in case
+            }
+            List<Integer> list = (PERMISSION_SYSTEM == permission) ? system : network;
             for (UserHandle user : users) {
                 if (user == null) continue;
 
-                list.add(user.getUid(app.getKey()));
+                list.add(user.getUid(apps.keyAt(i)));
             }
         }
         try {
@@ -395,10 +407,7 @@
      */
     public synchronized void onUserAdded(@NonNull UserHandle user) {
         mUsers.add(user);
-
-        Set<UserHandle> users = new HashSet<>();
-        users.add(user);
-        update(users, mApps, true);
+        update(Set.of(user), mApps, true);
     }
 
     /**
@@ -410,10 +419,7 @@
      */
     public synchronized void onUserRemoved(@NonNull UserHandle user) {
         mUsers.remove(user);
-
-        Set<UserHandle> users = new HashSet<>();
-        users.add(user);
-        update(users, mApps, false);
+        update(Set.of(user), mApps, false);
     }
 
     /**
@@ -425,17 +431,16 @@
      *             permission.
      */
     @VisibleForTesting
-    protected Boolean highestPermissionForUid(Boolean currentPermission, String name) {
-        if (currentPermission == SYSTEM) {
+    protected int highestPermissionForUid(int currentPermission, String name) {
+        if (currentPermission == PERMISSION_SYSTEM) {
             return currentPermission;
         }
         try {
             final PackageInfo app = mPackageManager.getPackageInfo(name,
                     GET_PERMISSIONS | MATCH_ANY_USER);
-            final boolean isNetwork = hasNetworkPermission(app);
-            final boolean hasRestrictedPermission = hasRestrictedNetworkPermission(app);
-            if (isNetwork || hasRestrictedPermission) {
-                currentPermission = hasRestrictedPermission;
+            final int permission = getPackageNetdNetworkPermission(app);
+            if (isHigherNetworkPermission(permission, currentPermission)) {
+                return permission;
             }
         } catch (NameNotFoundException e) {
             // App not found.
@@ -464,6 +469,17 @@
         return permission;
     }
 
+    private synchronized void updateVpnUid(int uid, boolean add) {
+        for (Map.Entry<String, Set<UidRange>> vpn : mVpnUidRanges.entrySet()) {
+            if (UidRange.containsUid(vpn.getValue(), uid)) {
+                final Set<Integer> changedUids = new HashSet<>();
+                changedUids.add(uid);
+                removeBypassingUids(changedUids, -1 /* vpnAppUid */);
+                updateVpnUidsInterfaceRules(vpn.getKey(), changedUids, add);
+            }
+        }
+    }
+
     /**
      * Called when a package is added.
      *
@@ -473,45 +489,37 @@
      * @hide
      */
     public synchronized void onPackageAdded(@NonNull final String packageName, final int uid) {
-        // TODO: Netd is using appId for checking traffic permission. Correct the methods that are
-        //  using appId instead of uid actually
-        sendPackagePermissionsForUid(UserHandle.getAppId(uid), getPermissionForUid(uid));
+        final int appId = UserHandle.getAppId(uid);
+        sendPackagePermissionsForAppId(appId, getPermissionForUid(uid));
 
         // If multiple packages share a UID (cf: android:sharedUserId) and ask for different
         // permissions, don't downgrade (i.e., if it's already SYSTEM, leave it as is).
-        final int appId = UserHandle.getAppId(uid);
-        final Boolean permission = highestPermissionForUid(mApps.get(appId), packageName);
-        if (permission != mApps.get(appId)) {
+        final int currentPermission = mApps.get(appId, PERMISSION_NONE);
+        final int permission = highestPermissionForUid(currentPermission, packageName);
+        if (permission != currentPermission) {
             mApps.put(appId, permission);
 
-            Map<Integer, Boolean> apps = new HashMap<>();
+            SparseIntArray apps = new SparseIntArray();
             apps.put(appId, permission);
             update(mUsers, apps, true);
         }
 
         // If the newly-installed package falls within some VPN's uid range, update Netd with it.
-        // This needs to happen after the mApps update above, since removeBypassingUids() depends
-        // on mApps to check if the package can bypass VPN.
-        for (Map.Entry<String, Set<UidRange>> vpn : mVpnUidRanges.entrySet()) {
-            if (UidRange.containsUid(vpn.getValue(), uid)) {
-                final Set<Integer> changedUids = new HashSet<>();
-                changedUids.add(uid);
-                removeBypassingUids(changedUids, /* vpnAppUid */ -1);
-                updateVpnUids(vpn.getKey(), changedUids, true);
-            }
-        }
+        // This needs to happen after the mApps update above, since removeBypassingUids() in
+        // updateVpnUid() depends on mApps to check if the package can bypass VPN.
+        updateVpnUid(uid, true /* add */);
         mAllApps.add(appId);
     }
 
-    private Boolean highestUidNetworkPermission(int uid) {
-        Boolean permission = null;
+    private int highestUidNetworkPermission(int uid) {
+        int permission = PERMISSION_NONE;
         final String[] packages = mPackageManager.getPackagesForUid(uid);
         if (!CollectionUtils.isEmpty(packages)) {
             for (String name : packages) {
                 // If multiple packages have the same UID, give the UID all permissions that
                 // any package in that UID has.
                 permission = highestPermissionForUid(permission, name);
-                if (permission == SYSTEM) {
+                if (permission == PERMISSION_SYSTEM) {
                     break;
                 }
             }
@@ -528,46 +536,36 @@
      * @hide
      */
     public synchronized void onPackageRemoved(@NonNull final String packageName, final int uid) {
-        // TODO: Netd is using appId for checking traffic permission. Correct the methods that are
-        //  using appId instead of uid actually
-        sendPackagePermissionsForUid(UserHandle.getAppId(uid), getPermissionForUid(uid));
+        final int appId = UserHandle.getAppId(uid);
+        sendPackagePermissionsForAppId(appId, getPermissionForUid(uid));
 
         // If the newly-removed package falls within some VPN's uid range, update Netd with it.
-        // This needs to happen before the mApps update below, since removeBypassingUids() depends
-        // on mApps to check if the package can bypass VPN.
-        for (Map.Entry<String, Set<UidRange>> vpn : mVpnUidRanges.entrySet()) {
-            if (UidRange.containsUid(vpn.getValue(), uid)) {
-                final Set<Integer> changedUids = new HashSet<>();
-                changedUids.add(uid);
-                removeBypassingUids(changedUids, /* vpnAppUid */ -1);
-                updateVpnUids(vpn.getKey(), changedUids, false);
-            }
-        }
+        // This needs to happen before the mApps update below, since removeBypassingUids() in
+        // updateVpnUid() depends on mApps to check if the package can bypass VPN.
+        updateVpnUid(uid, false /* add */);
         // If the package has been removed from all users on the device, clear it form mAllApps.
         if (mPackageManager.getNameForUid(uid) == null) {
-            mAllApps.remove(UserHandle.getAppId(uid));
+            mAllApps.remove(appId);
         }
 
-        Map<Integer, Boolean> apps = new HashMap<>();
-        final Boolean permission = highestUidNetworkPermission(uid);
-        if (permission == SYSTEM) {
+        final int permission = highestUidNetworkPermission(uid);
+        if (permission == PERMISSION_SYSTEM) {
             // An app with this UID still has the SYSTEM permission.
             // Therefore, this UID must already have the SYSTEM permission.
             // Nothing to do.
             return;
         }
+        // If the permissions of this UID have not changed, do nothing.
+        if (permission == mApps.get(appId, PERMISSION_NONE)) return;
 
-        final int appId = UserHandle.getAppId(uid);
-        if (permission == mApps.get(appId)) {
-            // The permissions of this UID have not changed. Nothing to do.
-            return;
-        } else if (permission != null) {
+        final SparseIntArray apps = new SparseIntArray();
+        if (permission != PERMISSION_NONE) {
             mApps.put(appId, permission);
             apps.put(appId, permission);
             update(mUsers, apps, true);
         } else {
-            mApps.remove(appId);
-            apps.put(appId, NETWORK);  // doesn't matter which permission we pick here
+            mApps.delete(appId);
+            apps.put(appId, PERMISSION_NETWORK);  // doesn't matter which permission we pick here
             update(mUsers, apps, false);
         }
     }
@@ -614,7 +612,7 @@
         // but that's safe.
         final Set<Integer> changedUids = intersectUids(rangesToAdd, mAllApps);
         removeBypassingUids(changedUids, vpnAppUid);
-        updateVpnUids(iface, changedUids, true);
+        updateVpnUidsInterfaceRules(iface, changedUids, true /* add */);
         if (mVpnUidRanges.containsKey(iface)) {
             mVpnUidRanges.get(iface).addAll(rangesToAdd);
         } else {
@@ -635,7 +633,7 @@
         // ranges and update Netd about them.
         final Set<Integer> changedUids = intersectUids(rangesToRemove, mAllApps);
         removeBypassingUids(changedUids, vpnAppUid);
-        updateVpnUids(iface, changedUids, false);
+        updateVpnUidsInterfaceRules(iface, changedUids, false /* add */);
         Set<UidRange> existingRanges = mVpnUidRanges.getOrDefault(iface, null);
         if (existingRanges == null) {
             loge("Attempt to remove unknown vpn uid Range iface = " + iface);
@@ -674,7 +672,7 @@
     /**
      * Remove all apps which can elect to bypass the VPN from the list of uids
      *
-     * An app can elect to bypass the VPN if it hold SYSTEM permission, or if its the active VPN
+     * An app can elect to bypass the VPN if it holds SYSTEM permission, or if it's the active VPN
      * app itself.
      *
      * @param uids The list of uids to operate on
@@ -682,7 +680,8 @@
      */
     private void removeBypassingUids(Set<Integer> uids, int vpnAppUid) {
         uids.remove(vpnAppUid);
-        uids.removeIf(uid -> mApps.getOrDefault(UserHandle.getAppId(uid), NETWORK) == SYSTEM);
+        uids.removeIf(uid ->
+                mApps.get(UserHandle.getAppId(uid), PERMISSION_NONE) == PERMISSION_SYSTEM);
     }
 
     /**
@@ -696,7 +695,7 @@
      * @param add {@code true} if the uids are to be added to the interface, {@code false} if they
      *        are to be removed from the interface.
      */
-    private void updateVpnUids(String iface, Set<Integer> uids, boolean add) {
+    private void updateVpnUidsInterfaceRules(String iface, Set<Integer> uids, boolean add) {
         if (uids.size() == 0) {
             return;
         }
@@ -718,27 +717,25 @@
     }
 
     /**
-     * Called by PackageListObserver when a package is installed/uninstalled. Send the updated
-     * permission information to netd.
+     * Send the updated permission information to netd. Called upon package install/uninstall.
      *
-     * @param uid the app uid of the package installed
+     * @param appId the appId of the package installed
      * @param permissions the permissions the app requested and netd cares about.
      *
      * @hide
      */
     @VisibleForTesting
-    void sendPackagePermissionsForUid(int uid, int permissions) {
+    void sendPackagePermissionsForAppId(int appId, int permissions) {
         SparseIntArray netdPermissionsAppIds = new SparseIntArray();
-        netdPermissionsAppIds.put(uid, permissions);
+        netdPermissionsAppIds.put(appId, 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.
+     * Grant or revoke the INTERNET and/or UPDATE_DEVICE_STATS permission of the appIds 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.
+     * @param netdPermissionsAppIds integer pairs of appIds and the permission granted to it. If the
+     * permission is 0, revoke all permissions of that appId.
      *
      * @hide
      */
@@ -816,17 +813,18 @@
         updateUidsAllowedOnRestrictedNetworks(mDeps.getUidsAllowedOnRestrictedNetworks(mContext));
         uidsToUpdate.addAll(mUidsAllowedOnRestrictedNetworks);
 
-        final Map<Integer, Boolean> updatedUids = new HashMap<>();
-        final Map<Integer, Boolean> removedUids = new HashMap<>();
+        final SparseIntArray updatedUids = new SparseIntArray();
+        final SparseIntArray removedUids = new SparseIntArray();
 
         // Step2. For each uid to update, find out its new permission.
         for (Integer uid : uidsToUpdate) {
-            final Boolean permission = highestUidNetworkPermission(uid);
+            final int permission = highestUidNetworkPermission(uid);
 
             final int appId = UserHandle.getAppId(uid);
-            if (null == permission) {
-                removedUids.put(appId, NETWORK); // Doesn't matter which permission is set here.
-                mApps.remove(appId);
+            if (PERMISSION_NONE == permission) {
+                // Doesn't matter which permission is set here.
+                removedUids.put(appId, PERMISSION_NETWORK);
+                mApps.delete(appId);
             } else {
                 updatedUids.put(appId, permission);
                 mApps.put(appId, permission);
diff --git a/tests/common/java/android/net/NetworkCapabilitiesTest.java b/tests/common/java/android/net/NetworkCapabilitiesTest.java
index 382fa1f..502b4f6 100644
--- a/tests/common/java/android/net/NetworkCapabilitiesTest.java
+++ b/tests/common/java/android/net/NetworkCapabilitiesTest.java
@@ -1170,46 +1170,104 @@
     }
 
     @Test @IgnoreUpTo(Build.VERSION_CODES.R) @ConnectivityModuleTest
-    public void testRestrictCapabilitiesForTestNetwork() {
+    public void testRestrictCapabilitiesForTestNetworkByNotOwnerWithNonRestrictedNc() {
+        testRestrictCapabilitiesForTestNetworkWithNonRestrictedNc(false /* isOwner */);
+    }
+
+    @Test @IgnoreUpTo(Build.VERSION_CODES.R) @ConnectivityModuleTest
+    public void testRestrictCapabilitiesForTestNetworkByOwnerWithNonRestrictedNc() {
+        testRestrictCapabilitiesForTestNetworkWithNonRestrictedNc(true /* isOwner */);
+    }
+
+    private void testRestrictCapabilitiesForTestNetworkWithNonRestrictedNc(boolean isOwner) {
         final int ownerUid = 1234;
+        final int signalStrength = -80;
         final int[] administratorUids = {1001, ownerUid};
+        final TelephonyNetworkSpecifier specifier = new TelephonyNetworkSpecifier(TEST_SUBID1);
+        final TransportInfo transportInfo = new TransportInfo() {};
         final NetworkCapabilities nonRestrictedNc = new NetworkCapabilities.Builder()
                 .addTransportType(TRANSPORT_CELLULAR)
-                .addTransportType(TRANSPORT_VPN)
                 .addCapability(NET_CAPABILITY_MMS)
                 .addCapability(NET_CAPABILITY_NOT_METERED)
                 .setAdministratorUids(administratorUids)
                 .setOwnerUid(ownerUid)
+                .setNetworkSpecifier(specifier)
+                .setSignalStrength(signalStrength)
+                .setTransportInfo(transportInfo)
                 .setSubscriptionIds(Set.of(TEST_SUBID1)).build();
+        final int creatorUid = isOwner ? ownerUid : INVALID_UID;
+        nonRestrictedNc.restrictCapabilitiesForTestNetwork(creatorUid);
 
-        nonRestrictedNc.restrictCapabilitiesForTestNetwork(ownerUid);
-        // TRANSPORT_TEST will be appended
-        assertTrue(nonRestrictedNc.hasTransport(TRANSPORT_TEST));
-        assertEquals(Set.of(TEST_SUBID1), nonRestrictedNc.getSubscriptionIds());
-        // Non-UNRESTRICTED_TEST_NETWORKS_ALLOWED_TRANSPORTS will be removed
-        assertFalse(nonRestrictedNc.hasTransport(TRANSPORT_CELLULAR));
-        assertTrue(nonRestrictedNc.hasTransport(TRANSPORT_VPN));
-        // Only TEST_NETWORKS_ALLOWED_CAPABILITIES will be kept
-        assertFalse(nonRestrictedNc.hasCapability(NET_CAPABILITY_MMS));
-        assertTrue(nonRestrictedNc.hasCapability(NET_CAPABILITY_NOT_METERED));
+        final NetworkCapabilities.Builder expectedNcBuilder = new NetworkCapabilities.Builder();
+        // Non-UNRESTRICTED_TEST_NETWORKS_ALLOWED_TRANSPORTS will be removed and TRANSPORT_TEST will
+        // be appended for non-restricted net cap.
+        expectedNcBuilder.addTransportType(TRANSPORT_TEST);
+        // Only TEST_NETWORKS_ALLOWED_CAPABILITIES will be kept. SubIds are only allowed for Test
+        // Networks that only declare TRANSPORT_TEST.
+        expectedNcBuilder.addCapability(NET_CAPABILITY_NOT_METERED)
+                .removeCapability(NET_CAPABILITY_TRUSTED)
+                .setSubscriptionIds(Set.of(TEST_SUBID1));
 
-        final NetworkCapabilities restrictedNc = new NetworkCapabilities.Builder(nonRestrictedNc)
+        expectedNcBuilder.setNetworkSpecifier(specifier)
+                .setSignalStrength(signalStrength).setTransportInfo(transportInfo);
+        if (creatorUid == ownerUid) {
+            // Only retain the owner and administrator UIDs if they match the app registering the
+            // remote caller that registered the network.
+            expectedNcBuilder.setAdministratorUids(new int[]{ownerUid}).setOwnerUid(ownerUid);
+        }
+
+        assertEquals(expectedNcBuilder.build(), nonRestrictedNc);
+    }
+
+    @Test @IgnoreUpTo(Build.VERSION_CODES.R) @ConnectivityModuleTest
+    public void testRestrictCapabilitiesForTestNetworkByNotOwnerWithRestrictedNc() {
+        testRestrictCapabilitiesForTestNetworkWithRestrictedNc(false /* isOwner */);
+    }
+
+    @Test @IgnoreUpTo(Build.VERSION_CODES.R) @ConnectivityModuleTest
+    public void testRestrictCapabilitiesForTestNetworkByOwnerWithRestrictedNc() {
+        testRestrictCapabilitiesForTestNetworkWithRestrictedNc(true /* isOwner */);
+    }
+
+    private void testRestrictCapabilitiesForTestNetworkWithRestrictedNc(boolean isOwner) {
+        final int ownerUid = 1234;
+        final int signalStrength = -80;
+        final int[] administratorUids = {1001, ownerUid};
+        final TransportInfo transportInfo = new TransportInfo() {};
+        // No NetworkSpecifier is set because after performing restrictCapabilitiesForTestNetwork
+        // the networkCapabilities will contain more than one transport type. However,
+        // networkCapabilities must have a single transport specified to use NetworkSpecifier. Thus,
+        // do not verify this part since it's verified in other tests.
+        final NetworkCapabilities restrictedNc = new NetworkCapabilities.Builder()
                 .removeCapability(NET_CAPABILITY_NOT_RESTRICTED)
                 .addTransportType(TRANSPORT_CELLULAR)
-                .addCapability(NET_CAPABILITY_MMS).build();
-        restrictedNc.restrictCapabilitiesForTestNetwork(ownerUid);
-        // It may declare any transport if the net cap is restricted
-        assertTrue(restrictedNc.hasTransport(TRANSPORT_CELLULAR));
-        // SubIds will be cleared.
-        assertEquals(new ArraySet<>(), restrictedNc.getSubscriptionIds());
-        // Only retain the owner and administrator UIDs if they match the app registering the remote
-        // caller that registered the network.
-        assertEquals(ownerUid, restrictedNc.getOwnerUid());
-        assertArrayEquals(new int[] {ownerUid}, restrictedNc.getAdministratorUids());
-        // The creator UID does not match the owner and administrator UIDs will clear the owner and
-        // administrator UIDs.
-        restrictedNc.restrictCapabilitiesForTestNetwork(5678);
-        assertEquals(INVALID_UID, restrictedNc.getOwnerUid());
-        assertArrayEquals(new int[0], restrictedNc.getAdministratorUids());
+                .addCapability(NET_CAPABILITY_MMS)
+                .addCapability(NET_CAPABILITY_NOT_METERED)
+                .setAdministratorUids(administratorUids)
+                .setOwnerUid(ownerUid)
+                .setSignalStrength(signalStrength)
+                .setTransportInfo(transportInfo)
+                .setSubscriptionIds(Set.of(TEST_SUBID1)).build();
+        final int creatorUid = isOwner ? ownerUid : INVALID_UID;
+        restrictedNc.restrictCapabilitiesForTestNetwork(creatorUid);
+
+        final NetworkCapabilities.Builder expectedNcBuilder = new NetworkCapabilities.Builder()
+                .removeCapability(NET_CAPABILITY_NOT_RESTRICTED);
+        // If the test network is restricted, then the network may declare any transport, and
+        // appended with TRANSPORT_TEST.
+        expectedNcBuilder.addTransportType(TRANSPORT_CELLULAR);
+        expectedNcBuilder.addTransportType(TRANSPORT_TEST);
+        // Only TEST_NETWORKS_ALLOWED_CAPABILITIES will be kept.
+        expectedNcBuilder.addCapability(NET_CAPABILITY_NOT_METERED);
+        expectedNcBuilder.removeCapability(NET_CAPABILITY_TRUSTED);
+
+        expectedNcBuilder.setSignalStrength(signalStrength).setTransportInfo(transportInfo);
+        if (creatorUid == ownerUid) {
+            // Only retain the owner and administrator UIDs if they match the app registering the
+            // remote caller that registered the network.
+            expectedNcBuilder.setAdministratorUids(new int[]{ownerUid}).setOwnerUid(ownerUid);
+        }
+
+        assertEquals(expectedNcBuilder.build(), restrictedNc);
     }
 }
diff --git a/tests/cts/net/src/android/net/cts/AirplaneModeTest.java b/tests/cts/net/src/android/net/cts/AirplaneModeTest.java
deleted file mode 100644
index 524e549..0000000
--- a/tests/cts/net/src/android/net/cts/AirplaneModeTest.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.cts;
-
-import android.content.ContentResolver;
-import android.content.Context;
-import android.platform.test.annotations.AppModeFull;
-import android.provider.Settings;
-import android.test.AndroidTestCase;
-import android.util.Log;
-
-import java.lang.Thread;
-
-@AppModeFull(reason = "WRITE_SECURE_SETTINGS permission can't be granted to instant apps")
-public class AirplaneModeTest extends AndroidTestCase {
-    private static final String TAG = "AirplaneModeTest";
-    private static final String FEATURE_BLUETOOTH = "android.hardware.bluetooth";
-    private static final String FEATURE_WIFI = "android.hardware.wifi";
-    private static final int TIMEOUT_MS = 10 * 1000;
-    private boolean mHasFeature;
-    private Context mContext;
-    private ContentResolver resolver;
-
-    public void setup() {
-        mContext= getContext();
-        resolver = mContext.getContentResolver();
-        mHasFeature = (mContext.getPackageManager().hasSystemFeature(FEATURE_BLUETOOTH)
-                       || mContext.getPackageManager().hasSystemFeature(FEATURE_WIFI));
-    }
-
-    public void testAirplaneMode() {
-        setup();
-        if (!mHasFeature) {
-            Log.i(TAG, "The device doesn't support network bluetooth or wifi feature");
-            return;
-        }
-
-        for (int testCount = 0; testCount < 2; testCount++) {
-            if (!doOneTest()) {
-                fail("Airplane mode failed to change in " + TIMEOUT_MS + "msec");
-                return;
-            }
-        }
-    }
-
-    private boolean doOneTest() {
-        boolean airplaneModeOn = isAirplaneModeOn();
-        setAirplaneModeOn(!airplaneModeOn);
-
-        try {
-            Thread.sleep(TIMEOUT_MS);
-        } catch (InterruptedException e) {
-            Log.e(TAG, "Sleep time interrupted.", e);
-        }
-
-        if (airplaneModeOn == isAirplaneModeOn()) {
-            return false;
-        }
-        return true;
-    }
-
-    private void setAirplaneModeOn(boolean enabling) {
-        // Change the system setting for airplane mode
-        Settings.Global.putInt(resolver, Settings.Global.AIRPLANE_MODE_ON, enabling ? 1 : 0);
-    }
-
-    private boolean isAirplaneModeOn() {
-        // Read the system setting for airplane mode
-        return Settings.Global.getInt(mContext.getContentResolver(),
-                                      Settings.Global.AIRPLANE_MODE_ON, 0) != 0;
-    }
-}
diff --git a/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt b/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt
index 9f079c4..9f98e3f 100644
--- a/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt
+++ b/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt
@@ -46,6 +46,7 @@
 import android.provider.DeviceConfig
 import android.provider.DeviceConfig.NAMESPACE_CONNECTIVITY
 import android.text.TextUtils
+import android.util.Log
 import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
 import androidx.test.runner.AndroidJUnit4
 import com.android.testutils.RecorderCallback
@@ -79,6 +80,8 @@
 private const val WIFI_CONNECT_TIMEOUT_MS = 120_000L
 private const val TEST_TIMEOUT_MS = 10_000L
 
+private const val TAG = "CaptivePortalTest"
+
 private fun <T> CompletableFuture<T>.assertGet(timeoutMs: Long, message: String): T {
     try {
         return get(timeoutMs, TimeUnit.MILLISECONDS)
@@ -155,6 +158,7 @@
         server.addResponse(Request(TEST_HTTP_URL_PATH), Status.REDIRECT, headers)
         setHttpsUrlDeviceConfig(makeUrl(TEST_HTTPS_URL_PATH))
         setHttpUrlDeviceConfig(makeUrl(TEST_HTTP_URL_PATH))
+        Log.d(TAG, "Set portal URLs to $TEST_HTTPS_URL_PATH and $TEST_HTTP_URL_PATH")
         // URL expiration needs to be in the next 10 minutes
         assertTrue(WIFI_CONNECT_TIMEOUT_MS < TimeUnit.MINUTES.toMillis(10))
         setUrlExpirationDeviceConfig(System.currentTimeMillis() + WIFI_CONNECT_TIMEOUT_MS)
diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
index 65dffbd..f5c43d6 100644
--- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
+++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
@@ -119,10 +119,8 @@
 import android.net.NetworkInfo.State;
 import android.net.NetworkProvider;
 import android.net.NetworkRequest;
-import android.net.NetworkScore;
 import android.net.NetworkSpecifier;
 import android.net.NetworkStateSnapshot;
-import android.net.NetworkUtils;
 import android.net.OemNetworkPreferences;
 import android.net.ProxyInfo;
 import android.net.SocketKeepalive;
@@ -260,6 +258,7 @@
             "config_allowedUnprivilegedKeepalivePerUid";
     private static final String KEEPALIVE_RESERVED_PER_SLOT_RES_NAME =
             "config_reservedPrivilegedKeepaliveSlots";
+    private static final String TEST_RESTRICTED_NW_IFACE_NAME = "test-restricted-nw";
 
     private static final LinkAddress TEST_LINKADDR = new LinkAddress(
             InetAddresses.parseNumericAddress("2001:db8::8"), 64);
@@ -1082,7 +1081,8 @@
     }
 
     private Network waitForActiveNetworkMetered(final int targetTransportType,
-            final boolean requestedMeteredness, final boolean useSystemDefault)
+            final boolean requestedMeteredness, final boolean waitForValidation,
+            final boolean useSystemDefault)
             throws Exception {
         final CompletableFuture<Network> networkFuture = new CompletableFuture<>();
         final NetworkCallback networkCallback = new NetworkCallback() {
@@ -1091,7 +1091,8 @@
                 if (!nc.hasTransport(targetTransportType)) return;
 
                 final boolean metered = !nc.hasCapability(NET_CAPABILITY_NOT_METERED);
-                if (metered == requestedMeteredness) {
+                final boolean validated = nc.hasCapability(NET_CAPABILITY_VALIDATED);
+                if (metered == requestedMeteredness && (!waitForValidation || validated)) {
                     networkFuture.complete(network);
                 }
             }
@@ -1120,11 +1121,13 @@
         }
     }
 
-    private Network setWifiMeteredStatusAndWait(String ssid, boolean isMetered) throws Exception {
+    private Network setWifiMeteredStatusAndWait(String ssid, boolean isMetered,
+            boolean waitForValidation) throws Exception {
         setWifiMeteredStatus(ssid, Boolean.toString(isMetered) /* metered */);
         mCtsNetUtils.ensureWifiConnected();
         return waitForActiveNetworkMetered(TRANSPORT_WIFI,
                 isMetered /* requestedMeteredness */,
+                waitForValidation,
                 true /* useSystemDefault */);
     }
 
@@ -1187,9 +1190,10 @@
             int newMeteredPreference = findNextPrefValue(resolver);
             Settings.Global.putString(resolver, NETWORK_METERED_MULTIPATH_PREFERENCE,
                     Integer.toString(newMeteredPreference));
-            // Wifi meterness changes from unmetered to metered will disconnect and reconnect since
-            // R.
-            final Network network = setWifiMeteredStatusAndWait(ssid, true);
+            // Wifi meteredness changes from unmetered to metered will disconnect and reconnect
+            // since R.
+            final Network network = setWifiMeteredStatusAndWait(ssid, true /* isMetered */,
+                    false /* waitForValidation */);
             assertEquals(ssid, unquoteSSID(mWifiManager.getConnectionInfo().getSSID()));
             assertEquals(mCm.getNetworkCapabilities(network).hasCapability(
                     NET_CAPABILITY_NOT_METERED), false);
@@ -1206,7 +1210,7 @@
                     oldMeteredPreference, newMeteredPreference);
 
             // No disconnect from unmetered to metered.
-            setWifiMeteredStatusAndWait(ssid, false);
+            setWifiMeteredStatusAndWait(ssid, false /* isMetered */, false /* waitForValidation */);
             assertEquals(mCm.getNetworkCapabilities(network).hasCapability(
                     NET_CAPABILITY_NOT_METERED), true);
             assertMultipathPreferenceIsEventually(network, newMeteredPreference,
@@ -1748,6 +1752,40 @@
                 greater >= lesser);
     }
 
+    private void verifyBindSocketToRestrictedNetworkDisallowed() throws Exception {
+        final TestableNetworkCallback testNetworkCb = new TestableNetworkCallback();
+        final NetworkRequest testRequest = new NetworkRequest.Builder()
+                .addTransportType(NetworkCapabilities.TRANSPORT_TEST)
+                .removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED)
+                .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
+                .setNetworkSpecifier(CompatUtil.makeTestNetworkSpecifier(
+                        TEST_RESTRICTED_NW_IFACE_NAME))
+                .build();
+        runWithShellPermissionIdentity(() -> requestNetwork(testRequest, testNetworkCb),
+                CONNECTIVITY_USE_RESTRICTED_NETWORKS,
+                // CONNECTIVITY_INTERNAL is for requesting restricted network because shell does not
+                // have CONNECTIVITY_USE_RESTRICTED_NETWORKS on R.
+                CONNECTIVITY_INTERNAL);
+
+        // Create a restricted network and ensure this package cannot bind to that network either.
+        final NetworkAgent agent = createRestrictedNetworkAgent(mContext);
+        final Network network = agent.getNetwork();
+
+        try (Socket socket = new Socket()) {
+            // Verify that the network is restricted.
+            testNetworkCb.eventuallyExpect(CallbackEntry.NETWORK_CAPS_UPDATED,
+                    NETWORK_CALLBACK_TIMEOUT_MS,
+                    entry -> network.equals(entry.getNetwork())
+                            && (!((CallbackEntry.CapabilitiesChanged) entry).getCaps()
+                            .hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)));
+            // CtsNetTestCases package doesn't hold CONNECTIVITY_USE_RESTRICTED_NETWORKS, so it
+            // does not allow to bind socket to restricted network.
+            assertThrows(IOException.class, () -> network.bindSocket(socket));
+        } finally {
+            agent.unregister();
+        }
+    }
+
     /**
      * Verifies that apps are not allowed to access restricted networks even if they declare the
      * CONNECTIVITY_USE_RESTRICTED_NETWORKS permission in their manifests.
@@ -1764,23 +1802,33 @@
         assertTrue(index >= 0);
         assertTrue(app.requestedPermissionsFlags[index] != PERMISSION_GRANTED);
 
-        // Ensure that NetworkUtils.queryUserAccess always returns false since this package should
-        // not have netd system permission to call this function.
-        final Network wifiNetwork = mCtsNetUtils.ensureWifiConnected();
-        assertFalse(NetworkUtils.queryUserAccess(Binder.getCallingUid(), wifiNetwork.netId));
+        if (mPackageManager.hasSystemFeature(FEATURE_WIFI)) {
+            // Expect binding to the wifi network to succeed.
+            final Network wifiNetwork = mCtsNetUtils.ensureWifiConnected();
+            try (Socket socket = new Socket()) {
+                wifiNetwork.bindSocket(socket);
+            }
+        }
 
         // Ensure that this package cannot bind to any restricted network that's currently
         // connected.
         Network[] networks = mCm.getAllNetworks();
         for (Network network : networks) {
-            NetworkCapabilities nc = mCm.getNetworkCapabilities(network);
-            if (nc != null && !nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED)) {
-                try {
-                    network.bindSocket(new Socket());
-                    fail("Bind to restricted network " + network + " unexpectedly succeeded");
-                } catch (IOException expected) {}
+            final NetworkCapabilities nc = mCm.getNetworkCapabilities(network);
+            if (nc == null) {
+                continue;
+            }
+
+            try (Socket socket = new Socket()) {
+                if (nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED)) {
+                    network.bindSocket(socket);  // binding should succeed
+                } else {
+                    assertThrows(IOException.class, () -> network.bindSocket(socket));
+                }
             }
         }
+
+        verifyBindSocketToRestrictedNetworkDisallowed();
     }
 
     /**
@@ -2322,8 +2370,10 @@
         final boolean oldMeteredValue = wifiNetworkCapabilities.isMetered();
 
         try {
-            // This network will be used for unmetered.
-            setWifiMeteredStatusAndWait(ssid, false /* isMetered */);
+            // This network will be used for unmetered. Wait for it to be validated because
+            // OEM_NETWORK_PREFERENCE_TEST only prefers NOT_METERED&VALIDATED to a network with
+            // TRANSPORT_TEST, like OEM_NETWORK_PREFERENCE_OEM_PAID.
+            setWifiMeteredStatusAndWait(ssid, false /* isMetered */, true /* waitForValidation */);
 
             setOemNetworkPreferenceForMyPackage(OemNetworkPreferences.OEM_NETWORK_PREFERENCE_TEST);
             registerTestOemNetworkPreferenceCallbacks(defaultCallback, systemDefaultCallback);
@@ -2332,9 +2382,10 @@
             waitForAvailable(defaultCallback, wifiNetwork);
             waitForAvailable(systemDefaultCallback, wifiNetwork);
 
-            // Validate when setting unmetered to metered, unmetered is lost and replaced by the
-            // network with the TEST transport.
-            setWifiMeteredStatusAndWait(ssid, true /* isMetered */);
+            // Validate that when setting unmetered to metered, unmetered is lost and replaced by
+            // the network with the TEST transport. Also wait for validation here, in case there
+            // is a bug that's only visible when the network is validated.
+            setWifiMeteredStatusAndWait(ssid, true /* isMetered */, true /* waitForValidation */);
             defaultCallback.expectCallback(CallbackEntry.LOST, wifiNetwork,
                     NETWORK_CALLBACK_TIMEOUT_MS);
             waitForAvailable(defaultCallback, tnt.getNetwork());
@@ -2350,7 +2401,7 @@
                     NETWORK_CALLBACK_TIMEOUT_MS);
             waitForAvailable(defaultCallback);
 
-            setWifiMeteredStatusAndWait(ssid, oldMeteredValue);
+            setWifiMeteredStatusAndWait(ssid, oldMeteredValue, false /* waitForValidation */);
 
             // Cleanup any prior test state from setOemNetworkPreference
             clearOemNetworkPreference();
@@ -2832,6 +2883,24 @@
         }
     }
 
+    private static NetworkAgent createRestrictedNetworkAgent(final Context context) {
+        // Create test network agent with restricted network.
+        final NetworkCapabilities nc = new NetworkCapabilities.Builder()
+                .addTransportType(NetworkCapabilities.TRANSPORT_TEST)
+                .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
+                .setNetworkSpecifier(CompatUtil.makeTestNetworkSpecifier(
+                        TEST_RESTRICTED_NW_IFACE_NAME))
+                .build();
+        final NetworkAgent agent = new NetworkAgent(context, Looper.getMainLooper(), TAG, nc,
+                new LinkProperties(), 10 /* score */, new NetworkAgentConfig.Builder().build(),
+                new NetworkProvider(context, Looper.getMainLooper(), TAG)) {};
+        runWithShellPermissionIdentity(() -> agent.register(),
+                android.Manifest.permission.MANAGE_TEST_NETWORKS);
+        agent.markConnected();
+
+        return agent;
+    }
+
     @AppModeFull(reason = "WRITE_SECURE_SETTINGS permission can't be granted to instant apps")
     @Test
     public void testUidsAllowedOnRestrictedNetworks() throws Exception {
@@ -2852,42 +2921,27 @@
                 ConnectivitySettingsManager.setUidsAllowedOnRestrictedNetworks(
                         mContext, originalUidsAllowedOnRestrictedNetworks), NETWORK_SETTINGS);
 
-        final Handler h = new Handler(Looper.getMainLooper());
         final TestableNetworkCallback testNetworkCb = new TestableNetworkCallback();
-        registerBestMatchingNetworkCallback(new NetworkRequest.Builder().clearCapabilities()
-                .addTransportType(NetworkCapabilities.TRANSPORT_TEST).build(), testNetworkCb, h);
-
-        // Create test network agent with restricted network.
-        final NetworkCapabilities nc = new NetworkCapabilities.Builder()
+        final NetworkRequest testRequest = new NetworkRequest.Builder()
                 .addTransportType(NetworkCapabilities.TRANSPORT_TEST)
-                .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED)
-                .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING)
-                .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED)
                 .removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED)
                 .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
+                .setNetworkSpecifier(CompatUtil.makeTestNetworkSpecifier(
+                        TEST_RESTRICTED_NW_IFACE_NAME))
                 .build();
-        final NetworkScore score = new NetworkScore.Builder()
-                .setExiting(false)
-                .setTransportPrimary(false)
-                .setKeepConnectedReason(NetworkScore.KEEP_CONNECTED_FOR_HANDOVER)
-                .build();
-        final NetworkAgent agent = new NetworkAgent(mContext, Looper.getMainLooper(),
-                TAG, nc, new LinkProperties(), score, new NetworkAgentConfig.Builder().build(),
-                new NetworkProvider(mContext, Looper.getMainLooper(), TAG)) {};
-        runWithShellPermissionIdentity(() -> agent.register(),
-                android.Manifest.permission.MANAGE_TEST_NETWORKS);
-        agent.markConnected();
+        runWithShellPermissionIdentity(() -> requestNetwork(testRequest, testNetworkCb),
+                CONNECTIVITY_USE_RESTRICTED_NETWORKS);
 
+        final NetworkAgent agent = createRestrictedNetworkAgent(mContext);
         final Network network = agent.getNetwork();
 
         try (Socket socket = new Socket()) {
-            testNetworkCb.eventuallyExpect(CallbackEntry.AVAILABLE, NETWORK_CALLBACK_TIMEOUT_MS,
-                    entry -> network.equals(entry.getNetwork()));
             // Verify that the network is restricted.
-            final NetworkCapabilities testNetworkNc = mCm.getNetworkCapabilities(network);
-            assertNotNull(testNetworkNc);
-            assertFalse(testNetworkNc.hasCapability(
-                    NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED));
+            testNetworkCb.eventuallyExpect(CallbackEntry.NETWORK_CAPS_UPDATED,
+                    NETWORK_CALLBACK_TIMEOUT_MS,
+                    entry -> network.equals(entry.getNetwork())
+                            && (!((CallbackEntry.CapabilitiesChanged) entry).getCaps()
+                            .hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)));
             // CtsNetTestCases package doesn't hold CONNECTIVITY_USE_RESTRICTED_NETWORKS, so it
             // does not allow to bind socket to restricted network.
             assertThrows(IOException.class, () -> network.bindSocket(socket));
diff --git a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt
index 7c380e3..1a131d8 100644
--- a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt
+++ b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt
@@ -1072,6 +1072,7 @@
         Executors.newSingleThreadExecutor().let { executor ->
             try {
                 val info = QosSocketInfo(agent.network!!, socket)
+                assertEquals(agent.network, info.getNetwork())
                 mCM.registerQosCallback(info, executor, qosCallback)
                 val callbackId = agent.expectCallback<OnRegisterQosCallback>().callbackId
 
diff --git a/tests/unit/java/android/net/NetworkTemplateTest.kt b/tests/unit/java/android/net/NetworkTemplateTest.kt
index 49c7271..9ff594a 100644
--- a/tests/unit/java/android/net/NetworkTemplateTest.kt
+++ b/tests/unit/java/android/net/NetworkTemplateTest.kt
@@ -39,6 +39,8 @@
 import android.net.NetworkTemplate.SUBSCRIBER_ID_MATCH_RULE_EXACT
 import android.net.NetworkTemplate.WIFI_NETWORKID_ALL
 import android.net.NetworkTemplate.buildTemplateCarrierMetered
+import android.net.NetworkTemplate.buildTemplateMobileAll
+import android.net.NetworkTemplate.buildTemplateMobileWildcard
 import android.net.NetworkTemplate.buildTemplateMobileWithRatType
 import android.net.NetworkTemplate.buildTemplateWifi
 import android.net.NetworkTemplate.buildTemplateWifiWildcard
@@ -171,6 +173,57 @@
     }
 
     @Test
+    fun testMobileMatches() {
+        val templateMobileImsi1 = buildTemplateMobileAll(TEST_IMSI1)
+        val templateMobileImsi2WithRatType = buildTemplateMobileWithRatType(TEST_IMSI2,
+                TelephonyManager.NETWORK_TYPE_UMTS)
+
+        val mobileImsi1 = buildNetworkState(TYPE_MOBILE, TEST_IMSI1, null /* ssid */,
+                OEM_NONE, true /* metered */)
+        val identMobile1 = buildNetworkIdentity(mockContext, mobileImsi1,
+                false /* defaultNetwork */, TelephonyManager.NETWORK_TYPE_UMTS)
+        val mobileImsi2 = buildMobileNetworkState(TEST_IMSI2)
+        val identMobile2Umts = buildNetworkIdentity(mockContext, mobileImsi2,
+                false /* defaultNetwork */, TelephonyManager.NETWORK_TYPE_UMTS)
+
+        val identWifiImsi1Ssid1 = buildNetworkIdentity(
+                mockContext, buildWifiNetworkState(TEST_IMSI1, TEST_SSID1), true, 0)
+
+        // Verify that the template matches type and the subscriberId.
+        templateMobileImsi1.assertMatches(identMobile1)
+        templateMobileImsi2WithRatType.assertMatches(identMobile2Umts)
+
+        // Verify that the template does not match the different subscriberId.
+        templateMobileImsi1.assertDoesNotMatch(identMobile2Umts)
+        templateMobileImsi2WithRatType.assertDoesNotMatch(identMobile1)
+
+        // Verify that the different type does not match.
+        templateMobileImsi1.assertDoesNotMatch(identWifiImsi1Ssid1)
+    }
+
+    @Test
+    fun testMobileWildcardMatches() {
+        val templateMobileWildcard = buildTemplateMobileWildcard()
+        val templateMobileNullImsiWithRatType = buildTemplateMobileWithRatType(null,
+                TelephonyManager.NETWORK_TYPE_UMTS)
+
+        val mobileImsi1 = buildMobileNetworkState(TEST_IMSI1)
+        val identMobile1 = buildNetworkIdentity(mockContext, mobileImsi1,
+                false /* defaultNetwork */, TelephonyManager.NETWORK_TYPE_UMTS)
+
+        // Verify that the template matches any subscriberId.
+        templateMobileWildcard.assertMatches(identMobile1)
+        templateMobileNullImsiWithRatType.assertMatches(identMobile1)
+
+        val identWifiImsi1Ssid1 = buildNetworkIdentity(
+                mockContext, buildWifiNetworkState(TEST_IMSI1, TEST_SSID1), true, 0)
+
+        // Verify that the different type does not match.
+        templateMobileWildcard.assertDoesNotMatch(identWifiImsi1Ssid1)
+        templateMobileNullImsiWithRatType.assertDoesNotMatch(identWifiImsi1Ssid1)
+    }
+
+    @Test
     fun testCarrierMeteredMatches() {
         val templateCarrierImsi1Metered = buildTemplateCarrierMetered(TEST_IMSI1)
 
diff --git a/tests/unit/java/com/android/server/ConnectivityServiceTest.java b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
index 814d799..2aba0b4 100644
--- a/tests/unit/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
@@ -350,8 +350,11 @@
 import org.mockito.ArgumentCaptor;
 import org.mockito.InOrder;
 import org.mockito.Mock;
+import org.mockito.MockingDetails;
+import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 import org.mockito.Spy;
+import org.mockito.exceptions.misusing.UnfinishedStubbingException;
 import org.mockito.stubbing.Answer;
 
 import java.io.FileDescriptor;
@@ -1734,7 +1737,15 @@
     }
 
     private void returnRealCallingUid() {
-        doAnswer((invocationOnMock) -> Binder.getCallingUid()).when(mDeps).getCallingUid();
+        try {
+            doAnswer((invocationOnMock) -> Binder.getCallingUid()).when(mDeps).getCallingUid();
+        } catch (UnfinishedStubbingException e) {
+            final MockingDetails details = Mockito.mockingDetails(mDeps);
+            Log.e("ConnectivityServiceTest", "UnfinishedStubbingException,"
+                    + " Stubbings: " + TextUtils.join(", ", details.getStubbings())
+                    + " Invocations: " + details.printInvocations(), e);
+            throw e;
+        }
     }
 
     private ConnectivityService.Dependencies makeDependencies() {
@@ -4848,7 +4859,6 @@
         final TestableNetworkOfferCallback wifiCallback = new TestableNetworkOfferCallback(
                 TIMEOUT_MS /* timeout */, TEST_CALLBACK_TIMEOUT_MS /* noCallbackTimeout */);
 
-        Log.e("ConnectivityService", "test registering " + cellProvider);
         // Offer callbacks will run on the CS handler thread in this test.
         cellProvider.registerNetworkOffer(cellScore, cellCaps, r -> r.run(), cellCallback);
         wifiProvider.registerNetworkOffer(wifiScore, wifiCaps, r -> r.run(), wifiCallback);
@@ -6238,16 +6248,16 @@
         mCm.unregisterNetworkCallback(networkCallback);
     }
 
-    private void expectNotifyNetworkStatus(List<Network> networks, String defaultIface,
+    private void expectNotifyNetworkStatus(List<Network> defaultNetworks, String defaultIface,
             Integer vpnUid, String vpnIfname, List<String> underlyingIfaces) throws Exception {
-        ArgumentCaptor<List<Network>> networksCaptor = ArgumentCaptor.forClass(List.class);
+        ArgumentCaptor<List<Network>> defaultNetworksCaptor = ArgumentCaptor.forClass(List.class);
         ArgumentCaptor<List<UnderlyingNetworkInfo>> vpnInfosCaptor =
                 ArgumentCaptor.forClass(List.class);
 
-        verify(mStatsManager, atLeastOnce()).notifyNetworkStatus(networksCaptor.capture(),
+        verify(mStatsManager, atLeastOnce()).notifyNetworkStatus(defaultNetworksCaptor.capture(),
                 any(List.class), eq(defaultIface), vpnInfosCaptor.capture());
 
-        assertSameElements(networks, networksCaptor.getValue());
+        assertSameElements(defaultNetworks, defaultNetworksCaptor.getValue());
 
         List<UnderlyingNetworkInfo> infos = vpnInfosCaptor.getValue();
         if (vpnUid != null) {
@@ -6263,8 +6273,8 @@
     }
 
     private void expectNotifyNetworkStatus(
-            List<Network> networks, String defaultIface) throws Exception {
-        expectNotifyNetworkStatus(networks, defaultIface, null, null, List.of());
+            List<Network> defaultNetworks, String defaultIface) throws Exception {
+        expectNotifyNetworkStatus(defaultNetworks, defaultIface, null, null, List.of());
     }
 
     @Test
@@ -12972,21 +12982,26 @@
         assertLength(2, snapshots);
         assertContainsAll(snapshots, cellSnapshot, wifiSnapshot);
 
-        // Set cellular as suspended, verify the snapshots will not contain suspended networks.
-        // TODO: Consider include SUSPENDED networks, which should be considered as
-        //  temporary shortage of connectivity of a connected network.
+        // Set cellular as suspended, verify the snapshots will contain suspended networks.
         mCellNetworkAgent.suspend();
         waitForIdle();
+        final NetworkCapabilities cellSuspendedNc =
+                mCm.getNetworkCapabilities(mCellNetworkAgent.getNetwork());
+        assertFalse(cellSuspendedNc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
+        final NetworkStateSnapshot cellSuspendedSnapshot = new NetworkStateSnapshot(
+                mCellNetworkAgent.getNetwork(), cellSuspendedNc, cellLp,
+                null, ConnectivityManager.TYPE_MOBILE);
         snapshots = mCm.getAllNetworkStateSnapshots();
-        assertLength(1, snapshots);
-        assertEquals(wifiSnapshot, snapshots.get(0));
+        assertLength(2, snapshots);
+        assertContainsAll(snapshots, cellSuspendedSnapshot, wifiSnapshot);
 
-        // Disconnect wifi, verify the snapshots contain nothing.
+        // Disconnect wifi, verify the snapshots contain only cellular.
         mWiFiNetworkAgent.disconnect();
         waitForIdle();
         snapshots = mCm.getAllNetworkStateSnapshots();
         assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
-        assertLength(0, snapshots);
+        assertLength(1, snapshots);
+        assertEquals(cellSuspendedSnapshot, snapshots.get(0));
 
         mCellNetworkAgent.resume();
         waitForIdle();
diff --git a/tests/unit/java/com/android/server/connectivity/PermissionMonitorTest.java b/tests/unit/java/com/android/server/connectivity/PermissionMonitorTest.java
index a9749c4..ecda338 100644
--- a/tests/unit/java/com/android/server/connectivity/PermissionMonitorTest.java
+++ b/tests/unit/java/com/android/server/connectivity/PermissionMonitorTest.java
@@ -32,6 +32,7 @@
 import static android.content.pm.PackageManager.MATCH_ANY_USER;
 import static android.net.ConnectivitySettingsManager.UIDS_ALLOWED_ON_RESTRICTED_NETWORKS;
 import static android.net.INetd.PERMISSION_INTERNET;
+import static android.net.INetd.PERMISSION_NETWORK;
 import static android.net.INetd.PERMISSION_NONE;
 import static android.net.INetd.PERMISSION_SYSTEM;
 import static android.net.INetd.PERMISSION_UNINSTALLED;
@@ -39,8 +40,7 @@
 import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
 import static android.os.Process.SYSTEM_UID;
 
-import static com.android.server.connectivity.PermissionMonitor.NETWORK;
-import static com.android.server.connectivity.PermissionMonitor.SYSTEM;
+import static com.android.server.connectivity.PermissionMonitor.isHigherNetworkPermission;
 
 import static junit.framework.Assert.fail;
 
@@ -55,12 +55,12 @@
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.argThat;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.intThat;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.doCallRealMethod;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -80,12 +80,14 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings;
-import android.util.ArraySet;
 import android.util.SparseIntArray;
 
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.SmallTest;
 
+import com.android.net.module.util.CollectionUtils;
 import com.android.testutils.DevSdkIgnoreRule;
 import com.android.testutils.DevSdkIgnoreRunner;
 
@@ -98,11 +100,8 @@
 import org.mockito.MockitoAnnotations;
 import org.mockito.invocation.InvocationOnMock;
 
-import java.util.ArrayList;
+import java.lang.reflect.Array;
 import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 
@@ -110,13 +109,19 @@
 @SmallTest
 @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R)
 public class PermissionMonitorTest {
-    private static final UserHandle MOCK_USER1 = UserHandle.of(0);
-    private static final UserHandle MOCK_USER2 = UserHandle.of(1);
-    private static final int MOCK_UID1 = 10001;
-    private static final int MOCK_UID2 = 10086;
-    private static final int SYSTEM_UID1 = 1000;
-    private static final int SYSTEM_UID2 = 1008;
-    private static final int VPN_UID = 10002;
+    private static final int MOCK_USER_ID1 = 0;
+    private static final int MOCK_USER_ID2 = 1;
+    private static final UserHandle MOCK_USER1 = UserHandle.of(MOCK_USER_ID1);
+    private static final UserHandle MOCK_USER2 = UserHandle.of(MOCK_USER_ID2);
+    private static final int MOCK_APPID1 = 10001;
+    private static final int MOCK_APPID2 = 10086;
+    private static final int SYSTEM_APPID1 = 1100;
+    private static final int SYSTEM_APPID2 = 1108;
+    private static final int VPN_APPID = 10002;
+    private static final int MOCK_UID1 = MOCK_USER1.getUid(MOCK_APPID1);
+    private static final int MOCK_UID2 = MOCK_USER1.getUid(MOCK_APPID2);
+    private static final int SYSTEM_APP_UID1 = MOCK_USER1.getUid(SYSTEM_APPID1);
+    private static final int VPN_UID = MOCK_USER1.getUid(VPN_APPID);
     private static final String REAL_SYSTEM_PACKAGE_NAME = "android";
     private static final String MOCK_PACKAGE1 = "appName1";
     private static final String MOCK_PACKAGE2 = "appName2";
@@ -146,8 +151,7 @@
         MockitoAnnotations.initMocks(this);
         when(mContext.getPackageManager()).thenReturn(mPackageManager);
         when(mContext.getSystemService(eq(Context.USER_SERVICE))).thenReturn(mUserManager);
-        when(mUserManager.getUserHandles(eq(true))).thenReturn(
-                Arrays.asList(new UserHandle[] { MOCK_USER1, MOCK_USER2 }));
+        doReturn(List.of(MOCK_USER1)).when(mUserManager).getUserHandles(eq(true));
         when(mContext.getSystemServiceName(SystemConfigManager.class))
                 .thenReturn(Context.SYSTEM_CONFIG_SERVICE);
         when(mContext.getSystemService(Context.SYSTEM_CONFIG_SERVICE))
@@ -160,19 +164,15 @@
         final Context asUserCtx = mock(Context.class, AdditionalAnswers.delegatesTo(mContext));
         doReturn(UserHandle.ALL).when(asUserCtx).getUser();
         when(mContext.createContextAsUser(eq(UserHandle.ALL), anyInt())).thenReturn(asUserCtx);
-        when(mDeps.getUidsAllowedOnRestrictedNetworks(any())).thenReturn(new ArraySet<>());
+        when(mDeps.getUidsAllowedOnRestrictedNetworks(any())).thenReturn(Set.of());
+        // Set DEVICE_INITIAL_SDK_INT to Q that SYSTEM_UID won't have restricted network permission
+        // by default.
+        doReturn(VERSION_Q).when(mDeps).getDeviceFirstSdkInt();
 
-        mPermissionMonitor = spy(new PermissionMonitor(mContext, mNetdService, mDeps));
+        mPermissionMonitor = new PermissionMonitor(mContext, mNetdService, mDeps);
         mNetdMonitor = new NetdMonitor(mNetdService);
 
-        when(mPackageManager.getInstalledPackages(anyInt())).thenReturn(/* empty app list */ null);
-        mPermissionMonitor.startMonitoring();
-    }
-
-    private boolean hasRestrictedNetworkPermission(String partition, int targetSdkVersion, int uid,
-            String... permissions) {
-        return hasRestrictedNetworkPermission(
-                partition, targetSdkVersion, "" /* packageName */, uid, permissions);
+        doReturn(List.of()).when(mPackageManager).getInstalledPackages(anyInt());
     }
 
     private boolean hasRestrictedNetworkPermission(String partition, int targetSdkVersion,
@@ -223,13 +223,44 @@
 
     private static PackageInfo buildPackageInfo(String packageName, int uid,
             String... permissions) {
-        final PackageInfo pkgInfo;
-        pkgInfo = systemPackageInfoWithPermissions(permissions);
+        final PackageInfo pkgInfo = systemPackageInfoWithPermissions(permissions);
         pkgInfo.packageName = packageName;
         pkgInfo.applicationInfo.uid = uid;
         return pkgInfo;
     }
 
+    // TODO: Move this method to static lib.
+    private static @NonNull <T> T[] appendElement(Class<T> kind, @Nullable T[] array, T element) {
+        final T[] result;
+        if (array != null) {
+            result = Arrays.copyOf(array, array.length + 1);
+        } else {
+            result = (T[]) Array.newInstance(kind, 1);
+        }
+        result[result.length - 1] = element;
+        return result;
+    }
+
+    private void buildAndMockPackageInfoWithPermissions(String packageName, int uid,
+            String... permissions) throws Exception {
+        final PackageInfo packageInfo = buildPackageInfo(packageName, uid, permissions);
+        // This will return the wrong UID for the package when queried with other users.
+        doReturn(packageInfo).when(mPackageManager)
+                .getPackageInfo(eq(packageName), anyInt() /* flag */);
+        final String[] oldPackages = mPackageManager.getPackagesForUid(uid);
+        // If it's duplicated package, no need to set it again.
+        if (CollectionUtils.contains(oldPackages, packageName)) return;
+
+        // Combine the package if this uid is shared with other packages.
+        final String[] newPackages = appendElement(String.class, oldPackages, packageName);
+        doReturn(newPackages).when(mPackageManager).getPackagesForUid(eq(uid));
+    }
+
+    private void addPackage(String packageName, int uid, String... permissions) throws Exception {
+        buildAndMockPackageInfoWithPermissions(packageName, uid, permissions);
+        mPermissionMonitor.onPackageAdded(packageName, uid);
+    }
+
     @Test
     public void testHasPermission() {
         PackageInfo app = systemPackageInfoWithPermissions();
@@ -298,67 +329,77 @@
 
     @Test
     public void testHasRestrictedNetworkPermission() {
-        assertFalse(hasRestrictedNetworkPermission(PARTITION_SYSTEM, VERSION_P, MOCK_UID1));
         assertFalse(hasRestrictedNetworkPermission(
-                PARTITION_SYSTEM, VERSION_P, MOCK_UID1, CHANGE_NETWORK_STATE));
-        assertTrue(hasRestrictedNetworkPermission(
-                PARTITION_SYSTEM, VERSION_P, MOCK_UID1, NETWORK_STACK));
+                PARTITION_SYSTEM, VERSION_P, MOCK_PACKAGE1, MOCK_UID1));
         assertFalse(hasRestrictedNetworkPermission(
-                PARTITION_SYSTEM, VERSION_P, MOCK_UID1, CONNECTIVITY_INTERNAL));
+                PARTITION_SYSTEM, VERSION_P, MOCK_PACKAGE1, MOCK_UID1, CHANGE_NETWORK_STATE));
         assertTrue(hasRestrictedNetworkPermission(
-                PARTITION_SYSTEM, VERSION_P, MOCK_UID1, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
+                PARTITION_SYSTEM, VERSION_P, MOCK_PACKAGE1, MOCK_UID1, NETWORK_STACK));
         assertFalse(hasRestrictedNetworkPermission(
-                PARTITION_SYSTEM, VERSION_P, MOCK_UID1, CHANGE_WIFI_STATE));
+                PARTITION_SYSTEM, VERSION_P, MOCK_PACKAGE1, MOCK_UID1, CONNECTIVITY_INTERNAL));
         assertTrue(hasRestrictedNetworkPermission(
-                PARTITION_SYSTEM, VERSION_P, MOCK_UID1, PERMISSION_MAINLINE_NETWORK_STACK));
+                PARTITION_SYSTEM, VERSION_P, MOCK_PACKAGE1, MOCK_UID1,
+                CONNECTIVITY_USE_RESTRICTED_NETWORKS));
+        assertFalse(hasRestrictedNetworkPermission(
+                PARTITION_SYSTEM, VERSION_P, MOCK_PACKAGE1, MOCK_UID1, CHANGE_WIFI_STATE));
+        assertTrue(hasRestrictedNetworkPermission(
+                PARTITION_SYSTEM, VERSION_P, MOCK_PACKAGE1, MOCK_UID1,
+                PERMISSION_MAINLINE_NETWORK_STACK));
 
-        assertFalse(hasRestrictedNetworkPermission(PARTITION_SYSTEM, VERSION_Q, MOCK_UID1));
         assertFalse(hasRestrictedNetworkPermission(
-                PARTITION_SYSTEM, VERSION_Q, MOCK_UID1, CONNECTIVITY_INTERNAL));
+                PARTITION_SYSTEM, VERSION_Q, MOCK_PACKAGE1, MOCK_UID1));
+        assertFalse(hasRestrictedNetworkPermission(
+                PARTITION_SYSTEM, VERSION_Q, MOCK_PACKAGE1, MOCK_UID1, CONNECTIVITY_INTERNAL));
     }
 
     @Test
     public void testHasRestrictedNetworkPermissionSystemUid() {
         doReturn(VERSION_P).when(mDeps).getDeviceFirstSdkInt();
-        assertTrue(hasRestrictedNetworkPermission(PARTITION_SYSTEM, VERSION_P, SYSTEM_UID));
         assertTrue(hasRestrictedNetworkPermission(
-                PARTITION_SYSTEM, VERSION_P, SYSTEM_UID, CONNECTIVITY_INTERNAL));
+                PARTITION_SYSTEM, VERSION_P, SYSTEM_PACKAGE1, SYSTEM_UID));
         assertTrue(hasRestrictedNetworkPermission(
-                PARTITION_SYSTEM, VERSION_P, SYSTEM_UID, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
+                PARTITION_SYSTEM, VERSION_P, SYSTEM_PACKAGE1, SYSTEM_UID, CONNECTIVITY_INTERNAL));
+        assertTrue(hasRestrictedNetworkPermission(
+                PARTITION_SYSTEM, VERSION_P, SYSTEM_PACKAGE1, SYSTEM_UID,
+                CONNECTIVITY_USE_RESTRICTED_NETWORKS));
 
         doReturn(VERSION_Q).when(mDeps).getDeviceFirstSdkInt();
-        assertFalse(hasRestrictedNetworkPermission(PARTITION_SYSTEM, VERSION_Q, SYSTEM_UID));
         assertFalse(hasRestrictedNetworkPermission(
-                PARTITION_SYSTEM, VERSION_Q, SYSTEM_UID, CONNECTIVITY_INTERNAL));
+                PARTITION_SYSTEM, VERSION_Q, SYSTEM_PACKAGE1, SYSTEM_UID));
+        assertFalse(hasRestrictedNetworkPermission(
+                PARTITION_SYSTEM, VERSION_Q, SYSTEM_PACKAGE1, SYSTEM_UID, CONNECTIVITY_INTERNAL));
         assertTrue(hasRestrictedNetworkPermission(
-                PARTITION_SYSTEM, VERSION_Q, SYSTEM_UID, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
+                PARTITION_SYSTEM, VERSION_Q, SYSTEM_PACKAGE1, SYSTEM_UID,
+                CONNECTIVITY_USE_RESTRICTED_NETWORKS));
     }
 
     @Test
     public void testHasRestrictedNetworkPermissionVendorApp() {
-        assertTrue(hasRestrictedNetworkPermission(PARTITION_VENDOR, VERSION_P, MOCK_UID1));
         assertTrue(hasRestrictedNetworkPermission(
-                PARTITION_VENDOR, VERSION_P, MOCK_UID1, CHANGE_NETWORK_STATE));
+                PARTITION_VENDOR, VERSION_P, MOCK_PACKAGE1, MOCK_UID1));
         assertTrue(hasRestrictedNetworkPermission(
-                PARTITION_VENDOR, VERSION_P, MOCK_UID1, NETWORK_STACK));
+                PARTITION_VENDOR, VERSION_P, MOCK_PACKAGE1, MOCK_UID1, CHANGE_NETWORK_STATE));
         assertTrue(hasRestrictedNetworkPermission(
-                PARTITION_VENDOR, VERSION_P, MOCK_UID1, CONNECTIVITY_INTERNAL));
+                PARTITION_VENDOR, VERSION_P, MOCK_PACKAGE1, MOCK_UID1, NETWORK_STACK));
         assertTrue(hasRestrictedNetworkPermission(
-                PARTITION_VENDOR, VERSION_P, MOCK_UID1, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
+                PARTITION_VENDOR, VERSION_P, MOCK_PACKAGE1, MOCK_UID1, CONNECTIVITY_INTERNAL));
         assertTrue(hasRestrictedNetworkPermission(
-                PARTITION_VENDOR, VERSION_P, MOCK_UID1, CHANGE_WIFI_STATE));
+                PARTITION_VENDOR, VERSION_P, MOCK_PACKAGE1, MOCK_UID1,
+                CONNECTIVITY_USE_RESTRICTED_NETWORKS));
+        assertTrue(hasRestrictedNetworkPermission(
+                PARTITION_VENDOR, VERSION_P, MOCK_PACKAGE1, MOCK_UID1, CHANGE_WIFI_STATE));
 
-        assertFalse(hasRestrictedNetworkPermission(PARTITION_VENDOR, VERSION_Q, MOCK_UID1));
         assertFalse(hasRestrictedNetworkPermission(
-                PARTITION_VENDOR, VERSION_Q, MOCK_UID1, CONNECTIVITY_INTERNAL));
+                PARTITION_VENDOR, VERSION_Q, MOCK_PACKAGE1, MOCK_UID1));
         assertFalse(hasRestrictedNetworkPermission(
-                PARTITION_VENDOR, VERSION_Q, MOCK_UID1, CHANGE_NETWORK_STATE));
+                PARTITION_VENDOR, VERSION_Q, MOCK_PACKAGE1, MOCK_UID1, CONNECTIVITY_INTERNAL));
+        assertFalse(hasRestrictedNetworkPermission(
+                PARTITION_VENDOR, VERSION_Q, MOCK_PACKAGE1, MOCK_UID1, CHANGE_NETWORK_STATE));
     }
 
     @Test
     public void testHasRestrictedNetworkPermissionUidAllowedOnRestrictedNetworks() {
-        mPermissionMonitor.updateUidsAllowedOnRestrictedNetworks(
-                new ArraySet<>(new Integer[] { MOCK_UID1 }));
+        mPermissionMonitor.updateUidsAllowedOnRestrictedNetworks(Set.of(MOCK_UID1));
         assertTrue(hasRestrictedNetworkPermission(
                 PARTITION_VENDOR, VERSION_Q, MOCK_PACKAGE1, MOCK_UID1));
         assertTrue(hasRestrictedNetworkPermission(
@@ -419,32 +460,26 @@
 
     @Test
     public void testIsAppAllowedOnRestrictedNetworks() {
-        mPermissionMonitor.updateUidsAllowedOnRestrictedNetworks(new ArraySet<>());
+        mPermissionMonitor.updateUidsAllowedOnRestrictedNetworks(Set.of());
         assertFalse(wouldBeUidAllowedOnRestrictedNetworks(MOCK_UID1));
         assertFalse(wouldBeUidAllowedOnRestrictedNetworks(MOCK_UID2));
 
-        mPermissionMonitor.updateUidsAllowedOnRestrictedNetworks(
-                new ArraySet<>(new Integer[] { MOCK_UID1 }));
+        mPermissionMonitor.updateUidsAllowedOnRestrictedNetworks(Set.of(MOCK_UID1));
         assertTrue(wouldBeUidAllowedOnRestrictedNetworks(MOCK_UID1));
         assertFalse(wouldBeUidAllowedOnRestrictedNetworks(MOCK_UID2));
 
-        mPermissionMonitor.updateUidsAllowedOnRestrictedNetworks(
-                new ArraySet<>(new Integer[] { MOCK_UID2 }));
+        mPermissionMonitor.updateUidsAllowedOnRestrictedNetworks(Set.of(MOCK_UID2));
         assertFalse(wouldBeUidAllowedOnRestrictedNetworks(MOCK_UID1));
         assertTrue(wouldBeUidAllowedOnRestrictedNetworks(MOCK_UID2));
 
-        mPermissionMonitor.updateUidsAllowedOnRestrictedNetworks(
-                new ArraySet<>(new Integer[] { 123 }));
+        mPermissionMonitor.updateUidsAllowedOnRestrictedNetworks(Set.of(123));
         assertFalse(wouldBeUidAllowedOnRestrictedNetworks(MOCK_UID1));
         assertFalse(wouldBeUidAllowedOnRestrictedNetworks(MOCK_UID2));
     }
 
     private void assertBackgroundPermission(boolean hasPermission, String name, int uid,
             String... permissions) throws Exception {
-        when(mPackageManager.getPackageInfo(eq(name), anyInt()))
-                .thenReturn(packageInfoWithPermissions(
-                        REQUESTED_PERMISSION_GRANTED, permissions, PARTITION_SYSTEM));
-        mPermissionMonitor.onPackageAdded(name, uid);
+        addPackage(name, uid, permissions);
         assertEquals(hasPermission, mPermissionMonitor.hasUseBackgroundNetworksPermission(uid));
     }
 
@@ -469,21 +504,22 @@
     }
 
     private class NetdMonitor {
-        private final HashMap<Integer, Boolean> mUidsNetworkPermission = new HashMap<>();
-        private final HashMap<Integer, Integer> mAppIdsTrafficPermission = new HashMap<>();
+        private final SparseIntArray mUidsNetworkPermission = new SparseIntArray();
+        private final SparseIntArray mAppIdsTrafficPermission = new SparseIntArray();
+        private static final int DOES_NOT_EXIST = -2;
 
         NetdMonitor(INetd mockNetd) throws Exception {
             // Add hook to verify and track result of networkSetPermission.
             doAnswer((InvocationOnMock invocation) -> {
                 final Object[] args = invocation.getArguments();
-                final Boolean isSystem = args[0].equals(PERMISSION_SYSTEM);
+                final int permission = (int) args[0];
                 for (final int uid : (int[]) args[1]) {
                     // TODO: Currently, permission monitor will send duplicate commands for each uid
                     // corresponding to each user. Need to fix that and uncomment below test.
                     // if (mApps.containsKey(uid) && mApps.get(uid) == isSystem) {
                     //     fail("uid " + uid + " is already set to " + isSystem);
                     // }
-                    mUidsNetworkPermission.put(uid, isSystem);
+                    mUidsNetworkPermission.put(uid, permission);
                 }
                 return null;
             }).when(mockNetd).networkSetPermissionForUser(anyInt(), any(int[].class));
@@ -497,7 +533,7 @@
                     // if (!mApps.containsKey(uid)) {
                     //     fail("uid " + uid + " does not exist.");
                     // }
-                    mUidsNetworkPermission.remove(uid);
+                    mUidsNetworkPermission.delete(uid);
                 }
                 return null;
             }).when(mockNetd).networkClearPermissionForUser(any(int[].class));
@@ -513,11 +549,11 @@
             }).when(mockNetd).trafficSetNetPermForUids(anyInt(), any(int[].class));
         }
 
-        public void expectNetworkPerm(Boolean permission, UserHandle[] users, int... appIds) {
+        public void expectNetworkPerm(int permission, UserHandle[] users, int... appIds) {
             for (final UserHandle user : users) {
                 for (final int appId : appIds) {
                     final int uid = user.getUid(appId);
-                    if (!mUidsNetworkPermission.containsKey(uid)) {
+                    if (mUidsNetworkPermission.get(uid, DOES_NOT_EXIST) == DOES_NOT_EXIST) {
                         fail("uid " + uid + " does not exist.");
                     }
                     if (mUidsNetworkPermission.get(uid) != permission) {
@@ -531,7 +567,7 @@
             for (final UserHandle user : users) {
                 for (final int appId : appIds) {
                     final int uid = user.getUid(appId);
-                    if (mUidsNetworkPermission.containsKey(uid)) {
+                    if (mUidsNetworkPermission.get(uid, DOES_NOT_EXIST) != DOES_NOT_EXIST) {
                         fail("uid " + uid + " has listed permissions, expected none.");
                     }
                 }
@@ -540,7 +576,7 @@
 
         public void expectTrafficPerm(int permission, int... appIds) {
             for (final int appId : appIds) {
-                if (!mAppIdsTrafficPermission.containsKey(appId)) {
+                if (mAppIdsTrafficPermission.get(appId, DOES_NOT_EXIST) == DOES_NOT_EXIST) {
                     fail("appId " + appId + " does not exist.");
                 }
                 if (mAppIdsTrafficPermission.get(appId) != permission) {
@@ -554,85 +590,92 @@
     @Test
     public void testUserAndPackageAddRemove() throws Exception {
         // MOCK_UID1: MOCK_PACKAGE1 only has network permission.
-        // SYSTEM_UID: SYSTEM_PACKAGE1 has system permission.
-        // SYSTEM_UID: SYSTEM_PACKAGE2 only has network permission.
-        doReturn(SYSTEM).when(mPermissionMonitor).highestPermissionForUid(any(),
-                eq(SYSTEM_PACKAGE1));
-        doReturn(NETWORK).when(mPermissionMonitor).highestPermissionForUid(any(),
-                eq(SYSTEM_PACKAGE2));
-        doReturn(NETWORK).when(mPermissionMonitor).highestPermissionForUid(any(),
-                eq(MOCK_PACKAGE1));
-        doReturn(SYSTEM).when(mPermissionMonitor).highestPermissionForUid(eq(SYSTEM), anyString());
+        // SYSTEM_APP_UID1: SYSTEM_PACKAGE1 has system permission.
+        // SYSTEM_APP_UID1: SYSTEM_PACKAGE2 only has network permission.
+        buildAndMockPackageInfoWithPermissions(MOCK_PACKAGE1, MOCK_UID1, CHANGE_NETWORK_STATE);
+        buildAndMockPackageInfoWithPermissions(SYSTEM_PACKAGE1, SYSTEM_APP_UID1,
+                CONNECTIVITY_USE_RESTRICTED_NETWORKS);
+        buildAndMockPackageInfoWithPermissions(SYSTEM_PACKAGE2, SYSTEM_APP_UID1,
+                CHANGE_NETWORK_STATE);
 
-        // Add SYSTEM_PACKAGE2, expect only have network permission.
+        // Add user MOCK_USER1.
         mPermissionMonitor.onUserAdded(MOCK_USER1);
-        addPackageForUsers(new UserHandle[]{MOCK_USER1}, SYSTEM_PACKAGE2, SYSTEM_UID);
-        mNetdMonitor.expectNetworkPerm(NETWORK, new UserHandle[]{MOCK_USER1}, SYSTEM_UID);
+        // Add SYSTEM_PACKAGE2, expect only have network permission.
+        addPackageForUsers(new UserHandle[]{MOCK_USER1}, SYSTEM_PACKAGE2, SYSTEM_APPID1);
+        mNetdMonitor.expectNetworkPerm(PERMISSION_NETWORK, new UserHandle[]{MOCK_USER1},
+                SYSTEM_APPID1);
 
-        // Add SYSTEM_PACKAGE1, expect permission escalate.
-        addPackageForUsers(new UserHandle[]{MOCK_USER1}, SYSTEM_PACKAGE1, SYSTEM_UID);
-        mNetdMonitor.expectNetworkPerm(SYSTEM, new UserHandle[]{MOCK_USER1}, SYSTEM_UID);
+        // Add SYSTEM_PACKAGE1, expect permission upgrade.
+        addPackageForUsers(new UserHandle[]{MOCK_USER1}, SYSTEM_PACKAGE1, SYSTEM_APPID1);
+        mNetdMonitor.expectNetworkPerm(PERMISSION_SYSTEM, new UserHandle[]{MOCK_USER1},
+                SYSTEM_APPID1);
 
+        // Add user MOCK_USER2.
         mPermissionMonitor.onUserAdded(MOCK_USER2);
-        mNetdMonitor.expectNetworkPerm(SYSTEM, new UserHandle[]{MOCK_USER1, MOCK_USER2},
-                SYSTEM_UID);
+        mNetdMonitor.expectNetworkPerm(PERMISSION_SYSTEM, new UserHandle[]{MOCK_USER1, MOCK_USER2},
+                SYSTEM_APPID1);
 
         // Remove SYSTEM_PACKAGE2, expect keep system permission.
-        when(mPackageManager.getPackagesForUid(MOCK_USER1.getUid(SYSTEM_UID)))
+        when(mPackageManager.getPackagesForUid(SYSTEM_APP_UID1))
                 .thenReturn(new String[]{SYSTEM_PACKAGE1});
-        when(mPackageManager.getPackagesForUid(MOCK_USER2.getUid(SYSTEM_UID)))
+        when(mPackageManager.getPackagesForUid(MOCK_USER2.getUid(SYSTEM_APPID1)))
                 .thenReturn(new String[]{SYSTEM_PACKAGE1});
         removePackageForUsers(new UserHandle[]{MOCK_USER1, MOCK_USER2},
-                SYSTEM_PACKAGE2, SYSTEM_UID);
-        mNetdMonitor.expectNetworkPerm(SYSTEM, new UserHandle[]{MOCK_USER1, MOCK_USER2},
-                SYSTEM_UID);
+                SYSTEM_PACKAGE2, SYSTEM_APPID1);
+        mNetdMonitor.expectNetworkPerm(PERMISSION_SYSTEM, new UserHandle[]{MOCK_USER1, MOCK_USER2},
+                SYSTEM_APPID1);
 
         // Add SYSTEM_PACKAGE2, expect keep system permission.
-        addPackageForUsers(new UserHandle[]{MOCK_USER1, MOCK_USER2}, SYSTEM_PACKAGE2, SYSTEM_UID);
-        mNetdMonitor.expectNetworkPerm(SYSTEM, new UserHandle[]{MOCK_USER1, MOCK_USER2},
-                SYSTEM_UID);
+        addPackageForUsers(new UserHandle[]{MOCK_USER1, MOCK_USER2}, SYSTEM_PACKAGE2,
+                SYSTEM_APPID1);
+        mNetdMonitor.expectNetworkPerm(PERMISSION_SYSTEM, new UserHandle[]{MOCK_USER1, MOCK_USER2},
+                SYSTEM_APPID1);
 
-        addPackageForUsers(new UserHandle[]{MOCK_USER1, MOCK_USER2}, MOCK_PACKAGE1, MOCK_UID1);
-        mNetdMonitor.expectNetworkPerm(SYSTEM, new UserHandle[]{MOCK_USER1, MOCK_USER2},
-                SYSTEM_UID);
-        mNetdMonitor.expectNetworkPerm(NETWORK, new UserHandle[]{MOCK_USER1, MOCK_USER2},
-                MOCK_UID1);
+        addPackageForUsers(new UserHandle[]{MOCK_USER1, MOCK_USER2}, MOCK_PACKAGE1, MOCK_APPID1);
+        mNetdMonitor.expectNetworkPerm(PERMISSION_SYSTEM, new UserHandle[]{MOCK_USER1, MOCK_USER2},
+                SYSTEM_APPID1);
+        mNetdMonitor.expectNetworkPerm(PERMISSION_NETWORK, new UserHandle[]{MOCK_USER1, MOCK_USER2},
+                MOCK_APPID1);
 
-        // Remove MOCK_UID1, expect no permission left for all user.
-        when(mPackageManager.getPackagesForUid(MOCK_USER1.getUid(MOCK_UID1)))
+        // Remove MOCK_PACKAGE1, expect no permission left for all user.
+        when(mPackageManager.getPackagesForUid(MOCK_UID1)).thenReturn(new String[]{});
+        when(mPackageManager.getPackagesForUid(MOCK_USER2.getUid(MOCK_APPID1)))
                 .thenReturn(new String[]{});
-        when(mPackageManager.getPackagesForUid(MOCK_USER2.getUid(MOCK_UID1)))
-                .thenReturn(new String[]{});
-        mPermissionMonitor.onPackageRemoved(MOCK_PACKAGE1, MOCK_UID1);
-        removePackageForUsers(new UserHandle[]{MOCK_USER1, MOCK_USER2}, MOCK_PACKAGE1, MOCK_UID1);
-        mNetdMonitor.expectNoNetworkPerm(new UserHandle[]{MOCK_USER1, MOCK_USER2}, MOCK_UID1);
+        removePackageForUsers(new UserHandle[]{MOCK_USER1, MOCK_USER2}, MOCK_PACKAGE1, MOCK_APPID1);
+        mNetdMonitor.expectNoNetworkPerm(new UserHandle[]{MOCK_USER1, MOCK_USER2}, MOCK_APPID1);
 
         // Remove SYSTEM_PACKAGE1, expect permission downgrade.
-        when(mPackageManager.getPackagesForUid(anyInt())).thenReturn(new String[]{SYSTEM_PACKAGE2});
+        when(mPackageManager.getPackagesForUid(
+                intThat(uid -> UserHandle.getAppId(uid) == SYSTEM_APPID1)))
+                .thenReturn(new String[]{SYSTEM_PACKAGE2});
         removePackageForUsers(new UserHandle[]{MOCK_USER1, MOCK_USER2},
-                SYSTEM_PACKAGE1, SYSTEM_UID);
-        mNetdMonitor.expectNetworkPerm(NETWORK, new UserHandle[]{MOCK_USER1, MOCK_USER2},
-                SYSTEM_UID);
+                SYSTEM_PACKAGE1, SYSTEM_APPID1);
+        mNetdMonitor.expectNetworkPerm(PERMISSION_NETWORK, new UserHandle[]{MOCK_USER1, MOCK_USER2},
+                SYSTEM_APPID1);
 
         mPermissionMonitor.onUserRemoved(MOCK_USER1);
-        mNetdMonitor.expectNetworkPerm(NETWORK, new UserHandle[]{MOCK_USER2}, SYSTEM_UID);
+        mNetdMonitor.expectNetworkPerm(PERMISSION_NETWORK, new UserHandle[]{MOCK_USER2},
+                SYSTEM_APPID1);
+        mNetdMonitor.expectNoNetworkPerm(new UserHandle[]{MOCK_USER1}, SYSTEM_APPID1);
 
         // Remove all packages, expect no permission left.
-        when(mPackageManager.getPackagesForUid(anyInt())).thenReturn(new String[]{});
-        removePackageForUsers(new UserHandle[]{MOCK_USER2}, SYSTEM_PACKAGE2, SYSTEM_UID);
-        mNetdMonitor.expectNoNetworkPerm(
-                new UserHandle[]{MOCK_USER1, MOCK_USER2}, SYSTEM_UID, MOCK_UID1);
+        when(mPackageManager.getPackagesForUid(
+                intThat(uid -> UserHandle.getAppId(uid) == SYSTEM_APPID1)))
+                .thenReturn(new String[]{});
+        removePackageForUsers(new UserHandle[]{MOCK_USER2}, SYSTEM_PACKAGE2, SYSTEM_APPID1);
+        mNetdMonitor.expectNoNetworkPerm(new UserHandle[]{MOCK_USER1, MOCK_USER2}, SYSTEM_APPID1,
+                MOCK_APPID1);
 
-        // Remove last user, expect no redundant clearPermission is invoked.
+        // Remove last user, expect no permission change.
         mPermissionMonitor.onUserRemoved(MOCK_USER2);
-        mNetdMonitor.expectNoNetworkPerm(
-                new UserHandle[]{MOCK_USER1, MOCK_USER2}, SYSTEM_UID, MOCK_UID1);
+        mNetdMonitor.expectNoNetworkPerm(new UserHandle[]{MOCK_USER1, MOCK_USER2}, SYSTEM_APPID1,
+                MOCK_APPID1);
     }
 
     @Test
     public void testUidFilteringDuringVpnConnectDisconnectAndUidUpdates() throws Exception {
         when(mPackageManager.getInstalledPackages(eq(GET_PERMISSIONS | MATCH_ANY_USER))).thenReturn(
-                List.of(buildPackageInfo(SYSTEM_PACKAGE1, SYSTEM_UID1, CHANGE_NETWORK_STATE,
+                List.of(buildPackageInfo(SYSTEM_PACKAGE1, SYSTEM_APP_UID1, CHANGE_NETWORK_STATE,
                                 CONNECTIVITY_USE_RESTRICTED_NETWORKS),
                         buildPackageInfo(MOCK_PACKAGE1, MOCK_UID1),
                         buildPackageInfo(MOCK_PACKAGE2, MOCK_UID2),
@@ -640,25 +683,22 @@
         buildAndMockPackageInfoWithPermissions(MOCK_PACKAGE1, MOCK_UID1);
         mPermissionMonitor.startMonitoring();
         // Every app on user 0 except MOCK_UID2 are under VPN.
-        final Set<UidRange> vpnRange1 = new HashSet<>(Arrays.asList(new UidRange[] {
+        final Set<UidRange> vpnRange1 = Set.of(
                 new UidRange(0, MOCK_UID2 - 1),
-                new UidRange(MOCK_UID2 + 1, UserHandle.PER_USER_RANGE - 1)}));
-        final Set<UidRange> vpnRange2 = Collections.singleton(new UidRange(MOCK_UID2, MOCK_UID2));
+                new UidRange(MOCK_UID2 + 1, UserHandle.PER_USER_RANGE - 1));
+        final Set<UidRange> vpnRange2 = Set.of(new UidRange(MOCK_UID2, MOCK_UID2));
 
         // When VPN is connected, expect a rule to be set up for user app MOCK_UID1
         mPermissionMonitor.onVpnUidRangesAdded("tun0", vpnRange1, VPN_UID);
-        verify(mNetdService).firewallAddUidInterfaceRules(eq("tun0"),
-                aryEq(new int[] {MOCK_UID1}));
+        verify(mNetdService).firewallAddUidInterfaceRules(eq("tun0"), aryEq(new int[]{MOCK_UID1}));
 
         reset(mNetdService);
 
         // When MOCK_UID1 package is uninstalled and reinstalled, expect Netd to be updated
-        mPermissionMonitor.onPackageRemoved(
-                MOCK_PACKAGE1, MOCK_USER1.getUid(MOCK_UID1));
-        verify(mNetdService).firewallRemoveUidInterfaceRules(aryEq(new int[] {MOCK_UID1}));
-        mPermissionMonitor.onPackageAdded(MOCK_PACKAGE1, MOCK_USER1.getUid(MOCK_UID1));
-        verify(mNetdService).firewallAddUidInterfaceRules(eq("tun0"),
-                aryEq(new int[] {MOCK_UID1}));
+        mPermissionMonitor.onPackageRemoved(MOCK_PACKAGE1, MOCK_UID1);
+        verify(mNetdService).firewallRemoveUidInterfaceRules(aryEq(new int[]{MOCK_UID1}));
+        mPermissionMonitor.onPackageAdded(MOCK_PACKAGE1, MOCK_UID1);
+        verify(mNetdService).firewallAddUidInterfaceRules(eq("tun0"), aryEq(new int[]{MOCK_UID1}));
 
         reset(mNetdService);
 
@@ -667,8 +707,7 @@
         mPermissionMonitor.onVpnUidRangesRemoved("tun0", vpnRange1, VPN_UID);
         verify(mNetdService).firewallRemoveUidInterfaceRules(aryEq(new int[] {MOCK_UID1}));
         mPermissionMonitor.onVpnUidRangesAdded("tun0", vpnRange2, VPN_UID);
-        verify(mNetdService).firewallAddUidInterfaceRules(eq("tun0"),
-                aryEq(new int[] {MOCK_UID2}));
+        verify(mNetdService).firewallAddUidInterfaceRules(eq("tun0"), aryEq(new int[]{MOCK_UID2}));
 
         reset(mNetdService);
 
@@ -681,23 +720,21 @@
     @Test
     public void testUidFilteringDuringPackageInstallAndUninstall() throws Exception {
         when(mPackageManager.getInstalledPackages(eq(GET_PERMISSIONS | MATCH_ANY_USER))).thenReturn(
-                List.of(buildPackageInfo(SYSTEM_PACKAGE1, SYSTEM_UID1, CHANGE_NETWORK_STATE,
+                List.of(buildPackageInfo(SYSTEM_PACKAGE1, SYSTEM_APP_UID1, CHANGE_NETWORK_STATE,
                                 NETWORK_STACK, CONNECTIVITY_USE_RESTRICTED_NETWORKS),
                         buildPackageInfo(SYSTEM_PACKAGE2, VPN_UID)));
         buildAndMockPackageInfoWithPermissions(MOCK_PACKAGE1, MOCK_UID1);
 
         mPermissionMonitor.startMonitoring();
-        final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(MOCK_USER1));
+        final Set<UidRange> vpnRange = Set.of(UidRange.createForUser(MOCK_USER1));
         mPermissionMonitor.onVpnUidRangesAdded("tun0", vpnRange, VPN_UID);
 
         // Newly-installed package should have uid rules added
-        mPermissionMonitor.onPackageAdded(MOCK_PACKAGE1, MOCK_USER1.getUid(MOCK_UID1));
-        verify(mNetdService).firewallAddUidInterfaceRules(eq("tun0"),
-                aryEq(new int[] {MOCK_UID1}));
+        mPermissionMonitor.onPackageAdded(MOCK_PACKAGE1, MOCK_UID1);
+        verify(mNetdService).firewallAddUidInterfaceRules(eq("tun0"), aryEq(new int[]{MOCK_UID1}));
 
         // Removed package should have its uid rules removed
-        mPermissionMonitor.onPackageRemoved(
-                MOCK_PACKAGE1, MOCK_USER1.getUid(MOCK_UID1));
+        mPermissionMonitor.onPackageRemoved(MOCK_PACKAGE1, MOCK_UID1);
         verify(mNetdService).firewallRemoveUidInterfaceRules(aryEq(new int[] {MOCK_UID1}));
     }
 
@@ -705,138 +742,118 @@
     // Normal package add/remove operations will trigger multiple intent for uids corresponding to
     // each user. To simulate generic package operations, the onPackageAdded/Removed will need to be
     // called multiple times with the uid corresponding to each user.
-    private void addPackageForUsers(UserHandle[] users, String packageName, int uid) {
+    private void addPackageForUsers(UserHandle[] users, String packageName, int appId) {
         for (final UserHandle user : users) {
-            mPermissionMonitor.onPackageAdded(packageName, user.getUid(uid));
+            mPermissionMonitor.onPackageAdded(packageName, user.getUid(appId));
         }
     }
 
-    private void removePackageForUsers(UserHandle[] users, String packageName, int uid) {
+    private void removePackageForUsers(UserHandle[] users, String packageName, int appId) {
         for (final UserHandle user : users) {
-            mPermissionMonitor.onPackageRemoved(packageName, user.getUid(uid));
+            mPermissionMonitor.onPackageRemoved(packageName, user.getUid(appId));
         }
     }
 
     @Test
     public void testPackagePermissionUpdate() throws Exception {
-        // MOCK_UID1: MOCK_PACKAGE1 only has internet permission.
-        // MOCK_UID2: MOCK_PACKAGE2 does not have any permission.
-        // SYSTEM_UID1: SYSTEM_PACKAGE1 has internet permission and update device stats permission.
-        // SYSTEM_UID2: SYSTEM_PACKAGE2 has only update device stats permission.
+        // MOCK_APPID1: MOCK_PACKAGE1 only has internet permission.
+        // MOCK_APPID2: MOCK_PACKAGE2 does not have any permission.
+        // SYSTEM_APPID1: SYSTEM_PACKAGE1 has internet permission and update device stats permission
+        // SYSTEM_APPID2: SYSTEM_PACKAGE2 has only update device stats permission.
         SparseIntArray netdPermissionsAppIds = new SparseIntArray();
-        netdPermissionsAppIds.put(MOCK_UID1, PERMISSION_INTERNET);
-        netdPermissionsAppIds.put(MOCK_UID2, PERMISSION_NONE);
-        netdPermissionsAppIds.put(SYSTEM_UID1, PERMISSION_TRAFFIC_ALL);
-        netdPermissionsAppIds.put(SYSTEM_UID2, PERMISSION_UPDATE_DEVICE_STATS);
+        netdPermissionsAppIds.put(MOCK_APPID1, PERMISSION_INTERNET);
+        netdPermissionsAppIds.put(MOCK_APPID2, PERMISSION_NONE);
+        netdPermissionsAppIds.put(SYSTEM_APPID1, PERMISSION_TRAFFIC_ALL);
+        netdPermissionsAppIds.put(SYSTEM_APPID2, PERMISSION_UPDATE_DEVICE_STATS);
 
         // Send the permission information to netd, expect permission updated.
         mPermissionMonitor.sendPackagePermissionsToNetd(netdPermissionsAppIds);
 
-        mNetdMonitor.expectTrafficPerm(PERMISSION_INTERNET, MOCK_UID1);
-        mNetdMonitor.expectTrafficPerm(PERMISSION_NONE, MOCK_UID2);
-        mNetdMonitor.expectTrafficPerm(PERMISSION_TRAFFIC_ALL, SYSTEM_UID1);
-        mNetdMonitor.expectTrafficPerm(PERMISSION_UPDATE_DEVICE_STATS, SYSTEM_UID2);
+        mNetdMonitor.expectTrafficPerm(PERMISSION_INTERNET, MOCK_APPID1);
+        mNetdMonitor.expectTrafficPerm(PERMISSION_NONE, MOCK_APPID2);
+        mNetdMonitor.expectTrafficPerm(PERMISSION_TRAFFIC_ALL, SYSTEM_APPID1);
+        mNetdMonitor.expectTrafficPerm(PERMISSION_UPDATE_DEVICE_STATS, SYSTEM_APPID2);
 
-        // Update permission of MOCK_UID1, expect new permission show up.
-        mPermissionMonitor.sendPackagePermissionsForUid(MOCK_UID1, PERMISSION_TRAFFIC_ALL);
-        mNetdMonitor.expectTrafficPerm(PERMISSION_TRAFFIC_ALL, MOCK_UID1);
+        // Update permission of MOCK_APPID1, expect new permission show up.
+        mPermissionMonitor.sendPackagePermissionsForAppId(MOCK_APPID1, PERMISSION_TRAFFIC_ALL);
+        mNetdMonitor.expectTrafficPerm(PERMISSION_TRAFFIC_ALL, MOCK_APPID1);
 
-        // Change permissions of SYSTEM_UID2, expect new permission show up and old permission
+        // Change permissions of SYSTEM_APPID2, expect new permission show up and old permission
         // revoked.
-        mPermissionMonitor.sendPackagePermissionsForUid(SYSTEM_UID2, PERMISSION_INTERNET);
-        mNetdMonitor.expectTrafficPerm(PERMISSION_INTERNET, SYSTEM_UID2);
+        mPermissionMonitor.sendPackagePermissionsForAppId(SYSTEM_APPID2, PERMISSION_INTERNET);
+        mNetdMonitor.expectTrafficPerm(PERMISSION_INTERNET, SYSTEM_APPID2);
 
-        // Revoke permission from SYSTEM_UID1, expect no permission stored.
-        mPermissionMonitor.sendPackagePermissionsForUid(SYSTEM_UID1, PERMISSION_NONE);
-        mNetdMonitor.expectTrafficPerm(PERMISSION_NONE, SYSTEM_UID1);
-    }
-
-    private PackageInfo setPackagePermissions(String packageName, int uid, String[] permissions)
-            throws Exception {
-        PackageInfo packageInfo = packageInfoWithPermissions(
-                REQUESTED_PERMISSION_GRANTED, permissions, PARTITION_SYSTEM);
-        when(mPackageManager.getPackageInfo(eq(packageName), anyInt())).thenReturn(packageInfo);
-        when(mPackageManager.getPackagesForUid(eq(uid))).thenReturn(new String[]{packageName});
-        return packageInfo;
-    }
-
-    private PackageInfo addPackage(String packageName, int uid, String[] permissions)
-            throws Exception {
-        PackageInfo packageInfo = setPackagePermissions(packageName, uid, permissions);
-        mPermissionMonitor.onPackageAdded(packageName, uid);
-        return packageInfo;
+        // Revoke permission from SYSTEM_APPID1, expect no permission stored.
+        mPermissionMonitor.sendPackagePermissionsForAppId(SYSTEM_APPID1, PERMISSION_NONE);
+        mNetdMonitor.expectTrafficPerm(PERMISSION_NONE, SYSTEM_APPID1);
     }
 
     @Test
     public void testPackageInstall() throws Exception {
-        addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET, UPDATE_DEVICE_STATS});
-        mNetdMonitor.expectTrafficPerm(PERMISSION_TRAFFIC_ALL, MOCK_UID1);
+        addPackage(MOCK_PACKAGE1, MOCK_UID1, INTERNET, UPDATE_DEVICE_STATS);
+        mNetdMonitor.expectTrafficPerm(PERMISSION_TRAFFIC_ALL, MOCK_APPID1);
 
-        addPackage(MOCK_PACKAGE2, MOCK_UID2, new String[] {INTERNET});
-        mNetdMonitor.expectTrafficPerm(PERMISSION_INTERNET, MOCK_UID2);
+        addPackage(MOCK_PACKAGE2, MOCK_UID2, INTERNET);
+        mNetdMonitor.expectTrafficPerm(PERMISSION_INTERNET, MOCK_APPID2);
     }
 
     @Test
     public void testPackageInstallSharedUid() throws Exception {
-        PackageInfo packageInfo1 = addPackage(MOCK_PACKAGE1, MOCK_UID1,
-                new String[] {INTERNET, UPDATE_DEVICE_STATS});
-        mNetdMonitor.expectTrafficPerm(PERMISSION_TRAFFIC_ALL, MOCK_UID1);
+        addPackage(MOCK_PACKAGE1, MOCK_UID1, INTERNET, UPDATE_DEVICE_STATS);
+        mNetdMonitor.expectTrafficPerm(PERMISSION_TRAFFIC_ALL, MOCK_APPID1);
 
-        // Install another package with the same uid and no permissions should not cause the UID to
-        // lose permissions.
-        PackageInfo packageInfo2 = systemPackageInfoWithPermissions();
-        when(mPackageManager.getPackageInfo(eq(MOCK_PACKAGE2), anyInt())).thenReturn(packageInfo2);
-        when(mPackageManager.getPackagesForUid(MOCK_UID1))
-              .thenReturn(new String[]{MOCK_PACKAGE1, MOCK_PACKAGE2});
-        mPermissionMonitor.onPackageAdded(MOCK_PACKAGE2, MOCK_UID1);
-        mNetdMonitor.expectTrafficPerm(PERMISSION_TRAFFIC_ALL, MOCK_UID1);
+        // Install another package with the same uid and no permissions should not cause the app id
+        // to lose permissions.
+        addPackage(MOCK_PACKAGE2, MOCK_UID1);
+        mNetdMonitor.expectTrafficPerm(PERMISSION_TRAFFIC_ALL, MOCK_APPID1);
     }
 
     @Test
     public void testPackageUninstallBasic() throws Exception {
-        addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET, UPDATE_DEVICE_STATS});
-        mNetdMonitor.expectTrafficPerm(PERMISSION_TRAFFIC_ALL, MOCK_UID1);
+        addPackage(MOCK_PACKAGE1, MOCK_UID1, INTERNET, UPDATE_DEVICE_STATS);
+        mNetdMonitor.expectTrafficPerm(PERMISSION_TRAFFIC_ALL, MOCK_APPID1);
 
         when(mPackageManager.getPackagesForUid(MOCK_UID1)).thenReturn(new String[]{});
         mPermissionMonitor.onPackageRemoved(MOCK_PACKAGE1, MOCK_UID1);
-        mNetdMonitor.expectTrafficPerm(PERMISSION_UNINSTALLED, MOCK_UID1);
+        mNetdMonitor.expectTrafficPerm(PERMISSION_UNINSTALLED, MOCK_APPID1);
     }
 
     @Test
     public void testPackageRemoveThenAdd() throws Exception {
-        addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET, UPDATE_DEVICE_STATS});
-        mNetdMonitor.expectTrafficPerm(PERMISSION_TRAFFIC_ALL, MOCK_UID1);
+        addPackage(MOCK_PACKAGE1, MOCK_UID1, INTERNET, UPDATE_DEVICE_STATS);
+        mNetdMonitor.expectTrafficPerm(PERMISSION_TRAFFIC_ALL, MOCK_APPID1);
 
         when(mPackageManager.getPackagesForUid(MOCK_UID1)).thenReturn(new String[]{});
         mPermissionMonitor.onPackageRemoved(MOCK_PACKAGE1, MOCK_UID1);
-        mNetdMonitor.expectTrafficPerm(PERMISSION_UNINSTALLED, MOCK_UID1);
+        mNetdMonitor.expectTrafficPerm(PERMISSION_UNINSTALLED, MOCK_APPID1);
 
-        addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET});
-        mNetdMonitor.expectTrafficPerm(PERMISSION_INTERNET, MOCK_UID1);
+        addPackage(MOCK_PACKAGE1, MOCK_UID1, INTERNET);
+        mNetdMonitor.expectTrafficPerm(PERMISSION_INTERNET, MOCK_APPID1);
     }
 
     @Test
     public void testPackageUpdate() throws Exception {
-        addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {});
-        mNetdMonitor.expectTrafficPerm(PERMISSION_NONE, MOCK_UID1);
+        addPackage(MOCK_PACKAGE1, MOCK_UID1);
+        mNetdMonitor.expectTrafficPerm(PERMISSION_NONE, MOCK_APPID1);
 
-        addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET});
-        mNetdMonitor.expectTrafficPerm(PERMISSION_INTERNET, MOCK_UID1);
+        addPackage(MOCK_PACKAGE1, MOCK_UID1, INTERNET);
+        mNetdMonitor.expectTrafficPerm(PERMISSION_INTERNET, MOCK_APPID1);
     }
 
     @Test
     public void testPackageUninstallWithMultiplePackages() throws Exception {
-        addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET, UPDATE_DEVICE_STATS});
+        addPackage(MOCK_PACKAGE1, MOCK_UID1, INTERNET, UPDATE_DEVICE_STATS);
+        mNetdMonitor.expectTrafficPerm(PERMISSION_TRAFFIC_ALL, MOCK_APPID1);
+
+        // Install another package with the same uid but different permissions.
+        addPackage(MOCK_PACKAGE2, MOCK_UID1, INTERNET);
         mNetdMonitor.expectTrafficPerm(PERMISSION_TRAFFIC_ALL, MOCK_UID1);
 
-        // Mock another package with the same uid but different permissions.
-        PackageInfo packageInfo2 = systemPackageInfoWithPermissions(INTERNET);
-        when(mPackageManager.getPackageInfo(eq(MOCK_PACKAGE2), anyInt())).thenReturn(packageInfo2);
-        when(mPackageManager.getPackagesForUid(MOCK_UID1)).thenReturn(new String[]{
-                MOCK_PACKAGE2});
-
+        // Uninstall MOCK_PACKAGE1 and expect only INTERNET permission left.
+        when(mPackageManager.getPackagesForUid(eq(MOCK_UID1)))
+                .thenReturn(new String[]{MOCK_PACKAGE2});
         mPermissionMonitor.onPackageRemoved(MOCK_PACKAGE1, MOCK_UID1);
-        mNetdMonitor.expectTrafficPerm(PERMISSION_INTERNET, MOCK_UID1);
+        mNetdMonitor.expectTrafficPerm(PERMISSION_INTERNET, MOCK_APPID1);
     }
 
     @Test
@@ -853,15 +870,14 @@
 
     @Test
     public void testUpdateUidPermissionsFromSystemConfig() throws Exception {
-        when(mPackageManager.getInstalledPackages(anyInt())).thenReturn(new ArrayList<>());
         when(mSystemConfigManager.getSystemPermissionUids(eq(INTERNET)))
                 .thenReturn(new int[]{ MOCK_UID1, MOCK_UID2 });
         when(mSystemConfigManager.getSystemPermissionUids(eq(UPDATE_DEVICE_STATS)))
                 .thenReturn(new int[]{ MOCK_UID2 });
 
         mPermissionMonitor.startMonitoring();
-        mNetdMonitor.expectTrafficPerm(PERMISSION_INTERNET, MOCK_UID1);
-        mNetdMonitor.expectTrafficPerm(PERMISSION_TRAFFIC_ALL, MOCK_UID2);
+        mNetdMonitor.expectTrafficPerm(PERMISSION_INTERNET, MOCK_APPID1);
+        mNetdMonitor.expectTrafficPerm(PERMISSION_TRAFFIC_ALL, MOCK_APPID2);
     }
 
     private BroadcastReceiver expectBroadcastReceiver(String... actions) {
@@ -881,6 +897,7 @@
 
     @Test
     public void testIntentReceiver() throws Exception {
+        mPermissionMonitor.startMonitoring();
         final BroadcastReceiver receiver = expectBroadcastReceiver(
                 Intent.ACTION_PACKAGE_ADDED, Intent.ACTION_PACKAGE_REMOVED);
 
@@ -888,18 +905,18 @@
         final Intent addedIntent = new Intent(Intent.ACTION_PACKAGE_ADDED,
                 Uri.fromParts("package", MOCK_PACKAGE1, null /* fragment */));
         addedIntent.putExtra(Intent.EXTRA_UID, MOCK_UID1);
-        setPackagePermissions(MOCK_PACKAGE1, MOCK_UID1,
-                new String[] { INTERNET, UPDATE_DEVICE_STATS });
+        buildAndMockPackageInfoWithPermissions(MOCK_PACKAGE1, MOCK_UID1, INTERNET,
+                UPDATE_DEVICE_STATS);
         receiver.onReceive(mContext, addedIntent);
-        mNetdMonitor.expectTrafficPerm(PERMISSION_TRAFFIC_ALL, MOCK_UID1);
+        mNetdMonitor.expectTrafficPerm(PERMISSION_TRAFFIC_ALL, MOCK_APPID1);
 
         // Verify receiving PACKAGE_REMOVED intent.
-        when(mPackageManager.getPackagesForUid(MOCK_UID1)).thenReturn(null);
+        when(mPackageManager.getPackagesForUid(MOCK_UID1)).thenReturn(new String[]{});
         final Intent removedIntent = new Intent(Intent.ACTION_PACKAGE_REMOVED,
                 Uri.fromParts("package", MOCK_PACKAGE1, null /* fragment */));
         removedIntent.putExtra(Intent.EXTRA_UID, MOCK_UID1);
         receiver.onReceive(mContext, removedIntent);
-        mNetdMonitor.expectTrafficPerm(PERMISSION_UNINSTALLED, MOCK_UID1);
+        mNetdMonitor.expectTrafficPerm(PERMISSION_UNINSTALLED, MOCK_APPID1);
     }
 
     private ContentObserver expectRegisterContentObserver(Uri expectedUri) {
@@ -910,138 +927,132 @@
         return captor.getValue();
     }
 
-    private void buildAndMockPackageInfoWithPermissions(String packageName, int uid,
-            String... permissions) throws Exception {
-        final PackageInfo packageInfo = setPackagePermissions(packageName, uid, permissions);
-        packageInfo.packageName = packageName;
-        packageInfo.applicationInfo.uid = uid;
-    }
-
     @Test
     public void testUidsAllowedOnRestrictedNetworksChanged() throws Exception {
+        mPermissionMonitor.startMonitoring();
         final ContentObserver contentObserver = expectRegisterContentObserver(
                 Settings.Global.getUriFor(UIDS_ALLOWED_ON_RESTRICTED_NETWORKS));
 
-        mPermissionMonitor.onUserAdded(MOCK_USER1);
         // Prepare PackageInfo for MOCK_PACKAGE1 and MOCK_PACKAGE2
         buildAndMockPackageInfoWithPermissions(MOCK_PACKAGE1, MOCK_UID1);
         buildAndMockPackageInfoWithPermissions(MOCK_PACKAGE2, MOCK_UID2);
 
         // MOCK_UID1 is listed in setting that allow to use restricted networks, MOCK_UID1
         // should have SYSTEM permission.
-        when(mDeps.getUidsAllowedOnRestrictedNetworks(any())).thenReturn(
-                new ArraySet<>(new Integer[] { MOCK_UID1 }));
+        when(mDeps.getUidsAllowedOnRestrictedNetworks(any())).thenReturn(Set.of(MOCK_UID1));
         contentObserver.onChange(true /* selfChange */);
-        mNetdMonitor.expectNetworkPerm(SYSTEM, new UserHandle[]{MOCK_USER1}, MOCK_UID1);
-        mNetdMonitor.expectNoNetworkPerm(new UserHandle[]{MOCK_USER1}, MOCK_UID2);
+        mNetdMonitor.expectNetworkPerm(PERMISSION_SYSTEM, new UserHandle[]{MOCK_USER1},
+                MOCK_APPID1);
+        mNetdMonitor.expectNoNetworkPerm(new UserHandle[]{MOCK_USER1}, MOCK_APPID2);
 
         // MOCK_UID2 is listed in setting that allow to use restricted networks, MOCK_UID2
         // should have SYSTEM permission but MOCK_UID1 should revoke permission.
-        when(mDeps.getUidsAllowedOnRestrictedNetworks(any())).thenReturn(
-                new ArraySet<>(new Integer[] { MOCK_UID2 }));
+        when(mDeps.getUidsAllowedOnRestrictedNetworks(any())).thenReturn(Set.of(MOCK_UID2));
         contentObserver.onChange(true /* selfChange */);
-        mNetdMonitor.expectNetworkPerm(SYSTEM, new UserHandle[]{MOCK_USER1}, MOCK_UID2);
-        mNetdMonitor.expectNoNetworkPerm(new UserHandle[]{MOCK_USER1}, MOCK_UID1);
+        mNetdMonitor.expectNetworkPerm(PERMISSION_SYSTEM, new UserHandle[]{MOCK_USER1},
+                MOCK_APPID2);
+        mNetdMonitor.expectNoNetworkPerm(new UserHandle[]{MOCK_USER1}, MOCK_APPID1);
 
         // No uid lists in setting, should revoke permission from all uids.
-        when(mDeps.getUidsAllowedOnRestrictedNetworks(any())).thenReturn(new ArraySet<>());
+        when(mDeps.getUidsAllowedOnRestrictedNetworks(any())).thenReturn(Set.of());
         contentObserver.onChange(true /* selfChange */);
-        mNetdMonitor.expectNoNetworkPerm(new UserHandle[]{MOCK_USER1}, MOCK_UID1, MOCK_UID2);
+        mNetdMonitor.expectNoNetworkPerm(new UserHandle[]{MOCK_USER1}, MOCK_APPID1, MOCK_APPID2);
     }
 
     @Test
     public void testUidsAllowedOnRestrictedNetworksChangedWithSharedUid() throws Exception {
+        mPermissionMonitor.startMonitoring();
         final ContentObserver contentObserver = expectRegisterContentObserver(
                 Settings.Global.getUriFor(UIDS_ALLOWED_ON_RESTRICTED_NETWORKS));
 
-        mPermissionMonitor.onUserAdded(MOCK_USER1);
         buildAndMockPackageInfoWithPermissions(MOCK_PACKAGE1, MOCK_UID1, CHANGE_NETWORK_STATE);
         buildAndMockPackageInfoWithPermissions(MOCK_PACKAGE2, MOCK_UID1);
-        when(mPackageManager.getPackagesForUid(MOCK_UID1))
-                .thenReturn(new String[]{MOCK_PACKAGE1, MOCK_PACKAGE2});
 
         // MOCK_PACKAGE1 have CHANGE_NETWORK_STATE, MOCK_UID1 should have NETWORK permission.
-        addPackageForUsers(new UserHandle[]{MOCK_USER1}, MOCK_PACKAGE1, MOCK_UID1);
-        mNetdMonitor.expectNetworkPerm(NETWORK, new UserHandle[]{MOCK_USER1}, MOCK_UID1);
+        addPackageForUsers(new UserHandle[]{MOCK_USER1}, MOCK_PACKAGE1, MOCK_APPID1);
+        mNetdMonitor.expectNetworkPerm(PERMISSION_NETWORK, new UserHandle[]{MOCK_USER1},
+                MOCK_APPID1);
 
         // MOCK_UID1 is listed in setting that allow to use restricted networks, MOCK_UID1
         // should upgrade to SYSTEM permission.
-        when(mDeps.getUidsAllowedOnRestrictedNetworks(any())).thenReturn(
-                new ArraySet<>(new Integer[] { MOCK_UID1 }));
+        when(mDeps.getUidsAllowedOnRestrictedNetworks(any())).thenReturn(Set.of(MOCK_UID1));
         contentObserver.onChange(true /* selfChange */);
-        mNetdMonitor.expectNetworkPerm(SYSTEM, new UserHandle[]{MOCK_USER1}, MOCK_UID1);
+        mNetdMonitor.expectNetworkPerm(PERMISSION_SYSTEM, new UserHandle[]{MOCK_USER1},
+                MOCK_APPID1);
 
         // No app lists in setting, MOCK_UID1 should downgrade to NETWORK permission.
-        when(mDeps.getUidsAllowedOnRestrictedNetworks(any())).thenReturn(new ArraySet<>());
+        when(mDeps.getUidsAllowedOnRestrictedNetworks(any())).thenReturn(Set.of());
         contentObserver.onChange(true /* selfChange */);
-        mNetdMonitor.expectNetworkPerm(NETWORK, new UserHandle[]{MOCK_USER1}, MOCK_UID1);
+        mNetdMonitor.expectNetworkPerm(PERMISSION_NETWORK, new UserHandle[]{MOCK_USER1},
+                MOCK_APPID1);
 
         // MOCK_PACKAGE1 removed, should revoke permission from MOCK_UID1.
         when(mPackageManager.getPackagesForUid(MOCK_UID1)).thenReturn(new String[]{MOCK_PACKAGE2});
-        removePackageForUsers(new UserHandle[]{MOCK_USER1}, MOCK_PACKAGE1, MOCK_UID1);
-        mNetdMonitor.expectNoNetworkPerm(new UserHandle[]{MOCK_USER1}, MOCK_UID1);
+        removePackageForUsers(new UserHandle[]{MOCK_USER1}, MOCK_PACKAGE1, MOCK_APPID1);
+        mNetdMonitor.expectNoNetworkPerm(new UserHandle[]{MOCK_USER1}, MOCK_APPID1);
     }
 
     @Test
     public void testUidsAllowedOnRestrictedNetworksChangedWithMultipleUsers() throws Exception {
+        mPermissionMonitor.startMonitoring();
         final ContentObserver contentObserver = expectRegisterContentObserver(
                 Settings.Global.getUriFor(UIDS_ALLOWED_ON_RESTRICTED_NETWORKS));
 
-        // One user MOCK_USER1
-        mPermissionMonitor.onUserAdded(MOCK_USER1);
         // Prepare PackageInfo for MOCK_PACKAGE1 and MOCK_PACKAGE2.
         buildAndMockPackageInfoWithPermissions(MOCK_PACKAGE1, MOCK_UID1);
         buildAndMockPackageInfoWithPermissions(MOCK_PACKAGE2, MOCK_UID2);
 
         // MOCK_UID1 is listed in setting that allow to use restricted networks, MOCK_UID1
-        // in MOCK_USER1 should have SYSTEM permission and MOCK_UID2 has no permissions.
-        when(mDeps.getUidsAllowedOnRestrictedNetworks(any())).thenReturn(
-                new ArraySet<>(new Integer[] { MOCK_UID1 }));
+        // should have SYSTEM permission and MOCK_UID2 has no permissions.
+        when(mDeps.getUidsAllowedOnRestrictedNetworks(any())).thenReturn(Set.of(MOCK_UID1));
         contentObserver.onChange(true /* selfChange */);
-        mNetdMonitor.expectNetworkPerm(SYSTEM, new UserHandle[]{MOCK_USER1}, MOCK_UID1);
-        mNetdMonitor.expectNoNetworkPerm(new UserHandle[]{MOCK_USER1}, MOCK_UID2);
+        mNetdMonitor.expectNetworkPerm(PERMISSION_SYSTEM, new UserHandle[]{MOCK_USER1},
+                MOCK_APPID1);
+        mNetdMonitor.expectNoNetworkPerm(new UserHandle[]{MOCK_USER1}, MOCK_APPID2);
 
         // Add user MOCK_USER2.
         mPermissionMonitor.onUserAdded(MOCK_USER2);
-        // MOCK_UID1 in both users should all have SYSTEM permission and MOCK_UID2 has no
+        // MOCK_APPID1 in both users should all have SYSTEM permission and MOCK_APPID2 has no
         // permissions in either user.
-        mNetdMonitor.expectNetworkPerm(SYSTEM, new UserHandle[]{MOCK_USER1, MOCK_USER2}, MOCK_UID1);
-        mNetdMonitor.expectNoNetworkPerm(new UserHandle[]{MOCK_USER1, MOCK_USER2}, MOCK_UID2);
+        mNetdMonitor.expectNetworkPerm(PERMISSION_SYSTEM, new UserHandle[]{MOCK_USER1, MOCK_USER2},
+                MOCK_APPID1);
+        mNetdMonitor.expectNoNetworkPerm(new UserHandle[]{MOCK_USER1, MOCK_USER2}, MOCK_APPID2);
 
-        // MOCK_UID2 is listed in setting that allow to use restricted networks, MOCK_UID2
-        // in both users should have SYSTEM permission and MOCK_UID1 has no permissions.
-        when(mDeps.getUidsAllowedOnRestrictedNetworks(any())).thenReturn(
-                new ArraySet<>(new Integer[] { MOCK_UID2 }));
+        // MOCK_UID2 is listed in setting that allow to use restricted networks, MOCK_APPID2
+        // in both users should have SYSTEM permission and MOCK_APPID1 has no permissions in either
+        // user.
+        when(mDeps.getUidsAllowedOnRestrictedNetworks(any())).thenReturn(Set.of(MOCK_UID2));
         contentObserver.onChange(true /* selfChange */);
-        mNetdMonitor.expectNetworkPerm(SYSTEM, new UserHandle[]{MOCK_USER1, MOCK_USER2}, MOCK_UID2);
-        mNetdMonitor.expectNoNetworkPerm(new UserHandle[]{MOCK_USER1, MOCK_USER2}, MOCK_UID1);
+        mNetdMonitor.expectNetworkPerm(PERMISSION_SYSTEM, new UserHandle[]{MOCK_USER1, MOCK_USER2},
+                MOCK_APPID2);
+        mNetdMonitor.expectNoNetworkPerm(new UserHandle[]{MOCK_USER1, MOCK_USER2}, MOCK_APPID1);
 
         // Remove user MOCK_USER1
         mPermissionMonitor.onUserRemoved(MOCK_USER1);
-        mNetdMonitor.expectNetworkPerm(SYSTEM, new UserHandle[]{MOCK_USER2}, MOCK_UID2);
-        mNetdMonitor.expectNoNetworkPerm(new UserHandle[]{MOCK_USER2}, MOCK_UID1);
+        mNetdMonitor.expectNetworkPerm(PERMISSION_SYSTEM, new UserHandle[]{MOCK_USER2},
+                MOCK_APPID2);
+        mNetdMonitor.expectNoNetworkPerm(new UserHandle[]{MOCK_USER2}, MOCK_APPID1);
+        mNetdMonitor.expectNoNetworkPerm(new UserHandle[]{MOCK_USER1}, MOCK_APPID2);
 
         // No uid lists in setting, should revoke permission from all uids.
-        when(mDeps.getUidsAllowedOnRestrictedNetworks(any())).thenReturn(new ArraySet<>());
+        when(mDeps.getUidsAllowedOnRestrictedNetworks(any())).thenReturn(Set.of());
         contentObserver.onChange(true /* selfChange */);
-        mNetdMonitor.expectNoNetworkPerm(new UserHandle[]{MOCK_USER2}, MOCK_UID1, MOCK_UID2);
+        mNetdMonitor.expectNoNetworkPerm(new UserHandle[]{MOCK_USER2}, MOCK_APPID1, MOCK_APPID2);
     }
 
     @Test
     public void testOnExternalApplicationsAvailable() throws Exception {
-        final BroadcastReceiver receiver = expectBroadcastReceiver(
-                Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
-
         // Initial the permission state. MOCK_PACKAGE1 and MOCK_PACKAGE2 are installed on external
         // and have different uids. There has no permission for both uids.
-        when(mUserManager.getUserHandles(eq(true))).thenReturn(List.of(MOCK_USER1));
         when(mPackageManager.getInstalledPackages(eq(GET_PERMISSIONS | MATCH_ANY_USER))).thenReturn(
                 List.of(buildPackageInfo(MOCK_PACKAGE1, MOCK_UID1),
                         buildPackageInfo(MOCK_PACKAGE2, MOCK_UID2)));
         mPermissionMonitor.startMonitoring();
-        mNetdMonitor.expectNoNetworkPerm(new UserHandle[]{MOCK_USER1}, MOCK_UID1, MOCK_UID2);
-        mNetdMonitor.expectTrafficPerm(PERMISSION_NONE, MOCK_UID1, MOCK_UID2);
+        mNetdMonitor.expectNoNetworkPerm(new UserHandle[]{MOCK_USER1}, MOCK_APPID1, MOCK_APPID2);
+        mNetdMonitor.expectTrafficPerm(PERMISSION_NONE, MOCK_APPID1, MOCK_APPID2);
 
+        final BroadcastReceiver receiver = expectBroadcastReceiver(
+                Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
         // Verify receiving EXTERNAL_APPLICATIONS_AVAILABLE intent and update permission to netd.
         final Intent externalIntent = new Intent(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
         externalIntent.putExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST,
@@ -1051,21 +1062,21 @@
         buildAndMockPackageInfoWithPermissions(MOCK_PACKAGE2, MOCK_UID2, CHANGE_NETWORK_STATE,
                 UPDATE_DEVICE_STATS);
         receiver.onReceive(mContext, externalIntent);
-        mNetdMonitor.expectNetworkPerm(SYSTEM, new UserHandle[]{MOCK_USER1}, MOCK_UID1);
-        mNetdMonitor.expectNetworkPerm(NETWORK, new UserHandle[]{MOCK_USER1}, MOCK_UID2);
-        mNetdMonitor.expectTrafficPerm(PERMISSION_INTERNET, MOCK_UID1);
-        mNetdMonitor.expectTrafficPerm(PERMISSION_UPDATE_DEVICE_STATS, MOCK_UID2);
+        mNetdMonitor.expectNetworkPerm(PERMISSION_SYSTEM, new UserHandle[]{MOCK_USER1},
+                MOCK_APPID1);
+        mNetdMonitor.expectNetworkPerm(PERMISSION_NETWORK, new UserHandle[]{MOCK_USER1},
+                MOCK_APPID2);
+        mNetdMonitor.expectTrafficPerm(PERMISSION_INTERNET, MOCK_APPID1);
+        mNetdMonitor.expectTrafficPerm(PERMISSION_UPDATE_DEVICE_STATS, MOCK_APPID2);
     }
 
     @Test
     public void testOnExternalApplicationsAvailable_AppsNotRegisteredOnStartMonitoring()
             throws Exception {
+        mPermissionMonitor.startMonitoring();
         final BroadcastReceiver receiver = expectBroadcastReceiver(
                 Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
 
-        // One user MOCK_USER1
-        mPermissionMonitor.onUserAdded(MOCK_USER1);
-
         // Initial the permission state. MOCK_PACKAGE1 and MOCK_PACKAGE2 are installed on external
         // and have different uids. There has no permission for both uids.
         buildAndMockPackageInfoWithPermissions(MOCK_PACKAGE1, MOCK_UID1,
@@ -1078,58 +1089,56 @@
         externalIntent.putExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST,
                 new String[] { MOCK_PACKAGE1 , MOCK_PACKAGE2});
         receiver.onReceive(mContext, externalIntent);
-        mNetdMonitor.expectNetworkPerm(SYSTEM, new UserHandle[]{MOCK_USER1}, MOCK_UID1);
-        mNetdMonitor.expectNetworkPerm(NETWORK, new UserHandle[]{MOCK_USER1}, MOCK_UID2);
-        mNetdMonitor.expectTrafficPerm(PERMISSION_INTERNET, MOCK_UID1);
-        mNetdMonitor.expectTrafficPerm(PERMISSION_UPDATE_DEVICE_STATS, MOCK_UID2);
+        mNetdMonitor.expectNetworkPerm(PERMISSION_SYSTEM, new UserHandle[]{MOCK_USER1},
+                MOCK_APPID1);
+        mNetdMonitor.expectNetworkPerm(PERMISSION_NETWORK, new UserHandle[]{MOCK_USER1},
+                MOCK_APPID2);
+        mNetdMonitor.expectTrafficPerm(PERMISSION_INTERNET, MOCK_APPID1);
+        mNetdMonitor.expectTrafficPerm(PERMISSION_UPDATE_DEVICE_STATS, MOCK_APPID2);
     }
 
     @Test
     public void testOnExternalApplicationsAvailableWithSharedUid()
             throws Exception {
-        final BroadcastReceiver receiver = expectBroadcastReceiver(
-                Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
-
         // Initial the permission state. MOCK_PACKAGE1 and MOCK_PACKAGE2 are installed on external
         // storage and shared on MOCK_UID1. There has no permission for MOCK_UID1.
-        when(mUserManager.getUserHandles(eq(true))).thenReturn(List.of(MOCK_USER1));
         when(mPackageManager.getInstalledPackages(eq(GET_PERMISSIONS | MATCH_ANY_USER))).thenReturn(
                 List.of(buildPackageInfo(MOCK_PACKAGE1, MOCK_UID1),
                         buildPackageInfo(MOCK_PACKAGE2, MOCK_UID1)));
         mPermissionMonitor.startMonitoring();
-        mNetdMonitor.expectNoNetworkPerm(new UserHandle[]{MOCK_USER1}, MOCK_UID1);
-        mNetdMonitor.expectTrafficPerm(PERMISSION_NONE, MOCK_UID1);
+        mNetdMonitor.expectNoNetworkPerm(new UserHandle[]{MOCK_USER1}, MOCK_APPID1);
+        mNetdMonitor.expectTrafficPerm(PERMISSION_NONE, MOCK_APPID1);
 
+        final BroadcastReceiver receiver = expectBroadcastReceiver(
+                Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
         // Verify receiving EXTERNAL_APPLICATIONS_AVAILABLE intent and update permission to netd.
         final Intent externalIntent = new Intent(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
         externalIntent.putExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST, new String[] {MOCK_PACKAGE1});
         buildAndMockPackageInfoWithPermissions(MOCK_PACKAGE1, MOCK_UID1, CHANGE_NETWORK_STATE);
         buildAndMockPackageInfoWithPermissions(MOCK_PACKAGE2, MOCK_UID1, UPDATE_DEVICE_STATS);
-        when(mPackageManager.getPackagesForUid(MOCK_UID1))
-                .thenReturn(new String[]{MOCK_PACKAGE1, MOCK_PACKAGE2});
         receiver.onReceive(mContext, externalIntent);
-        mNetdMonitor.expectNetworkPerm(NETWORK, new UserHandle[]{MOCK_USER1}, MOCK_UID1);
-        mNetdMonitor.expectTrafficPerm(PERMISSION_UPDATE_DEVICE_STATS, MOCK_UID1);
+        mNetdMonitor.expectNetworkPerm(PERMISSION_NETWORK, new UserHandle[]{MOCK_USER1},
+                MOCK_APPID1);
+        mNetdMonitor.expectTrafficPerm(PERMISSION_UPDATE_DEVICE_STATS, MOCK_APPID1);
     }
 
     @Test
     public void testOnExternalApplicationsAvailableWithSharedUid_DifferentStorage()
             throws Exception {
-        final BroadcastReceiver receiver = expectBroadcastReceiver(
-                Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
-
         // Initial the permission state. MOCK_PACKAGE1 is installed on external storage and
         // MOCK_PACKAGE2 is installed on device. These two packages are shared on MOCK_UID1.
         // MOCK_UID1 has NETWORK and INTERNET permissions.
-        when(mUserManager.getUserHandles(eq(true))).thenReturn(List.of(MOCK_USER1));
         when(mPackageManager.getInstalledPackages(eq(GET_PERMISSIONS | MATCH_ANY_USER))).thenReturn(
                 List.of(buildPackageInfo(MOCK_PACKAGE1, MOCK_UID1),
                         buildPackageInfo(MOCK_PACKAGE2, MOCK_UID1, CHANGE_NETWORK_STATE,
                                 INTERNET)));
         mPermissionMonitor.startMonitoring();
-        mNetdMonitor.expectNetworkPerm(NETWORK, new UserHandle[]{MOCK_USER1}, MOCK_UID1);
-        mNetdMonitor.expectTrafficPerm(PERMISSION_INTERNET, MOCK_UID1);
+        mNetdMonitor.expectNetworkPerm(PERMISSION_NETWORK, new UserHandle[]{MOCK_USER1},
+                MOCK_APPID1);
+        mNetdMonitor.expectTrafficPerm(PERMISSION_INTERNET, MOCK_APPID1);
 
+        final BroadcastReceiver receiver = expectBroadcastReceiver(
+                Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
         // Verify receiving EXTERNAL_APPLICATIONS_AVAILABLE intent and update permission to netd.
         final Intent externalIntent = new Intent(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
         externalIntent.putExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST, new String[] {MOCK_PACKAGE1});
@@ -1137,10 +1146,22 @@
                 CONNECTIVITY_USE_RESTRICTED_NETWORKS, UPDATE_DEVICE_STATS);
         buildAndMockPackageInfoWithPermissions(MOCK_PACKAGE2, MOCK_UID1, CHANGE_NETWORK_STATE,
                 INTERNET);
-        when(mPackageManager.getPackagesForUid(MOCK_UID1))
-                .thenReturn(new String[]{MOCK_PACKAGE1, MOCK_PACKAGE2});
         receiver.onReceive(mContext, externalIntent);
-        mNetdMonitor.expectNetworkPerm(SYSTEM, new UserHandle[]{MOCK_USER1}, MOCK_UID1);
-        mNetdMonitor.expectTrafficPerm(PERMISSION_TRAFFIC_ALL, MOCK_UID1);
+        mNetdMonitor.expectNetworkPerm(PERMISSION_SYSTEM, new UserHandle[]{MOCK_USER1},
+                MOCK_APPID1);
+        mNetdMonitor.expectTrafficPerm(PERMISSION_TRAFFIC_ALL, MOCK_APPID1);
+    }
+
+    @Test
+    public void testIsHigherNetworkPermission() {
+        assertFalse(isHigherNetworkPermission(PERMISSION_NONE, PERMISSION_NONE));
+        assertFalse(isHigherNetworkPermission(PERMISSION_NONE, PERMISSION_NETWORK));
+        assertFalse(isHigherNetworkPermission(PERMISSION_NONE, PERMISSION_SYSTEM));
+        assertTrue(isHigherNetworkPermission(PERMISSION_NETWORK, PERMISSION_NONE));
+        assertFalse(isHigherNetworkPermission(PERMISSION_NETWORK, PERMISSION_NETWORK));
+        assertFalse(isHigherNetworkPermission(PERMISSION_NETWORK, PERMISSION_SYSTEM));
+        assertTrue(isHigherNetworkPermission(PERMISSION_SYSTEM, PERMISSION_NONE));
+        assertTrue(isHigherNetworkPermission(PERMISSION_SYSTEM, PERMISSION_NETWORK));
+        assertFalse(isHigherNetworkPermission(PERMISSION_SYSTEM, PERMISSION_SYSTEM));
     }
 }