·??介紹ContentService
·??介紹AccountManagerService
·??SystemServer.java
frameworks/base/services/java/com/android/server/SystemServer.java
·??ContentService.java
frameworks/base/core/java/android/content/ContentService.java
·??ContentResolver.java
frameworks/base/core/java/android/content/ContentResolver.java
·??UsbSettings.java
packages/apps/Settings/src/com/android/settings/deviceinfo/UsbSettings.java
·??DevelopmentSettings.java
packages/apps/Settings/src/com/android/settings/DevelopmentSettings.java
·??UsbDeviceManager.java
frameworks/base/services/java/com/android/server/usb/UsbDeviceManager.java
·??AccountManagerService.java
frameworks/base/core/java/android/accounts/AccountManagerService.java
·??AccountAuthenticatorCache.java
frameworks/base/core/java/android/accounts/AccountAuthenticatorCache.java
·??RegisteredServicesCache.java
frameworks/base/core/java/android/content/pm/RegisteredServicesCache.java
·??AccountManager.java
frameworks/base/core/java/android/accounts/AccountManager.java
·??EasAuthenticatorService
packages/apps/Email/src/com/android/email/service/EasAuthenticatorService.java
·??SyncManager.java
frameworks/base/core/java/android/content/SyncManager.java
·??SyncStorageEngine.java
frameworks/base/core/java/android/content/SyncStorageEngine.java
·??SyncAdapterCache.java
frameworks/base/core/java/android/content/SyncAdapterCache.java
·??SyncQueue.java
frameworks/base/core/java/android/content/SyncQueue.java
·??EmailSyncAdapterService.java
packages/apps/Exchange/src/com/android/exchange/EmailSyncAdapterService.java
·??AbstractThreadedSyncAdapter.java
frameworks/base/core/java/android/content/AbstractThreadedSyncAdapter.java
本章將分析ContentService和AccountManagerService,其中,ContentService包含以下兩個(gè)主要功能:
·??它是Android平臺(tái)中數(shù)據(jù)更新通知的執(zhí)行者。數(shù)據(jù)更新通知與第7章分析Cursorquery函數(shù)實(shí)現(xiàn)時(shí)提到的ContentObserver有關(guān)。這部分內(nèi)容將在8.2節(jié)中分析。
·??它是Android平臺(tái)中數(shù)據(jù)同步服務(wù)的管理中樞。當(dāng)用戶通過(guò)Android手機(jī)中的Contacts應(yīng)用將聯(lián)系人信息同步到遠(yuǎn)端服務(wù)器時(shí),就需要和ContentService交互。這部分內(nèi)容是本章的難點(diǎn),將在8.4節(jié)中進(jìn)行分析
本章要分析的第二個(gè)Service是AccountManagerService,它負(fù)責(zé)管理Android手機(jī)中用戶的賬戶,這些賬戶是用戶的online賬戶,例如用戶在Google、Facebook上注冊(cè)的賬戶。
本章將先分析ContentService中數(shù)據(jù)通知機(jī)制的實(shí)現(xiàn),然后分析AccountManagerService,最后再介紹ContentService中的數(shù)據(jù)同步服務(wù)。
提示這兩個(gè)Service的難度都不大,它們?cè)谠O(shè)計(jì)結(jié)構(gòu)上有較大的相似性,在內(nèi)容上也有一定的關(guān)聯(lián)。另外,作為本書(shū)最后一章,筆者照例會(huì)留一些難度適中的問(wèn)題或知識(shí)點(diǎn)供讀者自行分析研究。
何為數(shù)據(jù)更新通知?先來(lái)看日常生活中的一個(gè)例子。
筆者所在公司采用BugZilla來(lái)管理Bug。在日常工作中,筆者和同事們的一部分工作就是登錄BugZilla查詢(xún)各自名下的Bug并修改它們。如何跟蹤自己的Bug呢?其實(shí),以上描述中已經(jīng)提到了一種方法,即登錄BugZilla并查詢(xún)。除此之外,BugZilla還支持另一種方法,即為每個(gè)Bug設(shè)置一個(gè)關(guān)系人列表,一旦該Bug的狀態(tài)發(fā)生變化,BugZilla就會(huì)給該Bug關(guān)系人列表中的人發(fā)送郵件。
上例中提到的第二種方法就是本節(jié)要分析的數(shù)據(jù)更新通知機(jī)制。一般說(shuō)來(lái),領(lǐng)導(dǎo)和項(xiàng)目經(jīng)理(PM)使用第一種方法居多,因?yàn)樗麄冃枰欢〞r(shí)地查詢(xún)和統(tǒng)計(jì)全局Bug的情況。而程序員使用第二種方法較多(也許是沒(méi)辦法的事情吧,誰(shuí)會(huì)情愿主動(dòng)查詢(xún)自己的Bug呢?)。
類(lèi)似的通知機(jī)制在日常生活中的其他地方還有使用。在操作系統(tǒng)中,這種通知機(jī)制同樣也廣泛存在。例如,在OS中,設(shè)計(jì)人員一般會(huì)安排外部設(shè)備以中斷的方式通知CPU并讓其開(kāi)展后續(xù)處理,而不會(huì)讓CPU去輪詢(xún)外設(shè)的狀態(tài)。
現(xiàn)在回到Android平臺(tái),如果程序需要監(jiān)控某數(shù)據(jù)項(xiàng)的變化,可以采用一個(gè)類(lèi)似while循環(huán)的語(yǔ)句不斷查詢(xún)它以判斷其值是否發(fā)生了變化。顯而易見(jiàn),這種方式的效率很低。有了通知機(jī)制以后,程序只需注冊(cè)一個(gè)ContentObserver實(shí)例即可。一旦該項(xiàng)數(shù)據(jù)發(fā)生變化,系統(tǒng)就會(huì)通過(guò)ContentObserver的onChange函數(shù)來(lái)通知我們。與前面所述的輪詢(xún)相比,此處的通知方式明顯更高效。
通過(guò)上面的描述可以知道,通知機(jī)制的實(shí)施包括兩個(gè)步驟:第一步,注冊(cè)觀察者;第二步,通知觀察者。在Android平臺(tái)中,這兩步都離不開(kāi)ContentService,下面來(lái)認(rèn)識(shí)一下它。
提示在設(shè)計(jì)模式中,通知機(jī)制對(duì)應(yīng)的模式是Observer模式,即觀察者模式。
SystemServer創(chuàng)建ContentService的代碼非常簡(jiǎn)單,如下所示:
[-->SystemServer::ServerThread.run]
public void run() {
?? ......
??ContentService.main(context,
???????????????????factoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL);
?? ......
}
以上代碼中直接調(diào)用了ContentService的main函數(shù)。在一般情況下,該函數(shù)第二個(gè)參數(shù)為false。此main函數(shù)的代碼如下:
·??[-->ContentService.java::main]
public static IContentService main(Contextcontext, boolean factoryTest) {
? ?//構(gòu)造ContentService實(shí)例
??ContentService service = new ContentService(context, factoryTest);
?? //將ContentService注冊(cè)到ServiceManager中,其注冊(cè)名叫“content”
??ServiceManager.addService(ContentResolver.CONTENT_SERVICE_NAME,
??????????????????????????????? ?service);
?? returnservice;
}
ContentService的構(gòu)造函數(shù)的代碼如下:
[-->ContentService.java::ContentService]
ContentService(Context context, booleanfactoryTest) {
?? ?mContext = context;
???mFactoryTest = factoryTest;
?? ?getSyncManager(); //獲取同步服務(wù)管理對(duì)象,接下來(lái)看它的代碼
}
[-->ContentService.java::getSyncManager]
private SyncManager getSyncManager() {
???synchronized(mSyncManagerLock) {
???? try {
??????????//創(chuàng)建一個(gè)SyncManager實(shí)例,它是ContentService中負(fù)責(zé)數(shù)據(jù)同步服務(wù)的
??????????//主力成員。留待8.4節(jié)再詳細(xì)分析它
???????????if (mSyncManager == null) mSyncManager = new
??????????????????????????????????????? SyncManager(mContext,mFactoryTest);
?????? }......
???????????return mSyncManager;
???? }
}
看完以上代碼讀者可能會(huì)覺(jué)得ContentService比較簡(jiǎn)單。其實(shí),ContentService中最難的功能是數(shù)據(jù)同步服務(wù),不過(guò)該功能的實(shí)現(xiàn)都封裝在SyncManager及相關(guān)類(lèi)中了,所以在分析通知機(jī)制時(shí)不會(huì)和數(shù)據(jù)同步服務(wù)有太多瓜葛。
下面來(lái)分析通知機(jī)制實(shí)施的第一步,注冊(cè)ContentObserver。該步驟由ContentResovler提供的registerContentObserver函數(shù)來(lái)實(shí)現(xiàn)。
[-->ContentResolver.java::registerContentObserver]
public final void registerContentObserver(Uri uri,
??????????? booleannotifyForDescendents,ContentObserver observer){
? /*
? ?注意registerContentObserver傳遞的參數(shù),其中:
?? uri是客戶端設(shè)置的它所需要監(jiān)聽(tīng)的數(shù)據(jù)項(xiàng)的地址,用Uri來(lái)表示
?? notifyForDescendents:如果該值為true,則所有地址包含此uri的數(shù)據(jù)項(xiàng)發(fā)生變化時(shí)
?? 都會(huì)觸發(fā)通知。否則只有完全符合該uri地址的數(shù)據(jù)項(xiàng)發(fā)生變化時(shí)才會(huì)觸發(fā)通知。以文件夾和
?? 其中的文件為例,若uri指向某文件夾,則需設(shè)置notifyForDescendents為true。即該文件
?? 夾下的任何文件發(fā)生變化,都需要通知監(jiān)聽(tīng)者。
?? observer是客戶端設(shè)置的監(jiān)聽(tīng)對(duì)象。當(dāng)數(shù)據(jù)項(xiàng)發(fā)生變化時(shí),該對(duì)象的onChange函數(shù)將被調(diào)用
? */
? try {???
???????????/*
????????????調(diào)用ContentService的registerContentObserver函數(shù),其第三個(gè)參數(shù)是
??????????? ?observer.getContentObserver的返回值,它是什么呢?
???????????*/
???????????getContentService().registerContentObserver(uri,
?????????????????????????????????? notifyForDescendents,
????? ?????????????????????????????observer.getContentObserver());
??????? } ......
?}
registerContentObserver最終將調(diào)用ContentService的registerContentObserver函數(shù),其中第三個(gè)參數(shù)是ContentObservergetContentObserver的返回值。這個(gè)返回值是什么呢?需請(qǐng)出ContentObserver家族成員。
ContentObserver家族成員如圖8-1所示。
http://wiki.jikexueyuan.com/project/deep-android-v2/images/chapter8/image001.png" alt="image" />
圖8-1? ContentObserver家族類(lèi)圖
圖8-1中的ContentObserver類(lèi)和第7章中介紹的ContentProvider類(lèi)非常類(lèi)似,內(nèi)部都定義了一個(gè)Transport類(lèi)參與Binder通信。由圖8-1可知,Transport類(lèi)從IContentObserver.stub派生。從Binder通信角度來(lái)看,客戶端進(jìn)程中的Transport將是Bn端。如此,通過(guò)registerContentObserver傳遞到ContentService所在進(jìn)程的就是Bp端。IContentObserverBp端對(duì)象的真實(shí)類(lèi)型是IContentObserver.Stub.Proxy。
注意IContentObserver.java由aidl處理IContentObserver.aidl生成,其位置在out/targer/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/android/database/IContentObserver.java中。
下面來(lái)看ContentService的registerContentObserver函數(shù)的代碼。
[-->ContentService.java::registerContentObserver]
public void registerContentObserver(Uri uri,boolean notifyForDescendents,
????? ?????????IContentObserver observer) {
?? ??......
???synchronized (mRootNode) {
????//ContentService要做的事情其實(shí)很簡(jiǎn)單,就是保存uri和observer的對(duì)應(yīng)關(guān)系到
???? //其內(nèi)部變量mRootNode中
????mRootNode.addObserverLocked(uri, observer, notifyForDescendents,
????????????????????mRootNode, Binder.getCallingUid(),
???????????????????Binder.getCallingPid());
?}
mRootNode是ContentService的成員變量,其類(lèi)型為ObserverNode。ObserverNode的組織形式是數(shù)據(jù)結(jié)構(gòu)中的樹(shù),其葉子節(jié)點(diǎn)的類(lèi)型為ObserverEntry,它保存了uri和對(duì)應(yīng)的IContentObserver對(duì)象。本節(jié)不關(guān)注它們的內(nèi)部實(shí)現(xiàn),讀者若有興趣,不妨自行研究。
至此,客戶端已經(jīng)為某數(shù)據(jù)項(xiàng)設(shè)置了ContentObserver。再來(lái)看通知機(jī)制實(shí)施的第二步,即通知觀察者。
數(shù)據(jù)更新的通知由ContentResolver的notifyChange函數(shù)觸發(fā)??碝ediaProvider的update函數(shù)的代碼如下:
[-->MediaProvider.java::update]
public int update(Uri uri, ContentValuesinitialValues, String userWhere,
????????? ???????????String[] whereArgs) {
?? int count;
?? int match= URI_MATCHER.match(uri);
??DatabaseHelper database = getDatabaseForUri(uri);
?? //找到對(duì)應(yīng)的數(shù)據(jù)庫(kù)對(duì)象
??SQLiteDatabase db = database.getWritableDatabase();
?? ......
? ?synchronized (sGetTableAndWhereParam) {
????getTableAndWhere(uri, match, userWhere, sGetTableAndWhereParam);
???? switch(match) {
????? ???......
???? ???case VIDEO_MEDIA:
???? ???case VIDEO_MEDIA_ID:{
??? ??????ContentValues values = newContentValues(initialValues);
??? ??????values.remove(ImageColumns.BUCKET_ID);
????? ????values.remove(ImageColumns.BUCKET_DISPLAY_NAME);
?????? ???......//調(diào)用SQLiteDatabase的update函數(shù)更新數(shù)據(jù)庫(kù)
?????? ???count =db.update(sGetTableAndWhereParam.table, values,
???????????????????????????????sGetTableAndWhereParam.where, whereArgs);
?????? ??.......
?? ??????}......//其他處理
???? }......//synchronized處理結(jié)束
?? ?if (count > 0 &&!db.inTransaction()) //調(diào)用notifyChange觸發(fā)通知
??????? getContext().getContentResolver().notifyChange(uri,null);
?? returncount;
}
由以上代碼可知,MediaProvider update函數(shù)更新完數(shù)據(jù)庫(kù)后,將通過(guò)notfiyChange函數(shù)來(lái)通知觀察者。notfiyChange函數(shù)的代碼如下:
[-->ContentResolver.java::notifyChange]
public void notifyChange(Uri uri, ContentObserverobserver) {
???? //在一般情況下,observer參數(shù)為null。調(diào)用另一個(gè)notifyChange函數(shù),直接來(lái)看它
????notifyChange(uri, observer, true);
?}
public void notifyChange(Uri uri, ContentObserverobserver,
????????????????????????? ?????boolean syncToNetwork) {
? //第三個(gè)參數(shù)syncToNetwork用于控制是否需要發(fā)起一次數(shù)據(jù)同步請(qǐng)求
? try {
?????? //調(diào)用ContentService的notifyChange函數(shù)
????? ?getContentService().notifyChange(
?????????????uri, observer == null ? null : observer.getContentObserver(),
?????????????observer != null && observer.deliverSelfNotifications(),
?????????????syncToNetwork);
??????? } ......
}
由以上代碼可知,ContentService的notifyChange函數(shù)將被調(diào)用,其代碼如下:
[-->ContentSerivce::notifyChange]
public void notifyChange(Uri uri, IContentObserverobserver,
?????boolean observerWantsSelfNotifications, boolean syncToNetwork) {
? longidentityToken = clearCallingIdentity();
? try {
?????????ArrayList<ObserverCall> calls = newArrayList<ObserverCall>();
????????? //從根節(jié)點(diǎn)開(kāi)始搜索需要通知的觀察者,結(jié)果保存在calls數(shù)組中
?????????synchronized (mRootNode) {
???????????????mRootNode.collectObserversLocked(uri, 0, observer,
?????????????????????????????? observerWantsSelfNotifications,calls);
????????? }
????????final int numCalls = calls.size();
???????? for(int i=0; i<numCalls; i++) {
??????????????ObserverCall oc = calls.get(i);
??????????????try {
???????????????????/*
???????????????????? 調(diào)用客戶端IContentObserver Bn端,即ContentObserver
??? ?????????????????內(nèi)部類(lèi)Transport的onChange函數(shù)。最后再由Transport調(diào)用
???????????????????? 客戶端提供的ContentObserver子類(lèi)的onChange函數(shù)
??????????????????*/
???????????????????oc.mObserver.onChange(oc.mSelfNotify);
???????????????} ......//異常處理
???????????}
???????????if (syncToNetwork) {
???????????????SyncManager syncManager = getSyncManager();
???????????????if (syncManager != null) {
???????????????????//發(fā)起一次同步請(qǐng)求,相關(guān)內(nèi)容留待8.4節(jié)再分析
???????????????????syncManager.scheduleLocalSync(null,
????????????????????????????????????????? ?uri.getAuthority());
???????????????}
???????????}
??????? }finally {
???????????restoreCallingIdentity(identityToken);
??????? }
??? }
總結(jié)上面所描述的數(shù)據(jù)更新通知機(jī)制的流程如圖8-2所示。
http://wiki.jikexueyuan.com/project/deep-android-v2/images/chapter8/image002.png" alt="image" />
圖8-2? 數(shù)據(jù)更新通知的流程圖
從前面的代碼介紹和圖8-2所示的流程來(lái)看,Android平臺(tái)中的數(shù)據(jù)更新通知機(jī)制還較為簡(jiǎn)單。不過(guò)此處尚有幾個(gè)問(wèn)題想和讀者一起探討。
問(wèn)題一:由圖8-2可知,客戶端2調(diào)用ContentProvider的update函數(shù)將間接觸發(fā)客戶端1的ContentObserver的onChange函數(shù)被調(diào)用。如果客戶端1在onChange函數(shù)中耗時(shí)過(guò)長(zhǎng),會(huì)不會(huì)導(dǎo)致客戶端2阻塞在update函數(shù)中呢?
想到這個(gè)問(wèn)題的讀者應(yīng)該是非常細(xì)致和認(rèn)真的了。確實(shí),從前面所示的代碼和流程圖來(lái)看,這個(gè)情況幾乎是必然會(huì)發(fā)生的,但是實(shí)際上該問(wèn)題并不存在,原因在于下面這一段代碼:
[-->IContentObserver.java::Proxy:onChange]
private static class Proxy implementsandroid.database.IContentObserver {
???? privateandroid.os.IBinder mRemote;
???? ......
???? publicvoid onChange(boolean selfUpdate)
????????? ????????????throws android.os.RemoteException {
??????? android.os.Parcel_data = android.os.Parcel.obtain();
??????? try{
?????????? _data.writeInterfaceToken(DESCRIPTOR);
?????????? _data.writeInt(((selfUpdate)? (1) : (0)));
??????????//調(diào)用客戶端1的ContentObserver Bn端的onChange函數(shù)
?????????? mRemote.transact(Stub.TRANSACTION_onChange,_data, null,
??????????????????????????? ????????????android.os.IBinder.FLAG_ONEWAY);
????? ??} finally {
??????????? _data.recycle();
???? ???}
???? }
???? ......
}
以上代碼告訴我們,ContentService在調(diào)用客戶端注冊(cè)的IContentObserver 的onChange函數(shù)時(shí),使用了FLAG_ONEWAY標(biāo)志。根據(jù)第2章對(duì)該標(biāo)志的介紹(參見(jiàn)2.2.1節(jié)),使用該標(biāo)志的Binder調(diào)用只需將請(qǐng)求發(fā)給binder驅(qū)動(dòng)即可,無(wú)需等待客戶端onChange函數(shù)的返回。因此,即使客戶端1在onChange中惡意浪費(fèi)時(shí)間,也不會(huì)阻塞客戶端2的update函數(shù)了。
問(wèn)題二:這是一個(gè)開(kāi)放性問(wèn)題,最終需要讀者給出合適的答案。
假設(shè)服務(wù)端有一項(xiàng)功能,需要客戶端通過(guò)某種方式來(lái)控制它的開(kāi)閉(即禁止或使用該功能),考慮一下有幾種方式來(lái)實(shí)現(xiàn)這個(gè)控制機(jī)制。
Android平臺(tái)上至少有三種方法可以實(shí)現(xiàn)這個(gè)控制機(jī)制。
第一種:服務(wù)端實(shí)現(xiàn)一個(gè)API函數(shù),客戶端直接調(diào)用這個(gè)函數(shù)來(lái)控制。
第二種客戶端發(fā)送指定的廣播,而服務(wù)端注冊(cè)該廣播的接收者,然后在這個(gè)廣播接收者的onReceive函數(shù)中去處理。
第三種:服務(wù)端輸出一個(gè)ContentProvider,并為這個(gè)功能輸出一個(gè)uri地址,然后注冊(cè)一個(gè)ContentObserver。客戶端可通過(guò)更新數(shù)據(jù)的方式來(lái)觸發(fā)服務(wù)端ContentObserver的onChange函數(shù),服務(wù)端在該函數(shù)中做對(duì)應(yīng)處理即可。
在Android代碼中,這三種方法都有地方使用。下面將以Settings應(yīng)用中和USB相關(guān)的功能設(shè)置為例來(lái)觀察第一種和第三種方法的使用情況。
第一個(gè)實(shí)例和Android 4.0中新支持的USB MTP/PTP功能有關(guān),相關(guān)代碼如下:
[-->UsbSettings.java::onPreferenceTreeClick]
public booleanonPreferenceTreeClick(PreferenceScreen preferenceScreen,
??????????????????????????? ?Preference preference) {
?
?? ......
?? if(preference == mMtp) {
????????mUsbManager.setCurrentFunction(UsbManager.USB_FUNCTION_MTP,true);
???????updateToggles(UsbManager.USB_FUNCTION_MTP);
?? } else if(preference == mPtp) {
????????mUsbManager.setCurrentFunction(UsbManager.USB_FUNCTION_PTP, true);
??????? ?updateToggles(UsbManager.USB_FUNCTION_PTP);
?? }
?? returntrue;
?}
由以上代碼可知,如果用戶從Settings界面中選擇了使能MTP,將直接調(diào)用UsbManager的setCurrentFunction來(lái)使能MTP功能。這個(gè)函數(shù)的Bn端實(shí)現(xiàn)在UsbService中。
不過(guò),同樣是USB相關(guān)的功能控制,ADB的開(kāi)關(guān)控制卻采用了第三種方法,相關(guān)代碼為:
[-->DevelopmentSettings.java::onClick]
public void onClick(DialogInterface dialog, intwhich) {
??if (which == DialogInterface.BUTTON_POSITIVE){
???????mOkClicked = true;
?????? //設(shè)置Settings數(shù)據(jù)庫(kù)ADB對(duì)應(yīng)的數(shù)據(jù)項(xiàng)值為1
???????Settings.Secure.putInt(getActivity().getContentResolver(),
???????????????????Settings.Secure.ADB_ENABLED, 1);
?? } else
???????mEnableAdb.setChecked(false);//界面更新
?}
上面的數(shù)據(jù)項(xiàng)更新操作將導(dǎo)致UsbDeviceManager做對(duì)應(yīng)處理,其相關(guān)代碼如下:
[-->UsbDeviceManager.java::onChange]
private class AdbSettingsObserver extendsContentObserver {
?? ......
?? publicvoid onChange(boolean selfChange) {
?????? ?//從數(shù)據(jù)庫(kù)中取出對(duì)應(yīng)項(xiàng)的值
?????? ?boolean enable =(Settings.Secure.getInt(mContentResolver,
????????????????????????????Settings.Secure.ADB_ENABLED, 0) > 0);
??????????//發(fā)送MSG_ENABLE_ADB消息,UsbDeviceManager將處理此消息
????????? ?mHandler.sendMessage(MSG_ENABLE_ADB, enable);
???? }
}
同樣是USB相關(guān)的功能,Settings應(yīng)用卻采用了兩種截然不同的方法來(lái)處理它們。這種做法為筆者目前所從事的項(xiàng)目中USB擴(kuò)展功能的實(shí)現(xiàn)帶來(lái)了極大困擾,因?yàn)槲覀兿氩捎媒y(tǒng)一的方法來(lái)處理USB相關(guān)功能。到底應(yīng)采用哪種方法比較合適呢?第一種方法和第三種方法各自的適用場(chǎng)景是什么?讀者不妨仔細(xì)思考并將結(jié)論告訴筆者。
問(wèn)題三:我們?cè)诘?章中分析Cursorquery時(shí)曾看到過(guò)ContentObserver的身影,但是并沒(méi)有對(duì)其進(jìn)行詳細(xì)分它。如果現(xiàn)在回過(guò)頭去分析query流程中和ContentObserver相關(guān)的部分,所涉及的流程可能比本節(jié)內(nèi)容還要多。
本節(jié)將分析AccountManagerService。如前所述,AccountManagerService負(fù)責(zé)管理手機(jī)中用戶的online賬戶,主要工作涉及賬戶的添加和刪除、AuthToken(全稱(chēng)為authentication token。有了它,客戶端就無(wú)須每次操作都向服務(wù)器發(fā)送密碼了)的獲取和更新等。關(guān)于AccountManagerSerivce更詳細(xì)的功能,可閱讀SDK文檔中AccountManager的說(shuō)明。
下面看AccountManagerService創(chuàng)建時(shí)的代碼:
[-->SystemServer.java::ServerThread.run]
? ......
??//注冊(cè)AccountManagerService到ServiceManager,服務(wù)名為“account”
??ServiceManager.addService(Context.ACCOUNT_SERVICE,
????????????????????????????????????newAccountManagerService(context));
其構(gòu)造函數(shù)的代碼如下:
[-->AccountManagerService.java::AccountManagerService]
public AccountManagerService(Context context) {
?? //調(diào)用另外一個(gè)構(gòu)造函數(shù),其第三個(gè)參數(shù)將構(gòu)造一個(gè)AccountAuthenticatorCache對(duì)象,它是
?? //什么呢?見(jiàn)下文分析
???this(context,context.getPackageManager(),
????????????new? AccountAuthenticatorCache(context));
}
在AccountManagerService構(gòu)造函數(shù)中創(chuàng)建了一個(gè)AccountAuthenticatorCache對(duì)象,它是什么?來(lái)看下文。
AccountAuthenticatorCache是Android平臺(tái)中賬戶驗(yàn)證服務(wù)(Account AuthenticatorService,AAS)的管理中心。而AAS則由應(yīng)用程序通過(guò)在AndroidManifest.xml中輸出符合指定要求的Service信息而來(lái)。稍后讀者將看到這些要求的具體格式。
先來(lái)看AccountAuthenticatorCache的派生關(guān)系,如圖8-3所示。
http://wiki.jikexueyuan.com/project/deep-android-v2/images/chapter8/image003.png" alt="image" />
圖8-3? AccountAuthenticatorCache類(lèi)圖
由圖8-3可知:
·??AccountAuthenticatorCache從RegisteredServicesCache<AuthenticatorDescription>派生。RegisteredServicesCache是一個(gè)模板類(lèi),專(zhuān)門(mén)用于管理系統(tǒng)中指定Service的信息收集和更新,而具體是哪些Service由RegisteredServicesCache構(gòu)造時(shí)的參數(shù)指定。AccountAuthenticatorCache對(duì)外輸出由RegisteredServicesCache模板參數(shù)指定的類(lèi)的實(shí)例。在圖8-3中應(yīng)該就是AuthenticatorDescription。
·??AuthenticatorDescription繼承了Parcelable接口,這代表它可以跨Binder傳遞。該類(lèi)描述了AAS相關(guān)的信息。
·??AccountAuthenticatorCache實(shí)現(xiàn)了IAccountAuthenticatorCache接口。這個(gè)接口供外部調(diào)用者使用以獲取AAS的信息。
下面看AccountAuthenticatorCache的創(chuàng)建,其相關(guān)代碼如下:
[-->AccountAuthenticatorCache.java::AccountAuthenticatorCache]
public AccountAuthenticatorCache(Context context){
? /*
? ACTION_AUTHENTICATOR_INTENT值為"android.accounts.AccountAuthenticator"
? AUTHENTICATOR_META_DATA_NAME值為"android.accounts.AccountAuthenticator"
? AUTHENTICATOR_ATTRIBUTES_NAME值為"account-authenticator"
? */
??super(context,
?????????? AccountManager.ACTION_AUTHENTICATOR_INTENT,
??????????AccountManager.AUTHENTICATOR_META_DATA_NAME,
??????????AccountManager.AUTHENTICATOR_ATTRIBUTES_NAME, sSerializer);
?}
AccountAuthenticatorCache調(diào)用在其基類(lèi)RegisteredServicesCache的構(gòu)造函數(shù)時(shí),傳遞了3個(gè)字符串參數(shù),這3個(gè)參數(shù)用于控制RegisteredServicesCache從PackageManagerService獲取哪些Service的信息。
[-->RegisteredServicesCache.java::RegisteredServicesCache]
public RegisteredServicesCache(Context context,String interfaceName,
???????????????????????????????????? StringmetaDataName, String attributeName,
????????????????????????????XmlSerializerAndParser<V>serializerAndParser) {
??? mContext= context;
?? ?//保存?zhèn)鬟f進(jìn)來(lái)的參數(shù)
???mInterfaceName = interfaceName;
???mMetaDataName = metaDataName;
???mAttributesName = attributeName;
???mSerializerAndParser = serializerAndParser;
?
??? FiledataDir = Environment.getDataDirectory();
??? FilesystemDir = new File(dataDir, "system");
???//syncDir指向/data/system/registered_service目錄
??? FilesyncDir = new File(systemDir, "registered_services");
??? //下面這個(gè)文件指向syncDir目錄下的android.accounts.AccountAuthenticator.xml
???mPersistentServicesFile = new AtomicFile(new File(syncDir,
????????????????????????????????????????? interfaceName+ ".xml"));
??? //生成服務(wù)信息
???generateServicesMap();
?
??? finalBroadcastReceiver receiver = new BroadcastReceiver() {
??????public void onReceive(Context context1, Intent intent) {
?????????generateServicesMap();
???????? }
??? };
??? //注冊(cè)Package安裝、卸載和更新等廣播監(jiān)聽(tīng)者
???mReceiver = new AtomicReference<BroadcastReceiver>(receiver);
?? ?IntentFilter intentFilter = newIntentFilter();
???intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
???intentFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
???intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
???intentFilter.addDataScheme("package");
???mContext.registerReceiver(receiver, intentFilter);
?? ?IntentFilter sdFilter = new IntentFilter();
???sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
???sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
???mContext.registerReceiver(receiver, sdFilter);
}
由以上代碼可知:
·??成員變量mPersistentServicesFile指向/data/system/registered_service/目錄下的一個(gè)文件,該文件保存了以前獲取的對(duì)應(yīng)Service的信息。就AccountAuthenticator而言,mPersistentServicesFile指向該目錄的android.accounts.AccountAuthenticator.xml文件。
·??由于RegisteredServicesCache管理的是系統(tǒng)中指定Service的信息,當(dāng)系統(tǒng)中有Package安裝、卸載或更新時(shí),RegisteredServicesCache也需要對(duì)應(yīng)更新自己的信息,因?yàn)橛行㏒ervice可能會(huì)隨著APK被刪除而不復(fù)存在。
generateServiceMap函數(shù)將獲取指定的Service信息,其代碼如下:
[-->RegisteredServicesCache.java::generateServicesMap]
void generateServicesMap() {
?? //獲取PackageManager接口,用來(lái)和PackageManagerService交互
??PackageManager pm = mContext.getPackageManager();
??ArrayList<ServiceInfo<V>> serviceInfos = newArrayList<ServiceInfo<V>>();
?? /*
?? 在本例中,查詢(xún)PKMS中滿足Intent Action為"android.accounts.AccountAuthenticator"
?? 的服務(wù)信息。由以下代碼可知,這些信息指的是Service中聲明的MetaData信息
?? */
??List<ResolveInfo> resolveInfos = pm.queryIntentServices(
???????????????new Intent(mInterfaceName),PackageManager.GET_META_DATA);
?
?? for(ResolveInfo resolveInfo : resolveInfos) {
????? try {
??????????/*
??????????? 調(diào)用parserServiceInfo函數(shù)解析從PKMS中獲得的MetaData信息,該函數(shù)
?????????? ?返回的是一個(gè)模板類(lèi)對(duì)象。就本例而言,這個(gè)函數(shù)返回一個(gè)
??????????? ServiceInfo<AccountAuthenticator>類(lèi)型的對(duì)象
??????????*/
??????????ServiceInfo<V> info = parseServiceInfo(resolveInfo);
??????????serviceInfos.add(info);
???????? }
???? ?}
?
???synchronized (mServicesLock) {
?????? if(mPersistentServices == null)
???????????readPersistentServicesLocked();
??????mServices = Maps.newHashMap();
??????StringBuilder changes = new StringBuilder();
?????? ......//檢查mPersistentServices保存的服務(wù)信息和當(dāng)前從PKMS中取出來(lái)的PKMS
????? //信息,判斷是否有變化,如果有變化,需要通知監(jiān)聽(tīng)者。讀者可自行閱讀這段代碼,
???? //注意其中uid的作用
???????mPersistentServicesFileDidNotExist = false;
???? }
?}
接下來(lái)解析Service的parseServiceInfo函數(shù)。
[-->RegisteredServicesCache.java::parseServiceInfo]
private ServiceInfo<V>parseServiceInfo(ResolveInfo service)
?????????? ??????????throws XmlPullParserException, IOException {
??android.content.pm.ServiceInfo si = service.serviceInfo;
??ComponentName componentName = new ComponentName(si.packageName, si.name);
?
??PackageManager pm = mContext.getPackageManager();
?
??XmlResourceParser parser = null;
?? try {
??????? //解析MetaData信息
???????parser = si.loadXmlMetaData(pm, mMetaDataName);
???????AttributeSet attrs = Xml.asAttributeSet(parser);
?
??????? inttype;
???????......
?
????? StringnodeName = parser.getName();
????? //調(diào)用子類(lèi)實(shí)現(xiàn)的parseServiceAttributes得到一個(gè)真實(shí)的對(duì)象,在本例中它是
????? //AuthenticatorDescription。注意,傳遞給parseServiceAttributes的第一個(gè)
????? //參數(shù)代表MetaData中的resource信息。詳細(xì)內(nèi)容見(jiàn)下文的圖例
???? V v=parseServiceAttributes(
???????????????????? pm.getResourcesForApplication(si.applicationInfo),
????????????????????si.packageName, attrs);
?
??? finalandroid.content.pm.ServiceInfo serviceInfo = service.serviceInfo;
??? finalApplicationInfo applicationInfo = serviceInfo.applicationInfo;
??? finalint uid = applicationInfo.uid;
??? returnnew ServiceInfo<V>(v, componentName, uid);
? ?} ...... finally {
???????????if (parser != null) parser.close();
??? }
?}
parseServiceInfo將解析Service中的MetaData信息,然后調(diào)用子類(lèi)實(shí)現(xiàn)的parseServiceAttributes函數(shù),以獲取特定類(lèi)型Service的信息。
下面通過(guò)實(shí)例向讀者展示最終的解析結(jié)果。
在Email應(yīng)用的AndroidManifest.xml中定義了一個(gè)AAS,如圖8-4所示。
http://wiki.jikexueyuan.com/project/deep-android-v2/images/chapter8/image004.png" alt="image" />
圖8-4? Email AAS定義
由圖8-4可知,在Email中這個(gè)Service對(duì)應(yīng)為EasAuthenticatorService,其Intent匹配的Action為“android.accounts.AccountAuthenticator”,其MetaData的name為“android.accounts.AccountAuthenticator”,而MetaData的具體信息保存在resource資源中,在本例中,它指向另外一個(gè)xml文件,即eas_authenticator.xml,此文件的內(nèi)容如圖8-5所示。
http://wiki.jikexueyuan.com/project/deep-android-v2/images/chapter8/image005.png" alt="image" />
圖8-5? eas_authenticator.xml的內(nèi)容
圖8-5為Email中eas_authenticator.xml的內(nèi)容。這個(gè)xml中的內(nèi)容是有嚴(yán)格要求的,其中:
·??accountType標(biāo)簽用于指定賬戶類(lèi)型(賬戶類(lèi)型和具體應(yīng)用有關(guān),Android并未規(guī)定賬戶的類(lèi)型)。
·??icon、smallIcon、label和accountPreferences等用于界面顯示。例如,當(dāng)需要用戶輸入賬戶信息時(shí),系統(tǒng)會(huì)彈出一個(gè)Activity,上述幾個(gè)標(biāo)簽就用于界面顯示。詳細(xì)情況可閱讀SDK文檔AbstractAccountAuthenticator的說(shuō)明。
而android.accounts.AccountAuthenticator.xml的內(nèi)容如圖8-6所示。
http://wiki.jikexueyuan.com/project/deep-android-v2/images/chapter8/image006.png" alt="image" />
圖8-6? android.accounts.AccountAuthenticator.xml的內(nèi)容
由圖8-6可知,筆者的測(cè)試機(jī)器上有3個(gè)AAS服務(wù),其中同一個(gè)uid有兩個(gè)服務(wù)(即uid為10015對(duì)應(yīng)的兩個(gè)Service)。
提示uid是在為PackageManagerService解析APK文件時(shí)賦予APK的。讀者不妨自行閱讀frameworks/base/services/java/com/android/server/pm/Settings.java中的newUserIdLPw函數(shù)。
下面來(lái)看AccountManagerService的構(gòu)造函數(shù)。
[-->AccountManagerService.java::AccountManagerService]
public AccountManagerService(Context context,PackageManager packageManager,
???????????IAccountAuthenticatorCache authenticatorCache) {
?
??? mContext= context;
???mPackageManager = packageManager;
?
??synchronized (mCacheLock) {
????? //此數(shù)據(jù)庫(kù)文件對(duì)應(yīng)為/data/system/accounts.db
?????mOpenHelper = new DatabaseHelper(mContext);
?? }
?
??mMessageThread = new HandlerThread("AccountManagerService");
??mMessageThread.start();
??mMessageHandler = new MessageHandler(mMessageThread.getLooper());
?
??mAuthenticatorCache = authenticatorCache;
?? //為AccountAuthenticatorCache設(shè)置一個(gè)監(jiān)聽(tīng)者,一旦AAS服務(wù)發(fā)生變化,
??//AccountManagerService需要做對(duì)應(yīng)處理
??mAuthenticatorCache.setListener(this, null /* Handler */);
?
??sThis.set(this);
?? //監(jiān)聽(tīng)ACTION_PACKAGE_REMOVED廣播
??IntentFilter intentFilter = new IntentFilter();
??intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
??intentFilter.addDataScheme("package");
??mContext.registerReceiver(new BroadcastReceiver() {
?? publicvoid onReceive(Context context1, Intent intent) {
???????purgeOldGrants();
???? }
?? },intentFilter);
? ?/*
??? accounts.db數(shù)據(jù)庫(kù)中有一個(gè)grants表,用于存儲(chǔ)授權(quán)信息,該信息用于保存哪些Package
?? ?有權(quán)限獲取賬戶信息。下面的函數(shù)將根據(jù)grants表中的數(shù)據(jù)查詢(xún)PKMS,以判斷這些
?? ?Package是否還存在。如果系統(tǒng)中已經(jīng)不存在這些Package,則grants表需要更新
? */
? ?purgeOldGrants();
?? /*
??accounts.db中有一個(gè)accounts表,該表中存儲(chǔ)了賬戶類(lèi)型和賬戶名。其中,賬戶類(lèi)型
?? 就是AuthenticatorDescription中的accountType,它和具體應(yīng)用有關(guān)。下面這個(gè)
?? 函數(shù)將比較accounts表中的內(nèi)容與AccountAuthenticatorCache中服務(wù)的信息,如果
?? AccountAuthenticatorCache已經(jīng)不存在對(duì)應(yīng)賬戶類(lèi)型的服務(wù),則需要?jiǎng)h除accounts表
?? 中的對(duì)應(yīng)項(xiàng)
? */
??validateAccountsAndPopulateCache();
?}
AccountManagerService的構(gòu)造函數(shù)較簡(jiǎn)單,有興趣的讀者可自行研究以上代碼中未詳細(xì)分析的函數(shù)。下面將通過(guò)一個(gè)具體的例子來(lái)分析AccountManagerService的工作流程。
這一節(jié)將分析AccountManagerService中的一個(gè)重要的函數(shù),即addAccount,其功能是為某項(xiàng)賬戶添加一個(gè)用戶。下面以前面提及的Email為例來(lái)認(rèn)識(shí)AAS的處理流程。
AccountManagerService是一個(gè)運(yùn)行在SystemServer中的服務(wù),客戶端進(jìn)程必須借助AccountManager提供的API來(lái)使用AccountManagerService服務(wù),所以,本例需從AccountManager的addAccount函數(shù)講起。
AccountManager 的addAccount函數(shù)的參數(shù)和返回值較復(fù)雜,先看其函數(shù)原型:
public AccountManagerFuture<Bundle>addAccount(
?? finalString accountType,
?? finalString authTokenType,
?? finalString[] requiredFeatures,
?? finalBundle addAccountOptions,
?? finalActivity activity,
?? AccountManagerCallback<Bundle>callback,
?? Handlerhandler)
在以上代碼中:
·??addAccount的返回值類(lèi)型是AccountManagerFuture<Bundle>。其中,AccountManagerFuture是一個(gè)模板Interface,其真實(shí)類(lèi)型只有在分析addAccount的實(shí)現(xiàn)時(shí)才能知道?,F(xiàn)在可以告訴讀者的是,它和Java并發(fā)庫(kù)(concurrent庫(kù))中的FutureTask有關(guān),是對(duì)異步函數(shù)調(diào)用的一種封裝[①]。調(diào)用者在后期只要調(diào)用它的getResult函數(shù)即可取得addAccount的調(diào)用結(jié)果。由于addAccount可能涉及網(wǎng)絡(luò)操作(例如,AAS需要把賬戶添加到網(wǎng)絡(luò)服務(wù)器上),所以這里采用了異步調(diào)用的方法以避免長(zhǎng)時(shí)間的阻塞。這也是AccountManagerFuture的getResult不能在主線程中調(diào)用的原因。
·??addAccount的第一個(gè)參數(shù)accountType代表賬戶類(lèi)型。該參數(shù)不能為空。就本例而言,它的值為“com.android.email”。
·??authTokenType、requiredFeatures和addAccountOptions與具體的AAS服務(wù)有關(guān)。如果想添加指定賬戶類(lèi)型的Account,則須對(duì)其背后的AAS有所了解。
·??activity:此參數(shù)和界面有關(guān)。例如有些AAS需要用戶輸入用戶名和密碼,故需啟動(dòng)一Activity。在這種情況下,AAS會(huì)返回一個(gè)Intent,客戶端將通過(guò)這個(gè)activity啟動(dòng)Intent所標(biāo)示的Activity。讀者將通過(guò)下文的分析了解這一點(diǎn)。
·??callback和handler:這兩個(gè)參數(shù)與如何獲取addAccount返回結(jié)果有關(guān)。如這兩個(gè)參數(shù)為空,客戶端則須單獨(dú)啟動(dòng)一個(gè)線程去調(diào)用AccountManagerFuture的getResult函數(shù)。
addAccount的代碼如下:
[-->AccountManager.java::addAccount]
public AccountManagerFuture<Bundle>addAccount(final String accountType,
???? finalString authTokenType, final String[] requiredFeatures,
???? finalBundle addAccountOptions, final Activity activity,
????AccountManagerCallback<Bundle> callback, Handler handler) {
??? if(accountType == null) //accountType不能為null
??????????? thrownew IllegalArgumentException("accountType is null");
?? finalBundle optionsIn = new Bundle();
?? if(addAccountOptions != null)//保存客戶端傳入的addAccountOptions
??????optionsIn.putAll(addAccountOptions);
?
??optionsIn.putString(KEY_ANDROID_PACKAGE_NAME,
??????????????????????? mContext.getPackageName());
??? //構(gòu)造一個(gè)匿名類(lèi)對(duì)象,該類(lèi)繼承自AmsTask,并實(shí)現(xiàn)了doWork函數(shù)。addAccount返回前
??? //將調(diào)用該對(duì)象的start函數(shù)
??? returnnew AmsTask(activity, handler, callback) {
????? publicvoid doWork() throws RemoteException {
???????????//mService用于和AccountManagerService通信
???????????mService.addAcount(mRespo