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_ENTERPRISE;
21 import static android.net.NetworkCapabilities.NET_CAPABILITY_IMS;
22 import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
23 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
24 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED;
25 import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
26 import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
27 import static android.net.vcn.VcnManager.VCN_RESTRICTED_TRANSPORTS_INT_ARRAY_KEY;
28 import static android.net.vcn.VcnManager.VCN_STATUS_CODE_ACTIVE;
29 import static android.net.vcn.VcnManager.VCN_STATUS_CODE_SAFE_MODE;
30 import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
31 import static android.telephony.TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS;
32 import static android.telephony.TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS;
33 
34 import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
35 import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionTrackerCallback;
36 import static com.android.server.vcn.VcnTestUtils.setupSystemService;
37 
38 import static org.junit.Assert.assertEquals;
39 import static org.junit.Assert.assertFalse;
40 import static org.junit.Assert.assertNotNull;
41 import static org.junit.Assert.assertNull;
42 import static org.junit.Assert.assertTrue;
43 import static org.junit.Assert.fail;
44 import static org.mockito.ArgumentMatchers.any;
45 import static org.mockito.ArgumentMatchers.anyBoolean;
46 import static org.mockito.ArgumentMatchers.anyInt;
47 import static org.mockito.ArgumentMatchers.eq;
48 import static org.mockito.Mockito.CALLS_REAL_METHODS;
49 import static org.mockito.Mockito.any;
50 import static org.mockito.Mockito.argThat;
51 import static org.mockito.Mockito.doAnswer;
52 import static org.mockito.Mockito.doNothing;
53 import static org.mockito.Mockito.doReturn;
54 import static org.mockito.Mockito.doThrow;
55 import static org.mockito.Mockito.eq;
56 import static org.mockito.Mockito.mock;
57 import static org.mockito.Mockito.never;
58 import static org.mockito.Mockito.times;
59 import static org.mockito.Mockito.verify;
60 
61 import android.annotation.NonNull;
62 import android.app.AppOpsManager;
63 import android.content.BroadcastReceiver;
64 import android.content.Context;
65 import android.content.Intent;
66 import android.content.pm.PackageManager;
67 import android.net.ConnectivityManager;
68 import android.net.LinkProperties;
69 import android.net.Network;
70 import android.net.NetworkCapabilities;
71 import android.net.NetworkRequest;
72 import android.net.Uri;
73 import android.net.vcn.IVcnStatusCallback;
74 import android.net.vcn.IVcnUnderlyingNetworkPolicyListener;
75 import android.net.vcn.VcnConfig;
76 import android.net.vcn.VcnConfigTest;
77 import android.net.vcn.VcnGatewayConnectionConfigTest;
78 import android.net.vcn.VcnManager;
79 import android.net.vcn.VcnUnderlyingNetworkPolicy;
80 import android.os.IBinder;
81 import android.os.ParcelUuid;
82 import android.os.PersistableBundle;
83 import android.os.Process;
84 import android.os.UserHandle;
85 import android.os.test.TestLooper;
86 import android.telephony.SubscriptionInfo;
87 import android.telephony.SubscriptionManager;
88 import android.telephony.TelephonyManager;
89 import android.util.ArraySet;
90 
91 import androidx.test.filters.SmallTest;
92 import androidx.test.runner.AndroidJUnit4;
93 
94 import com.android.server.VcnManagementService.VcnCallback;
95 import com.android.server.VcnManagementService.VcnStatusCallbackInfo;
96 import com.android.server.vcn.TelephonySubscriptionTracker;
97 import com.android.server.vcn.Vcn;
98 import com.android.server.vcn.VcnContext;
99 import com.android.server.vcn.VcnNetworkProvider;
100 import com.android.server.vcn.util.PersistableBundleUtils;
101 import com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper;
102 
103 import org.junit.Before;
104 import org.junit.Test;
105 import org.junit.runner.RunWith;
106 import org.mockito.ArgumentCaptor;
107 
108 import java.io.FileNotFoundException;
109 import java.util.Arrays;
110 import java.util.Collections;
111 import java.util.List;
112 import java.util.Map;
113 import java.util.Map.Entry;
114 import java.util.Set;
115 import java.util.UUID;
116 
117 /** Tests for {@link VcnManagementService}. */
118 @RunWith(AndroidJUnit4.class)
119 @SmallTest
120 public class VcnManagementServiceTest {
121     private static final String CONTEXT_ATTRIBUTION_TAG = "VCN";
122     private static final String TEST_PACKAGE_NAME =
123             VcnManagementServiceTest.class.getPackage().getName();
124     private static final String TEST_PACKAGE_NAME_2 = "TEST_PKG_2";
125     private static final String TEST_CB_PACKAGE_NAME =
126             VcnManagementServiceTest.class.getPackage().getName() + ".callback";
127     private static final ParcelUuid TEST_UUID_1 = new ParcelUuid(new UUID(0, 0));
128     private static final ParcelUuid TEST_UUID_2 = new ParcelUuid(new UUID(1, 1));
129     private static final ParcelUuid TEST_UUID_3 = new ParcelUuid(new UUID(2, 2));
130     private static final VcnConfig TEST_VCN_CONFIG;
131     private static final VcnConfig TEST_VCN_CONFIG_PKG_2;
132     private static final int TEST_UID = Process.FIRST_APPLICATION_UID;
133     private static final String TEST_IFACE_NAME = "TEST_IFACE";
134     private static final String TEST_IFACE_NAME_2 = "TEST_IFACE2";
135     private static final LinkProperties TEST_LP_1 = new LinkProperties();
136     private static final LinkProperties TEST_LP_2 = new LinkProperties();
137 
138     static {
139         TEST_LP_1.setInterfaceName(TEST_IFACE_NAME);
140         TEST_LP_2.setInterfaceName(TEST_IFACE_NAME_2);
141     }
142 
143     static {
144         final Context mockConfigContext = mock(Context.class);
145 
146         doReturn(TEST_PACKAGE_NAME).when(mockConfigContext).getOpPackageName();
147         TEST_VCN_CONFIG = VcnConfigTest.buildTestConfig(mockConfigContext);
148 
149         doReturn(TEST_PACKAGE_NAME_2).when(mockConfigContext).getOpPackageName();
150         TEST_VCN_CONFIG_PKG_2 = VcnConfigTest.buildTestConfig(mockConfigContext);
151     }
152 
153     private static final Map<ParcelUuid, VcnConfig> TEST_VCN_CONFIG_MAP =
154             Collections.unmodifiableMap(Collections.singletonMap(TEST_UUID_1, TEST_VCN_CONFIG));
155 
156     private static final int TEST_SUBSCRIPTION_ID = 1;
157     private static final int TEST_SUBSCRIPTION_ID_2 = 2;
158     private static final SubscriptionInfo TEST_SUBSCRIPTION_INFO =
159             new SubscriptionInfo(
160                     TEST_SUBSCRIPTION_ID /* id */,
161                     "" /* iccId */,
162                     0 /* simSlotIndex */,
163                     "Carrier" /* displayName */,
164                     "Carrier" /* carrierName */,
165                     0 /* nameSource */,
166                     255 /* iconTint */,
167                     "12345" /* number */,
168                     0 /* roaming */,
169                     null /* icon */,
170                     "0" /* mcc */,
171                     "0" /* mnc */,
172                     "0" /* countryIso */,
173                     false /* isEmbedded */,
174                     null /* nativeAccessRules */,
175                     null /* cardString */,
176                     false /* isOpportunistic */,
177                     TEST_UUID_1.toString() /* groupUUID */,
178                     0 /* carrierId */,
179                     0 /* profileClass */);
180 
181     private final Context mMockContextWithoutAttributionTag = mock(Context.class);
182     private final Context mMockContext = mock(Context.class);
183     private final VcnManagementService.Dependencies mMockDeps =
184             mock(VcnManagementService.Dependencies.class);
185     private final TestLooper mTestLooper = new TestLooper();
186     private final ConnectivityManager mConnMgr = mock(ConnectivityManager.class);
187     private final TelephonyManager mTelMgr = mock(TelephonyManager.class);
188     private final SubscriptionManager mSubMgr = mock(SubscriptionManager.class);
189     private final AppOpsManager mAppOpsMgr = mock(AppOpsManager.class);
190     private final VcnContext mVcnContext = mock(VcnContext.class);
191     private final PersistableBundleUtils.LockingReadWriteHelper mConfigReadWriteHelper =
192             mock(PersistableBundleUtils.LockingReadWriteHelper.class);
193     private final TelephonySubscriptionTracker mSubscriptionTracker =
194             mock(TelephonySubscriptionTracker.class);
195 
196     private final ArgumentCaptor<VcnCallback> mVcnCallbackCaptor =
197             ArgumentCaptor.forClass(VcnCallback.class);
198 
199     private final VcnManagementService mVcnMgmtSvc;
200 
201     private final IVcnUnderlyingNetworkPolicyListener mMockPolicyListener =
202             mock(IVcnUnderlyingNetworkPolicyListener.class);
203     private final IVcnStatusCallback mMockStatusCallback = mock(IVcnStatusCallback.class);
204     private final IBinder mMockIBinder = mock(IBinder.class);
205 
VcnManagementServiceTest()206     public VcnManagementServiceTest() throws Exception {
207         doReturn(mMockContext)
208                 .when(mMockContextWithoutAttributionTag)
209                 .createAttributionContext(CONTEXT_ATTRIBUTION_TAG);
210 
211         setupSystemService(
212                 mMockContext, mConnMgr, Context.CONNECTIVITY_SERVICE, ConnectivityManager.class);
213         setupSystemService(
214                 mMockContext, mTelMgr, Context.TELEPHONY_SERVICE, TelephonyManager.class);
215         setupSystemService(
216                 mMockContext,
217                 mSubMgr,
218                 Context.TELEPHONY_SUBSCRIPTION_SERVICE,
219                 SubscriptionManager.class);
220         setupSystemService(mMockContext, mAppOpsMgr, Context.APP_OPS_SERVICE, AppOpsManager.class);
221 
222         doReturn(TEST_PACKAGE_NAME).when(mMockContext).getOpPackageName();
223 
224         doReturn(mMockContext).when(mVcnContext).getContext();
225         doReturn(mTestLooper.getLooper()).when(mMockDeps).getLooper();
226         doReturn(TEST_UID).when(mMockDeps).getBinderCallingUid();
227         doReturn(mVcnContext)
228                 .when(mMockDeps)
229                 .newVcnContext(
230                         eq(mMockContext),
231                         eq(mTestLooper.getLooper()),
232                         any(VcnNetworkProvider.class),
233                         anyBoolean());
234         doReturn(mSubscriptionTracker)
235                 .when(mMockDeps)
236                 .newTelephonySubscriptionTracker(
237                         eq(mMockContext),
238                         eq(mTestLooper.getLooper()),
239                         any(TelephonySubscriptionTrackerCallback.class));
240         doReturn(mConfigReadWriteHelper)
241                 .when(mMockDeps)
242                 .newPersistableBundleLockingReadWriteHelper(any());
243 
244         // Setup VCN instance generation
245         doAnswer((invocation) -> {
246             // Mock-within a doAnswer is safe, because it doesn't actually run nested.
247             return mock(Vcn.class);
248         }).when(mMockDeps).newVcn(any(), any(), any(), any(), any());
249 
250         final PersistableBundle bundle =
251                 PersistableBundleUtils.fromMap(
252                         TEST_VCN_CONFIG_MAP,
253                         PersistableBundleUtils::fromParcelUuid,
254                         VcnConfig::toPersistableBundle);
255         doReturn(bundle).when(mConfigReadWriteHelper).readFromDisk();
256 
257         setupMockedCarrierPrivilege(true);
258         mVcnMgmtSvc = new VcnManagementService(mMockContextWithoutAttributionTag, mMockDeps);
259         setupActiveSubscription(TEST_UUID_1);
260 
261         doReturn(mMockIBinder).when(mMockPolicyListener).asBinder();
262         doReturn(mMockIBinder).when(mMockStatusCallback).asBinder();
263 
264         // Make sure the profiles are loaded.
265         mTestLooper.dispatchAll();
266     }
267 
268     @Before
setUp()269     public void setUp() {
270         doNothing()
271                 .when(mMockContext)
272                 .enforceCallingOrSelfPermission(
273                         eq(android.Manifest.permission.NETWORK_FACTORY), any());
274 
275         doReturn(Collections.singleton(TRANSPORT_WIFI))
276                 .when(mMockDeps)
277                 .getRestrictedTransports(any(), any(), any());
278     }
279 
280 
setupMockedCarrierPrivilege(boolean isPrivileged)281     private void setupMockedCarrierPrivilege(boolean isPrivileged) {
282         setupMockedCarrierPrivilege(isPrivileged, TEST_PACKAGE_NAME);
283     }
284 
setupMockedCarrierPrivilege(boolean isPrivileged, String pkg)285     private void setupMockedCarrierPrivilege(boolean isPrivileged, String pkg) {
286         doReturn(Collections.singletonList(TEST_SUBSCRIPTION_INFO))
287                 .when(mSubMgr)
288                 .getSubscriptionsInGroup(any());
289         doReturn(mTelMgr)
290                 .when(mTelMgr)
291                 .createForSubscriptionId(eq(TEST_SUBSCRIPTION_INFO.getSubscriptionId()));
292         doReturn(
293                         isPrivileged
294                                 ? CARRIER_PRIVILEGE_STATUS_HAS_ACCESS
295                                 : CARRIER_PRIVILEGE_STATUS_NO_ACCESS)
296                 .when(mTelMgr)
297                 .checkCarrierPrivilegesForPackage(eq(pkg));
298     }
299 
300     @Test
testSystemReady()301     public void testSystemReady() throws Exception {
302         mVcnMgmtSvc.systemReady();
303 
304         verify(mConnMgr).registerNetworkProvider(any(VcnNetworkProvider.class));
305         verify(mSubscriptionTracker).register();
306         verify(mConnMgr)
307                 .registerNetworkCallback(
308                         eq(new NetworkRequest.Builder().clearCapabilities().build()),
309                         any(NetworkCallback.class));
310     }
311 
312     @Test
testNonSystemServerRealConfigFileAccessPermission()313     public void testNonSystemServerRealConfigFileAccessPermission() throws Exception {
314         // Attempt to build a real instance of the dependencies, and verify we cannot write to the
315         // file.
316         VcnManagementService.Dependencies deps = new VcnManagementService.Dependencies();
317         PersistableBundleUtils.LockingReadWriteHelper configReadWriteHelper =
318                 deps.newPersistableBundleLockingReadWriteHelper(
319                         VcnManagementService.VCN_CONFIG_FILE);
320 
321         // Even tests should not be able to read/write configs from disk; SELinux policies restrict
322         // it to only the system server.
323         // Reading config should always return null since the file "does not exist", and writing
324         // should throw an IOException.
325         assertNull(configReadWriteHelper.readFromDisk());
326 
327         try {
328             configReadWriteHelper.writeToDisk(new PersistableBundle());
329             fail("Expected IOException due to SELinux policy");
330         } catch (FileNotFoundException expected) {
331         }
332     }
333 
334     @Test
testLoadVcnConfigsOnStartup()335     public void testLoadVcnConfigsOnStartup() throws Exception {
336         mTestLooper.dispatchAll();
337 
338         assertEquals(TEST_VCN_CONFIG_MAP, mVcnMgmtSvc.getConfigs());
339         verify(mConfigReadWriteHelper).readFromDisk();
340     }
341 
triggerSubscriptionTrackerCbAndGetSnapshot( ParcelUuid activeDataSubGrp, Set<ParcelUuid> activeSubscriptionGroups)342     private TelephonySubscriptionSnapshot triggerSubscriptionTrackerCbAndGetSnapshot(
343             ParcelUuid activeDataSubGrp, Set<ParcelUuid> activeSubscriptionGroups) {
344         return triggerSubscriptionTrackerCbAndGetSnapshot(
345                 activeDataSubGrp, activeSubscriptionGroups, Collections.emptyMap());
346     }
347 
triggerSubscriptionTrackerCbAndGetSnapshot( ParcelUuid activeDataSubGrp, Set<ParcelUuid> activeSubscriptionGroups, Map<Integer, ParcelUuid> subIdToGroupMap)348     private TelephonySubscriptionSnapshot triggerSubscriptionTrackerCbAndGetSnapshot(
349             ParcelUuid activeDataSubGrp,
350             Set<ParcelUuid> activeSubscriptionGroups,
351             Map<Integer, ParcelUuid> subIdToGroupMap) {
352         return triggerSubscriptionTrackerCbAndGetSnapshot(
353                 activeDataSubGrp,
354                 activeSubscriptionGroups,
355                 subIdToGroupMap,
356                 true /* hasCarrierPrivileges */);
357     }
358 
triggerSubscriptionTrackerCbAndGetSnapshot( ParcelUuid activeDataSubGrp, Set<ParcelUuid> activeSubscriptionGroups, Map<Integer, ParcelUuid> subIdToGroupMap, boolean hasCarrierPrivileges)359     private TelephonySubscriptionSnapshot triggerSubscriptionTrackerCbAndGetSnapshot(
360             ParcelUuid activeDataSubGrp,
361             Set<ParcelUuid> activeSubscriptionGroups,
362             Map<Integer, ParcelUuid> subIdToGroupMap,
363             boolean hasCarrierPrivileges) {
364         return triggerSubscriptionTrackerCbAndGetSnapshot(
365                 TEST_SUBSCRIPTION_ID,
366                 activeDataSubGrp,
367                 activeSubscriptionGroups,
368                 subIdToGroupMap,
369                 hasCarrierPrivileges);
370     }
371 
triggerSubscriptionTrackerCbAndGetSnapshot( int activeDataSubId, ParcelUuid activeDataSubGrp, Set<ParcelUuid> activeSubscriptionGroups, Map<Integer, ParcelUuid> subIdToGroupMap, boolean hasCarrierPrivileges)372     private TelephonySubscriptionSnapshot triggerSubscriptionTrackerCbAndGetSnapshot(
373             int activeDataSubId,
374             ParcelUuid activeDataSubGrp,
375             Set<ParcelUuid> activeSubscriptionGroups,
376             Map<Integer, ParcelUuid> subIdToGroupMap,
377             boolean hasCarrierPrivileges) {
378         final TelephonySubscriptionSnapshot snapshot =
379                 buildSubscriptionSnapshot(
380                         activeDataSubId,
381                         activeDataSubGrp,
382                         activeSubscriptionGroups,
383                         subIdToGroupMap,
384                         hasCarrierPrivileges);
385 
386         final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback();
387         cb.onNewSnapshot(snapshot);
388 
389         return snapshot;
390     }
391 
buildSubscriptionSnapshot( int activeDataSubId, ParcelUuid activeDataSubGrp, Set<ParcelUuid> activeSubscriptionGroups, Map<Integer, ParcelUuid> subIdToGroupMap, boolean hasCarrierPrivileges)392     private TelephonySubscriptionSnapshot buildSubscriptionSnapshot(
393             int activeDataSubId,
394             ParcelUuid activeDataSubGrp,
395             Set<ParcelUuid> activeSubscriptionGroups,
396             Map<Integer, ParcelUuid> subIdToGroupMap,
397             boolean hasCarrierPrivileges) {
398         final TelephonySubscriptionSnapshot snapshot = mock(TelephonySubscriptionSnapshot.class);
399         doReturn(activeSubscriptionGroups).when(snapshot).getActiveSubscriptionGroups();
400         doReturn(activeDataSubGrp).when(snapshot).getActiveDataSubscriptionGroup();
401         doReturn(activeDataSubId).when(snapshot).getActiveDataSubscriptionId();
402 
403         final Set<String> privilegedPackages =
404                 (activeSubscriptionGroups == null || activeSubscriptionGroups.isEmpty())
405                         ? Collections.emptySet()
406                         : Collections.singleton(TEST_PACKAGE_NAME);
407         doReturn(hasCarrierPrivileges)
408                 .when(snapshot)
409                 .packageHasPermissionsForSubscriptionGroup(
410                         argThat(val -> activeSubscriptionGroups.contains(val)),
411                         eq(TEST_PACKAGE_NAME));
412 
413         doAnswer(invocation -> {
414             return subIdToGroupMap.get(invocation.getArgument(0));
415         }).when(snapshot).getGroupForSubId(anyInt());
416 
417         doAnswer(invocation -> {
418             final ParcelUuid subGrp = invocation.getArgument(0);
419             final Set<Integer> subIds = new ArraySet<>();
420             for (Entry<Integer, ParcelUuid> entry : subIdToGroupMap.entrySet()) {
421                 if (entry.getValue().equals(subGrp)) {
422                     subIds.add(entry.getKey());
423                 }
424             }
425             return subIds;
426         }).when(snapshot).getAllSubIdsInGroup(any());
427 
428         return snapshot;
429     }
430 
setupActiveSubscription(ParcelUuid activeDataSubGrp)431     private void setupActiveSubscription(ParcelUuid activeDataSubGrp) {
432         mVcnMgmtSvc.setLastSnapshot(
433                 buildSubscriptionSnapshot(
434                         TEST_SUBSCRIPTION_ID,
435                         activeDataSubGrp,
436                         Collections.emptySet(),
437                         Collections.emptyMap(),
438                         true /* hasCarrierPrivileges */));
439     }
440 
getTelephonySubscriptionTrackerCallback()441     private TelephonySubscriptionTrackerCallback getTelephonySubscriptionTrackerCallback() {
442         final ArgumentCaptor<TelephonySubscriptionTrackerCallback> captor =
443                 ArgumentCaptor.forClass(TelephonySubscriptionTrackerCallback.class);
444         verify(mMockDeps)
445                 .newTelephonySubscriptionTracker(
446                         eq(mMockContext), eq(mTestLooper.getLooper()), captor.capture());
447         return captor.getValue();
448     }
449 
getPackageChangeReceiver()450     private BroadcastReceiver getPackageChangeReceiver() {
451         final ArgumentCaptor<BroadcastReceiver> captor =
452                 ArgumentCaptor.forClass(BroadcastReceiver.class);
453         verify(mMockContext).registerReceiver(captor.capture(), argThat(filter -> {
454             return filter.hasAction(Intent.ACTION_PACKAGE_ADDED)
455                     && filter.hasAction(Intent.ACTION_PACKAGE_REPLACED)
456                     && filter.hasAction(Intent.ACTION_PACKAGE_REMOVED)
457                     && filter.hasAction(Intent.ACTION_PACKAGE_DATA_CLEARED)
458                     && filter.hasAction(Intent.ACTION_PACKAGE_FULLY_REMOVED);
459         }), any(), any());
460         return captor.getValue();
461     }
462 
startAndGetVcnInstance(ParcelUuid uuid)463     private Vcn startAndGetVcnInstance(ParcelUuid uuid) {
464         mVcnMgmtSvc.setVcnConfig(uuid, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
465         return mVcnMgmtSvc.getAllVcns().get(uuid);
466     }
467 
468     @Test
testTelephonyNetworkTrackerCallbackStartsInstances()469     public void testTelephonyNetworkTrackerCallbackStartsInstances() throws Exception {
470         // Add a record for a non-active SIM
471         mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
472 
473         TelephonySubscriptionSnapshot snapshot =
474                 triggerSubscriptionTrackerCbAndGetSnapshot(
475                         TEST_UUID_1, new ArraySet<>(Arrays.asList(TEST_UUID_1, TEST_UUID_2)));
476         verify(mMockDeps)
477                 .newVcnContext(
478                         eq(mMockContext),
479                         eq(mTestLooper.getLooper()),
480                         any(VcnNetworkProvider.class),
481                         anyBoolean());
482 
483         // Verify that only the VCN for the active data SIM was started.
484         verify(mMockDeps)
485                 .newVcn(eq(mVcnContext), eq(TEST_UUID_1), eq(TEST_VCN_CONFIG), eq(snapshot), any());
486         verify(mMockDeps, never())
487                 .newVcn(eq(mVcnContext), eq(TEST_UUID_2), eq(TEST_VCN_CONFIG), eq(snapshot), any());
488     }
489 
490     @Test
testTelephonyNetworkTrackerCallbackSwitchingActiveDataStartsAndStopsInstances()491     public void testTelephonyNetworkTrackerCallbackSwitchingActiveDataStartsAndStopsInstances()
492             throws Exception {
493         // Add a record for a non-active SIM
494         mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
495         final Vcn vcn = startAndGetVcnInstance(TEST_UUID_1);
496 
497         TelephonySubscriptionSnapshot snapshot =
498                 triggerSubscriptionTrackerCbAndGetSnapshot(
499                         TEST_UUID_2, new ArraySet<>(Arrays.asList(TEST_UUID_1, TEST_UUID_2)));
500 
501         // Verify that a new VCN for UUID_2 was started, and the old instance was torn down
502         // immediately
503         verify(mMockDeps)
504                 .newVcn(eq(mVcnContext), eq(TEST_UUID_2), eq(TEST_VCN_CONFIG), eq(snapshot), any());
505         verify(vcn).teardownAsynchronously();
506         assertEquals(1, mVcnMgmtSvc.getAllVcns().size());
507         assertFalse(mVcnMgmtSvc.getAllVcns().containsKey(TEST_UUID_1));
508         assertTrue(mVcnMgmtSvc.getAllVcns().containsKey(TEST_UUID_2));
509     }
510 
511     @Test
testTelephonyNetworkTrackerCallbackStopsInstances()512     public void testTelephonyNetworkTrackerCallbackStopsInstances() throws Exception {
513         setupActiveSubscription(TEST_UUID_2);
514 
515         final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback();
516         final Vcn vcn = startAndGetVcnInstance(TEST_UUID_2);
517         mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
518 
519         triggerSubscriptionTrackerCbAndGetSnapshot(null, Collections.emptySet());
520 
521         // Verify teardown after delay
522         mTestLooper.moveTimeForward(VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS);
523         mTestLooper.dispatchAll();
524         verify(vcn).teardownAsynchronously();
525         verify(mMockPolicyListener).onPolicyChanged();
526     }
527 
528     @Test
testTelephonyNetworkTrackerCallbackSwitchToNewSubscriptionImmediatelyTearsDown()529     public void testTelephonyNetworkTrackerCallbackSwitchToNewSubscriptionImmediatelyTearsDown()
530             throws Exception {
531         setupActiveSubscription(TEST_UUID_2);
532 
533         final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback();
534         final Vcn vcn = startAndGetVcnInstance(TEST_UUID_2);
535 
536         // Simulate switch to different default data subscription that does not have a VCN.
537         triggerSubscriptionTrackerCbAndGetSnapshot(
538                 TEST_SUBSCRIPTION_ID,
539                 null /* activeDataSubscriptionGroup */,
540                 Collections.emptySet(),
541                 Collections.emptyMap(),
542                 false /* hasCarrierPrivileges */);
543         mTestLooper.dispatchAll();
544 
545         verify(vcn).teardownAsynchronously();
546         assertEquals(0, mVcnMgmtSvc.getAllVcns().size());
547     }
548 
549     /**
550      * Tests an intermediate state where carrier privileges are marked as lost before active data
551      * subId changes during a SIM ejection.
552      *
553      * <p>The expected outcome is that the VCN is torn down after a delay, as opposed to
554      * immediately.
555      */
556     @Test
testTelephonyNetworkTrackerCallbackLostCarrierPrivilegesBeforeActiveDataSubChanges()557     public void testTelephonyNetworkTrackerCallbackLostCarrierPrivilegesBeforeActiveDataSubChanges()
558             throws Exception {
559         setupActiveSubscription(TEST_UUID_2);
560 
561         final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback();
562         final Vcn vcn = startAndGetVcnInstance(TEST_UUID_2);
563 
564         // Simulate privileges lost
565         triggerSubscriptionTrackerCbAndGetSnapshot(
566                 TEST_SUBSCRIPTION_ID,
567                 TEST_UUID_2,
568                 Collections.emptySet(),
569                 Collections.emptyMap(),
570                 false /* hasCarrierPrivileges */);
571 
572         // Verify teardown after delay
573         mTestLooper.moveTimeForward(VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS);
574         mTestLooper.dispatchAll();
575         verify(vcn).teardownAsynchronously();
576     }
577 
578     @Test
testTelephonyNetworkTrackerCallbackSimSwitchesDoNotKillVcnInstances()579     public void testTelephonyNetworkTrackerCallbackSimSwitchesDoNotKillVcnInstances()
580             throws Exception {
581         setupActiveSubscription(TEST_UUID_2);
582 
583         final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback();
584         final Vcn vcn = startAndGetVcnInstance(TEST_UUID_2);
585 
586         // Simulate SIM unloaded
587         triggerSubscriptionTrackerCbAndGetSnapshot(
588                 INVALID_SUBSCRIPTION_ID,
589                 null /* activeDataSubscriptionGroup */,
590                 Collections.emptySet(),
591                 Collections.emptyMap(),
592                 false /* hasCarrierPrivileges */);
593 
594         // Simulate new SIM loaded right during teardown delay.
595         mTestLooper.moveTimeForward(
596                 VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS / 2);
597         mTestLooper.dispatchAll();
598         triggerSubscriptionTrackerCbAndGetSnapshot(TEST_UUID_2, Collections.singleton(TEST_UUID_2));
599 
600         // Verify that even after the full timeout duration, the VCN instance is not torn down
601         mTestLooper.moveTimeForward(VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS);
602         mTestLooper.dispatchAll();
603         verify(vcn, never()).teardownAsynchronously();
604     }
605 
606     @Test
testTelephonyNetworkTrackerCallbackDoesNotKillNewVcnInstances()607     public void testTelephonyNetworkTrackerCallbackDoesNotKillNewVcnInstances() throws Exception {
608         setupActiveSubscription(TEST_UUID_2);
609 
610         final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback();
611         final Vcn oldInstance = startAndGetVcnInstance(TEST_UUID_2);
612 
613         // Simulate SIM unloaded
614         triggerSubscriptionTrackerCbAndGetSnapshot(null, Collections.emptySet());
615 
616         // Config cleared, SIM reloaded & config re-added right before teardown delay, staring new
617         // vcnInstance.
618         mTestLooper.moveTimeForward(
619                 VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS / 2);
620         mTestLooper.dispatchAll();
621         mVcnMgmtSvc.clearVcnConfig(TEST_UUID_2, TEST_PACKAGE_NAME);
622         triggerSubscriptionTrackerCbAndGetSnapshot(TEST_UUID_2, Collections.singleton(TEST_UUID_2));
623         final Vcn newInstance = startAndGetVcnInstance(TEST_UUID_2);
624 
625         // Verify that new instance was different, and the old one was torn down
626         assertTrue(oldInstance != newInstance);
627         verify(oldInstance).teardownAsynchronously();
628 
629         // Verify that even after the full timeout duration, the new VCN instance is not torn down
630         mTestLooper.moveTimeForward(VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS);
631         mTestLooper.dispatchAll();
632         verify(newInstance, never()).teardownAsynchronously();
633     }
634 
635     @Test
testPackageChangeListenerRegistered()636     public void testPackageChangeListenerRegistered() throws Exception {
637         verify(mMockContext).registerReceiver(any(BroadcastReceiver.class), argThat(filter -> {
638             return filter.hasAction(Intent.ACTION_PACKAGE_ADDED)
639                     && filter.hasAction(Intent.ACTION_PACKAGE_REPLACED)
640                     && filter.hasAction(Intent.ACTION_PACKAGE_REMOVED);
641         }), any(), any());
642     }
643 
644     @Test
testPackageChangeListener_packageAdded()645     public void testPackageChangeListener_packageAdded() throws Exception {
646         final BroadcastReceiver receiver = getPackageChangeReceiver();
647 
648         verify(mMockContext).registerReceiver(any(), argThat(filter -> {
649             return filter.hasAction(Intent.ACTION_PACKAGE_ADDED)
650                     && filter.hasAction(Intent.ACTION_PACKAGE_REPLACED)
651                     && filter.hasAction(Intent.ACTION_PACKAGE_REMOVED);
652         }), any(), any());
653 
654         receiver.onReceive(mMockContext, new Intent(Intent.ACTION_PACKAGE_ADDED));
655         verify(mSubscriptionTracker).handleSubscriptionsChanged();
656     }
657 
658     @Test
testPackageChangeListener_packageRemoved()659     public void testPackageChangeListener_packageRemoved() throws Exception {
660         final BroadcastReceiver receiver = getPackageChangeReceiver();
661 
662         verify(mMockContext).registerReceiver(any(), argThat(filter -> {
663             return filter.hasAction(Intent.ACTION_PACKAGE_REMOVED);
664         }), any(), any());
665 
666         receiver.onReceive(mMockContext, new Intent(Intent.ACTION_PACKAGE_REMOVED));
667         verify(mSubscriptionTracker).handleSubscriptionsChanged();
668     }
669 
670     @Test
testPackageChangeListener_packageDataCleared()671     public void testPackageChangeListener_packageDataCleared() throws Exception {
672         triggerSubscriptionTrackerCbAndGetSnapshot(TEST_UUID_1, Collections.singleton(TEST_UUID_1));
673         final Vcn vcn = mVcnMgmtSvc.getAllVcns().get(TEST_UUID_1);
674 
675         final BroadcastReceiver receiver = getPackageChangeReceiver();
676         assertEquals(TEST_VCN_CONFIG_MAP, mVcnMgmtSvc.getConfigs());
677 
678         final Intent intent = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED);
679         intent.setData(Uri.parse("package:" + TEST_PACKAGE_NAME));
680         intent.putExtra(Intent.EXTRA_USER_HANDLE, UserHandle.getUserId(TEST_UID));
681 
682         receiver.onReceive(mMockContext, intent);
683         mTestLooper.dispatchAll();
684         verify(vcn).teardownAsynchronously();
685         assertTrue(mVcnMgmtSvc.getConfigs().isEmpty());
686         verify(mConfigReadWriteHelper).writeToDisk(any(PersistableBundle.class));
687     }
688 
689     @Test
testPackageChangeListener_packageFullyRemoved()690     public void testPackageChangeListener_packageFullyRemoved() throws Exception {
691         triggerSubscriptionTrackerCbAndGetSnapshot(TEST_UUID_1, Collections.singleton(TEST_UUID_1));
692         final Vcn vcn = mVcnMgmtSvc.getAllVcns().get(TEST_UUID_1);
693 
694         final BroadcastReceiver receiver = getPackageChangeReceiver();
695         assertEquals(TEST_VCN_CONFIG_MAP, mVcnMgmtSvc.getConfigs());
696 
697         final Intent intent = new Intent(Intent.ACTION_PACKAGE_FULLY_REMOVED);
698         intent.setData(Uri.parse("package:" + TEST_PACKAGE_NAME));
699         intent.putExtra(Intent.EXTRA_USER_HANDLE, UserHandle.getUserId(TEST_UID));
700 
701         receiver.onReceive(mMockContext, intent);
702         mTestLooper.dispatchAll();
703         verify(vcn).teardownAsynchronously();
704         assertTrue(mVcnMgmtSvc.getConfigs().isEmpty());
705         verify(mConfigReadWriteHelper).writeToDisk(any(PersistableBundle.class));
706     }
707 
708     @Test
testSetVcnConfigRequiresNonSystemServer()709     public void testSetVcnConfigRequiresNonSystemServer() throws Exception {
710         doReturn(Process.SYSTEM_UID).when(mMockDeps).getBinderCallingUid();
711 
712         try {
713             mVcnMgmtSvc.setVcnConfig(TEST_UUID_1, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
714             fail("Expected IllegalStateException exception for system server");
715         } catch (IllegalStateException expected) {
716         }
717     }
718 
719     @Test
testSetVcnConfigRequiresSystemUser()720     public void testSetVcnConfigRequiresSystemUser() throws Exception {
721         doReturn(UserHandle.getUid(UserHandle.MIN_SECONDARY_USER_ID, TEST_UID))
722                 .when(mMockDeps)
723                 .getBinderCallingUid();
724 
725         try {
726             mVcnMgmtSvc.setVcnConfig(TEST_UUID_1, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
727             fail("Expected security exception for non system user");
728         } catch (SecurityException expected) {
729             verify(mMockPolicyListener, never()).onPolicyChanged();
730         }
731     }
732 
733     @Test
testSetVcnConfigRequiresCarrierPrivileges()734     public void testSetVcnConfigRequiresCarrierPrivileges() throws Exception {
735         setupMockedCarrierPrivilege(false);
736 
737         try {
738             mVcnMgmtSvc.setVcnConfig(TEST_UUID_1, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
739             fail("Expected security exception for missing carrier privileges");
740         } catch (SecurityException expected) {
741             verify(mMockPolicyListener, never()).onPolicyChanged();
742         }
743     }
744 
745     @Test
testSetVcnConfigMismatchedPackages()746     public void testSetVcnConfigMismatchedPackages() throws Exception {
747         try {
748             mVcnMgmtSvc.setVcnConfig(TEST_UUID_1, TEST_VCN_CONFIG, TEST_PACKAGE_NAME_2);
749             fail("Expected exception due to mismatched packages in config and method call");
750         } catch (IllegalArgumentException expected) {
751             verify(mMockPolicyListener, never()).onPolicyChanged();
752         }
753     }
754 
755     @Test
testSetVcnConfig()756     public void testSetVcnConfig() throws Exception {
757         // Use a different UUID to simulate a new VCN config.
758         mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
759         assertEquals(TEST_VCN_CONFIG, mVcnMgmtSvc.getConfigs().get(TEST_UUID_2));
760         verify(mConfigReadWriteHelper).writeToDisk(any(PersistableBundle.class));
761     }
762 
763     @Test
testSetVcnConfigNonActiveSimDoesNotStartVcn()764     public void testSetVcnConfigNonActiveSimDoesNotStartVcn() throws Exception {
765         // Use a different UUID to simulate a new VCN config.
766         mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
767         assertEquals(TEST_VCN_CONFIG, mVcnMgmtSvc.getConfigs().get(TEST_UUID_2));
768         verify(mConfigReadWriteHelper).writeToDisk(any(PersistableBundle.class));
769 
770         verify(mMockDeps, never()).newVcn(any(), any(), any(), any(), any());
771     }
772 
773     @Test
testSetVcnConfigActiveSimTearsDownExistingVcnsImmediately()774     public void testSetVcnConfigActiveSimTearsDownExistingVcnsImmediately() throws Exception {
775         final Vcn vcn = startAndGetVcnInstance(TEST_UUID_1);
776 
777         // Use a different UUID to simulate a new VCN config.
778         setupActiveSubscription(TEST_UUID_2);
779         mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
780 
781         verify(mMockDeps, times(2)).newVcn(any(), any(), any(), any(), any());
782         verify(vcn).teardownAsynchronously();
783         assertEquals(1, mVcnMgmtSvc.getAllVcns().size());
784         assertFalse(mVcnMgmtSvc.getAllVcns().containsKey(TEST_UUID_1));
785         assertTrue(mVcnMgmtSvc.getAllVcns().containsKey(TEST_UUID_2));
786     }
787 
788     @Test
testSetVcnConfigTestModeRequiresPermission()789     public void testSetVcnConfigTestModeRequiresPermission() throws Exception {
790         doThrow(new SecurityException("Requires MANAGE_TEST_NETWORKS"))
791                 .when(mMockContext)
792                 .enforceCallingPermission(
793                         eq(android.Manifest.permission.MANAGE_TEST_NETWORKS), any());
794 
795         final VcnConfig vcnConfig =
796                 new VcnConfig.Builder(mMockContext)
797                         .addGatewayConnectionConfig(
798                                 VcnGatewayConnectionConfigTest.buildTestConfig())
799                         .setIsTestModeProfile()
800                         .build();
801 
802         try {
803             mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, vcnConfig, TEST_PACKAGE_NAME);
804             fail("Expected exception due to using test-mode without permission");
805         } catch (SecurityException e) {
806             verify(mMockPolicyListener, never()).onPolicyChanged();
807         }
808     }
809 
810     @Test
testSetVcnConfigNotifiesStatusCallback()811     public void testSetVcnConfigNotifiesStatusCallback() throws Exception {
812         triggerSubscriptionTrackerCbAndGetSnapshot(TEST_UUID_2, Collections.singleton(TEST_UUID_2));
813 
814         mVcnMgmtSvc.registerVcnStatusCallback(TEST_UUID_2, mMockStatusCallback, TEST_PACKAGE_NAME);
815         verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_NOT_CONFIGURED);
816 
817         // Use a different UUID to simulate a new VCN config.
818         mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
819 
820         verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_ACTIVE);
821     }
822 
823     @Test
testClearVcnConfigRequiresNonSystemServer()824     public void testClearVcnConfigRequiresNonSystemServer() throws Exception {
825         doReturn(Process.SYSTEM_UID).when(mMockDeps).getBinderCallingUid();
826 
827         try {
828             mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1, TEST_PACKAGE_NAME);
829             fail("Expected IllegalStateException exception for system server");
830         } catch (IllegalStateException expected) {
831         }
832     }
833 
834     @Test
testClearVcnConfigRequiresSystemUser()835     public void testClearVcnConfigRequiresSystemUser() throws Exception {
836         doReturn(UserHandle.getUid(UserHandle.MIN_SECONDARY_USER_ID, TEST_UID))
837                 .when(mMockDeps)
838                 .getBinderCallingUid();
839 
840         try {
841             mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1, TEST_PACKAGE_NAME);
842             fail("Expected security exception for non system user");
843         } catch (SecurityException expected) {
844         }
845     }
846 
847     @Test
testClearVcnConfigRequiresCarrierPrivilegesOrProvisioningPackage()848     public void testClearVcnConfigRequiresCarrierPrivilegesOrProvisioningPackage()
849             throws Exception {
850         setupMockedCarrierPrivilege(false);
851 
852         try {
853             mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1, TEST_PACKAGE_NAME_2);
854             fail("Expected security exception for missing carrier privileges");
855         } catch (SecurityException expected) {
856         }
857     }
858 
859     @Test
testClearVcnConfigMismatchedPackages()860     public void testClearVcnConfigMismatchedPackages() throws Exception {
861         try {
862             mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1, TEST_PACKAGE_NAME_2);
863             fail("Expected security exception due to mismatched packages");
864         } catch (SecurityException expected) {
865         }
866     }
867 
868     @Test
testClearVcnConfig_callerIsProvisioningPackage()869     public void testClearVcnConfig_callerIsProvisioningPackage() throws Exception {
870         // Lose carrier privileges to test that provisioning package is sufficient.
871         setupMockedCarrierPrivilege(false);
872 
873         mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1, TEST_PACKAGE_NAME);
874         assertTrue(mVcnMgmtSvc.getConfigs().isEmpty());
875         verify(mConfigReadWriteHelper).writeToDisk(any(PersistableBundle.class));
876     }
877 
878     @Test
testClearVcnConfig_callerIsCarrierPrivileged()879     public void testClearVcnConfig_callerIsCarrierPrivileged() throws Exception {
880         setupMockedCarrierPrivilege(true, TEST_PACKAGE_NAME_2);
881 
882         mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1, TEST_PACKAGE_NAME_2);
883         assertTrue(mVcnMgmtSvc.getConfigs().isEmpty());
884         verify(mConfigReadWriteHelper).writeToDisk(any(PersistableBundle.class));
885     }
886 
887     @Test
testClearVcnConfigNotifiesStatusCallback()888     public void testClearVcnConfigNotifiesStatusCallback() throws Exception {
889         setupSubscriptionAndStartVcn(TEST_SUBSCRIPTION_ID, TEST_UUID_2, true /* isActive */);
890         mVcnMgmtSvc.registerVcnStatusCallback(TEST_UUID_2, mMockStatusCallback, TEST_PACKAGE_NAME);
891         verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_ACTIVE);
892 
893         mVcnMgmtSvc.clearVcnConfig(TEST_UUID_2, TEST_PACKAGE_NAME);
894 
895         verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_NOT_CONFIGURED);
896     }
897 
898     @Test
testSetVcnConfigClearVcnConfigStartsUpdatesAndTearsDownVcns()899     public void testSetVcnConfigClearVcnConfigStartsUpdatesAndTearsDownVcns() throws Exception {
900         setupActiveSubscription(TEST_UUID_2);
901 
902         // Use a different UUID to simulate a new VCN config.
903         mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
904         final Map<ParcelUuid, Vcn> vcnInstances = mVcnMgmtSvc.getAllVcns();
905         final Vcn vcnInstance = vcnInstances.get(TEST_UUID_2);
906         assertEquals(1, vcnInstances.size());
907         assertEquals(TEST_VCN_CONFIG, mVcnMgmtSvc.getConfigs().get(TEST_UUID_2));
908         verify(mConfigReadWriteHelper).writeToDisk(any(PersistableBundle.class));
909 
910         // Verify Vcn is started
911         verify(mMockDeps)
912                 .newVcn(eq(mVcnContext), eq(TEST_UUID_2), eq(TEST_VCN_CONFIG), any(), any());
913 
914         // Verify Vcn is updated if it was previously started
915         mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
916         verify(vcnInstance).updateConfig(TEST_VCN_CONFIG);
917 
918         // Verify Vcn is stopped if it was already started
919         mVcnMgmtSvc.clearVcnConfig(TEST_UUID_2, TEST_PACKAGE_NAME);
920         verify(vcnInstance).teardownAsynchronously();
921     }
922 
923     @Test
testGetConfiguredSubscriptionGroupsRequiresSystemUser()924     public void testGetConfiguredSubscriptionGroupsRequiresSystemUser() throws Exception {
925         doReturn(UserHandle.getUid(UserHandle.MIN_SECONDARY_USER_ID, TEST_UID))
926                 .when(mMockDeps)
927                 .getBinderCallingUid();
928 
929         try {
930             mVcnMgmtSvc.getConfiguredSubscriptionGroups(TEST_PACKAGE_NAME);
931             fail("Expected security exception for non system user");
932         } catch (SecurityException expected) {
933         }
934     }
935 
936     @Test
testGetConfiguredSubscriptionGroupsMismatchedPackages()937     public void testGetConfiguredSubscriptionGroupsMismatchedPackages() throws Exception {
938         doThrow(new SecurityException())
939                 .when(mAppOpsMgr)
940                 .checkPackage(TEST_UID, TEST_PACKAGE_NAME_2);
941 
942         try {
943             mVcnMgmtSvc.getConfiguredSubscriptionGroups(TEST_PACKAGE_NAME_2);
944             fail("Expected security exception due to mismatched packages");
945         } catch (SecurityException expected) {
946         }
947     }
948 
949     @Test
testGetConfiguredSubscriptionGroups()950     public void testGetConfiguredSubscriptionGroups() throws Exception {
951         setupMockedCarrierPrivilege(true, TEST_PACKAGE_NAME_2);
952         mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
953         mVcnMgmtSvc.setVcnConfig(TEST_UUID_3, TEST_VCN_CONFIG_PKG_2, TEST_PACKAGE_NAME_2);
954 
955         // Assert that if UUIDs 1, 2 and 3 are provisioned, the caller only gets ones that they are
956         // privileged for, or are the provisioning package of.
957         triggerSubscriptionTrackerCbAndGetSnapshot(TEST_UUID_1, Collections.singleton(TEST_UUID_1));
958         final List<ParcelUuid> subGrps =
959                 mVcnMgmtSvc.getConfiguredSubscriptionGroups(TEST_PACKAGE_NAME);
960         assertEquals(Arrays.asList(new ParcelUuid[] {TEST_UUID_1, TEST_UUID_2}), subGrps);
961     }
962 
963     @Test
testAddVcnUnderlyingNetworkPolicyListener()964     public void testAddVcnUnderlyingNetworkPolicyListener() throws Exception {
965         mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
966 
967         verify(mMockIBinder).linkToDeath(any(), anyInt());
968     }
969 
970     @Test(expected = SecurityException.class)
testAddVcnUnderlyingNetworkPolicyListenerInvalidPermission()971     public void testAddVcnUnderlyingNetworkPolicyListenerInvalidPermission() {
972         doReturn(PackageManager.PERMISSION_DENIED)
973                 .when(mMockContext)
974                 .checkCallingOrSelfPermission(any());
975 
976         mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
977     }
978 
979     @Test
testRemoveVcnUnderlyingNetworkPolicyListener()980     public void testRemoveVcnUnderlyingNetworkPolicyListener() {
981         mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
982 
983         mVcnMgmtSvc.removeVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
984     }
985 
986     @Test(expected = SecurityException.class)
testRemoveVcnUnderlyingNetworkPolicyListenerInvalidPermission()987     public void testRemoveVcnUnderlyingNetworkPolicyListenerInvalidPermission() {
988         doReturn(PackageManager.PERMISSION_DENIED)
989                 .when(mMockContext)
990                 .checkCallingOrSelfPermission(any());
991 
992         mVcnMgmtSvc.removeVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
993     }
994 
995     @Test
testRemoveVcnUnderlyingNetworkPolicyListenerNeverRegistered()996     public void testRemoveVcnUnderlyingNetworkPolicyListenerNeverRegistered() {
997         mVcnMgmtSvc.removeVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
998     }
999 
verifyMergedNetworkCapabilities( NetworkCapabilities mergedCapabilities, int transportType, boolean isVcnManaged, boolean isRestricted)1000     private void verifyMergedNetworkCapabilities(
1001             NetworkCapabilities mergedCapabilities,
1002             int transportType,
1003             boolean isVcnManaged,
1004             boolean isRestricted) {
1005         assertTrue(mergedCapabilities.hasTransport(transportType));
1006         assertEquals(
1007                 !isVcnManaged,
1008                 mergedCapabilities.hasCapability(
1009                         NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED));
1010         assertEquals(
1011                 !isRestricted,
1012                 mergedCapabilities.hasCapability(
1013                         NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED));
1014     }
1015 
setupSubscriptionAndStartVcn(int subId, ParcelUuid subGrp, boolean isVcnActive)1016     private void setupSubscriptionAndStartVcn(int subId, ParcelUuid subGrp, boolean isVcnActive) {
1017         setupSubscriptionAndStartVcn(subId, subGrp, isVcnActive, true /* hasCarrierPrivileges */);
1018     }
1019 
setupSubscriptionAndStartVcn( int subId, ParcelUuid subGrp, boolean isVcnActive, boolean hasCarrierPrivileges)1020     private void setupSubscriptionAndStartVcn(
1021             int subId, ParcelUuid subGrp, boolean isVcnActive, boolean hasCarrierPrivileges) {
1022         mVcnMgmtSvc.systemReady();
1023         triggerSubscriptionTrackerCbAndGetSnapshot(
1024                 subGrp,
1025                 Collections.singleton(subGrp),
1026                 Collections.singletonMap(subId, subGrp),
1027                 hasCarrierPrivileges);
1028 
1029         final Vcn vcn = startAndGetVcnInstance(subGrp);
1030         doReturn(isVcnActive ? VCN_STATUS_CODE_ACTIVE : VCN_STATUS_CODE_SAFE_MODE)
1031                 .when(vcn)
1032                 .getStatus();
1033     }
1034 
getNetworkCapabilitiesBuilderForTransport( int subId, int transport)1035     private NetworkCapabilities.Builder getNetworkCapabilitiesBuilderForTransport(
1036             int subId, int transport) {
1037         final NetworkCapabilities.Builder ncBuilder =
1038                 new NetworkCapabilities.Builder()
1039                         .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
1040                         .addTransportType(transport);
1041         if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
1042             ncBuilder.setSubscriptionIds(Collections.singleton(subId));
1043         }
1044 
1045         return ncBuilder;
1046     }
1047 
startVcnAndGetPolicyForTransport( int subId, ParcelUuid subGrp, boolean isVcnActive, int transport)1048     private VcnUnderlyingNetworkPolicy startVcnAndGetPolicyForTransport(
1049             int subId, ParcelUuid subGrp, boolean isVcnActive, int transport) {
1050         setupSubscriptionAndStartVcn(subId, subGrp, isVcnActive);
1051 
1052         return mVcnMgmtSvc.getUnderlyingNetworkPolicy(
1053                 getNetworkCapabilitiesBuilderForTransport(subId, transport).build(), TEST_LP_1);
1054     }
1055 
checkGetRestrictedTransportsFromCarrierConfig( ParcelUuid subGrp, TelephonySubscriptionSnapshot lastSnapshot, Set<Integer> expectedTransports)1056     private void checkGetRestrictedTransportsFromCarrierConfig(
1057             ParcelUuid subGrp,
1058             TelephonySubscriptionSnapshot lastSnapshot,
1059             Set<Integer> expectedTransports) {
1060         Set<Integer> result =
1061                 new VcnManagementService.Dependencies()
1062                         .getRestrictedTransportsFromCarrierConfig(subGrp, lastSnapshot);
1063         assertEquals(expectedTransports, result);
1064     }
1065 
1066     @Test
testGetRestrictedTransportsFromCarrierConfig()1067     public void testGetRestrictedTransportsFromCarrierConfig() {
1068         final Set<Integer> restrictedTransports = new ArraySet<>();
1069         restrictedTransports.add(TRANSPORT_CELLULAR);
1070         restrictedTransports.add(TRANSPORT_WIFI);
1071 
1072         PersistableBundle carrierConfigBundle = new PersistableBundle();
1073         carrierConfigBundle.putIntArray(
1074                 VCN_RESTRICTED_TRANSPORTS_INT_ARRAY_KEY,
1075                 restrictedTransports.stream().mapToInt(i -> i).toArray());
1076         final PersistableBundleWrapper carrierConfig =
1077                 new PersistableBundleWrapper(carrierConfigBundle);
1078 
1079         final TelephonySubscriptionSnapshot lastSnapshot =
1080                 mock(TelephonySubscriptionSnapshot.class);
1081         doReturn(carrierConfig).when(lastSnapshot).getCarrierConfigForSubGrp(eq(TEST_UUID_2));
1082 
1083         checkGetRestrictedTransportsFromCarrierConfig(
1084                 TEST_UUID_2, lastSnapshot, restrictedTransports);
1085     }
1086 
1087     @Test
testGetRestrictedTransportsFromCarrierConfig_noRestrictPolicyConfigured()1088     public void testGetRestrictedTransportsFromCarrierConfig_noRestrictPolicyConfigured() {
1089         final Set<Integer> restrictedTransports = Collections.singleton(TRANSPORT_WIFI);
1090 
1091         final PersistableBundleWrapper carrierConfig =
1092                 new PersistableBundleWrapper(new PersistableBundle());
1093         final TelephonySubscriptionSnapshot lastSnapshot =
1094                 mock(TelephonySubscriptionSnapshot.class);
1095         doReturn(carrierConfig).when(lastSnapshot).getCarrierConfigForSubGrp(eq(TEST_UUID_2));
1096 
1097         checkGetRestrictedTransportsFromCarrierConfig(
1098                 TEST_UUID_2, lastSnapshot, restrictedTransports);
1099     }
1100 
1101     @Test
testGetRestrictedTransportsFromCarrierConfig_noCarrierConfig()1102     public void testGetRestrictedTransportsFromCarrierConfig_noCarrierConfig() {
1103         final Set<Integer> restrictedTransports = Collections.singleton(TRANSPORT_WIFI);
1104 
1105         final TelephonySubscriptionSnapshot lastSnapshot =
1106                 mock(TelephonySubscriptionSnapshot.class);
1107 
1108         checkGetRestrictedTransportsFromCarrierConfig(
1109                 TEST_UUID_2, lastSnapshot, restrictedTransports);
1110     }
1111 
1112     @Test
testGetRestrictedTransportsFromCarrierConfigAndVcnConfig()1113     public void testGetRestrictedTransportsFromCarrierConfigAndVcnConfig() {
1114         // Configure restricted transport in CarrierConfig
1115         final Set<Integer> restrictedTransportInCarrierConfig =
1116                 Collections.singleton(TRANSPORT_WIFI);
1117 
1118         PersistableBundle carrierConfigBundle = new PersistableBundle();
1119         carrierConfigBundle.putIntArray(
1120                 VCN_RESTRICTED_TRANSPORTS_INT_ARRAY_KEY,
1121                 restrictedTransportInCarrierConfig.stream().mapToInt(i -> i).toArray());
1122         final PersistableBundleWrapper carrierConfig =
1123                 new PersistableBundleWrapper(carrierConfigBundle);
1124 
1125         final TelephonySubscriptionSnapshot lastSnapshot =
1126                 mock(TelephonySubscriptionSnapshot.class);
1127         doReturn(carrierConfig).when(lastSnapshot).getCarrierConfigForSubGrp(eq(TEST_UUID_2));
1128 
1129         // Configure restricted transport in VcnConfig
1130         final Context mockContext = mock(Context.class);
1131         doReturn(TEST_PACKAGE_NAME).when(mockContext).getOpPackageName();
1132         final VcnConfig vcnConfig =
1133                 VcnConfigTest.buildTestConfig(
1134                         mockContext, Collections.singleton(TRANSPORT_CELLULAR));
1135 
1136         // Verifications
1137         final Set<Integer> expectedTransports = new ArraySet<>();
1138         expectedTransports.add(TRANSPORT_CELLULAR);
1139         expectedTransports.add(TRANSPORT_WIFI);
1140 
1141         Set<Integer> result =
1142                 new VcnManagementService.Dependencies()
1143                         .getRestrictedTransports(TEST_UUID_2, lastSnapshot, vcnConfig);
1144         assertEquals(expectedTransports, result);
1145     }
1146 
checkGetUnderlyingNetworkPolicy( int transportType, boolean isTransportRestricted, boolean isActive, boolean expectVcnManaged, boolean expectRestricted)1147     private void checkGetUnderlyingNetworkPolicy(
1148             int transportType,
1149             boolean isTransportRestricted,
1150             boolean isActive,
1151             boolean expectVcnManaged,
1152             boolean expectRestricted)
1153             throws Exception {
1154 
1155         final Set<Integer> restrictedTransports = new ArraySet();
1156         if (isTransportRestricted) {
1157             restrictedTransports.add(transportType);
1158         }
1159         doReturn(restrictedTransports).when(mMockDeps).getRestrictedTransports(any(), any(), any());
1160 
1161         final VcnUnderlyingNetworkPolicy policy =
1162                 startVcnAndGetPolicyForTransport(
1163                         TEST_SUBSCRIPTION_ID, TEST_UUID_2, isActive, transportType);
1164 
1165         assertFalse(policy.isTeardownRequested());
1166         verifyMergedNetworkCapabilities(
1167                 policy.getMergedNetworkCapabilities(),
1168                 transportType,
1169                 expectVcnManaged,
1170                 expectRestricted);
1171     }
1172 
1173     @Test
testGetUnderlyingNetworkPolicy_unrestrictCell()1174     public void testGetUnderlyingNetworkPolicy_unrestrictCell() throws Exception {
1175         checkGetUnderlyingNetworkPolicy(
1176                 TRANSPORT_CELLULAR,
1177                 false /* isTransportRestricted */,
1178                 true /* isActive */,
1179                 true /* expectVcnManaged */,
1180                 false /* expectRestricted */);
1181     }
1182 
1183     @Test
testGetUnderlyingNetworkPolicy_unrestrictCellSafeMode()1184     public void testGetUnderlyingNetworkPolicy_unrestrictCellSafeMode() throws Exception {
1185         checkGetUnderlyingNetworkPolicy(
1186                 TRANSPORT_CELLULAR,
1187                 false /* isTransportRestricted */,
1188                 false /* isActive */,
1189                 false /* expectVcnManaged */,
1190                 false /* expectRestricted */);
1191     }
1192 
1193     @Test
testGetUnderlyingNetworkPolicy_restrictCell()1194     public void testGetUnderlyingNetworkPolicy_restrictCell() throws Exception {
1195         checkGetUnderlyingNetworkPolicy(
1196                 TRANSPORT_CELLULAR,
1197                 true /* isTransportRestricted */,
1198                 true /* isActive */,
1199                 true /* expectVcnManaged */,
1200                 true /* expectRestricted */);
1201     }
1202 
1203     @Test
testGetUnderlyingNetworkPolicy_restrictCellSafeMode()1204     public void testGetUnderlyingNetworkPolicy_restrictCellSafeMode() throws Exception {
1205         checkGetUnderlyingNetworkPolicy(
1206                 TRANSPORT_CELLULAR,
1207                 true /* isTransportRestricted */,
1208                 false /* isActive */,
1209                 false /* expectVcnManaged */,
1210                 false /* expectRestricted */);
1211     }
1212 
1213     @Test
testGetUnderlyingNetworkPolicy_unrestrictWifi()1214     public void testGetUnderlyingNetworkPolicy_unrestrictWifi() throws Exception {
1215         checkGetUnderlyingNetworkPolicy(
1216                 TRANSPORT_WIFI,
1217                 false /* isTransportRestricted */,
1218                 true /* isActive */,
1219                 true /* expectVcnManaged */,
1220                 false /* expectRestricted */);
1221     }
1222 
1223     @Test
testGetUnderlyingNetworkPolicy_unrestrictWifiSafeMode()1224     public void testGetUnderlyingNetworkPolicy_unrestrictWifiSafeMode() throws Exception {
1225         checkGetUnderlyingNetworkPolicy(
1226                 TRANSPORT_WIFI,
1227                 false /* isTransportRestricted */,
1228                 false /* isActive */,
1229                 false /* expectVcnManaged */,
1230                 false /* expectRestricted */);
1231     }
1232 
1233     @Test
testGetUnderlyingNetworkPolicy_restrictWifi()1234     public void testGetUnderlyingNetworkPolicy_restrictWifi() throws Exception {
1235         checkGetUnderlyingNetworkPolicy(
1236                 TRANSPORT_WIFI,
1237                 true /* isTransportRestricted */,
1238                 true /* isActive */,
1239                 true /* expectVcnManaged */,
1240                 true /* expectRestricted */);
1241     }
1242 
1243     @Test
testGetUnderlyingNetworkPolicy_restrictWifiSafeMode()1244     public void testGetUnderlyingNetworkPolicy_restrictWifiSafeMode() throws Exception {
1245         checkGetUnderlyingNetworkPolicy(
1246                 TRANSPORT_WIFI,
1247                 true /* isTransportRestricted */,
1248                 false /* isActive */,
1249                 false /* expectVcnManaged */,
1250                 true /* expectRestricted */);
1251     }
1252 
1253     @Test
testGetUnderlyingNetworkPolicyCell_restrictWifi()1254     public void testGetUnderlyingNetworkPolicyCell_restrictWifi() throws Exception {
1255         doReturn(Collections.singleton(TRANSPORT_WIFI))
1256                 .when(mMockDeps)
1257                 .getRestrictedTransports(any(), any(), any());
1258 
1259         setupSubscriptionAndStartVcn(TEST_SUBSCRIPTION_ID, TEST_UUID_2, true /* isVcnActive */);
1260 
1261         // Get the policy for a cellular network and expect it won't be affected by the wifi
1262         // restriction policy
1263         final VcnUnderlyingNetworkPolicy policy =
1264                 mVcnMgmtSvc.getUnderlyingNetworkPolicy(
1265                         getNetworkCapabilitiesBuilderForTransport(
1266                                         TEST_SUBSCRIPTION_ID, TRANSPORT_CELLULAR)
1267                                 .build(),
1268                         new LinkProperties());
1269 
1270         assertFalse(policy.isTeardownRequested());
1271         verifyMergedNetworkCapabilities(
1272                 policy.getMergedNetworkCapabilities(),
1273                 TRANSPORT_CELLULAR,
1274                 true /* expectVcnManaged */,
1275                 false /* expectRestricted */);
1276     }
1277 
setupTrackedNetwork(NetworkCapabilities caps, LinkProperties lp)1278     private void setupTrackedNetwork(NetworkCapabilities caps, LinkProperties lp) {
1279         mVcnMgmtSvc.systemReady();
1280 
1281         final ArgumentCaptor<NetworkCallback> captor =
1282                 ArgumentCaptor.forClass(NetworkCallback.class);
1283         verify(mConnMgr)
1284                 .registerNetworkCallback(
1285                         eq(new NetworkRequest.Builder().clearCapabilities().build()),
1286                         captor.capture());
1287 
1288         Network mockNetwork = mock(Network.class, CALLS_REAL_METHODS);
1289         captor.getValue().onCapabilitiesChanged(mockNetwork, caps);
1290         captor.getValue().onLinkPropertiesChanged(mockNetwork, lp);
1291     }
1292 
1293     @Test
testGetUnderlyingNetworkPolicyVcnWifi_unrestrictingExistingNetworkRequiresRestart()1294     public void testGetUnderlyingNetworkPolicyVcnWifi_unrestrictingExistingNetworkRequiresRestart()
1295             throws Exception {
1296         final NetworkCapabilities existingNetworkCaps =
1297                 getNetworkCapabilitiesBuilderForTransport(TEST_SUBSCRIPTION_ID, TRANSPORT_WIFI)
1298                         .removeCapability(NET_CAPABILITY_NOT_RESTRICTED)
1299                         .build();
1300         setupTrackedNetwork(existingNetworkCaps, TEST_LP_1);
1301 
1302         // Trigger test without VCN instance alive; expect restart due to change of NOT_RESTRICTED
1303         // immutable capability
1304         final VcnUnderlyingNetworkPolicy policy =
1305                 mVcnMgmtSvc.getUnderlyingNetworkPolicy(
1306                         getNetworkCapabilitiesBuilderForTransport(
1307                                         TEST_SUBSCRIPTION_ID, TRANSPORT_WIFI)
1308                                 .build(),
1309                         TEST_LP_1);
1310         assertTrue(policy.isTeardownRequested());
1311     }
1312 
1313     @Test
testGetUnderlyingNetworkPolicyVcnWifi_restrictingExistingNetworkRequiresRestart()1314     public void testGetUnderlyingNetworkPolicyVcnWifi_restrictingExistingNetworkRequiresRestart()
1315             throws Exception {
1316         final NetworkCapabilities existingNetworkCaps =
1317                 getNetworkCapabilitiesBuilderForTransport(TEST_SUBSCRIPTION_ID, TRANSPORT_WIFI)
1318                         .build();
1319         setupTrackedNetwork(existingNetworkCaps, TEST_LP_1);
1320 
1321         final VcnUnderlyingNetworkPolicy policy =
1322                 startVcnAndGetPolicyForTransport(
1323                         TEST_SUBSCRIPTION_ID, TEST_UUID_2, false /* isActive */, TRANSPORT_WIFI);
1324 
1325         assertTrue(policy.isTeardownRequested());
1326     }
1327 
1328     @Test
testGetUnderlyingNetworkPolicyForRestrictedImsWhenUnrestrictingCell()1329     public void testGetUnderlyingNetworkPolicyForRestrictedImsWhenUnrestrictingCell()
1330             throws Exception {
1331         final NetworkCapabilities existingNetworkCaps =
1332                 getNetworkCapabilitiesBuilderForTransport(TEST_SUBSCRIPTION_ID, TRANSPORT_CELLULAR)
1333                         .addCapability(NET_CAPABILITY_NOT_RESTRICTED)
1334                         .removeCapability(NET_CAPABILITY_IMS)
1335                         .build();
1336         setupTrackedNetwork(existingNetworkCaps, TEST_LP_1);
1337 
1338         final VcnUnderlyingNetworkPolicy policy =
1339                 mVcnMgmtSvc.getUnderlyingNetworkPolicy(
1340                         getNetworkCapabilitiesBuilderForTransport(
1341                                         TEST_SUBSCRIPTION_ID, TRANSPORT_CELLULAR)
1342                                 .addCapability(NET_CAPABILITY_IMS)
1343                                 .removeCapability(NET_CAPABILITY_NOT_RESTRICTED)
1344                                 .build(),
1345                         new LinkProperties());
1346         assertFalse(policy.isTeardownRequested());
1347     }
1348 
1349     @Test
testGetUnderlyingNetworkPolicyNonVcnNetwork()1350     public void testGetUnderlyingNetworkPolicyNonVcnNetwork() throws Exception {
1351         setupSubscriptionAndStartVcn(TEST_SUBSCRIPTION_ID, TEST_UUID_1, true /* isActive */);
1352 
1353         NetworkCapabilities nc =
1354                 new NetworkCapabilities.Builder()
1355                         .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
1356                         .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
1357                         .setSubscriptionIds(Collections.singleton(TEST_SUBSCRIPTION_ID_2))
1358                         .build();
1359 
1360         VcnUnderlyingNetworkPolicy policy =
1361                 mVcnMgmtSvc.getUnderlyingNetworkPolicy(nc, new LinkProperties());
1362 
1363         assertFalse(policy.isTeardownRequested());
1364         assertEquals(nc, policy.getMergedNetworkCapabilities());
1365     }
1366 
1367     /**
1368      * Checks that networks with similar capabilities do not clobber each other.
1369      *
1370      * <p>In previous iterations, the VcnMgmtSvc used capability-matching to check if a network
1371      * undergoing policy checks were the same as an existing networks. However, this meant that if
1372      * there were newly added capabilities that the VCN did not check, two networks differing only
1373      * by that capability would restart each other constantly.
1374      */
1375     @Test
testGetUnderlyingNetworkPolicySimilarNetworks()1376     public void testGetUnderlyingNetworkPolicySimilarNetworks() throws Exception {
1377         NetworkCapabilities nc1 =
1378                 new NetworkCapabilities.Builder()
1379                         .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
1380                         .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
1381                         .addCapability(NET_CAPABILITY_INTERNET)
1382                         .setSubscriptionIds(Collections.singleton(TEST_SUBSCRIPTION_ID_2))
1383                         .build();
1384 
1385         NetworkCapabilities nc2 =
1386                 new NetworkCapabilities.Builder(nc1)
1387                         .addCapability(NET_CAPABILITY_ENTERPRISE)
1388                         .removeCapability(NET_CAPABILITY_NOT_RESTRICTED)
1389                         .build();
1390 
1391         setupTrackedNetwork(nc1, TEST_LP_1);
1392 
1393         VcnUnderlyingNetworkPolicy policy = mVcnMgmtSvc.getUnderlyingNetworkPolicy(nc2, TEST_LP_2);
1394 
1395         assertFalse(policy.isTeardownRequested());
1396         assertEquals(nc2, policy.getMergedNetworkCapabilities());
1397     }
1398 
1399     @Test(expected = SecurityException.class)
testGetUnderlyingNetworkPolicyInvalidPermission()1400     public void testGetUnderlyingNetworkPolicyInvalidPermission() {
1401         doReturn(PackageManager.PERMISSION_DENIED)
1402                 .when(mMockContext)
1403                 .checkCallingOrSelfPermission(any());
1404 
1405         mVcnMgmtSvc.getUnderlyingNetworkPolicy(new NetworkCapabilities(), new LinkProperties());
1406     }
1407 
1408     @Test
testSubscriptionSnapshotUpdateNotifiesVcn()1409     public void testSubscriptionSnapshotUpdateNotifiesVcn() {
1410         setupActiveSubscription(TEST_UUID_2);
1411 
1412         mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
1413         final Map<ParcelUuid, Vcn> vcnInstances = mVcnMgmtSvc.getAllVcns();
1414         final Vcn vcnInstance = vcnInstances.get(TEST_UUID_2);
1415 
1416         TelephonySubscriptionSnapshot snapshot =
1417                 triggerSubscriptionTrackerCbAndGetSnapshot(
1418                         TEST_UUID_2, Collections.singleton(TEST_UUID_2));
1419 
1420         verify(vcnInstance).updateSubscriptionSnapshot(eq(snapshot));
1421     }
1422 
1423     @Test
testAddNewVcnUpdatesPolicyListener()1424     public void testAddNewVcnUpdatesPolicyListener() throws Exception {
1425         setupActiveSubscription(TEST_UUID_2);
1426 
1427         mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
1428 
1429         mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
1430 
1431         verify(mMockPolicyListener).onPolicyChanged();
1432     }
1433 
1434     @Test
testVcnConfigChangeUpdatesPolicyListener()1435     public void testVcnConfigChangeUpdatesPolicyListener() throws Exception {
1436         setupActiveSubscription(TEST_UUID_2);
1437 
1438         mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
1439         mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
1440 
1441         final Context mockContext = mock(Context.class);
1442         doReturn(TEST_PACKAGE_NAME).when(mockContext).getOpPackageName();
1443         final VcnConfig vcnConfig =
1444                 VcnConfigTest.buildTestConfig(
1445                         mockContext, Collections.singleton(TRANSPORT_CELLULAR));
1446         mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, vcnConfig, TEST_PACKAGE_NAME);
1447 
1448         verify(mMockPolicyListener).onPolicyChanged();
1449     }
1450 
1451     @Test
testRemoveVcnUpdatesPolicyListener()1452     public void testRemoveVcnUpdatesPolicyListener() throws Exception {
1453         setupActiveSubscription(TEST_UUID_2);
1454 
1455         mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
1456         mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
1457 
1458         mVcnMgmtSvc.clearVcnConfig(TEST_UUID_2, TEST_PACKAGE_NAME);
1459 
1460         verify(mMockPolicyListener).onPolicyChanged();
1461     }
1462 
1463     @Test
testVcnSubIdChangeUpdatesPolicyListener()1464     public void testVcnSubIdChangeUpdatesPolicyListener() throws Exception {
1465         setupActiveSubscription(TEST_UUID_2);
1466 
1467         startAndGetVcnInstance(TEST_UUID_2);
1468         mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
1469 
1470         triggerSubscriptionTrackerCbAndGetSnapshot(
1471                 TEST_UUID_2,
1472                 Collections.singleton(TEST_UUID_2),
1473                 Collections.singletonMap(TEST_SUBSCRIPTION_ID, TEST_UUID_2));
1474 
1475         verify(mMockPolicyListener).onPolicyChanged();
1476     }
1477 
1478     @Test
testVcnCarrierConfigChangeUpdatesPolicyListener()1479     public void testVcnCarrierConfigChangeUpdatesPolicyListener() throws Exception {
1480         setupActiveSubscription(TEST_UUID_2);
1481 
1482         mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
1483         mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
1484 
1485         final TelephonySubscriptionSnapshot snapshot =
1486                 buildSubscriptionSnapshot(
1487                         TEST_SUBSCRIPTION_ID,
1488                         TEST_UUID_2,
1489                         Collections.singleton(TEST_UUID_2),
1490                         Collections.emptyMap(),
1491                         true /* hasCarrierPrivileges */);
1492 
1493         final PersistableBundleWrapper mockCarrierConfig = mock(PersistableBundleWrapper.class);
1494         doReturn(mockCarrierConfig).when(snapshot).getCarrierConfigForSubGrp(eq(TEST_UUID_2));
1495 
1496         final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback();
1497         cb.onNewSnapshot(snapshot);
1498 
1499         verify(mMockPolicyListener).onPolicyChanged();
1500     }
1501 
triggerVcnSafeMode( @onNull ParcelUuid subGroup, @NonNull TelephonySubscriptionSnapshot snapshot, boolean isInSafeMode)1502     private void triggerVcnSafeMode(
1503             @NonNull ParcelUuid subGroup,
1504             @NonNull TelephonySubscriptionSnapshot snapshot,
1505             boolean isInSafeMode)
1506             throws Exception {
1507         verify(mMockDeps)
1508                 .newVcn(
1509                         eq(mVcnContext),
1510                         eq(subGroup),
1511                         eq(TEST_VCN_CONFIG),
1512                         eq(snapshot),
1513                         mVcnCallbackCaptor.capture());
1514 
1515         VcnCallback vcnCallback = mVcnCallbackCaptor.getValue();
1516         vcnCallback.onSafeModeStatusChanged(isInSafeMode);
1517     }
1518 
verifyVcnSafeModeChangesNotifiesPolicyListeners(boolean enterSafeMode)1519     private void verifyVcnSafeModeChangesNotifiesPolicyListeners(boolean enterSafeMode)
1520             throws Exception {
1521         TelephonySubscriptionSnapshot snapshot =
1522                 triggerSubscriptionTrackerCbAndGetSnapshot(
1523                         TEST_UUID_1, Collections.singleton(TEST_UUID_1));
1524 
1525         mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
1526 
1527         triggerVcnSafeMode(TEST_UUID_1, snapshot, enterSafeMode);
1528 
1529         verify(mMockPolicyListener).onPolicyChanged();
1530     }
1531 
1532     @Test
testVcnEnteringSafeModeNotifiesPolicyListeners()1533     public void testVcnEnteringSafeModeNotifiesPolicyListeners() throws Exception {
1534         verifyVcnSafeModeChangesNotifiesPolicyListeners(true /* enterSafeMode */);
1535     }
1536 
1537     @Test
testVcnExitingSafeModeNotifiesPolicyListeners()1538     public void testVcnExitingSafeModeNotifiesPolicyListeners() throws Exception {
1539         verifyVcnSafeModeChangesNotifiesPolicyListeners(false /* enterSafeMode */);
1540     }
1541 
triggerVcnStatusCallbackOnSafeModeStatusChanged( @onNull ParcelUuid subGroup, @NonNull String pkgName, int uid, boolean hasPermissionsforSubGroup)1542     private void triggerVcnStatusCallbackOnSafeModeStatusChanged(
1543             @NonNull ParcelUuid subGroup,
1544             @NonNull String pkgName,
1545             int uid,
1546             boolean hasPermissionsforSubGroup)
1547             throws Exception {
1548         TelephonySubscriptionSnapshot snapshot =
1549                 triggerSubscriptionTrackerCbAndGetSnapshot(
1550                         subGroup, Collections.singleton(subGroup));
1551 
1552         setupSubscriptionAndStartVcn(
1553                 TEST_SUBSCRIPTION_ID, subGroup, true /* isActive */, hasPermissionsforSubGroup);
1554 
1555         doReturn(hasPermissionsforSubGroup)
1556                 .when(snapshot)
1557                 .packageHasPermissionsForSubscriptionGroup(eq(subGroup), eq(pkgName));
1558 
1559         mVcnMgmtSvc.registerVcnStatusCallback(subGroup, mMockStatusCallback, pkgName);
1560 
1561         triggerVcnSafeMode(subGroup, snapshot, true /* enterSafeMode */);
1562     }
1563 
1564     @Test
testVcnStatusCallbackOnSafeModeStatusChangedWithCarrierPrivileges()1565     public void testVcnStatusCallbackOnSafeModeStatusChangedWithCarrierPrivileges()
1566             throws Exception {
1567         triggerVcnStatusCallbackOnSafeModeStatusChanged(
1568                 TEST_UUID_1, TEST_PACKAGE_NAME, TEST_UID, true /* hasPermissionsforSubGroup */);
1569 
1570         verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_SAFE_MODE);
1571     }
1572 
1573     @Test
testVcnStatusCallbackOnSafeModeStatusChangedWithoutCarrierPrivileges()1574     public void testVcnStatusCallbackOnSafeModeStatusChangedWithoutCarrierPrivileges()
1575             throws Exception {
1576         triggerVcnStatusCallbackOnSafeModeStatusChanged(
1577                 TEST_UUID_1, TEST_PACKAGE_NAME, TEST_UID, false /* hasPermissionsforSubGroup */);
1578 
1579         verify(mMockStatusCallback, never())
1580                 .onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_SAFE_MODE);
1581     }
1582 
1583     @Test
testRegisterVcnStatusCallback()1584     public void testRegisterVcnStatusCallback() throws Exception {
1585         mVcnMgmtSvc.registerVcnStatusCallback(TEST_UUID_1, mMockStatusCallback, TEST_PACKAGE_NAME);
1586 
1587         Map<IBinder, VcnStatusCallbackInfo> callbacks = mVcnMgmtSvc.getAllStatusCallbacks();
1588         VcnStatusCallbackInfo cbInfo = callbacks.get(mMockIBinder);
1589 
1590         assertNotNull(cbInfo);
1591         assertEquals(TEST_UUID_1, cbInfo.mSubGroup);
1592         assertEquals(mMockStatusCallback, cbInfo.mCallback);
1593         assertEquals(TEST_PACKAGE_NAME, cbInfo.mPkgName);
1594         assertEquals(TEST_UID, cbInfo.mUid);
1595         verify(mMockIBinder).linkToDeath(eq(cbInfo), anyInt());
1596 
1597         verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_NOT_CONFIGURED);
1598     }
1599 
1600     @Test
testRegisterVcnStatusCallback_MissingPermission()1601     public void testRegisterVcnStatusCallback_MissingPermission() throws Exception {
1602         setupSubscriptionAndStartVcn(
1603                 TEST_SUBSCRIPTION_ID,
1604                 TEST_UUID_1,
1605                 true /* isActive */,
1606                 false /* hasCarrierPrivileges */);
1607 
1608         mVcnMgmtSvc.registerVcnStatusCallback(TEST_UUID_1, mMockStatusCallback, TEST_PACKAGE_NAME);
1609 
1610         verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_NOT_CONFIGURED);
1611     }
1612 
1613     @Test
testRegisterVcnStatusCallback_VcnInactive()1614     public void testRegisterVcnStatusCallback_VcnInactive() throws Exception {
1615         setupSubscriptionAndStartVcn(
1616                 TEST_SUBSCRIPTION_ID,
1617                 TEST_UUID_1,
1618                 true /* isActive */,
1619                 true /* hasCarrierPrivileges */);
1620 
1621         // VCN is currently active. Lose carrier privileges for TEST_PACKAGE and hit teardown
1622         // timeout so the VCN goes inactive.
1623         final TelephonySubscriptionSnapshot snapshot =
1624                 triggerSubscriptionTrackerCbAndGetSnapshot(
1625                         TEST_UUID_1,
1626                         Collections.singleton(TEST_UUID_1),
1627                         Collections.singletonMap(TEST_SUBSCRIPTION_ID, TEST_UUID_1),
1628                         false /* hasCarrierPrivileges */);
1629         mTestLooper.moveTimeForward(VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS);
1630         mTestLooper.dispatchAll();
1631 
1632         // Giving TEST_PACKAGE privileges again will restart the VCN (which will indicate ACTIVE
1633         // when the status callback is registered). Instead, setup permissions for TEST_CB_PACKAGE
1634         // so that it's permissioned to receive INACTIVE (instead of NOT_CONFIGURED) without
1635         // reactivating the VCN.
1636         doReturn(true)
1637                 .when(snapshot)
1638                 .packageHasPermissionsForSubscriptionGroup(
1639                         eq(TEST_UUID_1), eq(TEST_CB_PACKAGE_NAME));
1640 
1641         mVcnMgmtSvc.registerVcnStatusCallback(
1642                 TEST_UUID_1, mMockStatusCallback, TEST_CB_PACKAGE_NAME);
1643 
1644         verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_INACTIVE);
1645     }
1646 
1647     @Test
testRegisterVcnStatusCallback_VcnActive()1648     public void testRegisterVcnStatusCallback_VcnActive() throws Exception {
1649         setupSubscriptionAndStartVcn(
1650                 TEST_SUBSCRIPTION_ID,
1651                 TEST_UUID_1,
1652                 true /* isActive */,
1653                 true /* hasCarrierPrivileges */);
1654 
1655         mVcnMgmtSvc.registerVcnStatusCallback(TEST_UUID_1, mMockStatusCallback, TEST_PACKAGE_NAME);
1656 
1657         verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_ACTIVE);
1658     }
1659 
1660     @Test
testRegisterVcnStatusCallback_VcnSafeMode()1661     public void testRegisterVcnStatusCallback_VcnSafeMode() throws Exception {
1662         setupSubscriptionAndStartVcn(
1663                 TEST_SUBSCRIPTION_ID,
1664                 TEST_UUID_1,
1665                 false /* isActive */,
1666                 true /* hasCarrierPrivileges */);
1667 
1668         mVcnMgmtSvc.registerVcnStatusCallback(TEST_UUID_1, mMockStatusCallback, TEST_PACKAGE_NAME);
1669 
1670         verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_SAFE_MODE);
1671     }
1672 
1673     @Test(expected = IllegalStateException.class)
testRegisterVcnStatusCallbackDuplicate()1674     public void testRegisterVcnStatusCallbackDuplicate() {
1675         mVcnMgmtSvc.registerVcnStatusCallback(TEST_UUID_1, mMockStatusCallback, TEST_PACKAGE_NAME);
1676         mVcnMgmtSvc.registerVcnStatusCallback(TEST_UUID_1, mMockStatusCallback, TEST_PACKAGE_NAME);
1677     }
1678 
1679     @Test
testUnregisterVcnStatusCallback()1680     public void testUnregisterVcnStatusCallback() {
1681         mVcnMgmtSvc.registerVcnStatusCallback(TEST_UUID_1, mMockStatusCallback, TEST_PACKAGE_NAME);
1682         Map<IBinder, VcnStatusCallbackInfo> callbacks = mVcnMgmtSvc.getAllStatusCallbacks();
1683         VcnStatusCallbackInfo cbInfo = callbacks.get(mMockIBinder);
1684 
1685         mVcnMgmtSvc.unregisterVcnStatusCallback(mMockStatusCallback);
1686         assertTrue(mVcnMgmtSvc.getAllStatusCallbacks().isEmpty());
1687         verify(mMockIBinder).unlinkToDeath(eq(cbInfo), anyInt());
1688     }
1689 
1690     @Test(expected = SecurityException.class)
testRegisterVcnStatusCallbackInvalidPackage()1691     public void testRegisterVcnStatusCallbackInvalidPackage() {
1692         doThrow(new SecurityException()).when(mAppOpsMgr).checkPackage(TEST_UID, TEST_PACKAGE_NAME);
1693 
1694         mVcnMgmtSvc.registerVcnStatusCallback(TEST_UUID_1, mMockStatusCallback, TEST_PACKAGE_NAME);
1695     }
1696 
1697     @Test
testUnregisterVcnStatusCallbackNeverRegistered()1698     public void testUnregisterVcnStatusCallbackNeverRegistered() {
1699         mVcnMgmtSvc.unregisterVcnStatusCallback(mMockStatusCallback);
1700 
1701         assertTrue(mVcnMgmtSvc.getAllStatusCallbacks().isEmpty());
1702     }
1703 }
1704