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

歡迎訪問 生活随笔!

生活随笔

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

Android

Android init第三、四部分详细分析

發布時間:2025/3/15 Android 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android init第三、四部分详细分析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

本文一定要在詳細閱讀了,系列的第二篇文章時候,再來閱讀。

/init程序第三部分

action_for_each_trigger("early-init", action_add_queue_tail);queue_builtin_action(wait_for_coldboot_done_action, "wait_for_coldboot_done");queue_builtin_action(keychord_init_action, "keychord_init");queue_builtin_action(console_init_action, "console_init");/* execute all the boot actions to get us started */action_for_each_trigger("init", action_add_queue_tail);/* skip mounting filesystems in charger mode */if (!is_charger) {action_for_each_trigger("early-fs", action_add_queue_tail);action_for_each_trigger("fs", action_add_queue_tail);action_for_each_trigger("post-fs", action_add_queue_tail);action_for_each_trigger("post-fs-data", action_add_queue_tail);}queue_builtin_action(property_service_init_action, "property_service_init");queue_builtin_action(signal_init_action, "signal_init");queue_builtin_action(check_startup_action, "check_startup");if (is_charger) {action_for_each_trigger("charger", action_add_queue_tail);} else {action_for_each_trigger("early-boot", action_add_queue_tail);action_for_each_trigger("boot", action_add_queue_tail);}/* run all property triggers based on current state of the properties */queue_builtin_action(queue_property_triggers_action, "queue_property_triggers");

以上就是/init的第三部分,簡單說就是把在/init.rc中解析到的Action,通過trigger掛載到全局變量action_queue中。action_queue其實就是一個等待被執行的Action隊列。

那么我們來分析用到的函數action_for_each_trigger和queue_builtin_action

函數action_for_each_trigger(/system/core/init/init_parser.c)

void action_for_each_trigger(const char *trigger,void (*func)(struct action *act)) {struct listnode *node;struct action *act;list_for_each(node, &action_list) {act = node_to_item(node, struct action, alist);if (!strcmp(act->name, trigger)) {func(act);}} }

我們通過上一篇文章的分析知道,Action的name就是Trigger的名字。由于要分析不只一個文件,所以不同的Action可以有相同的名字也就是相同Trigger^trigger。

例如/init.rc和/init.trace.rc都有boot這個Trigger

多個action_for_each_trigger,只用過一種func參數就是action_add_queue_tail:

void action_add_queue_tail(struct action *act) {list_add_tail(&action_queue, &act->qlist); }

函數很簡單,就是把指定的Action掛到action_queue的尾部。注意,此時該Action還在action_list中的。

函數queue_builtin_action(/system/core/init/init_parser.c)

void queue_builtin_action(int (*func)(int nargs, char **args), char *name) {struct action *act;struct command *cmd;act = calloc(1, sizeof(*act));act->name = name;list_init(&act->commands);cmd = calloc(1, sizeof(*cmd));cmd->func = func;cmd->args[0] = name;list_add_tail(&act->commands, &cmd->clist);list_add_tail(&action_list, &act->alist);action_add_queue_tail(act); }

該函數就是把一些builtin action(這些action不在rc文件中,是系統內置的),同時掛載到action_list和action_queue中。這些ActionCommand只有一個就是傳入的第一個參數。 系統的builtin action

wait_for_coldboot_done_action

系統執行的第一個服務是ueventd用于檢測并掛載設備。有些設備在內核加載時同時加載了,所以需要內核重新發送uevent事件向ueventd服務注冊,稱為coldboot。該Action通過wait_for_file函數等待coldboot完成(coldboot完成是ueventd會創健coldboot_done文件)。

keychord_init_action

初始化keychord,一些服務可以通過keychord開啟

console_init_action

查看/dev/console是否能讀寫,并調用load_565rle_image加載開機動畫。

property_service_init_action

啟動Property Service在第一部分的初始化中完成的只是在/init中的set和get。通過建立一個socket并監聽來實現在全系統中的set和get功能。(主要調用/system/core/init/property_service.c中的start_property_service函數)

signal_init_action

建立新的signal handler處理SIGCHLD信號,目的是在各個服務退出后進行相應的操作(因為服務都是/init的子進程所以是SIGCHLD)。

check_startup_action

檢查上面兩個Action是否成功。

queue_property_triggers_action

有些rc文件中的Action是以on property:<name>=<value>形式的。本Action的作用就是通過讀取Property System檢查這樣的Action是否滿足,是的話掛載到action_queue尾部。?/init程序第四部分

for(;;) {int nr, i, timeout = -1;execute_one_command();restart_processes();if (!property_set_fd_init && get_property_set_fd() > 0) {ufds[fd_count].fd = get_property_set_fd();ufds[fd_count].events = POLLIN;ufds[fd_count].revents = 0;fd_count++;property_set_fd_init = 1;}if (!signal_fd_init && get_signal_fd() > 0) {ufds[fd_count].fd = get_signal_fd();ufds[fd_count].events = POLLIN;ufds[fd_count].revents = 0;fd_count++;signal_fd_init = 1;}if (!keychord_fd_init && get_keychord_fd() > 0) {ufds[fd_count].fd = get_keychord_fd();ufds[fd_count].events = POLLIN;ufds[fd_count].revents = 0;fd_count++;keychord_fd_init = 1;}if (process_needs_restart) {timeout = (process_needs_restart - gettime()) * 1000;if (timeout < 0)timeout = 0;}if (!action_queue_empty() || cur_action)timeout = 0;#if BOOTCHARTif (bootchart_count > 0) {if (timeout < 0 || timeout > BOOTCHART_POLLING_MS)timeout = BOOTCHART_POLLING_MS;if (bootchart_step() < 0 || --bootchart_count == 0) {bootchart_finish();bootchart_count = 0;}} #endifnr = poll(ufds, fd_count, timeout);if (nr <= 0)continue;for (i = 0; i < fd_count; i++) {if (ufds[i].revents == POLLIN) {if (ufds[i].fd == get_property_set_fd())handle_property_set_fd();else if (ufds[i].fd == get_keychord_fd())handle_keychord();else if (ufds[i].fd == get_signal_fd())handle_signal();}}}

函數execute_one_command

void execute_one_command(void) {int ret;if (!cur_action || !cur_command || is_last_command(cur_action, cur_command)) {cur_action = action_remove_queue_head();cur_command = NULL;if (!cur_action)return;INFO("processing action %p (%s)\n", cur_action, cur_action->name);cur_command = get_first_command(cur_action);} else {cur_command = get_next_command(cur_action, cur_command);}if (!cur_command)return;ret = cur_command->func(cur_command->nargs, cur_command->args);INFO("command '%s' r=%d\n", cur_command->args[0], ret); }

該函數就是不斷執行action_queue中ActionCommand

函數restart_processes

static void restart_processes() {process_needs_restart = 0;service_for_each_flags(SVC_RESTARTING,restart_service_if_needed); }

函數restart_service_if_needed

static void restart_service_if_needed(struct service *svc) {time_t next_start_time = svc->time_started + 5;if (next_start_time <= gettime()) {svc->flags &= (~SVC_RESTARTING);service_start(svc, NULL);return;}if ((next_start_time < process_needs_restart) ||(process_needs_restart == 0)) {process_needs_restart = next_start_time;} }

該函數比較難理解,其實是執行了如下的功能:

  • 服務的重啟間隔是5秒,如果需要重啟的服務啟動超過5秒就需要重啟。
  • 把全局變量process_need_restart的值設置成所有需要重啟的服務的最近的重啟時間。

Android系統中由于文件在fork是繼承的,往往/init和子進程——服務之間的通訊可以通過操作文件實現:

某個服務向要向`/init`通訊,只要操作相應的繼承過來的的文件。而`/init`通過`poll`輪詢這些文件。一旦文件被操作時,`/init`就可以知道,從而調用相應的處理函數。

/init中有三個這樣重要的文件:

property_set_fd

用于監聽property set事件

signal_fd

用于監聽服務的退出事件

keychord_fd

用于監聽keychord事件

把這三個文件描述符放到ufds中,通過poll^poll函數輪詢對這三個文件的操作事件,分別執行

handle_property_set_fd();

處理property set事件

handle_keychord();

處理keychord事件

handle_signal();

處理服務子信號(SIGCHLD)事件

我們只重點分析一下handle_signal函數:

void handle_signal(void) {char tmp[32];/* we got a SIGCHLD - reap and restart as needed */read(signal_recv_fd, tmp, sizeof(tmp));while (!wait_for_one_process(0)); }

該函數調用wait_for_process

static int wait_for_one_process(int block) {pid_t pid;int status;struct service *svc;struct socketinfo *si;time_t now;struct listnode *node;struct command *cmd;while ( (pid = waitpid(-1, &status, block ? 0 : WNOHANG)) == -1 && errno == EINTR );if (pid <= 0) return -1;INFO("waitpid returned pid %d, status = %08x\n", pid, status);svc = service_find_by_pid(pid);if (!svc) {ERROR("untracked pid %d exited\n", pid);return 0;}NOTICE("process '%s', pid %d exited\n", svc->name, pid);if (!(svc->flags & SVC_ONESHOT)) {kill(-pid, SIGKILL);NOTICE("process '%s' killing any children in process group\n", svc->name);}/* remove any sockets we may have created */for (si = svc->sockets; si; si = si->next) {char tmp[128];snprintf(tmp, sizeof(tmp), ANDROID_SOCKET_DIR"/%s", si->name);unlink(tmp);}svc->pid = 0;svc->flags &= (~SVC_RUNNING);/* oneshot processes go into the disabled state on exit */if (svc->flags & SVC_ONESHOT) {svc->flags |= SVC_DISABLED;}/* disabled and reset processes do not get restarted automatically */if (svc->flags & (SVC_DISABLED | SVC_RESET) ) {notify_service_state(svc->name, "stopped");return 0;}now = gettime();if (svc->flags & SVC_CRITICAL) {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 0;}} else {svc->time_crashed = now;svc->nr_crashed = 1;}}svc->flags |= SVC_RESTARTING;/* Execute all onrestart commands for this service. */list_for_each(node, &svc->onrestart.commands) {cmd = node_to_item(node, struct command, clist);cmd->func(cmd->nargs, cmd->args);}notify_service_state(svc->name, "restarting");return 0; }

該函數功能如下:

  • 通過waitpid函數獲取退出的子服務的pid。如果服務是onshot的直接kill掉,否則就要標記成重啟狀態。

    svc->flags |= SVC_RESTARTING;

  • 關閉該服務的socket

  • 如果是critical的服務在一定時間內退出超過4次,就調用reboot_android進入recovery mode。

  • 在服務重啟之前執行Onrestart上的命令。

值得注意的是服務沒有在此函數中真正重啟,只是設置成SVC_RESTARTING。

真正的重啟是在上面分析的restart_processes中通過調用service_start完成。

總結

以上是生活随笔為你收集整理的Android init第三、四部分详细分析的全部內容,希望文章能夠幫你解決所遇到的問題。

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