Android 有趣架構

學習安卓的架構,是從操作系統的角度理解安卓。安卓使用Linux內核,但安卓的架構又與常見的Linux系統有很大的區別。我們先來回顧一下傳統的Linux架構,再來看安卓的變化。

 

Linux系統架構

先來看常見的Linux系統架構,你可以參考Linux的架構

 

 

內核是系統的底層。Linux開機後,內核即啓動,並存活於屬於自己的內存空間,即內核空間(kernel space)。內核的一大功能是和硬件通信。內核中包含各種驅動程序,這些驅動程序既能實現底層的硬件讀寫操作,又包含硬件使用邏輯。比如一臺打印機的驅動,會把打印指令放在內存中的A位置,把打印數據放在內存中的B位置。打印機讀取指令後,會從B位置取得數據打印。在內核上層,驅動程序的功能被抽象爲函數調用,比如printx(data)。這個函數調用隱藏了許多細節,比如如何執行讀寫,以及A和B的具體位置。

除了抽象硬件外,內核還維護着Linux的許多重要運行機制,比如虛擬內存、調度器、信號以及進程間通信(IPC)。內核的功能接口是系統調用(system call)函數。

 

用戶使用C或者C++編寫的程序,將編譯成機器碼,運行成爲一個進程(process)。每個進程都會有一個自己的進程空間。進程空間存活於內核空間之外的用戶空間(user space)。進程空間中包含程序的代碼和數據。不同進程的進程空間相互獨立。進程間如果想要相互交流,需要借用特殊的進程間通信(IPC)機制。進程空間中有棧(stack)和堆(heap)。當執行到新的函數調用時,棧頂會增加一幀(stack frame),用於記錄該函數的數據和返回地址。當函數執行完成時,該幀會彈出,並根據返回地址接着執行母程序的指令。堆中的空間由程序自由分配。你可以進一步參考Linux從程序到進程

一個進程空間

 

Linux的程序大多是C和C++編寫。代碼被編譯爲機器碼,以便計算機理解。常用的代碼被編譯成(library)。程序員可以從自己的程序中調用庫函數,來重複利用已有代碼。程序中調用庫函數時,庫中包含的機器代碼會加載入程序對應的進程空間。

 

 

Android架構

我們現在來看看安卓的架構。Android的底層使用的是Linux內核。在用戶空間中,每個應用也會運行爲一個進程。但安卓細節方面和傳統Linux差別很大。

 

HAL

安卓驅動硬件的方式與Linux不盡相同。傳統Linux的驅動完全存活於內核空間。Android則在內核外部增加了硬件抽象層(HAL, Hardware Abstraction Layer),把一部分驅動功能放到HAL層中。你或許會奇怪,安卓爲什麼費盡麻煩增加一個HAL呢?爲了保護源代碼。Linux內核採用了GPL協議,所以硬件生產商想要支持Linux系統,必須遵照GPL協議公開硬件驅動的源代碼。但這些源代碼中包含有許多硬件的設計信息,牽涉到硬件生產商的核心利益。而增加了HAL層之後,硬件廠商就不需要開放所有的驅動代碼了。

我們來看看HAL的具體工作方式。安卓的HAL存活在用戶空間,它與內核驅動通信。但HAL是個“空殼”,安卓會根據需要,加載不同的動態庫,比如調用計算機時,載入libprinter.so。這個動態庫是由硬件廠商提供的。比如上面的打印機,硬件廠商可以把讀寫功能做成驅動。而“指令寫入位置A、數據寫入位置B”這樣的高層邏輯,則編譯成庫文件(.so)。當我們使用打印機打印時,我們將打印需求和數據發送給HAL。HAL加載對應的動態庫,通過內核驅動的讀寫功能,將指令寫入打印機的內存位置A,數據寫入位置B。打印機預裝的程序從位置A讀到打印指令,就會從位置B讀取數據,實現打印。這樣,HAL實際上把部分驅動功能放入到動態庫中,內核中的驅動只保留最基本的讀寫操作功能。部分驅動功能從內核空間轉移到了用戶空間。由於高層邏輯是編譯好的.so文件,打印機廠商不用擔心如指令位置A、數據位置B這樣的信息泄露。

 

左爲Linux,右爲安卓HAL

 

安卓的HAL模塊是從Linux內核導出的,所以源代碼公開。HAL是Apache協議,並不要求它的配套程序,如硬件驅動的源碼公開。由於這些庫函數沒有直接調用內核,所以不需要釋放源代碼。通過HAL層,安卓保護了硬件廠商的商業利益,鼓勵了硬件廠商對安卓系統的支持。

 

當然,Linux開發小組對此很不高興,把安卓的開發分支從Linux內核中刪除。

 

Dalvik虛擬機

安卓的應用是由Java編寫的,而包括HAL在內的Linux的庫都是由C/C++編寫的,這個落差由Dalvik虛擬機銜接的。當一個應用運行時,進程空間內將包含一個Dalvik虛擬機。Java程序編譯爲字節碼文件,運行在Dalvik虛擬機中。根據Java代碼中的要求,Dalvik通過JNI(Java Native Interface)調用底層的C/C++編寫的功能。JNI是從Java中調用C/C++模塊的接口。由於上層接口的標準化,字節碼可以暢通無阻的跨平臺運行。

 

Dalvik VM

Dalvik虛擬機內部是一個“虛擬”進程空間,有自己的棧和堆,管理代碼的運行流程。如果這以“虛擬”進程空間不足,Dalvik內建的垃圾回收(garbage collection)機制會自動清空堆上不再使用的對象。自動的垃圾回收簡化了程序員的工作,但速度較慢。手動內存管理效率高,但需要更多的編程,且容易犯錯。垃圾回收的具體原理可參考Java內存管理與垃圾回收。 

 

當然,Oracle不高興,認爲Dalvik是對JVM赤裸裸的抄襲。

 

Core Library和Android Framework

Android程序員的主要工作是編寫Dalvik上運行的Java程序。Google提供了核心類庫(Java core library),它包括Java的常用類庫,如:

  • java.lang
  • java.util
  • java.math
  • java.net
  • ...

這些類庫的API,與Oracle的官方API相同,所以你可以按照同樣的方法調用。

 

核心類庫中還包括Dalvik虛擬機的調用接口:

  • dalvik.annotation
  • dalvik.bytecode
  • dalvik.system

 

安卓程序員還可以調用一些針對安卓的類庫,即安卓框架(Android Framework)。這些類庫對應安卓的特定功能。通過它們,我們可以操縱安卓上的各個功能模塊,從觸屏到GPS,從視圖元素到數據庫。如:

  • android.database
  • android.bluetooth
  • android.gesture
  • ...

安卓相關的類庫列表

 

核心類庫和安卓框架是安卓程序員的左膀右臂。再加上Java語言本身的邏輯,這就是安卓程序員戰鬥着的世界了。我會在以後的文章中,繼續深入這個戰場。


總結

HAL

Dalvik

Core Library

Android Framework


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章