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 android.service.euicc;
     17 
     18 import android.annotation.CallSuper;
     19 import android.annotation.Nullable;
     20 import android.annotation.SystemApi;
     21 import android.app.Service;
     22 import android.content.Intent;
     23 import android.os.IBinder;
     24 import android.os.RemoteException;
     25 import android.telephony.euicc.DownloadableSubscription;
     26 import android.telephony.euicc.EuiccInfo;
     27 import android.telephony.euicc.EuiccManager.OtaStatus;
     28 import android.util.ArraySet;
     29 
     30 import java.util.concurrent.LinkedBlockingQueue;
     31 import java.util.concurrent.ThreadFactory;
     32 import java.util.concurrent.ThreadPoolExecutor;
     33 import java.util.concurrent.TimeUnit;
     34 import java.util.concurrent.atomic.AtomicInteger;
     35 
     36 /**
     37  * Service interface linking the system with an eUICC local profile assistant (LPA) application.
     38  *
     39  * <p>An LPA consists of two separate components (which may both be implemented in the same APK):
     40  * the LPA backend, and the LPA UI or LUI.
     41  *
     42  * <p>To implement the LPA backend, you must extend this class and declare this service in your
     43  * manifest file. The service must require the
     44  * {@link android.Manifest.permission#BIND_EUICC_SERVICE} permission and include an intent filter
     45  * with the {@link #EUICC_SERVICE_INTERFACE} action. It's suggested that the priority of the intent
     46  * filter to be set to a non-zero value in case multiple implementations are present on the device.
     47  * See the below example. Note that there will be problem if two LPAs are present and they have the
     48  * same priority.
     49  * Example:
     50  *
     51  * <pre>{@code
     52  * <service android:name=".MyEuiccService"
     53  *          android:permission="android.permission.BIND_EUICC_SERVICE">
     54  *     <intent-filter android:priority="100">
     55  *         <action android:name="android.service.euicc.EuiccService" />
     56  *     </intent-filter>
     57  * </service>
     58  * }</pre>
     59  *
     60  * <p>To implement the LUI, you must provide an activity for the following actions:
     61  *
     62  * <ul>
     63  * <li>{@link #ACTION_MANAGE_EMBEDDED_SUBSCRIPTIONS}
     64  * <li>{@link #ACTION_PROVISION_EMBEDDED_SUBSCRIPTION}
     65  * </ul>
     66  *
     67  * <p>As with the service, each activity must require the
     68  * {@link android.Manifest.permission#BIND_EUICC_SERVICE} permission. Each should have an intent
     69  * filter with the appropriate action, the {@link #CATEGORY_EUICC_UI} category, and a non-zero
     70  * priority.
     71  *
     72  * @hide
     73  */
     74 @SystemApi
     75 public abstract class EuiccService extends Service {
     76     /** Action which must be included in this service's intent filter. */
     77     public static final String EUICC_SERVICE_INTERFACE = "android.service.euicc.EuiccService";
     78 
     79     /** Category which must be defined to all UI actions, for efficient lookup. */
     80     public static final String CATEGORY_EUICC_UI = "android.service.euicc.category.EUICC_UI";
     81 
     82     // LUI actions. These are passthroughs of the corresponding EuiccManager actions.
     83 
     84     /**
     85      * @see android.telephony.euicc.EuiccManager#ACTION_MANAGE_EMBEDDED_SUBSCRIPTIONS
     86      * The difference is this one is used by system to bring up the LUI.
     87      */
     88     public static final String ACTION_MANAGE_EMBEDDED_SUBSCRIPTIONS =
     89             "android.service.euicc.action.MANAGE_EMBEDDED_SUBSCRIPTIONS";
     90     /** @see android.telephony.euicc.EuiccManager#ACTION_PROVISION_EMBEDDED_SUBSCRIPTION */
     91     public static final String ACTION_PROVISION_EMBEDDED_SUBSCRIPTION =
     92             "android.service.euicc.action.PROVISION_EMBEDDED_SUBSCRIPTION";
     93 
     94     // LUI resolution actions. These are called by the platform to resolve errors in situations that
     95     // require user interaction.
     96     // TODO(b/33075886): Define extras for any input parameters to these dialogs once they are
     97     // more scoped out.
     98     /**
     99      * Alert the user that this action will result in an active SIM being deactivated.
    100      * To implement the LUI triggered by the system, you need to define this in AndroidManifest.xml.
    101      */
    102     public static final String ACTION_RESOLVE_DEACTIVATE_SIM =
    103             "android.service.euicc.action.RESOLVE_DEACTIVATE_SIM";
    104     /**
    105      * Alert the user about a download/switch being done for an app that doesn't currently have
    106      * carrier privileges.
    107      */
    108     public static final String ACTION_RESOLVE_NO_PRIVILEGES =
    109             "android.service.euicc.action.RESOLVE_NO_PRIVILEGES";
    110 
    111     /** Ask the user to input carrier confirmation code. */
    112     public static final String ACTION_RESOLVE_CONFIRMATION_CODE =
    113             "android.service.euicc.action.RESOLVE_CONFIRMATION_CODE";
    114 
    115     /**
    116      * Intent extra set for resolution requests containing the package name of the calling app.
    117      * This is used by the above actions including ACTION_RESOLVE_DEACTIVATE_SIM,
    118      * ACTION_RESOLVE_NO_PRIVILEGES and ACTION_RESOLVE_CONFIRMATION_CODE.
    119      */
    120     public static final String EXTRA_RESOLUTION_CALLING_PACKAGE =
    121             "android.service.euicc.extra.RESOLUTION_CALLING_PACKAGE";
    122 
    123     /**
    124      * Intent extra set for resolution requests containing a boolean indicating whether to ask the
    125      * user to retry another confirmation code.
    126      */
    127     public static final String EXTRA_RESOLUTION_CONFIRMATION_CODE_RETRIED =
    128             "android.service.euicc.extra.RESOLUTION_CONFIRMATION_CODE_RETRIED";
    129 
    130     /** Result code for a successful operation. */
    131     public static final int RESULT_OK = 0;
    132     /** Result code indicating that an active SIM must be deactivated to perform the operation. */
    133     public static final int RESULT_MUST_DEACTIVATE_SIM = -1;
    134     /** Result code indicating that the user must input a carrier confirmation code. */
    135     public static final int RESULT_NEED_CONFIRMATION_CODE = -2;
    136     // New predefined codes should have negative values.
    137 
    138     /** Start of implementation-specific error results. */
    139     public static final int RESULT_FIRST_USER = 1;
    140 
    141     /**
    142      * List of all valid resolution actions for validation purposes.
    143      * @hide
    144      */
    145     public static final ArraySet<String> RESOLUTION_ACTIONS;
    146     static {
    147         RESOLUTION_ACTIONS = new ArraySet<>();
    148         RESOLUTION_ACTIONS.add(EuiccService.ACTION_RESOLVE_DEACTIVATE_SIM);
    149         RESOLUTION_ACTIONS.add(EuiccService.ACTION_RESOLVE_NO_PRIVILEGES);
    150         RESOLUTION_ACTIONS.add(EuiccService.ACTION_RESOLVE_CONFIRMATION_CODE);
    151     }
    152 
    153     /**
    154      * Boolean extra for resolution actions indicating whether the user granted consent.
    155      * This is used and set by the implementation and used in {@code EuiccOperation}.
    156      */
    157     public static final String EXTRA_RESOLUTION_CONSENT =
    158             "android.service.euicc.extra.RESOLUTION_CONSENT";
    159     /**
    160      * String extra for resolution actions indicating the carrier confirmation code.
    161      * This is used and set by the implementation and used in {@code EuiccOperation}.
    162      */
    163     public static final String EXTRA_RESOLUTION_CONFIRMATION_CODE =
    164             "android.service.euicc.extra.RESOLUTION_CONFIRMATION_CODE";
    165 
    166     private final IEuiccService.Stub mStubWrapper;
    167 
    168     private ThreadPoolExecutor mExecutor;
    169 
    170     public EuiccService() {
    171         mStubWrapper = new IEuiccServiceWrapper();
    172     }
    173 
    174     @Override
    175     @CallSuper
    176     public void onCreate() {
    177         super.onCreate();
    178         // We use a oneway AIDL interface to avoid blocking phone process binder threads on IPCs to
    179         // an external process, but doing so means the requests are serialized by binder, which is
    180         // not desired. Spin up a background thread pool to allow requests to be parallelized.
    181         // TODO(b/38206971): Consider removing this if basic card-level functions like listing
    182         // profiles are moved to the platform.
    183         mExecutor = new ThreadPoolExecutor(
    184                 4 /* corePoolSize */,
    185                 4 /* maxPoolSize */,
    186                 30, TimeUnit.SECONDS, /* keepAliveTime */
    187                 new LinkedBlockingQueue<>(), /* workQueue */
    188                 new ThreadFactory() {
    189                     private final AtomicInteger mCount = new AtomicInteger(1);
    190 
    191                     @Override
    192                     public Thread newThread(Runnable r) {
    193                         return new Thread(r, "EuiccService #" + mCount.getAndIncrement());
    194                     }
    195                 }
    196         );
    197         mExecutor.allowCoreThreadTimeOut(true);
    198     }
    199 
    200     @Override
    201     @CallSuper
    202     public void onDestroy() {
    203         mExecutor.shutdownNow();
    204         super.onDestroy();
    205     }
    206 
    207     /**
    208      * If overriding this method, call through to the super method for any unknown actions.
    209      * {@inheritDoc}
    210      */
    211     @Override
    212     @CallSuper
    213     public IBinder onBind(Intent intent) {
    214         return mStubWrapper;
    215     }
    216 
    217     /**
    218      * Callback class for {@link #onStartOtaIfNecessary(int, OtaStatusChangedCallback)}
    219      *
    220      * The status of OTA which can be {@code android.telephony.euicc.EuiccManager#EUICC_OTA_}
    221      *
    222      * @see IEuiccService#startOtaIfNecessary
    223      */
    224     public abstract static class OtaStatusChangedCallback {
    225         /** Called when OTA status is changed. */
    226         public abstract void onOtaStatusChanged(int status);
    227     }
    228 
    229     /**
    230      * Return the EID of the eUICC.
    231      *
    232      * @param slotId ID of the SIM slot being queried. This is currently not populated but is here
    233      *     to future-proof the APIs.
    234      * @return the EID.
    235      * @see android.telephony.euicc.EuiccManager#getEid
    236      */
    237     // TODO(b/36260308): Update doc when we have multi-SIM support.
    238     public abstract String onGetEid(int slotId);
    239 
    240     /**
    241      * Return the status of OTA update.
    242      *
    243      * @param slotId ID of the SIM slot to use for the operation. This is currently not populated
    244      *     but is here to future-proof the APIs.
    245      * @return The status of Euicc OTA update.
    246      * @see android.telephony.euicc.EuiccManager#getOtaStatus
    247      */
    248     public abstract @OtaStatus int onGetOtaStatus(int slotId);
    249 
    250     /**
    251      * Perform OTA if current OS is not the latest one.
    252      *
    253      * @param slotId ID of the SIM slot to use for the operation. This is currently not populated
    254      *     but is here to future-proof the APIs.
    255      * @param statusChangedCallback Function called when OTA status changed.
    256      */
    257     public abstract void onStartOtaIfNecessary(
    258             int slotId, OtaStatusChangedCallback statusChangedCallback);
    259 
    260     /**
    261      * Populate {@link DownloadableSubscription} metadata for the given downloadable subscription.
    262      *
    263      * @param slotId ID of the SIM slot to use for the operation.
    264      * @param subscription A subscription whose metadata needs to be populated.
    265      * @param forceDeactivateSim If true, and if an active SIM must be deactivated to access the
    266      *     eUICC, perform this action automatically. Otherwise, {@link #RESULT_MUST_DEACTIVATE_SIM)}
    267      *     should be returned to allow the user to consent to this operation first.
    268      * @return The result of the operation.
    269      * @see android.telephony.euicc.EuiccManager#getDownloadableSubscriptionMetadata
    270      */
    271     public abstract GetDownloadableSubscriptionMetadataResult onGetDownloadableSubscriptionMetadata(
    272             int slotId, DownloadableSubscription subscription, boolean forceDeactivateSim);
    273 
    274     /**
    275      * Return metadata for subscriptions which are available for download for this device.
    276      *
    277      * @param slotId ID of the SIM slot to use for the operation. This is currently not populated
    278      *     but is here to future-proof the APIs.
    279      * @param forceDeactivateSim If true, and if an active SIM must be deactivated to access the
    280      *     eUICC, perform this action automatically. Otherwise, {@link #RESULT_MUST_DEACTIVATE_SIM)}
    281      *     should be returned to allow the user to consent to this operation first.
    282      * @return The result of the list operation.
    283      * @see android.telephony.euicc.EuiccManager#getDefaultDownloadableSubscriptionList
    284      */
    285     public abstract GetDefaultDownloadableSubscriptionListResult
    286             onGetDefaultDownloadableSubscriptionList(int slotId, boolean forceDeactivateSim);
    287 
    288     /**
    289      * Download the given subscription.
    290      *
    291      * @param slotId ID of the SIM slot to use for the operation.
    292      * @param subscription The subscription to download.
    293      * @param switchAfterDownload If true, the subscription should be enabled upon successful
    294      *     download.
    295      * @param forceDeactivateSim If true, and if an active SIM must be deactivated to access the
    296      *     eUICC, perform this action automatically. Otherwise, {@link #RESULT_MUST_DEACTIVATE_SIM}
    297      *     should be returned to allow the user to consent to this operation first.
    298      * @return the result of the download operation. May be one of the predefined {@code RESULT_}
    299      *     constants or any implementation-specific code starting with {@link #RESULT_FIRST_USER}.
    300      * @see android.telephony.euicc.EuiccManager#downloadSubscription
    301      */
    302     public abstract int onDownloadSubscription(int slotId,
    303             DownloadableSubscription subscription, boolean switchAfterDownload,
    304             boolean forceDeactivateSim);
    305 
    306     /**
    307      * Return a list of all @link EuiccProfileInfo}s.
    308      *
    309      * @param slotId ID of the SIM slot to use for the operation.
    310      * @return The result of the operation.
    311      * @see android.telephony.SubscriptionManager#getAvailableSubscriptionInfoList
    312      * @see android.telephony.SubscriptionManager#getAccessibleSubscriptionInfoList
    313      */
    314     public abstract GetEuiccProfileInfoListResult onGetEuiccProfileInfoList(int slotId);
    315 
    316     /**
    317      * Return info about the eUICC chip/device.
    318      *
    319      * @param slotId ID of the SIM slot to use for the operation.
    320      * @return the {@link EuiccInfo} for the eUICC chip/device.
    321      * @see android.telephony.euicc.EuiccManager#getEuiccInfo
    322      */
    323     public abstract EuiccInfo onGetEuiccInfo(int slotId);
    324 
    325     /**
    326      * Delete the given subscription.
    327      *
    328      * <p>If the subscription is currently active, it should be deactivated first (equivalent to a
    329      * physical SIM being ejected).
    330      *
    331      * @param slotId ID of the SIM slot to use for the operation.
    332      * @param iccid the ICCID of the subscription to delete.
    333      * @return the result of the delete operation. May be one of the predefined {@code RESULT_}
    334      *     constants or any implementation-specific code starting with {@link #RESULT_FIRST_USER}.
    335      * @see android.telephony.euicc.EuiccManager#deleteSubscription
    336      */
    337     public abstract int onDeleteSubscription(int slotId, String iccid);
    338 
    339     /**
    340      * Switch to the given subscription.
    341      *
    342      * @param slotId ID of the SIM slot to use for the operation.
    343      * @param iccid the ICCID of the subscription to enable. May be null, in which case the current
    344      *     profile should be deactivated and no profile should be activated to replace it - this is
    345      *     equivalent to a physical SIM being ejected.
    346      * @param forceDeactivateSim If true, and if an active SIM must be deactivated to access the
    347      *     eUICC, perform this action automatically. Otherwise, {@link #RESULT_MUST_DEACTIVATE_SIM}
    348      *     should be returned to allow the user to consent to this operation first.
    349      * @return the result of the switch operation. May be one of the predefined {@code RESULT_}
    350      *     constants or any implementation-specific code starting with {@link #RESULT_FIRST_USER}.
    351      * @see android.telephony.euicc.EuiccManager#switchToSubscription
    352      */
    353     public abstract int onSwitchToSubscription(int slotId, @Nullable String iccid,
    354             boolean forceDeactivateSim);
    355 
    356     /**
    357      * Update the nickname of the given subscription.
    358      *
    359      * @param slotId ID of the SIM slot to use for the operation.
    360      * @param iccid the ICCID of the subscription to update.
    361      * @param nickname the new nickname to apply.
    362      * @return the result of the update operation. May be one of the predefined {@code RESULT_}
    363      *     constants or any implementation-specific code starting with {@link #RESULT_FIRST_USER}.
    364      * @see android.telephony.euicc.EuiccManager#updateSubscriptionNickname
    365      */
    366     public abstract int onUpdateSubscriptionNickname(int slotId, String iccid,
    367             String nickname);
    368 
    369     /**
    370      * Erase all of the subscriptions on the device.
    371      *
    372      * <p>This is intended to be used for device resets. As such, the reset should be performed even
    373      * if an active SIM must be deactivated in order to access the eUICC.
    374      *
    375      * @param slotId ID of the SIM slot to use for the operation. This is currently not populated
    376      *     but is here to future-proof the APIs.
    377      * @return the result of the erase operation. May be one of the predefined {@code RESULT_}
    378      *     constants or any implementation-specific code starting with {@link #RESULT_FIRST_USER}.
    379      * @see android.telephony.euicc.EuiccManager#eraseSubscriptions
    380      */
    381     public abstract int onEraseSubscriptions(int slotId);
    382 
    383     /**
    384      * Ensure that subscriptions will be retained on the next factory reset.
    385      *
    386      * <p>Called directly before a factory reset. Assumes that a normal factory reset will lead to
    387      * profiles being erased on first boot (to cover fastboot/recovery wipes), so the implementation
    388      * should persist some bit that will remain accessible after the factory reset to bypass this
    389      * flow when this method is called.
    390      *
    391      * @param slotId ID of the SIM slot to use for the operation. This is currently not populated
    392      *     but is here to future-proof the APIs.
    393      * @return the result of the operation. May be one of the predefined {@code RESULT_} constants
    394      *     or any implementation-specific code starting with {@link #RESULT_FIRST_USER}.
    395      */
    396     public abstract int onRetainSubscriptionsForFactoryReset(int slotId);
    397 
    398     /**
    399      * Wrapper around IEuiccService that forwards calls to implementations of {@link EuiccService}.
    400      */
    401     private class IEuiccServiceWrapper extends IEuiccService.Stub {
    402         @Override
    403         public void downloadSubscription(int slotId, DownloadableSubscription subscription,
    404                 boolean switchAfterDownload, boolean forceDeactivateSim,
    405                 IDownloadSubscriptionCallback callback) {
    406             mExecutor.execute(new Runnable() {
    407                 @Override
    408                 public void run() {
    409                     int result = EuiccService.this.onDownloadSubscription(
    410                             slotId, subscription, switchAfterDownload, forceDeactivateSim);
    411                     try {
    412                         callback.onComplete(result);
    413                     } catch (RemoteException e) {
    414                         // Can't communicate with the phone process; ignore.
    415                     }
    416                 }
    417             });
    418         }
    419 
    420         @Override
    421         public void getEid(int slotId, IGetEidCallback callback) {
    422             mExecutor.execute(new Runnable() {
    423                 @Override
    424                 public void run() {
    425                     String eid = EuiccService.this.onGetEid(slotId);
    426                     try {
    427                         callback.onSuccess(eid);
    428                     } catch (RemoteException e) {
    429                         // Can't communicate with the phone process; ignore.
    430                     }
    431                 }
    432             });
    433         }
    434 
    435         @Override
    436         public void startOtaIfNecessary(
    437                 int slotId, IOtaStatusChangedCallback statusChangedCallback) {
    438             mExecutor.execute(new Runnable() {
    439                 @Override
    440                 public void run() {
    441                     EuiccService.this.onStartOtaIfNecessary(slotId, new OtaStatusChangedCallback() {
    442                         @Override
    443                         public void onOtaStatusChanged(int status) {
    444                             try {
    445                                 statusChangedCallback.onOtaStatusChanged(status);
    446                             } catch (RemoteException e) {
    447                                 // Can't communicate with the phone process; ignore.
    448                             }
    449                         }
    450                     });
    451                 }
    452             });
    453         }
    454 
    455         @Override
    456         public void getOtaStatus(int slotId, IGetOtaStatusCallback callback) {
    457             mExecutor.execute(new Runnable() {
    458                 @Override
    459                 public void run() {
    460                     int status = EuiccService.this.onGetOtaStatus(slotId);
    461                     try {
    462                         callback.onSuccess(status);
    463                     } catch (RemoteException e) {
    464                         // Can't communicate with the phone process; ignore.
    465                     }
    466                 }
    467             });
    468         }
    469 
    470         @Override
    471         public void getDownloadableSubscriptionMetadata(int slotId,
    472                 DownloadableSubscription subscription,
    473                 boolean forceDeactivateSim,
    474                 IGetDownloadableSubscriptionMetadataCallback callback) {
    475             mExecutor.execute(new Runnable() {
    476                 @Override
    477                 public void run() {
    478                     GetDownloadableSubscriptionMetadataResult result =
    479                             EuiccService.this.onGetDownloadableSubscriptionMetadata(
    480                                     slotId, subscription, forceDeactivateSim);
    481                     try {
    482                         callback.onComplete(result);
    483                     } catch (RemoteException e) {
    484                         // Can't communicate with the phone process; ignore.
    485                     }
    486                 }
    487             });
    488         }
    489 
    490         @Override
    491         public void getDefaultDownloadableSubscriptionList(int slotId, boolean forceDeactivateSim,
    492                 IGetDefaultDownloadableSubscriptionListCallback callback) {
    493             mExecutor.execute(new Runnable() {
    494                 @Override
    495                 public void run() {
    496                     GetDefaultDownloadableSubscriptionListResult result =
    497                             EuiccService.this.onGetDefaultDownloadableSubscriptionList(
    498                                     slotId, forceDeactivateSim);
    499                     try {
    500                         callback.onComplete(result);
    501                     } catch (RemoteException e) {
    502                         // Can't communicate with the phone process; ignore.
    503                     }
    504                 }
    505             });
    506         }
    507 
    508         @Override
    509         public void getEuiccProfileInfoList(int slotId, IGetEuiccProfileInfoListCallback callback) {
    510             mExecutor.execute(new Runnable() {
    511                 @Override
    512                 public void run() {
    513                     GetEuiccProfileInfoListResult result =
    514                             EuiccService.this.onGetEuiccProfileInfoList(slotId);
    515                     try {
    516                         callback.onComplete(result);
    517                     } catch (RemoteException e) {
    518                         // Can't communicate with the phone process; ignore.
    519                     }
    520                 }
    521             });
    522         }
    523 
    524         @Override
    525         public void getEuiccInfo(int slotId, IGetEuiccInfoCallback callback) {
    526             mExecutor.execute(new Runnable() {
    527                 @Override
    528                 public void run() {
    529                     EuiccInfo euiccInfo = EuiccService.this.onGetEuiccInfo(slotId);
    530                     try {
    531                         callback.onSuccess(euiccInfo);
    532                     } catch (RemoteException e) {
    533                         // Can't communicate with the phone process; ignore.
    534                     }
    535                 }
    536             });
    537 
    538         }
    539 
    540         @Override
    541         public void deleteSubscription(int slotId, String iccid,
    542                 IDeleteSubscriptionCallback callback) {
    543             mExecutor.execute(new Runnable() {
    544                 @Override
    545                 public void run() {
    546                     int result = EuiccService.this.onDeleteSubscription(slotId, iccid);
    547                     try {
    548                         callback.onComplete(result);
    549                     } catch (RemoteException e) {
    550                         // Can't communicate with the phone process; ignore.
    551                     }
    552                 }
    553             });
    554         }
    555 
    556         @Override
    557         public void switchToSubscription(int slotId, String iccid, boolean forceDeactivateSim,
    558                 ISwitchToSubscriptionCallback callback) {
    559             mExecutor.execute(new Runnable() {
    560                 @Override
    561                 public void run() {
    562                     int result =
    563                             EuiccService.this.onSwitchToSubscription(
    564                                     slotId, iccid, forceDeactivateSim);
    565                     try {
    566                         callback.onComplete(result);
    567                     } catch (RemoteException e) {
    568                         // Can't communicate with the phone process; ignore.
    569                     }
    570                 }
    571             });
    572         }
    573 
    574         @Override
    575         public void updateSubscriptionNickname(int slotId, String iccid, String nickname,
    576                 IUpdateSubscriptionNicknameCallback callback) {
    577             mExecutor.execute(new Runnable() {
    578                 @Override
    579                 public void run() {
    580                     int result =
    581                             EuiccService.this.onUpdateSubscriptionNickname(slotId, iccid, nickname);
    582                     try {
    583                         callback.onComplete(result);
    584                     } catch (RemoteException e) {
    585                         // Can't communicate with the phone process; ignore.
    586                     }
    587                 }
    588             });
    589         }
    590 
    591         @Override
    592         public void eraseSubscriptions(int slotId, IEraseSubscriptionsCallback callback) {
    593             mExecutor.execute(new Runnable() {
    594                 @Override
    595                 public void run() {
    596                     int result = EuiccService.this.onEraseSubscriptions(slotId);
    597                     try {
    598                         callback.onComplete(result);
    599                     } catch (RemoteException e) {
    600                         // Can't communicate with the phone process; ignore.
    601                     }
    602                 }
    603             });
    604         }
    605 
    606         @Override
    607         public void retainSubscriptionsForFactoryReset(int slotId,
    608                 IRetainSubscriptionsForFactoryResetCallback callback) {
    609             mExecutor.execute(new Runnable() {
    610                 @Override
    611                 public void run() {
    612                     int result = EuiccService.this.onRetainSubscriptionsForFactoryReset(slotId);
    613                     try {
    614                         callback.onComplete(result);
    615                     } catch (RemoteException e) {
    616                         // Can't communicate with the phone process; ignore.
    617                     }
    618                 }
    619             });
    620         }
    621     }
    622 }
    623