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