subscriptions = subMgr.getSubscriptionsInGroup(subGrp);
+ if (subscriptions == null || subscriptions.isEmpty()) {
+ // Trim subGrps with no more subscriptions; must have moved to another subGrp
+ configsIterator.remove();
+ shouldWrite = true;
+ }
+ }
+
+ if (shouldWrite) {
+ writeConfigsToDiskLocked();
+ }
+ }
+
/**
* Retrieves the list of subscription groups with configured VcnConfigs
*
- * Limited to subscription groups for which the caller is carrier privileged.
+ *
Limited to subscription groups for which the caller had configured.
*
*
Implements the IVcnManagementService Binder interface.
*/
@@ -698,7 +794,8 @@ public class VcnManagementService extends IVcnManagementService.Stub {
final List result = new ArrayList<>();
synchronized (mLock) {
for (ParcelUuid subGrp : mConfigs.keySet()) {
- if (mLastSnapshot.packageHasPermissionsForSubscriptionGroup(subGrp, opPkgName)) {
+ if (mLastSnapshot.packageHasPermissionsForSubscriptionGroup(subGrp, opPkgName)
+ || isProvisioningPackageForConfig(subGrp, opPkgName)) {
result.add(subGrp);
}
}
diff --git a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
index bb98bc0bab536..54b3c400af4f1 100644
--- a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
+++ b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
@@ -65,6 +65,7 @@ import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
import android.net.TelephonyNetworkSpecifier;
+import android.net.Uri;
import android.net.vcn.IVcnStatusCallback;
import android.net.vcn.IVcnUnderlyingNetworkPolicyListener;
import android.net.vcn.VcnConfig;
@@ -114,18 +115,24 @@ import java.util.UUID;
public class VcnManagementServiceTest {
private static final String TEST_PACKAGE_NAME =
VcnManagementServiceTest.class.getPackage().getName();
+ private static final String TEST_PACKAGE_NAME_2 = "TEST_PKG_2";
private static final String TEST_CB_PACKAGE_NAME =
VcnManagementServiceTest.class.getPackage().getName() + ".callback";
private static final ParcelUuid TEST_UUID_1 = new ParcelUuid(new UUID(0, 0));
private static final ParcelUuid TEST_UUID_2 = new ParcelUuid(new UUID(1, 1));
+ private static final ParcelUuid TEST_UUID_3 = new ParcelUuid(new UUID(2, 2));
private static final VcnConfig TEST_VCN_CONFIG;
+ private static final VcnConfig TEST_VCN_CONFIG_PKG_2;
private static final int TEST_UID = Process.FIRST_APPLICATION_UID;
static {
final Context mockConfigContext = mock(Context.class);
- doReturn(TEST_PACKAGE_NAME).when(mockConfigContext).getOpPackageName();
+ doReturn(TEST_PACKAGE_NAME).when(mockConfigContext).getOpPackageName();
TEST_VCN_CONFIG = VcnConfigTest.buildTestConfig(mockConfigContext);
+
+ doReturn(TEST_PACKAGE_NAME_2).when(mockConfigContext).getOpPackageName();
+ TEST_VCN_CONFIG_PKG_2 = VcnConfigTest.buildTestConfig(mockConfigContext);
}
private static final Map TEST_VCN_CONFIG_MAP =
@@ -246,18 +253,24 @@ public class VcnManagementServiceTest {
eq(android.Manifest.permission.NETWORK_FACTORY), any());
}
+
private void setupMockedCarrierPrivilege(boolean isPrivileged) {
+ setupMockedCarrierPrivilege(isPrivileged, TEST_PACKAGE_NAME);
+ }
+
+ private void setupMockedCarrierPrivilege(boolean isPrivileged, String pkg) {
doReturn(Collections.singletonList(TEST_SUBSCRIPTION_INFO))
.when(mSubMgr)
.getSubscriptionsInGroup(any());
doReturn(mTelMgr)
.when(mTelMgr)
.createForSubscriptionId(eq(TEST_SUBSCRIPTION_INFO.getSubscriptionId()));
- doReturn(isPrivileged
- ? CARRIER_PRIVILEGE_STATUS_HAS_ACCESS
- : CARRIER_PRIVILEGE_STATUS_NO_ACCESS)
+ doReturn(
+ isPrivileged
+ ? CARRIER_PRIVILEGE_STATUS_HAS_ACCESS
+ : CARRIER_PRIVILEGE_STATUS_NO_ACCESS)
.when(mTelMgr)
- .checkCarrierPrivilegesForPackage(eq(TEST_PACKAGE_NAME));
+ .checkCarrierPrivilegesForPackage(eq(pkg));
}
@Test
@@ -414,7 +427,13 @@ public class VcnManagementServiceTest {
private BroadcastReceiver getPackageChangeReceiver() {
final ArgumentCaptor captor =
ArgumentCaptor.forClass(BroadcastReceiver.class);
- verify(mMockContext).registerReceiver(captor.capture(), any(), any(), any());
+ verify(mMockContext).registerReceiver(captor.capture(), argThat(filter -> {
+ return filter.hasAction(Intent.ACTION_PACKAGE_ADDED)
+ && filter.hasAction(Intent.ACTION_PACKAGE_REPLACED)
+ && filter.hasAction(Intent.ACTION_PACKAGE_REMOVED)
+ && filter.hasAction(Intent.ACTION_PACKAGE_DATA_CLEARED)
+ && filter.hasAction(Intent.ACTION_PACKAGE_FULLY_REMOVED);
+ }), any(), any());
return captor.getValue();
}
@@ -538,6 +557,44 @@ public class VcnManagementServiceTest {
verify(mSubscriptionTracker).handleSubscriptionsChanged();
}
+ @Test
+ public void testPackageChangeListener_packageDataCleared() throws Exception {
+ triggerSubscriptionTrackerCbAndGetSnapshot(TEST_UUID_1, Collections.singleton(TEST_UUID_1));
+ final Vcn vcn = mVcnMgmtSvc.getAllVcns().get(TEST_UUID_1);
+
+ final BroadcastReceiver receiver = getPackageChangeReceiver();
+ assertEquals(TEST_VCN_CONFIG_MAP, mVcnMgmtSvc.getConfigs());
+
+ final Intent intent = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED);
+ intent.setData(Uri.parse("package:" + TEST_PACKAGE_NAME));
+ intent.putExtra(Intent.EXTRA_USER_HANDLE, UserHandle.getUserId(TEST_UID));
+
+ receiver.onReceive(mMockContext, intent);
+ mTestLooper.dispatchAll();
+ verify(vcn).teardownAsynchronously();
+ assertTrue(mVcnMgmtSvc.getConfigs().isEmpty());
+ verify(mConfigReadWriteHelper).writeToDisk(any(PersistableBundle.class));
+ }
+
+ @Test
+ public void testPackageChangeListener_packageFullyRemoved() throws Exception {
+ triggerSubscriptionTrackerCbAndGetSnapshot(TEST_UUID_1, Collections.singleton(TEST_UUID_1));
+ final Vcn vcn = mVcnMgmtSvc.getAllVcns().get(TEST_UUID_1);
+
+ final BroadcastReceiver receiver = getPackageChangeReceiver();
+ assertEquals(TEST_VCN_CONFIG_MAP, mVcnMgmtSvc.getConfigs());
+
+ final Intent intent = new Intent(Intent.ACTION_PACKAGE_FULLY_REMOVED);
+ intent.setData(Uri.parse("package:" + TEST_PACKAGE_NAME));
+ intent.putExtra(Intent.EXTRA_USER_HANDLE, UserHandle.getUserId(TEST_UID));
+
+ receiver.onReceive(mMockContext, intent);
+ mTestLooper.dispatchAll();
+ verify(vcn).teardownAsynchronously();
+ assertTrue(mVcnMgmtSvc.getConfigs().isEmpty());
+ verify(mConfigReadWriteHelper).writeToDisk(any(PersistableBundle.class));
+ }
+
@Test
public void testSetVcnConfigRequiresNonSystemServer() throws Exception {
doReturn(Process.SYSTEM_UID).when(mMockDeps).getBinderCallingUid();
@@ -578,7 +635,7 @@ public class VcnManagementServiceTest {
@Test
public void testSetVcnConfigMismatchedPackages() throws Exception {
try {
- mVcnMgmtSvc.setVcnConfig(TEST_UUID_1, TEST_VCN_CONFIG, "IncorrectPackage");
+ mVcnMgmtSvc.setVcnConfig(TEST_UUID_1, TEST_VCN_CONFIG, TEST_PACKAGE_NAME_2);
fail("Expected exception due to mismatched packages in config and method call");
} catch (IllegalArgumentException expected) {
verify(mMockPolicyListener, never()).onPolicyChanged();
@@ -678,11 +735,12 @@ public class VcnManagementServiceTest {
}
@Test
- public void testClearVcnConfigRequiresCarrierPrivileges() throws Exception {
+ public void testClearVcnConfigRequiresCarrierPrivilegesOrProvisioningPackage()
+ throws Exception {
setupMockedCarrierPrivilege(false);
try {
- mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1, TEST_PACKAGE_NAME);
+ mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1, TEST_PACKAGE_NAME_2);
fail("Expected security exception for missing carrier privileges");
} catch (SecurityException expected) {
}
@@ -691,19 +749,31 @@ public class VcnManagementServiceTest {
@Test
public void testClearVcnConfigMismatchedPackages() throws Exception {
try {
- mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1, "IncorrectPackage");
+ mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1, TEST_PACKAGE_NAME_2);
fail("Expected security exception due to mismatched packages");
} catch (SecurityException expected) {
}
}
@Test
- public void testClearVcnConfig() throws Exception {
+ public void testClearVcnConfig_callerIsProvisioningPackage() throws Exception {
+ // Lose carrier privileges to test that provisioning package is sufficient.
+ setupMockedCarrierPrivilege(false);
+
mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1, TEST_PACKAGE_NAME);
assertTrue(mVcnMgmtSvc.getConfigs().isEmpty());
verify(mConfigReadWriteHelper).writeToDisk(any(PersistableBundle.class));
}
+ @Test
+ public void testClearVcnConfig_callerIsCarrierPrivileged() throws Exception {
+ setupMockedCarrierPrivilege(true, TEST_PACKAGE_NAME_2);
+
+ mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1, TEST_PACKAGE_NAME_2);
+ assertTrue(mVcnMgmtSvc.getConfigs().isEmpty());
+ verify(mConfigReadWriteHelper).writeToDisk(any(PersistableBundle.class));
+ }
+
@Test
public void testClearVcnConfigNotifiesStatusCallback() throws Exception {
setupSubscriptionAndStartVcn(TEST_SUBSCRIPTION_ID, TEST_UUID_2, true /* isActive */);
@@ -755,11 +825,12 @@ public class VcnManagementServiceTest {
@Test
public void testGetConfiguredSubscriptionGroupsMismatchedPackages() throws Exception {
- final String badPackage = "IncorrectPackage";
- doThrow(new SecurityException()).when(mAppOpsMgr).checkPackage(TEST_UID, badPackage);
+ doThrow(new SecurityException())
+ .when(mAppOpsMgr)
+ .checkPackage(TEST_UID, TEST_PACKAGE_NAME_2);
try {
- mVcnMgmtSvc.getConfiguredSubscriptionGroups(badPackage);
+ mVcnMgmtSvc.getConfiguredSubscriptionGroups(TEST_PACKAGE_NAME_2);
fail("Expected security exception due to mismatched packages");
} catch (SecurityException expected) {
}
@@ -767,14 +838,16 @@ public class VcnManagementServiceTest {
@Test
public void testGetConfiguredSubscriptionGroups() throws Exception {
+ setupMockedCarrierPrivilege(true, TEST_PACKAGE_NAME_2);
mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
+ mVcnMgmtSvc.setVcnConfig(TEST_UUID_3, TEST_VCN_CONFIG_PKG_2, TEST_PACKAGE_NAME_2);
- // Assert that if both UUID 1 and 2 are provisioned, the caller only gets ones that they are
- // privileged for.
+ // Assert that if UUIDs 1, 2 and 3 are provisioned, the caller only gets ones that they are
+ // privileged for, or are the provisioning package of.
triggerSubscriptionTrackerCbAndGetSnapshot(TEST_UUID_1, Collections.singleton(TEST_UUID_1));
final List subGrps =
mVcnMgmtSvc.getConfiguredSubscriptionGroups(TEST_PACKAGE_NAME);
- assertEquals(Collections.singletonList(TEST_UUID_1), subGrps);
+ assertEquals(Arrays.asList(new ParcelUuid[] {TEST_UUID_1, TEST_UUID_2}), subGrps);
}
@Test