Android之ActivityManagerService淺談

Android之ActivityManagerService淺談

一、在本文中需要提前了解的知識:?

1)AMS —— ActivityManagerService:android系統服務,Activity管理的服務端,用于管理activity的各種行為,控制activity的生命周期,派發消息事件,低內存管理等等。實現了IBinder接口,可以用于進程間通信。?

2)ApplicationThread:該類實現了IBinder接口,activity整個框架中客戶端和服務端(AMS)通信的接口。同時也是類ActivityThread的內部類。這樣就有效地把Ams和ActivityThread綁在了一起。?

3)ActivityThread:如第2點所述,ApplicationThread所綁定的客戶端就是ActivityThread,ActivityThread這個類在Activity客戶端非常重要。?

(1)它是應用程序的入口,眾所周知,java程序的入口為main()方法,同樣,當AMS拉起一個新的進程,同時啟動一個主線程的時候,主線程就從ActivityThread.main方法開始執行,它會初始化一些對象,然后自己進入消息等待隊列, 也就是Looper.loop();一旦進入loop()方法,線程就進入了死循環,再也不會退出;一直在等待別人給他消息,然后執行這個消息。這也是edt(事件驅動模型)的原理。?

(2)它是Activity客戶端的管理類,由它來決定什么時候調用onCreate(),什么時候調用onResume()方法。當Activity發起一個請求時,比如startActivity()或者finish()的時候,它會來處理這個請求,然后調用其它的人來具體做事。?

4)Instrumentation:這個類在Activity啟動時以及廣播注冊時都會調用,除了跟android的測試有關之外,還是activity管理中實際做事情的人。比如startActivity(),在某種情況下,就是調用這個類,然后調用到AMS,但是有的時候是通過ApplicationThread去訪問AMS的。?

問題:既然ApplicationThread可以訪問AMS,那么我們應用程序是不是可以調用ApplicationThread類來訪問AMS,直接啟動Activity呢??

->答案是不可以的。因為ApplicationThread是ActivityThead的私有內部類,外界無法訪問。而ActivityThread是hide的,所以我們應用程序不能通過sdk去訪問ActivityThread類。同理,拿到Ams引用的接口是ActivityManagerNative類,而這個類也是hide的。所以應用程序也不能直接操作AMS。

5)?Activity:這個類大家就再熟悉不過了,android最重要的組件之一,其實從java角度看,它一點也不特殊,它就是一個java對象,它會被創建,同時也會被垃圾回收機制銷毀,只不過它受AMS管理,所以它才有它的生命周期。?

6)ActivityResult: Activity管理服務端中,Activity的記錄緩存。換句話說,就是客戶端啟動一個activity, AMS會對它進行緩存,類型就是ActivityResult。?

問題:為什么不直接緩存Activity類型的值,而要新定義一個ActivityResult類型呢??

->答案是:因為Activity類沒有實現IBinder接口,不能用于進程之間通信。而這個緩存值是AMS和客戶端通信用的。所以必須實現IBinder接口。而且Activity設計的時候,也沒有打算讓它用于進程通信,看它的成員變量就可以知道,里面有很多的龐大對象,如list, map等等。這些對象是不適合跨進程傳輸的。因為java里面跨進程調用就是序列化和反序列化,那些龐大對象在序列化和反序列化的時候,會消耗大量的時間和資源。另外,根據設計法則,一個類的作用盡可能的單一,不要出現那種萬能類。

二、AMS是什么??

全名是ActivityManagerService, 顧名思義,就是Activity管理機制的服務器端,屬于一個系統服務,位置systemProcess進程中。?

可以從多個角度來看ams:?

(1) 從java的角度來看,ams就是一個java對象,實現了IBinder接口,所以它是一個用于進程間通信的接口。這個對象初始化是在SystemServer.java的run()方法里面。?

context = ActivityManagerService.main(factoryTest);?

這是一段很普通的java靜態工廠代碼,我們在這里創建我們的AMS對象。

初始化方法

public static final Context main(int factoryTest) {

AThread thr = new AThread();

? ? ? ? thr.start();? //啟動一個線程去初始化Ams對象? ? ? ? synchronized (thr) {

? ? ? ? ? ? while (thr.mService == null) {

? ? ? ? ? ? ? ? try {

? ? ? ? ? ? ? ? ? ? thr.wait(); //等待AThread初始化Ams完成? ? ? ? ? ? ? ??

? ? ? ? ? ? ? ? } catch (InterruptedException e) {

? ? ? ? ? ? ? ? }

? ? ? ? ? ? }

}

//…? ? ? ??

?//…..

}

AThread的run()方法public void run() {

Looper.prepare();

android.os.Process.setThreadPriority(? ? ? ? ? ? ? ? android.os.Process.THREAD_PRIORITY_FOREGROUND);? ? ? ? ? android.os.Process.setCanSelfBackground(false);

ActivityManagerService m = new ActivityManagerService();? //初始化Ams對象 ? ?

synchronized (this) {

? ? ? ? mService = m;

? ? ? ? notifyAll();? //初始化完成 ,notify main方法的wait()方法,告訴它已經完成,可以往下面走了。? ? ?

?}

? ? //…… ? ?

Looper.loop();? //自己進入消息循環等待狀態}

問題:?

這里是另外啟動了一個線程AThread去創建AMS對象,然后用wait/notify機制來實現線程之間的同步。?

a. 創建一個對象完全不必要另外開啟個線程來處理,直接new出來不就可以了。有畫蛇添足的感覺??

b. AThread在創建了Ams對象之后,進入消息循環狀態而不是直接退出。但是看代碼沒有發現有向這個線程的handler發送消息的地方,也就是說AThread線程的狀態接下來會永遠阻塞。不明白這樣做有什么意義??

答案:?

它是AThread的run方法里面new ActivityManagerService(), 而ActivityManagerService里面有個變量mHandler,這樣的話mHandler綁定的線程就是AThread這個線程了。通過向mHandler發消息,AThread就不停地從消息隊列獲取消息,處理消息。?

(2)AMS是一個服務?

ActivityManagerService從名字就可以看出,它是一個服務,用來管理Activity,而且是一個系統服務,就像包管理服務,電池管理,震動管理服務一樣。?

(3)AMS是一個Binder?

Ams實現了IBinder接口,所以它是一個Binder,這意味著它不但可以用于進程間通信,還是一個線程。因為一個Binder就是一個線程。?

這個怎么理解呢?可以這么理解,如果我們啟動一個Hello World安卓應用程序,里面不另外啟動其他線程,那我覺得,這個進程里面我們最起碼啟動了4個線程:?

a. Main線程:這是程序的主線程,也是我們日常編寫代碼時用到最多的那個線程。比如我們重寫了Activity的onCreate()方法,一般就是這個main線程來執行代碼,也叫ui線程。這是因為安卓的組件(包括TextView, Button等等這些ui控件)都是非線程安全的,所以只允許main線程來操作。?

b. GC線程:我們都知道,java有垃圾回收機制,每個java程序(一個java虛擬機)都有一個垃圾回收線程,專門回收不再使用的對象。?

c. Binder1 就是我們的ApplicationThread,這個類實現了IBinder接口,用于進程間通信。具體來說,是我們的應用程序和Ams通信的工具。?

d. Binder2 就是我們的ViewRoot.W對象,它也是實現了IBinder接口,是用于我們的應用程序和Wms通信的工具。?

Ps: WMS就是WindowManagerServier,和AMS差不多的概念,不過它是管理窗口的系統服務。

(4)AMS是一個單獨的線程?

a. 首先系統服務不可能運行在systemProcess進程的主線程中。因為這么多系統服務如果都是運行在主線程中的話,肯定會發生阻塞。比如這個線程正在管理Activity,然后手機來電震動,那就沒人來處理震動管理。所以一般服務都是運行在單獨的線程里面(有些服務例外)?

b. Ams實現了IBinder接口,所以它就是一個單獨的線程了,就是這個線程來處理Ams對Activity的管理。?

問題:?如果AMS只有一個線程來執行Activity管理的話,會不會發生阻塞。比如兩個客戶端同時發起請求。?

答案:應該不會,因為手機操作系統是單界面的操作系統,就是說,在同一個時刻,只有一個Activity能展示在用戶面前(TabActivity看起來同時展示了多個Activity,但安卓做了特殊的處理,暫不討論),不像windows是多任務多窗口的操作系統。單窗口的話,那么發送的onPause(),onResume()之類的請求時,在同一時刻,應該只有一個人發起。

三、AMS管理Activity流程?

(1) 以Activity.startActivityForResult()為例說明,一般我們見的最多的是調用Activity.startActivity()方法。不過startActivity()的內部實現也是調用startActivityForResult()方法,只不過requestCode=-1?

(2)Activity.startActivity():?

Activity啟動一個Activity 是異步的。換句話說,Activity不必等待ams結果的返回,直接往下面執行。當把接下來的代碼執行完畢后,它就進入消息循環等待隊列,繼續等待別人給他消息。否則就一直阻塞。不過ams很快就會給它發送一個暫停當前activity的消息。就是下面的調用流程:

Instrumentation. execStartActivity ();

Ams.startActivity();? ? ?

ActivityStack. startActivityMayWait ();

調用ActivityThread的暫停方法時候,同時向自己發送一個暫停消息,延遲500ms執行,如果500ms之后沒有remove掉這個消息,就會說暫停出現異常。?

這里要說明的是,AMS發送暫停消息給ActivityThread之后,就直接往下面走了。所以這是一個異步調用,非阻塞。發送消息后,再等待ActivityThread把暫停完畢的消息返回給自己。?

(3) ActivityThread. schedulePauseActivity () 暫停完畢調用ActivityManagerNative.getDefault().activityPaused(token, state),?

告訴AMS自己已經暫停完畢。在AMS.activityPaused()方法內會移除掉上面那個500ms的消息,然后調用新activity的onResume之類的方法。?

(4)startActivityForResult()方法啟動一個Activity,目標Acitivty結束后,會調用到onActivityResult()方法。?

這個流程也是類似的,以Activity.finish()方法是入口,AMS在接到finishActivity()之后,就會輾轉調用到Activity.onActivityResult()方法。

四、關系圖?

應用程序進程?

這里的意思是ActivityThread通過AppliactionThread這個Binder來和AMS通信。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容