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

Commit 0c20dd01 authored by Jiuyu Sun's avatar Jiuyu Sun Committed by Android (Google) Code Review
Browse files

Merge "Check metadata after the user consents to MUST_DEACTIVATE_SIM."

parents c7f6afa3 728deb56
Loading
Loading
Loading
Loading
+87 −50
Original line number Diff line number Diff line
@@ -350,7 +350,7 @@ public class EuiccController extends IEuiccController.Stub {
                    forceDeactivateSim,
                    new DownloadSubscriptionGetMetadataCommandCallback(token, subscription,
                            switchAfterDownload, callingPackage, forceDeactivateSim,
                            callbackIntent));
                            callbackIntent, false /* withUserConsent */));
        } finally {
            Binder.restoreCallingIdentity(token);
        }
@@ -359,28 +359,51 @@ public class EuiccController extends IEuiccController.Stub {
    class DownloadSubscriptionGetMetadataCommandCallback extends GetMetadataCommandCallback {
        private final boolean mSwitchAfterDownload;
        private final boolean mForceDeactivateSim;
        private final boolean mWithUserConsent;

        DownloadSubscriptionGetMetadataCommandCallback(long callingToken,
                DownloadableSubscription subscription, boolean switchAfterDownload,
                String callingPackage, boolean forceDeactivateSim,
                PendingIntent callbackIntent) {
                PendingIntent callbackIntent, boolean withUserConsent) {
            super(callingToken, subscription, callingPackage, callbackIntent);
            mSwitchAfterDownload = switchAfterDownload;
            mForceDeactivateSim = forceDeactivateSim;
            mWithUserConsent = withUserConsent;
        }

        @Override
        public void onGetMetadataComplete(int cardId,
                GetDownloadableSubscriptionMetadataResult result) {
            DownloadableSubscription subscription = result.getDownloadableSubscription();
            if (mWithUserConsent) {
                // We won't get RESULT_MUST_DEACTIVATE_SIM for the case with user consent.
                if (result.getResult() != EuiccService.RESULT_OK) {
                    // Just propagate the error as normal.
                    super.onGetMetadataComplete(cardId, result);
                    return;
                }

                if (checkCarrierPrivilegeInMetadata(subscription, mCallingPackage)) {
                    // Caller can download this profile. Since we already have the user's consent,
                    // proceed to download.
                    downloadSubscriptionPrivileged(cardId,
                            mCallingToken, subscription, mSwitchAfterDownload,  mForceDeactivateSim,
                            mCallingPackage, null /* resolvedBundle */,
                            mCallbackIntent);
                } else {
                    Log.e(TAG, "Caller does not have carrier privilege in metadata.");
                    sendResult(mCallbackIntent, ERROR, null /* extrasIntent */);
                }
            } else { // !mWithUserConsent
                if (result.getResult() == EuiccService.RESULT_MUST_DEACTIVATE_SIM) {
                // If we need to deactivate the current SIM to even check permissions, go ahead and
                // require that the user resolve the stronger permission dialog.
                    // If we need to deactivate the current SIM to even check permissions, go ahead
                    // and require that the user resolve the stronger permission dialog.
                    Intent extrasIntent = new Intent();
                    addResolutionIntent(extrasIntent, EuiccService.ACTION_RESOLVE_NO_PRIVILEGES,
                            mCallingPackage,
                            0 /* resolvableErrors */,
                            false /* confirmationCodeRetried */,
                            EuiccOperation.forDownloadNoPrivileges(
                            EuiccOperation.forDownloadNoPrivilegesCheckMetadata(
                                    mCallingToken, mSubscription, mSwitchAfterDownload,
                                    mCallingPackage),
                            cardId);
@@ -394,31 +417,7 @@ public class EuiccController extends IEuiccController.Stub {
                    return;
                }

            DownloadableSubscription subscription = result.getDownloadableSubscription();
            UiccAccessRule[] rules = null;
            List<UiccAccessRule> rulesList = subscription.getAccessRules();
            if (rulesList != null) {
                rules = rulesList.toArray(new UiccAccessRule[rulesList.size()]);
            }
            if (rules == null) {
                Log.e(TAG, "No access rules but caller is unprivileged");
                sendResult(mCallbackIntent, ERROR, null /* extrasIntent */);
                return;
            }

            final PackageInfo info;
            try {
                info = mPackageManager.getPackageInfo(
                        mCallingPackage, PackageManager.GET_SIGNATURES);
            } catch (PackageManager.NameNotFoundException e) {
                Log.e(TAG, "Calling package valid but gone");
                sendResult(mCallbackIntent, ERROR, null /* extrasIntent */);
                return;
            }

            for (int i = 0; i < rules.length; i++) {
                if (rules[i].getCarrierPrivilegeStatus(info)
                        == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
                if (checkCarrierPrivilegeInMetadata(subscription, mCallingPackage)) {
                    // Caller can download this profile.
                    // On a multi-active SIM device, if the caller can manage the active
                    // subscription on the target SIM, or there is no active subscription on the
@@ -435,7 +434,7 @@ public class EuiccController extends IEuiccController.Stub {
                        return;
                    }

                    // Switch might still be permitted, but the user must consent first.
                    // Download might still be permitted, but the user must consent first.
                    Intent extrasIntent = new Intent();
                    addResolutionIntent(extrasIntent, EuiccService.ACTION_RESOLVE_NO_PRIVILEGES,
                            mCallingPackage,
@@ -446,20 +445,26 @@ public class EuiccController extends IEuiccController.Stub {
                                    mCallingPackage),
                            cardId);
                    sendResult(mCallbackIntent, RESOLVABLE_ERROR, extrasIntent);
                    return;
                } else {
                    Log.e(TAG, "Caller is not permitted to download this profile per metadata");
                    sendResult(mCallbackIntent, ERROR, null /* extrasIntent */);
                }
            }
            Log.e(TAG, "Caller is not permitted to download this profile");
            sendResult(mCallbackIntent, ERROR, null /* extrasIntent */);
        }

        @Override
        protected EuiccOperation getOperationForDeactivateSim() {
            return EuiccOperation.forDownloadDeactivateSim(
                    mCallingToken, mSubscription, mSwitchAfterDownload, mCallingPackage);
    }

    // Already have user consent. Check metadata first before proceed to download.
    void downloadSubscriptionPrivilegedCheckMetadata(int cardId, final long callingToken,
            DownloadableSubscription subscription, boolean switchAfterDownload,
            boolean forceDeactivateSim, final String callingPackage, Bundle resolvedBundle,
            final PendingIntent callbackIntent) {
        mConnector.getDownloadableSubscriptionMetadata(cardId, subscription, forceDeactivateSim,
                new DownloadSubscriptionGetMetadataCommandCallback(callingToken, subscription,
                        switchAfterDownload, callingPackage, forceDeactivateSim, callbackIntent,
                        true /* withUserConsent */));
    }

    // Continue to download subscription without checking anything.
    void downloadSubscriptionPrivileged(int cardId, final long callingToken,
            DownloadableSubscription subscription, boolean switchAfterDownload,
            boolean forceDeactivateSim, final String callingPackage, Bundle resolvedBundle,
@@ -1166,6 +1171,38 @@ public class EuiccController extends IEuiccController.Stub {
        return resultRef.get();
    }

    // Returns whether the caller has carrier privilege on the given subscription.
    private boolean checkCarrierPrivilegeInMetadata(DownloadableSubscription subscription,
            String callingPackage) {
        UiccAccessRule[] rules = null;
        List<UiccAccessRule> rulesList = subscription.getAccessRules();
        if (rulesList != null) {
            rules = rulesList.toArray(new UiccAccessRule[rulesList.size()]);
        }
        if (rules == null) {
            Log.e(TAG, "No access rules but caller is unprivileged");
            return false;
        }

        final PackageInfo info;
        try {
            info = mPackageManager.getPackageInfo(callingPackage, PackageManager.GET_SIGNATURES);
        } catch (PackageManager.NameNotFoundException e) {
            Log.e(TAG, "Calling package valid but gone");
            return false;
        }

        for (int i = 0; i < rules.length; i++) {
            if (rules[i].getCarrierPrivilegeStatus(info)
                    == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
                Log.i(TAG, "Calling package has carrier privilege to this profile");
                return true;
            }
        }
        Log.e(TAG, "Calling package doesn't have carrier privilege to this profile");
        return false;
    }

    private boolean supportMultiActiveSlots() {
        return mTelephonyManager.getPhoneCount() > 1;
    }
+51 −6
Original line number Diff line number Diff line
@@ -88,6 +88,8 @@ public class EuiccOperation implements Parcelable {
    @VisibleForTesting
    @Deprecated
    static final int ACTION_DOWNLOAD_CONFIRMATION_CODE = 8;
    @VisibleForTesting
    static final int ACTION_DOWNLOAD_NO_PRIVILEGES_CHECK_METADATA = 9;

    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
    public final @Action int mAction;
@@ -107,7 +109,7 @@ public class EuiccOperation implements Parcelable {
     * {@link EuiccManager#getDownloadableSubscriptionMetadata} failed with
     * {@link EuiccService#RESULT_MUST_DEACTIVATE_SIM}.
     */
    public static EuiccOperation forGetMetadataDeactivateSim(long callingToken,
    static EuiccOperation forGetMetadataDeactivateSim(long callingToken,
            DownloadableSubscription subscription, String callingPackage) {
        return new EuiccOperation(ACTION_GET_METADATA_DEACTIVATE_SIM, callingToken,
                subscription, 0 /* subscriptionId */, false /* switchAfterDownload */,
@@ -119,7 +121,7 @@ public class EuiccOperation implements Parcelable {
     * be used for privileged callers; for unprivileged callers, use
     * {@link #forDownloadNoPrivileges} to avoid a double prompt.
     */
    public static EuiccOperation forDownloadDeactivateSim(long callingToken,
    static EuiccOperation forDownloadDeactivateSim(long callingToken,
            DownloadableSubscription subscription, boolean switchAfterDownload,
            String callingPackage) {
        return new EuiccOperation(ACTION_DOWNLOAD_DEACTIVATE_SIM, callingToken,
@@ -128,16 +130,26 @@ public class EuiccOperation implements Parcelable {

    /**
     * {@link EuiccManager#downloadSubscription} failed because the calling app does not have
     * permission to manage the current active subscription, or because we cannot determine the
     * privileges without deactivating the current SIM first.
     * permission to manage the current active subscription.
     */
    public static EuiccOperation forDownloadNoPrivileges(long callingToken,
    static EuiccOperation forDownloadNoPrivileges(long callingToken,
            DownloadableSubscription subscription, boolean switchAfterDownload,
            String callingPackage) {
        return new EuiccOperation(ACTION_DOWNLOAD_NO_PRIVILEGES, callingToken,
                subscription,  0 /* subscriptionId */, switchAfterDownload, callingPackage);
    }

    /**
     * {@link EuiccManager#downloadSubscription} failed because we cannot determine the
     * privileges without deactivating the current SIM first.
     */
    static EuiccOperation forDownloadNoPrivilegesCheckMetadata(long callingToken,
            DownloadableSubscription subscription, boolean switchAfterDownload,
            String callingPackage) {
        return new EuiccOperation(ACTION_DOWNLOAD_NO_PRIVILEGES_CHECK_METADATA, callingToken,
            subscription,  0 /* subscriptionId */, switchAfterDownload, callingPackage);
    }

    /**
     * {@link EuiccManager#downloadSubscription} failed with
     * {@link EuiccService#RESULT_NEED_CONFIRMATION_CODE} error.
@@ -158,7 +170,7 @@ public class EuiccOperation implements Parcelable {
     * {@link EuiccManager#downloadSubscription} failed with
     * {@link EuiccService#RESULT_RESOLVABLE_ERRORS} error.
     */
    public static EuiccOperation forDownloadResolvableErrors(long callingToken,
    static EuiccOperation forDownloadResolvableErrors(long callingToken,
            DownloadableSubscription subscription, boolean switchAfterDownload,
            String callingPackage, int resolvableErrors) {
        return new EuiccOperation(ACTION_DOWNLOAD_RESOLVABLE_ERRORS, callingToken,
@@ -268,6 +280,11 @@ public class EuiccOperation implements Parcelable {
                        resolutionExtras.getBoolean(EuiccService.EXTRA_RESOLUTION_CONSENT),
                        callbackIntent);
                break;
            case ACTION_DOWNLOAD_NO_PRIVILEGES_CHECK_METADATA:
                resolvedDownloadNoPrivilegesCheckMetadata(cardId,
                        resolutionExtras.getBoolean(EuiccService.EXTRA_RESOLUTION_CONSENT),
                        callbackIntent);
                break;
            case ACTION_DOWNLOAD_CONFIRMATION_CODE: // Deprecated case
                resolvedDownloadConfirmationCode(cardId,
                        resolutionExtras.getString(EuiccService.EXTRA_RESOLUTION_CONFIRMATION_CODE),
@@ -361,6 +378,34 @@ public class EuiccOperation implements Parcelable {
        }
    }

    private void resolvedDownloadNoPrivilegesCheckMetadata(int cardId, boolean consent,
            PendingIntent callbackIntent) {
        if (consent) {
            // User has consented; perform the download with full privileges.
            long token = Binder.clearCallingIdentity();
            try {
                // Note: We turn on "forceDeactivateSim" here under the assumption that the
                // privilege prompt should also cover permission to deactivate an active SIM, as
                // the privilege prompt makes it clear that we're switching from the current
                // carrier.
                EuiccController.get().downloadSubscriptionPrivilegedCheckMetadata(
                        cardId,
                        token,
                        mDownloadableSubscription,
                        mSwitchAfterDownload,
                        true /* forceDeactivateSim */,
                        mCallingPackage,
                        null /* resolvedBundle */,
                        callbackIntent);
            } finally {
                Binder.restoreCallingIdentity(token);
            }
        } else {
            // User has not consented; fail the operation.
            fail(callbackIntent);
        }
    }

    /**
     * @deprecated The resolvable errors in download step are solved by
     * {@link #resolvedDownloadResolvableErrors(Bundle, PendingIntent)} from Q.
+1 −1
Original line number Diff line number Diff line
@@ -502,7 +502,7 @@ public class EuiccControllerTest extends TelephonyTest {
        // In this case we go with the potentially stronger NO_PRIVILEGES consent dialog to avoid
        // double prompting.
        verifyResolutionIntent(EuiccService.ACTION_RESOLVE_NO_PRIVILEGES,
                EuiccOperation.ACTION_DOWNLOAD_NO_PRIVILEGES);
                EuiccOperation.ACTION_DOWNLOAD_NO_PRIVILEGES_CHECK_METADATA);
    }

    @Test