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