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