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