1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server;
18 
19 import static android.net.ConnectivityManager.NetworkCallback;
20 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
21 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED;
22 import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
23 import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
24 import static android.net.vcn.VcnManager.VCN_STATUS_CODE_ACTIVE;
25 import static android.net.vcn.VcnManager.VCN_STATUS_CODE_SAFE_MODE;
26 import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
27 import static android.telephony.TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS;
28 import static android.telephony.TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS;
29 
30 import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
31 import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionTrackerCallback;
32 import static com.android.server.vcn.VcnTestUtils.setupSystemService;
33 
34 import static org.junit.Assert.assertEquals;
35 import static org.junit.Assert.assertFalse;
36 import static org.junit.Assert.assertNotNull;
37 import static org.junit.Assert.assertNull;
38 import static org.junit.Assert.assertTrue;
39 import static org.junit.Assert.fail;
40 import static org.mockito.ArgumentMatchers.any;
41 import static org.mockito.ArgumentMatchers.anyBoolean;
42 import static org.mockito.ArgumentMatchers.anyInt;
43 import static org.mockito.ArgumentMatchers.eq;
44 import static org.mockito.Mockito.CALLS_REAL_METHODS;
45 import static org.mockito.Mockito.any;
46 import static org.mockito.Mockito.argThat;
47 import static org.mockito.Mockito.doAnswer;
48 import static org.mockito.Mockito.doNothing;
49 import static org.mockito.Mockito.doReturn;
50 import static org.mockito.Mockito.doThrow;
51 import static org.mockito.Mockito.eq;
52 import static org.mockito.Mockito.mock;
53 import static org.mockito.Mockito.never;
54 import static org.mockito.Mockito.times;
55 import static org.mockito.Mockito.verify;
56 
57 import android.annotation.NonNull;
58 import android.app.AppOpsManager;
59 import android.content.BroadcastReceiver;
60 import android.content.Context;
61 import android.content.Intent;
62 import android.content.pm.PackageManager;
63 import android.net.ConnectivityManager;
64 import android.net.LinkProperties;
65 import android.net.Network;
66 import android.net.NetworkCapabilities;
67 import android.net.NetworkRequest;
68 import android.net.TelephonyNetworkSpecifier;
69 import android.net.vcn.IVcnStatusCallback;
70 import android.net.vcn.IVcnUnderlyingNetworkPolicyListener;
71 import android.net.vcn.VcnConfig;
72 import android.net.vcn.VcnConfigTest;
73 import android.net.vcn.VcnGatewayConnectionConfigTest;
74 import android.net.vcn.VcnManager;
75 import android.net.vcn.VcnUnderlyingNetworkPolicy;
76 import android.os.IBinder;
77 import android.os.ParcelUuid;
78 import android.os.PersistableBundle;
79 import android.os.Process;
80 import android.os.UserHandle;
81 import android.os.test.TestLooper;
82 import android.telephony.SubscriptionInfo;
83 import android.telephony.SubscriptionManager;
84 import android.telephony.TelephonyManager;
85 import android.util.ArraySet;
86 
87 import androidx.test.filters.SmallTest;
88 import androidx.test.runner.AndroidJUnit4;
89 
90 import com.android.server.VcnManagementService.VcnCallback;
91 import com.android.server.VcnManagementService.VcnStatusCallbackInfo;
92 import com.android.server.vcn.TelephonySubscriptionTracker;
93 import com.android.server.vcn.Vcn;
94 import com.android.server.vcn.VcnContext;
95 import com.android.server.vcn.VcnNetworkProvider;
96 import com.android.server.vcn.util.PersistableBundleUtils;
97 
98 import org.junit.Before;
99 import org.junit.Test;
100 import org.junit.runner.RunWith;
101 import org.mockito.ArgumentCaptor;
102 
103 import java.io.FileNotFoundException;
104 import java.util.Arrays;
105 import java.util.Collections;
106 import java.util.List;
107 import java.util.Map;
108 import java.util.Map.Entry;
109 import java.util.Set;
110 import java.util.UUID;
111 
112 /** Tests for {@link VcnManagementService}. */
113 @RunWith(AndroidJUnit4.class)
114 @SmallTest
115 public class VcnManagementServiceTest {
116     private static final String TEST_PACKAGE_NAME =
117             VcnManagementServiceTest.class.getPackage().getName();
118     private static final String TEST_CB_PACKAGE_NAME =
119             VcnManagementServiceTest.class.getPackage().getName() + ".callback";
120     private static final ParcelUuid TEST_UUID_1 = new ParcelUuid(new UUID(0, 0));
121     private static final ParcelUuid TEST_UUID_2 = new ParcelUuid(new UUID(1, 1));
122     private static final VcnConfig TEST_VCN_CONFIG;
123     private static final int TEST_UID = Process.FIRST_APPLICATION_UID;
124 
125     static {
126         final Context mockConfigContext = mock(Context.class);
127         doReturn(TEST_PACKAGE_NAME).when(mockConfigContext).getOpPackageName();
128 
129         TEST_VCN_CONFIG = VcnConfigTest.buildTestConfig(mockConfigContext);
130     }
131 
132     private static final Map<ParcelUuid, VcnConfig> TEST_VCN_CONFIG_MAP =
133             Collections.unmodifiableMap(Collections.singletonMap(TEST_UUID_1, TEST_VCN_CONFIG));
134 
135     private static final int TEST_SUBSCRIPTION_ID = 1;
136     private static final int TEST_SUBSCRIPTION_ID_2 = 2;
137     private static final SubscriptionInfo TEST_SUBSCRIPTION_INFO =
138             new SubscriptionInfo(
139                     TEST_SUBSCRIPTION_ID /* id */,
140                     "" /* iccId */,
141                     0 /* simSlotIndex */,
142                     "Carrier" /* displayName */,
143                     "Carrier" /* carrierName */,
144                     0 /* nameSource */,
145                     255 /* iconTint */,
146                     "12345" /* number */,
147                     0 /* roaming */,
148                     null /* icon */,
149                     "0" /* mcc */,
150                     "0" /* mnc */,
151                     "0" /* countryIso */,
152                     false /* isEmbedded */,
153                     null /* nativeAccessRules */,
154                     null /* cardString */,
155                     false /* isOpportunistic */,
156                     TEST_UUID_1.toString() /* groupUUID */,
157                     0 /* carrierId */,
158                     0 /* profileClass */);
159 
160     private final Context mMockContext = mock(Context.class);
161     private final VcnManagementService.Dependencies mMockDeps =
162             mock(VcnManagementService.Dependencies.class);
163     private final TestLooper mTestLooper = new TestLooper();
164     private final ConnectivityManager mConnMgr = mock(ConnectivityManager.class);
165     private final TelephonyManager mTelMgr = mock(TelephonyManager.class);
166     private final SubscriptionManager mSubMgr = mock(SubscriptionManager.class);
167     private final AppOpsManager mAppOpsMgr = mock(AppOpsManager.class);
168     private final VcnContext mVcnContext = mock(VcnContext.class);
169     private final PersistableBundleUtils.LockingReadWriteHelper mConfigReadWriteHelper =
170             mock(PersistableBundleUtils.LockingReadWriteHelper.class);
171     private final TelephonySubscriptionTracker mSubscriptionTracker =
172             mock(TelephonySubscriptionTracker.class);
173 
174     private final ArgumentCaptor<VcnCallback> mVcnCallbackCaptor =
175             ArgumentCaptor.forClass(VcnCallback.class);
176 
177     private final VcnManagementService mVcnMgmtSvc;
178 
179     private final IVcnUnderlyingNetworkPolicyListener mMockPolicyListener =
180             mock(IVcnUnderlyingNetworkPolicyListener.class);
181     private final IVcnStatusCallback mMockStatusCallback = mock(IVcnStatusCallback.class);
182     private final IBinder mMockIBinder = mock(IBinder.class);
183 
VcnManagementServiceTest()184     public VcnManagementServiceTest() throws Exception {
185         setupSystemService(
186                 mMockContext, mConnMgr, Context.CONNECTIVITY_SERVICE, ConnectivityManager.class);
187         setupSystemService(
188                 mMockContext, mTelMgr, Context.TELEPHONY_SERVICE, TelephonyManager.class);
189         setupSystemService(
190                 mMockContext,
191                 mSubMgr,
192                 Context.TELEPHONY_SUBSCRIPTION_SERVICE,
193                 SubscriptionManager.class);
194         setupSystemService(mMockContext, mAppOpsMgr, Context.APP_OPS_SERVICE, AppOpsManager.class);
195 
196         doReturn(TEST_PACKAGE_NAME).when(mMockContext).getOpPackageName();
197 
198         doReturn(mMockContext).when(mVcnContext).getContext();
199         doReturn(mTestLooper.getLooper()).when(mMockDeps).getLooper();
200         doReturn(TEST_UID).when(mMockDeps).getBinderCallingUid();
201         doReturn(mVcnContext)
202                 .when(mMockDeps)
203                 .newVcnContext(
204                         eq(mMockContext),
205                         eq(mTestLooper.getLooper()),
206                         any(VcnNetworkProvider.class),
207                         anyBoolean());
208         doReturn(mSubscriptionTracker)
209                 .when(mMockDeps)
210                 .newTelephonySubscriptionTracker(
211                         eq(mMockContext),
212                         eq(mTestLooper.getLooper()),
213                         any(TelephonySubscriptionTrackerCallback.class));
214         doReturn(mConfigReadWriteHelper)
215                 .when(mMockDeps)
216                 .newPersistableBundleLockingReadWriteHelper(any());
217 
218         // Setup VCN instance generation
219         doAnswer((invocation) -> {
220             // Mock-within a doAnswer is safe, because it doesn't actually run nested.
221             return mock(Vcn.class);
222         }).when(mMockDeps).newVcn(any(), any(), any(), any(), any());
223 
224         final PersistableBundle bundle =
225                 PersistableBundleUtils.fromMap(
226                         TEST_VCN_CONFIG_MAP,
227                         PersistableBundleUtils::fromParcelUuid,
228                         VcnConfig::toPersistableBundle);
229         doReturn(bundle).when(mConfigReadWriteHelper).readFromDisk();
230 
231         setupMockedCarrierPrivilege(true);
232         mVcnMgmtSvc = new VcnManagementService(mMockContext, mMockDeps);
233         setupActiveSubscription(TEST_UUID_1);
234 
235         doReturn(mMockIBinder).when(mMockPolicyListener).asBinder();
236         doReturn(mMockIBinder).when(mMockStatusCallback).asBinder();
237 
238         // Make sure the profiles are loaded.
239         mTestLooper.dispatchAll();
240     }
241 
242     @Before
setUp()243     public void setUp() {
244         doNothing()
245                 .when(mMockContext)
246                 .enforceCallingOrSelfPermission(
247                         eq(android.Manifest.permission.NETWORK_FACTORY), any());
248     }
249 
setupMockedCarrierPrivilege(boolean isPrivileged)250     private void setupMockedCarrierPrivilege(boolean isPrivileged) {
251         doReturn(Collections.singletonList(TEST_SUBSCRIPTION_INFO))
252                 .when(mSubMgr)
253                 .getSubscriptionsInGroup(any());
254         doReturn(mTelMgr)
255                 .when(mTelMgr)
256                 .createForSubscriptionId(eq(TEST_SUBSCRIPTION_INFO.getSubscriptionId()));
257         doReturn(isPrivileged
258                         ? CARRIER_PRIVILEGE_STATUS_HAS_ACCESS
259                         : CARRIER_PRIVILEGE_STATUS_NO_ACCESS)
260                 .when(mTelMgr)
261                 .checkCarrierPrivilegesForPackage(eq(TEST_PACKAGE_NAME));
262     }
263 
264     @Test
testSystemReady()265     public void testSystemReady() throws Exception {
266         mVcnMgmtSvc.systemReady();
267 
268         verify(mConnMgr).registerNetworkProvider(any(VcnNetworkProvider.class));
269         verify(mSubscriptionTracker).register();
270         verify(mConnMgr)
271                 .registerNetworkCallback(
272                         eq(new NetworkRequest.Builder().clearCapabilities().build()),
273                         any(NetworkCallback.class));
274     }
275 
276     @Test
testNonSystemServerRealConfigFileAccessPermission()277     public void testNonSystemServerRealConfigFileAccessPermission() throws Exception {
278         // Attempt to build a real instance of the dependencies, and verify we cannot write to the
279         // file.
280         VcnManagementService.Dependencies deps = new VcnManagementService.Dependencies();
281         PersistableBundleUtils.LockingReadWriteHelper configReadWriteHelper =
282                 deps.newPersistableBundleLockingReadWriteHelper(
283                         VcnManagementService.VCN_CONFIG_FILE);
284 
285         // Even tests should not be able to read/write configs from disk; SELinux policies restrict
286         // it to only the system server.
287         // Reading config should always return null since the file "does not exist", and writing
288         // should throw an IOException.
289         assertNull(configReadWriteHelper.readFromDisk());
290 
291         try {
292             configReadWriteHelper.writeToDisk(new PersistableBundle());
293             fail("Expected IOException due to SELinux policy");
294         } catch (FileNotFoundException expected) {
295         }
296     }
297 
298     @Test
testLoadVcnConfigsOnStartup()299     public void testLoadVcnConfigsOnStartup() throws Exception {
300         mTestLooper.dispatchAll();
301 
302         assertEquals(TEST_VCN_CONFIG_MAP, mVcnMgmtSvc.getConfigs());
303         verify(mConfigReadWriteHelper).readFromDisk();
304     }
305 
triggerSubscriptionTrackerCbAndGetSnapshot( ParcelUuid activeDataSubGrp, Set<ParcelUuid> activeSubscriptionGroups)306     private TelephonySubscriptionSnapshot triggerSubscriptionTrackerCbAndGetSnapshot(
307             ParcelUuid activeDataSubGrp, Set<ParcelUuid> activeSubscriptionGroups) {
308         return triggerSubscriptionTrackerCbAndGetSnapshot(
309                 activeDataSubGrp, activeSubscriptionGroups, Collections.emptyMap());
310     }
311 
triggerSubscriptionTrackerCbAndGetSnapshot( ParcelUuid activeDataSubGrp, Set<ParcelUuid> activeSubscriptionGroups, Map<Integer, ParcelUuid> subIdToGroupMap)312     private TelephonySubscriptionSnapshot triggerSubscriptionTrackerCbAndGetSnapshot(
313             ParcelUuid activeDataSubGrp,
314             Set<ParcelUuid> activeSubscriptionGroups,
315             Map<Integer, ParcelUuid> subIdToGroupMap) {
316         return triggerSubscriptionTrackerCbAndGetSnapshot(
317                 activeDataSubGrp,
318                 activeSubscriptionGroups,
319                 subIdToGroupMap,
320                 true /* hasCarrierPrivileges */);
321     }
322 
triggerSubscriptionTrackerCbAndGetSnapshot( ParcelUuid activeDataSubGrp, Set<ParcelUuid> activeSubscriptionGroups, Map<Integer, ParcelUuid> subIdToGroupMap, boolean hasCarrierPrivileges)323     private TelephonySubscriptionSnapshot triggerSubscriptionTrackerCbAndGetSnapshot(
324             ParcelUuid activeDataSubGrp,
325             Set<ParcelUuid> activeSubscriptionGroups,
326             Map<Integer, ParcelUuid> subIdToGroupMap,
327             boolean hasCarrierPrivileges) {
328         return triggerSubscriptionTrackerCbAndGetSnapshot(
329                 TEST_SUBSCRIPTION_ID,
330                 activeDataSubGrp,
331                 activeSubscriptionGroups,
332                 subIdToGroupMap,
333                 hasCarrierPrivileges);
334     }
335 
triggerSubscriptionTrackerCbAndGetSnapshot( int activeDataSubId, ParcelUuid activeDataSubGrp, Set<ParcelUuid> activeSubscriptionGroups, Map<Integer, ParcelUuid> subIdToGroupMap, boolean hasCarrierPrivileges)336     private TelephonySubscriptionSnapshot triggerSubscriptionTrackerCbAndGetSnapshot(
337             int activeDataSubId,
338             ParcelUuid activeDataSubGrp,
339             Set<ParcelUuid> activeSubscriptionGroups,
340             Map<Integer, ParcelUuid> subIdToGroupMap,
341             boolean hasCarrierPrivileges) {
342         final TelephonySubscriptionSnapshot snapshot =
343                 buildSubscriptionSnapshot(
344                         activeDataSubId,
345                         activeDataSubGrp,
346                         activeSubscriptionGroups,
347                         subIdToGroupMap,
348                         hasCarrierPrivileges);
349 
350         final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback();
351         cb.onNewSnapshot(snapshot);
352 
353         return snapshot;
354     }
355 
buildSubscriptionSnapshot( int activeDataSubId, ParcelUuid activeDataSubGrp, Set<ParcelUuid> activeSubscriptionGroups, Map<Integer, ParcelUuid> subIdToGroupMap, boolean hasCarrierPrivileges)356     private TelephonySubscriptionSnapshot buildSubscriptionSnapshot(
357             int activeDataSubId,
358             ParcelUuid activeDataSubGrp,
359             Set<ParcelUuid> activeSubscriptionGroups,
360             Map<Integer, ParcelUuid> subIdToGroupMap,
361             boolean hasCarrierPrivileges) {
362         final TelephonySubscriptionSnapshot snapshot = mock(TelephonySubscriptionSnapshot.class);
363         doReturn(activeSubscriptionGroups).when(snapshot).getActiveSubscriptionGroups();
364         doReturn(activeDataSubGrp).when(snapshot).getActiveDataSubscriptionGroup();
365         doReturn(activeDataSubId).when(snapshot).getActiveDataSubscriptionId();
366 
367         final Set<String> privilegedPackages =
368                 (activeSubscriptionGroups == null || activeSubscriptionGroups.isEmpty())
369                         ? Collections.emptySet()
370                         : Collections.singleton(TEST_PACKAGE_NAME);
371         doReturn(hasCarrierPrivileges)
372                 .when(snapshot)
373                 .packageHasPermissionsForSubscriptionGroup(
374                         argThat(val -> activeSubscriptionGroups.contains(val)),
375                         eq(TEST_PACKAGE_NAME));
376 
377         doAnswer(invocation -> {
378             return subIdToGroupMap.get(invocation.getArgument(0));
379         }).when(snapshot).getGroupForSubId(anyInt());
380 
381         doAnswer(invocation -> {
382             final ParcelUuid subGrp = invocation.getArgument(0);
383             final Set<Integer> subIds = new ArraySet<>();
384             for (Entry<Integer, ParcelUuid> entry : subIdToGroupMap.entrySet()) {
385                 if (entry.getValue().equals(subGrp)) {
386                     subIds.add(entry.getKey());
387                 }
388             }
389             return subIds;
390         }).when(snapshot).getAllSubIdsInGroup(any());
391 
392         return snapshot;
393     }
394 
setupActiveSubscription(ParcelUuid activeDataSubGrp)395     private void setupActiveSubscription(ParcelUuid activeDataSubGrp) {
396         mVcnMgmtSvc.setLastSnapshot(
397                 buildSubscriptionSnapshot(
398                         TEST_SUBSCRIPTION_ID,
399                         activeDataSubGrp,
400                         Collections.emptySet(),
401                         Collections.emptyMap(),
402                         true /* hasCarrierPrivileges */));
403     }
404 
getTelephonySubscriptionTrackerCallback()405     private TelephonySubscriptionTrackerCallback getTelephonySubscriptionTrackerCallback() {
406         final ArgumentCaptor<TelephonySubscriptionTrackerCallback> captor =
407                 ArgumentCaptor.forClass(TelephonySubscriptionTrackerCallback.class);
408         verify(mMockDeps)
409                 .newTelephonySubscriptionTracker(
410                         eq(mMockContext), eq(mTestLooper.getLooper()), captor.capture());
411         return captor.getValue();
412     }
413 
getPackageChangeReceiver()414     private BroadcastReceiver getPackageChangeReceiver() {
415         final ArgumentCaptor<BroadcastReceiver> captor =
416                 ArgumentCaptor.forClass(BroadcastReceiver.class);
417         verify(mMockContext).registerReceiver(captor.capture(), any(), any(), any());
418         return captor.getValue();
419     }
420 
startAndGetVcnInstance(ParcelUuid uuid)421     private Vcn startAndGetVcnInstance(ParcelUuid uuid) {
422         mVcnMgmtSvc.setVcnConfig(uuid, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
423         return mVcnMgmtSvc.getAllVcns().get(uuid);
424     }
425 
426     @Test
testTelephonyNetworkTrackerCallbackStartsInstances()427     public void testTelephonyNetworkTrackerCallbackStartsInstances() throws Exception {
428         // Add a record for a non-active SIM
429         mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
430 
431         TelephonySubscriptionSnapshot snapshot =
432                 triggerSubscriptionTrackerCbAndGetSnapshot(
433                         TEST_UUID_1, new ArraySet<>(Arrays.asList(TEST_UUID_1, TEST_UUID_2)));
434         verify(mMockDeps)
435                 .newVcnContext(
436                         eq(mMockContext),
437                         eq(mTestLooper.getLooper()),
438                         any(VcnNetworkProvider.class),
439                         anyBoolean());
440 
441         // Verify that only the VCN for the active data SIM was started.
442         verify(mMockDeps)
443                 .newVcn(eq(mVcnContext), eq(TEST_UUID_1), eq(TEST_VCN_CONFIG), eq(snapshot), any());
444         verify(mMockDeps, never())
445                 .newVcn(eq(mVcnContext), eq(TEST_UUID_2), eq(TEST_VCN_CONFIG), eq(snapshot), any());
446     }
447 
448     @Test
testTelephonyNetworkTrackerCallbackSwitchingActiveDataStartsAndStopsInstances()449     public void testTelephonyNetworkTrackerCallbackSwitchingActiveDataStartsAndStopsInstances()
450             throws Exception {
451         // Add a record for a non-active SIM
452         mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
453         final Vcn vcn = startAndGetVcnInstance(TEST_UUID_1);
454 
455         TelephonySubscriptionSnapshot snapshot =
456                 triggerSubscriptionTrackerCbAndGetSnapshot(
457                         TEST_UUID_2, new ArraySet<>(Arrays.asList(TEST_UUID_1, TEST_UUID_2)));
458 
459         // Verify that a new VCN for UUID_2 was started, and the old instance was torn down
460         // immediately
461         verify(mMockDeps)
462                 .newVcn(eq(mVcnContext), eq(TEST_UUID_2), eq(TEST_VCN_CONFIG), eq(snapshot), any());
463         verify(vcn).teardownAsynchronously();
464         assertEquals(1, mVcnMgmtSvc.getAllVcns().size());
465         assertFalse(mVcnMgmtSvc.getAllVcns().containsKey(TEST_UUID_1));
466         assertTrue(mVcnMgmtSvc.getAllVcns().containsKey(TEST_UUID_2));
467     }
468 
469     @Test
testTelephonyNetworkTrackerCallbackStopsInstances()470     public void testTelephonyNetworkTrackerCallbackStopsInstances() throws Exception {
471         setupActiveSubscription(TEST_UUID_2);
472 
473         final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback();
474         final Vcn vcn = startAndGetVcnInstance(TEST_UUID_2);
475         mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
476 
477         triggerSubscriptionTrackerCbAndGetSnapshot(null, Collections.emptySet());
478 
479         // Verify teardown after delay
480         mTestLooper.moveTimeForward(VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS);
481         mTestLooper.dispatchAll();
482         verify(vcn).teardownAsynchronously();
483         verify(mMockPolicyListener).onPolicyChanged();
484     }
485 
486     @Test
testTelephonyNetworkTrackerCallbackSwitchToNewSubscriptionImmediatelyTearsDown()487     public void testTelephonyNetworkTrackerCallbackSwitchToNewSubscriptionImmediatelyTearsDown()
488             throws Exception {
489         setupActiveSubscription(TEST_UUID_2);
490 
491         final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback();
492         final Vcn vcn = startAndGetVcnInstance(TEST_UUID_2);
493 
494         // Simulate switch to different default data subscription that does not have a VCN.
495         triggerSubscriptionTrackerCbAndGetSnapshot(
496                 TEST_SUBSCRIPTION_ID,
497                 null /* activeDataSubscriptionGroup */,
498                 Collections.emptySet(),
499                 Collections.emptyMap(),
500                 false /* hasCarrierPrivileges */);
501         mTestLooper.dispatchAll();
502 
503         verify(vcn).teardownAsynchronously();
504         assertEquals(0, mVcnMgmtSvc.getAllVcns().size());
505     }
506 
507     /**
508      * Tests an intermediate state where carrier privileges are marked as lost before active data
509      * subId changes during a SIM ejection.
510      *
511      * <p>The expected outcome is that the VCN is torn down after a delay, as opposed to
512      * immediately.
513      */
514     @Test
testTelephonyNetworkTrackerCallbackLostCarrierPrivilegesBeforeActiveDataSubChanges()515     public void testTelephonyNetworkTrackerCallbackLostCarrierPrivilegesBeforeActiveDataSubChanges()
516             throws Exception {
517         setupActiveSubscription(TEST_UUID_2);
518 
519         final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback();
520         final Vcn vcn = startAndGetVcnInstance(TEST_UUID_2);
521 
522         // Simulate privileges lost
523         triggerSubscriptionTrackerCbAndGetSnapshot(
524                 TEST_SUBSCRIPTION_ID,
525                 TEST_UUID_2,
526                 Collections.emptySet(),
527                 Collections.emptyMap(),
528                 false /* hasCarrierPrivileges */);
529 
530         // Verify teardown after delay
531         mTestLooper.moveTimeForward(VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS);
532         mTestLooper.dispatchAll();
533         verify(vcn).teardownAsynchronously();
534     }
535 
536     @Test
testTelephonyNetworkTrackerCallbackSimSwitchesDoNotKillVcnInstances()537     public void testTelephonyNetworkTrackerCallbackSimSwitchesDoNotKillVcnInstances()
538             throws Exception {
539         setupActiveSubscription(TEST_UUID_2);
540 
541         final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback();
542         final Vcn vcn = startAndGetVcnInstance(TEST_UUID_2);
543 
544         // Simulate SIM unloaded
545         triggerSubscriptionTrackerCbAndGetSnapshot(
546                 INVALID_SUBSCRIPTION_ID,
547                 null /* activeDataSubscriptionGroup */,
548                 Collections.emptySet(),
549                 Collections.emptyMap(),
550                 false /* hasCarrierPrivileges */);
551 
552         // Simulate new SIM loaded right during teardown delay.
553         mTestLooper.moveTimeForward(
554                 VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS / 2);
555         mTestLooper.dispatchAll();
556         triggerSubscriptionTrackerCbAndGetSnapshot(TEST_UUID_2, Collections.singleton(TEST_UUID_2));
557 
558         // Verify that even after the full timeout duration, the VCN instance is not torn down
559         mTestLooper.moveTimeForward(VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS);
560         mTestLooper.dispatchAll();
561         verify(vcn, never()).teardownAsynchronously();
562     }
563 
564     @Test
testTelephonyNetworkTrackerCallbackDoesNotKillNewVcnInstances()565     public void testTelephonyNetworkTrackerCallbackDoesNotKillNewVcnInstances() throws Exception {
566         setupActiveSubscription(TEST_UUID_2);
567 
568         final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback();
569         final Vcn oldInstance = startAndGetVcnInstance(TEST_UUID_2);
570 
571         // Simulate SIM unloaded
572         triggerSubscriptionTrackerCbAndGetSnapshot(null, Collections.emptySet());
573 
574         // Config cleared, SIM reloaded & config re-added right before teardown delay, staring new
575         // vcnInstance.
576         mTestLooper.moveTimeForward(
577                 VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS / 2);
578         mTestLooper.dispatchAll();
579         mVcnMgmtSvc.clearVcnConfig(TEST_UUID_2, TEST_PACKAGE_NAME);
580         triggerSubscriptionTrackerCbAndGetSnapshot(TEST_UUID_2, Collections.singleton(TEST_UUID_2));
581         final Vcn newInstance = startAndGetVcnInstance(TEST_UUID_2);
582 
583         // Verify that new instance was different, and the old one was torn down
584         assertTrue(oldInstance != newInstance);
585         verify(oldInstance).teardownAsynchronously();
586 
587         // Verify that even after the full timeout duration, the new VCN instance is not torn down
588         mTestLooper.moveTimeForward(VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS);
589         mTestLooper.dispatchAll();
590         verify(newInstance, never()).teardownAsynchronously();
591     }
592 
593     @Test
testPackageChangeListenerRegistered()594     public void testPackageChangeListenerRegistered() throws Exception {
595         verify(mMockContext).registerReceiver(any(BroadcastReceiver.class), argThat(filter -> {
596             return filter.hasAction(Intent.ACTION_PACKAGE_ADDED)
597                     && filter.hasAction(Intent.ACTION_PACKAGE_REPLACED)
598                     && filter.hasAction(Intent.ACTION_PACKAGE_REMOVED);
599         }), any(), any());
600     }
601 
602     @Test
testPackageChangeListener_packageAdded()603     public void testPackageChangeListener_packageAdded() throws Exception {
604         final BroadcastReceiver receiver = getPackageChangeReceiver();
605 
606         verify(mMockContext).registerReceiver(any(), argThat(filter -> {
607             return filter.hasAction(Intent.ACTION_PACKAGE_ADDED)
608                     && filter.hasAction(Intent.ACTION_PACKAGE_REPLACED)
609                     && filter.hasAction(Intent.ACTION_PACKAGE_REMOVED);
610         }), any(), any());
611 
612         receiver.onReceive(mMockContext, new Intent(Intent.ACTION_PACKAGE_ADDED));
613         verify(mSubscriptionTracker).handleSubscriptionsChanged();
614     }
615 
616     @Test
testPackageChangeListener_packageRemoved()617     public void testPackageChangeListener_packageRemoved() throws Exception {
618         final BroadcastReceiver receiver = getPackageChangeReceiver();
619 
620         verify(mMockContext).registerReceiver(any(), argThat(filter -> {
621             return filter.hasAction(Intent.ACTION_PACKAGE_REMOVED)
622                     && filter.hasAction(Intent.ACTION_PACKAGE_REMOVED);
623         }), any(), any());
624 
625         receiver.onReceive(mMockContext, new Intent(Intent.ACTION_PACKAGE_REMOVED));
626         verify(mSubscriptionTracker).handleSubscriptionsChanged();
627     }
628 
629     @Test
testSetVcnConfigRequiresNonSystemServer()630     public void testSetVcnConfigRequiresNonSystemServer() throws Exception {
631         doReturn(Process.SYSTEM_UID).when(mMockDeps).getBinderCallingUid();
632 
633         try {
634             mVcnMgmtSvc.setVcnConfig(TEST_UUID_1, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
635             fail("Expected IllegalStateException exception for system server");
636         } catch (IllegalStateException expected) {
637         }
638     }
639 
640     @Test
testSetVcnConfigRequiresSystemUser()641     public void testSetVcnConfigRequiresSystemUser() throws Exception {
642         doReturn(UserHandle.getUid(UserHandle.MIN_SECONDARY_USER_ID, TEST_UID))
643                 .when(mMockDeps)
644                 .getBinderCallingUid();
645 
646         try {
647             mVcnMgmtSvc.setVcnConfig(TEST_UUID_1, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
648             fail("Expected security exception for non system user");
649         } catch (SecurityException expected) {
650             verify(mMockPolicyListener, never()).onPolicyChanged();
651         }
652     }
653 
654     @Test
testSetVcnConfigRequiresCarrierPrivileges()655     public void testSetVcnConfigRequiresCarrierPrivileges() throws Exception {
656         setupMockedCarrierPrivilege(false);
657 
658         try {
659             mVcnMgmtSvc.setVcnConfig(TEST_UUID_1, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
660             fail("Expected security exception for missing carrier privileges");
661         } catch (SecurityException expected) {
662             verify(mMockPolicyListener, never()).onPolicyChanged();
663         }
664     }
665 
666     @Test
testSetVcnConfigMismatchedPackages()667     public void testSetVcnConfigMismatchedPackages() throws Exception {
668         try {
669             mVcnMgmtSvc.setVcnConfig(TEST_UUID_1, TEST_VCN_CONFIG, "IncorrectPackage");
670             fail("Expected exception due to mismatched packages in config and method call");
671         } catch (IllegalArgumentException expected) {
672             verify(mMockPolicyListener, never()).onPolicyChanged();
673         }
674     }
675 
676     @Test
testSetVcnConfig()677     public void testSetVcnConfig() throws Exception {
678         // Use a different UUID to simulate a new VCN config.
679         mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
680         assertEquals(TEST_VCN_CONFIG, mVcnMgmtSvc.getConfigs().get(TEST_UUID_2));
681         verify(mConfigReadWriteHelper).writeToDisk(any(PersistableBundle.class));
682     }
683 
684     @Test
testSetVcnConfigNonActiveSimDoesNotStartVcn()685     public void testSetVcnConfigNonActiveSimDoesNotStartVcn() throws Exception {
686         // Use a different UUID to simulate a new VCN config.
687         mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
688         assertEquals(TEST_VCN_CONFIG, mVcnMgmtSvc.getConfigs().get(TEST_UUID_2));
689         verify(mConfigReadWriteHelper).writeToDisk(any(PersistableBundle.class));
690 
691         verify(mMockDeps, never()).newVcn(any(), any(), any(), any(), any());
692     }
693 
694     @Test
testSetVcnConfigActiveSimTearsDownExistingVcnsImmediately()695     public void testSetVcnConfigActiveSimTearsDownExistingVcnsImmediately() throws Exception {
696         final Vcn vcn = startAndGetVcnInstance(TEST_UUID_1);
697 
698         // Use a different UUID to simulate a new VCN config.
699         setupActiveSubscription(TEST_UUID_2);
700         mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
701 
702         verify(mMockDeps, times(2)).newVcn(any(), any(), any(), any(), any());
703         verify(vcn).teardownAsynchronously();
704         assertEquals(1, mVcnMgmtSvc.getAllVcns().size());
705         assertFalse(mVcnMgmtSvc.getAllVcns().containsKey(TEST_UUID_1));
706         assertTrue(mVcnMgmtSvc.getAllVcns().containsKey(TEST_UUID_2));
707     }
708 
709     @Test
testSetVcnConfigTestModeRequiresPermission()710     public void testSetVcnConfigTestModeRequiresPermission() throws Exception {
711         doThrow(new SecurityException("Requires MANAGE_TEST_NETWORKS"))
712                 .when(mMockContext)
713                 .enforceCallingPermission(
714                         eq(android.Manifest.permission.MANAGE_TEST_NETWORKS), any());
715 
716         final VcnConfig vcnConfig =
717                 new VcnConfig.Builder(mMockContext)
718                         .addGatewayConnectionConfig(
719                                 VcnGatewayConnectionConfigTest.buildTestConfig())
720                         .setIsTestModeProfile()
721                         .build();
722 
723         try {
724             mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, vcnConfig, TEST_PACKAGE_NAME);
725             fail("Expected exception due to using test-mode without permission");
726         } catch (SecurityException e) {
727             verify(mMockPolicyListener, never()).onPolicyChanged();
728         }
729     }
730 
731     @Test
testSetVcnConfigNotifiesStatusCallback()732     public void testSetVcnConfigNotifiesStatusCallback() throws Exception {
733         triggerSubscriptionTrackerCbAndGetSnapshot(TEST_UUID_2, Collections.singleton(TEST_UUID_2));
734 
735         mVcnMgmtSvc.registerVcnStatusCallback(TEST_UUID_2, mMockStatusCallback, TEST_PACKAGE_NAME);
736         verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_NOT_CONFIGURED);
737 
738         // Use a different UUID to simulate a new VCN config.
739         mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
740 
741         verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_ACTIVE);
742     }
743 
744     @Test
testClearVcnConfigRequiresNonSystemServer()745     public void testClearVcnConfigRequiresNonSystemServer() throws Exception {
746         doReturn(Process.SYSTEM_UID).when(mMockDeps).getBinderCallingUid();
747 
748         try {
749             mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1, TEST_PACKAGE_NAME);
750             fail("Expected IllegalStateException exception for system server");
751         } catch (IllegalStateException expected) {
752         }
753     }
754 
755     @Test
testClearVcnConfigRequiresSystemUser()756     public void testClearVcnConfigRequiresSystemUser() throws Exception {
757         doReturn(UserHandle.getUid(UserHandle.MIN_SECONDARY_USER_ID, TEST_UID))
758                 .when(mMockDeps)
759                 .getBinderCallingUid();
760 
761         try {
762             mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1, TEST_PACKAGE_NAME);
763             fail("Expected security exception for non system user");
764         } catch (SecurityException expected) {
765         }
766     }
767 
768     @Test
testClearVcnConfigRequiresCarrierPrivileges()769     public void testClearVcnConfigRequiresCarrierPrivileges() throws Exception {
770         setupMockedCarrierPrivilege(false);
771 
772         try {
773             mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1, TEST_PACKAGE_NAME);
774             fail("Expected security exception for missing carrier privileges");
775         } catch (SecurityException expected) {
776         }
777     }
778 
779     @Test
testClearVcnConfigMismatchedPackages()780     public void testClearVcnConfigMismatchedPackages() throws Exception {
781         try {
782             mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1, "IncorrectPackage");
783             fail("Expected security exception due to mismatched packages");
784         } catch (SecurityException expected) {
785         }
786     }
787 
788     @Test
testClearVcnConfig()789     public void testClearVcnConfig() throws Exception {
790         mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1, TEST_PACKAGE_NAME);
791         assertTrue(mVcnMgmtSvc.getConfigs().isEmpty());
792         verify(mConfigReadWriteHelper).writeToDisk(any(PersistableBundle.class));
793     }
794 
795     @Test
testClearVcnConfigNotifiesStatusCallback()796     public void testClearVcnConfigNotifiesStatusCallback() throws Exception {
797         setupSubscriptionAndStartVcn(TEST_SUBSCRIPTION_ID, TEST_UUID_2, true /* isActive */);
798         mVcnMgmtSvc.registerVcnStatusCallback(TEST_UUID_2, mMockStatusCallback, TEST_PACKAGE_NAME);
799         verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_ACTIVE);
800 
801         mVcnMgmtSvc.clearVcnConfig(TEST_UUID_2, TEST_PACKAGE_NAME);
802 
803         verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_NOT_CONFIGURED);
804     }
805 
806     @Test
testSetVcnConfigClearVcnConfigStartsUpdatesAndTearsDownVcns()807     public void testSetVcnConfigClearVcnConfigStartsUpdatesAndTearsDownVcns() throws Exception {
808         setupActiveSubscription(TEST_UUID_2);
809 
810         // Use a different UUID to simulate a new VCN config.
811         mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
812         final Map<ParcelUuid, Vcn> vcnInstances = mVcnMgmtSvc.getAllVcns();
813         final Vcn vcnInstance = vcnInstances.get(TEST_UUID_2);
814         assertEquals(1, vcnInstances.size());
815         assertEquals(TEST_VCN_CONFIG, mVcnMgmtSvc.getConfigs().get(TEST_UUID_2));
816         verify(mConfigReadWriteHelper).writeToDisk(any(PersistableBundle.class));
817 
818         // Verify Vcn is started
819         verify(mMockDeps)
820                 .newVcn(eq(mVcnContext), eq(TEST_UUID_2), eq(TEST_VCN_CONFIG), any(), any());
821 
822         // Verify Vcn is updated if it was previously started
823         mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
824         verify(vcnInstance).updateConfig(TEST_VCN_CONFIG);
825 
826         // Verify Vcn is stopped if it was already started
827         mVcnMgmtSvc.clearVcnConfig(TEST_UUID_2, TEST_PACKAGE_NAME);
828         verify(vcnInstance).teardownAsynchronously();
829     }
830 
831     @Test
testGetConfiguredSubscriptionGroupsRequiresSystemUser()832     public void testGetConfiguredSubscriptionGroupsRequiresSystemUser() throws Exception {
833         doReturn(UserHandle.getUid(UserHandle.MIN_SECONDARY_USER_ID, TEST_UID))
834                 .when(mMockDeps)
835                 .getBinderCallingUid();
836 
837         try {
838             mVcnMgmtSvc.getConfiguredSubscriptionGroups(TEST_PACKAGE_NAME);
839             fail("Expected security exception for non system user");
840         } catch (SecurityException expected) {
841         }
842     }
843 
844     @Test
testGetConfiguredSubscriptionGroupsMismatchedPackages()845     public void testGetConfiguredSubscriptionGroupsMismatchedPackages() throws Exception {
846         final String badPackage = "IncorrectPackage";
847         doThrow(new SecurityException()).when(mAppOpsMgr).checkPackage(TEST_UID, badPackage);
848 
849         try {
850             mVcnMgmtSvc.getConfiguredSubscriptionGroups(badPackage);
851             fail("Expected security exception due to mismatched packages");
852         } catch (SecurityException expected) {
853         }
854     }
855 
856     @Test
testGetConfiguredSubscriptionGroups()857     public void testGetConfiguredSubscriptionGroups() throws Exception {
858         mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
859 
860         // Assert that if both UUID 1 and 2 are provisioned, the caller only gets ones that they are
861         // privileged for.
862         triggerSubscriptionTrackerCbAndGetSnapshot(TEST_UUID_1, Collections.singleton(TEST_UUID_1));
863         final List<ParcelUuid> subGrps =
864                 mVcnMgmtSvc.getConfiguredSubscriptionGroups(TEST_PACKAGE_NAME);
865         assertEquals(Collections.singletonList(TEST_UUID_1), subGrps);
866     }
867 
868     @Test
testAddVcnUnderlyingNetworkPolicyListener()869     public void testAddVcnUnderlyingNetworkPolicyListener() throws Exception {
870         mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
871 
872         verify(mMockIBinder).linkToDeath(any(), anyInt());
873     }
874 
875     @Test(expected = SecurityException.class)
testAddVcnUnderlyingNetworkPolicyListenerInvalidPermission()876     public void testAddVcnUnderlyingNetworkPolicyListenerInvalidPermission() {
877         doReturn(PackageManager.PERMISSION_DENIED)
878                 .when(mMockContext)
879                 .checkCallingOrSelfPermission(any());
880 
881         mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
882     }
883 
884     @Test
testRemoveVcnUnderlyingNetworkPolicyListener()885     public void testRemoveVcnUnderlyingNetworkPolicyListener() {
886         mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
887 
888         mVcnMgmtSvc.removeVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
889     }
890 
891     @Test(expected = SecurityException.class)
testRemoveVcnUnderlyingNetworkPolicyListenerInvalidPermission()892     public void testRemoveVcnUnderlyingNetworkPolicyListenerInvalidPermission() {
893         doReturn(PackageManager.PERMISSION_DENIED)
894                 .when(mMockContext)
895                 .checkCallingOrSelfPermission(any());
896 
897         mVcnMgmtSvc.removeVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
898     }
899 
900     @Test
testRemoveVcnUnderlyingNetworkPolicyListenerNeverRegistered()901     public void testRemoveVcnUnderlyingNetworkPolicyListenerNeverRegistered() {
902         mVcnMgmtSvc.removeVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
903     }
904 
verifyMergedNetworkCapabilities( NetworkCapabilities mergedCapabilities, int transportType, boolean isVcnManaged, boolean isRestricted)905     private void verifyMergedNetworkCapabilities(
906             NetworkCapabilities mergedCapabilities,
907             int transportType,
908             boolean isVcnManaged,
909             boolean isRestricted) {
910         assertTrue(mergedCapabilities.hasTransport(transportType));
911         assertEquals(
912                 !isVcnManaged,
913                 mergedCapabilities.hasCapability(
914                         NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED));
915         assertEquals(
916                 !isRestricted,
917                 mergedCapabilities.hasCapability(
918                         NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED));
919     }
920 
setupSubscriptionAndStartVcn(int subId, ParcelUuid subGrp, boolean isVcnActive)921     private void setupSubscriptionAndStartVcn(int subId, ParcelUuid subGrp, boolean isVcnActive) {
922         setupSubscriptionAndStartVcn(subId, subGrp, isVcnActive, true /* hasCarrierPrivileges */);
923     }
924 
setupSubscriptionAndStartVcn( int subId, ParcelUuid subGrp, boolean isVcnActive, boolean hasCarrierPrivileges)925     private void setupSubscriptionAndStartVcn(
926             int subId, ParcelUuid subGrp, boolean isVcnActive, boolean hasCarrierPrivileges) {
927         mVcnMgmtSvc.systemReady();
928         triggerSubscriptionTrackerCbAndGetSnapshot(
929                 subGrp,
930                 Collections.singleton(subGrp),
931                 Collections.singletonMap(subId, subGrp),
932                 hasCarrierPrivileges);
933 
934         final Vcn vcn = startAndGetVcnInstance(subGrp);
935         doReturn(isVcnActive ? VCN_STATUS_CODE_ACTIVE : VCN_STATUS_CODE_SAFE_MODE)
936                 .when(vcn)
937                 .getStatus();
938     }
939 
getNetworkCapabilitiesBuilderForTransport( int subId, int transport)940     private NetworkCapabilities.Builder getNetworkCapabilitiesBuilderForTransport(
941             int subId, int transport) {
942         final NetworkCapabilities.Builder ncBuilder =
943                 new NetworkCapabilities.Builder()
944                         .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
945                         .addTransportType(transport);
946         if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
947             ncBuilder.setSubscriptionIds(Collections.singleton(subId));
948         }
949 
950         return ncBuilder;
951     }
952 
startVcnAndGetPolicyForTransport( int subId, ParcelUuid subGrp, boolean isVcnActive, int transport)953     private VcnUnderlyingNetworkPolicy startVcnAndGetPolicyForTransport(
954             int subId, ParcelUuid subGrp, boolean isVcnActive, int transport) {
955         setupSubscriptionAndStartVcn(subId, subGrp, isVcnActive);
956 
957         return mVcnMgmtSvc.getUnderlyingNetworkPolicy(
958                 getNetworkCapabilitiesBuilderForTransport(subId, transport).build(),
959                 new LinkProperties());
960     }
961 
962     @Test
testGetUnderlyingNetworkPolicyCellular()963     public void testGetUnderlyingNetworkPolicyCellular() throws Exception {
964         final VcnUnderlyingNetworkPolicy policy =
965                 startVcnAndGetPolicyForTransport(
966                         TEST_SUBSCRIPTION_ID, TEST_UUID_2, true /* isActive */, TRANSPORT_CELLULAR);
967 
968         assertFalse(policy.isTeardownRequested());
969         verifyMergedNetworkCapabilities(
970                 policy.getMergedNetworkCapabilities(),
971                 TRANSPORT_CELLULAR,
972                 true /* isVcnManaged */,
973                 false /* isRestricted */);
974     }
975 
976     @Test
testGetUnderlyingNetworkPolicyCellular_safeMode()977     public void testGetUnderlyingNetworkPolicyCellular_safeMode() throws Exception {
978         final VcnUnderlyingNetworkPolicy policy =
979                 startVcnAndGetPolicyForTransport(
980                         TEST_SUBSCRIPTION_ID,
981                         TEST_UUID_2,
982                         false /* isActive */,
983                         TRANSPORT_CELLULAR);
984 
985         assertFalse(policy.isTeardownRequested());
986         verifyMergedNetworkCapabilities(
987                 policy.getMergedNetworkCapabilities(),
988                 NetworkCapabilities.TRANSPORT_CELLULAR,
989                 false /* isVcnManaged */,
990                 false /* isRestricted */);
991     }
992 
993     @Test
testGetUnderlyingNetworkPolicyWifi()994     public void testGetUnderlyingNetworkPolicyWifi() throws Exception {
995         final VcnUnderlyingNetworkPolicy policy =
996                 startVcnAndGetPolicyForTransport(
997                         TEST_SUBSCRIPTION_ID, TEST_UUID_2, true /* isActive */, TRANSPORT_WIFI);
998 
999         assertFalse(policy.isTeardownRequested());
1000         verifyMergedNetworkCapabilities(
1001                 policy.getMergedNetworkCapabilities(),
1002                 NetworkCapabilities.TRANSPORT_WIFI,
1003                 true /* isVcnManaged */,
1004                 true /* isRestricted */);
1005     }
1006 
1007     @Test
testGetUnderlyingNetworkPolicyVcnWifi_safeMode()1008     public void testGetUnderlyingNetworkPolicyVcnWifi_safeMode() throws Exception {
1009         final VcnUnderlyingNetworkPolicy policy =
1010                 startVcnAndGetPolicyForTransport(
1011                         TEST_SUBSCRIPTION_ID, TEST_UUID_2, false /* isActive */, TRANSPORT_WIFI);
1012 
1013         assertFalse(policy.isTeardownRequested());
1014         verifyMergedNetworkCapabilities(
1015                 policy.getMergedNetworkCapabilities(),
1016                 NetworkCapabilities.TRANSPORT_WIFI,
1017                 false /* isVcnManaged */,
1018                 true /* isRestricted */);
1019     }
1020 
setupTrackedCarrierWifiNetwork(NetworkCapabilities caps)1021     private void setupTrackedCarrierWifiNetwork(NetworkCapabilities caps) {
1022         mVcnMgmtSvc.systemReady();
1023 
1024         final ArgumentCaptor<NetworkCallback> captor =
1025                 ArgumentCaptor.forClass(NetworkCallback.class);
1026         verify(mConnMgr)
1027                 .registerNetworkCallback(
1028                         eq(new NetworkRequest.Builder().clearCapabilities().build()),
1029                         captor.capture());
1030         captor.getValue().onCapabilitiesChanged(mock(Network.class, CALLS_REAL_METHODS), caps);
1031     }
1032 
1033     @Test
testGetUnderlyingNetworkPolicyVcnWifi_unrestrictingExistingNetworkRequiresRestart()1034     public void testGetUnderlyingNetworkPolicyVcnWifi_unrestrictingExistingNetworkRequiresRestart()
1035             throws Exception {
1036         final NetworkCapabilities existingNetworkCaps =
1037                 getNetworkCapabilitiesBuilderForTransport(TEST_SUBSCRIPTION_ID, TRANSPORT_WIFI)
1038                         .removeCapability(NET_CAPABILITY_NOT_RESTRICTED)
1039                         .build();
1040         setupTrackedCarrierWifiNetwork(existingNetworkCaps);
1041 
1042         // Trigger test without VCN instance alive; expect restart due to change of NOT_RESTRICTED
1043         // immutable capability
1044         final VcnUnderlyingNetworkPolicy policy =
1045                 mVcnMgmtSvc.getUnderlyingNetworkPolicy(
1046                         getNetworkCapabilitiesBuilderForTransport(
1047                                         TEST_SUBSCRIPTION_ID, TRANSPORT_WIFI)
1048                                 .build(),
1049                         new LinkProperties());
1050         assertTrue(policy.isTeardownRequested());
1051     }
1052 
1053     @Test
testGetUnderlyingNetworkPolicyVcnWifi_restrictingExistingNetworkRequiresRestart()1054     public void testGetUnderlyingNetworkPolicyVcnWifi_restrictingExistingNetworkRequiresRestart()
1055             throws Exception {
1056         final NetworkCapabilities existingNetworkCaps =
1057                 getNetworkCapabilitiesBuilderForTransport(TEST_SUBSCRIPTION_ID, TRANSPORT_WIFI)
1058                         .build();
1059         setupTrackedCarrierWifiNetwork(existingNetworkCaps);
1060 
1061         final VcnUnderlyingNetworkPolicy policy =
1062                 startVcnAndGetPolicyForTransport(
1063                         TEST_SUBSCRIPTION_ID, TEST_UUID_2, false /* isActive */, TRANSPORT_WIFI);
1064 
1065         assertTrue(policy.isTeardownRequested());
1066     }
1067 
1068     @Test
testGetUnderlyingNetworkPolicyNonVcnNetwork()1069     public void testGetUnderlyingNetworkPolicyNonVcnNetwork() throws Exception {
1070         setupSubscriptionAndStartVcn(TEST_SUBSCRIPTION_ID, TEST_UUID_1, true /* isActive */);
1071 
1072         NetworkCapabilities nc =
1073                 new NetworkCapabilities.Builder()
1074                         .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
1075                         .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
1076                         .setNetworkSpecifier(new TelephonyNetworkSpecifier(TEST_SUBSCRIPTION_ID_2))
1077                         .build();
1078 
1079         VcnUnderlyingNetworkPolicy policy =
1080                 mVcnMgmtSvc.getUnderlyingNetworkPolicy(nc, new LinkProperties());
1081 
1082         assertFalse(policy.isTeardownRequested());
1083         assertEquals(nc, policy.getMergedNetworkCapabilities());
1084     }
1085 
1086     @Test(expected = SecurityException.class)
testGetUnderlyingNetworkPolicyInvalidPermission()1087     public void testGetUnderlyingNetworkPolicyInvalidPermission() {
1088         doReturn(PackageManager.PERMISSION_DENIED)
1089                 .when(mMockContext)
1090                 .checkCallingOrSelfPermission(any());
1091 
1092         mVcnMgmtSvc.getUnderlyingNetworkPolicy(new NetworkCapabilities(), new LinkProperties());
1093     }
1094 
1095     @Test
testSubscriptionSnapshotUpdateNotifiesVcn()1096     public void testSubscriptionSnapshotUpdateNotifiesVcn() {
1097         setupActiveSubscription(TEST_UUID_2);
1098 
1099         mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
1100         final Map<ParcelUuid, Vcn> vcnInstances = mVcnMgmtSvc.getAllVcns();
1101         final Vcn vcnInstance = vcnInstances.get(TEST_UUID_2);
1102 
1103         TelephonySubscriptionSnapshot snapshot =
1104                 triggerSubscriptionTrackerCbAndGetSnapshot(
1105                         TEST_UUID_2, Collections.singleton(TEST_UUID_2));
1106 
1107         verify(vcnInstance).updateSubscriptionSnapshot(eq(snapshot));
1108     }
1109 
1110     @Test
testAddNewVcnUpdatesPolicyListener()1111     public void testAddNewVcnUpdatesPolicyListener() throws Exception {
1112         setupActiveSubscription(TEST_UUID_2);
1113 
1114         mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
1115 
1116         mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
1117 
1118         verify(mMockPolicyListener).onPolicyChanged();
1119     }
1120 
1121     @Test
testRemoveVcnUpdatesPolicyListener()1122     public void testRemoveVcnUpdatesPolicyListener() throws Exception {
1123         setupActiveSubscription(TEST_UUID_2);
1124 
1125         mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
1126         mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
1127 
1128         mVcnMgmtSvc.clearVcnConfig(TEST_UUID_2, TEST_PACKAGE_NAME);
1129 
1130         verify(mMockPolicyListener).onPolicyChanged();
1131     }
1132 
1133     @Test
testVcnSubIdChangeUpdatesPolicyListener()1134     public void testVcnSubIdChangeUpdatesPolicyListener() throws Exception {
1135         setupActiveSubscription(TEST_UUID_2);
1136 
1137         startAndGetVcnInstance(TEST_UUID_2);
1138         mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
1139 
1140         triggerSubscriptionTrackerCbAndGetSnapshot(
1141                 TEST_UUID_2,
1142                 Collections.singleton(TEST_UUID_2),
1143                 Collections.singletonMap(TEST_SUBSCRIPTION_ID, TEST_UUID_2));
1144 
1145         verify(mMockPolicyListener).onPolicyChanged();
1146     }
1147 
triggerVcnSafeMode( @onNull ParcelUuid subGroup, @NonNull TelephonySubscriptionSnapshot snapshot, boolean isInSafeMode)1148     private void triggerVcnSafeMode(
1149             @NonNull ParcelUuid subGroup,
1150             @NonNull TelephonySubscriptionSnapshot snapshot,
1151             boolean isInSafeMode)
1152             throws Exception {
1153         verify(mMockDeps)
1154                 .newVcn(
1155                         eq(mVcnContext),
1156                         eq(subGroup),
1157                         eq(TEST_VCN_CONFIG),
1158                         eq(snapshot),
1159                         mVcnCallbackCaptor.capture());
1160 
1161         VcnCallback vcnCallback = mVcnCallbackCaptor.getValue();
1162         vcnCallback.onSafeModeStatusChanged(isInSafeMode);
1163     }
1164 
verifyVcnSafeModeChangesNotifiesPolicyListeners(boolean enterSafeMode)1165     private void verifyVcnSafeModeChangesNotifiesPolicyListeners(boolean enterSafeMode)
1166             throws Exception {
1167         TelephonySubscriptionSnapshot snapshot =
1168                 triggerSubscriptionTrackerCbAndGetSnapshot(
1169                         TEST_UUID_1, Collections.singleton(TEST_UUID_1));
1170 
1171         mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
1172 
1173         triggerVcnSafeMode(TEST_UUID_1, snapshot, enterSafeMode);
1174 
1175         verify(mMockPolicyListener).onPolicyChanged();
1176     }
1177 
1178     @Test
testVcnEnteringSafeModeNotifiesPolicyListeners()1179     public void testVcnEnteringSafeModeNotifiesPolicyListeners() throws Exception {
1180         verifyVcnSafeModeChangesNotifiesPolicyListeners(true /* enterSafeMode */);
1181     }
1182 
1183     @Test
testVcnExitingSafeModeNotifiesPolicyListeners()1184     public void testVcnExitingSafeModeNotifiesPolicyListeners() throws Exception {
1185         verifyVcnSafeModeChangesNotifiesPolicyListeners(false /* enterSafeMode */);
1186     }
1187 
triggerVcnStatusCallbackOnSafeModeStatusChanged( @onNull ParcelUuid subGroup, @NonNull String pkgName, int uid, boolean hasPermissionsforSubGroup)1188     private void triggerVcnStatusCallbackOnSafeModeStatusChanged(
1189             @NonNull ParcelUuid subGroup,
1190             @NonNull String pkgName,
1191             int uid,
1192             boolean hasPermissionsforSubGroup)
1193             throws Exception {
1194         TelephonySubscriptionSnapshot snapshot =
1195                 triggerSubscriptionTrackerCbAndGetSnapshot(
1196                         subGroup, Collections.singleton(subGroup));
1197 
1198         setupSubscriptionAndStartVcn(
1199                 TEST_SUBSCRIPTION_ID, subGroup, true /* isActive */, hasPermissionsforSubGroup);
1200 
1201         doReturn(hasPermissionsforSubGroup)
1202                 .when(snapshot)
1203                 .packageHasPermissionsForSubscriptionGroup(eq(subGroup), eq(pkgName));
1204 
1205         mVcnMgmtSvc.registerVcnStatusCallback(subGroup, mMockStatusCallback, pkgName);
1206 
1207         triggerVcnSafeMode(subGroup, snapshot, true /* enterSafeMode */);
1208     }
1209 
1210     @Test
testVcnStatusCallbackOnSafeModeStatusChangedWithCarrierPrivileges()1211     public void testVcnStatusCallbackOnSafeModeStatusChangedWithCarrierPrivileges()
1212             throws Exception {
1213         triggerVcnStatusCallbackOnSafeModeStatusChanged(
1214                 TEST_UUID_1, TEST_PACKAGE_NAME, TEST_UID, true /* hasPermissionsforSubGroup */);
1215 
1216         verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_SAFE_MODE);
1217     }
1218 
1219     @Test
testVcnStatusCallbackOnSafeModeStatusChangedWithoutCarrierPrivileges()1220     public void testVcnStatusCallbackOnSafeModeStatusChangedWithoutCarrierPrivileges()
1221             throws Exception {
1222         triggerVcnStatusCallbackOnSafeModeStatusChanged(
1223                 TEST_UUID_1, TEST_PACKAGE_NAME, TEST_UID, false /* hasPermissionsforSubGroup */);
1224 
1225         verify(mMockStatusCallback, never())
1226                 .onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_SAFE_MODE);
1227     }
1228 
1229     @Test
testRegisterVcnStatusCallback()1230     public void testRegisterVcnStatusCallback() throws Exception {
1231         mVcnMgmtSvc.registerVcnStatusCallback(TEST_UUID_1, mMockStatusCallback, TEST_PACKAGE_NAME);
1232 
1233         Map<IBinder, VcnStatusCallbackInfo> callbacks = mVcnMgmtSvc.getAllStatusCallbacks();
1234         VcnStatusCallbackInfo cbInfo = callbacks.get(mMockIBinder);
1235 
1236         assertNotNull(cbInfo);
1237         assertEquals(TEST_UUID_1, cbInfo.mSubGroup);
1238         assertEquals(mMockStatusCallback, cbInfo.mCallback);
1239         assertEquals(TEST_PACKAGE_NAME, cbInfo.mPkgName);
1240         assertEquals(TEST_UID, cbInfo.mUid);
1241         verify(mMockIBinder).linkToDeath(eq(cbInfo), anyInt());
1242 
1243         verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_NOT_CONFIGURED);
1244     }
1245 
1246     @Test
testRegisterVcnStatusCallback_MissingPermission()1247     public void testRegisterVcnStatusCallback_MissingPermission() throws Exception {
1248         setupSubscriptionAndStartVcn(
1249                 TEST_SUBSCRIPTION_ID,
1250                 TEST_UUID_1,
1251                 true /* isActive */,
1252                 false /* hasCarrierPrivileges */);
1253 
1254         mVcnMgmtSvc.registerVcnStatusCallback(TEST_UUID_1, mMockStatusCallback, TEST_PACKAGE_NAME);
1255 
1256         verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_NOT_CONFIGURED);
1257     }
1258 
1259     @Test
testRegisterVcnStatusCallback_VcnInactive()1260     public void testRegisterVcnStatusCallback_VcnInactive() throws Exception {
1261         setupSubscriptionAndStartVcn(
1262                 TEST_SUBSCRIPTION_ID,
1263                 TEST_UUID_1,
1264                 true /* isActive */,
1265                 true /* hasCarrierPrivileges */);
1266 
1267         // VCN is currently active. Lose carrier privileges for TEST_PACKAGE and hit teardown
1268         // timeout so the VCN goes inactive.
1269         final TelephonySubscriptionSnapshot snapshot =
1270                 triggerSubscriptionTrackerCbAndGetSnapshot(
1271                         TEST_UUID_1,
1272                         Collections.singleton(TEST_UUID_1),
1273                         Collections.singletonMap(TEST_SUBSCRIPTION_ID, TEST_UUID_1),
1274                         false /* hasCarrierPrivileges */);
1275         mTestLooper.moveTimeForward(VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS);
1276         mTestLooper.dispatchAll();
1277 
1278         // Giving TEST_PACKAGE privileges again will restart the VCN (which will indicate ACTIVE
1279         // when the status callback is registered). Instead, setup permissions for TEST_CB_PACKAGE
1280         // so that it's permissioned to receive INACTIVE (instead of NOT_CONFIGURED) without
1281         // reactivating the VCN.
1282         doReturn(true)
1283                 .when(snapshot)
1284                 .packageHasPermissionsForSubscriptionGroup(
1285                         eq(TEST_UUID_1), eq(TEST_CB_PACKAGE_NAME));
1286 
1287         mVcnMgmtSvc.registerVcnStatusCallback(
1288                 TEST_UUID_1, mMockStatusCallback, TEST_CB_PACKAGE_NAME);
1289 
1290         verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_INACTIVE);
1291     }
1292 
1293     @Test
testRegisterVcnStatusCallback_VcnActive()1294     public void testRegisterVcnStatusCallback_VcnActive() throws Exception {
1295         setupSubscriptionAndStartVcn(
1296                 TEST_SUBSCRIPTION_ID,
1297                 TEST_UUID_1,
1298                 true /* isActive */,
1299                 true /* hasCarrierPrivileges */);
1300 
1301         mVcnMgmtSvc.registerVcnStatusCallback(TEST_UUID_1, mMockStatusCallback, TEST_PACKAGE_NAME);
1302 
1303         verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_ACTIVE);
1304     }
1305 
1306     @Test
testRegisterVcnStatusCallback_VcnSafeMode()1307     public void testRegisterVcnStatusCallback_VcnSafeMode() throws Exception {
1308         setupSubscriptionAndStartVcn(
1309                 TEST_SUBSCRIPTION_ID,
1310                 TEST_UUID_1,
1311                 false /* isActive */,
1312                 true /* hasCarrierPrivileges */);
1313 
1314         mVcnMgmtSvc.registerVcnStatusCallback(TEST_UUID_1, mMockStatusCallback, TEST_PACKAGE_NAME);
1315 
1316         verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_SAFE_MODE);
1317     }
1318 
1319     @Test(expected = IllegalStateException.class)
testRegisterVcnStatusCallbackDuplicate()1320     public void testRegisterVcnStatusCallbackDuplicate() {
1321         mVcnMgmtSvc.registerVcnStatusCallback(TEST_UUID_1, mMockStatusCallback, TEST_PACKAGE_NAME);
1322         mVcnMgmtSvc.registerVcnStatusCallback(TEST_UUID_1, mMockStatusCallback, TEST_PACKAGE_NAME);
1323     }
1324 
1325     @Test
testUnregisterVcnStatusCallback()1326     public void testUnregisterVcnStatusCallback() {
1327         mVcnMgmtSvc.registerVcnStatusCallback(TEST_UUID_1, mMockStatusCallback, TEST_PACKAGE_NAME);
1328         Map<IBinder, VcnStatusCallbackInfo> callbacks = mVcnMgmtSvc.getAllStatusCallbacks();
1329         VcnStatusCallbackInfo cbInfo = callbacks.get(mMockIBinder);
1330 
1331         mVcnMgmtSvc.unregisterVcnStatusCallback(mMockStatusCallback);
1332         assertTrue(mVcnMgmtSvc.getAllStatusCallbacks().isEmpty());
1333         verify(mMockIBinder).unlinkToDeath(eq(cbInfo), anyInt());
1334     }
1335 
1336     @Test(expected = SecurityException.class)
testRegisterVcnStatusCallbackInvalidPackage()1337     public void testRegisterVcnStatusCallbackInvalidPackage() {
1338         doThrow(new SecurityException()).when(mAppOpsMgr).checkPackage(TEST_UID, TEST_PACKAGE_NAME);
1339 
1340         mVcnMgmtSvc.registerVcnStatusCallback(TEST_UUID_1, mMockStatusCallback, TEST_PACKAGE_NAME);
1341     }
1342 
1343     @Test
testUnregisterVcnStatusCallbackNeverRegistered()1344     public void testUnregisterVcnStatusCallbackNeverRegistered() {
1345         mVcnMgmtSvc.unregisterVcnStatusCallback(mMockStatusCallback);
1346 
1347         assertTrue(mVcnMgmtSvc.getAllStatusCallbacks().isEmpty());
1348     }
1349 }
1350