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.Manifest;
19 import android.Manifest.permission;
20 import android.annotation.NonNull;
21 import android.annotation.Nullable;
22 import android.app.AppOpsManager;
23 import android.app.PendingIntent;
24 import android.content.ComponentName;
25 import android.content.Context;
26 import android.content.Intent;
27 import android.content.pm.ComponentInfo;
28 import android.content.pm.PackageInfo;
29 import android.content.pm.PackageManager;
30 import android.os.Binder;
31 import android.os.Bundle;
32 import android.os.ServiceManager;
33 import android.provider.Settings;
34 import android.service.euicc.DownloadSubscriptionResult;
35 import android.service.euicc.EuiccService;
36 import android.service.euicc.GetDefaultDownloadableSubscriptionListResult;
37 import android.service.euicc.GetDownloadableSubscriptionMetadataResult;
38 import android.service.euicc.GetEuiccProfileInfoListResult;
39 import android.telephony.SubscriptionInfo;
40 import android.telephony.SubscriptionManager;
41 import android.telephony.TelephonyManager;
42 import android.telephony.UiccAccessRule;
43 import android.telephony.UiccCardInfo;
44 import android.telephony.euicc.DownloadableSubscription;
45 import android.telephony.euicc.EuiccCardManager.ResetOption;
46 import android.telephony.euicc.EuiccInfo;
47 import android.telephony.euicc.EuiccManager;
48 import android.telephony.euicc.EuiccManager.OtaStatus;
49 import android.text.TextUtils;
50 import android.util.Log;
51 import android.util.Pair;
52 
53 import com.android.internal.annotations.VisibleForTesting;
54 import com.android.internal.telephony.SubscriptionController;
55 import com.android.internal.telephony.euicc.EuiccConnector.OtaStatusChangedCallback;
56 
57 import java.io.FileDescriptor;
58 import java.io.PrintWriter;
59 import java.util.Collections;
60 import java.util.List;
61 import java.util.Stack;
62 import java.util.concurrent.CountDownLatch;
63 import java.util.concurrent.TimeUnit;
64 import java.util.concurrent.atomic.AtomicReference;
65 
66 /** Backing implementation of {@link android.telephony.euicc.EuiccManager}. */
67 public class EuiccController extends IEuiccController.Stub {
68     private static final String TAG = "EuiccController";
69 
70     /** Extra set on resolution intents containing the {@link EuiccOperation}. */
71     @VisibleForTesting
72     static final String EXTRA_OPERATION = "operation";
73 
74     /**
75      * Time out for {@link #dump(FileDescriptor, PrintWriter, String[])}
76      */
77     private static final int EUICC_DUMP_TIME_OUT_SECONDS = 5;
78 
79     // Aliases so line lengths stay short.
80     private static final int OK = EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_OK;
81     private static final int RESOLVABLE_ERROR =
82             EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR;
83     private static final int ERROR =
84             EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_ERROR;
85     private static final String EXTRA_EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTION =
86             EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTION;
87 
88     /** Restrictions limiting access to the PendingIntent */
89     private static final String RESOLUTION_ACTIVITY_PACKAGE_NAME = "com.android.phone";
90     private static final String RESOLUTION_ACTIVITY_CLASS_NAME =
91             "com.android.phone.euicc.EuiccResolutionUiDispatcherActivity";
92 
93     private static EuiccController sInstance;
94 
95     private final Context mContext;
96     private final EuiccConnector mConnector;
97     private final SubscriptionManager mSubscriptionManager;
98     private final TelephonyManager mTelephonyManager;
99     private final AppOpsManager mAppOpsManager;
100     private final PackageManager mPackageManager;
101 
102     // These values should be set or updated upon 1) system boot, 2) EuiccService/LPA is bound to
103     // the phone process, 3) values are updated remotely by server flags.
104     private List<String> mSupportedCountries;
105     private List<String> mUnsupportedCountries;
106 
107     /** Initialize the instance. Should only be called once. */
init(Context context)108     public static EuiccController init(Context context) {
109         synchronized (EuiccController.class) {
110             if (sInstance == null) {
111                 sInstance = new EuiccController(context);
112             } else {
113                 Log.wtf(TAG, "init() called multiple times! sInstance = " + sInstance);
114             }
115         }
116         return sInstance;
117     }
118 
119     /** Get an instance. Assumes one has already been initialized with {@link #init}. */
get()120     public static EuiccController get() {
121         if (sInstance == null) {
122             synchronized (EuiccController.class) {
123                 if (sInstance == null) {
124                     throw new IllegalStateException("get() called before init()");
125                 }
126             }
127         }
128         return sInstance;
129     }
130 
EuiccController(Context context)131     private EuiccController(Context context) {
132         this(context, new EuiccConnector(context));
133         ServiceManager.addService("econtroller", this);
134     }
135 
136     @VisibleForTesting
EuiccController(Context context, EuiccConnector connector)137     public EuiccController(Context context, EuiccConnector connector) {
138         mContext = context;
139         mConnector = connector;
140         mSubscriptionManager = (SubscriptionManager)
141                 context.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
142         mTelephonyManager = (TelephonyManager)
143                 context.getSystemService(Context.TELEPHONY_SERVICE);
144         mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
145         mPackageManager = context.getPackageManager();
146     }
147 
148     /**
149      * Continue an operation which failed with a user-resolvable error.
150      *
151      * <p>The implementation here makes a key assumption that the resolutionIntent has not been
152      * tampered with. This is guaranteed because:
153      * <UL>
154      * <LI>The intent is wrapped in a PendingIntent created by the phone process which is created
155      * with {@link #EXTRA_OPERATION} already present. This means that the operation cannot be
156      * overridden on the PendingIntent - a caller can only add new extras.
157      * <LI>The resolution activity is restricted by a privileged permission; unprivileged apps
158      * cannot start it directly. So the PendingIntent is the only way to start it.
159      * </UL>
160      */
161     @Override
continueOperation(int cardId, Intent resolutionIntent, Bundle resolutionExtras)162     public void continueOperation(int cardId, Intent resolutionIntent, Bundle resolutionExtras) {
163         if (!callerCanWriteEmbeddedSubscriptions()) {
164             throw new SecurityException(
165                     "Must have WRITE_EMBEDDED_SUBSCRIPTIONS to continue operation");
166         }
167         long token = Binder.clearCallingIdentity();
168         try {
169             EuiccOperation op = resolutionIntent.getParcelableExtra(EXTRA_OPERATION);
170             if (op == null) {
171                 throw new IllegalArgumentException("Invalid resolution intent");
172             }
173 
174             PendingIntent callbackIntent =
175                     resolutionIntent.getParcelableExtra(
176                             EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_RESOLUTION_CALLBACK_INTENT);
177             op.continueOperation(cardId, resolutionExtras, callbackIntent);
178         } finally {
179             Binder.restoreCallingIdentity(token);
180         }
181     }
182 
183     /**
184      * Return the EID.
185      *
186      * <p>For API simplicity, this call blocks until completion; while it requires an IPC to load,
187      * that IPC should generally be fast, and the EID shouldn't be needed in the normal course of
188      * operation.
189      */
190     @Override
getEid(int cardId, String callingPackage)191     public String getEid(int cardId, String callingPackage) {
192         boolean callerCanReadPhoneStatePrivileged = callerCanReadPhoneStatePrivileged();
193         long token = Binder.clearCallingIdentity();
194         try {
195             if (!callerCanReadPhoneStatePrivileged
196                     && !canManageSubscriptionOnTargetSim(cardId, callingPackage)) {
197                 throw new SecurityException(
198                         "Must have carrier privileges on subscription to read EID for cardId="
199                                 + cardId);
200             }
201 
202             return blockingGetEidFromEuiccService(cardId);
203         } finally {
204             Binder.restoreCallingIdentity(token);
205         }
206     }
207 
208     /**
209      * Return the current status of OTA update.
210      *
211      * <p>For API simplicity, this call blocks until completion; while it requires an IPC to load,
212      * that IPC should generally be fast.
213      */
214     @Override
getOtaStatus(int cardId)215     public @OtaStatus int getOtaStatus(int cardId) {
216         if (!callerCanWriteEmbeddedSubscriptions()) {
217             throw new SecurityException("Must have WRITE_EMBEDDED_SUBSCRIPTIONS to get OTA status");
218         }
219         long token = Binder.clearCallingIdentity();
220         try {
221             return blockingGetOtaStatusFromEuiccService(cardId);
222         } finally {
223             Binder.restoreCallingIdentity(token);
224         }
225     }
226 
227     /**
228      * Start eUICC OTA update on the default eUICC if current eUICC OS is not the latest one. When
229      * OTA is started or finished, the broadcast {@link EuiccManager#ACTION_OTA_STATUS_CHANGED} will
230      * be sent.
231      *
232      * This function will only be called from phone process and isn't exposed to the other apps.
233      *
234      * (see {@link #startOtaUpdatingIfNecessary(int cardId)}).
235      */
startOtaUpdatingIfNecessary()236     public void startOtaUpdatingIfNecessary() {
237         // TODO(b/120796772) Eventually, we should use startOtaUpdatingIfNecessary(cardId)
238         startOtaUpdatingIfNecessary(mTelephonyManager.getCardIdForDefaultEuicc());
239     }
240 
241     /**
242      * Start eUICC OTA update on the given eUICC if current eUICC OS is not the latest one.
243      */
startOtaUpdatingIfNecessary(int cardId)244     public void startOtaUpdatingIfNecessary(int cardId) {
245         mConnector.startOtaIfNecessary(cardId,
246                 new OtaStatusChangedCallback() {
247                     @Override
248                     public void onOtaStatusChanged(int status) {
249                         sendOtaStatusChangedBroadcast();
250                     }
251 
252                     @Override
253                     public void onEuiccServiceUnavailable() {}
254                 });
255     }
256 
257     @Override
getDownloadableSubscriptionMetadata(int cardId, DownloadableSubscription subscription, String callingPackage, PendingIntent callbackIntent)258     public void getDownloadableSubscriptionMetadata(int cardId,
259             DownloadableSubscription subscription, String callingPackage,
260             PendingIntent callbackIntent) {
261         getDownloadableSubscriptionMetadata(cardId,
262                 subscription, false /* forceDeactivateSim */, callingPackage, callbackIntent);
263     }
264 
265     /**
266      * Sets the supported or unsupported countries for eUICC.
267      *
268      * <p>If {@code isSupported} is true, the supported country list will be replaced by
269      * {@code countriesList}. Otherwise, unsupported country list will be replaced by
270      * {@code countriesList}. For how we determine whether a country is supported by checking
271      * supported and unsupported country list please check {@link EuiccManager#isSupportedCountry}.
272      *
273      * @param isSupported should be true if caller wants to set supported country list. If
274      * isSupported is false, un-supported country list will be updated.
275      * @param countriesList is a list of strings contains country ISO codes in uppercase.
276      */
277     @Override
setSupportedCountries(boolean isSupported, @NonNull List<String> countriesList)278     public void setSupportedCountries(boolean isSupported, @NonNull List<String> countriesList) {
279         if (!callerCanWriteEmbeddedSubscriptions()) {
280             throw new SecurityException(
281                     "Must have WRITE_EMBEDDED_SUBSCRIPTIONS to set supported countries");
282         }
283         if (isSupported) {
284             mSupportedCountries = countriesList;
285         } else {
286             mUnsupportedCountries = countriesList;
287         }
288     }
289 
290     /**
291      * Gets the supported or unsupported countries for eUICC.
292      *
293      * <p>If {@code isSupported} is true, the supported country list will be returned. Otherwise,
294      * unsupported country list will be returned.
295      *
296      * @param isSupported should be true if caller wants to get supported country list. If
297      * isSupported is false, unsupported country list will be returned.
298      * @return a list of strings contains country ISO codes in uppercase.
299      */
300     @Override
301     @NonNull
getSupportedCountries(boolean isSupported)302     public List<String> getSupportedCountries(boolean isSupported) {
303         if (!callerCanWriteEmbeddedSubscriptions()) {
304             throw new SecurityException(
305                     "Must have WRITE_EMBEDDED_SUBSCRIPTIONS to get supported countries");
306         }
307         if (isSupported && mSupportedCountries != null) {
308             return mSupportedCountries;
309         } else if (!isSupported && mUnsupportedCountries != null) {
310             return mUnsupportedCountries;
311         }
312         return Collections.emptyList();
313     }
314 
315     /**
316      * Returns whether the given country supports eUICC.
317      *
318      * <p>Supported country list has a higher prority than unsupported country list. If the
319      * supported country list is not empty, {@code countryIso} will be considered as supported when
320      * it exists in the supported country list. Otherwise {@code countryIso} is not supported. If
321      * the supported country list is empty, {@code countryIso} will be considered as supported if it
322      * does not exist in the unsupported country list. Otherwise {@code countryIso} is not
323      * supported. If both supported and unsupported country lists are empty, then all countries are
324      * consider be supported. For how to set supported and unsupported country list, please check
325      * {@link #setSupportedCountries}.
326      *
327      * @param countryIso should be the ISO-3166 country code is provided in uppercase 2 character
328      * format.
329      * @return whether the given country supports eUICC or not.
330      */
331     @Override
isSupportedCountry(@onNull String countryIso)332     public boolean isSupportedCountry(@NonNull String countryIso) {
333         if (!callerCanWriteEmbeddedSubscriptions()) {
334             throw new SecurityException(
335                     "Must have WRITE_EMBEDDED_SUBSCRIPTIONS to check if the country is supported");
336         }
337         if (mSupportedCountries == null || mSupportedCountries.isEmpty()) {
338             Log.i(TAG, "Using deny list unsupportedCountries=" + mUnsupportedCountries);
339             return !isEsimUnsupportedCountry(countryIso);
340         } else {
341             Log.i(TAG, "Using allow list supportedCountries=" + mSupportedCountries);
342             return isEsimSupportedCountry(countryIso);
343         }
344     }
345 
isEsimSupportedCountry(String countryIso)346     private boolean isEsimSupportedCountry(String countryIso) {
347         if (mSupportedCountries == null || TextUtils.isEmpty(countryIso)) {
348             return true;
349         }
350         return mSupportedCountries.contains(countryIso);
351     }
352 
isEsimUnsupportedCountry(String countryIso)353     private boolean isEsimUnsupportedCountry(String countryIso) {
354         if (mUnsupportedCountries == null || TextUtils.isEmpty(countryIso)) {
355             return false;
356         }
357         return mUnsupportedCountries.contains(countryIso);
358     }
359 
getDownloadableSubscriptionMetadata(int cardId, DownloadableSubscription subscription, boolean forceDeactivateSim, String callingPackage, PendingIntent callbackIntent)360     void getDownloadableSubscriptionMetadata(int cardId, DownloadableSubscription subscription,
361             boolean forceDeactivateSim, String callingPackage, PendingIntent callbackIntent) {
362         if (!callerCanWriteEmbeddedSubscriptions()) {
363             throw new SecurityException("Must have WRITE_EMBEDDED_SUBSCRIPTIONS to get metadata");
364         }
365         mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage);
366         long token = Binder.clearCallingIdentity();
367         try {
368             mConnector.getDownloadableSubscriptionMetadata(cardId,
369                     subscription, forceDeactivateSim,
370                     new GetMetadataCommandCallback(
371                             token, subscription, callingPackage, callbackIntent));
372         } finally {
373             Binder.restoreCallingIdentity(token);
374         }
375     }
376 
377     class GetMetadataCommandCallback implements EuiccConnector.GetMetadataCommandCallback {
378         protected final long mCallingToken;
379         protected final DownloadableSubscription mSubscription;
380         protected final String mCallingPackage;
381         protected final PendingIntent mCallbackIntent;
382 
GetMetadataCommandCallback( long callingToken, DownloadableSubscription subscription, String callingPackage, PendingIntent callbackIntent)383         GetMetadataCommandCallback(
384                 long callingToken,
385                 DownloadableSubscription subscription,
386                 String callingPackage,
387                 PendingIntent callbackIntent) {
388             mCallingToken = callingToken;
389             mSubscription = subscription;
390             mCallingPackage = callingPackage;
391             mCallbackIntent = callbackIntent;
392         }
393 
394         @Override
onGetMetadataComplete(int cardId, GetDownloadableSubscriptionMetadataResult result)395         public void onGetMetadataComplete(int cardId,
396                 GetDownloadableSubscriptionMetadataResult result) {
397             Intent extrasIntent = new Intent();
398             final int resultCode;
399             switch (result.getResult()) {
400                 case EuiccService.RESULT_OK:
401                     resultCode = OK;
402                     extrasIntent.putExtra(
403                             EXTRA_EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTION,
404                             result.getDownloadableSubscription());
405                     break;
406                 case EuiccService.RESULT_MUST_DEACTIVATE_SIM:
407                     resultCode = RESOLVABLE_ERROR;
408                     addResolutionIntent(extrasIntent,
409                             EuiccService.ACTION_RESOLVE_DEACTIVATE_SIM,
410                             mCallingPackage,
411                             0 /* resolvableErrors */,
412                             false /* confirmationCodeRetried */,
413                             getOperationForDeactivateSim(),
414                             cardId);
415                     break;
416                 default:
417                     resultCode = ERROR;
418                     addExtrasToResultIntent(extrasIntent, result.getResult());
419                     break;
420             }
421 
422             sendResult(mCallbackIntent, resultCode, extrasIntent);
423         }
424 
425         @Override
onEuiccServiceUnavailable()426         public void onEuiccServiceUnavailable() {
427             sendResult(mCallbackIntent, ERROR, null /* extrasIntent */);
428         }
429 
getOperationForDeactivateSim()430         protected EuiccOperation getOperationForDeactivateSim() {
431             return EuiccOperation.forGetMetadataDeactivateSim(
432                     mCallingToken, mSubscription, mCallingPackage);
433         }
434     }
435 
436     @Override
downloadSubscription(int cardId, DownloadableSubscription subscription, boolean switchAfterDownload, String callingPackage, Bundle resolvedBundle, PendingIntent callbackIntent)437     public void downloadSubscription(int cardId, DownloadableSubscription subscription,
438             boolean switchAfterDownload, String callingPackage, Bundle resolvedBundle,
439             PendingIntent callbackIntent) {
440         downloadSubscription(cardId, subscription, switchAfterDownload, callingPackage,
441                 false /* forceDeactivateSim */, resolvedBundle, callbackIntent);
442     }
443 
444     /**
445      * Given encoded error code described in
446      * {@link android.telephony.euicc.EuiccManager#OPERATION_SMDX_SUBJECT_REASON_CODE} decode it
447      * into SubjectCode[5.2.6.1] and ReasonCode[5.2.6.2] from GSMA (SGP.22 v2.2)
448      *
449      * @param resultCode from
450      *               {@link android.telephony.euicc.EuiccManager#OPERATION_SMDX_SUBJECT_REASON_CODE}
451      * @return a pair containing SubjectCode[5.2.6.1] and ReasonCode[5.2.6.2] from GSMA (SGP.22
452      * v2.2)
453      */
decodeSmdxSubjectAndReasonCode(int resultCode)454     Pair<String, String> decodeSmdxSubjectAndReasonCode(int resultCode) {
455         final int numOfSections = 6;
456         final int bitsPerSection = 4;
457         final int sectionMask = 0xF;
458 
459         final Stack<Integer> sections = new Stack<>();
460 
461         // Extracting each section of digits backwards.
462         for (int i = 0; i < numOfSections; ++i) {
463             int sectionDigit = resultCode & sectionMask;
464             sections.push(sectionDigit);
465             resultCode = resultCode >>> bitsPerSection;
466         }
467 
468         String subjectCode = sections.pop() + "." + sections.pop() + "." + sections.pop();
469         String reasonCode = sections.pop() + "." + sections.pop() + "." + sections.pop();
470 
471         // drop the leading zeros, e.g 0.1 -> 1, 0.0.3 -> 3, 0.5.1 -> 5.1
472         subjectCode = subjectCode.replaceAll("^(0\\.)*", "");
473         reasonCode = reasonCode.replaceAll("^(0\\.)*", "");
474 
475         return Pair.create(subjectCode, reasonCode);
476     }
477 
478     /**
479      * Add more detailed information to the resulting intent.
480      * Fields added includes(key -> value):
481      * 1. {@link EuiccManager#EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE} -> original error code
482      * 2. {@link EuiccManager#EXTRA_EMBEDDED_SUBSCRIPTION_OPERATION_CODE} ->
483      * EuiccManager.OperationCode such as {@link EuiccManager#OPERATION_DOWNLOAD}
484      * 3. if @link EuiccManager.OperationCode is not
485      * {@link EuiccManager#OPERATION_SMDX_SUBJECT_REASON_CODE}:
486      * {@link EuiccManager#EXTRA_EMBEDDED_SUBSCRIPTION_ERROR_CODE} -> @link
487      * EuiccManager.ErrorCode such as {@link EuiccManager#OPERATION_SMDX}
488      * 4. if EuiccManager.OperationCode is
489      * {@link EuiccManager#OPERATION_SMDX_SUBJECT_REASON_CODE}:
490      * a) {@link EuiccManager#EXTRA_EMBEDDED_SUBSCRIPTION_SMDX_SUBJECT_CODE} ->
491      * SubjectCode[5.2.6.1] from GSMA (SGP.22 v2.2)
492      * b) {@link EuiccManager#EXTRA_EMBEDDED_SUBSCRIPTION_SMDX_REASON_CODE} ->
493      * ReasonCode[5.2.6.2] from GSMA (SGP.22 v2.2
494      */
addExtrasToResultIntent(Intent intent, int resultCode)495     private void addExtrasToResultIntent(Intent intent, int resultCode) {
496         final int firstByteBitOffset = 24;
497         int errorCodeMask = 0xFFFFFF;
498         int operationCode = resultCode >>> firstByteBitOffset;
499 
500         intent.putExtra(
501                 EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE, resultCode);
502 
503         intent.putExtra(EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_OPERATION_CODE, operationCode);
504 
505         // check to see if the operation code is EuiccManager#OPERATION_SMDX_SUBJECT_REASON_CODE
506         final boolean isSmdxSubjectReasonCode =
507                 (operationCode == EuiccManager.OPERATION_SMDX_SUBJECT_REASON_CODE);
508 
509         if (isSmdxSubjectReasonCode) {
510             final Pair<String, String> subjectReasonCode = decodeSmdxSubjectAndReasonCode(
511                     resultCode);
512             final String subjectCode = subjectReasonCode.first;
513             final String reasonCode = subjectReasonCode.second;
514             intent.putExtra(EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_SMDX_SUBJECT_CODE,
515                     subjectCode);
516             intent.putExtra(EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_SMDX_REASON_CODE, reasonCode);
517         } else {
518             final int errorCode = resultCode & errorCodeMask;
519             intent.putExtra(EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_ERROR_CODE, errorCode);
520         }
521     }
522 
downloadSubscription(int cardId, DownloadableSubscription subscription, boolean switchAfterDownload, String callingPackage, boolean forceDeactivateSim, Bundle resolvedBundle, PendingIntent callbackIntent)523     void downloadSubscription(int cardId, DownloadableSubscription subscription,
524             boolean switchAfterDownload, String callingPackage, boolean forceDeactivateSim,
525             Bundle resolvedBundle, PendingIntent callbackIntent) {
526         boolean callerCanWriteEmbeddedSubscriptions = callerCanWriteEmbeddedSubscriptions();
527         mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage);
528 
529         long token = Binder.clearCallingIdentity();
530         try {
531             if (callerCanWriteEmbeddedSubscriptions) {
532                 // With WRITE_EMBEDDED_SUBSCRIPTIONS, we can skip profile-specific permission checks
533                 // and move straight to the profile download.
534                 downloadSubscriptionPrivileged(cardId, token, subscription, switchAfterDownload,
535                         forceDeactivateSim, callingPackage, resolvedBundle, callbackIntent);
536                 return;
537             }
538 
539             // Without WRITE_EMBEDDED_SUBSCRIPTIONS, we first check whether the caller can manage
540             // subscription on the target SIM (see comments below). If yes, the caller *must* be
541             // whitelisted per the metadata of the profile to be downloaded, so check the metadata;
542             // If no, ask the user's consent before proceed.
543             // On a multi-active SIM device, if the caller can manage the active subscription on the
544             // target SIM, or there is no active subscription on the target SIM and the caller can
545             // manage any active subscription on other SIMs, we perform the download silently.
546             // Otherwise, the user must provide consent. If it's a single-active SIM device,
547             // determine whether the caller can manage the current profile; if so, we can perform
548             // the download silently; if not, the user must provide consent.
549             if (canManageSubscriptionOnTargetSim(cardId, callingPackage)) {
550                 mConnector.getDownloadableSubscriptionMetadata(cardId, subscription,
551                     forceDeactivateSim,
552                     new DownloadSubscriptionGetMetadataCommandCallback(token, subscription,
553                         switchAfterDownload, callingPackage, forceDeactivateSim,
554                         callbackIntent, false /* withUserConsent */));
555             } else {
556                 Log.i(TAG, "Caller can't manage subscription on target SIM. "
557                         + "Ask user's consent first");
558                 Intent extrasIntent = new Intent();
559                 addResolutionIntent(extrasIntent, EuiccService.ACTION_RESOLVE_NO_PRIVILEGES,
560                         callingPackage,
561                         0 /* resolvableErrors */,
562                         false /* confirmationCodeRetried */,
563                         EuiccOperation.forDownloadNoPrivilegesOrDeactivateSimCheckMetadata(token,
564                                 subscription, switchAfterDownload, callingPackage), cardId);
565                 sendResult(callbackIntent, RESOLVABLE_ERROR, extrasIntent);
566             }
567         } finally {
568             Binder.restoreCallingIdentity(token);
569         }
570     }
571 
572     class DownloadSubscriptionGetMetadataCommandCallback extends GetMetadataCommandCallback {
573         private final boolean mSwitchAfterDownload;
574         private final boolean mForceDeactivateSim;
575         private final boolean mWithUserConsent;
576 
DownloadSubscriptionGetMetadataCommandCallback(long callingToken, DownloadableSubscription subscription, boolean switchAfterDownload, String callingPackage, boolean forceDeactivateSim, PendingIntent callbackIntent, boolean withUserConsent)577         DownloadSubscriptionGetMetadataCommandCallback(long callingToken,
578                 DownloadableSubscription subscription, boolean switchAfterDownload,
579                 String callingPackage, boolean forceDeactivateSim,
580                 PendingIntent callbackIntent, boolean withUserConsent) {
581             super(callingToken, subscription, callingPackage, callbackIntent);
582             mSwitchAfterDownload = switchAfterDownload;
583             mForceDeactivateSim = forceDeactivateSim;
584             mWithUserConsent = withUserConsent;
585         }
586 
587         @Override
onGetMetadataComplete(int cardId, GetDownloadableSubscriptionMetadataResult result)588         public void onGetMetadataComplete(int cardId,
589                 GetDownloadableSubscriptionMetadataResult result) {
590             DownloadableSubscription subscription = result.getDownloadableSubscription();
591             if (mWithUserConsent) {
592                 // We won't get RESULT_MUST_DEACTIVATE_SIM for the case with user consent.
593                 if (result.getResult() != EuiccService.RESULT_OK) {
594                     // Just propagate the error as normal.
595                     super.onGetMetadataComplete(cardId, result);
596                     return;
597                 }
598 
599                 if (checkCarrierPrivilegeInMetadata(subscription, mCallingPackage)) {
600                     // Caller can download this profile. Since we already have the user's consent,
601                     // proceed to download.
602                     downloadSubscriptionPrivileged(cardId,
603                             mCallingToken, subscription, mSwitchAfterDownload,  mForceDeactivateSim,
604                             mCallingPackage, null /* resolvedBundle */,
605                             mCallbackIntent);
606                 } else {
607                     Log.e(TAG, "Caller does not have carrier privilege in metadata.");
608                     sendResult(mCallbackIntent, ERROR, null /* extrasIntent */);
609                 }
610             } else { // !mWithUserConsent
611                 if (result.getResult() == EuiccService.RESULT_MUST_DEACTIVATE_SIM) {
612                     // The caller can manage the target SIM. Ask the user's consent to deactivate
613                     // the current SIM.
614                     Intent extrasIntent = new Intent();
615                     addResolutionIntent(extrasIntent, EuiccService.ACTION_RESOLVE_DEACTIVATE_SIM,
616                             mCallingPackage,
617                             0 /* resolvableErrors */,
618                             false /* confirmationCodeRetried */,
619                             EuiccOperation.forDownloadNoPrivilegesOrDeactivateSimCheckMetadata(
620                                     mCallingToken, mSubscription, mSwitchAfterDownload,
621                                     mCallingPackage),
622                             cardId);
623                     sendResult(mCallbackIntent, RESOLVABLE_ERROR, extrasIntent);
624                     return;
625                 }
626 
627                 if (result.getResult() != EuiccService.RESULT_OK) {
628                     // Just propagate the error as normal.
629                     super.onGetMetadataComplete(cardId, result);
630                     return;
631                 }
632 
633                 if (checkCarrierPrivilegeInMetadata(subscription, mCallingPackage)) {
634                     // Caller can download this profile per profile metadata. Also, caller can
635                     // manage the subscription on the target SIM, which is already checked.
636                     downloadSubscriptionPrivileged(cardId,
637                             mCallingToken, subscription, mSwitchAfterDownload, mForceDeactivateSim,
638                             mCallingPackage, null /* resolvedBundle */,
639                             mCallbackIntent);
640                 } else {
641                     Log.e(TAG, "Caller is not permitted to download this profile per metadata");
642                     sendResult(mCallbackIntent, ERROR, null /* extrasIntent */);
643                 }
644             }
645         }
646     }
647 
648     // Already have user consent. Check metadata first before proceed to download.
downloadSubscriptionPrivilegedCheckMetadata(int cardId, final long callingToken, DownloadableSubscription subscription, boolean switchAfterDownload, boolean forceDeactivateSim, final String callingPackage, Bundle resolvedBundle, final PendingIntent callbackIntent)649     void downloadSubscriptionPrivilegedCheckMetadata(int cardId, final long callingToken,
650             DownloadableSubscription subscription, boolean switchAfterDownload,
651             boolean forceDeactivateSim, final String callingPackage, Bundle resolvedBundle,
652             final PendingIntent callbackIntent) {
653         mConnector.getDownloadableSubscriptionMetadata(cardId, subscription, forceDeactivateSim,
654                 new DownloadSubscriptionGetMetadataCommandCallback(callingToken, subscription,
655                         switchAfterDownload, callingPackage, forceDeactivateSim, callbackIntent,
656                         true /* withUserConsent */));
657     }
658 
659     // Continue to download subscription without checking anything.
downloadSubscriptionPrivileged(int cardId, final long callingToken, DownloadableSubscription subscription, boolean switchAfterDownload, boolean forceDeactivateSim, final String callingPackage, Bundle resolvedBundle, final PendingIntent callbackIntent)660     void downloadSubscriptionPrivileged(int cardId, final long callingToken,
661             DownloadableSubscription subscription, boolean switchAfterDownload,
662             boolean forceDeactivateSim, final String callingPackage, Bundle resolvedBundle,
663             final PendingIntent callbackIntent) {
664         mConnector.downloadSubscription(
665                 cardId,
666                 subscription,
667                 switchAfterDownload,
668                 forceDeactivateSim,
669                 resolvedBundle,
670                 new EuiccConnector.DownloadCommandCallback() {
671                     @Override
672                     public void onDownloadComplete(DownloadSubscriptionResult result) {
673                         Intent extrasIntent = new Intent();
674                         final int resultCode;
675                         switch (result.getResult()) {
676                             case EuiccService.RESULT_OK:
677                                 resultCode = OK;
678                                 // Now that a profile has been successfully downloaded, mark the
679                                 // eUICC as provisioned so it appears in settings UI as appropriate.
680                                 Settings.Global.putInt(
681                                         mContext.getContentResolver(),
682                                         Settings.Global.EUICC_PROVISIONED,
683                                         1);
684                                 extrasIntent.putExtra(
685                                         EXTRA_EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTION,
686                                         subscription);
687                                 if (!switchAfterDownload) {
688                                     // Since we're not switching, nothing will trigger a
689                                     // subscription list refresh on its own, so request one here.
690                                     refreshSubscriptionsAndSendResult(
691                                             callbackIntent, resultCode, extrasIntent);
692                                     return;
693                                 }
694                                 break;
695                             case EuiccService.RESULT_MUST_DEACTIVATE_SIM:
696                                 resultCode = RESOLVABLE_ERROR;
697                                 addResolutionIntent(extrasIntent,
698                                         EuiccService.ACTION_RESOLVE_DEACTIVATE_SIM,
699                                         callingPackage,
700                                         0 /* resolvableErrors */,
701                                         false /* confirmationCodeRetried */,
702                                         EuiccOperation.forDownloadDeactivateSim(
703                                                 callingToken, subscription, switchAfterDownload,
704                                                 callingPackage),
705                                         cardId);
706                                 break;
707                             case EuiccService.RESULT_RESOLVABLE_ERRORS:
708                                 // Same value as the deprecated
709                                 // {@link EuiccService#RESULT_NEED_CONFIRMATION_CODE}. For the
710                                 // deprecated case, the resolvableErrors is set as 0 in
711                                 // EuiccService.
712                                 resultCode = RESOLVABLE_ERROR;
713                                 boolean retried = false;
714                                 if (!TextUtils.isEmpty(subscription.getConfirmationCode())) {
715                                     retried = true;
716                                 }
717                                 if (result.getResolvableErrors() != 0) {
718                                     addResolutionIntent(extrasIntent,
719                                             EuiccService.ACTION_RESOLVE_RESOLVABLE_ERRORS,
720                                             callingPackage,
721                                             result.getResolvableErrors(),
722                                             retried,
723                                             EuiccOperation.forDownloadResolvableErrors(
724                                                 callingToken, subscription, switchAfterDownload,
725                                                 callingPackage, result.getResolvableErrors()),
726                                             cardId);
727                                 }  else { // Deprecated case
728                                     addResolutionIntent(extrasIntent,
729                                             EuiccService.ACTION_RESOLVE_CONFIRMATION_CODE,
730                                             callingPackage,
731                                             0 /* resolvableErrors */,
732                                             retried /* confirmationCodeRetried */,
733                                             EuiccOperation.forDownloadConfirmationCode(
734                                                 callingToken, subscription, switchAfterDownload,
735                                                 callingPackage),
736                                             cardId);
737                                 }
738                                 break;
739                             default:
740                                 resultCode = ERROR;
741 
742                                 addExtrasToResultIntent(extrasIntent, result.getResult());
743                                 break;
744                         }
745 
746                         sendResult(callbackIntent, resultCode, extrasIntent);
747                     }
748 
749                     @Override
750                     public void onEuiccServiceUnavailable() {
751                         sendResult(callbackIntent, ERROR, null /* extrasIntent */);
752                     }
753                 });
754     }
755 
756     /**
757      * Blocking call to {@link EuiccService#onGetEuiccProfileInfoList} of the eUICC with card ID
758      * {@code cardId}.
759      *
760      * <p>Does not perform permission checks as this is not an exposed API and is only used within
761      * the phone process.
762      */
blockingGetEuiccProfileInfoList(int cardId)763     public GetEuiccProfileInfoListResult blockingGetEuiccProfileInfoList(int cardId) {
764         final CountDownLatch latch = new CountDownLatch(1);
765         final AtomicReference<GetEuiccProfileInfoListResult> resultRef = new AtomicReference<>();
766         mConnector.getEuiccProfileInfoList(
767                 cardId,
768                 new EuiccConnector.GetEuiccProfileInfoListCommandCallback() {
769                     @Override
770                     public void onListComplete(GetEuiccProfileInfoListResult result) {
771                         resultRef.set(result);
772                         latch.countDown();
773                     }
774 
775                     @Override
776                     public void onEuiccServiceUnavailable() {
777                         latch.countDown();
778                     }
779                 });
780         try {
781             latch.await();
782         } catch (InterruptedException e) {
783             Log.e(TAG, "blockingGetEuiccInfoFromEuiccService got InterruptedException e: " + e);
784             Thread.currentThread().interrupt();
785         }
786         return resultRef.get();
787     }
788 
789     @Override
getDefaultDownloadableSubscriptionList(int cardId, String callingPackage, PendingIntent callbackIntent)790     public void getDefaultDownloadableSubscriptionList(int cardId,
791             String callingPackage, PendingIntent callbackIntent) {
792         getDefaultDownloadableSubscriptionList(cardId,
793                 false /* forceDeactivateSim */, callingPackage, callbackIntent);
794     }
795 
getDefaultDownloadableSubscriptionList(int cardId, boolean forceDeactivateSim, String callingPackage, PendingIntent callbackIntent)796     void getDefaultDownloadableSubscriptionList(int cardId,
797             boolean forceDeactivateSim, String callingPackage, PendingIntent callbackIntent) {
798         if (!callerCanWriteEmbeddedSubscriptions()) {
799             throw new SecurityException(
800                     "Must have WRITE_EMBEDDED_SUBSCRIPTIONS to get default list");
801         }
802         mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage);
803         long token = Binder.clearCallingIdentity();
804         try {
805             mConnector.getDefaultDownloadableSubscriptionList(cardId,
806                     forceDeactivateSim, new GetDefaultListCommandCallback(
807                             token, callingPackage, callbackIntent));
808         } finally {
809             Binder.restoreCallingIdentity(token);
810         }
811     }
812 
813     class GetDefaultListCommandCallback implements EuiccConnector.GetDefaultListCommandCallback {
814         final long mCallingToken;
815         final String mCallingPackage;
816         final PendingIntent mCallbackIntent;
817 
GetDefaultListCommandCallback(long callingToken, String callingPackage, PendingIntent callbackIntent)818         GetDefaultListCommandCallback(long callingToken, String callingPackage,
819                 PendingIntent callbackIntent) {
820             mCallingToken = callingToken;
821             mCallingPackage = callingPackage;
822             mCallbackIntent = callbackIntent;
823         }
824 
825         @Override
onGetDefaultListComplete(int cardId, GetDefaultDownloadableSubscriptionListResult result)826         public void onGetDefaultListComplete(int cardId,
827                 GetDefaultDownloadableSubscriptionListResult result) {
828             Intent extrasIntent = new Intent();
829             final int resultCode;
830             switch (result.getResult()) {
831                 case EuiccService.RESULT_OK:
832                     resultCode = OK;
833                     List<DownloadableSubscription> list = result.getDownloadableSubscriptions();
834                     if (list != null && list.size() > 0) {
835                         extrasIntent.putExtra(
836                                 EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTIONS,
837                                 list.toArray(new DownloadableSubscription[list.size()]));
838                     }
839                     break;
840                 case EuiccService.RESULT_MUST_DEACTIVATE_SIM:
841                     resultCode = RESOLVABLE_ERROR;
842                     addResolutionIntent(extrasIntent,
843                             EuiccService.ACTION_RESOLVE_DEACTIVATE_SIM,
844                             mCallingPackage,
845                             0 /* resolvableErrors */,
846                             false /* confirmationCodeRetried */,
847                             EuiccOperation.forGetDefaultListDeactivateSim(
848                                     mCallingToken, mCallingPackage),
849                             cardId);
850                     break;
851                 default:
852                     resultCode = ERROR;
853                     addExtrasToResultIntent(extrasIntent, result.getResult());
854                     break;
855             }
856 
857             sendResult(mCallbackIntent, resultCode, extrasIntent);
858         }
859 
860         @Override
onEuiccServiceUnavailable()861         public void onEuiccServiceUnavailable() {
862             sendResult(mCallbackIntent, ERROR, null /* extrasIntent */);
863         }
864     }
865 
866     /**
867      * Return the {@link EuiccInfo}.
868      *
869      * <p>For API simplicity, this call blocks until completion; while it requires an IPC to load,
870      * that IPC should generally be fast, and this info shouldn't be needed in the normal course of
871      * operation.
872      */
873     @Override
getEuiccInfo(int cardId)874     public EuiccInfo getEuiccInfo(int cardId) {
875         // No permissions required as EuiccInfo is not sensitive.
876         long token = Binder.clearCallingIdentity();
877         try {
878             return blockingGetEuiccInfoFromEuiccService(cardId);
879         } finally {
880             Binder.restoreCallingIdentity(token);
881         }
882     }
883 
884     @Override
deleteSubscription(int cardId, int subscriptionId, String callingPackage, PendingIntent callbackIntent)885     public void deleteSubscription(int cardId, int subscriptionId, String callingPackage,
886             PendingIntent callbackIntent) {
887         boolean callerCanWriteEmbeddedSubscriptions = callerCanWriteEmbeddedSubscriptions();
888         mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage);
889 
890         long token = Binder.clearCallingIdentity();
891         try {
892             SubscriptionInfo sub = getSubscriptionForSubscriptionId(subscriptionId);
893             if (sub == null) {
894                 Log.e(TAG, "Cannot delete nonexistent subscription: " + subscriptionId);
895                 sendResult(callbackIntent, ERROR, null /* extrasIntent */);
896                 return;
897             }
898 
899             // For both single active SIM device and multi-active SIM device, if the caller is
900             // system or the caller manage the target subscription, we let it continue. This is
901             // because deleting subscription won't change status of any other subscriptions.
902             if (!callerCanWriteEmbeddedSubscriptions
903                     && !mSubscriptionManager.canManageSubscription(sub, callingPackage)) {
904                 Log.e(TAG, "No permissions: " + subscriptionId);
905                 sendResult(callbackIntent, ERROR, null /* extrasIntent */);
906                 return;
907             }
908 
909             deleteSubscriptionPrivileged(cardId, sub.getIccId(), callbackIntent);
910         } finally {
911             Binder.restoreCallingIdentity(token);
912         }
913     }
914 
deleteSubscriptionPrivileged(int cardId, String iccid, final PendingIntent callbackIntent)915     void deleteSubscriptionPrivileged(int cardId, String iccid,
916             final PendingIntent callbackIntent) {
917         mConnector.deleteSubscription(
918                 cardId,
919                 iccid,
920                 new EuiccConnector.DeleteCommandCallback() {
921                     @Override
922                     public void onDeleteComplete(int result) {
923                         Intent extrasIntent = new Intent();
924                         final int resultCode;
925                         switch (result) {
926                             case EuiccService.RESULT_OK:
927                                 resultCode = OK;
928                                 refreshSubscriptionsAndSendResult(
929                                         callbackIntent, resultCode, extrasIntent);
930                                 return;
931                             default:
932                                 resultCode = ERROR;
933                                 addExtrasToResultIntent(extrasIntent, result);
934                                 break;
935                         }
936 
937                         sendResult(callbackIntent, resultCode, extrasIntent);
938                     }
939 
940                     @Override
941                     public void onEuiccServiceUnavailable() {
942                         sendResult(callbackIntent, ERROR, null /* extrasIntent */);
943                     }
944                 });
945     }
946 
947     @Override
switchToSubscription(int cardId, int subscriptionId, String callingPackage, PendingIntent callbackIntent)948     public void switchToSubscription(int cardId, int subscriptionId, String callingPackage,
949             PendingIntent callbackIntent) {
950         switchToSubscription(cardId,
951                 subscriptionId, false /* forceDeactivateSim */, callingPackage, callbackIntent);
952     }
953 
switchToSubscription(int cardId, int subscriptionId, boolean forceDeactivateSim, String callingPackage, PendingIntent callbackIntent)954     void switchToSubscription(int cardId, int subscriptionId, boolean forceDeactivateSim,
955             String callingPackage, PendingIntent callbackIntent) {
956         boolean callerCanWriteEmbeddedSubscriptions = callerCanWriteEmbeddedSubscriptions();
957         mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage);
958 
959         long token = Binder.clearCallingIdentity();
960         try {
961             if (callerCanWriteEmbeddedSubscriptions) {
962                 // Assume that if a privileged caller is calling us, we don't need to prompt the
963                 // user about changing carriers, because the caller would only be acting in response
964                 // to user action.
965                 forceDeactivateSim = true;
966             }
967 
968             final String iccid;
969             boolean passConsent = false;
970             if (subscriptionId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
971                 if (callerCanWriteEmbeddedSubscriptions
972                         || canManageActiveSubscriptionOnTargetSim(cardId, callingPackage)) {
973                     passConsent = true;
974                 } else {
975                     Log.e(TAG, "Not permitted to switch to empty subscription");
976                     sendResult(callbackIntent, ERROR, null /* extrasIntent */);
977                     return;
978                 }
979                 iccid = null;
980             } else {
981                 SubscriptionInfo sub = getSubscriptionForSubscriptionId(subscriptionId);
982                 if (sub == null) {
983                     Log.e(TAG, "Cannot switch to nonexistent sub: " + subscriptionId);
984                     sendResult(callbackIntent, ERROR, null /* extrasIntent */);
985                     return;
986                 }
987                 if (callerCanWriteEmbeddedSubscriptions) {
988                     passConsent = true;
989                 } else {
990                     if (!mSubscriptionManager.canManageSubscription(sub, callingPackage)) {
991                         Log.e(TAG, "Not permitted to switch to sub: " + subscriptionId);
992                         sendResult(callbackIntent, ERROR, null /* extrasIntent */);
993                         return;
994                     }
995 
996                     if (canManageSubscriptionOnTargetSim(cardId, callingPackage)) {
997                         passConsent = true;
998                     }
999                 }
1000                 iccid = sub.getIccId();
1001             }
1002 
1003             if (!passConsent) {
1004                 // Switch needs consent.
1005                 Intent extrasIntent = new Intent();
1006                 addResolutionIntent(extrasIntent,
1007                         EuiccService.ACTION_RESOLVE_NO_PRIVILEGES,
1008                         callingPackage,
1009                         0 /* resolvableErrors */,
1010                         false /* confirmationCodeRetried */,
1011                         EuiccOperation.forSwitchNoPrivileges(
1012                                 token, subscriptionId, callingPackage),
1013                         cardId);
1014                 sendResult(callbackIntent, RESOLVABLE_ERROR, extrasIntent);
1015                 return;
1016             }
1017 
1018             switchToSubscriptionPrivileged(cardId, token, subscriptionId, iccid, forceDeactivateSim,
1019                     callingPackage, callbackIntent);
1020         } finally {
1021             Binder.restoreCallingIdentity(token);
1022         }
1023     }
1024 
switchToSubscriptionPrivileged(int cardId, final long callingToken, int subscriptionId, boolean forceDeactivateSim, final String callingPackage, final PendingIntent callbackIntent)1025     void switchToSubscriptionPrivileged(int cardId, final long callingToken, int subscriptionId,
1026             boolean forceDeactivateSim, final String callingPackage,
1027             final PendingIntent callbackIntent) {
1028         String iccid = null;
1029         SubscriptionInfo sub = getSubscriptionForSubscriptionId(subscriptionId);
1030         if (sub != null) {
1031             iccid = sub.getIccId();
1032         }
1033         switchToSubscriptionPrivileged(cardId, callingToken, subscriptionId, iccid,
1034                 forceDeactivateSim, callingPackage, callbackIntent);
1035     }
1036 
switchToSubscriptionPrivileged(int cardId, final long callingToken, int subscriptionId, @Nullable String iccid, boolean forceDeactivateSim, final String callingPackage, final PendingIntent callbackIntent)1037     void switchToSubscriptionPrivileged(int cardId, final long callingToken, int subscriptionId,
1038             @Nullable String iccid, boolean forceDeactivateSim, final String callingPackage,
1039             final PendingIntent callbackIntent) {
1040         mConnector.switchToSubscription(
1041                 cardId,
1042                 iccid,
1043                 forceDeactivateSim,
1044                 new EuiccConnector.SwitchCommandCallback() {
1045                     @Override
1046                     public void onSwitchComplete(int result) {
1047                         Intent extrasIntent = new Intent();
1048                         final int resultCode;
1049                         switch (result) {
1050                             case EuiccService.RESULT_OK:
1051                                 resultCode = OK;
1052                                 break;
1053                             case EuiccService.RESULT_MUST_DEACTIVATE_SIM:
1054                                 resultCode = RESOLVABLE_ERROR;
1055                                 addResolutionIntent(extrasIntent,
1056                                         EuiccService.ACTION_RESOLVE_DEACTIVATE_SIM,
1057                                         callingPackage,
1058                                         0 /* resolvableErrors */,
1059                                         false /* confirmationCodeRetried */,
1060                                         EuiccOperation.forSwitchDeactivateSim(
1061                                                 callingToken, subscriptionId, callingPackage),
1062                                         cardId);
1063                                 break;
1064                             default:
1065                                 resultCode = ERROR;
1066                                 addExtrasToResultIntent(extrasIntent, result);
1067                                 break;
1068                         }
1069 
1070                         sendResult(callbackIntent, resultCode, extrasIntent);
1071                     }
1072 
1073                     @Override
1074                     public void onEuiccServiceUnavailable() {
1075                         sendResult(callbackIntent, ERROR, null /* extrasIntent */);
1076                     }
1077                 });
1078     }
1079 
1080     @Override
updateSubscriptionNickname(int cardId, int subscriptionId, String nickname, String callingPackage, PendingIntent callbackIntent)1081     public void updateSubscriptionNickname(int cardId, int subscriptionId, String nickname,
1082             String callingPackage, PendingIntent callbackIntent) {
1083         boolean callerCanWriteEmbeddedSubscriptions = callerCanWriteEmbeddedSubscriptions();
1084         mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage);
1085 
1086         long token = Binder.clearCallingIdentity();
1087         try {
1088             SubscriptionInfo sub = getSubscriptionForSubscriptionId(subscriptionId);
1089             if (sub == null) {
1090                 Log.e(TAG, "Cannot update nickname to nonexistent sub: " + subscriptionId);
1091                 sendResult(callbackIntent, ERROR, null /* extrasIntent */);
1092                 return;
1093             }
1094 
1095             // For both single active SIM device and multi-active SIM device, if the caller is
1096             // system or the caller can manage the target subscription, we let it continue. This is
1097             // because updating subscription nickname won't affect any other subscriptions.
1098             if (!callerCanWriteEmbeddedSubscriptions
1099                     && !mSubscriptionManager.canManageSubscription(sub, callingPackage)) {
1100                 Log.e(TAG, "No permissions: " + subscriptionId);
1101                 sendResult(callbackIntent, ERROR, null /* extrasIntent */);
1102                 return;
1103             }
1104 
1105             mConnector.updateSubscriptionNickname(cardId,
1106                     sub.getIccId(), nickname,
1107                     new EuiccConnector.UpdateNicknameCommandCallback() {
1108                         @Override
1109                         public void onUpdateNicknameComplete(int result) {
1110                             Intent extrasIntent = new Intent();
1111                             final int resultCode;
1112                             switch (result) {
1113                                 case EuiccService.RESULT_OK:
1114                                     resultCode = OK;
1115                                     refreshSubscriptionsAndSendResult(
1116                                             callbackIntent, resultCode, extrasIntent);
1117                                     return;
1118                                 default:
1119                                     resultCode = ERROR;
1120                                     addExtrasToResultIntent(extrasIntent, result);
1121                                     break;
1122                             }
1123 
1124                             sendResult(callbackIntent, resultCode, extrasIntent);
1125                         }
1126 
1127                         @Override
1128                         public void onEuiccServiceUnavailable() {
1129                             sendResult(callbackIntent, ERROR, null /* extrasIntent */);
1130                         }
1131                     });
1132         } finally {
1133             Binder.restoreCallingIdentity(token);
1134         }
1135     }
1136 
1137     @Override
eraseSubscriptions(int cardId, PendingIntent callbackIntent)1138     public void eraseSubscriptions(int cardId, PendingIntent callbackIntent) {
1139         if (!callerCanWriteEmbeddedSubscriptions()) {
1140             throw new SecurityException(
1141                     "Must have WRITE_EMBEDDED_SUBSCRIPTIONS to erase subscriptions");
1142         }
1143         long token = Binder.clearCallingIdentity();
1144         try {
1145             mConnector.eraseSubscriptions(
1146                     cardId, new EuiccConnector.EraseCommandCallback() {
1147                         @Override
1148                         public void onEraseComplete(int result) {
1149                             Intent extrasIntent = new Intent();
1150                             final int resultCode;
1151                             switch (result) {
1152                                 case EuiccService.RESULT_OK:
1153                                     resultCode = OK;
1154                                     refreshSubscriptionsAndSendResult(
1155                                             callbackIntent, resultCode, extrasIntent);
1156                                     return;
1157                                 default:
1158                                     resultCode = ERROR;
1159                                     addExtrasToResultIntent(extrasIntent, result);
1160                                     break;
1161                             }
1162 
1163                             sendResult(callbackIntent, resultCode, extrasIntent);
1164                         }
1165 
1166                         @Override
1167                         public void onEuiccServiceUnavailable() {
1168                             sendResult(callbackIntent, ERROR, null /* extrasIntent */);
1169                         }
1170                     });
1171         } finally {
1172             Binder.restoreCallingIdentity(token);
1173         }
1174     }
1175 
1176     @Override
eraseSubscriptionsWithOptions( int cardId, @ResetOption int options, PendingIntent callbackIntent)1177     public void eraseSubscriptionsWithOptions(
1178             int cardId, @ResetOption int options, PendingIntent callbackIntent) {
1179         if (!callerCanWriteEmbeddedSubscriptions()) {
1180             throw new SecurityException(
1181                     "Must have WRITE_EMBEDDED_SUBSCRIPTIONS to erase subscriptions");
1182         }
1183         long token = Binder.clearCallingIdentity();
1184         try {
1185             mConnector.eraseSubscriptionsWithOptions(
1186                     cardId, options, new EuiccConnector.EraseCommandCallback() {
1187                 @Override
1188                 public void onEraseComplete(int result) {
1189                     Intent extrasIntent = new Intent();
1190                     final int resultCode;
1191                     switch (result) {
1192                         case EuiccService.RESULT_OK:
1193                             resultCode = OK;
1194                             refreshSubscriptionsAndSendResult(
1195                                     callbackIntent, resultCode, extrasIntent);
1196                             return;
1197                         default:
1198                             resultCode = ERROR;
1199                                     addExtrasToResultIntent(extrasIntent, result);
1200                             break;
1201                     }
1202 
1203                     sendResult(callbackIntent, resultCode, extrasIntent);
1204                 }
1205 
1206                 @Override
1207                 public void onEuiccServiceUnavailable() {
1208                     sendResult(callbackIntent, ERROR, null /* extrasIntent */);
1209                 }
1210             });
1211         } finally {
1212             Binder.restoreCallingIdentity(token);
1213         }
1214     }
1215 
1216     @Override
retainSubscriptionsForFactoryReset(int cardId, PendingIntent callbackIntent)1217     public void retainSubscriptionsForFactoryReset(int cardId, PendingIntent callbackIntent) {
1218         mContext.enforceCallingPermission(Manifest.permission.MASTER_CLEAR,
1219                 "Must have MASTER_CLEAR to retain subscriptions for factory reset");
1220         long token = Binder.clearCallingIdentity();
1221         try {
1222             mConnector.retainSubscriptions(cardId,
1223                     new EuiccConnector.RetainSubscriptionsCommandCallback() {
1224                         @Override
1225                         public void onRetainSubscriptionsComplete(int result) {
1226                             Intent extrasIntent = new Intent();
1227                             final int resultCode;
1228                             switch (result) {
1229                                 case EuiccService.RESULT_OK:
1230                                     resultCode = OK;
1231                                     break;
1232                                 default:
1233                                     resultCode = ERROR;
1234                                     addExtrasToResultIntent(extrasIntent, result);
1235                                     break;
1236                             }
1237 
1238                             sendResult(callbackIntent, resultCode, extrasIntent);
1239                         }
1240 
1241                         @Override
1242                         public void onEuiccServiceUnavailable() {
1243                             sendResult(callbackIntent, ERROR, null /* extrasIntent */);
1244                         }
1245                     });
1246         } finally {
1247             Binder.restoreCallingIdentity(token);
1248         }
1249     }
1250 
1251     /** Refresh the embedded subscription list and dispatch the given result upon completion. */
1252     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
refreshSubscriptionsAndSendResult( PendingIntent callbackIntent, int resultCode, Intent extrasIntent)1253     public void refreshSubscriptionsAndSendResult(
1254             PendingIntent callbackIntent, int resultCode, Intent extrasIntent) {
1255         SubscriptionController.getInstance()
1256                 .requestEmbeddedSubscriptionInfoListRefresh(
1257                         () -> sendResult(callbackIntent, resultCode, extrasIntent));
1258     }
1259 
1260     /** Dispatch the given callback intent with the given result code and data. */
1261     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
sendResult(PendingIntent callbackIntent, int resultCode, Intent extrasIntent)1262     public void sendResult(PendingIntent callbackIntent, int resultCode, Intent extrasIntent) {
1263         try {
1264             callbackIntent.send(mContext, resultCode, extrasIntent);
1265         } catch (PendingIntent.CanceledException e) {
1266             // Caller canceled the callback; do nothing.
1267         }
1268     }
1269 
1270     /** Add a resolution intent to the given extras intent. */
1271     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
addResolutionIntent(Intent extrasIntent, String resolutionAction, String callingPackage, int resolvableErrors, boolean confirmationCodeRetried, EuiccOperation op, int cardId)1272     public void addResolutionIntent(Intent extrasIntent, String resolutionAction,
1273             String callingPackage, int resolvableErrors, boolean confirmationCodeRetried,
1274             EuiccOperation op, int cardId) {
1275         Intent intent = new Intent(EuiccManager.ACTION_RESOLVE_ERROR);
1276         intent.setPackage(RESOLUTION_ACTIVITY_PACKAGE_NAME);
1277         intent.setComponent(new ComponentName(
1278                         RESOLUTION_ACTIVITY_PACKAGE_NAME, RESOLUTION_ACTIVITY_CLASS_NAME));
1279         intent.putExtra(EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_RESOLUTION_ACTION,
1280                 resolutionAction);
1281         intent.putExtra(EuiccService.EXTRA_RESOLUTION_CALLING_PACKAGE, callingPackage);
1282         intent.putExtra(EuiccService.EXTRA_RESOLVABLE_ERRORS, resolvableErrors);
1283         intent.putExtra(EuiccService.EXTRA_RESOLUTION_CARD_ID, cardId);
1284         intent.putExtra(EuiccService.EXTRA_RESOLUTION_CONFIRMATION_CODE_RETRIED,
1285                 confirmationCodeRetried);
1286         intent.putExtra(EXTRA_OPERATION, op);
1287         PendingIntent resolutionIntent = PendingIntent.getActivity(
1288                 mContext, 0 /* requestCode */, intent, PendingIntent.FLAG_ONE_SHOT);
1289         extrasIntent.putExtra(
1290                 EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_RESOLUTION_INTENT, resolutionIntent);
1291     }
1292 
1293     @Override
dump(FileDescriptor fd, final PrintWriter pw, String[] args)1294     public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
1295         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, "Requires DUMP");
1296         final long token = Binder.clearCallingIdentity();
1297         pw.println("===== BEGIN EUICC CLINIC =====");
1298         try {
1299             pw.println("===== EUICC CONNECTOR =====");
1300             mConnector.dump(fd, pw, args);
1301             final CountDownLatch countDownLatch = new CountDownLatch(1);
1302             mConnector.dumpEuiccService(new EuiccConnector.DumpEuiccServiceCommandCallback() {
1303                 @Override
1304                 public void onDumpEuiccServiceComplete(String logs) {
1305                     pw.println("===== EUICC SERVICE =====");
1306                     pw.println(logs);
1307                     countDownLatch.countDown();
1308                 }
1309 
1310                 @Override
1311                 public void onEuiccServiceUnavailable() {
1312                     pw.println("===== EUICC SERVICE UNAVAILABLE =====");
1313                     countDownLatch.countDown();
1314                 }
1315             });
1316 
1317             // Wait up to 5 seconds
1318             if (!countDownLatch.await(EUICC_DUMP_TIME_OUT_SECONDS, TimeUnit.SECONDS)) {
1319                 pw.println("===== EUICC SERVICE TIMEOUT =====");
1320             }
1321         } catch (InterruptedException e) {
1322             pw.println("===== EUICC SERVICE INTERRUPTED =====");
1323         } finally {
1324             pw.println("===== END EUICC CLINIC =====");
1325             Binder.restoreCallingIdentity(token);
1326         }
1327     }
1328 
1329     /**
1330      * Send broadcast {@link EuiccManager#ACTION_OTA_STATUS_CHANGED} for OTA status
1331      * changed.
1332      */
1333     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
sendOtaStatusChangedBroadcast()1334     public void sendOtaStatusChangedBroadcast() {
1335         Intent intent = new Intent(EuiccManager.ACTION_OTA_STATUS_CHANGED);
1336         ComponentInfo bestComponent = mConnector.findBestComponent(mContext.getPackageManager());
1337         if (bestComponent != null) {
1338             intent.setPackage(bestComponent.packageName);
1339         }
1340         mContext.sendBroadcast(intent, permission.WRITE_EMBEDDED_SUBSCRIPTIONS);
1341     }
1342 
1343     @Nullable
getSubscriptionForSubscriptionId(int subscriptionId)1344     private SubscriptionInfo getSubscriptionForSubscriptionId(int subscriptionId) {
1345         List<SubscriptionInfo> subs = mSubscriptionManager.getAvailableSubscriptionInfoList();
1346         int subCount = (subs != null) ? subs.size() : 0;
1347         for (int i = 0; i < subCount; i++) {
1348             SubscriptionInfo sub = subs.get(i);
1349             if (subscriptionId == sub.getSubscriptionId()) {
1350                 return sub;
1351             }
1352         }
1353         return null;
1354     }
1355 
1356     @Nullable
blockingGetEidFromEuiccService(int cardId)1357     private String blockingGetEidFromEuiccService(int cardId) {
1358         CountDownLatch latch = new CountDownLatch(1);
1359         AtomicReference<String> eidRef = new AtomicReference<>();
1360         mConnector.getEid(cardId, new EuiccConnector.GetEidCommandCallback() {
1361             @Override
1362             public void onGetEidComplete(String eid) {
1363                 eidRef.set(eid);
1364                 latch.countDown();
1365             }
1366 
1367             @Override
1368             public void onEuiccServiceUnavailable() {
1369                 latch.countDown();
1370             }
1371         });
1372         return awaitResult(latch, eidRef);
1373     }
1374 
blockingGetOtaStatusFromEuiccService(int cardId)1375     private @OtaStatus int blockingGetOtaStatusFromEuiccService(int cardId) {
1376         CountDownLatch latch = new CountDownLatch(1);
1377         AtomicReference<Integer> statusRef =
1378                 new AtomicReference<>(EuiccManager.EUICC_OTA_STATUS_UNAVAILABLE);
1379         mConnector.getOtaStatus(cardId, new EuiccConnector.GetOtaStatusCommandCallback() {
1380             @Override
1381             public void onGetOtaStatusComplete(@OtaStatus int status) {
1382                 statusRef.set(status);
1383                 latch.countDown();
1384             }
1385 
1386             @Override
1387             public void onEuiccServiceUnavailable() {
1388                 latch.countDown();
1389             }
1390         });
1391         return awaitResult(latch, statusRef);
1392     }
1393 
1394     @Nullable
blockingGetEuiccInfoFromEuiccService(int cardId)1395     private EuiccInfo blockingGetEuiccInfoFromEuiccService(int cardId) {
1396         CountDownLatch latch = new CountDownLatch(1);
1397         AtomicReference<EuiccInfo> euiccInfoRef = new AtomicReference<>();
1398         mConnector.getEuiccInfo(cardId, new EuiccConnector.GetEuiccInfoCommandCallback() {
1399             @Override
1400             public void onGetEuiccInfoComplete(EuiccInfo euiccInfo) {
1401                 euiccInfoRef.set(euiccInfo);
1402                 latch.countDown();
1403             }
1404 
1405             @Override
1406             public void onEuiccServiceUnavailable() {
1407                 latch.countDown();
1408             }
1409         });
1410         return awaitResult(latch, euiccInfoRef);
1411     }
1412 
awaitResult(CountDownLatch latch, AtomicReference<T> resultRef)1413     private static <T> T awaitResult(CountDownLatch latch, AtomicReference<T> resultRef) {
1414         try {
1415             latch.await();
1416         } catch (InterruptedException e) {
1417             Thread.currentThread().interrupt();
1418         }
1419         return resultRef.get();
1420     }
1421 
1422     // Returns whether the caller has carrier privilege on the given subscription.
checkCarrierPrivilegeInMetadata(DownloadableSubscription subscription, String callingPackage)1423     private boolean checkCarrierPrivilegeInMetadata(DownloadableSubscription subscription,
1424             String callingPackage) {
1425         UiccAccessRule[] rules = null;
1426         List<UiccAccessRule> rulesList = subscription.getAccessRules();
1427         if (rulesList != null) {
1428             rules = rulesList.toArray(new UiccAccessRule[rulesList.size()]);
1429         }
1430         if (rules == null) {
1431             Log.e(TAG, "No access rules but caller is unprivileged");
1432             return false;
1433         }
1434 
1435         final PackageInfo info;
1436         try {
1437             info = mPackageManager.getPackageInfo(callingPackage,
1438                 PackageManager.GET_SIGNING_CERTIFICATES);
1439         } catch (PackageManager.NameNotFoundException e) {
1440             Log.e(TAG, "Calling package valid but gone");
1441             return false;
1442         }
1443 
1444         for (int i = 0; i < rules.length; i++) {
1445             if (rules[i].getCarrierPrivilegeStatus(info)
1446                     == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
1447                 Log.i(TAG, "Calling package has carrier privilege to this profile");
1448                 return true;
1449             }
1450         }
1451         Log.e(TAG, "Calling package doesn't have carrier privilege to this profile");
1452         return false;
1453     }
1454 
supportMultiActiveSlots()1455     private boolean supportMultiActiveSlots() {
1456         return mTelephonyManager.getSupportedModemCount() > 1;
1457     }
1458 
1459     // Checks whether the caller can manage the active embedded subscription on the SIM with the
1460     // given cardId.
canManageActiveSubscriptionOnTargetSim(int cardId, String callingPackage)1461     private boolean canManageActiveSubscriptionOnTargetSim(int cardId, String callingPackage) {
1462         List<SubscriptionInfo> subInfoList = mSubscriptionManager
1463                 .getActiveSubscriptionInfoList(/* userVisibleOnly */false);
1464         if (subInfoList == null || subInfoList.size() == 0) {
1465             // No active subscription on any SIM.
1466             return false;
1467         }
1468         for (SubscriptionInfo subInfo : subInfoList) {
1469             // If cardId == TelephonyManager.UNSUPPORTED_CARD_ID, we assume it does not support
1470             // multiple eSIMs. There are older multi-active SIM devices which do not implement HAL
1471             // 1.2 and if they have multiple eSIMs, we let it pass if the app can manage an active
1472             // subscription on any eSIM. That's the best we can do here.
1473             if ((cardId == TelephonyManager.UNSUPPORTED_CARD_ID || subInfo.getCardId() == cardId)
1474                     && subInfo.isEmbedded()
1475                     && mSubscriptionManager.canManageSubscription(subInfo, callingPackage)) {
1476                 return true;
1477             }
1478         }
1479         return false;
1480     }
1481 
1482     // For a multi-active subscriptions phone, checks whether the caller can manage subscription on
1483     // the target SIM with the given cardId. The caller can only manage subscription on the target
1484     // SIM if it can manage the active subscription on the target SIM or there is no active
1485     // subscription on the target SIM, and the caller can manage any active subscription on any
1486     // other SIM. The target SIM should be an eUICC.
1487     // For a single-active subscription phone, checks whether the caller can manage any active
1488     // embedded subscription.
canManageSubscriptionOnTargetSim(int cardId, String callingPackage)1489     private boolean canManageSubscriptionOnTargetSim(int cardId, String callingPackage) {
1490         List<SubscriptionInfo> subInfoList = mSubscriptionManager
1491                 .getActiveSubscriptionInfoList(false /* userVisibleonly */);
1492         // No active subscription on any SIM.
1493         if (subInfoList == null || subInfoList.size() == 0) {
1494             return false;
1495         }
1496         // If it's a multi-active SIM device, we assume it's above HAL 1.2 which supports cardId.
1497         // There are older multi-active SIM devices but don't implement HAL 1.2. In this case,
1498         // platform can't even detect UiccCardInfo#isEuicc as true for eSIM, which won't let the
1499         // below check pass. That's the best we can do here.
1500         if (supportMultiActiveSlots()) {
1501             // The target card should be an eUICC.
1502             List<UiccCardInfo> cardInfos = mTelephonyManager.getUiccCardsInfo();
1503             if (cardInfos == null || cardInfos.isEmpty()) {
1504                 return false;
1505             }
1506             boolean isEuicc = false;
1507             for (UiccCardInfo info : cardInfos) {
1508                 if (info != null && info.getCardId() == cardId && info.isEuicc()) {
1509                     isEuicc = true;
1510                     break;
1511                 }
1512             }
1513             if (!isEuicc) {
1514                 Log.i(TAG, "The target SIM is not an eUICC.");
1515                 return false;
1516             }
1517 
1518             // If the caller can't manage the active embedded subscription on the target SIM, return
1519             // false. If the caller can manage the active embedded subscription on the target SIM,
1520             // return true directly.
1521             for (SubscriptionInfo subInfo : subInfoList) {
1522                 // subInfo.isEmbedded() can only be true for the target SIM.
1523                 if (subInfo.isEmbedded() && subInfo.getCardId() == cardId) {
1524                     return mSubscriptionManager.canManageSubscription(subInfo, callingPackage);
1525                 }
1526             }
1527 
1528             // There is no active subscription on the target SIM, checks whether the caller can
1529             // manage any active subscription on any other SIM.
1530             return mTelephonyManager.checkCarrierPrivilegesForPackageAnyPhone(callingPackage)
1531                     == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS;
1532         } else {
1533             for (SubscriptionInfo subInfo : subInfoList) {
1534                 if (subInfo.isEmbedded()
1535                         && mSubscriptionManager.canManageSubscription(subInfo, callingPackage)) {
1536                     return true;
1537                 }
1538             }
1539             return false;
1540         }
1541     }
1542 
callerCanReadPhoneStatePrivileged()1543     private boolean callerCanReadPhoneStatePrivileged() {
1544         return mContext.checkCallingOrSelfPermission(
1545                 Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
1546                 == PackageManager.PERMISSION_GRANTED;
1547     }
1548 
callerCanWriteEmbeddedSubscriptions()1549     private boolean callerCanWriteEmbeddedSubscriptions() {
1550         return mContext.checkCallingOrSelfPermission(
1551                 Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
1552                 == PackageManager.PERMISSION_GRANTED;
1553     }
1554 }
1555