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 c84a2a2601
)
This commit is contained in:
parent
2583b0adb2
commit
2e1a40a203
|
@ -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 @@ enum FunctionEnum : uint8_t {
|
|||
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 void (*finalize_func_t)();
|
|||
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 @@ extern "C" void free_malloc_leak_info(uint8_t* info) {
|
|||
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 @@ static void* LoadSharedLibrary(const char* shared_lib, const char* prefix, Mallo
|
|||
"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];
|
||||
|
|
|
@ -1634,6 +1634,7 @@ LIBC_PRIVATE {
|
|||
tkill; # arm x86 mips
|
||||
wait3; # arm x86 mips
|
||||
wcswcs; # arm x86 mips
|
||||
write_malloc_leak_info;
|
||||
} LIBC_P;
|
||||
|
||||
LIBC_DEPRECATED {
|
||||
|
|
|
@ -1352,6 +1352,7 @@ LIBC_PRIVATE {
|
|||
free_malloc_leak_info;
|
||||
get_malloc_leak_info;
|
||||
gMallocLeakZygoteChild;
|
||||
write_malloc_leak_info;
|
||||
} LIBC_P;
|
||||
|
||||
LIBC_DEPRECATED {
|
||||
|
|
|
@ -1660,6 +1660,7 @@ LIBC_PRIVATE {
|
|||
tkill; # arm x86 mips
|
||||
wait3; # arm x86 mips
|
||||
wcswcs; # arm x86 mips
|
||||
write_malloc_leak_info;
|
||||
} LIBC_P;
|
||||
|
||||
LIBC_DEPRECATED {
|
||||
|
|
|
@ -1475,6 +1475,7 @@ LIBC_PRIVATE {
|
|||
tkill; # arm x86 mips
|
||||
wait3; # arm x86 mips
|
||||
wcswcs; # arm x86 mips
|
||||
write_malloc_leak_info;
|
||||
} LIBC_P;
|
||||
|
||||
LIBC_DEPRECATED {
|
||||
|
|
|
@ -1352,6 +1352,7 @@ LIBC_PRIVATE {
|
|||
free_malloc_leak_info;
|
||||
get_malloc_leak_info;
|
||||
gMallocLeakZygoteChild;
|
||||
write_malloc_leak_info;
|
||||
} LIBC_P;
|
||||
|
||||
LIBC_DEPRECATED {
|
||||
|
|
|
@ -1474,6 +1474,7 @@ LIBC_PRIVATE {
|
|||
tkill; # arm x86 mips
|
||||
wait3; # arm x86 mips
|
||||
wcswcs; # arm x86 mips
|
||||
write_malloc_leak_info;
|
||||
} LIBC_P;
|
||||
|
||||
LIBC_DEPRECATED {
|
||||
|
|
|
@ -1352,6 +1352,7 @@ LIBC_PRIVATE {
|
|||
free_malloc_leak_info;
|
||||
get_malloc_leak_info;
|
||||
gMallocLeakZygoteChild;
|
||||
write_malloc_leak_info;
|
||||
} LIBC_P;
|
||||
|
||||
LIBC_DEPRECATED {
|
||||
|
|
|
@ -139,5 +139,6 @@ cc_test {
|
|||
"-Wall",
|
||||
"-Werror",
|
||||
"-Wno-error=format-zero-length",
|
||||
"-O0",
|
||||
],
|
||||
}
|
||||
|
|
|
@ -161,7 +161,7 @@ on the signal will be backtrace\_dump\_prefix.**PID**.txt. The filename chosen
|
|||
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 final section is the map data for the process:
|
|||
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
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ LIBC_MALLOC_DEBUG {
|
|||
debug_pvalloc;
|
||||
debug_realloc;
|
||||
debug_valloc;
|
||||
debug_write_malloc_leak_info;
|
||||
|
||||
local:
|
||||
*;
|
||||
|
|
|
@ -19,6 +19,7 @@ LIBC_MALLOC_DEBUG {
|
|||
debug_memalign;
|
||||
debug_posix_memalign;
|
||||
debug_realloc;
|
||||
debug_write_malloc_leak_info;
|
||||
|
||||
local:
|
||||
*;
|
||||
|
|
|
@ -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 @@ __BEGIN_DECLS
|
|||
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 @@ void* debug_valloc(size_t size) {
|
|||
|
||||
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 @@ bool debug_dump_heap(const char* file_name) {
|
|||
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);
|
||||
}
|
||||
|
|
|
@ -1250,10 +1250,15 @@ static std::string SanitizeHeapData(const std::string& data) {
|
|||
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 @@ void MallocDebugTest::BacktraceDumpOnSignal(bool trigger_with_alloc) {
|
|||
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 @@ TEST_F(MallocDebugTest, backtrace_dump_on_exit) {
|
|||
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 @@ TEST_F(MallocDebugTest, backtrace_dump_on_exit_shared_backtrace) {
|
|||
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 @@ TEST_F(MallocDebugTest, backtrace_full_dump_on_exit) {
|
|||
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
|
||||
|
|
Loading…
Reference in New Issue