Telephony之UICC架构

总体设计

从图中可以看出,处理整个UICC的入口是在UiccController中。相当于Telephony中UICC的管家。

初始化流程

UiccController

UiccController的创建过程可以参考上图初始化流程,通过make方法初始化,注意只创建了一个UiccController对象。

UiccController的功能

UiccController更新机制

mCis[i].registerForIccStatusChanged(this, EVENT_ICC_STATUS_CHANGED, index);
mCis[i].registerForAvailable(this, EVENT_ICC_STATUS_CHANGED, index);
mCis[i].registerForNotAvailable(this, EVENT_RADIO_UNAVAILABLE, index);
mCis[i].registerForIccRefresh(this, EVENT_SIM_REFRESH, index);

UiccController构造函数中注册了4个监听器,依次看下这4个监听器要实现的功能。

这4个监听器都是在RIL的父类BaseCommands中实现的。

registerForIccStatusChanged

public void registerForIccStatusChanged(Handler h, int what, Object obj) {
    Registrant r = new Registrant (h, what, obj);
    mIccStatusChangedRegistrants.add(r);
}

1、当Modem主动上报sim卡状态改变时触发

public void simStatusChanged(int indicationType) {
    mRil.processIndication(indicationType);

    if (RIL.RILJ_LOGD) mRil.unsljLog(RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED);

    mRil.mIccStatusChangedRegistrants.notifyRegistrants();
}

2、处理sim卡PUK和PUK2码时触发

...
protected RILRequest processResponse(RadioResponseInfo responseInfo) {
    switch (rr.mRequest) {
        case RIL_REQUEST_ENTER_SIM_PUK:
        case RIL_REQUEST_ENTER_SIM_PUK2:
            if (mIccStatusChangedRegistrants != null) {
                if (RILJ_LOGD) {
                    riljLog("ON enter sim puk fakeSimStatusChanged: reg count="
                            + mIccStatusChangedRegistrants.size());
                }
                mIccStatusChangedRegistrants.notifyRegistrants();
            }
            break;
    }
    if (error != RadioError.NONE) {
        switch (rr.mRequest) {
            case RIL_REQUEST_ENTER_SIM_PIN:
            case RIL_REQUEST_ENTER_SIM_PIN2:
            case RIL_REQUEST_CHANGE_SIM_PIN:
            case RIL_REQUEST_CHANGE_SIM_PIN2:
            case RIL_REQUEST_SET_FACILITY_LOCK:
                if (mIccStatusChangedRegistrants != null) {
                    if (RILJ_LOGD) {
                        riljLog("ON some errors fakeSimStatusChanged: reg count="
                                + mIccStatusChangedRegistrants.size());
                    }
                    mIccStatusChangedRegistrants.notifyRegistrants();
                }
                break;
        }
    }
  ...
}

registerForAvailable

public void registerForAvailable(Handler h, int what, Object obj) {
    Registrant r = new Registrant (h, what, obj);
    synchronized (mStateMonitor) {
        mAvailRegistrants.add(r);
        if (mState.isAvailable()) {
            r.notifyRegistrant(new AsyncResult(null, null, null));
        }
    }
}

1、当设置Radio状态跟之前状态不同时触发

protected void setRadioState(RadioState newState) {
    RadioState oldState;

        ...

        if (mState.isAvailable() && !oldState.isAvailable()) {
            mAvailRegistrants.notifyRegistrants();
        }

        if (!mState.isAvailable() && oldState.isAvailable()) {
            mNotAvailRegistrants.notifyRegistrants();
        }
        ...
    }
}

registerForNotAvailable

public void registerForNotAvailable(Handler h, int what, Object obj) {
    Registrant r = new Registrant (h, what, obj);

    synchronized (mStateMonitor) {
        mNotAvailRegistrants.add(r);

        if (!mState.isAvailable()) {
            r.notifyRegistrant(new AsyncResult(null, null, null));
        }
    }
}

1、和registerForAvailable监听器一样也是在设置Radio状态跟之前不同时触发。

registerForIccRefresh

public void registerForIccRefresh(Handler h, int what, Object obj) {
    Registrant r = new Registrant (h, what, obj);
    mIccRefreshRegistrants.add(r);
}

1、当modem上报sim卡refresh时触发

public void simRefresh(int indicationType, SimRefreshResult refreshResult) {
    ...

    if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_SIM_REFRESH, response);
    mRil.mIccRefreshRegistrants.notifyRegistrants(new AsyncResult (null, response, null));
}

UiccController对监听事件的处理

UiccController注册了4个监听器,但是只使用了3个Message消息,其中前两个使用了相同的Message。通过在开机LOG中搜索下面的LOG,我们可以确认,开机之后首先触发的是registerForAvailable监听器。

UNSOL_RESPONSE_SIM_STATUS_CHANGED|UNSOL_RESPONSE_RADIO_STATE_CHANGED|UNSOL_SIM_REFRESH

EVENT_ICC_STATUS_CHANGED的处理内容很简单,就是去主动获取sim卡的状态。然后接下来的流程就和初始化流程相对应,依次去初始化其它相关的类。

switch (msg.what) {
    case EVENT_ICC_STATUS_CHANGED:
        if (DBG) log("Received EVENT_ICC_STATUS_CHANGED, calling getIccCardStatus");
        mCis[index].getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE, index));
        break;

UiccCard

UiccCard功能

UiccCard更新机制

UiccCard更新是依赖于UiccController 的,当UiccController中的监听器监听到事件改变时,和开机初始化一样,会主动去获取sim卡状态,然后进行更新UiccCard

UiccCardApplication

UiccCardApplication作用

UiccCardApplication更新机制

IccFileHandler

IccFileHandler根据不同类型的sim卡有5个子类,目前市场上占有量最大的是USIM。UiccCardApplication根据卡的类型会创建IccFileHandler相应的子类。

IccFileHandler功能

IccFileHandler主要提供访问sim卡中EF文件的一些接口。

IccRecords

IccRecords也有3个子类,和IccFileHandler类似,UiccCardApplication也根据不同sim卡的类型创建不同的IccRecords的子类。

IccRecords作用

IccRecords更新机制

这里以IccRecords的子类SIMRecords为例进行介绍。

mParentApp.registerForReady(this, EVENT_APP_READY, null);
mParentApp.registerForLocked(this, EVENT_APP_LOCKED, null);
if (DBG) log("SIMRecords X ctor this=" + this);

IntentFilter intentfilter = new IntentFilter();
intentfilter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);

SIMRecords初始化时注册了两个监听器和一个广播,比较常见的是第一个监听器,这个就是UiccCardApplication中定义的监听器。

@UiccCardApplication.java
public void registerForReady(Handler h, int what, Object obj) {
    synchronized (mLock) {
        Registrant r = new Registrant (h, what, obj);
        mReadyRegistrants.add(r);
        notifyReadyRegistrantsIfNeeded(r);
    }
}

从这里可以看到注册监听器之后,马上回去判断是否通知。根据前面的流程可以判断,这里是满足条件的,所以接下来就是在handleMessage中进行处理。

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

    ...
    loadEfLiAndEfPl();
    mFh.getEFLinearRecordSize(EF_SMS, obtainMessage(EVENT_GET_SMS_RECORD_SIZE_DONE));

    if (DBG) log("fetchSimRecords " + mRecordsToLoad + " requested: " + mRecordsRequested);
}