UiccCard.java revision 6bc4098827f3070a44b5e51508b455d7c7be9c07
1/* 2 * Copyright (C) 2006, 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 17package com.android.internal.telephony.uicc; 18 19import static android.Manifest.permission.READ_PHONE_STATE; 20import android.app.ActivityManagerNative; 21import android.app.AlertDialog; 22import android.content.Context; 23import android.content.DialogInterface; 24import android.content.Intent; 25import android.content.SharedPreferences; 26import android.content.pm.PackageManager; 27import android.content.pm.Signature; 28import android.content.res.Resources; 29import android.os.AsyncResult; 30import android.os.Handler; 31import android.os.Message; 32import android.os.PowerManager; 33import android.os.Registrant; 34import android.os.RegistrantList; 35import android.preference.PreferenceManager; 36import android.telephony.Rlog; 37import android.telephony.TelephonyManager; 38import android.text.TextUtils; 39import android.view.WindowManager; 40 41import com.android.internal.telephony.CommandsInterface; 42import com.android.internal.telephony.PhoneBase; 43import com.android.internal.telephony.CommandsInterface.RadioState; 44import com.android.internal.telephony.IccCardConstants.State; 45import com.android.internal.telephony.gsm.GSMPhone; 46import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppType; 47import com.android.internal.telephony.uicc.IccCardStatus.CardState; 48import com.android.internal.telephony.uicc.IccCardStatus.PinState; 49import com.android.internal.telephony.cat.CatService; 50import com.android.internal.telephony.cdma.CDMALTEPhone; 51import com.android.internal.telephony.cdma.CDMAPhone; 52import com.android.internal.telephony.cdma.CdmaSubscriptionSourceManager; 53 54import android.os.SystemProperties; 55 56import com.android.internal.R; 57 58import java.io.FileDescriptor; 59import java.io.PrintWriter; 60import java.util.List; 61 62/** 63 * {@hide} 64 */ 65public class UiccCard { 66 protected static final String LOG_TAG = "UiccCard"; 67 protected static final boolean DBG = true; 68 69 private static final String OPERATOR_BRAND_OVERRIDE_PREFIX = "operator_branding_"; 70 71 private final Object mLock = new Object(); 72 private CardState mCardState; 73 private PinState mUniversalPinState; 74 private int mGsmUmtsSubscriptionAppIndex; 75 private int mCdmaSubscriptionAppIndex; 76 private int mImsSubscriptionAppIndex; 77 private UiccCardApplication[] mUiccApplications = 78 new UiccCardApplication[IccCardStatus.CARD_MAX_APPS]; 79 private Context mContext; 80 private CommandsInterface mCi; 81 private CatService mCatService; 82 private boolean mDestroyed = false; //set to true once this card is commanded to be disposed of. 83 private RadioState mLastRadioState = RadioState.RADIO_UNAVAILABLE; 84 private UiccCarrierPrivilegeRules mCarrierPrivilegeRules; 85 86 private RegistrantList mAbsentRegistrants = new RegistrantList(); 87 88 private static final int EVENT_CARD_REMOVED = 13; 89 private static final int EVENT_CARD_ADDED = 14; 90 private static final int EVENT_OPEN_LOGICAL_CHANNEL_DONE = 15; 91 private static final int EVENT_CLOSE_LOGICAL_CHANNEL_DONE = 16; 92 private static final int EVENT_TRANSMIT_APDU_LOGICAL_CHANNEL_DONE = 17; 93 private static final int EVENT_TRANSMIT_APDU_BASIC_CHANNEL_DONE = 18; 94 private static final int EVENT_SIM_IO_DONE = 19; 95 96 private int mSlotId; 97 98 public UiccCard(Context c, CommandsInterface ci, IccCardStatus ics) { 99 if (DBG) log("Creating"); 100 mCardState = ics.mCardState; 101 update(c, ci, ics); 102 } 103 104 public UiccCard(Context c, CommandsInterface ci, IccCardStatus ics, int slotId) { 105 mCardState = ics.mCardState; 106 mSlotId = slotId; 107 update(c, ci, ics); 108 } 109 110 protected UiccCard() { 111 } 112 113 public void dispose() { 114 synchronized (mLock) { 115 if (DBG) log("Disposing card"); 116 if (mCatService != null) mCatService.dispose(); 117 for (UiccCardApplication app : mUiccApplications) { 118 if (app != null) { 119 app.dispose(); 120 } 121 } 122 mCatService = null; 123 mUiccApplications = null; 124 mCarrierPrivilegeRules = null; 125 } 126 } 127 128 public void update(Context c, CommandsInterface ci, IccCardStatus ics) { 129 synchronized (mLock) { 130 if (mDestroyed) { 131 loge("Updated after destroyed! Fix me!"); 132 return; 133 } 134 CardState oldState = mCardState; 135 mCardState = ics.mCardState; 136 mUniversalPinState = ics.mUniversalPinState; 137 mGsmUmtsSubscriptionAppIndex = ics.mGsmUmtsSubscriptionAppIndex; 138 mCdmaSubscriptionAppIndex = ics.mCdmaSubscriptionAppIndex; 139 mImsSubscriptionAppIndex = ics.mImsSubscriptionAppIndex; 140 mContext = c; 141 mCi = ci; 142 //update applications 143 if (DBG) log(ics.mApplications.length + " applications"); 144 for ( int i = 0; i < mUiccApplications.length; i++) { 145 if (mUiccApplications[i] == null) { 146 //Create newly added Applications 147 if (i < ics.mApplications.length) { 148 mUiccApplications[i] = new UiccCardApplication(this, 149 ics.mApplications[i], mContext, mCi); 150 } 151 } else if (i >= ics.mApplications.length) { 152 //Delete removed applications 153 mUiccApplications[i].dispose(); 154 mUiccApplications[i] = null; 155 } else { 156 //Update the rest 157 mUiccApplications[i].update(ics.mApplications[i], mContext, mCi); 158 } 159 } 160 161 createAndUpdateCatService(); 162 163 // Reload the carrier privilege rules if necessary. 164 log("Before privilege rules: " + mCarrierPrivilegeRules + " : " + mCardState); 165 if (mCarrierPrivilegeRules == null && mCardState == CardState.CARDSTATE_PRESENT) { 166 mCarrierPrivilegeRules = new UiccCarrierPrivilegeRules(this); 167 } else if (mCarrierPrivilegeRules != null && mCardState != CardState.CARDSTATE_PRESENT) { 168 mCarrierPrivilegeRules = null; 169 } 170 171 sanitizeApplicationIndexes(); 172 173 RadioState radioState = mCi.getRadioState(); 174 if (DBG) log("update: radioState=" + radioState + " mLastRadioState=" 175 + mLastRadioState); 176 // No notifications while radio is off or we just powering up 177 if (radioState == RadioState.RADIO_ON && mLastRadioState == RadioState.RADIO_ON) { 178 if (oldState != CardState.CARDSTATE_ABSENT && 179 mCardState == CardState.CARDSTATE_ABSENT) { 180 if (DBG) log("update: notify card removed"); 181 mAbsentRegistrants.notifyRegistrants(); 182 mHandler.sendMessage(mHandler.obtainMessage(EVENT_CARD_REMOVED, null)); 183 } else if (oldState == CardState.CARDSTATE_ABSENT && 184 mCardState != CardState.CARDSTATE_ABSENT) { 185 if (DBG) log("update: notify card added"); 186 mHandler.sendMessage(mHandler.obtainMessage(EVENT_CARD_ADDED, null)); 187 } 188 } 189 mLastRadioState = radioState; 190 } 191 } 192 193 protected void createAndUpdateCatService() { 194 if (mUiccApplications.length > 0 && mUiccApplications[0] != null) { 195 // Initialize or Reinitialize CatService 196 if (mCatService == null) { 197 mCatService = CatService.getInstance(mCi, mContext, this, mSlotId); 198 } else { 199 ((CatService)mCatService).update(mCi, mContext, this); 200 } 201 } else { 202 if (mCatService != null) { 203 mCatService.dispose(); 204 } 205 mCatService = null; 206 } 207 } 208 209 public CatService getCatService() { 210 return mCatService; 211 } 212 213 @Override 214 protected void finalize() { 215 if (DBG) log("UiccCard finalized"); 216 } 217 218 /** 219 * This function makes sure that application indexes are valid 220 * and resets invalid indexes. (This should never happen, but in case 221 * RIL misbehaves we need to manage situation gracefully) 222 */ 223 private void sanitizeApplicationIndexes() { 224 mGsmUmtsSubscriptionAppIndex = 225 checkIndex(mGsmUmtsSubscriptionAppIndex, AppType.APPTYPE_SIM, AppType.APPTYPE_USIM); 226 mCdmaSubscriptionAppIndex = 227 checkIndex(mCdmaSubscriptionAppIndex, AppType.APPTYPE_RUIM, AppType.APPTYPE_CSIM); 228 mImsSubscriptionAppIndex = 229 checkIndex(mImsSubscriptionAppIndex, AppType.APPTYPE_ISIM, null); 230 } 231 232 private int checkIndex(int index, AppType expectedAppType, AppType altExpectedAppType) { 233 if (mUiccApplications == null || index >= mUiccApplications.length) { 234 loge("App index " + index + " is invalid since there are no applications"); 235 return -1; 236 } 237 238 if (index < 0) { 239 // This is normal. (i.e. no application of this type) 240 return -1; 241 } 242 243 if (mUiccApplications[index].getType() != expectedAppType && 244 mUiccApplications[index].getType() != altExpectedAppType) { 245 loge("App index " + index + " is invalid since it's not " + 246 expectedAppType + " and not " + altExpectedAppType); 247 return -1; 248 } 249 250 // Seems to be valid 251 return index; 252 } 253 254 /** 255 * Notifies handler of any transition into State.ABSENT 256 */ 257 public void registerForAbsent(Handler h, int what, Object obj) { 258 synchronized (mLock) { 259 Registrant r = new Registrant (h, what, obj); 260 261 mAbsentRegistrants.add(r); 262 263 if (mCardState == CardState.CARDSTATE_ABSENT) { 264 r.notifyRegistrant(); 265 } 266 } 267 } 268 269 public void unregisterForAbsent(Handler h) { 270 synchronized (mLock) { 271 mAbsentRegistrants.remove(h); 272 } 273 } 274 275 private void onIccSwap(boolean isAdded) { 276 277 boolean isHotSwapSupported = mContext.getResources().getBoolean( 278 com.android.internal.R.bool.config_hotswapCapable); 279 280 if (isHotSwapSupported) { 281 log("onIccSwap: isHotSwapSupported is true, don't prompt for rebooting"); 282 return; 283 } 284 log("onIccSwap: isHotSwapSupported is false, prompt for rebooting"); 285 286 synchronized (mLock) { 287 // TODO: Here we assume the device can't handle SIM hot-swap 288 // and has to reboot. We may want to add a property, 289 // e.g. REBOOT_ON_SIM_SWAP, to indicate if modem support 290 // hot-swap. 291 DialogInterface.OnClickListener listener = null; 292 293 294 // TODO: SimRecords is not reset while SIM ABSENT (only reset while 295 // Radio_off_or_not_available). Have to reset in both both 296 // added or removed situation. 297 listener = new DialogInterface.OnClickListener() { 298 @Override 299 public void onClick(DialogInterface dialog, int which) { 300 synchronized (mLock) { 301 if (which == DialogInterface.BUTTON_POSITIVE) { 302 if (DBG) log("Reboot due to SIM swap"); 303 PowerManager pm = (PowerManager) mContext 304 .getSystemService(Context.POWER_SERVICE); 305 pm.reboot("SIM is added."); 306 } 307 } 308 } 309 310 }; 311 312 Resources r = Resources.getSystem(); 313 314 String title = (isAdded) ? r.getString(R.string.sim_added_title) : 315 r.getString(R.string.sim_removed_title); 316 String message = (isAdded) ? r.getString(R.string.sim_added_message) : 317 r.getString(R.string.sim_removed_message); 318 String buttonTxt = r.getString(R.string.sim_restart_button); 319 320 AlertDialog dialog = new AlertDialog.Builder(mContext) 321 .setTitle(title) 322 .setMessage(message) 323 .setPositiveButton(buttonTxt, listener) 324 .create(); 325 dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); 326 dialog.show(); 327 } 328 } 329 330 protected Handler mHandler = new Handler() { 331 @Override 332 public void handleMessage(Message msg){ 333 if (mDestroyed) { 334 loge("Received message " + msg + "[" + msg.what 335 + "] while being destroyed. Ignoring."); 336 return; 337 } 338 339 switch (msg.what) { 340 case EVENT_CARD_REMOVED: 341 onIccSwap(false); 342 break; 343 case EVENT_CARD_ADDED: 344 onIccSwap(true); 345 break; 346 case EVENT_OPEN_LOGICAL_CHANNEL_DONE: 347 case EVENT_CLOSE_LOGICAL_CHANNEL_DONE: 348 case EVENT_TRANSMIT_APDU_LOGICAL_CHANNEL_DONE: 349 case EVENT_TRANSMIT_APDU_BASIC_CHANNEL_DONE: 350 case EVENT_SIM_IO_DONE: 351 AsyncResult ar = (AsyncResult)msg.obj; 352 if (ar.exception != null) { 353 if (DBG) 354 log("Error in SIM access with exception" + ar.exception); 355 } 356 AsyncResult.forMessage((Message)ar.userObj, ar.result, ar.exception); 357 ((Message)ar.userObj).sendToTarget(); 358 break; 359 default: 360 loge("Unknown Event " + msg.what); 361 } 362 } 363 }; 364 365 public boolean isApplicationOnIcc(IccCardApplicationStatus.AppType type) { 366 synchronized (mLock) { 367 for (int i = 0 ; i < mUiccApplications.length; i++) { 368 if (mUiccApplications[i] != null && mUiccApplications[i].getType() == type) { 369 return true; 370 } 371 } 372 return false; 373 } 374 } 375 376 public CardState getCardState() { 377 synchronized (mLock) { 378 return mCardState; 379 } 380 } 381 382 public PinState getUniversalPinState() { 383 synchronized (mLock) { 384 return mUniversalPinState; 385 } 386 } 387 388 public UiccCardApplication getApplication(int family) { 389 synchronized (mLock) { 390 int index = IccCardStatus.CARD_MAX_APPS; 391 switch (family) { 392 case UiccController.APP_FAM_3GPP: 393 index = mGsmUmtsSubscriptionAppIndex; 394 break; 395 case UiccController.APP_FAM_3GPP2: 396 index = mCdmaSubscriptionAppIndex; 397 break; 398 case UiccController.APP_FAM_IMS: 399 index = mImsSubscriptionAppIndex; 400 break; 401 } 402 if (index >= 0 && index < mUiccApplications.length) { 403 return mUiccApplications[index]; 404 } 405 return null; 406 } 407 } 408 409 public UiccCardApplication getApplicationIndex(int index) { 410 synchronized (mLock) { 411 if (index >= 0 && index < mUiccApplications.length) { 412 return mUiccApplications[index]; 413 } 414 return null; 415 } 416 } 417 418 /** 419 * Returns the SIM application of the specified type. 420 * 421 * @param type ICC application type (@see com.android.internal.telephony.PhoneConstants#APPTYPE_xxx) 422 * @return application corresponding to type or a null if no match found 423 */ 424 public UiccCardApplication getApplicationByType(int type) { 425 synchronized (mLock) { 426 for (int i = 0 ; i < mUiccApplications.length; i++) { 427 if (mUiccApplications[i] != null && 428 mUiccApplications[i].getType().ordinal() == type) { 429 return mUiccApplications[i]; 430 } 431 } 432 return null; 433 } 434 } 435 436 /** 437 * Exposes {@link CommandsInterface.iccOpenLogicalChannel} 438 */ 439 public void iccOpenLogicalChannel(String AID, Message response) { 440 mCi.iccOpenLogicalChannel(AID, 441 mHandler.obtainMessage(EVENT_OPEN_LOGICAL_CHANNEL_DONE, response)); 442 } 443 444 /** 445 * Exposes {@link CommandsInterface.iccCloseLogicalChannel} 446 */ 447 public void iccCloseLogicalChannel(int channel, Message response) { 448 mCi.iccCloseLogicalChannel(channel, 449 mHandler.obtainMessage(EVENT_CLOSE_LOGICAL_CHANNEL_DONE, response)); 450 } 451 452 /** 453 * Exposes {@link CommandsInterface.iccTransmitApduLogicalChannel} 454 */ 455 public void iccTransmitApduLogicalChannel(int channel, int cla, int command, 456 int p1, int p2, int p3, String data, Message response) { 457 mCi.iccTransmitApduLogicalChannel(channel, cla, command, p1, p2, p3, 458 data, mHandler.obtainMessage(EVENT_TRANSMIT_APDU_LOGICAL_CHANNEL_DONE, response)); 459 } 460 461 /** 462 * Exposes {@link CommandsInterface.iccTransmitApduBasicChannel} 463 */ 464 public void iccTransmitApduBasicChannel(int cla, int command, 465 int p1, int p2, int p3, String data, Message response) { 466 mCi.iccTransmitApduBasicChannel(cla, command, p1, p2, p3, 467 data, mHandler.obtainMessage(EVENT_TRANSMIT_APDU_BASIC_CHANNEL_DONE, response)); 468 } 469 470 /** 471 * Exposes {@link CommandsInterface.iccIO} 472 */ 473 public void iccExchangeSimIO(int fileID, int command, int p1, int p2, int p3, 474 String pathID, Message response) { 475 mCi.iccIO(command, fileID, pathID, p1, p2, p3, null, null, 476 mHandler.obtainMessage(EVENT_SIM_IO_DONE, response)); 477 } 478 479 /** 480 * Exposes {@link CommandsInterface.sendEnvelopeWithStatus} 481 */ 482 public void sendEnvelopeWithStatus(String contents, Message response) { 483 mCi.sendEnvelopeWithStatus(contents, response); 484 } 485 486 /* Returns number of applications on this card */ 487 public int getNumApplications() { 488 int count = 0; 489 for (UiccCardApplication a : mUiccApplications) { 490 if (a != null) { 491 count++; 492 } 493 } 494 return count; 495 } 496 497 public int getSlotId() { 498 return mSlotId; 499 } 500 501 /** 502 * Exposes {@link UiccCarrierPrivilegeRules.getCarrierPrivilegeStatus}. 503 */ 504 public int getCarrierPrivilegeStatus(Signature signature, String packageName) { 505 return mCarrierPrivilegeRules == null ? 506 TelephonyManager.CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED : 507 mCarrierPrivilegeRules.getCarrierPrivilegeStatus(signature, packageName); 508 } 509 510 /** 511 * Exposes {@link UiccCarrierPrivilegeRules.getCarrierPrivilegeStatus}. 512 */ 513 public int getCarrierPrivilegeStatus(PackageManager packageManager, String packageName) { 514 return mCarrierPrivilegeRules == null ? 515 TelephonyManager.CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED : 516 mCarrierPrivilegeRules.getCarrierPrivilegeStatus(packageManager, packageName); 517 } 518 519 /** 520 * Exposes {@link UiccCarrierPrivilegeRules.getCarrierPrivilegeStatusForCurrentTransaction}. 521 */ 522 public int getCarrierPrivilegeStatusForCurrentTransaction(PackageManager packageManager) { 523 return mCarrierPrivilegeRules == null ? 524 TelephonyManager.CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED : 525 mCarrierPrivilegeRules.getCarrierPrivilegeStatusForCurrentTransaction(packageManager); 526 } 527 528 /** 529 * Exposes {@link UiccCarrierPrivilegeRules.getCarrierPackageNamesForIntent}. 530 */ 531 public List<String> getCarrierPackageNamesForIntent( 532 PackageManager packageManager, Intent intent) { 533 return mCarrierPrivilegeRules == null ? null : 534 mCarrierPrivilegeRules.getCarrierPackageNamesForIntent( 535 packageManager, intent); 536 } 537 538 public boolean setOperatorBrandOverride(String iccId, String brand) { 539 log("setOperatorBrandOverride: " + iccId + " : " + brand); 540 log("current iccId: " + getIccId()); 541 542 if (iccId.isEmpty() || !TextUtils.isDigitsOnly(iccId)) { 543 return false; 544 } 545 546 SharedPreferences.Editor spEditor = 547 PreferenceManager.getDefaultSharedPreferences(mContext).edit(); 548 String key = OPERATOR_BRAND_OVERRIDE_PREFIX + iccId; 549 if (brand == null) { 550 spEditor.remove(key).commit(); 551 } else { 552 spEditor.putString(key, brand).commit(); 553 } 554 return true; 555 } 556 557 public String getOperatorBrandOverride() { 558 String iccId = getIccId(); 559 if (iccId == null) { 560 return null; 561 } 562 SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext); 563 return sp.getString(OPERATOR_BRAND_OVERRIDE_PREFIX + iccId, null); 564 } 565 566 private String getIccId() { 567 // ICCID should be same across all the apps. 568 for (UiccCardApplication app : mUiccApplications) { 569 if (app != null) { 570 IccRecords ir = app.getIccRecords(); 571 if (ir != null && ir.getIccId() != null) { 572 return ir.getIccId(); 573 } 574 } 575 } 576 return null; 577 } 578 579 private void log(String msg) { 580 Rlog.d(LOG_TAG, msg); 581 } 582 583 private void loge(String msg) { 584 Rlog.e(LOG_TAG, msg); 585 } 586 587 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 588 pw.println("UiccCard:"); 589 pw.println(" mCi=" + mCi); 590 pw.println(" mDestroyed=" + mDestroyed); 591 pw.println(" mLastRadioState=" + mLastRadioState); 592 pw.println(" mCatService=" + mCatService); 593 pw.println(" mAbsentRegistrants: size=" + mAbsentRegistrants.size()); 594 for (int i = 0; i < mAbsentRegistrants.size(); i++) { 595 pw.println(" mAbsentRegistrants[" + i + "]=" 596 + ((Registrant)mAbsentRegistrants.get(i)).getHandler()); 597 } 598 pw.println(" mCardState=" + mCardState); 599 pw.println(" mUniversalPinState=" + mUniversalPinState); 600 pw.println(" mGsmUmtsSubscriptionAppIndex=" + mGsmUmtsSubscriptionAppIndex); 601 pw.println(" mCdmaSubscriptionAppIndex=" + mCdmaSubscriptionAppIndex); 602 pw.println(" mImsSubscriptionAppIndex=" + mImsSubscriptionAppIndex); 603 pw.println(" mImsSubscriptionAppIndex=" + mImsSubscriptionAppIndex); 604 pw.println(" mUiccApplications: length=" + mUiccApplications.length); 605 for (int i = 0; i < mUiccApplications.length; i++) { 606 if (mUiccApplications[i] == null) { 607 pw.println(" mUiccApplications[" + i + "]=" + null); 608 } else { 609 pw.println(" mUiccApplications[" + i + "]=" 610 + mUiccApplications[i].getType() + " " + mUiccApplications[i]); 611 } 612 } 613 pw.println(); 614 // Print details of all applications 615 for (UiccCardApplication app : mUiccApplications) { 616 if (app != null) { 617 app.dump(fd, pw, args); 618 pw.println(); 619 } 620 } 621 // Print details of all IccRecords 622 for (UiccCardApplication app : mUiccApplications) { 623 if (app != null) { 624 IccRecords ir = app.getIccRecords(); 625 if (ir != null) { 626 ir.dump(fd, pw, args); 627 pw.println(); 628 } 629 } 630 } 631 pw.flush(); 632 } 633} 634