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