Phone
对象初始化的过程中,会加载SIM卡的部分数据信息,这些信息会保存在IccRecords 和 AdnRecordCache
中。SIM卡的数据信息的初始化过程主要分为如下几个步骤
1.RIL 和 UiccController 建立监听关系
,SIM卡状态发生变化时,UiccController 第一个去处理。
Phone 应用初始化 Phone 对象时会建立一个 RIL
和UiccController 的监听关系:UiccController 监听 RIL,相关代码如下
sCommandsInterface = new RIL(context,
networkMode, cdmaSubscription); UiccController.make(context,
sCommandsInterface);
UiccController 构造的过程
private UiccController(Context c, CommandsInterface ci)
{
if (DBG) log("Creating
UiccController");
mContext = c;
mCi = ci;
mCi.registerForIccStatusChanged(this,
EVENT_ICC_STATUS_CHANGED, null);
// TODO remove this once modem correctly notifies
the unsols
mCi.registerForOn(this, EVENT_ICC_STATUS_CHANGED,
null);
}
从代码中可以看出,UiccController 对象被注册为RIL对象的监听者,当 RIL 检测到 uicc card
状态发生变化或者 radio on UiccController 都会处理对应的数据变化。UiccController 是
SIM卡状态发生变化后的第一个处理者。
UiccController 处理 EVENT_ICC_STATUS_CHANGED
public void handleMessage (Message msg) {
synchronized (mLock) {
switch
(msg.what) {
case
EVENT_ICC_STATUS_CHANGED:
if (DBG) log("Received EVENT_ICC_STATUS_CHANGED,
calling getIccCardStatus");
mCi.getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE));
break;
case
EVENT_GET_ICC_STATUS_DONE:
if (DBG) log("Received
EVENT_GET_ICC_STATUS_DONE");
AsyncResult ar =
(AsyncResult)msg.obj;
onGetIccCardStatusDone(ar);
break;
default:
Rlog.e(LOG_TAG, " Unknown Event " +
msg.what);
}
}
}
从代码中可以看出,RIL 上报
SIM卡状态发生变化后,做了两件事,一是获取SIM卡的具体状态,二是处理这个状态。
UiccController 处理具体的SIM卡状态
private synchronized void onGetIccCardStatusDone(AsyncResult
ar) {
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;
}
IccCardStatus status =
(IccCardStatus)ar.result;
if (mUiccCard == null) {
//Create
new card
mUiccCard =
new UiccCard(mContext, mCi, status);
} else {
//Update
already existing card
mUiccCard.update(mContext, mCi ,
status);
}
if (DBG) log("Notifying
IccChangedRegistrants");
mIccChangedRegistrants.notifyRegistrants();
}
从代码中可以看出,做了两件事,一是 创建或者 更新 UiccCard
二是 通知监听 UiccController 的监听者。
2.创建或者更新 UiccCard,UiccCard
创建或者更新与SIM卡类型对应的UiccCardApplication.
一个UiccCard 对象代表着一张SIM卡,UiccCard 根据获取的SIM卡信息创建
UiccCardApplication,UiccCardApplication去读取具体的SIM卡里的信息。
更新UiccCard
public void update(Context c, CommandsInterface ci,
IccCardStatus ics) {
synchronized (mLock) {
if
(mDestroyed) {
loge("Updated after destroyed!
Fix me!");
return;
}
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);
}
}
if
(mUiccApplications.length > 0 && mUiccApplications[0] !=
null) {
// Initialize or Reinitialize
CatService
mCatService =
CatService.getInstance(mCi,
mContext,
this);
} else
{
if (mCatService != null)
{
mCatService.dispose();
}
mCatService =
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) {
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;
}
}
IccCardStatus,记录了RIL 读取的SIM卡的信息,UiccCard 根据 IccCardStatus
中记录的应用程序信息,创建 UiccCardApplication.
UiccCard 还创建了 CatService,用于读取 STK 的信息。
创建或者更新 UiccCardApplication
UiccCardApplication,会记录对应的卡的状态,类型,以及卡的记录信息。
//创建 UiccCardApplication
UiccCardApplication(UiccCard uiccCard,
IccCardApplicationStatusas,
Context
c,
CommandsInterface ci) {
if (DBG) log("Creating UiccApp: " +
as);
mUiccCard = uiccCard;
mAppState = as.app_state;
mAppType = as.app_type;
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);
///读取 SIM卡上的 EF 文件信息
if (mAppState == AppState.APPSTATE_READY)
{
queryFdn();
// FDN 信息
queryPin1State(); // Pin State
}
}
//更新UiccCardApplication
void update (IccCardApplicationStatusas, 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;
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;
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();// FDN 信息
queryPin1State();
}
notifyPinLockedRegistrantsIfNeeded(null);
notifyReadyRegistrantsIfNeeded(null);
}
}
}
在更新和创建UiccCardApplication的过程中,有如下几个重要的变量
IccRecords
记录 SIM卡上的EF
文件信息,实现类有SIMRecords,RuimRecords,IsimUiccRecords,对应于不同的类型的SIM卡。
IccFileHandler
根据SIM卡的类型,去读取SIM卡上的信息,实现类有SIMFileHandler,RuimFileHandler,UsimFileHandler,CsimFileHandler,IsimFileHandler,对应于不同的SIM卡。
创建 IccRecords 对象
正如前面所描述的,IccRecords 记录SIM卡的EF文件信息,具体的读取SIM卡EF文件信息的过程是由
IccFileHandler 来实现的,以 SIMRecords 为例。
public SIMRecords(UiccCardApplication app, Context c,
CommandsInterface ci) {
super(app, c, ci);
// 1.电话本的缓存
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();
//2. 读取 SIM卡的所有重要的记录信息
mParentApp.registerForReady(this,
EVENT_APP_READY, null);
if (DBG) log("SIMRecords X ctor this=" +
this);
}
这个过程包含两个重要的步骤
创建AdnRecordCache,用于保存电话本数据,根据EF的ID,可以分别读取SIM卡和USIM卡的电话本数据。AdnRecordCache
中持有一个UsimPhoneBookManager,它就是用来读取USIM卡电话本数据的。GSM的SIM卡和WCDMA的USIM卡都是对应的
SimRecords.
读取SIM卡的所有重要记录信息,在fetchSimRecords 方法中实现。
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,
EF_EXT1, 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.
mFh.loadEFLinearFixed(EF_CFIS, 1,
obtainMessage(EVENT_GET_CFIS_DONE));
mRecordsToLoad++;
mFh.loadEFTransparent(EF_CFF_CPHS,
obtainMessage(EVENT_GET_CFF_DONE));
mRecordsToLoad++;
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++;
// 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);
}
总的来说,创建 SimRecords 的过程就是读取并且保存SIM卡重要信息的过程。其中,电话本的信息保存在 mAdnCache
中,其他信息保存在 SimRecords 中,但是在Phone对象完成初始化后,mAdnCache
里是空的,也就是说,在IccRecords 初始化的过程中,AdnRecordCache
并没有主动去请求SIM卡联系人的数据。
所有的IccRecords 是通过 IccFileHandler 向Modem 发命令读取数据的。他们之间的交互图如下
3.通知UiccController
的监听者,与UiccCardApplication的相关信息可以更新了。根据分析源代码,我们可以看到,PhoneBase
,ServiceStateTracker,IccCardProxy,DcTrackerBase,这些类是 UiccController
的监听者。他们都会处理UiccController
的变化。我们可以这么理解,这些类是SIM卡状态发生变化后,第二批处理SIM卡状态变化的实体。第一个处理SIM卡状态变化的是
UiccController.