文章目录
前言
一、dalvik_system_DexFile.cc#DexFile_openDexFileNative 函数分析
二、oat_file_manager.cc#OpenDexFilesFromOat 函数分析
三、oat_file_assistant.cc#MakeUpToDate 函数分析
四、oat_file_assistant.cc#GenerateOatFileNoChecks 函数分析
五、oat_file_assistant.cc#Dex2Oat 函数分析
前言
在上一篇博客 【Android 逆向】ART 脱壳 ( DexClassLoader 脱壳 | DexClassLoader 构造函数 | 参考 Dalvik 的 DexClassLoader 类加载流程 ) 中 , 分析了 ART 虚拟机下 DexClassLoader 类加载器加载 dex 文件的 Java 层流程 , 与 Dalvik 虚拟机下基本一致 , 从 native 层开始不一致 , 本篇博客开始分析 native 层的类加载流程 ;
一、dalvik_system_DexFile.cc#DexFile_openDexFileNative 函数分析
在下面的 DexFile_openDexFileNative 方法中 ,
jstring javaSourceName 参数是要加载的 dex 文件路径 ,
下面调用的 OpenDexFilesFromOat 函数 , 是生成 oat 文件的关键流程入口 ;
dex_files = runtime->GetOatFileManager().OpenDexFilesFromOat(sourceName.c_str(), class_loader, dex_elements, /*out*/ &oat_file, /*out*/ &error_msgs);
dalvik_system_DexFile.cc#DexFile_openDexFileNative 源码 :
// TODO(calin): clean up the unused parameters (here and in libcore). static jobject DexFile_openDexFileNative(JNIEnv* env, jclass, jstring javaSourceName, jstring javaOutputName ATTRIBUTE_UNUSED, jint flags ATTRIBUTE_UNUSED, jobject class_loader, jobjectArray dex_elements) { ScopedUtfChars sourceName(env, javaSourceName); if (sourceName.c_str() == nullptr) { return 0; } Runtime* const runtime = Runtime::Current(); ClassLinker* linker = runtime->GetClassLinker(); std::vector<std::unique_ptr<const DexFile>> dex_files; std::vector<std::string> error_msgs; // OAT 文件 const OatFile* oat_file = nullptr; // ★ 核心跳转 dex_files = runtime->GetOatFileManager().OpenDexFilesFromOat(sourceName.c_str(), class_loader, dex_elements, /*out*/ &oat_file, /*out*/ &error_msgs); if (!dex_files.empty()) { jlongArray array = ConvertDexFilesToJavaArray(env, oat_file, dex_files); if (array == nullptr) { ScopedObjectAccess soa(env); for (auto& dex_file : dex_files) { if (linker->IsDexFileRegistered(soa.Self(), *dex_file)) { dex_file.release(); } } } return array; } else { ScopedObjectAccess soa(env); CHECK(!error_msgs.empty()); // The most important message is at the end. So set up nesting by going forward, which will // wrap the existing exception as a cause for the following one. auto it = error_msgs.begin(); auto itEnd = error_msgs.end(); for ( ; it != itEnd; ++it) { ThrowWrappedIOException("%s", it->c_str()); } return nullptr; } }
源码路径 : /art/runtime/native/dalvik_system_DexFile.cc#DexFile_openDexFileNative
二、oat_file_manager.cc#OpenDexFilesFromOat 函数分析
先声明 oat 文件对象 ,
// 声明 OatFile 对象 const OatFile* source_oat_file = nullptr;
然后判断是否有生成 oat 文件 , 如果是第一次调用 , 肯定没有生成 oat 文件 ,
!oat_file_assistant.IsUpToDate()
如果没有生成 oat 文件 , 则执行
oat_file_assistant.MakeUpToDate(/*profile_changed*/false, /*out*/ &error_msg)
方法 , 开始生成 oat 文件 ;
oat_file_manager.cc#OpenDexFilesFromOat 函数源码 :
std::vector<std::unique_ptr<const DexFile>> OatFileManager::OpenDexFilesFromOat( const char* dex_location, jobject class_loader, jobjectArray dex_elements, const OatFile** out_oat_file, std::vector<std::string>* error_msgs) { ScopedTrace trace(__FUNCTION__); CHECK(dex_location != nullptr); CHECK(error_msgs != nullptr); // 验证我们没有持有mutator锁,如果我们必须生成或重新定位oat文件,这可能会导致GC饥饿。 Thread* const self = Thread::Current(); Locks::mutator_lock_->AssertNotHeld(self); Runtime* const runtime = Runtime::Current(); OatFileAssistant oat_file_assistant(dex_location, kRuntimeISA, !runtime->IsAotCompiler()); // 锁定目标oat位置以避免生成和加载oat文件。 std::string error_msg; if (!oat_file_assistant.Lock(/*out*/&error_msg)) { // Don't worry too much if this fails. If it does fail, it's unlikely we // can generate an oat file anyway. VLOG(class_linker) << "OatFileAssistant::Lock: " << error_msg; } // 声明 OatFile 对象 const OatFile* source_oat_file = nullptr; // 判断是否有生成 oat 文件 , 如果是第一次调用 , 肯定没有生成 oat 文件 if (!oat_file_assistant.IsUpToDate()) { // 如果可以,根据从当前运行时选项派生的--compiler-filter选项更新磁盘上的oat文件 // 这可能会失败,但没关系。这里最重要的是尽最大努力。 // ★ 核心跳转 switch (oat_file_assistant.MakeUpToDate(/*profile_changed*/false, /*out*/ &error_msg)) { case OatFileAssistant::kUpdateFailed: LOG(WARNING) << error_msg; break; case OatFileAssistant::kUpdateNotAttempted: // 如果我们决定不尝试更新oat文件,请避免滥发日志。 VLOG(oat) << error_msg; break; case OatFileAssistant::kUpdateSucceeded: // Nothing to do. break; } } // Get the oat file on disk. std::unique_ptr<const OatFile> oat_file(oat_file_assistant.GetBestOatFile().release()); if (oat_file != nullptr) { // 仅当文件没有冲突时才获取该文件,否则我们必须获取该文件,因为存在预选项。 bool accept_oat_file = !HasCollisions(oat_file.get(), class_loader, dex_elements, /*out*/ &error_msg); if (!accept_oat_file) { // 冲突检查失败。打印警告。 if (Runtime::Current()->IsDexFileFallbackEnabled()) { if (!oat_file_assistant.HasOriginalDexFiles()) { // 我们需要回退,但没有原始的dex文件。 // 我们必须回退到打开现有的oat文件。 // 这可能不安全,因此我们对此发出警告。 accept_oat_file = true; LOG(WARNING) << "Dex location " << dex_location << " does not seem to include dex file. " << "Allow oat file use. This is potentially dangerous."; } else { // 我们必须回退并找到原始的dex文件-从APK中提取它们。 // 同时警告此操作,因为它可能会造成浪费。 LOG(WARNING) << "Found duplicate classes, falling back to extracting from APK : " << dex_location; LOG(WARNING) << "NOTE: This wastes RAM and hurts startup performance."; } } else { // TODO: 我们应该删除这个。我们在这里的事实意味着没有设置-Xno dex文件回退, // 这意味着我们永远不应该回退。 // 如果我们没有原始的dex文件,我们应该按照标志的意图失败解析。 if (!oat_file_assistant.HasOriginalDexFiles()) { accept_oat_file = true; } LOG(WARNING) << "Found duplicate classes, dex-file-fallback disabled, will be failing to " " load classes for " << dex_location; } LOG(WARNING) << error_msg; } if (accept_oat_file) { VLOG(class_linker) << "Registering " << oat_file->GetLocation(); source_oat_file = RegisterOatFile(std::move(oat_file)); *out_oat_file = source_oat_file; } } std::vector<std::unique_ptr<const DexFile>> dex_files; // Load the dex files from the oat file. if (source_oat_file != nullptr) { bool added_image_space = false; if (source_oat_file->IsExecutable()) { std::unique_ptr<gc::space::ImageSpace> image_space = kEnableAppImage ? oat_file_assistant.OpenImageSpace(source_oat_file) : nullptr; if (image_space != nullptr) { ScopedObjectAccess soa(self); StackHandleScope<1> hs(self); Handle<mirror::ClassLoader> h_loader( hs.NewHandle(soa.Decode<mirror::ClassLoader>(class_loader))); // Can not load app image without class loader. if (h_loader != nullptr) { std::string temp_error_msg; // Add image space has a race condition since other threads could be reading from the // spaces array. { ScopedThreadSuspension sts(self, kSuspended); gc::ScopedGCCriticalSection gcs(self, gc::kGcCauseAddRemoveAppImageSpace, gc::kCollectorTypeAddRemoveAppImageSpace); ScopedSuspendAll ssa("Add image space"); runtime->GetHeap()->AddSpace(image_space.get()); } { ScopedTrace trace2(StringPrintf("Adding image space for location %s", dex_location)); added_image_space = runtime->GetClassLinker()->AddImageSpace(image_space.get(), h_loader, dex_elements, dex_location, /*out*/&dex_files, /*out*/&temp_error_msg); } if (added_image_space) { // Successfully added image space to heap, release the map so that it does not get // freed. image_space.release(); } else { LOG(INFO) << "Failed to add image file " << temp_error_msg; dex_files.clear(); { ScopedThreadSuspension sts(self, kSuspended); gc::ScopedGCCriticalSection gcs(self, gc::kGcCauseAddRemoveAppImageSpace, gc::kCollectorTypeAddRemoveAppImageSpace); ScopedSuspendAll ssa("Remove image space"); runtime->GetHeap()->RemoveSpace(image_space.get()); } // Non-fatal, don't update error_msg. } } } } if (!added_image_space) { DCHECK(dex_files.empty()); dex_files = oat_file_assistant.LoadDexFiles(*source_oat_file, dex_location); } if (dex_files.empty()) { error_msgs->push_back("Failed to open dex files from " + source_oat_file->GetLocation()); } } // Fall back to running out of the original dex file if we couldn't load any // dex_files from the oat file. if (dex_files.empty()) { if (oat_file_assistant.HasOriginalDexFiles()) { if (Runtime::Current()->IsDexFileFallbackEnabled()) { static constexpr bool kVerifyChecksum = true; if (!DexFile::Open( dex_location, dex_location, kVerifyChecksum, /*out*/ &error_msg, &dex_files)) { LOG(WARNING) << error_msg; error_msgs->push_back("Failed to open dex files from " + std::string(dex_location) + " because: " + error_msg); } } else { error_msgs->push_back("Fallback mode disabled, skipping dex files."); } } else { error_msgs->push_back("No original dex files found for dex location " + std::string(dex_location)); } } return dex_files; }
源码路径 : /art/runtime/oat_file_manager.cc#OpenDexFilesFromOat