Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 99e69a7a authored by Aishwarya Mallampati's avatar Aishwarya Mallampati Committed by Jack Yu
Browse files

Add subscription-user association check.

Bug: 250620312
Test: Manually sending/receiving SMS/MMS,
    atest com.android.internal.telephony.SmsControllerTest,
    atest com.android.internal.telephony.SubscriptionControllerTest,
    atest
    com.android.internal.telephony.subscription.SubscriptionManagerServiceTest,
    atest CtsTelephonyTestCases
Merged-In: I12bb0f34042529b76d0953ed51163e8efd1f498f
Change-Id: I12bb0f34042529b76d0953ed51163e8efd1f498f
parent 2df00896
Loading
Loading
Loading
Loading
+50 −1
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
import android.os.TelephonyServiceManager.ServiceRegisterer;
import android.os.UserHandle;
import android.provider.Telephony.Sms.Intents;
import android.telephony.CarrierConfigManager;
import android.telephony.SmsManager;
@@ -156,6 +157,14 @@ public class SmsController extends ISmsImplBase {
            callingPackage = getCallingPackage();
        }

        // Check if user is associated with the subscription
        if (!TelephonyPermissions.checkSubscriptionAssociatedWithUser(mContext, subId,
                Binder.getCallingUserHandle())) {
            // TODO(b/258629881): Display error dialog.
            sendErrorInPendingIntent(sentIntent, SmsManager.RESULT_USER_NOT_ALLOWED);
            return;
        }

        // Perform FDN check
        if (isNumberBlockedByFDN(subId, destAddr, callingPackage)) {
            sendErrorInPendingIntent(sentIntent, SmsManager.RESULT_ERROR_FDN_CHECK_FAILURE);
@@ -206,6 +215,14 @@ public class SmsController extends ISmsImplBase {
            return;
        }

        // Check if user is associated with the subscription
        if (!TelephonyPermissions.checkSubscriptionAssociatedWithUser(mContext, subId,
                Binder.getCallingUserHandle())) {
            // TODO(b/258629881): Display error dialog.
            sendErrorInPendingIntent(sentIntent, SmsManager.RESULT_USER_NOT_ALLOWED);
            return;
        }

        // Perform FDN check
        if (isNumberBlockedByFDN(subId, destAddr, callingPackage)) {
            sendErrorInPendingIntent(sentIntent, SmsManager.RESULT_ERROR_FDN_CHECK_FAILURE);
@@ -279,6 +296,14 @@ public class SmsController extends ISmsImplBase {
            callingPackage = getCallingPackage();
        }

        // Check if user is associated with the subscription
        if (!TelephonyPermissions.checkSubscriptionAssociatedWithUser(mContext, subId,
                Binder.getCallingUserHandle())) {
            // TODO(b/258629881): Display error dialog.
            sendErrorInPendingIntent(sentIntent, SmsManager.RESULT_USER_NOT_ALLOWED);
            return;
        }

        // Perform FDN check
        if (isNumberBlockedByFDN(subId, destAddr, callingPackage)) {
            sendErrorInPendingIntent(sentIntent, SmsManager.RESULT_ERROR_FDN_CHECK_FAILURE);
@@ -308,6 +333,14 @@ public class SmsController extends ISmsImplBase {
            callingPackage = getCallingPackage();
        }

        // Check if user is associated with the subscription
        if (!TelephonyPermissions.checkSubscriptionAssociatedWithUser(mContext, subId,
                Binder.getCallingUserHandle())) {
            // TODO(b/258629881): Display error dialog.
            sendErrorInPendingIntents(sentIntents, SmsManager.RESULT_USER_NOT_ALLOWED);
            return;
        }

        // Perform FDN check
        if (isNumberBlockedByFDN(subId, destAddr, callingPackage)) {
            sendErrorInPendingIntents(sentIntents, SmsManager.RESULT_ERROR_FDN_CHECK_FAILURE);
@@ -335,6 +368,14 @@ public class SmsController extends ISmsImplBase {
            callingPackage = getCallingPackage();
        }

        // Check if user is associated with the subscription
        if (!TelephonyPermissions.checkSubscriptionAssociatedWithUser(mContext, subId,
                Binder.getCallingUserHandle())) {
            // TODO(b/258629881): Display error dialog.
            sendErrorInPendingIntents(sentIntents, SmsManager.RESULT_USER_NOT_ALLOWED);
            return;
        }

        // Perform FDN check
        if (isNumberBlockedByFDN(subId, destAddr, callingPackage)) {
            sendErrorInPendingIntents(sentIntents, SmsManager.RESULT_ERROR_FDN_CHECK_FAILURE);
@@ -775,6 +816,14 @@ public class SmsController extends ISmsImplBase {
            return;
        }

        // Check if user is associated with the subscription
        if (!TelephonyPermissions.checkSubscriptionAssociatedWithUser(mContext, subId,
                Binder.getCallingUserHandle())) {
            // TODO(b/258629881): Display error dialog.
            sendErrorInPendingIntent(sentIntent, SmsManager.RESULT_USER_NOT_ALLOWED);
            return;
        }

        if (port == 0) {
            sendTextForSubscriberWithSelfPermissionsInternal(subId, callingPackage,
                    callingAttributionTag, number, null, text, sentIntent, null, false,
+93 −0
Original line number Diff line number Diff line
@@ -4840,6 +4840,99 @@ public class SubscriptionController extends ISub.Stub {
        }
    }

    /**
     * Check if subscription and user are associated with each other.
     *
     * @param subscriptionId the subId of the subscription
     * @param userHandle user handle of the user
     * @return {@code true} if subscription is associated with user
     * {code true} if there are no subscriptions on device
     * else {@code false} if subscription is not associated with user.
     *
     * @throws SecurityException if the caller doesn't have permissions required.
     * @throws IllegalStateException if subscription service is not available.
     *
     */
    @Override
    public boolean isSubscriptionAssociatedWithUser(int subscriptionId,
            @NonNull UserHandle userHandle) {
        enforceManageSubscriptionUserAssociation("isSubscriptionAssociatedWithUser");

        long token = Binder.clearCallingIdentity();
        try {
            // Return true if there are no subscriptions on the device.
            List<SubscriptionInfo> subInfoList = getAllSubInfoList(
                    mContext.getOpPackageName(), mContext.getAttributionTag());
            if (subInfoList == null || subInfoList.isEmpty()) {
                return true;
            }

            // Get list of subscriptions associated with this user.
            List<SubscriptionInfo> associatedSubscriptionsList =
                    getSubscriptionInfoListAssociatedWithUser(userHandle);
            if (associatedSubscriptionsList.isEmpty()) {
                return false;
            }

            // Return true if required subscription is present in associated subscriptions list.
            for (SubscriptionInfo subInfo: associatedSubscriptionsList) {
                if (subInfo.getSubscriptionId() == subscriptionId){
                    return true;
                }
            }
            return false;
        } finally {
            Binder.restoreCallingIdentity(token);
        }
    }

    /**
     * Get list of subscriptions associated with user.
     *
     * If user handle is associated with some subscriptions, return subscriptionsAssociatedWithUser
     * else return all the subscriptions which are not associated with any user.
     *
     * @param userHandle user handle of the user
     * @return list of subscriptionInfo associated with the user.
     *
     * @throws SecurityException if the caller doesn't have permissions required.
     * @throws IllegalStateException if subscription service is not available.
     *
     */
    @Override
    public @NonNull List<SubscriptionInfo> getSubscriptionInfoListAssociatedWithUser(
            @NonNull UserHandle userHandle) {
        enforceManageSubscriptionUserAssociation("getActiveSubscriptionInfoListAssociatedWithUser");

        long token = Binder.clearCallingIdentity();
        try {
            List<SubscriptionInfo> subInfoList =  getAllSubInfoList(
                    mContext.getOpPackageName(), mContext.getAttributionTag());
            if (subInfoList == null || subInfoList.isEmpty()) {
                return new ArrayList<>();
            }

            List<SubscriptionInfo> subscriptionsAssociatedWithUser = new ArrayList<>();
            List<SubscriptionInfo> subscriptionsWithNoAssociation = new ArrayList<>();
            for (SubscriptionInfo subInfo : subInfoList) {
                int subId = subInfo.getSubscriptionId();
                UserHandle subIdUserHandle = getSubscriptionUserHandle(subId);
                if (userHandle.equals(subIdUserHandle)) {
                    // Store subscriptions whose user handle matches with required user handle.
                    subscriptionsAssociatedWithUser.add(subInfo);
                } else if (subIdUserHandle == null) {
                    // Store subscriptions whose user handle is set to null.
                    subscriptionsWithNoAssociation.add(subInfo);
                }
            }

            return subscriptionsAssociatedWithUser.isEmpty() ?
                    subscriptionsWithNoAssociation : subscriptionsAssociatedWithUser;
        } finally {
            Binder.restoreCallingIdentity(token);
        }
    }

    /**
     * @hide
     */
+95 −0
Original line number Diff line number Diff line
@@ -3016,6 +3016,101 @@ public class SubscriptionManagerService extends ISub.Stub {
        }
    }

    /**
     * Check if subscription and user are associated with each other.
     *
     * @param subscriptionId the subId of the subscription
     * @param userHandle user handle of the user
     * @return {@code true} if subscription is associated with user
     * {code true} if there are no subscriptions on device
     * else {@code false} if subscription is not associated with user.
     *
     * @throws SecurityException if the caller doesn't have permissions required.
     * @throws IllegalStateException if subscription service is not available.
     *
     */
    @Override
    public boolean isSubscriptionAssociatedWithUser(int subscriptionId,
            @NonNull UserHandle userHandle) {
        enforcePermissions("isSubscriptionAssociatedWithUser",
                Manifest.permission.MANAGE_SUBSCRIPTION_USER_ASSOCIATION);

        long token = Binder.clearCallingIdentity();
        try {
            // Return true if there are no subscriptions on the device.
            List<SubscriptionInfo> subInfoList = getAllSubInfoList(
                    mContext.getOpPackageName(), mContext.getAttributionTag());
            if (subInfoList == null || subInfoList.isEmpty()) {
                return true;
            }

            // Get list of subscriptions associated with this user.
            List<SubscriptionInfo> associatedSubscriptionsList =
                    getSubscriptionInfoListAssociatedWithUser(userHandle);
            if (associatedSubscriptionsList.isEmpty()) {
                return false;
            }

            // Return true if required subscription is present in associated subscriptions list.
            for (SubscriptionInfo subInfo: associatedSubscriptionsList) {
                if (subInfo.getSubscriptionId() == subscriptionId){
                    return true;
                }
            }
            return false;
        } finally {
            Binder.restoreCallingIdentity(token);
        }
    }

    /**
     * Get list of subscriptions associated with user.
     *
     * If user handle is associated with some subscriptions, return subscriptionsAssociatedWithUser
     * else return all the subscriptions which are not associated with any user.
     *
     * @param userHandle user handle of the user
     * @return list of subscriptionInfo associated with the user.
     *
     * @throws SecurityException if the caller doesn't have permissions required.
     * @throws IllegalStateException if subscription service is not available.
     *
     */
    @Override
    public @NonNull List<SubscriptionInfo> getSubscriptionInfoListAssociatedWithUser(
            @NonNull UserHandle userHandle) {
        enforcePermissions("getSubscriptionInfoListAssociatedWithUser",
                Manifest.permission.MANAGE_SUBSCRIPTION_USER_ASSOCIATION);

        long token = Binder.clearCallingIdentity();
        try {
            List<SubscriptionInfo> subInfoList =  getAllSubInfoList(
                    mContext.getOpPackageName(), mContext.getAttributionTag());
            if (subInfoList == null || subInfoList.isEmpty()) {
                return new ArrayList<>();
            }

            List<SubscriptionInfo> subscriptionsAssociatedWithUser = new ArrayList<>();
            List<SubscriptionInfo> subscriptionsWithNoAssociation = new ArrayList<>();
            for (SubscriptionInfo subInfo : subInfoList) {
                int subId = subInfo.getSubscriptionId();
                UserHandle subIdUserHandle = getSubscriptionUserHandle(subId);
                if (userHandle.equals(subIdUserHandle)) {
                    // Store subscriptions whose user handle matches with required user handle.
                    subscriptionsAssociatedWithUser.add(subInfo);
                } else if (subIdUserHandle == null) {
                    // Store subscriptions whose user handle is set to null.
                    subscriptionsWithNoAssociation.add(subInfo);
                }
            }

            return subscriptionsAssociatedWithUser.isEmpty() ?
                    subscriptionsWithNoAssociation : subscriptionsAssociatedWithUser;
        } finally {
            Binder.restoreCallingIdentity(token);
        }
    }

    /**
     * Register the callback for receiving information from {@link SubscriptionManagerService}.
     *
+4 −1
Original line number Diff line number Diff line
@@ -174,9 +174,12 @@ public class SmsControllerTest extends TelephonyTest {
    @Test
    public void sendVisualVoicemailSmsForSubscriber_phoneIsNotInEcm() {
        assertFalse(mPhone.isInEcm());
        int subId = 1;
        doReturn(true).when(mSubscriptionManager)
                .isSubscriptionAssociatedWithUser(eq(subId), any());

        mSmsControllerUT.sendVisualVoicemailSmsForSubscriber(mCallingPackage,null ,
                1, null, 0, null, null);
                subId, null, 0, null, null);
        verify(mIccSmsInterfaceManager).sendTextWithSelfPermissions(any(),
                any(), any(), any(), any(), any(), any(), eq(false), eq(true));
    }
+76 −0
Original line number Diff line number Diff line
@@ -2217,6 +2217,82 @@ public class SubscriptionControllerTest extends TelephonyTest {
                        SubscriptionManager.DEFAULT_SUBSCRIPTION_ID));
    }

    @Test
    public void isSubscriptionAssociatedWithUser_withoutPermission() {
        mContextFixture.removeCallingOrSelfPermission(ContextFixture.PERMISSION_ENABLE_ALL);

        assertThrows(SecurityException.class,
                () -> mSubscriptionControllerUT.isSubscriptionAssociatedWithUser(1,
                        UserHandle.of(UserHandle.USER_SYSTEM)));
    }

    @Test
    public void isSubscriptionAssociatedWithUser_noSubscription() {
        // isSubscriptionAssociatedWithUser should return true if there are no active subscriptions.
        assertThat(mSubscriptionControllerUT.isSubscriptionAssociatedWithUser(1,
                UserHandle.of(UserHandle.USER_SYSTEM))).isEqualTo(true);
    }

    @Test
    public void isSubscriptionAssociatedWithUser_unknownSubId() {
        testInsertSim();
        /* Get SUB ID */
        int[] subIds = mSubscriptionControllerUT.getActiveSubIdList(/*visibleOnly*/false);
        assertTrue(subIds != null && subIds.length != 0);
        int unknownSubId = 123;

        assertThat(mSubscriptionControllerUT.isSubscriptionAssociatedWithUser(unknownSubId,
                UserHandle.of(UserHandle.USER_SYSTEM))).isEqualTo(false);
    }

    @Test
    public void isSubscriptionAssociatedWithUser_userAssociatedWithSubscription() {
        testInsertSim();
        /* Get SUB ID */
        int[] subIds = mSubscriptionControllerUT.getActiveSubIdList(/*visibleOnly*/false);
        assertTrue(subIds != null && subIds.length != 0);
        final int subId = subIds[0];

        mSubscriptionControllerUT.setSubscriptionUserHandle(
                UserHandle.of(UserHandle.USER_SYSTEM), subId);

        assertThat(mSubscriptionControllerUT.isSubscriptionAssociatedWithUser(subId,
                UserHandle.of(UserHandle.USER_SYSTEM))).isEqualTo(true);
    }

    @Test
    public void isSubscriptionAssociatedWithUser_userNotAssociatedWithSubscription() {
        testInsertSim();
        enableGetSubscriptionUserHandle();
        /* Get SUB ID */
        int[] subIds = mSubscriptionControllerUT.getActiveSubIdList(/*visibleOnly*/false);
        assertTrue(subIds != null && subIds.length != 0);
        final int subId = subIds[0];

        mSubscriptionControllerUT.setSubscriptionUserHandle(UserHandle.of(UserHandle.USER_SYSTEM),
                subId);

        assertThat(mSubscriptionControllerUT.isSubscriptionAssociatedWithUser(subId,
                UserHandle.of(10))).isEqualTo(false);
    }


    @Test
    public void getSubscriptionInfoListAssociatedWithUser_withoutPermission() {
        mContextFixture.removeCallingOrSelfPermission(ContextFixture.PERMISSION_ENABLE_ALL);

        assertThrows(SecurityException.class,
                () -> mSubscriptionControllerUT.getSubscriptionInfoListAssociatedWithUser(
                        UserHandle.of(UserHandle.USER_SYSTEM)));
    }

    @Test
    public void getSubscriptionInfoListAssociatedWithUser_noSubscription() {
        List<SubscriptionInfo> associatedSubInfoList = mSubscriptionControllerUT
                .getSubscriptionInfoListAssociatedWithUser(UserHandle.of(UserHandle.USER_SYSTEM));
        assertThat(associatedSubInfoList.size()).isEqualTo(0);
    }

    private void enableGetSubscriptionUserHandle() {
        Resources mResources = mock(Resources.class);
        doReturn(true).when(mResources).getBoolean(
Loading