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. */ init(Context context)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}. */ get()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 EuiccController(Context context)108 private EuiccController(Context context) { 109 this(context, new EuiccConnector(context)); 110 ServiceManager.addService("econtroller", this); 111 } 112 113 @VisibleForTesting EuiccController(Context context, EuiccConnector connector)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 continueOperation(Intent resolutionIntent, Bundle resolutionExtras)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 getEid()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 getOtaStatus()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 */ startOtaUpdatingIfNecessary()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 getDownloadableSubscriptionMetadata(DownloadableSubscription subscription, String callingPackage, PendingIntent callbackIntent)220 public void getDownloadableSubscriptionMetadata(DownloadableSubscription subscription, 221 String callingPackage, PendingIntent callbackIntent) { 222 getDownloadableSubscriptionMetadata( 223 subscription, false /* forceDeactivateSim */, callingPackage, callbackIntent); 224 } 225 getDownloadableSubscriptionMetadata(DownloadableSubscription subscription, boolean forceDeactivateSim, String callingPackage, PendingIntent callbackIntent)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 GetMetadataCommandCallback( long callingToken, DownloadableSubscription subscription, String callingPackage, PendingIntent callbackIntent)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 onGetMetadataComplete( GetDownloadableSubscriptionMetadataResult result)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 onEuiccServiceUnavailable()292 public void onEuiccServiceUnavailable() { 293 sendResult(mCallbackIntent, ERROR, null /* extrasIntent */); 294 } 295 getOperationForDeactivateSim()296 protected EuiccOperation getOperationForDeactivateSim() { 297 return EuiccOperation.forGetMetadataDeactivateSim( 298 mCallingToken, mSubscription, mCallingPackage); 299 } 300 } 301 302 @Override downloadSubscription(DownloadableSubscription subscription, boolean switchAfterDownload, String callingPackage, PendingIntent callbackIntent)303 public void downloadSubscription(DownloadableSubscription subscription, 304 boolean switchAfterDownload, String callingPackage, PendingIntent callbackIntent) { 305 downloadSubscription(subscription, switchAfterDownload, callingPackage, 306 false /* forceDeactivateSim */, callbackIntent); 307 } 308 downloadSubscription(DownloadableSubscription subscription, boolean switchAfterDownload, String callingPackage, boolean forceDeactivateSim, PendingIntent callbackIntent)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 DownloadSubscriptionGetMetadataCommandCallback(long callingToken, DownloadableSubscription subscription, boolean switchAfterDownload, String callingPackage, boolean forceDeactivateSim, PendingIntent callbackIntent)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 onGetMetadataComplete( GetDownloadableSubscriptionMetadataResult result)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 getOperationForDeactivateSim()424 protected EuiccOperation getOperationForDeactivateSim() { 425 return EuiccOperation.forDownloadDeactivateSim( 426 mCallingToken, mSubscription, mSwitchAfterDownload, mCallingPackage); 427 } 428 } 429 downloadSubscriptionPrivileged(final long callingToken, DownloadableSubscription subscription, boolean switchAfterDownload, boolean forceDeactivateSim, final String callingPackage, final PendingIntent callbackIntent)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 */ blockingGetEuiccProfileInfoList()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 getDefaultDownloadableSubscriptionList( String callingPackage, PendingIntent callbackIntent)536 public void getDefaultDownloadableSubscriptionList( 537 String callingPackage, PendingIntent callbackIntent) { 538 getDefaultDownloadableSubscriptionList( 539 false /* forceDeactivateSim */, callingPackage, callbackIntent); 540 } 541 getDefaultDownloadableSubscriptionList( boolean forceDeactivateSim, String callingPackage, PendingIntent callbackIntent)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 GetDefaultListCommandCallback(long callingToken, String callingPackage, PendingIntent callbackIntent)564 GetDefaultListCommandCallback(long callingToken, String callingPackage, 565 PendingIntent callbackIntent) { 566 mCallingToken = callingToken; 567 mCallingPackage = callingPackage; 568 mCallbackIntent = callbackIntent; 569 } 570 571 @Override onGetDefaultListComplete(GetDefaultDownloadableSubscriptionListResult result)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 onEuiccServiceUnavailable()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 getEuiccInfo()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 deleteSubscription(int subscriptionId, String callingPackage, PendingIntent callbackIntent)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 deleteSubscriptionPrivileged(String iccid, final PendingIntent callbackIntent)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 switchToSubscription(int subscriptionId, String callingPackage, PendingIntent callbackIntent)690 public void switchToSubscription(int subscriptionId, String callingPackage, 691 PendingIntent callbackIntent) { 692 switchToSubscription( 693 subscriptionId, false /* forceDeactivateSim */, callingPackage, callbackIntent); 694 } 695 switchToSubscription(int subscriptionId, boolean forceDeactivateSim, String callingPackage, PendingIntent callbackIntent)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 switchToSubscriptionPrivileged(final long callingToken, int subscriptionId, boolean forceDeactivateSim, final String callingPackage, final PendingIntent callbackIntent)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 switchToSubscriptionPrivileged(final long callingToken, int subscriptionId, @Nullable String iccid, boolean forceDeactivateSim, final String callingPackage, final PendingIntent callbackIntent)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 updateSubscriptionNickname(int subscriptionId, String nickname, PendingIntent callbackIntent)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 eraseSubscriptions(PendingIntent callbackIntent)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 retainSubscriptionsForFactoryReset(PendingIntent callbackIntent)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) refreshSubscriptionsAndSendResult( PendingIntent callbackIntent, int resultCode, Intent extrasIntent)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) sendResult(PendingIntent callbackIntent, int resultCode, Intent extrasIntent)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) addResolutionIntent(Intent extrasIntent, String resolutionAction, String callingPackage, boolean confirmationCodeRetried, EuiccOperation op)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 dump(FileDescriptor fd, PrintWriter pw, String[] args)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) sendOtaStatusChangedBroadcast()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 getSubscriptionForSubscriptionId(int subscriptionId)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 blockingGetEidFromEuiccService()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 blockingGetOtaStatusFromEuiccService()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 blockingGetEuiccInfoFromEuiccService()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 awaitResult(CountDownLatch latch, AtomicReference<T> resultRef)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 canManageActiveSubscription(String callingPackage)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 callerCanReadPhoneStatePrivileged()1092 private boolean callerCanReadPhoneStatePrivileged() { 1093 return mContext.checkCallingPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) 1094 == PackageManager.PERMISSION_GRANTED; 1095 } 1096 callerCanWriteEmbeddedSubscriptions()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 */ callerHasCarrierPrivilegesForActiveSubscription()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