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