Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d5441ca5 authored by Yan Yan's avatar Yan Yan Committed by Gerrit Code Review
Browse files

Merge changes I21aaab57,Ie174f7ec

* changes:
  Expose APIs to configure transports to be restricted by VCN
  Add restrictions on underlying networks with VcnConfig
parents b8549639 0838c8fb
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -27285,6 +27285,7 @@ package android.net.vcn {
  public final class VcnConfig implements android.os.Parcelable {
    method public int describeContents();
    method @NonNull public java.util.Set<android.net.vcn.VcnGatewayConnectionConfig> getGatewayConnectionConfigs();
    method @NonNull public java.util.Set<java.lang.Integer> getRestrictedUnderlyingNetworkTransports();
    method public void writeToParcel(@NonNull android.os.Parcel, int);
    field @NonNull public static final android.os.Parcelable.Creator<android.net.vcn.VcnConfig> CREATOR;
  }
@@ -27293,6 +27294,7 @@ package android.net.vcn {
    ctor public VcnConfig.Builder(@NonNull android.content.Context);
    method @NonNull public android.net.vcn.VcnConfig.Builder addGatewayConnectionConfig(@NonNull android.net.vcn.VcnGatewayConnectionConfig);
    method @NonNull public android.net.vcn.VcnConfig build();
    method @NonNull public android.net.vcn.VcnConfig.Builder setRestrictedUnderlyingNetworkTransports(@NonNull java.util.Set<java.lang.Integer>);
  }
  public final class VcnGatewayConnectionConfig {
+106 −2
Original line number Diff line number Diff line
@@ -15,16 +15,23 @@
 */
package android.net.vcn;

import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;

import static com.android.internal.annotations.VisibleForTesting.Visibility;
import static com.android.server.vcn.util.PersistableBundleUtils.INTEGER_DESERIALIZER;
import static com.android.server.vcn.util.PersistableBundleUtils.INTEGER_SERIALIZER;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.PersistableBundle;
import android.util.ArraySet;
import android.util.Log;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.Preconditions;
@@ -32,6 +39,7 @@ import com.android.server.vcn.util.PersistableBundleUtils;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.Objects;
import java.util.Set;

@@ -46,22 +54,36 @@ import java.util.Set;
public final class VcnConfig implements Parcelable {
    @NonNull private static final String TAG = VcnConfig.class.getSimpleName();

    private static final Set<Integer> ALLOWED_TRANSPORTS = new ArraySet<>();

    static {
        ALLOWED_TRANSPORTS.add(TRANSPORT_WIFI);
        ALLOWED_TRANSPORTS.add(TRANSPORT_CELLULAR);
    }

    private static final String PACKAGE_NAME_KEY = "mPackageName";
    @NonNull private final String mPackageName;

    private static final String GATEWAY_CONNECTION_CONFIGS_KEY = "mGatewayConnectionConfigs";
    @NonNull private final Set<VcnGatewayConnectionConfig> mGatewayConnectionConfigs;

    private static final Set<Integer> RESTRICTED_TRANSPORTS_DEFAULT =
            Collections.singleton(TRANSPORT_WIFI);
    private static final String RESTRICTED_TRANSPORTS_KEY = "mRestrictedTransports";
    @NonNull private final Set<Integer> mRestrictedTransports;

    private static final String IS_TEST_MODE_PROFILE_KEY = "mIsTestModeProfile";
    private final boolean mIsTestModeProfile;

    private VcnConfig(
            @NonNull String packageName,
            @NonNull Set<VcnGatewayConnectionConfig> gatewayConnectionConfigs,
            @NonNull Set<Integer> restrictedTransports,
            boolean isTestModeProfile) {
        mPackageName = packageName;
        mGatewayConnectionConfigs =
                Collections.unmodifiableSet(new ArraySet<>(gatewayConnectionConfigs));
        mRestrictedTransports = Collections.unmodifiableSet(new ArraySet<>(restrictedTransports));
        mIsTestModeProfile = isTestModeProfile;

        validate();
@@ -82,6 +104,20 @@ public final class VcnConfig implements Parcelable {
                new ArraySet<>(
                        PersistableBundleUtils.toList(
                                gatewayConnectionConfigsBundle, VcnGatewayConnectionConfig::new));

        final PersistableBundle restrictedTransportsBundle =
                in.getPersistableBundle(RESTRICTED_TRANSPORTS_KEY);
        if (restrictedTransportsBundle == null) {
            // RESTRICTED_TRANSPORTS_KEY was added in U and does not exist in VcnConfigs created in
            // older platforms
            mRestrictedTransports = RESTRICTED_TRANSPORTS_DEFAULT;
        } else {
            mRestrictedTransports =
                    new ArraySet<Integer>(
                            PersistableBundleUtils.toList(
                                    restrictedTransportsBundle, INTEGER_DESERIALIZER));
        }

        mIsTestModeProfile = in.getBoolean(IS_TEST_MODE_PROFILE_KEY);

        validate();
@@ -91,6 +127,19 @@ public final class VcnConfig implements Parcelable {
        Objects.requireNonNull(mPackageName, "packageName was null");
        Preconditions.checkCollectionNotEmpty(
                mGatewayConnectionConfigs, "gatewayConnectionConfigs was empty");

        final Iterator<Integer> iterator = mRestrictedTransports.iterator();
        while (iterator.hasNext()) {
            final int transport = iterator.next();
            if (!ALLOWED_TRANSPORTS.contains(transport)) {
                iterator.remove();
                Log.w(
                        TAG,
                        "Found invalid transport "
                                + transport
                                + " which might be from a new version of VcnConfig");
            }
        }
    }

    /**
@@ -109,6 +158,16 @@ public final class VcnConfig implements Parcelable {
        return Collections.unmodifiableSet(mGatewayConnectionConfigs);
    }

    /**
     * Retrieve the transports that will be restricted by the VCN.
     *
     * @see Builder#setRestrictedUnderlyingNetworkTransports(Set)
     */
    @NonNull
    public Set<Integer> getRestrictedUnderlyingNetworkTransports() {
        return Collections.unmodifiableSet(mRestrictedTransports);
    }

    /**
     * Returns whether or not this VcnConfig is restricted to test networks.
     *
@@ -134,6 +193,12 @@ public final class VcnConfig implements Parcelable {
                        new ArrayList<>(mGatewayConnectionConfigs),
                        VcnGatewayConnectionConfig::toPersistableBundle);
        result.putPersistableBundle(GATEWAY_CONNECTION_CONFIGS_KEY, gatewayConnectionConfigsBundle);

        final PersistableBundle restrictedTransportsBundle =
                PersistableBundleUtils.fromList(
                        new ArrayList<>(mRestrictedTransports), INTEGER_SERIALIZER);
        result.putPersistableBundle(RESTRICTED_TRANSPORTS_KEY, restrictedTransportsBundle);

        result.putBoolean(IS_TEST_MODE_PROFILE_KEY, mIsTestModeProfile);

        return result;
@@ -141,7 +206,8 @@ public final class VcnConfig implements Parcelable {

    @Override
    public int hashCode() {
        return Objects.hash(mPackageName, mGatewayConnectionConfigs, mIsTestModeProfile);
        return Objects.hash(
                mPackageName, mGatewayConnectionConfigs, mRestrictedTransports, mIsTestModeProfile);
    }

    @Override
@@ -153,6 +219,7 @@ public final class VcnConfig implements Parcelable {
        final VcnConfig rhs = (VcnConfig) other;
        return mPackageName.equals(rhs.mPackageName)
                && mGatewayConnectionConfigs.equals(rhs.mGatewayConnectionConfigs)
                && mRestrictedTransports.equals(rhs.mRestrictedTransports)
                && mIsTestModeProfile == rhs.mIsTestModeProfile;
    }

@@ -189,12 +256,15 @@ public final class VcnConfig implements Parcelable {
        @NonNull
        private final Set<VcnGatewayConnectionConfig> mGatewayConnectionConfigs = new ArraySet<>();

        @NonNull private final Set<Integer> mRestrictedTransports = new ArraySet<>();

        private boolean mIsTestModeProfile = false;

        public Builder(@NonNull Context context) {
            Objects.requireNonNull(context, "context was null");

            mPackageName = context.getOpPackageName();
            mRestrictedTransports.addAll(RESTRICTED_TRANSPORTS_DEFAULT);
        }

        /**
@@ -225,6 +295,36 @@ public final class VcnConfig implements Parcelable {
            return this;
        }

        private void validateRestrictedTransportsOrThrow(Set<Integer> restrictedTransports) {
            Objects.requireNonNull(restrictedTransports, "transports was null");

            for (int transport : restrictedTransports) {
                if (!ALLOWED_TRANSPORTS.contains(transport)) {
                    throw new IllegalArgumentException("Invalid transport " + transport);
                }
            }
        }

        /**
         * Sets transports that will be restricted by the VCN.
         *
         * @param transports transports that will be restricted by VCN. Networks that include any
         *     of the transports will be marked as restricted. Only {@link
         *     NetworkCapabilities#TRANSPORT_WIFI} and {@link
         *     NetworkCapabilities#TRANSPORT_CELLULAR} are allowed. {@link
         *     NetworkCapabilities#TRANSPORT_WIFI} is marked restricted by default.
         * @return this {@link Builder} instance, for chaining
         * @throws IllegalArgumentException if the input contains unsupported transport types.
         */
        @NonNull
        public Builder setRestrictedUnderlyingNetworkTransports(@NonNull Set<Integer> transports) {
            validateRestrictedTransportsOrThrow(transports);

            mRestrictedTransports.clear();
            mRestrictedTransports.addAll(transports);
            return this;
        }

        /**
         * Restricts this VcnConfig to matching with test networks (only).
         *
@@ -248,7 +348,11 @@ public final class VcnConfig implements Parcelable {
         */
        @NonNull
        public VcnConfig build() {
            return new VcnConfig(mPackageName, mGatewayConnectionConfigs, mIsTestModeProfile);
            return new VcnConfig(
                    mPackageName,
                    mGatewayConnectionConfigs,
                    mRestrictedTransports,
                    mIsTestModeProfile);
        }
    }
}
+22 −14
Original line number Diff line number Diff line
@@ -371,8 +371,9 @@ public class VcnManagementService extends IVcnManagementService.Stub {
            return new LocationPermissionChecker(context);
        }

        /** Gets the transports that need to be marked as restricted by the VCN */
        public Set<Integer> getRestrictedTransports(
        /** Gets transports that need to be marked as restricted by the VCN from CarrierConfig */
        @VisibleForTesting(visibility = Visibility.PRIVATE)
        public Set<Integer> getRestrictedTransportsFromCarrierConfig(
                ParcelUuid subGrp, TelephonySubscriptionSnapshot lastSnapshot) {
            if (!Build.IS_ENG && !Build.IS_USERDEBUG) {
                return RESTRICTED_TRANSPORTS_DEFAULT;
@@ -398,6 +399,22 @@ public class VcnManagementService extends IVcnManagementService.Stub {
            }
            return restrictedTransports;
        }

        /** Gets the transports that need to be marked as restricted by the VCN */
        public Set<Integer> getRestrictedTransports(
                ParcelUuid subGrp,
                TelephonySubscriptionSnapshot lastSnapshot,
                VcnConfig vcnConfig) {
            final Set<Integer> restrictedTransports = new ArraySet<>();
            restrictedTransports.addAll(vcnConfig.getRestrictedUnderlyingNetworkTransports());

            // TODO: b/262269892 Remove the ability to configure restricted transports
            // via CarrierConfig
            restrictedTransports.addAll(
                    getRestrictedTransportsFromCarrierConfig(subGrp, lastSnapshot));

            return restrictedTransports;
        }
    }

    /** Notifies the VcnManagementService that external dependencies can be set up. */
@@ -719,6 +736,7 @@ public class VcnManagementService extends IVcnManagementService.Stub {
        if (mVcns.containsKey(subscriptionGroup)) {
            final Vcn vcn = mVcns.get(subscriptionGroup);
            vcn.updateConfig(config);
            notifyAllPolicyListenersLocked();
        } else {
            // TODO(b/193687515): Support multiple VCNs active at the same time
            if (isActiveSubGroup(subscriptionGroup, mLastSnapshot)) {
@@ -936,7 +954,6 @@ public class VcnManagementService extends IVcnManagementService.Stub {
    }

    /** Adds the provided listener for receiving VcnUnderlyingNetworkPolicy updates. */
    @GuardedBy("mLock")
    @Override
    public void addVcnUnderlyingNetworkPolicyListener(
            @NonNull IVcnUnderlyingNetworkPolicyListener listener) {
@@ -963,16 +980,7 @@ 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
    public void removeVcnUnderlyingNetworkPolicyListener(
            @NonNull IVcnUnderlyingNetworkPolicyListener listener) {
@@ -1062,8 +1070,8 @@ public class VcnManagementService extends IVcnManagementService.Stub {
                        isVcnManagedNetwork = true;
                    }

                    final Set<Integer> restrictedTransports =
                            mDeps.getRestrictedTransports(subGrp, mLastSnapshot);
                    final Set<Integer> restrictedTransports = mDeps.getRestrictedTransports(
                            subGrp, mLastSnapshot, mConfigs.get(subGrp));
                    for (int restrictedTransport : restrictedTransports) {
                        if (ncCopy.hasTransport(restrictedTransport)) {
                            if (restrictedTransport == TRANSPORT_CELLULAR) {
+57 −2
Original line number Diff line number Diff line
@@ -16,7 +16,12 @@

package android.net.vcn;

import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
@@ -24,6 +29,7 @@ import static org.mockito.Mockito.mock;
import android.annotation.NonNull;
import android.content.Context;
import android.os.Parcel;
import android.util.ArraySet;

import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -42,19 +48,36 @@ public class VcnConfigTest {
    private static final Set<VcnGatewayConnectionConfig> GATEWAY_CONNECTION_CONFIGS =
            Collections.singleton(VcnGatewayConnectionConfigTest.buildTestConfig());

    private static final Set<Integer> RESTRICTED_TRANSPORTS = new ArraySet<>();

    static {
        RESTRICTED_TRANSPORTS.add(TRANSPORT_WIFI);
        RESTRICTED_TRANSPORTS.add(TRANSPORT_CELLULAR);
    }

    private final Context mContext = mock(Context.class);

    // Public visibility for VcnManagementServiceTest
    public static VcnConfig buildTestConfig(@NonNull Context context) {
    public static VcnConfig buildTestConfig(
            @NonNull Context context, Set<Integer> restrictedTransports) {
        VcnConfig.Builder builder = new VcnConfig.Builder(context);

        for (VcnGatewayConnectionConfig gatewayConnectionConfig : GATEWAY_CONNECTION_CONFIGS) {
            builder.addGatewayConnectionConfig(gatewayConnectionConfig);
        }

        if (restrictedTransports != null) {
            builder.setRestrictedUnderlyingNetworkTransports(restrictedTransports);
        }

        return builder.build();
    }

    // Public visibility for VcnManagementServiceTest
    public static VcnConfig buildTestConfig(@NonNull Context context) {
        return buildTestConfig(context, null);
    }

    @Before
    public void setUp() throws Exception {
        doReturn(TEST_PACKAGE_NAME).when(mContext).getOpPackageName();
@@ -91,11 +114,25 @@ public class VcnConfigTest {
    }

    @Test
    public void testBuilderAndGetters() {
    public void testBuilderAndGettersDefaultValues() {
        final VcnConfig config = buildTestConfig(mContext);

        assertEquals(TEST_PACKAGE_NAME, config.getProvisioningPackageName());
        assertEquals(GATEWAY_CONNECTION_CONFIGS, config.getGatewayConnectionConfigs());
        assertFalse(config.isTestModeProfile());
        assertEquals(
                Collections.singleton(TRANSPORT_WIFI),
                config.getRestrictedUnderlyingNetworkTransports());
    }

    @Test
    public void testBuilderAndGettersConfigRestrictedTransports() {
        final VcnConfig config = buildTestConfig(mContext, RESTRICTED_TRANSPORTS);

        assertEquals(TEST_PACKAGE_NAME, config.getProvisioningPackageName());
        assertEquals(GATEWAY_CONNECTION_CONFIGS, config.getGatewayConnectionConfigs());
        assertFalse(config.isTestModeProfile());
        assertEquals(RESTRICTED_TRANSPORTS, config.getRestrictedUnderlyingNetworkTransports());
    }

    @Test
@@ -105,6 +142,24 @@ public class VcnConfigTest {
        assertEquals(config, new VcnConfig(config.toPersistableBundle()));
    }

    @Test
    public void testPersistableBundleWithRestrictedTransports() {
        final VcnConfig config = buildTestConfig(mContext, RESTRICTED_TRANSPORTS);

        assertEquals(config, new VcnConfig(config.toPersistableBundle()));
    }

    @Test
    public void testEqualityWithRestrictedTransports() {
        final VcnConfig config = buildTestConfig(mContext, RESTRICTED_TRANSPORTS);
        final VcnConfig configEqual = buildTestConfig(mContext, RESTRICTED_TRANSPORTS);
        final VcnConfig configNotEqual =
                buildTestConfig(mContext, Collections.singleton(TRANSPORT_WIFI));

        assertEquals(config, configEqual);
        assertNotEquals(config, configNotEqual);
    }

    @Test
    public void testParceling() {
        final VcnConfig config = buildTestConfig(mContext);
+67 −12
Original line number Diff line number Diff line
@@ -258,7 +258,7 @@ public class VcnManagementServiceTest {

        doReturn(Collections.singleton(TRANSPORT_WIFI))
                .when(mMockDeps)
                .getRestrictedTransports(any(), any());
                .getRestrictedTransports(any(), any(), any());
    }


@@ -1038,18 +1038,18 @@ public class VcnManagementServiceTest {
                new LinkProperties());
    }

    private void checkGetRestrictedTransports(
    private void checkGetRestrictedTransportsFromCarrierConfig(
            ParcelUuid subGrp,
            TelephonySubscriptionSnapshot lastSnapshot,
            Set<Integer> expectedTransports) {
        Set<Integer> result =
                new VcnManagementService.Dependencies()
                        .getRestrictedTransports(subGrp, lastSnapshot);
                        .getRestrictedTransportsFromCarrierConfig(subGrp, lastSnapshot);
        assertEquals(expectedTransports, result);
    }

    @Test
    public void testGetRestrictedTransports() {
    public void testGetRestrictedTransportsFromCarrierConfig() {
        final Set<Integer> restrictedTransports = new ArraySet<>();
        restrictedTransports.add(TRANSPORT_CELLULAR);
        restrictedTransports.add(TRANSPORT_WIFI);
@@ -1065,11 +1065,12 @@ public class VcnManagementServiceTest {
                mock(TelephonySubscriptionSnapshot.class);
        doReturn(carrierConfig).when(lastSnapshot).getCarrierConfigForSubGrp(eq(TEST_UUID_2));

        checkGetRestrictedTransports(TEST_UUID_2, lastSnapshot, restrictedTransports);
        checkGetRestrictedTransportsFromCarrierConfig(
                TEST_UUID_2, lastSnapshot, restrictedTransports);
    }

    @Test
    public void testGetRestrictedTransports_noRestrictPolicyConfigured() {
    public void testGetRestrictedTransportsFromCarrierConfig_noRestrictPolicyConfigured() {
        final Set<Integer> restrictedTransports = Collections.singleton(TRANSPORT_WIFI);

        final PersistableBundleWrapper carrierConfig =
@@ -1078,17 +1079,54 @@ public class VcnManagementServiceTest {
                mock(TelephonySubscriptionSnapshot.class);
        doReturn(carrierConfig).when(lastSnapshot).getCarrierConfigForSubGrp(eq(TEST_UUID_2));

        checkGetRestrictedTransports(TEST_UUID_2, lastSnapshot, restrictedTransports);
        checkGetRestrictedTransportsFromCarrierConfig(
                TEST_UUID_2, lastSnapshot, restrictedTransports);
    }

    @Test
    public void testGetRestrictedTransports_noCarrierConfig() {
    public void testGetRestrictedTransportsFromCarrierConfig_noCarrierConfig() {
        final Set<Integer> restrictedTransports = Collections.singleton(TRANSPORT_WIFI);

        final TelephonySubscriptionSnapshot lastSnapshot =
                mock(TelephonySubscriptionSnapshot.class);

        checkGetRestrictedTransports(TEST_UUID_2, lastSnapshot, restrictedTransports);
        checkGetRestrictedTransportsFromCarrierConfig(
                TEST_UUID_2, lastSnapshot, restrictedTransports);
    }

    @Test
    public void testGetRestrictedTransportsFromCarrierConfigAndVcnConfig() {
        // Configure restricted transport in CarrierConfig
        final Set<Integer> restrictedTransportInCarrierConfig =
                Collections.singleton(TRANSPORT_WIFI);

        PersistableBundle carrierConfigBundle = new PersistableBundle();
        carrierConfigBundle.putIntArray(
                VCN_RESTRICTED_TRANSPORTS_INT_ARRAY_KEY,
                restrictedTransportInCarrierConfig.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));

        // Configure restricted transport in VcnConfig
        final Context mockContext = mock(Context.class);
        doReturn(TEST_PACKAGE_NAME).when(mockContext).getOpPackageName();
        final VcnConfig vcnConfig =
                VcnConfigTest.buildTestConfig(
                        mockContext, Collections.singleton(TRANSPORT_CELLULAR));

        // Verifications
        final Set<Integer> expectedTransports = new ArraySet<>();
        expectedTransports.add(TRANSPORT_CELLULAR);
        expectedTransports.add(TRANSPORT_WIFI);

        Set<Integer> result =
                new VcnManagementService.Dependencies()
                        .getRestrictedTransports(TEST_UUID_2, lastSnapshot, vcnConfig);
        assertEquals(expectedTransports, result);
    }

    private void checkGetUnderlyingNetworkPolicy(
@@ -1103,7 +1141,7 @@ public class VcnManagementServiceTest {
        if (isTransportRestricted) {
            restrictedTransports.add(transportType);
        }
        doReturn(restrictedTransports).when(mMockDeps).getRestrictedTransports(any(), any());
        doReturn(restrictedTransports).when(mMockDeps).getRestrictedTransports(any(), any(), any());

        final VcnUnderlyingNetworkPolicy policy =
                startVcnAndGetPolicyForTransport(
@@ -1201,7 +1239,7 @@ public class VcnManagementServiceTest {
    public void testGetUnderlyingNetworkPolicyCell_restrictWifi() throws Exception {
        doReturn(Collections.singleton(TRANSPORT_WIFI))
                .when(mMockDeps)
                .getRestrictedTransports(any(), any());
                .getRestrictedTransports(any(), any(), any());

        setupSubscriptionAndStartVcn(TEST_SUBSCRIPTION_ID, TEST_UUID_2, true /* isVcnActive */);

@@ -1343,6 +1381,23 @@ public class VcnManagementServiceTest {
        verify(mMockPolicyListener).onPolicyChanged();
    }

    @Test
    public void testVcnConfigChangeUpdatesPolicyListener() throws Exception {
        setupActiveSubscription(TEST_UUID_2);

        mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
        mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);

        final Context mockContext = mock(Context.class);
        doReturn(TEST_PACKAGE_NAME).when(mockContext).getOpPackageName();
        final VcnConfig vcnConfig =
                VcnConfigTest.buildTestConfig(
                        mockContext, Collections.singleton(TRANSPORT_CELLULAR));
        mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, vcnConfig, TEST_PACKAGE_NAME);

        verify(mMockPolicyListener).onPolicyChanged();
    }

    @Test
    public void testRemoveVcnUpdatesPolicyListener() throws Exception {
        setupActiveSubscription(TEST_UUID_2);
@@ -1375,7 +1430,7 @@ public class VcnManagementServiceTest {
        setupActiveSubscription(TEST_UUID_2);

        mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
        mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListenerForTest(mMockPolicyListener);
        mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);

        final TelephonySubscriptionSnapshot snapshot =
                buildSubscriptionSnapshot(