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

Commit 9164fbec authored by Varun Anand's avatar Varun Anand Committed by android-build-merger
Browse files

Merge "Update VPN capabilities when its underlying network set is null." am:...

Merge "Update VPN capabilities when its underlying network set is null." am: e3ae238f am: d6d59357
am: d5444c9e

Change-Id: I6dd5a369f1a3b74bbf498051ef1e4d1b31bd8e5e
parents 2f040bef d5444c9e
Loading
Loading
Loading
Loading
+55 −6
Original line number Diff line number Diff line
@@ -920,7 +920,8 @@ public class ConnectivityService extends IConnectivityManager.Stub

        mPermissionMonitor = new PermissionMonitor(mContext, mNMS);

        //set up the listener for user state for creating user VPNs
        // Set up the listener for user state for creating user VPNs.
        // Should run on mHandler to avoid any races.
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(Intent.ACTION_USER_STARTED);
        intentFilter.addAction(Intent.ACTION_USER_STOPPED);
@@ -928,7 +929,11 @@ public class ConnectivityService extends IConnectivityManager.Stub
        intentFilter.addAction(Intent.ACTION_USER_REMOVED);
        intentFilter.addAction(Intent.ACTION_USER_UNLOCKED);
        mContext.registerReceiverAsUser(
                mIntentReceiver, UserHandle.ALL, intentFilter, null, null);
                mIntentReceiver,
                UserHandle.ALL,
                intentFilter,
                null /* broadcastPermission */,
                mHandler);
        mContext.registerReceiverAsUser(mUserPresentReceiver, UserHandle.SYSTEM,
                new IntentFilter(Intent.ACTION_USER_PRESENT), null, null);

@@ -939,7 +944,11 @@ public class ConnectivityService extends IConnectivityManager.Stub
        intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
        intentFilter.addDataScheme("package");
        mContext.registerReceiverAsUser(
                mIntentReceiver, UserHandle.ALL, intentFilter, null, null);
                mIntentReceiver,
                UserHandle.ALL,
                intentFilter,
                null /* broadcastPermission */,
                mHandler);

        try {
            mNMS.registerObserver(mTethering);
@@ -4138,17 +4147,27 @@ public class ConnectivityService extends IConnectivityManager.Stub
     * handler thread through their agent, this is asynchronous. When the capabilities objects
     * are computed they will be up-to-date as they are computed synchronously from here and
     * this is running on the ConnectivityService thread.
     * TODO : Fix this and call updateCapabilities inline to remove out-of-order events.
     */
    private void updateAllVpnsCapabilities() {
        Network defaultNetwork = getNetwork(getDefaultNetwork());
        synchronized (mVpns) {
            for (int i = 0; i < mVpns.size(); i++) {
                final Vpn vpn = mVpns.valueAt(i);
                vpn.updateCapabilities();
                NetworkCapabilities nc = vpn.updateCapabilities(defaultNetwork);
                updateVpnCapabilities(vpn, nc);
            }
        }
    }

    private void updateVpnCapabilities(Vpn vpn, @Nullable NetworkCapabilities nc) {
        ensureRunningOnConnectivityServiceThread();
        NetworkAgentInfo vpnNai = getNetworkAgentInfoForNetId(vpn.getNetId());
        if (vpnNai == null || nc == null) {
            return;
        }
        updateCapabilities(vpnNai.getCurrentScore(), vpnNai, nc);
    }

    @Override
    public boolean updateLockdownVpn() {
        if (Binder.getCallingUid() != Process.SYSTEM_UID) {
@@ -4489,22 +4508,28 @@ public class ConnectivityService extends IConnectivityManager.Stub

    private void onUserAdded(int userId) {
        mPermissionMonitor.onUserAdded(userId);
        Network defaultNetwork = getNetwork(getDefaultNetwork());
        synchronized (mVpns) {
            final int vpnsSize = mVpns.size();
            for (int i = 0; i < vpnsSize; i++) {
                Vpn vpn = mVpns.valueAt(i);
                vpn.onUserAdded(userId);
                NetworkCapabilities nc = vpn.updateCapabilities(defaultNetwork);
                updateVpnCapabilities(vpn, nc);
            }
        }
    }

    private void onUserRemoved(int userId) {
        mPermissionMonitor.onUserRemoved(userId);
        Network defaultNetwork = getNetwork(getDefaultNetwork());
        synchronized (mVpns) {
            final int vpnsSize = mVpns.size();
            for (int i = 0; i < vpnsSize; i++) {
                Vpn vpn = mVpns.valueAt(i);
                vpn.onUserRemoved(userId);
                NetworkCapabilities nc = vpn.updateCapabilities(defaultNetwork);
                updateVpnCapabilities(vpn, nc);
            }
        }
    }
@@ -4573,6 +4598,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
    private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            ensureRunningOnConnectivityServiceThread();
            final String action = intent.getAction();
            final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
            final int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
@@ -5082,6 +5108,19 @@ public class ConnectivityService extends IConnectivityManager.Stub
        return getNetworkForRequest(mDefaultRequest.requestId);
    }

    @Nullable
    private Network getNetwork(@Nullable NetworkAgentInfo nai) {
        return nai != null ? nai.network : null;
    }

    private void ensureRunningOnConnectivityServiceThread() {
        if (mHandler.getLooper().getThread() != Thread.currentThread()) {
            throw new IllegalStateException(
                    "Not running on ConnectivityService thread: "
                            + Thread.currentThread().getName());
        }
    }

    private boolean isDefaultNetwork(NetworkAgentInfo nai) {
        return nai == getDefaultNetwork();
    }
@@ -5713,6 +5752,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
        updateTcpBufferSizes(newNetwork.linkProperties.getTcpBufferSizes());
        mDnsManager.setDefaultDnsSystemProperties(newNetwork.linkProperties.getDnsServers());
        notifyIfacesChangedForNetworkStats();
        // Fix up the NetworkCapabilities of any VPNs that don't specify underlying networks.
        updateAllVpnsCapabilities();
    }

    private void processListenRequests(NetworkAgentInfo nai, boolean capabilitiesChanged) {
@@ -6152,6 +6193,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
            // doing.
            updateSignalStrengthThresholds(networkAgent, "CONNECT", null);

            if (networkAgent.isVPN()) {
                updateAllVpnsCapabilities();
            }

            // Consider network even though it is not yet validated.
            final long now = SystemClock.elapsedRealtime();
            rematchNetworkAndRequests(networkAgent, ReapUnvalidatedNetworks.REAP, now);
@@ -6413,7 +6458,11 @@ public class ConnectivityService extends IConnectivityManager.Stub
            success = mVpns.get(user).setUnderlyingNetworks(networks);
        }
        if (success) {
            mHandler.post(() -> notifyIfacesChangedForNetworkStats());
            mHandler.post(() -> {
                // Update VPN's capabilities based on updated underlying network set.
                updateAllVpnsCapabilities();
                notifyIfacesChangedForNetworkStats();
            });
        }
        return success;
    }
+57 −20
Original line number Diff line number Diff line
@@ -241,7 +241,7 @@ public class Vpn {
        mNetworkCapabilities = new NetworkCapabilities();
        mNetworkCapabilities.addTransportType(NetworkCapabilities.TRANSPORT_VPN);
        mNetworkCapabilities.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN);
        updateCapabilities();
        updateCapabilities(null /* defaultNetwork */);

        loadAlwaysOnPackage();
    }
@@ -268,22 +268,44 @@ public class Vpn {
        updateAlwaysOnNotification(detailedState);
    }

    public void updateCapabilities() {
        final Network[] underlyingNetworks = (mConfig != null) ? mConfig.underlyingNetworks : null;
        // Only apps targeting Q and above can explicitly declare themselves as metered.
        final boolean isAlwaysMetered =
                mIsPackageTargetingAtLeastQ && (mConfig == null || mConfig.isMetered);
        updateCapabilities(mContext.getSystemService(ConnectivityManager.class), underlyingNetworks,
                mNetworkCapabilities, isAlwaysMetered);
    /**
     * Updates {@link #mNetworkCapabilities} based on current underlying networks and returns a
     * defensive copy.
     *
     * <p>Does not propagate updated capabilities to apps.
     *
     * @param defaultNetwork underlying network for VPNs following platform's default
     */
    public synchronized NetworkCapabilities updateCapabilities(
            @Nullable Network defaultNetwork) {
        if (mConfig == null) {
            // VPN is not running.
            return null;
        }

        if (mNetworkAgent != null) {
            mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
        Network[] underlyingNetworks = mConfig.underlyingNetworks;
        if (underlyingNetworks == null && defaultNetwork != null) {
            // null underlying networks means to track the default.
            underlyingNetworks = new Network[] { defaultNetwork };
        }
        // Only apps targeting Q and above can explicitly declare themselves as metered.
        final boolean isAlwaysMetered = mIsPackageTargetingAtLeastQ && mConfig.isMetered;

        applyUnderlyingCapabilities(
                mContext.getSystemService(ConnectivityManager.class),
                underlyingNetworks,
                mNetworkCapabilities,
                isAlwaysMetered);

        return new NetworkCapabilities(mNetworkCapabilities);
    }

    @VisibleForTesting
    public static void updateCapabilities(ConnectivityManager cm, Network[] underlyingNetworks,
            NetworkCapabilities caps, boolean isAlwaysMetered) {
    public static void applyUnderlyingCapabilities(
            ConnectivityManager cm,
            Network[] underlyingNetworks,
            NetworkCapabilities caps,
            boolean isAlwaysMetered) {
        int[] transportTypes = new int[] { NetworkCapabilities.TRANSPORT_VPN };
        int downKbps = NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED;
        int upKbps = NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED;
@@ -296,6 +318,7 @@ public class Vpn {
        boolean hadUnderlyingNetworks = false;
        if (null != underlyingNetworks) {
            for (Network underlying : underlyingNetworks) {
                // TODO(b/124469351): Get capabilities directly from ConnectivityService instead.
                final NetworkCapabilities underlyingCaps = cm.getNetworkCapabilities(underlying);
                if (underlyingCaps == null) continue;
                hadUnderlyingNetworks = true;
@@ -1007,9 +1030,8 @@ public class Vpn {
    }

    /**
     * Establish a VPN network and return the file descriptor of the VPN
     * interface. This methods returns {@code null} if the application is
     * revoked or not prepared.
     * Establish a VPN network and return the file descriptor of the VPN interface. This methods
     * returns {@code null} if the application is revoked or not prepared.
     *
     * @param config The parameters to configure the network.
     * @return The file descriptor of the VPN interface.
@@ -1101,8 +1123,6 @@ public class Vpn {
                // as rules are deleted. This prevents data leakage as the rules are moved over.
                agentDisconnect(oldNetworkAgent);
            }
            // Set up VPN's capabilities such as meteredness.
            updateCapabilities();

            if (oldConnection != null) {
                mContext.unbindService(oldConnection);
@@ -1258,6 +1278,11 @@ public class Vpn {
        return ranges;
    }

    /**
     * Updates UID ranges for this VPN and also updates its internal capabilities.
     *
     * <p>Should be called on primary ConnectivityService thread.
     */
    public void onUserAdded(int userHandle) {
        // If the user is restricted tie them to the parent user's VPN
        UserInfo user = UserManager.get(mContext).getUserInfo(userHandle);
@@ -1268,8 +1293,9 @@ public class Vpn {
                    try {
                        addUserToRanges(existingRanges, userHandle, mConfig.allowedApplications,
                                mConfig.disallowedApplications);
                        // ConnectivityService will call {@link #updateCapabilities} and apply
                        // those for VPN network.
                        mNetworkCapabilities.setUids(existingRanges);
                        updateCapabilities();
                    } catch (Exception e) {
                        Log.wtf(TAG, "Failed to add restricted user to owner", e);
                    }
@@ -1279,6 +1305,11 @@ public class Vpn {
        }
    }

    /**
     * Updates UID ranges for this VPN and also updates its capabilities.
     *
     * <p>Should be called on primary ConnectivityService thread.
     */
    public void onUserRemoved(int userHandle) {
        // clean up if restricted
        UserInfo user = UserManager.get(mContext).getUserInfo(userHandle);
@@ -1290,8 +1321,9 @@ public class Vpn {
                        final List<UidRange> removedRanges =
                            uidRangesForUser(userHandle, existingRanges);
                        existingRanges.removeAll(removedRanges);
                        // ConnectivityService will call {@link #updateCapabilities} and
                        // apply those for VPN network.
                        mNetworkCapabilities.setUids(existingRanges);
                        updateCapabilities();
                    } catch (Exception e) {
                        Log.wtf(TAG, "Failed to remove restricted user to owner", e);
                    }
@@ -1504,6 +1536,12 @@ public class Vpn {
        return success;
    }

    /**
     * Updates underlying network set.
     *
     * <p>Note: Does not updates capabilities. Call {@link #updateCapabilities} from
     * ConnectivityService thread to get updated capabilities.
     */
    public synchronized boolean setUnderlyingNetworks(Network[] networks) {
        if (!isCallerEstablishedOwnerLocked()) {
            return false;
@@ -1520,7 +1558,6 @@ public class Vpn {
                }
            }
        }
        updateCapabilities();
        return true;
    }

+98 −17
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OFF;
import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC;
import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME;
import static android.net.ConnectivityManager.NETID_UNSET;
import static android.net.ConnectivityManager.TYPE_ETHERNET;
import static android.net.ConnectivityManager.TYPE_MOBILE;
import static android.net.ConnectivityManager.TYPE_MOBILE_FOTA;
@@ -901,11 +902,14 @@ public class ConnectivityServiceTest {

        public void setUids(Set<UidRange> uids) {
            mNetworkCapabilities.setUids(uids);
            updateCapabilities();
            updateCapabilities(null /* defaultNetwork */);
        }

        @Override
        public int getNetId() {
            if (mMockNetworkAgent == null) {
                return NETID_UNSET;
            }
            return mMockNetworkAgent.getNetwork().netId;
        }

@@ -927,12 +931,13 @@ public class ConnectivityServiceTest {
        }

        @Override
        public void updateCapabilities() {
            if (!mConnected) return;
            super.updateCapabilities();
            // Because super.updateCapabilities will update the capabilities of the agent but not
            // the mock agent, the mock agent needs to know about them.
        public NetworkCapabilities updateCapabilities(Network defaultNetwork) {
            if (!mConnected) return null;
            super.updateCapabilities(defaultNetwork);
            // Because super.updateCapabilities will update the capabilities of the agent but
            // not the mock agent, the mock agent needs to know about them.
            copyCapabilitiesToNetworkAgent();
            return new NetworkCapabilities(mNetworkCapabilities);
        }

        private void copyCapabilitiesToNetworkAgent() {
@@ -4695,6 +4700,7 @@ public class ConnectivityServiceTest {

        vpnNetworkAgent.connect(false);
        mMockVpn.connect();
        mMockVpn.setUnderlyingNetworks(new Network[0]);

        genericNetworkCallback.expectAvailableCallbacksUnvalidated(vpnNetworkAgent);
        genericNotVpnNetworkCallback.assertNoCallback();
@@ -4727,6 +4733,7 @@ public class ConnectivityServiceTest {

        ranges.add(new UidRange(uid, uid));
        mMockVpn.setUids(ranges);
        vpnNetworkAgent.setUids(ranges);

        genericNetworkCallback.expectAvailableCallbacksValidated(vpnNetworkAgent);
        genericNotVpnNetworkCallback.assertNoCallback();
@@ -4760,12 +4767,11 @@ public class ConnectivityServiceTest {
    }

    @Test
    public void testVpnWithAndWithoutInternet() {
    public void testVpnWithoutInternet() {
        final int uid = Process.myUid();

        final TestNetworkCallback defaultCallback = new TestNetworkCallback();
        mCm.registerDefaultNetworkCallback(defaultCallback);
        defaultCallback.assertNoCallback();

        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
        mWiFiNetworkAgent.connect(true);
@@ -4787,11 +4793,30 @@ public class ConnectivityServiceTest {
        vpnNetworkAgent.disconnect();
        defaultCallback.assertNoCallback();

        vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN);
        mCm.unregisterNetworkCallback(defaultCallback);
    }

    @Test
    public void testVpnWithInternet() {
        final int uid = Process.myUid();

        final TestNetworkCallback defaultCallback = new TestNetworkCallback();
        mCm.registerDefaultNetworkCallback(defaultCallback);

        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
        mWiFiNetworkAgent.connect(true);

        defaultCallback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent);
        assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());

        MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN);
        final ArraySet<UidRange> ranges = new ArraySet<>();
        ranges.add(new UidRange(uid, uid));
        mMockVpn.setNetworkAgent(vpnNetworkAgent);
        mMockVpn.setUids(ranges);
        vpnNetworkAgent.connect(true /* validated */, true /* hasInternet */);
        mMockVpn.connect();

        defaultCallback.expectAvailableThenValidatedCallbacks(vpnNetworkAgent);
        assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());

@@ -4799,14 +4824,6 @@ public class ConnectivityServiceTest {
        defaultCallback.expectCallback(CallbackState.LOST, vpnNetworkAgent);
        defaultCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent);

        vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN);
        ranges.clear();
        mMockVpn.setNetworkAgent(vpnNetworkAgent);
        mMockVpn.setUids(ranges);
        vpnNetworkAgent.connect(false /* validated */, true /* hasInternet */);
        mMockVpn.connect();
        defaultCallback.assertNoCallback();

        mCm.unregisterNetworkCallback(defaultCallback);
    }

@@ -4908,6 +4925,70 @@ public class ConnectivityServiceTest {
        mMockVpn.disconnect();
    }

    @Test
    public void testNullUnderlyingNetworks() {
        final int uid = Process.myUid();

        final TestNetworkCallback vpnNetworkCallback = new TestNetworkCallback();
        final NetworkRequest vpnNetworkRequest = new NetworkRequest.Builder()
                .removeCapability(NET_CAPABILITY_NOT_VPN)
                .addTransportType(TRANSPORT_VPN)
                .build();
        NetworkCapabilities nc;
        mCm.registerNetworkCallback(vpnNetworkRequest, vpnNetworkCallback);
        vpnNetworkCallback.assertNoCallback();

        final MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN);
        final ArraySet<UidRange> ranges = new ArraySet<>();
        ranges.add(new UidRange(uid, uid));
        mMockVpn.setNetworkAgent(vpnNetworkAgent);
        mMockVpn.connect();
        mMockVpn.setUids(ranges);
        vpnNetworkAgent.connect(true /* validated */, false /* hasInternet */);

        vpnNetworkCallback.expectAvailableThenValidatedCallbacks(vpnNetworkAgent);
        nc = mCm.getNetworkCapabilities(vpnNetworkAgent.getNetwork());
        assertTrue(nc.hasTransport(TRANSPORT_VPN));
        assertFalse(nc.hasTransport(TRANSPORT_CELLULAR));
        assertFalse(nc.hasTransport(TRANSPORT_WIFI));
        // By default, VPN is set to track default network (i.e. its underlying networks is null).
        // In case of no default network, VPN is considered metered.
        assertFalse(nc.hasCapability(NET_CAPABILITY_NOT_METERED));

        // Connect to Cell; Cell is the default network.
        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
        mCellNetworkAgent.connect(true);

        vpnNetworkCallback.expectCapabilitiesLike((caps) -> caps.hasTransport(TRANSPORT_VPN)
                && caps.hasTransport(TRANSPORT_CELLULAR) && !caps.hasTransport(TRANSPORT_WIFI)
                && !caps.hasCapability(NET_CAPABILITY_NOT_METERED),
                vpnNetworkAgent);

        // Connect to WiFi; WiFi is the new default.
        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
        mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
        mWiFiNetworkAgent.connect(true);

        vpnNetworkCallback.expectCapabilitiesLike((caps) -> caps.hasTransport(TRANSPORT_VPN)
                && !caps.hasTransport(TRANSPORT_CELLULAR) && caps.hasTransport(TRANSPORT_WIFI)
                && caps.hasCapability(NET_CAPABILITY_NOT_METERED),
                vpnNetworkAgent);

        // Disconnect Cell. The default network did not change, so there shouldn't be any changes in
        // the capabilities.
        mCellNetworkAgent.disconnect();

        // Disconnect wifi too. Now we have no default network.
        mWiFiNetworkAgent.disconnect();

        vpnNetworkCallback.expectCapabilitiesLike((caps) -> caps.hasTransport(TRANSPORT_VPN)
                && !caps.hasTransport(TRANSPORT_CELLULAR) && !caps.hasTransport(TRANSPORT_WIFI)
                && !caps.hasCapability(NET_CAPABILITY_NOT_METERED),
                vpnNetworkAgent);

        mMockVpn.disconnect();
    }

    @Test
    public void testNetworkBlockedStatus() {
        final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback();
+5 −5
Original line number Diff line number Diff line
@@ -566,7 +566,7 @@ public class VpnTest {

        final NetworkCapabilities caps = new NetworkCapabilities();

        Vpn.updateCapabilities(
        Vpn.applyUnderlyingCapabilities(
                mConnectivityManager, new Network[] {}, caps, false /* isAlwaysMetered */);
        assertTrue(caps.hasTransport(TRANSPORT_VPN));
        assertFalse(caps.hasTransport(TRANSPORT_CELLULAR));
@@ -577,7 +577,7 @@ public class VpnTest {
        assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING));
        assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED));

        Vpn.updateCapabilities(
        Vpn.applyUnderlyingCapabilities(
                mConnectivityManager,
                new Network[] {mobile},
                caps,
@@ -591,7 +591,7 @@ public class VpnTest {
        assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING));
        assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED));

        Vpn.updateCapabilities(
        Vpn.applyUnderlyingCapabilities(
                mConnectivityManager, new Network[] {wifi}, caps, false /* isAlwaysMetered */);
        assertTrue(caps.hasTransport(TRANSPORT_VPN));
        assertFalse(caps.hasTransport(TRANSPORT_CELLULAR));
@@ -602,7 +602,7 @@ public class VpnTest {
        assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING));
        assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED));

        Vpn.updateCapabilities(
        Vpn.applyUnderlyingCapabilities(
                mConnectivityManager, new Network[] {wifi}, caps, true /* isAlwaysMetered */);
        assertTrue(caps.hasTransport(TRANSPORT_VPN));
        assertFalse(caps.hasTransport(TRANSPORT_CELLULAR));
@@ -613,7 +613,7 @@ public class VpnTest {
        assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING));
        assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED));

        Vpn.updateCapabilities(
        Vpn.applyUnderlyingCapabilities(
                mConnectivityManager,
                new Network[] {mobile, wifi},
                caps,