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

Commit 1e91f8db authored by Yan Yan's avatar Yan Yan
Browse files

Support configuring the VCN restriction policy

This commit implements the logic to support configuring
VCN restriction policy on the underlying network. This commit
also adds a stub for later CLs to add the configuration interface.

Bug: 239104955
Test: atest FrameworksVcnTests(new tests)
Test: atest CtsVcnTestCases
Change-Id: I1687df029b5bbd8f20e0e4839ba8bd1717051dcf
parent b6d9367b
Loading
Loading
Loading
Loading
+58 −10
Original line number Diff line number Diff line
@@ -18,8 +18,10 @@ 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_STATUS_CODE_ACTIVE;
import static android.net.vcn.VcnManager.VCN_STATUS_CODE_INACTIVE;
import static android.net.vcn.VcnManager.VCN_STATUS_CODE_NOT_CONFIGURED;
@@ -68,6 +70,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;
@@ -361,6 +364,16 @@ 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<Integer> getRestrictedTransports(
                ParcelUuid subGrp,
                Map<ParcelUuid, VcnConfig> vcnConfigs,
                TelephonySubscriptionSnapshot lastSnapshot) {
            // TODO: b/239104955 Read restriction policy configurations

            return Collections.singleton(TRANSPORT_WIFI);
        }
    }

    /** Notifies the VcnManagementService that external dependencies can be set up. */
@@ -1000,7 +1013,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 +1021,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<Integer> restrictedTransports =
                            mDeps.getRestrictedTransports(subGrp, mConfigs, 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 +1047,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 +1321,38 @@ public class VcnManagementService extends IVcnManagementService.Stub {
            }
        }

        private boolean requiresRestartForCarrierWifi(NetworkCapabilities caps) {
            if (!caps.hasTransport(TRANSPORT_WIFI) || caps.getSubscriptionIds() == null) {
        private Set<Integer> getNonTestTransportTypes(NetworkCapabilities caps) {
            final Set<Integer> 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);
+132 −34
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
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;
@@ -252,6 +253,10 @@ public class VcnManagementServiceTest {
                .when(mMockContext)
                .enforceCallingOrSelfPermission(
                        eq(android.Manifest.permission.NETWORK_FACTORY), any());

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


@@ -1032,63 +1037,135 @@ public class VcnManagementServiceTest {
                new LinkProperties());
    }

    @Test
    public void testGetUnderlyingNetworkPolicyCellular() throws Exception {
    private void checkGetUnderlyingNetworkPolicy(
            int transportType,
            boolean isTransportRestricted,
            boolean isActive,
            boolean expectVcnManaged,
            boolean expectRestricted)
            throws Exception {

        final Set<Integer> restrictedTransports = new ArraySet();
        if (isTransportRestricted) {
            restrictedTransports.add(transportType);
        }
        doReturn(restrictedTransports).when(mMockDeps).getRestrictedTransports(any(), 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,
                true /* isVcnManaged */,
                false /* isRestricted */);
                false /* isTransportRestricted */,
                true /* isActive */,
                true /* expectVcnManaged */,
                false /* expectRestricted */);
    }

    @Test
    public void testGetUnderlyingNetworkPolicyCellular_safeMode() throws Exception {
        final VcnUnderlyingNetworkPolicy policy =
                startVcnAndGetPolicyForTransport(
                        TEST_SUBSCRIPTION_ID,
                        TEST_UUID_2,
    public void testGetUnderlyingNetworkPolicy_unrestrictCellSafeMode() throws Exception {
        checkGetUnderlyingNetworkPolicy(
                TRANSPORT_CELLULAR,
                false /* isTransportRestricted */,
                false /* isActive */,
                        TRANSPORT_CELLULAR);
                false /* expectVcnManaged */,
                false /* expectRestricted */);
    }

        assertFalse(policy.isTeardownRequested());
        verifyMergedNetworkCapabilities(
                policy.getMergedNetworkCapabilities(),
                NetworkCapabilities.TRANSPORT_CELLULAR,
                false /* isVcnManaged */,
                false /* isRestricted */);
    @Test
    public void testGetUnderlyingNetworkPolicy_restrictCell() throws Exception {
        checkGetUnderlyingNetworkPolicy(
                TRANSPORT_CELLULAR,
                true /* isTransportRestricted */,
                true /* isActive */,
                true /* expectVcnManaged */,
                true /* expectRestricted */);
    }

    @Test
    public void testGetUnderlyingNetworkPolicyWifi() throws Exception {
        final VcnUnderlyingNetworkPolicy policy =
                startVcnAndGetPolicyForTransport(
                        TEST_SUBSCRIPTION_ID, TEST_UUID_2, true /* isActive */, TRANSPORT_WIFI);
    public void testGetUnderlyingNetworkPolicy_restrictCellSafeMode() throws Exception {
        checkGetUnderlyingNetworkPolicy(
                TRANSPORT_CELLULAR,
                true /* isTransportRestricted */,
                false /* isActive */,
                false /* expectVcnManaged */,
                false /* expectRestricted */);
    }

        assertFalse(policy.isTeardownRequested());
        verifyMergedNetworkCapabilities(
                policy.getMergedNetworkCapabilities(),
                NetworkCapabilities.TRANSPORT_WIFI,
                true /* isVcnManaged */,
                true /* isRestricted */);
    @Test
    public void testGetUnderlyingNetworkPolicy_unrestrictWifi() throws Exception {
        checkGetUnderlyingNetworkPolicy(
                TRANSPORT_WIFI,
                false /* isTransportRestricted */,
                true /* isActive */,
                true /* expectVcnManaged */,
                false /* expectRestricted */);
    }

    @Test
    public void testGetUnderlyingNetworkPolicyVcnWifi_safeMode() throws Exception {
    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(), 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 =
                startVcnAndGetPolicyForTransport(
                        TEST_SUBSCRIPTION_ID, TEST_UUID_2, false /* isActive */, TRANSPORT_WIFI);
                mVcnMgmtSvc.getUnderlyingNetworkPolicy(
                        getNetworkCapabilitiesBuilderForTransport(
                                        TEST_SUBSCRIPTION_ID, TRANSPORT_CELLULAR)
                                .build(),
                        new LinkProperties());

        assertFalse(policy.isTeardownRequested());
        verifyMergedNetworkCapabilities(
                policy.getMergedNetworkCapabilities(),
                NetworkCapabilities.TRANSPORT_WIFI,
                false /* isVcnManaged */,
                true /* isRestricted */);
                TRANSPORT_CELLULAR,
                true /* expectVcnManaged */,
                false /* expectRestricted */);
    }

    private void setupTrackedCarrierWifiNetwork(NetworkCapabilities caps) {
@@ -1138,6 +1215,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 */);