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.EuiccCardManager.ResetOption; 19 20 import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE; 21 22 import android.Manifest; 23 import android.annotation.Nullable; 24 import android.content.BroadcastReceiver; 25 import android.content.ComponentName; 26 import android.content.Context; 27 import android.content.Intent; 28 import android.content.IntentFilter; 29 import android.content.ServiceConnection; 30 import android.content.pm.ActivityInfo; 31 import android.content.pm.ComponentInfo; 32 import android.content.pm.PackageManager; 33 import android.content.pm.ResolveInfo; 34 import android.content.pm.ServiceInfo; 35 import android.os.Bundle; 36 import android.os.IBinder; 37 import android.os.Looper; 38 import android.os.Message; 39 import android.os.RemoteException; 40 import android.service.euicc.DownloadSubscriptionResult; 41 import android.service.euicc.EuiccService; 42 import android.service.euicc.GetDefaultDownloadableSubscriptionListResult; 43 import android.service.euicc.GetDownloadableSubscriptionMetadataResult; 44 import android.service.euicc.GetEuiccProfileInfoListResult; 45 import android.service.euicc.IDeleteSubscriptionCallback; 46 import android.service.euicc.IDownloadSubscriptionCallback; 47 import android.service.euicc.IEraseSubscriptionsCallback; 48 import android.service.euicc.IEuiccService; 49 import android.service.euicc.IEuiccServiceDumpResultCallback; 50 import android.service.euicc.IGetAvailableMemoryInBytesCallback; 51 import android.service.euicc.IGetDefaultDownloadableSubscriptionListCallback; 52 import android.service.euicc.IGetDownloadableSubscriptionMetadataCallback; 53 import android.service.euicc.IGetEidCallback; 54 import android.service.euicc.IGetEuiccInfoCallback; 55 import android.service.euicc.IGetEuiccProfileInfoListCallback; 56 import android.service.euicc.IGetOtaStatusCallback; 57 import android.service.euicc.IOtaStatusChangedCallback; 58 import android.service.euicc.IRetainSubscriptionsForFactoryResetCallback; 59 import android.service.euicc.ISwitchToSubscriptionCallback; 60 import android.service.euicc.IUpdateSubscriptionNicknameCallback; 61 import android.telephony.AnomalyReporter; 62 import android.telephony.SubscriptionManager; 63 import android.telephony.TelephonyManager; 64 import android.telephony.UiccCardInfo; 65 import android.telephony.UiccSlotInfo; 66 import android.telephony.euicc.DownloadableSubscription; 67 import android.telephony.euicc.EuiccInfo; 68 import android.telephony.euicc.EuiccManager; 69 import android.telephony.euicc.EuiccManager.OtaStatus; 70 import android.text.TextUtils; 71 import android.util.ArraySet; 72 import android.util.Log; 73 74 import com.android.internal.annotations.VisibleForTesting; 75 import com.android.internal.telephony.PackageChangeReceiver; 76 import com.android.internal.telephony.uicc.IccUtils; 77 import com.android.internal.telephony.uicc.UiccController; 78 import com.android.internal.telephony.util.TelephonyUtils; 79 import com.android.internal.util.IState; 80 import com.android.internal.util.State; 81 import com.android.internal.util.StateMachine; 82 83 import java.io.FileDescriptor; 84 import java.io.PrintWriter; 85 import java.util.List; 86 import java.util.Objects; 87 import java.util.Set; 88 import java.util.UUID; 89 90 /** 91 * State machine which maintains the binding to the EuiccService implementation and issues commands. 92 * 93 * <p>Keeps track of the highest-priority EuiccService implementation to use. When a command comes 94 * in, brings up a binding to that service, issues the command, and lingers the binding as long as 95 * more commands are coming in. The binding is dropped after an idle timeout. 96 */ 97 public class EuiccConnector extends StateMachine implements ServiceConnection { 98 private static final String TAG = "EuiccConnector"; 99 100 /** 101 * Maximum amount of time to wait for a connection to be established after bindService returns 102 * true or onServiceDisconnected is called (and no package change has occurred which should 103 * force us to reestablish the binding). 104 */ 105 @VisibleForTesting 106 static final int BIND_TIMEOUT_MILLIS = 30000; 107 108 /** 109 * Maximum amount of idle time to hold the binding while in {@link ConnectedState}. After this, 110 * the binding is dropped to free up memory as the EuiccService is not expected to be used 111 * frequently as part of ongoing device operation. 112 */ 113 @VisibleForTesting 114 static final int LINGER_TIMEOUT_MILLIS = 60000; 115 116 /** 117 * Command indicating that a package change has occurred. 118 * 119 * <p>{@link Message#obj} is an optional package name. If set, this package has changed in a 120 * way that will permanently sever any open bindings, and if we're bound to it, the binding must 121 * be forcefully reestablished. 122 */ 123 private static final int CMD_PACKAGE_CHANGE = 1; 124 /** Command indicating that {@link #BIND_TIMEOUT_MILLIS} has been reached. */ 125 private static final int CMD_CONNECT_TIMEOUT = 2; 126 /** Command indicating that {@link #LINGER_TIMEOUT_MILLIS} has been reached. */ 127 private static final int CMD_LINGER_TIMEOUT = 3; 128 /** 129 * Command indicating that the service has connected. 130 * 131 * <p>{@link Message#obj} is the connected {@link IEuiccService} implementation. 132 */ 133 private static final int CMD_SERVICE_CONNECTED = 4; 134 /** Command indicating that the service has disconnected. */ 135 private static final int CMD_SERVICE_DISCONNECTED = 5; 136 /** 137 * Command indicating that a command has completed and the callback should be executed. 138 * 139 * <p>{@link Message#obj} is a {@link Runnable} which will trigger the callback. 140 */ 141 private static final int CMD_COMMAND_COMPLETE = 6; 142 143 // Commands corresponding with EuiccService APIs. Keep isEuiccCommand in sync with any changes. 144 private static final int CMD_GET_EID = 100; 145 private static final int CMD_GET_DOWNLOADABLE_SUBSCRIPTION_METADATA = 101; 146 private static final int CMD_DOWNLOAD_SUBSCRIPTION = 102; 147 private static final int CMD_GET_EUICC_PROFILE_INFO_LIST = 103; 148 private static final int CMD_GET_DEFAULT_DOWNLOADABLE_SUBSCRIPTION_LIST = 104; 149 private static final int CMD_GET_EUICC_INFO = 105; 150 private static final int CMD_DELETE_SUBSCRIPTION = 106; 151 private static final int CMD_SWITCH_TO_SUBSCRIPTION = 107; 152 private static final int CMD_UPDATE_SUBSCRIPTION_NICKNAME = 108; 153 private static final int CMD_ERASE_SUBSCRIPTIONS = 109; 154 private static final int CMD_RETAIN_SUBSCRIPTIONS = 110; 155 private static final int CMD_GET_OTA_STATUS = 111; 156 private static final int CMD_START_OTA_IF_NECESSARY = 112; 157 private static final int CMD_ERASE_SUBSCRIPTIONS_WITH_OPTIONS = 113; 158 private static final int CMD_DUMP_EUICC_SERVICE = 114; 159 private static final int CMD_GET_AVAILABLE_MEMORY_IN_BYTES = 115; 160 isEuiccCommand(int what)161 private static boolean isEuiccCommand(int what) { 162 return what >= CMD_GET_EID; 163 } 164 165 /** Flags to use when querying PackageManager for Euicc component implementations. */ 166 private static final int EUICC_QUERY_FLAGS = 167 PackageManager.MATCH_SYSTEM_ONLY | PackageManager.MATCH_DIRECT_BOOT_AUTO 168 | PackageManager.GET_RESOLVED_FILTER; 169 170 /** 171 * Return the activity info of the activity to start for the given intent, or null if none 172 * was found. 173 */ findBestActivity(PackageManager packageManager, Intent intent)174 public static ActivityInfo findBestActivity(PackageManager packageManager, Intent intent) { 175 List<ResolveInfo> resolveInfoList = packageManager.queryIntentActivities(intent, 176 EUICC_QUERY_FLAGS); 177 ActivityInfo bestComponent = 178 (ActivityInfo) findBestComponent(packageManager, resolveInfoList); 179 if (bestComponent == null) { 180 Log.w(TAG, "No valid component found for intent: " + intent); 181 } 182 return bestComponent; 183 } 184 185 /** 186 * Return the component info of the EuiccService to bind to, or null if none were found. 187 */ findBestComponent(PackageManager packageManager)188 public static ComponentInfo findBestComponent(PackageManager packageManager) { 189 Intent intent = new Intent(EuiccService.EUICC_SERVICE_INTERFACE); 190 List<ResolveInfo> resolveInfoList = 191 packageManager.queryIntentServices(intent, EUICC_QUERY_FLAGS); 192 ComponentInfo bestComponent = findBestComponent(packageManager, resolveInfoList); 193 if (bestComponent == null) { 194 Log.w(TAG, "No valid EuiccService implementation found"); 195 } 196 return bestComponent; 197 } 198 199 /** Base class for all command callbacks. */ 200 @VisibleForTesting(visibility = PACKAGE) 201 public interface BaseEuiccCommandCallback { 202 /** Called when a command fails because the service is or became unavailable. */ onEuiccServiceUnavailable()203 void onEuiccServiceUnavailable(); 204 } 205 206 /** Callback class for {@link #getEid}. */ 207 @VisibleForTesting(visibility = PACKAGE) 208 public interface GetEidCommandCallback extends BaseEuiccCommandCallback { 209 /** Called when the EID lookup has completed. */ onGetEidComplete(String eid)210 void onGetEidComplete(String eid); 211 } 212 213 /** Callback class for {@link #getAvailableMemoryInBytes}. */ 214 @VisibleForTesting(visibility = PACKAGE) 215 public interface GetAvailableMemoryInBytesCommandCallback extends BaseEuiccCommandCallback { 216 /** Called when the available memory in bytes lookup has completed. */ onGetAvailableMemoryInBytesComplete(long availableMemoryInBytes)217 void onGetAvailableMemoryInBytesComplete(long availableMemoryInBytes); 218 /** 219 * Called when the connected LPA does not implement 220 * EuiccService#onGetAvailableMemoryInBytes(int). 221 */ onUnsupportedOperationExceptionComplete(String message)222 void onUnsupportedOperationExceptionComplete(String message); 223 } 224 225 /** Callback class for {@link #getOtaStatus}. */ 226 @VisibleForTesting(visibility = PACKAGE) 227 public interface GetOtaStatusCommandCallback extends BaseEuiccCommandCallback { 228 /** Called when the getting OTA status lookup has completed. */ onGetOtaStatusComplete(@taStatus int status)229 void onGetOtaStatusComplete(@OtaStatus int status); 230 } 231 232 /** Callback class for {@link #startOtaIfNecessary}. */ 233 @VisibleForTesting(visibility = PACKAGE) 234 public interface OtaStatusChangedCallback extends BaseEuiccCommandCallback { 235 /** 236 * Called when OTA status is changed to {@link EuiccM}. */ onOtaStatusChanged(int status)237 void onOtaStatusChanged(int status); 238 } 239 240 static class GetMetadataRequest { 241 DownloadableSubscription mSubscription; 242 boolean mForceDeactivateSim; 243 boolean mSwitchAfterDownload; 244 int mPortIndex; 245 GetMetadataCommandCallback mCallback; 246 } 247 248 /** Callback class for {@link #getDownloadableSubscriptionMetadata}. */ 249 @VisibleForTesting(visibility = PACKAGE) 250 public interface GetMetadataCommandCallback extends BaseEuiccCommandCallback { 251 /** Called when the metadata lookup has completed (though it may have failed). */ onGetMetadataComplete(int cardId, GetDownloadableSubscriptionMetadataResult result)252 void onGetMetadataComplete(int cardId, GetDownloadableSubscriptionMetadataResult result); 253 } 254 255 static class DownloadRequest { 256 DownloadableSubscription mSubscription; 257 boolean mSwitchAfterDownload; 258 boolean mForceDeactivateSim; 259 DownloadCommandCallback mCallback; 260 int mPortIndex; 261 Bundle mResolvedBundle; 262 } 263 264 /** Callback class for {@link #downloadSubscription}. */ 265 @VisibleForTesting(visibility = PACKAGE) 266 public interface DownloadCommandCallback extends BaseEuiccCommandCallback { 267 /** Called when the download has completed (though it may have failed). */ onDownloadComplete(DownloadSubscriptionResult result)268 void onDownloadComplete(DownloadSubscriptionResult result); 269 } 270 271 interface GetEuiccProfileInfoListCommandCallback extends BaseEuiccCommandCallback { 272 /** Called when the list has completed (though it may have failed). */ onListComplete(GetEuiccProfileInfoListResult result)273 void onListComplete(GetEuiccProfileInfoListResult result); 274 } 275 276 static class GetDefaultListRequest { 277 boolean mForceDeactivateSim; 278 GetDefaultListCommandCallback mCallback; 279 } 280 281 /** Callback class for {@link #getDefaultDownloadableSubscriptionList}. */ 282 @VisibleForTesting(visibility = PACKAGE) 283 public interface GetDefaultListCommandCallback extends BaseEuiccCommandCallback { 284 /** Called when the list has completed (though it may have failed). */ onGetDefaultListComplete(int cardId, GetDefaultDownloadableSubscriptionListResult result)285 void onGetDefaultListComplete(int cardId, 286 GetDefaultDownloadableSubscriptionListResult result); 287 } 288 289 /** Callback class for {@link #getEuiccInfo}. */ 290 @VisibleForTesting(visibility = PACKAGE) 291 public interface GetEuiccInfoCommandCallback extends BaseEuiccCommandCallback { 292 /** Called when the EuiccInfo lookup has completed. */ onGetEuiccInfoComplete(EuiccInfo euiccInfo)293 void onGetEuiccInfoComplete(EuiccInfo euiccInfo); 294 } 295 296 static class DeleteRequest { 297 String mIccid; 298 DeleteCommandCallback mCallback; 299 } 300 301 /** Callback class for {@link #deleteSubscription}. */ 302 @VisibleForTesting(visibility = PACKAGE) 303 public interface DeleteCommandCallback extends BaseEuiccCommandCallback { 304 /** Called when the delete has completed (though it may have failed). */ onDeleteComplete(int result)305 void onDeleteComplete(int result); 306 } 307 308 static class SwitchRequest { 309 @Nullable String mIccid; 310 boolean mForceDeactivateSim; 311 SwitchCommandCallback mCallback; 312 boolean mUsePortIndex; 313 } 314 315 /** Callback class for {@link #switchToSubscription}. */ 316 @VisibleForTesting(visibility = PACKAGE) 317 public interface SwitchCommandCallback extends BaseEuiccCommandCallback { 318 /** Called when the switch has completed (though it may have failed). */ onSwitchComplete(int result)319 void onSwitchComplete(int result); 320 } 321 322 static class UpdateNicknameRequest { 323 String mIccid; 324 String mNickname; 325 UpdateNicknameCommandCallback mCallback; 326 } 327 328 /** Callback class for {@link #updateSubscriptionNickname}. */ 329 @VisibleForTesting(visibility = PACKAGE) 330 public interface UpdateNicknameCommandCallback extends BaseEuiccCommandCallback { 331 /** Called when the update has completed (though it may have failed). */ onUpdateNicknameComplete(int result)332 void onUpdateNicknameComplete(int result); 333 } 334 335 /** 336 * Callback class for {@link #eraseSubscriptions} and {@link #eraseSubscriptionsWithOptions}. 337 */ 338 @VisibleForTesting(visibility = PACKAGE) 339 public interface EraseCommandCallback extends BaseEuiccCommandCallback { 340 /** Called when the erase has completed (though it may have failed). */ onEraseComplete(int result)341 void onEraseComplete(int result); 342 } 343 344 /** Callback class for {@link #retainSubscriptions}. */ 345 @VisibleForTesting(visibility = PACKAGE) 346 public interface RetainSubscriptionsCommandCallback extends BaseEuiccCommandCallback { 347 /** Called when the retain command has completed (though it may have failed). */ onRetainSubscriptionsComplete(int result)348 void onRetainSubscriptionsComplete(int result); 349 } 350 351 /** Callback class for {@link #dumpEuiccService(DumpEuiccCommandCallback)} }*/ 352 @VisibleForTesting(visibility = PACKAGE) 353 public interface DumpEuiccServiceCommandCallback extends BaseEuiccCommandCallback { 354 /** Called when the retain command has completed (though it may have failed). */ onDumpEuiccServiceComplete(String logs)355 void onDumpEuiccServiceComplete(String logs); 356 } 357 358 private Context mContext; 359 private PackageManager mPm; 360 private TelephonyManager mTm; 361 private SubscriptionManager mSm; 362 363 private final PackageChangeReceiver mPackageMonitor = new EuiccPackageMonitor(); 364 private final BroadcastReceiver mUserUnlockedReceiver = new BroadcastReceiver() { 365 @Override 366 public void onReceive(Context context, Intent intent) { 367 if (Intent.ACTION_USER_UNLOCKED.equals(intent.getAction())) { 368 // On user unlock, new components might become available, so rebind if needed. This 369 // can never make a component unavailable so there's never a need to force a 370 // rebind. 371 sendMessage(CMD_PACKAGE_CHANGE); 372 } 373 } 374 }; 375 376 /** Set to the current component we should bind to except in {@link UnavailableState}. */ 377 private @Nullable ServiceInfo mSelectedComponent; 378 379 /** Set to the currently connected EuiccService implementation in {@link ConnectedState}. */ 380 private @Nullable IEuiccService mEuiccService; 381 382 /** The callbacks for all (asynchronous) commands which are currently in flight. */ 383 private Set<BaseEuiccCommandCallback> mActiveCommandCallbacks = new ArraySet<>(); 384 385 @VisibleForTesting(visibility = PACKAGE) public UnavailableState mUnavailableState; 386 @VisibleForTesting(visibility = PACKAGE) public AvailableState mAvailableState; 387 @VisibleForTesting(visibility = PACKAGE) public BindingState mBindingState; 388 @VisibleForTesting(visibility = PACKAGE) public DisconnectedState mDisconnectedState; 389 @VisibleForTesting(visibility = PACKAGE) public ConnectedState mConnectedState; 390 EuiccConnector(Context context)391 EuiccConnector(Context context) { 392 super(TAG); 393 init(context); 394 } 395 396 @VisibleForTesting(visibility = PACKAGE) EuiccConnector(Context context, Looper looper)397 public EuiccConnector(Context context, Looper looper) { 398 super(TAG, looper); 399 init(context); 400 } 401 init(Context context)402 private void init(Context context) { 403 mContext = context; 404 mPm = context.getPackageManager(); 405 mTm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); 406 mSm = (SubscriptionManager) 407 context.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE); 408 409 // TODO(b/239277548): Disable debug logging after analysing this bug. 410 setDbg(true); 411 412 // Unavailable/Available both monitor for package changes and update mSelectedComponent but 413 // do not need to adjust the binding. 414 mUnavailableState = new UnavailableState(); 415 addState(mUnavailableState); 416 mAvailableState = new AvailableState(); 417 addState(mAvailableState, mUnavailableState); 418 419 mBindingState = new BindingState(); 420 addState(mBindingState); 421 422 // Disconnected/Connected both monitor for package changes and reestablish the active 423 // binding if necessary. 424 mDisconnectedState = new DisconnectedState(); 425 addState(mDisconnectedState); 426 mConnectedState = new ConnectedState(); 427 addState(mConnectedState, mDisconnectedState); 428 429 mSelectedComponent = findBestComponent(); 430 setInitialState(mSelectedComponent != null ? mAvailableState : mUnavailableState); 431 432 start(); 433 434 // All app package changes could trigger the package monitor receiver. It is not limited to 435 // apps extended from EuiccService. 436 mPackageMonitor.register(mContext, null /* thread */, null /* user */); 437 mContext.registerReceiver( 438 mUserUnlockedReceiver, new IntentFilter(Intent.ACTION_USER_UNLOCKED)); 439 } 440 441 @Override onHalting()442 public void onHalting() { 443 mPackageMonitor.unregister(); 444 mContext.unregisterReceiver(mUserUnlockedReceiver); 445 } 446 447 /** Asynchronously fetch the EID. */ 448 @VisibleForTesting(visibility = PACKAGE) getEid(int cardId, GetEidCommandCallback callback)449 public void getEid(int cardId, GetEidCommandCallback callback) { 450 sendMessage(CMD_GET_EID, cardId, 0 /* arg2 */, callback); 451 } 452 453 /** Asynchronously fetch the available memory in bytes. */ 454 @VisibleForTesting(visibility = PACKAGE) getAvailableMemoryInBytes( int cardId, GetAvailableMemoryInBytesCommandCallback callback)455 public void getAvailableMemoryInBytes( 456 int cardId, GetAvailableMemoryInBytesCommandCallback callback) { 457 sendMessage(CMD_GET_AVAILABLE_MEMORY_IN_BYTES, cardId, 0 /* arg2 */, callback); 458 } 459 460 /** Asynchronously get OTA status. */ 461 @VisibleForTesting(visibility = PACKAGE) getOtaStatus(int cardId, GetOtaStatusCommandCallback callback)462 public void getOtaStatus(int cardId, GetOtaStatusCommandCallback callback) { 463 sendMessage(CMD_GET_OTA_STATUS, cardId, 0 /* arg2 */, callback); 464 } 465 466 /** Asynchronously perform OTA update. */ 467 @VisibleForTesting(visibility = PACKAGE) startOtaIfNecessary(int cardId, OtaStatusChangedCallback callback)468 public void startOtaIfNecessary(int cardId, OtaStatusChangedCallback callback) { 469 sendMessage(CMD_START_OTA_IF_NECESSARY, cardId, 0 /* arg2 */, callback); 470 } 471 472 /** Asynchronously fetch metadata for the given downloadable subscription. */ 473 @VisibleForTesting(visibility = PACKAGE) getDownloadableSubscriptionMetadata(int cardId, int portIndex, DownloadableSubscription subscription, boolean switchAfterDownload, boolean forceDeactivateSim, GetMetadataCommandCallback callback)474 public void getDownloadableSubscriptionMetadata(int cardId, int portIndex, 475 DownloadableSubscription subscription, boolean switchAfterDownload, 476 boolean forceDeactivateSim, GetMetadataCommandCallback callback) { 477 GetMetadataRequest request = 478 new GetMetadataRequest(); 479 request.mSubscription = subscription; 480 request.mForceDeactivateSim = forceDeactivateSim; 481 request.mSwitchAfterDownload = switchAfterDownload; 482 request.mPortIndex = portIndex; 483 request.mCallback = callback; 484 sendMessage(CMD_GET_DOWNLOADABLE_SUBSCRIPTION_METADATA, cardId, 0 /* arg2 */, request); 485 } 486 487 /** Asynchronously download the given subscription. */ 488 @VisibleForTesting(visibility = PACKAGE) downloadSubscription(int cardId, int portIndex, DownloadableSubscription subscription, boolean switchAfterDownload, boolean forceDeactivateSim, Bundle resolvedBundle, DownloadCommandCallback callback)489 public void downloadSubscription(int cardId, int portIndex, 490 DownloadableSubscription subscription, boolean switchAfterDownload, 491 boolean forceDeactivateSim, Bundle resolvedBundle, DownloadCommandCallback callback) { 492 DownloadRequest request = new DownloadRequest(); 493 request.mSubscription = subscription; 494 request.mSwitchAfterDownload = switchAfterDownload; 495 request.mForceDeactivateSim = forceDeactivateSim; 496 request.mResolvedBundle = resolvedBundle; 497 request.mCallback = callback; 498 request.mPortIndex = portIndex; 499 sendMessage(CMD_DOWNLOAD_SUBSCRIPTION, cardId, 0 /* arg2 */, request); 500 } 501 getEuiccProfileInfoList(int cardId, GetEuiccProfileInfoListCommandCallback callback)502 void getEuiccProfileInfoList(int cardId, GetEuiccProfileInfoListCommandCallback callback) { 503 sendMessage(CMD_GET_EUICC_PROFILE_INFO_LIST, cardId, 0 /* arg2 */, callback); 504 } 505 506 /** Asynchronously fetch the default downloadable subscription list. */ 507 @VisibleForTesting(visibility = PACKAGE) getDefaultDownloadableSubscriptionList(int cardId, boolean forceDeactivateSim, GetDefaultListCommandCallback callback)508 public void getDefaultDownloadableSubscriptionList(int cardId, 509 boolean forceDeactivateSim, GetDefaultListCommandCallback callback) { 510 GetDefaultListRequest request = new GetDefaultListRequest(); 511 request.mForceDeactivateSim = forceDeactivateSim; 512 request.mCallback = callback; 513 sendMessage(CMD_GET_DEFAULT_DOWNLOADABLE_SUBSCRIPTION_LIST, cardId, 0 /* arg2 */, request); 514 } 515 516 /** Asynchronously fetch the {@link EuiccInfo}. */ 517 @VisibleForTesting(visibility = PACKAGE) getEuiccInfo(int cardId, GetEuiccInfoCommandCallback callback)518 public void getEuiccInfo(int cardId, GetEuiccInfoCommandCallback callback) { 519 sendMessage(CMD_GET_EUICC_INFO, cardId, 0 /* arg2 */, callback); 520 } 521 522 /** Asynchronously delete the given subscription. */ 523 @VisibleForTesting(visibility = PACKAGE) deleteSubscription(int cardId, String iccid, DeleteCommandCallback callback)524 public void deleteSubscription(int cardId, String iccid, DeleteCommandCallback callback) { 525 DeleteRequest request = new DeleteRequest(); 526 request.mIccid = iccid; 527 request.mCallback = callback; 528 sendMessage(CMD_DELETE_SUBSCRIPTION, cardId, 0 /* arg2 */, request); 529 } 530 531 /** Asynchronously switch to the given subscription. */ 532 @VisibleForTesting(visibility = PACKAGE) switchToSubscription(int cardId, int portIndex, @Nullable String iccid, boolean forceDeactivateSim, SwitchCommandCallback callback, boolean usePortIndex)533 public void switchToSubscription(int cardId, int portIndex, @Nullable String iccid, 534 boolean forceDeactivateSim, SwitchCommandCallback callback, boolean usePortIndex) { 535 SwitchRequest request = new SwitchRequest(); 536 request.mIccid = iccid; 537 request.mForceDeactivateSim = forceDeactivateSim; 538 request.mCallback = callback; 539 request.mUsePortIndex = usePortIndex; 540 sendMessage(CMD_SWITCH_TO_SUBSCRIPTION, cardId, portIndex, request); 541 } 542 543 /** Asynchronously update the nickname of the given subscription. */ 544 @VisibleForTesting(visibility = PACKAGE) updateSubscriptionNickname(int cardId, String iccid, String nickname, UpdateNicknameCommandCallback callback)545 public void updateSubscriptionNickname(int cardId, 546 String iccid, String nickname, UpdateNicknameCommandCallback callback) { 547 UpdateNicknameRequest request = new UpdateNicknameRequest(); 548 request.mIccid = iccid; 549 request.mNickname = nickname; 550 request.mCallback = callback; 551 sendMessage(CMD_UPDATE_SUBSCRIPTION_NICKNAME, cardId, 0 /* arg2 */, request); 552 } 553 554 /** Asynchronously erase operational profiles on the eUICC. */ 555 @VisibleForTesting(visibility = PACKAGE) eraseSubscriptions(int cardId, EraseCommandCallback callback)556 public void eraseSubscriptions(int cardId, EraseCommandCallback callback) { 557 sendMessage(CMD_ERASE_SUBSCRIPTIONS, cardId, 0 /* arg2 */, callback); 558 } 559 560 /** Asynchronously erase specific profiles on the eUICC. */ 561 @VisibleForTesting(visibility = PACKAGE) eraseSubscriptionsWithOptions( int cardId, @ResetOption int options, EraseCommandCallback callback)562 public void eraseSubscriptionsWithOptions( 563 int cardId, @ResetOption int options, EraseCommandCallback callback) { 564 sendMessage(CMD_ERASE_SUBSCRIPTIONS_WITH_OPTIONS, cardId, options, callback); 565 } 566 567 /** Asynchronously ensure that all profiles will be retained on the next factory reset. */ 568 @VisibleForTesting(visibility = PACKAGE) retainSubscriptions(int cardId, RetainSubscriptionsCommandCallback callback)569 public void retainSubscriptions(int cardId, RetainSubscriptionsCommandCallback callback) { 570 sendMessage(CMD_RETAIN_SUBSCRIPTIONS, cardId, 0 /* arg2 */, callback); 571 } 572 573 /** Asynchronously calls the currently bound EuiccService implementation to dump its states */ 574 @VisibleForTesting(visibility = PACKAGE) dumpEuiccService(DumpEuiccServiceCommandCallback callback)575 public void dumpEuiccService(DumpEuiccServiceCommandCallback callback) { 576 sendMessage(CMD_DUMP_EUICC_SERVICE, TelephonyManager.UNSUPPORTED_CARD_ID /* ignored */, 577 0 /* arg2 */, 578 callback); 579 } 580 581 @VisibleForTesting getBinder()582 public final IEuiccService getBinder() { 583 return mEuiccService; 584 } 585 586 /** 587 * State in which no EuiccService is available. 588 * 589 * <p>All incoming commands will be rejected through 590 * {@link BaseEuiccCommandCallback#onEuiccServiceUnavailable()}. 591 * 592 * <p>Package state changes will lead to transitions between {@link UnavailableState} and 593 * {@link AvailableState} depending on whether an EuiccService becomes unavailable or 594 * available. 595 */ 596 private class UnavailableState extends State { 597 @Override processMessage(Message message)598 public boolean processMessage(Message message) { 599 if (message.what == CMD_PACKAGE_CHANGE) { 600 mSelectedComponent = findBestComponent(); 601 if (mSelectedComponent != null) { 602 transitionTo(mAvailableState); 603 updateSubscriptionInfoListForAllAccessibleEuiccs(); 604 } else if (getCurrentState() != mUnavailableState) { 605 transitionTo(mUnavailableState); 606 } 607 return HANDLED; 608 } else if (isEuiccCommand(message.what)) { 609 BaseEuiccCommandCallback callback = getCallback(message); 610 callback.onEuiccServiceUnavailable(); 611 return HANDLED; 612 } 613 614 return NOT_HANDLED; 615 } 616 } 617 618 /** 619 * State in which a EuiccService is available, but no binding is established or in the process 620 * of being established. 621 * 622 * <p>If a command is received, this state will defer the message and enter {@link BindingState} 623 * to bring up the binding. 624 */ 625 private class AvailableState extends State { 626 @Override processMessage(Message message)627 public boolean processMessage(Message message) { 628 if (isEuiccCommand(message.what)) { 629 deferMessage(message); 630 transitionTo(mBindingState); 631 return HANDLED; 632 } 633 634 return NOT_HANDLED; 635 } 636 } 637 638 /** 639 * State in which we are binding to the current EuiccService. 640 * 641 * <p>This is a transient state. If bindService returns true, we enter {@link DisconnectedState} 642 * while waiting for the binding to be established. If it returns false, we move back to 643 * {@link AvailableState}. 644 * 645 * <p>Any received messages will be deferred. 646 */ 647 private class BindingState extends State { 648 @Override enter()649 public void enter() { 650 if (createBinding()) { 651 transitionTo(mDisconnectedState); 652 } else { 653 // createBinding() should generally not return false since we've already performed 654 // Intent resolution, but it's always possible that the package state changes 655 // asynchronously. Transition to available for now, and if the package state has 656 // changed, we'll process that event and move to mUnavailableState as needed. 657 transitionTo(mAvailableState); 658 } 659 } 660 661 @Override processMessage(Message message)662 public boolean processMessage(Message message) { 663 deferMessage(message); 664 return HANDLED; 665 } 666 } 667 668 /** 669 * State in which a binding is established, but not currently connected. 670 * 671 * <p>We wait up to {@link #BIND_TIMEOUT_MILLIS} for the binding to establish. If it doesn't, 672 * we go back to {@link AvailableState} to try again. 673 * 674 * <p>Package state changes will cause us to unbind and move to {@link BindingState} to 675 * reestablish the binding if the selected component has changed or if a forced rebind is 676 * necessary. 677 * 678 * <p>Any received commands will be deferred. 679 */ 680 private class DisconnectedState extends State { 681 @Override enter()682 public void enter() { 683 sendMessageDelayed(CMD_CONNECT_TIMEOUT, BIND_TIMEOUT_MILLIS); 684 } 685 686 @Override processMessage(Message message)687 public boolean processMessage(Message message) { 688 if (message.what == CMD_SERVICE_CONNECTED) { 689 mEuiccService = (IEuiccService) message.obj; 690 transitionTo(mConnectedState); 691 return HANDLED; 692 } else if (message.what == CMD_PACKAGE_CHANGE) { 693 ServiceInfo bestComponent = findBestComponent(); 694 String affectedPackage = (String) message.obj; 695 boolean isSameComponent; 696 if (bestComponent == null) { 697 isSameComponent = mSelectedComponent != null; 698 } else { 699 // Checks whether the bound component is the same as the best component. If it 700 // is not, set isSameComponent to false and the connector will bind the best 701 // component instead. 702 isSameComponent = mSelectedComponent == null 703 || Objects.equals(new ComponentName(bestComponent.packageName, 704 bestComponent.name), 705 new ComponentName(mSelectedComponent.packageName, mSelectedComponent.name)); 706 } 707 // Checks whether the bound component is impacted by the package changes. If it is, 708 // change the forceRebind to true so the connector will re-bind the component. 709 boolean forceRebind = bestComponent != null 710 && Objects.equals(bestComponent.packageName, affectedPackage); 711 if (!isSameComponent || forceRebind) { 712 unbind(); 713 mSelectedComponent = bestComponent; 714 if (mSelectedComponent == null) { 715 transitionTo(mUnavailableState); 716 } else { 717 transitionTo(mBindingState); 718 } 719 updateSubscriptionInfoListForAllAccessibleEuiccs(); 720 } 721 return HANDLED; 722 } else if (message.what == CMD_CONNECT_TIMEOUT) { 723 unbind(); 724 transitionTo(mAvailableState); 725 return HANDLED; 726 } else if (isEuiccCommand(message.what)) { 727 deferMessage(message); 728 return HANDLED; 729 } 730 731 return NOT_HANDLED; 732 } 733 } 734 735 /** 736 * State in which the binding is connected. 737 * 738 * <p>Commands will be processed as long as we're in this state. We wait up to 739 * {@link #LINGER_TIMEOUT_MILLIS} between commands; if this timeout is reached, we will drop the 740 * binding until the next command is received. 741 */ 742 private class ConnectedState extends State { 743 @Override enter()744 public void enter() { 745 removeMessages(CMD_CONNECT_TIMEOUT); 746 sendMessageDelayed(CMD_LINGER_TIMEOUT, LINGER_TIMEOUT_MILLIS); 747 } 748 749 @Override processMessage(Message message)750 public boolean processMessage(Message message) { 751 if (message.what == CMD_SERVICE_DISCONNECTED) { 752 EuiccSession.get(mContext).endAllSessions(); 753 mEuiccService = null; 754 transitionTo(mDisconnectedState); 755 return HANDLED; 756 } else if (message.what == CMD_LINGER_TIMEOUT) { 757 EuiccSession.get(mContext).endAllSessions(); 758 unbind(); 759 transitionTo(mAvailableState); 760 return HANDLED; 761 } else if (message.what == CMD_COMMAND_COMPLETE) { 762 Runnable runnable = (Runnable) message.obj; 763 runnable.run(); 764 return HANDLED; 765 } else if (isEuiccCommand(message.what)) { 766 final BaseEuiccCommandCallback callback = getCallback(message); 767 onCommandStart(callback); 768 final int cardId = message.arg1; 769 final int slotId = getSlotIdFromCardId(cardId); 770 try { 771 switch (message.what) { 772 case CMD_GET_EID: { 773 mEuiccService.getEid(slotId, 774 new IGetEidCallback.Stub() { 775 @Override 776 public void onSuccess(String eid) { 777 sendMessage(CMD_COMMAND_COMPLETE, (Runnable) () -> { 778 ((GetEidCommandCallback) callback) 779 .onGetEidComplete(eid); 780 onCommandEnd(callback); 781 }); 782 } 783 }); 784 break; 785 } 786 case CMD_GET_AVAILABLE_MEMORY_IN_BYTES: { 787 mEuiccService.getAvailableMemoryInBytes(slotId, 788 new IGetAvailableMemoryInBytesCallback.Stub() { 789 @Override 790 public void onSuccess(long availableMemoryInBytes) { 791 sendMessage(CMD_COMMAND_COMPLETE, (Runnable) () -> { 792 ((GetAvailableMemoryInBytesCommandCallback) 793 callback) 794 .onGetAvailableMemoryInBytesComplete( 795 availableMemoryInBytes); 796 onCommandEnd(callback); 797 }); 798 } 799 800 @Override 801 public void onUnsupportedOperationException( 802 String message) { 803 sendMessage(CMD_COMMAND_COMPLETE, (Runnable) () -> { 804 ((GetAvailableMemoryInBytesCommandCallback) 805 callback) 806 .onUnsupportedOperationExceptionComplete( 807 message); 808 onCommandEnd(callback); 809 }); 810 } 811 }); 812 break; 813 } 814 case CMD_GET_DOWNLOADABLE_SUBSCRIPTION_METADATA: { 815 GetMetadataRequest request = (GetMetadataRequest) message.obj; 816 mEuiccService.getDownloadableSubscriptionMetadata(slotId, 817 request.mPortIndex, 818 request.mSubscription, 819 request.mSwitchAfterDownload, 820 request.mForceDeactivateSim, 821 new IGetDownloadableSubscriptionMetadataCallback.Stub() { 822 @Override 823 public void onComplete( 824 GetDownloadableSubscriptionMetadataResult result) { 825 sendMessage(CMD_COMMAND_COMPLETE, (Runnable) () -> { 826 ((GetMetadataCommandCallback) callback) 827 .onGetMetadataComplete(cardId, result); 828 onCommandEnd(callback); 829 }); 830 } 831 }); 832 break; 833 } 834 case CMD_DOWNLOAD_SUBSCRIPTION: { 835 DownloadRequest request = (DownloadRequest) message.obj; 836 EuiccSession.get(mContext).startSession(EuiccSession.DOWNLOAD); 837 mEuiccService.downloadSubscription(slotId, 838 request.mPortIndex, 839 request.mSubscription, 840 request.mSwitchAfterDownload, 841 request.mForceDeactivateSim, 842 request.mResolvedBundle, 843 new IDownloadSubscriptionCallback.Stub() { 844 @Override 845 public void onComplete(DownloadSubscriptionResult result) { 846 sendMessage(CMD_COMMAND_COMPLETE, (Runnable) () -> { 847 ((DownloadCommandCallback) callback) 848 .onDownloadComplete(result); 849 onCommandEnd(callback); 850 }); 851 EuiccSession.get(mContext) 852 .endSession(EuiccSession.DOWNLOAD); 853 } 854 }); 855 break; 856 } 857 case CMD_GET_EUICC_PROFILE_INFO_LIST: { 858 mEuiccService.getEuiccProfileInfoList(slotId, 859 new IGetEuiccProfileInfoListCallback.Stub() { 860 @Override 861 public void onComplete( 862 GetEuiccProfileInfoListResult result) { 863 sendMessage(CMD_COMMAND_COMPLETE, (Runnable) () -> { 864 ((GetEuiccProfileInfoListCommandCallback) callback) 865 .onListComplete(result); 866 onCommandEnd(callback); 867 }); 868 } 869 }); 870 break; 871 } 872 case CMD_GET_DEFAULT_DOWNLOADABLE_SUBSCRIPTION_LIST: { 873 GetDefaultListRequest request = (GetDefaultListRequest) message.obj; 874 mEuiccService.getDefaultDownloadableSubscriptionList(slotId, 875 request.mForceDeactivateSim, 876 new IGetDefaultDownloadableSubscriptionListCallback.Stub() { 877 @Override 878 public void onComplete( 879 GetDefaultDownloadableSubscriptionListResult result 880 ) { 881 sendMessage(CMD_COMMAND_COMPLETE, (Runnable) () -> { 882 ((GetDefaultListCommandCallback) callback) 883 .onGetDefaultListComplete(cardId, result); 884 onCommandEnd(callback); 885 }); 886 } 887 }); 888 break; 889 } 890 case CMD_GET_EUICC_INFO: { 891 mEuiccService.getEuiccInfo(slotId, 892 new IGetEuiccInfoCallback.Stub() { 893 @Override 894 public void onSuccess(EuiccInfo euiccInfo) { 895 sendMessage(CMD_COMMAND_COMPLETE, (Runnable) () -> { 896 ((GetEuiccInfoCommandCallback) callback) 897 .onGetEuiccInfoComplete(euiccInfo); 898 onCommandEnd(callback); 899 }); 900 } 901 }); 902 break; 903 } 904 case CMD_DELETE_SUBSCRIPTION: { 905 DeleteRequest request = (DeleteRequest) message.obj; 906 mEuiccService.deleteSubscription(slotId, request.mIccid, 907 new IDeleteSubscriptionCallback.Stub() { 908 @Override 909 public void onComplete(int result) { 910 sendMessage(CMD_COMMAND_COMPLETE, (Runnable) () -> { 911 ((DeleteCommandCallback) callback) 912 .onDeleteComplete(result); 913 onCommandEnd(callback); 914 }); 915 } 916 }); 917 break; 918 } 919 case CMD_SWITCH_TO_SUBSCRIPTION: { 920 SwitchRequest request = (SwitchRequest) message.obj; 921 final int portIndex = message.arg2; 922 mEuiccService.switchToSubscription(slotId, portIndex, 923 request.mIccid, 924 request.mForceDeactivateSim, 925 new ISwitchToSubscriptionCallback.Stub() { 926 @Override 927 public void onComplete(int result) { 928 sendMessage(CMD_COMMAND_COMPLETE, (Runnable) () -> { 929 ((SwitchCommandCallback) callback) 930 .onSwitchComplete(result); 931 onCommandEnd(callback); 932 }); 933 } 934 }, 935 request.mUsePortIndex); 936 break; 937 } 938 case CMD_UPDATE_SUBSCRIPTION_NICKNAME: { 939 UpdateNicknameRequest request = (UpdateNicknameRequest) message.obj; 940 mEuiccService.updateSubscriptionNickname(slotId, request.mIccid, 941 request.mNickname, 942 new IUpdateSubscriptionNicknameCallback.Stub() { 943 @Override 944 public void onComplete(int result) { 945 sendMessage(CMD_COMMAND_COMPLETE, (Runnable) () -> { 946 ((UpdateNicknameCommandCallback) callback) 947 .onUpdateNicknameComplete(result); 948 onCommandEnd(callback); 949 }); 950 } 951 }); 952 break; 953 } 954 case CMD_ERASE_SUBSCRIPTIONS: { 955 mEuiccService.eraseSubscriptions(slotId, 956 new IEraseSubscriptionsCallback.Stub() { 957 @Override 958 public void onComplete(int result) { 959 sendMessage(CMD_COMMAND_COMPLETE, (Runnable) () -> { 960 ((EraseCommandCallback) callback) 961 .onEraseComplete(result); 962 onCommandEnd(callback); 963 }); 964 } 965 }); 966 break; 967 } 968 case CMD_ERASE_SUBSCRIPTIONS_WITH_OPTIONS: { 969 mEuiccService.eraseSubscriptionsWithOptions(slotId, 970 message.arg2 /* options */, 971 new IEraseSubscriptionsCallback.Stub() { 972 @Override 973 public void onComplete(int result) { 974 sendMessage(CMD_COMMAND_COMPLETE, (Runnable) () -> { 975 ((EraseCommandCallback) callback) 976 .onEraseComplete(result); 977 onCommandEnd(callback); 978 }); 979 } 980 }); 981 break; 982 } 983 case CMD_RETAIN_SUBSCRIPTIONS: { 984 mEuiccService.retainSubscriptionsForFactoryReset(slotId, 985 new IRetainSubscriptionsForFactoryResetCallback.Stub() { 986 @Override 987 public void onComplete(int result) { 988 sendMessage(CMD_COMMAND_COMPLETE, (Runnable) () -> { 989 ((RetainSubscriptionsCommandCallback) callback) 990 .onRetainSubscriptionsComplete(result); 991 onCommandEnd(callback); 992 }); 993 } 994 }); 995 break; 996 } 997 case CMD_GET_OTA_STATUS: { 998 mEuiccService.getOtaStatus(slotId, 999 new IGetOtaStatusCallback.Stub() { 1000 @Override 1001 public void onSuccess(@OtaStatus int status) { 1002 sendMessage(CMD_COMMAND_COMPLETE, (Runnable) () -> { 1003 ((GetOtaStatusCommandCallback) callback) 1004 .onGetOtaStatusComplete(status); 1005 onCommandEnd(callback); 1006 }); 1007 } 1008 }); 1009 break; 1010 } 1011 case CMD_START_OTA_IF_NECESSARY: { 1012 mEuiccService.startOtaIfNecessary(slotId, 1013 new IOtaStatusChangedCallback.Stub() { 1014 @Override 1015 public void onOtaStatusChanged(int status) 1016 throws RemoteException { 1017 if (status == EuiccManager.EUICC_OTA_IN_PROGRESS) { 1018 sendMessage(CMD_COMMAND_COMPLETE, (Runnable) () -> { 1019 ((OtaStatusChangedCallback) callback) 1020 .onOtaStatusChanged(status); 1021 }); 1022 } else { 1023 sendMessage(CMD_COMMAND_COMPLETE, (Runnable) () -> { 1024 ((OtaStatusChangedCallback) callback) 1025 .onOtaStatusChanged(status); 1026 onCommandEnd(callback); 1027 }); 1028 } 1029 } 1030 }); 1031 break; 1032 } 1033 case CMD_DUMP_EUICC_SERVICE: { 1034 mEuiccService.dump(new IEuiccServiceDumpResultCallback.Stub() { 1035 @Override 1036 public void onComplete(String logs) 1037 throws RemoteException { 1038 sendMessage(CMD_COMMAND_COMPLETE, (Runnable) () -> { 1039 ((DumpEuiccServiceCommandCallback) callback) 1040 .onDumpEuiccServiceComplete(logs); 1041 onCommandEnd(callback); 1042 }); 1043 } 1044 }); 1045 break; 1046 } 1047 default: { 1048 Log.wtf(TAG, "Unimplemented eUICC command: " + message.what); 1049 callback.onEuiccServiceUnavailable(); 1050 onCommandEnd(callback); 1051 return HANDLED; 1052 } 1053 } 1054 } catch (Exception e) { 1055 // If this is a RemoteException, we expect to be disconnected soon. For other 1056 // exceptions, this is a bug in the EuiccService implementation, but we must 1057 // not let it crash the phone process. 1058 Log.w(TAG, "Exception making binder call to EuiccService", e); 1059 callback.onEuiccServiceUnavailable(); 1060 onCommandEnd(callback); 1061 } 1062 1063 return HANDLED; 1064 } 1065 1066 return NOT_HANDLED; 1067 } 1068 1069 @Override exit()1070 public void exit() { 1071 removeMessages(CMD_LINGER_TIMEOUT); 1072 // Dispatch callbacks for all in-flight commands; they will no longer succeed. (The 1073 // remote process cannot possibly trigger a callback at this stage because the 1074 // connection has dropped). 1075 for (BaseEuiccCommandCallback callback : mActiveCommandCallbacks) { 1076 callback.onEuiccServiceUnavailable(); 1077 } 1078 mActiveCommandCallbacks.clear(); 1079 } 1080 } 1081 getCallback(Message message)1082 private static BaseEuiccCommandCallback getCallback(Message message) { 1083 switch (message.what) { 1084 case CMD_GET_EID: 1085 case CMD_GET_EUICC_PROFILE_INFO_LIST: 1086 case CMD_GET_EUICC_INFO: 1087 case CMD_ERASE_SUBSCRIPTIONS: 1088 case CMD_ERASE_SUBSCRIPTIONS_WITH_OPTIONS: 1089 case CMD_RETAIN_SUBSCRIPTIONS: 1090 case CMD_GET_OTA_STATUS: 1091 case CMD_START_OTA_IF_NECESSARY: 1092 case CMD_DUMP_EUICC_SERVICE: 1093 case CMD_GET_AVAILABLE_MEMORY_IN_BYTES: 1094 return (BaseEuiccCommandCallback) message.obj; 1095 case CMD_GET_DOWNLOADABLE_SUBSCRIPTION_METADATA: 1096 return ((GetMetadataRequest) message.obj).mCallback; 1097 case CMD_DOWNLOAD_SUBSCRIPTION: 1098 return ((DownloadRequest) message.obj).mCallback; 1099 case CMD_GET_DEFAULT_DOWNLOADABLE_SUBSCRIPTION_LIST: 1100 return ((GetDefaultListRequest) message.obj).mCallback; 1101 case CMD_DELETE_SUBSCRIPTION: 1102 return ((DeleteRequest) message.obj).mCallback; 1103 case CMD_SWITCH_TO_SUBSCRIPTION: 1104 return ((SwitchRequest) message.obj).mCallback; 1105 case CMD_UPDATE_SUBSCRIPTION_NICKNAME: 1106 return ((UpdateNicknameRequest) message.obj).mCallback; 1107 default: 1108 throw new IllegalArgumentException("Unsupported message: " + message.what); 1109 } 1110 } 1111 1112 /** 1113 * Gets the slot ID from the card ID. 1114 */ getSlotIdFromCardId(int cardId)1115 private int getSlotIdFromCardId(int cardId) { 1116 if (cardId == TelephonyManager.UNSUPPORTED_CARD_ID 1117 || cardId == TelephonyManager.UNINITIALIZED_CARD_ID) { 1118 return SubscriptionManager.INVALID_SIM_SLOT_INDEX; 1119 } 1120 TelephonyManager tm = (TelephonyManager) 1121 mContext.getSystemService(Context.TELEPHONY_SERVICE); 1122 UiccSlotInfo[] slotInfos = tm.getUiccSlotsInfo(); 1123 if (slotInfos == null || slotInfos.length == 0) { 1124 Log.e(TAG, "UiccSlotInfo is null or empty"); 1125 return SubscriptionManager.INVALID_SIM_SLOT_INDEX; 1126 } 1127 String cardIdString = UiccController.getInstance().convertToCardString(cardId); 1128 for (int slotIndex = 0; slotIndex < slotInfos.length; slotIndex++) { 1129 // Report Anomaly in case UiccSlotInfo is not. 1130 if (slotInfos[slotIndex] == null) { 1131 Log.i(TAG, "No UiccSlotInfo found for slotIndex: " + slotIndex); 1132 return SubscriptionManager.INVALID_SIM_SLOT_INDEX; 1133 } 1134 String retrievedCardId = slotInfos[slotIndex] != null 1135 ? slotInfos[slotIndex].getCardId() : null; 1136 if (IccUtils.compareIgnoreTrailingFs(cardIdString, retrievedCardId)) { 1137 return slotIndex; 1138 } 1139 } 1140 Log.i(TAG, "No UiccSlotInfo found for cardId: " + cardId); 1141 return SubscriptionManager.INVALID_SIM_SLOT_INDEX; 1142 } 1143 1144 /** Call this at the beginning of the execution of any command. */ onCommandStart(BaseEuiccCommandCallback callback)1145 private void onCommandStart(BaseEuiccCommandCallback callback) { 1146 mActiveCommandCallbacks.add(callback); 1147 removeMessages(CMD_LINGER_TIMEOUT); 1148 } 1149 1150 /** Call this at the end of execution of any command (whether or not it succeeded). */ onCommandEnd(BaseEuiccCommandCallback callback)1151 private void onCommandEnd(BaseEuiccCommandCallback callback) { 1152 if (!mActiveCommandCallbacks.remove(callback)) { 1153 Log.wtf(TAG, "Callback already removed from mActiveCommandCallbacks"); 1154 } 1155 if (mActiveCommandCallbacks.isEmpty()) { 1156 sendMessageDelayed(CMD_LINGER_TIMEOUT, LINGER_TIMEOUT_MILLIS); 1157 } 1158 } 1159 1160 /** Return the service info of the EuiccService to bind to, or null if none were found. */ 1161 @Nullable findBestComponent()1162 private ServiceInfo findBestComponent() { 1163 return (ServiceInfo) findBestComponent(mPm); 1164 } 1165 1166 /** 1167 * Bring up a binding to the currently-selected component. 1168 * 1169 * <p>Returns true if we've successfully bound to the service. 1170 */ createBinding()1171 private boolean createBinding() { 1172 if (mSelectedComponent == null) { 1173 Log.wtf(TAG, "Attempting to create binding but no component is selected"); 1174 return false; 1175 } 1176 Intent intent = new Intent(EuiccService.EUICC_SERVICE_INTERFACE); 1177 intent.setComponent(new ComponentName(mSelectedComponent.packageName, 1178 mSelectedComponent.name)); 1179 // We bind this as a foreground service because it is operating directly on the SIM, and we 1180 // do not want it subjected to power-savings restrictions while doing so. 1181 return mContext.bindService(intent, this, 1182 Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE); 1183 } 1184 unbind()1185 private void unbind() { 1186 mEuiccService = null; 1187 mContext.unbindService(this); 1188 } 1189 findBestComponent( PackageManager packageManager, List<ResolveInfo> resolveInfoList)1190 private static ComponentInfo findBestComponent( 1191 PackageManager packageManager, List<ResolveInfo> resolveInfoList) { 1192 int bestPriority = Integer.MIN_VALUE; 1193 ComponentInfo bestComponent = null; 1194 if (resolveInfoList != null) { 1195 for (ResolveInfo resolveInfo : resolveInfoList) { 1196 if (!isValidEuiccComponent(packageManager, resolveInfo)) { 1197 continue; 1198 } 1199 1200 if (resolveInfo.filter.getPriority() > bestPriority) { 1201 bestPriority = resolveInfo.filter.getPriority(); 1202 bestComponent = TelephonyUtils.getComponentInfo(resolveInfo); 1203 } 1204 } 1205 } 1206 1207 return bestComponent; 1208 } 1209 isValidEuiccComponent( PackageManager packageManager, ResolveInfo resolveInfo)1210 private static boolean isValidEuiccComponent( 1211 PackageManager packageManager, ResolveInfo resolveInfo) { 1212 ComponentInfo componentInfo = TelephonyUtils.getComponentInfo(resolveInfo); 1213 String packageName = new ComponentName(componentInfo.packageName, componentInfo.name) 1214 .getPackageName(); 1215 1216 // Verify that the app is privileged (via granting of a privileged permission). 1217 if (packageManager.checkPermission( 1218 Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS, packageName) 1219 != PackageManager.PERMISSION_GRANTED) { 1220 Log.wtf(TAG, "Package " + packageName 1221 + " does not declare WRITE_EMBEDDED_SUBSCRIPTIONS"); 1222 return false; 1223 } 1224 1225 // Verify that only the system can access the component. 1226 final String permission; 1227 if (componentInfo instanceof ServiceInfo) { 1228 permission = ((ServiceInfo) componentInfo).permission; 1229 } else if (componentInfo instanceof ActivityInfo) { 1230 permission = ((ActivityInfo) componentInfo).permission; 1231 } else { 1232 throw new IllegalArgumentException("Can only verify services/activities"); 1233 } 1234 if (!TextUtils.equals(permission, Manifest.permission.BIND_EUICC_SERVICE)) { 1235 Log.wtf(TAG, "Package " + packageName 1236 + " does not require the BIND_EUICC_SERVICE permission"); 1237 return false; 1238 } 1239 1240 // Verify that the component declares a priority. 1241 if (resolveInfo.filter == null || resolveInfo.filter.getPriority() == 0) { 1242 Log.wtf(TAG, "Package " + packageName + " does not specify a priority"); 1243 return false; 1244 } 1245 return true; 1246 } 1247 1248 @Override onServiceConnected(ComponentName name, IBinder service)1249 public void onServiceConnected(ComponentName name, IBinder service) { 1250 IEuiccService euiccService = IEuiccService.Stub.asInterface(service); 1251 sendMessage(CMD_SERVICE_CONNECTED, euiccService); 1252 } 1253 1254 @Override onServiceDisconnected(ComponentName name)1255 public void onServiceDisconnected(ComponentName name) { 1256 sendMessage(CMD_SERVICE_DISCONNECTED); 1257 } 1258 1259 private class EuiccPackageMonitor extends PackageChangeReceiver { 1260 @Override onPackageAdded(String packageName)1261 public void onPackageAdded(String packageName) { 1262 sendPackageChange(packageName, true /* forceUnbindForThisPackage */); 1263 } 1264 1265 @Override onPackageRemoved(String packageName)1266 public void onPackageRemoved(String packageName) { 1267 sendPackageChange(packageName, true /* forceUnbindForThisPackage */); 1268 } 1269 1270 @Override onPackageUpdateFinished(String packageName)1271 public void onPackageUpdateFinished(String packageName) { 1272 sendPackageChange(packageName, true /* forceUnbindForThisPackage */); 1273 } 1274 1275 @Override onPackageModified(String packageName)1276 public void onPackageModified(String packageName) { 1277 sendPackageChange(packageName, false /* forceUnbindForThisPackage */); 1278 } 1279 1280 @Override onHandleForceStop(String[] packages, boolean doit)1281 public void onHandleForceStop(String[] packages, boolean doit) { 1282 if (doit) { 1283 for (String packageName : packages) { 1284 sendPackageChange(packageName, true /* forceUnbindForThisPackage */); 1285 } 1286 } 1287 } 1288 sendPackageChange(String packageName, boolean forceUnbindForThisPackage)1289 private void sendPackageChange(String packageName, boolean forceUnbindForThisPackage) { 1290 sendMessage(CMD_PACKAGE_CHANGE, forceUnbindForThisPackage ? packageName : null); 1291 } 1292 } 1293 1294 @Override unhandledMessage(Message msg)1295 protected void unhandledMessage(Message msg) { 1296 IState state = getCurrentState(); 1297 Log.wtf(TAG, "Unhandled message " + msg.what + " in state " 1298 + (state == null ? "null" : state.getName())); 1299 AnomalyReporter.reportAnomaly( 1300 UUID.fromString("0db20514-5fa1-4e62-a7b7-2acf5f92c957"), 1301 "EuiccConnector: Found unhandledMessage " + String.valueOf(msg.what)); 1302 } 1303 1304 @Override dump(FileDescriptor fd, PrintWriter pw, String[] args)1305 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1306 super.dump(fd, pw, args); 1307 pw.println("mSelectedComponent=" + mSelectedComponent); 1308 pw.println("mEuiccService=" + mEuiccService); 1309 pw.println("mActiveCommandCount=" + mActiveCommandCallbacks.size()); 1310 } 1311 updateSubscriptionInfoListForAllAccessibleEuiccs()1312 private void updateSubscriptionInfoListForAllAccessibleEuiccs() { 1313 if (mTm.getCardIdForDefaultEuicc() == TelephonyManager.UNSUPPORTED_CARD_ID) { 1314 // Device does not support card ID 1315 mSm.requestEmbeddedSubscriptionInfoListRefresh(); 1316 } else { 1317 for (UiccCardInfo cardInfo : mTm.getUiccCardsInfo()) { 1318 if (cardInfo.isEuicc()) { 1319 mSm.requestEmbeddedSubscriptionInfoListRefresh(cardInfo.getCardId()); 1320 } 1321 } 1322 } 1323 } 1324 } 1325