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

   该解析从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
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,546评论 6 507
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,224评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,911评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,737评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,753评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,598评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,338评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,249评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,696评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,888评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,013评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,731评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,348评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,929评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,048评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,203评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,960评论 2 355

推荐阅读更多精彩内容