Linux孵化Androidの始まり-initプロセス
9465 ワード
本文は@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ソースコードの中でソースコードは以下の位置にある.
システムエンジニアとしては、多かれ少なかれ知っています.rcファイル、サービスマネージャ、installd、adbd、ueventdなど、nativeのデーモンプロセスを構成できます.なぜ私たちがこのファイルの構成がシステムで有効なのか、これはinitに関するものです.rcスクリプトの解析と実行;init.rcスクリプトの解析実行は上述のInitプロセスの実現である.Initプロセスには、次の機能があります.
次に,コードの観点からInitプロセスを解析することは,上記の機能を具体的に実現する.コードが長すぎるため、キーコードの一部が抽出され、コメントが追加されます.
一:main関数
1.1:init.cpp main関数
1.2:console_init_action
電源を入れると、下部にANDROIDの画面が表示されます.
二:信号処理
2.1:signal_handler_init
Initプロセスmainメソッドでsignal_を呼び出すhandler_Init関数は信号処理プロセスを初期化する.signal_handler_init定義:
各プロセスは、他のプロセスが送信するsignal信号を処理する際に先に登録され、プロセスの実行状態またはプロセスが死亡すると何らかのsignal信号が発生し、Initプロセスはすべてのユーザ空間プロセスの親プロセスであり、サブプロセスが終了するとSIGCHLD信号が生成され、sigactionメソッドはSIGCHLD信号をsigaction構造体に伝達する.この信号の処理は終了します.特定の信号処理関数についてSIGCHLD_を表示できます.handler実装は、実質的に上のSocketにデータを書くことです.SOcketのfdにデータがある場合、epollは登録されたhandle_を呼び出します.Signalは処理し、具体的にはこの方法の実現を参照することができる.
handle_Signalメソッドは、socket fdのデータをbufに読み込み、reap_を呼び出すことです.any_outstanding_childrenはサービスの終了と再起動を具体的に処理する.この方法ではinitに基づいていますrcスクリプトには、サービスが停止した後に再起動するかどうか、およびいくつかのデータをクリーンアップするかどうかを決定するために、さまざまなフラグが定義されています.reap_any_outstanding_childrenはwait_を呼び出すfor_one_プロセスメソッドで処理する;
2.2:reap_any_outstanding_children()::wait_for_one_process()
この方法はinitに基づいています.rcスクリプトの各サービスの各種フラグは、関連操作を行う.
2.3:register_epoll_handler EPOLL登録
この方法はsignal_handler.cppで呼び出すがinit.cppで定義します.
以上、initプロセスサブプロセス終了処理プロセス:initサブプロセス終了時にSIGCHLD信号が発生し、initプロセスに送信され、socketソケットを介してデータが伝達され、wait_に呼び出されるfor_one_process()メソッド、wait_for_one_プロセスは,サービスにoneshot,onrestartなどの識別子があるか否かに応じて後続の処理を行う.具体的な処理はこの方法に従って引き続きフォローすることができる.
本文は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
システムエンジニアとしては、多かれ少なかれ知っています.rcファイル、サービスマネージャ、installd、adbd、ueventdなど、nativeのデーモンプロセスを構成できます.なぜ私たちがこのファイルの構成がシステムで有効なのか、これは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
", 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 = "
"
"
"
"
"
"
"
"
"
"
"
"
" // console is 40 cols x 30 lines
"
"
"
"
"
"
"
"
"
"
"
"
"
"
" 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
", 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_プロセスメソッドで処理する;
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
", 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
", 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
", 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...
", 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
", 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(fn);
// fd epoll
if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev) == -1) {
ERROR("epoll_ctl failed: %s
", strerror(errno));
}
}
以上、initプロセスサブプロセス終了処理プロセス:initサブプロセス終了時にSIGCHLD信号が発生し、initプロセスに送信され、socketソケットを介してデータが伝達され、wait_に呼び出されるfor_one_process()メソッド、wait_for_one_プロセスは,サービスにoneshot,onrestartなどの識別子があるか否かに応じて後続の処理を行う.具体的な処理はこの方法に従って引き続きフォローすることができる.