读取卡联系人的provider定义于:
/packages/services/Telephony/AndroidManifest.xml
packages/services/Telephony/src/com/android/phone/IccProvider.java
public class IccProvider extends com.android.internal.telephony.IccProvider {
public IccProvider() {
super();
}
}
Telephony目录下的IccProvider其实是空的,实现全部在framework的同名文件中
frameworks/opt/telephony/src/java/com/android/internal/telephony/IccProvider.java
public class IccProvider extends ContentProvider {
static {
URL_MATCHER.addURI("icc", "adn", ADN);
URL_MATCHER.addURI("icc", "adn/subId/#", ADN_SUB);
...
}
static块中加入了adn的uri,adn/subid/#可以指定读取的sim卡
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());
...
}
query方法,调用loadFromEf
private MatrixCursor loadFromEf(int efType, int subId) {
List adnRecords = null;
try {
IIccPhoneBook iccIpb = getIccPhbService();
if (iccIpb != null) {
adnRecords = iccIpb.getAdnRecordsInEfForSubscriber(subId, efType);
}
} catch (RemoteException ex) {
log(ex.toString());
} catch (SecurityException ex) {
log(ex.toString());
}
if (adnRecords != null) {
// Load the results
final int size = adnRecords.size();
final MatrixCursor cursor = new MatrixCursor(ADDRESS_BOOK_COLUMN_NAMES, size);
if (DBG) {
log("adnRecords.size=" + size);
}
for (int i = 0; i < size; i++) {
loadRecord(adnRecords.get(i), cursor, i);
}
return cursor;
}
...
}
首先获取AdnRecord列表然后,然后loadRecord依据这个列表生成cursor返回。生成cursor的函数很简单,不做分析了。
private IIccPhoneBook getIccPhbService() {
IIccPhoneBook iccIpb = IIccPhoneBook.Stub.asInterface(
ServiceManager.getService("simphonebook"));
return iccIpb;
}
读取的服务名称叫做simphonebook,该服务添加的代码在UiccPhoneBookController中:
public UiccPhoneBookController(Phone[] phone) {
if (ServiceManager.getService("simphonebook") == null) {
ServiceManager.addService("simphonebook", this);
}
mPhone = phone;
}
构造函数中添加了服务,UiccPhoneBookController实例是在phone进程启动就初始化的,phone进程又是常驻的,所以phone的相关服务基本等于是永远可用的。
public List getAdnRecordsInEfForSubscriber(int subId, int efid)
throws android.os.RemoteException {
IccPhoneBookInterfaceManagerProxy iccPbkIntMgrProxy =
getIccPhoneBookInterfaceManagerProxy(subId);
if (iccPbkIntMgrProxy != null) {
return iccPbkIntMgrProxy.getAdnRecordsInEf(efid);
}
...
}
然后调用IccPhoneBookInterfaceManagerProxy的getAdnRecordsInEf
private IccPhoneBookInterfaceManagerProxy
getIccPhoneBookInterfaceManagerProxy(int subId) {
...
try {
return ((PhoneProxy)mPhone[(int)phoneId]).getIccPhoneBookInterfaceManagerProxy();
...
}
frameworks/opt/telephony/src/java/com/android/internal/telephony/PhoneProxy.java
public IccPhoneBookInterfaceManagerProxy getIccPhoneBookInterfaceManagerProxy() {
return mIccPhoneBookInterfaceManagerProxy;
}
public PhoneProxy(PhoneBase phone) {
...
mIccPhoneBookInterfaceManagerProxy = new IccPhoneBookInterfaceManagerProxy(
phone.getIccPhoneBookInterfaceManager());
...
}
IccPhoneBookInterfaceManagerProxy是在PhoneProxy构造函数中初始化的。
public List getAdnRecordsInEf(int efid) {
return mIccPhoneBookInterfaceManager.getAdnRecordsInEf(efid);
}
这里的mIccPhoneBookInterfaceManager就是PhoneProxy构造函数传递进去的phone.getIccPhoneBookInterfaceManager()
mSimPhoneBookIntManager = new SimPhoneBookInterfaceManager(this);
SimPhoneBookInterfaceManager的基类是IccPhoneBookInterfaceManager
public synchronized List getAdnRecordsInEf(int efid) {
...
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);
}
...
}
return mRecords;
}
frameworks/opt/telephony/src/java/com/android/internal/telephony/uicc/AdnRecordCache.java
public void
requestLoadAllAdnLike (int efid, int extensionEf, Message response) {
ArrayList waiters;
ArrayList result;
if (efid == EF_PBR) {
result = mUsimPhoneBookManager.loadEfFilesFromUsim();
} else {
result = getRecordsIfLoaded(efid); //该方法实际是从缓存读取数据
}
logd("requestLoadAllAdnLike result = null ?" + (result == null));
// Have we already loaded this efid?
if (result != null) { //如果缓存已有数据,return
if (response != null) {
AsyncResult.forMessage(response).result = result;
response.sendToTarget();
}
return;
}
// Have we already *started* loading this efid?
waiters = mAdnLikeWaiters.get(efid);
if (waiters != null) { //正在读取中,把回调消息加入等待队列中,return
waiters.add(response);
return;
}
waiters = new ArrayList();
waiters.add(response);
mAdnLikeWaiters.put(efid, waiters);
...
new AdnRecordLoader(mFh).loadAllFromEF(efid, extensionEf,
obtainMessage(EVENT_LOAD_ALL_ADN_LIKE_DONE, efid, 0)); //正真读取
}
流程分析已经写在注释中,usim是另一条分支(本流程不做解析),继续看loadAllFromEF
public void
loadAllFromEF(int ef, int extensionEF,
Message response) {
...
mFh.mCi.queryPhbStorageInfo(
type,
obtainMessage(EVENT_PHB_QUERY_STAUTS));
...
}
调用ril的queryPhbStorageInfo向modem发送请求,读取结果会在handleMessage中处理
case EVENT_PHB_QUERY_STAUTS:
/*
* response.obj.result[0] is number of current used entries
* response.obj.result[1] is number of total entries in the
* storage
*/
ar = (AsyncResult) (msg.obj);
int[] info = (int[]) (ar.result);
if (ar.exception != null) {
throw new RuntimeException("PHB Query Info Error",
ar.exception);
}
type = getPhbStorageType(mEf);
readInfo = new int[3];
readInfo[0] = 1; // current_index;
readInfo[1] = info[0]; // # of remaining entries
readInfo[2] = info[1]; // # of total entries
mAdns = new ArrayList(readInfo[2]);
for (int i = 0; i < readInfo[2]; i++) {
// fillin empty entries to mAdns
adn = new AdnRecord(mEf, i + 1, "", "");
mAdns.add(i, adn);
}
readEntryFromModem(type, readInfo);
mPendingExtLoads = 1;
break;
获取到了卡联系人总数目,先用空值初始化mAdn列表,然后调用readEntryFromModem正真的读取数据
private void readEntryFromModem(int type, int[] readInfo) {
...
mFh.mCi.ReadPhbEntry(type, readInfo[0], eIndex,
obtainMessage(EVENT_PHB_LOAD_ALL_DONE, readInfo));
}
消息处理:
case EVENT_PHB_LOAD_ALL_DONE:
ar = (AsyncResult) (msg.obj);
readInfo = (int[]) (ar.userObj);
entries = (PhbEntry[]) (ar.result);
...
for (int i = 0; i < entries.length; i++) {
adn = getAdnRecordFromPhbEntry(entries[i]);
if (adn != null) {
mAdns.set(adn.mRecordNumber - 1, adn);
readInfo[1]--;
Rlog.d(LOG_TAG, "Read entries: " + adn);
}
}
...
for循环中向mAdns添加数据。AdnRecordLoader会向AdnRecordCache发消息,EVENT_LOAD_ALL_ADN_LIKE_DONE消息处理:
case EVENT_LOAD_ALL_ADN_LIKE_DONE:
...
if (ar.exception == null) {
mAdnLikeFiles.put(efid, (ArrayList) ar.result);
} else {
Rlog.d(LOG_TAG, "EVENT_LOAD_ALL_ADN_LIKE_DONE exception", ar.exception);
}
notifyWaiters(waiters, ar);
...
break;
一路向上传递消息,这里的ar其实就包含了联系人数据列表ArrayList回到IccPhoneBookInterfaceManager.java
case EVENT_LOAD_DONE:
ar = (AsyncResult)msg.obj;
...
mRecords = (List) ar.result;
...
整个流程走完了。可以看出名称叫做IccProvider,其实没有建立任何数据库。第一次的查询是通过发送ril请求读取sim卡得到数据,后续用缓存返回数据。
packages/apps/Contacts/src/com/mediatek/contacts/simcontact/BootCmpReceiver.java
public void onReceive(Context context, Intent intent) {
...
if (action.equals(TelephonyIntents.ACTION_PHB_STATE_CHANGED)) {
processPhoneBookChanged(context, intent);
}
...
}
收到TelephonyIntents.ACTION_PHB_STATE_CHANGED广播后,该广播表示卡联系人可用不可用,调用processPhoneBookChanged
private void processPhoneBookChanged(Context context, Intent intent) {
...
if (phbReady && subId > 0) {
startSimService(context, subId, SIMServiceUtils.SERVICE_WORK_IMPORT);
} else if (subId > 0 && !phbReady) {
startSimService(context, subId, SIMServiceUtils.SERVICE_WORK_REMOVE);
}
}
广播处理有两个分支,一个是删除卡联系人,一个是导入卡联系人
@Override
public void onCreate() {
super.onCreate();
Log.i(TAG, "[onCreate]...");
mProcessorManager = new SIMProcessorManager(this, mListener);
}
@Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
processIntent(intent);
}
private void processIntent(Intent intent) {
...
mProcessorManager.handleProcessor(getApplicationContext(), subId, workType, intent);
}
一路调用到handleProcessor,注意mProcessorManager初始化的时候传入了接口的实现,这样mProcessorManager就可以通知SIMProcessorService工作开始或者完毕
private SIMProcessorManager.ProcessorManagerListener mListener
packages/apps/Contacts/src/com/mediatek/contacts/simservice/SIMProcessorManager.java
public void handleProcessor(Context context, int subId, int workType, Intent intent) {
Log.i(TAG, "[handleProcessor] subId=" + subId + ",time=" + System.currentTimeMillis());
SIMProcessorBase processor = createProcessor(context, subId, workType, intent);
if (processor != null && mListener != null) {
Log.d(TAG, "[handleProcessor]Add processor [subId=" + subId + "] to threadPool.");
mListener.addProcessor(/* 1000 + slotId * 300 */0, processor);
}
}
private SIMProcessorBase createProcessor(Context context, int subId, int workType,
Intent intent, ProcessorCompleteListener listener) {
...
if (workType == SIMServiceUtils.SERVICE_WORK_IMPORT) {
processor = new SIMImportProcessor(context, subId, intent, listener);
...
}
@Override
public void addProcessor(long scheduleTime, ProcessorBase processor) {
if (processor != null) {
try {
mExecutorService.execute(processor);
} catch (RejectedExecutionException e) {
Log.e(TAG, "[addProcessor] RejectedExecutionException: " + e.toString());
}
}
}
public abstract class ProcessorBase implements RunnableFuture
ProcessorBase实现了RunnableFuture,所以它可以放到线程池区运行。
public void run() {
try {
doWork();
} finally {
mDone = true;
if (mListener != null && !mCanceled) {
mListener.onProcessorCompleted(mIntent);
}
}
}
线程池是调用run方法开启工作的,run函数中调用doWork完成工作,用mListener接口通知SIMProcessorManager工作完毕
@Override
public void doWork() {
...
SIMServiceUtils.deleteSimContact(mContext, mSubId);
...
int simType = SimCardUtils.getSimTypeBySubId(mSubId);
final Uri iccUri = SubInfoUtils.getIccProviderUri(mSubId);
Cursor simCursor = querySimContact(mContext, mSubId, simType, iccUri);
Log.i(TAG, "[dowork]simType = " + simType + ",simType =" + simType + ",mSubId = " + mSubId);
importAllSimContacts(mContext, mSubId, simCursor, simType);
if (simCursor != null) {
simCursor.close();
}
}
首先删除所有数据库中的卡联系人,然后查询卡联系人,获取卡联系人数据后导入到ContactsProvider中。
private Cursor querySimContact(Context context, int subId, int simType, Uri iccUri) {
...
cursor = context.getContentResolver().query(iccUri, COLUMN_NAMES, null, null, null);
...
return cursor;
}
通过IccProvider查询卡联系人
private void importAllSimContacts(Context context, final Cursor cursor,
final ContentResolver resolver, int subId, int simType, HashSet insertSimIdSet,
boolean importSdnContacts) {
...
while (cursor.moveToNext()) {
...
i = actuallyImportOneSimContact(context, cursor, resolver, subId, simType,
indexInSim, importSdnContacts, operationList, i, account, isUsim,
accountSubId, countryCode);
...
if (i > MAX_OP_COUNT_IN_ONE_BATCH) {
...
resolver.applyBatch(ContactsContract.AUTHORITY, operationList);
...
}
}
...
}
基本流程是依据cursor利用actuallyImportOneSimContact生成数据库插入的operationlist,然后在每大于90个operation就批量操作一次,循环上诉流程直到处理完毕。