Dalvik虚拟机总结

本文详细介绍了Dalvik虚拟机的启动过程,从Zygote进程创建Dalvik虚拟机实例,加载Java核心类和JNI方法,到Zygote等待SystemServer请求创建应用进程。在SystemServer进程中,通过JNI注册和执行C/C++代码。接着,文章阐述了应用程序进程如何通过JNI注册方法并直接执行本地代码,以及线程创建和Dalvik虚拟机环境的配置,确保Java代码的解释执行。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

    一、Dalvik虚拟机启动

    在启动Zygote进程时,会启动Dalvik虚拟机,完成下面几件事:

    1. 创建了一个Dalvik虚拟机实例; 

    2. 加载了Java核心类及注册其JNI方法; 

    3. 为主线程的设置了一个JNI环境; 

    4. 注册了Android核心类的JNI方法。

void AndroidRuntime::start(const char* className, const bool startSystemServer)
{
    ......

    /* start the virtual machine */
    if (startVm(&mJavaVM, &env) != 0)
        goto bail;

    /*
     * Register android functions.
     */
    if (startReg(env) < 0) {
        LOGE("Unable to register all android natives\n");
        goto bail;
    }

    ......

    /*
     * Start VM.  This thread becomes the main thread of the VM, and will
     * not return until the VM exits.
     */
    jclass startClass;
    jmethodID startMeth;

    slashClassName = strdup(className);
    for (cp = slashClassName; *cp != '\0'; cp++)
        if (*cp == '.')
            *cp = '/';

    startClass = env->FindClass(slashClassName);
    if (startClass == NULL) {
        LOGE("JavaVM unable to locate class '%s'\n", slashClassName);
        /* keep going */
    } else {
        startMeth = env->GetStaticMethodID(startClass, "main",
            "([Ljava/lang/String;)V");
        if (startMeth == NULL) {
            LOGE("JavaVM unable to find main() in '%s'\n", className);
            /* keep going */
        } else {
            env->CallStaticVoidMethod(startClass, startMeth, strArray);
            ......
        }
    }

    LOGD("Shutting down VM\n");
    if (mJavaVM->DetachCurrentThread() != JNI_OK)
        LOGW("Warning: unable to detach main thread\n");
    if (mJavaVM->DestroyJavaVM() != 0)
        LOGW("Warning: VM did not shut down cleanly\n");

    ......
}


    二、第一次解释执行java程序,env->CallStaticVoidMethod(startClass, startMeth, strArray)最终会解释执行com.android.internal.os.ZygoteInit类的静态成员函数main

    参考Dalvik虚拟机的运行过程分析,随着方法调用的不同,不断执行不同的GOTO_TARGET(invokeMethod, bool methodCallRange, const Method* _methodToCall, u2 count, u2 regs)或者GOTO_TARGET(returnFromMethod)等等,去解释执行java程序。


    三、Zygote进程等待来在SystemServer的请求,来创建应用程序进程

    static native int selectReadable(FileDescriptor[] fds) throws IOException;

    此时dalvik虚拟机不是解释执行java程序,而是调用C/C++程序的入口地址,直接执行C/C++代码。由于在第一步中已经注册Android核心JNI,所以可以直接调用,请看考下面的第六点。


    四、Zygote进程创建SystemServer进程

pid = Zygote.forkSystemServer(
                    parsedArgs.uid, parsedArgs.gid,
                    parsedArgs.gids, debugFlags, null,
                    parsedArgs.permittedCapabilities,
                    parsedArgs.effectiveCapabilities);
 if (pid == 0) {
            handleSystemServerProcess(parsedArgs);//执行了com.android.server.SystemServer中main方法
        }
   本质上使用fork来创建一个新的进程,Zygote进程在启动是创建的Dalvik虚拟机实例和主线程的环境,使用COW的方式共享。其他两点由于是只读,共享即可。

   返回到pid==0,此时已经是SystemServer进程的Davlik虚拟机主线程的环境来解释执行handleSystemServerProcess。


    五、SystemServer进程调用Process.start,通过Socket请求Zygote进程来创建应用程序进程

pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid,
                    parsedArgs.gids, parsedArgs.debugFlags, rlimits);
if (pid == 0) {
            // in child
            handleChildProc(parsedArgs, descriptors, newStderr);//android.app.ActivityThread中的main函数
            // should never happen
            return true;
        }
    和第四点的描述一样。


    六、应用程序进程注册JNI,并执行JNI方法。

    注册过程请参考Dalvik虚拟机JNI方法的注册过程分析,会调用JNI_OnLoad获取主线程的Dalvik虚拟机环境JNIENV,并调用了dvmSetNativeFunc设置了navtiveFunc。

    当执行到JNI方法时,会调用*method->nativeFunc,不是解释执行,是直接在机器上执行。    

void dvmCallMethodV(Thread* self, const Method* method, Object* obj,
    bool fromJni, JValue* pResult, va_list args)
{
    ......

    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)(self->curFrame, pResult, method, self);
        TRACE_METHOD_EXIT(self, method);
    } else {
        dvmInterpret(self, method, pResult);
    }

    ......
}
    当如果想在JNI方法中调用Java方法,必须得有当前线程的Davlik虚拟机环境JNIENV,例如:

(*jniEnv)->CallVoidMethod(jniEnv, mTestProvider, sayHello,jstrMSG);
    和第二点一样,必须由Davlik虚拟机去解释执行Java方法。


    七、应用程序进程,Java中开启一个线程,Thread.start

    参考Dalvik虚拟机进程和线程的创建过程分析,使用clone创建了一个新的线程,和进程(主线程)共享进程空间,由于此线程没有Dalvik虚拟机环境JNIENV,所以要为该进程设置虚拟机环境。有了环境后就可以在解释执行Java代码了,如下:

dvmCallMethod(self, run, self->threadObj, &unused);  

    八、应用程序进程,C/C++中开启一个线程
    1、.只执行C/C++代码的Native线程的创建过程:

    不会创建该线程的Dalvik虚拟机环境JNIENV。

    2、能同时执行C/C++代码和Java代码的Native线程的创建过程

    需要创建该线程的Dalvik虚拟机环境JNIENV,就可以解释执行Java代码了。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值