本文目标:以MediaProvider为例,想搞清楚调用ContentResolver访问各个ContentProvider的调用过程。
Java code:
getContentResolver().query(MediaStore.Images.Thumbnails.EXTERNAL_CONTENT_URI,null,null)
具体调用过程是
1.通过ContentResolver先查找对应给定Uri的ContentProvider,返回对应的BinderProxy
如果该Provider尚未被调用进程使用过:
a.通过ServiceManager查找activity service得到ActivityManagerService对应BinderProxy
b.调用BinderProxy的transcat方法发送GET_CONTENT_PROVIDER_TRANSACTION命令,得到对应ContentProvider的BinderProxy。
如果该Provider已被调用进程使用过,则调用进程会保留使用过provider的HashMap。此时直接从此表查询即得。
2.调用BinderProxy的query()
通过下图,可以清楚的看到,getContentResolver().query调用时首先得到Actiivity服务,再次查询Activity服务中记录的对应ContentProviderRecord.如果发现此ContentProvider尚未publish则引发publish该ContentProvider,详见分析二一文。查询到ContentProviderRecord后返回对应MediaProvider的IBinder并返回给调用者。
整个调用过程中需要经过两次Binder调用以实现跨进程访问,即:
Calling Process -> ActivityManagerService Process -> MediaProvider process
Detailed call sequence(If calling process doesn't ever used the Provider):
源代码调用路径:
第1,2步:
frameworks/base/core/java/android/app/ContextImpl.java
private static final class ApplicationContentResolver extends ContentResolver {
public ApplicationContentResolver(Context context, ActivityThread mainThread) {
super(context);
mMainThread = mainThread;
}
@Override
protected IContentProvider acquireProvider(Context context, String name) {
return mMainThread.acquireProvider(context, name);
}
ActivityThread
public final IContentProvider acquireProvider(Context c, String name) {
IContentProvider provider = getProvider(c, name);
if(provider == null)
return null;
IBinder jBinder = provider.asBinder();
synchronized(mProviderMap) {
ProviderRefCount prc = mProviderRefCountMap.get(jBinder);
if(prc == null) {
mProviderRefCountMap.put(jBinder, new ProviderRefCount(1)); //创建对此Provider的引用计数
} else {
prc.count++; //计数+1
} //end else
} //end synchronized
return provider;
}