美文网首页
Android 启动系统综述

Android 启动系统综述

作者: 帝王鲨kingcp | 来源:发表于2024-03-04 13:36 被阅读0次

    系统启动

    系统启动架构图 image.png

    init进程(pid=1) Linux系统中用户空间的第一个进程

    1.启动zygote服务
    服务启动 zygote
    2.重启服务

    当init子进程退出时,会产生SIGCHLD信号,并发送给init进程,通过socket套接字传递数据,调用到wait_for_one_process()方法,根据是否是oneshot,来决定是重启子进程,还是放弃启动。


    重启服务
    3.属性服务

    创建一块共享的内存空间,用于属性服务器;
    解析各个rc文件,并启动相应属性服务进程;

    init进程(pid=1)是Linux系统中用户空间的第一个进程,主要工作如下:

    创建一块共享的内存空间,用于属性服务器;
    解析各个rc文件,并启动相应属性服务进程;
    初始化epoll,依次设置signal、property、keychord这3个fd可读时相对应的回调函数;
    进入无限循环状态,执行如下流程:
    检查action_queue列表是否为空,若不为空则执行相应的action;
    检查是否需要重启的进程,若有则将其重新启动;
    进入epoll_wait等待状态,直到系统属性变化事件(property_set改变属性值),或者收到子进程的信号SIGCHLD,再或者keychord 键盘输入事件,则会退出等待状态,执行相应的回调函数。

    可见init进程在开机之后的核心工作就是响应property变化事件和回收僵尸进程。当某个进程调用property_set来改变一个系统属性值时,系统会通过socket向init进程发送一个property变化的事件通知,那么property fd会变成可读,init进程采用epoll机制监听该fd则会 触发回调handle_property_set_fd()方法。回收僵尸进程,在Linux内核中,如父进程不等待子进程的结束直接退出,会导致子进程在结束后变成僵尸进程,占用系统资源。为此,init进程专门安装了SIGCHLD信号接收器,当某些子进程退出时发现其父进程已经退出,则会向init进程发送SIGCHLD信号,init进程调用回调方法handle_signal()来回收僵尸子进程。

    init.cpp
    static int epoll_fd = -1;
    
    int main(int argc, char** argv) {
        ...
        //设置文件属性0777
        umask(0);
        //初始化内核log,位于节点/dev/kmsg【见小节1.2】
        klog_init();
        //设置输出的log级别
        klog_set_level(KLOG_NOTICE_LEVEL);
    
        //创建一块共享的内存空间,用于属性服务【见小节5.1】
        property_init();
        //初始化epoll功能
        epoll_fd = epoll_create1(EPOLL_CLOEXEC);
        //初始化子进程退出的信号处理函数,并调用epoll_ctl设置signal fd可读的回调函数【见小节2.1】
        signal_handler_init();  
    
        //加载default.prop文件
        property_load_boot_defaults();
        //启动属性服务器,此处会调用epoll_ctl设置property fd可读的回调函数【见小节5.2】
        start_property_service();   
        //解析init.rc文件
        init_parse_config_file("/init.rc");
    
        //执行rc文件中触发器为on early-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(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");
        //设备组合键的初始化操作,此处会调用epoll_ctl设置keychord fd可读的回调函数
        queue_builtin_action(keychord_init_action, "keychord_init");
    
        // 屏幕上显示Android静态Logo 【见小节1.3】
        queue_builtin_action(console_init_action, "console_init");
    
        //执行rc文件中触发器为on init的语句
        action_for_each_trigger("init", action_add_queue_tail);
        queue_builtin_action(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");
    
        char bootmode[PROP_VALUE_MAX];
        //当处于充电模式,则charger加入执行队列;否则late-init加入队列。
        if (property_get("ro.bootmode", bootmode) > 0 && strcmp(bootmode, "charger") == 0)
        {
           action_for_each_trigger("charger", action_add_queue_tail);
        } else {
           action_for_each_trigger("late-init", action_add_queue_tail);
        }
        //触发器为属性是否设置
        queue_builtin_action(queue_property_triggers_action, "queue_property_triggers");
    
        while (true) {
            if (!waiting_for_exec) {
                execute_one_command();
                 //根据需要重启服务【见小节1.4】
                restart_processes();
            }
            int timeout = -1;
            if (process_needs_restart) {
                timeout = (process_needs_restart - gettime()) * 1000;
                if (timeout < 0)
                    timeout = 0;
            }
            if (!action_queue_empty() || cur_action) {
                timeout = 0;
            }
    
            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;
    }
    

    init进程

    Zygote进程启动

    Zygote是由init进程通过解析init.zygote.rc文件而创建的,zygote所对应的可执行程序app_process,所对应的源文件是App_main.cpp,进程名为zygote。

    Zygote启动流程
    Zygote启动流程调用图
    1.解析init.zygote.rc中的参数,创建AppRuntime并调用AppRuntime.start()方法;
    2.调用AndroidRuntime的startVM()方法创建虚拟机,再调用startReg()注册JNI函数;
    3.通过JNI方式调用ZygoteInit.main(),第一次进入Java世界;
    4.registerZygoteSocket()建立socket通道,zygote作为通信的服务端,用于响应客户端请求;
    5.preload()预加载通用类、drawable和color资源、openGL以及共享库以及WebView,用于提高app启动效率;
    6.zygote完毕大部分工作,接下来再通过startSystemServer(),fork得力帮手system_server进程,也是上层framework的运行载体。
    7.zygote功成身退,调用runSelectLoop(),随时待命,当接收到请求创建新进程请求时立即唤醒并执行相应工作。

    zygote进程内加载了preload()方法中的所有资源,当需要fork新进程时,采用copy on write技术。

    Zygote fork新进程
    zygote进程

    SystemServer进程

    SystemServer启动流程

    在RuntimeInit.java中invokeStaticMain方法通过创建并抛出异常ZygoteInit.MethodAndArgsCaller,在ZygoteInit.java中的main()方法会捕捉该异常,并调用caller.run(),再通过反射便会调用到SystemServer.main()方法,该方法主要执行流程:

    SystemServer.main
        SystemServer.run
            createSystemContext
            startBootstrapServices();
            startCoreServices();
            startOtherServices();
            Looper.loop();
    
    system_server服务启动流程

    Android进程创建

    android进程创建 进程创建流程图
    Zygote.forkAndSpecialize
        ZygoteHooks.preFork
            Daemons.stop
            ZygoteHooks.nativePreFork
                dalvik_system_ZygoteHooks.ZygoteHooks_nativePreFork
                    Runtime::PreZygoteFork
                        heap_->PreZygoteFork()
        Zygote.nativeForkAndSpecialize
            com_android_internal_os_Zygote.ForkAndSpecializeCommon
                fork()
                Zygote.callPostForkChildHooks
                    ZygoteHooks.postForkChild
                        dalvik_system_ZygoteHooks.nativePostForkChild
                            Runtime::DidForkFromZygote
        ZygoteHooks.postForkCommon
            Daemons.start
    
    forkAndSpecialize时序图
    ServiceManager启动流程图

    相关文章

      网友评论

          本文标题:Android 启动系统综述

          本文链接:https://www.haomeiwen.com/subject/cnfvadtx.html