simpleperf: use callback API to read dex symbols.

In experiment, it saves about 20% time reading dex symbols.

Bug: none
Test: run simpleperf_unit_test
Change-Id: I0e6bfd1f51f99f57175fece77c2ee3518e676a71
diff --git a/simpleperf/dso.cpp b/simpleperf/dso.cpp
index 77a8b15..d3b7ffb 100644
--- a/simpleperf/dso.cpp
+++ b/simpleperf/dso.cpp
@@ -463,9 +463,12 @@
 
   std::vector<Symbol> LoadSymbolsImpl() override {
     std::vector<Symbol> symbols;
-    std::vector<DexFileSymbol> dex_file_symbols;
     auto tuple = SplitUrlInApk(debug_file_path_);
     bool status = false;
+    auto symbol_callback = [&](DexFileSymbol* dex_symbol) {
+      symbols.emplace_back(std::string_view(dex_symbol->name, dex_symbol->name_size),
+                           dex_symbol->addr, dex_symbol->size);
+    };
     if (std::get<0>(tuple)) {
       std::unique_ptr<ArchiveHelper> ahelper = ArchiveHelper::CreateInstance(std::get<1>(tuple));
       ZipEntry entry;
@@ -473,10 +476,10 @@
       if (ahelper && ahelper->FindEntry(std::get<2>(tuple), &entry) &&
           ahelper->GetEntryData(entry, &data)) {
         status = ReadSymbolsFromDexFileInMemory(data.data(), data.size(), dex_file_offsets_,
-                                                &dex_file_symbols);
+                                                symbol_callback);
       }
     } else {
-      status = ReadSymbolsFromDexFile(debug_file_path_, dex_file_offsets_, &dex_file_symbols);
+      status = ReadSymbolsFromDexFile(debug_file_path_, dex_file_offsets_, symbol_callback);
     }
     if (!status) {
       android::base::LogSeverity level =
@@ -485,9 +488,6 @@
       return symbols;
     }
     LOG(VERBOSE) << "Read symbols from " << debug_file_path_ << " successfully";
-    for (auto& symbol : dex_file_symbols) {
-      symbols.emplace_back(symbol.name, symbol.offset, symbol.len);
-    }
     SortAndFixSymbols(symbols);
     return symbols;
   }
diff --git a/simpleperf/nonlinux_support/nonlinux_support.cpp b/simpleperf/nonlinux_support/nonlinux_support.cpp
index 823b6e5..2268e30 100644
--- a/simpleperf/nonlinux_support/nonlinux_support.cpp
+++ b/simpleperf/nonlinux_support/nonlinux_support.cpp
@@ -32,12 +32,12 @@
 }
 
 bool ReadSymbolsFromDexFileInMemory(void*, uint64_t, const std::vector<uint64_t>&,
-                                    std::vector<DexFileSymbol>*) {
+                                    const std::function<void(DexFileSymbol*)>&) {
   return true;
 }
 
 bool ReadSymbolsFromDexFile(const std::string&, const std::vector<uint64_t>&,
-                            std::vector<DexFileSymbol>*) {
+                            const std::function<void(DexFileSymbol*)>&) {
   return true;
 }
 
diff --git a/simpleperf/read_dex_file.cpp b/simpleperf/read_dex_file.cpp
index 055a408..d4d50e0 100644
--- a/simpleperf/read_dex_file.cpp
+++ b/simpleperf/read_dex_file.cpp
@@ -31,27 +31,20 @@
 namespace simpleperf {
 
 static bool ReadSymbols(
-    const std::vector<uint64_t>& dex_file_offsets, std::vector<DexFileSymbol>* symbols,
-    const std::function<std::unique_ptr<art_api::dex::DexFile>(uint64_t offset)>& open_file_cb) {
+    const std::vector<uint64_t>& dex_file_offsets,
+    const std::function<std::unique_ptr<art_api::dex::DexFile>(uint64_t offset)>& open_file_cb,
+    const std::function<void(DexFileSymbol*)>& symbol_cb) {
   for (uint64_t offset : dex_file_offsets) {
     std::unique_ptr<art_api::dex::DexFile> dex_file = open_file_cb(offset);
     if (dex_file == nullptr) {
       return false;
     }
 
-    std::vector<art_api::dex::MethodInfo> file_syms = dex_file->GetAllMethodInfos(false);
-
-    // Adjust offsets to be from the start of the combined file.
-    for (art_api::dex::MethodInfo& sym : file_syms) {
-      sym.offset += offset;
-    }
-
-    if (symbols->empty()) {
-      *symbols = std::move(file_syms);
-    } else {
-      symbols->reserve(symbols->size() + file_syms.size());
-      std::move(std::begin(file_syms), std::end(file_syms), std::back_inserter(*symbols));
-    }
+    auto callback = [&](DexFileSymbol* symbol) {
+      symbol->addr += offset;
+      symbol_cb(symbol);
+    };
+    dex_file->GetAllMethodInfos(callback);
   }
 
   return true;
@@ -59,9 +52,10 @@
 
 bool ReadSymbolsFromDexFileInMemory(void* addr, uint64_t size,
                                     const std::vector<uint64_t>& dex_file_offsets,
-                                    std::vector<DexFileSymbol>* symbols) {
+                                    const std::function<void(DexFileSymbol*)>& symbol_callback) {
   return ReadSymbols(
-      dex_file_offsets, symbols, [&](uint64_t offset) -> std::unique_ptr<art_api::dex::DexFile> {
+      dex_file_offsets,
+      [&](uint64_t offset) -> std::unique_ptr<art_api::dex::DexFile> {
         size_t max_file_size;
         if (__builtin_sub_overflow(size, offset, &max_file_size)) {
           return nullptr;
@@ -75,28 +69,31 @@
           return nullptr;
         }
         return dex_file;
-      });
+      },
+      symbol_callback);
 }
 
 bool ReadSymbolsFromDexFile(const std::string& file_path,
                             const std::vector<uint64_t>& dex_file_offsets,
-                            std::vector<DexFileSymbol>* symbols) {
+                            const std::function<void(DexFileSymbol*)>& symbol_callback) {
   android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(file_path.c_str(), O_RDONLY | O_CLOEXEC)));
   if (fd == -1) {
     return false;
   }
-  return ReadSymbols(dex_file_offsets, symbols,
-                     [&](uint64_t offset) -> std::unique_ptr<art_api::dex::DexFile> {
-                       std::string error_msg;
-                       std::unique_ptr<art_api::dex::DexFile> dex_file =
-                           art_api::dex::DexFile::OpenFromFd(fd, offset, file_path, &error_msg);
-                       if (dex_file == nullptr) {
-                         LOG(WARNING) << "Failed to read dex file symbols from '" << file_path
-                                      << "': " << error_msg;
-                         return nullptr;
-                       }
-                       return dex_file;
-                     });
+  return ReadSymbols(
+      dex_file_offsets,
+      [&](uint64_t offset) -> std::unique_ptr<art_api::dex::DexFile> {
+        std::string error_msg;
+        std::unique_ptr<art_api::dex::DexFile> dex_file =
+            art_api::dex::DexFile::OpenFromFd(fd, offset, file_path, &error_msg);
+        if (dex_file == nullptr) {
+          LOG(WARNING) << "Failed to read dex file symbols from '" << file_path
+                       << "': " << error_msg;
+          return nullptr;
+        }
+        return dex_file;
+      },
+      symbol_callback);
 }
 
 }  // namespace simpleperf
diff --git a/simpleperf/read_dex_file.h b/simpleperf/read_dex_file.h
index ebddc87..e5b9790 100644
--- a/simpleperf/read_dex_file.h
+++ b/simpleperf/read_dex_file.h
@@ -28,22 +28,24 @@
 
 namespace simpleperf {
 
-#ifndef NO_LIBDEXFILE_SUPPORT
-using DexFileSymbol = art_api::dex::MethodInfo;
-#else
+#ifdef NO_LIBDEXFILE_SUPPORT
 struct DexFileSymbol {
-  uint64_t offset;
-  uint64_t len;
-  std::string name;
+  size_t sizeof_struct;
+  uint32_t addr;
+  uint32_t size;
+  const char* name;
+  size_t name_size;
 };
+#else
+using DexFileSymbol = ExtDexFileMethodInfo;
 #endif
 
 bool ReadSymbolsFromDexFileInMemory(void* addr, uint64_t size,
                                     const std::vector<uint64_t>& dex_file_offsets,
-                                    std::vector<DexFileSymbol>* symbols);
+                                    const std::function<void(DexFileSymbol*)>& symbol_callback);
 bool ReadSymbolsFromDexFile(const std::string& file_path,
                             const std::vector<uint64_t>& dex_file_offsets,
-                            std::vector<DexFileSymbol>* symbols);
+                            const std::function<void(DexFileSymbol*)>& symbol_callback);
 
 }  // namespace simpleperf
 
diff --git a/simpleperf/read_dex_file_test.cpp b/simpleperf/read_dex_file_test.cpp
index 3d0e900..5d71bc3 100644
--- a/simpleperf/read_dex_file_test.cpp
+++ b/simpleperf/read_dex_file_test.cpp
@@ -20,6 +20,7 @@
 
 #include <algorithm>
 
+#include "dso.h"
 #include "get_test_data.h"
 #include "test_util.h"
 #include "utils.h"
@@ -27,13 +28,17 @@
 using namespace simpleperf;
 
 TEST(read_dex_file, smoke) {
-  std::vector<DexFileSymbol> symbols;
-  ASSERT_TRUE(ReadSymbolsFromDexFile(GetTestData("base.vdex"), {0x28}, &symbols));
+  std::vector<Symbol> symbols;
+  auto symbol_callback = [&](DexFileSymbol* symbol) {
+    symbols.emplace_back(std::string_view(symbol->name, symbol->name_size), symbol->addr,
+                         symbol->size);
+  };
+  ASSERT_TRUE(ReadSymbolsFromDexFile(GetTestData("base.vdex"), {0x28}, symbol_callback));
   ASSERT_EQ(12435u, symbols.size());
-  DexFileSymbol target;
-  target.offset = 0x6c77e;
-  target.len = 0x16;
-  target.name = art_api::dex::DexString(
-      "com.example.simpleperf.simpleperfexamplewithnative.MixActivity$1.run");
-  ASSERT_NE(std::find(symbols.begin(), symbols.end(), target), symbols.end());
+  auto it = std::find_if(symbols.begin(), symbols.end(),
+                         [](const Symbol& symbol) { return symbol.addr == 0x6c77e; });
+  ASSERT_NE(it, symbols.end());
+  ASSERT_EQ(it->addr, 0x6c77e);
+  ASSERT_EQ(it->len, 0x16);
+  ASSERT_STREQ(it->Name(), "com.example.simpleperf.simpleperfexamplewithnative.MixActivity$1.run");
 }