Merge "Perfprofd: Introduce libsimpleperf_dex_read and read vdex files"
diff --git a/perfprofd/Android.bp b/perfprofd/Android.bp
index 61da0f5..e03508f 100644
--- a/perfprofd/Android.bp
+++ b/perfprofd/Android.bp
@@ -62,14 +62,15 @@
         undefined: true,
     },
 
-    target: {
-        // On the host add ASAN.
-        host: {
-            sanitize: {
-                address: true,
-            },
-        },
-    }
+//  TODO: Re-enable when ART's ASAN flags are correctly propagated.
+//    target: {
+//        // On the host add ASAN.
+//        host: {
+//            sanitize: {
+//                address: true,
+//            },
+//        },
+//    }
 }
 
 filegroup {
@@ -153,6 +154,7 @@
         "libbase",
         "libperfprofd_proto_config",
         "libprotobuf-cpp-lite",
+        "libsimpleperf_dex_read",
         "libsimpleperf_elf_read",
     ],
     whole_static_libs: [
@@ -160,6 +162,7 @@
         "libperfprofd_record_proto",
         "libquipper",
     ],
+    shared_libs: ["libart"],
     srcs: [
         "perf_data_converter.cc",
         "configreader.cc",
@@ -213,6 +216,7 @@
     name: "perfprofd",
     defaults: [
         "perfprofd_defaults",
+        "libsimpleperf_dex_read_static_reqs_defaults",
         "libsimpleperf_elf_read_static_reqs_defaults",
     ],
 
@@ -225,12 +229,14 @@
         "libperfprofdcore",
         "libperfprofd_binder",
         "libperfprofd_proto_config",
+        "libsimpleperf_dex_read",
         "libsimpleperf_elf_read",
     ],
     group_static_libs: true,
 
     shared_libs: [
         "android.hardware.health@2.0",
+        "libart",
         "liblog",
         "libprotobuf-cpp-lite",
         "libbase",
diff --git a/perfprofd/symbolizer.cc b/perfprofd/symbolizer.cc
index bde680f..58ff280 100644
--- a/perfprofd/symbolizer.cc
+++ b/perfprofd/symbolizer.cc
@@ -22,9 +22,11 @@
 #include <unordered_map>
 
 #include <android-base/logging.h>
-
-#include "build_id.h"
-#include "read_elf.h"
+#include <base/mem_map.h>
+#include <build_id.h>
+#include <read_dex_file.h>
+#include <read_elf.h>
+#include <vdex_file.h>
 
 namespace perfprofd {
 
@@ -33,6 +35,8 @@
 struct SimpleperfSymbolizer : public Symbolizer {
   // For simplicity, we assume non-overlapping symbols.
   struct Symbol {
+    Symbol(const std::string& n, uint64_t l) : name(n), length(l) {}
+
     std::string name;
     uint64_t length;
   };
@@ -66,28 +70,99 @@
   }
 
   void LoadDso(const std::string& dso) {
-    SymbolMap data;
-    auto callback = [&data](const ElfFileSymbol& sym) {
-      if (sym.is_func) {
-        Symbol symbol;
-        symbol.name = sym.name;
-        symbol.length = sym.len;
-        if (sym.len == 0) {
-          LOG(ERROR) << "Symbol size is zero for " << sym.name;
+    // See whether it's an ELF file.
+    {
+      SymbolMap elf_data;
+      auto callback = [&elf_data](const ElfFileSymbol& sym) {
+        if (sym.is_func) {
+          if (sym.len == 0) {
+            LOG(ERROR) << "Symbol size is zero for " << sym.name;
+          }
+          elf_data.emplace(sym.vaddr, Symbol(sym.name, sym.len));
         }
-        data.emplace(sym.vaddr, std::move(symbol));
+      };
+      ElfStatus status = ParseSymbolsFromElfFile(dso, BuildId(), callback);
+      if (status == ElfStatus::NO_ERROR) {
+        dsos.emplace(dso, std::move(elf_data));
+        return;
       }
-    };
-    ElfStatus status = ParseSymbolsFromElfFile(dso, BuildId(), callback);
-    if (status != ElfStatus::NO_ERROR) {
-      LOG(WARNING) << "Could not parse dso " << dso << ": " << status;
     }
-    dsos.emplace(dso, std::move(data));
+
+    // See whether it's a vdex file.
+    {
+      ::art::MemMap::Init();
+
+      using VdexFile = ::art::VdexFile;
+      std::string error_msg;
+      std::unique_ptr<VdexFile> vdex = VdexFile::Open(dso,
+                                                      /* writable= */ false,
+                                                      /* low_4gb= */ false,
+                                                      /* unquicken= */ false,
+                                                      &error_msg);
+      if (vdex != nullptr) {
+        const uint8_t* cur = nullptr;
+        std::vector<uint64_t> dex_file_offsets;
+        const uint8_t* base = vdex->Begin();
+        for (;;) {
+          cur = vdex->GetNextDexFileData(cur);
+          if (cur == nullptr) {
+            break;
+          }
+          dex_file_offsets.push_back(cur - base);
+        }
+
+        if (!dex_file_offsets.empty()) {
+          std::vector<DexFileSymbol> symbols;
+          if (ReadSymbolsFromDexFile(dso, dex_file_offsets, &symbols)) {
+            SymbolMap vdex_data;
+            for (const DexFileSymbol& symbol : symbols) {
+              vdex_data.emplace(symbol.offset, Symbol(symbol.name, symbol.len));
+            }
+            dsos.emplace(dso, std::move(vdex_data));
+            LOG(INFO) << "Found " << symbols.size() << " dex symbols in " << dso;
+            return;
+          } else {
+            LOG(WARNING) << "Could not read symbols from dex files in " << dso;
+          }
+        } else {
+          LOG(WARNING) << "Could not find dex files for vdex " << dso;
+          dsos.emplace(dso, SymbolMap());
+        }
+      } else {
+        LOG(WARNING) << dso << " is not a vdex: " << error_msg;
+      }
+    }
+
+    // TODO: See whether it's a dex file.
+
+    // OK, give up.
+    LOG(WARNING) << "Could not symbolize " << dso;
+    dsos.emplace(dso, SymbolMap());
   }
 
   bool GetMinExecutableVAddr(const std::string& dso, uint64_t* addr) override {
     ElfStatus status = ReadMinExecutableVirtualAddressFromElfFile(dso, BuildId(), addr);
-    return status == ElfStatus::NO_ERROR;
+    if (status != ElfStatus::NO_ERROR) {
+      return true;
+    }
+
+    {
+      ::art::MemMap::Init();
+
+      using VdexFile = ::art::VdexFile;
+      std::string error_msg;
+      std::unique_ptr<VdexFile> vdex = VdexFile::Open(dso,
+                                                      /* writable= */ false,
+                                                      /* low_4gb= */ false,
+                                                      /* unquicken= */ false,
+                                                      &error_msg);
+      if (vdex != nullptr) {
+        *addr = 0u;
+        return true;
+      }
+    }
+
+    return false;
   }
 
   std::unordered_map<std::string, SymbolMap> dsos;
diff --git a/perfprofd/tests/Android.bp b/perfprofd/tests/Android.bp
index 215f9fc..837c28f 100644
--- a/perfprofd/tests/Android.bp
+++ b/perfprofd/tests/Android.bp
@@ -19,6 +19,7 @@
     name: "perfprofd_test",
     defaults: [
         "perfprofd_test_defaults",
+        "libsimpleperf_dex_read_static_reqs_defaults",
         "libsimpleperf_elf_read_static_reqs_defaults",
     ],
     test_suites: ["device-tests"],
@@ -28,6 +29,7 @@
     static_libs: [
         "libperfprofdcored",
         "libperfprofd_proto_config",
+        "libsimpleperf_dex_read",
         "libsimpleperf_elf_read",
         "libbase",
         "libutils",
@@ -35,6 +37,7 @@
         "libprotobuf-cpp-lite",
         "liblog",
     ],
+    shared_libs: ["libart"],
     target: {
         host: {
             host_ldlibs: [
diff --git a/simpleperf/Android.bp b/simpleperf/Android.bp
index dc98a26..759aee5 100644
--- a/simpleperf/Android.bp
+++ b/simpleperf/Android.bp
@@ -94,3 +94,34 @@
 
     group_static_libs: true,
 }
+
+cc_defaults {
+    name: "libsimpleperf_dex_read_static_reqs_defaults",
+    defaults: ["libdexfile_static_defaults"],
+}
+
+cc_library_static {
+    name: "libsimpleperf_dex_read",
+    defaults: [
+        "simpleperf_defaults",
+        "libsimpleperf_dex_read_static_reqs_defaults",
+    ],
+    host_supported: true,
+
+    export_include_dirs: [
+        ".",
+    ],
+
+    // TODO: fix or workaround this.
+    cflags: [
+        "-DSIMPLEPERF_REVISION=\"dummy\"",
+    ],
+
+    static_libs: ["libbase"],
+
+    srcs: [
+        "read_dex_file.cpp",
+    ],
+
+    group_static_libs: true,
+}