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

Commit bc3a5d11 authored by Ayush Sharma's avatar Ayush Sharma
Browse files

Allow switchAfterDownload for org owned devices

Manual testing
Case 1:
1. No exisiting SIM on device
2. COPE PO/DO downloads managed eSIM
3. eSIM gets downloaded successfully and is in an active state.

Case 2:
1. Existing physical SIM present on device
2. COPE PO/DO downloads managed eSIM
3. eSIM gets downloaded successfully and is in active state.
4. Default for data/sms/call remains existing physical SIM and do not change to new managed eSIM.

Case 3:
1. Existing physical SIM and users personal eSIM present on device
2. COPE PO/DO downloads managed eSIM
3. eSIM downloads fails with EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR status code

Bug: 295301164
Test: atest EuiccControllerTest
Change-Id: I7e23c5c290e11fe4f532c0f5621c0099354cdb21
parent cb91ac09
Loading
Loading
Loading
Loading
+63 −44
Original line number Diff line number Diff line
@@ -615,25 +615,32 @@ public class EuiccController extends IEuiccController.Stub {
    void downloadSubscription(int cardId, int portIndex, DownloadableSubscription subscription,
            boolean switchAfterDownload, String callingPackage, boolean forceDeactivateSim,
            Bundle resolvedBundle, PendingIntent callbackIntent) {
        boolean callerCanWriteEmbeddedSubscriptions = callerCanWriteEmbeddedSubscriptions();
        boolean callerCanDownloadAdminManagedSubscription =
                Flags.esimManagementEnabled()
                        && callerCanManageDevicePolicyManagedSubscriptions(callingPackage);
        mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage);

        boolean callerHasAdminPrivileges = false;
        if (Flags.esimManagementEnabled()) {
            if (mContext
                    .getSystemService(UserManager.class)
                    .hasUserRestriction(UserManager.DISALLOW_SIM_GLOBALLY)
                    && !callerCanDownloadAdminManagedSubscription) {
            callerHasAdminPrivileges = callerCanManageDevicePolicyManagedSubscriptions(
                    callingPackage);
            if (callerHasAdminPrivileges && (switchAfterDownload && !shouldAllowSwitchAfterDownload(
                    callingPackage))) {
                // Throw error if calling admin does not have privileges to enable
                // subscription silently after download but switchAfterDownload is passed as true.
                sendResult(callbackIntent, ERROR, null);
                return;
            }
            if (mContext.getSystemService(UserManager.class).hasUserRestriction(
                    UserManager.DISALLOW_SIM_GLOBALLY) && !callerHasAdminPrivileges) {
                // Only admin managed subscriptions are allowed, but the caller is not authorised to
                // download admin managed subscriptions. Abort.
                throw new SecurityException("Caller is not authorized to download subscriptions");
                sendResult(callbackIntent, ERROR, null);
                return;
            }
        }
        mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage);
        // Don't try to resolve the port index for apps which are not targeting on T for backward
        // compatibility. instead always use default port 0.
        boolean shouldResolvePortIndex = isCompatChangeEnabled(callingPackage,
                EuiccManager.SHOULD_RESOLVE_PORT_INDEX_FOR_APPS);
        boolean callerCanWriteEmbeddedSubscriptions = callerCanWriteEmbeddedSubscriptions();

        long token = Binder.clearCallingIdentity();
        try {
@@ -646,26 +653,19 @@ public class EuiccController extends IEuiccController.Stub {
                isConsentNeededToResolvePortIndex = (portIndex
                        == TelephonyManager.INVALID_PORT_INDEX);
            }
            // Caller has admin privileges if they can download admin managed subscription,
            // and are not switching the subscription after download (admins cannot silently
            // enable the subscription).
            boolean hasAdminPrivileges =
                    callerCanDownloadAdminManagedSubscription && !switchAfterDownload;
            Log.d(TAG, " downloadSubscription cardId: " + cardId + " switchAfterDownload: "
                    + switchAfterDownload + " portIndex: " + portIndex
                    + " forceDeactivateSim: " + forceDeactivateSim + " callingPackage: "
                    + callingPackage
                    + switchAfterDownload + " portIndex: " + portIndex + " forceDeactivateSim: "
                    + forceDeactivateSim + " callingPackage: " + callingPackage
                    + " isConsentNeededToResolvePortIndex: " + isConsentNeededToResolvePortIndex
                    + " shouldResolvePortIndex:" + shouldResolvePortIndex
                    + " hasAdminPrivileges:" + hasAdminPrivileges);
            if (!isConsentNeededToResolvePortIndex
                    && (callerCanWriteEmbeddedSubscriptions
                                    || hasAdminPrivileges)) {
                    + " callerHasAdminPrivileges:" + callerHasAdminPrivileges);
            if (!isConsentNeededToResolvePortIndex && (callerCanWriteEmbeddedSubscriptions
                    || callerHasAdminPrivileges)) {
                // With WRITE_EMBEDDED_SUBSCRIPTIONS, we can skip profile-specific permission checks
                // and move straight to the profile download.
                downloadSubscriptionPrivileged(cardId, portIndex, token, subscription,
                        switchAfterDownload, forceDeactivateSim, callingPackage, resolvedBundle,
                        callbackIntent, callerCanDownloadAdminManagedSubscription,
                        callbackIntent, callerHasAdminPrivileges,
                        getCurrentEmbeddedSubscriptionIds(cardId));
                return;
            }
@@ -862,6 +862,9 @@ public class EuiccController extends IEuiccController.Stub {
                                            cardId,
                                            existingSubscriptions);
                                    return;
                                } else if (markAsOwnedByAdmin) {
                                    refreshSubscriptionsOwnership(true, callingPackage, cardId,
                                            existingSubscriptions);
                                }
                            break;
                            case EuiccService.RESULT_MUST_DEACTIVATE_SIM:
@@ -1728,6 +1731,15 @@ public class EuiccController extends IEuiccController.Stub {
        SubscriptionManagerService.getInstance().updateEmbeddedSubscriptions(
                List.of(mTelephonyManager.getCardIdForDefaultEuicc()),
                () -> {
                    refreshSubscriptionsOwnership(isCallerAdmin, callingPackage, cardId,
                            subscriptionsBefore);
                    sendResult(callbackIntent, resultCode, extrasIntent);
                });

    }

    private void refreshSubscriptionsOwnership(boolean isCallerAdmin, String callingPackage,
            int cardId, Set<Integer> subscriptionsBefore) {
        if (Flags.esimManagementEnabled() && isCallerAdmin) {
            // Mark the newly downloaded subscriptions as being owned by an admin so
            // that actions for that subscription can be restricted,
@@ -1735,13 +1747,9 @@ public class EuiccController extends IEuiccController.Stub {
            Set<Integer> subscriptionsAfter = getCurrentEmbeddedSubscriptionIds(cardId);
            subscriptionsAfter.removeAll(subscriptionsBefore);
            for (int subId : subscriptionsAfter) {
                            SubscriptionManagerService
                                    .getInstance().setGroupOwner(subId, callingPackage);
                SubscriptionManagerService.getInstance().setGroupOwner(subId, callingPackage);
            }
        }
                    sendResult(callbackIntent, resultCode, extrasIntent);
                });

    }

    /** Dispatch the given callback intent with the given result code and data. */
@@ -2181,20 +2189,31 @@ public class EuiccController extends IEuiccController.Stub {
    }

    private boolean callerCanManageDevicePolicyManagedSubscriptions(String callingPackage) {
        // isProfileOwner/isDeviceOwner needs to callers user, so create device policy manager
        // with the correct context associated with the caller.
        DevicePolicyManager devicePolicyManager = getDevicePolicyManager();
        boolean isAdmin =
                devicePolicyManager != null && (devicePolicyManager.isProfileOwnerApp(
                        callingPackage)
                        || devicePolicyManager.isDeviceOwnerApp(callingPackage));
        return isAdmin || mContext.checkCallingOrSelfPermission(
                Manifest.permission.MANAGE_DEVICE_POLICY_MANAGED_SUBSCRIPTIONS)
                == PackageManager.PERMISSION_GRANTED;
    }

    private boolean shouldAllowSwitchAfterDownload(String callingPackage) {
        DevicePolicyManager devicePolicyManager = getDevicePolicyManager();
        return devicePolicyManager != null && (devicePolicyManager.isDeviceOwnerApp(callingPackage)
                || (devicePolicyManager.isProfileOwnerApp(callingPackage)
                && devicePolicyManager.isOrganizationOwnedDeviceWithManagedProfile()));
    }

    private DevicePolicyManager getDevicePolicyManager() {
        // create device policy manager with the correct context associated with the caller.
        DevicePolicyManager devicePolicyManager =
                retrieveDevicePolicyManagerFromUserContext(Binder.getCallingUserHandle());
        if (devicePolicyManager == null) {
            Log.w(TAG, "Unable to get device policy manager");
            return false;
        }
        boolean isAdmin =
                devicePolicyManager.isProfileOwnerApp(callingPackage)
                        || devicePolicyManager.isDeviceOwnerApp(callingPackage);
        return isAdmin || mContext.checkCallingOrSelfPermission(
                Manifest.permission.MANAGE_DEVICE_POLICY_MANAGED_SUBSCRIPTIONS)
                == PackageManager.PERMISSION_GRANTED;
        return devicePolicyManager;
    }

    @Override
+4 −0
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@ import android.app.AppOpsManager;
import android.app.IActivityManager;
import android.app.KeyguardManager;
import android.app.PropertyInvalidatedCache;
import android.app.admin.DevicePolicyManager;
import android.app.usage.NetworkStatsManager;
import android.content.ContentProvider;
import android.content.ContentResolver;
@@ -304,6 +305,7 @@ public abstract class TelephonyTest {
    protected AppOpsManager mAppOpsManager;
    protected CarrierConfigManager mCarrierConfigManager;
    protected UserManager mUserManager;
    protected DevicePolicyManager mDevicePolicyManager;
    protected KeyguardManager mKeyguardManager;
    protected VcnManager mVcnManager;
    protected NetworkPolicyManager mNetworkPolicyManager;
@@ -630,6 +632,8 @@ public abstract class TelephonyTest {
        mCarrierConfigManager =
                (CarrierConfigManager) mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
        mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
        mDevicePolicyManager = (DevicePolicyManager) mContext.getSystemService(
                Context.DEVICE_POLICY_SERVICE);
        mKeyguardManager = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
        mVcnManager = mContext.getSystemService(VcnManager.class);
        mNetworkPolicyManager = mContext.getSystemService(NetworkPolicyManager.class);
+91 −14
Original line number Diff line number Diff line
@@ -230,6 +230,7 @@ public class EuiccControllerTest extends TelephonyTest {
                Settings.Global.EUICC_PROVISIONED, 0);
        Settings.Global.putInt(mContext.getContentResolver(),
                Settings.Global.EUICC_PROVISIONED, 0);
        setHasManageDevicePolicyManagedSubscriptionsPermission(false);
    }

    @After
@@ -894,7 +895,7 @@ public class EuiccControllerTest extends TelephonyTest {

    @Test
    @DisableCompatChanges({EuiccManager.SHOULD_RESOLVE_PORT_INDEX_FOR_APPS})
    public void testDownloadSubscription_adminPermission_usingSwitchAfterDownload()
    public void testDownloadSubscription_adminPermission_usingSwitchAfterDownload_fails()
            throws Exception {
        mSetFlagsRule.enableFlags(Flags.FLAG_ESIM_MANAGEMENT_ENABLED);
        setHasWriteEmbeddedPermission(false);
@@ -909,18 +910,99 @@ public class EuiccControllerTest extends TelephonyTest {
        when(mPackageManager.getPackageInfo(eq(PACKAGE_NAME), anyInt())).thenReturn(pi);
        setCanManageSubscriptionOnTargetSim(false /* isTargetEuicc */, false /* hasPrivileges */);

        callDownloadSubscription(SUBSCRIPTION, true /* switchAfterDownload */, true /* complete */,
        callDownloadSubscription(SUBSCRIPTION, true /* switchAfterDownload */,
                true /* complete */,
                12345, 0 /* resolvableError */, PACKAGE_NAME /* callingPackage */);

        verifyIntentSent(EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR,
                0 /* detailedCode */);
        verifyIntentSent(EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_ERROR, 0 /* detailedCode */);
        verify(mMockConnector, never()).downloadSubscription(anyInt(), anyInt(),
                any(), anyBoolean(), anyBoolean(), any(), any());
    }

    @Test
    @DisableCompatChanges({EuiccManager.SHOULD_RESOLVE_PORT_INDEX_FOR_APPS})
    public void testDownloadSubscription_onlyAdminManagedAllowed_callerNotAdmin_throws()
    public void testDownloadSubscription_profileOwner_usingSwitchAfterDownload_fails()
            throws Exception {
        mSetFlagsRule.enableFlags(Flags.FLAG_ESIM_MANAGEMENT_ENABLED);
        setHasWriteEmbeddedPermission(false);
        setHasManageDevicePolicyManagedSubscriptionsPermission(true);
        setUpUiccSlotData();
        GetDownloadableSubscriptionMetadataResult result =
                new GetDownloadableSubscriptionMetadataResult(EuiccService.RESULT_OK,
                        SUBSCRIPTION_WITH_METADATA);
        doReturn(true).when(mDevicePolicyManager).isProfileOwnerApp(PACKAGE_NAME);
        doReturn(false).when(mDevicePolicyManager).isOrganizationOwnedDeviceWithManagedProfile();
        doReturn(false).when(mDevicePolicyManager).isDeviceOwnerApp(PACKAGE_NAME);
        prepareGetDownloadableSubscriptionMetadataCall(true /* complete */, result);
        PackageInfo pi = new PackageInfo();
        pi.packageName = PACKAGE_NAME;
        when(mPackageManager.getPackageInfo(eq(PACKAGE_NAME), anyInt())).thenReturn(pi);
        setCanManageSubscriptionOnTargetSim(false /* isTargetEuicc */, false /* hasPrivileges */);

        callDownloadSubscription(SUBSCRIPTION, true /* switchAfterDownload */,
                true /* complete */,
                12345, 0 /* resolvableError */, PACKAGE_NAME /* callingPackage */);

        verifyIntentSent(EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_ERROR, 0 /* detailedCode */);
        verify(mMockConnector, never()).downloadSubscription(anyInt(), anyInt(), any(),
                anyBoolean(), anyBoolean(), any(), any());
    }

    @Test
    @DisableCompatChanges({EuiccManager.SHOULD_RESOLVE_PORT_INDEX_FOR_APPS})
    public void testDownloadSubscription_orgOwnedProfileOwner_usingSwitchAfterDownload_success()
            throws Exception {
        mSetFlagsRule.enableFlags(Flags.FLAG_ESIM_MANAGEMENT_ENABLED);
        setHasWriteEmbeddedPermission(false);
        setHasManageDevicePolicyManagedSubscriptionsPermission(true);
        setUpUiccSlotData();
        GetDownloadableSubscriptionMetadataResult result =
                new GetDownloadableSubscriptionMetadataResult(EuiccService.RESULT_OK,
                        SUBSCRIPTION_WITH_METADATA);
        doReturn(true).when(mDevicePolicyManager).isProfileOwnerApp(PACKAGE_NAME);
        doReturn(true).when(mDevicePolicyManager).isOrganizationOwnedDeviceWithManagedProfile();
        doReturn(false).when(mDevicePolicyManager).isDeviceOwnerApp(PACKAGE_NAME);
        prepareGetDownloadableSubscriptionMetadataCall(true /* complete */, result);
        PackageInfo pi = new PackageInfo();
        pi.packageName = PACKAGE_NAME;
        when(mPackageManager.getPackageInfo(eq(PACKAGE_NAME), anyInt())).thenReturn(pi);

        callDownloadSubscription(SUBSCRIPTION, true /* switchAfterDownload */, true /* complete */,
                EuiccService.RESULT_OK, 0 /* resolvableError */, PACKAGE_NAME /* callingPackage */);

        verifyIntentSent(EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_OK, 0 /* detailedCode */);
        assertFalse(mController.mCalledRefreshSubscriptionsAndSendResult);
    }

    @Test
    @DisableCompatChanges({EuiccManager.SHOULD_RESOLVE_PORT_INDEX_FOR_APPS})
    public void testDownloadSubscription_deviceOwner_usingSwitchAfterDownload_success()
            throws Exception {
        mSetFlagsRule.enableFlags(Flags.FLAG_ESIM_MANAGEMENT_ENABLED);
        setHasWriteEmbeddedPermission(false);
        setHasManageDevicePolicyManagedSubscriptionsPermission(true);
        setUpUiccSlotData();
        GetDownloadableSubscriptionMetadataResult result =
                new GetDownloadableSubscriptionMetadataResult(EuiccService.RESULT_OK,
                        SUBSCRIPTION_WITH_METADATA);
        doReturn(false).when(mDevicePolicyManager).isProfileOwnerApp(PACKAGE_NAME);
        doReturn(false).when(mDevicePolicyManager).isOrganizationOwnedDeviceWithManagedProfile();
        doReturn(true).when(mDevicePolicyManager).isDeviceOwnerApp(PACKAGE_NAME);
        prepareGetDownloadableSubscriptionMetadataCall(true /* complete */, result);
        PackageInfo pi = new PackageInfo();
        pi.packageName = PACKAGE_NAME;
        when(mPackageManager.getPackageInfo(eq(PACKAGE_NAME), anyInt())).thenReturn(pi);

        callDownloadSubscription(SUBSCRIPTION, true /* switchAfterDownload */, true /* complete */,
                EuiccService.RESULT_OK, 0 /* resolvableError */, PACKAGE_NAME /* callingPackage */);

        verifyIntentSent(EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_OK, 0 /* detailedCode */);
        assertFalse(mController.mCalledRefreshSubscriptionsAndSendResult);
    }

    @Test
    @DisableCompatChanges({EuiccManager.SHOULD_RESOLVE_PORT_INDEX_FOR_APPS})
    public void testDownloadSubscription_onlyAdminManagedAllowed_callerNotAdmin_error()
            throws Exception {
        mSetFlagsRule.enableFlags(Flags.FLAG_ESIM_MANAGEMENT_ENABLED);
        setHasManageDevicePolicyManagedSubscriptionsPermission(false);
@@ -929,15 +1011,10 @@ public class EuiccControllerTest extends TelephonyTest {
                .when(mUserManager)
                .hasUserRestriction(UserManager.DISALLOW_SIM_GLOBALLY);

        assertThrows(SecurityException.class,
                () ->
                        callDownloadSubscription(
                                SUBSCRIPTION,
                                false /* switchAfterDownload */,
                                true /* complete */,
                                EuiccService.RESULT_OK,
                                0 /* resolvableError */,
                                "whatever" /* callingPackage */));
        callDownloadSubscription(SUBSCRIPTION, false /* switchAfterDownload */, true /* complete */,
                12345, 0 /* resolvableError */, "whatever" /* callingPackage */);

        verifyIntentSent(EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_ERROR, 0 /* detailedCode */);
        assertFalse(mController.mCalledRefreshSubscriptionsAndSendResult);
    }