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