還記得Settings數據庫嗎?SystemServer中很多Service都需要向它查詢配置信息。為此,Android提供了一個SettingsProvider來幫助開發者。該Provider在SettingsProvider.apk中,installSystemProviders就會加載該APK并把SettingsProvider放到SystemServer進程中來運行。
此時的SystemServer已經加載了framework-res.apk,現在又要加載另外一個APK文件,這就是多個APK運行在同一進程的典型案例。另外,通過installSystemProviders函數還能見識ContentProvider的安裝過程,下面就來分析它。
* * * * *
**提示**:讀者在定制自己的Android系統時,萬不可去掉/system/app/SettingsProvider.apk,否則系統將無法正常啟動。
* * * * *
**ActivityManagerService.java::installSystemProviders**
~~~
public static final void installSystemProviders(){
List<ProviderInfo> providers;
synchronized (mSelf) {
/*
從mProcessNames找到進程名為“system”且uid為SYSTEM_UID的ProcessRecord,
返回值就是前面在installSystemApplication中創建的那個ProcessRecord,它代表
SystemServer進程
*/
ProcessRecord app = mSelf.mProcessNames.get("system",Process.SYSTEM_UID);
//①關鍵調用,見下文分析
providers= mSelf.generateApplicationProvidersLocked(app);
if(providers != null) {
......//將非系統APK(即未設ApplicationInfo.FLAG_SYSTEM標志)提供的Provider
//從providers列表中去掉
}
if(providers != null) {//②為SystemServer進程安裝Provider
mSystemThread.installSystemProviders(providers);
}
//監視Settings數據庫中Secure表的變化,目前只關注long_press_timeout配置的變化
mSelf.mCoreSettingsObserver = new CoreSettingsObserver(mSelf);
//UsageStatsService的工作,以后再討論
mSelf.mUsageStatsService.monitorPackages();
}
~~~
在代碼中列出了兩個關鍵調用,分別是:
- 調用generateApplicationProvidersLocked函數,該函數返回一個ProviderInfo List。
- 調用ActivityThread的installSystemProviders函數。ActivityThread可以看做是進程的Android運行環境,那么installSystemProviders表示為該進程安裝ContentProvider。
* * * * *
**注意**:此處不再區分系統進程還是應用進程。由于只和ActivityThread交互,因此它運行在什么進程無關緊要。
* * * * *
下面來看第一個關鍵點generateApplicationProvidersLocked函數。
1. AMS的 generateApplicationProvidersLocked函數分析
**ActivityManagerService.java::generateApplicationProvidersLocked**
~~~
private final List<ProviderInfo> generateApplicationProvidersLocked(
ProcessRecordapp) {
List<ProviderInfo> providers = null;
try {
//①向PKMS查詢滿足要求的ProviderInfo,最重要的查詢條件包括:進程名和進程uid
providers = AppGlobals.getPackageManager().
queryContentProviders(app.processName, app.info.uid,
STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
} ......
if(providers != null) {
finalint N = providers.size();
for(int i=0; i<N; i++) {
//②AMS對ContentProvider的管理,見下文解釋
ProviderInfo cpi = (ProviderInfo)providers.get(i);
ComponentName comp = new ComponentName(cpi.packageName, cpi.name);
ContentProviderRecord cpr = mProvidersByClass.get(comp);
if(cpr == null) {
cpr = new ContentProviderRecord(cpi, app.info, comp);
//ContentProvider在AMS中用ContentProviderRecord來表示
mProvidersByClass.put(comp, cpr);//保存到AMS的mProvidersByClass中
}
//將信息也保存到ProcessRecord中
app.pubProviders.put(cpi.name, cpr);
//保存PackageName到ProcessRecord中
app.addPackage(cpi.applicationInfo.packageName);
//對該APK進行dex優化
ensurePackageDexOpt(cpi.applicationInfo.packageName);
}
}
returnproviders;
}
~~~
由以上代碼可知:generateApplicationProvidersLocked先從PKMS那里查詢滿足條件的ProviderInfo信息,而后將它們分別保存到AMS和ProcessRecord中對應的數據結構中。
先看查詢函數queryContentProviders。
(1) PMS中 queryContentProviders函數分析
**PackageManagerService.java::queryContentProviders**
~~~
public List<ProviderInfo>queryContentProviders(String processName,
int uid,int flags) {
ArrayList<ProviderInfo> finalList = null;
synchronized (mPackages) {
//還記得mProvidersByComponent的作用嗎?它以ComponentName為key,保存了
//PKMS掃描APK得到的PackageParser.Provider信息。讀者可參考圖4-8
finalIterator<PackageParser.Provider> i =
mProvidersByComponent.values().iterator();
while(i.hasNext()) {
final PackageParser.Provider p = i.next();
//下面的if語句將從這些Provider中搜索本例設置的processName為“system”,
//uid為SYSTEM_UID,flags為FLAG_SYSTEM的Provider
if (p.info.authority != null
&& (processName == null
||(p.info.processName.equals(processName)
&&p.info.applicationInfo.uid == uid))
&& mSettings.isEnabledLPr(p.info, flags)
&& (!mSafeMode || ( p.info.applicationInfo.flags
&ApplicationInfo.FLAG_SYSTEM) != 0)) {
if (finalList == null) {
finalList = newArrayList<ProviderInfo>(3);
}
//由PackageParser.Provider得到ProviderInfo,并添加到finalList中
//關于Provider類及ProviderInfo類,可參考圖4-5
finalList.add(PackageParser.generateProviderInfo(p,flags));
}
}
}
if(finalList != null)
//最終結果按provider的initOrder排序,該值用于表示初始化ContentProvider的順序
Collections.sort(finalList, mProviderInitOrderSorter);
returnfinalList;//返回最終結果
}
~~~
queryContentProviders函數很簡單,就是從PKMS那里查找滿足條件的Provider,然后生成AMS使用的ProviderInfo信息。為何偏偏能找到SettingsProvider呢?來看它的AndroidManifest.xml文件,如圖6-7所示。
:-: 
圖6-7 SettingsProvider的AndroidManifest.xml文件示意
由圖6-7可知,SettingsProvider設置了其uid為“android.uid.system”,同時在application中設置了process名為“system”。而在framework-res.apk中也做了相同的設置。所以,現在可以確認SettingsProvider將和framework-res.apk運行在同一個進程,即SystemServer中。
提示從運行效率角度來說,這樣做也是合情合理的。因為SystemServer的很多Service都依賴Settings數據庫,把它們放在同一個進程中,可以降低由于進程間通信帶來的效率損失。
(2) 關于ContentProvider的介紹
前面介紹的從PKMS那里查詢到的ProviderInfo還屬于公有財產,現在我們要將它與AMS及ProcessRecord聯系起來。
- AMS保存ProviderInfo的原因是它要管理ContentProvider。
- ProcessRecord保存ProviderInfo的原因是ContentProvider最終要落實到一個進程中。其實也是為了方便AMS管理,例如該進程一旦退出,AMS需要把其中的ContentProvider信息從系統中去除。
AMS及ProcessRecord均使用了一個新的數據結構ContentProviderRecord來管理ContentProvider信息。圖6-8展示了ContentProviderRecord相應的數據結構。
:-: 
圖6-8 ContentProvicerRecord及相應的“管理團隊”
由圖6-8可知:
- ContentProviderRecord從ContentProviderHolder派生,內部保存了ProviderInfo、該Provider所駐留的進程ProcessRecord,以及使用該ContentProvider的客戶端進程ProcessRecord(即clients成員變量)。
- AMS的mProviderByClass成員變量及ProcessRecord的pubProviders成員變量均以ComponentName為Key來保存對應的ContentProviderRecord對象。
至此,Provider信息已經保存到AMS及ProcessRecord中了。那么,下一步的工作是什么呢?
2. ActivityThread 的installSystemProviders函數分析
在AMS和ProcessRecord中都保存了Provider信息,但這些僅僅都是一些信息,并不是ContentProvider,因此下面要創建一個ContentProvider實例(即SettingsProvider對象)。該工作由ActivityThread的installSystemProviders來完成,代碼如下:
**ActivityThread.java::installSystemProviders**
~~~
public final void installSystemProviders(List<ProviderInfo>providers) {
if(providers != null)
//調用installContentProviders,第一個參數真實類型是Application
installContentProviders(mInitialApplication, providers);
}
~~~
installContentProviders這個函數是所有ContentProvider產生的必經之路,其代碼如下:
**ActivityThread.java::installContentProviders**
~~~
private void installContentProviders(
Context context, List<ProviderInfo> providers) {
finalArrayList<IActivityManager.ContentProviderHolder> results =
new ArrayList<IActivityManager.ContentProviderHolder>();
Iterator<ProviderInfo> i = providers.iterator();
while(i.hasNext()) {
ProviderInfo cpi = i.next();
//①調用installProvider函數,得到一個IContentProvider對象
IContentProvider cp = installProvider(context, null, cpi, false);
if (cp!= null) {
IActivityManager.ContentProviderHolder cph =
newIActivityManager.ContentProviderHolder(cpi);
cph.provider = cp;
//將返回的cp保存到results數組中
results.add(cph);
synchronized(mProviderMap){
//mProviderRefCountMap,;類型為HashMap<IBinder,ProviderRefCount>,
//主要通過ProviderRefCount對ContentProvider進行引用計數控制,一旦引用計數
//降為零,表示系統中沒有地方使用該ContentProvider,要考慮從系統中注銷它
mProviderRefCountMap.put(cp.asBinder(), new ProviderRefCount(10000));
}
}
}
try {
//②調用AMS的publishContentProviders注冊這些ContentProvider,第一個參數
//為ApplicationThread
ActivityManagerNative.getDefault().publishContentProviders(
getApplicationThread(), results);
} ......
}
~~~
installContentProviders實際上是標準的ContentProvider安裝時調用的程序。安裝ContentProvider包括兩方面的工作:
- 先在ActivityThread中通過installProvider得到一個ContentProvider實例。
- 向AMS發布這個ContentProvider實例。如此這般,一個APK中聲明的ContentProvider才能登上歷史舞臺,發揮其該有的作用。
* * * * *
**提示** :上述工作其實和Binder Service類似,一個Binder Service也需要先創建,然后注冊到ServiceManager中。
* * * * *
馬上來看ActivityThread的installProvider函數。
(1) ActivityThread的installProvider函數分析
**ActivityThread.java::installProvider**
~~~
private IContentProvider installProvider(Contextcontext,
IContentProvider provider, ProviderInfoinfo, boolean noisy) {
//注意本例所傳的參數:context為mInitialApplication,provider為null,info不為null,
// noisy為false
ContentProvider localProvider = null;
if(provider == null) {
Context c = null;
ApplicationInfo ai = info.applicationInfo;
/*
下面這個if判斷的作用就是為該ContentProvider找到對應的Application。
在AndroidManifest.xml中,ContentProvider是Application的子標簽,所以
ContentProvider和Application有一種對應關系。在本例中,傳入的context(
其實是mInitialApplication)代表的是framework-res.apk,而Provider代表的
是SettingsProvider。而SettingsProvider.apk所對應的Application還未創建,
所以下面的判斷語句最終會進入最后的else分支
*/
if(context.getPackageName().equals(ai.packageName)) {
c= context;
}else if (mInitialApplication != null &&
mInitialApplication.getPackageName().equals(ai.packageName)){
c = mInitialApplication;
} else {
try{
//ai.packageName應該是SettingsProvider.apk的Package,
//名為“com.android.providers.settings”
//下面將創建一個Context,指向該APK
c = context.createPackageContext(ai.packageName,
Context.CONTEXT_INCLUDE_CODE);
}
}//if(context.getPackageName().equals(ai.packageName))判斷結束
if (c == null) return null;
try {
/*
為什么一定要找到對應的Context呢?除了ContentProvider和Application的
對應關系外,還有一個決定性原因:即只有對應的Context才能加載對應APK的Java字節碼,
從而可通過反射機制生成ContentProvider實例
*/
finaljava.lang.ClassLoader cl = c.getClassLoader();
//通過Java反射機制得到真正的ContentProvider,
//此處將得到一個SettingsProvider對象
localProvider=(ContentProvider)cl.loadClass(info.name).newInstance();
//從ContentProvider中取出其mTransport成員(見下文分析)
provider =localProvider.getIContentProvider();
if (provider == null) return null;
//初始化該ContentProvider,內部會調用其onCreate函數
localProvider.attachInfo(c, info);
}......
}//if(provider == null)判斷結束
synchronized (mProviderMap) {
/*
ContentProvider必須指明一個和多個authority,在第4章曾經提到過,
在URL中host:port的組合表示一個authority。這個單詞不太好理解,可簡單
認為它用于指定ContentProvider的位置(類似網站的域名)
*/
String names[] =PATTERN_SEMICOLON.split(info.authority);
for (int i=0; i<names.length; i++) {
ProviderClientRecord pr = newProviderClientRecord(names[i],
provider, localProvider);
try {
//下面這句對linkToDeath的調用頗讓人費解,見下文分析
provider.asBinder().linkToDeath(pr, 0);
mProviderMap.put(names[i], pr);
}......
}//for循環結束
if(localProvider != null) {
// mLocalProviders用于存儲由本進程創建的ContentProvider信息
mLocalProviders.put(provider.asBinder(),
new ProviderClientRecord(null, provider, localProvider));
}
}//synchronized 結束
return provider;
}
~~~
以上代碼不算復雜,但是涉及一些數據結構和一句令人費解的對inkToDeath函數的調用。先來說說那句令人費解的調用。
在本例中,provider變量并非通過函數參數傳入,而是在本進程內部創建的。provider在本例中是Bn端(后面分析ContentProvider的getIContentProvider時即可知道),Bn端進程為Bn端設置死亡通知本身就比較奇怪。如果Bn端進程死亡,它設置的死亡通知也無法發送給自己。幸好源代碼中有句注釋:“Cache the pointer for the remote provider”。意思是如果provider參數是通過installProvider傳遞過來的(即該Provider代表遠端進程的ContentProvider,此時它應為Bp端),那么這種處理是合適的。不管怎樣,這僅僅是為了保存pointer,所以也無關宏旨。
至于代碼中涉及的數據結構,我們整理為如圖6-9所示。
:-: 
圖6-9 ActivityThread中ContentProvider涉及的數據結構
由圖6-9可知:
- ContentProvider類本身只是一個容器,而跨進程調用的支持是通過內部類Transport實現的。Transport從ContentProviderNative派生,而ContentProvider的成員變量mTransport指向該Transport對象。ContentProvider的getIContentProvider函數即返回mTransport成員變量。
- ContentProviderNative從Binder派生,并實現了IContentProvider接口。其內部類ContentProviderProxy是供客戶端使用的。
- ProviderClientRecord是ActivityThread提供的用于保存ContentProvider信息的一個數據結構。它的mLocalProvider用于保存ContentProvider對象,mProvider用于保存IContentProvider對象。另外一個成員mName用于保存該ContentProvider的一個authority。注意,ContentProvider可以定義多個authority,就好像一個網站有多個域名一樣。
至此,本例中的SettingProvider已經創建完畢,接下來的工作就是把它推向歷史舞臺——即發布該Provider。
(2) AMS的 publishContentProviders分析
publicContentProviders函數用于向AMS注冊ContentProviders,其代碼如下:
**ActivityManagerService.java::publishContentProviders**
~~~
publicfinal void publishContentProviders(IApplicationThread caller,
List<ContentProviderHolder>providers) {
......
synchronized(this){
//找到調用者所在的ProcessRecord對象
finalProcessRecord r = getRecordForAppLocked(caller);
......
finallong origId = Binder.clearCallingIdentity();
final intN = providers.size();
for (inti=0; i<N; i++) {
ContentProviderHolder src = providers.get(i);
......
//①注意:先從該ProcessRecord中找對應的ContentProviderRecord
ContentProviderRecord dst = r.pubProviders.get(src.info.name);
if(dst != null) {
ComponentName comp = newComponentName(dst.info.packageName,
dst.info.name);
//以ComponentName為key,保存到mProvidersByClass中
mProvidersByClass.put(comp, dst);
String names[] = dst.info.authority.split(";");
for (int j = 0; j < names.length; j++)
mProvidersByName.put(names[j], dst);//以authority為key,保存
//mLaunchingProviders用于保存處于啟動狀態的Provider
int NL = mLaunchingProviders.size();
int j;
for (j=0; j<NL; j++) {
if (mLaunchingProviders.get(j) ==dst) {
mLaunchingProviders.remove(j);
j--;
NL--;
}//
}//for (j=0; j<NL; j++)結束
synchronized (dst) {
dst.provider = src.provider;
dst.proc = r;
dst.notifyAll();
}//synchronized結束
updateOomAdjLocked(r);//每發布一個Provider,需要調整對應進程的oom_adj
}//for(int j = 0; j < names.length; j++)結束
}//for(int i=0; i<N; i++)結束
Binder.restoreCallingIdentity(origId);
}// synchronized(this)結束
}
~~~
這里應解釋一下publishContentProviders的工作流程:
- 先根據調用者的pid找到對應的ProcessRecord對象。
- 該ProcessRecord的pubProviders中保存了ContentProviderRecord信息。該信息由前面介紹的AMS的generateApplicationProvidersLocked函數根據Package本身的信息生成。此處將判斷要發布的ContentProvider是否由該Package聲明。
- 如果判斷返回成功,則將該ContentProvider及其對應的authority加到mProvidersByName中。注意,AMS中還有一個mProvidersByClass變量,該變量以ContentProvider的ComponentName為key,即系統提供多種方式找到某一個ContentProvider,一種是通過 authority,另一種方式就是指明ComponentName。
- mLaunchingProviders和最后的notifyAll函數用于通知那些等待ContentProvider所在進程啟動的客戶端進程。例如,進程A要查詢一個數據庫,需要通過進程B中的某個ContentProvider 來實施。如果B還未啟動,那么AMS就需要先啟動B。在這段時間內,A需要等待B啟動并注冊對應的ContentProvider。B一旦完成注冊,就需要告知A退出等待以繼續后續的查詢工作。
現在,一個SettingsProvider就算正式在系統中掛牌并注冊了,此后,和Settings數據庫相關的操作均由它來打理。
3. AMS的installSystemProviders總結
AMS的installSystemProviders函數其實就是用于啟動SettingsProvider,其中比較復雜的是ContentProvider相關的數據結構,讀者可參考圖6-9。
- 前言
- 第1章 搭建Android源碼工作環境
- 1.1 Android系統架構
- 1.2 搭建開發環境
- 1.2.1 下載源碼
- 1.2.2 編譯源碼
- 1.2.3 利用Eclipse調試system_process
- 1.3 本章小結
- 第2章 深入理解Java Binder和MessageQueue
- 2.1 概述
- 2.2 Java層中的Binder架構分析
- 2.2.1 Binder架構總覽
- 2.2.2 初始化Java層Binder框架
- 2.2.3 addService實例分析
- 2.2.4 Java層Binder架構總結
- 2.3 心系兩界的MessageQueue
- 2.3.1 MessageQueue的創建
- 2.3.2 提取消息
- 2.3.3 nativePollOnce函數分析
- 2.3.4 MessageQueue總結
- 2.4 本章小結
- 第3章 深入理解SystemServer
- 3.1 概述
- 3.2 SystemServer分析
- 3.2.1 main函數分析
- 3.2.2 Service群英會
- 3.3 EntropyService分析
- 3.4 DropBoxManagerService分析
- 3.4.1 DBMS構造函數分析
- 3.4.2 dropbox日志文件的添加
- 3.4.3 DBMS和settings數據庫
- 3.5 DiskStatsService和DeviceStorageMonitorService分析
- 3.5.1 DiskStatsService分析
- 3.5.2 DeviceStorageManagerService分析
- 3.6 SamplingProfilerService分析
- 3.6.1 SamplingProfilerService構造函數分析
- 3.6.2 SamplingProfilerIntegration分析
- 3.7 ClipboardService分析
- 3.7.1 復制數據到剪貼板
- 3.7.2 從剪切板粘貼數據
- 3.7.3 CBS中的權限管理
- 3.8 本章小結
- 第4章 深入理解PackageManagerService
- 4.1 概述
- 4.2 初識PackageManagerService
- 4.3 PKMS的main函數分析
- 4.3.1 構造函數分析之前期準備工作
- 4.3.2 構造函數分析之掃描Package
- 4.3.3 構造函數分析之掃尾工作
- 4.3.4 PKMS構造函數總結
- 4.4 APK Installation分析
- 4.4.1 adb install分析
- 4.4.2 pm分析
- 4.4.3 installPackageWithVerification函數分析
- 4.4.4 APK 安裝流程總結
- 4.4.5 Verification介紹
- 4.5 queryIntentActivities分析
- 4.5.1 Intent及IntentFilter介紹
- 4.5.2 Activity信息的管理
- 4.5.3 Intent 匹配查詢分析
- 4.5.4 queryIntentActivities總結
- 4.6 installd及UserManager介紹
- 4.6.1 installd介紹
- 4.6.2 UserManager介紹
- 4.7 本章學習指導
- 4.8 本章小結
- 第5章 深入理解PowerManagerService
- 5.1 概述
- 5.2 初識PowerManagerService
- 5.2.1 PMS構造函數分析
- 5.2.2 init分析
- 5.2.3 systemReady分析
- 5.2.4 BootComplete處理
- 5.2.5 初識PowerManagerService總結
- 5.3 PMS WakeLock分析
- 5.3.1 WakeLock客戶端分析
- 5.3.2 PMS acquireWakeLock分析
- 5.3.3 Power類及LightService類介紹
- 5.3.4 WakeLock總結
- 5.4 userActivity及Power按鍵處理分析
- 5.4.1 userActivity分析
- 5.4.2 Power按鍵處理分析
- 5.5 BatteryService及BatteryStatsService分析
- 5.5.1 BatteryService分析
- 5.5.2 BatteryStatsService分析
- 5.5.3 BatteryService及BatteryStatsService總結
- 5.6 本章學習指導
- 5.7 本章小結
- 第6章 深入理解ActivityManagerService
- 6.1 概述
- 6.2 初識ActivityManagerService
- 6.2.1 ActivityManagerService的main函數分析
- 6.2.2 AMS的 setSystemProcess分析
- 6.2.3 AMS的 installSystemProviders函數分析
- 6.2.4 AMS的 systemReady分析
- 6.2.5 初識ActivityManagerService總結
- 6.3 startActivity分析
- 6.3.1 從am說起
- 6.3.2 AMS的startActivityAndWait函數分析
- 6.3.3 startActivityLocked分析
- 6.4 Broadcast和BroadcastReceiver分析
- 6.4.1 registerReceiver流程分析
- 6.4.2 sendBroadcast流程分析
- 6.4.3 BROADCAST_INTENT_MSG消息處理函數
- 6.4.4 應用進程處理廣播分析
- 6.4.5 廣播處理總結
- 6.5 startService之按圖索驥
- 6.5.1 Service知識介紹
- 6.5.2 startService流程圖
- 6.6 AMS中的進程管理
- 6.6.1 Linux進程管理介紹
- 6.6.2 關于Android中的進程管理的介紹
- 6.6.3 AMS進程管理函數分析
- 6.6.4 AMS進程管理總結
- 6.7 App的 Crash處理
- 6.7.1 應用進程的Crash處理
- 6.7.2 AMS的handleApplicationCrash分析
- 6.7.3 AppDeathRecipient binderDied分析
- 6.7.4 App的Crash處理總結
- 6.8 本章學習指導
- 6.9 本章小結
- 第7章 深入理解ContentProvider
- 7.1 概述
- 7.2 MediaProvider的啟動及創建
- 7.2.1 Context的getContentResolver函數分析
- 7.2.2 MediaStore.Image.Media的query函數分析
- 7.2.3 MediaProvider的啟動及創建總結
- 7.3 SQLite創建數據庫分析
- 7.3.1 SQLite及SQLiteDatabase家族
- 7.3.2 MediaProvider創建數據庫分析
- 7.3.3 SQLiteDatabase創建數據庫的分析總結
- 7.4 Cursor 的query函數的實現分析
- 7.4.1 提取query關鍵點
- 7.4.2 MediaProvider 的query分析
- 7.4.3 query關鍵點分析
- 7.4.4 Cursor query實現分析總結
- 7.5 Cursor close函數實現分析
- 7.5.1 客戶端close的分析
- 7.5.2 服務端close的分析
- 7.5.3 finalize函數分析
- 7.5.4 Cursor close函數總結
- 7.6 ContentResolver openAssetFileDescriptor函數分析
- 7.6.1 openAssetFileDescriptor之客戶端調用分析
- 7.6.2 ContentProvider的 openTypedAssetFile函數分析
- 7.6.3 跨進程傳遞文件描述符的探討
- 7.6.4 openAssetFileDescriptor函數分析總結
- 7.7 本章學習指導
- 7.8 本章小結
- 第8章 深入理解ContentService和AccountManagerService
- 8.1 概述
- 8.2 數據更新通知機制分析
- 8.2.1 初識ContentService
- 8.2.2 ContentResovler 的registerContentObserver分析
- 8.2.3 ContentResolver的 notifyChange分析
- 8.2.4 數據更新通知機制總結和深入探討
- 8.3 AccountManagerService分析
- 8.3.1 初識AccountManagerService
- 8.3.2 AccountManager addAccount分析
- 8.3.3 AccountManagerService的分析總結
- 8.4 數據同步管理SyncManager分析
- 8.4.1 初識SyncManager
- 8.4.2 ContentResolver 的requestSync分析
- 8.4.3 數據同步管理SyncManager分析總結
- 8.5 本章學習指導
- 8.6 本章小結