1 /* 2 * Copyright (C) 2011-2012 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 17 package com.android.internal.telephony.uicc; 18 19 import static android.telephony.TelephonyManager.UNINITIALIZED_CARD_ID; 20 import static android.telephony.TelephonyManager.UNSUPPORTED_CARD_ID; 21 22 import static java.util.Arrays.copyOf; 23 24 import android.app.BroadcastOptions; 25 import android.compat.annotation.UnsupportedAppUsage; 26 import android.content.Context; 27 import android.content.Intent; 28 import android.content.SharedPreferences; 29 import android.content.pm.PackageManager; 30 import android.os.AsyncResult; 31 import android.os.Handler; 32 import android.os.Message; 33 import android.os.Registrant; 34 import android.os.RegistrantList; 35 import android.os.storage.StorageManager; 36 import android.preference.PreferenceManager; 37 import android.sysprop.TelephonyProperties; 38 import android.telephony.CarrierConfigManager; 39 import android.telephony.SubscriptionManager; 40 import android.telephony.TelephonyManager; 41 import android.telephony.UiccCardInfo; 42 import android.text.TextUtils; 43 import android.util.LocalLog; 44 45 import com.android.internal.annotations.VisibleForTesting; 46 import com.android.internal.telephony.CommandException; 47 import com.android.internal.telephony.CommandsInterface; 48 import com.android.internal.telephony.IccCardConstants; 49 import com.android.internal.telephony.PhoneConfigurationManager; 50 import com.android.internal.telephony.PhoneConstants; 51 import com.android.internal.telephony.PhoneFactory; 52 import com.android.internal.telephony.RadioConfig; 53 import com.android.internal.telephony.SubscriptionInfoUpdater; 54 import com.android.internal.telephony.uicc.euicc.EuiccCard; 55 import com.android.internal.telephony.util.TelephonyUtils; 56 import com.android.telephony.Rlog; 57 58 import java.io.FileDescriptor; 59 import java.io.PrintWriter; 60 import java.util.ArrayList; 61 import java.util.Arrays; 62 import java.util.HashSet; 63 import java.util.Set; 64 65 /** 66 * This class is responsible for keeping all knowledge about 67 * Universal Integrated Circuit Card (UICC), also know as SIM's, 68 * in the system. It is also used as API to get appropriate 69 * applications to pass them to phone and service trackers. 70 * 71 * UiccController is created with the call to make() function. 72 * UiccController is a singleton and make() must only be called once 73 * and throws an exception if called multiple times. 74 * 75 * Once created UiccController registers with RIL for "on" and "unsol_sim_status_changed" 76 * notifications. When such notification arrives UiccController will call 77 * getIccCardStatus (GET_SIM_STATUS). Based on the response of GET_SIM_STATUS 78 * request appropriate tree of uicc objects will be created. 79 * 80 * Following is class diagram for uicc classes: 81 * 82 * UiccController 83 * # 84 * | 85 * UiccSlot[] 86 * # 87 * | 88 * UiccCard 89 * # 90 * | 91 * UiccProfile 92 * # # 93 * | ------------------ 94 * UiccCardApplication CatService 95 * # # 96 * | | 97 * IccRecords IccFileHandler 98 * ^ ^ ^ ^ ^ ^ ^ ^ 99 * SIMRecords---- | | | | | | ---SIMFileHandler 100 * RuimRecords----- | | | | ----RuimFileHandler 101 * IsimUiccRecords--- | | -----UsimFileHandler 102 * | ------CsimFileHandler 103 * ----IsimFileHandler 104 * 105 * Legend: # stands for Composition 106 * ^ stands for Generalization 107 * 108 * See also {@link com.android.internal.telephony.IccCard} 109 */ 110 public class UiccController extends Handler { 111 private static final boolean DBG = true; 112 private static final boolean VDBG = false; //STOPSHIP if true 113 private static final String LOG_TAG = "UiccController"; 114 115 public static final int INVALID_SLOT_ID = -1; 116 117 public static final int APP_FAM_3GPP = 1; 118 public static final int APP_FAM_3GPP2 = 2; 119 public static final int APP_FAM_IMS = 3; 120 121 private static final int EVENT_ICC_STATUS_CHANGED = 1; 122 private static final int EVENT_SLOT_STATUS_CHANGED = 2; 123 private static final int EVENT_GET_ICC_STATUS_DONE = 3; 124 private static final int EVENT_GET_SLOT_STATUS_DONE = 4; 125 private static final int EVENT_RADIO_ON = 5; 126 private static final int EVENT_RADIO_AVAILABLE = 6; 127 private static final int EVENT_RADIO_UNAVAILABLE = 7; 128 private static final int EVENT_SIM_REFRESH = 8; 129 private static final int EVENT_EID_READY = 9; 130 private static final int EVENT_MULTI_SIM_CONFIG_CHANGED = 10; 131 // NOTE: any new EVENT_* values must be added to eventToString. 132 133 // this needs to be here, because on bootup we dont know which index maps to which UiccSlot 134 @UnsupportedAppUsage 135 private CommandsInterface[] mCis; 136 @VisibleForTesting 137 public UiccSlot[] mUiccSlots; 138 private int[] mPhoneIdToSlotId; 139 private boolean mIsSlotStatusSupported = true; 140 141 // This maps the externally exposed card ID (int) to the internal card ID string (ICCID/EID). 142 // The array index is the card ID (int). 143 // This mapping exists to expose card-based functionality without exposing the EID, which is 144 // considered sensetive information. 145 // mCardStrings is populated using values from the IccSlotStatus and IccCardStatus. For 146 // HAL < 1.2, these do not contain the EID or the ICCID, so mCardStrings will be empty 147 private ArrayList<String> mCardStrings; 148 149 // This is the card ID of the default eUICC. It starts as UNINITIALIZED_CARD_ID. 150 // When we load the EID (either with slot status or from the EuiccCard), we set it to the eUICC 151 // with the lowest slot index. 152 // If EID is not supported (e.g. on HAL version < 1.2), we set it to UNSUPPORTED_CARD_ID 153 private int mDefaultEuiccCardId; 154 155 // Default Euicc Card ID used when the device is temporarily unable to read the EID (e.g. on HAL 156 // 1.2-1.3 if the eUICC is currently inactive). This value is only used within the 157 // UiccController and should be converted to UNSUPPORTED_CARD_ID when others ask. 158 // (This value is -3 because UNSUPPORTED_CARD_ID and UNINITIALIZED_CARD_ID are -1 and -2) 159 private static final int TEMPORARILY_UNSUPPORTED_CARD_ID = -3; 160 161 // GSM SGP.02 section 2.2.2 states that the EID is always 32 digits long 162 private static final int EID_LENGTH = 32; 163 164 // SharedPreference key for saving the known card strings (ICCIDs and EIDs) ordered by card ID 165 private static final String CARD_STRINGS = "card_strings"; 166 167 // Whether the device has an eUICC built in. 168 private boolean mHasBuiltInEuicc = false; 169 170 // Whether the device has a currently active built in eUICC 171 private boolean mHasActiveBuiltInEuicc = false; 172 173 // The physical slots which correspond to built-in eUICCs 174 private final int[] mEuiccSlots; 175 176 // SharedPreferences key for saving the default euicc card ID 177 private static final String DEFAULT_CARD = "default_card"; 178 179 @UnsupportedAppUsage 180 private static final Object mLock = new Object(); 181 @UnsupportedAppUsage 182 private static UiccController mInstance; 183 @VisibleForTesting 184 public static ArrayList<IccSlotStatus> sLastSlotStatus; 185 186 @UnsupportedAppUsage 187 @VisibleForTesting 188 public Context mContext; 189 190 protected RegistrantList mIccChangedRegistrants = new RegistrantList(); 191 192 private UiccStateChangedLauncher mLauncher; 193 private RadioConfig mRadioConfig; 194 195 // LocalLog buffer to hold important SIM related events for debugging 196 private static LocalLog sLocalLog = new LocalLog(TelephonyUtils.IS_DEBUGGABLE ? 250 : 100); 197 198 /** 199 * API to make UiccController singleton if not already created. 200 */ make(Context c)201 public static UiccController make(Context c) { 202 synchronized (mLock) { 203 if (mInstance != null) { 204 throw new RuntimeException("UiccController.make() should only be called once"); 205 } 206 mInstance = new UiccController(c); 207 return mInstance; 208 } 209 } 210 UiccController(Context c)211 private UiccController(Context c) { 212 if (DBG) log("Creating UiccController"); 213 mContext = c; 214 mCis = PhoneFactory.getCommandsInterfaces(); 215 int numPhysicalSlots = c.getResources().getInteger( 216 com.android.internal.R.integer.config_num_physical_slots); 217 numPhysicalSlots = TelephonyProperties.sim_slots_count().orElse(numPhysicalSlots); 218 if (DBG) { 219 logWithLocalLog("config_num_physical_slots = " + numPhysicalSlots); 220 } 221 // Minimum number of physical slot count should be equals to or greater than phone count, 222 // if it is less than phone count use phone count as physical slot count. 223 if (numPhysicalSlots < mCis.length) { 224 numPhysicalSlots = mCis.length; 225 } 226 227 mUiccSlots = new UiccSlot[numPhysicalSlots]; 228 mPhoneIdToSlotId = new int[mCis.length]; 229 Arrays.fill(mPhoneIdToSlotId, INVALID_SLOT_ID); 230 if (VDBG) logPhoneIdToSlotIdMapping(); 231 mRadioConfig = RadioConfig.getInstance(mContext); 232 mRadioConfig.registerForSimSlotStatusChanged(this, EVENT_SLOT_STATUS_CHANGED, null); 233 for (int i = 0; i < mCis.length; i++) { 234 mCis[i].registerForIccStatusChanged(this, EVENT_ICC_STATUS_CHANGED, i); 235 236 if (!StorageManager.inCryptKeeperBounce()) { 237 mCis[i].registerForAvailable(this, EVENT_RADIO_AVAILABLE, i); 238 } else { 239 mCis[i].registerForOn(this, EVENT_RADIO_ON, i); 240 } 241 242 mCis[i].registerForNotAvailable(this, EVENT_RADIO_UNAVAILABLE, i); 243 mCis[i].registerForIccRefresh(this, EVENT_SIM_REFRESH, i); 244 } 245 246 mLauncher = new UiccStateChangedLauncher(c, this); 247 mCardStrings = loadCardStrings(); 248 mDefaultEuiccCardId = UNINITIALIZED_CARD_ID; 249 250 mEuiccSlots = mContext.getResources() 251 .getIntArray(com.android.internal.R.array.non_removable_euicc_slots); 252 mHasBuiltInEuicc = hasBuiltInEuicc(); 253 254 PhoneConfigurationManager.registerForMultiSimConfigChange( 255 this, EVENT_MULTI_SIM_CONFIG_CHANGED, null); 256 } 257 258 /** 259 * Given the slot index, return the phone ID, or -1 if no phone is associated with the given 260 * slot. 261 * @param slotId the slot index to check 262 * @return the associated phone ID or -1 263 */ getPhoneIdFromSlotId(int slotId)264 public int getPhoneIdFromSlotId(int slotId) { 265 for (int i = 0; i < mPhoneIdToSlotId.length; i++) { 266 if (mPhoneIdToSlotId[i] == slotId) { 267 return i; 268 } 269 } 270 return -1; 271 } 272 273 /** 274 * Return the physical slot id associated with the given phoneId, or INVALID_SLOT_ID. 275 * @param phoneId the phoneId to check 276 */ getSlotIdFromPhoneId(int phoneId)277 public int getSlotIdFromPhoneId(int phoneId) { 278 try { 279 return mPhoneIdToSlotId[phoneId]; 280 } catch (ArrayIndexOutOfBoundsException e) { 281 return INVALID_SLOT_ID; 282 } 283 } 284 285 @UnsupportedAppUsage getInstance()286 public static UiccController getInstance() { 287 synchronized (mLock) { 288 if (mInstance == null) { 289 throw new RuntimeException( 290 "UiccController.getInstance can't be called before make()"); 291 } 292 return mInstance; 293 } 294 } 295 296 @UnsupportedAppUsage getUiccCard(int phoneId)297 public UiccCard getUiccCard(int phoneId) { 298 synchronized (mLock) { 299 return getUiccCardForPhone(phoneId); 300 } 301 } 302 303 /** 304 * API to get UiccCard corresponding to given physical slot index 305 * @param slotId index of physical slot on the device 306 * @return UiccCard object corresponting to given physical slot index; null if card is 307 * absent 308 */ getUiccCardForSlot(int slotId)309 public UiccCard getUiccCardForSlot(int slotId) { 310 synchronized (mLock) { 311 UiccSlot uiccSlot = getUiccSlot(slotId); 312 if (uiccSlot != null) { 313 return uiccSlot.getUiccCard(); 314 } 315 return null; 316 } 317 } 318 319 /** 320 * API to get UiccCard corresponding to given phone id 321 * @return UiccCard object corresponding to given phone id; null if there is no card present for 322 * the phone id 323 */ getUiccCardForPhone(int phoneId)324 public UiccCard getUiccCardForPhone(int phoneId) { 325 synchronized (mLock) { 326 if (isValidPhoneIndex(phoneId)) { 327 UiccSlot uiccSlot = getUiccSlotForPhone(phoneId); 328 if (uiccSlot != null) { 329 return uiccSlot.getUiccCard(); 330 } 331 } 332 return null; 333 } 334 } 335 336 /** 337 * API to get UiccProfile corresponding to given phone id 338 * @return UiccProfile object corresponding to given phone id; null if there is no card/profile 339 * present for the phone id 340 */ getUiccProfileForPhone(int phoneId)341 public UiccProfile getUiccProfileForPhone(int phoneId) { 342 synchronized (mLock) { 343 if (isValidPhoneIndex(phoneId)) { 344 UiccCard uiccCard = getUiccCardForPhone(phoneId); 345 return uiccCard != null ? uiccCard.getUiccProfile() : null; 346 } 347 return null; 348 } 349 } 350 351 /** 352 * API to get all the UICC slots. 353 * @return UiccSlots array. 354 */ getUiccSlots()355 public UiccSlot[] getUiccSlots() { 356 synchronized (mLock) { 357 return mUiccSlots; 358 } 359 } 360 361 /** Map logicalSlot to physicalSlot, and activate the physicalSlot if it is inactive. */ switchSlots(int[] physicalSlots, Message response)362 public void switchSlots(int[] physicalSlots, Message response) { 363 logWithLocalLog("switchSlots: " + Arrays.toString(physicalSlots)); 364 mRadioConfig.setSimSlotsMapping(physicalSlots, response); 365 } 366 367 /** 368 * API to get UiccSlot object for a specific physical slot index on the device 369 * @return UiccSlot object for the given physical slot index 370 */ getUiccSlot(int slotId)371 public UiccSlot getUiccSlot(int slotId) { 372 synchronized (mLock) { 373 if (isValidSlotIndex(slotId)) { 374 return mUiccSlots[slotId]; 375 } 376 return null; 377 } 378 } 379 380 /** 381 * API to get UiccSlot object for a given phone id 382 * @return UiccSlot object for the given phone id 383 */ getUiccSlotForPhone(int phoneId)384 public UiccSlot getUiccSlotForPhone(int phoneId) { 385 synchronized (mLock) { 386 if (isValidPhoneIndex(phoneId)) { 387 int slotId = getSlotIdFromPhoneId(phoneId); 388 if (isValidSlotIndex(slotId)) { 389 return mUiccSlots[slotId]; 390 } 391 } 392 return null; 393 } 394 } 395 396 /** 397 * API to get UiccSlot object for a given cardId 398 * @param cardId Identifier for a SIM. This can be an ICCID, or an EID in case of an eSIM. 399 * @return int Index of UiccSlot for the given cardId if one is found, {@link #INVALID_SLOT_ID} 400 * otherwise 401 */ getUiccSlotForCardId(String cardId)402 public int getUiccSlotForCardId(String cardId) { 403 synchronized (mLock) { 404 // first look up based on cardId 405 for (int idx = 0; idx < mUiccSlots.length; idx++) { 406 if (mUiccSlots[idx] != null) { 407 UiccCard uiccCard = mUiccSlots[idx].getUiccCard(); 408 if (uiccCard != null && cardId.equals(uiccCard.getCardId())) { 409 return idx; 410 } 411 } 412 } 413 // if a match is not found, do a lookup based on ICCID 414 for (int idx = 0; idx < mUiccSlots.length; idx++) { 415 if (mUiccSlots[idx] != null && cardId.equals(mUiccSlots[idx].getIccId())) { 416 return idx; 417 } 418 } 419 return INVALID_SLOT_ID; 420 } 421 } 422 423 // Easy to use API 424 @UnsupportedAppUsage getIccRecords(int phoneId, int family)425 public IccRecords getIccRecords(int phoneId, int family) { 426 synchronized (mLock) { 427 UiccCardApplication app = getUiccCardApplication(phoneId, family); 428 if (app != null) { 429 return app.getIccRecords(); 430 } 431 return null; 432 } 433 } 434 435 // Easy to use API 436 @UnsupportedAppUsage getIccFileHandler(int phoneId, int family)437 public IccFileHandler getIccFileHandler(int phoneId, int family) { 438 synchronized (mLock) { 439 UiccCardApplication app = getUiccCardApplication(phoneId, family); 440 if (app != null) { 441 return app.getIccFileHandler(); 442 } 443 return null; 444 } 445 } 446 447 448 //Notifies when card status changes 449 @UnsupportedAppUsage registerForIccChanged(Handler h, int what, Object obj)450 public void registerForIccChanged(Handler h, int what, Object obj) { 451 synchronized (mLock) { 452 mIccChangedRegistrants.addUnique(h, what, obj); 453 } 454 //Notify registrant right after registering, so that it will get the latest ICC status, 455 //otherwise which may not happen until there is an actual change in ICC status. 456 Message.obtain(h, what, new AsyncResult(obj, null, null)).sendToTarget(); 457 } 458 unregisterForIccChanged(Handler h)459 public void unregisterForIccChanged(Handler h) { 460 synchronized (mLock) { 461 mIccChangedRegistrants.remove(h); 462 } 463 } 464 465 @Override handleMessage(Message msg)466 public void handleMessage (Message msg) { 467 synchronized (mLock) { 468 Integer phoneId = getCiIndex(msg); 469 String eventName = eventToString(msg.what); 470 471 if (phoneId < 0 || phoneId >= mCis.length) { 472 Rlog.e(LOG_TAG, "Invalid phoneId : " + phoneId + " received with event " 473 + eventName); 474 return; 475 } 476 477 logWithLocalLog("handleMessage: Received " + eventName + " for phoneId " + phoneId); 478 479 AsyncResult ar = (AsyncResult)msg.obj; 480 switch (msg.what) { 481 case EVENT_ICC_STATUS_CHANGED: 482 if (DBG) log("Received EVENT_ICC_STATUS_CHANGED, calling getIccCardStatus"); 483 mCis[phoneId].getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE, 484 phoneId)); 485 break; 486 case EVENT_RADIO_AVAILABLE: 487 case EVENT_RADIO_ON: 488 if (DBG) { 489 log("Received EVENT_RADIO_AVAILABLE/EVENT_RADIO_ON, calling " 490 + "getIccCardStatus"); 491 } 492 mCis[phoneId].getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE, 493 phoneId)); 494 // slot status should be the same on all RILs; request it only for phoneId 0 495 if (phoneId == 0) { 496 if (DBG) { 497 log("Received EVENT_RADIO_AVAILABLE/EVENT_RADIO_ON for phoneId 0, " 498 + "calling getIccSlotsStatus"); 499 } 500 mRadioConfig.getSimSlotsStatus(obtainMessage(EVENT_GET_SLOT_STATUS_DONE, 501 phoneId)); 502 } 503 break; 504 case EVENT_GET_ICC_STATUS_DONE: 505 if (DBG) log("Received EVENT_GET_ICC_STATUS_DONE"); 506 onGetIccCardStatusDone(ar, phoneId); 507 break; 508 case EVENT_SLOT_STATUS_CHANGED: 509 case EVENT_GET_SLOT_STATUS_DONE: 510 if (DBG) { 511 log("Received EVENT_SLOT_STATUS_CHANGED or EVENT_GET_SLOT_STATUS_DONE"); 512 } 513 onGetSlotStatusDone(ar); 514 break; 515 case EVENT_RADIO_UNAVAILABLE: 516 if (DBG) log("EVENT_RADIO_UNAVAILABLE, dispose card"); 517 UiccSlot uiccSlot = getUiccSlotForPhone(phoneId); 518 if (uiccSlot != null) { 519 uiccSlot.onRadioStateUnavailable(); 520 } 521 mIccChangedRegistrants.notifyRegistrants(new AsyncResult(null, phoneId, null)); 522 break; 523 case EVENT_SIM_REFRESH: 524 if (DBG) log("Received EVENT_SIM_REFRESH"); 525 onSimRefresh(ar, phoneId); 526 break; 527 case EVENT_EID_READY: 528 if (DBG) log("Received EVENT_EID_READY"); 529 onEidReady(ar, phoneId); 530 break; 531 case EVENT_MULTI_SIM_CONFIG_CHANGED: 532 if (DBG) log("Received EVENT_MULTI_SIM_CONFIG_CHANGED"); 533 int activeModemCount = (int) ((AsyncResult) msg.obj).result; 534 onMultiSimConfigChanged(activeModemCount); 535 break; 536 default: 537 Rlog.e(LOG_TAG, " Unknown Event " + msg.what); 538 break; 539 } 540 } 541 } 542 onMultiSimConfigChanged(int newActiveModemCount)543 private void onMultiSimConfigChanged(int newActiveModemCount) { 544 int prevActiveModemCount = mCis.length; 545 mCis = PhoneFactory.getCommandsInterfaces(); 546 547 logWithLocalLog("onMultiSimConfigChanged: prevActiveModemCount " + prevActiveModemCount 548 + ", newActiveModemCount " + newActiveModemCount); 549 550 // Resize array. 551 mPhoneIdToSlotId = copyOf(mPhoneIdToSlotId, newActiveModemCount); 552 553 // Register for new active modem for ss -> ds switch. 554 // For ds -> ss switch, there's no need to unregister as the mCis should unregister 555 // everything itself. 556 for (int i = prevActiveModemCount; i < newActiveModemCount; i++) { 557 mPhoneIdToSlotId[i] = INVALID_SLOT_ID; 558 mCis[i].registerForIccStatusChanged(this, EVENT_ICC_STATUS_CHANGED, i); 559 560 /* 561 * To support FDE (deprecated), additional check is needed: 562 * 563 * if (!StorageManager.inCryptKeeperBounce()) { 564 * mCis[i].registerForAvailable(this, EVENT_RADIO_AVAILABLE, i); 565 * } else { 566 * mCis[i].registerForOn(this, EVENT_RADIO_ON, i); 567 * } 568 */ 569 mCis[i].registerForAvailable(this, EVENT_RADIO_AVAILABLE, i); 570 571 mCis[i].registerForNotAvailable(this, EVENT_RADIO_UNAVAILABLE, i); 572 mCis[i].registerForIccRefresh(this, EVENT_SIM_REFRESH, i); 573 } 574 } 575 getCiIndex(Message msg)576 private Integer getCiIndex(Message msg) { 577 AsyncResult ar; 578 Integer index = new Integer(PhoneConstants.DEFAULT_SLOT_INDEX); 579 580 /* 581 * The events can be come in two ways. By explicitly sending it using 582 * sendMessage, in this case the user object passed is msg.obj and from 583 * the CommandsInterface, in this case the user object is msg.obj.userObj 584 */ 585 if (msg != null) { 586 if (msg.obj != null && msg.obj instanceof Integer) { 587 index = (Integer)msg.obj; 588 } else if(msg.obj != null && msg.obj instanceof AsyncResult) { 589 ar = (AsyncResult)msg.obj; 590 if (ar.userObj != null && ar.userObj instanceof Integer) { 591 index = (Integer)ar.userObj; 592 } 593 } 594 } 595 return index; 596 } 597 eventToString(int event)598 private static String eventToString(int event) { 599 switch (event) { 600 case EVENT_ICC_STATUS_CHANGED: return "ICC_STATUS_CHANGED"; 601 case EVENT_SLOT_STATUS_CHANGED: return "SLOT_STATUS_CHANGED"; 602 case EVENT_GET_ICC_STATUS_DONE: return "GET_ICC_STATUS_DONE"; 603 case EVENT_GET_SLOT_STATUS_DONE: return "GET_SLOT_STATUS_DONE"; 604 case EVENT_RADIO_ON: return "RADIO_ON"; 605 case EVENT_RADIO_AVAILABLE: return "RADIO_AVAILABLE"; 606 case EVENT_RADIO_UNAVAILABLE: return "RADIO_UNAVAILABLE"; 607 case EVENT_SIM_REFRESH: return "SIM_REFRESH"; 608 case EVENT_EID_READY: return "EID_READY"; 609 case EVENT_MULTI_SIM_CONFIG_CHANGED: return "MULTI_SIM_CONFIG_CHANGED"; 610 default: return "UNKNOWN(" + event + ")"; 611 } 612 } 613 614 // Easy to use API 615 @UnsupportedAppUsage getUiccCardApplication(int phoneId, int family)616 public UiccCardApplication getUiccCardApplication(int phoneId, int family) { 617 synchronized (mLock) { 618 UiccCard uiccCard = getUiccCardForPhone(phoneId); 619 if (uiccCard != null) { 620 return uiccCard.getApplication(family); 621 } 622 return null; 623 } 624 } 625 getIccStateIntentString(IccCardConstants.State state)626 static String getIccStateIntentString(IccCardConstants.State state) { 627 switch (state) { 628 case ABSENT: return IccCardConstants.INTENT_VALUE_ICC_ABSENT; 629 case PIN_REQUIRED: return IccCardConstants.INTENT_VALUE_ICC_LOCKED; 630 case PUK_REQUIRED: return IccCardConstants.INTENT_VALUE_ICC_LOCKED; 631 case NETWORK_LOCKED: return IccCardConstants.INTENT_VALUE_ICC_LOCKED; 632 case READY: return IccCardConstants.INTENT_VALUE_ICC_READY; 633 case NOT_READY: return IccCardConstants.INTENT_VALUE_ICC_NOT_READY; 634 case PERM_DISABLED: return IccCardConstants.INTENT_VALUE_ICC_LOCKED; 635 case CARD_IO_ERROR: return IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR; 636 case CARD_RESTRICTED: return IccCardConstants.INTENT_VALUE_ICC_CARD_RESTRICTED; 637 case LOADED: return IccCardConstants.INTENT_VALUE_ICC_LOADED; 638 default: return IccCardConstants.INTENT_VALUE_ICC_UNKNOWN; 639 } 640 } 641 updateInternalIccStateForInactiveSlot( Context context, int prevActivePhoneId, String iccId)642 static void updateInternalIccStateForInactiveSlot( 643 Context context, int prevActivePhoneId, String iccId) { 644 if (SubscriptionManager.isValidPhoneId(prevActivePhoneId)) { 645 // Mark SIM state as ABSENT on previously phoneId. 646 TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService( 647 Context.TELEPHONY_SERVICE); 648 telephonyManager.setSimStateForPhone(prevActivePhoneId, 649 IccCardConstants.State.ABSENT.toString()); 650 } 651 652 SubscriptionInfoUpdater subInfoUpdator = PhoneFactory.getSubscriptionInfoUpdater(); 653 if (subInfoUpdator != null) { 654 subInfoUpdator.updateInternalIccStateForInactiveSlot(prevActivePhoneId, iccId); 655 } else { 656 Rlog.e(LOG_TAG, "subInfoUpdate is null."); 657 } 658 } 659 updateInternalIccState(Context context, IccCardConstants.State state, String reason, int phoneId)660 static void updateInternalIccState(Context context, IccCardConstants.State state, String reason, 661 int phoneId) { 662 TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService( 663 Context.TELEPHONY_SERVICE); 664 telephonyManager.setSimStateForPhone(phoneId, state.toString()); 665 666 SubscriptionInfoUpdater subInfoUpdator = PhoneFactory.getSubscriptionInfoUpdater(); 667 if (subInfoUpdator != null) { 668 subInfoUpdator.updateInternalIccState(getIccStateIntentString(state), reason, phoneId); 669 } else { 670 Rlog.e(LOG_TAG, "subInfoUpdate is null."); 671 } 672 } 673 onGetIccCardStatusDone(AsyncResult ar, Integer index)674 private synchronized void onGetIccCardStatusDone(AsyncResult ar, Integer index) { 675 if (ar.exception != null) { 676 Rlog.e(LOG_TAG,"Error getting ICC status. " 677 + "RIL_REQUEST_GET_ICC_STATUS should " 678 + "never return an error", ar.exception); 679 return; 680 } 681 if (!isValidPhoneIndex(index)) { 682 Rlog.e(LOG_TAG,"onGetIccCardStatusDone: invalid index : " + index); 683 return; 684 } 685 686 IccCardStatus status = (IccCardStatus)ar.result; 687 688 logWithLocalLog("onGetIccCardStatusDone: phoneId " + index + " IccCardStatus: " + status); 689 690 int slotId = status.physicalSlotIndex; 691 if (VDBG) log("onGetIccCardStatusDone: phoneId " + index + " physicalSlotIndex " + slotId); 692 if (slotId == INVALID_SLOT_ID) { 693 slotId = index; 694 } 695 696 if (eidIsNotSupported(status)) { 697 // we will never get EID from the HAL, so set mDefaultEuiccCardId to UNSUPPORTED_CARD_ID 698 if (DBG) log("eid is not supported"); 699 mDefaultEuiccCardId = UNSUPPORTED_CARD_ID; 700 } 701 mPhoneIdToSlotId[index] = slotId; 702 703 if (VDBG) logPhoneIdToSlotIdMapping(); 704 705 if (mUiccSlots[slotId] == null) { 706 if (VDBG) { 707 log("Creating mUiccSlots[" + slotId + "]; mUiccSlots.length = " 708 + mUiccSlots.length); 709 } 710 mUiccSlots[slotId] = new UiccSlot(mContext, true); 711 } 712 713 mUiccSlots[slotId].update(mCis[index], status, index, slotId); 714 715 UiccCard card = mUiccSlots[slotId].getUiccCard(); 716 if (card == null) { 717 if (DBG) log("mUiccSlots[" + slotId + "] has no card. Notifying IccChangedRegistrants"); 718 mIccChangedRegistrants.notifyRegistrants(new AsyncResult(null, index, null)); 719 return; 720 } 721 722 String cardString = null; 723 boolean isEuicc = mUiccSlots[slotId].isEuicc(); 724 if (isEuicc) { 725 cardString = ((EuiccCard) card).getEid(); 726 } else { 727 cardString = card.getIccId(); 728 } 729 730 if (cardString != null) { 731 addCardId(cardString); 732 } 733 734 // EID is unpopulated if Radio HAL < 1.4 (RadioConfig < 1.2) 735 // If so, just register for EID loaded and skip this stuff 736 if (isEuicc && mDefaultEuiccCardId != UNSUPPORTED_CARD_ID) { 737 if (cardString == null) { 738 ((EuiccCard) card).registerForEidReady(this, EVENT_EID_READY, index); 739 } else { 740 // If we know the EID from IccCardStatus, just use it to set mDefaultEuiccCardId if 741 // it's not already set. 742 // This is needed in cases where slot status doesn't include EID, and we don't want 743 // to register for EID from APDU because we already know cardString from a previous 744 // APDU 745 if (mDefaultEuiccCardId == UNINITIALIZED_CARD_ID 746 || mDefaultEuiccCardId == TEMPORARILY_UNSUPPORTED_CARD_ID) { 747 mDefaultEuiccCardId = convertToPublicCardId(cardString); 748 logWithLocalLog("IccCardStatus eid=" + cardString + " slot=" + slotId 749 + " mDefaultEuiccCardId=" + mDefaultEuiccCardId); 750 } 751 } 752 } 753 754 if (DBG) log("Notifying IccChangedRegistrants"); 755 mIccChangedRegistrants.notifyRegistrants(new AsyncResult(null, index, null)); 756 } 757 758 /** 759 * Returns true if EID is not supproted. 760 */ eidIsNotSupported(IccCardStatus status)761 private boolean eidIsNotSupported(IccCardStatus status) { 762 // if card status does not contain slot ID, we know we are on HAL < 1.2, so EID will never 763 // be available 764 return status.physicalSlotIndex == INVALID_SLOT_ID; 765 } 766 767 /** 768 * Add a cardString to mCardStrings. If this is an ICCID, trailing Fs will be automatically 769 * stripped. 770 */ addCardId(String cardString)771 private void addCardId(String cardString) { 772 if (TextUtils.isEmpty(cardString)) { 773 return; 774 } 775 if (cardString.length() < EID_LENGTH) { 776 cardString = IccUtils.stripTrailingFs(cardString); 777 } 778 if (!mCardStrings.contains(cardString)) { 779 mCardStrings.add(cardString); 780 saveCardStrings(); 781 } 782 } 783 784 /** 785 * Converts an integer cardId (public card ID) to a card string. 786 * @param cardId to convert 787 * @return cardString, or null if the cardId is not valid 788 */ convertToCardString(int cardId)789 public String convertToCardString(int cardId) { 790 if (cardId < 0 || cardId >= mCardStrings.size()) { 791 log("convertToCardString: cardId " + cardId + " is not valid"); 792 return null; 793 } 794 return mCardStrings.get(cardId); 795 } 796 797 /** 798 * Converts the card string (the ICCID/EID, formerly named card ID) to the public int cardId. 799 * If the given cardString is an ICCID, trailing Fs will be automatically stripped before trying 800 * to match to a card ID. 801 * 802 * @return the matching cardId, or UNINITIALIZED_CARD_ID if the card string does not map to a 803 * currently loaded cardId, or UNSUPPORTED_CARD_ID if the device does not support card IDs 804 */ convertToPublicCardId(String cardString)805 public int convertToPublicCardId(String cardString) { 806 if (mDefaultEuiccCardId == UNSUPPORTED_CARD_ID) { 807 // even if cardString is not an EID, if EID is not supported (e.g. HAL < 1.2) we can't 808 // guarentee a working card ID implementation, so return UNSUPPORTED_CARD_ID 809 return UNSUPPORTED_CARD_ID; 810 } 811 if (TextUtils.isEmpty(cardString)) { 812 return UNINITIALIZED_CARD_ID; 813 } 814 815 if (cardString.length() < EID_LENGTH) { 816 cardString = IccUtils.stripTrailingFs(cardString); 817 } 818 int id = mCardStrings.indexOf(cardString); 819 if (id == -1) { 820 return UNINITIALIZED_CARD_ID; 821 } else { 822 return id; 823 } 824 } 825 826 /** 827 * Returns the UiccCardInfo of all currently inserted UICCs and embedded eUICCs. 828 */ getAllUiccCardInfos()829 public ArrayList<UiccCardInfo> getAllUiccCardInfos() { 830 ArrayList<UiccCardInfo> infos = new ArrayList<>(); 831 for (int slotIndex = 0; slotIndex < mUiccSlots.length; slotIndex++) { 832 final UiccSlot slot = mUiccSlots[slotIndex]; 833 if (slot == null) continue; 834 boolean isEuicc = slot.isEuicc(); 835 String eid = null; 836 UiccCard card = slot.getUiccCard(); 837 String iccid = null; 838 int cardId = UNINITIALIZED_CARD_ID; 839 boolean isRemovable = slot.isRemovable(); 840 841 // first we try to populate UiccCardInfo using the UiccCard, but if it doesn't exist 842 // (e.g. the slot is for an inactive eUICC) then we try using the UiccSlot. 843 if (card != null) { 844 iccid = card.getIccId(); 845 if (isEuicc) { 846 eid = ((EuiccCard) card).getEid(); 847 cardId = convertToPublicCardId(eid); 848 } else { 849 // leave eid null if the UICC is not embedded 850 cardId = convertToPublicCardId(iccid); 851 } 852 } else { 853 iccid = slot.getIccId(); 854 // Fill in the fields we can 855 if (!isEuicc && !TextUtils.isEmpty(iccid)) { 856 cardId = convertToPublicCardId(iccid); 857 } 858 } 859 UiccCardInfo info = new UiccCardInfo(isEuicc, cardId, eid, 860 IccUtils.stripTrailingFs(iccid), slotIndex, isRemovable); 861 infos.add(info); 862 } 863 return infos; 864 } 865 866 /** 867 * Get the card ID of the default eUICC. 868 */ getCardIdForDefaultEuicc()869 public int getCardIdForDefaultEuicc() { 870 if (mDefaultEuiccCardId == TEMPORARILY_UNSUPPORTED_CARD_ID) { 871 return UNSUPPORTED_CARD_ID; 872 } 873 return mDefaultEuiccCardId; 874 } 875 loadCardStrings()876 private ArrayList<String> loadCardStrings() { 877 String cardStrings = 878 PreferenceManager.getDefaultSharedPreferences(mContext).getString(CARD_STRINGS, ""); 879 if (TextUtils.isEmpty(cardStrings)) { 880 // just return an empty list, since String.split would return the list { "" } 881 return new ArrayList<String>(); 882 } 883 return new ArrayList<String>(Arrays.asList(cardStrings.split(","))); 884 } 885 saveCardStrings()886 private void saveCardStrings() { 887 SharedPreferences.Editor editor = 888 PreferenceManager.getDefaultSharedPreferences(mContext).edit(); 889 editor.putString(CARD_STRINGS, TextUtils.join(",", mCardStrings)); 890 editor.commit(); 891 } 892 onGetSlotStatusDone(AsyncResult ar)893 private synchronized void onGetSlotStatusDone(AsyncResult ar) { 894 if (!mIsSlotStatusSupported) { 895 if (VDBG) log("onGetSlotStatusDone: ignoring since mIsSlotStatusSupported is false"); 896 return; 897 } 898 Throwable e = ar.exception; 899 if (e != null) { 900 if (!(e instanceof CommandException) || ((CommandException) e).getCommandError() 901 != CommandException.Error.REQUEST_NOT_SUPPORTED) { 902 // this is not expected; there should be no exception other than 903 // REQUEST_NOT_SUPPORTED 904 logeWithLocalLog("Unexpected error getting slot status: " + ar.exception); 905 } else { 906 // REQUEST_NOT_SUPPORTED 907 logWithLocalLog("onGetSlotStatusDone: request not supported; marking " 908 + "mIsSlotStatusSupported to false"); 909 mIsSlotStatusSupported = false; 910 } 911 return; 912 } 913 914 ArrayList<IccSlotStatus> status = (ArrayList<IccSlotStatus>) ar.result; 915 916 if (!slotStatusChanged(status)) { 917 log("onGetSlotStatusDone: No change in slot status"); 918 return; 919 } 920 logWithLocalLog("onGetSlotStatusDone: " + status); 921 922 sLastSlotStatus = status; 923 924 int numActiveSlots = 0; 925 boolean isDefaultEuiccCardIdSet = false; 926 boolean anyEuiccIsActive = false; 927 mHasActiveBuiltInEuicc = false; 928 929 int numSlots = status.size(); 930 if (mUiccSlots.length < numSlots) { 931 logeWithLocalLog("The number of the physical slots reported " + numSlots 932 + " is greater than the expectation " + mUiccSlots.length); 933 numSlots = mUiccSlots.length; 934 } 935 936 for (int i = 0; i < numSlots; i++) { 937 IccSlotStatus iss = status.get(i); 938 boolean isActive = (iss.slotState == IccSlotStatus.SlotState.SLOTSTATE_ACTIVE); 939 if (isActive) { 940 numActiveSlots++; 941 942 // sanity check: logicalSlotIndex should be valid for an active slot 943 if (!isValidPhoneIndex(iss.logicalSlotIndex)) { 944 Rlog.e(LOG_TAG, "Skipping slot " + i + " as phone " + iss.logicalSlotIndex 945 + " is not available to communicate with this slot"); 946 } else { 947 mPhoneIdToSlotId[iss.logicalSlotIndex] = i; 948 } 949 } 950 951 if (mUiccSlots[i] == null) { 952 if (VDBG) { 953 log("Creating mUiccSlot[" + i + "]; mUiccSlots.length = " + mUiccSlots.length); 954 } 955 mUiccSlots[i] = new UiccSlot(mContext, isActive); 956 } 957 958 if (!isValidPhoneIndex(iss.logicalSlotIndex)) { 959 mUiccSlots[i].update(null, iss, i /* slotIndex */); 960 } else { 961 mUiccSlots[i].update(isActive ? mCis[iss.logicalSlotIndex] : null, iss, 962 i /* slotIndex */); 963 } 964 965 if (mUiccSlots[i].isEuicc()) { 966 if (isActive) { 967 anyEuiccIsActive = true; 968 969 if (isBuiltInEuiccSlot(i)) { 970 mHasActiveBuiltInEuicc = true; 971 } 972 } 973 String eid = iss.eid; 974 if (TextUtils.isEmpty(eid)) { 975 // iss.eid is not populated on HAL<1.4 976 continue; 977 } 978 979 addCardId(eid); 980 981 // whenever slot status is received, set default card to the non-removable eUICC 982 // with the lowest slot index. 983 if (!mUiccSlots[i].isRemovable() && !isDefaultEuiccCardIdSet) { 984 isDefaultEuiccCardIdSet = true; 985 mDefaultEuiccCardId = convertToPublicCardId(eid); 986 logWithLocalLog("Using eid=" + eid + " in slot=" + i 987 + " to set mDefaultEuiccCardId=" + mDefaultEuiccCardId); 988 } 989 } 990 } 991 992 if (!mHasActiveBuiltInEuicc && !isDefaultEuiccCardIdSet) { 993 // if there are no active built-in eUICCs, then consider setting a removable eUICC to 994 // the default. 995 // Note that on HAL<1.2, it's possible that a built-in eUICC exists, but does not 996 // correspond to any slot in mUiccSlots. This logic is still safe in that case because 997 // SlotStatus is only for HAL >= 1.2 998 for (int i = 0; i < numSlots; i++) { 999 if (mUiccSlots[i].isEuicc()) { 1000 String eid = status.get(i).eid; 1001 if (!TextUtils.isEmpty(eid)) { 1002 isDefaultEuiccCardIdSet = true; 1003 mDefaultEuiccCardId = convertToPublicCardId(eid); 1004 logWithLocalLog("Using eid=" + eid + " from removable eUICC in slot=" 1005 + i + " to set mDefaultEuiccCardId=" + mDefaultEuiccCardId); 1006 break; 1007 } 1008 } 1009 } 1010 } 1011 1012 if (mHasBuiltInEuicc && !anyEuiccIsActive && !isDefaultEuiccCardIdSet) { 1013 logWithLocalLog( 1014 "onGetSlotStatusDone: mDefaultEuiccCardId=TEMPORARILY_UNSUPPORTED_CARD_ID"); 1015 isDefaultEuiccCardIdSet = true; 1016 mDefaultEuiccCardId = TEMPORARILY_UNSUPPORTED_CARD_ID; 1017 } 1018 1019 1020 if (!isDefaultEuiccCardIdSet) { 1021 if (mDefaultEuiccCardId >= 0) { 1022 // if mDefaultEuiccCardId has already been set to an actual eUICC, 1023 // don't overwrite mDefaultEuiccCardId unless that eUICC is no longer inserted 1024 boolean defaultEuiccCardIdIsStillInserted = false; 1025 String cardString = mCardStrings.get(mDefaultEuiccCardId); 1026 for (UiccSlot slot : mUiccSlots) { 1027 if (slot.getUiccCard() == null) { 1028 continue; 1029 } 1030 if (cardString.equals( 1031 IccUtils.stripTrailingFs(slot.getUiccCard().getCardId()))) { 1032 defaultEuiccCardIdIsStillInserted = true; 1033 } 1034 } 1035 if (!defaultEuiccCardIdIsStillInserted) { 1036 logWithLocalLog("onGetSlotStatusDone: mDefaultEuiccCardId=" 1037 + mDefaultEuiccCardId 1038 + " is no longer inserted. Setting mDefaultEuiccCardId=UNINITIALIZED"); 1039 mDefaultEuiccCardId = UNINITIALIZED_CARD_ID; 1040 } 1041 } else { 1042 // no known eUICCs at all (it's possible that an eUICC is inserted and we just don't 1043 // know it's EID) 1044 logWithLocalLog("onGetSlotStatusDone: mDefaultEuiccCardId=UNINITIALIZED"); 1045 mDefaultEuiccCardId = UNINITIALIZED_CARD_ID; 1046 } 1047 } 1048 1049 if (VDBG) logPhoneIdToSlotIdMapping(); 1050 1051 // sanity check: number of active slots should be valid 1052 if (numActiveSlots != mPhoneIdToSlotId.length) { 1053 Rlog.e(LOG_TAG, "Number of active slots " + numActiveSlots 1054 + " does not match the number of Phones" + mPhoneIdToSlotId.length); 1055 } 1056 1057 // sanity check: slotIds should be unique in mPhoneIdToSlotId 1058 Set<Integer> slotIds = new HashSet<>(); 1059 for (int slotId : mPhoneIdToSlotId) { 1060 if (slotIds.contains(slotId)) { 1061 throw new RuntimeException("slotId " + slotId + " mapped to multiple phoneIds"); 1062 } 1063 slotIds.add(slotId); 1064 } 1065 1066 // broadcast slot status changed 1067 final BroadcastOptions options = BroadcastOptions.makeBasic(); 1068 options.setBackgroundActivityStartsAllowed(true); 1069 Intent intent = new Intent(TelephonyManager.ACTION_SIM_SLOT_STATUS_CHANGED); 1070 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1071 mContext.sendBroadcast(intent, android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, 1072 options.toBundle()); 1073 } 1074 slotStatusChanged(ArrayList<IccSlotStatus> slotStatusList)1075 private boolean slotStatusChanged(ArrayList<IccSlotStatus> slotStatusList) { 1076 if (sLastSlotStatus == null || sLastSlotStatus.size() != slotStatusList.size()) { 1077 return true; 1078 } 1079 for (IccSlotStatus iccSlotStatus : slotStatusList) { 1080 if (!sLastSlotStatus.contains(iccSlotStatus)) { 1081 return true; 1082 } 1083 } 1084 return false; 1085 } 1086 logPhoneIdToSlotIdMapping()1087 private void logPhoneIdToSlotIdMapping() { 1088 log("mPhoneIdToSlotId mapping:"); 1089 for (int i = 0; i < mPhoneIdToSlotId.length; i++) { 1090 log(" phoneId " + i + " slotId " + mPhoneIdToSlotId[i]); 1091 } 1092 } 1093 onSimRefresh(AsyncResult ar, Integer index)1094 private void onSimRefresh(AsyncResult ar, Integer index) { 1095 if (ar.exception != null) { 1096 Rlog.e(LOG_TAG, "onSimRefresh: Sim REFRESH with exception: " + ar.exception); 1097 return; 1098 } 1099 1100 if (!isValidPhoneIndex(index)) { 1101 Rlog.e(LOG_TAG,"onSimRefresh: invalid index : " + index); 1102 return; 1103 } 1104 1105 IccRefreshResponse resp = (IccRefreshResponse) ar.result; 1106 logWithLocalLog("onSimRefresh: index " + index + ", " + resp); 1107 1108 if (resp == null) { 1109 Rlog.e(LOG_TAG, "onSimRefresh: received without input"); 1110 return; 1111 } 1112 1113 UiccCard uiccCard = getUiccCardForPhone(index); 1114 if (uiccCard == null) { 1115 Rlog.e(LOG_TAG,"onSimRefresh: refresh on null card : " + index); 1116 return; 1117 } 1118 1119 boolean changed = false; 1120 switch(resp.refreshResult) { 1121 // Reset the required apps when we know about the refresh so that 1122 // anyone interested does not get stale state. 1123 case IccRefreshResponse.REFRESH_RESULT_RESET: 1124 changed = uiccCard.resetAppWithAid(resp.aid, true /* reset */); 1125 break; 1126 case IccRefreshResponse.REFRESH_RESULT_INIT: 1127 // don't dispose CatService on SIM REFRESH of type INIT 1128 changed = uiccCard.resetAppWithAid(resp.aid, false /* initialize */); 1129 break; 1130 default: 1131 return; 1132 } 1133 1134 if (changed && resp.refreshResult == IccRefreshResponse.REFRESH_RESULT_RESET) { 1135 // If there is any change on RESET, reset carrier config as well. From carrier config 1136 // perspective, this is treated the same as sim state unknown 1137 CarrierConfigManager configManager = (CarrierConfigManager) 1138 mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE); 1139 configManager.updateConfigForPhoneId(index, IccCardConstants.INTENT_VALUE_ICC_UNKNOWN); 1140 1141 boolean requirePowerOffOnSimRefreshReset = mContext.getResources().getBoolean( 1142 com.android.internal.R.bool.config_requireRadioPowerOffOnSimRefreshReset); 1143 if (requirePowerOffOnSimRefreshReset) { 1144 mCis[index].setRadioPower(false, null); 1145 } 1146 } 1147 1148 // The card status could have changed. Get the latest state. 1149 mCis[index].getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE, index)); 1150 } 1151 1152 // for HAL 1.2-1.3 we register for EID ready, set mCardStrings and mDefaultEuiccCardId here. 1153 // Note that if there are multiple eUICCs on HAL 1.2-1.3, the default eUICC is the one whose EID 1154 // is first loaded onEidReady(AsyncResult ar, Integer index)1155 private void onEidReady(AsyncResult ar, Integer index) { 1156 if (ar.exception != null) { 1157 Rlog.e(LOG_TAG, "onEidReady: exception: " + ar.exception); 1158 return; 1159 } 1160 1161 if (!isValidPhoneIndex(index)) { 1162 Rlog.e(LOG_TAG, "onEidReady: invalid index: " + index); 1163 return; 1164 } 1165 int slotId = mPhoneIdToSlotId[index]; 1166 EuiccCard card = (EuiccCard) mUiccSlots[slotId].getUiccCard(); 1167 if (card == null) { 1168 Rlog.e(LOG_TAG, "onEidReady: UiccCard in slot " + slotId + " is null"); 1169 return; 1170 } 1171 1172 // set mCardStrings and the defaultEuiccCardId using the now available EID 1173 String eid = card.getEid(); 1174 addCardId(eid); 1175 if (mDefaultEuiccCardId == UNINITIALIZED_CARD_ID 1176 || mDefaultEuiccCardId == TEMPORARILY_UNSUPPORTED_CARD_ID) { 1177 if (!mUiccSlots[slotId].isRemovable()) { 1178 mDefaultEuiccCardId = convertToPublicCardId(eid); 1179 logWithLocalLog("onEidReady: eid=" + eid + " slot=" + slotId 1180 + " mDefaultEuiccCardId=" + mDefaultEuiccCardId); 1181 } else if (!mHasActiveBuiltInEuicc) { 1182 // we only set a removable eUICC to the default if there are no active non-removable 1183 // eUICCs 1184 mDefaultEuiccCardId = convertToPublicCardId(eid); 1185 logWithLocalLog("onEidReady: eid=" + eid + " from removable eUICC in slot=" + slotId 1186 + " mDefaultEuiccCardId=" + mDefaultEuiccCardId); 1187 } 1188 } 1189 card.unregisterForEidReady(this); 1190 } 1191 1192 // Return true if the device has at least one built in eUICC based on the resource overlay hasBuiltInEuicc()1193 private boolean hasBuiltInEuicc() { 1194 return mEuiccSlots != null && mEuiccSlots.length > 0; 1195 } 1196 isBuiltInEuiccSlot(int slotIndex)1197 private boolean isBuiltInEuiccSlot(int slotIndex) { 1198 if (!mHasBuiltInEuicc) { 1199 return false; 1200 } 1201 for (int slot : mEuiccSlots) { 1202 if (slot == slotIndex) { 1203 return true; 1204 } 1205 } 1206 return false; 1207 } 1208 1209 /** 1210 * static method to return whether CDMA is supported on the device 1211 * @param context object representative of the application that is calling this method 1212 * @return true if CDMA is supported by the device 1213 */ isCdmaSupported(Context context)1214 public static boolean isCdmaSupported(Context context) { 1215 PackageManager packageManager = context.getPackageManager(); 1216 boolean isCdmaSupported = 1217 packageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY_CDMA); 1218 return isCdmaSupported; 1219 } 1220 isValidPhoneIndex(int index)1221 private boolean isValidPhoneIndex(int index) { 1222 return (index >= 0 && index < TelephonyManager.getDefault().getPhoneCount()); 1223 } 1224 isValidSlotIndex(int index)1225 private boolean isValidSlotIndex(int index) { 1226 return (index >= 0 && index < mUiccSlots.length); 1227 } 1228 1229 @UnsupportedAppUsage log(String string)1230 private void log(String string) { 1231 Rlog.d(LOG_TAG, string); 1232 } 1233 logWithLocalLog(String string)1234 private void logWithLocalLog(String string) { 1235 Rlog.d(LOG_TAG, string); 1236 sLocalLog.log("UiccController: " + string); 1237 } 1238 logeWithLocalLog(String string)1239 private void logeWithLocalLog(String string) { 1240 Rlog.e(LOG_TAG, string); 1241 sLocalLog.log("UiccController: " + string); 1242 } 1243 1244 /** The supplied log should also indicate the caller to avoid ambiguity. */ addLocalLog(String data)1245 public static void addLocalLog(String data) { 1246 sLocalLog.log(data); 1247 } 1248 dump(FileDescriptor fd, PrintWriter pw, String[] args)1249 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1250 pw.println("UiccController: " + this); 1251 pw.println(" mContext=" + mContext); 1252 pw.println(" mInstance=" + mInstance); 1253 pw.println(" mIccChangedRegistrants: size=" + mIccChangedRegistrants.size()); 1254 for (int i = 0; i < mIccChangedRegistrants.size(); i++) { 1255 pw.println(" mIccChangedRegistrants[" + i + "]=" 1256 + ((Registrant)mIccChangedRegistrants.get(i)).getHandler()); 1257 } 1258 pw.println(); 1259 pw.flush(); 1260 pw.println(" mIsCdmaSupported=" + isCdmaSupported(mContext)); 1261 pw.println(" mHasBuiltInEuicc=" + mHasBuiltInEuicc); 1262 pw.println(" mHasActiveBuiltInEuicc=" + mHasActiveBuiltInEuicc); 1263 pw.println(" mUiccSlots: size=" + mUiccSlots.length); 1264 pw.println(" mCardStrings=" + mCardStrings); 1265 pw.println(" mDefaultEuiccCardId=" + mDefaultEuiccCardId); 1266 for (int i = 0; i < mUiccSlots.length; i++) { 1267 if (mUiccSlots[i] == null) { 1268 pw.println(" mUiccSlots[" + i + "]=null"); 1269 } else { 1270 pw.println(" mUiccSlots[" + i + "]=" + mUiccSlots[i]); 1271 mUiccSlots[i].dump(fd, pw, args); 1272 } 1273 } 1274 pw.println(" sLocalLog= "); 1275 sLocalLog.dump(fd, pw, args); 1276 } 1277 } 1278