Android 系統ContentProvider流程

一、ContentProvider初始化注冊流程

源碼查看路徑:http://xrefandroid.com/android-11.0.0_r48/
涉及到源碼文件:
/frameworks/base/core/java/android/content/ContentProvider.java
自定義ContentProvider需要繼承該類,內部類Transport繼承關系如下,實現了aidl 接口 IContentProvider,提供增刪改查注冊監聽操作
ContentProvider.Transport -> ContentProviderNative -> IContentProvider
客戶端通過獲取aidl binder對象,調用注冊的ContentProvider接口
ContentProvider.getIContentProvider 返回創建的aidl 實現Transport對象

/frameworks/base/core/java/android/app/ContentProviderHolder.java
ContentProviderHolder繼承Parcelable 通過序列化支持跨進程傳輸.
ContentProviderHolder.provider 存儲 ContentProvider 的 Binder 接口(IContentProvider)
ContentProviderHolder.info ? 存儲當前ContentProvider的組件信息ProviderInfo

/frameworks/base/services/core/java/com/android/server/content/ContentService.java
作為系統級觀察者模型的核心組件,允許應用通過注冊 ContentObserver 監聽指定 URI 的數據變更(如聯系人、短信、設置等),并在數據更新時異步通知所有訂閱者,實現跨進程數據同步。

/frameworks/base/core/java/android/database/ContentObserver.java
ContentObserver.Transport 繼承 IContentObserver.Stub ?ContentProvider服務端通過此 binder 對象通知客戶端用戶數據發生變化

/frameworks/base/services/core/java/com/android/server/am/ContentProviderRecord.java
存儲 ContentProvider 的 Binder 對象(如 IContentProvider)、所屬進程(ProcessRecord)及權限配置(如 readPermission)
記錄 ContentProvider 的啟動狀態(如已綁定、已發布)
ContentProviderRecord.provider 存儲 ContentProvider 的 Binder 接口(IContentProvider)

/frameworks/base/core/java/android/content/pm/ProviderInfo.java
繼承自 ComponentInfo,定義 ContentProvider 的組件信息,包括包名、類名、權限(如 readPermission/writePermission)、路徑匹配規則(pathPattern)等。
在 AndroidManifest.xml 中通過 <provider> 標簽聲明,由 PMS(PackageManagerService)解析后生成內存對象。

/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
/frameworks/base/services/core/java/com/android/server/pm/ComponentResolver.java
解析所有Android組件類型activities, services, providers 和 receivers

由Android系統啟動流程可知SystemServer進程啟動時,會調用SystemServer.startBootstrapServices 啟動系統Boot級別服務,該方法會啟動ams。
還會調用SystemServer.startOtherServices 該方法會mActivityManagerService.installSystemProviders()來解析所以注冊的ContentProvider
ActivityManagerService.installSystemProviders() 中調用如下2步,
1.從pms中獲取ContentProvider列表
從AMS的processList中找到進程為"system"且uid="SYSTEM_UID"的ProcessRecord,
然后從系統進程中獲取所有ContentProvider ,具體是調用
ActivityManagerService.generateApplicationProvidersLocked(ProcessRecord app) ?執行2步
1.1 調用 List<ProviderInfo> providers = ppGlobals.getPackageManager().queryContentProviders(app.processName,...) 獲取ProviderInfo列表
ApplicationPackageManager.queryContentProviders(String processName,int uid, int flags,null) 調用 slice = mPM.queryContentProviders(processName, ...) 通過aidl調用pms接口
PackageManagerService.queryContentProviders(String processName,...) 調用matchList =mComponentResolver.queryProviders(processName,...)
ComponentResolver.queryProviders(String processName,...) 遍歷 mProviders.mProviders 中的ParsedProvider 如果進程和當前請求進程一致添加到providerList然后返回
ps:mProviders.mProviders 是開機PackageManagerService(PMS)掃描應用安裝包(APK)后,將解析出的應用信息添加到mProviders中的。
1.2 將 ProviderInfo列表 封裝到 ContentProviderRecord 然后添加到 ProcessRecord.pubProviders 。

2.調用mSystemThread.installSystemProviders(providers) 發布providers
ActivityThread.installSystemProviders(List<ProviderInfo> providers) ?調用 installContentProviders(mInitialApplication, providers)
ActivityThread.installContentProviders(Context context, List<ProviderInfo> providers) 主要執行如下兩步
2.1 遍歷providers列表對象ProviderInfo.
生成 ContentProviderHolder 對象(包含 ContentProvider 的 Binder 接口 IContentProvider) 列表,用于跨進程通信時傳遞數據提供實例,
具體是調用:?
cph = installProvider(context, null, cpi,false /*noisy*/, true /*noReleaseNeeded*/, true /*stable*/)
ActivityThread.installProvider(.., ProviderInfo info,...) 創建當前應用注冊的 ContentProvider 實例,并完成其初始化操作
基于ContentProvider名稱創建ContentProvider實現類對象, localProvider = packageInfo.getAppFactory().instantiateProvider(cl, info.name)
然后獲取ContentProvider中的binder對象賦值給 ?holder.provider = provider, 調用 provider = localProvider.getIContentProvider() 返回binder 對象 ContentProvider.mTransport.
installProvider方法最后返回ContentProviderHolder對象 holder.
然后將 獲取的ContentProviderHolder添加到ContentProviderHolder列表對象results,調用 results.add(cph)
2.2 將ContentProviderHolder列表發布到ams
具體是調用:ActivityManager.getService().publishContentProviders(getApplicationThread(), results)
ActivityManagerService.publishContentProviders(IApplicationThread caller,List<ContentProviderHolder> providers)
遍歷ContentProviderHolder列表providers 中 ContentProviderHolder對象src
?? ?基于ContentProviderHolder 從ProcessRecord.pubProviders 獲取ContentProviderRecord對象dst,然后添加到ActivityManagerService.mProviderMap,
?? ?調用mProviderMap.putProviderByClass(comp, dst),mProviderMap.putProviderByName(names[j], dst)
?? ?初始化 ContentProviderRecord.provider 調用dst.provider = src.provider.ContentProviderRecord.provider為ContentProvider 的 Binder 接口。

總結:?? ?先從pms獲取ContentProvider基本信息創建 ContentProvider實現類對象,然后將ContentProvider 的 Binder 接口對象封裝到 ProcessRecord.pubProviders
供應客戶端aidl調用


二、ContentResolver調用ContentProvider接口流程

1.查詢接口
1.1 獲取ContentResolver對象(ContextImpl.ApplicationContentResolver對象) ?
調用 ContentResolver cr = getContentResolver() 獲取ContentResolver為ApplicationContentResolver對象
ContextWrapper.getContentResolver() 調用 mBase.getContentResolver()
ContextImpl.getContentResolver() ?返回mContentResolver
mContentResolver是 ContextImpl.ContextImpl構造方法中調用mContentResolver = new ApplicationContentResolver(this, mainThread)
ContextImpl.ApplicationContentResolver繼承ContentResolver?
1.2 查詢
cr.query(uri, null, null, null, null) 從上可知cr為ContextImpl.ApplicationContentResolver
ContentResolver.query(Uri uri,...) ?調用 如下2幾步:
#1.獲取對應的IContentProvider
調用IContentProvider unstableProvider = acquireUnstableProvider(uri) ,基于uri獲取對應ContentProvider的aidl 接口實現的binder。
ContentResolver.acquireUnstableProvider(Uri uri) 調用acquireUnstableProvider(mContext, uri.getAuthority()
ContextImpl.ApplicationContentResolver.acquireUnstableProvider(Context c, String auth) ? 調用 mMainThread.acquireProvider(c,ContentProvider.getAuthorityWithoutUserId(auth),resolveUserIdFromAuthority(auth), false)
ActivityThread.acquireProvider(Context c, String auth, int userId, boolean stable) 獲取holder.provider,holder獲取流程如下:
調用holder = ActivityManager.getService().getContentProvider(getApplicationThread(), c.getOpPackageName(), auth, userId, stable)
ActivityManagerService.getContentProvider(....) 調用getContentProviderImpl(caller, name,...)
ActivityManagerService.getContentProviderImpl(...) 該方法返回ContentProviderHolder對象
根據調用方請求的 ContentProvider 的 authority(如 com.example.provider),遍歷系統已注冊的 ProviderInfo 列表,匹配到對應的組件信息。
若目標 ContentProvider 尚未啟動(未綁定到宿主進程),則觸發其宿主進程的啟動流程(如通過 startProcessLocked 方法),并等待其初始化完成。
通過 IContentProvider 接口封裝 ContentProvider 的 Binder 通信句柄,返回 ContentProviderHolder 對象給調用方(如 ContentResolver),作為后續數據操作(query、insert 等)的通道

#2.調用qCursor = unstableProvider.query(mPackageName, mAttributionTag, uri, projection,queryArgs, remoteCancellationSignal)
因為 unstableProvider是基于uri獲取對應ContentProvider的aidl 接口實現的binder。
即通過aidl 調用服務端創建的 ContentProvider.query 方法.

其他增刪改流程同上。

2.監聽接口
2.1注冊監聽
cr.registerContentObserver(uri, true, ContentObserver類對象)
ContentResolver.registerContentObserver(Uri uri, boolean notifyForDescendents,ContentObserver observer, int userHandle) 該方法
調用getContentService().registerContentObserver(uri, notifyForDescendents,observer.getContentObserver(), userHandle, mTargetSdkVersion)
getContentService方法返回 ContentService 對象的binder IContentService,即調用
ContentService.registerContentObserver(Uri uri, ...) 調用 mRootNode.addObserverLocked(uri, ...)?
ContentService.addObserverLocked(Uri uri, ...)?
例如uri為content://com.android.mycontentprovider/contact
?最終我們得到ObserverNode的樹形結構如下所示:
? ? ? ? mRootNode("")
? ? ? ? ? ? -- ObserverNode("com.android.mycontentprovider")
? ? ? ? ? ? ? ? --ObserverNode("contact") ,
2.2. 監聽回調
例如uri為 content://com.android.mycontentprovider/contact/d
getContext().getContentResolver().notifyChange(uri, null)?? ??? ? 調用notifyChange(uri, observer, true /* sync to network */);
ContentResolver.notifyChange(Uri uri, ContentObserver observer,boolean syncToNetwork) 調用notifyChange(uri, observer, syncToNetwork ? NOTIFY_SYNC_TO_NETWORK : 0)
ContentResolver.notifyChange(Uri uri, ContentObserver observer,int flags) 調用notifyChange(ContentProvider.getUriWithoutUserId(uri),observer,flags,ContentProvider.getUserIdFromUri(uri, mContext.getUserId()))
ContentResolver.notifyChange(Uri uri, ContentObserver observer, int flags,int userHandle) 調用notifyChange(new Uri[] { uri }, observer, flags, userHandle)
ContentResolver.notifyChange(Uri[] uris, ContentObserver observer, int flags,int userHandle) 調用getContentService().notifyChange(uris, observer == null ? null : observer.getContentObserver(),...)
ContentService.notifyChange(Uri[] uris, IContentObserver observer,...)?
1.調用ContentService的成員變量mRootNode的collectObserverLocked()函數來收集那些注冊了監控"content://com.android.mycontentprovider/contact/d"這個URI的ContentObserver,
2.調用了這些ContentObserver的onChange()函數來通知它們監控的數據發生變化了

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/73864.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/73864.shtml
英文地址,請注明出處:http://en.pswp.cn/web/73864.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

爬蟲工程師分享自動批量化獲取商品評論數據的方法有哪些?

在電商領域&#xff0c;商品評論數據對于商家了解產品口碑、洞悉用戶需求&#xff0c;以及開展競品分析等工作具有極其重要的價值。作為爬蟲工程師&#xff0c;掌握自動批量化獲取商品評論數據的方法&#xff0c;能極大提升數據收集效率。下面&#xff0c;我將分享一些實用的操…

Vue3組件事件用戶信息卡練習

用戶信息卡 題目要求 實現一個用戶信息卡系統&#xff0c;包含以下功能&#xff1a; 1.父組件收集用戶信息&#xff08;姓名、年齡、班級&#xff09; 2.子組件接收并展示用戶信息卡片 3.添加基本的數據驗證 <!DOCTYPE html> <html lang"en"> <h…

SpringBean模塊(二)bean初始化(2)和容器初始化順序的比較--引入ApplicationContextInitializer

前面介紹了獲取容器可以讓spring bean實現ApplicationContextAware&#xff0c;實際也是初始化執行了setApplicationContext接口&#xff0c; 初始化接口還可以借助一些注解或者spring bean的初始化方法&#xff0c;那么他們的執行順序是什么樣的呢&#xff1f; 一、驗證&…

中小型企業網絡的搭建

1.1 網絡邏輯拓撲、布線方案的設計 1.1.1 網絡設計依據 網絡設計應遵循以下基本原則&#xff1a; 高效性&#xff1a;確保網絡架構能夠支持企業日常業務的高效運行。 可靠性&#xff1a;采用冗余設計&#xff0c;確保網絡的高可用性&#xff0c;避免單點故障。 可擴展性…

angr基礎學習

參考&#xff1a;angr AngrCTF_FITM/筆記/03/Angr_CTF從入門到精通&#xff08;三&#xff09;.md at master ZERO-A-ONE/AngrCTF_FITM angr_explore 00_angr_find IDA分析結果&#xff1a; 邏輯簡單&#xff0c;輸入&#xff0c;complex_function進行加密&#xff0c;加密…

軟考-高級-系統架構設計師【考試備考資料下載】

計算機技術與軟件專業技術資格&#xff08;水平&#xff09;考試是原中國計算機軟件專業技術資格和水平考試的完善與發展。計算機技術與軟件專業技術資格&#xff08;水平&#xff09;考試是由國家人力資源和社會保障部、工業和信息化部領導下的國家級考試。 計算機技術與軟件專…

3. 第三放平臺部署deepseek

有時候我們會發現使用deepseek服務器&#xff0c;異常卡頓&#xff0c;這是由于多方面原因造成的&#xff0c;比如說訪問人數過多等。想要解決這個問題&#xff0c;我們可以選擇第三方平臺進行部署 第三方平臺 我們可以選擇的第三方平臺很多&#xff0c;比如硅基流動、秘塔搜索…

1.4-蜜罐\堡壘機\API接口

1.4-蜜罐\堡壘機\API接口 蜜罐&#xff1a;用來釣魚或誘惑測試人員的防護系統 bash <(curl -sS -L https://hfish.net/webinstall.sh) # 安裝HFISH蜜罐堡壘機&#xff1a; 運維用的&#xff0c;統一管理運維平臺;拿下堡壘機就很有可能等于拿下了多個平臺 jumpServer一鍵安…

知識圖引導的檢索增強生成

摘要 檢索增強生成&#xff08;RAG&#xff09;已經成為一種很有前途的技術&#xff0c;用于解決大型語言模型&#xff08;LLM&#xff09;生成的響應中的幻覺問題。現有的RAG研究主要集中在應用基于語義的方法來提取孤立的相關組塊&#xff0c;忽略了它們之間的內在關系。在本…

【機器學習】imagenet2012 數據預處理數據預處理

【機器學習】數據預處理 1. 下載/解壓數據2. 數據預處理3. 加載以及訓練代碼3.1 使用PIL等加載代碼3.2 使用OpenCV的方式來一張張加載代碼3.3 h5的方式來加載大文件 最后總結 這個數據大約 140個G,128w的訓練集 1. 下載/解壓數據 首先需要下載數據&#xff1a; 數據最后處理…

質量工程:數字化轉型時代的質量體系重構

前言&#xff1a;質量理念的范式轉移閱讀原文 如果把軟件開發比作建造摩天大樓&#xff1a; 傳統測試 竣工后檢查裂縫&#xff08;高成本返工&#xff09; 質量工程 從地基開始的全流程監理體系&#xff08;設計圖紙→施工工藝→建材選擇→竣工驗收&#xff09; IEEE研究…

【全棧開發】—— Paddle OCR 文字識別 + deepseek接入(基于python 最新!!!)

所有源碼都在文章中&#xff0c;大家不要私信來要源碼&#xff0c;當然&#xff0c;評論區歡迎交流技術 目錄 Paddle OCR 配置環境 示例 deepseek接入 環境配置 api 調用代碼 sliconflow Paddle OCR 配置環境 清華源下載 paddlepaddle&#xff1a; pip install paddlepaddle …

SAIL-RK3588J 核心板技術方案——高精度裝配式建筑機器人控制?

&#xff08;本方案契合《建筑機器人產業目錄》政策要求&#xff09; 一、方案背景與政策支持? ?政策驅動? 2025年2月《建筑機器人產業目錄》明確將?“高精度建筑機器人控制設備”?納入重點補貼范圍&#xff0c;要求定位精度≤0.5mm、支持實時質檢與多機協同&#xff0c…

OpenAI API - 快速入門開發

文章目錄 開發者快速入門分析圖像輸入使用工具擴展模型提供閃電般的 AI 體驗構建代理進一步探索 模型精選模型推理模型旗艦聊天模型成本優化模型實時模型舊版 GPT 模型DALLE文本轉語音轉寫嵌入調度工具特定模型GPT 基礎模型 Libraries創建和導出 API 密鑰安裝官方 SDKJavaScrip…

藍橋杯省賽 棋盤 3533 二維差分+二維前綴和

傳送門 0棋盤 - 藍橋云課 const int N 2e3 10;int n,m; int a[N][N];void insert(int x11,int y11,int x22,int y22) {a[x11][y11] ;a[x11][y22 1] --;a[x22 1][y11] --;a[x22 1][y22 1] ; }void solve() {cin >> n >> m;for (int i 1;i < m;i ){int x11…

《C++Linux編程進階:從0實現muduo 》-第6講.C++死鎖問題如何分析調試-原子操作,互斥量,條件變量的封裝

重點內容 視頻講解&#xff1a;《CLinux編程進階&#xff1a;從0實現muduo C網絡框架系列》-第6講.C死鎖問題如何分析調試-原子操作,互斥量,條件變量的封裝 代碼改動 lesson6代碼 實現&#xff1a;base/Atomic.h 實現&#xff1a;base/Mutex.h 實現&#xff1a;base/Condit…

洛谷題單1-P5708 【深基2.習2】三角形面積-python-流程圖重構

題目描述 一個三角形的三邊長分別是 a a a、 b b b、 c c c&#xff0c;那么它的面積為 p ( p ? a ) ( p ? b ) ( p ? c ) \sqrt{p(p-a)(p-b)(p-c)} p(p?a)(p?b)(p?c) ?&#xff0c;其中 p 1 2 ( a b c ) p\frac{1}{2}(abc) p21?(abc)。輸入這三個數字&#xff…

matplotlib標題比x,y軸字體大,明明標題字體更大?

原始代碼&#xff1a; plt.xlabel(訓練輪次&#xff08;Epochs&#xff09;, fontsize14, fontweightbold, fontpropertieschinese_font) # 設置中文字體、加大、加粗 plt.ylabel(R值, fontsize14, fontweightbold, fontpropertieschinese_font) # 設置中文字體、加大、加粗…

Baklib內容中臺的核心優勢是什么?

智能化知識管理引擎 Baklib的智能化知識管理引擎通過多源數據整合與智能分類技術&#xff0c;實現企業知識資產的自動化歸集與動態更新。系統內置的語義分析算法可自動識別文檔主題&#xff0c;結合自然語言處理技術生成結構化標簽體系&#xff0c;大幅降低人工標注成本。針對…

Android學習總結之ContentProvider跨應用數據共享

在 Android 開發中&#xff0c;跨應用數據共享是構建開放生態的關鍵需求。作為四大組件之一&#xff0c;ContentProvider通過標準化接口和安全機制&#xff0c;成為實現這一需求的核心樞紐。本文將圍繞其生命周期方法、核心機制、自定義實現及最佳實踐展開&#xff0c;幫助開發…