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