一、概述
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/
系统目录:/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