在AndroidRuntime.start函数中,在经过startVm和startReg两个函数对Dalvik虚拟机实例初始化之后(启动过程)
会执行如下代码
<span style="font-size:14px;"> if (startClass == NULL) {
ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
/* keep going */
} else {
jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
"([Ljava/lang/String;)V");
if (startMeth == NULL) {
ALOGE("JavaVM unable to find main() in '%s'\n", className);
/* keep going */
} else {
env->CallStaticVoidMethod(startClass, startMeth, strArray);</span>
也就是说会通过CallStaticVoidMethod来启动入口函数。
CallStaticVoidMethod来自于struct _JNIEnv结构中
void CallVoidMethod(jobject obj, jmethodID methodID, ...)
{
va_list args;
va_start(args, methodID);
functions->CallVoidMethodV(this, obj, methodID, args);
va_end(args);
}当中的functions是一个const struct JNINativeInterface*成员,指向一个回调函数表
<span style="font-size:14px;">void (*CallStaticVoidMethodV)(JNIEnv*, jclass, jmethodID, va_list);</span>
从启动过程的分析看到,在JNI_CreateJavaVM函数中,返回的JNIEnv** p_env实际上是由强制类型转化得来的
*p_env = (JNIEnv*) pEnv; 而这个pEnv本身则是一个
JNIEnvExt *对象
pEnv = (JNIEnvExt*) dvmCreateJNIEnv(NULL);所以,这里JNIEnv的functions实际上是JNIEnvExt结构中的第一个成员
struct JNIEnvExt {
const struct JNINativeInterface* funcTable; /* must be first */
const struct JNINativeInterface* baseFuncTable;
u4 envThreadId;
Thread* self;
/* if nonzero, we are in a "critical" JNI call */
int critical;
struct JNIEnvExt* prev;
struct JNIEnvExt* next;
};同样是JNINativeInterface结构的funcTable指针
在启动时,由dvmCreateJNIEnv创建这个pEnv(其实它的返回值就是JNIEnv结构)
JNIEnv* dvmCreateJNIEnv(Thread* self) {
JavaVMExt* vm = (JavaVMExt*) gDvmJni.jniVm;
//if (self != NULL)
// ALOGI("Ent CreateJNIEnv: threadid=%d %p", self->threadId, self);
assert(vm != NULL);
JNIEnvExt* newEnv = (JNIEnvExt*) calloc(1, sizeof(JNIEnvExt));
newEnv->funcTable = &gNativeInterface; //在这里
if (self != NULL) {
dvmSetJniEnvThreadId((JNIEnv*) newEnv, self);
assert(newEnv->envThreadId != 0);
} else {
/* make it obvious if we fail to initialize these later */
newEnv->envThreadId = 0x77777775;
newEnv->self = (Thread*) 0x77777779;
}
if (gDvmJni.useCheckJni) {
dvmUseCheckedJniEnv(newEnv);
}
ScopedPthreadMutexLock lock(&vm->envListLock);
/* insert at head of list */
newEnv->next = vm->envList;
assert(newEnv->prev == NULL);
if (vm->envList == NULL) {
// rare, but possible
vm->envList = newEnv;
} else {
vm->envList->prev = newEnv;
}
vm->envList = newEnv;
//if (self != NULL)
// ALOGI("Xit CreateJNIEnv: threadid=%d %p", self->threadId, self);
return (JNIEnv*) newEnv;
}所以这个funcTable指向了gNativeInterface
在gNativeInterface中有一个CallStaticVoidMethodV,它的定义在同一个文件中,是通过宏定义的
static _ctype CallStatic##_jname##MethodV(JNIEnv* env, jclass jclazz, \
jmethodID methodID, va_list args) \
{ \
UNUSED_PARAMETER(jclazz); \
ScopedJniThreadState ts(env); \
JValue result; \
dvmCallMethodV(ts.self(), (Method*)methodID, NULL, true, &result, args);\
if (_isref && !dvmCheckException(ts.self())) \
result.l = (Object*)addLocalReference(ts.self(), result.l); \
return _retok; \
} 终于找到了,也就是说最开始的env->CallStaticVoidMethod(startClass, startMeth, strArray);
其实是调用的这个宏(真的好绕)。
这个宏内容很简单,调用dvmCallMethonV执行下一步
void dvmCallMethodV(Thread* self, const Method* method, Object* obj,
bool fromJni, JValue* pResult, va_list args)
{
const char* desc = &(method->shorty[1]); // [0] is the return type.
int verifyCount = 0;
ClassObject* clazz;
u4* ins;
clazz = callPrep(self, method, obj, false);
if (clazz == NULL)
return;
/* "ins" for new frame start at frame pointer plus locals */
ins = ((u4*)self->interpSave.curFrame) +
(method->registersSize - method->insSize);
//ALOGD(" FP is %p, INs live at >= %p", self->interpSave.curFrame, ins);
/* put "this" pointer into in0 if appropriate */
if (!dvmIsStaticMethod(method)) {
#ifdef WITH_EXTRA_OBJECT_VALIDATION
assert(obj != NULL && dvmIsHeapAddress(obj));
#endif
*ins++ = (u4) obj;
verifyCount++;
}
while (*desc != '\0') {
switch (*(desc++)) {
case 'D': case 'J': {
u8 val = va_arg(args, u8);
memcpy(ins, &val, 8); // EABI prevents direct store
ins += 2;
verifyCount += 2;
break;
}
case 'F': {
/* floats were normalized to doubles; convert back */
float f = (float) va_arg(args, double);
*ins++ = dvmFloatToU4(f);
verifyCount++;
break;
}
case 'L': { /* 'shorty' descr uses L for all refs, incl array */
void* arg = va_arg(args, void*);
assert(obj == NULL || dvmIsHeapAddress(obj));
jobject argObj = reinterpret_cast<jobject>(arg);
if (fromJni)
*ins++ = (u4) dvmDecodeIndirectRef(self, argObj);
else
*ins++ = (u4) argObj;
verifyCount++;
break;
}
default: {
/* Z B C S I -- all passed as 32-bit integers */
*ins++ = va_arg(args, u4);
verifyCount++;
break;
}
}
}
#ifndef NDEBUG
if (verifyCount != method->insSize) {
ALOGE("Got vfycount=%d insSize=%d for %s.%s", verifyCount,
method->insSize, clazz->descriptor, method->name);
assert(false);
goto bail;
}
#endif
//dvmDumpThreadStack(dvmThreadSelf());
if (dvmIsNativeMethod(method)) {
TRACE_METHOD_ENTER(self, method);
/*
* Because we leave no space for local variables, "curFrame" points
* directly at the method arguments.
*/
(*method->nativeFunc)((u4*)self->interpSave.curFrame, pResult,
method, self);
TRACE_METHOD_EXIT(self, method);
} else {
dvmInterpret(self, method, pResult);
}
#ifndef NDEBUG
bail:
#endif
dvmPopFrame(self);
}函数有点长,不过没关系,直接看最后
dvmIsNativeMethod判断这个method是不是native,如果是,通过method的nativeFunc保存的地址就可以
直接进行调用。如果不是,也就是Java函数,那么调用dvmInterpert
dvmInterpert函数挺长的,而主要需要看的地方在这里
if (gDvm.executionMode == kExecutionModeInterpFast)
stdInterp = dvmMterpStd;
#if defined(WITH_JIT)
else if (gDvm.executionMode == kExecutionModeJit ||
gDvm.executionMode == kExecutionModeNcgO0 ||
gDvm.executionMode == kExecutionModeNcgO1)
stdInterp = dvmMterpStd;
#endif
else
stdInterp = dvmInterpretPortable;
// Call the interpreter
(*stdInterp)(self);Dalvik虚拟机有三种执行模式,fast、jit、protable
fast会针对本地平台进行优化,可以更快速的执行Java代码
jit会将Java代码动态编译为Native代码,然后执行
protable则是可移植模式,也就是通用模式
根据模式不同会选择dvmMterpStd和dvmInterpretProtable当中的一个执行。
void dvmMterpStd(Thread* self)
{
/* configure mterp items */
self->interpSave.methodClassDex = self->interpSave.method->clazz->pDvmDex;
IF_LOGVV() {
char* desc = dexProtoCopyMethodDescriptor(
&self->interpSave.method->prototype);
LOGVV("mterp threadid=%d : %s.%s %s",
dvmThreadSelf()->threadId,
self->interpSave.method->clazz->descriptor,
self->interpSave.method->name,
desc);
free(desc);
}
//ALOGI("self is %p, pc=%p, fp=%p", self, self->interpSave.pc,
// self->interpSave.curFrame);
//ALOGI("first instruction is 0x%04x", self->interpSave.pc[0]);
/*
* Handle any ongoing profiling and prep for debugging
*/
if (self->interpBreak.ctl.subMode != 0) {
TRACE_METHOD_ENTER(self, self->interpSave.method);
self->debugIsMethodEntry = true; // Always true on startup
}
dvmMterpStdRun(self);
#ifdef LOG_INSTR
ALOGD("|-- Leaving interpreter loop");
#endif
}继续调用dvmMterStdRun
void dvmMterpStdRun(Thread* self)
{
jmp_buf jmpBuf;
self->interpSave.bailPtr = &jmpBuf;
/* We exit via a longjmp */
if (setjmp(jmpBuf)) {
LOGVV("mterp threadid=%d returning", dvmThreadSelf()->threadId);
return;
}
/* run until somebody longjmp()s out */
while (true) {
typedef void (*Handler)(Thread* self);
u2 inst = /*self->interpSave.*/pc[0];
/*
* In mterp, dvmCheckBefore is handled via the altHandlerTable,
* while in the portable interpreter it is part of the handler
* FINISH code. For allstubs, we must do an explicit check
* in the interpretation loop.
*/
if (self->interpBreak.ctl.subMode) {
dvmCheckBefore(pc, fp, self);
}
Handler handler = (Handler) gDvmMterpHandlers[inst & 0xff];
(void) gDvmMterpHandlerNames; /* avoid gcc "defined but not used" */
LOGVV("handler %p %s",
handler, (const char*) gDvmMterpHandlerNames[inst & 0xff]);
(*handler)(self);
}
}获取指令然后处理
看下mterp下的目录
这些不同的平台文件夹下都是.S汇编文件,通过这种方法来提高程序运行速度
至于另外一个函数dvmInterpretProtable,实在有点长,就不贴出来了,内容大概一样的
提取指令,执行。
总结流程
本文详细解析了Android应用程序的启动流程,重点关注Dalvik虚拟机如何通过JNI接口调用Java层的main方法,以及Dalvik虚拟机内部如何解释执行Java字节码。
390

被折叠的 条评论
为什么被折叠?



