ContentProvider笔记

本文通过时序图简要分析ContentProvider的获取过程,重点解释installProvider()函数及其参数holder的作用,强调在不同进程如何实例化ContentProvider,并指出holder.provider在进程间通信中的角色。
摘要由CSDN通过智能技术生成

      关于ContentProvider网上有很多文章进行了详细的分析,这里我初略地画了一个getContentProvider时序图,帮助整体上进行理解把握。其中ActivityThread_A代表进程A的ActivityThread,ActivityThread_B代表进程B的ActivityThread,这里是在进程A中去get进程B中的ContentProvider。有四个关键点,下面将一一详细说明下。


节点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中调用该函数满足这个条件。
  
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值