Merge "Remove exclusivity restriction of multiple preferences" into sc-dev
diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java
index 0b61247..b655ed6 100644
--- a/service/src/com/android/server/ConnectivityService.java
+++ b/service/src/com/android/server/ConnectivityService.java
@@ -402,30 +402,45 @@
     }
 
     /**
-     * The priority value is used when issue uid ranges rules to netd. Netd will use the priority
-     * value and uid ranges to generate corresponding ip rules specific to the given preference.
-     * Thus, any device originated data traffic of the applied uids can be routed to the altered
-     * default network which has highest priority.
+     * For per-app preferences, requests contain an int to signify which request
+     * should have priority. The priority is passed to netd which will use it
+     * together with UID ranges to generate the corresponding IP rule. This serves
+     * to direct device-originated data traffic of the specific UIDs to the correct
+     * default network for each app.
+     * Priorities passed to netd must be in the 0~999 range. Larger values code for
+     * a lower priority, {@see NativeUidRangeConfig}
      *
-     * Note: The priority value should be in 0~1000. Larger value means lower priority, see
-     *       {@link NativeUidRangeConfig}.
+     * Requests that don't code for a per-app preference use PREFERENCE_PRIORITY_INVALID.
+     * The default request uses PREFERENCE_PRIORITY_DEFAULT.
      */
-    // This is default priority value for those NetworkRequests which doesn't have preference to
-    // alter default network and use the global one.
+    // Bound for the lowest valid priority.
+    static final int PREFERENCE_PRIORITY_LOWEST = 999;
+    // Used when sending to netd to code for "no priority".
+    static final int PREFERENCE_PRIORITY_NONE = 0;
+    // Priority for requests that don't code for a per-app preference. As it is
+    // out of the valid range, the corresponding priority should be
+    // PREFERENCE_PRIORITY_NONE when sending to netd.
     @VisibleForTesting
-    static final int DEFAULT_NETWORK_PRIORITY_NONE = 0;
-    // Used by automotive devices to set the network preferences used to direct traffic at an
-    // application level. See {@link #setOemNetworkPreference}.
+    static final int PREFERENCE_PRIORITY_INVALID = Integer.MAX_VALUE;
+    // Priority for the default internet request. Since this must always have the
+    // lowest priority, its value is larger than the largest acceptable value. As
+    // it is out of the valid range, the corresponding priority should be
+    // PREFERENCE_PRIORITY_NONE when sending to netd.
+    static final int PREFERENCE_PRIORITY_DEFAULT = 1000;
+    // As a security feature, VPNs have the top priority.
+    static final int PREFERENCE_PRIORITY_VPN = 1;
+    // Priority of per-app OEM preference. See {@link #setOemNetworkPreference}.
     @VisibleForTesting
-    static final int DEFAULT_NETWORK_PRIORITY_OEM = 10;
-    // Request that a user profile is put by default on a network matching a given preference.
+    static final int PREFERENCE_PRIORITY_OEM = 10;
+    // Priority of per-profile preference, such as used by enterprise networks.
     // See {@link #setProfileNetworkPreference}.
     @VisibleForTesting
-    static final int DEFAULT_NETWORK_PRIORITY_PROFILE = 20;
-    // Set by MOBILE_DATA_PREFERRED_UIDS setting. Use mobile data in preference even when
-    // higher-priority networks are connected.
+    static final int PREFERENCE_PRIORITY_PROFILE = 20;
+    // Priority of user setting to prefer mobile data even when networks with
+    // better scores are connected.
+    // See {@link ConnectivitySettingsManager#setMobileDataPreferredUids}
     @VisibleForTesting
-    static final int DEFAULT_NETWORK_PRIORITY_MOBILE_DATA_PREFERRED = 30;
+    static final int PREFERENCE_PRIORITY_MOBILE_DATA_PREFERERRED = 30;
 
     /**
      * used internally to clear a wakelock when transitioning
@@ -4212,7 +4227,7 @@
                     mNetd.networkRemoveUidRangesParcel(new NativeUidRangeConfig(
                             satisfier.network.getNetId(),
                             toUidRangeStableParcels(nri.getUids()),
-                            nri.getDefaultNetworkPriority()));
+                            nri.getPriorityForNetd()));
                 } catch (RemoteException e) {
                     loge("Exception setting network preference default network", e);
                 }
@@ -5678,11 +5693,7 @@
         final int mAsUid;
 
         // Default network priority of this request.
-        private final int mDefaultNetworkPriority;
-
-        int getDefaultNetworkPriority() {
-            return mDefaultNetworkPriority;
-        }
+        final int mPreferencePriority;
 
         // In order to preserve the mapping of NetworkRequest-to-callback when apps register
         // callbacks using a returned NetworkRequest, the original NetworkRequest needs to be
@@ -5714,12 +5725,12 @@
         NetworkRequestInfo(int asUid, @NonNull final NetworkRequest r,
                 @Nullable final PendingIntent pi, @Nullable String callingAttributionTag) {
             this(asUid, Collections.singletonList(r), r, pi, callingAttributionTag,
-                    DEFAULT_NETWORK_PRIORITY_NONE);
+                    PREFERENCE_PRIORITY_INVALID);
         }
 
         NetworkRequestInfo(int asUid, @NonNull final List<NetworkRequest> r,
                 @NonNull final NetworkRequest requestForCallback, @Nullable final PendingIntent pi,
-                @Nullable String callingAttributionTag, final int defaultNetworkPriority) {
+                @Nullable String callingAttributionTag, final int preferencePriority) {
             ensureAllNetworkRequestsHaveType(r);
             mRequests = initializeRequests(r);
             mNetworkRequestForCallback = requestForCallback;
@@ -5737,7 +5748,7 @@
              */
             mCallbackFlags = NetworkCallback.FLAG_NONE;
             mCallingAttributionTag = callingAttributionTag;
-            mDefaultNetworkPriority = defaultNetworkPriority;
+            mPreferencePriority = preferencePriority;
         }
 
         NetworkRequestInfo(int asUid, @NonNull final NetworkRequest r, @Nullable final Messenger m,
@@ -5767,7 +5778,7 @@
             mPerUidCounter.incrementCountOrThrow(mUid);
             mCallbackFlags = callbackFlags;
             mCallingAttributionTag = callingAttributionTag;
-            mDefaultNetworkPriority = DEFAULT_NETWORK_PRIORITY_NONE;
+            mPreferencePriority = PREFERENCE_PRIORITY_INVALID;
             linkDeathRecipient();
         }
 
@@ -5807,18 +5818,18 @@
             mPerUidCounter.incrementCountOrThrow(mUid);
             mCallbackFlags = nri.mCallbackFlags;
             mCallingAttributionTag = nri.mCallingAttributionTag;
-            mDefaultNetworkPriority = DEFAULT_NETWORK_PRIORITY_NONE;
+            mPreferencePriority = PREFERENCE_PRIORITY_INVALID;
             linkDeathRecipient();
         }
 
         NetworkRequestInfo(int asUid, @NonNull final NetworkRequest r) {
-            this(asUid, Collections.singletonList(r), DEFAULT_NETWORK_PRIORITY_NONE);
+            this(asUid, Collections.singletonList(r), PREFERENCE_PRIORITY_INVALID);
         }
 
         NetworkRequestInfo(int asUid, @NonNull final List<NetworkRequest> r,
-                final int defaultNetworkPriority) {
+                final int preferencePriority) {
             this(asUid, r, r.get(0), null /* pi */, null /* callingAttributionTag */,
-                    defaultNetworkPriority);
+                    preferencePriority);
         }
 
         // True if this NRI is being satisfied. It also accounts for if the nri has its satisifer
@@ -5859,6 +5870,19 @@
             }
         }
 
+        boolean hasHigherPriorityThan(@NonNull final NetworkRequestInfo target) {
+            // Compare two priorities, larger value means lower priority.
+            return mPreferencePriority < target.mPreferencePriority;
+        }
+
+        int getPriorityForNetd() {
+            if (mPreferencePriority >= PREFERENCE_PRIORITY_NONE
+                    && mPreferencePriority <= PREFERENCE_PRIORITY_LOWEST) {
+                return mPreferencePriority;
+            }
+            return PREFERENCE_PRIORITY_NONE;
+        }
+
         @Override
         public void binderDied() {
             log("ConnectivityService NetworkRequestInfo binderDied(" +
@@ -5875,7 +5899,8 @@
                     + mNetworkRequestForCallback.requestId
                     + " " + mRequests
                     + (mPendingIntent == null ? "" : " to trigger " + mPendingIntent)
-                    + " callback flags: " + mCallbackFlags;
+                    + " callback flags: " + mCallbackFlags
+                    + " priority: " + mPreferencePriority;
         }
     }
 
@@ -6467,17 +6492,18 @@
      */
     @NonNull
     private NetworkRequestInfo getDefaultRequestTrackingUid(final int uid) {
+        NetworkRequestInfo highestPriorityNri = mDefaultRequest;
         for (final NetworkRequestInfo nri : mDefaultNetworkRequests) {
-            if (nri == mDefaultRequest) {
-                continue;
-            }
             // Checking the first request is sufficient as only multilayer requests will have more
             // than one request and for multilayer, all requests will track the same uids.
             if (nri.mRequests.get(0).networkCapabilities.appliesToUid(uid)) {
-                return nri;
+                // Find out the highest priority request.
+                if (nri.hasHigherPriorityThan(highestPriorityNri)) {
+                    highestPriorityNri = nri;
+                }
             }
         }
-        return mDefaultRequest;
+        return highestPriorityNri;
     }
 
     /**
@@ -6607,6 +6633,7 @@
     }
 
     private NetworkAgentInfo getDefaultNetworkForUid(final int uid) {
+        NetworkRequestInfo highestPriorityNri = mDefaultRequest;
         for (final NetworkRequestInfo nri : mDefaultNetworkRequests) {
             // Currently, all network requests will have the same uids therefore checking the first
             // one is sufficient. If/when uids are tracked at the nri level, this can change.
@@ -6616,11 +6643,13 @@
             }
             for (final UidRange range : uids) {
                 if (range.contains(uid)) {
-                    return nri.getSatisfier();
+                    if (nri.hasHigherPriorityThan(highestPriorityNri)) {
+                        highestPriorityNri = nri;
+                    }
                 }
             }
         }
-        return getDefaultNetwork();
+        return highestPriorityNri.getSatisfier();
     }
 
     @Nullable
@@ -7457,7 +7486,7 @@
         }
     }
 
-    private void updateUidRanges(boolean add, NetworkAgentInfo nai, Set<UidRange> uidRanges) {
+    private void updateVpnUidRanges(boolean add, NetworkAgentInfo nai, Set<UidRange> uidRanges) {
         int[] exemptUids = new int[2];
         // TODO: Excluding VPN_UID is necessary in order to not to kill the TCP connection used
         // by PPTP. Fix this by making Vpn set the owner UID to VPN_UID instead of system when
@@ -7470,10 +7499,10 @@
         try {
             if (add) {
                 mNetd.networkAddUidRangesParcel(new NativeUidRangeConfig(
-                        nai.network.netId, ranges, DEFAULT_NETWORK_PRIORITY_NONE));
+                        nai.network.netId, ranges, PREFERENCE_PRIORITY_VPN));
             } else {
                 mNetd.networkRemoveUidRangesParcel(new NativeUidRangeConfig(
-                        nai.network.netId, ranges, DEFAULT_NETWORK_PRIORITY_NONE));
+                        nai.network.netId, ranges, PREFERENCE_PRIORITY_VPN));
             }
         } catch (Exception e) {
             loge("Exception while " + (add ? "adding" : "removing") + " uid ranges " + uidRanges +
@@ -7535,10 +7564,10 @@
             // This can prevent the sockets of uid 1-2, 4-5 from being closed. It also reduce the
             // number of binder calls from 6 to 4.
             if (!newRanges.isEmpty()) {
-                updateUidRanges(true, nai, newRanges);
+                updateVpnUidRanges(true, nai, newRanges);
             }
             if (!prevRanges.isEmpty()) {
-                updateUidRanges(false, nai, prevRanges);
+                updateVpnUidRanges(false, nai, prevRanges);
             }
             final boolean wasFiltering = requiresVpnIsolation(nai, prevNc, nai.linkProperties);
             final boolean shouldFilter = requiresVpnIsolation(nai, newNc, nai.linkProperties);
@@ -7818,13 +7847,13 @@
                 mNetd.networkAddUidRangesParcel(new NativeUidRangeConfig(
                         newDefaultNetwork.network.getNetId(),
                         toUidRangeStableParcels(nri.getUids()),
-                        nri.getDefaultNetworkPriority()));
+                        nri.getPriorityForNetd()));
             }
             if (null != oldDefaultNetwork) {
                 mNetd.networkRemoveUidRangesParcel(new NativeUidRangeConfig(
                         oldDefaultNetwork.network.getNetId(),
                         toUidRangeStableParcels(nri.getUids()),
-                        nri.getDefaultNetworkPriority()));
+                        nri.getPriorityForNetd()));
             }
         } catch (RemoteException | ServiceSpecificException e) {
             loge("Exception setting app default network", e);
@@ -9789,21 +9818,6 @@
         mQosCallbackTracker.unregisterCallback(callback);
     }
 
-    // Network preference per-profile and OEM network preferences can't be set at the same
-    // time, because it is unclear what should happen if both preferences are active for
-    // one given UID. To make it possible, the stack would have to clarify what would happen
-    // in case both are active at the same time. The implementation may have to be adjusted
-    // to implement the resulting rules. For example, a priority could be defined between them,
-    // where the OEM preference would be considered less or more important than the enterprise
-    // preference ; this would entail implementing the priorities somehow, e.g. by doing
-    // UID arithmetic with UID ranges or passing a priority to netd so that the routing rules
-    // are set at the right level. Other solutions are possible, e.g. merging of the
-    // preferences for the relevant UIDs.
-    private static void throwConcurrentPreferenceException() {
-        throw new IllegalStateException("Can't set NetworkPreferenceForUser and "
-                + "set OemNetworkPreference at the same time");
-    }
-
     /**
      * Request that a user profile is put by default on a network matching a given preference.
      *
@@ -9832,15 +9846,7 @@
         if (!um.isManagedProfile(profile.getIdentifier())) {
             throw new IllegalArgumentException("Profile must be a managed profile");
         }
-        // Strictly speaking, mOemNetworkPreferences should only be touched on the
-        // handler thread. However it is an immutable object, so reading the reference is
-        // safe - it's just possible the value is slightly outdated. For the final check,
-        // see #handleSetProfileNetworkPreference. But if this can be caught here it is a
-        // lot easier to understand, so opportunistically check it.
-        // TODO: Have a priority for each preference.
-        if (!mOemNetworkPreferences.isEmpty() || !mMobileDataPreferredUids.isEmpty()) {
-            throwConcurrentPreferenceException();
-        }
+
         final NetworkCapabilities nc;
         switch (preference) {
             case ConnectivityManager.PROFILE_NETWORK_PREFERENCE_DEFAULT:
@@ -9883,7 +9889,7 @@
                     TYPE_NONE, NetworkRequest.Type.TRACK_DEFAULT));
             setNetworkRequestUids(nrs, UidRange.fromIntRanges(pref.capabilities.getUids()));
             final NetworkRequestInfo nri = new NetworkRequestInfo(Process.myUid(), nrs,
-                    DEFAULT_NETWORK_PRIORITY_PROFILE);
+                    PREFERENCE_PRIORITY_PROFILE);
             result.add(nri);
         }
         return result;
@@ -9892,20 +9898,6 @@
     private void handleSetProfileNetworkPreference(
             @NonNull final ProfileNetworkPreferences.Preference preference,
             @Nullable final IOnCompleteListener listener) {
-        // setProfileNetworkPreference and setOemNetworkPreference are mutually exclusive, in
-        // particular because it's not clear what preference should win in case both apply
-        // to the same app.
-        // The binder call has already checked this, but as mOemNetworkPreferences is only
-        // touched on the handler thread, it's theoretically not impossible that it has changed
-        // since.
-        // TODO: Have a priority for each preference.
-        if (!mOemNetworkPreferences.isEmpty() || !mMobileDataPreferredUids.isEmpty()) {
-            // This may happen on a device with an OEM preference set when a user is removed.
-            // In this case, it's safe to ignore. In particular this happens in the tests.
-            loge("handleSetProfileNetworkPreference, but OEM network preferences not empty");
-            return;
-        }
-
         validateNetworkCapabilitiesOfProfileNetworkPreference(preference.capabilities);
 
         mProfileNetworkPreferences = mProfileNetworkPreferences.plus(preference);
@@ -9914,7 +9906,7 @@
                 () -> {
                     final ArraySet<NetworkRequestInfo> nris =
                             createNrisFromProfileNetworkPreferences(mProfileNetworkPreferences);
-                    replaceDefaultNetworkRequestsForPreference(nris);
+                    replaceDefaultNetworkRequestsForPreference(nris, PREFERENCE_PRIORITY_PROFILE);
                 });
         // Finally, rematch.
         rematchAllNetworksAndRequests();
@@ -9954,26 +9946,19 @@
         }
         setNetworkRequestUids(requests, ranges);
         nris.add(new NetworkRequestInfo(Process.myUid(), requests,
-                DEFAULT_NETWORK_PRIORITY_MOBILE_DATA_PREFERRED));
+                PREFERENCE_PRIORITY_MOBILE_DATA_PREFERERRED));
         return nris;
     }
 
     private void handleMobileDataPreferredUidsChanged() {
-        // Ignore update preference because it's not clear what preference should win in case both
-        // apply to the same app.
-        // TODO: Have a priority for each preference.
-        if (!mOemNetworkPreferences.isEmpty() || !mProfileNetworkPreferences.isEmpty()) {
-            loge("Ignore mobile data preference change because other preferences are not empty");
-            return;
-        }
-
         mMobileDataPreferredUids = ConnectivitySettingsManager.getMobileDataPreferredUids(mContext);
         mSystemNetworkRequestCounter.transact(
                 mDeps.getCallingUid(), 1 /* numOfNewRequests */,
                 () -> {
                     final ArraySet<NetworkRequestInfo> nris =
                             createNrisFromMobileDataPreferredUids(mMobileDataPreferredUids);
-                    replaceDefaultNetworkRequestsForPreference(nris);
+                    replaceDefaultNetworkRequestsForPreference(nris,
+                            PREFERENCE_PRIORITY_MOBILE_DATA_PREFERERRED);
                 });
         // Finally, rematch.
         rematchAllNetworksAndRequests();
@@ -10015,16 +10000,6 @@
             validateOemNetworkPreferences(preference);
         }
 
-        // TODO: Have a priority for each preference.
-        if (!mProfileNetworkPreferences.isEmpty() || !mMobileDataPreferredUids.isEmpty()) {
-            // Strictly speaking, mProfileNetworkPreferences should only be touched on the
-            // handler thread. However it is an immutable object, so reading the reference is
-            // safe - it's just possible the value is slightly outdated. For the final check,
-            // see #handleSetOemPreference. But if this can be caught here it is a
-            // lot easier to understand, so opportunistically check it.
-            throwConcurrentPreferenceException();
-        }
-
         mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_OEM_NETWORK_PREFERENCE,
                 new Pair<>(preference, listener)));
     }
@@ -10071,17 +10046,6 @@
         if (DBG) {
             log("set OEM network preferences :" + preference.toString());
         }
-        // setProfileNetworkPreference and setOemNetworkPreference are mutually exclusive, in
-        // particular because it's not clear what preference should win in case both apply
-        // to the same app.
-        // The binder call has already checked this, but as mOemNetworkPreferences is only
-        // touched on the handler thread, it's theoretically not impossible that it has changed
-        // since.
-        // TODO: Have a priority for each preference.
-        if (!mProfileNetworkPreferences.isEmpty() || !mMobileDataPreferredUids.isEmpty()) {
-            logwtf("handleSetOemPreference, but per-profile network preferences not empty");
-            return;
-        }
 
         mOemNetworkPreferencesLogs.log("UPDATE INITIATED: " + preference);
         final int uniquePreferenceCount = new ArraySet<>(
@@ -10092,7 +10056,7 @@
                     final ArraySet<NetworkRequestInfo> nris =
                             new OemNetworkRequestFactory()
                                     .createNrisFromOemNetworkPreferences(preference);
-                    replaceDefaultNetworkRequestsForPreference(nris);
+                    replaceDefaultNetworkRequestsForPreference(nris, PREFERENCE_PRIORITY_OEM);
                 });
         mOemNetworkPreferences = preference;
 
@@ -10106,9 +10070,12 @@
     }
 
     private void replaceDefaultNetworkRequestsForPreference(
-            @NonNull final Set<NetworkRequestInfo> nris) {
-        // Pass in a defensive copy as this collection will be updated on remove.
-        handleRemoveNetworkRequests(new ArraySet<>(mDefaultNetworkRequests));
+            @NonNull final Set<NetworkRequestInfo> nris, final int preferencePriority) {
+        // Skip the requests which are set by other network preference. Because the uid range rules
+        // should stay in netd.
+        final Set<NetworkRequestInfo> requests = new ArraySet<>(mDefaultNetworkRequests);
+        requests.removeIf(request -> request.mPreferencePriority != preferencePriority);
+        handleRemoveNetworkRequests(requests);
         addPerAppDefaultNetworkRequests(nris);
     }
 
@@ -10302,8 +10269,7 @@
                 ranges.add(new UidRange(uid, uid));
             }
             setNetworkRequestUids(requests, ranges);
-            return new NetworkRequestInfo(
-                    Process.myUid(), requests, DEFAULT_NETWORK_PRIORITY_OEM);
+            return new NetworkRequestInfo(Process.myUid(), requests, PREFERENCE_PRIORITY_OEM);
         }
 
         private NetworkRequest createUnmeteredNetworkRequest() {
diff --git a/tests/unit/java/com/android/server/ConnectivityServiceTest.java b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
index cdf5d62..103ed8b 100644
--- a/tests/unit/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
@@ -125,10 +125,10 @@
 import static android.os.Process.INVALID_UID;
 import static android.system.OsConstants.IPPROTO_TCP;
 
-import static com.android.server.ConnectivityService.DEFAULT_NETWORK_PRIORITY_MOBILE_DATA_PREFERRED;
-import static com.android.server.ConnectivityService.DEFAULT_NETWORK_PRIORITY_NONE;
-import static com.android.server.ConnectivityService.DEFAULT_NETWORK_PRIORITY_OEM;
-import static com.android.server.ConnectivityService.DEFAULT_NETWORK_PRIORITY_PROFILE;
+import static com.android.server.ConnectivityService.PREFERENCE_PRIORITY_MOBILE_DATA_PREFERERRED;
+import static com.android.server.ConnectivityService.PREFERENCE_PRIORITY_OEM;
+import static com.android.server.ConnectivityService.PREFERENCE_PRIORITY_PROFILE;
+import static com.android.server.ConnectivityService.PREFERENCE_PRIORITY_VPN;
 import static com.android.server.ConnectivityServiceTestUtils.transportToLegacyType;
 import static com.android.testutils.ConcurrentUtils.await;
 import static com.android.testutils.ConcurrentUtils.durationOf;
@@ -437,6 +437,7 @@
     private static final String TEST_PACKAGE_NAME = "com.android.test.package";
     private static final int TEST_PACKAGE_UID = 123;
     private static final int TEST_PACKAGE_UID2 = 321;
+    private static final int TEST_PACKAGE_UID3 = 456;
     private static final String ALWAYS_ON_PACKAGE = "com.android.test.alwaysonvpn";
 
     private static final String INTERFACE_NAME = "interface";
@@ -1301,10 +1302,10 @@
 
             verify(mMockNetd, times(1)).networkAddUidRangesParcel(
                     new NativeUidRangeConfig(mMockVpn.getNetwork().getNetId(),
-                            toUidRangeStableParcels(uids), DEFAULT_NETWORK_PRIORITY_NONE));
+                            toUidRangeStableParcels(uids), PREFERENCE_PRIORITY_VPN));
             verify(mMockNetd, never()).networkRemoveUidRangesParcel(argThat(config ->
                     mMockVpn.getNetwork().getNetId() == config.netId
-                            && DEFAULT_NETWORK_PRIORITY_NONE == config.subPriority));
+                            && PREFERENCE_PRIORITY_VPN == config.subPriority));
             mAgentRegistered = true;
             verify(mMockNetd).networkCreate(nativeNetworkConfigVpn(getNetwork().netId,
                     !mMockNetworkAgent.isBypassableVpn(), mVpnType));
@@ -10556,11 +10557,11 @@
         if (add) {
             inOrder.verify(mMockNetd, times(1)).networkAddUidRangesParcel(
                     new NativeUidRangeConfig(mMockVpn.getNetwork().getNetId(),
-                            toUidRangeStableParcels(vpnRanges), DEFAULT_NETWORK_PRIORITY_NONE));
+                            toUidRangeStableParcels(vpnRanges), PREFERENCE_PRIORITY_VPN));
         } else {
             inOrder.verify(mMockNetd, times(1)).networkRemoveUidRangesParcel(
                     new NativeUidRangeConfig(mMockVpn.getNetwork().getNetId(),
-                            toUidRangeStableParcels(vpnRanges), DEFAULT_NETWORK_PRIORITY_NONE));
+                            toUidRangeStableParcels(vpnRanges), PREFERENCE_PRIORITY_VPN));
         }
 
         inOrder.verify(mMockNetd, times(1)).socketDestroy(eq(toUidRangeStableParcels(vpnRanges)),
@@ -11034,7 +11035,7 @@
                         .createNrisFromOemNetworkPreferences(
                                 createDefaultOemNetworkPreferences(prefToTest));
         final NetworkRequestInfo nri = nris.iterator().next();
-        assertEquals(DEFAULT_NETWORK_PRIORITY_OEM, nri.getDefaultNetworkPriority());
+        assertEquals(PREFERENCE_PRIORITY_OEM, nri.mPreferencePriority);
         final List<NetworkRequest> mRequests = nri.mRequests;
         assertEquals(expectedNumOfNris, nris.size());
         assertEquals(expectedNumOfRequests, mRequests.size());
@@ -11064,7 +11065,7 @@
                         .createNrisFromOemNetworkPreferences(
                                 createDefaultOemNetworkPreferences(prefToTest));
         final NetworkRequestInfo nri = nris.iterator().next();
-        assertEquals(DEFAULT_NETWORK_PRIORITY_OEM, nri.getDefaultNetworkPriority());
+        assertEquals(PREFERENCE_PRIORITY_OEM, nri.mPreferencePriority);
         final List<NetworkRequest> mRequests = nri.mRequests;
         assertEquals(expectedNumOfNris, nris.size());
         assertEquals(expectedNumOfRequests, mRequests.size());
@@ -11091,7 +11092,7 @@
                         .createNrisFromOemNetworkPreferences(
                                 createDefaultOemNetworkPreferences(prefToTest));
         final NetworkRequestInfo nri = nris.iterator().next();
-        assertEquals(DEFAULT_NETWORK_PRIORITY_OEM, nri.getDefaultNetworkPriority());
+        assertEquals(PREFERENCE_PRIORITY_OEM, nri.mPreferencePriority);
         final List<NetworkRequest> mRequests = nri.mRequests;
         assertEquals(expectedNumOfNris, nris.size());
         assertEquals(expectedNumOfRequests, mRequests.size());
@@ -11115,7 +11116,7 @@
                         .createNrisFromOemNetworkPreferences(
                                 createDefaultOemNetworkPreferences(prefToTest));
         final NetworkRequestInfo nri = nris.iterator().next();
-        assertEquals(DEFAULT_NETWORK_PRIORITY_OEM, nri.getDefaultNetworkPriority());
+        assertEquals(PREFERENCE_PRIORITY_OEM, nri.mPreferencePriority);
         final List<NetworkRequest> mRequests = nri.mRequests;
         assertEquals(expectedNumOfNris, nris.size());
         assertEquals(expectedNumOfRequests, mRequests.size());
@@ -11493,19 +11494,29 @@
             @OemNetworkPreferences.OemNetworkPreference final int networkPrefToSetup,
             @NonNull final UidRangeParcel[] uidRanges,
             @NonNull final String testPackageName) throws Exception {
-        setupSetOemNetworkPreferenceForPreferenceTest(
-                networkPrefToSetup, uidRanges, testPackageName, true);
+        setupSetOemNetworkPreferenceForPreferenceTest(networkPrefToSetup, uidRanges,
+                testPackageName, PRIMARY_USER_HANDLE, true /* hasAutomotiveFeature */);
     }
 
     private void setupSetOemNetworkPreferenceForPreferenceTest(
             @OemNetworkPreferences.OemNetworkPreference final int networkPrefToSetup,
             @NonNull final UidRangeParcel[] uidRanges,
             @NonNull final String testPackageName,
+            @NonNull final UserHandle user) throws Exception {
+        setupSetOemNetworkPreferenceForPreferenceTest(networkPrefToSetup, uidRanges,
+                testPackageName, user, true /* hasAutomotiveFeature */);
+    }
+
+    private void setupSetOemNetworkPreferenceForPreferenceTest(
+            @OemNetworkPreferences.OemNetworkPreference final int networkPrefToSetup,
+            @NonNull final UidRangeParcel[] uidRanges,
+            @NonNull final String testPackageName,
+            @NonNull final UserHandle user,
             final boolean hasAutomotiveFeature) throws Exception {
         mockHasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, hasAutomotiveFeature);
 
         // These tests work off a single UID therefore using 'start' is valid.
-        mockGetApplicationInfo(testPackageName, uidRanges[0].start);
+        mockGetApplicationInfo(testPackageName, uidRanges[0].start, user);
 
         setOemNetworkPreference(networkPrefToSetup, testPackageName);
     }
@@ -11796,11 +11807,11 @@
         verify(mMockNetd, times(addUidRangesTimes)).networkAddUidRangesParcel(argThat(config ->
                 (useAnyIdForAdd ? true : addUidRangesNetId == config.netId)
                         && Arrays.equals(addedUidRanges, config.uidRanges)
-                        && DEFAULT_NETWORK_PRIORITY_OEM == config.subPriority));
+                        && PREFERENCE_PRIORITY_OEM == config.subPriority));
         verify(mMockNetd, times(removeUidRangesTimes)).networkRemoveUidRangesParcel(
                 argThat(config -> (useAnyIdForRemove ? true : removeUidRangesNetId == config.netId)
                         && Arrays.equals(removedUidRanges, config.uidRanges)
-                        && DEFAULT_NETWORK_PRIORITY_OEM == config.subPriority));
+                        && PREFERENCE_PRIORITY_OEM == config.subPriority));
         if (shouldDestroyNetwork) {
             verify(mMockNetd, times(1))
                     .networkDestroy((useAnyIdForRemove ? anyInt() : eq(removeUidRangesNetId)));
@@ -11850,7 +11861,7 @@
 
         // Add an OEM default network request to track.
         setupSetOemNetworkPreferenceForPreferenceTest(
-                networkPref, uidRanges, validTestPackageName,
+                networkPref, uidRanges, validTestPackageName, PRIMARY_USER_HANDLE,
                 false /* hasAutomotiveFeature */);
 
         // Two requests should now exist; the system default and the test request.
@@ -12955,7 +12966,7 @@
         // is not handled specially, the rules are always active as long as a preference is set.
         inOrder.verify(mMockNetd).networkAddUidRangesParcel(new NativeUidRangeConfig(
                 mCellNetworkAgent.getNetwork().netId, uidRangeFor(testHandle),
-                DEFAULT_NETWORK_PRIORITY_PROFILE));
+                PREFERENCE_PRIORITY_PROFILE));
 
         // The enterprise network is not ready yet.
         assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback,
@@ -12971,10 +12982,10 @@
                 nativeNetworkConfigPhysical(workAgent.getNetwork().netId, INetd.PERMISSION_SYSTEM));
         inOrder.verify(mMockNetd).networkAddUidRangesParcel(new NativeUidRangeConfig(
                 workAgent.getNetwork().netId, uidRangeFor(testHandle),
-                DEFAULT_NETWORK_PRIORITY_PROFILE));
+                PREFERENCE_PRIORITY_PROFILE));
         inOrder.verify(mMockNetd).networkRemoveUidRangesParcel(new NativeUidRangeConfig(
                 mCellNetworkAgent.getNetwork().netId, uidRangeFor(testHandle),
-                DEFAULT_NETWORK_PRIORITY_PROFILE));
+                PREFERENCE_PRIORITY_PROFILE));
 
         // Make sure changes to the work agent send callbacks to the app in the work profile, but
         // not to the other apps.
@@ -13024,7 +13035,7 @@
         assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback);
         inOrder.verify(mMockNetd).networkAddUidRangesParcel(new NativeUidRangeConfig(
                 mCellNetworkAgent.getNetwork().netId, uidRangeFor(testHandle),
-                DEFAULT_NETWORK_PRIORITY_PROFILE));
+                PREFERENCE_PRIORITY_PROFILE));
         inOrder.verify(mMockNetd).networkDestroy(workAgent.getNetwork().netId);
 
         mCellNetworkAgent.disconnect();
@@ -13049,7 +13060,7 @@
                 workAgent2.getNetwork().netId, INetd.PERMISSION_SYSTEM));
         inOrder.verify(mMockNetd).networkAddUidRangesParcel(new NativeUidRangeConfig(
                 workAgent2.getNetwork().netId, uidRangeFor(testHandle),
-                DEFAULT_NETWORK_PRIORITY_PROFILE));
+                PREFERENCE_PRIORITY_PROFILE));
 
         workAgent2.setNetworkValid(true /* isStrictMode */);
         workAgent2.mNetworkMonitor.forceReevaluation(Process.myUid());
@@ -13096,7 +13107,7 @@
                 mCellNetworkAgent.getNetwork().netId, INetd.PERMISSION_NONE));
         inOrder.verify(mMockNetd).networkAddUidRangesParcel(new NativeUidRangeConfig(
                 workAgent.getNetwork().netId, uidRangeFor(testHandle),
-                DEFAULT_NETWORK_PRIORITY_PROFILE));
+                PREFERENCE_PRIORITY_PROFILE));
 
         registerDefaultNetworkCallbacks();
 
@@ -13112,7 +13123,7 @@
         assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback);
         inOrder.verify(mMockNetd).networkRemoveUidRangesParcel(new NativeUidRangeConfig(
                 workAgent.getNetwork().netId, uidRangeFor(testHandle),
-                DEFAULT_NETWORK_PRIORITY_PROFILE));
+                PREFERENCE_PRIORITY_PROFILE));
 
         workAgent.disconnect();
         mCellNetworkAgent.disconnect();
@@ -13158,7 +13169,7 @@
         listener.expectOnComplete();
         inOrder.verify(mMockNetd).networkAddUidRangesParcel(new NativeUidRangeConfig(
                 workAgent.getNetwork().netId, uidRangeFor(testHandle2),
-                DEFAULT_NETWORK_PRIORITY_PROFILE));
+                PREFERENCE_PRIORITY_PROFILE));
 
         mProfileDefaultNetworkCallback.expectAvailableCallbacksValidated(workAgent);
         assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback,
@@ -13169,7 +13180,7 @@
         listener.expectOnComplete();
         inOrder.verify(mMockNetd).networkAddUidRangesParcel(new NativeUidRangeConfig(
                 workAgent.getNetwork().netId, uidRangeFor(testHandle4),
-                DEFAULT_NETWORK_PRIORITY_PROFILE));
+                PREFERENCE_PRIORITY_PROFILE));
 
         app4Cb.expectAvailableCallbacksValidated(workAgent);
         assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback,
@@ -13180,7 +13191,7 @@
         listener.expectOnComplete();
         inOrder.verify(mMockNetd).networkRemoveUidRangesParcel(new NativeUidRangeConfig(
                 workAgent.getNetwork().netId, uidRangeFor(testHandle2),
-                DEFAULT_NETWORK_PRIORITY_PROFILE));
+                PREFERENCE_PRIORITY_PROFILE));
 
         mProfileDefaultNetworkCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
         assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback,
@@ -13209,7 +13220,7 @@
                 mCellNetworkAgent.getNetwork().netId, INetd.PERMISSION_NONE));
         inOrder.verify(mMockNetd).networkAddUidRangesParcel(new NativeUidRangeConfig(
                 mCellNetworkAgent.getNetwork().netId, uidRangeFor(testHandle),
-                DEFAULT_NETWORK_PRIORITY_PROFILE));
+                PREFERENCE_PRIORITY_PROFILE));
 
         final Intent removedIntent = new Intent(ACTION_USER_REMOVED);
         removedIntent.putExtra(Intent.EXTRA_USER, testHandle);
@@ -13217,39 +13228,7 @@
 
         inOrder.verify(mMockNetd).networkRemoveUidRangesParcel(new NativeUidRangeConfig(
                 mCellNetworkAgent.getNetwork().netId, uidRangeFor(testHandle),
-                DEFAULT_NETWORK_PRIORITY_PROFILE));
-    }
-
-    /**
-     * Make sure that OEM preference and per-profile preference can't be used at the same
-     * time and throw ISE if tried
-     */
-    @Test
-    public void testOemPreferenceAndProfilePreferenceExclusive() throws Exception {
-        final UserHandle testHandle = UserHandle.of(TEST_WORK_PROFILE_USER_ID);
-        mServiceContext.setWorkProfile(testHandle, true);
-        final TestOnCompleteListener listener = new TestOnCompleteListener();
-
-        setupMultipleDefaultNetworksForOemNetworkPreferenceNotCurrentUidTest(
-                OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY);
-        assertThrows("Should not be able to set per-profile pref while OEM prefs present",
-                IllegalStateException.class, () ->
-                        mCm.setProfileNetworkPreference(testHandle,
-                                PROFILE_NETWORK_PREFERENCE_ENTERPRISE,
-                                r -> r.run(), listener));
-
-        // Empty the OEM prefs
-        final TestOemListenerCallback oemPrefListener = new TestOemListenerCallback();
-        final OemNetworkPreferences emptyOemPref = new OemNetworkPreferences.Builder().build();
-        mService.setOemNetworkPreference(emptyOemPref, oemPrefListener);
-        oemPrefListener.expectOnComplete();
-
-        mCm.setProfileNetworkPreference(testHandle, PROFILE_NETWORK_PREFERENCE_ENTERPRISE,
-                r -> r.run(), listener);
-        listener.expectOnComplete();
-        assertThrows("Should not be able to set OEM prefs while per-profile pref is on",
-                IllegalStateException.class , () ->
-                        mService.setOemNetworkPreference(emptyOemPref, oemPrefListener));
+                PREFERENCE_PRIORITY_PROFILE));
     }
 
     /**
@@ -13420,8 +13399,7 @@
         assertEquals(1, nris.size());
         assertTrue(nri.isMultilayerRequest());
         assertEquals(nri.getUids(), uidRangesForUids(uids));
-        assertEquals(DEFAULT_NETWORK_PRIORITY_MOBILE_DATA_PREFERRED,
-                nri.getDefaultNetworkPriority());
+        assertEquals(PREFERENCE_PRIORITY_MOBILE_DATA_PREFERERRED, nri.mPreferencePriority);
     }
 
     /**
@@ -13473,7 +13451,7 @@
         final Set<Integer> uids1 = Set.of(PRIMARY_USER_HANDLE.getUid(TEST_PACKAGE_UID));
         final UidRangeParcel[] uidRanges1 = toUidRangeStableParcels(uidRangesForUids(uids1));
         final NativeUidRangeConfig config1 = new NativeUidRangeConfig(cellNetId, uidRanges1,
-                DEFAULT_NETWORK_PRIORITY_MOBILE_DATA_PREFERRED);
+                PREFERENCE_PRIORITY_MOBILE_DATA_PREFERERRED);
         setAndUpdateMobileDataPreferredUids(uids1);
         inorder.verify(mMockNetd, times(1)).networkAddUidRangesParcel(config1);
         inorder.verify(mMockNetd, never()).networkRemoveUidRangesParcel(any());
@@ -13485,7 +13463,7 @@
                 SECONDARY_USER_HANDLE.getUid(TEST_PACKAGE_UID));
         final UidRangeParcel[] uidRanges2 = toUidRangeStableParcels(uidRangesForUids(uids2));
         final NativeUidRangeConfig config2 = new NativeUidRangeConfig(cellNetId, uidRanges2,
-                DEFAULT_NETWORK_PRIORITY_MOBILE_DATA_PREFERRED);
+                PREFERENCE_PRIORITY_MOBILE_DATA_PREFERERRED);
         setAndUpdateMobileDataPreferredUids(uids2);
         inorder.verify(mMockNetd, times(1)).networkRemoveUidRangesParcel(config1);
         inorder.verify(mMockNetd, times(1)).networkAddUidRangesParcel(config2);
@@ -13533,7 +13511,7 @@
         final Set<Integer> uids = Set.of(PRIMARY_USER_HANDLE.getUid(TEST_PACKAGE_UID));
         final UidRangeParcel[] uidRanges = toUidRangeStableParcels(uidRangesForUids(uids));
         final NativeUidRangeConfig wifiConfig = new NativeUidRangeConfig(wifiNetId, uidRanges,
-                DEFAULT_NETWORK_PRIORITY_MOBILE_DATA_PREFERRED);
+                PREFERENCE_PRIORITY_MOBILE_DATA_PREFERERRED);
         setAndUpdateMobileDataPreferredUids(uids);
         inorder.verify(mMockNetd, times(1)).networkAddUidRangesParcel(wifiConfig);
         inorder.verify(mMockNetd, never()).networkRemoveUidRangesParcel(any());
@@ -13549,7 +13527,7 @@
 
         final int cellNetId = mCellNetworkAgent.getNetwork().netId;
         final NativeUidRangeConfig cellConfig = new NativeUidRangeConfig(cellNetId, uidRanges,
-                DEFAULT_NETWORK_PRIORITY_MOBILE_DATA_PREFERRED);
+                PREFERENCE_PRIORITY_MOBILE_DATA_PREFERERRED);
         inorder.verify(mMockNetd, times(1)).networkCreate(nativeNetworkConfigPhysical(
                 cellNetId, INetd.PERMISSION_NONE));
         inorder.verify(mMockNetd, times(1)).networkAddUidRangesParcel(cellConfig);
@@ -13578,7 +13556,7 @@
 
         final int cellNetId2 = mCellNetworkAgent.getNetwork().netId;
         final NativeUidRangeConfig cellConfig2 = new NativeUidRangeConfig(cellNetId2, uidRanges,
-                DEFAULT_NETWORK_PRIORITY_MOBILE_DATA_PREFERRED);
+                PREFERENCE_PRIORITY_MOBILE_DATA_PREFERERRED);
         inorder.verify(mMockNetd, times(1)).networkCreate(nativeNetworkConfigPhysical(
                 cellNetId2, INetd.PERMISSION_NONE));
         inorder.verify(mMockNetd, times(1)).networkAddUidRangesParcel(cellConfig2);
@@ -13659,4 +13637,181 @@
             waitForIdle();
         });
     }
+
+    @Test
+    public void testAllNetworkPreferencesCanCoexist()
+            throws Exception {
+        final InOrder inorder = inOrder(mMockNetd);
+        @OemNetworkPreferences.OemNetworkPreference final int networkPref =
+                OEM_NETWORK_PREFERENCE_OEM_PAID;
+        final UserHandle testHandle = setupEnterpriseNetwork();
+
+        setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, true);
+        final int cellNetId = mCellNetworkAgent.getNetwork().netId;
+        inorder.verify(mMockNetd, times(1)).networkCreate(nativeNetworkConfigPhysical(
+                cellNetId, INetd.PERMISSION_NONE));
+
+        // Set oem network preference
+        final int[] uids1 = new int[] { PRIMARY_USER_HANDLE.getUid(TEST_PACKAGE_UID) };
+        final UidRangeParcel[] uidRanges1 = toUidRangeStableParcels(uidRangesForUids(uids1));
+        final NativeUidRangeConfig config1 = new NativeUidRangeConfig(cellNetId, uidRanges1,
+                PREFERENCE_PRIORITY_OEM);
+        setupSetOemNetworkPreferenceForPreferenceTest(networkPref, uidRanges1, TEST_PACKAGE_NAME);
+        inorder.verify(mMockNetd, times(1)).networkAddUidRangesParcel(config1);
+        inorder.verify(mMockNetd, never()).networkRemoveUidRangesParcel(any());
+
+        // Set user profile network preference
+        final TestNetworkAgentWrapper workAgent = makeEnterpriseNetworkAgent();
+        workAgent.connect(true);
+
+        final TestOnCompleteListener listener = new TestOnCompleteListener();
+        mCm.setProfileNetworkPreference(testHandle, PROFILE_NETWORK_PREFERENCE_ENTERPRISE,
+                r -> r.run(), listener);
+        listener.expectOnComplete();
+        final NativeUidRangeConfig config2 = new NativeUidRangeConfig(workAgent.getNetwork().netId,
+                uidRangeFor(testHandle), PREFERENCE_PRIORITY_PROFILE);
+        inorder.verify(mMockNetd).networkCreate(nativeNetworkConfigPhysical(
+                workAgent.getNetwork().netId, INetd.PERMISSION_SYSTEM));
+        inorder.verify(mMockNetd, never()).networkRemoveUidRangesParcel(any());
+        inorder.verify(mMockNetd).networkAddUidRangesParcel(config2);
+
+        // Set MOBILE_DATA_PREFERRED_UIDS setting
+        final Set<Integer> uids2 = Set.of(PRIMARY_USER_HANDLE.getUid(TEST_PACKAGE_UID2));
+        final UidRangeParcel[] uidRanges2 = toUidRangeStableParcels(uidRangesForUids(uids2));
+        final NativeUidRangeConfig config3 = new NativeUidRangeConfig(cellNetId, uidRanges2,
+                PREFERENCE_PRIORITY_MOBILE_DATA_PREFERERRED);
+        setAndUpdateMobileDataPreferredUids(uids2);
+        inorder.verify(mMockNetd, never()).networkRemoveUidRangesParcel(any());
+        inorder.verify(mMockNetd, times(1)).networkAddUidRangesParcel(config3);
+
+        // Set oem network preference again with different uid.
+        final Set<Integer> uids3 = Set.of(PRIMARY_USER_HANDLE.getUid(TEST_PACKAGE_UID3));
+        final UidRangeParcel[] uidRanges3 = toUidRangeStableParcels(uidRangesForUids(uids3));
+        final NativeUidRangeConfig config4 = new NativeUidRangeConfig(cellNetId, uidRanges3,
+                PREFERENCE_PRIORITY_OEM);
+        setupSetOemNetworkPreferenceForPreferenceTest(networkPref, uidRanges3, "com.android.test");
+        inorder.verify(mMockNetd, times(1)).networkRemoveUidRangesParcel(config1);
+        inorder.verify(mMockNetd, times(1)).networkAddUidRangesParcel(config4);
+
+        // Remove user profile network preference
+        mCm.setProfileNetworkPreference(testHandle, PROFILE_NETWORK_PREFERENCE_DEFAULT,
+                r -> r.run(), listener);
+        listener.expectOnComplete();
+        inorder.verify(mMockNetd, times(1)).networkRemoveUidRangesParcel(config2);
+        inorder.verify(mMockNetd, never()).networkAddUidRangesParcel(any());
+
+        // Set MOBILE_DATA_PREFERRED_UIDS setting again with same uid as oem network preference.
+        final NativeUidRangeConfig config6 = new NativeUidRangeConfig(cellNetId, uidRanges3,
+                PREFERENCE_PRIORITY_MOBILE_DATA_PREFERERRED);
+        setAndUpdateMobileDataPreferredUids(uids3);
+        inorder.verify(mMockNetd, times(1)).networkRemoveUidRangesParcel(config3);
+        inorder.verify(mMockNetd, times(1)).networkAddUidRangesParcel(config6);
+    }
+
+    @Test
+    public void testNetworkCallbackAndActiveNetworkForUid_AllNetworkPreferencesEnabled()
+            throws Exception {
+        // File a request for cell to ensure it doesn't go down.
+        final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback();
+        final NetworkRequest cellRequest = new NetworkRequest.Builder()
+                .addTransportType(TRANSPORT_CELLULAR).build();
+        mCm.requestNetwork(cellRequest, cellNetworkCallback);
+        cellNetworkCallback.assertNoCallback();
+
+        // Register callbacks and have wifi network as default network.
+        registerDefaultNetworkCallbacks();
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
+        mWiFiNetworkAgent.connect(true);
+        mDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent);
+        mProfileDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent);
+        mTestPackageDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent);
+        assertEquals(mWiFiNetworkAgent.getNetwork(),
+                mCm.getActiveNetworkForUid(TEST_WORK_PROFILE_APP_UID));
+        assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(TEST_PACKAGE_UID));
+
+        // Set MOBILE_DATA_PREFERRED_UIDS setting with TEST_WORK_PROFILE_APP_UID and
+        // TEST_PACKAGE_UID. Both mProfileDefaultNetworkCallback and
+        // mTestPackageDefaultNetworkCallback should receive callback with cell network.
+        setAndUpdateMobileDataPreferredUids(Set.of(TEST_WORK_PROFILE_APP_UID, TEST_PACKAGE_UID));
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
+        mCellNetworkAgent.connect(true);
+        cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
+        mDefaultNetworkCallback.assertNoCallback();
+        mProfileDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
+        mTestPackageDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
+        assertEquals(mCellNetworkAgent.getNetwork(),
+                mCm.getActiveNetworkForUid(TEST_WORK_PROFILE_APP_UID));
+        assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(TEST_PACKAGE_UID));
+
+        // Set user profile network preference with test profile. mProfileDefaultNetworkCallback
+        // should receive callback with higher priority network preference (enterprise network).
+        // The others should have no callbacks.
+        final UserHandle testHandle = setupEnterpriseNetwork();
+        final TestNetworkAgentWrapper workAgent = makeEnterpriseNetworkAgent();
+        workAgent.connect(true);
+        final TestOnCompleteListener listener = new TestOnCompleteListener();
+        mCm.setProfileNetworkPreference(testHandle, PROFILE_NETWORK_PREFERENCE_ENTERPRISE,
+                r -> r.run(), listener);
+        listener.expectOnComplete();
+        assertNoCallbacks(mDefaultNetworkCallback, mTestPackageDefaultNetworkCallback);
+        mProfileDefaultNetworkCallback.expectAvailableCallbacksValidated(workAgent);
+        assertEquals(workAgent.getNetwork(), mCm.getActiveNetworkForUid(TEST_WORK_PROFILE_APP_UID));
+        assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(TEST_PACKAGE_UID));
+
+        // Set oem network preference with TEST_PACKAGE_UID. mTestPackageDefaultNetworkCallback
+        // should receive callback with higher priority network preference (current default network)
+        // and the others should have no callbacks.
+        @OemNetworkPreferences.OemNetworkPreference final int networkPref =
+                OEM_NETWORK_PREFERENCE_OEM_PAID;
+        final int[] uids1 = new int[] { TEST_PACKAGE_UID };
+        final UidRangeParcel[] uidRanges1 = toUidRangeStableParcels(uidRangesForUids(uids1));
+        setupSetOemNetworkPreferenceForPreferenceTest(networkPref, uidRanges1, TEST_PACKAGE_NAME);
+        assertNoCallbacks(mDefaultNetworkCallback, mProfileDefaultNetworkCallback);
+        mTestPackageDefaultNetworkCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent);
+        assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(TEST_PACKAGE_UID));
+        assertEquals(workAgent.getNetwork(), mCm.getActiveNetworkForUid(TEST_WORK_PROFILE_APP_UID));
+
+        // Set oem network preference with TEST_WORK_PROFILE_APP_UID. Both
+        // mProfileDefaultNetworkCallback and mTestPackageDefaultNetworkCallback should receive
+        // callback.
+        final int[] uids2 = new int[] { TEST_WORK_PROFILE_APP_UID };
+        final UidRangeParcel[] uidRanges2 = toUidRangeStableParcels(uidRangesForUids(uids2));
+        when(mUserManager.getUserHandles(anyBoolean())).thenReturn(Arrays.asList(testHandle));
+        setupSetOemNetworkPreferenceForPreferenceTest(
+                networkPref, uidRanges2, "com.android.test", testHandle);
+        mDefaultNetworkCallback.assertNoCallback();
+        mProfileDefaultNetworkCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent);
+        mTestPackageDefaultNetworkCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
+        assertEquals(mWiFiNetworkAgent.getNetwork(),
+                mCm.getActiveNetworkForUid(TEST_WORK_PROFILE_APP_UID));
+        assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(TEST_PACKAGE_UID));
+
+        // Remove oem network preference, mProfileDefaultNetworkCallback should receive callback
+        // with current highest priority network preference (enterprise network) and the others
+        // should have no callbacks.
+        final TestOemListenerCallback oemPrefListener = new TestOemListenerCallback();
+        mService.setOemNetworkPreference(
+                new OemNetworkPreferences.Builder().build(), oemPrefListener);
+        oemPrefListener.expectOnComplete();
+        assertNoCallbacks(mDefaultNetworkCallback, mTestPackageDefaultNetworkCallback);
+        mProfileDefaultNetworkCallback.expectAvailableCallbacksValidated(workAgent);
+        assertEquals(workAgent.getNetwork(), mCm.getActiveNetworkForUid(TEST_WORK_PROFILE_APP_UID));
+        assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(TEST_PACKAGE_UID));
+
+        // Remove user profile network preference.
+        mCm.setProfileNetworkPreference(testHandle, PROFILE_NETWORK_PREFERENCE_DEFAULT,
+                r -> r.run(), listener);
+        listener.expectOnComplete();
+        assertNoCallbacks(mDefaultNetworkCallback, mTestPackageDefaultNetworkCallback);
+        mProfileDefaultNetworkCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
+        assertEquals(mCellNetworkAgent.getNetwork(),
+                mCm.getActiveNetworkForUid(TEST_WORK_PROFILE_APP_UID));
+        assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(TEST_PACKAGE_UID));
+
+        // Disconnect wifi
+        mWiFiNetworkAgent.disconnect();
+        assertNoCallbacks(mProfileDefaultNetworkCallback, mTestPackageDefaultNetworkCallback);
+        mDefaultNetworkCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
+        mDefaultNetworkCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
+    }
 }