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.PackageChangeReceiver; 61 import android.telephony.SubscriptionManager; 62 import android.telephony.TelephonyManager; 63 import android.telephony.UiccCardInfo; 64 import android.telephony.euicc.DownloadableSubscription; 65 import android.telephony.euicc.EuiccInfo; 66 import android.telephony.euicc.EuiccManager; 67 import android.telephony.euicc.EuiccManager.OtaStatus; 68 import android.text.TextUtils; 69 import android.util.ArraySet; 70 import android.util.Log; 71 72 import com.android.internal.annotations.VisibleForTesting; 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 mPackageMonitor.register(mContext, null /* thread */, null /* user */); 406 mContext.registerReceiver( 407 mUserUnlockedReceiver, new IntentFilter(Intent.ACTION_USER_UNLOCKED)); 408 409 start(); 410 } 411 412 @Override onHalting()413 public void onHalting() { 414 mPackageMonitor.unregister(); 415 mContext.unregisterReceiver(mUserUnlockedReceiver); 416 } 417 418 /** Asynchronously fetch the EID. */ 419 @VisibleForTesting(visibility = PACKAGE) getEid(int cardId, GetEidCommandCallback callback)420 public void getEid(int cardId, GetEidCommandCallback callback) { 421 sendMessage(CMD_GET_EID, cardId, 0 /* arg2 */, callback); 422 } 423 424 /** Asynchronously get OTA status. */ 425 @VisibleForTesting(visibility = PACKAGE) getOtaStatus(int cardId, GetOtaStatusCommandCallback callback)426 public void getOtaStatus(int cardId, GetOtaStatusCommandCallback callback) { 427 sendMessage(CMD_GET_OTA_STATUS, cardId, 0 /* arg2 */, callback); 428 } 429 430 /** Asynchronously perform OTA update. */ 431 @VisibleForTesting(visibility = PACKAGE) startOtaIfNecessary(int cardId, OtaStatusChangedCallback callback)432 public void startOtaIfNecessary(int cardId, OtaStatusChangedCallback callback) { 433 sendMessage(CMD_START_OTA_IF_NECESSARY, cardId, 0 /* arg2 */, callback); 434 } 435 436 /** Asynchronously fetch metadata for the given downloadable subscription. */ 437 @VisibleForTesting(visibility = PACKAGE) getDownloadableSubscriptionMetadata(int cardId, DownloadableSubscription subscription, boolean forceDeactivateSim, GetMetadataCommandCallback callback)438 public void getDownloadableSubscriptionMetadata(int cardId, 439 DownloadableSubscription subscription, 440 boolean forceDeactivateSim, GetMetadataCommandCallback callback) { 441 GetMetadataRequest request = 442 new GetMetadataRequest(); 443 request.mSubscription = subscription; 444 request.mForceDeactivateSim = forceDeactivateSim; 445 request.mCallback = callback; 446 sendMessage(CMD_GET_DOWNLOADABLE_SUBSCRIPTION_METADATA, cardId, 0 /* arg2 */, request); 447 } 448 449 /** Asynchronously download the given subscription. */ 450 @VisibleForTesting(visibility = PACKAGE) downloadSubscription(int cardId, DownloadableSubscription subscription, boolean switchAfterDownload, boolean forceDeactivateSim, Bundle resolvedBundle, DownloadCommandCallback callback)451 public void downloadSubscription(int cardId, DownloadableSubscription subscription, 452 boolean switchAfterDownload, boolean forceDeactivateSim, 453 Bundle resolvedBundle, DownloadCommandCallback callback) { 454 DownloadRequest request = new DownloadRequest(); 455 request.mSubscription = subscription; 456 request.mSwitchAfterDownload = switchAfterDownload; 457 request.mForceDeactivateSim = forceDeactivateSim; 458 request.mResolvedBundle = resolvedBundle; 459 request.mCallback = callback; 460 sendMessage(CMD_DOWNLOAD_SUBSCRIPTION, cardId, 0 /* arg2 */, request); 461 } 462 getEuiccProfileInfoList(int cardId, GetEuiccProfileInfoListCommandCallback callback)463 void getEuiccProfileInfoList(int cardId, GetEuiccProfileInfoListCommandCallback callback) { 464 sendMessage(CMD_GET_EUICC_PROFILE_INFO_LIST, cardId, 0 /* arg2 */, callback); 465 } 466 467 /** Asynchronously fetch the default downloadable subscription list. */ 468 @VisibleForTesting(visibility = PACKAGE) getDefaultDownloadableSubscriptionList(int cardId, boolean forceDeactivateSim, GetDefaultListCommandCallback callback)469 public void getDefaultDownloadableSubscriptionList(int cardId, 470 boolean forceDeactivateSim, GetDefaultListCommandCallback callback) { 471 GetDefaultListRequest request = new GetDefaultListRequest(); 472 request.mForceDeactivateSim = forceDeactivateSim; 473 request.mCallback = callback; 474 sendMessage(CMD_GET_DEFAULT_DOWNLOADABLE_SUBSCRIPTION_LIST, cardId, 0 /* arg2 */, request); 475 } 476 477 /** Asynchronously fetch the {@link EuiccInfo}. */ 478 @VisibleForTesting(visibility = PACKAGE) getEuiccInfo(int cardId, GetEuiccInfoCommandCallback callback)479 public void getEuiccInfo(int cardId, GetEuiccInfoCommandCallback callback) { 480 sendMessage(CMD_GET_EUICC_INFO, cardId, 0 /* arg2 */, callback); 481 } 482 483 /** Asynchronously delete the given subscription. */ 484 @VisibleForTesting(visibility = PACKAGE) deleteSubscription(int cardId, String iccid, DeleteCommandCallback callback)485 public void deleteSubscription(int cardId, String iccid, DeleteCommandCallback callback) { 486 DeleteRequest request = new DeleteRequest(); 487 request.mIccid = iccid; 488 request.mCallback = callback; 489 sendMessage(CMD_DELETE_SUBSCRIPTION, cardId, 0 /* arg2 */, request); 490 } 491 492 /** Asynchronously switch to the given subscription. */ 493 @VisibleForTesting(visibility = PACKAGE) switchToSubscription(int cardId, @Nullable String iccid, boolean forceDeactivateSim, SwitchCommandCallback callback)494 public void switchToSubscription(int cardId, @Nullable String iccid, boolean forceDeactivateSim, 495 SwitchCommandCallback callback) { 496 SwitchRequest request = new SwitchRequest(); 497 request.mIccid = iccid; 498 request.mForceDeactivateSim = forceDeactivateSim; 499 request.mCallback = callback; 500 sendMessage(CMD_SWITCH_TO_SUBSCRIPTION, cardId, 0 /* arg2 */, request); 501 } 502 503 /** Asynchronously update the nickname of the given subscription. */ 504 @VisibleForTesting(visibility = PACKAGE) updateSubscriptionNickname(int cardId, String iccid, String nickname, UpdateNicknameCommandCallback callback)505 public void updateSubscriptionNickname(int cardId, 506 String iccid, String nickname, UpdateNicknameCommandCallback callback) { 507 UpdateNicknameRequest request = new UpdateNicknameRequest(); 508 request.mIccid = iccid; 509 request.mNickname = nickname; 510 request.mCallback = callback; 511 sendMessage(CMD_UPDATE_SUBSCRIPTION_NICKNAME, cardId, 0 /* arg2 */, request); 512 } 513 514 /** Asynchronously erase operational profiles on the eUICC. */ 515 @VisibleForTesting(visibility = PACKAGE) eraseSubscriptions(int cardId, EraseCommandCallback callback)516 public void eraseSubscriptions(int cardId, EraseCommandCallback callback) { 517 sendMessage(CMD_ERASE_SUBSCRIPTIONS, cardId, 0 /* arg2 */, callback); 518 } 519 520 /** Asynchronously erase specific profiles on the eUICC. */ 521 @VisibleForTesting(visibility = PACKAGE) eraseSubscriptionsWithOptions( int cardId, @ResetOption int options, EraseCommandCallback callback)522 public void eraseSubscriptionsWithOptions( 523 int cardId, @ResetOption int options, EraseCommandCallback callback) { 524 sendMessage(CMD_ERASE_SUBSCRIPTIONS_WITH_OPTIONS, cardId, options, callback); 525 } 526 527 /** Asynchronously ensure that all profiles will be retained on the next factory reset. */ 528 @VisibleForTesting(visibility = PACKAGE) retainSubscriptions(int cardId, RetainSubscriptionsCommandCallback callback)529 public void retainSubscriptions(int cardId, RetainSubscriptionsCommandCallback callback) { 530 sendMessage(CMD_RETAIN_SUBSCRIPTIONS, cardId, 0 /* arg2 */, callback); 531 } 532 533 /** Asynchronously calls the currently bound EuiccService implementation to dump its states */ 534 @VisibleForTesting(visibility = PACKAGE) dumpEuiccService(DumpEuiccServiceCommandCallback callback)535 public void dumpEuiccService(DumpEuiccServiceCommandCallback callback) { 536 sendMessage(CMD_DUMP_EUICC_SERVICE, TelephonyManager.UNSUPPORTED_CARD_ID /* ignored */, 537 0 /* arg2 */, 538 callback); 539 } 540 541 /** 542 * State in which no EuiccService is available. 543 * 544 * <p>All incoming commands will be rejected through 545 * {@link BaseEuiccCommandCallback#onEuiccServiceUnavailable()}. 546 * 547 * <p>Package state changes will lead to transitions between {@link UnavailableState} and 548 * {@link AvailableState} depending on whether an EuiccService becomes unavailable or 549 * available. 550 */ 551 private class UnavailableState extends State { 552 @Override processMessage(Message message)553 public boolean processMessage(Message message) { 554 if (message.what == CMD_PACKAGE_CHANGE) { 555 mSelectedComponent = findBestComponent(); 556 if (mSelectedComponent != null) { 557 transitionTo(mAvailableState); 558 } else if (getCurrentState() != mUnavailableState) { 559 transitionTo(mUnavailableState); 560 } 561 updateSubscriptionInfoListForAllAccessibleEuiccs(); 562 return HANDLED; 563 } else if (isEuiccCommand(message.what)) { 564 BaseEuiccCommandCallback callback = getCallback(message); 565 callback.onEuiccServiceUnavailable(); 566 return HANDLED; 567 } 568 569 return NOT_HANDLED; 570 } 571 } 572 573 /** 574 * State in which a EuiccService is available, but no binding is established or in the process 575 * of being established. 576 * 577 * <p>If a command is received, this state will defer the message and enter {@link BindingState} 578 * to bring up the binding. 579 */ 580 private class AvailableState extends State { 581 @Override processMessage(Message message)582 public boolean processMessage(Message message) { 583 if (isEuiccCommand(message.what)) { 584 deferMessage(message); 585 transitionTo(mBindingState); 586 return HANDLED; 587 } 588 589 return NOT_HANDLED; 590 } 591 } 592 593 /** 594 * State in which we are binding to the current EuiccService. 595 * 596 * <p>This is a transient state. If bindService returns true, we enter {@link DisconnectedState} 597 * while waiting for the binding to be established. If it returns false, we move back to 598 * {@link AvailableState}. 599 * 600 * <p>Any received messages will be deferred. 601 */ 602 private class BindingState extends State { 603 @Override enter()604 public void enter() { 605 if (createBinding()) { 606 transitionTo(mDisconnectedState); 607 } else { 608 // createBinding() should generally not return false since we've already performed 609 // Intent resolution, but it's always possible that the package state changes 610 // asynchronously. Transition to available for now, and if the package state has 611 // changed, we'll process that event and move to mUnavailableState as needed. 612 transitionTo(mAvailableState); 613 } 614 } 615 616 @Override processMessage(Message message)617 public boolean processMessage(Message message) { 618 deferMessage(message); 619 return HANDLED; 620 } 621 } 622 623 /** 624 * State in which a binding is established, but not currently connected. 625 * 626 * <p>We wait up to {@link #BIND_TIMEOUT_MILLIS} for the binding to establish. If it doesn't, 627 * we go back to {@link AvailableState} to try again. 628 * 629 * <p>Package state changes will cause us to unbind and move to {@link BindingState} to 630 * reestablish the binding if the selected component has changed or if a forced rebind is 631 * necessary. 632 * 633 * <p>Any received commands will be deferred. 634 */ 635 private class DisconnectedState extends State { 636 @Override enter()637 public void enter() { 638 sendMessageDelayed(CMD_CONNECT_TIMEOUT, BIND_TIMEOUT_MILLIS); 639 } 640 641 @Override processMessage(Message message)642 public boolean processMessage(Message message) { 643 if (message.what == CMD_SERVICE_CONNECTED) { 644 mEuiccService = (IEuiccService) message.obj; 645 transitionTo(mConnectedState); 646 return HANDLED; 647 } else if (message.what == CMD_PACKAGE_CHANGE) { 648 ServiceInfo bestComponent = findBestComponent(); 649 String affectedPackage = (String) message.obj; 650 boolean isSameComponent; 651 if (bestComponent == null) { 652 isSameComponent = mSelectedComponent != null; 653 } else { 654 isSameComponent = mSelectedComponent == null 655 || Objects.equals(new ComponentName(bestComponent.packageName, 656 bestComponent.name), 657 new ComponentName(mSelectedComponent.packageName, mSelectedComponent.name)); 658 } 659 boolean forceRebind = bestComponent != null 660 && Objects.equals(bestComponent.packageName, affectedPackage); 661 if (!isSameComponent || forceRebind) { 662 unbind(); 663 mSelectedComponent = bestComponent; 664 if (mSelectedComponent == null) { 665 transitionTo(mUnavailableState); 666 } else { 667 transitionTo(mBindingState); 668 } 669 } 670 updateSubscriptionInfoListForAllAccessibleEuiccs(); 671 return HANDLED; 672 } else if (message.what == CMD_CONNECT_TIMEOUT) { 673 transitionTo(mAvailableState); 674 return HANDLED; 675 } else if (isEuiccCommand(message.what)) { 676 deferMessage(message); 677 return HANDLED; 678 } 679 680 return NOT_HANDLED; 681 } 682 } 683 684 /** 685 * State in which the binding is connected. 686 * 687 * <p>Commands will be processed as long as we're in this state. We wait up to 688 * {@link #LINGER_TIMEOUT_MILLIS} between commands; if this timeout is reached, we will drop the 689 * binding until the next command is received. 690 */ 691 private class ConnectedState extends State { 692 @Override enter()693 public void enter() { 694 removeMessages(CMD_CONNECT_TIMEOUT); 695 sendMessageDelayed(CMD_LINGER_TIMEOUT, LINGER_TIMEOUT_MILLIS); 696 } 697 698 @Override processMessage(Message message)699 public boolean processMessage(Message message) { 700 if (message.what == CMD_SERVICE_DISCONNECTED) { 701 mEuiccService = null; 702 transitionTo(mDisconnectedState); 703 return HANDLED; 704 } else if (message.what == CMD_LINGER_TIMEOUT) { 705 unbind(); 706 transitionTo(mAvailableState); 707 return HANDLED; 708 } else if (message.what == CMD_COMMAND_COMPLETE) { 709 Runnable runnable = (Runnable) message.obj; 710 runnable.run(); 711 return HANDLED; 712 } else if (isEuiccCommand(message.what)) { 713 final BaseEuiccCommandCallback callback = getCallback(message); 714 onCommandStart(callback); 715 final int cardId = message.arg1; 716 final int slotId = getSlotIdFromCardId(cardId); 717 try { 718 switch (message.what) { 719 case CMD_GET_EID: { 720 mEuiccService.getEid(slotId, 721 new IGetEidCallback.Stub() { 722 @Override 723 public void onSuccess(String eid) { 724 sendMessage(CMD_COMMAND_COMPLETE, (Runnable) () -> { 725 ((GetEidCommandCallback) callback) 726 .onGetEidComplete(eid); 727 onCommandEnd(callback); 728 }); 729 } 730 }); 731 break; 732 } 733 case CMD_GET_DOWNLOADABLE_SUBSCRIPTION_METADATA: { 734 GetMetadataRequest request = (GetMetadataRequest) message.obj; 735 mEuiccService.getDownloadableSubscriptionMetadata(slotId, 736 request.mSubscription, 737 request.mForceDeactivateSim, 738 new IGetDownloadableSubscriptionMetadataCallback.Stub() { 739 @Override 740 public void onComplete( 741 GetDownloadableSubscriptionMetadataResult result) { 742 sendMessage(CMD_COMMAND_COMPLETE, (Runnable) () -> { 743 ((GetMetadataCommandCallback) callback) 744 .onGetMetadataComplete(cardId, result); 745 onCommandEnd(callback); 746 }); 747 } 748 }); 749 break; 750 } 751 case CMD_DOWNLOAD_SUBSCRIPTION: { 752 DownloadRequest request = (DownloadRequest) message.obj; 753 mEuiccService.downloadSubscription(slotId, 754 request.mSubscription, 755 request.mSwitchAfterDownload, 756 request.mForceDeactivateSim, 757 request.mResolvedBundle, 758 new IDownloadSubscriptionCallback.Stub() { 759 @Override 760 public void onComplete(DownloadSubscriptionResult result) { 761 sendMessage(CMD_COMMAND_COMPLETE, (Runnable) () -> { 762 ((DownloadCommandCallback) callback) 763 .onDownloadComplete(result); 764 onCommandEnd(callback); 765 }); 766 } 767 }); 768 break; 769 } 770 case CMD_GET_EUICC_PROFILE_INFO_LIST: { 771 mEuiccService.getEuiccProfileInfoList(slotId, 772 new IGetEuiccProfileInfoListCallback.Stub() { 773 @Override 774 public void onComplete( 775 GetEuiccProfileInfoListResult result) { 776 sendMessage(CMD_COMMAND_COMPLETE, (Runnable) () -> { 777 ((GetEuiccProfileInfoListCommandCallback) callback) 778 .onListComplete(result); 779 onCommandEnd(callback); 780 }); 781 } 782 }); 783 break; 784 } 785 case CMD_GET_DEFAULT_DOWNLOADABLE_SUBSCRIPTION_LIST: { 786 GetDefaultListRequest request = (GetDefaultListRequest) message.obj; 787 mEuiccService.getDefaultDownloadableSubscriptionList(slotId, 788 request.mForceDeactivateSim, 789 new IGetDefaultDownloadableSubscriptionListCallback.Stub() { 790 @Override 791 public void onComplete( 792 GetDefaultDownloadableSubscriptionListResult result 793 ) { 794 sendMessage(CMD_COMMAND_COMPLETE, (Runnable) () -> { 795 ((GetDefaultListCommandCallback) callback) 796 .onGetDefaultListComplete(cardId, result); 797 onCommandEnd(callback); 798 }); 799 } 800 }); 801 break; 802 } 803 case CMD_GET_EUICC_INFO: { 804 mEuiccService.getEuiccInfo(slotId, 805 new IGetEuiccInfoCallback.Stub() { 806 @Override 807 public void onSuccess(EuiccInfo euiccInfo) { 808 sendMessage(CMD_COMMAND_COMPLETE, (Runnable) () -> { 809 ((GetEuiccInfoCommandCallback) callback) 810 .onGetEuiccInfoComplete(euiccInfo); 811 onCommandEnd(callback); 812 }); 813 } 814 }); 815 break; 816 } 817 case CMD_DELETE_SUBSCRIPTION: { 818 DeleteRequest request = (DeleteRequest) message.obj; 819 mEuiccService.deleteSubscription(slotId, request.mIccid, 820 new IDeleteSubscriptionCallback.Stub() { 821 @Override 822 public void onComplete(int result) { 823 sendMessage(CMD_COMMAND_COMPLETE, (Runnable) () -> { 824 ((DeleteCommandCallback) callback) 825 .onDeleteComplete(result); 826 onCommandEnd(callback); 827 }); 828 } 829 }); 830 break; 831 } 832 case CMD_SWITCH_TO_SUBSCRIPTION: { 833 SwitchRequest request = (SwitchRequest) message.obj; 834 mEuiccService.switchToSubscription(slotId, request.mIccid, 835 request.mForceDeactivateSim, 836 new ISwitchToSubscriptionCallback.Stub() { 837 @Override 838 public void onComplete(int result) { 839 sendMessage(CMD_COMMAND_COMPLETE, (Runnable) () -> { 840 ((SwitchCommandCallback) callback) 841 .onSwitchComplete(result); 842 onCommandEnd(callback); 843 }); 844 } 845 }); 846 break; 847 } 848 case CMD_UPDATE_SUBSCRIPTION_NICKNAME: { 849 UpdateNicknameRequest request = (UpdateNicknameRequest) message.obj; 850 mEuiccService.updateSubscriptionNickname(slotId, request.mIccid, 851 request.mNickname, 852 new IUpdateSubscriptionNicknameCallback.Stub() { 853 @Override 854 public void onComplete(int result) { 855 sendMessage(CMD_COMMAND_COMPLETE, (Runnable) () -> { 856 ((UpdateNicknameCommandCallback) callback) 857 .onUpdateNicknameComplete(result); 858 onCommandEnd(callback); 859 }); 860 } 861 }); 862 break; 863 } 864 case CMD_ERASE_SUBSCRIPTIONS: { 865 mEuiccService.eraseSubscriptions(slotId, 866 new IEraseSubscriptionsCallback.Stub() { 867 @Override 868 public void onComplete(int result) { 869 sendMessage(CMD_COMMAND_COMPLETE, (Runnable) () -> { 870 ((EraseCommandCallback) callback) 871 .onEraseComplete(result); 872 onCommandEnd(callback); 873 }); 874 } 875 }); 876 break; 877 } 878 case CMD_ERASE_SUBSCRIPTIONS_WITH_OPTIONS: { 879 mEuiccService.eraseSubscriptionsWithOptions(slotId, 880 message.arg2 /* options */, 881 new IEraseSubscriptionsCallback.Stub() { 882 @Override 883 public void onComplete(int result) { 884 sendMessage(CMD_COMMAND_COMPLETE, (Runnable) () -> { 885 ((EraseCommandCallback) callback) 886 .onEraseComplete(result); 887 onCommandEnd(callback); 888 }); 889 } 890 }); 891 break; 892 } 893 case CMD_RETAIN_SUBSCRIPTIONS: { 894 mEuiccService.retainSubscriptionsForFactoryReset(slotId, 895 new IRetainSubscriptionsForFactoryResetCallback.Stub() { 896 @Override 897 public void onComplete(int result) { 898 sendMessage(CMD_COMMAND_COMPLETE, (Runnable) () -> { 899 ((RetainSubscriptionsCommandCallback) callback) 900 .onRetainSubscriptionsComplete(result); 901 onCommandEnd(callback); 902 }); 903 } 904 }); 905 break; 906 } 907 case CMD_GET_OTA_STATUS: { 908 mEuiccService.getOtaStatus(slotId, 909 new IGetOtaStatusCallback.Stub() { 910 @Override 911 public void onSuccess(@OtaStatus int status) { 912 sendMessage(CMD_COMMAND_COMPLETE, (Runnable) () -> { 913 ((GetOtaStatusCommandCallback) callback) 914 .onGetOtaStatusComplete(status); 915 onCommandEnd(callback); 916 }); 917 } 918 }); 919 break; 920 } 921 case CMD_START_OTA_IF_NECESSARY: { 922 mEuiccService.startOtaIfNecessary(slotId, 923 new IOtaStatusChangedCallback.Stub() { 924 @Override 925 public void onOtaStatusChanged(int status) 926 throws RemoteException { 927 if (status == EuiccManager.EUICC_OTA_IN_PROGRESS) { 928 sendMessage(CMD_COMMAND_COMPLETE, (Runnable) () -> { 929 ((OtaStatusChangedCallback) callback) 930 .onOtaStatusChanged(status); 931 }); 932 } else { 933 sendMessage(CMD_COMMAND_COMPLETE, (Runnable) () -> { 934 ((OtaStatusChangedCallback) callback) 935 .onOtaStatusChanged(status); 936 onCommandEnd(callback); 937 }); 938 } 939 } 940 }); 941 break; 942 } 943 case CMD_DUMP_EUICC_SERVICE: { 944 mEuiccService.dump(new IEuiccServiceDumpResultCallback.Stub() { 945 @Override 946 public void onComplete(String logs) 947 throws RemoteException { 948 sendMessage(CMD_COMMAND_COMPLETE, (Runnable) () -> { 949 ((DumpEuiccServiceCommandCallback) callback) 950 .onDumpEuiccServiceComplete(logs); 951 onCommandEnd(callback); 952 }); 953 } 954 }); 955 break; 956 } 957 default: { 958 Log.wtf(TAG, "Unimplemented eUICC command: " + message.what); 959 callback.onEuiccServiceUnavailable(); 960 onCommandEnd(callback); 961 return HANDLED; 962 } 963 } 964 } catch (Exception e) { 965 // If this is a RemoteException, we expect to be disconnected soon. For other 966 // exceptions, this is a bug in the EuiccService implementation, but we must 967 // not let it crash the phone process. 968 Log.w(TAG, "Exception making binder call to EuiccService", e); 969 callback.onEuiccServiceUnavailable(); 970 onCommandEnd(callback); 971 } 972 973 return HANDLED; 974 } 975 976 return NOT_HANDLED; 977 } 978 979 @Override exit()980 public void exit() { 981 removeMessages(CMD_LINGER_TIMEOUT); 982 // Dispatch callbacks for all in-flight commands; they will no longer succeed. (The 983 // remote process cannot possibly trigger a callback at this stage because the 984 // connection has dropped). 985 for (BaseEuiccCommandCallback callback : mActiveCommandCallbacks) { 986 callback.onEuiccServiceUnavailable(); 987 } 988 mActiveCommandCallbacks.clear(); 989 } 990 } 991 getCallback(Message message)992 private static BaseEuiccCommandCallback getCallback(Message message) { 993 switch (message.what) { 994 case CMD_GET_EID: 995 case CMD_GET_EUICC_PROFILE_INFO_LIST: 996 case CMD_GET_EUICC_INFO: 997 case CMD_ERASE_SUBSCRIPTIONS: 998 case CMD_ERASE_SUBSCRIPTIONS_WITH_OPTIONS: 999 case CMD_RETAIN_SUBSCRIPTIONS: 1000 case CMD_GET_OTA_STATUS: 1001 case CMD_START_OTA_IF_NECESSARY: 1002 case CMD_DUMP_EUICC_SERVICE: 1003 return (BaseEuiccCommandCallback) message.obj; 1004 case CMD_GET_DOWNLOADABLE_SUBSCRIPTION_METADATA: 1005 return ((GetMetadataRequest) message.obj).mCallback; 1006 case CMD_DOWNLOAD_SUBSCRIPTION: 1007 return ((DownloadRequest) message.obj).mCallback; 1008 case CMD_GET_DEFAULT_DOWNLOADABLE_SUBSCRIPTION_LIST: 1009 return ((GetDefaultListRequest) message.obj).mCallback; 1010 case CMD_DELETE_SUBSCRIPTION: 1011 return ((DeleteRequest) message.obj).mCallback; 1012 case CMD_SWITCH_TO_SUBSCRIPTION: 1013 return ((SwitchRequest) message.obj).mCallback; 1014 case CMD_UPDATE_SUBSCRIPTION_NICKNAME: 1015 return ((UpdateNicknameRequest) message.obj).mCallback; 1016 default: 1017 throw new IllegalArgumentException("Unsupported message: " + message.what); 1018 } 1019 } 1020 1021 /** 1022 * Gets the slot ID from the card ID. 1023 */ getSlotIdFromCardId(int cardId)1024 private int getSlotIdFromCardId(int cardId) { 1025 if (cardId == TelephonyManager.UNSUPPORTED_CARD_ID 1026 || cardId == TelephonyManager.UNINITIALIZED_CARD_ID) { 1027 return SubscriptionManager.INVALID_SIM_SLOT_INDEX; 1028 } 1029 TelephonyManager tm = (TelephonyManager) 1030 mContext.getSystemService(Context.TELEPHONY_SERVICE); 1031 List<UiccCardInfo> infos = tm.getUiccCardsInfo(); 1032 if (infos == null || infos.size() == 0) { 1033 return SubscriptionManager.INVALID_SIM_SLOT_INDEX; 1034 } 1035 int slotId = SubscriptionManager.INVALID_SIM_SLOT_INDEX; 1036 for (UiccCardInfo info : infos) { 1037 if (info.getCardId() == cardId) { 1038 slotId = info.getSlotIndex(); 1039 } 1040 } 1041 return slotId; 1042 } 1043 1044 /** Call this at the beginning of the execution of any command. */ onCommandStart(BaseEuiccCommandCallback callback)1045 private void onCommandStart(BaseEuiccCommandCallback callback) { 1046 mActiveCommandCallbacks.add(callback); 1047 removeMessages(CMD_LINGER_TIMEOUT); 1048 } 1049 1050 /** Call this at the end of execution of any command (whether or not it succeeded). */ onCommandEnd(BaseEuiccCommandCallback callback)1051 private void onCommandEnd(BaseEuiccCommandCallback callback) { 1052 if (!mActiveCommandCallbacks.remove(callback)) { 1053 Log.wtf(TAG, "Callback already removed from mActiveCommandCallbacks"); 1054 } 1055 if (mActiveCommandCallbacks.isEmpty()) { 1056 sendMessageDelayed(CMD_LINGER_TIMEOUT, LINGER_TIMEOUT_MILLIS); 1057 } 1058 } 1059 1060 /** Return the service info of the EuiccService to bind to, or null if none were found. */ 1061 @Nullable findBestComponent()1062 private ServiceInfo findBestComponent() { 1063 return (ServiceInfo) findBestComponent(mPm); 1064 } 1065 1066 /** 1067 * Bring up a binding to the currently-selected component. 1068 * 1069 * <p>Returns true if we've successfully bound to the service. 1070 */ createBinding()1071 private boolean createBinding() { 1072 if (mSelectedComponent == null) { 1073 Log.wtf(TAG, "Attempting to create binding but no component is selected"); 1074 return false; 1075 } 1076 Intent intent = new Intent(EuiccService.EUICC_SERVICE_INTERFACE); 1077 intent.setComponent(new ComponentName(mSelectedComponent.packageName, 1078 mSelectedComponent.name)); 1079 // We bind this as a foreground service because it is operating directly on the SIM, and we 1080 // do not want it subjected to power-savings restrictions while doing so. 1081 return mContext.bindService(intent, this, 1082 Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE); 1083 } 1084 unbind()1085 private void unbind() { 1086 mEuiccService = null; 1087 mContext.unbindService(this); 1088 } 1089 findBestComponent( PackageManager packageManager, List<ResolveInfo> resolveInfoList)1090 private static ComponentInfo findBestComponent( 1091 PackageManager packageManager, List<ResolveInfo> resolveInfoList) { 1092 int bestPriority = Integer.MIN_VALUE; 1093 ComponentInfo bestComponent = null; 1094 if (resolveInfoList != null) { 1095 for (ResolveInfo resolveInfo : resolveInfoList) { 1096 if (!isValidEuiccComponent(packageManager, resolveInfo)) { 1097 continue; 1098 } 1099 1100 if (resolveInfo.filter.getPriority() > bestPriority) { 1101 bestPriority = resolveInfo.filter.getPriority(); 1102 bestComponent = TelephonyUtils.getComponentInfo(resolveInfo); 1103 } 1104 } 1105 } 1106 1107 return bestComponent; 1108 } 1109 isValidEuiccComponent( PackageManager packageManager, ResolveInfo resolveInfo)1110 private static boolean isValidEuiccComponent( 1111 PackageManager packageManager, ResolveInfo resolveInfo) { 1112 ComponentInfo componentInfo = TelephonyUtils.getComponentInfo(resolveInfo); 1113 String packageName = new ComponentName(componentInfo.packageName, componentInfo.name) 1114 .getPackageName(); 1115 1116 // Verify that the app is privileged (via granting of a privileged permission). 1117 if (packageManager.checkPermission( 1118 Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS, packageName) 1119 != PackageManager.PERMISSION_GRANTED) { 1120 Log.wtf(TAG, "Package " + packageName 1121 + " does not declare WRITE_EMBEDDED_SUBSCRIPTIONS"); 1122 return false; 1123 } 1124 1125 // Verify that only the system can access the component. 1126 final String permission; 1127 if (componentInfo instanceof ServiceInfo) { 1128 permission = ((ServiceInfo) componentInfo).permission; 1129 } else if (componentInfo instanceof ActivityInfo) { 1130 permission = ((ActivityInfo) componentInfo).permission; 1131 } else { 1132 throw new IllegalArgumentException("Can only verify services/activities"); 1133 } 1134 if (!TextUtils.equals(permission, Manifest.permission.BIND_EUICC_SERVICE)) { 1135 Log.wtf(TAG, "Package " + packageName 1136 + " does not require the BIND_EUICC_SERVICE permission"); 1137 return false; 1138 } 1139 1140 // Verify that the component declares a priority. 1141 if (resolveInfo.filter == null || resolveInfo.filter.getPriority() == 0) { 1142 Log.wtf(TAG, "Package " + packageName + " does not specify a priority"); 1143 return false; 1144 } 1145 return true; 1146 } 1147 1148 @Override onServiceConnected(ComponentName name, IBinder service)1149 public void onServiceConnected(ComponentName name, IBinder service) { 1150 IEuiccService euiccService = IEuiccService.Stub.asInterface(service); 1151 sendMessage(CMD_SERVICE_CONNECTED, euiccService); 1152 } 1153 1154 @Override onServiceDisconnected(ComponentName name)1155 public void onServiceDisconnected(ComponentName name) { 1156 sendMessage(CMD_SERVICE_DISCONNECTED); 1157 } 1158 1159 private class EuiccPackageMonitor extends PackageChangeReceiver { 1160 @Override onPackageAdded(String packageName)1161 public void onPackageAdded(String packageName) { 1162 sendPackageChange(packageName, true /* forceUnbindForThisPackage */); 1163 } 1164 1165 @Override onPackageRemoved(String packageName)1166 public void onPackageRemoved(String packageName) { 1167 sendPackageChange(packageName, true /* forceUnbindForThisPackage */); 1168 } 1169 1170 @Override onPackageUpdateFinished(String packageName)1171 public void onPackageUpdateFinished(String packageName) { 1172 sendPackageChange(packageName, true /* forceUnbindForThisPackage */); 1173 } 1174 1175 @Override onPackageModified(String packageName)1176 public void onPackageModified(String packageName) { 1177 sendPackageChange(packageName, false /* forceUnbindForThisPackage */); 1178 } 1179 1180 @Override onHandleForceStop(String[] packages, boolean doit)1181 public void onHandleForceStop(String[] packages, boolean doit) { 1182 if (doit) { 1183 for (String packageName : packages) { 1184 sendPackageChange(packageName, true /* forceUnbindForThisPackage */); 1185 } 1186 } 1187 } 1188 sendPackageChange(String packageName, boolean forceUnbindForThisPackage)1189 private void sendPackageChange(String packageName, boolean forceUnbindForThisPackage) { 1190 sendMessage(CMD_PACKAGE_CHANGE, forceUnbindForThisPackage ? packageName : null); 1191 } 1192 } 1193 1194 @Override unhandledMessage(Message msg)1195 protected void unhandledMessage(Message msg) { 1196 IState state = getCurrentState(); 1197 Log.wtf(TAG, "Unhandled message " + msg.what + " in state " 1198 + (state == null ? "null" : state.getName())); 1199 } 1200 1201 @Override dump(FileDescriptor fd, PrintWriter pw, String[] args)1202 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1203 super.dump(fd, pw, args); 1204 pw.println("mSelectedComponent=" + mSelectedComponent); 1205 pw.println("mEuiccService=" + mEuiccService); 1206 pw.println("mActiveCommandCount=" + mActiveCommandCallbacks.size()); 1207 } 1208 updateSubscriptionInfoListForAllAccessibleEuiccs()1209 private void updateSubscriptionInfoListForAllAccessibleEuiccs() { 1210 if (mTm.getCardIdForDefaultEuicc() == TelephonyManager.UNSUPPORTED_CARD_ID) { 1211 // Device does not support card ID 1212 mSm.requestEmbeddedSubscriptionInfoListRefresh(); 1213 } else { 1214 for (UiccCardInfo cardInfo : mTm.getUiccCardsInfo()) { 1215 if (cardInfo.isEuicc()) { 1216 mSm.requestEmbeddedSubscriptionInfoListRefresh(cardInfo.getCardId()); 1217 } 1218 } 1219 } 1220 } 1221 } 1222