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