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 android.content.Context; 20 import android.content.Intent; 21 import android.os.AsyncResult; 22 import android.os.Handler; 23 import android.os.Message; 24 import android.os.Registrant; 25 import android.os.RegistrantList; 26 import android.os.storage.StorageManager; 27 import android.telephony.CarrierConfigManager; 28 import android.telephony.Rlog; 29 import android.telephony.TelephonyManager; 30 import android.util.LocalLog; 31 32 import com.android.internal.telephony.CommandException; 33 import com.android.internal.telephony.CommandsInterface; 34 import com.android.internal.telephony.IccCardConstants; 35 import com.android.internal.telephony.PhoneConstants; 36 import com.android.internal.telephony.PhoneFactory; 37 import com.android.internal.telephony.RadioConfig; 38 import com.android.internal.telephony.SubscriptionInfoUpdater; 39 40 import java.io.FileDescriptor; 41 import java.io.PrintWriter; 42 import java.util.ArrayList; 43 import java.util.Arrays; 44 import java.util.HashSet; 45 import java.util.Set; 46 47 /** 48 * This class is responsible for keeping all knowledge about 49 * Universal Integrated Circuit Card (UICC), also know as SIM's, 50 * in the system. It is also used as API to get appropriate 51 * applications to pass them to phone and service trackers. 52 * 53 * UiccController is created with the call to make() function. 54 * UiccController is a singleton and make() must only be called once 55 * and throws an exception if called multiple times. 56 * 57 * Once created UiccController registers with RIL for "on" and "unsol_sim_status_changed" 58 * notifications. When such notification arrives UiccController will call 59 * getIccCardStatus (GET_SIM_STATUS). Based on the response of GET_SIM_STATUS 60 * request appropriate tree of uicc objects will be created. 61 * 62 * Following is class diagram for uicc classes: 63 * 64 * UiccController 65 * # 66 * | 67 * UiccSlot[] 68 * # 69 * | 70 * UiccCard 71 * # 72 * | 73 * UiccProfile 74 * # # 75 * | ------------------ 76 * UiccCardApplication CatService 77 * # # 78 * | | 79 * IccRecords IccFileHandler 80 * ^ ^ ^ ^ ^ ^ ^ ^ 81 * SIMRecords---- | | | | | | ---SIMFileHandler 82 * RuimRecords----- | | | | ----RuimFileHandler 83 * IsimUiccRecords--- | | -----UsimFileHandler 84 * | ------CsimFileHandler 85 * ----IsimFileHandler 86 * 87 * Legend: # stands for Composition 88 * ^ stands for Generalization 89 * 90 * See also {@link com.android.internal.telephony.IccCard} 91 */ 92 public class UiccController extends Handler { 93 private static final boolean DBG = true; 94 private static final boolean VDBG = false; //STOPSHIP if true 95 private static final String LOG_TAG = "UiccController"; 96 97 public static final int INVALID_SLOT_ID = -1; 98 99 public static final int APP_FAM_3GPP = 1; 100 public static final int APP_FAM_3GPP2 = 2; 101 public static final int APP_FAM_IMS = 3; 102 103 private static final int EVENT_ICC_STATUS_CHANGED = 1; 104 private static final int EVENT_SLOT_STATUS_CHANGED = 2; 105 private static final int EVENT_GET_ICC_STATUS_DONE = 3; 106 private static final int EVENT_GET_SLOT_STATUS_DONE = 4; 107 private static final int EVENT_RADIO_ON = 5; 108 private static final int EVENT_RADIO_AVAILABLE = 6; 109 private static final int EVENT_RADIO_UNAVAILABLE = 7; 110 private static final int EVENT_SIM_REFRESH = 8; 111 112 // this needs to be here, because on bootup we dont know which index maps to which UiccSlot 113 private CommandsInterface[] mCis; 114 private UiccSlot[] mUiccSlots; 115 private int[] mPhoneIdToSlotId; 116 private boolean mIsSlotStatusSupported = true; 117 118 private static final Object mLock = new Object(); 119 private static UiccController mInstance; 120 private static ArrayList<IccSlotStatus> sLastSlotStatus; 121 122 private Context mContext; 123 124 protected RegistrantList mIccChangedRegistrants = new RegistrantList(); 125 126 private UiccStateChangedLauncher mLauncher; 127 private RadioConfig mRadioConfig; 128 129 // LocalLog buffer to hold important SIM related events for debugging 130 static LocalLog sLocalLog = new LocalLog(100); 131 make(Context c, CommandsInterface[] ci)132 public static UiccController make(Context c, CommandsInterface[] ci) { 133 synchronized (mLock) { 134 if (mInstance != null) { 135 throw new RuntimeException("UiccController.make() should only be called once"); 136 } 137 mInstance = new UiccController(c, ci); 138 return mInstance; 139 } 140 } 141 UiccController(Context c, CommandsInterface []ci)142 private UiccController(Context c, CommandsInterface []ci) { 143 if (DBG) log("Creating UiccController"); 144 mContext = c; 145 mCis = ci; 146 if (DBG) { 147 String logStr = "config_num_physical_slots = " + c.getResources().getInteger( 148 com.android.internal.R.integer.config_num_physical_slots); 149 log(logStr); 150 sLocalLog.log(logStr); 151 } 152 int numPhysicalSlots = c.getResources().getInteger( 153 com.android.internal.R.integer.config_num_physical_slots); 154 // Minimum number of physical slot count should be equals to or greater than phone count, 155 // if it is less than phone count use phone count as physical slot count. 156 if (numPhysicalSlots < mCis.length) { 157 numPhysicalSlots = mCis.length; 158 } 159 160 mUiccSlots = new UiccSlot[numPhysicalSlots]; 161 mPhoneIdToSlotId = new int[ci.length]; 162 Arrays.fill(mPhoneIdToSlotId, INVALID_SLOT_ID); 163 if (VDBG) logPhoneIdToSlotIdMapping(); 164 mRadioConfig = RadioConfig.getInstance(mContext); 165 mRadioConfig.registerForSimSlotStatusChanged(this, EVENT_SLOT_STATUS_CHANGED, null); 166 for (int i = 0; i < mCis.length; i++) { 167 mCis[i].registerForIccStatusChanged(this, EVENT_ICC_STATUS_CHANGED, i); 168 169 // TODO remove this once modem correctly notifies the unsols 170 // If the device is unencrypted or has been decrypted or FBE is supported, 171 // i.e. not in CryptKeeper bounce, read SIM when radio state is available. 172 // Else wait for radio to be on. This is needed for the scenario when SIM is locked -- 173 // to avoid overlap of CryptKeeper and SIM unlock screen. 174 if (!StorageManager.inCryptKeeperBounce()) { 175 mCis[i].registerForAvailable(this, EVENT_RADIO_AVAILABLE, i); 176 } else { 177 mCis[i].registerForOn(this, EVENT_RADIO_ON, i); 178 } 179 mCis[i].registerForNotAvailable(this, EVENT_RADIO_UNAVAILABLE, i); 180 mCis[i].registerForIccRefresh(this, EVENT_SIM_REFRESH, i); 181 } 182 183 mLauncher = new UiccStateChangedLauncher(c, this); 184 } 185 getSlotIdFromPhoneId(int phoneId)186 private int getSlotIdFromPhoneId(int phoneId) { 187 return mPhoneIdToSlotId[phoneId]; 188 } 189 getInstance()190 public static UiccController getInstance() { 191 synchronized (mLock) { 192 if (mInstance == null) { 193 throw new RuntimeException( 194 "UiccController.getInstance can't be called before make()"); 195 } 196 return mInstance; 197 } 198 } 199 getUiccCard(int phoneId)200 public UiccCard getUiccCard(int phoneId) { 201 synchronized (mLock) { 202 return getUiccCardForPhone(phoneId); 203 } 204 } 205 206 /** 207 * API to get UiccCard corresponding to given physical slot index 208 * @param slotId index of physical slot on the device 209 * @return UiccCard object corresponting to given physical slot index; null if card is 210 * absent 211 */ getUiccCardForSlot(int slotId)212 public UiccCard getUiccCardForSlot(int slotId) { 213 synchronized (mLock) { 214 UiccSlot uiccSlot = getUiccSlot(slotId); 215 if (uiccSlot != null) { 216 return uiccSlot.getUiccCard(); 217 } 218 return null; 219 } 220 } 221 222 /** 223 * API to get UiccCard corresponding to given phone id 224 * @return UiccCard object corresponding to given phone id; null if there is no card present for 225 * the phone id 226 */ getUiccCardForPhone(int phoneId)227 public UiccCard getUiccCardForPhone(int phoneId) { 228 synchronized (mLock) { 229 if (isValidPhoneIndex(phoneId)) { 230 UiccSlot uiccSlot = getUiccSlotForPhone(phoneId); 231 if (uiccSlot != null) { 232 return uiccSlot.getUiccCard(); 233 } 234 } 235 return null; 236 } 237 } 238 239 /** 240 * API to get UiccProfile corresponding to given phone id 241 * @return UiccProfile object corresponding to given phone id; null if there is no card/profile 242 * present for the phone id 243 */ getUiccProfileForPhone(int phoneId)244 public UiccProfile getUiccProfileForPhone(int phoneId) { 245 synchronized (mLock) { 246 if (isValidPhoneIndex(phoneId)) { 247 UiccCard uiccCard = getUiccCardForPhone(phoneId); 248 return uiccCard != null ? uiccCard.getUiccProfile() : null; 249 } 250 return null; 251 } 252 } 253 254 /** 255 * API to get all the UICC slots. 256 * @return UiccSlots array. 257 */ getUiccSlots()258 public UiccSlot[] getUiccSlots() { 259 synchronized (mLock) { 260 return mUiccSlots; 261 } 262 } 263 264 /** Map logicalSlot to physicalSlot, and activate the physicalSlot if it is inactive. */ switchSlots(int[] physicalSlots, Message response)265 public void switchSlots(int[] physicalSlots, Message response) { 266 mRadioConfig.setSimSlotsMapping(physicalSlots, response); 267 } 268 269 /** 270 * API to get UiccSlot object for a specific physical slot index on the device 271 * @return UiccSlot object for the given physical slot index 272 */ getUiccSlot(int slotId)273 public UiccSlot getUiccSlot(int slotId) { 274 synchronized (mLock) { 275 if (isValidSlotIndex(slotId)) { 276 return mUiccSlots[slotId]; 277 } 278 return null; 279 } 280 } 281 282 /** 283 * API to get UiccSlot object for a given phone id 284 * @return UiccSlot object for the given phone id 285 */ getUiccSlotForPhone(int phoneId)286 public UiccSlot getUiccSlotForPhone(int phoneId) { 287 synchronized (mLock) { 288 if (isValidPhoneIndex(phoneId)) { 289 int slotId = getSlotIdFromPhoneId(phoneId); 290 if (isValidSlotIndex(slotId)) { 291 return mUiccSlots[slotId]; 292 } 293 } 294 return null; 295 } 296 } 297 298 /** 299 * API to get UiccSlot object for a given cardId 300 * @param cardId Identifier for a SIM. This can be an ICCID, or an EID in case of an eSIM. 301 * @return int Index of UiccSlot for the given cardId if one is found, {@link #INVALID_SLOT_ID} 302 * otherwise 303 */ getUiccSlotForCardId(String cardId)304 public int getUiccSlotForCardId(String cardId) { 305 synchronized (mLock) { 306 // first look up based on cardId 307 for (int idx = 0; idx < mUiccSlots.length; idx++) { 308 if (mUiccSlots[idx] != null) { 309 UiccCard uiccCard = mUiccSlots[idx].getUiccCard(); 310 if (uiccCard != null && cardId.equals(uiccCard.getCardId())) { 311 return idx; 312 } 313 } 314 } 315 // if a match is not found, do a lookup based on ICCID 316 for (int idx = 0; idx < mUiccSlots.length; idx++) { 317 if (mUiccSlots[idx] != null && cardId.equals(mUiccSlots[idx].getIccId())) { 318 return idx; 319 } 320 } 321 return INVALID_SLOT_ID; 322 } 323 } 324 325 // Easy to use API getIccRecords(int phoneId, int family)326 public IccRecords getIccRecords(int phoneId, int family) { 327 synchronized (mLock) { 328 UiccCardApplication app = getUiccCardApplication(phoneId, family); 329 if (app != null) { 330 return app.getIccRecords(); 331 } 332 return null; 333 } 334 } 335 336 // Easy to use API getIccFileHandler(int phoneId, int family)337 public IccFileHandler getIccFileHandler(int phoneId, int family) { 338 synchronized (mLock) { 339 UiccCardApplication app = getUiccCardApplication(phoneId, family); 340 if (app != null) { 341 return app.getIccFileHandler(); 342 } 343 return null; 344 } 345 } 346 347 348 //Notifies when card status changes registerForIccChanged(Handler h, int what, Object obj)349 public void registerForIccChanged(Handler h, int what, Object obj) { 350 synchronized (mLock) { 351 Registrant r = new Registrant (h, what, obj); 352 mIccChangedRegistrants.add(r); 353 //Notify registrant right after registering, so that it will get the latest ICC status, 354 //otherwise which may not happen until there is an actual change in ICC status. 355 r.notifyRegistrant(); 356 } 357 } 358 unregisterForIccChanged(Handler h)359 public void unregisterForIccChanged(Handler h) { 360 synchronized (mLock) { 361 mIccChangedRegistrants.remove(h); 362 } 363 } 364 365 @Override handleMessage(Message msg)366 public void handleMessage (Message msg) { 367 synchronized (mLock) { 368 Integer phoneId = getCiIndex(msg); 369 370 if (phoneId < 0 || phoneId >= mCis.length) { 371 Rlog.e(LOG_TAG, "Invalid phoneId : " + phoneId + " received with event " 372 + msg.what); 373 return; 374 } 375 376 sLocalLog.log("handleMessage: Received " + msg.what + " for phoneId " + phoneId); 377 378 AsyncResult ar = (AsyncResult)msg.obj; 379 switch (msg.what) { 380 case EVENT_ICC_STATUS_CHANGED: 381 if (DBG) log("Received EVENT_ICC_STATUS_CHANGED, calling getIccCardStatus"); 382 mCis[phoneId].getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE, 383 phoneId)); 384 break; 385 case EVENT_RADIO_AVAILABLE: 386 case EVENT_RADIO_ON: 387 if (DBG) { 388 log("Received EVENT_RADIO_AVAILABLE/EVENT_RADIO_ON, calling " 389 + "getIccCardStatus"); 390 } 391 mCis[phoneId].getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE, 392 phoneId)); 393 // slot status should be the same on all RILs; request it only for phoneId 0 394 if (phoneId == 0) { 395 if (DBG) { 396 log("Received EVENT_RADIO_AVAILABLE/EVENT_RADIO_ON for phoneId 0, " 397 + "calling getIccSlotsStatus"); 398 } 399 mRadioConfig.getSimSlotsStatus(obtainMessage(EVENT_GET_SLOT_STATUS_DONE, 400 phoneId)); 401 } 402 break; 403 case EVENT_GET_ICC_STATUS_DONE: 404 if (DBG) log("Received EVENT_GET_ICC_STATUS_DONE"); 405 onGetIccCardStatusDone(ar, phoneId); 406 break; 407 case EVENT_SLOT_STATUS_CHANGED: 408 case EVENT_GET_SLOT_STATUS_DONE: 409 if (DBG) { 410 log("Received EVENT_SLOT_STATUS_CHANGED or EVENT_GET_SLOT_STATUS_DONE"); 411 } 412 onGetSlotStatusDone(ar); 413 break; 414 case EVENT_RADIO_UNAVAILABLE: 415 if (DBG) log("EVENT_RADIO_UNAVAILABLE, dispose card"); 416 UiccSlot uiccSlot = getUiccSlotForPhone(phoneId); 417 if (uiccSlot != null) { 418 uiccSlot.onRadioStateUnavailable(); 419 } 420 mIccChangedRegistrants.notifyRegistrants(new AsyncResult(null, phoneId, null)); 421 break; 422 case EVENT_SIM_REFRESH: 423 if (DBG) log("Received EVENT_SIM_REFRESH"); 424 onSimRefresh(ar, phoneId); 425 break; 426 default: 427 Rlog.e(LOG_TAG, " Unknown Event " + msg.what); 428 break; 429 } 430 } 431 } 432 getCiIndex(Message msg)433 private Integer getCiIndex(Message msg) { 434 AsyncResult ar; 435 Integer index = new Integer(PhoneConstants.DEFAULT_CARD_INDEX); 436 437 /* 438 * The events can be come in two ways. By explicitly sending it using 439 * sendMessage, in this case the user object passed is msg.obj and from 440 * the CommandsInterface, in this case the user object is msg.obj.userObj 441 */ 442 if (msg != null) { 443 if (msg.obj != null && msg.obj instanceof Integer) { 444 index = (Integer)msg.obj; 445 } else if(msg.obj != null && msg.obj instanceof AsyncResult) { 446 ar = (AsyncResult)msg.obj; 447 if (ar.userObj != null && ar.userObj instanceof Integer) { 448 index = (Integer)ar.userObj; 449 } 450 } 451 } 452 return index; 453 } 454 455 // Easy to use API getUiccCardApplication(int phoneId, int family)456 public UiccCardApplication getUiccCardApplication(int phoneId, int family) { 457 synchronized (mLock) { 458 UiccCard uiccCard = getUiccCardForPhone(phoneId); 459 if (uiccCard != null) { 460 return uiccCard.getApplication(family); 461 } 462 return null; 463 } 464 } 465 updateInternalIccState(String value, String reason, int phoneId)466 static void updateInternalIccState(String value, String reason, int phoneId) { 467 SubscriptionInfoUpdater subInfoUpdator = PhoneFactory.getSubscriptionInfoUpdater(); 468 if (subInfoUpdator != null) { 469 subInfoUpdator.updateInternalIccState(value, reason, phoneId); 470 } else { 471 Rlog.e(LOG_TAG, "subInfoUpdate is null."); 472 } 473 } 474 onGetIccCardStatusDone(AsyncResult ar, Integer index)475 private synchronized void onGetIccCardStatusDone(AsyncResult ar, Integer index) { 476 if (ar.exception != null) { 477 Rlog.e(LOG_TAG,"Error getting ICC status. " 478 + "RIL_REQUEST_GET_ICC_STATUS should " 479 + "never return an error", ar.exception); 480 return; 481 } 482 if (!isValidPhoneIndex(index)) { 483 Rlog.e(LOG_TAG,"onGetIccCardStatusDone: invalid index : " + index); 484 return; 485 } 486 487 IccCardStatus status = (IccCardStatus)ar.result; 488 489 sLocalLog.log("onGetIccCardStatusDone: phoneId " + index + " IccCardStatus: " + status); 490 491 int slotId = status.physicalSlotIndex; 492 if (VDBG) log("onGetIccCardStatusDone: phoneId " + index + " physicalSlotIndex " + slotId); 493 if (slotId == INVALID_SLOT_ID) { 494 slotId = index; 495 } 496 mPhoneIdToSlotId[index] = slotId; 497 498 if (VDBG) logPhoneIdToSlotIdMapping(); 499 500 if (mUiccSlots[slotId] == null) { 501 if (VDBG) { 502 log("Creating mUiccSlots[" + slotId + "]; mUiccSlots.length = " 503 + mUiccSlots.length); 504 } 505 mUiccSlots[slotId] = new UiccSlot(mContext, true); 506 } 507 508 mUiccSlots[slotId].update(mCis[index], status, index); 509 510 if (DBG) log("Notifying IccChangedRegistrants"); 511 mIccChangedRegistrants.notifyRegistrants(new AsyncResult(null, index, null)); 512 } 513 onGetSlotStatusDone(AsyncResult ar)514 private synchronized void onGetSlotStatusDone(AsyncResult ar) { 515 if (!mIsSlotStatusSupported) { 516 if (VDBG) log("onGetSlotStatusDone: ignoring since mIsSlotStatusSupported is false"); 517 return; 518 } 519 Throwable e = ar.exception; 520 if (e != null) { 521 String logStr; 522 if (!(e instanceof CommandException) || ((CommandException) e).getCommandError() 523 != CommandException.Error.REQUEST_NOT_SUPPORTED) { 524 // this is not expected; there should be no exception other than 525 // REQUEST_NOT_SUPPORTED 526 logStr = "Unexpected error getting slot status: " + ar.exception; 527 Rlog.e(LOG_TAG, logStr); 528 sLocalLog.log(logStr); 529 } else { 530 // REQUEST_NOT_SUPPORTED 531 logStr = "onGetSlotStatusDone: request not supported; marking " 532 + "mIsSlotStatusSupported to false"; 533 log(logStr); 534 sLocalLog.log(logStr); 535 mIsSlotStatusSupported = false; 536 } 537 return; 538 } 539 540 ArrayList<IccSlotStatus> status = (ArrayList<IccSlotStatus>) ar.result; 541 542 if (!slotStatusChanged(status)) { 543 log("onGetSlotStatusDone: No change in slot status"); 544 return; 545 } 546 547 sLastSlotStatus = status; 548 549 int numActiveSlots = 0; 550 for (int i = 0; i < status.size(); i++) { 551 IccSlotStatus iss = status.get(i); 552 boolean isActive = (iss.slotState == IccSlotStatus.SlotState.SLOTSTATE_ACTIVE); 553 if (isActive) { 554 numActiveSlots++; 555 556 // sanity check: logicalSlotIndex should be valid for an active slot 557 if (!isValidPhoneIndex(iss.logicalSlotIndex)) { 558 throw new RuntimeException("Logical slot index " + iss.logicalSlotIndex 559 + " invalid for physical slot " + i); 560 } 561 mPhoneIdToSlotId[iss.logicalSlotIndex] = i; 562 } 563 564 if (mUiccSlots[i] == null) { 565 if (VDBG) { 566 log("Creating mUiccSlot[" + i + "]; mUiccSlots.length = " + mUiccSlots.length); 567 } 568 mUiccSlots[i] = new UiccSlot(mContext, isActive); 569 } 570 571 mUiccSlots[i].update(isActive ? mCis[iss.logicalSlotIndex] : null, iss); 572 } 573 574 if (VDBG) logPhoneIdToSlotIdMapping(); 575 576 // sanity check: number of active slots should be valid 577 if (numActiveSlots != mPhoneIdToSlotId.length) { 578 throw new RuntimeException("Number of active slots " + numActiveSlots 579 + " does not match the expected value " + mPhoneIdToSlotId.length); 580 } 581 582 // sanity check: slotIds should be unique in mPhoneIdToSlotId 583 Set<Integer> slotIds = new HashSet<>(); 584 for (int slotId : mPhoneIdToSlotId) { 585 if (slotIds.contains(slotId)) { 586 throw new RuntimeException("slotId " + slotId + " mapped to multiple phoneIds"); 587 } 588 slotIds.add(slotId); 589 } 590 591 // broadcast slot status changed 592 Intent intent = new Intent(TelephonyManager.ACTION_SIM_SLOT_STATUS_CHANGED); 593 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 594 intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); 595 mContext.sendBroadcast(intent, android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE); 596 } 597 slotStatusChanged(ArrayList<IccSlotStatus> slotStatusList)598 private boolean slotStatusChanged(ArrayList<IccSlotStatus> slotStatusList) { 599 if (sLastSlotStatus == null || sLastSlotStatus.size() != slotStatusList.size()) { 600 return true; 601 } 602 for (IccSlotStatus iccSlotStatus : slotStatusList) { 603 if (!sLastSlotStatus.contains(iccSlotStatus)) { 604 return true; 605 } 606 } 607 return false; 608 } 609 logPhoneIdToSlotIdMapping()610 private void logPhoneIdToSlotIdMapping() { 611 log("mPhoneIdToSlotId mapping:"); 612 for (int i = 0; i < mPhoneIdToSlotId.length; i++) { 613 log(" phoneId " + i + " slotId " + mPhoneIdToSlotId[i]); 614 } 615 } 616 onSimRefresh(AsyncResult ar, Integer index)617 private void onSimRefresh(AsyncResult ar, Integer index) { 618 if (ar.exception != null) { 619 Rlog.e(LOG_TAG, "onSimRefresh: Sim REFRESH with exception: " + ar.exception); 620 return; 621 } 622 623 if (!isValidPhoneIndex(index)) { 624 Rlog.e(LOG_TAG,"onSimRefresh: invalid index : " + index); 625 return; 626 } 627 628 IccRefreshResponse resp = (IccRefreshResponse) ar.result; 629 log("onSimRefresh: " + resp); 630 sLocalLog.log("onSimRefresh: " + resp); 631 632 if (resp == null) { 633 Rlog.e(LOG_TAG, "onSimRefresh: received without input"); 634 return; 635 } 636 637 UiccCard uiccCard = getUiccCardForPhone(index); 638 if (uiccCard == null) { 639 Rlog.e(LOG_TAG,"onSimRefresh: refresh on null card : " + index); 640 return; 641 } 642 643 boolean changed = false; 644 switch(resp.refreshResult) { 645 case IccRefreshResponse.REFRESH_RESULT_RESET: 646 case IccRefreshResponse.REFRESH_RESULT_INIT: 647 // Reset the required apps when we know about the refresh so that 648 // anyone interested does not get stale state. 649 changed = uiccCard.resetAppWithAid(resp.aid); 650 break; 651 default: 652 return; 653 } 654 655 if (changed && resp.refreshResult == IccRefreshResponse.REFRESH_RESULT_RESET) { 656 // If there is any change on RESET, reset carrier config as well. From carrier config 657 // perspective, this is treated the same as sim state unknown 658 CarrierConfigManager configManager = (CarrierConfigManager) 659 mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE); 660 configManager.updateConfigForPhoneId(index, IccCardConstants.INTENT_VALUE_ICC_UNKNOWN); 661 662 boolean requirePowerOffOnSimRefreshReset = mContext.getResources().getBoolean( 663 com.android.internal.R.bool.config_requireRadioPowerOffOnSimRefreshReset); 664 if (requirePowerOffOnSimRefreshReset) { 665 mCis[index].setRadioPower(false, null); 666 } 667 } 668 669 // The card status could have changed. Get the latest state. 670 mCis[index].getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE, index)); 671 } 672 isValidPhoneIndex(int index)673 private boolean isValidPhoneIndex(int index) { 674 return (index >= 0 && index < TelephonyManager.getDefault().getPhoneCount()); 675 } 676 isValidSlotIndex(int index)677 private boolean isValidSlotIndex(int index) { 678 return (index >= 0 && index < mUiccSlots.length); 679 } 680 log(String string)681 private void log(String string) { 682 Rlog.d(LOG_TAG, string); 683 } 684 addCardLog(String data)685 public void addCardLog(String data) { 686 sLocalLog.log(data); 687 } 688 dump(FileDescriptor fd, PrintWriter pw, String[] args)689 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 690 pw.println("UiccController: " + this); 691 pw.println(" mContext=" + mContext); 692 pw.println(" mInstance=" + mInstance); 693 pw.println(" mIccChangedRegistrants: size=" + mIccChangedRegistrants.size()); 694 for (int i = 0; i < mIccChangedRegistrants.size(); i++) { 695 pw.println(" mIccChangedRegistrants[" + i + "]=" 696 + ((Registrant)mIccChangedRegistrants.get(i)).getHandler()); 697 } 698 pw.println(); 699 pw.flush(); 700 pw.println(" mUiccSlots: size=" + mUiccSlots.length); 701 for (int i = 0; i < mUiccSlots.length; i++) { 702 if (mUiccSlots[i] == null) { 703 pw.println(" mUiccSlots[" + i + "]=null"); 704 } else { 705 pw.println(" mUiccSlots[" + i + "]=" + mUiccSlots[i]); 706 mUiccSlots[i].dump(fd, pw, args); 707 } 708 } 709 pw.println(" sLocalLog= "); 710 sLocalLog.dump(fd, pw, args); 711 } 712 } 713