1. 程式人生 > >查詢SIM卡聯絡人——原始碼流程簡介

查詢SIM卡聯絡人——原始碼流程簡介

查詢SIM卡聯絡人

查詢SIM卡中的聯絡人使用的方法為 query( ) 方法,與操作資料庫中的查詢方法極其類似,使用方式與如下類似:

getContentResolver().query("content://icc/adn/subId/1", null, null, null, null);

那麼我們就來探究一下該方法的流程。

流程

  • IccProvider.java —— query( )
@Override
public Cursor query(Uri url, String[] projection, String selection,
       String[] selectionArgs, String sort) {
    switch
(URL_MATCHER.match(url)) { case ADN: return loadFromEf(IccConstants.EF_ADN, mSubscriptionManager.getDefaultSubId()); case ADN_SUB: return loadFromEf(IccConstants.EF_ADN, getRequestSubId(url)); //……省略其它程式碼……// } }

從 IccProvider 中的 query 方法開始。我們首先匹配到的是 ADN 的情況,並且由於是雙卡,所以下一步需要執行第二種情況的 loadFromEf 方法。該方法中可以看到 IccConstants.EF_ADN 值為6F3A,這就是SIM卡上的地址。

  • IccProvider.java —— loadFromEf( )
private MatrixCursor loadFromEf(int efType, int subId) {
    List<AdnRecord> adnRecords = null;
    try {
        IIccPhoneBook iccIpb = getIccPhbService();
        if (iccIpb != null) {
            adnRecords = iccIpb.getAdnRecordsInEfForSubscriber(subId, efType);
        }
    } 
    //……省略其它程式碼……//
return new MatrixCursor(ADDRESS_BOOK_COLUMN_NAMES); }

可以看到接下來就是 IIccPhoneBook 中的 getAdnRecordsInEfForSubscriber 方法。實際上接下來執行的是 IccPhoneBookManager.java 中的 getAdnRecordInEf 方法,其中經過了 IIccPhoneBook.java –> UiccPhoneBookController.java –> IccPhoneBookManager.java 的跳轉與轉換,使用了 Binder 和 AIDL 實現跨程序通訊以及使用了代理模式(Proxy Pattern)控制訪問,如果不瞭解這兩方面的知識,就會有點看不懂程式碼的意圖與具體實現的內涵,關於這兩點,在文章最後進行簡單的描述。

  • IccPhoneBookManager.java —— getAdnRecordsInEf( )
public synchronized List<AdnRecord> getAdnRecordsInEf(int efid) {
    //……省略其它程式碼……//
    efid = updateEfForIccType(efid);// Check if we are trying to read ADN records
    //……省略其它程式碼……//
    synchronized (mLock) {
        checkThread();
        AtomicBoolean status = new AtomicBoolean(false);
        Message response = mBaseHandler.obtainMessage(EVENT_LOAD_DONE, status);
        if (mAdnCache != null) {
            mAdnCache.requestLoadAllAdnLike(efid, mAdnCache.extensionEfForEf(efid), response);
            waitForResult(status);
        } else {
            loge("Failure while trying to load from SIM due to uninitialised adncache");
        }
    }
    return mRecords;
}

在該方法中,首先先檢查 efid 是否是 IccConstants.EF_ADN,判斷一下下面的 efid 是使用 IccConstants.EF_ADN 還是 IccConstants.EF_PBR。然後就是執行 requestLoadAllAdnLike 方法,可以看到從該方法開始,使用了 Message 來通知獲取結果。

  • AdnRecordCache.java —— requestLoadAllAdnLike( )
 public void requestLoadAllAdnLike (int efid, int extensionEf, Message response) {
        ArrayList<Message> waiters;
        ArrayList<AdnRecord> result;
        if (efid == EF_PBR) {
            result = mUsimPhoneBookManager.loadEfFilesFromUsim();
        } else {
            result = getRecordsIfLoaded(efid);
        }

        // Have we already loaded this efid?
        if (result != null) {
            if (response != null) {
                AsyncResult.forMessage(response).result = result;
                response.sendToTarget();
            }

            return;
        }
    //……省略其它程式碼……//
    }

這裡我們需要看的是 loadEfFilesFromUsim 方法,可以看到先對各種情況進行判斷,如果已經存在紀錄,剛只需要 refresh 一下,否則迴圈讀取。

  • UsimPhoneBookManager.java —— loadEfFilesFromUsim( )
 public ArrayList<AdnRecord> loadEfFilesFromUsim() {
    //……省略其它程式碼……//
    int numRecs = mPbrFile.mFileIds.size();
    // read adn by CPBR, not by read record from EF , So we needn't read
    // for every pbr record.
    if (mFh instanceof CsimFileHandler) { //fzl add for Uicc card start
        // fzl comment: UICC card need CRSM, not CPBR. and need read for every pbr record.
        for (int i = 0; i < numRecs; i++) {
            Rlog.d(LOG_TAG, "readAdnFileAndWaitForUicc: numRecs = " + i);
            readAdnFileAndWaitForUICC(i);
        }
    } else {
        readAdnFileAndWait(0);
    }  //fzl add for Uicc card end
    //……省略其它程式碼……//
    mAasForAnrRec.clear();
    for (int i = 0; i < numRecs; i++) {
        readAASFileAndWait(i);
        readSneFileAndWait(i);
        readAnrFileAndWait(i);
        readEmailFileAndWait(i);
    }
    readGrpIdsAndWait();
    // All EF files are loaded, post the response.

    return mPhoneBookRecords;
}

這個方法的再接著往下跳轉可以看到 RIL.java 檔案裡的 iccIO 方法,在 IO 方法中可以找到一個 TAG,根據這個 TAG 可以在 Reference-ril.c 檔案中找到處理這個 Case 的分支,因為對於這種 IO 指令不瞭解,大概就只能看個熱鬧了。

AIDL跨程序通訊

loadFromEf( ) 方法中呼叫了 IIccPhoneBook.java 中的方法,事實上,這是用了 AIDL 方式生成的類。

通過新增 IIccPhoneBook.aidl 檔案,描述了方法介面,然後編譯生成了 IIccPhoneBook.java 檔案,然後 UiccPhoneBookController.java 繼承於 IIccPhoneBook.Stub。一般而言,繼承於 Stub 的稱之為 Binder。

這種方式可以實現跨程序通訊,在 Android 中的 Binder 機制是一個龐大的體系模組,而 Android 考慮到了邏輯的複雜性,提供了一個簡便的方式即 AIDL (Android Interface Description Language)來生成所需要的檔案。

代理模式

代理模式適用於無法或不想直接訪問某個物件或者訪問某個物件有困難時可以通過一個代理物件來間接訪問。

在這裡我們可以看一下原始碼中是怎麼實現代理模式的。
首先定義一個介面 Phone.java

public interface Phone {
    // ……省略程式碼
}   

然後 PhoneBase.java 實現介面

public abstract class PhoneBase extends Handler implements Phone {
    // ……省略程式碼 
}

然後幾種不同制式的SIM卡手機繼承了 PhoneBase.java。比如 CDMAPhone.java 、GSMPhone.java 等。
最後定義一個代理類來整合繼承於 PhoneBase.java 的類。

public class PhoneProxy extends Handler implements Phone {
    // ……省略程式碼 
    private IccPhoneBookInterfaceManagerProxy mIccPhoneBookInterfaceManagerProxy;
    // ……省略程式碼 
    public PhoneProxy(PhoneBase phone) {
        mActivePhone = phone;
        mResetModemOnRadioTechnologyChange = SystemProperties.getBoolean(
                TelephonyProperties.PROPERTY_RESET_ON_RADIO_TECH_CHANGE, false);
        mIccPhoneBookInterfaceManagerProxy = new IccPhoneBookInterfaceManagerProxy(
                phone.getIccPhoneBookInterfaceManager());
        mPhoneSubInfoProxy = new PhoneSubInfoProxy(phone.getPhoneSubInfo());
        // ……省略程式碼 
    }
}

以上三個類的構造是代理模式常用的實現:一個公共介面、一個被代理類、一個代理類。

可以看到,在 PhoneProxy 代理類中還包含了其他的代理類,比如流程中所用的 IccPhoneBookInterfaceManagerProxy。事實上 UiccPhoneBookController.java 就是通過 IccPhoneBookInterfaceManagerProxy 來訪問 IccPhoneBookInterfaceManager 中的 getAdnRecordsInEf( ) 方法,而在這個方法中:

public synchronized List<AdnRecord> getAdnRecordsInEf(int efid) {

    if (mPhone.getContext().checkCallingOrSelfPermission(
            android.Manifest.permission.READ_CONTACTS)
            != PackageManager.PERMISSION_GRANTED) {
        throw new SecurityException(
                "Requires android.permission.READ_CONTACTS permission");
    }
    //……省略其它程式碼……//
            mAdnCache.requestLoadAllAdnLike(efid, mAdnCache.extensionEfForEf(efid), response);
   //……省略其它程式碼……//         
    return mRecords;
}

可以看到除了業務邏輯之外還呼叫了 PhoneBase 的方法來檢查許可權問題。

由此可以看出代理模式的優點和其使用方式,通過代理來控制對原始物件的訪問,而在訪問原始物件時執行一些自己的附加操作,實現了代理類與被代理類之間的解耦,符合面向物件原則。

相關推薦

查詢SIM聯絡人——原始碼流程簡介

查詢SIM卡聯絡人 查詢SIM卡中的聯絡人使用的方法為 query( ) 方法,與操作資料庫中的查詢方法極其類似,使用方式與如下類似: getContentResolver().query("content://icc/adn/subId/1", nul

android中對sim聯絡人的增刪改查以及監聽sim聯絡資料的改變

sim卡聯絡人的增刪改查主要是通過ContentProvider來進行操作的,在android中對sim卡聯絡人操作的provider是定義在IccProvider.java這個類中的,這個類位於android原始碼的位置frameworks/base/telephony/

SIM --- 聯絡人增加/刪除/更新 分析

3.2 更新 insert/ delete/ update 三個方法執行的流程幾乎完全相同,以update方法為例進行論述。 update方法主要邏輯如下, 1,根據不同型別為引數賦值, case ADN: efType = IccConstants.EF_ADN;

資料庫中同步SIM聯絡人

4.2 同步聯絡人 當重新插入SIM卡時, SimContactsService 的onCreate方法內的匿名Handler的handleMessage方法對應的處理如下, case MSG_SIM_REFRESH: ••• if (mSimState[sub] == S

android讀取sim聯絡人

SIM的provider是IccProvider。既然是provider,就和操作Contact的provider類似的,只是有一些微小差別。 IccProvider的Uri是content://icc/and,可以通過這個Uri來操作SIM卡。當然,使用時需要轉換為an

獲取android手機了通訊錄和sim聯絡人

private ArrayList<SamContact> getAllContacts(){ArrayList<SamContact> arrayList = new ArrayList<SamContact>();//獲取本機聯絡人C

sim資料互動流程資料

/**  * 本文件記錄了與UIM卡互動的  * 詳細過程,整個的流程是基於高通平臺來進行的,  * 參考了GSM 11.11 及電信UIM卡技術要求規範。  *  */ // 高通軟體指令執行序列 [1]:UIM_POWER_UP_ST              -(UI

資料庫中刪除SIM聯絡人

4,SIM卡聯絡人 Contacts2.db資料庫中聯絡人其實包括2部分,手機上面的聯絡人以及SIM卡中的聯絡人。 當然, SIM卡中的聯絡人是儲存在單獨的資料庫中,其對應的Provider為IccProvider,在packages\services\Telephony

Android SIM聯絡人操作總結

--- by Ruiming.Lv 在Android中,對SIM中的聯絡人進行操作,需要通過系統提供的Content Provider進行,該Provider就是Telphony中的IccProvider。但是,由於SIM卡儲存的一些特性,在操作上,與ContactsP

Android原始碼----操作SIM聯絡人的影響(一)

前言 SIM(Subscriber Identification Module )卡:也稱為使用者身份識別卡、智慧卡,GSM數字行動電話機必須裝上此卡方能使用。SIM卡有很多功能,其中有一項是儲存使用者相關資料,這些資料主要分為五類:第一類是固定存放的資料,這類

Android---操作SIM聯絡人的影響(二)

前言 今天整理一下關於在Contacts中通過Setting進行Import/Export SIM卡聯絡人的過程。同樣,原始碼分析基於Android8高通平臺。 Import過程 Import過程是指將SIM卡中的聯絡人匯入(copy)到本地賬號中,需要強調的一

SIM上的聯絡人匯入Android手機中

新購買Android手機的朋友第一件事情可能就是需要將SIM卡上的聯絡人匯入到手機中,但是許多朋友卻不知道如何將聯絡人從SIM卡匯入到新購買的Android手機上,為此在這裡我們有必要給大家介紹下如何快速將SIM卡聯絡人匯入到手機中。 對於許多朋友的提問,我們並無

Android工具類—— android 從SIM獲取聯絡人資訊

<span style="font-size:18px;color:#3333ff;">01./**   02.     * 從SIM卡中讀取聯絡人資訊   03.     * @r

SIM中獲取聯絡人資訊

Uri uri = Uri.parse("content://icc/adn"); String[] projection = {"_id", "name", "number"}; Cursor cursor = managedQuery(uri, projection,

信用評分(A/B/C)的模型簡介及開發流程|乾貨

如今在銀行、消費金融公司等各種貸款業務機構,普遍使用信用評分,對客戶實行打分制,以期對客戶有一個優質與否的評判。但是不是所有人都知道信用評分卡還分A,B,C卡三類! A卡(Application score card)申請評分卡 B卡(Behavior score car

DNS查詢流程簡介

        DNS(domain name system),讀者們或多或少都聽過,就是可以將域名轉換給IP的一個系統。使得我們只需記住域名而非IP就能訪問某個網站。當我們在瀏覽器裡面輸入一個網址時,瀏覽器會向本地DNS伺服器發出查詢請求,本地DNS伺服器會把網

Android 4.4Telephony流程分析SIM開機時的資料載入

本文程式碼以MTK平臺Android 4.4為分析物件,與Google原生AOSP有些許差異,請讀者知悉。 本文主要介紹sim卡資料的讀取過程,當射頻狀態處於準備狀態時,此時UiccCardApplication應處於AppState.APPSTATE_READ

linux啟動流程簡介

機器 配置文件 互聯網 local 相關信息 ade 通過 在操作 mbr 我們都知道,由於linux的穩定性,通常被作為服務器系統,要想稱為一個PHP的高手,linux是必修之課。那麽linux系統從開機到啟動,中間到底都發生了什麽?本文來簡單探討一下中間的神秘過程。 1

MICRO SIM(SIM)尺寸圖及剪圖解

pan avi watermark water http 輪廓 ack 壁紙 img 如今使用MICRO SIM卡的手機越來越多。近期剛剛買了一個手機到手才發現尼馬使用的是MICRO SIM卡。再去買剪卡器吧,十幾二十塊用一次就廢了,去營業廳吧。又比較遠,懶的出門。怎麽

微信小程序券接入流程,酷客多為你支招

酷客多小程序 小程序 微信小程序 酷客多 1.必須是已經認證的小程序(需300元/年認證費)2.必須是已經認證的微信公眾號(需300元/年認證費)必須在微信公眾平臺開通卡券功能3.需要在微信開放平臺綁定公眾號AppId與小程序AppId(開發者資質認證300元/年)在開放平臺綁定小程序和微信公