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 mEuiccService = null; 753 transitionTo(mDisconnectedState); 754 return HANDLED; 755 } else if (message.what == CMD_LINGER_TIMEOUT) { 756 unbind(); 757 transitionTo(mAvailableState); 758 return HANDLED; 759 } else if (message.what == CMD_COMMAND_COMPLETE) { 760 Runnable runnable = (Runnable) message.obj; 761 runnable.run(); 762 return HANDLED; 763 } else if (isEuiccCommand(message.what)) { 764 final BaseEuiccCommandCallback callback = getCallback(message); 765 onCommandStart(callback); 766 final int cardId = message.arg1; 767 final int slotId = getSlotIdFromCardId(cardId); 768 try { 769 switch (message.what) { 770 case CMD_GET_EID: { 771 mEuiccService.getEid(slotId, 772 new IGetEidCallback.Stub() { 773 @Override 774 public void onSuccess(String eid) { 775 sendMessage(CMD_COMMAND_COMPLETE, (Runnable) () -> { 776 ((GetEidCommandCallback) callback) 777 .onGetEidComplete(eid); 778 onCommandEnd(callback); 779 }); 780 } 781 }); 782 break; 783 } 784 case CMD_GET_AVAILABLE_MEMORY_IN_BYTES: { 785 mEuiccService.getAvailableMemoryInBytes(slotId, 786 new IGetAvailableMemoryInBytesCallback.Stub() { 787 @Override 788 public void onSuccess(long availableMemoryInBytes) { 789 sendMessage(CMD_COMMAND_COMPLETE, (Runnable) () -> { 790 ((GetAvailableMemoryInBytesCommandCallback) 791 callback) 792 .onGetAvailableMemoryInBytesComplete( 793 availableMemoryInBytes); 794 onCommandEnd(callback); 795 }); 796 } 797 798 @Override 799 public void onUnsupportedOperationException( 800 String message) { 801 sendMessage(CMD_COMMAND_COMPLETE, (Runnable) () -> { 802 ((GetAvailableMemoryInBytesCommandCallback) 803 callback) 804 .onUnsupportedOperationExceptionComplete( 805 message); 806 onCommandEnd(callback); 807 }); 808 } 809 }); 810 break; 811 } 812 case CMD_GET_DOWNLOADABLE_SUBSCRIPTION_METADATA: { 813 GetMetadataRequest request = (GetMetadataRequest) message.obj; 814 mEuiccService.getDownloadableSubscriptionMetadata(slotId, 815 request.mPortIndex, 816 request.mSubscription, 817 request.mSwitchAfterDownload, 818 request.mForceDeactivateSim, 819 new IGetDownloadableSubscriptionMetadataCallback.Stub() { 820 @Override 821 public void onComplete( 822 GetDownloadableSubscriptionMetadataResult result) { 823 sendMessage(CMD_COMMAND_COMPLETE, (Runnable) () -> { 824 ((GetMetadataCommandCallback) callback) 825 .onGetMetadataComplete(cardId, result); 826 onCommandEnd(callback); 827 }); 828 } 829 }); 830 break; 831 } 832 case CMD_DOWNLOAD_SUBSCRIPTION: { 833 DownloadRequest request = (DownloadRequest) message.obj; 834 mEuiccService.downloadSubscription(slotId, 835 request.mPortIndex, 836 request.mSubscription, 837 request.mSwitchAfterDownload, 838 request.mForceDeactivateSim, 839 request.mResolvedBundle, 840 new IDownloadSubscriptionCallback.Stub() { 841 @Override 842 public void onComplete(DownloadSubscriptionResult result) { 843 sendMessage(CMD_COMMAND_COMPLETE, (Runnable) () -> { 844 ((DownloadCommandCallback) callback) 845 .onDownloadComplete(result); 846 onCommandEnd(callback); 847 }); 848 } 849 }); 850 break; 851 } 852 case CMD_GET_EUICC_PROFILE_INFO_LIST: { 853 mEuiccService.getEuiccProfileInfoList(slotId, 854 new IGetEuiccProfileInfoListCallback.Stub() { 855 @Override 856 public void onComplete( 857 GetEuiccProfileInfoListResult result) { 858 sendMessage(CMD_COMMAND_COMPLETE, (Runnable) () -> { 859 ((GetEuiccProfileInfoListCommandCallback) callback) 860 .onListComplete(result); 861 onCommandEnd(callback); 862 }); 863 } 864 }); 865 break; 866 } 867 case CMD_GET_DEFAULT_DOWNLOADABLE_SUBSCRIPTION_LIST: { 868 GetDefaultListRequest request = (GetDefaultListRequest) message.obj; 869 mEuiccService.getDefaultDownloadableSubscriptionList(slotId, 870 request.mForceDeactivateSim, 871 new IGetDefaultDownloadableSubscriptionListCallback.Stub() { 872 @Override 873 public void onComplete( 874 GetDefaultDownloadableSubscriptionListResult result 875 ) { 876 sendMessage(CMD_COMMAND_COMPLETE, (Runnable) () -> { 877 ((GetDefaultListCommandCallback) callback) 878 .onGetDefaultListComplete(cardId, result); 879 onCommandEnd(callback); 880 }); 881 } 882 }); 883 break; 884 } 885 case CMD_GET_EUICC_INFO: { 886 mEuiccService.getEuiccInfo(slotId, 887 new IGetEuiccInfoCallback.Stub() { 888 @Override 889 public void onSuccess(EuiccInfo euiccInfo) { 890 sendMessage(CMD_COMMAND_COMPLETE, (Runnable) () -> { 891 ((GetEuiccInfoCommandCallback) callback) 892 .onGetEuiccInfoComplete(euiccInfo); 893 onCommandEnd(callback); 894 }); 895 } 896 }); 897 break; 898 } 899 case CMD_DELETE_SUBSCRIPTION: { 900 DeleteRequest request = (DeleteRequest) message.obj; 901 mEuiccService.deleteSubscription(slotId, request.mIccid, 902 new IDeleteSubscriptionCallback.Stub() { 903 @Override 904 public void onComplete(int result) { 905 sendMessage(CMD_COMMAND_COMPLETE, (Runnable) () -> { 906 ((DeleteCommandCallback) callback) 907 .onDeleteComplete(result); 908 onCommandEnd(callback); 909 }); 910 } 911 }); 912 break; 913 } 914 case CMD_SWITCH_TO_SUBSCRIPTION: { 915 SwitchRequest request = (SwitchRequest) message.obj; 916 final int portIndex = message.arg2; 917 mEuiccService.switchToSubscription(slotId, portIndex, 918 request.mIccid, 919 request.mForceDeactivateSim, 920 new ISwitchToSubscriptionCallback.Stub() { 921 @Override 922 public void onComplete(int result) { 923 sendMessage(CMD_COMMAND_COMPLETE, (Runnable) () -> { 924 ((SwitchCommandCallback) callback) 925 .onSwitchComplete(result); 926 onCommandEnd(callback); 927 }); 928 } 929 }, 930 request.mUsePortIndex); 931 break; 932 } 933 case CMD_UPDATE_SUBSCRIPTION_NICKNAME: { 934 UpdateNicknameRequest request = (UpdateNicknameRequest) message.obj; 935 mEuiccService.updateSubscriptionNickname(slotId, request.mIccid, 936 request.mNickname, 937 new IUpdateSubscriptionNicknameCallback.Stub() { 938 @Override 939 public void onComplete(int result) { 940 sendMessage(CMD_COMMAND_COMPLETE, (Runnable) () -> { 941 ((UpdateNicknameCommandCallback) callback) 942 .onUpdateNicknameComplete(result); 943 onCommandEnd(callback); 944 }); 945 } 946 }); 947 break; 948 } 949 case CMD_ERASE_SUBSCRIPTIONS: { 950 mEuiccService.eraseSubscriptions(slotId, 951 new IEraseSubscriptionsCallback.Stub() { 952 @Override 953 public void onComplete(int result) { 954 sendMessage(CMD_COMMAND_COMPLETE, (Runnable) () -> { 955 ((EraseCommandCallback) callback) 956 .onEraseComplete(result); 957 onCommandEnd(callback); 958 }); 959 } 960 }); 961 break; 962 } 963 case CMD_ERASE_SUBSCRIPTIONS_WITH_OPTIONS: { 964 mEuiccService.eraseSubscriptionsWithOptions(slotId, 965 message.arg2 /* options */, 966 new IEraseSubscriptionsCallback.Stub() { 967 @Override 968 public void onComplete(int result) { 969 sendMessage(CMD_COMMAND_COMPLETE, (Runnable) () -> { 970 ((EraseCommandCallback) callback) 971 .onEraseComplete(result); 972 onCommandEnd(callback); 973 }); 974 } 975 }); 976 break; 977 } 978 case CMD_RETAIN_SUBSCRIPTIONS: { 979 mEuiccService.retainSubscriptionsForFactoryReset(slotId, 980 new IRetainSubscriptionsForFactoryResetCallback.Stub() { 981 @Override 982 public void onComplete(int result) { 983 sendMessage(CMD_COMMAND_COMPLETE, (Runnable) () -> { 984 ((RetainSubscriptionsCommandCallback) callback) 985 .onRetainSubscriptionsComplete(result); 986 onCommandEnd(callback); 987 }); 988 } 989 }); 990 break; 991 } 992 case CMD_GET_OTA_STATUS: { 993 mEuiccService.getOtaStatus(slotId, 994 new IGetOtaStatusCallback.Stub() { 995 @Override 996 public void onSuccess(@OtaStatus int status) { 997 sendMessage(CMD_COMMAND_COMPLETE, (Runnable) () -> { 998 ((GetOtaStatusCommandCallback) callback) 999 .onGetOtaStatusComplete(status); 1000 onCommandEnd(callback); 1001 }); 1002 } 1003 }); 1004 break; 1005 } 1006 case CMD_START_OTA_IF_NECESSARY: { 1007 mEuiccService.startOtaIfNecessary(slotId, 1008 new IOtaStatusChangedCallback.Stub() { 1009 @Override 1010 public void onOtaStatusChanged(int status) 1011 throws RemoteException { 1012 if (status == EuiccManager.EUICC_OTA_IN_PROGRESS) { 1013 sendMessage(CMD_COMMAND_COMPLETE, (Runnable) () -> { 1014 ((OtaStatusChangedCallback) callback) 1015 .onOtaStatusChanged(status); 1016 }); 1017 } else { 1018 sendMessage(CMD_COMMAND_COMPLETE, (Runnable) () -> { 1019 ((OtaStatusChangedCallback) callback) 1020 .onOtaStatusChanged(status); 1021 onCommandEnd(callback); 1022 }); 1023 } 1024 } 1025 }); 1026 break; 1027 } 1028 case CMD_DUMP_EUICC_SERVICE: { 1029 mEuiccService.dump(new IEuiccServiceDumpResultCallback.Stub() { 1030 @Override 1031 public void onComplete(String logs) 1032 throws RemoteException { 1033 sendMessage(CMD_COMMAND_COMPLETE, (Runnable) () -> { 1034 ((DumpEuiccServiceCommandCallback) callback) 1035 .onDumpEuiccServiceComplete(logs); 1036 onCommandEnd(callback); 1037 }); 1038 } 1039 }); 1040 break; 1041 } 1042 default: { 1043 Log.wtf(TAG, "Unimplemented eUICC command: " + message.what); 1044 callback.onEuiccServiceUnavailable(); 1045 onCommandEnd(callback); 1046 return HANDLED; 1047 } 1048 } 1049 } catch (Exception e) { 1050 // If this is a RemoteException, we expect to be disconnected soon. For other 1051 // exceptions, this is a bug in the EuiccService implementation, but we must 1052 // not let it crash the phone process. 1053 Log.w(TAG, "Exception making binder call to EuiccService", e); 1054 callback.onEuiccServiceUnavailable(); 1055 onCommandEnd(callback); 1056 } 1057 1058 return HANDLED; 1059 } 1060 1061 return NOT_HANDLED; 1062 } 1063 1064 @Override exit()1065 public void exit() { 1066 removeMessages(CMD_LINGER_TIMEOUT); 1067 // Dispatch callbacks for all in-flight commands; they will no longer succeed. (The 1068 // remote process cannot possibly trigger a callback at this stage because the 1069 // connection has dropped). 1070 for (BaseEuiccCommandCallback callback : mActiveCommandCallbacks) { 1071 callback.onEuiccServiceUnavailable(); 1072 } 1073 mActiveCommandCallbacks.clear(); 1074 } 1075 } 1076 getCallback(Message message)1077 private static BaseEuiccCommandCallback getCallback(Message message) { 1078 switch (message.what) { 1079 case CMD_GET_EID: 1080 case CMD_GET_EUICC_PROFILE_INFO_LIST: 1081 case CMD_GET_EUICC_INFO: 1082 case CMD_ERASE_SUBSCRIPTIONS: 1083 case CMD_ERASE_SUBSCRIPTIONS_WITH_OPTIONS: 1084 case CMD_RETAIN_SUBSCRIPTIONS: 1085 case CMD_GET_OTA_STATUS: 1086 case CMD_START_OTA_IF_NECESSARY: 1087 case CMD_DUMP_EUICC_SERVICE: 1088 case CMD_GET_AVAILABLE_MEMORY_IN_BYTES: 1089 return (BaseEuiccCommandCallback) message.obj; 1090 case CMD_GET_DOWNLOADABLE_SUBSCRIPTION_METADATA: 1091 return ((GetMetadataRequest) message.obj).mCallback; 1092 case CMD_DOWNLOAD_SUBSCRIPTION: 1093 return ((DownloadRequest) message.obj).mCallback; 1094 case CMD_GET_DEFAULT_DOWNLOADABLE_SUBSCRIPTION_LIST: 1095 return ((GetDefaultListRequest) message.obj).mCallback; 1096 case CMD_DELETE_SUBSCRIPTION: 1097 return ((DeleteRequest) message.obj).mCallback; 1098 case CMD_SWITCH_TO_SUBSCRIPTION: 1099 return ((SwitchRequest) message.obj).mCallback; 1100 case CMD_UPDATE_SUBSCRIPTION_NICKNAME: 1101 return ((UpdateNicknameRequest) message.obj).mCallback; 1102 default: 1103 throw new IllegalArgumentException("Unsupported message: " + message.what); 1104 } 1105 } 1106 1107 /** 1108 * Gets the slot ID from the card ID. 1109 */ getSlotIdFromCardId(int cardId)1110 private int getSlotIdFromCardId(int cardId) { 1111 if (cardId == TelephonyManager.UNSUPPORTED_CARD_ID 1112 || cardId == TelephonyManager.UNINITIALIZED_CARD_ID) { 1113 return SubscriptionManager.INVALID_SIM_SLOT_INDEX; 1114 } 1115 TelephonyManager tm = (TelephonyManager) 1116 mContext.getSystemService(Context.TELEPHONY_SERVICE); 1117 UiccSlotInfo[] slotInfos = tm.getUiccSlotsInfo(); 1118 if (slotInfos == null || slotInfos.length == 0) { 1119 Log.e(TAG, "UiccSlotInfo is null or empty"); 1120 return SubscriptionManager.INVALID_SIM_SLOT_INDEX; 1121 } 1122 String cardIdString = UiccController.getInstance().convertToCardString(cardId); 1123 for (int slotIndex = 0; slotIndex < slotInfos.length; slotIndex++) { 1124 // Report Anomaly in case UiccSlotInfo is not. 1125 if (slotInfos[slotIndex] == null) { 1126 Log.i(TAG, "No UiccSlotInfo found for slotIndex: " + slotIndex); 1127 return SubscriptionManager.INVALID_SIM_SLOT_INDEX; 1128 } 1129 String retrievedCardId = slotInfos[slotIndex] != null 1130 ? slotInfos[slotIndex].getCardId() : null; 1131 if (IccUtils.compareIgnoreTrailingFs(cardIdString, retrievedCardId)) { 1132 return slotIndex; 1133 } 1134 } 1135 Log.i(TAG, "No UiccSlotInfo found for cardId: " + cardId); 1136 return SubscriptionManager.INVALID_SIM_SLOT_INDEX; 1137 } 1138 1139 /** Call this at the beginning of the execution of any command. */ onCommandStart(BaseEuiccCommandCallback callback)1140 private void onCommandStart(BaseEuiccCommandCallback callback) { 1141 mActiveCommandCallbacks.add(callback); 1142 removeMessages(CMD_LINGER_TIMEOUT); 1143 } 1144 1145 /** Call this at the end of execution of any command (whether or not it succeeded). */ onCommandEnd(BaseEuiccCommandCallback callback)1146 private void onCommandEnd(BaseEuiccCommandCallback callback) { 1147 if (!mActiveCommandCallbacks.remove(callback)) { 1148 Log.wtf(TAG, "Callback already removed from mActiveCommandCallbacks"); 1149 } 1150 if (mActiveCommandCallbacks.isEmpty()) { 1151 sendMessageDelayed(CMD_LINGER_TIMEOUT, LINGER_TIMEOUT_MILLIS); 1152 } 1153 } 1154 1155 /** Return the service info of the EuiccService to bind to, or null if none were found. */ 1156 @Nullable findBestComponent()1157 private ServiceInfo findBestComponent() { 1158 return (ServiceInfo) findBestComponent(mPm); 1159 } 1160 1161 /** 1162 * Bring up a binding to the currently-selected component. 1163 * 1164 * <p>Returns true if we've successfully bound to the service. 1165 */ createBinding()1166 private boolean createBinding() { 1167 if (mSelectedComponent == null) { 1168 Log.wtf(TAG, "Attempting to create binding but no component is selected"); 1169 return false; 1170 } 1171 Intent intent = new Intent(EuiccService.EUICC_SERVICE_INTERFACE); 1172 intent.setComponent(new ComponentName(mSelectedComponent.packageName, 1173 mSelectedComponent.name)); 1174 // We bind this as a foreground service because it is operating directly on the SIM, and we 1175 // do not want it subjected to power-savings restrictions while doing so. 1176 return mContext.bindService(intent, this, 1177 Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE); 1178 } 1179 unbind()1180 private void unbind() { 1181 mEuiccService = null; 1182 mContext.unbindService(this); 1183 } 1184 findBestComponent( PackageManager packageManager, List<ResolveInfo> resolveInfoList)1185 private static ComponentInfo findBestComponent( 1186 PackageManager packageManager, List<ResolveInfo> resolveInfoList) { 1187 int bestPriority = Integer.MIN_VALUE; 1188 ComponentInfo bestComponent = null; 1189 if (resolveInfoList != null) { 1190 for (ResolveInfo resolveInfo : resolveInfoList) { 1191 if (!isValidEuiccComponent(packageManager, resolveInfo)) { 1192 continue; 1193 } 1194 1195 if (resolveInfo.filter.getPriority() > bestPriority) { 1196 bestPriority = resolveInfo.filter.getPriority(); 1197 bestComponent = TelephonyUtils.getComponentInfo(resolveInfo); 1198 } 1199 } 1200 } 1201 1202 return bestComponent; 1203 } 1204 isValidEuiccComponent( PackageManager packageManager, ResolveInfo resolveInfo)1205 private static boolean isValidEuiccComponent( 1206 PackageManager packageManager, ResolveInfo resolveInfo) { 1207 ComponentInfo componentInfo = TelephonyUtils.getComponentInfo(resolveInfo); 1208 String packageName = new ComponentName(componentInfo.packageName, componentInfo.name) 1209 .getPackageName(); 1210 1211 // Verify that the app is privileged (via granting of a privileged permission). 1212 if (packageManager.checkPermission( 1213 Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS, packageName) 1214 != PackageManager.PERMISSION_GRANTED) { 1215 Log.wtf(TAG, "Package " + packageName 1216 + " does not declare WRITE_EMBEDDED_SUBSCRIPTIONS"); 1217 return false; 1218 } 1219 1220 // Verify that only the system can access the component. 1221 final String permission; 1222 if (componentInfo instanceof ServiceInfo) { 1223 permission = ((ServiceInfo) componentInfo).permission; 1224 } else if (componentInfo instanceof ActivityInfo) { 1225 permission = ((ActivityInfo) componentInfo).permission; 1226 } else { 1227 throw new IllegalArgumentException("Can only verify services/activities"); 1228 } 1229 if (!TextUtils.equals(permission, Manifest.permission.BIND_EUICC_SERVICE)) { 1230 Log.wtf(TAG, "Package " + packageName 1231 + " does not require the BIND_EUICC_SERVICE permission"); 1232 return false; 1233 } 1234 1235 // Verify that the component declares a priority. 1236 if (resolveInfo.filter == null || resolveInfo.filter.getPriority() == 0) { 1237 Log.wtf(TAG, "Package " + packageName + " does not specify a priority"); 1238 return false; 1239 } 1240 return true; 1241 } 1242 1243 @Override onServiceConnected(ComponentName name, IBinder service)1244 public void onServiceConnected(ComponentName name, IBinder service) { 1245 IEuiccService euiccService = IEuiccService.Stub.asInterface(service); 1246 sendMessage(CMD_SERVICE_CONNECTED, euiccService); 1247 } 1248 1249 @Override onServiceDisconnected(ComponentName name)1250 public void onServiceDisconnected(ComponentName name) { 1251 sendMessage(CMD_SERVICE_DISCONNECTED); 1252 } 1253 1254 private class EuiccPackageMonitor extends PackageChangeReceiver { 1255 @Override onPackageAdded(String packageName)1256 public void onPackageAdded(String packageName) { 1257 sendPackageChange(packageName, true /* forceUnbindForThisPackage */); 1258 } 1259 1260 @Override onPackageRemoved(String packageName)1261 public void onPackageRemoved(String packageName) { 1262 sendPackageChange(packageName, true /* forceUnbindForThisPackage */); 1263 } 1264 1265 @Override onPackageUpdateFinished(String packageName)1266 public void onPackageUpdateFinished(String packageName) { 1267 sendPackageChange(packageName, true /* forceUnbindForThisPackage */); 1268 } 1269 1270 @Override onPackageModified(String packageName)1271 public void onPackageModified(String packageName) { 1272 sendPackageChange(packageName, false /* forceUnbindForThisPackage */); 1273 } 1274 1275 @Override onHandleForceStop(String[] packages, boolean doit)1276 public void onHandleForceStop(String[] packages, boolean doit) { 1277 if (doit) { 1278 for (String packageName : packages) { 1279 sendPackageChange(packageName, true /* forceUnbindForThisPackage */); 1280 } 1281 } 1282 } 1283 sendPackageChange(String packageName, boolean forceUnbindForThisPackage)1284 private void sendPackageChange(String packageName, boolean forceUnbindForThisPackage) { 1285 sendMessage(CMD_PACKAGE_CHANGE, forceUnbindForThisPackage ? packageName : null); 1286 } 1287 } 1288 1289 @Override unhandledMessage(Message msg)1290 protected void unhandledMessage(Message msg) { 1291 IState state = getCurrentState(); 1292 Log.wtf(TAG, "Unhandled message " + msg.what + " in state " 1293 + (state == null ? "null" : state.getName())); 1294 AnomalyReporter.reportAnomaly( 1295 UUID.fromString("0db20514-5fa1-4e62-a7b7-2acf5f92c957"), 1296 "EuiccConnector: Found unhandledMessage " + String.valueOf(msg.what)); 1297 } 1298 1299 @Override dump(FileDescriptor fd, PrintWriter pw, String[] args)1300 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1301 super.dump(fd, pw, args); 1302 pw.println("mSelectedComponent=" + mSelectedComponent); 1303 pw.println("mEuiccService=" + mEuiccService); 1304 pw.println("mActiveCommandCount=" + mActiveCommandCallbacks.size()); 1305 } 1306 updateSubscriptionInfoListForAllAccessibleEuiccs()1307 private void updateSubscriptionInfoListForAllAccessibleEuiccs() { 1308 if (mTm.getCardIdForDefaultEuicc() == TelephonyManager.UNSUPPORTED_CARD_ID) { 1309 // Device does not support card ID 1310 mSm.requestEmbeddedSubscriptionInfoListRefresh(); 1311 } else { 1312 for (UiccCardInfo cardInfo : mTm.getUiccCardsInfo()) { 1313 if (cardInfo.isEuicc()) { 1314 mSm.requestEmbeddedSubscriptionInfoListRefresh(cardInfo.getCardId()); 1315 } 1316 } 1317 } 1318 } 1319 } 1320