深入理解ART虚拟机—虚拟机的启动
Posted threepigs
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了深入理解ART虚拟机—虚拟机的启动相关的知识,希望对你有一定的参考价值。
看art虚拟机也有一段时间了,是时候写点什么出来了。早先看art的时候,发现不是太能理解,所以就恶补了一下dalvik虚拟机,所以有了之前的dalvik系列,等再次回头看art的时候,确实轻松了不少。
art从android L开始正式替换dalvik,成为Android的默认虚拟机,网上很多分析ART的文章都是基于KK的art源码,L的art源码和之前KK的差别比较大,L开始art才走向成熟,我们的分析则是基于L上的art。art的运行方式是AOT(Ahead Of Time),AOT和JIT(Just In Time)对应,JIT是即时编译,而AOT是提前编译,在apk安装的时候,由dex2oat将dex编译成oat文件。oat是扩展的elf文件,elf的文件结构不在这里详述,我几年前的文章《linker and loader 读书笔记》里有介绍。oat文件包含了类的各个method的native代码,会在apk运行时被加载。
我们来看art是怎么工作的:《 深入理解Dalvik虚拟机- Android进程启动过程》这篇文章介绍了Android的进程启动过程,不管是art还是dalvik,apk的启动过程都是一样的,不一样的是JavaVM和JNIEnv的创建的代码实现不同。JavaVM和JNIEnv这两个是Java虚拟机的核心接口,art和dalvik有其各自不同的实现。
#if defined(__cplusplus)
typedef _JNIEnv JNIEnv;
typedef _JavaVM JavaVM;
#else
typedef const struct JNINativeInterface* JNIEnv;
typedef const struct JNIInvokeInterface* JavaVM;
#endif
struct JNIInvokeInterface
void* reserved0;
void* reserved1;
void* reserved2;
jint (*DestroyJavaVM)(JavaVM*);
jint (*AttachCurrentThread)(JavaVM*, JNIEnv**, void*);
jint (*DetachCurrentThread)(JavaVM*);
jint (*GetEnv)(JavaVM*, void**, jint);
jint (*AttachCurrentThreadAsDaemon)(JavaVM*, JNIEnv**, void*);
;
struct _JavaVM
const struct JNIInvokeInterface* functions;
#if defined(__cplusplus)
jint DestroyJavaVM()
return functions->DestroyJavaVM(this);
jint AttachCurrentThread(JNIEnv** p_env, void* thr_args)
return functions->AttachCurrentThread(this, p_env, thr_args);
jint DetachCurrentThread()
return functions->DetachCurrentThread(this);
jint GetEnv(void** env, jint version)
return functions->GetEnv(this, env, version);
jint AttachCurrentThreadAsDaemon(JNIEnv** p_env, void* thr_args)
return functions->AttachCurrentThreadAsDaemon(this, p_env, thr_args);
#endif /*__cplusplus*/
;
可见JavaVM的主要接口如下:
AttachCurrentThread — 将当前的Thread attach到JavaVM,主要是生成JniEnv对象,JniEnv对象是属于线程的,不同的线程有自己的JniEnv。JavaVM创建的时候,会在当前线程自动attach作为Java的主线程,Java->Native的JNI调用就是走这个线程,而如果你想在自己的pthread里调用Java的代码的话,就需要调用AttachCurrentThread,得到JniEnv才能执行Java代码。
DetachCurrentThread — Detach当前线程,销毁JniEnv。
GetEnv — 获得当前线程的JNIEnv,JNI是线程相关的,只有Attach过的线程,才有JniEnv对象。
DestoryJavaVM — 销毁JavaVM。
JavaVM是全局的,而JNIEnv是线程相关的,JNIEnv定义了所有的JNI调用的接口:
struct JNINativeInterface
void* reserved0;
void* reserved1;
void* reserved2;
void* reserved3;
jint (*GetVersion)(JNIEnv *);
jclass (*DefineClass)(JNIEnv*, const char*, jobject, const jbyte*,
jsize);
jclass (*FindClass)(JNIEnv*, const char*);
jmethodID (*FromReflectedMethod)(JNIEnv*, jobject);
jfieldID (*FromReflectedField)(JNIEnv*, jobject);
/* spec doesn't show jboolean parameter */
jobject (*ToReflectedMethod)(JNIEnv*, jclass, jmethodID, jboolean);
jclass (*GetSuperclass)(JNIEnv*, jclass);
jboolean (*IsAssignableFrom)(JNIEnv*, jclass, jclass);
/* spec doesn't show jboolean parameter */
jobject (*ToReflectedField)(JNIEnv*, jclass, jfieldID, jboolean);
jint (*Throw)(JNIEnv*, jthrowable);
jint (*ThrowNew)(JNIEnv *, jclass, const char *);
jthrowable (*ExceptionOccurred)(JNIEnv*);
void (*ExceptionDescribe)(JNIEnv*);
void (*ExceptionClear)(JNIEnv*);
void (*FatalError)(JNIEnv*, const char*);
jint (*PushLocalFrame)(JNIEnv*, jint);
jobject (*PopLocalFrame)(JNIEnv*, jobject);
jobject (*NewGlobalRef)(JNIEnv*, jobject);
void (*DeleteGlobalRef)(JNIEnv*, jobject);
void (*DeleteLocalRef)(JNIEnv*, jobject);
jboolean (*IsSameObject)(JNIEnv*, jobject, jobject);
jobject (*NewLocalRef)(JNIEnv*, jobject);
jint (*EnsureLocalCapacity)(JNIEnv*, jint);
jobject (*AllocObject)(JNIEnv*, jclass);
jobject (*NewObject)(JNIEnv*, jclass, jmethodID, ...);
jobject (*NewObjectV)(JNIEnv*, jclass, jmethodID, va_list);
jobject (*NewObjectA)(JNIEnv*, jclass, jmethodID, jvalue*);
jclass (*GetObjectClass)(JNIEnv*, jobject);
jboolean (*IsInstanceOf)(JNIEnv*, jobject, jclass);
jmethodID (*GetMethodID)(JNIEnv*, jclass, const char*, const char*);
jobject (*CallObjectMethod)(JNIEnv*, jobject, jmethodID, ...);
jobject (*CallObjectMethodV)(JNIEnv*, jobject, jmethodID, va_list);
jobject (*CallObjectMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);
jboolean (*CallBooleanMethod)(JNIEnv*, jobject, jmethodID, ...);
jboolean (*CallBooleanMethodV)(JNIEnv*, jobject, jmethodID, va_list);
jboolean (*CallBooleanMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);
jbyte (*CallByteMethod)(JNIEnv*, jobject, jmethodID, ...);
jbyte (*CallByteMethodV)(JNIEnv*, jobject, jmethodID, va_list);
jbyte (*CallByteMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);
jchar (*CallCharMethod)(JNIEnv*, jobject, jmethodID, ...);
jchar (*CallCharMethodV)(JNIEnv*, jobject, jmethodID, va_list);
jchar (*CallCharMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);
jshort (*CallShortMethod)(JNIEnv*, jobject, jmethodID, ...);
jshort (*CallShortMethodV)(JNIEnv*, jobject, jmethodID, va_list);
jshort (*CallShortMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);
jint (*CallIntMethod)(JNIEnv*, jobject, jmethodID, ...);
jint (*CallIntMethodV)(JNIEnv*, jobject, jmethodID, va_list);
jint (*CallIntMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);
jlong (*CallLongMethod)(JNIEnv*, jobject, jmethodID, ...);
jlong (*CallLongMethodV)(JNIEnv*, jobject, jmethodID, va_list);
jlong (*CallLongMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);
jfloat (*CallFloatMethod)(JNIEnv*, jobject, jmethodID, ...);
jfloat (*CallFloatMethodV)(JNIEnv*, jobject, jmethodID, va_list);
jfloat (*CallFloatMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);
jdouble (*CallDoubleMethod)(JNIEnv*, jobject, jmethodID, ...);
jdouble (*CallDoubleMethodV)(JNIEnv*, jobject, jmethodID, va_list);
jdouble (*CallDoubleMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);
void (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...);
void (*CallVoidMethodV)(JNIEnv*, jobject, jmethodID, va_list);
void (*CallVoidMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);
jobject (*CallNonvirtualObjectMethod)(JNIEnv*, jobject, jclass,
jmethodID, ...);
jobject (*CallNonvirtualObjectMethodV)(JNIEnv*, jobject, jclass,
jmethodID, va_list);
jobject (*CallNonvirtualObjectMethodA)(JNIEnv*, jobject, jclass,
jmethodID, jvalue*);
jboolean (*CallNonvirtualBooleanMethod)(JNIEnv*, jobject, jclass,
jmethodID, ...);
jboolean (*CallNonvirtualBooleanMethodV)(JNIEnv*, jobject, jclass,
jmethodID, va_list);
jboolean (*CallNonvirtualBooleanMethodA)(JNIEnv*, jobject, jclass,
jmethodID, jvalue*);
jbyte (*CallNonvirtualByteMethod)(JNIEnv*, jobject, jclass,
jmethodID, ...);
jbyte (*CallNonvirtualByteMethodV)(JNIEnv*, jobject, jclass,
jmethodID, va_list);
jbyte (*CallNonvirtualByteMethodA)(JNIEnv*, jobject, jclass,
jmethodID, jvalue*);
jchar (*CallNonvirtualCharMethod)(JNIEnv*, jobject, jclass,
jmethodID, ...);
jchar (*CallNonvirtualCharMethodV)(JNIEnv*, jobject, jclass,
jmethodID, va_list);
jchar (*CallNonvirtualCharMethodA)(JNIEnv*, jobject, jclass,
jmethodID, jvalue*);
jshort (*CallNonvirtualShortMethod)(JNIEnv*, jobject, jclass,
jmethodID, ...);
jshort (*CallNonvirtualShortMethodV)(JNIEnv*, jobject, jclass,
jmethodID, va_list);
jshort (*CallNonvirtualShortMethodA)(JNIEnv*, jobject, jclass,
jmethodID, jvalue*);
jint (*CallNonvirtualIntMethod)(JNIEnv*, jobject, jclass,
jmethodID, ...);
jint (*CallNonvirtualIntMethodV)(JNIEnv*, jobject, jclass,
jmethodID, va_list);
jint (*CallNonvirtualIntMethodA)(JNIEnv*, jobject, jclass,
jmethodID, jvalue*);
jlong (*CallNonvirtualLongMethod)(JNIEnv*, jobject, jclass,
jmethodID, ...);
jlong (*CallNonvirtualLongMethodV)(JNIEnv*, jobject, jclass,
jmethodID, va_list);
jlong (*CallNonvirtualLongMethodA)(JNIEnv*, jobject, jclass,
jmethodID, jvalue*);
jfloat (*CallNonvirtualFloatMethod)(JNIEnv*, jobject, jclass,
jmethodID, ...);
jfloat (*CallNonvirtualFloatMethodV)(JNIEnv*, jobject, jclass,
jmethodID, va_list);
jfloat (*CallNonvirtualFloatMethodA)(JNIEnv*, jobject, jclass,
jmethodID, jvalue*);
jdouble (*CallNonvirtualDoubleMethod)(JNIEnv*, jobject, jclass,
jmethodID, ...);
jdouble (*CallNonvirtualDoubleMethodV)(JNIEnv*, jobject, jclass,
jmethodID, va_list);
jdouble (*CallNonvirtualDoubleMethodA)(JNIEnv*, jobject, jclass,
jmethodID, jvalue*);
void (*CallNonvirtualVoidMethod)(JNIEnv*, jobject, jclass,
jmethodID, ...);
void (*CallNonvirtualVoidMethodV)(JNIEnv*, jobject, jclass,
jmethodID, va_list);
void (*CallNonvirtualVoidMethodA)(JNIEnv*, jobject, jclass,
jmethodID, jvalue*);
jfieldID (*GetFieldID)(JNIEnv*, jclass, const char*, const char*);
jobject (*GetObjectField)(JNIEnv*, jobject, jfieldID);
jboolean (*GetBooleanField)(JNIEnv*, jobject, jfieldID);
jbyte (*GetByteField)(JNIEnv*, jobject, jfieldID);
jchar (*GetCharField)(JNIEnv*, jobject, jfieldID);
jshort (*GetShortField)(JNIEnv*, jobject, jfieldID);
jint (*GetIntField)(JNIEnv*, jobject, jfieldID);
jlong (*GetLongField)(JNIEnv*, jobject, jfieldID);
jfloat (*GetFloatField)(JNIEnv*, jobject, jfieldID);
jdouble (*GetDoubleField)(JNIEnv*, jobject, jfieldID);
void (*SetObjectField)(JNIEnv*, jobject, jfieldID, jobject);
void (*SetBooleanField)(JNIEnv*, jobject, jfieldID, jboolean);
void (*SetByteField)(JNIEnv*, jobject, jfieldID, jbyte);
void (*SetCharField)(JNIEnv*, jobject, jfieldID, jchar);
void (*SetShortField)(JNIEnv*, jobject, jfieldID, jshort);
void (*SetIntField)(JNIEnv*, jobject, jfieldID, jint);
void (*SetLongField)(JNIEnv*, jobject, jfieldID, jlong);
void (*SetFloatField)(JNIEnv*, jobject, jfieldID, jfloat);
void (*SetDoubleField)(JNIEnv*, jobject, jfieldID, jdouble);
jmethodID (*GetStaticMethodID)(JNIEnv*, jclass, const char*, const char*);
jobject (*CallStaticObjectMethod)(JNIEnv*, jclass, jmethodID, ...);
jobject (*CallStaticObjectMethodV)(JNIEnv*, jclass, jmethodID, va_list);
jobject (*CallStaticObjectMethodA)(JNIEnv*, jclass, jmethodID, jvalue*);
jboolean (*CallStaticBooleanMethod)(JNIEnv*, jclass, jmethodID, ...);
jboolean (*CallStaticBooleanMethodV)(JNIEnv*, jclass, jmethodID,
va_list);
jboolean (*CallStaticBooleanMethodA)(JNIEnv*, jclass, jmethodID,
jvalue*);
jbyte (*CallStaticByteMethod)(JNIEnv*, jclass, jmethodID, ...);
jbyte (*CallStaticByteMethodV)(JNIEnv*, jclass, jmethodID, va_list);
jbyte (*CallStaticByteMethodA)(JNIEnv*, jclass, jmethodID, jvalue*);
jchar (*CallStaticCharMethod)(JNIEnv*, jclass, jmethodID, ...);
jchar (*CallStaticCharMethodV)(JNIEnv*, jclass, jmethodID, va_list);
jchar (*CallStaticCharMethodA)(JNIEnv*, jclass, jmethodID, jvalue*);
jshort (*CallStaticShortMethod)(JNIEnv*, jclass, jmethodID, ...);
jshort (*CallStaticShortMethodV)(JNIEnv*, jclass, jmethodID, va_list);
jshort (*CallStaticShortMethodA)(JNIEnv*, jclass, jmethodID, jvalue*);
jint (*CallStaticIntMethod)(JNIEnv*, jclass, jmethodID, ...);
jint (*CallStaticIntMethodV)(JNIEnv*, jclass, jmethodID, va_list);
jint (*CallStaticIntMethodA)(JNIEnv*, jclass, jmethodID, jvalue*);
jlong (*CallStaticLongMethod)(JNIEnv*, jclass, jmethodID, ...);
jlong (*CallStaticLongMethodV)(JNIEnv*, jclass, jmethodID, va_list);
jlong (*CallStaticLongMethodA)(JNIEnv*, jclass, jmethodID, jvalue*);
jfloat (*CallStaticFloatMethod)(JNIEnv*, jclass, jmethodID, ...);
jfloat (*CallStaticFloatMethodV)(JNIEnv*, jclass, jmethodID, va_list);
jfloat (*CallStaticFloatMethodA)(JNIEnv*, jclass, jmethodID, jvalue*);
jdouble (*CallStaticDoubleMethod)(JNIEnv*, jclass, jmethodID, ...);
jdouble (*CallStaticDoubleMethodV)(JNIEnv*, jclass, jmethodID, va_list);
jdouble (*CallStaticDoubleMethodA)(JNIEnv*, jclass, jmethodID, jvalue*);
void (*CallStaticVoidMethod)(JNIEnv*, jclass, jmethodID, ...);
void (*CallStaticVoidMethodV)(JNIEnv*, jclass, jmethodID, va_list);
void (*CallStaticVoidMethodA)(JNIEnv*, jclass, jmethodID, jvalue*);
jfieldID (*GetStaticFieldID)(JNIEnv*, jclass, const char*,
const char*);
jobject (*GetStaticObjectField)(JNIEnv*, jclass, jfieldID);
jboolean (*GetStaticBooleanField)(JNIEnv*, jclass, jfieldID);
jbyte (*GetStaticByteField)(JNIEnv*, jclass, jfieldID);
jchar (*GetStaticCharField)(JNIEnv*, jclass, jfieldID);
jshort (*GetStaticShortField)(JNIEnv*, jclass, jfieldID);
jint (*GetStaticIntField)(JNIEnv*, jclass, jfieldID);
jlong (*GetStaticLongField)(JNIEnv*, jclass, jfieldID);
jfloat (*GetStaticFloatField)(JNIEnv*, jclass, jfieldID);
jdouble (*GetStaticDoubleField)(JNIEnv*, jclass, jfieldID);
void (*SetStaticObjectField)(JNIEnv*, jclass, jfieldID, jobject);
void (*SetStaticBooleanField)(JNIEnv*, jclass, jfieldID, jboolean);
void (*SetStaticByteField)(JNIEnv*, jclass, jfieldID, jbyte);
void (*SetStaticCharField)(JNIEnv*, jclass, jfieldID, jchar);
void (*SetStaticShortField)(JNIEnv*, jclass, jfieldID, jshort);
void (*SetStaticIntField)(JNIEnv*, jclass, jfieldID, jint);
void (*SetStaticLongField)(JNIEnv*, jclass, jfieldID, jlong);
void (*SetStaticFloatField)(JNIEnv*, jclass, jfieldID, jfloat);
void (*SetStaticDoubleField)(JNIEnv*, jclass, jfieldID, jdouble);
jstring (*NewString)(JNIEnv*, const jchar*, jsize);
jsize (*GetStringLength)(JNIEnv*, jstring);
const jchar* (*GetStringChars)(JNIEnv*, jstring, jboolean*);
void (*ReleaseStringChars)(JNIEnv*, jstring, const jchar*);
jstring (*NewStringUTF)(JNIEnv*, const char*);
jsize (*GetStringUTFLength)(JNIEnv*, jstring);
/* JNI spec says this returns const jbyte*, but that's inconsistent */
const char* (*GetStringUTFChars)(JNIEnv*, jstring, jboolean*);
void (*ReleaseStringUTFChars)(JNIEnv*, jstring, const char*);
jsize (*GetArrayLength)(JNIEnv*, jarray);
jobjectArray (*NewObjectArray)(JNIEnv*, jsize, jclass, jobject);
jobject (*GetObjectArrayElement)(JNIEnv*, jobjectArray, jsize);
void (*SetObjectArrayElement)(JNIEnv*, jobjectArray, jsize, jobject);
jbooleanArray (*NewBooleanArray)(JNIEnv*, jsize);
jbyteArray (*NewByteArray)(JNIEnv*, jsize);
jcharArray (*NewCharArray)(JNIEnv*, jsize);
jshortArray (*NewShortArray)(JNIEnv*, jsize);
jintArray (*NewIntArray)(JNIEnv*, jsize);
jlongArray (*NewLongArray)(JNIEnv*, jsize);
jfloatArray (*NewFloatArray)(JNIEnv*, jsize);
jdoubleArray (*NewDoubleArray)(JNIEnv*, jsize);
jboolean* (*GetBooleanArrayElements)(JNIEnv*, jbooleanArray, jboolean*);
jbyte* (*GetByteArrayElements)(JNIEnv*, jbyteArray, jboolean*);
jchar* (*GetCharArrayElements)(JNIEnv*, jcharArray, jboolean*);
jshort* (*GetShortArrayElements)(JNIEnv*, jshortArray, jboolean*);
jint* (*GetIntArrayElements)(JNIEnv*, jintArray, jboolean*);
jlong* (*GetLongArrayElements)(JNIEnv*, jlongArray, jboolean*);
jfloat* (*GetFloatArrayElements)(JNIEnv*, jfloatArray, jboolean*);
jdouble* (*GetDoubleArrayElements)(JNIEnv*, jdoubleArray, jboolean*);
void (*ReleaseBooleanArrayElements)(JNIEnv*, jbooleanArray,
jboolean*, jint);
void (*ReleaseByteArrayElements)(JNIEnv*, jbyteArray,
jbyte*, jint);
void (*ReleaseCharArrayElements)(JNIEnv*, jcharArray,
jchar*, jint);
void (*ReleaseShortArrayElements)(JNIEnv*, jshortArray,
jshort*, jint);
void (*ReleaseIntArrayElements)(JNIEnv*, jintArray,
jint*, jint);
void (*ReleaseLongArrayElements)(JNIEnv*, jlongArray,
jlong*, jint);
void (*ReleaseFloatArrayElements)(JNIEnv*, jfloatArray,
jfloat*, jint);
void (*ReleaseDoubleArrayElements)(JNIEnv*, jdoubleArray,
jdouble*, jint);
void (*GetBooleanArrayRegion)(JNIEnv*, jbooleanArray,
jsize, jsize, jboolean*);
void (*GetByteArrayRegion)(JNIEnv*, jbyteArray,
jsize, jsize, jbyte*);
void (*GetCharArrayRegion)(JNIEnv*, jcharArray,
jsize, jsize, jchar*);
void (*GetShortArrayRegion)(JNIEnv*, jshortArray,
jsize, jsize, jshort*);
void (*GetIntArrayRegion)(JNIEnv*, jintArray,
jsize, jsize, jint*);
void (*GetLongArrayRegion)(JNIEnv*, jlongArray,
jsize, jsize, jlong*);
void (*GetFloatArrayRegion)(JNIEnv*, jfloatArray,
jsize, jsize, jfloat*);
void (*GetDoubleArrayRegion)(JNIEnv*, jdoubleArray,
jsize, jsize, jdouble*);
/* spec shows these without const; some jni.h do, some don't */
void (*SetBooleanArrayRegion)(JNIEnv*, jbooleanArray,
jsize, jsize, const jboolean*);
void (*SetByteArrayRegion)(JNIEnv*, jbyteArray,
jsize, jsize, const jbyte*);
void (*SetCharArrayRegion)(JNIEnv*, jcharArray,
jsize, jsize, const jchar*);
void (*SetShortArrayRegion)(JNIEnv*, jshortArray,
jsize, jsize, const jshort*);
void (*SetIntArrayRegion)(JNIEnv*, jintArray,
jsize, jsize, const jint*);
void (*SetLongArrayRegion)(JNIEnv*, jlongArray,
jsize, jsize, const jlong*);
void (*SetFloatArrayRegion)(JNIEnv*, jfloatArray,
jsize, jsize, const jfloat*);
void (*SetDoubleArrayRegion)(JNIEnv*, jdoubleArray,
jsize, jsize, const jdouble*);
jint (*RegisterNatives)(JNIEnv*, jclass, const JNINativeMethod*,
jint);
jint (*UnregisterNatives)(JNIEnv*, jclass);
jint (*MonitorEnter)(JNIEnv*, jobject);
jint (*MonitorExit)(JNIEnv*, jobject);
jint (*GetJavaVM)(JNIEnv*, JavaVM**);
void (*GetStringRegion)(JNIEnv*, jstring, jsize, jsize, jchar*);
void (*GetStringUTFRegion)(JNIEnv*, jstring, jsize, jsize, char*);
void* (*GetPrimitiveArrayCritical)(JNIEnv*, jarray, jboolean*);
void (*ReleasePrimitiveArrayCritical)(JNIEnv*, jarray, void*, jint);
const jchar* (*GetStringCritical)(JNIEnv*, jstring, jboolean*);
void (*ReleaseStringCritical)(JNIEnv*, jstring, const jchar*);
jweak (*NewWeakGlobalRef)(JNIEnv*, jobject);
void (*DeleteWeakGlobalRef)(JNIEnv*, jweak);
jboolean (*ExceptionCheck)(JNIEnv*);
jobject (*NewDirectByteBuffer)(JNIEnv*, void*, jlong);
void* (*GetDirectBufferAddress)(JNIEnv*, jobject);
jlong (*GetDirectBufferCapacity)(JNIEnv*, jobject);
/* added in JNI 1.6 */
jobjectRefType (*GetObjectRefType)(JNIEnv*, jobject);
;
JNIEnv既包含了jmethod、jobject等类型定义,也包含了NewObject、CallObjectMethod等函数定义。JNIEnv有LocalReference、GlobalReference、WeakReference,每种Reference有自己的Reference Table,LocalReference的Table只有512项,超过512就会overflow导致crash,Java函数返回的时候出栈调用PopFrame(不同的虚拟机的函数名有不同)会释放当前栈的local reference。如果同一个Java函数里使用过多的local reference就需要显示的调用DeleteLocalRef来释放。GlobalReference则只有手动释放,所以不要指望Java函数退出的时候虚拟机会回收。
JNIEnv是Java执行的核心接口,JavaVM是管理JNIEnv的全局对象,这两接口就是虚拟机的核心接口。
JNI_CreateJavaVM是libdvm.so和libart.so都会导出的函数,用于创建虚拟机JavaVM。以下的代码分析都是出自Android L源码的art目录,art的JNI_CreateJavaVM在java_vm_ext.cc里定义的,代码不长,主要是Runtime类来实现。
extern "C" jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args)
ATRACE_BEGIN(__FUNCTION__);
const JavaVMInitArgs* args = static_cast<JavaVMInitArgs*>(vm_args);
if (IsBadJniVersion(args->version))
LOG(ERROR) << "Bad JNI version passed to CreateJavaVM: " << args->version;
ATRACE_END();
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;
if (!Runtime::Create(options, ignore_unrecognized))
ATRACE_END();
return JNI_ERR;
Runtime* runtime = Runtime::Current();
bool started = runtime->Start();
if (!started)
delete Thread::Current()->GetJniEnv();
delete runtime->GetJavaVM();
LOG(WARNING) << "CreateJavaVM failed";
ATRACE_END();
return JNI_ERR;
*p_env = Thread::Current()->GetJniEnv();
*p_vm = runtime->GetJavaVM();
ATRACE_END();
return JNI_OK;
Runtime是JavaVM的运行类,JavaVM的创建和JNIEnv的创建都是由其负责,JNI_CreateJavaVM的实现就是先调用Runtime::Create创建Runtime实例,调用Runtime::Init初始化。Runtime初始化之后,调用Start之后就能获得JavaVM和JNIEnv。
bool Runtime::Create(const RuntimeOptions& options, bool ignore_unrecognized)
// TODO: acquire a static mutex on Runtime to avoid racing.
if (Runtime::instance_ != nullptr)
return false;
InitLogging(nullptr); // Calls Locks::Init() as a side effect.
instance_ = new Runtime;
if (!instance_->Init(options, ignore_unrecognized))
// 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;
bool Runtime::Init(const RuntimeOptions& raw_options, bool ignore_unrecognized)
ATRACE_BEGIN("Runtime::Init");
CHECK_EQ(sysconf(_SC_PAGE_SIZE), kPageSize);
MemMap::Init();
using Opt = RuntimeArgumentMap;
RuntimeArgumentMap runtime_options;
std::unique_ptr<ParsedOptions> parsed_options(
ParsedOptions::Create(raw_options, ignore_unrecognized, &runtime_options));
if (parsed_options.get() == nullptr)
LOG(ERROR) << "Failed to parse options";
ATRACE_END();
return false;
VLOG(startup) << "Runtime::Init -verbose:startup enabled";
QuasiAtomic::Startup();
Monitor::Init(runtime_options.GetOrDefault(Opt::LockProfThreshold),
runtime_options.GetOrDefault(Opt::HookIsSensitiveThread));
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);
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);
stack_trace_file_ = runtime_options.ReleaseOrDefault(Opt::StackTraceFile);
compiler_executable_ = runtime_options.ReleaseOrDefault(Opt::Compiler);
compiler_options_ = runtime_options.ReleaseOrDefault(Opt::CompilerOptions);
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;
intern_table_ = new InternTable;
verify_ = runtime_options.GetOrDefault(Opt::Verify);
allow_dex_file_fallback_ = !runtime_options.Exists(Opt::NoDexFileFallback);
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);
XGcOption xgc_option = runtime_options.GetOrDefault(Opt::GcOption);
ATRACE_BEGIN("CreateHeap");
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),
runtime_options.GetOrDefault(Opt::ForegroundHeapGrowthMultiplier),
runtime_options.GetOrDefault(Opt::MemoryMaximumSize),
runtime_options.GetOrDefault(Opt::NonMovingSpaceCapacity),
runtime_options.GetOrDefault(Opt::Image),
runtime_options.GetOrDefault(Opt::ImageInstructionSet),
xgc_option.collector_type_,
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_,
runtime_options.GetOrDefault(Opt::EnableHSpaceCompactForOOM),
runtime_options.GetOrDefault(Opt::HSpaceCompactForOOMMinIntervalsMs));
ATRACE_END();
if (heap_->GetImageSpace() == nullptr && !allow_dex_file_fallback_)
LOG(ERROR) << "Dex file fallback disabled, cannot continue without image.";
ATRACE_END();
return false;
dump_gc_performance_on_shutdown_ = runtime_options.Exists(Opt::DumpGCPerformanceOnShutdown);
if (runtime_options.Exists(Opt::JdwpOptions))
Dbg::ConfigureJdwp(runtime_options.GetOrDefault(Opt::JdwpOptions));
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_->SetUseJIT(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, false));
if (IsCompiler() && Is64BitInstructionSet(kRuntimeISA))
// 4gb, no malloc. Explanation in header.
low_4gb_arena_pool_.reset(new ArenaPool(false, true));
linear_alloc_.reset(new LinearAlloc(low_4gb_arena_pool_.get()));
else
linear_alloc_.reset(new LinearAlloc(arena_pool_.get()));
BlockSignals();
InitPlatformSignalHandlers();
// Change the implicit checks flags based on runtime architecture.
switch (kRuntimeISA)
case kArm:
case kThumb2:
case kX86:
case kArm64:
case kX86_64:
case kMips:
case kMips64:
implicit_null_checks_ = true;
// Installing stack protection does not play well with valgrind.
implicit_so_checks_ = (RUNNING_ON_VALGRIND == 0);
break;
default:
// Keep the defaults.
break;
// Always initialize the signal chain so that any calls to sigaction get
// correctly routed to the next in the chain regardless of whether we
// have claimed the signal or not.
InitializeSignalChain();
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);
java_vm_ = new JavaVMExt(this, runtime_options);
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);
// 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);
class_linker_ = new ClassLinker(intern_table_);
if (GetHeap()->HasImageSpace())
ATRACE_BEGIN("InitFromImage");
class_linker_->InitFromImage();
ATRACE_END();
if (kIsDebugBuild)
GetHeap()->GetImageSpace()->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_ = Join(dex_locations, ':');
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;
OpenDexFiles(dex_filenames,
dex_locations,
runtime_options.GetOrDefault(Opt::Image),
&boot_class_path);
instruction_set_ = runtime_options.GetOrDefault(Opt::ImageInstructionSet);
class_linker_->InitWithoutImage(std::move(boot_class_path));
// TODO: Should we move the following to InitWithoutImage?
SetInstructionSet(instruction_set_);
for (int i = 0; i < Runtime::kLastCalleeSaveType; i++)
Runtime::CalleeSaveType type = Runtime::CalleeSaveType(i);
if (!HasCalleeSaveMethod(type))
SetCalleeSaveMethod(CreateCalleeSaveMethod(), type);
CHECK(class_linker_ != nullptr);
// Initialize the special sentinel_ value early.
sentinel_ = GcRoot<mirror::Object>(class_linker_->AllocObject(self));
CHECK(sentinel_.Read() != 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;
auto&& profiler_options = runtime_options.ReleaseOrDefault(Opt::ProfilerOpts);
profile_output_filename_ = profiler_options.output_file_name_;
// TODO: Don't do this, just change ProfilerOptions to include the output file name?
ProfilerOptions other_options(
profiler_options.enabled_,
profiler_options.period_s_,
profiler_options.duration_s_,
profiler_options.interval_us_,
profiler_options.backoff_coefficient_,
profiler_options.start_immediately_,
profiler_options.top_k_threshold_,
profiler_options.top_k_change_threshold_,
profiler_options.profile_type_,
profiler_options.max_stack_depth_);
profiler_options_ = other_options;
// 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();
// 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);
VLOG(startup) << "Runtime::Init exiting";
ATRACE_END();
return true;
Runtime的Init函数创建Heap实例实现GC
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),
runtime_options.GetOrDefault(Opt::ForegroundHeapGrowthMultiplier),
runtime_options.GetOrDefault(Opt::MemoryMaximumSize),
runtime_options.GetOrDefault(Opt::NonMovingSpaceCapacity),
runtime_options.GetOrDefault(Opt::Image),
runtime_options.GetOrDefault(Opt::ImageInstructionSet),
xgc_option.collector_type_,
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_,
runtime_options.GetOrDefault(Opt::EnableHSpaceCompactForOOM),
runtime_options.GetOrDefault(Opt::HSpaceCompactForOOMMinIntervalsMs));
创建虚拟机主线程、JavaVMExt实例(继承自JavaVM)
java_vm_ = new JavaVMExt(this, runtime_options);
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);
// Set us to runnable so tools using a runtime can allocate and GC by default
self->TransitionFromSuspendedToRunnable();
初始化ClassLinker,用作加载类、方法等。ClassLinker加载类有两个初始化方法,一个是InitFromImage,一个是InitFromWithoutImage。前者是通过ImageSpace来加载系统类,后者是通过boot_class_path,boot_class_path是系统类的DexFile数组。ImageSpace的优点是加载快,通过mmap加载一个系统类的镜像文件。
class_linker_ = new ClassLinker(intern_table_);
if (GetHeap()->HasImageSpace())
ATRACE_BEGIN("InitFromImage");
class_linker_->InitFromImage();
ATRACE_END();
if (kIsDebugBuild)
GetHeap()->GetImageSpace()->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_ = Join(dex_locations, ':');
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;
OpenDexFiles(dex_filenames,
dex_locations,
runtime_options.GetOrDefault(Opt::Image),
&boot_class_path);
instruction_set_ = runtime_options.GetOrDefault(Opt::ImageInstructionSet);
class_linker_->InitWithoutImage(std::move(boot_class_path));
// TODO: Should we move the following to InitWithoutImage?
SetInstructionSet(instruction_set_);
for (int i = 0; i < Runtime::kLastCalleeSaveType; i++)
Runtime::CalleeSaveType type = Runtime::CalleeSaveType(i);
if (!HasCalleeSaveMethod(type))
SetCalleeSaveMethod(CreateCalleeSaveMethod(), type);
让我们来看看ClassLinker的初始化,先看InitWithoutImage
void ClassLinker::InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> boot_class_path)
VLOG(startup) << "ClassLinker::Init";
Thread* const self = Thread::Current();
Runtime* const runtime = Runtime::Current();
gc::Heap* const heap = runtime->GetHeap();
CHECK(!heap->HasImageSpace()) << "Runtime has image. We should use it.";
CHECK(!init_done_);
// Use the pointer size from the runtime since we are probably creating the image.
image_pointer_size_ = InstructionSetPointerSize(runtime->GetInstructionSet());
// java_lang_Class comes first, it's needed for AllocClass
// The GC can't handle an object with a null class since we can't get the size of this object.
heap->IncrementDisableMovingGC(self);
StackHandleScope<64> hs(self); // 64 is picked arbitrarily.
auto class_class_size = mirror::Class::ClassClassSize(image_pointer_size_);
Handle<mirror::Class> java_lang_Class(hs.NewHandle(down_cast<mirror::Class*>(
heap->AllocNonMovableObject<true>(self, nullptr, class_class_size, VoidFunctor()))));
CHECK(java_lang_Class.Get() != nullptr);
mirror::Class::SetClassClass(java_lang_Class.Get());
java_lang_Class->SetClass(java_lang_Class.Get());
if (kUseBakerOrBrooksReadBarrier)
java_lang_Class->AssertReadBarrierPointer();
java_lang_Class->SetClassSize(class_class_size);
java_lang_Class->SetPrimitiveType(Primitive::kPrimNot);
heap->DecrementDisableMovingGC(self);
// AllocClass(mirror::Class*) can now be used
// Class[] is used for reflection support.
auto class_array_class_size = mirror::ObjectArray<mirror::Class>::ClassSize(image_pointer_size_);
Handle<mirror::Class> class_array_class(hs.NewHandle(
AllocClass(self, java_lang_Class.Get(), class_array_class_size)));
class_array_class->SetComponentType(java_lang_Class.Get());
// java_lang_Object comes next so that object_array_class can be created.
Handle<mirror::Class> java_lang_Object(hs.NewHandle(
AllocClass(self, java_lang_Class.Get(), mirror::Object::ClassSize(image_pointer_size_))));
CHECK(java_lang_Object.Get() != nullptr);
// backfill Object as the super class of Class.
java_lang_Class->SetSuperClass(java_lang_Object.Get());
mirror::Class::SetStatus(java_lang_Object, mirror::Class::kStatusLoaded, self);
// Object[] next to hold class roots.
Handle<mirror::Class> object_array_class(hs.NewHandle(
AllocClass(self, java_lang_Class.Get(),
mirror::ObjectArray<mirror::Object>::ClassSize(image_pointer_size_))));
object_array_class->SetComponentType(java_lang_Object.Get());
// Setup the char (primitive) class to be used for char[].
Handle<mirror::Class> char_class(hs.NewHandle(
AllocClass(self, java_lang_Class.Get(),
mirror::Class::PrimitiveClassSize(image_pointer_size_))));
// The primitive char class won't be initialized by
// InitializePrimitiveClass until line 459, but strings (and
// internal char arrays) will be allocated before that and the
// component size, which is computed from the primitive type, needs
// to be set here.
char_class->SetPrimitiveType(Primitive::kPrimChar);
// Setup the char[] class to be used for String.
Handle<mirror::Class> char_array_class(hs.NewHandle(
AllocClass(self, java_lang_Class.Get(), mirror::Array::ClassSize(image_pointer_size_))));
char_array_class->SetComponentType(char_class.Get());
mirror::CharArray::SetArrayClass(char_array_class.Get());
// Setup String.
Handle<mirror::Class> java_lang_String(hs.NewHandle(
AllocClass(self, java_lang_Class.Get(), mirror::String::ClassSize(image_pointer_size_))));
mirror::String::SetClass(java_lang_String.Get());
mirror::Class::SetStatus(java_lang_String, mirror::Class::kStatusResolved, self);
java_lang_String->SetStringClass();
// Setup java.lang.ref.Reference.
Handle<mirror::Class> java_lang_ref_Reference(hs.NewHandle(
AllocClass(self, java_lang_Class.Get(), mirror::Reference::ClassSize(image_pointer_size_))));
mirror::Reference::SetClass(java_lang_ref_Reference.Get());
java_lang_ref_Reference->SetObjectSize(mirror::Reference::InstanceSize());
mirror::Class::SetStatus(java_lang_ref_Reference, mirror::Class::kStatusResolved, self);
// Create storage for root classes, save away our work so far (requires descriptors).
class_roots_ = GcRoot<mirror::ObjectArray<mirror::Class>>(
mirror::ObjectArray<mirror::Class>::Alloc(self, object_array_class.Get(),
kClassRootsMax));
CHECK(!class_roots_.IsNull());
SetClassRoot(kJavaLangClass, java_lang_Class.Get());
SetClassRoot(kJavaLangObject, java_lang_Object.Get());
SetClassRoot(kClassArrayClass, class_array_class.Get());
SetClassRoot(kObjectArrayClass, object_array_class.Get());
SetClassRoot(kCharArrayClass, char_array_class.Get());
SetClassRoot(kJavaLangString, java_lang_String.Get());
SetClassRoot(kJavaLangRefReference, java_lang_ref_Reference.Get());
// Setup the primitive type classes.
SetClassRoot(kPrimitiveBoolean, CreatePrimitiveClass(self, Primitive::kPrimBoolean));
SetClassRoot(kPrimitiveByte, CreatePrimitiveClass(self, Primitive::kPrimByte));
SetClassRoot(kPrimitiveShort, CreatePrimitiveClass(self, Primitive::kPrimShort));
SetClassRoot(kPrimitiveInt, CreatePrimitiveClass(self, Primitive::kPrimInt));
SetClassRoot(kPrimitiveLong, CreatePrimitiveClass(self, Primitive::kPrimLong));
SetClassRoot(kPrimitiveFloat, CreatePrimitiveClass(self, Primitive::kPrimFloat));
SetClassRoot(kPrimitiveDouble, CreatePrimitiveClass(self, Primitive::kPrimDouble));
SetClassRoot(kPrimitiveVoid, CreatePrimitiveClass(self, Primitive::kPrimVoid));
// Create array interface entries to populate once we can load system classes.
array_iftable_ = GcRoot<mirror::IfTable>(AllocIfTable(self, 2));
// Create int array type for AllocDexCache (done in AppendToBootClassPath).
Handle<mirror::Class> int_array_class(hs.NewHandle(
AllocClass(self, java_lang_Class.Get(), mirror::Array::ClassSize(image_pointer_size_))));
int_array_class->SetComponentType(GetClassRoot(kPrimitiveInt));
mirror::IntArray::SetArrayClass(int_array_class.Get());
SetClassRoot(kIntArrayClass, int_array_class.Get());
// Create long array type for AllocDexCache (done in AppendToBootClassPath).
Handle<mirror::Class> long_array_class(hs.NewHandle(
AllocClass(self, java_lang_Class.Get(), mirror::Array::ClassSize(image_pointer_size_))));
long_array_class->SetComponentType(GetClassRoot(kPrimitiveLong));
mirror::LongArray::SetArrayClass(long_array_class.Get());
SetClassRoot(kLongArrayClass, long_array_class.Get());
// now that these are registered, we can use AllocClass() and AllocObjectArray
// Set up DexCache. This cannot be done later since AppendToBootClassPath calls AllocDexCache.
Handle<mirror::Class> java_lang_DexCache(hs.NewHandle(
AllocClass(self, java_lang_Class.Get(), mirror::DexCache::ClassSize(image_pointer_size_))));
SetClassRoot(kJavaLangDexCache, java_lang_DexCache.Get());
java_lang_DexCache->SetObjectSize(mirror::DexCache::InstanceSize());
mirror::Class::SetStatus(java_lang_DexCache, mirror::Class::kStatusResolved, self);
// Set up array classes for string, field, method
Handle<mirror::Class> object_array_string(hs.NewHandle(
AllocClass(self, java_lang_Class.Get(),
mirror::ObjectArray<mirror::String>::ClassSize(image_pointer_size_))));
object_array_string->SetComponentType(java_lang_String.Get());
SetClassRoot(kJavaLangStringArrayClass, object_array_string.Get());
// Create runtime resolution and imt conflict methods.
runtime->SetResolutionMethod(runtime->CreateResolutionMethod());
runtime->SetImtConflictMethod(runtime->CreateImtConflictMethod());
runtime->SetImtUnimplementedMethod(runtime->CreateImtConflictMethod());
// Setup boot_class_path_ and register class_path now that we can use AllocObjectArray to create
// DexCache instances. Needs to be after String, Field, Method arrays since AllocDexCache uses
// these roots.
CHECK_NE(0U, boot_class_path.size());
for (auto& dex_file : boot_class_path)
CHECK(dex_file.get() != nullptr);
AppendToBootClassPath(self, *dex_file);
opened_dex_files_.push_back(std::move(dex_file));
// now we can use FindSystemClass
// run char class through InitializePrimitiveClass to finish init
InitializePrimitiveClass(char_class.Get(), Primitive::kPrimChar);
SetClassRoot(kPrimitiveChar, char_class.Get()); // needs descriptor
// Set up GenericJNI entrypoint. That is mainly a hack for common_compiler_test.h so that
// we do not need friend classes or a publicly exposed setter.
quick_generic_jni_trampoline_ = GetQuickGenericJniStub();
if (!runtime->IsAotCompiler())
// We need to set up the generic trampolines since we don't have an image.
quick_resolution_trampoline_ = GetQuickResolutionStub();
quick_imt_conflict_trampoline_ = GetQuickImtConflictStub();
quick_to_interpreter_bridge_trampoline_ = GetQuickToInterpreterBridge();
// Object, String and DexCache need to be rerun through FindSystemClass to finish init
mirror::Class::SetStatus(java_lang_Object, mirror::Class::kStatusNotReady, self);
CHECK_EQ(java_lang_Object.Get(), FindSystemClass(self, "Ljava/lang/Object;"));
CHECK_EQ(java_lang_Object->GetObjectSize(), mirror::Object::InstanceSize());
mirror::Class::SetStatus(java_lang_String, mirror::Class::kStatusNotReady, self);
mirror::Class* String_class = FindSystemClass(self, "Ljava/lang/String;");
if (java_lang_String.Get() != String_class)
std::ostringstream os1, os2;
java_lang_String->DumpClass(os1, mirror::Class::kDumpClassFullDetail);
String_class->DumpClass(os2, mirror::Class::kDumpClassFullDetail);
LOG(FATAL) << os1.str() << "\\n\\n" << os2.str();
mirror::Class::SetStatus(java_lang_DexCache, mirror::Class::kStatusNotReady, self);
CHECK_EQ(java_lang_DexCache.Get(), FindSystemClass(self, "Ljava/lang/DexCache;"));
CHECK_EQ(java_lang_DexCache->GetObjectSize(), mirror::DexCache::InstanceSize());
// Setup the primitive array type classes - can't be done until Object has a vtable.
SetClassRoot(kBooleanArrayClass, FindSystemClass(self, "[Z"));
mirror::BooleanArray::SetArrayClass(GetClassRoot(kBooleanArrayClass));
SetClassRoot(kByteArrayClass, FindSystemClass(self, "[B"));
mirror::ByteArray::SetArrayClass(GetClassRoot(kByteArrayClass));
CHECK_EQ(char_array_class.Get(), FindSystemClass(self, "[C"));
SetClassRoot(kShortArrayClass, FindSystemClass(self, "[S"));
mirror::ShortArray::SetArrayClass(GetClassRoot(kShortArrayClass));
CHECK_EQ(int_array_class.Get(), FindSystemClass(self, "[I"));
CHECK_EQ(long_array_class.Get(), FindSystemClass(self, "[J"));
SetClassRoot(kFloatArrayClass, FindSystemClass(self, "[F"));
mirror::FloatArray::SetArrayClass(GetClassRoot(kFloatArrayClass));
SetClassRoot(kDoubleArrayClass, FindSystemClass(self, "[D"));
mirror::DoubleArray::SetArrayClass(GetClassRoot(kDoubleArrayClass));
CHECK_EQ(class_array_class.Get(), FindSystemClass(self, "[Ljava/lang/Class;"));
CHECK_EQ(object_array_class.Get(), FindSystemClass(self, "[Ljava/lang/Object;"));
// Setup the single, global copy of "iftable".
auto java_lang_Cloneable = hs.NewHandle(FindSystemClass(self, "Ljava/lang/Cloneable;"));
CHECK(java_lang_Cloneable.Get() != nullptr);
auto java_io_Serializable = hs.NewHandle(FindSystemClass(self, "Ljava/io/Serializable;"));
CHECK(java_io_Serializable.Get() != nullptr);
// We assume that Cloneable/Serializable don't have superinterfaces -- normally we'd have to
// crawl up and explicitly list all of the supers as well.
array_iftable_.Read()->SetInterface(0, java_lang_Cloneable.Get());
array_iftable_.Read()->SetInterface(1, java_io_Serializable.Get());
// Sanity check Class[] and Object[]'s interfaces. GetDirectInterface may cause thread
// suspension.
CHECK_EQ(java_lang_Cloneable.Get(),
mirror::Class::GetDirectInterface(self, class_array_class, 0));
CHECK_EQ(java_io_Serializable.Get(),
mirror::Class::GetDirectInterface(self, class_array_class, 1));
CHECK_EQ(java_lang_Cloneable.Get(),
mirror::Class::GetDirectInterface(self, object_array_class, 0));
CHECK_EQ(java_io_Serializable.Get(),
mirror::Class::GetDirectInterface(self, object_array_class, 1));
// Run Class, ArtField, and ArtMethod through FindSystemClass. This initializes their
// dex_cache_ fields and register them in class_table_.
CHECK_EQ(java_lang_Class.Get(), FindSystemClass(self, "Ljava/lang/Class;"));
CHECK_EQ(object_array_string.Get(),
FindSystemClass(self, GetClassRootDescriptor(kJavaLangStringArrayClass)));
// End of special init trickery, subsequent classes may be loaded via FindSystemClass.
// Create java.lang.reflect.Proxy root.
SetClassRoot(kJavaLangReflectProxy, FindSystemClass(self, "Ljava/lang/reflect/Proxy;"));
// Create java.lang.reflect.Field.class root.
auto* class_root = FindSystemClass(self, "Ljava/lang/reflect/Field;");
CHECK(class_root != nullptr);
SetClassRoot(kJavaLangReflectField, class_root);
mirror::Field::SetClass(class_root);
// Create java.lang.reflect.Field array root.
class_root = FindSystemClass(self, "[Ljava/lang/reflect/Field;");
CHECK(class_root != nullptr);
SetClassRoot(kJavaLangReflectFieldArrayClass, class_root);
mirror::Field::SetArrayClass(class_root);
// Create java.lang.reflect.Constructor.class root and array root.
class_root = FindSystemClass(self, "Ljava/lang/reflect/Constructor;");
CHECK(class_root != nullptr);
SetClassRoot(kJavaLangReflectConstructor, class_root);
mirror::Constructor::SetClass(class_root);
class_root = FindSystemClass(self, "[Ljava/lang/reflect/Constructor;");
CHECK(class_root != nullptr);
SetClassRoot(kJavaLangReflectConstructorArrayClass, class_root);
mirror::Constructor::SetArrayClass(class_root);
// Create java.lang.reflect.Method.class root and array root.
class_root = FindSystemClass(self, "Ljava/lang/reflect/Method;");
CHECK(class_root != nullptr);
SetClassRoot(kJavaLangReflectMethod, class_root);
mirror::Method::SetClass(class_root);
class_root = FindSystemClass(self, "[Ljava/lang/reflect/Method;");
CHECK(class_root != nullptr);
SetClassRoot(kJavaLangReflectMethodArrayClass, class_root);
mirror::Method::SetArrayClass(class_root);
// java.lang.ref classes need to be specially flagged, but otherwise are normal classes
// finish initializing Reference class
mirror::Class::SetStatus(java_lang_ref_Reference, mirror::Class::kStatusNotReady, self);
CHECK_EQ(java_lang_ref_Reference.Get(), FindSystemClass(self, "Ljava/lang/ref/Reference;"));
CHECK_EQ(java_lang_ref_Reference->GetObjectSize(), mirror::Reference::InstanceSize());
CHECK_EQ(java_lang_ref_Reference->GetClassSize(),
mirror::Reference::ClassSize(image_pointer_size_));
class_root = FindSystemClass(self, "Ljava/lang/ref/FinalizerReference;");
class_root->SetAccessFlags(class_root->GetAccessFlags() |
kAccClassIsReference | kAccClassIsFinalizerReference);
class_root = FindSystemClass(self, "Ljava/lang/ref/PhantomReference;");
class_root->SetAccessFlags(class_root->GetAccessFlags() | kAccClassIsReference |
kAccClassIsPhantomReference);
class_root = FindSystemClass(self, "Ljava/lang/ref/SoftReference;");
class_root->SetAccessFlags(class_root->GetAccessFlags() | kAccClassIsReference);
class_root = FindSystemClass(self, "Ljava/lang/ref/WeakReference;");
class_root->SetAccessFlags(class_root->GetAccessFlags() | kAccClassIsReference |
kAccClassIsWeakReference);
// Setup the ClassLoader, verifying the object_size_.
class_root = FindSystemClass(self, "Ljava/lang/ClassLoader;");
CHECK_EQ(class_root->GetObjectSize(), mirror::ClassLoader::InstanceSize());
SetClassRoot(kJavaLangClassLoader, class_root);
// Set up java.lang.Throwable, java.lang.ClassNotFoundException, and
// java.lang.StackTraceElement as a convenience.
SetClassRoot(kJavaLangThrowable, FindSystemClass(self, "Ljava/lang/Throwable;"));
mirror::Throwable::SetClass(GetClassRoot(kJavaLangThrowable));
SetClassRoot(kJavaLangClassNotFoundException,
FindSystemClass(self, "Ljava/lang/ClassNotFoundException;"));
SetClassRoot(kJavaLangStackTraceElement, FindSystemClass(self, "Ljava/lang/StackTraceElement;"));
SetClassRoot(kJavaLangStackTraceElementArrayClass,
FindSystemClass(self, "[Ljava/lang/StackTraceElement;"));
mirror::StackTraceElement::SetClass(GetClassRoot(kJavaLangStackTraceElement));
// Ensure void type is resolved in the core's dex cache so java.lang.Void is correctly
// initialized.
const DexFile& dex_file = java_lang_Object->GetDexFile();
const DexFile::StringId* void_string_id = dex_file.FindStringId("V");
CHECK(void_string_id != nullptr);
uint32_t void_string_index = dex_file.GetIndexForStringId(*void_string_id);
const DexFile::TypeId* void_type_id = dex_file.FindTypeId(void_string_index);
CHECK(void_type_id != nullptr);
uint16_t void_type_idx = dex_file.GetIndexForTypeId(*void_type_id);
// Now we resolve void type so the dex cache contains it. We use java.lang.Object class
// as referrer so the used dex cache is core's one.
mirror::Class* resolved_type = ResolveType(dex_file, void_type_idx, java_lang_Object.Get());
CHECK_EQ(resolved_type, GetClassRoot(kPrimitiveVoid));
self->AssertNoPendingException();
FinishInit(self);
VLOG(startup) << "ClassLinker::InitFromCompiler exiting";
参数boot_class_path是由之前的OpenDexFiles函数创建,具体的实现细节,我们放到后期分析DexFile,OatFile,OatDexFile的时候再深入。
OpenDexFiles(dex_filenames,
dex_locations,
runtime_options.GetOrDefault(Opt::Image),
&boot_class_path);
再回到InitWithoutImage的实现,首先实例化java_lang_class(java.lang.Class)这个基本的Class类,以上是关于深入理解ART虚拟机—虚拟机的启动的主要内容,如果未能解决你的问题,请参考以下文章