Simplify libdexfile external api.
Bug: 123517037
Test: m test-art-host-gtest
Test: libunwindstack_unit_test
Test: simpleperf_unit_test --gtest_filter=*dex*
Change-Id: I1bd9a6849ad79d9ddd0a0dfb93ea7c7d2311bf49
diff --git a/libdexfile/Android.bp b/libdexfile/Android.bp
index 63f2827..8aa287f 100644
--- a/libdexfile/Android.bp
+++ b/libdexfile/Android.bp
@@ -395,7 +395,10 @@
"external/dex_file_supp.cc",
],
runtime_libs: ["libdexfile_external"],
- shared_libs: ["liblog"],
+ shared_libs: [
+ "liblog",
+ "libbase",
+ ],
header_libs: ["libdexfile_external_headers"],
export_header_lib_headers: ["libdexfile_external_headers"],
diff --git a/libdexfile/external/dex_file_ext.cc b/libdexfile/external/dex_file_ext.cc
index c574ff3..65c0920 100644
--- a/libdexfile/external/dex_file_ext.cc
+++ b/libdexfile/external/dex_file_ext.cc
@@ -42,74 +42,29 @@
#include <dex/dex_file-inl.h>
#include <dex/dex_file_loader.h>
-namespace art {
-namespace {
-
-struct MethodCacheEntry {
- int32_t offset; // Offset relative to the start of the dex file header.
- int32_t len;
- int32_t index; // Method index.
-};
-
-class MappedFileContainer : public DexFileContainer {
- public:
- explicit MappedFileContainer(std::unique_ptr<android::base::MappedFile>&& map)
- : map_(std::move(map)) {}
- ~MappedFileContainer() override {}
- int GetPermissions() override { return 0; }
- bool IsReadOnly() override { return true; }
- bool EnableWrite() override { return false; }
- bool DisableWrite() override { return false; }
-
- private:
- std::unique_ptr<android::base::MappedFile> map_;
- DISALLOW_COPY_AND_ASSIGN(MappedFileContainer);
-};
-
-} // namespace
-} // namespace art
-
extern "C" {
-
-struct ExtDexFileString {
- const std::string str_;
-};
-
-static const ExtDexFileString empty_string{""};
-
-const ExtDexFileString* ExtDexFileMakeString(const char* str, size_t size) {
- if (size == 0) {
- return &empty_string;
- }
- return new ExtDexFileString{std::string(str, size)};
-}
-
-const char* ExtDexFileGetString(const ExtDexFileString* ext_string, /*out*/ size_t* size) {
- DCHECK(ext_string != nullptr);
- *size = ext_string->str_.size();
- return ext_string->str_.data();
-}
-
-void ExtDexFileFreeString(const ExtDexFileString* ext_string) {
- DCHECK(ext_string != nullptr);
- if (ext_string != &empty_string) {
- delete (ext_string);
- }
-}
-
// Wraps DexFile to add the caching needed by the external interface. This is
// what gets passed over as ExtDexFile*.
struct ExtDexFile {
+ struct MethodCacheEntry {
+ uint32_t offset; // Offset relative to the start of the dex file header.
+ uint32_t len;
+ uint32_t index; // Method index.
+ };
+
public:
std::unique_ptr<const art::DexFile> dex_file_;
explicit ExtDexFile(std::unique_ptr<const art::DexFile>&& dex_file)
: dex_file_(std::move(dex_file)) {}
- art::MethodCacheEntry* GetMethodCacheEntryForOffset(int64_t dex_offset) {
+ bool GetMethodDefIndex(uint32_t dex_offset, uint32_t* index, uint32_t* addr, uint32_t* size) {
// First look in the method cache.
auto it = method_cache_.upper_bound(dex_offset);
if (it != method_cache_.end() && dex_offset >= it->second.offset) {
- return &it->second;
+ *index = it->second.index;
+ *addr = it->second.offset;
+ *size = it->second.len;
+ return true;
}
uint32_t class_def_index;
@@ -122,17 +77,18 @@
continue;
}
- int32_t offset = reinterpret_cast<const uint8_t*>(code.Insns()) - dex_file_->Begin();
- int32_t len = code.InsnsSizeInBytes();
+ uint32_t offset = reinterpret_cast<const uint8_t*>(code.Insns()) - dex_file_->Begin();
+ uint32_t len = code.InsnsSizeInBytes();
if (offset <= dex_offset && dex_offset < offset + len) {
- int32_t index = method.GetIndex();
- auto res = method_cache_.emplace(offset + len, art::MethodCacheEntry{offset, len, index});
- return &res.first->second;
+ *index = method.GetIndex();
+ *addr = offset;
+ *size = len;
+ method_cache_.emplace(offset + len, MethodCacheEntry{offset, len, *index});
+ return true;
}
}
}
-
- return nullptr;
+ return false;
}
private:
@@ -183,18 +139,16 @@
// Binary search table with (end_dex_offset, class_def_index) entries.
std::vector<std::pair<uint32_t, uint32_t>> class_cache_;
- std::map<uint32_t, art::MethodCacheEntry> method_cache_; // end_dex_offset -> method.
+ std::map<uint32_t, MethodCacheEntry> method_cache_; // end_dex_offset -> method.
};
int ExtDexFileOpenFromMemory(const void* addr,
/*inout*/ size_t* size,
const char* location,
- /*out*/ const ExtDexFileString** ext_error_msg,
/*out*/ ExtDexFile** ext_dex_file) {
if (*size < sizeof(art::DexFile::Header)) {
*size = sizeof(art::DexFile::Header);
- *ext_error_msg = nullptr;
- return false;
+ return kExtDexFileNotEnoughData;
}
const art::DexFile::Header* header = reinterpret_cast<const art::DexFile::Header*>(addr);
@@ -206,23 +160,18 @@
// In practice, this should be fine, as such sharing only happens on disk.
uint32_t computed_file_size;
if (__builtin_add_overflow(header->data_off_, header->data_size_, &computed_file_size)) {
- *ext_error_msg = new ExtDexFileString{
- android::base::StringPrintf("Corrupt CompactDexFile header in '%s'", location)};
- return false;
+ return kExtDexFileInvalidHeader;
}
if (computed_file_size > file_size) {
file_size = computed_file_size;
}
} else if (!art::StandardDexFile::IsMagicValid(header->magic_)) {
- *ext_error_msg = new ExtDexFileString{
- android::base::StringPrintf("Unrecognized dex file header in '%s'", location)};
- return false;
+ return kExtDexFileInvalidHeader;
}
if (*size < file_size) {
*size = file_size;
- *ext_error_msg = nullptr;
- return false;
+ return kExtDexFileNotEnoughData;
}
std::string loc_str(location);
@@ -237,99 +186,19 @@
/*verify_checksum=*/false,
&error_msg);
if (dex_file == nullptr) {
- *ext_error_msg = new ExtDexFileString{std::move(error_msg)};
- return false;
+ LOG(ERROR) << "Can not opend dex file " << loc_str << ": " << error_msg;
+ return kExtDexFileError;
}
*ext_dex_file = new ExtDexFile(std::move(dex_file));
- return true;
-}
-
-int ExtDexFileOpenFromFd(int fd,
- off_t offset,
- const char* location,
- /*out*/ const ExtDexFileString** ext_error_msg,
- /*out*/ ExtDexFile** ext_dex_file) {
- size_t length;
- {
- struct stat sbuf;
- std::memset(&sbuf, 0, sizeof(sbuf));
- if (fstat(fd, &sbuf) == -1) {
- *ext_error_msg = new ExtDexFileString{
- android::base::StringPrintf("fstat '%s' failed: %s", location, std::strerror(errno))};
- return false;
- }
- if (S_ISDIR(sbuf.st_mode)) {
- *ext_error_msg = new ExtDexFileString{
- android::base::StringPrintf("Attempt to mmap directory '%s'", location)};
- return false;
- }
- length = sbuf.st_size;
- }
-
- if (length < offset + sizeof(art::DexFile::Header)) {
- *ext_error_msg = new ExtDexFileString{android::base::StringPrintf(
- "Offset %" PRId64 " too large for '%s' of size %zu",
- int64_t{offset},
- location,
- length)};
- return false;
- }
-
- // Cannot use MemMap in libartbase here, because it pulls in dlopen which we
- // can't have when being compiled statically.
- std::unique_ptr<android::base::MappedFile> map =
- android::base::MappedFile::FromFd(fd, offset, length, PROT_READ);
- if (map == nullptr) {
- *ext_error_msg = new ExtDexFileString{
- android::base::StringPrintf("mmap '%s' failed: %s", location, std::strerror(errno))};
- return false;
- }
-
- const art::DexFile::Header* header = reinterpret_cast<const art::DexFile::Header*>(map->data());
- uint32_t file_size;
- if (__builtin_add_overflow(offset, header->file_size_, &file_size)) {
- *ext_error_msg =
- new ExtDexFileString{android::base::StringPrintf("Corrupt header in '%s'", location)};
- return false;
- }
- if (length < file_size) {
- *ext_error_msg = new ExtDexFileString{
- android::base::StringPrintf("Dex file '%s' too short: expected %" PRIu32 ", got %" PRIu64,
- location,
- file_size,
- uint64_t{length})};
- return false;
- }
-
- void* addr = map->data();
- size_t size = map->size();
- auto container = std::make_unique<art::MappedFileContainer>(std::move(map));
-
- std::string loc_str(location);
- std::string error_msg;
- art::DexFileLoader loader;
- std::unique_ptr<const art::DexFile> dex_file = loader.Open(reinterpret_cast<const uint8_t*>(addr),
- size,
- loc_str,
- header->checksum_,
- /*oat_dex_file=*/nullptr,
- /*verify=*/false,
- /*verify_checksum=*/false,
- &error_msg,
- std::move(container));
- if (dex_file == nullptr) {
- *ext_error_msg = new ExtDexFileString{std::move(error_msg)};
- return false;
- }
- *ext_dex_file = new ExtDexFile(std::move(dex_file));
- return true;
+ return kExtDexFileOk;
}
int ExtDexFileGetMethodInfoForOffset(ExtDexFile* ext_dex_file,
- int64_t dex_offset,
- int with_signature,
- /*out*/ ExtDexFileMethodInfo* method_info) {
+ uint32_t dex_offset,
+ uint32_t flags,
+ ExtDexFileMethodInfoCallback* method_info_cb,
+ void* user_data) {
if (!ext_dex_file->dex_file_->IsInDataSection(ext_dex_file->dex_file_->Begin() + dex_offset)) {
return false; // The DEX offset is not within the bytecode of this dex file.
}
@@ -346,40 +215,49 @@
}
}
- art::MethodCacheEntry* entry = ext_dex_file->GetMethodCacheEntryForOffset(dex_offset);
- if (entry != nullptr) {
- method_info->offset = entry->offset;
- method_info->len = entry->len;
- method_info->name =
- new ExtDexFileString{ext_dex_file->dex_file_->PrettyMethod(entry->index, with_signature)};
- return true;
+ uint32_t method_index, addr, size;
+ if (!ext_dex_file->GetMethodDefIndex(dex_offset, &method_index, &addr, &size)) {
+ return false;
}
- return false;
+ bool with_signature = flags & kExtDexFileWithSignature;
+ std::string name = ext_dex_file->dex_file_->PrettyMethod(method_index, with_signature);
+ ExtDexFileMethodInfo info {
+ .sizeof_struct = sizeof(ExtDexFileMethodInfo),
+ .addr = addr,
+ .size = size,
+ .name = name.c_str(),
+ .name_size = name.size()
+ };
+ method_info_cb(user_data, &info);
+ return true;
}
void ExtDexFileGetAllMethodInfos(ExtDexFile* ext_dex_file,
- int with_signature,
+ uint32_t flags,
ExtDexFileMethodInfoCallback* method_info_cb,
void* user_data) {
+ const art::DexFile* dex_file = ext_dex_file->dex_file_.get();
for (art::ClassAccessor accessor : ext_dex_file->dex_file_->GetClasses()) {
for (const art::ClassAccessor::Method& method : accessor.GetMethods()) {
art::CodeItemInstructionAccessor code = method.GetInstructions();
- if (!code.HasCodeItem()) {
- continue;
+ if (code.HasCodeItem()) {
+ const uint8_t* insns = reinterpret_cast<const uint8_t*>(code.Insns());
+ bool with_signature = flags & kExtDexFileWithSignature;
+ std::string name = dex_file->PrettyMethod(method.GetIndex(), with_signature);
+ ExtDexFileMethodInfo info {
+ .sizeof_struct = sizeof(ExtDexFileMethodInfo),
+ .addr = static_cast<uint32_t>(insns - dex_file->Begin()),
+ .size = code.InsnsSizeInBytes(),
+ .name = name.c_str(),
+ .name_size = name.size()
+ };
+ method_info_cb(user_data, &info);
}
-
- ExtDexFileMethodInfo method_info;
- method_info.offset = static_cast<int32_t>(reinterpret_cast<const uint8_t*>(code.Insns()) -
- ext_dex_file->dex_file_->Begin());
- method_info.len = code.InsnsSizeInBytes();
- method_info.name = new ExtDexFileString{
- ext_dex_file->dex_file_->PrettyMethod(method.GetIndex(), with_signature)};
- method_info_cb(&method_info, user_data);
}
}
}
-void ExtDexFileFree(ExtDexFile* ext_dex_file) { delete (ext_dex_file); }
+void ExtDexFileClose(ExtDexFile* ext_dex_file) { delete (ext_dex_file); }
} // extern "C"
diff --git a/libdexfile/external/dex_file_supp.cc b/libdexfile/external/dex_file_supp.cc
index c0bfe54..7200451 100644
--- a/libdexfile/external/dex_file_supp.cc
+++ b/libdexfile/external/dex_file_supp.cc
@@ -17,7 +17,12 @@
#include "art_api/dex_file_support.h"
#include <dlfcn.h>
+#include <inttypes.h>
#include <mutex>
+#include <sys/stat.h>
+
+#include <android-base/mapped_file.h>
+#include <android-base/stringprintf.h>
#ifndef STATIC_LIB
// Not used in the static lib, so avoid a dependency on this header in
@@ -29,14 +34,10 @@
namespace dex {
#define FOR_ALL_DLFUNCS(MACRO) \
- MACRO(DexString, ExtDexFileMakeString) \
- MACRO(DexString, ExtDexFileGetString) \
- MACRO(DexString, ExtDexFileFreeString) \
MACRO(DexFile, ExtDexFileOpenFromMemory) \
- MACRO(DexFile, ExtDexFileOpenFromFd) \
MACRO(DexFile, ExtDexFileGetMethodInfoForOffset) \
MACRO(DexFile, ExtDexFileGetAllMethodInfos) \
- MACRO(DexFile, ExtDexFileFree)
+ MACRO(DexFile, ExtDexFileClose)
#ifdef STATIC_LIB
#define DEFINE_DLFUNC_PTR(CLASS, DLFUNC) decltype(DLFUNC)* CLASS::g_##DLFUNC = DLFUNC;
@@ -103,15 +104,97 @@
#endif
}
-DexFile::~DexFile() { g_ExtDexFileFree(ext_dex_file_); }
+DexFile::~DexFile() { g_ExtDexFileClose(ext_dex_file_); }
-MethodInfo DexFile::AbsorbMethodInfo(const ExtDexFileMethodInfo& ext_method_info) {
- return {ext_method_info.offset, ext_method_info.len, DexString(ext_method_info.name)};
+std::unique_ptr<DexFile> DexFile::OpenFromMemory(const void* addr,
+ size_t* size,
+ const std::string& location,
+ /*out*/ std::string* error_msg) {
+ if (UNLIKELY(g_ExtDexFileOpenFromMemory == nullptr)) {
+ // Load libdexfile_external.so in this factory function, so instance
+ // methods don't need to check this.
+ LoadLibdexfileExternal();
+ }
+ ExtDexFile* ext_dex_file;
+ int res = g_ExtDexFileOpenFromMemory(addr, size, location.c_str(), &ext_dex_file);
+ switch (static_cast<ExtDexFileError>(res)) {
+ case kExtDexFileOk:
+ return std::unique_ptr<DexFile>(new DexFile(ext_dex_file));
+ case kExtDexFileInvalidHeader:
+ *error_msg = std::string("Invalid DexFile header ") + location;
+ return nullptr;
+ case kExtDexFileNotEnoughData:
+ *error_msg = std::string("Not enough data");
+ return nullptr;
+ case kExtDexFileError:
+ break;
+ }
+ *error_msg = std::string("Failed to open DexFile ") + location;
+ return nullptr;
}
-void DexFile::AddMethodInfoCallback(const ExtDexFileMethodInfo* ext_method_info, void* ctx) {
- auto vect = static_cast<MethodInfoVector*>(ctx);
- vect->emplace_back(AbsorbMethodInfo(*ext_method_info));
+std::unique_ptr<DexFile> DexFile::OpenFromFd(int fd,
+ off_t offset,
+ const std::string& location,
+ /*out*/ std::string* error_msg) {
+ using android::base::StringPrintf;
+ size_t length;
+ {
+ struct stat sbuf;
+ std::memset(&sbuf, 0, sizeof(sbuf));
+ if (fstat(fd, &sbuf) == -1) {
+ *error_msg = StringPrintf("fstat '%s' failed: %s", location.c_str(), std::strerror(errno));
+ return nullptr;
+ }
+ if (S_ISDIR(sbuf.st_mode)) {
+ *error_msg = StringPrintf("Attempt to mmap directory '%s'", location.c_str());
+ return nullptr;
+ }
+ length = sbuf.st_size;
+ }
+
+ if (static_cast<off_t>(length) < offset) {
+ *error_msg = StringPrintf(
+ "Offset %" PRId64 " too large for '%s' of size %zu",
+ int64_t{offset},
+ location.c_str(),
+ length);
+ return nullptr;
+ }
+ length -= offset;
+
+ std::unique_ptr<android::base::MappedFile> map;
+ map = android::base::MappedFile::FromFd(fd, offset, length, PROT_READ);
+ if (map == nullptr) {
+ *error_msg = StringPrintf("mmap '%s' failed: %s", location.c_str(), std::strerror(errno));
+ return nullptr;
+ }
+
+ std::unique_ptr<DexFile> dex = OpenFromMemory(map->data(), &length, location, error_msg);
+ if (dex != nullptr) {
+ dex->map_ = std::move(map); // Ensure the map gets freed with the dex file.
+ }
+ return dex;
+}
+
+MethodInfo DexFile::GetMethodInfoForOffset(int64_t dex_offset, bool with_signature) {
+ MethodInfo res{};
+ auto set_method = [](void* ctx, ExtDexFileMethodInfo* info) {
+ *reinterpret_cast<MethodInfo*>(ctx) = AbsorbMethodInfo(info);
+ };
+ uint32_t flags = with_signature ? kExtDexFileWithSignature : 0;
+ g_ExtDexFileGetMethodInfoForOffset(ext_dex_file_, dex_offset, flags, set_method, &res);
+ return res;
+}
+
+std::vector<MethodInfo> DexFile::GetAllMethodInfos(bool with_signature) {
+ std::vector<MethodInfo> res;
+ auto add_method = [](void* ctx, ExtDexFileMethodInfo* info) {
+ reinterpret_cast<std::vector<MethodInfo>*>(ctx)->push_back(AbsorbMethodInfo(info));
+ };
+ uint32_t flags = with_signature ? kExtDexFileWithSignature : 0;
+ g_ExtDexFileGetAllMethodInfos(ext_dex_file_, flags, add_method, &res);
+ return res;
}
} // namespace dex
diff --git a/libdexfile/external/dex_file_supp_test.cc b/libdexfile/external/dex_file_supp_test.cc
index 0d7644a..ff263fc 100644
--- a/libdexfile/external/dex_file_supp_test.cc
+++ b/libdexfile/external/dex_file_supp_test.cc
@@ -49,69 +49,12 @@
0x00000002, 0x00000173, 0x00002000, 0x00000001, 0x0000017e, 0x00001000, 0x00000001, 0x0000018c,
};
-TEST(DexStringTest, alloc_string) {
- auto s = DexString("123");
- EXPECT_EQ(std::string_view(s), "123");
-}
-
-TEST(DexStringTest, alloc_empty_string) {
- auto s = DexString("");
- EXPECT_TRUE(std::string_view(s).empty());
-}
-
-TEST(DexStringTest, move_construct) {
- auto s1 = DexString("foo");
- auto s2 = DexString(std::move(s1));
- EXPECT_TRUE(std::string_view(s1).empty()); // NOLINT bugprone-use-after-move
- EXPECT_EQ(std::string_view(s2), "foo");
-}
-
-TEST(DexStringTest, move_assign) {
- auto s1 = DexString("foo");
- DexString s2;
- EXPECT_TRUE(std::string_view(s2).empty());
- s2 = std::move(s1);
- EXPECT_TRUE(std::string_view(s1).empty()); // NOLINT bugprone-use-after-move
- EXPECT_EQ(std::string_view(s2), "foo");
-}
-
-TEST(DexStringTest, reassign) {
- auto s = DexString("foo");
- s = DexString("bar");
- EXPECT_EQ(std::string_view(s), "bar");
-}
-
-TEST(DexStringTest, data_access) {
- auto s = DexString("foo");
- EXPECT_STREQ(s.data(), "foo");
- EXPECT_STREQ(s.c_str(), "foo");
-}
-
-TEST(DexStringTest, size_access) {
- auto s = DexString("foo");
- EXPECT_EQ(s.size(), size_t{3});
- EXPECT_EQ(s.length(), size_t{3});
-}
-
-TEST(DexStringTest, equality) {
- auto s = DexString("foo");
- EXPECT_EQ(s, DexString("foo"));
- EXPECT_FALSE(s == DexString("bar"));
-}
-
-TEST(DexStringTest, equality_with_nul) {
- auto s = DexString(std::string("foo\0bar", 7));
- EXPECT_EQ(s.size(), size_t{7});
- EXPECT_EQ(s, DexString(std::string("foo\0bar", 7)));
- EXPECT_FALSE(s == DexString(std::string("foo\0baz", 7)));
-}
-
TEST(DexFileTest, from_memory_header_too_small) {
size_t size = sizeof(art::DexFile::Header) - 1;
std::string error_msg;
EXPECT_EQ(DexFile::OpenFromMemory(kDexData, &size, "", &error_msg), nullptr);
EXPECT_EQ(size, sizeof(art::DexFile::Header));
- EXPECT_TRUE(error_msg.empty());
+ EXPECT_FALSE(error_msg.empty());
}
TEST(DexFileTest, from_memory_file_too_small) {
@@ -119,7 +62,7 @@
std::string error_msg;
EXPECT_EQ(DexFile::OpenFromMemory(kDexData, &size, "", &error_msg), nullptr);
EXPECT_EQ(size, sizeof(kDexData));
- EXPECT_TRUE(error_msg.empty());
+ EXPECT_FALSE(error_msg.empty());
}
static std::unique_ptr<DexFile> GetTestDexData() {
@@ -259,8 +202,8 @@
ASSERT_NE(dex_file, nullptr);
std::vector<MethodInfo> infos;
- infos.emplace_back(MethodInfo{0x100, 8, DexString("Main.<init>")});
- infos.emplace_back(MethodInfo{0x118, 2, DexString("Main.main")});
+ infos.emplace_back(MethodInfo{0x100, 8, std::string("Main.<init>")});
+ infos.emplace_back(MethodInfo{0x118, 2, std::string("Main.main")});
ASSERT_EQ(dex_file->GetAllMethodInfos(false), infos);
}
@@ -269,8 +212,8 @@
ASSERT_NE(dex_file, nullptr);
std::vector<MethodInfo> infos;
- infos.emplace_back(MethodInfo{0x100, 8, DexString("void Main.<init>()")});
- infos.emplace_back(MethodInfo{0x118, 2, DexString("void Main.main(java.lang.String[])")});
+ infos.emplace_back(MethodInfo{0x100, 8, std::string("void Main.<init>()")});
+ infos.emplace_back(MethodInfo{0x118, 2, std::string("void Main.main(java.lang.String[])")});
ASSERT_EQ(dex_file->GetAllMethodInfos(true), infos);
}
diff --git a/libdexfile/external/include/art_api/dex_file_external.h b/libdexfile/external/include/art_api/dex_file_external.h
index b29e759..b880335 100644
--- a/libdexfile/external/include/art_api/dex_file_external.h
+++ b/libdexfile/external/include/art_api/dex_file_external.h
@@ -20,6 +20,7 @@
// Dex file external API
#include <sys/types.h>
+#include <stdint.h>
#ifdef __cplusplus
extern "C" {
@@ -28,59 +29,53 @@
// This is the stable C ABI that backs art_api::dex below. Structs and functions
// may only be added here. C++ users should use dex_file_support.h instead.
-// Opaque wrapper for an std::string allocated in libdexfile which must be freed
-// using ExtDexFileFreeString.
-struct ExtDexFileString;
-
-// Returns an ExtDexFileString initialized to the given string.
-const struct ExtDexFileString* ExtDexFileMakeString(const char* str, size_t size);
-
-// Returns a pointer to the underlying null-terminated character array and its
-// size for the given ExtDexFileString.
-const char* ExtDexFileGetString(const struct ExtDexFileString* ext_string, /*out*/ size_t* size);
-
-// Frees an ExtDexFileString.
-void ExtDexFileFreeString(const struct ExtDexFileString* ext_string);
-
struct ExtDexFileMethodInfo {
- int32_t offset;
- int32_t len;
- const struct ExtDexFileString* name;
+ size_t sizeof_struct; // Size of this structure (to allow future extensions).
+ uint32_t addr; // Start of dex byte-code relative to the start of the dex file.
+ uint32_t size; // Size of the dex byte-code in bytes.
+ const char* name;
+ size_t name_size;
+};
+
+enum ExtDexFileError {
+ kExtDexFileOk = 0,
+ kExtDexFileError = 1, // Unspecified error.
+ kExtDexFileNotEnoughData = 2,
+ kExtDexFileInvalidHeader = 3,
+};
+
+enum ExtDexFileMethodFlags {
+ kExtDexFileWithSignature = 1,
};
struct ExtDexFile;
-// See art_api::dex::DexFile::OpenFromMemory. Returns true on success.
+// Try to open a dex file in the given memory range.
+// If the memory range is too small, larger suggest size is written to the argument.
int ExtDexFileOpenFromMemory(const void* addr,
/*inout*/ size_t* size,
const char* location,
- /*out*/ const struct ExtDexFileString** error_msg,
/*out*/ struct ExtDexFile** ext_dex_file);
-// See art_api::dex::DexFile::OpenFromFd. Returns true on success.
-int ExtDexFileOpenFromFd(int fd,
- off_t offset,
- const char* location,
- /*out*/ const struct ExtDexFileString** error_msg,
- /*out*/ struct ExtDexFile** ext_dex_file);
+// Callback used to return information about a dex method.
+typedef void ExtDexFileMethodInfoCallback(void* user_data,
+ struct ExtDexFileMethodInfo* method_info);
-// See art_api::dex::DexFile::GetMethodInfoForOffset. Returns true on success.
+// Find a single dex method based on the given dex offset.
int ExtDexFileGetMethodInfoForOffset(struct ExtDexFile* ext_dex_file,
- int64_t dex_offset,
- int with_signature,
- /*out*/ struct ExtDexFileMethodInfo* method_info);
+ uint32_t dex_offset,
+ uint32_t flags,
+ ExtDexFileMethodInfoCallback* method_info_cb,
+ void* user_data);
-typedef void ExtDexFileMethodInfoCallback(const struct ExtDexFileMethodInfo* ext_method_info,
- void* user_data);
-
-// See art_api::dex::DexFile::GetAllMethodInfos.
+// Return all dex methods in the dex file.
void ExtDexFileGetAllMethodInfos(struct ExtDexFile* ext_dex_file,
- int with_signature,
+ uint32_t flags,
ExtDexFileMethodInfoCallback* method_info_cb,
void* user_data);
-// Frees an ExtDexFile.
-void ExtDexFileFree(struct ExtDexFile* ext_dex_file);
+// Release all associated memory.
+void ExtDexFileClose(struct ExtDexFile* ext_dex_file);
#ifdef __cplusplus
} // extern "C"
diff --git a/libdexfile/external/include/art_api/dex_file_support.h b/libdexfile/external/include/art_api/dex_file_support.h
index 404fa65..3fbf169 100644
--- a/libdexfile/external/include/art_api/dex_file_support.h
+++ b/libdexfile/external/include/art_api/dex_file_support.h
@@ -27,6 +27,7 @@
#include <vector>
#include <android-base/macros.h>
+#include <android-base/mapped_file.h>
#include "art_api/dex_file_external.h"
@@ -44,75 +45,11 @@
// below.
void LoadLibdexfileExternal();
-// Minimal std::string look-alike for a string returned from libdexfile.
-class DexString final {
- public:
- DexString(DexString&& dex_str) noexcept : ext_string_(dex_str.ext_string_) {
- dex_str.ext_string_ = MakeExtDexFileString("", 0);
- }
- explicit DexString(const char* str = "")
- : ext_string_(MakeExtDexFileString(str, std::strlen(str))) {}
- explicit DexString(std::string_view str)
- : ext_string_(MakeExtDexFileString(str.data(), str.size())) {}
- ~DexString() { g_ExtDexFileFreeString(ext_string_); }
-
- DexString& operator=(DexString&& dex_str) noexcept {
- std::swap(ext_string_, dex_str.ext_string_);
- return *this;
- }
-
- const char* data() const {
- size_t ignored;
- return g_ExtDexFileGetString(ext_string_, &ignored);
- }
- const char* c_str() const { return data(); }
-
- size_t size() const {
- size_t len;
- (void)g_ExtDexFileGetString(ext_string_, &len);
- return len;
- }
- size_t length() const { return size(); }
-
- operator std::string_view() const {
- size_t len;
- const char* chars = g_ExtDexFileGetString(ext_string_, &len);
- return std::string_view(chars, len);
- }
-
- private:
- friend bool TryLoadLibdexfileExternal(std::string* error_msg);
- friend class DexFile;
- friend bool operator==(const DexString&, const DexString&);
- explicit DexString(const ExtDexFileString* ext_string) : ext_string_(ext_string) {}
- const ExtDexFileString* ext_string_; // Owned instance. Never nullptr.
-
- // These are initialized by TryLoadLibdexfileExternal.
- static decltype(ExtDexFileMakeString)* g_ExtDexFileMakeString;
- static decltype(ExtDexFileGetString)* g_ExtDexFileGetString;
- static decltype(ExtDexFileFreeString)* g_ExtDexFileFreeString;
-
- static const struct ExtDexFileString* MakeExtDexFileString(const char* str, size_t size) {
- if (UNLIKELY(g_ExtDexFileMakeString == nullptr)) {
- LoadLibdexfileExternal();
- }
- return g_ExtDexFileMakeString(str, size);
- }
-
- DISALLOW_COPY_AND_ASSIGN(DexString);
-};
-
-inline bool operator==(const DexString& s1, const DexString& s2) {
- size_t l1, l2;
- const char* str1 = DexString::g_ExtDexFileGetString(s1.ext_string_, &l1);
- const char* str2 = DexString::g_ExtDexFileGetString(s2.ext_string_, &l2);
- // Use memcmp to avoid assumption about absence of null characters in the strings.
- return l1 == l2 && !std::memcmp(str1, str2, l1);
-}
+using DexString = std::string;
struct MethodInfo {
- int32_t offset; // Code offset relative to the start of the dex file header
- int32_t len; // Code length
+ uint32_t offset = 0; // Code offset relative to the start of the dex file header
+ uint32_t len = 0; // Code length
DexString name;
};
@@ -126,20 +63,21 @@
class DexFile {
public:
DexFile(DexFile&& dex_file) noexcept {
- ext_dex_file_ = dex_file.ext_dex_file_;
- dex_file.ext_dex_file_ = nullptr;
+ std::swap(ext_dex_file_, dex_file.ext_dex_file_);
+ std::swap(map_, dex_file.map_);
}
explicit DexFile(std::unique_ptr<DexFile>& dex_file) noexcept {
- ext_dex_file_ = dex_file->ext_dex_file_;
- dex_file->ext_dex_file_ = nullptr;
- dex_file.reset(nullptr);
+ std::swap(ext_dex_file_, dex_file->ext_dex_file_);
+ std::swap(map_, dex_file->map_);
+ dex_file.reset();
}
+
virtual ~DexFile();
// Interprets a chunk of memory as a dex file. As long as *size is too small,
// returns nullptr, sets *size to a new size to try again with, and sets
- // *error_msg to "". That might happen repeatedly. Also returns nullptr
+ // *error_msg. That might happen repeatedly. Also returns nullptr
// on error in which case *error_msg is set to a nonempty string.
//
// location is a string that describes the dex file, and is preferably its
@@ -149,20 +87,7 @@
static std::unique_ptr<DexFile> OpenFromMemory(const void* addr,
size_t* size,
const std::string& location,
- /*out*/ std::string* error_msg) {
- if (UNLIKELY(g_ExtDexFileOpenFromMemory == nullptr)) {
- // Load libdexfile_external.so in this factory function, so instance
- // methods don't need to check this.
- LoadLibdexfileExternal();
- }
- ExtDexFile* ext_dex_file;
- const ExtDexFileString* ext_error_msg = nullptr;
- if (g_ExtDexFileOpenFromMemory(addr, size, location.c_str(), &ext_error_msg, &ext_dex_file)) {
- return std::unique_ptr<DexFile>(new DexFile(ext_dex_file));
- }
- *error_msg = (ext_error_msg == nullptr) ? "" : std::string(DexString(ext_error_msg));
- return nullptr;
- }
+ /*out*/ std::string* error_msg);
// mmaps the given file offset in the open fd and reads a dexfile from there.
// Returns nullptr on error in which case *error_msg is set.
@@ -172,65 +97,39 @@
static std::unique_ptr<DexFile> OpenFromFd(int fd,
off_t offset,
const std::string& location,
- /*out*/ std::string* error_msg) {
- if (UNLIKELY(g_ExtDexFileOpenFromFd == nullptr)) {
- // Load libdexfile_external.so in this factory function, so instance
- // methods don't need to check this.
- LoadLibdexfileExternal();
- }
- ExtDexFile* ext_dex_file;
- const ExtDexFileString* ext_error_msg = nullptr;
- if (g_ExtDexFileOpenFromFd(fd, offset, location.c_str(), &ext_error_msg, &ext_dex_file)) {
- return std::unique_ptr<DexFile>(new DexFile(ext_dex_file));
- }
- *error_msg = std::string(DexString(ext_error_msg));
- return nullptr;
- }
+ /*out*/ std::string* error_msg);
// Given an offset relative to the start of the dex file header, if there is a
// method whose instruction range includes that offset then returns info about
// it, otherwise returns a struct with offset == 0. MethodInfo.name receives
// the full function signature if with_signature is set, otherwise it gets the
// class and method name only.
- MethodInfo GetMethodInfoForOffset(int64_t dex_offset, bool with_signature) {
- ExtDexFileMethodInfo ext_method_info;
- if (g_ExtDexFileGetMethodInfoForOffset(ext_dex_file_,
- dex_offset,
- with_signature,
- &ext_method_info)) {
- return AbsorbMethodInfo(ext_method_info);
- }
- return {/*offset=*/0, /*len=*/0, /*name=*/DexString()};
- }
+ MethodInfo GetMethodInfoForOffset(int64_t dex_offset, bool with_signature);
// Returns info structs about all methods in the dex file. MethodInfo.name
// receives the full function signature if with_signature is set, otherwise it
// gets the class and method name only.
- std::vector<MethodInfo> GetAllMethodInfos(bool with_signature) {
- MethodInfoVector res;
- g_ExtDexFileGetAllMethodInfos(ext_dex_file_,
- with_signature,
- AddMethodInfoCallback,
- static_cast<void*>(&res));
- return res;
- }
+ std::vector<MethodInfo> GetAllMethodInfos(bool with_signature);
private:
+ static inline MethodInfo AbsorbMethodInfo(const ExtDexFileMethodInfo* info) {
+ return {
+ .offset = info->addr,
+ .len = info->size,
+ .name = std::string(info->name, info->name_size)
+ };
+ }
+
friend bool TryLoadLibdexfileExternal(std::string* error_msg);
explicit DexFile(ExtDexFile* ext_dex_file) : ext_dex_file_(ext_dex_file) {}
- ExtDexFile* ext_dex_file_; // Owned instance. nullptr only in moved-from zombies.
-
- typedef std::vector<MethodInfo> MethodInfoVector;
-
- static MethodInfo AbsorbMethodInfo(const ExtDexFileMethodInfo& ext_method_info);
- static void AddMethodInfoCallback(const ExtDexFileMethodInfo* ext_method_info, void* user_data);
+ ExtDexFile* ext_dex_file_ = nullptr; // Owned instance. nullptr only in moved-from zombies.
+ std::unique_ptr<android::base::MappedFile> map_; // Owned map (if we allocated one).
// These are initialized by TryLoadLibdexfileExternal.
static decltype(ExtDexFileOpenFromMemory)* g_ExtDexFileOpenFromMemory;
- static decltype(ExtDexFileOpenFromFd)* g_ExtDexFileOpenFromFd;
static decltype(ExtDexFileGetMethodInfoForOffset)* g_ExtDexFileGetMethodInfoForOffset;
static decltype(ExtDexFileGetAllMethodInfos)* g_ExtDexFileGetAllMethodInfos;
- static decltype(ExtDexFileFree)* g_ExtDexFileFree;
+ static decltype(ExtDexFileClose)* g_ExtDexFileClose;
DISALLOW_COPY_AND_ASSIGN(DexFile);
};
diff --git a/libdexfile/external/libdexfile_external.map.txt b/libdexfile/external/libdexfile_external.map.txt
index 450b633..e9d12fb 100644
--- a/libdexfile/external/libdexfile_external.map.txt
+++ b/libdexfile/external/libdexfile_external.map.txt
@@ -1,12 +1,8 @@
LIBDEXFILE_EXTERNAL_1 {
global:
- ExtDexFileFree;
- ExtDexFileFreeString;
+ ExtDexFileClose;
ExtDexFileGetAllMethodInfos;
ExtDexFileGetMethodInfoForOffset;
- ExtDexFileGetString;
- ExtDexFileMakeString;
- ExtDexFileOpenFromFd;
ExtDexFileOpenFromMemory;
local:
*;