Merge "Change heap dump format slightly."
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];
diff --git a/libc/libc.arm.map b/libc/libc.arm.map
index 159d4a0..18099dd 100644
--- a/libc/libc.arm.map
+++ b/libc/libc.arm.map
@@ -1634,6 +1634,7 @@
     tkill; # arm x86 mips
     wait3; # arm x86 mips
     wcswcs; # arm x86 mips
+    write_malloc_leak_info;
 } LIBC_P;
 
 LIBC_DEPRECATED {
diff --git a/libc/libc.arm64.map b/libc/libc.arm64.map
index 7702f9e..f37641e 100644
--- a/libc/libc.arm64.map
+++ b/libc/libc.arm64.map
@@ -1352,6 +1352,7 @@
     free_malloc_leak_info;
     get_malloc_leak_info;
     gMallocLeakZygoteChild;
+    write_malloc_leak_info;
 } LIBC_P;
 
 LIBC_DEPRECATED {
diff --git a/libc/libc.map.txt b/libc/libc.map.txt
index ebe2098..21966b3 100644
--- a/libc/libc.map.txt
+++ b/libc/libc.map.txt
@@ -1660,6 +1660,7 @@
     tkill; # arm x86 mips
     wait3; # arm x86 mips
     wcswcs; # arm x86 mips
+    write_malloc_leak_info;
 } LIBC_P;
 
 LIBC_DEPRECATED {
diff --git a/libc/libc.mips.map b/libc/libc.mips.map
index d04cb4f..0bc6fce 100644
--- a/libc/libc.mips.map
+++ b/libc/libc.mips.map
@@ -1475,6 +1475,7 @@
     tkill; # arm x86 mips
     wait3; # arm x86 mips
     wcswcs; # arm x86 mips
+    write_malloc_leak_info;
 } LIBC_P;
 
 LIBC_DEPRECATED {
diff --git a/libc/libc.mips64.map b/libc/libc.mips64.map
index 7702f9e..f37641e 100644
--- a/libc/libc.mips64.map
+++ b/libc/libc.mips64.map
@@ -1352,6 +1352,7 @@
     free_malloc_leak_info;
     get_malloc_leak_info;
     gMallocLeakZygoteChild;
+    write_malloc_leak_info;
 } LIBC_P;
 
 LIBC_DEPRECATED {
diff --git a/libc/libc.x86.map b/libc/libc.x86.map
index 2e10bbb..14ee151 100644
--- a/libc/libc.x86.map
+++ b/libc/libc.x86.map
@@ -1474,6 +1474,7 @@
     tkill; # arm x86 mips
     wait3; # arm x86 mips
     wcswcs; # arm x86 mips
+    write_malloc_leak_info;
 } LIBC_P;
 
 LIBC_DEPRECATED {
diff --git a/libc/libc.x86_64.map b/libc/libc.x86_64.map
index 7702f9e..f37641e 100644
--- a/libc/libc.x86_64.map
+++ b/libc/libc.x86_64.map
@@ -1352,6 +1352,7 @@
     free_malloc_leak_info;
     get_malloc_leak_info;
     gMallocLeakZygoteChild;
+    write_malloc_leak_info;
 } LIBC_P;
 
 LIBC_DEPRECATED {
diff --git a/libc/malloc_debug/Android.bp b/libc/malloc_debug/Android.bp
index a4ff5d4..0cb4cca 100644
--- a/libc/malloc_debug/Android.bp
+++ b/libc/malloc_debug/Android.bp
@@ -139,5 +139,6 @@
         "-Wall",
         "-Werror",
         "-Wno-error=format-zero-length",
+        "-O0",
     ],
 }
diff --git a/libc/malloc_debug/README.md b/libc/malloc_debug/README.md
index c427d5f..c4ee722 100644
--- a/libc/malloc_debug/README.md
+++ b/libc/malloc_debug/README.md
@@ -161,7 +161,7 @@
 when the program exits will be backtrace\_dump\_prefix.**PID**.exit.txt.
 
 ### backtrace\_full
-As of P, any time that a backtrace is gathered, a different algorithm is used
+As of Q, any time that a backtrace is gathered, a different algorithm is used
 that is extra thorough and can unwind through Java frames. This will run
 slower than the normal backtracing function.
 
@@ -495,15 +495,32 @@
 The map data is simply the output of /proc/PID/maps. This data can be used to
 decode the frames in the backtraces.
 
-As of Android P, there is a new version of this file. The new header is:
+There are now multiple versions of the file:
+
+Android P produces version v1.1 of the heap dump.
 
     Android Native Heap Dump v1.1
 
-The new version no longer 0 pads the backtrace addresses. In v1.0:
+The only difference between v1.0 and v1.1 is that the NUM\_ALLOCATIONS
+value is always accurate in v1.1. A previous version of malloc debug set
+NUM\_ALLOCATIONS to an incorrect value. For heap dump v1.0, the
+NUM\_ALLOCATIONS value should be treated as always 1 no matter what is
+actually present.
+
+Android Q introduces v1.2 of the heap dump. The new header looks like this:
+
+    Android Native Heap Dump v1.2
+
+    Build fingerprint: 'google/taimen/taimen:8.1.0/OPM2.171026.006.C1/4769658:user/release-keys'
+
+The new line fingerprint line is the contents of the ro.build.fingerprint
+property.
+
+The new version no longer 0 pads the backtrace addresses. In v1.0/v1.1:
 
     z 0  sz      400  num    1  bt 0000a230 0000b500
 
-While v1.1:
+While v1.2:
 
     z 0  sz      400  num    1  bt a230 b500
 
diff --git a/libc/malloc_debug/exported32.map b/libc/malloc_debug/exported32.map
index 78a6990..2f590d0 100644
--- a/libc/malloc_debug/exported32.map
+++ b/libc/malloc_debug/exported32.map
@@ -21,6 +21,7 @@
     debug_pvalloc;
     debug_realloc;
     debug_valloc;
+    debug_write_malloc_leak_info;
 
   local:
     *;
diff --git a/libc/malloc_debug/exported64.map b/libc/malloc_debug/exported64.map
index 2bfc38b..08d36a5 100644
--- a/libc/malloc_debug/exported64.map
+++ b/libc/malloc_debug/exported64.map
@@ -19,6 +19,7 @@
     debug_memalign;
     debug_posix_memalign;
     debug_realloc;
+    debug_write_malloc_leak_info;
 
   local:
     *;
diff --git a/libc/malloc_debug/malloc_debug.cpp b/libc/malloc_debug/malloc_debug.cpp
index 836c33b..1e7086c 100644
--- a/libc/malloc_debug/malloc_debug.cpp
+++ b/libc/malloc_debug/malloc_debug.cpp
@@ -38,6 +38,7 @@
 #include <vector>
 
 #include <android-base/file.h>
+#include <android-base/properties.h>
 #include <android-base/stringprintf.h>
 #include <private/bionic_malloc_dispatch.h>
 
@@ -69,9 +70,10 @@
 bool debug_initialize(const MallocDispatch* malloc_dispatch, int* malloc_zygote_child,
                       const char* options);
 void debug_finalize();
-bool debug_dump_heap(const char* file_name);
+void debug_dump_heap(const char* file_name);
 void debug_get_malloc_leak_info(uint8_t** info, size_t* overall_size, size_t* info_size,
                                 size_t* total_memory, size_t* backtrace_size);
+bool debug_write_malloc_leak_info(FILE* fp);
 ssize_t debug_malloc_backtrace(void* pointer, uintptr_t* frames, size_t frame_count);
 void debug_free_malloc_leak_info(uint8_t* info);
 size_t debug_malloc_usable_size(void* pointer);
@@ -813,28 +815,11 @@
 
 static std::mutex g_dump_lock;
 
-bool debug_dump_heap(const char* file_name) {
-  ScopedDisableDebugCalls disable;
+static void write_dump(FILE* fp) {
+  fprintf(fp, "Android Native Heap Dump v1.2\n\n");
 
-  std::lock_guard<std::mutex> guard(g_dump_lock);
-
-  FILE* fp = fopen(file_name, "w+e");
-  if (fp == nullptr) {
-    error_log("Unable to create file: %s", file_name);
-    return false;
-  }
-  error_log("Dumping to file: %s\n", file_name);
-
-  if (!(g_debug->config().options() & BACKTRACE)) {
-    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");
-    fclose(fp);
-    return false;
-  }
-
-  fprintf(fp, "Android Native Heap Dump v1.1\n\n");
+  std::string fingerprint = android::base::GetProperty("ro.build.fingerprint", "unknown");
+  fprintf(fp, "Build fingerprint: '%s'\n\n", fingerprint.c_str());
 
   PointerData::DumpLiveToFile(fp);
 
@@ -846,6 +831,33 @@
     fprintf(fp, "%s", content.c_str());
   }
   fprintf(fp, "END\n");
-  fclose(fp);
+}
+
+bool debug_write_malloc_leak_info(FILE* fp) {
+  ScopedDisableDebugCalls disable;
+
+  std::lock_guard<std::mutex> guard(g_dump_lock);
+
+  if (!(g_debug->config().options() & BACKTRACE)) {
+    return false;
+  }
+
+  write_dump(fp);
   return true;
 }
+
+void debug_dump_heap(const char* file_name) {
+  ScopedDisableDebugCalls disable;
+
+  std::lock_guard<std::mutex> guard(g_dump_lock);
+
+  FILE* fp = fopen(file_name, "w+e");
+  if (fp == nullptr) {
+    error_log("Unable to create file: %s", file_name);
+    return;
+  }
+
+  error_log("Dumping to file: %s\n", file_name);
+  write_dump(fp);
+  fclose(fp);
+}
diff --git a/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp b/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp
index 0663f6a..cd6d2c2 100644
--- a/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp
+++ b/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp
@@ -1250,10 +1250,15 @@
         continue;
       }
     }
-    if (line == "MAPS") {
-      skip_map_data = true;
+
+    if (android::base::StartsWith(line, "Build fingerprint:")) {
+      sanitized += "Build fingerprint: ''\n";
+    } else {
+      if (line == "MAPS") {
+        skip_map_data = true;
+      }
+      sanitized += line + '\n';
     }
-    sanitized += line + '\n';
   }
   return sanitized;
 }
@@ -1312,7 +1317,9 @@
   std::string sanitized(SanitizeHeapData(actual));
 
   std::string expected =
-R"(Android Native Heap Dump v1.1
+R"(Android Native Heap Dump v1.2
+
+Build fingerprint: ''
 
 Total memory: 405
 Allocation records: 6
@@ -1377,7 +1384,9 @@
   std::string sanitized(SanitizeHeapData(actual));
 
   std::string expected =
-R"(Android Native Heap Dump v1.1
+R"(Android Native Heap Dump v1.2
+
+Build fingerprint: ''
 
 Total memory: 1200
 Allocation records: 3
@@ -1426,7 +1435,9 @@
   std::string sanitized(SanitizeHeapData(actual));
 
   std::string expected =
-R"(Android Native Heap Dump v1.1
+R"(Android Native Heap Dump v1.2
+
+Build fingerprint: ''
 
 Total memory: 1000
 Allocation records: 2
@@ -1482,7 +1493,9 @@
   std::string sanitized(SanitizeHeapData(actual));
 
   std::string expected =
-R"(Android Native Heap Dump v1.1
+R"(Android Native Heap Dump v1.2
+
+Build fingerprint: ''
 
 Total memory: 1200
 Allocation records: 3