Android运行时ART加载OAT文件的过程分析资料Word文档格式.docx

上传人:b****5 文档编号:21407682 上传时间:2023-01-30 格式:DOCX 页数:31 大小:248.35KB
下载 相关 举报
Android运行时ART加载OAT文件的过程分析资料Word文档格式.docx_第1页
第1页 / 共31页
Android运行时ART加载OAT文件的过程分析资料Word文档格式.docx_第2页
第2页 / 共31页
Android运行时ART加载OAT文件的过程分析资料Word文档格式.docx_第3页
第3页 / 共31页
Android运行时ART加载OAT文件的过程分析资料Word文档格式.docx_第4页
第4页 / 共31页
Android运行时ART加载OAT文件的过程分析资料Word文档格式.docx_第5页
第5页 / 共31页
点击查看更多>>
下载资源
资源描述

Android运行时ART加载OAT文件的过程分析资料Word文档格式.docx

《Android运行时ART加载OAT文件的过程分析资料Word文档格式.docx》由会员分享,可在线阅读,更多相关《Android运行时ART加载OAT文件的过程分析资料Word文档格式.docx(31页珍藏版)》请在冰豆网上搜索。

Android运行时ART加载OAT文件的过程分析资料Word文档格式.docx

--zip-fd="

)+MAX_INT_LEN];

charzip_location_arg[strlen("

--zip-location="

)+PKG_PATH_MAX];

charoat_fd_arg[strlen("

--oat-fd="

charoat_location_arg[strlen("

--oat-name="

sprintf(zip_fd_arg,"

--zip-fd=%d"

zip_fd);

sprintf(zip_location_arg,"

--zip-location=%s"

input_file_name);

sprintf(oat_fd_arg,"

--oat-fd=%d"

oat_fd);

sprintf(oat_location_arg,"

--oat-location=%s"

output_file_name);

ALOGV("

Running%sin=%sout=%s\n"

DEX2OAT_BIN,input_file_name,output_file_name);

execl(DEX2OAT_BIN,DEX2OAT_BIN,

zip_fd_arg,zip_location_arg,

oat_fd_arg,oat_location_arg,

(char*)NULL);

ALOGE("

execl(%s)failed:

%s\n"

DEX2OAT_BIN,strerror(errno));

}

这个函数定义在文件frameworks/native/cmds/installd/commands.c中。

其中,参数zip_fd和oat_fd都是打开文件描述符,指向的分别是正在安装的APK文件和要生成的OAT文件。

OAT文件的生成过程主要就是涉及到将包含在APK里面的classes.dex文件的DEX字节码翻译成本地机器指令。

这相当于是编写一个输入文件为DEX、输出文件为OAT的编译器。

这个编译器是基于LLVM编译框架开发的。

编译器的工作原理比较高大上,所幸的是它不会影响到我们接下来的分析,因此我们就略过DEX字节码翻译成本地机器指令的过程,假设它很愉快地完成了。

APK安装过程中生成的OAT文件的输入只有一个DEX文件,也就是来自于打包在要安装的APK文件里面的classes.dex文件。

实际上,一个OAT文件是可以由若干个DEX生成的。

这意味着在生成的OAT文件的oatdata段中,包含有多个DEX文件。

那么,在什么情况下,会生成包含多个DEX文件的OAT文件呢?

从前面一文可以知道,当我们选择了ART运行时时,Zygote进程在启动的过程中,会调用libart.so里面的函数JNI_CreateJavaVM来创建一个ART虚拟机。

函数JNI_CreateJavaVM的实现如下所示:

extern"

C"

jintJNI_CreateJavaVM(JavaVM**p_vm,JNIEnv**p_env,void*vm_args){

constJavaVMInitArgs*args=static_cast<

JavaVMInitArgs*>

(vm_args);

if(IsBadJniVersion(args->

version)){

LOG(ERROR)<

<

"

BadJNIversionpassedtoCreateJavaVM:

<

args->

version;

returnJNI_EVERSION;

}

Runtime:

:

Optionsoptions;

for(inti=0;

i<

nOptions;

++i){

JavaVMOption*option=&

args->

options[i];

options.push_back(std:

make_pair(std:

string(option->

optionString),option->

extraInfo));

boolignore_unrecognized=args->

ignoreUnrecognized;

if(!

Runtime:

Create(options,ignore_unrecognized)){

returnJNI_ERR;

Runtime*runtime=Runtime:

Current();

boolstarted=runtime->

Start();

started){

deleteThread:

Current()->

GetJniEnv();

deleteruntime->

GetJavaVM();

LOG(WARNING)<

CreateJavaVMfailed"

*p_env=Thread:

*p_vm=runtime->

returnJNI_OK;

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

参数vm_args用作ART虚拟机的启动参数,它被转换为一个JavaVMInitArgs对象后,再按照Key-Value的组织形式保存一个Options向量中,并且以该向量作为参数传递给Runtime类的静态成员函数Create。

Runtime类的静态成员函数Create负责在进程中创建一个ART虚拟机。

创建成功后,就调用Runtime类的另外一个静态成员函数Start启动该ART虚拟机。

注意,这个创建ART虚拟的动作只会在Zygote进程中执行,SystemServer系统进程以及Android应用程序进程的ART虚拟机都是直接从Zygote进程fork出来共享的。

这与Dalvik虚拟机的创建方式是完全一样的。

接下来我们就重点分析Runtime类的静态成员函数Create,它的实现如下所示:

boolRuntime:

Create(constOptions&

options,boolignore_unrecognized){

//TODO:

acquireastaticmutexonRuntimetoavoidracing.

if(Runtime:

instance_!

=NULL){

returnfalse;

InitLogging(NULL);

//CallsLocks:

Init()asasideeffect.

instance_=newRuntime;

instance_->

Init(options,ignore_unrecognized)){

deleteinstance_;

instance_=NULL;

returntrue;

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

instance_是Runtime类的静态成员变量,它指向进程中的一个Runtime单例。

这个Runtime单例描述的就是当前进程的ART虚拟机实例。

函数首先判断当前进程是否已经创建有一个ART虚拟机实例了。

如果有的话,函数就立即返回。

否则的话,就创建一个ART虚拟机实例,并且保存在Runtime类的静态成员变量instance_中,最后调用Runtime类的成员函数Init对该新创建的ART虚拟机进行初始化。

Runtime类的成员函数Init的实现如下所示:

Init(constOptions&

raw_options,boolignore_unrecognized){

......

UniquePtr<

ParsedOptions>

options(ParsedOptions:

Create(raw_options,ignore_unrecognized));

heap_=newgc:

Heap(options->

heap_initial_size_,

options->

heap_growth_limit_,

heap_min_free_,

heap_max_free_,

heap_target_utilization_,

heap_maximum_size_,

image_,

is_concurrent_gc_enabled_,

parallel_gc_threads_,

conc_gc_threads_,

low_memory_mode_,

long_pause_log_threshold_,

long_gc_log_threshold_,

ignore_max_footprint_);

java_vm_=newJavaVMExt(this,options.get());

Thread*self=Thread:

Attach("

main"

false,NULL,false);

if(GetHeap()->

GetContinuousSpaces()[0]->

IsImageSpace()){

class_linker_=ClassLinker:

CreateFromImage(intern_table_);

}else{

CreateFromCompiler(*options->

boot_class_path_,intern_table_);

Runtime类的成员函数Init首先调用ParsedOptions类的静态成员函数Create对ART虚拟机的启动参数raw_options进行解析。

解析后得到的参数保存在一个ParsedOptions对象中,接下来就根据这些参数一个ART虚拟机堆。

ART虚拟机堆使用一个Heap对象来描述。

创建好ART虚拟机堆后,Runtime类的成员函数Init接着又创建了一个JavaVMExt实例。

这个JavaVMExt实例最终是要返回给调用者的,使得调用者可以通过该JavaVMExt实例来和ART虚拟机交互。

再接下来,Runtime类的成员函数Init通过Thread类的成员函数Attach将当前线程作为ART虚拟机的主线程,使得当前线程可以调用ART虚拟机提供的JNI接口。

Runtime类的成员函数GetHeap返回的便是当前ART虚拟机的堆,也就是前面创建的ART虚拟机堆。

通过调用Heap类的成员函数GetContinuousSpaces可以获得堆里面的连续空间列表。

如果这个列表的第一个连续空间是一个Image空间,那么就调用ClassLinker类的静态成员函数CreateFromImage来创建一个ClassLinker对象。

否则的话,上述ClassLinker对象就要通过ClassLinker类的另外一个静态成员函数CreateFromCompiler来创建。

创建出来的ClassLinker对象是后面ART虚拟机加载加载Java类时要用到的。

后面我们分析ART虚拟机的垃圾收集机制时会看到,ART虚拟机的堆包含有三个连续空间和一个不连续空间。

三个连续空间分别用来分配不同的对象。

当第一个连续空间不是Image空间时,就表明当前进程不是Zygote进程,而是安装应用程序时启动的一个dex2oat进程。

安装应用程序时启动的dex2oat进程也会在内部创建一个ART虚拟机,不过这个ART虚拟机是用来将DEX字节码编译成本地机器指令的,而Zygote进程创建的ART虚拟机是用来运行应用程序的。

接下来我们主要分析ParsedOptions类的静态成员函数Create和ART虚拟机堆Heap的构造函数,以便可以了解ART虚拟机的启动参数解析过程和ART虚拟机的堆创建过程。

ParsedOptions类的静态成员函数Create的实现如下所示:

ParsedOptions*Runtime:

ParsedOptions:

parsed(newParsedOptions());

constchar*boot_class_path_string=getenv("

BOOTCLASSPATH"

);

if(boot_class_path_string!

parsed->

boot_class_path_string_=boot_class_path_string;

is_compiler_=false;

for(size_ti=0;

options.size();

conststd:

stringoption(options[i].first);

if(StartsWith(option,"

-Xbootclasspath:

"

)){

boot_class_path_string_=option.substr(strlen("

)).data();

}elseif(option=="

bootclasspath"

){

boot_class_path_

=reinterpret_cast<

conststd:

vector<

constDexFile*>

*>

(options[i].second);

}elseif(StartsWith(option,"

-Ximage:

image_=option.substr(strlen("

}elseif(......){

compiler"

is_compiler_=true;

parsed->

is_compiler_&

&

image_.empty()){

image_+=GetAndroidRoot();

image_+="

/framework/boot.art"

returnparsed.release();

ART虚拟机的启动参数比较多,这里我们只关注两个:

-Xbootclasspath、-Ximage和compiler。

参数-Xbootclasspath用来指定启动类路径。

如果没有指定启动类路径,那么默认的启动类路径就通过环境变量BOOTCLASSPATH来获得。

参数-Ximage用来指定ART虚拟机所使用的Image文件。

这个Image是用来启动ART虚拟机的。

参数compiler用来指定当前要创建的ART虚拟机是用来将DEX字节码编译成本地机器指令的。

如果没有指定Image文件,并且当前创建的ART虚拟机又不是用来编译DEX字节码的,那么就将该Image文件指定为设备上的/system/framework/boot.art文件。

我们知道,system分区的文件都是在制作ROM时打包进去的。

这样上述代码的逻辑就是说,如果没有指定Image文件,那么将system分区预先准备好的framework/boot.art文件作为Image文件来启动ART虚拟机。

不过,/system/framework/boot.art文件可能是不存在的。

在这种情况下,就需要生成一个新的Image文件。

这个Image文件就是一个包含了多个DEX文件的OAT文件。

接下来通过分析ART虚拟机堆的创建过程就会清楚地看到这一点。

Heap类的构造函数的实现如下所示:

Heap:

Heap(size_tinitial_size,size_tgrowth_limit,size_tmin_free,size_tmax_free,

doubletarget_utilization,size_tcapacity,conststd:

string&

original_image_file_name,

boolconcurrent_gc,size_tparallel_gc_threads,size_tconc_gc_threads,

boollow_memory_mode,size_tlong_pause_log_threshold,size_tlong_gc_log_threshold,

boolignore_max_footprint)

:

......{

std:

stringimage_file_name(original_image_file_name);

image_file_name.empty()){

space:

ImageSpace*image_space=space:

ImageSpace:

Create(image_file_name);

AddContinuousSpace(image_space);

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

ART虚拟机堆的详细创建过程我们在后面分析ART虚拟机的垃圾收集机制时再分析,这里只关注与Image文件相关的逻辑。

参数original_image_file_name描述的就是前面提到的Image文件的路径。

如果它的值不等于空的话,那么就以它为参数,调用ImageSpace类的静态成员函数Create创建一个Image空间,并且调用Heap类的成员函数AddContinuousSpace将该Image空间作为本进程的ART虚拟机堆的第一个连续空间。

接下来我们继续分析ImageSpace类的静态成员函数Create,它的实现如下所示:

ImageSpace*ImageSpace:

Create(conststd:

original_image_file_name){

if(OS:

FileExists(original_image_file_name.c_str())){

//Ifthe/systemfileexists,itshouldbeup-to-date,don'

ttrytogenerate

returnspace:

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 法律文书 > 起诉状

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1