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