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

Android 7.0 高通平台-telephony-机器无Sim卡情况下,获取SIM卡状态方法getSimState偶现为6,而不是1

 

 

然后生成一个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卡状态发生变化的其他类。

 

 

Android 7.0 高通平台-telephony-机器无Sim卡情况下,获取SIM卡状态方法getSimState偶现为6,而不是1

 

 

Android 7.0 高通平台-telephony-机器无Sim卡情况下,获取SIM卡状态方法getSimState偶现为6,而不是1

 

 

Android 7.0 高通平台-telephony-机器无Sim卡情况下,获取SIM卡状态方法getSimState偶现为6,而不是1

 

详细内容参考如下文章:

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

 

现在来分析如题问题,为何会机器在无卡状态下,偶现获取状态值为6,

正确值应该是1:

SIM_STATE_NOT_READY---------6

SIM_STATE_ABSENT-------1

Android 7.0 高通平台-telephony-机器无Sim卡情况下,获取SIM卡状态方法getSimState偶现为6,而不是1

 

是用at命令,获取的值为1

如果重置网络数据,这个值理应就是1了

因为首次开机,sim卡状态会被system保存,只有icc状态发生改变,modem才会触发上报机制,然后更新icc状态

 

为了验证推理是否正确,因为sim卡支持热插拔,重新插一张卡,状态为Ready,然后把卡拔了,状态值为1,属正常了。因为插入卡,触发了更新状态流程

 

此问题解决方式:

因为大部分时候,机器都没问题,可能重启、刷机一下,就能解决此问题,概率比较低,约为2/500,如果要彻底解决此问题,建议从modem端解决,较为彻底。

可以使用重发机制,icc卡状态上报两次,间隔一段时间。

 

如果要在AP端解决此问题,可以在更新icc状态前,做一定的延时,或者针对mInitialized为false的情况,重发一次。