Android10 JNI原理分析

JNI(Java Native Interface,Java本地接口),是连接Android Native层和Java层的纽带

发布日期 2020-12-29

一、概述

JNI(Java Native Interface,Java本地接口),是连接Android Native层和Java层的纽带,这个是Java所特有的,并不是Android系统独有。Java作为跨平台的语言,依靠的是虚拟机,虚拟机采用C/C++编写,适配各个系统,通过JNI为上层Java提供各种服务,保证跨平台性。下面将从Android虚拟机启动开始深入理解JNI的原理。

二、Android虚拟机启动

在Android系统systemserver启动上,有介绍过虚拟机的启动。虚拟机的启动是在Zygote进程中,Zygote启动过程中通过AndroidRuntime::start函数中的startVm来创建虚拟机而后注册JNI函数。

2.1 AR::start


void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
   ......
    /* start the virtual machine */
    JniInvocation jni_invocation;
    jni_invocation.Init(NULL);
    JNIEnv* env;
    //创建虚拟机
    if (startVm(&mJavaVM, &env, zygote) != 0) {
        return;
    }
    //空函数
    onVmCreated(env);
    /*
     * Register android functions.
     */
    //注册JNI函数
    if (startReg(env) < 0) {
        ALOGE("Unable to register all android natives/n");
        return;
    }

    ......
}

2.2 AR::startVm


int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv, bool zygote, bool primary_zygote)
{
    JavaVMInitArgs initArgs;
    char propBuf[PROPERTY_VALUE_MAX];
    char jniOptsBuf[sizeof("-Xjniopts:")-1 + PROPERTY_VALUE_MAX];
    char heapstartsizeOptsBuf[sizeof("-Xms")-1 + PROPERTY_VALUE_MAX];
    char heapsizeOptsBuf[sizeof("-Xmx")-1 + PROPERTY_VALUE_MAX];
    char heapgrowthlimitOptsBuf[sizeof("-XX:HeapGrowthLimit=")-1 + PROPERTY_VALUE_MAX];
    char heapminfreeOptsBuf[sizeof("-XX:HeapMinFree=")-1 + PROPERTY_VALUE_MAX];
    char heapmaxfreeOptsBuf[sizeof("-XX:HeapMaxFree=")-1 + PROPERTY_VALUE_MAX];
    char usejitOptsBuf[sizeof("-Xusejit:")-1 + PROPERTY_VALUE_MAX];
    char jitpthreadpriorityOptsBuf[sizeof("-Xjitpthreadpriority:")-1 + PROPERTY_VALUE_MAX];
    char jitmaxsizeOptsBuf[sizeof("-Xjitmaxsize:")-1 + PROPERTY_VALUE_MAX];
    char jitinitialsizeOptsBuf[sizeof("-Xjitinitialsize:")-1 + PROPERTY_VALUE_MAX];
    char jitthresholdOptsBuf[sizeof("-Xjitthreshold:")-1 + PROPERTY_VALUE_MAX];
    char useJitProfilesOptsBuf[sizeof("-Xjitsaveprofilinginfo:")-1 + PROPERTY_VALUE_MAX];
    char jitprithreadweightOptBuf[sizeof("-Xjitprithreadweight:")-1 + PROPERTY_VALUE_MAX];
    char jittransitionweightOptBuf[sizeof("-Xjittransitionweight:")-1 + PROPERTY_VALUE_MAX];
    char hotstartupsamplesOptsBuf[sizeof("-Xps-hot-startup-method-samples:")-1 + PROPERTY_VALUE_MAX];
    char madviseRandomOptsBuf[sizeof("-XX:MadviseRandomAccess:")-1 + PROPERTY_VALUE_MAX];
    char gctypeOptsBuf[sizeof("-Xgc:")-1 + PROPERTY_VALUE_MAX];
    char backgroundgcOptsBuf[sizeof("-XX:BackgroundGC=")-1 + PROPERTY_VALUE_MAX];
    char heaptargetutilizationOptsBuf[sizeof("-XX:HeapTargetUtilization=")-1 + PROPERTY_VALUE_MAX];
    char foregroundHeapGrowthMultiplierOptsBuf[
            sizeof("-XX:ForegroundHeapGrowthMultiplier=")-1 + PROPERTY_VALUE_MAX];
    char cachePruneBuf[sizeof("-Xzygote-max-boot-retry=")-1 + PROPERTY_VALUE_MAX];
    char dex2oatXmsImageFlagsBuf[sizeof("-Xms")-1 + PROPERTY_VALUE_MAX];
    char dex2oatXmxImageFlagsBuf[sizeof("-Xmx")-1 + PROPERTY_VALUE_MAX];
    char dex2oatXmsFlagsBuf[sizeof("-Xms")-1 + PROPERTY_VALUE_MAX];
    char dex2oatXmxFlagsBuf[sizeof("-Xmx")-1 + PROPERTY_VALUE_MAX];
    char dex2oatCompilerFilterBuf[sizeof("--compiler-filter=")-1 + PROPERTY_VALUE_MAX];
    char dex2oatImageCompilerFilterBuf[sizeof("--compiler-filter=")-1 + PROPERTY_VALUE_MAX];
    char dex2oatThreadsBuf[sizeof("-j")-1 + PROPERTY_VALUE_MAX];
    char dex2oatThreadsImageBuf[sizeof("-j")-1 + PROPERTY_VALUE_MAX];
    char dex2oat_isa_variant_key[PROPERTY_KEY_MAX];
    char dex2oat_isa_variant[sizeof("--instruction-set-variant=") -1 + PROPERTY_VALUE_MAX];
    char dex2oat_isa_features_key[PROPERTY_KEY_MAX];
    char dex2oat_isa_features[sizeof("--instruction-set-features=") -1 + PROPERTY_VALUE_MAX];
    char dex2oatFlagsBuf[PROPERTY_VALUE_MAX];
    char dex2oatImageFlagsBuf[PROPERTY_VALUE_MAX];
    char extraOptsBuf[PROPERTY_VALUE_MAX];
    char voldDecryptBuf[PROPERTY_VALUE_MAX];
    enum {
      kEMDefault,
      kEMIntPortable,
      kEMIntFast,
      kEMJitCompiler,
    } executionMode = kEMDefault;
    char localeOption[sizeof("-Duser.locale=") + PROPERTY_VALUE_MAX];
    char lockProfThresholdBuf[sizeof("-Xlockprofthreshold:")-1 + PROPERTY_VALUE_MAX];
    char nativeBridgeLibrary[sizeof("-XX:NativeBridge=") + PROPERTY_VALUE_MAX];
    char cpuAbiListBuf[sizeof("--cpu-abilist=") + PROPERTY_VALUE_MAX];
    char corePlatformApiPolicyBuf[sizeof("-Xcore-platform-api-policy:") + PROPERTY_VALUE_MAX];
    char methodTraceFileBuf[sizeof("-Xmethod-trace-file:") + PROPERTY_VALUE_MAX];
    char methodTraceFileSizeBuf[sizeof("-Xmethod-trace-file-size:") + PROPERTY_VALUE_MAX];
    std::string fingerprintBuf;
    char jdwpProviderBuf[sizeof("-XjdwpProvider:") - 1 + PROPERTY_VALUE_MAX];
    char bootImageBuf[sizeof("-Ximage:") - 1 + PROPERTY_VALUE_MAX];

    std::string use_apex_image =
        server_configurable_flags::GetServerConfigurableFlag(RUNTIME_NATIVE_BOOT_NAMESPACE,
                                                             ENABLE_APEX_IMAGE,
                                                             /*default_value=*/ "");
    if (use_apex_image == "true") {
        addOption(kApexImageOption);
        ALOGI("Using Apex boot image: '%s'/n", kApexImageOption);
    } else if (parseRuntimeOption("dalvik.vm.boot-image", bootImageBuf, "-Ximage:")) {
        ALOGI("Using dalvik.vm.boot-image: '%s'/n", bootImageBuf);
    } else {
        ALOGI("Using default boot image");
    }

    std::string disable_lock_profiling =
        server_configurable_flags::GetServerConfigurableFlag(RUNTIME_NATIVE_BOOT_NAMESPACE,
                                                             DISABLE_LOCK_PROFILING,
                                                             /*default_value=*/ "");
    if (disable_lock_profiling == "true") {
        addOption(kLockProfThresholdRuntimeOption);
        ALOGI("Disabling lock profiling: '%s'/n", kLockProfThresholdRuntimeOption);
    } else {
        ALOGI("Leaving lock profiling enabled");
    }

    bool checkJni = false;
    property_get("dalvik.vm.checkjni", propBuf, "");
    if (strcmp(propBuf, "true") == 0) {
        checkJni = true;
    } else if (strcmp(propBuf, "false") != 0) {
        /* property is neither true nor false; fall back on kernel parameter */
        property_get("ro.kernel.android.checkjni", propBuf, "");
        if (propBuf[0] == '1') {
            checkJni = true;
        }
    }
    ALOGV("CheckJNI is %s/n", checkJni ? "ON" : "OFF");
    if (checkJni) {
        /* extended JNI checking */
        addOption("-Xcheck:jni");

        /* with -Xcheck:jni, this provides a JNI function call trace */
        //addOption("-verbose:jni");
    }

    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;
    }

    strcpy(jniOptsBuf, "-Xjniopts:");
    if (parseRuntimeOption("dalvik.vm.jniopts", jniOptsBuf, "-Xjniopts:")) {
        ALOGI("JNI options: '%s'/n", jniOptsBuf);
    }

    /* route exit() to our handler */
    addOption("exit", (void*) runtime_exit);

    /* route fprintf() to our handler */
    addOption("vfprintf", (void*) runtime_vfprintf);

    /* register the framework-specific "is sensitive thread" hook */
    addOption("sensitiveThread", (void*) runtime_isSensitiveThread);

    /* enable verbose; standard options are { jni, gc, class } */
    //addOption("-verbose:jni");
    addOption("-verbose:gc");
    //addOption("-verbose:class");

    if (primary_zygote) {
        addOption("-Xprimaryzygote");
    }

    /*
     * The default starting and maximum size of the heap.  Larger
     * values should be specified in a product property override.
     */
    parseRuntimeOption("dalvik.vm.heapstartsize", heapstartsizeOptsBuf, "-Xms", "4m");
    parseRuntimeOption("dalvik.vm.heapsize", heapsizeOptsBuf, "-Xmx", "16m");

    parseRuntimeOption("dalvik.vm.heapgrowthlimit", heapgrowthlimitOptsBuf, "-XX:HeapGrowthLimit=");
    parseRuntimeOption("dalvik.vm.heapminfree", heapminfreeOptsBuf, "-XX:HeapMinFree=");
    parseRuntimeOption("dalvik.vm.heapmaxfree", heapmaxfreeOptsBuf, "-XX:HeapMaxFree=");
    parseRuntimeOption("dalvik.vm.heaptargetutilization",
                       heaptargetutilizationOptsBuf,
                       "-XX:HeapTargetUtilization=");

    /* Foreground heap growth multiplier option */
    parseRuntimeOption("dalvik.vm.foreground-heap-growth-multiplier",
                       foregroundHeapGrowthMultiplierOptsBuf,
                       "-XX:ForegroundHeapGrowthMultiplier=");

    /*
     * JIT related options.
     */
    parseRuntimeOption("dalvik.vm.usejit", usejitOptsBuf, "-Xusejit:");
    parseRuntimeOption("dalvik.vm.jitmaxsize", jitmaxsizeOptsBuf, "-Xjitmaxsize:");
    parseRuntimeOption("dalvik.vm.jitinitialsize", jitinitialsizeOptsBuf, "-Xjitinitialsize:");
    parseRuntimeOption("dalvik.vm.jitthreshold", jitthresholdOptsBuf, "-Xjitthreshold:");
    parseRuntimeOption("dalvik.vm.jitpthreadpriority",
                       jitpthreadpriorityOptsBuf,
                       "-Xjitpthreadpriority:");
    property_get("dalvik.vm.usejitprofiles", useJitProfilesOptsBuf, "");
    if (strcmp(useJitProfilesOptsBuf, "true") == 0) {
        addOption("-Xjitsaveprofilinginfo");
    }

    parseRuntimeOption("dalvik.vm.jitprithreadweight",
                       jitprithreadweightOptBuf,
                       "-Xjitprithreadweight:");

    parseRuntimeOption("dalvik.vm.jittransitionweight",
                       jittransitionweightOptBuf,
                       "-Xjittransitionweight:");

    property_get("dalvik.vm.profilebootimage", propBuf, "");
    if (strcmp(propBuf, "true") == 0) {
        addOption("-Xps-profile-boot-class-path");
        addOption("-Xps-profile-aot-code");
    }

    /*
     * Madvise related options.
     */
    parseRuntimeOption("dalvik.vm.madvise-random", madviseRandomOptsBuf, "-XX:MadviseRandomAccess:");

    /*
     * Profile related options.
     */
    parseRuntimeOption("dalvik.vm.hot-startup-method-samples", hotstartupsamplesOptsBuf,
            "-Xps-hot-startup-method-samples:");

    property_get("ro.config.low_ram", propBuf, "");
    if (strcmp(propBuf, "true") == 0) {
      addOption("-XX:LowMemoryMode");
    }

    /*
     * Garbage-collection related options.
     */
    parseRuntimeOption("dalvik.vm.gctype", gctypeOptsBuf, "-Xgc:");

    // If it set, honor the "enable_generational_cc" device configuration;
    // otherwise, let the runtime use its default behavior.
    std::string enable_generational_cc =
        server_configurable_flags::GetServerConfigurableFlag(RUNTIME_NATIVE_BOOT_NAMESPACE,
                                                             ENABLE_GENERATIONAL_CC,
                                                             /*default_value=*/ "");
    if (enable_generational_cc == "true") {
        addOption(kGenerationalCCRuntimeOption);
    } else if (enable_generational_cc == "false") {
        addOption(kNoGenerationalCCRuntimeOption);
    }

    parseRuntimeOption("dalvik.vm.backgroundgctype", backgroundgcOptsBuf, "-XX:BackgroundGC=");

    /*
     * Enable debugging only for apps forked from zygote.
     */
    if (zygote) {
      // Set the JDWP provider and required arguments. By default let the runtime choose how JDWP is
      // implemented. When this is not set the runtime defaults to not allowing JDWP.
      addOption("-XjdwpOptions:suspend=n,server=y");
      parseRuntimeOption("dalvik.vm.jdwp-provider",
                         jdwpProviderBuf,
                         "-XjdwpProvider:",
                         "default");
    }

    parseRuntimeOption("dalvik.vm.lockprof.threshold",
                       lockProfThresholdBuf,
                       "-Xlockprofthreshold:");

    if (executionMode == kEMIntPortable) {
        addOption("-Xint:portable");
    } else if (executionMode == kEMIntFast) {
        addOption("-Xint:fast");
    } else if (executionMode == kEMJitCompiler) {
        addOption("-Xint:jit");
    }

    // If we are booting without the real /data, don't spend time compiling.
    property_get("vold.decrypt", voldDecryptBuf, "");
    bool skip_compilation = ((strcmp(voldDecryptBuf, "trigger_restart_min_framework") == 0) ||
                             (strcmp(voldDecryptBuf, "1") == 0));

    // Extra options for boot.art/boot.oat image generation.
    parseCompilerRuntimeOption("dalvik.vm.image-dex2oat-Xms", dex2oatXmsImageFlagsBuf,
                               "-Xms", "-Ximage-compiler-option");
    parseCompilerRuntimeOption("dalvik.vm.image-dex2oat-Xmx", dex2oatXmxImageFlagsBuf,
                               "-Xmx", "-Ximage-compiler-option");
    if (skip_compilation) {
        addOption("-Ximage-compiler-option");
        addOption("--compiler-filter=assume-verified");
    } else {
        parseCompilerOption("dalvik.vm.image-dex2oat-filter", dex2oatImageCompilerFilterBuf,
                            "--compiler-filter=", "-Ximage-compiler-option");
    }

    // If there is a boot profile, it takes precedence over the image and preloaded classes.
    if (hasFile("/system/etc/boot-image.prof")) {
        addOption("-Ximage-compiler-option");
        addOption("--profile-file=/system/etc/boot-image.prof");
        addOption("-Ximage-compiler-option");
        addOption("--compiler-filter=speed-profile");
    } else {
        // Make sure there is a preloaded-classes file.
        if (!hasFile("/system/etc/preloaded-classes")) {
            ALOGE("Missing preloaded-classes file, /system/etc/preloaded-classes not found: %s/n",
                  strerror(errno));
            return -1;
        }
        addOption("-Ximage-compiler-option");
        addOption("--image-classes=/system/etc/preloaded-classes");

        // If there is a dirty-image-objects file, push it.
        if (hasFile("/system/etc/dirty-image-objects")) {
            addOption("-Ximage-compiler-option");
            addOption("--dirty-image-objects=/system/etc/dirty-image-objects");
        }
    }

    property_get("dalvik.vm.image-dex2oat-flags", dex2oatImageFlagsBuf, "");
    parseExtraOpts(dex2oatImageFlagsBuf, "-Ximage-compiler-option");

    // Extra options for DexClassLoader.
    parseCompilerRuntimeOption("dalvik.vm.dex2oat-Xms", dex2oatXmsFlagsBuf,
                               "-Xms", "-Xcompiler-option");
    parseCompilerRuntimeOption("dalvik.vm.dex2oat-Xmx", dex2oatXmxFlagsBuf,
                               "-Xmx", "-Xcompiler-option");
    if (skip_compilation) {
        addOption("-Xcompiler-option");
        addOption("--compiler-filter=assume-verified");

        // We skip compilation when a minimal runtime is brought up for decryption. In that case
        // /data is temporarily backed by a tmpfs, which is usually small.
        // If the system image contains prebuilts, they will be relocated into the tmpfs. In this
        // specific situation it is acceptable to *not* relocate and run out of the prebuilts
        // directly instead.
        addOption("--runtime-arg");
        addOption("-Xnorelocate");
    } else {
        parseCompilerOption("dalvik.vm.dex2oat-filter", dex2oatCompilerFilterBuf,
                            "--compiler-filter=", "-Xcompiler-option");
    }
    parseCompilerOption("dalvik.vm.dex2oat-threads", dex2oatThreadsBuf, "-j", "-Xcompiler-option");
    parseCompilerOption("dalvik.vm.image-dex2oat-threads", dex2oatThreadsImageBuf, "-j",
                        "-Ximage-compiler-option");

    // The runtime will compile a boot image, when necessary, not using installd. Thus, we need to
    // pass the instruction-set-features/variant as an image-compiler-option.
    // Note: it is OK to reuse the buffer, as the values are exactly the same between
    //       * compiler-option, used for runtime compilation (DexClassLoader)
    //       * image-compiler-option, used for boot-image compilation on device

    // Copy the variant.
    sprintf(dex2oat_isa_variant_key, "dalvik.vm.isa.%s.variant", ABI_STRING);
    parseCompilerOption(dex2oat_isa_variant_key, dex2oat_isa_variant,
                        "--instruction-set-variant=", "-Ximage-compiler-option");
    parseCompilerOption(dex2oat_isa_variant_key, dex2oat_isa_variant,
                        "--instruction-set-variant=", "-Xcompiler-option");
    // Copy the features.
    sprintf(dex2oat_isa_features_key, "dalvik.vm.isa.%s.features", ABI_STRING);
    parseCompilerOption(dex2oat_isa_features_key, dex2oat_isa_features,
                        "--instruction-set-features=", "-Ximage-compiler-option");
    parseCompilerOption(dex2oat_isa_features_key, dex2oat_isa_features,
                        "--instruction-set-features=", "-Xcompiler-option");


    property_get("dalvik.vm.dex2oat-flags", dex2oatFlagsBuf, "");
    parseExtraOpts(dex2oatFlagsBuf, "-Xcompiler-option");

    /* extra options; parse this late so it overrides others */
    property_get("dalvik.vm.extra-opts", extraOptsBuf, "");
    parseExtraOpts(extraOptsBuf, NULL);

    /* Set the properties for locale */
    {
        strcpy(localeOption, "-Duser.locale=");
        const std::string locale = readLocale();
        strncat(localeOption, locale.c_str(), PROPERTY_VALUE_MAX);
        addOption(localeOption);
    }

    // Trace files are stored in /data/misc/trace which is writable only in debug mode.
    property_get("ro.debuggable", propBuf, "0");
    if (strcmp(propBuf, "1") == 0) {
        property_get("dalvik.vm.method-trace", propBuf, "false");
        if (strcmp(propBuf, "true") == 0) {
            addOption("-Xmethod-trace");
            parseRuntimeOption("dalvik.vm.method-trace-file",
                               methodTraceFileBuf,
                               "-Xmethod-trace-file:");
            parseRuntimeOption("dalvik.vm.method-trace-file-siz",
                               methodTraceFileSizeBuf,
                               "-Xmethod-trace-file-size:");
            property_get("dalvik.vm.method-trace-stream", propBuf, "false");
            if (strcmp(propBuf, "true") == 0) {
                addOption("-Xmethod-trace-stream");
            }
        }
    }

    // Native bridge library. "0" means that native bridge is disabled.
    //
    // Note: bridging is only enabled for the zygote. Other runs of
    //       app_process may not have the permissions to mount etc.
    property_get("ro.dalvik.vm.native.bridge", propBuf, "");
    if (propBuf[0] == '/0') {
        ALOGW("ro.dalvik.vm.native.bridge is not expected to be empty");
    } else if (zygote && strcmp(propBuf, "0") != 0) {
        snprintf(nativeBridgeLibrary, sizeof("-XX:NativeBridge=") + PROPERTY_VALUE_MAX,
                 "-XX:NativeBridge=%s", propBuf);
        addOption(nativeBridgeLibrary);
    }

#if defined(__LP64__)
    const char* cpu_abilist_property_name = "ro.product.cpu.abilist64";
#else
    const char* cpu_abilist_property_name = "ro.product.cpu.abilist32";
#endif  // defined(__LP64__)
    property_get(cpu_abilist_property_name, propBuf, "");
    if (propBuf[0] == '/0') {
        ALOGE("%s is not expected to be empty", cpu_abilist_property_name);
        return -1;
    }
    snprintf(cpuAbiListBuf, sizeof(cpuAbiListBuf), "--cpu-abilist=%s", propBuf);
    addOption(cpuAbiListBuf);

    // Dalvik-cache pruning counter.
    parseRuntimeOption("dalvik.vm.zygote.max-boot-retry", cachePruneBuf,
                       "-Xzygote-max-boot-retry=");

    /*
     * When running with debug.generate-debug-info, add --generate-debug-info to
     * the compiler options so that the boot image, if it is compiled on device,
     * will include native debugging information.
     */
    property_get("debug.generate-debug-info", propBuf, "");
    if (strcmp(propBuf, "true") == 0) {
        addOption("-Xcompiler-option");
        addOption("--generate-debug-info");
        addOption("-Ximage-compiler-option");
        addOption("--generate-debug-info");
    }

    // The mini-debug-info makes it possible to backtrace through JIT code.
    if (property_get_bool("dalvik.vm.minidebuginfo", 0)) {
        addOption("-Xcompiler-option");
        addOption("--generate-mini-debug-info");
    }

    // If set, the property below can be used to enable core platform API violation reporting.
    property_get("persist.debug.dalvik.vm.core_platform_api_policy", propBuf, "");
    if (propBuf[0] != '/0') {
      snprintf(corePlatformApiPolicyBuf,
               sizeof(corePlatformApiPolicyBuf),
               "-Xcore-platform-api-policy:%s",
               propBuf);
      addOption(corePlatformApiPolicyBuf);
    }

    /*
     * Retrieve the build fingerprint and provide it to the runtime. That way, ANR dumps will
     * contain the fingerprint and can be parsed.
     * Fingerprints are potentially longer than PROPERTY_VALUE_MAX, so parseRuntimeOption() cannot
     * be used here.
     * Do not ever re-assign fingerprintBuf as its c_str() value is stored in mOptions.
     */
    std::string fingerprint = GetProperty("ro.build.fingerprint", "");
    if (!fingerprint.empty()) {
        fingerprintBuf = "-Xfingerprint:" + fingerprint;
        addOption(fingerprintBuf.c_str());
    }

    initArgs.version = JNI_VERSION_1_4;
    initArgs.options = mOptions.editArray();
    initArgs.nOptions = mOptions.size();
    initArgs.ignoreUnrecognized = JNI_FALSE;

    /*
     * Initialize the VM.
     *
     * The JavaVM* is essentially per-process, and the JNIEnv* is per-thread.
     * If this call succeeds, the VM is ready, and we can start issuing
     * JNI calls.
     */
    if (JNI_CreateJavaVM(pJavaVM, pEnv, &initArgs) < 0) {
        ALOGE("JNI_CreateJavaVM failed/n");
        return -1;
    }

    return 0;
}int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv, bool zygote, bool primary_zygote)
{
    JavaVMInitArgs initArgs;
    char propBuf[PROPERTY_VALUE_MAX];
    char jniOptsBuf[sizeof("-Xjniopts:")-1 + PROPERTY_VALUE_MAX];
    char heapstartsizeOptsBuf[sizeof("-Xms")-1 + PROPERTY_VALUE_MAX];
    char heapsizeOptsBuf[sizeof("-Xmx")-1 + PROPERTY_VALUE_MAX];
    char heapgrowthlimitOptsBuf[sizeof("-XX:HeapGrowthLimit=")-1 + PROPERTY_VALUE_MAX];
    char heapminfreeOptsBuf[sizeof("-XX:HeapMinFree=")-1 + PROPERTY_VALUE_MAX];
    char heapmaxfreeOptsBuf[sizeof("-XX:HeapMaxFree=")-1 + PROPERTY_VALUE_MAX];
    char usejitOptsBuf[sizeof("-Xusejit:")-1 + PROPERTY_VALUE_MAX];
    char jitpthreadpriorityOptsBuf[sizeof("-Xjitpthreadpriority:")-1 + PROPERTY_VALUE_MAX];
    char jitmaxsizeOptsBuf[sizeof("-Xjitmaxsize:")-1 + PROPERTY_VALUE_MAX];
    char jitinitialsizeOptsBuf[sizeof("-Xjitinitialsize:")-1 + PROPERTY_VALUE_MAX];
    char jitthresholdOptsBuf[sizeof("-Xjitthreshold:")-1 + PROPERTY_VALUE_MAX];
    char useJitProfilesOptsBuf[sizeof("-Xjitsaveprofilinginfo:")-1 + PROPERTY_VALUE_MAX];
    char jitprithreadweightOptBuf[sizeof("-Xjitprithreadweight:")-1 + PROPERTY_VALUE_MAX];
    char jittransitionweightOptBuf[sizeof("-Xjittransitionweight:")-1 + PROPERTY_VALUE_MAX];
    char hotstartupsamplesOptsBuf[sizeof("-Xps-hot-startup-method-samples:")-1 + PROPERTY_VALUE_MAX];
    char madviseRandomOptsBuf[sizeof("-XX:MadviseRandomAccess:")-1 + PROPERTY_VALUE_MAX];
    char gctypeOptsBuf[sizeof("-Xgc:")-1 + PROPERTY_VALUE_MAX];
    char backgroundgcOptsBuf[sizeof("-XX:BackgroundGC=")-1 + PROPERTY_VALUE_MAX];
    char heaptargetutilizationOptsBuf[sizeof("-XX:HeapTargetUtilization=")-1 + PROPERTY_VALUE_MAX];
    char foregroundHeapGrowthMultiplierOptsBuf[
            sizeof("-XX:ForegroundHeapGrowthMultiplier=")-1 + PROPERTY_VALUE_MAX];
    char cachePruneBuf[sizeof("-Xzygote-max-boot-retry=")-1 + PROPERTY_VALUE_MAX];
    char dex2oatXmsImageFlagsBuf[sizeof("-Xms")-1 + PROPERTY_VALUE_MAX];
    char dex2oatXmxImageFlagsBuf[sizeof("-Xmx")-1 + PROPERTY_VALUE_MAX];
    char dex2oatXmsFlagsBuf[sizeof("-Xms")-1 + PROPERTY_VALUE_MAX];
    char dex2oatXmxFlagsBuf[sizeof("-Xmx")-1 + PROPERTY_VALUE_MAX];
    char dex2oatCompilerFilterBuf[sizeof("--compiler-filter=")-1 + PROPERTY_VALUE_MAX];
    char dex2oatImageCompilerFilterBuf[sizeof("--compiler-filter=")-1 + PROPERTY_VALUE_MAX];
    char dex2oatThreadsBuf[sizeof("-j")-1 + PROPERTY_VALUE_MAX];
    char dex2oatThreadsImageBuf[sizeof("-j")-1 + PROPERTY_VALUE_MAX];
    char dex2oat_isa_variant_key[PROPERTY_KEY_MAX];
    char dex2oat_isa_variant[sizeof("--instruction-set-variant=") -1 + PROPERTY_VALUE_MAX];
    char dex2oat_isa_features_key[PROPERTY_KEY_MAX];
    char dex2oat_isa_features[sizeof("--instruction-set-features=") -1 + PROPERTY_VALUE_MAX];
    char dex2oatFlagsBuf[PROPERTY_VALUE_MAX];
    char dex2oatImageFlagsBuf[PROPERTY_VALUE_MAX];
    char extraOptsBuf[PROPERTY_VALUE_MAX];
    char voldDecryptBuf[PROPERTY_VALUE_MAX];
    enum {
      kEMDefault,
      kEMIntPortable,
      kEMIntFast,
      kEMJitCompiler,
    } executionMode = kEMDefault;
    char localeOption[sizeof("-Duser.locale=") + PROPERTY_VALUE_MAX];
    char lockProfThresholdBuf[sizeof("-Xlockprofthreshold:")-1 + PROPERTY_VALUE_MAX];
    char nativeBridgeLibrary[sizeof("-XX:NativeBridge=") + PROPERTY_VALUE_MAX];
    char cpuAbiListBuf[sizeof("--cpu-abilist=") + PROPERTY_VALUE_MAX];
    char corePlatformApiPolicyBuf[sizeof("-Xcore-platform-api-policy:") + PROPERTY_VALUE_MAX];
    char methodTraceFileBuf[sizeof("-Xmethod-trace-file:") + PROPERTY_VALUE_MAX];
    char methodTraceFileSizeBuf[sizeof("-Xmethod-trace-file-size:") + PROPERTY_VALUE_MAX];
    std::string fingerprintBuf;
    char jdwpProviderBuf[sizeof("-XjdwpProvider:") - 1 + PROPERTY_VALUE_MAX];
    char bootImageBuf[sizeof("-Ximage:") - 1 + PROPERTY_VALUE_MAX];

    std::string use_apex_image =
        server_configurable_flags::GetServerConfigurableFlag(RUNTIME_NATIVE_BOOT_NAMESPACE,
                                                             ENABLE_APEX_IMAGE,
                                                             /*default_value=*/ "");
    if (use_apex_image == "true") {
        addOption(kApexImageOption);
        ALOGI("Using Apex boot image: '%s'/n", kApexImageOption);
    } else if (parseRuntimeOption("dalvik.vm.boot-image", bootImageBuf, "-Ximage:")) {
        ALOGI("Using dalvik.vm.boot-image: '%s'/n", bootImageBuf);
    } else {
        ALOGI("Using default boot image");
    }

    std::string disable_lock_profiling =
        server_configurable_flags::GetServerConfigurableFlag(RUNTIME_NATIVE_BOOT_NAMESPACE,
                                                             DISABLE_LOCK_PROFILING,
                                                             /*default_value=*/ "");
    if (disable_lock_profiling == "true") {
        addOption(kLockProfThresholdRuntimeOption);
        ALOGI("Disabling lock profiling: '%s'/n", kLockProfThresholdRuntimeOption);
    } else {
        ALOGI("Leaving lock profiling enabled");
    }

    bool checkJni = false;
    property_get("dalvik.vm.checkjni", propBuf, "");
    if (strcmp(propBuf, "true") == 0) {
        checkJni = true;
    } else if (strcmp(propBuf, "false") != 0) {
        /* property is neither true nor false; fall back on kernel parameter */
        property_get("ro.kernel.android.checkjni", propBuf, "");
        if (propBuf[0] == '1') {
            checkJni = true;
        }
    }
    ALOGV("CheckJNI is %s/n", checkJni ? "ON" : "OFF");
    if (checkJni) {
        /* extended JNI checking */
        addOption("-Xcheck:jni");

        /* with -Xcheck:jni, this provides a JNI function call trace */
        //addOption("-verbose:jni");
    }

    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;
    }

    strcpy(jniOptsBuf, "-Xjniopts:");
    if (parseRuntimeOption("dalvik.vm.jniopts", jniOptsBuf, "-Xjniopts:")) {
        ALOGI("JNI options: '%s'/n", jniOptsBuf);
    }

    /* route exit() to our handler */
    addOption("exit", (void*) runtime_exit);

    /* route fprintf() to our handler */
    addOption("vfprintf", (void*) runtime_vfprintf);

    /* register the framework-specific "is sensitive thread" hook */
    addOption("sensitiveThread", (void*) runtime_isSensitiveThread);

    /* enable verbose; standard options are { jni, gc, class } */
    //addOption("-verbose:jni");
    addOption("-verbose:gc");
    //addOption("-verbose:class");

    if (primary_zygote) {
        addOption("-Xprimaryzygote");
    }

    /*
     * The default starting and maximum size of the heap.  Larger
     * values should be specified in a product property override.
     */
    parseRuntimeOption("dalvik.vm.heapstartsize", heapstartsizeOptsBuf, "-Xms", "4m");
    parseRuntimeOption("dalvik.vm.heapsize", heapsizeOptsBuf, "-Xmx", "16m");

    parseRuntimeOption("dalvik.vm.heapgrowthlimit", heapgrowthlimitOptsBuf, "-XX:HeapGrowthLimit=");
    parseRuntimeOption("dalvik.vm.heapminfree", heapminfreeOptsBuf, "-XX:HeapMinFree=");
    parseRuntimeOption("dalvik.vm.heapmaxfree", heapmaxfreeOptsBuf, "-XX:HeapMaxFree=");
    parseRuntimeOption("dalvik.vm.heaptargetutilization",
                       heaptargetutilizationOptsBuf,
                       "-XX:HeapTargetUtilization=");

    /* Foreground heap growth multiplier option */
    parseRuntimeOption("dalvik.vm.foreground-heap-growth-multiplier",
                       foregroundHeapGrowthMultiplierOptsBuf,
                       "-XX:ForegroundHeapGrowthMultiplier=");

    /*
     * JIT related options.
     */
    parseRuntimeOption("dalvik.vm.usejit", usejitOptsBuf, "-Xusejit:");
    parseRuntimeOption("dalvik.vm.jitmaxsize", jitmaxsizeOptsBuf, "-Xjitmaxsize:");
    parseRuntimeOption("dalvik.vm.jitinitialsize", jitinitialsizeOptsBuf, "-Xjitinitialsize:");
    parseRuntimeOption("dalvik.vm.jitthreshold", jitthresholdOptsBuf, "-Xjitthreshold:");
    parseRuntimeOption("dalvik.vm.jitpthreadpriority",
                       jitpthreadpriorityOptsBuf,
                       "-Xjitpthreadpriority:");
    property_get("dalvik.vm.usejitprofiles", useJitProfilesOptsBuf, "");
    if (strcmp(useJitProfilesOptsBuf, "true") == 0) {
        addOption("-Xjitsaveprofilinginfo");
    }

    parseRuntimeOption("dalvik.vm.jitprithreadweight",
                       jitprithreadweightOptBuf,
                       "-Xjitprithreadweight:");

    parseRuntimeOption("dalvik.vm.jittransitionweight",
                       jittransitionweightOptBuf,
                       "-Xjittransitionweight:");

    property_get("dalvik.vm.profilebootimage", propBuf, "");
    if (strcmp(propBuf, "true") == 0) {
        addOption("-Xps-profile-boot-class-path");
        addOption("-Xps-profile-aot-code");
    }

    /*
     * Madvise related options.
     */
    parseRuntimeOption("dalvik.vm.madvise-random", madviseRandomOptsBuf, "-XX:MadviseRandomAccess:");

    /*
     * Profile related options.
     */
    parseRuntimeOption("dalvik.vm.hot-startup-method-samples", hotstartupsamplesOptsBuf,
            "-Xps-hot-startup-method-samples:");

    property_get("ro.config.low_ram", propBuf, "");
    if (strcmp(propBuf, "true") == 0) {
      addOption("-XX:LowMemoryMode");
    }

    /*
     * Garbage-collection related options.
     */
    parseRuntimeOption("dalvik.vm.gctype", gctypeOptsBuf, "-Xgc:");

    // If it set, honor the "enable_generational_cc" device configuration;
    // otherwise, let the runtime use its default behavior.
    std::string enable_generational_cc =
        server_configurable_flags::GetServerConfigurableFlag(RUNTIME_NATIVE_BOOT_NAMESPACE,
                                                             ENABLE_GENERATIONAL_CC,
                                                             /*default_value=*/ "");
    if (enable_generational_cc == "true") {
        addOption(kGenerationalCCRuntimeOption);
    } else if (enable_generational_cc == "false") {
        addOption(kNoGenerationalCCRuntimeOption);
    }

    parseRuntimeOption("dalvik.vm.backgroundgctype", backgroundgcOptsBuf, "-XX:BackgroundGC=");

    /*
     * Enable debugging only for apps forked from zygote.
     */
    if (zygote) {
      // Set the JDWP provider and required arguments. By default let the runtime choose how JDWP is
      // implemented. When this is not set the runtime defaults to not allowing JDWP.
      addOption("-XjdwpOptions:suspend=n,server=y");
      parseRuntimeOption("dalvik.vm.jdwp-provider",
                         jdwpProviderBuf,
                         "-XjdwpProvider:",
                         "default");
    }

    parseRuntimeOption("dalvik.vm.lockprof.threshold",
                       lockProfThresholdBuf,
                       "-Xlockprofthreshold:");

    if (executionMode == kEMIntPortable) {
        addOption("-Xint:portable");
    } else if (executionMode == kEMIntFast) {
        addOption("-Xint:fast");
    } else if (executionMode == kEMJitCompiler) {
        addOption("-Xint:jit");
    }

    // If we are booting without the real /data, don't spend time compiling.
    property_get("vold.decrypt", voldDecryptBuf, "");
    bool skip_compilation = ((strcmp(voldDecryptBuf, "trigger_restart_min_framework") == 0) ||
                             (strcmp(voldDecryptBuf, "1") == 0));

    // Extra options for boot.art/boot.oat image generation.
    parseCompilerRuntimeOption("dalvik.vm.image-dex2oat-Xms", dex2oatXmsImageFlagsBuf,
                               "-Xms", "-Ximage-compiler-option");
    parseCompilerRuntimeOption("dalvik.vm.image-dex2oat-Xmx", dex2oatXmxImageFlagsBuf,
                               "-Xmx", "-Ximage-compiler-option");
    if (skip_compilation) {
        addOption("-Ximage-compiler-option");
        addOption("--compiler-filter=assume-verified");
    } else {
        parseCompilerOption("dalvik.vm.image-dex2oat-filter", dex2oatImageCompilerFilterBuf,
                            "--compiler-filter=", "-Ximage-compiler-option");
    }

    // If there is a boot profile, it takes precedence over the image and preloaded classes.
    if (hasFile("/system/etc/boot-image.prof")) {
        addOption("-Ximage-compiler-option");
        addOption("--profile-file=/system/etc/boot-image.prof");
        addOption("-Ximage-compiler-option");
        addOption("--compiler-filter=speed-profile");
    } else {
        // Make sure there is a preloaded-classes file.
        if (!hasFile("/system/etc/preloaded-classes")) {
            ALOGE("Missing preloaded-classes file, /system/etc/preloaded-classes not found: %s/n",
                  strerror(errno));
            return -1;
        }
        addOption("-Ximage-compiler-option");
        addOption("--image-classes=/system/etc/preloaded-classes");

        // If there is a dirty-image-objects file, push it.
        if (hasFile("/system/etc/dirty-image-objects")) {
            addOption("-Ximage-compiler-option");
            addOption("--dirty-image-objects=/system/etc/dirty-image-objects");
        }
    }

    property_get("dalvik.vm.image-dex2oat-flags", dex2oatImageFlagsBuf, "");
    parseExtraOpts(dex2oatImageFlagsBuf, "-Ximage-compiler-option");

    // Extra options for DexClassLoader.
    parseCompilerRuntimeOption("dalvik.vm.dex2oat-Xms", dex2oatXmsFlagsBuf,
                               "-Xms", "-Xcompiler-option");
    parseCompilerRuntimeOption("dalvik.vm.dex2oat-Xmx", dex2oatXmxFlagsBuf,
                               "-Xmx", "-Xcompiler-option");
    if (skip_compilation) {
        addOption("-Xcompiler-option");
        addOption("--compiler-filter=assume-verified");

        // We skip compilation when a minimal runtime is brought up for decryption. In that case
        // /data is temporarily backed by a tmpfs, which is usually small.
        // If the system image contains prebuilts, they will be relocated into the tmpfs. In this
        // specific situation it is acceptable to *not* relocate and run out of the prebuilts
        // directly instead.
        addOption("--runtime-arg");
        addOption("-Xnorelocate");
    } else {
        parseCompilerOption("dalvik.vm.dex2oat-filter", dex2oatCompilerFilterBuf,
                            "--compiler-filter=", "-Xcompiler-option");
    }
    parseCompilerOption("dalvik.vm.dex2oat-threads", dex2oatThreadsBuf, "-j", "-Xcompiler-option");
    parseCompilerOption("dalvik.vm.image-dex2oat-threads", dex2oatThreadsImageBuf, "-j",
                        "-Ximage-compiler-option");

    // The runtime will compile a boot image, when necessary, not using installd. Thus, we need to
    // pass the instruction-set-features/variant as an image-compiler-option.
    // Note: it is OK to reuse the buffer, as the values are exactly the same between
    //       * compiler-option, used for runtime compilation (DexClassLoader)
    //       * image-compiler-option, used for boot-image compilation on device

    // Copy the variant.
    sprintf(dex2oat_isa_variant_key, "dalvik.vm.isa.%s.variant", ABI_STRING);
    parseCompilerOption(dex2oat_isa_variant_key, dex2oat_isa_variant,
                        "--instruction-set-variant=", "-Ximage-compiler-option");
    parseCompilerOption(dex2oat_isa_variant_key, dex2oat_isa_variant,
                        "--instruction-set-variant=", "-Xcompiler-option");
    // Copy the features.
    sprintf(dex2oat_isa_features_key, "dalvik.vm.isa.%s.features", ABI_STRING);
    parseCompilerOption(dex2oat_isa_features_key, dex2oat_isa_features,
                        "--instruction-set-features=", "-Ximage-compiler-option");
    parseCompilerOption(dex2oat_isa_features_key, dex2oat_isa_features,
                        "--instruction-set-features=", "-Xcompiler-option");


    property_get("dalvik.vm.dex2oat-flags", dex2oatFlagsBuf, "");
    parseExtraOpts(dex2oatFlagsBuf, "-Xcompiler-option");

    /* extra options; parse this late so it overrides others */
    property_get("dalvik.vm.extra-opts", extraOptsBuf, "");
    parseExtraOpts(extraOptsBuf, NULL);

    /* Set the properties for locale */
    {
        strcpy(localeOption, "-Duser.locale=");
        const std::string locale = readLocale();
        strncat(localeOption, locale.c_str(), PROPERTY_VALUE_MAX);
        addOption(localeOption);
    }

    // Trace files are stored in /data/misc/trace which is writable only in debug mode.
    property_get("ro.debuggable", propBuf, "0");
    if (strcmp(propBuf, "1") == 0) {
        property_get("dalvik.vm.method-trace", propBuf, "false");
        if (strcmp(propBuf, "true") == 0) {
            addOption("-Xmethod-trace");
            parseRuntimeOption("dalvik.vm.method-trace-file",
                               methodTraceFileBuf,
                               "-Xmethod-trace-file:");
            parseRuntimeOption("dalvik.vm.method-trace-file-siz",
                               methodTraceFileSizeBuf,
                               "-Xmethod-trace-file-size:");
            property_get("dalvik.vm.method-trace-stream", propBuf, "false");
            if (strcmp(propBuf, "true") == 0) {
                addOption("-Xmethod-trace-stream");
            }
        }
    }

    // Native bridge library. "0" means that native bridge is disabled.
    //
    // Note: bridging is only enabled for the zygote. Other runs of
    //       app_process may not have the permissions to mount etc.
    property_get("ro.dalvik.vm.native.bridge", propBuf, "");
    if (propBuf[0] == '/0') {
        ALOGW("ro.dalvik.vm.native.bridge is not expected to be empty");
    } else if (zygote && strcmp(propBuf, "0") != 0) {
        snprintf(nativeBridgeLibrary, sizeof("-XX:NativeBridge=") + PROPERTY_VALUE_MAX,
                 "-XX:NativeBridge=%s", propBuf);
        addOption(nativeBridgeLibrary);
    }

#if defined(__LP64__)
    const char* cpu_abilist_property_name = "ro.product.cpu.abilist64";
#else
    const char* cpu_abilist_property_name = "ro.product.cpu.abilist32";
#endif  // defined(__LP64__)
    property_get(cpu_abilist_property_name, propBuf, "");
    if (propBuf[0] == '/0') {
        ALOGE("%s is not expected to be empty", cpu_abilist_property_name);
        return -1;
    }
    snprintf(cpuAbiListBuf, sizeof(cpuAbiListBuf), "--cpu-abilist=%s", propBuf);
    addOption(cpuAbiListBuf);

    // Dalvik-cache pruning counter.
    parseRuntimeOption("dalvik.vm.zygote.max-boot-retry", cachePruneBuf,
                       "-Xzygote-max-boot-retry=");

    /*
     * When running with debug.generate-debug-info, add --generate-debug-info to
     * the compiler options so that the boot image, if it is compiled on device,
     * will include native debugging information.
     */
    property_get("debug.generate-debug-info", propBuf, "");
    if (strcmp(propBuf, "true") == 0) {
        addOption("-Xcompiler-option");
        addOption("--generate-debug-info");
        addOption("-Ximage-compiler-option");
        addOption("--generate-debug-info");
    }

    // The mini-debug-info makes it possible to backtrace through JIT code.
    if (property_get_bool("dalvik.vm.minidebuginfo", 0)) {
        addOption("-Xcompiler-option");
        addOption("--generate-mini-debug-info");
    }

    // If set, the property below can be used to enable core platform API violation reporting.
    property_get("persist.debug.dalvik.vm.core_platform_api_policy", propBuf, "");
    if (propBuf[0] != '/0') {
      snprintf(corePlatformApiPolicyBuf,
               sizeof(corePlatformApiPolicyBuf),
               "-Xcore-platform-api-policy:%s",
               propBuf);
      addOption(corePlatformApiPolicyBuf);
    }

    /*
     * Retrieve the build fingerprint and provide it to the runtime. That way, ANR dumps will
     * contain the fingerprint and can be parsed.
     * Fingerprints are potentially longer than PROPERTY_VALUE_MAX, so parseRuntimeOption() cannot
     * be used here.
     * Do not ever re-assign fingerprintBuf as its c_str() value is stored in mOptions.
     */
    std::string fingerprint = GetProperty("ro.build.fingerprint", "");
    if (!fingerprint.empty()) {
        fingerprintBuf = "-Xfingerprint:" + fingerprint;
        addOption(fingerprintBuf.c_str());
    }

    initArgs.version = JNI_VERSION_1_4;
    initArgs.options = mOptions.editArray();
    initArgs.nOptions = mOptions.size();
    initArgs.ignoreUnrecognized = JNI_FALSE;

    /*
     * Initialize the VM.
     *
     * The JavaVM* is essentially per-process, and the JNIEnv* is per-thread.
     * If this call succeeds, the VM is ready, and we can start issuing
     * JNI calls.
     */
    if (JNI_CreateJavaVM(pJavaVM, pEnv, &initArgs) < 0) {
        ALOGE("JNI_CreateJavaVM failed/n");
        return -1;
    }

    return 0;
}

startVM主要是对虚拟机的一些参数进行配置,配置完成之后才执行JNI_CreateJavaVM方法。这个方法会创建JavaVM,每个进程都有一个JNIEnv,虚拟机创建完成之后就可进行JNI的调用。

2.2.1 JNI_CreateJavaVM

[->java_vm_ext.cc]


// JNI Invocation interface.

extern "C" jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) {
  ScopedTrace trace(__FUNCTION__);
  const JavaVMInitArgs* args = static_cast<JavaVMInitArgs*>(vm_args);
  if (JavaVMExt::IsBadJniVersion(args->version)) {
    LOG(ERROR) << "Bad JNI version passed to CreateJavaVM: " << args->version;
    return JNI_EVERSION;
  }
  RuntimeOptions options;
  for (int i = 0; i < args->nOptions; ++i) {
    JavaVMOption* option = &args->options[i];
    options.push_back(std::make_pair(std::string(option->optionString), option->extraInfo));
  }
  bool ignore_unrecognized = args->ignoreUnrecognized;
  //创建Runtime
  if (!Runtime::Create(options, ignore_unrecognized)) {
    return JNI_ERR;
  }

  // Initialize native loader. This step makes sure we have
  // everything set up before we start using JNI.
  android::InitializeNativeLoader();

  Runtime* runtime = Runtime::Current();
  //启动Runtime
  bool started = runtime->Start();
  if (!started) {
    delete Thread::Current()->GetJniEnv();
    delete runtime->GetJavaVM();
    LOG(WARNING) << "CreateJavaVM failed";
    return JNI_ERR;
  }

  *p_env = Thread::Current()->GetJniEnv();
  *p_vm = runtime->GetJavaVM();
  return JNI_OK;
}

Runtime表示当前进程ART虚拟机实例

2.2.2 Runtime::Create

bool Runtime::Create(const RuntimeOptions& raw_options, bool ignore_unrecognized) {
  RuntimeArgumentMap runtime_options;
  return ParseOptions(raw_options, ignore_unrecognized, &runtime_options) &&
      Create(std::move(runtime_options));
}

bool Runtime::Create(RuntimeArgumentMap&& runtime_options) {
  // TODO: acquire a static mutex on Runtime to avoid racing.
  if (Runtime::instance_ != nullptr) {
    return false;
  }
  instance_ = new Runtime;
  Locks::SetClientCallback(IsSafeToCallAbort);
  if (!instance_->Init(std::move(runtime_options))) {
    // TODO: Currently deleting the instance will abort the runtime on destruction. Now This will
    // leak memory, instead. Fix the destructor. b/19100793.
    // delete instance_;
    instance_ = nullptr;
    return false;
  }
  return true;
}
2.2.3 Runtime::Init

[->runtime.cc]


bool Runtime::Init(RuntimeArgumentMap&& runtime_options_in) {
  // (b/30160149): protect subprocesses from modifications to LD_LIBRARY_PATH, etc.
  // Take a snapshot of the environment at the time the runtime was created, for use by Exec, etc.
  env_snapshot_.TakeSnapshot();

  using Opt = RuntimeArgumentMap;
  Opt runtime_options(std::move(runtime_options_in));
  ScopedTrace trace(__FUNCTION__);
  CHECK_EQ(sysconf(_SC_PAGE_SIZE), kPageSize);

  // Early override for logging output.
  if (runtime_options.Exists(Opt::UseStderrLogger)) {
    android::base::SetLogger(android::base::StderrLogger);
  }

  MemMap::Init();

  // Try to reserve a dedicated fault page. This is allocated for clobbered registers and sentinels.
  // If we cannot reserve it, log a warning.
  // Note: We allocate this first to have a good chance of grabbing the page. The address (0xebad..)
  //       is out-of-the-way enough that it should not collide with boot image mapping.
  // Note: Don't request an error message. That will lead to a maps dump in the case of failure,
  //       leading to logspam.
  {
    constexpr uintptr_t kSentinelAddr =
        RoundDown(static_cast<uintptr_t>(Context::kBadGprBase), kPageSize);
    protected_fault_page_.reset(MemMap::MapAnonymous("Sentinel fault page",
                                                     reinterpret_cast<uint8_t*>(kSentinelAddr),
                                                     kPageSize,
                                                     PROT_NONE,
                                                     /* low_4g */ true,
                                                     /* reuse */ false,
                                                     /* error_msg */ nullptr));
    if (protected_fault_page_ == nullptr) {
      LOG(WARNING) << "Could not reserve sentinel fault page";
    } else if (reinterpret_cast<uintptr_t>(protected_fault_page_->Begin()) != kSentinelAddr) {
      LOG(WARNING) << "Could not reserve sentinel fault page at the right address.";
      protected_fault_page_.reset();
    }
  }

  VLOG(startup) << "Runtime::Init -verbose:startup enabled";

  QuasiAtomic::Startup();

  oat_file_manager_ = new OatFileManager;

  Thread::SetSensitiveThreadHook(runtime_options.GetOrDefault(Opt::HookIsSensitiveThread));
  Monitor::Init(runtime_options.GetOrDefault(Opt::LockProfThreshold),
                runtime_options.GetOrDefault(Opt::StackDumpLockProfThreshold));

  boot_class_path_string_ = runtime_options.ReleaseOrDefault(Opt::BootClassPath);
  class_path_string_ = runtime_options.ReleaseOrDefault(Opt::ClassPath);
  properties_ = runtime_options.ReleaseOrDefault(Opt::PropertiesList);

  compiler_callbacks_ = runtime_options.GetOrDefault(Opt::CompilerCallbacksPtr);
  patchoat_executable_ = runtime_options.ReleaseOrDefault(Opt::PatchOat);
  must_relocate_ = runtime_options.GetOrDefault(Opt::Relocate);
  is_zygote_ = runtime_options.Exists(Opt::Zygote);
  is_explicit_gc_disabled_ = runtime_options.Exists(Opt::DisableExplicitGC);
  dex2oat_enabled_ = runtime_options.GetOrDefault(Opt::Dex2Oat);
  image_dex2oat_enabled_ = runtime_options.GetOrDefault(Opt::ImageDex2Oat);
  dump_native_stack_on_sig_quit_ = runtime_options.GetOrDefault(Opt::DumpNativeStackOnSigQuit);

  vfprintf_ = runtime_options.GetOrDefault(Opt::HookVfprintf);
  exit_ = runtime_options.GetOrDefault(Opt::HookExit);
  abort_ = runtime_options.GetOrDefault(Opt::HookAbort);

  default_stack_size_ = runtime_options.GetOrDefault(Opt::StackSize);
  use_tombstoned_traces_ = runtime_options.GetOrDefault(Opt::UseTombstonedTraces);
#if !defined(ART_TARGET_ANDROID)
  CHECK(!use_tombstoned_traces_)
      << "-Xusetombstonedtraces is only supported in an Android environment";
#endif
  stack_trace_file_ = runtime_options.ReleaseOrDefault(Opt::StackTraceFile);

  compiler_executable_ = runtime_options.ReleaseOrDefault(Opt::Compiler);
  compiler_options_ = runtime_options.ReleaseOrDefault(Opt::CompilerOptions);
  for (StringPiece option : Runtime::Current()->GetCompilerOptions()) {
    if (option.starts_with("--debuggable")) {
      SetJavaDebuggable(true);
      break;
    }
  }
  image_compiler_options_ = runtime_options.ReleaseOrDefault(Opt::ImageCompilerOptions);
  image_location_ = runtime_options.GetOrDefault(Opt::Image);

  max_spins_before_thin_lock_inflation_ =
      runtime_options.GetOrDefault(Opt::MaxSpinsBeforeThinLockInflation);

  monitor_list_ = new MonitorList;
  monitor_pool_ = MonitorPool::Create();
  thread_list_ = new ThreadList(runtime_options.GetOrDefault(Opt::ThreadSuspendTimeout));
  intern_table_ = new InternTable;

  verify_ = runtime_options.GetOrDefault(Opt::Verify);
  allow_dex_file_fallback_ = !runtime_options.Exists(Opt::NoDexFileFallback);

  target_sdk_version_ = runtime_options.GetOrDefault(Opt::TargetSdkVersion);

  // Check whether to enforce hidden API access checks. The checks are disabled
  // by default and we only enable them if:
  // (a) runtime was started with a flag that enables the checks, or
  // (b) Zygote forked a new process that is not exempt (see ZygoteHooks).
  //hidden_api检查
  bool do_hidden_api_checks = runtime_options.Exists(Opt::HiddenApiChecks);
  DCHECK(!is_zygote_ || !do_hidden_api_checks);
  // TODO pass the actual enforcement policy in, rather than just a single bit.
  // As is, we're encoding some logic here about which specific policy to use, which would be better
  // controlled by the framework.
  hidden_api_policy_ = do_hidden_api_checks
      ? hiddenapi::EnforcementPolicy::kDarkGreyAndBlackList
      : hiddenapi::EnforcementPolicy::kNoChecks;

  no_sig_chain_ = runtime_options.Exists(Opt::NoSigChain);
  force_native_bridge_ = runtime_options.Exists(Opt::ForceNativeBridge);

  Split(runtime_options.GetOrDefault(Opt::CpuAbiList), ',', &cpu_abilist_);

  fingerprint_ = runtime_options.ReleaseOrDefault(Opt::Fingerprint);

  if (runtime_options.GetOrDefault(Opt::Interpret)) {
    GetInstrumentation()->ForceInterpretOnly();
  }

  zygote_max_failed_boots_ = runtime_options.GetOrDefault(Opt::ZygoteMaxFailedBoots);
  experimental_flags_ = runtime_options.GetOrDefault(Opt::Experimental);
  is_low_memory_mode_ = runtime_options.Exists(Opt::LowMemoryMode);
  madvise_random_access_ = runtime_options.GetOrDefault(Opt::MadviseRandomAccess);

  plugins_ = runtime_options.ReleaseOrDefault(Opt::Plugins);
  agent_specs_ = runtime_options.ReleaseOrDefault(Opt::AgentPath);
  // TODO Add back in -agentlib
  // for (auto lib : runtime_options.ReleaseOrDefault(Opt::AgentLib)) {
  //   agents_.push_back(lib);
  // }

  float foreground_heap_growth_multiplier;
  if (is_low_memory_mode_ && !runtime_options.Exists(Opt::ForegroundHeapGrowthMultiplier)) {
    // If low memory mode, use 1.0 as the multiplier by default.
    foreground_heap_growth_multiplier = 1.0f;
  } else {
    foreground_heap_growth_multiplier =
        runtime_options.GetOrDefault(Opt::ForegroundHeapGrowthMultiplier) +
            kExtraDefaultHeapGrowthMultiplier;
  }
  XGcOption xgc_option = runtime_options.GetOrDefault(Opt::GcOption);
  //创建堆
  heap_ = new gc::Heap(runtime_options.GetOrDefault(Opt::MemoryInitialSize),
                       runtime_options.GetOrDefault(Opt::HeapGrowthLimit),
                       runtime_options.GetOrDefault(Opt::HeapMinFree),
                       runtime_options.GetOrDefault(Opt::HeapMaxFree),
                       runtime_options.GetOrDefault(Opt::HeapTargetUtilization),
                       foreground_heap_growth_multiplier,
                       runtime_options.GetOrDefault(Opt::MemoryMaximumSize),
                       runtime_options.GetOrDefault(Opt::NonMovingSpaceCapacity),
                       runtime_options.GetOrDefault(Opt::Image),
                       runtime_options.GetOrDefault(Opt::ImageInstructionSet),
                       // Override the collector type to CC if the read barrier config.
                       kUseReadBarrier ? gc::kCollectorTypeCC : xgc_option.collector_type_,
                       kUseReadBarrier ? BackgroundGcOption(gc::kCollectorTypeCCBackground)
                                       : runtime_options.GetOrDefault(Opt::BackgroundGc),
                       runtime_options.GetOrDefault(Opt::LargeObjectSpace),
                       runtime_options.GetOrDefault(Opt::LargeObjectThreshold),
                       runtime_options.GetOrDefault(Opt::ParallelGCThreads),
                       runtime_options.GetOrDefault(Opt::ConcGCThreads),
                       runtime_options.Exists(Opt::LowMemoryMode),
                       runtime_options.GetOrDefault(Opt::LongPauseLogThreshold),
                       runtime_options.GetOrDefault(Opt::LongGCLogThreshold),
                       runtime_options.Exists(Opt::IgnoreMaxFootprint),
                       runtime_options.GetOrDefault(Opt::UseTLAB),
                       xgc_option.verify_pre_gc_heap_,
                       xgc_option.verify_pre_sweeping_heap_,
                       xgc_option.verify_post_gc_heap_,
                       xgc_option.verify_pre_gc_rosalloc_,
                       xgc_option.verify_pre_sweeping_rosalloc_,
                       xgc_option.verify_post_gc_rosalloc_,
                       xgc_option.gcstress_,
                       xgc_option.measure_,
                       runtime_options.GetOrDefault(Opt::EnableHSpaceCompactForOOM),
                       runtime_options.GetOrDefault(Opt::HSpaceCompactForOOMMinIntervalsMs));

  if (!heap_->HasBootImageSpace() && !allow_dex_file_fallback_) {
    LOG(ERROR) << "Dex file fallback disabled, cannot continue without image.";
    return false;
  }

  dump_gc_performance_on_shutdown_ = runtime_options.Exists(Opt::DumpGCPerformanceOnShutdown);

  jdwp_options_ = runtime_options.GetOrDefault(Opt::JdwpOptions);
  jdwp_provider_ = runtime_options.GetOrDefault(Opt::JdwpProvider);
  switch (jdwp_provider_) {
    case JdwpProvider::kNone: {
      VLOG(jdwp) << "Disabling all JDWP support.";
      if (!jdwp_options_.empty()) {
        bool has_transport = jdwp_options_.find("transport") != std::string::npos;
        const char* transport_internal = !has_transport ? "transport=dt_android_adb," : "";
        std::string adb_connection_args =
            std::string("  -XjdwpProvider:adbconnection -XjdwpOptions:") + jdwp_options_;
        LOG(WARNING) << "Jdwp options given when jdwp is disabled! You probably want to enable "
                     << "jdwp with one of:" << std::endl
                     << "  -XjdwpProvider:internal "
                     << "-XjdwpOptions:" << transport_internal << jdwp_options_ << std::endl
                     << "  -Xplugin:libopenjdkjvmti" << (kIsDebugBuild ? "d" : "") << ".so "
                     << "-agentpath:libjdwp.so=" << jdwp_options_ << std::endl
                     << (has_transport ? "" : adb_connection_args);
      }
      break;
    }
    case JdwpProvider::kInternal: {
      if (runtime_options.Exists(Opt::JdwpOptions)) {
        JDWP::JdwpOptions ops;
        if (!JDWP::ParseJdwpOptions(runtime_options.GetOrDefault(Opt::JdwpOptions), &ops)) {
          LOG(ERROR) << "failed to parse jdwp options!";
          return false;
        }
        Dbg::ConfigureJdwp(ops);
      }
      break;
    }
    case JdwpProvider::kAdbConnection: {
      constexpr const char* plugin_name = kIsDebugBuild ? "libadbconnectiond.so"
                                                        : "libadbconnection.so";
      plugins_.push_back(Plugin::Create(plugin_name));
    }
  }
  callbacks_->AddThreadLifecycleCallback(Dbg::GetThreadLifecycleCallback());
  callbacks_->AddClassLoadCallback(Dbg::GetClassLoadCallback());

  jit_options_.reset(jit::JitOptions::CreateFromRuntimeArguments(runtime_options));
  if (IsAotCompiler()) {
    // If we are already the compiler at this point, we must be dex2oat. Don't create the jit in
    // this case.
    // If runtime_options doesn't have UseJIT set to true then CreateFromRuntimeArguments returns
    // null and we don't create the jit.
    jit_options_->SetUseJitCompilation(false);
    jit_options_->SetSaveProfilingInfo(false);
  }

  // Use MemMap arena pool for jit, malloc otherwise. Malloc arenas are faster to allocate but
  // can't be trimmed as easily.
  const bool use_malloc = IsAotCompiler();
  arena_pool_.reset(new ArenaPool(use_malloc, /* low_4gb */ false));
  jit_arena_pool_.reset(
      new ArenaPool(/* use_malloc */ false, /* low_4gb */ false, "CompilerMetadata"));

  if (IsAotCompiler() && Is64BitInstructionSet(kRuntimeISA)) {
    // 4gb, no malloc. Explanation in header.
    low_4gb_arena_pool_.reset(new ArenaPool(/* use_malloc */ false, /* low_4gb */ true));
  }
  linear_alloc_.reset(CreateLinearAlloc());

  BlockSignals();
  InitPlatformSignalHandlers();

  // Change the implicit checks flags based on runtime architecture.
  switch (kRuntimeISA) {
    case InstructionSet::kArm:
    case InstructionSet::kThumb2:
    case InstructionSet::kX86:
    case InstructionSet::kArm64:
    case InstructionSet::kX86_64:
    case InstructionSet::kMips:
    case InstructionSet::kMips64:
      implicit_null_checks_ = true;
      // Installing stack protection does not play well with valgrind.
      implicit_so_checks_ = !(RUNNING_ON_MEMORY_TOOL && kMemoryToolIsValgrind);
      break;
    default:
      // Keep the defaults.
      break;
  }

  if (!no_sig_chain_) {
    // Dex2Oat's Runtime does not need the signal chain or the fault handler.
    if (implicit_null_checks_ || implicit_so_checks_ || implicit_suspend_checks_) {
      fault_manager.Init();

      // These need to be in a specific order.  The null point check handler must be
      // after the suspend check and stack overflow check handlers.
      //
      // Note: the instances attach themselves to the fault manager and are handled by it. The manager
      //       will delete the instance on Shutdown().
      if (implicit_suspend_checks_) {
        new SuspensionHandler(&fault_manager);
      }

      if (implicit_so_checks_) {
        new StackOverflowHandler(&fault_manager);
      }

      if (implicit_null_checks_) {
        new NullPointerHandler(&fault_manager);
      }

      if (kEnableJavaStackTraceHandler) {
        new JavaStackTraceHandler(&fault_manager);
      }
    }
  }

  std::string error_msg;
  //创建JavaVMExt实例
  java_vm_ = JavaVMExt::Create(this, runtime_options, &error_msg);
  if (java_vm_.get() == nullptr) {
    LOG(ERROR) << "Could not initialize JavaVMExt: " << error_msg;
    return false;
  }

  // Add the JniEnv handler.
  // TODO Refactor this stuff.
  java_vm_->AddEnvironmentHook(JNIEnvExt::GetEnvHandler);

  //创建线程
  Thread::Startup();

  // ClassLinker needs an attached thread, but we can't fully attach a thread without creating
  // objects. We can't supply a thread group yet; it will be fixed later. Since we are the main
  // thread, we do not get a java peer.
  Thread* self = Thread::Attach("main", false, nullptr, false);
  CHECK_EQ(self->GetThreadId(), ThreadList::kMainThreadId);
  CHECK(self != nullptr);

  self->SetCanCallIntoJava(!IsAotCompiler());

  // Set us to runnable so tools using a runtime can allocate and GC by default
  self->TransitionFromSuspendedToRunnable();

  // Now we're attached, we can take the heap locks and validate the heap.
  GetHeap()->EnableObjectValidation();

  CHECK_GE(GetHeap()->GetContinuousSpaces().size(), 1U);
  if (UNLIKELY(IsAotCompiler())) {
    class_linker_ = new AotClassLinker(intern_table_);
  } else {
    class_linker_ = new ClassLinker(intern_table_);
  }
  if (GetHeap()->HasBootImageSpace()) {
    bool result = class_linker_->InitFromBootImage(&error_msg);
    if (!result) {
      LOG(ERROR) << "Could not initialize from image: " << error_msg;
      return false;
    }
    if (kIsDebugBuild) {
      for (auto image_space : GetHeap()->GetBootImageSpaces()) {
        image_space->VerifyImageAllocations();
      }
    }
    if (boot_class_path_string_.empty()) {
      // The bootclasspath is not explicitly specified: construct it from the loaded dex files.
      const std::vector<const DexFile*>& boot_class_path = GetClassLinker()->GetBootClassPath();
      std::vector<std::string> dex_locations;
      dex_locations.reserve(boot_class_path.size());
      for (const DexFile* dex_file : boot_class_path) {
        dex_locations.push_back(dex_file->GetLocation());
      }
      boot_class_path_string_ = android::base::Join(dex_locations, ':');
    }
    {
      ScopedTrace trace2("AddImageStringsToTable");
      GetInternTable()->AddImagesStringsToTable(heap_->GetBootImageSpaces());
    }
    if (IsJavaDebuggable()) {
      // Now that we have loaded the boot image, deoptimize its methods if we are running
      // debuggable, as the code may have been compiled non-debuggable.
      DeoptimizeBootImage();
    }
  } else {
    std::vector<std::string> dex_filenames;
    Split(boot_class_path_string_, ':', &dex_filenames);

    std::vector<std::string> dex_locations;
    if (!runtime_options.Exists(Opt::BootClassPathLocations)) {
      dex_locations = dex_filenames;
    } else {
      dex_locations = runtime_options.GetOrDefault(Opt::BootClassPathLocations);
      CHECK_EQ(dex_filenames.size(), dex_locations.size());
    }

    std::vector<std::unique_ptr<const DexFile>> boot_class_path;
    if (runtime_options.Exists(Opt::BootClassPathDexList)) {
      boot_class_path.swap(*runtime_options.GetOrDefault(Opt::BootClassPathDexList));
    } else {
      //打开dex文件
      OpenDexFiles(dex_filenames,
                   dex_locations,
                   runtime_options.GetOrDefault(Opt::Image),
                   &boot_class_path);
    }
    instruction_set_ = runtime_options.GetOrDefault(Opt::ImageInstructionSet);
    if (!class_linker_->InitWithoutImage(std::move(boot_class_path), &error_msg)) {
      LOG(ERROR) << "Could not initialize without image: " << error_msg;
      return false;
    }

    // TODO: Should we move the following to InitWithoutImage?
    SetInstructionSet(instruction_set_);
    for (uint32_t i = 0; i < kCalleeSaveSize; i++) {
      CalleeSaveType type = CalleeSaveType(i);
      if (!HasCalleeSaveMethod(type)) {
        SetCalleeSaveMethod(CreateCalleeSaveMethod(), type);
      }
    }
  }

  CHECK(class_linker_ != nullptr);

  verifier::MethodVerifier::Init();

  if (runtime_options.Exists(Opt::MethodTrace)) {
    trace_config_.reset(new TraceConfig());
    trace_config_->trace_file = runtime_options.ReleaseOrDefault(Opt::MethodTraceFile);
    trace_config_->trace_file_size = runtime_options.ReleaseOrDefault(Opt::MethodTraceFileSize);
    trace_config_->trace_mode = Trace::TraceMode::kMethodTracing;
    trace_config_->trace_output_mode = runtime_options.Exists(Opt::MethodTraceStreaming) ?
        Trace::TraceOutputMode::kStreaming :
        Trace::TraceOutputMode::kFile;
  }

  // TODO: move this to just be an Trace::Start argument
  Trace::SetDefaultClockSource(runtime_options.GetOrDefault(Opt::ProfileClock));

  // Pre-allocate an OutOfMemoryError for the double-OOME case.
  self->ThrowNewException("Ljava/lang/OutOfMemoryError;",
                          "OutOfMemoryError thrown while trying to throw OutOfMemoryError; "
                          "no stack trace available");
  pre_allocated_OutOfMemoryError_ = GcRoot<mirror::Throwable>(self->GetException());
  self->ClearException();

  // Pre-allocate a NoClassDefFoundError for the common case of failing to find a system class
  // ahead of checking the application's class loader.
  self->ThrowNewException("Ljava/lang/NoClassDefFoundError;",
                          "Class not found using the boot class loader; no stack trace available");
  pre_allocated_NoClassDefFoundError_ = GcRoot<mirror::Throwable>(self->GetException());
  self->ClearException();

  // Runtime initialization is largely done now.
  // We load plugins first since that can modify the runtime state slightly.
  // Load all plugins
  for (auto& plugin : plugins_) {
    std::string err;
    if (!plugin.Load(&err)) {
      LOG(FATAL) << plugin << " failed to load: " << err;
    }
  }

  // Look for a native bridge.
  //
  // The intended flow here is, in the case of a running system:
  //
  // Runtime::Init() (zygote):
  //   LoadNativeBridge -> dlopen from cmd line parameter.
  //  |
  //  V
  // Runtime::Start() (zygote):
  //   No-op wrt native bridge.
  //  |
  //  | start app
  //  V
  // DidForkFromZygote(action)
  //   action = kUnload -> dlclose native bridge.
  //   action = kInitialize -> initialize library
  //
  //
  // The intended flow here is, in the case of a simple dalvikvm call:
  //
  // Runtime::Init():
  //   LoadNativeBridge -> dlopen from cmd line parameter.
  //  |
  //  V
  // Runtime::Start():
  //   DidForkFromZygote(kInitialize) -> try to initialize any native bridge given.
  //   No-op wrt native bridge.
  {
    std::string native_bridge_file_name = runtime_options.ReleaseOrDefault(Opt::NativeBridge);
    is_native_bridge_loaded_ = LoadNativeBridge(native_bridge_file_name);
  }

  // Startup agents
  // TODO Maybe we should start a new thread to run these on. Investigate RI behavior more.
  for (auto& agent_spec : agent_specs_) {
    // TODO Check err
    int res = 0;
    std::string err = "";
    ti::LoadError error;
    std::unique_ptr<ti::Agent> agent = agent_spec.Load(&res, &error, &err);

    if (agent != nullptr) {
      agents_.push_back(std::move(agent));
      continue;
    }

    switch (error) {
      case ti::LoadError::kInitializationError:
        LOG(FATAL) << "Unable to initialize agent!";
        UNREACHABLE();

      case ti::LoadError::kLoadingError:
        LOG(ERROR) << "Unable to load an agent: " << err;
        continue;

      case ti::LoadError::kNoError:
        break;
    }
    LOG(FATAL) << "Unreachable";
    UNREACHABLE();
  }
  {
    ScopedObjectAccess soa(self);
    callbacks_->NextRuntimePhase(RuntimePhaseCallback::RuntimePhase::kInitialAgents);
  }

  VLOG(startup) << "Runtime::Init exiting";

  // Set OnlyUseSystemOatFiles only after boot classpath has been set up.
  if (runtime_options.Exists(Opt::OnlyUseSystemOatFiles)) {
    oat_file_manager_->SetOnlyUseSystemOatFiles();
  }

  return true;
}

这个方法比较长,主要是对Art虚拟机进行一序列初始化。比较重要的有,创建ART虚拟机堆,创建JavaVMExt实例,启动当前线程,加载OAT文件。

2.3 startReg


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.)
     */
     //设置线程创建方法为javaCreateThreadEtc
    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);
    //进程JNI方法注册
    if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) {
        env->PopLocalFrame(NULL);
        return -1;
    }
    env->PopLocalFrame(NULL);

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

    return 0;
}
2.3.1 register_jni_procs

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;
}

循环调用gRegJNI数组成员所对应的方法


static const RegJNIRec gRegJNI[] = {
    REG_JNI(register_com_android_internal_os_RuntimeInit),
    REG_JNI(register_com_android_internal_os_ZygoteInit_nativeZygoteInit),
    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_util_StatsLog),
    REG_JNI(register_android_util_StatsLogInternal),
    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_content_res_ApkAssets),
    REG_JNI(register_android_text_AndroidCharacter),
    REG_JNI(register_android_text_Hyphenator),
    REG_JNI(register_android_text_MeasuredParagraph),
    REG_JNI(register_android_text_StaticLayout),
    REG_JNI(register_android_view_InputDevice),
    REG_JNI(register_android_view_KeyCharacterMap),
    REG_JNI(register_android_os_Process),
    REG_JNI(register_android_os_SystemProperties),
    REG_JNI(register_android_os_Binder),
    REG_JNI(register_android_os_Parcel),
    REG_JNI(register_android_os_HidlSupport),
    REG_JNI(register_android_os_HwBinder),
    REG_JNI(register_android_os_HwBlob),
    REG_JNI(register_android_os_HwParcel),
    REG_JNI(register_android_os_HwRemoteBinder),
    REG_JNI(register_android_os_NativeHandle),
    REG_JNI(register_android_os_VintfObject),
    REG_JNI(register_android_os_VintfRuntimeInfo),
    REG_JNI(register_android_nio_utils),
    REG_JNI(register_android_graphics_Canvas),
    REG_JNI(register_android_graphics_Graphics),
    REG_JNI(register_android_view_DisplayEventReceiver),
    REG_JNI(register_android_view_RenderNode),
    REG_JNI(register_android_view_RenderNodeAnimator),
    REG_JNI(register_android_view_DisplayListCanvas),
    REG_JNI(register_android_view_TextureLayer),
    REG_JNI(register_android_view_ThreadedRenderer),
    REG_JNI(register_android_view_Surface),
    REG_JNI(register_android_view_SurfaceControl),
    REG_JNI(register_android_view_SurfaceSession),
    REG_JNI(register_android_view_TextureView),
    REG_JNI(register_com_android_internal_view_animation_NativeInterpolatorFactoryHelper),
    REG_JNI(register_com_google_android_gles_jni_EGLImpl),
    REG_JNI(register_com_google_android_gles_jni_GLImpl),
    REG_JNI(register_android_opengl_jni_EGL14),
    REG_JNI(register_android_opengl_jni_EGLExt),
    REG_JNI(register_android_opengl_jni_GLES10),
    REG_JNI(register_android_opengl_jni_GLES10Ext),
    REG_JNI(register_android_opengl_jni_GLES11),
    REG_JNI(register_android_opengl_jni_GLES11Ext),
    REG_JNI(register_android_opengl_jni_GLES20),
    REG_JNI(register_android_opengl_jni_GLES30),
    REG_JNI(register_android_opengl_jni_GLES31),
    REG_JNI(register_android_opengl_jni_GLES31Ext),
    REG_JNI(register_android_opengl_jni_GLES32),

    REG_JNI(register_android_graphics_Bitmap),
    REG_JNI(register_android_graphics_BitmapFactory),
    REG_JNI(register_android_graphics_BitmapRegionDecoder),
    REG_JNI(register_android_graphics_ByteBufferStreamAdaptor),
    REG_JNI(register_android_graphics_Camera),
    REG_JNI(register_android_graphics_CreateJavaOutputStreamAdaptor),
    REG_JNI(register_android_graphics_CanvasProperty),
    REG_JNI(register_android_graphics_ColorFilter),
    REG_JNI(register_android_graphics_DrawFilter),
    REG_JNI(register_android_graphics_FontFamily),
    REG_JNI(register_android_graphics_GraphicBuffer),
    REG_JNI(register_android_graphics_ImageDecoder),
    REG_JNI(register_android_graphics_drawable_AnimatedImageDrawable),
    REG_JNI(register_android_graphics_Interpolator),
    REG_JNI(register_android_graphics_MaskFilter),
    REG_JNI(register_android_graphics_Matrix),
    REG_JNI(register_android_graphics_Movie),
    REG_JNI(register_android_graphics_NinePatch),
    REG_JNI(register_android_graphics_Paint),
    REG_JNI(register_android_graphics_Path),
    REG_JNI(register_android_graphics_PathMeasure),
    REG_JNI(register_android_graphics_PathEffect),
    REG_JNI(register_android_graphics_Picture),
    REG_JNI(register_android_graphics_Region),
    REG_JNI(register_android_graphics_Shader),
    REG_JNI(register_android_graphics_SurfaceTexture),
    REG_JNI(register_android_graphics_Typeface),
    REG_JNI(register_android_graphics_YuvImage),
    REG_JNI(register_android_graphics_drawable_AnimatedVectorDrawable),
    REG_JNI(register_android_graphics_drawable_VectorDrawable),
    REG_JNI(register_android_graphics_pdf_PdfDocument),
    REG_JNI(register_android_graphics_pdf_PdfEditor),
    REG_JNI(register_android_graphics_pdf_PdfRenderer),

    REG_JNI(register_android_database_CursorWindow),
    REG_JNI(register_android_database_SQLiteConnection),
    REG_JNI(register_android_database_SQLiteGlobal),
    REG_JNI(register_android_database_SQLiteDebug),
    REG_JNI(register_android_os_Debug),
    REG_JNI(register_android_os_FileObserver),
    REG_JNI(register_android_os_GraphicsEnvironment),
    REG_JNI(register_android_os_MessageQueue),
    REG_JNI(register_android_os_SELinux),
    REG_JNI(register_android_os_Trace),
    REG_JNI(register_android_os_UEventObserver),
    REG_JNI(register_android_net_LocalSocketImpl),
    REG_JNI(register_android_net_NetworkUtils),
    REG_JNI(register_android_os_MemoryFile),
    REG_JNI(register_android_os_SharedMemory),
    REG_JNI(register_com_android_internal_os_ClassLoaderFactory),
    REG_JNI(register_com_android_internal_os_Zygote),
    REG_JNI(register_com_android_internal_os_ZygoteInit),
    REG_JNI(register_com_android_internal_util_VirtualRefBasePtr),
    REG_JNI(register_android_hardware_Camera),
    REG_JNI(register_android_hardware_camera2_CameraMetadata),
    REG_JNI(register_android_hardware_camera2_legacy_LegacyCameraDevice),
    REG_JNI(register_android_hardware_camera2_legacy_PerfMeasurement),
    REG_JNI(register_android_hardware_camera2_DngCreator),
    REG_JNI(register_android_hardware_HardwareBuffer),
    REG_JNI(register_android_hardware_SensorManager),
    REG_JNI(register_android_hardware_SerialPort),
    REG_JNI(register_android_hardware_SoundTrigger),
    REG_JNI(register_android_hardware_UsbDevice),
    REG_JNI(register_android_hardware_UsbDeviceConnection),
    REG_JNI(register_android_hardware_UsbRequest),
    REG_JNI(register_android_hardware_location_ActivityRecognitionHardware),
    REG_JNI(register_android_media_AudioRecord),
    REG_JNI(register_android_media_AudioSystem),
    REG_JNI(register_android_media_AudioTrack),
    REG_JNI(register_android_media_JetPlayer),
    REG_JNI(register_android_media_MicrophoneInfo),
    REG_JNI(register_android_media_RemoteDisplay),
    REG_JNI(register_android_media_ToneGenerator),

    REG_JNI(register_android_opengl_classes),
    REG_JNI(register_android_server_NetworkManagementSocketTagger),
    REG_JNI(register_android_ddm_DdmHandleNativeHeap),
    REG_JNI(register_android_backup_BackupDataInput),
    REG_JNI(register_android_backup_BackupDataOutput),
    REG_JNI(register_android_backup_FileBackupHelperBase),
    REG_JNI(register_android_backup_BackupHelperDispatcher),
    REG_JNI(register_android_app_backup_FullBackup),
    REG_JNI(register_android_app_Activity),
    REG_JNI(register_android_app_ActivityThread),
    REG_JNI(register_android_app_NativeActivity),
    REG_JNI(register_android_util_jar_StrictJarFile),
    REG_JNI(register_android_view_InputChannel),
    REG_JNI(register_android_view_InputEventReceiver),
    REG_JNI(register_android_view_InputEventSender),
    REG_JNI(register_android_view_InputQueue),
    REG_JNI(register_android_view_KeyEvent),
    REG_JNI(register_android_view_MotionEvent),
    REG_JNI(register_android_view_PointerIcon),
    REG_JNI(register_android_view_VelocityTracker),

    REG_JNI(register_android_content_res_ObbScanner),
    REG_JNI(register_android_content_res_Configuration),

    REG_JNI(register_android_animation_PropertyValuesHolder),
    REG_JNI(register_android_security_Scrypt),
    REG_JNI(register_com_android_internal_content_NativeLibraryHelper),
    REG_JNI(register_com_android_internal_os_FuseAppLoop),
};

上面有100多个成员变量,每个成员变量代表一个类文件的JNI映射,通过宏定义的方式调用相应的方法。

下面就一个例子,分析下注册的过程

2.3.2 register_com_android_internal_os_RuntimeInit

int register_com_android_internal_os_RuntimeInit(JNIEnv* env)
{
    const JNINativeMethod methods[] = {
        { "nativeFinishInit", "()V",
            (void*) com_android_internal_os_RuntimeInit_nativeFinishInit },
        { "nativeSetExitWithoutCleanup", "(Z)V",
            (void*) com_android_internal_os_RuntimeInit_nativeSetExitWithoutCleanup },
    };
    return jniRegisterNativeMethods(env, "com/android/internal/os/RuntimeInit",
        methods, NELEM(methods));
}

jniRegisterNativeMethods最后调用到jni.h中的RegisterNatives方法

2.3.3 RegisterNatives

[->jni.h]


jint RegisterNatives(jclass clazz, const JNINativeMethod* methods,
      jint nMethods)
  { return functions->RegisterNatives(this, clazz, methods, nMethods); }

functions是指向JNINativeInterface结构体指针,也就是将调用下面方法:


#if defined(__cplusplus)
typedef _JNIEnv JNIEnv;
typedef _JavaVM JavaVM;
#else
typedef const struct JNINativeInterface* JNIEnv;
typedef const struct JNIInvokeInterface* JavaVM;
#endif
struct _JavaVM {
    const struct JNIInvokeInterface* functions;
     ...
    }
struct _JNIEnv {
      /* do not rename this; it does not seem to be entirely opaque */
      const struct JNINativeInterface* functions;
      ...
 }
 
 jint (*RegisterNatives)(JNIEnv*, jclass, const JNINativeMethod*,jint);

通过这种方法java层的nativeFinishInit与native层的com_android_internal_os_RuntimeInit_nativeFinishInit就完成了映射,后面通过JNIEvn这个变量就可以访问java中的方法了。

虚拟机中有两个重要的变量JavaVM和JNIEnv:

  • JavaVM:进程虚拟机环境,每个进程有且只有一个JavaVM实例
  • JNIEnv:线程上下文环境,每个线程有且只有一个JNIEnv实例,通过该变量调用Java中的代码

三、动态库加载分析

JNI注册除了上面通过手动注册外,一般都是通过System.loadLibrary方法,下面就这个过程进行分析。

3.1 System.loadLibrary

[->System.java]


public static void loadLibrary(String libname) {
       Runtime.getRuntime().loadLibrary0(VMStack.getCallingClassLoader(), libname);
}

3.2 Runtime.loadLibrary0

[->Runtime.java]


synchronized void loadLibrary0(ClassLoader loader, String libname) {
       if (libname.indexOf((int)File.separatorChar) != -1) {
           throw new UnsatisfiedLinkError(
   "Directory separator should not appear in library name: " + libname);
       }
       String libraryName = libname;
       if (loader != null) {
           //查找库
           String filename = loader.findLibrary(libraryName);
           if (filename == null) {
               // It's not necessarily true that the ClassLoader used
               // System.mapLibraryName, but the default setup does, and it's
               // misleading to say we didn't find "libMyLibrary.so" when we
               // actually searched for "liblibMyLibrary.so.so".
               throw new UnsatisfiedLinkError(loader + " couldn't find /"" +
                                              System.mapLibraryName(libraryName) + "/"");
           }
           //加载库
           String error = nativeLoad(filename, loader);
           if (error != null) {
               throw new UnsatisfiedLinkError(error);
           }
           return;
       }

       //见3.2.2.1节,映射库的名字
       String filename = System.mapLibraryName(libraryName);
       List<String> candidates = new ArrayList<String>();
       String lastError = null;
       //getLibPaths见3.5节
       for (String directory : getLibPaths()) {
           String candidate = directory + filename;
           candidates.add(candidate);
           //判断目标动态库是否存在
           if (IoUtils.canOpenReadOnly(candidate)) {
               //见3.4节,加载库
               String error = nativeLoad(candidate, loader);
               if (error == null) {
                   return; // We successfully loaded the library. Job done.
               }
               lastError = error;
           }
       }

       if (lastError != null) {
           throw new UnsatisfiedLinkError(lastError);
       }
       throw new UnsatisfiedLinkError("Library " + libraryName + " not found; tried " + candidates);
   }

这里核心的操作时nativeLoad方法,来加载so动态库,注意该方法为同步方法。

如果classload为空,则从默认mLibPaths下查看库是否存在并加载

如果classload不为空,则通过findLibrary查找库并加载

3.3 findLibrary

[->BaseDexClassLoader.java]


@Override
   public String findLibrary(String name) {
       return pathList.findLibrary(name);
   }

Classloader一般都是PathClassLoader,由于PathClassLoader继承于BaseDexClassLoader,没有复写该方法,所以调用的是BaseDexClassLoader方法。

3.3.1 DexPathList初始化

[->BaseDexClassLoader.java]


public BaseDexClassLoader(String dexPath, File optimizedDirectory,
           String librarySearchPath, ClassLoader parent, boolean isTrusted) {
       super(parent);
       this.pathList = new DexPathList(this, dexPath, librarySearchPath, null, isTrusted);

       if (reporter != null) {
           reportClassLoaderChain();
       }
   }
3.3.1.1 new DexPathList

DexPathList(ClassLoader definingContext, String dexPath,
           String librarySearchPath, File optimizedDirectory, boolean isTrusted) {
       if (definingContext == null) {
           throw new NullPointerException("definingContext == null");
       }

       if (dexPath == null) {
           throw new NullPointerException("dexPath == null");
       }

       if (optimizedDirectory != null) {
           if (!optimizedDirectory.exists())  {
               throw new IllegalArgumentException(
                       "optimizedDirectory doesn't exist: "
                       + optimizedDirectory);
           }

           if (!(optimizedDirectory.canRead()
                           && optimizedDirectory.canWrite())) {
               throw new IllegalArgumentException(
                       "optimizedDirectory not readable/writable: "
                       + optimizedDirectory);
           }
       }

       this.definingContext = definingContext;

       ArrayList<IOException> suppressedExceptions = new ArrayList<IOException>();
       // save dexPath for BaseDexClassLoader
       //所有的dexFile文件
       this.dexElements = makeDexElements(splitDexPath(dexPath), optimizedDirectory,
                                          suppressedExceptions, definingContext, isTrusted);

       // Native libraries may exist in both the system and
       // application library paths, and we use this search order:
       //
       //   1. This class loader's library path for application libraries (librarySearchPath):
       //   1.1. Native library directories
       //   1.2. Path to libraries in apk-files
       //   2. The VM's library path from the system property for system libraries
       //      also known as java.library.path
       //
       // This order was reversed prior to Gingerbread; see http://b/2933456.
       //app目录下的native库
       this.nativeLibraryDirectories = splitPaths(librarySearchPath, false);
       //系统目录下的native库
       this.systemNativeLibraryDirectories =
               splitPaths(System.getProperty("java.library.path"), true);
       List<File> allNativeLibraryDirectories = new ArrayList<>(nativeLibraryDirectories);
       allNativeLibraryDirectories.addAll(systemNativeLibraryDirectories);

       //记录所有的native动态库
       this.nativeLibraryPathElements = makePathElements(allNativeLibraryDirectories);

       if (suppressedExceptions.size() > 0) {
           this.dexElementsSuppressedExceptions =
               suppressedExceptions.toArray(new IOException[suppressedExceptions.size()]);
       } else {
           dexElementsSuppressedExceptions = null;
       }
   }

DexPathList初始化主要是给两个全局变量赋值

dexElements:记录所有的dexFile文件

nativeLibraryPathElements:记录所有的Native动态库,包括app目录下和系统目录下的native库

app目录下:/data/app/-xyz–/lib/下

系统目录:/system/lib下

3.3.1.2 makePathElements

private static NativeLibraryElement[] makePathElements(List<File> files) {
       NativeLibraryElement[] elements = new NativeLibraryElement[files.size()];
       int elementsPos = 0;
       for (File file : files) {
           String path = file.getPath();

           if (path.contains(zipSeparator)) {
               String split[] = path.split(zipSeparator, 2);
               File zip = new File(split[0]);
               String dir = split[1];
               elements[elementsPos++] = new NativeLibraryElement(zip, dir);
           } else if (file.isDirectory()) {
               // We support directories for looking up native libraries.
               elements[elementsPos++] = new NativeLibraryElement(file);
           }
       }
       if (elementsPos != elements.length) {
           elements = Arrays.copyOf(elements, elementsPos);
       }
       return elements;
   }

将native动态库存在nativeLibraryPathElements中,可以看出一个native库对应一个NativeLibraryElement

3.3.2 DexPathList.findLibrary

[->DexPathList.java]


public String findLibrary(String libraryName) {
       String fileName = System.mapLibraryName(libraryName);
       //从之前初始化的NativeLibraryElementS中查找库
       for (NativeLibraryElement element : nativeLibraryPathElements) {
          //见3.3.2.2节
           String path = element.findNativeLibrary(fileName);

           if (path != null) {
               return path;
           }
       }

       return null;
   }
3.3.2.1 System_mapLibraryName

[->System.c]


JNIEXPORT jstring JNICALL
System_mapLibraryName(JNIEnv *env, jclass ign, jstring libname)
{
    int len;
    int prefix_len = (int) strlen(JNI_LIB_PREFIX);
    int suffix_len = (int) strlen(JNI_LIB_SUFFIX);

    jchar chars[256];
    if (libname == NULL) {
        JNU_ThrowNullPointerException(env, 0);
        return NULL;
    }
    len = (*env)->GetStringLength(env, libname);
    if (len > 240) {
        JNU_ThrowIllegalArgumentException(env, "name too long");
        return NULL;
    }
    cpchars(chars, JNI_LIB_PREFIX, prefix_len);
    (*env)->GetStringRegion(env, libname, 0, len, chars + prefix_len);
    len += prefix_len;
    cpchars(chars + len, JNI_LIB_SUFFIX, suffix_len);
    len += suffix_len;

    return (*env)->NewString(env, chars, len);
}

这里主要是将库的名字前面加上lib后缀加so,例如库名字是native,则转化后为libnative.so

3.3.2.2 findNativeLibrary

[->DexPathList.java]


public String findNativeLibrary(String name) {
          maybeInit();

          if (zipDir == null) {
              String entryPath = new File(path, name).getPath();
              if (IoUtils.canOpenReadOnly(entryPath)) {
                  return entryPath;
              }
          } else if (urlHandler != null) {
              // Having a urlHandler means the element has a zip file.
              // In this case Android supports loading the library iff
              // it is stored in the zip uncompressed.
              String entryName = zipDir + '/' + name;
              if (urlHandler.isEntryStored(entryName)) {
                return path.getPath() + zipSeparator + entryName;
              }
          }

          return null;
      }

找到目标动态库,准备加载。

3.4 nativeLoad

[->libcore/ojluni/src/main/native/Runtime.c]


JNIEXPORT jstring JNICALL
Runtime_nativeLoad(JNIEnv* env, jclass ignored, jstring javaFilename,
                   jobject javaLoader)
{
    //JVM加载动态库
    return JVM_NativeLoad(env, javaFilename, javaLoader);
}

static JNINativeMethod gMethods[] = {
  FAST_NATIVE_METHOD(Runtime, freeMemory, "()J"),
  FAST_NATIVE_METHOD(Runtime, totalMemory, "()J"),
  FAST_NATIVE_METHOD(Runtime, maxMemory, "()J"),
  NATIVE_METHOD(Runtime, gc, "()V"),
  NATIVE_METHOD(Runtime, nativeExit, "(I)V"),
  NATIVE_METHOD(Runtime, nativeLoad,
                "(Ljava/lang/String;Ljava/lang/ClassLoader;)"
                    "Ljava/lang/String;"),
};
3.4.1 JVM_NativeLoad

[->art/openjdkjvm/OpenjdkJvm.cc]


JNIEXPORT jstring JVM_NativeLoad(JNIEnv* env,
                                 jstring javaFilename,
                                 jobject javaLoader) {
  ScopedUtfChars filename(env, javaFilename);
  if (filename.c_str() == NULL) {
    return NULL;
  }

  std::string error_msg;
  {
    art::JavaVMExt* vm = art::Runtime::Current()->GetJavaVM();
    //见3.4.2节
    bool success = vm->LoadNativeLibrary(env,
                                         filename.c_str(),
                                         javaLoader,
                                         &error_msg);
    if (success) {
      return nullptr;
    }
  }

  // Don't let a pending exception from JNI_OnLoad cause a CheckJNI issue with NewStringUTF.
  env->ExceptionClear();
  return env->NewStringUTF(error_msg.c_str());
}
3.4.2 LoadNativeLibrary

[->art/runtime/java_vm_ext.cc]


bool JavaVMExt::LoadNativeLibrary(JNIEnv* env,
                                  const std::string& path,
                                  jobject class_loader,
                                  std::string* error_msg) {
  error_msg->clear();

  // See if we've already loaded this library.  If we have, and the class loader
  // matches, return successfully without doing anything.
  // TODO: for better results we should canonicalize the pathname (or even compare
  // inodes). This implementation is fine if everybody is using System.loadLibrary.
  SharedLibrary* library;
  Thread* self = Thread::Current();
  {
    // TODO: move the locking (and more of this logic) into Libraries.
    MutexLock mu(self, *Locks::jni_libraries_lock_);
    //检查该动态库是否完成加载
    library = libraries_->Get(path);
  }
  void* class_loader_allocator = nullptr;
  {
    ScopedObjectAccess soa(env);
    // As the incoming class loader is reachable/alive during the call of this function,
    // it's okay to decode it without worrying about unexpectedly marking it alive.
    ObjPtr<mirror::ClassLoader> loader = soa.Decode<mirror::ClassLoader>(class_loader);

    ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
    if (class_linker->IsBootClassLoader(soa, loader.Ptr())) {
      loader = nullptr;
      class_loader = nullptr;
    }

    class_loader_allocator = class_linker->GetAllocatorForClassLoader(loader.Ptr());
    CHECK(class_loader_allocator != nullptr);
  }
  if (library != nullptr) {
    // Use the allocator pointers for class loader equality to avoid unnecessary weak root decode.
    if (library->GetClassLoaderAllocator() != class_loader_allocator) {
      // The library will be associated with class_loader. The JNI
      // spec says we can't load the same library into more than one
      // class loader.
      //
      // This isn't very common. So spend some time to get a readable message.
      auto call_to_string = [&](jobject obj) -> std::string {
        if (obj == nullptr) {
          return "null";
        }
        // Handle jweaks. Ignore double local-ref.
        ScopedLocalRef<jobject> local_ref(env, env->NewLocalRef(obj));
        if (local_ref != nullptr) {
          ScopedLocalRef<jclass> local_class(env, env->GetObjectClass(local_ref.get()));
          jmethodID to_string = env->GetMethodID(local_class.get(),
                                                 "toString",
                                                 "()Ljava/lang/String;");
          DCHECK(to_string != nullptr);
          ScopedLocalRef<jobject> local_string(env,
                                               env->CallObjectMethod(local_ref.get(), to_string));
          if (local_string != nullptr) {
            ScopedUtfChars utf(env, reinterpret_cast<jstring>(local_string.get()));
            if (utf.c_str() != nullptr) {
              return utf.c_str();
            }
          }
          env->ExceptionClear();
          return "(Error calling toString)";
        }
        return "null";
      };
      std::string old_class_loader = call_to_string(library->GetClassLoader());
      std::string new_class_loader = call_to_string(class_loader);
      StringAppendF(error_msg, "Shared library /"%s/" already opened by "
          "ClassLoader %p(%s); can't open in ClassLoader %p(%s)",
          path.c_str(),
          library->GetClassLoader(),
          old_class_loader.c_str(),
          class_loader,
          new_class_loader.c_str());
      LOG(WARNING) << *error_msg;
      return false;
    }
    VLOG(jni) << "[Shared library /"" << path << "/" already loaded in "
              << " ClassLoader " << class_loader << "]";
    if (!library->CheckOnLoadResult()) {
      StringAppendF(error_msg, "JNI_OnLoad failed on a previous attempt "
          "to load /"%s/"", path.c_str());
      return false;
    }
    return true;
  }

  // Open the shared library.  Because we're using a full path, the system
  // doesn't have to search through LD_LIBRARY_PATH.  (It may do so to
  // resolve this library's dependencies though.)

  // Failures here are expected when java.library.path has several entries
  // and we have to hunt for the lib.

  // Below we dlopen but there is no paired dlclose, this would be necessary if we supported
  // class unloading. Libraries will only be unloaded when the reference count (incremented by
  // dlopen) becomes zero from dlclose.

  // Retrieve the library path from the classloader, if necessary.
  ScopedLocalRef<jstring> library_path(env, GetLibrarySearchPath(env, class_loader));

  Locks::mutator_lock_->AssertNotHeld(self);
  const char* path_str = path.empty() ? nullptr : path.c_str();
  bool needs_native_bridge = false;
  //加载动态库
  void* handle = android::OpenNativeLibrary(env,
                                            runtime_->GetTargetSdkVersion(),
                                            path_str,
                                            class_loader,
                                            library_path.get(),
                                            &needs_native_bridge,
                                            error_msg);

  VLOG(jni) << "[Call to dlopen(/"" << path << "/", RTLD_NOW) returned " << handle << "]";

  if (handle == nullptr) {
    VLOG(jni) << "dlopen(/"" << path << "/", RTLD_NOW) failed: " << *error_msg;
    return false;
  }

  if (env->ExceptionCheck() == JNI_TRUE) {
    LOG(ERROR) << "Unexpected exception:";
    env->ExceptionDescribe();
    env->ExceptionClear();
  }
  // Create a new entry.
  // TODO: move the locking (and more of this logic) into Libraries.
  //创建SharedLibrary共享库
  bool created_library = false;
  {
    // Create SharedLibrary ahead of taking the libraries lock to maintain lock ordering.
    std::unique_ptr<SharedLibrary> new_library(
        new SharedLibrary(env,
                          self,
                          path,
                          handle,
                          needs_native_bridge,
                          class_loader,
                          class_loader_allocator));

    MutexLock mu(self, *Locks::jni_libraries_lock_);
    library = libraries_->Get(path);
    if (library == nullptr) {  // We won race to get libraries_lock.
      library = new_library.release();
      libraries_->Put(path, library);
      created_library = true;
    }
  }
  if (!created_library) {
    LOG(INFO) << "WOW: we lost a race to add shared library: "
        << "/"" << path << "/" ClassLoader=" << class_loader;
    return library->CheckOnLoadResult();
  }
  VLOG(jni) << "[Added shared library /"" << path << "/" for ClassLoader " << class_loader << "]";

  bool was_successful = false;
  void* sym = library->FindSymbol("JNI_OnLoad", nullptr);
  if (sym == nullptr) {
    VLOG(jni) << "[No JNI_OnLoad found in /"" << path << "/"]";
    was_successful = true;
  } else {
    // Call JNI_OnLoad.  We have to override the current class
    // loader, which will always be "null" since the stuff at the
    // top of the stack is around Runtime.loadLibrary().  (See
    // the comments in the JNI FindClass function.)
    //调用JNI_OnLoad方法
    ScopedLocalRef<jobject> old_class_loader(env, env->NewLocalRef(self->GetClassLoaderOverride()));
    self->SetClassLoaderOverride(class_loader);

    VLOG(jni) << "[Calling JNI_OnLoad in /"" << path << "/"]";
    typedef int (*JNI_OnLoadFn)(JavaVM*, void*);
    JNI_OnLoadFn jni_on_load = reinterpret_cast<JNI_OnLoadFn>(sym);
    int version = (*jni_on_load)(this, nullptr);

    if (runtime_->GetTargetSdkVersion() != 0 && runtime_->GetTargetSdkVersion() <= 21) {
      // Make sure that sigchain owns SIGSEGV.
      EnsureFrontOfChain(SIGSEGV);
    }

    self->SetClassLoaderOverride(old_class_loader.get());

    if (version == JNI_ERR) {
      StringAppendF(error_msg, "JNI_ERR returned from JNI_OnLoad in /"%s/"", path.c_str());
    } else if (JavaVMExt::IsBadJniVersion(version)) {
      StringAppendF(error_msg, "Bad JNI version returned from JNI_OnLoad in /"%s/": %d",
                    path.c_str(), version);
      // It's unwise to call dlclose() here, but we can mark it
      // as bad and ensure that future load attempts will fail.
      // We don't know how far JNI_OnLoad got, so there could
      // be some partially-initialized stuff accessible through
      // newly-registered native method calls.  We could try to
      // unregister them, but that doesn't seem worthwhile.
    } else {
      was_successful = true;
    }
    VLOG(jni) << "[Returned " << (was_successful ? "successfully" : "failure")
              << " from JNI_OnLoad in /"" << path << "/"]";
  }

  library->SetResult(was_successful);
  return was_successful;
}
3.4.2 OpenNativeLibrary

[->art/openjdkjvm/OpenjdkJvm.cc]


void* OpenNativeLibrary(JNIEnv* env,
                        int32_t target_sdk_version,
                        const char* path,
                        jobject class_loader,
                        jstring library_path,
                        bool* needs_native_bridge,
                        std::string* error_msg) {
#if defined(__ANDROID__)
  UNUSED(target_sdk_version);
  if (class_loader == nullptr) {
    *needs_native_bridge = false;
    return dlopen(path, RTLD_NOW);
  }

  std::lock_guard<std::mutex> guard(g_namespaces_mutex);
  NativeLoaderNamespace ns;
 
  if (!g_namespaces->FindNamespaceByClassLoader(env, class_loader, &ns)) {
    // This is the case where the classloader was not created by ApplicationLoaders
    // In this case we create an isolated not-shared namespace for it.
    if (!g_namespaces->Create(env,
                              target_sdk_version,
                              class_loader,
                              false /* is_shared */,
                              false /* is_for_vendor */,
                              library_path,
                              nullptr,
                              &ns,
                              error_msg)) {
      return nullptr;
    }
  }
  //是否是android命名空间
  if (ns.is_android_namespace()) {
    android_dlextinfo extinfo;
    extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
    extinfo.library_namespace = ns.get_android_ns();

    void* handle = android_dlopen_ext(path, RTLD_NOW, &extinfo);
    if (handle == nullptr) {
      *error_msg = dlerror();
    }
    *needs_native_bridge = false;
    return handle;
  } else {
    void* handle = NativeBridgeLoadLibraryExt(path, RTLD_NOW, ns.get_native_bridge_ns());
    if (handle == nullptr) {
      *error_msg = NativeBridgeGetError();
    }
    *needs_native_bridge = true;
    return handle;
  }
#else
  UNUSED(env, target_sdk_version, class_loader);

  // Do some best effort to emulate library-path support. It will not
  // work for dependencies.
  //
  // Note: null has a special meaning and must be preserved.
  std::string c_library_path;  // Empty string by default.
  if (library_path != nullptr && path != nullptr && path[0] != '/') {
    ScopedUtfChars library_path_utf_chars(env, library_path);
    c_library_path = library_path_utf_chars.c_str();
  }

  std::vector<std::string> library_paths = base::Split(c_library_path, ":");

  for (const std::string& lib_path : library_paths) {
    *needs_native_bridge = false;
    const char* path_arg;
    std::string complete_path;
    if (path == nullptr) {
      // Preserve null.
      path_arg = nullptr;
    } else {
      complete_path = lib_path;
      if (!complete_path.empty()) {
        complete_path.append("/");
      }
      complete_path.append(path);
      path_arg = complete_path.c_str();
    }
    //打开动态库
    void* handle = dlopen(path_arg, RTLD_NOW);
    if (handle != nullptr) {
      return handle;
    }
    if (NativeBridgeIsSupported(path_arg)) {
      *needs_native_bridge = true;
      handle = NativeBridgeLoadLibrary(path_arg, RTLD_NOW);
      if (handle != nullptr) {
        return handle;
      }
      *error_msg = NativeBridgeGetError();
    } else {
      *error_msg = dlerror();
    }
  }
  return nullptr;
#endif
}

LoadNativeLibrar最后通过android::OpenNativeLibrary加载so库,这里有一个名字空间的概念,通过它来实现系统的私有库,不被第三方加载,这样应用就没法去链接系统的私有库。

3.5 getLibPaths()

[->Runtime.java]


private String[] getLibPaths() {
        if (mLibPaths == null) {
            synchronized(this) {
                if (mLibPaths == null) {
                    mLibPaths = initLibPaths();
                }
            }
        }
        return mLibPaths;
    }

 private static String[] initLibPaths() {
        String javaLibraryPath = System.getProperty("java.library.path");
        if (javaLibraryPath == null) {
            return EmptyArray.STRING;
        }
        String[] paths = javaLibraryPath.split(":");
        // Add a '/' to the end of each directory so we don't have to do it every time.
        for (int i = 0; i < paths.length; ++i) {
            if (!paths[i].endsWith("/")) {
                paths[i] += "/";
            }
        }
        return paths;
    }

这里主要是查找系统库下的so库,/system/lib64

3.6 总结

动态库的调用顺序如下


System.loadLibrary()
  Runtime.loadLibrary()
      nativeLoad()
          JVM_NativeLoad
          LoadNativeLibrary()
              LoadNativeLibrary
                  OpenNativeLibrary
                     dlopen()
                        JNI_OnLoad()

加载动态库的主要流程如下:

1.判断是否为空,如果classload为空,则从默认mLibPaths下查看库是否存在并加载;如果classload不为空,则通过findLibrary查找库并加载,这两种加载库最后调用都是nativeLoad方法;

2.nativeLoad最后通过 android::OpenNativeLibrary来加载so库,通过这种方式来实现系统的私有so库,最后调用dlopen来打开动态库;

3.判断JNI_OnLoad方法是否存在,如果存在就调用该方法。

四、JNI应用

4.1 数据签名

4.1.1 基本数据类型
Signature格式 Java Native
B byte jbyte
C char jchar
D double jdouble
F float jfloat
I int jint
S short jshort
J long jlong
Z boolean jboolean
V void void
4.1.2 数组数据类型
Signature格式 Java Native
[B byte[] jbyteArray
[C char[] jcharArray
[D double[] jdoubleArray
[F float[] jfloatArray
[I int[] jintArray
[S short[] jshortArray
[J long[] jlongArray
[Z boolean[] jbooleanArray
4.1.3 对象数据类型
Signature格式 Java Native
Ljava/lang/String; String jstring
L+classname +; 所有对象 jobject
[L+classname +; Object[] jobjectArray
Ljava.lang.Class; Class jclass
Ljava.lang.Throwable; Throwable jthrowable
4.1.4 函数签名
Java函数 对应的签名
void foo() ()V
float foo(int i) (I)F
long foo(int[] i) ([I)J
double foo(Class c) (Ljava/lang/Class;)D
boolean foo(int[] i,String s) ([ILjava/lang/String;)Z
String foo(int i) (I)Ljava/lang/String;

4.2 Native层调用Java层

4.2.1 访问属性

访问普通属性


public String gBlogName = "skytoby";
  
Java_com_skytoby_myapplication_MainActivity_modifyBlogNameField(JNIEnv *env, jobject obj) {  
   //获取类
   jclass clazz = env->GetObjectClass(obj);
   //获取属性签名
   jfieldID  fieldId = env->GetFieldID(clazz,"gBlogName","Ljava/lang/String;");
   //获取属性值
   jstring jstr = static_cast<jstring>(env->GetObjectField(obj, fieldId));
   //jstring转char*
   //isCopy 是否复制(true代表赋值,false不复制)
   char *str = const_cast<char *>(env->GetStringUTFChars(jstr, JNI_FALSE));
   char *name = strcat(str,"haha");
   //修改属性值
   env->SetObjectField(obj,fieldId,env->NewStringUTF(name));
   env->ReleaseStringUTFChars(jstr,str);
 }

访问静态属性


public static String gStaticBlogName = "skytoby";

jclass clazz = env->GetObjectClass(obj);
jfieldID  fieldId = env->GetStaticFieldID(clazz,"gStaticBlogName","Ljava/lang/String;");
jstring jstr = static_cast<jstring>(env->GetStaticObjectField(clazz, fieldId));
 char *str = const_cast<char *>(env->GetStringUTFChars(jstr,JNI_FALSE));
 char *name = strcat(str,"hehe");
 env->SetStaticObjectField(clazz,fieldId,env->NewStringUTF(name));
 env->ReleaseStringUTFChars(jstr,str);
4.2.2.访问方法

每个native函数,都至少有两个参数(JNIEnv*,jobject)
1)当native方法为静态方法时:
jclass 代表native方法所属类的class对象
2)当native方法为非静态方法时:
jobject 代表native方法所属的对象

访问普通方法


public String getgBlogName(int age){
    return "skytoby"+age;
}
   
//获取类
jclass  clazz = env->GetObjectClass(obj);
//获取方法签名
jmethodID  methodId = env->GetMethodID(clazz,"getgBlogName","(I)Ljava/lang/String;");
//调用方法
jstring  jstr = static_cast<jstring>(env->CallObjectMethod(obj, methodId, 12));

访问静态方法


public static String getStaticgBlogName(int age){
    return "static skytoby"+age;
}
    
jclass  clazz = env->GetObjectClass(obj);
jmethodID  methodId = env->GetStaticMethodID(clazz,"getStaticgBlogName","(I)Ljava/lang/String;");
jstring  jstr = static_cast<jstring>(env->CallStaticObjectMethod(clazz, methodId, 12));

4.3 引用

在JNI中有三种引用关系

Local Reference(本地引用)

Global Reference(全局引用)

Weak Global Reference(全局弱引用)

Global Reference如果不主动释放,则一直不会释放;对于其他两种类型的引用都是释放的可能性。不管是这三种类型的哪种引用,在内存不再需要时,应立即释放,减少不可预知的性能与稳定性问题。


env->NewGlobalRef(obj);
env->NewLocalRef(obj);
env->NewWeakGlobalRef(obj);
env->DeleteGlobalRef(obj);
env->DeleteLocalRef(obj);
env->DeleteWeakGlobalRef(obj);

4.4 异常处理

Java中点异常用trycatch就可以处理,不会影响代码点继续执行,但是JNI中的异常,Java层是无法捕获的,只能够在JNI中清除,可以通过ThrowNew给Java层抛出异常,让java层捕获。


jclass clazz = env->GetObjectClass(obj);
jfieldID  fieldId = env->GetStaticFieldID(clazz,"gStaticBlogName1","Ljava/lang/String;");
//检测是否发生Java异常
jthrowable exception = env->ExceptionOccurred();
if (exception != NULL){
    //让Java代码可以继续运行
    //清空异常信息
    env->ExceptionClear();
    if (fieldId == NULL){
        //认为抛出异常,给Java层处理
        jclass newExcCls = env->FindClass( "java/lang/IllegalArgumentException");
        env->ThrowNew(newExcCls,"fieldId's value is invalid!");
    }
}

五、总结

本文主要从虚拟机的启动开始,再详细分析动态库的加载流程,最后对JNI的应用有详细的举例。

虚拟机启动过程中:

1.对Art虚拟机进行一序列初始化,如创建ART虚拟机堆,创建JavaVMExt实例,启动当前线程,加载OAT文件;

2.注册JNI函数,分析注册的详细过程

动态库的加载流程:

1.判断是否为空,如果classload为空,则从默认mLibPaths下查看库是否存在并加载;如果classload不为空,则通过findLibrary查找库并加载,这两种加载库最后调用都是nativeLoad方法;

2.nativeLoad最后通过 android::OpenNativeLibrary来加载so库,通过这种方式来实现系统的私有so库,最后调用dlopen来打开动态库;

3.判断JNI_OnLoad方法是否存在,如果存在就调用该方法。

JNI应用主要介绍了数据签名,Nativie层调用java层的基本方法,以及JNI引用和异常处理的问题。

附录


/libcore/ojluni/src/main/java/java/lang/System.java
/libcore/ojluni/src/main/java/java/lang/Runtime.java
/libcore/dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java
/libcore/dalvik/src/main/java/dalvik/system/DexPathList.java

/frameworks/base/core/jni/AndroidRuntime.cpp
/libcore/ojluni/src/main/native/Runtime.c
/art/openjdkjvm/OpenjdkJvm.cc
/art/runtime/java_vm_ext.cc
/libcore/ojluni/src/main/native/System.c