diff options
author | 2012-02-01 15:02:31 -0800 | |
---|---|---|
committer | 2012-02-03 18:11:56 -0800 | |
commit | 5b332c89fa3fdd7dc184b22c2587d28af304d019 (patch) | |
tree | f348c63b6756adad52d1e242786df1c9136d6eee | |
parent | 9cb39392bacbd2a561c6bd840fff821ff7afaa7e (diff) |
Fix checksum verification when opening DexFiles from OatFiles
Change-Id: Ic3d13f3d591c34f159bf0739536a1751c3e7dc75
-rw-r--r-- | src/class_linker.cc | 220 | ||||
-rw-r--r-- | src/class_linker.h | 16 | ||||
-rw-r--r-- | src/dalvik_system_DexFile.cc | 70 | ||||
-rw-r--r-- | src/dex2oat.cc | 17 | ||||
-rw-r--r-- | src/dex_file.cc | 57 | ||||
-rw-r--r-- | src/dex_file.h | 36 | ||||
-rw-r--r-- | src/dex_file_test.cc | 13 | ||||
-rw-r--r-- | src/oat_file.cc | 71 | ||||
-rw-r--r-- | src/oat_file.h | 13 | ||||
-rw-r--r-- | src/oat_test.cc | 1 | ||||
-rw-r--r-- | src/oat_writer.cc | 10 | ||||
-rw-r--r-- | src/oat_writer.h | 2 | ||||
-rw-r--r-- | src/oatdump.cc | 2 |
13 files changed, 301 insertions, 227 deletions
diff --git a/src/class_linker.cc b/src/class_linker.cc index 87976a338e..f414c4b594 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 @@ OatFile* ClassLinker::OpenOat(const ImageSpace* space) { } 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 @@ class LockedFd { 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); - if (open_oat_file != NULL) { - return open_oat_file; + + uint32_t dex_location_checksum; + if (!DexFile::GetChecksum(dex_location, dex_location_checksum)) { + LOG(WARNING) << "Failed to compute checksum: " << dex_location; + return NULL; } - std::string oat_filename(OatFile::DexFilenameToOatFilename(dex_file.GetLocation())); - open_oat_file = FindOpenedOatFileFromOatLocation(oat_filename); + 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(); } - 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... - } - // 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; + // 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(); } - - // 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 @@ const OatFile* ClassLinker::FindOatFileFromOatLocation(const std::string& oat_lo 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 @@ void ClassLinker::InitFromImage() { << " 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 @@ void ClassLinker::LoadClass(const DexFile& dex_file, 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 @@ bool ClassLinker::VerifyClassUsingOatFile(const DexFile& dex_file, Class* klass) 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 @@ bool ClassLinker::VerifyClassUsingOatFile(const DexFile& dex_file, Class* klass) // 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 f2b44a3ed8..c49c03f403 100644 --- a/src/class_linker.h +++ b/src/class_linker.h @@ -247,12 +247,18 @@ class ClassLinker { 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 @@ class ClassLinker { } 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 67cb49bc9d..a2551412ff 100644 --- a/src/dalvik_system_DexFile.cc +++ b/src/dalvik_system_DexFile.cc @@ -84,60 +84,22 @@ static jint DexFile_openDexFile(JNIEnv* env, jclass, jstring javaSourceName, jst 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 @@ jboolean DexFile_isDexOptNeeded(JNIEnv* env, jclass, jstring javaFilename) { } } - 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 c4ca89483b..25c1d82722 100644 --- a/src/dex2oat.cc +++ b/src/dex2oat.cc @@ -379,6 +379,21 @@ bool ParseInt(const char* in, int* out) { 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 @@ int dex2oat(int argc, char** argv) { } 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 cb90e158b6..16fd407e53 100644 --- a/src/dex_file.cc +++ b/src/dex_file.cc @@ -60,18 +60,28 @@ DexFile::ClassPathEntry DexFile::FindInClassPath(const StringPiece& descriptor, 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 @@ const DexFile* DexFile::Open(const std::string& filename, 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 std::string StripLocationPrefix(const std::string& original_location, } 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 @@ const DexFile* DexFile::OpenFile(const std::string& filename, 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 @@ const DexFile* DexFile::Open(const ZipArchive& zip_archive, const std::string& l 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::Open(const ZipArchive& zip_archive, const std::string& l 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 d883f983c4..5d63408e90 100644 --- a/src/dex_file.h +++ b/src/dex_file.h @@ -54,7 +54,7 @@ class DexFile { // 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 @@ class DexFile { 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 @@ class DexFile { 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 @@ class DexFile { // 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 @@ class DexFile { // 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 @@ class DexFile { 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 @@ class DexFile { // 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 1e876bab03..f075feafcb 100644 --- a/src/dex_file_test.cc +++ b/src/dex_file_test.cc @@ -81,6 +81,19 @@ TEST_F(DexFileTest, Header) { 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 4bcd9679f1..cf8bafe2a5 100644 --- a/src/oat_file.cc +++ b/src/oat_file.cc @@ -34,15 +34,24 @@ std::string OatFile::DexFilenameToOatFilename(const std::string& location) { 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 @@ OatFile::~OatFile() { 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 @@ std::vector<const OatFile::OatDexFile*> OatFile::GetOatDexFiles() const { 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 @@ OatFile::OatDexFile::~OatDexFile() {} 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 4740ae77ab..2895d74d5f 100644 --- a/src/oat_file.h +++ b/src/oat_file.h @@ -39,6 +39,11 @@ class OatFile { 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 @@ class OatFile { 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 @@ class OatFile { 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 @@ class OatFile { 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 d64f81017e..0fd64ffb51 100644 --- a/src/oat_test.cc +++ b/src/oat_test.cc @@ -47,6 +47,7 @@ TEST_F(OatTest, WriteRead) { 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 94281c9203..e4c8135fec 100644 --- a/src/oat_writer.cc +++ b/src/oat_writer.cc @@ -680,7 +680,7 @@ OatWriter::OatDexFile::OatDexFile(const DexFile& dex_file) { 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 @@ OatWriter::OatDexFile::OatDexFile(const DexFile& dex_file) { 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 @@ size_t OatWriter::OatDexFile::SizeOf() const { 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 @@ bool OatWriter::OatDexFile::Write(File* file) const { 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 93e42098bc..abb1f2e74b 100644 --- a/src/oat_writer.h +++ b/src/oat_writer.h @@ -115,7 +115,7 @@ class OatWriter { // 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 60b1a3baef..4ea2af16df 100644 --- a/src/oatdump.cc +++ b/src/oatdump.cc @@ -127,7 +127,7 @@ class OatDump { 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"; |