1.UiccController 是处理SIM卡的核心类,其他关键类都是通过他产生
* Following is class diagram for uicc classes:
*
* UiccController
* #
* |
* UiccCard
* # #
* | ------------------
* UiccCardApplication CatService
* # #
* | |
* IccRecords IccFileHandler
* ^ ^ ^ ^ ^ ^ ^ ^
* SIMRecords---- | | | | | | ---SIMFileHandler
* RuimRecords----- | | | | ----RuimFileHandler
* IsimUiccRecords--- | | -----UsimFileHandler
* | ------CsimFileHandler
* ----IsimFileHandler
*
* Legend: # stands for Composition
* ^ stands for Generalization
*
* See also {@link com.android.internal.telephony.IccCard}
* and {@link com.android.internal.telephony.uicc.IccCardProxy}
2 分析UiccController是如何初始化的
2.1 Phone进程初始化PhoneApp.java
public void onCreate() {
if (UserHandle.myUserId() == 0) {
// We are running as the primary user, so should bring up the
// global phone state.
mPhoneGlobals = new PhoneGlobals(this);
mPhoneGlobals.onCreate();
mTelephonyGlobals = new TelephonyGlobals(this);
mTelephonyGlobals.onCreate();
}
}
2.2 在PhoneGlobals.java的onCreate()中创建Phone
if (mCM == null) {
// Initialize the telephony framework
PhoneFactory.makeDefaultPhones(this);
2.3 PhoneFactory类makeDefaultPhone方法中初始化UiccController,UiccController是UICC的控制接口,与RIL建立监听关系,当SIM卡状态变化时,RIL通知UiccController.
sCommandsInterfaces = new RIL[numPhones];
sCommandsInterfaces[i] = new RIL(context, networkModes[i],cdmaSubscription, i);
sUiccController = UiccController.make(context, sCommandsInterfaces);
if (phoneType == PhoneConstants.PHONE_TYPE_GSM) {
phone = new GsmCdmaPhone(context,
sCommandsInterfaces[i], sPhoneNotifier, i,
PhoneConstants.PHONE_TYPE_GSM,
TelephonyComponentFactory.getInstance());
} else if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
phone = new GsmCdmaPhone(context,
sCommandsInterfaces[i], sPhoneNotifier, i,
PhoneConstants.PHONE_TYPE_CDMA_LTE,
TelephonyComponentFactory.getInstance());
}
2.4 看看UiccController的make方法中都对RIL注册了哪些监听
public static UiccController make(Context c, CommandsInterface[] ci) {
synchronized (mLock) {
if (mInstance != null) {
throw new RuntimeException("MSimUiccController.make() should only be called once");
}
mInstance = new UiccController(c, ci);
return (UiccController)mInstance;
}
}
private UiccController(Context c, CommandsInterface []ci) {
if (DBG) log("Creating UiccController");
mContext = c;
mCis = ci;
for (int i = 0; i < mCis.length; i++) {
Integer index = new Integer(i);
mCis[i].registerForIccStatusChanged(this, EVENT_ICC_STATUS_CHANGED, index);
// TODO remove this once modem correctly notifies the unsols
// If the device has been decrypted or FBE is supported, read SIM when radio state is
// available.
// Else wait for radio to be on. This is needed for the scenario when SIM is locked --
// to avoid overlap of CryptKeeper and SIM unlock screen.
if (DECRYPT_STATE.equals(SystemProperties.get("vold.decrypt")) ||
StorageManager.isFileEncryptedNativeOrEmulated()) {
mCis[i].registerForAvailable(this, EVENT_ICC_STATUS_CHANGED, index);
} else {
mCis[i].registerForOn(this, EVENT_ICC_STATUS_CHANGED, index);
}
mCis[i].registerForNotAvailable(this, EVENT_RADIO_UNAVAILABLE, index);
mCis[i].registerForIccRefresh(this, EVENT_SIM_REFRESH, index);
}
}
监听了三个事件:EVENT_ICC_STATUS_CHANGED/EVENT_RADIO_UNAVAILABLE/EVENT_SIM_REFRESH
index对应phoneId
registerForIccStatusChanged方法是CommandsInterface接口中定义
抽象类BaseCommands中实现
@Override
public void registerForIccStatusChanged(Handler h, int what, Object obj) {
Registrant r = new Registrant (h, what, obj);
mIccStatusChangedRegistrants.add(r);
}
mIccStatusChangedRegistrants是在RIL中发出通知
private void processUnsolicited (Parcel p, int type) {
....
case RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED:
if (RILJ_LOGD) unsljLog(response);
if (mIccStatusChangedRegistrants != null) {
mIccStatusChangedRegistrants.notifyRegistrants();
}
break;
2.5 UiccController handleMessage方法中处理事件EVENT_ICC_STATUS_CHANGED,请求RIL getIccCardStatus()方法发送RIL_REQUEST_GET_SIM_STATUS消息给modem查询SIM卡状态,通过onGetIccCardStatusDone处理
@Override
public void handleMessage (Message msg) {
synchronized (mLock) {
Integer index = getCiIndex(msg);
if (index < 0 || index >= mCis.length) {
Rlog.e(LOG_TAG, "Invalid index : " + index + " received with event " + msg.what);
return;
}
AsyncResult ar = (AsyncResult)msg.obj;
switch (msg.what) {
case EVENT_ICC_STATUS_CHANGED:
if (DBG) log("Received EVENT_ICC_STATUS_CHANGED, calling getIccCardStatus");
mCis[index].getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE, index));
break;
case EVENT_GET_ICC_STATUS_DONE:
if (DBG) log("Received EVENT_GET_ICC_STATUS_DONE");
onGetIccCardStatusDone(ar, index);
break;
case EVENT_RADIO_UNAVAILABLE:
if (DBG) log("EVENT_RADIO_UNAVAILABLE, dispose card");
if (mUiccCards[index] != null) {
mUiccCards[index].dispose();
}
mUiccCards[index] = null;
mIccChangedRegistrants.notifyRegistrants(new AsyncResult(null, index, null));
break;
case EVENT_SIM_REFRESH:
if (DBG) log("Received EVENT_SIM_REFRESH");
onSimRefresh(ar, index);
break;
default:
Rlog.e(LOG_TAG, " Unknown Event " + msg.what);
}
}
}
RIL.java
@Override
public void
getIccCardStatus(Message result) {
//Note: This RIL request has not been renamed to ICC,
// but this request is also valid for SIM and RUIM
RILRequest rr = RILRequest.obtain(RIL_REQUEST_GET_SIM_STATUS, result);
if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
send(rr);
}
2.6 在onGetIccCardStatusDone方法中,依据IccCardStatus创建UiccCard,每个UiccCard对应一张SIM卡,方法的最后通知注册UiccController监听,UiccCard的构造方法也是调用update方法
private synchronized void onGetIccCardStatusDone(AsyncResult ar, Integer index) {
if (ar.exception != null) {
Rlog.e(LOG_TAG,"Error getting ICC status. "
+ "RIL_REQUEST_GET_ICC_STATUS should "
+ "never return an error", ar.exception);
return;
}
if (!isValidCardIndex(index)) {
Rlog.e(LOG_TAG,"onGetIccCardStatusDone: invalid index : " + index);
return;
}
IccCardStatus status = (IccCardStatus)ar.result;
if (mUiccCards[index] == null) {
//Create new card
mUiccCards[index] = new UiccCard(mContext, mCis[index], status, index);
} else {
//Update already existing card
mUiccCards[index].update(mContext, mCis[index] , status);
}
if (DBG) log("Notifying IccChangedRegistrants");
mIccChangedRegistrants.notifyRegistrants(new AsyncResult(null, index, null));
}
UiccController总结:
3.UiccCard
3.1 UiccCard构造方法
public UiccCard(Context c, CommandsInterface ci, IccCardStatus ics, int phoneId) {
mCardState = ics.mCardState;
mPhoneId = phoneId;
update(c, ci, ics);
}
public void update(Context c, CommandsInterface ci, IccCardStatus ics) {
synchronized (mLock) {
CardState oldState = mCardState;
mCardState = ics.mCardState;
mUniversalPinState = ics.mUniversalPinState;
mGsmUmtsSubscriptionAppIndex = ics.mGsmUmtsSubscriptionAppIndex;
mCdmaSubscriptionAppIndex = ics.mCdmaSubscriptionAppIndex;
mImsSubscriptionAppIndex = ics.mImsSubscriptionAppIndex;
mContext = c;
mCi = ci;
//update applications
if (DBG) log(ics.mApplications.length + " applications");
for ( int i = 0; i < mUiccApplications.length; i++) {
if (mUiccApplications[i] == null) {
//Create newly added Applications
if (i < ics.mApplications.length) {
mUiccApplications[i] = new UiccCardApplication(this,
ics.mApplications[i], mContext, mCi);
}
} else if (i >= ics.mApplications.length) {
//Delete removed applications
mUiccApplications[i].dispose();
mUiccApplications[i] = null;
} else {
//Update the rest
mUiccApplications[i].update(ics.mApplications[i], mContext, mCi);
}
}
createAndUpdateCatService();
// Reload the carrier privilege rules if necessary.
log("Before privilege rules: " + mCarrierPrivilegeRules + " : " + mCardState);
if (mCarrierPrivilegeRules == null && mCardState == CardState.CARDSTATE_PRESENT) {
mCarrierPrivilegeRules = new UiccCarrierPrivilegeRules(this,
mHandler.obtainMessage(EVENT_CARRIER_PRIVILIGES_LOADED));
} else if (mCarrierPrivilegeRules != null && mCardState != CardState.CARDSTATE_PRESENT) {
mCarrierPrivilegeRules = null;
}
sanitizeApplicationIndexes();
RadioState radioState = mCi.getRadioState();
if (DBG) log("update: radioState=" + radioState + " mLastRadioState="
+ mLastRadioState);
// No notifications while radio is off or we just powering up
if (radioState == RadioState.RADIO_ON && mLastRadioState == RadioState.RADIO_ON) {
//根据mCardState 和oldState 判断是ADD还是REMOVE card
if (oldState != CardState.CARDSTATE_ABSENT &&
mCardState == CardState.CARDSTATE_ABSENT) {
if (DBG) log("update: notify card removed");
mAbsentRegistrants.notifyRegistrants();
mHandler.sendMessage(mHandler.obtainMessage(EVENT_CARD_REMOVED, null));
} else if (oldState == CardState.CARDSTATE_ABSENT &&
mCardState != CardState.CARDSTATE_ABSENT) {
if (DBG) log("update: notify card added");
mHandler.sendMessage(mHandler.obtainMessage(EVENT_CARD_ADDED, null));
}
}
mLastRadioState = radioState;
}
}
在构造方法中调用update方法,在update中创建或者更新UiccCardApplication,
根据mCardState 和oldState 判断是ADD还是REMOVE card,当SIM卡拔出时,通知IccCardProxy, 以及promptForRestart。
createAndUpdateCatService();建CatService,用于读取STK的信息
protected void createAndUpdateCatService() {
if (mUiccApplications.length > 0 && mUiccApplications[0] != null) {
// Initialize or Reinitialize CatService
if (mCatService == null) {
mCatService = CatService.getInstance(mCi, mContext, this, mPhoneId);
} else {
((CatService)mCatService).update(mCi, mContext, this);
}
} else {
if (mCatService != null) {
mCatService.dispose();
}
mCatService = null;
}
}
UiccCard主要就是创建UiccCardApplication和CatService,以及通知SIM Card ADD和REMOVE事件
4.UiccCardApplication
主要方法:
public void registerForReady(Handler h, int what, Object obj) {}
public void registerForLocked(Handler h, int what, Object obj) {}
public void registerForNetworkLocked(Handler h, int what, Object obj) {}
public AppState getState() {}
public AppType getType() {}
public PersoSubState getPersoSubState() {}
public String getAid() {}
public PinState getPin1State() {}
public IccFileHandler getIccFileHandler() {}
public IccRecords getIccRecords() {}
public void supplyPin (String pin, Message onComplete) {}
public void supplyPuk (String puk, String newPin, Message onComplete) {}
public void supplyPin2 (String pin2, Message onComplete) {}
public void supplyPuk2 (String puk2, String newPin2, Message onComplete) {}
public void supplyNetworkDepersonalization (String pin, Message onComplete) {}
public boolean getIccLockEnabled() {}
public boolean getIccFdnEnabled() {}
public void setIccLockEnabled (boolean enabled, String password, Message onComplete) {}
public void setIccFdnEnabled (boolean enabled, String password, Message onComplete) {}
public void changeIccLockPassword(String oldPassword, String newPassword, Message onComplete) {}
public void changeIccFdnPassword(String oldPassword, String newPassword, Message onComplete) {}
UiccCardApplication的主要功能:创建对象IccFileHandler、IccRecords,并提供获取对象的接口;FDN/PIN/PUK设置和查询接口(通过RIL实现);查询UiccCardApplication状态信息(mAppState、mAppType)
public UiccCardApplication(UiccCard uiccCard,
IccCardApplicationStatus as,
Context c,
CommandsInterface ci) {
if (DBG) log("Creating UiccApp: " + as);
mUiccCard = uiccCard;
mAppState = as.app_state;
mAppType = as.app_type;
mAuthContext = getAuthContext(mAppType);
mPersoSubState = as.perso_substate;
mAid = as.aid;
mAppLabel = as.app_label;
mPin1Replaced = (as.pin1_replaced != 0);
mPin1State = as.pin1;
mPin2State = as.pin2;
mContext = c;
mCi = ci;
mIccFh = createIccFileHandler(as.app_type);
mIccRecords = createIccRecords(as.app_type, mContext, mCi);
if (mAppState == AppState.APPSTATE_READY) {
queryFdn();
queryPin1State();
}
mCi.registerForNotAvailable(mHandler, EVENT_RADIO_UNAVAILABLE, null);
}
创建IccFileHandler:SIMFileHandler/RuimFileHandler/UsimFileHandler/CsimFileHandler/IsimFileHandler
创建IccRecords:SIMRecords/RuimRecords/IsimUiccRecords
查询Fdn号码/查询Pin码状态
4.1 UiccCardApplication的更新
SIM卡或者Radio状态改变时,ril通过UiccController更新UiccCard,由UiccCard更新UiccCardApplication调用update()
public void update (IccCardApplicationStatus as, Context c, CommandsInterface ci) {
synchronized (mLock) {
if (mDestroyed) {
loge("Application updated after destroyed! Fix me!");
return;
}
if (DBG) log(mAppType + " update. New " + as);
//变量更新
mContext = c;
mCi = ci;
AppType oldAppType = mAppType;
AppState oldAppState = mAppState;
PersoSubState oldPersoSubState = mPersoSubState;
mAppType = as.app_type;
mAuthContext = getAuthContext(mAppType);
mAppState = as.app_state;
mPersoSubState = as.perso_substate;
mAid = as.aid;
mAppLabel = as.app_label;
mPin1Replaced = (as.pin1_replaced != 0);
mPin1State = as.pin1;
mPin2State = as.pin2;
//更新IccRecords和IccFileHandler
if (mAppType != oldAppType) {
if (mIccFh != null) { mIccFh.dispose();}
if (mIccRecords != null) { mIccRecords.dispose();}
mIccFh = createIccFileHandler(as.app_type);
mIccRecords = createIccRecords(as.app_type, c, ci);
}
if (mPersoSubState != oldPersoSubState &&
mPersoSubState == PersoSubState.PERSOSUBSTATE_SIM_NETWORK) {
notifyNetworkLockedRegistrantsIfNeeded(null);
}
if (mAppState != oldAppState) {
if (DBG) log(oldAppType + " changed state: " + oldAppState + " -> " + mAppState);
// If the app state turns to APPSTATE_READY, then query FDN status,
//as it might have failed in earlier attempt.
if (mAppState == AppState.APPSTATE_READY) {
queryFdn();
queryPin1State();
}
notifyPinLockedRegistrantsIfNeeded(null);
notifyReadyRegistrantsIfNeeded(null);
}
}
}
4.2
// 根据modem返回的不同卡类型,创建不同 IccRecords 对象
private IccRecords createIccRecords(AppType type, Context c, CommandsInterface ci) {
if (type == AppType.APPTYPE_USIM || type == AppType.APPTYPE_SIM) {
return new SIMRecords(this, c, ci);
} else if (type == AppType.APPTYPE_RUIM || type == AppType.APPTYPE_CSIM){
return new RuimRecords(this, c, ci);
} else if (type == AppType.APPTYPE_ISIM) {
return new IsimUiccRecords(this, c, ci);
} else {
// Unknown app type (maybe detection is still in progress)
return null;
}
}
// 根据modem返回的不同卡类型,创建不同 IccFileHandler 对象
private IccFileHandler createIccFileHandler(AppType type) {
switch (type) {
case APPTYPE_SIM:
return new SIMFileHandler(this, mAid, mCi);
case APPTYPE_RUIM:
return new RuimFileHandler(this, mAid, mCi);
case APPTYPE_USIM:
return new UsimFileHandler(this, mAid, mCi);
case APPTYPE_CSIM:
return new CsimFileHandler(this, mAid, mCi);
case APPTYPE_ISIM:
return new IsimFileHandler(this, mAid, mCi);
default:
return null;
}
}
5.CatService(接3)
6.IccFileHandler(接4)
从这些方法可以看出,IccFileHandler的主要作用就是提供SIM卡文件系统的读写操作,当调用这些方法时,需要传递要读写的文件系统地址,以及读写完毕后的回调函数,IccFileHandler会在读取完数据之后通知到调用者,并把返回值传递过去。
6.1 以UsimFileHandler为例
protected String getEFPath(int efid) {
// TODO(): DF_GSM can be 7F20 or 7F21 to handle backward compatibility.
// Implement this after discussion with OEMs.
switch(efid) {
case EF_SMS:
return MF_SIM + DF_TELECOM;
case EF_EXT6:
case EF_MWIS:
case EF_MBI:
case EF_SPN:
case EF_AD:
case EF_MBDN:
case EF_PNN:
case EF_SPDI:
case EF_SST:
case EF_CFIS:
case EF_GID1:
case EF_GID2:
case EF_MAILBOX_CPHS:
case EF_VOICE_MAIL_INDICATOR_CPHS:
case EF_CFF_CPHS:
case EF_SPN_CPHS:
case EF_SPN_SHORT_CPHS:
case EF_INFO_CPHS:
case EF_CSP_CPHS:
return MF_SIM + DF_GSM;
}
String path = getCommonIccEFPath(efid);
if (path == null) {
Rlog.e(LOG_TAG, "Error: EF Path being returned in null");
}
return path;
}
不同SIM卡主要区别就是文件结构不同,因此各自实现getEFPath方法
6.2
6.3
7.IccRecords(接4)
IccRecords 记录SIM卡的EF文件信息,具体的读取SIM卡EF文件信息的过程是由 IccFileHandler 来实现的,以 SIMRecords 为例。
7.1
主要方法:
父类的方法
// * Constructor
public IccRecords(UiccCardApplication app, Context c, CommandsInterface ci) {
mContext = c;
mCi = ci;
mFh = app.getIccFileHandler();
mParentApp = app;
mTelephonyManager = (TelephonyManager) mContext.getSystemService(
Context.TELEPHONY_SERVICE);
}
// ***** Constructor
public SIMRecords(UiccCardApplication app, Context c, CommandsInterface ci) {
super(app, c, ci);
mAdnCache = new AdnRecordCache(mFh);
mVmConfig = new VoiceMailConstants();
mSpnOverride = new SpnOverride();
mRecordsRequested = false; // No load request is made till SIM ready
// recordsToLoad is set to 0 because no requests are made yet
mRecordsToLoad = 0;
mCi.setOnSmsOnSim(this, EVENT_SMS_ON_SIM, null);
mCi.registerForIccRefresh(this, EVENT_SIM_REFRESH, null);
// Start off by setting empty state
resetRecords();
mParentApp.registerForReady(this, EVENT_APP_READY, null);
mParentApp.registerForLocked(this, EVENT_APP_LOCKED, null);
if (DBG) log("SIMRecords X ctor this=" + this);
IntentFilter intentfilter = new IntentFilter();
intentfilter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
c.registerReceiver(mReceiver, intentfilter);
}
以上的创建过程完成了两个重要任务:
创建Adn和VoiceMail缓存,这里的Adn缓存用于SIM卡联系人的增、删、改、查等功能;
监听UiccCardApplication的Ready状态;
@Override
public void onReady() {
fetchSimRecords();
}
7.2 SIMRecords更新
protected void fetchSimRecords() {
mRecordsRequested = true;
if (DBG) log("fetchSimRecords " + mRecordsToLoad);
mCi.getIMSIForApp(mParentApp.getAid(), obtainMessage(EVENT_GET_IMSI_DONE));
mRecordsToLoad++;
mFh.loadEFTransparent(EF_ICCID, obtainMessage(EVENT_GET_ICCID_DONE));
mRecordsToLoad++;
// FIXME should examine EF[MSISDN]'s capability configuration
// to determine which is the voice/data/fax line
new AdnRecordLoader(mFh).loadFromEF(EF_MSISDN, getExtFromEf(EF_MSISDN), 1,
obtainMessage(EVENT_GET_MSISDN_DONE));
mRecordsToLoad++;
// Record number is subscriber profile
mFh.loadEFLinearFixed(EF_MBI, 1, obtainMessage(EVENT_GET_MBI_DONE));
mRecordsToLoad++;
mFh.loadEFTransparent(EF_AD, obtainMessage(EVENT_GET_AD_DONE));
mRecordsToLoad++;
// Record number is subscriber profile
mFh.loadEFLinearFixed(EF_MWIS, 1, obtainMessage(EVENT_GET_MWIS_DONE));
mRecordsToLoad++;
// Also load CPHS-style voice mail indicator, which stores
// the same info as EF[MWIS]. If both exist, both are updated
// but the EF[MWIS] data is preferred
// Please note this must be loaded after EF[MWIS]
mFh.loadEFTransparent(
EF_VOICE_MAIL_INDICATOR_CPHS,
obtainMessage(EVENT_GET_VOICE_MAIL_INDICATOR_CPHS_DONE));
mRecordsToLoad++;
// Same goes for Call Forward Status indicator: fetch both
// EF[CFIS] and CPHS-EF, with EF[CFIS] preferred.
loadCallForwardingRecords();
getSpnFsm(true, null);
mFh.loadEFTransparent(EF_SPDI, obtainMessage(EVENT_GET_SPDI_DONE));
mRecordsToLoad++;
mFh.loadEFLinearFixed(EF_PNN, 1, obtainMessage(EVENT_GET_PNN_DONE));
mRecordsToLoad++;
mFh.loadEFTransparent(EF_SST, obtainMessage(EVENT_GET_SST_DONE));
mRecordsToLoad++;
mFh.loadEFTransparent(EF_INFO_CPHS, obtainMessage(EVENT_GET_INFO_CPHS_DONE));
mRecordsToLoad++;
mFh.loadEFTransparent(EF_CSP_CPHS,obtainMessage(EVENT_GET_CSP_CPHS_DONE));
mRecordsToLoad++;
mFh.loadEFTransparent(EF_GID1, obtainMessage(EVENT_GET_GID1_DONE));
mRecordsToLoad++;
mFh.loadEFTransparent(EF_GID2, obtainMessage(EVENT_GET_GID2_DONE));
mRecordsToLoad++;
mFh.loadEFTransparent(EF_PLMN_W_ACT, obtainMessage(EVENT_GET_PLMN_W_ACT_DONE));
mFh.loadEFTransparent(EF_OPLMN_W_ACT, obtainMessage(EVENT_GET_OPLMN_W_ACT_DONE));
mFh.loadEFTransparent(EF_HPLMN_W_ACT, obtainMessage(EVENT_GET_HPLMN_W_ACT_DONE));
mFh.loadEFTransparent(EF_EHPLMN, obtainMessage(EVENT_GET_EHPLMN_DONE));
mFh.loadEFTransparent(EF_FPLMN, obtainMessage(EVENT_GET_FPLMN_DONE));
mRecordsToLoad++;
loadEfLiAndEfPl();
// XXX should seek instead of examining them all
if (false) { // XXX
mFh.loadEFLinearFixedAll(EF_SMS, obtainMessage(EVENT_GET_ALL_SMS_DONE));
mRecordsToLoad++;
}
if (CRASH_RIL) {
String sms = "0107912160130310f20404d0110041007030208054832b0120"
+ "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+ "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+ "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+ "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+ "ffffffffffffffffffffffffffffff";
byte[] ba = IccUtils.hexStringToBytes(sms);
mFh.updateEFLinearFixed(EF_SMS, 1, ba, null,
obtainMessage(EVENT_MARK_SMS_READ_DONE, 1));
}
if (DBG) log("fetchSimRecords " + mRecordsToLoad + " requested: " + mRecordsRequested);
}
从log中可以看到更新流程:
1572:09-12 15:33:37.899 2237 2237 D UiccCardApplication: Notifying 1 registrant: READY
1588:09-12 15:33:37.956 2237 2237 D SIMRecords: [SIMRecords] fetchSimRecords 0
查询IMSI:
1589:09-12 15:33:37.957 2237 2237 D RILJ : [3749]> getIMSI: GET_IMSI aid: a0000000871002ff86ffff89ffffffff [SUB0]
查询ICCID:
1590:09-12 15:33:37.962 2237 2237 D RILJ : [3750]> iccIO: SIM_IO 0xc0 0x2fe2 path: 3F00,0,0,15 aid: a0000000871002ff86ffff89ffffffff [SUB0]
查询电话号码:
1593:09-12 15:33:37.969 2237 2237 D RILJ : [3751]> iccIO: SIM_IO 0xc0 0x6f40 path: 3F007FFF,0,0,15 aid: a0000000871002ff86ffff89ffffffff [SUB0]
查询EF_MBI 语音信箱号码:
1594:09-12 15:33:37.971 2237 2237 D RILJ : [3752]> iccIO: SIM_IO 0xc0 0x6fc9 path: 3F007FFF,0,0,15 aid: a0000000871002ff86ffff89ffffffff [SUB0]
返回IMSI:
1597:09-12 15:33:37.971 2237 2299 D RILJ : [3749]< GET_IMSI [SUB0]
查询EF_AD:
1598:09-12 15:33:37.975 2237 2237 D RILJ : [3753]> iccIO: SIM_IO 0xc0 0x6fad path: 3F007FFF,0,0,15 aid: a0000000871002ff86ffff89ffffffff [SUB0]
查询EF_MWIS:
1602:09-12 15:33:37.978 2237 2237 D RILJ : [3754]> iccIO: SIM_IO 0xc0 0x6fca path: 3F007FFF,0,0,15 aid: a0000000871002ff86ffff89ffffffff [SUB0]
查询EF_VOICE_MAIL_INDICATOR_CPHS:
1603:09-12 15:33:37.979 2237 2237 D RILJ : [3755]> iccIO: SIM_IO 0xc0 0x6f11 path: 3F007FFF,0,0,15 aid: a0000000871002ff86ffff89ffffffff [SUB0]
查询call forwarding EF_CFIS:
1604:09-12 15:33:37.984 2237 2237 D RILJ : [3756]> iccIO: SIM_IO 0xc0 0x6fcb path: 3F007FFF,0,0,15 aid: a0000000871002ff86ffff89ffffffff [SUB0]
查询EF_CFF_CPHS:
1605:09-12 15:33:37.989 2237 2237 D RILJ : [3757]> iccIO: SIM_IO 0xc0 0x6f13 path: 3F007FFF,0,0,15 aid: a0000000871002ff86ffff89ffffffff [SUB0]
查询EF_SPN:
1606:09-12 15:33:37.991 2237 2237 D RILJ : [3758]> iccIO: SIM_IO 0xc0 0x6f46 path: 3F007FFF,0,0,15 aid: a0000000871002ff86ffff89ffffffff [SUB0]
查询EF_SPDI:
1608:09-12 15:33:37.995 2237 2237 D RILJ : [3759]> iccIO: SIM_IO 0xc0 0x6fcd path: 3F007FFF,0,0,15 aid: a0000000871002ff86ffff89ffffffff [SUB0]
查询EF_PNN:
1609:09-12 15:33:37.997 2237 2237 D RILJ : [3760]> iccIO: SIM_IO 0xc0 0x6fc5 path: 3F007FFF,0,0,15 aid: a0000000871002ff86ffff89ffffffff [SUB0]
其他查询:
1610:09-12 15:33:37.999 2237 2237 D RILJ : [3761]> iccIO: SIM_IO 0xc0 0x6f38 path: 3F007FFF,0,0,15 aid: a0000000871002ff86ffff89ffffffff [SUB0]
1611:09-12 15:33:38.001 2237 2237 D RILJ : [3762]> iccIO: SIM_IO 0xc0 0x6f16 path: 3F007FFF,0,0,15 aid: a0000000871002ff86ffff89ffffffff [SUB0]
1612:09-12 15:33:38.002 2237 2299 D RILJ : [3751]< SIM_IO IccIoResult sw1:0x90 sw2:0x0 [SUB0]
1613:09-12 15:33:38.003 2237 2237 D RILJ : [3763]> iccIO: SIM_IO 0xc0 0x6f15 path: 3F007FFF,0,0,15 aid: a0000000871002ff86ffff89ffffffff [SUB0]
1614:09-12 15:33:38.005 2237 2237 D RILJ : [3764]> iccIO: SIM_IO 0xc0 0x6f3e path: 3F007FFF,0,0,15 aid: a0000000871002ff86ffff89ffffffff [SUB0]
1615:09-12 15:33:38.010 2237 2237 D RILJ : [3765]> iccIO: SIM_IO 0xc0 0x6f3f path: 3F007FFF,0,0,15 aid: a0000000871002ff86ffff89ffffffff [SUB0]
1616:09-12 15:33:38.024 2237 2299 D RILJ : [3753]< SIM_IO IccIoResult sw1:0x90 sw2:0x0 [SUB0]
1633:09-12 15:33:38.206 2237 2237 D RILJ : [3766]> iccIO: SIM_IO 0xc0 0x6f60 path: 3F007FFF,0,0,15 aid: a0000000871002ff86ffff89ffffffff [SUB0]
1634:09-12 15:33:38.213 2237 2237 D RILJ : [3767]> iccIO: SIM_IO 0xc0 0x6f61 path: 3F007FFF,0,0,15 aid: a0000000871002ff86ffff89ffffffff [SUB0]
1636:09-12 15:33:38.231 2237 2237 D RILJ : [3768]> iccIO: SIM_IO 0xc0 0x6f62 path: 3F007FFF,0,0,15 aid: a0000000871002ff86ffff89ffffffff [SUB0]
1638:09-12 15:33:38.235 2237 2237 D RILJ : [3769]> iccIO: SIM_IO 0xc0 0x6fd9 path: 3F007FFF,0,0,15 aid: a0000000871002ff86ffff89ffffffff [SUB0]
1639:09-12 15:33:38.237 2237 2237 D RILJ : [3770]> iccIO: SIM_IO 0xc0 0x6f7b path: 3F007FFF,0,0,15 aid: a0000000871002ff86ffff89ffffffff [SUB0]
1641:09-12 15:33:38.241 2237 2299 D RILJ : [3764]< SIM_IO IccIoResult sw1:0x90 sw2:0x0 [SUB0]
1642:09-12 15:33:38.241 2237 2237 D RILJ : [3771]> iccIO: SIM_IO 0xc0 0x6f05 path: 3F007FFF,0,0,15 aid: a0000000871002ff86ffff89ffffffff [SUB0]
1644:09-12 15:33:38.247 2237 2237 D RILJ : [3772]> iccIO: SIM_IO 0xc0 0x2f05 path: 3F00,0,0,15 aid: a0000000871002ff86ffff89ffffffff [SUB0]
1646:09-12 15:33:38.248 2237 2237 D RILJ : [3773]> iccIO: SIM_IO 0xc0 0x6f3c path: 3F007FFF,0,0,15 aid: a0000000871002ff86ffff89ffffffff [SUB0]
1648:09-12 15:33:38.250 2237 2237 D SIMRecords: [SIMRecords] fetchSimRecords 20 requested: true
在ICCCardProxy中注册IccRecords事件监听
private void registerUiccCardEvents() {
if (mUiccCard != null) {
mUiccCard.registerForAbsent(this, EVENT_ICC_ABSENT, null);
}
if (mUiccApplication != null) {
mUiccApplication.registerForReady(this, EVENT_APP_READY, null);
mUiccApplication.registerForLocked(this, EVENT_ICC_LOCKED, null);
mUiccApplication.registerForNetworkLocked(this, EVENT_NETWORK_LOCKED, null);
}
if (mIccRecords != null) {
mIccRecords.registerForImsiReady(this, EVENT_IMSI_READY, null);
mIccRecords.registerForRecordsLoaded(this, EVENT_RECORDS_LOADED, null);
mIccRecords.registerForRecordsEvents(this, EVENT_ICC_RECORD_EVENTS, null);
}
}
加载完IMSI/record load complete会通知IccCardProxy更新SIM卡状态
7.3
8.IccCardProxy
在PhoneFactory makeDefaultPhone是会创建Phone,在Phone的初始化时会创建IccCardProxy,UiccController初始化之后.IccCardProxy实现IccCard接口,通过Phone getIccCard返回IccCardProxy实例,接口的注释:
/**
* {@hide}
* @Deprecated use UiccController.getUiccCard instead.
*
* Integrated Circuit Card (ICC) interface
* An object of a class implementing this interface is used by external
* apps (specifically PhoneApp) to perform icc card related functionality.
*
* Apps (those that have access to Phone object) can retrieve this object
* by calling phone.getIccCard()
*
* This interface is implemented by IccCardProxy and the object PhoneApp
* gets when it calls getIccCard is IccCardProxy.
*/
接口定义的方法都是通过持有UiccController/UiccCard/UiccCardApplication/IccRecords来实现
8.1 IccCardProxy初始化
makeDefaultPhone方法:
phone = new GsmCdmaPhone(context,
sCommandsInterfaces[i], sPhoneNotifier, i,
PhoneConstants.PHONE_TYPE_CDMA_LTE,
TelephonyComponentFactory.getInstance());
构造方法:
public GsmCdmaPhone(Context context, CommandsInterface ci, PhoneNotifier notifier,
boolean unitTestMode, int phoneId, int precisePhoneType,
TelephonyComponentFactory telephonyComponentFactory) {
super(precisePhoneType == PhoneConstants.PHONE_TYPE_GSM ? "GSM" : "CDMA",
notifier, context, ci, unitTestMode, phoneId, telephonyComponentFactory);
// phone type needs to be set before other initialization as other objects rely on it
mPrecisePhoneType = precisePhoneType;
initOnce(ci);
initRatSpecific(precisePhoneType);
mSST = mTelephonyComponentFactory.makeServiceStateTracker(this, this.mCi);
// DcTracker uses SST so needs to be created after it is instantiated
mDcTracker = mTelephonyComponentFactory.makeDcTracker(this);
mSST.registerForNetworkAttached(this, EVENT_REGISTERED_TO_NETWORK,
null);
logd("GsmCdmaPhone: constructor: sub = " + mPhoneId);
}
initOnce方法:
mIccCardProxy = mTelephonyComponentFactory.makeIccCardProxy(mContext, mCi, mPhoneId);
IccCardProxy实例的个数是与Phone的个数相对应的,有2个phone就会有两个IccCardProxy对象。
IccCardProxy构造方法:
public IccCardProxy(Context context, CommandsInterface ci, int phoneId) {
if (DBG) log("ctor: ci=" + ci + " phoneId=" + phoneId);
mContext = context;
mCi = ci;
mPhoneId = phoneId;
mTelephonyManager = (TelephonyManager) mContext.getSystemService(
Context.TELEPHONY_SERVICE);
mCdmaSSM = CdmaSubscriptionSourceManager.getInstance(context,
ci, this, EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED, null);
mUiccController = UiccController.getInstance();
mUiccController.registerForIccChanged(this, EVENT_ICC_CHANGED, null);
ci.registerForOn(this,EVENT_RADIO_ON, null);
ci.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_UNAVAILABLE, null);
resetProperties();
setExternalState(State.NOT_READY, false);
}
在IccCardProxy初始化时,SIM卡状态是NOT_READY状态并且会broadcastIccStateChangedIntent广播出去;然后在Phone中设置radio模式setVoiceRadioTech。
8.2 IccCardProxy事件处理
IccCardProxy构造方法中向UiccController中注册ICC_CARD_STATUS_CHANGED消息,UiccController在更新完自己内部的UiccCard之后会notify IccCardProxy更新内部各个实例,处理EVENT_ICC_CHANGED的方法updateIccAvailability():
private void updateIccAvailability() {
synchronized (mLock) {
//获取UiccCard
UiccCard newCard = mUiccController.getUiccCard(mPhoneId);
CardState state = CardState.CARDSTATE_ABSENT;
UiccCardApplication newApp = null;
IccRecords newRecords = null;
if (newCard != null) {
state = newCard.getCardState();
//获取UiccCardApplication
newApp = newCard.getApplication(mCurrentAppType);
if (newApp != null) {
//获取IccRecords
newRecords = newApp.getIccRecords();
}
}
if (mIccRecords != newRecords || mUiccApplication != newApp || mUiccCard != newCard) {
if (DBG) log("Icc changed. Reregestering.");
unregisterUiccCardEvents();
mUiccCard = newCard;
mUiccApplication = newApp;
mIccRecords = newRecords;
//注册UiccCard/UiccCardApplication/IccRecords 监听
registerUiccCardEvents();
}
//更新SIM卡状态判断是否发送广播
updateExternalState();
}
}
监听事件:
private void registerUiccCardEvents() {
if (mUiccCard != null) {
//SIM卡拔出事件对外发送广播
mUiccCard.registerForAbsent(this, EVENT_ICC_ABSENT, null);
}
if (mUiccApplication != null) {
//SIM卡Ready对外发送广播
mUiccApplication.registerForReady(this, EVENT_APP_READY, null);
mUiccApplication.registerForLocked(this, EVENT_ICC_LOCKED, null);
mUiccApplication.registerForNetworkLocked(this, EVENT_NETWORK_LOCKED, null);
}
if (mIccRecords != null) {
mIccRecords.registerForImsiReady(this, EVENT_IMSI_READY, null);
mIccRecords.registerForRecordsLoaded(this, EVENT_RECORDS_LOADED, null);
mIccRecords.registerForRecordsEvents(this, EVENT_ICC_RECORD_EVENTS, null);
}
}
UiccController负责对卡槽的卡实时实例化或销毁对象,IccCardProxy监听UiccController里的变化并及时更新自己内部的状态,Phone实例通过getIccCard得到IccCardProxy实例来获取各种卡状态。