diff options
-rw-r--r-- | dexdump/Android.bp | 27 | ||||
-rw-r--r-- | dexdump/dexdump.cc | 48 | ||||
-rw-r--r-- | dexdump/dexdump_main.cc | 10 | ||||
-rw-r--r-- | dexlist/Android.bp | 6 | ||||
-rw-r--r-- | dexlist/dexlist.cc | 55 | ||||
-rw-r--r-- | runtime/Android.bp | 5 | ||||
-rw-r--r-- | runtime/dex/art_dex_file_loader.h | 15 | ||||
-rw-r--r-- | runtime/dex/dex_file_loader.cc | 366 | ||||
-rw-r--r-- | runtime/dex/dex_file_loader.h | 130 |
9 files changed, 457 insertions, 205 deletions
diff --git a/dexdump/Android.bp b/dexdump/Android.bp index 4916d643c6..eca08448bc 100644 --- a/dexdump/Android.bp +++ b/dexdump/Android.bp @@ -14,33 +14,38 @@ // TODO(ajcbik): rename dexdump2 into dexdump when Dalvik version is removed -art_cc_binary { - name: "dexdump2", - host_supported: true, + +cc_defaults { + name: "dexdump_defaults", srcs: [ "dexdump_cfg.cc", "dexdump_main.cc", "dexdump.cc", ], cflags: ["-Wall", "-Werror"], + // TODO: fix b/72216369 and remove the need for this. + include_dirs: [ + "art/runtime" // dex utils. + ], +} + +art_cc_binary { + name: "dexdump2", + defaults: ["dexdump_defaults"], + host_supported: true, shared_libs: [ - "libart", + "libdexfile", "libbase", ], } art_cc_binary { name: "dexdumps", + defaults: ["dexdump_defaults"], host_supported: true, device_supported: false, - srcs: [ - "dexdump_cfg.cc", - "dexdump_main.cc", - "dexdump.cc", - ], - cflags: ["-Wall", "-Werror"], static_libs: [ - "libart", + "libdexfile", "libbase", ] + art_static_dependencies, target: { diff --git a/dexdump/dexdump.cc b/dexdump/dexdump.cc index 1518e1d205..16cb302a84 100644 --- a/dexdump/dexdump.cc +++ b/dexdump/dexdump.cc @@ -34,8 +34,13 @@ #include "dexdump.h" +#include <fcntl.h> #include <inttypes.h> #include <stdio.h> +#include <sys/mman.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> #include <iostream> #include <memory> @@ -44,7 +49,6 @@ #include "android-base/stringprintf.h" -#include "dex/art_dex_file_loader.h" #include "dex/code_item_accessors-no_art-inl.h" #include "dex/dex_file-inl.h" #include "dex/dex_file_exception_helpers.h" @@ -1868,6 +1872,34 @@ static void processDexFile(const char* fileName, } } +static bool openAndMapFile(const char* fileName, + const uint8_t** base, + size_t* size, + std::string* error_msg) { + int fd = open(fileName, O_RDONLY); + if (fd < 0) { + *error_msg = "open failed"; + return false; + } + struct stat st; + if (fstat(fd, &st) < 0) { + *error_msg = "stat failed"; + return false; + } + *size = st.st_size; + if (*size == 0) { + *error_msg = "size == 0"; + return false; + } + void* addr = mmap(nullptr /*addr*/, *size, PROT_READ, MAP_PRIVATE, fd, 0 /*offset*/); + if (addr == MAP_FAILED) { + *error_msg = "mmap failed"; + return false; + } + *base = reinterpret_cast<const uint8_t*>(addr); + return true; +} + /* * Processes a single file (either direct .dex or indirect .zip/.jar/.apk). */ @@ -1879,12 +1911,18 @@ int processFile(const char* fileName) { // If the file is not a .dex file, the function tries .zip/.jar/.apk files, // all of which are Zip archives with "classes.dex" inside. const bool kVerifyChecksum = !gOptions.ignoreBadChecksum; + const uint8_t* base = nullptr; + size_t size = 0; std::string error_msg; - // TODO: Use DexFileLoader when that is implemented. - const ArtDexFileLoader dex_file_loader; + if (!openAndMapFile(fileName, &base, &size, &error_msg)) { + fputs(error_msg.c_str(), stderr); + fputc('\n', stderr); + return -1; + } + const DexFileLoader dex_file_loader; std::vector<std::unique_ptr<const DexFile>> dex_files; - if (!dex_file_loader.Open( - fileName, fileName, /* verify */ true, kVerifyChecksum, &error_msg, &dex_files)) { + if (!dex_file_loader.OpenAll( + base, size, fileName, /*verify*/ true, kVerifyChecksum, &error_msg, &dex_files)) { // Display returned error message to user. Note that this error behavior // differs from the error messages shown by the original Dalvik dexdump. fputs(error_msg.c_str(), stderr); diff --git a/dexdump/dexdump_main.cc b/dexdump/dexdump_main.cc index 382b551a1a..2247e7a7e6 100644 --- a/dexdump/dexdump_main.cc +++ b/dexdump/dexdump_main.cc @@ -28,12 +28,6 @@ #include <string.h> #include <unistd.h> -#include <android-base/logging.h> - -#include <base/logging.h> // For InitLogging. -#include "mem_map.h" -#include "runtime.h" - namespace art { static const char* gProgName = "dexdump"; @@ -61,10 +55,6 @@ static void usage(void) { * Main driver of the dexdump utility. */ int dexdumpDriver(int argc, char** argv) { - // Art specific set up. - InitLogging(argv, Runtime::Abort); - MemMap::Init(); - // Reset options. bool wantUsage = false; memset(&gOptions, 0, sizeof(gOptions)); diff --git a/dexlist/Android.bp b/dexlist/Android.bp index 8ecff4210e..2703732db6 100644 --- a/dexlist/Android.bp +++ b/dexlist/Android.bp @@ -17,7 +17,11 @@ art_cc_binary { host_supported: true, srcs: ["dexlist.cc"], cflags: ["-Wall", "-Werror"], - shared_libs: ["libart", "libbase"], + shared_libs: ["libdexfile", "libbase"], + // TODO: fix b/72216369 and remove the need for this. + include_dirs: [ + "art/runtime" // dex utils. + ], } art_cc_test { diff --git a/dexlist/dexlist.cc b/dexlist/dexlist.cc index 1ced8ca771..8daaef19dc 100644 --- a/dexlist/dexlist.cc +++ b/dexlist/dexlist.cc @@ -23,16 +23,18 @@ * List all methods in all concrete classes in one or more DEX files. */ +#include <fcntl.h> +#include <inttypes.h> #include <stdio.h> #include <stdlib.h> +#include <sys/mman.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> -#include "base/logging.h" // For InitLogging. -#include "dex/art_dex_file_loader.h" #include "dex/code_item_accessors-no_art-inl.h" #include "dex/dex_file-inl.h" #include "dex/dex_file_loader.h" -#include "mem_map.h" -#include "runtime.h" namespace art { @@ -166,6 +168,34 @@ void dumpClass(const DexFile* pDexFile, u4 idx) { } } +static bool openAndMapFile(const char* fileName, + const uint8_t** base, + size_t* size, + std::string* error_msg) { + int fd = open(fileName, O_RDONLY); + if (fd < 0) { + *error_msg = "open failed"; + return false; + } + struct stat st; + if (fstat(fd, &st) < 0) { + *error_msg = "stat failed"; + return false; + } + *size = st.st_size; + if (*size == 0) { + *error_msg = "size == 0"; + return false; + } + void* addr = mmap(nullptr /*addr*/, *size, PROT_READ, MAP_PRIVATE, fd, 0 /*offset*/); + if (addr == MAP_FAILED) { + *error_msg = "mmap failed"; + return false; + } + *base = reinterpret_cast<const uint8_t*>(addr); + return true; +} + /* * Processes a single file (either direct .dex or indirect .zip/.jar/.apk). */ @@ -173,11 +203,18 @@ static int processFile(const char* fileName) { // If the file is not a .dex file, the function tries .zip/.jar/.apk files, // all of which are Zip archives with "classes.dex" inside. static constexpr bool kVerifyChecksum = true; + const uint8_t* base = nullptr; + size_t size = 0; std::string error_msg; + if (!openAndMapFile(fileName, &base, &size, &error_msg)) { + fputs(error_msg.c_str(), stderr); + fputc('\n', stderr); + return -1; + } std::vector<std::unique_ptr<const DexFile>> dex_files; - const ArtDexFileLoader dex_file_loader; - if (!dex_file_loader.Open( - fileName, fileName, /* verify */ true, kVerifyChecksum, &error_msg, &dex_files)) { + const DexFileLoader dex_file_loader; + if (!dex_file_loader.OpenAll( + base, size, fileName, /*verify*/ true, kVerifyChecksum, &error_msg, &dex_files)) { fputs(error_msg.c_str(), stderr); fputc('\n', stderr); return -1; @@ -209,10 +246,6 @@ static void usage(void) { * Main driver of the dexlist utility. */ int dexlistDriver(int argc, char** argv) { - // Art specific set up. - InitLogging(argv, Runtime::Abort); - MemMap::Init(); - // Reset options. bool wantUsage = false; memset(&gOptions, 0, sizeof(gOptions)); diff --git a/runtime/Android.bp b/runtime/Android.bp index 07764b8151..ac2c62597c 100644 --- a/runtime/Android.bp +++ b/runtime/Android.bp @@ -41,12 +41,17 @@ cc_defaults { target: { android: { static_libs: [ + "libziparchive", "libz", "libbase", ], + shared_libs: [ + "libutils", + ], }, host: { shared_libs: [ + "libziparchive", "libz", ], }, diff --git a/runtime/dex/art_dex_file_loader.h b/runtime/dex/art_dex_file_loader.h index 8c12bf3137..b31d1e94e0 100644 --- a/runtime/dex/art_dex_file_loader.h +++ b/runtime/dex/art_dex_file_loader.h @@ -68,7 +68,7 @@ class ArtDexFileLoader : public DexFileLoader { std::unique_ptr<MemMap> mem_map, bool verify, bool verify_checksum, - std::string* error_msg) const OVERRIDE; + std::string* error_msg) const; // Opens all .dex files found in the file, guessing the container format based on file extension. bool Open(const char* filename, @@ -76,7 +76,7 @@ class ArtDexFileLoader : public DexFileLoader { bool verify, bool verify_checksum, std::string* error_msg, - std::vector<std::unique_ptr<const DexFile>>* dex_files) const OVERRIDE; + std::vector<std::unique_ptr<const DexFile>>* dex_files) const; // Open a single dex file from an fd. This function closes the fd. std::unique_ptr<const DexFile> OpenDex(int fd, @@ -84,7 +84,7 @@ class ArtDexFileLoader : public DexFileLoader { bool verify, bool verify_checksum, bool mmap_shared, - std::string* error_msg) const OVERRIDE; + std::string* error_msg) const; // Opens dex files from within a .jar, .zip, or .apk file bool OpenZip(int fd, @@ -92,7 +92,7 @@ class ArtDexFileLoader : public DexFileLoader { bool verify, bool verify_checksum, std::string* error_msg, - std::vector<std::unique_ptr<const DexFile>>* dex_files) const OVERRIDE; + std::vector<std::unique_ptr<const DexFile>>* dex_files) const; private: std::unique_ptr<const DexFile> OpenFile(int fd, @@ -100,7 +100,7 @@ class ArtDexFileLoader : public DexFileLoader { bool verify, bool verify_checksum, bool mmap_shared, - std::string* error_msg) const OVERRIDE; + std::string* error_msg) const; // Open all classesXXX.dex files from a zip archive. bool OpenAllDexFilesFromZip(const ZipArchive& zip_archive, @@ -108,8 +108,7 @@ class ArtDexFileLoader : public DexFileLoader { bool verify, bool verify_checksum, std::string* error_msg, - std::vector<std::unique_ptr<const DexFile>>* dex_files) - const OVERRIDE; + std::vector<std::unique_ptr<const DexFile>>* dex_files) const; // Opens .dex file from the entry_name in a zip archive. error_code is undefined when non-null // return. @@ -119,7 +118,7 @@ class ArtDexFileLoader : public DexFileLoader { bool verify, bool verify_checksum, std::string* error_msg, - ZipOpenErrorCode* error_code) const OVERRIDE; + ZipOpenErrorCode* error_code) const; }; } // namespace art diff --git a/runtime/dex/dex_file_loader.cc b/runtime/dex/dex_file_loader.cc index c80ea199bc..ccad19f22e 100644 --- a/runtime/dex/dex_file_loader.cc +++ b/runtime/dex/dex_file_loader.cc @@ -16,25 +16,143 @@ #include "dex_file_loader.h" -// #include <sys/mman.h> // For the PROT_* and MAP_* constants. -// #include <sys/stat.h> - #include "android-base/stringprintf.h" -#include "base/file_magic.h" #include "base/stl_util.h" -// #include "base/systrace.h" -// #include "base/unix_file/fd_file.h" #include "compact_dex_file.h" #include "dex_file.h" #include "dex_file_verifier.h" #include "standard_dex_file.h" -// #include "zip_archive.h" +#include "ziparchive/zip_archive.h" + +// system/core/zip_archive definitions. +struct ZipEntry; +typedef void* ZipArchiveHandle; namespace art { +namespace { + +class VectorContainer : public DexFileContainer { + public: + explicit VectorContainer(std::vector<uint8_t>&& vector) : vector_(std::move(vector)) { } + virtual ~VectorContainer() OVERRIDE { } + + int GetPermissions() OVERRIDE { + return 0; + } + + bool IsReadOnly() OVERRIDE { + return true; + } + + bool EnableWrite() OVERRIDE { + return false; + } + + bool DisableWrite() OVERRIDE { + return false; + } + + private: + std::vector<uint8_t> vector_; + DISALLOW_COPY_AND_ASSIGN(VectorContainer); +}; + +} // namespace + using android::base::StringPrintf; +class DexZipArchive; + +class DexZipEntry { + public: + // Extract this entry to memory. + // Returns null on failure and sets error_msg. + const std::vector<uint8_t> Extract(std::string* error_msg) { + std::vector<uint8_t> map(GetUncompressedLength()); + if (map.size() == 0) { + DCHECK(!error_msg->empty()); + return map; + } + const int32_t error = ExtractToMemory(handle_, zip_entry_, map.data(), map.size()); + if (error) { + *error_msg = std::string(ErrorCodeString(error)); + } + return map; + } + + virtual ~DexZipEntry() { + delete zip_entry_; + } + + uint32_t GetUncompressedLength() { + return zip_entry_->uncompressed_length; + } + + uint32_t GetCrc32() { + return zip_entry_->crc32; + } + + private: + DexZipEntry(ZipArchiveHandle handle, + ::ZipEntry* zip_entry, + const std::string& entry_name) + : handle_(handle), zip_entry_(zip_entry), entry_name_(entry_name) {} + + ZipArchiveHandle handle_; + ::ZipEntry* const zip_entry_; + std::string const entry_name_; + + friend class DexZipArchive; + DISALLOW_COPY_AND_ASSIGN(DexZipEntry); +}; + +class DexZipArchive { + public: + // return new DexZipArchive instance on success, null on error. + static DexZipArchive* Open(const uint8_t* base, size_t size, std::string* error_msg) { + ZipArchiveHandle handle; + uint8_t* nonconst_base = const_cast<uint8_t*>(base); + const int32_t error = OpenArchiveFromMemory(nonconst_base, size, "ZipArchiveMemory", &handle); + if (error) { + *error_msg = std::string(ErrorCodeString(error)); + CloseArchive(handle); + return nullptr; + } + return new DexZipArchive(handle); + } + + DexZipEntry* Find(const char* name, std::string* error_msg) const { + DCHECK(name != nullptr); + // Resist the urge to delete the space. <: is a bigraph sequence. + std::unique_ptr< ::ZipEntry> zip_entry(new ::ZipEntry); + const int32_t error = FindEntry(handle_, ZipString(name), zip_entry.get()); + if (error) { + *error_msg = std::string(ErrorCodeString(error)); + return nullptr; + } + return new DexZipEntry(handle_, zip_entry.release(), name); + } + + ~DexZipArchive() { + CloseArchive(handle_); + } + + + private: + explicit DexZipArchive(ZipArchiveHandle handle) : handle_(handle) {} + ZipArchiveHandle handle_; + + friend class DexZipEntry; + DISALLOW_COPY_AND_ASSIGN(DexZipArchive); +}; + +static bool IsZipMagic(uint32_t magic) { + return (('P' == ((magic >> 0) & 0xff)) && + ('K' == ((magic >> 8) & 0xff))); +} + bool DexFileLoader::IsMagicValid(uint32_t magic) { return IsMagicValid(reinterpret_cast<uint8_t*>(&magic)); } @@ -114,80 +232,47 @@ std::unique_ptr<const DexFile> DexFileLoader::Open(const uint8_t* base, /*verify_result*/ nullptr); } -std::unique_ptr<const DexFile> DexFileLoader::Open(const std::string& location ATTRIBUTE_UNUSED, - uint32_t location_checksum ATTRIBUTE_UNUSED, - std::unique_ptr<MemMap> map ATTRIBUTE_UNUSED, - bool verify ATTRIBUTE_UNUSED, - bool verify_checksum ATTRIBUTE_UNUSED, - std::string* error_msg) const { - *error_msg = "UNIMPLEMENTED"; - return nullptr; -} - -bool DexFileLoader::Open( - const char* filename ATTRIBUTE_UNUSED, - const std::string& location ATTRIBUTE_UNUSED, - bool verify ATTRIBUTE_UNUSED, - bool verify_checksum ATTRIBUTE_UNUSED, - std::string* error_msg, - std::vector<std::unique_ptr<const DexFile>>* dex_files ATTRIBUTE_UNUSED) const { - *error_msg = "UNIMPLEMENTED"; - return false; -} - -std::unique_ptr<const DexFile> DexFileLoader::OpenDex( - int fd ATTRIBUTE_UNUSED, - const std::string& location ATTRIBUTE_UNUSED, - bool verify ATTRIBUTE_UNUSED, - bool verify_checksum ATTRIBUTE_UNUSED, - bool mmap_shared ATTRIBUTE_UNUSED, - std::string* error_msg) const { - *error_msg = "UNIMPLEMENTED"; - return nullptr; -} - -bool DexFileLoader::OpenZip( - int fd ATTRIBUTE_UNUSED, - const std::string& location ATTRIBUTE_UNUSED, - bool verify ATTRIBUTE_UNUSED, - bool verify_checksum ATTRIBUTE_UNUSED, - std::string* error_msg, - std::vector<std::unique_ptr<const DexFile>>* dex_files ATTRIBUTE_UNUSED) const { - *error_msg = "UNIMPLEMENTED"; - return false; -} - -std::unique_ptr<const DexFile> DexFileLoader::OpenFile( - int fd ATTRIBUTE_UNUSED, - const std::string& location ATTRIBUTE_UNUSED, - bool verify ATTRIBUTE_UNUSED, - bool verify_checksum ATTRIBUTE_UNUSED, - bool mmap_shared ATTRIBUTE_UNUSED, - std::string* error_msg) const { - *error_msg = "UNIMPLEMENTED"; - return nullptr; -} - -std::unique_ptr<const DexFile> DexFileLoader::OpenOneDexFileFromZip( - const ZipArchive& zip_archive ATTRIBUTE_UNUSED, - const char* entry_name ATTRIBUTE_UNUSED, - const std::string& location ATTRIBUTE_UNUSED, - bool verify ATTRIBUTE_UNUSED, - bool verify_checksum ATTRIBUTE_UNUSED, - std::string* error_msg, - ZipOpenErrorCode* error_code ATTRIBUTE_UNUSED) const { - *error_msg = "UNIMPLEMENTED"; - return nullptr; -} - -bool DexFileLoader::OpenAllDexFilesFromZip( - const ZipArchive& zip_archive ATTRIBUTE_UNUSED, - const std::string& location ATTRIBUTE_UNUSED, - bool verify ATTRIBUTE_UNUSED, - bool verify_checksum ATTRIBUTE_UNUSED, +bool DexFileLoader::OpenAll( + const uint8_t* base, + size_t size, + const std::string& location, + bool verify, + bool verify_checksum, std::string* error_msg, - std::vector<std::unique_ptr<const DexFile>>* dex_files ATTRIBUTE_UNUSED) const { - *error_msg = "UNIMPLEMENTED"; + std::vector<std::unique_ptr<const DexFile>>* dex_files) const { + DCHECK(dex_files != nullptr) << "DexFile::Open: out-param is nullptr"; + uint32_t magic = *reinterpret_cast<const uint32_t*>(base); + if (IsZipMagic(magic)) { + std::unique_ptr<DexZipArchive> zip_archive(DexZipArchive::Open(base, size, error_msg)); + if (zip_archive.get() == nullptr) { + DCHECK(!error_msg->empty()); + return false; + } + return OpenAllDexFilesFromZip(*zip_archive.get(), + location, + verify, + verify_checksum, + error_msg, + dex_files); + } + if (IsMagicValid(magic)) { + const DexFile::Header* dex_header = reinterpret_cast<const DexFile::Header*>(base); + std::unique_ptr<const DexFile> dex_file(Open(base, + size, + location, + dex_header->checksum_, + /*oat_dex_file*/ nullptr, + verify, + verify_checksum, + error_msg)); + if (dex_file.get() != nullptr) { + dex_files->push_back(std::move(dex_file)); + return true; + } else { + return false; + } + } + *error_msg = StringPrintf("Expected valid zip or dex file"); return false; } @@ -238,4 +323,125 @@ std::unique_ptr<DexFile> DexFileLoader::OpenCommon(const uint8_t* base, return dex_file; } +std::unique_ptr<const DexFile> DexFileLoader::OpenOneDexFileFromZip( + const DexZipArchive& zip_archive, + const char* entry_name, + const std::string& location, + bool verify, + bool verify_checksum, + std::string* error_msg, + ZipOpenErrorCode* error_code) const { + CHECK(!location.empty()); + std::unique_ptr<DexZipEntry> zip_entry(zip_archive.Find(entry_name, error_msg)); + if (zip_entry == nullptr) { + *error_code = ZipOpenErrorCode::kEntryNotFound; + return nullptr; + } + if (zip_entry->GetUncompressedLength() == 0) { + *error_msg = StringPrintf("Dex file '%s' has zero length", location.c_str()); + *error_code = ZipOpenErrorCode::kDexFileError; + return nullptr; + } + + std::vector<uint8_t> map(zip_entry->Extract(error_msg)); + if (map.size() == 0) { + *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; + } + VerifyResult verify_result; + std::unique_ptr<const DexFile> dex_file = OpenCommon(map.data(), + map.size(), + location, + zip_entry->GetCrc32(), + /*oat_dex_file*/ nullptr, + verify, + verify_checksum, + error_msg, + new VectorContainer(std::move(map)), + &verify_result); + if (dex_file == nullptr) { + if (verify_result == VerifyResult::kVerifyNotAttempted) { + *error_code = ZipOpenErrorCode::kDexFileError; + } else { + *error_code = ZipOpenErrorCode::kVerifyError; + } + return nullptr; + } + if (verify_result != VerifyResult::kVerifySucceeded) { + *error_code = ZipOpenErrorCode::kVerifyError; + return nullptr; + } + *error_code = ZipOpenErrorCode::kNoError; + return dex_file; +} + +// Technically we do not have a limitation with respect to the number of dex files that can be in a +// multidex APK. However, it's bad practice, as each dex file requires its own tables for symbols +// (types, classes, methods, ...) and dex caches. So warn the user that we open a zip with what +// seems an excessive number. +static constexpr size_t kWarnOnManyDexFilesThreshold = 100; + +bool DexFileLoader::OpenAllDexFilesFromZip( + const DexZipArchive& zip_archive, + const std::string& location, + bool verify, + bool verify_checksum, + std::string* error_msg, + std::vector<std::unique_ptr<const DexFile>>* dex_files) const { + DCHECK(dex_files != nullptr) << "DexFile::OpenFromZip: out-param is nullptr"; + ZipOpenErrorCode error_code; + std::unique_ptr<const DexFile> dex_file(OpenOneDexFileFromZip(zip_archive, + kClassesDex, + location, + verify, + verify_checksum, + error_msg, + &error_code)); + if (dex_file.get() == nullptr) { + return false; + } else { + // Had at least classes.dex. + dex_files->push_back(std::move(dex_file)); + + // Now try some more. + + // 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. + + for (size_t i = 1; ; ++i) { + std::string name = GetMultiDexClassesDexName(i); + std::string fake_location = GetMultiDexLocation(i, location.c_str()); + std::unique_ptr<const DexFile> next_dex_file(OpenOneDexFileFromZip(zip_archive, + name.c_str(), + fake_location, + verify, + verify_checksum, + error_msg, + &error_code)); + if (next_dex_file.get() == nullptr) { + if (error_code != ZipOpenErrorCode::kEntryNotFound) { + LOG(WARNING) << "Zip open failed: " << *error_msg; + } + break; + } else { + dex_files->push_back(std::move(next_dex_file)); + } + + if (i == kWarnOnManyDexFilesThreshold) { + LOG(WARNING) << location << " has in excess of " << kWarnOnManyDexFilesThreshold + << " dex files. Please consider coalescing and shrinking the number to " + " avoid runtime overhead."; + } + + if (i == std::numeric_limits<size_t>::max()) { + LOG(ERROR) << "Overflow in number of dex files!"; + break; + } + } + + return true; + } +} } // namespace art diff --git a/runtime/dex/dex_file_loader.h b/runtime/dex/dex_file_loader.h index 4e45fb03b8..05a51d09b3 100644 --- a/runtime/dex/dex_file_loader.h +++ b/runtime/dex/dex_file_loader.h @@ -28,7 +28,8 @@ class DexFile; class DexFileContainer; class MemMap; class OatDexFile; -class ZipArchive; + +class DexZipArchive; // Class that is used to open dex files and deal with corresponding multidex and location logic. class DexFileLoader { @@ -46,68 +47,10 @@ class DexFileLoader { // Return true if the corresponding version and magic is valid. static bool IsVersionAndMagicValid(const uint8_t* magic); - virtual ~DexFileLoader() { } - - // Returns the checksums of a file for comparison with GetLocationChecksum(). - // For .dex files, this is the single header checksum. - // For zip files, this is the zip entry CRC32 checksum for classes.dex and - // each additional multidex entry classes2.dex, classes3.dex, etc. - // If a valid zip_fd is provided the file content will be read directly from - // the descriptor and `filename` will be used as alias for error logging. If - // zip_fd is -1, the method will try to open the `filename` and read the - // content from it. - // Return true if the checksums could be found, false otherwise. - virtual bool GetMultiDexChecksums(const char* filename, - std::vector<uint32_t>* checksums, - std::string* error_msg, - int zip_fd = -1) 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); - // Opens .dex file, backed by existing memory - virtual std::unique_ptr<const DexFile> Open(const uint8_t* base, - size_t size, - const std::string& location, - uint32_t location_checksum, - const OatDexFile* oat_dex_file, - bool verify, - bool verify_checksum, - std::string* error_msg) const; - - // Opens .dex file that has been memory-mapped by the caller. - virtual std::unique_ptr<const DexFile> Open(const std::string& location, - uint32_t location_checkum, - std::unique_ptr<MemMap> mem_map, - bool verify, - bool verify_checksum, - std::string* error_msg) const; - - // Opens all .dex files found in the file, guessing the container format based on file extension. - virtual bool Open(const char* filename, - const std::string& location, - bool verify, - bool verify_checksum, - std::string* error_msg, - std::vector<std::unique_ptr<const DexFile>>* dex_files) const; - - // Open a single dex file from an fd. This function closes the fd. - virtual std::unique_ptr<const DexFile> OpenDex(int fd, - const std::string& location, - bool verify, - bool verify_checksum, - bool mmap_shared, - std::string* error_msg) const; - - // Opens dex files from within a .jar, .zip, or .apk file - virtual bool OpenZip(int fd, - const std::string& location, - bool verify, - bool verify_checksum, - std::string* error_msg, - std::vector<std::unique_ptr<const DexFile>>* dex_files) const; - // Return the name of the index-th classes.dex in a multidex zip file. This is classes.dex for // index == 0, and classes{index + 1}.dex else. static std::string GetMultiDexClassesDexName(size_t index); @@ -151,6 +94,42 @@ class DexFileLoader { return (pos == std::string::npos) ? std::string() : location.substr(pos); } + virtual ~DexFileLoader() { } + + // Returns the checksums of a file for comparison with GetLocationChecksum(). + // For .dex files, this is the single header checksum. + // For zip files, this is the zip entry CRC32 checksum for classes.dex and + // each additional multidex entry classes2.dex, classes3.dex, etc. + // If a valid zip_fd is provided the file content will be read directly from + // the descriptor and `filename` will be used as alias for error logging. If + // zip_fd is -1, the method will try to open the `filename` and read the + // content from it. + // Return true if the checksums could be found, false otherwise. + virtual bool GetMultiDexChecksums(const char* filename, + std::vector<uint32_t>* checksums, + std::string* error_msg, + int zip_fd = -1) const; + + // Opens .dex file, backed by existing memory + virtual std::unique_ptr<const DexFile> Open(const uint8_t* base, + size_t size, + const std::string& location, + uint32_t location_checksum, + const OatDexFile* oat_dex_file, + bool verify, + bool verify_checksum, + std::string* error_msg) const; + + // Opens all .dex files found in the memory map, guessing the container format based on file + // extension. + virtual bool OpenAll(const uint8_t* base, + size_t size, + const std::string& location, + bool verify, + bool verify_checksum, + std::string* error_msg, + std::vector<std::unique_ptr<const DexFile>>* dex_files) const; + protected: enum class ZipOpenErrorCode { kNoError, @@ -179,30 +158,23 @@ class DexFileLoader { VerifyResult* verify_result); private: - virtual std::unique_ptr<const DexFile> OpenFile(int fd, - const std::string& location, - bool verify, - bool verify_checksum, - bool mmap_shared, - std::string* error_msg) const; - // Open all classesXXX.dex files from a zip archive. - virtual bool OpenAllDexFilesFromZip(const ZipArchive& zip_archive, - const std::string& location, - bool verify, - bool verify_checksum, - std::string* error_msg, - std::vector<std::unique_ptr<const DexFile>>* dex_files) const; + bool OpenAllDexFilesFromZip(const DexZipArchive& zip_archive, + const std::string& location, + bool verify, + bool verify_checksum, + std::string* error_msg, + std::vector<std::unique_ptr<const DexFile>>* dex_files) const; // Opens .dex file from the entry_name in a zip archive. error_code is undefined when non-null // return. - virtual std::unique_ptr<const DexFile> OpenOneDexFileFromZip(const ZipArchive& zip_archive, - const char* entry_name, - const std::string& location, - bool verify, - bool verify_checksum, - std::string* error_msg, - ZipOpenErrorCode* error_code) const; + std::unique_ptr<const DexFile> OpenOneDexFileFromZip(const DexZipArchive& zip_archive, + const char* entry_name, + const std::string& location, + bool verify, + bool verify_checksum, + std::string* error_msg, + ZipOpenErrorCode* error_code) const; }; } // namespace art |