解析android系统下Dex2oat的实现

简介

在Android系统5.0及以上系统开始逐渐丢弃Dalvik虚拟机,由于ART虚拟机对内存分配和回收都做了算法优化,降低了内存碎片化程度,回收时间也得以缩短,所有android系统5.0及以上都在主推ART虚拟机。在ART虚拟机中ART则会将Dex通过dex2oat工具编译得到一个ELF文件,它是一个可执行的文件。所以下面我们就针对ART的dex2oat实现进行做分析。

dex2oat介绍

Dex2oat的全称是:dalvik excutable file to optimized art file,它是一个对 android系统下的dex文件,进行编译优化的程序。通过dex2oat的编译优化,可以大大的提高android系统的启动的速度和使用手机过程的的流畅度。

dex2oat在安卓手机环境下的存放位置为/system/bin/dex2oat

为什么要使用dex2oat进行转换

在android系统中,Android 虚拟机可以识别到的是dex文件,App应用在使用过程中如果每次将dex文件加载进行内存,解释性执行字节码,效率就会变得非常低, 从而影响到用户在使用安卓手机的体验。通过利用dex2oat进行优化处理, 那么可以在android系统运行之前,利用合适的时机将dex文件字节码,提前转化为虚拟机上可以执行运行的机器码,后续直接从效率更高的机器码中运行,则运行阶段更加流畅,优化用户体验。

dex2oat代码

dex2oat类定义

class Dex2Oat {
 public:
 
 //创建函数,返回值为bool,static bool Create(Dex2Oat** p_dex2oat, const RuntimeOptions& runtime_options, const CompilerOptions& compiler_options, Compiler::Kind compiler_kind, InstructionSet instruction_set, InstructionSetFeatures instruction_set_features, VerificationResults* verification_results, DexFileToMethodInlinerMap* method_inliner_map, size_t thread_count)SHARED_TRYLOCK_FUNCTION(true, Locks::mutator_lock_) {//判断参数传递进来的释放为空CHECK(verification_results != nullptr);CHECK(method_inliner_map != nullptr);//用智能指针方式进行去实例化dex2oatstd::unique_ptr<Dex2Oat> dex2oat(new Dex2Oat(&compiler_options, compiler_kind, instruction_set, instruction_set_features, verification_results, method_inliner_map, thread_count));if (!dex2oat->CreateRuntime(runtime_options, instruction_set)) {*p_dex2oat = nullptr;return false;}*p_dex2oat = dex2oat.release();return true;}//dex2oat的虚构函数,用于释放操作。~Dex2Oat() {delete runtime_;LogCompletionTime();}void LogCompletionTime() {LOG(INFO) << "dex2oat took " << PrettyDuration(NanoTime() - start_ns_)<< " (threads: " << thread_count_ << ")";}//从文件上获取到类名称std::set<std::string>* ReadImageClassesFromFile(const char* image_classes_filename) {std::unique_ptr<std::ifstream> image_classes_file(new std::ifstream(image_classes_filename,std::ifstream::in));if (image_classes_file.get() == nullptr) {LOG(ERROR) << "Failed to open image classes file " << image_classes_filename;return nullptr;}std::unique_ptr<std::set<std::string>> result(ReadImageClasses(*image_classes_file));image_classes_file->close();return result.release();} //读取imageclassesstd::set<std::string>* ReadImageClasses(std::istream& image_classes_stream) {std::unique_ptr<std::set<std::string>> image_classes(new std::set<std::string>);while (image_classes_stream.good()) {std::string dot;std::getline(image_classes_stream, dot);if (StartsWith(dot, "#") || dot.empty()) {continue;}std::string descriptor(DotToDescriptor(dot.c_str()));image_classes->insert(descriptor);}return image_classes.release();}// Reads the class names (java.lang.Object) and returns a set of descriptors (Ljava/lang/Object;)//从zip文件(apk其实就是个zip文件)读取类名称,读取到返回一个描述std::set<std::string>* ReadImageClassesFromZip(const char* zip_filename, const char* image_classes_filename, std::string* error_msg) { //通过智能指针进行打开zip压缩包,也就是apk包 std::unique_ptr<ZipArchive> zip_archive(ZipArchive::Open(zip_filename, error_msg));//判断打开是否失败if (zip_archive.get() == nullptr) {return nullptr;}//进行遍历zip包获取zip包里面的文件信息std::unique_ptr<ZipEntry> zip_entry(zip_archive->Find(image_classes_filename, error_msg));if (zip_entry.get() == nullptr) {*error_msg = StringPrintf("Failed to find '%s' within '%s': %s", image_classes_filename,zip_filename, error_msg->c_str());return nullptr;}std::unique_ptr<MemMap> image_classes_file(zip_entry->ExtractToMemMap(zip_filename,image_classes_filename,error_msg));if (image_classes_file.get() == nullptr) {*error_msg = StringPrintf("Failed to extract '%s' from '%s': %s", image_classes_filename,zip_filename, error_msg->c_str());return nullptr;}const std::string image_classes_string(reinterpret_cast<char*>(image_classes_file->Begin()), image_classes_file->Size());std::istringstream image_classes_stream(image_classes_string);return ReadImageClasses(image_classes_stream);}bool PatchOatCode(const CompilerDriver* compiler_driver, File* oat_file,const std::string& oat_location, std::string* error_msg) {// We asked to include patch information but we are not making an image. We need to fix// everything up manually.std::unique_ptr<ElfFile> elf_file(ElfFile::Open(oat_file, PROT_READ|PROT_WRITE,MAP_SHARED, error_msg));if (elf_file.get() == NULL) {LOG(ERROR) << error_msg;return false;}{ReaderMutexLock mu(Thread::Current(), *Locks::mutator_lock_);return ElfPatcher::Patch(compiler_driver, elf_file.get(), oat_location, error_msg);}}//创建一个oat文件,返回一个常量指针const CompilerDriver* CreateOatFile(const std::string& boot_image_option,const std::string& android_root,bool is_host,const std::vector<const DexFile*>& dex_files,File* oat_file,const std::string& oat_location,const std::string& bitcode_filename,bool image,std::unique_ptr<std::set<std::string>>& image_classes,bool dump_stats,bool dump_passes,TimingLogger& timings,CumulativeLogger& compiler_phases_timings,std::string profile_file,SafeMap<std::string, std::string>* key_value_store) {CHECK(key_value_store != nullptr);// Handle and ClassLoader creation needs to come after Runtime::Createjobject class_loader = nullptr;//获取自身进程Thread* self = Thread::Current();//如果boot_image_option不为空的话,执行下面的代码if (!boot_image_option.empty()) {ClassLinker* class_linker = Runtime::Current()->GetClassLinker();std::vector<const DexFile*> class_path_files(dex_files);OpenClassPathFiles(runtime_->GetClassPathString(), class_path_files);ScopedObjectAccess soa(self);//循环遍历并类文件大小,并进行dex文件进行注册for (size_t i = 0; i < class_path_files.size(); i++) {class_linker->RegisterDexFile(*class_path_files[i]);}soa.Env()->AllocObject(WellKnownClasses::dalvik_system_PathClassLoader);ScopedLocalRef<jobject> class_loader_local(soa.Env(),soa.Env()->AllocObject(WellKnownClasses::dalvik_system_PathClassLoader));class_loader = soa.Env()->NewGlobalRef(class_loader_local.get());Runtime::Current()->SetCompileTimeClassPath(class_loader, class_path_files);}std::unique_ptr<CompilerDriver> driver(new CompilerDriver(compiler_options_,verification_results_,method_inliner_map_,compiler_kind_,instruction_set_,instruction_set_features_,image,image_classes.release(),thread_count_,dump_stats,dump_passes,&compiler_phases_timings,profile_file));driver->GetCompiler()->SetBitcodeFileName(*driver.get(), bitcode_filename);driver->CompileAll(class_loader, dex_files, &timings);TimingLogger::ScopedTiming t2("dex2oat OatWriter", &timings);std::string image_file_location;uint32_t image_file_location_oat_checksum = 0;uintptr_t image_file_location_oat_data_begin = 0;int32_t image_patch_delta = 0;if (!driver->IsImage()) {TimingLogger::ScopedTiming t3("Loading image checksum", &timings);gc::space::ImageSpace* image_space = Runtime::Current()->GetHeap()->GetImageSpace();image_file_location_oat_checksum = image_space->GetImageHeader().GetOatChecksum();image_file_location_oat_data_begin =reinterpret_cast<uintptr_t>(image_space->GetImageHeader().GetOatDataBegin());image_file_location = image_space->GetImageFilename();image_patch_delta = image_space->GetImageHeader().GetPatchDelta();}if (!image_file_location.empty()) {key_value_store->Put(OatHeader::kImageLocationKey, image_file_location);}//oat写入操作OatWriter oat_writer(dex_files, image_file_location_oat_checksum, image_file_location_oat_data_begin, image_patch_delta, driver.get(), &timings, key_value_store);t2.NewTiming("Writing ELF");if (!driver->WriteElf(android_root, is_host, dex_files, &oat_writer, oat_file)) 
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值