• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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 android.net.vcn.cts;
18 
19 import static android.content.pm.PackageManager.FEATURE_TELEPHONY;
20 import static android.content.pm.PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION;
21 import static android.ipsec.ike.cts.IkeTunUtils.PortPair;
22 import static android.net.ConnectivityDiagnosticsManager.DataStallReport.DETECTION_METHOD_DNS_EVENTS;
23 import static android.net.ConnectivitySettingsManager.CAPTIVE_PORTAL_MODE_PROMPT;
24 import static android.net.ConnectivitySettingsManager.getCaptivePortalMode;
25 import static android.net.ConnectivitySettingsManager.setCaptivePortalMode;
26 import static android.net.NetworkCapabilities.NET_CAPABILITY_CBS;
27 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
28 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
29 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED;
30 import static android.net.NetworkCapabilities.NET_CAPABILITY_RCS;
31 import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
32 import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
33 import static android.net.NetworkCapabilities.TRANSPORT_TEST;
34 import static android.net.vcn.VcnGatewayConnectionConfig.VCN_GATEWAY_OPTION_ENABLE_DATA_STALL_RECOVERY_WITH_MOBILITY;
35 import static android.net.vcn.VcnManager.VCN_STATUS_CODE_ACTIVE;
36 import static android.net.vcn.VcnManager.VCN_STATUS_CODE_NOT_CONFIGURED;
37 import static android.net.vcn.VcnManager.VCN_STATUS_CODE_SAFE_MODE;
38 import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_ANY;
39 import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_FORBIDDEN;
40 import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_REQUIRED;
41 import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
42 
43 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
44 
45 import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
46 import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity;
47 import static com.android.compatibility.common.util.TestUtils.waitUntil;
48 import static com.android.internal.util.HexDump.hexStringToByteArray;
49 
50 import static org.junit.Assert.assertEquals;
51 import static org.junit.Assert.assertFalse;
52 import static org.junit.Assert.assertNotNull;
53 import static org.junit.Assert.assertNull;
54 import static org.junit.Assert.assertTrue;
55 import static org.junit.Assert.fail;
56 import static org.junit.Assume.assumeTrue;
57 
58 import android.annotation.NonNull;
59 import android.annotation.Nullable;
60 import android.content.Context;
61 import android.content.pm.PackageManager;
62 import android.ipsec.ike.cts.IkeTunUtils;
63 import android.net.ConnectivityManager;
64 import android.net.InetAddresses;
65 import android.net.LinkProperties;
66 import android.net.Network;
67 import android.net.NetworkCapabilities;
68 import android.net.NetworkRequest;
69 import android.net.vcn.VcnCellUnderlyingNetworkTemplate;
70 import android.net.vcn.VcnConfig;
71 import android.net.vcn.VcnGatewayConnectionConfig;
72 import android.net.vcn.VcnManager;
73 import android.net.vcn.VcnNetworkPolicyResult;
74 import android.net.vcn.VcnUnderlyingNetworkTemplate;
75 import android.net.vcn.VcnWifiUnderlyingNetworkTemplate;
76 import android.net.vcn.cts.TestNetworkWrapper.VcnTestNetworkCallback;
77 import android.net.vcn.cts.TestNetworkWrapper.VcnTestNetworkCallback.CapabilitiesChangedEvent;
78 import android.os.ParcelUuid;
79 import android.os.PersistableBundle;
80 import android.os.Process;
81 import android.os.SystemClock;
82 import android.os.UserManager;
83 import android.telephony.CarrierConfigManager;
84 import android.telephony.SubscriptionManager;
85 import android.telephony.TelephonyManager;
86 import android.telephony.cts.util.SubscriptionGroupUtils;
87 
88 import androidx.test.InstrumentationRegistry;
89 import androidx.test.ext.junit.runners.AndroidJUnit4;
90 
91 import com.android.compatibility.common.util.CarrierPrivilegeUtils;
92 
93 import org.junit.After;
94 import org.junit.Before;
95 import org.junit.Test;
96 import org.junit.runner.RunWith;
97 
98 import java.net.InetAddress;
99 import java.util.ArrayList;
100 import java.util.Arrays;
101 import java.util.Collections;
102 import java.util.HashSet;
103 import java.util.List;
104 import java.util.Objects;
105 import java.util.Set;
106 import java.util.UUID;
107 import java.util.concurrent.BlockingQueue;
108 import java.util.concurrent.CompletableFuture;
109 import java.util.concurrent.Executor;
110 import java.util.concurrent.LinkedBlockingQueue;
111 import java.util.concurrent.TimeUnit;
112 
113 @RunWith(AndroidJUnit4.class)
114 public class VcnManagerTest extends VcnTestBase {
115     private static final String TAG = VcnManagerTest.class.getSimpleName();
116 
117     private static final int CALLBACK_TIMEOUT_MS = 5000;
118     private static final long SAFEMODE_TIMEOUT_MILLIS = TimeUnit.SECONDS.toMillis(35);
119 
120     private static final int ACTIVE_SUB_ID_TIMEOUT_SECONDS = 60;
121 
122     private static final Executor INLINE_EXECUTOR = Runnable::run;
123 
124     private static final int TEST_NETWORK_MTU = 1500;
125 
126     private static final int VCN_STATUS_CODE_AWAIT_TIMEOUT = -1;
127 
128     private static final InetAddress LOCAL_ADDRESS =
129             InetAddresses.parseNumericAddress("198.51.100.1");
130     private static final InetAddress SECONDARY_LOCAL_ADDRESS =
131             InetAddresses.parseNumericAddress("198.51.100.2");
132 
133     private static final long IKE_DETERMINISTIC_INITIATOR_SPI =
134             Long.parseLong("46B8ECA1E0D72A18", 16);
135 
136     private final Context mContext;
137     private final VcnManager mVcnManager;
138     private final SubscriptionManager mSubscriptionManager;
139     private final TelephonyManager mTelephonyManager;
140     private final ConnectivityManager mConnectivityManager;
141     private final CarrierConfigManager mCarrierConfigManager;
142     private final int mOldCaptivePortalMode;
143 
VcnManagerTest()144     public VcnManagerTest() {
145         mContext = InstrumentationRegistry.getContext();
146         mVcnManager = mContext.getSystemService(VcnManager.class);
147         mSubscriptionManager = mContext.getSystemService(SubscriptionManager.class);
148         mTelephonyManager = mContext.getSystemService(TelephonyManager.class);
149         mConnectivityManager = mContext.getSystemService(ConnectivityManager.class);
150         mCarrierConfigManager = mContext.getSystemService(CarrierConfigManager.class);
151 
152         mOldCaptivePortalMode = getCaptivePortalMode(mContext, CAPTIVE_PORTAL_MODE_PROMPT);
153     }
154 
155     @Before
setUp()156     public void setUp() throws Exception {
157         final boolean hasFeatureTelephony =
158                 mContext.getPackageManager().hasSystemFeature(FEATURE_TELEPHONY);
159         final boolean hasFeatureTelSubscription =
160                 mContext.getPackageManager().hasSystemFeature(FEATURE_TELEPHONY_SUBSCRIPTION);
161         final boolean hasTelephonyFlag = hasFeatureTelephony || hasFeatureTelSubscription;
162 
163         // Before V, only devices with FEATURE_TELEPHONY are required to run the tests. Starting
164         // from V, tests are also required on following cases:
165         //
166         // Device that has a non-null VcnManager even if it has neither of FEATURE_TELEPHONY or
167         // FEATURE_TELEPHONY_SUBSCRIPTION.
168         //
169         // Device that has FEATURE_TELEPHONY_SUBSCRIPTION. This should not be a new requirement
170         // since before V devices with FEATURE_TELEPHONY_SUBSCRIPTION are already enforced to have
171         // FEATURE_TELEPHONY.
172         assumeTrue(hasTelephonyFlag || mVcnManager != null);
173 
174         getInstrumentation().getUiAutomation().adoptShellPermissionIdentity();
175 
176         // TODO: b/348715017 Add multi-user support for VCN
177         // Skip the test if it is not running as a main user
178         final UserManager userManager = mContext.getSystemService(UserManager.class);
179         assumeTrue(Objects.equals(userManager.getMainUser(), Process.myUserHandle()));
180 
181         // Ensure Internet probing check will be performed on VCN networks
182         setCaptivePortalMode(mContext, CAPTIVE_PORTAL_MODE_PROMPT);
183 
184         runShellCommand("cmd connectivity airplane-mode disable");
185     }
186 
187     @After
tearDown()188     public void tearDown() throws Exception {
189         setCaptivePortalMode(mContext, mOldCaptivePortalMode);
190         getInstrumentation().getUiAutomation().dropShellPermissionIdentity();
191     }
192 
buildVcnConfigBase()193     private VcnConfig.Builder buildVcnConfigBase() {
194         return buildVcnConfigBase(new ArrayList<VcnUnderlyingNetworkTemplate>());
195     }
196 
buildVcnConfigBase(List<VcnUnderlyingNetworkTemplate> nwTemplate)197     private VcnConfig.Builder buildVcnConfigBase(List<VcnUnderlyingNetworkTemplate> nwTemplate) {
198         // TODO(b/191371669): remove the exposed MMS capability and use
199         // VcnGatewayConnectionConfigTest.buildVcnGatewayConnectionConfig() instead
200         return new VcnConfig.Builder(mContext)
201                 .addGatewayConnectionConfig(
202                         VcnGatewayConnectionConfigTest.buildVcnGatewayConnectionConfigBase()
203                                 .addExposedCapability(NetworkCapabilities.NET_CAPABILITY_MMS)
204                                 .setVcnUnderlyingNetworkPriorities(nwTemplate)
205                                 .addGatewayOption(
206                                         VCN_GATEWAY_OPTION_ENABLE_DATA_STALL_RECOVERY_WITH_MOBILITY)
207                                 .build());
208     }
209 
buildVcnConfig()210     private VcnConfig buildVcnConfig() {
211         return buildVcnConfigBase().build();
212     }
213 
buildTestModeVcnConfig()214     private VcnConfig buildTestModeVcnConfig() {
215         return buildVcnConfigBase().setIsTestModeProfile().build();
216     }
217 
verifyAndGetValidDataSubId()218     private int verifyAndGetValidDataSubId() throws Exception {
219         // Wait for an active sub ID to mitigate the cuttlefish test issue where the CTS will
220         // start before a valid data subId is ready. In most cases this should return immediately
221         // without needing to wait.
222         waitUntil(
223                 "There must be an active data subscription to complete CTS",
224                 ACTIVE_SUB_ID_TIMEOUT_SECONDS,
225                 () ->
226                         SubscriptionManager.getDefaultDataSubscriptionId()
227                                 != INVALID_SUBSCRIPTION_ID);
228         return SubscriptionManager.getDefaultDataSubscriptionId();
229     }
230 
231     @Test(expected = SecurityException.class)
testSetVcnConfig_noCarrierPrivileges()232     public void testSetVcnConfig_noCarrierPrivileges() throws Exception {
233         mVcnManager.setVcnConfig(new ParcelUuid(UUID.randomUUID()), buildVcnConfig());
234     }
235 
236     @Test
testSetVcnConfig_withCarrierPrivileges()237     public void testSetVcnConfig_withCarrierPrivileges() throws Exception {
238         final int dataSubId = verifyAndGetValidDataSubId();
239         CarrierPrivilegeUtils.withCarrierPrivileges(mContext, dataSubId, () -> {
240             SubscriptionGroupUtils.withEphemeralSubscriptionGroup(mContext, dataSubId, (subGrp) -> {
241                 mVcnManager.setVcnConfig(subGrp, buildVcnConfig());
242                 mVcnManager.clearVcnConfig(subGrp);
243             });
244         });
245 
246         assertFalse(mTelephonyManager.createForSubscriptionId(dataSubId).hasCarrierPrivileges());
247     }
248 
249     @Test(expected = SecurityException.class)
testClearVcnConfig_noCarrierPrivileges()250     public void testClearVcnConfig_noCarrierPrivileges() throws Exception {
251         mVcnManager.clearVcnConfig(new ParcelUuid(UUID.randomUUID()));
252     }
253 
254     @Test
testClearVcnConfig_withCarrierPrivileges()255     public void testClearVcnConfig_withCarrierPrivileges() throws Exception {
256         final int dataSubId = verifyAndGetValidDataSubId();
257 
258         CarrierPrivilegeUtils.withCarrierPrivileges(mContext, dataSubId, () -> {
259             SubscriptionGroupUtils.withEphemeralSubscriptionGroup(mContext, dataSubId, (subGrp) -> {
260                 mVcnManager.clearVcnConfig(subGrp);
261             });
262         });
263     }
264 
265     @Test
testGetConfiguredSubscriptionGroups()266     public void testGetConfiguredSubscriptionGroups() throws Exception {
267         final int dataSubId = verifyAndGetValidDataSubId();
268         CarrierPrivilegeUtils.withCarrierPrivileges(mContext, dataSubId, () -> {
269             SubscriptionGroupUtils.withEphemeralSubscriptionGroup(mContext, dataSubId, (subGrp) -> {
270                 mVcnManager.setVcnConfig(subGrp, buildVcnConfig());
271                 assertEquals(Arrays.asList(subGrp), mVcnManager.getConfiguredSubscriptionGroups());
272 
273                 mVcnManager.clearVcnConfig(subGrp);
274             });
275         });
276     }
277 
278     /** Test implementation of VcnNetworkPolicyChangeListener for verification purposes. */
279     private static class TestVcnNetworkPolicyChangeListener
280             implements VcnManager.VcnNetworkPolicyChangeListener {
281         private final CompletableFuture<Void> mFutureOnPolicyChanged = new CompletableFuture<>();
282 
283         @Override
onPolicyChanged()284         public void onPolicyChanged() {
285             mFutureOnPolicyChanged.complete(null /* unused */);
286         }
287 
awaitOnPolicyChanged()288         public void awaitOnPolicyChanged() throws Exception {
289             mFutureOnPolicyChanged.get(CALLBACK_TIMEOUT_MS, TimeUnit.MILLISECONDS);
290         }
291     }
292 
293     @Test(expected = SecurityException.class)
testAddVcnNetworkPolicyChangeListener_noNetworkFactoryPermission()294     public void testAddVcnNetworkPolicyChangeListener_noNetworkFactoryPermission()
295             throws Exception {
296         // Drop shell permission identity to test unpermissioned behavior.
297         getInstrumentation().getUiAutomation().dropShellPermissionIdentity();
298 
299         final TestVcnNetworkPolicyChangeListener listener =
300                 new TestVcnNetworkPolicyChangeListener();
301 
302         try {
303             mVcnManager.addVcnNetworkPolicyChangeListener(INLINE_EXECUTOR, listener);
304         } finally {
305             mVcnManager.removeVcnNetworkPolicyChangeListener(listener);
306         }
307     }
308 
309     @Test
testRemoveVcnNetworkPolicyChangeListener_noNetworkFactoryPermission()310     public void testRemoveVcnNetworkPolicyChangeListener_noNetworkFactoryPermission() {
311         final TestVcnNetworkPolicyChangeListener listener =
312                 new TestVcnNetworkPolicyChangeListener();
313 
314         mVcnManager.removeVcnNetworkPolicyChangeListener(listener);
315     }
316 
317     @Test(expected = SecurityException.class)
testApplyVcnNetworkPolicy_noNetworkFactoryPermission()318     public void testApplyVcnNetworkPolicy_noNetworkFactoryPermission() throws Exception {
319         // Drop shell permission identity to test unpermissioned behavior.
320         getInstrumentation().getUiAutomation().dropShellPermissionIdentity();
321 
322         final NetworkCapabilities nc = new NetworkCapabilities.Builder().build();
323         final LinkProperties lp = new LinkProperties();
324 
325         mVcnManager.applyVcnNetworkPolicy(nc, lp);
326     }
327 
328     @Test
testApplyVcnNetworkPolicy_manageTestNetworkRequiresTransportTest()329     public void testApplyVcnNetworkPolicy_manageTestNetworkRequiresTransportTest()
330             throws Exception {
331         final NetworkCapabilities nc =
332                 new NetworkCapabilities.Builder().addTransportType(TRANSPORT_CELLULAR).build();
333         final LinkProperties lp = new LinkProperties();
334 
335         runWithShellPermissionIdentity(
336                 () -> {
337                     try {
338                         mVcnManager.applyVcnNetworkPolicy(nc, lp);
339                         fail("Expected IllegalStateException for applyVcnNetworkPolicy");
340                     } catch (IllegalStateException e) {
341                     }
342                 },
343                 android.Manifest.permission.MANAGE_TEST_NETWORKS);
344     }
345 
createTestNetworkWrapperForPolicyTest( boolean isRestricted, int subId)346     private TestNetworkWrapper createTestNetworkWrapperForPolicyTest(
347             boolean isRestricted, int subId) throws Exception {
348         final Set<Integer> capabilities = new HashSet<>();
349         capabilities.add(NET_CAPABILITY_CBS);
350         if (!isRestricted) {
351             capabilities.add(NET_CAPABILITY_NOT_RESTRICTED);
352         }
353 
354         return createTestNetworkWrapper(subId, LOCAL_ADDRESS, capabilities);
355     }
356 
buildVcnConfigWithTransportTestRestricted()357     private VcnConfig buildVcnConfigWithTransportTestRestricted() {
358         return buildVcnConfigBase()
359                 .setIsTestModeProfile()
360                 .setRestrictedUnderlyingNetworkTransports(Set.of(TRANSPORT_TEST))
361                 .build();
362     }
363 
364     @Test
testApplyVcnNetworkPolicyDuringVcnSetup_onUnrestrictedNetwork()365     public void testApplyVcnNetworkPolicyDuringVcnSetup_onUnrestrictedNetwork() throws Exception {
366         final int subId = verifyAndGetValidDataSubId();
367         final VcnConfig vcnConfig = buildVcnConfigWithTransportTestRestricted();
368 
369         try (TestNetworkWrapper networkWrapperUnrestricted =
370                 createTestNetworkWrapperForPolicyTest(false /* isRestricted */, subId)) {
371             verifyUnderlyingCellAndRunTest(
372                     subId,
373                     (subGrp, cellNetwork, cellNetworkCb) -> {
374                         cellNetworkCb.waitForAvailable();
375 
376                         // Attempt VCN setup on an unrestricted network; expect the network to
377                         // change to be restricted
378                         mVcnManager.setVcnConfig(subGrp, vcnConfig);
379 
380                         VcnNetworkPolicyResult policyResult =
381                                 networkWrapperUnrestricted.awaitVcnNetworkPolicyChange();
382 
383                         // Expect teardown due to restriction capability change
384                         assertTrue(policyResult.isTeardownRequested());
385                         assertFalse(
386                                 policyResult
387                                         .getNetworkCapabilities()
388                                         .hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
389 
390                         // Verify underlying network is lost
391                         networkWrapperUnrestricted.vcnNetworkCallback.waitForLost();
392 
393                         mVcnManager.clearVcnConfig(subGrp);
394                     });
395         }
396     }
397 
398     @Test
testApplyVcnNetworkPolicyDuringVcnSetup_onRestrictedNetwork()399     public void testApplyVcnNetworkPolicyDuringVcnSetup_onRestrictedNetwork() throws Exception {
400         final int subId = verifyAndGetValidDataSubId();
401         final VcnConfig vcnConfig = buildVcnConfigWithTransportTestRestricted();
402 
403         try (TestNetworkWrapper networkWrapperRestricted =
404                 createTestNetworkWrapperForPolicyTest(true /* isRestricted */, subId)) {
405 
406             verifyUnderlyingCellAndRunTest(
407                     subId,
408                     (subGrp, cellNetwork, cellNetworkCb) -> {
409                         // Set up VCN on a restricted network
410                         final VcnSetupResult vcnSetupResult =
411                                 setupAndGetVcnNetwork(
412                                         subGrp,
413                                         cellNetwork,
414                                         cellNetworkCb,
415                                         vcnConfig,
416                                         networkWrapperRestricted);
417 
418                         VcnNetworkPolicyResult policyResult =
419                                 networkWrapperRestricted.awaitVcnNetworkPolicyChange();
420 
421                         // Do not expect teardown since the restriction capability does not change
422                         assertFalse(policyResult.isTeardownRequested());
423                         assertFalse(
424                                 policyResult
425                                         .getNetworkCapabilities()
426                                         .hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
427 
428                         clearVcnConfigsAndVerifyNetworkTeardown(
429                                 subGrp, cellNetworkCb, vcnSetupResult.vcnNetwork);
430                     });
431         }
432     }
433 
waitForSafeMode(TestNetworkWrapper networkWrapper)434     private void waitForSafeMode(TestNetworkWrapper networkWrapper) throws Exception {
435         // Once VCN starts, the test network should lose NOT_VCN_MANAGED
436         waitForExpectedUnderlyingNetworkWithCapabilities(
437                 networkWrapper,
438                 false /* expectNotVcnManaged */,
439                 false /* expectNotMetered */,
440                 TestNetworkWrapper.NETWORK_CB_TIMEOUT_MS);
441 
442         // After VCN has started up, wait for safemode to kick in and expect the
443         // underlying Test Network to regain NOT_VCN_MANAGED.
444         waitForExpectedUnderlyingNetworkWithCapabilities(
445                 networkWrapper,
446                 true /* expectNotVcnManaged */,
447                 false /* expectNotMetered */,
448                 SAFEMODE_TIMEOUT_MILLIS);
449     }
450 
verifyApplyVcnNetworkPolicyPostVcnSetupChangeNetworkRestriction( boolean isSafeMode, boolean isRestrictedBefore, boolean expectRestrictedAfter)451     private void verifyApplyVcnNetworkPolicyPostVcnSetupChangeNetworkRestriction(
452             boolean isSafeMode, boolean isRestrictedBefore, boolean expectRestrictedAfter)
453             throws Exception {
454         final int subId = verifyAndGetValidDataSubId();
455         final VcnConfig vcnConfig = buildVcnConfigWithTransportTestRestricted();
456 
457         try (TestNetworkWrapper networkWrapperRestricted =
458                 createTestNetworkWrapperForPolicyTest(true /* isRestricted */, subId)) {
459 
460             verifyUnderlyingCellAndRunTest(
461                     subId,
462                     (subGrp, cellNetwork, cellNetworkCb) -> {
463                         // Set up VCN on a restricted network
464                         final VcnSetupResult vcnSetupResult =
465                                 setupAndGetVcnNetwork(
466                                         subGrp,
467                                         cellNetwork,
468                                         cellNetworkCb,
469                                         vcnConfig,
470                                         networkWrapperRestricted);
471 
472                         if (isSafeMode) {
473                             waitForSafeMode(networkWrapperRestricted);
474                         }
475 
476                         // Bring up another test network and verify its restriction capability
477                         // change.
478                         try (TestNetworkWrapper testNetworkWrapper =
479                                 createTestNetworkWrapperForPolicyTest(isRestrictedBefore, subId)) {
480 
481                             // The requested NetworkCapabilities should have been changed by
482                             // VcnManager before the test network was brought up. Verify it by
483                             // checking the NetworkCapabilities after the network setup.
484                             final NetworkCapabilities nc =
485                                     mConnectivityManager.getNetworkCapabilities(
486                                             testNetworkWrapper.tunNetwork);
487                             assertEquals(
488                                     !expectRestrictedAfter,
489                                     nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
490                         }
491 
492                         clearVcnConfigsAndVerifyNetworkTeardown(
493                                 subGrp, cellNetworkCb, vcnSetupResult.vcnNetwork);
494                     });
495         }
496     }
497 
498     @Test
testApplyVcnNetworkPolicy_activeMode_onRestrictedNetwork()499     public void testApplyVcnNetworkPolicy_activeMode_onRestrictedNetwork() throws Exception {
500         verifyApplyVcnNetworkPolicyPostVcnSetupChangeNetworkRestriction(
501                 false /* isSafeMode */,
502                 true /* isRestrictedBefore */,
503                 true /* expectRestrictedAfter */);
504     }
505 
506     @Test
testApplyVcnNetworkPolicy_safeMode_onRestrictedNetwork()507     public void testApplyVcnNetworkPolicy_safeMode_onRestrictedNetwork() throws Exception {
508         verifyApplyVcnNetworkPolicyPostVcnSetupChangeNetworkRestriction(
509                 true /* isSafeMode */,
510                 true /* isRestrictedBefore */,
511                 true /* expectRestrictedAfter */);
512     }
513 
514     @Test
testApplyVcnNetworkPolicy_activeMode_onUnrestrictedNetwork()515     public void testApplyVcnNetworkPolicy_activeMode_onUnrestrictedNetwork() throws Exception {
516         verifyApplyVcnNetworkPolicyPostVcnSetupChangeNetworkRestriction(
517                 false /* isSafeMode */,
518                 false /* isRestrictedBefore */,
519                 true /* expectRestrictedAfter */);
520     }
521 
522     @Test
testApplyVcnNetworkPolicy_safeMode_onUnrestrictedNetwork()523     public void testApplyVcnNetworkPolicy_safeMode_onUnrestrictedNetwork() throws Exception {
524         verifyApplyVcnNetworkPolicyPostVcnSetupChangeNetworkRestriction(
525                 true /* isSafeMode */,
526                 false /* isRestrictedBefore */,
527                 false /* expectRestrictedAfter */);
528     }
529 
530     /** Test implementation of VcnStatusCallback for verification purposes. */
531     private static class TestVcnStatusCallback extends VcnManager.VcnStatusCallback {
532         private final BlockingQueue<Integer> mOnStatusChangedHistory = new LinkedBlockingQueue<>();
533         private final BlockingQueue<GatewayConnectionError> mOnGatewayConnectionErrorHistory =
534                 new LinkedBlockingQueue<>();
535 
536         @Override
onStatusChanged(int statusCode)537         public void onStatusChanged(int statusCode) {
538             mOnStatusChangedHistory.offer(statusCode);
539         }
540 
541         @Override
onGatewayConnectionError( @onNull String gatewayConnectionName, int errorCode, @Nullable Throwable detail)542         public void onGatewayConnectionError(
543                 @NonNull String gatewayConnectionName, int errorCode, @Nullable Throwable detail) {
544             mOnGatewayConnectionErrorHistory.offer(
545                     new GatewayConnectionError(gatewayConnectionName, errorCode, detail));
546         }
547 
awaitOnStatusChanged()548         public int awaitOnStatusChanged() throws Exception {
549             final Integer status =
550                     mOnStatusChangedHistory.poll(CALLBACK_TIMEOUT_MS, TimeUnit.MILLISECONDS);
551 
552             // Null means timeout
553             return status == null ? VCN_STATUS_CODE_AWAIT_TIMEOUT : status;
554         }
555 
awaitOnGatewayConnectionError()556         public GatewayConnectionError awaitOnGatewayConnectionError() throws Exception {
557             return mOnGatewayConnectionErrorHistory.poll(
558                     CALLBACK_TIMEOUT_MS, TimeUnit.MILLISECONDS);
559         }
560     }
561 
verifyVcnStatus(ParcelUuid subGrp, int expectedStatus)562     private void verifyVcnStatus(ParcelUuid subGrp, int expectedStatus) throws Exception {
563         final TestVcnStatusCallback callback = new TestVcnStatusCallback();
564         mVcnManager.registerVcnStatusCallback(subGrp, INLINE_EXECUTOR, callback);
565 
566         assertEquals(expectedStatus, callback.awaitOnStatusChanged());
567 
568         mVcnManager.unregisterVcnStatusCallback(callback);
569     }
570 
571     /** Info class for organizing VcnStatusCallback#onGatewayConnectionError response data. */
572     private static class GatewayConnectionError {
573         @NonNull public final String gatewayConnectionName;
574         public final int errorCode;
575         @Nullable public final Throwable detail;
576 
GatewayConnectionError( @onNull String gatewayConnectionName, int errorCode, @Nullable Throwable detail)577         public GatewayConnectionError(
578                 @NonNull String gatewayConnectionName, int errorCode, @Nullable Throwable detail) {
579             this.gatewayConnectionName = gatewayConnectionName;
580             this.errorCode = errorCode;
581             this.detail = detail;
582         }
583     }
584 
registerVcnStatusCallbackForSubId( @onNull TestVcnStatusCallback callback, int subId)585     private void registerVcnStatusCallbackForSubId(
586             @NonNull TestVcnStatusCallback callback, int subId) throws Exception {
587         CarrierPrivilegeUtils.withCarrierPrivileges(mContext, subId, () -> {
588             SubscriptionGroupUtils.withEphemeralSubscriptionGroup(mContext, subId, (subGrp) -> {
589                 mVcnManager.registerVcnStatusCallback(subGrp, INLINE_EXECUTOR, callback);
590             });
591         });
592     }
593 
594     @Test
testRegisterVcnStatusCallback()595     public void testRegisterVcnStatusCallback() throws Exception {
596         final TestVcnStatusCallback callback = new TestVcnStatusCallback();
597         final int subId = verifyAndGetValidDataSubId();
598 
599         try {
600             registerVcnStatusCallbackForSubId(callback, subId);
601 
602             final int statusCode = callback.awaitOnStatusChanged();
603             assertEquals(VcnManager.VCN_STATUS_CODE_NOT_CONFIGURED, statusCode);
604         } finally {
605             mVcnManager.unregisterVcnStatusCallback(callback);
606         }
607     }
608 
609     @Test
testRegisterVcnStatusCallback_reuseUnregisteredCallback()610     public void testRegisterVcnStatusCallback_reuseUnregisteredCallback() throws Exception {
611         final TestVcnStatusCallback callback = new TestVcnStatusCallback();
612         final int subId = verifyAndGetValidDataSubId();
613 
614         try {
615             registerVcnStatusCallbackForSubId(callback, subId);
616             mVcnManager.unregisterVcnStatusCallback(callback);
617             registerVcnStatusCallbackForSubId(callback, subId);
618         } finally {
619             mVcnManager.unregisterVcnStatusCallback(callback);
620         }
621     }
622 
623     @Test(expected = IllegalStateException.class)
testRegisterVcnStatusCallback_duplicateRegister()624     public void testRegisterVcnStatusCallback_duplicateRegister() throws Exception {
625         final TestVcnStatusCallback callback = new TestVcnStatusCallback();
626         final int subId = verifyAndGetValidDataSubId();
627 
628         try {
629             registerVcnStatusCallbackForSubId(callback, subId);
630             registerVcnStatusCallbackForSubId(callback, subId);
631         } finally {
632             mVcnManager.unregisterVcnStatusCallback(callback);
633         }
634     }
635 
636     @Test
testUnregisterVcnStatusCallback()637     public void testUnregisterVcnStatusCallback() throws Exception {
638         final TestVcnStatusCallback callback = new TestVcnStatusCallback();
639 
640         mVcnManager.unregisterVcnStatusCallback(callback);
641     }
642 
createTestNetworkWrapper( int subId, InetAddress localAddress, Set<Integer> capabilities)643     private TestNetworkWrapper createTestNetworkWrapper(
644             int subId, InetAddress localAddress, Set<Integer> capabilities) throws Exception {
645         TestNetworkWrapper testNetworkWrapper =
646                 new TestNetworkWrapper(
647                         mContext,
648                         TEST_NETWORK_MTU,
649                         capabilities,
650                         Collections.singleton(subId),
651                         localAddress);
652         assertNotNull("No test network found", testNetworkWrapper.tunNetwork);
653         return testNetworkWrapper;
654     }
655 
createTestNetworkWrapper( boolean isMetered, int subId, InetAddress localAddress)656     private TestNetworkWrapper createTestNetworkWrapper(
657             boolean isMetered, int subId, InetAddress localAddress) throws Exception {
658         final Set<Integer> capabilities = new HashSet<>();
659         capabilities.add(NET_CAPABILITY_CBS);
660         if (!isMetered) {
661             capabilities.add(NET_CAPABILITY_NOT_METERED);
662         }
663 
664         return createTestNetworkWrapper(subId, localAddress, capabilities);
665     }
666 
667     @Test
testVcnManagedNetworkLosesNotVcnManagedCapability()668     public void testVcnManagedNetworkLosesNotVcnManagedCapability() throws Exception {
669         final int subId = verifyAndGetValidDataSubId();
670         try (TestNetworkWrapper testNetworkWrapper =
671                 createTestNetworkWrapper(true /* isMetered */, subId, LOCAL_ADDRESS)) {
672             // Before the VCN starts, the test network should have NOT_VCN_MANAGED
673             waitForExpectedUnderlyingNetworkWithCapabilities(
674                     testNetworkWrapper,
675                     true /* expectNotVcnManaged */,
676                     false /* expectNotMetered */,
677                     TestNetworkWrapper.NETWORK_CB_TIMEOUT_MS);
678 
679             CarrierPrivilegeUtils.withCarrierPrivilegesForShell(mContext, subId, () -> {
680                 SubscriptionGroupUtils.withEphemeralSubscriptionGroup(mContext, subId, (subGrp) -> {
681                     mVcnManager.setVcnConfig(subGrp, buildVcnConfig());
682 
683                     // Once VCN starts, the test network should lose NOT_VCN_MANAGED
684                     waitForExpectedUnderlyingNetworkWithCapabilities(
685                             testNetworkWrapper,
686                             false /* expectNotVcnManaged */,
687                             false /* expectNotMetered */,
688                             TestNetworkWrapper.NETWORK_CB_TIMEOUT_MS);
689 
690                     mVcnManager.clearVcnConfig(subGrp);
691 
692                     // After the VCN tears down, the test network should have
693                     // NOT_VCN_MANAGED again
694                     waitForExpectedUnderlyingNetworkWithCapabilities(
695                             testNetworkWrapper,
696                             true /* expectNotVcnManaged */,
697                             false /* expectNotMetered */,
698                             TestNetworkWrapper.NETWORK_CB_TIMEOUT_MS);
699                 });
700             });
701         }
702     }
703 
waitForExpectedUnderlyingNetworkWithCapabilities( TestNetworkWrapper testNetworkWrapper, boolean expectNotVcnManaged, boolean expectNotMetered, long timeoutMillis)704     private void waitForExpectedUnderlyingNetworkWithCapabilities(
705             TestNetworkWrapper testNetworkWrapper,
706             boolean expectNotVcnManaged,
707             boolean expectNotMetered,
708             long timeoutMillis)
709             throws Exception {
710         final long start = SystemClock.elapsedRealtime();
711 
712         // Wait for NetworkCapabilities changes until they match the expected capabilities
713         do {
714             final CapabilitiesChangedEvent capabilitiesChangedEvent =
715                     testNetworkWrapper.vcnNetworkCallback.waitForOnCapabilitiesChanged(
716                             timeoutMillis);
717             assertNotNull("Failed to receive NetworkCapabilities change", capabilitiesChangedEvent);
718 
719             final NetworkCapabilities nc = capabilitiesChangedEvent.networkCapabilities;
720             if (testNetworkWrapper.tunNetwork.equals(capabilitiesChangedEvent.network)
721                     && nc.hasCapability(NET_CAPABILITY_VALIDATED)
722                     && expectNotVcnManaged == nc.hasCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
723                     && expectNotMetered == nc.hasCapability(NET_CAPABILITY_NOT_METERED)) {
724                 return;
725             }
726         } while (SystemClock.elapsedRealtime() - start < timeoutMillis);
727 
728         fail(
729                 "Expected update for network="
730                         + testNetworkWrapper.tunNetwork.getNetId()
731                         + ". Wanted NOT_VCN_MANAGED="
732                         + expectNotVcnManaged
733                         + " NOT_METERED="
734                         + expectNotMetered);
735     }
736 
737     private interface VcnTestRunnable {
runTest(ParcelUuid subGrp, Network cellNetwork, VcnTestNetworkCallback cellNetworkCb)738         void runTest(ParcelUuid subGrp, Network cellNetwork, VcnTestNetworkCallback cellNetworkCb)
739                 throws Exception;
740     }
741 
verifyUnderlyingCellAndRunTest(int subId, VcnTestRunnable test)742     private void verifyUnderlyingCellAndRunTest(int subId, VcnTestRunnable test) throws Exception {
743         // Get current cell Network then wait for it to drop (due to losing NOT_VCN_MANAGED)
744         // before waiting for VCN Network.
745         final NetworkRequest cellNetworkReq =
746                 new NetworkRequest.Builder()
747                         .addTransportType(TRANSPORT_CELLULAR)
748                         .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
749                         .build();
750         final VcnTestNetworkCallback cellNetworkCb = new VcnTestNetworkCallback();
751         mConnectivityManager.requestNetwork(cellNetworkReq, cellNetworkCb);
752         final Network cellNetwork = cellNetworkCb.waitForAvailable();
753         assertNotNull("No cell network found", cellNetwork);
754 
755         CarrierPrivilegeUtils.withCarrierPrivilegesForShell(mContext, subId, () -> {
756             SubscriptionGroupUtils.withEphemeralSubscriptionGroup(
757                 mContext,
758                 subId,
759                 (subGrp) -> {
760                     test.runTest(subGrp, cellNetwork, cellNetworkCb);
761                 }
762             );
763         });
764         mConnectivityManager.unregisterNetworkCallback(cellNetworkCb);
765     }
766 
767     @Test
testSetVcnConfigOnTestNetwork()768     public void testSetVcnConfigOnTestNetwork() throws Exception {
769         final int subId = verifyAndGetValidDataSubId();
770 
771         try (TestNetworkWrapper testNetworkWrapper =
772                 createTestNetworkWrapper(true /* isMetered */, subId, LOCAL_ADDRESS)) {
773             verifyUnderlyingCellAndRunTest(subId, (subGrp, cellNetwork, cellNetworkCb) -> {
774                 final VcnSetupResult vcnSetupResult =
775                     setupAndGetVcnNetwork(subGrp, cellNetwork, cellNetworkCb, testNetworkWrapper);
776 
777                 clearVcnConfigsAndVerifyNetworkTeardown(
778                         subGrp, cellNetworkCb, vcnSetupResult.vcnNetwork);
779             });
780         }
781     }
782 
783     @Test
testSetVcnConfigOnTestNetworkAndDumpsys()784     public void testSetVcnConfigOnTestNetworkAndDumpsys() throws Exception {
785         final int subId = verifyAndGetValidDataSubId();
786 
787         try (TestNetworkWrapper testNetworkWrapper =
788                 createTestNetworkWrapper(true /* isMetered */, subId, LOCAL_ADDRESS)) {
789             verifyUnderlyingCellAndRunTest(subId, (subGrp, cellNetwork, cellNetworkCb) -> {
790                 final VcnSetupResult vcnSetupResult =
791                     setupAndGetVcnNetwork(subGrp, cellNetwork, cellNetworkCb, testNetworkWrapper);
792 
793                 runShellCommand("dumpsys vcn_management");
794 
795                 clearVcnConfigsAndVerifyNetworkTeardown(
796                         subGrp, cellNetworkCb, vcnSetupResult.vcnNetwork);
797             });
798         }
799     }
800 
801     @Test
testSetVcnConfigOnTestNetworkAndHandleDataStall()802     public void testSetVcnConfigOnTestNetworkAndHandleDataStall() throws Exception {
803         final int subId = verifyAndGetValidDataSubId();
804 
805         try (TestNetworkWrapper testNetworkWrapper =
806                 createTestNetworkWrapper(true /* isMetered */, subId, LOCAL_ADDRESS)) {
807             verifyUnderlyingCellAndRunTest(
808                     subId,
809                     (subGrp, cellNetwork, cellNetworkCb) -> {
810                         final VcnSetupResult vcnSetupResult =
811                                 setupAndGetVcnNetwork(
812                                         subGrp, cellNetwork, cellNetworkCb, testNetworkWrapper);
813 
814                         mConnectivityManager.simulateDataStall(
815                                 DETECTION_METHOD_DNS_EVENTS,
816                                 System.currentTimeMillis(),
817                                 vcnSetupResult.vcnNetwork,
818                                 new PersistableBundle() /* extra data stall info; unused */);
819 
820                         injectAndVerifyIkeMobikePackets(testNetworkWrapper.ikeTunUtils);
821 
822                         clearVcnConfigsAndVerifyNetworkTeardown(
823                                 subGrp, cellNetworkCb, vcnSetupResult.vcnNetwork);
824                     });
825         }
826     }
827 
createTestNetworkForNetworkSelection( int subId, Set<Integer> capabilities)828     private TestNetworkWrapper createTestNetworkForNetworkSelection(
829             int subId, Set<Integer> capabilities) throws Exception {
830         return createTestNetworkWrapper(subId, LOCAL_ADDRESS, capabilities);
831     }
832 
verifyVcnMigratesToPreferredUnderlyingNetwork( VcnConfig vcnConfig, Set<Integer> capSetLessPreferred, Set<Integer> capSetPreferred)833     private void verifyVcnMigratesToPreferredUnderlyingNetwork(
834             VcnConfig vcnConfig, Set<Integer> capSetLessPreferred, Set<Integer> capSetPreferred)
835             throws Exception {
836         final int subId = verifyAndGetValidDataSubId();
837 
838         // Start on a less preferred network.
839         try (TestNetworkWrapper testNetworkWrapperLessPreferred =
840                 createTestNetworkForNetworkSelection(subId, capSetLessPreferred)) {
841             verifyUnderlyingCellAndRunTest(
842                     subId,
843                     (subGrp, cellNetwork, cellNetworkCb) -> {
844                         final VcnSetupResult vcnSetupResult =
845                                 setupAndGetVcnNetwork(
846                                         subGrp,
847                                         cellNetwork,
848                                         cellNetworkCb,
849                                         vcnConfig,
850                                         testNetworkWrapperLessPreferred);
851 
852                         // Then bring up a more preferred network, and expect to switch to it.
853                         try (TestNetworkWrapper testNetworkWrapperPreferred =
854                                 createTestNetworkForNetworkSelection(subId, capSetPreferred)) {
855                             injectAndVerifyIkeMobikePackets(
856                                     testNetworkWrapperPreferred.ikeTunUtils);
857 
858                             clearVcnConfigsAndVerifyNetworkTeardown(
859                                     subGrp, cellNetworkCb, vcnSetupResult.vcnNetwork);
860                         }
861                     });
862         }
863     }
864 
verifyVcnDoesNotSelectLessPreferredUnderlyingNetwork( VcnConfig vcnConfig, Set<Integer> capSetLessPreferred, Set<Integer> capSetPreferred)865     private void verifyVcnDoesNotSelectLessPreferredUnderlyingNetwork(
866             VcnConfig vcnConfig, Set<Integer> capSetLessPreferred, Set<Integer> capSetPreferred)
867             throws Exception {
868         final int subId = verifyAndGetValidDataSubId();
869 
870         // Start on a more preferred network.
871         try (TestNetworkWrapper testNetworkWrapperPreferred =
872                 createTestNetworkForNetworkSelection(subId, capSetPreferred)) {
873             verifyUnderlyingCellAndRunTest(
874                     subId,
875                     (subGrp, cellNetwork, cellNetworkCb) -> {
876                         final VcnSetupResult vcnSetupResult =
877                                 setupAndGetVcnNetwork(
878                                         subGrp,
879                                         cellNetwork,
880                                         cellNetworkCb,
881                                         vcnConfig,
882                                         testNetworkWrapperPreferred);
883 
884                         // Then bring up a less preferred network, and expect the VCN underlying
885                         // network does not change.
886                         try (TestNetworkWrapper testNetworkWrapperLessPreferred =
887                                 createTestNetworkForNetworkSelection(subId, capSetLessPreferred)) {
888                             injectAndVerifyIkeDpdPackets(
889                                     testNetworkWrapperPreferred.ikeTunUtils,
890                                     vcnSetupResult.ikeExchangePortPair);
891 
892                             clearVcnConfigsAndVerifyNetworkTeardown(
893                                     subGrp, cellNetworkCb, vcnSetupResult.vcnNetwork);
894                         }
895                     });
896         }
897     }
898 
verifyVcnMigratesAfterPreferredUnderlyingNetworkDies( VcnConfig vcnConfig, Set<Integer> capSetLessPreferred, Set<Integer> capSetPreferred)899     private void verifyVcnMigratesAfterPreferredUnderlyingNetworkDies(
900             VcnConfig vcnConfig, Set<Integer> capSetLessPreferred, Set<Integer> capSetPreferred)
901             throws Exception {
902         final int subId = verifyAndGetValidDataSubId();
903 
904         // Start on a more preferred network
905         try (TestNetworkWrapper testNetworkWrapperPreferred =
906                 createTestNetworkForNetworkSelection(subId, capSetPreferred)) {
907             verifyUnderlyingCellAndRunTest(
908                     subId,
909                     (subGrp, cellNetwork, cellNetworkCb) -> {
910                         final VcnSetupResult vcnSetupResult =
911                                 setupAndGetVcnNetwork(
912                                         subGrp,
913                                         cellNetwork,
914                                         cellNetworkCb,
915                                         vcnConfig,
916                                         testNetworkWrapperPreferred);
917 
918                         // Bring up a less preferred network
919                         try (TestNetworkWrapper testNetworkWrapperLessPreferred =
920                                 createTestNetworkForNetworkSelection(subId, capSetLessPreferred)) {
921                             // Teardown the preferred network
922                             testNetworkWrapperPreferred.close();
923                             testNetworkWrapperPreferred.vcnNetworkCallback.waitForLost();
924 
925                             // Verify the VCN switches to the remaining less preferred network
926                             injectAndVerifyIkeMobikePackets(
927                                     testNetworkWrapperLessPreferred.ikeTunUtils);
928 
929                             clearVcnConfigsAndVerifyNetworkTeardown(
930                                     subGrp, cellNetworkCb, vcnSetupResult.vcnNetwork);
931                         }
932                     });
933         }
934     }
935 
createCellTemplateBaseBuilder()936     private VcnCellUnderlyingNetworkTemplate.Builder createCellTemplateBaseBuilder()
937             throws Exception {
938         return new VcnCellUnderlyingNetworkTemplate.Builder().setInternet(MATCH_ANY);
939     }
940 
createVcnConfigPrefersMetered()941     private VcnConfig createVcnConfigPrefersMetered() throws Exception {
942         final List<VcnUnderlyingNetworkTemplate> nwTemplates = new ArrayList<>();
943         nwTemplates.add(
944                 createCellTemplateBaseBuilder()
945                         .setCbs(MATCH_REQUIRED)
946                         .setMetered(MATCH_REQUIRED)
947                         .build());
948         nwTemplates.add(
949                 createCellTemplateBaseBuilder()
950                         .setCbs(MATCH_REQUIRED)
951                         .setMetered(MATCH_FORBIDDEN)
952                         .build());
953         return buildVcnConfigBase(nwTemplates).setIsTestModeProfile().build();
954     }
955 
956     @Test
testVcnMigratesToPreferredUnderlyingNetwork_preferMetered()957     public void testVcnMigratesToPreferredUnderlyingNetwork_preferMetered() throws Exception {
958         verifyVcnMigratesToPreferredUnderlyingNetwork(
959                 createVcnConfigPrefersMetered(),
960                 Set.of(NET_CAPABILITY_NOT_METERED, NET_CAPABILITY_CBS),
961                 Set.of(NET_CAPABILITY_CBS));
962     }
963 
964     @Test
testVcnDoesNotSelectLessPreferredUnderlyingNetwork_preferMetered()965     public void testVcnDoesNotSelectLessPreferredUnderlyingNetwork_preferMetered()
966             throws Exception {
967         verifyVcnDoesNotSelectLessPreferredUnderlyingNetwork(
968                 createVcnConfigPrefersMetered(),
969                 Set.of(NET_CAPABILITY_NOT_METERED, NET_CAPABILITY_CBS),
970                 Set.of(NET_CAPABILITY_CBS));
971     }
972 
973     @Test
testVcnMigratesAfterPreferredUnderlyingNetworkDies_preferMetered()974     public void testVcnMigratesAfterPreferredUnderlyingNetworkDies_preferMetered()
975             throws Exception {
976         verifyVcnMigratesAfterPreferredUnderlyingNetworkDies(
977                 createVcnConfigPrefersMetered(),
978                 Set.of(NET_CAPABILITY_NOT_METERED, NET_CAPABILITY_CBS),
979                 Set.of(NET_CAPABILITY_CBS));
980     }
981 
createVcnConfigPrefersCbs()982     private VcnConfig createVcnConfigPrefersCbs() throws Exception {
983         final List<VcnUnderlyingNetworkTemplate> nwTemplates = new ArrayList<>();
984         nwTemplates.add(createCellTemplateBaseBuilder().setCbs(MATCH_REQUIRED).build());
985         nwTemplates.add(createCellTemplateBaseBuilder().setRcs(MATCH_REQUIRED).build());
986 
987         return buildVcnConfigBase(nwTemplates).setIsTestModeProfile().build();
988     }
989 
990     @Test
testVcnMigratesToPreferredUnderlyingNetwork_preferCbs()991     public void testVcnMigratesToPreferredUnderlyingNetwork_preferCbs() throws Exception {
992         verifyVcnMigratesToPreferredUnderlyingNetwork(
993                 createVcnConfigPrefersCbs(),
994                 Set.of(NET_CAPABILITY_NOT_METERED, NET_CAPABILITY_RCS),
995                 Set.of(NET_CAPABILITY_NOT_METERED, NET_CAPABILITY_CBS));
996     }
997 
998     @Test
testVcnDoesNotSelectLessPreferredUnderlyingNetwork_preferCbs()999     public void testVcnDoesNotSelectLessPreferredUnderlyingNetwork_preferCbs() throws Exception {
1000         verifyVcnDoesNotSelectLessPreferredUnderlyingNetwork(
1001                 createVcnConfigPrefersCbs(),
1002                 Set.of(NET_CAPABILITY_NOT_METERED, NET_CAPABILITY_RCS),
1003                 Set.of(NET_CAPABILITY_NOT_METERED, NET_CAPABILITY_CBS));
1004     }
1005 
1006     @Test
testVcnMigratesAfterPreferredUnderlyingNetworkDies_preferCbs()1007     public void testVcnMigratesAfterPreferredUnderlyingNetworkDies_preferCbs() throws Exception {
1008         verifyVcnMigratesAfterPreferredUnderlyingNetworkDies(
1009                 createVcnConfigPrefersCbs(),
1010                 Set.of(NET_CAPABILITY_NOT_METERED, NET_CAPABILITY_RCS),
1011                 Set.of(NET_CAPABILITY_NOT_METERED, NET_CAPABILITY_CBS));
1012     }
1013 
createVcnConfigPrefersNonCbs()1014     private VcnConfig createVcnConfigPrefersNonCbs() throws Exception {
1015         final List<VcnUnderlyingNetworkTemplate> nwTemplates = new ArrayList<>();
1016         nwTemplates.add(
1017                 createCellTemplateBaseBuilder()
1018                         .setRcs(MATCH_REQUIRED)
1019                         .setCbs(MATCH_FORBIDDEN)
1020                         .build());
1021         nwTemplates.add(
1022                 createCellTemplateBaseBuilder().setRcs(MATCH_REQUIRED).setCbs(MATCH_ANY).build());
1023 
1024         return buildVcnConfigBase(nwTemplates).setIsTestModeProfile().build();
1025     }
1026 
1027     @Test
testVcnMigratesToPreferredUnderlyingNetwork_preferNonCbs()1028     public void testVcnMigratesToPreferredUnderlyingNetwork_preferNonCbs() throws Exception {
1029         verifyVcnMigratesToPreferredUnderlyingNetwork(
1030                 createVcnConfigPrefersNonCbs(),
1031                 Set.of(NET_CAPABILITY_NOT_METERED, NET_CAPABILITY_RCS, NET_CAPABILITY_CBS),
1032                 Set.of(NET_CAPABILITY_NOT_METERED, NET_CAPABILITY_RCS));
1033     }
1034 
1035     @Test
testVcnDoesNotSelectLessPreferredUnderlyingNetwork_preferNonCbs()1036     public void testVcnDoesNotSelectLessPreferredUnderlyingNetwork_preferNonCbs() throws Exception {
1037         verifyVcnDoesNotSelectLessPreferredUnderlyingNetwork(
1038                 createVcnConfigPrefersNonCbs(),
1039                 Set.of(NET_CAPABILITY_NOT_METERED, NET_CAPABILITY_RCS, NET_CAPABILITY_CBS),
1040                 Set.of(NET_CAPABILITY_NOT_METERED, NET_CAPABILITY_RCS));
1041     }
1042 
1043     @Test
testVcnMigratesAfterPreferredUnderlyingNetworkDies_preferNonCbs()1044     public void testVcnMigratesAfterPreferredUnderlyingNetworkDies_preferNonCbs() throws Exception {
1045         verifyVcnMigratesAfterPreferredUnderlyingNetworkDies(
1046                 createVcnConfigPrefersNonCbs(),
1047                 Set.of(NET_CAPABILITY_NOT_METERED, NET_CAPABILITY_RCS, NET_CAPABILITY_CBS),
1048                 Set.of(NET_CAPABILITY_NOT_METERED, NET_CAPABILITY_RCS));
1049     }
1050 
1051     @Test
testSetVcnWithCbsMatchAny_preferCbsNetworkOverUnmatchedNetwork()1052     public void testSetVcnWithCbsMatchAny_preferCbsNetworkOverUnmatchedNetwork() throws Exception {
1053         final List<VcnUnderlyingNetworkTemplate> nwTemplates = new ArrayList<>();
1054         nwTemplates.add(
1055                 createCellTemplateBaseBuilder().setRcs(MATCH_REQUIRED).setCbs(MATCH_ANY).build());
1056 
1057         final VcnConfig vcnConfig = buildVcnConfigBase(nwTemplates).setIsTestModeProfile().build();
1058 
1059         verifyVcnMigratesToPreferredUnderlyingNetwork(
1060                 vcnConfig,
1061                 Set.of(NET_CAPABILITY_NOT_METERED),
1062                 Set.of(NET_CAPABILITY_NOT_METERED, NET_CAPABILITY_RCS, NET_CAPABILITY_CBS));
1063     }
1064 
1065     @Test
testSetVcnWithCbsMatchAny_preferNonCbsNetworkOverUnmatchedNetwork()1066     public void testSetVcnWithCbsMatchAny_preferNonCbsNetworkOverUnmatchedNetwork()
1067             throws Exception {
1068         final List<VcnUnderlyingNetworkTemplate> nwTemplates = new ArrayList<>();
1069         nwTemplates.add(
1070                 createCellTemplateBaseBuilder().setRcs(MATCH_REQUIRED).setCbs(MATCH_ANY).build());
1071 
1072         final VcnConfig vcnConfig = buildVcnConfigBase(nwTemplates).setIsTestModeProfile().build();
1073 
1074         verifyVcnMigratesToPreferredUnderlyingNetwork(
1075                 vcnConfig,
1076                 Set.of(NET_CAPABILITY_NOT_METERED),
1077                 Set.of(NET_CAPABILITY_NOT_METERED, NET_CAPABILITY_RCS));
1078     }
1079 
1080     @Test
testVcnNoUnderlyingNetworkSelectedFallback()1081     public void testVcnNoUnderlyingNetworkSelectedFallback() throws Exception {
1082         final int subId = verifyAndGetValidDataSubId();
1083         final List<VcnUnderlyingNetworkTemplate> nwTemplates = new ArrayList<>();
1084         nwTemplates.add(
1085                 new VcnWifiUnderlyingNetworkTemplate.Builder().setMetered(MATCH_REQUIRED).build());
1086         final VcnConfig vcnConfig = buildVcnConfigBase(nwTemplates).setIsTestModeProfile().build();
1087 
1088         // Bring up a network that does not match any of the configured network templates
1089         try (TestNetworkWrapper testNetworkWrapper =
1090                 createTestNetworkWrapper(false /* isMetered */, subId, LOCAL_ADDRESS)) {
1091             verifyUnderlyingCellAndRunTest(subId, (subGrp, cellNetwork, cellNetworkCb) -> {
1092                 // Verify the VCN can still be set up on the only one underlying network
1093                 final VcnSetupResult vcnSetupResult =
1094                         setupAndGetVcnNetwork(
1095                                 subGrp,
1096                                 cellNetwork,
1097                                 cellNetworkCb,
1098                                 vcnConfig,
1099                                 testNetworkWrapper);
1100 
1101                 clearVcnConfigsAndVerifyNetworkTeardown(
1102                         subGrp, cellNetworkCb, vcnSetupResult.vcnNetwork);
1103             });
1104         }
1105     }
1106 
1107     private static class VcnSetupResult {
1108         public final Network vcnNetwork;
1109         public final PortPair ikeExchangePortPair;
1110 
VcnSetupResult(Network vcnNetwork, PortPair ikeExchangePortPair)1111         VcnSetupResult(Network vcnNetwork, PortPair ikeExchangePortPair) {
1112             this.vcnNetwork = vcnNetwork;
1113             this.ikeExchangePortPair = ikeExchangePortPair;
1114         }
1115     }
1116 
setupAndGetVcnNetwork( @onNull ParcelUuid subGrp, @NonNull Network cellNetwork, @NonNull VcnTestNetworkCallback cellNetworkCb, @NonNull VcnConfig testModeVcnConfig, @NonNull TestNetworkWrapper testNetworkWrapper)1117     private VcnSetupResult setupAndGetVcnNetwork(
1118             @NonNull ParcelUuid subGrp,
1119             @NonNull Network cellNetwork,
1120             @NonNull VcnTestNetworkCallback cellNetworkCb,
1121             @NonNull VcnConfig testModeVcnConfig,
1122             @NonNull TestNetworkWrapper testNetworkWrapper)
1123             throws Exception {
1124         cellNetworkCb.waitForAvailable();
1125         mVcnManager.setVcnConfig(subGrp, testModeVcnConfig);
1126 
1127         // Wait until the cell Network is lost (due to losing NOT_VCN_MANAGED) to wait for
1128         // VCN network
1129         final Network lostCellNetwork = cellNetworkCb.waitForLost();
1130         assertEquals(cellNetwork, lostCellNetwork);
1131 
1132         final PortPair ikeExchangePortPair =
1133                 injectAndVerifyIkeSessionNegotiationPackets(testNetworkWrapper.ikeTunUtils);
1134 
1135         final Network vcnNetwork = cellNetworkCb.waitForAvailable();
1136         assertNotNull("VCN network did not come up", vcnNetwork);
1137         return new VcnSetupResult(vcnNetwork, ikeExchangePortPair);
1138     }
1139 
setupAndGetVcnNetwork( @onNull ParcelUuid subGrp, @NonNull Network cellNetwork, @NonNull VcnTestNetworkCallback cellNetworkCb, @NonNull TestNetworkWrapper testNetworkWrapper)1140     private VcnSetupResult setupAndGetVcnNetwork(
1141             @NonNull ParcelUuid subGrp,
1142             @NonNull Network cellNetwork,
1143             @NonNull VcnTestNetworkCallback cellNetworkCb,
1144             @NonNull TestNetworkWrapper testNetworkWrapper)
1145             throws Exception {
1146         return setupAndGetVcnNetwork(
1147                 subGrp, cellNetwork, cellNetworkCb, buildTestModeVcnConfig(), testNetworkWrapper);
1148     }
1149 
injectAndVerifyIkeSessionNegotiationPackets(@onNull IkeTunUtils ikeTunUtils)1150     private PortPair injectAndVerifyIkeSessionNegotiationPackets(@NonNull IkeTunUtils ikeTunUtils)
1151             throws Exception {
1152         // Generated by forcing IKE to use Test Mode (RandomnessFactory#mIsTestModeEnabled) and
1153         // capturing IKE packets with a live server.
1154         final String ikeInitResp =
1155                 "46b8eca1e0d72a189b9f8e0158e1c0a52120222000000000000001d022000030"
1156                         + "0000002c010100040300000c0100000c800e0080030000080300000803000008"
1157                         + "02000008000000080400000e28000108000e0000164d3413d855a1642d4d6355"
1158                         + "a8ef6666bfaa28a4b5264600c9ffbaef7930bd33af49022926013aae0a48d764"
1159                         + "750ccb3987605957e31a2ef0e6838cfa67af989933c2879434081c4e9787f0d4"
1160                         + "4da0d7dacca5589702a4537ee4fb18e8db21a948b245260f55212a1c619f61c6"
1161                         + "fa1caaff4474082f9714b14ef4bcc7b2b8f43fcb939931119e53b05274faec65"
1162                         + "2816c563529e60c1a88183eba9c456ecb644faf57b726b83e3242e08489d95e9"
1163                         + "81e59c7ad82cf3cdfb00fe0213c4e65d61e88bbefbd536261027da722a2bbf89"
1164                         + "c6378e63ce6fbcef282421e5576bba1b2faa3c4c2d41028f91df7ba165a24a18"
1165                         + "fcba4f96db3e5e0eed76dc7c3c432362dd4a82d32900002461cbd03c08819730"
1166                         + "f1060ed0c0446f784eb8dd884d3f73f54eb2b0c3071cc4f32900001c00004004"
1167                         + "07150f3fd9584dbebb7e88ad256c7bfb9b0bb55a2900001c00004005e3aa3788"
1168                         + "7040e38dbb4de8fd435161cce904ec59290000080000402e290000100000402f"
1169                         + "00020003000400050000000800004014";
1170         final String ikeAuthResp =
1171                 "46b8eca1e0d72a189b9f8e0158e1c0a52e20232000000001000000fc240000e0"
1172                         + "1a666eb2a02b37682436a18fff5e9cef67b9096d6c7887ed235f8b5173c9469e"
1173                         + "361621b66849de2dbcabf956b3d055cafafd503530543540e81dac9bf8fb8826"
1174                         + "e08bc99e9ed2185d8f1322c8885abe4f98a9832c694da775eaa4ae69f17b8cbf"
1175                         + "b009bf82b4bf4012bca489595631c3168cd417f813e7d177d2ceb70766a0773c"
1176                         + "8819d8763627ddc9455ae3d5a5a03224020a66c8e58c8073c4a1fcf5d67cfa95"
1177                         + "15de86b392a63ff54ff5572302b9ce7725085b05839252794c3680f5d8f34019"
1178                         + "fa1930ea045d2a9987850e2049235c7328ef148370b6a3403408b987";
1179 
1180         ikeTunUtils.awaitReqAndInjectResp(
1181                 IKE_DETERMINISTIC_INITIATOR_SPI,
1182                 0 /* expectedMsgId */,
1183                 false /* expectedUseEncap */,
1184                 ikeInitResp);
1185 
1186         byte[] ikeAuthReqPkt =
1187                 ikeTunUtils.awaitReqAndInjectResp(
1188                         IKE_DETERMINISTIC_INITIATOR_SPI,
1189                         1 /* expectedMsgId */,
1190                         true /* expectedUseEncap */,
1191                         ikeAuthResp);
1192 
1193         return IkeTunUtils.getSrcDestPortPair(ikeAuthReqPkt);
1194     }
1195 
clearVcnConfigsAndVerifyNetworkTeardown( @onNull ParcelUuid subGrp, @NonNull VcnTestNetworkCallback cellNetworkCb, @NonNull Network vcnNetwork)1196     private void clearVcnConfigsAndVerifyNetworkTeardown(
1197             @NonNull ParcelUuid subGrp,
1198             @NonNull VcnTestNetworkCallback cellNetworkCb,
1199             @NonNull Network vcnNetwork)
1200             throws Exception {
1201         // Clear the history to remove other networks have been matched to the request
1202         cellNetworkCb.clearLostHistory();
1203 
1204         mVcnManager.clearVcnConfig(subGrp);
1205 
1206         // Expect VCN Network to disappear after VcnConfig is cleared.
1207         if (mConnectivityManager.getNetworkCapabilities(vcnNetwork) != null) {
1208 
1209             // If not already torn down, wait for teardown. In the event that the underlying network
1210             // has already regained the NOT_VCN_MANAGED bit (before the VCN's NetworkAgent teardown)
1211             // the VCN network MAY be immediately replaced with the underlying Cell, which only
1212             // fires an onAvailable for the new network, as opposed to an onLost() for the VCN
1213             // network. In that case, check that the VCN network has been unregistered.
1214             //
1215             // An alternative approach is to monitor #onAvailable as an indicator of potential
1216             // network loss. However, since #onAvailable can mean either 1) the new network has
1217             // higher priority, or 2) the old network is disconnected, this approach will introduce
1218             // a lot more complexities.
1219             final Network lostVcnNetwork = cellNetworkCb.waitForLost();
1220             if (lostVcnNetwork != null) {
1221                 assertEquals(vcnNetwork, lostVcnNetwork);
1222             } else {
1223                 assertNull(mConnectivityManager.getNetworkCapabilities(vcnNetwork));
1224             }
1225         } // Else already torn down, pass.
1226     }
1227 
1228     @Test
testVcnMigrationAfterNetworkDies()1229     public void testVcnMigrationAfterNetworkDies() throws Exception {
1230         final int subId = verifyAndGetValidDataSubId();
1231 
1232         try (TestNetworkWrapper testNetworkWrapper =
1233                 createTestNetworkWrapper(true /* isMetered */, subId, LOCAL_ADDRESS)) {
1234             verifyUnderlyingCellAndRunTest(subId, (subGrp, cellNetwork, cellNetworkCb) -> {
1235                 final VcnSetupResult vcnSetupResult =
1236                     setupAndGetVcnNetwork(subGrp, cellNetwork, cellNetworkCb, testNetworkWrapper);
1237 
1238                 testNetworkWrapper.close();
1239                 testNetworkWrapper.vcnNetworkCallback.waitForLost();
1240 
1241             try (TestNetworkWrapper secondaryTestNetworkWrapper =
1242                     createTestNetworkWrapper(true /* isMetered */, subId, LOCAL_ADDRESS)) {
1243                 try {
1244                     injectAndVerifyIkeMobikePackets(secondaryTestNetworkWrapper.ikeTunUtils);
1245 
1246                     clearVcnConfigsAndVerifyNetworkTeardown(
1247                             subGrp, cellNetworkCb, vcnSetupResult.vcnNetwork);
1248                 } finally {
1249                     secondaryTestNetworkWrapper.close();
1250                 }
1251             }
1252             });
1253         }
1254     }
1255 
injectAndVerifyIkeMobikePackets(@onNull IkeTunUtils ikeTunUtils)1256     private void injectAndVerifyIkeMobikePackets(@NonNull IkeTunUtils ikeTunUtils)
1257             throws Exception {
1258         // Generated by forcing IKE to use Test Mode (RandomnessFactory#mIsTestModeEnabled) and
1259         // capturing IKE packets with a live server. To force the mobility event, use
1260         // IkeSession#setNetwork with the new desired Network.
1261         final String ikeUpdateSaResp =
1262                 "46b8eca1e0d72a189b9f8e0158e1c0a52e202520000000020000007c29000060"
1263                         + "a1fd35f112d92d1df19ce734f6edf56ccda1bfd44ef6de428a097e04d5b40b28"
1264                         + "3897e42f23dd53e444dc6c676cf9a7d9d73bb3975d663ec351fb5ae4e56a55d8"
1265                         + "cbcf376a3b99cc6fd858621cc78b3017d895e4309f09a444028dba85";
1266         final String ikeCreateChildResp =
1267                 "46b8eca1e0d72a189b9f8e0158e1c0a52e20242000000003000000cc210000b0"
1268                         + "e6bb78203dbe2189806c5cecef5040b8c4c0253895c7c0acea6483a1f0f72425"
1269                         + "77ab46e18d553329d4ae1bd31cf57eec6ec31ceb1f2ed6b1195cac98b4b97a25"
1270                         + "115d14c414e44dba8ebbdaf502e43f98a09036bee0ea2a621176300874a3eae8"
1271                         + "c988357255b4e5923928d335b0ef62a565333fae6a64c85ac30e7da34ceeade4"
1272                         + "1a161bcad0b51f8209ee1fdaf53d50359ad6b986ecd4290c9f69a34c64ddc0eb"
1273                         + "73b8f3231f3f4e057404c18d";
1274         final String ikeDeleteChildResp =
1275                 "46b8eca1e0d72a189b9f8e0158e1c0a52e202520000000040000004c2a000030"
1276                         + "53d97806d48ce44e0d4e1adf1de36778f77c3823bfaf8186cc71d4dc73497099"
1277                         + "a9049e7be8a2013affd56ab7";
1278 
1279         ikeTunUtils.awaitReqAndInjectResp(
1280                 IKE_DETERMINISTIC_INITIATOR_SPI,
1281                 2 /* expectedMsgId */,
1282                 true /* expectedUseEncap */,
1283                 ikeUpdateSaResp);
1284 
1285         // If Kernel migration enabled, it will be used instead of MOBIKE-rekey
1286         // TODO (b/277939911): Decouple VCN CTS from IKE implementation behavior
1287         if (!mContext.getPackageManager()
1288                 .hasSystemFeature(PackageManager.FEATURE_IPSEC_TUNNEL_MIGRATION)) {
1289             ikeTunUtils.awaitReqAndInjectResp(
1290                     IKE_DETERMINISTIC_INITIATOR_SPI,
1291                     3 /* expectedMsgId */,
1292                     true /* expectedUseEncap */,
1293                     ikeCreateChildResp);
1294 
1295             ikeTunUtils.awaitReqAndInjectResp(
1296                     IKE_DETERMINISTIC_INITIATOR_SPI,
1297                     4 /* expectedMsgId */,
1298                     true /* expectedUseEncap */,
1299                     ikeDeleteChildResp);
1300         }
1301     }
1302 
injectAndVerifyIkeDpdPackets( @onNull IkeTunUtils ikeTunUtils, PortPair localRemotePorts)1303     private void injectAndVerifyIkeDpdPackets(
1304             @NonNull IkeTunUtils ikeTunUtils, PortPair localRemotePorts) throws Exception {
1305         // Generated by forcing IKE to use Test Mode (RandomnessFactory#mIsTestModeEnabled) and
1306         // capturing IKE packets with a live server.
1307         final String ikeDpdRequestHex =
1308                 "46b8eca1e0d72a189b9f8e0158e1c0a52E202500000000000000004c00000030"
1309                         + "3A31D5FAC230FEA67246B0C1A049A28944C341301979EB7B52FC669274B77D5F"
1310                         + "A6CFE8D768CF390536436D08";
1311 
1312         byte[] ikeDpdRequest =
1313                 IkeTunUtils.buildIkePacket(
1314                         REMOTE_ADDRESS,
1315                         LOCAL_ADDRESS,
1316                         localRemotePorts.dstPort,
1317                         localRemotePorts.srcPort,
1318                         true /* useEncap */,
1319                         hexStringToByteArray(ikeDpdRequestHex));
1320 
1321         ikeTunUtils.injectPacket(ikeDpdRequest);
1322         ikeTunUtils.awaitResp(
1323                 IKE_DETERMINISTIC_INITIATOR_SPI,
1324                 0 /* expectedMsgId */,
1325                 true /* expectedUseEncap */);
1326     }
1327 
verifyVcnSafeModeTimeoutOnTestNetwork(int subId, long timeoutMillis)1328     private void verifyVcnSafeModeTimeoutOnTestNetwork(int subId, long timeoutMillis)
1329             throws Exception {
1330         try (TestNetworkWrapper testNetworkWrapper =
1331                 createTestNetworkWrapper(true /* isMetered */, subId, LOCAL_ADDRESS)) {
1332             // Before the VCN starts, the test network should have NOT_VCN_MANAGED
1333             waitForExpectedUnderlyingNetworkWithCapabilities(
1334                     testNetworkWrapper,
1335                     true /* expectNotVcnManaged */,
1336                     false /* expectNotMetered */,
1337                     TestNetworkWrapper.NETWORK_CB_TIMEOUT_MS);
1338             verifyUnderlyingCellAndRunTest(subId, (subGrp, cellNetwork, cellNetworkCb) -> {
1339                 final VcnSetupResult vcnSetupResult =
1340                     setupAndGetVcnNetwork(subGrp, cellNetwork, cellNetworkCb, testNetworkWrapper);
1341 
1342                 // Once VCN starts, the test network should lose NOT_VCN_MANAGED
1343                 waitForExpectedUnderlyingNetworkWithCapabilities(
1344                         testNetworkWrapper,
1345                         false /* expectNotVcnManaged */,
1346                         false /* expectNotMetered */,
1347                         TestNetworkWrapper.NETWORK_CB_TIMEOUT_MS);
1348 
1349                 // After VCN has started up, wait for safemode to kick in and expect the
1350                 // underlying Test Network to regain NOT_VCN_MANAGED.
1351                 waitForExpectedUnderlyingNetworkWithCapabilities(
1352                         testNetworkWrapper,
1353                         true /* expectNotVcnManaged */,
1354                         false /* expectNotMetered */,
1355                         timeoutMillis);
1356 
1357                 // Verify that VCN Network is also lost in safemode
1358                 cellNetworkCb.waitForLostNetwork(vcnSetupResult.vcnNetwork);
1359 
1360                 verifyVcnStatus(subGrp, VCN_STATUS_CODE_SAFE_MODE);
1361 
1362                 mVcnManager.clearVcnConfig(subGrp);
1363             });
1364         }
1365     }
1366 
setSafeModeTimeoutForCarrier(int subId, int timeoutSeconds)1367     private void setSafeModeTimeoutForCarrier(int subId, int timeoutSeconds) {
1368         final PersistableBundle carrierConfig = new PersistableBundle();
1369         carrierConfig.putInt(VcnManager.VCN_SAFE_MODE_TIMEOUT_SECONDS_KEY, timeoutSeconds);
1370         mCarrierConfigManager.overrideConfig(subId, carrierConfig);
1371     }
1372 
1373     @Test
testVcnSafeModeOnTestNetwork_defaultTimeout()1374     public void testVcnSafeModeOnTestNetwork_defaultTimeout() throws Exception {
1375         final int subId = verifyAndGetValidDataSubId();
1376         verifyVcnSafeModeTimeoutOnTestNetwork(subId, SAFEMODE_TIMEOUT_MILLIS);
1377     }
1378 
1379     @Test
testVcnSafeModeOnTestNetwork_overrideTimeout()1380     public void testVcnSafeModeOnTestNetwork_overrideTimeout() throws Exception {
1381         final int subId = verifyAndGetValidDataSubId();
1382         final int safeModeTimeoutSeconds = 5;
1383         final int gracePeriod = 5;
1384 
1385         final PersistableBundle oldCarrierConfig = mCarrierConfigManager.getConfigForSubId(subId);
1386         setSafeModeTimeoutForCarrier(subId, safeModeTimeoutSeconds);
1387 
1388         verifyVcnSafeModeTimeoutOnTestNetwork(
1389                 subId, TimeUnit.SECONDS.toMillis(safeModeTimeoutSeconds + gracePeriod));
1390 
1391         mCarrierConfigManager.overrideConfig(subId, oldCarrierConfig);
1392     }
1393 
verifyEnterSafeModeImmediately(VcnConfig vcnConfig, boolean isSafeModeExpected)1394     private void verifyEnterSafeModeImmediately(VcnConfig vcnConfig, boolean isSafeModeExpected)
1395             throws Exception {
1396         final int subId = verifyAndGetValidDataSubId();
1397         final TestVcnStatusCallback callback = new TestVcnStatusCallback();
1398 
1399         // Override the safe mode timeout to be zero
1400         final PersistableBundle oldCarrierConfig = mCarrierConfigManager.getConfigForSubId(subId);
1401         setSafeModeTimeoutForCarrier(subId, 0);
1402 
1403         try (TestNetworkWrapper testNetworkWrapper =
1404                 createTestNetworkWrapper(true /* isMetered */, subId, LOCAL_ADDRESS)) {
1405             verifyUnderlyingCellAndRunTest(subId, (subGrp, cellNetwork, cellNetworkCb) -> {
1406                 mVcnManager.registerVcnStatusCallback(subGrp, INLINE_EXECUTOR, callback);
1407                 mVcnManager.setVcnConfig(subGrp, vcnConfig);
1408 
1409                 assertEquals(
1410                         VCN_STATUS_CODE_NOT_CONFIGURED, callback.awaitOnStatusChanged());
1411                 assertEquals(VCN_STATUS_CODE_ACTIVE, callback.awaitOnStatusChanged());
1412 
1413                 if (isSafeModeExpected) {
1414                     assertEquals(
1415                             VCN_STATUS_CODE_SAFE_MODE, callback.awaitOnStatusChanged());
1416                 } else {
1417                     assertEquals(
1418                             VCN_STATUS_CODE_AWAIT_TIMEOUT, callback.awaitOnStatusChanged());
1419                 }
1420 
1421                 mVcnManager.clearVcnConfig(subGrp);
1422                 mVcnManager.unregisterVcnStatusCallback(callback);
1423             });
1424         }
1425 
1426         // Reset Carrier Config
1427         mCarrierConfigManager.overrideConfig(subId, oldCarrierConfig);
1428     }
1429 
newVcnConfig(boolean isSafeModeEnabled)1430     private VcnConfig newVcnConfig(boolean isSafeModeEnabled) {
1431         final VcnGatewayConnectionConfig.Builder gatewayConfigBuilder =
1432                 VcnGatewayConnectionConfigTest.buildVcnGatewayConnectionConfigBase()
1433                         .addExposedCapability(NetworkCapabilities.NET_CAPABILITY_MMS);
1434 
1435         if (!isSafeModeEnabled) {
1436             gatewayConfigBuilder.setSafeModeEnabled(false);
1437         }
1438         // Don't call setSafeModeEnabled since enabling safe mode should not be flag gated
1439 
1440         return new VcnConfig.Builder(mContext)
1441                 .setIsTestModeProfile()
1442                 .addGatewayConnectionConfig(gatewayConfigBuilder.build())
1443                 .build();
1444     }
1445 
1446     @Test
testEnterSafeModeImmediately_safeModeEnabled()1447     public void testEnterSafeModeImmediately_safeModeEnabled() throws Exception {
1448         verifyEnterSafeModeImmediately(
1449                 newVcnConfig(true /* isSafeModeEnabled */), true /* isSafeModeExpected */);
1450     }
1451 
1452     @Test
testEnterSafeModeImmediately_safeModeDisabled()1453     public void testEnterSafeModeImmediately_safeModeDisabled() throws Exception {
1454         verifyEnterSafeModeImmediately(
1455                 newVcnConfig(false /* isSafeModeEnabled */), false /* isSafeModeExpected */);
1456     }
1457 }
1458