Jimmy Chen

A Programmer

(原创)基于Android R之ContentProvider分析

1. 概述

  ContentProvider(内容提供器)是Android四大组件之一,提供对数据访问的统一格式,封装具体的实现。使用方无需知道底层数据的组织形式(例如数据库、文件、网络等),只需要使用ContentProvider提供的数据操作接口,即可实现增删改查操作。ContentProvider是抽象类,ContentProvider实现方需要实现下列方法

  • onCreate:用于初始化ContentProvider
  • query:查询操作,用于返回数据给调用方
  • insert:插入操作,用于向ContentProvider插入新的数据
  • update:更新操作,用于更新ContentProvider现有的数据
  • delete:删除操作,用于删除ContentProvider中对应的数据
  • getType:返回数据的MIME类型

2. 类继承关系

《(原创)基于Android R之ContentProvider分析》

ContentProvider相关类的继承关系如上图所示,我们在编写ContentProvider提供者的时候,都会继承ContentProvider基类,ContentProvider实现在Android框架中,ContentProvider内部有一个mTransport成员,其类型是TransportTransport继承了ContentProviderNative,通过类名大概可以了解到ContentProvderNativeContentProviderProxy是Binder通信的双方,通过这种方式最终实现跨进程的数据访问。

3. 以query调用为例

ContentProvider的适用方会通过如下的代码进行调用,所以下面就按照这个调用的逻辑来做简单分析

3.1 getContentResolver

老套路,Context只是定义了接口,具体的实现还是在ContextImpl

从上到下,根据摘取的代码可以知道,getContentResolver最后返回的是ApplicationContentResolver实例对象。

3.2 ApplicationContentResolver query调用流程

ApplicationContentResolver继承了ContentResolver,query实现在ContentResolver

这里acquireUnstableProvider最后会调用到父类ApplicationContentResolveracquireUnstableProvider,细心的同学应该还会注意到,ContentResolver内部还有一个acquireProvider方法。unstableProviderstableProviderActivityThread和 AMS 都有各自独立的引用计数,区别在于使用unstableProvider的客户端进程不会受到ContentProvider服务端进程死亡的牵连,而使用stableProvider,服务端死亡将导致客户端进程也被杀死。

acquireProvider(Uri)方法的情况与acquireUnstableProvider的情况相似,唯一要注意的是调用ActivityThread.acquireProvider方法时最后一个参数为 true 而非 false。这里因为我们调用的是acquireUnstableProvider,所以最后传递的参数为false。接下来就看ActivityThread中具体的实现

    1. 第一步是在查询当前进程中是否已经安装过该ContentProvider,需要注意的是运行当前代码的仍是ContentProvider的使用方
    1. 如果第一步没有在本进程中查询到ContentProvider,就需要和AMS交互进行查询
    1. 最后会通过installProvider安装内容提供器,这个方法我们先记住,在后面还会遇到,我们在后面做进一步分析

第三步的installProvider我们在后面还会继续做分析的,所以这里我们可以先暂时越过。现在我们假设需要使用的内容提供器还没有运行,接下来看看AMS是如何处理的。

3.3 AMS getContentProvider处理

AMS中实现的getContentProvider的主要工作还是以来于getContentProviderImpl来进行,所以我们下面直接看getContentProviderImpl

好了,getContentProviderImpl方法的内容非常的多,建议同学们详细的多看几次就好了。getContentProviderImpl方法的内容虽然很多,但是我们记下来关注的地方是两个,一个是如果此前该ContentProvider已经尝试启动了,则调用scheduleInstallProvider来等待其启动。如果之前ContentProvider还没有尝试启动,则调用startProcessLocked进行进程的创建和启动

scheduleInstallProvider方法分析

上一节说到,在获取ContentProvider的过程中会先尝试获取应用的ProcessRecord,如果获取成功,调用其 ActivityThread.scheduleInstallProvider方法,接下来我们就简要分析下这个scheduleInstallProvider方法,该方法是现在ActivityThread.java文件中

调用的流程如上,可以看到最后也是调用installProvider来进行ContentProvider的安装,这个方法我们在前面分析acquireProvider的时候有看到过,这个也一样留到最后做分析。只是要注意的是,当前调用installProvider的第二个参数传递的是null,而在acquireProvider中是有传递ContentProviderHolder对象参数的。

startProcessLocked简要分析

startProcessLocked是启动新进程会调用的一个流程,整个流程比较复杂,中间有很多流程是和我们分析ContentProvider没有太多关联的,所以就只给出startProcessLocked过程中的调用流程,总体流程可以参考下面的调用流程图做分析:

《(原创)基于Android R之ContentProvider分析》

上面之分析到Zygote fork部分,到最后就和Zygote启动新进程的流程一样了,这部分网上教程也比较多,可以参考下图二(之前从网上保存的图,原出处找不到了),因为startProcessLocked过程中会传递参数android.app.ActivityThread,如下图一,在后续通过反射创建ActivityThread。所以下面的流程图(如图二)就从`ActivityThread开始了

《(原创)基于Android R之ContentProvider分析》

图一:android.app.ActivityThread

《(原创)基于Android R之ContentProvider分析》

图二:进程启动

在Zygote启动进程的过程中,会进行ContentProvider的安装,从流程图可以看到最后也是会调用到installContentProviders。在scheduleInstallProvider一节我们可以看到,installContentProviders最后也还是会调用到installProvider来进行的,所以这几个地方最后最后都是会跑到installProvider方法来执行。

installProvider分析

终于来到installProvider方法了,这个方法在前面已经出现过三次了

  • 第一次是在acquireProvider过程中,最后会通过installProvider安装内容提供器,此第二个参数传递的是ContentProviderHolder实例对象,此时代码运行在调用着进程中
  • 第二次是在scheduleInstallProvider调用过程中,此时第二个参数传递的是null
  • 第三次是在startProcessLocked调用过程中,此时第二个参数传递的也是null

installProvider的内容比较简单,方法最后返回获取的 ContentProviderHolder对象,其中详细的情况同学们可以看上述代码中的注释。

OK,关于获取ContentProvider的获取流程就到这里结束了。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注