summaryrefslogtreecommitdiffstats
path: root/runtime
diff options
context:
space:
mode:
Diffstat (limited to 'runtime')
-rw-r--r--runtime/base/scoped_flock.cc4
-rw-r--r--runtime/base/scoped_flock.h4
-rw-r--r--runtime/class_linker.cc364
-rw-r--r--runtime/class_linker.h67
-rw-r--r--runtime/common_runtime_test.h58
-rw-r--r--runtime/dex_file.cc124
-rw-r--r--runtime/dex_file.h50
-rw-r--r--runtime/dex_file_test.cc7
-rw-r--r--runtime/dex_file_verifier_test.cc19
-rw-r--r--runtime/dex_method_iterator_test.cc19
-rw-r--r--runtime/native/dalvik_system_DexFile.cc135
-rw-r--r--runtime/utils.cc1
-rw-r--r--runtime/utils.h1
13 files changed, 610 insertions, 243 deletions
diff --git a/runtime/base/scoped_flock.cc b/runtime/base/scoped_flock.cc
index c0bce84..351de3d 100644
--- a/runtime/base/scoped_flock.cc
+++ b/runtime/base/scoped_flock.cc
@@ -63,6 +63,10 @@ File* ScopedFlock::GetFile() {
return file_.get();
}
+bool ScopedFlock::HasFile() {
+ return file_.get() != nullptr;
+}
+
ScopedFlock::ScopedFlock() { }
ScopedFlock::~ScopedFlock() {
diff --git a/runtime/base/scoped_flock.h b/runtime/base/scoped_flock.h
index 26b4eb0..f8ed805 100644
--- a/runtime/base/scoped_flock.h
+++ b/runtime/base/scoped_flock.h
@@ -40,6 +40,10 @@ class ScopedFlock {
// Returns the (locked) file associated with this instance.
File* GetFile();
+
+ // Returns whether a file is held.
+ bool HasFile();
+
~ScopedFlock();
private:
std::unique_ptr<File> file_;
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 61f94d4..60453c3 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) {
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 7d7bf15..60dad7b 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -273,23 +273,12 @@ class ClassLinker {
std::string* error_msg)
LOCKS_EXCLUDED(dex_lock_);
- // Finds the oat file for a dex location, generating the oat file if
- // it is missing or out of date. Returns the DexFile from within the
- // created oat file.
- const DexFile* FindOrCreateOatFileForDexLocation(const char* dex_location,
- uint32_t dex_location_checksum,
- const char* oat_location,
- std::vector<std::string>* error_msgs)
+ // Find or create the oat file holding dex_location. Then load all corresponding dex files
+ // (if multidex) into the given vector.
+ bool OpenDexFilesFromOat(const char* dex_location, const char* oat_location,
+ std::vector<std::string>* error_msgs,
+ std::vector<const DexFile*>* dex_files)
LOCKS_EXCLUDED(dex_lock_, Locks::mutator_lock_);
- // Find a DexFile within an OatFile given a DexFile location. Note
- // that this returns null if the location checksum of the DexFile
- // does not match the OatFile.
- const DexFile* FindDexFileInOatFileFromDexLocation(const char* location,
- const uint32_t* const location_checksum,
- InstructionSet isa,
- std::vector<std::string>* error_msgs)
- LOCKS_EXCLUDED(dex_lock_, Locks::mutator_lock_);
-
// Returns true if oat file contains the dex file with the given location and checksum.
static bool VerifyOatFileChecksums(const OatFile* oat_file,
@@ -545,21 +534,47 @@ class ClassLinker {
const OatFile* FindOpenedOatFileForDexFile(const DexFile& dex_file)
LOCKS_EXCLUDED(dex_lock_)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- const OatFile* FindOpenedOatFileFromDexLocation(const char* dex_location,
- const uint32_t* const dex_location_checksum)
+
+ // Find an opened oat file that contains dex_location. If oat_location is not nullptr, the file
+ // must have that location, else any oat location is accepted.
+ const OatFile* FindOpenedOatFile(const char* oat_location, const char* dex_location,
+ const uint32_t* const dex_location_checksum)
LOCKS_EXCLUDED(dex_lock_);
const OatFile* FindOpenedOatFileFromOatLocation(const std::string& oat_location)
LOCKS_EXCLUDED(dex_lock_);
- const DexFile* FindDexFileInOatLocation(const char* dex_location,
- uint32_t dex_location_checksum,
- const char* oat_location,
- std::string* error_msg)
+
+ // Note: will not register the oat file.
+ const OatFile* FindOatFileInOatLocationForDexFile(const char* dex_location,
+ uint32_t dex_location_checksum,
+ const char* oat_location,
+ std::string* error_msg)
LOCKS_EXCLUDED(dex_lock_);
- const DexFile* VerifyAndOpenDexFileFromOatFile(const std::string& oat_file_location,
- const char* dex_location,
- std::string* error_msg,
- bool* open_failed)
+ // Creates the oat file from the dex_location to the oat_location. Needs a file descriptor for
+ // the file to be written, which is assumed to be under a lock.
+ const OatFile* CreateOatFileForDexLocation(const char* dex_location,
+ int fd, const char* oat_location,
+ std::vector<std::string>* error_msgs)
+ LOCKS_EXCLUDED(dex_lock_, Locks::mutator_lock_);
+
+ // Finds an OatFile that contains a DexFile for the given a DexFile location.
+ //
+ // Note 1: this will not check open oat files, which are assumed to be stale when this is run.
+ // Note 2: Does not register the oat file. It is the caller's job to register if the file is to
+ // be kept.
+ const OatFile* FindOatFileContainingDexFileFromDexLocation(const char* location,
+ const uint32_t* const location_checksum,
+ InstructionSet isa,
+ std::vector<std::string>* error_msgs)
+ LOCKS_EXCLUDED(dex_lock_, Locks::mutator_lock_);
+
+ // Find a verify an oat file with the given dex file. Will return nullptr when the oat file
+ // was not found or the dex file could not be verified.
+ // Note: Does not register the oat file.
+ const OatFile* LoadOatFileAndVerifyDexFile(const std::string& oat_file_location,
+ const char* dex_location,
+ std::string* error_msg,
+ bool* open_failed)
LOCKS_EXCLUDED(dex_lock_);
mirror::ArtMethod* CreateProxyConstructor(Thread* self, Handle<mirror::Class> klass,
diff --git a/runtime/common_runtime_test.h b/runtime/common_runtime_test.h
index 044d08b..1df4c05 100644
--- a/runtime/common_runtime_test.h
+++ b/runtime/common_runtime_test.h
@@ -156,6 +156,18 @@ class CommonRuntimeTest : public testing::Test {
return !kIsTargetBuild;
}
+ const DexFile* LoadExpectSingleDexFile(const char* location) {
+ std::vector<const DexFile*> dex_files;
+ std::string error_msg;
+ if (!DexFile::Open(location, location, &error_msg, &dex_files)) {
+ LOG(FATAL) << "Could not open .dex file '" << location << "': " << error_msg << "\n";
+ return nullptr;
+ } else {
+ CHECK_EQ(1U, dex_files.size()) << "Expected only one dex file in " << location;
+ return dex_files[0];
+ }
+ }
+
virtual void SetUp() {
SetEnvironmentVariables(android_data_);
dalvik_cache_.append(android_data_.c_str());
@@ -164,12 +176,7 @@ class CommonRuntimeTest : public testing::Test {
ASSERT_EQ(mkdir_result, 0);
std::string error_msg;
- java_lang_dex_file_ = DexFile::Open(GetLibCoreDexFileName().c_str(),
- GetLibCoreDexFileName().c_str(), &error_msg);
- if (java_lang_dex_file_ == nullptr) {
- LOG(FATAL) << "Could not open .dex file '" << GetLibCoreDexFileName() << "': "
- << error_msg << "\n";
- }
+ java_lang_dex_file_ = LoadExpectSingleDexFile(GetLibCoreDexFileName().c_str());
boot_class_path_.push_back(java_lang_dex_file_);
std::string min_heap_string(StringPrintf("-Xms%zdm", gc::Heap::kDefaultInitialSize / MB));
@@ -233,7 +240,7 @@ class CommonRuntimeTest : public testing::Test {
// There's a function to clear the array, but it's not public...
typedef void (*IcuCleanupFn)();
void* sym = dlsym(RTLD_DEFAULT, "u_cleanup_" U_ICU_VERSION_SHORT);
- CHECK(sym != nullptr);
+ CHECK(sym != nullptr) << dlerror();
IcuCleanupFn icu_cleanup_fn = reinterpret_cast<IcuCleanupFn>(sym);
(*icu_cleanup_fn)();
@@ -264,7 +271,8 @@ class CommonRuntimeTest : public testing::Test {
return GetAndroidRoot();
}
- const DexFile* OpenTestDexFile(const char* name) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ std::vector<const DexFile*> OpenTestDexFiles(const char* name)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
CHECK(name != nullptr);
std::string filename;
if (IsHost()) {
@@ -277,26 +285,36 @@ class CommonRuntimeTest : public testing::Test {
filename += name;
filename += ".jar";
std::string error_msg;
- const DexFile* dex_file = DexFile::Open(filename.c_str(), filename.c_str(), &error_msg);
- CHECK(dex_file != nullptr) << "Failed to open '" << filename << "': " << error_msg;
- CHECK_EQ(PROT_READ, dex_file->GetPermissions());
- CHECK(dex_file->IsReadOnly());
- opened_dex_files_.push_back(dex_file);
- return dex_file;
+ std::vector<const DexFile*> dex_files;
+ bool success = DexFile::Open(filename.c_str(), filename.c_str(), &error_msg, &dex_files);
+ CHECK(success) << "Failed to open '" << filename << "': " << error_msg;
+ for (const DexFile* dex_file : dex_files) {
+ CHECK_EQ(PROT_READ, dex_file->GetPermissions());
+ CHECK(dex_file->IsReadOnly());
+ }
+ opened_dex_files_.insert(opened_dex_files_.end(), dex_files.begin(), dex_files.end());
+ return dex_files;
+ }
+
+ const DexFile* OpenTestDexFile(const char* name)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ std::vector<const DexFile*> vector = OpenTestDexFiles(name);
+ EXPECT_EQ(1U, vector.size());
+ return vector[0];
}
jobject LoadDex(const char* dex_name) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- const DexFile* dex_file = OpenTestDexFile(dex_name);
- CHECK(dex_file != nullptr);
- class_linker_->RegisterDexFile(*dex_file);
- std::vector<const DexFile*> class_path;
- class_path.push_back(dex_file);
+ std::vector<const DexFile*> dex_files = OpenTestDexFiles(dex_name);
+ CHECK_NE(0U, dex_files.size());
+ for (const DexFile* dex_file : dex_files) {
+ class_linker_->RegisterDexFile(*dex_file);
+ }
ScopedObjectAccessUnchecked soa(Thread::Current());
ScopedLocalRef<jobject> class_loader_local(soa.Env(),
soa.Env()->AllocObject(WellKnownClasses::dalvik_system_PathClassLoader));
jobject class_loader = soa.Env()->NewGlobalRef(class_loader_local.get());
soa.Self()->SetClassLoaderOverride(soa.Decode<mirror::ClassLoader*>(class_loader_local.get()));
- Runtime::Current()->SetCompileTimeClassPath(class_loader, class_path);
+ Runtime::Current()->SetCompileTimeClassPath(class_loader, dex_files);
return class_loader;
}
diff --git a/runtime/dex_file.cc b/runtime/dex_file.cc
index 10f34d9..d368e41 100644
--- a/runtime/dex_file.cc
+++ b/runtime/dex_file.cc
@@ -87,7 +87,21 @@ static int OpenAndReadMagic(const char* filename, uint32_t* magic, std::string*
bool DexFile::GetChecksum(const char* filename, uint32_t* checksum, std::string* error_msg) {
CHECK(checksum != NULL);
uint32_t magic;
- ScopedFd fd(OpenAndReadMagic(filename, &magic, error_msg));
+
+ // Strip ":...", which is the location
+ const char* zip_entry_name = kClassesDex;
+ const char* file_part = filename;
+ std::unique_ptr<const char> file_part_ptr;
+
+
+ if (IsMultiDexLocation(filename)) {
+ std::pair<const char*, const char*> pair = SplitMultiDexLocation(filename);
+ file_part_ptr.reset(pair.first);
+ file_part = pair.first;
+ zip_entry_name = pair.second;
+ }
+
+ ScopedFd fd(OpenAndReadMagic(file_part, &magic, error_msg));
if (fd.get() == -1) {
DCHECK(!error_msg->empty());
return false;
@@ -95,13 +109,13 @@ bool DexFile::GetChecksum(const char* filename, uint32_t* checksum, std::string*
if (IsZipMagic(magic)) {
std::unique_ptr<ZipArchive> zip_archive(ZipArchive::OpenFromFd(fd.release(), filename, error_msg));
if (zip_archive.get() == NULL) {
- *error_msg = StringPrintf("Failed to open zip archive '%s'", filename);
+ *error_msg = StringPrintf("Failed to open zip archive '%s'", file_part);
return false;
}
- std::unique_ptr<ZipEntry> zip_entry(zip_archive->Find(kClassesDex, error_msg));
+ std::unique_ptr<ZipEntry> zip_entry(zip_archive->Find(zip_entry_name, error_msg));
if (zip_entry.get() == NULL) {
- *error_msg = StringPrintf("Zip archive '%s' doesn't contain %s (error msg: %s)", filename,
- kClassesDex, error_msg->c_str());
+ *error_msg = StringPrintf("Zip archive '%s' doesn't contain %s (error msg: %s)", file_part,
+ zip_entry_name, error_msg->c_str());
return false;
}
*checksum = zip_entry->GetCrc32();
@@ -119,20 +133,26 @@ bool DexFile::GetChecksum(const char* filename, uint32_t* checksum, std::string*
return false;
}
-const DexFile* DexFile::Open(const char* filename,
- const char* location,
- std::string* error_msg) {
+bool DexFile::Open(const char* filename, const char* location, std::string* error_msg,
+ std::vector<const DexFile*>* dex_files) {
uint32_t magic;
ScopedFd fd(OpenAndReadMagic(filename, &magic, error_msg));
if (fd.get() == -1) {
DCHECK(!error_msg->empty());
- return NULL;
+ return false;
}
if (IsZipMagic(magic)) {
- return DexFile::OpenZip(fd.release(), location, error_msg);
+ return DexFile::OpenZip(fd.release(), location, error_msg, dex_files);
}
if (IsDexMagic(magic)) {
- return DexFile::OpenFile(fd.release(), location, true, error_msg);
+ std::unique_ptr<const DexFile> dex_file(DexFile::OpenFile(fd.release(), location, true,
+ error_msg));
+ if (dex_file.get() != nullptr) {
+ dex_files->push_back(dex_file.release());
+ return true;
+ } else {
+ return false;
+ }
}
*error_msg = StringPrintf("Expected valid zip or dex file: '%s'", filename);
return nullptr;
@@ -217,13 +237,14 @@ const DexFile* DexFile::OpenFile(int fd, const char* location, bool verify,
const char* DexFile::kClassesDex = "classes.dex";
-const DexFile* DexFile::OpenZip(int fd, const std::string& location, std::string* error_msg) {
+bool DexFile::OpenZip(int fd, const std::string& location, std::string* error_msg,
+ std::vector<const DexFile*>* dex_files) {
std::unique_ptr<ZipArchive> zip_archive(ZipArchive::OpenFromFd(fd, location.c_str(), error_msg));
if (zip_archive.get() == nullptr) {
DCHECK(!error_msg->empty());
- return nullptr;
+ return false;
}
- return DexFile::Open(*zip_archive, location, error_msg);
+ return DexFile::OpenFromZip(*zip_archive, location, error_msg, dex_files);
}
const DexFile* DexFile::OpenMemory(const std::string& location,
@@ -238,17 +259,20 @@ const DexFile* DexFile::OpenMemory(const std::string& location,
error_msg);
}
-const DexFile* DexFile::Open(const ZipArchive& zip_archive, const std::string& location,
- std::string* error_msg) {
+const DexFile* DexFile::Open(const ZipArchive& zip_archive, const char* entry_name,
+ const std::string& location, std::string* error_msg,
+ ZipOpenErrorCode* error_code) {
CHECK(!location.empty());
- std::unique_ptr<ZipEntry> zip_entry(zip_archive.Find(kClassesDex, error_msg));
+ std::unique_ptr<ZipEntry> zip_entry(zip_archive.Find(entry_name, error_msg));
if (zip_entry.get() == NULL) {
+ *error_code = ZipOpenErrorCode::kEntryNotFound;
return nullptr;
}
- std::unique_ptr<MemMap> map(zip_entry->ExtractToMemMap(location.c_str(), kClassesDex, error_msg));
+ std::unique_ptr<MemMap> map(zip_entry->ExtractToMemMap(location.c_str(), entry_name, error_msg));
if (map.get() == NULL) {
- *error_msg = StringPrintf("Failed to extract '%s' from '%s': %s", kClassesDex, location.c_str(),
+ *error_msg = StringPrintf("Failed to extract '%s' from '%s': %s", entry_name, location.c_str(),
error_msg->c_str());
+ *error_code = ZipOpenErrorCode::kExtractToMemoryError;
return nullptr;
}
std::unique_ptr<const DexFile> dex_file(OpenMemory(location, zip_entry->GetCrc32(), map.release(),
@@ -256,20 +280,63 @@ const DexFile* DexFile::Open(const ZipArchive& zip_archive, const std::string& l
if (dex_file.get() == nullptr) {
*error_msg = StringPrintf("Failed to open dex file '%s' from memory: %s", location.c_str(),
error_msg->c_str());
+ *error_code = ZipOpenErrorCode::kDexFileError;
return nullptr;
}
if (!dex_file->DisableWrite()) {
*error_msg = StringPrintf("Failed to make dex file '%s' read only", location.c_str());
+ *error_code = ZipOpenErrorCode::kMakeReadOnlyError;
return nullptr;
}
CHECK(dex_file->IsReadOnly()) << location;
if (!DexFileVerifier::Verify(dex_file.get(), dex_file->Begin(), dex_file->Size(),
location.c_str(), error_msg)) {
+ *error_code = ZipOpenErrorCode::kVerifyError;
return nullptr;
}
+ *error_code = ZipOpenErrorCode::kNoError;
return dex_file.release();
}
+bool DexFile::OpenFromZip(const ZipArchive& zip_archive, const std::string& location,
+ std::string* error_msg, std::vector<const DexFile*>* dex_files) {
+ ZipOpenErrorCode error_code;
+ std::unique_ptr<const DexFile> dex_file(Open(zip_archive, kClassesDex, location, error_msg,
+ &error_code));
+ if (dex_file.get() == nullptr) {
+ return false;
+ } else {
+ // Had at least classes.dex.
+ dex_files->push_back(dex_file.release());
+
+ // Now try some more.
+ size_t i = 2;
+
+ // We could try to avoid std::string allocations by working on a char array directly. As we
+ // do not expect a lot of iterations, this seems too involved and brittle.
+
+ while (i < 100) {
+ std::string name = StringPrintf("classes%zu.dex", i);
+ std::string fake_location = location + ":" + name;
+ std::unique_ptr<const DexFile> next_dex_file(Open(zip_archive, name.c_str(), fake_location,
+ error_msg, &error_code));
+ if (next_dex_file.get() == nullptr) {
+ if (error_code != ZipOpenErrorCode::kEntryNotFound) {
+ LOG(WARNING) << error_msg;
+ }
+ break;
+ } else {
+ dex_files->push_back(next_dex_file.release());
+ }
+
+ i++;
+ }
+
+ return true;
+ }
+}
+
+
const DexFile* DexFile::OpenMemory(const byte* base,
size_t size,
const std::string& location,
@@ -865,6 +932,25 @@ bool DexFile::LineNumForPcCb(void* raw_context, uint32_t address, uint32_t line_
}
}
+bool DexFile::IsMultiDexLocation(const char* location) {
+ return strrchr(location, kMultiDexSeparator) != nullptr;
+}
+
+std::pair<const char*, const char*> DexFile::SplitMultiDexLocation(
+ const char* location) {
+ const char* colon_ptr = strrchr(location, kMultiDexSeparator);
+
+ // Check it's synthetic.
+ CHECK_NE(colon_ptr, static_cast<const char*>(nullptr));
+
+ size_t colon_index = colon_ptr - location;
+ char* tmp = new char[colon_index + 1];
+ strncpy(tmp, location, colon_index);
+ tmp[colon_index] = 0;
+
+ return std::make_pair(tmp, colon_ptr + 1);
+}
+
std::ostream& operator<<(std::ostream& os, const DexFile& dex_file) {
os << StringPrintf("[DexFile: %s dex-checksum=%08x location-checksum=%08x %p-%p]",
dex_file.GetLocation().c_str(),
diff --git a/runtime/dex_file.h b/runtime/dex_file.h
index 8270a2b..04f1cc1 100644
--- a/runtime/dex_file.h
+++ b/runtime/dex_file.h
@@ -63,6 +63,13 @@ class DexFile {
// The value of an invalid index.
static const uint16_t kDexNoIndex16 = 0xFFFF;
+ // The separator charactor in MultiDex locations.
+ static constexpr char kMultiDexSeparator = ':';
+
+ // A string version of the previous. This is a define so that we can merge string literals in the
+ // preprocessor.
+ #define kMultiDexSeparatorString ":"
+
// Raw header_item.
struct Header {
uint8_t magic_[8];
@@ -352,8 +359,9 @@ class DexFile {
// Return true if the checksum could be found, false otherwise.
static bool GetChecksum(const char* filename, uint32_t* checksum, std::string* error_msg);
- // Opens .dex file, guessing the container format based on file extension
- static const DexFile* Open(const char* filename, const char* location, std::string* error_msg);
+ // Opens .dex files found in the container, guessing the container format based on file extension.
+ static bool Open(const char* filename, const char* location, std::string* error_msg,
+ std::vector<const DexFile*>* dex_files);
// Opens .dex file, backed by existing memory
static const DexFile* Open(const uint8_t* base, size_t size,
@@ -363,9 +371,9 @@ class DexFile {
return OpenMemory(base, size, location, location_checksum, NULL, error_msg);
}
- // Opens .dex file from the classes.dex in a zip archive
- static const DexFile* Open(const ZipArchive& zip_archive, const std::string& location,
- std::string* error_msg);
+ // Open all classesXXX.dex files from a zip archive.
+ static bool OpenFromZip(const ZipArchive& zip_archive, const std::string& location,
+ std::string* error_msg, std::vector<const DexFile*>* dex_files);
// Closes a .dex file.
virtual ~DexFile();
@@ -823,8 +831,24 @@ class DexFile {
// Opens a .dex file
static const DexFile* OpenFile(int fd, const char* location, bool verify, std::string* error_msg);
- // Opens a dex file from within a .jar, .zip, or .apk file
- static const DexFile* OpenZip(int fd, const std::string& location, std::string* error_msg);
+ // Opens dex files from within a .jar, .zip, or .apk file
+ static bool OpenZip(int fd, const std::string& location, std::string* error_msg,
+ std::vector<const DexFile*>* dex_files);
+
+ enum class ZipOpenErrorCode { // private
+ kNoError,
+ kEntryNotFound,
+ kExtractToMemoryError,
+ kDexFileError,
+ kMakeReadOnlyError,
+ kVerifyError
+ };
+
+ // Opens .dex file from the entry_name in a zip archive. error_code is undefined when non-nullptr
+ // return.
+ static const DexFile* Open(const ZipArchive& zip_archive, const char* entry_name,
+ const std::string& location, std::string* error_msg,
+ ZipOpenErrorCode* error_code);
// Opens a .dex file at the given address backed by a MemMap
static const DexFile* OpenMemory(const std::string& location,
@@ -855,6 +879,18 @@ class DexFile {
DexDebugNewPositionCb position_cb, DexDebugNewLocalCb local_cb,
void* context, const byte* stream, LocalInfo* local_in_reg) const;
+ // Check whether a location denotes a multidex dex file. This is a very simple check: returns
+ // whether the string contains the separator character.
+ static bool IsMultiDexLocation(const char* location);
+
+ // Splits a multidex location at the last separator character. The second component is a pointer
+ // to the character after the separator. The first is a copy of the substring up to the separator.
+ //
+ // Note: It's the caller's job to free the first component of the returned pair.
+ // Bug 15313523: gcc/libc++ don't allow a unique_ptr for the first component
+ static std::pair<const char*, const char*> SplitMultiDexLocation(const char* location);
+
+
// The base address of the memory mapping.
const byte* const begin_;
diff --git a/runtime/dex_file_test.cc b/runtime/dex_file_test.cc
index a814c34..c1e00fc 100644
--- a/runtime/dex_file_test.cc
+++ b/runtime/dex_file_test.cc
@@ -146,8 +146,11 @@ static const DexFile* OpenDexFileBase64(const char* base64,
// read dex file
ScopedObjectAccess soa(Thread::Current());
std::string error_msg;
- const DexFile* dex_file = DexFile::Open(location, location, &error_msg);
- CHECK(dex_file != nullptr) << error_msg;
+ std::vector<const DexFile*> tmp;
+ bool success = DexFile::Open(location, location, &error_msg, &tmp);
+ CHECK(success) << error_msg;
+ EXPECT_EQ(1U, tmp.size());
+ const DexFile* dex_file = tmp[0];
EXPECT_EQ(PROT_READ, dex_file->GetPermissions());
EXPECT_TRUE(dex_file->IsReadOnly());
return dex_file;
diff --git a/runtime/dex_file_verifier_test.cc b/runtime/dex_file_verifier_test.cc
index d0ce00f..93faeae 100644
--- a/runtime/dex_file_verifier_test.cc
+++ b/runtime/dex_file_verifier_test.cc
@@ -115,7 +115,14 @@ static const DexFile* OpenDexFileBase64(const char* base64, const char* location
// read dex file
ScopedObjectAccess soa(Thread::Current());
- return DexFile::Open(location, location, error_msg);
+ std::vector<const DexFile*> tmp;
+ bool success = DexFile::Open(location, location, error_msg, &tmp);
+ CHECK(success) << error_msg;
+ EXPECT_EQ(1U, tmp.size());
+ const DexFile* dex_file = tmp[0];
+ EXPECT_EQ(PROT_READ, dex_file->GetPermissions());
+ EXPECT_TRUE(dex_file->IsReadOnly());
+ return dex_file;
}
@@ -170,7 +177,15 @@ static const DexFile* FixChecksumAndOpen(byte* bytes, size_t length, const char*
// read dex file
ScopedObjectAccess soa(Thread::Current());
- return DexFile::Open(location, location, error_msg);
+ std::vector<const DexFile*> tmp;
+ if (!DexFile::Open(location, location, error_msg, &tmp)) {
+ return nullptr;
+ }
+ EXPECT_EQ(1U, tmp.size());
+ const DexFile* dex_file = tmp[0];
+ EXPECT_EQ(PROT_READ, dex_file->GetPermissions());
+ EXPECT_TRUE(dex_file->IsReadOnly());
+ return dex_file;
}
static bool ModifyAndLoad(const char* location, size_t offset, uint8_t new_val,
diff --git a/runtime/dex_method_iterator_test.cc b/runtime/dex_method_iterator_test.cc
index 5e2d89e..0d00cc3 100644
--- a/runtime/dex_method_iterator_test.cc
+++ b/runtime/dex_method_iterator_test.cc
@@ -21,26 +21,15 @@
namespace art {
class DexMethodIteratorTest : public CommonRuntimeTest {
- public:
- const DexFile* OpenDexFile(const std::string& partial_filename) {
- std::string dfn = GetDexFileName(partial_filename);
- std::string error_msg;
- const DexFile* dexfile = DexFile::Open(dfn.c_str(), dfn.c_str(), &error_msg);
- if (dexfile == nullptr) {
- LG << "Failed to open '" << dfn << "': " << error_msg;
- }
- return dexfile;
- }
};
TEST_F(DexMethodIteratorTest, Basic) {
ScopedObjectAccess soa(Thread::Current());
std::vector<const DexFile*> dex_files;
- dex_files.push_back(OpenDexFile("core-libart"));
- dex_files.push_back(OpenDexFile("conscrypt"));
- dex_files.push_back(OpenDexFile("okhttp"));
- dex_files.push_back(OpenDexFile("core-junit"));
- dex_files.push_back(OpenDexFile("bouncycastle"));
+ const char* jars[] = { "core-libart", "conscrypt", "okhttp", "core-junit", "bouncycastle" };
+ for (size_t i = 0; i < 5; ++i) {
+ dex_files.push_back(LoadExpectSingleDexFile(GetDexFileName(jars[i]).c_str()));
+ }
DexMethodIterator it(dex_files);
while (it.HasNext()) {
const DexFile& dex_file = it.GetDexFile();
diff --git a/runtime/native/dalvik_system_DexFile.cc b/runtime/native/dalvik_system_DexFile.cc
index 9512a5a..440d3d0 100644
--- a/runtime/native/dalvik_system_DexFile.cc
+++ b/runtime/native/dalvik_system_DexFile.cc
@@ -26,6 +26,7 @@
#include <unistd.h>
#include "base/logging.h"
+#include "base/stl_util.h"
#include "class_linker.h"
#include "common_throws.h"
#include "dex_file-inl.h"
@@ -106,34 +107,19 @@ static jlong DexFile_openDexFileNative(JNIEnv* env, jclass, jstring javaSourceNa
return 0;
}
- uint32_t dex_location_checksum;
- uint32_t* dex_location_checksum_pointer = &dex_location_checksum;
+ ClassLinker* linker = Runtime::Current()->GetClassLinker();
+ std::unique_ptr<std::vector<const DexFile*>> dex_files(new std::vector<const DexFile*>());
std::vector<std::string> error_msgs;
- std::string error_msg;
- if (!DexFile::GetChecksum(sourceName.c_str(), dex_location_checksum_pointer, &error_msg)) {
- dex_location_checksum_pointer = NULL;
- }
- ClassLinker* linker = Runtime::Current()->GetClassLinker();
- const DexFile* dex_file;
- if (outputName.c_str() == nullptr) {
- // FindOrCreateOatFileForDexLocation can tolerate a missing dex_location_checksum
- dex_file = linker->FindDexFileInOatFileFromDexLocation(sourceName.c_str(),
- dex_location_checksum_pointer,
- kRuntimeISA,
- &error_msgs);
+ bool success = linker->OpenDexFilesFromOat(sourceName.c_str(), outputName.c_str(), &error_msgs,
+ dex_files.get());
+
+ if (success) {
+ return static_cast<jlong>(reinterpret_cast<uintptr_t>(dex_files.release()));
} else {
- // FindOrCreateOatFileForDexLocation requires the dex_location_checksum
- if (dex_location_checksum_pointer == NULL) {
- ScopedObjectAccess soa(env);
- DCHECK(!error_msg.empty());
- ThrowIOException("%s", error_msg.c_str());
- return 0;
- }
- dex_file = linker->FindOrCreateOatFileForDexLocation(sourceName.c_str(), dex_location_checksum,
- outputName.c_str(), &error_msgs);
- }
- if (dex_file == nullptr) {
+ // The vector should be empty after a failed loading attempt.
+ DCHECK_EQ(0U, dex_files->size());
+
ScopedObjectAccess soa(env);
CHECK(!error_msgs.empty());
// The most important message is at the end. So set up nesting by going forward, which will
@@ -146,35 +132,41 @@ static jlong DexFile_openDexFileNative(JNIEnv* env, jclass, jstring javaSourceNa
return 0;
}
- return static_cast<jlong>(reinterpret_cast<uintptr_t>(dex_file));
}
-static const DexFile* toDexFile(jlong dex_file_address, JNIEnv* env) {
- const DexFile* dex_file = reinterpret_cast<const DexFile*>(static_cast<uintptr_t>(dex_file_address));
- if (UNLIKELY(dex_file == nullptr)) {
+static std::vector<const DexFile*>* toDexFiles(jlong dex_file_address, JNIEnv* env) {
+ std::vector<const DexFile*>* dex_files = reinterpret_cast<std::vector<const DexFile*>*>(
+ static_cast<uintptr_t>(dex_file_address));
+ if (UNLIKELY(dex_files == nullptr)) {
ScopedObjectAccess soa(env);
ThrowNullPointerException(NULL, "dex_file == null");
}
- return dex_file;
+ return dex_files;
}
static void DexFile_closeDexFile(JNIEnv* env, jclass, jlong cookie) {
- const DexFile* dex_file;
- dex_file = toDexFile(cookie, env);
- if (dex_file == nullptr) {
+ std::unique_ptr<std::vector<const DexFile*>> dex_files(toDexFiles(cookie, env));
+ if (dex_files.get() == nullptr) {
return;
}
ScopedObjectAccess soa(env);
- if (Runtime::Current()->GetClassLinker()->IsDexFileRegistered(*dex_file)) {
- return;
+
+ size_t index = 0;
+ for (const DexFile* dex_file : *dex_files) {
+ if (Runtime::Current()->GetClassLinker()->IsDexFileRegistered(*dex_file)) {
+ (*dex_files)[index] = nullptr;
+ }
+ index++;
}
- delete dex_file;
+
+ STLDeleteElements(dex_files.get());
+ // Unique_ptr will delete the vector itself.
}
static jclass DexFile_defineClassNative(JNIEnv* env, jclass, jstring javaName, jobject javaLoader,
jlong cookie) {
- const DexFile* dex_file = toDexFile(cookie, env);
- if (dex_file == NULL) {
+ std::vector<const DexFile*>* dex_files = toDexFiles(cookie, env);
+ if (dex_files == NULL) {
VLOG(class_linker) << "Failed to find dex_file";
return NULL;
}
@@ -184,33 +176,60 @@ static jclass DexFile_defineClassNative(JNIEnv* env, jclass, jstring javaName, j
return NULL;
}
const std::string descriptor(DotToDescriptor(class_name.c_str()));
- const DexFile::ClassDef* dex_class_def = dex_file->FindClassDef(descriptor.c_str());
- if (dex_class_def == NULL) {
- VLOG(class_linker) << "Failed to find dex_class_def";
- return NULL;
+
+ for (const DexFile* dex_file : *dex_files) {
+ const DexFile::ClassDef* dex_class_def = dex_file->FindClassDef(descriptor.c_str());
+ if (dex_class_def != nullptr) {
+ ScopedObjectAccess soa(env);
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ class_linker->RegisterDexFile(*dex_file);
+ StackHandleScope<1> hs(soa.Self());
+ Handle<mirror::ClassLoader> class_loader(
+ hs.NewHandle(soa.Decode<mirror::ClassLoader*>(javaLoader)));
+ mirror::Class* result = class_linker->DefineClass(descriptor.c_str(), class_loader, *dex_file,
+ *dex_class_def);
+ if (result != nullptr) {
+ VLOG(class_linker) << "DexFile_defineClassNative returning " << result;
+ return soa.AddLocalReference<jclass>(result);
+ }
+ }
}
- ScopedObjectAccess soa(env);
- ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
- class_linker->RegisterDexFile(*dex_file);
- StackHandleScope<1> hs(soa.Self());
- Handle<mirror::ClassLoader> class_loader(
- hs.NewHandle(soa.Decode<mirror::ClassLoader*>(javaLoader)));
- mirror::Class* result = class_linker->DefineClass(descriptor.c_str(), class_loader, *dex_file,
- *dex_class_def);
- VLOG(class_linker) << "DexFile_defineClassNative returning " << result;
- return soa.AddLocalReference<jclass>(result);
+ VLOG(class_linker) << "Failed to find dex_class_def";
+ return nullptr;
}
+// Needed as a compare functor for sets of const char
+struct CharPointerComparator {
+ bool operator()(const char *str1, const char *str2) const {
+ return strcmp(str1, str2) < 0;
+ }
+};
+
+// Note: this can be an expensive call, as we sort out duplicates in MultiDex files.
static jobjectArray DexFile_getClassNameList(JNIEnv* env, jclass, jlong cookie) {
jobjectArray result = nullptr;
- const DexFile* dex_file = toDexFile(cookie, env);
- if (dex_file != nullptr) {
- result = env->NewObjectArray(dex_file->NumClassDefs(), WellKnownClasses::java_lang_String,
- nullptr);
- if (result != nullptr) {
+ std::vector<const DexFile*>* dex_files = toDexFiles(cookie, env);
+
+ if (dex_files != nullptr) {
+ // Push all class descriptors into a set. Use set instead of unordered_set as we want to
+ // retrieve all in the end.
+ std::set<const char*, CharPointerComparator> descriptors;
+ for (const DexFile* dex_file : *dex_files) {
for (size_t i = 0; i < dex_file->NumClassDefs(); ++i) {
const DexFile::ClassDef& class_def = dex_file->GetClassDef(i);
- std::string descriptor(DescriptorToDot(dex_file->GetClassDescriptor(class_def)));
+ const char* descriptor = dex_file->GetClassDescriptor(class_def);
+ descriptors.insert(descriptor);
+ }
+ }
+
+ // Now create output array and copy the set into it.
+ result = env->NewObjectArray(descriptors.size(), WellKnownClasses::java_lang_String, nullptr);
+ if (result != nullptr) {
+ auto it = descriptors.begin();
+ auto it_end = descriptors.end();
+ jsize i = 0;
+ for (; it != it_end; it++, ++i) {
+ std::string descriptor(DescriptorToDot(*it));
ScopedLocalRef<jstring> jdescriptor(env, env->NewStringUTF(descriptor.c_str()));
if (jdescriptor.get() == nullptr) {
return nullptr;
diff --git a/runtime/utils.cc b/runtime/utils.cc
index e5b8b22..c52549e 100644
--- a/runtime/utils.cc
+++ b/runtime/utils.cc
@@ -1232,6 +1232,7 @@ std::string GetSystemImageFilename(const char* location, const InstructionSet is
std::string DexFilenameToOdexFilename(const std::string& location, const InstructionSet isa) {
// location = /foo/bar/baz.jar
// odex_location = /foo/bar/<isa>/baz.odex
+
CHECK_GE(location.size(), 4U) << location; // must be at least .123
std::string odex_location(location);
InsertIsaDirectory(isa, &odex_location);
diff --git a/runtime/utils.h b/runtime/utils.h
index a61d30f..68ea475 100644
--- a/runtime/utils.h
+++ b/runtime/utils.h
@@ -401,6 +401,7 @@ std::string GetSystemImageFilename(const char* location, InstructionSet isa);
// Returns an .odex file name next adjacent to the dex location.
// For example, for "/foo/bar/baz.jar", return "/foo/bar/<isa>/baz.odex".
+// Note: does not support multidex location strings.
std::string DexFilenameToOdexFilename(const std::string& location, InstructionSet isa);
// Check whether the given magic matches a known file type.