1. 程式人生 > >寫給Android App開發人員看的Android底層知識(2)

寫給Android App開發人員看的Android底層知識(2)

(五)AMS

如果站在四大元件的角度來看,AMS就是Binder中的Server。

      AMS全稱是ActivityManagerService,看字面意思是管理Activity的,但其實四大元件都歸它管。估計是Android底層開發人員先寫了ActivityManagerService用來管理Activity,後來寫Service、Receiver、CP的時候發現程式碼都差不多,於是就全都用ActivityManagerService,但是卻忘記改名字了——我也是猜的,純屬八卦。

由此而說到了外掛化,我記得16年和Lody、張勇、林光亮一起吃夜宵的時候,我當時問了困惑已久的兩個問題:

1)App的安裝過程,為什麼不把apk解壓縮到本地,這樣讀取圖片就不用每次從apk包中讀取了——這個問題,我們放到PMS那一節再詳細說。

2)為什麼Hook永遠是在Binder Client端,也就是四大元件這邊,而不是在AMS那一側進行Hook。

這裡要說清楚第二個問題。就拿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. Launcher通知AMS,要啟動鬥魚App,而且指定要啟動鬥魚的哪個頁面(也就是首頁)。
  2. AMS通知Launcher,好了我知道了,沒你什麼事了,同時,把要啟動的首頁記下來。
  3. Launcher當前頁面進入Paused狀態,然後通知AMS,我睡了,你可以去找鬥魚App了。
  4. AMS檢查鬥魚App是否已經啟動了。是,則喚起鬥魚App即可。否,就要啟動一個新的程序。AMS在新程序中建立一個ActivityThread物件,啟動其中的main函式。
  5. 鬥魚App啟動後,通知AMS,說我啟動好了。
  6. AMS翻出之前在第二步存的值,告訴鬥魚App,啟動哪個頁面。
  7. 鬥魚App啟動首頁,建立Context並與首頁Activity關聯。然後呼叫首頁Activity的onCreate函式。

至此啟動流程完成,分成兩部分,1-3步,Launcher和AMS相互通訊,而後面幾步,鬥魚App和AMS相互通訊。

這會牽扯一堆類進來,列舉如下,在接下來的分析中,我們都會遇到:

  •    Instrumentation
  •    ActivityThread
  •    H
  •    LoadedApk
  •    AMS
  •    ActivityManagerNative和ActivityManagerProxy
  •    ApplicationThread和ApplicationThreadProxy

第1階段 Launcher通知AMS

這是我根據老羅那本書中對Activity的分析,自己手繪的UML圖,一共七張,也就是Activity啟動所經歷的七個階段。建議各位讀者也親自手繪一遍,從而就加深理解。

  •    第1步、第2步

      從上圖中我們看到,點選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個很重要的引數:

  •    通過ActivityThread的getApplicationThread方法取到一個Binder物件,它的型別為ApplicationThread,它代表著Launcher所在的App程序。
  •    mToken,這也是個Binder物件,它代表了Launcher這個Activity,這裡也通過Instrumentation傳給AMS,AMS一查電話簿,就知道是誰向AMS發起請求了。

      這兩個引數是伏筆,傳遞給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返回結果。

至此,第一階段的工作就做完了。

後續流程請參加下一篇文章。

相關推薦

Android App開發人員Android底層知識1

這個系列的文章一共8篇,我醞釀了很多年,參考了很多資源,查看了很多原始碼,直到今天把它寫出來,也是戰戰兢兢,生怕什麼地方寫錯了,貽笑大方 (一)引言 早在我還是Android菜鳥的時候,有很多技術我都不太明白,也都找不到答案,比如apk是怎麼安裝的,比如資源是怎

Android App開發人員Android底層知識8

(十)PMS及App安裝過程        PMS,全稱PackageManagerService,是用來獲取Apk包的資訊的。        在前面分析四大元件與AMS通訊的時候,我們介紹過,AMS總是會使用PMS載入包的資訊,將其封裝在LoadedApk這個類物件

Android App開發人員Android底層知識7

(十二)ContentProvider (1)ContentProvider是什麼? ContentProvider,簡稱CP。 做App開發的同學,尤其是電商類App,對CP並不熟悉,對這個概念的最大程度的瞭解,也僅僅是建立在書本上,它是Android四大元件中的一個。 做系統管理類的App,比

Android App開發人員Android底層知識5

     (十)Service      Service有兩套流程,一套是啟動流程,另一套是繫結流程。我們做App開發的同學都應該知道。            1)在新程序啟動Service        我們先看Service啟動過程,假設要啟動的Service是在一個新的程序中,分為5個階段:

Android App開發人員Android底層知識4

(八)App內部的頁面跳轉       在介紹完App的啟動流程後,我們發現,其實就是啟動一個App的首頁。       接下來我們看App內部頁面的跳轉。       從ActivityA跳轉到ActivityB,其實可以把ActivityA看作是Launcher,那麼這個跳轉過程,和Ap

Android App開發人員Android底層知識3

       (七)App啟動流程第2篇        書接上文,App啟動一共有七個階段,上篇文章篇幅所限,我們只看了第一階段,接下來講剩餘的六個階段,仍然是拿鬥魚App舉例子。        簡單回顧一下第一階段的流程,就是Launcher向AMS傳送一個跨程序通訊,通過AMN/AMP,告訴A

Android App開發人員Android底層知識2

(五)AMS 如果站在四大元件的角度來看,AMS就是Binder中的Server。       AMS全稱是ActivityManagerService,看字面意思是管理Activity的,但其實四大元件都歸它管。估計是Android底層開發人員先寫了ActivityManagerService用來管理A

Android App開發人員Android底層知識6

(十一)BroadcastReceiver BroadcastReceiver,也就是廣播,簡稱Receiver。      很多App開發人員表示,從來沒用過Receiver。其實吧,對於音樂播放類App,用Service和Receiver還是蠻多的,如果你用過QQ音樂,App退到後臺,音樂照樣播放

初次接觸Android APP開發之安裝Android studio軟體出現的問題以及解決方案錯誤史,一把辛酸淚

     序言     筆者由於心血來潮,想玩玩Android開發。本想著用eclipes開發Android APP。但是發現網上說eclipes不是最好的選擇,所以筆者就放棄了熟悉的eclipes來開發Android APP,改用Android studio。在此之前,筆

Android應用開發:網絡工具——Volley

respond sid 開發 多少 called creat miss 相等 eal 引言 在Android應用開發:網絡工具——Volley(一)中結合Cloudant服務介紹了Volley的一般使用方法,當中包括了兩種請求類型StringRequest和JsonOb

Android應用開發:網絡工具——Volley

要求 com 庫文件 urn welcom 順序 之前 air tin 引言 網絡一直是我個人的盲點,前一陣子抽空學習了一下Volley網絡工具的用法,也透過源代碼進行了進一步的學習,有一些心得想分享出來。在Android開發中,成熟的網絡工具不少,And

Android安全/開發基礎--8--Java本地介面JNI

8-1、JNI概述 JNI的本意是Java Native Interface(Java本地介面),是為了方便Java和C/C++等原生代碼所封裝的一層介面,使用JNI技術可以對Java層遮蔽不同作業系統平臺之間的差異,從而實現Java本身的平臺無關特性。JNI和

Android應用開發以及設計思想深度剖析1

本文內容,主題是透過應用程式來分析Android系統的設計原理與構架。我們先會簡單介紹一下Android裡的應用程式程式設計,然後以這些應用程 序在執行環境上的需求來分析出,為什麼我們的Android系統需要今天這樣的設計方案,這樣的設計會有怎樣的意義, Android究竟

一個android專案開發遇到的各種小問題

1、map格式字串如何解析? 藉助json,先將字串轉化為json格式,再取值 JSONObject object = new JSONObject(posMap); clientIden = object.getString("iden"); ---------

Android 消息處理源代碼分析2

urn msg illegal r.java roi fin 報錯 mes pri Android 消息處理源代碼分析(1)點擊打開鏈接 繼續接著分析剩下的類文件 Looper.java public final class Looper {

Android進階3:Activity原始碼分析2 —— Activity啟動和銷燬流程8.0

上篇文章講述了app從啟動建立Activity呼叫onCreate,onStart, onResume方法,這篇文章講述一下Activity啟動的另一個切入點:startActivity方法,啟動Activity。 通過上一篇文章,我們總結一下: 1:A

Android學習之listView顯示下拉列表2SimpleAdapter介面卡

                     ListView顯示下拉列表(2)(SimpleAdapter介面卡) 上一篇文章我大概介紹了listView的主要功能以及用ArrayAdapter陣列介面卡實現純文字的下拉列表。但是在現實生活中,純文字的使用率不是很高,更多的

【安卓-自定義佈局】安卓App開發思路 一步一個腳印實現內嵌在app中的webview 騰訊開源X5 高效安全

實現內嵌在app中的webview 採用騰訊開源X5 高效安全 webview在app的使用中,十分頻繁,原生的webview載入速度相對來說很慢,而且很費流量。騰訊開源了x5的webview

Android中聯絡人和通話記錄詳解2

  在文章Android中聯絡人和通話記錄詳解(1)中對通話記錄進行了分析,本章將對聯絡人的資料庫表、欄位以及Insert,Query,Delelte,Update四大基本資料操作進行分析。   與聯

Android音視訊學習——Camera2官方demo解析2

本篇主要就幾個關鍵的類進行解釋,並且對需要注意的點註釋,此外再總結一下如何使用Camera2進行拍照和預覽的流程。附上官方demo。 上面是Camera2的流程示意圖,由於我喜歡從整體思路上分析程式碼,所以下面先就整個呆萌的思路拓展一下。 首先肯