Android运行时ART加载类和方法的过程分析

805 查看

在前面Android运行时ART加载OAT文件的过程分析这篇文章的最后,我们简单总结了ART运行时查找类方法的本地机器指令的过程,如图1所示:

图1 ART运行时查找类方法的本地机器指令的过程

       为了方便描述,我们将DEX文件中描述的类和方法称为DEX类(Dex Class)和DEX方法(Dex Method),而将在OAT文件中描述的类和方法称为OAT类(Oat Class)和OAT方法(Oat Method)。接下来我们还会看到,ART运行时在内部又会使用另外两个不同的术语来描述类和方法,其中将类描述为Class,而将类方法描述为ArtMethod。

在图1中,为了找到一个类方法的本地机器指令,我们需要执行以下的操作:

1. 在DEX文件中找到目标DEX类的编号,并且以这个编号为索引,在OAT文件中找到对应的OAT类。

2. 在DEX文件中找到目标DEX方法的编号,并且以这个编号为索引,在上一步找到的OAT类中找到对应的OAT方法。

3. 使用上一步找到的OAT方法的成员变量begin_和code_offset_,计算出该方法对应的本地机器指令。

通过前面Android运行时ART简要介绍和学习计划一文的学习,我们可以知道,ART运行时的入口是com.android.internal.os.ZygoteInit类的静态成员函数main,如下所示:

这个函数定义在文件frameworks/base/core/jni/AndroidRuntime.cpp中。

在AndroidRuntime类的成员函数start中,首先是通过调用函数startVm创建了一个Java虚拟机mJavaVM及其JNI接口env。这个Java虚拟机实际上就是ART运行时。在接下来的描述中,我们将不区分ART虚拟机和ART运行时,并且认为它们表达的是同一个概念。获得了ART虚拟机的JNI接口之后,就可以通过它提供的函数FindClass和GetStaticMethodID来加载com.android.internal.os.ZygoteInit类及其静态成员函数main。于是,最后就可以再通过JNI接口提供的函数CallStaticVoidMethod来调用com.android.internal.os.ZygoteInit类的静态成员函数main,以及进行到ART虚拟机里面去运行。

接下来,我们就通过分析JNI接口FindClass和GetStaticMethodID的实现,以便理解ART运行时是如何查找到指定的类和方法的。在接下来的一篇文章中,我们再分析ART运行时是如何通过JNI接口CallStaticVoidMethod来执行指定类方法的本地机器指令的。

在分析JNI接口FindClass和GetStaticMethodID的实现之前,我们先要讲清楚JNI接口是如何创建的。从前面Android运行时ART加载OAT文件的过程分析一文可以知道,与ART虚拟机主线程关联的JNI接口是在函数JNI_CreateJavaVM中创建的,如下所示:

这个函数定义在文件art/runtime/jni_internal.cc中。

调用Thread类的静态成员函数Current获得的是用来描述当前线程(即ART虚拟机的主线程)的一个Thread对象,再通过调用这个Thread对象的成员函数GetJniEnv就获得一个JNI接口,并且保存在输出参数p_env中。

Thread类的成员函数GetJniEnv的实现如下所示: