Loading src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +125 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,9 @@ package com.android.internal.telephony.subscription; import static android.content.pm.PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION; import static android.telephony.TelephonyManager.ENABLE_FEATURE_MAPPING; import android.Manifest; import android.annotation.CallbackExecutor; import android.annotation.ColorInt; Loading Loading @@ -249,6 +252,10 @@ public class SubscriptionManagerService extends ISub.Stub { @Nullable private EuiccController mEuiccController; /** Package manager instance. */ @NonNull private final PackageManager mPackageManager; /** * The main handler of subscription manager service. This is running on phone process's main * thread. Loading Loading @@ -455,6 +462,7 @@ public class SubscriptionManagerService extends ISub.Stub { mSubscriptionManager = context.getSystemService(SubscriptionManager.class); mEuiccManager = context.getSystemService(EuiccManager.class); mAppOpsManager = context.getSystemService(AppOpsManager.class); mPackageManager = context.getPackageManager(); mUiccController = UiccController.getInstance(); mHandler = new Handler(looper); Loading Loading @@ -1777,6 +1785,9 @@ public class SubscriptionManagerService extends ISub.Stub { throw new SecurityException("Need READ_PHONE_STATE, READ_PRIVILEGED_PHONE_STATE, or " + "carrier privilege"); } enforceTelephonyFeatureWithException(callingPackage, "getAllSubInfoList"); return getSubscriptionInfoStreamAsUser(BINDER_WRAPPER.getCallingUserHandle()) // callers have READ_PHONE_STATE or READ_PRIVILEGED_PHONE_STATE can get a full // list. Carrier apps can only get the subscriptions they have privileged. Loading Loading @@ -1819,6 +1830,8 @@ public class SubscriptionManagerService extends ISub.Stub { + "carrier privilege"); } enforceTelephonyFeatureWithException(callingPackage, "getActiveSubscriptionInfo"); SubscriptionInfoInternal subInfo = mSubscriptionDatabaseManager .getSubscriptionInfoInternal(subId); if (subInfo != null && subInfo.isActive()) { Loading Loading @@ -1847,6 +1860,8 @@ public class SubscriptionManagerService extends ISub.Stub { enforcePermissions("getActiveSubscriptionInfoForIccId", Manifest.permission.READ_PRIVILEGED_PHONE_STATE); enforceTelephonyFeatureWithException(callingPackage, "getActiveSubscriptionInfoForIccId"); final long identity = Binder.clearCallingIdentity(); try { iccId = IccUtils.stripTrailingFs(iccId); Loading Loading @@ -1891,6 +1906,9 @@ public class SubscriptionManagerService extends ISub.Stub { } enforceTelephonyFeatureWithException(callingPackage, "getActiveSubscriptionInfoForSimSlotIndex"); if (!SubscriptionManager.isValidSlotIndex(slotIndex)) { throw new IllegalArgumentException("Invalid slot index " + slotIndex); } Loading Loading @@ -1940,6 +1958,9 @@ public class SubscriptionManagerService extends ISub.Stub { + "permission. Returning empty list here."); return Collections.emptyList(); } enforceTelephonyFeatureWithException(callingPackage, "getActiveSubscriptionInfoList"); if (isForAllProfiles && !hasAcrossAllUsersPermission()) { //TODO(b/308809058 to determine whether the permission enforcement is needed) loge("getActiveSubscriptionInfoList: " Loading Loading @@ -1989,6 +2010,9 @@ public class SubscriptionManagerService extends ISub.Stub { loge("getActiveSubInfoCount: " + callingPackage + " has no appropriate permission."); } enforceTelephonyFeatureWithException(callingPackage, "getActiveSubInfoCount"); return getActiveSubIdListAsUser(false, isForAllProfiles ? UserHandle.ALL : BINDER_WRAPPER.getCallingUserHandle()).length; } Loading Loading @@ -2028,6 +2052,9 @@ public class SubscriptionManagerService extends ISub.Stub { @Nullable String callingFeatureId) { enforcePermissions("getAvailableSubscriptionInfoList", Manifest.permission.READ_PRIVILEGED_PHONE_STATE); enforceTelephonyFeatureWithException(callingPackage, "getAvailableSubscriptionInfoList"); return getAvailableSubscriptionsInternalStream() .sorted(Comparator.comparing(SubscriptionInfoInternal::getSimSlotIndex) .thenComparing(SubscriptionInfoInternal::getSubscriptionId)) Loading Loading @@ -2137,6 +2164,8 @@ public class SubscriptionManagerService extends ISub.Stub { + SubscriptionManager.subscriptionTypeToString(subscriptionType) + ", " + getCallingPackage()); enforceTelephonyFeatureWithException(getCurrentPackageName(), "addSubInfo"); // Now that all security checks passes, perform the operation as ourselves. final long identity = Binder.clearCallingIdentity(); try { Loading Loading @@ -2192,6 +2221,9 @@ public class SubscriptionManagerService extends ISub.Stub { logl("removeSubInfo: uniqueId=" + SubscriptionInfo.getPrintableId(uniqueId) + ", " + SubscriptionManager.subscriptionTypeToString(subscriptionType) + ", " + getCallingPackage()); enforceTelephonyFeatureWithException(getCurrentPackageName(), "removeSubInfo"); final long identity = Binder.clearCallingIdentity(); try { SubscriptionInfoInternal subInfo = mSubscriptionDatabaseManager Loading Loading @@ -2415,6 +2447,8 @@ public class SubscriptionManagerService extends ISub.Stub { mContext, Binder.getCallingUid(), subId, true, "setOpportunistic", Manifest.permission.MODIFY_PHONE_STATE); enforceTelephonyFeatureWithException(callingPackage, "setOpportunistic"); long token = Binder.clearCallingIdentity(); try { mSubscriptionDatabaseManager.setOpportunistic(subId, opportunistic); Loading Loading @@ -2467,6 +2501,8 @@ public class SubscriptionManagerService extends ISub.Stub { + " carrier privilege permission on all specified subscriptions"); } enforceTelephonyFeatureWithException(callingPackage, "createSubscriptionGroup"); long identity = Binder.clearCallingIdentity(); try { Loading Loading @@ -2503,6 +2539,10 @@ public class SubscriptionManagerService extends ISub.Stub { @Nullable ISetOpportunisticDataCallback callback) { enforcePermissions("setPreferredDataSubscriptionId", Manifest.permission.MODIFY_PHONE_STATE); enforceTelephonyFeatureWithException(getCurrentPackageName(), "setPreferredDataSubscriptionId"); final long token = Binder.clearCallingIdentity(); try { Loading Loading @@ -2589,6 +2629,8 @@ public class SubscriptionManagerService extends ISub.Stub { return Collections.emptyList(); } enforceTelephonyFeatureWithException(callingPackage, "getOpportunisticSubscriptions"); return mSubscriptionDatabaseManager.getAllSubscriptions().stream() // callers have READ_PHONE_STATE or READ_PRIVILEGED_PHONE_STATE can get a full // list. Carrier apps can only get the subscriptions they have privileged. Loading Loading @@ -2641,6 +2683,8 @@ public class SubscriptionManagerService extends ISub.Stub { throw new IllegalArgumentException("subIdList is empty."); } enforceTelephonyFeatureWithException(callingPackage, "removeSubscriptionsFromGroup"); long identity = Binder.clearCallingIdentity(); try { Loading Loading @@ -2723,6 +2767,8 @@ public class SubscriptionManagerService extends ISub.Stub { + " permissions on subscriptions and the group."); } enforceTelephonyFeatureWithException(callingPackage, "addSubscriptionsIntoGroup"); long identity = Binder.clearCallingIdentity(); try { Loading Loading @@ -2792,6 +2838,8 @@ public class SubscriptionManagerService extends ISub.Stub { } } enforceTelephonyFeatureWithException(callingPackage, "getSubscriptionsInGroup"); return mSubscriptionDatabaseManager.getAllSubscriptions().stream() .map(SubscriptionInfoInternal::toSubscriptionInfo) .filter(info -> groupUuid.equals(info.getGroupUuid()) Loading Loading @@ -2902,6 +2950,9 @@ public class SubscriptionManagerService extends ISub.Stub { */ @Override public int getDefaultSubIdAsUser(@UserIdInt int userId) { enforceTelephonyFeatureWithException(getCurrentPackageName(), "getDefaultVoiceSubIdAsUser"); return getDefaultAsUser(userId, mDefaultSubId.get()); } Loading Loading @@ -2978,6 +3029,8 @@ public class SubscriptionManagerService extends ISub.Stub { throw new RuntimeException("setDefaultDataSubId called with DEFAULT_SUBSCRIPTION_ID"); } enforceTelephonyFeatureWithException(getCurrentPackageName(), "setDefaultDataSubId"); final long token = Binder.clearCallingIdentity(); try { if (mDefaultDataSubId.set(subId)) { Loading Loading @@ -3046,6 +3099,8 @@ public class SubscriptionManagerService extends ISub.Stub { throw new RuntimeException("setDefaultVoiceSubId called with DEFAULT_SUB_ID"); } enforceTelephonyFeatureWithException(getCurrentPackageName(), "setDefaultVoiceSubId"); final long token = Binder.clearCallingIdentity(); try { if (mDefaultVoiceSubId.set(subId)) { Loading Loading @@ -3106,6 +3161,8 @@ public class SubscriptionManagerService extends ISub.Stub { throw new RuntimeException("setDefaultSmsSubId called with DEFAULT_SUB_ID"); } enforceTelephonyFeatureWithException(getCurrentPackageName(), "setDefaultSmsSubId"); final long token = Binder.clearCallingIdentity(); try { if (mDefaultSmsSubId.set(subId)) { Loading Loading @@ -3144,6 +3201,9 @@ public class SubscriptionManagerService extends ISub.Stub { @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int[] getActiveSubIdList(boolean visibleOnly) { enforcePermissions("getActiveSubIdList", Manifest.permission.READ_PRIVILEGED_PHONE_STATE); enforceTelephonyFeatureWithException(getCurrentPackageName(), "getActiveSubIdList"); // UserHandle.ALL because this API is exposed as system API. return getActiveSubIdListAsUser(visibleOnly, UserHandle.ALL); } Loading Loading @@ -3255,6 +3315,8 @@ public class SubscriptionManagerService extends ISub.Stub { + "accessed through getSubscriptionProperty."); } enforceTelephonyFeatureWithException(callingPackage, "getSubscriptionProperty"); final long token = Binder.clearCallingIdentity(); try { Object value = mSubscriptionDatabaseManager.getSubscriptionProperty(subId, columnName); Loading Loading @@ -3299,6 +3361,8 @@ public class SubscriptionManagerService extends ISub.Stub { throw new IllegalArgumentException("Invalid subscription id " + subId); } enforceTelephonyFeatureWithException(getCurrentPackageName(), "isSubscriptionEnabled"); final long identity = Binder.clearCallingIdentity(); try { SubscriptionInfoInternal subInfo = mSubscriptionDatabaseManager Loading Loading @@ -3328,6 +3392,8 @@ public class SubscriptionManagerService extends ISub.Stub { throw new IllegalArgumentException("Invalid slot index " + slotIndex); } enforceTelephonyFeatureWithException(getCurrentPackageName(), "getEnabledSubscriptionId"); final long identity = Binder.clearCallingIdentity(); try { return mSubscriptionDatabaseManager.getAllSubscriptions().stream() Loading Loading @@ -3364,6 +3430,9 @@ public class SubscriptionManagerService extends ISub.Stub { throw new SecurityException("Need READ_PHONE_STATE, READ_PRIVILEGED_PHONE_STATE, or " + "carrier privilege"); } enforceTelephonyFeatureWithException(callingPackage, "isActiveSubId"); final long identity = Binder.clearCallingIdentity(); try { SubscriptionInfoInternal subInfo = mSubscriptionDatabaseManager Loading Loading @@ -3421,6 +3490,9 @@ public class SubscriptionManagerService extends ISub.Stub { enforcePermissions("canDisablePhysicalSubscription", Manifest.permission.READ_PRIVILEGED_PHONE_STATE); enforceTelephonyFeatureWithException(getCurrentPackageName(), "canDisablePhysicalSubscription"); final long identity = Binder.clearCallingIdentity(); try { Phone phone = PhoneFactory.getDefaultPhone(); Loading Loading @@ -3454,6 +3526,9 @@ public class SubscriptionManagerService extends ISub.Stub { logl("setUiccApplicationsEnabled: subId=" + subId + ", enabled=" + enabled + ", calling package=" + getCallingPackage()); enforceTelephonyFeatureWithException(getCurrentPackageName(), "setUiccApplicationsEnabled"); final long identity = Binder.clearCallingIdentity(); try { Loading Loading @@ -3496,6 +3571,9 @@ public class SubscriptionManagerService extends ISub.Stub { enforcePermissions("setDeviceToDeviceStatusSharing", Manifest.permission.MODIFY_PHONE_STATE); enforceTelephonyFeatureWithException(getCurrentPackageName(), "setDeviceToDeviceStatusSharing"); final long identity = Binder.clearCallingIdentity(); try { if (sharing < SubscriptionManager.D2D_SHARING_DISABLED Loading Loading @@ -3528,6 +3606,9 @@ public class SubscriptionManagerService extends ISub.Stub { enforcePermissions("setDeviceToDeviceStatusSharingContacts", Manifest.permission.MODIFY_PHONE_STATE); enforceTelephonyFeatureWithException(getCurrentPackageName(), "setDeviceToDeviceStatusSharingContacts"); final long identity = Binder.clearCallingIdentity(); try { Objects.requireNonNull(contacts, "contacts"); Loading Loading @@ -3595,6 +3676,8 @@ public class SubscriptionManagerService extends ISub.Stub { Manifest.permission.READ_PHONE_NUMBERS, Manifest.permission.READ_PRIVILEGED_PHONE_STATE); enforceTelephonyFeatureWithException(callingPackage, "getPhoneNumber"); final long identity = Binder.clearCallingIdentity(); SubscriptionInfoInternal subInfo = mSubscriptionDatabaseManager Loading Loading @@ -3655,6 +3738,9 @@ public class SubscriptionManagerService extends ISub.Stub { Manifest.permission.READ_PHONE_NUMBERS, Manifest.permission.READ_PRIVILEGED_PHONE_STATE); enforceTelephonyFeatureWithException(callingPackage, "getPhoneNumberFromFirstAvailableSource"); String numberFromCarrier = getPhoneNumber(subId, SubscriptionManager.PHONE_NUMBER_SOURCE_CARRIER, callingPackage, callingFeatureId); Loading Loading @@ -3702,6 +3788,8 @@ public class SubscriptionManagerService extends ISub.Stub { + SubscriptionManager.phoneNumberSourceToString(source)); } enforceTelephonyFeatureWithException(callingPackage, "setPhoneNumber"); Objects.requireNonNull(number, "number"); final long identity = Binder.clearCallingIdentity(); Loading Loading @@ -3977,6 +4065,9 @@ public class SubscriptionManagerService extends ISub.Stub { enforcePermissions("restoreAllSimSpecificSettingsFromBackup", Manifest.permission.MODIFY_PHONE_STATE); enforceTelephonyFeatureWithException(getCurrentPackageName(), "restoreAllSimSpecificSettingsFromBackup"); long token = Binder.clearCallingIdentity(); try { Bundle bundle = new Bundle(); Loading Loading @@ -4199,6 +4290,40 @@ public class SubscriptionManagerService extends ISub.Stub { } } /** * Get the current calling package name. * @return the current calling package name */ @Nullable private String getCurrentPackageName() { if (mPackageManager == null) return null; String[] callingUids = mPackageManager.getPackagesForUid(Binder.getCallingUid()); return (callingUids == null) ? null : callingUids[0]; } /** * Make sure the device has required telephony feature * * @throws UnsupportedOperationException if the device does not have required telephony feature */ private void enforceTelephonyFeatureWithException(@Nullable String callingPackage, @NonNull String methodName) { if (callingPackage == null || mPackageManager == null) { return; } if (!mFeatureFlags.enforceTelephonyFeatureMappingForPublicApis() || !CompatChanges.isChangeEnabled(ENABLE_FEATURE_MAPPING, callingPackage, Binder.getCallingUserHandle())) { return; } if (!mPackageManager.hasSystemFeature(FEATURE_TELEPHONY_SUBSCRIPTION)) { throw new UnsupportedOperationException( methodName + " is unsupported without " + FEATURE_TELEPHONY_SUBSCRIPTION); } } /** * @return The logical SIM slot/sub mapping to string. */ Loading tests/telephonytests/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -42,6 +42,7 @@ android_test { "testables", "platform-compat-test-rules", "flag-junit", "telephony_flags_core_java_lib", ], jarjar_rules: ":jarjar-rules-telephony-tests", Loading tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java +47 −0 Original line number Diff line number Diff line Loading @@ -113,6 +113,7 @@ import com.android.internal.telephony.subscription.SubscriptionManagerService.Su import com.android.internal.telephony.uicc.IccCardStatus; import com.android.internal.telephony.uicc.UiccSlot; import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges; import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges; import org.junit.After; Loading Loading @@ -232,6 +233,11 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { doReturn(true).when(mUserManager) .isManagedProfile(eq(FAKE_MANAGED_PROFILE_USER_HANDLE.getIdentifier())); // Due to affect exist implementation, bypass feature flag. doReturn(false).when(mFlags).enforceTelephonyFeatureMappingForPublicApis(); doReturn(true).when(mPackageManager).hasSystemFeature( eq(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)); logd("SubscriptionManagerServiceTest -Setup!"); } Loading Loading @@ -407,7 +413,12 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { } @Test @DisableCompatChanges({TelephonyManager.ENABLE_FEATURE_MAPPING}) public void testSetPhoneNumber() { doReturn(false).when(mFlags).enforceTelephonyFeatureMapping(); doReturn(true).when(mPackageManager).hasSystemFeature( eq(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)); mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); mSubscriptionManagerServiceUT.addSubInfo(FAKE_ICCID1, FAKE_CARRIER_NAME1, 0, SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM); Loading Loading @@ -443,6 +454,41 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { verify(mMockedSubscriptionManagerServiceCallback).onSubscriptionChanged(eq(1)); } @Test @EnableCompatChanges({TelephonyManager.ENABLE_FEATURE_MAPPING}) public void testSetPhoneNumber_EnabledEnforceTelephonyFeatureMappingForPublicApis() { mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); mSubscriptionManagerServiceUT.addSubInfo(FAKE_ICCID1, FAKE_CARRIER_NAME1, 0, SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM); processAllMessages(); verify(mMockedSubscriptionManagerServiceCallback).onSubscriptionChanged(eq(1)); Mockito.clearInvocations(mMockedSubscriptionManagerServiceCallback); // Grant carrier privilege setCarrierPrivilegesForSubId(true, 1); // Enabled FeatureFlags and ENABLE_FEATURE_MAPPING, telephony features are defined doReturn(true).when(mFlags).enforceTelephonyFeatureMappingForPublicApis(); doReturn(true).when(mPackageManager).hasSystemFeature( eq(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)); try { mSubscriptionManagerServiceUT.setPhoneNumber(1, SubscriptionManager.PHONE_NUMBER_SOURCE_CARRIER, FAKE_PHONE_NUMBER2, CALLING_PACKAGE, CALLING_FEATURE); } catch (UnsupportedOperationException e) { fail("Not expect exception " + e.getMessage()); } // Telephony features is not defined, expect UnsupportedOperationException. doReturn(false).when(mPackageManager).hasSystemFeature( eq(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)); assertThrows(UnsupportedOperationException.class, () -> mSubscriptionManagerServiceUT.setPhoneNumber(1, SubscriptionManager.PHONE_NUMBER_SOURCE_CARRIER, FAKE_PHONE_NUMBER2, CALLING_PACKAGE, CALLING_FEATURE)); } @Test public void testGetAllSubInfoList() { mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); Loading Loading @@ -2274,6 +2320,7 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { } @Test @DisableCompatChanges({TelephonyManager.ENABLE_FEATURE_MAPPING}) public void testGetPhoneNumber() { mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE); testSetPhoneNumber(); Loading Loading
src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +125 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,9 @@ package com.android.internal.telephony.subscription; import static android.content.pm.PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION; import static android.telephony.TelephonyManager.ENABLE_FEATURE_MAPPING; import android.Manifest; import android.annotation.CallbackExecutor; import android.annotation.ColorInt; Loading Loading @@ -249,6 +252,10 @@ public class SubscriptionManagerService extends ISub.Stub { @Nullable private EuiccController mEuiccController; /** Package manager instance. */ @NonNull private final PackageManager mPackageManager; /** * The main handler of subscription manager service. This is running on phone process's main * thread. Loading Loading @@ -455,6 +462,7 @@ public class SubscriptionManagerService extends ISub.Stub { mSubscriptionManager = context.getSystemService(SubscriptionManager.class); mEuiccManager = context.getSystemService(EuiccManager.class); mAppOpsManager = context.getSystemService(AppOpsManager.class); mPackageManager = context.getPackageManager(); mUiccController = UiccController.getInstance(); mHandler = new Handler(looper); Loading Loading @@ -1777,6 +1785,9 @@ public class SubscriptionManagerService extends ISub.Stub { throw new SecurityException("Need READ_PHONE_STATE, READ_PRIVILEGED_PHONE_STATE, or " + "carrier privilege"); } enforceTelephonyFeatureWithException(callingPackage, "getAllSubInfoList"); return getSubscriptionInfoStreamAsUser(BINDER_WRAPPER.getCallingUserHandle()) // callers have READ_PHONE_STATE or READ_PRIVILEGED_PHONE_STATE can get a full // list. Carrier apps can only get the subscriptions they have privileged. Loading Loading @@ -1819,6 +1830,8 @@ public class SubscriptionManagerService extends ISub.Stub { + "carrier privilege"); } enforceTelephonyFeatureWithException(callingPackage, "getActiveSubscriptionInfo"); SubscriptionInfoInternal subInfo = mSubscriptionDatabaseManager .getSubscriptionInfoInternal(subId); if (subInfo != null && subInfo.isActive()) { Loading Loading @@ -1847,6 +1860,8 @@ public class SubscriptionManagerService extends ISub.Stub { enforcePermissions("getActiveSubscriptionInfoForIccId", Manifest.permission.READ_PRIVILEGED_PHONE_STATE); enforceTelephonyFeatureWithException(callingPackage, "getActiveSubscriptionInfoForIccId"); final long identity = Binder.clearCallingIdentity(); try { iccId = IccUtils.stripTrailingFs(iccId); Loading Loading @@ -1891,6 +1906,9 @@ public class SubscriptionManagerService extends ISub.Stub { } enforceTelephonyFeatureWithException(callingPackage, "getActiveSubscriptionInfoForSimSlotIndex"); if (!SubscriptionManager.isValidSlotIndex(slotIndex)) { throw new IllegalArgumentException("Invalid slot index " + slotIndex); } Loading Loading @@ -1940,6 +1958,9 @@ public class SubscriptionManagerService extends ISub.Stub { + "permission. Returning empty list here."); return Collections.emptyList(); } enforceTelephonyFeatureWithException(callingPackage, "getActiveSubscriptionInfoList"); if (isForAllProfiles && !hasAcrossAllUsersPermission()) { //TODO(b/308809058 to determine whether the permission enforcement is needed) loge("getActiveSubscriptionInfoList: " Loading Loading @@ -1989,6 +2010,9 @@ public class SubscriptionManagerService extends ISub.Stub { loge("getActiveSubInfoCount: " + callingPackage + " has no appropriate permission."); } enforceTelephonyFeatureWithException(callingPackage, "getActiveSubInfoCount"); return getActiveSubIdListAsUser(false, isForAllProfiles ? UserHandle.ALL : BINDER_WRAPPER.getCallingUserHandle()).length; } Loading Loading @@ -2028,6 +2052,9 @@ public class SubscriptionManagerService extends ISub.Stub { @Nullable String callingFeatureId) { enforcePermissions("getAvailableSubscriptionInfoList", Manifest.permission.READ_PRIVILEGED_PHONE_STATE); enforceTelephonyFeatureWithException(callingPackage, "getAvailableSubscriptionInfoList"); return getAvailableSubscriptionsInternalStream() .sorted(Comparator.comparing(SubscriptionInfoInternal::getSimSlotIndex) .thenComparing(SubscriptionInfoInternal::getSubscriptionId)) Loading Loading @@ -2137,6 +2164,8 @@ public class SubscriptionManagerService extends ISub.Stub { + SubscriptionManager.subscriptionTypeToString(subscriptionType) + ", " + getCallingPackage()); enforceTelephonyFeatureWithException(getCurrentPackageName(), "addSubInfo"); // Now that all security checks passes, perform the operation as ourselves. final long identity = Binder.clearCallingIdentity(); try { Loading Loading @@ -2192,6 +2221,9 @@ public class SubscriptionManagerService extends ISub.Stub { logl("removeSubInfo: uniqueId=" + SubscriptionInfo.getPrintableId(uniqueId) + ", " + SubscriptionManager.subscriptionTypeToString(subscriptionType) + ", " + getCallingPackage()); enforceTelephonyFeatureWithException(getCurrentPackageName(), "removeSubInfo"); final long identity = Binder.clearCallingIdentity(); try { SubscriptionInfoInternal subInfo = mSubscriptionDatabaseManager Loading Loading @@ -2415,6 +2447,8 @@ public class SubscriptionManagerService extends ISub.Stub { mContext, Binder.getCallingUid(), subId, true, "setOpportunistic", Manifest.permission.MODIFY_PHONE_STATE); enforceTelephonyFeatureWithException(callingPackage, "setOpportunistic"); long token = Binder.clearCallingIdentity(); try { mSubscriptionDatabaseManager.setOpportunistic(subId, opportunistic); Loading Loading @@ -2467,6 +2501,8 @@ public class SubscriptionManagerService extends ISub.Stub { + " carrier privilege permission on all specified subscriptions"); } enforceTelephonyFeatureWithException(callingPackage, "createSubscriptionGroup"); long identity = Binder.clearCallingIdentity(); try { Loading Loading @@ -2503,6 +2539,10 @@ public class SubscriptionManagerService extends ISub.Stub { @Nullable ISetOpportunisticDataCallback callback) { enforcePermissions("setPreferredDataSubscriptionId", Manifest.permission.MODIFY_PHONE_STATE); enforceTelephonyFeatureWithException(getCurrentPackageName(), "setPreferredDataSubscriptionId"); final long token = Binder.clearCallingIdentity(); try { Loading Loading @@ -2589,6 +2629,8 @@ public class SubscriptionManagerService extends ISub.Stub { return Collections.emptyList(); } enforceTelephonyFeatureWithException(callingPackage, "getOpportunisticSubscriptions"); return mSubscriptionDatabaseManager.getAllSubscriptions().stream() // callers have READ_PHONE_STATE or READ_PRIVILEGED_PHONE_STATE can get a full // list. Carrier apps can only get the subscriptions they have privileged. Loading Loading @@ -2641,6 +2683,8 @@ public class SubscriptionManagerService extends ISub.Stub { throw new IllegalArgumentException("subIdList is empty."); } enforceTelephonyFeatureWithException(callingPackage, "removeSubscriptionsFromGroup"); long identity = Binder.clearCallingIdentity(); try { Loading Loading @@ -2723,6 +2767,8 @@ public class SubscriptionManagerService extends ISub.Stub { + " permissions on subscriptions and the group."); } enforceTelephonyFeatureWithException(callingPackage, "addSubscriptionsIntoGroup"); long identity = Binder.clearCallingIdentity(); try { Loading Loading @@ -2792,6 +2838,8 @@ public class SubscriptionManagerService extends ISub.Stub { } } enforceTelephonyFeatureWithException(callingPackage, "getSubscriptionsInGroup"); return mSubscriptionDatabaseManager.getAllSubscriptions().stream() .map(SubscriptionInfoInternal::toSubscriptionInfo) .filter(info -> groupUuid.equals(info.getGroupUuid()) Loading Loading @@ -2902,6 +2950,9 @@ public class SubscriptionManagerService extends ISub.Stub { */ @Override public int getDefaultSubIdAsUser(@UserIdInt int userId) { enforceTelephonyFeatureWithException(getCurrentPackageName(), "getDefaultVoiceSubIdAsUser"); return getDefaultAsUser(userId, mDefaultSubId.get()); } Loading Loading @@ -2978,6 +3029,8 @@ public class SubscriptionManagerService extends ISub.Stub { throw new RuntimeException("setDefaultDataSubId called with DEFAULT_SUBSCRIPTION_ID"); } enforceTelephonyFeatureWithException(getCurrentPackageName(), "setDefaultDataSubId"); final long token = Binder.clearCallingIdentity(); try { if (mDefaultDataSubId.set(subId)) { Loading Loading @@ -3046,6 +3099,8 @@ public class SubscriptionManagerService extends ISub.Stub { throw new RuntimeException("setDefaultVoiceSubId called with DEFAULT_SUB_ID"); } enforceTelephonyFeatureWithException(getCurrentPackageName(), "setDefaultVoiceSubId"); final long token = Binder.clearCallingIdentity(); try { if (mDefaultVoiceSubId.set(subId)) { Loading Loading @@ -3106,6 +3161,8 @@ public class SubscriptionManagerService extends ISub.Stub { throw new RuntimeException("setDefaultSmsSubId called with DEFAULT_SUB_ID"); } enforceTelephonyFeatureWithException(getCurrentPackageName(), "setDefaultSmsSubId"); final long token = Binder.clearCallingIdentity(); try { if (mDefaultSmsSubId.set(subId)) { Loading Loading @@ -3144,6 +3201,9 @@ public class SubscriptionManagerService extends ISub.Stub { @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int[] getActiveSubIdList(boolean visibleOnly) { enforcePermissions("getActiveSubIdList", Manifest.permission.READ_PRIVILEGED_PHONE_STATE); enforceTelephonyFeatureWithException(getCurrentPackageName(), "getActiveSubIdList"); // UserHandle.ALL because this API is exposed as system API. return getActiveSubIdListAsUser(visibleOnly, UserHandle.ALL); } Loading Loading @@ -3255,6 +3315,8 @@ public class SubscriptionManagerService extends ISub.Stub { + "accessed through getSubscriptionProperty."); } enforceTelephonyFeatureWithException(callingPackage, "getSubscriptionProperty"); final long token = Binder.clearCallingIdentity(); try { Object value = mSubscriptionDatabaseManager.getSubscriptionProperty(subId, columnName); Loading Loading @@ -3299,6 +3361,8 @@ public class SubscriptionManagerService extends ISub.Stub { throw new IllegalArgumentException("Invalid subscription id " + subId); } enforceTelephonyFeatureWithException(getCurrentPackageName(), "isSubscriptionEnabled"); final long identity = Binder.clearCallingIdentity(); try { SubscriptionInfoInternal subInfo = mSubscriptionDatabaseManager Loading Loading @@ -3328,6 +3392,8 @@ public class SubscriptionManagerService extends ISub.Stub { throw new IllegalArgumentException("Invalid slot index " + slotIndex); } enforceTelephonyFeatureWithException(getCurrentPackageName(), "getEnabledSubscriptionId"); final long identity = Binder.clearCallingIdentity(); try { return mSubscriptionDatabaseManager.getAllSubscriptions().stream() Loading Loading @@ -3364,6 +3430,9 @@ public class SubscriptionManagerService extends ISub.Stub { throw new SecurityException("Need READ_PHONE_STATE, READ_PRIVILEGED_PHONE_STATE, or " + "carrier privilege"); } enforceTelephonyFeatureWithException(callingPackage, "isActiveSubId"); final long identity = Binder.clearCallingIdentity(); try { SubscriptionInfoInternal subInfo = mSubscriptionDatabaseManager Loading Loading @@ -3421,6 +3490,9 @@ public class SubscriptionManagerService extends ISub.Stub { enforcePermissions("canDisablePhysicalSubscription", Manifest.permission.READ_PRIVILEGED_PHONE_STATE); enforceTelephonyFeatureWithException(getCurrentPackageName(), "canDisablePhysicalSubscription"); final long identity = Binder.clearCallingIdentity(); try { Phone phone = PhoneFactory.getDefaultPhone(); Loading Loading @@ -3454,6 +3526,9 @@ public class SubscriptionManagerService extends ISub.Stub { logl("setUiccApplicationsEnabled: subId=" + subId + ", enabled=" + enabled + ", calling package=" + getCallingPackage()); enforceTelephonyFeatureWithException(getCurrentPackageName(), "setUiccApplicationsEnabled"); final long identity = Binder.clearCallingIdentity(); try { Loading Loading @@ -3496,6 +3571,9 @@ public class SubscriptionManagerService extends ISub.Stub { enforcePermissions("setDeviceToDeviceStatusSharing", Manifest.permission.MODIFY_PHONE_STATE); enforceTelephonyFeatureWithException(getCurrentPackageName(), "setDeviceToDeviceStatusSharing"); final long identity = Binder.clearCallingIdentity(); try { if (sharing < SubscriptionManager.D2D_SHARING_DISABLED Loading Loading @@ -3528,6 +3606,9 @@ public class SubscriptionManagerService extends ISub.Stub { enforcePermissions("setDeviceToDeviceStatusSharingContacts", Manifest.permission.MODIFY_PHONE_STATE); enforceTelephonyFeatureWithException(getCurrentPackageName(), "setDeviceToDeviceStatusSharingContacts"); final long identity = Binder.clearCallingIdentity(); try { Objects.requireNonNull(contacts, "contacts"); Loading Loading @@ -3595,6 +3676,8 @@ public class SubscriptionManagerService extends ISub.Stub { Manifest.permission.READ_PHONE_NUMBERS, Manifest.permission.READ_PRIVILEGED_PHONE_STATE); enforceTelephonyFeatureWithException(callingPackage, "getPhoneNumber"); final long identity = Binder.clearCallingIdentity(); SubscriptionInfoInternal subInfo = mSubscriptionDatabaseManager Loading Loading @@ -3655,6 +3738,9 @@ public class SubscriptionManagerService extends ISub.Stub { Manifest.permission.READ_PHONE_NUMBERS, Manifest.permission.READ_PRIVILEGED_PHONE_STATE); enforceTelephonyFeatureWithException(callingPackage, "getPhoneNumberFromFirstAvailableSource"); String numberFromCarrier = getPhoneNumber(subId, SubscriptionManager.PHONE_NUMBER_SOURCE_CARRIER, callingPackage, callingFeatureId); Loading Loading @@ -3702,6 +3788,8 @@ public class SubscriptionManagerService extends ISub.Stub { + SubscriptionManager.phoneNumberSourceToString(source)); } enforceTelephonyFeatureWithException(callingPackage, "setPhoneNumber"); Objects.requireNonNull(number, "number"); final long identity = Binder.clearCallingIdentity(); Loading Loading @@ -3977,6 +4065,9 @@ public class SubscriptionManagerService extends ISub.Stub { enforcePermissions("restoreAllSimSpecificSettingsFromBackup", Manifest.permission.MODIFY_PHONE_STATE); enforceTelephonyFeatureWithException(getCurrentPackageName(), "restoreAllSimSpecificSettingsFromBackup"); long token = Binder.clearCallingIdentity(); try { Bundle bundle = new Bundle(); Loading Loading @@ -4199,6 +4290,40 @@ public class SubscriptionManagerService extends ISub.Stub { } } /** * Get the current calling package name. * @return the current calling package name */ @Nullable private String getCurrentPackageName() { if (mPackageManager == null) return null; String[] callingUids = mPackageManager.getPackagesForUid(Binder.getCallingUid()); return (callingUids == null) ? null : callingUids[0]; } /** * Make sure the device has required telephony feature * * @throws UnsupportedOperationException if the device does not have required telephony feature */ private void enforceTelephonyFeatureWithException(@Nullable String callingPackage, @NonNull String methodName) { if (callingPackage == null || mPackageManager == null) { return; } if (!mFeatureFlags.enforceTelephonyFeatureMappingForPublicApis() || !CompatChanges.isChangeEnabled(ENABLE_FEATURE_MAPPING, callingPackage, Binder.getCallingUserHandle())) { return; } if (!mPackageManager.hasSystemFeature(FEATURE_TELEPHONY_SUBSCRIPTION)) { throw new UnsupportedOperationException( methodName + " is unsupported without " + FEATURE_TELEPHONY_SUBSCRIPTION); } } /** * @return The logical SIM slot/sub mapping to string. */ Loading
tests/telephonytests/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -42,6 +42,7 @@ android_test { "testables", "platform-compat-test-rules", "flag-junit", "telephony_flags_core_java_lib", ], jarjar_rules: ":jarjar-rules-telephony-tests", Loading
tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java +47 −0 Original line number Diff line number Diff line Loading @@ -113,6 +113,7 @@ import com.android.internal.telephony.subscription.SubscriptionManagerService.Su import com.android.internal.telephony.uicc.IccCardStatus; import com.android.internal.telephony.uicc.UiccSlot; import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges; import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges; import org.junit.After; Loading Loading @@ -232,6 +233,11 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { doReturn(true).when(mUserManager) .isManagedProfile(eq(FAKE_MANAGED_PROFILE_USER_HANDLE.getIdentifier())); // Due to affect exist implementation, bypass feature flag. doReturn(false).when(mFlags).enforceTelephonyFeatureMappingForPublicApis(); doReturn(true).when(mPackageManager).hasSystemFeature( eq(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)); logd("SubscriptionManagerServiceTest -Setup!"); } Loading Loading @@ -407,7 +413,12 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { } @Test @DisableCompatChanges({TelephonyManager.ENABLE_FEATURE_MAPPING}) public void testSetPhoneNumber() { doReturn(false).when(mFlags).enforceTelephonyFeatureMapping(); doReturn(true).when(mPackageManager).hasSystemFeature( eq(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)); mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); mSubscriptionManagerServiceUT.addSubInfo(FAKE_ICCID1, FAKE_CARRIER_NAME1, 0, SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM); Loading Loading @@ -443,6 +454,41 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { verify(mMockedSubscriptionManagerServiceCallback).onSubscriptionChanged(eq(1)); } @Test @EnableCompatChanges({TelephonyManager.ENABLE_FEATURE_MAPPING}) public void testSetPhoneNumber_EnabledEnforceTelephonyFeatureMappingForPublicApis() { mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); mSubscriptionManagerServiceUT.addSubInfo(FAKE_ICCID1, FAKE_CARRIER_NAME1, 0, SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM); processAllMessages(); verify(mMockedSubscriptionManagerServiceCallback).onSubscriptionChanged(eq(1)); Mockito.clearInvocations(mMockedSubscriptionManagerServiceCallback); // Grant carrier privilege setCarrierPrivilegesForSubId(true, 1); // Enabled FeatureFlags and ENABLE_FEATURE_MAPPING, telephony features are defined doReturn(true).when(mFlags).enforceTelephonyFeatureMappingForPublicApis(); doReturn(true).when(mPackageManager).hasSystemFeature( eq(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)); try { mSubscriptionManagerServiceUT.setPhoneNumber(1, SubscriptionManager.PHONE_NUMBER_SOURCE_CARRIER, FAKE_PHONE_NUMBER2, CALLING_PACKAGE, CALLING_FEATURE); } catch (UnsupportedOperationException e) { fail("Not expect exception " + e.getMessage()); } // Telephony features is not defined, expect UnsupportedOperationException. doReturn(false).when(mPackageManager).hasSystemFeature( eq(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)); assertThrows(UnsupportedOperationException.class, () -> mSubscriptionManagerServiceUT.setPhoneNumber(1, SubscriptionManager.PHONE_NUMBER_SOURCE_CARRIER, FAKE_PHONE_NUMBER2, CALLING_PACKAGE, CALLING_FEATURE)); } @Test public void testGetAllSubInfoList() { mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); Loading Loading @@ -2274,6 +2320,7 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { } @Test @DisableCompatChanges({TelephonyManager.ENABLE_FEATURE_MAPPING}) public void testGetPhoneNumber() { mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE); testSetPhoneNumber(); Loading