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 android.service.euicc; 17 18 import static android.telephony.euicc.EuiccCardManager.ResetOption; 19 20 import android.annotation.CallSuper; 21 import android.annotation.IntDef; 22 import android.annotation.NonNull; 23 import android.annotation.Nullable; 24 import android.annotation.SdkConstant; 25 import android.annotation.SystemApi; 26 import android.app.PendingIntent; 27 import android.app.Service; 28 import android.content.Intent; 29 import android.os.Bundle; 30 import android.os.IBinder; 31 import android.os.RemoteException; 32 import android.telephony.euicc.DownloadableSubscription; 33 import android.telephony.euicc.EuiccInfo; 34 import android.telephony.euicc.EuiccManager; 35 import android.telephony.euicc.EuiccManager.OtaStatus; 36 import android.text.TextUtils; 37 import android.util.Log; 38 39 import java.io.PrintWriter; 40 import java.io.StringWriter; 41 import java.lang.annotation.Retention; 42 import java.lang.annotation.RetentionPolicy; 43 import java.util.concurrent.LinkedBlockingQueue; 44 import java.util.concurrent.ThreadFactory; 45 import java.util.concurrent.ThreadPoolExecutor; 46 import java.util.concurrent.TimeUnit; 47 import java.util.concurrent.atomic.AtomicInteger; 48 49 /** 50 * Service interface linking the system with an eUICC local profile assistant (LPA) application. 51 * 52 * <p>An LPA consists of two separate components (which may both be implemented in the same APK): 53 * the LPA backend, and the LPA UI or LUI. 54 * 55 * <p>To implement the LPA backend, you must extend this class and declare this service in your 56 * manifest file. The service must require the 57 * {@link android.Manifest.permission#BIND_EUICC_SERVICE} permission and include an intent filter 58 * with the {@link #EUICC_SERVICE_INTERFACE} action. It's suggested that the priority of the intent 59 * filter to be set to a non-zero value in case multiple implementations are present on the device. 60 * See the below example. Note that there will be problem if two LPAs are present and they have the 61 * same priority. 62 * Example: 63 * 64 * <pre>{@code 65 * <service android:name=".MyEuiccService" 66 * android:permission="android.permission.BIND_EUICC_SERVICE"> 67 * <intent-filter android:priority="100"> 68 * <action android:name="android.service.euicc.EuiccService" /> 69 * </intent-filter> 70 * </service> 71 * }</pre> 72 * 73 * <p>To implement the LUI, you must provide an activity for the following actions: 74 * 75 * <ul> 76 * <li>{@link #ACTION_MANAGE_EMBEDDED_SUBSCRIPTIONS} 77 * <li>{@link #ACTION_PROVISION_EMBEDDED_SUBSCRIPTION} 78 * </ul> 79 * 80 * <p>As with the service, each activity must require the 81 * {@link android.Manifest.permission#BIND_EUICC_SERVICE} permission. Each should have an intent 82 * filter with the appropriate action, the {@link #CATEGORY_EUICC_UI} category, and a non-zero 83 * priority. 84 * 85 * <p>Old implementations of EuiccService may support passing in slot IDs equal to 86 * {@link android.telephony.SubscriptionManager#INVALID_SIM_SLOT_INDEX}, which allows the LPA to 87 * decide which eUICC to target when there are multiple eUICCs. This behavior is not supported in 88 * Android Q or later. 89 * 90 * @hide 91 */ 92 @SystemApi 93 public abstract class EuiccService extends Service { 94 private static final String TAG = "EuiccService"; 95 96 /** Action which must be included in this service's intent filter. */ 97 public static final String EUICC_SERVICE_INTERFACE = "android.service.euicc.EuiccService"; 98 99 /** Category which must be defined to all UI actions, for efficient lookup. */ 100 public static final String CATEGORY_EUICC_UI = "android.service.euicc.category.EUICC_UI"; 101 102 // LUI actions. These are passthroughs of the corresponding EuiccManager actions. 103 104 /** 105 * Action used to bind the carrier app and get the activation code from the carrier app. This 106 * activation code will be used to download the eSIM profile during eSIM activation flow. 107 */ 108 public static final String ACTION_BIND_CARRIER_PROVISIONING_SERVICE = 109 "android.service.euicc.action.BIND_CARRIER_PROVISIONING_SERVICE"; 110 111 /** 112 * Intent action sent by the LPA to launch a carrier app Activity for eSIM activation, e.g. a 113 * carrier login screen. Carrier apps wishing to support this activation method must implement 114 * an Activity that responds to this intent action. Upon completion, the Activity must return 115 * one of the following results to the LPA: 116 * 117 * <p>{@code Activity.RESULT_CANCELED}: The LPA should treat this as an back button and abort 118 * the activation flow. 119 * <p>{@code Activity.RESULT_OK}: The LPA should try to get an activation code from the carrier 120 * app by binding to the carrier app service implementing 121 * {@link #ACTION_BIND_CARRIER_PROVISIONING_SERVICE}. 122 * <p>{@code Activity.RESULT_OK} with 123 * {@link android.telephony.euicc.EuiccManager#EXTRA_USE_QR_SCANNER} set to true: The LPA should 124 * start a QR scanner for the user to scan an eSIM profile QR code. 125 * <p>For other results: The LPA should treat this as an error. 126 **/ 127 @SdkConstant(SdkConstant.SdkConstantType.ACTIVITY_INTENT_ACTION) 128 public static final String ACTION_START_CARRIER_ACTIVATION = 129 "android.service.euicc.action.START_CARRIER_ACTIVATION"; 130 131 /** 132 * @see android.telephony.euicc.EuiccManager#ACTION_MANAGE_EMBEDDED_SUBSCRIPTIONS 133 * The difference is this one is used by system to bring up the LUI. 134 */ 135 public static final String ACTION_MANAGE_EMBEDDED_SUBSCRIPTIONS = 136 "android.service.euicc.action.MANAGE_EMBEDDED_SUBSCRIPTIONS"; 137 138 /** @see android.telephony.euicc.EuiccManager#ACTION_PROVISION_EMBEDDED_SUBSCRIPTION */ 139 public static final String ACTION_PROVISION_EMBEDDED_SUBSCRIPTION = 140 "android.service.euicc.action.PROVISION_EMBEDDED_SUBSCRIPTION"; 141 142 /** 143 * @see android.telephony.euicc.EuiccManager#ACTION_TOGGLE_SUBSCRIPTION_PRIVILEGED. This is 144 * a protected intent that can only be sent by the system, and requires the 145 * {@link android.Manifest.permission#BIND_EUICC_SERVICE} permission. 146 */ 147 public static final String ACTION_TOGGLE_SUBSCRIPTION_PRIVILEGED = 148 "android.service.euicc.action.TOGGLE_SUBSCRIPTION_PRIVILEGED"; 149 150 /** 151 * @see android.telephony.euicc.EuiccManager#ACTION_DELETE_SUBSCRIPTION_PRIVILEGED. This is 152 * a protected intent that can only be sent by the system, and requires the 153 * {@link android.Manifest.permission#BIND_EUICC_SERVICE} permission. 154 */ 155 public static final String ACTION_DELETE_SUBSCRIPTION_PRIVILEGED = 156 "android.service.euicc.action.DELETE_SUBSCRIPTION_PRIVILEGED"; 157 158 /** 159 * @see android.telephony.euicc.EuiccManager#ACTION_RENAME_SUBSCRIPTION_PRIVILEGED. This is 160 * a protected intent that can only be sent by the system, and requires the 161 * {@link android.Manifest.permission#BIND_EUICC_SERVICE} permission. 162 */ 163 public static final String ACTION_RENAME_SUBSCRIPTION_PRIVILEGED = 164 "android.service.euicc.action.RENAME_SUBSCRIPTION_PRIVILEGED"; 165 166 /** 167 * @see android.telephony.euicc.EuiccManager#ACTION_START_EUICC_ACTIVATION. This is 168 * a protected intent that can only be sent by the system, and requires the 169 * {@link android.Manifest.permission#BIND_EUICC_SERVICE} permission. 170 */ 171 @SdkConstant(SdkConstant.SdkConstantType.ACTIVITY_INTENT_ACTION) 172 public static final String ACTION_START_EUICC_ACTIVATION = 173 "android.service.euicc.action.START_EUICC_ACTIVATION"; 174 175 // LUI resolution actions. These are called by the platform to resolve errors in situations that 176 // require user interaction. 177 // TODO(b/33075886): Define extras for any input parameters to these dialogs once they are 178 // more scoped out. 179 /** 180 * Alert the user that this action will result in an active SIM being deactivated. 181 * To implement the LUI triggered by the system, you need to define this in AndroidManifest.xml. 182 */ 183 public static final String ACTION_RESOLVE_DEACTIVATE_SIM = 184 "android.service.euicc.action.RESOLVE_DEACTIVATE_SIM"; 185 /** 186 * Alert the user about a download/switch being done for an app that doesn't currently have 187 * carrier privileges. 188 */ 189 public static final String ACTION_RESOLVE_NO_PRIVILEGES = 190 "android.service.euicc.action.RESOLVE_NO_PRIVILEGES"; 191 192 /** 193 * Ask the user to input carrier confirmation code. 194 * 195 * @deprecated From Q, the resolvable errors happened in the download step are presented as 196 * bit map in {@link #EXTRA_RESOLVABLE_ERRORS}. The corresponding action would be 197 * {@link #ACTION_RESOLVE_RESOLVABLE_ERRORS}. 198 */ 199 @Deprecated 200 public static final String ACTION_RESOLVE_CONFIRMATION_CODE = 201 "android.service.euicc.action.RESOLVE_CONFIRMATION_CODE"; 202 203 /** Ask the user to resolve all the resolvable errors. */ 204 public static final String ACTION_RESOLVE_RESOLVABLE_ERRORS = 205 "android.service.euicc.action.RESOLVE_RESOLVABLE_ERRORS"; 206 207 /** @hide */ 208 @Retention(RetentionPolicy.SOURCE) 209 @IntDef(flag = true, prefix = { "RESOLVABLE_ERROR_" }, value = { 210 RESOLVABLE_ERROR_CONFIRMATION_CODE, 211 RESOLVABLE_ERROR_POLICY_RULES, 212 }) 213 public @interface ResolvableError {} 214 215 /** 216 * Possible value for the bit map of resolvable errors indicating the download process needs 217 * the user to input confirmation code. 218 */ 219 public static final int RESOLVABLE_ERROR_CONFIRMATION_CODE = 1 << 0; 220 /** 221 * Possible value for the bit map of resolvable errors indicating the download process needs 222 * the user's consent to allow profile policy rules. 223 */ 224 public static final int RESOLVABLE_ERROR_POLICY_RULES = 1 << 1; 225 226 /** 227 * Intent extra set for resolution requests containing the package name of the calling app. 228 * This is used by the above actions including ACTION_RESOLVE_DEACTIVATE_SIM, 229 * ACTION_RESOLVE_NO_PRIVILEGES and ACTION_RESOLVE_RESOLVABLE_ERRORS. 230 */ 231 public static final String EXTRA_RESOLUTION_CALLING_PACKAGE = 232 "android.service.euicc.extra.RESOLUTION_CALLING_PACKAGE"; 233 234 /** 235 * Intent extra set for resolution requests containing the list of resolvable errors to be 236 * resolved. Each resolvable error is an integer. Its possible values include: 237 * <UL> 238 * <LI>{@link #RESOLVABLE_ERROR_CONFIRMATION_CODE} 239 * <LI>{@link #RESOLVABLE_ERROR_POLICY_RULES} 240 * </UL> 241 */ 242 public static final String EXTRA_RESOLVABLE_ERRORS = 243 "android.service.euicc.extra.RESOLVABLE_ERRORS"; 244 245 /** 246 * Intent extra set for resolution requests containing a boolean indicating whether to ask the 247 * user to retry another confirmation code. 248 */ 249 public static final String EXTRA_RESOLUTION_CONFIRMATION_CODE_RETRIED = 250 "android.service.euicc.extra.RESOLUTION_CONFIRMATION_CODE_RETRIED"; 251 252 /** 253 * Intent extra set for resolution requests containing an int indicating the current card Id. 254 */ 255 public static final String EXTRA_RESOLUTION_CARD_ID = 256 "android.service.euicc.extra.RESOLUTION_CARD_ID"; 257 258 /** 259 * Intent extra set for resolution requests containing an int indicating the subscription id 260 * to be enabled. 261 */ 262 public static final String EXTRA_RESOLUTION_SUBSCRIPTION_ID = 263 "android.service.euicc.extra.RESOLUTION_SUBSCRIPTION_ID"; 264 265 /** 266 * Intent extra set for resolution requests containing an int indicating the current port index. 267 */ 268 public static final String EXTRA_RESOLUTION_PORT_INDEX = 269 "android.service.euicc.extra.RESOLUTION_PORT_INDEX"; 270 271 /** 272 * Intent extra set for resolution requests containing a bool indicating whether to use the 273 * given port index. For example, if {@link #switchToSubscription(int, PendingIntent)} is 274 * called, then no portIndex has been provided by the caller, and this extra will be false. 275 */ 276 public static final String EXTRA_RESOLUTION_USE_PORT_INDEX = 277 "android.service.euicc.extra.RESOLUTION_USE_PORT_INDEX"; 278 279 /** @hide */ 280 @Retention(RetentionPolicy.SOURCE) 281 @IntDef(prefix = { "RESULT_" }, value = { 282 RESULT_OK, 283 RESULT_MUST_DEACTIVATE_SIM, 284 RESULT_RESOLVABLE_ERRORS, 285 RESULT_NEED_CONFIRMATION_CODE, 286 RESULT_FIRST_USER, 287 }) 288 public @interface Result {} 289 290 /** Result code for a successful operation. */ 291 public static final int RESULT_OK = 0; 292 /** Result code indicating that an active SIM must be deactivated to perform the operation. */ 293 public static final int RESULT_MUST_DEACTIVATE_SIM = -1; 294 /** Result code indicating that the user must resolve resolvable errors. */ 295 public static final int RESULT_RESOLVABLE_ERRORS = -2; 296 /** 297 * Result code indicating that the user must input a carrier confirmation code. 298 * 299 * @deprecated From Q, the resolvable errors happened in the download step are presented as 300 * bit map in {@link #EXTRA_RESOLVABLE_ERRORS}. The corresponding result would be 301 * {@link #RESULT_RESOLVABLE_ERRORS}. 302 */ 303 @Deprecated 304 public static final int RESULT_NEED_CONFIRMATION_CODE = -2; 305 // New predefined codes should have negative values. 306 307 /** Start of implementation-specific error results. */ 308 public static final int RESULT_FIRST_USER = 1; 309 310 /** 311 * Boolean extra for resolution actions indicating whether the user granted consent. 312 * This is used and set by the implementation and used in {@code EuiccOperation}. 313 */ 314 public static final String EXTRA_RESOLUTION_CONSENT = 315 "android.service.euicc.extra.RESOLUTION_CONSENT"; 316 /** 317 * String extra for resolution actions indicating the carrier confirmation code. 318 * This is used and set by the implementation and used in {@code EuiccOperation}. 319 */ 320 public static final String EXTRA_RESOLUTION_CONFIRMATION_CODE = 321 "android.service.euicc.extra.RESOLUTION_CONFIRMATION_CODE"; 322 /** 323 * String extra for resolution actions indicating whether the user allows policy rules. 324 * This is used and set by the implementation and used in {@code EuiccOperation}. 325 */ 326 public static final String EXTRA_RESOLUTION_ALLOW_POLICY_RULES = 327 "android.service.euicc.extra.RESOLUTION_ALLOW_POLICY_RULES"; 328 329 private final IEuiccService.Stub mStubWrapper; 330 331 private ThreadPoolExecutor mExecutor; 332 EuiccService()333 public EuiccService() { 334 mStubWrapper = new IEuiccServiceWrapper(); 335 } 336 337 /** 338 * Given a SubjectCode[5.2.6.1] and ReasonCode[5.2.6.2] from GSMA (SGP.22 v2.2), encode it to 339 * the format described in 340 * {@link android.telephony.euicc.EuiccManager#OPERATION_SMDX_SUBJECT_REASON_CODE} 341 * 342 * @param subjectCode SubjectCode[5.2.6.1] from GSMA (SGP.22 v2.2) 343 * @param reasonCode ReasonCode[5.2.6.2] from GSMA (SGP.22 v2.2) 344 * @return encoded error code described in 345 * {@link android.telephony.euicc.EuiccManager#OPERATION_SMDX_SUBJECT_REASON_CODE} 346 * @throws NumberFormatException when the Subject/Reason code contains non digits 347 * @throws IllegalArgumentException when Subject/Reason code is null/empty 348 * @throws UnsupportedOperationException when sections has more than four layers (e.g 5.8.1.2) 349 * or when an number is bigger than 15 350 */ encodeSmdxSubjectAndReasonCode(@ullable String subjectCode, @Nullable String reasonCode)351 public int encodeSmdxSubjectAndReasonCode(@Nullable String subjectCode, 352 @Nullable String reasonCode) { 353 final int maxSupportedSection = 3; 354 final int maxSupportedDigit = 15; 355 final int bitsPerSection = 4; 356 357 if (TextUtils.isEmpty(subjectCode) || TextUtils.isEmpty(reasonCode)) { 358 throw new IllegalArgumentException("SubjectCode/ReasonCode is empty"); 359 } 360 361 final String[] subjectCodeToken = subjectCode.split("\\."); 362 final String[] reasonCodeToken = reasonCode.split("\\."); 363 364 if (subjectCodeToken.length > maxSupportedSection 365 || reasonCodeToken.length > maxSupportedSection) { 366 throw new UnsupportedOperationException("Only three nested layer is supported."); 367 } 368 369 int result = EuiccManager.OPERATION_SMDX_SUBJECT_REASON_CODE; 370 371 // Pad the 0s needed for subject code 372 result = result << (maxSupportedSection - subjectCodeToken.length) * bitsPerSection; 373 374 for (String digitString : subjectCodeToken) { 375 int num = Integer.parseInt(digitString); 376 if (num > maxSupportedDigit) { 377 throw new UnsupportedOperationException("SubjectCode exceeds " + maxSupportedDigit); 378 } 379 result = (result << bitsPerSection) + num; 380 } 381 382 // Pad the 0s needed for reason code 383 result = result << (maxSupportedSection - reasonCodeToken.length) * bitsPerSection; 384 for (String digitString : reasonCodeToken) { 385 int num = Integer.parseInt(digitString); 386 if (num > maxSupportedDigit) { 387 throw new UnsupportedOperationException("ReasonCode exceeds " + maxSupportedDigit); 388 } 389 result = (result << bitsPerSection) + num; 390 } 391 392 return result; 393 } 394 395 @Override 396 @CallSuper onCreate()397 public void onCreate() { 398 super.onCreate(); 399 // We use a oneway AIDL interface to avoid blocking phone process binder threads on IPCs to 400 // an external process, but doing so means the requests are serialized by binder, which is 401 // not desired. Spin up a background thread pool to allow requests to be parallelized. 402 // TODO(b/38206971): Consider removing this if basic card-level functions like listing 403 // profiles are moved to the platform. 404 mExecutor = new ThreadPoolExecutor( 405 4 /* corePoolSize */, 406 4 /* maxPoolSize */, 407 30, TimeUnit.SECONDS, /* keepAliveTime */ 408 new LinkedBlockingQueue<>(), /* workQueue */ 409 new ThreadFactory() { 410 private final AtomicInteger mCount = new AtomicInteger(1); 411 412 @Override 413 public Thread newThread(Runnable r) { 414 return new Thread(r, "EuiccService #" + mCount.getAndIncrement()); 415 } 416 } 417 ); 418 mExecutor.allowCoreThreadTimeOut(true); 419 } 420 421 @Override 422 @CallSuper onDestroy()423 public void onDestroy() { 424 mExecutor.shutdownNow(); 425 super.onDestroy(); 426 } 427 428 /** 429 * If overriding this method, call through to the super method for any unknown actions. 430 * {@inheritDoc} 431 */ 432 @Override 433 @CallSuper onBind(Intent intent)434 public IBinder onBind(Intent intent) { 435 return mStubWrapper; 436 } 437 438 /** 439 * Callback class for {@link #onStartOtaIfNecessary(int, OtaStatusChangedCallback)} 440 * 441 * The status of OTA which can be {@code android.telephony.euicc.EuiccManager#EUICC_OTA_} 442 * 443 * @see IEuiccService#startOtaIfNecessary 444 */ 445 public abstract static class OtaStatusChangedCallback { 446 /** Called when OTA status is changed. */ onOtaStatusChanged(int status)447 public abstract void onOtaStatusChanged(int status); 448 } 449 450 /** 451 * Return the EID of the eUICC. 452 * 453 * @param slotId ID of the SIM slot being queried. 454 * @return the EID. 455 * @see android.telephony.euicc.EuiccManager#getEid 456 */ 457 // TODO(b/36260308): Update doc when we have multi-SIM support. onGetEid(int slotId)458 public abstract String onGetEid(int slotId); 459 460 /** 461 * Return the status of OTA update. 462 * 463 * @param slotId ID of the SIM slot to use for the operation. 464 * @return The status of Euicc OTA update. 465 * @see android.telephony.euicc.EuiccManager#getOtaStatus 466 */ onGetOtaStatus(int slotId)467 public abstract @OtaStatus int onGetOtaStatus(int slotId); 468 469 /** 470 * Perform OTA if current OS is not the latest one. 471 * 472 * @param slotId ID of the SIM slot to use for the operation. 473 * @param statusChangedCallback Function called when OTA status changed. 474 */ onStartOtaIfNecessary( int slotId, OtaStatusChangedCallback statusChangedCallback)475 public abstract void onStartOtaIfNecessary( 476 int slotId, OtaStatusChangedCallback statusChangedCallback); 477 478 /** 479 * Populate {@link DownloadableSubscription} metadata for the given downloadable subscription. 480 * 481 * @param slotId ID of the SIM slot to use for the operation. 482 * @param subscription A subscription whose metadata needs to be populated. 483 * @param forceDeactivateSim If true, and if an active SIM must be deactivated to access the 484 * eUICC, perform this action automatically. Otherwise, {@link #RESULT_MUST_DEACTIVATE_SIM)} 485 * should be returned to allow the user to consent to this operation first. 486 * @return The result of the operation. 487 * @see android.telephony.euicc.EuiccManager#getDownloadableSubscriptionMetadata 488 */ onGetDownloadableSubscriptionMetadata( int slotId, DownloadableSubscription subscription, boolean forceDeactivateSim)489 public abstract GetDownloadableSubscriptionMetadataResult onGetDownloadableSubscriptionMetadata( 490 int slotId, DownloadableSubscription subscription, boolean forceDeactivateSim); 491 492 /** 493 * Return metadata for subscriptions which are available for download for this device. 494 * 495 * @param slotId ID of the SIM slot to use for the operation. 496 * @param forceDeactivateSim If true, and if an active SIM must be deactivated to access the 497 * eUICC, perform this action automatically. Otherwise, {@link #RESULT_MUST_DEACTIVATE_SIM)} 498 * should be returned to allow the user to consent to this operation first. 499 * @return The result of the list operation. 500 * @see android.telephony.euicc.EuiccManager#getDefaultDownloadableSubscriptionList 501 */ 502 public abstract GetDefaultDownloadableSubscriptionListResult onGetDefaultDownloadableSubscriptionList(int slotId, boolean forceDeactivateSim)503 onGetDefaultDownloadableSubscriptionList(int slotId, boolean forceDeactivateSim); 504 505 /** 506 * Download the given subscription. 507 * 508 * @param slotId ID of the SIM slot to use for the operation. 509 * @param subscription The subscription to download. 510 * @param switchAfterDownload If true, the subscription should be enabled upon successful 511 * download. 512 * @param forceDeactivateSim If true, and if an active SIM must be deactivated to access the 513 * eUICC, perform this action automatically. Otherwise, {@link #RESULT_MUST_DEACTIVATE_SIM} 514 * should be returned to allow the user to consent to this operation first. 515 * @param resolvedBundle The bundle containing information on resolved errors. It can contain 516 * a string of confirmation code for the key {@link #EXTRA_RESOLUTION_CONFIRMATION_CODE}, 517 * and a boolean for key {@link #EXTRA_RESOLUTION_ALLOW_POLICY_RULES} indicating whether 518 * the user allows profile policy rules or not. 519 * @return a DownloadSubscriptionResult instance including a result code, a resolvable errors 520 * bit map, and original the card Id. The result code may be one of the predefined 521 * {@code RESULT_} constants or any implementation-specific code starting with 522 * {@link #RESULT_FIRST_USER}. The resolvable error bit map can be either 0 or values 523 * defined in {@code RESOLVABLE_ERROR_}. A subclass should override this method. Otherwise, 524 * this method does nothing and returns null by default. 525 * @see android.telephony.euicc.EuiccManager#downloadSubscription 526 * @deprecated prefer {@link #onDownloadSubscription(int, int, 527 * DownloadableSubscription, boolean, boolean, Bundle)} 528 */ 529 @Deprecated onDownloadSubscription(int slotId, @NonNull DownloadableSubscription subscription, boolean switchAfterDownload, boolean forceDeactivateSim, @Nullable Bundle resolvedBundle)530 public DownloadSubscriptionResult onDownloadSubscription(int slotId, 531 @NonNull DownloadableSubscription subscription, boolean switchAfterDownload, 532 boolean forceDeactivateSim, @Nullable Bundle resolvedBundle) { 533 return null; 534 } 535 536 /** 537 * Download the given subscription. 538 * 539 * @param slotIndex Index of the SIM slot to use for the operation. 540 * @param portIndex Index of the port from the slot. portIndex is used when 541 * switchAfterDownload is set to {@code true}, otherwise download is port agnostic. 542 * @param subscription The subscription to download. 543 * @param switchAfterDownload If true, the subscription should be enabled upon successful 544 * download. 545 * @param forceDeactivateSim If true, and if an active SIM must be deactivated to access the 546 * eUICC, perform this action automatically. Otherwise, {@link #RESULT_MUST_DEACTIVATE_SIM} 547 * should be returned to allow the user to consent to this operation first. 548 * @param resolvedBundle The bundle containing information on resolved errors. It can contain 549 * a string of confirmation code for the key {@link #EXTRA_RESOLUTION_CONFIRMATION_CODE}, 550 * and a boolean for key {@link #EXTRA_RESOLUTION_ALLOW_POLICY_RULES} indicating whether 551 * the user allows profile policy rules or not. 552 * @return a DownloadSubscriptionResult instance including a result code, a resolvable errors 553 * bit map, and original the card Id. The result code may be one of the predefined 554 * {@code RESULT_} constants or any implementation-specific code starting with 555 * {@link #RESULT_FIRST_USER}. The resolvable error bit map can be either 0 or values 556 * defined in {@code RESOLVABLE_ERROR_}. 557 * @see android.telephony.euicc.EuiccManager#downloadSubscription 558 */ 559 @NonNull onDownloadSubscription(int slotIndex, int portIndex, @NonNull DownloadableSubscription subscription, boolean switchAfterDownload, boolean forceDeactivateSim, @NonNull Bundle resolvedBundle)560 public DownloadSubscriptionResult onDownloadSubscription(int slotIndex, int portIndex, 561 @NonNull DownloadableSubscription subscription, boolean switchAfterDownload, 562 boolean forceDeactivateSim, @NonNull Bundle resolvedBundle) { 563 // stub implementation, LPA needs to implement this 564 throw new UnsupportedOperationException("LPA must override onDownloadSubscription"); 565 } 566 567 /** 568 * Download the given subscription. 569 * 570 * @param slotId ID of the SIM slot to use for the operation. 571 * @param subscription The subscription to download. 572 * @param switchAfterDownload If true, the subscription should be enabled upon successful 573 * download. 574 * @param forceDeactivateSim If true, and if an active SIM must be deactivated to access the 575 * eUICC, perform this action automatically. Otherwise, {@link #RESULT_MUST_DEACTIVATE_SIM} 576 * should be returned to allow the user to consent to this operation first. 577 * @return the result of the download operation. May be one of the predefined {@code RESULT_} 578 * constants or any implementation-specific code starting with {@link #RESULT_FIRST_USER}. 579 * @see android.telephony.euicc.EuiccManager#downloadSubscription 580 * 581 * @deprecated From Q, a subclass should use and override the above 582 * {@link #onDownloadSubscription(int, DownloadableSubscription, boolean, boolean, Bundle)}. The 583 * default return value for this one is Integer.MIN_VALUE. 584 */ onDownloadSubscription(int slotId, @NonNull DownloadableSubscription subscription, boolean switchAfterDownload, boolean forceDeactivateSim)585 @Deprecated public @Result int onDownloadSubscription(int slotId, 586 @NonNull DownloadableSubscription subscription, boolean switchAfterDownload, 587 boolean forceDeactivateSim) { 588 return Integer.MIN_VALUE; 589 } 590 591 /** 592 * Return a list of all @link EuiccProfileInfo}s. 593 * 594 * @param slotId ID of the SIM slot to use for the operation. 595 * @return The result of the operation. 596 * @see android.telephony.SubscriptionManager#getAvailableSubscriptionInfoList 597 * @see android.telephony.SubscriptionManager#getAccessibleSubscriptionInfoList 598 */ onGetEuiccProfileInfoList(int slotId)599 public abstract @NonNull GetEuiccProfileInfoListResult onGetEuiccProfileInfoList(int slotId); 600 601 /** 602 * Return info about the eUICC chip/device. 603 * 604 * @param slotId ID of the SIM slot to use for the operation. 605 * @return the {@link EuiccInfo} for the eUICC chip/device. 606 * @see android.telephony.euicc.EuiccManager#getEuiccInfo 607 */ onGetEuiccInfo(int slotId)608 public abstract @NonNull EuiccInfo onGetEuiccInfo(int slotId); 609 610 /** 611 * Delete the given subscription. 612 * 613 * <p>If the subscription is currently active, it should be deactivated first (equivalent to a 614 * physical SIM being ejected). 615 * 616 * @param slotId ID of the SIM slot to use for the operation. 617 * @param iccid the ICCID of the subscription to delete. 618 * @return the result of the delete operation. May be one of the predefined {@code RESULT_} 619 * constants or any implementation-specific code starting with {@link #RESULT_FIRST_USER}. 620 * @see android.telephony.euicc.EuiccManager#deleteSubscription 621 */ onDeleteSubscription(int slotId, String iccid)622 public abstract @Result int onDeleteSubscription(int slotId, String iccid); 623 624 /** 625 * Switch to the given subscription. 626 * 627 * @param slotId ID of the SIM slot to use for the operation. 628 * @param iccid the ICCID of the subscription to enable. May be null, in which case the current 629 * profile should be deactivated and no profile should be activated to replace it - this is 630 * equivalent to a physical SIM being ejected. 631 * @param forceDeactivateSim If true, and if an active SIM must be deactivated to access the 632 * eUICC, perform this action automatically. Otherwise, {@link #RESULT_MUST_DEACTIVATE_SIM} 633 * should be returned to allow the user to consent to this operation first. 634 * @return the result of the switch operation. May be one of the predefined {@code RESULT_} 635 * constants or any implementation-specific code starting with {@link #RESULT_FIRST_USER}. 636 * @see android.telephony.euicc.EuiccManager#switchToSubscription 637 * 638 * @deprecated prefer {@link #onSwitchToSubscriptionWithPort(int, int, String, boolean)} 639 */ onSwitchToSubscription(int slotId, @Nullable String iccid, boolean forceDeactivateSim)640 @Deprecated public abstract @Result int onSwitchToSubscription(int slotId, 641 @Nullable String iccid, boolean forceDeactivateSim); 642 643 /** 644 * Switch to the given subscription. 645 * 646 * @param slotId ID of the SIM slot to use for the operation. 647 * @param portIndex which port on the eUICC to use 648 * @param iccid the ICCID of the subscription to enable. May be null, in which case the current 649 * profile should be deactivated and no profile should be activated to replace it - this is 650 * equivalent to a physical SIM being ejected. 651 * @param forceDeactivateSim If true, and if an active SIM must be deactivated to access the 652 * eUICC, perform this action automatically. Otherwise, {@link #RESULT_MUST_DEACTIVATE_SIM} 653 * should be returned to allow the user to consent to this operation first. 654 * @return the result of the switch operation. May be one of the predefined {@code RESULT_} 655 * constants or any implementation-specific code starting with {@link #RESULT_FIRST_USER}. 656 * @see android.telephony.euicc.EuiccManager#switchToSubscription 657 */ onSwitchToSubscriptionWithPort(int slotId, int portIndex, @Nullable String iccid, boolean forceDeactivateSim)658 public @Result int onSwitchToSubscriptionWithPort(int slotId, int portIndex, 659 @Nullable String iccid, boolean forceDeactivateSim) { 660 // stub implementation, LPA needs to implement this 661 throw new UnsupportedOperationException("LPA must override onSwitchToSubscriptionWithPort"); 662 } 663 664 /** 665 * Update the nickname of the given subscription. 666 * 667 * @param slotId ID of the SIM slot to use for the operation. 668 * @param iccid the ICCID of the subscription to update. 669 * @param nickname the new nickname to apply. 670 * @return the result of the update operation. May be one of the predefined {@code RESULT_} 671 * constants or any implementation-specific code starting with {@link #RESULT_FIRST_USER}. 672 * @see android.telephony.euicc.EuiccManager#updateSubscriptionNickname 673 */ onUpdateSubscriptionNickname(int slotId, String iccid, String nickname)674 public abstract int onUpdateSubscriptionNickname(int slotId, String iccid, 675 String nickname); 676 677 /** 678 * Erase all operational subscriptions on the device. 679 * 680 * <p>This is intended to be used for device resets. As such, the reset should be performed even 681 * if an active SIM must be deactivated in order to access the eUICC. 682 * 683 * @param slotId ID of the SIM slot to use for the operation. 684 * @return the result of the erase operation. May be one of the predefined {@code RESULT_} 685 * constants or any implementation-specific code starting with {@link #RESULT_FIRST_USER}. 686 * @see android.telephony.euicc.EuiccManager#eraseSubscriptions 687 * 688 * @deprecated From R, callers should specify a flag for specific set of subscriptions to erase 689 * and use {@link #onEraseSubscriptions(int, int)} instead 690 */ 691 @Deprecated onEraseSubscriptions(int slotId)692 public abstract int onEraseSubscriptions(int slotId); 693 694 /** 695 * Erase specific subscriptions on the device. 696 * 697 * <p>This is intended to be used for device resets. As such, the reset should be performed even 698 * if an active SIM must be deactivated in order to access the eUICC. 699 * 700 * @param slotIndex index of the SIM slot to use for the operation. 701 * @param options flag for specific group of subscriptions to erase 702 * @return the result of the erase operation. May be one of the predefined {@code RESULT_} 703 * constants or any implementation-specific code starting with {@link #RESULT_FIRST_USER}. 704 * @see android.telephony.euicc.EuiccManager#eraseSubscriptionsWithOptions 705 */ onEraseSubscriptions(int slotIndex, @ResetOption int options)706 public int onEraseSubscriptions(int slotIndex, @ResetOption int options) { 707 throw new UnsupportedOperationException( 708 "This method must be overridden to enable the ResetOption parameter"); 709 } 710 711 /** 712 * Ensure that subscriptions will be retained on the next factory reset. 713 * 714 * <p>Called directly before a factory reset. Assumes that a normal factory reset will lead to 715 * profiles being erased on first boot (to cover fastboot/recovery wipes), so the implementation 716 * should persist some bit that will remain accessible after the factory reset to bypass this 717 * flow when this method is called. 718 * 719 * @param slotId ID of the SIM slot to use for the operation. 720 * @return the result of the operation. May be one of the predefined {@code RESULT_} constants 721 * or any implementation-specific code starting with {@link #RESULT_FIRST_USER}. 722 */ onRetainSubscriptionsForFactoryReset(int slotId)723 public abstract int onRetainSubscriptionsForFactoryReset(int slotId); 724 725 /** 726 * Dump to a provided printWriter. 727 */ dump(@onNull PrintWriter printWriter)728 public void dump(@NonNull PrintWriter printWriter) { 729 printWriter.println("The connected LPA does not implement EuiccService#dump()"); 730 } 731 732 /** 733 * Wrapper around IEuiccService that forwards calls to implementations of {@link EuiccService}. 734 */ 735 private class IEuiccServiceWrapper extends IEuiccService.Stub { 736 @Override downloadSubscription(int slotId, int portIndex, DownloadableSubscription subscription, boolean switchAfterDownload, boolean forceDeactivateSim, Bundle resolvedBundle, IDownloadSubscriptionCallback callback)737 public void downloadSubscription(int slotId, int portIndex, 738 DownloadableSubscription subscription, 739 boolean switchAfterDownload, boolean forceDeactivateSim, Bundle resolvedBundle, 740 IDownloadSubscriptionCallback callback) { 741 mExecutor.execute(new Runnable() { 742 @Override 743 public void run() { 744 DownloadSubscriptionResult result; 745 try { 746 result = EuiccService.this.onDownloadSubscription( 747 slotId, portIndex, subscription, switchAfterDownload, 748 forceDeactivateSim, resolvedBundle); 749 } catch (UnsupportedOperationException | AbstractMethodError e) { 750 Log.w(TAG, "The new onDownloadSubscription(int, int, " 751 + "DownloadableSubscription, boolean, boolean, Bundle) is not " 752 + "implemented. Fall back to the old one.", e); 753 result = EuiccService.this.onDownloadSubscription( 754 slotId, subscription, switchAfterDownload, 755 forceDeactivateSim, resolvedBundle); 756 } 757 try { 758 callback.onComplete(result); 759 } catch (RemoteException e) { 760 // Can't communicate with the phone process; ignore. 761 } 762 } 763 }); 764 } 765 766 @Override getEid(int slotId, IGetEidCallback callback)767 public void getEid(int slotId, IGetEidCallback callback) { 768 mExecutor.execute(new Runnable() { 769 @Override 770 public void run() { 771 String eid = EuiccService.this.onGetEid(slotId); 772 try { 773 callback.onSuccess(eid); 774 } catch (RemoteException e) { 775 // Can't communicate with the phone process; ignore. 776 } 777 } 778 }); 779 } 780 781 @Override startOtaIfNecessary( int slotId, IOtaStatusChangedCallback statusChangedCallback)782 public void startOtaIfNecessary( 783 int slotId, IOtaStatusChangedCallback statusChangedCallback) { 784 mExecutor.execute(new Runnable() { 785 @Override 786 public void run() { 787 EuiccService.this.onStartOtaIfNecessary(slotId, new OtaStatusChangedCallback() { 788 @Override 789 public void onOtaStatusChanged(int status) { 790 try { 791 statusChangedCallback.onOtaStatusChanged(status); 792 } catch (RemoteException e) { 793 // Can't communicate with the phone process; ignore. 794 } 795 } 796 }); 797 } 798 }); 799 } 800 801 @Override getOtaStatus(int slotId, IGetOtaStatusCallback callback)802 public void getOtaStatus(int slotId, IGetOtaStatusCallback callback) { 803 mExecutor.execute(new Runnable() { 804 @Override 805 public void run() { 806 int status = EuiccService.this.onGetOtaStatus(slotId); 807 try { 808 callback.onSuccess(status); 809 } catch (RemoteException e) { 810 // Can't communicate with the phone process; ignore. 811 } 812 } 813 }); 814 } 815 816 @Override getDownloadableSubscriptionMetadata(int slotId, DownloadableSubscription subscription, boolean forceDeactivateSim, IGetDownloadableSubscriptionMetadataCallback callback)817 public void getDownloadableSubscriptionMetadata(int slotId, 818 DownloadableSubscription subscription, 819 boolean forceDeactivateSim, 820 IGetDownloadableSubscriptionMetadataCallback callback) { 821 mExecutor.execute(new Runnable() { 822 @Override 823 public void run() { 824 GetDownloadableSubscriptionMetadataResult result = 825 EuiccService.this.onGetDownloadableSubscriptionMetadata( 826 slotId, subscription, forceDeactivateSim); 827 try { 828 callback.onComplete(result); 829 } catch (RemoteException e) { 830 // Can't communicate with the phone process; ignore. 831 } 832 } 833 }); 834 } 835 836 @Override getDefaultDownloadableSubscriptionList(int slotId, boolean forceDeactivateSim, IGetDefaultDownloadableSubscriptionListCallback callback)837 public void getDefaultDownloadableSubscriptionList(int slotId, boolean forceDeactivateSim, 838 IGetDefaultDownloadableSubscriptionListCallback callback) { 839 mExecutor.execute(new Runnable() { 840 @Override 841 public void run() { 842 GetDefaultDownloadableSubscriptionListResult result = 843 EuiccService.this.onGetDefaultDownloadableSubscriptionList( 844 slotId, forceDeactivateSim); 845 try { 846 callback.onComplete(result); 847 } catch (RemoteException e) { 848 // Can't communicate with the phone process; ignore. 849 } 850 } 851 }); 852 } 853 854 @Override getEuiccProfileInfoList(int slotId, IGetEuiccProfileInfoListCallback callback)855 public void getEuiccProfileInfoList(int slotId, IGetEuiccProfileInfoListCallback callback) { 856 mExecutor.execute(new Runnable() { 857 @Override 858 public void run() { 859 GetEuiccProfileInfoListResult result = 860 EuiccService.this.onGetEuiccProfileInfoList(slotId); 861 try { 862 callback.onComplete(result); 863 } catch (RemoteException e) { 864 // Can't communicate with the phone process; ignore. 865 } 866 } 867 }); 868 } 869 870 @Override getEuiccInfo(int slotId, IGetEuiccInfoCallback callback)871 public void getEuiccInfo(int slotId, IGetEuiccInfoCallback callback) { 872 mExecutor.execute(new Runnable() { 873 @Override 874 public void run() { 875 EuiccInfo euiccInfo = EuiccService.this.onGetEuiccInfo(slotId); 876 try { 877 callback.onSuccess(euiccInfo); 878 } catch (RemoteException e) { 879 // Can't communicate with the phone process; ignore. 880 } 881 } 882 }); 883 884 } 885 886 @Override deleteSubscription(int slotId, String iccid, IDeleteSubscriptionCallback callback)887 public void deleteSubscription(int slotId, String iccid, 888 IDeleteSubscriptionCallback callback) { 889 mExecutor.execute(new Runnable() { 890 @Override 891 public void run() { 892 int result = EuiccService.this.onDeleteSubscription(slotId, iccid); 893 try { 894 callback.onComplete(result); 895 } catch (RemoteException e) { 896 // Can't communicate with the phone process; ignore. 897 } 898 } 899 }); 900 } 901 @Override switchToSubscription(int slotId, int portIndex, String iccid, boolean forceDeactivateSim, ISwitchToSubscriptionCallback callback, boolean usePortIndex)902 public void switchToSubscription(int slotId, int portIndex, String iccid, 903 boolean forceDeactivateSim, ISwitchToSubscriptionCallback callback, 904 boolean usePortIndex) { 905 mExecutor.execute(new Runnable() { 906 @Override 907 public void run() { 908 int result = 0; 909 if (usePortIndex) { 910 result = EuiccService.this.onSwitchToSubscriptionWithPort( 911 slotId, portIndex, iccid, forceDeactivateSim); 912 } else { 913 result = EuiccService.this.onSwitchToSubscription( 914 slotId, iccid, forceDeactivateSim); 915 } 916 try { 917 callback.onComplete(result); 918 } catch (RemoteException e) { 919 // Can't communicate with the phone process; ignore. 920 } 921 } 922 }); 923 } 924 925 @Override updateSubscriptionNickname(int slotId, String iccid, String nickname, IUpdateSubscriptionNicknameCallback callback)926 public void updateSubscriptionNickname(int slotId, String iccid, String nickname, 927 IUpdateSubscriptionNicknameCallback callback) { 928 mExecutor.execute(new Runnable() { 929 @Override 930 public void run() { 931 int result = 932 EuiccService.this.onUpdateSubscriptionNickname(slotId, iccid, nickname); 933 try { 934 callback.onComplete(result); 935 } catch (RemoteException e) { 936 // Can't communicate with the phone process; ignore. 937 } 938 } 939 }); 940 } 941 942 @Override eraseSubscriptions(int slotId, IEraseSubscriptionsCallback callback)943 public void eraseSubscriptions(int slotId, IEraseSubscriptionsCallback callback) { 944 mExecutor.execute(new Runnable() { 945 @Override 946 public void run() { 947 int result = EuiccService.this.onEraseSubscriptions(slotId); 948 try { 949 callback.onComplete(result); 950 } catch (RemoteException e) { 951 // Can't communicate with the phone process; ignore. 952 } 953 } 954 }); 955 } 956 957 @Override eraseSubscriptionsWithOptions( int slotIndex, @ResetOption int options, IEraseSubscriptionsCallback callback)958 public void eraseSubscriptionsWithOptions( 959 int slotIndex, @ResetOption int options, IEraseSubscriptionsCallback callback) { 960 mExecutor.execute(new Runnable() { 961 @Override 962 public void run() { 963 int result = EuiccService.this.onEraseSubscriptions(slotIndex, options); 964 try { 965 callback.onComplete(result); 966 } catch (RemoteException e) { 967 // Can't communicate with the phone process; ignore. 968 } 969 } 970 }); 971 } 972 973 @Override retainSubscriptionsForFactoryReset(int slotId, IRetainSubscriptionsForFactoryResetCallback callback)974 public void retainSubscriptionsForFactoryReset(int slotId, 975 IRetainSubscriptionsForFactoryResetCallback callback) { 976 mExecutor.execute(new Runnable() { 977 @Override 978 public void run() { 979 int result = EuiccService.this.onRetainSubscriptionsForFactoryReset(slotId); 980 try { 981 callback.onComplete(result); 982 } catch (RemoteException e) { 983 // Can't communicate with the phone process; ignore. 984 } 985 } 986 }); 987 } 988 989 @Override dump(IEuiccServiceDumpResultCallback callback)990 public void dump(IEuiccServiceDumpResultCallback callback) throws RemoteException { 991 mExecutor.execute(new Runnable() { 992 @Override 993 public void run() { 994 try { 995 final StringWriter sw = new StringWriter(); 996 final PrintWriter pw = new PrintWriter(sw); 997 EuiccService.this.dump(pw); 998 callback.onComplete(sw.toString()); 999 } catch (RemoteException e) { 1000 // Can't communicate with the phone process; ignore. 1001 } 1002 } 1003 }); 1004 } 1005 } 1006 } 1007