• Android 系统启动(init,zygote)


    主要文件目录:
    system/core/init/ - init.cpp - init_parser.cpp - signal_handler.cpp
    - property_service.cpp

    一、概述

    1.启动电源以及系统启动

      当按下电源时引导芯片代码从预定义的地方(固化在ROM)开始执行。加载引导程序Boot Loader到RAM中,然后执行。

    2.引导程序Boot Loader是在Android操作系统开始运行前的一个小程序,它的主要作用是把系统OS拉起来并运行。

    3.Linux内核运行

      当内核启动时设置缓存、被保护存储器、计划列表、加载驱动。在内核完成系统设置后,首先在系统文件中寻找init.rc 文件,并启动init进程。

    4.init进程启动

      init进程做的工作比较多,主要用初始化和启动属性服务,也用来启动Zygote进程。

    init进程是Linux系统中用户空间的第一个进程,进程号固定为1。Kernel启动后,在用户空间启动init进程,并调用init中的main()方法执行init进程的职责。对于init进程的功能分为4部分:

    • 解析并运行所有的init.rc相关文件
    • 根据rc文件,生成相应的设备驱动节点
    • 处理子进程的终止(signal方式)
    • 提供属性服务的功能

    1.main

    [-> init.cpp]

    int main(int argc, char** argv) {
        ...//创建一块共享的内存空间,用于属性服务
        property_init();
    //初始化子进程退出的信号处理函数,并调用epoll_ctl设置signal fd可读的回调函数
        signal_handler_init();  
    //启动属性服务器,此处会调用epoll_ctl设置property fd可读的回调函数
        start_property_service();   
    //解析init.rc文件 init_parse_config_file("/init.rc");//循环等待事件发生 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; }

    init进程执行完成后进入循环等待epoll_wait的状态。

    二、rc文件语法

      rc文件语法是以行为单位,以空格间隔的语法,以#开始代表注释行。rc文件主要包含Action、Service、Command、Options,其中对于Action和Service的名称都是唯一的,对于重复的命名视为无效。

    1.Action

    Action: 通过触发器trigger,即以on开头的语句来决定执行相应的service的时机,具体有如下时机:

    • on early-init; 在初始化早期阶段触发;
    • on init; 在初始化阶段触发;
    • on late-init; 在初始化晚期阶段触发;
    • on boot/charger: 当系统启动/充电时触发,还包含其他情况,此处不一一列举;
    • on property:<key>=<value>: 当属性值满足条件时触发;

    2. Service

      服务Service,以 service开头,由init进程启动,一般运行在init的一个子进程,所以启动service前需要判断对应的可执行文件是否存在。init生成的子进程,定义在rc文件,其中每一个service在启动时会通过fork方式生成子进程。

    例如: service servicemanager /system/bin/servicemanager代表的是服务名为servicemanager,服务执行的路径为/system/bin/servicemanager。

    3. Command

    常用的命令

    • class_start <service_class_name>: 启动属于同一个class的所有服务;
    • start <service_name>: 启动指定的服务,若已启动则跳过;
    • stop <service_name>: 停止正在运行的服务
    • setprop <name> <value>:设置属性值
    • mkdir <path>:创建指定目录
    • symlink <target> <sym_link>: 创建连接到<target>的<sym_link>符号链接;
    • write <path> <string>: 向文件path中写入字符串;
    • exec: fork并执行,会阻塞init进程直到程序完毕;
    • exprot <name> <name>:设定环境变量;
    • loglevel <level>:设置log级别

    4.Options

    Options是Service的可选项,与service配合使用

    • disabled: 不随class自动启动,只有根据service名才启动;
    • oneshot: service退出后不再重启;
    • user/group: 设置执行服务的用户/用户组,默认都是root;
    • class:设置所属的类名,当所属类启动/退出时,服务也启动/停止,默认为default;
    • onrestart:当服务重启时执行相应命令;
    • socket: 创建名为/dev/socket/<name>的socket
    • critical: 在规定时间内该service不断重启,则系统会重启并进入恢复模式

    default: 意味着disabled=false,oneshot=false,critical=false。

    三、启动服务

    1.服务启动(Zygote)

    在init.zygote.rc文件中,zygote服务定义如下:

    service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
        class main
        socket zygote stream 660 root system
        onrestart write /sys/android_power/request_state wake
        onrestart write /sys/power/state on
        onrestart restart media
        onrestart restart netd

    Zygote服务会随着main class的启动而启动,退出后会由init重启zygote,即使多次重启也不会进入recovery模式。zygote所对应的可执行文件是/system/bin/app_process。

    流程如下:

    zygote_init

    2. 服务重启

    init_oneshot

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

    所有的Service里面只有servicemanager ,zygote ,surfaceflinger这3个服务有onrestart关键字来触发其他service启动过程。

    //zygote可触发media、netd重启
    service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
        class main
        socket zygote stream 660 root system
        onrestart write /sys/android_power/request_state wake
        onrestart write /sys/power/state on
        onrestart restart media
        onrestart restart netd
    
    //servicemanager可触发healthd、zygote、media、surfaceflinger、drm重启
    service servicemanager /system/bin/servicemanager
        class core
        user system
        group system
        critical
        onrestart restart healthd
        onrestart restart zygote
        onrestart restart media
        onrestart restart surfaceflinger
        onrestart restart drm
    
    //surfaceflinger可触发zygote重启
    service surfaceflinger /system/bin/surfaceflinger
        class core
        user system
        group graphics drmrpc
        onrestart restart zygote

    由上可知:

    • zygote:触发media、netd以及子进程(包括system_server进程)重启;
    • system_server: 触发zygote重启;
    • surfaceflinger:触发zygote重启;
    • servicemanager: 触发zygote、healthd、media、surfaceflinger、drm重启

    所以,surfaceflinger,servicemanager,zygote自身以及system_server进程被杀都会触发Zygote重启。

    四、Zygote

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

    从App_main()开始,Zygote启动过程的函数调用类大致流程如下:

    zygote_process

    五、Zygote启动过程

    1. App_main.main

    [-> App_main.cpp]

    int main(int argc, char* const argv[])
    {
        //传到的参数argv为“-Xzygote /system/bin --zygote --start-system-server”
        AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
      //设置进程名
        if (!niceName.isEmpty()) {
            runtime.setArgv0(niceName.string());
            set_process_name(niceName.string());
        }
        if (zygote) {
            // 启动AppRuntime 
            runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
        } else if (className) {
            runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
        } else {
            //没有指定类名或zygote,参数错误
            return 10;
        }
    }

    2.start

    [-> AndroidRuntime.cpp]

    void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
    {
        static const String8 startSystemServer("start-system-server");// 虚拟机创建
        if (startVm(&mJavaVM, &env, zygote) != 0) {
            return;
        }
        onVmCreated(env);
        // JNI方法注册
        if (startReg(env) < 0) {
            return;
        }//将"com.android.internal.os.ZygoteInit"转换为"com/android/internal/os/ZygoteInit"
        char* slashClassName = toSlashClassName(className);
        jclass startClass = env->FindClass(slashClassName);
        if (startClass == NULL) {
            ...
        } else {
            jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
                "([Ljava/lang/String;)V");
            // 调用ZygoteInit.main()方法
            env->CallStaticVoidMethod(startClass, startMeth, strArray);
        }
    }

    六. 进入Java层

    AndroidRuntime.start()执行到最后通过反射调用到ZygoteInit.main()

    1. ZygoteInit.main

    [–>ZygoteInit.java]

    public static void main(String argv[]) {
        try {
            ...
            registerZygoteSocket(socketName); //为Zygote注册socket
            preload(); // 预加载类和资源
            if (startSystemServer) {
                startSystemServer(abiList, socketName);//启动system_server
            }
            runSelectLoop(abiList); //进入循环模式
            closeServerSocket();
        } catch (MethodAndArgsCaller caller) {
            caller.run(); //启动system_server
        } catch (RuntimeException ex) {
            closeServerSocket();
            throw ex;
        }
    }

    在异常捕获后调用的方法caller.run()

    2. preload

    [–>ZygoteInit.java]

    static void preload() {
        //预加载位于/system/etc/preloaded-classes文件中的类
        preloadClasses();
    
        //预加载资源,包含drawable和color资源
        preloadResources();
    
        //预加载OpenGL
        preloadOpenGL();
    
        //通过System.loadLibrary()方法,
        //预加载"android","compiler_rt","jnigraphics"这3个共享库
        preloadSharedLibraries();
    
        //预加载 文本连接符资源
        preloadTextResources();
    
        //仅用于zygote进程,用于内存共享的进程
        WebViewFactory.prepareWebViewInZygote();
    }

    3. startSystemServer

    [–>ZygoteInit.java]

    private static boolean startSystemServer(String abiList, String socketName) throws MethodAndArgsCaller, RuntimeException {//参数准备
        String args[] = {
            "--setuid=1000",
            "--setgid=1000",
            "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1032,3001,3002,3003,3006,3007",
            "--capabilities=" + capabilities + "," + capabilities,
            "--nice-name=system_server",
            "--runtime-args",
            "com.android.server.SystemServer",
        };
    
        ZygoteConnection.Arguments parsedArgs = null;
        int pid;
        try {
            //用于解析参数,生成目标格式
            parsedArgs = new ZygoteConnection.Arguments(args);
            ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);
            ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);
    
            // fork子进程,用于运行system_server
            pid = Zygote.forkSystemServer(
                    parsedArgs.uid, parsedArgs.gid,
                    parsedArgs.gids,
                    parsedArgs.debugFlags,
                    null,
                    parsedArgs.permittedCapabilities,
                    parsedArgs.effectiveCapabilities);
        } catch (IllegalArgumentException ex) {
            throw new RuntimeException(ex);
        }
    
        //进入子进程system_server
        if (pid == 0) {
            if (hasSecondZygote(abiList)) {
                waitForSecondaryZygote(socketName);
            }
            // 完成system_server进程剩余的工作
            handleSystemServerProcess(parsedArgs);
        }
        return true;
    }

      准备参数并fork新进程,从上面可以看出system server进程参数信息为uid=1000,gid=1000,进程名为sytem_server,从zygote进程fork新进程后,需要关闭zygote原有的socket。

    4. runSelectLoop

    [–>ZygoteInit.java]

    private static void runSelectLoop(String abiList) throws MethodAndArgsCaller {
        ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
        ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
        //sServerSocket是socket通信中的服务端,即zygote进程。保存到fds[0]
        fds.add(sServerSocket.getFileDescriptor());
        peers.add(null);
    
        while (true) {
            StructPollfd[] pollFds = new StructPollfd[fds.size()];
            for (int i = 0; i < pollFds.length; ++i) {
                pollFds[i] = new StructPollfd();
                pollFds[i].fd = fds.get(i);
                pollFds[i].events = (short) POLLIN;
            }
            try {
                 //处理轮询状态,当pollFds有事件到来则往下执行,否则阻塞在这里
                Os.poll(pollFds, -1);
            } catch (ErrnoException ex) {
                ...
            }
            
            for (int i = pollFds.length - 1; i >= 0; --i) {
                //采用I/O多路复用机制,当接收到客户端发出连接请求 或者数据处理请求到来,则往下执行;
                // 否则进入continue,跳出本次循环。
                if ((pollFds[i].revents & POLLIN) == 0) {
                    continue;
                }
                if (i == 0) {
                    //即fds[0],代表的是sServerSocket,则意味着有客户端连接请求;
                    // 则创建ZygoteConnection对象,并添加到fds。
                    ZygoteConnection newPeer = acceptCommandPeer(abiList);
                    peers.add(newPeer);
                    fds.add(newPeer.getFileDesciptor()); //添加到fds.
                } else {
                    //i>0,则代表通过socket接收来自对端的数据,并执行相应操作
                    boolean done = peers.get(i).runOnce();
                    if (done) {
                        peers.remove(i);
                        fds.remove(i); //处理完则从fds中移除该文件描述符
                    }
                }
            }
        }
    }

    Zygote采用高效的I/O多路复用机制,保证在没有客户端连接请求或数据处理时休眠,否则响应客户端的请求。

    5. runOnce

    [-> ZygoteConnection.java]

    boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {
    
        String args[];
        Arguments parsedArgs = null;
        FileDescriptor[] descriptors;
    
        try {
            //读取socket客户端发送过来的参数列表
            args = readArgumentList();
            descriptors = mSocket.getAncillaryFileDescriptors();
        } catch (IOException ex) {
            ...
            return true;
        }
        ...
    
        try {
            //将binder客户端传递过来的参数,解析成Arguments对象格式
            parsedArgs = new Arguments(args);
        
            pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
                    parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
                    parsedArgs.niceName, fdsToClose, parsedArgs.instructionSet,
                    parsedArgs.appDataDir);
        } catch (Exception e) {
            ...
        }
    
        try {
            if (pid == 0) {
                //子进程执行
                IoUtils.closeQuietly(serverPipeFd);
                serverPipeFd = null;
                //进入子进程流程
                handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);
                return true;
            } else {
                //父进程执行
                IoUtils.closeQuietly(childPipeFd);
                childPipeFd = null;
                return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs);
            }
        } finally {
            IoUtils.closeQuietly(childPipeFd);
            IoUtils.closeQuietly(serverPipeFd);
        }
    }

    七、总结

    Zygote启动过程的调用流程图:

    zygote_start

    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(),随时待命,当接收到请求创建新进程请求时立即唤醒并执行相应工作。
  • 相关阅读:
    jsp eclipse 创建jsp项目
    SQL Server 身份验证 登陆
    HUD 5086 Revenge of Segment Tree(递推)
    HDU 1700 Points on Cycle (几何 向量旋转)
    RocketMQ broker jvm 监控
    RocketMQ runbroker.sh 分析JVM启动参数
    问题:虚拟机老生代垃圾回收频繁出现
    空白行 ,空白
    eclipse find 两位数
    生成字母+数字6位字符串
  • 原文地址:https://www.cnblogs.com/lufeibin/p/13491044.html
Copyright © 2020-2023  润新知