14d03abcd49af490dba3850d341b955dd72f24959Robin Lee/*
24d03abcd49af490dba3850d341b955dd72f24959Robin Lee * Copyright (C) 2016 The Android Open Source Project
34d03abcd49af490dba3850d341b955dd72f24959Robin Lee *
44d03abcd49af490dba3850d341b955dd72f24959Robin Lee * Licensed under the Apache License, Version 2.0 (the "License");
54d03abcd49af490dba3850d341b955dd72f24959Robin Lee * you may not use this file except in compliance with the License.
64d03abcd49af490dba3850d341b955dd72f24959Robin Lee * You may obtain a copy of the License at
74d03abcd49af490dba3850d341b955dd72f24959Robin Lee *
84d03abcd49af490dba3850d341b955dd72f24959Robin Lee *      http://www.apache.org/licenses/LICENSE-2.0
94d03abcd49af490dba3850d341b955dd72f24959Robin Lee *
104d03abcd49af490dba3850d341b955dd72f24959Robin Lee * Unless required by applicable law or agreed to in writing, software
114d03abcd49af490dba3850d341b955dd72f24959Robin Lee * distributed under the License is distributed on an "AS IS" BASIS,
124d03abcd49af490dba3850d341b955dd72f24959Robin Lee * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
134d03abcd49af490dba3850d341b955dd72f24959Robin Lee * See the License for the specific language governing permissions and
144d03abcd49af490dba3850d341b955dd72f24959Robin Lee * limitations under the License.
154d03abcd49af490dba3850d341b955dd72f24959Robin Lee */
164d03abcd49af490dba3850d341b955dd72f24959Robin Lee
174d03abcd49af490dba3850d341b955dd72f24959Robin Leepackage com.android.server.connectivity;
184d03abcd49af490dba3850d341b955dd72f24959Robin Lee
194d03abcd49af490dba3850d341b955dd72f24959Robin Leeimport static android.content.pm.UserInfo.FLAG_ADMIN;
204d03abcd49af490dba3850d341b955dd72f24959Robin Leeimport static android.content.pm.UserInfo.FLAG_MANAGED_PROFILE;
214d03abcd49af490dba3850d341b955dd72f24959Robin Leeimport static android.content.pm.UserInfo.FLAG_PRIMARY;
224d03abcd49af490dba3850d341b955dd72f24959Robin Leeimport static android.content.pm.UserInfo.FLAG_RESTRICTED;
2372f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkeyimport static android.net.NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED;
2472f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkeyimport static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
259b2a10f55d1659895e20ec0b88dd023ae18770ebJeff Sharkeyimport static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED;
2672f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkeyimport static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
2772f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkeyimport static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
2872f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkeyimport static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
2972f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkeyimport static android.net.NetworkCapabilities.TRANSPORT_VPN;
3072f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkeyimport static android.net.NetworkCapabilities.TRANSPORT_WIFI;
3172f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkey
324a0c5d7ef7144280fe8a209a871bbd4ef90d6368Hugo Benichiimport static org.junit.Assert.assertEquals;
334a0c5d7ef7144280fe8a209a871bbd4ef90d6368Hugo Benichiimport static org.junit.Assert.assertFalse;
344a0c5d7ef7144280fe8a209a871bbd4ef90d6368Hugo Benichiimport static org.junit.Assert.assertTrue;
3572f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkeyimport static org.mockito.AdditionalMatchers.aryEq;
3672f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkeyimport static org.mockito.ArgumentMatchers.any;
3772f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkeyimport static org.mockito.ArgumentMatchers.anyBoolean;
3872f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkeyimport static org.mockito.ArgumentMatchers.anyInt;
3972f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkeyimport static org.mockito.ArgumentMatchers.anyString;
4072f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkeyimport static org.mockito.ArgumentMatchers.eq;
4172f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkeyimport static org.mockito.Mockito.atLeastOnce;
4272f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkeyimport static org.mockito.Mockito.doAnswer;
4372f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkeyimport static org.mockito.Mockito.doNothing;
4472f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkeyimport static org.mockito.Mockito.inOrder;
4572f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkeyimport static org.mockito.Mockito.times;
4672f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkeyimport static org.mockito.Mockito.verify;
4772f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkeyimport static org.mockito.Mockito.when;
484d03abcd49af490dba3850d341b955dd72f24959Robin Lee
494d03abcd49af490dba3850d341b955dd72f24959Robin Leeimport android.annotation.UserIdInt;
5017e6183b85ba3038acb935aaa01415058b2e6dddRobin Leeimport android.app.AppOpsManager;
51de7f7d195eec64802b7b6eee819c699f1a7d6951Tony Makimport android.app.NotificationManager;
524d03abcd49af490dba3850d341b955dd72f24959Robin Leeimport android.content.Context;
53b8c2a2b85052479cb6affe2d4a8240e78198e2d5Robin Leeimport android.content.pm.ApplicationInfo;
544d03abcd49af490dba3850d341b955dd72f24959Robin Leeimport android.content.pm.PackageManager;
55a0a87e810870b696239f0371d33de924f84cb431Charles Heimport android.content.pm.ResolveInfo;
56a0a87e810870b696239f0371d33de924f84cb431Charles Heimport android.content.pm.ServiceInfo;
574d03abcd49af490dba3850d341b955dd72f24959Robin Leeimport android.content.pm.UserInfo;
58c17f50f83d3e35f338095df6065426f2f304a1dcCharles Heimport android.content.res.Resources;
5972f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkeyimport android.net.ConnectivityManager;
60adbf1d029b753fabc2a7a5ad3b22d3d416cecdd9Chalard Jeanimport android.net.IConnectivityManager;
61adbf1d029b753fabc2a7a5ad3b22d3d416cecdd9Chalard Jeanimport android.net.IpPrefix;
62adbf1d029b753fabc2a7a5ad3b22d3d416cecdd9Chalard Jeanimport android.net.LinkProperties;
6372f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkeyimport android.net.Network;
6472f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkeyimport android.net.NetworkCapabilities;
65de7f7d195eec64802b7b6eee819c699f1a7d6951Tony Makimport android.net.NetworkInfo.DetailedState;
66adbf1d029b753fabc2a7a5ad3b22d3d416cecdd9Chalard Jeanimport android.net.RouteInfo;
674d03abcd49af490dba3850d341b955dd72f24959Robin Leeimport android.net.UidRange;
68a0a87e810870b696239f0371d33de924f84cb431Charles Heimport android.net.VpnService;
69a0a87e810870b696239f0371d33de924f84cb431Charles Heimport android.os.Build.VERSION_CODES;
70a0a87e810870b696239f0371d33de924f84cb431Charles Heimport android.os.Bundle;
714d03abcd49af490dba3850d341b955dd72f24959Robin Leeimport android.os.INetworkManagementService;
724d03abcd49af490dba3850d341b955dd72f24959Robin Leeimport android.os.Looper;
73507754a81e0b9d871e59fe9621c2a5d57befff90Chalard Jeanimport android.os.SystemClock;
744d03abcd49af490dba3850d341b955dd72f24959Robin Leeimport android.os.UserHandle;
754d03abcd49af490dba3850d341b955dd72f24959Robin Leeimport android.os.UserManager;
764a0c5d7ef7144280fe8a209a871bbd4ef90d6368Hugo Benichiimport android.support.test.filters.SmallTest;
7772f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkeyimport android.support.test.runner.AndroidJUnit4;
784d03abcd49af490dba3850d341b955dd72f24959Robin Leeimport android.util.ArrayMap;
794d03abcd49af490dba3850d341b955dd72f24959Robin Leeimport android.util.ArraySet;
804d03abcd49af490dba3850d341b955dd72f24959Robin Lee
81c17f50f83d3e35f338095df6065426f2f304a1dcCharles Heimport com.android.internal.R;
82c3736bc10da63d6a351d3f8e7781ff1d67ecc9a6Robin Leeimport com.android.internal.net.VpnConfig;
83c3736bc10da63d6a351d3f8e7781ff1d67ecc9a6Robin Lee
844a0c5d7ef7144280fe8a209a871bbd4ef90d6368Hugo Benichiimport org.junit.Before;
854a0c5d7ef7144280fe8a209a871bbd4ef90d6368Hugo Benichiimport org.junit.Test;
8672f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkeyimport org.junit.runner.RunWith;
87b8c2a2b85052479cb6affe2d4a8240e78198e2d5Robin Leeimport org.mockito.Answers;
88de7f7d195eec64802b7b6eee819c699f1a7d6951Tony Makimport org.mockito.InOrder;
894d03abcd49af490dba3850d341b955dd72f24959Robin Leeimport org.mockito.Mock;
904d03abcd49af490dba3850d341b955dd72f24959Robin Leeimport org.mockito.MockitoAnnotations;
914d03abcd49af490dba3850d341b955dd72f24959Robin Lee
92507754a81e0b9d871e59fe9621c2a5d57befff90Chalard Jeanimport java.net.Inet4Address;
93507754a81e0b9d871e59fe9621c2a5d57befff90Chalard Jeanimport java.net.UnknownHostException;
94a0a87e810870b696239f0371d33de924f84cb431Charles Heimport java.util.ArrayList;
95a0a87e810870b696239f0371d33de924f84cb431Charles Heimport java.util.Arrays;
96a0a87e810870b696239f0371d33de924f84cb431Charles Heimport java.util.Collections;
9772f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkeyimport java.util.HashMap;
98a0a87e810870b696239f0371d33de924f84cb431Charles Heimport java.util.Map;
99a0a87e810870b696239f0371d33de924f84cb431Charles Heimport java.util.Set;
100adbf1d029b753fabc2a7a5ad3b22d3d416cecdd9Chalard Jeanimport java.util.stream.Collectors;
101adbf1d029b753fabc2a7a5ad3b22d3d416cecdd9Chalard Jeanimport java.util.stream.Stream;
1024a0c5d7ef7144280fe8a209a871bbd4ef90d6368Hugo Benichi
1034d03abcd49af490dba3850d341b955dd72f24959Robin Lee/**
1044d03abcd49af490dba3850d341b955dd72f24959Robin Lee * Tests for {@link Vpn}.
1054d03abcd49af490dba3850d341b955dd72f24959Robin Lee *
1064d03abcd49af490dba3850d341b955dd72f24959Robin Lee * Build, install and run with:
1074a0c5d7ef7144280fe8a209a871bbd4ef90d6368Hugo Benichi *  runtest frameworks-net -c com.android.server.connectivity.VpnTest
1084d03abcd49af490dba3850d341b955dd72f24959Robin Lee */
1094a0c5d7ef7144280fe8a209a871bbd4ef90d6368Hugo Benichi@RunWith(AndroidJUnit4.class)
1104a0c5d7ef7144280fe8a209a871bbd4ef90d6368Hugo Benichi@SmallTest
1114a0c5d7ef7144280fe8a209a871bbd4ef90d6368Hugo Benichipublic class VpnTest {
1124d03abcd49af490dba3850d341b955dd72f24959Robin Lee    private static final String TAG = "VpnTest";
1134d03abcd49af490dba3850d341b955dd72f24959Robin Lee
1144d03abcd49af490dba3850d341b955dd72f24959Robin Lee    // Mock users
1154d03abcd49af490dba3850d341b955dd72f24959Robin Lee    static final UserInfo primaryUser = new UserInfo(27, "Primary", FLAG_ADMIN | FLAG_PRIMARY);
1164d03abcd49af490dba3850d341b955dd72f24959Robin Lee    static final UserInfo secondaryUser = new UserInfo(15, "Secondary", FLAG_ADMIN);
1174d03abcd49af490dba3850d341b955dd72f24959Robin Lee    static final UserInfo restrictedProfileA = new UserInfo(40, "RestrictedA", FLAG_RESTRICTED);
1184d03abcd49af490dba3850d341b955dd72f24959Robin Lee    static final UserInfo restrictedProfileB = new UserInfo(42, "RestrictedB", FLAG_RESTRICTED);
1194d03abcd49af490dba3850d341b955dd72f24959Robin Lee    static final UserInfo managedProfileA = new UserInfo(45, "ManagedA", FLAG_MANAGED_PROFILE);
1204d03abcd49af490dba3850d341b955dd72f24959Robin Lee    static {
1214d03abcd49af490dba3850d341b955dd72f24959Robin Lee        restrictedProfileA.restrictedProfileParentId = primaryUser.id;
1224d03abcd49af490dba3850d341b955dd72f24959Robin Lee        restrictedProfileB.restrictedProfileParentId = secondaryUser.id;
1234d03abcd49af490dba3850d341b955dd72f24959Robin Lee        managedProfileA.profileGroupId = primaryUser.id;
1244d03abcd49af490dba3850d341b955dd72f24959Robin Lee    }
1254d03abcd49af490dba3850d341b955dd72f24959Robin Lee
12617e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee    /**
12717e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee     * Names and UIDs for some fake packages. Important points:
12817e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee     *  - UID is ordered increasing.
12917e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee     *  - One pair of packages have consecutive UIDs.
13017e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee     */
13117e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee    static final String[] PKGS = {"com.example", "org.example", "net.example", "web.vpn"};
13217e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee    static final int[] PKG_UIDS = {66, 77, 78, 400};
13317e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee
13417e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee    // Mock packages
13517e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee    static final Map<String, Integer> mPackages = new ArrayMap<>();
13617e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee    static {
13717e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee        for (int i = 0; i < PKGS.length; i++) {
13817e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee            mPackages.put(PKGS[i], PKG_UIDS[i]);
13917e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee        }
14017e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee    }
14117e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee
142b8c2a2b85052479cb6affe2d4a8240e78198e2d5Robin Lee    @Mock(answer = Answers.RETURNS_DEEP_STUBS) private Context mContext;
1434d03abcd49af490dba3850d341b955dd72f24959Robin Lee    @Mock private UserManager mUserManager;
1444d03abcd49af490dba3850d341b955dd72f24959Robin Lee    @Mock private PackageManager mPackageManager;
1454d03abcd49af490dba3850d341b955dd72f24959Robin Lee    @Mock private INetworkManagementService mNetService;
14617e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee    @Mock private AppOpsManager mAppOps;
147de7f7d195eec64802b7b6eee819c699f1a7d6951Tony Mak    @Mock private NotificationManager mNotificationManager;
148b8c2a2b85052479cb6affe2d4a8240e78198e2d5Robin Lee    @Mock private Vpn.SystemServices mSystemServices;
14972f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkey    @Mock private ConnectivityManager mConnectivityManager;
1504d03abcd49af490dba3850d341b955dd72f24959Robin Lee
1514a0c5d7ef7144280fe8a209a871bbd4ef90d6368Hugo Benichi    @Before
1524d03abcd49af490dba3850d341b955dd72f24959Robin Lee    public void setUp() throws Exception {
1534d03abcd49af490dba3850d341b955dd72f24959Robin Lee        MockitoAnnotations.initMocks(this);
154c3736bc10da63d6a351d3f8e7781ff1d67ecc9a6Robin Lee
1554d03abcd49af490dba3850d341b955dd72f24959Robin Lee        when(mContext.getPackageManager()).thenReturn(mPackageManager);
15617e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee        setMockedPackages(mPackages);
157c3736bc10da63d6a351d3f8e7781ff1d67ecc9a6Robin Lee
158de7f7d195eec64802b7b6eee819c699f1a7d6951Tony Mak        when(mContext.getPackageName()).thenReturn(Vpn.class.getPackage().getName());
1594d03abcd49af490dba3850d341b955dd72f24959Robin Lee        when(mContext.getSystemService(eq(Context.USER_SERVICE))).thenReturn(mUserManager);
16017e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee        when(mContext.getSystemService(eq(Context.APP_OPS_SERVICE))).thenReturn(mAppOps);
161de7f7d195eec64802b7b6eee819c699f1a7d6951Tony Mak        when(mContext.getSystemService(eq(Context.NOTIFICATION_SERVICE)))
162de7f7d195eec64802b7b6eee819c699f1a7d6951Tony Mak                .thenReturn(mNotificationManager);
16372f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkey        when(mContext.getSystemService(eq(Context.CONNECTIVITY_SERVICE)))
16472f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkey                .thenReturn(mConnectivityManager);
165c17f50f83d3e35f338095df6065426f2f304a1dcCharles He        when(mContext.getString(R.string.config_customVpnAlwaysOnDisconnectedDialogComponent))
166c17f50f83d3e35f338095df6065426f2f304a1dcCharles He                .thenReturn(Resources.getSystem().getString(
167c17f50f83d3e35f338095df6065426f2f304a1dcCharles He                        R.string.config_customVpnAlwaysOnDisconnectedDialogComponent));
168b8c2a2b85052479cb6affe2d4a8240e78198e2d5Robin Lee
169b8c2a2b85052479cb6affe2d4a8240e78198e2d5Robin Lee        // Used by {@link Notification.Builder}
170b8c2a2b85052479cb6affe2d4a8240e78198e2d5Robin Lee        ApplicationInfo applicationInfo = new ApplicationInfo();
171a0a87e810870b696239f0371d33de924f84cb431Charles He        applicationInfo.targetSdkVersion = VERSION_CODES.CUR_DEVELOPMENT;
172b8c2a2b85052479cb6affe2d4a8240e78198e2d5Robin Lee        when(mContext.getApplicationInfo()).thenReturn(applicationInfo);
173b8c2a2b85052479cb6affe2d4a8240e78198e2d5Robin Lee
1744d03abcd49af490dba3850d341b955dd72f24959Robin Lee        doNothing().when(mNetService).registerObserver(any());
1754d03abcd49af490dba3850d341b955dd72f24959Robin Lee    }
1764d03abcd49af490dba3850d341b955dd72f24959Robin Lee
1774a0c5d7ef7144280fe8a209a871bbd4ef90d6368Hugo Benichi    @Test
1784d03abcd49af490dba3850d341b955dd72f24959Robin Lee    public void testRestrictedProfilesAreAddedToVpn() {
1794d03abcd49af490dba3850d341b955dd72f24959Robin Lee        setMockedUsers(primaryUser, secondaryUser, restrictedProfileA, restrictedProfileB);
1804d03abcd49af490dba3850d341b955dd72f24959Robin Lee
181b8c2a2b85052479cb6affe2d4a8240e78198e2d5Robin Lee        final Vpn vpn = createVpn(primaryUser.id);
1824d03abcd49af490dba3850d341b955dd72f24959Robin Lee        final Set<UidRange> ranges = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id,
1834d03abcd49af490dba3850d341b955dd72f24959Robin Lee                null, null);
1844d03abcd49af490dba3850d341b955dd72f24959Robin Lee
1854d03abcd49af490dba3850d341b955dd72f24959Robin Lee        assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] {
1864d03abcd49af490dba3850d341b955dd72f24959Robin Lee            UidRange.createForUser(primaryUser.id),
1874d03abcd49af490dba3850d341b955dd72f24959Robin Lee            UidRange.createForUser(restrictedProfileA.id)
1884d03abcd49af490dba3850d341b955dd72f24959Robin Lee        })), ranges);
1894d03abcd49af490dba3850d341b955dd72f24959Robin Lee    }
1904d03abcd49af490dba3850d341b955dd72f24959Robin Lee
1914a0c5d7ef7144280fe8a209a871bbd4ef90d6368Hugo Benichi    @Test
1924d03abcd49af490dba3850d341b955dd72f24959Robin Lee    public void testManagedProfilesAreNotAddedToVpn() {
1934d03abcd49af490dba3850d341b955dd72f24959Robin Lee        setMockedUsers(primaryUser, managedProfileA);
1944d03abcd49af490dba3850d341b955dd72f24959Robin Lee
195b8c2a2b85052479cb6affe2d4a8240e78198e2d5Robin Lee        final Vpn vpn = createVpn(primaryUser.id);
1964d03abcd49af490dba3850d341b955dd72f24959Robin Lee        final Set<UidRange> ranges = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id,
1974d03abcd49af490dba3850d341b955dd72f24959Robin Lee                null, null);
1984d03abcd49af490dba3850d341b955dd72f24959Robin Lee
1994d03abcd49af490dba3850d341b955dd72f24959Robin Lee        assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] {
2004d03abcd49af490dba3850d341b955dd72f24959Robin Lee            UidRange.createForUser(primaryUser.id)
2014d03abcd49af490dba3850d341b955dd72f24959Robin Lee        })), ranges);
2024d03abcd49af490dba3850d341b955dd72f24959Robin Lee    }
2034d03abcd49af490dba3850d341b955dd72f24959Robin Lee
2044a0c5d7ef7144280fe8a209a871bbd4ef90d6368Hugo Benichi    @Test
2054d03abcd49af490dba3850d341b955dd72f24959Robin Lee    public void testAddUserToVpnOnlyAddsOneUser() {
2064d03abcd49af490dba3850d341b955dd72f24959Robin Lee        setMockedUsers(primaryUser, restrictedProfileA, managedProfileA);
2074d03abcd49af490dba3850d341b955dd72f24959Robin Lee
208b8c2a2b85052479cb6affe2d4a8240e78198e2d5Robin Lee        final Vpn vpn = createVpn(primaryUser.id);
2094d03abcd49af490dba3850d341b955dd72f24959Robin Lee        final Set<UidRange> ranges = new ArraySet<>();
2104d03abcd49af490dba3850d341b955dd72f24959Robin Lee        vpn.addUserToRanges(ranges, primaryUser.id, null, null);
2114d03abcd49af490dba3850d341b955dd72f24959Robin Lee
2124d03abcd49af490dba3850d341b955dd72f24959Robin Lee        assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] {
2134d03abcd49af490dba3850d341b955dd72f24959Robin Lee            UidRange.createForUser(primaryUser.id)
2144d03abcd49af490dba3850d341b955dd72f24959Robin Lee        })), ranges);
2154d03abcd49af490dba3850d341b955dd72f24959Robin Lee    }
2164d03abcd49af490dba3850d341b955dd72f24959Robin Lee
2174a0c5d7ef7144280fe8a209a871bbd4ef90d6368Hugo Benichi    @Test
2184d03abcd49af490dba3850d341b955dd72f24959Robin Lee    public void testUidWhiteAndBlacklist() throws Exception {
219b8c2a2b85052479cb6affe2d4a8240e78198e2d5Robin Lee        final Vpn vpn = createVpn(primaryUser.id);
2204d03abcd49af490dba3850d341b955dd72f24959Robin Lee        final UidRange user = UidRange.createForUser(primaryUser.id);
22117e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee        final String[] packages = {PKGS[0], PKGS[1], PKGS[2]};
2224d03abcd49af490dba3850d341b955dd72f24959Robin Lee
2234d03abcd49af490dba3850d341b955dd72f24959Robin Lee        // Whitelist
2244d03abcd49af490dba3850d341b955dd72f24959Robin Lee        final Set<UidRange> allow = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id,
22517e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee                Arrays.asList(packages), null);
2264d03abcd49af490dba3850d341b955dd72f24959Robin Lee        assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] {
22717e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee            new UidRange(user.start + PKG_UIDS[0], user.start + PKG_UIDS[0]),
22817e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee            new UidRange(user.start + PKG_UIDS[1], user.start + PKG_UIDS[2])
2294d03abcd49af490dba3850d341b955dd72f24959Robin Lee        })), allow);
2304d03abcd49af490dba3850d341b955dd72f24959Robin Lee
2314d03abcd49af490dba3850d341b955dd72f24959Robin Lee        // Blacklist
2324d03abcd49af490dba3850d341b955dd72f24959Robin Lee        final Set<UidRange> disallow = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id,
23317e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee                null, Arrays.asList(packages));
2344d03abcd49af490dba3850d341b955dd72f24959Robin Lee        assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] {
23517e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee            new UidRange(user.start, user.start + PKG_UIDS[0] - 1),
23617e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee            new UidRange(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[1] - 1),
23717e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee            /* Empty range between UIDS[1] and UIDS[2], should be excluded, */
23817e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee            new UidRange(user.start + PKG_UIDS[2] + 1, user.stop)
2394d03abcd49af490dba3850d341b955dd72f24959Robin Lee        })), disallow);
2404d03abcd49af490dba3850d341b955dd72f24959Robin Lee    }
2414d03abcd49af490dba3850d341b955dd72f24959Robin Lee
2424a0c5d7ef7144280fe8a209a871bbd4ef90d6368Hugo Benichi    @Test
24317e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee    public void testLockdownChangingPackage() throws Exception {
244b8c2a2b85052479cb6affe2d4a8240e78198e2d5Robin Lee        final Vpn vpn = createVpn(primaryUser.id);
24517e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee        final UidRange user = UidRange.createForUser(primaryUser.id);
24617e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee
24717e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee        // Default state.
248de7f7d195eec64802b7b6eee819c699f1a7d6951Tony Mak        assertUnblocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[1], user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]);
24917e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee
25017e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee        // Set always-on without lockdown.
25117e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee        assertTrue(vpn.setAlwaysOnPackage(PKGS[1], false));
252de7f7d195eec64802b7b6eee819c699f1a7d6951Tony Mak        assertUnblocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[1], user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]);
25317e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee
25417e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee        // Set always-on with lockdown.
25517e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee        assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true));
25617e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee        verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
25717e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee            new UidRange(user.start, user.start + PKG_UIDS[1] - 1),
25817e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee            new UidRange(user.start + PKG_UIDS[1] + 1, user.stop)
25917e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee        }));
260de7f7d195eec64802b7b6eee819c699f1a7d6951Tony Mak        assertBlocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]);
261de7f7d195eec64802b7b6eee819c699f1a7d6951Tony Mak        assertUnblocked(vpn, user.start + PKG_UIDS[1]);
26217e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee
26317e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee        // Switch to another app.
26417e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee        assertTrue(vpn.setAlwaysOnPackage(PKGS[3], true));
26517e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee        verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[] {
26617e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee            new UidRange(user.start, user.start + PKG_UIDS[1] - 1),
26717e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee            new UidRange(user.start + PKG_UIDS[1] + 1, user.stop)
26817e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee        }));
26917e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee        verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
27017e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee            new UidRange(user.start, user.start + PKG_UIDS[3] - 1),
27117e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee            new UidRange(user.start + PKG_UIDS[3] + 1, user.stop)
27217e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee        }));
273de7f7d195eec64802b7b6eee819c699f1a7d6951Tony Mak        assertBlocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[1], user.start + PKG_UIDS[2]);
274de7f7d195eec64802b7b6eee819c699f1a7d6951Tony Mak        assertUnblocked(vpn, user.start + PKG_UIDS[3]);
27517e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee    }
27617e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee
2774a0c5d7ef7144280fe8a209a871bbd4ef90d6368Hugo Benichi    @Test
27817e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee    public void testLockdownAddingAProfile() throws Exception {
279b8c2a2b85052479cb6affe2d4a8240e78198e2d5Robin Lee        final Vpn vpn = createVpn(primaryUser.id);
28017e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee        setMockedUsers(primaryUser);
28117e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee
28217e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee        // Make a copy of the restricted profile, as we're going to mark it deleted halfway through.
28317e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee        final UserInfo tempProfile = new UserInfo(restrictedProfileA.id, restrictedProfileA.name,
28417e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee                restrictedProfileA.flags);
28517e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee        tempProfile.restrictedProfileParentId = primaryUser.id;
28617e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee
28717e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee        final UidRange user = UidRange.createForUser(primaryUser.id);
28817e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee        final UidRange profile = UidRange.createForUser(tempProfile.id);
28917e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee
29017e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee        // Set lockdown.
29117e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee        assertTrue(vpn.setAlwaysOnPackage(PKGS[3], true));
29217e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee        verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
29317e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee            new UidRange(user.start, user.start + PKG_UIDS[3] - 1),
29417e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee            new UidRange(user.start + PKG_UIDS[3] + 1, user.stop)
29517e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee        }));
29617e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee
29717e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee        // Verify restricted user isn't affected at first.
298de7f7d195eec64802b7b6eee819c699f1a7d6951Tony Mak        assertUnblocked(vpn, profile.start + PKG_UIDS[0]);
29917e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee
30017e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee        // Add the restricted user.
30117e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee        setMockedUsers(primaryUser, tempProfile);
30217e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee        vpn.onUserAdded(tempProfile.id);
30317e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee        verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
30417e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee            new UidRange(profile.start, profile.start + PKG_UIDS[3] - 1),
30517e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee            new UidRange(profile.start + PKG_UIDS[3] + 1, profile.stop)
30617e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee        }));
30717e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee
30817e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee        // Remove the restricted user.
30917e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee        tempProfile.partial = true;
31017e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee        vpn.onUserRemoved(tempProfile.id);
31117e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee        verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[] {
31217e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee            new UidRange(profile.start, profile.start + PKG_UIDS[3] - 1),
31317e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee            new UidRange(profile.start + PKG_UIDS[3] + 1, profile.stop)
31417e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee        }));
31517e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee    }
31617e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee
3174a0c5d7ef7144280fe8a209a871bbd4ef90d6368Hugo Benichi    @Test
318c3736bc10da63d6a351d3f8e7781ff1d67ecc9a6Robin Lee    public void testLockdownRuleRepeatability() throws Exception {
319c3736bc10da63d6a351d3f8e7781ff1d67ecc9a6Robin Lee        final Vpn vpn = createVpn(primaryUser.id);
320c3736bc10da63d6a351d3f8e7781ff1d67ecc9a6Robin Lee
321c3736bc10da63d6a351d3f8e7781ff1d67ecc9a6Robin Lee        // Given legacy lockdown is already enabled,
322c3736bc10da63d6a351d3f8e7781ff1d67ecc9a6Robin Lee        vpn.setLockdown(true);
323c3736bc10da63d6a351d3f8e7781ff1d67ecc9a6Robin Lee        verify(mNetService, times(1)).setAllowOnlyVpnForUids(
324c3736bc10da63d6a351d3f8e7781ff1d67ecc9a6Robin Lee                eq(true), aryEq(new UidRange[] {UidRange.createForUser(primaryUser.id)}));
325c3736bc10da63d6a351d3f8e7781ff1d67ecc9a6Robin Lee
326c3736bc10da63d6a351d3f8e7781ff1d67ecc9a6Robin Lee        // Enabling legacy lockdown twice should do nothing.
327c3736bc10da63d6a351d3f8e7781ff1d67ecc9a6Robin Lee        vpn.setLockdown(true);
328c3736bc10da63d6a351d3f8e7781ff1d67ecc9a6Robin Lee        verify(mNetService, times(1)).setAllowOnlyVpnForUids(anyBoolean(), any(UidRange[].class));
329c3736bc10da63d6a351d3f8e7781ff1d67ecc9a6Robin Lee
330c3736bc10da63d6a351d3f8e7781ff1d67ecc9a6Robin Lee        // And disabling should remove the rules exactly once.
331c3736bc10da63d6a351d3f8e7781ff1d67ecc9a6Robin Lee        vpn.setLockdown(false);
332c3736bc10da63d6a351d3f8e7781ff1d67ecc9a6Robin Lee        verify(mNetService, times(1)).setAllowOnlyVpnForUids(
333c3736bc10da63d6a351d3f8e7781ff1d67ecc9a6Robin Lee                eq(false), aryEq(new UidRange[] {UidRange.createForUser(primaryUser.id)}));
334c3736bc10da63d6a351d3f8e7781ff1d67ecc9a6Robin Lee
335c3736bc10da63d6a351d3f8e7781ff1d67ecc9a6Robin Lee        // Removing the lockdown again should have no effect.
336c3736bc10da63d6a351d3f8e7781ff1d67ecc9a6Robin Lee        vpn.setLockdown(false);
337c3736bc10da63d6a351d3f8e7781ff1d67ecc9a6Robin Lee        verify(mNetService, times(2)).setAllowOnlyVpnForUids(anyBoolean(), any(UidRange[].class));
338c3736bc10da63d6a351d3f8e7781ff1d67ecc9a6Robin Lee    }
339c3736bc10da63d6a351d3f8e7781ff1d67ecc9a6Robin Lee
3404a0c5d7ef7144280fe8a209a871bbd4ef90d6368Hugo Benichi    @Test
341c3736bc10da63d6a351d3f8e7781ff1d67ecc9a6Robin Lee    public void testLockdownRuleReversibility() throws Exception {
342c3736bc10da63d6a351d3f8e7781ff1d67ecc9a6Robin Lee        final Vpn vpn = createVpn(primaryUser.id);
343c3736bc10da63d6a351d3f8e7781ff1d67ecc9a6Robin Lee
344c3736bc10da63d6a351d3f8e7781ff1d67ecc9a6Robin Lee        final UidRange[] entireUser = {
345c3736bc10da63d6a351d3f8e7781ff1d67ecc9a6Robin Lee            UidRange.createForUser(primaryUser.id)
346c3736bc10da63d6a351d3f8e7781ff1d67ecc9a6Robin Lee        };
347c3736bc10da63d6a351d3f8e7781ff1d67ecc9a6Robin Lee        final UidRange[] exceptPkg0 = {
348c3736bc10da63d6a351d3f8e7781ff1d67ecc9a6Robin Lee            new UidRange(entireUser[0].start, entireUser[0].start + PKG_UIDS[0] - 1),
349c3736bc10da63d6a351d3f8e7781ff1d67ecc9a6Robin Lee            new UidRange(entireUser[0].start + PKG_UIDS[0] + 1, entireUser[0].stop)
350c3736bc10da63d6a351d3f8e7781ff1d67ecc9a6Robin Lee        };
351c3736bc10da63d6a351d3f8e7781ff1d67ecc9a6Robin Lee
352c3736bc10da63d6a351d3f8e7781ff1d67ecc9a6Robin Lee        final InOrder order = inOrder(mNetService);
353c3736bc10da63d6a351d3f8e7781ff1d67ecc9a6Robin Lee
354c3736bc10da63d6a351d3f8e7781ff1d67ecc9a6Robin Lee        // Given lockdown is enabled with no package (legacy VPN),
355c3736bc10da63d6a351d3f8e7781ff1d67ecc9a6Robin Lee        vpn.setLockdown(true);
356c3736bc10da63d6a351d3f8e7781ff1d67ecc9a6Robin Lee        order.verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(entireUser));
357c3736bc10da63d6a351d3f8e7781ff1d67ecc9a6Robin Lee
358c3736bc10da63d6a351d3f8e7781ff1d67ecc9a6Robin Lee        // When a new VPN package is set the rules should change to cover that package.
359c3736bc10da63d6a351d3f8e7781ff1d67ecc9a6Robin Lee        vpn.prepare(null, PKGS[0]);
360c3736bc10da63d6a351d3f8e7781ff1d67ecc9a6Robin Lee        order.verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(entireUser));
361c3736bc10da63d6a351d3f8e7781ff1d67ecc9a6Robin Lee        order.verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(exceptPkg0));
362c3736bc10da63d6a351d3f8e7781ff1d67ecc9a6Robin Lee
363c3736bc10da63d6a351d3f8e7781ff1d67ecc9a6Robin Lee        // When that VPN package is unset, everything should be undone again in reverse.
364c3736bc10da63d6a351d3f8e7781ff1d67ecc9a6Robin Lee        vpn.prepare(null, VpnConfig.LEGACY_VPN);
365c3736bc10da63d6a351d3f8e7781ff1d67ecc9a6Robin Lee        order.verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(exceptPkg0));
366c3736bc10da63d6a351d3f8e7781ff1d67ecc9a6Robin Lee        order.verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(entireUser));
367c3736bc10da63d6a351d3f8e7781ff1d67ecc9a6Robin Lee    }
368c3736bc10da63d6a351d3f8e7781ff1d67ecc9a6Robin Lee
3694a0c5d7ef7144280fe8a209a871bbd4ef90d6368Hugo Benichi    @Test
370a0a87e810870b696239f0371d33de924f84cb431Charles He    public void testIsAlwaysOnPackageSupported() throws Exception {
371a0a87e810870b696239f0371d33de924f84cb431Charles He        final Vpn vpn = createVpn(primaryUser.id);
372a0a87e810870b696239f0371d33de924f84cb431Charles He
373a0a87e810870b696239f0371d33de924f84cb431Charles He        ApplicationInfo appInfo = new ApplicationInfo();
374a0a87e810870b696239f0371d33de924f84cb431Charles He        when(mPackageManager.getApplicationInfoAsUser(eq(PKGS[0]), anyInt(), eq(primaryUser.id)))
375a0a87e810870b696239f0371d33de924f84cb431Charles He                .thenReturn(appInfo);
376a0a87e810870b696239f0371d33de924f84cb431Charles He
377a0a87e810870b696239f0371d33de924f84cb431Charles He        ServiceInfo svcInfo = new ServiceInfo();
378a0a87e810870b696239f0371d33de924f84cb431Charles He        ResolveInfo resInfo = new ResolveInfo();
379a0a87e810870b696239f0371d33de924f84cb431Charles He        resInfo.serviceInfo = svcInfo;
380a0a87e810870b696239f0371d33de924f84cb431Charles He        when(mPackageManager.queryIntentServicesAsUser(any(), eq(PackageManager.GET_META_DATA),
381a0a87e810870b696239f0371d33de924f84cb431Charles He                eq(primaryUser.id)))
382a0a87e810870b696239f0371d33de924f84cb431Charles He                .thenReturn(Collections.singletonList(resInfo));
383a0a87e810870b696239f0371d33de924f84cb431Charles He
384a0a87e810870b696239f0371d33de924f84cb431Charles He        // null package name should return false
385a0a87e810870b696239f0371d33de924f84cb431Charles He        assertFalse(vpn.isAlwaysOnPackageSupported(null));
386a0a87e810870b696239f0371d33de924f84cb431Charles He
387a0a87e810870b696239f0371d33de924f84cb431Charles He        // Pre-N apps are not supported
388a0a87e810870b696239f0371d33de924f84cb431Charles He        appInfo.targetSdkVersion = VERSION_CODES.M;
389a0a87e810870b696239f0371d33de924f84cb431Charles He        assertFalse(vpn.isAlwaysOnPackageSupported(PKGS[0]));
390a0a87e810870b696239f0371d33de924f84cb431Charles He
391a0a87e810870b696239f0371d33de924f84cb431Charles He        // N+ apps are supported by default
392a0a87e810870b696239f0371d33de924f84cb431Charles He        appInfo.targetSdkVersion = VERSION_CODES.N;
393a0a87e810870b696239f0371d33de924f84cb431Charles He        assertTrue(vpn.isAlwaysOnPackageSupported(PKGS[0]));
394a0a87e810870b696239f0371d33de924f84cb431Charles He
395a0a87e810870b696239f0371d33de924f84cb431Charles He        // Apps that opt out explicitly are not supported
396a0a87e810870b696239f0371d33de924f84cb431Charles He        appInfo.targetSdkVersion = VERSION_CODES.CUR_DEVELOPMENT;
397a0a87e810870b696239f0371d33de924f84cb431Charles He        Bundle metaData = new Bundle();
3985da5ae3b96769735a2dc5abe265101df545be828Charles He        metaData.putBoolean(VpnService.SERVICE_META_DATA_SUPPORTS_ALWAYS_ON, false);
399a0a87e810870b696239f0371d33de924f84cb431Charles He        svcInfo.metaData = metaData;
400a0a87e810870b696239f0371d33de924f84cb431Charles He        assertFalse(vpn.isAlwaysOnPackageSupported(PKGS[0]));
401a0a87e810870b696239f0371d33de924f84cb431Charles He    }
402a0a87e810870b696239f0371d33de924f84cb431Charles He
4034a0c5d7ef7144280fe8a209a871bbd4ef90d6368Hugo Benichi    @Test
404de7f7d195eec64802b7b6eee819c699f1a7d6951Tony Mak    public void testNotificationShownForAlwaysOnApp() {
405b8c2a2b85052479cb6affe2d4a8240e78198e2d5Robin Lee        final UserHandle userHandle = UserHandle.of(primaryUser.id);
406b8c2a2b85052479cb6affe2d4a8240e78198e2d5Robin Lee        final Vpn vpn = createVpn(primaryUser.id);
407de7f7d195eec64802b7b6eee819c699f1a7d6951Tony Mak        setMockedUsers(primaryUser);
408de7f7d195eec64802b7b6eee819c699f1a7d6951Tony Mak
409b8c2a2b85052479cb6affe2d4a8240e78198e2d5Robin Lee        final InOrder order = inOrder(mNotificationManager);
410b8c2a2b85052479cb6affe2d4a8240e78198e2d5Robin Lee
411de7f7d195eec64802b7b6eee819c699f1a7d6951Tony Mak        // Don't show a notification for regular disconnected states.
412de7f7d195eec64802b7b6eee819c699f1a7d6951Tony Mak        vpn.updateState(DetailedState.DISCONNECTED, TAG);
413b8c2a2b85052479cb6affe2d4a8240e78198e2d5Robin Lee        order.verify(mNotificationManager, atLeastOnce())
414b8c2a2b85052479cb6affe2d4a8240e78198e2d5Robin Lee                .cancelAsUser(anyString(), anyInt(), eq(userHandle));
415de7f7d195eec64802b7b6eee819c699f1a7d6951Tony Mak
416de7f7d195eec64802b7b6eee819c699f1a7d6951Tony Mak        // Start showing a notification for disconnected once always-on.
417de7f7d195eec64802b7b6eee819c699f1a7d6951Tony Mak        vpn.setAlwaysOnPackage(PKGS[0], false);
418b8c2a2b85052479cb6affe2d4a8240e78198e2d5Robin Lee        order.verify(mNotificationManager)
419b8c2a2b85052479cb6affe2d4a8240e78198e2d5Robin Lee                .notifyAsUser(anyString(), anyInt(), any(), eq(userHandle));
420de7f7d195eec64802b7b6eee819c699f1a7d6951Tony Mak
421de7f7d195eec64802b7b6eee819c699f1a7d6951Tony Mak        // Stop showing the notification once connected.
422de7f7d195eec64802b7b6eee819c699f1a7d6951Tony Mak        vpn.updateState(DetailedState.CONNECTED, TAG);
423b8c2a2b85052479cb6affe2d4a8240e78198e2d5Robin Lee        order.verify(mNotificationManager).cancelAsUser(anyString(), anyInt(), eq(userHandle));
424de7f7d195eec64802b7b6eee819c699f1a7d6951Tony Mak
425de7f7d195eec64802b7b6eee819c699f1a7d6951Tony Mak        // Show the notification if we disconnect again.
426de7f7d195eec64802b7b6eee819c699f1a7d6951Tony Mak        vpn.updateState(DetailedState.DISCONNECTED, TAG);
427b8c2a2b85052479cb6affe2d4a8240e78198e2d5Robin Lee        order.verify(mNotificationManager)
428b8c2a2b85052479cb6affe2d4a8240e78198e2d5Robin Lee                .notifyAsUser(anyString(), anyInt(), any(), eq(userHandle));
429de7f7d195eec64802b7b6eee819c699f1a7d6951Tony Mak
430de7f7d195eec64802b7b6eee819c699f1a7d6951Tony Mak        // Notification should be cleared after unsetting always-on package.
431de7f7d195eec64802b7b6eee819c699f1a7d6951Tony Mak        vpn.setAlwaysOnPackage(null, false);
432b8c2a2b85052479cb6affe2d4a8240e78198e2d5Robin Lee        order.verify(mNotificationManager).cancelAsUser(anyString(), anyInt(), eq(userHandle));
433de7f7d195eec64802b7b6eee819c699f1a7d6951Tony Mak    }
434de7f7d195eec64802b7b6eee819c699f1a7d6951Tony Mak
43572f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkey    @Test
43672f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkey    public void testCapabilities() {
43772f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkey        final Vpn vpn = createVpn(primaryUser.id);
43872f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkey        setMockedUsers(primaryUser);
43972f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkey
44072f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkey        final Network mobile = new Network(1);
44172f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkey        final Network wifi = new Network(2);
44272f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkey
44372f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkey        final Map<Network, NetworkCapabilities> networks = new HashMap<>();
44472f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkey        networks.put(mobile, new NetworkCapabilities()
44572f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkey                .addTransportType(TRANSPORT_CELLULAR)
44672f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkey                .addCapability(NET_CAPABILITY_INTERNET)
44772f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkey                .addCapability(NET_CAPABILITY_NOT_METERED)
4489b2a10f55d1659895e20ec0b88dd023ae18770ebJeff Sharkey                .addCapability(NET_CAPABILITY_NOT_CONGESTED)
44972f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkey                .setLinkDownstreamBandwidthKbps(10));
45072f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkey        networks.put(wifi, new NetworkCapabilities()
45172f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkey                .addTransportType(TRANSPORT_WIFI)
45272f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkey                .addCapability(NET_CAPABILITY_INTERNET)
45372f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkey                .addCapability(NET_CAPABILITY_NOT_ROAMING)
4549b2a10f55d1659895e20ec0b88dd023ae18770ebJeff Sharkey                .addCapability(NET_CAPABILITY_NOT_CONGESTED)
45572f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkey                .setLinkUpstreamBandwidthKbps(20));
45672f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkey        setMockedNetworks(networks);
45772f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkey
45872f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkey        final NetworkCapabilities caps = new NetworkCapabilities();
45972f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkey
46072f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkey        Vpn.updateCapabilities(mConnectivityManager, new Network[] { }, caps);
46172f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkey        assertTrue(caps.hasTransport(TRANSPORT_VPN));
46272f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkey        assertFalse(caps.hasTransport(TRANSPORT_CELLULAR));
46372f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkey        assertFalse(caps.hasTransport(TRANSPORT_WIFI));
46472f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkey        assertEquals(LINK_BANDWIDTH_UNSPECIFIED, caps.getLinkDownstreamBandwidthKbps());
46572f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkey        assertEquals(LINK_BANDWIDTH_UNSPECIFIED, caps.getLinkUpstreamBandwidthKbps());
46672f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkey        assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_METERED));
46772f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkey        assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING));
4689b2a10f55d1659895e20ec0b88dd023ae18770ebJeff Sharkey        assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED));
46972f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkey
47072f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkey        Vpn.updateCapabilities(mConnectivityManager, new Network[] { mobile }, caps);
47172f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkey        assertTrue(caps.hasTransport(TRANSPORT_VPN));
47272f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkey        assertTrue(caps.hasTransport(TRANSPORT_CELLULAR));
47372f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkey        assertFalse(caps.hasTransport(TRANSPORT_WIFI));
47472f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkey        assertEquals(10, caps.getLinkDownstreamBandwidthKbps());
47572f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkey        assertEquals(LINK_BANDWIDTH_UNSPECIFIED, caps.getLinkUpstreamBandwidthKbps());
47672f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkey        assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_METERED));
47772f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkey        assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING));
4789b2a10f55d1659895e20ec0b88dd023ae18770ebJeff Sharkey        assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED));
47972f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkey
48072f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkey        Vpn.updateCapabilities(mConnectivityManager, new Network[] { wifi }, caps);
48172f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkey        assertTrue(caps.hasTransport(TRANSPORT_VPN));
48272f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkey        assertFalse(caps.hasTransport(TRANSPORT_CELLULAR));
48372f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkey        assertTrue(caps.hasTransport(TRANSPORT_WIFI));
48472f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkey        assertEquals(LINK_BANDWIDTH_UNSPECIFIED, caps.getLinkDownstreamBandwidthKbps());
48572f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkey        assertEquals(20, caps.getLinkUpstreamBandwidthKbps());
48672f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkey        assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_METERED));
48772f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkey        assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING));
4889b2a10f55d1659895e20ec0b88dd023ae18770ebJeff Sharkey        assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED));
48972f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkey
49072f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkey        Vpn.updateCapabilities(mConnectivityManager, new Network[] { mobile, wifi }, caps);
49172f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkey        assertTrue(caps.hasTransport(TRANSPORT_VPN));
49272f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkey        assertTrue(caps.hasTransport(TRANSPORT_CELLULAR));
49372f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkey        assertTrue(caps.hasTransport(TRANSPORT_WIFI));
49472f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkey        assertEquals(10, caps.getLinkDownstreamBandwidthKbps());
49572f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkey        assertEquals(20, caps.getLinkUpstreamBandwidthKbps());
49672f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkey        assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_METERED));
49772f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkey        assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING));
4989b2a10f55d1659895e20ec0b88dd023ae18770ebJeff Sharkey        assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED));
49972f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkey    }
50072f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkey
5014d03abcd49af490dba3850d341b955dd72f24959Robin Lee    /**
502de7f7d195eec64802b7b6eee819c699f1a7d6951Tony Mak     * Mock some methods of vpn object.
5034d03abcd49af490dba3850d341b955dd72f24959Robin Lee     */
504b8c2a2b85052479cb6affe2d4a8240e78198e2d5Robin Lee    private Vpn createVpn(@UserIdInt int userId) {
505b8c2a2b85052479cb6affe2d4a8240e78198e2d5Robin Lee        return new Vpn(Looper.myLooper(), mContext, mNetService, userId, mSystemServices);
506de7f7d195eec64802b7b6eee819c699f1a7d6951Tony Mak    }
507de7f7d195eec64802b7b6eee819c699f1a7d6951Tony Mak
508de7f7d195eec64802b7b6eee819c699f1a7d6951Tony Mak    private static void assertBlocked(Vpn vpn, int... uids) {
509de7f7d195eec64802b7b6eee819c699f1a7d6951Tony Mak        for (int uid : uids) {
510de7f7d195eec64802b7b6eee819c699f1a7d6951Tony Mak            assertTrue("Uid " + uid + " should be blocked", vpn.isBlockingUid(uid));
51117e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee        }
512de7f7d195eec64802b7b6eee819c699f1a7d6951Tony Mak    }
51317e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee
514de7f7d195eec64802b7b6eee819c699f1a7d6951Tony Mak    private static void assertUnblocked(Vpn vpn, int... uids) {
515de7f7d195eec64802b7b6eee819c699f1a7d6951Tony Mak        for (int uid : uids) {
516de7f7d195eec64802b7b6eee819c699f1a7d6951Tony Mak            assertFalse("Uid " + uid + " should not be blocked", vpn.isBlockingUid(uid));
51717e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee        }
5184d03abcd49af490dba3850d341b955dd72f24959Robin Lee    }
5194d03abcd49af490dba3850d341b955dd72f24959Robin Lee
5204d03abcd49af490dba3850d341b955dd72f24959Robin Lee    /**
5214d03abcd49af490dba3850d341b955dd72f24959Robin Lee     * Populate {@link #mUserManager} with a list of fake users.
5224d03abcd49af490dba3850d341b955dd72f24959Robin Lee     */
5234d03abcd49af490dba3850d341b955dd72f24959Robin Lee    private void setMockedUsers(UserInfo... users) {
5244d03abcd49af490dba3850d341b955dd72f24959Robin Lee        final Map<Integer, UserInfo> userMap = new ArrayMap<>();
5254d03abcd49af490dba3850d341b955dd72f24959Robin Lee        for (UserInfo user : users) {
5264d03abcd49af490dba3850d341b955dd72f24959Robin Lee            userMap.put(user.id, user);
5274d03abcd49af490dba3850d341b955dd72f24959Robin Lee        }
5284d03abcd49af490dba3850d341b955dd72f24959Robin Lee
52917e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee        /**
53017e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee         * @see UserManagerService#getUsers(boolean)
53117e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee         */
5324d03abcd49af490dba3850d341b955dd72f24959Robin Lee        doAnswer(invocation -> {
53317e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee            final boolean excludeDying = (boolean) invocation.getArguments()[0];
53417e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee            final ArrayList<UserInfo> result = new ArrayList<>(users.length);
53517e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee            for (UserInfo ui : users) {
53617e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee                if (!excludeDying || (ui.isEnabled() && !ui.partial)) {
53717e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee                    result.add(ui);
53817e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee                }
53917e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee            }
54017e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee            return result;
54117e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee        }).when(mUserManager).getUsers(anyBoolean());
5424d03abcd49af490dba3850d341b955dd72f24959Robin Lee
5434d03abcd49af490dba3850d341b955dd72f24959Robin Lee        doAnswer(invocation -> {
5444d03abcd49af490dba3850d341b955dd72f24959Robin Lee            final int id = (int) invocation.getArguments()[0];
5454d03abcd49af490dba3850d341b955dd72f24959Robin Lee            return userMap.get(id);
5464d03abcd49af490dba3850d341b955dd72f24959Robin Lee        }).when(mUserManager).getUserInfo(anyInt());
5474d03abcd49af490dba3850d341b955dd72f24959Robin Lee
5484d03abcd49af490dba3850d341b955dd72f24959Robin Lee        doAnswer(invocation -> {
5494d03abcd49af490dba3850d341b955dd72f24959Robin Lee            final int id = (int) invocation.getArguments()[0];
5504d03abcd49af490dba3850d341b955dd72f24959Robin Lee            return (userMap.get(id).flags & UserInfo.FLAG_ADMIN) != 0;
5514d03abcd49af490dba3850d341b955dd72f24959Robin Lee        }).when(mUserManager).canHaveRestrictedProfile(anyInt());
5524d03abcd49af490dba3850d341b955dd72f24959Robin Lee    }
5534d03abcd49af490dba3850d341b955dd72f24959Robin Lee
5544d03abcd49af490dba3850d341b955dd72f24959Robin Lee    /**
5554d03abcd49af490dba3850d341b955dd72f24959Robin Lee     * Populate {@link #mPackageManager} with a fake packageName-to-UID mapping.
5564d03abcd49af490dba3850d341b955dd72f24959Robin Lee     */
5574d03abcd49af490dba3850d341b955dd72f24959Robin Lee    private void setMockedPackages(final Map<String, Integer> packages) {
5584d03abcd49af490dba3850d341b955dd72f24959Robin Lee        try {
5594d03abcd49af490dba3850d341b955dd72f24959Robin Lee            doAnswer(invocation -> {
5604d03abcd49af490dba3850d341b955dd72f24959Robin Lee                final String appName = (String) invocation.getArguments()[0];
5614d03abcd49af490dba3850d341b955dd72f24959Robin Lee                final int userId = (int) invocation.getArguments()[1];
5624d03abcd49af490dba3850d341b955dd72f24959Robin Lee                return UserHandle.getUid(userId, packages.get(appName));
5634d03abcd49af490dba3850d341b955dd72f24959Robin Lee            }).when(mPackageManager).getPackageUidAsUser(anyString(), anyInt());
5644d03abcd49af490dba3850d341b955dd72f24959Robin Lee        } catch (Exception e) {
5654d03abcd49af490dba3850d341b955dd72f24959Robin Lee        }
5664d03abcd49af490dba3850d341b955dd72f24959Robin Lee    }
56772f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkey
56872f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkey    private void setMockedNetworks(final Map<Network, NetworkCapabilities> networks) {
56972f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkey        doAnswer(invocation -> {
57072f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkey            final Network network = (Network) invocation.getArguments()[0];
57172f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkey            return networks.get(network);
57272f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkey        }).when(mConnectivityManager).getNetworkCapabilities(any());
57372f9c42b9e59761a28d6b32c42f65de57c98daedJeff Sharkey    }
574adbf1d029b753fabc2a7a5ad3b22d3d416cecdd9Chalard Jean
575adbf1d029b753fabc2a7a5ad3b22d3d416cecdd9Chalard Jean    // Need multiple copies of this, but Java's Stream objects can't be reused or
576adbf1d029b753fabc2a7a5ad3b22d3d416cecdd9Chalard Jean    // duplicated.
577adbf1d029b753fabc2a7a5ad3b22d3d416cecdd9Chalard Jean    private Stream<String> publicIpV4Routes() {
578adbf1d029b753fabc2a7a5ad3b22d3d416cecdd9Chalard Jean        return Stream.of(
579adbf1d029b753fabc2a7a5ad3b22d3d416cecdd9Chalard Jean                "0.0.0.0/5", "8.0.0.0/7", "11.0.0.0/8", "12.0.0.0/6", "16.0.0.0/4",
580adbf1d029b753fabc2a7a5ad3b22d3d416cecdd9Chalard Jean                "32.0.0.0/3", "64.0.0.0/2", "128.0.0.0/3", "160.0.0.0/5", "168.0.0.0/6",
581adbf1d029b753fabc2a7a5ad3b22d3d416cecdd9Chalard Jean                "172.0.0.0/12", "172.32.0.0/11", "172.64.0.0/10", "172.128.0.0/9",
582adbf1d029b753fabc2a7a5ad3b22d3d416cecdd9Chalard Jean                "173.0.0.0/8", "174.0.0.0/7", "176.0.0.0/4", "192.0.0.0/9", "192.128.0.0/11",
583adbf1d029b753fabc2a7a5ad3b22d3d416cecdd9Chalard Jean                "192.160.0.0/13", "192.169.0.0/16", "192.170.0.0/15", "192.172.0.0/14",
584adbf1d029b753fabc2a7a5ad3b22d3d416cecdd9Chalard Jean                "192.176.0.0/12", "192.192.0.0/10", "193.0.0.0/8", "194.0.0.0/7",
585adbf1d029b753fabc2a7a5ad3b22d3d416cecdd9Chalard Jean                "196.0.0.0/6", "200.0.0.0/5", "208.0.0.0/4");
586adbf1d029b753fabc2a7a5ad3b22d3d416cecdd9Chalard Jean    }
587adbf1d029b753fabc2a7a5ad3b22d3d416cecdd9Chalard Jean
588adbf1d029b753fabc2a7a5ad3b22d3d416cecdd9Chalard Jean    private Stream<String> publicIpV6Routes() {
589adbf1d029b753fabc2a7a5ad3b22d3d416cecdd9Chalard Jean        return Stream.of(
590adbf1d029b753fabc2a7a5ad3b22d3d416cecdd9Chalard Jean                "::/1", "8000::/2", "c000::/3", "e000::/4", "f000::/5", "f800::/6",
591adbf1d029b753fabc2a7a5ad3b22d3d416cecdd9Chalard Jean                "fe00::/8", "2605:ef80:e:af1d::/64");
592adbf1d029b753fabc2a7a5ad3b22d3d416cecdd9Chalard Jean    }
593adbf1d029b753fabc2a7a5ad3b22d3d416cecdd9Chalard Jean
594adbf1d029b753fabc2a7a5ad3b22d3d416cecdd9Chalard Jean    @Test
595adbf1d029b753fabc2a7a5ad3b22d3d416cecdd9Chalard Jean    public void testProvidesRoutesToMostDestinations() {
596adbf1d029b753fabc2a7a5ad3b22d3d416cecdd9Chalard Jean        final LinkProperties lp = new LinkProperties();
597adbf1d029b753fabc2a7a5ad3b22d3d416cecdd9Chalard Jean
598adbf1d029b753fabc2a7a5ad3b22d3d416cecdd9Chalard Jean        // Default route provides routes to all IPv4 destinations.
599adbf1d029b753fabc2a7a5ad3b22d3d416cecdd9Chalard Jean        lp.addRoute(new RouteInfo(new IpPrefix("0.0.0.0/0")));
600adbf1d029b753fabc2a7a5ad3b22d3d416cecdd9Chalard Jean        assertTrue(Vpn.providesRoutesToMostDestinations(lp));
601adbf1d029b753fabc2a7a5ad3b22d3d416cecdd9Chalard Jean
602adbf1d029b753fabc2a7a5ad3b22d3d416cecdd9Chalard Jean        // Empty LP provides routes to no destination
603adbf1d029b753fabc2a7a5ad3b22d3d416cecdd9Chalard Jean        lp.clear();
604adbf1d029b753fabc2a7a5ad3b22d3d416cecdd9Chalard Jean        assertFalse(Vpn.providesRoutesToMostDestinations(lp));
605adbf1d029b753fabc2a7a5ad3b22d3d416cecdd9Chalard Jean
606adbf1d029b753fabc2a7a5ad3b22d3d416cecdd9Chalard Jean        // All IPv4 routes except for local networks. This is the case most relevant
607adbf1d029b753fabc2a7a5ad3b22d3d416cecdd9Chalard Jean        // to this function. It provides routes to almost the entire space.
608adbf1d029b753fabc2a7a5ad3b22d3d416cecdd9Chalard Jean        // (clone the stream so that we can reuse it later)
609adbf1d029b753fabc2a7a5ad3b22d3d416cecdd9Chalard Jean        publicIpV4Routes().forEach(s -> lp.addRoute(new RouteInfo(new IpPrefix(s))));
610adbf1d029b753fabc2a7a5ad3b22d3d416cecdd9Chalard Jean        assertTrue(Vpn.providesRoutesToMostDestinations(lp));
611adbf1d029b753fabc2a7a5ad3b22d3d416cecdd9Chalard Jean
612adbf1d029b753fabc2a7a5ad3b22d3d416cecdd9Chalard Jean        // Removing a 16-bit prefix, which is 65536 addresses. This is still enough to
613adbf1d029b753fabc2a7a5ad3b22d3d416cecdd9Chalard Jean        // provide routes to "most" destinations.
614adbf1d029b753fabc2a7a5ad3b22d3d416cecdd9Chalard Jean        lp.removeRoute(new RouteInfo(new IpPrefix("192.169.0.0/16")));
615adbf1d029b753fabc2a7a5ad3b22d3d416cecdd9Chalard Jean        assertTrue(Vpn.providesRoutesToMostDestinations(lp));
616adbf1d029b753fabc2a7a5ad3b22d3d416cecdd9Chalard Jean
617adbf1d029b753fabc2a7a5ad3b22d3d416cecdd9Chalard Jean        // Remove the /2 route, which represent a quarter of the available routing space.
618adbf1d029b753fabc2a7a5ad3b22d3d416cecdd9Chalard Jean        // This LP does not provides routes to "most" destinations any more.
619adbf1d029b753fabc2a7a5ad3b22d3d416cecdd9Chalard Jean        lp.removeRoute(new RouteInfo(new IpPrefix("64.0.0.0/2")));
620adbf1d029b753fabc2a7a5ad3b22d3d416cecdd9Chalard Jean        assertFalse(Vpn.providesRoutesToMostDestinations(lp));
621adbf1d029b753fabc2a7a5ad3b22d3d416cecdd9Chalard Jean
622adbf1d029b753fabc2a7a5ad3b22d3d416cecdd9Chalard Jean        lp.clear();
623adbf1d029b753fabc2a7a5ad3b22d3d416cecdd9Chalard Jean        publicIpV6Routes().forEach(s -> lp.addRoute(new RouteInfo(new IpPrefix(s))));
624adbf1d029b753fabc2a7a5ad3b22d3d416cecdd9Chalard Jean        assertTrue(Vpn.providesRoutesToMostDestinations(lp));
625adbf1d029b753fabc2a7a5ad3b22d3d416cecdd9Chalard Jean
626adbf1d029b753fabc2a7a5ad3b22d3d416cecdd9Chalard Jean        lp.removeRoute(new RouteInfo(new IpPrefix("::/1")));
627adbf1d029b753fabc2a7a5ad3b22d3d416cecdd9Chalard Jean        assertFalse(Vpn.providesRoutesToMostDestinations(lp));
628adbf1d029b753fabc2a7a5ad3b22d3d416cecdd9Chalard Jean
629adbf1d029b753fabc2a7a5ad3b22d3d416cecdd9Chalard Jean        // V6 does not provide sufficient coverage but v4 does
630adbf1d029b753fabc2a7a5ad3b22d3d416cecdd9Chalard Jean        publicIpV4Routes().forEach(s -> lp.addRoute(new RouteInfo(new IpPrefix(s))));
631adbf1d029b753fabc2a7a5ad3b22d3d416cecdd9Chalard Jean        assertTrue(Vpn.providesRoutesToMostDestinations(lp));
632adbf1d029b753fabc2a7a5ad3b22d3d416cecdd9Chalard Jean
633adbf1d029b753fabc2a7a5ad3b22d3d416cecdd9Chalard Jean        // V4 still does
634adbf1d029b753fabc2a7a5ad3b22d3d416cecdd9Chalard Jean        lp.removeRoute(new RouteInfo(new IpPrefix("192.169.0.0/16")));
635adbf1d029b753fabc2a7a5ad3b22d3d416cecdd9Chalard Jean        assertTrue(Vpn.providesRoutesToMostDestinations(lp));
636adbf1d029b753fabc2a7a5ad3b22d3d416cecdd9Chalard Jean
637adbf1d029b753fabc2a7a5ad3b22d3d416cecdd9Chalard Jean        // V4 does not any more
638adbf1d029b753fabc2a7a5ad3b22d3d416cecdd9Chalard Jean        lp.removeRoute(new RouteInfo(new IpPrefix("64.0.0.0/2")));
639adbf1d029b753fabc2a7a5ad3b22d3d416cecdd9Chalard Jean        assertFalse(Vpn.providesRoutesToMostDestinations(lp));
640adbf1d029b753fabc2a7a5ad3b22d3d416cecdd9Chalard Jean
641adbf1d029b753fabc2a7a5ad3b22d3d416cecdd9Chalard Jean        // V4 does not, but V6 has sufficient coverage again
642adbf1d029b753fabc2a7a5ad3b22d3d416cecdd9Chalard Jean        lp.addRoute(new RouteInfo(new IpPrefix("::/1")));
643adbf1d029b753fabc2a7a5ad3b22d3d416cecdd9Chalard Jean        assertTrue(Vpn.providesRoutesToMostDestinations(lp));
644adbf1d029b753fabc2a7a5ad3b22d3d416cecdd9Chalard Jean    }
645507754a81e0b9d871e59fe9621c2a5d57befff90Chalard Jean
646507754a81e0b9d871e59fe9621c2a5d57befff90Chalard Jean    @Test
647507754a81e0b9d871e59fe9621c2a5d57befff90Chalard Jean    public void testDoesNotLockUpWithTooManyRoutes() {
648507754a81e0b9d871e59fe9621c2a5d57befff90Chalard Jean        final LinkProperties lp = new LinkProperties();
649507754a81e0b9d871e59fe9621c2a5d57befff90Chalard Jean        final byte[] ad = new byte[4];
650507754a81e0b9d871e59fe9621c2a5d57befff90Chalard Jean        // Actually evaluating this many routes under 1500ms is impossible on
651507754a81e0b9d871e59fe9621c2a5d57befff90Chalard Jean        // current hardware and for some time, as the algorithm is O(n²).
652507754a81e0b9d871e59fe9621c2a5d57befff90Chalard Jean        // Make sure the system has a safeguard against this and does not
653507754a81e0b9d871e59fe9621c2a5d57befff90Chalard Jean        // lock up.
654507754a81e0b9d871e59fe9621c2a5d57befff90Chalard Jean        final int MAX_ROUTES = 4000;
655507754a81e0b9d871e59fe9621c2a5d57befff90Chalard Jean        final long MAX_ALLOWED_TIME_MS = 1500;
656507754a81e0b9d871e59fe9621c2a5d57befff90Chalard Jean        for (int i = 0; i < MAX_ROUTES; ++i) {
657507754a81e0b9d871e59fe9621c2a5d57befff90Chalard Jean            ad[0] = (byte)((i >> 24) & 0xFF);
658507754a81e0b9d871e59fe9621c2a5d57befff90Chalard Jean            ad[1] = (byte)((i >> 16) & 0xFF);
659507754a81e0b9d871e59fe9621c2a5d57befff90Chalard Jean            ad[2] = (byte)((i >> 8) & 0xFF);
660507754a81e0b9d871e59fe9621c2a5d57befff90Chalard Jean            ad[3] = (byte)(i & 0xFF);
661507754a81e0b9d871e59fe9621c2a5d57befff90Chalard Jean            try {
662507754a81e0b9d871e59fe9621c2a5d57befff90Chalard Jean                lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.getByAddress(ad), 32)));
663507754a81e0b9d871e59fe9621c2a5d57befff90Chalard Jean            } catch (UnknownHostException e) {
664507754a81e0b9d871e59fe9621c2a5d57befff90Chalard Jean                // UnknownHostException is only thrown for an address of illegal length,
665507754a81e0b9d871e59fe9621c2a5d57befff90Chalard Jean                // which can't happen in the case above.
666507754a81e0b9d871e59fe9621c2a5d57befff90Chalard Jean            }
667507754a81e0b9d871e59fe9621c2a5d57befff90Chalard Jean        }
668507754a81e0b9d871e59fe9621c2a5d57befff90Chalard Jean        final long start = SystemClock.currentThreadTimeMillis();
669507754a81e0b9d871e59fe9621c2a5d57befff90Chalard Jean        assertTrue(Vpn.providesRoutesToMostDestinations(lp));
670507754a81e0b9d871e59fe9621c2a5d57befff90Chalard Jean        final long end = SystemClock.currentThreadTimeMillis();
671507754a81e0b9d871e59fe9621c2a5d57befff90Chalard Jean        assertTrue(end - start < MAX_ALLOWED_TIME_MS);
672507754a81e0b9d871e59fe9621c2a5d57befff90Chalard Jean    }
6734d03abcd49af490dba3850d341b955dd72f24959Robin Lee}
674