PKMS 的分析从两个角度来看, 一个是Client进程另一个是Server进程:
在IPackageManager.aidl文件中, 申明了所有Client和Server之间有业务交流的接口, 在经过编译后会生成一个面向Server端的Stub 类,Stub 所实现的onTransact()函数就是用于响应来自Client端的远程调用; 同时还会生成一个Stub.Proxy 类是面向Client端的.
IoC、DI的联系
控制反转是一种把主程序随意引入其他资源的能力转交给第三方容器, 由第三方容器在运行期建立起主程序与资源文件之间的联系的思想,这样的好处就是避免了主程序与资源文件之间的大量耦合, 通过这个第三方容器实现了依赖的隔离。
通过控制反转思想,成功的把主程序依赖各种资源文件转化成主程序只依赖了第三方容器暴露出的接口
那么问题是:主程序所依赖的资源文件是如何被第三方容器所依赖的呢?,实现的方式便是依赖注入(DI), 依赖注入的实现方式最简单就是利用注解, 参考ButterKnife/Dagger.
ContentResolver.query->ContentProvider.query的流程.md
每一个Application都有一个全局的mContentResolver对象, 作为内部类继承ContentProvider. 主要的职责是根据提供的auth字符串来找到一个可用的ContentProvider. 在mContentResolver的实现中覆盖了ContentProvider的抽象函数acquireProvider(Context context,String auth)和acquireExistingProvider(Context context,String auth)函数, 把定位ContentProvider的逻辑转交给了ActivityThread对象内部处理:
在acquireProvider的入口,先检测是否已经有可用的Providers对象,如果是查询已经存在了的ContentProvider则走acquireExistingProvider(), 否则继续走installProviders的流程.
在acquireExistingProvider()函数中首先是对mProviderMap对象的同步加锁操作, 避免出现竞态问题. mProviderMap是一个ProviderKey->ProviderClient的Map对象, 存放的ContentProvider为当前进程内的ContentProviders, 而ProviderKey是由(authString,userId)组成的一个Provider唯一标志符. 在检索出对应的ProviderClientRecorder后还得检查一下此ContentProvider附着的进程是否是Alive状态, 否则也是不可用的。只有在可用的状态下, 才会拿到一个ContentProvider对应的一个IBinder接口对象, 后续就能通过此Binder接口进行Uri数据交互啦.
如果是走installProviders的流程, 则通过ActivityManagerService对象的getContentProviderImpl()实现; 在通过getDefault()获取到的就是ActivityManager的一个代理对象, 通过binder代理对象的getContentProvider()接口调用到ActivityManagerService端的getContentProvider(). ActivityManagerService端的getContentProviderImpl()函数是核心实现代码.
在ActivityManagerService中也有一个mProviderMap对象,不过是一个ProviderMap的对象. 可以通过conponentName+uid 来查询到一个ContentProviderRecord对象, 首先用的是普通传递过来的UID配合conponentName去查,如果没查到, 则把UID换成root级别也就是uid=0 来查询ContentProviderRecord对象, 在拿到这个ContentProviderRecord对象后继续对其进行单例检查,
- 如果得到的ContentProviderRecord不为空, 在通过权限检查后通过recorder初始化出一个 ContentProviderHolder返回即可.
- 如果得到的ContentProviderRecord为空, 根据ComponentName,从ActivityManagerService.mProviderMap中查询相应的ContentProviderRecord;当首次调用,则创建对象ContentProviderRecord.然后返回.
所以可以理解流程为: ContentProvider在本地进程中如果有可用的话, 则直接从ActivityThread的mProviderMap对象中根据AuthString找到对应的provider;(此阶段尚处于Client_Process)
如果本地进程中并没有install过provider的话则需要AMS来先搜索一下对应ComponentName的provider对象(System_process), 如果系统进程尚未加载过对应的Provider, 则跳到installProvider的流程中, 把最终即将publish的Provider回馈给系统进程, 系统进程告知 Client_Process 添加新的ContentProvider对象到mProviderMap对象里面.