if (success || !dex_files->empty()) { // In the case of non-success, we have not found or could not generate the oat file. // But we may still have found a dex file that we can use. returnstatic_cast<jlong>(reinterpret_cast<uintptr_t>(dex_files.release())); } else { // 加载失败的情况,省略 } }
// Multidex files make it possible that some, but not all, dex files can be broken/outdated. This // complicates the loading process, as we should not use an iterative loading process, because that // would register the oat file and dex files that come before the broken one. Instead, check all // multidex ahead of time. bool ClassLinker::OpenDexFilesFromOat(constchar* dex_location, constchar* oat_location, std::vector<std::string>* error_msgs, std::vector<const DexFile*>* dex_files) { // 1) Check whether we have an open oat file. // This requires a dex checksum, use the "primary" one. bool needs_registering = false;
// 2) If we do not have an open one, maybe there's one on disk already.
// In case the oat file is not open, we play a locking game here so // that if two different processes race to load and register or generate // (or worse, one tries to open a partial generated file) we will be okay. // This is actually common with apps that use DexClassLoader to work // around the dex method reference limit and that have a background // service running in a separate process. ScopedFlock scoped_flock;
if (open_oat_file.get() == nullptr) { if (oat_location != nullptr) { std::string error_msg;
// We are loading or creating one in the future. Time to set up the file lock. if (!scoped_flock.Init(oat_location, &error_msg)) { error_msgs->push_back(error_msg); returnfalse; }
// TODO Caller specifically asks for this oat_location. We should honor it. Probably? open_oat_file.reset(FindOatFileInOatLocationForDexFile(dex_location, dex_location_checksum, oat_location, &error_msg));
if (open_oat_file.get() == nullptr) { std::string compound_msg = StringPrintf("Failed to find dex file '%s' in oat location '%s': %s", dex_location, oat_location, error_msg.c_str()); VLOG(class_linker) << compound_msg; error_msgs->push_back(compound_msg); } } else { // TODO: What to lock here? bool obsolete_file_cleanup_failed; open_oat_file.reset(FindOatFileContainingDexFileFromDexLocation(dex_location, dex_location_checksum_pointer, kRuntimeISA, error_msgs, &obsolete_file_cleanup_failed)); // There's no point in going forward and eventually try to regenerate the // file if we couldn't remove the obsolete one. Mostly likely we will fail // with the same error when trying to write the new file. // TODO: should we maybe do this only when we get permission issues? (i.e. EACCESS). if (obsolete_file_cleanup_failed) { returnfalse; } } needs_registering = true; }
// 3) If we have an oat file, check all contained multidex files for our dex_location. // Note: LoadMultiDexFilesFromOatFile will check for nullptr in the first argument. bool success = LoadMultiDexFilesFromOatFile(open_oat_file.get(), dex_location, dex_location_checksum_pointer, false, error_msgs, dex_files); if (success) { // 我们没有有效的oat文件,所以不会走到这里 } else { if (needs_registering) { // We opened it, delete it. open_oat_file.reset(); } else { open_oat_file.release(); // Do not delete open oat files. } }
// 4) If it's not the case (either no oat file or mismatches), regenerate and load.
// Look in cache location if no oat_location is given. std::string cache_location; if (oat_location == nullptr) { // Use the dalvik cache. conststd::stringdalvik_cache(GetDalvikCacheOrDie(GetInstructionSetString(kRuntimeISA))); cache_location = GetDalvikCacheFilenameOrDie(dex_location, dalvik_cache.c_str()); oat_location = cache_location.c_str(); }
bool has_flock = true; // Definitely need to lock now. if (!scoped_flock.HasFile()) { std::string error_msg; if (!scoped_flock.Init(oat_location, &error_msg)) { error_msgs->push_back(error_msg); has_flock = false; } }
if (Runtime::Current()->IsDex2OatEnabled() && has_flock && scoped_flock.HasFile()) { // Create the oat file. open_oat_file.reset(CreateOatFileForDexLocation(dex_location, scoped_flock.GetFile()->Fd(), oat_location, error_msgs)); }
// Failed, bail. if (open_oat_file.get() == nullptr) { // 如果无法生成oat,那么直接加载dex std::string error_msg; // dex2oat was disabled or crashed. Add the dex file in the list of dex_files to make progress. DexFile::Open(dex_location, dex_location, &error_msg, dex_files); error_msgs->push_back(error_msg); returnfalse; } // 再次尝试加载oat,无关,省略 }
bool has_flock = true; // Definitely need to lock now. if (!scoped_flock.HasFile()) { std::string error_msg; if (!scoped_flock.Init(oat_location, &error_msg)) { error_msgs->push_back(error_msg); has_flock = false; } }
又是scoped_flock,看看在上面scoped_flock可能在哪里被初始化:
1 2 3 4 5 6 7 8 9 10 11 12 13
ScopedFlock scoped_flock; if (open_oat_file.get() == nullptr) { if (oat_location != nullptr) { std::string error_msg;
// We are loading or creating one in the future. Time to set up the file lock. if (!scoped_flock.Init(oat_location, &error_msg)) { error_msgs->push_back(error_msg); returnfalse; } // 省略代码 } }
看看ScopedFlock的Init方法:
1 2 3 4 5 6 7 8 9 10
bool ScopedFlock::Init(constchar* filename, std::string* error_msg) { while (true) { file_.reset(OS::OpenFileWithFlags(filename, O_CREAT | O_RDWR)); if (file_.get() == NULL) { *error_msg = StringPrintf("Failed to open file '%s': %s", filename, strerror(errno)); returnfalse; } // 省略一大堆代码…… } }
privatestaticnativelongopenDexFileNative(String sourceName, String outputName, int flags);
如果是PathClassLoader,outputName为null,会进入这个if分支中:
1 2 3 4 5 6 7 8
// Look in cache location if no oat_location is given. std::string cache_location; if (oat_location == nullptr) { // Use the dalvik cache. conststd::stringdalvik_cache(GetDalvikCacheOrDie(GetInstructionSetString(kRuntimeISA))); cache_location = GetDalvikCacheFilenameOrDie(dex_location, dalvik_cache.c_str()); oat_location = cache_location.c_str(); }
if (open_oat_file.get() == nullptr) { std::string error_msg; // dex2oat was disabled or crashed. Add the dex file in the list of dex_files to make progress. DexFile::Open(dex_location, dex_location, &error_msg, dex_files); error_msgs->push_back(error_msg); returnfalse; }