UICC框架初识

一.UICC概念

UICC:Universal Integrated Circuit Card,通用集成电路卡。主要用于存储用户信息、鉴权密钥、短消、付费方式等信息。俗称电话卡,SIM卡。

二.UICC种类

UICC引入了多应用平台的概念,实现了多个逻辑应用(即逻辑模块)同时运行的多通道机制。一个UICC可同时包含多种不同的逻辑模块,根据当前终端所支持的无线接入网络的类型,来选择使用相应的逻辑模块。

UICC根据逻辑模块的不同,分为以下几种不同的电话卡:

1.SIM:如用户标识模块(Subscriber Identity Module)
早期的SIM卡类型,支持GSM网络。
2.USIM:通用用户标识模块(Universal Subscriber Identity Module,)
升级版的SIM卡,支持UMTS(WCMDA,TD-SCDMA)和GSM网络,(联通卡,移动卡)
3.RUIM:可移动用户身份模块(Removable User Identity Module)
在SIM卡基础上做了扩展,专门为网络而设计,不再只是针对GSM,比如:CDMA.R-UIM卡支持在CDMA和GSM网络之间的漫游。支持CDMA和GSM网络(电信卡)
4.ISIM:IP多媒体业务标识模块(IP Multi Media Service Identity Module,)
存储了IMS(IP多媒体系统)专用的用户数据,主要由IMS运营商所提供。
5.CSIM:CDMA用户识别模块(CDMA Subscriber Identity Module )

三.UICC框架

Android4.1之后的版本都使用了UICC框架来管理和控制SIM卡。

UICC的大体框架图如下:
UICC的大体框架图

UICC框架中涉及的类主要有以下几个:































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


UICC框架中主动读取SIM卡状态的时序图:

uicc的时序图

结合框架图和时序图,下面大致说一下各个类的工作细节。从上到下的顺序:
RIL.java->UiccController.java->UiccCard.java->UiccCardApplication.java->IccCardProxy.java

UICC框架中把SIM卡的状态分为以下几种:

IccCardStatus.java

public static enum CardState {
    CARDSTATE_ABSENT,
    CARDSTATE_PRESENT,
    CARDSTATE_ERROR;
}

UiccController监听RIL中的状态变化,其中几个比较重要的监听事件如下:

EVENT_ICC_STATUS_CHANGED SIM卡状态
EVENT_GET_ICC_STATUS_DONE 主动查询SIM卡状态
EVENT_RADIO_UNAVAILABLE Modem没启动或者错误
EVENT_SIM_REFRESH SIM卡刷新

EVENT_ICC_STATUS_CHANGED,EVENT_RADIO_UNAVAILABLE,EVENT_SIM_REFRESH 都是RIL主动上报的事件消息。其中EVENT_ICC_STATUS_CHANGED这个事件消息的上报结果中并不会携带结果,也就是说得到这个状态,只能判断到当前SIM卡状态变化了,但是当前是CARDSTATE_ABSENT,CARDSTATE_PRESENT,CARDSTATE_ERROR中的哪一个,你还需要查询一遍,所以就有了以下的这个状态监听:
EVENT_GET_ICC_STATUS_DONE 主动查询SIM卡状态
这就是有了EVENT_ICC_STATUS_CHANGED事件消息后还需要设置EVENT_GET_ICC_STATUS_DONE事件消息的原因。

1.RIL.java

RIL中处理SIM卡状态相关的事件消息。其中,在处理EVENT_GET_ICC_STATUS_DONE 主动查询SIM卡状态的时候,查询结果被封装在IccCardStatus类中并交由其监听类UiccController中处理(ret):

case RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED:
    if (RILJ_LOGD) unsljLog(response);

    if (mIccStatusChangedRegistrants != null) {
        mIccStatusChangedRegistrants.notifyRegistrants();
    }
    break;
case RIL_UNSOL_SIM_REFRESH:
    if (RILJ_LOGD) unsljLogRet(response, ret);
    if (mIccRefreshRegistrants != null) {
        mIccRefreshRegistrants.notifyRegistrants(
                new AsyncResult (null, ret, null));
    }
    break;
case RIL_REQUEST_GET_ICC_APPLICATION_STATUS: ret = responseIccCardStatus(p); break;
case RIL_REQUEST_GET_SIM_STATUS: ret =  responseIccCardStatus(p); break;
......

private Object responseIccCardStatus(Parcel p) {
    IccCardApplicationStatus appStatus;

    IccCardStatus cardStatus = new IccCardStatus();
    cardStatus.setCardState(p.readInt());
    ......
    return cardStatus;
}

2.UiccController.java

UiccController中处理SIM卡状态相关的事件消息:

case EVENT_GET_ICC_STATUS_DONE:
    if (DBG) log("Received EVENT_GET_ICC_STATUS_DONE");
    onGetIccCardStatusDone(ar, index);
    break;
case EVENT_RADIO_UNAVAILABLE:
    if (DBG) log("EVENT_RADIO_UNAVAILABLE, dispose card");
    if (mUiccCards[index] != null) {
        mUiccCards[index].dispose();
    }
    mUiccCards[index] = null;
    mIccChangedRegistrants.notifyRegistrants(new AsyncResult(null, index, null));
    break;
case EVENT_SIM_REFRESH:
    if (DBG) log("Received EVENT_SIM_REFRESH");
    onSimRefresh(ar, index);    

如时序图所示,主要分析主动查询SIM卡状态时的流程:为每一张SIM卡初始化一个UiccCards对象并赋初值。

private synchronized void onGetIccCardStatusDone(AsyncResult ar, Integer index) {
    ......
    if(this.mUiccCards[index.intValue()] == null) {
        this.mUiccCards[index.intValue()] = new UiccCard(this.mContext,       this.mCis[index.intValue()], status, index.intValue());
    } else {
        this.mUiccCards[index.intValue()].update(this.mContext,  this.mCis[index.intValue()], status);
    }
......
}

3.UiccCard.java

一个UiccCard对象就表示了一张SIM卡(PhoneID),其控制了UiccApplications,CatService的生命周期。参见UiccCard.java—->createAndUpdateCatService()和update()

4.UiccApplications.java

UiccApplications代表了SIM卡中的逻辑模块,根据当前SIM中的逻辑模块的多少产生多少个UiccApplications对象,上限为8个。控制着IccRecords和IccFileHandler的生命周期,此外还包含了一系列对SIM卡数据的操作,比如pin码,puk码,是否锁卡,是否支持FDN等等,系统文件的读取则交由IccFileHandler处理。

根据UICC卡的种类不同,创建相应的模板类IccRecords:

        if (type == AppType.APPTYPE_USIM || type == AppType.APPTYPE_SIM) {
            return new SIMRecords(this, c, ci);
        } else if (type == AppType.APPTYPE_RUIM || type == AppType.APPTYPE_CSIM){
            return new RuimRecords(this, c, ci);
        } else if (type == AppType.APPTYPE_ISIM) {
            return new IsimUiccRecords(this, c, ci);
        } else {
            // Unknown app type (maybe detection is still in progress)
            return null;
        }

根据UICC卡的种类不同,创建相应的系统文件读取类IccFileHandler:

    private IccFileHandler createIccFileHandler(AppType type) {
        switch (type) {
            case APPTYPE_SIM:
                return new SIMFileHandler(this, mAid, mCi);
            case APPTYPE_RUIM:
                return new RuimFileHandler(this, mAid, mCi);
            case APPTYPE_USIM:
                return new UsimFileHandler(this, mAid, mCi);
            case APPTYPE_CSIM:
                return new CsimFileHandler(this, mAid, mCi);
            case APPTYPE_ISIM:
                return new IsimFileHandler(this, mAid, mCi);
            default:
                return null;
        }
}

这里忽略IccRecords和IccFileHandler中对SIM卡内存的数据操作……

5.IccCardProxy.java

IccCardProxy设计的初衷就是对外提供接口。因为UiccCards对象的创建跟卡状态相关,会动态创建和销毁,如果外部通过UiccCards来获取卡的状态以及其他信息,不可避免的会出现错误,因此,android就设计了IccCardProxy,无论卡状态如何变化,它的对象都存在,其初始化在TelephonyComponentFactory.java中:

public IccCardProxy makeIccCardProxy(Context context, CommandsInterface ci, int phoneId) {
    return new IccCardProxy(context, ci, phoneId);
}

Phone对象创建时,先创建了UiccController对象,之后根据mPhoneId创建了IccCardProxy对象,意味着有几个卡槽就有几个IccCardProxy对象。

mIccCardProxy = mTelephonyComponentFactory.makeIccCardProxy(mContext, mCi, mPhoneId);

如果我们需要操作SIM卡相关,正确的姿势应该是通过Phone对象获取IccCardProxy对象,通过IccCardProxy暴露出的接口来实现对SIM卡相关的操作。

@Override
public IccCard getIccCard() {
    return mIccCardProxy;
}

Android对IccCardProxy的设计初衷的注释如下:
* The Phone App assumes that there is only one icc card, and one icc application
* available at a time. Moreover, it assumes such object (represented with IccCard)
* is available all the time (whether {@link RILConstants#RIL_REQUEST_GET_SIM_STATUS} returned
* or not, whether card has desired application or not, whether there really is a card in the
* slot or not).
*
* UiccController, however, can handle multiple instances of icc objects (multiple
* {@link UiccCardApplication}, multiple {@link IccFileHandler}, multiple {@link IccRecords})
* created and destroyed dynamically during phone operation.
*
* This class implements the IccCard interface that is always available (right after default
* phone object is constructed) to expose the current (based on voice radio technology)
* application on the uicc card, so that external apps won’t break.

以上就是对UICC框架的一些简单总结,细节方面待以后使用到的时候再去研究。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值