Android 源碼開發系列(二)Android SIM/USIM

來源:互聯網
上載者:User

   

      隨著手機的普及,大家從非智能機到智能機的轉變,從沒有作業系統的定製機到智能手機,但唯一沒有變的是,手機中的SIM,今天我們就來談談手機中SIM卡相關的內容。在日常生活中,SIM卡就是一張很小的卡片,但這個卡片上卻儲存了很重要的資訊。  同樣,Android作為一個智能手機作業系統,也對SIM卡的讀取有相關的操作。下面就以Android2.2的SIM卡讀寫過程進行講述。

     在上次部落格中,有講述STK,大家可以點這個連結進行查看。android STK 實現原理 (一)。STK與SIM卡是緊密相關的,講到STK,不可能不說到SIM卡,下面就回到正題。

    在Android的源碼中,SIM卡相關的操作,都封裝在framework中,

源碼所在的目錄

 

 

 

   這個檔案夾下,儲存了所有與手機通訊業務相關的類檔案,其中也包括了SIM,STK,CALL, PS資料業務。在上面的圖片中,大家可以看到GSM和CDMA兩個檔案夾,這也是SIM卡相關的,如果插入的是CDMA卡片,就使用CDMA檔案夾中的源碼,如果是2G SIM卡,或是3G 聯通卡(即GSM/WCDMA)都是使用GSM檔案夾。當開啟GSM檔案夾,可以看到有一個STK 檔案夾,裡面裝的就是上面那個連結裡面的源碼。如果是2G SIM卡,或是3G 聯通卡(即GSM/WCDMA)都是使用GSM檔案夾。當開啟GSM檔案夾,可以看到有一個STK
檔案夾,裡面裝的就是上面那個連結裡面的源碼。

和SIM卡相關的類主要有以下幾個,

IccConstants  (裡面記錄很多的常量,主要用來儲存某個欄位在SIM卡上的位置是什麼,比如ADN(sim卡上的電話本),6F3A,  FDN(固定拔號 6F3B)),

IccCardStatus(記錄SIM卡的狀態,如ABSENT, READY,UNKNOW,ETC),

IccFileHandler(這個是用來SIM卡上的RECORD讀完後,要處理什麼事情),

IccRecords(SIM卡上的檔案內容,每一個欄位,一個RECORD),

IccProvider(手機上的資料庫,讀出來的資料全放這),

IccUtils(裡面一般全是靜態方法,主要用來碼制轉換),

IccSmsInterfaceManager,IccCard(這個是一個抽象類別,會根據上面手機的制式,自動起一個SIMCARD 或者RUIMCARD).

下面就以GSM為例說下讀取的過程,

在GSM中就對應上面說的這些會有自己的類,如

SimCard,

SIMRecords,

SimPhoneBookInterfaceManager,

 

1,手機啟動時,

根據SIM卡的類型,進入SIMRecords, 開始探測SIM卡的狀態,因為,有些SIM卡會設定有數字 PIN 碼,如果SIM卡有數字 PIN 碼的話,手機會彈出輸入數字 PIN 碼的框,等待使用者進行解碼,注意,這個時候,如果數字 PIN 碼如果沒有解的話,手機是不會去讀SIM卡的,因為,讀SIM卡時,必須通過PIN才能去讀,只有一些比較特殊的欄位,可以不用,比如ECC 也就是緊急電話號碼(一般存在卡上,電訊廠商定製的)。同時,這數字 PIN 碼未解的情況,手機中SIM卡的狀態也是PIN_REQURIED_BLOCK,

2,當解完數字 PIN 碼,或是手機沒有設定數字 PIN 碼,這時,手機的會探測到SIM是READY的狀態,手機只有檢測到SIM READY,才會發出讀卡的請求。

[java]
view plaincopy
  1. case EVENT_SIM_READY:  
  2.                 onSimReady();  
  3.             break;  
  4.   
  5.     private void onSimReady() {  
  6.         /* broadcast intent SIM_READY here so that we can make sure 
  7.           READY is sent before IMSI ready 
  8.         */  
  9.         ((GSMPhone) phone).mSimCard.broadcastIccStateChangedIntent(  
  10.                 SimCard.INTENT_VALUE_ICC_READY, null);  
  11.   
  12.         fetchSimRecords();  
  13. }  

PIN驗證通過,會發出一個廣播,通知其它的手機應用,SIM卡好了。

[java]
view plaincopy
  1. private void fetchSimRecords() {  
  2.         recordsRequested = true;  
  3.         IccFileHandler iccFh = phone.getIccFileHandler();  
  4.   
  5.         Log.v(LOG_TAG, "SIMRecords:fetchSimRecords " + recordsToLoad);  
  6.   
  7.         phone.mCM.getIMSI(obtainMessage(EVENT_GET_IMSI_DONE));  
  8.         recordsToLoad++;  
  9.   
  10.         iccFh.loadEFTransparent(EF_ICCID, obtainMessage(EVENT_GET_ICCID_DONE));  
  11.         recordsToLoad++;  
  12.   
  13.         // FIXME should examine EF[MSISDN]'s capability configuration  
  14.         // to determine which is the voice/data/fax line  
  15.         new AdnRecordLoader(phone).loadFromEF(EF_MSISDN, EF_EXT1, 1,  
  16.                     obtainMessage(EVENT_GET_MSISDN_DONE));  
  17.         recordsToLoad++;  
  18.   
  19.         // Record number is subscriber profile  
  20.         iccFh.loadEFLinearFixed(EF_MBI, 1, obtainMessage(EVENT_GET_MBI_DONE));  
  21.         recordsToLoad++;  
  22.   
  23.         iccFh.loadEFTransparent(EF_AD, obtainMessage(EVENT_GET_AD_DONE));  
  24.         recordsToLoad++;  
  25.   
  26.         // Record number is subscriber profile  
  27.         iccFh.loadEFLinearFixed(EF_MWIS, 1, obtainMessage(EVENT_GET_MWIS_DONE));  
  28.         recordsToLoad++;  
  29.   
  30.   
  31.         // Also load CPHS-style voice mail indicator, which stores  
  32.         // the same info as EF[MWIS]. If both exist, both are updated  
  33.         // but the EF[MWIS] data is preferred  
  34.         // Please note this must be loaded after EF[MWIS]  
  35.         iccFh.loadEFTransparent(  
  36.                 EF_VOICE_MAIL_INDICATOR_CPHS,  
  37.                 obtainMessage(EVENT_GET_VOICE_MAIL_INDICATOR_CPHS_DONE));  
  38.         recordsToLoad++;  
  39.   
  40.         // Same goes for Call Forward Status indicator: fetch both  
  41.         // EF[CFIS] and CPHS-EF, with EF[CFIS] preferred.  
  42.         iccFh.loadEFLinearFixed(EF_CFIS, 1, obtainMessage(EVENT_GET_CFIS_DONE));  
  43.         recordsToLoad++;  
  44.         iccFh.loadEFTransparent(EF_CFF_CPHS, obtainMessage(EVENT_GET_CFF_DONE));  
  45.         recordsToLoad++;  
  46.   
  47.   
  48.         getSpnFsm(true, null);  
  49.   
  50.         iccFh.loadEFTransparent(EF_SPDI, obtainMessage(EVENT_GET_SPDI_DONE));  
  51.         recordsToLoad++;  
  52.   
  53.         iccFh.loadEFLinearFixed(EF_PNN, 1, obtainMessage(EVENT_GET_PNN_DONE));  
  54.         recordsToLoad++;  
  55.   
  56.         iccFh.loadEFTransparent(EF_SST, obtainMessage(EVENT_GET_SST_DONE));  
  57.         recordsToLoad++;  
  58.   
  59.         iccFh.loadEFTransparent(EF_INFO_CPHS, obtainMessage(EVENT_GET_INFO_CPHS_DONE));  
  60.         recordsToLoad++;  
  61.   
  62.         // XXX should seek instead of examining them all  
  63.         if (false) { // XXX  
  64.             iccFh.loadEFLinearFixedAll(EF_SMS, obtainMessage(EVENT_GET_ALL_SMS_DONE));  
  65.             recordsToLoad++;  
  66.         }  
  67.   
  68.         if (CRASH_RIL) {  
  69.             String sms = "0107912160130310f20404d0110041007030208054832b0120"  
  70.                          + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"  
  71.                          + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"  
  72.                          + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"  
  73.                          + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"  
  74.                          + "ffffffffffffffffffffffffffffff";  
  75.             byte[] ba = IccUtils.hexStringToBytes(sms);  
  76.   
  77.             iccFh.updateEFLinearFixed(EF_SMS, 1, ba, null,  
  78.                             obtainMessage(EVENT_MARK_SMS_READ_DONE, 1));  
  79.         }  
  80.     }  

這裡,手機開始讀卡第一個是

IMSI(International Mobile SubscriberIdentification Number)主要用來尋找電訊廠商的網路,裡面有MCC,MNC,

ICCID(Integrate circuit card identity)唯一標識一個移動使用者。

然後,大家可以看到有很多類似這樣的函數調用iccFh.loadEFTransparent,這個就是調用IccFileHandler,讀取SIM卡欄位

[java]
view plaincopy
  1. public void loadEFTransparent(int fileid, Message onLoaded) {  
  2.         Message response = obtainMessage(EVENT_GET_BINARY_SIZE_DONE,  
  3.                         fileid, 0, onLoaded);  
  4.   
  5.         phone.mCM.iccIO(COMMAND_GET_RESPONSE, fileid, getEFPath(fileid),  
  6.                         0, 0, GET_RESPONSE_EF_SIZE_BYTES, null, null, response);  
  7.     }  

大家注意到phone.mCM.iccIO,這個東東就是我們的RIL.JAVA, 向低層的MODEM 發送一個讀取SIM卡的命令,在RIL.JAVA 中。Fileid 是欄位的地址,如上面說的AND(在這為6F3A),FDN(在這為6F3B).

3.當低層的MODEM讀到欄位結果後,會有一個返回結果,由於發送讀取請求時,有一個事件資訊EVENT_GET_BINARY_SIZE_DONE,當有返回時,會直接交給IccFileHandler,然後由IccFileHandler轉寄給SIMRecords,最後進行處理該欄位讀完後應該執行的操作。由RIL.JAVA通知IccFileHandler,處理如下

[java]
view plaincopy
  1. case EVENT_GET_BINARY_SIZE_DONE:  
  2.                ar = (AsyncResult)msg.obj;  
  3.                response = (Message) ar.userObj;  
  4.                result = (IccIoResult) ar.result;  
  5.   
  6.                if (ar.exception != null) {  
  7.                    sendResult(response, null, ar.exception);  
  8.                    break;  
  9.                }  
  10.   
  11.                iccException = result.getException();  
  12.   
  13.                if (iccException != null) {  
  14.                    sendResult(response, null, iccException);  
  15.                    break;  
  16.                }  
  17.   
  18.                data = result.payload;  
  19.   
  20.                fileid = msg.arg1;  
  21.   
  22.                if (TYPE_EF != data[RESPONSE_DATA_FILE_TYPE]) {  
  23.                    throw new IccFileTypeMismatch();  
  24.                }  
  25.   
  26.                if (EF_TYPE_TRANSPARENT != data[RESPONSE_DATA_STRUCTURE]) {  
  27.                    throw new IccFileTypeMismatch();  
  28.                }  
  29.   
  30.                size = ((data[RESPONSE_DATA_FILE_SIZE_1] & 0xff) << 8)  
  31.                       + (data[RESPONSE_DATA_FILE_SIZE_2] & 0xff);  
  32.   
  33.                phone.mCM.iccIO(COMMAND_READ_BINARY, fileid, getEFPath(fileid),  
  34.                                0, 0, size, null, null,  
  35.                                obtainMessage(EVENT_READ_BINARY_DONE,  
  36.                                              fileid, 0, response));  
  37.            break;  

回到SIMRecords,處理ICCID讀完後相關操作,代碼如下:

[java]
view plaincopy
  1. case EVENT_GET_ICCID_DONE:  
  2.                 isRecordLoadResponse = true;  
  3.   
  4.                 ar = (AsyncResult)msg.obj;  
  5.                 data = (byte[])ar.result;  
  6.   
  7.                 if (ar.exception != null) {  
  8.                     break;  
  9.                 }  
  10.   
  11.                 iccid = IccUtils.bcdToString(data, 0, data.length);  
  12.   
  13.                 Log.d(LOG_TAG, "iccid: " + iccid);  
  14.   
  15.             break;  

 

到此,一個完整的SIM卡讀取過程就完成了。

PS:有可能有人會問,為什麼有時候是

iccFh.loadEFTransparent

有時候是

iccFh.loadEFLinearFixed

這主要是跟所要讀取EF的類型有關係,SIM卡上的檔案類型有Elementary File, Delicated File, Cyclic File,其中EF又分為Linear fixed EF,Transparent EF,Cyclic EF,所以讀取的方式是不一樣的,可能參考3GPP 11.11,  3GPP 51.011.

OK, 累了,有什麼問題,可以在下面問,

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.