版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)
文檔簡介
1、Android系統(tǒng)啟動流程(一)解析init進程前言作為“Android框架層”這個大系列中的第一個系列,我們首先要了解的是Android系統(tǒng)啟動流程,在這個流程中會涉及到很多重要的知識點,這個系列我們就來一一講解它們,這一篇我們就來學習init進程。1.init簡介init進程是Android系統(tǒng)中用戶空間的第一個進程,作為第一個進程,它被賦予了很多極其重要的工作職責,比如創(chuàng)建zygote(孵化器)和屬性服務等。init進程是由多個源文件共同組成的,這些文件位于源碼目錄system/core/init。本文將基于Android7.0源碼來分析Init進程。2.引入init進程說到init進程
2、,首先要提到Android系統(tǒng)啟動流程的前幾步: 1.啟動電源以及系統(tǒng)啟動 當電源按下時引導芯片代碼開始從預定義的地方(固化在ROM)開始執(zhí)行。加載引導程序Bootloader到RAM,然后執(zhí)行。 2.引導程序Bootloader 引導程序是在Android操作系統(tǒng)開始運行前的一個小程序,它的主要作用是把系統(tǒng)OS拉起來并運行。 3.Linux內(nèi)核啟動 內(nèi)核啟動時,設(shè)置緩存、被保護存儲器、計劃列表,加載驅(qū)動。當內(nèi)核完成系統(tǒng)設(shè)置,它首先在系統(tǒng)文件中尋找”init”文件,然后啟動root進程或者系統(tǒng)的第一個進程。 4.init進程啟動講到第四步就發(fā)現(xiàn)我們這一節(jié)要講的init進程了。關(guān)于Android
3、系統(tǒng)啟動流程的所有步驟會在本系列的最后一篇做講解。3.init入口函數(shù)init的入口函數(shù)為main,代碼如下所示。 system/core/init/init.cppint main(int argc, char* argv) if (!strcmp(basename(argv0), "ueventd") return ueventd_main(argc, argv); if (!strcmp(basename(argv0), "watchdogd") return watchdogd_main(argc, argv); umask(0); add_en
4、vironment("PATH", _PATH_DEFPATH); bool is_first_stage = (argc = 1) | (strcmp(argv1, "-second-stage") != 0); /創(chuàng)建文件并掛載 if (is_first_stage) mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755"); mkdir("/dev/pts", 0755); mkdir("
5、;/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); mount("sysfs", "/sys", "
6、sysfs", 0, NULL); open_devnull_stdio(); klog_init(); klog_set_level(KLOG_NOTICE_LEVEL); NOTICE("init %s started!n", is_first_stage ? "first stage" : "second stage"); if (!is_first_stage) / Indicate that booting is in progress to background fw loaders, etc. close(op
7、en("/dev/.booting", O_WRONLY | O_CREAT | O_CLOEXEC, 0000); /初始化屬性相關(guān)資源 property_init();/1 process_kernel_dt(); process_kernel_cmdline(); export_kernel_boot_props(); . /啟動屬性服務 start_property_service();/2 const BuiltinFunctionMap function_map; Action:set_function_map(&function_map); Parse
8、r& parser = Parser:GetInstance(); parser.AddSectionParser("service",std:make_unique<ServiceParser>(); parser.AddSectionParser("on", std:make_unique<ActionParser>(); parser.AddSectionParser("import", std:make_unique<ImportParser>(); /解析init.rc配置文件 p
9、arser.ParseConfig("/init.rc");/3 . while (true) if (!waiting_for_exec) am.ExecuteOneCommand(); restart_processes(); int timeout = -1; if (process_needs_restart) timeout = (process_needs_restart - gettime() * 1000; if (timeout < 0) timeout = 0; if (am.HasMoreCommands() timeout = 0; bootc
10、hart_sample(&timeout); epoll_event ev; int nr = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd, &ev, 1, timeout); if (nr = -1) ERROR("epoll_wait failed: %sn", strerror(errno); else if (nr = 1) (void (*)() ev.data.ptr)(); return 0;init的main方法做了很多事情,我們只需要關(guān)注主要的幾點,在注釋1處調(diào)用 property_init來對屬性進行初始
11、化并在注釋2處的 調(diào)用start_property_service啟動屬性服務,關(guān)于屬性服務,后面會講到。注釋3處 parser.ParseConfig(“/init.rc”)用來解析init.rc。解析init.rc的文件為system/core/init/init_parse.cpp文件,接下來我們查看init.rc里做了什么。4.init.rcinit.rc是一個配置文件,內(nèi)部由Android初始化語言編寫(Android Init Language)編寫的腳本,它主要包含五種類型語句: Action、Commands、Services、Options和Import。init.rc的配置
12、代碼如下所示。 system/core/rootdir/init.rcon init sysclktz 0 # Mix device-specific information into the entropy pool copy /proc/cmdline /dev/urandom copy /p /dev/urandom.on boot # basic network init ifup lo hostname localhost domainname localdomain # set RLIMIT_NICE to allow priorities from 19 t
13、o -20 setrlimit 13 40 40. 這里只截取了一部分代碼,其中#是注釋符號。on init和on boot是Action類型語句,它的格式為:on <trigger> && <trigger>* /設(shè)置觸發(fā)器 <command> <command> /動作觸發(fā)之后要執(zhí)行的命令 為了分析如何創(chuàng)建zygote,我們主要查看Services類型語句,它的格式如下所示:service <name> <pathname> <argument> * /<service的名字>&
14、lt;執(zhí)行程序路徑><傳遞參數(shù)> <option> /option是service的修飾詞,影響什么時候、如何啟動services <option> . 需要注意的是在Android 7.0中對init.rc文件進行了拆分,每個服務一個rc文件。我們要分析的zygote服務的啟動腳本則在init.zygoteXX.rc中定義,這里拿64位處理器為例,init.zygote64.rc的代碼如下所示。 system/core/rootdir/init.zygote64.rcservice zygote /system/bin/app_process64 -
15、Xzygote /system/bin -zygote -start-system-server class main socket zygote stream 660 root system onrestart write /sys/android_power/request_state wake onrestart write /sys/power/state on onrestart restart audioserver onrestart restart cameraserver onrestart restart media onrestart restart netdwritep
16、id /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks其中service用于通知init進程創(chuàng)建名zygote的進程,這個zygote進程執(zhí)行程序的路徑為/system/bin/app_process64,后面的則是要傳給app_process64的參數(shù)。class main指的是zygote的class name為main,后文會用到它。5.解析service接下來我們來解析service,會用到兩個函數(shù),一個是ParseSection,它會解析service的rc文件,比如上文講到的init.zygote64.rc,Parse
17、Section函數(shù)主要用來搭建service的架子。另一個是ParseLineSection,用于解析子項。代碼如下所示。 system/core/init/service.cppbool ServiceParser:ParseSection(const std:vector<std:string>& args, std:string* err) if (args.size() < 3) *err = "services must have a name and a program" return false; const std:string&a
18、mp; name = args1; if (!IsValidName(name) *err = StringPrintf("invalid service name '%s'", name.c_str(); return false; std:vector<std:string> str_args(args.begin() + 2, args.end(); service_ = std:make_unique<Service>(name, "default", str_args);/1 return true;bo
19、ol ServiceParser:ParseLineSection(const std:vector<std:string>& args, const std:string& filename, int line, std:string* err) const return service_ ? service_->HandleLine(args, err) : false;注釋1處,根據(jù)參數(shù),構(gòu)造出一個service對象,它的classname為”default”。當解析完畢時會調(diào)用EndSection:void ServiceParser:EndSecti
20、on() if (service_) ServiceManager:GetInstance().AddService(std:move(service_); 接著查看AddService做了什么:void ServiceManager:AddService(std:unique_ptr<Service> service) Service* old_service = FindServiceByName(service->name(); if (old_service) ERROR("ignored duplicate definition of service
21、39;%s'", service->name().c_str(); return; services_.emplace_back(std:move(service);/1注釋1處的代碼將service對象加入到services鏈表中。上面的解析過程總體來講就是根據(jù)參數(shù)創(chuàng)建出service對象,然后根據(jù)選項域的內(nèi)容填充service對象,最后將service對象加入到vector類型的services鏈表中。,6.init啟動zygote講完了解析service,接下來該講init是如何啟動service,在這里我們主要講解啟動zygote這個service。在zygot
22、e的啟動腳本中我們得知zygote的class name為main。在init.rc有如下配置代碼: system/core/rootdir/init.rc.on nonencrypted # A/B update verifier that marks a successful boot. exec - root - /system/bin/update_verifier nonencrypted class_start main class_start late_start . 其中class_start是一個COMMAND,對應的函數(shù)為do_class_start。我們知道m(xù)ain指的就
23、是zygote,因此class_start main用來啟動zygote。do_class_start函數(shù)在builtins.cpp中定義,如下所示。system/core/init/builtins.cppstatic int do_class_start(const std:vector<std:string>& args) /* Starting a class does not start services * which are explicitly disabled. They must * be started individually. */ Service
24、Manager:GetInstance(). ForEachServiceInClass(args1, (Service* s) s->StartIfNotDisabled(); ); return 0;來查看StartIfNotDisabled做了什么: system/core/init/service.cppbool Service:StartIfNotDisabled() if (!(flags_ & SVC_DISABLED) return Start(); else flags_ |= SVC_DISABLED_START; return true;接著查看Start方
25、法,如下所示。bool Service:Start() flags_ &= (SVC_DISABLED|SVC_RESTARTING|SVC_RESET|SVC_RESTART|SVC_DISABLED_START); time_started_ = 0; if (flags_ & SVC_RUNNING) /如果Service已經(jīng)運行,則不啟動 return false; bool needs_console = (flags_ & SVC_CONSOLE); if (needs_console && !have_console) ERROR(&quo
26、t;service '%s' requires consolen", name_.c_str(); flags_ |= SVC_DISABLED; return false; /判斷需要啟動的Service的對應的執(zhí)行文件是否存在,不存在則不啟動該Service struct stat sb; if (stat(args_0.c_str(), &sb) = -1) ERROR("cannot find '%s' (%s), disabling '%s'n", args_0.c_str(), strerror(
27、errno), name_.c_str(); flags_ |= SVC_DISABLED; return false; . pid_t pid = fork();/1.fork函數(shù)創(chuàng)建子進程 if (pid = 0) /運行在子進程中 umask(077); for (const auto& ei : envvars_) add_environment(.c_str(), ei.value.c_str(); for (const auto& si : sockets_) int socket_type = (si.type = "stream"
28、; ? SOCK_STREAM : (si.type = "dgram" ? SOCK_DGRAM : SOCK_SEQPACKET); const char* socketcon = !si.socketcon.empty() ? si.socketcon.c_str() : scon.c_str(); int s = create_socket(.c_str(), socket_type, si.perm, si.uid, si.gid, socketcon); if (s >= 0) PublishSocket(, s); . /2.
29、通過execve執(zhí)行程序 if (execve(args_0.c_str(), (char*) &strs0, (char*) ENV) < 0) ERROR("cannot execve('%s'): %sn", args_0.c_str(), strerror(errno); _exit(127); . return true;通過注釋1和2的代碼,我們得知在Start方法中調(diào)用fork函數(shù)來創(chuàng)建子進程,并在子進程中調(diào)用execve執(zhí)行system/bin/app_process,這樣就會進入framework/cmds/app_proce
30、ss/app_main.cpp的main函數(shù),如下所示。 Fks/base/cmds/app_process/app_main.cppint main(int argc, char* const argv) . if (zygote) runtime.start("ernal.os.ZygoteInit", args, zygote);/1 else if (className) runtime.start("ernal.os.RuntimeInit", args, zygote); else
31、fprintf(stderr, "Error: no class name or -zygote supplied.n"); app_usage(); LOG_ALWAYS_FATAL("app_process: no class name or -zygote supplied."); return 10; 從注釋1處的代碼可以得知調(diào)用runtime(AppRuntime)的start來啟動zygote。7.屬性服務Windows平臺上有一個注冊表管理器,注冊表的內(nèi)容采用鍵值對的形式來記錄用戶、軟件的一些使用信息。即使系統(tǒng)或者軟件重啟,它還是能夠根據(jù)之
32、前在注冊表中的記錄,進行相應的初始化工作。Android也提供了一個類似的機制,叫做屬性服務。 在本文的開始,我們提到在init.cpp代碼中和屬性服務相關(guān)的代碼有: system/core/init/init.cpp property_init(); start_property_service();這兩句代碼用來初始化屬性服務配置并啟動屬性服務。首先我們來學習服務配置的初始化和啟動。屬性服務初始化與啟動property_init函數(shù)具體實現(xiàn)的代碼如下所示。 system/core/init/property_service.cppvoid property_init() if (_syst
33、em_property_area_init() ERROR("Failed to initialize property arean"); exit(1); _system_property_area_init函數(shù)用來初始化屬性內(nèi)存區(qū)域。接下來查看start_property_service函數(shù)的具體代碼:void start_property_service() property_set_fd = create_socket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0666, 0, 0,
34、 NULL);/1 if (property_set_fd = -1) ERROR("start_property_service socket creation failed: %sn", strerror(errno); exit(1); listen(property_set_fd, 8);/2 register_epoll_handler(property_set_fd, handle_property_set_fd);/3注釋1處用來創(chuàng)建非阻塞的socket。注釋2處調(diào)用listen函數(shù)對property_set_fd進行監(jiān)聽,這樣創(chuàng)建的socket就成為了ser
35、ver,也就是屬性服務;listen函數(shù)的第二個參數(shù)設(shè)置8意味著屬性服務最多可以同時為8個試圖設(shè)置屬性的用戶提供服務。注釋3處的代碼將property_set_fd放入了epoll句柄中,用epoll來監(jiān)聽property_set_fd:當property_set_fd中有數(shù)據(jù)到來時,init進程將用handle_property_set_fd函數(shù)進行處理。 在linux新的內(nèi)核中,epoll用來替換select,epoll最大的好處在于它不會隨著監(jiān)聽fd數(shù)目的增長而降低效率。因為內(nèi)核中的select實現(xiàn)是采用輪詢來處理的,輪詢的fd數(shù)目越多,自然耗時越多。屬性服務處理請求 從上文我們得知,屬
36、性服務接收到客戶端的請求時,會調(diào)用handle_property_set_fd函數(shù)進行處理: system/core/init/property_service.cppstatic void handle_property_set_fd() . if(memcmp(,"ctl.",4) = 0) se(s); if (check_control_mac_perms(msg.value, source_ctx, &cr) handle_control_message(char*) + 4, (char*) msg.value); el
37、se ERROR("sys_prop: Unable to %s service ctl %s uid:%d gid:%d pid:%dn", + 4, msg.value, cr.uid, cr.gid, cr.pid); else /檢查客戶端進程權(quán)限 if (check_mac_perms(, source_ctx, &cr) /1 property_set(char*) , (char*) msg.value);/2 else ERROR("sys_prop: permission denied u
38、id:%d name:%sn", cr.uid, ); close(s); freecon(source_ctx); break; default: close(s); break; 注釋1處的代碼用來檢查客戶端進程權(quán)限,在注釋2處則調(diào)用property_set函數(shù)對屬性進行修改,代碼如下所示。int property_set(const char* name, const char* value) int rc = property_set_impl(name, value); if (rc = -1) ERROR("property_set("
39、%s", "%s") failedn", name, value); return rc;property_set函數(shù)主要調(diào)用了property_set_impl函數(shù):static int property_set_impl(const char* name, const char* value) size_t namelen = strlen(name); size_t valuelen = strlen(value); if (!is_legal_property_name(name, namelen) return -1; if (valuelen >= PROP_VALUE_MAX) return -1; if (strcmp("selinux.reload_policy", name) = 0 && strcmp("1", value) = 0) if (selinux_reload_policy() != 0) ERROR("Failed to reload policyn"); else
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
- 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 二零二五版美發(fā)培訓學校師資聘用標準合同4篇
- 2025年度門面租賃合同電子版(含租金遞增與調(diào)整機制)
- 2025年度簽競業(yè)協(xié)議打工人財產(chǎn)保全及職業(yè)規(guī)劃合同
- 二零二五年度酒店前臺員工權(quán)益保障與勞動合同
- 二零二五年度超市與物流公司貨物扣點運輸合同
- 2025年度復雜地質(zhì)條件頂管施工安全協(xié)議書
- 2025年度住宅室內(nèi)裝修工程保修協(xié)議
- 2025年度簽競業(yè)協(xié)議打工人財產(chǎn)保全及心理支持合同
- 2025年度跆拳道青少年運動員培養(yǎng)合作協(xié)議
- 二零二五年度退休人員教育輔助教學勞務合同
- 2024年國家焊工職業(yè)技能理論考試題庫(含答案)
- 特魯索綜合征
- 《向心力》 教學課件
- 結(jié)構(gòu)力學數(shù)值方法:邊界元法(BEM):邊界元法的基本原理與步驟
- 2024年山東省泰安市高考語文一模試卷
- 北師大版物理九年級全一冊課件
- 2024年第三師圖木舒克市市場監(jiān)督管理局招錄2人《行政職業(yè)能力測驗》高頻考點、難點(含詳細答案)
- RFJ 006-2021 RFP型人防過濾吸收器制造與驗收規(guī)范(暫行)
- 盆腔炎教學查房課件
- 110kv各類型變壓器的計算單
- 新概念英語課件NCE3-lesson15(共34張)
評論
0/150
提交評論