Android中UICC 實現框架和數據讀寫(SIM,USIM,UIM)

現有的手機中使用的卡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:Inpidual recZ喎?/kf/ware/vc/” target=”_blank” class=”keylink”>vcmRzIChvciBmaWxlcykgYXJlIGtub3duIGFzIEVsZW1lbnRhcnkgZmlsZXMuPC9wPgo8cD4gPC9wPgo8cD6hoaGhQWxsIGZpbGVzIGFyZSBpZGVudGlmaWVkIGFzIGFuIGFkZHJlc3MgKGEgRFdPUkQgdmFsdWUpLCByYXRoZXIgdGhhbiBhIGZpbGVuYW1lLjwvcD4KPHA+IDwvcD4KPGgyPjMgzsS8/sDg0M08L2gyPgo8cD48c3Ryb25nPlRyYW5zcGFyZW50PC9zdHJvbmc+o7o8L3A+CjxwPqGhoaHNuMP3veG5ubXERUYg08nSu7j219a92tDywdDX6bPJoaO1sc7EvP62wbvyuPzQwqOs19a92tDywdC77ravyseyztXVz+C21LXYPC9wPgo8cD7Wt6OoT0ZGU0VUo6m9+NDQtcSjrM/gttS12Na3v8mx7cq+s/bG8Mq8stnX97XEtdjWt6Oo08PX1r3ase3KvqOpus22wbP2oaK4/NDCtcQ8L3A+CjxwPtfWvdrK/aGjzbjD90VGILXEtdrSu7j219a92tPQ0ru49s/gttS12Na3oa4wMDAwoa+ho0VGINb3zOW1xMr9vt2zpLbI1NpFRiC1xM7EvP48L3A+CjxwPs231tChozwvcD4KPHA+PHN0cm9uZz5MaW5lYXIgRml4ZWQgRmlsZaO6PC9zdHJvbmc+PC9wPgo8cD6hoaGhz9/Q1LnMtqhFRiDOxLz+08nSu7j2vMfCvLOktsi5zLaotcS8x8K80PLB0Nfps8mho7Xa0ru49rzHwry8x8K8usXKxzGho7zHwrw8L3A+CjxwPrXEs6S2yLrNvMfCvLOktsjT67zHwry49sr9tcSzy7v9tOa3xdTaRUYgzsS8/s231tChozwvcD4KPHA+PHN0cm9uZz5DeWNsaWOjujwvc3Ryb25nPjwvcD4KPHA+oaGhodGtu7fOxLz+08PT2tLUyrG85Muz0PK05rSitcS8x8K8o6y1scv509C1xLzHwry/1bzktrzVvNPDyrGjrNDCtcS05rSiyv2+3b2rPC9wPgo8cD64srjH1+6+ybXE0MXPoqGjPC9wPgo8cD6hoaGht8POyrK7zay1xM7EvP7A4NDNo6zKudPDtcS3vcq90rK9q7K7zayho7bU09pVU0lNo6xSVUlNtci/qLv5sb7OxLz+veG5udOmuMPKx9K71sK1xKOsvtayv7TmtKLQxc+itcS1pdSqo6zOu9bDsrvNrLb40tGhozwvcD4KPHA+IDwvcD4KPGgxPrb+IFVJQ0O/qMr9vt22wdC0PC9oMT4KPGgyPjEgVUlDQ7/yvNzA4L3hubk8L2gyPgo8cD6hoaGhyta7+tDo0qq52NeitcRVSUNDsPzAqKO6yv2+3bbB0LS8x8K8o6zXtMysseS7r7ncwO2ju0FuZHJvaWTW0MrHudzA7VVJQ0O1xL/yvNy0+sLrzrvT2qO6PC9wPgo8cD5mcmFtZXdvcmtzXG9wdFx0ZWxlcGhvbnlcc3JjXGphdmFcY29tXGFuZHJvaWRcaW50ZXJuYWxcdGVsZXBob255XHVpY2NcPC9wPgo8cD48c3Ryb25nPrv5sb6/8rzcwOC1w73hubnNvKO6PC9zdHJvbmc+PC9wPgo8cD6hoaGhoaGhoSAgICAgICAgPGltZyBzcmM9″/uploadfile/Collfiles/20140111/2014011114104238.jpg” alt=”\”>

對於不同的卡會有不同的類與之對應,這些類的作用:

  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) {
                    //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.

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *