讀書筆記--Android系統(tǒng)啟動

==本文為讀書和博客學(xué)習(xí)筆記,記錄將知識總結(jié)自己理解的方式。可能存在錯誤。文末會給出相關(guān)參考鏈接==

1. Android系統(tǒng)概括

1.1 Android系統(tǒng)架構(gòu)整體認識

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)用程序使用的各種非代碼資源,如本地化字符串、圖片、布局文件、顏色文件等

更多參考《Android進階解密》 Page.2 表1-1

  • 系統(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進程啟動

整體進程啟動概述:

image

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方法。

init.cpp

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ù)更多查看

了解屬性服務(wù)是什么和有什么用,下面來分析下代碼

property_init() 初始化屬性服務(wù)

property_service.cpp

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

  1. 固定的監(jiān)聽數(shù)量(1024個)
  2. 輪訓(xùn)方式,每次調(diào)用一次select來查看準備就緒的事件 時間復(fù)雜度O(n)
  3. 兼容好,比較底層,各個平臺系統(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é):

  1. 創(chuàng)建非阻塞Socket,返回fd,這個Socket作為服務(wù)端,一直等待客戶端對屬性服務(wù)操作的事件
  2. 對fd監(jiān)聽,設(shè)置最大同時能處理8客戶端
  3. 放入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組合使用:如下:

Android進階解密.png

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進程啟動Zygote

init進程啟動總結(jié):
( 1 ) 創(chuàng)建和掛載啟動所需的文件目錄。
( 2 )初始化和啟動屬性服務(wù)。
( 3 )解析 init.rc 配置文件并啟動 Zygote 進程。

參考:
《Android進階解密》
什么是用戶空間與內(nèi)核空間1

什么是用戶空間與內(nèi)核空間2

Android系統(tǒng)啟動——2init進程-第4部分

android的surfaceflinger原理講解

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é)

linux fork()返回值

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。