LD_PRELOAD-able library to hook malloc functions.

Test: Profile trace_processor_shell on Linux.

Bug: 160399441
Change-Id: I9ceaa1ff195468f2cc77908915171613f495309e
diff --git a/Android.bp b/Android.bp
index eace06e..0f587a6 100644
--- a/Android.bp
+++ b/Android.bp
@@ -376,6 +376,7 @@
     ":perfetto_src_profiling_common_unwind_support",
     ":perfetto_src_profiling_memory_client",
     ":perfetto_src_profiling_memory_client_ext",
+    ":perfetto_src_profiling_memory_client_ext_standalone",
     ":perfetto_src_profiling_memory_daemon",
     ":perfetto_src_profiling_memory_ring_buffer",
     ":perfetto_src_profiling_memory_scoped_spinlock",
@@ -385,7 +386,6 @@
     ":perfetto_src_tracing_core_core",
     ":perfetto_src_tracing_ipc_common",
     ":perfetto_src_tracing_ipc_producer_producer",
-    "src/profiling/memory/client_ext_standalone.cc",
   ],
   shared_libs: [
     "liblog",
@@ -6376,6 +6376,14 @@
   ],
 }
 
+// GN: //src/profiling/memory:client_ext_standalone
+filegroup {
+  name: "perfetto_src_profiling_memory_client_ext_standalone",
+  srcs: [
+    "src/profiling/memory/client_ext_standalone.cc",
+  ],
+}
+
 // GN: //src/profiling/memory:daemon
 filegroup {
   name: "perfetto_src_profiling_memory_daemon",
diff --git a/src/profiling/memory/BUILD.gn b/src/profiling/memory/BUILD.gn
index 3a80ec5..50c9435 100644
--- a/src/profiling/memory/BUILD.gn
+++ b/src/profiling/memory/BUILD.gn
@@ -76,7 +76,7 @@
   sources = [ "heapprofd_standalone_client_example.cc" ]
 }
 
-shared_library("heapprofd_standalone_client") {
+source_set("client_ext_standalone") {
   deps = [
     ":client_ext",
     ":daemon",
@@ -85,11 +85,22 @@
     "../../base",
     "../common:proc_utils",
   ]
+  sources = [ "client_ext_standalone.cc" ]
+}
+
+# This can be used to instrument custom allocators to report their allocations
+# to Perfetto. This bundles a copy of heapprofd in the library, in contrast to
+# heapprofd_client_api (see below), which expects one to be present in the
+# Android platform.
+shared_library("heapprofd_standalone_client") {
+  deps = [
+    ":client_ext_standalone",
+    "../../../gn:default_deps",
+  ]
   ldflags = [
     "-Wl,--version-script",
     rebase_path("heapprofd_client_api.map.txt", root_build_dir),
   ]
-  sources = [ "client_ext_standalone.cc" ]
 }
 
 shared_library("heapprofd_standalone_client_noop") {
@@ -117,6 +128,22 @@
   }
 }
 
+# On GLibc Linux, this can be used to override the allocators using
+# LD_PRELOAD. On non-GLibc, this will probably fail to link.
+shared_library("heapprofd_preload") {
+  deps = [
+    ":client_ext_standalone",
+    ":wrap_allocators",
+    "../../../gn:default_deps",
+    "../../base",
+  ]
+  ldflags = [
+    "-Wl,--version-script",
+    rebase_path("heapprofd_preload.map.txt", root_build_dir),
+  ]
+  sources = [ "malloc_preload.cc" ]
+}
+
 # On Android builds, this is converted to
 # header_libs: ["bionic_libc_platform_headers"].
 source_set("bionic_libc_platform_headers_on_android") {
@@ -143,6 +170,10 @@
 }
 
 source_set("wrap_allocators") {
+  deps = [
+    "../../../gn:default_deps",
+    "../../base",
+  ]
   sources = [ "wrap_allocators.cc" ]
 }
 
diff --git a/src/profiling/memory/heapprofd_preload.map.txt b/src/profiling/memory/heapprofd_preload.map.txt
new file mode 100644
index 0000000..ca2ffbb
--- /dev/null
+++ b/src/profiling/memory/heapprofd_preload.map.txt
@@ -0,0 +1,15 @@
+{
+  global:
+    malloc;
+    free;
+    calloc;
+    realloc;
+    posix_memalign;
+    aligned_alloc;
+    memalign;
+    pvalloc;
+    valloc;
+    reallocarray;
+  local:
+    *;
+};
diff --git a/src/profiling/memory/malloc_preload.cc b/src/profiling/memory/malloc_preload.cc
new file mode 100644
index 0000000..7c036b4
--- /dev/null
+++ b/src/profiling/memory/malloc_preload.cc
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2020 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 <malloc.h>
+#include <unistd.h>
+
+#include "perfetto/base/logging.h"
+#include "perfetto/profiling/memory/client_ext.h"
+#include "src/profiling/memory/wrap_allocators.h"
+
+namespace {
+// AHeapProfile_registerHeap is guaranteed to be safe to call from global
+// constructors.
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wglobal-constructors"
+uint32_t g_heap_id =
+    AHeapProfile_registerHeap(AHeapInfo_create("com.android.malloc"));
+#pragma GCC diagnostic pop
+}  // namespace
+
+extern "C" {
+
+// These are exported by GLibc to be used by functions overwriting malloc
+// to call back to the real implementation.
+extern void* __libc_malloc(size_t);
+extern void __libc_free(void*);
+extern void* __libc_calloc(size_t, size_t);
+extern void* __libc_realloc(void*, size_t);
+extern int __libc_posix_memalign(void**, size_t, size_t);
+extern void* __libc_memalign(size_t, size_t);
+extern void* __libc_pvalloc(size_t);
+extern void* __libc_valloc(size_t);
+extern void* __libc_reallocarray(void*, size_t, size_t);
+
+#pragma GCC visibility push(default)
+
+void* malloc(size_t size) {
+  return perfetto::profiling::wrap_malloc(g_heap_id, __libc_malloc, size);
+}
+
+void free(void* ptr) {
+  return perfetto::profiling::wrap_free(g_heap_id, __libc_free, ptr);
+}
+
+void* calloc(size_t nmemb, size_t size) {
+  return perfetto::profiling::wrap_calloc(g_heap_id, __libc_calloc, nmemb,
+                                          size);
+}
+
+void* realloc(void* ptr, size_t size) {
+  return perfetto::profiling::wrap_realloc(g_heap_id, __libc_realloc, ptr,
+                                           size);
+}
+
+int posix_memalign(void** memptr, size_t alignment, size_t size) {
+  return perfetto::profiling::wrap_posix_memalign(
+      g_heap_id, __libc_posix_memalign, memptr, alignment, size);
+}
+
+void* aligned_alloc(size_t alignment, size_t size) {
+  return perfetto::profiling::wrap_memalign(g_heap_id, __libc_memalign,
+                                            alignment, size);
+}
+
+void* memalign(size_t alignment, size_t size) {
+  return perfetto::profiling::wrap_memalign(g_heap_id, __libc_memalign,
+                                            alignment, size);
+}
+
+void* pvalloc(size_t size) {
+  return perfetto::profiling::wrap_pvalloc(g_heap_id, __libc_pvalloc, size);
+}
+
+void* valloc(size_t size) {
+  return perfetto::profiling::wrap_valloc(g_heap_id, __libc_valloc, size);
+}
+
+void* reallocarray(void* ptr, size_t nmemb, size_t size) {
+  return perfetto::profiling::wrap_reallocarray(g_heap_id, __libc_reallocarray,
+                                                ptr, nmemb, size);
+}
+
+#pragma GCC visibility pop
+}
diff --git a/src/profiling/memory/wrap_allocators.cc b/src/profiling/memory/wrap_allocators.cc
index bcf3b1c..f7ac4b8 100644
--- a/src/profiling/memory/wrap_allocators.cc
+++ b/src/profiling/memory/wrap_allocators.cc
@@ -120,5 +120,18 @@
   return addr;
 }
 
+void* wrap_reallocarray(uint32_t heap_id,
+                        void* (*fn)(void*, size_t, size_t),
+                        void* pointer,
+                        size_t nmemb,
+                        size_t size) {
+  if (pointer)
+    AHeapProfile_reportFree(heap_id, reinterpret_cast<uint64_t>(pointer));
+  void* addr = fn(pointer, nmemb, size);
+  AHeapProfile_reportAllocation(heap_id, reinterpret_cast<uint64_t>(addr),
+                                nmemb * size);
+  return addr;
+}
+
 }  // namespace profiling
 }  // namespace perfetto
diff --git a/src/profiling/memory/wrap_allocators.h b/src/profiling/memory/wrap_allocators.h
index 8b5d420..ce9fb3e 100644
--- a/src/profiling/memory/wrap_allocators.h
+++ b/src/profiling/memory/wrap_allocators.h
@@ -45,6 +45,12 @@
 void* wrap_pvalloc(uint32_t heap_id, void* (*fn)(size_t), size_t size);
 void* wrap_valloc(uint32_t heap_id, void* (*fn)(size_t), size_t size);
 
+void* wrap_reallocarray(uint32_t heap_id,
+                        void* (*fn)(void*, size_t, size_t),
+                        void* pointer,
+                        size_t nmemb,
+                        size_t size);
+
 }  // namespace profiling
 }  // namespace perfetto