android虚拟机详解
来源:互联网 发布:淘宝运营规则 编辑:程序博客网 时间:2024/06/05 17:37
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server @system/core/rootdir/init.rc
/system/bin/app_process
|-->main(): @frameworks/base/cmds/app_process/app_main.cpp
虚拟机启动入口函数
if (strcmp(arg, "--zygote") == 0) zygote = true;
if (strcmp(arg, "--start-system-server") == 0) startSystemServer = true;
if (zygote) { runtime.start("com.android.internal.os.ZygoteInit",startSystemServer ? "start-system-server" : "");
|--> AndroidRuntime::start(const char* className, const char* options) 配置环境(ANDROID_ROOT)目录变量等 @frameworks/base/core/jni/AndroidRuntime.cpp
|--> AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv)
| |--> JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) @dalvik/vm/Jni.cpp
| |--> dvmStartup(int argc, const char* const argv[],bool ignoreUnrecognized, JNIEnv* pEnv) @dalvik/vm/Init.cpp
| |-->初始化组建
| |--> dvmCheckAsmConstants() 明确mterp解释器要用到的一些变量正确
| |--> dvmAllocTrackerStartup() 函数初始化跟踪显示系统,跟踪系统主要用生成调试系统的数据包
| |--> dvmGcStartup() 初始化垃圾回收器//初始化heap
| |--> dvmThreadStartup() 初始化线程列表和主线程环境参数
| |--> dvmInlineNativeStartup() 分配内部操作方法的表格内存
| |--> dvmRegisterMapStartup() 分配指令寄存器状态的内存
| |--> dvmInstanceofStartup() 分配虚拟机使用的缓存
| |--> dvmClassStartup() 初始化虚拟机最基本用的JAVA库
| |--> dvmFindRequiredClassesAndMembers()类查找相关的初始化
| |--> dvmStringInternStartup() 初始化虚拟机解释器使用的字符串哈希表
| |--> dvmNativeStartup() 初始化本地方法库的表
| |--> dvmInternalNativeStartup() 初始化内部本地方法,建立哈希表,方便快速查找到
| |--> dvmJniStartup() 初始化JNI调用表,以便快速找到本地方法调用的入口
| |--> dvmProfilingStartup()
| |--> dvmCreateInlineSubsTable()创建一个方法表代替inline方法表
| |--> dvmValidateBoxClasses() 始化JAVA基本类型库
| |--> dvmPrepMainForJni(pEnv) 准备主线程里的解释栈可以调用JNI的方法
| |--> dvmInitClass(gDvm.classJavaLangClass)初始化java.lang.Class
| |--> registerSystemNatives(pEnv)注册JAVA库里的JNI方法
| |--> dvmCreateStockExceptions()分配异常出错的内存
| |--> dvmPrepMainThread()解释器主线程的初始化
| |--> dvmDebuggerStartup()调试器初始化
| |--> dvmGcStartupClasses()
| |--> dvmInitAfterZygote() 此函数执行完虚拟机进程创建就完成了.
| |--> dvmGcStartupAfterZygote() 进行一次GC
| |--> dvmSignalCatcherStartup() 启动一个Linux信号收集线程,主要是用来捕捉SIGQUIT信号,以便可以在进程退出前将各个线程的堆栈DUMP出来
| |--> dvmStdioConverterStartup() 启动一个标准输出重定向线程,该线程负责将当前进程的标准输出(stdout和stderr)重定向到日志输出系统中去
| |--> dvmInitJDWP() 启动一个JDWP线程,以便我们可以用DDMS工具来调试进程中的Dalvik虚拟机
| |--> dvmCompilerStartup() 启动JIT,前提是当前使用的Dalvik虚拟机在编译时支持JIT,并且该Dalvik虚拟机在启动时指定了-Xint:jit选项
| |--> dvmCreateInternalThread(&gDvmJit.compilerHandle, "Compiler",compilerThreadStart, NULL);
| |--> *compilerThreadStart(void *arg) 启动线程初始化dalvik的编译器,在虚拟机支持JIT的前提下.
| |--> compilerThreadStartup(void)在虚拟机运行过程中一直生存的线程,while循环判断是否有代码需要编译,如果有,则调用dvmCompilerDoWork()对其进行编译
|--> startReg(env) //注册android native函数
|--> jmethodID startMeth = env->GetStaticMethodID(startClass, "main","([Ljava/lang/String;)V");
|--> env->CallStaticVoidMethod(startClass, startMeth, strArray); step1: JNIEnv.CallStaticVoidMethod setp2: JNINativeInterface.CallStaticVoidMethodV
|--> functions->CallStaticVoidMethodV(this, clazz, methodID, args);
|--> dvmInterpret(Thread* , const Method*, JValue* ) (Main interpreter loop entry point.将上一个激活状态保存到当前解释器,
初始化工作状态(比如,执行的method赋值),选择解释器运行模式)
if |--> dvmMterpStd :此函数为指针函数函数名,为解释器汇编实现的入口
else|--> dvmInterpretPortable :此函数为可移植C的解释器实现入口
# typedef void (*Interpreter)(Thread*);
# Interpreter stdInterp;
# if (gDvm.executionMode == kExecutionModeInterpFast)
# stdInterp = dvmMterpStd;
# #if defined(WITH_JIT)
# else if (gDvm.executionMode == kExecutionModeJit)
# stdInterp = dvmMterpStd;
# #endif
# else
# stdInterp = dvmInterpretPortable;
# // Call the interpreter
# (*stdInterp)(self);
分支到dvmInterpretPortable,比较容易看懂:
dvmInterpretPortable(Thread* self) @vm/mterp/out/InterpC-portable.cpp
void dvmInterpretPortable(Thread* self)
{
#if defined(EASY_GDB)
StackSaveArea* debugSaveArea = SAVEAREA_FROM_FP(self->interpSave.curFrame);
#endif
DvmDex* methodClassDex; // curMethod->clazz->pDvmDex
JValue retval;
/* core state */
const Method* curMethod; // method we're interpreting
const u2* pc; // program counter
u4* fp; // frame pointer
u2 inst; // current instruction
/* instruction decoding */
u4 ref; // 16 or 32-bit quantity fetched directly
u2 vsrc1, vsrc2, vdst; // usually used for register indexes
/* method call setup */
const Method* methodToCall;
bool methodCallRange;
bool jumboFormat;
/* static computed goto table */
DEFINE_GOTO_TABLE(handlerTable);
/* copy state in */
curMethod = self->interpSave.method;
pc = self->interpSave.pc;
fp = self->interpSave.curFrame;
retval = self->interpSave.retval; /* only need for kInterpEntryReturn? */
methodClassDex = curMethod->clazz->pDvmDex;
LOGVV("threadid=%d: %s.%s pc=%#x fp=%p",
self->threadId, curMethod->clazz->descriptor, curMethod->name,
pc - curMethod->insns, fp);
/*
* Handle any ongoing profiling and prep for debugging.
*/
if (self->interpBreak.ctl.subMode != 0) {
TRACE_METHOD_ENTER(self, curMethod);
self->debugIsMethodEntry = true; // Always true on startup
}
/*
* DEBUG: scramble this to ensure we're not relying on it.
*/
methodToCall = (const Method*) -1;
#if 0
if (self->debugIsMethodEntry) {
ILOGD("|-- Now interpreting %s.%s", curMethod->clazz->descriptor,
curMethod->name);
DUMP_REGS(curMethod, self->interpSave.curFrame, false);
}
#endif
FINISH(0); /* fetch and execute first instruction */
/*--- start of opcodes ---*/
/* File: c/OP_NOP.cpp */
HANDLE_OPCODE(OP_NOP)
FINISH(1);
OP_END
/* File: c/OP_MOVE.cpp */
HANDLE_OPCODE(OP_MOVE /*vA, vB*/)
vdst = INST_A(inst);
vsrc1 = INST_B(inst);
ILOGV("|move%s v%d,v%d %s(v%d=0x%08x)",
(INST_INST(inst) == OP_MOVE) ? "" : "-object", vdst, vsrc1,
kSpacing, vdst, GET_REGISTER(vsrc1));
SET_REGISTER(vdst, GET_REGISTER(vsrc1));
FINISH(1);
OP_END
首先解释器先加载dex文件,从中取出函数,函数就如x86的函数地址一样,虚拟机的opcode如汇编指令。opcode比汇编功能多一些,高级一些,所以个别opcode不想汇编那么简洁。须要调用函数来实现。
如函数内调转另一个函数,就需要使用函数来实现,需要传参数。
在看看汇编:dvmMterpStd:
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);
}
//LOGI("self is %p, pc=%p, fp=%p", self, self->interpSave.pc,
// self->interpSave.curFrame);
//LOGI("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
LOGD("|-- Leaving interpreter loop");
#endif
}
@InterpAsm-armv5te.S
/* File: armv5te/OP_MOVE.S */
/* for move, move-object, long-to-int */
/* op vA, vB */
mov r1, rINST, lsr #12 @ r1<- B from 15:12
mov r0, rINST, lsr #8 @ r0<- A from 11:8
FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
GET_VREG(r2, r1) @ r2<- fp[B]
and r0, r0, #15
GET_INST_OPCODE(ip) @ ip<- opcode from rINST
SET_VREG(r2, r0) @ fp[A]<- r2
/system/bin/app_process
|-->main(): @frameworks/base/cmds/app_process/app_main.cpp
虚拟机启动入口函数
if (strcmp(arg, "--zygote") == 0) zygote = true;
if (strcmp(arg, "--start-system-server") == 0) startSystemServer = true;
if (zygote) { runtime.start("com.android.internal.os.ZygoteInit",startSystemServer ? "start-system-server" : "");
|--> AndroidRuntime::start(const char* className, const char* options) 配置环境(ANDROID_ROOT)目录变量等 @frameworks/base/core/jni/AndroidRuntime.cpp
|--> AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv)
| |--> JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) @dalvik/vm/Jni.cpp
| |--> dvmStartup(int argc, const char* const argv[],bool ignoreUnrecognized, JNIEnv* pEnv) @dalvik/vm/Init.cpp
| |-->初始化组建
| |--> dvmCheckAsmConstants() 明确mterp解释器要用到的一些变量正确
| |--> dvmAllocTrackerStartup() 函数初始化跟踪显示系统,跟踪系统主要用生成调试系统的数据包
| |--> dvmGcStartup() 初始化垃圾回收器//初始化heap
| |--> dvmThreadStartup() 初始化线程列表和主线程环境参数
| |--> dvmInlineNativeStartup() 分配内部操作方法的表格内存
| |--> dvmRegisterMapStartup() 分配指令寄存器状态的内存
| |--> dvmInstanceofStartup() 分配虚拟机使用的缓存
| |--> dvmClassStartup() 初始化虚拟机最基本用的JAVA库
| |--> dvmFindRequiredClassesAndMembers()类查找相关的初始化
| |--> dvmStringInternStartup() 初始化虚拟机解释器使用的字符串哈希表
| |--> dvmNativeStartup() 初始化本地方法库的表
| |--> dvmInternalNativeStartup() 初始化内部本地方法,建立哈希表,方便快速查找到
| |--> dvmJniStartup() 初始化JNI调用表,以便快速找到本地方法调用的入口
| |--> dvmProfilingStartup()
| |--> dvmCreateInlineSubsTable()创建一个方法表代替inline方法表
| |--> dvmValidateBoxClasses() 始化JAVA基本类型库
| |--> dvmPrepMainForJni(pEnv) 准备主线程里的解释栈可以调用JNI的方法
| |--> dvmInitClass(gDvm.classJavaLangClass)初始化java.lang.Class
| |--> registerSystemNatives(pEnv)注册JAVA库里的JNI方法
| |--> dvmCreateStockExceptions()分配异常出错的内存
| |--> dvmPrepMainThread()解释器主线程的初始化
| |--> dvmDebuggerStartup()调试器初始化
| |--> dvmGcStartupClasses()
| |--> dvmInitAfterZygote() 此函数执行完虚拟机进程创建就完成了.
| |--> dvmGcStartupAfterZygote() 进行一次GC
| |--> dvmSignalCatcherStartup() 启动一个Linux信号收集线程,主要是用来捕捉SIGQUIT信号,以便可以在进程退出前将各个线程的堆栈DUMP出来
| |--> dvmStdioConverterStartup() 启动一个标准输出重定向线程,该线程负责将当前进程的标准输出(stdout和stderr)重定向到日志输出系统中去
| |--> dvmInitJDWP() 启动一个JDWP线程,以便我们可以用DDMS工具来调试进程中的Dalvik虚拟机
| |--> dvmCompilerStartup() 启动JIT,前提是当前使用的Dalvik虚拟机在编译时支持JIT,并且该Dalvik虚拟机在启动时指定了-Xint:jit选项
| |--> dvmCreateInternalThread(&gDvmJit.compilerHandle, "Compiler",compilerThreadStart, NULL);
| |--> *compilerThreadStart(void *arg) 启动线程初始化dalvik的编译器,在虚拟机支持JIT的前提下.
| |--> compilerThreadStartup(void)在虚拟机运行过程中一直生存的线程,while循环判断是否有代码需要编译,如果有,则调用dvmCompilerDoWork()对其进行编译
|--> startReg(env) //注册android native函数
|--> jmethodID startMeth = env->GetStaticMethodID(startClass, "main","([Ljava/lang/String;)V");
|--> env->CallStaticVoidMethod(startClass, startMeth, strArray); step1: JNIEnv.CallStaticVoidMethod setp2: JNINativeInterface.CallStaticVoidMethodV
|--> functions->CallStaticVoidMethodV(this, clazz, methodID, args);
|--> dvmInterpret(Thread* , const Method*, JValue* ) (Main interpreter loop entry point.将上一个激活状态保存到当前解释器,
初始化工作状态(比如,执行的method赋值),选择解释器运行模式)
if |--> dvmMterpStd :此函数为指针函数函数名,为解释器汇编实现的入口
else|--> dvmInterpretPortable :此函数为可移植C的解释器实现入口
# typedef void (*Interpreter)(Thread*);
# Interpreter stdInterp;
# if (gDvm.executionMode == kExecutionModeInterpFast)
# stdInterp = dvmMterpStd;
# #if defined(WITH_JIT)
# else if (gDvm.executionMode == kExecutionModeJit)
# stdInterp = dvmMterpStd;
# #endif
# else
# stdInterp = dvmInterpretPortable;
# // Call the interpreter
# (*stdInterp)(self);
分支到dvmInterpretPortable,比较容易看懂:
dvmInterpretPortable(Thread* self) @vm/mterp/out/InterpC-portable.cpp
void dvmInterpretPortable(Thread* self)
{
#if defined(EASY_GDB)
StackSaveArea* debugSaveArea = SAVEAREA_FROM_FP(self->interpSave.curFrame);
#endif
DvmDex* methodClassDex; // curMethod->clazz->pDvmDex
JValue retval;
/* core state */
const Method* curMethod; // method we're interpreting
const u2* pc; // program counter
u4* fp; // frame pointer
u2 inst; // current instruction
/* instruction decoding */
u4 ref; // 16 or 32-bit quantity fetched directly
u2 vsrc1, vsrc2, vdst; // usually used for register indexes
/* method call setup */
const Method* methodToCall;
bool methodCallRange;
bool jumboFormat;
/* static computed goto table */
DEFINE_GOTO_TABLE(handlerTable);
/* copy state in */
curMethod = self->interpSave.method;
pc = self->interpSave.pc;
fp = self->interpSave.curFrame;
retval = self->interpSave.retval; /* only need for kInterpEntryReturn? */
methodClassDex = curMethod->clazz->pDvmDex;
LOGVV("threadid=%d: %s.%s pc=%#x fp=%p",
self->threadId, curMethod->clazz->descriptor, curMethod->name,
pc - curMethod->insns, fp);
/*
* Handle any ongoing profiling and prep for debugging.
*/
if (self->interpBreak.ctl.subMode != 0) {
TRACE_METHOD_ENTER(self, curMethod);
self->debugIsMethodEntry = true; // Always true on startup
}
/*
* DEBUG: scramble this to ensure we're not relying on it.
*/
methodToCall = (const Method*) -1;
#if 0
if (self->debugIsMethodEntry) {
ILOGD("|-- Now interpreting %s.%s", curMethod->clazz->descriptor,
curMethod->name);
DUMP_REGS(curMethod, self->interpSave.curFrame, false);
}
#endif
FINISH(0); /* fetch and execute first instruction */
/*--- start of opcodes ---*/
/* File: c/OP_NOP.cpp */
HANDLE_OPCODE(OP_NOP)
FINISH(1);
OP_END
/* File: c/OP_MOVE.cpp */
HANDLE_OPCODE(OP_MOVE /*vA, vB*/)
vdst = INST_A(inst);
vsrc1 = INST_B(inst);
ILOGV("|move%s v%d,v%d %s(v%d=0x%08x)",
(INST_INST(inst) == OP_MOVE) ? "" : "-object", vdst, vsrc1,
kSpacing, vdst, GET_REGISTER(vsrc1));
SET_REGISTER(vdst, GET_REGISTER(vsrc1));
FINISH(1);
OP_END
首先解释器先加载dex文件,从中取出函数,函数就如x86的函数地址一样,虚拟机的opcode如汇编指令。opcode比汇编功能多一些,高级一些,所以个别opcode不想汇编那么简洁。须要调用函数来实现。
如函数内调转另一个函数,就需要使用函数来实现,需要传参数。
在看看汇编:dvmMterpStd:
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);
}
//LOGI("self is %p, pc=%p, fp=%p", self, self->interpSave.pc,
// self->interpSave.curFrame);
//LOGI("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
LOGD("|-- Leaving interpreter loop");
#endif
}
@InterpAsm-armv5te.S
OP如何连接执行?
/* File: armv5te/OP_MOVE.S */
/* for move, move-object, long-to-int */
/* op vA, vB */
mov r1, rINST, lsr #12 @ r1<- B from 15:12
mov r0, rINST, lsr #8 @ r0<- A from 11:8
FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
GET_VREG(r2, r1) @ r2<- fp[B]
and r0, r0, #15
GET_INST_OPCODE(ip) @ ip<- opcode from rINST
SET_VREG(r2, r0) @ fp[A]<- r2
GOTO_OPCODE(ip) @ execute next instruction
0 0
- android虚拟机详解
- android虚拟机详解(5%原创)
- Android内存优化(1)-Android虚拟机Dalvik 概念详解
- 【Android应用开发】-(12)图文详解Dalvik虚拟机
- Android热修复与插件化(二)虚拟机详解
- android虚拟机
- android 虚拟机
- Android虚拟机
- Android虚拟机
- android虚拟机
- Android虚拟机
- Android 虚拟机
- java虚拟机参数详解
- java虚拟机参数详解
- java虚拟机参数详解
- java虚拟机参数详解
- java虚拟机参数详解
- Java虚拟机参数详解
- MongoDB副本集创建和管理
- C#快递单号查询源码
- 【javascript】关于正则的面试题一
- Spring restTemplate 超时配置
- 16周,指针处理字符串,删除句子开始的空格
- android虚拟机详解
- 上海色彩设计招聘面试者色彩搭配技术
- C语言指针转换为intptr_t类型
- 心灵
- 总会有一个人知你冷暖,懂你悲欢
- Tengine/Nginx 启动出错 error while loading shared libraries: libpcre.so.1
- 第十六周项目二 去除第一个单词前空格
- shell脚本变量比较
- NSUserDefaults 置空某值