Home | History | Annotate | Download | only in euicc
      1 /*
      2  * Copyright (C) 2017 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 package com.android.internal.telephony.euicc;
     17 
     18 import android.annotation.IntDef;
     19 import android.annotation.Nullable;
     20 import android.app.PendingIntent;
     21 import android.os.Binder;
     22 import android.os.Bundle;
     23 import android.os.Parcel;
     24 import android.os.Parcelable;
     25 import android.service.euicc.EuiccService;
     26 import android.telephony.euicc.DownloadableSubscription;
     27 import android.telephony.euicc.EuiccManager;
     28 import android.text.TextUtils;
     29 import android.util.Log;
     30 
     31 import com.android.internal.annotations.VisibleForTesting;
     32 
     33 import java.lang.annotation.Retention;
     34 import java.lang.annotation.RetentionPolicy;
     35 
     36 /**
     37  * Representation of an {@link EuiccController} operation which failed with a resolvable error.
     38  *
     39  * <p>This class tracks the operation which failed and the reason for failure. Once the error is
     40  * resolved, the operation can be resumed with {@link #continueOperation}.
     41  */
     42 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
     43 public class EuiccOperation implements Parcelable {
     44     private static final String TAG = "EuiccOperation";
     45 
     46     public static final Creator<EuiccOperation> CREATOR = new Creator<EuiccOperation>() {
     47         @Override
     48         public EuiccOperation createFromParcel(Parcel in) {
     49             return new EuiccOperation(in);
     50         }
     51 
     52         @Override
     53         public EuiccOperation[] newArray(int size) {
     54             return new EuiccOperation[size];
     55         }
     56     };
     57 
     58     @VisibleForTesting
     59     @Retention(RetentionPolicy.SOURCE)
     60     @IntDef({
     61             ACTION_GET_METADATA_DEACTIVATE_SIM,
     62             ACTION_DOWNLOAD_DEACTIVATE_SIM,
     63             ACTION_DOWNLOAD_NO_PRIVILEGES,
     64             ACTION_DOWNLOAD_CONFIRMATION_CODE,
     65     })
     66     @interface Action {}
     67 
     68     @VisibleForTesting
     69     static final int ACTION_GET_METADATA_DEACTIVATE_SIM = 1;
     70     @VisibleForTesting
     71     static final int ACTION_DOWNLOAD_DEACTIVATE_SIM = 2;
     72     @VisibleForTesting
     73     static final int ACTION_DOWNLOAD_NO_PRIVILEGES = 3;
     74     @VisibleForTesting
     75     static final int ACTION_GET_DEFAULT_LIST_DEACTIVATE_SIM = 4;
     76     @VisibleForTesting
     77     static final int ACTION_SWITCH_DEACTIVATE_SIM = 5;
     78     @VisibleForTesting
     79     static final int ACTION_SWITCH_NO_PRIVILEGES = 6;
     80     @VisibleForTesting
     81     static final int ACTION_DOWNLOAD_CONFIRMATION_CODE = 7;
     82 
     83     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
     84     public final @Action int mAction;
     85 
     86     private final long mCallingToken;
     87 
     88     @Nullable
     89     private final DownloadableSubscription mDownloadableSubscription;
     90     private final int mSubscriptionId;
     91     private final boolean mSwitchAfterDownload;
     92     @Nullable
     93     private final String mCallingPackage;
     94 
     95     /**
     96      * {@link EuiccManager#getDownloadableSubscriptionMetadata} failed with
     97      * {@link EuiccService#RESULT_MUST_DEACTIVATE_SIM}.
     98      */
     99     public static EuiccOperation forGetMetadataDeactivateSim(long callingToken,
    100             DownloadableSubscription subscription, String callingPackage) {
    101         return new EuiccOperation(ACTION_GET_METADATA_DEACTIVATE_SIM, callingToken,
    102                 subscription, 0 /* subscriptionId */, false /* switchAfterDownload */,
    103                 callingPackage);
    104     }
    105 
    106     /**
    107      * {@link EuiccManager#downloadSubscription} failed with a mustDeactivateSim error. Should only
    108      * be used for privileged callers; for unprivileged callers, use
    109      * {@link #forDownloadNoPrivileges} to avoid a double prompt.
    110      */
    111     public static EuiccOperation forDownloadDeactivateSim(long callingToken,
    112             DownloadableSubscription subscription, boolean switchAfterDownload,
    113             String callingPackage) {
    114         return new EuiccOperation(ACTION_DOWNLOAD_DEACTIVATE_SIM, callingToken,
    115                 subscription,  0 /* subscriptionId */, switchAfterDownload, callingPackage);
    116     }
    117 
    118     /**
    119      * {@link EuiccManager#downloadSubscription} failed because the calling app does not have
    120      * permission to manage the current active subscription, or because we cannot determine the
    121      * privileges without deactivating the current SIM first.
    122      */
    123     public static EuiccOperation forDownloadNoPrivileges(long callingToken,
    124             DownloadableSubscription subscription, boolean switchAfterDownload,
    125             String callingPackage) {
    126         return new EuiccOperation(ACTION_DOWNLOAD_NO_PRIVILEGES, callingToken,
    127                 subscription,  0 /* subscriptionId */, switchAfterDownload, callingPackage);
    128     }
    129 
    130     /**
    131      * {@link EuiccManager#downloadSubscription} failed with
    132      * {@link EuiccService#RESULT_NEED_CONFIRMATION_CODE} error.
    133      */
    134     public static EuiccOperation forDownloadConfirmationCode(long callingToken,
    135             DownloadableSubscription subscription, boolean switchAfterDownload,
    136             String callingPackage) {
    137         return new EuiccOperation(ACTION_DOWNLOAD_CONFIRMATION_CODE, callingToken,
    138                 subscription, 0 /* subscriptionId */, switchAfterDownload, callingPackage);
    139     }
    140 
    141     static EuiccOperation forGetDefaultListDeactivateSim(long callingToken, String callingPackage) {
    142         return new EuiccOperation(ACTION_GET_DEFAULT_LIST_DEACTIVATE_SIM, callingToken,
    143                 null /* downloadableSubscription */, 0 /* subscriptionId */,
    144                 false /* switchAfterDownload */, callingPackage);
    145     }
    146 
    147     static EuiccOperation forSwitchDeactivateSim(long callingToken, int subscriptionId,
    148             String callingPackage) {
    149         return new EuiccOperation(ACTION_SWITCH_DEACTIVATE_SIM, callingToken,
    150                 null /* downloadableSubscription */, subscriptionId,
    151                 false /* switchAfterDownload */, callingPackage);
    152     }
    153 
    154     static EuiccOperation forSwitchNoPrivileges(long callingToken, int subscriptionId,
    155             String callingPackage) {
    156         return new EuiccOperation(ACTION_SWITCH_NO_PRIVILEGES, callingToken,
    157                 null /* downloadableSubscription */, subscriptionId,
    158                 false /* switchAfterDownload */, callingPackage);
    159     }
    160 
    161     EuiccOperation(@Action int action,
    162             long callingToken,
    163             @Nullable DownloadableSubscription downloadableSubscription,
    164             int subscriptionId,
    165             boolean switchAfterDownload,
    166             String callingPackage) {
    167         mAction = action;
    168         mCallingToken = callingToken;
    169         mDownloadableSubscription = downloadableSubscription;
    170         mSubscriptionId = subscriptionId;
    171         mSwitchAfterDownload = switchAfterDownload;
    172         mCallingPackage = callingPackage;
    173     }
    174 
    175     EuiccOperation(Parcel in) {
    176         mAction = in.readInt();
    177         mCallingToken = in.readLong();
    178         mDownloadableSubscription = in.readTypedObject(DownloadableSubscription.CREATOR);
    179         mSubscriptionId = in.readInt();
    180         mSwitchAfterDownload = in.readBoolean();
    181         mCallingPackage = in.readString();
    182     }
    183 
    184     @Override
    185     public void writeToParcel(Parcel dest, int flags) {
    186         dest.writeInt(mAction);
    187         dest.writeLong(mCallingToken);
    188         dest.writeTypedObject(mDownloadableSubscription, flags);
    189         dest.writeInt(mSubscriptionId);
    190         dest.writeBoolean(mSwitchAfterDownload);
    191         dest.writeString(mCallingPackage);
    192     }
    193 
    194     /**
    195      * Resume this operation based on the results of the resolution activity.
    196      *
    197      * @param resolutionExtras The resolution extras as provided to
    198      *     {@link EuiccManager#continueOperation}.
    199      * @param callbackIntent The callback intent to trigger after the operation completes.
    200      */
    201     public void continueOperation(Bundle resolutionExtras, PendingIntent callbackIntent) {
    202         // Restore the identity of the caller. We should err on the side of caution and redo any
    203         // permission checks before continuing with the operation in case the caller state has
    204         // changed. Resolution flows can re-clear the identity if required.
    205         Binder.restoreCallingIdentity(mCallingToken);
    206 
    207         switch (mAction) {
    208             case ACTION_GET_METADATA_DEACTIVATE_SIM:
    209                 resolvedGetMetadataDeactivateSim(
    210                         resolutionExtras.getBoolean(EuiccService.EXTRA_RESOLUTION_CONSENT),
    211                         callbackIntent);
    212                 break;
    213             case ACTION_DOWNLOAD_DEACTIVATE_SIM:
    214                 resolvedDownloadDeactivateSim(
    215                         resolutionExtras.getBoolean(EuiccService.EXTRA_RESOLUTION_CONSENT),
    216                         callbackIntent);
    217                 break;
    218             case ACTION_DOWNLOAD_NO_PRIVILEGES:
    219                 resolvedDownloadNoPrivileges(
    220                         resolutionExtras.getBoolean(EuiccService.EXTRA_RESOLUTION_CONSENT),
    221                         callbackIntent);
    222                 break;
    223             case ACTION_DOWNLOAD_CONFIRMATION_CODE:
    224                 resolvedDownloadConfirmationCode(
    225                         resolutionExtras.getString(EuiccService.EXTRA_RESOLUTION_CONFIRMATION_CODE),
    226                         callbackIntent);
    227                 break;
    228             case ACTION_GET_DEFAULT_LIST_DEACTIVATE_SIM:
    229                 resolvedGetDefaultListDeactivateSim(
    230                         resolutionExtras.getBoolean(EuiccService.EXTRA_RESOLUTION_CONSENT),
    231                         callbackIntent);
    232                 break;
    233             case ACTION_SWITCH_DEACTIVATE_SIM:
    234                 resolvedSwitchDeactivateSim(
    235                         resolutionExtras.getBoolean(EuiccService.EXTRA_RESOLUTION_CONSENT),
    236                         callbackIntent);
    237                 break;
    238             case ACTION_SWITCH_NO_PRIVILEGES:
    239                 resolvedSwitchNoPrivileges(
    240                         resolutionExtras.getBoolean(EuiccService.EXTRA_RESOLUTION_CONSENT),
    241                         callbackIntent);
    242                 break;
    243             default:
    244                 Log.wtf(TAG, "Unknown action: " + mAction);
    245                 break;
    246         }
    247     }
    248 
    249     private void resolvedGetMetadataDeactivateSim(
    250             boolean consent, PendingIntent callbackIntent) {
    251         if (consent) {
    252             // User has consented; perform the lookup, but this time, tell the LPA to deactivate any
    253             // required active SIMs.
    254             EuiccController.get().getDownloadableSubscriptionMetadata(
    255                     mDownloadableSubscription,
    256                     true /* forceDeactivateSim */,
    257                     mCallingPackage,
    258                     callbackIntent);
    259         } else {
    260             // User has not consented; fail the operation.
    261             fail(callbackIntent);
    262         }
    263     }
    264 
    265     private void resolvedDownloadDeactivateSim(
    266             boolean consent, PendingIntent callbackIntent) {
    267         if (consent) {
    268             // User has consented; perform the download, but this time, tell the LPA to deactivate
    269             // any required active SIMs.
    270             EuiccController.get().downloadSubscription(
    271                     mDownloadableSubscription,
    272                     mSwitchAfterDownload,
    273                     mCallingPackage,
    274                     true /* forceDeactivateSim */,
    275                     callbackIntent);
    276         } else {
    277             // User has not consented; fail the operation.
    278             fail(callbackIntent);
    279         }
    280     }
    281 
    282     private void resolvedDownloadNoPrivileges(boolean consent, PendingIntent callbackIntent) {
    283         if (consent) {
    284             // User has consented; perform the download with full privileges.
    285             long token = Binder.clearCallingIdentity();
    286             try {
    287                 // Note: We turn on "forceDeactivateSim" here under the assumption that the
    288                 // privilege prompt should also cover permission to deactivate an active SIM, as
    289                 // the privilege prompt makes it clear that we're switching from the current
    290                 // carrier.
    291                 EuiccController.get().downloadSubscriptionPrivileged(
    292                         token,
    293                         mDownloadableSubscription,
    294                         mSwitchAfterDownload,
    295                         true /* forceDeactivateSim */,
    296                         mCallingPackage,
    297                         callbackIntent);
    298             } finally {
    299                 Binder.restoreCallingIdentity(token);
    300             }
    301         } else {
    302             // User has not consented; fail the operation.
    303             fail(callbackIntent);
    304         }
    305     }
    306 
    307     private void resolvedDownloadConfirmationCode(String confirmationCode,
    308             PendingIntent callbackIntent) {
    309         if (TextUtils.isEmpty(confirmationCode)) {
    310             fail(callbackIntent);
    311         } else {
    312             mDownloadableSubscription.setConfirmationCode(confirmationCode);
    313             EuiccController.get()
    314                     .downloadSubscription(
    315                             mDownloadableSubscription,
    316                             mSwitchAfterDownload,
    317                             mCallingPackage,
    318                             true /* forceDeactivateSim */,
    319                             callbackIntent);
    320         }
    321     }
    322 
    323     private void resolvedGetDefaultListDeactivateSim(
    324             boolean consent, PendingIntent callbackIntent) {
    325         if (consent) {
    326             // User has consented; perform the lookup, but this time, tell the LPA to deactivate any
    327             // required active SIMs.
    328             EuiccController.get().getDefaultDownloadableSubscriptionList(
    329                     true /* forceDeactivateSim */, mCallingPackage, callbackIntent);
    330         } else {
    331             // User has not consented; fail the operation.
    332             fail(callbackIntent);
    333         }
    334     }
    335 
    336     private void resolvedSwitchDeactivateSim(
    337             boolean consent, PendingIntent callbackIntent) {
    338         if (consent) {
    339             // User has consented; perform the switch, but this time, tell the LPA to deactivate any
    340             // required active SIMs.
    341             EuiccController.get().switchToSubscription(
    342                     mSubscriptionId,
    343                     true /* forceDeactivateSim */,
    344                     mCallingPackage,
    345                     callbackIntent);
    346         } else {
    347             // User has not consented; fail the operation.
    348             fail(callbackIntent);
    349         }
    350     }
    351 
    352     private void resolvedSwitchNoPrivileges(boolean consent, PendingIntent callbackIntent) {
    353         if (consent) {
    354             // User has consented; perform the switch with full privileges.
    355             long token = Binder.clearCallingIdentity();
    356             try {
    357                 // Note: We turn on "forceDeactivateSim" here under the assumption that the
    358                 // privilege prompt should also cover permission to deactivate an active SIM, as
    359                 // the privilege prompt makes it clear that we're switching from the current
    360                 // carrier. Also note that in practice, we'd need to deactivate the active SIM to
    361                 // even reach this point, because we cannot fetch the metadata needed to check the
    362                 // privileges without doing so.
    363                 EuiccController.get().switchToSubscriptionPrivileged(
    364                         token,
    365                         mSubscriptionId,
    366                         true /* forceDeactivateSim */,
    367                         mCallingPackage,
    368                         callbackIntent);
    369             } finally {
    370                 Binder.restoreCallingIdentity(token);
    371             }
    372         } else {
    373             // User has not consented; fail the operation.
    374             fail(callbackIntent);
    375         }
    376     }
    377 
    378     private static void fail(PendingIntent callbackIntent) {
    379         EuiccController.get().sendResult(
    380                 callbackIntent,
    381                 EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_ERROR,
    382                 null /* extrasIntent */);
    383     }
    384 
    385     @Override
    386     public int describeContents() {
    387         return 0;
    388     }
    389 }
    390