本文代码以MTK平台Android 4.4为分析对象,与Google原生AOSP有些许差异,请读者知悉。
本文主要介绍sim卡数据的读取过程,当射频状态处于准备状态时,此时UiccCardApplication应处于AppState.APPSTATE_READY状态,我们沿着这个信号跟踪下去。阅读本文时可先阅读Android4.4 Telephony流程分析——SIM卡开机时的初始化一文,了解Radio和sim卡状态更新过程。
先来看一下数据加载的序列图:
step1~step3,走的是更新过程,创建过程参考Android4.4 Telephony流程分析——SIM卡开机时的初始化一文step21之后的步骤。
step4,通过Modem查询sim卡的FDN(固定拨号)数据。
step5,通过Modem查询sim卡的pin1状态。
step6~step7,将pin1状态通知出去,IccCardProxy会注册mPinLockedRegistrants。
step8~step9,将sim卡ready状态发出去。
01.
private
void
notifyReadyRegistrantsIfNeeded(Registrant r) {
02.
if
(mDestroyed) {
03.
return
;
04.
}
05.
if
(mAppState == AppState.APPSTATE_READY) {
06.
if
(mPin1State == PinState.PINSTATE_ENABLED_NOT_VERIFIED ||
07.
mPin1State == PinState.PINSTATE_ENABLED_BLOCKED ||
08.
mPin1State == PinState.PINSTATE_ENABLED_PERM_BLOCKED) {
09.
loge(
"Sanity check failed! APPSTATE is ready while PIN1 is not verified!!!"
);
10.
// Don't notify if application is in insane state
11.
return
;
12.
}
13.
if
(r ==
null
) {
14.
if
(DBG) log(
"Notifying registrants: READY"
);
15.
mReadyRegistrants.notifyRegistrants();
16.
}
else
{
17.
if
(DBG) log(
"Notifying 1 registrant: READY"
);
18.
r.notifyRegistrant(
new
AsyncResult(
null
,
null
,
null
));
19.
}
20.
}
21.
}
如果此时pin1是被激活的,也就是sim卡开启了pin1锁,sim卡ready状态就不会发出去。
监听mReadyRegistrants状态变化的对象很多,主要有:SIMRecords(同类的还有RuimRecords、IsimUiccRecords),IccCardProxy(会将SIM卡状态广播出去),GsmServiceStateTracker(会根据SIM状态去注册网络),这里主要说一下SIMRecords,读取SIM的数据。
step12,fetchSimRecords()方法:
001.
//MTK-END [mtk80601][111215][ALPS00093395]
002.
protected
void
fetchSimRecords() {
003.
mRecordsRequested =
true
;
004.
005.
if
(DBG) log(
"fetchSimRecords "
+ mRecordsToLoad);
006.
007.
mCi.getIMSIForApp(mParentApp.getAid(), obtainMessage(EVENT_GET_IMSI_DONE));
//读IMSI
008.
mRecordsToLoad++;
009.
010.
//iccFh.loadEFTransparent(EF_ICCID, obtainMessage(EVENT_GET_ICCID_DONE));
011.
//mRecordsToLoad++;
012.
013.
// FIXME should examine EF[MSISDN]'s capability configuration
014.
// to determine which is the voice/data/fax line
015.
//new AdnRecordLoader(phone).loadFromEF(EF_MSISDN, EF_EXT1, 1,
016.
//obtainMessage(EVENT_GET_MSISDN_DONE));
017.
//recordsToLoad++;
018.
019.
// Record number is subscriber profile
020.
mFh.loadEFLinearFixed(EF_MBI,
1
, obtainMessage(EVENT_GET_MBI_DONE));
021.
mRecordsToLoad++;
022.
023.
mFh.loadEFTransparent(EF_AD, obtainMessage(EVENT_GET_AD_DONE));
024.
mRecordsToLoad++;
025.
026.
// Record number is subscriber profile
027.
mFh.loadEFLinearFixed(EF_MWIS,
1
, obtainMessage(EVENT_GET_MWIS_DONE));
028.
mRecordsToLoad++;
029.
030.
031.
// Also load CPHS-style voice mail indicator, which stores
032.
// the same info as EF[MWIS]. If both exist, both are updated
033.
// but the EF[MWIS] data is preferred
034.
// Please note this must be loaded after EF[MWIS]
035.
mFh.loadEFTransparent(
036.
EF_VOICE_MAIL_INDICATOR_CPHS,
037.
obtainMessage(EVENT_GET_VOICE_MAIL_INDICATOR_CPHS_DONE));
038.
mRecordsToLoad++;
039.
040.
// Same goes for Call Forward Status indicator: fetch both
041.
// EF[CFIS] and CPHS-EF, with EF[CFIS] preferred.
042.
mFh.loadEFLinearFixed(EF_CFIS,
1
, obtainMessage(EVENT_GET_CFIS_DONE));
043.
mRecordsToLoad++;
044.
mFh.loadEFTransparent(EF_CFF_CPHS, obtainMessage(EVENT_GET_CFF_DONE));
045.
mRecordsToLoad++;
046.
047.
048.
//getSpnFsm(true, null);
049.
050.
mFh.loadEFTransparent(EF_SPDI, obtainMessage(EVENT_GET_SPDI_DONE));
051.
mRecordsToLoad++;
052.
053.
//mFh.loadEFLinearFixed(EF_PNN, 1, obtainMessage(EVENT_GET_PNN_DONE));
054.
//recordsToLoad++;
055.
056.
mFh.loadEFTransparent(EF_SST, obtainMessage(EVENT_GET_SST_DONE));
057.
mRecordsToLoad++;
058.
059.
mFh.loadEFTransparent(EF_INFO_CPHS, obtainMessage(EVENT_GET_INFO_CPHS_DONE));
060.
mRecordsToLoad++;
061.
062.
mFh.loadEFTransparent(EF_CSP_CPHS,obtainMessage(EVENT_GET_CSP_CPHS_DONE));
063.
mRecordsToLoad++;
064.
065.
mFh.loadEFTransparent(EF_GID1, obtainMessage(EVENT_GET_GID1_DONE));
066.
mRecordsToLoad++;
067.
068.
/*
069.
Detail description:
070.
This feature provides a interface to get menu title string from EF_SUME
071.
*/
072.
if
(mTelephonyExt !=
null
) {
073.
if
(mTelephonyExt.isSetLanguageBySIM()) {
074.
mFh.loadEFTransparent(EF_SUME, obtainMessage(EVENT_QUERY_MENU_TITLE_DONE));
075.
mRecordsToLoad++;
076.
}
077.
}
else
{
078.
loge(
"fetchSimRecords(): mTelephonyExt is null!!!"
);
079.
}
080.
081.
fetchCPHSOns();
082.
083.
// XXX should seek instead of examining them all
084.
if
(
false
) {
// XXX
085.
mFh.loadEFLinearFixedAll(EF_SMS, obtainMessage(EVENT_GET_ALL_SMS_DONE));
086.
mRecordsToLoad++;
087.
}
088.
089.
if
(CRASH_RIL) {
090.
String sms =
"0107912160130310f20404d0110041007030208054832b0120"
091.
+
"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
092.
+
"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
093.
+
"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
094.
+
"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
095.
+
"ffffffffffffffffffffffffffffff"
;
096.
byte
[] ba = IccUtils.hexStringToBytes(sms);
097.
098.
mFh.updateEFLinearFixed(EF_SMS,
1
, ba,
null
,
099.
obtainMessage(EVENT_MARK_SMS_READ_DONE,
1
));
100.
}
101.
if
(DBG) log(
"fetchSimRecords "
+ mRecordsToLoad +
" requested: "
+ mRecordsRequested);
102.
/*
103.
* Here, we assume that PHB is ready and try to read the entries.
104.
* If it is not, we will receive the event EVENT_PHB_READY later.
105.
* Then, we will ready the PHB entries again.
106.
*/
107.
fetchPhbRecords();
//读adn联系人
108.
109.
fetchRatBalancing();
110.
}
读SIM卡是要通过Modem的,上层读Modem就得通过RIL,我们以读ADN联系人fetchPhbRecords()为例,来看看读取过程step13~step22,主要是通过IccFileHandler实现,先请求adn的长度(step16~step19),然后再请求具体的adn联系人数据step20~step22,这个过程就是与Modem交互的过程,读者可以先了解一下SIM卡的文件结构,才能更好的理解为什么这样读,我也不甚熟悉。
step23,获取SIM卡内置的紧急号码,这个是由运营商定制的。
step24~step26,当需要load的数据都load完成,才会执行,再在onAllRecordsLoaded中发布mRecordsLoadedRegistrants通知。
01.
protected
void
onRecordLoaded() {
02.
// One record loaded successfully or failed, In either case
03.
// we need to update the recordsToLoad count
04.
mRecordsToLoad -=
1
;
05.
if
(DBG) log(
"onRecordLoaded "
+ mRecordsToLoad +
" requested: "
+ mRecordsRequested);
06.
07.
if
(mRecordsToLoad ==
0
&& mRecordsRequested ==
true
) {
08.
onAllRecordsLoaded();
09.
}
else
if
(mRecordsToLoad <
0
) {
10.
loge(
"recordsToLoad <0, programmer error suspected"
);
11.
mRecordsToLoad =
0
;
12.
}
13.
}
step27之后的步骤,都是对mRecordsLoadedRegistrants侦听的响应,IccCardProxy侦听到后,会发广播给外界:
01.
private
void
broadcastIccStateChangedIntent(String value, String reason) {
02.
synchronized
(mLock) {
03.
if
(mQuietMode) {
04.
log(
"QuietMode: NOT Broadcasting intent ACTION_SIM_STATE_CHANGED "
+ value
05.
+
" reason "
+ reason);
06.
return
;
07.
}
08.
09.
Intent intent =
new
Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
10.
//intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
11.
intent.putExtra(PhoneConstants.PHONE_NAME_KEY,
"Phone"
);
12.
intent.putExtra(IccCardConstants.INTENT_KEY_ICC_STATE, value);
13.
intent.putExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON, reason);
14.
intent.putExtra(PhoneConstants.GEMINI_SIM_ID_KEY, mSimId);
15.
if
(DBG) log(
"Broadcasting intent ACTION_SIM_STATE_CHANGED "
+ value
16.
+
" reason "
+ reason +
" sim id "
+ mSimId);
17.
ActivityManagerNative.broadcastStickyIntent(intent, READ_PHONE_STATE,
18.
UserHandle.USER_ALL);
19.
}
20.
}
21.
22.
public
void
broadcastIccStateChangedExtendIntent(String value, String reason) {
23.
synchronized
(mLock) {
24.
if
(mQuietMode) {
25.
log(
"QuietMode: NOT Broadcasting extend intent ACTION_SIM_STATE_CHANGED "
+ value
26.
+
" reason "
+ reason);
27.
return
;
28.
}
29.
30.
Intent intent =
new
Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED_EXTEND);
31.
//intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
32.
intent.putExtra(PhoneConstants.PHONE_NAME_KEY,
"Phone"
);
33.
intent.putExtra(IccCardConstants.INTENT_KEY_ICC_STATE, value);
34.
intent.putExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON, reason);
35.
intent.putExtra(PhoneConstants.GEMINI_SIM_ID_KEY, mSimId);
36.
if
(DBG) log(
"Broadcasting intent ACTION_SIM_STATE_CHANGED_EXTEND "
+ value
37.
+
" reason "
+ reason +
" sim id "
+ mSimId);
38.
ActivityManagerNative.broadcastStickyIntent(intent, READ_PHONE_STATE,
39.
UserHandle.USER_ALL);
40.
}
41.
}