To read the group UUID, the calling app either needs carrier privileges or the READ_PHONE_STATE permission and access to device identifiers.
If the app has only the READ_PHONE_STATE permission, it can no longer read the group UUID.
When SubscriptionManager#getSubscriptionsInGroup is called, If the calling app has carrier permission or READ_PHONE_STATE permission and access to device identifiers, then returns a list.
If not, it returns an empty list.
Bug: 213902861
Test: atest SubscriptionManagerTest
Test: atest SubscriptionControllerTest
Test: manual (b/213902861#comment54)
Change-Id: Ia7474f5d9aa248cf1c9d1ffa8f1e48cb26caddd6
Merged-In: Ia7474f5d9aa248cf1c9d1ffa8f1e48cb26caddd6
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/SubscriptionManagerTest.java b/tests/tests/telephony/current/src/android/telephony/cts/SubscriptionManagerTest.java
index 03d95bd..475aede 100755
--- a/tests/tests/telephony/current/src/android/telephony/cts/SubscriptionManagerTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/SubscriptionManagerTest.java
@@ -33,6 +33,7 @@
import static org.junit.Assume.assumeTrue;
import android.annotation.Nullable;
+import android.app.AppOpsManager;
import android.app.UiAutomation;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -49,6 +50,7 @@
import android.os.Looper;
import android.os.ParcelUuid;
import android.os.PersistableBundle;
+import android.os.Process;
import android.telephony.CarrierConfigManager;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
@@ -671,6 +673,7 @@
}
@Test
+ @ApiTest(apis = "android.telephony.SubscriptionManager#getSubscriptionsInGroup")
public void testSubscriptionGroupingWithPermission() throws Exception {
// Set subscription group with current sub Id.
List<Integer> subGroup = new ArrayList();
@@ -681,8 +684,14 @@
// Getting subscriptions in group.
List<SubscriptionInfo> infoList = mSm.getSubscriptionsInGroup(uuid);
assertNotNull(infoList);
+ assertTrue(infoList.isEmpty());
+
+ // has the READ_PRIVILEGED_PHONE_STATE permission
+ infoList = ShellIdentityUtils.invokeMethodWithShellPermissions(mSm,
+ (sm) -> sm.getSubscriptionsInGroup(uuid), READ_PRIVILEGED_PHONE_STATE);
+ assertNotNull(infoList);
assertEquals(1, infoList.size());
- assertNull(infoList.get(0).getGroupUuid());
+ assertEquals(uuid, infoList.get(0).getGroupUuid());
infoList = ShellIdentityUtils.invokeMethodWithShellPermissions(mSm,
(sm) -> sm.getSubscriptionsInGroup(uuid));
@@ -699,33 +708,40 @@
}
availableInfoList = ShellIdentityUtils.invokeMethodWithShellPermissions(mSm,
(sm) -> sm.getAvailableSubscriptionInfoList());
- if (availableInfoList.size() > 1) {
- List<Integer> availableSubGroup = availableInfoList.stream()
- .map(info -> info.getSubscriptionId())
- .filter(subId -> subId != mSubId)
- .collect(Collectors.toList());
+ // has the OPSTR_READ_DEVICE_IDENTIFIERS permission
+ try {
+ setIdentifierAccess(true);
+ if (availableInfoList.size() > 1) {
+ List<Integer> availableSubGroup = availableInfoList.stream()
+ .map(info -> info.getSubscriptionId())
+ .filter(subId -> subId != mSubId)
+ .collect(Collectors.toList());
+ ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mSm,
+ (sm) -> sm.addSubscriptionsIntoGroup(availableSubGroup, uuid));
+
+ infoList = mSm.getSubscriptionsInGroup(uuid);
+ assertNotNull(infoList);
+ assertEquals(availableInfoList.size(), infoList.size());
+
+ ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mSm,
+ (sm) -> sm.removeSubscriptionsFromGroup(availableSubGroup, uuid));
+ }
+
+ // Remove from subscription group with current sub Id.
ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mSm,
- (sm) -> sm.addSubscriptionsIntoGroup(availableSubGroup, uuid));
+ (sm) -> sm.removeSubscriptionsFromGroup(subGroup, uuid));
infoList = mSm.getSubscriptionsInGroup(uuid);
assertNotNull(infoList);
- assertEquals(availableInfoList.size(), infoList.size());
-
- ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mSm,
- (sm) -> sm.removeSubscriptionsFromGroup(availableSubGroup, uuid));
+ assertTrue(infoList.isEmpty());
+ } finally {
+ setIdentifierAccess(false);
}
-
- // Remove from subscription group with current sub Id.
- ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mSm,
- (sm) -> sm.removeSubscriptionsFromGroup(subGroup, uuid));
-
- infoList = mSm.getSubscriptionsInGroup(uuid);
- assertNotNull(infoList);
- assertTrue(infoList.isEmpty());
}
@Test
+ @ApiTest(apis = "android.telephony.SubscriptionManager#getSubscriptionsInGroup")
public void testAddSubscriptionIntoNewGroupWithPermission() throws Exception {
// Set subscription group with current sub Id.
List<Integer> subGroup = new ArrayList();
@@ -734,23 +750,27 @@
ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mSm,
(sm) -> sm.addSubscriptionsIntoGroup(subGroup, uuid));
- // Getting subscriptions in group.
List<SubscriptionInfo> infoList = mSm.getSubscriptionsInGroup(uuid);
assertNotNull(infoList);
- assertEquals(1, infoList.size());
- assertNull(infoList.get(0).getGroupUuid());
+ assertTrue(infoList.isEmpty());
- infoList = ShellIdentityUtils.invokeMethodWithShellPermissions(mSm,
- (sm) -> sm.getSubscriptionsInGroup(uuid));
- assertNotNull(infoList);
- assertEquals(1, infoList.size());
- assertEquals(uuid, infoList.get(0).getGroupUuid());
+ // Getting subscriptions in group.
+ try {
+ setIdentifierAccess(true);
+ infoList = mSm.getSubscriptionsInGroup(uuid);
+ assertNotNull(infoList);
+ assertEquals(1, infoList.size());
+ assertEquals(uuid, infoList.get(0).getGroupUuid());
+ } finally {
+ setIdentifierAccess(false);
+ }
// Remove from subscription group with current sub Id.
ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mSm,
(sm) -> sm.removeSubscriptionsFromGroup(subGroup, uuid));
- infoList = mSm.getSubscriptionsInGroup(uuid);
+ infoList = ShellIdentityUtils.invokeMethodWithShellPermissions(mSm,
+ (sm) -> sm.getSubscriptionsInGroup(uuid));
assertNotNull(infoList);
assertTrue(infoList.isEmpty());
}
@@ -1467,4 +1487,13 @@
return validCarrier && validNetworkType && validCapabilities;
}
+
+ private void setIdentifierAccess(boolean allowed) {
+ String op = AppOpsManager.OPSTR_READ_DEVICE_IDENTIFIERS;
+ AppOpsManager appOpsManager = InstrumentationRegistry.getContext().getSystemService(
+ AppOpsManager.class);
+ int mode = allowed ? AppOpsManager.MODE_ALLOWED : AppOpsManager.opToDefaultMode(op);
+ ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(
+ appOpsManager, (appOps) -> appOps.setUidMode(op, Process.myUid(), mode));
+ }
}