日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > windows >内容正文

windows

系统进程启动流程分析(一)

發布時間:2024/1/8 windows 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 系统进程启动流程分析(一) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Android啟動概覽
眾所周知,Android是谷歌開發的一款基于Linux的開源操作系統,下圖所示為 Android 平臺的主要組件

1. Linux 內核
Android 平臺的基礎是 Linux 內核。例如,Android Runtime (ART) 依靠 Linux 內核來執行底層功

能,例如線程和低層內存管理。
使用 Linux 內核可讓 Android 利用主要安全功能,并且允許設備制造商為著名的內核開發硬件驅動程
序。
2. 硬件抽象層 (HAL)
硬件抽象層 (HAL) 提供標準界面,向更高級別的 Java API 框架顯示設備硬件功能。HAL 包含多個
庫模塊,其中每個模塊都為特定類型的硬件組件實現一個界面,例如相機或藍牙模塊。當框架 API
要求訪問設備硬件時,Android 系統將為該硬件組件加載庫模塊。
3. Android Runtime
對于運行 Android 5.0(API 級別 21)或更高版本的設備,每個應用都在其自己的進程中運行,并
且有其自己的 Android Runtime (ART) 實例。ART 編寫為通過執行 DEX 文件在低內存設備上運行
多個虛擬機,DEX 文件是一種專為 Android 設計的字節碼格式,經過優化,使用的內存很少。編
譯工具鏈(例如 Jack)將 Java 源代碼編譯為 DEX 字節碼,使其可在 Android 平臺上運行。
ART 的部分主要功能包括:
預先 (AOT) 和即時 (JIT) 編譯
優化的垃圾回收 (GC)
在 Android 9(API 級別 28)及更高版本的系統中,支持將應用軟件包中的 Dalvik Executable 格
式 (DEX) 文件轉換為更緊湊的機器代碼。
更好的調試支持,包括專用采樣分析器、詳細的診斷異常和崩潰報告,并且能夠設置觀察點以監控
特定字段
在 Android 版本 5.0(API 級別 21)之前,Dalvik 是 Android Runtime。如果您的應用在 ART 上
運行效果很好,那么它應該也可在 Dalvik 上運行,但反過來不一定。
Android 還包含一套核心運行時庫,可提供 Java API 框架所使用的 Java 編程語言中的大部分功能,包括
一些 Java 8 語言功能。
4. 原生 C/C++ 庫
許多核心 Android 系統組件和服務(例如 ART 和 HAL)構建自原生代碼,需要以 C 和 C++ 編寫的
原生庫。Android 平臺提供 Java 框架 API 以向應用顯示其中部分原生庫的功能。例如,您可以通
過 Android 框架的 Java OpenGL API 訪問 OpenGL ES,以支持在應用中繪制和操作 2D 和 3D 圖形。
如果開發的是需要 C 或 C++ 代碼的應用,可以使用 Android NDK 直接從原生代碼訪問某些原生平臺庫。

5. Java API 框架
您可通過以 Java 語言編寫的 API 使用 Android OS 的整個功能集。這些 API 形成創建 Android 應
用所需的構建塊,它們可簡化核心模塊化系統組件和服務的重復使用,包括以下組件和服務:
豐富、可擴展的視圖系統,可用以構建應用的 UI,包括列表、網格、文本框、按鈕甚至可嵌入的網
絡瀏覽器
資源管理器,用于訪問非代碼資源,例如本地化的字符串、圖形和布局文件
通知管理器,可讓所有應用在狀態欄中顯示自定義提醒
Activity 管理器,用于管理應用的生命周期,提供常見的導航返回棧
內容提供程序,可讓應用訪問其他應用(例如“聯系人”應用)中的數據或者共享其自己的數據
開發者可以完全訪問 Android 系統應用使用的框架 API。
6. 系統應用
Android 隨附一套用于電子郵件、短信、日歷、互聯網瀏覽和聯系人等的核心應用。平臺隨附的應
用與用戶可以選擇安裝的應用一樣,沒有特殊狀態。因此第三方應用可成為用戶的默認網絡瀏覽
器、短信 Messenger 甚至默認鍵盤(有一些例外,例如系統的“設置”應用)。
系統應用可用作用戶的應用,以及提供開發者可從其自己的應用訪問的主要功能。例如,如果您的應用
要發短信,您無需自己構建該功能,可以改為調用已安裝的短信應用向您指定的接收者發送消息。

接下來,我們來看下Android系統啟動的大概流程,如下圖所示:

第一步: 啟動電源以及系統啟動

當電源按下,引導芯片代碼開始從預定義的地方(固化在ROM)開始執行。加載引導程序到RAM,然后
執行

第二步:引導程序
引導程序是在Android操作系統開始運行前的一個小程序。引導程序是運行的第一個程序,因此它是針
對特定的主板與芯片的。設備制造商要么使用很受歡迎的引導程序比如redboot、uboot、qi
bootloader或者開發自己的引導程序,它不是Android操作系統的一部分。引導程序是OEM廠商或者運
營商加鎖和限制的地方。
引導程序分兩個階段執行。
第一個階段,檢測外部的RAM以及加載對第二階段有用的程序;
第二階段,引導程序設置網絡、內存等等。這些對于運行內核是必要的,為了達到特殊的目標,引導程
序可以根據配置參數或者輸入數據設置內核。
Android引導程序可以在\bootable\bootloader\legacy\usbloader找到。傳統的加載器包含兩個文件,
需要在這里說明:
init.s初始化堆棧,清零BBS段,調用main.c的_main()函數;
main.c初始化硬件(鬧鐘、主板、鍵盤、控制臺),創建linux標簽

第三步:內核

Android內核與桌面linux內核啟動的方式差不多。內核啟動時,設置緩存、被保護存儲器、計劃列表,
加載驅動。當內核完成系統設置,它首先在系統文件中尋找”init”文件,然后啟動root進程或者系統的第
一個進程
第四步:init進程
init進程是Linux系統中用戶空間的第一個進程,進程號固定為1。Kernel啟動后,在用戶空間啟動init進
程,并調用init中的main()方法執行init進程的職責。
第五步:啟動Lancher App

init進程分析
其中init進程是Android系統中及其重要的第一個進程,接下來我們來看下init進程注意做了些什么
1. 創建和掛載啟動所需要的文件目錄
2. 初始化和啟動屬性服務
3. 解析init.rc配置文件并啟動Zygote進程

// \system\core\init\init.cpp main() L545 /* * 1.C++中主函數有兩個參數,第一個參數argc表示參數個數,第二個參數是參數列表,也就是具體 的參數 * 2.init的main函數有兩個其它入口,一是參數中有ueventd,進入ueventd_main,二是參數中 有watchdogd,進入watchdogd_main */ int main(int argc, char** argv) { /** 1.strcmp是String的一個函數,比較字符串,相等返回0* 2.C++中0也可以表示false* 3.basename是C庫中的一個函數,得到特定的路徑中的最后一個'/'后面的內容,* 比如/sdcard/miui_recovery/backup,得到的結果是backup*/if (!strcmp(basename(argv[0]), "ueventd")) {//當argv[0]的內容為ueventd 時,strcmp的值為0,!strcmp為1 //1表示true,也就執行ueventd_main,ueventd主要是負責設備節點的創建、權限設定等一 些列工作return ueventd_main(argc, argv);}if (!strcmp(basename(argv[0]), "watchdogd")) {//watchdogd俗稱看門狗,用于 系統出問題時重啟系統return watchdogd_main(argc, argv);}if (argc > 1 && !strcmp(argv[1], "subcontext")) {InitKernelLogging(argv);const BuiltinFunctionMap function_map;return SubcontextMain(argc, argv, &function_map);}if (REBOOT_BOOTLOADER_ON_PANIC) {InstallRebootSignalHandlers();//初始化重啟系統的處理信號,內部通過 sigaction 注冊信號,當監聽到該信號時重啟系統}bool is_first_stage = (getenv("INIT_SECOND_STAGE") == nullptr);//查看是 否有環境變量INIT_SECOND_STAGE/** 1.init的main方法會執行兩次,由is_first_stage控制,first_stage就是第一階段要 做的事*/if (is_first_stage) {boot_clock::time_point start_time = boot_clock::now();// Clear the umask.umask(0);//清空文件權限clearenv();setenv("PATH", _PATH_DEFPATH, 1);// Get the basic filesystem setup we need put together in the initramdisk// on / and then we'll let the rc file figure out the rest. //mount是用來掛載文件系統的,mount屬于Linux系統調用mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755");mkdir("/dev/pts", 0755);//創建目錄,第一個參數是目錄路徑,第二個是讀寫權限mkdir("/dev/socket", 0755);mount("devpts", "/dev/pts", "devpts", 0, NULL);#define MAKE_STR(x) __STRING(x)mount("proc", "/proc", "proc", 0, "hidepid=2,gid=" MAKE_STR(AID_READPROC));// Don't expose the raw commandline to unprivileged processes.chmod("/proc/cmdline", 0440);//用于修改文件/目錄的讀寫權限gid_t groups[] = { AID_READPROC };setgroups(arraysize(groups), groups);// 用來將list 數組中所標明的組加入 到目前進程的組設置中mount("sysfs", "/sys", "sysfs", 0, NULL);mount("selinuxfs", "/sys/fs/selinux", "selinuxfs", 0, NULL); //mknod用于創建Linux中的設備文件mknod("/dev/kmsg", S_IFCHR | 0600, makedev(1, 11));if constexpr (WORLD_WRITABLE_KMSG) {mknod("/dev/kmsg_debug", S_IFCHR | 0622, makedev(1, 11));}mknod("/dev/random", S_IFCHR | 0666, makedev(1, 8));mknod("/dev/urandom", S_IFCHR | 0666, makedev(1, 9));// Mount staging areas for devices managed by vold// See storage config details at http://source.android.com/devices/storage/mount("tmpfs", "/mnt", "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV,"mode=0755,uid=0,gid=1000");// /mnt/vendor is used to mount vendor-specific partitions that can not be// part of the vendor partition, e.g. because they are mounted read-write.mkdir("/mnt/vendor", 0755);// Now that tmpfs is mounted on /dev and we have /dev/kmsg, we can actually// talk to the outside world...InitKernelLogging(argv);//將標準輸入輸出重定向到"/sys/fs/selinux/null"LOG(INFO) << "init first stage started!";if (!DoFirstStageMount()) {LOG(FATAL) << "Failed to mount required partitions early ...";}//Avb即Android Verfied boot,功能包括Secure Boot, verfying boot 和 dm- verity,//原理都是對二進制文件進行簽名,在系統啟動時進行認證,確保系統運行的是合法的二進 制鏡像文件。//其中認證的范圍涵蓋:bootloader,boot.img,system.imgSetInitAvbVersionInRecovery();//在刷機模式下初始化avb的版本,不是刷機模式 直接跳過// Enable seccomp if global boot option was passed (otherwise it is enabled in zygote).global_seccomp();// Set up SELinux, loading the SELinux policy.SelinuxSetupKernelLogging();SelinuxInitialize();//加載SELinux policy,也就是安全策略,// We're in the kernel domain, so re-exec init to transition to the init domain now// that the SELinux policy has been loaded. /** 1.這句英文大概意思是,我們執行第一遍時是在kernel domain,所以要重新執行 init文件,切換到init domain,* 這樣SELinux policy才已經加載進來了* 2.后面的security_failure函數會調用panic重啟系統*/if (selinux_android_restorecon("/init", 0) == -1) {PLOG(FATAL) << "restorecon failed of /init failed";}setenv("INIT_SECOND_STAGE", "true", 1);static constexpr uint32_t kNanosecondsPerMillisecond = 1e6;uint64_t start_ms = start_time.time_since_epoch().count() / kNanosecondsPerMillisecond;setenv("INIT_STARTED_AT", std::to_string(start_ms).c_str(), 1);char* path = argv[0];char* args[] = { path, nullptr };execv(path, args);//重新執行main方法,進入第二階段// execv() only returns if an error happened, in which case we// panic and never fall through this conditional.PLOG(FATAL) << "execv(\"" << path << "\") failed";}// At this point we're in the second stage of init.InitKernelLogging(argv);LOG(INFO) << "init second stage started!";// Set up a session keyring that all processes will have access to. It// will hold things like FBE encryption keys. No process should override// its session keyring.keyctl_get_keyring_ID(KEY_SPEC_SESSION_KEYRING, 1);// Indicate that booting is in progress to background fw loaders, etc.close(open("/dev/.booting", O_WRONLY | O_CREAT | O_CLOEXEC, 0000));property_init();//初始化屬性系統,并從指定文件讀取屬性// If arguments are passed both on the command line and in DT,// properties set in DT always have priority over the command-line ones. //接下來的一系列操作都是從各個文件讀取一些屬性,然后通過property_set設置系統屬性// If arguments are passed both on the command line and in DT,// properties set in DT always have priority over the command-line ones./** 1.這句英文的大概意思是,如果參數同時從命令行和DT傳過來,DT的優先級總是大于命令行 的* 2.DT即device-tree,中文意思是設備樹,這里面記錄自己的硬件配置和系統運行參數,參 考http://www.wowotech.net/linux_kenrel/why-dt.html*/process_kernel_dt();//處理DT屬性process_kernel_cmdline();//處理命令行屬性// Propagate the kernel variables to internal variables// used by init as well as the current required properties.export_kernel_boot_props();//處理其他的一些屬性// Make the time that init started available for bootstat to log.property_set("ro.boottime.init", getenv("INIT_STARTED_AT"));property_set("ro.boottime.init.selinux", getenv("INIT_SELINUX_TOOK"));// Set libavb version for Framework-only OTA match in Treble build.const char* avb_version = getenv("INIT_AVB_VERSION");if (avb_version) property_set("ro.boot.avb_version", avb_version);// Clean up our environment.unsetenv("INIT_SECOND_STAGE");//清空這些環境變量,因為之前都已經存入到系統屬性 中去了unsetenv("INIT_STARTED_AT");unsetenv("INIT_SELINUX_TOOK");unsetenv("INIT_AVB_VERSION");// Now set up SELinux for second stage.SelinuxSetupKernelLogging();SelabelInitialize();SelinuxRestoreContext();epoll_fd = epoll_create1(EPOLL_CLOEXEC);//創建epoll實例,并返回epoll的文件 描述符if (epoll_fd == -1) {PLOG(FATAL) << "epoll_create1 failed";}sigchld_handler_init();//主要是創建handler處理子進程終止信號,創建一個匿名 socket并注冊到epoll進行監聽if (!IsRebootCapable()) {// If init does not have the CAP_SYS_BOOT capability, it is running in a container.// In that case, receiving SIGTERM will cause the system to shut down.InstallSigtermHandler();}property_load_boot_defaults();//從文件中加載一些屬性,讀取usb配置export_oem_lock_status();//設置ro.boot.flash.locked 屬性start_property_service();//開啟一個socket監聽系統屬性的設置set_usb_controller();//設置sys.usb.controller 屬性const BuiltinFunctionMap function_map;//方法映射 “class_start”-> "do_class_start" /** 1.C++中::表示靜態方法調用,相當于java中static的方法*/Action::set_function_map(&function_map);//將function_map存放到Action中作 為成員屬性subcontexts = InitializeSubcontexts();ActionManager& am = ActionManager::GetInstance();ServiceList& sm = ServiceList::GetInstance();LoadBootScripts(am, sm);//解析xxx.rc// Turning this on and letting the INFO logging be discarded adds 0.2s to// Nexus 9 boot time, so it's disabled by default.if (false) DumpState();//打印一些當前Parser的信息,默認是不執行的am.QueueEventTrigger("early-init");//QueueEventTrigger用于觸發Action,這里 觸發 early-init事件// Queue an action that waits for coldboot done so we know ueventd has set up all of /dev...am.QueueBuiltinAction(wait_for_coldboot_done_action, "wait_for_coldboot_done");//QueueBuiltinAction用于添加Action,第一個參數是 Action要執行的Command,第二個是Trigger// ... so that we can start queuing up actions that require stuff from /dev.am.QueueBuiltinAction(MixHwrngIntoLinuxRngAction, "MixHwrngIntoLinuxRng");am.QueueBuiltinAction(SetMmapRndBitsAction, "SetMmapRndBits");am.QueueBuiltinAction(SetKptrRestrictAction, "SetKptrRestrict");am.QueueBuiltinAction(keychord_init_action, "keychord_init");am.QueueBuiltinAction(console_init_action, "console_init");// Trigger all the boot actions to get us started.am.QueueEventTrigger("init");// Repeat mix_hwrng_into_linux_rng in case /dev/hw_random or /dev/random// wasn't ready immediately after wait_for_coldboot_doneam.QueueBuiltinAction(MixHwrngIntoLinuxRngAction, "MixHwrngIntoLinuxRng");// Don't mount filesystems or start core system services in charger mode.std::string bootmode = GetProperty("ro.bootmode", "");if (bootmode == "charger") {am.QueueEventTrigger("charger");} else {am.QueueEventTrigger("late-init");}// Run all property triggers based on current state of the properties.am.QueueBuiltinAction(queue_property_triggers_action, "queue_property_triggers");while (true) {// By default, sleep until something happens.int epoll_timeout_ms = -1; //epoll超時時間,相當于阻塞時間if (do_shutdown && !shutting_down) {do_shutdown = false;if (HandlePowerctlMessage(shutdown_command)) {shutting_down = true;}}if (!(waiting_for_prop || Service::is_exec_service_running())) {am.ExecuteOneCommand();//執行一個command} /** 1.waiting_for_prop和IsWaitingForExec都是判斷一個Timer為不為空,相當 于一個標志位* 2.waiting_for_prop負責屬性設置,IsWaitingForExe負責service運行* 3.當有屬性設置或Service開始運行時,這兩個值就不為空,直到執行完畢才置為空* 4.其實這兩個判斷條件主要作用就是保證屬性設置和service啟動的完整性,也可以 說是為了同步*/if (!(waiting_for_prop || Service::is_exec_service_running())) {if (!shutting_down) {auto next_process_restart_time = RestartProcesses();//重啟服 務// If there's a process that needs restarting, wake up in time for that.if (next_process_restart_time) {epoll_timeout_ms = std::chrono::ceil<std::chrono::milliseconds>(*next_process_restart_time - boot_clock::now()).count();if (epoll_timeout_ms < 0) epoll_timeout_ms = 0;}}// If there's more work to do, wake up again immediately.if (am.HasMoreCommands()) epoll_timeout_ms = 0;//當還有命令要執行 時,將epoll_timeout_ms設置為0}epoll_event ev; /** 1.epoll_wait與epoll_create1、epoll_ctl是一起使用的* 2.epoll_create1用于創建epoll的文件描述符,epoll_ctl、epoll_wait都把它 創建的fd作為第一個參數傳入* 3.epoll_ctl用于操作epoll,EPOLL_CTL_ADD:注冊新的fd到epfd中, EPOLL_CTL_MOD:修改已經注冊的fd的監聽事件,EPOLL_CTL_DEL:從epfd中刪除一個fd;* 4.epoll_wait用于等待事件的產生,epoll_ctl調用EPOLL_CTL_ADD時會傳入需要 監聽什么類型的事件,* ?比如EPOLLIN表示監聽fd可讀,當該fd有可讀的數據時,調用epoll_wait經過 epoll_timeout_ms時間就會把該事件的信息返回給&ev*/int nr = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd, &ev, 1, epoll_timeout_ms));if (nr == -1) {PLOG(ERROR) << "epoll_wait failed";} else if (nr == 1) {((void (*)()) ev.data.ptr)();//當有event返回時,取出 ev.data.ptr(之前epoll_ctl注冊時的回調函數),直接執行 //在signal_handler_init和start_property_service有注冊兩個fd的監 聽,一個用于監聽SIGCHLD(子進程結束信號),一個用于監聽屬性設置}}return 0; }

init.rc解析
init.rc是一個非常重要的配置文件,它是由Android初始化語言(Android Init Language)編寫的腳
本,它主要包含五種類型語句:Action(Action中包含了一系列的Command)、Commands(init語言
中的命令)、Services(由init進程啟動的服務)、Options(對服務進行配置的選項)和Import(引入
其他配置文件)。init.rc的配置代碼如下所示。

# \system\core\rootdir\init.rc on init # L41sysclktz 0# Mix device-specific information into the entropy poolcopy /proc/cmdline /dev/urandomcopy /default.prop /dev/urandom... on <trigger> [&& <trigger>]* //設置觸發器<command><command> //動作觸發之后要執行的命令service <name> <pathname> [ <argument> ]* //<service的名字><執行程序路徑><傳遞參 數><option> //Options是Services的參數配置. 它們影響Service如何運行及運行時機group <groupname> [ <groupname>\* ] //在啟動Service前將group改為第一個 groupname,第一個groupname是必須有的,//默認值為root(或許默認值是無),第二個groupname可以不設置,用于追加組(通過 setgroups)priority <priority> //設置進程優先級. 在-20~19之間,默認值是0,能過 setpriority實現socket <name> <type> <perm> [ <user> [ <group> [ <seclabel> ] ] ]//創建 一個unix域的socket,名字叫/dev/socket/name , 并將fd返回給Service. type 只能是 "dgram", "stream" or "seqpacket".... ?

Action
Action: 通過觸發器trigger,即以on開頭的語句來決定執行相應的service的時機,具體有如下時機:

  • on early-init; 在初始化早期階段觸發;
  • on init; 在初始化階段觸發;
  • on late-init; 在初始化晚期階段觸發;
  • on boot/charger: 當系統啟動/充電時觸發,還包含其他情況,此處不一一列舉;
  • on property:=: 當屬性值滿足條件時觸發

Service
服務Service,以 service開頭,由init進程啟動,一般運行在init的一個子進程,所以啟動service前需要
判斷對應的可執行文件是否存在。init生成的子進程,定義在rc文件,其中每一個service在啟動時會通過
fork方式生成子進程。
例如: ?service servicemanager /system/bin/servicemanager 代表的是服務名為
servicemanager,服務執行的路徑為/system/bin/servicemanager。

Command
下面列舉常用的命令

  • class_start <service_class_name>: 啟動屬于同一個class的所有服務;
  • start <service_name>: 啟動指定的服務,若已啟動則跳過;
  • stop <service_name>: 停止正在運行的服務
  • setprop :設置屬性值
  • mkdir :創建指定目錄
  • symlink <sym_link>: 創建連接到的<sym_link>符號鏈接;
  • write : 向文件path中寫入字符串;
  • exec: fork并執行,會阻塞init進程直到程序完畢;
  • exprot :設定環境變量;
  • loglevel :設置log級別

Options
Options是Service的可選項,與service配合使用

  • disabled: 不隨class自動啟動,只有根據service名才啟動;
  • oneshot: service退出后不再重啟;
  • user/group: 設置執行服務的用戶/用戶組,默認都是root;
  • class:設置所屬的類名,當所屬類啟動/退出時,服務也啟動/停止,默認為default;
  • onrestart:當服務重啟時執行相應命令;
  • socket: 創建名為 /dev/socket/<name> 的socket
  • critical: 在規定時間內該service不斷重啟,則系統會重啟并進入恢復模式

default: 意味著disabled=false,oneshot=false,critical=false。

service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote -- start-system-serverclass mainpriority -20user rootgroup root readproc reserved_disksocket zygote stream 660 root systemonrestart write /sys/android_power/request_state wakeonrestart write /sys/power/state ononrestart restart audioserveronrestart restart cameraserveronrestart restart mediaonrestart restart netdonrestart restart wificondwritepid /dev/cpuset/foreground/tasks

service解析流程

// \system\core\init\init.cpp LoadBootScripts() L110 static void LoadBootScripts(ActionManager& action_manager, ServiceList& service_list) {Parser parser = CreateParser(action_manager, service_list);//創建解析器std::string bootscript = GetProperty("ro.boot.init_rc", "");if (bootscript.empty()) {parser.ParseConfig("/init.rc");if (!parser.ParseConfig("/system/etc/init")) {late_import_paths.emplace_back("/system/etc/init");}if (!parser.ParseConfig("/product/etc/init")) {late_import_paths.emplace_back("/product/etc/init");}if (!parser.ParseConfig("/odm/etc/init")) {late_import_paths.emplace_back("/odm/etc/init");}if (!parser.ParseConfig("/vendor/etc/init")) {late_import_paths.emplace_back("/vendor/etc/init");}} else {parser.ParseConfig(bootscript);//開始解析} // \system\core\init\init.cpp CreateParser() L100 Parser CreateParser(ActionManager& action_manager, ServiceList& service_list) {Parser parser;parser.AddSectionParser("service", std::make_unique<ServiceParser> (&service_list, subcontexts));//service解析parser.AddSectionParser("on", std::make_unique<ActionParser> (&action_manager, subcontexts));parser.AddSectionParser("import", std::make_unique<ImportParser> (&parser));return parser; } // \system\core\init\parser.cpp ParseData() L 42 void Parser::ParseData(const std::string& filename, const std::string& data, size_t* parse_errors) {...for (;;) {switch (next_token(&state)) {case T_EOF:end_section();return;case T_NEWLINE:...if (section_parsers_.count(args[0])) {end_section();section_parser = section_parsers_[args[0]].get();section_start_line = state.line;if (auto result =section_parser->ParseSection(std::move(args), filename, state.line);// L95!result) {(*parse_errors)++;LOG(ERROR) << filename << ": " << state.line << ": " << result.error();section_parser = nullptr;}} else if (section_parser) {if (auto result = section_parser- >ParseLineSection(std::move(args), state.line);// L102!result) {(*parse_errors)++;LOG(ERROR) << filename << ": " << state.line << ": " << result.error();}}args.clear();break;case T_TEXT:args.emplace_back(state.text);break;}} } // \system\core\init\service.cpp ParseSection() L1180 Result<Success> ServiceParser::ParseSection(std::vector<std::string>&& args,const std::string& filename, int line) {if (args.size() < 3) {return Error() << "services must have a name and a program";}const std::string& name = args[1];if (!IsValidName(name)) {return Error() << "invalid service name '" << name << "'";}Subcontext* restart_action_subcontext = nullptr;if (subcontexts_) {for (auto& subcontext : *subcontexts_) {if (StartsWith(filename, subcontext.path_prefix())) {restart_action_subcontext = &subcontext;break;}}}std::vector<std::string> str_args(args.begin() + 2, args.end());service_ = std::make_unique<Service>(name, restart_action_subcontext, str_args);//構建出一個service對象return Success(); } // \system\core\init\service.cpp ParseLineSection() L1206 Result<Success> ServiceParser::ParseLineSection(std::vector<std::string>&& args, int line) {return service_ ? service_->ParseLine(std::move(args)) : Success(); } // \system\core\init\service.cpp EndSection() L1210 Result<Success> ServiceParser::EndSection() {if (service_) {Service* old_service = service_list_->FindService(service_->name());if (old_service) {if (!service_->is_override()) {return Error() << "ignored duplicate definition of service '" << service_->name()<< "'";}service_list_->RemoveService(*old_service);old_service = nullptr;}service_list_->AddService(std::move(service_)); }return Success(); } // \system\core\init\service.cpp AddService() L1082 void ServiceList::AddService(std::unique_ptr<Service> service) {services_.emplace_back(std::move(service)); } 上面解析完成后,接下來就是啟動Service,這里我們以啟動Zygote來分析 # \system\core\rootdir\init.rc L680 on nonencryptedclass_start main //class_start是一個命令,通過do_class_start函數處理class_start late_start // \system\core\init\builtins..cpp do_class_start() L101 static Result<Success> do_class_start(const BuiltinArguments& args) {// Starting a class does not start services which are explicitly disabled.// They must be started individually.for (const auto& service : ServiceList::GetInstance()) {if (service->classnames().count(args[1])) {if (auto result = service->StartIfNotDisabled(); !result) {LOG(ERROR) << "Could not start service '" << service->name()<< "' as part of class '" << args[1] << "': " << result.error();}}}return Success(); } // \system\core\init\service.cpp StartIfNotDisabled() L977 Result<Success> Service::StartIfNotDisabled() {if (!(flags_ & SVC_DISABLED)) {return Start();} else {flags_ |= SVC_DISABLED_START;}return Success(); } // \system\core\init\service.cpp Start() L785 Result<Success> Service::Start() {//如果service已經運行,則不啟動if (flags_ & SVC_RUNNING) {if ((flags_ & SVC_ONESHOT) && disabled) {flags_ |= SVC_RESTART;}// It is not an error to try to start a service that is already running.return Success(); }...//判斷需要啟動的service的對應的執行文件是否存在,不存在則不啟動servicestruct stat sb;if (stat(args_[0].c_str(), &sb) == -1) {flags_ |= SVC_DISABLED;return ErrnoError() << "Cannot find '" << args_[0] << "'";}std::string scon;if (!seclabel_.empty()) {scon = seclabel_;} else {auto result = ComputeContextFromExecutable(args_[0]);if (!result) {return result.error();}scon = *result;}LOG(INFO) << "starting service '" << name_ << "'...";//如果子進程沒有啟動,則調用fork函數創建子進程pid_t pid = -1;if (namespace_flags_) {pid = clone(nullptr, nullptr, namespace_flags_ | SIGCHLD, nullptr);} else {pid = fork();}if (pid == 0) {//當期代碼邏輯在子進程中運行umask(077);//調用execv函數,啟動sevice子進程if (!ExpandArgsAndExecv(args_)) {PLOG(ERROR) << "cannot execve('" << args_[0] << "')";}_exit(127);}return Success(); }

Zygote概敘
Zygote中文翻譯為“受精卵”,正如其名,它主要用于孵化子進程。在Android系統中有以下兩種程序:
java應用程序,主要基于ART虛擬機,所有的應用程序apk都屬于這類native程序,也就是利用C或C++語
言開發的程序,如bootanimation。所有的Java應用程序進程及系統服務SystemServer進程都由Zygote
進程通過Linux的fork()函數孵化出來的,這也就是為什么把它稱為Zygote的原因,因為他就像一個受精
卵,孵化出無數子進程,而native程序則由Init程序創建啟動。Zygote進程最初的名字不是“zygote”而是
“app_process”,這個名字是在Android.mk文件中定義的
Zgyote是Android中的第一個art虛擬機,他通過socket的方式與其他進程進行通信。這里的“其他進程”
其實主要是系統進程——SystemServer

Zygote是一個C/S模型,Zygote進程作為服務端,它主要負責創建Java虛擬機,加載系統資源,啟
動SystemServer進程,以及在后續運行過程中啟動普通的應用程序,其他進程作為客戶端向它發
出“孵化”請求,而Zygote接收到這個請求后就“孵化”出一個新的進程。比如,當點擊Launcher里的
應用程序圖標去啟動一個新的應用程序進程時,這個請求會到達框架層的核心服務
ActivityManagerService中,當AMS收到這個請求后,它通過調用Process類發出一個“孵化”子進
程的Socket請求,而Zygote監聽到這個請求后就立刻fork一個新的進程出來

Zygote觸發過程
1. init.zygoteXX.rc

import /init.${ro.zygote}.rc

${ro.zygote} 會被替換成 ro.zyogte 的屬性值,這個是由不同的硬件廠商自己定制的,
有四個值,
zygote32: zygote 進程對應的執行程序是 app_process (純 32bit 模式)
zygote64: zygote 進程對應的執行程序是 app_process64 (純 64bit 模式)
zygote32_64: 啟動兩個 zygote 進程 (名為 zygote 和 zygote_secondary),對應的執行程序分別
是 app_process32 (主模式)
zygote64_32: 啟動兩個 zygote 進程 (名為 zygote 和 zygote_secondary),對應的執行程序分別
是 app_process64 (主模式)、app_process32
2. start zygote
位置:system\core\rootdir\init.rc 560

# It is recommended to put unnecessary data/ initialization from post-fs- data # to start-zygote in device's init.rc to unblock zygote start. on zygote-start && property:ro.crypto.state=unencrypted# A/B update verifier that marks a successful boot.exec_start update_verifier_nonencryptedstart netdstart zygotestart zygote_secondary on zygote-start && property:ro.crypto.state=unsupported# A/B update verifier that marks a successful boot.exec_start update_verifier_nonencryptedstart netdstart zygotestart zygote_secondary on zygote-start && property:ro.crypto.state=encrypted && property:ro.crypto.type=file# A/B update verifier that marks a successful boot.exec_start update_verifier_nonencryptedstart netdstart zygotestart zygote_secondary

zygote-start 是在 on late-init 中觸發的

# Mount filesystems and start core system services. on late-inittrigger early-fs# Mount fstab in init.{$device}.rc by mount_all command. Optional parameter# '--early' can be specified to skip entries with 'latemount'.# /system and /vendor must be mounted by the end of the fs stage,# while /data is optional.trigger fstrigger post-fs# Mount fstab in init.{$device}.rc by mount_all with '--late' parameter# to only mount entries with 'latemount'. This is needed if '--early' is# specified in the previous mount_all command on the fs stage.# With /system mounted and properties form /system + /factory available,# some services can be started.trigger late-fs# Now we can mount /data. File encryption requires keymaster to decrypt# /data, which in turn can only be loaded when system properties are present.trigger post-fs-data# Now we can start zygote for devices with file based encryptiontrigger zygote-start # zygote-start 是在 on late-init 中觸發的# Load persist properties and override properties (if enabled) from /data.trigger load_persist_props_action# Remove a file to wake up anything waiting for firmware.trigger firmware_mounts_completetrigger early-boottrigger boot if (bootmode == "charger") {am.QueueEventTrigger("charger");} else {am.QueueEventTrigger("late-init");}

3. app_processXX
位置\frameworks\base\cmds\app_process\

app_process_src_files := \app_main.cpp \ LOCAL_SRC_FILES:= $(app_process_src_files) ... LOCAL_MODULE:= app_process LOCAL_MULTILIB := both LOCAL_MODULE_STEM_32 := app_process32 LOCAL_MODULE_STEM_64 := app_process64

Zygote啟動過程
位置\frameworks\base\cmds\app_process\app_main.cpp
在app_main.cpp的main函數中,主要做的事情就是參數解析. 這個函數有兩種啟動模式:
1. 一種是zygote模式,也就是初始化zygote進程,傳遞的參數有--start-system-server --socket-
name=zygote,前者表示啟動SystemServer,后者指定socket的名稱
2. 一種是application模式,也就是啟動普通應用程序,傳遞的參數有class名字以及class帶的參數
兩者最終都是調用AppRuntime對象的start函數,加載ZygoteInit或RuntimeInit兩個Java類,并將之前
整理的參數傳入進去

app_process

// \frameworks\base\cmds\app_process\app_main.cpp main() L280 if (strcmp(arg, "--zygote") == 0) {zygote = true;niceName = ZYGOTE_NICE_NAME;} else if (strcmp(arg, "--start-system-server") == 0) {startSystemServer = true;} else if (strcmp(arg, "--application") == 0) {application = true;} // L349 ?? if (zygote) {//這些Java的應用都是通過 AppRuntime.start(className)開始的//其實AppRuntime是AndroidRuntime的子類,它主要實現了幾個回調函數,而start()方 法是實現在AndroidRuntime這個方法類里runtime.start("com.android.internal.os.ZygoteInit", args, zygote);} else if (className) {runtime.start("com.android.internal.os.RuntimeInit", args, zygote);}

app_process 里面定義了三種應用程序類型:
1. Zygote: com.android.internal.os.ZygoteInit
2. System Server, 不單獨啟動,而是由Zygote啟動
3. 其他指定類名的Java 程序

// \frameworks\base\core\jni\androidRuntime.cpp class AppRuntime : public AndroidRuntime { public:AppRuntime(char* argBlockStart, const size_t argBlockLength): AndroidRuntime(argBlockStart, argBlockLength), mClass(NULL){}void setClassNameAndArgs(const String8& className, int argc, char * const *argv) {mClassName = className;for (int i = 0; i < argc; ++i) {mArgs.add(String8(argv[i]));}}virtual void onVmCreated(JNIEnv* env){if (mClassName.isEmpty()) {return; // Zygote. Nothing to do here.}/** This is a little awkward because the JNI FindClass call uses the* class loader associated with the native method we're executing in.* If called in onStarted (from RuntimeInit.finishInit because we're* launching "am", for example), FindClass would see that we're calling* from a boot class' native method, and so wouldn't look for the class* we're trying to look up in CLASSPATH. Unfortunately it needs to,* because the "am" classes are not boot classes.** The easiest fix is to call FindClass here, early on before we start* executing boot class Java code and thereby deny ourselves access to* non-boot classes.*/char* slashClassName = toSlashClassName(mClassName.string());mClass = env->FindClass(slashClassName);if (mClass == NULL) {ALOGE("ERROR: could not find class '%s'\n", mClassName.string());}free(slashClassName);mClass = reinterpret_cast<jclass>(env->NewGlobalRef(mClass));}virtual void onStarted(){sp<ProcessState> proc = ProcessState::self();ALOGV("App process: starting thread pool.\n");proc->startThreadPool();AndroidRuntime* ar = AndroidRuntime::getRuntime();ar->callMain(mClassName, mClass, mArgs);IPCThreadState::self()->stopProcess();hardware::IPCThreadState::self()->stopProcess();}virtual void onZygoteInit(){sp<ProcessState> proc = ProcessState::self();ALOGV("App process: starting thread pool.\n");proc->startThreadPool();}virtual void onExit(int code){if (mClassName.isEmpty()) {// if zygoteIPCThreadState::self()->stopProcess();hardware::IPCThreadState::self()->stopProcess();}AndroidRuntime::onExit(code);}String8 mClassName;Vector<String8> mArgs;jclass mClass; }; }

?

總結

以上是生活随笔為你收集整理的系统进程启动流程分析(一)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。