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