Change heap dump format slightly.

Bump the version from v1.1 to v1.2 and add a build fingerprint line.

Update the heap dump documentation to match the new format and reflect
what made it in P and what made it in Q.

Update the unit tests for this change.

Add -O0 to unit test code to make it easier to debug.

Add an external function that can be used by the framework code
so that there is only one way to dump the heap.

Bug: 110095681

Test: Ran unit tests.
Test: Did a dump of a real process and verified fingerprint.
Test: Did a dump of a process without malloc debug enabled.
Change-Id: I769a476cbeaf4c85c5d75bd6d6385f0e3add948c
Merged-In: I769a476cbeaf4c85c5d75bd6d6385f0e3add948c
(cherry picked from commit c84a2a2601a4112ca6e43a33defb989c1da8c2f4)
diff --git a/libc/bionic/malloc_common.cpp b/libc/bionic/malloc_common.cpp
index 1ea4ac1..40a0023 100644
--- a/libc/bionic/malloc_common.cpp
+++ b/libc/bionic/malloc_common.cpp
@@ -39,6 +39,7 @@
 //                         allocations that are currently in use.
 //   free_malloc_leak_info: Frees the data allocated by the call to
 //                          get_malloc_leak_info.
+//   write_malloc_leak_info: Writes the leak info data to a file.
 
 #include <pthread.h>
 
@@ -211,6 +212,7 @@
   FUNC_GET_MALLOC_LEAK_INFO,
   FUNC_FREE_MALLOC_LEAK_INFO,
   FUNC_MALLOC_BACKTRACE,
+  FUNC_WRITE_LEAK_INFO,
   FUNC_LAST,
 };
 static void* g_functions[FUNC_LAST];
@@ -219,6 +221,7 @@
 typedef bool (*init_func_t)(const MallocDispatch*, int*, const char*);
 typedef void (*get_malloc_leak_info_func_t)(uint8_t**, size_t*, size_t*, size_t*, size_t*);
 typedef void (*free_malloc_leak_info_func_t)(uint8_t*);
+typedef bool (*write_malloc_leak_info_func_t)(FILE*);
 typedef ssize_t (*malloc_backtrace_func_t)(void*, uintptr_t*, size_t);
 
 // =============================================================================
@@ -260,6 +263,26 @@
   reinterpret_cast<free_malloc_leak_info_func_t>(func)(info);
 }
 
+extern "C" void write_malloc_leak_info(FILE* fp) {
+  if (fp == nullptr) {
+    error_log("write_malloc_leak_info called with a nullptr");
+    return;
+  }
+
+  void* func = g_functions[FUNC_WRITE_LEAK_INFO];
+  bool written = false;
+  if (func != nullptr) {
+    written = reinterpret_cast<write_malloc_leak_info_func_t>(func)(fp);
+  }
+
+  if (!written) {
+    fprintf(fp, "Native heap dump not available. To enable, run these commands (requires root):\n");
+    fprintf(fp, "# adb shell stop\n");
+    fprintf(fp, "# adb shell setprop libc.debug.malloc.options backtrace\n");
+    fprintf(fp, "# adb shell start\n");
+  }
+}
+
 // =============================================================================
 
 template<typename FunctionType>
@@ -392,6 +415,7 @@
     "get_malloc_leak_info",
     "free_malloc_leak_info",
     "malloc_backtrace",
+    "write_malloc_leak_info",
   };
   for (size_t i = 0; i < FUNC_LAST; i++) {
     char symbol[128];