版權聲明:本文參考@gityuan 袁神相關文章,轉載請注明出處。
注:限于作者水平有限,文中有不對的地方還請指教。
本文基于Android 6.0,涉及源碼如下:
/system/core/rootdir/init.rc
/system/core/rootdir/init.zygote32.rc
/system/core/init/init.cpp
/system/core/init/init_parser.cpp //解析各個服務都是靠它完成
/system/core/init/signal_handler.cpp
概述
Init 進程屬于Linux系統中用戶空間第一個進程,進程號(PID)為1;Linux Kernel啟動后,就會在用戶空間啟動Init 進程,對于Init 進程,使用C++ 語言實現,所以該進程的入口函數是main()方法,在Android源碼中源碼位于:
/system/core/init/init.cpp
作為一個系統工程師,或多或少都知道Init.rc文件,我們可以通過該文件配置一些native 的守護進程,比如:servicemanager,installd,adbd,ueventd 等等;為何我們在該文件中的配置會在系統中有效,這就涉及到系統對于init.rc腳本的解析和執行;init.rc腳本的解析執行就是上述Init進程實現;Init 進程有如下幾個功能:
1. 解析并運行所有init.rc腳本。
2. 生成設備驅動節點。
3. 處理子進程終結(Signal方式)。
4. 提供屬性服務。
接下來從代碼的角度來分析Init進程是具體做到上述功能的。
由于代碼太長,將會提取部分關鍵代碼并添加注釋:
一:main 函數
1.1:init.cpp main函數
int main(int argc, char** argv) {
......
add_environment("PATH", _PATH_DEFPATH); //添加path 環境變量
open_devnull_stdio();
klog_init(); //初始化Kernel Log
property_init(); //創建一塊共享的內存空間,用于屬性服務
selinux_initialize(is_first_stage); //初始化 selinux
signal_handler_init();//初始化子進程終止處理
property_load_boot_defaults(); //加載/default.prop文件
start_property_service(); //啟動屬性服務器(通過socket通信)
init_parse_config_file("/init.rc"); //解析init.rc文件
action_for_each_trigger("early-init", action_add_queue_tail);//執行init.rc中觸發器為on early-init的語句
queue_builtin_action(console_init_action, "console_init");//屏幕上顯示Android靜態Logo 見1.2
action_for_each_trigger("init", action_add_queue_tail);
action_for_each_trigger("late-init", action_add_queue_tail);
while (true) {
if (!waiting_for_exec) {
execute_one_command();
restart_processes();//*啟動有需要的進程
}
......
epoll_event ev;
//循環 等待事件發生
int nr = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd, &ev, 1, timeout));
if (nr == -1) {
ERROR("epoll_wait failed: %s\n", strerror(errno));
} else if (nr == 1) {
((void (*)()) ev.data.ptr)();
}
}
return 0;
}
1.2:console_init_action
開機顯示的底部帶ANDROID字樣畫面。
static int console_init_action(int nargs, char **args)
{
int fd;
if (console[0]) {
snprintf(console_name, sizeof(console_name), "/dev/%s", console);
}
fd = open(console_name, O_RDWR);
if (fd >= 0)
have_console = 1;
close(fd);
fd = open("/dev/tty0", O_WRONLY);
if (fd >= 0) {
const char *msg;
msg = "\n"
"\n"
"\n"
"\n"
"\n"
"\n"
"\n" // console is 40 cols x 30 lines
"\n"
"\n"
"\n"
"\n"
"\n"
"\n"
"\n"
" A N D R O I D ";//這就是Android 原聲底部顯示的字樣,靜態顯示
write(fd, msg, strlen(msg));
close(fd);
}
return 0;
}
二:信號處理
/system/core/init/signal_handler.cpp //第二節的所有內容都是在該文件
2.1:signal_handler_init
在init進程main 方法中,通過調用signal_handler_init 函數來初始化信號處理過程;signal_handler_init定義于:
void signal_handler_init() {
// Create a signalling mechanism for SIGCHLD.
int s[2];
//sockerpair:調用一對已經存在的socke(socketpair是一個SysCall 命令)
if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0, s) == -1) {
ERROR("socketpair failed: %s\n", strerror(errno));
exit(1);
}
signal_write_fd = s[0];
signal_read_fd = s[1];
// Write to signal_write_fd if we catch SIGCHLD.
struct sigaction act;
memset(&act, 0, sizeof(act));
act.sa_handler = SIGCHLD_handler;//設置信號處理函數句柄,即當有數據時,會調用該方法,向上面的
//socket 的fd 中寫入數據,后面epoll 監控到socket 中的fd可讀時,就會調用注冊的函數去處理
act.sa_flags = SA_NOCLDSTOP;//該標志表示init進程只有在子進程終止時才會收到SIGHCLD信號
sigaction(SIGCHLD, &act, 0);
reap_any_outstanding_children();
register_epoll_handler(signal_read_fd, handle_signal); //初始化EPOLL,此處會調用handle_signal方法
}
每個進程在處理其他進程發送的signal信號的時候都會先去注冊,當進程的運行狀態或者進程死亡的時候會產生某種signal信號,Init進程是所有用戶空間進程的父進程,當子進程終止的時候,會產生SIGCHLD信號,sigaction方法將SIGCHLD信號傳遞給sigaction 結構體;到此信號的處理過程就會結束。
對于具體的信號處理函數可以查看SIGCHLD_handler 實現,實質就是向上面的Socket 寫數據;
當socket 的fd 中有數據后,epoll會調用注冊的handle_signal來處理,具體可以參考該方法的實現;
static void handle_signal() {
// Clear outstanding requests.
char buf[32];
read(signal_read_fd, buf, sizeof(buf));
reap_any_outstanding_children();
}
handle_signal方法大概就是將socket fd中的數據讀入到buf 中,然后調用 reap_any_outstanding_children來具體處理服務的退出以及重啟工作;在該方法中,就是根據我們在init.rc腳本中的是否有定義各種標志來確定當服務掛掉后是否要重啟,以及清理一些數據;reap_any_outstanding_children 具體會會調用wait_for_one_process方法來處理;
2.2:reap_any_outstanding_children()::wait_for_one_process()
static bool wait_for_one_process() {
int status;
pid_t pid = TEMP_FAILURE_RETRY(waitpid(-1, &status, WNOHANG));
if (pid == 0) {
return false;
} else if (pid == -1) {
ERROR("waitpid failed: %s\n", strerror(errno));
return false;
}
service* svc = service_find_by_pid(pid);
std::string name;
if (svc) {
name = android::base::StringPrintf("Service '%s' (pid %d)", svc->name, pid);
} else {
name = android::base::StringPrintf("Untracked pid %d", pid);
}
NOTICE("%s %s\n", name.c_str(), DescribeStatus(status).c_str());
if (!svc) {
return true;
}
// TODO: all the code from here down should be a member function on service.
if (!(svc->flags & SVC_ONESHOT) || (svc->flags & SVC_RESTART)) {
NOTICE("Service '%s' (pid %d) killing any children in process group\n", svc->name, pid);
kill(-pid, SIGKILL);
}
//移除當前服務svc中的所有創建過的socket
// Remove any sockets we may have created.
for (socketinfo* si = svc->sockets; si; si = si->next) {
char tmp[128];
snprintf(tmp, sizeof(tmp), ANDROID_SOCKET_DIR"/%s", si->name);
unlink(tmp);
}
//當flags為EXEC時,釋放相應的服務
if (svc->flags & SVC_EXEC) {
INFO("SVC_EXEC pid %d finished...\n", svc->pid);
waiting_for_exec = false;
list_remove(&svc->slist);
free(svc->name);
free(svc);
return true;
}
svc->pid = 0;
svc->flags &= (~SVC_RUNNING);
// Oneshot processes go into the disabled state on exit,
// except when manually restarted.
//對于ONESHOT服務,使其進入disabled狀態
if ((svc->flags & SVC_ONESHOT) && !(svc->flags & SVC_RESTART)) {
svc->flags |= SVC_DISABLED;
}
//禁用和重置的服務,都不再自動重啟
// Disabled and reset processes do not get restarted automatically.
if (svc->flags & (SVC_DISABLED | SVC_RESET)) {
svc->NotifyStateChange("stopped");
return true;
}
//服務在4分鐘內重啟次數超過4次,則重啟手機進入recovery模式
time_t now = gettime();
if ((svc->flags & SVC_CRITICAL) && !(svc->flags & SVC_RESTART)) {
if (svc->time_crashed + CRITICAL_CRASH_WINDOW >= now) {
if (++svc->nr_crashed > CRITICAL_CRASH_THRESHOLD) {
ERROR("critical process '%s' exited %d times in %d minutes; "
"rebooting into recovery mode\n", svc->name,
CRITICAL_CRASH_THRESHOLD, CRITICAL_CRASH_WINDOW / 60);
android_reboot(ANDROID_RB_RESTART2, 0, "recovery");
return true;
}
} else {
svc->time_crashed = now;
svc->nr_crashed = 1;
}
}
svc->flags &= (~SVC_RESTART);
svc->flags |= SVC_RESTARTING;
// Execute all onrestart commands for this service.
struct listnode* node;
//執行當前service中所有onrestart命令
list_for_each(node, &svc->onrestart.commands) {
command* cmd = node_to_item(node, struct command, clist);
cmd->func(cmd->nargs, cmd->args);
}
//設置相應的service狀態為restarting
svc->NotifyStateChange("restarting");
return true;
}
該方法會根據init.rc腳本中各個服務的各種標志來進行相關操作;
2.3:register_epoll_handler 注冊EPOLL
該方法在signal_handler.cpp中調用,但是在init.cpp 中定義。
void register_epoll_handler(int fd, void (*fn)()) {
epoll_event ev;
ev.events = EPOLLIN; //可讀
ev.data.ptr = reinterpret_cast<void*>(fn);
//將fd中的數據添加到epoll 監聽隊列中
if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev) == -1) {
ERROR("epoll_ctl failed: %s\n", strerror(errno));
}
}