Loading src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +152 −51 Original line number Diff line number Diff line Loading @@ -51,6 +51,7 @@ import android.telephony.SubscriptionManager; import android.telephony.SubscriptionManager.PhoneNumberSource; import android.telephony.SubscriptionManager.SimDisplayNameSource; import android.telephony.SubscriptionManager.SubscriptionType; import android.telephony.TelephonyCallback; import android.telephony.TelephonyFrameworkInitializer; import android.telephony.TelephonyManager; import android.telephony.TelephonyRegistryManager; Loading @@ -72,6 +73,7 @@ import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneFactory; import com.android.internal.telephony.TelephonyIntents; import com.android.internal.telephony.TelephonyPermissions; import com.android.internal.telephony.data.PhoneSwitcher; import com.android.internal.telephony.euicc.EuiccController; import com.android.internal.telephony.subscription.SubscriptionDatabaseManager.SubscriptionDatabaseManagerCallback; import com.android.internal.telephony.uicc.IccUtils; Loading Loading @@ -120,6 +122,10 @@ public class SubscriptionManagerService extends ISub.Stub { @NonNull private final Context mContext; /** App Ops manager instance. */ @NonNull private final AppOpsManager mAppOpsManager; /** Telephony manager instance. */ @NonNull private final TelephonyManager mTelephonyManager; Loading Loading @@ -316,6 +322,7 @@ public class SubscriptionManagerService extends ISub.Stub { mTelephonyManager = context.getSystemService(TelephonyManager.class); mSubscriptionManager = context.getSystemService(SubscriptionManager.class); mEuiccManager = context.getSystemService(EuiccManager.class); mAppOpsManager = context.getSystemService(AppOpsManager.class); mUiccController = UiccController.getInstance(); mHandler = new Handler(looper); Loading Loading @@ -902,8 +909,7 @@ public class SubscriptionManagerService extends ISub.Stub { public List<SubscriptionInfo> getAllSubInfoList(@NonNull String callingPackage, @Nullable String callingFeatureId) { // Verify that the callingPackage belongs to the calling UID mContext.getSystemService(AppOpsManager.class) .checkPackage(Binder.getCallingUid(), callingPackage); mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); // Check if the caller has READ_PHONE_STATE, READ_PRIVILEGED_PHONE_STATE, or carrier // privilege on any active subscription. The carrier app will get full subscription infos Loading Loading @@ -951,8 +957,7 @@ public class SubscriptionManagerService extends ISub.Stub { public SubscriptionInfo getActiveSubscriptionInfo(int subId, @NonNull String callingPackage, @Nullable String callingFeatureId) { // Verify that the callingPackage belongs to the calling UID mContext.getSystemService(AppOpsManager.class) .checkPackage(Binder.getCallingUid(), callingPackage); mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(mContext, subId, callingPackage, callingFeatureId, "getActiveSubscriptionInfo")) { Loading @@ -977,20 +982,33 @@ public class SubscriptionManagerService extends ISub.Stub { * Get the active {@link SubscriptionInfo} associated with the iccId. * * @param iccId the IccId of SIM card * @param callingPackage The package making the call * @param callingFeatureId The feature in the package * @param callingPackage The package making the call. * @param callingFeatureId The feature in the package. * * @return The subscription info. */ @Override @Nullable @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public SubscriptionInfo getActiveSubscriptionInfoForIccId(@NonNull String iccId, @NonNull String callingPackage, @Nullable String callingFeatureId) { // Verify that the callingPackage belongs to the calling UID mContext.getSystemService(AppOpsManager.class) .checkPackage(Binder.getCallingUid(), callingPackage); mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); return null; enforcePermissions("getActiveSubscriptionInfoForIccId", Manifest.permission.READ_PRIVILEGED_PHONE_STATE); final long identity = Binder.clearCallingIdentity(); try { iccId = IccUtils.stripTrailingFs(iccId); SubscriptionInfoInternal subInfo = mSubscriptionDatabaseManager .getSubscriptionInfoInternalByIccId(iccId); return (subInfo != null && subInfo.isActive()) ? subInfo.toSubscriptionInfo() : null; } finally { Binder.restoreCallingIdentity(identity); } } /** Loading @@ -1012,8 +1030,7 @@ public class SubscriptionManagerService extends ISub.Stub { public SubscriptionInfo getActiveSubscriptionInfoForSimSlotIndex(int slotIndex, @NonNull String callingPackage, @Nullable String callingFeatureId) { // Verify that the callingPackage belongs to the calling UID mContext.getSystemService(AppOpsManager.class) .checkPackage(Binder.getCallingUid(), callingPackage); mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); int subId = mSlotIndexToSubId.getOrDefault(slotIndex, SubscriptionManager.INVALID_SUBSCRIPTION_ID); Loading Loading @@ -1061,8 +1078,7 @@ public class SubscriptionManagerService extends ISub.Stub { public List<SubscriptionInfo> getActiveSubscriptionInfoList(@NonNull String callingPackage, @Nullable String callingFeatureId) { // Verify that the callingPackage belongs to the calling UID mContext.getSystemService(AppOpsManager.class) .checkPackage(Binder.getCallingUid(), callingPackage); mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); // Check if the caller has READ_PHONE_STATE, READ_PRIVILEGED_PHONE_STATE, or carrier // privilege on any active subscription. The carrier app will get full subscription infos Loading Loading @@ -1109,8 +1125,7 @@ public class SubscriptionManagerService extends ISub.Stub { public int getActiveSubInfoCount(@NonNull String callingPackage, @Nullable String callingFeatureId) { // Verify that the callingPackage belongs to the calling UID mContext.getSystemService(AppOpsManager.class) .checkPackage(Binder.getCallingUid(), callingPackage); mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); if (!TelephonyPermissions.checkReadPhoneStateOnAnyActiveSub(mContext, Binder.getCallingPid(), Binder.getCallingUid(), callingPackage, callingFeatureId, Loading Loading @@ -1147,8 +1162,8 @@ public class SubscriptionManagerService extends ISub.Stub { public List<SubscriptionInfo> getAvailableSubscriptionInfoList(@NonNull String callingPackage, @Nullable String callingFeatureId) { // Verify that the callingPackage belongs to the calling UID mContext.getSystemService(AppOpsManager.class) .checkPackage(Binder.getCallingUid(), callingPackage); mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); enforcePermissions("getAvailableSubscriptionInfoList", Manifest.permission.READ_PRIVILEGED_PHONE_STATE); Loading @@ -1175,18 +1190,43 @@ public class SubscriptionManagerService extends ISub.Stub { } /** * @see SubscriptionManager#getAccessibleSubscriptionInfoList * Gets the SubscriptionInfo(s) of all embedded subscriptions accessible to the calling app, if * any. * * <p>Only those subscriptions for which the calling app has carrier privileges per the * subscription metadata, if any, will be included in the returned list. * * <p>The records will be sorted by {@link SubscriptionInfo#getSimSlotIndex} then by * {@link SubscriptionInfo#getSubscriptionId}. * * @return Sorted list of the current embedded {@link SubscriptionInfo} records available on the * device which are accessible to the caller. * <ul> * <li> * * if the list is non-empty the list is sorted by {@link SubscriptionInfo#getSimSlotIndex} * then by {@link SubscriptionInfo#getSubscriptionId}. * </ul> */ @Override public List<SubscriptionInfo> getAccessibleSubscriptionInfoList( @NonNull String callingPackage) { // Verify that the callingPackage belongs to the calling UID mContext.getSystemService(AppOpsManager.class) .checkPackage(Binder.getCallingUid(), callingPackage); mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); if (!mEuiccManager.isEnabled()) { return null; } return mSubscriptionDatabaseManager.getAllSubscriptions().stream() .map(SubscriptionInfoInternal::toSubscriptionInfo) .filter(subInfo -> mSubscriptionManager .canManageSubscription(subInfo, callingPackage)) .sorted(Comparator.comparing(SubscriptionInfo::getSimSlotIndex) .thenComparing(SubscriptionInfo::getSubscriptionId)) .collect(Collectors.toList()); } /** * @see SubscriptionManager#requestEmbeddedSubscriptionInfoListRefresh */ Loading Loading @@ -1437,9 +1477,7 @@ public class SubscriptionManagerService extends ISub.Stub { @Override public int setOpportunistic(boolean opportunistic, int subId, @NonNull String callingPackage) { // Verify that the callingPackage belongs to the calling UID mContext.getSystemService(AppOpsManager.class) .checkPackage(Binder.getCallingUid(), callingPackage); mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); return 0; } Loading @@ -1463,9 +1501,7 @@ public class SubscriptionManagerService extends ISub.Stub { @Override public ParcelUuid createSubscriptionGroup(int[] subIdList, @NonNull String callingPackage) { // Verify that the callingPackage belongs to the calling UID mContext.getSystemService(AppOpsManager.class) .checkPackage(Binder.getCallingUid(), callingPackage); mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); return null; } Loading Loading @@ -1500,8 +1536,7 @@ public class SubscriptionManagerService extends ISub.Stub { public List<SubscriptionInfo> getOpportunisticSubscriptions(@NonNull String callingPackage, @Nullable String callingFeatureId) { // Verify that the callingPackage belongs to the calling UID mContext.getSystemService(AppOpsManager.class) .checkPackage(Binder.getCallingUid(), callingPackage); mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); return Collections.emptyList(); } Loading @@ -1510,8 +1545,7 @@ public class SubscriptionManagerService extends ISub.Stub { public void removeSubscriptionsFromGroup(int[] subIdList, @NonNull ParcelUuid groupUuid, @NonNull String callingPackage) { // Verify that the callingPackage belongs to the calling UID mContext.getSystemService(AppOpsManager.class) .checkPackage(Binder.getCallingUid(), callingPackage); mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); } Loading @@ -1519,9 +1553,7 @@ public class SubscriptionManagerService extends ISub.Stub { public void addSubscriptionsIntoGroup(int[] subIdList, @NonNull ParcelUuid groupUuid, @NonNull String callingPackage) { // Verify that the callingPackage belongs to the calling UID mContext.getSystemService(AppOpsManager.class) .checkPackage(Binder.getCallingUid(), callingPackage); mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); } /** Loading Loading @@ -1556,8 +1588,7 @@ public class SubscriptionManagerService extends ISub.Stub { public List<SubscriptionInfo> getSubscriptionsInGroup(@NonNull ParcelUuid groupUuid, @NonNull String callingPackage, @Nullable String callingFeatureId) { // Verify that the callingPackage belongs to the calling UID mContext.getSystemService(AppOpsManager.class) .checkPackage(Binder.getCallingUid(), callingPackage); mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); // If the calling app neither has carrier privileges nor READ_PHONE_STATE and access to // device identifiers, it will throw a SecurityException. Loading Loading @@ -1858,8 +1889,7 @@ public class SubscriptionManagerService extends ISub.Stub { public String getSubscriptionProperty(int subId, @NonNull String propKey, @NonNull String callingPackage, @Nullable String callingFeatureId) { // Verify that the callingPackage belongs to the calling UID mContext.getSystemService(AppOpsManager.class) .checkPackage(Binder.getCallingUid(), callingPackage); mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); return null; } Loading @@ -1869,14 +1899,62 @@ public class SubscriptionManagerService extends ISub.Stub { return true; } /** * Check if a subscription is active. * * @param subId The subscription id to check. * * @return {@code true} if the subscription is active. * * @throws IllegalArgumentException if the provided slot index is invalid. */ @Override @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isSubscriptionEnabled(int subId) { return true; enforcePermissions("isSubscriptionEnabled", Manifest.permission.READ_PRIVILEGED_PHONE_STATE); if (!SubscriptionManager.isValidSubscriptionId(subId)) { throw new IllegalArgumentException("Invalid subscription id " + subId); } final long identity = Binder.clearCallingIdentity(); try { SubscriptionInfoInternal subInfo = mSubscriptionDatabaseManager .getSubscriptionInfoInternal(subId); return subInfo != null && subInfo.isActive(); } finally { Binder.restoreCallingIdentity(identity); } } /** * Get the active subscription id by logical SIM slot index. * * @param slotIndex The logical SIM slot index. * @return The active subscription id. * * @throws IllegalArgumentException if the provided slot index is invalid. */ @Override @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getEnabledSubscriptionId(int slotIndex) { return 0; enforcePermissions("getEnabledSubscriptionId", Manifest.permission.READ_PRIVILEGED_PHONE_STATE); if (!SubscriptionManager.isValidSlotIndex(slotIndex)) { throw new IllegalArgumentException("Invalid slot index " + slotIndex); } final long identity = Binder.clearCallingIdentity(); try { return mSubscriptionDatabaseManager.getAllSubscriptions().stream() .filter(subInfo -> subInfo.isActive() && subInfo.getSimSlotIndex() == slotIndex) .mapToInt(SubscriptionInfoInternal::getSubscriptionId) .findFirst() .orElse(SubscriptionManager.INVALID_SUBSCRIPTION_ID); } finally { Binder.restoreCallingIdentity(identity); } } @Override Loading @@ -1902,8 +1980,7 @@ public class SubscriptionManagerService extends ISub.Stub { public boolean isActiveSubId(int subId, @NonNull String callingPackage, @Nullable String callingFeatureId) { // Verify that the callingPackage belongs to the calling UID mContext.getSystemService(AppOpsManager.class) .checkPackage(Binder.getCallingUid(), callingPackage); mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(mContext, subId, callingPackage, callingFeatureId, "isActiveSubId")) { Loading @@ -1920,9 +1997,33 @@ public class SubscriptionManagerService extends ISub.Stub { } } /** * Get active data subscription id. Active data subscription refers to the subscription * currently chosen to provide cellular internet connection to the user. This may be * different from getDefaultDataSubscriptionId(). * * @return Active data subscription id if any is chosen, or * SubscriptionManager.INVALID_SUBSCRIPTION_ID if not. * * @see TelephonyCallback.ActiveDataSubscriptionIdListener */ @Override public int getActiveDataSubscriptionId() { return 0; final long token = Binder.clearCallingIdentity(); try { PhoneSwitcher phoneSwitcher = PhoneSwitcher.getInstance(); if (phoneSwitcher != null) { int activeDataSubId = phoneSwitcher.getActiveDataSubId(); if (SubscriptionManager.isUsableSubscriptionId(activeDataSubId)) { return activeDataSubId; } } // If phone switcher isn't ready, or active data sub id is not available, use default // sub id from settings. return getDefaultDataSubId(); } finally { Binder.restoreCallingIdentity(token); } } @Override Loading Loading @@ -1997,8 +2098,7 @@ public class SubscriptionManagerService extends ISub.Stub { public String getPhoneNumber(int subId, @PhoneNumberSource int source, @NonNull String callingPackage, @Nullable String callingFeatureId) { // Verify that the callingPackage belongs to the calling UID mContext.getSystemService(AppOpsManager.class) .checkPackage(Binder.getCallingUid(), callingPackage); mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); TelephonyPermissions.enforceAnyPermissionGrantedOrCarrierPrivileges( mContext, subId, Binder.getCallingUid(), "getPhoneNumber", Loading Loading @@ -2039,8 +2139,7 @@ public class SubscriptionManagerService extends ISub.Stub { public String getPhoneNumberFromFirstAvailableSource(int subId, @NonNull String callingPackage, @Nullable String callingFeatureId) { // Verify that the callingPackage belongs to the calling UID mContext.getSystemService(AppOpsManager.class) .checkPackage(Binder.getCallingUid(), callingPackage); mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); return null; } Loading @@ -2049,8 +2148,7 @@ public class SubscriptionManagerService extends ISub.Stub { public void setPhoneNumber(int subId, @PhoneNumberSource int source, @NonNull String number, @NonNull String callingPackage, @Nullable String callingFeatureId) { // Verify that the callingPackage belongs to the calling UID mContext.getSystemService(AppOpsManager.class) .checkPackage(Binder.getCallingUid(), callingPackage); mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); if (source != SubscriptionManager.PHONE_NUMBER_SOURCE_CARRIER) { throw new IllegalArgumentException("setPhoneNumber doesn't accept source " Loading Loading @@ -2083,8 +2181,7 @@ public class SubscriptionManagerService extends ISub.Stub { @Override public int setUsageSetting(int usageSetting, int subId, @NonNull String callingPackage) { // Verify that the callingPackage belongs to the calling UID mContext.getSystemService(AppOpsManager.class) .checkPackage(Binder.getCallingUid(), callingPackage); mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); return 0; } Loading Loading @@ -2238,7 +2335,11 @@ public class SubscriptionManagerService extends ISub.Stub { pw.println("defaultSubId=" + getDefaultSubId()); pw.println("defaultVoiceSubId=" + getDefaultVoiceSubId()); pw.println("defaultDataSubId" + getDefaultDataSubId()); pw.println("activeDataSubId" + getActiveDataSubscriptionId()); pw.println("defaultSmsSubId" + getDefaultSmsSubId()); if (mEuiccManager != null) { pw.println("Euicc enabled=" + mEuiccManager.isEnabled()); } pw.decreaseIndent(); } } tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java +4 −0 Original line number Diff line number Diff line Loading @@ -103,6 +103,7 @@ import com.android.internal.telephony.data.DataRetryManager; import com.android.internal.telephony.data.DataServiceManager; import com.android.internal.telephony.data.DataSettingsManager; import com.android.internal.telephony.data.LinkBandwidthEstimator; import com.android.internal.telephony.data.PhoneSwitcher; import com.android.internal.telephony.emergency.EmergencyNumberTracker; import com.android.internal.telephony.imsphone.ImsExternalCallTracker; import com.android.internal.telephony.imsphone.ImsPhone; Loading Loading @@ -212,6 +213,7 @@ public abstract class TelephonyTest { protected RuimRecords mRuimRecords; protected IsimUiccRecords mIsimUiccRecords; protected ProxyController mProxyController; protected PhoneSwitcher mPhoneSwitcher; protected Singleton<IActivityManager> mIActivityManagerSingleton; protected IActivityManager mIActivityManager; protected IIntentSender mIIntentSender; Loading Loading @@ -442,6 +444,7 @@ public abstract class TelephonyTest { mRuimRecords = Mockito.mock(RuimRecords.class); mIsimUiccRecords = Mockito.mock(IsimUiccRecords.class); mProxyController = Mockito.mock(ProxyController.class); mPhoneSwitcher = Mockito.mock(PhoneSwitcher.class); mIActivityManagerSingleton = Mockito.mock(Singleton.class); mIActivityManager = Mockito.mock(IActivityManager.class); mIIntentSender = Mockito.mock(IIntentSender.class); Loading Loading @@ -808,6 +811,7 @@ public abstract class TelephonyTest { replaceInstance(CdmaSubscriptionSourceManager.class, "sInstance", null, mCdmaSSM); replaceInstance(SubscriptionController.class, "sInstance", null, mSubscriptionController); replaceInstance(ProxyController.class, "sProxyController", null, mProxyController); replaceInstance(PhoneSwitcher.class, "sPhoneSwitcher", null, mPhoneSwitcher); replaceInstance(ActivityManager.class, "IActivityManagerSingleton", null, mIActivityManagerSingleton); replaceInstance(CdmaSubscriptionSourceManager.class, Loading tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java +75 −3 Original line number Diff line number Diff line Loading @@ -210,6 +210,9 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { method.setAccessible(true); method.invoke(map, subInfo.getSimSlotIndex(), subId); mContextFixture.removeCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); processAllMessages(); verify(mMockedSubscriptionManagerServiceCallback).onSubscriptionChanged(eq(subId)); Mockito.clearInvocations(mMockedSubscriptionManagerServiceCallback); return subId; } catch (Exception e) { fail("Failed to insert subscription. e=" + e); Loading Loading @@ -337,8 +340,6 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { insertSubscription(FAKE_SUBSCRIPTION_INFO1); insertSubscription(FAKE_SUBSCRIPTION_INFO2); verify(mMockedSubscriptionManagerServiceCallback).onSubscriptionChanged(eq(2)); // Should throw security exception if the caller does not have permission. assertThrows(SecurityException.class, () -> mSubscriptionManagerServiceUT.getAllSubInfoList( Loading Loading @@ -818,7 +819,6 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { @Test public void testSetIconTint() throws Exception { insertSubscription(FAKE_SUBSCRIPTION_INFO1); Mockito.clearInvocations(mMockedSubscriptionManagerServiceCallback); // Should fail without MODIFY_PHONE_STATE assertThrows(SecurityException.class, () -> mSubscriptionManagerServiceUT Loading @@ -834,4 +834,76 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { assertThat(subInfo.getIconTint()).isEqualTo(12345); verify(mMockedSubscriptionManagerServiceCallback).onSubscriptionChanged(eq(1)); } @Test public void testGetActiveSubscriptionInfoForIccId() { insertSubscription(FAKE_SUBSCRIPTION_INFO1); // Should fail without READ_PRIVILEGED_PHONE_STATE assertThrows(SecurityException.class, () -> mSubscriptionManagerServiceUT .getActiveSubscriptionInfoForIccId(FAKE_ICCID1, CALLING_PACKAGE, CALLING_FEATURE)); mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE); SubscriptionInfo subInfo = mSubscriptionManagerServiceUT.getActiveSubscriptionInfoForIccId( FAKE_ICCID1, CALLING_PACKAGE, CALLING_FEATURE); assertThat(subInfo).isEqualTo(FAKE_SUBSCRIPTION_INFO1.toSubscriptionInfo()); } @Test public void testGetAccessibleSubscriptionInfoList() { insertSubscription(FAKE_SUBSCRIPTION_INFO1); doReturn(false).when(mEuiccManager).isEnabled(); assertThat(mSubscriptionManagerServiceUT.getAccessibleSubscriptionInfoList( CALLING_PACKAGE)).isNull(); doReturn(true).when(mEuiccManager).isEnabled(); assertThat(mSubscriptionManagerServiceUT.getAccessibleSubscriptionInfoList( CALLING_PACKAGE)).isEmpty(); doReturn(true).when(mSubscriptionManager).canManageSubscription( eq(FAKE_SUBSCRIPTION_INFO1.toSubscriptionInfo()), eq(CALLING_PACKAGE)); assertThat(mSubscriptionManagerServiceUT.getAccessibleSubscriptionInfoList( CALLING_PACKAGE)).isEqualTo(List.of(FAKE_SUBSCRIPTION_INFO1.toSubscriptionInfo())); } @Test public void testIsSubscriptionEnabled() { insertSubscription(FAKE_SUBSCRIPTION_INFO1); // Should fail without READ_PRIVILEGED_PHONE_STATE assertThrows(SecurityException.class, () -> mSubscriptionManagerServiceUT .isSubscriptionEnabled(1)); mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE); assertThat(mSubscriptionManagerServiceUT.isSubscriptionEnabled(1)).isTrue(); assertThat(mSubscriptionManagerServiceUT.isSubscriptionEnabled(2)).isFalse(); } @Test public void testGetEnabledSubscriptionId() { insertSubscription(FAKE_SUBSCRIPTION_INFO1); // Should fail without READ_PRIVILEGED_PHONE_STATE assertThrows(SecurityException.class, () -> mSubscriptionManagerServiceUT .getEnabledSubscriptionId(0)); mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE); assertThrows(IllegalArgumentException.class, () -> mSubscriptionManagerServiceUT .getEnabledSubscriptionId(SubscriptionManager.INVALID_SIM_SLOT_INDEX)); doReturn(2).when(mTelephonyManager).getActiveModemCount(); assertThat(mSubscriptionManagerServiceUT.getEnabledSubscriptionId(0)).isEqualTo(1); assertThat(mSubscriptionManagerServiceUT.getEnabledSubscriptionId(1)).isEqualTo( SubscriptionManager.INVALID_SUBSCRIPTION_ID); assertThrows(IllegalArgumentException.class, () -> mSubscriptionManagerServiceUT .getEnabledSubscriptionId(2)); } @Test public void testGetActiveDataSubscriptionId() { doReturn(12345).when(mPhoneSwitcher).getActiveDataSubId(); assertThat(mSubscriptionManagerServiceUT.getActiveDataSubscriptionId()).isEqualTo(12345); } } Loading
src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +152 −51 Original line number Diff line number Diff line Loading @@ -51,6 +51,7 @@ import android.telephony.SubscriptionManager; import android.telephony.SubscriptionManager.PhoneNumberSource; import android.telephony.SubscriptionManager.SimDisplayNameSource; import android.telephony.SubscriptionManager.SubscriptionType; import android.telephony.TelephonyCallback; import android.telephony.TelephonyFrameworkInitializer; import android.telephony.TelephonyManager; import android.telephony.TelephonyRegistryManager; Loading @@ -72,6 +73,7 @@ import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneFactory; import com.android.internal.telephony.TelephonyIntents; import com.android.internal.telephony.TelephonyPermissions; import com.android.internal.telephony.data.PhoneSwitcher; import com.android.internal.telephony.euicc.EuiccController; import com.android.internal.telephony.subscription.SubscriptionDatabaseManager.SubscriptionDatabaseManagerCallback; import com.android.internal.telephony.uicc.IccUtils; Loading Loading @@ -120,6 +122,10 @@ public class SubscriptionManagerService extends ISub.Stub { @NonNull private final Context mContext; /** App Ops manager instance. */ @NonNull private final AppOpsManager mAppOpsManager; /** Telephony manager instance. */ @NonNull private final TelephonyManager mTelephonyManager; Loading Loading @@ -316,6 +322,7 @@ public class SubscriptionManagerService extends ISub.Stub { mTelephonyManager = context.getSystemService(TelephonyManager.class); mSubscriptionManager = context.getSystemService(SubscriptionManager.class); mEuiccManager = context.getSystemService(EuiccManager.class); mAppOpsManager = context.getSystemService(AppOpsManager.class); mUiccController = UiccController.getInstance(); mHandler = new Handler(looper); Loading Loading @@ -902,8 +909,7 @@ public class SubscriptionManagerService extends ISub.Stub { public List<SubscriptionInfo> getAllSubInfoList(@NonNull String callingPackage, @Nullable String callingFeatureId) { // Verify that the callingPackage belongs to the calling UID mContext.getSystemService(AppOpsManager.class) .checkPackage(Binder.getCallingUid(), callingPackage); mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); // Check if the caller has READ_PHONE_STATE, READ_PRIVILEGED_PHONE_STATE, or carrier // privilege on any active subscription. The carrier app will get full subscription infos Loading Loading @@ -951,8 +957,7 @@ public class SubscriptionManagerService extends ISub.Stub { public SubscriptionInfo getActiveSubscriptionInfo(int subId, @NonNull String callingPackage, @Nullable String callingFeatureId) { // Verify that the callingPackage belongs to the calling UID mContext.getSystemService(AppOpsManager.class) .checkPackage(Binder.getCallingUid(), callingPackage); mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(mContext, subId, callingPackage, callingFeatureId, "getActiveSubscriptionInfo")) { Loading @@ -977,20 +982,33 @@ public class SubscriptionManagerService extends ISub.Stub { * Get the active {@link SubscriptionInfo} associated with the iccId. * * @param iccId the IccId of SIM card * @param callingPackage The package making the call * @param callingFeatureId The feature in the package * @param callingPackage The package making the call. * @param callingFeatureId The feature in the package. * * @return The subscription info. */ @Override @Nullable @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public SubscriptionInfo getActiveSubscriptionInfoForIccId(@NonNull String iccId, @NonNull String callingPackage, @Nullable String callingFeatureId) { // Verify that the callingPackage belongs to the calling UID mContext.getSystemService(AppOpsManager.class) .checkPackage(Binder.getCallingUid(), callingPackage); mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); return null; enforcePermissions("getActiveSubscriptionInfoForIccId", Manifest.permission.READ_PRIVILEGED_PHONE_STATE); final long identity = Binder.clearCallingIdentity(); try { iccId = IccUtils.stripTrailingFs(iccId); SubscriptionInfoInternal subInfo = mSubscriptionDatabaseManager .getSubscriptionInfoInternalByIccId(iccId); return (subInfo != null && subInfo.isActive()) ? subInfo.toSubscriptionInfo() : null; } finally { Binder.restoreCallingIdentity(identity); } } /** Loading @@ -1012,8 +1030,7 @@ public class SubscriptionManagerService extends ISub.Stub { public SubscriptionInfo getActiveSubscriptionInfoForSimSlotIndex(int slotIndex, @NonNull String callingPackage, @Nullable String callingFeatureId) { // Verify that the callingPackage belongs to the calling UID mContext.getSystemService(AppOpsManager.class) .checkPackage(Binder.getCallingUid(), callingPackage); mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); int subId = mSlotIndexToSubId.getOrDefault(slotIndex, SubscriptionManager.INVALID_SUBSCRIPTION_ID); Loading Loading @@ -1061,8 +1078,7 @@ public class SubscriptionManagerService extends ISub.Stub { public List<SubscriptionInfo> getActiveSubscriptionInfoList(@NonNull String callingPackage, @Nullable String callingFeatureId) { // Verify that the callingPackage belongs to the calling UID mContext.getSystemService(AppOpsManager.class) .checkPackage(Binder.getCallingUid(), callingPackage); mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); // Check if the caller has READ_PHONE_STATE, READ_PRIVILEGED_PHONE_STATE, or carrier // privilege on any active subscription. The carrier app will get full subscription infos Loading Loading @@ -1109,8 +1125,7 @@ public class SubscriptionManagerService extends ISub.Stub { public int getActiveSubInfoCount(@NonNull String callingPackage, @Nullable String callingFeatureId) { // Verify that the callingPackage belongs to the calling UID mContext.getSystemService(AppOpsManager.class) .checkPackage(Binder.getCallingUid(), callingPackage); mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); if (!TelephonyPermissions.checkReadPhoneStateOnAnyActiveSub(mContext, Binder.getCallingPid(), Binder.getCallingUid(), callingPackage, callingFeatureId, Loading Loading @@ -1147,8 +1162,8 @@ public class SubscriptionManagerService extends ISub.Stub { public List<SubscriptionInfo> getAvailableSubscriptionInfoList(@NonNull String callingPackage, @Nullable String callingFeatureId) { // Verify that the callingPackage belongs to the calling UID mContext.getSystemService(AppOpsManager.class) .checkPackage(Binder.getCallingUid(), callingPackage); mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); enforcePermissions("getAvailableSubscriptionInfoList", Manifest.permission.READ_PRIVILEGED_PHONE_STATE); Loading @@ -1175,18 +1190,43 @@ public class SubscriptionManagerService extends ISub.Stub { } /** * @see SubscriptionManager#getAccessibleSubscriptionInfoList * Gets the SubscriptionInfo(s) of all embedded subscriptions accessible to the calling app, if * any. * * <p>Only those subscriptions for which the calling app has carrier privileges per the * subscription metadata, if any, will be included in the returned list. * * <p>The records will be sorted by {@link SubscriptionInfo#getSimSlotIndex} then by * {@link SubscriptionInfo#getSubscriptionId}. * * @return Sorted list of the current embedded {@link SubscriptionInfo} records available on the * device which are accessible to the caller. * <ul> * <li> * * if the list is non-empty the list is sorted by {@link SubscriptionInfo#getSimSlotIndex} * then by {@link SubscriptionInfo#getSubscriptionId}. * </ul> */ @Override public List<SubscriptionInfo> getAccessibleSubscriptionInfoList( @NonNull String callingPackage) { // Verify that the callingPackage belongs to the calling UID mContext.getSystemService(AppOpsManager.class) .checkPackage(Binder.getCallingUid(), callingPackage); mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); if (!mEuiccManager.isEnabled()) { return null; } return mSubscriptionDatabaseManager.getAllSubscriptions().stream() .map(SubscriptionInfoInternal::toSubscriptionInfo) .filter(subInfo -> mSubscriptionManager .canManageSubscription(subInfo, callingPackage)) .sorted(Comparator.comparing(SubscriptionInfo::getSimSlotIndex) .thenComparing(SubscriptionInfo::getSubscriptionId)) .collect(Collectors.toList()); } /** * @see SubscriptionManager#requestEmbeddedSubscriptionInfoListRefresh */ Loading Loading @@ -1437,9 +1477,7 @@ public class SubscriptionManagerService extends ISub.Stub { @Override public int setOpportunistic(boolean opportunistic, int subId, @NonNull String callingPackage) { // Verify that the callingPackage belongs to the calling UID mContext.getSystemService(AppOpsManager.class) .checkPackage(Binder.getCallingUid(), callingPackage); mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); return 0; } Loading @@ -1463,9 +1501,7 @@ public class SubscriptionManagerService extends ISub.Stub { @Override public ParcelUuid createSubscriptionGroup(int[] subIdList, @NonNull String callingPackage) { // Verify that the callingPackage belongs to the calling UID mContext.getSystemService(AppOpsManager.class) .checkPackage(Binder.getCallingUid(), callingPackage); mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); return null; } Loading Loading @@ -1500,8 +1536,7 @@ public class SubscriptionManagerService extends ISub.Stub { public List<SubscriptionInfo> getOpportunisticSubscriptions(@NonNull String callingPackage, @Nullable String callingFeatureId) { // Verify that the callingPackage belongs to the calling UID mContext.getSystemService(AppOpsManager.class) .checkPackage(Binder.getCallingUid(), callingPackage); mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); return Collections.emptyList(); } Loading @@ -1510,8 +1545,7 @@ public class SubscriptionManagerService extends ISub.Stub { public void removeSubscriptionsFromGroup(int[] subIdList, @NonNull ParcelUuid groupUuid, @NonNull String callingPackage) { // Verify that the callingPackage belongs to the calling UID mContext.getSystemService(AppOpsManager.class) .checkPackage(Binder.getCallingUid(), callingPackage); mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); } Loading @@ -1519,9 +1553,7 @@ public class SubscriptionManagerService extends ISub.Stub { public void addSubscriptionsIntoGroup(int[] subIdList, @NonNull ParcelUuid groupUuid, @NonNull String callingPackage) { // Verify that the callingPackage belongs to the calling UID mContext.getSystemService(AppOpsManager.class) .checkPackage(Binder.getCallingUid(), callingPackage); mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); } /** Loading Loading @@ -1556,8 +1588,7 @@ public class SubscriptionManagerService extends ISub.Stub { public List<SubscriptionInfo> getSubscriptionsInGroup(@NonNull ParcelUuid groupUuid, @NonNull String callingPackage, @Nullable String callingFeatureId) { // Verify that the callingPackage belongs to the calling UID mContext.getSystemService(AppOpsManager.class) .checkPackage(Binder.getCallingUid(), callingPackage); mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); // If the calling app neither has carrier privileges nor READ_PHONE_STATE and access to // device identifiers, it will throw a SecurityException. Loading Loading @@ -1858,8 +1889,7 @@ public class SubscriptionManagerService extends ISub.Stub { public String getSubscriptionProperty(int subId, @NonNull String propKey, @NonNull String callingPackage, @Nullable String callingFeatureId) { // Verify that the callingPackage belongs to the calling UID mContext.getSystemService(AppOpsManager.class) .checkPackage(Binder.getCallingUid(), callingPackage); mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); return null; } Loading @@ -1869,14 +1899,62 @@ public class SubscriptionManagerService extends ISub.Stub { return true; } /** * Check if a subscription is active. * * @param subId The subscription id to check. * * @return {@code true} if the subscription is active. * * @throws IllegalArgumentException if the provided slot index is invalid. */ @Override @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isSubscriptionEnabled(int subId) { return true; enforcePermissions("isSubscriptionEnabled", Manifest.permission.READ_PRIVILEGED_PHONE_STATE); if (!SubscriptionManager.isValidSubscriptionId(subId)) { throw new IllegalArgumentException("Invalid subscription id " + subId); } final long identity = Binder.clearCallingIdentity(); try { SubscriptionInfoInternal subInfo = mSubscriptionDatabaseManager .getSubscriptionInfoInternal(subId); return subInfo != null && subInfo.isActive(); } finally { Binder.restoreCallingIdentity(identity); } } /** * Get the active subscription id by logical SIM slot index. * * @param slotIndex The logical SIM slot index. * @return The active subscription id. * * @throws IllegalArgumentException if the provided slot index is invalid. */ @Override @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getEnabledSubscriptionId(int slotIndex) { return 0; enforcePermissions("getEnabledSubscriptionId", Manifest.permission.READ_PRIVILEGED_PHONE_STATE); if (!SubscriptionManager.isValidSlotIndex(slotIndex)) { throw new IllegalArgumentException("Invalid slot index " + slotIndex); } final long identity = Binder.clearCallingIdentity(); try { return mSubscriptionDatabaseManager.getAllSubscriptions().stream() .filter(subInfo -> subInfo.isActive() && subInfo.getSimSlotIndex() == slotIndex) .mapToInt(SubscriptionInfoInternal::getSubscriptionId) .findFirst() .orElse(SubscriptionManager.INVALID_SUBSCRIPTION_ID); } finally { Binder.restoreCallingIdentity(identity); } } @Override Loading @@ -1902,8 +1980,7 @@ public class SubscriptionManagerService extends ISub.Stub { public boolean isActiveSubId(int subId, @NonNull String callingPackage, @Nullable String callingFeatureId) { // Verify that the callingPackage belongs to the calling UID mContext.getSystemService(AppOpsManager.class) .checkPackage(Binder.getCallingUid(), callingPackage); mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(mContext, subId, callingPackage, callingFeatureId, "isActiveSubId")) { Loading @@ -1920,9 +1997,33 @@ public class SubscriptionManagerService extends ISub.Stub { } } /** * Get active data subscription id. Active data subscription refers to the subscription * currently chosen to provide cellular internet connection to the user. This may be * different from getDefaultDataSubscriptionId(). * * @return Active data subscription id if any is chosen, or * SubscriptionManager.INVALID_SUBSCRIPTION_ID if not. * * @see TelephonyCallback.ActiveDataSubscriptionIdListener */ @Override public int getActiveDataSubscriptionId() { return 0; final long token = Binder.clearCallingIdentity(); try { PhoneSwitcher phoneSwitcher = PhoneSwitcher.getInstance(); if (phoneSwitcher != null) { int activeDataSubId = phoneSwitcher.getActiveDataSubId(); if (SubscriptionManager.isUsableSubscriptionId(activeDataSubId)) { return activeDataSubId; } } // If phone switcher isn't ready, or active data sub id is not available, use default // sub id from settings. return getDefaultDataSubId(); } finally { Binder.restoreCallingIdentity(token); } } @Override Loading Loading @@ -1997,8 +2098,7 @@ public class SubscriptionManagerService extends ISub.Stub { public String getPhoneNumber(int subId, @PhoneNumberSource int source, @NonNull String callingPackage, @Nullable String callingFeatureId) { // Verify that the callingPackage belongs to the calling UID mContext.getSystemService(AppOpsManager.class) .checkPackage(Binder.getCallingUid(), callingPackage); mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); TelephonyPermissions.enforceAnyPermissionGrantedOrCarrierPrivileges( mContext, subId, Binder.getCallingUid(), "getPhoneNumber", Loading Loading @@ -2039,8 +2139,7 @@ public class SubscriptionManagerService extends ISub.Stub { public String getPhoneNumberFromFirstAvailableSource(int subId, @NonNull String callingPackage, @Nullable String callingFeatureId) { // Verify that the callingPackage belongs to the calling UID mContext.getSystemService(AppOpsManager.class) .checkPackage(Binder.getCallingUid(), callingPackage); mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); return null; } Loading @@ -2049,8 +2148,7 @@ public class SubscriptionManagerService extends ISub.Stub { public void setPhoneNumber(int subId, @PhoneNumberSource int source, @NonNull String number, @NonNull String callingPackage, @Nullable String callingFeatureId) { // Verify that the callingPackage belongs to the calling UID mContext.getSystemService(AppOpsManager.class) .checkPackage(Binder.getCallingUid(), callingPackage); mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); if (source != SubscriptionManager.PHONE_NUMBER_SOURCE_CARRIER) { throw new IllegalArgumentException("setPhoneNumber doesn't accept source " Loading Loading @@ -2083,8 +2181,7 @@ public class SubscriptionManagerService extends ISub.Stub { @Override public int setUsageSetting(int usageSetting, int subId, @NonNull String callingPackage) { // Verify that the callingPackage belongs to the calling UID mContext.getSystemService(AppOpsManager.class) .checkPackage(Binder.getCallingUid(), callingPackage); mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); return 0; } Loading Loading @@ -2238,7 +2335,11 @@ public class SubscriptionManagerService extends ISub.Stub { pw.println("defaultSubId=" + getDefaultSubId()); pw.println("defaultVoiceSubId=" + getDefaultVoiceSubId()); pw.println("defaultDataSubId" + getDefaultDataSubId()); pw.println("activeDataSubId" + getActiveDataSubscriptionId()); pw.println("defaultSmsSubId" + getDefaultSmsSubId()); if (mEuiccManager != null) { pw.println("Euicc enabled=" + mEuiccManager.isEnabled()); } pw.decreaseIndent(); } }
tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java +4 −0 Original line number Diff line number Diff line Loading @@ -103,6 +103,7 @@ import com.android.internal.telephony.data.DataRetryManager; import com.android.internal.telephony.data.DataServiceManager; import com.android.internal.telephony.data.DataSettingsManager; import com.android.internal.telephony.data.LinkBandwidthEstimator; import com.android.internal.telephony.data.PhoneSwitcher; import com.android.internal.telephony.emergency.EmergencyNumberTracker; import com.android.internal.telephony.imsphone.ImsExternalCallTracker; import com.android.internal.telephony.imsphone.ImsPhone; Loading Loading @@ -212,6 +213,7 @@ public abstract class TelephonyTest { protected RuimRecords mRuimRecords; protected IsimUiccRecords mIsimUiccRecords; protected ProxyController mProxyController; protected PhoneSwitcher mPhoneSwitcher; protected Singleton<IActivityManager> mIActivityManagerSingleton; protected IActivityManager mIActivityManager; protected IIntentSender mIIntentSender; Loading Loading @@ -442,6 +444,7 @@ public abstract class TelephonyTest { mRuimRecords = Mockito.mock(RuimRecords.class); mIsimUiccRecords = Mockito.mock(IsimUiccRecords.class); mProxyController = Mockito.mock(ProxyController.class); mPhoneSwitcher = Mockito.mock(PhoneSwitcher.class); mIActivityManagerSingleton = Mockito.mock(Singleton.class); mIActivityManager = Mockito.mock(IActivityManager.class); mIIntentSender = Mockito.mock(IIntentSender.class); Loading Loading @@ -808,6 +811,7 @@ public abstract class TelephonyTest { replaceInstance(CdmaSubscriptionSourceManager.class, "sInstance", null, mCdmaSSM); replaceInstance(SubscriptionController.class, "sInstance", null, mSubscriptionController); replaceInstance(ProxyController.class, "sProxyController", null, mProxyController); replaceInstance(PhoneSwitcher.class, "sPhoneSwitcher", null, mPhoneSwitcher); replaceInstance(ActivityManager.class, "IActivityManagerSingleton", null, mIActivityManagerSingleton); replaceInstance(CdmaSubscriptionSourceManager.class, Loading
tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java +75 −3 Original line number Diff line number Diff line Loading @@ -210,6 +210,9 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { method.setAccessible(true); method.invoke(map, subInfo.getSimSlotIndex(), subId); mContextFixture.removeCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); processAllMessages(); verify(mMockedSubscriptionManagerServiceCallback).onSubscriptionChanged(eq(subId)); Mockito.clearInvocations(mMockedSubscriptionManagerServiceCallback); return subId; } catch (Exception e) { fail("Failed to insert subscription. e=" + e); Loading Loading @@ -337,8 +340,6 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { insertSubscription(FAKE_SUBSCRIPTION_INFO1); insertSubscription(FAKE_SUBSCRIPTION_INFO2); verify(mMockedSubscriptionManagerServiceCallback).onSubscriptionChanged(eq(2)); // Should throw security exception if the caller does not have permission. assertThrows(SecurityException.class, () -> mSubscriptionManagerServiceUT.getAllSubInfoList( Loading Loading @@ -818,7 +819,6 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { @Test public void testSetIconTint() throws Exception { insertSubscription(FAKE_SUBSCRIPTION_INFO1); Mockito.clearInvocations(mMockedSubscriptionManagerServiceCallback); // Should fail without MODIFY_PHONE_STATE assertThrows(SecurityException.class, () -> mSubscriptionManagerServiceUT Loading @@ -834,4 +834,76 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { assertThat(subInfo.getIconTint()).isEqualTo(12345); verify(mMockedSubscriptionManagerServiceCallback).onSubscriptionChanged(eq(1)); } @Test public void testGetActiveSubscriptionInfoForIccId() { insertSubscription(FAKE_SUBSCRIPTION_INFO1); // Should fail without READ_PRIVILEGED_PHONE_STATE assertThrows(SecurityException.class, () -> mSubscriptionManagerServiceUT .getActiveSubscriptionInfoForIccId(FAKE_ICCID1, CALLING_PACKAGE, CALLING_FEATURE)); mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE); SubscriptionInfo subInfo = mSubscriptionManagerServiceUT.getActiveSubscriptionInfoForIccId( FAKE_ICCID1, CALLING_PACKAGE, CALLING_FEATURE); assertThat(subInfo).isEqualTo(FAKE_SUBSCRIPTION_INFO1.toSubscriptionInfo()); } @Test public void testGetAccessibleSubscriptionInfoList() { insertSubscription(FAKE_SUBSCRIPTION_INFO1); doReturn(false).when(mEuiccManager).isEnabled(); assertThat(mSubscriptionManagerServiceUT.getAccessibleSubscriptionInfoList( CALLING_PACKAGE)).isNull(); doReturn(true).when(mEuiccManager).isEnabled(); assertThat(mSubscriptionManagerServiceUT.getAccessibleSubscriptionInfoList( CALLING_PACKAGE)).isEmpty(); doReturn(true).when(mSubscriptionManager).canManageSubscription( eq(FAKE_SUBSCRIPTION_INFO1.toSubscriptionInfo()), eq(CALLING_PACKAGE)); assertThat(mSubscriptionManagerServiceUT.getAccessibleSubscriptionInfoList( CALLING_PACKAGE)).isEqualTo(List.of(FAKE_SUBSCRIPTION_INFO1.toSubscriptionInfo())); } @Test public void testIsSubscriptionEnabled() { insertSubscription(FAKE_SUBSCRIPTION_INFO1); // Should fail without READ_PRIVILEGED_PHONE_STATE assertThrows(SecurityException.class, () -> mSubscriptionManagerServiceUT .isSubscriptionEnabled(1)); mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE); assertThat(mSubscriptionManagerServiceUT.isSubscriptionEnabled(1)).isTrue(); assertThat(mSubscriptionManagerServiceUT.isSubscriptionEnabled(2)).isFalse(); } @Test public void testGetEnabledSubscriptionId() { insertSubscription(FAKE_SUBSCRIPTION_INFO1); // Should fail without READ_PRIVILEGED_PHONE_STATE assertThrows(SecurityException.class, () -> mSubscriptionManagerServiceUT .getEnabledSubscriptionId(0)); mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE); assertThrows(IllegalArgumentException.class, () -> mSubscriptionManagerServiceUT .getEnabledSubscriptionId(SubscriptionManager.INVALID_SIM_SLOT_INDEX)); doReturn(2).when(mTelephonyManager).getActiveModemCount(); assertThat(mSubscriptionManagerServiceUT.getEnabledSubscriptionId(0)).isEqualTo(1); assertThat(mSubscriptionManagerServiceUT.getEnabledSubscriptionId(1)).isEqualTo( SubscriptionManager.INVALID_SUBSCRIPTION_ID); assertThrows(IllegalArgumentException.class, () -> mSubscriptionManagerServiceUT .getEnabledSubscriptionId(2)); } @Test public void testGetActiveDataSubscriptionId() { doReturn(12345).when(mPhoneSwitcher).getActiveDataSubId(); assertThat(mSubscriptionManagerServiceUT.getActiveDataSubscriptionId()).isEqualTo(12345); } }