一圖解惑之Android管理ContentProvider結(jié)構(gòu)

準(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)成員變量:
  1. info :ProviderInfo 描述該ContentProvider的具體信息逗柴。
  2. appInfo :ApplicationInfo 描述定義該ContentProvider的應(yīng)用的信息剔猿。
  3. name :ComponentName 描述標(biāo)識(shí)該ContentProvider的ComponentName唾糯。
  4. 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)限。
  5. 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)成員變量:
  1. authority :String 定義ContentProvider時(shí)指定的authority滋迈。
  2. readPermission :String 定義ContentProvider時(shí)指定的readPermission霎奢。
  3. writePermission :String 定義ContentProvider時(shí)指定的writePermission。
  4. 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)成員變量:
  1. provider :ContentProviderRecord 描述其訪問(wèn)的是哪個(gè)ContentProvider晤硕。
  2. client :ProcessRecord 描述該客戶端進(jìn)程。
  3. stableCount :int 用來(lái)記錄穩(wěn)定連接的數(shù)量庇忌。
  4. 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之間的連接损同。

上圖

額哼哼...小二翩腐,上圖:


Provider結(jié)構(gòu)圖 (1).png

查看原圖

簡(jiǎn)要總結(jié):

  1. 圖中根節(jié)點(diǎn)ProviderMap是服務(wù)于AMS的一個(gè)類,主要負(fù)責(zé)管理ContentProviderRecord膏燃。

  2. 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)幕袱。

  3. ContentProviderRecord的connections成員是一個(gè)容器,保存了所有訪問(wèn)該ContentProvider的客戶端的連接悠瞬。

  4. 整個(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~

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末谚攒,一起剝皮案震驚了整個(gè)濱河市阳准,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌馏臭,老刑警劉巖野蝇,帶你破解...
    沈念sama閱讀 211,948評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異括儒,居然都是意外死亡绕沈,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,371評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén)帮寻,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)乍狐,“玉大人,你說(shuō)我怎么就攤上這事固逗∏瞅剑” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,490評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵烫罩,是天一觀的道長(zhǎng)惜傲。 經(jīng)常有香客問(wèn)我,道長(zhǎng)贝攒,這世上最難降的妖魔是什么盗誊? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,521評(píng)論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮隘弊,結(jié)果婚禮上哈踱,老公的妹妹穿的比我還像新娘。我一直安慰自己长捧,他們只是感情好嚣鄙,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,627評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著串结,像睡著了一般哑子。 火紅的嫁衣襯著肌膚如雪舅列。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,842評(píng)論 1 290
  • 那天卧蜓,我揣著相機(jī)與錄音帐要,去河邊找鬼。 笑死弥奸,一個(gè)胖子當(dāng)著我的面吹牛榨惠,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播盛霎,決...
    沈念sama閱讀 38,997評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼赠橙,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了愤炸?” 一聲冷哼從身側(cè)響起期揪,我...
    開(kāi)封第一講書(shū)人閱讀 37,741評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎规个,沒(méi)想到半個(gè)月后凤薛,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,203評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡诞仓,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,534評(píng)論 2 327
  • 正文 我和宋清朗相戀三年缤苫,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片墅拭。...
    茶點(diǎn)故事閱讀 38,673評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡活玲,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出谍婉,到底是詐尸還是另有隱情翼虫,我是刑警寧澤,帶...
    沈念sama閱讀 34,339評(píng)論 4 330
  • 正文 年R本政府宣布屡萤,位于F島的核電站,受9級(jí)特大地震影響掸宛,放射性物質(zhì)發(fā)生泄漏死陆。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,955評(píng)論 3 313
  • 文/蒙蒙 一唧瘾、第九天 我趴在偏房一處隱蔽的房頂上張望措译。 院中可真熱鬧,春花似錦饰序、人聲如沸领虹。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,770評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)塌衰。三九已至诉稍,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間最疆,已是汗流浹背杯巨。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,000評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留努酸,地道東北人服爷。 一個(gè)月前我還...
    沈念sama閱讀 46,394評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像获诈,于是被迫代替她去往敵國(guó)和親仍源。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,562評(píng)論 2 349

推薦閱讀更多精彩內(nèi)容