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ソースコードの中でソースコードは以下の位置にある.
/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などの識別子があるか否かに応じて後続の処理を行う.具体的な処理はこの方法に従って引き続きフォローすることができる.