Android系統源碼閱讀(8):Content Provider資料傳輸過程
該系列隻記錄閱讀代碼時遇到的問題和心得體會,具體代碼講解可以參考老羅的《Android系統源代碼情景分析》,我就不班門弄斧了。我編譯的AOSP版本:6.0.1_r50。
- Android系統源碼閱讀8Content Provider資料傳輸過程
- 使用者開始查詢
- Content Provider處理事務
- Provider建立window的native過程
- Provider填充window的native過程
1. 使用者開始查詢
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIiN3YDOzMDNxITNwkDM2EDMy8CX0Vmbu4GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.jpg)
1. 使用者調用
query
函數進行查詢。首先嘗試獲得provider,這裡分為兩種,先是unstable,後是stable,暫時沒有厘清這兩者之間的差別。在嘗試擷取Provider的過程中,将會類似于第7篇文章中的過程。這裡假設該使用者已經有該provider的記錄,擷取過程見1.2。在取得provider後,見1.5。
2. 繼續擷取Provider。
3. 繼續擷取Provider。
4. ActivityThread将所有已經獲得的Provider放在mProviderMap中。這裡假設需要擷取的Provider存在,傳回一個
IContentProvider
類型的provider,這個接口指向了Content Provider的一個Transport代理對象,即ContentProviderProxy對象。
5. 使用provider的代理進行查詢。這裡會建立一個
BulkCursorToCursorAdaptor
對象。該版本沒有建立CursorWindow對象,即沒有建立匿名記憶體,和舊版本有些差別。那麼,新版本中在哪裡建立共享的記憶體區呢?最後,準備通過程序間通信發送消息,等待傳回的BulkCursorDescriptor,然後可以獲得對應的BulkCursorToCursorAdaptor,即一個AbstractWindowedCursor。
2. Content Provider處理事務
1. 該函數負責處理
QUERY_TRANSACTION
事務。首先将傳入的資料解析出來,然後利用其子類Transport進行查詢,從2.2~2.6,獲得一個SQLiteCursor對象。然後用SQLiteCursor封裝成CursorToBulkCursorAdapter對象。然後建立BulkCursorDescriptor,從2.7~2.11,目的就是建立window,将資料放入window。然後将BulkCursorDescriptor存入reply,裡面包含了SQLiteCursor的binder本地對象,因為SQLiteCursor裡又含有window,最後傳回給使用者後,使用者可以獲得window裡存儲的内容。
2. 這裡會檢查使用者是否有權限通路該資料,如果有權限,則調用自己實作的ContentProvider子類的query函數進行查詢。
3. 該函數需要在子類中重載,實作自己的查詢過程。這裡,我們假設使用了資料庫查詢。
4. 這裡會首先根據傳入的參數建立一條SQL查詢語句,然後在資料庫中進行查詢。
5. 這一步會建立一個資料查詢driver,用來執行查詢。
6. 建立一個SQLiteCursor對象,這個對象包含了database、driver、query。下面就是将SQLiteCursor傳回,一直傳回到2.1中。
7. 該步驟會對建立的BulkCursorDescriptor進行一定的初始化。
8. 獲得使用者需要的資料條數。開始時為-1,說明尚未執行查詢過程,是以下面要執行查詢資料,同時将資料放入記憶體共享區window。
9. 因為window還沒建立,是以第一件事是先建立共享記憶體區window,見2.10。然後填充window,見2.11。
10. 這一步會建立新的window或者清空舊的window以重複利用。這裡的window以資料庫的路徑為名稱。建立CursorWindow的過程會調用native函數,見3.1~3.3,是以,新的Android版本放棄了原來在使用者中建立window的模式,而是在Content Provider中統一建立、管理window。
11. 填充window,這裡同樣會使用sql的一些方法,最後落腳于調用native函數,見4.1~4.3。執行到這裡,需要查詢的資料已經被存儲于window中。
3. Provider建立window的native過程
1. 在2.10中,會建立CursorWindow對象,是以,SQLiteCursor調用了CursorWindow的構造函數。在該步驟中,會設定window的大小,該大小會在資源檔案xml中設定。然後建立window的過程就交給c++代碼完成。
2.
android_database_CursorWindow.cpp
位于frameworks/base/core/jni/目錄下。這裡會建立一個CursorWindow對象window,見3.3。然後用
reinterpret_cast
函數将window指針類型變為jlong傳回。
3. 這裡就會建立匿名記憶體塊。這裡使用了匿名記憶體配置設定的機制,暫不深究。
4. Provider填充window的native過程
1. 在2.11中,會對步驟3中建立的window進行填充。這一步會獲得一個SQLiteConnection對象,然後通過這個connection進行資料庫操作。
2. 這裡開始調用native code執行資料查詢,同時填充window。
3. 這裡會通過sqlite3一行一行的将資料copy入window,這裡暫不深究sqlite3如何在c++中的使用過程。