diff options
Diffstat (limited to 'runtime/dex_file.cc')
| -rw-r--r-- | runtime/dex_file.cc | 124 |
1 files changed, 105 insertions, 19 deletions
diff --git a/runtime/dex_file.cc b/runtime/dex_file.cc index 10f34d973b..d368e416f9 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(), |