Android启动流程分析(十一) zygote的启动

#############################################

本文为极度寒冰原创,转载请注明出处

#############################################

前面的文章花了很大的篇幅去介绍了init进程如何去解析init.rc,如何去执行系统的一些服务。

那么,我们所说的zygote是怎么启动的呢?zygote又是具体负责了哪些工作呢?

本文我们来一探究竟。

zygote在inir.rc中有如下的描述:

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

我们可以简单的分析下这两句话,

service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server

class main

这个是说,zygote是属于main的class。

zygote是一个服务,服务的名字叫zygote. 启动的时候执行的命令是app_process, 传递的参数是-Xzygote /system/bin --zygote --start-system-server

那么,按照我们前面分析的理论,我们去看一下app_process是个什么东西

首先我们到framework的目录下,在base/cmds/app_process里面,我们看到了生成app_process的makefile

include $(CLEAR_VARS)

LOCAL_SRC_FILES:=         app_main.cpp

LOCAL_SHARED_LIBRARIES :=         libcutils         libutils         liblog         libbinder         libandroid_runtime

LOCAL_MODULE:= app_process
LOCAL_MULTILIB := both
LOCAL_MODULE_STEM_32 := app_process32
LOCAL_MODULE_STEM_64 := app_process64
include $(BUILD_EXECUTABLE)

我们可以看到app_process被执行生成了一个应用程序。

试想一下,zygote的这个服务应该是一直在运行的,但是我们如果adb shell去看ps的话,并找不到app_process的这个命令在一直运行。

这个是为什么呢?

首先我们从app_process的main函数里面截取出来一段

    while (i < argc) {
        const char* arg = argv[i++];
        if (strcmp(arg, "--zygote") == 0) { // 如果从init.rc里面传进来的参数是带--zygote的话,一定是会进这个判断
            zygote = true;  // 将zygote设置为true
            niceName = ZYGOTE_NICE_NAME;  // 将niceName设置为zygote_nice_name设置为zygote
        } else if (strcmp(arg, "--start-system-server") == 0) { // 如果是要启动start-system-server的话
            startSystemServer = true; // 会将startsystemserver设置为true
        } else if (strcmp(arg, "--application") == 0) {  //
            application = true;
        } else if (strncmp(arg, "--nice-name=", 12) == 0) {
            niceName.setTo(arg + 12);
        } else if (strncmp(arg, "--", 2) != 0) {
            className.setTo(arg);
            break;
        } else {
            --i;
            break;
        }
    }

然后这几个参数可以怎么去使用呢?

接着看一下后面的代码,是如何使用的。

    if (!niceName.isEmpty()) {  //如果niceName不为空的话
        runtime.setArgv0(niceName.string());
        set_process_name(niceName.string()); // 调用这个函数将这个process的name设置为zygote
    }

    if (zygote) { // zygote一定为true
        runtime.start("com.android.internal.os.ZygoteInit", args); //我们进入到了这个判断
    } else if (className) {
        runtime.start("com.android.internal.os.RuntimeInit", args);
    } else {
        fprintf(stderr, "Error: no class name or --zygote supplied.\n");
        app_usage();
        LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
        return 10;
    }

我们可以看到,runtime是调用了start的方法区进行了这个zygote的启动的工作,那么我们这个runtime是调用的哪边的start呢?

我们在当前的appruntime里面,是没有相关start函数的实现。

那我们去他的父类里面去看一下。

class AppRuntime : public AndroidRuntime

androidruntime是怎么样的呢?里面有没有start的方法呢?

AndroidRunTime的实现位于:frameworks/base/core/jni/AndroidRuntime.cpp

我们从里面找到了start的方法。

951void AndroidRuntime::start(const char* className, const Vector<String8>& options)
952{
953    ALOGD(">>>>>> START %s uid %d <<<<<<\n",
954            className != NULL ? className : "(unknown)", getuid());
955
956    static const String8 startSystemServer("start-system-server");
957
958    /*
959     * 'startSystemServer == true' means runtime is obsolete and not run from
960     * init.rc anymore, so we print out the boot start event here.
961     */
962    for (size_t i = 0; i < options.size(); ++i) {
963        if (options[i] == startSystemServer) {
964           /* track our progress through the boot sequence */
965           const int LOG_BOOT_PROGRESS_START = 3000;
966           LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START,  ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
967        }
968    }
969
970    const char* rootDir = getenv("ANDROID_ROOT");
971    if (rootDir == NULL) {
972        rootDir = "/system";
973        if (!hasDir("/system")) {
974            LOG_FATAL("No root directory specified, and /android does not exist.");
975            return;
976        }
977        setenv("ANDROID_ROOT", rootDir, 1);
978    }
979
980    //const char* kernelHack = getenv("LD_ASSUME_KERNEL");
981    //ALOGD("Found LD_ASSUME_KERNEL='%s'\n", kernelHack);
982
983    /* start the virtual machine */
984    JniInvocation jni_invocation;
985    jni_invocation.Init(NULL);
986    JNIEnv* env;
987    if (startVm(&mJavaVM, &env) != 0) {    // 创建虚拟机
988        return;
989    }
990    onVmCreated(env);
991
992    /*
993     * Register android functions.
994     */
995    if (startReg(env) < 0) { // 注册jni的方法
996        ALOGE("Unable to register all android natives\n");
997        return;
998    }
999
1000    /*
1001     * We want to call main() with a String array with arguments in it.
1002     * At present we have two arguments, the class name and an option string.
1003     * Create an array to hold them.
1004     */
1005    jclass stringClass;  // class对象
1006    jobjectArray strArray; // 对应objectArray对象
1007    jstring classNameStr; // 一个string
1008
1009    stringClass = env->FindClass("java/lang/String"); //首先找到了string的class
1010    assert(stringClass != NULL);
1011    strArray = env->NewObjectArray(options.size() + 1, stringClass, NULL);  // New 了一个ObjectArray
1012    assert(strArray != NULL);
1013    classNameStr = env->NewStringUTF(className);  // 将className转换为UTF8的类型
1014    assert(classNameStr != NULL);
1015    env->SetObjectArrayElement(strArray, 0, classNameStr);  // 设置objectarray的第一个元素为classname
1016
1017    for (size_t i = 0; i < options.size(); ++i) {  // 将后续的参数依次经过转换push到strArray的数组中
1018        jstring optionsStr = env->NewStringUTF(options.itemAt(i).string());
1019        assert(optionsStr != NULL);
1020        env->SetObjectArrayElement(strArray, i + 1, optionsStr);
1021    }
1022
1023    /*
1024     * Start VM.  This thread becomes the main thread of the VM, and will
1025     * not return until the VM exits.
1026     */
1027    char* slashClassName = toSlashClassName(className); // 将className转换为/的形式
1028    jclass startClass = env->FindClass(slashClassName); // 寻找这个类
1029    if (startClass == NULL) { // 如果找不到的话,我们会返回NULL
1030        ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
1031        /* keep going */
1032    } else {
1033        jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
1034            "([Ljava/lang/String;)V");   // 获取我们寻找到的这个类的main函数
1035        if (startMeth == NULL) {
1036            ALOGE("JavaVM unable to find main() in '%s'\n", className);
1037            /* keep going */
1038        } else {
1039            env->CallStaticVoidMethod(startClass, startMeth, strArray); // 去执行这个类的main函数的方法。
1040
1041#if 0
1042            if (env->ExceptionCheck())
1043                threadExitUncaughtException(env);
1044#endif
1045        }
1046    }
1047    free(slashClassName);  // free
1048
1049    ALOGD("Shutting down VM\n");
1050    if (mJavaVM->DetachCurrentThread() != JNI_OK)
1051        ALOGW("Warning: unable to detach main thread\n");
1052    if (mJavaVM->DestroyJavaVM() != 0)
1053        ALOGW("Warning: VM did not shut down cleanly\n");
1054}

来根据刚才传递的参数来看一下zygoteInit的main函数

648    public static void main(String argv[]) {
649        try {
650            // Start profiling the zygote initialization.
651            SamplingProfilerIntegration.start();
652
653            boolean startSystemServer = false;
654            String socketName = "zygote";
655            String abiList = null;
656            for (int i = 1; i < argv.length; i++) {
657                if ("start-system-server".equals(argv[i])) {
658                    startSystemServer = true;  // startSystemServer为true
659                } else if (argv[i].startsWith(ABI_LIST_ARG)) {
660                    abiList = argv[i].substring(ABI_LIST_ARG.length());
661                } else if (argv[i].startsWith(SOCKET_NAME_ARG)) {
662                    socketName = argv[i].substring(SOCKET_NAME_ARG.length());
663                } else {
664                    throw new RuntimeException("Unknown command line argument: " + argv[i]);
665                }
666            }
667
668            if (abiList == null) {
669                throw new RuntimeException("No ABI list supplied.");
670            }
671
672            registerZygoteSocket(socketName); // 注册了一个socket,用来与系统中的其他应用程序进行通信
673            EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
674                SystemClock.uptimeMillis());
675            preload(); // 预加载一些资源
676            EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
677                SystemClock.uptimeMillis());
678
679            // Finish profiling the zygote initialization.
680            SamplingProfilerIntegration.writeZygoteSnapshot();
681
682            // Do an initial gc to clean up after startup
683            gc();
684
685            // Disable tracing so that forked processes do not inherit stale tracing tags from
686            // Zygote.
687            Trace.setTracingEnabled(false);
688
689            if (startSystemServer) {  // 如果startSystemServer为true的话,我们会启动systemServer
690                startSystemServer(abiList, socketName);
691            }
692
693            Log.i(TAG, "Accepting command socket connections");
694            runSelectLoop(abiList);  // 进入select的循环,用来响应其他应用程序的请求
695
696            closeServerSocket();
697        } catch (MethodAndArgsCaller caller) {
698            caller.run();
699        } catch (RuntimeException ex) {
700            Log.e(TAG, "Zygote died with exception", ex);
701            closeServerSocket();
702            throw ex;
703        }
704    }

那么,最后我们对zygote进行一下总结

首先zygote创建了appruntime的对象,并调用他的start。此后的活动由AppRuntime来控制

然后调用startVM来创建了虚拟机,调用startReg来注册JNI的函数

通过JNI调用zygoteInit进入了java的世界

调用registerZygoteSocket来响应子孙后代的请求,同时调用preload函数进行资源的预加载

调用startSystemServer来进行系统启动的后续工作

完成了java世界的初创工作后,变进入了select循环,来处理后续的请求。

时间: 2024-10-28 19:31:06

Android启动流程分析(十一) zygote的启动的相关文章

Android5 Zygote 与 SystemServer 启动流程分析

Android5 Zygote 与 SystemServer 启动流程分析 Android5 Zygote 与 SystemServer 启动流程分析 前言 zygote 进程 解析 zygoterc 启动 SystemServer 执行 ZygoteInitrunSelectLoop SystemServer 启动过程 Zygote 的 fork 本地方法分析 forkSystemServer ZygoteHookspreFork 创建 system_server 进程 ZygoteHooks

Android启动流程分析(一)

############################################# 本文为极度寒冰原创,转载请注明出处 ############################################# Android的启动流程绝大部分人都知道,但是大多数人都是这样描述的: Android启动,首先是启动Bootloader,然后挂载kernel,挂载完kernel之后,会启动android的init进程,init进程会去孵化Zygote,Zygote是android的重要支柱之

Cocos2d-x3.3RC0的Android编译Activity启动流程分析

本文将从引擎源代码Jni分析Cocos2d-x3.3RC0的Android Activity的启动流程,以下是具体分析. 1.引擎源代码Jni.部分Java层和C++层代码分析 watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveXV4aWt1b18x/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" > watermark/2/text/aHR0cDov

Android -- Audio Native服务之启动流程分析(一)

Android -- Audio Native服务之启动流程分析(一) Android中的Audio系统是比较庞大.繁杂的一部分内容, 其中会涉及较多的音频编解码.多媒体制式与Android Audio HAL设备管理的知识.随着Android的发展,其所支持的音频设备也变得越来丰富,如扬声器.耳机.听筒等等:这种变化也为Android管理如此丰富的音频设备以及如何正确.合理地切换音频输出提出了更高的要求.面对如此繁杂的管理要求,我们分析Android Audio服务的历程想必也不会轻松.接下来

u-boot启动流程分析(2)_板级(board)部分

转自:http://www.wowotech.net/u-boot/boot_flow_2.html 目录: 1. 前言 2. Generic Board 3. _main 4. global data介绍以及背后的思考 5. 前置的板级初始化操作 6. u-boot的relocation 7. 后置的板级初始化操作 1. 前言 书接上文(u-boot启动流程分析(1)_平台相关部分),本文介绍u-boot启动流程中和具体版型(board)有关的部分,也即board_init_f/board_i

u-boot启动流程分析(1)_平台相关部分

转自:http://www.wowotech.net/u-boot/boot_flow_1.html 1. 前言 本文将结合u-boot的“board—>machine—>arch—>cpu”框架,介绍u-boot中平台相关部分的启动流程.并通过对启动流程的简单分析,掌握u-boot移植的基本方法. 注1:本文所使用的u-boot版本,是2016/4/23从u-boot官网(git://git.denx.de/u-boot.git)导入的一个快照,具体可参考“https://github

ubuntu upstart启动流程分析

ubuntu自从6.10版本之后就使用了较新的upstart机制来进行系统的初始化. upstart是一种基于事件驱动的服务启动机制,可以使多个系统任务在保持依赖关系的前提下并发启动(据说这样这样启动会比较快,理论上应当如此).使用upstart机制时,我们通过/etc/init下的一系列 *.conf 配置文件来指定各种系统服务的依赖关系(启动时机).系统启动时,upstart主进程/sbin/init会解析这些配置文件,按照指定的依赖关系并发启动各种服务与应用. 主要程序 upstart有三

YARN Container 启动流程分析

YARN Container 启动流程分析 本文档从代码出发,分析了 YARN 中 Container 启动的整个过程,希望给出这个过程的一个整体的概念. 文档分为两个部分:第一部分是全局,从头至尾地把 Container 启动的整个流程串联起来:第二部分是细节,简要分析了 Container 启动流程中涉及到的服务.接口和类. 注意: 基于 hadoop-2.6.0 的代码 只写了与 Container 启动相关的逻辑,并且还大量忽略了很多细节,目的是为了得到一个整体的概念. 为了让分析更具体

STB 参考Linux启动流程分析

STB启动流程 1. uboot启动(Fastboot启动) 硬件资源检测(如CPU,DDR Size,Nand  flash,mem size,flash size) print Version(如HW Version,Boot Version,Loader Version) boot设置模型的选择(autoboot or stop) 2. Starting kernel 各种接口驱动的启动() Creating 10 MTD partitions on “hinand” 网卡驱动,USB驱动