summaryrefslogtreecommitdiff
path: root/runtime/class_linker.cc
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/class_linker.cc')
-rw-r--r--runtime/class_linker.cc364
1 files changed, 270 insertions, 94 deletions
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 61f94d4cbf..60453c3cc1 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -634,15 +634,22 @@ OatFile& ClassLinker::GetImageOatFile(gc::space::ImageSpace* space) {
const OatFile* ClassLinker::FindOpenedOatFileForDexFile(const DexFile& dex_file) {
const char* dex_location = dex_file.GetLocation().c_str();
uint32_t dex_location_checksum = dex_file.GetLocationChecksum();
- return FindOpenedOatFileFromDexLocation(dex_location, &dex_location_checksum);
+ return FindOpenedOatFile(nullptr, dex_location, &dex_location_checksum);
}
-const OatFile* ClassLinker::FindOpenedOatFileFromDexLocation(
- const char* dex_location, const uint32_t* const dex_location_checksum) {
+const OatFile* ClassLinker::FindOpenedOatFile(const char* oat_location, const char* dex_location,
+ const uint32_t* const dex_location_checksum) {
ReaderMutexLock mu(Thread::Current(), dex_lock_);
for (size_t i = 0; i < oat_files_.size(); i++) {
const OatFile* oat_file = oat_files_[i];
DCHECK(oat_file != NULL);
+
+ if (oat_location != nullptr) {
+ if (oat_file->GetLocation() != oat_location) {
+ continue;
+ }
+ }
+
const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_location,
dex_location_checksum,
false);
@@ -653,10 +660,229 @@ const OatFile* ClassLinker::FindOpenedOatFileFromDexLocation(
return NULL;
}
-const DexFile* ClassLinker::FindDexFileInOatLocation(const char* dex_location,
- uint32_t dex_location_checksum,
- const char* oat_location,
- std::string* error_msg) {
+static std::string GetMultiDexClassesDexName(size_t number, const char* dex_location) {
+ if (number == 0) {
+ return dex_location;
+ } else {
+ return StringPrintf("%s" kMultiDexSeparatorString "classes%zu.dex", dex_location, number + 1);
+ }
+}
+
+static bool LoadMultiDexFilesFromOatFile(const OatFile* oat_file, const char* dex_location,
+ bool generated,
+ std::vector<std::string>* error_msgs,
+ std::vector<const DexFile*>* dex_files) {
+ if (oat_file == nullptr) {
+ return false;
+ }
+
+ size_t old_size = dex_files->size(); // To rollback on error.
+
+ bool success = true;
+ for (size_t i = 0; success; ++i) {
+ std::string next_name_str = GetMultiDexClassesDexName(i, dex_location);
+ const char* next_name = next_name_str.c_str();
+
+ uint32_t dex_location_checksum;
+ uint32_t* dex_location_checksum_pointer = &dex_location_checksum;
+ std::string error_msg;
+ if (!DexFile::GetChecksum(next_name, dex_location_checksum_pointer, &error_msg)) {
+ DCHECK_EQ(false, i == 0 && generated);
+ dex_location_checksum_pointer = nullptr;
+ }
+
+ const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(next_name, nullptr, false);
+
+ if (oat_dex_file == nullptr) {
+ if (i == 0 && generated) {
+ std::string error_msg;
+ error_msg = StringPrintf("\nFailed to find dex file '%s' (checksum 0x%x) in generated out "
+ " file'%s'", dex_location, dex_location_checksum,
+ oat_file->GetLocation().c_str());
+ error_msgs->push_back(error_msg);
+ }
+ break; // Not found, done.
+ }
+
+ // Checksum test. Test must succeed when generated.
+ success = !generated;
+ if (dex_location_checksum_pointer != nullptr) {
+ success = dex_location_checksum == oat_dex_file->GetDexFileLocationChecksum();
+ }
+
+ if (success) {
+ const DexFile* dex_file = oat_dex_file->OpenDexFile(&error_msg);
+ if (dex_file == nullptr) {
+ success = false;
+ error_msgs->push_back(error_msg);
+ } else {
+ dex_files->push_back(dex_file);
+ }
+ }
+
+ // When we generated the file, we expect success, or something is terribly wrong.
+ CHECK_EQ(false, generated && !success)
+ << "dex_location=" << next_name << " oat_location=" << oat_file->GetLocation().c_str()
+ << std::hex << " dex_location_checksum=" << dex_location_checksum
+ << " OatDexFile::GetLocationChecksum()=" << oat_dex_file->GetDexFileLocationChecksum();
+ }
+
+ if (dex_files->size() == old_size) {
+ success = false; // We did not even find classes.dex
+ }
+
+ if (success) {
+ return true;
+ } else {
+ // Free all the dex files we have loaded.
+ auto it = dex_files->begin() + old_size;
+ auto it_end = dex_files->end();
+ for (; it != it_end; it++) {
+ delete *it;
+ }
+ dex_files->erase(dex_files->begin() + old_size, it_end);
+
+ return false;
+ }
+}
+
+// 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(const char* dex_location, const char* 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.
+ uint32_t dex_location_checksum;
+ uint32_t* dex_location_checksum_pointer = &dex_location_checksum;
+ bool have_checksum = true;
+ std::string checksum_error_msg;
+ if (!DexFile::GetChecksum(dex_location, dex_location_checksum_pointer, &checksum_error_msg)) {
+ dex_location_checksum_pointer = nullptr;
+ have_checksum = false;
+ }
+
+ bool needs_registering = false;
+
+ std::unique_ptr<const OatFile> open_oat_file(FindOpenedOatFile(oat_location, dex_location,
+ dex_location_checksum_pointer));
+
+ // 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) {
+ // Can only do this if we have a checksum, else error.
+ if (!have_checksum) {
+ error_msgs->push_back(checksum_error_msg);
+ return false;
+ }
+
+ 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);
+ return false;
+ }
+
+ 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?
+ open_oat_file.reset(FindOatFileContainingDexFileFromDexLocation(dex_location,
+ dex_location_checksum_pointer,
+ kRuntimeISA, error_msgs));
+ }
+ 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, false, error_msgs,
+ dex_files);
+ if (success) {
+ const OatFile* oat_file = open_oat_file.release(); // Avoid deleting it.
+ if (needs_registering) {
+ // We opened the oat file, so we must register it.
+ RegisterOatFile(oat_file);
+ }
+ return true;
+ } 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.
+
+ // Need a checksum, fail else.
+ if (!have_checksum) {
+ error_msgs->push_back(checksum_error_msg);
+ return false;
+ }
+
+ // Look in cache location if no oat_location is given.
+ std::string cache_location;
+ if (oat_location == nullptr) {
+ // Use the dalvik cache.
+ const std::string dalvik_cache(GetDalvikCacheOrDie(GetInstructionSetString(kRuntimeISA)));
+ cache_location = GetDalvikCacheFilenameOrDie(dex_location, dalvik_cache.c_str());
+ oat_location = cache_location.c_str();
+ }
+
+ // 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);
+ return false;
+ }
+ }
+
+ // 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) {
+ return false;
+ }
+
+ // Try to load again, but stronger checks.
+ success = LoadMultiDexFilesFromOatFile(open_oat_file.get(), dex_location, true, error_msgs,
+ dex_files);
+ if (success) {
+ RegisterOatFile(open_oat_file.release());
+ return true;
+ } else {
+ return false;
+ }
+}
+
+const OatFile* ClassLinker::FindOatFileInOatLocationForDexFile(const char* dex_location,
+ uint32_t dex_location_checksum,
+ const char* oat_location,
+ std::string* error_msg) {
std::unique_ptr<OatFile> oat_file(OatFile::Open(oat_location, oat_location, NULL,
!Runtime::Current()->IsCompiler(),
error_msg));
@@ -699,44 +925,21 @@ const DexFile* ClassLinker::FindDexFileInOatLocation(const char* dex_location,
actual_dex_checksum);
return nullptr;
}
- const DexFile* dex_file = oat_dex_file->OpenDexFile(error_msg);
- if (dex_file != nullptr) {
- RegisterOatFile(oat_file.release());
- }
- return dex_file;
-}
-
-const DexFile* ClassLinker::FindOrCreateOatFileForDexLocation(
- const char* dex_location,
- uint32_t dex_location_checksum,
- const char* oat_location,
- std::vector<std::string>* error_msgs) {
- // We play a locking game here so that if two different processes
- // race to 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;
- std::string error_msg;
- if (!scoped_flock.Init(oat_location, &error_msg)) {
- error_msgs->push_back(error_msg);
+ std::unique_ptr<const DexFile> dex_file(oat_dex_file->OpenDexFile(error_msg));
+ if (dex_file.get() != nullptr) {
+ return oat_file.release();
+ } else {
return nullptr;
}
+}
- // Check if we already have an up-to-date output file
- const DexFile* dex_file = FindDexFileInOatLocation(dex_location, dex_location_checksum,
- oat_location, &error_msg);
- if (dex_file != nullptr) {
- return dex_file;
- }
- 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);
-
+const OatFile* ClassLinker::CreateOatFileForDexLocation(const char* dex_location,
+ int fd, const char* oat_location,
+ std::vector<std::string>* error_msgs) {
// Generate the output oat file for the dex file
VLOG(class_linker) << "Generating oat file " << oat_location << " for " << dex_location;
- if (!GenerateOatFile(dex_location, scoped_flock.GetFile()->Fd(), oat_location, &error_msg)) {
+ std::string error_msg;
+ if (!GenerateOatFile(dex_location, fd, oat_location, &error_msg)) {
CHECK(!error_msg.empty());
error_msgs->push_back(error_msg);
return nullptr;
@@ -745,27 +948,13 @@ const DexFile* ClassLinker::FindOrCreateOatFileForDexLocation(
!Runtime::Current()->IsCompiler(),
&error_msg));
if (oat_file.get() == nullptr) {
- compound_msg = StringPrintf("\nFailed to open generated oat file '%s': %s",
- oat_location, error_msg.c_str());
+ std::string compound_msg = StringPrintf("\nFailed to open generated oat file '%s': %s",
+ oat_location, error_msg.c_str());
error_msgs->push_back(compound_msg);
return nullptr;
}
- const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_location,
- &dex_location_checksum);
- if (oat_dex_file == nullptr) {
- error_msg = StringPrintf("\nFailed to find dex file '%s' (checksum 0x%x) in generated out file "
- "'%s'", dex_location, dex_location_checksum, oat_location);
- error_msgs->push_back(error_msg);
- return nullptr;
- }
- const DexFile* result = oat_dex_file->OpenDexFile(&error_msg);
- CHECK(result != nullptr) << error_msgs << ", " << error_msg;
- CHECK_EQ(dex_location_checksum, result->GetLocationChecksum())
- << "dex_location=" << dex_location << " oat_location=" << oat_location << std::hex
- << " dex_location_checksum=" << dex_location_checksum
- << " DexFile::GetLocationChecksum()=" << result->GetLocationChecksum();
- RegisterOatFile(oat_file.release());
- return result;
+
+ return oat_file.release();
}
bool ClassLinker::VerifyOatFileChecksums(const OatFile* oat_file,
@@ -832,17 +1021,17 @@ bool ClassLinker::VerifyOatFileChecksums(const OatFile* oat_file,
return false;
}
-const DexFile* ClassLinker::VerifyAndOpenDexFileFromOatFile(const std::string& oat_file_location,
- const char* dex_location,
- std::string* error_msg,
- bool* open_failed) {
+const OatFile* ClassLinker::LoadOatFileAndVerifyDexFile(const std::string& oat_file_location,
+ const char* dex_location,
+ std::string* error_msg,
+ bool* open_failed) {
std::unique_ptr<const OatFile> oat_file(FindOatFileFromOatLocation(oat_file_location, error_msg));
if (oat_file.get() == nullptr) {
*open_failed = true;
return nullptr;
}
*open_failed = false;
- const DexFile* dex_file = nullptr;
+ std::unique_ptr<const DexFile> dex_file;
uint32_t dex_location_checksum;
if (!DexFile::GetChecksum(dex_location, &dex_location_checksum, error_msg)) {
// If no classes.dex found in dex_location, it has been stripped or is corrupt, assume oat is
@@ -855,49 +1044,38 @@ const DexFile* ClassLinker::VerifyAndOpenDexFileFromOatFile(const std::string& o
error_msg->c_str());
return nullptr;
}
- dex_file = oat_dex_file->OpenDexFile(error_msg);
+ dex_file.reset(oat_dex_file->OpenDexFile(error_msg));
} else {
bool verified = VerifyOatFileChecksums(oat_file.get(), dex_location, dex_location_checksum,
kRuntimeISA, error_msg);
if (!verified) {
return nullptr;
}
- dex_file = oat_file->GetOatDexFile(dex_location,
- &dex_location_checksum)->OpenDexFile(error_msg);
+ dex_file.reset(oat_file->GetOatDexFile(dex_location,
+ &dex_location_checksum)->OpenDexFile(error_msg));
}
- if (dex_file != nullptr) {
- RegisterOatFile(oat_file.release());
+
+ if (dex_file.get() != nullptr) {
+ return oat_file.release();
+ } else {
+ return nullptr;
}
- return dex_file;
}
-const DexFile* ClassLinker::FindDexFileInOatFileFromDexLocation(
+const OatFile* ClassLinker::FindOatFileContainingDexFileFromDexLocation(
const char* dex_location,
const uint32_t* const dex_location_checksum,
InstructionSet isa,
std::vector<std::string>* error_msgs) {
- const OatFile* open_oat_file = FindOpenedOatFileFromDexLocation(dex_location,
- dex_location_checksum);
- if (open_oat_file != nullptr) {
- const OatFile::OatDexFile* oat_dex_file = open_oat_file->GetOatDexFile(dex_location,
- dex_location_checksum);
- std::string error_msg;
- const DexFile* ret = oat_dex_file->OpenDexFile(&error_msg);
- if (ret == nullptr) {
- error_msgs->push_back(error_msg);
- }
- return ret;
- }
-
// Look for an existing file next to dex. for example, for
// /foo/bar/baz.jar, look for /foo/bar/<isa>/baz.odex.
std::string odex_filename(DexFilenameToOdexFilename(dex_location, isa));
bool open_failed;
std::string error_msg;
- const DexFile* dex_file = VerifyAndOpenDexFileFromOatFile(odex_filename, dex_location,
- &error_msg, &open_failed);
- if (dex_file != nullptr) {
- return dex_file;
+ const OatFile* oat_file = LoadOatFileAndVerifyDexFile(odex_filename, dex_location, &error_msg,
+ &open_failed);
+ if (oat_file != nullptr) {
+ return oat_file;
}
if (dex_location_checksum == nullptr) {
error_msgs->push_back(StringPrintf("Failed to open oat file from %s and no classes.dex found in"
@@ -910,10 +1088,10 @@ const DexFile* ClassLinker::FindDexFileInOatFileFromDexLocation(
const std::string dalvik_cache(GetDalvikCacheOrDie(GetInstructionSetString(kRuntimeISA)));
std::string cache_location(GetDalvikCacheFilenameOrDie(dex_location,
dalvik_cache.c_str()));
- dex_file = VerifyAndOpenDexFileFromOatFile(cache_location, dex_location, &cache_error_msg,
- &open_failed);
- if (dex_file != nullptr) {
- return dex_file;
+ oat_file = LoadOatFileAndVerifyDexFile(cache_location, dex_location, &cache_error_msg,
+ &open_failed);
+ if (oat_file != nullptr) {
+ return oat_file;
}
if (!open_failed && TEMP_FAILURE_RETRY(unlink(cache_location.c_str())) != 0) {
PLOG(FATAL) << "Failed to remove obsolete oat file from " << cache_location;
@@ -924,9 +1102,7 @@ const DexFile* ClassLinker::FindDexFileInOatFileFromDexLocation(
VLOG(class_linker) << compound_msg;
error_msgs->push_back(compound_msg);
- // Try to generate oat file if it wasn't found or was obsolete.
- return FindOrCreateOatFileForDexLocation(dex_location, *dex_location_checksum,
- cache_location.c_str(), error_msgs);
+ return nullptr;
}
const OatFile* ClassLinker::FindOpenedOatFileFromOatLocation(const std::string& oat_location) {