android 架構及運行機制

android 架構及運行機制

導讀:對於Android開發者來說,成系列的技術文章對他們的技術成長幫助最大。如下是我們向您強烈推薦的主題爲Android開發的第一個系列文章。
《Android核心分析》整理如下:
1. 方法論探討之設計意圖
爲什麼要研究Android,是因爲它夠龐大,它夠複雜,他激起了我作爲一個程序員的內心的渴望,渴望理解這種複雜性。我研究的對象是作爲手機開發平臺的Android軟件系統部分,而不是Dalvik虛擬機本身。

作爲一個從其他平臺裝接過來的程序員,要從事Andoid平臺系統開發,我的關於手機平臺上積累的知識已經不能滿足需要了,Android爲我們帶來了大量的新名詞,Activity,Manifest,INTENT,Service,Binder,Dalvik虛擬機,Framework,Linux,Navtive ,JNI.....。通過在源代碼,在開發社區,在開發博客,甚至在招聘過程中,我不斷的尋求Android是什麼。經過一定時間的沉澱,我慢慢的理解到Android不僅僅是一類手機的總稱,不僅僅是一個手機開發平臺,不僅僅是一個虛擬java操作系統,不僅僅是一個開發社區,一個開發標準,不僅僅是一堆代碼,Android已經成了一個新的潮流。

代碼多,系統複雜,縱觀社區中Android的研究者,一開始從源代碼分析Android就走向迷途,不斷的跋山涉水,向縱深衝刺,最終腦袋堆棧不夠用,迷失在開始的旅程,或者掛在半途中,鮮有通達者。我感覺到大部分的研究者總是忘記站在高山上向下望一望設計者的意圖,一味的隨着代碼的控制流走入繁雜的謎團,陷入到複雜性的深淵。

我的研究分析是從設計者的意圖出發,從抽象的甚至從哲學的高度,從最簡單的系統原型開始,從設計猜想開始,而不是一開始就從代碼分析展開。首先理解Android大的運行框架,主幹流程,系統原型,之後再用源代碼分析充實之。當然我這裏的設計者意圖並不是真正的Android設計者意圖,而是我以爲的Android設計者意圖。

要理解設計者意圖,就需要抽象。我們需要在哲學意義空間中去考慮系統的描述,即系統在本質上要表達什麼。在邏輯空間上去考慮系統基本構成和動態結構。從現實到虛擬對象的映射去理解系統對象的組成,在從數據流的角度分析數據的產生者和消費者之間作用關係,從控制流的角度去分析對象之間的交互關係,從函數調用去分析具體的層次關係。

在系統設計上,原型是最能表達哲學空間和邏輯空間中系統本質的東西,原型是事物本質的第一層體現。我以爲任何複雜的系統都一個簡潔的系統原型,都有它簡潔的意義。系統原型是設計者意圖的第一體現,所以我們需要從幾個方向上去提煉系統原型:
(1)從系統本質和基本原理出發
(2)從分析系統數據流和控制流分析出發。
從設計者意圖出發,得出系統原型,提取到大的邏輯結構和系統構成是第一步。之後我們可以從設計者的角度考慮系統猜想系統設計,爲什麼要這樣設計,爲什麼要有這些構成。這樣的基本原型是什麼?系統的限制是什麼,應用場景有哪些,有些設計的引進還是系統收斂性而爲之呢。我們還可以從代碼痕跡上去分析,這些概念是如何的得來的?從一定的抽象和高度去理解這些問題,遵循系統原型出發之原則,在深入分析代碼的時候,就不容易陷入細節中。我們就可以隨時跳出來想,這些代碼在整體上載表達一個什麼概念,在描繪一個什麼邏輯,他要構成一個虛擬層嗎?他是在管理這個硬件嗎?他在 虛擬這個對象嗎?他在構建管理機構?還是在構建一個對象管理?空間管理,爲了快速引入了什麼樣的複雜算法,實際上的原型算法應該是什麼樣的?

只有深入到這個抽象層次,我們才能很好的把握住系統的每一條線,每一個對象的意義。只用從原型出發,我們才能把握住這個系統的實質所在,在幹什麼?他要表達什麼?設計者爲什麼要這樣想?最終極的想法是什麼?這樣,代碼分析就變得簡單明瞭,讀代碼就變成了是在印證猜想,修正方向。

2. 方法論探討之概念空間篇
我們潛意識就不想用計算機的方式來思考問題,我們有自己的思維描述方式,越是接近我們思維描述方式,我們越容易接受和使用。各種計算機語言,建模工具,不外乎就是建立一個更接近人的思維方式的概念空間,再使用工具從該概念空間向另外一個概念空間映射,我稱之爲人性思維空間向01序列描述空間的一個映射。實現方面來看,系統就是一個翻譯器,將機器性更加人性化的一種機制。大學計算機經典課“計算機體系結構”,其他的可以忘記,但是下面這個圖不能忘記:

這個就是概念空間最本質的原型體現:作爲觀測者看到了什麼?設計者給了觀察者什麼?給出的答案是外部特性。
(1)提供給觀察者的概念空間是什麼?
(2)內部特性的概念空間是什麼?
概念空間所表達的東西帶有兩個方面的纏繞:一面是人性自由,一面是物性制約(實時響應,系統資源的限制)。所以程序實現的概念空間是人性自由與特定計算機系統物性之間有一個折中,並且根據實際系統而採取某種動態的平衡。而這種平衡將會影響到系統架構,以及設計的思想。特別在手機這樣的嵌入式系統中,這種矛盾和平衡無處不在,這種折中無處不在。而對系統的選取和採用,也就接受了某個方面的折中或某中即在的,也許是看不見的標準,及這樣的標準有隱式和顯式的。正因爲如此,不管是工具的產生,新的平臺的產生, 都是計算機的物性向人性靠近的一個小臺階。一個新的思想的形成隨即帶來的新工具,新系統框架,新的體系結構。

如果設計者站的高度足夠高,那麼設計者一開始就會考慮到“我該給他們一個什麼樣的概念空間,甚至一個什麼樣的理念,讓他們這個概念空間去建立自己的產品”,於是設計者就會開始主動的去建立概念空間,這個概念空間要表達的實際意義,概念空間應該有哪些內容構成,考慮概念空間的完備性和封閉性,考慮概念空間的邊界,考慮從哪個基礎上建立這個概念空間,考慮如何與概念空間外的實體進行交互,考慮系統的資源限制條件,考慮功能性構建的合理性,考慮機器系統與人的平衡問題。

我們在學習新系統時,首先映入眼簾的就是新概念。新名詞,就如現在我們面臨的Android大量的新名詞,在程序員的世界都是從代碼實踐開始的,是從寫應用開始去涉及。SDK給了我們一個概念,我們就在這個概念框架下,使用SDK給我提供的函數接口,數據結構,初始化過程等,我們最初的接觸到原型就是“HelloWorld”之類的DEMO程序,我們在Hello world上去使用各種不同的接口函數,對於應用程序員來講,他說看到的系統就是系統調用接口,及其編程開發流程。實際上只要一使用這些接口,就不得不接受一系列的概念,只有在這種概念系統下,我們才能工作。但是,實際上我們卻忽略了這樣的概念系統的理解,只是在編程接口的這個狹窄的空間去理解系統.我們理解系統在形成理解概念的空間只是微小的一角,很少有資料來介紹這種概念系統的形成和理解,編程接口只是這個概念空間一個,對外部的一個表徵。我們可以抽象起來,以接口,協議和行爲,來描述系統的情況。SDK API的實質向上層提供了一個語義接口,從而在層間實現了一個轉義過程,同時又成爲一個功能的集合體。但是我們很少這樣跳出來看,我們到底是處於一種什麼樣的概念空間,SDK除了調用接口外,還給了我們怎樣一種整體概念?目標系統的基本構架在本質上的東西就是一個概念系統到另一個概念系統的映射。讓我們大腦理解的概念系統映射到計算機能實現的概念域的一個映射。我們假定這個概念域E,機器能夠理解的概念域爲M,我們的軟件工程要做的事情實質就是:EàM領域的一個映射過程。

爲什麼要在宏觀上把握這些概念呢,顯然有我的目的,理解概念空間是理解設計者意圖的一個重要途徑。設計者要想給開發者提供什麼,設計者想要提供給最終用戶什麼。我們需要站在高處看待系統明白設計者意圖。

Android的實質還是一套管理手機硬件系統的軟件,這個話講起來沒有多大意義,計算機操作系統本質都是如此,Android是Google雲計算計劃的一部分,我們修正成:Android建立的本質就是讓計算機成爲我的雲接入移動智能終端。作爲硬件管理軟件,Android提供概念空間內涵實質上泛操作系統內涵,我們的理解可以從泛操作系統概念空間映射到Android系統中去。而作爲雲計算的一部分的內容,我們可以雲計算的概念入手去研究Andoird。

3. 手機之硬件形態
本節可能與Android無關,但是Android系統現在這個階段更多的是移動終端形態的開發平臺,本節給出了Android背後的工作-Android管理的硬件是什麼,Android的本質就是要管理好這些硬件部分,爲用戶提供一個體驗更好,速度更快的智能移動終端。對手機硬件形態的認識是要讓我們對手機硬件組成有個感性的認識,讓程序員知道系統中的代碼是管理那一部分的,即我們堆磚頭的目的是什麼,讓思維有一個伸展。

爲了對手機這類嵌入式系統有一個較爲深入的瞭解,我製作瞭如下的手機硬件結構思維導圖,在這張圖上我們可以看到組成手機硬件的有哪些,初步瞭解到手機管理平臺爲什麼要那麼多的管理框架和層次,從最底層理解Android設計者的設計意圖,這個思維導圖其實只是示意圖。


我們知道手機這種嵌入式系統,硬件架構最簡單描述的描述爲: 
應用處理器+Modem+射頻
對於應用處理器而言,對設計者最爲本質的描述爲輸入輸出,而對於移動終端設備電源管理,連接機制,多媒體又是很重要的考慮環節,而這些環節都會在軟件平臺上有所體現。

4. 手機的軟件形態
上節我給出了手機的硬件樹,本節將給出手機軟件形態樹。主要突出手機軟件涵蓋的內容。通過該思維導圖,我們可以看到手機軟件所涉及到的方方面面,Android所涉及到的內容也不會超過下面所示太多,這個也是Andoid系統外特性空間所要展示的,這個也是Android設計者需要考慮管理的大部分內容,通過下面的整理,我們可以讓我們的思維更加貼近Android設計意圖,從而更深入的瞭解Android中各種組成的由來,這個就是前面講到的分析思想之一從退到源頭出發,從思考最終極的問題開始。

5. Android基本空間劃分
Google給了我們一張系統架構圖,在這張圖上我們可以看到Android的大體框架組成。

從上圖可以看到:Android Applications,Application Framework,Dalvik Virtual Machine,Linux。如果將Android泛化,我們可以將系統劃分成兩部分:

但是爲了研究的方便我們先看最爲本質的三層,上面是Android,中間叫Dalvik虛擬機,下面叫Linux。

雖然上兩層都包含在Android中,但是爲了理解的方便或者從實用主義出發,我還是將虛擬機這次給分開出來,因爲我研究的對象是Android的手機系統相關部分,對於虛擬機我們不做太深入的研究。

e: pre;"> 從上面我們可以看到這個系統靜態的劃分成這樣的三層。但是從動態運行邏輯上不是這樣劃分的,所以空間的劃分是一個有趣的概念。我們從操作系統的角度看,Android就是一堆Linux應用的集合。從Linux角度看到的空間劃分:進程空間和內核空間。從Android的應用對應着Linux的一個個進程。

Andoid中包含一個Java虛擬機,虛擬機是運行在Linux之上的,Android構建在JVM之上,從Android動態運行邏輯上我們需要將Android劃分成Android空間和非Android空間。在Andoid系統中我們面對的是Andoid概念空間,而不是Linux進程了,在Andoid概念空間中已經沒有了Lliux進程的概念,而是Service,proxy,Activity,provider等。

至於虛擬機JVM,我們只需要知道JVM是Dalvik VM(虛擬機)這是一個專爲嵌入式設備打造的JAVA虛擬機,是一個有着自己的code-byte和格式的可以在嵌入式設備上高效運行的Java虛擬機。

爲了研究的深入,我們還是需要涉及到JNI Native部分。在這個分類中我將JVM分爲JVM空間和C++空間。

Android應用的開發者是工作在Android外特性概念空間的,這裏沒有了Linux的一點氣息,Android構建的外特性空間概念包含了:Activity,Provider,Interface,Events,Provider,Service等。至於JVM空間和C++空間的劃分是爲了研究Android核心的描述而提出的,我們在做Android系統開發時,常常需要修改到JNI的Native部分。後面我將用較多的篇幅來深入闡述這個部分。

6. IPC框架分析(Binder,Service,Service manager)
我首先從宏觀的角度觀察Binder,Service,Service Manager,並闡述各自的概念。從Linux的概念空間中,Android的設計Activity託管在不同的的進程,Service也都是託管在不同的進程,不同進程間的Activity,Service之間要交換數據屬於IPC。Binder就是爲了Activity通訊而設計的一個輕量級的IPC框架。

在代碼分析中,我發現Android中只是把Binder理解成進程間通訊的實現,有點狹隘,而是應該站在公共對象請求代理這個高度來理解Binder,Service的概念,這樣我們就會看到不一樣的格局,從這個高度來理解設計意圖,我們纔會對Android中的一些天才想法感到驚奇。從Android的外特性概念空間中,我們看不到進程的概念,而是Activity,Service,AIDL,INTENT。一般的如果我作爲設計者,在我們的根深蒂固的想法中,這些都是如下的C/S架構,客戶端和服務端直接通過Binder交互數據,打開Binder寫入數據,通過Binder讀取數據,通訊就可以完成了。

該注意到Android的概念中,Binder是一個很低層的概念,上面一層根本都看不到Binder,而是Activity跟一個Service的對象直接通過方法調用,獲取服務。

這個就是Android提供給我們的外特性:在Android中,要完成某個操作,所需要做的就是請求某個有能力的服務對象去完成動作,而無需知道這個通訊是怎樣工作的,以及服務在哪裏。所以Andoid的IPC在本質上屬於對象請求代理架構,Android的設計者用CORBA的概念將自己包裝了一下,實現了一個微型的輕量級CORBA架構,這就是Andoid的IPC設計的意圖所在,它並不是僅僅解決通訊,而是給出了一個架構,一種設計理念,這就是Android的閃光的地方。Android的Binder更多考慮了數據交換的便捷,並且只是解決本機的進程間的通訊,所以不像CORBA那樣複雜,所以叫做輕量級。

所以要理解Android的IPC架構,就需要了解CORBA的架構。而CORBA的架構在本質上可以使用下面圖來表示:

在服務端,多了一個代理器,更爲抽象一點我們可以下圖來表示。

分析和CORBA的大體理論架構,我給出下面的Android的對象代理結構。

在結構圖中,我們可以較爲清楚的把握Android的IPC包含了如下的概念:

設備上下文什(ContextObject)
設備上下文包含關於客服端,環境或者請求中沒有作爲參數傳遞個操作的上下文信息,應用程序開發者用ContextObject接口上定義的操作來創建和操作上下文。
Android代理:這個是指代理對象
Binder Linux內核提供的Binder通訊機制

Android的外特性空間是不需要知道服務在那裏,只要通過代理對象完成請求,但是我們要探究Android是如何實現這個架構,首先要問的是在Client端要完成雲服務端的通訊,首先應該知道服務在哪裏?我們首先來看看Service Manger管理了那些數據。Service Manager提供了add service,check service兩個重要的方法,並且維護了一個服務列表記錄登記的服務名稱和句柄。


Service manager service使用0來標識自己。並且在初始化的時候,通過binder設備使用BINDER_SET_CONTEXT_MGR ioctl將自己變成了CONTEXT_MGR。Svclist中存儲了服務的名字和Handle,這個Handle作爲Client端發起請求時的目標地址。服務通過add_service方法將自己的名字和Binder標識handle登記在svclist中。而服務請求者,通過check_service方法,通過服務名字在service list中獲取到service 相關聯的Binder的標識handle,通過這個Handle作爲請求包的目標地址發起請求。

我們理解了Service Manager的工作就是登記功能,現在再回到IPC上,客服端如何建立連接的?我們首先回到通訊的本質:IPC。從一般的概念來講,Android設計者在Linux內核中設計了一個叫做Binder的設備文件,專門用來進行Android的數據交換。所有從數據流來看Java對象從Java的VM空間進入到C++空間進行了一次轉換,並利用C++空間的函數將轉換過的對象通過driver/binder設備傳遞到服務進程,從而完成進程間的IPC。這個過程可以用下圖來表示。
這裏數據流有幾層轉換過程。

(1) 從JVM空間傳到c++空間,這個是靠JNI使用ENV來完成對象的映射過程。
(2) 從c++空間傳入內核Binder設備,使用ProcessState類完成工作。
(3) Service從內核中Binder設備讀取數據。
Android設計者需要利用面嚮對象的技術設計一個框架來屏蔽掉這個過程。要讓上層概念空間中沒有這些細節。Android設計者是怎樣做的呢?我們通過c++空間代碼分析,看到有如下空間概念包裝(ProcessState@(ProcessState.cpp)

在ProcessState類中包含了通訊細節,利用open_binder打開Linux設備dev/binder,通過ioctrl建立的基本的通訊框架。利用上層傳遞下來的servicehandle來確定請求發送到那個Service。通過分析我終於明白了Bnbinder,BpBinder的命名含義,Bn-代表Native,而Bp代表Proxy。一旦理解到這個層次,ProcessState就容易弄明白了。

下面我們看JVM概念空間中對這些概念的包裝。爲了通篇理解設備上下文,我們需要將Android VM概念空間中的設備上下文和C++空間總的設備上下文連接起來進行研究。

爲了在上層使用統一的接口,在JVM層面有兩個東西。在Android中,爲了簡化管理框架,引入了ServiceManger這個服務。所有的服務都是從ServiceManager開始的,只用通過Service Manager獲取到某個特定的服務標識構建代理IBinder。在Android的設計中利用Service Manager是默認的Handle爲0,只要設置請求包的目標句柄爲0,就是發給Service Manager這個Service的。在做服務請求時,Android建立一個新的Service Manager Proxy。Service Manager Proxy使用ContexObject作爲Binder和Service Manager Service(服務端)進行通訊。

我們看到Android代碼一般的獲取Service建立本地代理的用法如下:
IXXX mIxxx=IXXXInterface.Stub.asInterface(ServiceManager.getService("xxx"));

例如:使用輸入法服務:
IInputMethodManager mImm=
IInputMethodManager.Stub.asInterface(ServiceManager.getService("input_method"));

這些服務代理獲取過程分解如下:

(1) 通過調用GetContextObject調用獲取設備上下對象。注意在AndroidJVM概念空間的ContextObject只是 與Service Manger Service通訊的代理Binder有對應關係。這個跟c++概念空間的GetContextObject意義是不一樣的。

注意看看關鍵的代碼

  1. BinderInternal.getContextObject() @BinderInteral.java
  2. NATIVE JNI:getContextObject() @android_util_Binder.cpp
  3. Android_util_getConextObject @android_util_Binder.cpp
  4. ProcessState::self()->getCotextObject(0) @processState.cpp
  5. getStrongProxyForHandle(0) @
  6. NEW BpBinder(0)
複製代碼
注意ProcessState::self()->getCotextObject(0) @processtate.cpp,就是該函數在進程空間建立 了ProcessState對象,打開了Binder設備dev/binder,並且傳遞了參數0,這個0代表了與Service Manager這個服務綁定。

(2) 通過調用ServiceManager.asInterface(ContextObject)建立一個代理ServiceManger。
mRemote= ContextObject(Binder)
這樣就建立起來ServiceManagerProxy通訊框架。

(3)客戶端通過調用ServiceManager的getService的方法建立一個相關的代理Binder。
ServiceMangerProxy.remote.transact(GET_SERVICE)
IBinder=ret.ReadStrongBinder() -》這個就是JVM空間的代理Binder
JNI Navite: android_os_Parcel_readStrongBinder() @android_util_binder.cpp
Parcel->readStrongBinder() @pacel.cpp
unflatten_binder @pacel.cpp
getStrongProxyForHandle(flat_handle)
NEW BpBinder(flat_handle)-》這個就是底層c++空間新建的代理Binder。

整個建立過程可以使用如下的示意圖來表示:

Activity爲了建立一個IPC,需要建立兩個連接:訪問Servicemanager Service的連接,IXXX具體XXX Service的代理對象與XXXService的連接。這兩個連接對應c++空間ProcessState中BpBinder。對IXXX的操作最後就是對BpBinder的操作。由於我們在寫一個Service時,在一個Package中寫了Service Native部分和Service Proxy部分,而Native和Proxy都實現相同的接口:IXXX Interface,但是一個在服務端,一個在客服端。客戶端調用的方式是使用remote->transact方法向Service發出請求,而在服務端的OnTransact中則是處理這些請求。所以在Android Client空間就看到這個效果:只需要調用代理對象方法就達到了對遠程服務的調用目的,實際上這個調用路徑好長好長。

我們其實還一部分沒有研究,就是同一個進程之間的對象傳遞與遠程傳遞是區別的。同一個進程間專遞服務地和對象,就沒有代理BpBinder產生,而只是對象的直接應用了。應用程序並不知道數據是在同一進程間傳遞還是不同進程間傳遞,這個只有內核中的Binder知道,所以內核Binder驅動可以將Binder對象數據類型從BINDER_TYPE_BINDER修改爲BINDER_TYPE_HANDLE或者BINDER_TYPE_WEAK_HANDLE作爲引用傳遞。
7. Service詳解
上一章我們分析了Android IPC架構,知道了Android服務構建的一些基本理念和原理,本章我們將深入分析Android的服務。Android體系架構中三種意義上服務:
Native服務
Android服務
Init空間的服務,主要是屬性設置,這個IPC是利用Socket來完成的,這個我將在另外一章來討論。
Navite服務,實際上就是指完全在C++空間完成的服務,主要是指系統一開始初始化,通過Init.rc腳本起來的服務,例如Service Manger service,Zygote service,Media service , ril_demon service等。
Android服務是指在JVM空間完成的服務,雖然也要使用Navite上的框架,但是服務主體存在於Android空間。Android是二階段初始(Init2)初始化時建立的服務。
1 Service本質結構
我們還是從Service的根本意義分析入手,服務的本質就是響應客戶端請求。要提供服務,就必須建立接收請求,處理請求,應答客服端的框架。我想在Android Service設計者也會無時不刻把這個服務本質框圖掛在腦海中。從程序的角度,服務一定要存在一個閉合循環框架和請求處理框架

分析清楚服務框就必須弄清楚以下的機制及其構成。
(1)閉合循環結構放置在哪裏?
(2)處理請求是如何分發和管理?
(3)處理框架是如何建立的?
(4)概念框架是如何建立的?
2 Service基本框架分析
Android設計中,Native Service和Android Service採用了同一個閉合循環框架。這個閉合循環框架放置在Native的C++空間中,,[email protected][email protected]兩個類完成了全部工作。

在服務框架中,ProcessState是公用的部分,這個公用部分最主要的框架就是閉合循環框架和接收到從Binder來的請求後的處理框架。我們將服務框架用ProcessSate來表示,簡言之:
(1) addservice
(2) 建立閉合循環處理框架。
  1. int main(int argc, char** argv)

  2. {

  3. sp<ProcessState> proc(ProcessState::self());

  4. addService(String16("xxx0"), new xxx0Service());

  5. addService(String16("xxx1"), new xxx1Service());


  6. ProcessState::self()->startThreadPool();

  7. IPCThreadState::self()->joinThreadPool();//閉合循環框架
複製代碼

2.1 Native Service 
Native Service是在系統Init階段通過Init.rc腳本建立的服務。
首先來看看一個例子mediaserver@main_mediaserver.cpp的建立過程。
  1. int main(int argc, char** argv)

  2. {

  3. sp<ProcessState> proc(ProcessState::self());

  4. sp<IServiceManager> sm = defaultServiceManager();

  5. LOGI("ServiceManager: %p", sm.get());

  6. AudioFlinger::instantiate();

  7. MediaPlayerService::instantiate();

  8. CameraService::instantiate();

  9. AudioPolicyService::instantiate();

  10. ProcessState::self()->startThreadPool();

  11. IPCThreadState::self()->joinThreadPool();

  12. }
複製代碼
我們將代碼向下展開了一層,更能看到事物的本質。
  1. int main(int argc, char** argv)

  2. {

  3. sp<ProcessState> proc(ProcessState::self());

  4. sp<IServiceManager> sm = defaultServiceManager();

  5. defaultServiceManager()->addService(String16("media.audio_flinger"), new AudioFlinger());


  6. ProcessState::self()->startThreadPool();

  7. IPCThreadState::self()->joinThreadPool();

  8. }
複製代碼
(1)服務進程建立了ProcessState對象,並將給對象登記在進程的上下文中。
(2)建立一個新AudioFlinger對象,並將對象登記Service Manager Service中。
(3)開始就收請求,處理請求,應答這個循環閉合框架。
2.2 Android Service
Androids service是系統二階段(Init2)初始化時建立的服務。
Android的所有服務循環框架都是建立SystemServer@(SystemServer.java)上。在SystemServer.java中看不到循環結構,只是可以看到建立了init2的實現函數,建立了一大堆服務,並AddService到service Manager。
  1. main() @ com/android/server/SystemServer 

  2. {

  3. init1();

  4. }

  5. Init1()是在Native空間實現的(com_andoird_server_systemServer.cpp)。我們一看這個函數就知道了,原來這個閉合循環處理框架在這裏:

  6. init1->system_init() @System_init.cpp

  7. system_init()我們看到了這個久違的循環閉合管理框架。

  8. {

  9. Call "com/android/server/SystemServer", "init2"

  10. ….. 

  11. ProcessState::self()->startThreadPool();

  12. IPCThreadState::self()->joinThreadPool();

  13. }
複製代碼
Init2()@SystemServer.java中建立了Android中所有要用到的服務:
Entropy Service
Power Manager
Activity Manager
Telephony Registry
Package Manager
Account Manager
Content Manager
System Content Providers
Battery Service
Hardware Service
Alarm Manager
Init Watchdog
Sensor Service
Window Manager
Bluetooth Service
statusbar
Clipboard Service
Input Method Service
NetStat Service
Connectivity Service
Accessibility Manager
Notification Manager
Mount Service
Device Storage Monitor
Location Manager
Search Service
Checkin Service
Wallpaper Service
Audio Service
Headset Observer
Backup Service
AppWidget Service
3 ProcessState和IPCThreadState
從宏觀來講,PocessState及其IPCThreadState處於IPC與內核打交道包裝層。前面的章節已經提到,下面我將更詳細的分析。有關IPC的c++空間的實現都是從ProcessState這個對象完成的。

我們可以得出如下的結論:不管JVM的Binder做了多麼複雜的操作,最終還是需要利用ProcessState 這個c++空間的對象把數據傳遞給Binder Driver,接收數據也是通過ProcessState這個對象完成,ProcessState是所有Binder IPC必經的通道。

ProcessState放置在全局變量gProcess中,每個進程只有一個ProcessState對象,負責打開Binder設備驅動,建立線程池等。而IPCThreadState每個線程有一個,IPCThreadState實例登記在Linux線程程的上下文附屬數據中,主要負責Binder數據讀取,寫入和請求處理框架。IPCThreadSate在構造的時候,獲取進程的ProcessSate並記錄在自己的成員變量mProcess中,通過mProcess可以獲取到Binder的句柄。
3.1 ProcessState的生命週期
既然ProcessState是Binder通訊的基礎,那麼Process必須在Binder通訊之前建立。客戶端,服務端都必須建立。由於現在重點討論服務端,所以重心放置在服務端。在Android體系中有c++空間的服務,JVM空間的服務,這兩類服務在本質上相同的,只是形式上不同,由於他們都是建立在ProcessState這個基礎上,所以在形式上不同就僅僅表現在對OnTransact的回調處理的不同。
Native Service 
我們直接可以看到使用sp<ProcessState> proc(ProcessState::self()),建立建立ProcessState,一旦調用ProcessState就建立了,並且這個self將ProcessSate登記在全局變量中。
Android Service
建立Android Service服務system_init @System_init.cpp中我們可以看到相同的結構。有一點不同的是所有的Android Service都運行在一個進程中:systemsever進程。
3.2 Binder Driver包裝 @IPCThreadState
ProcessSate構造的時候,使用open_binder打開/driver/binder,並將句柄記錄在mDriverFD,在ProcessState中並不使用這個句柄,真正使用這個Binder設備句柄的是IPCThreadState,所有關於Binder的操作放置在IPCThreadState中:
(1)讀取/寫入:talkWithDriver()@IPCThreadState對ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr)進行包裝。
(2)請求處理:executeCommand(...)@ IPCThreadState
(3)循環結構:joinThreadPool()
  1. joinThreadPool()

  2. {

  3. While(1){

  4. talkWithDriver(...)

  5. ...

  6. executeCommand(...)

  7. }

  8. }
複製代碼
8. Android啓動過程詳解
Android從Linux系統啓動有4個步驟;
(1) init進程啓動
(2) Native服務啓動
(3) System Server,Android服務啓動
(4) Home啓動

第一步:initial進程(system/core/init)
init進程,它是一個由內核啓動的用戶級進程。內核自行啓動(已經被載入內存,開始運行,並已初始化所有的設備驅動程序和數據結構等)之後,就通過啓動一個用戶級程序init的方式,完成引導進程。init始終是第一個進程.
Init.rc
Init.marvell.rc

UInit進程一起來就根據init.rc和init.xxx.rc腳本文件建立了幾個基本的服務:
servicemanamger
zygote
。。。

最後Init並不退出,而是擔當起property service的功能。
1.1腳本文件
init@System/Core/Init
Init.c: parse_config_file(Init.rc)
@parse_config_file(Init.marvel.rc)
解析腳本文件:Init.rc和Init.xxxx.rc(硬件平臺相關)
Init.rc是Android自己規定的初始化腳本(Android Init Language, System/Core/Init/readme.txt)
該腳本包含四個類型的聲明:
Actions
Commands
Services
Options.
1.2 服務啓動機制
我們來看看Init是這樣解析.rc文件開啓服務的。
(1)打開.rc文件,解析文件內容@ system/core/init/init.c
將service信息放置到service_list中。@ system/core/init parser.c
(2)restart_service()@ system/core/init/init.c
service_start
execve(…).建立service進程。
第二步 Zygote
Servicemanager和zygote進程就奠定了Android的基礎。Zygote這個進程起來纔會建立起真正的Android運行空間,初始化建立的Service都是Navtive service.在.rc腳本文件中zygote的描述:
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
所以Zygote從main(…)@frameworks/base/cmds/app_main.cpp開始。
(1) main(…)@frameworks/base/cmds/app_main.cpp
建立Java Runtime
runtime.start("com.android.internal.os.ZygoteInit", startSystemServer);
(2) [email protected]
建立虛擬機
運行:com.android.internal.os.ZygoteInit:main函數。
(3)main()@com.android.internal.os.ZygoteInit//正真的Zygote。
registerZygoteSocket();//登記Listen端口
startSystemServer();
進入Zygote服務框架。
經過這幾個步驟,Zygote就建立好了,利用Socket通訊,接收ActivityManangerService的請求,Fork應用程序。
第三步 System Server
[email protected]在Zygote上fork了一個進程: com.android.server.SystemServer.於是SystemServer@(SystemServer.java)就建立了。Android的所有服務循環框架都是建立SystemServer@(SystemServer.java)上。在SystemServer.java中看不到循環結構,只是可以看到建立了init2的實現函數,建立了一大堆服務,並AddService到service Manager。
main() @ com/android/server/SystemServer
{
init1();
}
Init1()是在Native空間實現的(com_andoird_server_systemServer.cpp)。我們一看這個函數就知道了,init1->system_init() @System_init.cpp
在system_init()我們看到了循環閉合管理框架。

{

Call "com/android/server/SystemServer", "init2"

…..

ProcessState::self()->startThreadPool();

IPCThreadState::self()->joinThreadPool();

}


init2()@SystemServer.java中建立了Android中所有要用到的服務。

這個init2()建立了一個線程,來New Service和AddService來建立服務

第三步 Home啓動
[email protected]後半段,我們可以看到系統在啓動完所有的Android服務後,做了這樣一些動作:
(1) 使用xxx.systemReady()通知各個服務,系統已經就緒。
(2) 特別對於ActivityManagerService.systemReady(回調)
Widget.wallpaper,imm(輸入法)等ready通知。
Home就是在ActivityManagerService.systemReady()通知的過程中建立的。下面是ActivityManagerService.systemReady()的僞代碼:
systemReady()@ActivityManagerService.java
resumeTopActivityLocked()
startHomeActivityLocked();//如果是第一個則啓動HomeActivity。
startActivityLocked(。。。)CATEGORY_HOME
9. Zygote Service詳解
在本章我們會接觸到這兩個單詞:
Zygote [生物] 受精卵, 接合子, 接合體
Spawn:產卵
通過這兩個單詞,我們就可以大體知道Zygote是幹什麼的了,就是叫老母雞下蛋。通過“Zygote”產出不同的子“Zygote”。從大的架構上講,Zygote是一個簡單的典型C/S結構。其他進程作爲一個客服端向Zygote發出”孵化”請求,Zygote接收到命令就“孵化”出一個Activity進程來。

Zygote系統代碼組成及其調用結構:
Zygote.java
提供訪問Dalvik “zygote”的接口。主要是包裝Linux系統的Fork,以建立一個新的VM實例進程。
ZygoteConnection.java
Zygote的套接口連接管理及其參數解析。其他Actvitiy建立進程請求是通過套接口發送命令參數給Zygote。
ZygoteInit.java
Zygote的main函數入口。
Zygote系統代碼層次調用
main()
startSystemServer()…
runSelectLoopMode()
Accept socket connection
Conntecion.RunOnce()
Read argument
folkAndSpecialize
folkAndSpecialize使用Native函數Dalvik_dalvik_system_Zygote_forkAndSpecialize
//native 的獲取
dalvik/vm/native
//dalvik_system_Zygote.c
const DalvikNativeMethod dvm_dalvik_system_Zygote[] = {
{ "fork", "()I",
Dalvik_dalvik_system_Zygote_fork },
{ "forkAndSpecialize", "(II[II[[I)I",
Dalvik_dalvik_system_Zygote_forkAndSpecialize },
{ "forkSystemServer", "(II[II[[I)I",
Dalvik_dalvik_system_Zygote_forkSystemServer },
{ NULL, NULL, NULL },
};
在這裏我們就有了Zygote服務的全貌理解,也在Code中印證了。【應yk_hu0621修正】{由於Android中沒有具體應用程序的入口,都是通過啓動Actvity來啓動相關的Android應用,而這個 Android應用則對應着Linux進程,Activity便Host在這個應用程序上。}
{原文:Activity在本質上是個什麼東西,就是一個Linux進程}
從分析中我們可以看到,Android使用了Linux的fork機制。在Linux中Fork是很高效的。
一個Android的應用實際上一個Linux進程,所謂進程具備下面幾個要素,
a.要有一段程序供該進程運行,程序是可以被多個進程共享的。
b..進程專用的系統堆棧空間。
c.進程控制塊,在linux中具體實現是task_struct
d.有獨立的存儲空間。
fork 創造的子進程複製了父親進程的資源,包括內存的內容task_struct內容,在複製過程中,子進程複製了父進程的task_struct,系統堆棧空間和頁面表,而當子進程改變了父進程的變量時候,會通過copy_on_write的手段爲所涉及的頁面建立一個新的副本。所以只有子進程有改變變量時,子進程才新建了一個頁面複製原來頁面的內容,基本資源的複製是必須的,整體看上去就像是父進程的獨立存儲空間也複製了一遍。
再看看下面Google在講解Dalvik虛擬機的圖片,我們就大體有了Android系統中Actvitiy的實際映射狀態有了基本的認識。

10.Android GWES基本原理篇
我這裏的GWES這個術語實際上從Microsoft 的Window上移植過來的,用GWES來表示Android的窗口事件系統不是那麼準確,在Android中Window是個弱化了的概念,更多的表現在View這個概念上。在很大程度上,Android的View的概念可以代替Microsoft Window這個概念,有點和Microsof暗中較勁的意味,你用過的概念我就偏不用,這個也是我以爲的設計者意圖。
原始GUI基本框架
首先我們從Android的SDK外特性空間開始,在編寫Actvitiy時,我們都是面對的處理函數:OnXXXX(),例如有按鍵按下就是OnKeyDown等,在這個過程中系統做了怎樣的處理?要詳細的理解這個過程,我們就需要理解Andoid的View管理,窗口系統,消息系統和輸入系統。我們還是從最本質的地方開始,Android作爲一種嵌入式的圖形用戶界面系統,它的基本原理與一般GUI的原理是相同的,同時也是遵循GWES(圖形窗口事件系統)的一般規律,總體上Android就是管理用戶輸入和系統屏幕輸出的一個系統。其實GWES這個名稱更能體現GUI的基本實質要素:圖形、窗口、事件。
1. 一般GUI的基本組成
GUI的實現就是對上面提到的三個基本要素的管理,根據這這三個要素的特性及其涉及的範圍,GUI在總體上可以分爲三部分:
事件管理器
窗口管理器
GDI(繪製與GDI邏輯對象管理)

(1) 事件管理器
收集系統消息,轉換並分發系統消息和用戶消息給各個窗口對象。
消息隊列管理
(2)窗口管理器:
管理窗口的創建,銷燬
窗口的繪製
活動窗口,輸入焦點的切換
窗口間關係的管理
控件,菜單實現
(3)GDI
上下文設備管理
上下文設備對象管理:字體,畫筆等
圖形繪製:點、線,填充等
圖象操作:位傳送、位圖操作
2 系統體系構架及其數據流的大體走向

在本質上GUI就是管理用戶輸入和屏幕輸出,我們從上面的體系結構可以看到GUI的這兩大數據流的基本流向,這也決定了Android GWES設計的最基本的着眼點。
Android弱化了窗口的概念,着重使用View的概念。所以Android的基本組成可以從上面的圖修改成如下的組成:

11.Android GWES消息系統篇
我們要理解Android的消息系統,Looper,Handle,View等概念還是需要從消息系統的基本原理及其構造這個源頭開始。從這個源頭,我們才能很清楚的看到Android設計者設計消息系統之意圖及其設計的技術路線。
消息系統的基本原理

從一般的系統設計來講,一個消息循環系統的建立需要有以下幾個要素:
消息隊列
發送消息
消息讀取
消息分發
消息循環線程
首先來研究一下消息驅動的基本模型,我使用如下的圖形來表示一個消息系統最基本構成:

上面的模型代表應用程序一直查詢自己的消息隊列,如果有有消息進來,應用消息處理函數中根據消息類型及其參數來作相應的處理。

消息系統要運作起來,必定有消息的產生和消費。我們可以從下圖看到消息生產和消費的一個基本的鏈條,這是一個最基本的,最簡單的消息系統。

生產線程將消息發送到消息隊列,消息消費者線程從消息隊列取出消息進行相應的處理。但是這樣簡單的模型對實際運行的系統來說是不夠的,例如對系統資源的消耗等不能很好的處理,我們就需要一個有旗語的消息系統模型,在上面的消息系統模型中加入了一個旗語,讓消息消費者線程在沒有消息隊列爲空時,等待旗語,進入到掛起狀態,而有消息到達時,才被喚醒繼續運行。當然生產者同時也可以是消費者。

2 Android的消息模型

Android要建立一個消息系統使用了Looper,MessageQueue,Handler等概念,從上節的原理我們可以知道這些都是概念包裝,本質的東西就是消息隊列中消息的分發路徑的和消息分發處理方式的設計。Android巧妙的利用了對象抽象技術抽象出了Looper和Handler的概念。在Looper和Handler兩個概念的基礎上,通過View的處理函數框架,Android十分完美的達到消息分發的目的。

參照基本消息系統描述模型,我給出了Android消息系統整體框架,表示如下:

Android消息系統消息分發框架

3 Looper,Handler詳解

Looper只是產生一個消息循環框架,首先Looper創建了消息隊列並把它掛接在Linux的線程上下文中,進入到取消息,並分發消息的循環當中。Handler對象在同一個線程上下文中取得消息隊列,對消息隊列進行封裝操作,最主要的就是SendMessage和擔當起dispatchMessage這個實際工作。外部系統需要向某個Android線程發送消息,必須通過屬於該AndroidThread的Handler這個對象進行。

Handler屬於某個線程,取決Handlerd對象在哪個線程中建立。Handler在構建時做了如下的默認動作:

從線程上下文取得Looper。
通過Looper獲取到消息隊列並記錄在自己的成員mQueue變量中
Handler使用消息隊列進行對象封裝,提供如下的成員函數:
通過 post(Runnable r)發送。Runnable是消息處理的回調函數,通過該消息的發送,引起Runable 的回調運行,Post消息放置消息隊列的前面。Message.callback=Runable.
通過 sendMessage發送。放置在所有的Post消息之後,sendMessage發送消息.
dispatchMessage分發消息。消息帶有回調函數,則執行消息回調函數,如何沒有則使用默認處理函數:handleMessage。而handleMessage往往被重載成某個繼承Handler對象的新的特定的handleMessage。
幾乎所有的Message發送時,都指定了target。Message.target=(this).
Looper運行在Activity何處?我們現在可以從代碼堆棧中縱觀一下Looper的位置。
NaiveStart.main()
ZygoteInit.main
ZygoteInit$MethodAndArgsCall.run
Method.Invoke
method.invokeNative
ActivityThread.main()
Looper.loop()
ViewRoot$RootHandler().dispatch()
handleMessage
....

這樣我們就更清楚的瞭解到Looper的運行位置。


發佈了57 篇原創文章 · 獲贊 17 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章