Android6.0中oat文件的加载过程

本文详细分析了Android 6.0中oat文件的生成过程及加载流程,介绍了如何从APK安装时的dex2oat工具生成OAT文件,以及在ART运行时如何通过OatFile类的Open方法加载OAT文件。文章探讨了OAT文件的结构,包括OAT头、DEX文件信息、OAT类和OAT方法,强调了在不同场景下加载OAT文件的方式,如通过dlopen或手动解析ELF文件格式。
摘要由CSDN通过智能技术生成

主要参考:http://blog.csdn.net/luoshengyang/article/details/39307813 罗升阳老师的Android运行时ART加载OAT文件的过程分析 。将代码换成了Android6.0部分,并且对其中某些内容进行了修改,比如oat文件的内容等。

在分析OAT文件的加载过程之前,我们需要简单介绍一下OAT是如何产生的。如前面Android ART运行时无缝替换Dalvik虚拟机的过程分析一文所示,APK在安装的过程中,会通过dex2oat工具生成一个OAT文件:

 747 static void run_dex2oat(int zip_fd, int oat_fd, const char* input_file_name,
 748     const char* output_file_name, int swap_fd, const char *pkgname, const char *instruction_set,
 749     bool vm_safe_mode, bool debuggable, bool post_bootcomplete)
 750 {
     ...
 813     static const char* DEX2OAT_BIN = "/system/bin/dex2oat";
 814 
 815     static const char* RUNTIME_ARG = "--runtime-arg";
    ...
 834     sprintf(zip_fd_arg, "--zip-fd=%d", zip_fd);
 835     sprintf(zip_location_arg, "--zip-location=%s", input_file_name);
 836     sprintf(oat_fd_arg, "--oat-fd=%d", oat_fd);
 837     sprintf(oat_location_arg, "--oat-location=%s", output_file_name);
 838     sprintf(instruction_set_arg, "--instruction-set=%s", instruction_set);
 839     sprintf(instruction_set_variant_arg, "--instruction-set-variant=%s", dex2oat_isa_variant);
 840     sprintf(instruction_set_features_arg, "--instruction-set-features=%s", dex2oat_isa_features);
    ...
 958 
 959     execv(DEX2OAT_BIN, (char * const *)argv);
 960     ALOGE("execv(%s) failed: %s\n", DEX2OAT_BIN, strerror(errno));
 961 }

这个函数定义在文件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文件呢?
从前面Android ART运行时无缝替换Dalvik虚拟机的过程分析一文可以知道,当我们选择了ART运行时时,Zygote进程在启动的过程中,会调用libart.so里面的函数JNI_CreateJavaVM来创建一个ART虚拟机。函数JNI_CreateJavaVM的实现如下所示:

789 // JNI Invocation interface.
790 
791 extern "C" jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) {
792   ATRACE_BEGIN(__FUNCTION__);
793   const JavaVMInitArgs* args = static_cast<JavaVMInitArgs*>(vm_args);
794   if (IsBadJniVersion(args->version)) {
795     LOG(ERROR) << "Bad JNI version passed to CreateJavaVM: " << args->version;
796     ATRACE_END();
797     return JNI_EVERSION;
798   }
799   RuntimeOptions options;
800   for (int i = 0; i < args->nOptions; ++i) {
801     JavaVMOption* option = &args->options[i];
802     options.push_back(std::make_pair(std::string(option->optionString), option->extraInfo));
803   }
804   bool ignore_unrecognized = args->ignoreUnrecognized;
805   if (!Runtime::Create(options, ignore_unrecognized)) {
806     ATRACE_END();
807     return JNI_ERR;
808   }
809   Runtime* runtime = Runtime::Current();
810   bool started = runtime->Start();
811   if (!started) {
812     delete Thread::Current()->GetJniEnv();
813     delete runtime->GetJavaVM();
814     LOG(WARNING) << "CreateJavaVM failed";
815     ATRACE_END();
816     return JNI_ERR;
817   }
818   *p_env = Thread::Current()->GetJniEnv();
819   *p_vm = runtime->GetJavaVM();
820   ATRACE_END();
821   return JNI_OK;
822 }

这个函数定义在文件art/runtime/java_vm_ext.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,它的实现如下所示:

 410 bool Runtime::Create(const RuntimeOptions& options, bool ignore_unrecognized) {
 411   // TODO: acquire a static mutex on Runtime to avoid racing.
 412   if (Runtime::instance_ != nullptr) {
 413     return false;
 414   }
 415   InitLogging(nullptr);  // Calls Locks::Init() as a side effect.
 416   instance_ = new Runtime;
 417   if (!instance_->Init(options, ignore_unrecognized)) {
 418     // TODO: Currently deleting the instance will abort the runtime on destruction. Now This will
 419     // leak memory, instead. Fix the destructor. b/19100793.
 420     // delete instance_;
 421     instance_ = nullptr;
 422     return false;
 423   }
 424   return true;
 425 }

这个函数定义在文件art/runtime/runtime.cc中。
instance_是Runtime类的静态成员变量,它指向进程中的一个Runtime单例。这个Runtime单例描述的就是当前进程的ART虚拟机实例。
函数首先判断当前进程是否已经创建有一个ART虚拟机实例了。如果有的话,函数就立即返回。否则的话,就创建一个ART虚拟机实例,并且保存在Runtime类的静态成员变量instance_中,最后调用Runtime类的成员函数Init对该新创建的ART虚拟机进行初始化。
Runtime类的成员函数Init的实现如下所示:

 782 bool Runtime::Init(const RuntimeOptions& raw_options, bool ignore_unrecognized) {
    ...
 788   using Opt = RuntimeArgumentMap;
 789   RuntimeArgumentMap runtime_options;
 790   std::unique_ptr<ParsedOptions> parsed_options(
 791       ParsedOptions::Create(raw_options, ignore_unrecognized, &runtime_options));
     ...
 849   XGcOption xgc_option = runtime_options.GetOrDefault(Opt::GcOption);
 850   ATRACE_BEGIN("CreateHeap");
 851   heap_ = new gc::Heap(runtime_options.GetOrDefault(Opt::MemoryInitialSize),
 852                        runtime_options.GetOrDefault(Opt::HeapGrowthLimit),
 853                        runtime_options.GetOrDefault(Opt::HeapMinFree),
 854                        runtime_options.GetOrDefault(Opt::HeapMaxFree),
 855                        runtime_options.GetOrDefault(Opt::HeapTargetUtilization),
 856                        runtime_options.GetOrDefault(Opt::ForegroundHeapGrowthMultiplier),
 857                        runtime_options.GetOrDefault(Opt::MemoryMaximumSize),
 858                        runtime_options.GetOrDefault(Opt::NonMovingSpaceCapacity),
 859                        runtime_options.GetOrDefault(Opt::Image),
 860                        runtime_options.GetOrDefault(Opt::ImageInstructionSet),
 861                        xgc_option.collector_type_,
 862                        runtime_options.GetOrDefault(Opt::BackgroundGc),
 863                        runtime_options.GetOrDefault(Opt::LargeObjectSpace),
 864                        runtime_options.GetOrDefault(Opt::LargeObjectThreshold),
 865                        runtime_options.GetOrDefault(Opt::ParallelGCThreads),
 866                        runtime_options.GetOrDefault(Opt::ConcGCThreads),
 867                        runtime_options.Exists(Opt::LowMemoryMode),
 868                        runtime_options.GetOrDefault(Opt::LongPauseLogThreshold),
 869                        runtime_options.GetOrDefault(Opt::LongGCLogThreshold),
 870                        runtime_options.Exists(Opt::IgnoreMaxFootprint),
 871                        runtime_options.GetOrDefault(Opt::UseTLAB),
 872                        xgc_option.verify_pre_gc_heap_,
 873                        xgc_option.verify_pre_sweeping_heap_,
 874                        xgc_option.verify_post_gc_heap_,
 875                        xgc_option.verify_pre_gc_rosalloc_,
 876                        xgc_option.verify_pre_sweeping_rosalloc_,
 877                        xgc_option.verify_post_gc_rosalloc_,
 878                        xgc_option.gcstress_,
 879                        runtime_options.GetOrDefault(Opt::EnableHSpaceCompactForOOM),
 880                        runtime_options.GetOrDefault(Opt::HSpaceCompactForOOMMinIntervalsMs));
    ...
 967   java_vm_ = new JavaVMExt(this, runtime_options);
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值