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卡 --- 联系人查询过程分析的主要内容,如果未能解决你的问题,请参考以下文章