当前位置: 首页 > news >正文

Android运行时ART加载OAT文件的过程

目录

一,概述

 1.1 OAT是如何产生的


一,概述

OAT文件是一种Android私有ELF文件格式,它不仅包含有从DEX文件翻译而来的本地机器指令,还包含有原来的DEX文件内容。这使得我们无需重新编译原有的APK就可以让它正常地在ART里面运行,也就是我们不需要改变原来的APK编程接口

为了更好了弄明白oat文件的格式,目前还需要看下elf 文件格式

oat文件格式

作为Android私有的一种ELF文件,OAT文件包含有两个特殊的段oatdata和oatexec,前者包含有用来生成本地机器指令的dex文件内容,后者包含有生成的本地机器指令,它们之间的关系通过储存在oatdata段前面的oat头部描述。此外,在OAT文件的dynamic段,导出了三个符号oatdata、oatexec和oatlastword,它们的值就是用来界定oatdata段和oatexec段的起止位置的。其中,[oatdata, oatexec - 1]描述的是oatdata段的起止位置,而[oatexec, oatlastword + 3]描述的是oatexec的起止位置。要完全理解OAT的文件格式,除了要理解本文即将要分析的OAT加载过程之外,还需要掌握接下来文章分析的类和方法查找过程。


 1.1 OAT是如何产生的

/Volumes/aosp/android-8.1.0_r52/frameworks/native/cmds/installd/dexopt.cpp

static void run_dex2oat(int zip_fd, int oat_fd, int input_vdex_fd, int output_vdex_fd, int image_fd,const char* input_file_name, const char* output_file_name, int swap_fd,const char* instruction_set, const char* compiler_filter,bool debuggable, bool post_bootcomplete, int profile_fd, const char* class_loader_context) {static const unsigned int MAX_INSTRUCTION_SET_LEN = 7;if (strlen(instruction_set) >= MAX_INSTRUCTION_SET_LEN) {ALOGE("Instruction set %s longer than max length of %d",instruction_set, MAX_INSTRUCTION_SET_LEN);return;}// Get the relative path to the input file.const char* relative_input_file_name = get_location_from_path(input_file_name);char dex2oat_Xms_flag[kPropertyValueMax];bool have_dex2oat_Xms_flag = get_property("dalvik.vm.dex2oat-Xms", dex2oat_Xms_flag, NULL) > 0;char dex2oat_Xmx_flag[kPropertyValueMax];bool have_dex2oat_Xmx_flag = get_property("dalvik.vm.dex2oat-Xmx", dex2oat_Xmx_flag, NULL) > 0;char dex2oat_threads_buf[kPropertyValueMax];bool have_dex2oat_threads_flag = get_property(post_bootcomplete? "dalvik.vm.dex2oat-threads": "dalvik.vm.boot-dex2oat-threads",dex2oat_threads_buf,NULL) > 0;char dex2oat_threads_arg[kPropertyValueMax + 2];if (have_dex2oat_threads_flag) {sprintf(dex2oat_threads_arg, "-j%s", dex2oat_threads_buf);}char dex2oat_isa_features_key[kPropertyKeyMax];sprintf(dex2oat_isa_features_key, "dalvik.vm.isa.%s.features", instruction_set);char dex2oat_isa_features[kPropertyValueMax];bool have_dex2oat_isa_features = get_property(dex2oat_isa_features_key,dex2oat_isa_features, NULL) > 0;char dex2oat_isa_variant_key[kPropertyKeyMax];sprintf(dex2oat_isa_variant_key, "dalvik.vm.isa.%s.variant", instruction_set);char dex2oat_isa_variant[kPropertyValueMax];bool have_dex2oat_isa_variant = get_property(dex2oat_isa_variant_key,dex2oat_isa_variant, NULL) > 0;const char *dex2oat_norelocation = "-Xnorelocate";bool have_dex2oat_relocation_skip_flag = false;char dex2oat_flags[kPropertyValueMax];int dex2oat_flags_count = get_property("dalvik.vm.dex2oat-flags",dex2oat_flags, NULL) <= 0 ? 0 : split_count(dex2oat_flags);ALOGV("dalvik.vm.dex2oat-flags=%s\n", dex2oat_flags);// If we are booting without the real /data, don't spend time compiling.char vold_decrypt[kPropertyValueMax];bool have_vold_decrypt = get_property("vold.decrypt", vold_decrypt, "") > 0;bool skip_compilation = (have_vold_decrypt &&(strcmp(vold_decrypt, "trigger_restart_min_framework") == 0 ||(strcmp(vold_decrypt, "1") == 0)));bool generate_debug_info = property_get_bool("debug.generate-debug-info", false);char app_image_format[kPropertyValueMax];char image_format_arg[strlen("--image-format=") + kPropertyValueMax];bool have_app_image_format =image_fd >= 0 && get_property("dalvik.vm.appimageformat", app_image_format, NULL) > 0;if (have_app_image_format) {sprintf(image_format_arg, "--image-format=%s", app_image_format);}char dex2oat_large_app_threshold[kPropertyValueMax];bool have_dex2oat_large_app_threshold =get_property("dalvik.vm.dex2oat-very-large", dex2oat_large_app_threshold, NULL) > 0;char dex2oat_large_app_threshold_arg[strlen("--very-large-app-threshold=") + kPropertyValueMax];if (have_dex2oat_large_app_threshold) {sprintf(dex2oat_large_app_threshold_arg,"--very-large-app-threshold=%s",dex2oat_large_app_threshold);}static const char* DEX2OAT_BIN = "/system/bin/dex2oat";static const char* RUNTIME_ARG = "--runtime-arg";static const int MAX_INT_LEN = 12;      // '-'+10dig+'\0' -OR- 0x+8dig// clang FORTIFY doesn't let us use strlen in constant array bounds, so we// use arraysize instead.char zip_fd_arg[arraysize("--zip-fd=") + MAX_INT_LEN];char zip_location_arg[arraysize("--zip-location=") + PKG_PATH_MAX];char input_vdex_fd_arg[arraysize("--input-vdex-fd=") + MAX_INT_LEN];char output_vdex_fd_arg[arraysize("--output-vdex-fd=") + MAX_INT_LEN];char oat_fd_arg[arraysize("--oat-fd=") + MAX_INT_LEN];char oat_location_arg[arraysize("--oat-location=") + PKG_PATH_MAX];char instruction_set_arg[arraysize("--instruction-set=") + MAX_INSTRUCTION_SET_LEN];char instruction_set_variant_arg[arraysize("--instruction-set-variant=") + kPropertyValueMax];char instruction_set_features_arg[arraysize("--instruction-set-features=") + kPropertyValueMax];char dex2oat_Xms_arg[arraysize("-Xms") + kPropertyValueMax];char dex2oat_Xmx_arg[arraysize("-Xmx") + kPropertyValueMax];char dex2oat_compiler_filter_arg[arraysize("--compiler-filter=") + kPropertyValueMax];bool have_dex2oat_swap_fd = false;char dex2oat_swap_fd[arraysize("--swap-fd=") + MAX_INT_LEN];bool have_dex2oat_image_fd = false;char dex2oat_image_fd[arraysize("--app-image-fd=") + MAX_INT_LEN];size_t class_loader_context_size = arraysize("--class-loader-context=") + PKG_PATH_MAX;char class_loader_context_arg[class_loader_context_size];if (class_loader_context != nullptr) {snprintf(class_loader_context_arg, class_loader_context_size, "--class-loader-context=%s",class_loader_context);}sprintf(zip_fd_arg, "--zip-fd=%d", zip_fd);sprintf(zip_location_arg, "--zip-location=%s", relative_input_file_name);sprintf(input_vdex_fd_arg, "--input-vdex-fd=%d", input_vdex_fd);sprintf(output_vdex_fd_arg, "--output-vdex-fd=%d", output_vdex_fd);sprintf(oat_fd_arg, "--oat-fd=%d", oat_fd);sprintf(oat_location_arg, "--oat-location=%s", output_file_name);sprintf(instruction_set_arg, "--instruction-set=%s", instruction_set);sprintf(instruction_set_variant_arg, "--instruction-set-variant=%s", dex2oat_isa_variant);sprintf(instruction_set_features_arg, "--instruction-set-features=%s", dex2oat_isa_features);if (swap_fd >= 0) {have_dex2oat_swap_fd = true;sprintf(dex2oat_swap_fd, "--swap-fd=%d", swap_fd);}if (image_fd >= 0) {have_dex2oat_image_fd = true;sprintf(dex2oat_image_fd, "--app-image-fd=%d", image_fd);}if (have_dex2oat_Xms_flag) {sprintf(dex2oat_Xms_arg, "-Xms%s", dex2oat_Xms_flag);}if (have_dex2oat_Xmx_flag) {sprintf(dex2oat_Xmx_arg, "-Xmx%s", dex2oat_Xmx_flag);}// Compute compiler filter.bool have_dex2oat_compiler_filter_flag = false;if (skip_compilation) {strcpy(dex2oat_compiler_filter_arg, "--compiler-filter=extract");have_dex2oat_compiler_filter_flag = true;have_dex2oat_relocation_skip_flag = true;} else if (compiler_filter != nullptr) {if (strlen(compiler_filter) + strlen("--compiler-filter=") <arraysize(dex2oat_compiler_filter_arg)) {sprintf(dex2oat_compiler_filter_arg, "--compiler-filter=%s", compiler_filter);have_dex2oat_compiler_filter_flag = true;} else {ALOGW("Compiler filter name '%s' is too large (max characters is %zu)",compiler_filter,kPropertyValueMax);}}if (!have_dex2oat_compiler_filter_flag) {char dex2oat_compiler_filter_flag[kPropertyValueMax];have_dex2oat_compiler_filter_flag = get_property("dalvik.vm.dex2oat-filter",dex2oat_compiler_filter_flag, NULL) > 0;if (have_dex2oat_compiler_filter_flag) {sprintf(dex2oat_compiler_filter_arg,"--compiler-filter=%s",dex2oat_compiler_filter_flag);}}// Check whether all apps should be compiled debuggable.if (!debuggable) {char prop_buf[kPropertyValueMax];debuggable =(get_property("dalvik.vm.always_debuggable", prop_buf, "0") > 0) &&(prop_buf[0] == '1');}char profile_arg[strlen("--profile-file-fd=") + MAX_INT_LEN];if (profile_fd != -1) {sprintf(profile_arg, "--profile-file-fd=%d", profile_fd);}// Get the directory of the apk to pass as a base classpath directory.char base_dir[arraysize("--classpath-dir=") + PKG_PATH_MAX];std::string apk_dir(input_file_name);unsigned long dir_index = apk_dir.rfind('/');bool has_base_dir = dir_index != std::string::npos;if (has_base_dir) {apk_dir = apk_dir.substr(0, dir_index);sprintf(base_dir, "--classpath-dir=%s", apk_dir.c_str());}ALOGV("Running %s in=%s out=%s\n", DEX2OAT_BIN, relative_input_file_name, output_file_name);const char* argv[9  // program name, mandatory arguments and the final NULL+ (have_dex2oat_isa_variant ? 1 : 0)+ (have_dex2oat_isa_features ? 1 : 0)+ (have_dex2oat_Xms_flag ? 2 : 0)+ (have_dex2oat_Xmx_flag ? 2 : 0)+ (have_dex2oat_compiler_filter_flag ? 1 : 0)+ (have_dex2oat_threads_flag ? 1 : 0)+ (have_dex2oat_swap_fd ? 1 : 0)+ (have_dex2oat_image_fd ? 1 : 0)+ (have_dex2oat_relocation_skip_flag ? 2 : 0)+ (generate_debug_info ? 1 : 0)+ (debuggable ? 1 : 0)+ (have_app_image_format ? 1 : 0)+ dex2oat_flags_count+ (profile_fd == -1 ? 0 : 1)+ (class_loader_context != nullptr ? 1 : 0)+ (has_base_dir ? 1 : 0)+ (have_dex2oat_large_app_threshold ? 1 : 0)];int i = 0;argv[i++] = DEX2OAT_BIN;argv[i++] = zip_fd_arg;argv[i++] = zip_location_arg;argv[i++] = input_vdex_fd_arg;argv[i++] = output_vdex_fd_arg;argv[i++] = oat_fd_arg;argv[i++] = oat_location_arg;argv[i++] = instruction_set_arg;if (have_dex2oat_isa_variant) {argv[i++] = instruction_set_variant_arg;}if (have_dex2oat_isa_features) {argv[i++] = instruction_set_features_arg;}if (have_dex2oat_Xms_flag) {argv[i++] = RUNTIME_ARG;argv[i++] = dex2oat_Xms_arg;}if (have_dex2oat_Xmx_flag) {argv[i++] = RUNTIME_ARG;argv[i++] = dex2oat_Xmx_arg;}if (have_dex2oat_compiler_filter_flag) {argv[i++] = dex2oat_compiler_filter_arg;}if (have_dex2oat_threads_flag) {argv[i++] = dex2oat_threads_arg;}if (have_dex2oat_swap_fd) {argv[i++] = dex2oat_swap_fd;}if (have_dex2oat_image_fd) {argv[i++] = dex2oat_image_fd;}if (generate_debug_info) {argv[i++] = "--generate-debug-info";}if (debuggable) {argv[i++] = "--debuggable";}if (have_app_image_format) {argv[i++] = image_format_arg;}if (have_dex2oat_large_app_threshold) {argv[i++] = dex2oat_large_app_threshold_arg;}if (dex2oat_flags_count) {i += split(dex2oat_flags, argv + i);}if (have_dex2oat_relocation_skip_flag) {argv[i++] = RUNTIME_ARG;argv[i++] = dex2oat_norelocation;}if (profile_fd != -1) {argv[i++] = profile_arg;}if (has_base_dir) {argv[i++] = base_dir;}if (class_loader_context != nullptr) {argv[i++] = class_loader_context_arg;}// Do not add after dex2oat_flags, they should override others for debugging.argv[i] = NULL;execv(DEX2OAT_BIN, (char * const *)argv);ALOGE("execv(%s) failed: %s\n", DEX2OAT_BIN, strerror(errno));
}

其中,参数zip_fd和oat_fd都是打开文件描述符,指向的分别是正在安装的APK文件和要生成的OAT文件。OAT文件的生成过程主要就是涉及到将包含在APK里面的classes.dex文件的DEX字节码翻译成本地机器指令。这相当于是编写一个输入文件为DEX、输出文件为OAT的编译器
 当我们选择了ART运行时时,Zygote进程在启动的过程中,会调用libart.so里面的函数JNI_CreateJavaVM来创建一个ART

/Volumes/aosp/android-8.1.0_r52/art/runtime/java_vm_ext.cc

extern "C" jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) {ScopedTrace trace(__FUNCTION__);const JavaVMInitArgs* args = static_cast<JavaVMInitArgs*>(vm_args);if (JavaVMExt::IsBadJniVersion(args->version)) {LOG(ERROR) << "Bad JNI version passed to CreateJavaVM: " << args->version;return JNI_EVERSION;}RuntimeOptions options;for (int i = 0; i < args->nOptions; ++i) {JavaVMOption* option = &args->options[i];options.push_back(std::make_pair(std::string(option->optionString), option->extraInfo));}bool ignore_unrecognized = args->ignoreUnrecognized;if (!Runtime::Create(options, ignore_unrecognized)) {return JNI_ERR;}// Initialize native loader. This step makes sure we have// everything set up before we start using JNI.android::InitializeNativeLoader();Runtime* runtime = Runtime::Current();bool started = runtime->Start();if (!started) {delete Thread::Current()->GetJniEnv();delete runtime->GetJavaVM();LOG(WARNING) << "CreateJavaVM failed";return JNI_ERR;}*p_env = Thread::Current()->GetJniEnv();*p_vm = runtime->GetJavaVM();return JNI_OK;
}

参数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,它的实现如下所示

/Volumes/aosp/android-8.1.0_r52/art/runtime/runtime.cc

bool Runtime::Create(RuntimeArgumentMap&& runtime_options) {// TODO: acquire a static mutex on Runtime to avoid racing.if (Runtime::instance_ != nullptr) {return false;}instance_ = new Runtime;Locks::SetClientCallback(IsSafeToCallAbort);if (!instance_->Init(std::move(runtime_options))) {// TODO: Currently deleting the instance will abort the runtime on destruction. Now This will// leak memory, instead. Fix the destructor. b/19100793.// delete instance_;instance_ = nullptr;return false;}return true;
}

instance_是Runtime类的静态成员变量,它指向进程中的一个Runtime单例。这个Runtime单例描述的就是当前进程的ART虚拟机实例。

       函数首先判断当前进程是否已经创建有一个ART虚拟机实例了。如果有的话,函数就立即返回。否则的话,就创建一个ART虚拟机实例,并且保存在Runtime类的静态成员变量instance_中,最后调用Runtime类的成员函数Init对该新创建的ART虚拟机进行初始化。

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

bool Runtime::Init(RuntimeArgumentMap&& runtime_options_in) {// (b/30160149): protect subprocesses from modifications to LD_LIBRARY_PATH, etc.// Take a snapshot of the environment at the time the runtime was created, for use by Exec, etc.env_snapshot_.TakeSnapshot();RuntimeArgumentMap runtime_options(std::move(runtime_options_in));ScopedTrace trace(__FUNCTION__);CHECK_EQ(sysconf(_SC_PAGE_SIZE), kPageSize);MemMap::Init();// Try to reserve a dedicated fault page. This is allocated for clobbered registers and sentinels.// If we cannot reserve it, log a warning.// Note: We allocate this first to have a good chance of grabbing the page. The address (0xebad..)//       is out-of-the-way enough that it should not collide with boot image mapping.// Note: Don't request an error message. That will lead to a maps dump in the case of failure,//       leading to logspam.{constexpr uintptr_t kSentinelAddr =RoundDown(static_cast<uintptr_t>(Context::kBadGprBase), kPageSize);protected_fault_page_.reset(MemMap::MapAnonymous("Sentinel fault page",reinterpret_cast<uint8_t*>(kSentinelAddr),kPageSize,PROT_NONE,/* low_4g */ true,/* reuse */ false,/* error_msg */ nullptr));if (protected_fault_page_ == nullptr) {LOG(WARNING) << "Could not reserve sentinel fault page";} else if (reinterpret_cast<uintptr_t>(protected_fault_page_->Begin()) != kSentinelAddr) {LOG(WARNING) << "Could not reserve sentinel fault page at the right address.";protected_fault_page_.reset();}}using Opt = RuntimeArgumentMap;VLOG(startup) << "Runtime::Init -verbose:startup enabled";QuasiAtomic::Startup();oat_file_manager_ = new OatFileManager;Thread::SetSensitiveThreadHook(runtime_options.GetOrDefault(Opt::HookIsSensitiveThread));Monitor::Init(runtime_options.GetOrDefault(Opt::LockProfThreshold),runtime_options.GetOrDefault(Opt::StackDumpLockProfThreshold));boot_class_path_string_ = runtime_options.ReleaseOrDefault(Opt::BootClassPath);class_path_string_ = runtime_options.ReleaseOrDefault(Opt::ClassPath);properties_ = runtime_options.ReleaseOrDefault(Opt::PropertiesList);compiler_callbacks_ = runtime_options.GetOrDefault(Opt::CompilerCallbacksPtr);patchoat_executable_ = runtime_options.ReleaseOrDefault(Opt::PatchOat);must_relocate_ = runtime_options.GetOrDefault(Opt::Relocate);is_zygote_ = runtime_options.Exists(Opt::Zygote);is_explicit_gc_disabled_ = runtime_options.Exists(Opt::DisableExplicitGC);dex2oat_enabled_ = runtime_options.GetOrDefault(Opt::Dex2Oat);image_dex2oat_enabled_ = runtime_options.GetOrDefault(Opt::ImageDex2Oat);dump_native_stack_on_sig_quit_ = runtime_options.GetOrDefault(Opt::DumpNativeStackOnSigQuit);vfprintf_ = runtime_options.GetOrDefault(Opt::HookVfprintf);exit_ = runtime_options.GetOrDefault(Opt::HookExit);abort_ = runtime_options.GetOrDefault(Opt::HookAbort);default_stack_size_ = runtime_options.GetOrDefault(Opt::StackSize);use_tombstoned_traces_ = runtime_options.GetOrDefault(Opt::UseTombstonedTraces);
#if !defined(ART_TARGET_ANDROID)CHECK(!use_tombstoned_traces_)<< "-Xusetombstonedtraces is only supported in an Android environment";
#endifstack_trace_file_ = runtime_options.ReleaseOrDefault(Opt::StackTraceFile);compiler_executable_ = runtime_options.ReleaseOrDefault(Opt::Compiler);compiler_options_ = runtime_options.ReleaseOrDefault(Opt::CompilerOptions);for (StringPiece option : Runtime::Current()->GetCompilerOptions()) {if (option.starts_with("--debuggable")) {SetJavaDebuggable(true);break;}}image_compiler_options_ = runtime_options.ReleaseOrDefault(Opt::ImageCompilerOptions);image_location_ = runtime_options.GetOrDefault(Opt::Image);max_spins_before_thin_lock_inflation_ =runtime_options.GetOrDefault(Opt::MaxSpinsBeforeThinLockInflation);monitor_list_ = new MonitorList;monitor_pool_ = MonitorPool::Create();thread_list_ = new ThreadList(runtime_options.GetOrDefault(Opt::ThreadSuspendTimeout));intern_table_ = new InternTable;verify_ = runtime_options.GetOrDefault(Opt::Verify);allow_dex_file_fallback_ = !runtime_options.Exists(Opt::NoDexFileFallback);no_sig_chain_ = runtime_options.Exists(Opt::NoSigChain);force_native_bridge_ = runtime_options.Exists(Opt::ForceNativeBridge);Split(runtime_options.GetOrDefault(Opt::CpuAbiList), ',', &cpu_abilist_);fingerprint_ = runtime_options.ReleaseOrDefault(Opt::Fingerprint);if (runtime_options.GetOrDefault(Opt::Interpret)) {GetInstrumentation()->ForceInterpretOnly();}zygote_max_failed_boots_ = runtime_options.GetOrDefault(Opt::ZygoteMaxFailedBoots);experimental_flags_ = runtime_options.GetOrDefault(Opt::Experimental);is_low_memory_mode_ = runtime_options.Exists(Opt::LowMemoryMode);madvise_random_access_ = runtime_options.GetOrDefault(Opt::MadviseRandomAccess);plugins_ = runtime_options.ReleaseOrDefault(Opt::Plugins);agents_ = runtime_options.ReleaseOrDefault(Opt::AgentPath);// TODO Add back in -agentlib// for (auto lib : runtime_options.ReleaseOrDefault(Opt::AgentLib)) {//   agents_.push_back(lib);// }float foreground_heap_growth_multiplier;if (is_low_memory_mode_ && !runtime_options.Exists(Opt::ForegroundHeapGrowthMultiplier)) {// If low memory mode, use 1.0 as the multiplier by default.foreground_heap_growth_multiplier = 1.0f;} else {foreground_heap_growth_multiplier =runtime_options.GetOrDefault(Opt::ForegroundHeapGrowthMultiplier) +kExtraDefaultHeapGrowthMultiplier;}XGcOption xgc_option = runtime_options.GetOrDefault(Opt::GcOption);heap_ = new gc::Heap(runtime_options.GetOrDefault(Opt::MemoryInitialSize),runtime_options.GetOrDefault(Opt::HeapGrowthLimit),runtime_options.GetOrDefault(Opt::HeapMinFree),runtime_options.GetOrDefault(Opt::HeapMaxFree),runtime_options.GetOrDefault(Opt::HeapTargetUtilization),foreground_heap_growth_multiplier,runtime_options.GetOrDefault(Opt::MemoryMaximumSize),runtime_options.GetOrDefault(Opt::NonMovingSpaceCapacity),runtime_options.GetOrDefault(Opt::Image),runtime_options.GetOrDefault(Opt::ImageInstructionSet),// Override the collector type to CC if the read barrier config.kUseReadBarrier ? gc::kCollectorTypeCC : xgc_option.collector_type_,kUseReadBarrier ? BackgroundGcOption(gc::kCollectorTypeCCBackground): runtime_options.GetOrDefault(Opt::BackgroundGc),runtime_options.GetOrDefault(Opt::LargeObjectSpace),runtime_options.GetOrDefault(Opt::LargeObjectThreshold),runtime_options.GetOrDefault(Opt::ParallelGCThreads),runtime_options.GetOrDefault(Opt::ConcGCThreads),runtime_options.Exists(Opt::LowMemoryMode),runtime_options.GetOrDefault(Opt::LongPauseLogThreshold),runtime_options.GetOrDefault(Opt::LongGCLogThreshold),runtime_options.Exists(Opt::IgnoreMaxFootprint),runtime_options.GetOrDefault(Opt::UseTLAB),xgc_option.verify_pre_gc_heap_,xgc_option.verify_pre_sweeping_heap_,xgc_option.verify_post_gc_heap_,xgc_option.verify_pre_gc_rosalloc_,xgc_option.verify_pre_sweeping_rosalloc_,xgc_option.verify_post_gc_rosalloc_,xgc_option.gcstress_,xgc_option.measure_,runtime_options.GetOrDefault(Opt::EnableHSpaceCompactForOOM),runtime_options.GetOrDefault(Opt::HSpaceCompactForOOMMinIntervalsMs));if (!heap_->HasBootImageSpace() && !allow_dex_file_fallback_) {LOG(ERROR) << "Dex file fallback disabled, cannot continue without image.";return false;}dump_gc_performance_on_shutdown_ = runtime_options.Exists(Opt::DumpGCPerformanceOnShutdown);if (runtime_options.Exists(Opt::JdwpOptions)) {Dbg::ConfigureJdwp(runtime_options.GetOrDefault(Opt::JdwpOptions));}callbacks_->AddThreadLifecycleCallback(Dbg::GetThreadLifecycleCallback());callbacks_->AddClassLoadCallback(Dbg::GetClassLoadCallback());jit_options_.reset(jit::JitOptions::CreateFromRuntimeArguments(runtime_options));if (IsAotCompiler()) {// If we are already the compiler at this point, we must be dex2oat. Don't create the jit in// this case.// If runtime_options doesn't have UseJIT set to true then CreateFromRuntimeArguments returns// null and we don't create the jit.jit_options_->SetUseJitCompilation(false);jit_options_->SetSaveProfilingInfo(false);}// Use MemMap arena pool for jit, malloc otherwise. Malloc arenas are faster to allocate but// can't be trimmed as easily.const bool use_malloc = IsAotCompiler();arena_pool_.reset(new ArenaPool(use_malloc, /* low_4gb */ false));jit_arena_pool_.reset(new ArenaPool(/* use_malloc */ false, /* low_4gb */ false, "CompilerMetadata"));if (IsAotCompiler() && Is64BitInstructionSet(kRuntimeISA)) {// 4gb, no malloc. Explanation in header.low_4gb_arena_pool_.reset(new ArenaPool(/* use_malloc */ false, /* low_4gb */ true));}linear_alloc_.reset(CreateLinearAlloc());BlockSignals();InitPlatformSignalHandlers();// Change the implicit checks flags based on runtime architecture.switch (kRuntimeISA) {case kArm:case kThumb2:case kX86:case kArm64:case kX86_64:case kMips:case kMips64:implicit_null_checks_ = true;// Installing stack protection does not play well with valgrind.implicit_so_checks_ = !(RUNNING_ON_MEMORY_TOOL && kMemoryToolIsValgrind);break;default:// Keep the defaults.break;}if (!no_sig_chain_) {// Dex2Oat's Runtime does not need the signal chain or the fault handler.if (implicit_null_checks_ || implicit_so_checks_ || implicit_suspend_checks_) {fault_manager.Init();// These need to be in a specific order.  The null point check handler must be// after the suspend check and stack overflow check handlers.//// Note: the instances attach themselves to the fault manager and are handled by it. The manager//       will delete the instance on Shutdown().if (implicit_suspend_checks_) {new SuspensionHandler(&fault_manager);}if (implicit_so_checks_) {new StackOverflowHandler(&fault_manager);}if (implicit_null_checks_) {new NullPointerHandler(&fault_manager);}if (kEnableJavaStackTraceHandler) {new JavaStackTraceHandler(&fault_manager);}}}std::string error_msg;java_vm_ = JavaVMExt::Create(this, runtime_options, &error_msg);if (java_vm_.get() == nullptr) {LOG(ERROR) << "Could not initialize JavaVMExt: " << error_msg;return false;}// Add the JniEnv handler.// TODO Refactor this stuff.java_vm_->AddEnvironmentHook(JNIEnvExt::GetEnvHandler);Thread::Startup();// ClassLinker needs an attached thread, but we can't fully attach a thread without creating// objects. We can't supply a thread group yet; it will be fixed later. Since we are the main// thread, we do not get a java peer.Thread* self = Thread::Attach("main", false, nullptr, false);CHECK_EQ(self->GetThreadId(), ThreadList::kMainThreadId);CHECK(self != nullptr);self->SetCanCallIntoJava(!IsAotCompiler());// Set us to runnable so tools using a runtime can allocate and GC by defaultself->TransitionFromSuspendedToRunnable();// Now we're attached, we can take the heap locks and validate the heap.GetHeap()->EnableObjectValidation();CHECK_GE(GetHeap()->GetContinuousSpaces().size(), 1U);if (UNLIKELY(IsAotCompiler())) {class_linker_ = new AotClassLinker(intern_table_);} else {class_linker_ = new ClassLinker(intern_table_);}if (GetHeap()->HasBootImageSpace()) {bool result = class_linker_->InitFromBootImage(&error_msg);if (!result) {LOG(ERROR) << "Could not initialize from image: " << error_msg;return false;}if (kIsDebugBuild) {for (auto image_space : GetHeap()->GetBootImageSpaces()) {image_space->VerifyImageAllocations();}}if (boot_class_path_string_.empty()) {// The bootclasspath is not explicitly specified: construct it from the loaded dex files.const std::vector<const DexFile*>& boot_class_path = GetClassLinker()->GetBootClassPath();std::vector<std::string> dex_locations;dex_locations.reserve(boot_class_path.size());for (const DexFile* dex_file : boot_class_path) {dex_locations.push_back(dex_file->GetLocation());}boot_class_path_string_ = android::base::Join(dex_locations, ':');}{ScopedTrace trace2("AddImageStringsToTable");GetInternTable()->AddImagesStringsToTable(heap_->GetBootImageSpaces());}if (IsJavaDebuggable()) {// Now that we have loaded the boot image, deoptimize its methods if we are running// debuggable, as the code may have been compiled non-debuggable.DeoptimizeBootImage();}} else {std::vector<std::string> dex_filenames;Split(boot_class_path_string_, ':', &dex_filenames);std::vector<std::string> dex_locations;if (!runtime_options.Exists(Opt::BootClassPathLocations)) {dex_locations = dex_filenames;} else {dex_locations = runtime_options.GetOrDefault(Opt::BootClassPathLocations);CHECK_EQ(dex_filenames.size(), dex_locations.size());}std::vector<std::unique_ptr<const DexFile>> boot_class_path;if (runtime_options.Exists(Opt::BootClassPathDexList)) {boot_class_path.swap(*runtime_options.GetOrDefault(Opt::BootClassPathDexList));} else {OpenDexFiles(dex_filenames,dex_locations,runtime_options.GetOrDefault(Opt::Image),&boot_class_path);}instruction_set_ = runtime_options.GetOrDefault(Opt::ImageInstructionSet);if (!class_linker_->InitWithoutImage(std::move(boot_class_path), &error_msg)) {LOG(ERROR) << "Could not initialize without image: " << error_msg;return false;}// TODO: Should we move the following to InitWithoutImage?SetInstructionSet(instruction_set_);for (uint32_t i = 0; i < kCalleeSaveSize; i++) {CalleeSaveType type = CalleeSaveType(i);if (!HasCalleeSaveMethod(type)) {SetCalleeSaveMethod(CreateCalleeSaveMethod(), type);}}}CHECK(class_linker_ != nullptr);verifier::MethodVerifier::Init();if (runtime_options.Exists(Opt::MethodTrace)) {trace_config_.reset(new TraceConfig());trace_config_->trace_file = runtime_options.ReleaseOrDefault(Opt::MethodTraceFile);trace_config_->trace_file_size = runtime_options.ReleaseOrDefault(Opt::MethodTraceFileSize);trace_config_->trace_mode = Trace::TraceMode::kMethodTracing;trace_config_->trace_output_mode = runtime_options.Exists(Opt::MethodTraceStreaming) ?Trace::TraceOutputMode::kStreaming :Trace::TraceOutputMode::kFile;}// TODO: move this to just be an Trace::Start argumentTrace::SetDefaultClockSource(runtime_options.GetOrDefault(Opt::ProfileClock));// Pre-allocate an OutOfMemoryError for the double-OOME case.self->ThrowNewException("Ljava/lang/OutOfMemoryError;","OutOfMemoryError thrown while trying to throw OutOfMemoryError; ""no stack trace available");pre_allocated_OutOfMemoryError_ = GcRoot<mirror::Throwable>....
......}

 

创建好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虚拟机的堆创建过程。
 Heap类的构造函数的

相关文章:

  • Hadoop 1.x设计理念解析
  • 配置和使用持久卷
  • Prompt多版本测试指南:如何科学评估不同提示词的效果
  • OpenCv实战笔记(1)在win11搭建opencv4.11.1 + qt5.15.2 + vs2019_x64开发环境
  • ROC-AUC:模型评估的“超级英雄
  • 文献分享:CH-CL配对和VL结构域的完整性影响IgG1分泌过程
  • Coco AI 入驻 GitCode:打破数据孤岛,解锁智能协作新可能
  • (undone) MIT6.S081 2023 学习笔记 (Day10: LAB9 fs file system)
  • 深入了解 OpenIddict:实现 OAuth 2.0 和 OpenID Connect 协议的 .NET 库
  • 如何使用VSCode编写C、C++和Python程序
  • Go语言八股文之Map详解
  • 【项目篇之统一内存操作】仿照RabbitMQ模拟实现消息队列
  • R语言traj包进行潜轨迹分析
  • 电气设备器件选型参数---断路器
  • 学习黑客 TCP/IP
  • 民法学学习笔记(个人向) Part.3
  • [方法论]软件工程中的软件架构设计:从理论到实践的深度解析
  • 碰撞检测学习笔记
  • 平衡二叉搜索树模拟实现1-------AVL树(插入,删除,查找)
  • C++入门小馆:继承
  • 当一群杜克土木工程毕业生在三四十年后怀念大学的历史课……
  • 海港通报颜骏凌伤停两至三周,国足面临门将伤病危机
  • “特朗普效应”下澳大利亚执政工党赢得大选,年轻选民担忧房价
  • 中虎跳峡封闭仍有游客逆行打卡,景区:专人值守防意外
  • 长三角铁路今日预计发送390万人次,昨日客发量同比增长10.5%
  • 月薪3万文科友好,“AI训练师”真有那么赚?