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