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

OP如何连接执行?


.L_OP_MOVE: /* 0x01 */
/* 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


抓取第一個Dalvik OpCode指令並執行,同時在每個指令執行結束後,再透過FETCH_ADVANCE_INST與GET_INST_OPCODE抓取下一個Dalvik OpCode指令,最後再透過GOTO_OPCODE執行該指令集的實作,如此持續運作下去,藉此得到比用C版本Busy Loop更高的執行效率.









0 0