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