Android架構
Android系統啓動過程:Loader -> Kernel -> Native -> Framework -> App
Loader
Boot ROM: 當手機處於關機狀態時,長按Power鍵開機,引導芯片開始從固化在ROM裏的預設出代碼開始執行,然後加載引導程序到RAM
**Boot Loader:**這是啓動Android系統之前的引導程序,主要是檢查RAM,初始化硬件參數等功能。
Kernel
Android內核層,到這裏纔剛剛開始進入Android系統。
啓動Kernel的swapper進程(pid=0):該進程又稱爲idle進程, 系統初始化過程Kernel由無到有開創的第一個進程, 用於初始化進程管理、內存管理,加載Display,Camera Driver,Binder Driver等相關工作。
啓動kthreadd進程(pid=2):是Linux系統的內核進程,會創建內核工作線程kworkder,軟中斷線程ksoftirqd,thermal等內核守護進程。kthreadd進程是所有內核進程的鼻祖。
Native
啓動init進程(pid=1),是Linux系統的用戶進程,init進程是所有用戶進程的鼻祖。init孵化用戶空間的守護進程、HAL層以及開機動畫等。
init進程會孵化出ueventd、logd、healthd、installd、adbd、lmkd等用戶守護進程。
init進程還啓動servicemanager(binder服務管家)、bootanim(開機動畫)等重要服務。
init進程孵化出Zygote進程,Zygote進程是Android系統的第一個Java進程(即虛擬機進程),Zygote是所有Java進程的父進程,Zygote進程本身是由init進程孵化而來的。
Framework
Zygote進程,是由init進程通過解析init.rc文件後fork生成的,Zygote進程主要包含:
- 加載ZygoteInit類,註冊Zygote Socket服務端套接字
- 加載虛擬機
- preloadClasses
- preloadResouces
System Server進程,是由Zygote進程fork而來,System Server是Zygote孵化的第一個進程,System Server負責啓動和管理整個Java framework,包含ActivityManager,PowerManager等服務。
Media Server進程,是由init進程fork而來,負責啓動和管理整個C++ framework,包含AudioFlinger,Camera Service,等服務。
App
Zygote進程孵化出的第一個App進程是Launcher,這是用戶看到的桌面App。
Zygote進程還會創建Browser,Phone,Email等App進程,每個App至少運行在一個進程上。
所有的App進程都是由Zygote進程fork生成的。
通信方式
進程/線程之間的通信。
IPC(Inter-Process Communication, 進程間通信)Linux現有管道、消息隊列、共享內存、套接字、信號量、信號這些IPC機制,Android額外還有Binder IPC機制。
Android OS中的Zygote進程的IPC採用的是Socket機制,在上層system server、media server以及上層App之間更多的是採用Binder IPC方式來完成跨進程間的通信。
Handler:對於Android上層架構中,很多時候是在同一個進程的線程之間需要相互通信,例如同一個進程的主線程與工作線程之間的通信,往往採用的Handler消息機制。
Android上層架構,則最常用的通信方式是Binder、Socket、Handler,當然也有少量其他的IPC方式,比如殺進程Process.killProcess()採用的是signal方式。
Binder
現有IPC通訊
- 管道:在創建時分配一個page大小的內存,緩存區大小比較有限。
- 消息隊列:信息複製兩次,額外的CPU消耗;不合適頻繁或信息量大的通信。
- 共享內存:無須複製,共享緩衝區直接付附加到進程虛擬地址空間,速度快;但進程間的同步問題操作系統無法實現,必須各進程利用同步工具解決。
- 套接字:作爲更通用的接口,傳輸效率低,主要用於不通機器或跨網絡的通信。
- 信號量:常作爲一種鎖機制,防止某進程正在訪問共享資源時,其他進程也訪問該資源。因此,主要作爲進程間以及同一進程內不同線程之間的同步手段。
- 信號: 不適用於信息交換,更適用於進程中斷控制,比如非法內存訪問,殺死某個進程等。
Binder分析
- 從性能的角度
數據拷貝次數:Binder數據拷貝只需要一次,而管道、消息隊列、Socket都需要2次,但共享內存方式一次內存拷貝都不需要;從性能角度看,Binder性能僅次於共享內存。 - 從穩定性的角度
Binder是基於C/S架構的 C/S 相對獨立,穩定性較好。
共享內存實現方式複雜,沒有客戶與服務端之別, 需要充分考慮到訪問臨界資源的併發同步問題,否則可能會出現死鎖等問題。 - 從安全的角度
傳統Linux IPC的接收方無法獲得對方進程可靠的UID/PID,從而無法鑑別對方身份。傳統IPC只能由用戶在數據包裏填入UID/PID。可靠的身份標記只有由IPC機制本身在內核中添加。傳統IPC訪問接入點是開放的,無法建立私有通道 - 從語言層面的角度
Linux是基於C語言(面向過程的語言),而Android是基於Java語言(面向對象的語句)
Binder恰恰也符合面向對象的思想 Binder模糊了進程邊界,淡化了進程間通信過程,整個系統彷彿運行於同一個面向對象的程序之中。
Android OS中的Zygote進程的IPC採用的是Socket(套接字)機制,Android中的Kill Process採用的signal(信號)機制等等。而Binder更多則用在system_server進程與上層App層的IPC交互。
Handler
可以詳見handler源碼分析
系統啓動
進程啓動 | 概述 |
---|---|
init進程 | Linux系統中用戶空間的第一個進程, Init.main |
zygote進程 | 所有App進程的父進程, ZygoteInit.main |
system_server進程 | 系統各大服務的載體 |
servicemanager進程 | binder服務的大管家, 守護進程循環運行在binder_loop |
app進程 | 通過Process.start啓動App進程, ActivityThread.main |
AMS
AMS啓動
在system_server進程中啓動
SystemServer.java #startBootstrapServices()
創建AMS實例對象,創建Andoid Runtime,ActivityThread和Context對象
setSystemProcess:註冊AMS、meminfo、cpuinfo等服務到ServiceManager
installSystemProviderss,加載SettingsProvider
啓動SystemUIService,再調用一系列服務的systemReady()方法
發佈Binder服務
服務名 | 類名 | 功能 |
---|---|---|
activity | ActivityManagerService | AMS |
procstats | ProcessStatsService | 進程統計 |
meminfo | MemBinder | 內存 |
gfxinfo | GraphicsBinder | 圖像信息 |
dbinfo | DbBinder | 數據庫 |
cpuinfo | CpuBinder | CPU |
permission | PermissionController | 權限 |
processinfo | ProcessInfoService | 進程服務 |
usagestats | UsageStatsService | 應用使用情況 |
想要查看這些服務的信息,可通過dumpsys <服務名>命令。比如查看CPU信息命令dumpsys cpuinfo
AMS類圖結構
IActivityManager
ActivityManager
ActivityManagerService
以ActivityManager的getRunningServices()函數爲例
public List<RunningServiceInfo> getRunningServices(int maxNum)
throws SecurityException {
try {
return getService()
.getServices(maxNum, 0);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
可以看到,調用被委託到了getService.getServices()。
public static IActivityManager getService() {
return IActivityManagerSingleton.get();
}
實際上調用的是ActivityManagerService中的代碼
@Override
public List<ActivityManager.RunningServiceInfo> getServices(int maxNum, int flags) {
enforceNotIsolatedCaller("getServices");
final int callingUid = Binder.getCallingUid();
final boolean canInteractAcrossUsers = (ActivityManager.checkUidPermission(
INTERACT_ACROSS_USERS_FULL, callingUid) == PERMISSION_GRANTED);
final boolean allowed = mAtmInternal.isGetTasksAllowed("getServices",
Binder.getCallingPid(), callingUid);
synchronized (this) {
return mServices.getRunningServiceInfoLocked(maxNum, flags, callingUid,
allowed, canInteractAcrossUsers);
}
}