Android深入四大组件(五)Content Provider的启动过程

前言

Content Provider做为四大组件之一,通常情况下并没有其他的组件使用频繁,但这不能作为我们不去深入学习它的理由。关于Content Provider一篇文章是写不完的,这一篇文章先来介绍它的启动过程。

1.query方法到AMS的调用过程

Android IPC机制(四)用ContentProvider进行进程间通信这篇文章我举了一个Content Provider使用的例子,在Activity中我是使用如下代码调用Content Provider的:

要想调用Content Provider,首先需要使用注释1处的getContentResolver方法,如下所示。 frameworks/base/core/Java/android/content/ContextWrapper.java

这里mBase指的是ContextImpl,ContextImpl的getContentResolver方法如下所示。

frameworks/base/core/java/android/app/ContextImpl.java

上面的代码return了ApplicationContentResolver类型的mContentResolver对象,ApplicationContentResolver是ContextImpl中的静态内部类,继承自ContentResolver,它在ContextImpl的构造方法中被创建。 当我们调用ContentResolver的insert、query、update等方法时就会启动Content Provider,这里拿query方法来进行举例。 query方法的实现在ApplicationContentResolver的父类ContentResolver中,代码如下所示。 frameworks/base/core/java/android/content/ContentResolver.java

在注释1处通过acquireUnstableProvider方法返回IContentProvider类型的unstableProvider对象,在注释2处调用unstableProvider的query方法。我们查看acquireUnstableProvider方法做了什么,如下所示。 frameworks/base/core/java/android/content/ContentResolver.java

注释1处用来检查Uri的scheme是否等于”content”,如果不是则返回null。注释2处调用了acquireUnstableProvider方法,这是个抽象方法,它的实现在ContentResolver的子类ApplicationContentResolver中: frameworks/base/core/java/android/app/ContextImpl.java

return了ActivityThread类型的mMainThread对象的acquireProvider方法: frameworks/base/core/java/android/app/ActivityThread.java

注释1处检查ActivityThread中的ArrayMap类型的mProviderMap中是否有目标ContentProvider存在,有则返回,没有就会在注释2处调用AMP的getContentProvider方法,最终会调用AMS的getContentProvider方法。注释3处的installProvider方法用来将注释2处返回的ContentProvider相关的数据存储在mProviderMap中,起到缓存的作用,这样使用相同的Content Provider时,就不需要每次都要调用AMS的getContentProvider方法。使用我们接着查看AMS的getContentProvider方法,代码如下所示。 frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

getContentProvider方法return了getContentProviderImpl方法: frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

getContentProviderImpl方法的代码很多,这里截取了关键的部分。注释1处通过getProcessRecordLocked方法来获取目标ContentProvider的应用程序进程信息,这些信息用ProcessRecord类型的proc来表示,如果该应用进程已经启动就会调用注释2处的代码,否则就会调用注释3的startProcessLocked方法来启动进程。这里我们假设ContentProvider的应用进程还没有启动,关于应用进程启动过程,我在Android应用程序进程启动过程(前篇)已经讲过,最终会调用ActivityThread的main方法,代码如下所示。 frameworks/base/core/java/android/app/ActivityThread.java

注释1处通过prepareMainLooper方法在ThreadLocal中获取Looper,并在注释3处开启消息循环。在注释2处创建了ActivityThread并调用了它的attach方法: frameworks/base/core/java/android/app/ActivityThread.java

注释1处最终会得到AMS,在注释2处调用AMS的attachApplication方法,并将ApplicationThread类型的mAppThread对象传进去。 query方法到AMS的调用过程,如下面时序图所示(省略应用程序进程启动过程)。

2.AMS启动Content Provider的过程

我们接着来查看AMS的attachApplication方法,如下所示。 frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

attachApplication方法中又调用了attachApplicationLocked方法: frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

attachApplicationLocked方法中调用了thread的bindApplication方法,thread是IApplicationThread类型的,从类型名字就可以看出来是用于进程间通信,这里实现bindApplication方法的是ApplicationThreadProxy类,它实现了IApplicationThread接口。 frameworks/base/core/java/android/app/ApplicationThreadNative.java

到目前为止,上面的调用过程还是在AMS进程中执行的,因此,需要通过IBinder类型的mRemote对象向新创建的应用程序进程(目标Content Provider所在的进程)发送BIND_APPLICATION_TRANSACTION类型的通信请求。处理这个通信请求的是在新创建的应用程序进程中执行的ApplicationThread的bindApplication方法,如下所示。 frameworks/base/core/java/android/app/ActivityThread.java

调用sendMessage方法像H发送BIND_APPLICATION类型消息,H的handleMessage方法如下所示。 frameworks/base/core/java/android/app/ActivityThread.java

handleBindApplication方法的代码很长,这里截取了主要的部分。注释1处创建了ContextImpl 。注释2处通过反射创建Instrumentation并在注释3处初始化Instrumentation。注释4处创建Application并且在注释6处调用Application的onCreate方法,这意味着Content Provider所在的应用程序进程已经启动完毕,在这之前,注释5处调用installContentProviders方法来启动Content Provider,代码如下所示。 frameworks/base/core/java/android/app/ActivityThread.java

注释1处遍历当前应用程序进程的ProviderInfo列表,得到每个Content Provider的ProviderInfo(存储Content Provider的信息),并在注释2处调用installProvider方法来启动这些Content Provider。在注释3处通过AMS的publishContentProviders方法将这些Content Provider存储在AMS的mProviderMap中,这个mProviderMap在前面提到过,起到缓存的作用,防止每次使用相同的Content Provider时都会调用AMS的getContentProvider方法。来查看installProvider方法时如何启动Content Provider的,installProvider方法如下所示。 frameworks/base/core/java/android/app/ActivityThread.java

在注释1处通过反射来创建ContentProvider类型的localProvider对象,并在注释2处调用了它的attachInfo方法: frameworks/base/core/java/android/content/ContentProvider.java

在attachInfo方法中调用了onCreate方法,它是一个抽象方法。这样Content Provider就启动完毕。 最后给出AMS启动Content Provider的时序图。

原文发布于微信公众号 - 刘望舒(liuwangshuAndroid)

原文发表时间:2017-05-23

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏有趣的django

Django rest framework(5)----解析器

解析器  (1)api/urls.py # api/urls.py from django.urls import path,re_path from .v...

47650
来自专栏coolblog.xyz技术专栏

MyBatis 源码分析 - 插件机制

一般情况下,开源框架都会提供插件或其他形式的拓展点,供开发者自行拓展。这样的好处是显而易见的,一是增加了框架的灵活性。二是开发者可以结合实际需求,对框架进行拓展...

13730
来自专栏hotqin888的专栏

提升beego插入sqlite的效率

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/hotqin888/article/det...

26730
来自专栏JadePeng的技术博客

XNginx - nginx 集群可视化管理工具

之前团队的nginx管理,都是运维同学每次去修改配置文件,然后重启,非常不方便,一直想找一个可以方便管理nginx集群的工具,翻遍web,未寻到可用之物,于是自...

2.2K40
来自专栏生信宝典

分子对接简明教程 (二)

用PyMOL展示配体和受体相互作用的原子和氢键 为了简化展示过程,我们设计了一个pml脚本 (脚本内有很详细的解释),只需要修改脚本里面受体和配体的名字,然后在...

57850
来自专栏分布式系统和大数据处理

HttpHandler介绍

在 Http请求处理流程 一文中,我们了解了Http请求的处理过程以及其它一些运作原理。我们知道Http管道中有两个可用接口,一个是IHttpHandler,一...

14320
来自专栏Core Net

ASP.NET Core 2.1 : 十一. 如何在后台运行一个任务

23640
来自专栏刘望舒

Android深入四大组件(二)Service的启动过程

此前我用较长的篇幅来介绍Android应用程序的启动过程(根Activity的启动过程),这一篇我们接着来分析Service的启动过程。建议阅读此篇文章前,请先...

19960
来自专栏生信宝典

简单可视化-送你一双发现美的眼睛

用PyMOL展示配体和受体相互作用的原子和氢键 为了简化展示过程,我们设计了一个pml脚本 (脚本内有很详细的解释),只需要修改脚本里面受体和配体的名字,然后在...

26660
来自专栏开发之途

Android 模拟登陆网站实现移动客户端

60580

扫码关注云+社区

领取腾讯云代金券