天天看點

Android系統源碼閱讀(7):Content Provider的啟動Android系統源碼閱讀(7):Content Provider的啟動

Android系統源碼閱讀(7):Content Provider的啟動

該系列隻記錄閱讀代碼時遇到的問題和心得體會,具體代碼講解可以參考老羅的《Android系統源代碼情景分析》,我就不班門弄斧了。我編譯的AOSP版本:6.0.1_r50。
  • Android系統源碼閱讀7Content Provider的啟動
    • 基本知識
    • 使用者開始調用Provider
    • ActivityManager處理請求
    • 新程序的啟動
    • ActivityManager處理新的程序
    • Content Provider在新程序中啟動
    • ActivityManager釋出Provider

基本知識

  • Content Provider運作在一個獨立的應用程式程序中,它本事就是一個Android應用程式。
  • Binder程序間通信隻适合傳遞體積較小的資料結構,不适合大量資料的傳輸。是以需要采用匿名共享記憶體來傳輸體積較大的資料。
  • Cursor對象通過匿名共享記憶體來傳輸資料,而Bundle是通過Binder傳遞資料。

1. 使用者開始調用Provider

首先,Activity內建的ContextWrapper中有成員函數

getContentResolver

,用該函數可以獲得一個ContentResolver對象。該ContentResolver對象是在ContextImpl對象建立時建立的一個ApplicationContentResolver對象。

下面從ContentResolver.acquireProvider開始。

Android系統源碼閱讀(7):Content Provider的啟動Android系統源碼閱讀(7):Content Provider的啟動

1. 步驟1的主要目的是驗證URI是否正确,然後就會将acquireProvider的任務交給子類來實作,這裡它将任務傳遞給ApplicationContentResolver。

2. 步驟2直接将任務給主線程處理。

3. 步驟3将會嘗試從已有的Provider中擷取目标Provider,ActivityThread将已經通路過的Provider放入mProviderMap中,如果其中含有需要擷取的Provider,隻需要增加對其的引用數目即可。如果沒有,則需要請求ActivityManager來擷取Provider(見1.4),ActivityManager最後會傳回一個ContentProviderHolder(見2.2,見6.1)。最後,需要将獲得的ContentProviderHolder進行install(見1.5)。

4. 這裡假設沒有現成的Provider,則需要交給ActivityManager進行處理。

5. 這一步和5.7是一樣的函數,差別在于這裡的holder不為null,是以不需要自己通過類加載建立Provider,隻需要将這個Provider放入mProviderRefCountMap中,對其引用加1。

2. ActivityManager處理請求

Android系統源碼閱讀(7):Content Provider的啟動Android系統源碼閱讀(7):Content Provider的啟動

1. 這一步檢驗調用者caller是否為空,如果為空,則說明沒有應用在請求Provider,則無需繼續進行。

2. 這一步所做的處理比較多。首先,Manager首先根據name在mProviderMap中查找是否已經啟動。如果沒有,則根據Class來查找是否已經啟動。如果仍然沒有,則建構

ContentProviderRecord

,裡面包含了

ProviderInfo

,

ApplicationInfo

等重要資訊。然後,如果是multiprocess屬性為

true

,則将該

ContentProviderRecord

直接傳回給調用者,讓其執行個體化。在我們的例子中,我們假設該屬性為false,需要建立新的程序來啟動該Provider。下面就要開始啟動新的程序,會在2.3中詳細講述,然後将Record放入mProvider。最後,ActivityManager進入循環等待provider啟動,在發現provider啟動後(見6.1),則退出循環,将ContentProviderHolder傳回給使用者(見1.3)。

3. 這一步就是進入啟動新程序的準備工作。

3. 新程序的啟動

Android系統源碼閱讀(7):Content Provider的啟動Android系統源碼閱讀(7):Content Provider的啟動

這裡的啟動過程和原來一樣。

4. ActivityManager處理新的程序

Android系統源碼閱讀(7):Content Provider的啟動Android系統源碼閱讀(7):Content Provider的啟動

1. 擷取新程序pid。

2. 這一步先根據pid獲得對應的ProcessRecord,然後填充ProcessRecord的資訊。然後,擷取需要在該程序中啟動的Provider的清單,将在4.3中詳解。接下來依次啟動該程序中的Content Provider(在4.4中詳解)、Activity、Service和Broadcast Receiver。

3. 這一步通過PackageManager獲得所有的該應用程序下需要啟動的Provider,然後為其建立ContentProviderRecord,放入mProviderMap。

4. 準備向新程序發送消息。

5. Content Provider在新程序中啟動

Android系統源碼閱讀(7):Content Provider的啟動Android系統源碼閱讀(7):Content Provider的啟動

1. 将收到的資料封裝成一個AppBindData,準備發送到主線程中。

2. 發送消息。

3. 發送消息。

4. 處理異步消息。

5. 準備啟動所有的Provider。

6. 這一步将傳遞過來的每一個

ProviderInfo

通過

installProvider

函數(見5.7)封裝成了

ContentProviderHolder

。然後将所有生成的

ContentProviderHolder

告知給ActivityManager(見5.11)。

7. 這一步根據Provider的類名,使用ClassLoader執行個體化一個ContentProvider對象,并對其進行一定的初始化(見5.8、5.9)工作。然後,建立對應的ProviderClientRecord,将其放入mLocalProviders和mLocalProvidersByName。

8. 擷取該Provider的類型為Transport的Binder本地對象。這個Binder将會告知給ActivityManagerService,然後有它再告知給需要使用該Provider的其它元件。然後其它程序元件就可以使用這個Binder來使用這個provider了。

9. 這裡會設定該provider的context,同時設定讀寫權限。最後會調用重寫的onCreate函數。

10. 調用自己實作的onCreate函數。

11. 将自己的Provider告知給ActivityManager。

6. ActivityManager釋出Provider

Android系統源碼閱讀(7):Content Provider的啟動Android系統源碼閱讀(7):Content Provider的啟動

1. 這一步會将ActivityManager利用獲得的ContentProviderHolder對記錄的ContentProviderRecord的provider進行填充,同時将該ContentProviderRecord放入mProviderMap。最後将該Record移除mLaunchingProviders。在2.2中等待的ActivityManagerService線程循環等待發現provider不為null,退出循環,傳回ContentProviderHolder給使用者(見1.3)。