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開始。
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsICOzkjN1IDMyIjMwkDM2EDMy8CX0Vmbu4GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.jpg)
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處理請求
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. 新程序的啟動
這裡的啟動過程和原來一樣。
4. ActivityManager處理新的程序
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在新程序中啟動
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
1. 這一步會将ActivityManager利用獲得的ContentProviderHolder對記錄的ContentProviderRecord的provider進行填充,同時将該ContentProviderRecord放入mProviderMap。最後将該Record移除mLaunchingProviders。在2.2中等待的ActivityManagerService線程循環等待發現provider不為null,退出循環,傳回ContentProviderHolder給使用者(見1.3)。