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