EuiccService.java revision 83f8bc81be65cb09720c6d8dac7717d4652cd931
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 */
16package android.service.euicc;
17
18import android.annotation.CallSuper;
19import android.annotation.Nullable;
20import android.app.Service;
21import android.content.Intent;
22import android.os.IBinder;
23import android.os.RemoteException;
24import android.telephony.euicc.DownloadableSubscription;
25import android.telephony.euicc.EuiccInfo;
26import android.util.ArraySet;
27
28/**
29 * Service interface linking the system with an eUICC local profile assistant (LPA) application.
30 *
31 * <p>An LPA consists of two separate components (which may both be implemented in the same APK):
32 * the LPA backend, and the LPA UI or LUI.
33 *
34 * <p>To implement the LPA backend, you must extend this class and declare this service in your
35 * manifest file. The service must require the
36 * {@link android.Manifest.permission#BIND_EUICC_SERVICE} permission and include an intent filter
37 * with the {@link #EUICC_SERVICE_INTERFACE} action. The priority of the intent filter must be set
38 * to a non-zero value in case multiple implementations are present on the device. For example:
39 *
40 * <pre>{@code
41 * <service android:name=".MyEuiccService"
42 *          android:permission="android.permission.BIND_EUICC_SERVICE">
43 *     <intent-filter android:priority="100">
44 *         <action android:name="android.service.euicc.EuiccService" />
45 *     </intent-filter>
46 * </service>
47 * }</pre>
48 *
49 * <p>To implement the LUI, you must provide an activity for the following actions:
50 *
51 * <ul>
52 * <li>{@link #ACTION_MANAGE_EMBEDDED_SUBSCRIPTIONS}
53 * <li>{@link #ACTION_PROVISION_EMBEDDED_SUBSCRIPTION}
54 * </ul>
55 *
56 * <p>As with the service, each activity must require the
57 * {@link android.Manifest.permission#BIND_EUICC_SERVICE} permission. Each should have an intent
58 * filter with the appropriate action, the {@link #CATEGORY_EUICC_UI} category, and a non-zero
59 * priority.
60 *
61 * TODO(b/35851809): Make this a SystemApi.
62 * @hide
63 */
64public abstract class EuiccService extends Service {
65    /** Action which must be included in this service's intent filter. */
66    public static final String EUICC_SERVICE_INTERFACE = "android.service.euicc.EuiccService";
67
68    /** Category which must be defined to all UI actions, for efficient lookup. */
69    public static final String CATEGORY_EUICC_UI = "android.service.euicc.category.EUICC_UI";
70
71    // LUI actions. These are passthroughs of the corresponding EuiccManager actions.
72
73    /** @see android.telephony.euicc.EuiccManager#ACTION_MANAGE_EMBEDDED_SUBSCRIPTIONS */
74    public static final String ACTION_MANAGE_EMBEDDED_SUBSCRIPTIONS =
75            "android.service.euicc.action.MANAGE_EMBEDDED_SUBSCRIPTIONS";
76    /** @see android.telephony.euicc.EuiccManager#ACTION_PROVISION_EMBEDDED_SUBSCRIPTION */
77    public static final String ACTION_PROVISION_EMBEDDED_SUBSCRIPTION =
78            "android.service.euicc.action.PROVISION_EMBEDDED_SUBSCRIPTION";
79
80    // LUI resolution actions. These are called by the platform to resolve errors in situations that
81    // require user interaction.
82    // TODO(b/33075886): Define extras for any input parameters to these dialogs once they are
83    // more scoped out.
84    /** Alert the user that this action will result in an active SIM being deactivated. */
85    public static final String ACTION_RESOLVE_DEACTIVATE_SIM =
86            "android.service.euicc.action.RESOLVE_DEACTIVATE_SIM";
87    /**
88     * Alert the user about a download/switch being done for an app that doesn't currently have
89     * carrier privileges.
90     */
91    public static final String ACTION_RESOLVE_NO_PRIVILEGES =
92            "android.service.euicc.action.RESOLVE_NO_PRIVILEGES";
93
94    /** Result code for a successful operation. */
95    public static final int RESULT_OK = 0;
96    /** Result code indicating that an active SIM must be deactivated to perform the operation. */
97    public static final int RESULT_MUST_DEACTIVATE_SIM = -1;
98    // New predefined codes should have negative values.
99
100    /** Start of implementation-specific error results. */
101    public static final int RESULT_FIRST_USER = 1;
102
103    /**
104     * List of all valid resolution actions for validation purposes.
105     * @hide
106     */
107    public static final ArraySet<String> RESOLUTION_ACTIONS;
108    static {
109        RESOLUTION_ACTIONS = new ArraySet<>();
110        RESOLUTION_ACTIONS.add(EuiccService.ACTION_RESOLVE_DEACTIVATE_SIM);
111        RESOLUTION_ACTIONS.add(EuiccService.ACTION_RESOLVE_NO_PRIVILEGES);
112    }
113
114    /** Boolean extra for resolution actions indicating whether the user granted consent. */
115    public static final String RESOLUTION_EXTRA_CONSENT = "consent";
116
117    private final IEuiccService.Stub mStubWrapper;
118
119    public EuiccService() {
120        mStubWrapper = new IEuiccServiceWrapper();
121    }
122
123    /**
124     * If overriding this method, call through to the super method for any unknown actions.
125     * {@inheritDoc}
126     */
127    @Override
128    @CallSuper
129    public IBinder onBind(Intent intent) {
130        return mStubWrapper;
131    }
132
133    /**
134     * Return the EID of the eUICC.
135     *
136     * @param slotId ID of the SIM slot being queried. This is currently not populated but is here
137     *     to future-proof the APIs.
138     * @return the EID.
139     * @see android.telephony.euicc.EuiccManager#getEid
140     */
141    // TODO(b/36260308): Update doc when we have multi-SIM support.
142    public abstract String onGetEid(int slotId);
143
144    /**
145     * Populate {@link DownloadableSubscription} metadata for the given downloadable subscription.
146     *
147     * @param slotId ID of the SIM slot to use for the operation. This is currently not populated
148     *     but is here to future-proof the APIs.
149     * @param subscription A subscription whose metadata needs to be populated.
150     * @param forceDeactivateSim If true, and if an active SIM must be deactivated to access the
151     *     eUICC, perform this action automatically. Otherwise, {@link #RESULT_MUST_DEACTIVATE_SIM)}
152     *     should be returned to allow the user to consent to this operation first.
153     * @return The result of the operation.
154     * @see android.telephony.euicc.EuiccManager#getDownloadableSubscriptionMetadata
155     */
156    public abstract GetDownloadableSubscriptionMetadataResult onGetDownloadableSubscriptionMetadata(
157            int slotId, DownloadableSubscription subscription, boolean forceDeactivateSim);
158
159    /**
160     * Return metadata for subscriptions which are available for download for this device.
161     *
162     * @param slotId ID of the SIM slot to use for the operation. This is currently not populated
163     *     but is here to future-proof the APIs.
164     * @param forceDeactivateSim If true, and if an active SIM must be deactivated to access the
165     *     eUICC, perform this action automatically. Otherwise, {@link #RESULT_MUST_DEACTIVATE_SIM)}
166     *     should be returned to allow the user to consent to this operation first.
167     * @return The result of the list operation.
168     * @see android.telephony.euicc.EuiccManager#getDefaultDownloadableSubscriptionList
169     */
170    public abstract GetDefaultDownloadableSubscriptionListResult
171            onGetDefaultDownloadableSubscriptionList(int slotId, boolean forceDeactivateSim);
172
173    /**
174     * Download the given subscription.
175     *
176     * @param slotId ID of the SIM slot to use for the operation. This is currently not populated
177     *     but is here to future-proof the APIs.
178     * @param subscription The subscription to download.
179     * @param switchAfterDownload If true, the subscription should be enabled upon successful
180     *     download.
181     * @param forceDeactivateSim If true, and if an active SIM must be deactivated to access the
182     *     eUICC, perform this action automatically. Otherwise, {@link #RESULT_MUST_DEACTIVATE_SIM}
183     *     should be returned to allow the user to consent to this operation first.
184     * @return the result of the download operation. May be one of the predefined {@code RESULT_}
185     *     constants or any implementation-specific code starting with {@link #RESULT_FIRST_USER}.
186     * @see android.telephony.euicc.EuiccManager#downloadSubscription
187     */
188    public abstract int onDownloadSubscription(int slotId,
189            DownloadableSubscription subscription, boolean switchAfterDownload,
190            boolean forceDeactivateSim);
191
192    /**
193     * Return a list of all @link EuiccProfileInfo}s.
194     *
195     * @param slotId ID of the SIM slot to use for the operation. This is currently not populated
196     *     but is here to future-proof the APIs.
197     * @return The result of the operation.
198     * @see android.telephony.SubscriptionManager#getAvailableSubscriptionInfoList
199     * @see android.telephony.SubscriptionManager#getAccessibleSubscriptionInfoList
200     */
201    public abstract GetEuiccProfileInfoListResult onGetEuiccProfileInfoList(int slotId);
202
203    /**
204     * Return info about the eUICC chip/device.
205     *
206     * @param slotId ID of the SIM slot to use for the operation. This is currently not populated
207     *     but is here to future-proof the APIs.
208     * @return the {@link EuiccInfo} for the eUICC chip/device.
209     * @see android.telephony.euicc.EuiccManager#getEuiccInfo
210     */
211    public abstract EuiccInfo onGetEuiccInfo(int slotId);
212
213    /**
214     * Delete the given subscription.
215     *
216     * <p>If the subscription is currently active, it should be deactivated first (equivalent to a
217     * physical SIM being ejected).
218     *
219     * @param slotId ID of the SIM slot to use for the operation. This is currently not populated
220     *     but is here to future-proof the APIs.
221     * @param iccid the ICCID of the subscription to delete.
222     * @return the result of the delete operation. May be one of the predefined {@code RESULT_}
223     *     constants or any implementation-specific code starting with {@link #RESULT_FIRST_USER}.
224     * @see android.telephony.euicc.EuiccManager#deleteSubscription
225     */
226    public abstract int onDeleteSubscription(int slotId, String iccid);
227
228    /**
229     * Switch to the given subscription.
230     *
231     * @param slotId ID of the SIM slot to use for the operation. This is currently not populated
232     *     but is here to future-proof the APIs.
233     * @param iccid the ICCID of the subscription to enable. May be null, in which case the current
234     *     profile should be deactivated and no profile should be activated to replace it - this is
235     *     equivalent to a physical SIM being ejected.
236     * @param forceDeactivateSim If true, and if an active SIM must be deactivated to access the
237     *     eUICC, perform this action automatically. Otherwise, {@link #RESULT_MUST_DEACTIVATE_SIM}
238     *     should be returned to allow the user to consent to this operation first.
239     * @return the result of the switch operation. May be one of the predefined {@code RESULT_}
240     *     constants or any implementation-specific code starting with {@link #RESULT_FIRST_USER}.
241     * @see android.telephony.euicc.EuiccManager#switchToSubscription
242     */
243    public abstract int onSwitchToSubscription(int slotId, @Nullable String iccid,
244            boolean forceDeactivateSim);
245
246    /**
247     * Update the nickname of the given subscription.
248     *
249     * @param slotId ID of the SIM slot to use for the operation. This is currently not populated
250     *     but is here to future-proof the APIs.
251     * @param iccid the ICCID of the subscription to update.
252     * @param nickname the new nickname to apply.
253     * @return the result of the update operation. May be one of the predefined {@code RESULT_}
254     *     constants or any implementation-specific code starting with {@link #RESULT_FIRST_USER}.
255     * @see android.telephony.euicc.EuiccManager#updateSubscriptionNickname
256     */
257    public abstract int onUpdateSubscriptionNickname(int slotId, String iccid,
258            String nickname);
259
260    /**
261     * Erase all of the subscriptions on the device.
262     *
263     * <p>This is intended to be used for device resets. As such, the reset should be performed even
264     * if an active SIM must be deactivated in order to access the eUICC.
265     *
266     * @param slotId ID of the SIM slot to use for the operation. This is currently not populated
267     *     but is here to future-proof the APIs.
268     * @return the result of the erase operation. May be one of the predefined {@code RESULT_}
269     *     constants or any implementation-specific code starting with {@link #RESULT_FIRST_USER}.
270     * @see android.telephony.euicc.EuiccManager#eraseSubscriptions
271     */
272    public abstract int onEraseSubscriptions(int slotId);
273
274    /**
275     * Wrapper around IEuiccService that forwards calls to implementations of {@link EuiccService}.
276     */
277    private class IEuiccServiceWrapper extends IEuiccService.Stub {
278        @Override
279        public void downloadSubscription(int slotId, DownloadableSubscription subscription,
280                boolean switchAfterDownload, boolean forceDeactivateSim,
281                IDownloadSubscriptionCallback callback) {
282            int result = EuiccService.this.onDownloadSubscription(
283                    slotId, subscription, switchAfterDownload, forceDeactivateSim);
284            try {
285                callback.onComplete(result);
286            } catch (RemoteException e) {
287                // Can't communicate with the phone process; ignore.
288            }
289        }
290
291        @Override
292        public void getEid(int slotId, IGetEidCallback callback) {
293            String eid = EuiccService.this.onGetEid(slotId);
294            try {
295                callback.onSuccess(eid);
296            } catch (RemoteException e) {
297                // Can't communicate with the phone process; ignore.
298            }
299        }
300
301        @Override
302        public void getDownloadableSubscriptionMetadata(int slotId,
303                DownloadableSubscription subscription,
304                boolean forceDeactivateSim,
305                IGetDownloadableSubscriptionMetadataCallback callback) {
306            GetDownloadableSubscriptionMetadataResult result =
307                    EuiccService.this.onGetDownloadableSubscriptionMetadata(
308                            slotId, subscription, forceDeactivateSim);
309            try {
310                callback.onComplete(result);
311            } catch (RemoteException e) {
312                // Can't communicate with the phone process; ignore.
313            }
314        }
315
316        @Override
317        public void getDefaultDownloadableSubscriptionList(int slotId, boolean forceDeactivateSim,
318                IGetDefaultDownloadableSubscriptionListCallback callback) {
319            GetDefaultDownloadableSubscriptionListResult result =
320                    EuiccService.this.onGetDefaultDownloadableSubscriptionList(
321                            slotId, forceDeactivateSim);
322            try {
323                callback.onComplete(result);
324            } catch (RemoteException e) {
325                // Can't communicate with the phone process; ignore.
326            }
327        }
328
329        @Override
330        public void getEuiccProfileInfoList(int slotId, IGetEuiccProfileInfoListCallback callback) {
331            GetEuiccProfileInfoListResult result =
332                    EuiccService.this.onGetEuiccProfileInfoList(slotId);
333            try {
334                callback.onComplete(result);
335            } catch (RemoteException e) {
336                // Can't communicate with the phone process; ignore.
337            }
338        }
339
340        @Override
341        public void getEuiccInfo(int slotId, IGetEuiccInfoCallback callback) {
342            EuiccInfo euiccInfo = EuiccService.this.onGetEuiccInfo(slotId);
343            try {
344                callback.onSuccess(euiccInfo);
345            } catch (RemoteException e) {
346                // Can't communicate with the phone process; ignore.
347            }
348        }
349
350        @Override
351        public void deleteSubscription(int slotId, String iccid,
352                IDeleteSubscriptionCallback callback) {
353            int result = EuiccService.this.onDeleteSubscription(slotId, iccid);
354            try {
355                callback.onComplete(result);
356            } catch (RemoteException e) {
357                // Can't communicate with the phone process; ignore.
358            }
359        }
360
361        @Override
362        public void switchToSubscription(int slotId, String iccid, boolean forceDeactivateSim,
363                ISwitchToSubscriptionCallback callback) {
364            int result =
365                    EuiccService.this.onSwitchToSubscription(slotId, iccid, forceDeactivateSim);
366            try {
367                callback.onComplete(result);
368            } catch (RemoteException e) {
369                // Can't communicate with the phone process; ignore.
370            }
371        }
372
373        @Override
374        public void updateSubscriptionNickname(int slotId, String iccid, String nickname,
375                IUpdateSubscriptionNicknameCallback callback) {
376            int result = EuiccService.this.onUpdateSubscriptionNickname(slotId, iccid, nickname);
377            try {
378                callback.onComplete(result);
379            } catch (RemoteException e) {
380                // Can't communicate with the phone process; ignore.
381            }
382        }
383
384        @Override
385        public void eraseSubscriptions(int slotId, IEraseSubscriptionsCallback callback) {
386            int result = EuiccService.this.onEraseSubscriptions(slotId);
387            try {
388                callback.onComplete(result);
389            } catch (RemoteException e) {
390                // Can't communicate with the phone process; ignore.
391            }
392        }
393    }
394}
395