UICC 实现框架和数据读写

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

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

一 Sim文件系统数据结构

1 sim卡文件系统

  SIM card file system structure:

            

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\

基本框架类得结构图:

            

        

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

  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通知;

状态更新流程如下:

            

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.

        

posted @ 2013-05-07 19:16  __Shadow  阅读(6214)  评论(0编辑  收藏  举报