Build dexdump2 and dexlist without libart
Finally, flesh out libdexfile enough that it can replace libart for use
in dexdump2.
Bug: 22322814
Test: make -j 50 dexdump2 dexlist
dexdump2 -d fb/base.apk
dexlist fb/base.apk
Change-Id: Ibf9a1cd642cd473eea0b2208d72b4768aaa17f02
diff --git a/dexdump/Android.bp b/dexdump/Android.bp
index 4916d64..eca0844 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 1518e1d..16cb302 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 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 @@
// 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 382b551..2247e7a 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 @@
* 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 8ecff42..2703732 100644
--- a/dexlist/Android.bp
+++ b/dexlist/Android.bp
@@ -17,7 +17,11 @@
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 1ced8ca..8daaef1 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 @@
}
}
+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 @@
// 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 @@
* 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 07764b8..ac2c625 100644
--- a/runtime/Android.bp
+++ b/runtime/Android.bp
@@ -41,12 +41,17 @@
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 8c12bf3..b31d1e9 100644
--- a/runtime/dex/art_dex_file_loader.h
+++ b/runtime/dex/art_dex_file_loader.h
@@ -68,7 +68,7 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 c80ea19..ccad19f 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 @@
/*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,
+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";
- 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,
- 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 @@
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 4e45fb0..05a51d0 100644
--- a/runtime/dex/dex_file_loader.h
+++ b/runtime/dex/dex_file_loader.h
@@ -28,7 +28,8 @@
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 @@
// 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 @@
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 @@
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