AOSP 8.0 系统启动之三Zygote启动(一)

目录

前言

​​​​​​​一、zygote触发过程

1.1 init.zygoteXX.rc

1.2 start zygote

1.3 app_processXX

二、zygote运行

二、zygote参数解析

三、创建虚拟机

3.1  AndroidRuntime和AppRuntime

3.1.1 AndroidRuntime类

3.1.2 AppRuntime类

3.1.3 Android runtime类的功能

3.2 创建虚拟机、注册JNI函数

3.2.1 JniInvocation.Init

3.2.2 startVm

3.2.3 startReg

3.2.4 register_jni_procs

四、小结


前言

在上一篇中我们讲到,init进程会解析.rc文件,然后得到一些service去启动,这些service通常不是普通的服务,文档里面的称呼是daemon(守护进程).
所谓守护进程就是这些服务进程会在系统初始化时启动,并一直运行于后台,直到系统关闭时终止,并不会主动结束进程. 我们本篇讲的zygote进程就是其中之一。

zygote进程包含两个阶段,

第一阶段是Native(C/C++)阶段主要负责创建Java虚拟机,JNI注册等,

第二阶段是在Java主要是负责加载系统资源,启动SystemServer进程,以及在后续运行过程中等待AMS请求来启动普通的应用程序.

由于zygote进程内容比较多,我将分两个篇章来讲,本篇只讲zygote的触发到创建Java虚拟机的部分(虚拟机的详细过程,后续专题补充).

本文主要讲解以下内容

  • zygote触发过程
  • zygote参数解析
  • 创建虚拟机

本文涉及到的文件

platform/system/core/rootdir/init.zygoteXX.rc
platform/system/core/rootdir/init.rc
platform/frameworks/base/cmds/app_process/app_main.cpp
platform/frameworks/base/core/jni/AndroidRuntime.cpp
platform/libnativehelper/JniInvocation.cpp
platform/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

一、zygote触发过程

1.1 init.zygoteXX.rc

定义在platform/system/core/rootdir/init.zygoteXX.rc

我们知道service是定义在.rc文件中的,那么zygote定义在哪儿呢?在init.rc中有这样一句

import /init.${ro.zygote}.rc

上节中讲到 ${ro.zygote} 会被替换成 ro.zyogte 的属性值,这个是由不同的硬件厂商自己定制的,
有四个值,zygote32、zygote64、zygote32_64、zygote64_32 ,也就是说可能有四种 .rc 文件,分别是:

  • init.zygote32.rc:zygote 进程对应的执行程序是 app_process (纯 32bit 模式)
  • init.zygote64.rc:zygote 进程对应的执行程序是 app_process64 (纯 64bit 模式)
  • init.zygote32_64.rc:启动两个 zygote 进程 (名为 zygote 和 zygote_secondary),对应的执行程序分别是 app_process32 (主模式)、app_process64
  • init.zygote64_32.rc:启动两个 zygote 进程 (名为 zygote 和 zygote_secondary),对应的执行程序分别是 app_process64 (主模式)、app_process32

//目标设备查询(系统低于6.0 设备)
root@xxxx:/ # getprop | grep zygote                                       
[init.svc.zygote]: [running] 
[init.svc.zygote_secondary]: [running]
[ro.zygote.preload.enable]: [0]
[ro.zygote]: [zygote64_32]  //以64为主,32为辅

为什么要定义这么多种情况呢?直接定义一个不就好了,这主要是因为Android 5.0以后开始支持64位程序,为了兼容32位和64位才这样定义.
不同的zygote.rc内容大致相同,主要区别体现在启动的是32位,还是64位的进程.
init.zygote32_64.rc和init.zygote64_32.rc会启动两个进程,且存在主次之分. 我们以init.zygote64_32.rc为例(设备支持64位应用程序)

// 进程名称是zygote,运行的二进制文件在/system/bin/app_process64
// 启动参数是 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
    class main
    priority -20
    user root
    group root readproc
    socket zygote stream 660 root system //创建一个socket,名字叫zygote,以tcp形式
    onrestart write /sys/android_power/request_state wake //onrestart 指当进程重启时执行后面的命令
    onrestart write /sys/power/state on
    onrestart restart audioserver
    onrestart restart cameraserver
    onrestart restart media
    onrestart restart netd
    onrestart restart wificond
    writepid /dev/cpuset/foreground/tasks //创建子进程时,向/dev/cpuset/foreground/tasks 写入pid

// 另一个service ,名字 zygote_secondary
service zygote_secondary /system/bin/app_process32 -Xzygote /system/bin --zygote --socket-name=zygote_secondary --enable-lazy-preload
    class main
    priority -20
    user root
    group root readproc
    socket zygote_secondary stream 660 root system
    onrestart restart zygote
    writepid /dev/cpuset/foreground/tasks

1.2 start zygote

定义在 platform/system/core/rootdir/init.rc

定义了service,肯定有地方调用 start zygote ,搜索一下就在init.rc中找到了, 只要触发 zygote-start 就可以

on zygote-start && property:ro.crypto.state=unencrypted  //一般走这个分支,数据不加密
    # A/B update verifier that marks a successful boot.
    exec_start update_verifier_nonencrypted
    start netd
    start zygote
    start zygote_secondary

on zygote-start && property:ro.crypto.state=unsupported
    # A/B update verifier that marks a successful boot.
    exec_start update_verifier_nonencrypted
    start netd
    start zygote
    start zygote_secondary

on zygote-start && property:ro.crypto.state=encrypted && property:ro.crypto.type=file
    # A/B update verifier that marks a successful boot.
    exec_start update_verifier_nonencrypted
    start netd
    start zygote
    start zygote_secondary

zygote-start 是在 on late-init 中触发的

on late-init
    ...

    trigger zygote-start

late-init 在哪儿触发的呢?其实上一篇中有讲到,在init进程的最后,会加入 late-init 的trigger

    if (bootmode == "charger") {
        am.QueueEventTrigger("charger");
    } else {
        am.QueueEventTrigger("late-init");
    }

由此分析,zygote的触发是在init进程最后,接下来,我们看看start zygote是如何继续执行的.

1.3 app_processXX

上一篇中我们知道 start 命令有一个对应的执行函数 do_start ,定义在platform/system/core/init/builtins.cpp中

static const Map builtin_functions = {
        ...

        {"start",                   {1,     1,    do_start}},

        ...
};

static int do_start(const std::vector<std::string>& args) {
    Service* svc = ServiceManager::GetInstance().FindServiceByName(args[1]); //找出对应service
    if (!svc) {
        LOG(ERROR) << "do_start: Service " << args[1] << " not found";
        return -1;
    }
    if (!svc->Start())
        return -1;
    return 0;
}

do_start首先是通过FindServiceByName去service数组中遍历,根据名字匹配出对应的service,然后调用service的Start函数,
Start函数我们在上一篇结尾有分析,主要是fork出一个新进程然后执行service对应的二进制文件,并将参数传递进去.

zygote对应的二进制文件是 /system/bin/app_process64 (以此为例),我们看一下对应的mk文件,
对应的目录在platform/frameworks/base/cmds/app_process/Android.mk,
其实不管是app_process、app_process32还是app_process64,对应的源文件都是app_main.cpp.

...

app_process_src_files := \
    app_main.cpp \


LOCAL_SRC_FILES:= $(app_process_src_files)

...

LOCAL_MODULE:= app_process
LOCAL_MULTILIB := both
LOCAL_MODULE_STEM_32 := app_process32
LOCAL_MODULE_STEM_64 := app_process64

...

接下来,我们分析app_main.cpp.

二、zygote运行

二、zygote参数解析

platform/frameworks/base/cmds/app_process/app_main.cpp

//上面start zygote传入的参数是 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
//argc是传入参数的参数数目:argc=5
//argv是传入的参数值:
//                 argv[0]="/system/bin/app_process64" 
//                 argv[1]="-Xzygote" 
//                 argv[2]="/system/bin"
//                 argv[3]="--zygote"
//                 argv[4]="--start-system-server"
int main(int argc, char* const argv[])
{
    //将参数argv放到argv_String字符串中,然后打印出来
    if (!LOG_NDEBUG) {
      String8 argv_String;
      for (int i = 0; i < argc; ++i) {
        argv_String.append("\"");
        argv_String.append(argv[i]);
        argv_String.append("\" ");
      }
      ALOGV("app_process main with argv: %s", argv_String.string());
    }

    AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));//构建AppRuntime对象,并将参数传入
    // Process command line arguments
    // ignore argv[0]
    argc--;
    argv++;

    // Everything up to '--' or first non '-' arg goes to the vm.
    //
    // The first argument after the VM args is the "parent dir", which
    // is currently unused.
    //
    // After the parent dir, we expect one or more the following internal
    // arguments :
    //
    // --zygote : Start in zygote mode
    // --start-system-server : Start the system server.
    // --application : Start in application (stand alone, non zygote) mode.
    // --nice-name : The nice name for this process.
    //
    // For non zygote starts, these arguments will be followed by
    // the main class name. All remaining arguments are passed to
    // the main method of this class.
    //
    // For zygote starts, all remaining arguments are passed to the zygote.
    // main function.
    //
    // Note that we must copy argument string values since we will rewrite the
    // entire argument block when we apply the nice name to argv0.
    //
    // As an exception to the above rule, anything in "spaced commands"
    // goes to the vm even though it has a space in it.

    //上面这段英文大概讲的是,所有在 "--" 后面的非 "-"开头的参数都将传入vm, 但是有个例外是spaced commands数组中的参数

    const char* spaced_commands[] = { "-cp", "-classpath" };//这两个参数是Java程序需要依赖的Jar包,相当于import
    // Allow "spaced commands" to be succeeded by exactly 1 argument (regardless of -s).
    bool known_command = false;
    int i;
    for (i = 0; i < argc; i++) {
        if (known_command == true) { //将spaced_commands中的参数额外加入VM
          runtime.addOption(strdup(argv[i]));
          ALOGV("app_process main add known option '%s'", argv[i]);
          known_command = false;
          continue;
        }

        for (int j = 0;
             j < static_cast<int>(sizeof(spaced_commands) / sizeof(spaced_commands[0]));
             ++j) {
          if (strcmp(argv[i], spaced_commands[j]) == 0) {//比较参数是否是spaced_commands中的参数
            known_command = true;
            ALOGV("app_process main found known command '%s'", argv[i]);
          }
        }

        if (argv[i][0] != '-') { //如果参数第一个字符是'-',直接跳出循环,之前传入的第一个参数是 -Xzygote,所以执行到这儿就跳出了,i=0
            break;
        }
        if (argv[i][1] == '-' && argv[i][2] == 0) {
            ++i; // Skip --.
            break;
        }

        runtime.addOption(strdup(argv[i]));
        ALOGV("app_process main add option '%s'", argv[i]);
    }

    // Parse runtime arguments.  Stop at first unrecognized option.
    bool zygote = false;
    bool startSystemServer = false;
    bool application = false;
    String8 niceName;
    String8 className;

    ++i;  // Skip unused "parent dir" argument.
    //跳过一个参数,之前跳过了-Xzygote,这里继续跳过 /system/bin ,也就是所谓的 "parent dir"
    while (i < argc) {
        const char* arg = argv[i++];
        if (strcmp(arg, "--zygote") == 0) {//表示是zygote启动模式
            zygote = true;
            niceName = ZYGOTE_NICE_NAME;//这个值根据平台可能是zygote64或zygote
        } else if (strcmp(arg, "--start-system-server") == 0) {//需要启动SystemServer
            startSystemServer = true;
        } else if (strcmp(arg, "--application") == 0) {//表示是application启动模式,也就是普通应用程序
            application = true;
        } else if (strncmp(arg, "--nice-name=", 12) == 0) {//进程别名, zygote启动并不会设置nice-name值, 当然会在后面设置
            niceName.setTo(arg + 12);
        } else if (strncmp(arg, "--", 2) != 0) {//application启动的class
            className.setTo(arg);
            break;
        } else {
            --i;
            break;
        }
    }

    Vector<String8> args;
    if (!className.isEmpty()) {//className不为空,说明是application启动模式
        args.add(application ? String8("application") : String8("tool"));
        runtime.setClassNameAndArgs(className, argc - i, argv + i);//将className和参数设置给runtime
    } else { //zygote启动模式
        // We're in zygote mode.
        maybeCreateDalvikCache(); //新建Dalvik的缓存目录. data/dalvik-cache/arm64

        if (startSystemServer) {//加入start-system-server参数
            args.add(String8("start-system-server"));
        }

        char prop[PROP_VALUE_MAX];
        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); //加入--abi-list=参数

        // In zygote mode, pass all remaining arguments to the zygote
        // main() method.
        for (; i < argc; ++i) {//将剩下的参数加入args
            args.add(String8(argv[i]));
        }
    }

    if (!niceName.isEmpty()) {//设置进程别名,根据上面入参,zygote的进程面还无法修改,默认值app_process64
        runtime.setArgv0(niceName.string(), true /* setProcName */);
    }

    if (zygote) { //如果是zygote启动模式,则加载Java 类 ZygoteInit
        runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
    } else if (className) {//如果是application启动模式,则加载RuntimeInit
        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.");
    }
}

在app_main.cpp的main函数中,主要做的事情就是参数解析. 这个函数有两种启动模式:

  • 一种是zygote模式,也就是初始化zygote进程,传递的参数有--start-system-server --socket-name=zygote,前者表示启动SystemServer,后者指定socket的名称
  • 一种是application模式,也就是启动普通应用程序,传递的参数有class名字以及class带的参数 

可参考 Android上app_process启动java进程

两者最终都是调用AppRuntime对象的start函数,加载ZygoteInit或RuntimeInit两个Java类,并将之前整理的参数传入进去

由于本篇讲的是zygote进程启动流程,因此接下来我只讲解ZygoteInit的加载.

我们看到,在最后调用的是runtime.start函数,这个就是要启动虚拟机了,接下来我们分析start函数

三、创建虚拟机

3.1  AndroidRuntime和AppRuntime


在介绍虚拟机启动流程之前,我们先来看看两个重要的类AppRuntime 和AndroidRuntime。
这两个类是Android runtime运行环境的接口类,在Android runtime中起着至关重要的作用。

下面是这两个类之间的关系:

class AppRuntime : public AndroidRuntime

从上面的类继承关系中可以看到,AppRuntime类继承自AndroidRuntime。从后续处理中,在Android 创建运行时环境的时候,主要是通过子类AppRuntime实例操作。

3.1.1 AndroidRuntime类


AndroidRuntime类是AppRuntime的父类,基本承载着Android runtime的绝大部分操作处理。

下面是AndroidRuntime类的声明,从其声明中,我们可以看到Android runtime的几个重要的接口:

公共接口:

registerNativeMethods函数。JNI编程时,应用程序向虚拟机注册本地方法时使用。JNI编程时非常重要的一个函数接口。

  • getRuntime函数。提供给外部获取当前进程AndroidRuntime类实例的接口。
  • getJavaVM函数。提供给外部获取当前进程android虚拟机的接口。
  • getJNIEnv函数。提供给外部获取当前进程JNI环境的接口。

私有接口:

  • startReg函数。系统级服务的JNI注册函数。
  • startVm函数。创建并启动Android虚拟机。
  • mJavaVM。指向虚拟机的指针,用以访问Android虚拟机。

3.1.2 AppRuntime类


AppRuntime类继承自AndroidRuntime类,重载了AndroidRuntime类的onVmCreated()、onStarted()、onZygoteInit()和onExit()函数,是zygote进程处理时实际runtime入口。

3.1.3 Android runtime类的功能

从上面AppRuntime类和AndroidRuntime类的实现声明中可知,AndroidRumtime主要实现如下功能:

  • 创建并启动虚拟机
  • 注册JNI服务
  • 提供外部访问虚拟机的接口
  • 提供外部访问JNI环境的接口,并提供JNI程序开发的功能支持。​​​​​​​

这部分我将分两步讲解,一是虚拟机的创建,二是调用ZygoteInit类的main函数

3.2 创建虚拟机、注册JNI函数

platform/frameworks/base/core/jni/AndroidRuntime.cpp

void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{

    ... //打印一些日志,获取ANDROID_ROOT环境变量

    /* start the virtual machine */
    JniInvocation jni_invocation;
    jni_invocation.Init(NULL);//初始化JNI,加载libart.so
    JNIEnv* env;
    if (startVm(&mJavaVM, &env, zygote) != 0) {//创建虚拟机
        return;
    }
    onVmCreated(env);//表示虚拟创建完成,但是里面是空实现

    /*
     * Register android functions.
     */
    if (startReg(env) < 0) {注册JNI函数
        ALOGE("Unable to register all android natives\n");
        return;
    }
    
    ... //JNI方式调用ZygoteInit类的main函数
}

前半部分主要是初始化JNI,然后创建虚拟机,注册一些JNI函数,我将分开一个个单独讲

3.2.1 JniInvocation.Init

定义在platform/libnativehelper/JniInvocation.cpp

bool JniInvocation::Init(const char* library) {
#ifdef __ANDROID__
  char buffer[PROP_VALUE_MAX];
#else
  char* buffer = NULL;
#endif
  library = GetLibrary(library, buffer);//默认返回 libart.so
  // Load with RTLD_NODELETE in order to ensure that libart.so is not unmapped when it is closed.
  // This is due to the fact that it is possible that some threads might have yet to finish
  // exiting even after JNI_DeleteJavaVM returns, which can lead to segfaults if the library is
  // unloaded.
  const int kDlopenFlags = RTLD_NOW | RTLD_NODELETE;
  /*
   * 1.dlopen功能是以指定模式打开指定的动态链接库文件(elf文件),并返回一个句柄,dlopen的内容比较多,后续会单独讲elf的加载过程
   * 2.RTLD_NOW表示需要在dlopen返回前,解析出所有未定义符号,如果解析不出来,在dlopen会返回NULL
   * 3.RTLD_NODELETE表示在dlclose()期间不卸载库,并且在以后使用dlopen()重新加载库时不初始化库中的静态变量
   */
  handle_ = dlopen(library, kDlopenFlags); // 获取libart.so的句柄
  if (handle_ == NULL) { //获取失败打印错误日志并尝试再次打开libart.so
    if (strcmp(library, kLibraryFallback) == 0) {
      // Nothing else to try.
      ALOGE("Failed to dlopen %s: %s", library, dlerror());
      return false;
    }
    // Note that this is enough to get something like the zygote
    // running, we can't property_set here to fix this for the future
    // because we are root and not the system user. See
    // RuntimeInit.commonInit for where we fix up the property to
    // avoid future fallbacks. http://b/11463182
    ALOGW("Falling back from %s to %s after dlopen error: %s",
          library, kLibraryFallback, dlerror());
    library = kLibraryFallback;
    handle_ = dlopen(library, kDlopenFlags);
    if (handle_ == NULL) {
      ALOGE("Failed to dlopen %s: %s", library, dlerror());
      return false;
    }
  }

  /*
   * 1.FindSymbol函数内部实际调用的是dlsym
   * 2.dlsym作用是根据 动态链接库 操作句柄(handle)与符号(symbol),返回符号对应的地址
   * 3.这里实际就是从libart.so中将JNI_GetDefaultJavaVMInitArgs等对应的地址存入&JNI_GetDefaultJavaVMInitArgs_中
   */
  if (!FindSymbol(reinterpret_cast<void**>(&JNI_GetDefaultJavaVMInitArgs_),
                  "JNI_GetDefaultJavaVMInitArgs")) {
    return false;
  }
  if (!FindSymbol(reinterpret_cast<void**>(&JNI_CreateJavaVM_),
                  "JNI_CreateJavaVM")) {
    return false;
  }
  if (!FindSymbol(reinterpret_cast<void**>(&JNI_GetCreatedJavaVMs_),
                  "JNI_GetCreatedJavaVMs")) {
    return false;
  }
  return true;
}

Init函数主要作用是初始化JNI,具体工作是首先通过dlopen加载libart.so获得其句柄,然后调用dlsym从libart.so中找到
JNI_GetDefaultJavaVMInitArgs、JNI_CreateJavaVM、JNI_GetCreatedJavaVMs三个函数地址,赋值给对应成员属性,
这三个函数会在后续虚拟机创建中调用.

3.2.2 startVm

定义在platform/frameworks/base/core/jni/AndroidRuntime.cpp

int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv, bool zygote)
{
    JavaVMInitArgs initArgs;
    ...
    addOption("exit", (void*) runtime_exit);各//将参数放入mOptions数组中
    ...
    initArgs.version = JNI_VERSION_1_4;
    initArgs.options = mOptions.editArray();//将mOptions赋值给initArgs
    initArgs.nOptions = mOptions.size();
    initArgs.ignoreUnrecognized = JNI_FALSE;
    if (JNI_CreateJavaVM(pJavaVM, pEnv, &initArgs) < 0) {//调用libart.so的JNI_CreateJavaVM函数
            ALOGE("JNI_CreateJavaVM failed\n");
            return -1;
    }
    return 0;
}

extern "C" jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) {
  return JniInvocation::GetJniInvocation().JNI_CreateJavaVM(p_vm, p_env, vm_args);
}

jint JniInvocation::JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) {
  return JNI_CreateJavaVM_(p_vm, p_env, vm_args);//调用之前初始化的JNI_CreateJavaVM_
}

这个函数特别长,但是里面做的事情很单一,其实就是从各种系统属性中读取一些参数,然后通过addOption设置到AndroidRuntime的mOptions数组中存起来,
另外就是调用之前从libart.so中找到JNI_CreateJavaVM函数,并将这些参数传入,由于本篇主要讲zygote启动流程,因此关于虚拟机的实现就不深入探究了

3.2.3 startReg

定义在platform/frameworks/base/core/jni/AndroidRuntime.cpp

int AndroidRuntime::startReg(JNIEnv* env)
{
    ATRACE_NAME("RegisterAndroidNatives");
    /*
     * This hook causes all future threads created in this process to be
     * attached to the JavaVM.  (This needs to go away in favor of JNI
     * Attach calls.)
     */
    androidSetCreateThreadFunc((android_create_thread_fn) javaCreateThreadEtc);
    //设置Android创建线程的函数javaCreateThreadEtc,这个函数内部是通过Linux的clone来创建线程的

    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);//创建一个200容量的局部引用作用域,这个局部引用其实就是局部变量

    if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) { //注册JNI函数
        env->PopLocalFrame(NULL);
        return -1;
    }
    env->PopLocalFrame(NULL);//释放局部引用作用域

    //createJavaThread("fubar", quickTest, (void*) "hello");

    return 0;
}

startReg首先是设置了Android创建线程的处理函数,然后创建了一个200容量的局部引用作用域,用于确保不会出现OutOfMemoryException,
最后就是调用register_jni_procs进行JNI注册

3.2.4 register_jni_procs

定义在platform/frameworks/base/core/jni/AndroidRuntime.cpp

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) { //调用mProc
#ifndef NDEBUG
            ALOGD("----------!!! %s failed to load\n", array[i].mName);
#endif
            return -1;
        }
    }
    return 0;
}

struct RegJNIRec {
   int (*mProc)(JNIEnv*);
};

它的处理是交给RegJNIRec的mProc,RegJNIRec是个很简单的结构体,mProc是个函数指针

我们看看register_jni_procs传入的RegJNIRec数组gRegJNI,里面就是一堆的函数指针

static const RegJNIRec gRegJNI[] = {
    REG_JNI(register_com_android_internal_os_RuntimeInit),
    REG_JNI(register_com_android_internal_os_ZygoteInit),
    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是一个宏定义

    #define REG_JNI(name)      { name }
    struct RegJNIRec {
        int (*mProc)(JNIEnv*);
    };

也就是说REG_JNI(register_com_android_internal_os_ZygoteInit)这句就相当于,{register_com_android_internal_os_ZygoteInit},
也就是将register_com_android_internal_os_ZygoteInit强转为 int (mProc)(JNIEnv) 这样一个方法指针,于是就可以array[i].mProc(env)这样调用,
等同于调用register_com_android_internal_os_ZygoteInit(JNIEnv* env)这个方法

再看看register_com_android_internal_os_ZygoteInit,这实际上是自定义JNI函数并进行动态注册的标准写法,
内部是调用JNI的RegisterNatives,这样注册后,Java类ZygoteInit的native方法nativeZygoteInit就会调用com_android_internal_os_ZygoteInit_nativeZygoteInit函数

int register_com_android_internal_os_ZygoteInit(JNIEnv* env)
{
    const JNINativeMethod methods[] = {
        { "nativeZygoteInit", "()V",
            (void*) com_android_internal_os_ZygoteInit_nativeZygoteInit },
    };
    return jniRegisterNativeMethods(env, "com/android/internal/os/ZygoteInit",
        methods, NELEM(methods));
}

以上便是第一部分的内容,主要工作是从libart.so提取出JNI初始函数JNI_CreateJavaVM等,然后读取一些系统属性作为参数调用JNI_CreateJavaVM创建虚拟机,
在虚拟机创建完成后,动态注册一些native函数,接下来我们讲第二部分,反射调用ZygoteInit类的main函数

四、小结

本篇主要讲zygote进程的触发过程,zygote是如何解析传进来的参数,然后讲了Java虚拟机的创建. 有了虚拟机,后续就通过JNI 中的C 调用Java机制,然后就可以执行Java代码了,
下一篇我将讲解JNI有关的知识,因为这是沟通Java层和C++层的桥梁,frameworks层有非常多的native方法,如果不了解JNI相关的知识,
代码是很难读懂的.

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值