diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java index 0b612470d2..b655ed6e6a 100644 --- a/service/src/com/android/server/ConnectivityService.java +++ b/service/src/com/android/server/ConnectivityService.java @@ -402,30 +402,45 @@ public class ConnectivityService extends IConnectivityManager.Stub } /** - * 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 @@ public class ConnectivityService extends IConnectivityManager.Stub 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 @@ public class ConnectivityService extends IConnectivityManager.Stub 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 @@ public class ConnectivityService extends IConnectivityManager.Stub 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 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 @@ public class ConnectivityService extends IConnectivityManager.Stub */ 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 @@ public class ConnectivityService extends IConnectivityManager.Stub mPerUidCounter.incrementCountOrThrow(mUid); mCallbackFlags = callbackFlags; mCallingAttributionTag = callingAttributionTag; - mDefaultNetworkPriority = DEFAULT_NETWORK_PRIORITY_NONE; + mPreferencePriority = PREFERENCE_PRIORITY_INVALID; linkDeathRecipient(); } @@ -5807,18 +5818,18 @@ public class ConnectivityService extends IConnectivityManager.Stub 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 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 @@ public class ConnectivityService extends IConnectivityManager.Stub } } + 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 @@ public class ConnectivityService extends IConnectivityManager.Stub + mNetworkRequestForCallback.requestId + " " + mRequests + (mPendingIntent == null ? "" : " to trigger " + mPendingIntent) - + " callback flags: " + mCallbackFlags; + + " callback flags: " + mCallbackFlags + + " priority: " + mPreferencePriority; } } @@ -6467,17 +6492,18 @@ public class ConnectivityService extends IConnectivityManager.Stub */ @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 @@ public class ConnectivityService extends IConnectivityManager.Stub } 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 @@ public class ConnectivityService extends IConnectivityManager.Stub } 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 @@ public class ConnectivityService extends IConnectivityManager.Stub } } - private void updateUidRanges(boolean add, NetworkAgentInfo nai, Set uidRanges) { + private void updateVpnUidRanges(boolean add, NetworkAgentInfo nai, Set 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 @@ public class ConnectivityService extends IConnectivityManager.Stub 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 @@ public class ConnectivityService extends IConnectivityManager.Stub // 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 @@ public class ConnectivityService extends IConnectivityManager.Stub 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 @@ public class ConnectivityService extends IConnectivityManager.Stub 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 @@ public class ConnectivityService extends IConnectivityManager.Stub 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 @@ public class ConnectivityService extends IConnectivityManager.Stub 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 @@ public class ConnectivityService extends IConnectivityManager.Stub 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 @@ public class ConnectivityService extends IConnectivityManager.Stub () -> { final ArraySet nris = createNrisFromProfileNetworkPreferences(mProfileNetworkPreferences); - replaceDefaultNetworkRequestsForPreference(nris); + replaceDefaultNetworkRequestsForPreference(nris, PREFERENCE_PRIORITY_PROFILE); }); // Finally, rematch. rematchAllNetworksAndRequests(); @@ -9954,26 +9946,19 @@ public class ConnectivityService extends IConnectivityManager.Stub } 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 nris = createNrisFromMobileDataPreferredUids(mMobileDataPreferredUids); - replaceDefaultNetworkRequestsForPreference(nris); + replaceDefaultNetworkRequestsForPreference(nris, + PREFERENCE_PRIORITY_MOBILE_DATA_PREFERERRED); }); // Finally, rematch. rematchAllNetworksAndRequests(); @@ -10015,16 +10000,6 @@ public class ConnectivityService extends IConnectivityManager.Stub 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 @@ public class ConnectivityService extends IConnectivityManager.Stub 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 @@ public class ConnectivityService extends IConnectivityManager.Stub final ArraySet nris = new OemNetworkRequestFactory() .createNrisFromOemNetworkPreferences(preference); - replaceDefaultNetworkRequestsForPreference(nris); + replaceDefaultNetworkRequestsForPreference(nris, PREFERENCE_PRIORITY_OEM); }); mOemNetworkPreferences = preference; @@ -10106,9 +10070,12 @@ public class ConnectivityService extends IConnectivityManager.Stub } private void replaceDefaultNetworkRequestsForPreference( - @NonNull final Set nris) { - // Pass in a defensive copy as this collection will be updated on remove. - handleRemoveNetworkRequests(new ArraySet<>(mDefaultNetworkRequests)); + @NonNull final Set 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 requests = new ArraySet<>(mDefaultNetworkRequests); + requests.removeIf(request -> request.mPreferencePriority != preferencePriority); + handleRemoveNetworkRequests(requests); addPerAppDefaultNetworkRequests(nris); } @@ -10302,8 +10269,7 @@ public class ConnectivityService extends IConnectivityManager.Stub 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 cdf5d62a9f..103ed8bbe6 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.net.resolv.aidl.IDnsResolverUnsolicitedEventListener.VALID 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 @@ public class ConnectivityServiceTest { 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 @@ public class ConnectivityServiceTest { 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 @@ public class ConnectivityServiceTest { 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 @@ public class ConnectivityServiceTest { .createNrisFromOemNetworkPreferences( createDefaultOemNetworkPreferences(prefToTest)); final NetworkRequestInfo nri = nris.iterator().next(); - assertEquals(DEFAULT_NETWORK_PRIORITY_OEM, nri.getDefaultNetworkPriority()); + assertEquals(PREFERENCE_PRIORITY_OEM, nri.mPreferencePriority); final List mRequests = nri.mRequests; assertEquals(expectedNumOfNris, nris.size()); assertEquals(expectedNumOfRequests, mRequests.size()); @@ -11064,7 +11065,7 @@ public class ConnectivityServiceTest { .createNrisFromOemNetworkPreferences( createDefaultOemNetworkPreferences(prefToTest)); final NetworkRequestInfo nri = nris.iterator().next(); - assertEquals(DEFAULT_NETWORK_PRIORITY_OEM, nri.getDefaultNetworkPriority()); + assertEquals(PREFERENCE_PRIORITY_OEM, nri.mPreferencePriority); final List mRequests = nri.mRequests; assertEquals(expectedNumOfNris, nris.size()); assertEquals(expectedNumOfRequests, mRequests.size()); @@ -11091,7 +11092,7 @@ public class ConnectivityServiceTest { .createNrisFromOemNetworkPreferences( createDefaultOemNetworkPreferences(prefToTest)); final NetworkRequestInfo nri = nris.iterator().next(); - assertEquals(DEFAULT_NETWORK_PRIORITY_OEM, nri.getDefaultNetworkPriority()); + assertEquals(PREFERENCE_PRIORITY_OEM, nri.mPreferencePriority); final List mRequests = nri.mRequests; assertEquals(expectedNumOfNris, nris.size()); assertEquals(expectedNumOfRequests, mRequests.size()); @@ -11115,7 +11116,7 @@ public class ConnectivityServiceTest { .createNrisFromOemNetworkPreferences( createDefaultOemNetworkPreferences(prefToTest)); final NetworkRequestInfo nri = nris.iterator().next(); - assertEquals(DEFAULT_NETWORK_PRIORITY_OEM, nri.getDefaultNetworkPriority()); + assertEquals(PREFERENCE_PRIORITY_OEM, nri.mPreferencePriority); final List mRequests = nri.mRequests; assertEquals(expectedNumOfNris, nris.size()); assertEquals(expectedNumOfRequests, mRequests.size()); @@ -11493,19 +11494,29 @@ public class ConnectivityServiceTest { @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 @@ public class ConnectivityServiceTest { 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 @@ public class ConnectivityServiceTest { // 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 @@ public class ConnectivityServiceTest { // 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 @@ public class ConnectivityServiceTest { 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 @@ public class ConnectivityServiceTest { 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 @@ public class ConnectivityServiceTest { 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 @@ public class ConnectivityServiceTest { 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 @@ public class ConnectivityServiceTest { 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 @@ public class ConnectivityServiceTest { 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 @@ public class ConnectivityServiceTest { 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 @@ public class ConnectivityServiceTest { 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 @@ public class ConnectivityServiceTest { 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 @@ public class ConnectivityServiceTest { 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 @@ public class ConnectivityServiceTest { 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 @@ public class ConnectivityServiceTest { final Set 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 @@ public class ConnectivityServiceTest { 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 @@ public class ConnectivityServiceTest { final Set 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 @@ public class ConnectivityServiceTest { 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 @@ public class ConnectivityServiceTest { 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 @@ public class ConnectivityServiceTest { 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 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 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); + } }