準(zhǔn)備
在上圖之前還是先簡(jiǎn)單總結(jié)下相關(guān)的數(shù)據(jù)結(jié)構(gòu)類翠拣。
在Framework中可以理解為一個(gè)ContentProviderRecord對(duì)應(yīng)應(yīng)用層中的一個(gè)ContentProvider副编,主要的數(shù)據(jù)結(jié)構(gòu)類和其相關(guān)的成員變量在下面簡(jiǎn)要描述:
- ContentProviderRecord : 一個(gè)表示應(yīng)用層定義的ContentProvider的數(shù)據(jù)結(jié)構(gòu)。相關(guān)成員變量:
- info :ProviderInfo 描述該ContentProvider的具體信息逗柴。
- appInfo :ApplicationInfo 描述定義該ContentProvider的應(yīng)用的信息剔猿。
- name :ComponentName 描述標(biāo)識(shí)該ContentProvider的ComponentName唾糯。
- singleton :boolean 表示該ContentProvider是否是跨用戶單例的,所謂跨用戶單例即系統(tǒng)中只會(huì)保存一個(gè)這樣的ContentProviderRecord結(jié)構(gòu),多個(gè)用戶使用的是同一個(gè)ContentProviderRecord移怯。當(dāng)?shù)谌綉?yīng)用的ContentProvider想要定義為跨用戶單例時(shí)邦泄,需要添加INTERACT_ACROSS_USERS權(quán)限。
- connections :ArrayList<ContentProviderConnection> 保存訪問(wèn)該ContentProvider的客戶端的連接砸彬,用于在比如當(dāng)前ContentProvider所在進(jìn)程掛掉等時(shí)刻通知客戶端進(jìn)程颠毙。因?yàn)橐粋€(gè)ContentProvider定義后可以被系統(tǒng)中不同的進(jìn)程訪問(wèn),所以此處使用一個(gè)容器來(lái)存儲(chǔ)砂碉。
從該結(jié)構(gòu)得到信息:
ContentProviderRecord中主要保存當(dāng)前ContentProvider信息的是info成員變量蛀蜜,除此之外該結(jié)構(gòu)中還保存了定義當(dāng)前ContentProvider的進(jìn)程的相關(guān)信息。另外由于一個(gè)ContentProvider可以被多個(gè)進(jìn)程訪問(wèn)增蹭,所以該結(jié)構(gòu)中用一個(gè)容器來(lái)保存客戶端與訪問(wèn)的ContentProvider之間的連接關(guān)系滴某。
- ProviderInfo :真正描述應(yīng)用層定義的ContentProvider的屬性信息。相關(guān)成員變量:
- authority :String 定義ContentProvider時(shí)指定的authority滋迈。
- readPermission :String 定義ContentProvider時(shí)指定的readPermission霎奢。
- writePermission :String 定義ContentProvider時(shí)指定的writePermission。
- grantUriPermissions :boolean 定義ContentProvider時(shí)指定的grantUriPermissions饼灿。
從該結(jié)構(gòu)得到信息:
該結(jié)構(gòu)中基本就是保存定義ContentProvider時(shí)聲明的各個(gè)屬性幕侠。PMS去掃描AndroidManifest文件時(shí)得到的也是該結(jié)構(gòu)。
- ContentProviderConnection :表示一個(gè)訪問(wèn)ContentProvider的客戶端連接碍彭。相關(guān)成員變量:
- provider :ContentProviderRecord 描述其訪問(wèn)的是哪個(gè)ContentProvider晤硕。
- client :ProcessRecord 描述該客戶端進(jìn)程。
- stableCount :int 用來(lái)記錄穩(wěn)定連接的數(shù)量庇忌。
-
unstableCount :int 用來(lái)記錄非穩(wěn)定連接的數(shù)量舞箍。
這兩個(gè)連接數(shù)來(lái)幫助系統(tǒng)判斷當(dāng)前的ContentProvider還有沒(méi)有客戶端在訪問(wèn)。
這里需要多說(shuō)幾句漆枚,站在系統(tǒng)的角度看穩(wěn)定連接與非穩(wěn)定連接的區(qū)別主要是在ContentProvider發(fā)生一些事件時(shí)创译,采用兩種不同的連接訪問(wèn)該ContentProvider的客戶端會(huì)被不同的策略處理。比如當(dāng)ContentProvider所在的進(jìn)程掛掉時(shí)墙基,系統(tǒng)會(huì)遍歷該ContentProviderRecord的connections软族,處理正在訪問(wèn)該ContentProvider的客戶端,如果此時(shí)客戶端采用穩(wěn)定連接訪問(wèn)残制,那么系統(tǒng)會(huì)連同該客戶端一起kill立砸。如果此時(shí)客戶端采用非穩(wěn)定連接訪問(wèn),則系統(tǒng)只是通知客戶端訪問(wèn)的ContentProvider已經(jīng)死亡初茶。
那么具體什么時(shí)候是穩(wěn)定連接颗祝,什么時(shí)候是非穩(wěn)定連接。這取決于訪問(wèn)數(shù)據(jù)的方式,一般來(lái)說(shuō)螺戳,查詢數(shù)據(jù)會(huì)使用非穩(wěn)定的連接搁宾,而增刪改則使用的是穩(wěn)定的連接。
從該結(jié)構(gòu)得到信息:
該結(jié)構(gòu)主要是用于描述一個(gè)訪問(wèn)ContentProvider的客戶端連接倔幼,并保存了客戶端在訪問(wèn)ContentProvider時(shí)的一些屬性盖腿。系統(tǒng)中運(yùn)行的一個(gè)ContentProvider是可能被多個(gè)客戶端訪問(wèn)的,系統(tǒng)就用該結(jié)構(gòu)來(lái)記錄一個(gè)客戶端到它訪問(wèn)的ContentProvider之間的連接损同。
上圖
額哼哼...小二翩腐,上圖:
簡(jiǎn)要總結(jié):
圖中根節(jié)點(diǎn)ProviderMap是服務(wù)于AMS的一個(gè)類,主要負(fù)責(zé)管理ContentProviderRecord膏燃。
ProviderMap中有四個(gè)集合:
mSingletonByName:
直接以定義ContentProvider時(shí)的authority為key來(lái)保存所有正在運(yùn)行的跨用戶單例的ContentProvider所對(duì)應(yīng)的ContentProviderRecord結(jié)構(gòu)茂卦。
mSingletonByClass:
直接以ContentProvider對(duì)應(yīng)的ComponentName為key來(lái)保存所有正在運(yùn)行的跨用戶單例的ContentProvider所對(duì)應(yīng)的ContentProviderRecord結(jié)構(gòu)。
mProvidersByNamePerUser:
先用userId做一級(jí)分類组哩,再在每一個(gè)userId中以定義ContentProvider時(shí)的authority為key來(lái)保存當(dāng)前userId下正在運(yùn)行的ContentProvider對(duì)應(yīng)的ContentProviderRecord結(jié)構(gòu)等龙。
mProvidersByClassPerUser:
先用userId做一級(jí)分類,再在每一個(gè)userId中以ContentProvider對(duì)應(yīng)的ComponentName為key來(lái)保存當(dāng)前userId下正在運(yùn)行的ContentProvider對(duì)應(yīng)的ContentProviderRecord結(jié)構(gòu)伶贰。
簡(jiǎn)而言之而咆,前二者中只保存跨用戶單例(即singleton為true)的ContentProviderRecord結(jié)構(gòu)。后二者中只保存不跨用戶單例(即singleton為false)的ContentProviderRecord結(jié)構(gòu)幕袱。ContentProviderRecord的connections成員是一個(gè)容器,保存了所有訪問(wèn)該ContentProvider的客戶端的連接悠瞬。
整個(gè)ContentProvider的管理都是動(dòng)態(tài)的们豌,也就是說(shuō)ProviderMap中保存的都是正在運(yùn)行的ContentProvider對(duì)應(yīng)的ContentProviderRecord結(jié)構(gòu),所謂正在運(yùn)行其實(shí)就是指有被客戶端訪問(wèn)的ContentProvider浅妆。所以說(shuō)當(dāng)ContentProvider所在進(jìn)程掛掉時(shí)望迎,其對(duì)應(yīng)的ContentProviderRecord結(jié)構(gòu)也會(huì)從ProviderMap中刪除,當(dāng)有客戶端訪問(wèn)時(shí)又會(huì)添加進(jìn)去凌外。同樣ContentProviderConnection也一樣是動(dòng)態(tài)管理的辩尊。
加料
可以用adb shell dumpsys activity providers命令將當(dāng)前手機(jī)系統(tǒng)中運(yùn)行的ContentProvider信息dump出來(lái):
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---
由于系統(tǒng)中運(yùn)行的ContentProvider太多,這里的dump結(jié)果我省略了做了縮減康辑。它的內(nèi)容其實(shí)很簡(jiǎn)單摄欲,就是對(duì)ProviderMap中的四個(gè)集合做遍歷并dump信息。整個(gè)dump內(nèi)容也因此也分為四大段疮薇。
簡(jiǎn)要說(shuō)明:
- 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就是對(duì)應(yīng)于ContentProviderRecord中的connections成員。可以看到系統(tǒng)中訪問(wèn)設(shè)置的ContentProvider的客戶端有很多智袭。
- ByClass的集合dump的是每個(gè)ContentProviderRecord的具體信息奔缠。ByName的集合dump的是key: value形式,其中key是定義該ContentProvider時(shí)指定的authority吼野,value是該描述該ContentProvider的ComponentName校哎。
- 具體每個(gè)字段的含義可以直接參考ProviderMap的源碼,這里就不一一解釋了箫锤。
And Then
后面我會(huì)再根據(jù)自己的理解總結(jié)一篇ContentProvider基本運(yùn)行流程的文章贬蛙,同樣以一張圖的形式盡量簡(jiǎn)單的表達(dá)出其內(nèi)部的基本思想。
Thank you~