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

軟件 文章 Java 通信 創未來 2017-05-22

這個系列的文章一共8篇,我醞釀了很多年,參考了很多資源,查看了很多源碼,直到今天把它寫出來,也是戰戰兢兢,生怕什麼地方寫錯了,貽笑大方。

(一)引言

早在我還是Android菜鳥的時候,有很多技術我都不太明白,也都找不到答案,比如apk是怎麼安裝的,比如資源是怎麼加載的。

再比如說,每本書都會講AIDL,但我卻從來沒用過。四大組件也是這個問題,我只用過Activity,其它三個組件,不但沒用過,甚至連它們是做什麼的,都不是很清楚。

之所以這樣,是因為我一直從事的是電商類App開發工作,對於這類App,基本就是由列表頁和詳情頁組成的,所以我們每天面對的是Activity,會寫這兩類頁面,把網絡底層封裝的足夠強大就夠了。

絕大多數App開發人員,都是如此。

但直到接觸Android的插件化編程和熱修復技術,才發現只掌握上述這些技術是遠遠不夠的。

(二)還是引言

市場上有很多介紹Android底層的書籍,網上也有很多文章,但大都是給ROM開發人員看的,動輒貼出幾頁代碼,不適合App開發人員去閱讀學習。

我曾經在微信中問過老羅和老鄧,你們寫的書為什麼我們App開發人員看不懂啊,他們就呵呵了,跟我說,他們的書就是寫給ROM開發人員看的。

於是,這幾年來,我一直在尋找這樣一類知識,App開發人員看了能有助於他們更好的編寫App程序,而又不需要知道太多這門技術底層的代碼實現。

這類知識分為兩種。

一種是知道概念即可,就比如說Zygote,其實App開發人員是不需要了解Zygote的,知道有這麼個東西是“孕育天地”的就夠了,類似的還有SurfaceFlinger、WMS這些概念。

還有一種是需要知道內部原理,就比如說Binder。關於Binder的介紹鋪天蓋地,但對於我們App開發人員,需要了解的是它的架構模型,只要有Client和Server,以及SM就足夠了。

四大組件的底層通信機制都是基於Binder的,我們需要知道每個組件中,分別是哪些類扮演了Binder Client,哪些類扮演了Binder Server。知道這些概念,有助於我們App開發人員進行插件化編程。

(三)目錄

我這個系列的文章,已經寫好了下面的內容,會在接下來的每天發佈一篇,共計8篇,看了這8篇文章,就可以邁進Android插件化的大門了。

  • Binder
  • AIDL
  • AMS
  • Activity
  • Service
  • ContentProvider
  • 匿名共享內存
  • BroadcastReceiver
  • PMS及App安裝過程

Android底層知識,還應該包括以下內容,但是和插件化關係不大,也不是我擅長的領域,所以我只列出了大綱,沒有繼續寫下去:

  • View和ViewGroup
  • Message、Looper和Handler
  • 權限管理
  • Android SDK工具內部原理

有興趣的同學,可以按照我這個思路繼續寫下去,記得,一,少貼代碼。多畫圖,二,一定要有趣。

接下來就詳細講那些App開發人員需要知道的Android底層知識。

(三)Binder

Binder是為了解決跨進程通信。

關於Binder的文章實在是太多了,每篇文章都能從Java層講到C++層,App開發人員其實是沒必要了解這麼多內容的。我們看對App開發有用的幾個點:

1)首先,Binder分為Client和Server兩個進程。

注意,Client和Server是相對的。誰發消息,誰就是Client,誰接收消息,誰就是Server。

舉個例子,兩個進程A和B之間使用Binder通信,進程A發消息給進程B,那麼這時候A是Binder Client,B是Binder Server;進程B發消息給進程A,那麼這時候B是Binder Client,A是Binder Server——其實這麼說雖然簡單了,但還是不太嚴謹,我們先這麼理解著。

2)其次,我們看下面這個圖(摘自田維術的博客),基本說明白了Binder的組成解構:

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

圖中的IPC就是進程間通信的意思。

圖中的ServiceManager,負責把Binder Server註冊到一個容器中。

有人把ServiceManager比喻成電話局,存儲著每個住宅的座機電話,還是很恰當的。張三給李四打電話,撥打電話號碼,會先轉接到電話局,電話局的接線員查到這個電話號碼的地址,因為李四的電話號碼之前在電話局註冊過,所以就能撥通;沒註冊,就會提示該號碼不存在。

對照著Android Binder機制,對著上面這圖,張三就是Binder Client,李四就是Binder Server,電話局就是ServiceManager,電話局的接線員在這個過程中做了很多事情,對應著圖中的Binder驅動

3)接下來我們看Binder通信的過程,還是摘自田維術博客的一張圖:

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

注:圖中的SM也就是ServiceManager。

我們看到,Client想要直接調用Server的add方法,是不可以的,因為它們在不同的進程中,這時候就需要Binder來幫忙了。

  1. 首先是Server在SM這個容器中註冊。
  2. 其次,Client想要調用Server的add方法,就需要先獲取Server對象, 但是SM不會把真正的Server對象返回給Client,而是把Server的一個代理對象返回給Client,也就是Proxy。
  3. 然後,Client調用Proxy的add方法,SM會幫他去調用Server的add方法,並把結果返回給Client。

以上這3步,Binder驅動出了很多力,但我們不需要知道Binder驅動的底層實現,涉及到C++的代碼了——把有限的時間去做更有意義的事情。

App開發人員對Binder的掌握,這些內容就足夠了。

是時候總結一波了:

  1. 學習Binder,是為了更好的理解AIDL,基於AIDL模型,進而瞭解四大組件的原理。
  2. 理解了Binder,再看AMS和四大組件的關係,就像是Binder的兩個進程Server和Client通信。

(四)AIDL

AIDL是Binder的延伸。一定要先看懂我前面介紹的Binder,再來看AIDL。要按順序閱讀。

Android系統中很多系統服務都是aidl,比如說剪切板。舉這個例子,是為了讓App開發人員知道AIDL無處不在,和我們距離非常近。

AIDL中需要知道下面幾個類:

  • IBinder
  • IInterface
  • Binder
  • Proxy
  • Stub

當我們自定義一個aidl文件時(比如MyAidl.aidl,裡面有一個sum方法),Android Studio會幫我們生成一個類文件MyAidl.java,如下圖所示:

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

MyAidl.java這個生成文件中,包括MyAidl接口,以及Stub和Proxy兩個實現了MyAidl接口的類,其中Stub是定義在MyAidl接口中的,而Proxy則定義在Stub類中。

我曾經很不理解,為什麼不是生成3個文件,一個接口,兩個類,清晰明瞭。都放在一個文件中,這是導致很多人看不懂AIDL的一個門檻。其實Android這麼設計是有道理的。當有多個AIDL類的時候,Stub和Proxy類就會重名,把它們放在各自的AIDL接口中,就必須MyAidl.Stub這樣去使用,就區分開了。

對照這張圖,我們繼續來分析,Stub的sum方法是怎麼調用到Proxy的sum方法?然後又調用另一個進程的sum方法的?

起決定意義的是Stub的asInterface方法和onTransact方法。其實這個圖沒有畫全,把完整的Binder Server也畫上,就應該是這樣:

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

1)先從Client看起,對於AIDL的使用者,我們這麼寫程序:

MyAidl.Stub.asInterface(某IBinder對象).sum(1, 2); //最好在執行sum方法前判空。

asInterface方法的作用是判斷參數——也就是IBinder對象,和自己是否在同一個進程:

  • 是,則直接轉換、直接使用,接下來就跟Binder跨進程通信無關啦;
  • 否,則把這個IBinder參數包裝成一個Proxy對象,這時調用Stub的sum方法,間接調用Proxy的sum方法。

return new MyAidl.Stub.Proxy(obj);

2)Proxy在自己的sum方法中,會使用Parcelable來準備數據,把函數名稱、函數參數都寫入_data,讓_reply接收函數返回值。最後使用IBinder的transact方法,把數據就傳給Binder的Server端了。

mRemote.transact(Stub.TRANSACTION_addBook, _data, _reply, 0); //這裡的mRemote就是asInterface方法傳過來的obj參數

———————我是Binder分界線—————-

3)Server則是通過onTransact方法接收Client進程傳過來的數據,包括函數名稱、函數參數,找到對應的函數,這裡是sum,把參數喂進去,得到結果,返回。

所以onTransact函數經歷了讀數據-->執行要調用的函數-->把執行結果再寫數據的過程。

下一篇文章要介紹的四大組件的原理,我們都可以對照著AIDL的這張圖來看,比如說,四大組件的啟動和後續流程,都是在和ActivityManagerService(簡稱AMS)來來回回的通信,四大組件給AMS發消息,四大組件就是Binder Client,而AMS就是Binder Server;AMS發消息通知四大組件,那麼角色就互換。

那麼四大組件中,比如說Activity,又是哪個類扮演了Stub的角色,哪個類扮演了Proxy的角色呢?這也是我下一篇文章要介紹的,包括AMS、四大組件各自的運行原理。

好戲即將開始。

相關推薦

推薦中...