==本文為讀書和博客學(xué)習(xí)筆記,記錄將知識總結(jié)自己理解的方式。可能存在錯誤。文末會給出相關(guān)參考鏈接==
1. Android系統(tǒng)概括
1.1 Android系統(tǒng)架構(gòu)整體認識
上圖可以看出,Android系統(tǒng)大致可以分為5層(這個分層是主觀的,并不準確),自頂向下依次介紹。
- 應(yīng)用層(System APP)
這一層主要就是系統(tǒng)APP和非系統(tǒng)APP(也就是開發(fā)者開發(fā)的APP,如抖音,微信等)主要是Kotlin + Java
- 框架層(Java API Framework)
供應(yīng)用層直接調(diào)用的Java API,系統(tǒng)APP和普通開發(fā)者直接調(diào)用的API。如Activity Manager,Package Manager等,具體如下:
應(yīng)用框架層提供的組件
名稱 | 功能描述 |
---|---|
Activity Manager (活動管理器) | 管理各個應(yīng)用程序生命周期,以及常用的導(dǎo)航回退功能 |
Package Manager (包管理器) | 管理所有安裝在 Android 系統(tǒng)中的應(yīng)用程序 |
Notification Manager (通知管理器) | 使得應(yīng)用程序可以在狀態(tài)欄中顯示自定義的提示信息 |
Window Manager (窗口管理器) | 管理所有開啟的窗口程序 |
Resource Manager (資源管理器) | 提供應(yīng)用程序使用的各種非代碼資源,如本地化字符串、圖片、布局文件、顏色文件等 |
- 系統(tǒng)運行庫層(Native)
系統(tǒng)運行庫分成兩部分: 是C/C++程序庫和Android運行時庫。
C/C++程序庫能被Android系統(tǒng)中的不同組件所使用,井通過應(yīng)用程序框架為開發(fā)者提供服務(wù)。
名稱 | 功能描述 |
---|---|
SQ Lite | 輕型關(guān)系型數(shù)據(jù)庫引擎 |
OpenGL ES | 3D繪圖函數(shù)庫 |
更多參考《Android進階解密》 Page.3 表1-2
主要是由C/C++語言編寫,然后Java框架層封裝供應(yīng)用層調(diào)用
運行時庫又分為核心庫和 ART (Android 5.0 系統(tǒng)之后, Dalvik
擬機被 ART 取代)。核心庫提供了Java語言核心庫的大多數(shù)功能,這樣開發(fā)者可以使用 Java語言來編寫Android應(yīng)用。DVM是JVM再Android中虛擬機,每個DVM運行在一個獨立的進程中,避免一個DVM出現(xiàn)錯誤而影響其他進程的應(yīng)用層序。那么也就是說一個程序?qū)?yīng)至少一個進程,和至少一個DVM虛擬機。
ART和DVM的區(qū)別
ART是為了替代DVM而誕生的,DVM采用通過即時編譯器(Just In Time ,JIT )轉(zhuǎn)換為機器碼,也就是每次應(yīng)用程序運行都將經(jīng)過JIT,這會使應(yīng)用程序的運行效率降低。而在ART中,系統(tǒng)在安裝應(yīng)用時會進行一次預(yù)編譯(Ahead Of Time,AOT),將字節(jié)碼預(yù)先編譯成機器碼并存儲在本地,這樣應(yīng)用每次運行時就不需要執(zhí)行編譯了,運行效率也大大提高。
- 硬件抽象層 (HAL)
目的保護硬件知識產(chǎn)權(quán),屏蔽硬件實現(xiàn)細節(jié),提供向上層(Native 層)接口。將控制硬件動作放在硬件抽象層中
- Linux 內(nèi)核層 Linux Kernel)
核心系統(tǒng)服務(wù)在這層中,系統(tǒng)的安全性、內(nèi)存管理、進程管理、網(wǎng)絡(luò)協(xié)議技和驅(qū)動模型等都依賴于該內(nèi)核。
1.2 從開機到init進程啟動
整體進程啟動概述:
Android系統(tǒng)啟動由上到下分別經(jīng)過:Loader -> Kernel -> Native -> Framework -> App
Loader層: 激活Kernel。
- 啟動電源以及系統(tǒng)啟動: 當(dāng)電源按下時引導(dǎo)芯片代碼從預(yù)定義的地方(固化在 ROM)開始執(zhí)行。加載引導(dǎo)程序BootLoader 到RAM中,然后執(zhí)行。
- 引導(dǎo)程序 Bootloader: 引導(dǎo)程序 BootLoader 是在 Android 操作系統(tǒng)開始運行前的 個小程序,它的主要作用是把系統(tǒng) OS 拉起來并運行。
- Linux 內(nèi)核啟動: 當(dāng)內(nèi)核啟動時,設(shè)置緩存、被保護存儲器、計劃列表、加載驅(qū)動。在內(nèi)核完成系統(tǒng)設(shè)置后,它首先在系統(tǒng)文件中尋找 init.rc 文件,井啟動 init 進程。
Kernel層: Android內(nèi)核空間,到這里才剛剛開始進入Android系統(tǒng)。
Bootloader啟動Kernel的swapper進程(pid=0),它是內(nèi)核首個進程,用于初始化進程管理、內(nèi)存管理、加載各種驅(qū)動。更重要的是啟動如下兩個重要進程:
- init進程(pid=1):用戶進程的鼻祖
- threadd進程(pid=2):內(nèi)核進程的鼻祖
這層真正大主管是threadd進程,會創(chuàng)建內(nèi)核工作線程kworkder,軟中斷線程ksoftirqd,thermal等內(nèi)核守護進程。
Native層: 進入用戶空間。 什么是用戶空間與內(nèi)核空間1 什么是用戶空間與內(nèi)核空間2
這層init進程(pid=1)是大主管。它負責(zé)孵化各種系統(tǒng)級服務(wù)、守護進程等。最重要的是孵化出Zygote進程:Java進程的鼻祖。
- Media Server進程:負責(zé)啟動和管理整個C++ framework,包含AudioFlinger,Camera Service等服務(wù)。 什么是AudioFlinger?
Framework層: 在Native之上,也是用戶空間,主要給app層提供api以及系統(tǒng)服務(wù)。
這層大主管是 Zygote進程。它負責(zé)注冊ZygoteSocket服務(wù)端套接字,加載虛擬機,preloadClasses和preloadResouces。
- System Server進程:負責(zé)啟動和管理整個Java framework,包含AMS、WMS、PMS等服務(wù)
App層: 應(yīng)用程序。
所有的App進程都是由Zygote進程fork生成的。
2. Android系統(tǒng)啟動
2.1 init進程
上面提到,在kernel層中通過swapper進程(也稱Idle進程 pid=0)創(chuàng)建init進程,同時進程空間由內(nèi)核態(tài)轉(zhuǎn)到用戶態(tài),init的入口函數(shù)在init.cpp的main函數(shù)中,在init進程啟動后會先執(zhí)行init入口函數(shù)的main方法。
int main(int argc, char** argv) {
...省略
965 if (is_first_stage) {//1
966 boot_clock::time_point start_time = boot_clock::now();
967
968 // Clear the umask.
969 umask(0);
970
971 // Get the basic filesystem setup we need put together in the initramdisk
972 // on / and then we'll let the rc file figure out the rest.
973 mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755");
974 mkdir("/dev/pts", 0755);
975 mkdir("/dev/socket", 0755);
976 mount("devpts", "/dev/pts", "devpts", 0, NULL);
977 #define MAKE_STR(x) __STRING(x)
978 mount("proc", "/proc", "proc", 0, "hidepid=2,gid=" MAKE_STR(AID_READPROC));
979 // Don't expose the raw commandline to unprivileged processes.
980 chmod("/proc/cmdline", 0440);
981 gid_t groups[] = { AID_READPROC };
982 setgroups(arraysize(groups), groups);
983 mount("sysfs", "/sys", "sysfs", 0, NULL);
984 mount("selinuxfs", "/sys/fs/selinux", "selinuxfs", 0, NULL);
985 mknod("/dev/kmsg", S_IFCHR | 0600, makedev(1, 11));
986 mknod("/dev/random", S_IFCHR | 0666, makedev(1, 8));
987 mknod("/dev/urandom", S_IFCHR | 0666, makedev(1, 9));
988
...省略
1026 }
//初始化屬性服務(wù)
1040 property_init();//2
...省略
1068 //創(chuàng)建epoll句柄
1069 epoll_fd = epoll_create1(EPOLL_CLOEXEC);//3
1070 if (epoll_fd == -1) {
1071 PLOG(ERROR) << "epoll_create1 failed";
1072 exit(1);
1073 }
1074 //用于設(shè)置子進程信號處理函數(shù)
1075 signal_handler_init();//4
1076
//啟動屬性服務(wù)
1079 start_property_service();//5
1080 set_usb_controller();
1081
1082 const BuiltinFunctionMap function_map;
1083 Action::set_function_map(&function_map);
1084
1085 Parser& parser = Parser::GetInstance();
1086 parser.AddSectionParser("service",std::make_unique<ServiceParser>());
1087 parser.AddSectionParser("on", std::make_unique<ActionParser>());
1088 parser.AddSectionParser("import", std::make_unique<ImportParser>());
1089 std::string bootscript = GetProperty("ro.boot.init_rc", "");
1090 if (bootscript.empty()) {
//解析init.rc 文件
1091 parser.ParseConfig("/init.rc");//6
1092 parser.set_is_system_etc_init_loaded(
1093 parser.ParseConfig("/system/etc/init"));
1094 parser.set_is_vendor_etc_init_loaded(
1095 parser.ParseConfig("/vendor/etc/init"));
1096 parser.set_is_odm_etc_init_loaded(parser.ParseConfig("/odm/etc/init"));
1097 } else {
1098 parser.ParseConfig(bootscript);
1099 parser.set_is_system_etc_init_loaded(true);
1100 parser.set_is_vendor_etc_init_loaded(true);
1101 parser.set_is_odm_etc_init_loaded(true);
1102 }
1103
...省略
1138
1139 while (true) {
1140 // By default, sleep until something happens.
1141 int epoll_timeout_ms = -1;
1142
1143 if (!(waiting_for_prop || ServiceManager::GetInstance().IsWaitingForExec())) {
1144 am.ExecuteOneCommand();
1145 }
1146 if (!(waiting_for_prop || ServiceManager::GetInstance().IsWaitingForExec())) {
1147 restart_processes();//重啟死去的進程
1148
1149 // If there's a process that needs restarting, wake up in time for that.
1150 if (process_needs_restart_at != 0) {
1151 epoll_timeout_ms = (process_needs_restart_at - time(nullptr)) * 1000;
1152 if (epoll_timeout_ms < 0) epoll_timeout_ms = 0;
1153 }
1154
1155 // If there's more work to do, wake up again immediately.
1156 if (am.HasMoreCommands()) epoll_timeout_ms = 0;
1157 }
1158
1159 epoll_event ev;
1160 int nr = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd, &ev, 1, epoll_timeout_ms));//7
1161 if (nr == -1) {
1162 PLOG(ERROR) << "epoll_wait failed";
1163 } else if (nr == 1) {
1164 ((void (*)()) ev.data.ptr)();
1165 }
1166 }
1167
1168 return 0;
1169}
Part.1 創(chuàng)建和掛在啟動所需的文件目錄
這部分主要有兩個函數(shù)mount()和mkdir()。
- mkdir()主要是創(chuàng)建基本目錄,如mkdir("/dev/pts", 0755);第一個是文件目錄,第二個0755是文件屬性。
- mount() 主要是將文件系統(tǒng)掛載(安裝)到指定目錄
- 創(chuàng)建的文件目錄有/dev、/porc、/sysfc等。
- 文件系統(tǒng)有mpfs、devpt、proc、sysfs等。
這一步的目的就是創(chuàng)建目錄,然后將文件系統(tǒng)掛載到指定的目錄
關(guān)于詳細見Android系統(tǒng)啟動——2init進程-第4部分
Part.2 初始化屬性服務(wù)
首先了解什么是屬性服務(wù)?
屬性服務(wù): 類似Windows中的注冊表,它的作用是采用鍵=值對的方式來記錄用戶,軟件,系統(tǒng)的屬性信息,這樣在系統(tǒng)或是軟件重啟后,依然能夠根據(jù)之前的注冊表中的記錄,進行一些相應(yīng)的初始化工作。
先來了解下屬性服務(wù)有那些特點:
- 在init進程啟動中啟動屬性服務(wù),分配內(nèi)存空間存儲這些屬性。
- 屬性服務(wù)是全局可見的,系統(tǒng)中的所有進程都可以訪問和修改,但是在各個進程在修改時,通過訪問權(quán)限控制,系統(tǒng)中的所有進程想要修改必須要想init進程提出請求,init在接到請求后通過訪問權(quán)限級別決定是否修改
- 屬性服務(wù)的屬性類別有多種,包括:"ro." , "NET. " "ersist." , "ctl." ctl.為控制屬性 其他為普通屬性
關(guān)于屬性服務(wù)更多查看:
- Android屬性系統(tǒng)簡介及使用主要是介紹屬性服務(wù)的概念、優(yōu)缺點、類別和實際形式
了解屬性服務(wù)是什么和有什么用,下面來分析下代碼
property_init() 初始化屬性服務(wù)
68void property_init() {
69 if (__system_property_area_init()) { //1
70 LOG(ERROR) << "Failed to initialize property area";
71 exit(1);
72 }
73}
__system_property_area_init()調(diào)用此方法初始化屬性服務(wù)內(nèi)存區(qū)域,將屬性服務(wù)信息存到這片內(nèi)存中
根據(jù)Android系統(tǒng)啟動-Init篇第五部分將,其中用到mmap()方法
理解mmap()之前先了解內(nèi)存映射文件,如下圖:
文件系統(tǒng)調(diào)用過程
Linux系統(tǒng)分為用戶空間和內(nèi)核空間。文件一般存在物理內(nèi)存上,進程需要訪問文件同時做到進程共享,那么就需要用戶空間進程->訪問內(nèi)核進程->內(nèi)核進程訪問物理內(nèi)存磁盤文件。但是有個問題就是用戶空間進程不能直接使用內(nèi)核空間進程讀取到的文件資源,需要將其copy到自己進程的用戶內(nèi)存空間然后訪問,所以虛擬地址空間(虛擬文件系統(tǒng))誕生,這樣不管是用戶空間的進程還是內(nèi)核空間的進程,他們在自己的進程開辟一塊進程地址空間,里面的地址映射的到虛擬地址空間。這樣無論是內(nèi)核空間還是用戶用戶空間就都可以直接訪問,減少一次copy到自己進程空間在讀取的操作。用戶空間和內(nèi)核空間都有mmap()方法,在用戶空間mmap()就是創(chuàng)建進程地址空間的作用,也就是__system_property_area_init()方法中其中一項工作
參考:概述及使用:
Linux內(nèi)存映射(mmap)
Linux中的mmap映射 [一]
Linux驅(qū)動mmap內(nèi)存映射
Part.3 創(chuàng)建epoll句柄
要理解epoll,首先要簡單了解下Linux中 I/O模式分為那些?具體參考這邊文章的一些概念介紹LinuxIO模式及select、poll、epoll詳解
這里做下自己的概括理解總結(jié):
1. 用戶空間與內(nèi)核空間
現(xiàn)在操作系統(tǒng)都是采用虛擬存儲器,那么對32位操作系統(tǒng)而言,它的尋址空間(虛擬存儲空間)為4G(2的32次方)。操作系統(tǒng)的核心是內(nèi)核,獨立于普通的應(yīng)用程序,可以訪問受保護的內(nèi)存空間,也有訪問底層硬件設(shè)備的所有權(quán)限。為了保證用戶進程不能直接操作內(nèi)核(kernel),保證內(nèi)核的安全,操心系統(tǒng)將虛擬空間劃分為兩部分,一部分為內(nèi)核空間,一部分為用戶空間。針對linux操作系統(tǒng)而言,將最高的1G字節(jié)(從虛擬地址0xC0000000到0xFFFFFFFF),供內(nèi)核使用,稱為內(nèi)核空間,而將較低的3G字節(jié)(從虛擬地址0x00000000到0xBFFFFFFF),供各個進程使用,稱為用戶空間。
2. 文件描述符fd
Linux中多次出現(xiàn)fd這個概念,文件描述符本質(zhì)上是一個索引內(nèi)核中資源地址的一個下標描述,可能指的的Socket,UDP,TCP數(shù)據(jù)包,文件流等可讀寫操作的數(shù)據(jù)。
3. I/O模式
Linux中的I/O模式可能與APP應(yīng)用層不同,APP應(yīng)用層發(fā)生I/O操作,往往指的是同進程下的線程。而Linux中好像貌似沒有線程這個概念,同時發(fā)生發(fā)生數(shù)據(jù)讀寫(也就是要操作fd)時,往往是用戶空間和內(nèi)核空間進程之間的操作,上面也提到,內(nèi)核進程權(quán)限更高,可以訪問更高的級別,那么用戶空間發(fā)起I/O操作最后是交給內(nèi)核去處理的,不管你的讀取硬件設(shè)備(如磁盤)和是Socket,都是用戶空間進程發(fā)起請求給內(nèi)核空間,然后內(nèi)核空間去進行真正的read/write,然后返回給用戶空間。這樣的過程只能給就發(fā)生2中情況
- 用戶空間發(fā)起后是否阻塞 block/non-blocking
- 內(nèi)核空間是否立馬返回數(shù)據(jù) synchronous/asynchronous
相互組合形成4中I/O模式
4. I/O 多路復(fù)用之select、poll、epoll詳解
I/O 多路復(fù)用也是I/O模式的一種,但是不同的是,常規(guī)的一般是一個讀寫操作,而I/O多路復(fù)用可以實現(xiàn)一個進程可以監(jiān)視多個描述符,一旦某個描述符就緒(一般是讀就緒或者寫就緒),能夠通知程序進行相應(yīng)的讀寫操作。但select,poll,epoll本質(zhì)上都是同步I/O,因為他們都需要在讀寫事件就緒后自己負責(zé)進行讀寫,也就是說這個讀寫過程是阻塞的,而異步I/O則無需自己負責(zé)進行讀寫,異步I/O的實現(xiàn)會負責(zé)把數(shù)據(jù)從內(nèi)核拷貝到用戶空間。
select
- 固定的監(jiān)聽數(shù)量(1024個)
- 輪訓(xùn)方式,每次調(diào)用一次select來查看準備就緒的事件 時間復(fù)雜度O(n)
- 兼容好,比較底層,各個平臺系統(tǒng)都支持
poll
select的升級,不限制最大數(shù)量,用鏈表維護文件事件fd
epoll
linux獨有,維護一個隊列(好像是雙向隊列)通過epoll_create(epoll_create1)初始化隊列大小,epoll_ctl()處理事件,epoll_wait()返回可處理事件fd,屬性服務(wù)最后處理的fd就是在這里注冊的fd處理的
具體參考:
相關(guān)知識點全面講解:
Linux IO模式及 select、poll、epoll詳解
三個方法的優(yōu)缺點:細說select、poll和epoll之間的區(qū)別與優(yōu)缺點
簡單通俗的三個知識點的講解:select、poll、epoll、同步、異步、阻塞、非阻塞總結(jié)
Part.4 信號處理
Linux進程通過相互發(fā)送接收消息來實現(xiàn)進程間通信,這些消息被稱為"信號"。每個進程在處理它進程發(fā)送的信號時,都要注冊處理者,處理者被稱為信號處理器。
每個進程在處理其他進程發(fā)送的signal信號時都需要先注冊,當(dāng)進程的運行狀態(tài)改變或終止時會產(chǎn)生某種signal信號,init進程是所有用戶空間進程的父進程,當(dāng)其子進程終止時產(chǎn)生SIGCHLD信號,init進程調(diào)用信號安裝函數(shù)sigaction(),傳遞參數(shù)給sigaction結(jié)構(gòu)體,便完成信號處理的過程。
//定義兩個文件描述符
34static int signal_write_fd = -1;
35static int signal_read_fd = -1;
36
37static void handle_signal() {
38 // Clear outstanding requests.
39 char buf[32];
40 read(signal_read_fd, buf, sizeof(buf));
41
42 ServiceManager::GetInstance().ReapAnyOutstandingChildren();
43}
44
45static void SIGCHLD_handler(int) {
46 if (TEMP_FAILURE_RETRY(write(signal_write_fd, "1", 1)) == -1) {
47 PLOG(ERROR) << "write(signal_write_fd) failed";
48 }
49}
50
51void signal_handler_init() {
52 // Create a signalling mechanism for SIGCHLD.
53 int s[2];
//創(chuàng)建讀寫socket對
54 if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0, s) == -1) {
55 PLOG(ERROR) << "socketpair failed";
56 exit(1);
57 }
58
//通過 讀寫 socket對賦值fd
59 signal_write_fd = s[0];
60 signal_read_fd = s[1];
61
62 // Write to signal_write_fd if we catch SIGCHLD.
//sigaction 處理信號的結(jié)構(gòu)體
63 struct sigaction act;
64 memset(&act, 0, sizeof(act));
65 act.sa_handler = SIGCHLD_handler;
66 act.sa_flags = SA_NOCLDSTOP;
// 調(diào)用信號安裝函數(shù)sigaction(),傳遞參數(shù)給sigaction結(jié)構(gòu)體,便完成信號處理的過程。
67 sigaction(SIGCHLD, &act, 0);
68
69 ServiceManager::GetInstance().ReapAnyOutstandingChildren();
70 //添加到epoll
71 register_epoll_handler(signal_read_fd, handle_signal);
72}
當(dāng)init進程調(diào)用signal_handler_init后,一旦受到子進程終止帶來的SIGCHLD消息后,將利用信號處理者SIGCHLD_handler向signal_write_fd寫入信息;epoll句柄監(jiān)聽到signal_read_fd收到消息后,將調(diào)用handle_signal進行處理。如下圖
Part.5 啟動屬性服務(wù)
666void start_property_service() {
667 property_set("ro.property_service.version", "2");
668 //SOCK_NONBLOCK 創(chuàng)建非阻塞Sokcet 返回fd文件描述符
669 property_set_fd = create_socket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
670 0666, 0, 0, NULL);
671 if (property_set_fd == -1) {
672 PLOG(ERROR) << "start_property_service socket creation failed";
673 exit(1);
674 }
675 //對property_set_fd監(jiān)聽 8表示最多同時處理8個服務(wù)
676 listen(property_set_fd, 8);
677 //handle_property_set_fd 方法處理屬性服務(wù)
678 register_epoll_handler(property_set_fd, handle_property_set_fd);
679}
總結(jié):
- 創(chuàng)建非阻塞Socket,返回fd,這個Socket作為服務(wù)端,一直等待客戶端對屬性服務(wù)操作的事件
- 對fd監(jiān)聽,設(shè)置最大同時能處理8客戶端
- 放入epoll中, 然后調(diào)用handle_property_set_fd方法處理。
Part.6 解析init.rc
init.rc是重要得配置文件,是由Android初始化語言AIL(Android Init Language)編寫得腳本,具體格式和含義參考:
主要參考,內(nèi)容簡潔介紹什么是AIL語言:Init篇
詳細介紹:init.rc解析
總結(jié): AIL有5種類型語句: Action(動作),Command(命令),Service(服務(wù)
),Option(xuan),Improt(導(dǎo)入)
Action:
動作標識了進程執(zhí)行得各個生命周期和對應(yīng)做得做得事情。
Service: 是一個程序,對應(yīng)各一個進程或服務(wù)得啟動。由fork()創(chuàng)建。
Commond: 執(zhí)行的命令
Option: 啟動Services預(yù)設(shè)參數(shù)
Import: 再init.rc 導(dǎo)入其他rc文件
default: 意味著disabled=false,oneshot=false,critical=false。
各個類型得命令可以相互組合使用常常Action與Commond組合使用,Service和Option組合使用:如下:
init.rc是內(nèi)容比較多。也不用專門細研究這個文件,知道他是通過解析這個文件啟動服務(wù)和相應(yīng)的進程(也包括守護進程),其中 ServiceManager(管理IBinder的服務(wù)),Zygote(Java進程的鼻祖),Surfaceflinger(圖像展示服務(wù))。
其中Action和Service都有專門得類進項相應(yīng)的解析:ActionParser和ServiceParser
1) service解析
其中Service->ServiceParser(service.cpp)。 在會調(diào)用如:
877void ServiceManager::AddService(std::unique_ptr<Service> service) {
878 Service* old_service = FindServiceByName(service->name());
879 if (old_service) {
880 LOG(ERROR) << "ignored duplicate definition of service '" << service->name() << "'";
881 return;
882 }
883 services_.emplace_back(std::move(service));//加入鏈表
884}
通過解析Service語句,最后將解析的數(shù)據(jù)封裝到一個service種然后加入鏈表。
2) service啟動
上面提到init.rc中會啟動多個Service。這里以啟動Zygote為例子。
init.rc
在init.rc中
622on nonencrypted
623 class_start main
624 class_start late_start
class_start 是一個COMMAND
表示:class_start <service_class_name>: 啟動屬于同一個class的所有服務(wù);
main表示的Service就是Zygote。對應(yīng)函數(shù)為do_class_start:
builtins.cpp:
129static int do_class_start(const std::vector<std::string>& args) {
130 /* Starting a class does not start services
131 * which are explicitly disabled. They must
132 * be started individually.
133 */
134 ServiceManager::GetInstance().
135 ForEachServiceInClass(args[1], [] (Service* s) { s->StartIfNotDisabled(); });
136 return 0;
137}
ForEachServiceInClass是遍歷上一步的Service鏈表。取出量表中的每個Service
函數(shù)中調(diào)用service.cpp
762bool Service::StartIfNotDisabled() {
763 if (!(flags_ & SVC_DISABLED)) {
764 return Start();
765 } else {
766 flags_ |= SVC_DISABLED_START;
767 }
768 return true;
769}
主要是判斷這個Servcie是否是disabled(表示不隨class自動啟動,只有根據(jù)service名才啟動)
接著調(diào)用start方法:
service.cpp :
bool Service::Start() {
648
649 pid_t pid = -1;//定義pid
650 if (namespace_flags_) {是否沒有啟動
651 pid = clone(nullptr, nullptr, namespace_flags_ | SIGCHLD, nullptr);
652 } else {
653 pid = fork();//創(chuàng)建子進程
654 }
655
656 if (pid == 0) {
657 umask(077);
658
//通過execve函數(shù),啟動Service子進程
721 if (execve(strs[0], (char**) &strs[0], (char**) ENV) < 0) {
722 PLOG(ERROR) << "cannot execve('" << strs[0] << "')";
723 }
724
725 _exit(127);
726 }
757
758 NotifyStateChange("running");
759 return true;
760}
761
關(guān)于fork() 函數(shù)返回值的含義 linux fork()返回值
通過init.rc中
12行:
12 import /init.${ro.zygote}.rc
其中得知會根據(jù)系統(tǒng)加載不同得zygote.rc:
- zygote32
- zygote32_64
- zygote64
- zygote64_32
以zygote64對應(yīng)文件為init.zygote64.rc為例子:
init.zygote64.rc
1 service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server
2 class main
3 priority -20
4 user root
關(guān)于Zygote進程解析得是init.zygote64.rc這個文件,/system/bin/app_process64這個路徑下對用得是app_main.cpp,這樣我們得知當(dāng)service.cpp#start()中調(diào)用execve()函數(shù)啟動子進程,此時就進入app_main.cpp中的mian函數(shù)。
187int main(int argc, char* const argv[])
188{
342
343 if (zygote) {//如果是zygote進程,則啟動zygote
344 runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
345 } else if (className) {
346 runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
347 } else {
348 fprintf(stderr, "Error: no class name or --zygote supplied.\n");
349 app_usage();
350 LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
351 }
352}
至此Zygote進程啟動。
Zygote啟動流程
init進程啟動總結(jié):
( 1 ) 創(chuàng)建和掛載啟動所需的文件目錄。
( 2 )初始化和啟動屬性服務(wù)。
( 3 )解析 init.rc 配置文件并啟動 Zygote 進程。
參考:
《Android進階解密》
什么是用戶空間與內(nèi)核空間1
Android系統(tǒng)啟動——2init進程-第4部分
Linux內(nèi)存映射(mmap)
Linux中的mmap映射 [一]
Linux驅(qū)動mmap內(nèi)存映射
LinuxIO模式及select、poll、epoll詳解
Linux IO模式及 select、poll、epoll詳解
細說select、poll和epoll之間的區(qū)別與優(yōu)缺點
select、poll、epoll、同步、異步、阻塞、非阻塞總結(jié)