本節要瞭解、弄懂安卓系統架構的原理,首先將安卓系統架構完全分析清楚,再根據下載好的Android8的原始碼,將原始碼目錄中的內容與系統架構聯合在一起,最後總結爲什麼安卓系統架構要這麼設計。
安卓系統架構,就是從底層硬體到高層軟體的一整套技術體系,使用者使用的行動端裝置如果使用安卓系統搭建,那麼使用者就可以使用安卓平臺上的應用,安卓系統架構圖如下:
從頂層到底層依次是:APP --> Framework --> Native --> HAL --> Kernal,接下來對這些層進行三個層次的分析:爲什麼要有它、是什麼、在哪裏,一切要從爲什麼入手。
why
我今天早上睡過頭遲到了,那麼我就在想,如果有一個鬧鐘就好了,於是就出現了手機鬧鐘APP,就解決了使用者每天起牀需要有人按時提醒上班的需求。所以當應用設計出來後,一些頁面、頁面跳轉、功能都需要在APP層進行實現。
what
就如同英文直譯過來一樣,是一些應用軟體,比如系統自帶的應用如:時鐘、計算器,和使用者自己安裝的應用如:微信、微博。應用需要給使用者提供好看的外觀和滿足需求的功能,是安卓系統架構中使用者看得見摸得着的第一個東西,直接和使用者的體驗掛鉤。
where
以apk的形式安裝在使用者的手機上,開啓手機一看全是。
原始碼根目錄中的packages目錄對應着系統應用層,如下所示。
packages目錄 | 描述 |
---|---|
apps | 核心應用程式 |
experimental | 第三方應用程式 |
inputmethods | 輸入法目錄 |
providers | 內容提供者目錄 |
screensavers | 螢幕保護 |
services | 通訊服務 |
wallpapers | 牆紙 |
why
當產品的定位和設計出來後,安卓軟體工程師就要進行開發,手機上的產品,都是軟體和硬體一起協助開發完成的,那是不是每次開發產品的時候都要將硬體和軟體都寫好呢?當然不是,這樣開發的效率太低、所需要的開發知識的門檻太高了,所以就需要有人幫助安卓應用工程師把一些與系統打交道、通用的東西都封裝好,變成有描述、可以呼叫的API介面,達到提效率、降門檻的效果。
what
Framework層是一些封裝好的api,主要由Java程式碼實現。當安卓應用工程師在程式設計的時候,就可以呼叫Framework層的api對系統層面比如電源管理、訊息佇列、包管理等做操作。Framework同下層打交到的方式有很多種,參考:Android Framework層和Native層通訊的6種方式,同上層打交到的方式就是抽象出各種Java介面。
往上層看,在AS中開發app的時候,import的各種android.*,就是Framework層的api。
package com.leo.helloworld;
import android.app.ActivityManager;// 這邊都是
import android.content.Context;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
public class leo extends AppCompatActivity {
public void activityManagerDemo(Context context){
ActivityManager activityManager =
(ActivityManager)(context.getSystemService(android.content.Context.ACTIVITY_SERVICE )) ;
return;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_leo1);
}
}
往下層看,Framework層提供了jni.h的檔案去連線Native中的C或C++程式碼,達到了Java程式碼呼叫C或C++程式碼的效果。
下面 下麪參照網上對於 ‘Framework是什麼’ 的回答:
直接翻譯的意思是架構,但這樣說可能不懂,下面 下麪我從兩個方面來給你說吧:
一是比喻來說,假設你現在要蓋樓房,framework就好比一個建築公司,它裏面有專門採集石料的,專門的租夾板的,專門的磨砂,搬磚的,運輸的等等一系列的,你需要做的就是要通過這家建築公司來蓋樓,比如說你要採集石料,你通過公司採購部門,直接採集來了石料,然後通過他們進行一系列的工作,這要比你自己去河裏採砂,到山上去炸石頭(這些活都是不使用framework的底層嵌入式開發人員做的)要簡單的多,這也是爲什麼farmework要高效的多,所以說,對於開發人員來說,他就像是會爲開發省很多事情,但這種框架下開發的軟體有一定的依賴性,所以,對於不是開發人員的使用者來說,如果你的電腦上有這種框架下開發的軟體,你必須有這個框架軟體纔可以,就好像你如果要用擴充套件名爲EXE的應用程式,你必須先有windows系統一樣
另外呢,就是通過實際案例來說明framework
如果我們要完成螢幕列印「hello world」,你如果沒用框架軟體,你或許會先瞭解底層如何實現在螢幕上顯示字元,又如何啓動顯示器,如何控制字元位置等等,然後再考慮如何列印hello world
但是在framework下,框架下的Console類下有個靜態方法Write直接實現了列印,你只需要呼叫這個方法,然後告訴他你要列印的資訊就可以了,Console.Write(「hello world」)
不管你是不是開發人員,解釋的覺得還是透徹的,不懂的話可以再追問,希望能得到最佳~
Framework層主要提供的元件如下:
名稱 | 功能描述 |
---|---|
Activity Manager(活動管理器) | 管理各個應用程式生命週期以及通常的導航回退功能 |
Location Manager(位置管理器) | 提供地理位置以及定位功能服務 |
Package Manager(包管理器) | 管理所有安裝在Android系統中的應用程式 |
Notification Manager(通知管理器) | 使得應用程式可以在狀態列中顯示自定義的提示資訊 |
Resource Manager(資源管理器) | 提供應用程式使用的各種非程式碼資源,如在地化字串、圖片、佈局檔案、顏色檔案等 |
Telephony Manager(電話管理器) | 管理所有的移動裝置功能 |
Window Manager(視窗管理器) | 管理所有開啓的視窗程式 |
Content Providers(內容提供器) | 使得不同應用程式之間可以共用數據 |
View System(檢視系統) | 構建應用程式的基本元件 |
where
應用框架層的主要實現程式碼在/frameworks/base和/frameworks/av目錄下,其中/frameworks/base目錄結構如下所示:
/frameworks/base目錄 | 描述 | /frameworks/base目錄 | 描述 |
---|---|---|---|
api | 定義API | cmds | 重要命令:am、app_proce等 |
core | 核心庫 | data | 字型和聲音等數據檔案 |
docs | 文件 | graphics | 圖形影象相關 |
include | 標頭檔案 | keystore | 和數據簽名證書相關 |
libs | 庫 | location | 地理位置相關庫 |
media | 多媒體相關庫 | native | 本地庫 |
nfc-extras | NFC相關 | obex | 藍牙傳輸 |
opengl | 2D/3D 圖形API | packages | 設定、TTS、VPN程式 |
sax | XML解析器 | services | 系統服務 |
telephony | 電話通訊管理 | test-runner | 測試工具相關 |
tests | 測試相關 | tools | 工具 |
wifi | wifi無線網路 |
參考鏈接:Android系統架構與系統原始碼目錄
why
首先,安卓的應用和framework層主要使用Java語言開發,但是Java是高階語言的一種,雖然在程式設計時比較容易學習,但是如果要完成一些複雜運算和偏向底層的操作,Java非常難實現,而使用C/C++會很簡單,所以一般會使用虛擬機器:JVM等,將Java程式碼編譯後再解釋成機器語言,來驅動硬體。那麼除開使用虛擬機器將.class檔案解釋後變成機器可識別的檔案,我們可以通過給Java程式碼加上native關鍵字、Java程式碼利用jni.h檔案呼叫C/C++程式碼的方式,把複雜的Java難以實現的功能,交給C/C++程式碼來實現。
what
常見一些本地服務和一些鏈接庫等。這一層的一個特點就是通過C和C++語言實現。
where
C/C++程式庫並不完全在一個目錄中,主要的C/C++程式庫如:
名稱 | 功能描述 |
---|---|
OpenGL ES | 3D繪圖函數庫 |
Libc | 從BSD繼承來的標準C系統函數庫,專門爲基於嵌入式Linux的裝置定製 |
Media Framework | 多媒體庫,支援多種常用的音訊、視訊格式錄製和回放。 |
SQLite | 輕型的關係型數據庫引擎 |
SGL | 底層的2D圖形渲染引擎 |
SSL | 安全通訊協定,是爲網路通訊提供安全及數據完整性的一種安全協定 |
FreeType | 可移植的字型引擎,它提供統一的介面來存取多種字型格式檔案 |
要檢視framework層對應的native層原始碼,參考:如何查詢native方法所對應的底層檔案
why
在安卓系統中,APP開發和Framework層開發都是Java程式碼,Java程式碼執行在虛擬機器上,如:JVM。Art也是虛擬機器的一種,所以其存在的理由就是爲了支援Java程式碼編譯、解釋。
what
Art,Android Runtime,是安卓手機上執行的虛擬機器,Android4.4及以前使用的都是Dalvik虛擬機器,Android5.0纔開始使用Art。
爲什麼不使用JVM做爲虛擬機器?
Java VM是以基於棧的虛擬機器(Stack-based),而Dalvik是基於暫存器的虛擬機器(Register-based)。 顯然,後者最大的好處在於可以根據硬體實現更大的優化,這更適合移動裝置的特點。DVM非常適合在行動終端上使用,與PC相比,它不需要很快的CPU和大量的記憶體空間。
爲什麼要從Dalvik變爲Art?
簡而言之,就是Dalvik是邊執行邊解釋.dex檔案,Art是啓動時就預解釋.dex檔案爲.oat檔案,Dalvik啓動時更快,Art執行時更快。
參考鏈接:
一篇文章帶你瞭解 Android的 JIT 、AOT、Dalvik、ART ,不再傻傻分不清
JVM:.java檔案->.class檔案->.jar檔案
DVM:.java檔案->.class檔案->.dex檔案->.apk檔案
ART:.java檔案->.class檔案->.dex檔案->.oat檔案->.apk檔案
where
why
設想一下使用Java開發後端的情況,似乎在JVM後,就直接是操作系統,利用操作系統內提供的對機器的指令完成軟體對硬體的操作,但是爲啥安卓系統架構中Art之下還需要有一個硬體抽象層?下面 下麪參照一下羅老師對於HAL層的介紹:
Android的硬體抽象層,簡單來說,就是對Linux內核驅動程式的封裝,向上提供介面,遮蔽低層的實現細節。也就是說,把對硬體的支援分成了兩層,一層放在使用者空間(User Space),一層放在內核空間(Kernel Space),其中,硬體抽象層執行在使用者空間,而Linux內核驅動程式執行在內核空間。爲什麼要這樣安排呢?把硬體抽象層和內核驅動整合在一起放在內核空間不可行嗎?從技術實現的角度來看,是可以的,然而從商業的角度來看,把對硬體的支援邏輯都放在內核空間,可能會損害廠家的利益。我們知道,Linux內核原始碼版權遵循GNU License,而Android原始碼版權遵循Apache License,前者在發佈產品時,必須公佈原始碼,而後者無須發佈原始碼。如果把對硬體支援的所有程式碼都放在Linux驅動層,那就意味着發佈時要公開驅動程式的原始碼,而公開原始碼就意味着把硬體的相關參數和實現都公開了,在手機市場競爭激烈的今天,這對廠家來說,損害是非常大的。因此,Android纔會想到把對硬體的支援分成硬體抽象層和內核驅動層,內核驅動層只提供簡單的存取硬體邏輯,例如讀寫硬體暫存器的通道,至於從硬體中讀到了什麼值或者寫了什麼值到硬體中的邏輯,都放在硬體抽象層中去了,這樣就可以把商業祕密隱藏起來了。也正是由於這個分層的原因,Android被踢出了Linux內核主線程式碼樹中。大家想想,Android放在內核空間的驅動程式對硬體的支援是不完整的,把Linux內核移植到別的機器上去時,由於缺乏硬體抽象層的支援,硬體就完全不能用了,這也是爲什麼說Android是開放系統而不是開源系統的原因。
參考鏈接:Android硬體抽象層(HAL)概要介紹和學習計劃
我的理解是,其實安卓系統架構中的HAL層和Kernal層組合起來,起到的是操作系統的作用,但是爲了將關鍵原始碼不開源,所以將一些不能公佈的原始碼放在HAL層,一些能開源的程式碼放在Kernal層。
what
硬體抽象層是位於操作系統內核與硬體電路之間的介面層,其目的在於將硬體抽象化,爲了保護硬體廠商的智慧財產權,它隱藏了特定平臺的硬體介面細節,爲操作系統提供虛擬硬體平臺,使其具有硬體無關性,可在多種平臺上進行移植。
在HAL層,程式碼也是儲存在jni.h和.c型別的檔案中,與Framework層呼叫Native層不一樣的是,HAL層的程式碼需要遵循固定的格式、命名進行編寫。
where
why
如果說上面的所有層,都是決定邏輯上去驅動那個硬體,那麼需要有一層只負責對硬體做操作,不是說上面的所有層沒辦法對硬體做操作,畢竟大家都是圖靈完備的Java/C/C++程式碼,而是要把相同類似的事物放在一起,這樣可以解耦,所以Kernal層,主要負責對硬體做操作,也叫驅動層。
爲什麼安卓要採用linux作爲操作系統呢?
Android系統是基於Linux內核的,這一層爲Android裝置的各種硬體提供了底層的驅動(如顯示,音訊,照相機,藍牙,WI-FI,電源管理等等),那麼Android爲什麼會選擇採用linux呢?原因與Linux的特性有關,內核作爲一個抽象層存在硬體和軟體之間,強大的記憶體管理和進程管理,基於許可權的安全模式,支援共用庫,經過認證的驅動模式,Linux本身就是開源專案等等。
what
Android 的核心繫統服務基於Linux 內核,在此基礎上新增了部分Android專用的驅動。系統的安全性、記憶體管理、進程管理、網路協定棧和驅動模型等都依賴於該內核。
主要驅動:增強顯示驅動、鍵盤驅動、Flash記憶體驅動、照相機驅動、音訊驅動、藍牙驅動、WiFi驅動、Binder IPC驅動、Power Management(電源管理),包括硬體時鐘,記憶體分配和共用,低記憶體管理,kernel偵錯,日誌裝置,android IPC機制 機製,電源管理等。
如果要寫一個驅動應該怎樣寫呢?Android 從上層到底層-----kernel層
where
主要在Driver目錄下。
1、Binder IPC驅動:基於OpenBinder框架的一個驅動,用於提供 Android平臺的進程間通訊功能。原始碼位於drivers/staging/android/binder.c。
2、電源管理(PM) :一個基於標準Linux電源管理系統的輕量級Android電源管理驅動,針對嵌入式裝置做了很多優化,比如電池電量。原始碼位於:kernel/power/earlysuspend.c、kernel/power/consoleearlysuspend.c、kernel/power/fbearlysuspend.c、kernel/power/wakelock.c、kernel/power/userwakelock.c
3、低記憶體管理器:比Linux的標準的OOM機制 機製更加靈活,它可以根據需要殺死進程以釋放需要的記憶體。原始碼位於 drivers/staging/ android/lowmemorykiller.c。
4、匿名共用記憶體: 爲進程間提供大塊共用記憶體,同時爲內核提供回收和管理這個記憶體的機制 機製。原始碼位於mm/ashmem.c。
5、 PMEM :用於向使用者空間提供連續的實體記憶體區域,DSP和某些裝置只能工作在連續的實體記憶體上。原始碼位於drivers/misc/pmem.c。
6、 Logger :一個輕量級的日誌裝置,用於抓取Android系統的各種日誌。原始碼位於drivers/staging/android/logger.c。
7、 Alarm :提供了一個定時器,用於把裝置從睡眠狀態喚醒,同時它還提供了一個即使在裝置睡眠時也會 執行的時鐘基準。原始碼位於drivers/rtc/alarm.c。
8、USB Gadget:驅動 一個基於標準 Linux USB gadget驅動框架的裝置驅動,Android的USB驅動是基於gaeget框 架的。原始碼位於drivers/usb/gadget/。
9、Ram Console: 爲了提供偵錯功能,Android允許將偵錯日誌資訊寫入一個被稱爲RAM Console的裝置裡,它是一個基於RAM的Buffer。原始碼位於drivers/staging/android / ram_console.c。
10、timed device: 提供了對裝置進行定時控制的功能,目前支援vibrator和LED裝置。原始碼位於drivers/staging/android /timed_output.c(timed_gpio.c)。
11、Yaffs2 :是檔案系統 Android採用Yaffs2作爲MTD nand flash檔案系統,原始碼位於fs/yaffs2/目錄下。Yaffs2是一個快速穩定的應用於NAND和NOR Flash的跨平臺的嵌入式裝置檔案系統,同其他Flash檔案系統相比,Yaffs2能使用更小的記憶體來儲存其執行狀態,因此它佔用記憶體小。Yaffs2的垃圾回收非常簡單而且快速,因此能表現出更好的效能。Yaffs2在大容量的NAND Flash上的效能表現尤爲突出,非常適合大容量的Flash儲存。
從安卓8的原始碼目錄入手,分析安卓系統架構的每一層,大概在原始碼中的什麼位置。
目錄圖如下:
Android原始碼根目錄 | 描述 |
---|---|
art | 全新的ART執行環境 |
bionic | 系統C庫 |
bootable | 啓動引導相關程式碼 |
build | 存放系統編譯規則及generic等基礎開發包設定 |
cts | Android相容性測試套件標準 |
dalvik | dalvik虛擬機器 |
developers | 開發者目錄 |
development | 應用程式開發相關 |
device | 裝置相關設定 |
docs | 參考文件目錄 |
external | 開源模組相關檔案 |
frameworks | 應用程式框架,Android系統核心部分,由Java和C++編寫 |
hardware | 主要是硬體抽象層的程式碼 |
kernel | Linux Kernal,需要單獨去下載 |
libcore | 核心庫相關檔案 |
libnativehelper | 動態庫,實現JNI庫的基礎 |
packages | 應用程式包 |
pdk | Plug Development Kit 的縮寫,本地開發套件 |
platform_testing | 平臺測試 |
prebuilts | x86和arm架構下預編譯的一些資源 |
sdk | sdk和模擬器 |
system | 底層檔案系統庫、應用和元件 |
toolchain | 工具鏈檔案 |
tools | 工具檔案 |
Makefile | 全域性Makefile檔案,用來定義編譯規則 |
App層:packages
Framework層:frameworks
Native/ART層
NativeC/C++:bionic
Art:art
HAL層:hardware
Kernal層:kernel
思路:從整體架構分析,再從大到小,到每層分工來分析。
從0開始,什麼都沒有,我們收到需求:做一款能在手機上執行的應用,分析本質,就是軟體和硬體的互動,完成一種滿足使用者需求的產品。那麼現在開始開發了,寫了很多程式碼,配合上硬體,能完成功能,那麼這些程式碼裏面,肯定必須得有軟體能直接驅動硬體的程式碼,而這些程式碼肯定是最後被呼叫,又因爲要和硬體打交道,C語言很合適,於是選擇C語言編寫,這時候把這些驅動硬體的程式碼拉出來放在一個資料夾裏面,把這個資料夾叫做操作系統程式碼。由於在軟體選語言的時候,覺得Java的可移植性好,所以選擇用Java進行開發,接下來再看看寫的程式碼,除去驅動硬體的程式碼後,發現有一些程式碼是用來寫APP的頁面、頁面跳轉之類的,那也把這些程式碼整合一下,放在一個資料夾裏面,就叫業務程式碼吧。而Java開發,那必須得有虛擬機器才能 纔能變成機器識別的程式碼,所以又將虛擬機器的程式碼放在一個資料夾裡,就叫虛擬機器程式碼吧。
開發的某一天,我們忽然碰到一個很複雜的功能,Java實現起來太難了,這時候想到一個辦法–使用C/C++來實現,然後用Java呼叫這些C/C++程式碼來實現功能,那也把這些C/C++程式碼也放在一個資料夾裡,就叫呼叫的C/C++程式碼吧。
開發工作結束了,現在的專案結構是:業務程式碼、虛擬機器程式碼、呼叫的C/C++程式碼、操作系統程式碼最後連線到硬體。
在休息兩天後,又接到新的需求,要開發另外一款新的產品,這下根據上一款專案的程式碼,忽然發現,好像業務程式碼中,有一部分是可以重複使用的,比如一些位置、電話之類的通用模組,那新建一個資料夾,把這部分重複的程式碼也放在一個資料夾裏面,就叫通用程式碼吧。這時候忽然收到通知,操作系統的程式碼要求要開源了,但是裏面有一部分程式碼涉及商業機密不允許開源啊,於是把這部分無法開源的程式碼放在一個資料夾裡,就叫不開原始碼吧。
第二款APP開發結束了,現在的專案結構是:業務程式碼、通用程式碼、虛擬機器程式碼、呼叫的C/C++程式碼、不開原始碼、操作系統程式碼,對應了安卓系統架構的:APP層、Framework層、Art、Native、HAL層、Kernal層。