一、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()函數來通知它們監控的數據發生變化了