• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.app.compat.CompatChanges;
25 import android.content.ComponentName;
26 import android.content.Context;
27 import android.content.Intent;
28 import android.content.pm.ComponentInfo;
29 import android.content.pm.PackageInfo;
30 import android.content.pm.PackageManager;
31 import android.os.Binder;
32 import android.os.Bundle;
33 import android.provider.Settings;
34 import android.service.euicc.DownloadSubscriptionResult;
35 import android.service.euicc.EuiccService;
36 import android.service.euicc.GetDefaultDownloadableSubscriptionListResult;
37 import android.service.euicc.GetDownloadableSubscriptionMetadataResult;
38 import android.service.euicc.GetEuiccProfileInfoListResult;
39 import android.telephony.AnomalyReporter;
40 import android.telephony.SubscriptionInfo;
41 import android.telephony.SubscriptionManager;
42 import android.telephony.TelephonyFrameworkInitializer;
43 import android.telephony.TelephonyManager;
44 import android.telephony.UiccAccessRule;
45 import android.telephony.UiccCardInfo;
46 import android.telephony.UiccPortInfo;
47 import android.telephony.UiccSlotInfo;
48 import android.telephony.euicc.DownloadableSubscription;
49 import android.telephony.euicc.EuiccCardManager.ResetOption;
50 import android.telephony.euicc.EuiccInfo;
51 import android.telephony.euicc.EuiccManager;
52 import android.telephony.euicc.EuiccManager.OtaStatus;
53 import android.text.TextUtils;
54 import android.util.EventLog;
55 import android.util.Log;
56 import android.util.Pair;
57 
58 import com.android.internal.annotations.VisibleForTesting;
59 import com.android.internal.telephony.CarrierPrivilegesTracker;
60 import com.android.internal.telephony.Phone;
61 import com.android.internal.telephony.PhoneFactory;
62 import com.android.internal.telephony.SubscriptionController;
63 import com.android.internal.telephony.euicc.EuiccConnector.OtaStatusChangedCallback;
64 import com.android.internal.telephony.uicc.IccUtils;
65 import com.android.internal.telephony.uicc.UiccController;
66 import com.android.internal.telephony.uicc.UiccPort;
67 import com.android.internal.telephony.uicc.UiccSlot;
68 
69 import java.io.FileDescriptor;
70 import java.io.PrintWriter;
71 import java.util.Collections;
72 import java.util.List;
73 import java.util.Stack;
74 import java.util.UUID;
75 import java.util.concurrent.CountDownLatch;
76 import java.util.concurrent.TimeUnit;
77 import java.util.concurrent.atomic.AtomicReference;
78 
79 /** Backing implementation of {@link android.telephony.euicc.EuiccManager}. */
80 public class EuiccController extends IEuiccController.Stub {
81     private static final String TAG = "EuiccController";
82 
83     /** Extra set on resolution intents containing the {@link EuiccOperation}. */
84     @VisibleForTesting
85     static final String EXTRA_OPERATION = "operation";
86 
87     /**
88      * Time out for {@link #dump(FileDescriptor, PrintWriter, String[])}
89      */
90     private static final int EUICC_DUMP_TIME_OUT_SECONDS = 5;
91 
92     // Aliases so line lengths stay short.
93     private static final int OK = EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_OK;
94     private static final int RESOLVABLE_ERROR =
95             EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR;
96     private static final int ERROR =
97             EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_ERROR;
98     private static final String EXTRA_EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTION =
99             EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTION;
100 
101     /** Restrictions limiting access to the PendingIntent */
102     private static final String RESOLUTION_ACTIVITY_PACKAGE_NAME = "com.android.phone";
103     private static final String RESOLUTION_ACTIVITY_CLASS_NAME =
104             "com.android.phone.euicc.EuiccResolutionUiDispatcherActivity";
105 
106     private static EuiccController sInstance;
107 
108     private final Context mContext;
109     private final EuiccConnector mConnector;
110     private final SubscriptionManager mSubscriptionManager;
111     private final TelephonyManager mTelephonyManager;
112     private final AppOpsManager mAppOpsManager;
113     private final PackageManager mPackageManager;
114 
115     // These values should be set or updated upon 1) system boot, 2) EuiccService/LPA is bound to
116     // the phone process, 3) values are updated remotely by server flags.
117     private List<String> mSupportedCountries;
118     private List<String> mUnsupportedCountries;
119 
120     /** Initialize the instance. Should only be called once. */
init(Context context)121     public static EuiccController init(Context context) {
122         synchronized (EuiccController.class) {
123             if (sInstance == null) {
124                 sInstance = new EuiccController(context);
125             } else {
126                 Log.wtf(TAG, "init() called multiple times! sInstance = " + sInstance);
127             }
128         }
129         return sInstance;
130     }
131 
132     /** Get an instance. Assumes one has already been initialized with {@link #init}. */
get()133     public static EuiccController get() {
134         if (sInstance == null) {
135             synchronized (EuiccController.class) {
136                 if (sInstance == null) {
137                     throw new IllegalStateException("get() called before init()");
138                 }
139             }
140         }
141         return sInstance;
142     }
143 
EuiccController(Context context)144     private EuiccController(Context context) {
145         this(context, new EuiccConnector(context));
146         TelephonyFrameworkInitializer
147                 .getTelephonyServiceManager().getEuiccControllerService().register(this);
148     }
149 
150     @VisibleForTesting
EuiccController(Context context, EuiccConnector connector)151     public EuiccController(Context context, EuiccConnector connector) {
152         mContext = context;
153         mConnector = connector;
154         mSubscriptionManager = (SubscriptionManager)
155                 context.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
156         mTelephonyManager = (TelephonyManager)
157                 context.getSystemService(Context.TELEPHONY_SERVICE);
158         mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
159         mPackageManager = context.getPackageManager();
160     }
161 
162     /**
163      * Continue an operation which failed with a user-resolvable error.
164      *
165      * <p>The implementation here makes a key assumption that the resolutionIntent has not been
166      * tampered with. This is guaranteed because:
167      * <UL>
168      * <LI>The intent is wrapped in a PendingIntent created by the phone process which is created
169      * with {@link #EXTRA_OPERATION} already present. This means that the operation cannot be
170      * overridden on the PendingIntent - a caller can only add new extras.
171      * <LI>The resolution activity is restricted by a privileged permission; unprivileged apps
172      * cannot start it directly. So the PendingIntent is the only way to start it.
173      * </UL>
174      */
175     @Override
continueOperation(int cardId, Intent resolutionIntent, Bundle resolutionExtras)176     public void continueOperation(int cardId, Intent resolutionIntent, Bundle resolutionExtras) {
177         if (!callerCanWriteEmbeddedSubscriptions()) {
178             throw new SecurityException(
179                     "Must have WRITE_EMBEDDED_SUBSCRIPTIONS to continue operation");
180         }
181         long token = Binder.clearCallingIdentity();
182         try {
183             EuiccOperation op = resolutionIntent.getParcelableExtra(EXTRA_OPERATION);
184             if (op == null) {
185                 throw new IllegalArgumentException("Invalid resolution intent");
186             }
187 
188             PendingIntent callbackIntent =
189                     resolutionIntent.getParcelableExtra(
190                             EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_RESOLUTION_CALLBACK_INTENT);
191             boolean usePortIndex = resolutionIntent.getBooleanExtra(
192                     EuiccService.EXTRA_RESOLUTION_USE_PORT_INDEX, false);
193             resolutionExtras.putBoolean(EuiccService.EXTRA_RESOLUTION_USE_PORT_INDEX, usePortIndex);
194             Log.i(TAG, " continueOperation portIndex: " + resolutionExtras.getInt(
195                     EuiccService.EXTRA_RESOLUTION_PORT_INDEX) + " usePortIndex: " + usePortIndex);
196             op.continueOperation(cardId, resolutionExtras, callbackIntent);
197         } finally {
198             Binder.restoreCallingIdentity(token);
199         }
200     }
201 
202     /**
203      * Return the EID.
204      *
205      * <p>For API simplicity, this call blocks until completion; while it requires an IPC to load,
206      * that IPC should generally be fast, and the EID shouldn't be needed in the normal course of
207      * operation.
208      */
209     @Override
getEid(int cardId, String callingPackage)210     public String getEid(int cardId, String callingPackage) {
211         boolean callerCanReadPhoneStatePrivileged = callerCanReadPhoneStatePrivileged();
212         try {
213             mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage);
214         } catch (SecurityException e) {
215             EventLog.writeEvent(0x534e4554, "159062405", -1, "Missing UID checking");
216             throw e;
217         }
218         long token = Binder.clearCallingIdentity();
219         try {
220             if (!callerCanReadPhoneStatePrivileged
221                     && !canManageSubscriptionOnTargetSim(cardId, callingPackage, false,
222                     TelephonyManager.INVALID_PORT_INDEX)) {
223                 throw new SecurityException(
224                         "Must have carrier privileges on subscription to read EID for cardId="
225                                 + cardId);
226             }
227 
228             return blockingGetEidFromEuiccService(cardId);
229         } finally {
230             Binder.restoreCallingIdentity(token);
231         }
232     }
233 
234     /**
235      * Return the current status of OTA update.
236      *
237      * <p>For API simplicity, this call blocks until completion; while it requires an IPC to load,
238      * that IPC should generally be fast.
239      */
240     @Override
getOtaStatus(int cardId)241     public @OtaStatus int getOtaStatus(int cardId) {
242         if (!callerCanWriteEmbeddedSubscriptions()) {
243             throw new SecurityException("Must have WRITE_EMBEDDED_SUBSCRIPTIONS to get OTA status");
244         }
245         long token = Binder.clearCallingIdentity();
246         try {
247             return blockingGetOtaStatusFromEuiccService(cardId);
248         } finally {
249             Binder.restoreCallingIdentity(token);
250         }
251     }
252 
253     /**
254      * Start eUICC OTA update on the default eUICC if current eUICC OS is not the latest one. When
255      * OTA is started or finished, the broadcast {@link EuiccManager#ACTION_OTA_STATUS_CHANGED} will
256      * be sent.
257      *
258      * This function will only be called from phone process and isn't exposed to the other apps.
259      *
260      * (see {@link #startOtaUpdatingIfNecessary(int cardId)}).
261      */
startOtaUpdatingIfNecessary()262     public void startOtaUpdatingIfNecessary() {
263         // TODO(b/120796772) Eventually, we should use startOtaUpdatingIfNecessary(cardId)
264         startOtaUpdatingIfNecessary(mTelephonyManager.getCardIdForDefaultEuicc());
265     }
266 
267     /**
268      * Start eUICC OTA update on the given eUICC if current eUICC OS is not the latest one.
269      */
startOtaUpdatingIfNecessary(int cardId)270     public void startOtaUpdatingIfNecessary(int cardId) {
271         mConnector.startOtaIfNecessary(cardId,
272                 new OtaStatusChangedCallback() {
273                     @Override
274                     public void onOtaStatusChanged(int status) {
275                         sendOtaStatusChangedBroadcast();
276                     }
277 
278                     @Override
279                     public void onEuiccServiceUnavailable() {}
280                 });
281     }
282 
283     @Override
getDownloadableSubscriptionMetadata(int cardId, DownloadableSubscription subscription, String callingPackage, PendingIntent callbackIntent)284     public void getDownloadableSubscriptionMetadata(int cardId,
285             DownloadableSubscription subscription, String callingPackage,
286             PendingIntent callbackIntent) {
287         getDownloadableSubscriptionMetadata(cardId,
288                 subscription, false /* forceDeactivateSim */, callingPackage, callbackIntent);
289     }
290 
291     /**
292      * Sets the supported or unsupported countries for eUICC.
293      *
294      * <p>If {@code isSupported} is true, the supported country list will be replaced by
295      * {@code countriesList}. Otherwise, unsupported country list will be replaced by
296      * {@code countriesList}. For how we determine whether a country is supported by checking
297      * supported and unsupported country list please check {@link EuiccManager#isSupportedCountry}.
298      *
299      * @param isSupported should be true if caller wants to set supported country list. If
300      * isSupported is false, un-supported country list will be updated.
301      * @param countriesList is a list of strings contains country ISO codes in uppercase.
302      */
303     @Override
setSupportedCountries(boolean isSupported, @NonNull List<String> countriesList)304     public void setSupportedCountries(boolean isSupported, @NonNull List<String> countriesList) {
305         if (!callerCanWriteEmbeddedSubscriptions()) {
306             throw new SecurityException(
307                     "Must have WRITE_EMBEDDED_SUBSCRIPTIONS to set supported countries");
308         }
309         if (isSupported) {
310             mSupportedCountries = countriesList;
311         } else {
312             mUnsupportedCountries = countriesList;
313         }
314     }
315 
316     /**
317      * Gets the supported or unsupported countries for eUICC.
318      *
319      * <p>If {@code isSupported} is true, the supported country list will be returned. Otherwise,
320      * unsupported country list will be returned.
321      *
322      * @param isSupported should be true if caller wants to get supported country list. If
323      * isSupported is false, unsupported country list will be returned.
324      * @return a list of strings contains country ISO codes in uppercase.
325      */
326     @Override
327     @NonNull
getSupportedCountries(boolean isSupported)328     public List<String> getSupportedCountries(boolean isSupported) {
329         if (!callerCanWriteEmbeddedSubscriptions()) {
330             throw new SecurityException(
331                     "Must have WRITE_EMBEDDED_SUBSCRIPTIONS to get supported countries");
332         }
333         if (isSupported && mSupportedCountries != null) {
334             return mSupportedCountries;
335         } else if (!isSupported && mUnsupportedCountries != null) {
336             return mUnsupportedCountries;
337         }
338         return Collections.emptyList();
339     }
340 
341     /**
342      * Returns whether the given country supports eUICC.
343      *
344      * <p>Supported country list has a higher prority than unsupported country list. If the
345      * supported country list is not empty, {@code countryIso} will be considered as supported when
346      * it exists in the supported country list. Otherwise {@code countryIso} is not supported. If
347      * the supported country list is empty, {@code countryIso} will be considered as supported if it
348      * does not exist in the unsupported country list. Otherwise {@code countryIso} is not
349      * supported. If both supported and unsupported country lists are empty, then all countries are
350      * consider be supported. For how to set supported and unsupported country list, please check
351      * {@link #setSupportedCountries}.
352      *
353      * @param countryIso should be the ISO-3166 country code is provided in uppercase 2 character
354      * format.
355      * @return whether the given country supports eUICC or not.
356      */
357     @Override
isSupportedCountry(@onNull String countryIso)358     public boolean isSupportedCountry(@NonNull String countryIso) {
359         if (!callerCanWriteEmbeddedSubscriptions()) {
360             throw new SecurityException(
361                     "Must have WRITE_EMBEDDED_SUBSCRIPTIONS to check if the country is supported");
362         }
363         if (mSupportedCountries == null || mSupportedCountries.isEmpty()) {
364             Log.i(TAG, "Using deny list unsupportedCountries=" + mUnsupportedCountries);
365             return !isEsimUnsupportedCountry(countryIso);
366         } else {
367             Log.i(TAG, "Using allow list supportedCountries=" + mSupportedCountries);
368             return isEsimSupportedCountry(countryIso);
369         }
370     }
371 
isEsimSupportedCountry(String countryIso)372     private boolean isEsimSupportedCountry(String countryIso) {
373         if (mSupportedCountries == null || TextUtils.isEmpty(countryIso)) {
374             return true;
375         }
376         return mSupportedCountries.contains(countryIso);
377     }
378 
isEsimUnsupportedCountry(String countryIso)379     private boolean isEsimUnsupportedCountry(String countryIso) {
380         if (mUnsupportedCountries == null || TextUtils.isEmpty(countryIso)) {
381             return false;
382         }
383         return mUnsupportedCountries.contains(countryIso);
384     }
385 
getDownloadableSubscriptionMetadata(int cardId, DownloadableSubscription subscription, boolean forceDeactivateSim, String callingPackage, PendingIntent callbackIntent)386     void getDownloadableSubscriptionMetadata(int cardId, DownloadableSubscription subscription,
387             boolean forceDeactivateSim, String callingPackage, PendingIntent callbackIntent) {
388         if (!callerCanWriteEmbeddedSubscriptions()) {
389             throw new SecurityException("Must have WRITE_EMBEDDED_SUBSCRIPTIONS to get metadata");
390         }
391         mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage);
392         long token = Binder.clearCallingIdentity();
393         try {
394             mConnector.getDownloadableSubscriptionMetadata(cardId,
395                     subscription, forceDeactivateSim,
396                     new GetMetadataCommandCallback(
397                             token, subscription, callingPackage, callbackIntent));
398         } finally {
399             Binder.restoreCallingIdentity(token);
400         }
401     }
402 
403     class GetMetadataCommandCallback implements EuiccConnector.GetMetadataCommandCallback {
404         protected final long mCallingToken;
405         protected final DownloadableSubscription mSubscription;
406         protected final String mCallingPackage;
407         protected final PendingIntent mCallbackIntent;
408 
GetMetadataCommandCallback( long callingToken, DownloadableSubscription subscription, String callingPackage, PendingIntent callbackIntent)409         GetMetadataCommandCallback(
410                 long callingToken,
411                 DownloadableSubscription subscription,
412                 String callingPackage,
413                 PendingIntent callbackIntent) {
414             mCallingToken = callingToken;
415             mSubscription = subscription;
416             mCallingPackage = callingPackage;
417             mCallbackIntent = callbackIntent;
418         }
419 
420         @Override
onGetMetadataComplete(int cardId, GetDownloadableSubscriptionMetadataResult result)421         public void onGetMetadataComplete(int cardId,
422                 GetDownloadableSubscriptionMetadataResult result) {
423             Intent extrasIntent = new Intent();
424             final int resultCode;
425             switch (result.getResult()) {
426                 case EuiccService.RESULT_OK:
427                     resultCode = OK;
428                     extrasIntent.putExtra(
429                             EXTRA_EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTION,
430                             result.getDownloadableSubscription());
431                     break;
432                 case EuiccService.RESULT_MUST_DEACTIVATE_SIM:
433                     resultCode = RESOLVABLE_ERROR;
434                     addResolutionIntentWithPort(extrasIntent,
435                             EuiccService.ACTION_RESOLVE_DEACTIVATE_SIM,
436                             mCallingPackage,
437                             0 /* resolvableErrors */,
438                             false /* confirmationCodeRetried */,
439                             getOperationForDeactivateSim(),
440                             cardId,
441                             TelephonyManager.DEFAULT_PORT_INDEX,   false /* usePortIndex */);
442                     break;
443                 default:
444                     resultCode = ERROR;
445                     addExtrasToResultIntent(extrasIntent, result.getResult());
446                     break;
447             }
448 
449             sendResult(mCallbackIntent, resultCode, extrasIntent);
450         }
451 
452         @Override
onEuiccServiceUnavailable()453         public void onEuiccServiceUnavailable() {
454             sendResult(mCallbackIntent, ERROR, null /* extrasIntent */);
455         }
456 
getOperationForDeactivateSim()457         protected EuiccOperation getOperationForDeactivateSim() {
458             return EuiccOperation.forGetMetadataDeactivateSim(
459                     mCallingToken, mSubscription, mCallingPackage);
460         }
461     }
462 
463     @Override
downloadSubscription(int cardId, DownloadableSubscription subscription, boolean switchAfterDownload, String callingPackage, Bundle resolvedBundle, PendingIntent callbackIntent)464     public void downloadSubscription(int cardId, DownloadableSubscription subscription,
465             boolean switchAfterDownload, String callingPackage, Bundle resolvedBundle,
466             PendingIntent callbackIntent) {
467         // If switchAfterDownload is true, set portIndex as
468         // {@link android.telephony.TelephonyManager#INVALID_PORT_INDEX} to resolve the port index.
469         int portIndex = switchAfterDownload ? TelephonyManager.INVALID_PORT_INDEX
470                 : TelephonyManager.DEFAULT_PORT_INDEX;
471         downloadSubscription(cardId, portIndex, subscription,
472                 switchAfterDownload, callingPackage, false /* forceDeactivateSim */,
473                 resolvedBundle, callbackIntent);
474     }
475 
476     /**
477      * Given encoded error code described in
478      * {@link android.telephony.euicc.EuiccManager#OPERATION_SMDX_SUBJECT_REASON_CODE} decode it
479      * into SubjectCode[5.2.6.1] and ReasonCode[5.2.6.2] from GSMA (SGP.22 v2.2)
480      *
481      * @param resultCode from
482      *               {@link android.telephony.euicc.EuiccManager#OPERATION_SMDX_SUBJECT_REASON_CODE}
483      * @return a pair containing SubjectCode[5.2.6.1] and ReasonCode[5.2.6.2] from GSMA (SGP.22
484      * v2.2)
485      */
decodeSmdxSubjectAndReasonCode(int resultCode)486     Pair<String, String> decodeSmdxSubjectAndReasonCode(int resultCode) {
487         final int numOfSections = 6;
488         final int bitsPerSection = 4;
489         final int sectionMask = 0xF;
490 
491         final Stack<Integer> sections = new Stack<>();
492 
493         // Extracting each section of digits backwards.
494         for (int i = 0; i < numOfSections; ++i) {
495             int sectionDigit = resultCode & sectionMask;
496             sections.push(sectionDigit);
497             resultCode = resultCode >>> bitsPerSection;
498         }
499 
500         String subjectCode = sections.pop() + "." + sections.pop() + "." + sections.pop();
501         String reasonCode = sections.pop() + "." + sections.pop() + "." + sections.pop();
502 
503         // drop the leading zeros, e.g 0.1 -> 1, 0.0.3 -> 3, 0.5.1 -> 5.1
504         subjectCode = subjectCode.replaceAll("^(0\\.)*", "");
505         reasonCode = reasonCode.replaceAll("^(0\\.)*", "");
506 
507         return Pair.create(subjectCode, reasonCode);
508     }
509 
510     /**
511      * Add more detailed information to the resulting intent.
512      * Fields added includes(key -> value):
513      * 1. {@link EuiccManager#EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE} -> original error code
514      * 2. {@link EuiccManager#EXTRA_EMBEDDED_SUBSCRIPTION_OPERATION_CODE} ->
515      * EuiccManager.OperationCode such as {@link EuiccManager#OPERATION_DOWNLOAD}
516      * 3. if @link EuiccManager.OperationCode is not
517      * {@link EuiccManager#OPERATION_SMDX_SUBJECT_REASON_CODE}:
518      * {@link EuiccManager#EXTRA_EMBEDDED_SUBSCRIPTION_ERROR_CODE} -> @link
519      * EuiccManager.ErrorCode such as {@link EuiccManager#OPERATION_SMDX}
520      * 4. if EuiccManager.OperationCode is
521      * {@link EuiccManager#OPERATION_SMDX_SUBJECT_REASON_CODE}:
522      * a) {@link EuiccManager#EXTRA_EMBEDDED_SUBSCRIPTION_SMDX_SUBJECT_CODE} ->
523      * SubjectCode[5.2.6.1] from GSMA (SGP.22 v2.2)
524      * b) {@link EuiccManager#EXTRA_EMBEDDED_SUBSCRIPTION_SMDX_REASON_CODE} ->
525      * ReasonCode[5.2.6.2] from GSMA (SGP.22 v2.2
526      */
addExtrasToResultIntent(Intent intent, int resultCode)527     private void addExtrasToResultIntent(Intent intent, int resultCode) {
528         final int firstByteBitOffset = 24;
529         int errorCodeMask = 0xFFFFFF;
530         int operationCode = resultCode >>> firstByteBitOffset;
531 
532         intent.putExtra(
533                 EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE, resultCode);
534 
535         intent.putExtra(EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_OPERATION_CODE, operationCode);
536 
537         // check to see if the operation code is EuiccManager#OPERATION_SMDX_SUBJECT_REASON_CODE
538         final boolean isSmdxSubjectReasonCode =
539                 (operationCode == EuiccManager.OPERATION_SMDX_SUBJECT_REASON_CODE);
540 
541         if (isSmdxSubjectReasonCode) {
542             final Pair<String, String> subjectReasonCode = decodeSmdxSubjectAndReasonCode(
543                     resultCode);
544             final String subjectCode = subjectReasonCode.first;
545             final String reasonCode = subjectReasonCode.second;
546             intent.putExtra(EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_SMDX_SUBJECT_CODE,
547                     subjectCode);
548             intent.putExtra(EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_SMDX_REASON_CODE, reasonCode);
549         } else {
550             final int errorCode = resultCode & errorCodeMask;
551             intent.putExtra(EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_ERROR_CODE, errorCode);
552         }
553     }
554 
downloadSubscription(int cardId, int portIndex, DownloadableSubscription subscription, boolean switchAfterDownload, String callingPackage, boolean forceDeactivateSim, Bundle resolvedBundle, PendingIntent callbackIntent)555     void downloadSubscription(int cardId, int portIndex, DownloadableSubscription subscription,
556             boolean switchAfterDownload, String callingPackage, boolean forceDeactivateSim,
557             Bundle resolvedBundle, PendingIntent callbackIntent) {
558         boolean callerCanWriteEmbeddedSubscriptions = callerCanWriteEmbeddedSubscriptions();
559         mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage);
560         // Don't try to resolve the port index for apps which are not targeting on T for backward
561         // compatibility. instead always use default port 0.
562         boolean shouldResolvePortIndex = isCompatChangeEnabled(callingPackage,
563                 EuiccManager.SHOULD_RESOLVE_PORT_INDEX_FOR_APPS);
564 
565         long token = Binder.clearCallingIdentity();
566         try {
567             boolean isConsentNeededToResolvePortIndex = false;
568             if (switchAfterDownload && portIndex == TelephonyManager.INVALID_PORT_INDEX) {
569                 // If switchAfterDownload is true, resolve the portIndex
570                 portIndex = shouldResolvePortIndex ?
571                         getResolvedPortIndexForSubscriptionSwitch(cardId)
572                         : TelephonyManager.DEFAULT_PORT_INDEX;
573                 isConsentNeededToResolvePortIndex = (portIndex
574                         == TelephonyManager.INVALID_PORT_INDEX);
575             }
576             Log.d(TAG, " downloadSubscription cardId: " + cardId + " switchAfterDownload: "
577                     + switchAfterDownload + " portIndex: " + portIndex
578                     + " forceDeactivateSim: " + forceDeactivateSim + " callingPackage: "
579                     + callingPackage
580                     + " isConsentNeededToResolvePortIndex: " + isConsentNeededToResolvePortIndex
581                     + " shouldResolvePortIndex:" + shouldResolvePortIndex);
582             if (!isConsentNeededToResolvePortIndex && callerCanWriteEmbeddedSubscriptions) {
583                 // With WRITE_EMBEDDED_SUBSCRIPTIONS, we can skip profile-specific permission checks
584                 // and move straight to the profile download.
585                 downloadSubscriptionPrivileged(cardId, portIndex, token, subscription,
586                         switchAfterDownload, forceDeactivateSim, callingPackage, resolvedBundle,
587                         callbackIntent);
588                 return;
589             }
590 
591             // Without WRITE_EMBEDDED_SUBSCRIPTIONS, we first check whether the caller can manage
592             // subscription on the target SIM (see comments below). If yes, the caller *must* be
593             // allowlisted per the metadata of the profile to be downloaded, so check the metadata;
594             // If no, ask the user's consent before proceed.
595             // On a multi-active SIM device, if the caller can manage the active subscription on the
596             // target SIM, or there is no active subscription on the target SIM and the caller can
597             // manage any active subscription on other SIMs, we perform the download silently.
598             // Otherwise, the user must provide consent. If it's a single-active SIM device,
599             // determine whether the caller can manage the current profile; if so, we can perform
600             // the download silently; if not, the user must provide consent.
601             if (!isConsentNeededToResolvePortIndex
602                     && canManageSubscriptionOnTargetSim(cardId, callingPackage, true,
603                     portIndex)) {
604                 mConnector.getDownloadableSubscriptionMetadata(cardId, subscription,
605                     forceDeactivateSim,
606                     new DownloadSubscriptionGetMetadataCommandCallback(token, subscription,
607                         switchAfterDownload, callingPackage, forceDeactivateSim,
608                         callbackIntent, false /* withUserConsent */, portIndex));
609             } else {
610                 Log.i(TAG, "Caller can't manage subscription on target SIM or "
611                         + " User consent is required for resolving port index. "
612                         + "Ask user's consent first");
613                 Intent extrasIntent = new Intent();
614                 addResolutionIntentWithPort(extrasIntent,
615                         EuiccService.ACTION_RESOLVE_NO_PRIVILEGES,
616                         callingPackage,
617                         0 /* resolvableErrors */,
618                         false /* confirmationCodeRetried */,
619                         EuiccOperation.forDownloadNoPrivilegesOrDeactivateSimCheckMetadata(token,
620                                 subscription, switchAfterDownload, callingPackage), cardId,
621                         portIndex, switchAfterDownload /* usePortIndex */);
622                 sendResult(callbackIntent, RESOLVABLE_ERROR, extrasIntent);
623             }
624         } finally {
625             Binder.restoreCallingIdentity(token);
626         }
627     }
628 
629     class DownloadSubscriptionGetMetadataCommandCallback extends GetMetadataCommandCallback {
630         private final boolean mSwitchAfterDownload;
631         private final boolean mForceDeactivateSim;
632         private final boolean mWithUserConsent;
633         private final int mPortIndex;
634 
DownloadSubscriptionGetMetadataCommandCallback(long callingToken, DownloadableSubscription subscription, boolean switchAfterDownload, String callingPackage, boolean forceDeactivateSim, PendingIntent callbackIntent, boolean withUserConsent, int portIndex)635         DownloadSubscriptionGetMetadataCommandCallback(long callingToken,
636                 DownloadableSubscription subscription, boolean switchAfterDownload,
637                 String callingPackage, boolean forceDeactivateSim,
638                 PendingIntent callbackIntent, boolean withUserConsent, int portIndex) {
639             super(callingToken, subscription, callingPackage, callbackIntent);
640             mSwitchAfterDownload = switchAfterDownload;
641             mForceDeactivateSim = forceDeactivateSim;
642             mWithUserConsent = withUserConsent;
643             mPortIndex = portIndex;
644         }
645 
646         @Override
onGetMetadataComplete(int cardId, GetDownloadableSubscriptionMetadataResult result)647         public void onGetMetadataComplete(int cardId,
648                 GetDownloadableSubscriptionMetadataResult result) {
649             DownloadableSubscription subscription = result.getDownloadableSubscription();
650             if (mWithUserConsent) {
651                 // We won't get RESULT_MUST_DEACTIVATE_SIM for the case with user consent.
652                 if (result.getResult() != EuiccService.RESULT_OK) {
653                     // Just propagate the error as normal.
654                     super.onGetMetadataComplete(cardId, result);
655                     return;
656                 }
657 
658                 if (checkCarrierPrivilegeInMetadata(subscription, mCallingPackage)) {
659                     // Caller can download this profile. Since we already have the user's consent,
660                     // proceed to download.
661                     downloadSubscriptionPrivileged(cardId, mPortIndex,
662                             mCallingToken, subscription, mSwitchAfterDownload,  mForceDeactivateSim,
663                             mCallingPackage, null /* resolvedBundle */,
664                             mCallbackIntent);
665                 } else {
666                     Log.e(TAG, "Caller does not have carrier privilege in metadata.");
667                     sendResult(mCallbackIntent, ERROR, null /* extrasIntent */);
668                 }
669             } else { // !mWithUserConsent
670                 if (result.getResult() == EuiccService.RESULT_MUST_DEACTIVATE_SIM) {
671                     // The caller can manage the target SIM. Ask the user's consent to deactivate
672                     // the current SIM.
673                     Intent extrasIntent = new Intent();
674                     addResolutionIntentWithPort(extrasIntent,
675                             EuiccService.ACTION_RESOLVE_DEACTIVATE_SIM,
676                             mCallingPackage,
677                             0 /* resolvableErrors */,
678                             false /* confirmationCodeRetried */,
679                             EuiccOperation.forDownloadNoPrivilegesOrDeactivateSimCheckMetadata(
680                                     mCallingToken, mSubscription, mSwitchAfterDownload,
681                                     mCallingPackage),
682                             cardId,  mPortIndex,  mSwitchAfterDownload /* usePortIndex */);
683                     sendResult(mCallbackIntent, RESOLVABLE_ERROR, extrasIntent);
684                     return;
685                 }
686 
687                 if (result.getResult() != EuiccService.RESULT_OK) {
688                     // Just propagate the error as normal.
689                     super.onGetMetadataComplete(cardId, result);
690                     return;
691                 }
692 
693                 if (checkCarrierPrivilegeInMetadata(subscription, mCallingPackage)) {
694                     // Caller can download this profile per profile metadata. Also, caller can
695                     // manage the subscription on the target SIM, which is already checked.
696                     downloadSubscriptionPrivileged(cardId, mPortIndex,
697                             mCallingToken, subscription, mSwitchAfterDownload, mForceDeactivateSim,
698                             mCallingPackage, null /* resolvedBundle */,
699                             mCallbackIntent);
700                 } else {
701                     Log.e(TAG, "Caller is not permitted to download this profile per metadata");
702                     sendResult(mCallbackIntent, ERROR, null /* extrasIntent */);
703                 }
704             }
705         }
706     }
707 
708     // Already have user consent. Check metadata first before proceed to download.
downloadSubscriptionPrivilegedCheckMetadata(int cardId, int portIndex, final long callingToken, DownloadableSubscription subscription, boolean switchAfterDownload, boolean forceDeactivateSim, final String callingPackage, Bundle resolvedBundle, final PendingIntent callbackIntent)709     void downloadSubscriptionPrivilegedCheckMetadata(int cardId, int portIndex,
710             final long callingToken, DownloadableSubscription subscription,
711             boolean switchAfterDownload, boolean forceDeactivateSim, final String callingPackage,
712             Bundle resolvedBundle, final PendingIntent callbackIntent) {
713         Log.d(TAG, " downloadSubscriptionPrivilegedCheckMetadata cardId: " + cardId
714                 + " switchAfterDownload: " + switchAfterDownload + " portIndex: " + portIndex
715                 + " forceDeactivateSim: " + forceDeactivateSim);
716         mConnector.getDownloadableSubscriptionMetadata(cardId, subscription, forceDeactivateSim,
717                 new DownloadSubscriptionGetMetadataCommandCallback(callingToken, subscription,
718                         switchAfterDownload, callingPackage, forceDeactivateSim, callbackIntent,
719                         true /* withUserConsent */, portIndex));
720     }
721 
722     // Continue to download subscription without checking anything.
downloadSubscriptionPrivileged(int cardId, int portIndex, final long callingToken, DownloadableSubscription subscription, boolean switchAfterDownload, boolean forceDeactivateSim, final String callingPackage, Bundle resolvedBundle, final PendingIntent callbackIntent)723     void downloadSubscriptionPrivileged(int cardId, int portIndex, final long callingToken,
724             DownloadableSubscription subscription, boolean switchAfterDownload,
725             boolean forceDeactivateSim, final String callingPackage, Bundle resolvedBundle,
726             final PendingIntent callbackIntent) {
727         mConnector.downloadSubscription(
728                 cardId,
729                 portIndex,
730                 subscription,
731                 switchAfterDownload,
732                 forceDeactivateSim,
733                 resolvedBundle,
734                 new EuiccConnector.DownloadCommandCallback() {
735                     @Override
736                     public void onDownloadComplete(DownloadSubscriptionResult result) {
737                         Intent extrasIntent = new Intent();
738                         final int resultCode;
739                         switch (result.getResult()) {
740                             case EuiccService.RESULT_OK:
741                                 resultCode = OK;
742                                 // Now that a profile has been successfully downloaded, mark the
743                                 // eUICC as provisioned so it appears in settings UI as appropriate.
744                                 Settings.Global.putInt(
745                                         mContext.getContentResolver(),
746                                         Settings.Global.EUICC_PROVISIONED,
747                                         1);
748                                 extrasIntent.putExtra(
749                                         EXTRA_EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTION,
750                                         subscription);
751                                 if (!switchAfterDownload) {
752                                     // Since we're not switching, nothing will trigger a
753                                     // subscription list refresh on its own, so request one here.
754                                     refreshSubscriptionsAndSendResult(
755                                             callbackIntent, resultCode, extrasIntent);
756                                     return;
757                                 }
758                                 break;
759                             case EuiccService.RESULT_MUST_DEACTIVATE_SIM:
760                                 resultCode = RESOLVABLE_ERROR;
761                                 addResolutionIntentWithPort(extrasIntent,
762                                         EuiccService.ACTION_RESOLVE_DEACTIVATE_SIM,
763                                         callingPackage,
764                                         0 /* resolvableErrors */,
765                                         false /* confirmationCodeRetried */,
766                                         EuiccOperation.forDownloadDeactivateSim(
767                                                 callingToken, subscription, switchAfterDownload,
768                                                 callingPackage),
769                                         cardId,
770                                         portIndex, switchAfterDownload /* usePortIndex */);
771                                 break;
772                             case EuiccService.RESULT_RESOLVABLE_ERRORS:
773                                 // Same value as the deprecated
774                                 // {@link EuiccService#RESULT_NEED_CONFIRMATION_CODE}. For the
775                                 // deprecated case, the resolvableErrors is set as 0 in
776                                 // EuiccService.
777                                 resultCode = RESOLVABLE_ERROR;
778                                 boolean retried = false;
779                                 if (!TextUtils.isEmpty(subscription.getConfirmationCode())) {
780                                     retried = true;
781                                 }
782                                 if (result.getResolvableErrors() != 0) {
783                                     addResolutionIntentWithPort(extrasIntent,
784                                             EuiccService.ACTION_RESOLVE_RESOLVABLE_ERRORS,
785                                             callingPackage,
786                                             result.getResolvableErrors(),
787                                             retried,
788                                             EuiccOperation.forDownloadResolvableErrors(
789                                                 callingToken, subscription, switchAfterDownload,
790                                                 callingPackage, result.getResolvableErrors()),
791                                             cardId,
792                                             portIndex, switchAfterDownload /* usePortIndex */);
793                                 }  else { // Deprecated case
794                                     addResolutionIntentWithPort(extrasIntent,
795                                             EuiccService.ACTION_RESOLVE_CONFIRMATION_CODE,
796                                             callingPackage,
797                                             0 /* resolvableErrors */,
798                                             retried /* confirmationCodeRetried */,
799                                             EuiccOperation.forDownloadConfirmationCode(
800                                                 callingToken, subscription, switchAfterDownload,
801                                                 callingPackage),
802                                             cardId,
803                                             portIndex, switchAfterDownload /* usePortIndex */);
804                                 }
805                                 break;
806                             default:
807                                 resultCode = ERROR;
808 
809                                 addExtrasToResultIntent(extrasIntent, result.getResult());
810                                 break;
811                         }
812 
813                         sendResult(callbackIntent, resultCode, extrasIntent);
814                     }
815 
816                     @Override
817                     public void onEuiccServiceUnavailable() {
818                         sendResult(callbackIntent, ERROR, null /* extrasIntent */);
819                     }
820                 });
821     }
822 
823     /**
824      * Blocking call to {@link EuiccService#onGetEuiccProfileInfoList} of the eUICC with card ID
825      * {@code cardId}.
826      *
827      * <p>Does not perform permission checks as this is not an exposed API and is only used within
828      * the phone process.
829      */
blockingGetEuiccProfileInfoList(int cardId)830     public GetEuiccProfileInfoListResult blockingGetEuiccProfileInfoList(int cardId) {
831         final CountDownLatch latch = new CountDownLatch(1);
832         final AtomicReference<GetEuiccProfileInfoListResult> resultRef = new AtomicReference<>();
833         mConnector.getEuiccProfileInfoList(
834                 cardId,
835                 new EuiccConnector.GetEuiccProfileInfoListCommandCallback() {
836                     @Override
837                     public void onListComplete(GetEuiccProfileInfoListResult result) {
838                         resultRef.set(result);
839                         latch.countDown();
840                     }
841 
842                     @Override
843                     public void onEuiccServiceUnavailable() {
844                         latch.countDown();
845                     }
846                 });
847         try {
848             latch.await();
849         } catch (InterruptedException e) {
850             Log.e(TAG, "blockingGetEuiccInfoFromEuiccService got InterruptedException e: " + e);
851             Thread.currentThread().interrupt();
852         }
853         return resultRef.get();
854     }
855 
856     @Override
getDefaultDownloadableSubscriptionList(int cardId, String callingPackage, PendingIntent callbackIntent)857     public void getDefaultDownloadableSubscriptionList(int cardId,
858             String callingPackage, PendingIntent callbackIntent) {
859         getDefaultDownloadableSubscriptionList(cardId,
860                 false /* forceDeactivateSim */, callingPackage, callbackIntent);
861     }
862 
getDefaultDownloadableSubscriptionList(int cardId, boolean forceDeactivateSim, String callingPackage, PendingIntent callbackIntent)863     void getDefaultDownloadableSubscriptionList(int cardId,
864             boolean forceDeactivateSim, String callingPackage, PendingIntent callbackIntent) {
865         if (!callerCanWriteEmbeddedSubscriptions()) {
866             throw new SecurityException(
867                     "Must have WRITE_EMBEDDED_SUBSCRIPTIONS to get default list");
868         }
869         mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage);
870         long token = Binder.clearCallingIdentity();
871         try {
872             mConnector.getDefaultDownloadableSubscriptionList(cardId,
873                     forceDeactivateSim, new GetDefaultListCommandCallback(
874                             token, callingPackage, callbackIntent));
875         } finally {
876             Binder.restoreCallingIdentity(token);
877         }
878     }
879 
880     class GetDefaultListCommandCallback implements EuiccConnector.GetDefaultListCommandCallback {
881         final long mCallingToken;
882         final String mCallingPackage;
883         final PendingIntent mCallbackIntent;
884 
GetDefaultListCommandCallback(long callingToken, String callingPackage, PendingIntent callbackIntent)885         GetDefaultListCommandCallback(long callingToken, String callingPackage,
886                 PendingIntent callbackIntent) {
887             mCallingToken = callingToken;
888             mCallingPackage = callingPackage;
889             mCallbackIntent = callbackIntent;
890         }
891 
892         @Override
onGetDefaultListComplete(int cardId, GetDefaultDownloadableSubscriptionListResult result)893         public void onGetDefaultListComplete(int cardId,
894                 GetDefaultDownloadableSubscriptionListResult result) {
895             Intent extrasIntent = new Intent();
896             final int resultCode;
897             switch (result.getResult()) {
898                 case EuiccService.RESULT_OK:
899                     resultCode = OK;
900                     List<DownloadableSubscription> list = result.getDownloadableSubscriptions();
901                     if (list != null && list.size() > 0) {
902                         extrasIntent.putExtra(
903                                 EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTIONS,
904                                 list.toArray(new DownloadableSubscription[list.size()]));
905                     }
906                     break;
907                 case EuiccService.RESULT_MUST_DEACTIVATE_SIM:
908                     resultCode = RESOLVABLE_ERROR;
909                     addResolutionIntentWithPort(extrasIntent,
910                             EuiccService.ACTION_RESOLVE_DEACTIVATE_SIM,
911                             mCallingPackage,
912                             0 /* resolvableErrors */,
913                             false /* confirmationCodeRetried */,
914                             EuiccOperation.forGetDefaultListDeactivateSim(
915                                     mCallingToken, mCallingPackage),
916                             cardId,
917                             TelephonyManager.DEFAULT_PORT_INDEX, false /* usePortIndex */);
918                     break;
919                 default:
920                     resultCode = ERROR;
921                     addExtrasToResultIntent(extrasIntent, result.getResult());
922                     break;
923             }
924 
925             sendResult(mCallbackIntent, resultCode, extrasIntent);
926         }
927 
928         @Override
onEuiccServiceUnavailable()929         public void onEuiccServiceUnavailable() {
930             sendResult(mCallbackIntent, ERROR, null /* extrasIntent */);
931         }
932     }
933 
934     /**
935      * Return the {@link EuiccInfo}.
936      *
937      * <p>For API simplicity, this call blocks until completion; while it requires an IPC to load,
938      * that IPC should generally be fast, and this info shouldn't be needed in the normal course of
939      * operation.
940      */
941     @Override
getEuiccInfo(int cardId)942     public EuiccInfo getEuiccInfo(int cardId) {
943         // No permissions required as EuiccInfo is not sensitive.
944         long token = Binder.clearCallingIdentity();
945         try {
946             return blockingGetEuiccInfoFromEuiccService(cardId);
947         } finally {
948             Binder.restoreCallingIdentity(token);
949         }
950     }
951 
952     @Override
deleteSubscription(int cardId, int subscriptionId, String callingPackage, PendingIntent callbackIntent)953     public void deleteSubscription(int cardId, int subscriptionId, String callingPackage,
954             PendingIntent callbackIntent) {
955         boolean callerCanWriteEmbeddedSubscriptions = callerCanWriteEmbeddedSubscriptions();
956         mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage);
957 
958         long token = Binder.clearCallingIdentity();
959         try {
960             SubscriptionInfo sub = getSubscriptionForSubscriptionId(subscriptionId);
961             if (sub == null) {
962                 Log.e(TAG, "Cannot delete nonexistent subscription: " + subscriptionId);
963                 sendResult(callbackIntent, ERROR, null /* extrasIntent */);
964                 return;
965             }
966 
967             // For both single active SIM device and multi-active SIM device, if the caller is
968             // system or the caller manage the target subscription, we let it continue. This is
969             // because deleting subscription won't change status of any other subscriptions.
970             if (!callerCanWriteEmbeddedSubscriptions
971                     && !mSubscriptionManager.canManageSubscription(sub, callingPackage)) {
972                 Log.e(TAG, "No permissions: " + subscriptionId);
973                 sendResult(callbackIntent, ERROR, null /* extrasIntent */);
974                 return;
975             }
976 
977             deleteSubscriptionPrivileged(cardId, sub.getIccId(), callbackIntent);
978         } finally {
979             Binder.restoreCallingIdentity(token);
980         }
981     }
982 
deleteSubscriptionPrivileged(int cardId, String iccid, final PendingIntent callbackIntent)983     void deleteSubscriptionPrivileged(int cardId, String iccid,
984             final PendingIntent callbackIntent) {
985         mConnector.deleteSubscription(
986                 cardId,
987                 iccid,
988                 new EuiccConnector.DeleteCommandCallback() {
989                     @Override
990                     public void onDeleteComplete(int result) {
991                         Intent extrasIntent = new Intent();
992                         final int resultCode;
993                         switch (result) {
994                             case EuiccService.RESULT_OK:
995                                 resultCode = OK;
996                                 refreshSubscriptionsAndSendResult(
997                                         callbackIntent, resultCode, extrasIntent);
998                                 return;
999                             default:
1000                                 resultCode = ERROR;
1001                                 addExtrasToResultIntent(extrasIntent, result);
1002                                 break;
1003                         }
1004 
1005                         sendResult(callbackIntent, resultCode, extrasIntent);
1006                     }
1007 
1008                     @Override
1009                     public void onEuiccServiceUnavailable() {
1010                         sendResult(callbackIntent, ERROR, null /* extrasIntent */);
1011                     }
1012                 });
1013     }
1014 
1015     @Override
switchToSubscription(int cardId, int subscriptionId, String callingPackage, PendingIntent callbackIntent)1016     public void switchToSubscription(int cardId, int subscriptionId, String callingPackage,
1017             PendingIntent callbackIntent) {
1018         // convert PendingIntent to callback if no callback provided
1019         switchToSubscription(cardId, subscriptionId, 0, false /* forceDeactivateSim */,
1020                 callingPackage, callbackIntent, false);
1021     }
1022 
1023     @Override
switchToSubscriptionWithPort(int cardId, int subscriptionId, int portIndex, String callingPackage, PendingIntent callbackIntent)1024     public void switchToSubscriptionWithPort(int cardId, int subscriptionId, int portIndex,
1025             String callingPackage, PendingIntent callbackIntent) {
1026         switchToSubscription(cardId, subscriptionId, portIndex, false /* forceDeactivateSim */,
1027                 callingPackage, callbackIntent, true);
1028     }
1029 
switchToSubscription(int cardId, int subscriptionId, int portIndex, boolean forceDeactivateSim, String callingPackage, PendingIntent callbackIntent, boolean usePortIndex)1030     void switchToSubscription(int cardId, int subscriptionId, int portIndex,
1031             boolean forceDeactivateSim, String callingPackage, PendingIntent callbackIntent,
1032             boolean usePortIndex) {
1033         boolean callerCanWriteEmbeddedSubscriptions = callerCanWriteEmbeddedSubscriptions();
1034         mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage);
1035         // Resolve the portIndex internally if apps targeting T and beyond are calling
1036         // switchToSubscription API without portIndex.
1037         boolean shouldResolvePortIndex = isCompatChangeEnabled(callingPackage,
1038                 EuiccManager.SHOULD_RESOLVE_PORT_INDEX_FOR_APPS);
1039         Log.d(TAG, " subId: " + subscriptionId + " portIndex: " + portIndex
1040                 + " forceDeactivateSim: " + forceDeactivateSim + " usePortIndex: " + usePortIndex
1041                 + " callingPackage: " + callingPackage + " shouldResolvePortIndex: "
1042                 + shouldResolvePortIndex);
1043         long token = Binder.clearCallingIdentity();
1044         try {
1045             if (callerCanWriteEmbeddedSubscriptions) {
1046                 // Assume that if a privileged caller is calling us, we don't need to prompt the
1047                 // user about changing carriers, because the caller would only be acting in response
1048                 // to user action.
1049                 forceDeactivateSim = true;
1050             }
1051 
1052             final String iccid;
1053             boolean passConsent = false;
1054             boolean isConsentNeededToResolvePortIndex = false;
1055             if (subscriptionId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
1056                 if (!usePortIndex) {
1057                     // Resolve the portIndex internally if apps are calling switchToSubscription
1058                     // API without portIndex and subscription id is invalid.
1059                     portIndex = getResolvedPortIndexForDisableSubscription(cardId, callingPackage,
1060                             callerCanWriteEmbeddedSubscriptions);
1061                     if (portIndex == TelephonyManager.INVALID_PORT_INDEX) {
1062                         Log.e(TAG, "Disable is not permitted: no active subscription or cannot"
1063                                 + " manage subscription");
1064                         sendResult(callbackIntent, ERROR, null /* extrasIntent */);
1065                         return;
1066                     }
1067                     usePortIndex = true;
1068                 }
1069                 if (callerCanWriteEmbeddedSubscriptions
1070                         || canManageActiveSubscriptionOnTargetSim(cardId, callingPackage,
1071                         usePortIndex, portIndex)) {
1072                     passConsent = true;
1073                 } else {
1074                     Log.e(TAG, "Not permitted to switch to empty subscription");
1075                     sendResult(callbackIntent, ERROR, null /* extrasIntent */);
1076                     return;
1077                 }
1078                 iccid = null;
1079             } else {
1080                 SubscriptionInfo sub = getSubscriptionForSubscriptionId(subscriptionId);
1081                 if (sub == null) {
1082                     Log.e(TAG, "Cannot switch to nonexistent sub: " + subscriptionId);
1083                     sendResult(callbackIntent, ERROR, null /* extrasIntent */);
1084                     return;
1085                 }
1086                 if (callerCanWriteEmbeddedSubscriptions) {
1087                     passConsent = true;
1088                 } else {
1089                     if (!mSubscriptionManager.canManageSubscription(sub, callingPackage)) {
1090                         Log.e(TAG, "Not permitted to switch to sub: " + subscriptionId);
1091                         sendResult(callbackIntent, ERROR, null /* extrasIntent */);
1092                         return;
1093                     }
1094 
1095                     if (canManageSubscriptionOnTargetSim(cardId, callingPackage, usePortIndex,
1096                             portIndex)) {
1097                         passConsent = true;
1098                     }
1099                 }
1100                 iccid = sub.getIccId();
1101                 if (usePortIndex) {
1102                     boolean hasValidPortIndex = isTargetPortIndexValid(cardId, portIndex);
1103                     if (!hasValidPortIndex) {
1104                         // Return permanent error.
1105                         Log.e(TAG, "Not permitted to switch to invalid portIndex");
1106                         Intent extrasIntent = new Intent();
1107                         extrasIntent.putExtra(EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_ERROR_CODE,
1108                                 EuiccManager.ERROR_INVALID_PORT);
1109                         sendResult(callbackIntent, ERROR, extrasIntent /* extrasIntent */);
1110                         return;
1111                     }
1112                 } else {
1113                     // Resolve the portIndex internally if apps targeting T and beyond are calling
1114                     // switchToSubscription API without portIndex.
1115                     portIndex = shouldResolvePortIndex ?
1116                             getResolvedPortIndexForSubscriptionSwitch(cardId)
1117                             : TelephonyManager.DEFAULT_PORT_INDEX;
1118                     isConsentNeededToResolvePortIndex = (portIndex
1119                             == TelephonyManager.INVALID_PORT_INDEX);
1120                     usePortIndex = true;
1121                     Log.d(TAG, " Resolved portIndex: " + portIndex);
1122                 }
1123             }
1124             if (!passConsent || isConsentNeededToResolvePortIndex) {
1125                 // Switch needs consent.
1126                 Intent extrasIntent = new Intent();
1127                 addResolutionIntent(extrasIntent,
1128                         EuiccService.ACTION_RESOLVE_NO_PRIVILEGES,
1129                         callingPackage,
1130                         0 /* resolvableErrors */,
1131                         false /* confirmationCodeRetried */,
1132                         EuiccOperation.forSwitchNoPrivileges(
1133                                 token, subscriptionId, callingPackage),
1134                         cardId, portIndex, usePortIndex, subscriptionId);
1135                 sendResult(callbackIntent, RESOLVABLE_ERROR, extrasIntent);
1136                 return;
1137             }
1138 
1139             switchToSubscriptionPrivileged(cardId, portIndex, token, subscriptionId, iccid,
1140                     forceDeactivateSim, callingPackage, callbackIntent, usePortIndex);
1141         } finally {
1142             Binder.restoreCallingIdentity(token);
1143         }
1144     }
1145 
1146     /**
1147      * Returns the resolved portIndex or {@link TelephonyManager#INVALID_PORT_INDEX} if calling
1148      * cannot manage any active subscription.
1149      */
getResolvedPortIndexForDisableSubscription(int cardId, String callingPackage, boolean callerCanWriteEmbeddedSubscriptions)1150     private int getResolvedPortIndexForDisableSubscription(int cardId, String callingPackage,
1151             boolean callerCanWriteEmbeddedSubscriptions) {
1152         List<SubscriptionInfo> subInfoList = mSubscriptionManager
1153                 .getActiveSubscriptionInfoList(/* userVisibleOnly */false);
1154         if (subInfoList == null || subInfoList.size() == 0) {
1155             // No active subscription on any SIM.
1156             return TelephonyManager.INVALID_PORT_INDEX;
1157         }
1158         // Return the portIndex of the first active subscription managed by the calling app.
1159         for (SubscriptionInfo subInfo : subInfoList) {
1160             // If cardId == TelephonyManager.UNSUPPORTED_CARD_ID, we assume it does not support
1161             // multiple eSIMs. There are older multi-active SIM devices which do not implement HAL
1162             // 1.2 and if they have multiple eSIMs, we let it pass if the app can manage an active
1163             // subscription on any eSIM. That's the best we can do here.
1164             if ((cardId == TelephonyManager.UNSUPPORTED_CARD_ID || subInfo.getCardId() == cardId)
1165                     && subInfo.isEmbedded()
1166                     && (callerCanWriteEmbeddedSubscriptions
1167                     || mSubscriptionManager.canManageSubscription(subInfo, callingPackage))) {
1168                 return subInfo.getPortIndex();
1169             }
1170         }
1171         return TelephonyManager.INVALID_PORT_INDEX;
1172     }
1173 
1174     /**
1175      * Returns the resolved portIndex or {@link TelephonyManager#INVALID_PORT_INDEX} if no port
1176      * is available without user consent.
1177      */
getResolvedPortIndexForSubscriptionSwitch(int cardId)1178     private int getResolvedPortIndexForSubscriptionSwitch(int cardId) {
1179         int slotIndex = getSlotIndexFromCardId(cardId);
1180         // Euicc Slot
1181         UiccSlot slot = UiccController.getInstance().getUiccSlot(slotIndex);
1182         if (slot == null) {
1183             // Check is to make sure crash is avoided in case of slot is null.
1184             Log.d(TAG, "Switch to inactive slot, return default port index. slotIndex: "
1185                     + slotIndex);
1186             return TelephonyManager.DEFAULT_PORT_INDEX;
1187         }
1188         if (!slot.isMultipleEnabledProfileSupported()) {
1189             Log.d(TAG, "Multiple enabled profiles is not supported, return default port index");
1190             return TelephonyManager.DEFAULT_PORT_INDEX;
1191         }
1192         boolean isPsimActive = getRemovableNonEuiccSlot() != null
1193                 && getRemovableNonEuiccSlot().isActive();
1194         if (mTelephonyManager.getActiveModemCount() == 1) {
1195             // SS Mode
1196             if (isPsimActive) {
1197                 // In case of SS Mode and pSim is active, return default port index for
1198                 // two reasons.
1199                 // 1. If psim and esim share the same carrier privilege, then users wouldn't need
1200                 // to consent, the switch should be seamless.
1201                 // 2. If psim is active and empty or psim and esim doesn't share the same carrier
1202                 // privilege, then permission check dialog will be shown anyway.
1203                 return TelephonyManager.DEFAULT_PORT_INDEX;
1204             }
1205             // If esim port is active, return the active portIndex irrespective of whether port is
1206             // empty or has active subscription.
1207             for (int portIndex : slot.getPortList()) {
1208                 if (slot.isPortActive(portIndex)) {
1209                     return portIndex;
1210                 }
1211             }
1212         } else {
1213             // DSDS Mode
1214             for (int portIndex : slot.getPortList()) {
1215                 if (slot.isPortActive(portIndex)) {
1216                     SubscriptionInfo subscriptionInfo =
1217                               mSubscriptionManager.getActiveSubscriptionInfoForSimSlotIndex(
1218                                     slot.getPhoneIdFromPortIndex(portIndex));
1219                     if (subscriptionInfo == null || subscriptionInfo.isOpportunistic()) {
1220                             // If the port is active and empty/opportunistic, return the portIndex.
1221                         return portIndex;
1222                     }
1223                 }
1224             }
1225             // Check whether the pSim is active and empty
1226             boolean isPsimEmpty = isPsimActive && !isRemovalNonEuiccSlotHasActiveSubscription();
1227             if (isPsimEmpty) {
1228                 // This logic will execute only if below two conditions are true.
1229                 // 1. pSim is active and empty
1230                 // 2. eSim has active subscription
1231                 // Return the next available inactive eSim portIndex.
1232                 return getNextAvailableInActivePortIndex(slot);
1233             }
1234         }
1235         return TelephonyManager.INVALID_PORT_INDEX;
1236     }
1237 
1238     /**
1239      * Returns true if the target port index is valid.
1240      * 1. Port index is valid if it is non-negative and less than the total port count.
1241      * 2. In SS Mode, port index is invalid if the embedded slot already has an active port
1242      * with different port index than the target port index.
1243      * 3. In DSDS mode, port index is invalid if the pSim slot is active and the embedded slot
1244      * already has an active empty port with different port index than the target port index.
1245      */
isTargetPortIndexValid(int cardId, int targetPortIndex)1246     private boolean isTargetPortIndexValid(int cardId, int targetPortIndex) {
1247         if (targetPortIndex < 0) {
1248             Log.e(TAG, "Invalid portIndex: " + targetPortIndex);
1249             return false;
1250         }
1251         int slotIndex = getSlotIndexFromCardId(cardId);
1252         UiccSlot slot = UiccController.getInstance().getUiccSlot(slotIndex);
1253         if (slot == null || slot.getPortList().length == 0
1254                 || targetPortIndex >= slot.getPortList().length) {
1255             Log.e(TAG, "Invalid portIndex");
1256             return false;
1257         }
1258 
1259         if (mTelephonyManager.getActiveModemCount() == 1) {
1260             // SS Mode
1261             for (int portIndex : slot.getPortList()) {
1262                 if (slot.isPortActive(portIndex) && portIndex != targetPortIndex) {
1263                     // if there is an active esim port, should not try to enable the
1264                     // profile on other inactive port.
1265                     Log.e(TAG, "In SS Mode, slot already has active port on portIndex " + portIndex
1266                             + " , reject the switch request to portIndex " + targetPortIndex);
1267                     return false;
1268                 }
1269             }
1270         } else if (mTelephonyManager.getActiveModemCount() > 1) {
1271             // DSDS Mode
1272             // If physical slot has active subscription and eSim has active port (without active
1273             // subscription), should not try to enable the profile on other inactive port.
1274             boolean isPsimActive = isRemovalNonEuiccSlotHasActiveSubscription();
1275             if (isPsimActive) {
1276                 for (int portIndex : slot.getPortList()) {
1277                     if (slot.isPortActive(portIndex)
1278                             && mSubscriptionManager
1279                             .getActiveSubscriptionInfoForSimSlotIndex(
1280                                     slot.getPhoneIdFromPortIndex(portIndex)) == null
1281                             && portIndex != targetPortIndex) {
1282                         Log.e(TAG, "In DSDS Mode, pSim has active subscription, eSim has empty"
1283                                 + " active port on portIndex " + portIndex
1284                                 + " , reject the switch request to portIndex " + targetPortIndex);
1285                         return false;
1286                     }
1287                 }
1288             }
1289         }
1290         return true;
1291     }
1292 
getNextAvailableInActivePortIndex(UiccSlot slot)1293     private int getNextAvailableInActivePortIndex(UiccSlot slot) {
1294         if (slot != null) {
1295             for (int portIndex : slot.getPortList()) {
1296                 if (!slot.isPortActive(portIndex)) {
1297                     return portIndex;
1298                 }
1299             }
1300         }
1301         return TelephonyManager.INVALID_PORT_INDEX;
1302     }
1303 
1304     /**
1305      * Gets the slot index from the card ID.
1306      */
getSlotIndexFromCardId(int cardId)1307     private int getSlotIndexFromCardId(int cardId) {
1308         UiccSlotInfo[] slotInfos = mTelephonyManager.getUiccSlotsInfo();
1309         if (slotInfos == null || slotInfos.length == 0) {
1310             Log.e(TAG, "UiccSlotInfo is null or empty");
1311             return SubscriptionManager.INVALID_SIM_SLOT_INDEX;
1312         }
1313         String cardIdString = UiccController.getInstance().convertToCardString(cardId);
1314         for (int slotIndex = 0; slotIndex < slotInfos.length; slotIndex++) {
1315             if (slotInfos[slotIndex] == null) {
1316                 AnomalyReporter.reportAnomaly(
1317                         UUID.fromString("e9517acf-e1a1-455f-9231-1b5515a0d0eb"),
1318                         "EuiccController: Found UiccSlotInfo Null object.");
1319             }
1320             String retrievedCardId = slotInfos[slotIndex] != null
1321                     ? slotInfos[slotIndex].getCardId() : null;
1322             if (IccUtils.compareIgnoreTrailingFs(cardIdString, retrievedCardId)) {
1323                 return slotIndex;
1324             }
1325         }
1326         Log.i(TAG, "No UiccSlotInfo found for cardId: " + cardId);
1327         return SubscriptionManager.INVALID_SIM_SLOT_INDEX;
1328     }
1329 
isRemovalNonEuiccSlotHasActiveSubscription()1330     private boolean isRemovalNonEuiccSlotHasActiveSubscription() {
1331         UiccSlot uiccSlot = getRemovableNonEuiccSlot();
1332         if (uiccSlot != null) {
1333             for (int portIndex : uiccSlot.getPortList()) {
1334                 if (uiccSlot.isPortActive(portIndex)
1335                         && mSubscriptionManager.getActiveSubscriptionInfoForSimSlotIndex(
1336                                 uiccSlot.getPhoneIdFromPortIndex(portIndex)) != null) {
1337                     return true;
1338                 }
1339             }
1340         }
1341         return false;
1342     }
1343 
getRemovableNonEuiccSlot()1344     private UiccSlot getRemovableNonEuiccSlot() {
1345         UiccSlot[] uiccSlots = UiccController.getInstance().getUiccSlots();
1346         if (uiccSlots != null) {
1347             for (int i = 0; i < uiccSlots.length; i++) {
1348                 if (uiccSlots[i] != null && uiccSlots[i].isRemovable()
1349                         && !uiccSlots[i].isEuicc()) {
1350                     return uiccSlots[i];
1351                 }
1352             }
1353         }
1354         return null;
1355     }
1356 
switchToSubscriptionPrivileged(int cardId, int portIndex, final long callingToken, int subscriptionId, boolean forceDeactivateSim, final String callingPackage, final PendingIntent callbackIntent, boolean usePortIndex)1357     void switchToSubscriptionPrivileged(int cardId, int portIndex, final long callingToken,
1358             int subscriptionId, boolean forceDeactivateSim, final String callingPackage,
1359             final PendingIntent callbackIntent, boolean usePortIndex) {
1360         String iccid = null;
1361         SubscriptionInfo sub = getSubscriptionForSubscriptionId(subscriptionId);
1362         if (sub != null) {
1363             iccid = sub.getIccId();
1364         }
1365         switchToSubscriptionPrivileged(cardId, portIndex, callingToken, subscriptionId, iccid,
1366                 forceDeactivateSim, callingPackage, callbackIntent, usePortIndex);
1367     }
1368 
switchToSubscriptionPrivileged(int cardId, int portIndex, final long callingToken, int subscriptionId, @Nullable String iccid, boolean forceDeactivateSim, final String callingPackage, final PendingIntent callbackIntent, boolean usePortIndex)1369     void switchToSubscriptionPrivileged(int cardId, int portIndex, final long callingToken,
1370             int subscriptionId, @Nullable String iccid, boolean forceDeactivateSim,
1371             final String callingPackage, final PendingIntent callbackIntent, boolean usePortIndex) {
1372         mConnector.switchToSubscription(
1373                 cardId,
1374                 portIndex,
1375                 iccid,
1376                 forceDeactivateSim,
1377                 new EuiccConnector.SwitchCommandCallback() {
1378                     @Override
1379                     public void onSwitchComplete(int result) {
1380                         Intent extrasIntent = new Intent();
1381                         final int resultCode;
1382                         switch (result) {
1383                             case EuiccService.RESULT_OK:
1384                                 resultCode = OK;
1385                                 break;
1386                             case EuiccService.RESULT_MUST_DEACTIVATE_SIM:
1387                                 resultCode = RESOLVABLE_ERROR;
1388                                 addResolutionIntent(extrasIntent,
1389                                         EuiccService.ACTION_RESOLVE_DEACTIVATE_SIM,
1390                                         callingPackage,
1391                                         0 /* resolvableErrors */,
1392                                         false /* confirmationCodeRetried */,
1393                                         EuiccOperation.forSwitchDeactivateSim(
1394                                                 callingToken, subscriptionId, callingPackage),
1395                                         cardId, portIndex, usePortIndex, subscriptionId);
1396                                 break;
1397                             default:
1398                                 resultCode = ERROR;
1399                                 addExtrasToResultIntent(extrasIntent, result);
1400                                 break;
1401                         }
1402                         sendResult(callbackIntent, resultCode, extrasIntent);
1403                     }
1404 
1405                     @Override
1406                     public void onEuiccServiceUnavailable() {
1407                         sendResult(callbackIntent, ERROR, null /* extrasIntent */);
1408                     }
1409                 },
1410                 usePortIndex);
1411     }
1412 
1413     @Override
updateSubscriptionNickname(int cardId, int subscriptionId, String nickname, String callingPackage, PendingIntent callbackIntent)1414     public void updateSubscriptionNickname(int cardId, int subscriptionId, String nickname,
1415             String callingPackage, PendingIntent callbackIntent) {
1416         boolean callerCanWriteEmbeddedSubscriptions = callerCanWriteEmbeddedSubscriptions();
1417         mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage);
1418 
1419         long token = Binder.clearCallingIdentity();
1420         try {
1421             SubscriptionInfo sub = getSubscriptionForSubscriptionId(subscriptionId);
1422             if (sub == null) {
1423                 Log.e(TAG, "Cannot update nickname to nonexistent sub: " + subscriptionId);
1424                 sendResult(callbackIntent, ERROR, null /* extrasIntent */);
1425                 return;
1426             }
1427 
1428             // For both single active SIM device and multi-active SIM device, if the caller is
1429             // system or the caller can manage the target subscription, we let it continue. This is
1430             // because updating subscription nickname won't affect any other subscriptions.
1431             if (!callerCanWriteEmbeddedSubscriptions
1432                     && !mSubscriptionManager.canManageSubscription(sub, callingPackage)) {
1433                 Log.e(TAG, "No permissions: " + subscriptionId);
1434                 sendResult(callbackIntent, ERROR, null /* extrasIntent */);
1435                 return;
1436             }
1437 
1438             mConnector.updateSubscriptionNickname(cardId,
1439                     sub.getIccId(), nickname,
1440                     new EuiccConnector.UpdateNicknameCommandCallback() {
1441                         @Override
1442                         public void onUpdateNicknameComplete(int result) {
1443                             Intent extrasIntent = new Intent();
1444                             final int resultCode;
1445                             switch (result) {
1446                                 case EuiccService.RESULT_OK:
1447                                     resultCode = OK;
1448                                     refreshSubscriptionsAndSendResult(
1449                                             callbackIntent, resultCode, extrasIntent);
1450                                     return;
1451                                 default:
1452                                     resultCode = ERROR;
1453                                     addExtrasToResultIntent(extrasIntent, result);
1454                                     break;
1455                             }
1456 
1457                             sendResult(callbackIntent, resultCode, extrasIntent);
1458                         }
1459 
1460                         @Override
1461                         public void onEuiccServiceUnavailable() {
1462                             sendResult(callbackIntent, ERROR, null /* extrasIntent */);
1463                         }
1464                     });
1465         } finally {
1466             Binder.restoreCallingIdentity(token);
1467         }
1468     }
1469 
1470     @Override
eraseSubscriptions(int cardId, PendingIntent callbackIntent)1471     public void eraseSubscriptions(int cardId, PendingIntent callbackIntent) {
1472         if (!callerCanWriteEmbeddedSubscriptions()) {
1473             throw new SecurityException(
1474                     "Must have WRITE_EMBEDDED_SUBSCRIPTIONS to erase subscriptions");
1475         }
1476         long token = Binder.clearCallingIdentity();
1477         try {
1478             mConnector.eraseSubscriptions(
1479                     cardId, new EuiccConnector.EraseCommandCallback() {
1480                         @Override
1481                         public void onEraseComplete(int result) {
1482                             Intent extrasIntent = new Intent();
1483                             final int resultCode;
1484                             switch (result) {
1485                                 case EuiccService.RESULT_OK:
1486                                     resultCode = OK;
1487                                     refreshSubscriptionsAndSendResult(
1488                                             callbackIntent, resultCode, extrasIntent);
1489                                     return;
1490                                 default:
1491                                     resultCode = ERROR;
1492                                     addExtrasToResultIntent(extrasIntent, result);
1493                                     break;
1494                             }
1495 
1496                             sendResult(callbackIntent, resultCode, extrasIntent);
1497                         }
1498 
1499                         @Override
1500                         public void onEuiccServiceUnavailable() {
1501                             sendResult(callbackIntent, ERROR, null /* extrasIntent */);
1502                         }
1503                     });
1504         } finally {
1505             Binder.restoreCallingIdentity(token);
1506         }
1507     }
1508 
1509     @Override
eraseSubscriptionsWithOptions( int cardId, @ResetOption int options, PendingIntent callbackIntent)1510     public void eraseSubscriptionsWithOptions(
1511             int cardId, @ResetOption int options, PendingIntent callbackIntent) {
1512         if (!callerCanWriteEmbeddedSubscriptions()) {
1513             throw new SecurityException(
1514                     "Must have WRITE_EMBEDDED_SUBSCRIPTIONS to erase subscriptions");
1515         }
1516         long token = Binder.clearCallingIdentity();
1517         try {
1518             mConnector.eraseSubscriptionsWithOptions(
1519                     cardId, options, new EuiccConnector.EraseCommandCallback() {
1520                 @Override
1521                 public void onEraseComplete(int result) {
1522                     Intent extrasIntent = new Intent();
1523                     final int resultCode;
1524                     switch (result) {
1525                         case EuiccService.RESULT_OK:
1526                             resultCode = OK;
1527                             refreshSubscriptionsAndSendResult(
1528                                     callbackIntent, resultCode, extrasIntent);
1529                             return;
1530                         default:
1531                             resultCode = ERROR;
1532                                     addExtrasToResultIntent(extrasIntent, result);
1533                             break;
1534                     }
1535 
1536                     sendResult(callbackIntent, resultCode, extrasIntent);
1537                 }
1538 
1539                 @Override
1540                 public void onEuiccServiceUnavailable() {
1541                     sendResult(callbackIntent, ERROR, null /* extrasIntent */);
1542                 }
1543             });
1544         } finally {
1545             Binder.restoreCallingIdentity(token);
1546         }
1547     }
1548 
1549     @Override
retainSubscriptionsForFactoryReset(int cardId, PendingIntent callbackIntent)1550     public void retainSubscriptionsForFactoryReset(int cardId, PendingIntent callbackIntent) {
1551         mContext.enforceCallingPermission(Manifest.permission.MASTER_CLEAR,
1552                 "Must have MASTER_CLEAR to retain subscriptions for factory reset");
1553         long token = Binder.clearCallingIdentity();
1554         try {
1555             mConnector.retainSubscriptions(cardId,
1556                     new EuiccConnector.RetainSubscriptionsCommandCallback() {
1557                         @Override
1558                         public void onRetainSubscriptionsComplete(int result) {
1559                             Intent extrasIntent = new Intent();
1560                             final int resultCode;
1561                             switch (result) {
1562                                 case EuiccService.RESULT_OK:
1563                                     resultCode = OK;
1564                                     break;
1565                                 default:
1566                                     resultCode = ERROR;
1567                                     addExtrasToResultIntent(extrasIntent, result);
1568                                     break;
1569                             }
1570 
1571                             sendResult(callbackIntent, resultCode, extrasIntent);
1572                         }
1573 
1574                         @Override
1575                         public void onEuiccServiceUnavailable() {
1576                             sendResult(callbackIntent, ERROR, null /* extrasIntent */);
1577                         }
1578                     });
1579         } finally {
1580             Binder.restoreCallingIdentity(token);
1581         }
1582     }
1583 
1584     /** Refresh the embedded subscription list and dispatch the given result upon completion. */
1585     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
refreshSubscriptionsAndSendResult( PendingIntent callbackIntent, int resultCode, Intent extrasIntent)1586     public void refreshSubscriptionsAndSendResult(
1587             PendingIntent callbackIntent, int resultCode, Intent extrasIntent) {
1588         SubscriptionController.getInstance()
1589                 .requestEmbeddedSubscriptionInfoListRefresh(
1590                         () -> sendResult(callbackIntent, resultCode, extrasIntent));
1591     }
1592 
1593     /** Dispatch the given callback intent with the given result code and data. */
1594     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
sendResult(PendingIntent callbackIntent, int resultCode, Intent extrasIntent)1595     public void sendResult(PendingIntent callbackIntent, int resultCode, Intent extrasIntent) {
1596         try {
1597             callbackIntent.send(mContext, resultCode, extrasIntent);
1598         } catch (PendingIntent.CanceledException e) {
1599             // Caller canceled the callback; do nothing.
1600         }
1601     }
1602 
1603     /** Add a resolution intent to the given extras intent with invalid subscriptionId */
addResolutionIntentWithPort(Intent extrasIntent, String resolutionAction, String callingPackage, int resolvableErrors, boolean confirmationCodeRetried, EuiccOperation op, int cardId, int portIndex, boolean usePortIndex)1604     public void addResolutionIntentWithPort(Intent extrasIntent, String resolutionAction,
1605             String callingPackage, int resolvableErrors, boolean confirmationCodeRetried,
1606             EuiccOperation op, int cardId, int portIndex, boolean usePortIndex) {
1607         // use invalid subscriptionId in case of download/metadata flow
1608         addResolutionIntent(extrasIntent, resolutionAction, callingPackage, resolvableErrors,
1609                 confirmationCodeRetried, op, cardId, portIndex,
1610                 usePortIndex /* usePortIndex */, SubscriptionManager.INVALID_SUBSCRIPTION_ID);
1611     }
1612 
1613     /** Add a resolution intent to the given extras intent. */
1614     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
addResolutionIntent(Intent extrasIntent, String resolutionAction, String callingPackage, int resolvableErrors, boolean confirmationCodeRetried, EuiccOperation op, int cardId, int portIndex, boolean usePortIndex, int subscriptionId)1615     public void addResolutionIntent(Intent extrasIntent, String resolutionAction,
1616             String callingPackage, int resolvableErrors, boolean confirmationCodeRetried,
1617             EuiccOperation op, int cardId, int portIndex, boolean usePortIndex,
1618             int subscriptionId) {
1619         Intent intent = new Intent(EuiccManager.ACTION_RESOLVE_ERROR);
1620         intent.setPackage(RESOLUTION_ACTIVITY_PACKAGE_NAME);
1621         intent.setComponent(new ComponentName(
1622                         RESOLUTION_ACTIVITY_PACKAGE_NAME, RESOLUTION_ACTIVITY_CLASS_NAME));
1623         intent.putExtra(EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_RESOLUTION_ACTION,
1624                 resolutionAction);
1625         intent.putExtra(EuiccService.EXTRA_RESOLUTION_CALLING_PACKAGE, callingPackage);
1626         intent.putExtra(EuiccService.EXTRA_RESOLVABLE_ERRORS, resolvableErrors);
1627         intent.putExtra(EuiccService.EXTRA_RESOLUTION_CARD_ID, cardId);
1628         intent.putExtra(EuiccService.EXTRA_RESOLUTION_SUBSCRIPTION_ID, subscriptionId);
1629         intent.putExtra(EuiccService.EXTRA_RESOLUTION_PORT_INDEX, portIndex);
1630         intent.putExtra(EuiccService.EXTRA_RESOLUTION_USE_PORT_INDEX, usePortIndex);
1631         intent.putExtra(EuiccService.EXTRA_RESOLUTION_CONFIRMATION_CODE_RETRIED,
1632                 confirmationCodeRetried);
1633         intent.putExtra(EXTRA_OPERATION, op);
1634         PendingIntent resolutionIntent = PendingIntent.getActivity(
1635                 mContext,
1636                 0 /* requestCode */,
1637                 intent,
1638                 PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_MUTABLE);
1639         extrasIntent.putExtra(
1640                 EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_RESOLUTION_INTENT, resolutionIntent);
1641     }
1642 
1643     @Override
dump(FileDescriptor fd, final PrintWriter pw, String[] args)1644     public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
1645         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, "Requires DUMP");
1646         final long token = Binder.clearCallingIdentity();
1647         pw.println("===== BEGIN EUICC CLINIC =====");
1648         try {
1649             pw.println("===== EUICC CONNECTOR =====");
1650             mConnector.dump(fd, pw, args);
1651             final CountDownLatch countDownLatch = new CountDownLatch(1);
1652             mConnector.dumpEuiccService(new EuiccConnector.DumpEuiccServiceCommandCallback() {
1653                 @Override
1654                 public void onDumpEuiccServiceComplete(String logs) {
1655                     pw.println("===== EUICC SERVICE =====");
1656                     pw.println(logs);
1657                     countDownLatch.countDown();
1658                 }
1659 
1660                 @Override
1661                 public void onEuiccServiceUnavailable() {
1662                     pw.println("===== EUICC SERVICE UNAVAILABLE =====");
1663                     countDownLatch.countDown();
1664                 }
1665             });
1666 
1667             // Wait up to 5 seconds
1668             if (!countDownLatch.await(EUICC_DUMP_TIME_OUT_SECONDS, TimeUnit.SECONDS)) {
1669                 pw.println("===== EUICC SERVICE TIMEOUT =====");
1670             }
1671         } catch (InterruptedException e) {
1672             pw.println("===== EUICC SERVICE INTERRUPTED =====");
1673         } finally {
1674             pw.println("===== END EUICC CLINIC =====");
1675             Binder.restoreCallingIdentity(token);
1676         }
1677     }
1678 
1679     /**
1680      * Send broadcast {@link EuiccManager#ACTION_OTA_STATUS_CHANGED} for OTA status
1681      * changed.
1682      */
1683     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
sendOtaStatusChangedBroadcast()1684     public void sendOtaStatusChangedBroadcast() {
1685         Intent intent = new Intent(EuiccManager.ACTION_OTA_STATUS_CHANGED);
1686         ComponentInfo bestComponent = mConnector.findBestComponent(mContext.getPackageManager());
1687         if (bestComponent != null) {
1688             intent.setPackage(bestComponent.packageName);
1689         }
1690         mContext.sendBroadcast(intent, permission.WRITE_EMBEDDED_SUBSCRIPTIONS);
1691     }
1692 
1693     @Nullable
getSubscriptionForSubscriptionId(int subscriptionId)1694     private SubscriptionInfo getSubscriptionForSubscriptionId(int subscriptionId) {
1695         List<SubscriptionInfo> subs = mSubscriptionManager.getAvailableSubscriptionInfoList();
1696         int subCount = (subs != null) ? subs.size() : 0;
1697         for (int i = 0; i < subCount; i++) {
1698             SubscriptionInfo sub = subs.get(i);
1699             if (subscriptionId == sub.getSubscriptionId()) {
1700                 return sub;
1701             }
1702         }
1703         return null;
1704     }
1705 
1706     @Nullable
blockingGetEidFromEuiccService(int cardId)1707     private String blockingGetEidFromEuiccService(int cardId) {
1708         CountDownLatch latch = new CountDownLatch(1);
1709         AtomicReference<String> eidRef = new AtomicReference<>();
1710         mConnector.getEid(cardId, new EuiccConnector.GetEidCommandCallback() {
1711             @Override
1712             public void onGetEidComplete(String eid) {
1713                 eidRef.set(eid);
1714                 latch.countDown();
1715             }
1716 
1717             @Override
1718             public void onEuiccServiceUnavailable() {
1719                 latch.countDown();
1720             }
1721         });
1722         return awaitResult(latch, eidRef);
1723     }
1724 
blockingGetOtaStatusFromEuiccService(int cardId)1725     private @OtaStatus int blockingGetOtaStatusFromEuiccService(int cardId) {
1726         CountDownLatch latch = new CountDownLatch(1);
1727         AtomicReference<Integer> statusRef =
1728                 new AtomicReference<>(EuiccManager.EUICC_OTA_STATUS_UNAVAILABLE);
1729         mConnector.getOtaStatus(cardId, new EuiccConnector.GetOtaStatusCommandCallback() {
1730             @Override
1731             public void onGetOtaStatusComplete(@OtaStatus int status) {
1732                 statusRef.set(status);
1733                 latch.countDown();
1734             }
1735 
1736             @Override
1737             public void onEuiccServiceUnavailable() {
1738                 latch.countDown();
1739             }
1740         });
1741         return awaitResult(latch, statusRef);
1742     }
1743 
1744     @Nullable
blockingGetEuiccInfoFromEuiccService(int cardId)1745     private EuiccInfo blockingGetEuiccInfoFromEuiccService(int cardId) {
1746         CountDownLatch latch = new CountDownLatch(1);
1747         AtomicReference<EuiccInfo> euiccInfoRef = new AtomicReference<>();
1748         mConnector.getEuiccInfo(cardId, new EuiccConnector.GetEuiccInfoCommandCallback() {
1749             @Override
1750             public void onGetEuiccInfoComplete(EuiccInfo euiccInfo) {
1751                 euiccInfoRef.set(euiccInfo);
1752                 latch.countDown();
1753             }
1754 
1755             @Override
1756             public void onEuiccServiceUnavailable() {
1757                 latch.countDown();
1758             }
1759         });
1760         return awaitResult(latch, euiccInfoRef);
1761     }
1762 
awaitResult(CountDownLatch latch, AtomicReference<T> resultRef)1763     private static <T> T awaitResult(CountDownLatch latch, AtomicReference<T> resultRef) {
1764         try {
1765             latch.await();
1766         } catch (InterruptedException e) {
1767             Thread.currentThread().interrupt();
1768         }
1769         return resultRef.get();
1770     }
1771 
1772     // Returns whether the caller has carrier privilege on the given subscription.
checkCarrierPrivilegeInMetadata(DownloadableSubscription subscription, String callingPackage)1773     private boolean checkCarrierPrivilegeInMetadata(DownloadableSubscription subscription,
1774             String callingPackage) {
1775         UiccAccessRule[] rules = null;
1776         List<UiccAccessRule> rulesList = subscription.getAccessRules();
1777         if (rulesList != null) {
1778             rules = rulesList.toArray(new UiccAccessRule[rulesList.size()]);
1779         }
1780         if (rules == null) {
1781             Log.e(TAG, "No access rules but caller is unprivileged");
1782             return false;
1783         }
1784 
1785         final PackageInfo info;
1786         try {
1787             info = mPackageManager.getPackageInfo(callingPackage,
1788                 PackageManager.GET_SIGNING_CERTIFICATES);
1789         } catch (PackageManager.NameNotFoundException e) {
1790             Log.e(TAG, "Calling package valid but gone");
1791             return false;
1792         }
1793 
1794         for (int i = 0; i < rules.length; i++) {
1795             if (rules[i].getCarrierPrivilegeStatus(info)
1796                     == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
1797                 Log.i(TAG, "Calling package has carrier privilege to this profile");
1798                 return true;
1799             }
1800         }
1801         Log.e(TAG, "Calling package doesn't have carrier privilege to this profile");
1802         return false;
1803     }
1804 
supportMultiActiveSlots()1805     private boolean supportMultiActiveSlots() {
1806         return mTelephonyManager.getSupportedModemCount() > 1;
1807     }
1808 
1809     // Checks whether the caller can manage the active embedded subscription on the SIM with the
1810     // given cardId.
1811     // From Android T, if usePortIndex is true then should check if the calling app has carrier
1812     // privilege over the subscription on the target port index.
canManageActiveSubscriptionOnTargetSim(int cardId, String callingPackage, boolean usePortIndex, int targetPortIndex)1813     private boolean canManageActiveSubscriptionOnTargetSim(int cardId, String callingPackage,
1814             boolean usePortIndex, int targetPortIndex) {
1815         List<SubscriptionInfo> subInfoList = mSubscriptionManager
1816                 .getActiveSubscriptionInfoList(/* userVisibleOnly */false);
1817         if (subInfoList == null || subInfoList.size() == 0) {
1818             // No active subscription on any SIM.
1819             return false;
1820         }
1821         for (SubscriptionInfo subInfo : subInfoList) {
1822             // If cardId == TelephonyManager.UNSUPPORTED_CARD_ID, we assume it does not support
1823             // multiple eSIMs. There are older multi-active SIM devices which do not implement HAL
1824             // 1.2 and if they have multiple eSIMs, we let it pass if the app can manage an active
1825             // subscription on any eSIM. That's the best we can do here.
1826             if ((cardId == TelephonyManager.UNSUPPORTED_CARD_ID || subInfo.getCardId() == cardId)
1827                     && subInfo.isEmbedded()
1828                     && (!usePortIndex || subInfo.getPortIndex() == targetPortIndex)
1829                     && mSubscriptionManager.canManageSubscription(subInfo, callingPackage)) {
1830                 return true;
1831             }
1832         }
1833         return false;
1834     }
1835 
1836     // For a multi-active subscriptions phone, checks whether the caller can manage subscription on
1837     // the target SIM with the given cardId. The caller can only manage subscription on the target
1838     // SIM if it can manage the active subscription on the target SIM or there is no active
1839     // subscription on the target SIM, and the caller can manage any active subscription on any
1840     // other SIM. The target SIM should be an eUICC.
1841     // For a single-active subscription phone, checks whether the caller can manage any active
1842     // embedded subscription.
1843     // From Android T, if usePortIndex is true then verify whether the calling app has carrier
1844     // privilege over the active embedded subscription on the target port index.
1845     // If usePortIndex is false then check whether the calling app can manage any active
1846     // subscription on any of the active ports, if there are no active embedded subscriptions then
1847     // verify whether the calling app can manage any active subscription on any of the other SIM.
canManageSubscriptionOnTargetSim(int cardId, String callingPackage, boolean usePortIndex, int targetPortIndex)1848     private boolean canManageSubscriptionOnTargetSim(int cardId, String callingPackage,
1849             boolean usePortIndex, int targetPortIndex) {
1850         List<SubscriptionInfo> subInfoList = mSubscriptionManager
1851                 .getActiveSubscriptionInfoList(false /* userVisibleonly */);
1852         // No active subscription on any SIM.
1853         if (subInfoList == null || subInfoList.size() == 0) {
1854             return false;
1855         }
1856         // If it's a multi-active SIM device, we assume it's above HAL 1.2 which supports cardId.
1857         // There are older multi-active SIM devices but don't implement HAL 1.2. In this case,
1858         // platform can't even detect UiccCardInfo#isEuicc as true for eSIM, which won't let the
1859         // below check pass. That's the best we can do here.
1860         if (supportMultiActiveSlots()) {
1861             // The target card should be an eUICC.
1862             List<UiccCardInfo> cardInfos = mTelephonyManager.getUiccCardsInfo();
1863             if (cardInfos == null || cardInfos.isEmpty()) {
1864                 return false;
1865             }
1866             boolean isEuicc = false;
1867             for (UiccCardInfo info : cardInfos) {
1868                 if (info != null && info.getCardId() == cardId && info.isEuicc()) {
1869                     isEuicc = true;
1870                     break;
1871                 }
1872             }
1873             if (!isEuicc) {
1874                 Log.i(TAG, "The target SIM is not an eUICC.");
1875                 return false;
1876             }
1877 
1878             // If the caller can't manage the active embedded subscription on the target SIM port,
1879             // return false. If the caller can manage the active embedded subscription on the
1880             // target SIM port, return true directly.
1881             boolean hasActiveEmbeddedSubscription = subInfoList.stream().anyMatch(
1882                     subInfo -> subInfo.isEmbedded() && subInfo.getCardId() == cardId
1883                             && (!usePortIndex || subInfo.getPortIndex() == targetPortIndex));
1884             Log.d(TAG, "canManageSubscriptionOnTargetSim hasActiveEmbeddedSubscriptions: "
1885                     + hasActiveEmbeddedSubscription);
1886             if (hasActiveEmbeddedSubscription) {
1887                 // hasActiveEmbeddedSubscription is true if there is an active embedded subscription
1888                 // on the target port(in case of usePortIndex is true) or if there is an active
1889                 // embedded subscription on any of the active ports.
1890 
1891                 // 1. If usePortIndex is true, check whether the caller can manage subscription on
1892                 // the target port.
1893                 // 2. If usePortIndex is false, check whether the caller can manage subscription on
1894                 // any of the active ports.
1895                 for (SubscriptionInfo subInfo : subInfoList) {
1896                     // subInfo.isEmbedded() can only be true for the target SIM.
1897                     if (subInfo.isEmbedded()
1898                             && subInfo.getCardId() == cardId
1899                             && (!usePortIndex || subInfo.getPortIndex() == targetPortIndex)
1900                             && mSubscriptionManager.canManageSubscription(
1901                             subInfo, callingPackage)) {
1902                         return true;
1903                     }
1904                 }
1905                 Log.i(TAG, "canManageSubscriptionOnTargetSim cannot manage embedded subscription");
1906                 return false;
1907             }
1908             // There is no active subscription on the target SIM, checks whether the caller can
1909             // manage any active subscription on any other SIM.
1910             final long token = Binder.clearCallingIdentity();
1911             try {
1912                 return mTelephonyManager.checkCarrierPrivilegesForPackageAnyPhone(callingPackage)
1913                     == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS;
1914             } finally {
1915                 Binder.restoreCallingIdentity(token);
1916             }
1917         } else {
1918             for (SubscriptionInfo subInfo : subInfoList) {
1919                 if (subInfo.isEmbedded()
1920                         && mSubscriptionManager.canManageSubscription(subInfo, callingPackage)) {
1921                     return true;
1922                 }
1923             }
1924             return false;
1925         }
1926     }
1927 
callerCanReadPhoneStatePrivileged()1928     private boolean callerCanReadPhoneStatePrivileged() {
1929         return mContext.checkCallingOrSelfPermission(
1930                 Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
1931                 == PackageManager.PERMISSION_GRANTED;
1932     }
1933 
callerCanWriteEmbeddedSubscriptions()1934     private boolean callerCanWriteEmbeddedSubscriptions() {
1935         return mContext.checkCallingOrSelfPermission(
1936                 Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
1937                 == PackageManager.PERMISSION_GRANTED;
1938     }
1939 
1940     @Override
isSimPortAvailable(int cardId, int portIndex, String callingPackage)1941     public boolean isSimPortAvailable(int cardId, int portIndex, String callingPackage) {
1942         List<UiccCardInfo> cardInfos;
1943         final long token = Binder.clearCallingIdentity();
1944         try {
1945             cardInfos = mTelephonyManager.getUiccCardsInfo();
1946         } finally {
1947             Binder.restoreCallingIdentity(token);
1948         }
1949         for (UiccCardInfo info : cardInfos) {
1950             if (info == null || info.getCardId() != cardId) {
1951                 continue;
1952             }
1953             // Return false in case of non esim or passed port index is greater than
1954             // the available ports.
1955             if (!info.isEuicc() || (portIndex == TelephonyManager.INVALID_PORT_INDEX)
1956                     || portIndex >= info.getPorts().size()) {
1957                 return false;
1958             }
1959             for (UiccPortInfo portInfo : info.getPorts()) {
1960                 if (portInfo == null || portInfo.getPortIndex() != portIndex) {
1961                     continue;
1962                 }
1963                 // Return false if port is not active.
1964                 if (!portInfo.isActive()) {
1965                     return false;
1966                 }
1967                 // A port is available if it has no profiles enabled on it or calling app has
1968                 // Carrier privilege over the profile installed on the selected port.
1969                 if (TextUtils.isEmpty(portInfo.getIccId())) {
1970                     return true;
1971                 }
1972                 UiccPort uiccPort =
1973                         UiccController.getInstance().getUiccPortForSlot(
1974                                 info.getPhysicalSlotIndex(), portIndex);
1975                 // Some eSim Vendors return boot profile iccid if no profile is installed.
1976                 // So in this case if profile is empty, port is available.
1977                 if (uiccPort != null
1978                         && uiccPort.getUiccProfile() != null
1979                         && uiccPort.getUiccProfile().isEmptyProfile()) {
1980                     return true;
1981                 }
1982                 Phone phone = PhoneFactory.getPhone(portInfo.getLogicalSlotIndex());
1983                 if (phone == null) {
1984                     Log.e(TAG, "Invalid logical slot: " + portInfo.getLogicalSlotIndex());
1985                     return false;
1986                 }
1987                 CarrierPrivilegesTracker cpt = phone.getCarrierPrivilegesTracker();
1988                 if (cpt == null) {
1989                     Log.e(TAG, "No CarrierPrivilegesTracker");
1990                     return false;
1991                 }
1992                 return (cpt.getCarrierPrivilegeStatusForPackage(callingPackage)
1993                         == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS);
1994             }
1995         }
1996         return false;
1997     }
1998 
1999     @Override
hasCarrierPrivilegesForPackageOnAnyPhone(String callingPackage)2000     public boolean hasCarrierPrivilegesForPackageOnAnyPhone(String callingPackage) {
2001         mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage);
2002         final long token = Binder.clearCallingIdentity();
2003         try {
2004             // checkCarrierPrivilegesForPackageAnyPhone API requires READ_PHONE_STATE permission,
2005             // hence cannot call directly from EuiccManager switchToSubscription
2006             return mTelephonyManager.checkCarrierPrivilegesForPackageAnyPhone(callingPackage)
2007                     == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS;
2008         } finally {
2009             Binder.restoreCallingIdentity(token);
2010         }
2011     }
2012 
2013     @Override
isCompatChangeEnabled(String callingPackage, long changeId)2014     public boolean isCompatChangeEnabled(String callingPackage, long changeId) {
2015         mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage);
2016         // Platform compat framework kills the callingPackage app to ensure that the change
2017         // takes affect immediately. So the corresponding compat checking is moved to controller.
2018         boolean changeEnabled = CompatChanges.isChangeEnabled(changeId, callingPackage,
2019                 Binder.getCallingUserHandle());
2020         Log.i(TAG, "isCompatChangeEnabled changeId: " + changeId
2021                 + " changeEnabled: " + changeEnabled);
2022         return changeEnabled;
2023     }
2024 }
2025