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 
EuiccService()170     public EuiccService() {
171         mStubWrapper = new IEuiccServiceWrapper();
172     }
173 
174     @Override
175     @CallSuper
onCreate()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
onDestroy()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
onBind(Intent intent)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. */
onOtaStatusChanged(int status)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.
onGetEid(int slotId)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      */
onGetOtaStatus(int slotId)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      */
onStartOtaIfNecessary( int slotId, OtaStatusChangedCallback statusChangedCallback)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      */
onGetDownloadableSubscriptionMetadata( int slotId, DownloadableSubscription subscription, boolean forceDeactivateSim)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
onGetDefaultDownloadableSubscriptionList(int slotId, boolean forceDeactivateSim)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      */
onDownloadSubscription(int slotId, DownloadableSubscription subscription, boolean switchAfterDownload, boolean forceDeactivateSim)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      */
onGetEuiccProfileInfoList(int slotId)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      */
onGetEuiccInfo(int slotId)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      */
onDeleteSubscription(int slotId, String iccid)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      */
onSwitchToSubscription(int slotId, @Nullable String iccid, boolean forceDeactivateSim)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      */
onUpdateSubscriptionNickname(int slotId, String iccid, String nickname)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      */
onEraseSubscriptions(int slotId)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      */
onRetainSubscriptionsForFactoryReset(int slotId)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
downloadSubscription(int slotId, DownloadableSubscription subscription, boolean switchAfterDownload, boolean forceDeactivateSim, IDownloadSubscriptionCallback callback)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
getEid(int slotId, IGetEidCallback callback)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
startOtaIfNecessary( int slotId, IOtaStatusChangedCallback statusChangedCallback)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
getOtaStatus(int slotId, IGetOtaStatusCallback callback)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
getDownloadableSubscriptionMetadata(int slotId, DownloadableSubscription subscription, boolean forceDeactivateSim, IGetDownloadableSubscriptionMetadataCallback callback)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
getDefaultDownloadableSubscriptionList(int slotId, boolean forceDeactivateSim, IGetDefaultDownloadableSubscriptionListCallback callback)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
getEuiccProfileInfoList(int slotId, IGetEuiccProfileInfoListCallback callback)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
getEuiccInfo(int slotId, IGetEuiccInfoCallback callback)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
deleteSubscription(int slotId, String iccid, IDeleteSubscriptionCallback callback)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
switchToSubscription(int slotId, String iccid, boolean forceDeactivateSim, ISwitchToSubscriptionCallback callback)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
updateSubscriptionNickname(int slotId, String iccid, String nickname, IUpdateSubscriptionNicknameCallback callback)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
eraseSubscriptions(int slotId, IEraseSubscriptionsCallback callback)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
retainSubscriptionsForFactoryReset(int slotId, IRetainSubscriptionsForFactoryResetCallback callback)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