Ability for DPM to specify fallback mechanism
Bug: 194332512
Test: unit test
Change-Id: Id4d85da8f64e7559326c4657b8833dac3ce5ce3d
diff --git a/framework/api/module-lib-current.txt b/framework/api/module-lib-current.txt
index 7a0142a..b8dfd3d 100644
--- a/framework/api/module-lib-current.txt
+++ b/framework/api/module-lib-current.txt
@@ -41,6 +41,7 @@
field public static final int BLOCKED_REASON_RESTRICTED_MODE = 8; // 0x8
field public static final int PROFILE_NETWORK_PREFERENCE_DEFAULT = 0; // 0x0
field public static final int PROFILE_NETWORK_PREFERENCE_ENTERPRISE = 1; // 0x1
+ field public static final int PROFILE_NETWORK_PREFERENCE_ENTERPRISE_NO_FALLBACK = 2; // 0x2
}
public static class ConnectivityManager.NetworkCallback {
diff --git a/framework/src/android/net/ConnectivityManager.java b/framework/src/android/net/ConnectivityManager.java
index ba8aabb..9735252 100644
--- a/framework/src/android/net/ConnectivityManager.java
+++ b/framework/src/android/net/ConnectivityManager.java
@@ -1078,7 +1078,8 @@
}
/**
- * Preference for {@link #setNetworkPreferenceForUser(UserHandle, int, Executor, Runnable)}.
+ * Preference for {@link ProfileNetworkPreference#setPreference(int)}.
+ * {@see #setProfileNetworkPreferences(UserHandle, List, Executor, Runnable)}
* Specify that the traffic for this user should by follow the default rules.
* @hide
*/
@@ -1086,7 +1087,8 @@
public static final int PROFILE_NETWORK_PREFERENCE_DEFAULT = 0;
/**
- * Preference for {@link #setNetworkPreferenceForUser(UserHandle, int, Executor, Runnable)}.
+ * Preference for {@link ProfileNetworkPreference#setPreference(int)}.
+ * {@see #setProfileNetworkPreferences(UserHandle, List, Executor, Runnable)}
* Specify that the traffic for this user should by default go on a network with
* {@link NetworkCapabilities#NET_CAPABILITY_ENTERPRISE}, and on the system default network
* if no such network is available.
@@ -1095,11 +1097,23 @@
@SystemApi(client = MODULE_LIBRARIES)
public static final int PROFILE_NETWORK_PREFERENCE_ENTERPRISE = 1;
+ /**
+ * Preference for {@link ProfileNetworkPreference#setPreference(int)}.
+ * {@see #setProfileNetworkPreferences(UserHandle, List, Executor, Runnable)}
+ * Specify that the traffic for this user should by default go on a network with
+ * {@link NetworkCapabilities#NET_CAPABILITY_ENTERPRISE} and if no such network is available
+ * should not go on the system default network
+ * @hide
+ */
+ @SystemApi(client = MODULE_LIBRARIES)
+ public static final int PROFILE_NETWORK_PREFERENCE_ENTERPRISE_NO_FALLBACK = 2;
+
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef(value = {
PROFILE_NETWORK_PREFERENCE_DEFAULT,
- PROFILE_NETWORK_PREFERENCE_ENTERPRISE
+ PROFILE_NETWORK_PREFERENCE_ENTERPRISE,
+ PROFILE_NETWORK_PREFERENCE_ENTERPRISE_NO_FALLBACK
})
public @interface ProfileNetworkPreferencePolicy {
}
diff --git a/framework/src/android/net/ProfileNetworkPreference.java b/framework/src/android/net/ProfileNetworkPreference.java
index d580209..2ce1698 100644
--- a/framework/src/android/net/ProfileNetworkPreference.java
+++ b/framework/src/android/net/ProfileNetworkPreference.java
@@ -63,7 +63,7 @@
@Override
public int hashCode() {
- return (mPreference);
+ return mPreference;
}
/**
@@ -91,6 +91,7 @@
mPreference = preference;
return this;
}
+
/**
* Returns an instance of {@link ProfileNetworkPreference} created from the
* fields set on this builder.
diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java
index e4faf85..a906537 100644
--- a/service/src/com/android/server/ConnectivityService.java
+++ b/service/src/com/android/server/ConnectivityService.java
@@ -5674,7 +5674,7 @@
mPermissionMonitor.onUserRemoved(user);
// If there was a network preference for this user, remove it.
handleSetProfileNetworkPreference(
- List.of(new ProfileNetworkPreferenceList.Preference(user, null)),
+ List.of(new ProfileNetworkPreferenceList.Preference(user, null, true)),
null /* listener */);
if (mOemNetworkPreferences.getNetworkPreferences().size() > 0) {
handleSetOemNetworkPreference(mOemNetworkPreferences, null);
@@ -10139,12 +10139,16 @@
final List<ProfileNetworkPreferenceList.Preference> preferenceList =
new ArrayList<ProfileNetworkPreferenceList.Preference>();
+ boolean allowFallback = true;
for (final ProfileNetworkPreference preference : preferences) {
final NetworkCapabilities nc;
switch (preference.getPreference()) {
case ConnectivityManager.PROFILE_NETWORK_PREFERENCE_DEFAULT:
nc = null;
break;
+ case ConnectivityManager.PROFILE_NETWORK_PREFERENCE_ENTERPRISE_NO_FALLBACK:
+ allowFallback = false;
+ // continue to process the enterprise preference.
case ConnectivityManager.PROFILE_NETWORK_PREFERENCE_ENTERPRISE:
final UidRange uids = UidRange.createForUser(profile);
nc = createDefaultNetworkCapabilitiesForUidRange(uids);
@@ -10155,8 +10159,8 @@
throw new IllegalArgumentException(
"Invalid preference in setProfileNetworkPreferences");
}
- preferenceList.add(
- new ProfileNetworkPreferenceList.Preference(profile, nc));
+ preferenceList.add(new ProfileNetworkPreferenceList.Preference(
+ profile, nc, allowFallback));
}
mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_PROFILE_NETWORK_PREFERENCE,
new Pair<>(preferenceList, listener)));
@@ -10172,17 +10176,17 @@
@NonNull final ProfileNetworkPreferenceList prefs) {
final ArraySet<NetworkRequestInfo> result = new ArraySet<>();
for (final ProfileNetworkPreferenceList.Preference pref : prefs.preferences) {
- // The NRI for a user should be comprised of two layers:
- // - The request for the capabilities
- // - The request for the default network, for fallback. Create an image of it to
- // have the correct UIDs in it (also a request can only be part of one NRI, because
- // of lookups in 1:1 associations like mNetworkRequests).
- // Note that denying a fallback can be implemented simply by not adding the second
- // request.
+ // The NRI for a user should contain the request for capabilities.
+ // If fallback to default network is needed then NRI should include
+ // the request for the default network. Create an image of it to
+ // have the correct UIDs in it (also a request can only be part of one NRI, because
+ // of lookups in 1:1 associations like mNetworkRequests).
final ArrayList<NetworkRequest> nrs = new ArrayList<>();
nrs.add(createNetworkRequest(NetworkRequest.Type.REQUEST, pref.capabilities));
- nrs.add(createDefaultInternetRequestForTransport(
- TYPE_NONE, NetworkRequest.Type.TRACK_DEFAULT));
+ if (pref.allowFallback) {
+ nrs.add(createDefaultInternetRequestForTransport(
+ TYPE_NONE, NetworkRequest.Type.TRACK_DEFAULT));
+ }
setNetworkRequestUids(nrs, UidRange.fromIntRanges(pref.capabilities.getUids()));
final NetworkRequestInfo nri = new NetworkRequestInfo(Process.myUid(), nrs,
PREFERENCE_ORDER_PROFILE);
diff --git a/service/src/com/android/server/connectivity/ProfileNetworkPreferenceList.java b/service/src/com/android/server/connectivity/ProfileNetworkPreferenceList.java
index b345ede..71f342d 100644
--- a/service/src/com/android/server/connectivity/ProfileNetworkPreferenceList.java
+++ b/service/src/com/android/server/connectivity/ProfileNetworkPreferenceList.java
@@ -38,16 +38,22 @@
@NonNull public final UserHandle user;
// Capabilities are only null when sending an object to remove the setting for a user
@Nullable public final NetworkCapabilities capabilities;
+ public final boolean allowFallback;
public Preference(@NonNull final UserHandle user,
- @Nullable final NetworkCapabilities capabilities) {
+ @Nullable final NetworkCapabilities capabilities,
+ final boolean allowFallback) {
this.user = user;
this.capabilities = null == capabilities ? null : new NetworkCapabilities(capabilities);
+ this.allowFallback = allowFallback;
}
/** toString */
public String toString() {
- return "[ProfileNetworkPreference user=" + user + " caps=" + capabilities + "]";
+ return "[ProfileNetworkPreference user=" + user
+ + " caps=" + capabilities
+ + " allowFallback=" + allowFallback
+ + "]";
}
}
diff --git a/tests/unit/java/com/android/server/ConnectivityServiceTest.java b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
index 8d91552..abb34dc 100644
--- a/tests/unit/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
@@ -51,6 +51,7 @@
import static android.net.ConnectivityManager.EXTRA_NETWORK_TYPE;
import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_DEFAULT;
import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_ENTERPRISE;
+import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_ENTERPRISE_NO_FALLBACK;
import static android.net.ConnectivityManager.TYPE_ETHERNET;
import static android.net.ConnectivityManager.TYPE_MOBILE;
import static android.net.ConnectivityManager.TYPE_MOBILE_FOTA;
@@ -250,6 +251,7 @@
import android.net.NetworkTestResultParcelable;
import android.net.OemNetworkPreferences;
import android.net.PacProxyManager;
+import android.net.ProfileNetworkPreference;
import android.net.Proxy;
import android.net.ProxyInfo;
import android.net.QosCallbackException;
@@ -13755,12 +13757,12 @@
}
/**
- * Make sure per-profile networking preference behaves as expected when the enterprise network
- * goes up and down while the preference is active. Make sure they behave as expected whether
- * there is a general default network or not.
+ * Make sure per profile network preferences behave as expected for a given
+ * profile network preference.
*/
- @Test
- public void testPreferenceForUserNetworkUpDown() throws Exception {
+ public void testPreferenceForUserNetworkUpDownForGivenPreference(
+ ProfileNetworkPreference profileNetworkPreference,
+ boolean connectWorkProfileAgentAhead) throws Exception {
final InOrder inOrder = inOrder(mMockNetd);
final UserHandle testHandle = setupEnterpriseNetwork();
registerDefaultNetworkCallbacks();
@@ -13774,29 +13776,45 @@
inOrder.verify(mMockNetd).networkCreate(nativeNetworkConfigPhysical(
mCellNetworkAgent.getNetwork().netId, INetd.PERMISSION_NONE));
+ final TestNetworkAgentWrapper workAgent = makeEnterpriseNetworkAgent();
+ if (connectWorkProfileAgentAhead) {
+ workAgent.connect(false);
+ }
final TestOnCompleteListener listener = new TestOnCompleteListener();
- mCm.setProfileNetworkPreference(testHandle, PROFILE_NETWORK_PREFERENCE_ENTERPRISE,
+ mCm.setProfileNetworkPreferences(testHandle, List.of(profileNetworkPreference),
r -> r.run(), listener);
listener.expectOnComplete();
-
- // Setting a network preference for this user will create a new set of routing rules for
- // the UID range that corresponds to this user, so as to define the default network
- // for these apps separately. This is true because the multi-layer request relevant to
- // this UID range contains a TRACK_DEFAULT, so the range will be moved through UID-specific
- // rules to the correct network – in this case the system default network. The case where
- // the default network for the profile happens to be the same as the system default
- // 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),
- PREFERENCE_ORDER_PROFILE));
+ boolean allowFallback = true;
+ if (profileNetworkPreference.getPreference()
+ == PROFILE_NETWORK_PREFERENCE_ENTERPRISE_NO_FALLBACK) {
+ allowFallback = false;
+ }
+ if (allowFallback) {
+ // Setting a network preference for this user will create a new set of routing rules for
+ // the UID range that corresponds to this user, inorder to define the default network
+ // for these apps separately. This is true because the multi-layer request relevant to
+ // this UID range contains a TRACK_DEFAULT, so the range will be moved through
+ // UID-specific rules to the correct network – in this case the system default network.
+ // The case where the default network for the profile happens to be the same as the
+ // system default 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),
+ PREFERENCE_ORDER_PROFILE));
+ }
// The enterprise network is not ready yet.
- assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback,
- mProfileDefaultNetworkCallback);
+ assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback);
+ if (allowFallback) {
+ assertNoCallbacks(mProfileDefaultNetworkCallback);
+ } else if (!connectWorkProfileAgentAhead) {
+ mProfileDefaultNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
+ }
- final TestNetworkAgentWrapper workAgent = makeEnterpriseNetworkAgent();
- workAgent.connect(false);
+ if (!connectWorkProfileAgentAhead) {
+ workAgent.connect(false);
+ }
mProfileDefaultNetworkCallback.expectAvailableCallbacksUnvalidated(workAgent);
mSystemDefaultNetworkCallback.assertNoCallback();
@@ -13805,9 +13823,12 @@
nativeNetworkConfigPhysical(workAgent.getNetwork().netId, INetd.PERMISSION_SYSTEM));
inOrder.verify(mMockNetd).networkAddUidRangesParcel(new NativeUidRangeConfig(
workAgent.getNetwork().netId, uidRangeFor(testHandle), PREFERENCE_ORDER_PROFILE));
- inOrder.verify(mMockNetd).networkRemoveUidRangesParcel(new NativeUidRangeConfig(
- mCellNetworkAgent.getNetwork().netId, uidRangeFor(testHandle),
- PREFERENCE_ORDER_PROFILE));
+
+ if (allowFallback) {
+ inOrder.verify(mMockNetd).networkRemoveUidRangesParcel(new NativeUidRangeConfig(
+ mCellNetworkAgent.getNetwork().netId, uidRangeFor(testHandle),
+ PREFERENCE_ORDER_PROFILE));
+ }
// Make sure changes to the work agent send callbacks to the app in the work profile, but
// not to the other apps.
@@ -13853,17 +13874,23 @@
// default network.
workAgent.disconnect();
mProfileDefaultNetworkCallback.expectCallback(CallbackEntry.LOST, workAgent);
- mProfileDefaultNetworkCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
+ if (allowFallback) {
+ mProfileDefaultNetworkCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
+ }
assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback);
- inOrder.verify(mMockNetd).networkAddUidRangesParcel(new NativeUidRangeConfig(
- mCellNetworkAgent.getNetwork().netId, uidRangeFor(testHandle),
- PREFERENCE_ORDER_PROFILE));
+ if (allowFallback) {
+ inOrder.verify(mMockNetd).networkAddUidRangesParcel(new NativeUidRangeConfig(
+ mCellNetworkAgent.getNetwork().netId, uidRangeFor(testHandle),
+ PREFERENCE_ORDER_PROFILE));
+ }
inOrder.verify(mMockNetd).networkDestroy(workAgent.getNetwork().netId);
mCellNetworkAgent.disconnect();
mSystemDefaultNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
mDefaultNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- mProfileDefaultNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
+ if (allowFallback) {
+ mProfileDefaultNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
+ }
// Waiting for the handler to be idle before checking for networkDestroy is necessary
// here because ConnectivityService calls onLost before the network is fully torn down.
@@ -13891,7 +13918,7 @@
assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback);
inOrder.verify(mMockNetd, never()).networkAddUidRangesParcel(any());
- // When the agent disconnects, test that the app on the work profile falls back to the
+ // When the agent disconnects, test that the app on the work profile fall back to the
// default network.
workAgent2.disconnect();
mProfileDefaultNetworkCallback.expectCallback(CallbackEntry.LOST, workAgent2);
@@ -13905,6 +13932,52 @@
}
/**
+ * Make sure per-profile networking preference behaves as expected when the enterprise network
+ * goes up and down while the preference is active. Make sure they behave as expected whether
+ * there is a general default network or not.
+ */
+ @Test
+ public void testPreferenceForUserNetworkUpDown() throws Exception {
+ ProfileNetworkPreference.Builder profileNetworkPreferenceBuilder =
+ new ProfileNetworkPreference.Builder();
+ profileNetworkPreferenceBuilder.setPreference(PROFILE_NETWORK_PREFERENCE_ENTERPRISE);
+ testPreferenceForUserNetworkUpDownForGivenPreference(
+ profileNetworkPreferenceBuilder.build(), false);
+ }
+
+ /**
+ * Make sure per-profile networking preference behaves as expected when the enterprise network
+ * goes up and down while the preference is active. Make sure they behave as expected whether
+ * there is a general default network or not when configured to not fallback to default network.
+ */
+ @Test
+ public void testPreferenceForUserNetworkUpDownWithNoFallback() throws Exception {
+ ProfileNetworkPreference.Builder profileNetworkPreferenceBuilder =
+ new ProfileNetworkPreference.Builder();
+ profileNetworkPreferenceBuilder.setPreference(
+ PROFILE_NETWORK_PREFERENCE_ENTERPRISE_NO_FALLBACK);
+ testPreferenceForUserNetworkUpDownForGivenPreference(
+ profileNetworkPreferenceBuilder.build(), false);
+ }
+
+ /**
+ * Make sure per-profile networking preference behaves as expected when the enterprise network
+ * goes up and down while the preference is active. Make sure they behave as expected whether
+ * there is a general default network or not when configured to not fallback to default network
+ * along with already connected enterprise work agent
+ */
+ @Test
+ public void testPreferenceForUserNetworkUpDownWithNoFallbackWithAlreadyConnectedWorkAgent()
+ throws Exception {
+ ProfileNetworkPreference.Builder profileNetworkPreferenceBuilder =
+ new ProfileNetworkPreference.Builder();
+ profileNetworkPreferenceBuilder.setPreference(
+ PROFILE_NETWORK_PREFERENCE_ENTERPRISE_NO_FALLBACK);
+ testPreferenceForUserNetworkUpDownForGivenPreference(
+ profileNetworkPreferenceBuilder.build(), true);
+ }
+
+ /**
* Test that, in a given networking context, calling setPreferenceForUser to set per-profile
* defaults on then off works as expected.
*/
@@ -14057,7 +14130,8 @@
assertThrows("Should not be able to set an illegal preference",
IllegalArgumentException.class,
() -> mCm.setProfileNetworkPreference(testHandle,
- PROFILE_NETWORK_PREFERENCE_ENTERPRISE + 1, null, null));
+ PROFILE_NETWORK_PREFERENCE_ENTERPRISE_NO_FALLBACK + 1,
+ null, null));
}
/**