diff --git a/core/java/android/net/vcn/VcnManager.java b/core/java/android/net/vcn/VcnManager.java
index 40e4083c02db2..3a7aea5d5194d 100644
--- a/core/java/android/net/vcn/VcnManager.java
+++ b/core/java/android/net/vcn/VcnManager.java
@@ -104,12 +104,23 @@ public class VcnManager {
// TODO: Add separate signal strength thresholds for 2.4 GHz and 5GHz
+ /**
+ * Key for transports that need to be marked as restricted by the VCN
+ *
+ *
Defaults to TRANSPORT_WIFI if the config does not exist
+ *
+ * @hide
+ */
+ public static final String VCN_RESTRICTED_TRANSPORTS_INT_ARRAY_KEY =
+ "vcn_restricted_transports";
+
/** List of Carrier Config options to extract from Carrier Config bundles. @hide */
@NonNull
public static final String[] VCN_RELATED_CARRIER_CONFIG_KEYS =
new String[] {
VCN_NETWORK_SELECTION_WIFI_ENTRY_RSSI_THRESHOLD_KEY,
- VCN_NETWORK_SELECTION_WIFI_EXIT_RSSI_THRESHOLD_KEY
+ VCN_NETWORK_SELECTION_WIFI_EXIT_RSSI_THRESHOLD_KEY,
+ VCN_RESTRICTED_TRANSPORTS_INT_ARRAY_KEY
};
private static final Map<
diff --git a/services/core/java/com/android/server/VcnManagementService.java b/services/core/java/com/android/server/VcnManagementService.java
index 76cac934fdfea..61f7f301a838e 100644
--- a/services/core/java/com/android/server/VcnManagementService.java
+++ b/services/core/java/com/android/server/VcnManagementService.java
@@ -18,8 +18,11 @@ package com.android.server;
import static android.Manifest.permission.DUMP;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkCapabilities.TRANSPORT_TEST;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
+import static android.net.vcn.VcnGatewayConnectionConfig.ALLOWED_CAPABILITIES;
+import static android.net.vcn.VcnManager.VCN_RESTRICTED_TRANSPORTS_INT_ARRAY_KEY;
import static android.net.vcn.VcnManager.VCN_STATUS_CODE_ACTIVE;
import static android.net.vcn.VcnManager.VCN_STATUS_CODE_INACTIVE;
import static android.net.vcn.VcnManager.VCN_STATUS_CODE_NOT_CONFIGURED;
@@ -53,6 +56,7 @@ import android.net.vcn.VcnManager.VcnStatusCode;
import android.net.vcn.VcnUnderlyingNetworkPolicy;
import android.net.wifi.WifiInfo;
import android.os.Binder;
+import android.os.Build;
import android.os.Environment;
import android.os.Handler;
import android.os.HandlerThread;
@@ -68,6 +72,7 @@ import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.util.ArrayMap;
+import android.util.ArraySet;
import android.util.LocalLog;
import android.util.Log;
import android.util.Slog;
@@ -83,6 +88,7 @@ import com.android.server.vcn.Vcn;
import com.android.server.vcn.VcnContext;
import com.android.server.vcn.VcnNetworkProvider;
import com.android.server.vcn.util.PersistableBundleUtils;
+import com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper;
import java.io.File;
import java.io.FileDescriptor;
@@ -159,6 +165,9 @@ public class VcnManagementService extends IVcnManagementService.Stub {
private static final long DUMP_TIMEOUT_MILLIS = TimeUnit.SECONDS.toMillis(5);
private static final int LOCAL_LOG_LINE_COUNT = 512;
+ private static final Set RESTRICTED_TRANSPORTS_DEFAULT =
+ Collections.singleton(TRANSPORT_WIFI);
+
// Public for use in all other VCN classes
@NonNull public static final LocalLog LOCAL_LOG = new LocalLog(LOCAL_LOG_LINE_COUNT);
@@ -361,6 +370,34 @@ public class VcnManagementService extends IVcnManagementService.Stub {
public LocationPermissionChecker newLocationPermissionChecker(@NonNull Context context) {
return new LocationPermissionChecker(context);
}
+
+ /** Gets the transports that need to be marked as restricted by the VCN */
+ public Set getRestrictedTransports(
+ ParcelUuid subGrp, TelephonySubscriptionSnapshot lastSnapshot) {
+ if (!Build.IS_ENG && !Build.IS_USERDEBUG) {
+ return RESTRICTED_TRANSPORTS_DEFAULT;
+ }
+
+ final PersistableBundleWrapper carrierConfig =
+ lastSnapshot.getCarrierConfigForSubGrp(subGrp);
+ if (carrierConfig == null) {
+ return RESTRICTED_TRANSPORTS_DEFAULT;
+ }
+
+ final int[] defaultValue =
+ RESTRICTED_TRANSPORTS_DEFAULT.stream().mapToInt(i -> i).toArray();
+ final int[] restrictedTransportsArray =
+ carrierConfig.getIntArray(
+ VCN_RESTRICTED_TRANSPORTS_INT_ARRAY_KEY,
+ defaultValue);
+
+ // Convert to a boxed set
+ final Set restrictedTransports = new ArraySet<>();
+ for (int transport : restrictedTransportsArray) {
+ restrictedTransports.add(transport);
+ }
+ return restrictedTransports;
+ }
}
/** Notifies the VcnManagementService that external dependencies can be set up. */
@@ -517,6 +554,7 @@ public class VcnManagementService extends IVcnManagementService.Stub {
}
}
+ boolean needNotifyAllPolicyListeners = false;
// Schedule teardown of any VCN instances that have lost carrier privileges (after a
// delay)
for (Entry entry : mVcns.entrySet()) {
@@ -564,6 +602,10 @@ public class VcnManagementService extends IVcnManagementService.Stub {
} else {
// If this VCN's status has not changed, update it with the new snapshot
entry.getValue().updateSubscriptionSnapshot(mLastSnapshot);
+ needNotifyAllPolicyListeners |=
+ !Objects.equals(
+ oldSnapshot.getCarrierConfigForSubGrp(subGrp),
+ mLastSnapshot.getCarrierConfigForSubGrp(subGrp));
}
}
@@ -573,6 +615,10 @@ public class VcnManagementService extends IVcnManagementService.Stub {
getSubGroupToSubIdMappings(mLastSnapshot);
if (!currSubGrpMappings.equals(oldSubGrpMappings)) {
garbageCollectAndWriteVcnConfigsLocked();
+ needNotifyAllPolicyListeners = true;
+ }
+
+ if (needNotifyAllPolicyListeners) {
notifyAllPolicyListenersLocked();
}
}
@@ -917,6 +963,14 @@ public class VcnManagementService extends IVcnManagementService.Stub {
});
}
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ void addVcnUnderlyingNetworkPolicyListenerForTest(
+ @NonNull IVcnUnderlyingNetworkPolicyListener listener) {
+ synchronized (mLock) {
+ addVcnUnderlyingNetworkPolicyListener(listener);
+ }
+ }
+
/** Removes the provided listener from receiving VcnUnderlyingNetworkPolicy updates. */
@GuardedBy("mLock")
@Override
@@ -1000,7 +1054,7 @@ public class VcnManagementService extends IVcnManagementService.Stub {
final ParcelUuid subGrp = getSubGroupForNetworkCapabilities(ncCopy);
boolean isVcnManagedNetwork = false;
- boolean isRestrictedCarrierWifi = false;
+ boolean isRestricted = false;
synchronized (mLock) {
final Vcn vcn = mVcns.get(subGrp);
if (vcn != null) {
@@ -1008,9 +1062,19 @@ public class VcnManagementService extends IVcnManagementService.Stub {
isVcnManagedNetwork = true;
}
- if (ncCopy.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
- // Carrier WiFi always restricted if VCN exists (even in safe mode).
- isRestrictedCarrierWifi = true;
+ final Set restrictedTransports =
+ mDeps.getRestrictedTransports(subGrp, mLastSnapshot);
+ for (int restrictedTransport : restrictedTransports) {
+ if (ncCopy.hasTransport(restrictedTransport)) {
+ if (restrictedTransport == TRANSPORT_CELLULAR) {
+ // Only make a cell network as restricted when the VCN is in
+ // active mode.
+ isRestricted |= (vcn.getStatus() == VCN_STATUS_CODE_ACTIVE);
+ } else {
+ isRestricted = true;
+ break;
+ }
+ }
}
}
}
@@ -1024,14 +1088,16 @@ public class VcnManagementService extends IVcnManagementService.Stub {
ncBuilder.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED);
}
- if (isRestrictedCarrierWifi) {
+ if (isRestricted) {
ncBuilder.removeCapability(
NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
}
final NetworkCapabilities result = ncBuilder.build();
final VcnUnderlyingNetworkPolicy policy = new VcnUnderlyingNetworkPolicy(
- mTrackingNetworkCallback.requiresRestartForCarrierWifi(result), result);
+ mTrackingNetworkCallback
+ .requiresRestartForImmutableCapabilityChanges(result),
+ result);
logVdbg("getUnderlyingNetworkPolicy() called for caps: " + networkCapabilities
+ "; and lp: " + linkProperties + "; result = " + policy);
@@ -1296,15 +1362,38 @@ public class VcnManagementService extends IVcnManagementService.Stub {
}
}
- private boolean requiresRestartForCarrierWifi(NetworkCapabilities caps) {
- if (!caps.hasTransport(TRANSPORT_WIFI) || caps.getSubscriptionIds() == null) {
+ private Set getNonTestTransportTypes(NetworkCapabilities caps) {
+ final Set transportTypes = new ArraySet<>();
+ for (int t : caps.getTransportTypes()) {
+ transportTypes.add(t);
+ }
+ return transportTypes;
+ }
+
+ private boolean hasSameTransportsAndCapabilities(
+ NetworkCapabilities caps, NetworkCapabilities capsOther) {
+ if (!Objects.equals(
+ getNonTestTransportTypes(caps), getNonTestTransportTypes(capsOther))) {
+ return false;
+ }
+
+ for (int capability : ALLOWED_CAPABILITIES) {
+ if (caps.hasCapability(capability) != capsOther.hasCapability(capability)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private boolean requiresRestartForImmutableCapabilityChanges(NetworkCapabilities caps) {
+ if (caps.getSubscriptionIds() == null) {
return false;
}
synchronized (mCaps) {
for (NetworkCapabilities existing : mCaps.values()) {
- if (existing.hasTransport(TRANSPORT_WIFI)
- && caps.getSubscriptionIds().equals(existing.getSubscriptionIds())) {
+ if (caps.getSubscriptionIds().equals(existing.getSubscriptionIds())
+ && hasSameTransportsAndCapabilities(caps, existing)) {
// Restart if any immutable capabilities have changed
return existing.hasCapability(NET_CAPABILITY_NOT_RESTRICTED)
!= caps.hasCapability(NET_CAPABILITY_NOT_RESTRICTED);
diff --git a/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java b/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java
index 5c305c6902af3..ca4a32f553aea 100644
--- a/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java
+++ b/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java
@@ -390,8 +390,13 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver {
Objects.requireNonNull(privilegedPackages, "privilegedPackages was null");
Objects.requireNonNull(subIdToCarrierConfigMap, "subIdToCarrierConfigMap was null");
- mSubIdToInfoMap = Collections.unmodifiableMap(subIdToInfoMap);
- mSubIdToCarrierConfigMap = Collections.unmodifiableMap(subIdToCarrierConfigMap);
+ mSubIdToInfoMap =
+ Collections.unmodifiableMap(
+ new HashMap(subIdToInfoMap));
+ mSubIdToCarrierConfigMap =
+ Collections.unmodifiableMap(
+ new HashMap(
+ subIdToCarrierConfigMap));
final Map> unmodifiableInnerSets = new ArrayMap<>();
for (Entry> entry : privilegedPackages.entrySet()) {
diff --git a/services/core/java/com/android/server/vcn/util/PersistableBundleUtils.java b/services/core/java/com/android/server/vcn/util/PersistableBundleUtils.java
index 999d4064c9516..d22ec0ad456d2 100644
--- a/services/core/java/com/android/server/vcn/util/PersistableBundleUtils.java
+++ b/services/core/java/com/android/server/vcn/util/PersistableBundleUtils.java
@@ -544,6 +544,20 @@ public class PersistableBundleUtils {
return mBundle.getInt(key, defaultValue);
}
+ /**
+ * Returns the value associated with the given key, or null if no mapping of the desired
+ * type exists for the given key or a null value is explicitly associated with the key.
+ *
+ * @param key a String, or null
+ * @param defaultValue the value to return if key does not exist
+ * @return an int[] value, or null
+ */
+ @Nullable
+ public int[] getIntArray(@Nullable String key, @Nullable int[] defaultValue) {
+ final int[] value = mBundle.getIntArray(key);
+ return value == null ? defaultValue : value;
+ }
+
@Override
public int hashCode() {
return getHashCode(mBundle);
diff --git a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
index ad068308d481b..258642ac229e7 100644
--- a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
+++ b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
@@ -17,10 +17,12 @@
package com.android.server;
import static android.net.ConnectivityManager.NetworkCallback;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_IMS;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
+import static android.net.vcn.VcnManager.VCN_RESTRICTED_TRANSPORTS_INT_ARRAY_KEY;
import static android.net.vcn.VcnManager.VCN_STATUS_CODE_ACTIVE;
import static android.net.vcn.VcnManager.VCN_STATUS_CODE_SAFE_MODE;
import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
@@ -95,6 +97,7 @@ import com.android.server.vcn.Vcn;
import com.android.server.vcn.VcnContext;
import com.android.server.vcn.VcnNetworkProvider;
import com.android.server.vcn.util.PersistableBundleUtils;
+import com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper;
import org.junit.Before;
import org.junit.Test;
@@ -252,6 +255,10 @@ public class VcnManagementServiceTest {
.when(mMockContext)
.enforceCallingOrSelfPermission(
eq(android.Manifest.permission.NETWORK_FACTORY), any());
+
+ doReturn(Collections.singleton(TRANSPORT_WIFI))
+ .when(mMockDeps)
+ .getRestrictedTransports(any(), any());
}
@@ -1031,63 +1038,188 @@ public class VcnManagementServiceTest {
new LinkProperties());
}
+ private void checkGetRestrictedTransports(
+ ParcelUuid subGrp,
+ TelephonySubscriptionSnapshot lastSnapshot,
+ Set expectedTransports) {
+ Set result =
+ new VcnManagementService.Dependencies()
+ .getRestrictedTransports(subGrp, lastSnapshot);
+ assertEquals(expectedTransports, result);
+ }
+
@Test
- public void testGetUnderlyingNetworkPolicyCellular() throws Exception {
+ public void testGetRestrictedTransports() {
+ final Set restrictedTransports = new ArraySet<>();
+ restrictedTransports.add(TRANSPORT_CELLULAR);
+ restrictedTransports.add(TRANSPORT_WIFI);
+
+ PersistableBundle carrierConfigBundle = new PersistableBundle();
+ carrierConfigBundle.putIntArray(
+ VCN_RESTRICTED_TRANSPORTS_INT_ARRAY_KEY,
+ restrictedTransports.stream().mapToInt(i -> i).toArray());
+ final PersistableBundleWrapper carrierConfig =
+ new PersistableBundleWrapper(carrierConfigBundle);
+
+ final TelephonySubscriptionSnapshot lastSnapshot =
+ mock(TelephonySubscriptionSnapshot.class);
+ doReturn(carrierConfig).when(lastSnapshot).getCarrierConfigForSubGrp(eq(TEST_UUID_2));
+
+ checkGetRestrictedTransports(TEST_UUID_2, lastSnapshot, restrictedTransports);
+ }
+
+ @Test
+ public void testGetRestrictedTransports_noRestrictPolicyConfigured() {
+ final Set restrictedTransports = Collections.singleton(TRANSPORT_WIFI);
+
+ final PersistableBundleWrapper carrierConfig =
+ new PersistableBundleWrapper(new PersistableBundle());
+ final TelephonySubscriptionSnapshot lastSnapshot =
+ mock(TelephonySubscriptionSnapshot.class);
+ doReturn(carrierConfig).when(lastSnapshot).getCarrierConfigForSubGrp(eq(TEST_UUID_2));
+
+ checkGetRestrictedTransports(TEST_UUID_2, lastSnapshot, restrictedTransports);
+ }
+
+ @Test
+ public void testGetRestrictedTransports_noCarrierConfig() {
+ final Set restrictedTransports = Collections.singleton(TRANSPORT_WIFI);
+
+ final TelephonySubscriptionSnapshot lastSnapshot =
+ mock(TelephonySubscriptionSnapshot.class);
+
+ checkGetRestrictedTransports(TEST_UUID_2, lastSnapshot, restrictedTransports);
+ }
+
+ private void checkGetUnderlyingNetworkPolicy(
+ int transportType,
+ boolean isTransportRestricted,
+ boolean isActive,
+ boolean expectVcnManaged,
+ boolean expectRestricted)
+ throws Exception {
+
+ final Set restrictedTransports = new ArraySet();
+ if (isTransportRestricted) {
+ restrictedTransports.add(transportType);
+ }
+ doReturn(restrictedTransports).when(mMockDeps).getRestrictedTransports(any(), any());
+
final VcnUnderlyingNetworkPolicy policy =
startVcnAndGetPolicyForTransport(
- TEST_SUBSCRIPTION_ID, TEST_UUID_2, true /* isActive */, TRANSPORT_CELLULAR);
+ TEST_SUBSCRIPTION_ID, TEST_UUID_2, isActive, transportType);
+
+ assertFalse(policy.isTeardownRequested());
+ verifyMergedNetworkCapabilities(
+ policy.getMergedNetworkCapabilities(),
+ transportType,
+ expectVcnManaged,
+ expectRestricted);
+ }
+
+ @Test
+ public void testGetUnderlyingNetworkPolicy_unrestrictCell() throws Exception {
+ checkGetUnderlyingNetworkPolicy(
+ TRANSPORT_CELLULAR,
+ false /* isTransportRestricted */,
+ true /* isActive */,
+ true /* expectVcnManaged */,
+ false /* expectRestricted */);
+ }
+
+ @Test
+ public void testGetUnderlyingNetworkPolicy_unrestrictCellSafeMode() throws Exception {
+ checkGetUnderlyingNetworkPolicy(
+ TRANSPORT_CELLULAR,
+ false /* isTransportRestricted */,
+ false /* isActive */,
+ false /* expectVcnManaged */,
+ false /* expectRestricted */);
+ }
+
+ @Test
+ public void testGetUnderlyingNetworkPolicy_restrictCell() throws Exception {
+ checkGetUnderlyingNetworkPolicy(
+ TRANSPORT_CELLULAR,
+ true /* isTransportRestricted */,
+ true /* isActive */,
+ true /* expectVcnManaged */,
+ true /* expectRestricted */);
+ }
+
+ @Test
+ public void testGetUnderlyingNetworkPolicy_restrictCellSafeMode() throws Exception {
+ checkGetUnderlyingNetworkPolicy(
+ TRANSPORT_CELLULAR,
+ true /* isTransportRestricted */,
+ false /* isActive */,
+ false /* expectVcnManaged */,
+ false /* expectRestricted */);
+ }
+
+ @Test
+ public void testGetUnderlyingNetworkPolicy_unrestrictWifi() throws Exception {
+ checkGetUnderlyingNetworkPolicy(
+ TRANSPORT_WIFI,
+ false /* isTransportRestricted */,
+ true /* isActive */,
+ true /* expectVcnManaged */,
+ false /* expectRestricted */);
+ }
+
+ @Test
+ public void testGetUnderlyingNetworkPolicy_unrestrictWifiSafeMode() throws Exception {
+ checkGetUnderlyingNetworkPolicy(
+ TRANSPORT_WIFI,
+ false /* isTransportRestricted */,
+ false /* isActive */,
+ false /* expectVcnManaged */,
+ false /* expectRestricted */);
+ }
+
+ @Test
+ public void testGetUnderlyingNetworkPolicy_restrictWifi() throws Exception {
+ checkGetUnderlyingNetworkPolicy(
+ TRANSPORT_WIFI,
+ true /* isTransportRestricted */,
+ true /* isActive */,
+ true /* expectVcnManaged */,
+ true /* expectRestricted */);
+ }
+
+ @Test
+ public void testGetUnderlyingNetworkPolicy_restrictWifiSafeMode() throws Exception {
+ checkGetUnderlyingNetworkPolicy(
+ TRANSPORT_WIFI,
+ true /* isTransportRestricted */,
+ false /* isActive */,
+ false /* expectVcnManaged */,
+ true /* expectRestricted */);
+ }
+
+ @Test
+ public void testGetUnderlyingNetworkPolicyCell_restrictWifi() throws Exception {
+ doReturn(Collections.singleton(TRANSPORT_WIFI))
+ .when(mMockDeps)
+ .getRestrictedTransports(any(), any());
+
+ setupSubscriptionAndStartVcn(TEST_SUBSCRIPTION_ID, TEST_UUID_2, true /* isVcnActive */);
+
+ // Get the policy for a cellular network and expect it won't be affected by the wifi
+ // restriction policy
+ final VcnUnderlyingNetworkPolicy policy =
+ mVcnMgmtSvc.getUnderlyingNetworkPolicy(
+ getNetworkCapabilitiesBuilderForTransport(
+ TEST_SUBSCRIPTION_ID, TRANSPORT_CELLULAR)
+ .build(),
+ new LinkProperties());
assertFalse(policy.isTeardownRequested());
verifyMergedNetworkCapabilities(
policy.getMergedNetworkCapabilities(),
TRANSPORT_CELLULAR,
- true /* isVcnManaged */,
- false /* isRestricted */);
- }
-
- @Test
- public void testGetUnderlyingNetworkPolicyCellular_safeMode() throws Exception {
- final VcnUnderlyingNetworkPolicy policy =
- startVcnAndGetPolicyForTransport(
- TEST_SUBSCRIPTION_ID,
- TEST_UUID_2,
- false /* isActive */,
- TRANSPORT_CELLULAR);
-
- assertFalse(policy.isTeardownRequested());
- verifyMergedNetworkCapabilities(
- policy.getMergedNetworkCapabilities(),
- NetworkCapabilities.TRANSPORT_CELLULAR,
- false /* isVcnManaged */,
- false /* isRestricted */);
- }
-
- @Test
- public void testGetUnderlyingNetworkPolicyWifi() throws Exception {
- final VcnUnderlyingNetworkPolicy policy =
- startVcnAndGetPolicyForTransport(
- TEST_SUBSCRIPTION_ID, TEST_UUID_2, true /* isActive */, TRANSPORT_WIFI);
-
- assertFalse(policy.isTeardownRequested());
- verifyMergedNetworkCapabilities(
- policy.getMergedNetworkCapabilities(),
- NetworkCapabilities.TRANSPORT_WIFI,
- true /* isVcnManaged */,
- true /* isRestricted */);
- }
-
- @Test
- public void testGetUnderlyingNetworkPolicyVcnWifi_safeMode() throws Exception {
- final VcnUnderlyingNetworkPolicy policy =
- startVcnAndGetPolicyForTransport(
- TEST_SUBSCRIPTION_ID, TEST_UUID_2, false /* isActive */, TRANSPORT_WIFI);
-
- assertFalse(policy.isTeardownRequested());
- verifyMergedNetworkCapabilities(
- policy.getMergedNetworkCapabilities(),
- NetworkCapabilities.TRANSPORT_WIFI,
- false /* isVcnManaged */,
- true /* isRestricted */);
+ true /* expectVcnManaged */,
+ false /* expectRestricted */);
}
private void setupTrackedCarrierWifiNetwork(NetworkCapabilities caps) {
@@ -1137,6 +1269,27 @@ public class VcnManagementServiceTest {
assertTrue(policy.isTeardownRequested());
}
+ @Test
+ public void testGetUnderlyingNetworkPolicyForRestrictedImsWhenUnrestrictingCell()
+ throws Exception {
+ final NetworkCapabilities existingNetworkCaps =
+ getNetworkCapabilitiesBuilderForTransport(TEST_SUBSCRIPTION_ID, TRANSPORT_CELLULAR)
+ .addCapability(NET_CAPABILITY_NOT_RESTRICTED)
+ .removeCapability(NET_CAPABILITY_IMS)
+ .build();
+ setupTrackedCarrierWifiNetwork(existingNetworkCaps);
+
+ final VcnUnderlyingNetworkPolicy policy =
+ mVcnMgmtSvc.getUnderlyingNetworkPolicy(
+ getNetworkCapabilitiesBuilderForTransport(
+ TEST_SUBSCRIPTION_ID, TRANSPORT_CELLULAR)
+ .addCapability(NET_CAPABILITY_IMS)
+ .removeCapability(NET_CAPABILITY_NOT_RESTRICTED)
+ .build(),
+ new LinkProperties());
+ assertFalse(policy.isTeardownRequested());
+ }
+
@Test
public void testGetUnderlyingNetworkPolicyNonVcnNetwork() throws Exception {
setupSubscriptionAndStartVcn(TEST_SUBSCRIPTION_ID, TEST_UUID_1, true /* isActive */);
@@ -1217,6 +1370,30 @@ public class VcnManagementServiceTest {
verify(mMockPolicyListener).onPolicyChanged();
}
+ @Test
+ public void testVcnCarrierConfigChangeUpdatesPolicyListener() throws Exception {
+ setupActiveSubscription(TEST_UUID_2);
+
+ mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
+ mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListenerForTest(mMockPolicyListener);
+
+ final TelephonySubscriptionSnapshot snapshot =
+ buildSubscriptionSnapshot(
+ TEST_SUBSCRIPTION_ID,
+ TEST_UUID_2,
+ Collections.singleton(TEST_UUID_2),
+ Collections.emptyMap(),
+ true /* hasCarrierPrivileges */);
+
+ final PersistableBundleWrapper mockCarrierConfig = mock(PersistableBundleWrapper.class);
+ doReturn(mockCarrierConfig).when(snapshot).getCarrierConfigForSubGrp(eq(TEST_UUID_2));
+
+ final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback();
+ cb.onNewSnapshot(snapshot);
+
+ verify(mMockPolicyListener).onPolicyChanged();
+ }
+
private void triggerVcnSafeMode(
@NonNull ParcelUuid subGroup,
@NonNull TelephonySubscriptionSnapshot snapshot,
diff --git a/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java b/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java
index 09080be9ee41f..965b073ff0db4 100644
--- a/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java
+++ b/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java
@@ -16,6 +16,9 @@
package com.android.server.vcn;
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
+import static android.net.vcn.VcnManager.VCN_RESTRICTED_TRANSPORTS_INT_ARRAY_KEY;
import static android.telephony.CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED;
import static android.telephony.CarrierConfigManager.EXTRA_SLOT_INDEX;
import static android.telephony.CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX;
@@ -39,6 +42,7 @@ import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
@@ -493,6 +497,37 @@ public class TelephonySubscriptionTrackerTest {
verify(mCallback).onNewSnapshot(eq(buildExpectedSnapshot(emptyMap(), emptyMap())));
}
+ @Test
+ public void testCarrierConfigUpdatedAfterValidTriggersCallbacks() throws Exception {
+ mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(true));
+ mTestLooper.dispatchAll();
+ verify(mCallback).onNewSnapshot(eq(buildExpectedSnapshot(TEST_PRIVILEGED_PACKAGES)));
+ reset(mCallback);
+
+ final PersistableBundle updatedConfig = new PersistableBundle();
+ updatedConfig.putIntArray(
+ VCN_RESTRICTED_TRANSPORTS_INT_ARRAY_KEY,
+ new int[] {TRANSPORT_WIFI, TRANSPORT_CELLULAR});
+ doReturn(updatedConfig)
+ .when(mCarrierConfigManager)
+ .getConfigForSubId(eq(TEST_SUBSCRIPTION_ID_1));
+
+ Map subIdToCarrierConfigMap = new HashMap<>();
+ subIdToCarrierConfigMap.put(
+ TEST_SUBSCRIPTION_ID_1, new PersistableBundleWrapper(updatedConfig));
+ mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(true));
+ mTestLooper.dispatchAll();
+
+ verify(mCallback)
+ .onNewSnapshot(
+ eq(
+ buildExpectedSnapshot(
+ 0,
+ TEST_SUBID_TO_INFO_MAP,
+ subIdToCarrierConfigMap,
+ TEST_PRIVILEGED_PACKAGES)));
+ }
+
@Test
public void testSlotClearedAfterValidTriggersCallbacks() throws Exception {
mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(true));