All Downloads are FREE. Search and download functionalities are using the official Maven repository.

src.com.android.internal.telephony.euicc.EuiccOperation Maven / Gradle / Ivy

/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.android.internal.telephony.euicc;

import android.annotation.IntDef;
import android.annotation.Nullable;
import android.app.PendingIntent;
import android.os.Binder;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import android.service.euicc.EuiccService;
import android.telephony.euicc.DownloadableSubscription;
import android.telephony.euicc.EuiccManager;
import android.text.TextUtils;
import android.util.Log;

import com.android.internal.annotations.VisibleForTesting;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

/**
 * Representation of an {@link EuiccController} operation which failed with a resolvable error.
 *
 * 

This class tracks the operation which failed and the reason for failure. Once the error is * resolved, the operation can be resumed with {@link #continueOperation}. */ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) public class EuiccOperation implements Parcelable { private static final String TAG = "EuiccOperation"; public static final Creator CREATOR = new Creator() { @Override public EuiccOperation createFromParcel(Parcel in) { return new EuiccOperation(in); } @Override public EuiccOperation[] newArray(int size) { return new EuiccOperation[size]; } }; @VisibleForTesting @Retention(RetentionPolicy.SOURCE) @IntDef({ ACTION_GET_METADATA_DEACTIVATE_SIM, ACTION_DOWNLOAD_DEACTIVATE_SIM, ACTION_DOWNLOAD_NO_PRIVILEGES, ACTION_GET_DEFAULT_LIST_DEACTIVATE_SIM, ACTION_SWITCH_DEACTIVATE_SIM, ACTION_SWITCH_NO_PRIVILEGES, ACTION_DOWNLOAD_RESOLVABLE_ERRORS, }) @interface Action {} @VisibleForTesting static final int ACTION_GET_METADATA_DEACTIVATE_SIM = 1; @VisibleForTesting static final int ACTION_DOWNLOAD_DEACTIVATE_SIM = 2; @VisibleForTesting static final int ACTION_DOWNLOAD_NO_PRIVILEGES = 3; @VisibleForTesting static final int ACTION_GET_DEFAULT_LIST_DEACTIVATE_SIM = 4; @VisibleForTesting static final int ACTION_SWITCH_DEACTIVATE_SIM = 5; @VisibleForTesting static final int ACTION_SWITCH_NO_PRIVILEGES = 6; @VisibleForTesting static final int ACTION_DOWNLOAD_RESOLVABLE_ERRORS = 7; /** * @deprecated Use ACTION_DOWNLOAD_RESOLVABLE_ERRORS and pass the resolvable errors in bit map. */ @VisibleForTesting @Deprecated static final int ACTION_DOWNLOAD_CONFIRMATION_CODE = 8; /** * ACTION_DOWNLOAD_CHECK_METADATA can be used for either NO_PRIVILEGES or DEACTIVATE_SIM. */ @VisibleForTesting static final int ACTION_DOWNLOAD_NO_PRIVILEGES_OR_DEACTIVATE_SIM_CHECK_METADATA = 9; @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) public final @Action int mAction; private final long mCallingToken; @Nullable private final DownloadableSubscription mDownloadableSubscription; private final int mSubscriptionId; private final boolean mSwitchAfterDownload; @Nullable private final String mCallingPackage; @Nullable private final int mResolvableErrors; /** * {@link EuiccManager#getDownloadableSubscriptionMetadata} failed with * {@link EuiccService#RESULT_MUST_DEACTIVATE_SIM}. */ static EuiccOperation forGetMetadataDeactivateSim(long callingToken, DownloadableSubscription subscription, String callingPackage) { return new EuiccOperation(ACTION_GET_METADATA_DEACTIVATE_SIM, callingToken, subscription, 0 /* subscriptionId */, false /* switchAfterDownload */, callingPackage); } /** * {@link EuiccManager#downloadSubscription} failed with a mustDeactivateSim error. Should only * be used for privileged callers; for unprivileged callers, use * {@link #forDownloadNoPrivileges} to avoid a double prompt. */ static EuiccOperation forDownloadDeactivateSim(long callingToken, DownloadableSubscription subscription, boolean switchAfterDownload, String callingPackage) { return new EuiccOperation(ACTION_DOWNLOAD_DEACTIVATE_SIM, callingToken, subscription, 0 /* subscriptionId */, switchAfterDownload, callingPackage); } /** * {@link EuiccManager#downloadSubscription} failed because the calling app does not have * permission to manage the current active subscription. */ 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 the caller can't manage the target * SIM, or we cannot determine the privileges without deactivating the current SIM first. */ static EuiccOperation forDownloadNoPrivilegesOrDeactivateSimCheckMetadata(long callingToken, DownloadableSubscription subscription, boolean switchAfterDownload, String callingPackage) { return new EuiccOperation(ACTION_DOWNLOAD_NO_PRIVILEGES_OR_DEACTIVATE_SIM_CHECK_METADATA, callingToken, subscription, 0 /* subscriptionId */, switchAfterDownload, callingPackage); } /** * {@link EuiccManager#downloadSubscription} failed with * {@link EuiccService#RESULT_NEED_CONFIRMATION_CODE} error. * * @deprecated Use * {@link #forDownloadResolvableErrors(long, DownloadableSubscription, boolean, String, int)} * instead. */ @Deprecated public static EuiccOperation forDownloadConfirmationCode(long callingToken, DownloadableSubscription subscription, boolean switchAfterDownload, String callingPackage) { return new EuiccOperation(ACTION_DOWNLOAD_CONFIRMATION_CODE, callingToken, subscription, 0 /* subscriptionId */, switchAfterDownload, callingPackage); } /** * {@link EuiccManager#downloadSubscription} failed with * {@link EuiccService#RESULT_RESOLVABLE_ERRORS} error. */ static EuiccOperation forDownloadResolvableErrors(long callingToken, DownloadableSubscription subscription, boolean switchAfterDownload, String callingPackage, int resolvableErrors) { return new EuiccOperation(ACTION_DOWNLOAD_RESOLVABLE_ERRORS, callingToken, subscription, 0 /* subscriptionId */, switchAfterDownload, callingPackage, resolvableErrors); } static EuiccOperation forGetDefaultListDeactivateSim(long callingToken, String callingPackage) { return new EuiccOperation(ACTION_GET_DEFAULT_LIST_DEACTIVATE_SIM, callingToken, null /* downloadableSubscription */, 0 /* subscriptionId */, false /* switchAfterDownload */, callingPackage); } static EuiccOperation forSwitchDeactivateSim(long callingToken, int subscriptionId, String callingPackage) { return new EuiccOperation(ACTION_SWITCH_DEACTIVATE_SIM, callingToken, null /* downloadableSubscription */, subscriptionId, false /* switchAfterDownload */, callingPackage); } static EuiccOperation forSwitchNoPrivileges(long callingToken, int subscriptionId, String callingPackage) { return new EuiccOperation(ACTION_SWITCH_NO_PRIVILEGES, callingToken, null /* downloadableSubscription */, subscriptionId, false /* switchAfterDownload */, callingPackage); } EuiccOperation(@Action int action, long callingToken, @Nullable DownloadableSubscription downloadableSubscription, int subscriptionId, boolean switchAfterDownload, String callingPackage, int resolvableErrors) { mAction = action; mCallingToken = callingToken; mDownloadableSubscription = downloadableSubscription; mSubscriptionId = subscriptionId; mSwitchAfterDownload = switchAfterDownload; mCallingPackage = callingPackage; mResolvableErrors = resolvableErrors; } EuiccOperation(@Action int action, long callingToken, @Nullable DownloadableSubscription downloadableSubscription, int subscriptionId, boolean switchAfterDownload, String callingPackage) { mAction = action; mCallingToken = callingToken; mDownloadableSubscription = downloadableSubscription; mSubscriptionId = subscriptionId; mSwitchAfterDownload = switchAfterDownload; mCallingPackage = callingPackage; mResolvableErrors = 0; } EuiccOperation(Parcel in) { mAction = in.readInt(); mCallingToken = in.readLong(); mDownloadableSubscription = in.readTypedObject(DownloadableSubscription.CREATOR); mSubscriptionId = in.readInt(); mSwitchAfterDownload = in.readBoolean(); mCallingPackage = in.readString(); mResolvableErrors = in.readInt(); } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(mAction); dest.writeLong(mCallingToken); dest.writeTypedObject(mDownloadableSubscription, flags); dest.writeInt(mSubscriptionId); dest.writeBoolean(mSwitchAfterDownload); dest.writeString(mCallingPackage); dest.writeInt(mResolvableErrors); } /** * Resume this operation based on the results of the resolution activity. * * @param resolutionExtras The resolution extras as provided to * {@link EuiccManager#continueOperation}. * @param callbackIntent The callback intent to trigger after the operation completes. */ public void continueOperation(int cardId, Bundle resolutionExtras, PendingIntent callbackIntent) { // Restore the identity of the caller. We should err on the side of caution and redo any // permission checks before continuing with the operation in case the caller state has // changed. Resolution flows can re-clear the identity if required. Binder.restoreCallingIdentity(mCallingToken); switch (mAction) { case ACTION_GET_METADATA_DEACTIVATE_SIM: resolvedGetMetadataDeactivateSim(cardId, resolutionExtras.getBoolean(EuiccService.EXTRA_RESOLUTION_CONSENT), callbackIntent); break; case ACTION_DOWNLOAD_DEACTIVATE_SIM: resolvedDownloadDeactivateSim(cardId, resolutionExtras.getBoolean(EuiccService.EXTRA_RESOLUTION_CONSENT), callbackIntent); break; case ACTION_DOWNLOAD_NO_PRIVILEGES: resolvedDownloadNoPrivileges(cardId, resolutionExtras.getBoolean(EuiccService.EXTRA_RESOLUTION_CONSENT), callbackIntent); break; case ACTION_DOWNLOAD_NO_PRIVILEGES_OR_DEACTIVATE_SIM_CHECK_METADATA: resolvedDownloadNoPrivilegesOrDeactivateSimCheckMetadata(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), callbackIntent); break; case ACTION_DOWNLOAD_RESOLVABLE_ERRORS: resolvedDownloadResolvableErrors(cardId, resolutionExtras, callbackIntent); break; case ACTION_GET_DEFAULT_LIST_DEACTIVATE_SIM: resolvedGetDefaultListDeactivateSim(cardId, resolutionExtras.getBoolean(EuiccService.EXTRA_RESOLUTION_CONSENT), callbackIntent); break; case ACTION_SWITCH_DEACTIVATE_SIM: resolvedSwitchDeactivateSim(cardId, resolutionExtras.getBoolean(EuiccService.EXTRA_RESOLUTION_CONSENT), callbackIntent); break; case ACTION_SWITCH_NO_PRIVILEGES: resolvedSwitchNoPrivileges(cardId, resolutionExtras.getBoolean(EuiccService.EXTRA_RESOLUTION_CONSENT), callbackIntent); break; default: Log.wtf(TAG, "Unknown action: " + mAction); break; } } private void resolvedGetMetadataDeactivateSim(int cardId, boolean consent, PendingIntent callbackIntent) { if (consent) { // User has consented; perform the lookup, but this time, tell the LPA to deactivate any // required active SIMs. EuiccController.get().getDownloadableSubscriptionMetadata( cardId, mDownloadableSubscription, true /* forceDeactivateSim */, mCallingPackage, callbackIntent); } else { // User has not consented; fail the operation. fail(callbackIntent); } } private void resolvedDownloadDeactivateSim(int cardId, boolean consent, PendingIntent callbackIntent) { if (consent) { // User has consented; perform the download, but this time, tell the LPA to deactivate // any required active SIMs. EuiccController.get().downloadSubscription( cardId, mDownloadableSubscription, mSwitchAfterDownload, mCallingPackage, true /* forceDeactivateSim */, null /* resolvedBundle */, callbackIntent); } else { // User has not consented; fail the operation. fail(callbackIntent); } } private void resolvedDownloadNoPrivileges(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().downloadSubscriptionPrivileged( cardId, token, mDownloadableSubscription, mSwitchAfterDownload, true /* forceDeactivateSim */, mCallingPackage, null /* resolvedBundle */, callbackIntent); } finally { Binder.restoreCallingIdentity(token); } } else { // User has not consented; fail the operation. fail(callbackIntent); } } private void resolvedDownloadNoPrivilegesOrDeactivateSimCheckMetadata(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. */ @Deprecated private void resolvedDownloadConfirmationCode(int cardId, String confirmationCode, PendingIntent callbackIntent) { if (TextUtils.isEmpty(confirmationCode)) { fail(callbackIntent); } else { mDownloadableSubscription.setConfirmationCode(confirmationCode); EuiccController.get().downloadSubscription( cardId, mDownloadableSubscription, mSwitchAfterDownload, mCallingPackage, true /* forceDeactivateSim */, null, callbackIntent); } } private void resolvedDownloadResolvableErrors(int cardId, Bundle resolvedBundle, PendingIntent callbackIntent) { boolean pass = true; String confirmationCode = null; if ((mResolvableErrors & EuiccService.RESOLVABLE_ERROR_POLICY_RULES) != 0) { if (!resolvedBundle.getBoolean(EuiccService.EXTRA_RESOLUTION_ALLOW_POLICY_RULES)) { pass = false; } } if ((mResolvableErrors & EuiccService.RESOLVABLE_ERROR_CONFIRMATION_CODE) != 0) { confirmationCode = resolvedBundle.getString( EuiccService.EXTRA_RESOLUTION_CONFIRMATION_CODE); // The check here just makes sure the entered confirmation code is non-empty. The actual // check to valid the confirmation code is done by LPA on the ensuing download attemp. if (TextUtils.isEmpty(confirmationCode)) { pass = false; } } if (!pass) { fail(callbackIntent); } else { mDownloadableSubscription.setConfirmationCode(confirmationCode); EuiccController.get().downloadSubscription( cardId, mDownloadableSubscription, mSwitchAfterDownload, mCallingPackage, true /* forceDeactivateSim */, resolvedBundle, callbackIntent); } } private void resolvedGetDefaultListDeactivateSim(int cardId, boolean consent, PendingIntent callbackIntent) { if (consent) { // User has consented; perform the lookup, but this time, tell the LPA to deactivate any // required active SIMs. EuiccController.get().getDefaultDownloadableSubscriptionList( cardId, true /* forceDeactivateSim */, mCallingPackage, callbackIntent); } else { // User has not consented; fail the operation. fail(callbackIntent); } } private void resolvedSwitchDeactivateSim(int cardId, boolean consent, PendingIntent callbackIntent) { if (consent) { // User has consented; perform the switch, but this time, tell the LPA to deactivate any // required active SIMs. EuiccController.get().switchToSubscription( cardId, mSubscriptionId, true /* forceDeactivateSim */, mCallingPackage, callbackIntent); } else { // User has not consented; fail the operation. fail(callbackIntent); } } private void resolvedSwitchNoPrivileges(int cardId, boolean consent, PendingIntent callbackIntent) { if (consent) { // User has consented; perform the switch 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. Also note that in practice, we'd need to deactivate the active SIM to // even reach this point, because we cannot fetch the metadata needed to check the // privileges without doing so. EuiccController.get().switchToSubscriptionPrivileged( cardId, token, mSubscriptionId, true /* forceDeactivateSim */, mCallingPackage, callbackIntent); } finally { Binder.restoreCallingIdentity(token); } } else { // User has not consented; fail the operation. fail(callbackIntent); } } private static void fail(PendingIntent callbackIntent) { EuiccController.get().sendResult( callbackIntent, EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_ERROR, null /* extrasIntent */); } @Override public int describeContents() { return 0; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy