准备
在上图之前还是先简单总结下相关的数据结构类。
在Framework中可以理解为一个ContentProviderRecord对应应用层中的一个ContentProvider,主要的数据结构类和其相关的成员变量在下面简要描述:
- ContentProviderRecord : 一个表示应用层定义的ContentProvider的数据结构。相关成员变量:
- info :ProviderInfo 描述该ContentProvider的具体信息。
- appInfo :ApplicationInfo 描述定义该ContentProvider的应用的信息。
- name :ComponentName 描述标识该ContentProvider的ComponentName。
- singleton :boolean 表示该ContentProvider是否是跨用户单例的,所谓跨用户单例即系统中只会保存一个这样的ContentProviderRecord结构,多个用户使用的是同一个ContentProviderRecord。当第三方应用的ContentProvider想要定义为跨用户单例时,需要添加INTERACT_ACROSS_USERS权限。
- connections :ArrayList<ContentProviderConnection> 保存访问该ContentProvider的客户端的连接,用于在比如当前ContentProvider所在进程挂掉等时刻通知客户端进程。因为一个ContentProvider定义后可以被系统中不同的进程访问,所以此处使用一个容器来存储。
从该结构得到信息:
ContentProviderRecord中主要保存当前ContentProvider信息的是info成员变量,除此之外该结构中还保存了定义当前ContentProvider的进程的相关信息。另外由于一个ContentProvider可以被多个进程访问,所以该结构中用一个容器来保存客户端与访问的ContentProvider之间的连接关系。
- ProviderInfo :真正描述应用层定义的ContentProvider的属性信息。相关成员变量:
- authority :String 定义ContentProvider时指定的authority。
- readPermission :String 定义ContentProvider时指定的readPermission。
- writePermission :String 定义ContentProvider时指定的writePermission。
- grantUriPermissions :boolean 定义ContentProvider时指定的grantUriPermissions。
从该结构得到信息:
该结构中基本就是保存定义ContentProvider时声明的各个属性。PMS去扫描AndroidManifest文件时得到的也是该结构。
- ContentProviderConnection :表示一个访问ContentProvider的客户端连接。相关成员变量:
- provider :ContentProviderRecord 描述其访问的是哪个ContentProvider。
- client :ProcessRecord 描述该客户端进程。
- stableCount :int 用来记录稳定连接的数量。
-
unstableCount :int 用来记录非稳定连接的数量。
这两个连接数来帮助系统判断当前的ContentProvider还有没有客户端在访问。
这里需要多说几句,站在系统的角度看稳定连接与非稳定连接的区别主要是在ContentProvider发生一些事件时,采用两种不同的连接访问该ContentProvider的客户端会被不同的策略处理。比如当ContentProvider所在的进程挂掉时,系统会遍历该ContentProviderRecord的connections,处理正在访问该ContentProvider的客户端,如果此时客户端采用稳定连接访问,那么系统会连同该客户端一起kill。如果此时客户端采用非稳定连接访问,则系统只是通知客户端访问的ContentProvider已经死亡。
那么具体什么时候是稳定连接,什么时候是非稳定连接。这取决于访问数据的方式,一般来说,查询数据会使用非稳定的连接,而增删改则使用的是稳定的连接。
从该结构得到信息:
该结构主要是用于描述一个访问ContentProvider的客户端连接,并保存了客户端在访问ContentProvider时的一些属性。系统中运行的一个ContentProvider是可能被多个客户端访问的,系统就用该结构来记录一个客户端到它访问的ContentProvider之间的连接。
上图
额哼哼...小二,上图:
Provider结构图 (1).png
简要总结:
-
图中根节点ProviderMap是服务于AMS的一个类,主要负责管理ContentProviderRecord。
-
ProviderMap中有四个集合:
mSingletonByName:
直接以定义ContentProvider时的authority为key来保存所有正在运行的跨用户单例的ContentProvider所对应的ContentProviderRecord结构。
mSingletonByClass:
直接以ContentProvider对应的ComponentName为key来保存所有正在运行的跨用户单例的ContentProvider所对应的ContentProviderRecord结构。
mProvidersByNamePerUser:
先用userId做一级分类,再在每一个userId中以定义ContentProvider时的authority为key来保存当前userId下正在运行的ContentProvider对应的ContentProviderRecord结构。
mProvidersByClassPerUser:
先用userId做一级分类,再在每一个userId中以ContentProvider对应的ComponentName为key来保存当前userId下正在运行的ContentProvider对应的ContentProviderRecord结构。
简而言之,前二者中只保存跨用户单例(即singleton为true)的ContentProviderRecord结构。后二者中只保存不跨用户单例(即singleton为false)的ContentProviderRecord结构。 -
ContentProviderRecord的connections成员是一个容器,保存了所有访问该ContentProvider的客户端的连接。
-
整个ContentProvider的管理都是动态的,也就是说ProviderMap中保存的都是正在运行的ContentProvider对应的ContentProviderRecord结构,所谓正在运行其实就是指有被客户端访问的ContentProvider。所以说当ContentProvider所在进程挂掉时,其对应的ContentProviderRecord结构也会从ProviderMap中删除,当有客户端访问时又会添加进去。同样ContentProviderConnection也一样是动态管理的。
加料
可以用adb shell dumpsys activity providers命令将当前手机系统中运行的ContentProvider信息dump出来:
adb shell dumpsys activity providers
ACTIVITY MANAGER CONTENT PROVIDERS (dumpsys activity providers)
Published single-user content providers (by class):
* ContentProviderRecord{6da87f4 u0 com.android.providers.settings/.SettingsProvider}
package=com.android.providers.settings process=system
proc=ProcessRecord{1c0b52f 907:system/1000}
uid=1000 provider=android.content.ContentProvider$Transport@5e045f5
singleton=true
authority=settings
isSyncable=false multiprocess=false initOrder=100
Connections:
-> 1366:com.google.android.inputmethod.pinyin/u0a90 s1/1 u0/0 +1d5h33m4s312ms
-> 1382:com.android.systemui/u0a39 s1/1 u0/0 +1d5h33m4s249ms
-> 1506:com.quicinc.cne.CNEService/1000 s1/1 u0/0 +1d5h33m3s747ms
-> 1540:com.android.phone/1001 s1/1 u0/0 +1d5h33m3s666ms
-> 2143:com.google.android.apps.nexuslauncher/u0a61 s1/1 u0/0 +1d5h32m51s663ms
-> 2061:com.android.ims.rcsservice/1001 s1/1 u0/0 +1d5h32m51s634ms
-> 2049:com.android.nfc/1027 s1/1 u0/0 +1d5h32m51s523ms
-> 2032:com.google.android.googlequicksearchbox:interactor/u0a47 s1/1 u0/0 +1d5h32m50s742ms
-> 2763:com.android.bluetooth/1002 s1/1 u0/0 +1d5h32m45s175ms
-> 2852:com.tencent.mm:exdevice/u0a129 s1/1 u0/0 +1d5h32m44s534ms
-> 2586:com.google.android.gms/u0a40 s1/1 u0/0 +1d5h32m41s651ms
-> 3680:cn.com.langeasy.LangEasyLrc:channel/u0a143 s1/1 u0/0 +1d5h32m24s937ms
-> 8803:cn.com.langeasy.LangEasyLexis/u0a152 s1/1 u0/0 +1d5h28m37s335ms
-> 4741:com.google.android.googlequicksearchbox:search/u0a47 s1/1 u0/0 +4h54m32s412ms
-> 5436:com.tencent.mm:push/u0a129 s1/1 u0/0 +4h54m4s981ms
-> 14262:com.google.android.gms.persistent/u0a40 s1/1 u0/0 +3h40m12s345ms
-> 16671:cn.com.langeasy.LangEasyLexis:channel/u0a152 s1/1 u0/0 +3h23m10s31ms
-> 20077:com.google.android.tts/u0a84 s1/1 u0/0 +3h20m16s488ms
-> 20364:cn.poco.interphoto2/u0a138 s1/1 u0/0 +3h20m1s501ms
-> 20480:com.tencent.mm/u0a129 s1/1 u0/0 +3h19m59s219ms
-> 27828:cn.com.langeasy.LangEasyLrc/u0a143 s1/1 u0/0 +2h18m39s482ms
-> 32580:com.vip.zb:pushcore/u0a201 s1/1 u0/0 +2h9m13s53ms
-> 31904:android.process.media/u0a9 s1/1 u0/0 +2h2m58s536ms
-> 1866:com.google.android.apps.photos/u0a116 s1/1 u0/0 +1h58m55s281ms
-> 3892:com.tencent.mm:appbrand0/u0a129 s1/1 u0/0 +1h51m37s766ms
-> 32527:com.vip.zb/u0a201 s1/1 u0/0 +1h0m10s366ms
-> 9189:com.android.vending/u0a59 s1/1 u0/0 +58m1s728ms
-> 11603:com.evernote/u0a135 s1/1 u0/0 +2m7s712ms
---此处省略一堆ContentProviderRecord---
Published user 0 content providers (by class):
* ContentProviderRecord{3835601 u0 com.google.android.gms/.auth.api.credentials.be.persistence.TemporaryValueProvider}
package=com.google.android.gms process=com.google.android.gms
proc=ProcessRecord{ea68992 2586:com.google.android.gms/u0a40}
uid=10040 provider=android.content.ContentProviderProxy@a2fbf8c
authority=com.google.android.gms.auth.api.credentials.be.persistence.TemporaryValueProvider
---此处省略一堆ContentProviderRecord---
Single-user authority to provider mappings:
settings: 6da87f4/com.android.providers.settings/.SettingsProvider
---此处省略一堆name: ComponentName---
User 0 authority to provider mappings:
com.google.android.gms.auth.api.credentials.be.persistence.TemporaryValueProvider: 3835601/com.google.android.gms/.auth.api.credentials.be.persistence.TemporaryValueProvider
---此处省略一堆name: ComponentName---
由于系统中运行的ContentProvider太多,这里的dump结果我省略了做了缩减。它的内容其实很简单,就是对ProviderMap中的四个集合做遍历并dump信息。整个dump内容也因此也分为四大段。
简要说明:
- Published single-user content providers (by class):
mSingletonByClass集合中的记录。 - Published user 0 content providers (by class):
mProvidersByClassPerUser集合中的记录。 - Single-user authority to provider mappings:
mSingletonByName集合中的记录。 - User 0 authority to provider mappings:
mProvidersByNamePerUser集合中的记录。 - 上面的例子中看到ComponentName为com.android.providers.settings/.SettingsProvider的ContentProvider打印出的Connections就是对应于ContentProviderRecord中的connections成员。可以看到系统中访问设置的ContentProvider的客户端有很多。
- ByClass的集合dump的是每个ContentProviderRecord的具体信息。ByName的集合dump的是key: value形式,其中key是定义该ContentProvider时指定的authority,value是该描述该ContentProvider的ComponentName。
- 具体每个字段的含义可以直接参考ProviderMap的源码,这里就不一一解释了。
And Then
后面我会再根据自己的理解总结一篇ContentProvider基本运行流程的文章,同样以一张图的形式尽量简单的表达出其内部的基本思想。
Thank you~
网友评论