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