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

Commit 282ed251 authored by Lorenzo Colitti's avatar Lorenzo Colitti
Browse files

Inform ConnectivityService about always-on VPN lockdown.

Currently, when an always-on VPN is set in lockdown mode, Vpn
configures prohibit UID rules in netd directly and does not
inform ConnectivityService of the fact.

This means that ConnectivityService cannot send NetworkCallbacks
that tells apps that they are blocked or unblocked. It also means
that ConnectivityService has to take the mVpns lock and call into
Vpn to allow synchronous APIs such as getActiveNetwork to return
BLOCKED if the app is blocked.

Move all this to ConnectivityService:
- Add a setRequireVpnForUids API to ConnectivityManager, and have
  that pass the routing rules to netd.
- Update VpnTest to expect calls to ConnectivityManager instead
  of to netd.
- Whenever setRequireVpnForUids is called, ensure that
  ConnectivityService sends onBlockedStatusChanged to the
  affected callbacks.
- Update existing unit tests to check for callbacks.
- Add a way to find the VPN that applies to a given UID without
  taking the VPN lock, by instead scanning all connected VPNs.
  Use this as a replacement for direct access to mVpns.

For simplicity, and in order to ensure proper ordering between
the NetworkCallbacks sent for VPNs connecting and disconnecting,
process blocked UID ranges on the handler thread. This means that
when setRequireVpnForUids returns, the rule changes might not
have been applied. This shouldn't impact apps using network
connectivity, but it might mean that apps setting an always-on
package, and then immediately checking whether networking is
blocked, will see a behaviour change.

Bug: 173331190
Fix: 175670887
Test: new test coverage in ConnectivityServiceTest
Test: atest MixedDeviceOwnerTest#testAlwaysOnVpn \
            MixedDeviceOwnerTest#testAlwaysOnVpnLockDown \
	    MixedDeviceOwnerTest#testAlwaysOnVpnAcrossReboot \
	    MixedDeviceOwnerTest#testAlwaysOnVpnPackageUninstalled \
	    MixedDeviceOwnerTest#testAlwaysOnVpnUnsupportedPackage \
	    MixedDeviceOwnerTest#testAlwaysOnVpnUnsupportedPackageReplaced \
	    MixedDeviceOwnerTest#testAlwaysOnVpnPackageLogged \
            MixedProfileOwnerTest#testAlwaysOnVpn \
            MixedProfileOwnerTest#testAlwaysOnVpnLockDown \
	    MixedProfileOwnerTest#testAlwaysOnVpnAcrossReboot \
	    MixedProfileOwnerTest#testAlwaysOnVpnPackageUninstalled \
	    MixedProfileOwnerTest#testAlwaysOnVpnUnsupportedPackage \
	    MixedProfileOwnerTest#testAlwaysOnVpnUnsupportedPackageReplaced \
	    MixedProfileOwnerTest#testAlwaysOnVpnPackageLogged \
            MixedManagedProfileOwnerTest#testAlwaysOnVpn \
            MixedManagedProfileOwnerTest#testAlwaysOnVpnLockDown \
	    MixedManagedProfileOwnerTest#testAlwaysOnVpnAcrossReboot \
	    MixedManagedProfileOwnerTest#testAlwaysOnVpnPackageUninstalled \
	    MixedManagedProfileOwnerTest#testAlwaysOnVpnUnsupportedPackage \
	    MixedManagedProfileOwnerTest#testAlwaysOnVpnUnsupportedPackageReplaced \
	    MixedManagedProfileOwnerTest#testAlwaysOnVpnPackageLogged
Test: atest FrameworksNetTests HostsideVpnTests \
            CtsNetTestCases:VpnServiceTest \
	    CtsNetTestCases:Ikev2VpnTest
Change-Id: Iaca8a7cc343aef52706cff62a7735f338cb1b772
parent 60dfb880
Loading
Loading
Loading
Loading
+52 −0
Original line number Diff line number Diff line
@@ -59,6 +59,7 @@ import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.util.ArrayMap;
import android.util.Log;
import android.util.Range;
import android.util.SparseIntArray;

import com.android.connectivity.aidl.INetworkAgent;
@@ -73,10 +74,12 @@ import java.io.IOException;
import java.io.UncheckedIOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -1162,6 +1165,55 @@ public class ConnectivityManager {
        }
    }

    /**
     * Adds or removes a requirement for given UID ranges to use the VPN.
     *
     * If set to {@code true}, informs the system that the UIDs in the specified ranges must not
     * have any connectivity except if a VPN is connected and applies to the UIDs, or if the UIDs
     * otherwise have permission to bypass the VPN (e.g., because they have the
     * {@link android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS} permission, or when
     * using a socket protected by a method such as {@link VpnService#protect(DatagramSocket)}. If
     * set to {@code false}, a previously-added restriction is removed.
     * <p>
     * Each of the UID ranges specified by this method is added and removed as is, and no processing
     * is performed on the ranges to de-duplicate, merge, split, or intersect them. In order to
     * remove a previously-added range, the exact range must be removed as is.
     * <p>
     * The changes are applied asynchronously and may not have been applied by the time the method
     * returns. Apps will be notified about any changes that apply to them via
     * {@link NetworkCallback#onBlockedStatusChanged} callbacks called after the changes take
     * effect.
     * <p>
     * This method should be called only by the VPN code.
     *
     * @param ranges the UID ranges to restrict
     * @param requireVpn whether the specified UID ranges must use a VPN
     *
     * TODO: expose as @SystemApi.
     * @hide
     */
    @RequiresPermission(anyOf = {
            NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
            android.Manifest.permission.NETWORK_STACK})
    public void setRequireVpnForUids(boolean requireVpn,
            @NonNull Collection<Range<Integer>> ranges) {
        Objects.requireNonNull(ranges);
        // The Range class is not parcelable. Convert to UidRange, which is what is used internally.
        // This method is not necessarily expected to be used outside the system server, so
        // parceling may not be necessary, but it could be used out-of-process, e.g., by the network
        // stack process, or by tests.
        UidRange[] rangesArray = new UidRange[ranges.size()];
        int index = 0;
        for (Range<Integer> range : ranges) {
            rangesArray[index++] = new UidRange(range.getLower(), range.getUpper());
        }
        try {
            mService.setRequireVpnForUids(requireVpn, rangesArray);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * Returns details about the currently active default data network
     * for a given uid.  This is for internal use only to avoid spying
+2 −0
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@ import android.net.NetworkRequest;
import android.net.NetworkState;
import android.net.ISocketKeepaliveCallback;
import android.net.ProxyInfo;
import android.net.UidRange;
import android.os.Bundle;
import android.os.IBinder;
import android.os.INetworkActivityListener;
@@ -146,6 +147,7 @@ interface IConnectivityManager
    String getAlwaysOnVpnPackage(int userId);
    boolean isVpnLockdownEnabled(int userId);
    List<String> getVpnLockdownWhitelist(int userId);
    void setRequireVpnForUids(boolean requireVpn, in UidRange[] ranges);

    void setProvisioningNotificationVisible(boolean visible, int networkType, in String action);

+120 −52
Original line number Diff line number Diff line
@@ -546,6 +546,13 @@ public class ConnectivityService extends IConnectivityManager.Stub
     */
    private static final int EVENT_CAPPORT_DATA_CHANGED = 46;

    /**
     * Used by setRequireVpnForUids.
     * arg1 = whether the specified UID ranges are required to use a VPN.
     * obj  = Array of UidRange objects.
     */
    private static final int EVENT_SET_REQUIRE_VPN_FOR_UIDS = 47;

    /**
     * Argument for {@link #EVENT_PROVISIONING_NOTIFICATION} to indicate that the notification
     * should be shown.
@@ -1274,16 +1281,25 @@ public class ConnectivityService extends IConnectivityManager.Stub
        }
    }

    private Network[] getVpnUnderlyingNetworks(int uid) {
        synchronized (mVpns) {
            if (!mLockdownEnabled) {
                int user = UserHandle.getUserId(uid);
                Vpn vpn = mVpns.get(user);
                if (vpn != null && vpn.appliesToUid(uid)) {
                    return vpn.getUnderlyingNetworks();
    // TODO: determine what to do when more than one VPN applies to |uid|.
    private NetworkAgentInfo getVpnForUid(int uid) {
        synchronized (mNetworkForNetId) {
            for (int i = 0; i < mNetworkForNetId.size(); i++) {
                final NetworkAgentInfo nai = mNetworkForNetId.valueAt(i);
                if (nai.isVPN() && nai.everConnected && nai.networkCapabilities.appliesToUid(uid)) {
                    return nai;
                }
            }
        }
        return null;
    }

    private Network[] getVpnUnderlyingNetworks(int uid) {
        synchronized (mVpns) {
            if (mLockdownEnabled) return null;
        }
        final NetworkAgentInfo nai = getVpnForUid(uid);
        if (nai != null) return nai.declaredUnderlyingNetworks;
        return null;
    }

@@ -1312,7 +1328,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
    }

    /**
     * Check if UID should be blocked from using the network with the given LinkProperties.
     * Check if UID should be blocked from using the specified network.
     */
    private boolean isNetworkWithLinkPropertiesBlocked(LinkProperties lp, int uid,
            boolean ignoreBlocked) {
@@ -1320,12 +1336,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
        if (ignoreBlocked) {
            return false;
        }
        synchronized (mVpns) {
            final Vpn vpn = mVpns.get(UserHandle.getUserId(uid));
            if (vpn != null && vpn.getLockdown() && vpn.isBlockingUid(uid)) {
                return true;
            }
        }
        if (isUidBlockedByVpn(uid, mVpnBlockedUidRanges)) return true;
        final String iface = (lp == null ? "" : lp.getInterfaceName());
        return mPolicyManagerInternal.isUidNetworkingBlocked(uid, iface);
    }
@@ -1992,29 +2003,18 @@ public class ConnectivityService extends IConnectivityManager.Stub
    void handleRestrictBackgroundChanged(boolean restrictBackground) {
        if (mRestrictBackground == restrictBackground) return;

        final List<UidRange> blockedRanges = mVpnBlockedUidRanges;
        for (final NetworkAgentInfo nai : mNetworkAgentInfos) {
            final boolean curMetered = nai.networkCapabilities.isMetered();
            maybeNotifyNetworkBlocked(nai, curMetered, curMetered, mRestrictBackground,
                    restrictBackground);
                    restrictBackground, blockedRanges, blockedRanges);
        }

        mRestrictBackground = restrictBackground;
    }

    private boolean isUidNetworkingWithVpnBlocked(int uid, int uidRules, boolean isNetworkMetered,
    private boolean isUidBlockedByRules(int uid, int uidRules, boolean isNetworkMetered,
            boolean isBackgroundRestricted) {
        synchronized (mVpns) {
            final Vpn vpn = mVpns.get(UserHandle.getUserId(uid));
            // Because the return value of this function depends on the list of UIDs the
            // always-on VPN blocks when in lockdown mode, when the always-on VPN changes that
            // list all state depending on the return value of this function has to be recomputed.
            // TODO: add a trigger when the always-on VPN sets its blocked UIDs to reevaluate and
            // send the necessary onBlockedStatusChanged callbacks.
            if (vpn != null && vpn.getLockdown() && vpn.isBlockingUid(uid)) {
                return true;
            }
        }

        return NetworkPolicyManagerInternal.isUidNetworkingBlocked(uid, uidRules,
                isNetworkMetered, isBackgroundRestricted);
    }
@@ -4289,6 +4289,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
                case EVENT_DATA_SAVER_CHANGED:
                    handleRestrictBackgroundChanged(toBool(msg.arg1));
                    break;
                case EVENT_SET_REQUIRE_VPN_FOR_UIDS:
                    handleSetRequireVpnForUids(toBool(msg.arg1), (UidRange[]) msg.obj);
                    break;
            }
        }
    }
@@ -4457,8 +4460,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
        if (!nai.everConnected) {
            return;
        }
        LinkProperties lp = getLinkProperties(nai);
        if (isNetworkWithLinkPropertiesBlocked(lp, uid, false)) {
        if (isNetworkWithLinkPropertiesBlocked(nai.linkProperties, uid, false)) {
            return;
        }
        nai.networkMonitor().forceReevaluation(uid);
@@ -4885,6 +4887,56 @@ public class ConnectivityService extends IConnectivityManager.Stub
        }
    }

    private boolean isUidBlockedByVpn(int uid, List<UidRange> blockedUidRanges) {
        // Determine whether this UID is blocked because of always-on VPN lockdown. If a VPN applies
        // to the UID, then the UID is not blocked because always-on VPN lockdown applies only when
        // a VPN is not up.
        final NetworkAgentInfo vpnNai = getVpnForUid(uid);
        if (vpnNai != null && !vpnNai.networkAgentConfig.allowBypass) return false;
        for (UidRange range : blockedUidRanges) {
            if (range.contains(uid)) return true;
        }
        return false;
    }

    @Override
    public void setRequireVpnForUids(boolean requireVpn, UidRange[] ranges) {
        NetworkStack.checkNetworkStackPermission(mContext);
        mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_REQUIRE_VPN_FOR_UIDS,
                encodeBool(requireVpn), 0 /* arg2 */, ranges));
    }

    private void handleSetRequireVpnForUids(boolean requireVpn, UidRange[] ranges) {
        if (DBG) {
            Log.d(TAG, "Setting VPN " + (requireVpn ? "" : "not ") + "required for UIDs: "
                    + Arrays.toString(ranges));
        }
        // Cannot use a Set since the list of UID ranges might contain duplicates.
        final List<UidRange> newVpnBlockedUidRanges = new ArrayList(mVpnBlockedUidRanges);
        for (int i = 0; i < ranges.length; i++) {
            if (requireVpn) {
                newVpnBlockedUidRanges.add(ranges[i]);
            } else {
                newVpnBlockedUidRanges.remove(ranges[i]);
            }
        }

        try {
            mNetd.networkRejectNonSecureVpn(requireVpn, toUidRangeStableParcels(ranges));
        } catch (RemoteException | ServiceSpecificException e) {
            Log.e(TAG, "setRequireVpnForUids(" + requireVpn + ", "
                    + Arrays.toString(ranges) + "): netd command failed: " + e);
        }

        for (final NetworkAgentInfo nai : mNetworkAgentInfos) {
            final boolean curMetered = nai.networkCapabilities.isMetered();
            maybeNotifyNetworkBlocked(nai, curMetered, curMetered, mRestrictBackground,
                    mRestrictBackground, mVpnBlockedUidRanges, newVpnBlockedUidRanges);
        }

        mVpnBlockedUidRanges = newVpnBlockedUidRanges;
    }

    @Override
    public boolean updateLockdownVpn() {
        if (mDeps.getCallingUid() != Process.SYSTEM_UID) {
@@ -5870,6 +5922,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
    // NOTE: Only should be accessed on ConnectivityServiceThread, except dump().
    private final ArraySet<NetworkAgentInfo> mNetworkAgentInfos = new ArraySet<>();

    // UID ranges for users that are currently blocked by VPNs.
    // This array is accessed and iterated on multiple threads without holding locks, so its
    // contents must never be mutated. When the ranges change, the array is replaced with a new one
    // (on the handler thread).
    private volatile List<UidRange> mVpnBlockedUidRanges = new ArrayList<>();

    @GuardedBy("mBlockedAppUids")
    private final HashSet<Integer> mBlockedAppUids = new HashSet<>();

@@ -6524,7 +6582,7 @@ public class ConnectivityService extends IConnectivityManager.Stub

            if (meteredChanged) {
                maybeNotifyNetworkBlocked(nai, oldMetered, newMetered, mRestrictBackground,
                        mRestrictBackground);
                        mRestrictBackground, mVpnBlockedUidRanges, mVpnBlockedUidRanges);
            }

            final boolean roamingChanged = prevNc.hasCapability(NET_CAPABILITY_NOT_ROAMING) !=
@@ -6589,6 +6647,15 @@ public class ConnectivityService extends IConnectivityManager.Stub
        return stableRanges;
    }

    private static UidRangeParcel[] toUidRangeStableParcels(UidRange[] ranges) {
        final UidRangeParcel[] stableRanges = new UidRangeParcel[ranges.length];
        for (int i = 0; i < ranges.length; i++) {
            stableRanges[i] = new UidRangeParcel(ranges[i].start, ranges[i].stop);
        }
        return stableRanges;
    }


    private void updateUids(NetworkAgentInfo nai, NetworkCapabilities prevNc,
            NetworkCapabilities newNc) {
        Set<UidRange> prevRanges = null == prevNc ? null : prevNc.getUids();
@@ -7416,7 +7483,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
        }

        final boolean metered = nai.networkCapabilities.isMetered();
        final boolean blocked = isUidNetworkingWithVpnBlocked(nri.mUid, mUidRules.get(nri.mUid),
        boolean blocked;
        blocked = isUidBlockedByVpn(nri.mUid, mVpnBlockedUidRanges);
        blocked |= isUidBlockedByRules(nri.mUid, mUidRules.get(nri.mUid),
                metered, mRestrictBackground);
        callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_AVAILABLE, blocked ? 1 : 0);
    }
@@ -7438,21 +7507,25 @@ public class ConnectivityService extends IConnectivityManager.Stub
     * @param newRestrictBackground True if data saver is enabled.
     */
    private void maybeNotifyNetworkBlocked(NetworkAgentInfo nai, boolean oldMetered,
            boolean newMetered, boolean oldRestrictBackground, boolean newRestrictBackground) {
            boolean newMetered, boolean oldRestrictBackground, boolean newRestrictBackground,
            List<UidRange> oldBlockedUidRanges, List<UidRange> newBlockedUidRanges) {

        for (int i = 0; i < nai.numNetworkRequests(); i++) {
            NetworkRequest nr = nai.requestAt(i);
            NetworkRequestInfo nri = mNetworkRequests.get(nr);
            final int uidRules = mUidRules.get(nri.mUid);
            final boolean oldBlocked, newBlocked;
            // mVpns lock needs to be hold here to ensure that the active VPN cannot be changed
            // between these two calls.
            synchronized (mVpns) {
                oldBlocked = isUidNetworkingWithVpnBlocked(nri.mUid, uidRules, oldMetered,
            final boolean oldBlocked, newBlocked, oldVpnBlocked, newVpnBlocked;

            oldVpnBlocked = isUidBlockedByVpn(nri.mUid, oldBlockedUidRanges);
            newVpnBlocked = (oldBlockedUidRanges != newBlockedUidRanges)
                    ? isUidBlockedByVpn(nri.mUid, newBlockedUidRanges)
                    : oldVpnBlocked;

            oldBlocked = oldVpnBlocked || isUidBlockedByRules(nri.mUid, uidRules, oldMetered,
                    oldRestrictBackground);
                newBlocked = isUidNetworkingWithVpnBlocked(nri.mUid, uidRules, newMetered,
            newBlocked = newVpnBlocked || isUidBlockedByRules(nri.mUid, uidRules, newMetered,
                    newRestrictBackground);
            }

            if (oldBlocked != newBlocked) {
                callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_BLK_CHANGED,
                        encodeBool(newBlocked));
@@ -7468,17 +7541,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
    private void maybeNotifyNetworkBlockedForNewUidRules(int uid, int newRules) {
        for (final NetworkAgentInfo nai : mNetworkAgentInfos) {
            final boolean metered = nai.networkCapabilities.isMetered();
            final boolean vpnBlocked = isUidBlockedByVpn(uid, mVpnBlockedUidRanges);
            final boolean oldBlocked, newBlocked;
            // TODO: Consider that doze mode or turn on/off battery saver would deliver lots of uid
            // rules changed event. And this function actually loop through all connected nai and
            // its requests. It seems that mVpns lock will be grabbed frequently in this case.
            // Reduce the number of locking or optimize the use of lock are likely needed in future.
            synchronized (mVpns) {
                oldBlocked = isUidNetworkingWithVpnBlocked(
            oldBlocked = vpnBlocked || isUidBlockedByRules(
                    uid, mUidRules.get(uid), metered, mRestrictBackground);
                newBlocked = isUidNetworkingWithVpnBlocked(
            newBlocked = vpnBlocked || isUidBlockedByRules(
                    uid, newRules, metered, mRestrictBackground);
            }
            if (oldBlocked == newBlocked) {
                continue;
            }
+5 −1
Original line number Diff line number Diff line
@@ -146,7 +146,11 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
    // Underlying networks declared by the agent. Only set if supportsUnderlyingNetworks is true.
    // The networks in this list might be declared by a VPN app using setUnderlyingNetworks and are
    // not guaranteed to be current or correct, or even to exist.
    public @Nullable Network[] declaredUnderlyingNetworks;
    //
    // This array is read and iterated on multiple threads with no locking so its contents must
    // never be modified. When the list of networks changes, replace with a new array, on the
    // handler thread.
    public @Nullable volatile Network[] declaredUnderlyingNetworks;

    // The capabilities originally announced by the NetworkAgent, regardless of any capabilities
    // that were added or removed due to this network's underlying networks.
+28 −24
Original line number Diff line number Diff line
@@ -101,6 +101,7 @@ import android.security.KeyStore;
import android.text.TextUtils;
import android.util.ArraySet;
import android.util.Log;
import android.util.Range;

import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
@@ -223,7 +224,7 @@ public class Vpn {
    private @NonNull List<String> mLockdownAllowlist = Collections.emptyList();

     /**
     * A memory of what UIDs this class told netd to block for the lockdown feature.
     * A memory of what UIDs this class told ConnectivityService to block for the lockdown feature.
     *
     * Netd maintains ranges of UIDs for which network should be restricted to using only the VPN
     * for the lockdown feature. This class manages these UIDs and sends this information to netd.
@@ -237,7 +238,7 @@ public class Vpn {
     * @see mLockdown
     */
    @GuardedBy("this")
    private final Set<UidRangeParcel> mBlockedUidsAsToldToNetd = new ArraySet<>();
    private final Set<UidRangeParcel> mBlockedUidsAsToldToConnectivity = new ArraySet<>();

    // The user id of initiating VPN.
    private final int mUserId;
@@ -1588,7 +1589,7 @@ public class Vpn {
     *                {@link Vpn} goes through a VPN connection or is blocked until one is
     *                available, {@code false} to lift the requirement.
     *
     * @see #mBlockedUidsAsToldToNetd
     * @see #mBlockedUidsAsToldToConnectivity
     */
    @GuardedBy("this")
    private void setVpnForcedLocked(boolean enforce) {
@@ -1599,10 +1600,8 @@ public class Vpn {
            exemptedPackages = new ArrayList<>(mLockdownAllowlist);
            exemptedPackages.add(mPackage);
        }
        final Set<UidRangeParcel> rangesToTellNetdToRemove =
                new ArraySet<>(mBlockedUidsAsToldToNetd);

        final Set<UidRangeParcel> rangesToTellNetdToAdd;
        final Set<UidRangeParcel> rangesToRemove = new ArraySet<>(mBlockedUidsAsToldToConnectivity);
        final Set<UidRangeParcel> rangesToAdd;
        if (enforce) {
            final Set<UidRange> restrictedProfilesRanges =
                    createUserAndRestrictedProfilesRanges(mUserId,
@@ -1621,26 +1620,27 @@ public class Vpn {
                }
            }

            rangesToTellNetdToRemove.removeAll(rangesThatShouldBeBlocked);
            rangesToTellNetdToAdd = rangesThatShouldBeBlocked;
            // The ranges to tell netd to add are the ones that should be blocked minus the
            // ones it already knows to block. Note that this will change the contents of
            rangesToRemove.removeAll(rangesThatShouldBeBlocked);
            rangesToAdd = rangesThatShouldBeBlocked;
            // The ranges to tell ConnectivityService to add are the ones that should be blocked
            // minus the ones it already knows to block. Note that this will change the contents of
            // rangesThatShouldBeBlocked, but the list of ranges that should be blocked is
            // not used after this so it's fine to destroy it.
            rangesToTellNetdToAdd.removeAll(mBlockedUidsAsToldToNetd);
            rangesToAdd.removeAll(mBlockedUidsAsToldToConnectivity);
        } else {
            rangesToTellNetdToAdd = Collections.emptySet();
            rangesToAdd = Collections.emptySet();
        }

        // If mBlockedUidsAsToldToNetd used to be empty, this will always be a no-op.
        setAllowOnlyVpnForUids(false, rangesToTellNetdToRemove);
        setAllowOnlyVpnForUids(false, rangesToRemove);
        // If nothing should be blocked now, this will now be a no-op.
        setAllowOnlyVpnForUids(true, rangesToTellNetdToAdd);
        setAllowOnlyVpnForUids(true, rangesToAdd);
    }

    /**
     * Tell netd to add or remove a list of {@link UidRange}s to the list of UIDs that are only
     * allowed to make connections through sockets that have had {@code protect()} called on them.
     * Tell ConnectivityService to add or remove a list of {@link UidRange}s to the list of UIDs
     * that are only allowed to make connections through sockets that have had {@code protect()}
     * called on them.
     *
     * @param enforce {@code true} to add to the denylist, {@code false} to remove.
     * @param ranges {@link Collection} of {@link UidRange}s to add (if {@param enforce} is
@@ -1653,18 +1653,22 @@ public class Vpn {
        if (ranges.size() == 0) {
            return true;
        }
        final UidRangeParcel[] stableRanges = ranges.toArray(new UidRangeParcel[ranges.size()]);
        // Convert to Collection<Range> which is what the ConnectivityManager API takes.
        ArrayList<Range<Integer>> integerRanges = new ArrayList<>(ranges.size());
        for (UidRangeParcel uidRange : ranges) {
            integerRanges.add(new Range<>(uidRange.start, uidRange.stop));
        }
        try {
            mNetd.networkRejectNonSecureVpn(enforce, stableRanges);
        } catch (RemoteException | RuntimeException e) {
            mConnectivityManager.setRequireVpnForUids(enforce, integerRanges);
        } catch (RuntimeException e) {
            Log.e(TAG, "Updating blocked=" + enforce
                    + " for UIDs " + Arrays.toString(ranges.toArray()) + " failed", e);
            return false;
        }
        if (enforce) {
            mBlockedUidsAsToldToNetd.addAll(ranges);
            mBlockedUidsAsToldToConnectivity.addAll(ranges);
        } else {
            mBlockedUidsAsToldToNetd.removeAll(ranges);
            mBlockedUidsAsToldToConnectivity.removeAll(ranges);
        }
        return true;
    }
@@ -1864,13 +1868,13 @@ public class Vpn {
     * the {@code uid}.
     *
     * @apiNote This method don't check VPN lockdown status.
     * @see #mBlockedUidsAsToldToNetd
     * @see #mBlockedUidsAsToldToConnectivity
     */
    public synchronized boolean isBlockingUid(int uid) {
        if (mNetworkInfo.isConnected()) {
            return !appliesToUid(uid);
        } else {
            return containsUid(mBlockedUidsAsToldToNetd, uid);
            return containsUid(mBlockedUidsAsToldToConnectivity, uid);
        }
    }

Loading