美文网首页
Android开机启动流程分析一(Zygote进程)

Android开机启动流程分析一(Zygote进程)

作者: 假期开发仔 | 来源:发表于2021-01-11 11:51 被阅读0次

       该解析从system/core/init/init.cpp初始化一系列文件系统,解析system/core/rootdir/init.rc文件启动Zygote进程分析至Zygote进程启动完成。

       当我们驱动层启动完毕时首先会启动init进程,也就是用户进程。在system/core/init/init.cpp中会对init.rc文件进行解析,之后会孵化出一些进程和一些重要服务,最后会创建一个Zygote进程。这个实现过程的源码流程如下:

       以下源码基于rk3399_industry Android7.1.2

    init.rc

    system/core/init/init.cpp

        ....
        //构造出解析文件用的parser(解析器)对象
        Parser& parser = Parser::GetInstance();
        //为一些类型的关键字,创建特定的parser
        parser.AddSectionParser("service",std::make_unique<ServiceParser>());
        parser.AddSectionParser("on", std::make_unique<ActionParser>());
        parser.AddSectionParser("import", std::make_unique<ImportParser>());
        //开始解析init.rc文件
        //init.rc文件是在init进程启动后执行的启动脚本,文件中记录着init进程需执行的操作。
        //在Android系统中,使用init.rc和init.{ hardware }.rc两个文件。
        //init.rc文件在Android系统运行过程中用于通用的环境设置与进程相关的定义
        //init.{hardware}.rc(例如,高通有init.qcom.rc,MTK有init.mediatek.rc)
        //用于定义Android在不同平台下的特定进程和环境设置等。
        //此处加载的init.rc文件是system/core/rootdir/init.rc,此处记载放在下方解析
        parser.ParseConfig("/init.rc");
        
        ....
    

    system/core/rootdir/init.rc

    import /init.environ.rc
    import /init.usb.rc
    import /init.${ro.hardware}.rc
    import /init.usb.configfs.rc
    import /init.${ro.zygote}.rc
    ....
    

    init.rczygote相关的启动配置文件根据ro.zygote而定,ro.zygote的值可分为zygote32、zygote64、zygote32_64、zygote64_32四种,分别代表

    • init.zygote32.rc:32位的zygote进程,对应的执行程序是app_process
    • init.zygote64.rc:64位的zygote进程,对应的执行程序是app_process64
    • init.zygote32_64.rc:启动两个zygote进程 (zygotezygote_secondary),32位的app_process32 为主、64位的app_process64为辅。
    • init.zygote64_32.rc:启动两个zygote进程 (zygotezygote_secondary),64位的app_process64为主、32位的app_process32为辅。
      ro.zygote的属性值定义是在 build/target/product/core_64_bit.mk
      core_64_bit.mkdevice/rockchip/rk3399/product.mk内调用(根据芯片平台不同,对应的文件便不同,这里以RK3399为例子),代码如下
      device/rockchip/rk3399/product.mk
    PRODUCT_RUNTIMES := runtime_libart_default
    
    $(call inherit-product, device/rockchip/rk3399/device.mk)
    
    $(call inherit-product, $(SRC_TARGET_DIR)/product/core_64_bit.mk)
    

    其中$(SRC_TARGET_DIR)为build/target,所以对应的文件路径是
    build/target/product/core_64_bit.mk

    ifeq ($(strip $(TARGET_BOARD_PLATFORM_PRODUCT)), box)
      PRODUCT_COPY_FILES += system/core/rootdir/init.zygote64_32.box.rc:root/init.zygote64_32.rc
    else
      PRODUCT_COPY_FILES += system/core/rootdir/init.zygote64_32.rc:root/init.zygote64_32.rc
    endif
    
    # 设置zygote属性以选择64位的主脚本,32位的从脚本,必须在core_minimal.mk中的脚本之前解析这一行
    PRODUCT_DEFAULT_PROPERTY_OVERRIDES += ro.zygote=zygote64_32
    
    TARGET_SUPPORTS_32_BIT_APPS := true
    TARGET_SUPPORTS_64_BIT_APPS := true
    

       由于我的源码系统种使用的是init.zygote64_32.rc文件,所以分析这个文件:
    system/core/rootdir/init.zygote64_32.rc

    #创建一个名为zygote的进程,对应的可执行程序路径为/system/bin/app_process64
    # -Xzygote:jvm使用的参数;在AndroidRuntime.cpp类的startVm()函数中调用JNI_CreateJavaVM()时被使用。
    # /system/bin:代表虚拟机程序所在目录
    # --zygote  指明以ZygoteInit类作为虚拟机执行的入口,如果没有–zygote参数,则需要明确指定需要执行的类名。
    # --start-system-server仅在指定–zygote参数时才有效,意思是告知ZygoteInit启动完毕后孵化出第一个进程SystemServe
    # --socket-name=zygote:指定zygote所用到的socket名为zygote
    service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
        class main
        #  指定zygote服务使用到的名为zygote的socket,类型为stream,读写权限为660,用户为root,用户组为system。
        socket zygote stream 660 root system
        # onrestart 服务重启时执行的命令。
        onrestart write /sys/android_power/request_state wake
        onrestart write /sys/power/state on
        onrestart restart audioserver
        onrestart restart cameraserver
        onrestart restart media
        onrestart restart netd
        # writepid <file…> :fork 时将子进程的 pid 写入给定文件。
        writepid /dev/cpuset/foreground/tasks
    
    #与上面类似
    service zygote_secondary /system/bin/app_process32 -Xzygote /system/bin --zygote --socket-name=zygote_secondary
        class main
        socket zygote_secondary stream 660 root system
        onrestart restart zygote
        writepid /dev/cpuset/foreground/tasks
        
    #rc文件结构可以简单为
    #service <name> <pathname> [ <argument> ]*
    #<option>
    #<option>
    #service 服务名称 服务对应的命令的路径 命令的参数
    #选项
    #选项
    

       init.zygote64_32.rc内部启动了两个 zygote 进程 (一个为64位的进程 zygote 和32位的进程zygote_secondary),对应的执行程序分别是 app_process64 (主模式)和app_process32

    app_process的执行

       接下来分析zygote64的可执行程序/system/bin/app_process64文件,app_process64frameworks/base/cmds/app_process文件夹内部文件生成,app_process64的执行入口是目录下的app_main.cpp中的main函数,就从这里开始分析Zygote的启动流程:
    frameworks/base/cmds/app_process/app_main.cpp

    #if defined(__LP64__)
    static const char ABI_LIST_PROPERTY[] = "ro.product.cpu.abilist64";
    static const char ZYGOTE_NICE_NAME[] = "zygote64";
    #else
    static const char ABI_LIST_PROPERTY[] = "ro.product.cpu.abilist32";
    static const char ZYGOTE_NICE_NAME[] = "zygote";
    #endif
    
    //传入的参数根据上方分析得知有
    //{-Xzygote , /system/bin , --zygote , --start-system-server , --socket-name=zygote}
    // argc = 5
    // argv[] = "-Xzygote /system/bin --zygote --start-system-server --socket-name=zygote";
    int main(int argc, char* const argv[])
    {
        //下方有AppRuntime和 computeArgBlockSize的代码
        //computeArgBlockSize方法会计算并且返回了传入参数的字节数
        //之后会创建有AppRuntime对象runtime
        AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
        // 进程命令行参数
        // 忽略 argv[0] 即-Xzygote
        argc--;
        argv++;
    
        // '--'开头或者第一个字符非'-'参数开头的所有内容都将进入vm。
        // 虚拟机参数后的第一个参数是“父目录”,即/system/bin,目前还未使用。
        // 在父目录之后,需要一个或多个内部参数:
        // --zygote : zygote 模式启动
        // --start-system-server : 启动系统服务
        // --application : 开始应用(独立,非Zygote)模式。
        // --nice-name : 进程名
        // 对于非Zygote模式开始,这些参数后面将跟着启动类名。所有剩余的参数都传递给这个类的main方法。
        // 对于zygote模式开始,所有剩余参数都传递给zygote main函数。
        int i;
        for (i = 0; i < argc; i++) {
            if (argv[i][0] != '-') {
                // argv[0] = “/system/bin”,所以直接就结束循环
                break;
            }
            if (argv[i][1] == '-' && argv[i][2] == 0) {
                ++i; // Skip --.
                break;
            }
            //这里过滤后 这部分只有'-'开头的参数
            runtime.addOption(strdup(argv[i]));
        }
    
        // 解析运行时参数。在第一次未被识别的选项时停止。
        bool zygote = false;
        bool startSystemServer = false;
        bool application = false;
        String8 niceName;
        String8 className;
        // 跳过未使用的“父目录(/system/bin)”参数,所以这里需要解析的参数数组为
        // {--zygote , --start-system-server , --socket-name=zygote}
        ++i; 
        while (i < argc) {
            const char* arg = argv[i++];
            if (strcmp(arg, "--zygote") == 0) {//是否存在--zygote参数
                 //设置zygot参数为true,代表启动zygote模式
                zygote = true;
                niceName = ZYGOTE_NICE_NAME; //将niceName设置为"zygote"或者"zygote64"
            } else if (strcmp(arg, "--start-system-server") == 0) {
                 //启动zygot模式存在--start-system-server,将startSystemServer设置为true
                startSystemServer = true; 
            } else if (strcmp(arg, "--application") == 0) {//启动zygote模式不存在--application
                application = true;
            } else if (strncmp(arg, "--nice-name=", 12) == 0) {//启动zygot模式不存在--nice-name
                niceName.setTo(arg + 12);
            } else if (strncmp(arg, "--", 2) != 0) {//启动zygot模式时不成立
                className.setTo(arg);
                break;
            } else {
                --i;
                break;
            }
        }
       // 启动zygote时,上面运行完对应参数如下:
       // zygote = true; niceName = ZYGOTE_NICE_NAME;startSystemServer = true; 
       // application = false; className =null;i=3;
      Vector<String8> args;//该参数接下来要传入AndroidRuntime.start函数
        if (!className.isEmpty()) { //启动zygote时未进入
            // 假如我们要启动的不是zygote进程,而是application或tool程序
            // 我们需要传递给RuntimeInit的唯一参数是应用程序参数。
            // 其余的参数传递给启动类的main()。在使用进程名覆盖它们之前,对它们进行复制。
            args.add(application ? String8("application") : String8("tool"));
            runtime.setClassNameAndArgs(className, argc - i, argv + i);
        } else {
            //启动zygote时
            maybeCreateDalvikCache();//创建/data/dalvik-cache路径,下方会放源码
    
            if (startSystemServer) {
                // 设置启动系统服务的参数
                args.add(String8("start-system-server"));
            }
    
            char prop[PROP_VALUE_MAX];
            // 获取到对应的ABI类型
            // [ro.product.cpu.abilist] : [arm64-v8a, armeabi-v7a, armeabi]
            // [ro.product.cpu.abilist32] : [armeabi-v7a, armeabi]
            // [ro.product.cpu.abilist64] : [arm64-v8a]
            // 根据我们的参数这里获得的是arm64-v8a
            if (property_get(ABI_LIST_PROPERTY, prop, NULL) == 0) {
                LOG_ALWAYS_FATAL("app_process: Unable to determine ABI list from property %s.",
                    ABI_LIST_PROPERTY);
                return 11;
            }
            
            String8 abiFlag("--abi-list=");
            abiFlag.append(prop);
            args.add(abiFlag);
    
            // 将所有剩余参数传递给zygote main()方法。
            // 启动zygote时这里argv就剩下“--socket-name=zygote”参数没加入了,添加进args
            for (; i < argc; ++i) {
                args.add(String8(argv[i]));
            }
        }   
        // 继续启动zygote,此时的args的值为
        // {"start-system-server","--abi-list=ro.product.cpu.abilist64",--socket-name=zygote}
    
        if (!niceName.isEmpty()) { //启动zygote时不成立
            runtime.setArgv0(niceName.string());
            set_process_name(niceName.string());
        }
        if (zygote) { // 启动zygot时成立,调用
            runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
        } else if (className) {
            runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
        } 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;
        }
    }
    
    /************ 下面是内部调用的一些方法的源码,有需要可以看看 ************/
    //这里计算并且返回了传入参数的字节数,这样的目的可以确保传入的四个参数是在一个连续的内存中。
    static size_t computeArgBlockSize(int argc, char* const argv[]) {
        uintptr_t start = reinterpret_cast<uintptr_t>(argv[0]);
        uintptr_t end = reinterpret_cast<uintptr_t>(argv[argc - 1]);
        end += strlen(argv[argc - 1]) + 1;
        return (end - start);
    }
    
    //创建了/data/dalvik-cache目录,并修改该路径的用户、用户组和权限信息
    static void maybeCreateDalvikCache() {
    #if defined(__aarch64__)
        static const char kInstructionSet[] = "arm64";
    #elif defined(__x86_64__)
        static const char kInstructionSet[] = "x86_64";
    #elif defined(__arm__)
        static const char kInstructionSet[] = "arm";
    #elif defined(__i386__)
        static const char kInstructionSet[] = "x86";
    #elif defined (__mips__) && !defined(__LP64__)
        static const char kInstructionSet[] = "mips";
    #elif defined (__mips__) && defined(__LP64__)
        static const char kInstructionSet[] = "mips64";
    #else
    #error "Unknown instruction set"
    #endif
        const char* androidRoot = getenv("ANDROID_DATA");//这里的androidRoot为"data
        LOG_ALWAYS_FATAL_IF(androidRoot == NULL, "ANDROID_DATA environment variable unset");
    
        char dalvikCacheDir[PATH_MAX];
        const int numChars = snprintf(dalvikCacheDir, PATH_MAX,
                "%s/dalvik-cache/%s", androidRoot, kInstructionSet);
        LOG_ALWAYS_FATAL_IF((numChars >= PATH_MAX || numChars < 0),
                "Error constructing dalvik cache : %s", strerror(errno));
    
        //0711 只有属主有读、写、执行权限;而属组用户和其他用户只有执行权限。 
        int result = mkdir(dalvikCacheDir, 0711); //创建/data/dalvik-cache目录
        LOG_ALWAYS_FATAL_IF((result < 0 && errno != EEXIST),
                "Error creating cache dir %s : %s", dalvikCacheDir, strerror(errno));
        
        //更改/data/dalvik-cache目录的用户与用户组为root用户、root用户组
        result = chown(dalvikCacheDir, AID_ROOT, AID_ROOT);
        LOG_ALWAYS_FATAL_IF((result < 0), "Error changing dalvik-cache ownership : %s", strerror(errno));
    
        result = chmod(dalvikCacheDir, 0711);//更改/data/dalvik-cache路径的权限
        LOG_ALWAYS_FATAL_IF((result < 0),
                "Error changing dalvik-cache permissions : %s", strerror(errno));
    }
    

       由上面源码分析可得。由于rc内启动zygote时带有参数--zygote,所以最后会执行到runtime.start("com.android.internal.os.ZygoteInit", args, true);函数, runtimeAppRuntime类的对象,而AppRuntime类继承自AndroidRuntime,对应源码如下:

    class AppRuntime : public AndroidRuntime
    {
    public:
        AppRuntime(char* argBlockStart, const size_t argBlockLength)
            : AndroidRuntime(argBlockStart, argBlockLength)
            , mClass(NULL)
        {
        }
        ....
    }
    /** frameworks/base/core/jni/AndroidRuntime.cpp **/
    //静态全局变量gCurRuntime指向AndroidRuntime对象本身,之后我们若需要获取AndroidRuntime对象,获取gCurRuntime就可以了。
    static AndroidRuntime* gCurRuntime = NULL;
    //创建AndroidRuntime对象
    AndroidRuntime::AndroidRuntime(char* argBlockStart, const size_t argBlockLength) :
            mExitWithoutCleanup(false),
            mArgBlockStart(argBlockStart),
            mArgBlockLength(argBlockLength)
    {   
        SkGraphics::Init();
        // 预先分配足够的空间来容纳相当数量的选项。
        mOptions.setCapacity(20);
        
        assert(gCurRuntime == NULL);        // one per process
        gCurRuntime = this;
    }
    

       在AppRuntime类其内部并没有start方法,实际调用的是AndroidRuntime类的start方法,接下来分析这个函数;

    frameworks/base/core/jni/AndroidRuntime.cpp

    /*
     * 启动 Android runtime.这部分涉及到启动虚拟机并在名为“className”的类中调用其
     * “static void main(String[] args)”方法。
     * 向main函数传递两个参数,类名和指定的选项字符串。
     */
    void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
    {
        //此时的options为{"start-system-server","--abi-list=ro.product.cpu.abilist64",--socket-name=zygote}
        static const String8 startSystemServer("start-system-server");
    
        ....
        const char* rootDir = getenv("ANDROID_ROOT");//rootDir为"/system"目录
        if (rootDir == NULL) {
            rootDir = "/system";
            if (!hasDir("/system")) {
                LOG_FATAL("No root directory specified, and /android does not exist.");
                return;
            }
            setenv("ANDROID_ROOT", rootDir, 1);
        }
        
        /* 启动虚拟机 */
        JniInvocation jni_invocation;
        jni_invocation.Init(NULL);
        JNIEnv* env;
        if (startVm(&mJavaVM, &env, zygote) != 0) {
            return;
        }
        onVmCreated(env);
        /*
         * 注册安卓jni函数。
         */
        if (startReg(env) < 0) {
            ALOGE("Unable to register all android natives\n");
            return;
        }
    
        /*
         * 创建一个带有参数的数组来保存类名和选项字符串参数
         */
        jclass stringClass;
        jobjectArray strArray;
        jstring classNameStr;
    
        stringClass = env->FindClass("java/lang/String");
        assert(stringClass != NULL);
        // String数组
        strArray = env->NewObjectArray(options.size() + 1, stringClass, NULL);
        assert(strArray != NULL);
        // 即ZygoteInit类名字符串
        classNameStr = env->NewStringUTF(className);
        assert(classNameStr != NULL);
        //将类名传入String数组strArray的第0个位置
        env->SetObjectArrayElement(strArray, 0, classNameStr);
    
        // 循环添加输入的参数
        for (size_t i = 0; i < options.size(); ++i) {
            jstring optionsStr = env->NewStringUTF(options.itemAt(i).string());
            assert(optionsStr != NULL);
            env->SetObjectArrayElement(strArray, i + 1, optionsStr);
        }
    
        /*
         * 启动虚拟机。该线程成为VM的主线程,并且在VM退出之前不会返回。
         */
        char* slashClassName = toSlashClassName(className);
        jclass startClass = env->FindClass(slashClassName);
        if (startClass == NULL) {
            ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
            /* keep going */
        } else {
            jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
                "([Ljava/lang/String;)V");//获取ZygoteInit类的main函数
            if (startMeth == NULL) {
                ALOGE("JavaVM unable to find main() in '%s'\n", className);
                /* keep going */
            } else {
                //调用ZygoteInit.main函数
                env->CallStaticVoidMethod(startClass, startMeth, strArray);
                
    #if 0
                if (env->ExceptionCheck())
                    threadExitUncaughtException(env);
    #endif
            }
        }
        //释放slashClassName
        free(slashClassName);
    
        ALOGD("Shutting down VM\n");
        if (mJavaVM->DetachCurrentThread() != JNI_OK)
            ALOGW("Warning: unable to detach main thread\n");
        if (mJavaVM->DestroyJavaVM() != 0)
            ALOGW("Warning: VM did not shut down cleanly\n");
    }
    
    
    

    根据源码得出AndroidRuntime.start内可分为如下几步:

    • 设置了rootDir的目录为/system
    • 通过startVm(&mJavaVM, &env, zygote)启动了虚拟机;
    • 调用startReg(env)注册jni函数;
    • 创建字符串数组来保存类和设置选项
    • 将生成的字符串数组传入并调用ZygoteInit.main方法

    AndroidRuntime.startVm:启动虚拟机

       startVm内部定义了虚拟机的一系列参数,下面简单介绍一些虚拟机的参数,大部分省略掉了,太多了。

    /*
     * 启动Dalvik虚拟机。
     *
     * 传入的各种参数(大多数由系统属性决定)。还有一些由“mOptions” Vector更新。
     *
     * 成功返回0
     */
    int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv, bool zygote)
    {
        ....
    
        bool checkJni = false;
         //JNI检测功能,用于native层调用jni函数时进行常规检测,比较弱字符串格式是否符合要求,资源是否正确释放。
         //该功能一般用于早期系统调试或手机Eng版,对于User版往往不会开启,引用该功能比较消耗系统CPU资源,降低系统性能。
        property_get("dalvik.vm.checkjni", propBuf, "");
        if (strcmp(propBuf, "true") == 0) {
            checkJni = true;
        } else if (strcmp(propBuf, "false") != 0) {
            /* 判断kernel层是否开启 */
            property_get("pa.kernel.android.checkjni", propBuf, "");
            if (propBuf[0] == '1') {
                checkJni = true;
            }
        }
        ALOGD("CheckJNI is %s\n", checkJni ? "ON" : "OFF");
        if (checkJni) {
            /* 开启JNI检测功能 */
            addOption("-Xcheck:jni");
        }
        //dalvik虚拟机启动模式
        property_get("dalvik.vm.execution-mode", propBuf, "");
        if (strcmp(propBuf, "int:portable") == 0) {
            executionMode = kEMIntPortable;
        } else if (strcmp(propBuf, "int:fast") == 0) {
            executionMode = kEMIntFast;
        } else if (strcmp(propBuf, "int:jit") == 0) {
            executionMode = kEMJitCompiler;
        }
        //虚拟机产生的trace文件,主要用于分析系统问题,路径默认为/data/anr/traces.txt
        parseRuntimeOption("dalvik.vm.stack-trace-file", stackTraceFileBuf, "-Xstacktracefile:");
        
        ....
    
        /*
         * 堆的默认启动和最大大小。根据不同的设备可以做相应的调整
         */
        //dalvik.vm.heapstartsize:应用程序启动后为其分配的初始大小
        parseRuntimeOption("dalvik.vm.heapstartsize", heapstartsizeOptsBuf, "-Xms", "4m");
        //dalvik.vm.heapsize:单个虚拟机可分配的最大内存
        parseRuntimeOption("dalvik.vm.heapsize", heapsizeOptsBuf, "-Xmx", "16m");
        //dalvik.vm.heapgrowthlimit:每个应用程序最大可分配内存
        parseRuntimeOption("dalvik.vm.heapgrowthlimit", heapgrowthlimitOptsBuf, "-XX:HeapGrowthLimit=");
        //dalvik.vm.heapminfree:堆最小空闲内存
        parseRuntimeOption("dalvik.vm.heapminfree", heapminfreeOptsBuf, "-XX:HeapMinFree=");
        //dalvik.vm.heapmaxfree:堆最大空闲内存
        parseRuntimeOption("dalvik.vm.heapmaxfree", heapmaxfreeOptsBuf, "-XX:HeapMaxFree=");
        //dalvik.vm.heaptargetutilization:堆利用率
        parseRuntimeOption("dalvik.vm.heaptargetutilization",
                           heaptargetutilizationOptsBuf,
                           "-XX:HeapTargetUtilization=");
        //heapminfree、heapmaxfree、heaptargetutilization这三个值的设置则对垃圾回收(GC)的某些性能有影响。
    
        /*
         * JIT编译器相关配置。JIT:即时编译技术
         */
        ....
    
        //确保有一个预加载的类文件preloaded-classes(由WritePreloadedClassFile.java生成)。
        //在ZygoteInit类中会预加载工作将其中的classes提前加载到内存,以提高系统性能
        if (!hasFile("/system/etc/preloaded-classes")) {
            ALOGE("Missing preloaded-classes file, /system/etc/preloaded-classes not found: %s\n",
                  strerror(errno));
            return -1;
        }
        ....
    
        //创建虚拟机
        if (JNI_CreateJavaVM(pJavaVM, pEnv, &initArgs) < 0) {
            ALOGE("JNI_CreateJavaVM failed\n");
            return -1;
        }
    
        return 0;
    }
    

    AndroidRuntime.startReg:注册jni函数

    /*
     * 向VM注册android jni函数。
     */
    /*static*/ int AndroidRuntime::startReg(JNIEnv* env)
    {
        ATRACE_NAME("RegisterAndroidNatives");
        androidSetCreateThreadFunc((android_create_thread_fn) javaCreateThreadEtc);
    
        ALOGV("--- registering native functions ---\n");
    
        /*
         * Every "register" function calls one or more things that return
         * a local reference (e.g. FindClass).  Because we haven't really
         * started the VM yet, they're all getting stored in the base frame
         * and never released.  Use Push/Pop to manage the storage.
         */
        env->PushLocalFrame(200);
        
        //调用register_jni_procs进行jni接口注册,gRegJNI就是通过REG_JNI宏定义的jni函数数组
        if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) {
            env->PopLocalFrame(NULL);
            return -1;
        }
        env->PopLocalFrame(NULL);
    
        return 0;
    }
    
    static int register_jni_procs(const RegJNIRec array[], size_t count, JNIEnv* env)
    {
        for (size_t i = 0; i < count; i++) {
            if (array[i].mProc(env) < 0) {
    #ifndef NDEBUG
                ALOGD("----------!!! %s failed to load\n", array[i].mName);
    #endif
                return -1;
            }
        }
        return 0;
    }
    //REG_JNI宏定义
    #define REG_JNI(name)      { name }
        struct RegJNIRec {
            int (*mProc)(JNIEnv*);
        };
        
    static const RegJNIRec gRegJNI[] = {
        REG_JNI(register_com_android_internal_os_RuntimeInit),
        REG_JNI(register_android_os_SystemClock),
        REG_JNI(register_android_util_EventLog),
        REG_JNI(register_android_util_Log),
        REG_JNI(register_android_util_MemoryIntArray),
        REG_JNI(register_android_util_PathParser),
        REG_JNI(register_android_app_admin_SecurityLog),
        REG_JNI(register_android_content_AssetManager),
        REG_JNI(register_android_content_StringBlock),
        REG_JNI(register_android_content_XmlBlock),
        REG_JNI(register_android_text_AndroidCharacter),
        REG_JNI(register_android_text_StaticLayout),
        REG_JNI(register_android_text_AndroidBidi),
        REG_JNI(register_android_view_InputDevice),
        ....
        }
    

       到此,虚拟机已经启动,jni函数也已经注册,这里只是简单分析,毕竟完整的分析就有点偏离启动流程了。之后进入ZygoteInit.main类的main函数;

    ZygoteInit.main

    frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

      private static final String ABI_LIST_ARG = "--abi-list=";
    
      private static final String SOCKET_NAME_ARG = "--socket-name=";
      
    // 此时的argv[]为
    // {"ZygoteInit","start-system-server","--abi-list=ro.product.cpu.abilist64",--socket-name=zygote}
     public static void main(String argv[]) {
            ....
            try {
                // DDMS:DalvikDebugMonitorServer,Dalvik调试监控服务器
                RuntimeInit.enableDdms();//开启DDMS监听,监听DDMS消息
                // Start profiling the zygote initialization.
                SamplingProfilerIntegration.start();//启动性能统计
    
                boolean startSystemServer = false;
                String socketName = "zygote";
                String abiList = null;
                for (int i = 1; i < argv.length; i++) {
                    if ("start-system-server".equals(argv[i])) {
                        startSystemServer = true;
                    } else if (argv[i].startsWith(ABI_LIST_ARG)) {
                        // 获得adb类型,此时为ro.product.cpu.abilist64
                        abiList = argv[i].substring(ABI_LIST_ARG.length());
                    } else if (argv[i].startsWith(SOCKET_NAME_ARG)) {
                         // socketName = zygote
                        socketName = argv[i].substring(SOCKET_NAME_ARG.length());
                    } else {
                        throw new RuntimeException("Unknown command line argument: " + argv[i]);
                    }
                }
                if (abiList == null) {
                     // 没有获取到abi
                    throw new RuntimeException("No ABI list supplied.");
                }
                //创建名为zygote的的Server端socket
                registerZygoteSocket(socketName);
                preload();// 预加载类和资源
                Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
    
                SamplingProfilerIntegration.writeZygoteSnapshot();
    
                //初始化gc
                Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PostZygoteInitGC");
                gcAndFinalize();
                Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
    
                Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
    
                // 关闭trace以防止fork出的进程trace错误
                Trace.setTracingEnabled(false);
    
                // Zygote进程卸载根存储空间,不太明白,希望大神赐教
                Zygote.nativeUnmountStorageOnInit();
    
                ....
                if (startSystemServer) {
                    //启动系统服务
                    startSystemServer(abiList, socketName);
                }
    
                //进入循环等待
                //等待Activity管理服务ActivityManagerService请求Zygote进程创建新的应用程序进程
                runSelectLoop(abiList);
    
                closeServerSocket();
            } catch (MethodAndArgsCaller caller) {
                caller.run();
            } catch (Throwable ex) {
                Log.e(TAG, "Zygote died with exception", ex);
                closeServerSocket();
                throw ex;
            }
        }
    

    registerZygoteSocket

       registerZygoteSocket:创建名为zygoteServersocket:用来等待ActivityManagerService请求Zygote进程创建新的应用程序进程。

     private static LocalServerSocket sServerSocket;
     private static final String ANDROID_SOCKET_PREFIX = "ANDROID_SOCKET_";
     private static void registerZygoteSocket(String socketName) {
            if (sServerSocket == null) {
                int fileDesc;
                final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
                try {   
                    //env = ANDROID_SOCKET_zygote
                    String env = System.getenv(fullSocketName);
                    //将env转成文件描述符
                    fileDesc = Integer.parseInt(env);
                } catch (RuntimeException ex) {
                    throw new RuntimeException(fullSocketName + " unset or invalid", ex);
                }
    
                try {   
                    //根据fileDesc创建一个Server端socket
                    FileDescriptor fd = new FileDescriptor();
                    fd.setInt$(fileDesc);
                    //保存至ZygoteInit的静态成员变量sServerSocket
                    sServerSocket = new LocalServerSocket(fd);
                } catch (IOException ex) {
                    throw new RuntimeException(
                            "Error binding to local socket '" + fileDesc + "'", ex);
                }
            }
        }
    

       创建完成后,会进行一些预加载类和资源,如果有需要会调用startSystemServer启动System进程,然后调用runSelectLoop进行循环等待。

    runSelectLoop

       runSelectLoop:进入循环等待,等待Activity管理服务ActivityManagerService(以下简称AMS),请求Zygote进程创建新的应用程序进程。

        /**
         * 运行Zygote进程的循环等待,当新的连接请求发生时生成新的应用程序进程。
         */
        private static void runSelectLoop(String abiList) throws MethodAndArgsCaller {
            ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
            //peers是与Zygote进程的Server Socket(mServerSocket)连接的连接列表
            ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
            //将mServerSocket的文件描述符放入fds
            fds.add(sServerSocket.getFileDescriptor());
            peers.add(null);
            //无限循环等待AMS请求Zygote进程创建新的应用程序进程
            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 {
                    Os.poll(pollFds, -1);
                } catch (ErrnoException ex) {
                    throw new RuntimeException("poll failed", ex);
                }
                for (int i = pollFds.length - 1; i >= 0; --i) {
                    if ((pollFds[i].revents & POLLIN) == 0) {
                        continue;
                    }
                    if (i == 0) {
                        //AMS与Zygote进程的mServerSocket建立连接
                        ZygoteConnection newPeer = acceptCommandPeer(abiList);
                        //将这个连接添加到sdocket连接列表peer中
                        peers.add(newPeer);
                        //将该连接的socket文件描述符添加到fds中
                        fds.add(newPeer.getFileDesciptor());
                        //添加完成后就可以接受AMS发送过来的创建应用程序进程请求
                    } else {
                         //处理AMS与Zygote发送的请求
                         //peers.get(i)就是之前建立起来的连接(ZygoteConnection)
                         //调用其runOnce()来创建一个新的应用程序进程
                        boolean done = peers.get(i).runOnce();
                        if (done) {
                            //处理完成了这个连接,将对应的连接和描述符删除
                            peers.remove(i);
                            fds.remove(i);
                        }
                    }
                }
            }
        }
    

       runSelectLoop发生在启动System进程完成之后,根据代码得到Zygote进程会进入一个无限循环,不断等待AMS的连接和请求创建新的应用程序进程。针对如何通过ZygoteConnection.runOnce()来创建一个新的进程过程比较复杂,之后另开一篇文章分析;

    整个过程可以用流程图简单概括:


    image.png

    相关文章

      网友评论

          本文标题:Android开机启动流程分析一(Zygote进程)

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