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

    技术2022-07-10  199

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

     

     

     

     

     

     

     

    详细内容参考如下文章:

    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的情况,重发一次。

     

     

     

     

     

     

     

    Processed: 0.076, SQL: 9