·??詳細分析ActivityManagerService
·??SystemServer.java
frameworks/base/services/java/com/android/server/SystemServer.java
·??ActivityManagerService.java
frameworks/base/services/java/com/android/server/am/ActivityManagerService.java
·??ContextImpl.java
frameworks/base/core/java/android/app/ContextImpl.java
·??ActivityThread.java
frameworks/base/core/java/android/app/ActivityThread.java
·??ActivityStack.java
frameworks/base/services/java/com/android/server/am/ActivityStack.java
·??Am.java
frameworks/base/cmds/am/src/com/android/commands/am/Am.java
·??ProcessRecord.java
frameworks/base/services/java/com/android/server/am/ProcessRecord.java
·??ProcessList.java
frameworks/base/services/java/com/android/server/am/ProcessList.java
·??RuntimeInit.java
frameworks/base/core/java/com/android/internal/os/RuntimeInit.java
相信絕大部分讀者對本書提到的ActivityManagerService(以后簡稱AMS)都有所耳聞。AMS是Android中最核心的服務(wù),主要負責(zé)系統(tǒng)中四大組件的啟動、切換、調(diào)度及應(yīng)用進程的管理和調(diào)度等工作,其職責(zé)與操作系統(tǒng)中的進程管理和調(diào)度模塊相類似,因此它在Android中非常重要。
AMS是本書碰到的第一塊難啃的骨頭[①],涉及的知識點較多。為了幫助讀者更好地理解AMS,本章將帶領(lǐng)讀者按五條不同的線來分析它。
·??第一條線:同其他服務(wù)一樣,將分析SystemServer中AMS的調(diào)用軌跡。
·??第二條線:以am命令啟動一個Activity為例,分析應(yīng)用進程的創(chuàng)建、Activity的啟動,以及它們和AMS之間的交互等知識。
·??第三條線和第四條線:分別以Broadcast和Service為例,分析AMS中Broadcast和Service的相關(guān)處理流程。
·??第五條線:以一個Crash的應(yīng)用進程為出發(fā)點,分析AMS如何打理該應(yīng)用進程的身后事。
除了這五條線外,還將統(tǒng)一分析在這五條線中頻繁出現(xiàn)的與AMS中應(yīng)用進程的調(diào)度、內(nèi)存管理等相關(guān)的知識。
提示ContentProvider將放到下一章分析,不過本章將涉及和ContentProvider有關(guān)的知識點。
先來看AMS的家族圖譜,如圖6-1所示。
http://wiki.jikexueyuan.com/project/deep-android-v2/images/chapter6/image001.png" alt="image" />
圖6-1? AMS家族圖譜
由圖6-1可知:
·??AMS由ActivityManagerNative(以后簡稱AMN)類派生,并實現(xiàn)Watchdog.Monitor和BatteryStatsImpl.BatteryCallback接口。而AMN由Binder派生,實現(xiàn)了IActivityManager接口。
·??客戶端使用ActivityManager類。由于AMS是系統(tǒng)核心服務(wù),很多API不能開放供客戶端使用,所以設(shè)計者沒有讓ActivityManager直接加入AMS家族。在ActivityManager類內(nèi)部通過調(diào)用AMN的getDefault函數(shù)得到一個ActivityManagerProxy對象,通過它可與AMS通信。
AMS的簡單介紹就到此為止,下面分析AMS。相信不少讀者已經(jīng)磨拳擦掌,躍躍欲試了。
提示讀者們最好在桌上放一杯清茶,以保持AMS分析旅途中頭腦清醒。
AMS由SystemServer的ServerThread線程創(chuàng)建,提取它的調(diào)用軌跡,代碼如下:
[-->SystemServer.java::ServerThread的run函數(shù)]
//①調(diào)用main函數(shù),得到一個Context對象
context =ActivityManagerService.main(factoryTest);
?
//②setSystemProcess:這樣SystemServer進程可加到AMS中,并被它管理
ActivityManagerService.setSystemProcess();
?
//③installSystemProviders:將SettingsProvider放到SystemServer進程中來運行
ActivityManagerService.installSystemProviders();
?
//④在內(nèi)部保存WindowManagerService(以后簡稱WMS)
ActivityManagerService.self().setWindowManager(wm);
?
//⑤和WMS交互,彈出“啟動進度“對話框
ActivityManagerNative.getDefault().showBootMessage(
?????????????context.getResources().getText(
????????? ?????//該字符串中文為:“正在啟動應(yīng)用程序”
????????? ?????com.android.internal.R.string.android_upgrading_starting_apps),
??????????????false);
?
//⑥AMS是系統(tǒng)的核心,只有它準備好后,才能調(diào)用其他服務(wù)的systemReady
//注意,有少量服務(wù)在AMS systemReady之前就緒,它們不影響此處的分析
ActivityManagerService.self().systemReady(newRunnable() {
??? publicvoid run() {
???startSystemUi(contextF);//啟動systemUi。如此,狀態(tài)欄就準備好了
??? if(batteryF != null) batteryF.systemReady();
??? if(networkManagementF != null) networkManagementF.systemReady();
??? ......
??? Watchdog.getInstance().start();//啟動Watchdog
??? ......//調(diào)用其他服務(wù)的systemReady函數(shù)
}
在以上代碼中,一共列出了6個重要調(diào)用及這些調(diào)用的簡單說明,本節(jié)將分析除與WindowManagerService(以后簡稱WMS)交互的4、5外的其余四項調(diào)用。
先來分析1處調(diào)用。
AMS的main函數(shù)將返回一個Context類型的對象,該對象在SystemServer中被其他服務(wù)大量使用。Context,顧名思義,代表了一種上下文環(huán)境(筆者覺得其意義和JNIEnv類似),有了這個環(huán)境,我們就可以做很多事情(例如獲取該環(huán)境中的資源、Java類信息等)。那么AMS的main將返回一個怎樣的上下文環(huán)境呢?來看以下代碼:
[-->ActivityManagerService.java::main]
?publicstatic final Context main(int factoryTest) {
??? AThreadthr = new AThread();//①創(chuàng)建一個AThread線程對象
??? thr.start();
?? ?......//等待thr創(chuàng)建成功
??? ActivityManagerServicem = thr.mService;
??? mSelf =m;
??? //②調(diào)用ActivityThread的systemMain函數(shù)
??? ActivityThreadat = ActivityThread.systemMain();
??? mSystemThread= at;
?
??? //③得到一個Context對象,注意調(diào)用的函數(shù)名為getSystemContext,何為System Context
??? Contextcontext = at.getSystemContext();
??? context.setTheme(android.R.style.Theme_Holo);
??? m.mContext= context;
??? m.mFactoryTest= factoryTest;
?
??? //ActivtyStack是AMS中用來管理Activity的啟動和調(diào)度的核心類,以后再分析它
?? ?m.mMainStack = new ActivityStack(m, context,true);
??? //調(diào)用BSS的publish函數(shù),我們在第5章的BSS知識中介紹過了
??? m.mBatteryStatsService.publish(context);
??? //另外一個service:UsageStatsService。后續(xù)再分析該服務(wù)
??? m.mUsageStatsService.publish(context);
??? synchronized (thr) {
???????????thr.mReady = true;
???????????thr.notifyAll();//通知thr線程,本線程工作完成
???? }
?
??? //④調(diào)用AMS的startRunning函數(shù)
?? ?m.startRunning(null, null, null, null);
???????
?? returncontext;
}
在main函數(shù)中,我們又列出了4個關(guān)鍵函數(shù),分別是:
·??創(chuàng)建AThread線程。雖然AMS的main函數(shù)由ServerThread線程調(diào)用,但是AMS自己的工作并沒有放在ServerThread中去做,而是新創(chuàng)建了一個線程,即AThread線程。
·??ActivityThread.systemMain函數(shù)。初始化ActivityThread對象。
·??ActivityThread.getSystemContext函數(shù)。用于獲取一個Context對象,從函數(shù)名上看,該Context代表了System的上下文環(huán)境。
·??AMS的startRunning函數(shù)。
注意,main函數(shù)中有一處等待(wait)及一處通知(notifyAll),原因是:
·??main函數(shù)首先需要等待AThread所在線程啟動并完成一部分工作。
·??AThread完成那一部分工作后,將等待main函數(shù)完成后續(xù)的工作。
這種雙線程互相等待的情況,在Android代碼中比較少見,讀者只需了解它們的目的即可。下邊來分析以上代碼中的第一個關(guān)鍵點。
AThread的代碼如下:
[-->ActivityManagerService.java::AThread]
static class AThread extends Thread {//AThread從Thread類派生
?? ActivityManagerServicemService;
?? booleanmReady = false;
?? publicAThread() {
???? super("ActivityManager");//線程名就叫“ActivityManager”
?? }
?? publicvoid run() {
???? Looper.prepare();//看來,AThread線程將支持消息循環(huán)及處理功能
???? android.os.Process.setThreadPriority(//設(shè)置線程優(yōu)先級
???????????????????android.os.Process.THREAD_PRIORITY_FOREGROUND);
???? android.os.Process.setCanSelfBackground(false);
????? //創(chuàng)建AMS對象
?????ActivityManagerService m = new ActivityManagerService();
?????synchronized (this) {
?????????? mService= m;//賦值A(chǔ)Thread內(nèi)部成員變量mService,指向AMS
??????????notifyAll();? //通知main函數(shù)所在線程
????? }
?????synchronized (this) {
????????while (!mReady) {
?????????? try{
?????????????????wait();//等待main函數(shù)所在線程的notifyAll
???????????????}......
?????????? }
?????? }......
??? Looper.loop();//進入消息循環(huán)
?}
?}
從本質(zhì)上說,AThread是一個支持消息循環(huán)及處理的線程,其主要工作就是創(chuàng)建AMS對象,然后通知AMS的main函數(shù)。這樣看來,main函數(shù)等待的就是這個AMS對象。
AMS的構(gòu)造函數(shù)的代碼如下:
[-->ActivityManagerService.java::ActivityManagerService構(gòu)造]
private ActivityManagerService() {
??? FiledataDir = Environment.getDataDirectory();//指向/data/目錄
??? FilesystemDir = new File(dataDir, "system");//指向/data/system/目錄
???systemDir.mkdirs();//創(chuàng)建/data/system/目錄
?
??? //創(chuàng)建BatteryStatsService(以后簡稱BSS)和UsageStatsService(以后簡稱USS)
?? //我們在分析PowerManageService時已經(jīng)見過BSS了
???mBatteryStatsService = new BatteryStatsService(new File(
???????????????systemDir, "batterystats.bin").toString());
???mBatteryStatsService.getActiveStatistics().readLocked();
??? mBatteryStatsService.getActiveStatistics().writeAsyncLocked();
???mOnBattery = DEBUG_POWER ? true
???????????????: mBatteryStatsService.getActiveStatistics().getIsOnBattery();
???mBatteryStatsService.getActiveStatistics().setCallback(this);
?
??? //創(chuàng)建USS
??? mUsageStatsService= new UsageStatsService(new File(
???????????????systemDir, "usagestats").toString());
??? //獲取OpenGl版本
???GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version",
???????????ConfigurationInfo.GL_ES_VERSION_UNDEFINED);
???? //mConfiguration類型為Configuration,用于描述資源文件的配置屬性,例如
??? ?//字體、語言等。后文再討論這方面的內(nèi)容
????mConfiguration.setToDefaults();
????mConfiguration.locale = Locale.getDefault();
???? //mProcessStats為ProcessStats類型,用于統(tǒng)計CPU、內(nèi)存等信息。其內(nèi)部工作原理就是
??? //讀取并解析/proc/stat文件的內(nèi)容。該文件由內(nèi)核生成,用于記錄kernel及system
??? //一些運行時的統(tǒng)計信息。讀者可在Linux系統(tǒng)上通過man proc命令查詢詳細信息
????mProcessStats.init();
?
???? //解析/data/system/packages-compat.xml文件,該文件用于存儲那些需要考慮屏幕尺寸
??? //的APK的一些信息。讀者可參考AndroidManifest.xml中compatible-screens相關(guān)說明。
?? ?//當(dāng)APK所運行的設(shè)備不滿足要求時,AMS會根據(jù)設(shè)置的參數(shù)以采用屏幕兼容的方式去運行它
????mCompatModePackages = new CompatModePackages(this, systemDir);
?
???? Watchdog.getInstance().addMonitor(this);
???? //創(chuàng)建一個新線程,用于定時更新系統(tǒng)信息(和mProcessStats交互)
????mProcessStatsThread = new Thread("ProcessStats") {...//先略去該段代碼}
????mProcessStatsThread.start();
?}
AMS的構(gòu)造函數(shù)比想象得要簡單些,下面回顧一下它的工作:
·??創(chuàng)建BSS、USS、mProcessStats (ProcessStats類型)、mProcessStatsThread線程,這些都與系統(tǒng)運行狀況統(tǒng)計相關(guān)。
·??創(chuàng)建/data/system目錄,為mCompatModePackages(CompatModePackages類型)和mConfiguration(Configuration類型)等成員變量賦值。
AMS main函數(shù)的第一個關(guān)鍵點就分析到此,再來分析它的第二個關(guān)鍵點。
ActivityThread是Android Framework中一個非常重要的類,它代表一個應(yīng)用進程的主線程(對于應(yīng)用進程來說,ActivityThread的main函數(shù)確實是由該進程的主線程執(zhí)行),其職責(zé)就是調(diào)度及執(zhí)行在該線程中運行的四大組件。
注意應(yīng)用進程指那些運行APK的進程,它們由Zyote 派生(fork)而來,上面運行了dalvik虛擬機。與應(yīng)用進程相對的就是系統(tǒng)進程(包括Zygote和SystemServer)。
另外,讀者須將“應(yīng)用進程和系統(tǒng)進程”與“應(yīng)用APK和系統(tǒng)APK”的概念區(qū)分開來。APK的判別依賴其文件所在位置(如果apk文件在/data/app目錄下,則為應(yīng)用APK)。
該函數(shù)代碼如下:
[-->ActivityThread.java::systemMain]
public static final ActivityThread systemMain() {
?? HardwareRenderer.disable(true);//禁止硬件渲染加速
?? //創(chuàng)建一個ActivityThread對象,其構(gòu)造函數(shù)非常簡單
??ActivityThread thread = new ActivityThread();
??thread.attach(true);//調(diào)用它的attach函數(shù),注意傳遞的參數(shù)為true
?? returnthread;
?}
在分析ActivityThread的attach函數(shù)之前,先提一個問題供讀者思考:前面所說的ActivityThread代表應(yīng)用進程(其上運行了APK)的主線程,而SystemServer并非一個應(yīng)用進程,那么為什么此處也需要ActivityThread呢?
·??還記得在PackageManagerService分析中提到的framework-res.apk嗎?這個APK除了包含資源文件外,還包含一些Activity(如關(guān)機對話框),這些Activity實際上運行在SystemServer進程中[②]。從這個角度看,SystemServer是一個特殊的應(yīng)用進程。
·??另外,通過ActivityThread可以把Android系統(tǒng)提供的組件之間的交互機制和交互接口(如利用Context提供的API)也拓展到SystemServer中使用。
提示解答這個問題,對于理解SystemServer中各服務(wù)的交互方式是尤其重要的。
下面來看ActivityThread的attach函數(shù)。
[-->ActivityThread.java::attach]
private void attach(boolean system) {
??? sThreadLocal.set(this);
??? mSystemThread= system;//判斷是否為系統(tǒng)進程
??? if(!system) {
?????? ?......//應(yīng)用進程的處理流程
??? ?} else {//系統(tǒng)進程的處理流程,該情況只在SystemServer中處理
?????? //設(shè)置DDMS時看到的systemserver進程名為system_process
?????? android.ddm.DdmHandleAppName.setAppName("system_process");
?????? try {
????????????//ActivityThread的幾員大將出場,見后文的分析
????????????mInstrumentation = new Instrumentation();
????????????ContextImpl context = new ContextImpl();
????????????//初始化context,注意第一個參數(shù)值為getSystemContext
????????????context.init(getSystemContext().mPackageInfo, null, this);
????????????Application app = //利用Instrumentation創(chuàng)建一個Application對象
???????????? ???????Instrumentation.newApplication(Application.class,context);
??????????? ?//一個進程支持多個Application,mAllApplications用于保存該進程中
????????????//的Application對象
????????????mAllApplications.add(app);
???????????? mInitialApplication = app;//設(shè)置mInitialApplication
????????????app.onCreate();//調(diào)用Application的onCreate函數(shù)
?????????? }......//try/catch結(jié)束
????? }//if(!system)判斷結(jié)束
?
???? //注冊Configuration變化的回調(diào)通知
???? ViewRootImpl.addConfigCallback(newComponentCallbacks2() {
????????? publicvoid onConfigurationChanged(Configuration newConfig) {
????????????......//當(dāng)系統(tǒng)配置發(fā)生變化(如語言切換等)時,需要調(diào)用該回調(diào)
????????? }
???????????public void onLowMemory() {}
???????????public void onTrimMemory(int level) {}
??????? });
?}
attach函數(shù)中出現(xiàn)了幾個重要成員,其類型分別是Instrumentation類、Application類及Context類,它們的作用如下(為了保證準確,這里先引用Android的官方說明)。
·??Instrumentation:Base class for implementingapplication instrumentation code. When running with instrumentation turned on,this class will be instantiated for you before any of the application code,allowing you to monitor all of the interaction the system has with the application.An Instrumentation implementation is described to the system through anAndroidManifest.xml's <instrumentation> tag.大意是:Instrumentaion是一個工具類。當(dāng)它被啟用時,系統(tǒng)先創(chuàng)建它,再通過它來創(chuàng)建其他組件。另外,系統(tǒng)和組件之間的交互也將通過Instrumentation來傳遞,這樣,Instrumentation就能監(jiān)測系統(tǒng)和這些組件的交互情況了。在實際使用中,我們可以創(chuàng)建Instrumentation的派生類來進行相應(yīng)的處理。讀者可查詢Android中Junit的使用來了解Intrstrumentation的作用。本書不討論Intrstrumentation方面的內(nèi)容。
·??Application:Base class for those who need tomaintain global application state. You can provide your own implementation byspecifying its name in your AndroidManifest.xml's <application> tag,which will cause that class to be instantiated for you when the process foryour application/package is created.大意是:Application類保存了一個全局的application狀態(tài)。Application由AndroidManifest.xml中的<application>標(biāo)簽聲明。在實際使用時需定義Application的派生類。
·??Context:Interface to global informationabout an application environment. This is an abstract class whoseimplementation is provided by the Android system. It allows access toapplication-specific resources and classes, as well as up-calls forapplication-level operations such as launching activities, broadcasting andreceiving intents, etc.大意是:Context是一個接口,通過它可以獲取并操作Application對應(yīng)的資源、類,甚至包含于Application中的四大組件。
提示此處的Application是Android中的一個概念,可理解為一種容器,它內(nèi)部包含四大組件。另外,一個進程可以運行多個Application。
Context是一個抽象類,而由AMS創(chuàng)建的將是它的子類ContextImpl。如前所述,Context提供了Application的上下文信息,這些信息是如何傳遞給Context的呢?此問題包括兩個方面:
·??Context本身是什么?
·??Context背后所包含的上下文信息又是什么?
下面來關(guān)注上邊代碼中調(diào)用的getSystemContext函數(shù)。
[-->ActivityThread.java::getSystemContext]
public ContextImpl getSystemContext() {
? synchronized(this) {
?? if(mSystemContext == null) {//單例模式
?????? ContextImplcontext =? ContextImpl.createSystemContext(this);
?????? //LoadedApk是2.3引入的一個新類,代表一個加載到系統(tǒng)中的APK
?????? LoadedApkinfo = new LoadedApk(this, "android", context, null,
???????????????????????CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO);
?????? //初始化該ContextImpl對象
??????context.init(info, null, this);
????? //初始化資源信息
??????context.getResources().updateConfiguration(
??????????????????????? getConfiguration(),getDisplayMetricsLocked(
???????????????????????CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, false));
???????mSystemContext = context;//保存這個特殊的ContextImpl對象
????? }
?? }
??? returnmSystemContext;
}
以上代碼無非是先創(chuàng)建一個ContextImpl,然后再將其初始化(調(diào)用init函數(shù))。為什么函數(shù)名是getSystemContext呢?因為在初始化ContextImp時使用了一個LoadedApk對象。如注釋中所說,LoadedApk是Android 2.3引入的一個類,該類用于保存一些和APK相關(guān)的信息(如資源文件位置、JNI庫位置等)。在getSystemContext函數(shù)中初始化ContextImpl的這個LoadedApk所代表的package名為“android”,其實就是framework-res.apk,由于該APK僅供SystemServer使用,所以此處叫g(shù)etSystemContext。
上面這些類的關(guān)系比較復(fù)雜,可通過圖6-2展示它們之間的關(guān)系。
http://wiki.jikexueyuan.com/project/deep-android-v2/images/chapter6/image002.png" alt="image" />
圖6-2? ContextImpl和它的“兄弟”們
由圖6-2可知:
·??先來看派生關(guān)系, ApplicationContentResolver從ConentResolver派生,它主要用于和ContentProvider打交道。ContextImpl和ContextWrapper均從Context繼承,而Application則從ContextWrapper派生。
·??從社會關(guān)系角度看,ContextImpl交際面最廣。它通過mResources指向Resources,mPackageInfo指向LoadedApk,mMainThread指向ActivityThread,mContentResolver指向ApplicationContentResolver。
·??ActivityThread代表主線程,它通過mInstrumentation指向Instrumentation。另外,它還保存多個Application對象。
注意在函數(shù)中有些成員變量的類型為基類類型,而在圖6-2中直接指向了實際類型。
調(diào)用systemMain函數(shù)結(jié)束后,我們得到了什么?
·??得到一個ActivityThread對象,它代表應(yīng)用進程的主線程。
·??得到一個Context對象,它背后所指向的Application環(huán)境與framework-res.apk有關(guān)。
費了如此大的功夫,systemMain函數(shù)的目的到底是什么?一針見血地說:
systemMain函數(shù)將為SystemServer進程搭建一個和應(yīng)用進程一樣的Android運行環(huán)境。這句話涉及兩個概念。
·??進程:來源于操作系統(tǒng),是在OS中看到的運行體。我們編寫的代碼一定要運行在一個進程中。
·??Android運行環(huán)境:Android努力構(gòu)筑了一個自己的運行環(huán)境。在這個環(huán)境中,進程的概念被模糊化了。組件的運行及它們之間的交互均在該環(huán)境中實現(xiàn)。
Android運行環(huán)境是構(gòu)建在進程之上的。有Android開發(fā)經(jīng)驗的讀者可能會發(fā)現(xiàn),在應(yīng)用程序中,一般只和Android運行環(huán)境交互?;谕瑯拥牡览?,SystemServer希望它內(nèi)部的那些Service也通過Android運行環(huán)境交互,因此也需為它創(chuàng)建一個運行環(huán)境。由于SystemServer的特殊性,此處調(diào)用了systemMain函數(shù),而普通的應(yīng)用進程將在主線程中調(diào)用ActivityThread的main函數(shù)來創(chuàng)建Android運行環(huán)境。
另外,ActivityThread雖然本意是代表進程的主線程,但是作為一個Java類,它的實例到底由什么線程創(chuàng)建,恐怕不是ActivityThread自己能做主的,所以在SystemServer中可以發(fā)現(xiàn),ActivityThread對象由其他線程創(chuàng)建,而在應(yīng)用進程中,ActivityThread將由主線程來創(chuàng)建。
該函數(shù)在上一節(jié)已經(jīng)見過了。調(diào)用該函數(shù)后,將得到一個代表系統(tǒng)進程的Context對象。到底什么是Context?先來看如圖6-3所示的Context家族圖譜。
注意該族譜成員并不完全。另外,Activity、Service和Application所實現(xiàn)的接口也未畫出。
http://wiki.jikexueyuan.com/project/deep-android-v2/images/chapter6/image003.png" alt="image" />
圖6-3? Context家族圖譜
由圖6-3可知:
·??ContextWrapper比較有意思,其在SDK中的說明為“Proxying implementation ofContext that simply delegates all of its calls to another Context. Can besubclassed to modify behavior without changing the original Context.”大概意思是:ContextWrapper是一個代理類,被代理的對象是另外一個Context。在圖6-3中,被代理的類其實是ContextImpl,由ContextWrapper通過mBase成員變量指定。讀者可查看ContextWrapper.java,其內(nèi)部函數(shù)功能的實現(xiàn)最終都由mBase完成。這樣設(shè)計的目的是想把ContextImpl隱藏起來。
·??Application從ContextWrapper派生,并實現(xiàn)了ComponentCallbacks2接口。Application中有一個LoadedApk類型的成員變量mLoadedApk。LoadedApk代表一個APK文件。由于一個AndroidManifest.xml文件只能聲明一個Application標(biāo)簽,所以一個Application必然會和一個LoadedApk綁定。
·??Service從ContextWrapper派生,其中Service內(nèi)部成員變量mApplication指向Application(在AndroidManifest.xml中,Service只能作為Application的子標(biāo)簽,所以在代碼中Service必然會和一個Application綁定)。
·??ContextThemeWrapper重載了和Theme(主題)相關(guān)的兩個函數(shù)。這些和界面有關(guān),所以Activity作為Android系統(tǒng)中的UI容器,必然也會從ContextThemeWrapper派生。與Service一樣,Activity內(nèi)部也通過mApplication成員變量指向Application。
對Context的分析先到這里,再來分析第三個關(guān)鍵函數(shù)startRunning。
[-->ActivityManagerService.java::startRunning]
//注意調(diào)用該函數(shù)時所傳遞的4個參數(shù)全為null
public final void startRunning(String pkg, Stringcls, String action,
??????????? ????????????????????????String data) {
??synchronized(this) {
??? ?if (mStartRunning) return; ?//如果已經(jīng)調(diào)用過該函數(shù),則直接返回
?
????mStartRunning = true;
???? //mTopComponent最終賦值為null
????mTopComponent = pkg != null && cls != null
???????????????????? new ComponentName(pkg, cls) : null;
????mTopAction = action != null ? action : Intent.ACTION_MAIN;
????mTopData = data; //mTopData最終為null
???? if(!mSystemReady) return; //此時mSystemReady為false,所以直接返回
??? }
???systemReady(null);//這個函數(shù)很重要,可惜不在本次startRunning中調(diào)用
}
startRunning函數(shù)很簡單,此處不贅述。
至此,ASM 的main函數(shù)所涉及的4個知識點已全部分析完。下面回顧一下AMS 的main函數(shù)的工作。
AMS的main函數(shù)的目的有兩個:
·??首先也是最容易想到的目的是創(chuàng)建AMS對象。
·??另外一個目的比較隱晦,但是非常重要,那就是創(chuàng)建一個供SystemServer進程使用的Android運行環(huán)境。
根據(jù)目前所分析的代碼,Android運行環(huán)境將包括兩個成員:ActivityThread和ContextImpl(一般用它的基類Context)。
圖6-4展示了在這兩個類中定義的一些成員變量,通過它們可看出ActivityThread及ContextImpl的作用。
http://wiki.jikexueyuan.com/project/deep-android-v2/images/chapter6/image004.png" alt="image" />
圖6-4? ActivityThread和ContextImpl的部分成員變量
由圖6-4可知:
·??ActivityThread中有一個mLooper成員,它代表一個消息循環(huán)。這恐怕是ActivityThread被稱做“Thread”的一個直接證據(jù)。另外,mServices用于保存Service,Activities用于保存ActivityClientRecord,mAllApplications用于保存Application。關(guān)于這些變量的具體作用,以后遇到時再說。
·??對于ContextImpl,其成員變量表明它和資源、APK文件有關(guān)。
AMS的main函數(shù)先分析到此,至于其創(chuàng)建的Android運行環(huán)境將在下節(jié)分析中派上用場。
接下來分析AMS的第三個調(diào)用函數(shù)setSystemProcess。
AMS的setSystemProcess的代碼如下:
[-->ActivityManagerService.java::setSystemProcess]
public static void setSystemProcess() {
? try {
??????ActivityManagerService m = mSelf;
?????? //向ServiceManager注冊幾個服務(wù)
? ?????ServiceManager.addService("activity",m);
?????? //用于打印內(nèi)存信息
??????ServiceManager.addService("meminfo", new MemBinder(m));
?
?????? /*
??????? Android4.0新增的,用于打印應(yīng)用進程使用硬件顯示加速方面的信息(Applications
???????? Graphics Acceleration Info)。讀者通過adb shell dumpsys gfxinfo看看具體的
???????? 輸出
?????? */
??????ServiceManager.addService("gfxinfo", new GraphicsBinder(m));
?
??????? if(MONITOR_CPU_USAGE)//該值默認為true,添加cpuinfo服務(wù)
????????????ServiceManager.addService("cpuinfo", new CpuBinder(m));
?
??????? //向SM注冊權(quán)限管理服務(wù)PermissionController
???????ServiceManager.addService("permission", newPermissionController(m));
?
??????/*??? 重要說明:
??????? 向PackageManagerService查詢package名為"android"的ApplicationInfo。
??????? 注意這句調(diào)用:雖然PKMS和AMS同屬一個進程,但是二者交互仍然借助Context。
??????? 其實,此處完全可以直接調(diào)用PKMS的函數(shù)。為什么要費如此周折呢
????? */
??????ApplicationInfo info = //使用AMS的mContext對象
???????????????mSelf.mContext.getPackageManager().getApplicationInfo(
??????????????????????? "android",STOCK_PM_FLAGS);
?
??????????//①調(diào)用ActivityThread的installSystemApplicationInfo函數(shù)
?????????? ?mSystemThread.installSystemApplicationInfo(info);
???????????synchronized (mSelf) {
???????????????//②此處涉及AMS對進程的管理,見下文分析
???????????????ProcessRecord app = mSelf.newProcessRecordLocked(
???????????????????????mSystemThread.getApplicationThread(), info,
??????????????????????? info.processName);//注意,最后一個參數(shù)為字符串,值為“system”
???????????????app.persistent = true;
???????????????app.pid = MY_PID;
???????????????app.maxAdj = ProcessList.SYSTEM_ADJ;
???????????????//③保存該ProcessRecord對象
???????????????mSelf.mProcessNames.put(app.processName, app.info.uid, app);
???????????????synchronized (mSelf.mPidsSelfLocked) {
???????????????????mSelf.mPidsSelfLocked.put(app.pid, app);
???????????????}
???????????????//根據(jù)系統(tǒng)當(dāng)前狀態(tài),調(diào)整進程的調(diào)度優(yōu)先級和OOM_Adj,后續(xù)將詳細分析該函數(shù)
??????? ????????mSelf.updateLruProcessLocked(app, true,true);
???????????}
??????? } ......//拋異常
??? }
在以上代碼中列出了一個重要說明和兩個關(guān)鍵點。
·??重要說明:AMS向PKMS查詢名為“android”的ApplicationInfo。此處AMS和PKMS的交互是通過Context來完成的,查看這一系列函數(shù)調(diào)用的代碼,最終發(fā)現(xiàn)AMS將通過Binder發(fā)送請求給PKMS來完成查詢功能。AMS和PKMS同屬一個進程,它們完全可以不通過Context來交互。此處為何要如此大費周章呢?原因很簡單,Android希望SystemServer中的服務(wù)也通過Android運行環(huán)境來交互。這更多是從設(shè)計上來考慮的,比如組件之間交互接口的統(tǒng)一及未來系統(tǒng)的可擴展性。
·??關(guān)鍵點一:ActivityThread的installSystemApplicationInfo函數(shù)。
·??關(guān)鍵點二:ProcessRecord類,它和AMS對進程的管理有關(guān)。
通過重要說明,相信讀者能真正理解AMS的 main函數(shù)中第二個隱含目的的作用,故此處不再展開敘述。
現(xiàn)在來看第一個關(guān)鍵點,即ActivityThread的installSystemApplicationInfo函數(shù)。
installSystemApplicationInfo函數(shù)的參數(shù)為一個ApplicationInfo對象,該對象由AMS通過Context查詢PKMS中一個名為“android”的package得來(根據(jù)前面介紹的知識,目前只有framework-res.apk聲明其package名為“android”)。
再來看installSystemApplicationInfo的代碼,如下所示:
[-->ActivityThread.java::installSystemApplicationInfo]
public voidinstallSystemApplicationInfo(ApplicationInfo info) {
?synchronized (this) {
?? //返回的ContextImpl對象即之前在AMS的main函數(shù)一節(jié)中創(chuàng)建的那個對象
???ContextImpl context = getSystemContext();
??? //又調(diào)用init初始化該Context,是不是重復(fù)調(diào)用init了?
???context.init(new LoadedApk(this, "android", context, info,
??????????????CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO), null, this);
???? //創(chuàng)建一個Profiler對象,用于性能統(tǒng)計
??? ?mProfiler = new Profiler();
???? }
?}
在以上代碼中看到調(diào)用context.init的地方,讀者可能會有疑惑,getSystemContext函數(shù)將返回mSystemContext,而此mSystemContext在AMS的main函數(shù)中已經(jīng)初始化過了,此處為何再次初始化呢?
仔細查看看代碼便會發(fā)現(xiàn):
·??第一次執(zhí)行init時,在LoadedApk構(gòu)造函數(shù)中第四個表示ApplicationInfo的參數(shù)為null。
·??第二次執(zhí)行init時,LoadedApk構(gòu)造函數(shù)的第四個參數(shù)不為空,即該參數(shù)將真正指向一個實際的ApplicationInfo,該ApplicationInfo來源于framework-res.apk。
基于上面的信息,某些讀者可能馬上能想到:Context第一次執(zhí)行init的目的僅僅是為了創(chuàng)建一個Android運行環(huán)境,而該Context并沒有和實際的ApplicationInfo綁定。而第二次執(zhí)行init前,先利用Context和PKMS交互得到一個實際的ApplicationInfo,然后再通過init將此Context和ApplicationInfo綁定。
是否覺得前面的疑惑已豁然而解?且慢,此處又拋出了一個更難的問題:
第一次執(zhí)行init后得到的Context雖然沒有綁定ApplicationInfo,不是也能使用嗎?此處為何非要和一個ApplicationInfo綁定?
答案很簡單,因為framework-res.apk(包括后面將介紹的SettingsProvider.apk)運行在SystemServer中。和其他所有apk一樣,它的運行需要一個正確初始化的Android運行環(huán)境。
長噓一口氣,這個大難題終于弄明白了!在此即基礎(chǔ)上,AMS下一步的工作就就順理成章了。
由于framework-res.apk是一個APK文件,和其他APK文件一樣,它應(yīng)該運行在一個進程中。而AMS是專門用于進程管理和調(diào)度的,所以運行APK的進程應(yīng)該在AMS中有對應(yīng)的管理結(jié)構(gòu)。因此AMS下一步工作就是將這個運行環(huán)境和一個進程管理結(jié)構(gòu)對應(yīng)起來并交由AMS統(tǒng)一管理。
AMS中的進程管理結(jié)構(gòu)是ProcessRecord。
分析ProcessRecord之前,先來思考一個問題:
AMS如何與應(yīng)用進程交互?例如AMS啟動一個位于其他進程的Activity,由于該Activity運行在另外一進程中,因此AMS勢必要和該進程進行跨進程通信。
答案自然是通過Binder進行通信。為此,Android提供了一個IApplicationThread接口,該接口定義了AMS和應(yīng)用進程之間的交互函數(shù),如圖6-5所示為該接口的家族圖譜。
http://wiki.jikexueyuan.com/project/deep-android-v2/images/chapter6/image005.png" alt="image" />
圖6-5? ApplicationThread類
由圖6-5可知:
·??ApplicationThreadNative實現(xiàn)了IApplicationThread接口。從該接口定義的函數(shù)可知,AMS通過它可以和應(yīng)用進程進行交互,例如,AMS啟動一個Activity的時候會調(diào)用該接口的scheduleLaunchActivity函數(shù)。
·??ActivityThread通過成員變量mAppThread指向它的內(nèi)部類ApplicationThread,而ApplicationThread從ApplicationThreadNative派生。
基于以上知識,讀者能快速得出下面問題的答案嗎?
IApplicationThread的Binder服務(wù)端在應(yīng)用進程中還是在AMS中?
提示如果讀者知道Binder系統(tǒng)支持客戶端監(jiān)聽服務(wù)端的死亡消息,那么這個問題的答案就簡單了:服務(wù)端自然在應(yīng)用進程中,因為AMS需要監(jiān)聽?wèi)?yīng)用進程的死亡通知。
有了IApplicationThread接口,AMS就可以和應(yīng)用進程交互了。例如,對于下面一個簡單的函數(shù):
[-->ActivityThread.java::scheduleStopActivity]
public final void scheduleStopActivity(IBindertoken, boolean showWindow,
?????????????????????????????????????intconfigChanges) {
??queueOrSendMessage(//該函數(shù)內(nèi)部將給一個Handler發(fā)送對應(yīng)的消息
???????????????showWindow ? H.STOP_ACTIVITY_SHOW : H.STOP_ACTIVITY_HIDE,
???????????????token, 0, configChanges);
?}
當(dāng)AMS想要停止(stop)一個Activity時,會調(diào)用對應(yīng)進程IApplicationThread Binder客戶端的scheduleStopActivity函數(shù)。該函數(shù)服務(wù)端實現(xiàn)的就是向ActivityThread所在線程發(fā)送一個消息。在應(yīng)用進程中,ActivityThread運行在主線程中,所以這個消息最終在主線程被處理。
提示Activity的onStop函數(shù)也將在主線程中被調(diào)用。
IApplicationThread僅僅是AMS和另外一個進程交互的接口,除此之外,AMS還需要更多的有關(guān)該進程的信息。在AMS中,進程的信息都保存在ProcessRecord數(shù)據(jù)結(jié)構(gòu)中。那么,ProcessRecord是什么呢?先來看setSystemProcess的第二個關(guān)鍵點,即newProcessRecordLocked函數(shù),其代碼如下:
[-->ActivityManagerService.java::newProcessRecordLocked]
final ProcessRecordnewProcessRecordLocked(IApplicationThread thread,
?????????? ?????ApplicationInfo info, String customProcess) {
?? Stringproc = customProcess != null ? customProcess : info.processName;
??BatteryStatsImpl.Uid.Proc ps = null;
??BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
??synchronized (stats) {
??????? //BSImpl將為該進程創(chuàng)建一個耗電量統(tǒng)計項
??????? ps =stats.getProcessStatsLocked(info.uid, proc);
?? }
?? //創(chuàng)建一個ProcessRecord對象,用于和其他進程通信的thread作為第一個參數(shù)
?? returnnew ProcessRecord(ps, thread, info, proc);
?}
ProcessRecord的成員變量較多,先來看看再其構(gòu)造函數(shù)中都初始化了哪些成員變量。
[-->ProcessRecord.java::ProcessRecord]
ProcessRecord(BatteryStatsImpl.Uid.Proc_batteryStats,
??????? IApplicationThread_thread,ApplicationInfo _info, String _processName) {
????batteryStats = _batteryStats; //用于電量統(tǒng)計
???? info =_info; //保存ApplicationInfo
????processName = _processName; //保存進程名
????? //一個進程能運行多個Package,pkgList用于保存package名
????pkgList.add(_info.packageName);
???? thread= _thread;//保存IApplicationThread,通過它可以和應(yīng)用進程交互
?
???? //下面這些xxxAdj成員變量和進程調(diào)度優(yōu)先級及OOM_adj有關(guān)。以后再分析它的作用
???? maxAdj= ProcessList.EMPTY_APP_ADJ;
????hiddenAdj = ProcessList.HIDDEN_APP_MIN_ADJ;
????curRawAdj = setRawAdj = -100;
???? curAdj= setAdj = -100;
? ?//用于控制該進程是否常駐內(nèi)存(即使被殺掉,系統(tǒng)也會重啟它),只有重要的進程才會有此待遇
????persistent = false;
???? removed= false;
}
ProcessRecord除保存和應(yīng)用進程通信的IApplicationThread對象外,還保存了進程名、不同狀態(tài)對應(yīng)的Oom_adj值及一個ApplicationInfo。一個進程雖然可運行多個Application,但是ProcessRecord一般保存該進程中先運行的那個Application的ApplicationInfo。
至此,已經(jīng)創(chuàng)建了一個ProcessRecord對象,和其他應(yīng)用進程不同的是,該對象對應(yīng)的進程為SystemServer。為了彰顯其特殊性,AMS為其中的一些成員變量設(shè)置了特定的值:
?? app.persistent = true;//設(shè)置該值為true
?? app.pid =MY_PID;//設(shè)置pid為SystemServer的進程號
?? app.maxAdj= ProcessList.SYSTEM_ADJ;//設(shè)置最大OOM_Adj,系統(tǒng)進程默認值為-16
?? //另外,app的processName被設(shè)置成“system”
這時,一個針對SystemServer的ProcessRecord對象就創(chuàng)建完成了。此后AMS將把它并入自己的勢力范圍內(nèi)。
AMS中有兩個成員變量用于保存ProcessRecord,一個是mProcessNames,另一個是mPidsSelfLocked,如圖6-6所示為這兩個成員變量的數(shù)據(jù)結(jié)構(gòu)示意圖。
http://wiki.jikexueyuan.com/project/deep-android-v2/images/chapter6/image006.png" alt="image" />
圖6-6? mPidsSelfLocked和mProcessNames數(shù)據(jù)結(jié)構(gòu)示意圖
現(xiàn)在來總結(jié)回顧setSystemProcess的工作:
·??注冊AMS、meminfo、gfxinfo等服務(wù)到ServiceManager中。
·??根據(jù)PKMS返回的ApplicationInfo初始化Android運行環(huán)境,并創(chuàng)建一個代表SystemServer進程的ProcessRecord,從此,SystemServer進程也并入AMS的管理范圍內(nèi)。
?
還記得Settings數(shù)據(jù)庫嗎?SystemServer中很多Service都需要向它查詢配置信息。為此,Android提供了一個SettingsProvider來幫助開發(fā)者。該Provider在SettingsProvider.apk中,installSystemProviders就會加載該APK并把SettingsProvider放到SystemServer進程中來運行。
此時的SystemServer已經(jīng)加載了framework-res.apk,現(xiàn)在又要加載另外一個APK文件,這就是多個APK運行在同一進程的典型案例。另外,通過installSystemProviders函數(shù)還能見識ContentProvider的安裝過程,下面就來分析它。
提示讀者在定制自己的Android系統(tǒng)時,萬不可去掉/system/app/SettingsProvider.apk,否則系統(tǒng)將無法正常啟動。
[-->ActivityManagerService.java::installSystemProviders]
public static final void installSystemProviders(){
?List<ProviderInfo> providers;
?synchronized (mSelf) {
??? /*
??? 從mProcessNames找到進程名為“system”且uid為SYSTEM_UID的ProcessRecord,
?? ?返回值就是前面在installSystemApplication中創(chuàng)建的那個ProcessRecord,它代表
?? ?SystemServer進程
??? */
???ProcessRecord app = mSelf.mProcessNames.get("system",Process.SYSTEM_UID);
?
??? //①關(guān)鍵調(diào)用,見下文分析
??? providers= mSelf.generateApplicationProvidersLocked(app);
??? if(providers != null) {
?????? ......//將非系統(tǒng)APK(即未設(shè)ApplicationInfo.FLAG_SYSTEM標(biāo)志)提供的Provider
????? //從providers列表中去掉
??????? }
???? if(providers != null) {//②為SystemServer進程安裝Provider
?????????mSystemThread.installSystemProviders(providers);
???? }
??? //監(jiān)視Settings數(shù)據(jù)庫中Secure表的變化,目前只關(guān)注long_press_timeout配置的變化
????mSelf.mCoreSettingsObserver = new CoreSettingsObserver(mSelf);
?
???? //UsageStatsService的工作,以后再討論
????mSelf.mUsageStatsService.monitorPackages();
?}
在代碼