UICC 实现框架和数据读写

  现有的手机中使用的卡SIM, USIM,UIM等统称为:UICC——Universal Integrated Circuit Card;

这些卡之间数据结构是有些区别的,先来看看SIM卡的文件结构。

一 Sim文件系统数据结构

1 sim卡文件系统

  SIM card file system structure:

            UICC 实现框架和数据读写_第1张图片

2 文件结构

  MF:The root level of the file system is known as the Master file.

  DF:Directories are known as Dedicated files and are of a fixed size.

  EF:Individual records (or files) are known as Elementary files.

 

  All files are identified as an address (a DWORD value), rather than a filename.

 

3 文件类型

Transparent

  透明结构的EF 由一个字节序列组成。当文件读或更新,字节序列活动是参照相对地

址(OFFSET)进行的,相对地址可表示出起始操作的地址(用字节表示)和读出、更新的

字节数。透明EF 的第一个字节有一个相对地址‘0000’。EF 主体的数据长度在EF 的文件

头中。

Linear Fixed File

  线性固定EF 文件由一个记录长度固定的记录序列组成。第一个记录记录号是1。记录

的长度和记录长度与记录个数的乘积存放在EF 文件头中。

Cyclic

  循环文件用于以时间顺序存储的记录,当所有的记录空间都占用时,新的存储数据将

覆盖最旧的信息。

  访问不同的文件类型,使用的方式也将不同。对于USIM,RUIM等卡基本文件结构应该是一致的,局部存储信息的单元,位置不同而已。

 

二 UICC卡数据读写

1 UICC框架类结构

  手机需要关注的UICC包括:数据读写记录,状态变化管理;Android中是管理UICC的框架代码位于:

frameworks\opt\telephony\src\java\com\android\internal\telephony\uicc\

基本框架类得结构图:

            UICC 实现框架和数据读写_第2张图片

        

对于不同的卡会有不同的类与之对应,这些类的作用:

  UiccController:整个UICC相关信息的控制接口;监控SIM状态变化;

  UiccCard:UICC卡代码中对应的抽象;

  IccCardStatus:维护UICC卡的状态:CardState & PinState;

  UiccCardApplication:UICC具体的一个应用;负责Pin Puk密码设置解锁,数据的读取,存储;

  CatService:负责SIM Toolkit相关;

  IccConstants:SIM File Address;存储不同数据在Sim卡上的字段地址;SIMRecords等基类;

  SIMRecords /RuimRecords:记录SIM卡上的数据;

  IccFileHandler:读取SIM数据以及接收读取的结果;

2 UICC 框架执行流程

  UICC的状态监控是在UiccController中进行的;

UiccController构造函数:

private UiccController(Context c, CommandsInterface ci) { mCi = ci; //注册UICC卡状态变化监听
        mCi.registerForIccStatusChanged(this, EVENT_ICC_STATUS_CHANGED, null); //注册RADIO状态变化监听
        mCi.registerForOn(this, EVENT_ICC_STATUS_CHANGED, null); mCi.registerForAvailable(this, EVENT_ICC_STATUS_CHANGED, null); mCi.registerForNotAvailable(this, EVENT_RADIO_UNAVAILABLE, null); }

 

UICC Card状态有变化处理:

public void handleMessage (Message msg) { switch (msg.what) { case EVENT_ICC_STATUS_CHANGED: //UICC状态变化,获取UICC状态
 mCi.getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE)); break;
case EVENT_GET_ICC_STATUS_DONE: //UICC状态变化,获取UICC状态返回处理 AsyncResult ar = (AsyncResult)msg.obj; onGetIccCardStatusDone(ar); break; } }

 

UICC Card处理状态变化:

private synchronized void onGetIccCardStatusDone(AsyncResult ar) { //返回的数据结构IccCardStatus
        IccCardStatus status = (IccCardStatus)ar.result; //更新Uicc Card状态 ,若UiccCard未创建则新创建 //新创建也是一样调用UiccCard@update
        if (mUiccCard == null) { //Create new card
            mUiccCard = new UiccCard(mContext, mCi, status); } else { //Update already existing card
 mUiccCard.update(mContext, mCi , status); } }

 

UICC Card状态更新:

public void update(Context c, CommandsInterface ci, IccCardStatus ics) { synchronized (mLock) { mCardState = ics.mCardState; mUniversalPinState = ics.mUniversalPinState; //update applications UiccApplications构造则新创建 //新创建跟update流程一致
            for ( int i = 0; i < mUiccApplications.length; i++) { if (mUiccApplications[i] == null) { //Create newly added Applications
                    if (i < ics.mApplications.length) { mUiccApplications[i] = new UiccCardApplication(this, ics.mApplications[i], mContext, mCi); } } else if (i >= ics.mApplications.length) { //Delete removed applications
 mUiccApplications[i].dispose(); mUiccApplications[i] = null; } else { //Update the rest
 mUiccApplications[i].update(ics.mApplications[i], mContext, mCi); } } //STK相关
 createAndUpdateCatService(); } }

 

Uicc Applications更新:

void update (IccCardApplicationStatus as, Context c, CommandsInterface ci) { synchronized (mLock) { //更新type state pin ……
            AppType oldAppType = mAppType; AppState oldAppState = mAppState; mAppType = as.app_type; mAppState = as.app_state; …… //APP Type变化更新
            if (mAppType != oldAppType) { if (mIccFh != null) { mIccFh.dispose();} if (mIccRecords != null) { mIccRecords.dispose();} mIccFh = createIccFileHandler(as.app_type); mIccRecords = createIccRecords(as.app_type, c, ci); } //APP State变化更新
            if (mAppState != oldAppState) { // If the app state turns to APPSTATE_READY, then query FDN status, //as it might have failed in earlier attempt.
                if (mAppState == AppState.APPSTATE_READY) { //FDN查询
 queryFdn(); //PIN查询
 queryPin1State(); } //PIN状态通知
                notifyPinLockedRegistrantsIfNeeded(null); //UICC Ready否状态通知
                notifyReadyRegistrantsIfNeeded(null); } } }

这里会根据UICC的状态继续下一步的操作: 

  如果UICC需要PIN解锁,则会发出需要Pin码锁通知;进行UICC pin码输入解锁,然后状态变化,

    继续更新UICC Card,Uicc Applications直到UICC状态Ready;

  如果UICC已经ready,则发出UICC Ready通知;

状态更新流程如下:

            UICC 实现框架和数据读写_第3张图片

3 UICC数据读取过程

  发出UICC Ready的通知是在UiccApplications中,

  在接收到UICC Ready的通知后,就可以进行UICC中相关数据的读写;

  这个有在IccRecords类中进行,以SimRecors为例:

public SIMRecords(UiccCardApplication app, Context c, CommandsInterface ci) { super(app, c, ci); //电话号码 
        adnCache = new AdnRecordCache(mFh); //监听UiccApplications 发出Sim Ready通知
        mParentApp.registerForReady(this, EVENT_APP_READY, null); } 

 

SIMRecords消息处理:

    public void handleMessage(Message msg) { switch (msg.what) { case EVENT_APP_READY: onReady(); break; //IO events 通过IccFileHandler数据读取SIM数据,返回结果处理
            case EVENT_GET_IMSI_DONE: …… break; case EVENT_GET_MBI_DONE: …… break; case EVENT_GET_AD_DONE: case EVENT_GET_SPN_DONE: break; …… } }

 

监听到SIM Ready消息: 

  public void onReady() { fetchSimRecords(); }
protected void fetchSimRecords() { //通过IccFileHandler向 RIL发送读取数据的消息 mFh.loadEFTransparent(EF_ICCID, obtainMessage(EVENT_GET_ICCID_DONE)); recordsToLoad++; // Record number is subscriber profile mFh.loadEFLinearFixed(EF_MBI, 1, obtainMessage(EVENT_GET_MBI_DONE)); recordsToLoad++; mFh.loadEFTransparent(EF_AD, obtainMessage(EVENT_GET_AD_DONE)); recordsToLoad++; // Record number is subscriber profile mFh.loadEFLinearFixed(EF_MWIS, 1, obtainMessage(EVENT_GET_MWIS_DONE)); recordsToLoad++; …… }

 

IccFileHandler数据读取:

public void loadEFTransparent(int fileid, Message onLoaded) { Message response = obtainMessage(EVENT_GET_BINARY_SIZE_DONE, fileid, 0, onLoaded); mCi.iccIOForApp(COMMAND_GET_RESPONSE, fileid, getEFPath(fileid), 0, 0, GET_RESPONSE_EF_SIZE_BYTES, null, null, mAid, response); }

 

loadEFTransparent和loadEFLinearFixed,就是针对不同的文件格式,

实际都是调用RIL_JAVA:

    void iccIOForApp (int command, int fileid, String path, int p1, int p2, int p3, String data, String pin2, String aid,           Message result) { …… }  

RIL_iccIOForApp函数的参数含义:

  command:读写更新……操作命令

    final int COMMAND_READ_BINARY = 0xb0;

       final int COMMAND_UPDATE_BINARY = 0xd6;

    final int COMMAND_READ_RECORD = 0xb2;

    final int COMMAND_UPDATE_RECORD = 0xdc;

    final int COMMAND_SEEK = 0xa2;

    final int COMMAND_GET_RESPONSE = 0xc0;

    ……

  fileid:数据字段在SIM文件系统中的地址 :例如Plmn:0x6F30

  path:     此数据字段上级所有目录地址:

    例如Plmn的Path:MF + DF_GSM = "0x3F000x7F20"

    地址字段都需要根据UICC文件系统结构,地址决定

  p1:

  p2:

  p3:

  data:

  pin2:

  aid:  由UICC传递上来的

  result:回调Message

从3GPP SIM相关协议可以看到,P1,P2,P3等这些参数的含义:

  S:stands for data sent by the ME

  R:stands for data received by the ME

  Offset is coded on 2 bytes where P1 gives thehigh order byte and P2 the low order byte.

  '00 00' means no offset and reading/updating starts with the first byte

  '00 01' means that reading/updating starts with the second byte.

        UICC 实现框架和数据读写_第4张图片

你可能感兴趣的:(UICC 实现框架和数据读写)