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