天天看點

Android系統源碼閱讀(8):Content Provider資料傳輸過程Android系統源碼閱讀(8):Content Provider資料傳輸過程

Android系統源碼閱讀(8):Content Provider資料傳輸過程

該系列隻記錄閱讀代碼時遇到的問題和心得體會,具體代碼講解可以參考老羅的《Android系統源代碼情景分析》,我就不班門弄斧了。我編譯的AOSP版本:6.0.1_r50。
  • Android系統源碼閱讀8Content Provider資料傳輸過程
    • 使用者開始查詢
    • Content Provider處理事務
    • Provider建立window的native過程
    • Provider填充window的native過程

1. 使用者開始查詢

Android系統源碼閱讀(8):Content Provider資料傳輸過程Android系統源碼閱讀(8):Content Provider資料傳輸過程

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處理事務

Android系統源碼閱讀(8):Content Provider資料傳輸過程Android系統源碼閱讀(8):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過程

Android系統源碼閱讀(8):Content Provider資料傳輸過程Android系統源碼閱讀(8):Content Provider資料傳輸過程

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過程

Android系統源碼閱讀(8):Content Provider資料傳輸過程Android系統源碼閱讀(8):Content Provider資料傳輸過程

1. 在2.11中,會對步驟3中建立的window進行填充。這一步會獲得一個SQLiteConnection對象,然後通過這個connection進行資料庫操作。

2. 這裡開始調用native code執行資料查詢,同時填充window。

3. 這裡會通過sqlite3一行一行的将資料copy入window,這裡暫不深究sqlite3如何在c++中的使用過程。