(五)AMSjava
若是站在四大組件的角度來看,AMS就是Binder中的Server。android
AMS全稱是ActivityManagerService,看字面意思是管理Activity的,但其實四大組件都歸它管。估計是Android底層開發人員先寫了ActivityManagerService用來管理Activity,後來寫Service、Receiver、CP的時候發現代碼都差很少,因而就全都用ActivityManagerService,可是卻忘記更名字了——我也是猜的,純屬八卦。網絡
由此而說到了插件化,我記得16年和Lody、張勇、林光亮一塊兒吃夜宵的時候,我當時問了困惑已久的兩個問題:app
1)App的安裝過程,爲何不把apk解壓縮到本地,這樣讀取圖片就不用每次從apk包中讀取了——這個問題,咱們放到PMS那一節再詳細說。函數
2)爲何Hook永遠是在Binder Client端,也就是四大組件這邊,而不是在AMS那一側進行Hook。oop
這裏要說清楚第二個問題。就拿Android剪切板舉例吧。前面說過,這也是個Binder服務。單元測試
AMS要負責和全部App的四大組件進行通訊,也真夠他忙的。若是在一個App中,在AMS層面把剪切板功能給篡改了,那會致使Android系統全部的剪切板功能被篡改——這就是病毒了,若是是這樣的話,Android系統早就死翹翹了。因此Android系統不容許咱們這麼作。測試
咱們只能在AMS的另外一側,Client端,也就是四大組件這邊作篡改,這樣即便咱們把剪切板功能篡改了,也隻影響篡改代碼所在的App,在別的App中,剪切板功能仍是正常的。插件
關於AMS咱們就說這麼多,下面介紹四大組件時,會反覆提到四大組件和AMS的跨進程通訊。線程
(六)Activity 第1講
對於作App的開發人員而言,Activity是四大組件中用的最多的,也是最複雜的,我這裏只講Activity的啓動和通訊原理。還有一些相關的概念,好比說View、Looper、Intent、Resource,我之後另起章節來介紹。
注:我對四大組件的分析,都是基於羅昇陽的那本分析Android底層的書,我把其中羅列的大部分代碼都刪掉了,只保留那些對App開發人員有用的一些代碼片斷和一些關鍵類名,並融入了我對四大組件的理解。
1)首先要搞清,App是怎麼啓動的。
在手機屏幕上點擊某個App的Icon,假設就是鬥魚App吧,這個App的首頁(或引導頁)就出如今咱們面前了。這個看似簡單的操做,背後經歷了Activity和AMS的反反覆覆的通訊過程。
首先要搞清楚,在手機屏幕上點擊App的icon快捷圖標,此時手機屏幕就是一個Activity,而這個Activity所在的App,業界稱之爲Launcher。Launcher是手機系統廠商提供的,相似小米華爲這樣的手機,比拼的就是誰的Launcher絢麗和人性化。
Launcher這個App,其實和咱們作的各種應用類App沒有什麼不一樣,咱們你們用過華爲、小米之類的手機,預裝App以及咱們下載的各類App,都顯示在Launcher上,每一個App表現爲一個Icon。Icon多了能夠分頁,能夠分組,此外,Launcher也會發起網絡請求,調用天氣的數據,顯示在屏幕上,所謂的人性化界面。
還記得咱們在開發一款App時,在Manifest文件中是怎麼定義默認啓動Activity的麼?以下所示:
而Launcher中爲每一個App的icon提供了啓動這個App所須要的Intent信息,以下所示(好比說鬥魚的包名是):
action:android.intent.action.MAIN
category: android.intent.category.LAUNCHER
cmp: 鬥魚的包名+ 首頁Activity名
這些信息是App安裝(或Android系統啓動)的時候,PackageManagerService從鬥魚的apk包的manifest文件中讀取到的。
因此點擊icon就啓動了鬥魚App中的首頁。
2)啓動App哪有那麼簡單
前面介紹的只是App啓動的一個最簡單的概述。
仔細看,咱們會發現,Launcher和鬥魚是兩個不一樣的App,他們位於不一樣的進程中,它們之間的通訊是經過Binder完成的——這時候AMS出場了。
仍然以啓動鬥魚App爲例子,總體流程是:
至此啓動流程完成,分紅兩部分,1-3步,Launcher和AMS相互通訊,然後面幾步,鬥魚App和AMS相互通訊。
這會牽扯一堆類進來,列舉以下,在接下來的分析中,咱們都會遇到:
第1階段 Launcher通知AMS
這是我根據老羅那本書中對Activity的分析,本身手繪的UML圖,一共七張,也就是Activity啓動所經歷的七個階段。建議各位讀者也親自手繪一遍,從而就加深理解。
從上圖中咱們看到,點擊Launcher上的鬥魚App的icon快捷圖標,這時會調用Launcher的startActivitySafely方法,其實仍是會調用Activity的startActivity方法,intent中帶着要啓動鬥魚App所須要的關鍵信息,以下所示:
action = 「android.intent.action.MAIN」
category = 「android.intent.category.LAUNCHER」
cmp = 「com.douyu.activity.MainActivity」
第3行代碼是我猜的,就是鬥魚App在Mainfest文件中指定爲首頁的那個Activity。這樣,咱們終於明白,爲何在Mainfest中,給首頁指定action和category了。在app的安裝過程當中,會把這個信息「記錄」在Launcher的鬥魚啓動快捷圖標中。關於App的安裝過程,我會在後面的文章詳細介紹。
startActivity這個方法,若是咱們看它的實現,會發現它調來調去,通過一系列startActivity的重載方法,最後會走到startActivityForResult方法。
咱們知道startActivityForResult須要兩個參數,一個是intent,另外一個是code,這裏code是-1,表示Launcher纔不關心鬥魚的App是否啓動成功了呢。
第3步: startActivityForResult
Activity內部會保持一個對Instrumentation的引用,但凡是作過App單元測試的同窗,對這個類都很熟悉,稱之爲儀表盤。
在startActivityForResult方法的實現中,會調用Instrumentation的execStartActivity方法。
看到這裏,咱們發現有個mMainThread變量,這是一個ActivityThread類型的變量。
這個傢伙的來頭可不小。
ActivityThread,就是主線程,也就是UI線程,它是在App啓動時建立的,它表明了App應用程序。
啥?ActivityThread表明了App應用程序,那Application類豈不是被架空了?其實,Application對咱們App開發人員來講也許很重要,可是在Android系統中還真的沒那麼重要,他就是個上下文。Activity不是有個Context上下文嗎?Application就是整個ActivityThread的上下文。
ActivityThread則沒有那麼簡單了。它裏面有main函數。
咱們知道大部分程序都有main函數,好比java、C#,遠了不說,iPhone App用到的Objective-C,也有main函數,那麼Android的main函數藏在哪裏?就在ActivityThread中,以下所示,代碼太多,我只截取了一部分
又有人會問?不是說誰寫的程序,誰就要提供main函數,做爲入口嗎?但Android App卻不是這樣的。Android App的main函數,在ActivityThread裏面,而這個類是Android系統提供的底層類,不是咱們提供的。
因此這就是Andoid有趣的地方。Android App的入口是Mainifest中定義默認啓動Activity。這是由Android AMS與四大組件的通訊機制決定的。
最近在看吳越版的西遊記,就發現這個西天取經爲啥用了十幾年啊?由於這師徒四個取經路上愛管閒事,因此耽擱了好久。我這篇文章也是如此,常常講着講着就跑題了,再這麼寫下去,不知道要寫到啥時候,因此咱們一路向西,徑直往前走,再遇到奇怪的類,先不要理它。
在回到代碼來,這裏要傳遞2個很重要的參數:
這兩個參數是伏筆,傳遞給AMS,之後AMS想反過來通知Launcher,就能經過這兩個參數,找到Launcher。
第4步,Instrumentation的execStartActivity方法
Instrumentation絕對是Adnroid測試團隊的最愛,由於它能夠幫咱們啓動Activity。
回到咱們的App啓動過程來,在Instrumentation的execStartActivity方法中,
我理解這就是一個透傳,Activity把數據藉助Instrumentation,傳遞給ActivityManagerNative,沒太多有趣的內容,就很少講了。
第5步:AMN的getDefault方法
ActivityManagerNative,簡稱AMN。這個類後面會反覆用到。
AMN經過getDefault方法,從ServiceManager中取得一個名爲activity的對象,而後把它包裝成一個ActivityManagerProxy對象(簡稱AMP),AMP就是AMS的代理對象。
備註1:ServiceManager是一個容器類。
備註2: AMN的getDefault方法返回類型爲IActivityManager,而不是AMP。IActivityManager是一個實現了IInterface的接口,裏面定義了四大組件全部的生命週期。
AMN和AMP都實現了IActivityManager接口,AMS繼承自AMN(好亂),那麼對照着前面AIDL的UML,就不難理解了:
第6步,AMP的startActivity方法
看到這裏,你會發現AMP的startActivity方法,和AIDL的Proxy方法,是如出一轍的,寫入數據到另外一個進程,也就是AMS,而後等待AMS返回結果。
至此,第一階段的工做就作完了。
後續流程請參加下一篇文章。