blob: b5d1ff9a029858220df982facc989a5ac8763c9d [file] [log] [blame]
Robin Lee4d03abc2016-05-09 12:32:27 +01001/*
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
17package com.android.server.connectivity;
18
19import static android.content.pm.UserInfo.FLAG_ADMIN;
20import static android.content.pm.UserInfo.FLAG_MANAGED_PROFILE;
21import static android.content.pm.UserInfo.FLAG_PRIMARY;
22import static android.content.pm.UserInfo.FLAG_RESTRICTED;
Jeff Sharkey72f9c422017-10-27 17:22:59 -060023import static android.net.NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED;
24import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
Jeff Sharkey9b2a10f2018-01-17 13:27:03 +090025import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED;
Jeff Sharkey72f9c422017-10-27 17:22:59 -060026import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
27import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
28import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
29import static android.net.NetworkCapabilities.TRANSPORT_VPN;
30import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
Rubin Xuc63e48d2019-02-19 16:56:47 +000031import static android.net.RouteInfo.RTN_UNREACHABLE;
Jeff Sharkey72f9c422017-10-27 17:22:59 -060032
Hugo Benichi4a0c5d72017-10-11 11:26:25 +090033import static org.junit.Assert.assertEquals;
34import static org.junit.Assert.assertFalse;
35import static org.junit.Assert.assertTrue;
Jeff Sharkey72f9c422017-10-27 17:22:59 -060036import static org.mockito.AdditionalMatchers.aryEq;
37import static org.mockito.ArgumentMatchers.any;
38import static org.mockito.ArgumentMatchers.anyBoolean;
39import static org.mockito.ArgumentMatchers.anyInt;
40import static org.mockito.ArgumentMatchers.anyString;
41import static org.mockito.ArgumentMatchers.eq;
42import static org.mockito.Mockito.atLeastOnce;
43import static org.mockito.Mockito.doAnswer;
44import static org.mockito.Mockito.doNothing;
45import static org.mockito.Mockito.inOrder;
46import static org.mockito.Mockito.times;
47import static org.mockito.Mockito.verify;
48import static org.mockito.Mockito.when;
Robin Lee4d03abc2016-05-09 12:32:27 +010049
50import android.annotation.UserIdInt;
Robin Lee17e61832016-05-09 13:46:28 +010051import android.app.AppOpsManager;
Tony Makde7f7d12016-06-30 11:19:20 +010052import android.app.NotificationManager;
Robin Lee4d03abc2016-05-09 12:32:27 +010053import android.content.Context;
Robin Leeb8c2a2b2017-03-10 16:17:06 +000054import android.content.pm.ApplicationInfo;
Robin Lee4d03abc2016-05-09 12:32:27 +010055import android.content.pm.PackageManager;
Charles Hea0a87e82017-05-15 17:07:18 +010056import android.content.pm.ResolveInfo;
57import android.content.pm.ServiceInfo;
Robin Lee4d03abc2016-05-09 12:32:27 +010058import android.content.pm.UserInfo;
Charles Hec17f50f2017-08-16 13:14:13 +010059import android.content.res.Resources;
Jeff Sharkey72f9c422017-10-27 17:22:59 -060060import android.net.ConnectivityManager;
Chalard Jeanadbf1d02018-02-26 11:52:46 +090061import android.net.IpPrefix;
62import android.net.LinkProperties;
Jeff Sharkey72f9c422017-10-27 17:22:59 -060063import android.net.Network;
64import android.net.NetworkCapabilities;
Tony Makde7f7d12016-06-30 11:19:20 +010065import android.net.NetworkInfo.DetailedState;
Chalard Jeanadbf1d02018-02-26 11:52:46 +090066import android.net.RouteInfo;
Robin Lee4d03abc2016-05-09 12:32:27 +010067import android.net.UidRange;
Charles Hea0a87e82017-05-15 17:07:18 +010068import android.net.VpnService;
69import android.os.Build.VERSION_CODES;
70import android.os.Bundle;
Robin Lee4d03abc2016-05-09 12:32:27 +010071import android.os.INetworkManagementService;
72import android.os.Looper;
Chalard Jeane0d26f62018-03-29 14:10:44 +090073import android.os.SystemClock;
Robin Lee4d03abc2016-05-09 12:32:27 +010074import android.os.UserHandle;
75import android.os.UserManager;
Hugo Benichi4a0c5d72017-10-11 11:26:25 +090076import android.support.test.filters.SmallTest;
Jeff Sharkey72f9c422017-10-27 17:22:59 -060077import android.support.test.runner.AndroidJUnit4;
Robin Lee4d03abc2016-05-09 12:32:27 +010078import android.util.ArrayMap;
79import android.util.ArraySet;
80
Charles Hec17f50f2017-08-16 13:14:13 +010081import com.android.internal.R;
Robin Leec3736bc2017-03-10 16:19:54 +000082import com.android.internal.net.VpnConfig;
83
Hugo Benichi4a0c5d72017-10-11 11:26:25 +090084import org.junit.Before;
85import org.junit.Test;
Jeff Sharkey72f9c422017-10-27 17:22:59 -060086import org.junit.runner.RunWith;
Robin Leeb8c2a2b2017-03-10 16:17:06 +000087import org.mockito.Answers;
Tony Makde7f7d12016-06-30 11:19:20 +010088import org.mockito.InOrder;
Robin Lee4d03abc2016-05-09 12:32:27 +010089import org.mockito.Mock;
90import org.mockito.MockitoAnnotations;
91
Chalard Jeane0d26f62018-03-29 14:10:44 +090092import java.net.Inet4Address;
Rubin Xuc63e48d2019-02-19 16:56:47 +000093import java.net.Inet6Address;
Chalard Jeane0d26f62018-03-29 14:10:44 +090094import java.net.UnknownHostException;
Charles Hea0a87e82017-05-15 17:07:18 +010095import java.util.ArrayList;
96import java.util.Arrays;
97import java.util.Collections;
Jeff Sharkey72f9c422017-10-27 17:22:59 -060098import java.util.HashMap;
Charles Hea0a87e82017-05-15 17:07:18 +010099import java.util.Map;
100import java.util.Set;
Chalard Jeanadbf1d02018-02-26 11:52:46 +0900101import java.util.stream.Stream;
Hugo Benichi4a0c5d72017-10-11 11:26:25 +0900102
Robin Lee4d03abc2016-05-09 12:32:27 +0100103/**
104 * Tests for {@link Vpn}.
105 *
106 * Build, install and run with:
Hugo Benichi4a0c5d72017-10-11 11:26:25 +0900107 * runtest frameworks-net -c com.android.server.connectivity.VpnTest
Robin Lee4d03abc2016-05-09 12:32:27 +0100108 */
Hugo Benichi4a0c5d72017-10-11 11:26:25 +0900109@RunWith(AndroidJUnit4.class)
110@SmallTest
111public class VpnTest {
Robin Lee4d03abc2016-05-09 12:32:27 +0100112 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
Robin Lee17e61832016-05-09 13:46:28 +0100126 /**
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++) {
138 mPackages.put(PKGS[i], PKG_UIDS[i]);
139 }
140 }
141
Robin Leeb8c2a2b2017-03-10 16:17:06 +0000142 @Mock(answer = Answers.RETURNS_DEEP_STUBS) private Context mContext;
Robin Lee4d03abc2016-05-09 12:32:27 +0100143 @Mock private UserManager mUserManager;
144 @Mock private PackageManager mPackageManager;
145 @Mock private INetworkManagementService mNetService;
Robin Lee17e61832016-05-09 13:46:28 +0100146 @Mock private AppOpsManager mAppOps;
Tony Makde7f7d12016-06-30 11:19:20 +0100147 @Mock private NotificationManager mNotificationManager;
Robin Leeb8c2a2b2017-03-10 16:17:06 +0000148 @Mock private Vpn.SystemServices mSystemServices;
Jeff Sharkey72f9c422017-10-27 17:22:59 -0600149 @Mock private ConnectivityManager mConnectivityManager;
Robin Lee4d03abc2016-05-09 12:32:27 +0100150
Hugo Benichi4a0c5d72017-10-11 11:26:25 +0900151 @Before
Robin Lee4d03abc2016-05-09 12:32:27 +0100152 public void setUp() throws Exception {
153 MockitoAnnotations.initMocks(this);
Robin Leec3736bc2017-03-10 16:19:54 +0000154
Robin Lee4d03abc2016-05-09 12:32:27 +0100155 when(mContext.getPackageManager()).thenReturn(mPackageManager);
Robin Lee17e61832016-05-09 13:46:28 +0100156 setMockedPackages(mPackages);
Robin Leec3736bc2017-03-10 16:19:54 +0000157
Tony Makde7f7d12016-06-30 11:19:20 +0100158 when(mContext.getPackageName()).thenReturn(Vpn.class.getPackage().getName());
Robin Lee4d03abc2016-05-09 12:32:27 +0100159 when(mContext.getSystemService(eq(Context.USER_SERVICE))).thenReturn(mUserManager);
Robin Lee17e61832016-05-09 13:46:28 +0100160 when(mContext.getSystemService(eq(Context.APP_OPS_SERVICE))).thenReturn(mAppOps);
Tony Makde7f7d12016-06-30 11:19:20 +0100161 when(mContext.getSystemService(eq(Context.NOTIFICATION_SERVICE)))
162 .thenReturn(mNotificationManager);
Jeff Sharkey72f9c422017-10-27 17:22:59 -0600163 when(mContext.getSystemService(eq(Context.CONNECTIVITY_SERVICE)))
164 .thenReturn(mConnectivityManager);
Charles Hec17f50f2017-08-16 13:14:13 +0100165 when(mContext.getString(R.string.config_customVpnAlwaysOnDisconnectedDialogComponent))
166 .thenReturn(Resources.getSystem().getString(
167 R.string.config_customVpnAlwaysOnDisconnectedDialogComponent));
Robin Leeb8c2a2b2017-03-10 16:17:06 +0000168
169 // Used by {@link Notification.Builder}
170 ApplicationInfo applicationInfo = new ApplicationInfo();
Charles Hea0a87e82017-05-15 17:07:18 +0100171 applicationInfo.targetSdkVersion = VERSION_CODES.CUR_DEVELOPMENT;
Robin Leeb8c2a2b2017-03-10 16:17:06 +0000172 when(mContext.getApplicationInfo()).thenReturn(applicationInfo);
Varun Anand1215f092019-01-14 11:45:33 -0800173 when(mPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), anyInt()))
174 .thenReturn(applicationInfo);
Robin Leeb8c2a2b2017-03-10 16:17:06 +0000175
Robin Lee4d03abc2016-05-09 12:32:27 +0100176 doNothing().when(mNetService).registerObserver(any());
177 }
178
Hugo Benichi4a0c5d72017-10-11 11:26:25 +0900179 @Test
Robin Lee4d03abc2016-05-09 12:32:27 +0100180 public void testRestrictedProfilesAreAddedToVpn() {
181 setMockedUsers(primaryUser, secondaryUser, restrictedProfileA, restrictedProfileB);
182
Robin Leeb8c2a2b2017-03-10 16:17:06 +0000183 final Vpn vpn = createVpn(primaryUser.id);
Robin Lee4d03abc2016-05-09 12:32:27 +0100184 final Set<UidRange> ranges = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id,
185 null, null);
186
187 assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] {
188 UidRange.createForUser(primaryUser.id),
189 UidRange.createForUser(restrictedProfileA.id)
190 })), ranges);
191 }
192
Hugo Benichi4a0c5d72017-10-11 11:26:25 +0900193 @Test
Robin Lee4d03abc2016-05-09 12:32:27 +0100194 public void testManagedProfilesAreNotAddedToVpn() {
195 setMockedUsers(primaryUser, managedProfileA);
196
Robin Leeb8c2a2b2017-03-10 16:17:06 +0000197 final Vpn vpn = createVpn(primaryUser.id);
Robin Lee4d03abc2016-05-09 12:32:27 +0100198 final Set<UidRange> ranges = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id,
199 null, null);
200
201 assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] {
202 UidRange.createForUser(primaryUser.id)
203 })), ranges);
204 }
205
Hugo Benichi4a0c5d72017-10-11 11:26:25 +0900206 @Test
Robin Lee4d03abc2016-05-09 12:32:27 +0100207 public void testAddUserToVpnOnlyAddsOneUser() {
208 setMockedUsers(primaryUser, restrictedProfileA, managedProfileA);
209
Robin Leeb8c2a2b2017-03-10 16:17:06 +0000210 final Vpn vpn = createVpn(primaryUser.id);
Robin Lee4d03abc2016-05-09 12:32:27 +0100211 final Set<UidRange> ranges = new ArraySet<>();
212 vpn.addUserToRanges(ranges, primaryUser.id, null, null);
213
214 assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] {
215 UidRange.createForUser(primaryUser.id)
216 })), ranges);
217 }
218
Hugo Benichi4a0c5d72017-10-11 11:26:25 +0900219 @Test
Robin Lee4d03abc2016-05-09 12:32:27 +0100220 public void testUidWhiteAndBlacklist() throws Exception {
Robin Leeb8c2a2b2017-03-10 16:17:06 +0000221 final Vpn vpn = createVpn(primaryUser.id);
Robin Lee4d03abc2016-05-09 12:32:27 +0100222 final UidRange user = UidRange.createForUser(primaryUser.id);
Robin Lee17e61832016-05-09 13:46:28 +0100223 final String[] packages = {PKGS[0], PKGS[1], PKGS[2]};
Robin Lee4d03abc2016-05-09 12:32:27 +0100224
225 // Whitelist
226 final Set<UidRange> allow = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id,
Robin Lee17e61832016-05-09 13:46:28 +0100227 Arrays.asList(packages), null);
Robin Lee4d03abc2016-05-09 12:32:27 +0100228 assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] {
Robin Lee17e61832016-05-09 13:46:28 +0100229 new UidRange(user.start + PKG_UIDS[0], user.start + PKG_UIDS[0]),
230 new UidRange(user.start + PKG_UIDS[1], user.start + PKG_UIDS[2])
Robin Lee4d03abc2016-05-09 12:32:27 +0100231 })), allow);
232
233 // Blacklist
234 final Set<UidRange> disallow = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id,
Robin Lee17e61832016-05-09 13:46:28 +0100235 null, Arrays.asList(packages));
Robin Lee4d03abc2016-05-09 12:32:27 +0100236 assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] {
Robin Lee17e61832016-05-09 13:46:28 +0100237 new UidRange(user.start, user.start + PKG_UIDS[0] - 1),
238 new UidRange(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[1] - 1),
239 /* Empty range between UIDS[1] and UIDS[2], should be excluded, */
240 new UidRange(user.start + PKG_UIDS[2] + 1, user.stop)
Robin Lee4d03abc2016-05-09 12:32:27 +0100241 })), disallow);
242 }
243
Hugo Benichi4a0c5d72017-10-11 11:26:25 +0900244 @Test
Pavel Grafovcb3b8952018-12-14 13:51:07 +0000245 public void testGetAlwaysAndOnGetLockDown() throws Exception {
246 final Vpn vpn = createVpn(primaryUser.id);
247
248 // Default state.
249 assertFalse(vpn.getAlwaysOn());
250 assertFalse(vpn.getLockdown());
251
252 // Set always-on without lockdown.
Pavel Grafova462bcb2019-01-25 08:50:06 +0000253 assertTrue(vpn.setAlwaysOnPackage(PKGS[1], false, Collections.emptyList()));
Pavel Grafovcb3b8952018-12-14 13:51:07 +0000254 assertTrue(vpn.getAlwaysOn());
255 assertFalse(vpn.getLockdown());
256
257 // Set always-on with lockdown.
Pavel Grafova462bcb2019-01-25 08:50:06 +0000258 assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true, Collections.emptyList()));
Pavel Grafovcb3b8952018-12-14 13:51:07 +0000259 assertTrue(vpn.getAlwaysOn());
260 assertTrue(vpn.getLockdown());
261
262 // Remove always-on configuration.
Pavel Grafova462bcb2019-01-25 08:50:06 +0000263 assertTrue(vpn.setAlwaysOnPackage(null, false, Collections.emptyList()));
Pavel Grafovcb3b8952018-12-14 13:51:07 +0000264 assertFalse(vpn.getAlwaysOn());
265 assertFalse(vpn.getLockdown());
266 }
267
268 @Test
Robin Lee17e61832016-05-09 13:46:28 +0100269 public void testLockdownChangingPackage() throws Exception {
Robin Leeb8c2a2b2017-03-10 16:17:06 +0000270 final Vpn vpn = createVpn(primaryUser.id);
Robin Lee17e61832016-05-09 13:46:28 +0100271 final UidRange user = UidRange.createForUser(primaryUser.id);
272
273 // Default state.
Tony Makde7f7d12016-06-30 11:19:20 +0100274 assertUnblocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[1], user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]);
Robin Lee17e61832016-05-09 13:46:28 +0100275
276 // Set always-on without lockdown.
Pavel Grafova462bcb2019-01-25 08:50:06 +0000277 assertTrue(vpn.setAlwaysOnPackage(PKGS[1], false, null));
Tony Makde7f7d12016-06-30 11:19:20 +0100278 assertUnblocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[1], user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]);
Robin Lee17e61832016-05-09 13:46:28 +0100279
280 // Set always-on with lockdown.
Pavel Grafova462bcb2019-01-25 08:50:06 +0000281 assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true, null));
Robin Lee17e61832016-05-09 13:46:28 +0100282 verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
283 new UidRange(user.start, user.start + PKG_UIDS[1] - 1),
284 new UidRange(user.start + PKG_UIDS[1] + 1, user.stop)
285 }));
Tony Makde7f7d12016-06-30 11:19:20 +0100286 assertBlocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]);
287 assertUnblocked(vpn, user.start + PKG_UIDS[1]);
Robin Lee17e61832016-05-09 13:46:28 +0100288
289 // Switch to another app.
Pavel Grafova462bcb2019-01-25 08:50:06 +0000290 assertTrue(vpn.setAlwaysOnPackage(PKGS[3], true, null));
Robin Lee17e61832016-05-09 13:46:28 +0100291 verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[] {
292 new UidRange(user.start, user.start + PKG_UIDS[1] - 1),
293 new UidRange(user.start + PKG_UIDS[1] + 1, user.stop)
294 }));
295 verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
296 new UidRange(user.start, user.start + PKG_UIDS[3] - 1),
297 new UidRange(user.start + PKG_UIDS[3] + 1, user.stop)
298 }));
Tony Makde7f7d12016-06-30 11:19:20 +0100299 assertBlocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[1], user.start + PKG_UIDS[2]);
300 assertUnblocked(vpn, user.start + PKG_UIDS[3]);
Robin Lee17e61832016-05-09 13:46:28 +0100301 }
302
Hugo Benichi4a0c5d72017-10-11 11:26:25 +0900303 @Test
Pavel Grafova462bcb2019-01-25 08:50:06 +0000304 public void testLockdownWhitelist() throws Exception {
305 final Vpn vpn = createVpn(primaryUser.id);
306 final UidRange user = UidRange.createForUser(primaryUser.id);
307
308 // Set always-on with lockdown and whitelist app PKGS[2] from lockdown.
309 assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true, Collections.singletonList(PKGS[2])));
310 verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
311 new UidRange(user.start, user.start + PKG_UIDS[1] - 1),
312 new UidRange(user.start + PKG_UIDS[2] + 1, user.stop)
313 }));
314 assertBlocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[3]);
315 assertUnblocked(vpn, user.start + PKG_UIDS[1], user.start + PKG_UIDS[2]);
316
317 // Change whitelisted app to PKGS[3].
318 assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true, Collections.singletonList(PKGS[3])));
319 verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[] {
320 new UidRange(user.start + PKG_UIDS[2] + 1, user.stop)
321 }));
322 verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
323 new UidRange(user.start + PKG_UIDS[1] + 1, user.start + PKG_UIDS[3] - 1),
324 new UidRange(user.start + PKG_UIDS[3] + 1, user.stop)
325 }));
326 assertBlocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[2]);
327 assertUnblocked(vpn, user.start + PKG_UIDS[1], user.start + PKG_UIDS[3]);
328
329 // Change the VPN app.
330 assertTrue(vpn.setAlwaysOnPackage(PKGS[0], true, Collections.singletonList(PKGS[3])));
331 verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[] {
332 new UidRange(user.start, user.start + PKG_UIDS[1] - 1),
333 new UidRange(user.start + PKG_UIDS[1] + 1, user.start + PKG_UIDS[3] - 1)
334 }));
335 verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
336 new UidRange(user.start, user.start + PKG_UIDS[0] - 1),
337 new UidRange(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[3] - 1)
338 }));
339 assertBlocked(vpn, user.start + PKG_UIDS[1], user.start + PKG_UIDS[2]);
340 assertUnblocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[3]);
341
342 // Remove the whitelist.
343 assertTrue(vpn.setAlwaysOnPackage(PKGS[0], true, null));
344 verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[] {
345 new UidRange(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[3] - 1),
346 new UidRange(user.start + PKG_UIDS[3] + 1, user.stop)
347 }));
348 verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
349 new UidRange(user.start + PKG_UIDS[0] + 1, user.stop),
350 }));
351 assertBlocked(vpn, user.start + PKG_UIDS[1], user.start + PKG_UIDS[2],
352 user.start + PKG_UIDS[3]);
353 assertUnblocked(vpn, user.start + PKG_UIDS[0]);
354
355 // Add the whitelist.
356 assertTrue(vpn.setAlwaysOnPackage(PKGS[0], true, Collections.singletonList(PKGS[1])));
357 verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[] {
358 new UidRange(user.start + PKG_UIDS[0] + 1, user.stop)
359 }));
360 verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
361 new UidRange(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[1] - 1),
362 new UidRange(user.start + PKG_UIDS[1] + 1, user.stop)
363 }));
364 assertBlocked(vpn, user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]);
365 assertUnblocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[1]);
366
367 // Try whitelisting a package with a comma, should be rejected.
368 assertFalse(vpn.setAlwaysOnPackage(PKGS[0], true, Collections.singletonList("a.b,c.d")));
369
370 // Pass a non-existent packages in the whitelist, they (and only they) should be ignored.
371 // Whitelisted package should change from PGKS[1] to PKGS[2].
372 assertTrue(vpn.setAlwaysOnPackage(PKGS[0], true,
373 Arrays.asList("com.foo.app", PKGS[2], "com.bar.app")));
374 verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[]{
375 new UidRange(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[1] - 1),
376 new UidRange(user.start + PKG_UIDS[1] + 1, user.stop)
377 }));
378 verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[]{
379 new UidRange(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[2] - 1),
380 new UidRange(user.start + PKG_UIDS[2] + 1, user.stop)
381 }));
382 }
383
384 @Test
Robin Lee17e61832016-05-09 13:46:28 +0100385 public void testLockdownAddingAProfile() throws Exception {
Robin Leeb8c2a2b2017-03-10 16:17:06 +0000386 final Vpn vpn = createVpn(primaryUser.id);
Robin Lee17e61832016-05-09 13:46:28 +0100387 setMockedUsers(primaryUser);
388
389 // Make a copy of the restricted profile, as we're going to mark it deleted halfway through.
390 final UserInfo tempProfile = new UserInfo(restrictedProfileA.id, restrictedProfileA.name,
391 restrictedProfileA.flags);
392 tempProfile.restrictedProfileParentId = primaryUser.id;
393
394 final UidRange user = UidRange.createForUser(primaryUser.id);
395 final UidRange profile = UidRange.createForUser(tempProfile.id);
396
397 // Set lockdown.
Pavel Grafova462bcb2019-01-25 08:50:06 +0000398 assertTrue(vpn.setAlwaysOnPackage(PKGS[3], true, null));
Robin Lee17e61832016-05-09 13:46:28 +0100399 verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
400 new UidRange(user.start, user.start + PKG_UIDS[3] - 1),
401 new UidRange(user.start + PKG_UIDS[3] + 1, user.stop)
402 }));
403
404 // Verify restricted user isn't affected at first.
Tony Makde7f7d12016-06-30 11:19:20 +0100405 assertUnblocked(vpn, profile.start + PKG_UIDS[0]);
Robin Lee17e61832016-05-09 13:46:28 +0100406
407 // Add the restricted user.
408 setMockedUsers(primaryUser, tempProfile);
409 vpn.onUserAdded(tempProfile.id);
410 verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
411 new UidRange(profile.start, profile.start + PKG_UIDS[3] - 1),
412 new UidRange(profile.start + PKG_UIDS[3] + 1, profile.stop)
413 }));
414
415 // Remove the restricted user.
416 tempProfile.partial = true;
417 vpn.onUserRemoved(tempProfile.id);
418 verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[] {
419 new UidRange(profile.start, profile.start + PKG_UIDS[3] - 1),
420 new UidRange(profile.start + PKG_UIDS[3] + 1, profile.stop)
421 }));
422 }
423
Hugo Benichi4a0c5d72017-10-11 11:26:25 +0900424 @Test
Robin Leec3736bc2017-03-10 16:19:54 +0000425 public void testLockdownRuleRepeatability() throws Exception {
426 final Vpn vpn = createVpn(primaryUser.id);
427
428 // Given legacy lockdown is already enabled,
429 vpn.setLockdown(true);
430 verify(mNetService, times(1)).setAllowOnlyVpnForUids(
431 eq(true), aryEq(new UidRange[] {UidRange.createForUser(primaryUser.id)}));
432
433 // Enabling legacy lockdown twice should do nothing.
434 vpn.setLockdown(true);
435 verify(mNetService, times(1)).setAllowOnlyVpnForUids(anyBoolean(), any(UidRange[].class));
436
437 // And disabling should remove the rules exactly once.
438 vpn.setLockdown(false);
439 verify(mNetService, times(1)).setAllowOnlyVpnForUids(
440 eq(false), aryEq(new UidRange[] {UidRange.createForUser(primaryUser.id)}));
441
442 // Removing the lockdown again should have no effect.
443 vpn.setLockdown(false);
444 verify(mNetService, times(2)).setAllowOnlyVpnForUids(anyBoolean(), any(UidRange[].class));
445 }
446
Hugo Benichi4a0c5d72017-10-11 11:26:25 +0900447 @Test
Robin Leec3736bc2017-03-10 16:19:54 +0000448 public void testLockdownRuleReversibility() throws Exception {
449 final Vpn vpn = createVpn(primaryUser.id);
450
451 final UidRange[] entireUser = {
452 UidRange.createForUser(primaryUser.id)
453 };
454 final UidRange[] exceptPkg0 = {
455 new UidRange(entireUser[0].start, entireUser[0].start + PKG_UIDS[0] - 1),
456 new UidRange(entireUser[0].start + PKG_UIDS[0] + 1, entireUser[0].stop)
457 };
458
459 final InOrder order = inOrder(mNetService);
460
461 // Given lockdown is enabled with no package (legacy VPN),
462 vpn.setLockdown(true);
463 order.verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(entireUser));
464
465 // When a new VPN package is set the rules should change to cover that package.
466 vpn.prepare(null, PKGS[0]);
467 order.verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(entireUser));
468 order.verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(exceptPkg0));
469
470 // When that VPN package is unset, everything should be undone again in reverse.
471 vpn.prepare(null, VpnConfig.LEGACY_VPN);
472 order.verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(exceptPkg0));
473 order.verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(entireUser));
474 }
475
Hugo Benichi4a0c5d72017-10-11 11:26:25 +0900476 @Test
Charles Hea0a87e82017-05-15 17:07:18 +0100477 public void testIsAlwaysOnPackageSupported() throws Exception {
478 final Vpn vpn = createVpn(primaryUser.id);
479
480 ApplicationInfo appInfo = new ApplicationInfo();
481 when(mPackageManager.getApplicationInfoAsUser(eq(PKGS[0]), anyInt(), eq(primaryUser.id)))
482 .thenReturn(appInfo);
483
484 ServiceInfo svcInfo = new ServiceInfo();
485 ResolveInfo resInfo = new ResolveInfo();
486 resInfo.serviceInfo = svcInfo;
487 when(mPackageManager.queryIntentServicesAsUser(any(), eq(PackageManager.GET_META_DATA),
488 eq(primaryUser.id)))
489 .thenReturn(Collections.singletonList(resInfo));
490
491 // null package name should return false
492 assertFalse(vpn.isAlwaysOnPackageSupported(null));
493
494 // Pre-N apps are not supported
495 appInfo.targetSdkVersion = VERSION_CODES.M;
496 assertFalse(vpn.isAlwaysOnPackageSupported(PKGS[0]));
497
498 // N+ apps are supported by default
499 appInfo.targetSdkVersion = VERSION_CODES.N;
500 assertTrue(vpn.isAlwaysOnPackageSupported(PKGS[0]));
501
502 // Apps that opt out explicitly are not supported
503 appInfo.targetSdkVersion = VERSION_CODES.CUR_DEVELOPMENT;
504 Bundle metaData = new Bundle();
Charles He5da5ae32017-08-15 15:30:22 +0100505 metaData.putBoolean(VpnService.SERVICE_META_DATA_SUPPORTS_ALWAYS_ON, false);
Charles Hea0a87e82017-05-15 17:07:18 +0100506 svcInfo.metaData = metaData;
507 assertFalse(vpn.isAlwaysOnPackageSupported(PKGS[0]));
508 }
509
Hugo Benichi4a0c5d72017-10-11 11:26:25 +0900510 @Test
Tony Makde7f7d12016-06-30 11:19:20 +0100511 public void testNotificationShownForAlwaysOnApp() {
Robin Leeb8c2a2b2017-03-10 16:17:06 +0000512 final UserHandle userHandle = UserHandle.of(primaryUser.id);
513 final Vpn vpn = createVpn(primaryUser.id);
Tony Makde7f7d12016-06-30 11:19:20 +0100514 setMockedUsers(primaryUser);
515
Robin Leeb8c2a2b2017-03-10 16:17:06 +0000516 final InOrder order = inOrder(mNotificationManager);
517
Tony Makde7f7d12016-06-30 11:19:20 +0100518 // Don't show a notification for regular disconnected states.
519 vpn.updateState(DetailedState.DISCONNECTED, TAG);
Robin Leeb8c2a2b2017-03-10 16:17:06 +0000520 order.verify(mNotificationManager, atLeastOnce())
521 .cancelAsUser(anyString(), anyInt(), eq(userHandle));
Tony Makde7f7d12016-06-30 11:19:20 +0100522
523 // Start showing a notification for disconnected once always-on.
Pavel Grafova462bcb2019-01-25 08:50:06 +0000524 vpn.setAlwaysOnPackage(PKGS[0], false, null);
Robin Leeb8c2a2b2017-03-10 16:17:06 +0000525 order.verify(mNotificationManager)
526 .notifyAsUser(anyString(), anyInt(), any(), eq(userHandle));
Tony Makde7f7d12016-06-30 11:19:20 +0100527
528 // Stop showing the notification once connected.
529 vpn.updateState(DetailedState.CONNECTED, TAG);
Robin Leeb8c2a2b2017-03-10 16:17:06 +0000530 order.verify(mNotificationManager).cancelAsUser(anyString(), anyInt(), eq(userHandle));
Tony Makde7f7d12016-06-30 11:19:20 +0100531
532 // Show the notification if we disconnect again.
533 vpn.updateState(DetailedState.DISCONNECTED, TAG);
Robin Leeb8c2a2b2017-03-10 16:17:06 +0000534 order.verify(mNotificationManager)
535 .notifyAsUser(anyString(), anyInt(), any(), eq(userHandle));
Tony Makde7f7d12016-06-30 11:19:20 +0100536
537 // Notification should be cleared after unsetting always-on package.
Pavel Grafova462bcb2019-01-25 08:50:06 +0000538 vpn.setAlwaysOnPackage(null, false, null);
Robin Leeb8c2a2b2017-03-10 16:17:06 +0000539 order.verify(mNotificationManager).cancelAsUser(anyString(), anyInt(), eq(userHandle));
Tony Makde7f7d12016-06-30 11:19:20 +0100540 }
541
Jeff Sharkey72f9c422017-10-27 17:22:59 -0600542 @Test
543 public void testCapabilities() {
544 final Vpn vpn = createVpn(primaryUser.id);
545 setMockedUsers(primaryUser);
546
547 final Network mobile = new Network(1);
548 final Network wifi = new Network(2);
549
550 final Map<Network, NetworkCapabilities> networks = new HashMap<>();
Varun Anand1215f092019-01-14 11:45:33 -0800551 networks.put(
552 mobile,
553 new NetworkCapabilities()
554 .addTransportType(TRANSPORT_CELLULAR)
555 .addCapability(NET_CAPABILITY_INTERNET)
556 .addCapability(NET_CAPABILITY_NOT_CONGESTED)
557 .setLinkDownstreamBandwidthKbps(10));
558 networks.put(
559 wifi,
560 new NetworkCapabilities()
561 .addTransportType(TRANSPORT_WIFI)
562 .addCapability(NET_CAPABILITY_INTERNET)
563 .addCapability(NET_CAPABILITY_NOT_METERED)
564 .addCapability(NET_CAPABILITY_NOT_ROAMING)
565 .addCapability(NET_CAPABILITY_NOT_CONGESTED)
566 .setLinkUpstreamBandwidthKbps(20));
Jeff Sharkey72f9c422017-10-27 17:22:59 -0600567 setMockedNetworks(networks);
568
569 final NetworkCapabilities caps = new NetworkCapabilities();
570
Varun Anand4fa80e82019-02-06 10:13:38 -0800571 Vpn.applyUnderlyingCapabilities(
Varun Anand1215f092019-01-14 11:45:33 -0800572 mConnectivityManager, new Network[] {}, caps, false /* isAlwaysMetered */);
Jeff Sharkey72f9c422017-10-27 17:22:59 -0600573 assertTrue(caps.hasTransport(TRANSPORT_VPN));
574 assertFalse(caps.hasTransport(TRANSPORT_CELLULAR));
575 assertFalse(caps.hasTransport(TRANSPORT_WIFI));
576 assertEquals(LINK_BANDWIDTH_UNSPECIFIED, caps.getLinkDownstreamBandwidthKbps());
577 assertEquals(LINK_BANDWIDTH_UNSPECIFIED, caps.getLinkUpstreamBandwidthKbps());
578 assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_METERED));
579 assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING));
Jeff Sharkey9b2a10f2018-01-17 13:27:03 +0900580 assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED));
Jeff Sharkey72f9c422017-10-27 17:22:59 -0600581
Varun Anand4fa80e82019-02-06 10:13:38 -0800582 Vpn.applyUnderlyingCapabilities(
Varun Anand1215f092019-01-14 11:45:33 -0800583 mConnectivityManager,
584 new Network[] {mobile},
585 caps,
586 false /* isAlwaysMetered */);
Jeff Sharkey72f9c422017-10-27 17:22:59 -0600587 assertTrue(caps.hasTransport(TRANSPORT_VPN));
588 assertTrue(caps.hasTransport(TRANSPORT_CELLULAR));
589 assertFalse(caps.hasTransport(TRANSPORT_WIFI));
590 assertEquals(10, caps.getLinkDownstreamBandwidthKbps());
591 assertEquals(LINK_BANDWIDTH_UNSPECIFIED, caps.getLinkUpstreamBandwidthKbps());
Varun Anand1215f092019-01-14 11:45:33 -0800592 assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_METERED));
Jeff Sharkey72f9c422017-10-27 17:22:59 -0600593 assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING));
Jeff Sharkey9b2a10f2018-01-17 13:27:03 +0900594 assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED));
Jeff Sharkey72f9c422017-10-27 17:22:59 -0600595
Varun Anand4fa80e82019-02-06 10:13:38 -0800596 Vpn.applyUnderlyingCapabilities(
Varun Anand1215f092019-01-14 11:45:33 -0800597 mConnectivityManager, new Network[] {wifi}, caps, false /* isAlwaysMetered */);
598 assertTrue(caps.hasTransport(TRANSPORT_VPN));
599 assertFalse(caps.hasTransport(TRANSPORT_CELLULAR));
600 assertTrue(caps.hasTransport(TRANSPORT_WIFI));
601 assertEquals(LINK_BANDWIDTH_UNSPECIFIED, caps.getLinkDownstreamBandwidthKbps());
602 assertEquals(20, caps.getLinkUpstreamBandwidthKbps());
603 assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_METERED));
604 assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING));
605 assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED));
606
Varun Anand4fa80e82019-02-06 10:13:38 -0800607 Vpn.applyUnderlyingCapabilities(
Varun Anand1215f092019-01-14 11:45:33 -0800608 mConnectivityManager, new Network[] {wifi}, caps, true /* isAlwaysMetered */);
Jeff Sharkey72f9c422017-10-27 17:22:59 -0600609 assertTrue(caps.hasTransport(TRANSPORT_VPN));
610 assertFalse(caps.hasTransport(TRANSPORT_CELLULAR));
611 assertTrue(caps.hasTransport(TRANSPORT_WIFI));
612 assertEquals(LINK_BANDWIDTH_UNSPECIFIED, caps.getLinkDownstreamBandwidthKbps());
613 assertEquals(20, caps.getLinkUpstreamBandwidthKbps());
614 assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_METERED));
615 assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING));
Jeff Sharkey9b2a10f2018-01-17 13:27:03 +0900616 assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED));
Jeff Sharkey72f9c422017-10-27 17:22:59 -0600617
Varun Anand4fa80e82019-02-06 10:13:38 -0800618 Vpn.applyUnderlyingCapabilities(
Varun Anand1215f092019-01-14 11:45:33 -0800619 mConnectivityManager,
620 new Network[] {mobile, wifi},
621 caps,
622 false /* isAlwaysMetered */);
Jeff Sharkey72f9c422017-10-27 17:22:59 -0600623 assertTrue(caps.hasTransport(TRANSPORT_VPN));
624 assertTrue(caps.hasTransport(TRANSPORT_CELLULAR));
625 assertTrue(caps.hasTransport(TRANSPORT_WIFI));
626 assertEquals(10, caps.getLinkDownstreamBandwidthKbps());
627 assertEquals(20, caps.getLinkUpstreamBandwidthKbps());
628 assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_METERED));
629 assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING));
Jeff Sharkey9b2a10f2018-01-17 13:27:03 +0900630 assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED));
Jeff Sharkey72f9c422017-10-27 17:22:59 -0600631 }
632
Robin Lee4d03abc2016-05-09 12:32:27 +0100633 /**
Tony Makde7f7d12016-06-30 11:19:20 +0100634 * Mock some methods of vpn object.
Robin Lee4d03abc2016-05-09 12:32:27 +0100635 */
Robin Leeb8c2a2b2017-03-10 16:17:06 +0000636 private Vpn createVpn(@UserIdInt int userId) {
637 return new Vpn(Looper.myLooper(), mContext, mNetService, userId, mSystemServices);
Tony Makde7f7d12016-06-30 11:19:20 +0100638 }
Robin Lee17e61832016-05-09 13:46:28 +0100639
Tony Makde7f7d12016-06-30 11:19:20 +0100640 private static void assertBlocked(Vpn vpn, int... uids) {
641 for (int uid : uids) {
junyulai8ed89152018-10-25 10:56:17 +0800642 final boolean blocked = vpn.getLockdown() && vpn.isBlockingUid(uid);
643 assertTrue("Uid " + uid + " should be blocked", blocked);
Tony Makde7f7d12016-06-30 11:19:20 +0100644 }
645 }
646
647 private static void assertUnblocked(Vpn vpn, int... uids) {
648 for (int uid : uids) {
junyulai8ed89152018-10-25 10:56:17 +0800649 final boolean blocked = vpn.getLockdown() && vpn.isBlockingUid(uid);
650 assertFalse("Uid " + uid + " should not be blocked", blocked);
Robin Lee17e61832016-05-09 13:46:28 +0100651 }
Robin Lee4d03abc2016-05-09 12:32:27 +0100652 }
653
654 /**
655 * Populate {@link #mUserManager} with a list of fake users.
656 */
657 private void setMockedUsers(UserInfo... users) {
658 final Map<Integer, UserInfo> userMap = new ArrayMap<>();
659 for (UserInfo user : users) {
660 userMap.put(user.id, user);
661 }
662
Robin Lee17e61832016-05-09 13:46:28 +0100663 /**
664 * @see UserManagerService#getUsers(boolean)
665 */
Robin Lee4d03abc2016-05-09 12:32:27 +0100666 doAnswer(invocation -> {
Robin Lee17e61832016-05-09 13:46:28 +0100667 final boolean excludeDying = (boolean) invocation.getArguments()[0];
668 final ArrayList<UserInfo> result = new ArrayList<>(users.length);
669 for (UserInfo ui : users) {
670 if (!excludeDying || (ui.isEnabled() && !ui.partial)) {
671 result.add(ui);
672 }
673 }
674 return result;
675 }).when(mUserManager).getUsers(anyBoolean());
Robin Lee4d03abc2016-05-09 12:32:27 +0100676
677 doAnswer(invocation -> {
678 final int id = (int) invocation.getArguments()[0];
679 return userMap.get(id);
680 }).when(mUserManager).getUserInfo(anyInt());
681
682 doAnswer(invocation -> {
683 final int id = (int) invocation.getArguments()[0];
684 return (userMap.get(id).flags & UserInfo.FLAG_ADMIN) != 0;
685 }).when(mUserManager).canHaveRestrictedProfile(anyInt());
686 }
687
688 /**
689 * Populate {@link #mPackageManager} with a fake packageName-to-UID mapping.
690 */
691 private void setMockedPackages(final Map<String, Integer> packages) {
692 try {
693 doAnswer(invocation -> {
694 final String appName = (String) invocation.getArguments()[0];
695 final int userId = (int) invocation.getArguments()[1];
Pavel Grafova462bcb2019-01-25 08:50:06 +0000696 Integer appId = packages.get(appName);
697 if (appId == null) throw new PackageManager.NameNotFoundException(appName);
698 return UserHandle.getUid(userId, appId);
Robin Lee4d03abc2016-05-09 12:32:27 +0100699 }).when(mPackageManager).getPackageUidAsUser(anyString(), anyInt());
700 } catch (Exception e) {
701 }
702 }
Jeff Sharkey72f9c422017-10-27 17:22:59 -0600703
704 private void setMockedNetworks(final Map<Network, NetworkCapabilities> networks) {
705 doAnswer(invocation -> {
706 final Network network = (Network) invocation.getArguments()[0];
707 return networks.get(network);
708 }).when(mConnectivityManager).getNetworkCapabilities(any());
709 }
Chalard Jeanadbf1d02018-02-26 11:52:46 +0900710
711 // Need multiple copies of this, but Java's Stream objects can't be reused or
712 // duplicated.
713 private Stream<String> publicIpV4Routes() {
714 return Stream.of(
715 "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",
716 "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",
717 "172.0.0.0/12", "172.32.0.0/11", "172.64.0.0/10", "172.128.0.0/9",
718 "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",
719 "192.160.0.0/13", "192.169.0.0/16", "192.170.0.0/15", "192.172.0.0/14",
720 "192.176.0.0/12", "192.192.0.0/10", "193.0.0.0/8", "194.0.0.0/7",
721 "196.0.0.0/6", "200.0.0.0/5", "208.0.0.0/4");
722 }
723
724 private Stream<String> publicIpV6Routes() {
725 return Stream.of(
726 "::/1", "8000::/2", "c000::/3", "e000::/4", "f000::/5", "f800::/6",
727 "fe00::/8", "2605:ef80:e:af1d::/64");
728 }
729
730 @Test
731 public void testProvidesRoutesToMostDestinations() {
732 final LinkProperties lp = new LinkProperties();
733
734 // Default route provides routes to all IPv4 destinations.
735 lp.addRoute(new RouteInfo(new IpPrefix("0.0.0.0/0")));
736 assertTrue(Vpn.providesRoutesToMostDestinations(lp));
737
738 // Empty LP provides routes to no destination
739 lp.clear();
740 assertFalse(Vpn.providesRoutesToMostDestinations(lp));
741
742 // All IPv4 routes except for local networks. This is the case most relevant
743 // to this function. It provides routes to almost the entire space.
744 // (clone the stream so that we can reuse it later)
745 publicIpV4Routes().forEach(s -> lp.addRoute(new RouteInfo(new IpPrefix(s))));
746 assertTrue(Vpn.providesRoutesToMostDestinations(lp));
747
748 // Removing a 16-bit prefix, which is 65536 addresses. This is still enough to
749 // provide routes to "most" destinations.
750 lp.removeRoute(new RouteInfo(new IpPrefix("192.169.0.0/16")));
751 assertTrue(Vpn.providesRoutesToMostDestinations(lp));
752
753 // Remove the /2 route, which represent a quarter of the available routing space.
754 // This LP does not provides routes to "most" destinations any more.
755 lp.removeRoute(new RouteInfo(new IpPrefix("64.0.0.0/2")));
756 assertFalse(Vpn.providesRoutesToMostDestinations(lp));
757
758 lp.clear();
759 publicIpV6Routes().forEach(s -> lp.addRoute(new RouteInfo(new IpPrefix(s))));
760 assertTrue(Vpn.providesRoutesToMostDestinations(lp));
761
762 lp.removeRoute(new RouteInfo(new IpPrefix("::/1")));
763 assertFalse(Vpn.providesRoutesToMostDestinations(lp));
764
765 // V6 does not provide sufficient coverage but v4 does
766 publicIpV4Routes().forEach(s -> lp.addRoute(new RouteInfo(new IpPrefix(s))));
767 assertTrue(Vpn.providesRoutesToMostDestinations(lp));
768
769 // V4 still does
770 lp.removeRoute(new RouteInfo(new IpPrefix("192.169.0.0/16")));
771 assertTrue(Vpn.providesRoutesToMostDestinations(lp));
772
773 // V4 does not any more
774 lp.removeRoute(new RouteInfo(new IpPrefix("64.0.0.0/2")));
775 assertFalse(Vpn.providesRoutesToMostDestinations(lp));
776
777 // V4 does not, but V6 has sufficient coverage again
778 lp.addRoute(new RouteInfo(new IpPrefix("::/1")));
779 assertTrue(Vpn.providesRoutesToMostDestinations(lp));
Rubin Xuc63e48d2019-02-19 16:56:47 +0000780
781 lp.clear();
782 // V4-unreachable route should not be treated as sufficient coverage
783 lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), RTN_UNREACHABLE));
784 assertFalse(Vpn.providesRoutesToMostDestinations(lp));
785
786 lp.clear();
787 // V6-unreachable route should not be treated as sufficient coverage
788 lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), RTN_UNREACHABLE));
789 assertFalse(Vpn.providesRoutesToMostDestinations(lp));
Chalard Jeanadbf1d02018-02-26 11:52:46 +0900790 }
Chalard Jeane0d26f62018-03-29 14:10:44 +0900791
792 @Test
793 public void testDoesNotLockUpWithTooManyRoutes() {
794 final LinkProperties lp = new LinkProperties();
795 final byte[] ad = new byte[4];
796 // Actually evaluating this many routes under 1500ms is impossible on
797 // current hardware and for some time, as the algorithm is O(n²).
798 // Make sure the system has a safeguard against this and does not
799 // lock up.
800 final int MAX_ROUTES = 4000;
801 final long MAX_ALLOWED_TIME_MS = 1500;
802 for (int i = 0; i < MAX_ROUTES; ++i) {
803 ad[0] = (byte)((i >> 24) & 0xFF);
804 ad[1] = (byte)((i >> 16) & 0xFF);
805 ad[2] = (byte)((i >> 8) & 0xFF);
806 ad[3] = (byte)(i & 0xFF);
807 try {
808 lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.getByAddress(ad), 32)));
809 } catch (UnknownHostException e) {
810 // UnknownHostException is only thrown for an address of illegal length,
811 // which can't happen in the case above.
812 }
813 }
814 final long start = SystemClock.currentThreadTimeMillis();
815 assertTrue(Vpn.providesRoutesToMostDestinations(lp));
816 final long end = SystemClock.currentThreadTimeMillis();
817 assertTrue(end - start < MAX_ALLOWED_TIME_MS);
818 }
Robin Lee4d03abc2016-05-09 12:32:27 +0100819}