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