Android 7.0 高通平臺-telephony-機器無Sim卡情況下,獲取SIM卡狀態方法getSimState偶現爲6,而不是1

TelephonyManager.java

--------》getSimState接口

/**

* Returns a constant indicating the state of the default SIM card.

*

* @see #SIM_STATE_UNKNOWN

* @see #SIM_STATE_ABSENT

* @see #SIM_STATE_PIN_REQUIRED

* @see #SIM_STATE_PUK_REQUIRED

* @see #SIM_STATE_NETWORK_LOCKED

* @see #SIM_STATE_READY

* @see #SIM_STATE_NOT_READY

* @see #SIM_STATE_PERM_DISABLED

* @see #SIM_STATE_CARD_IO_ERROR

*/

public int getSimState() {

int slotIdx = getDefaultSim();

// slotIdx may be invalid due to sim being absent. In that case query all slots to get

// sim state

if (slotIdx < 0) {

// query for all slots and return absent if all sim states are absent, otherwise

// return unknown

for (int i = 0; i < getPhoneCount(); i++) {

int simState = getSimState(i);

if (simState != SIM_STATE_ABSENT) {

Rlog.d(TAG, "getSimState: default sim:" + slotIdx + ", sim state for " +

"slotIdx=" + i + " is " + simState + ", return state as unknown");

return SIM_STATE_UNKNOWN;

}

}

Rlog.d(TAG, "getSimState: default sim:" + slotIdx + ", all SIMs absent, return " +

"state as absent");

return SIM_STATE_ABSENT;

}

return getSimState(slotIdx);

}

 

--------》

public int getSimState(int slotIdx) {

int simState = SubscriptionManager.getSimStateForSlotIdx(slotIdx);

return simState;

}

 

-------》SubscriptionManager.java

public static int getSimStateForSlotIdx(int slotIdx) {

int simState = TelephonyManager.SIM_STATE_UNKNOWN;

 

try {

ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));

if (iSub != null) {

simState = iSub.getSimStateForSlotIdx(slotIdx);

}

} catch (RemoteException ex) {

}

 

return simState;

}

 

 

 

------》SubscriptionController.java

/**

* Get the SIM state for the slot idx

* @return SIM state as the ordinal of {@See IccCardConstants.State}

*/

@Override

public int getSimStateForSlotIdx(int slotIdx) {

State simState;

String err;

if (slotIdx < 0) {

simState = IccCardConstants.State.UNKNOWN;

err = "invalid slotIdx";

} else {

Phone phone = PhoneFactory.getPhone(slotIdx);

if (phone == null) {

simState = IccCardConstants.State.UNKNOWN;

err = "phone == null";

} else {

IccCard icc = phone.getIccCard();

if (icc == null) {

simState = IccCardConstants.State.UNKNOWN;

err = "icc == null";

} else {

simState = icc.getState();

err = "";

}

}

}

if (VDBG) {

logd("getSimStateForSlotIdx: " + err + " simState=" + simState

+ " ordinal=" + simState.ordinal() + " slotIdx=" + slotIdx);

}

return simState.ordinal();

}

 

PhoneFactory.getPhone的內容,我們暫時不用管

其實是GsmCdmaPhone.java的:

@Override

public IccCard getIccCard() {

return mIccCardProxy;

}

 

而,mIccCardProxy恰好是:

private IccCardProxy mIccCardProxy;

 

通過IccCardProxy ,獲取simState = icc.getState();

一個sim卡一個IccCardProxy;

然後return內容是simState.ordinal();

 

--------》IccCardProxy .java

/* IccCard interface implementation */

@Override

public State getState() {

synchronized (mLock) {

return mExternalState;

}

}

 

然後分析全局的mExternalState,是如何獲取到的:

 

private State mExternalState = State.UNKNOWN;

初始值爲UNKNOWN

 

 

然後生成一個Sim卡的Icc代理,就會初始化內容爲:

 

setExternalState(State.NOT_READY, false);

 

也就是說,如果設備沒有Modem,默認情況下爲NOT_READY,即爲6

 

我們主要註冊了以下Message,如下:

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);

 

我們再看如下處理消息的代碼:

@Override

public void handleMessage(Message msg) {

switch (msg.what) {

case EVENT_RADIO_OFF_OR_UNAVAILABLE:

mRadioOn = false;

if (CommandsInterface.RadioState.RADIO_UNAVAILABLE == mCi.getRadioState()) {

setExternalState(State.NOT_READY);

}

break;

case EVENT_RADIO_ON:

mRadioOn = true;

if (!mInitialized) {

updateQuietMode();

}

break;

case EVENT_ICC_CHANGED:

if (mInitialized) {

updateIccAvailability();

}

break;

case EVENT_ICC_ABSENT:

mAbsentRegistrants.notifyRegistrants();

setExternalState(State.ABSENT);

break;

 

IccCardProxy就相當於一個接口代理類,集成了關於Icc的所有接口

但是Icc數據的來源呢?

當然一切的數據來源都是Modem了,BP,基帶了

AP端接受BP信號的入口爲RIL.java

 

結合框架圖和時序圖,下面大致說一下各個類的工作細節。從上到下的順序:

RIL.java

->CommandsInterface.java(CommandsInterface由RIL來實現)

->UiccController.java

->UiccCard.java

->UiccCardApplication.java

->IccCardProxy.java

 

關於這些類,做一個簡要的總結如下:

 

UiccController 設計爲單例模式。監聽RIL中的SIM卡狀態,並把SIM卡狀態的變化通知給其他類。在UICC框架中,它屬於核心部分,除了分發SIM卡狀態變化,還對外提供接口用於獲取UiccCard,IccFileHandler,IccRecords,UiccCardApplication的對象。

 

UiccCard 它代表了具體的卡,一個UiccCard對象就表示了一張SIM卡(PhoneID)。SIM卡中的狀態或者數據都可以在這裏獲取,比如,屬性mCardState保存了SIM卡狀態,mUniversalPinState保存了PIN碼狀態,mCatService代表了STK應用信息,mUiccApplications中包含了SIM卡的具體數據。。。等等,總結起來,UiccCard是SIM卡的大管家,它既代表了SIM卡,又控制了UiccApplications,CatService的生命週期。

 

UiccCardApplication 顧名思義,這是SIM卡應用(不是STK)。應該是對應了上面說到的邏輯模塊,一張SIM卡可以有多個邏輯模塊,也就有多個UiccCardApplication對象。它控制了IccRecords和IccFileHandler的生命週期。而IccRecords和IccFileHandler都是讀取和保存SIM卡中具體數據的操作類

 

IccFileHandler 讀取SIM卡中(邏輯模塊)的文件系統,也就是SIM卡中的具體數據。根據UICC卡的種類不同,衍生了幾個對應的子類SIMFileHandler,UsimFileHandler,RuimFileHandler,CsimFileHandler,IsimFileHandler

 

IccRecords 模板類,通過IccFileHandler來操作SIM卡中的文件系統個,獲取並保存SIM中的具體數據,根據UICC卡的種類不同,衍生了幾個對應的子類SIMRecords,RuimRecords,IsimUiccRecords

 

IccCardProxy 封裝了對UICC的一系列操作(狀態和數據),並對外提供接口。一張卡(PhoneID)對應一個IccCardProxy對象。實際上,我們可以使用UiccController獲取其他的對象從而實現對UICC的操作,但是需要傳入一系列參數並保證卡狀態正確,否則需要做判斷處理,使用IccCardProxy操作只需要知道PhoneID。併發出ACTION_SIM_STATE_CHANGED廣播,通知應用層以及沒有監聽UiccController得知SIM卡狀態發生變化的其他類。

 

 

 

 

 

 

uiccçæ¶åºå¾

 

詳細內容參考如下文章:

https://blog.csdn.net/supergame111/article/details/106452987

 

現在來分析如題問題,爲何會機器在無卡狀態下,偶現獲取狀態值爲6,

正確值應該是1:

SIM_STATE_NOT_READY---------6

SIM_STATE_ABSENT-------1

 

是用at命令,獲取的值爲1

如果重置網絡數據,這個值理應就是1了

因爲首次開機,sim卡狀態會被system保存,只有icc狀態發生改變,modem纔會觸發上報機制,然後更新icc狀態

 

爲了驗證推理是否正確,因爲sim卡支持熱插拔,重新插一張卡,狀態爲Ready,然後把卡拔了,狀態值爲1,屬正常了。因爲插入卡,觸發了更新狀態流程

 

此問題解決方式:

因爲大部分時候,機器都沒問題,可能重啓、刷機一下,就能解決此問題,概率比較低,約爲2/500,如果要徹底解決此問題,建議從modem端解決,較爲徹底。

可以使用重發機制,icc卡狀態上報兩次,間隔一段時間。

 

如果要在AP端解決此問題,可以在更新icc狀態前,做一定的延時,或者針對mInitialized爲false的情況,重發一次。

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章