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