• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.connectivity;
18 
19 import static android.content.pm.UserInfo.FLAG_ADMIN;
20 import static android.content.pm.UserInfo.FLAG_MANAGED_PROFILE;
21 import static android.content.pm.UserInfo.FLAG_PRIMARY;
22 import static android.content.pm.UserInfo.FLAG_RESTRICTED;
23 import static android.net.NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED;
24 import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
25 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED;
26 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
27 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
28 import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
29 import static android.net.NetworkCapabilities.TRANSPORT_VPN;
30 import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
31 
32 import static org.junit.Assert.assertEquals;
33 import static org.junit.Assert.assertFalse;
34 import static org.junit.Assert.assertTrue;
35 import static org.mockito.AdditionalMatchers.aryEq;
36 import static org.mockito.ArgumentMatchers.any;
37 import static org.mockito.ArgumentMatchers.anyBoolean;
38 import static org.mockito.ArgumentMatchers.anyInt;
39 import static org.mockito.ArgumentMatchers.anyString;
40 import static org.mockito.ArgumentMatchers.eq;
41 import static org.mockito.Mockito.atLeastOnce;
42 import static org.mockito.Mockito.doAnswer;
43 import static org.mockito.Mockito.doNothing;
44 import static org.mockito.Mockito.inOrder;
45 import static org.mockito.Mockito.times;
46 import static org.mockito.Mockito.verify;
47 import static org.mockito.Mockito.when;
48 
49 import android.annotation.UserIdInt;
50 import android.app.AppOpsManager;
51 import android.app.NotificationManager;
52 import android.content.Context;
53 import android.content.pm.ApplicationInfo;
54 import android.content.pm.PackageManager;
55 import android.content.pm.ResolveInfo;
56 import android.content.pm.ServiceInfo;
57 import android.content.pm.UserInfo;
58 import android.content.res.Resources;
59 import android.net.ConnectivityManager;
60 import android.net.IConnectivityManager;
61 import android.net.IpPrefix;
62 import android.net.LinkProperties;
63 import android.net.Network;
64 import android.net.NetworkCapabilities;
65 import android.net.NetworkInfo.DetailedState;
66 import android.net.RouteInfo;
67 import android.net.UidRange;
68 import android.net.VpnService;
69 import android.os.Build.VERSION_CODES;
70 import android.os.Bundle;
71 import android.os.INetworkManagementService;
72 import android.os.Looper;
73 import android.os.SystemClock;
74 import android.os.UserHandle;
75 import android.os.UserManager;
76 import android.support.test.filters.SmallTest;
77 import android.support.test.runner.AndroidJUnit4;
78 import android.util.ArrayMap;
79 import android.util.ArraySet;
80 
81 import com.android.internal.R;
82 import com.android.internal.net.VpnConfig;
83 
84 import org.junit.Before;
85 import org.junit.Test;
86 import org.junit.runner.RunWith;
87 import org.mockito.Answers;
88 import org.mockito.InOrder;
89 import org.mockito.Mock;
90 import org.mockito.MockitoAnnotations;
91 
92 import java.net.Inet4Address;
93 import java.net.UnknownHostException;
94 import java.util.ArrayList;
95 import java.util.Arrays;
96 import java.util.Collections;
97 import java.util.HashMap;
98 import java.util.Map;
99 import java.util.Set;
100 import java.util.stream.Collectors;
101 import java.util.stream.Stream;
102 
103 /**
104  * Tests for {@link Vpn}.
105  *
106  * Build, install and run with:
107  *  runtest frameworks-net -c com.android.server.connectivity.VpnTest
108  */
109 @RunWith(AndroidJUnit4.class)
110 @SmallTest
111 public class VpnTest {
112     private static final String TAG = "VpnTest";
113 
114     // Mock users
115     static final UserInfo primaryUser = new UserInfo(27, "Primary", FLAG_ADMIN | FLAG_PRIMARY);
116     static final UserInfo secondaryUser = new UserInfo(15, "Secondary", FLAG_ADMIN);
117     static final UserInfo restrictedProfileA = new UserInfo(40, "RestrictedA", FLAG_RESTRICTED);
118     static final UserInfo restrictedProfileB = new UserInfo(42, "RestrictedB", FLAG_RESTRICTED);
119     static final UserInfo managedProfileA = new UserInfo(45, "ManagedA", FLAG_MANAGED_PROFILE);
120     static {
121         restrictedProfileA.restrictedProfileParentId = primaryUser.id;
122         restrictedProfileB.restrictedProfileParentId = secondaryUser.id;
123         managedProfileA.profileGroupId = primaryUser.id;
124     }
125 
126     /**
127      * Names and UIDs for some fake packages. Important points:
128      *  - UID is ordered increasing.
129      *  - One pair of packages have consecutive UIDs.
130      */
131     static final String[] PKGS = {"com.example", "org.example", "net.example", "web.vpn"};
132     static final int[] PKG_UIDS = {66, 77, 78, 400};
133 
134     // Mock packages
135     static final Map<String, Integer> mPackages = new ArrayMap<>();
136     static {
137         for (int i = 0; i < PKGS.length; i++) {
mPackages.put(PKGS[i], PKG_UIDS[i])138             mPackages.put(PKGS[i], PKG_UIDS[i]);
139         }
140     }
141 
142     @Mock(answer = Answers.RETURNS_DEEP_STUBS) private Context mContext;
143     @Mock private UserManager mUserManager;
144     @Mock private PackageManager mPackageManager;
145     @Mock private INetworkManagementService mNetService;
146     @Mock private AppOpsManager mAppOps;
147     @Mock private NotificationManager mNotificationManager;
148     @Mock private Vpn.SystemServices mSystemServices;
149     @Mock private ConnectivityManager mConnectivityManager;
150 
151     @Before
setUp()152     public void setUp() throws Exception {
153         MockitoAnnotations.initMocks(this);
154 
155         when(mContext.getPackageManager()).thenReturn(mPackageManager);
156         setMockedPackages(mPackages);
157 
158         when(mContext.getPackageName()).thenReturn(Vpn.class.getPackage().getName());
159         when(mContext.getSystemService(eq(Context.USER_SERVICE))).thenReturn(mUserManager);
160         when(mContext.getSystemService(eq(Context.APP_OPS_SERVICE))).thenReturn(mAppOps);
161         when(mContext.getSystemService(eq(Context.NOTIFICATION_SERVICE)))
162                 .thenReturn(mNotificationManager);
163         when(mContext.getSystemService(eq(Context.CONNECTIVITY_SERVICE)))
164                 .thenReturn(mConnectivityManager);
165         when(mContext.getString(R.string.config_customVpnAlwaysOnDisconnectedDialogComponent))
166                 .thenReturn(Resources.getSystem().getString(
167                         R.string.config_customVpnAlwaysOnDisconnectedDialogComponent));
168 
169         // Used by {@link Notification.Builder}
170         ApplicationInfo applicationInfo = new ApplicationInfo();
171         applicationInfo.targetSdkVersion = VERSION_CODES.CUR_DEVELOPMENT;
172         when(mContext.getApplicationInfo()).thenReturn(applicationInfo);
173 
174         doNothing().when(mNetService).registerObserver(any());
175     }
176 
177     @Test
testRestrictedProfilesAreAddedToVpn()178     public void testRestrictedProfilesAreAddedToVpn() {
179         setMockedUsers(primaryUser, secondaryUser, restrictedProfileA, restrictedProfileB);
180 
181         final Vpn vpn = createVpn(primaryUser.id);
182         final Set<UidRange> ranges = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id,
183                 null, null);
184 
185         assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] {
186             UidRange.createForUser(primaryUser.id),
187             UidRange.createForUser(restrictedProfileA.id)
188         })), ranges);
189     }
190 
191     @Test
testManagedProfilesAreNotAddedToVpn()192     public void testManagedProfilesAreNotAddedToVpn() {
193         setMockedUsers(primaryUser, managedProfileA);
194 
195         final Vpn vpn = createVpn(primaryUser.id);
196         final Set<UidRange> ranges = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id,
197                 null, null);
198 
199         assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] {
200             UidRange.createForUser(primaryUser.id)
201         })), ranges);
202     }
203 
204     @Test
testAddUserToVpnOnlyAddsOneUser()205     public void testAddUserToVpnOnlyAddsOneUser() {
206         setMockedUsers(primaryUser, restrictedProfileA, managedProfileA);
207 
208         final Vpn vpn = createVpn(primaryUser.id);
209         final Set<UidRange> ranges = new ArraySet<>();
210         vpn.addUserToRanges(ranges, primaryUser.id, null, null);
211 
212         assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] {
213             UidRange.createForUser(primaryUser.id)
214         })), ranges);
215     }
216 
217     @Test
testUidWhiteAndBlacklist()218     public void testUidWhiteAndBlacklist() throws Exception {
219         final Vpn vpn = createVpn(primaryUser.id);
220         final UidRange user = UidRange.createForUser(primaryUser.id);
221         final String[] packages = {PKGS[0], PKGS[1], PKGS[2]};
222 
223         // Whitelist
224         final Set<UidRange> allow = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id,
225                 Arrays.asList(packages), null);
226         assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] {
227             new UidRange(user.start + PKG_UIDS[0], user.start + PKG_UIDS[0]),
228             new UidRange(user.start + PKG_UIDS[1], user.start + PKG_UIDS[2])
229         })), allow);
230 
231         // Blacklist
232         final Set<UidRange> disallow = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id,
233                 null, Arrays.asList(packages));
234         assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] {
235             new UidRange(user.start, user.start + PKG_UIDS[0] - 1),
236             new UidRange(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[1] - 1),
237             /* Empty range between UIDS[1] and UIDS[2], should be excluded, */
238             new UidRange(user.start + PKG_UIDS[2] + 1, user.stop)
239         })), disallow);
240     }
241 
242     @Test
testLockdownChangingPackage()243     public void testLockdownChangingPackage() throws Exception {
244         final Vpn vpn = createVpn(primaryUser.id);
245         final UidRange user = UidRange.createForUser(primaryUser.id);
246 
247         // Default state.
248         assertUnblocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[1], user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]);
249 
250         // Set always-on without lockdown.
251         assertTrue(vpn.setAlwaysOnPackage(PKGS[1], false));
252         assertUnblocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[1], user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]);
253 
254         // Set always-on with lockdown.
255         assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true));
256         verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
257             new UidRange(user.start, user.start + PKG_UIDS[1] - 1),
258             new UidRange(user.start + PKG_UIDS[1] + 1, user.stop)
259         }));
260         assertBlocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]);
261         assertUnblocked(vpn, user.start + PKG_UIDS[1]);
262 
263         // Switch to another app.
264         assertTrue(vpn.setAlwaysOnPackage(PKGS[3], true));
265         verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[] {
266             new UidRange(user.start, user.start + PKG_UIDS[1] - 1),
267             new UidRange(user.start + PKG_UIDS[1] + 1, user.stop)
268         }));
269         verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
270             new UidRange(user.start, user.start + PKG_UIDS[3] - 1),
271             new UidRange(user.start + PKG_UIDS[3] + 1, user.stop)
272         }));
273         assertBlocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[1], user.start + PKG_UIDS[2]);
274         assertUnblocked(vpn, user.start + PKG_UIDS[3]);
275     }
276 
277     @Test
testLockdownAddingAProfile()278     public void testLockdownAddingAProfile() throws Exception {
279         final Vpn vpn = createVpn(primaryUser.id);
280         setMockedUsers(primaryUser);
281 
282         // Make a copy of the restricted profile, as we're going to mark it deleted halfway through.
283         final UserInfo tempProfile = new UserInfo(restrictedProfileA.id, restrictedProfileA.name,
284                 restrictedProfileA.flags);
285         tempProfile.restrictedProfileParentId = primaryUser.id;
286 
287         final UidRange user = UidRange.createForUser(primaryUser.id);
288         final UidRange profile = UidRange.createForUser(tempProfile.id);
289 
290         // Set lockdown.
291         assertTrue(vpn.setAlwaysOnPackage(PKGS[3], true));
292         verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
293             new UidRange(user.start, user.start + PKG_UIDS[3] - 1),
294             new UidRange(user.start + PKG_UIDS[3] + 1, user.stop)
295         }));
296 
297         // Verify restricted user isn't affected at first.
298         assertUnblocked(vpn, profile.start + PKG_UIDS[0]);
299 
300         // Add the restricted user.
301         setMockedUsers(primaryUser, tempProfile);
302         vpn.onUserAdded(tempProfile.id);
303         verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
304             new UidRange(profile.start, profile.start + PKG_UIDS[3] - 1),
305             new UidRange(profile.start + PKG_UIDS[3] + 1, profile.stop)
306         }));
307 
308         // Remove the restricted user.
309         tempProfile.partial = true;
310         vpn.onUserRemoved(tempProfile.id);
311         verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[] {
312             new UidRange(profile.start, profile.start + PKG_UIDS[3] - 1),
313             new UidRange(profile.start + PKG_UIDS[3] + 1, profile.stop)
314         }));
315     }
316 
317     @Test
testLockdownRuleRepeatability()318     public void testLockdownRuleRepeatability() throws Exception {
319         final Vpn vpn = createVpn(primaryUser.id);
320 
321         // Given legacy lockdown is already enabled,
322         vpn.setLockdown(true);
323         verify(mNetService, times(1)).setAllowOnlyVpnForUids(
324                 eq(true), aryEq(new UidRange[] {UidRange.createForUser(primaryUser.id)}));
325 
326         // Enabling legacy lockdown twice should do nothing.
327         vpn.setLockdown(true);
328         verify(mNetService, times(1)).setAllowOnlyVpnForUids(anyBoolean(), any(UidRange[].class));
329 
330         // And disabling should remove the rules exactly once.
331         vpn.setLockdown(false);
332         verify(mNetService, times(1)).setAllowOnlyVpnForUids(
333                 eq(false), aryEq(new UidRange[] {UidRange.createForUser(primaryUser.id)}));
334 
335         // Removing the lockdown again should have no effect.
336         vpn.setLockdown(false);
337         verify(mNetService, times(2)).setAllowOnlyVpnForUids(anyBoolean(), any(UidRange[].class));
338     }
339 
340     @Test
testLockdownRuleReversibility()341     public void testLockdownRuleReversibility() throws Exception {
342         final Vpn vpn = createVpn(primaryUser.id);
343 
344         final UidRange[] entireUser = {
345             UidRange.createForUser(primaryUser.id)
346         };
347         final UidRange[] exceptPkg0 = {
348             new UidRange(entireUser[0].start, entireUser[0].start + PKG_UIDS[0] - 1),
349             new UidRange(entireUser[0].start + PKG_UIDS[0] + 1, entireUser[0].stop)
350         };
351 
352         final InOrder order = inOrder(mNetService);
353 
354         // Given lockdown is enabled with no package (legacy VPN),
355         vpn.setLockdown(true);
356         order.verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(entireUser));
357 
358         // When a new VPN package is set the rules should change to cover that package.
359         vpn.prepare(null, PKGS[0]);
360         order.verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(entireUser));
361         order.verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(exceptPkg0));
362 
363         // When that VPN package is unset, everything should be undone again in reverse.
364         vpn.prepare(null, VpnConfig.LEGACY_VPN);
365         order.verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(exceptPkg0));
366         order.verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(entireUser));
367     }
368 
369     @Test
testIsAlwaysOnPackageSupported()370     public void testIsAlwaysOnPackageSupported() throws Exception {
371         final Vpn vpn = createVpn(primaryUser.id);
372 
373         ApplicationInfo appInfo = new ApplicationInfo();
374         when(mPackageManager.getApplicationInfoAsUser(eq(PKGS[0]), anyInt(), eq(primaryUser.id)))
375                 .thenReturn(appInfo);
376 
377         ServiceInfo svcInfo = new ServiceInfo();
378         ResolveInfo resInfo = new ResolveInfo();
379         resInfo.serviceInfo = svcInfo;
380         when(mPackageManager.queryIntentServicesAsUser(any(), eq(PackageManager.GET_META_DATA),
381                 eq(primaryUser.id)))
382                 .thenReturn(Collections.singletonList(resInfo));
383 
384         // null package name should return false
385         assertFalse(vpn.isAlwaysOnPackageSupported(null));
386 
387         // Pre-N apps are not supported
388         appInfo.targetSdkVersion = VERSION_CODES.M;
389         assertFalse(vpn.isAlwaysOnPackageSupported(PKGS[0]));
390 
391         // N+ apps are supported by default
392         appInfo.targetSdkVersion = VERSION_CODES.N;
393         assertTrue(vpn.isAlwaysOnPackageSupported(PKGS[0]));
394 
395         // Apps that opt out explicitly are not supported
396         appInfo.targetSdkVersion = VERSION_CODES.CUR_DEVELOPMENT;
397         Bundle metaData = new Bundle();
398         metaData.putBoolean(VpnService.SERVICE_META_DATA_SUPPORTS_ALWAYS_ON, false);
399         svcInfo.metaData = metaData;
400         assertFalse(vpn.isAlwaysOnPackageSupported(PKGS[0]));
401     }
402 
403     @Test
testNotificationShownForAlwaysOnApp()404     public void testNotificationShownForAlwaysOnApp() {
405         final UserHandle userHandle = UserHandle.of(primaryUser.id);
406         final Vpn vpn = createVpn(primaryUser.id);
407         setMockedUsers(primaryUser);
408 
409         final InOrder order = inOrder(mNotificationManager);
410 
411         // Don't show a notification for regular disconnected states.
412         vpn.updateState(DetailedState.DISCONNECTED, TAG);
413         order.verify(mNotificationManager, atLeastOnce())
414                 .cancelAsUser(anyString(), anyInt(), eq(userHandle));
415 
416         // Start showing a notification for disconnected once always-on.
417         vpn.setAlwaysOnPackage(PKGS[0], false);
418         order.verify(mNotificationManager)
419                 .notifyAsUser(anyString(), anyInt(), any(), eq(userHandle));
420 
421         // Stop showing the notification once connected.
422         vpn.updateState(DetailedState.CONNECTED, TAG);
423         order.verify(mNotificationManager).cancelAsUser(anyString(), anyInt(), eq(userHandle));
424 
425         // Show the notification if we disconnect again.
426         vpn.updateState(DetailedState.DISCONNECTED, TAG);
427         order.verify(mNotificationManager)
428                 .notifyAsUser(anyString(), anyInt(), any(), eq(userHandle));
429 
430         // Notification should be cleared after unsetting always-on package.
431         vpn.setAlwaysOnPackage(null, false);
432         order.verify(mNotificationManager).cancelAsUser(anyString(), anyInt(), eq(userHandle));
433     }
434 
435     @Test
testCapabilities()436     public void testCapabilities() {
437         final Vpn vpn = createVpn(primaryUser.id);
438         setMockedUsers(primaryUser);
439 
440         final Network mobile = new Network(1);
441         final Network wifi = new Network(2);
442 
443         final Map<Network, NetworkCapabilities> networks = new HashMap<>();
444         networks.put(mobile, new NetworkCapabilities()
445                 .addTransportType(TRANSPORT_CELLULAR)
446                 .addCapability(NET_CAPABILITY_INTERNET)
447                 .addCapability(NET_CAPABILITY_NOT_METERED)
448                 .addCapability(NET_CAPABILITY_NOT_CONGESTED)
449                 .setLinkDownstreamBandwidthKbps(10));
450         networks.put(wifi, new NetworkCapabilities()
451                 .addTransportType(TRANSPORT_WIFI)
452                 .addCapability(NET_CAPABILITY_INTERNET)
453                 .addCapability(NET_CAPABILITY_NOT_ROAMING)
454                 .addCapability(NET_CAPABILITY_NOT_CONGESTED)
455                 .setLinkUpstreamBandwidthKbps(20));
456         setMockedNetworks(networks);
457 
458         final NetworkCapabilities caps = new NetworkCapabilities();
459 
460         Vpn.updateCapabilities(mConnectivityManager, new Network[] { }, caps);
461         assertTrue(caps.hasTransport(TRANSPORT_VPN));
462         assertFalse(caps.hasTransport(TRANSPORT_CELLULAR));
463         assertFalse(caps.hasTransport(TRANSPORT_WIFI));
464         assertEquals(LINK_BANDWIDTH_UNSPECIFIED, caps.getLinkDownstreamBandwidthKbps());
465         assertEquals(LINK_BANDWIDTH_UNSPECIFIED, caps.getLinkUpstreamBandwidthKbps());
466         assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_METERED));
467         assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING));
468         assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED));
469 
470         Vpn.updateCapabilities(mConnectivityManager, new Network[] { mobile }, caps);
471         assertTrue(caps.hasTransport(TRANSPORT_VPN));
472         assertTrue(caps.hasTransport(TRANSPORT_CELLULAR));
473         assertFalse(caps.hasTransport(TRANSPORT_WIFI));
474         assertEquals(10, caps.getLinkDownstreamBandwidthKbps());
475         assertEquals(LINK_BANDWIDTH_UNSPECIFIED, caps.getLinkUpstreamBandwidthKbps());
476         assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_METERED));
477         assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING));
478         assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED));
479 
480         Vpn.updateCapabilities(mConnectivityManager, new Network[] { wifi }, caps);
481         assertTrue(caps.hasTransport(TRANSPORT_VPN));
482         assertFalse(caps.hasTransport(TRANSPORT_CELLULAR));
483         assertTrue(caps.hasTransport(TRANSPORT_WIFI));
484         assertEquals(LINK_BANDWIDTH_UNSPECIFIED, caps.getLinkDownstreamBandwidthKbps());
485         assertEquals(20, caps.getLinkUpstreamBandwidthKbps());
486         assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_METERED));
487         assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING));
488         assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED));
489 
490         Vpn.updateCapabilities(mConnectivityManager, new Network[] { mobile, wifi }, caps);
491         assertTrue(caps.hasTransport(TRANSPORT_VPN));
492         assertTrue(caps.hasTransport(TRANSPORT_CELLULAR));
493         assertTrue(caps.hasTransport(TRANSPORT_WIFI));
494         assertEquals(10, caps.getLinkDownstreamBandwidthKbps());
495         assertEquals(20, caps.getLinkUpstreamBandwidthKbps());
496         assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_METERED));
497         assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING));
498         assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED));
499     }
500 
501     /**
502      * Mock some methods of vpn object.
503      */
createVpn(@serIdInt int userId)504     private Vpn createVpn(@UserIdInt int userId) {
505         return new Vpn(Looper.myLooper(), mContext, mNetService, userId, mSystemServices);
506     }
507 
assertBlocked(Vpn vpn, int... uids)508     private static void assertBlocked(Vpn vpn, int... uids) {
509         for (int uid : uids) {
510             assertTrue("Uid " + uid + " should be blocked", vpn.isBlockingUid(uid));
511         }
512     }
513 
assertUnblocked(Vpn vpn, int... uids)514     private static void assertUnblocked(Vpn vpn, int... uids) {
515         for (int uid : uids) {
516             assertFalse("Uid " + uid + " should not be blocked", vpn.isBlockingUid(uid));
517         }
518     }
519 
520     /**
521      * Populate {@link #mUserManager} with a list of fake users.
522      */
setMockedUsers(UserInfo... users)523     private void setMockedUsers(UserInfo... users) {
524         final Map<Integer, UserInfo> userMap = new ArrayMap<>();
525         for (UserInfo user : users) {
526             userMap.put(user.id, user);
527         }
528 
529         /**
530          * @see UserManagerService#getUsers(boolean)
531          */
532         doAnswer(invocation -> {
533             final boolean excludeDying = (boolean) invocation.getArguments()[0];
534             final ArrayList<UserInfo> result = new ArrayList<>(users.length);
535             for (UserInfo ui : users) {
536                 if (!excludeDying || (ui.isEnabled() && !ui.partial)) {
537                     result.add(ui);
538                 }
539             }
540             return result;
541         }).when(mUserManager).getUsers(anyBoolean());
542 
543         doAnswer(invocation -> {
544             final int id = (int) invocation.getArguments()[0];
545             return userMap.get(id);
546         }).when(mUserManager).getUserInfo(anyInt());
547 
548         doAnswer(invocation -> {
549             final int id = (int) invocation.getArguments()[0];
550             return (userMap.get(id).flags & UserInfo.FLAG_ADMIN) != 0;
551         }).when(mUserManager).canHaveRestrictedProfile(anyInt());
552     }
553 
554     /**
555      * Populate {@link #mPackageManager} with a fake packageName-to-UID mapping.
556      */
setMockedPackages(final Map<String, Integer> packages)557     private void setMockedPackages(final Map<String, Integer> packages) {
558         try {
559             doAnswer(invocation -> {
560                 final String appName = (String) invocation.getArguments()[0];
561                 final int userId = (int) invocation.getArguments()[1];
562                 return UserHandle.getUid(userId, packages.get(appName));
563             }).when(mPackageManager).getPackageUidAsUser(anyString(), anyInt());
564         } catch (Exception e) {
565         }
566     }
567 
setMockedNetworks(final Map<Network, NetworkCapabilities> networks)568     private void setMockedNetworks(final Map<Network, NetworkCapabilities> networks) {
569         doAnswer(invocation -> {
570             final Network network = (Network) invocation.getArguments()[0];
571             return networks.get(network);
572         }).when(mConnectivityManager).getNetworkCapabilities(any());
573     }
574 
575     // Need multiple copies of this, but Java's Stream objects can't be reused or
576     // duplicated.
publicIpV4Routes()577     private Stream<String> publicIpV4Routes() {
578         return Stream.of(
579                 "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",
580                 "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",
581                 "172.0.0.0/12", "172.32.0.0/11", "172.64.0.0/10", "172.128.0.0/9",
582                 "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",
583                 "192.160.0.0/13", "192.169.0.0/16", "192.170.0.0/15", "192.172.0.0/14",
584                 "192.176.0.0/12", "192.192.0.0/10", "193.0.0.0/8", "194.0.0.0/7",
585                 "196.0.0.0/6", "200.0.0.0/5", "208.0.0.0/4");
586     }
587 
publicIpV6Routes()588     private Stream<String> publicIpV6Routes() {
589         return Stream.of(
590                 "::/1", "8000::/2", "c000::/3", "e000::/4", "f000::/5", "f800::/6",
591                 "fe00::/8", "2605:ef80:e:af1d::/64");
592     }
593 
594     @Test
testProvidesRoutesToMostDestinations()595     public void testProvidesRoutesToMostDestinations() {
596         final LinkProperties lp = new LinkProperties();
597 
598         // Default route provides routes to all IPv4 destinations.
599         lp.addRoute(new RouteInfo(new IpPrefix("0.0.0.0/0")));
600         assertTrue(Vpn.providesRoutesToMostDestinations(lp));
601 
602         // Empty LP provides routes to no destination
603         lp.clear();
604         assertFalse(Vpn.providesRoutesToMostDestinations(lp));
605 
606         // All IPv4 routes except for local networks. This is the case most relevant
607         // to this function. It provides routes to almost the entire space.
608         // (clone the stream so that we can reuse it later)
609         publicIpV4Routes().forEach(s -> lp.addRoute(new RouteInfo(new IpPrefix(s))));
610         assertTrue(Vpn.providesRoutesToMostDestinations(lp));
611 
612         // Removing a 16-bit prefix, which is 65536 addresses. This is still enough to
613         // provide routes to "most" destinations.
614         lp.removeRoute(new RouteInfo(new IpPrefix("192.169.0.0/16")));
615         assertTrue(Vpn.providesRoutesToMostDestinations(lp));
616 
617         // Remove the /2 route, which represent a quarter of the available routing space.
618         // This LP does not provides routes to "most" destinations any more.
619         lp.removeRoute(new RouteInfo(new IpPrefix("64.0.0.0/2")));
620         assertFalse(Vpn.providesRoutesToMostDestinations(lp));
621 
622         lp.clear();
623         publicIpV6Routes().forEach(s -> lp.addRoute(new RouteInfo(new IpPrefix(s))));
624         assertTrue(Vpn.providesRoutesToMostDestinations(lp));
625 
626         lp.removeRoute(new RouteInfo(new IpPrefix("::/1")));
627         assertFalse(Vpn.providesRoutesToMostDestinations(lp));
628 
629         // V6 does not provide sufficient coverage but v4 does
630         publicIpV4Routes().forEach(s -> lp.addRoute(new RouteInfo(new IpPrefix(s))));
631         assertTrue(Vpn.providesRoutesToMostDestinations(lp));
632 
633         // V4 still does
634         lp.removeRoute(new RouteInfo(new IpPrefix("192.169.0.0/16")));
635         assertTrue(Vpn.providesRoutesToMostDestinations(lp));
636 
637         // V4 does not any more
638         lp.removeRoute(new RouteInfo(new IpPrefix("64.0.0.0/2")));
639         assertFalse(Vpn.providesRoutesToMostDestinations(lp));
640 
641         // V4 does not, but V6 has sufficient coverage again
642         lp.addRoute(new RouteInfo(new IpPrefix("::/1")));
643         assertTrue(Vpn.providesRoutesToMostDestinations(lp));
644     }
645 
646     @Test
testDoesNotLockUpWithTooManyRoutes()647     public void testDoesNotLockUpWithTooManyRoutes() {
648         final LinkProperties lp = new LinkProperties();
649         final byte[] ad = new byte[4];
650         // Actually evaluating this many routes under 1500ms is impossible on
651         // current hardware and for some time, as the algorithm is O(n²).
652         // Make sure the system has a safeguard against this and does not
653         // lock up.
654         final int MAX_ROUTES = 4000;
655         final long MAX_ALLOWED_TIME_MS = 1500;
656         for (int i = 0; i < MAX_ROUTES; ++i) {
657             ad[0] = (byte)((i >> 24) & 0xFF);
658             ad[1] = (byte)((i >> 16) & 0xFF);
659             ad[2] = (byte)((i >> 8) & 0xFF);
660             ad[3] = (byte)(i & 0xFF);
661             try {
662                 lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.getByAddress(ad), 32)));
663             } catch (UnknownHostException e) {
664                 // UnknownHostException is only thrown for an address of illegal length,
665                 // which can't happen in the case above.
666             }
667         }
668         final long start = SystemClock.currentThreadTimeMillis();
669         assertTrue(Vpn.providesRoutesToMostDestinations(lp));
670         final long end = SystemClock.currentThreadTimeMillis();
671         assertTrue(end - start < MAX_ALLOWED_TIME_MS);
672     }
673 }
674