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

Commit 481b4636 authored by Lorenzo Colitti's avatar Lorenzo Colitti Committed by Automerger Merge Worker
Browse files

Merge changes I982543cd,I41c3bf6c,Id3e5f6e1 am: 86d837da am: e5334a1b am: 487c7453

Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/1511316

Change-Id: I91ccdc9a5f4426d9c1623b869c0411b9af203c36
parents 5b299479 487c7453
Loading
Loading
Loading
Loading
+0 −7
Original line number Original line Diff line number Diff line
@@ -50,13 +50,6 @@ public class NetworkProvider {
     */
     */
    public static final int ID_NONE = -1;
    public static final int ID_NONE = -1;


    /**
     * A hardcoded ID for NetworkAgents representing VPNs. These agents are not created by any
     * provider, so they use this constant for clarity instead of NONE.
     * @hide only used by ConnectivityService.
     */
    public static final int ID_VPN = -2;

    /**
    /**
     * The first providerId value that will be allocated.
     * The first providerId value that will be allocated.
     * @hide only used by ConnectivityService.
     * @hide only used by ConnectivityService.
+4 −4
Original line number Original line Diff line number Diff line
@@ -5140,7 +5140,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
        }
        }
    }
    }


    private void onUserStart(int userId) {
    private void onUserStarted(int userId) {
        synchronized (mVpns) {
        synchronized (mVpns) {
            Vpn userVpn = mVpns.get(userId);
            Vpn userVpn = mVpns.get(userId);
            if (userVpn != null) {
            if (userVpn != null) {
@@ -5155,7 +5155,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
        }
        }
    }
    }


    private void onUserStop(int userId) {
    private void onUserStopped(int userId) {
        synchronized (mVpns) {
        synchronized (mVpns) {
            Vpn userVpn = mVpns.get(userId);
            Vpn userVpn = mVpns.get(userId);
            if (userVpn == null) {
            if (userVpn == null) {
@@ -5272,9 +5272,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
            if (userId == UserHandle.USER_NULL) return;
            if (userId == UserHandle.USER_NULL) return;


            if (Intent.ACTION_USER_STARTED.equals(action)) {
            if (Intent.ACTION_USER_STARTED.equals(action)) {
                onUserStart(userId);
                onUserStarted(userId);
            } else if (Intent.ACTION_USER_STOPPED.equals(action)) {
            } else if (Intent.ACTION_USER_STOPPED.equals(action)) {
                onUserStop(userId);
                onUserStopped(userId);
            } else if (Intent.ACTION_USER_ADDED.equals(action)) {
            } else if (Intent.ACTION_USER_ADDED.equals(action)) {
                onUserAdded(userId);
                onUserAdded(userId);
            } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
            } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
+75 −67
Original line number Original line Diff line number Diff line
@@ -122,7 +122,6 @@ import java.io.File;
import java.io.IOException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStream;
import java.math.BigInteger;
import java.net.Inet4Address;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.InetAddress;
@@ -152,36 +151,13 @@ import java.util.concurrent.atomic.AtomicInteger;
public class Vpn {
public class Vpn {
    private static final String NETWORKTYPE = "VPN";
    private static final String NETWORKTYPE = "VPN";
    private static final String TAG = "Vpn";
    private static final String TAG = "Vpn";
    private static final String VPN_PROVIDER_NAME_BASE = "VpnNetworkProvider:";
    private static final boolean LOGD = true;
    private static final boolean LOGD = true;


    // Length of time (in milliseconds) that an app hosting an always-on VPN is placed on
    // Length of time (in milliseconds) that an app hosting an always-on VPN is placed on
    // the device idle allowlist during service launch and VPN bootstrap.
    // the device idle allowlist during service launch and VPN bootstrap.
    private static final long VPN_LAUNCH_IDLE_ALLOWLIST_DURATION_MS = 60 * 1000;
    private static final long VPN_LAUNCH_IDLE_ALLOWLIST_DURATION_MS = 60 * 1000;


    // Settings for how much of the address space should be routed so that Vpn considers
    // "most" of the address space is routed. This is used to determine whether this Vpn
    // should be marked with the INTERNET capability.
    private static final long MOST_IPV4_ADDRESSES_COUNT;
    private static final BigInteger MOST_IPV6_ADDRESSES_COUNT;
    static {
        // 85% of the address space must be routed for Vpn to consider this VPN to provide
        // INTERNET access.
        final int howManyPercentIsMost = 85;

        final long twoPower32 = 1L << 32;
        MOST_IPV4_ADDRESSES_COUNT = twoPower32 * howManyPercentIsMost / 100;
        final BigInteger twoPower128 = BigInteger.ONE.shiftLeft(128);
        MOST_IPV6_ADDRESSES_COUNT = twoPower128
                .multiply(BigInteger.valueOf(howManyPercentIsMost))
                .divide(BigInteger.valueOf(100));
    }
    // How many routes to evaluate before bailing and declaring this Vpn should provide
    // the INTERNET capability. This is necessary because computing the address space is
    // O(n²) and this is running in the system service, so a limit is needed to alleviate
    // the risk of attack.
    // This is taken as a total of IPv4 + IPV6 routes for simplicity, but the algorithm
    // is actually O(n²)+O(n²).
    private static final int MAX_ROUTES_TO_EVALUATE = 150;
    private static final String LOCKDOWN_ALLOWLIST_SETTING_NAME =
    private static final String LOCKDOWN_ALLOWLIST_SETTING_NAME =
            Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN_WHITELIST;
            Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN_WHITELIST;
    /**
    /**
@@ -198,6 +174,7 @@ public class Vpn {
    // automated reconnection
    // automated reconnection


    private final Context mContext;
    private final Context mContext;
    private final ConnectivityManager mConnectivityManager;
    // The context is for specific user which is created from mUserId
    // The context is for specific user which is created from mUserId
    private final Context mUserIdContext;
    private final Context mUserIdContext;
    @VisibleForTesting final Dependencies mDeps;
    @VisibleForTesting final Dependencies mDeps;
@@ -218,6 +195,7 @@ public class Vpn {
    private final INetworkManagementService mNetd;
    private final INetworkManagementService mNetd;
    @VisibleForTesting
    @VisibleForTesting
    protected VpnConfig mConfig;
    protected VpnConfig mConfig;
    private final NetworkProvider mNetworkProvider;
    @VisibleForTesting
    @VisibleForTesting
    protected NetworkAgent mNetworkAgent;
    protected NetworkAgent mNetworkAgent;
    private final Looper mLooper;
    private final Looper mLooper;
@@ -401,6 +379,7 @@ public class Vpn {
            int userId, @NonNull KeyStore keyStore, SystemServices systemServices,
            int userId, @NonNull KeyStore keyStore, SystemServices systemServices,
            Ikev2SessionCreator ikev2SessionCreator) {
            Ikev2SessionCreator ikev2SessionCreator) {
        mContext = context;
        mContext = context;
        mConnectivityManager = mContext.getSystemService(ConnectivityManager.class);
        mUserIdContext = context.createContextAsUser(UserHandle.of(userId), 0 /* flags */);
        mUserIdContext = context.createContextAsUser(UserHandle.of(userId), 0 /* flags */);
        mDeps = deps;
        mDeps = deps;
        mNetd = netService;
        mNetd = netService;
@@ -419,6 +398,10 @@ public class Vpn {
            Log.wtf(TAG, "Problem registering observer", e);
            Log.wtf(TAG, "Problem registering observer", e);
        }
        }


        mNetworkProvider = new NetworkProvider(context, looper, VPN_PROVIDER_NAME_BASE + mUserId);
        // This constructor is called in onUserStart and registers the provider. The provider
        // will be unregistered in onUserStop.
        mConnectivityManager.registerNetworkProvider(mNetworkProvider);
        mLegacyState = LegacyVpnInfo.STATE_DISCONNECTED;
        mLegacyState = LegacyVpnInfo.STATE_DISCONNECTED;
        mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_VPN, 0 /* subtype */, NETWORKTYPE,
        mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_VPN, 0 /* subtype */, NETWORKTYPE,
                "" /* subtypeName */);
                "" /* subtypeName */);
@@ -443,12 +426,39 @@ public class Vpn {
     * Update current state, dispatching event to listeners.
     * Update current state, dispatching event to listeners.
     */
     */
    @VisibleForTesting
    @VisibleForTesting
    @GuardedBy("this")
    protected void updateState(DetailedState detailedState, String reason) {
    protected void updateState(DetailedState detailedState, String reason) {
        if (LOGD) Log.d(TAG, "setting state=" + detailedState + ", reason=" + reason);
        if (LOGD) Log.d(TAG, "setting state=" + detailedState + ", reason=" + reason);
        mLegacyState = LegacyVpnInfo.stateFromNetworkInfo(detailedState);
        mLegacyState = LegacyVpnInfo.stateFromNetworkInfo(detailedState);
        mNetworkInfo.setDetailedState(detailedState, reason, null);
        mNetworkInfo.setDetailedState(detailedState, reason, null);
        if (mNetworkAgent != null) {
        // TODO : only accept transitions when the agent is in the correct state (non-null for
            mNetworkAgent.sendNetworkInfo(mNetworkInfo);
        // CONNECTED, DISCONNECTED and FAILED, null for CONNECTED).
        // This will require a way for tests to pretend the VPN is connected that's not
        // calling this method with CONNECTED.
        // It will also require audit of where the code calls this method with DISCONNECTED
        // with a null agent, which it was doing historically to make sure the agent is
        // disconnected as this was a no-op if the agent was null.
        switch (detailedState) {
            case CONNECTED:
                if (null != mNetworkAgent) {
                    mNetworkAgent.markConnected();
                }
                break;
            case DISCONNECTED:
            case FAILED:
                if (null != mNetworkAgent) {
                    mNetworkAgent.unregister();
                    mNetworkAgent = null;
                }
                break;
            case CONNECTING:
                if (null != mNetworkAgent) {
                    throw new IllegalStateException("VPN can only go to CONNECTING state when"
                            + " the agent is null.");
                }
                break;
            default:
                throw new IllegalArgumentException("Illegal state argument " + detailedState);
        }
        }
        updateAlwaysOnNotification(detailedState);
        updateAlwaysOnNotification(detailedState);
    }
    }
@@ -476,7 +486,7 @@ public class Vpn {
        final boolean isAlwaysMetered = mIsPackageTargetingAtLeastQ && mConfig.isMetered;
        final boolean isAlwaysMetered = mIsPackageTargetingAtLeastQ && mConfig.isMetered;


        applyUnderlyingCapabilities(
        applyUnderlyingCapabilities(
                mContext.getSystemService(ConnectivityManager.class),
                mConnectivityManager,
                underlyingNetworks,
                underlyingNetworks,
                mNetworkCapabilities,
                mNetworkCapabilities,
                isAlwaysMetered);
                isAlwaysMetered);
@@ -486,10 +496,10 @@ public class Vpn {


    @VisibleForTesting
    @VisibleForTesting
    public static void applyUnderlyingCapabilities(
    public static void applyUnderlyingCapabilities(
            ConnectivityManager cm,
            @NonNull final ConnectivityManager cm,
            Network[] underlyingNetworks,
            @Nullable final Network[] underlyingNetworks,
            NetworkCapabilities caps,
            @NonNull final NetworkCapabilities caps,
            boolean isAlwaysMetered) {
            final boolean isAlwaysMetered) {
        int[] transportTypes = new int[] { NetworkCapabilities.TRANSPORT_VPN };
        int[] transportTypes = new int[] { NetworkCapabilities.TRANSPORT_VPN };
        int downKbps = NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED;
        int downKbps = NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED;
        int upKbps = NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED;
        int upKbps = NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED;
@@ -1016,7 +1026,7 @@ public class Vpn {
            }
            }
            mConfig = null;
            mConfig = null;


            updateState(DetailedState.IDLE, "prepare");
            updateState(DetailedState.DISCONNECTED, "prepare");
            setVpnForcedLocked(mLockdown);
            setVpnForcedLocked(mLockdown);
        } finally {
        } finally {
            Binder.restoreCallingIdentity(token);
            Binder.restoreCallingIdentity(token);
@@ -1252,7 +1262,7 @@ public class Vpn {
        mNetworkCapabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
        mNetworkCapabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);


        mLegacyState = LegacyVpnInfo.STATE_CONNECTING;
        mLegacyState = LegacyVpnInfo.STATE_CONNECTING;
        mNetworkInfo.setDetailedState(DetailedState.CONNECTING, null, null);
        updateState(DetailedState.CONNECTING, "agentConnect");


        NetworkAgentConfig networkAgentConfig = new NetworkAgentConfig();
        NetworkAgentConfig networkAgentConfig = new NetworkAgentConfig();
        networkAgentConfig.allowBypass = mConfig.allowBypass && !mLockdown;
        networkAgentConfig.allowBypass = mConfig.allowBypass && !mLockdown;
@@ -1270,20 +1280,23 @@ public class Vpn {
            mNetworkCapabilities.addCapability(NET_CAPABILITY_NOT_METERED);
            mNetworkCapabilities.addCapability(NET_CAPABILITY_NOT_METERED);
        }
        }


        final long token = Binder.clearCallingIdentity();
        mNetworkAgent = new NetworkAgent(mContext, mLooper, NETWORKTYPE /* logtag */,
        try {
                mNetworkCapabilities, lp,
            mNetworkAgent = new NetworkAgent(mLooper, mContext, NETWORKTYPE /* logtag */,
                ConnectivityConstants.VPN_DEFAULT_SCORE, networkAgentConfig, mNetworkProvider) {
                    mNetworkInfo, mNetworkCapabilities, lp,
                    ConnectivityConstants.VPN_DEFAULT_SCORE, networkAgentConfig,
                    NetworkProvider.ID_VPN) {
            @Override
            @Override
            public void unwanted() {
            public void unwanted() {
                // We are user controlled, not driven by NetworkRequest.
                // We are user controlled, not driven by NetworkRequest.
            }
            }
        };
        };
        } finally {
        Binder.withCleanCallingIdentity(() -> {
            Binder.restoreCallingIdentity(token);
            try {
                mNetworkAgent.register();
            } catch (final Exception e) {
                // If register() throws, don't keep an unregistered agent.
                mNetworkAgent = null;
                throw e;
            }
            }
        });
        mNetworkAgent.setUnderlyingNetworks((mConfig.underlyingNetworks != null)
        mNetworkAgent.setUnderlyingNetworks((mConfig.underlyingNetworks != null)
                ? Arrays.asList(mConfig.underlyingNetworks) : null);
                ? Arrays.asList(mConfig.underlyingNetworks) : null);
        mNetworkInfo.setIsAvailable(true);
        mNetworkInfo.setIsAvailable(true);
@@ -1301,19 +1314,12 @@ public class Vpn {


    private void agentDisconnect(NetworkAgent networkAgent) {
    private void agentDisconnect(NetworkAgent networkAgent) {
        if (networkAgent != null) {
        if (networkAgent != null) {
            NetworkInfo networkInfo = new NetworkInfo(mNetworkInfo);
            networkAgent.unregister();
            networkInfo.setIsAvailable(false);
            networkInfo.setDetailedState(DetailedState.DISCONNECTED, null, null);
            networkAgent.sendNetworkInfo(networkInfo);
        }
        }
    }
    }


    private void agentDisconnect() {
    private void agentDisconnect() {
        if (mNetworkInfo.isConnected()) {
            mNetworkInfo.setIsAvailable(false);
        updateState(DetailedState.DISCONNECTED, "agentDisconnect");
        updateState(DetailedState.DISCONNECTED, "agentDisconnect");
            mNetworkAgent = null;
        }
    }
    }


    /**
    /**
@@ -1402,6 +1408,8 @@ public class Vpn {
                    && updateLinkPropertiesInPlaceIfPossible(mNetworkAgent, oldConfig)) {
                    && updateLinkPropertiesInPlaceIfPossible(mNetworkAgent, oldConfig)) {
                // Keep mNetworkAgent unchanged
                // Keep mNetworkAgent unchanged
            } else {
            } else {
                // Initialize the state for a new agent, while keeping the old one connected
                // in case this new connection fails.
                mNetworkAgent = null;
                mNetworkAgent = null;
                updateState(DetailedState.CONNECTING, "establish");
                updateState(DetailedState.CONNECTING, "establish");
                // Set up forwarding and DNS rules.
                // Set up forwarding and DNS rules.
@@ -1635,6 +1643,9 @@ public class Vpn {


        // Quit any active connections
        // Quit any active connections
        agentDisconnect();
        agentDisconnect();

        // The provider has been registered in the constructor, which is called in onUserStart.
        mConnectivityManager.unregisterNetworkProvider(mNetworkProvider);
    }
    }


    /**
    /**
@@ -2411,7 +2422,6 @@ public class Vpn {
            // When restricted to test networks, select any network with TRANSPORT_TEST. Since the
            // When restricted to test networks, select any network with TRANSPORT_TEST. Since the
            // creator of the profile and the test network creator both have MANAGE_TEST_NETWORKS,
            // creator of the profile and the test network creator both have MANAGE_TEST_NETWORKS,
            // this is considered safe.
            // this is considered safe.
            final ConnectivityManager cm = ConnectivityManager.from(mContext);
            final NetworkRequest req;
            final NetworkRequest req;


            if (mProfile.isRestrictedToTestNetworks()) {
            if (mProfile.isRestrictedToTestNetworks()) {
@@ -2430,7 +2440,7 @@ public class Vpn {
                        .build();
                        .build();
            }
            }


            cm.requestNetwork(req, mNetworkCallback);
            mConnectivityManager.requestNetwork(req, mNetworkCallback);
        }
        }


        private boolean isActiveNetwork(@Nullable Network network) {
        private boolean isActiveNetwork(@Nullable Network network) {
@@ -2717,8 +2727,7 @@ public class Vpn {


            resetIkeState();
            resetIkeState();


            final ConnectivityManager cm = ConnectivityManager.from(mContext);
            mConnectivityManager.unregisterNetworkCallback(mNetworkCallback);
            cm.unregisterNetworkCallback(mNetworkCallback);


            mExecutor.shutdown();
            mExecutor.shutdown();
        }
        }
@@ -2799,13 +2808,12 @@ public class Vpn {
            mProfile = profile;
            mProfile = profile;


            if (!TextUtils.isEmpty(mOuterInterface)) {
            if (!TextUtils.isEmpty(mOuterInterface)) {
                final ConnectivityManager cm = ConnectivityManager.from(mContext);
                for (Network network : mConnectivityManager.getAllNetworks()) {
                for (Network network : cm.getAllNetworks()) {
                    final LinkProperties lp = mConnectivityManager.getLinkProperties(network);
                    final LinkProperties lp = cm.getLinkProperties(network);
                    if (lp != null && lp.getAllInterfaceNames().contains(mOuterInterface)) {
                    if (lp != null && lp.getAllInterfaceNames().contains(mOuterInterface)) {
                        final NetworkInfo networkInfo = cm.getNetworkInfo(network);
                        final NetworkInfo netInfo = mConnectivityManager.getNetworkInfo(network);
                        if (networkInfo != null) {
                        if (netInfo != null) {
                            mOuterConnection.set(networkInfo.getType());
                            mOuterConnection.set(netInfo.getType());
                            break;
                            break;
                        }
                        }
                    }
                    }
+6 −2
Original line number Original line Diff line number Diff line
@@ -1089,6 +1089,10 @@ public class ConnectivityServiceTest {
            mMockNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_VPN, lp,
            mMockNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_VPN, lp,
                    mNetworkCapabilities);
                    mNetworkCapabilities);
            mMockNetworkAgent.waitForIdle(TIMEOUT_MS);
            mMockNetworkAgent.waitForIdle(TIMEOUT_MS);
            verify(mNetworkManagementService, times(1))
                    .addVpnUidRanges(eq(mMockVpn.getNetId()), eq(uids.toArray(new UidRange[0])));
            verify(mNetworkManagementService, never())
                    .removeVpnUidRanges(eq(mMockVpn.getNetId()), any());
            mAgentRegistered = true;
            mAgentRegistered = true;
            mNetworkCapabilities.set(mMockNetworkAgent.getNetworkCapabilities());
            mNetworkCapabilities.set(mMockNetworkAgent.getNetworkCapabilities());
            mNetworkAgent = mMockNetworkAgent.getNetworkAgent();
            mNetworkAgent = mMockNetworkAgent.getNetworkAgent();
@@ -6922,8 +6926,8 @@ public class ConnectivityServiceTest {
        final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(VPN_USER));
        final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(VPN_USER));
        mMockVpn.establish(lp, VPN_UID, vpnRange);
        mMockVpn.establish(lp, VPN_UID, vpnRange);


        // Connected VPN should have interface rules set up. There are two expected invocations,
        // A connected VPN should have interface rules set up. There are two expected invocations,
        // one during VPN uid update, one during VPN LinkProperties update
        // one during the VPN initial connection, one during the VPN LinkProperties update.
        ArgumentCaptor<int[]> uidCaptor = ArgumentCaptor.forClass(int[].class);
        ArgumentCaptor<int[]> uidCaptor = ArgumentCaptor.forClass(int[].class);
        verify(mMockNetd, times(2)).firewallAddUidInterfaceRules(eq("tun0"), uidCaptor.capture());
        verify(mMockNetd, times(2)).firewallAddUidInterfaceRules(eq("tun0"), uidCaptor.capture());
        assertContainsExactly(uidCaptor.getAllValues().get(0), APP1_UID, APP2_UID);
        assertContainsExactly(uidCaptor.getAllValues().get(0), APP1_UID, APP2_UID);
+19 −12
Original line number Original line Diff line number Diff line
@@ -41,6 +41,7 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doAnswer;
@@ -86,10 +87,10 @@ import android.os.Build.VERSION_CODES;
import android.os.Bundle;
import android.os.Bundle;
import android.os.ConditionVariable;
import android.os.ConditionVariable;
import android.os.INetworkManagementService;
import android.os.INetworkManagementService;
import android.os.Looper;
import android.os.Process;
import android.os.Process;
import android.os.UserHandle;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.UserManager;
import android.os.test.TestLooper;
import android.provider.Settings;
import android.provider.Settings;
import android.security.Credentials;
import android.security.Credentials;
import android.security.KeyStore;
import android.security.KeyStore;
@@ -100,6 +101,7 @@ import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import androidx.test.runner.AndroidJUnit4;


import com.android.internal.R;
import com.android.internal.R;
import com.android.internal.net.LegacyVpnInfo;
import com.android.internal.net.VpnConfig;
import com.android.internal.net.VpnConfig;
import com.android.internal.net.VpnProfile;
import com.android.internal.net.VpnProfile;
import com.android.server.IpSecService;
import com.android.server.IpSecService;
@@ -223,6 +225,8 @@ public class VpnTest {
                .thenReturn(mNotificationManager);
                .thenReturn(mNotificationManager);
        when(mContext.getSystemService(eq(Context.CONNECTIVITY_SERVICE)))
        when(mContext.getSystemService(eq(Context.CONNECTIVITY_SERVICE)))
                .thenReturn(mConnectivityManager);
                .thenReturn(mConnectivityManager);
        when(mContext.getSystemServiceName(eq(ConnectivityManager.class)))
                .thenReturn(Context.CONNECTIVITY_SERVICE);
        when(mContext.getSystemService(eq(Context.IPSEC_SERVICE))).thenReturn(mIpSecManager);
        when(mContext.getSystemService(eq(Context.IPSEC_SERVICE))).thenReturn(mIpSecManager);
        when(mContext.getString(R.string.config_customVpnAlwaysOnDisconnectedDialogComponent))
        when(mContext.getString(R.string.config_customVpnAlwaysOnDisconnectedDialogComponent))
                .thenReturn(Resources.getSystem().getString(
                .thenReturn(Resources.getSystem().getString(
@@ -589,7 +593,7 @@ public class VpnTest {
    }
    }


    @Test
    @Test
    public void testNotificationShownForAlwaysOnApp() {
    public void testNotificationShownForAlwaysOnApp() throws Exception {
        final UserHandle userHandle = UserHandle.of(primaryUser.id);
        final UserHandle userHandle = UserHandle.of(primaryUser.id);
        final Vpn vpn = createVpn(primaryUser.id);
        final Vpn vpn = createVpn(primaryUser.id);
        setMockedUsers(primaryUser);
        setMockedUsers(primaryUser);
@@ -619,7 +623,6 @@ public class VpnTest {


    @Test
    @Test
    public void testCapabilities() {
    public void testCapabilities() {
        final Vpn vpn = createVpn(primaryUser.id);
        setMockedUsers(primaryUser);
        setMockedUsers(primaryUser);


        final Network mobile = new Network(1);
        final Network mobile = new Network(1);
@@ -1037,7 +1040,7 @@ public class VpnTest {
        when(exception.getErrorType())
        when(exception.getErrorType())
                .thenReturn(IkeProtocolException.ERROR_TYPE_AUTHENTICATION_FAILED);
                .thenReturn(IkeProtocolException.ERROR_TYPE_AUTHENTICATION_FAILED);


        final Vpn vpn = startLegacyVpn(mVpnProfile);
        final Vpn vpn = startLegacyVpn(createVpn(primaryUser.id), (mVpnProfile));
        final NetworkCallback cb = triggerOnAvailableAndGetCallback();
        final NetworkCallback cb = triggerOnAvailableAndGetCallback();


        // Wait for createIkeSession() to be called before proceeding in order to ensure consistent
        // Wait for createIkeSession() to be called before proceeding in order to ensure consistent
@@ -1048,20 +1051,20 @@ public class VpnTest {
        ikeCb.onClosedExceptionally(exception);
        ikeCb.onClosedExceptionally(exception);


        verify(mConnectivityManager, timeout(TEST_TIMEOUT_MS)).unregisterNetworkCallback(eq(cb));
        verify(mConnectivityManager, timeout(TEST_TIMEOUT_MS)).unregisterNetworkCallback(eq(cb));
        assertEquals(DetailedState.FAILED, vpn.getNetworkInfo().getDetailedState());
        assertEquals(LegacyVpnInfo.STATE_FAILED, vpn.getLegacyVpnInfo().state);
    }
    }


    @Test
    @Test
    public void testStartPlatformVpnIllegalArgumentExceptionInSetup() throws Exception {
    public void testStartPlatformVpnIllegalArgumentExceptionInSetup() throws Exception {
        when(mIkev2SessionCreator.createIkeSession(any(), any(), any(), any(), any(), any()))
        when(mIkev2SessionCreator.createIkeSession(any(), any(), any(), any(), any(), any()))
                .thenThrow(new IllegalArgumentException());
                .thenThrow(new IllegalArgumentException());
        final Vpn vpn = startLegacyVpn(mVpnProfile);
        final Vpn vpn = startLegacyVpn(createVpn(primaryUser.id), mVpnProfile);
        final NetworkCallback cb = triggerOnAvailableAndGetCallback();
        final NetworkCallback cb = triggerOnAvailableAndGetCallback();


        // Wait for createIkeSession() to be called before proceeding in order to ensure consistent
        // Wait for createIkeSession() to be called before proceeding in order to ensure consistent
        // state
        // state
        verify(mConnectivityManager, timeout(TEST_TIMEOUT_MS)).unregisterNetworkCallback(eq(cb));
        verify(mConnectivityManager, timeout(TEST_TIMEOUT_MS)).unregisterNetworkCallback(eq(cb));
        assertEquals(DetailedState.FAILED, vpn.getNetworkInfo().getDetailedState());
        assertEquals(LegacyVpnInfo.STATE_FAILED, vpn.getLegacyVpnInfo().state);
    }
    }


    private void setAndVerifyAlwaysOnPackage(Vpn vpn, int uid, boolean lockdownEnabled) {
    private void setAndVerifyAlwaysOnPackage(Vpn vpn, int uid, boolean lockdownEnabled) {
@@ -1100,8 +1103,7 @@ public class VpnTest {
        // a subsequent CL.
        // a subsequent CL.
    }
    }


    public Vpn startLegacyVpn(final VpnProfile vpnProfile) throws Exception {
    private Vpn startLegacyVpn(final Vpn vpn, final VpnProfile vpnProfile) throws Exception {
        final Vpn vpn = createVpn(primaryUser.id);
        setMockedUsers(primaryUser);
        setMockedUsers(primaryUser);


        // Dummy egress interface
        // Dummy egress interface
@@ -1118,7 +1120,7 @@ public class VpnTest {


    @Test
    @Test
    public void testStartPlatformVpn() throws Exception {
    public void testStartPlatformVpn() throws Exception {
        startLegacyVpn(mVpnProfile);
        startLegacyVpn(createVpn(primaryUser.id), mVpnProfile);
        // TODO: Test the Ikev2VpnRunner started up properly. Relies on utility methods added in
        // TODO: Test the Ikev2VpnRunner started up properly. Relies on utility methods added in
        // a subsequent patch.
        // a subsequent patch.
    }
    }
@@ -1153,7 +1155,7 @@ public class VpnTest {
                    legacyRunnerReady.open();
                    legacyRunnerReady.open();
                    return new Network(102);
                    return new Network(102);
                });
                });
        final Vpn vpn = startLegacyVpn(profile);
        final Vpn vpn = startLegacyVpn(createVpn(primaryUser.id), profile);
        final TestDeps deps = (TestDeps) vpn.mDeps;
        final TestDeps deps = (TestDeps) vpn.mDeps;
        try {
        try {
            // udppsk and 1701 are the values for TYPE_L2TP_IPSEC_PSK
            // udppsk and 1701 are the values for TYPE_L2TP_IPSEC_PSK
@@ -1287,8 +1289,13 @@ public class VpnTest {
        doReturn(UserHandle.of(userId)).when(asUserContext).getUser();
        doReturn(UserHandle.of(userId)).when(asUserContext).getUser();
        when(mContext.createContextAsUser(eq(UserHandle.of(userId)), anyInt()))
        when(mContext.createContextAsUser(eq(UserHandle.of(userId)), anyInt()))
                .thenReturn(asUserContext);
                .thenReturn(asUserContext);
        return new Vpn(Looper.myLooper(), mContext, new TestDeps(), mNetService,
        final TestLooper testLooper = new TestLooper();
        final Vpn vpn = new Vpn(testLooper.getLooper(), mContext, new TestDeps(), mNetService,
                userId, mKeyStore, mSystemServices, mIkev2SessionCreator);
                userId, mKeyStore, mSystemServices, mIkev2SessionCreator);
        verify(mConnectivityManager, times(1)).registerNetworkProvider(argThat(
                provider -> provider.getName().contains("VpnNetworkProvider")
        ));
        return vpn;
    }
    }


    private static void assertBlocked(Vpn vpn, int... uids) {
    private static void assertBlocked(Vpn vpn, int... uids) {