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.

        


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM