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