主要参考: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);