• 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.Manifest.permission.BIND_VPN_SERVICE;
20 import static android.Manifest.permission.CONTROL_VPN;
21 import static android.content.pm.PackageManager.PERMISSION_DENIED;
22 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
23 import static android.net.ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback;
24 import static android.net.ConnectivityDiagnosticsManager.DataStallReport;
25 import static android.net.ConnectivityManager.NetworkCallback;
26 import static android.net.INetd.IF_STATE_DOWN;
27 import static android.net.INetd.IF_STATE_UP;
28 import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
29 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
30 import static android.net.NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED;
31 import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
32 import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
33 import static android.net.RouteInfo.RTN_UNREACHABLE;
34 import static android.net.VpnManager.TYPE_VPN_PLATFORM;
35 import static android.net.cts.util.IkeSessionTestUtils.CHILD_PARAMS;
36 import static android.net.cts.util.IkeSessionTestUtils.TEST_IDENTITY;
37 import static android.net.cts.util.IkeSessionTestUtils.TEST_KEEPALIVE_TIMEOUT_UNSET;
38 import static android.net.cts.util.IkeSessionTestUtils.getTestIkeSessionParams;
39 import static android.net.ipsec.ike.IkeSessionConfiguration.EXTENSION_TYPE_MOBIKE;
40 import static android.net.ipsec.ike.IkeSessionParams.ESP_ENCAP_TYPE_AUTO;
41 import static android.net.ipsec.ike.IkeSessionParams.ESP_ENCAP_TYPE_NONE;
42 import static android.net.ipsec.ike.IkeSessionParams.ESP_ENCAP_TYPE_UDP;
43 import static android.net.ipsec.ike.IkeSessionParams.ESP_IP_VERSION_AUTO;
44 import static android.net.ipsec.ike.IkeSessionParams.ESP_IP_VERSION_IPV4;
45 import static android.net.ipsec.ike.IkeSessionParams.ESP_IP_VERSION_IPV6;
46 import static android.os.Build.VERSION_CODES.S_V2;
47 import static android.os.UserHandle.PER_USER_RANGE;
48 import static android.telephony.CarrierConfigManager.KEY_CARRIER_CONFIG_APPLIED_BOOL;
49 import static android.telephony.CarrierConfigManager.KEY_MIN_UDP_PORT_4500_NAT_TIMEOUT_SEC_INT;
50 import static android.telephony.CarrierConfigManager.KEY_PREFERRED_IKE_PROTOCOL_INT;
51 
52 import static com.android.net.module.util.NetworkStackConstants.IPV6_MIN_MTU;
53 import static com.android.server.connectivity.Vpn.AUTOMATIC_KEEPALIVE_DELAY_SECONDS;
54 import static com.android.server.connectivity.Vpn.DEFAULT_LONG_LIVED_TCP_CONNS_EXPENSIVE_TIMEOUT_SEC;
55 import static com.android.server.connectivity.Vpn.DEFAULT_UDP_PORT_4500_NAT_TIMEOUT_SEC_INT;
56 import static com.android.server.connectivity.Vpn.PREFERRED_IKE_PROTOCOL_AUTO;
57 import static com.android.server.connectivity.Vpn.PREFERRED_IKE_PROTOCOL_IPV4_UDP;
58 import static com.android.server.connectivity.Vpn.PREFERRED_IKE_PROTOCOL_IPV6_ESP;
59 import static com.android.server.connectivity.Vpn.PREFERRED_IKE_PROTOCOL_IPV6_UDP;
60 import static com.android.testutils.Cleanup.testAndCleanup;
61 import static com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
62 import static com.android.testutils.MiscAsserts.assertThrows;
63 
64 import static org.junit.Assert.assertArrayEquals;
65 import static org.junit.Assert.assertEquals;
66 import static org.junit.Assert.assertFalse;
67 import static org.junit.Assert.assertNotNull;
68 import static org.junit.Assert.assertNull;
69 import static org.junit.Assert.assertTrue;
70 import static org.junit.Assert.fail;
71 import static org.mockito.ArgumentMatchers.any;
72 import static org.mockito.ArgumentMatchers.anyBoolean;
73 import static org.mockito.ArgumentMatchers.anyInt;
74 import static org.mockito.ArgumentMatchers.anyLong;
75 import static org.mockito.ArgumentMatchers.anyString;
76 import static org.mockito.ArgumentMatchers.argThat;
77 import static org.mockito.ArgumentMatchers.eq;
78 import static org.mockito.ArgumentMatchers.longThat;
79 import static org.mockito.Mockito.after;
80 import static org.mockito.Mockito.atLeastOnce;
81 import static org.mockito.Mockito.doAnswer;
82 import static org.mockito.Mockito.doCallRealMethod;
83 import static org.mockito.Mockito.doNothing;
84 import static org.mockito.Mockito.doReturn;
85 import static org.mockito.Mockito.inOrder;
86 import static org.mockito.Mockito.mock;
87 import static org.mockito.Mockito.never;
88 import static org.mockito.Mockito.reset;
89 import static org.mockito.Mockito.spy;
90 import static org.mockito.Mockito.timeout;
91 import static org.mockito.Mockito.times;
92 import static org.mockito.Mockito.verify;
93 import static org.mockito.Mockito.when;
94 
95 import android.annotation.NonNull;
96 import android.annotation.UserIdInt;
97 import android.app.AppOpsManager;
98 import android.app.NotificationManager;
99 import android.app.PendingIntent;
100 import android.content.Context;
101 import android.content.Intent;
102 import android.content.pm.ApplicationInfo;
103 import android.content.pm.PackageManager;
104 import android.content.pm.ResolveInfo;
105 import android.content.pm.ServiceInfo;
106 import android.content.pm.UserInfo;
107 import android.content.res.Resources;
108 import android.net.ConnectivityDiagnosticsManager;
109 import android.net.ConnectivityManager;
110 import android.net.INetd;
111 import android.net.Ikev2VpnProfile;
112 import android.net.InetAddresses;
113 import android.net.InterfaceConfigurationParcel;
114 import android.net.IpPrefix;
115 import android.net.IpSecConfig;
116 import android.net.IpSecManager;
117 import android.net.IpSecTransform;
118 import android.net.IpSecTunnelInterfaceResponse;
119 import android.net.LinkAddress;
120 import android.net.LinkProperties;
121 import android.net.LocalSocket;
122 import android.net.Network;
123 import android.net.NetworkAgent;
124 import android.net.NetworkAgentConfig;
125 import android.net.NetworkCapabilities;
126 import android.net.NetworkInfo.DetailedState;
127 import android.net.RouteInfo;
128 import android.net.TelephonyNetworkSpecifier;
129 import android.net.UidRangeParcel;
130 import android.net.VpnManager;
131 import android.net.VpnProfileState;
132 import android.net.VpnService;
133 import android.net.VpnTransportInfo;
134 import android.net.ipsec.ike.ChildSessionCallback;
135 import android.net.ipsec.ike.ChildSessionConfiguration;
136 import android.net.ipsec.ike.IkeFqdnIdentification;
137 import android.net.ipsec.ike.IkeSessionCallback;
138 import android.net.ipsec.ike.IkeSessionConfiguration;
139 import android.net.ipsec.ike.IkeSessionConnectionInfo;
140 import android.net.ipsec.ike.IkeSessionParams;
141 import android.net.ipsec.ike.IkeTrafficSelector;
142 import android.net.ipsec.ike.IkeTunnelConnectionParams;
143 import android.net.ipsec.ike.exceptions.IkeException;
144 import android.net.ipsec.ike.exceptions.IkeNetworkLostException;
145 import android.net.ipsec.ike.exceptions.IkeNonProtocolException;
146 import android.net.ipsec.ike.exceptions.IkeProtocolException;
147 import android.net.ipsec.ike.exceptions.IkeTimeoutException;
148 import android.net.vcn.VcnTransportInfo;
149 import android.net.wifi.WifiInfo;
150 import android.os.Build.VERSION_CODES;
151 import android.os.Bundle;
152 import android.os.ConditionVariable;
153 import android.os.INetworkManagementService;
154 import android.os.ParcelFileDescriptor;
155 import android.os.PersistableBundle;
156 import android.os.PowerWhitelistManager;
157 import android.os.Process;
158 import android.os.UserHandle;
159 import android.os.UserManager;
160 import android.os.test.TestLooper;
161 import android.provider.Settings;
162 import android.security.Credentials;
163 import android.telephony.CarrierConfigManager;
164 import android.telephony.SubscriptionInfo;
165 import android.telephony.SubscriptionManager;
166 import android.telephony.TelephonyManager;
167 import android.util.ArrayMap;
168 import android.util.ArraySet;
169 import android.util.Pair;
170 import android.util.Range;
171 
172 import androidx.test.filters.SmallTest;
173 
174 import com.android.internal.R;
175 import com.android.internal.net.LegacyVpnInfo;
176 import com.android.internal.net.VpnConfig;
177 import com.android.internal.net.VpnProfile;
178 import com.android.internal.util.HexDump;
179 import com.android.internal.util.IndentingPrintWriter;
180 import com.android.server.DeviceIdleInternal;
181 import com.android.server.IpSecService;
182 import com.android.server.VpnTestBase;
183 import com.android.server.vcn.util.PersistableBundleUtils;
184 import com.android.testutils.DevSdkIgnoreRule;
185 import com.android.testutils.DevSdkIgnoreRunner;
186 
187 import org.junit.Before;
188 import org.junit.Rule;
189 import org.junit.Test;
190 import org.junit.runner.RunWith;
191 import org.mockito.AdditionalAnswers;
192 import org.mockito.Answers;
193 import org.mockito.ArgumentCaptor;
194 import org.mockito.InOrder;
195 import org.mockito.Mock;
196 import org.mockito.MockitoAnnotations;
197 
198 import java.io.BufferedWriter;
199 import java.io.File;
200 import java.io.FileDescriptor;
201 import java.io.FileWriter;
202 import java.io.IOException;
203 import java.io.StringWriter;
204 import java.net.Inet4Address;
205 import java.net.Inet6Address;
206 import java.net.InetAddress;
207 import java.net.UnknownHostException;
208 import java.util.ArrayList;
209 import java.util.Arrays;
210 import java.util.Collections;
211 import java.util.HashMap;
212 import java.util.List;
213 import java.util.Map;
214 import java.util.Set;
215 import java.util.SortedSet;
216 import java.util.TreeSet;
217 import java.util.concurrent.CompletableFuture;
218 import java.util.concurrent.ScheduledFuture;
219 import java.util.concurrent.ScheduledThreadPoolExecutor;
220 import java.util.concurrent.TimeUnit;
221 import java.util.regex.Matcher;
222 import java.util.regex.Pattern;
223 import java.util.stream.Stream;
224 
225 /**
226  * Tests for {@link Vpn}.
227  *
228  * Build, install and run with:
229  *  runtest frameworks-net -c com.android.server.connectivity.VpnTest
230  */
231 @RunWith(DevSdkIgnoreRunner.class)
232 @SmallTest
233 @IgnoreUpTo(S_V2)
234 public class VpnTest extends VpnTestBase {
235     private static final String TAG = "VpnTest";
236 
237     @Rule
238     public final DevSdkIgnoreRule mIgnoreRule = new DevSdkIgnoreRule();
239 
240     static final Network EGRESS_NETWORK = new Network(101);
241     static final String EGRESS_IFACE = "wlan0";
242     private static final String TEST_VPN_CLIENT = "2.4.6.8";
243     private static final String TEST_VPN_SERVER = "1.2.3.4";
244     private static final String TEST_VPN_IDENTITY = "identity";
245     private static final byte[] TEST_VPN_PSK = "psk".getBytes();
246 
247     private static final int IP4_PREFIX_LEN = 32;
248     private static final int IP6_PREFIX_LEN = 64;
249     private static final int MIN_PORT = 0;
250     private static final int MAX_PORT = 65535;
251 
252     private static final InetAddress TEST_VPN_CLIENT_IP =
253             InetAddresses.parseNumericAddress(TEST_VPN_CLIENT);
254     private static final InetAddress TEST_VPN_SERVER_IP =
255             InetAddresses.parseNumericAddress(TEST_VPN_SERVER);
256     private static final InetAddress TEST_VPN_CLIENT_IP_2 =
257             InetAddresses.parseNumericAddress("192.0.2.200");
258     private static final InetAddress TEST_VPN_SERVER_IP_2 =
259             InetAddresses.parseNumericAddress("192.0.2.201");
260     private static final InetAddress TEST_VPN_INTERNAL_IP =
261             InetAddresses.parseNumericAddress("198.51.100.10");
262     private static final InetAddress TEST_VPN_INTERNAL_IP6 =
263             InetAddresses.parseNumericAddress("2001:db8::1");
264     private static final InetAddress TEST_VPN_INTERNAL_DNS =
265             InetAddresses.parseNumericAddress("8.8.8.8");
266     private static final InetAddress TEST_VPN_INTERNAL_DNS6 =
267             InetAddresses.parseNumericAddress("2001:4860:4860::8888");
268 
269     private static final IkeTrafficSelector IN_TS =
270             new IkeTrafficSelector(MIN_PORT, MAX_PORT, TEST_VPN_INTERNAL_IP, TEST_VPN_INTERNAL_IP);
271     private static final IkeTrafficSelector IN_TS6 =
272             new IkeTrafficSelector(
273                     MIN_PORT, MAX_PORT, TEST_VPN_INTERNAL_IP6, TEST_VPN_INTERNAL_IP6);
274     private static final IkeTrafficSelector OUT_TS =
275             new IkeTrafficSelector(MIN_PORT, MAX_PORT,
276                     InetAddresses.parseNumericAddress("0.0.0.0"),
277                     InetAddresses.parseNumericAddress("255.255.255.255"));
278     private static final IkeTrafficSelector OUT_TS6 =
279             new IkeTrafficSelector(
280                     MIN_PORT,
281                     MAX_PORT,
282                     InetAddresses.parseNumericAddress("::"),
283                     InetAddresses.parseNumericAddress("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"));
284 
285     private static final Network TEST_NETWORK = new Network(Integer.MAX_VALUE);
286     private static final Network TEST_NETWORK_2 = new Network(Integer.MAX_VALUE - 1);
287     private static final String TEST_IFACE_NAME = "TEST_IFACE";
288     private static final int TEST_TUNNEL_RESOURCE_ID = 0x2345;
289     private static final long TEST_TIMEOUT_MS = 500L;
290     private static final long TIMEOUT_CROSSTHREAD_MS = 20_000L;
291     private static final String PRIMARY_USER_APP_EXCLUDE_KEY =
292             "VPNAPPEXCLUDED_27_com.testvpn.vpn";
293     static final String PKGS_BYTES = getPackageByteString(List.of(PKGS));
294     private static final Range<Integer> PRIMARY_USER_RANGE = uidRangeForUser(PRIMARY_USER.id);
295     private static final int TEST_KEEPALIVE_TIMER = 800;
296     private static final int TEST_SUB_ID = 1234;
297     private static final String TEST_MCCMNC = "12345";
298 
299     @Mock(answer = Answers.RETURNS_DEEP_STUBS) private Context mContext;
300     @Mock private UserManager mUserManager;
301     @Mock private PackageManager mPackageManager;
302     @Mock private INetworkManagementService mNetService;
303     @Mock private INetd mNetd;
304     @Mock private AppOpsManager mAppOps;
305     @Mock private NotificationManager mNotificationManager;
306     @Mock private Vpn.SystemServices mSystemServices;
307     @Mock private Vpn.IkeSessionWrapper mIkeSessionWrapper;
308     @Mock private Vpn.Ikev2SessionCreator mIkev2SessionCreator;
309     @Mock private Vpn.VpnNetworkAgentWrapper mMockNetworkAgent;
310     @Mock private ConnectivityManager mConnectivityManager;
311     @Mock private ConnectivityDiagnosticsManager mCdm;
312     @Mock private TelephonyManager mTelephonyManager;
313     @Mock private TelephonyManager mTmPerSub;
314     @Mock private CarrierConfigManager mConfigManager;
315     @Mock private SubscriptionManager mSubscriptionManager;
316     @Mock private IpSecService mIpSecService;
317     @Mock private VpnProfileStore mVpnProfileStore;
318     private final TestExecutor mExecutor;
319     @Mock DeviceIdleInternal mDeviceIdleInternal;
320     private final VpnProfile mVpnProfile;
321 
322     private IpSecManager mIpSecManager;
323     private TestDeps mTestDeps;
324 
325     public static class TestExecutor extends ScheduledThreadPoolExecutor {
326         public static final long REAL_DELAY = -1;
327 
328         // For the purposes of the test, run all scheduled tasks after 10ms to save
329         // execution time, unless overridden by the specific test. Set to REAL_DELAY
330         // to actually wait for the delay specified by the real call to schedule().
331         public long delayMs = 10;
332         // If this is true, execute() will call the runnable inline. This is useful because
333         // super.execute() calls schedule(), which messes with checks that scheduled() is
334         // called a given number of times.
335         public boolean executeDirect = false;
336 
TestExecutor()337         public TestExecutor() {
338             super(1);
339         }
340 
341         @Override
execute(final Runnable command)342         public void execute(final Runnable command) {
343             // See |executeDirect| for why this is necessary.
344             if (executeDirect) {
345                 command.run();
346             } else {
347                 super.execute(command);
348             }
349         }
350 
351         @Override
schedule(final Runnable command, final long delay, TimeUnit unit)352         public ScheduledFuture<?> schedule(final Runnable command, final long delay,
353                 TimeUnit unit) {
354             if (0 == delay || delayMs == REAL_DELAY) {
355                 // super.execute() calls schedule() with 0, so use the real delay if it's 0.
356                 return super.schedule(command, delay, unit);
357             } else {
358                 return super.schedule(command, delayMs, TimeUnit.MILLISECONDS);
359             }
360         }
361     }
362 
VpnTest()363     public VpnTest() throws Exception {
364         // Build an actual VPN profile that is capable of being converted to and from an
365         // Ikev2VpnProfile
366         final Ikev2VpnProfile.Builder builder =
367                 new Ikev2VpnProfile.Builder(TEST_VPN_SERVER, TEST_VPN_IDENTITY);
368         builder.setAuthPsk(TEST_VPN_PSK);
369         builder.setBypassable(true /* isBypassable */);
370         mExecutor = spy(new TestExecutor());
371         mVpnProfile = builder.build().toVpnProfile();
372     }
373 
374     @Before
setUp()375     public void setUp() throws Exception {
376         MockitoAnnotations.initMocks(this);
377 
378         mIpSecManager = new IpSecManager(mContext, mIpSecService);
379         mTestDeps = spy(new TestDeps());
380         doReturn(IPV6_MIN_MTU)
381                 .when(mTestDeps)
382                 .calculateVpnMtu(any(), anyInt(), anyInt(), anyBoolean());
383         doReturn(1500).when(mTestDeps).getJavaNetworkInterfaceMtu(any(), anyInt());
384 
385         when(mContext.getPackageManager()).thenReturn(mPackageManager);
386         setMockedPackages(sPackages);
387 
388         when(mContext.getPackageName()).thenReturn(TEST_VPN_PKG);
389         when(mContext.getOpPackageName()).thenReturn(TEST_VPN_PKG);
390         mockService(UserManager.class, Context.USER_SERVICE, mUserManager);
391         mockService(AppOpsManager.class, Context.APP_OPS_SERVICE, mAppOps);
392         mockService(NotificationManager.class, Context.NOTIFICATION_SERVICE, mNotificationManager);
393         mockService(ConnectivityManager.class, Context.CONNECTIVITY_SERVICE, mConnectivityManager);
394         mockService(IpSecManager.class, Context.IPSEC_SERVICE, mIpSecManager);
395         mockService(ConnectivityDiagnosticsManager.class, Context.CONNECTIVITY_DIAGNOSTICS_SERVICE,
396                 mCdm);
397         mockService(TelephonyManager.class, Context.TELEPHONY_SERVICE, mTelephonyManager);
398         mockService(CarrierConfigManager.class, Context.CARRIER_CONFIG_SERVICE, mConfigManager);
399         mockService(SubscriptionManager.class, Context.TELEPHONY_SUBSCRIPTION_SERVICE,
400                 mSubscriptionManager);
401         doReturn(mTmPerSub).when(mTelephonyManager).createForSubscriptionId(anyInt());
402         when(mContext.getString(R.string.config_customVpnAlwaysOnDisconnectedDialogComponent))
403                 .thenReturn(Resources.getSystem().getString(
404                         R.string.config_customVpnAlwaysOnDisconnectedDialogComponent));
405         when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_IPSEC_TUNNELS))
406                 .thenReturn(true);
407 
408         // Used by {@link Notification.Builder}
409         ApplicationInfo applicationInfo = new ApplicationInfo();
410         applicationInfo.targetSdkVersion = VERSION_CODES.CUR_DEVELOPMENT;
411         when(mContext.getApplicationInfo()).thenReturn(applicationInfo);
412         when(mPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), anyInt()))
413                 .thenReturn(applicationInfo);
414 
415         doNothing().when(mNetService).registerObserver(any());
416 
417         // Deny all appops by default.
418         when(mAppOps.noteOpNoThrow(anyString(), anyInt(), anyString(), any(), any()))
419                 .thenReturn(AppOpsManager.MODE_IGNORED);
420 
421         // Setup IpSecService
422         final IpSecTunnelInterfaceResponse tunnelResp =
423                 new IpSecTunnelInterfaceResponse(
424                         IpSecManager.Status.OK, TEST_TUNNEL_RESOURCE_ID, TEST_IFACE_NAME);
425         when(mIpSecService.createTunnelInterface(any(), any(), any(), any(), any()))
426                 .thenReturn(tunnelResp);
427         doReturn(new LinkProperties()).when(mConnectivityManager).getLinkProperties(any());
428 
429         // The unit test should know what kind of permission it needs and set the permission by
430         // itself, so set the default value of Context#checkCallingOrSelfPermission to
431         // PERMISSION_DENIED.
432         doReturn(PERMISSION_DENIED).when(mContext).checkCallingOrSelfPermission(any());
433 
434         // Set up mIkev2SessionCreator and mExecutor
435         resetIkev2SessionCreator(mIkeSessionWrapper);
436     }
437 
resetIkev2SessionCreator(Vpn.IkeSessionWrapper ikeSession)438     private void resetIkev2SessionCreator(Vpn.IkeSessionWrapper ikeSession) {
439         reset(mIkev2SessionCreator);
440         when(mIkev2SessionCreator.createIkeSession(any(), any(), any(), any(), any(), any()))
441                 .thenReturn(ikeSession);
442     }
443 
mockService(Class<T> clazz, String name, T service)444     private <T> void mockService(Class<T> clazz, String name, T service) {
445         doReturn(service).when(mContext).getSystemService(name);
446         doReturn(name).when(mContext).getSystemServiceName(clazz);
447         if (mContext.getSystemService(clazz).getClass().equals(Object.class)) {
448             // Test is using mockito-extended (mContext uses Answers.RETURNS_DEEP_STUBS and returned
449             // a mock object on a final method)
450             doCallRealMethod().when(mContext).getSystemService(clazz);
451         }
452     }
453 
rangeSet(Range<Integer> .... ranges)454     private Set<Range<Integer>> rangeSet(Range<Integer> ... ranges) {
455         final Set<Range<Integer>> range = new ArraySet<>();
456         for (Range<Integer> r : ranges) range.add(r);
457 
458         return range;
459     }
460 
uidRangeForUser(int userId)461     private static Range<Integer> uidRangeForUser(int userId) {
462         return new Range<Integer>(userId * PER_USER_RANGE, (userId + 1) * PER_USER_RANGE - 1);
463     }
464 
uidRange(int start, int stop)465     private Range<Integer> uidRange(int start, int stop) {
466         return new Range<Integer>(start, stop);
467     }
468 
getPackageByteString(List<String> packages)469     private static String getPackageByteString(List<String> packages) {
470         try {
471             return HexDump.toHexString(
472                     PersistableBundleUtils.toDiskStableBytes(PersistableBundleUtils.fromList(
473                             packages, PersistableBundleUtils.STRING_SERIALIZER)),
474                         true /* upperCase */);
475         } catch (IOException e) {
476             return null;
477         }
478     }
479 
480     @Test
testRestrictedProfilesAreAddedToVpn()481     public void testRestrictedProfilesAreAddedToVpn() {
482         setMockedUsers(PRIMARY_USER, SECONDARY_USER, RESTRICTED_PROFILE_A, RESTRICTED_PROFILE_B);
483 
484         final Vpn vpn = createVpn(PRIMARY_USER.id);
485 
486         // Assume the user can have restricted profiles.
487         doReturn(true).when(mUserManager).canHaveRestrictedProfile();
488         final Set<Range<Integer>> ranges =
489                 vpn.createUserAndRestrictedProfilesRanges(PRIMARY_USER.id, null, null);
490 
491         assertEquals(rangeSet(PRIMARY_USER_RANGE, uidRangeForUser(RESTRICTED_PROFILE_A.id)),
492                  ranges);
493     }
494 
495     @Test
testManagedProfilesAreNotAddedToVpn()496     public void testManagedProfilesAreNotAddedToVpn() {
497         setMockedUsers(PRIMARY_USER, MANAGED_PROFILE_A);
498 
499         final Vpn vpn = createVpn(PRIMARY_USER.id);
500         final Set<Range<Integer>> ranges = vpn.createUserAndRestrictedProfilesRanges(
501                 PRIMARY_USER.id, null, null);
502 
503         assertEquals(rangeSet(PRIMARY_USER_RANGE), ranges);
504     }
505 
506     @Test
testAddUserToVpnOnlyAddsOneUser()507     public void testAddUserToVpnOnlyAddsOneUser() {
508         setMockedUsers(PRIMARY_USER, RESTRICTED_PROFILE_A, MANAGED_PROFILE_A);
509 
510         final Vpn vpn = createVpn(PRIMARY_USER.id);
511         final Set<Range<Integer>> ranges = new ArraySet<>();
512         vpn.addUserToRanges(ranges, PRIMARY_USER.id, null, null);
513 
514         assertEquals(rangeSet(PRIMARY_USER_RANGE), ranges);
515     }
516 
517     @Test
testUidAllowAndDenylist()518     public void testUidAllowAndDenylist() throws Exception {
519         final Vpn vpn = createVpn(PRIMARY_USER.id);
520         final Range<Integer> user = PRIMARY_USER_RANGE;
521         final int userStart = user.getLower();
522         final int userStop = user.getUpper();
523         final String[] packages = {PKGS[0], PKGS[1], PKGS[2]};
524 
525         // Allowed list
526         final Set<Range<Integer>> allow = vpn.createUserAndRestrictedProfilesRanges(PRIMARY_USER.id,
527                 Arrays.asList(packages), null /* disallowedApplications */);
528         assertEquals(rangeSet(
529                 uidRange(userStart + PKG_UIDS[0], userStart + PKG_UIDS[0]),
530                 uidRange(userStart + PKG_UIDS[1], userStart + PKG_UIDS[2]),
531                 uidRange(Process.toSdkSandboxUid(userStart + PKG_UIDS[0]),
532                          Process.toSdkSandboxUid(userStart + PKG_UIDS[0])),
533                 uidRange(Process.toSdkSandboxUid(userStart + PKG_UIDS[1]),
534                          Process.toSdkSandboxUid(userStart + PKG_UIDS[2]))),
535                 allow);
536 
537         // Denied list
538         final Set<Range<Integer>> disallow =
539                 vpn.createUserAndRestrictedProfilesRanges(PRIMARY_USER.id,
540                         null /* allowedApplications */, Arrays.asList(packages));
541         assertEquals(rangeSet(
542                 uidRange(userStart, userStart + PKG_UIDS[0] - 1),
543                 uidRange(userStart + PKG_UIDS[0] + 1, userStart + PKG_UIDS[1] - 1),
544                 /* Empty range between UIDS[1] and UIDS[2], should be excluded, */
545                 uidRange(userStart + PKG_UIDS[2] + 1,
546                          Process.toSdkSandboxUid(userStart + PKG_UIDS[0] - 1)),
547                 uidRange(Process.toSdkSandboxUid(userStart + PKG_UIDS[0] + 1),
548                          Process.toSdkSandboxUid(userStart + PKG_UIDS[1] - 1)),
549                 uidRange(Process.toSdkSandboxUid(userStart + PKG_UIDS[2] + 1), userStop)),
550                 disallow);
551     }
552 
verifyPowerSaveTempWhitelistApp(String packageName)553     private void verifyPowerSaveTempWhitelistApp(String packageName) {
554         verify(mDeviceIdleInternal, timeout(TEST_TIMEOUT_MS)).addPowerSaveTempWhitelistApp(
555                 anyInt(), eq(packageName), anyLong(), anyInt(), eq(false),
556                 eq(PowerWhitelistManager.REASON_VPN), eq("VpnManager event"));
557     }
558 
559     @Test
testGetAlwaysAndOnGetLockDown()560     public void testGetAlwaysAndOnGetLockDown() throws Exception {
561         final Vpn vpn = createVpn(PRIMARY_USER.id);
562 
563         // Default state.
564         assertFalse(vpn.getAlwaysOn());
565         assertFalse(vpn.getLockdown());
566 
567         // Set always-on without lockdown.
568         assertTrue(vpn.setAlwaysOnPackage(PKGS[1], false, Collections.emptyList()));
569         assertTrue(vpn.getAlwaysOn());
570         assertFalse(vpn.getLockdown());
571 
572         // Set always-on with lockdown.
573         assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true, Collections.emptyList()));
574         assertTrue(vpn.getAlwaysOn());
575         assertTrue(vpn.getLockdown());
576 
577         // Remove always-on configuration.
578         assertTrue(vpn.setAlwaysOnPackage(null, false, Collections.emptyList()));
579         assertFalse(vpn.getAlwaysOn());
580         assertFalse(vpn.getLockdown());
581     }
582 
583     @Test
testLockdownChangingPackage()584     public void testLockdownChangingPackage() throws Exception {
585         final Vpn vpn = createVpn(PRIMARY_USER.id);
586         final Range<Integer> user = PRIMARY_USER_RANGE;
587         final int userStart = user.getLower();
588         final int userStop = user.getUpper();
589         // Set always-on without lockdown.
590         assertTrue(vpn.setAlwaysOnPackage(PKGS[1], false, null));
591 
592         // Set always-on with lockdown.
593         assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true, null));
594         verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[] {
595                 new UidRangeParcel(userStart, userStart + PKG_UIDS[1] - 1),
596                 new UidRangeParcel(userStart + PKG_UIDS[1] + 1,
597                                    Process.toSdkSandboxUid(userStart + PKG_UIDS[1] - 1)),
598                 new UidRangeParcel(Process.toSdkSandboxUid(userStart + PKG_UIDS[1] + 1), userStop)
599         }));
600 
601         // Switch to another app.
602         assertTrue(vpn.setAlwaysOnPackage(PKGS[3], true, null));
603         verify(mConnectivityManager).setRequireVpnForUids(false, toRanges(new UidRangeParcel[] {
604                 new UidRangeParcel(userStart, userStart + PKG_UIDS[1] - 1),
605                 new UidRangeParcel(userStart + PKG_UIDS[1] + 1,
606                                    Process.toSdkSandboxUid(userStart + PKG_UIDS[1] - 1)),
607                 new UidRangeParcel(Process.toSdkSandboxUid(userStart + PKG_UIDS[1] + 1), userStop)
608         }));
609         verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[] {
610                 new UidRangeParcel(userStart, userStart + PKG_UIDS[3] - 1),
611                 new UidRangeParcel(userStart + PKG_UIDS[3] + 1,
612                                    Process.toSdkSandboxUid(userStart + PKG_UIDS[3] - 1)),
613                 new UidRangeParcel(Process.toSdkSandboxUid(userStart + PKG_UIDS[3] + 1), userStop)
614         }));
615     }
616 
617     @Test
testLockdownAllowlist()618     public void testLockdownAllowlist() throws Exception {
619         final Vpn vpn = createVpn(PRIMARY_USER.id);
620         final Range<Integer> user = PRIMARY_USER_RANGE;
621         final int userStart = user.getLower();
622         final int userStop = user.getUpper();
623         // Set always-on with lockdown and allow app PKGS[2] from lockdown.
624         assertTrue(vpn.setAlwaysOnPackage(
625                 PKGS[1], true, Collections.singletonList(PKGS[2])));
626         verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[]  {
627                 new UidRangeParcel(userStart, userStart + PKG_UIDS[1] - 1),
628                 new UidRangeParcel(userStart + PKG_UIDS[2] + 1,
629                                    Process.toSdkSandboxUid(userStart + PKG_UIDS[1]) - 1),
630                 new UidRangeParcel(Process.toSdkSandboxUid(userStart + PKG_UIDS[2] + 1), userStop)
631         }));
632         // Change allowed app list to PKGS[3].
633         assertTrue(vpn.setAlwaysOnPackage(
634                 PKGS[1], true, Collections.singletonList(PKGS[3])));
635         verify(mConnectivityManager).setRequireVpnForUids(false, toRanges(new UidRangeParcel[] {
636                 new UidRangeParcel(userStart + PKG_UIDS[2] + 1,
637                                    Process.toSdkSandboxUid(userStart + PKG_UIDS[1] - 1)),
638                 new UidRangeParcel(Process.toSdkSandboxUid(userStart + PKG_UIDS[2] + 1), userStop)
639         }));
640         verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[] {
641                 new UidRangeParcel(userStart + PKG_UIDS[1] + 1, userStart + PKG_UIDS[3] - 1),
642                 new UidRangeParcel(userStart + PKG_UIDS[3] + 1,
643                                    Process.toSdkSandboxUid(userStart + PKG_UIDS[1] - 1)),
644                 new UidRangeParcel(Process.toSdkSandboxUid(userStart + PKG_UIDS[1] + 1),
645                                    Process.toSdkSandboxUid(userStart + PKG_UIDS[3] - 1)),
646                 new UidRangeParcel(Process.toSdkSandboxUid(userStart + PKG_UIDS[3] + 1), userStop)
647         }));
648 
649         // Change the VPN app.
650         assertTrue(vpn.setAlwaysOnPackage(
651                 PKGS[0], true, Collections.singletonList(PKGS[3])));
652         verify(mConnectivityManager).setRequireVpnForUids(false, toRanges(new UidRangeParcel[] {
653                 new UidRangeParcel(userStart, userStart + PKG_UIDS[1] - 1),
654                 new UidRangeParcel(userStart + PKG_UIDS[1] + 1, userStart + PKG_UIDS[3] - 1),
655                 new UidRangeParcel(userStart + PKG_UIDS[3] + 1,
656                                    Process.toSdkSandboxUid(userStart + PKG_UIDS[1] - 1)),
657                 new UidRangeParcel(Process.toSdkSandboxUid(userStart + PKG_UIDS[1] + 1),
658                                    Process.toSdkSandboxUid(userStart + PKG_UIDS[3] - 1))
659         }));
660         verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[] {
661                 new UidRangeParcel(userStart, userStart + PKG_UIDS[0] - 1),
662                 new UidRangeParcel(userStart + PKG_UIDS[0] + 1, userStart + PKG_UIDS[3] - 1),
663                 new UidRangeParcel(userStart + PKG_UIDS[3] + 1,
664                                    Process.toSdkSandboxUid(userStart + PKG_UIDS[0] - 1)),
665                 new UidRangeParcel(Process.toSdkSandboxUid(userStart + PKG_UIDS[0] + 1),
666                                    Process.toSdkSandboxUid(userStart + PKG_UIDS[3] - 1))
667         }));
668 
669         // Remove the list of allowed packages.
670         assertTrue(vpn.setAlwaysOnPackage(PKGS[0], true, null));
671         verify(mConnectivityManager).setRequireVpnForUids(false, toRanges(new UidRangeParcel[] {
672                 new UidRangeParcel(userStart + PKG_UIDS[0] + 1, userStart + PKG_UIDS[3] - 1),
673                 new UidRangeParcel(userStart + PKG_UIDS[3] + 1,
674                                    Process.toSdkSandboxUid(userStart + PKG_UIDS[0] - 1)),
675                 new UidRangeParcel(Process.toSdkSandboxUid(userStart + PKG_UIDS[0] + 1),
676                                    Process.toSdkSandboxUid(userStart + PKG_UIDS[3] - 1)),
677                 new UidRangeParcel(Process.toSdkSandboxUid(userStart + PKG_UIDS[3] + 1), userStop)
678         }));
679         verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[] {
680                 new UidRangeParcel(userStart + PKG_UIDS[0] + 1,
681                                    Process.toSdkSandboxUid(userStart + PKG_UIDS[0] - 1)),
682                 new UidRangeParcel(Process.toSdkSandboxUid(userStart + PKG_UIDS[0] + 1), userStop),
683         }));
684 
685         // Add the list of allowed packages.
686         assertTrue(vpn.setAlwaysOnPackage(
687                 PKGS[0], true, Collections.singletonList(PKGS[1])));
688         verify(mConnectivityManager).setRequireVpnForUids(false, toRanges(new UidRangeParcel[] {
689                 new UidRangeParcel(userStart + PKG_UIDS[0] + 1,
690                                    Process.toSdkSandboxUid(userStart + PKG_UIDS[0] - 1)),
691                 new UidRangeParcel(Process.toSdkSandboxUid(userStart + PKG_UIDS[0] + 1), userStop),
692         }));
693         verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[] {
694                 new UidRangeParcel(userStart + PKG_UIDS[0] + 1, userStart + PKG_UIDS[1] - 1),
695                 new UidRangeParcel(userStart + PKG_UIDS[1] + 1,
696                                    Process.toSdkSandboxUid(userStart + PKG_UIDS[0] - 1)),
697                 new UidRangeParcel(Process.toSdkSandboxUid(userStart + PKG_UIDS[0] + 1),
698                                    Process.toSdkSandboxUid(userStart + PKG_UIDS[1] - 1)),
699                 new UidRangeParcel(Process.toSdkSandboxUid(userStart + PKG_UIDS[1] + 1), userStop)
700         }));
701 
702         // Try allowing a package with a comma, should be rejected.
703         assertFalse(vpn.setAlwaysOnPackage(
704                 PKGS[0], true, Collections.singletonList("a.b,c.d")));
705 
706         // Pass a non-existent packages in the allowlist, they (and only they) should be ignored.
707         // allowed package should change from PGKS[1] to PKGS[2].
708         assertTrue(vpn.setAlwaysOnPackage(
709                 PKGS[0], true, Arrays.asList("com.foo.app", PKGS[2], "com.bar.app")));
710         verify(mConnectivityManager).setRequireVpnForUids(false, toRanges(new UidRangeParcel[] {
711                 new UidRangeParcel(userStart + PKG_UIDS[0] + 1, userStart + PKG_UIDS[1] - 1),
712                 new UidRangeParcel(userStart + PKG_UIDS[1] + 1,
713                                    Process.toSdkSandboxUid(userStart + PKG_UIDS[0] - 1)),
714                 new UidRangeParcel(Process.toSdkSandboxUid(userStart + PKG_UIDS[0] + 1),
715                                    Process.toSdkSandboxUid(userStart + PKG_UIDS[1] - 1)),
716                 new UidRangeParcel(Process.toSdkSandboxUid(userStart + PKG_UIDS[1] + 1), userStop)
717         }));
718         verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[] {
719                 new UidRangeParcel(userStart + PKG_UIDS[0] + 1, userStart + PKG_UIDS[2] - 1),
720                 new UidRangeParcel(userStart + PKG_UIDS[2] + 1,
721                                    Process.toSdkSandboxUid(userStart + PKG_UIDS[0] - 1)),
722                 new UidRangeParcel(Process.toSdkSandboxUid(userStart + PKG_UIDS[0] + 1),
723                                    Process.toSdkSandboxUid(userStart + PKG_UIDS[2] - 1)),
724                 new UidRangeParcel(Process.toSdkSandboxUid(userStart + PKG_UIDS[2] + 1), userStop)
725         }));
726     }
727 
728     @Test
testLockdownRuleRepeatability()729     public void testLockdownRuleRepeatability() throws Exception {
730         final Vpn vpn = createVpn(PRIMARY_USER.id);
731         final UidRangeParcel[] primaryUserRangeParcel = new UidRangeParcel[] {
732                 new UidRangeParcel(PRIMARY_USER_RANGE.getLower(), PRIMARY_USER_RANGE.getUpper())};
733         // Given legacy lockdown is already enabled,
734         vpn.setLockdown(true);
735         verify(mConnectivityManager, times(1)).setRequireVpnForUids(true,
736                 toRanges(primaryUserRangeParcel));
737 
738         // Enabling legacy lockdown twice should do nothing.
739         vpn.setLockdown(true);
740         verify(mConnectivityManager, times(1)).setRequireVpnForUids(anyBoolean(), any());
741 
742         // And disabling should remove the rules exactly once.
743         vpn.setLockdown(false);
744         verify(mConnectivityManager, times(1)).setRequireVpnForUids(false,
745                 toRanges(primaryUserRangeParcel));
746 
747         // Removing the lockdown again should have no effect.
748         vpn.setLockdown(false);
749         verify(mConnectivityManager, times(2)).setRequireVpnForUids(anyBoolean(), any());
750     }
751 
toRanges(UidRangeParcel[] ranges)752     private ArrayList<Range<Integer>> toRanges(UidRangeParcel[] ranges) {
753         ArrayList<Range<Integer>> rangesArray = new ArrayList<>(ranges.length);
754         for (int i = 0; i < ranges.length; i++) {
755             rangesArray.add(new Range<>(ranges[i].start, ranges[i].stop));
756         }
757         return rangesArray;
758     }
759 
760     @Test
testLockdownRuleReversibility()761     public void testLockdownRuleReversibility() throws Exception {
762         doReturn(PERMISSION_GRANTED).when(mContext).checkCallingOrSelfPermission(CONTROL_VPN);
763         final Vpn vpn = createVpn(PRIMARY_USER.id);
764         final UidRangeParcel[] entireUser = {
765             new UidRangeParcel(PRIMARY_USER_RANGE.getLower(), PRIMARY_USER_RANGE.getUpper())
766         };
767         final UidRangeParcel[] exceptPkg0 = {
768             new UidRangeParcel(entireUser[0].start, entireUser[0].start + PKG_UIDS[0] - 1),
769             new UidRangeParcel(entireUser[0].start + PKG_UIDS[0] + 1,
770                                Process.toSdkSandboxUid(entireUser[0].start + PKG_UIDS[0] - 1)),
771             new UidRangeParcel(Process.toSdkSandboxUid(entireUser[0].start + PKG_UIDS[0] + 1),
772                                entireUser[0].stop),
773         };
774 
775         final InOrder order = inOrder(mConnectivityManager);
776 
777         // Given lockdown is enabled with no package (legacy VPN),
778         vpn.setLockdown(true);
779         order.verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(entireUser));
780 
781         // When a new VPN package is set the rules should change to cover that package.
782         vpn.prepare(null, PKGS[0], VpnManager.TYPE_VPN_SERVICE);
783         order.verify(mConnectivityManager).setRequireVpnForUids(false, toRanges(entireUser));
784         order.verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(exceptPkg0));
785 
786         // When that VPN package is unset, everything should be undone again in reverse.
787         vpn.prepare(null, VpnConfig.LEGACY_VPN, VpnManager.TYPE_VPN_SERVICE);
788         order.verify(mConnectivityManager).setRequireVpnForUids(false, toRanges(exceptPkg0));
789         order.verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(entireUser));
790     }
791 
792     @Test
testPrepare_throwSecurityExceptionWhenGivenPackageDoesNotBelongToTheCaller()793     public void testPrepare_throwSecurityExceptionWhenGivenPackageDoesNotBelongToTheCaller()
794             throws Exception {
795         mTestDeps.mIgnoreCallingUidChecks = false;
796         final Vpn vpn = createVpn();
797         assertThrows(SecurityException.class,
798                 () -> vpn.prepare("com.not.vpn.owner", null, VpnManager.TYPE_VPN_SERVICE));
799         assertThrows(SecurityException.class,
800                 () -> vpn.prepare(null, "com.not.vpn.owner", VpnManager.TYPE_VPN_SERVICE));
801         assertThrows(SecurityException.class,
802                 () -> vpn.prepare("com.not.vpn.owner1", "com.not.vpn.owner2",
803                         VpnManager.TYPE_VPN_SERVICE));
804     }
805 
806     @Test
testPrepare_bothOldPackageAndNewPackageAreNull()807     public void testPrepare_bothOldPackageAndNewPackageAreNull() throws Exception {
808         final Vpn vpn = createVpn();
809         assertTrue(vpn.prepare(null, null, VpnManager.TYPE_VPN_SERVICE));
810 
811     }
812 
813     @Test
testIsAlwaysOnPackageSupported()814     public void testIsAlwaysOnPackageSupported() throws Exception {
815         final Vpn vpn = createVpn(PRIMARY_USER.id);
816 
817         ApplicationInfo appInfo = new ApplicationInfo();
818         when(mPackageManager.getApplicationInfoAsUser(eq(PKGS[0]), anyInt(), eq(PRIMARY_USER.id)))
819                 .thenReturn(appInfo);
820 
821         ServiceInfo svcInfo = new ServiceInfo();
822         ResolveInfo resInfo = new ResolveInfo();
823         resInfo.serviceInfo = svcInfo;
824         when(mPackageManager.queryIntentServicesAsUser(any(), eq(PackageManager.GET_META_DATA),
825                 eq(PRIMARY_USER.id)))
826                 .thenReturn(Collections.singletonList(resInfo));
827 
828         // null package name should return false
829         assertFalse(vpn.isAlwaysOnPackageSupported(null));
830 
831         // Pre-N apps are not supported
832         appInfo.targetSdkVersion = VERSION_CODES.M;
833         assertFalse(vpn.isAlwaysOnPackageSupported(PKGS[0]));
834 
835         // N+ apps are supported by default
836         appInfo.targetSdkVersion = VERSION_CODES.N;
837         assertTrue(vpn.isAlwaysOnPackageSupported(PKGS[0]));
838 
839         // Apps that opt out explicitly are not supported
840         appInfo.targetSdkVersion = VERSION_CODES.CUR_DEVELOPMENT;
841         Bundle metaData = new Bundle();
842         metaData.putBoolean(VpnService.SERVICE_META_DATA_SUPPORTS_ALWAYS_ON, false);
843         svcInfo.metaData = metaData;
844         assertFalse(vpn.isAlwaysOnPackageSupported(PKGS[0]));
845     }
846 
847     @Test
testNotificationShownForAlwaysOnApp()848     public void testNotificationShownForAlwaysOnApp() throws Exception {
849         final UserHandle userHandle = UserHandle.of(PRIMARY_USER.id);
850         final Vpn vpn = createVpn(PRIMARY_USER.id);
851         setMockedUsers(PRIMARY_USER);
852 
853         final InOrder order = inOrder(mNotificationManager);
854 
855         // Don't show a notification for regular disconnected states.
856         vpn.updateState(DetailedState.DISCONNECTED, TAG);
857         order.verify(mNotificationManager, atLeastOnce()).cancel(anyString(), anyInt());
858 
859         // Start showing a notification for disconnected once always-on.
860         vpn.setAlwaysOnPackage(PKGS[0], false, null);
861         order.verify(mNotificationManager).notify(anyString(), anyInt(), any());
862 
863         // Stop showing the notification once connected.
864         vpn.updateState(DetailedState.CONNECTED, TAG);
865         order.verify(mNotificationManager).cancel(anyString(), anyInt());
866 
867         // Show the notification if we disconnect again.
868         vpn.updateState(DetailedState.DISCONNECTED, TAG);
869         order.verify(mNotificationManager).notify(anyString(), anyInt(), any());
870 
871         // Notification should be cleared after unsetting always-on package.
872         vpn.setAlwaysOnPackage(null, false, null);
873         order.verify(mNotificationManager).cancel(anyString(), anyInt());
874     }
875 
876     /**
877      * The profile name should NOT change between releases for backwards compatibility
878      *
879      * <p>If this is changed between releases, the {@link Vpn#getVpnProfilePrivileged()} method MUST
880      * be updated to ensure backward compatibility.
881      */
882     @Test
testGetProfileNameForPackage()883     public void testGetProfileNameForPackage() throws Exception {
884         final Vpn vpn = createVpn(PRIMARY_USER.id);
885         setMockedUsers(PRIMARY_USER);
886 
887         final String expected = Credentials.PLATFORM_VPN + PRIMARY_USER.id + "_" + TEST_VPN_PKG;
888         assertEquals(expected, vpn.getProfileNameForPackage(TEST_VPN_PKG));
889     }
890 
createVpn(String... grantedOps)891     private Vpn createVpn(String... grantedOps) throws Exception {
892         return createVpn(PRIMARY_USER, grantedOps);
893     }
894 
createVpn(UserInfo user, String... grantedOps)895     private Vpn createVpn(UserInfo user, String... grantedOps) throws Exception {
896         final Vpn vpn = createVpn(user.id);
897         setMockedUsers(user);
898 
899         for (final String opStr : grantedOps) {
900             when(mAppOps.noteOpNoThrow(opStr, Process.myUid(), TEST_VPN_PKG,
901                     null /* attributionTag */, null /* message */))
902                     .thenReturn(AppOpsManager.MODE_ALLOWED);
903         }
904 
905         return vpn;
906     }
907 
checkProvisionVpnProfile(Vpn vpn, boolean expectedResult, String... checkedOps)908     private void checkProvisionVpnProfile(Vpn vpn, boolean expectedResult, String... checkedOps) {
909         assertEquals(expectedResult, vpn.provisionVpnProfile(TEST_VPN_PKG, mVpnProfile));
910 
911         // The profile should always be stored, whether or not consent has been previously granted.
912         verify(mVpnProfileStore)
913                 .put(
914                         eq(vpn.getProfileNameForPackage(TEST_VPN_PKG)),
915                         eq(mVpnProfile.encode()));
916 
917         for (final String checkedOpStr : checkedOps) {
918             verify(mAppOps).noteOpNoThrow(checkedOpStr, Process.myUid(), TEST_VPN_PKG,
919                     null /* attributionTag */, null /* message */);
920         }
921     }
922 
923     @Test
testProvisionVpnProfileNoIpsecTunnels()924     public void testProvisionVpnProfileNoIpsecTunnels() throws Exception {
925         when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_IPSEC_TUNNELS))
926                 .thenReturn(false);
927         final Vpn vpn = createVpn(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
928 
929         try {
930             checkProvisionVpnProfile(
931                     vpn, true /* expectedResult */, AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
932             fail("Expected exception due to missing feature");
933         } catch (UnsupportedOperationException expected) {
934         }
935     }
936 
prepareVpnForVerifyAppExclusionList()937     private Vpn prepareVpnForVerifyAppExclusionList() throws Exception {
938         final Vpn vpn = createVpn(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
939         when(mVpnProfileStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG)))
940                 .thenReturn(mVpnProfile.encode());
941         when(mVpnProfileStore.get(PRIMARY_USER_APP_EXCLUDE_KEY))
942                 .thenReturn(HexDump.hexStringToByteArray(PKGS_BYTES));
943 
944         vpn.startVpnProfile(TEST_VPN_PKG);
945         verify(mVpnProfileStore).get(eq(vpn.getProfileNameForPackage(TEST_VPN_PKG)));
946         vpn.mNetworkAgent = mMockNetworkAgent;
947         return vpn;
948     }
949 
950     @Test
testSetAndGetAppExclusionList()951     public void testSetAndGetAppExclusionList() throws Exception {
952         final Vpn vpn = prepareVpnForVerifyAppExclusionList();
953         verify(mVpnProfileStore, never()).put(eq(PRIMARY_USER_APP_EXCLUDE_KEY), any());
954         vpn.setAppExclusionList(TEST_VPN_PKG, Arrays.asList(PKGS));
955         verify(mVpnProfileStore)
956                 .put(eq(PRIMARY_USER_APP_EXCLUDE_KEY),
957                      eq(HexDump.hexStringToByteArray(PKGS_BYTES)));
958         assertEquals(vpn.createUserAndRestrictedProfilesRanges(
959                 PRIMARY_USER.id, null, Arrays.asList(PKGS)),
960                 vpn.mNetworkCapabilities.getUids());
961         assertEquals(Arrays.asList(PKGS), vpn.getAppExclusionList(TEST_VPN_PKG));
962     }
963 
964     @Test
testRefreshPlatformVpnAppExclusionList_updatesExcludedUids()965     public void testRefreshPlatformVpnAppExclusionList_updatesExcludedUids() throws Exception {
966         final Vpn vpn = prepareVpnForVerifyAppExclusionList();
967         vpn.setAppExclusionList(TEST_VPN_PKG, Arrays.asList(PKGS));
968         verify(mMockNetworkAgent).doSendNetworkCapabilities(any());
969         assertEquals(Arrays.asList(PKGS), vpn.getAppExclusionList(TEST_VPN_PKG));
970 
971         reset(mMockNetworkAgent);
972 
973         // Remove one of the package
974         List<Integer> newExcludedUids = toList(PKG_UIDS);
975         newExcludedUids.remove((Integer) PKG_UIDS[0]);
976         sPackages.remove(PKGS[0]);
977         vpn.refreshPlatformVpnAppExclusionList();
978 
979         // List in keystore is not changed, but UID for the removed packages is no longer exempted.
980         assertEquals(Arrays.asList(PKGS), vpn.getAppExclusionList(TEST_VPN_PKG));
981         assertEquals(makeVpnUidRange(PRIMARY_USER.id, newExcludedUids),
982                 vpn.mNetworkCapabilities.getUids());
983         ArgumentCaptor<NetworkCapabilities> ncCaptor =
984                 ArgumentCaptor.forClass(NetworkCapabilities.class);
985         verify(mMockNetworkAgent).doSendNetworkCapabilities(ncCaptor.capture());
986         assertEquals(makeVpnUidRange(PRIMARY_USER.id, newExcludedUids),
987                 ncCaptor.getValue().getUids());
988 
989         reset(mMockNetworkAgent);
990 
991         // Add the package back
992         newExcludedUids.add(PKG_UIDS[0]);
993         sPackages.put(PKGS[0], PKG_UIDS[0]);
994         vpn.refreshPlatformVpnAppExclusionList();
995 
996         // List in keystore is not changed and the uid list should be updated in the net cap.
997         assertEquals(Arrays.asList(PKGS), vpn.getAppExclusionList(TEST_VPN_PKG));
998         assertEquals(makeVpnUidRange(PRIMARY_USER.id, newExcludedUids),
999                 vpn.mNetworkCapabilities.getUids());
1000         verify(mMockNetworkAgent).doSendNetworkCapabilities(ncCaptor.capture());
1001         assertEquals(makeVpnUidRange(PRIMARY_USER.id, newExcludedUids),
1002                 ncCaptor.getValue().getUids());
1003     }
1004 
makeVpnUidRange(int userId, List<Integer> excludedList)1005     private Set<Range<Integer>> makeVpnUidRange(int userId, List<Integer> excludedList) {
1006         final SortedSet<Integer> list = new TreeSet<>();
1007 
1008         final int userBase = userId * UserHandle.PER_USER_RANGE;
1009         for (int uid : excludedList) {
1010             final int applicationUid = UserHandle.getUid(userId, uid);
1011             list.add(applicationUid);
1012             list.add(Process.toSdkSandboxUid(applicationUid)); // Add Sdk Sandbox UID
1013         }
1014 
1015         final int minUid = userBase;
1016         final int maxUid = userBase + UserHandle.PER_USER_RANGE - 1;
1017         final Set<Range<Integer>> ranges = new ArraySet<>();
1018 
1019         // Iterate the list to create the ranges between each uid.
1020         int start = minUid;
1021         for (int uid : list) {
1022             if (uid == start) {
1023                 start++;
1024             } else {
1025                 ranges.add(new Range<>(start, uid - 1));
1026                 start = uid + 1;
1027             }
1028         }
1029 
1030         // Create the range between last uid and max uid.
1031         if (start <= maxUid) {
1032             ranges.add(new Range<>(start, maxUid));
1033         }
1034 
1035         return ranges;
1036     }
1037 
1038     @Test
testSetAndGetAppExclusionListRestrictedUser()1039     public void testSetAndGetAppExclusionListRestrictedUser() throws Exception {
1040         final Vpn vpn = prepareVpnForVerifyAppExclusionList();
1041 
1042         // Mock it to restricted profile
1043         when(mUserManager.getUserInfo(anyInt())).thenReturn(RESTRICTED_PROFILE_A);
1044 
1045         // Restricted users cannot configure VPNs
1046         assertThrows(SecurityException.class,
1047                 () -> vpn.setAppExclusionList(TEST_VPN_PKG, new ArrayList<>()));
1048 
1049         assertEquals(Arrays.asList(PKGS), vpn.getAppExclusionList(TEST_VPN_PKG));
1050     }
1051 
1052     @Test
testProvisionVpnProfilePreconsented()1053     public void testProvisionVpnProfilePreconsented() throws Exception {
1054         final Vpn vpn = createVpn(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
1055 
1056         checkProvisionVpnProfile(
1057                 vpn, true /* expectedResult */, AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
1058     }
1059 
1060     @Test
testProvisionVpnProfileNotPreconsented()1061     public void testProvisionVpnProfileNotPreconsented() throws Exception {
1062         final Vpn vpn = createVpn();
1063 
1064         // Expect that both the ACTIVATE_VPN and ACTIVATE_PLATFORM_VPN were tried, but the caller
1065         // had neither.
1066         checkProvisionVpnProfile(vpn, false /* expectedResult */,
1067                 AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN, AppOpsManager.OPSTR_ACTIVATE_VPN);
1068     }
1069 
1070     @Test
testProvisionVpnProfileVpnServicePreconsented()1071     public void testProvisionVpnProfileVpnServicePreconsented() throws Exception {
1072         final Vpn vpn = createVpn(AppOpsManager.OPSTR_ACTIVATE_VPN);
1073 
1074         checkProvisionVpnProfile(vpn, true /* expectedResult */, AppOpsManager.OPSTR_ACTIVATE_VPN);
1075     }
1076 
1077     @Test
testProvisionVpnProfileTooLarge()1078     public void testProvisionVpnProfileTooLarge() throws Exception {
1079         final Vpn vpn = createVpn(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
1080 
1081         final VpnProfile bigProfile = new VpnProfile("");
1082         bigProfile.name = new String(new byte[Vpn.MAX_VPN_PROFILE_SIZE_BYTES + 1]);
1083 
1084         try {
1085             vpn.provisionVpnProfile(TEST_VPN_PKG, bigProfile);
1086             fail("Expected IAE due to profile size");
1087         } catch (IllegalArgumentException expected) {
1088         }
1089     }
1090 
1091     @Test
testProvisionVpnProfileRestrictedUser()1092     public void testProvisionVpnProfileRestrictedUser() throws Exception {
1093         final Vpn vpn =
1094                 createVpn(
1095                         RESTRICTED_PROFILE_A, AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
1096 
1097         try {
1098             vpn.provisionVpnProfile(TEST_VPN_PKG, mVpnProfile);
1099             fail("Expected SecurityException due to restricted user");
1100         } catch (SecurityException expected) {
1101         }
1102     }
1103 
1104     @Test
testDeleteVpnProfile()1105     public void testDeleteVpnProfile() throws Exception {
1106         final Vpn vpn = createVpn();
1107 
1108         vpn.deleteVpnProfile(TEST_VPN_PKG);
1109 
1110         verify(mVpnProfileStore)
1111                 .remove(eq(vpn.getProfileNameForPackage(TEST_VPN_PKG)));
1112     }
1113 
1114     @Test
testDeleteVpnProfileRestrictedUser()1115     public void testDeleteVpnProfileRestrictedUser() throws Exception {
1116         final Vpn vpn =
1117                 createVpn(
1118                         RESTRICTED_PROFILE_A, AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
1119 
1120         try {
1121             vpn.deleteVpnProfile(TEST_VPN_PKG);
1122             fail("Expected SecurityException due to restricted user");
1123         } catch (SecurityException expected) {
1124         }
1125     }
1126 
1127     @Test
testGetVpnProfilePrivileged()1128     public void testGetVpnProfilePrivileged() throws Exception {
1129         final Vpn vpn = createVpn();
1130 
1131         when(mVpnProfileStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG)))
1132                 .thenReturn(new VpnProfile("").encode());
1133 
1134         vpn.getVpnProfilePrivileged(TEST_VPN_PKG);
1135 
1136         verify(mVpnProfileStore).get(eq(vpn.getProfileNameForPackage(TEST_VPN_PKG)));
1137     }
1138 
verifyPlatformVpnIsActivated(String packageName)1139     private void verifyPlatformVpnIsActivated(String packageName) {
1140         verify(mAppOps).noteOpNoThrow(
1141                 eq(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN),
1142                 eq(Process.myUid()),
1143                 eq(packageName),
1144                 eq(null) /* attributionTag */,
1145                 eq(null) /* message */);
1146         verify(mAppOps).startOp(
1147                 eq(AppOpsManager.OPSTR_ESTABLISH_VPN_MANAGER),
1148                 eq(UserHandle.getUid(PRIMARY_USER.id, Process.myUid())),
1149                 eq(packageName),
1150                 eq(null) /* attributionTag */,
1151                 eq(null) /* message */);
1152     }
1153 
verifyPlatformVpnIsDeactivated(String packageName)1154     private void verifyPlatformVpnIsDeactivated(String packageName) {
1155         // Add a small delay to double confirm that finishOp is only called once.
1156         verify(mAppOps, after(100)).finishOp(
1157                 eq(AppOpsManager.OPSTR_ESTABLISH_VPN_MANAGER),
1158                 eq(UserHandle.getUid(PRIMARY_USER.id, Process.myUid())),
1159                 eq(packageName),
1160                 eq(null) /* attributionTag */);
1161     }
1162 
1163     @Test
testStartVpnProfile()1164     public void testStartVpnProfile() throws Exception {
1165         final Vpn vpn = createVpn(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
1166 
1167         when(mVpnProfileStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG)))
1168                 .thenReturn(mVpnProfile.encode());
1169 
1170         vpn.startVpnProfile(TEST_VPN_PKG);
1171 
1172         verify(mVpnProfileStore).get(eq(vpn.getProfileNameForPackage(TEST_VPN_PKG)));
1173         verifyPlatformVpnIsActivated(TEST_VPN_PKG);
1174     }
1175 
1176     @Test
testStartVpnProfileVpnServicePreconsented()1177     public void testStartVpnProfileVpnServicePreconsented() throws Exception {
1178         final Vpn vpn = createVpn(AppOpsManager.OPSTR_ACTIVATE_VPN);
1179 
1180         when(mVpnProfileStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG)))
1181                 .thenReturn(mVpnProfile.encode());
1182 
1183         vpn.startVpnProfile(TEST_VPN_PKG);
1184 
1185         // Verify that the ACTIVATE_VPN appop was checked, but no error was thrown.
1186         verify(mAppOps).noteOpNoThrow(AppOpsManager.OPSTR_ACTIVATE_VPN, Process.myUid(),
1187                 TEST_VPN_PKG, null /* attributionTag */, null /* message */);
1188     }
1189 
1190     @Test
testStartVpnProfileNotConsented()1191     public void testStartVpnProfileNotConsented() throws Exception {
1192         final Vpn vpn = createVpn();
1193 
1194         try {
1195             vpn.startVpnProfile(TEST_VPN_PKG);
1196             fail("Expected failure due to no user consent");
1197         } catch (SecurityException expected) {
1198         }
1199 
1200         // Verify both appops were checked.
1201         verify(mAppOps)
1202                 .noteOpNoThrow(
1203                         eq(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN),
1204                         eq(Process.myUid()),
1205                         eq(TEST_VPN_PKG),
1206                         eq(null) /* attributionTag */,
1207                         eq(null) /* message */);
1208         verify(mAppOps).noteOpNoThrow(AppOpsManager.OPSTR_ACTIVATE_VPN, Process.myUid(),
1209                 TEST_VPN_PKG, null /* attributionTag */, null /* message */);
1210 
1211         // Keystore should never have been accessed.
1212         verify(mVpnProfileStore, never()).get(any());
1213     }
1214 
1215     @Test
testStartVpnProfileMissingProfile()1216     public void testStartVpnProfileMissingProfile() throws Exception {
1217         final Vpn vpn = createVpn(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
1218 
1219         when(mVpnProfileStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG))).thenReturn(null);
1220 
1221         try {
1222             vpn.startVpnProfile(TEST_VPN_PKG);
1223             fail("Expected failure due to missing profile");
1224         } catch (IllegalArgumentException expected) {
1225         }
1226 
1227         verify(mVpnProfileStore).get(vpn.getProfileNameForPackage(TEST_VPN_PKG));
1228         verify(mAppOps)
1229                 .noteOpNoThrow(
1230                         eq(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN),
1231                         eq(Process.myUid()),
1232                         eq(TEST_VPN_PKG),
1233                         eq(null) /* attributionTag */,
1234                         eq(null) /* message */);
1235     }
1236 
1237     @Test
testStartVpnProfileRestrictedUser()1238     public void testStartVpnProfileRestrictedUser() throws Exception {
1239         final Vpn vpn = createVpn(RESTRICTED_PROFILE_A, AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
1240 
1241         try {
1242             vpn.startVpnProfile(TEST_VPN_PKG);
1243             fail("Expected SecurityException due to restricted user");
1244         } catch (SecurityException expected) {
1245         }
1246     }
1247 
1248     @Test
testStopVpnProfileRestrictedUser()1249     public void testStopVpnProfileRestrictedUser() throws Exception {
1250         final Vpn vpn = createVpn(RESTRICTED_PROFILE_A, AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
1251 
1252         try {
1253             vpn.stopVpnProfile(TEST_VPN_PKG);
1254             fail("Expected SecurityException due to restricted user");
1255         } catch (SecurityException expected) {
1256         }
1257     }
1258 
1259     @Test
testStartOpAndFinishOpWillBeCalledWhenPlatformVpnIsOnAndOff()1260     public void testStartOpAndFinishOpWillBeCalledWhenPlatformVpnIsOnAndOff() throws Exception {
1261         final Vpn vpn = createVpn(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
1262         when(mVpnProfileStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG)))
1263                 .thenReturn(mVpnProfile.encode());
1264         vpn.startVpnProfile(TEST_VPN_PKG);
1265         verifyPlatformVpnIsActivated(TEST_VPN_PKG);
1266         // Add a small delay to make sure that startOp is only called once.
1267         verify(mAppOps, after(100).times(1)).startOp(
1268                 eq(AppOpsManager.OPSTR_ESTABLISH_VPN_MANAGER),
1269                 eq(UserHandle.getUid(PRIMARY_USER.id, Process.myUid())),
1270                 eq(TEST_VPN_PKG),
1271                 eq(null) /* attributionTag */,
1272                 eq(null) /* message */);
1273         // Check that the startOp is not called with OPSTR_ESTABLISH_VPN_SERVICE.
1274         verify(mAppOps, never()).startOp(
1275                 eq(AppOpsManager.OPSTR_ESTABLISH_VPN_SERVICE),
1276                 eq(UserHandle.getUid(PRIMARY_USER.id, Process.myUid())),
1277                 eq(TEST_VPN_PKG),
1278                 eq(null) /* attributionTag */,
1279                 eq(null) /* message */);
1280         vpn.stopVpnProfile(TEST_VPN_PKG);
1281         verifyPlatformVpnIsDeactivated(TEST_VPN_PKG);
1282     }
1283 
1284     @Test
testStartOpWithSeamlessHandover()1285     public void testStartOpWithSeamlessHandover() throws Exception {
1286         // Create with SYSTEM_USER so that establish() will match the user ID when checking
1287         // against Binder.getCallerUid
1288         final Vpn vpn = createVpn(SYSTEM_USER, AppOpsManager.OPSTR_ACTIVATE_VPN);
1289         assertTrue(vpn.prepare(TEST_VPN_PKG, null, VpnManager.TYPE_VPN_SERVICE));
1290         final VpnConfig config = new VpnConfig();
1291         config.user = "VpnTest";
1292         config.addresses.add(new LinkAddress("192.0.2.2/32"));
1293         config.mtu = 1450;
1294         final ResolveInfo resolveInfo = new ResolveInfo();
1295         final ServiceInfo serviceInfo = new ServiceInfo();
1296         serviceInfo.permission = BIND_VPN_SERVICE;
1297         resolveInfo.serviceInfo = serviceInfo;
1298         when(mPackageManager.resolveService(any(), anyInt())).thenReturn(resolveInfo);
1299         when(mContext.bindServiceAsUser(any(), any(), anyInt(), any())).thenReturn(true);
1300         vpn.establish(config);
1301         verify(mAppOps, times(1)).startOp(
1302                 eq(AppOpsManager.OPSTR_ESTABLISH_VPN_SERVICE),
1303                 eq(Process.myUid()),
1304                 eq(TEST_VPN_PKG),
1305                 eq(null) /* attributionTag */,
1306                 eq(null) /* message */);
1307         // Call establish() twice with the same config, it should match seamless handover case and
1308         // startOp() shouldn't be called again.
1309         vpn.establish(config);
1310         verify(mAppOps, times(1)).startOp(
1311                 eq(AppOpsManager.OPSTR_ESTABLISH_VPN_SERVICE),
1312                 eq(Process.myUid()),
1313                 eq(TEST_VPN_PKG),
1314                 eq(null) /* attributionTag */,
1315                 eq(null) /* message */);
1316     }
1317 
verifyVpnManagerEvent(String sessionKey, String category, int errorClass, int errorCode, String[] packageName, @NonNull VpnProfileState... profileState)1318     private void verifyVpnManagerEvent(String sessionKey, String category, int errorClass,
1319             int errorCode, String[] packageName, @NonNull VpnProfileState... profileState) {
1320         final Context userContext =
1321                 mContext.createContextAsUser(UserHandle.of(PRIMARY_USER.id), 0 /* flags */);
1322         final ArgumentCaptor<Intent> intentArgumentCaptor = ArgumentCaptor.forClass(Intent.class);
1323 
1324         final int verifyTimes = profileState.length;
1325         verify(userContext, times(verifyTimes)).startService(intentArgumentCaptor.capture());
1326 
1327         for (int i = 0; i < verifyTimes; i++) {
1328             final Intent intent = intentArgumentCaptor.getAllValues().get(i);
1329             assertEquals(packageName[i], intent.getPackage());
1330             assertEquals(sessionKey, intent.getStringExtra(VpnManager.EXTRA_SESSION_KEY));
1331             final Set<String> categories = intent.getCategories();
1332             assertTrue(categories.contains(category));
1333             assertEquals(1, categories.size());
1334             assertEquals(errorClass,
1335                     intent.getIntExtra(VpnManager.EXTRA_ERROR_CLASS, -1 /* defaultValue */));
1336             assertEquals(errorCode,
1337                     intent.getIntExtra(VpnManager.EXTRA_ERROR_CODE, -1 /* defaultValue */));
1338             // CATEGORY_EVENT_DEACTIVATED_BY_USER & CATEGORY_EVENT_ALWAYS_ON_STATE_CHANGED won't
1339             // send NetworkCapabilities & LinkProperties to VPN app.
1340             // For ERROR_CODE_NETWORK_LOST, the NetworkCapabilities & LinkProperties of underlying
1341             // network will be cleared. So the VPN app will receive null for those 2 extra values.
1342             if (category.equals(VpnManager.CATEGORY_EVENT_DEACTIVATED_BY_USER)
1343                     || category.equals(VpnManager.CATEGORY_EVENT_ALWAYS_ON_STATE_CHANGED)
1344                     || errorCode == VpnManager.ERROR_CODE_NETWORK_LOST) {
1345                 assertNull(intent.getParcelableExtra(
1346                         VpnManager.EXTRA_UNDERLYING_NETWORK_CAPABILITIES));
1347                 assertNull(intent.getParcelableExtra(VpnManager.EXTRA_UNDERLYING_LINK_PROPERTIES));
1348             } else {
1349                 assertNotNull(intent.getParcelableExtra(
1350                         VpnManager.EXTRA_UNDERLYING_NETWORK_CAPABILITIES));
1351                 assertNotNull(intent.getParcelableExtra(
1352                         VpnManager.EXTRA_UNDERLYING_LINK_PROPERTIES));
1353             }
1354 
1355             assertEquals(profileState[i], intent.getParcelableExtra(
1356                     VpnManager.EXTRA_VPN_PROFILE_STATE, VpnProfileState.class));
1357         }
1358         reset(userContext);
1359     }
1360 
verifyDeactivatedByUser(String sessionKey, String[] packageName)1361     private void verifyDeactivatedByUser(String sessionKey, String[] packageName) {
1362         // CATEGORY_EVENT_DEACTIVATED_BY_USER is not an error event, so both of errorClass and
1363         // errorCode won't be set.
1364         verifyVpnManagerEvent(sessionKey, VpnManager.CATEGORY_EVENT_DEACTIVATED_BY_USER,
1365                 -1 /* errorClass */, -1 /* errorCode */, packageName,
1366                 // VPN NetworkAgnet does not switch to CONNECTED in the test, and the state is not
1367                 // important here. Verify that the state as it is, i.e. CONNECTING state.
1368                 new VpnProfileState(VpnProfileState.STATE_CONNECTING,
1369                         sessionKey, false /* alwaysOn */, false /* lockdown */));
1370     }
1371 
verifyAlwaysOnStateChanged(String[] packageName, VpnProfileState... profileState)1372     private void verifyAlwaysOnStateChanged(String[] packageName, VpnProfileState... profileState) {
1373         verifyVpnManagerEvent(null /* sessionKey */,
1374                 VpnManager.CATEGORY_EVENT_ALWAYS_ON_STATE_CHANGED, -1 /* errorClass */,
1375                 -1 /* errorCode */, packageName, profileState);
1376     }
1377 
1378     @Test
testVpnManagerEventForUserDeactivated()1379     public void testVpnManagerEventForUserDeactivated() throws Exception {
1380         // For security reasons, Vpn#prepare() will check that oldPackage and newPackage are either
1381         // null or the package of the caller. This test will call Vpn#prepare() to pretend the old
1382         // VPN is replaced by a new one. But only Settings can change to some other packages, and
1383         // this is checked with CONTROL_VPN so simulate holding CONTROL_VPN in order to pass the
1384         // security checks.
1385         doReturn(PERMISSION_GRANTED).when(mContext).checkCallingOrSelfPermission(CONTROL_VPN);
1386         final Vpn vpn = createVpn(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
1387         when(mVpnProfileStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG)))
1388                 .thenReturn(mVpnProfile.encode());
1389 
1390         // Test the case that the user deactivates the vpn in vpn app.
1391         final String sessionKey1 = vpn.startVpnProfile(TEST_VPN_PKG);
1392         verifyPlatformVpnIsActivated(TEST_VPN_PKG);
1393         vpn.stopVpnProfile(TEST_VPN_PKG);
1394         verifyPlatformVpnIsDeactivated(TEST_VPN_PKG);
1395         verifyPowerSaveTempWhitelistApp(TEST_VPN_PKG);
1396         reset(mDeviceIdleInternal);
1397         verifyDeactivatedByUser(sessionKey1, new String[] {TEST_VPN_PKG});
1398         reset(mAppOps);
1399 
1400         // Test the case that the user chooses another vpn and the original one is replaced.
1401         final String sessionKey2 = vpn.startVpnProfile(TEST_VPN_PKG);
1402         verifyPlatformVpnIsActivated(TEST_VPN_PKG);
1403         vpn.prepare(TEST_VPN_PKG, "com.new.vpn" /* newPackage */, TYPE_VPN_PLATFORM);
1404         verifyPlatformVpnIsDeactivated(TEST_VPN_PKG);
1405         verifyPowerSaveTempWhitelistApp(TEST_VPN_PKG);
1406         reset(mDeviceIdleInternal);
1407         verifyDeactivatedByUser(sessionKey2, new String[] {TEST_VPN_PKG});
1408     }
1409 
1410     @Test
testVpnManagerEventForAlwaysOnChanged()1411     public void testVpnManagerEventForAlwaysOnChanged() throws Exception {
1412         // Calling setAlwaysOnPackage() needs to hold CONTROL_VPN.
1413         doReturn(PERMISSION_GRANTED).when(mContext).checkCallingOrSelfPermission(CONTROL_VPN);
1414         final Vpn vpn = createVpn(PRIMARY_USER.id);
1415         // Enable VPN always-on for PKGS[1].
1416         assertTrue(vpn.setAlwaysOnPackage(PKGS[1], false /* lockdown */,
1417                 null /* lockdownAllowlist */));
1418         verifyPowerSaveTempWhitelistApp(PKGS[1]);
1419         reset(mDeviceIdleInternal);
1420         verifyAlwaysOnStateChanged(new String[] {PKGS[1]},
1421                 new VpnProfileState(VpnProfileState.STATE_DISCONNECTED,
1422                         null /* sessionKey */, true /* alwaysOn */, false /* lockdown */));
1423 
1424         // Enable VPN lockdown for PKGS[1].
1425         assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true /* lockdown */,
1426                 null /* lockdownAllowlist */));
1427         verifyPowerSaveTempWhitelistApp(PKGS[1]);
1428         reset(mDeviceIdleInternal);
1429         verifyAlwaysOnStateChanged(new String[] {PKGS[1]},
1430                 new VpnProfileState(VpnProfileState.STATE_DISCONNECTED,
1431                         null /* sessionKey */, true /* alwaysOn */, true /* lockdown */));
1432 
1433         // Disable VPN lockdown for PKGS[1].
1434         assertTrue(vpn.setAlwaysOnPackage(PKGS[1], false /* lockdown */,
1435                 null /* lockdownAllowlist */));
1436         verifyPowerSaveTempWhitelistApp(PKGS[1]);
1437         reset(mDeviceIdleInternal);
1438         verifyAlwaysOnStateChanged(new String[] {PKGS[1]},
1439                 new VpnProfileState(VpnProfileState.STATE_DISCONNECTED,
1440                         null /* sessionKey */, true /* alwaysOn */, false /* lockdown */));
1441 
1442         // Disable VPN always-on.
1443         assertTrue(vpn.setAlwaysOnPackage(null, false /* lockdown */,
1444                 null /* lockdownAllowlist */));
1445         verifyPowerSaveTempWhitelistApp(PKGS[1]);
1446         reset(mDeviceIdleInternal);
1447         verifyAlwaysOnStateChanged(new String[] {PKGS[1]},
1448                 new VpnProfileState(VpnProfileState.STATE_DISCONNECTED,
1449                         null /* sessionKey */, false /* alwaysOn */, false /* lockdown */));
1450 
1451         // Enable VPN always-on for PKGS[1] again.
1452         assertTrue(vpn.setAlwaysOnPackage(PKGS[1], false /* lockdown */,
1453                 null /* lockdownAllowlist */));
1454         verifyPowerSaveTempWhitelistApp(PKGS[1]);
1455         reset(mDeviceIdleInternal);
1456         verifyAlwaysOnStateChanged(new String[] {PKGS[1]},
1457                 new VpnProfileState(VpnProfileState.STATE_DISCONNECTED,
1458                         null /* sessionKey */, true /* alwaysOn */, false /* lockdown */));
1459 
1460         // Enable VPN always-on for PKGS[2].
1461         assertTrue(vpn.setAlwaysOnPackage(PKGS[2], false /* lockdown */,
1462                 null /* lockdownAllowlist */));
1463         verifyPowerSaveTempWhitelistApp(PKGS[2]);
1464         reset(mDeviceIdleInternal);
1465         // PKGS[1] is replaced with PKGS[2].
1466         // Pass 2 VpnProfileState objects to verifyVpnManagerEvent(), the first one is sent to
1467         // PKGS[1] to notify PKGS[1] that the VPN always-on is disabled, the second one is sent to
1468         // PKGS[2] to notify PKGS[2] that the VPN always-on is enabled.
1469         verifyAlwaysOnStateChanged(new String[] {PKGS[1], PKGS[2]},
1470                 new VpnProfileState(VpnProfileState.STATE_DISCONNECTED,
1471                         null /* sessionKey */, false /* alwaysOn */, false /* lockdown */),
1472                 new VpnProfileState(VpnProfileState.STATE_DISCONNECTED,
1473                         null /* sessionKey */, true /* alwaysOn */, false /* lockdown */));
1474     }
1475 
1476     @Test
testReconnectVpnManagerVpnWithAlwaysOnEnabled()1477     public void testReconnectVpnManagerVpnWithAlwaysOnEnabled() throws Exception {
1478         final Vpn vpn = createVpn(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
1479         when(mVpnProfileStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG)))
1480                 .thenReturn(mVpnProfile.encode());
1481         vpn.startVpnProfile(TEST_VPN_PKG);
1482         verifyPlatformVpnIsActivated(TEST_VPN_PKG);
1483 
1484         // Enable VPN always-on for TEST_VPN_PKG.
1485         assertTrue(vpn.setAlwaysOnPackage(TEST_VPN_PKG, false /* lockdown */,
1486                 null /* lockdownAllowlist */));
1487 
1488         // Reset to verify next startVpnProfile.
1489         reset(mAppOps);
1490 
1491         vpn.stopVpnProfile(TEST_VPN_PKG);
1492 
1493         // Reconnect the vpn with different package will cause exception.
1494         assertThrows(SecurityException.class, () -> vpn.startVpnProfile(PKGS[0]));
1495 
1496         // Reconnect the vpn again with the vpn always on package w/o exception.
1497         vpn.startVpnProfile(TEST_VPN_PKG);
1498         verifyPlatformVpnIsActivated(TEST_VPN_PKG);
1499     }
1500 
1501     @Test
testLockdown_enableDisableWhileConnected()1502     public void testLockdown_enableDisableWhileConnected() throws Exception {
1503         final PlatformVpnSnapshot vpnSnapShot = verifySetupPlatformVpn(
1504                 createIkeConfig(createIkeConnectInfo(), true /* isMobikeEnabled */));
1505 
1506         final InOrder order = inOrder(mTestDeps);
1507         order.verify(mTestDeps, timeout(TIMEOUT_CROSSTHREAD_MS))
1508                 .newNetworkAgent(any(), any(), any(), any(), any(), any(),
1509                         argThat(config -> config.allowBypass), any(), any());
1510 
1511         // Make VPN lockdown.
1512         assertTrue(vpnSnapShot.vpn.setAlwaysOnPackage(TEST_VPN_PKG, true /* lockdown */,
1513                 null /* lockdownAllowlist */));
1514 
1515         order.verify(mTestDeps, timeout(TIMEOUT_CROSSTHREAD_MS))
1516                 .newNetworkAgent(any(), any(), any(), any(), any(), any(),
1517                 argThat(config -> !config.allowBypass), any(), any());
1518 
1519         // Disable lockdown.
1520         assertTrue(vpnSnapShot.vpn.setAlwaysOnPackage(TEST_VPN_PKG, false /* lockdown */,
1521                 null /* lockdownAllowlist */));
1522 
1523         order.verify(mTestDeps, timeout(TIMEOUT_CROSSTHREAD_MS))
1524                 .newNetworkAgent(any(), any(), any(), any(), any(), any(),
1525                         argThat(config -> config.allowBypass), any(), any());
1526     }
1527 
1528     @Test
testSetPackageAuthorizationVpnService()1529     public void testSetPackageAuthorizationVpnService() throws Exception {
1530         final Vpn vpn = createVpn();
1531 
1532         assertTrue(vpn.setPackageAuthorization(TEST_VPN_PKG, VpnManager.TYPE_VPN_SERVICE));
1533         verify(mAppOps)
1534                 .setMode(
1535                         eq(AppOpsManager.OPSTR_ACTIVATE_VPN),
1536                         eq(UserHandle.getUid(PRIMARY_USER.id, Process.myUid())),
1537                         eq(TEST_VPN_PKG),
1538                         eq(AppOpsManager.MODE_ALLOWED));
1539     }
1540 
1541     @Test
testSetPackageAuthorizationPlatformVpn()1542     public void testSetPackageAuthorizationPlatformVpn() throws Exception {
1543         final Vpn vpn = createVpn();
1544 
1545         assertTrue(vpn.setPackageAuthorization(TEST_VPN_PKG, TYPE_VPN_PLATFORM));
1546         verify(mAppOps)
1547                 .setMode(
1548                         eq(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN),
1549                         eq(UserHandle.getUid(PRIMARY_USER.id, Process.myUid())),
1550                         eq(TEST_VPN_PKG),
1551                         eq(AppOpsManager.MODE_ALLOWED));
1552     }
1553 
1554     @Test
testSetPackageAuthorizationRevokeAuthorization()1555     public void testSetPackageAuthorizationRevokeAuthorization() throws Exception {
1556         final Vpn vpn = createVpn();
1557 
1558         assertTrue(vpn.setPackageAuthorization(TEST_VPN_PKG, VpnManager.TYPE_VPN_NONE));
1559         verify(mAppOps)
1560                 .setMode(
1561                         eq(AppOpsManager.OPSTR_ACTIVATE_VPN),
1562                         eq(UserHandle.getUid(PRIMARY_USER.id, Process.myUid())),
1563                         eq(TEST_VPN_PKG),
1564                         eq(AppOpsManager.MODE_IGNORED));
1565         verify(mAppOps)
1566                 .setMode(
1567                         eq(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN),
1568                         eq(UserHandle.getUid(PRIMARY_USER.id, Process.myUid())),
1569                         eq(TEST_VPN_PKG),
1570                         eq(AppOpsManager.MODE_IGNORED));
1571     }
1572 
triggerOnAvailableAndGetCallback()1573     private NetworkCallback triggerOnAvailableAndGetCallback() throws Exception {
1574         return triggerOnAvailableAndGetCallback(new NetworkCapabilities.Builder().build());
1575     }
1576 
triggerOnAvailableAndGetCallback( @onNull final NetworkCapabilities caps)1577     private NetworkCallback triggerOnAvailableAndGetCallback(
1578             @NonNull final NetworkCapabilities caps) throws Exception {
1579         final ArgumentCaptor<NetworkCallback> networkCallbackCaptor =
1580                 ArgumentCaptor.forClass(NetworkCallback.class);
1581         verify(mConnectivityManager, timeout(TEST_TIMEOUT_MS))
1582                 .registerSystemDefaultNetworkCallback(networkCallbackCaptor.capture(), any());
1583 
1584         // onAvailable() will trigger onDefaultNetworkChanged(), so NetdUtils#setInterfaceUp will be
1585         // invoked. Set the return value of INetd#interfaceGetCfg to prevent NullPointerException.
1586         final InterfaceConfigurationParcel config = new InterfaceConfigurationParcel();
1587         config.flags = new String[] {IF_STATE_DOWN};
1588         when(mNetd.interfaceGetCfg(anyString())).thenReturn(config);
1589         final NetworkCallback cb = networkCallbackCaptor.getValue();
1590         cb.onAvailable(TEST_NETWORK);
1591         // Trigger onCapabilitiesChanged() and onLinkPropertiesChanged() so the test can verify that
1592         // if NetworkCapabilities and LinkProperties of underlying network will be sent/cleared or
1593         // not.
1594         // See verifyVpnManagerEvent().
1595         cb.onCapabilitiesChanged(TEST_NETWORK, caps);
1596         cb.onLinkPropertiesChanged(TEST_NETWORK, new LinkProperties());
1597         return cb;
1598     }
1599 
verifyInterfaceSetCfgWithFlags(String flag)1600     private void verifyInterfaceSetCfgWithFlags(String flag) throws Exception {
1601         // Add a timeout for waiting for interfaceSetCfg to be called.
1602         verify(mNetd, timeout(TEST_TIMEOUT_MS)).interfaceSetCfg(argThat(
1603                 config -> Arrays.asList(config.flags).contains(flag)));
1604     }
1605 
doTestPlatformVpnWithException(IkeException exception, String category, int errorType, int errorCode)1606     private void doTestPlatformVpnWithException(IkeException exception,
1607             String category, int errorType, int errorCode) throws Exception {
1608         final ArgumentCaptor<IkeSessionCallback> captor =
1609                 ArgumentCaptor.forClass(IkeSessionCallback.class);
1610 
1611         final Vpn vpn = createVpn(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
1612         when(mVpnProfileStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG)))
1613                 .thenReturn(mVpnProfile.encode());
1614 
1615         doReturn(new NetworkCapabilities()).when(mConnectivityManager)
1616                 .getRedactedNetworkCapabilitiesForPackage(any(), anyInt(), anyString());
1617         doReturn(new LinkProperties()).when(mConnectivityManager)
1618                 .getRedactedLinkPropertiesForPackage(any(), anyInt(), anyString());
1619 
1620         final String sessionKey = vpn.startVpnProfile(TEST_VPN_PKG);
1621         final NetworkCallback cb = triggerOnAvailableAndGetCallback();
1622 
1623         verifyInterfaceSetCfgWithFlags(IF_STATE_UP);
1624 
1625         // Wait for createIkeSession() to be called before proceeding in order to ensure consistent
1626         // state
1627         verify(mIkev2SessionCreator, timeout(TEST_TIMEOUT_MS))
1628                 .createIkeSession(any(), any(), any(), any(), captor.capture(), any());
1629         reset(mIkev2SessionCreator);
1630         // For network lost case, the process should be triggered by calling onLost(), which is the
1631         // same process with the real case.
1632         if (errorCode == VpnManager.ERROR_CODE_NETWORK_LOST) {
1633             cb.onLost(TEST_NETWORK);
1634             verify(mExecutor, atLeastOnce()).schedule(any(Runnable.class), anyLong(), any());
1635         } else {
1636             final IkeSessionCallback ikeCb = captor.getValue();
1637             ikeCb.onClosedWithException(exception);
1638         }
1639 
1640         verifyPowerSaveTempWhitelistApp(TEST_VPN_PKG);
1641         reset(mDeviceIdleInternal);
1642         verifyVpnManagerEvent(sessionKey, category, errorType, errorCode,
1643                 // VPN NetworkAgnet does not switch to CONNECTED in the test, and the state is not
1644                 // important here. Verify that the state as it is, i.e. CONNECTING state.
1645                 new String[] {TEST_VPN_PKG}, new VpnProfileState(VpnProfileState.STATE_CONNECTING,
1646                         sessionKey, false /* alwaysOn */, false /* lockdown */));
1647         if (errorType == VpnManager.ERROR_CLASS_NOT_RECOVERABLE) {
1648             verify(mConnectivityManager, timeout(TEST_TIMEOUT_MS))
1649                     .unregisterNetworkCallback(eq(cb));
1650         } else if (errorType == VpnManager.ERROR_CLASS_RECOVERABLE
1651                 // Vpn won't retry when there is no usable underlying network.
1652                 && errorCode != VpnManager.ERROR_CODE_NETWORK_LOST) {
1653             int retryIndex = 0;
1654             final IkeSessionCallback ikeCb2 = verifyRetryAndGetNewIkeCb(retryIndex++);
1655 
1656             ikeCb2.onClosedWithException(exception);
1657             verifyRetryAndGetNewIkeCb(retryIndex++);
1658         }
1659     }
1660 
verifyRetryAndGetNewIkeCb(int retryIndex)1661     private IkeSessionCallback verifyRetryAndGetNewIkeCb(int retryIndex) {
1662         final ArgumentCaptor<IkeSessionCallback> ikeCbCaptor =
1663                 ArgumentCaptor.forClass(IkeSessionCallback.class);
1664 
1665         // Verify retry is scheduled
1666         final long expectedDelayMs = mTestDeps.getNextRetryDelayMs(retryIndex);
1667         final ArgumentCaptor<Long> delayCaptor = ArgumentCaptor.forClass(Long.class);
1668         verify(mExecutor, atLeastOnce()).schedule(any(Runnable.class), delayCaptor.capture(),
1669                 eq(TimeUnit.MILLISECONDS));
1670         final List<Long> delays = delayCaptor.getAllValues();
1671         assertEquals(expectedDelayMs, (long) delays.get(delays.size() - 1));
1672 
1673         verify(mIkev2SessionCreator, timeout(TEST_TIMEOUT_MS + expectedDelayMs))
1674                 .createIkeSession(any(), any(), any(), any(), ikeCbCaptor.capture(), any());
1675 
1676         // Forget the mIkev2SessionCreator#createIkeSession call and mExecutor#schedule call
1677         // for the next retry verification
1678         resetIkev2SessionCreator(mIkeSessionWrapper);
1679 
1680         return ikeCbCaptor.getValue();
1681     }
1682 
1683     @Test
testStartPlatformVpnAuthenticationFailed()1684     public void testStartPlatformVpnAuthenticationFailed() throws Exception {
1685         final IkeProtocolException exception = mock(IkeProtocolException.class);
1686         final int errorCode = IkeProtocolException.ERROR_TYPE_AUTHENTICATION_FAILED;
1687         when(exception.getErrorType()).thenReturn(errorCode);
1688         doTestPlatformVpnWithException(exception,
1689                 VpnManager.CATEGORY_EVENT_IKE_ERROR, VpnManager.ERROR_CLASS_NOT_RECOVERABLE,
1690                 errorCode);
1691     }
1692 
1693     @Test
testStartPlatformVpnFailedWithRecoverableError()1694     public void testStartPlatformVpnFailedWithRecoverableError() throws Exception {
1695         final IkeProtocolException exception = mock(IkeProtocolException.class);
1696         final int errorCode = IkeProtocolException.ERROR_TYPE_TEMPORARY_FAILURE;
1697         when(exception.getErrorType()).thenReturn(errorCode);
1698         doTestPlatformVpnWithException(exception,
1699                 VpnManager.CATEGORY_EVENT_IKE_ERROR, VpnManager.ERROR_CLASS_RECOVERABLE, errorCode);
1700     }
1701 
1702     @Test
testStartPlatformVpnFailedWithUnknownHostException()1703     public void testStartPlatformVpnFailedWithUnknownHostException() throws Exception {
1704         final IkeNonProtocolException exception = mock(IkeNonProtocolException.class);
1705         final UnknownHostException unknownHostException = new UnknownHostException();
1706         final int errorCode = VpnManager.ERROR_CODE_NETWORK_UNKNOWN_HOST;
1707         when(exception.getCause()).thenReturn(unknownHostException);
1708         doTestPlatformVpnWithException(exception,
1709                 VpnManager.CATEGORY_EVENT_NETWORK_ERROR, VpnManager.ERROR_CLASS_RECOVERABLE,
1710                 errorCode);
1711     }
1712 
1713     @Test
testStartPlatformVpnFailedWithIkeTimeoutException()1714     public void testStartPlatformVpnFailedWithIkeTimeoutException() throws Exception {
1715         final IkeNonProtocolException exception = mock(IkeNonProtocolException.class);
1716         final IkeTimeoutException ikeTimeoutException =
1717                 new IkeTimeoutException("IkeTimeoutException");
1718         final int errorCode = VpnManager.ERROR_CODE_NETWORK_PROTOCOL_TIMEOUT;
1719         when(exception.getCause()).thenReturn(ikeTimeoutException);
1720         doTestPlatformVpnWithException(exception,
1721                 VpnManager.CATEGORY_EVENT_NETWORK_ERROR, VpnManager.ERROR_CLASS_RECOVERABLE,
1722                 errorCode);
1723     }
1724 
1725     @Test
testStartPlatformVpnFailedWithIkeNetworkLostException()1726     public void testStartPlatformVpnFailedWithIkeNetworkLostException() throws Exception {
1727         final IkeNetworkLostException exception = new IkeNetworkLostException(
1728                 new Network(100));
1729         doTestPlatformVpnWithException(exception,
1730                 VpnManager.CATEGORY_EVENT_NETWORK_ERROR, VpnManager.ERROR_CLASS_RECOVERABLE,
1731                 VpnManager.ERROR_CODE_NETWORK_LOST);
1732     }
1733 
1734     @Test
testStartPlatformVpnFailedWithIOException()1735     public void testStartPlatformVpnFailedWithIOException() throws Exception {
1736         final IkeNonProtocolException exception = mock(IkeNonProtocolException.class);
1737         final IOException ioException = new IOException();
1738         final int errorCode = VpnManager.ERROR_CODE_NETWORK_IO;
1739         when(exception.getCause()).thenReturn(ioException);
1740         doTestPlatformVpnWithException(exception,
1741                 VpnManager.CATEGORY_EVENT_NETWORK_ERROR, VpnManager.ERROR_CLASS_RECOVERABLE,
1742                 errorCode);
1743     }
1744 
1745     @Test
testStartPlatformVpnIllegalArgumentExceptionInSetup()1746     public void testStartPlatformVpnIllegalArgumentExceptionInSetup() throws Exception {
1747         when(mIkev2SessionCreator.createIkeSession(any(), any(), any(), any(), any(), any()))
1748                 .thenThrow(new IllegalArgumentException());
1749         final Vpn vpn = startLegacyVpn(createVpn(PRIMARY_USER.id), mVpnProfile);
1750         final NetworkCallback cb = triggerOnAvailableAndGetCallback();
1751 
1752         verifyInterfaceSetCfgWithFlags(IF_STATE_UP);
1753 
1754         // Wait for createIkeSession() to be called before proceeding in order to ensure consistent
1755         // state
1756         verify(mConnectivityManager, timeout(TEST_TIMEOUT_MS)).unregisterNetworkCallback(eq(cb));
1757         assertEquals(LegacyVpnInfo.STATE_FAILED, vpn.getLegacyVpnInfo().state);
1758     }
1759 
1760     @Test
testVpnManagerEventWillNotBeSentToSettingsVpn()1761     public void testVpnManagerEventWillNotBeSentToSettingsVpn() throws Exception {
1762         startLegacyVpn(createVpn(PRIMARY_USER.id), mVpnProfile);
1763         triggerOnAvailableAndGetCallback();
1764 
1765         verifyInterfaceSetCfgWithFlags(IF_STATE_UP);
1766 
1767         final IkeNonProtocolException exception = mock(IkeNonProtocolException.class);
1768         final IkeTimeoutException ikeTimeoutException =
1769                 new IkeTimeoutException("IkeTimeoutException");
1770         when(exception.getCause()).thenReturn(ikeTimeoutException);
1771 
1772         final ArgumentCaptor<IkeSessionCallback> captor =
1773                 ArgumentCaptor.forClass(IkeSessionCallback.class);
1774         verify(mIkev2SessionCreator, timeout(TEST_TIMEOUT_MS))
1775                 .createIkeSession(any(), any(), any(), any(), captor.capture(), any());
1776         final IkeSessionCallback ikeCb = captor.getValue();
1777         ikeCb.onClosedWithException(exception);
1778 
1779         final Context userContext =
1780                 mContext.createContextAsUser(UserHandle.of(PRIMARY_USER.id), 0 /* flags */);
1781         verify(userContext, never()).startService(any());
1782     }
1783 
setAndVerifyAlwaysOnPackage(Vpn vpn, int uid, boolean lockdownEnabled)1784     private void setAndVerifyAlwaysOnPackage(Vpn vpn, int uid, boolean lockdownEnabled) {
1785         assertTrue(vpn.setAlwaysOnPackage(TEST_VPN_PKG, lockdownEnabled, null));
1786 
1787         verify(mVpnProfileStore).get(eq(vpn.getProfileNameForPackage(TEST_VPN_PKG)));
1788         verify(mAppOps).setMode(
1789                 eq(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN), eq(uid), eq(TEST_VPN_PKG),
1790                 eq(AppOpsManager.MODE_ALLOWED));
1791 
1792         verify(mSystemServices).settingsSecurePutStringForUser(
1793                 eq(Settings.Secure.ALWAYS_ON_VPN_APP), eq(TEST_VPN_PKG), eq(PRIMARY_USER.id));
1794         verify(mSystemServices).settingsSecurePutIntForUser(
1795                 eq(Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN), eq(lockdownEnabled ? 1 : 0),
1796                 eq(PRIMARY_USER.id));
1797         verify(mSystemServices).settingsSecurePutStringForUser(
1798                 eq(Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN_WHITELIST), eq(""), eq(PRIMARY_USER.id));
1799     }
1800 
1801     @Test
testSetAndStartAlwaysOnVpn()1802     public void testSetAndStartAlwaysOnVpn() throws Exception {
1803         final Vpn vpn = createVpn(PRIMARY_USER.id);
1804         setMockedUsers(PRIMARY_USER);
1805 
1806         // UID checks must return a different UID; otherwise it'll be treated as already prepared.
1807         final int uid = Process.myUid() + 1;
1808         when(mPackageManager.getPackageUidAsUser(eq(TEST_VPN_PKG), anyInt()))
1809                 .thenReturn(uid);
1810         when(mVpnProfileStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG)))
1811                 .thenReturn(mVpnProfile.encode());
1812 
1813         setAndVerifyAlwaysOnPackage(vpn, uid, false);
1814         assertTrue(vpn.startAlwaysOnVpn());
1815 
1816         // TODO: Test the Ikev2VpnRunner started up properly. Relies on utility methods added in
1817         // a subsequent CL.
1818     }
1819 
startLegacyVpn(final Vpn vpn, final VpnProfile vpnProfile)1820     private Vpn startLegacyVpn(final Vpn vpn, final VpnProfile vpnProfile) throws Exception {
1821         setMockedUsers(PRIMARY_USER);
1822 
1823         // Dummy egress interface
1824         final LinkProperties lp = new LinkProperties();
1825         lp.setInterfaceName(EGRESS_IFACE);
1826 
1827         final RouteInfo defaultRoute = new RouteInfo(new IpPrefix(Inet4Address.ANY, 0),
1828                         InetAddresses.parseNumericAddress("192.0.2.0"), EGRESS_IFACE);
1829         lp.addRoute(defaultRoute);
1830 
1831         vpn.startLegacyVpn(vpnProfile, EGRESS_NETWORK, lp);
1832         return vpn;
1833     }
1834 
createIkeConnectInfo()1835     private IkeSessionConnectionInfo createIkeConnectInfo() {
1836         return new IkeSessionConnectionInfo(TEST_VPN_CLIENT_IP, TEST_VPN_SERVER_IP, TEST_NETWORK);
1837     }
1838 
createIkeConnectInfo_2()1839     private IkeSessionConnectionInfo createIkeConnectInfo_2() {
1840         return new IkeSessionConnectionInfo(
1841                 TEST_VPN_CLIENT_IP_2, TEST_VPN_SERVER_IP_2, TEST_NETWORK_2);
1842     }
1843 
createIkeConfig( IkeSessionConnectionInfo ikeConnectInfo, boolean isMobikeEnabled)1844     private IkeSessionConfiguration createIkeConfig(
1845             IkeSessionConnectionInfo ikeConnectInfo, boolean isMobikeEnabled) {
1846         final IkeSessionConfiguration.Builder builder =
1847                 new IkeSessionConfiguration.Builder(ikeConnectInfo);
1848 
1849         if (isMobikeEnabled) {
1850             builder.addIkeExtension(EXTENSION_TYPE_MOBIKE);
1851         }
1852 
1853         return builder.build();
1854     }
1855 
createChildConfig()1856     private ChildSessionConfiguration createChildConfig() {
1857         return new ChildSessionConfiguration.Builder(
1858                         Arrays.asList(IN_TS, IN_TS6), Arrays.asList(OUT_TS, OUT_TS6))
1859                 .addInternalAddress(new LinkAddress(TEST_VPN_INTERNAL_IP, IP4_PREFIX_LEN))
1860                 .addInternalAddress(new LinkAddress(TEST_VPN_INTERNAL_IP6, IP6_PREFIX_LEN))
1861                 .addInternalDnsServer(TEST_VPN_INTERNAL_DNS)
1862                 .addInternalDnsServer(TEST_VPN_INTERNAL_DNS6)
1863                 .build();
1864     }
1865 
createIpSecTransform()1866     private IpSecTransform createIpSecTransform() {
1867         return new IpSecTransform(mContext, new IpSecConfig());
1868     }
1869 
verifyApplyTunnelModeTransforms(int expectedTimes)1870     private void verifyApplyTunnelModeTransforms(int expectedTimes) throws Exception {
1871         verify(mIpSecService, times(expectedTimes)).applyTunnelModeTransform(
1872                 eq(TEST_TUNNEL_RESOURCE_ID), eq(IpSecManager.DIRECTION_IN),
1873                 anyInt(), anyString());
1874         verify(mIpSecService, times(expectedTimes)).applyTunnelModeTransform(
1875                 eq(TEST_TUNNEL_RESOURCE_ID), eq(IpSecManager.DIRECTION_OUT),
1876                 anyInt(), anyString());
1877     }
1878 
verifyCreateIkeAndCaptureCbs()1879     private Pair<IkeSessionCallback, ChildSessionCallback> verifyCreateIkeAndCaptureCbs()
1880             throws Exception {
1881         final ArgumentCaptor<IkeSessionCallback> ikeCbCaptor =
1882                 ArgumentCaptor.forClass(IkeSessionCallback.class);
1883         final ArgumentCaptor<ChildSessionCallback> childCbCaptor =
1884                 ArgumentCaptor.forClass(ChildSessionCallback.class);
1885 
1886         verify(mIkev2SessionCreator, timeout(TEST_TIMEOUT_MS)).createIkeSession(
1887                 any(), any(), any(), any(), ikeCbCaptor.capture(), childCbCaptor.capture());
1888 
1889         return new Pair<>(ikeCbCaptor.getValue(), childCbCaptor.getValue());
1890     }
1891 
1892     private static class PlatformVpnSnapshot {
1893         public final Vpn vpn;
1894         public final NetworkCallback nwCb;
1895         public final IkeSessionCallback ikeCb;
1896         public final ChildSessionCallback childCb;
1897 
PlatformVpnSnapshot(Vpn vpn, NetworkCallback nwCb, IkeSessionCallback ikeCb, ChildSessionCallback childCb)1898         PlatformVpnSnapshot(Vpn vpn, NetworkCallback nwCb,
1899                 IkeSessionCallback ikeCb, ChildSessionCallback childCb) {
1900             this.vpn = vpn;
1901             this.nwCb = nwCb;
1902             this.ikeCb = ikeCb;
1903             this.childCb = childCb;
1904         }
1905     }
1906 
verifySetupPlatformVpn(IkeSessionConfiguration ikeConfig)1907     private PlatformVpnSnapshot verifySetupPlatformVpn(IkeSessionConfiguration ikeConfig)
1908             throws Exception {
1909         return verifySetupPlatformVpn(ikeConfig, true);
1910     }
1911 
verifySetupPlatformVpn( IkeSessionConfiguration ikeConfig, boolean mtuSupportsIpv6)1912     private PlatformVpnSnapshot verifySetupPlatformVpn(
1913             IkeSessionConfiguration ikeConfig, boolean mtuSupportsIpv6) throws Exception {
1914         return verifySetupPlatformVpn(mVpnProfile, ikeConfig, mtuSupportsIpv6);
1915     }
1916 
verifySetupPlatformVpn(VpnProfile vpnProfile, IkeSessionConfiguration ikeConfig, boolean mtuSupportsIpv6)1917     private PlatformVpnSnapshot verifySetupPlatformVpn(VpnProfile vpnProfile,
1918             IkeSessionConfiguration ikeConfig, boolean mtuSupportsIpv6) throws Exception {
1919         return verifySetupPlatformVpn(vpnProfile, ikeConfig,
1920                 new NetworkCapabilities.Builder().build() /* underlying network caps */,
1921                 mtuSupportsIpv6, false /* areLongLivedTcpConnectionsExpensive */);
1922     }
1923 
verifySetupPlatformVpn(VpnProfile vpnProfile, IkeSessionConfiguration ikeConfig, @NonNull final NetworkCapabilities underlyingNetworkCaps, boolean mtuSupportsIpv6, boolean areLongLivedTcpConnectionsExpensive)1924     private PlatformVpnSnapshot verifySetupPlatformVpn(VpnProfile vpnProfile,
1925             IkeSessionConfiguration ikeConfig,
1926             @NonNull final NetworkCapabilities underlyingNetworkCaps,
1927             boolean mtuSupportsIpv6,
1928             boolean areLongLivedTcpConnectionsExpensive) throws Exception {
1929         if (!mtuSupportsIpv6) {
1930             doReturn(IPV6_MIN_MTU - 1).when(mTestDeps).calculateVpnMtu(any(), anyInt(), anyInt(),
1931                     anyBoolean());
1932         }
1933 
1934         doReturn(mMockNetworkAgent).when(mTestDeps)
1935                 .newNetworkAgent(
1936                         any(), any(), anyString(), any(), any(), any(), any(), any(), any());
1937         doReturn(TEST_NETWORK).when(mMockNetworkAgent).getNetwork();
1938 
1939         final Vpn vpn = createVpn(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
1940         when(mVpnProfileStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG)))
1941                 .thenReturn(vpnProfile.encode());
1942 
1943         vpn.startVpnProfile(TEST_VPN_PKG);
1944         final NetworkCallback nwCb = triggerOnAvailableAndGetCallback(underlyingNetworkCaps);
1945         verify(mExecutor, atLeastOnce()).schedule(any(Runnable.class), anyLong(), any());
1946         reset(mExecutor);
1947 
1948         // Mock the setup procedure by firing callbacks
1949         final Pair<IkeSessionCallback, ChildSessionCallback> cbPair =
1950                 verifyCreateIkeAndCaptureCbs();
1951         final IkeSessionCallback ikeCb = cbPair.first;
1952         final ChildSessionCallback childCb = cbPair.second;
1953 
1954         ikeCb.onOpened(ikeConfig);
1955         childCb.onIpSecTransformCreated(createIpSecTransform(), IpSecManager.DIRECTION_IN);
1956         childCb.onIpSecTransformCreated(createIpSecTransform(), IpSecManager.DIRECTION_OUT);
1957         childCb.onOpened(createChildConfig());
1958 
1959         // Verification VPN setup
1960         verifyApplyTunnelModeTransforms(1);
1961 
1962         ArgumentCaptor<LinkProperties> lpCaptor = ArgumentCaptor.forClass(LinkProperties.class);
1963         ArgumentCaptor<NetworkCapabilities> ncCaptor =
1964                 ArgumentCaptor.forClass(NetworkCapabilities.class);
1965         ArgumentCaptor<NetworkAgentConfig> nacCaptor =
1966                 ArgumentCaptor.forClass(NetworkAgentConfig.class);
1967         verify(mTestDeps).newNetworkAgent(
1968                 any(), any(), anyString(), ncCaptor.capture(), lpCaptor.capture(),
1969                 any(), nacCaptor.capture(), any(), any());
1970         verify(mIkeSessionWrapper).setUnderpinnedNetwork(TEST_NETWORK);
1971         // Check LinkProperties
1972         final LinkProperties lp = lpCaptor.getValue();
1973         final List<RouteInfo> expectedRoutes =
1974                 new ArrayList<>(
1975                         Arrays.asList(
1976                                 new RouteInfo(
1977                                         new IpPrefix(Inet4Address.ANY, 0),
1978                                         null /* gateway */,
1979                                         TEST_IFACE_NAME,
1980                                         RouteInfo.RTN_UNICAST)));
1981         final List<LinkAddress> expectedAddresses =
1982                 new ArrayList<>(
1983                         Arrays.asList(new LinkAddress(TEST_VPN_INTERNAL_IP, IP4_PREFIX_LEN)));
1984         final List<InetAddress> expectedDns = new ArrayList<>(Arrays.asList(TEST_VPN_INTERNAL_DNS));
1985 
1986         if (mtuSupportsIpv6) {
1987             expectedRoutes.add(
1988                     new RouteInfo(
1989                             new IpPrefix(Inet6Address.ANY, 0),
1990                             null /* gateway */,
1991                             TEST_IFACE_NAME,
1992                             RouteInfo.RTN_UNICAST));
1993             expectedAddresses.add(new LinkAddress(TEST_VPN_INTERNAL_IP6, IP6_PREFIX_LEN));
1994             expectedDns.add(TEST_VPN_INTERNAL_DNS6);
1995         } else {
1996             expectedRoutes.add(
1997                     new RouteInfo(
1998                             new IpPrefix(Inet6Address.ANY, 0),
1999                             null /* gateway */,
2000                             TEST_IFACE_NAME,
2001                             RTN_UNREACHABLE));
2002         }
2003 
2004         assertEquals(expectedRoutes, lp.getRoutes());
2005         assertEquals(expectedAddresses, lp.getLinkAddresses());
2006         assertEquals(expectedDns, lp.getDnsServers());
2007 
2008         // Check NetworkCapabilities
2009         assertEquals(Arrays.asList(TEST_NETWORK), ncCaptor.getValue().getUnderlyingNetworks());
2010 
2011         // Check if allowBypass is set or not.
2012         assertTrue(nacCaptor.getValue().isBypassableVpn());
2013         final VpnTransportInfo info = (VpnTransportInfo) ncCaptor.getValue().getTransportInfo();
2014         assertTrue(info.isBypassable());
2015         assertEquals(areLongLivedTcpConnectionsExpensive,
2016                 info.areLongLivedTcpConnectionsExpensive());
2017         return new PlatformVpnSnapshot(vpn, nwCb, ikeCb, childCb);
2018     }
2019 
2020     @Test
testStartPlatformVpn()2021     public void testStartPlatformVpn() throws Exception {
2022         final PlatformVpnSnapshot vpnSnapShot = verifySetupPlatformVpn(
2023                 createIkeConfig(createIkeConnectInfo(), true /* isMobikeEnabled */));
2024         vpnSnapShot.vpn.mVpnRunner.exitVpnRunner();
2025     }
2026 
2027     @Test
testMigrateIkeSession_FromIkeTunnConnParams_AutoTimerNoTimer()2028     public void testMigrateIkeSession_FromIkeTunnConnParams_AutoTimerNoTimer() throws Exception {
2029         doTestMigrateIkeSession_FromIkeTunnConnParams(
2030                 false /* isAutomaticIpVersionSelectionEnabled */,
2031                 true /* isAutomaticNattKeepaliveTimerEnabled */,
2032                 TEST_KEEPALIVE_TIMEOUT_UNSET /* keepaliveInProfile */,
2033                 ESP_IP_VERSION_AUTO /* ipVersionInProfile */,
2034                 ESP_ENCAP_TYPE_AUTO /* encapTypeInProfile */);
2035     }
2036 
2037     @Test
testMigrateIkeSession_FromIkeTunnConnParams_AutoTimerTimerSet()2038     public void testMigrateIkeSession_FromIkeTunnConnParams_AutoTimerTimerSet() throws Exception {
2039         doTestMigrateIkeSession_FromIkeTunnConnParams(
2040                 false /* isAutomaticIpVersionSelectionEnabled */,
2041                 true /* isAutomaticNattKeepaliveTimerEnabled */,
2042                 TEST_KEEPALIVE_TIMER /* keepaliveInProfile */,
2043                 ESP_IP_VERSION_AUTO /* ipVersionInProfile */,
2044                 ESP_ENCAP_TYPE_AUTO /* encapTypeInProfile */);
2045     }
2046 
2047     @Test
testMigrateIkeSession_FromIkeTunnConnParams_AutoIp()2048     public void testMigrateIkeSession_FromIkeTunnConnParams_AutoIp() throws Exception {
2049         doTestMigrateIkeSession_FromIkeTunnConnParams(
2050                 true /* isAutomaticIpVersionSelectionEnabled */,
2051                 false /* isAutomaticNattKeepaliveTimerEnabled */,
2052                 TEST_KEEPALIVE_TIMEOUT_UNSET /* keepaliveInProfile */,
2053                 ESP_IP_VERSION_AUTO /* ipVersionInProfile */,
2054                 ESP_ENCAP_TYPE_AUTO /* encapTypeInProfile */);
2055     }
2056 
2057     @Test
testMigrateIkeSession_FromIkeTunnConnParams_AssignedIpProtocol()2058     public void testMigrateIkeSession_FromIkeTunnConnParams_AssignedIpProtocol() throws Exception {
2059         doTestMigrateIkeSession_FromIkeTunnConnParams(
2060                 false /* isAutomaticIpVersionSelectionEnabled */,
2061                 false /* isAutomaticNattKeepaliveTimerEnabled */,
2062                 TEST_KEEPALIVE_TIMEOUT_UNSET /* keepaliveInProfile */,
2063                 ESP_IP_VERSION_IPV4 /* ipVersionInProfile */,
2064                 ESP_ENCAP_TYPE_UDP /* encapTypeInProfile */);
2065     }
2066 
2067     @Test
testMigrateIkeSession_FromNotIkeTunnConnParams_AutoTimer()2068     public void testMigrateIkeSession_FromNotIkeTunnConnParams_AutoTimer() throws Exception {
2069         doTestMigrateIkeSession_FromNotIkeTunnConnParams(
2070                 false /* isAutomaticIpVersionSelectionEnabled */,
2071                 true /* isAutomaticNattKeepaliveTimerEnabled */);
2072     }
2073 
2074     @Test
testMigrateIkeSession_FromNotIkeTunnConnParams_AutoIp()2075     public void testMigrateIkeSession_FromNotIkeTunnConnParams_AutoIp() throws Exception {
2076         doTestMigrateIkeSession_FromNotIkeTunnConnParams(
2077                 true /* isAutomaticIpVersionSelectionEnabled */,
2078                 false /* isAutomaticNattKeepaliveTimerEnabled */);
2079     }
2080 
doTestMigrateIkeSession_FromNotIkeTunnConnParams( boolean isAutomaticIpVersionSelectionEnabled, boolean isAutomaticNattKeepaliveTimerEnabled)2081     private void doTestMigrateIkeSession_FromNotIkeTunnConnParams(
2082             boolean isAutomaticIpVersionSelectionEnabled,
2083             boolean isAutomaticNattKeepaliveTimerEnabled) throws Exception {
2084         final Ikev2VpnProfile ikeProfile =
2085                 new Ikev2VpnProfile.Builder(TEST_VPN_SERVER, TEST_VPN_IDENTITY)
2086                         .setAuthPsk(TEST_VPN_PSK)
2087                         .setBypassable(true /* isBypassable */)
2088                         .setAutomaticNattKeepaliveTimerEnabled(isAutomaticNattKeepaliveTimerEnabled)
2089                         .setAutomaticIpVersionSelectionEnabled(isAutomaticIpVersionSelectionEnabled)
2090                         .build();
2091 
2092         final int expectedKeepalive = isAutomaticNattKeepaliveTimerEnabled
2093                 ? AUTOMATIC_KEEPALIVE_DELAY_SECONDS
2094                 : DEFAULT_UDP_PORT_4500_NAT_TIMEOUT_SEC_INT;
2095         doTestMigrateIkeSession(ikeProfile.toVpnProfile(),
2096                 expectedKeepalive,
2097                 ESP_IP_VERSION_AUTO /* expectedIpVersion */,
2098                 ESP_ENCAP_TYPE_AUTO /* expectedEncapType */,
2099                 new NetworkCapabilities.Builder().build());
2100     }
2101 
makeIkeV2VpnProfile( boolean isAutomaticIpVersionSelectionEnabled, boolean isAutomaticNattKeepaliveTimerEnabled, int keepaliveInProfile, int ipVersionInProfile, int encapTypeInProfile)2102     private Ikev2VpnProfile makeIkeV2VpnProfile(
2103             boolean isAutomaticIpVersionSelectionEnabled,
2104             boolean isAutomaticNattKeepaliveTimerEnabled,
2105             int keepaliveInProfile,
2106             int ipVersionInProfile,
2107             int encapTypeInProfile) {
2108         // TODO: Update helper function in IkeSessionTestUtils to support building IkeSessionParams
2109         // with IP version and encap type when mainline-prod branch support these two APIs.
2110         final IkeSessionParams params = getTestIkeSessionParams(true /* testIpv6 */,
2111                 new IkeFqdnIdentification(TEST_IDENTITY), keepaliveInProfile);
2112         final IkeSessionParams ikeSessionParams = new IkeSessionParams.Builder(params)
2113                 .setIpVersion(ipVersionInProfile)
2114                 .setEncapType(encapTypeInProfile)
2115                 .build();
2116 
2117         final IkeTunnelConnectionParams tunnelParams =
2118                 new IkeTunnelConnectionParams(ikeSessionParams, CHILD_PARAMS);
2119         return new Ikev2VpnProfile.Builder(tunnelParams)
2120                 .setBypassable(true)
2121                 .setAutomaticNattKeepaliveTimerEnabled(isAutomaticNattKeepaliveTimerEnabled)
2122                 .setAutomaticIpVersionSelectionEnabled(isAutomaticIpVersionSelectionEnabled)
2123                 .build();
2124     }
2125 
doTestMigrateIkeSession_FromIkeTunnConnParams( boolean isAutomaticIpVersionSelectionEnabled, boolean isAutomaticNattKeepaliveTimerEnabled, int keepaliveInProfile, int ipVersionInProfile, int encapTypeInProfile)2126     private void doTestMigrateIkeSession_FromIkeTunnConnParams(
2127             boolean isAutomaticIpVersionSelectionEnabled,
2128             boolean isAutomaticNattKeepaliveTimerEnabled,
2129             int keepaliveInProfile,
2130             int ipVersionInProfile,
2131             int encapTypeInProfile) throws Exception {
2132         doTestMigrateIkeSession_FromIkeTunnConnParams(isAutomaticIpVersionSelectionEnabled,
2133                 isAutomaticNattKeepaliveTimerEnabled, keepaliveInProfile, ipVersionInProfile,
2134                 encapTypeInProfile, new NetworkCapabilities.Builder().build());
2135     }
2136 
doTestMigrateIkeSession_FromIkeTunnConnParams( boolean isAutomaticIpVersionSelectionEnabled, boolean isAutomaticNattKeepaliveTimerEnabled, int keepaliveInProfile, int ipVersionInProfile, int encapTypeInProfile, @NonNull final NetworkCapabilities nc)2137     private void doTestMigrateIkeSession_FromIkeTunnConnParams(
2138             boolean isAutomaticIpVersionSelectionEnabled,
2139             boolean isAutomaticNattKeepaliveTimerEnabled,
2140             int keepaliveInProfile,
2141             int ipVersionInProfile,
2142             int encapTypeInProfile,
2143             @NonNull final NetworkCapabilities nc) throws Exception {
2144         final Ikev2VpnProfile ikeProfile = makeIkeV2VpnProfile(
2145                 isAutomaticIpVersionSelectionEnabled,
2146                 isAutomaticNattKeepaliveTimerEnabled,
2147                 keepaliveInProfile,
2148                 ipVersionInProfile,
2149                 encapTypeInProfile);
2150 
2151         final IkeSessionParams ikeSessionParams =
2152                 ikeProfile.getIkeTunnelConnectionParams().getIkeSessionParams();
2153         final int expectedKeepalive = isAutomaticNattKeepaliveTimerEnabled
2154                 ? AUTOMATIC_KEEPALIVE_DELAY_SECONDS
2155                 : ikeSessionParams.getNattKeepAliveDelaySeconds();
2156         final int expectedIpVersion = isAutomaticIpVersionSelectionEnabled
2157                 ? ESP_IP_VERSION_AUTO
2158                 : ikeSessionParams.getIpVersion();
2159         final int expectedEncapType = isAutomaticIpVersionSelectionEnabled
2160                 ? ESP_ENCAP_TYPE_AUTO
2161                 : ikeSessionParams.getEncapType();
2162         doTestMigrateIkeSession(ikeProfile.toVpnProfile(), expectedKeepalive,
2163                 expectedIpVersion, expectedEncapType, nc);
2164     }
2165 
2166     @Test
doTestMigrateIkeSession_Vcn()2167     public void doTestMigrateIkeSession_Vcn() throws Exception {
2168         final int expectedKeepalive = 2097; // Any unlikely number will do
2169         final NetworkCapabilities vcnNc = new NetworkCapabilities.Builder()
2170                 .addTransportType(TRANSPORT_CELLULAR)
2171                 .setTransportInfo(new VcnTransportInfo(TEST_SUB_ID, expectedKeepalive))
2172                 .build();
2173         final Ikev2VpnProfile ikev2VpnProfile = makeIkeV2VpnProfile(
2174                 true /* isAutomaticIpVersionSelectionEnabled */,
2175                 true /* isAutomaticNattKeepaliveTimerEnabled */,
2176                 234 /* keepaliveInProfile */, // Should be ignored, any value will do
2177                 ESP_IP_VERSION_IPV4, // Should be ignored
2178                 ESP_ENCAP_TYPE_UDP // Should be ignored
2179         );
2180         doTestMigrateIkeSession(
2181                 ikev2VpnProfile.toVpnProfile(),
2182                 expectedKeepalive,
2183                 ESP_IP_VERSION_AUTO /* expectedIpVersion */,
2184                 ESP_ENCAP_TYPE_AUTO /* expectedEncapType */,
2185                 vcnNc);
2186     }
2187 
doTestMigrateIkeSession( @onNull final VpnProfile profile, final int expectedKeepalive, final int expectedIpVersion, final int expectedEncapType, @NonNull final NetworkCapabilities caps)2188     private void doTestMigrateIkeSession(
2189             @NonNull final VpnProfile profile,
2190             final int expectedKeepalive,
2191             final int expectedIpVersion,
2192             final int expectedEncapType,
2193             @NonNull final NetworkCapabilities caps) throws Exception {
2194         final PlatformVpnSnapshot vpnSnapShot =
2195                 verifySetupPlatformVpn(profile,
2196                         createIkeConfig(createIkeConnectInfo(), true /* isMobikeEnabled */),
2197                         caps /* underlying network capabilities */,
2198                         false /* mtuSupportsIpv6 */,
2199                         expectedKeepalive < DEFAULT_LONG_LIVED_TCP_CONNS_EXPENSIVE_TIMEOUT_SEC);
2200         // Simulate a new network coming up
2201         vpnSnapShot.nwCb.onAvailable(TEST_NETWORK_2);
2202         verify(mIkeSessionWrapper, never()).setNetwork(any(), anyInt(), anyInt(), anyInt());
2203 
2204         vpnSnapShot.nwCb.onCapabilitiesChanged(TEST_NETWORK_2, caps);
2205         // Verify MOBIKE is triggered
2206         verify(mIkeSessionWrapper, timeout(TEST_TIMEOUT_MS)).setNetwork(TEST_NETWORK_2,
2207                 expectedIpVersion, expectedEncapType, expectedKeepalive);
2208 
2209         vpnSnapShot.vpn.mVpnRunner.exitVpnRunner();
2210     }
2211 
2212     @Test
testLinkPropertiesUpdateTriggerReevaluation()2213     public void testLinkPropertiesUpdateTriggerReevaluation() throws Exception {
2214         final boolean hasV6 = true;
2215 
2216         mockCarrierConfig(TEST_SUB_ID, TelephonyManager.SIM_STATE_LOADED, TEST_KEEPALIVE_TIMER,
2217                 PREFERRED_IKE_PROTOCOL_IPV6_ESP);
2218         final IkeSessionParams params = getTestIkeSessionParams(hasV6,
2219                 new IkeFqdnIdentification(TEST_IDENTITY), TEST_KEEPALIVE_TIMER);
2220         final IkeTunnelConnectionParams tunnelParams =
2221                 new IkeTunnelConnectionParams(params, CHILD_PARAMS);
2222         final Ikev2VpnProfile ikeProfile = new Ikev2VpnProfile.Builder(tunnelParams)
2223                 .setBypassable(true)
2224                 .setAutomaticNattKeepaliveTimerEnabled(false)
2225                 .setAutomaticIpVersionSelectionEnabled(true)
2226                 .build();
2227         final PlatformVpnSnapshot vpnSnapShot =
2228                 verifySetupPlatformVpn(ikeProfile.toVpnProfile(),
2229                         createIkeConfig(createIkeConnectInfo(), true /* isMobikeEnabled */),
2230                         new NetworkCapabilities.Builder().build() /* underlying network caps */,
2231                         hasV6 /* mtuSupportsIpv6 */,
2232                         false /* areLongLivedTcpConnectionsExpensive */);
2233         reset(mExecutor);
2234 
2235         // Simulate a new network coming up
2236         final LinkProperties lp = new LinkProperties();
2237         lp.addLinkAddress(new LinkAddress("192.0.2.2/32"));
2238 
2239         // Have the executor use the real delay to make sure schedule() was called only
2240         // once for all calls. Also, arrange for execute() not to call schedule() to avoid
2241         // messing with the checks for schedule().
2242         mExecutor.delayMs = TestExecutor.REAL_DELAY;
2243         mExecutor.executeDirect = true;
2244         vpnSnapShot.nwCb.onAvailable(TEST_NETWORK_2);
2245         vpnSnapShot.nwCb.onCapabilitiesChanged(
2246                 TEST_NETWORK_2, new NetworkCapabilities.Builder().build());
2247         vpnSnapShot.nwCb.onLinkPropertiesChanged(TEST_NETWORK_2, new LinkProperties(lp));
2248         verify(mExecutor).schedule(any(Runnable.class), longThat(it -> it > 0), any());
2249         reset(mExecutor);
2250 
2251         final InOrder order = inOrder(mIkeSessionWrapper);
2252 
2253         // Verify the network is started
2254         order.verify(mIkeSessionWrapper, timeout(TIMEOUT_CROSSTHREAD_MS)).setNetwork(TEST_NETWORK_2,
2255                 ESP_IP_VERSION_AUTO, ESP_ENCAP_TYPE_AUTO, TEST_KEEPALIVE_TIMER);
2256 
2257         // Send the same properties, check that no migration is scheduled
2258         vpnSnapShot.nwCb.onLinkPropertiesChanged(TEST_NETWORK_2, new LinkProperties(lp));
2259         verify(mExecutor, never()).schedule(any(Runnable.class), anyLong(), any());
2260 
2261         // Add v6 address, verify MOBIKE is triggered
2262         lp.addLinkAddress(new LinkAddress("2001:db8::1/64"));
2263         vpnSnapShot.nwCb.onLinkPropertiesChanged(TEST_NETWORK_2, new LinkProperties(lp));
2264         order.verify(mIkeSessionWrapper, timeout(TIMEOUT_CROSSTHREAD_MS)).setNetwork(TEST_NETWORK_2,
2265                 ESP_IP_VERSION_AUTO, ESP_ENCAP_TYPE_AUTO, TEST_KEEPALIVE_TIMER);
2266 
2267         // Add another v4 address, verify MOBIKE is triggered
2268         final LinkProperties stacked = new LinkProperties();
2269         stacked.setInterfaceName("v4-" + lp.getInterfaceName());
2270         stacked.addLinkAddress(new LinkAddress("192.168.0.1/32"));
2271         lp.addStackedLink(stacked);
2272         vpnSnapShot.nwCb.onLinkPropertiesChanged(TEST_NETWORK_2, new LinkProperties(lp));
2273         order.verify(mIkeSessionWrapper, timeout(TIMEOUT_CROSSTHREAD_MS)).setNetwork(TEST_NETWORK_2,
2274                 ESP_IP_VERSION_AUTO, ESP_ENCAP_TYPE_AUTO, TEST_KEEPALIVE_TIMER);
2275 
2276         vpnSnapShot.vpn.mVpnRunner.exitVpnRunner();
2277     }
2278 
mockCarrierConfig(int subId, int simStatus, int keepaliveTimer, int ikeProtocol)2279     private void mockCarrierConfig(int subId, int simStatus, int keepaliveTimer, int ikeProtocol) {
2280         final SubscriptionInfo subscriptionInfo = mock(SubscriptionInfo.class);
2281         doReturn(subId).when(subscriptionInfo).getSubscriptionId();
2282         doReturn(List.of(subscriptionInfo)).when(mSubscriptionManager)
2283                 .getActiveSubscriptionInfoList();
2284 
2285         doReturn(simStatus).when(mTmPerSub).getSimApplicationState();
2286         doReturn(TEST_MCCMNC).when(mTmPerSub).getSimOperator(subId);
2287 
2288         final PersistableBundle persistableBundle = new PersistableBundle();
2289         persistableBundle.putInt(KEY_MIN_UDP_PORT_4500_NAT_TIMEOUT_SEC_INT, keepaliveTimer);
2290         persistableBundle.putInt(KEY_PREFERRED_IKE_PROTOCOL_INT, ikeProtocol);
2291         // For CarrierConfigManager.isConfigForIdentifiedCarrier check
2292         persistableBundle.putBoolean(KEY_CARRIER_CONFIG_APPLIED_BOOL, true);
2293         doReturn(persistableBundle).when(mConfigManager).getConfigForSubId(subId);
2294     }
2295 
getCarrierConfigListener()2296     private CarrierConfigManager.CarrierConfigChangeListener getCarrierConfigListener() {
2297         final ArgumentCaptor<CarrierConfigManager.CarrierConfigChangeListener> listenerCaptor =
2298                 ArgumentCaptor.forClass(CarrierConfigManager.CarrierConfigChangeListener.class);
2299 
2300         verify(mConfigManager).registerCarrierConfigChangeListener(any(), listenerCaptor.capture());
2301 
2302         return listenerCaptor.getValue();
2303     }
2304 
2305     @Test
testNattKeepaliveTimerFromCarrierConfig_noSubId()2306     public void testNattKeepaliveTimerFromCarrierConfig_noSubId() throws Exception {
2307         doTestReadCarrierConfig(new NetworkCapabilities(),
2308                 TelephonyManager.SIM_STATE_LOADED,
2309                 PREFERRED_IKE_PROTOCOL_IPV4_UDP,
2310                 AUTOMATIC_KEEPALIVE_DELAY_SECONDS /* expectedKeepaliveTimer */,
2311                 ESP_IP_VERSION_AUTO /* expectedIpVersion */,
2312                 ESP_ENCAP_TYPE_AUTO /* expectedEncapType */,
2313                 false /* expectedReadFromCarrierConfig*/,
2314                 true /* areLongLivedTcpConnectionsExpensive */);
2315     }
2316 
2317     @Test
testNattKeepaliveTimerFromCarrierConfig_simAbsent()2318     public void testNattKeepaliveTimerFromCarrierConfig_simAbsent() throws Exception {
2319         doTestReadCarrierConfig(new NetworkCapabilities.Builder().build(),
2320                 TelephonyManager.SIM_STATE_ABSENT,
2321                 PREFERRED_IKE_PROTOCOL_IPV4_UDP,
2322                 AUTOMATIC_KEEPALIVE_DELAY_SECONDS /* expectedKeepaliveTimer */,
2323                 ESP_IP_VERSION_AUTO /* expectedIpVersion */,
2324                 ESP_ENCAP_TYPE_AUTO /* expectedEncapType */,
2325                 false /* expectedReadFromCarrierConfig*/,
2326                 true /* areLongLivedTcpConnectionsExpensive */);
2327     }
2328 
2329     @Test
testNattKeepaliveTimerFromCarrierConfig()2330     public void testNattKeepaliveTimerFromCarrierConfig() throws Exception {
2331         doTestReadCarrierConfig(createTestCellNc(),
2332                 TelephonyManager.SIM_STATE_LOADED,
2333                 PREFERRED_IKE_PROTOCOL_AUTO,
2334                 TEST_KEEPALIVE_TIMER /* expectedKeepaliveTimer */,
2335                 ESP_IP_VERSION_AUTO /* expectedIpVersion */,
2336                 ESP_ENCAP_TYPE_AUTO /* expectedEncapType */,
2337                 true /* expectedReadFromCarrierConfig*/,
2338                 false /* areLongLivedTcpConnectionsExpensive */);
2339     }
2340 
2341     @Test
testNattKeepaliveTimerFromCarrierConfig_NotCell()2342     public void testNattKeepaliveTimerFromCarrierConfig_NotCell() throws Exception {
2343         final NetworkCapabilities nc = new NetworkCapabilities.Builder()
2344                 .addTransportType(TRANSPORT_WIFI)
2345                 .setTransportInfo(new WifiInfo.Builder().build())
2346                 .build();
2347         doTestReadCarrierConfig(nc,
2348                 TelephonyManager.SIM_STATE_LOADED,
2349                 PREFERRED_IKE_PROTOCOL_IPV4_UDP,
2350                 AUTOMATIC_KEEPALIVE_DELAY_SECONDS /* expectedKeepaliveTimer */,
2351                 ESP_IP_VERSION_AUTO /* expectedIpVersion */,
2352                 ESP_ENCAP_TYPE_AUTO /* expectedEncapType */,
2353                 false /* expectedReadFromCarrierConfig*/,
2354                 true /* areLongLivedTcpConnectionsExpensive */);
2355     }
2356 
2357     @Test
testPreferredIpProtocolFromCarrierConfig_v4UDP()2358     public void testPreferredIpProtocolFromCarrierConfig_v4UDP() throws Exception {
2359         doTestReadCarrierConfig(createTestCellNc(),
2360                 TelephonyManager.SIM_STATE_LOADED,
2361                 PREFERRED_IKE_PROTOCOL_IPV4_UDP,
2362                 TEST_KEEPALIVE_TIMER /* expectedKeepaliveTimer */,
2363                 ESP_IP_VERSION_IPV4 /* expectedIpVersion */,
2364                 ESP_ENCAP_TYPE_UDP /* expectedEncapType */,
2365                 true /* expectedReadFromCarrierConfig*/,
2366                 false /* areLongLivedTcpConnectionsExpensive */);
2367     }
2368 
2369     @Test
testPreferredIpProtocolFromCarrierConfig_v6ESP()2370     public void testPreferredIpProtocolFromCarrierConfig_v6ESP() throws Exception {
2371         doTestReadCarrierConfig(createTestCellNc(),
2372                 TelephonyManager.SIM_STATE_LOADED,
2373                 PREFERRED_IKE_PROTOCOL_IPV6_ESP,
2374                 TEST_KEEPALIVE_TIMER /* expectedKeepaliveTimer */,
2375                 ESP_IP_VERSION_IPV6 /* expectedIpVersion */,
2376                 ESP_ENCAP_TYPE_NONE /* expectedEncapType */,
2377                 true /* expectedReadFromCarrierConfig*/,
2378                 false /* areLongLivedTcpConnectionsExpensive */);
2379     }
2380 
2381     @Test
testPreferredIpProtocolFromCarrierConfig_v6UDP()2382     public void testPreferredIpProtocolFromCarrierConfig_v6UDP() throws Exception {
2383         doTestReadCarrierConfig(createTestCellNc(),
2384                 TelephonyManager.SIM_STATE_LOADED,
2385                 PREFERRED_IKE_PROTOCOL_IPV6_UDP,
2386                 TEST_KEEPALIVE_TIMER /* expectedKeepaliveTimer */,
2387                 ESP_IP_VERSION_IPV6 /* expectedIpVersion */,
2388                 ESP_ENCAP_TYPE_UDP /* expectedEncapType */,
2389                 true /* expectedReadFromCarrierConfig*/,
2390                 false /* areLongLivedTcpConnectionsExpensive */);
2391     }
2392 
createTestCellNc()2393     private NetworkCapabilities createTestCellNc() {
2394         return new NetworkCapabilities.Builder()
2395                 .addTransportType(TRANSPORT_CELLULAR)
2396                 .setNetworkSpecifier(new TelephonyNetworkSpecifier.Builder()
2397                         .setSubscriptionId(TEST_SUB_ID)
2398                         .build())
2399                 .build();
2400     }
2401 
doTestReadCarrierConfig(NetworkCapabilities nc, int simState, int preferredIpProto, int expectedKeepaliveTimer, int expectedIpVersion, int expectedEncapType, boolean expectedReadFromCarrierConfig, boolean areLongLivedTcpConnectionsExpensive)2402     private void doTestReadCarrierConfig(NetworkCapabilities nc, int simState, int preferredIpProto,
2403             int expectedKeepaliveTimer, int expectedIpVersion, int expectedEncapType,
2404             boolean expectedReadFromCarrierConfig,
2405             boolean areLongLivedTcpConnectionsExpensive)
2406             throws Exception {
2407         final Ikev2VpnProfile ikeProfile =
2408                 new Ikev2VpnProfile.Builder(TEST_VPN_SERVER, TEST_VPN_IDENTITY)
2409                         .setAuthPsk(TEST_VPN_PSK)
2410                         .setBypassable(true /* isBypassable */)
2411                         .setAutomaticNattKeepaliveTimerEnabled(true)
2412                         .setAutomaticIpVersionSelectionEnabled(true)
2413                         .build();
2414 
2415         final PlatformVpnSnapshot vpnSnapShot =
2416                 verifySetupPlatformVpn(ikeProfile.toVpnProfile(),
2417                         createIkeConfig(createIkeConnectInfo(), true /* isMobikeEnabled */),
2418                         new NetworkCapabilities.Builder().build() /* underlying network caps */,
2419                         false /* mtuSupportsIpv6 */,
2420                         true /* areLongLivedTcpConnectionsExpensive */);
2421 
2422         final CarrierConfigManager.CarrierConfigChangeListener listener =
2423                 getCarrierConfigListener();
2424 
2425         // Simulate a new network coming up
2426         vpnSnapShot.nwCb.onAvailable(TEST_NETWORK_2);
2427         // Migration will not be started until receiving network capabilities change.
2428         verify(mIkeSessionWrapper, never()).setNetwork(any(), anyInt(), anyInt(), anyInt());
2429 
2430         reset(mIkeSessionWrapper);
2431         mockCarrierConfig(TEST_SUB_ID, simState, TEST_KEEPALIVE_TIMER, preferredIpProto);
2432         vpnSnapShot.nwCb.onCapabilitiesChanged(TEST_NETWORK_2, nc);
2433         verify(mIkeSessionWrapper, timeout(TEST_TIMEOUT_MS)).setNetwork(TEST_NETWORK_2,
2434                 expectedIpVersion, expectedEncapType, expectedKeepaliveTimer);
2435         if (expectedReadFromCarrierConfig) {
2436             final ArgumentCaptor<NetworkCapabilities> ncCaptor =
2437                     ArgumentCaptor.forClass(NetworkCapabilities.class);
2438             verify(mMockNetworkAgent).doSendNetworkCapabilities(ncCaptor.capture());
2439 
2440             final VpnTransportInfo info =
2441                     (VpnTransportInfo) ncCaptor.getValue().getTransportInfo();
2442             assertEquals(areLongLivedTcpConnectionsExpensive,
2443                     info.areLongLivedTcpConnectionsExpensive());
2444         } else {
2445             verify(mMockNetworkAgent, never()).doSendNetworkCapabilities(any());
2446         }
2447 
2448         reset(mExecutor);
2449         reset(mIkeSessionWrapper);
2450         reset(mMockNetworkAgent);
2451 
2452         // Trigger carrier config change
2453         listener.onCarrierConfigChanged(1 /* logicalSlotIndex */, TEST_SUB_ID,
2454                 -1 /* carrierId */, -1 /* specificCarrierId */);
2455         verify(mIkeSessionWrapper).setNetwork(TEST_NETWORK_2,
2456                 expectedIpVersion, expectedEncapType, expectedKeepaliveTimer);
2457         // Expect no NetworkCapabilities change.
2458         // Call to doSendNetworkCapabilities() will not be triggered.
2459         verify(mMockNetworkAgent, never()).doSendNetworkCapabilities(any());
2460     }
2461 
2462     @Test
testStartPlatformVpn_mtuDoesNotSupportIpv6()2463     public void testStartPlatformVpn_mtuDoesNotSupportIpv6() throws Exception {
2464         final PlatformVpnSnapshot vpnSnapShot =
2465                 verifySetupPlatformVpn(
2466                         createIkeConfig(createIkeConnectInfo(), true /* isMobikeEnabled */),
2467                         false /* mtuSupportsIpv6 */);
2468         vpnSnapShot.vpn.mVpnRunner.exitVpnRunner();
2469     }
2470 
2471     @Test
testStartPlatformVpnMobility_mobikeEnabled()2472     public void testStartPlatformVpnMobility_mobikeEnabled() throws Exception {
2473         final PlatformVpnSnapshot vpnSnapShot = verifySetupPlatformVpn(
2474                 createIkeConfig(createIkeConnectInfo(), true /* isMobikeEnabled */));
2475 
2476         // Set new MTU on a different network
2477         final int newMtu = IPV6_MIN_MTU + 1;
2478         doReturn(newMtu).when(mTestDeps).calculateVpnMtu(any(), anyInt(), anyInt(), anyBoolean());
2479 
2480         // Mock network loss and verify a cleanup task is scheduled
2481         vpnSnapShot.nwCb.onLost(TEST_NETWORK);
2482         verify(mExecutor, atLeastOnce()).schedule(any(Runnable.class), anyLong(), any());
2483 
2484         // Mock new network comes up and the cleanup task is cancelled
2485         vpnSnapShot.nwCb.onAvailable(TEST_NETWORK_2);
2486         verify(mIkeSessionWrapper, never()).setNetwork(any(), anyInt(), anyInt(), anyInt());
2487 
2488         vpnSnapShot.nwCb.onCapabilitiesChanged(TEST_NETWORK_2,
2489                 new NetworkCapabilities.Builder().build());
2490         // Verify MOBIKE is triggered
2491         verify(mIkeSessionWrapper, timeout(TEST_TIMEOUT_MS)).setNetwork(eq(TEST_NETWORK_2),
2492                 eq(ESP_IP_VERSION_AUTO) /* ipVersion */,
2493                 eq(ESP_ENCAP_TYPE_AUTO) /* encapType */,
2494                 eq(DEFAULT_UDP_PORT_4500_NAT_TIMEOUT_SEC_INT) /* keepaliveDelay */);
2495 
2496         // Mock the MOBIKE procedure
2497         vpnSnapShot.ikeCb.onIkeSessionConnectionInfoChanged(createIkeConnectInfo_2());
2498         vpnSnapShot.childCb.onIpSecTransformsMigrated(
2499                 createIpSecTransform(), createIpSecTransform());
2500 
2501         verify(mIpSecService).setNetworkForTunnelInterface(
2502                 eq(TEST_TUNNEL_RESOURCE_ID), eq(TEST_NETWORK_2), anyString());
2503 
2504         // Expect 2 times: one for initial setup and one for MOBIKE
2505         verifyApplyTunnelModeTransforms(2);
2506 
2507         // Verify mNetworkCapabilities and mNetworkAgent are updated
2508         assertEquals(
2509                 Collections.singletonList(TEST_NETWORK_2),
2510                 vpnSnapShot.vpn.mNetworkCapabilities.getUnderlyingNetworks());
2511         verify(mMockNetworkAgent)
2512                 .doSetUnderlyingNetworks(Collections.singletonList(TEST_NETWORK_2));
2513         verify(mMockNetworkAgent).doSendLinkProperties(argThat(lp -> lp.getMtu() == newMtu));
2514         verify(mMockNetworkAgent, never()).unregister();
2515 
2516         vpnSnapShot.vpn.mVpnRunner.exitVpnRunner();
2517     }
2518 
2519     @Test
testStartPlatformVpnMobility_mobikeEnabledMtuDoesNotSupportIpv6()2520     public void testStartPlatformVpnMobility_mobikeEnabledMtuDoesNotSupportIpv6() throws Exception {
2521         final PlatformVpnSnapshot vpnSnapShot =
2522                 verifySetupPlatformVpn(
2523                         createIkeConfig(createIkeConnectInfo(), true /* isMobikeEnabled */));
2524 
2525         // Set MTU below 1280
2526         final int newMtu = IPV6_MIN_MTU - 1;
2527         doReturn(newMtu).when(mTestDeps).calculateVpnMtu(any(), anyInt(), anyInt(), anyBoolean());
2528 
2529         // Mock new network available & MOBIKE procedures
2530         vpnSnapShot.nwCb.onAvailable(TEST_NETWORK_2);
2531         vpnSnapShot.ikeCb.onIkeSessionConnectionInfoChanged(createIkeConnectInfo_2());
2532         vpnSnapShot.childCb.onIpSecTransformsMigrated(
2533                 createIpSecTransform(), createIpSecTransform());
2534 
2535         // Verify removal of IPv6 addresses and routes triggers a network agent restart
2536         final ArgumentCaptor<LinkProperties> lpCaptor =
2537                 ArgumentCaptor.forClass(LinkProperties.class);
2538         verify(mTestDeps, times(2))
2539                 .newNetworkAgent(any(), any(), anyString(), any(), lpCaptor.capture(), any(), any(),
2540                         any(), any());
2541         verify(mMockNetworkAgent).unregister();
2542         // mMockNetworkAgent is an old NetworkAgent, so it won't update LinkProperties after
2543         // unregistering.
2544         verify(mMockNetworkAgent, never()).doSendLinkProperties(any());
2545 
2546         final LinkProperties lp = lpCaptor.getValue();
2547 
2548         for (LinkAddress addr : lp.getLinkAddresses()) {
2549             if (addr.isIpv6()) {
2550                 fail("IPv6 address found on VPN with MTU < IPv6 minimum MTU");
2551             }
2552         }
2553 
2554         for (InetAddress dnsAddr : lp.getDnsServers()) {
2555             if (dnsAddr instanceof Inet6Address) {
2556                 fail("IPv6 DNS server found on VPN with MTU < IPv6 minimum MTU");
2557             }
2558         }
2559 
2560         for (RouteInfo routeInfo : lp.getRoutes()) {
2561             if (routeInfo.getDestinationLinkAddress().isIpv6()
2562                     && !routeInfo.isIPv6UnreachableDefault()) {
2563                 fail("IPv6 route found on VPN with MTU < IPv6 minimum MTU");
2564             }
2565         }
2566 
2567         assertEquals(newMtu, lp.getMtu());
2568 
2569         vpnSnapShot.vpn.mVpnRunner.exitVpnRunner();
2570     }
2571 
2572     @Test
testStartPlatformVpnReestablishes_mobikeDisabled()2573     public void testStartPlatformVpnReestablishes_mobikeDisabled() throws Exception {
2574         final PlatformVpnSnapshot vpnSnapShot = verifySetupPlatformVpn(
2575                 createIkeConfig(createIkeConnectInfo(), false /* isMobikeEnabled */));
2576 
2577         // Forget the first IKE creation to be prepared to capture callbacks of the second
2578         // IKE session
2579         resetIkev2SessionCreator(mock(Vpn.IkeSessionWrapper.class));
2580 
2581         // Mock network switch
2582         vpnSnapShot.nwCb.onLost(TEST_NETWORK);
2583         vpnSnapShot.nwCb.onAvailable(TEST_NETWORK_2);
2584         // The old IKE Session will not be killed until receiving network capabilities change.
2585         verify(mIkeSessionWrapper, never()).kill();
2586 
2587         vpnSnapShot.nwCb.onCapabilitiesChanged(
2588                 TEST_NETWORK_2, new NetworkCapabilities.Builder().build());
2589         // Verify the old IKE Session is killed
2590         verify(mIkeSessionWrapper, timeout(TEST_TIMEOUT_MS)).kill();
2591 
2592         // Capture callbacks of the new IKE Session
2593         final Pair<IkeSessionCallback, ChildSessionCallback> cbPair =
2594                 verifyCreateIkeAndCaptureCbs();
2595         final IkeSessionCallback ikeCb = cbPair.first;
2596         final ChildSessionCallback childCb = cbPair.second;
2597 
2598         // Mock the IKE Session setup
2599         ikeCb.onOpened(createIkeConfig(createIkeConnectInfo_2(), false /* isMobikeEnabled */));
2600 
2601         childCb.onIpSecTransformCreated(createIpSecTransform(), IpSecManager.DIRECTION_IN);
2602         childCb.onIpSecTransformCreated(createIpSecTransform(), IpSecManager.DIRECTION_OUT);
2603         childCb.onOpened(createChildConfig());
2604 
2605         // Expect 2 times since there have been two Session setups
2606         verifyApplyTunnelModeTransforms(2);
2607 
2608         // Verify mNetworkCapabilities and mNetworkAgent are updated
2609         assertEquals(
2610                 Collections.singletonList(TEST_NETWORK_2),
2611                 vpnSnapShot.vpn.mNetworkCapabilities.getUnderlyingNetworks());
2612         verify(mMockNetworkAgent)
2613                 .doSetUnderlyingNetworks(Collections.singletonList(TEST_NETWORK_2));
2614 
2615         vpnSnapShot.vpn.mVpnRunner.exitVpnRunner();
2616     }
2617 
getDump(@onNull final Vpn vpn)2618     private String getDump(@NonNull final Vpn vpn) {
2619         final StringWriter sw = new StringWriter();
2620         final IndentingPrintWriter writer = new IndentingPrintWriter(sw, "");
2621         vpn.dump(writer);
2622         writer.flush();
2623         return sw.toString();
2624     }
2625 
countMatches(@onNull final Pattern regexp, @NonNull final String string)2626     private int countMatches(@NonNull final Pattern regexp, @NonNull final String string) {
2627         final Matcher m = regexp.matcher(string);
2628         int i = 0;
2629         while (m.find()) ++i;
2630         return i;
2631     }
2632 
2633     @Test
testNCEventChanges()2634     public void testNCEventChanges() throws Exception {
2635         final NetworkCapabilities.Builder ncBuilder = new NetworkCapabilities.Builder()
2636                 .addTransportType(TRANSPORT_CELLULAR)
2637                 .addCapability(NET_CAPABILITY_INTERNET)
2638                 .addCapability(NET_CAPABILITY_NOT_RESTRICTED)
2639                 .setLinkDownstreamBandwidthKbps(1000)
2640                 .setLinkUpstreamBandwidthKbps(500);
2641 
2642         final Ikev2VpnProfile ikeProfile =
2643                 new Ikev2VpnProfile.Builder(TEST_VPN_SERVER, TEST_VPN_IDENTITY)
2644                         .setAuthPsk(TEST_VPN_PSK)
2645                         .setBypassable(true /* isBypassable */)
2646                         .setAutomaticNattKeepaliveTimerEnabled(true)
2647                         .setAutomaticIpVersionSelectionEnabled(true)
2648                         .build();
2649 
2650         final PlatformVpnSnapshot vpnSnapShot =
2651                 verifySetupPlatformVpn(ikeProfile.toVpnProfile(),
2652                         createIkeConfig(createIkeConnectInfo(), true /* isMobikeEnabled */),
2653                         ncBuilder.build(), false /* mtuSupportsIpv6 */,
2654                         true /* areLongLivedTcpConnectionsExpensive */);
2655 
2656         // Calls to onCapabilitiesChanged will be thrown to the executor for execution ; by
2657         // default this will incur a 10ms delay before it's executed, messing with the timing
2658         // of the log and having the checks for counts in equals() below flake.
2659         mExecutor.executeDirect = true;
2660 
2661         // First nc changed triggered by verifySetupPlatformVpn
2662         final Pattern pattern = Pattern.compile("Cap changed from", Pattern.MULTILINE);
2663         final String stage1 = getDump(vpnSnapShot.vpn);
2664         assertEquals(1, countMatches(pattern, stage1));
2665 
2666         vpnSnapShot.nwCb.onCapabilitiesChanged(TEST_NETWORK, ncBuilder.build());
2667         final String stage2 = getDump(vpnSnapShot.vpn);
2668         // Was the same caps, there should still be only 1 match
2669         assertEquals(1, countMatches(pattern, stage2));
2670 
2671         ncBuilder.setLinkDownstreamBandwidthKbps(1200)
2672                 .setLinkUpstreamBandwidthKbps(300);
2673         vpnSnapShot.nwCb.onCapabilitiesChanged(TEST_NETWORK, ncBuilder.build());
2674         final String stage3 = getDump(vpnSnapShot.vpn);
2675         // Was not an important change, should not be logged, still only 1 match
2676         assertEquals(1, countMatches(pattern, stage3));
2677 
2678         ncBuilder.addCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED);
2679         vpnSnapShot.nwCb.onCapabilitiesChanged(TEST_NETWORK, ncBuilder.build());
2680         final String stage4 = getDump(vpnSnapShot.vpn);
2681         // Change to caps is important, should cause a new match
2682         assertEquals(2, countMatches(pattern, stage4));
2683 
2684         ncBuilder.removeCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED);
2685         ncBuilder.setLinkDownstreamBandwidthKbps(600);
2686         vpnSnapShot.nwCb.onCapabilitiesChanged(TEST_NETWORK, ncBuilder.build());
2687         final String stage5 = getDump(vpnSnapShot.vpn);
2688         // Change to caps is important, should cause a new match even with the unimportant change
2689         assertEquals(3, countMatches(pattern, stage5));
2690     }
2691     // TODO : beef up event logs tests
2692 
verifyHandlingNetworkLoss(PlatformVpnSnapshot vpnSnapShot)2693     private void verifyHandlingNetworkLoss(PlatformVpnSnapshot vpnSnapShot) throws Exception {
2694         // Forget the #sendLinkProperties during first setup.
2695         reset(mMockNetworkAgent);
2696 
2697         // Mock network loss
2698         vpnSnapShot.nwCb.onLost(TEST_NETWORK);
2699 
2700         // Mock the grace period expires
2701         verify(mExecutor, atLeastOnce()).schedule(any(Runnable.class), anyLong(), any());
2702 
2703         final ArgumentCaptor<LinkProperties> lpCaptor =
2704                 ArgumentCaptor.forClass(LinkProperties.class);
2705         verify(mMockNetworkAgent, timeout(TEST_TIMEOUT_MS))
2706                 .doSendLinkProperties(lpCaptor.capture());
2707         final LinkProperties lp = lpCaptor.getValue();
2708 
2709         assertNull(lp.getInterfaceName());
2710         final List<RouteInfo> expectedRoutes = Arrays.asList(
2711                 new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null /* gateway */,
2712                         null /* iface */, RTN_UNREACHABLE),
2713                 new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null /* gateway */,
2714                         null /* iface */, RTN_UNREACHABLE));
2715         assertEquals(expectedRoutes, lp.getRoutes());
2716 
2717         verify(mMockNetworkAgent).unregister();
2718     }
2719 
2720     @Test
testStartPlatformVpnHandlesNetworkLoss_mobikeEnabled()2721     public void testStartPlatformVpnHandlesNetworkLoss_mobikeEnabled() throws Exception {
2722         final PlatformVpnSnapshot vpnSnapShot = verifySetupPlatformVpn(
2723                 createIkeConfig(createIkeConnectInfo(), true /* isMobikeEnabled */));
2724         verifyHandlingNetworkLoss(vpnSnapShot);
2725     }
2726 
2727     @Test
testStartPlatformVpnHandlesNetworkLoss_mobikeDisabled()2728     public void testStartPlatformVpnHandlesNetworkLoss_mobikeDisabled() throws Exception {
2729         final PlatformVpnSnapshot vpnSnapShot = verifySetupPlatformVpn(
2730                 createIkeConfig(createIkeConnectInfo(), false /* isMobikeEnabled */));
2731         verifyHandlingNetworkLoss(vpnSnapShot);
2732     }
2733 
getConnectivityDiagCallback()2734     private ConnectivityDiagnosticsCallback getConnectivityDiagCallback() {
2735         final ArgumentCaptor<ConnectivityDiagnosticsCallback> cdcCaptor =
2736                 ArgumentCaptor.forClass(ConnectivityDiagnosticsCallback.class);
2737         verify(mCdm).registerConnectivityDiagnosticsCallback(
2738                 any(), any(), cdcCaptor.capture());
2739         return cdcCaptor.getValue();
2740     }
2741 
createDataStallReport()2742     private DataStallReport createDataStallReport() {
2743         return new DataStallReport(TEST_NETWORK, 1234 /* reportTimestamp */,
2744                 1 /* detectionMethod */, new LinkProperties(), new NetworkCapabilities(),
2745                 new PersistableBundle());
2746     }
2747 
verifyMobikeTriggered(List<Network> expected, int retryIndex)2748     private void verifyMobikeTriggered(List<Network> expected, int retryIndex) {
2749         // Verify retry is scheduled
2750         final long expectedDelaySec = mTestDeps.getValidationFailRecoverySeconds(retryIndex);
2751         final ArgumentCaptor<Long> delayCaptor = ArgumentCaptor.forClass(Long.class);
2752         verify(mExecutor, times(retryIndex + 1)).schedule(
2753                 any(Runnable.class), delayCaptor.capture(), eq(TimeUnit.SECONDS));
2754         final List<Long> delays = delayCaptor.getAllValues();
2755         assertEquals(expectedDelaySec, (long) delays.get(delays.size() - 1));
2756 
2757         final ArgumentCaptor<Network> networkCaptor = ArgumentCaptor.forClass(Network.class);
2758         // TODO: Make the timeout shorter if real timeout will be used
2759         verify(mIkeSessionWrapper, timeout(TEST_TIMEOUT_MS + expectedDelaySec * 1000))
2760                 .setNetwork(networkCaptor.capture(), anyInt() /* ipVersion */,
2761                         anyInt() /* encapType */, anyInt() /* keepaliveDelay */);
2762         assertEquals(expected, Collections.singletonList(networkCaptor.getValue()));
2763     }
2764 
2765     @Test
testDataStallInIkev2VpnMobikeDisabled()2766     public void testDataStallInIkev2VpnMobikeDisabled() throws Exception {
2767         final PlatformVpnSnapshot vpnSnapShot = verifySetupPlatformVpn(
2768                 createIkeConfig(createIkeConnectInfo(), false /* isMobikeEnabled */));
2769 
2770         doReturn(TEST_NETWORK).when(mMockNetworkAgent).getNetwork();
2771         ((Vpn.IkeV2VpnRunner) vpnSnapShot.vpn.mVpnRunner).onValidationStatus(
2772                 NetworkAgent.VALIDATION_STATUS_NOT_VALID);
2773 
2774         // Should not trigger MOBIKE if MOBIKE is not enabled
2775         verify(mIkeSessionWrapper, never()).setNetwork(any() /* network */,
2776                 anyInt() /* ipVersion */, anyInt() /* encapType */, anyInt() /* keepaliveDelay */);
2777     }
2778 
2779     @Test
testDataStallInIkev2VpnRecoveredByMobike()2780     public void testDataStallInIkev2VpnRecoveredByMobike() throws Exception {
2781         final PlatformVpnSnapshot vpnSnapShot = verifySetupPlatformVpn(
2782                 createIkeConfig(createIkeConnectInfo(), true /* isMobikeEnabled */));
2783 
2784         doReturn(TEST_NETWORK).when(mMockNetworkAgent).getNetwork();
2785         ((Vpn.IkeV2VpnRunner) vpnSnapShot.vpn.mVpnRunner).onValidationStatus(
2786                 NetworkAgent.VALIDATION_STATUS_NOT_VALID);
2787         // Verify MOBIKE is triggered
2788         verifyMobikeTriggered(vpnSnapShot.vpn.mNetworkCapabilities.getUnderlyingNetworks(),
2789                 0 /* retryIndex */);
2790 
2791         reset(mIkev2SessionCreator);
2792 
2793         // Send validation status update.
2794         // Recovered and get network validated. It should not trigger the ike session reset.
2795         ((Vpn.IkeV2VpnRunner) vpnSnapShot.vpn.mVpnRunner).onValidationStatus(
2796                 NetworkAgent.VALIDATION_STATUS_VALID);
2797         verify(mIkev2SessionCreator, never()).createIkeSession(
2798                 any(), any(), any(), any(), any(), any());
2799     }
2800 
2801     @Test
testDataStallInIkev2VpnNotRecoveredByMobike()2802     public void testDataStallInIkev2VpnNotRecoveredByMobike() throws Exception {
2803         final PlatformVpnSnapshot vpnSnapShot = verifySetupPlatformVpn(
2804                 createIkeConfig(createIkeConnectInfo(), true /* isMobikeEnabled */));
2805 
2806         int retry = 0;
2807         doReturn(TEST_NETWORK).when(mMockNetworkAgent).getNetwork();
2808         ((Vpn.IkeV2VpnRunner) vpnSnapShot.vpn.mVpnRunner).onValidationStatus(
2809                 NetworkAgent.VALIDATION_STATUS_NOT_VALID);
2810         verifyMobikeTriggered(vpnSnapShot.vpn.mNetworkCapabilities.getUnderlyingNetworks(),
2811                 retry++);
2812 
2813         reset(mIkev2SessionCreator);
2814 
2815         // Second validation status update.
2816         ((Vpn.IkeV2VpnRunner) vpnSnapShot.vpn.mVpnRunner).onValidationStatus(
2817                 NetworkAgent.VALIDATION_STATUS_NOT_VALID);
2818         verifyMobikeTriggered(vpnSnapShot.vpn.mNetworkCapabilities.getUnderlyingNetworks(),
2819                 retry++);
2820 
2821         // Use real delay to verify reset session will not be performed if there is an existing
2822         // recovery for resetting the session.
2823         mExecutor.delayMs = TestExecutor.REAL_DELAY;
2824         mExecutor.executeDirect = true;
2825         // Send validation status update should result in ike session reset.
2826         ((Vpn.IkeV2VpnRunner) vpnSnapShot.vpn.mVpnRunner).onValidationStatus(
2827                 NetworkAgent.VALIDATION_STATUS_NOT_VALID);
2828 
2829         // Verify session reset is scheduled
2830         long expectedDelay = mTestDeps.getValidationFailRecoverySeconds(retry++);
2831         final ArgumentCaptor<Long> delayCaptor = ArgumentCaptor.forClass(Long.class);
2832         verify(mExecutor, times(retry)).schedule(any(Runnable.class), delayCaptor.capture(),
2833                 eq(TimeUnit.SECONDS));
2834         final List<Long> delays = delayCaptor.getAllValues();
2835         assertEquals(expectedDelay, (long) delays.get(delays.size() - 1));
2836 
2837         // Another invalid status reported should not trigger other scheduled recovery.
2838         expectedDelay = mTestDeps.getValidationFailRecoverySeconds(retry++);
2839         ((Vpn.IkeV2VpnRunner) vpnSnapShot.vpn.mVpnRunner).onValidationStatus(
2840                 NetworkAgent.VALIDATION_STATUS_NOT_VALID);
2841         verify(mExecutor, never()).schedule(
2842                 any(Runnable.class), eq(expectedDelay), eq(TimeUnit.SECONDS));
2843 
2844         // Verify that session being reset
2845         verify(mIkev2SessionCreator, timeout(TEST_TIMEOUT_MS + expectedDelay * 1000))
2846                 .createIkeSession(any(), any(), any(), any(), any(), any());
2847     }
2848 
2849     @Test
testStartRacoonNumericAddress()2850     public void testStartRacoonNumericAddress() throws Exception {
2851         startRacoon("1.2.3.4", "1.2.3.4");
2852     }
2853 
2854     @Test
testStartRacoonHostname()2855     public void testStartRacoonHostname() throws Exception {
2856         startRacoon("hostname", "5.6.7.8"); // address returned by deps.resolve
2857     }
2858 
2859     @Test
testStartPptp()2860     public void testStartPptp() throws Exception {
2861         startPptp(true /* useMppe */);
2862     }
2863 
2864     @Test
testStartPptp_NoMppe()2865     public void testStartPptp_NoMppe() throws Exception {
2866         startPptp(false /* useMppe */);
2867     }
2868 
assertTransportInfoMatches(NetworkCapabilities nc, int type)2869     private void assertTransportInfoMatches(NetworkCapabilities nc, int type) {
2870         assertNotNull(nc);
2871         VpnTransportInfo ti = (VpnTransportInfo) nc.getTransportInfo();
2872         assertNotNull(ti);
2873         assertEquals(type, ti.getType());
2874     }
2875 
startPptp(boolean useMppe)2876     private void startPptp(boolean useMppe) throws Exception {
2877         final VpnProfile profile = new VpnProfile("testProfile" /* key */);
2878         profile.type = VpnProfile.TYPE_PPTP;
2879         profile.name = "testProfileName";
2880         profile.username = "userName";
2881         profile.password = "thePassword";
2882         profile.server = "192.0.2.123";
2883         profile.mppe = useMppe;
2884 
2885         doReturn(new Network[] { new Network(101) }).when(mConnectivityManager).getAllNetworks();
2886         doReturn(new Network(102)).when(mConnectivityManager).registerNetworkAgent(any(), any(),
2887                 any(), any(), any(), any(), anyInt());
2888 
2889         final Vpn vpn = startLegacyVpn(createVpn(PRIMARY_USER.id), profile);
2890         final TestDeps deps = (TestDeps) vpn.mDeps;
2891 
2892         testAndCleanup(() -> {
2893             final String[] mtpdArgs = deps.mtpdArgs.get(10, TimeUnit.SECONDS);
2894             final String[] argsPrefix = new String[]{
2895                     EGRESS_IFACE, "pptp", profile.server, "1723", "name", profile.username,
2896                     "password", profile.password, "linkname", "vpn", "refuse-eap", "nodefaultroute",
2897                     "usepeerdns", "idle", "1800", "mtu", "1270", "mru", "1270"
2898             };
2899             assertArrayEquals(argsPrefix, Arrays.copyOf(mtpdArgs, argsPrefix.length));
2900             if (useMppe) {
2901                 assertEquals(argsPrefix.length + 2, mtpdArgs.length);
2902                 assertEquals("+mppe", mtpdArgs[argsPrefix.length]);
2903                 assertEquals("-pap", mtpdArgs[argsPrefix.length + 1]);
2904             } else {
2905                 assertEquals(argsPrefix.length + 1, mtpdArgs.length);
2906                 assertEquals("nomppe", mtpdArgs[argsPrefix.length]);
2907             }
2908 
2909             verify(mConnectivityManager, timeout(10_000)).registerNetworkAgent(any(), any(),
2910                     any(), any(), any(), any(), anyInt());
2911         }, () -> { // Cleanup
2912                 vpn.mVpnRunner.exitVpnRunner();
2913                 deps.getStateFile().delete(); // set to delete on exit, but this deletes it earlier
2914                 vpn.mVpnRunner.join(10_000); // wait for up to 10s for the runner to die and cleanup
2915             });
2916     }
2917 
startRacoon(final String serverAddr, final String expectedAddr)2918     public void startRacoon(final String serverAddr, final String expectedAddr)
2919             throws Exception {
2920         final ConditionVariable legacyRunnerReady = new ConditionVariable();
2921         final VpnProfile profile = new VpnProfile("testProfile" /* key */);
2922         profile.type = VpnProfile.TYPE_L2TP_IPSEC_PSK;
2923         profile.name = "testProfileName";
2924         profile.username = "userName";
2925         profile.password = "thePassword";
2926         profile.server = serverAddr;
2927         profile.ipsecIdentifier = "id";
2928         profile.ipsecSecret = "secret";
2929         profile.l2tpSecret = "l2tpsecret";
2930 
2931         when(mConnectivityManager.getAllNetworks())
2932             .thenReturn(new Network[] { new Network(101) });
2933 
2934         when(mConnectivityManager.registerNetworkAgent(any(), any(), any(), any(),
2935                 any(), any(), anyInt())).thenAnswer(invocation -> {
2936                     // The runner has registered an agent and is now ready.
2937                     legacyRunnerReady.open();
2938                     return new Network(102);
2939                 });
2940         final Vpn vpn = startLegacyVpn(createVpn(PRIMARY_USER.id), profile);
2941         final TestDeps deps = (TestDeps) vpn.mDeps;
2942         try {
2943             // udppsk and 1701 are the values for TYPE_L2TP_IPSEC_PSK
2944             assertArrayEquals(
2945                     new String[] { EGRESS_IFACE, expectedAddr, "udppsk",
2946                             profile.ipsecIdentifier, profile.ipsecSecret, "1701" },
2947                     deps.racoonArgs.get(10, TimeUnit.SECONDS));
2948             // literal values are hardcoded in Vpn.java for mtpd args
2949             assertArrayEquals(
2950                     new String[] { EGRESS_IFACE, "l2tp", expectedAddr, "1701", profile.l2tpSecret,
2951                             "name", profile.username, "password", profile.password,
2952                             "linkname", "vpn", "refuse-eap", "nodefaultroute", "usepeerdns",
2953                             "idle", "1800", "mtu", "1270", "mru", "1270" },
2954                     deps.mtpdArgs.get(10, TimeUnit.SECONDS));
2955 
2956             // Now wait for the runner to be ready before testing for the route.
2957             ArgumentCaptor<LinkProperties> lpCaptor = ArgumentCaptor.forClass(LinkProperties.class);
2958             ArgumentCaptor<NetworkCapabilities> ncCaptor =
2959                     ArgumentCaptor.forClass(NetworkCapabilities.class);
2960             verify(mConnectivityManager, timeout(10_000)).registerNetworkAgent(any(), any(),
2961                     lpCaptor.capture(), ncCaptor.capture(), any(), any(), anyInt());
2962 
2963             // In this test the expected address is always v4 so /32.
2964             // Note that the interface needs to be specified because RouteInfo objects stored in
2965             // LinkProperties objects always acquire the LinkProperties' interface.
2966             final RouteInfo expectedRoute = new RouteInfo(new IpPrefix(expectedAddr + "/32"),
2967                     null, EGRESS_IFACE, RouteInfo.RTN_THROW);
2968             final List<RouteInfo> actualRoutes = lpCaptor.getValue().getRoutes();
2969             assertTrue("Expected throw route (" + expectedRoute + ") not found in " + actualRoutes,
2970                     actualRoutes.contains(expectedRoute));
2971 
2972             assertTransportInfoMatches(ncCaptor.getValue(), VpnManager.TYPE_VPN_LEGACY);
2973         } finally {
2974             // Now interrupt the thread, unblock the runner and clean up.
2975             vpn.mVpnRunner.exitVpnRunner();
2976             deps.getStateFile().delete(); // set to delete on exit, but this deletes it earlier
2977             vpn.mVpnRunner.join(10_000); // wait for up to 10s for the runner to die and cleanup
2978         }
2979     }
2980 
2981     // Make it public and un-final so as to spy it
2982     public class TestDeps extends Vpn.Dependencies {
2983         public final CompletableFuture<String[]> racoonArgs = new CompletableFuture();
2984         public final CompletableFuture<String[]> mtpdArgs = new CompletableFuture();
2985         public final File mStateFile;
2986 
2987         private final HashMap<String, Boolean> mRunningServices = new HashMap<>();
2988 
TestDeps()2989         TestDeps() {
2990             try {
2991                 mStateFile = File.createTempFile("vpnTest", ".tmp");
2992                 mStateFile.deleteOnExit();
2993             } catch (final IOException e) {
2994                 throw new RuntimeException(e);
2995             }
2996         }
2997 
2998         @Override
isCallerSystem()2999         public boolean isCallerSystem() {
3000             return true;
3001         }
3002 
3003         @Override
startService(final String serviceName)3004         public void startService(final String serviceName) {
3005             mRunningServices.put(serviceName, true);
3006         }
3007 
3008         @Override
stopService(final String serviceName)3009         public void stopService(final String serviceName) {
3010             mRunningServices.put(serviceName, false);
3011         }
3012 
3013         @Override
isServiceRunning(final String serviceName)3014         public boolean isServiceRunning(final String serviceName) {
3015             return mRunningServices.getOrDefault(serviceName, false);
3016         }
3017 
3018         @Override
isServiceStopped(final String serviceName)3019         public boolean isServiceStopped(final String serviceName) {
3020             return !isServiceRunning(serviceName);
3021         }
3022 
3023         @Override
getStateFile()3024         public File getStateFile() {
3025             return mStateFile;
3026         }
3027 
3028         @Override
getIntentForStatusPanel(Context context)3029         public PendingIntent getIntentForStatusPanel(Context context) {
3030             return null;
3031         }
3032 
3033         @Override
sendArgumentsToDaemon( final String daemon, final LocalSocket socket, final String[] arguments, final Vpn.RetryScheduler interruptChecker)3034         public void sendArgumentsToDaemon(
3035                 final String daemon, final LocalSocket socket, final String[] arguments,
3036                 final Vpn.RetryScheduler interruptChecker) throws IOException {
3037             if ("racoon".equals(daemon)) {
3038                 racoonArgs.complete(arguments);
3039             } else if ("mtpd".equals(daemon)) {
3040                 writeStateFile(arguments);
3041                 mtpdArgs.complete(arguments);
3042             } else {
3043                 throw new UnsupportedOperationException("Unsupported daemon : " + daemon);
3044             }
3045         }
3046 
writeStateFile(final String[] arguments)3047         private void writeStateFile(final String[] arguments) throws IOException {
3048             mStateFile.delete();
3049             mStateFile.createNewFile();
3050             mStateFile.deleteOnExit();
3051             final BufferedWriter writer = new BufferedWriter(
3052                     new FileWriter(mStateFile, false /* append */));
3053             writer.write(EGRESS_IFACE);
3054             writer.write("\n");
3055             // addresses
3056             writer.write("10.0.0.1/24\n");
3057             // routes
3058             writer.write("192.168.6.0/24\n");
3059             // dns servers
3060             writer.write("192.168.6.1\n");
3061             // search domains
3062             writer.write("vpn.searchdomains.com\n");
3063             // endpoint - intentionally empty
3064             writer.write("\n");
3065             writer.flush();
3066             writer.close();
3067         }
3068 
3069         @Override
3070         @NonNull
resolve(final String endpoint)3071         public InetAddress resolve(final String endpoint) {
3072             try {
3073                 // If a numeric IP address, return it.
3074                 return InetAddress.parseNumericAddress(endpoint);
3075             } catch (IllegalArgumentException e) {
3076                 // Otherwise, return some token IP to test for.
3077                 return InetAddress.parseNumericAddress("5.6.7.8");
3078             }
3079         }
3080 
3081         @Override
isInterfacePresent(final Vpn vpn, final String iface)3082         public boolean isInterfacePresent(final Vpn vpn, final String iface) {
3083             return true;
3084         }
3085 
3086         @Override
adoptFd(Vpn vpn, int mtu)3087         public ParcelFileDescriptor adoptFd(Vpn vpn, int mtu) {
3088             return new ParcelFileDescriptor(new FileDescriptor());
3089         }
3090 
3091         @Override
jniCreate(Vpn vpn, int mtu)3092         public int jniCreate(Vpn vpn, int mtu) {
3093             // Pick a random positive number as fd to return.
3094             return 345;
3095         }
3096 
3097         @Override
jniGetName(Vpn vpn, int fd)3098         public String jniGetName(Vpn vpn, int fd) {
3099             return TEST_IFACE_NAME;
3100         }
3101 
3102         @Override
jniSetAddresses(Vpn vpn, String interfaze, String addresses)3103         public int jniSetAddresses(Vpn vpn, String interfaze, String addresses) {
3104             if (addresses == null) return 0;
3105             // Return the number of addresses.
3106             return addresses.split(" ").length;
3107         }
3108 
3109         @Override
setBlocking(FileDescriptor fd, boolean blocking)3110         public void setBlocking(FileDescriptor fd, boolean blocking) {}
3111 
3112         @Override
getDeviceIdleInternal()3113         public DeviceIdleInternal getDeviceIdleInternal() {
3114             return mDeviceIdleInternal;
3115         }
3116 
3117         @Override
getNextRetryDelayMs(int retryCount)3118         public long getNextRetryDelayMs(int retryCount) {
3119             // Simply return retryCount as the delay seconds for retrying.
3120             return retryCount * 1000;
3121         }
3122 
3123         @Override
getValidationFailRecoverySeconds(int retryCount)3124         public long getValidationFailRecoverySeconds(int retryCount) {
3125             // Simply return retryCount as the delay seconds for retrying.
3126             return retryCount;
3127         }
3128 
3129         @Override
newScheduledThreadPoolExecutor()3130         public ScheduledThreadPoolExecutor newScheduledThreadPoolExecutor() {
3131             return mExecutor;
3132         }
3133 
3134         public boolean mIgnoreCallingUidChecks = true;
3135         @Override
verifyCallingUidAndPackage(Context context, String packageName, int userId)3136         public void verifyCallingUidAndPackage(Context context, String packageName, int userId) {
3137             if (!mIgnoreCallingUidChecks) {
3138                 super.verifyCallingUidAndPackage(context, packageName, userId);
3139             }
3140         }
3141     }
3142 
3143     /**
3144      * Mock some methods of vpn object.
3145      */
createVpn(@serIdInt int userId)3146     private Vpn createVpn(@UserIdInt int userId) {
3147         final Context asUserContext = mock(Context.class, AdditionalAnswers.delegatesTo(mContext));
3148         doReturn(UserHandle.of(userId)).when(asUserContext).getUser();
3149         when(mContext.createContextAsUser(eq(UserHandle.of(userId)), anyInt()))
3150                 .thenReturn(asUserContext);
3151         final TestLooper testLooper = new TestLooper();
3152         final Vpn vpn = new Vpn(testLooper.getLooper(), mContext, mTestDeps, mNetService,
3153                 mNetd, userId, mVpnProfileStore, mSystemServices, mIkev2SessionCreator);
3154         verify(mConnectivityManager, times(1)).registerNetworkProvider(argThat(
3155                 provider -> provider.getName().contains("VpnNetworkProvider")
3156         ));
3157         return vpn;
3158     }
3159 
3160     /**
3161      * Populate {@link #mUserManager} with a list of fake users.
3162      */
setMockedUsers(UserInfo... users)3163     private void setMockedUsers(UserInfo... users) {
3164         final Map<Integer, UserInfo> userMap = new ArrayMap<>();
3165         for (UserInfo user : users) {
3166             userMap.put(user.id, user);
3167         }
3168 
3169         /**
3170          * @see UserManagerService#getUsers(boolean)
3171          */
3172         doAnswer(invocation -> {
3173             final ArrayList<UserInfo> result = new ArrayList<>(users.length);
3174             for (UserInfo ui : users) {
3175                 if (ui.isEnabled() && !ui.partial) {
3176                     result.add(ui);
3177                 }
3178             }
3179             return result;
3180         }).when(mUserManager).getAliveUsers();
3181 
3182         doAnswer(invocation -> {
3183             final int id = (int) invocation.getArguments()[0];
3184             return userMap.get(id);
3185         }).when(mUserManager).getUserInfo(anyInt());
3186     }
3187 
3188     /**
3189      * Populate {@link #mPackageManager} with a fake packageName-to-UID mapping.
3190      */
setMockedPackages(final Map<String, Integer> packages)3191     private void setMockedPackages(final Map<String, Integer> packages) {
3192         try {
3193             doAnswer(invocation -> {
3194                 final String appName = (String) invocation.getArguments()[0];
3195                 final int userId = (int) invocation.getArguments()[1];
3196                 Integer appId = packages.get(appName);
3197                 if (appId == null) throw new PackageManager.NameNotFoundException(appName);
3198                 return UserHandle.getUid(userId, appId);
3199             }).when(mPackageManager).getPackageUidAsUser(anyString(), anyInt());
3200         } catch (Exception e) {
3201         }
3202     }
3203 
setMockedNetworks(final Map<Network, NetworkCapabilities> networks)3204     private void setMockedNetworks(final Map<Network, NetworkCapabilities> networks) {
3205         doAnswer(invocation -> {
3206             final Network network = (Network) invocation.getArguments()[0];
3207             return networks.get(network);
3208         }).when(mConnectivityManager).getNetworkCapabilities(any());
3209     }
3210 
3211     // Need multiple copies of this, but Java's Stream objects can't be reused or
3212     // duplicated.
publicIpV4Routes()3213     private Stream<String> publicIpV4Routes() {
3214         return Stream.of(
3215                 "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",
3216                 "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",
3217                 "172.0.0.0/12", "172.32.0.0/11", "172.64.0.0/10", "172.128.0.0/9",
3218                 "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",
3219                 "192.160.0.0/13", "192.169.0.0/16", "192.170.0.0/15", "192.172.0.0/14",
3220                 "192.176.0.0/12", "192.192.0.0/10", "193.0.0.0/8", "194.0.0.0/7",
3221                 "196.0.0.0/6", "200.0.0.0/5", "208.0.0.0/4");
3222     }
3223 
publicIpV6Routes()3224     private Stream<String> publicIpV6Routes() {
3225         return Stream.of(
3226                 "::/1", "8000::/2", "c000::/3", "e000::/4", "f000::/5", "f800::/6",
3227                 "fe00::/8", "2605:ef80:e:af1d::/64");
3228     }
3229 }
3230