Fix checksum verification when opening DexFiles from OatFiles
Change-Id: Ic3d13f3d591c34f159bf0739536a1751c3e7dc75
diff --git a/src/class_linker.cc b/src/class_linker.cc
index 87976a3..f414c4b 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -40,6 +40,7 @@
#include "oat_file.h"
#include "object.h"
#include "object_utils.h"
+#include "os.h"
#include "runtime.h"
#include "runtime_support.h"
#include "ScopedLocalRef.h"
@@ -678,10 +679,18 @@
}
const OatFile* ClassLinker::FindOpenedOatFileForDexFile(const DexFile& dex_file) {
+ return FindOpenedOatFileFromDexLocation(dex_file.GetLocation(),
+ dex_file.GetLocationChecksum());
+}
+
+const OatFile* ClassLinker::FindOpenedOatFileFromDexLocation(const std::string& dex_location,
+ uint32_t dex_location_checksum) {
for (size_t i = 0; i < oat_files_.size(); i++) {
const OatFile* oat_file = oat_files_[i];
DCHECK(oat_file != NULL);
- if (oat_file->GetOatDexFile(dex_file.GetLocation(), false)) {
+ const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_location, false);
+ if (oat_dex_file != NULL
+ && oat_dex_file->GetDexFileLocationChecksum() == dex_location_checksum) {
return oat_file;
}
}
@@ -734,77 +743,103 @@
int fd_;
};
-const OatFile* ClassLinker::FindOatFileForDexFile(const DexFile& dex_file) {
+static const DexFile* FindDexFileInOatLocation(const std::string& dex_location,
+ uint32_t dex_location_checksum,
+ const std::string& oat_location) {
+ UniquePtr<OatFile> oat_file(OatFile::Open(oat_location, "", NULL));
+ if (oat_file.get() == NULL) {
+ return NULL;
+ }
+ const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_location);
+ if (oat_dex_file == NULL) {
+ return NULL;
+ }
+ if (oat_dex_file->GetDexFileLocationChecksum() != dex_location_checksum) {
+ return NULL;
+ }
+ Runtime::Current()->GetClassLinker()->RegisterOatFile(*oat_file.release());
+ return oat_dex_file->OpenDexFile();
+}
+
+const DexFile* ClassLinker::FindOrCreateOatFileForDexLocation(const std::string& dex_location,
+ const std::string& oat_location) {
+ uint32_t dex_location_checksum;
+ if (!DexFile::GetChecksum(dex_location, dex_location_checksum)) {
+ LOG(ERROR) << "Failed to compute checksum '" << dex_location << "'";
+ return NULL;
+ }
+
+ // Check if we already have an up-to-date output file
+ const DexFile* dex_file = FindDexFileInOatLocation(dex_location,
+ dex_location_checksum,
+ oat_location);
+ if (dex_file != NULL) {
+ return dex_file;
+ }
+
+ // Generate the output oat file for the dex file
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ UniquePtr<File> file(OS::OpenFile(oat_location.c_str(), true));
+ if (file.get() == NULL) {
+ LOG(ERROR) << "Failed to create oat file: " << oat_location;
+ return NULL;
+ }
+ if (!class_linker->GenerateOatFile(dex_location, file->Fd(), oat_location)) {
+ LOG(ERROR) << "Failed to generate oat file: " << oat_location;
+ return NULL;
+ }
+ // Open the oat from file descriptor we passed to GenerateOatFile
+ if (lseek(file->Fd(), 0, SEEK_SET) != 0) {
+ LOG(ERROR) << "Failed to seek to start of generated oat file: " << oat_location;
+ return NULL;
+ }
+ const OatFile* oat_file = OatFile::Open(*file.get(), oat_location, NULL);
+ if (oat_file == NULL) {
+ LOG(ERROR) << "Failed to open generated oat file: " << oat_location;
+ return NULL;
+ }
+ class_linker->RegisterOatFile(*oat_file);
+ const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_location);
+ if (oat_dex_file == NULL) {
+ LOG(ERROR) << "Failed to find dex file in generated oat file: " << oat_location;
+ return NULL;
+ }
+ return oat_dex_file->OpenDexFile();
+}
+
+const DexFile* ClassLinker::FindDexFileInOatFileFromDexLocation(const std::string& dex_location) {
MutexLock mu(dex_lock_);
- const OatFile* open_oat_file = FindOpenedOatFileForDexFile(dex_file);
+
+ uint32_t dex_location_checksum;
+ if (!DexFile::GetChecksum(dex_location, dex_location_checksum)) {
+ LOG(WARNING) << "Failed to compute checksum: " << dex_location;
+ return NULL;
+ }
+
+ const OatFile* open_oat_file = FindOpenedOatFileFromDexLocation(dex_location, dex_location_checksum);
if (open_oat_file != NULL) {
- return open_oat_file;
+ return open_oat_file->GetOatDexFile(dex_location)->OpenDexFile();
}
- std::string oat_filename(OatFile::DexFilenameToOatFilename(dex_file.GetLocation()));
- open_oat_file = FindOpenedOatFileFromOatLocation(oat_filename);
- if (open_oat_file != NULL) {
- return open_oat_file;
- }
-
- while (true) {
- UniquePtr<const OatFile> oat_file(FindOatFileFromOatLocation(oat_filename));
- if (oat_file.get() != NULL) {
- const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_file.GetLocation());
- if (dex_file.GetHeader().checksum_ == oat_dex_file->GetDexFileChecksum()) {
- return oat_file.release();
- }
- LOG(WARNING) << ".oat file " << oat_file->GetLocation()
- << " checksum mismatch with " << dex_file.GetLocation() << " --- regenerating";
- if (TEMP_FAILURE_RETRY(unlink(oat_file->GetLocation().c_str())) != 0) {
- PLOG(FATAL) << "Couldn't remove obsolete .oat file " << oat_file->GetLocation();
- }
- // Fall through...
+ // Look for an existing file first next to dex and in art-cache
+ std::string oat_filename(OatFile::DexFilenameToOatFilename(dex_location));
+ const OatFile* oat_file(FindOatFileFromOatLocation(oat_filename));
+ if (oat_file != NULL) {
+ const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_location);
+ if (dex_location_checksum == oat_dex_file->GetDexFileLocationChecksum()) {
+ return oat_file->GetOatDexFile(dex_location)->OpenDexFile();
}
- // Try to generate oat file if it wasn't found or was obsolete.
- // Note we can be racing with another runtime to do this.
- std::string oat_cache_filename(GetArtCacheFilenameOrDie(oat_filename));
- UniquePtr<LockedFd> locked_fd(LockedFd::CreateAndLock(oat_cache_filename, 0644));
- if (locked_fd.get() == NULL) {
- LOG(ERROR) << "Failed to create and lock oat file " << oat_cache_filename;
- return NULL;
- }
- // Check to see if the fd we opened and locked matches the file in
- // the filesystem. If they don't, then somebody else unlinked ours
- // and created a new file, and we need to use that one instead. (If
- // we caught them between the unlink and the create, we'll get an
- // ENOENT from the file stat.)
- struct stat fd_stat;
- int fd_stat_result = fstat(locked_fd->GetFd(), &fd_stat);
- if (fd_stat_result != 0) {
- PLOG(ERROR) << "Failed to fstat file descriptor of oat file " << oat_cache_filename;
- return NULL;
- }
- struct stat file_stat;
- int file_stat_result = stat(oat_cache_filename.c_str(), &file_stat);
- if (file_stat_result != 0
- || fd_stat.st_dev != file_stat.st_dev
- || fd_stat.st_ino != file_stat.st_ino) {
- LOG(INFO) << "Opened oat file " << oat_cache_filename << " is stale; sleeping and retrying";
- usleep(250 * 1000); // if something is hosed, don't peg machine
- continue;
- }
-
- // We have the correct file open and locked. If the file size is
- // zero, then it was just created by us and we can generate its
- // contents. If not, someone else created it. Either way, we'll
- // loop to retry opening the file.
- if (fd_stat.st_size == 0) {
- bool success = GenerateOatFile(dex_file.GetLocation(),
- locked_fd->GetFd(),
- oat_cache_filename);
- if (!success) {
- LOG(ERROR) << "Failed to generate oat file " << oat_cache_filename;
- return NULL;
- }
+ LOG(WARNING) << ".oat file " << oat_file->GetLocation()
+ << " checksum ( " << std::hex << oat_dex_file->GetDexFileLocationChecksum()
+ << ") mismatch with " << dex_location
+ << " (" << std::hex << dex_location_checksum << ")--- regenerating";
+ if (TEMP_FAILURE_RETRY(unlink(oat_file->GetLocation().c_str())) != 0) {
+ PLOG(FATAL) << "Couldn't remove obsolete .oat file " << oat_file->GetLocation();
}
}
- // Not reached
+ // Try to generate oat file if it wasn't found or was obsolete.
+ std::string oat_cache_filename(GetArtCacheFilenameOrDie(oat_filename));
+ return FindOrCreateOatFileForDexLocation(dex_location, oat_cache_filename);
}
const OatFile* ClassLinker::FindOpenedOatFileFromOatLocation(const std::string& oat_location) {
@@ -850,26 +885,6 @@
return oat_file;
}
-const DexFile* ClassLinker::FindDexFileFromDexLocation(const std::string& location) {
- std::string oat_location(OatFile::DexFilenameToOatFilename(location));
- const OatFile* oat_file = FindOatFileFromOatLocation(oat_location);
- if (oat_file == NULL) {
- return NULL;
- }
- const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(location);
- if (oat_dex_file == NULL) {
- return NULL;
- }
- const DexFile* dex_file = oat_dex_file->OpenDexFile();
- if (dex_file == NULL) {
- return NULL;
- }
- if (oat_dex_file->GetDexFileChecksum() != dex_file->GetHeader().checksum_) {
- return NULL;
- }
- return dex_file;
-}
-
void ClassLinker::InitFromImage() {
VLOG(startup) << "ClassLinker::InitFromImage entering";
CHECK(!init_done_);
@@ -903,7 +918,7 @@
<< " from within oat file " << oat_file->GetLocation();
}
- CHECK_EQ(dex_file->GetHeader().checksum_, oat_dex_file->GetDexFileChecksum());
+ CHECK_EQ(dex_file->GetLocationChecksum(), oat_dex_file->GetDexFileLocationChecksum());
AppendToBootClassPath(*dex_file, dex_cache);
}
@@ -1402,17 +1417,15 @@
UniquePtr<const OatFile::OatClass> oat_class;
if (Runtime::Current()->IsStarted() && !ClassLoader::UseCompileTimeClassPath()) {
- const OatFile* oat_file = FindOatFileForDexFile(dex_file);
- if (oat_file != NULL) {
- const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_file.GetLocation());
- if (oat_dex_file != NULL) {
- uint32_t class_def_index;
- bool found = dex_file.FindClassDefIndex(descriptor, class_def_index);
- CHECK(found) << descriptor;
- oat_class.reset(oat_dex_file->GetOatClass(class_def_index));
- CHECK(oat_class.get() != NULL) << descriptor;
- }
- }
+ const OatFile* oat_file = FindOpenedOatFileForDexFile(dex_file);
+ CHECK(oat_file != NULL) << dex_file.GetLocation() << " " << descriptor;
+ const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_file.GetLocation());
+ CHECK(oat_dex_file != NULL) << dex_file.GetLocation() << " " << descriptor;
+ uint32_t class_def_index;
+ bool found = dex_file.FindClassDefIndex(descriptor, class_def_index);
+ CHECK(found) << dex_file.GetLocation() << " " << descriptor;
+ oat_class.reset(oat_dex_file->GetOatClass(class_def_index));
+ CHECK(oat_class.get() != NULL) << dex_file.GetLocation() << " " << descriptor;
}
// Load methods.
if (it.NumDirectMethods() != 0) {
@@ -1956,18 +1969,17 @@
if (ClassLoader::UseCompileTimeClassPath()) {
return false;
}
- const OatFile* oat_file = FindOatFileForDexFile(dex_file);
- if (oat_file == NULL) {
- return false;
- }
+ const OatFile* oat_file = FindOpenedOatFileForDexFile(dex_file);
+ CHECK(oat_file != NULL) << dex_file.GetLocation() << " " << PrettyClass(klass);
const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_file.GetLocation());
- CHECK(oat_dex_file != NULL) << PrettyClass(klass);
+ CHECK(oat_dex_file != NULL) << dex_file.GetLocation() << " " << PrettyClass(klass);
const char* descriptor = ClassHelper(klass).GetDescriptor();
uint32_t class_def_index;
bool found = dex_file.FindClassDefIndex(descriptor, class_def_index);
- CHECK(found) << descriptor;
+ CHECK(found) << dex_file.GetLocation() << " " << PrettyClass(klass) << " " << descriptor;
UniquePtr<const OatFile::OatClass> oat_class(oat_dex_file->GetOatClass(class_def_index));
- CHECK(oat_class.get() != NULL) << descriptor;
+ CHECK(oat_class.get() != NULL)
+ << dex_file.GetLocation() << " " << PrettyClass(klass) << " " << descriptor;
Class::Status status = oat_class->GetStatus();
if (status == Class::kStatusVerified || status == Class::kStatusInitialized) {
return true;
@@ -1999,7 +2011,9 @@
// isn't a problem and this case shouldn't occur
return false;
}
- LOG(FATAL) << "Unexpected class status: " << status;
+ LOG(FATAL) << "Unexpected class status: " << status
+ << " " << dex_file.GetLocation() << " " << PrettyClass(klass) << " " << descriptor;
+
return false;
}
diff --git a/src/class_linker.h b/src/class_linker.h
index f2b44a3..c49c03f 100644
--- a/src/class_linker.h
+++ b/src/class_linker.h
@@ -247,12 +247,18 @@
int oat_fd,
const std::string& oat_cache_filename);
- // Find, possibily opening, an OatFile corresponding to a DexFile
- const OatFile* FindOatFileForDexFile(const DexFile& dex_file);
const OatFile* FindOatFileFromOatLocation(const std::string& location);
- // Find a DexFile within an OatFile given a DexFile location
- const DexFile* FindDexFileFromDexLocation(const std::string& location);
+ // 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 std::string& dex_location,
+ const std::string& oat_location);
+ // 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 std::string& location);
+
// TODO: replace this with multiple methods that allocate the correct managed type.
template <class T>
@@ -388,6 +394,8 @@
}
const OatFile* FindOpenedOatFileForDexFile(const DexFile& dex_file);
+ const OatFile* FindOpenedOatFileFromDexLocation(const std::string& dex_location,
+ uint32_t dex_location_checksum);
const OatFile* FindOpenedOatFileFromOatLocation(const std::string& oat_location);
Method* CreateProxyConstructor(SirtRef<Class>& klass, Class* proxy_class);
diff --git a/src/dalvik_system_DexFile.cc b/src/dalvik_system_DexFile.cc
index 67cb49b..a255141 100644
--- a/src/dalvik_system_DexFile.cc
+++ b/src/dalvik_system_DexFile.cc
@@ -84,60 +84,22 @@
if (sourceName.c_str() == NULL) {
return 0;
}
+ std::string source(sourceName.c_str());
NullableScopedUtfChars outputName(env, javaOutputName);
if (env->ExceptionCheck()) {
return 0;
}
const DexFile* dex_file;
if (outputName.c_str() == NULL) {
- dex_file = Runtime::Current()->GetClassLinker()->FindDexFileFromDexLocation(sourceName.c_str());
- if (dex_file == NULL) {
- dex_file = DexFile::Open(sourceName.c_str(), "");
- }
+ dex_file = Runtime::Current()->GetClassLinker()->FindDexFileInOatFileFromDexLocation(source);
} else {
- // Sanity check the arguments.
- if (!IsValidZipFilename(sourceName.c_str()) || !IsValidDexFilename(outputName.c_str())) {
- LOG(ERROR) << "Bad filenames extracting dex '" << outputName.c_str()
- << "' from zip '" << sourceName.c_str() << "'";
- return 0;
- }
- // Generate the output oat file for the source dex file
- ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
- UniquePtr<File> file(OS::OpenFile(outputName.c_str(), true));
- if (file.get() == NULL) {
- LOG(WARNING) << "unable to create oat file: " << outputName.c_str();
- jniThrowExceptionFmt(env, "java/io/IOException", "unable to create oat file: %s",
- outputName.c_str());
- return 0;
- }
- if (!class_linker->GenerateOatFile(sourceName.c_str(), file->Fd(), outputName.c_str())) {
- LOG(WARNING) << "unable to generate oat file: " << outputName.c_str();
- jniThrowExceptionFmt(env, "java/io/IOException", "unable to generate oat file: %s",
- outputName.c_str());
- return 0;
- }
- UniquePtr<OatFile> oat_file(OatFile::Open(outputName.c_str(), "", NULL));
- if (oat_file.get() == NULL) {
- LOG(WARNING) << "unable to open oat file: " << outputName.c_str();
- jniThrowExceptionFmt(env, "java/io/IOException", "unable to open oat file: %s",
- outputName.c_str());
- return 0;
- }
- const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(sourceName.c_str());
- if (oat_dex_file == NULL) {
- LOG(WARNING) << "unable to find dex file in oat file: " << outputName.c_str();
- jniThrowExceptionFmt(env, "java/io/IOException", "unable to find dex file in oat file: %s",
- outputName.c_str());
- return 0;
- }
- Runtime::Current()->GetClassLinker()->RegisterOatFile(*oat_file.release());
- dex_file = oat_dex_file->OpenDexFile();
+ std::string output(outputName.c_str());
+ dex_file = Runtime::Current()->GetClassLinker()->FindOrCreateOatFileForDexLocation(source, output);
}
-
if (dex_file == NULL) {
- LOG(WARNING) << "unable to open dex file: " << sourceName.c_str();
+ LOG(WARNING) << "Failed to open dex file: " << source;
jniThrowExceptionFmt(env, "java/io/IOException", "unable to open dex file: %s",
- sourceName.c_str());
+ source.c_str());
return 0;
}
return static_cast<jint>(reinterpret_cast<uintptr_t>(dex_file));
@@ -236,10 +198,26 @@
}
}
- const DexFile* dex_file = class_linker->FindDexFileFromDexLocation(filename.c_str());
- if (dex_file == NULL) {
+ uint32_t location_checksum;
+ if (!DexFile::GetChecksum(filename.c_str(), location_checksum)) {
return JNI_TRUE;
}
+
+ std::string oat_filename(OatFile::DexFilenameToOatFilename(filename.c_str()));
+ const OatFile* oat_file(class_linker->FindOatFileFromOatLocation(oat_filename));
+ if (oat_file == NULL) {
+ return JNI_TRUE;
+ }
+
+ const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(filename.c_str());
+ if (oat_dex_file == NULL) {
+ return JNI_TRUE;
+ }
+
+ if (location_checksum != oat_dex_file->GetDexFileLocationChecksum()) {
+ return JNI_TRUE;
+ }
+
return JNI_FALSE;
}
diff --git a/src/dex2oat.cc b/src/dex2oat.cc
index c4ca894..25c1d82 100644
--- a/src/dex2oat.cc
+++ b/src/dex2oat.cc
@@ -379,6 +379,21 @@
return true;
}
+void OpenDexFiles(const std::vector<const char*>& dex_filenames,
+ std::vector<const DexFile*>& dex_files,
+ const std::string& strip_location_prefix) {
+ for (size_t i = 0; i < dex_filenames.size(); i++) {
+ const char* dex_filename = dex_filenames[i];
+ const DexFile* dex_file = DexFile::Open(dex_filename, strip_location_prefix);
+ if (dex_file == NULL) {
+ fprintf(stderr, "could not open .dex from file %s\n", dex_filename);
+ exit(EXIT_FAILURE);
+ }
+ dex_files.push_back(dex_file);
+ }
+}
+
+
int dex2oat(int argc, char** argv) {
// Skip over argv[0].
argv++;
@@ -609,7 +624,7 @@
}
dex_files.push_back(dex_file);
} else {
- DexFile::OpenDexFiles(dex_filenames, dex_files, host_prefix);
+ OpenDexFiles(dex_filenames, dex_files, host_prefix);
}
}
diff --git a/src/dex_file.cc b/src/dex_file.cc
index cb90e15..16fd407 100644
--- a/src/dex_file.cc
+++ b/src/dex_file.cc
@@ -60,18 +60,28 @@
reinterpret_cast<const DexFile::ClassDef*>(NULL));
}
-void DexFile::OpenDexFiles(const std::vector<const char*>& dex_filenames,
- std::vector<const DexFile*>& dex_files,
- const std::string& strip_location_prefix) {
- for (size_t i = 0; i < dex_filenames.size(); i++) {
- const char* dex_filename = dex_filenames[i];
- const DexFile* dex_file = Open(dex_filename, strip_location_prefix);
- if (dex_file == NULL) {
- fprintf(stderr, "could not open .dex from file %s\n", dex_filename);
- exit(EXIT_FAILURE);
+bool DexFile::GetChecksum(const std::string& filename, uint32_t& checksum) {
+ if (IsValidZipFilename(filename)) {
+ UniquePtr<ZipArchive> zip_archive(ZipArchive::Open(filename));
+ if (zip_archive.get() == NULL) {
+ return false;
}
- dex_files.push_back(dex_file);
+ UniquePtr<ZipEntry> zip_entry(zip_archive->Find(kClassesDex));
+ if (zip_entry.get() == NULL) {
+ return false;
+ }
+ checksum = zip_entry->GetCrc32();
+ return true;
}
+ if (IsValidDexFilename(filename)) {
+ UniquePtr<const DexFile> dex_file(DexFile::OpenFile(filename, "", false));
+ if (dex_file.get() == NULL) {
+ return false;
+ }
+ checksum = dex_file->GetHeader().checksum_;
+ return true;
+ }
+ return false;
}
const DexFile* DexFile::Open(const std::string& filename,
@@ -82,7 +92,7 @@
if (!IsValidDexFilename(filename)) {
LOG(WARNING) << "Attempting to open dex file with unknown extension '" << filename << "'";
}
- return DexFile::OpenFile(filename, filename, strip_location_prefix);
+ return DexFile::OpenFile(filename, strip_location_prefix, true);
}
void DexFile::ChangePermissions(int prot) const {
@@ -103,9 +113,9 @@
}
const DexFile* DexFile::OpenFile(const std::string& filename,
- const std::string& original_location,
- const std::string& strip_location_prefix) {
- std::string location(StripLocationPrefix(original_location, strip_location_prefix));
+ const std::string& strip_location_prefix,
+ bool verify) {
+ std::string location(StripLocationPrefix(filename, strip_location_prefix));
if (location.empty()) {
return NULL;
}
@@ -134,14 +144,22 @@
return NULL;
}
close(fd);
- const DexFile* dex_file = OpenMemory(location, map.release());
+
+ if (map->Size() < sizeof(DexFile::Header)) {
+ LOG(ERROR) << "Failed to open dex file '" << filename << "' that is too short to have a header";
+ return NULL;
+ }
+
+ const Header* dex_header = reinterpret_cast<const Header*>(map->Begin());
+
+ const DexFile* dex_file = OpenMemory(location, dex_header->checksum_, map.release());
if (dex_file == NULL) {
- LOG(ERROR) << "Failed to open dex file '" << location << "' from memory";
+ LOG(ERROR) << "Failed to open dex file '" << filename << "' from memory";
return NULL;
}
if (!DexFileVerifier::Verify(dex_file, dex_file->Begin(), dex_file->Size())) {
- LOG(ERROR) << "Failed to verify dex file '" << location << "'";
+ LOG(ERROR) << "Failed to verify dex file '" << filename << "'";
return NULL;
}
@@ -189,7 +207,7 @@
return NULL;
}
- const DexFile* dex_file = OpenMemory(location, map.release());
+ const DexFile* dex_file = OpenMemory(location, zip_entry->GetCrc32(), map.release());
if (dex_file == NULL) {
LOG(ERROR) << "Failed to open dex file '" << location << "' from memory";
return NULL;
@@ -206,9 +224,10 @@
const DexFile* DexFile::OpenMemory(const byte* base,
size_t size,
const std::string& location,
+ uint32_t location_checksum,
MemMap* mem_map) {
CHECK_ALIGNED(base, 4); // various dex file structures must be word aligned
- UniquePtr<DexFile> dex_file(new DexFile(base, size, location, mem_map));
+ UniquePtr<DexFile> dex_file(new DexFile(base, size, location, location_checksum, mem_map));
if (!dex_file->Init()) {
return NULL;
} else {
diff --git a/src/dex_file.h b/src/dex_file.h
index d883f98..5d63408 100644
--- a/src/dex_file.h
+++ b/src/dex_file.h
@@ -54,7 +54,7 @@
// Raw header_item.
struct Header {
uint8_t magic_[8];
- uint32_t checksum_;
+ uint32_t checksum_; // See also location_checksum_
uint8_t signature_[kSha1DigestSize];
uint32_t file_size_; // size of entire file
uint32_t header_size_; // offset to start of next section
@@ -314,18 +314,20 @@
static ClassPathEntry FindInClassPath(const StringPiece& descriptor,
const ClassPath& class_path);
- // Opens a collection of .dex files
- static void OpenDexFiles(const std::vector<const char*>& dex_filenames,
- std::vector<const DexFile*>& dex_files,
- const std::string& strip_location_prefix);
+ // Returns the checksum of a file for comparison with GetLocationChecksum().
+ // For .dex files, this is the header checksum.
+ // For zip files, this is the classes.dex zip entry CRC32 checksum.
+ // Return true if the checksum could be found, false otherwise.
+ static bool GetChecksum(const std::string& filename, uint32_t& checksum);
// Opens .dex file, guessing the container format based on file extension
static const DexFile* Open(const std::string& filename,
const std::string& strip_location_prefix);
// Opens .dex file, backed by existing memory
- static const DexFile* Open(const uint8_t* base, size_t size, const std::string& location) {
- return OpenMemory(base, size, location, NULL);
+ static const DexFile* Open(const uint8_t* base, size_t size,
+ const std::string& location, uint32_t location_checksum) {
+ return OpenMemory(base, size, location, location_checksum, NULL);
}
// Opens .dex file from the classes.dex in a zip archive
@@ -338,6 +340,12 @@
return location_;
}
+ // For DexFiles directly from .dex files, this is the checksum from the DexFile::Header.
+ // For DexFiles opened from a zip files, this will be the ZipEntry CRC32 of classes.dex.
+ uint32_t GetLocationChecksum() const {
+ return location_checksum_;
+ }
+
// Returns a com.android.dex.Dex object corresponding to the mapped-in dex file.
// Used by managed code to implement annotations.
jobject GetDexObject(JNIEnv* env) const;
@@ -765,8 +773,8 @@
// Opens a .dex file
static const DexFile* OpenFile(const std::string& filename,
- const std::string& original_location,
- const std::string& strip_location_prefix);
+ const std::string& strip_location_prefix,
+ bool verify);
// Opens a dex file from within a .jar, .zip, or .apk file
static const DexFile* OpenZip(const std::string& filename,
@@ -774,10 +782,12 @@
// Opens a .dex file at the given address backed by a MemMap
static const DexFile* OpenMemory(const std::string& location,
+ uint32_t location_checksum,
MemMap* mem_map) {
return OpenMemory(mem_map->Begin(),
mem_map->Size(),
location,
+ location_checksum,
mem_map);
}
@@ -785,12 +795,16 @@
static const DexFile* OpenMemory(const byte* dex_file,
size_t size,
const std::string& location,
+ uint32_t location_checksum,
MemMap* mem_map);
- DexFile(const byte* base, size_t size, const std::string& location, MemMap* mem_map)
+ DexFile(const byte* base, size_t size,
+ const std::string& location, uint32_t location_checksum,
+ MemMap* mem_map)
: begin_(base),
size_(size),
location_(location),
+ location_checksum_(location_checksum),
mem_map_(mem_map),
dex_object_lock_("a dex_object_lock_"),
dex_object_(NULL),
@@ -845,6 +859,8 @@
// path to DexCache::GetLocation when loading from an image.
const std::string location_;
+ const uint32_t location_checksum_;
+
// Manages the underlying memory allocation.
UniquePtr<MemMap> mem_map_;
diff --git a/src/dex_file_test.cc b/src/dex_file_test.cc
index 1e876ba..f075fea 100644
--- a/src/dex_file_test.cc
+++ b/src/dex_file_test.cc
@@ -81,6 +81,19 @@
EXPECT_EQ(256U, header.class_defs_off_);
EXPECT_EQ(584U, header.data_size_);
EXPECT_EQ(320U, header.data_off_);
+
+ EXPECT_EQ(header.checksum_, raw->GetLocationChecksum());
+}
+
+TEST_F(DexFileTest, GetLocationChecksum) {
+ const DexFile* raw(OpenTestDexFile("Main"));
+ EXPECT_NE(raw->GetHeader().checksum_, raw->GetLocationChecksum());
+}
+
+TEST_F(DexFileTest, GetChecksum) {
+ uint32_t checksum;
+ EXPECT_TRUE(DexFile::GetChecksum(GetLibCoreDexFileName(), checksum));
+ EXPECT_EQ(java_lang_dex_file_->GetLocationChecksum(), checksum);
}
TEST_F(DexFileTest, ClassDefs) {
diff --git a/src/oat_file.cc b/src/oat_file.cc
index 4bcd967..cf8bafe 100644
--- a/src/oat_file.cc
+++ b/src/oat_file.cc
@@ -34,15 +34,24 @@
OatFile* OatFile::Open(const std::string& filename,
const std::string& strip_location_prefix,
byte* requested_base) {
- StringPiece location = filename;
+ StringPiece location(filename);
if (!location.starts_with(strip_location_prefix)) {
LOG(ERROR) << filename << " does not start with " << strip_location_prefix;
return NULL;
}
location.remove_prefix(strip_location_prefix.size());
+ UniquePtr<File> file(OS::OpenFile(filename.c_str(), false));
+ if (file.get() == NULL) {
+ return false;
+ }
+ return Open(*file.get(), location.ToString(), requested_base);
+}
- UniquePtr<OatFile> oat_file(new OatFile(location.ToString()));
- bool success = oat_file->Read(filename, requested_base);
+OatFile* OatFile::Open(File& file,
+ const std::string& location,
+ byte* requested_base) {
+ UniquePtr<OatFile> oat_file(new OatFile(location));
+ bool success = oat_file->Read(file, requested_base);
if (!success) {
return NULL;
}
@@ -55,81 +64,77 @@
STLDeleteValues(&oat_dex_files_);
}
-bool OatFile::Read(const std::string& filename, byte* requested_base) {
- UniquePtr<File> file(OS::OpenFile(filename.c_str(), false));
- if (file.get() == NULL) {
- return false;
- }
+bool OatFile::Read(File& file, byte* requested_base) {
OatHeader oat_header;
- bool success = file->ReadFully(&oat_header, sizeof(oat_header));
+ bool success = file.ReadFully(&oat_header, sizeof(oat_header));
if (!success || !oat_header.IsValid()) {
- LOG(WARNING) << "Invalid oat header " << filename;
+ LOG(WARNING) << "Invalid oat header " << GetLocation();
return false;
}
int flags = MAP_PRIVATE | ((requested_base != NULL) ? MAP_FIXED : 0);
UniquePtr<MemMap> map(MemMap::MapFileAtAddress(requested_base,
- file->Length(),
+ file.Length(),
PROT_READ,
flags,
- file->Fd(),
+ file.Fd(),
0));
if (map.get() == NULL) {
- LOG(WARNING) << "Failed to map oat file " << filename;
+ LOG(WARNING) << "Failed to map oat file " << GetLocation();
return false;
}
CHECK(requested_base == 0 || requested_base == map->Begin())
- << filename << " " << reinterpret_cast<void*>(map->Begin());
- DCHECK_EQ(0, memcmp(&oat_header, map->Begin(), sizeof(OatHeader))) << filename;
+ << GetLocation() << " " << reinterpret_cast<void*>(map->Begin());
+ DCHECK_EQ(0, memcmp(&oat_header, map->Begin(), sizeof(OatHeader))) << GetLocation();
off_t code_offset = oat_header.GetExecutableOffset();
- if (code_offset < file->Length()) {
+ if (code_offset < file.Length()) {
byte* code_address = map->Begin() + code_offset;
- size_t code_length = file->Length() - code_offset;
+ size_t code_length = file.Length() - code_offset;
if (mprotect(code_address, code_length, PROT_READ | PROT_EXEC) != 0) {
- PLOG(ERROR) << "Failed to make oat code executable in " << filename;
+ PLOG(ERROR) << "Failed to make oat code executable in " << GetLocation();
return false;
}
} else {
// its possible to have no code if all the methods were abstract, native, etc
- DCHECK_EQ(code_offset, RoundUp(file->Length(), kPageSize)) << filename;
+ DCHECK_EQ(code_offset, RoundUp(file.Length(), kPageSize)) << GetLocation();
}
const byte* oat = map->Begin();
oat += sizeof(OatHeader);
- CHECK_LE(oat, map->End()) << filename;
+ CHECK_LE(oat, map->End()) << GetLocation();
for (size_t i = 0; i < oat_header.GetDexFileCount(); i++) {
size_t dex_file_location_size = *reinterpret_cast<const uint32_t*>(oat);
- CHECK_GT(dex_file_location_size, 0U) << filename;
+ CHECK_GT(dex_file_location_size, 0U) << GetLocation();
oat += sizeof(dex_file_location_size);
- CHECK_LT(oat, map->End()) << filename;
+ CHECK_LT(oat, map->End()) << GetLocation();
const char* dex_file_location_data = reinterpret_cast<const char*>(oat);
oat += dex_file_location_size;
- CHECK_LT(oat, map->End()) << filename;
+ CHECK_LT(oat, map->End()) << GetLocation();
std::string dex_file_location(dex_file_location_data, dex_file_location_size);
uint32_t dex_file_checksum = *reinterpret_cast<const uint32_t*>(oat);
oat += sizeof(dex_file_checksum);
- CHECK_LT(oat, map->End()) << filename;
+ CHECK_LT(oat, map->End()) << GetLocation();
uint32_t dex_file_offset = *reinterpret_cast<const uint32_t*>(oat);
- CHECK_GT(dex_file_offset, 0U) << filename;
- CHECK_LT(dex_file_offset, static_cast<uint32_t>(file->Length())) << filename;
+ CHECK_GT(dex_file_offset, 0U) << GetLocation();
+ CHECK_LT(dex_file_offset, static_cast<uint32_t>(file.Length())) << GetLocation();
oat += sizeof(dex_file_offset);
- CHECK_LT(oat, map->End()) << filename;
+ CHECK_LT(oat, map->End()) << GetLocation();
uint8_t* dex_file_pointer = map->Begin() + dex_file_offset;
- CHECK(DexFile::IsMagicValid(dex_file_pointer)) << filename << " " << dex_file_pointer;
- CHECK(DexFile::IsVersionValid(dex_file_pointer)) << filename << " " << dex_file_pointer;
+ CHECK(DexFile::IsMagicValid(dex_file_pointer)) << GetLocation() << " " << dex_file_pointer;
+ CHECK(DexFile::IsVersionValid(dex_file_pointer)) << GetLocation() << " " << dex_file_pointer;
const DexFile::Header* header = reinterpret_cast<const DexFile::Header*>(dex_file_pointer);
const uint32_t* methods_offsets_pointer = reinterpret_cast<const uint32_t*>(oat);
oat += (sizeof(*methods_offsets_pointer) * header->class_defs_size_);
- CHECK_LE(oat, map->End()) << filename;
+ CHECK_LE(oat, map->End()) << GetLocation();
oat_dex_files_[dex_file_location] = new OatDexFile(this,
dex_file_location,
@@ -178,12 +183,12 @@
OatFile::OatDexFile::OatDexFile(const OatFile* oat_file,
const std::string& dex_file_location,
- uint32_t dex_file_checksum,
+ uint32_t dex_file_location_checksum,
byte* dex_file_pointer,
const uint32_t* oat_class_offsets_pointer)
: oat_file_(oat_file),
dex_file_location_(dex_file_location),
- dex_file_checksum_(dex_file_checksum),
+ dex_file_location_checksum_(dex_file_location_checksum),
dex_file_pointer_(dex_file_pointer),
oat_class_offsets_pointer_(oat_class_offsets_pointer) {}
@@ -191,7 +196,7 @@
const DexFile* OatFile::OatDexFile::OpenDexFile() const {
size_t length = reinterpret_cast<const DexFile::Header*>(dex_file_pointer_)->file_size_;
- return DexFile::Open(dex_file_pointer_, length, dex_file_location_);
+ return DexFile::Open(dex_file_pointer_, length, dex_file_location_, dex_file_location_checksum_);
}
const OatFile::OatClass* OatFile::OatDexFile::GetOatClass(uint32_t class_def_index) const {
diff --git a/src/oat_file.h b/src/oat_file.h
index 4740ae7..2895d74 100644
--- a/src/oat_file.h
+++ b/src/oat_file.h
@@ -39,6 +39,11 @@
const std::string& strip_location_prefix,
byte* requested_base);
+ // Open an oat file from an already opened File with the given location.
+ static OatFile* Open(File& file,
+ const std::string& location,
+ byte* requested_base);
+
~OatFile();
const std::string& GetLocation() const {
@@ -166,8 +171,8 @@
return dex_file_location_;
}
- uint32_t GetDexFileChecksum() const {
- return dex_file_checksum_;
+ uint32_t GetDexFileLocationChecksum() const {
+ return dex_file_location_checksum_;
}
~OatDexFile();
@@ -180,7 +185,7 @@
const OatFile* oat_file_;
std::string dex_file_location_;
- uint32_t dex_file_checksum_;
+ uint32_t dex_file_location_checksum_;
const byte* dex_file_pointer_;
const uint32_t* oat_class_offsets_pointer_;
@@ -198,7 +203,7 @@
private:
explicit OatFile(const std::string& filename);
- bool Read(const std::string& filename, byte* requested_base);
+ bool Read(File& file, byte* requested_base);
const byte* Begin() const;
const byte* End() const;
diff --git a/src/oat_test.cc b/src/oat_test.cc
index d64f810..0fd64ff 100644
--- a/src/oat_test.cc
+++ b/src/oat_test.cc
@@ -47,6 +47,7 @@
const DexFile& dex_file = *java_lang_dex_file_.get();
const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_file.GetLocation());
+ CHECK_EQ(dex_file.GetLocationChecksum(), oat_dex_file->GetDexFileLocationChecksum());
for (size_t i = 0; i < dex_file.NumClassDefs(); i++) {
const DexFile::ClassDef& class_def = dex_file.GetClassDef(i);
const byte* class_data = dex_file.GetClassData(class_def);
diff --git a/src/oat_writer.cc b/src/oat_writer.cc
index 94281c9..e4c8135 100644
--- a/src/oat_writer.cc
+++ b/src/oat_writer.cc
@@ -680,7 +680,7 @@
const std::string& location(dex_file.GetLocation());
dex_file_location_size_ = location.size();
dex_file_location_data_ = reinterpret_cast<const uint8_t*>(location.data());
- dex_file_checksum_ = dex_file.GetHeader().checksum_;
+ dex_file_location_checksum_ = dex_file.GetLocationChecksum();
dex_file_offset_ = 0;
methods_offsets_.resize(dex_file.NumClassDefs());
}
@@ -688,7 +688,7 @@
size_t OatWriter::OatDexFile::SizeOf() const {
return sizeof(dex_file_location_size_)
+ dex_file_location_size_
- + sizeof(dex_file_checksum_)
+ + sizeof(dex_file_location_checksum_)
+ sizeof(dex_file_offset_)
+ (sizeof(methods_offsets_[0]) * methods_offsets_.size());
}
@@ -696,7 +696,7 @@
void OatWriter::OatDexFile::UpdateChecksum(OatHeader& oat_header) const {
oat_header.UpdateChecksum(&dex_file_location_size_, sizeof(dex_file_location_size_));
oat_header.UpdateChecksum(dex_file_location_data_, dex_file_location_size_);
- oat_header.UpdateChecksum(&dex_file_checksum_, sizeof(dex_file_checksum_));
+ oat_header.UpdateChecksum(&dex_file_location_checksum_, sizeof(dex_file_location_checksum_));
oat_header.UpdateChecksum(&dex_file_offset_, sizeof(dex_file_offset_));
oat_header.UpdateChecksum(&methods_offsets_[0],
sizeof(methods_offsets_[0]) * methods_offsets_.size());
@@ -711,8 +711,8 @@
PLOG(ERROR) << "Failed to write dex file location data to " << file->name();
return false;
}
- if (!file->WriteFully(&dex_file_checksum_, sizeof(dex_file_checksum_))) {
- PLOG(ERROR) << "Failed to write dex file checksum to " << file->name();
+ if (!file->WriteFully(&dex_file_location_checksum_, sizeof(dex_file_location_checksum_))) {
+ PLOG(ERROR) << "Failed to write dex file location checksum to " << file->name();
return false;
}
if (!file->WriteFully(&dex_file_offset_, sizeof(dex_file_offset_))) {
diff --git a/src/oat_writer.h b/src/oat_writer.h
index 93e4209..abb1f2e 100644
--- a/src/oat_writer.h
+++ b/src/oat_writer.h
@@ -115,7 +115,7 @@
// data to write
uint32_t dex_file_location_size_;
const uint8_t* dex_file_location_data_;
- uint32_t dex_file_checksum_;
+ uint32_t dex_file_location_checksum_;
uint32_t dex_file_offset_;
std::vector<uint32_t> methods_offsets_;
diff --git a/src/oatdump.cc b/src/oatdump.cc
index 60b1a3b..4ea2af1 100644
--- a/src/oatdump.cc
+++ b/src/oatdump.cc
@@ -127,7 +127,7 @@
os << " (" << dex_file_location << ")";
}
os << "\n";
- os << StringPrintf("checksum: %08x\n", oat_dex_file.GetDexFileChecksum());
+ os << StringPrintf("checksum: %08x\n", oat_dex_file.GetDexFileLocationChecksum());
const DexFile* dex_file = DexFile::Open(dex_file_location, "");
if (dex_file == NULL) {
os << "NOT FOUND\n\n";