Enterprise slicing for profile blocking default

Test: atest ConnectivityServiceTest#testProfileNetworkPreferenceBlocking_networkChanges \
      ConnectivityServiceTest#testProfileNetworkPreferenceBlocking_changePreference \
      --rerun-until-failure 100
Bug: 263219497

Change-Id: Idbda582542bcabf0156e2bab9f8bea42fc908cae
diff --git a/framework/api/module-lib-current.txt b/framework/api/module-lib-current.txt
index 7669e0e..f623b05 100644
--- a/framework/api/module-lib-current.txt
+++ b/framework/api/module-lib-current.txt
@@ -63,6 +63,7 @@
     field public static final int FIREWALL_RULE_DENY = 2; // 0x2
     field public static final int PROFILE_NETWORK_PREFERENCE_DEFAULT = 0; // 0x0
     field public static final int PROFILE_NETWORK_PREFERENCE_ENTERPRISE = 1; // 0x1
+    field public static final int PROFILE_NETWORK_PREFERENCE_ENTERPRISE_BLOCKING = 3; // 0x3
     field public static final int PROFILE_NETWORK_PREFERENCE_ENTERPRISE_NO_FALLBACK = 2; // 0x2
   }
 
diff --git a/framework/src/android/net/ConnectivityManager.java b/framework/src/android/net/ConnectivityManager.java
index 60bc68c..40defd4 100644
--- a/framework/src/android/net/ConnectivityManager.java
+++ b/framework/src/android/net/ConnectivityManager.java
@@ -1232,16 +1232,19 @@
     }
 
     /**
-     * Preference for {@link ProfileNetworkPreference#setPreference(int)}.
+     * Preference for {@link ProfileNetworkPreference.Builder#setPreference(int)}.
      * See {@link #setProfileNetworkPreferences(UserHandle, List, Executor, Runnable)}
-     * Specify that the traffic for this user should by follow the default rules.
+     * Specify that the traffic for this user should by follow the default rules:
+     * applications in the profile designated by the UserHandle behave like any
+     * other application and use the system default network as their default
+     * network. Compare other PROFILE_NETWORK_PREFERENCE_* settings.
      * @hide
      */
     @SystemApi(client = MODULE_LIBRARIES)
     public static final int PROFILE_NETWORK_PREFERENCE_DEFAULT = 0;
 
     /**
-     * Preference for {@link ProfileNetworkPreference#setPreference(int)}.
+     * Preference for {@link ProfileNetworkPreference.Builder#setPreference(int)}.
      * See {@link #setProfileNetworkPreferences(UserHandle, List, Executor, Runnable)}
      * Specify that the traffic for this user should by default go on a network with
      * {@link NetworkCapabilities#NET_CAPABILITY_ENTERPRISE}, and on the system default network
@@ -1252,16 +1255,38 @@
     public static final int PROFILE_NETWORK_PREFERENCE_ENTERPRISE = 1;
 
     /**
-     * Preference for {@link ProfileNetworkPreference#setPreference(int)}.
+     * Preference for {@link ProfileNetworkPreference.Builder#setPreference(int)}.
      * See {@link #setProfileNetworkPreferences(UserHandle, List, Executor, Runnable)}
      * Specify that the traffic for this user should by default go on a network with
      * {@link NetworkCapabilities#NET_CAPABILITY_ENTERPRISE} and if no such network is available
-     * should not go on the system default network
+     * should not have a default network at all (that is, network accesses that
+     * do not specify a network explicitly terminate with an error), even if there
+     * is a system default network available to apps outside this preference.
+     * The apps can still use a non-enterprise network if they request it explicitly
+     * provided that specific network doesn't require any specific permission they
+     * do not hold.
      * @hide
      */
     @SystemApi(client = MODULE_LIBRARIES)
     public static final int PROFILE_NETWORK_PREFERENCE_ENTERPRISE_NO_FALLBACK = 2;
 
+    /**
+     * Preference for {@link ProfileNetworkPreference.Builder#setPreference(int)}.
+     * See {@link #setProfileNetworkPreferences(UserHandle, List, Executor, Runnable)}
+     * Specify that the traffic for this user should by default go on a network with
+     * {@link NetworkCapabilities#NET_CAPABILITY_ENTERPRISE}.
+     * If there is no such network, the apps will have no default
+     * network at all, even if there are available non-enterprise networks on the
+     * device (that is, network accesses that do not specify a network explicitly
+     * terminate with an error). Additionally, the designated apps should be
+     * blocked from using any non-enterprise network even if they specify it
+     * explicitly, unless they hold specific privilege overriding this (see
+     * {@link android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS}).
+     * @hide
+     */
+    @SystemApi(client = MODULE_LIBRARIES)
+    public static final int PROFILE_NETWORK_PREFERENCE_ENTERPRISE_BLOCKING = 3;
+
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(value = {
diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java
index 004b4d2..8107be3 100755
--- a/service/src/com/android/server/ConnectivityService.java
+++ b/service/src/com/android/server/ConnectivityService.java
@@ -4366,6 +4366,9 @@
             mNetworkForNetId.remove(nai.network.getNetId());
         }
         propagateUnderlyingNetworkCapabilities(nai.network);
+        // Update allowed network lists in netd. This should be called after removing nai
+        // from mNetworkAgentInfos.
+        updateProfileAllowedNetworks();
         // Remove all previously satisfied requests.
         for (int i = 0; i < nai.numNetworkRequests(); i++) {
             final NetworkRequest request = nai.requestAt(i);
@@ -4800,6 +4803,7 @@
                 }
             }
         }
+
         nri.mPerUidCounter.decrementCount(nri.mUid);
         mNetworkRequestInfoLogs.log("RELEASE " + nri);
         checkNrisConsistency(nri);
@@ -6166,12 +6170,16 @@
         if (mOemNetworkPreferences.getNetworkPreferences().size() > 0) {
             handleSetOemNetworkPreference(mOemNetworkPreferences, null);
         }
+        if (!mProfileNetworkPreferences.isEmpty()) {
+            updateProfileAllowedNetworks();
+        }
     }
 
     private void onUserRemoved(@NonNull final UserHandle user) {
         // If there was a network preference for this user, remove it.
         handleSetProfileNetworkPreference(
-                List.of(new ProfileNetworkPreferenceInfo(user, null, true)),
+                List.of(new ProfileNetworkPreferenceInfo(user, null, true,
+                        false /* blockingNonEnterprise */)),
                 null /* listener */);
         if (mOemNetworkPreferences.getNetworkPreferences().size() > 0) {
             handleSetOemNetworkPreference(mOemNetworkPreferences, null);
@@ -8688,6 +8696,73 @@
         }
     }
 
+    /**
+     * Collect restricted uid ranges for the given network and UserHandle, these uids
+     * are not restricted for matched enterprise networks but being restricted for non-matched
+     * enterprise networks and non-enterprise networks.
+     */
+    @NonNull
+    private ArraySet<UidRange> getRestrictedUidRangesForEnterpriseBlocking(
+            @NonNull NetworkAgentInfo nai, @NonNull UserHandle user) {
+        final ArraySet<UidRange> restrictedUidRanges = new ArraySet<>();
+        for (final ProfileNetworkPreferenceInfo pref : mProfileNetworkPreferences) {
+            if (!pref.user.equals(user) || !pref.blockingNonEnterprise) continue;
+
+            if (nai.networkCapabilities.hasCapability(NET_CAPABILITY_ENTERPRISE)) {
+                // The NC is built from a `ProfileNetworkPreference` which has only one
+                // enterprise ID, so it's guaranteed to have exactly one.
+                final int prefId = pref.capabilities.getEnterpriseIds()[0];
+                if (nai.networkCapabilities.hasEnterpriseId(prefId)) {
+                    continue;
+                }
+            }
+
+            if (UidRangeUtils.doesRangeSetOverlap(restrictedUidRanges,
+                    pref.capabilities.getUidRanges())) {
+                throw new IllegalArgumentException(
+                        "Overlapping uid range in preference: " + pref);
+            }
+            restrictedUidRanges.addAll(pref.capabilities.getUidRanges());
+        }
+        return restrictedUidRanges;
+    }
+
+    private void updateProfileAllowedNetworks() {
+        ensureRunningOnConnectivityServiceThread();
+        final ArrayList<NativeUidRangeConfig> configs = new ArrayList<>();
+        final List<UserHandle> users = mContext.getSystemService(UserManager.class)
+                        .getUserHandles(true /* excludeDying */);
+        if (users.isEmpty()) {
+            throw new IllegalStateException("No user is available");
+        }
+
+        for (final NetworkAgentInfo nai : mNetworkAgentInfos) {
+            ArraySet<UidRange> allowedUidRanges = new ArraySet<>();
+            for (final UserHandle user : users) {
+                final ArraySet<UidRange> restrictedUidRanges =
+                        getRestrictedUidRangesForEnterpriseBlocking(nai, user);
+                allowedUidRanges.addAll(UidRangeUtils.removeRangeSetFromUidRange(
+                        UidRange.createForUser(user), restrictedUidRanges));
+            }
+
+            final UidRangeParcel[] rangesParcel = toUidRangeStableParcels(allowedUidRanges);
+            configs.add(new NativeUidRangeConfig(
+                    nai.network.netId, rangesParcel, 0 /* subPriority */));
+        }
+
+        // The netd API replaces the previous configs with the current configs.
+        // Thus, for network disconnection or preference removal, no need to
+        // unset previous config. Instead, collecting all currently needed
+        // configs and issue to netd.
+        try {
+            mNetd.setNetworkAllowlist(configs.toArray(new NativeUidRangeConfig[0]));
+        } catch (ServiceSpecificException e) {
+            // Has the interface disappeared since the network was built?
+        } catch (RemoteException e) {
+            // Netd died. This usually causes a runtime restart anyway.
+        }
+    }
+
     private void makeDefaultNetwork(@Nullable final NetworkAgentInfo newDefaultNetwork) {
         try {
             if (null != newDefaultNetwork) {
@@ -9320,6 +9395,7 @@
             networkAgent.setCreated();
             networkAgent.onNetworkCreated();
             updateAllowedUids(networkAgent, null, networkAgent.networkCapabilities);
+            updateProfileAllowedNetworks();
         }
 
         if (!networkAgent.everConnected() && state == NetworkInfo.State.CONNECTED) {
@@ -10856,6 +10932,7 @@
         for (final ProfileNetworkPreference preference : preferences) {
             final NetworkCapabilities nc;
             boolean allowFallback = true;
+            boolean blockingNonEnterprise = false;
             switch (preference.getPreference()) {
                 case ConnectivityManager.PROFILE_NETWORK_PREFERENCE_DEFAULT:
                     nc = null;
@@ -10865,6 +10942,9 @@
                                 "Invalid enterprise identifier in setProfileNetworkPreferences");
                     }
                     break;
+                case ConnectivityManager.PROFILE_NETWORK_PREFERENCE_ENTERPRISE_BLOCKING:
+                    blockingNonEnterprise = true;
+                    // continue to process the enterprise preference.
                 case ConnectivityManager.PROFILE_NETWORK_PREFERENCE_ENTERPRISE_NO_FALLBACK:
                     allowFallback = false;
                     // continue to process the enterprise preference.
@@ -10898,7 +10978,8 @@
                     throw new IllegalArgumentException(
                             "Invalid preference in setProfileNetworkPreferences");
             }
-            preferenceList.add(new ProfileNetworkPreferenceInfo(profile, nc, allowFallback));
+            preferenceList.add(new ProfileNetworkPreferenceInfo(
+                    profile, nc, allowFallback, blockingNonEnterprise));
             if (hasDefaultPreference && preferenceList.size() > 1) {
                 throw new IllegalArgumentException(
                         "Default profile preference should not be set along with other preference");
@@ -11011,6 +11092,7 @@
         removeDefaultNetworkRequestsForPreference(PREFERENCE_ORDER_PROFILE);
         addPerAppDefaultNetworkRequests(
                 createNrisFromProfileNetworkPreferences(mProfileNetworkPreferences));
+        updateProfileAllowedNetworks();
 
         // Finally, rematch.
         rematchAllNetworksAndRequests();
diff --git a/service/src/com/android/server/connectivity/ProfileNetworkPreferenceInfo.java b/service/src/com/android/server/connectivity/ProfileNetworkPreferenceInfo.java
index 10f3886..7679660 100644
--- a/service/src/com/android/server/connectivity/ProfileNetworkPreferenceInfo.java
+++ b/service/src/com/android/server/connectivity/ProfileNetworkPreferenceInfo.java
@@ -32,13 +32,15 @@
     @Nullable
     public final NetworkCapabilities capabilities;
     public final boolean allowFallback;
+    public final boolean blockingNonEnterprise;
 
     public ProfileNetworkPreferenceInfo(@NonNull final UserHandle user,
             @Nullable final NetworkCapabilities capabilities,
-            final boolean allowFallback) {
+            final boolean allowFallback, final boolean blockingNonEnterprise) {
         this.user = user;
         this.capabilities = null == capabilities ? null : new NetworkCapabilities(capabilities);
         this.allowFallback = allowFallback;
+        this.blockingNonEnterprise = blockingNonEnterprise;
     }
 
     @Override
@@ -57,6 +59,7 @@
         return "[ProfileNetworkPreference user=" + user
                 + " caps=" + capabilities
                 + " allowFallback=" + allowFallback
+                + " blockingNonEnterprise=" + blockingNonEnterprise
                 + "]";
     }
 }
diff --git a/tests/unit/java/com/android/server/ConnectivityServiceTest.java b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
index 3d6ee09..e6e2d60 100755
--- a/tests/unit/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
@@ -64,6 +64,7 @@
 import static android.net.ConnectivityManager.FIREWALL_RULE_DENY;
 import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_DEFAULT;
 import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_ENTERPRISE;
+import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_ENTERPRISE_BLOCKING;
 import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_ENTERPRISE_NO_FALLBACK;
 import static android.net.ConnectivityManager.TYPE_ETHERNET;
 import static android.net.ConnectivityManager.TYPE_MOBILE;
@@ -10402,6 +10403,7 @@
         verify(mMockNetd, times(1)).idletimerRemoveInterface(eq(MOBILE_IFNAME), anyInt(),
                 eq(Integer.toString(TRANSPORT_CELLULAR)));
         verify(mMockNetd).networkDestroy(cellNetId);
+        verify(mMockNetd).setNetworkAllowlist(any());
         verifyNoMoreInteractions(mMockNetd);
         verifyNoMoreInteractions(mClatCoordinator);
         reset(mMockNetd);
@@ -10442,6 +10444,7 @@
         verify(mMockNetd).idletimerRemoveInterface(eq(MOBILE_IFNAME), anyInt(),
                 eq(Integer.toString(TRANSPORT_CELLULAR)));
         verify(mMockNetd).networkDestroy(cellNetId);
+        verify(mMockNetd).setNetworkAllowlist(any());
         verifyNoMoreInteractions(mMockNetd);
         verifyNoMoreInteractions(mClatCoordinator);
 
@@ -15752,6 +15755,171 @@
                 PREFERENCE_ORDER_PROFILE));
     }
 
+    @Test
+    public void testProfileNetworkPreferenceBlocking_changePreference() throws Exception {
+        final InOrder inOrder = inOrder(mMockNetd);
+        final UserHandle testHandle = setupEnterpriseNetwork();
+        doReturn(asList(PRIMARY_USER_HANDLE, testHandle))
+                .when(mUserManager).getUserHandles(anyBoolean());
+
+        // Start with 1 default network and 1 enterprise network, both networks should
+        // not be restricted since the blocking preference is not set yet.
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
+        mCellNetworkAgent.connect(true);
+
+        // Verify uid ranges 0~99999, 200000~299999 are all allowed for cellular.
+        final UidRange profileUidRange =
+                UidRange.createForUser(UserHandle.of(TEST_WORK_PROFILE_USER_ID));
+        ArraySet<UidRange> allowedAllUidRanges = new ArraySet<>();
+        allowedAllUidRanges.add(PRIMARY_UIDRANGE);
+        allowedAllUidRanges.add(profileUidRange);
+        final UidRangeParcel[] allowAllUidRangesParcel = toUidRangeStableParcels(
+                allowedAllUidRanges);
+        final NativeUidRangeConfig cellAllAllowedConfig = new NativeUidRangeConfig(
+                mCellNetworkAgent.getNetwork().netId,
+                allowAllUidRangesParcel,
+                0 /* subPriority */);
+        inOrder.verify(mMockNetd).setNetworkAllowlist(
+                new NativeUidRangeConfig[]{cellAllAllowedConfig});
+
+        // Verify the same uid ranges are also applied for enterprise network.
+        final TestNetworkAgentWrapper enterpriseAgent = makeEnterpriseNetworkAgent(
+                NET_ENTERPRISE_ID_1);
+        enterpriseAgent.connect(true);
+        final NativeUidRangeConfig enterpriseAllAllowedConfig = new NativeUidRangeConfig(
+                enterpriseAgent.getNetwork().netId,
+                allowAllUidRangesParcel,
+                0 /* subPriority */);
+        // Network agents are stored in an ArraySet which does not guarantee the order and
+        // making the order of the list undeterministic. Thus, verify this in order insensitive way.
+        final ArgumentCaptor<NativeUidRangeConfig[]> configsCaptor = ArgumentCaptor.forClass(
+                NativeUidRangeConfig[].class);
+        inOrder.verify(mMockNetd).setNetworkAllowlist(configsCaptor.capture());
+        assertContainsAll(List.of(configsCaptor.getValue()),
+                List.of(cellAllAllowedConfig, enterpriseAllAllowedConfig));
+
+        // Setup profile preference which only applies to test app uid on the managed profile.
+        ProfileNetworkPreference.Builder prefBuilder = new ProfileNetworkPreference.Builder();
+        prefBuilder.setPreference(PROFILE_NETWORK_PREFERENCE_ENTERPRISE_BLOCKING)
+                .setIncludedUids(new int[]{testHandle.getUid(TEST_WORK_PROFILE_APP_UID)})
+                .setPreferenceEnterpriseId(NET_ENTERPRISE_ID_1);
+        final TestOnCompleteListener listener = new TestOnCompleteListener();
+        mCm.setProfileNetworkPreferences(testHandle,
+                List.of(prefBuilder.build()),
+                r -> r.run(), listener);
+        listener.expectOnComplete();
+
+        // Verify Netd is called for the preferences changed.
+        // Cell: 0~99999, 200000~TEST_APP_UID-1, TEST_APP_UID+1~299999
+        // Enterprise: 0~99999, 200000~299999
+        final ArraySet<UidRange> excludeAppRanges = new ArraySet<>();
+        excludeAppRanges.add(PRIMARY_UIDRANGE);
+        excludeAppRanges.addAll(UidRangeUtils.removeRangeSetFromUidRange(
+                profileUidRange,
+                new ArraySet(new UidRange[]{
+                        (new UidRange(TEST_WORK_PROFILE_APP_UID, TEST_WORK_PROFILE_APP_UID))})
+        ));
+        final UidRangeParcel[] excludeAppRangesParcel = toUidRangeStableParcels(excludeAppRanges);
+        final NativeUidRangeConfig cellExcludeAppConfig = new NativeUidRangeConfig(
+                mCellNetworkAgent.getNetwork().netId,
+                excludeAppRangesParcel,
+                0 /* subPriority */);
+        inOrder.verify(mMockNetd).setNetworkAllowlist(configsCaptor.capture());
+        assertContainsAll(List.of(configsCaptor.getValue()),
+                List.of(cellExcludeAppConfig, enterpriseAllAllowedConfig));
+
+        // Verify unset by giving all allowed set for all users when the preference got removed.
+        mCm.setProfileNetworkPreference(testHandle, PROFILE_NETWORK_PREFERENCE_ENTERPRISE,
+                r -> r.run(), listener);
+        listener.expectOnComplete();
+        inOrder.verify(mMockNetd).setNetworkAllowlist(configsCaptor.capture());
+        assertContainsAll(List.of(configsCaptor.getValue()),
+                List.of(cellAllAllowedConfig, enterpriseAllAllowedConfig));
+
+        // Verify issuing with cellular set only when a network with enterprise capability
+        // disconnects.
+        enterpriseAgent.disconnect();
+        waitForIdle();
+        inOrder.verify(mMockNetd).setNetworkAllowlist(
+                new NativeUidRangeConfig[]{cellAllAllowedConfig});
+    }
+
+    @Test
+    public void testProfileNetworkPreferenceBlocking_networkChanges() throws Exception {
+        final InOrder inOrder = inOrder(mMockNetd);
+        final UserHandle testHandle = setupEnterpriseNetwork();
+        doReturn(asList(PRIMARY_USER_HANDLE, testHandle))
+                .when(mUserManager).getUserHandles(anyBoolean());
+
+        // Setup profile preference which only applies to test app uid on the managed profile.
+        ProfileNetworkPreference.Builder prefBuilder = new ProfileNetworkPreference.Builder();
+        prefBuilder.setPreference(PROFILE_NETWORK_PREFERENCE_ENTERPRISE_BLOCKING)
+                .setIncludedUids(new int[]{testHandle.getUid(TEST_WORK_PROFILE_APP_UID)})
+                .setPreferenceEnterpriseId(NET_ENTERPRISE_ID_1);
+        final TestOnCompleteListener listener = new TestOnCompleteListener();
+        mCm.setProfileNetworkPreferences(testHandle,
+                List.of(prefBuilder.build()),
+                r -> r.run(), listener);
+        listener.expectOnComplete();
+        inOrder.verify(mMockNetd).setNetworkAllowlist(new NativeUidRangeConfig[]{});
+
+        // Start with 1 default network, which should be restricted since the blocking
+        // preference is already set.
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
+        mCellNetworkAgent.connect(true);
+
+        // Verify cellular network applies to the allow list.
+        // Cell: 0~99999, 200000~TEST_APP_UID-1, TEST_APP_UID+1~299999
+        // Enterprise: 0~99999, 200000~299999
+        final ArraySet<UidRange> excludeAppRanges = new ArraySet<>();
+        final UidRange profileUidRange =
+                UidRange.createForUser(UserHandle.of(TEST_WORK_PROFILE_USER_ID));
+        excludeAppRanges.add(PRIMARY_UIDRANGE);
+        excludeAppRanges.addAll(UidRangeUtils.removeRangeSetFromUidRange(
+                profileUidRange,
+                new ArraySet(new UidRange[]{
+                        (new UidRange(TEST_WORK_PROFILE_APP_UID, TEST_WORK_PROFILE_APP_UID))})
+        ));
+        final UidRangeParcel[] excludeAppRangesParcel = toUidRangeStableParcels(excludeAppRanges);
+        final NativeUidRangeConfig cellExcludeAppConfig = new NativeUidRangeConfig(
+                mCellNetworkAgent.getNetwork().netId,
+                excludeAppRangesParcel,
+                0 /* subPriority */);
+        inOrder.verify(mMockNetd).setNetworkAllowlist(
+                new NativeUidRangeConfig[]{cellExcludeAppConfig});
+
+        // Verify enterprise network is not blocked for test app.
+        final TestNetworkAgentWrapper enterpriseAgent = makeEnterpriseNetworkAgent(
+                NET_ENTERPRISE_ID_1);
+        enterpriseAgent.connect(true);
+        ArraySet<UidRange> allowedAllUidRanges = new ArraySet<>();
+        allowedAllUidRanges.add(PRIMARY_UIDRANGE);
+        allowedAllUidRanges.add(profileUidRange);
+        final UidRangeParcel[] allowAllUidRangesParcel = toUidRangeStableParcels(
+                allowedAllUidRanges);
+        final NativeUidRangeConfig enterpriseAllAllowedConfig = new NativeUidRangeConfig(
+                enterpriseAgent.getNetwork().netId,
+                allowAllUidRangesParcel,
+                0 /* subPriority */);
+        // Network agents are stored in an ArraySet which does not guarantee the order and
+        // making the order of the list undeterministic. Thus, verify this in order insensitive way.
+        final ArgumentCaptor<NativeUidRangeConfig[]> configsCaptor = ArgumentCaptor.forClass(
+                NativeUidRangeConfig[].class);
+        inOrder.verify(mMockNetd).setNetworkAllowlist(configsCaptor.capture());
+        assertContainsAll(List.of(configsCaptor.getValue()),
+                List.of(enterpriseAllAllowedConfig, cellExcludeAppConfig));
+
+        // Verify issuing with cellular set only when enterprise network disconnects.
+        enterpriseAgent.disconnect();
+        waitForIdle();
+        inOrder.verify(mMockNetd).setNetworkAllowlist(
+                new NativeUidRangeConfig[]{cellExcludeAppConfig});
+
+        mCellNetworkAgent.disconnect();
+        waitForIdle();
+        inOrder.verify(mMockNetd).setNetworkAllowlist(new NativeUidRangeConfig[]{});
+    }
+
     /**
      * Make sure wrong preferences for per-profile default networking are rejected.
      */
@@ -15762,7 +15930,7 @@
         ProfileNetworkPreference.Builder profileNetworkPreferenceBuilder =
                 new ProfileNetworkPreference.Builder();
         profileNetworkPreferenceBuilder.setPreference(
-                PROFILE_NETWORK_PREFERENCE_ENTERPRISE_NO_FALLBACK + 1);
+                PROFILE_NETWORK_PREFERENCE_ENTERPRISE_BLOCKING + 1);
         profileNetworkPreferenceBuilder.setPreferenceEnterpriseId(NET_ENTERPRISE_ID_1);
         assertThrows("Should not be able to set an illegal preference",
                 IllegalArgumentException.class,