1 以桌面啓動一個應用Activity爲例,onClick事件後,會調用startActivityForResult(Intent, int)
public void startActivityForResult(Intent intent, int requestCode, Bundle options) { 2 if (mParent == null) {
//Activity啓動執行交由Instrumentation對象去處理 3 Instrumentation.ActivityResult ar = 4 mInstrumentation.execStartActivity(
//mMainThread 在attach方法中被設置,當ActivityThread PerformLauchActivity,調用attach把ActivityThread.this傳送過來
//mMainThread.getApplicationThread()它是一個進程通訊服務端存根對象,提供了不少操做ActivityThread的方法,它繼承了ApplicationThreadNative 5 this, mMainThread.getApplicationThread(), mToken, this, 6 intent, requestCode, options); 7 if (ar != null) { 8 mMainThread.sendActivityResult( 9 mToken, mEmbeddedID, requestCode, ar.getResultCode(), 10 ar.getResultData()); 11 } 12 if (requestCode >= 0) { 13 // If this start is requesting a result, we can avoid making 14 // the activity visible until the result is received. Setting 15 // this code during onCreate(Bundle savedInstanceState) or onResume() will keep the 16 // activity hidden during this time, to avoid flickering. 17 // This can only be done when a result is requested because 18 // that guarantees we will get information back when the 19 // activity is finished, no matter what happens to it. 20 mStartedActivity = true; 21 } 22 23 final View decor = mWindow != null ? mWindow.peekDecorView() : null; 24 if (decor != null) { 25 decor.cancelPendingInputEvents(); 26 } 27 // TODO Consider clearing/flushing other event sources and events for child windows. 28 } else { 29 if (options != null) { 30 mParent.startActivityFromChild(this, intent, requestCode, options); 31 } else { 32 // Note we want to go through this method for compatibility with 33 // existing applications that may have overridden it. 34 mParent.startActivityFromChild(this, intent, requestCode); 35 } 36 } 37 }
AMS由ActivityManagerNative(之後簡稱AMN)類派生,並實現Watchdog.Monitor和BatteryStatsImpl.BatteryCallback接口。而AMN由Binder派生,實現了IActivityManager接口。java
客戶端使用ActivityManager類。因爲AMS是系統核心服務,不少API不能開放供客戶端使用,因此設計者沒有讓ActivityManager直接加入AMS家族。在ActivityManager類內部經過調用AMN的getDefault函數獲得一個ActivityManagerProxy對象,經過它可與AMS通訊。android
AMS由SystemServer的ServerThread線程建立,提取它的調用軌跡,代碼以下:windows
[-->SystemServer.java::ServerThread的run函數]app
//①調用main函數,獲得一個Context對象 context =ActivityManagerService.main(factoryTest); //②setSystemProcess:這樣SystemServer進程可加到AMS中,並被它管理 ActivityManagerService.setSystemProcess(); //③installSystemProviders:將SettingsProvider放到SystemServer進程中來運行 ActivityManagerService.installSystemProviders(); //④在內部保存WindowManagerService(之後簡稱WMS) ActivityManagerService.self().setWindowManager(wm); //⑤和WMS交互,彈出「啓動進度「對話框 ActivityManagerNative.getDefault().showBootMessage( context.getResources().getText( //該字符串中文爲:「正在啓動應用程序」 com.android.internal.R.string.android_upgrading_starting_apps), false); //⑥AMS是系統的核心,只有它準備好後,才能調用其餘服務的systemReady //注意,有少許服務在AMS systemReady以前就緒,它們不影響此處的分析 ActivityManagerService.self().systemReady(newRunnable() { publicvoid run() { startSystemUi(contextF);//啓動systemUi。如此,狀態欄就準備好了 if(batteryF != null) batteryF.systemReady(); if(networkManagementF != null) networkManagementF.systemReady(); ...... Watchdog.getInstance().start();//啓動Watchdog ......//調用其餘服務的systemReady函數 }
[-->ActivityManagerService.java::main]ide
AThread thr = new AThread();//①建立一個AThread線程對象 thr.start(); ......//等待thr建立成功 ActivityManagerService m = thr.mService; mSelf =m; //②調用ActivityThread的systemMain函數 ActivityThread at = ActivityThread.systemMain(); mSystemThread= at; //③獲得一個Context對象,注意調用的函數名爲getSystemContext,何爲System Context Context context = at.getSystemContext(); context.setTheme(android.R.style.Theme_Holo); m.mContext= context; m.mFactoryTest= factoryTest; //ActivtyStack是AMS中用來管理Activity的啓動和調度的核心類,之後再分析它 m.mMainStack = new ActivityStack(m, context,true); //調用BSS的publish函數,咱們在第5章的BSS知識中介紹過了 m.mBatteryStatsService.publish(context); //另一個service:UsageStatsService。後續再分析該服務 m.mUsageStatsService.publish(context); synchronized (thr) { thr.mReady = true; thr.notifyAll();//通知thr線程,本線程工做完成 } //④調用AMS的startRunning函數 m.startRunning(null, null, null, null); return context; }
在main函數中,咱們又列出了4個關鍵函數,分別是:函數
建立AThread線程。雖然AMS的main函數由ServerThread線程調用,可是AMS本身的工做並無放在ServerThread中去作,而是新建立了一個線程,即AThread線程。工具
· ActivityThread.systemMain函數。初始化ActivityThread對象。oop
· ActivityThread.systemMain函數。初始化ActivityThread對象。字體
· ActivityThread.getSystemContext函數。用於獲取一個Context對象,從函數名上看,該Context表明了System的上下文環境。this
· AMS的startRunning函數。
注意,main函數中有一處等待(wait)及一處通知(notifyAll),緣由是:
· main函數首先須要等待AThread所在線程啓動並完成一部分工做。
· AThread完成那一部分工做後,將等待main函數完成後續的工做。
AThread的代碼以下:
[-->ActivityManagerService.java::AThread]
static class AThread extends Thread {//AThread從Thread類派生 ActivityManagerServicemService; booleanmReady = false; publicAThread() { super("ActivityManager");//線程名就叫「ActivityManager」 } publicvoid run() { Looper.prepare();//看來,AThread線程將支持消息循環及處理功能 android.os.Process.setThreadPriority(//設置線程優先級 android.os.Process.THREAD_PRIORITY_FOREGROUND); android.os.Process.setCanSelfBackground(false); //建立AMS對象 ActivityManagerService m = new ActivityManagerService(); synchronized (this) { mService= m;//賦值AThread內部成員變量mService,指向AMS notifyAll(); //通知main函數所在線程 } synchronized (this) { while (!mReady) { try{ wait();//等待main函數所在線程的notifyAll }...... } }...... Looper.loop();//進入消息循環 } }
從本質上說,AThread是一個支持消息循環及處理的線程,其主要工做就是建立AMS對象,而後通知AMS的main函數。這樣看來,main函數等待的就是這個AMS對象。
AMS的構造函數的代碼以下:
[-->ActivityManagerService.java::ActivityManagerService構造]
private ActivityManagerService() { FiledataDir = Environment.getDataDirectory();//指向/data/目錄 FilesystemDir = new File(dataDir, "system");//指向/data/system/目錄 systemDir.mkdirs();//建立/data/system/目錄 //建立BatteryStatsService(之後簡稱BSS)和UsageStatsService(之後簡稱USS) //咱們在分析PowerManageService時已經見過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); //建立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,用於描述資源文件的配置屬性,例如 //字體、語言等。後文再討論這方面的內容 mConfiguration.setToDefaults(); mConfiguration.locale = Locale.getDefault(); //mProcessStats爲ProcessStats類型,用於統計CPU、內存等信息。其內部工做原理就是 //讀取並解析/proc/stat文件的內容。該文件由內核生成,用於記錄kernel及system //一些運行時的統計信息。讀者可在Linux系統上經過man proc命令查詢詳細信息 mProcessStats.init(); //解析/data/system/packages-compat.xml文件,該文件用於存儲那些須要考慮屏幕尺寸 //的APK的一些信息。讀者可參考AndroidManifest.xml中compatible-screens相關說明。 //當APK所運行的設備不知足要求時,AMS會根據設置的參數以採用屏幕兼容的方式去運行它 mCompatModePackages = new CompatModePackages(this, systemDir); Watchdog.getInstance().addMonitor(this); //建立一個新線程,用於定時更新系統信息(和mProcessStats交互) mProcessStatsThread = new Thread("ProcessStats") {...//先略去該段代碼} mProcessStatsThread.start(); }
AMS的構造函數比想象得要簡單些,下面回顧一下它的工做:
· 建立BSS、USS、mProcessStats (ProcessStats類型)、mProcessStatsThread線程,這些都與系統運行情況統計相關。
· 建立/data/system目錄,爲mCompatModePackages(CompatModePackages類型)和mConfiguration(Configuration類型)等成員變量賦值。
ActivityThread是Android Framework中一個很是重要的類,它表明一個應用進程的主線程(對於應用進程來講,ActivityThread的main函數確實是由該進程的主線程執行),其職責就是調度及執行在該線程中運行的四大組件。
注意應用進程指那些運行APK的進程,它們由Zyote 派生(fork)而來,上面運行了dalvik虛擬機。與應用進程相對的就是系統進程(包括Zygote和SystemServer)。
另外,讀者須將「應用進程和系統進程」與「應用APK和系統APK」的概念區分開來。APK的判別依賴其文件所在位置(若是apk文件在/data/app目錄下,則爲應用APK)。
[-->ActivityThread.java::systemMain]
public static final ActivityThread systemMain() { HardwareRenderer.disable(true);//禁止硬件渲染加速 //建立一個ActivityThread對象,其構造函數很是簡單 ActivityThread thread = new ActivityThread(); thread.attach(true);//調用它的attach函數,注意傳遞的參數爲true return thread; }
在分析ActivityThread的attach函數以前,先提一個問題供讀者思考:前面所說的ActivityThread表明應用進程(其上運行了APK)的主線程,而SystemServer並不是一個應用進程,那麼爲何此處也須要ActivityThread呢?
· 還記得在PackageManagerService分析中提到的framework-res.apk嗎?這個APK除了包含資源文件外,還包含一些Activity(如關機對話框),這些Activity實際上運行在SystemServer進程中[②]。從這個角度看,SystemServer是一個特殊的應用進程。
· 另外,經過ActivityThread能夠把Android系統提供的組件之間的交互機制和交互接口(如利用Context提供的API)也拓展到SystemServer中使用。
下面來看ActivityThread的attach函數。
[-->ActivityThread.java::attach]
private void attach(boolean system) { sThreadLocal.set(this); mSystemThread= system;//判斷是否爲系統進程 if(!system) { ......//應用進程的處理流程 } else {//系統進程的處理流程,該狀況只在SystemServer中處理 //設置DDMS時看到的systemserver進程名爲system_process android.ddm.DdmHandleAppName.setAppName("system_process"); try { //ActivityThread的幾員大將出場,見後文的分析 mInstrumentation = new Instrumentation(); ContextImpl context = new ContextImpl(); //初始化context,注意第一個參數值爲getSystemContext context.init(getSystemContext().mPackageInfo, null, this); Application app = //利用Instrumentation建立一個Application對象 Instrumentation.newApplication(Application.class,context); //一個進程支持多個Application,mAllApplications用於保存該進程中 //的Application對象 mAllApplications.add(app); mInitialApplication = app;//設置mInitialApplication app.onCreate();//調用Application的onCreate函數 }......//try/catch結束 }//if(!system)判斷結束 //註冊Configuration變化的回調通知 ViewRootImpl.addConfigCallback(newComponentCallbacks2() { publicvoid onConfigurationChanged(Configuration newConfig) { ......//當系統配置發生變化(如語言切換等)時,須要調用該回調 } public void onLowMemory() {} public void onTrimMemory(int level) {} }); }
attach函數中出現了幾個重要成員,其類型分別是Instrumentation類、Application類及Context類
Instrumentaion是一個工具類。當它被啓用時,系統先建立它,再經過它來建立其餘組件。另外,系統和組件之間的交互也將經過Instrumentation來傳遞,這樣,Instrumentation就能監測系統和這些組件的交互狀況了。在實際使用中,咱們能夠建立Instrumentation的派生類來進行相應的處理。讀者可查詢Android中Junit的使用來了解Intrstrumentation的做用。
Application類保存了一個全局的application狀態。Application由AndroidManifest.xml中的<application>標籤聲明。在實際使用時需定義Application的派生類。
Context是一個接口,經過它能夠獲取並操做Application對應的資源、類,甚至包含於Application中的四大組件。
Context是一個抽象類,而由AMS建立的將是它的子類ContextImpl。如前所述,Context提供了Application的上下文信息,這些信息是如何傳遞給Context的呢?此問題包括兩個方面:
· Context自己是什麼?
· Context背後所包含的上下文信息又是什麼?
下面來關注上邊代碼中調用的getSystemContext函數。
[-->ActivityThread.java::getSystemContext]
public ContextImpl getSystemContext() { synchronized(this) { if(mSystemContext == null) {//單例模式 ContextImpl context = ContextImpl.createSystemContext(this); //LoadedApk是2.3引入的一個新類,表明一個加載到系統中的APK LoadedApk info = 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對象 } } return mSystemContext; }
以上代碼無非是先建立一個ContextImpl,而後再將其初始化(調用init函數)。爲何函數名是getSystemContext呢?由於在初始化ContextImp時使用了一個LoadedApk對象。如註釋中所說,LoadedApk是Android 2.3引入的一個類,該類用於保存一些和APK相關的信息(如資源文件位置、JNI庫位置等)。在getSystemContext函數中初始化ContextImpl的這個LoadedApk所表明的package名爲「android」,其實就是framework-res.apk,因爲該APK僅供SystemServer使用,因此此處叫getSystemContext。
上面這些類的關係比較複雜,可經過圖6-2展現它們之間的關係。
Android運行環境是構建在進程之上的。有Android開發經驗的讀者可能會發現,在應用程序中,通常只和Android運行環境交互。基於一樣的道理,SystemServer但願它內部的那些Service也經過Android運行環境交互,所以也需爲它建立一個運行環境。因爲SystemServer的特殊性,此處調用了systemMain函數,而普通的應用進程將在主線程中調用ActivityThread的main函數來建立Android運行環境。
另外,ActivityThread雖然本意是表明進程的主線程,可是做爲一個Java類,它的實例到底由什麼線程建立,恐怕不是ActivityThread本身能作主的,因此在SystemServer中能夠發現,ActivityThread對象由其餘線程建立,而在應用進程中,ActivityThread將由主線程來建立。
· 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,其內部函數功能的實現最終都由mBase完成。這樣設計的目的是想把ContextImpl隱藏起來。
· Application從ContextWrapper派生,並實現了ComponentCallbacks2接口。Application中有一個LoadedApk類型的成員變量mLoadedApk。LoadedApk表明一個APK文件。因爲一個AndroidManifest.xml文件只能聲明一個Application標籤,因此一個Application必然會和一個LoadedApk綁定。
· Service從ContextWrapper派生,其中Service內部成員變量mApplication指向Application(在AndroidManifest.xml中,Service只能做爲Application的子標籤,因此在代碼中Service必然會和一個Application綁定)。
· ContextThemeWrapper重載了和Theme(主題)相關的兩個函數。這些和界面有關,因此Activity做爲Android系統中的UI容器,必然也會從ContextThemeWrapper派生。與Service同樣,Activity內部也經過mApplication成員變量指向Application。
對Context的分析先到這裏,
再來分析第三個關鍵函數startRunning。
[-->ActivityManagerService.java::startRunning]
//注意調用該函數時所傳遞的4個參數全爲null public final void startRunning(String pkg, Stringcls, String action, String data) { synchronized(this) { if (mStartRunning) return; //若是已經調用過該函數,則直接返回 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);//這個函數很重要,惋惜不在本次startRunning中調用 }
AMS的main函數的目的有兩個:
· 首先也是最容易想到的目的是建立AMS對象。
· 另一個目的比較隱晦,可是很是重要,那就是建立一個供SystemServer進程使用的Android運行環境。
根據目前所分析的代碼,Android運行環境將包括兩個成員:ActivityThread和ContextImpl(通常用它的基類Context)。
圖6-4展現了在這兩個類中定義的一些成員變量,經過它們可看出ActivityThread及ContextImpl的做用。
ActivityThread中有一個mLooper成員,它表明一個消息循環。這恐怕是ActivityThread被稱作「Thread」的一個直接證據。另外,mServices用於保存Service,Activities用於保存ActivityClientRecord,mAllApplications用於保存Application。關於這些變量的具體做用,之後遇到時再說。
· 對於ContextImpl,其成員變量代表它和資源、APK文件有關。
因爲framework-res.apk是一個APK文件,和其餘APK文件同樣,它應該運行在一個進程中。而AMS是專門用於進程管理和調度的,因此運行APK的進程應該在AMS中有對應的管理結構。所以AMS下一步工做就是將這個運行環境和一個進程管理結構對應起來並交由AMS統一管理。
AMS中的進程管理結構是ProcessRecord。
AMS如何與應用進程交互?例如AMS啓動一個位於其餘進程的Activity,因爲該Activity運行在另一進程中,所以AMS勢必要和該進程進行跨進程通訊。
答案天然是經過Binder進行通訊。爲此,Android提供了一個IApplicationThread接口,該接口定義了AMS和應用進程之間的交互函數,如圖6-5所示爲該接口的家族圖譜。
· ApplicationThreadNative實現了IApplicationThread接口。從該接口定義的函數可知,AMS經過它能夠和應用進程進行交互,例如,AMS啓動一個Activity的時候會調用該接口的scheduleLaunchActivity函數。
· ActivityThread經過成員變量mAppThread指向它的內部類ApplicationThread,而ApplicationThread從ApplicationThreadNative派生。
IApplicationThread的Binder服務端在應用進程中仍是在AMS中?
提示若是讀者知道Binder系統支持客戶端監聽服務端的死亡消息,那麼這個問題的答案就簡單了:服務端天然在應用進程中,由於AMS須要監聽應用進程的死亡通知。
有了IApplicationThread接口,AMS就能夠和應用進程交互了。例如,對於下面一個簡單的函數:
IOPP