前言
Linus Benedict Torvalds : RTFSC – Read The Funning Source Code
ContentProvider下文将会简称CP。
ContentResolver下文将会简称CR。
CP 启动原理
安装APK的时候,并不会把相应的Content Provider加载到内存中来,系统采取的是懒加载的机制,等到第一次使用这个Content Provider的时候,系统才会把它加载到内存中来,下次再要使用这个Content Provider的时候,就可以直接从内存读取了。
ContentProvider 的启动原理从startProcessLocked开始,也就是Android的应用程序启动原理。
Step1.ActivityManagerService.startProcessLocked
Step2.Process.start
Step3.ActivityThread.main
Step4.ActivityThread.attach
Step5.ActivityManagerService.attachApplication
所以我们从attachApplication开始浅析
ActivityManagerService
Step 1.attachApplicationLocked
|
|
这里首先根据传进来的进程ID找到相应的进程记录块,然后对这个进程记录块做一些初倾始化的工作。接下来通过调用generateApplicationProvidersLocked获得需要在这个过程中加载的Content Provider列表,最后调用从参数传进来的IApplicationThread对象thread的bindApplication函数来执行一些应用程序初始化工作。
ActivityThread
Step 2.bindApplication
|
|
bindApplication把相关的信息都封装成一个AppBindData对象,然后以一个消息的形式发送到主线程的消息队列中去等等待处理。这个消息最终是是在ActivityThread类的handleBindApplication函数中进行处理的。
Step 3.handleBindApplication
|
|
这个函数有很多内容,其中对于Provider就是调用installContentProviders函数来在本地安装Content Providers信息。
Step 4.installContentProviders
|
|
installContentProviders做了两件事,第一件是调用installProvider来在本地安装每一个Content Proivder的信息,并且为每一个Content Provider创建一个ContentProviderHolder对象来保存相关的信息。第二件就是调用ActivityManagerService服务的publishContentProviders函数来通知ActivityManagerService服务,这个进程中所要加载的Content Provider,都已经准备完毕。
Step 5.installProvider
|
|
installProvider主要是在应用程序进程中把相应的Content Provider类加载进来。
先来看下其中的localProvider.getIContentProvider()函数,它是从ContentProvider中返回该对象的。
ContentProvider
Step 6.getIContentProvider
|
|
ContentProvider类和Transport类的关系就类似于ActivityThread和ApplicationThread的关系,其它应用程序不是直接调用ContentProvider接口来访问它的数据,而是通过调用它的内部对象mTransport来间接调用ContentProvider的接口。
接着我们来看localProvider.attachInfo(c, info)函数,通过它可以开始初始化Provider。
Step 7.attachInfo
|
|
主要就是根据这个Content Provider的信息info来设置相应的读写权限,然后调用它的子类的onCreate函数来让子类执行一些初始化的工作。
接着回到Step 5.installProvider
ActivityThread
Step 8 ->Step 5.installProvider
在ActivityThread中,以Content Provider的authority为键值来把这个Content Provider的信息保存在mProviderMap成员变量中,因为一个Content Provider可以对应多个authority,因此这里用一个for循环来处理,同时又以这个Content Provider对应的Binder对象provider来键值来把这个Content Provider的信息保存在mLocalProviders成员变量中,表明这是一个在本地加载的Content Provider。
接着返回到Step 4 instalContentProviders
Step 9.publishContentProviders
|
|
此函数调用的作用就是通知ActivityMangerService,需要在这个进程中加载的Content Provider已经完加载完成。在这句函数最后执行了dst.notiryAll语句会通知之前加载的线程要被唤醒。
最后将会返回getProvider函数中执行接下来的installProvider()
Step 10 .installProvider
|
|
与Step 5不同,这里传进来的参数provider是不为null的,因此,它不需要执行在本地加载Content Provider的工作,只需要把从ActivityMangerService中获得的Content Provider接口保存在成员变量mProviderMap中就可以了。