关于ContentProvider网上有很多文章进行了详细的分析,这里我初略地画了一个getContentProvider时序图,帮助整体上进行理解把握。其中ActivityThread_A代表进程A的ActivityThread,ActivityThread_B代表进程B的ActivityThread,这里是在进程A中去get进程B中的ContentProvider。有四个关键点,下面将一一详细说明下。
![](https://img-blog.csdn.net/20150816150250053?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
节点1、在getContentProviderImpl()函数中会判断
ContentProvider所在的目标进程B是否已经启动,如果未启动,那么会先启动目标进程B,然后当前线程会wait在一个ContentProviderRecord对象上,只有等到进程B启动并将ContentProvider publish到AMS中,通过notifyAll()唤醒,前面那个线程才会继续执行。
节点2、进程B启动过程中,在handleBindApplication()函数中进行
ContentProvider安装,安装函数便是installProvider(),我们可以看到关键点4也是调用installProvider()进行
ContentProvider安装,为什么会有两次ContentProvider安装呢?是因为同时需要在进程A和进程B中进行安装,那么进程A、B中安装有何不同?答案就在installProvider()函数中,installProvider()具体分析见下文。
节点3、当进程B本地安装完ContentProvider,然后夸Binder调用AMS.publishContentProviders()接口将ContentProvider中Transport 的Binder实体传递到AMS中,并调用notifyAll()进行唤醒上面所说的等待线程。
节点4、进程A中调用完AMS.getContentProvider()后立即调用installProvider()进行ContentProvider本地安装,这是第二次调用
installProvider(),具体分析见下面。
installProvider()函数分析:
在分析这个函数之前我们先要搞清楚ContentProviderHolder类的两个成员变量provider、connection。在进程B启动过程中,会实例化ContentProvider对象, ContentProvider中有一个Transport类型的Binder本地对象mTransport,进程A就是要拿到这个mTransport的代理来与B进程中的ContentProvider建立Binder通信。
那进程A是如何拿到进程B中ContentProvider.mTransport的代理的呢?mTransport是一个匿名Binder对象,我们知道匿名Binder对象是可以在已经建立起的Binder通信的链路中进行传递的,于是,mTransport便是这样传递到进程A并保存在ContentProviderHolder.provider中:
①进程B启动安装
ContentProvider时通过publishContentProviders()接口将mTransport传递到AMS,并保存在ContentProviderRecord.provider中;
②进程A调用AMS.getContentProvider()接口,AMS会将ContentProviderRecord.provider和新创建的ContentProviderConnection匿名Binder对象一并传递到进程A中,分别保存在ContentProviderHolder.provider和ContentProviderHolder.connection中。
注意,进程A中ContentProviderHolder.provider与AMS中的ContentProviderRecord.provider均是进程B中mTransport的Binder代理。进程A拿到了进程B中ContentProvider.mTransport代理,便建立Binder通信。更具体的ContentProvider操作在自定义的ContentProvider中实现,Transport只是通信的封装。
了解了上面这些信息我们再来看installProvider()函数。在上面的时序图中有两次调用,一次在进程B中,一次在进程A中。这里我们只关心installProvider(..,holder,..)函数的第二个参数holder。holder是一个ContentProviderHolder类型参数,如果holder.provider为null,那边需要在本次installProvider()函数调用中实例化ContentProvider对象,如果holder.provider不为null,则无需实例化ContentProvider对象。在进程B中installProvider()函数调用参数holder.provider=null,在进程A中installProvider()函数调用参数holder.provider!=null,因此进程B中会实例化ContentProvider对象,而进程A中holder.provider保存着进程B中ContentProvider.mTransport的代理,这一点读者稍微跟下代码便可发现。
private IActivityManager.ContentProviderHolder installProvider(Context context,
IActivityManager.ContentProviderHolder holder, ProviderInfo info,
boolean noisy, boolean noReleaseNeeded, boolean stable) {
ContentProvider localProvider = null;
IContentProvider provider;
if (holder == null || holder.provider == null) { //holder.provider=null,意味着需要在此实例化ContentProvider对象。进程B中调用该函数满足这个条件。