profiling: Add malloc hooks.

Change-Id: Iea9ab138810a2c38b092e3c4823e1b8a56fdf25f
diff --git a/Android.bp b/Android.bp
index 8e6341e..e7cd8f0 100644
--- a/Android.bp
+++ b/Android.bp
@@ -14,6 +14,78 @@
 //
 // This file is automatically generated by tools/gen_android_bp. Do not edit.
 
+// GN target: //:heapprofd
+cc_binary {
+  name: "heapprofd",
+  srcs: [
+    "src/base/event.cc",
+    "src/base/file_utils.cc",
+    "src/base/metatrace.cc",
+    "src/base/page_allocator.cc",
+    "src/base/string_splitter.cc",
+    "src/base/string_utils.cc",
+    "src/base/temp_file.cc",
+    "src/base/thread_checker.cc",
+    "src/base/time.cc",
+    "src/base/unix_socket.cc",
+    "src/base/unix_task_runner.cc",
+    "src/base/virtual_destructors.cc",
+    "src/base/watchdog_posix.cc",
+    "src/profiling/memory/bookkeeping.cc",
+    "src/profiling/memory/main.cc",
+    "src/profiling/memory/record_reader.cc",
+    "src/profiling/memory/socket_listener.cc",
+    "src/profiling/memory/string_interner.cc",
+    "src/profiling/memory/unwinding.cc",
+    "src/profiling/memory/wire_protocol.cc",
+  ],
+  shared_libs: [
+    "libbase",
+    "liblog",
+    "libprocinfo",
+    "libunwindstack",
+  ],
+  defaults: [
+    "perfetto_defaults",
+  ],
+}
+
+// GN target: //:heapprofd_client
+cc_library_shared {
+  name: "heapprofd_client",
+  srcs: [
+    "src/base/event.cc",
+    "src/base/file_utils.cc",
+    "src/base/metatrace.cc",
+    "src/base/page_allocator.cc",
+    "src/base/string_splitter.cc",
+    "src/base/string_utils.cc",
+    "src/base/temp_file.cc",
+    "src/base/thread_checker.cc",
+    "src/base/time.cc",
+    "src/base/unix_socket.cc",
+    "src/base/unix_task_runner.cc",
+    "src/base/virtual_destructors.cc",
+    "src/base/watchdog_posix.cc",
+    "src/profiling/memory/client.cc",
+    "src/profiling/memory/malloc_hooks.cc",
+    "src/profiling/memory/sampler.cc",
+    "src/profiling/memory/wire_protocol.cc",
+  ],
+  shared_libs: [
+    "libbase",
+    "liblog",
+    "libprocinfo",
+    "libunwindstack",
+  ],
+  defaults: [
+    "perfetto_defaults",
+  ],
+  include_dirs: [
+    "bionic/libc",
+  ],
+}
+
 // GN target: //:libperfetto
 cc_library_shared {
   name: "libperfetto",
diff --git a/BUILD.gn b/BUILD.gn
index 15f2bd9..576f101 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -274,3 +274,25 @@
     ]
   }
 }
+
+if (!build_with_chromium) {
+  # TODO(fmayer): Investigate shared library for common pieces.
+  shared_library("heapprofd_client") {
+    deps = [
+      "src/profiling/memory:malloc_hooks",
+    ]
+  }
+
+  executable("heapprofd") {
+    deps = [
+      "gn:default_deps",
+      "src/base",
+      "src/base:unix_socket",
+      "src/profiling/memory:daemon",
+      "src/profiling/memory:wire_protocol",
+    ]
+    sources = [
+      "src/profiling/memory/main.cc",
+    ]
+  }
+}
diff --git a/src/profiling/memory/BUILD.gn b/src/profiling/memory/BUILD.gn
index d143901..871c99f 100644
--- a/src/profiling/memory/BUILD.gn
+++ b/src/profiling/memory/BUILD.gn
@@ -21,6 +21,7 @@
     "../../../buildtools:libunwindstack",
     "../../../gn:default_deps",
     "../../base",
+    "../../base:unix_socket",
   ]
   sources = [
     "wire_protocol.cc",
@@ -35,7 +36,7 @@
     "../../../buildtools:libunwindstack",
     "../../../gn:default_deps",
     "../../base",
-    "../../ipc",
+    "../../base:unix_socket",
   ]
   sources = [
     "bookkeeping.cc",
@@ -59,6 +60,7 @@
     "../../../buildtools:libunwindstack",
     "../../../gn:default_deps",
     "../../base",
+    "../../base:unix_socket",
   ]
   sources = [
     "client.cc",
@@ -94,15 +96,20 @@
   ]
 }
 
-executable("heapprofd") {
+# This will export publicly visibile symbols for the malloc_hooks.
+source_set("malloc_hooks") {
   deps = [
-    ":daemon",
+    ":client",
     ":wire_protocol",
     "../../../gn:default_deps",
     "../../base",
-    "../../ipc",
+    "../../base:unix_socket",
+  ]
+  cflags = [
+    "-isystem",
+    rebase_path("../../../buildtools/bionic/libc", root_build_dir),
   ]
   sources = [
-    "main.cc",
+    "malloc_hooks.cc",
   ]
 }
diff --git a/src/profiling/memory/malloc_hooks.cc b/src/profiling/memory/malloc_hooks.cc
new file mode 100644
index 0000000..ed42605
--- /dev/null
+++ b/src/profiling/memory/malloc_hooks.cc
@@ -0,0 +1,259 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <inttypes.h>
+#include <malloc.h>
+#include <stddef.h>
+#include <stdio.h>
+
+#include <atomic>
+
+#include <private/bionic_malloc_dispatch.h>
+
+#include "perfetto/base/build_config.h"
+#include "src/profiling/memory/client.h"
+#include "src/profiling/memory/wire_protocol.h"
+
+// The real malloc function pointers we get in initialize.
+static std::atomic<const MallocDispatch*> g_dispatch{nullptr};
+static std::atomic<perfetto::Client*> g_client{nullptr};
+static constexpr size_t kNumConnections = 2;
+
+// The only writes are in the initialization function. Because Bionic does a
+// release write after initialization and an acquire read to retrieve the hooked
+// malloc functions, we can use relaxed memory mode for both writing, and more
+// importantly because in the fast-path, reading.
+static constexpr std::memory_order write_order = std::memory_order_relaxed;
+
+static perfetto::Client* GetClient() {
+  return g_client.load(std::memory_order_relaxed);
+}
+
+static const MallocDispatch* GetDispatch() {
+  return g_dispatch.load(std::memory_order_relaxed);
+}
+
+// This is so we can make an so that we can swap out with the existing
+// libc_malloc_hooks.so
+#ifndef HEAPPROFD_PREFIX
+#define HEAPPROFD_PREFIX heapprofd
+#endif
+
+#define HEAPPROFD_ADD_PREFIX(name) \
+  PERFETTO_BUILDFLAG_CAT(HEAPPROFD_PREFIX, name)
+
+#pragma GCC visibility push(default)
+extern "C" {
+
+bool HEAPPROFD_ADD_PREFIX(_initialize)(const MallocDispatch* malloc_dispatch,
+                                       int* malloc_zygote_child,
+                                       const char* options);
+void HEAPPROFD_ADD_PREFIX(_finalize)();
+void HEAPPROFD_ADD_PREFIX(_dump_heap)(const char* file_name);
+void HEAPPROFD_ADD_PREFIX(_get_malloc_leak_info)(uint8_t** info,
+                                                 size_t* overall_size,
+                                                 size_t* info_size,
+                                                 size_t* total_memory,
+                                                 size_t* backtrace_size);
+bool HEAPPROFD_ADD_PREFIX(_write_malloc_leak_info)(FILE* fp);
+ssize_t HEAPPROFD_ADD_PREFIX(_malloc_backtrace)(void* pointer,
+                                                uintptr_t* frames,
+                                                size_t frame_count);
+void HEAPPROFD_ADD_PREFIX(_free_malloc_leak_info)(uint8_t* info);
+size_t HEAPPROFD_ADD_PREFIX(_malloc_usable_size)(void* pointer);
+void* HEAPPROFD_ADD_PREFIX(_malloc)(size_t size);
+void HEAPPROFD_ADD_PREFIX(_free)(void* pointer);
+void* HEAPPROFD_ADD_PREFIX(_aligned_alloc)(size_t alignment, size_t size);
+void* HEAPPROFD_ADD_PREFIX(_memalign)(size_t alignment, size_t bytes);
+void* HEAPPROFD_ADD_PREFIX(_realloc)(void* pointer, size_t bytes);
+void* HEAPPROFD_ADD_PREFIX(_calloc)(size_t nmemb, size_t bytes);
+struct mallinfo HEAPPROFD_ADD_PREFIX(_mallinfo)();
+int HEAPPROFD_ADD_PREFIX(_mallopt)(int param, int value);
+int HEAPPROFD_ADD_PREFIX(_posix_memalign)(void** memptr,
+                                          size_t alignment,
+                                          size_t size);
+int HEAPPROFD_ADD_PREFIX(_iterate)(uintptr_t base,
+                                   size_t size,
+                                   void (*callback)(uintptr_t base,
+                                                    size_t size,
+                                                    void* arg),
+                                   void* arg);
+void HEAPPROFD_ADD_PREFIX(_malloc_disable)();
+void HEAPPROFD_ADD_PREFIX(_malloc_enable)();
+
+#if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
+void* HEAPPROFD_ADD_PREFIX(_pvalloc)(size_t bytes);
+void* HEAPPROFD_ADD_PREFIX(_valloc)(size_t size);
+#endif
+}
+#pragma GCC visibility pop
+
+bool HEAPPROFD_ADD_PREFIX(_initialize)(const MallocDispatch* malloc_dispatch,
+                                       int*,
+                                       const char*) {
+  g_dispatch.store(malloc_dispatch, write_order);
+  // This can store a nullptr, so we have to check in the hooks below to avoid
+  // segfaulting in that case.
+  g_client.store(new (std::nothrow) perfetto::Client(
+                     perfetto::kHeapprofdSocketFile, kNumConnections),
+                 write_order);
+  return true;
+}
+
+void HEAPPROFD_ADD_PREFIX(_finalize)() {
+  // TODO(fmayer): Shut down client.
+  // Allow to re-enable existing client on subsequent initialize call.
+}
+
+void HEAPPROFD_ADD_PREFIX(_dump_heap)(const char*) {}
+
+void HEAPPROFD_ADD_PREFIX(
+    _get_malloc_leak_info)(uint8_t**, size_t*, size_t*, size_t*, size_t*) {}
+
+bool HEAPPROFD_ADD_PREFIX(_write_malloc_leak_info)(FILE*) {
+  return false;
+}
+
+ssize_t HEAPPROFD_ADD_PREFIX(_malloc_backtrace)(void*, uintptr_t*, size_t) {
+  return -1;
+}
+
+void HEAPPROFD_ADD_PREFIX(_free_malloc_leak_info)(uint8_t*) {}
+
+size_t HEAPPROFD_ADD_PREFIX(_malloc_usable_size)(void* pointer) {
+  const MallocDispatch* dispatch = GetDispatch();
+  return dispatch->malloc_usable_size(pointer);
+}
+
+void* HEAPPROFD_ADD_PREFIX(_malloc)(size_t size) {
+  const MallocDispatch* dispatch = GetDispatch();
+  perfetto::Client* client = GetClient();
+  void* addr = dispatch->malloc(size);
+  if (client) {
+    client->MaybeSampleAlloc(size, reinterpret_cast<uint64_t>(addr),
+                             dispatch->malloc, dispatch->free);
+  }
+  return addr;
+}
+
+void HEAPPROFD_ADD_PREFIX(_free)(void* pointer) {
+  const MallocDispatch* dispatch = GetDispatch();
+  perfetto::Client* client = GetClient();
+  if (client)
+    client->RecordFree(reinterpret_cast<uint64_t>(pointer));
+  return dispatch->free(pointer);
+}
+
+void* HEAPPROFD_ADD_PREFIX(_aligned_alloc)(size_t alignment, size_t size) {
+  const MallocDispatch* dispatch = GetDispatch();
+  perfetto::Client* client = GetClient();
+  void* addr = dispatch->aligned_alloc(alignment, size);
+  if (client) {
+    client->MaybeSampleAlloc(size, reinterpret_cast<uint64_t>(addr),
+                             dispatch->malloc, dispatch->free);
+  }
+  return addr;
+}
+
+void* HEAPPROFD_ADD_PREFIX(_memalign)(size_t alignment, size_t size) {
+  const MallocDispatch* dispatch = GetDispatch();
+  perfetto::Client* client = GetClient();
+  void* addr = dispatch->memalign(alignment, size);
+  if (client) {
+    client->MaybeSampleAlloc(size, reinterpret_cast<uint64_t>(addr),
+                             dispatch->malloc, dispatch->free);
+  }
+  return addr;
+}
+
+void* HEAPPROFD_ADD_PREFIX(_realloc)(void* pointer, size_t size) {
+  const MallocDispatch* dispatch = GetDispatch();
+  perfetto::Client* client = GetClient();
+  if (client && pointer)
+    client->RecordFree(reinterpret_cast<uint64_t>(pointer));
+  void* addr = dispatch->realloc(pointer, size);
+  if (client && size > 0) {
+    client->MaybeSampleAlloc(size, reinterpret_cast<uint64_t>(addr),
+                             dispatch->malloc, dispatch->free);
+  }
+  return addr;
+}
+
+void* HEAPPROFD_ADD_PREFIX(_calloc)(size_t nmemb, size_t size) {
+  const MallocDispatch* dispatch = GetDispatch();
+  perfetto::Client* client = GetClient();
+  void* addr = dispatch->calloc(nmemb, size);
+  if (client) {
+    client->MaybeSampleAlloc(size, reinterpret_cast<uint64_t>(addr),
+                             dispatch->malloc, dispatch->free);
+  }
+  return addr;
+}
+
+struct mallinfo HEAPPROFD_ADD_PREFIX(_mallinfo)() {
+  const MallocDispatch* dispatch = GetDispatch();
+  return dispatch->mallinfo();
+}
+
+int HEAPPROFD_ADD_PREFIX(_mallopt)(int param, int value) {
+  const MallocDispatch* dispatch = GetDispatch();
+  return dispatch->mallopt(param, value);
+}
+
+int HEAPPROFD_ADD_PREFIX(_posix_memalign)(void** memptr,
+                                          size_t alignment,
+                                          size_t size) {
+  const MallocDispatch* dispatch = GetDispatch();
+  perfetto::Client* client = GetClient();
+  int res = dispatch->posix_memalign(memptr, alignment, size);
+  if (res == 0 && client) {
+    client->MaybeSampleAlloc(size, reinterpret_cast<uint64_t>(*memptr),
+                             dispatch->malloc, dispatch->free);
+  }
+  return res;
+}
+
+int HEAPPROFD_ADD_PREFIX(_iterate)(uintptr_t,
+                                   size_t,
+                                   void (*)(uintptr_t base,
+                                            size_t size,
+                                            void* arg),
+                                   void*) {
+  return 0;
+}
+
+void HEAPPROFD_ADD_PREFIX(_malloc_disable)() {
+  const MallocDispatch* dispatch = GetDispatch();
+  return dispatch->malloc_disable();
+}
+
+void HEAPPROFD_ADD_PREFIX(_malloc_enable)() {
+  const MallocDispatch* dispatch = GetDispatch();
+  return dispatch->malloc_enable();
+}
+
+#if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
+void* HEAPPROFD_ADD_PREFIX(_pvalloc)(size_t size) {
+  const MallocDispatch* dispatch = GetDispatch();
+  return dispatch->pvalloc(size);
+}
+
+void* HEAPPROFD_ADD_PREFIX(_valloc)(size_t size) {
+  const MallocDispatch* dispatch = GetDispatch();
+  return dispatch->valloc(size);
+}
+
+#endif
diff --git a/tools/gen_android_bp b/tools/gen_android_bp
index e32289e..3483c1a 100755
--- a/tools/gen_android_bp
+++ b/tools/gen_android_bp
@@ -44,6 +44,8 @@
     '//:traced',
     '//:traced_probes',
     '//:trace_to_text',
+    '//:heapprofd_client',
+    '//:heapprofd',
 ]
 
 # Defines a custom init_rc argument to be applied to the corresponding output
@@ -94,6 +96,13 @@
     'libservices',
 }
 
+# Additional arguments to apply to Android.bp rules.
+additional_args = {
+    "heapprofd_client": [
+        ("include_dirs", ["bionic/libc"]),
+    ],
+}
+
 
 def enable_gmock(module):
     module.static_libs.append('libgmock')
@@ -201,6 +210,8 @@
         self._output_field(output, 'defaults')
         self._output_field(output, 'cflags')
         self._output_field(output, 'local_include_dirs')
+        for key, value in additional_args.get(self.name, []):
+          self._write_value(output, key, value)
 
         disable_pdk = any(name in library_not_in_pdk for name in self.shared_libs)
         if self.user_debug_flag or disable_pdk:
@@ -219,6 +230,9 @@
 
     def _output_field(self, output, name, sort=True):
         value = getattr(self, name)
+        return self._write_value(output, name, value, sort)
+
+    def _write_value(self, output, name, value, sort=True):
         if not value:
             return
         if isinstance(value, set):