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对象里面.