1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.internal.telephony.euicc; 17 18 import static android.telephony.euicc.EuiccManager.EUICC_OTA_STATUS_UNAVAILABLE; 19 20 import android.Manifest; 21 import android.Manifest.permission; 22 import android.annotation.Nullable; 23 import android.app.AppOpsManager; 24 import android.app.PendingIntent; 25 import android.content.Context; 26 import android.content.Intent; 27 import android.content.pm.ComponentInfo; 28 import android.content.pm.PackageInfo; 29 import android.content.pm.PackageManager; 30 import android.os.Binder; 31 import android.os.Bundle; 32 import android.os.ServiceManager; 33 import android.provider.Settings; 34 import android.service.euicc.EuiccService; 35 import android.service.euicc.GetDefaultDownloadableSubscriptionListResult; 36 import android.service.euicc.GetDownloadableSubscriptionMetadataResult; 37 import android.service.euicc.GetEuiccProfileInfoListResult; 38 import android.telephony.SubscriptionInfo; 39 import android.telephony.SubscriptionManager; 40 import android.telephony.TelephonyManager; 41 import android.telephony.UiccAccessRule; 42 import android.telephony.euicc.DownloadableSubscription; 43 import android.telephony.euicc.EuiccInfo; 44 import android.telephony.euicc.EuiccManager; 45 import android.telephony.euicc.EuiccManager.OtaStatus; 46 import android.text.TextUtils; 47 import android.util.Log; 48 49 import com.android.internal.annotations.VisibleForTesting; 50 import com.android.internal.telephony.SubscriptionController; 51 import com.android.internal.telephony.euicc.EuiccConnector.OtaStatusChangedCallback; 52 53 import java.io.FileDescriptor; 54 import java.io.PrintWriter; 55 import java.util.List; 56 import java.util.concurrent.CountDownLatch; 57 import java.util.concurrent.atomic.AtomicReference; 58 59 /** Backing implementation of {@link android.telephony.euicc.EuiccManager}. */ 60 public class EuiccController extends IEuiccController.Stub { 61 private static final String TAG = "EuiccController"; 62 63 /** Extra set on resolution intents containing the {@link EuiccOperation}. */ 64 @VisibleForTesting 65 static final String EXTRA_OPERATION = "operation"; 66 67 // Aliases so line lengths stay short. 68 private static final int OK = EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_OK; 69 private static final int RESOLVABLE_ERROR = 70 EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR; 71 private static final int ERROR = 72 EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_ERROR; 73 private static final String EXTRA_EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTION = 74 EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTION; 75 76 private static EuiccController sInstance; 77 78 private final Context mContext; 79 private final EuiccConnector mConnector; 80 private final SubscriptionManager mSubscriptionManager; 81 private final AppOpsManager mAppOpsManager; 82 private final PackageManager mPackageManager; 83 84 /** Initialize the instance. Should only be called once. */ 85 public static EuiccController init(Context context) { 86 synchronized (EuiccController.class) { 87 if (sInstance == null) { 88 sInstance = new EuiccController(context); 89 } else { 90 Log.wtf(TAG, "init() called multiple times! sInstance = " + sInstance); 91 } 92 } 93 return sInstance; 94 } 95 96 /** Get an instance. Assumes one has already been initialized with {@link #init}. */ 97 public static EuiccController get() { 98 if (sInstance == null) { 99 synchronized (EuiccController.class) { 100 if (sInstance == null) { 101 throw new IllegalStateException("get() called before init()"); 102 } 103 } 104 } 105 return sInstance; 106 } 107 108 private EuiccController(Context context) { 109 this(context, new EuiccConnector(context)); 110 ServiceManager.addService("econtroller", this); 111 } 112 113 @VisibleForTesting 114 public EuiccController(Context context, EuiccConnector connector) { 115 mContext = context; 116 mConnector = connector; 117 mSubscriptionManager = (SubscriptionManager) 118 context.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE); 119 mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); 120 mPackageManager = context.getPackageManager(); 121 } 122 123 /** 124 * Continue an operation which failed with a user-resolvable error. 125 * 126 * <p>The implementation here makes a key assumption that the resolutionIntent has not been 127 * tampered with. This is guaranteed because: 128 * <UL> 129 * <LI>The intent is wrapped in a PendingIntent created by the phone process which is created 130 * with {@link #EXTRA_OPERATION} already present. This means that the operation cannot be 131 * overridden on the PendingIntent - a caller can only add new extras. 132 * <LI>The resolution activity is restricted by a privileged permission; unprivileged apps 133 * cannot start it directly. So the PendingIntent is the only way to start it. 134 * </UL> 135 */ 136 @Override 137 public void continueOperation(Intent resolutionIntent, Bundle resolutionExtras) { 138 if (!callerCanWriteEmbeddedSubscriptions()) { 139 throw new SecurityException( 140 "Must have WRITE_EMBEDDED_SUBSCRIPTIONS to continue operation"); 141 } 142 long token = Binder.clearCallingIdentity(); 143 try { 144 EuiccOperation op = resolutionIntent.getParcelableExtra(EXTRA_OPERATION); 145 if (op == null) { 146 throw new IllegalArgumentException("Invalid resolution intent"); 147 } 148 149 PendingIntent callbackIntent = 150 resolutionIntent.getParcelableExtra( 151 EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_RESOLUTION_CALLBACK_INTENT); 152 op.continueOperation(resolutionExtras, callbackIntent); 153 } finally { 154 Binder.restoreCallingIdentity(token); 155 } 156 } 157 158 /** 159 * Return the EID. 160 * 161 * <p>For API simplicity, this call blocks until completion; while it requires an IPC to load, 162 * that IPC should generally be fast, and the EID shouldn't be needed in the normal course of 163 * operation. 164 */ 165 @Override 166 public String getEid() { 167 if (!callerCanReadPhoneStatePrivileged() 168 && !callerHasCarrierPrivilegesForActiveSubscription()) { 169 throw new SecurityException( 170 "Must have carrier privileges on active subscription to read EID"); 171 } 172 long token = Binder.clearCallingIdentity(); 173 try { 174 return blockingGetEidFromEuiccService(); 175 } finally { 176 Binder.restoreCallingIdentity(token); 177 } 178 } 179 180 /** 181 * Return the current status of OTA update. 182 * 183 * <p>For API simplicity, this call blocks until completion; while it requires an IPC to load, 184 * that IPC should generally be fast. 185 */ 186 @Override 187 public @OtaStatus int getOtaStatus() { 188 if (!callerCanWriteEmbeddedSubscriptions()) { 189 throw new SecurityException("Must have WRITE_EMBEDDED_SUBSCRIPTIONS to get OTA status"); 190 } 191 long token = Binder.clearCallingIdentity(); 192 try { 193 return blockingGetOtaStatusFromEuiccService(); 194 } finally { 195 Binder.restoreCallingIdentity(token); 196 } 197 } 198 199 200 /** 201 * Start eUICC OTA update if current eUICC OS is not the latest one. When OTA is started or 202 * finished, the broadcast {@link EuiccManager#ACTION_OTA_STATUS_CHANGED} will be sent. 203 * 204 * This function will only be called from phone process and isn't exposed to the other apps. 205 */ 206 public void startOtaUpdatingIfNecessary() { 207 mConnector.startOtaIfNecessary( 208 new OtaStatusChangedCallback() { 209 @Override 210 public void onOtaStatusChanged(int status) { 211 sendOtaStatusChangedBroadcast(); 212 } 213 214 @Override 215 public void onEuiccServiceUnavailable() {} 216 }); 217 } 218 219 @Override 220 public void getDownloadableSubscriptionMetadata(DownloadableSubscription subscription, 221 String callingPackage, PendingIntent callbackIntent) { 222 getDownloadableSubscriptionMetadata( 223 subscription, false /* forceDeactivateSim */, callingPackage, callbackIntent); 224 } 225 226 void getDownloadableSubscriptionMetadata(DownloadableSubscription subscription, 227 boolean forceDeactivateSim, String callingPackage, PendingIntent callbackIntent) { 228 if (!callerCanWriteEmbeddedSubscriptions()) { 229 throw new SecurityException("Must have WRITE_EMBEDDED_SUBSCRIPTIONS to get metadata"); 230 } 231 mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); 232 long token = Binder.clearCallingIdentity(); 233 try { 234 mConnector.getDownloadableSubscriptionMetadata( 235 subscription, forceDeactivateSim, 236 new GetMetadataCommandCallback( 237 token, subscription, callingPackage, callbackIntent)); 238 } finally { 239 Binder.restoreCallingIdentity(token); 240 } 241 } 242 243 class GetMetadataCommandCallback implements EuiccConnector.GetMetadataCommandCallback { 244 protected final long mCallingToken; 245 protected final DownloadableSubscription mSubscription; 246 protected final String mCallingPackage; 247 protected final PendingIntent mCallbackIntent; 248 249 GetMetadataCommandCallback( 250 long callingToken, 251 DownloadableSubscription subscription, 252 String callingPackage, 253 PendingIntent callbackIntent) { 254 mCallingToken = callingToken; 255 mSubscription = subscription; 256 mCallingPackage = callingPackage; 257 mCallbackIntent = callbackIntent; 258 } 259 260 @Override 261 public void onGetMetadataComplete( 262 GetDownloadableSubscriptionMetadataResult result) { 263 Intent extrasIntent = new Intent(); 264 final int resultCode; 265 switch (result.getResult()) { 266 case EuiccService.RESULT_OK: 267 resultCode = OK; 268 extrasIntent.putExtra( 269 EXTRA_EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTION, 270 result.getDownloadableSubscription()); 271 break; 272 case EuiccService.RESULT_MUST_DEACTIVATE_SIM: 273 resultCode = RESOLVABLE_ERROR; 274 addResolutionIntent(extrasIntent, 275 EuiccService.ACTION_RESOLVE_DEACTIVATE_SIM, 276 mCallingPackage, 277 false /* confirmationCodeRetried */, 278 getOperationForDeactivateSim()); 279 break; 280 default: 281 resultCode = ERROR; 282 extrasIntent.putExtra( 283 EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE, 284 result.getResult()); 285 break; 286 } 287 288 sendResult(mCallbackIntent, resultCode, extrasIntent); 289 } 290 291 @Override 292 public void onEuiccServiceUnavailable() { 293 sendResult(mCallbackIntent, ERROR, null /* extrasIntent */); 294 } 295 296 protected EuiccOperation getOperationForDeactivateSim() { 297 return EuiccOperation.forGetMetadataDeactivateSim( 298 mCallingToken, mSubscription, mCallingPackage); 299 } 300 } 301 302 @Override 303 public void downloadSubscription(DownloadableSubscription subscription, 304 boolean switchAfterDownload, String callingPackage, PendingIntent callbackIntent) { 305 downloadSubscription(subscription, switchAfterDownload, callingPackage, 306 false /* forceDeactivateSim */, callbackIntent); 307 } 308 309 void downloadSubscription(DownloadableSubscription subscription, 310 boolean switchAfterDownload, String callingPackage, boolean forceDeactivateSim, 311 PendingIntent callbackIntent) { 312 boolean callerCanWriteEmbeddedSubscriptions = callerCanWriteEmbeddedSubscriptions(); 313 mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); 314 315 long token = Binder.clearCallingIdentity(); 316 try { 317 if (callerCanWriteEmbeddedSubscriptions) { 318 // With WRITE_EMBEDDED_SUBSCRIPTIONS, we can skip profile-specific permission checks 319 // and move straight to the profile download. 320 downloadSubscriptionPrivileged(token, subscription, switchAfterDownload, 321 forceDeactivateSim, callingPackage, callbackIntent); 322 return; 323 } 324 // Without WRITE_EMBEDDED_SUBSCRIPTIONS, the caller *must* be whitelisted per the 325 // metadata of the profile to be downloaded, so check the metadata first. 326 mConnector.getDownloadableSubscriptionMetadata(subscription, 327 forceDeactivateSim, 328 new DownloadSubscriptionGetMetadataCommandCallback(token, subscription, 329 switchAfterDownload, callingPackage, forceDeactivateSim, 330 callbackIntent)); 331 } finally { 332 Binder.restoreCallingIdentity(token); 333 } 334 } 335 336 class DownloadSubscriptionGetMetadataCommandCallback extends GetMetadataCommandCallback { 337 private final boolean mSwitchAfterDownload; 338 private final boolean mForceDeactivateSim; 339 340 DownloadSubscriptionGetMetadataCommandCallback(long callingToken, 341 DownloadableSubscription subscription, boolean switchAfterDownload, 342 String callingPackage, boolean forceDeactivateSim, 343 PendingIntent callbackIntent) { 344 super(callingToken, subscription, callingPackage, callbackIntent); 345 mSwitchAfterDownload = switchAfterDownload; 346 mForceDeactivateSim = forceDeactivateSim; 347 } 348 349 @Override 350 public void onGetMetadataComplete( 351 GetDownloadableSubscriptionMetadataResult result) { 352 if (result.getResult() == EuiccService.RESULT_MUST_DEACTIVATE_SIM) { 353 // If we need to deactivate the current SIM to even check permissions, go ahead and 354 // require that the user resolve the stronger permission dialog. 355 Intent extrasIntent = new Intent(); 356 addResolutionIntent(extrasIntent, EuiccService.ACTION_RESOLVE_NO_PRIVILEGES, 357 mCallingPackage, 358 false /* confirmationCodeRetried */, 359 EuiccOperation.forDownloadNoPrivileges( 360 mCallingToken, mSubscription, mSwitchAfterDownload, 361 mCallingPackage)); 362 sendResult(mCallbackIntent, RESOLVABLE_ERROR, extrasIntent); 363 return; 364 } 365 366 if (result.getResult() != EuiccService.RESULT_OK) { 367 // Just propagate the error as normal. 368 super.onGetMetadataComplete(result); 369 return; 370 } 371 372 DownloadableSubscription subscription = result.getDownloadableSubscription(); 373 UiccAccessRule[] rules = null; 374 List<UiccAccessRule> rulesList = subscription.getAccessRules(); 375 if (rulesList != null) { 376 rules = rulesList.toArray(new UiccAccessRule[rulesList.size()]); 377 } 378 if (rules == null) { 379 Log.e(TAG, "No access rules but caller is unprivileged"); 380 sendResult(mCallbackIntent, ERROR, null /* extrasIntent */); 381 return; 382 } 383 384 final PackageInfo info; 385 try { 386 info = mPackageManager.getPackageInfo( 387 mCallingPackage, PackageManager.GET_SIGNATURES); 388 } catch (PackageManager.NameNotFoundException e) { 389 Log.e(TAG, "Calling package valid but gone"); 390 sendResult(mCallbackIntent, ERROR, null /* extrasIntent */); 391 return; 392 } 393 394 for (int i = 0; i < rules.length; i++) { 395 if (rules[i].getCarrierPrivilegeStatus(info) 396 == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) { 397 // Caller can download this profile. Now, determine whether the caller can also 398 // manage the current profile; if so, we can perform the download silently; if 399 // not, the user must provide consent. 400 if (canManageActiveSubscription(mCallingPackage)) { 401 downloadSubscriptionPrivileged( 402 mCallingToken, subscription, mSwitchAfterDownload, 403 mForceDeactivateSim, mCallingPackage, mCallbackIntent); 404 return; 405 } 406 407 // Switch might still be permitted, but the user must consent first. 408 Intent extrasIntent = new Intent(); 409 addResolutionIntent(extrasIntent, EuiccService.ACTION_RESOLVE_NO_PRIVILEGES, 410 mCallingPackage, 411 false /* confirmationCodeRetried */, 412 EuiccOperation.forDownloadNoPrivileges( 413 mCallingToken, subscription, mSwitchAfterDownload, 414 mCallingPackage)); 415 sendResult(mCallbackIntent, RESOLVABLE_ERROR, extrasIntent); 416 return; 417 } 418 } 419 Log.e(TAG, "Caller is not permitted to download this profile"); 420 sendResult(mCallbackIntent, ERROR, null /* extrasIntent */); 421 } 422 423 @Override 424 protected EuiccOperation getOperationForDeactivateSim() { 425 return EuiccOperation.forDownloadDeactivateSim( 426 mCallingToken, mSubscription, mSwitchAfterDownload, mCallingPackage); 427 } 428 } 429 430 void downloadSubscriptionPrivileged(final long callingToken, 431 DownloadableSubscription subscription, boolean switchAfterDownload, 432 boolean forceDeactivateSim, final String callingPackage, 433 final PendingIntent callbackIntent) { 434 mConnector.downloadSubscription( 435 subscription, 436 switchAfterDownload, 437 forceDeactivateSim, 438 new EuiccConnector.DownloadCommandCallback() { 439 @Override 440 public void onDownloadComplete(int result) { 441 Intent extrasIntent = new Intent(); 442 final int resultCode; 443 switch (result) { 444 case EuiccService.RESULT_OK: 445 resultCode = OK; 446 // Now that a profile has been successfully downloaded, mark the 447 // eUICC as provisioned so it appears in settings UI as appropriate. 448 Settings.Global.putInt( 449 mContext.getContentResolver(), 450 Settings.Global.EUICC_PROVISIONED, 451 1); 452 extrasIntent.putExtra( 453 EXTRA_EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTION, 454 subscription); 455 if (!switchAfterDownload) { 456 // Since we're not switching, nothing will trigger a 457 // subscription list refresh on its own, so request one here. 458 refreshSubscriptionsAndSendResult( 459 callbackIntent, resultCode, extrasIntent); 460 return; 461 } 462 break; 463 case EuiccService.RESULT_MUST_DEACTIVATE_SIM: 464 resultCode = RESOLVABLE_ERROR; 465 addResolutionIntent(extrasIntent, 466 EuiccService.ACTION_RESOLVE_DEACTIVATE_SIM, 467 callingPackage, 468 false /* confirmationCodeRetried */, 469 EuiccOperation.forDownloadDeactivateSim( 470 callingToken, subscription, switchAfterDownload, 471 callingPackage)); 472 break; 473 case EuiccService.RESULT_NEED_CONFIRMATION_CODE: 474 resultCode = RESOLVABLE_ERROR; 475 boolean retried = false; 476 if (!TextUtils.isEmpty(subscription.getConfirmationCode())) { 477 retried = true; 478 } 479 addResolutionIntent(extrasIntent, 480 EuiccService.ACTION_RESOLVE_CONFIRMATION_CODE, 481 callingPackage, 482 retried /* confirmationCodeRetried */, 483 EuiccOperation.forDownloadConfirmationCode( 484 callingToken, subscription, switchAfterDownload, 485 callingPackage)); 486 break; 487 default: 488 resultCode = ERROR; 489 extrasIntent.putExtra( 490 EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE, 491 result); 492 break; 493 } 494 495 sendResult(callbackIntent, resultCode, extrasIntent); 496 } 497 498 @Override 499 public void onEuiccServiceUnavailable() { 500 sendResult(callbackIntent, ERROR, null /* extrasIntent */); 501 } 502 }); 503 } 504 505 /** 506 * Blocking call to {@link EuiccService#onGetEuiccProfileInfoList}. 507 * 508 * <p>Does not perform permission checks as this is not an exposed API and is only used within 509 * the phone process. 510 */ 511 public GetEuiccProfileInfoListResult blockingGetEuiccProfileInfoList() { 512 final CountDownLatch latch = new CountDownLatch(1); 513 final AtomicReference<GetEuiccProfileInfoListResult> resultRef = new AtomicReference<>(); 514 mConnector.getEuiccProfileInfoList( 515 new EuiccConnector.GetEuiccProfileInfoListCommandCallback() { 516 @Override 517 public void onListComplete(GetEuiccProfileInfoListResult result) { 518 resultRef.set(result); 519 latch.countDown(); 520 } 521 522 @Override 523 public void onEuiccServiceUnavailable() { 524 latch.countDown(); 525 } 526 }); 527 try { 528 latch.await(); 529 } catch (InterruptedException e) { 530 Thread.currentThread().interrupt(); 531 } 532 return resultRef.get(); 533 } 534 535 @Override 536 public void getDefaultDownloadableSubscriptionList( 537 String callingPackage, PendingIntent callbackIntent) { 538 getDefaultDownloadableSubscriptionList( 539 false /* forceDeactivateSim */, callingPackage, callbackIntent); 540 } 541 542 void getDefaultDownloadableSubscriptionList( 543 boolean forceDeactivateSim, String callingPackage, PendingIntent callbackIntent) { 544 if (!callerCanWriteEmbeddedSubscriptions()) { 545 throw new SecurityException( 546 "Must have WRITE_EMBEDDED_SUBSCRIPTIONS to get default list"); 547 } 548 mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); 549 long token = Binder.clearCallingIdentity(); 550 try { 551 mConnector.getDefaultDownloadableSubscriptionList( 552 forceDeactivateSim, new GetDefaultListCommandCallback( 553 token, callingPackage, callbackIntent)); 554 } finally { 555 Binder.restoreCallingIdentity(token); 556 } 557 } 558 559 class GetDefaultListCommandCallback implements EuiccConnector.GetDefaultListCommandCallback { 560 final long mCallingToken; 561 final String mCallingPackage; 562 final PendingIntent mCallbackIntent; 563 564 GetDefaultListCommandCallback(long callingToken, String callingPackage, 565 PendingIntent callbackIntent) { 566 mCallingToken = callingToken; 567 mCallingPackage = callingPackage; 568 mCallbackIntent = callbackIntent; 569 } 570 571 @Override 572 public void onGetDefaultListComplete(GetDefaultDownloadableSubscriptionListResult result) { 573 Intent extrasIntent = new Intent(); 574 final int resultCode; 575 switch (result.getResult()) { 576 case EuiccService.RESULT_OK: 577 resultCode = OK; 578 List<DownloadableSubscription> list = result.getDownloadableSubscriptions(); 579 if (list != null && list.size() > 0) { 580 extrasIntent.putExtra( 581 EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTIONS, 582 list.toArray(new DownloadableSubscription[list.size()])); 583 } 584 break; 585 case EuiccService.RESULT_MUST_DEACTIVATE_SIM: 586 resultCode = RESOLVABLE_ERROR; 587 addResolutionIntent(extrasIntent, 588 EuiccService.ACTION_RESOLVE_DEACTIVATE_SIM, 589 mCallingPackage, 590 false /* confirmationCodeRetried */, 591 EuiccOperation.forGetDefaultListDeactivateSim( 592 mCallingToken, mCallingPackage)); 593 break; 594 default: 595 resultCode = ERROR; 596 extrasIntent.putExtra( 597 EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE, 598 result.getResult()); 599 break; 600 } 601 602 sendResult(mCallbackIntent, resultCode, extrasIntent); 603 } 604 605 @Override 606 public void onEuiccServiceUnavailable() { 607 sendResult(mCallbackIntent, ERROR, null /* extrasIntent */); 608 } 609 } 610 611 /** 612 * Return the {@link EuiccInfo}. 613 * 614 * <p>For API simplicity, this call blocks until completion; while it requires an IPC to load, 615 * that IPC should generally be fast, and this info shouldn't be needed in the normal course of 616 * operation. 617 */ 618 @Override 619 public EuiccInfo getEuiccInfo() { 620 // No permissions required as EuiccInfo is not sensitive. 621 long token = Binder.clearCallingIdentity(); 622 try { 623 return blockingGetEuiccInfoFromEuiccService(); 624 } finally { 625 Binder.restoreCallingIdentity(token); 626 } 627 } 628 629 @Override 630 public void deleteSubscription(int subscriptionId, String callingPackage, 631 PendingIntent callbackIntent) { 632 boolean callerCanWriteEmbeddedSubscriptions = callerCanWriteEmbeddedSubscriptions(); 633 mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); 634 635 long token = Binder.clearCallingIdentity(); 636 try { 637 SubscriptionInfo sub = getSubscriptionForSubscriptionId(subscriptionId); 638 if (sub == null) { 639 Log.e(TAG, "Cannot delete nonexistent subscription: " + subscriptionId); 640 sendResult(callbackIntent, ERROR, null /* extrasIntent */); 641 return; 642 } 643 644 if (!callerCanWriteEmbeddedSubscriptions 645 && !sub.canManageSubscription(mContext, callingPackage)) { 646 Log.e(TAG, "No permissions: " + subscriptionId); 647 sendResult(callbackIntent, ERROR, null /* extrasIntent */); 648 return; 649 } 650 651 deleteSubscriptionPrivileged(sub.getIccId(), callbackIntent); 652 } finally { 653 Binder.restoreCallingIdentity(token); 654 } 655 } 656 657 void deleteSubscriptionPrivileged(String iccid, final PendingIntent callbackIntent) { 658 mConnector.deleteSubscription( 659 iccid, 660 new EuiccConnector.DeleteCommandCallback() { 661 @Override 662 public void onDeleteComplete(int result) { 663 Intent extrasIntent = new Intent(); 664 final int resultCode; 665 switch (result) { 666 case EuiccService.RESULT_OK: 667 resultCode = OK; 668 refreshSubscriptionsAndSendResult( 669 callbackIntent, resultCode, extrasIntent); 670 return; 671 default: 672 resultCode = ERROR; 673 extrasIntent.putExtra( 674 EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE, 675 result); 676 break; 677 } 678 679 sendResult(callbackIntent, resultCode, extrasIntent); 680 } 681 682 @Override 683 public void onEuiccServiceUnavailable() { 684 sendResult(callbackIntent, ERROR, null /* extrasIntent */); 685 } 686 }); 687 } 688 689 @Override 690 public void switchToSubscription(int subscriptionId, String callingPackage, 691 PendingIntent callbackIntent) { 692 switchToSubscription( 693 subscriptionId, false /* forceDeactivateSim */, callingPackage, callbackIntent); 694 } 695 696 void switchToSubscription(int subscriptionId, boolean forceDeactivateSim, String callingPackage, 697 PendingIntent callbackIntent) { 698 boolean callerCanWriteEmbeddedSubscriptions = callerCanWriteEmbeddedSubscriptions(); 699 mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); 700 701 long token = Binder.clearCallingIdentity(); 702 try { 703 if (callerCanWriteEmbeddedSubscriptions) { 704 // Assume that if a privileged caller is calling us, we don't need to prompt the 705 // user about changing carriers, because the caller would only be acting in response 706 // to user action. 707 forceDeactivateSim = true; 708 } 709 710 final String iccid; 711 if (subscriptionId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { 712 // Switch to "no" subscription. Only the system can do this. 713 if (!callerCanWriteEmbeddedSubscriptions) { 714 Log.e(TAG, "Not permitted to switch to empty subscription"); 715 sendResult(callbackIntent, ERROR, null /* extrasIntent */); 716 return; 717 } 718 iccid = null; 719 } else { 720 SubscriptionInfo sub = getSubscriptionForSubscriptionId(subscriptionId); 721 if (sub == null) { 722 Log.e(TAG, "Cannot switch to nonexistent subscription: " + subscriptionId); 723 sendResult(callbackIntent, ERROR, null /* extrasIntent */); 724 return; 725 } 726 if (!callerCanWriteEmbeddedSubscriptions 727 && !mSubscriptionManager.canManageSubscription(sub, callingPackage)) { 728 Log.e(TAG, "Not permitted to switch to subscription: " + subscriptionId); 729 sendResult(callbackIntent, ERROR, null /* extrasIntent */); 730 return; 731 } 732 iccid = sub.getIccId(); 733 } 734 735 if (!callerCanWriteEmbeddedSubscriptions 736 && !canManageActiveSubscription(callingPackage)) { 737 // Switch needs consent. 738 Intent extrasIntent = new Intent(); 739 addResolutionIntent(extrasIntent, 740 EuiccService.ACTION_RESOLVE_NO_PRIVILEGES, 741 callingPackage, 742 false /* confirmationCodeRetried */, 743 EuiccOperation.forSwitchNoPrivileges( 744 token, subscriptionId, callingPackage)); 745 sendResult(callbackIntent, RESOLVABLE_ERROR, extrasIntent); 746 return; 747 } 748 749 switchToSubscriptionPrivileged(token, subscriptionId, iccid, forceDeactivateSim, 750 callingPackage, callbackIntent); 751 } finally { 752 Binder.restoreCallingIdentity(token); 753 } 754 } 755 756 void switchToSubscriptionPrivileged(final long callingToken, int subscriptionId, 757 boolean forceDeactivateSim, final String callingPackage, 758 final PendingIntent callbackIntent) { 759 String iccid = null; 760 SubscriptionInfo sub = getSubscriptionForSubscriptionId(subscriptionId); 761 if (sub != null) { 762 iccid = sub.getIccId(); 763 } 764 switchToSubscriptionPrivileged(callingToken, subscriptionId, iccid, forceDeactivateSim, 765 callingPackage, callbackIntent); 766 } 767 768 void switchToSubscriptionPrivileged(final long callingToken, int subscriptionId, 769 @Nullable String iccid, boolean forceDeactivateSim, final String callingPackage, 770 final PendingIntent callbackIntent) { 771 mConnector.switchToSubscription( 772 iccid, 773 forceDeactivateSim, 774 new EuiccConnector.SwitchCommandCallback() { 775 @Override 776 public void onSwitchComplete(int result) { 777 Intent extrasIntent = new Intent(); 778 final int resultCode; 779 switch (result) { 780 case EuiccService.RESULT_OK: 781 resultCode = OK; 782 break; 783 case EuiccService.RESULT_MUST_DEACTIVATE_SIM: 784 resultCode = RESOLVABLE_ERROR; 785 addResolutionIntent(extrasIntent, 786 EuiccService.ACTION_RESOLVE_DEACTIVATE_SIM, 787 callingPackage, 788 false /* confirmationCodeRetried */, 789 EuiccOperation.forSwitchDeactivateSim( 790 callingToken, subscriptionId, callingPackage)); 791 break; 792 default: 793 resultCode = ERROR; 794 extrasIntent.putExtra( 795 EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE, 796 result); 797 break; 798 } 799 800 sendResult(callbackIntent, resultCode, extrasIntent); 801 } 802 803 @Override 804 public void onEuiccServiceUnavailable() { 805 sendResult(callbackIntent, ERROR, null /* extrasIntent */); 806 } 807 }); 808 } 809 810 @Override 811 public void updateSubscriptionNickname(int subscriptionId, String nickname, 812 PendingIntent callbackIntent) { 813 if (!callerCanWriteEmbeddedSubscriptions()) { 814 throw new SecurityException( 815 "Must have WRITE_EMBEDDED_SUBSCRIPTIONS to update nickname"); 816 } 817 long token = Binder.clearCallingIdentity(); 818 try { 819 SubscriptionInfo sub = getSubscriptionForSubscriptionId(subscriptionId); 820 if (sub == null) { 821 Log.e(TAG, "Cannot update nickname to nonexistent subscription: " + subscriptionId); 822 sendResult(callbackIntent, ERROR, null /* extrasIntent */); 823 return; 824 } 825 mConnector.updateSubscriptionNickname( 826 sub.getIccId(), nickname, 827 new EuiccConnector.UpdateNicknameCommandCallback() { 828 @Override 829 public void onUpdateNicknameComplete(int result) { 830 Intent extrasIntent = new Intent(); 831 final int resultCode; 832 switch (result) { 833 case EuiccService.RESULT_OK: 834 resultCode = OK; 835 break; 836 default: 837 resultCode = ERROR; 838 extrasIntent.putExtra( 839 EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE, 840 result); 841 break; 842 } 843 844 sendResult(callbackIntent, resultCode, extrasIntent); 845 } 846 847 @Override 848 public void onEuiccServiceUnavailable() { 849 sendResult(callbackIntent, ERROR, null /* extrasIntent */); 850 } 851 }); 852 } finally { 853 Binder.restoreCallingIdentity(token); 854 } 855 } 856 857 @Override 858 public void eraseSubscriptions(PendingIntent callbackIntent) { 859 if (!callerCanWriteEmbeddedSubscriptions()) { 860 throw new SecurityException( 861 "Must have WRITE_EMBEDDED_SUBSCRIPTIONS to erase subscriptions"); 862 } 863 long token = Binder.clearCallingIdentity(); 864 try { 865 mConnector.eraseSubscriptions(new EuiccConnector.EraseCommandCallback() { 866 @Override 867 public void onEraseComplete(int result) { 868 Intent extrasIntent = new Intent(); 869 final int resultCode; 870 switch (result) { 871 case EuiccService.RESULT_OK: 872 resultCode = OK; 873 refreshSubscriptionsAndSendResult( 874 callbackIntent, resultCode, extrasIntent); 875 return; 876 default: 877 resultCode = ERROR; 878 extrasIntent.putExtra( 879 EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE, 880 result); 881 break; 882 } 883 884 sendResult(callbackIntent, resultCode, extrasIntent); 885 } 886 887 @Override 888 public void onEuiccServiceUnavailable() { 889 sendResult(callbackIntent, ERROR, null /* extrasIntent */); 890 } 891 }); 892 } finally { 893 Binder.restoreCallingIdentity(token); 894 } 895 } 896 897 @Override 898 public void retainSubscriptionsForFactoryReset(PendingIntent callbackIntent) { 899 mContext.enforceCallingPermission(Manifest.permission.MASTER_CLEAR, 900 "Must have MASTER_CLEAR to retain subscriptions for factory reset"); 901 long token = Binder.clearCallingIdentity(); 902 try { 903 mConnector.retainSubscriptions( 904 new EuiccConnector.RetainSubscriptionsCommandCallback() { 905 @Override 906 public void onRetainSubscriptionsComplete(int result) { 907 Intent extrasIntent = new Intent(); 908 final int resultCode; 909 switch (result) { 910 case EuiccService.RESULT_OK: 911 resultCode = OK; 912 break; 913 default: 914 resultCode = ERROR; 915 extrasIntent.putExtra( 916 EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE, 917 result); 918 break; 919 } 920 921 sendResult(callbackIntent, resultCode, extrasIntent); 922 } 923 924 @Override 925 public void onEuiccServiceUnavailable() { 926 sendResult(callbackIntent, ERROR, null /* extrasIntent */); 927 } 928 }); 929 } finally { 930 Binder.restoreCallingIdentity(token); 931 } 932 } 933 934 /** Refresh the embedded subscription list and dispatch the given result upon completion. */ 935 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) 936 public void refreshSubscriptionsAndSendResult( 937 PendingIntent callbackIntent, int resultCode, Intent extrasIntent) { 938 SubscriptionController.getInstance() 939 .requestEmbeddedSubscriptionInfoListRefresh( 940 () -> sendResult(callbackIntent, resultCode, extrasIntent)); 941 } 942 943 /** Dispatch the given callback intent with the given result code and data. */ 944 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) 945 public void sendResult(PendingIntent callbackIntent, int resultCode, Intent extrasIntent) { 946 try { 947 callbackIntent.send(mContext, resultCode, extrasIntent); 948 } catch (PendingIntent.CanceledException e) { 949 // Caller canceled the callback; do nothing. 950 } 951 } 952 953 /** Add a resolution intent to the given extras intent. */ 954 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) 955 public void addResolutionIntent(Intent extrasIntent, String resolutionAction, 956 String callingPackage, boolean confirmationCodeRetried, EuiccOperation op) { 957 Intent intent = new Intent(EuiccManager.ACTION_RESOLVE_ERROR); 958 intent.putExtra(EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_RESOLUTION_ACTION, 959 resolutionAction); 960 intent.putExtra(EuiccService.EXTRA_RESOLUTION_CALLING_PACKAGE, callingPackage); 961 intent.putExtra(EuiccService.EXTRA_RESOLUTION_CONFIRMATION_CODE_RETRIED, 962 confirmationCodeRetried); 963 intent.putExtra(EXTRA_OPERATION, op); 964 PendingIntent resolutionIntent = PendingIntent.getActivity( 965 mContext, 0 /* requestCode */, intent, PendingIntent.FLAG_ONE_SHOT); 966 extrasIntent.putExtra( 967 EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_RESOLUTION_INTENT, resolutionIntent); 968 } 969 970 @Override 971 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 972 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, "Requires DUMP"); 973 final long token = Binder.clearCallingIdentity(); 974 try { 975 mConnector.dump(fd, pw, args); 976 } finally { 977 Binder.restoreCallingIdentity(token); 978 } 979 } 980 981 /** 982 * Send broadcast {@link EuiccManager#ACTION_OTA_STATUS_CHANGED} for OTA status 983 * changed. 984 */ 985 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) 986 public void sendOtaStatusChangedBroadcast() { 987 Intent intent = new Intent(EuiccManager.ACTION_OTA_STATUS_CHANGED); 988 ComponentInfo bestComponent = mConnector.findBestComponent(mContext.getPackageManager()); 989 if (bestComponent != null) { 990 intent.setPackage(bestComponent.packageName); 991 } 992 mContext.sendBroadcast(intent, permission.WRITE_EMBEDDED_SUBSCRIPTIONS); 993 } 994 995 @Nullable 996 private SubscriptionInfo getSubscriptionForSubscriptionId(int subscriptionId) { 997 List<SubscriptionInfo> subs = mSubscriptionManager.getAvailableSubscriptionInfoList(); 998 int subCount = subs.size(); 999 for (int i = 0; i < subCount; i++) { 1000 SubscriptionInfo sub = subs.get(i); 1001 if (subscriptionId == sub.getSubscriptionId()) { 1002 return sub; 1003 } 1004 } 1005 return null; 1006 } 1007 1008 @Nullable 1009 private String blockingGetEidFromEuiccService() { 1010 CountDownLatch latch = new CountDownLatch(1); 1011 AtomicReference<String> eidRef = new AtomicReference<>(); 1012 mConnector.getEid(new EuiccConnector.GetEidCommandCallback() { 1013 @Override 1014 public void onGetEidComplete(String eid) { 1015 eidRef.set(eid); 1016 latch.countDown(); 1017 } 1018 1019 @Override 1020 public void onEuiccServiceUnavailable() { 1021 latch.countDown(); 1022 } 1023 }); 1024 return awaitResult(latch, eidRef); 1025 } 1026 1027 private @OtaStatus int blockingGetOtaStatusFromEuiccService() { 1028 CountDownLatch latch = new CountDownLatch(1); 1029 AtomicReference<Integer> statusRef = 1030 new AtomicReference<>(EUICC_OTA_STATUS_UNAVAILABLE); 1031 mConnector.getOtaStatus(new EuiccConnector.GetOtaStatusCommandCallback() { 1032 @Override 1033 public void onGetOtaStatusComplete(@OtaStatus int status) { 1034 statusRef.set(status); 1035 latch.countDown(); 1036 } 1037 1038 @Override 1039 public void onEuiccServiceUnavailable() { 1040 latch.countDown(); 1041 } 1042 }); 1043 return awaitResult(latch, statusRef); 1044 } 1045 1046 @Nullable 1047 private EuiccInfo blockingGetEuiccInfoFromEuiccService() { 1048 CountDownLatch latch = new CountDownLatch(1); 1049 AtomicReference<EuiccInfo> euiccInfoRef = new AtomicReference<>(); 1050 mConnector.getEuiccInfo(new EuiccConnector.GetEuiccInfoCommandCallback() { 1051 @Override 1052 public void onGetEuiccInfoComplete(EuiccInfo euiccInfo) { 1053 euiccInfoRef.set(euiccInfo); 1054 latch.countDown(); 1055 } 1056 1057 @Override 1058 public void onEuiccServiceUnavailable() { 1059 latch.countDown(); 1060 } 1061 }); 1062 return awaitResult(latch, euiccInfoRef); 1063 } 1064 1065 private static <T> T awaitResult(CountDownLatch latch, AtomicReference<T> resultRef) { 1066 try { 1067 latch.await(); 1068 } catch (InterruptedException e) { 1069 Thread.currentThread().interrupt(); 1070 } 1071 return resultRef.get(); 1072 } 1073 1074 private boolean canManageActiveSubscription(String callingPackage) { 1075 // TODO(b/36260308): We should plumb a slot ID through here for multi-SIM devices. 1076 List<SubscriptionInfo> subInfoList = mSubscriptionManager.getActiveSubscriptionInfoList(); 1077 if (subInfoList == null) { 1078 return false; 1079 } 1080 int size = subInfoList.size(); 1081 for (int subIndex = 0; subIndex < size; subIndex++) { 1082 SubscriptionInfo subInfo = subInfoList.get(subIndex); 1083 1084 if (subInfo.isEmbedded() 1085 && mSubscriptionManager.canManageSubscription(subInfo, callingPackage)) { 1086 return true; 1087 } 1088 } 1089 return false; 1090 } 1091 1092 private boolean callerCanReadPhoneStatePrivileged() { 1093 return mContext.checkCallingPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) 1094 == PackageManager.PERMISSION_GRANTED; 1095 } 1096 1097 private boolean callerCanWriteEmbeddedSubscriptions() { 1098 return mContext.checkCallingPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) 1099 == PackageManager.PERMISSION_GRANTED; 1100 } 1101 1102 /** 1103 * Returns whether the caller has carrier privileges for the active mSubscription on this eUICC. 1104 */ 1105 private boolean callerHasCarrierPrivilegesForActiveSubscription() { 1106 // TODO(b/36260308): We should plumb a slot ID through here for multi-SIM devices. 1107 TelephonyManager tm = 1108 (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE); 1109 return tm.hasCarrierPrivileges(); 1110 } 1111 } 1112