SIM卡 --- 联系人查询过程分析

Posted Achillisjack

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SIM卡 --- 联系人查询过程分析相关的知识,希望对你有一定的参考价值。

6.3 联系人操作

在前面已经论述过, SIM卡中的联系人是保存在单独的数据库中,其对应的Provider为IccProvider,在packages\\services\\Telephony 路径下,也就是phone进程中。并且,增删改查直接看jar包中的IccProvider类就可以了, IccProvider路径如下,

frameworks/opt/telephony/src/java/com/android/internal/telephony/IccProvider.java

IccProvider中对应的4个增删改查的方法分别对应, query/ insert/ delete/ update 方法。

其中insert/ delete/ update 三个方法都是调用updateIccRecordInEf方法实现。

3.1 查询

IccProvider中有3种类型的电话本,分别是ADN/FDN/SDN, FDN/SDN 用的比较少, sim卡上的电话本就是ADN。当然,处理过程也是大同小异,只看AND的处理。

IccProvider的query方法主要逻辑就是根据不同类型分别调用loadFromEf方法进行处理。

对AND的处理如下,

case ADN:  //默认SIM卡
    return loadFromEf(IccConstants.EF_ADN, SubscriptionManager.getDefaultSubId());
case ADN_SUB: // 双卡双待
    return loadFromEf(IccConstants.EF_ADN, getRequestSubId(url));

调用流程图如下,


loadFromEf方法主要逻辑如下,

1,调用UiccPhoneBookController的getAdnRecordsInEfForSubscriber方法进行查询,将结果封装成AdnRecord,

List<AdnRecord> adnRecords = null;
try 
   IIccPhoneBook iccIpb = IIccPhoneBook.Stub.asInterface(
       ServiceManager.getService("simphonebook"));
   if (iccIpb != null) 
       adnRecords = iccIpb.getAdnRecordsInEfForSubscriber(subId, efType);

•••

2,调用loadRecord方法将查询结果封装为MatrixCursor对象,并返回,

if (adnRecords != null) 
   // Load the results
   final int N = adnRecords.size();
   final MatrixCursor cursor = new MatrixCursor(ADDRESS_BOOK_COLUMN_NAMES, N);
   log("adnRecords.size=" + N);
   for (int i = 0; i < N ; i++) 
      loadRecord(adnRecords.get(i), cursor, i);
   
   return cursor;

3,如果查询结果为空,

return new MatrixCursor(ADDRESS_BOOK_COLUMN_NAMES);

主要分为2个部分,分别进行阐述。loadRecord方法很简单,主要逻辑如下,

1,首先获取联系人的信息,

String alphaTag = record.getAlphaTag();
String number = record.getNumber();
String[] anrs =record.getAdditionalNumbers();

2,然后将信息封装在

Object[] contact = new Object[5];
•••
contact[0] = alphaTag;
contact[1] = number;
•••

3,最后将contact封装为MatrixCursor对象,

cursor.addRow(contact);

1.1查询分析

"simphonebook"对应的系统服务为UiccPhoneBookController,UiccPhoneBookController定义如下,

public class UiccPhoneBookController extends IIccPhoneBook.Stub 

构造方法如下,

if (ServiceManager.getService("simphonebook") == null) 
    ServiceManager.addService("simphonebook", this);

mPhone = phone;

getAdnRecordsInEfForSubscriber方法如下,

1,调用getIccPhoneBookInterfaceManagerProxy方法获取IccPhoneBookInterfaceManagerProxy对象,

IccPhoneBookInterfaceManagerProxy iccPbkIntMgrProxy =
    getIccPhoneBookInterfaceManagerProxy(subId);

2,调用IccPhoneBookInterfaceManagerProxy对象的getAdnRecordsInEf方法,

return iccPbkIntMgrProxy.getAdnRecordsInEf(efid);

getAdnRecordsInEf方法如下,

return mIccPhoneBookInterfaceManager.getAdnRecordsInEf(efid);

IccPhoneBookInterfaceManager只是一个抽象类,子类分别为CDMA卡对应的RuimPhoneBookInterfaceManager对象,GSM卡对应的SimPhoneBookInterfaceManager对象。

无论哪个对象, getAdnRecordsInEf都是在IccPhoneBookInterfaceManager中实现的。

getAdnRecordsInEf方法逻辑如下,

1,给代码块加锁

synchronized(mLock) 

2,检查当前线程不是UI线程,因此,Contentprovider的操作一般都在子线程中进行,

checkThread();

3,构造回调处理消息, EVENT_LOAD_DONE,

AtomicBoolean status = new AtomicBoolean(false);
Message response = mBaseHandler.obtainMessage(EVENT_LOAD_DONE, status);

4,调用AdnRecordCache的requestLoadAllAdnLike方法处理,

mAdnCache.requestLoadAllAdnLike(efid, mAdnCache.extensionEfForEf(efid), null, response);

5,当前线程进行休眠,

waitForResult(status);

6,当前线程唤醒后,调用getAdnRecordsInEf方法返回结果,

return getAdnRecordsInEf(IccConstants.EF_ADN);

注意,这里面有个休眠唤醒的操作来进行子线程的同步。

AdnRecordCache的requestLoadAllAdnLike方法主要逻辑如下,

1,如果是EF_PBR类型,调用UsimPhoneBookManager方法的loadEfFilesFromUsim/ loadEfFilesFromUsim方法加载,否则调用getRecordsIfLoaded方法直接获取,

result = mUsimPhoneBookManager.loadEfFilesFromUsim();
•••
result = getRecordsIfLoaded(efid);

如果result不为空,说明结果已经加载过了,已经缓存了,直接返回,

if (result != null) 
   if (response != null) 
       AsyncResult.forMessage(response).result = result;
       response.sendToTarget();
   
   return;

2,如果已经开始查询了,就直接返回,

waiters = mAdnLikeWaiters.get(efid);
if (waiters != null) 
    •••
waiters.add(response);
     return;

3,最后调用AdnRecordLoader的loadAllFromEF方法进行加载,

waiters = new ArrayList<Message>();
waiters.add(response);
mAdnLikeWaiters.put(efid, waiters);
•••
new AdnRecordLoader(mFh).loadAllFromEF(efid, extensionEf, path,
    obtainMessage(EVENT_LOAD_ALL_ADN_LIKE_DONE, efid, extensionEf));

当然,加载完成之后的回调处理消息为EVENT_LOAD_ALL_ADN_LIKE_DONE,

AdnRecordLoader的loadAllFromEF方法如下,

mEf = ef;
mExtensionEF = extensionEF;
mPath = path;
mUserResponse = response;
mFh.getEFLinearRecordSize( mExtensionEF, getEFPath(mExtensionEF),
     obtainMessage(EVENT_EFEXT1_LINEAR_RECORD_SIZE_DONE, path));

调用IccFileHandler的getEFLinearRecordSize方法进行处理,并且回到消息为EVENT_EFEXT1_LINEAR_RECORD_SIZE_DONE

IccFileHandler也是一个抽象类,但是实现了getEFLinearRecordSize方法,该方法逻辑如下,

String efPath = (path == null) ? getEFPath(fileid) : path;
Message response = obtainMessage(EVENT_GET_EF_LINEAR_RECORD_SIZE_DONE,
        new LoadLinearFixedContext(fileid, efPath, onLoaded));
mCi.iccIOForApp(COMMAND_GET_RESPONSE, fileid, efPath,
        0, 0, GET_RESPONSE_EF_SIZE_BYTES, null, null, mAid, response);

调用RIL的iccIOForApp方法进行加载, iccIOForApp方法会向rild守护进程发送RIL_REQUEST_SIM_IO消息,到modem侧进行处理。回调处理消息为EVENT_GET_EF_LINEAR_RECORD_SIZE_DONE。

以上是关于SIM卡 --- 联系人查询过程分析的主要内容,如果未能解决你的问题,请参考以下文章

SIM卡 --- 联系人查询过程回调处理

Android - 创建新的 SIM 卡联系人

SIM功能简介以及流程分析

esp32读取sim

华为手机装了手机卡为啥总显示没有sm

如何排查模组无法识别SIM卡?