summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Christopher Ferris <cferris@google.com> 2018-06-13 13:19:57 -0700
committer Christopher Ferris <cferris@google.com> 2018-06-15 12:29:36 -0700
commitffa139e83d830ef01106ab27d0ed4a5a422bc2f7 (patch)
tree8db53b92b68a5f2ce2ace93b5cf6723b4b49f54e
parentaa5d8dfeb0e12466da355fc4111ab8a089afd140 (diff)
Use the malloc debug heap dumper.
Instead of having the malloc debug heap dump code live in frameworks code, call into malloc debug to do the dump. Test: Ran am dumpheap -n <PID> <FILE> of a process with and without Test: malloc debug enabled. Change-Id: I7911a3ee7dcbc79dd11003a24e27ff99c8301d43 Merged-In: I7911a3ee7dcbc79dd11003a24e27ff99c8301d43 (cherry picked from commit 38e2c3bc9c50770aa5efce47f90fbcfcdda523de)
-rw-r--r--core/jni/android_os_Debug.cpp147
1 files changed, 6 insertions, 141 deletions
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index d3da21b5635b..b35d92fe0d0c 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -902,146 +902,6 @@ jint android_os_Debug_getLocalObjectCount(JNIEnv* env, jobject clazz);
jint android_os_Debug_getProxyObjectCount(JNIEnv* env, jobject clazz);
jint android_os_Debug_getDeathObjectCount(JNIEnv* env, jobject clazz);
-
-/* pulled out of bionic */
-extern "C" void get_malloc_leak_info(uint8_t** info, size_t* overallSize,
- size_t* infoSize, size_t* totalMemory, size_t* backtraceSize);
-extern "C" void free_malloc_leak_info(uint8_t* info);
-#define SIZE_FLAG_ZYGOTE_CHILD (1<<31)
-
-static size_t gNumBacktraceElements;
-
-/*
- * This is a qsort() callback.
- *
- * See dumpNativeHeap() for comments about the data format and sort order.
- */
-static int compareHeapRecords(const void* vrec1, const void* vrec2)
-{
- const size_t* rec1 = (const size_t*) vrec1;
- const size_t* rec2 = (const size_t*) vrec2;
- size_t size1 = *rec1;
- size_t size2 = *rec2;
-
- if (size1 < size2) {
- return 1;
- } else if (size1 > size2) {
- return -1;
- }
-
- uintptr_t* bt1 = (uintptr_t*)(rec1 + 2);
- uintptr_t* bt2 = (uintptr_t*)(rec2 + 2);
- for (size_t idx = 0; idx < gNumBacktraceElements; idx++) {
- uintptr_t addr1 = bt1[idx];
- uintptr_t addr2 = bt2[idx];
- if (addr1 == addr2) {
- if (addr1 == 0)
- break;
- continue;
- }
- if (addr1 < addr2) {
- return -1;
- } else if (addr1 > addr2) {
- return 1;
- }
- }
-
- return 0;
-}
-
-/*
- * The get_malloc_leak_info() call returns an array of structs that
- * look like this:
- *
- * size_t size
- * size_t allocations
- * intptr_t backtrace[32]
- *
- * "size" is the size of the allocation, "backtrace" is a fixed-size
- * array of function pointers, and "allocations" is the number of
- * allocations with the exact same size and backtrace.
- *
- * The entries are sorted by descending total size (i.e. size*allocations)
- * then allocation count. For best results with "diff" we'd like to sort
- * primarily by individual size then stack trace. Since the entries are
- * fixed-size, and we're allowed (by the current implementation) to mangle
- * them, we can do this in place.
- */
-static void dumpNativeHeap(FILE* fp)
-{
- uint8_t* info = NULL;
- size_t overallSize, infoSize, totalMemory, backtraceSize;
-
- get_malloc_leak_info(&info, &overallSize, &infoSize, &totalMemory,
- &backtraceSize);
- if (info == NULL) {
- 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");
- return;
- }
- assert(infoSize != 0);
- assert(overallSize % infoSize == 0);
-
- fprintf(fp, "Android Native Heap Dump v1.0\n\n");
-
- size_t recordCount = overallSize / infoSize;
- fprintf(fp, "Total memory: %zu\n", totalMemory);
- fprintf(fp, "Allocation records: %zd\n", recordCount);
- fprintf(fp, "Backtrace size: %zd\n", backtraceSize);
- fprintf(fp, "\n");
-
- /* re-sort the entries */
- gNumBacktraceElements = backtraceSize;
- qsort(info, recordCount, infoSize, compareHeapRecords);
-
- /* dump the entries to the file */
- const uint8_t* ptr = info;
- for (size_t idx = 0; idx < recordCount; idx++) {
- size_t size = *(size_t*) ptr;
- size_t allocations = *(size_t*) (ptr + sizeof(size_t));
- uintptr_t* backtrace = (uintptr_t*) (ptr + sizeof(size_t) * 2);
-
- fprintf(fp, "z %d sz %8zu num %4zu bt",
- (size & SIZE_FLAG_ZYGOTE_CHILD) != 0,
- size & ~SIZE_FLAG_ZYGOTE_CHILD,
- allocations);
- for (size_t bt = 0; bt < backtraceSize; bt++) {
- if (backtrace[bt] == 0) {
- break;
- } else {
-#ifdef __LP64__
- fprintf(fp, " %016" PRIxPTR, backtrace[bt]);
-#else
- fprintf(fp, " %08" PRIxPTR, backtrace[bt]);
-#endif
- }
- }
- fprintf(fp, "\n");
-
- ptr += infoSize;
- }
-
- free_malloc_leak_info(info);
-
- fprintf(fp, "MAPS\n");
- const char* maps = "/proc/self/maps";
- UniqueFile in = MakeUniqueFile(maps, "re");
- if (in == nullptr) {
- fprintf(fp, "Could not open %s\n", maps);
- return;
- }
- char buf[BUFSIZ];
- while (size_t n = fread(buf, sizeof(char), BUFSIZ, in.get())) {
- fwrite(buf, sizeof(char), n, fp);
- }
-
- fprintf(fp, "END\n");
-}
-
static bool openFile(JNIEnv* env, jobject fileDescriptor, UniqueFile& fp)
{
if (fileDescriptor == NULL) {
@@ -1072,6 +932,9 @@ static bool openFile(JNIEnv* env, jobject fileDescriptor, UniqueFile& fp)
return true;
}
+/* pulled out of bionic */
+extern "C" void write_malloc_leak_info(FILE* fp);
+
/*
* Dump the native heap, writing human-readable output to the specified
* file descriptor.
@@ -1085,7 +948,9 @@ static void android_os_Debug_dumpNativeHeap(JNIEnv* env, jobject,
}
ALOGD("Native heap dump starting...\n");
- dumpNativeHeap(fp.get());
+ // Formatting of the native heap dump is handled by malloc debug itself.
+ // See https://android.googlesource.com/platform/bionic/+/master/libc/malloc_debug/README.md#backtrace-heap-dump-format
+ write_malloc_leak_info(fp.get());
ALOGD("Native heap dump complete.\n");
}