源碼Android10
init 概述
init進(jìn)程是Linux系統(tǒng)中用戶空間的第一個(gè)進(jìn)程力试,進(jìn)程號(hào)固定為1跋核。啟動(dòng)代碼在 system/core/init/main.cpp
中
int main(int argc, char** argv) {
#if __has_feature(address_sanitizer)
__asan_set_error_report_callback(AsanReportCallback);
#endif
if (!strcmp(basename(argv[0]), "ueventd")) {//不清楚何時(shí)調(diào)用
return ueventd_main(argc, argv);
}
if (argc > 1) {
if (!strcmp(argv[1], "subcontext")) {//不清楚何時(shí)調(diào)用
android::base::InitLogging(argv, &android::base::KernelLogger);
const BuiltinFunctionMap function_map;
return SubcontextMain(argc, argv, &function_map);
}
if (!strcmp(argv[1], "selinux_setup")) {
return SetupSelinux(argv);
}
if (!strcmp(argv[1], "second_stage")) {
return SecondStageMain(argc, argv);
}
}
return FirstStageMain(argc, argv);
}
已知調(diào)用順序:FirstStageMain --> SetupSelinux --> SecondStageMain
- FirstStageMain : 掛載及創(chuàng)建基本的文件系統(tǒng)绞惦,并設(shè)置合適的訪問(wèn)權(quán)限; 關(guān)閉默認(rèn)控制臺(tái)輸出偷霉,并初始化內(nèi)核級(jí)log; 掛載 system拘哨、cache疤苹、data 等系統(tǒng)分區(qū)
- SetupSelinux : 設(shè)置SELinux安全策略
- SecondStageMain : 核心步驟习勤,下面詳細(xì)解釋
SecondStageMain
SecondStageMain
方法在 system/core/init/init.cpp
中踪栋,下面只列出了核心代碼
int SecondStageMain(int argc, char** argv) {
...
//初始化屬性服務(wù),并從指定文件讀取屬性
property_init();
...
//epoll 中注冊(cè)signalfd,主要是為了創(chuàng)建handler處理子進(jìn)程終止信號(hào)(SIGCHLD)
InstallSignalFdHandler(&epoll);
...
//解析init.rc文件图毕,文件在 system/core/rootdir 目錄下
LoadBootScripts(am, sm);
...
//執(zhí)行rc文件中觸發(fā)器為on early-init的語(yǔ)句
am.QueueEventTrigger("early-init");
...
//執(zhí)行rc文件中觸發(fā)器為on init的語(yǔ)句
am.QueueEventTrigger("init");
...
// 當(dāng)處于充電模式夷都,則charger加入執(zhí)行隊(duì)列;否則late-init加入隊(duì)列予颤。
std::string bootmode = GetProperty("ro.bootmode", "");
if (bootmode == "charger") {
am.QueueEventTrigger("charger");
} else {
am.QueueEventTrigger("late-init");
}
...
while (true) {
// By default, sleep until something happens.
auto epoll_timeout = std::optional<std::chrono::milliseconds>{};
if (do_shutdown && !shutting_down) {//關(guān)機(jī)重啟
do_shutdown = false;
if (HandlePowerctlMessage(shutdown_command)) {
shutting_down = true;
}
}
if (!(waiting_for_prop || Service::is_exec_service_running())) {//囤官?
am.ExecuteOneCommand();
}
if (!(waiting_for_prop || Service::is_exec_service_running())) {//重啟進(jìn)程
if (!shutting_down) {
auto next_process_action_time = HandleProcessActions();
// If there's a process that needs restarting, wake up in time for that.
if (next_process_action_time) {
epoll_timeout = std::chrono::ceil<std::chrono::milliseconds>(
*next_process_action_time - boot_clock::now());
if (*epoll_timeout < 0ms) epoll_timeout = 0ms;
}
}
// If there's more work to do, wake up again immediately.
if (am.HasMoreCommands()) epoll_timeout = 0ms;
}
if (auto result = epoll.Wait(epoll_timeout); !result) {//循環(huán)等待事件發(fā)生
LOG(ERROR) << result.error();
}
}
return 0;
}
屬性服務(wù)
一般而言,系統(tǒng)或者某些應(yīng)用程序會(huì)把自己的一些屬性存儲(chǔ)在注冊(cè)表中(注冊(cè)表可以存儲(chǔ)一些類似key/value的鍵值對(duì))蛤虐,即使系統(tǒng)重啟或者應(yīng)用程序重啟党饮,它還能根據(jù)之前在注冊(cè)表中設(shè)置的屬性,進(jìn)行相應(yīng)的初始化工作驳庭。Android平臺(tái)也提供了類似的機(jī)制刑顺,稱為屬性服務(wù)。應(yīng)用程序可以通過(guò)這個(gè)屬性機(jī)制查詢或者設(shè)置屬性饲常。
property_init()
在 system/core/init/property_service.cpp
文件中
信號(hào)處理
在Linux內(nèi)核中蹲堂,如父進(jìn)程不等待子進(jìn)程的結(jié)束直接退出,會(huì)導(dǎo)致子進(jìn)程在結(jié)束后變成僵尸進(jìn)程贝淤,占用系統(tǒng)資源柒竞。為此,init進(jìn)程專門安裝了SIGCHLD信號(hào)接收器霹娄,當(dāng)某些子進(jìn)程退出時(shí)發(fā)現(xiàn)其父進(jìn)程已經(jīng)退出能犯,則會(huì)向init進(jìn)程發(fā)送SIGCHLD信號(hào)鲫骗,init進(jìn)程調(diào)用回調(diào)方法handle_signal()來(lái)回收僵尸子進(jìn)程。
init.rc
nit.rc文件在 system/core/rootdir 目錄下
Action
Action: 通過(guò)觸發(fā)器trigger踩晶,即以on開頭的語(yǔ)句來(lái)決定執(zhí)行相應(yīng)的service的時(shí)機(jī)执泰,具體有如下時(shí)機(jī):
on early-init; 在初始化早期階段觸發(fā);
on init; 在初始化階段觸發(fā)渡蜻;
on late-init; 在初始化晚期階段觸發(fā)术吝;
on boot/charger: 當(dāng)系統(tǒng)啟動(dòng)/充電時(shí)觸發(fā),還包含其他情況茸苇,此處不一一列舉排苍;
on property:<key>=<value>: 當(dāng)屬性值滿足條件時(shí)觸發(fā);
Service
服務(wù)Service学密,以 service開頭淘衙,由init進(jìn)程啟動(dòng),一般運(yùn)行在init的一個(gè)子進(jìn)程腻暮,所以啟動(dòng)service前需要判斷對(duì)應(yīng)的可執(zhí)行文件是否存在彤守。init生成的子進(jìn)程,定義在rc文件哭靖,其中每一個(gè)service在啟動(dòng)時(shí)會(huì)通過(guò)fork方式生成子進(jìn)程具垫。
例如: service servicemanager /system/bin/servicemanager代表的是服務(wù)名為servicemanager,服務(wù)執(zhí)行的路徑為/system/bin/servicemanager试幽。
Command
下面列舉常用的命令
class_start <service_class_name>: 啟動(dòng)屬于同一個(gè)class的所有服務(wù)筝蚕;
start <service_name>: 啟動(dòng)指定的服務(wù),若已啟動(dòng)則跳過(guò)铺坞;
stop <service_name>: 停止正在運(yùn)行的服務(wù)
setprop <name> <value>:設(shè)置屬性值
mkdir <path>:創(chuàng)建指定目錄
symlink <target> <sym_link>: 創(chuàng)建連接到<target>的<sym_link>符號(hào)鏈接起宽;
write <path> <string>: 向文件path中寫入字符串;
exec: fork并執(zhí)行康震,會(huì)阻塞init進(jìn)程直到程序完畢燎含;
exprot <name> <name>:設(shè)定環(huán)境變量;
loglevel <level>:設(shè)置log級(jí)別
trigger command :觸發(fā)命令
Options
Options是Service的可選項(xiàng)腿短,與service配合使用
disabled: 不隨class自動(dòng)啟動(dòng)屏箍,只有根據(jù)service名才啟動(dòng);
oneshot: service退出后不再重啟橘忱;
user/group: 設(shè)置執(zhí)行服務(wù)的用戶/用戶組赴魁,默認(rèn)都是root;
class:設(shè)置所屬的類名钝诚,當(dāng)所屬類啟動(dòng)/退出時(shí)颖御,服務(wù)也啟動(dòng)/停止,默認(rèn)為default;
onrestart:當(dāng)服務(wù)重啟時(shí)執(zhí)行相應(yīng)命令潘拱;
socket: 創(chuàng)建名為/dev/socket/<name>的socket
critical: 在規(guī)定時(shí)間內(nèi)該service不斷重啟疹鳄,則系統(tǒng)會(huì)重啟并進(jìn)入恢復(fù)模式
default: 意味著disabled=false,oneshot=false芦岂,critical=false瘪弓。
參考
http://gityuan.com/2016/02/05/android-init/
https://www.imgeek.org/article/825358229
https://juejin.cn/post/6998441504364560420/