Loading drm/drmserver/DrmManagerService.cpp +6 −2 Original line number Original line Diff line number Diff line Loading @@ -337,7 +337,7 @@ ssize_t DrmManagerService::pread(int uniqueId, DecryptHandle* decryptHandle, return mDrmManager->pread(uniqueId, decryptHandle, buffer, numBytes, offset); return mDrmManager->pread(uniqueId, decryptHandle, buffer, numBytes, offset); } } status_t DrmManagerService::dump(int fd, const Vector<String16>& /* args */) status_t DrmManagerService::dump(int fd, const Vector<String16>& args) { { const size_t SIZE = 256; const size_t SIZE = 256; char buffer[SIZE]; char buffer[SIZE]; Loading @@ -357,8 +357,12 @@ status_t DrmManagerService::dump(int fd, const Vector<String16>& /* args */) } } } } if (dumpMem) { if (dumpMem) { dumpMemoryAddresses(fd); result.append("\nDumping memory:\n"); std::string s = dumpMemoryAddresses(100 /* limit */); result.append(s.c_str(), s.size()); } } #else (void)args; #endif #endif } } write(fd, result.string(), result.size()); write(fd, result.string(), result.size()); Loading include/media/MemoryLeakTrackUtil.h +7 −2 Original line number Original line Diff line number Diff line Loading @@ -16,11 +16,16 @@ #ifndef MEMORY_LEAK_TRACK_UTIL_H #ifndef MEMORY_LEAK_TRACK_UTIL_H #define MEMORY_LEAK_TRACK_UTIL_H #define MEMORY_LEAK_TRACK_UTIL_H #include <iostream> namespace android { namespace android { /* /* * Dump the memory address of the calling process to the given fd. * Dump the heap memory of the calling process, sorted by total size * (allocation size * number of allocations). * * limit is the number of unique allocations to return. */ */ extern void dumpMemoryAddresses(int fd); extern std::string dumpMemoryAddresses(size_t limit); }; }; Loading media/libmedia/Android.mk +3 −0 Original line number Original line Diff line number Diff line Loading @@ -81,6 +81,9 @@ LOCAL_SHARED_LIBRARIES := \ LOCAL_WHOLE_STATIC_LIBRARIES := libmedia_helper LOCAL_WHOLE_STATIC_LIBRARIES := libmedia_helper # for memory heap analysis LOCAL_STATIC_LIBRARIES := libc_malloc_debug_backtrace libc_logging LOCAL_MODULE:= libmedia LOCAL_MODULE:= libmedia LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk Loading media/libmedia/MemoryLeakTrackUtil.cpp +62 −144 Original line number Original line Diff line number Diff line Loading @@ -14,166 +14,84 @@ * limitations under the License. * limitations under the License. */ */ #include <media/MemoryLeakTrackUtil.h> #include <stdio.h> //#define LOG_NDEBUG 0 #include <stdlib.h> #define LOG_TAG "MemoryLeackTrackUtil" #include <string.h> #include <utils/Log.h> #include <sys/types.h> #include <unistd.h> #include "media/MemoryLeakTrackUtil.h" #include <sstream> /* /* * The code here originally resided in MediaPlayerService.cpp and was * The code here originally resided in MediaPlayerService.cpp * shamelessly copied over to support memory leak tracking from * multiple places. */ */ namespace android { // Figure out the abi based on defined macros. #if defined(__arm__) #if defined(__arm__) #define ABI_STRING "arm" #elif defined(__aarch64__) #define ABI_STRING "arm64" #elif defined(__mips__) && !defined(__LP64__) #define ABI_STRING "mips" #elif defined(__mips__) && defined(__LP64__) #define ABI_STRING "mips64" #elif defined(__i386__) #define ABI_STRING "x86" #elif defined(__x86_64__) #define ABI_STRING "x86_64" #else #error "Unsupported ABI" #endif extern std::string backtrace_string(const uintptr_t* frames, size_t frame_count); namespace android { extern "C" void get_malloc_leak_info(uint8_t** info, size_t* overallSize, extern "C" void get_malloc_leak_info(uint8_t** info, size_t* overallSize, size_t* infoSize, size_t* totalMemory, size_t* backtraceSize); size_t* infoSize, size_t* totalMemory, size_t* backtraceSize); extern "C" void free_malloc_leak_info(uint8_t* info); extern "C" void free_malloc_leak_info(uint8_t* info); // Use the String-class below instead of String8 to allocate all memory std::string dumpMemoryAddresses(size_t limit) // beforehand and not reenter the heap while we are examining it... struct MyString8 { static const size_t MAX_SIZE = 256 * 1024; MyString8() : mPtr((char *)malloc(MAX_SIZE)) { *mPtr = '\0'; } ~MyString8() { free(mPtr); } void append(const char *s) { strncat(mPtr, s, MAX_SIZE - size() - 1); } const char *string() const { return mPtr; } size_t size() const { return strlen(mPtr); } void clear() { *mPtr = '\0'; } private: char *mPtr; MyString8(const MyString8 &); MyString8 &operator=(const MyString8 &); }; void dumpMemoryAddresses(int fd) { { const size_t SIZE = 256; uint8_t *info; char buffer[SIZE]; size_t overallSize; MyString8 result; size_t infoSize; size_t totalMemory; typedef struct { size_t backtraceSize; size_t size; size_t dups; intptr_t * backtrace; } AllocEntry; uint8_t *info = NULL; size_t overallSize = 0; size_t infoSize = 0; size_t totalMemory = 0; size_t backtraceSize = 0; get_malloc_leak_info(&info, &overallSize, &infoSize, &totalMemory, &backtraceSize); get_malloc_leak_info(&info, &overallSize, &infoSize, &totalMemory, &backtraceSize); if (info) { uint8_t *ptr = info; size_t count = overallSize / infoSize; snprintf(buffer, SIZE, " Allocation count %i\n", count); result.append(buffer); snprintf(buffer, SIZE, " Total memory %i\n", totalMemory); result.append(buffer); AllocEntry * entries = new AllocEntry[count]; for (size_t i = 0; i < count; i++) { // Each entry should be size_t, size_t, intptr_t[backtraceSize] AllocEntry *e = &entries[i]; e->size = *reinterpret_cast<size_t *>(ptr); size_t count; ptr += sizeof(size_t); if (info == nullptr || overallSize == 0 || infoSize == 0 || (count = overallSize / infoSize) == 0) { e->dups = *reinterpret_cast<size_t *>(ptr); ALOGD("no malloc info, libc.debug.malloc.program property should be set"); ptr += sizeof(size_t); return std::string(); e->backtrace = reinterpret_cast<intptr_t *>(ptr); ptr += sizeof(intptr_t) * backtraceSize; } // Now we need to sort the entries. They come sorted by size but // not by stack trace which causes problems using diff. bool moved; do { moved = false; for (size_t i = 0; i < (count - 1); i++) { AllocEntry *e1 = &entries[i]; AllocEntry *e2 = &entries[i+1]; bool swap = e1->size < e2->size; if (e1->size == e2->size) { for(size_t j = 0; j < backtraceSize; j++) { if (e1->backtrace[j] == e2->backtrace[j]) { continue; } swap = e1->backtrace[j] < e2->backtrace[j]; break; } } } if (swap) { AllocEntry t = entries[i]; entries[i] = entries[i+1]; entries[i+1] = t; moved = true; } } } while (moved); write(fd, result.string(), result.size()); std::ostringstream oss; result.clear(); oss << totalMemory << " bytes in " << count << " allocations\n"; oss << " ABI: '" ABI_STRING "'" << "\n\n"; if (count > limit) count = limit; // The memory is sorted based on total size which is useful for finding // worst memory offenders. For diffs, sometimes it is preferable to sort // based on the backtrace. for (size_t i = 0; i < count; i++) { for (size_t i = 0; i < count; i++) { AllocEntry *e = &entries[i]; struct AllocEntry { size_t size; // bit 31 is set if this is zygote allocated memory size_t allocations; uintptr_t backtrace[]; }; snprintf(buffer, SIZE, "size %8i, dup %4i, ", e->size, e->dups); const AllocEntry * const e = (AllocEntry *)(info + i * infoSize); result.append(buffer); for (size_t ct = 0; (ct < backtraceSize) && e->backtrace[ct]; ct++) { if (ct) { result.append(", "); } snprintf(buffer, SIZE, "0x%08x", e->backtrace[ct]); result.append(buffer); } result.append("\n"); write(fd, result.string(), result.size()); oss << (e->size * e->allocations) result.clear(); << " bytes ( " << e->size << " bytes * " << e->allocations << " allocations )\n"; oss << backtrace_string(e->backtrace, backtraceSize) << "\n"; } } oss << "\n"; delete[] entries; free_malloc_leak_info(info); free_malloc_leak_info(info); } return oss.str(); } } #else // Does nothing void dumpMemoryAddresses(int fd __unused) {} #endif } // namespace android } // namespace android media/libmediaplayerservice/MediaPlayerService.cpp +3 −1 Original line number Original line Diff line number Diff line Loading @@ -536,7 +536,9 @@ status_t MediaPlayerService::dump(int fd, const Vector<String16>& args) } } } } if (dumpMem) { if (dumpMem) { dumpMemoryAddresses(fd); result.append("\nDumping memory:\n"); std::string s = dumpMemoryAddresses(100 /* limit */); result.append(s.c_str(), s.size()); } } if (unreachableMemory) { if (unreachableMemory) { result.append("\nDumping unreachable memory:\n"); result.append("\nDumping unreachable memory:\n"); Loading Loading
drm/drmserver/DrmManagerService.cpp +6 −2 Original line number Original line Diff line number Diff line Loading @@ -337,7 +337,7 @@ ssize_t DrmManagerService::pread(int uniqueId, DecryptHandle* decryptHandle, return mDrmManager->pread(uniqueId, decryptHandle, buffer, numBytes, offset); return mDrmManager->pread(uniqueId, decryptHandle, buffer, numBytes, offset); } } status_t DrmManagerService::dump(int fd, const Vector<String16>& /* args */) status_t DrmManagerService::dump(int fd, const Vector<String16>& args) { { const size_t SIZE = 256; const size_t SIZE = 256; char buffer[SIZE]; char buffer[SIZE]; Loading @@ -357,8 +357,12 @@ status_t DrmManagerService::dump(int fd, const Vector<String16>& /* args */) } } } } if (dumpMem) { if (dumpMem) { dumpMemoryAddresses(fd); result.append("\nDumping memory:\n"); std::string s = dumpMemoryAddresses(100 /* limit */); result.append(s.c_str(), s.size()); } } #else (void)args; #endif #endif } } write(fd, result.string(), result.size()); write(fd, result.string(), result.size()); Loading
include/media/MemoryLeakTrackUtil.h +7 −2 Original line number Original line Diff line number Diff line Loading @@ -16,11 +16,16 @@ #ifndef MEMORY_LEAK_TRACK_UTIL_H #ifndef MEMORY_LEAK_TRACK_UTIL_H #define MEMORY_LEAK_TRACK_UTIL_H #define MEMORY_LEAK_TRACK_UTIL_H #include <iostream> namespace android { namespace android { /* /* * Dump the memory address of the calling process to the given fd. * Dump the heap memory of the calling process, sorted by total size * (allocation size * number of allocations). * * limit is the number of unique allocations to return. */ */ extern void dumpMemoryAddresses(int fd); extern std::string dumpMemoryAddresses(size_t limit); }; }; Loading
media/libmedia/Android.mk +3 −0 Original line number Original line Diff line number Diff line Loading @@ -81,6 +81,9 @@ LOCAL_SHARED_LIBRARIES := \ LOCAL_WHOLE_STATIC_LIBRARIES := libmedia_helper LOCAL_WHOLE_STATIC_LIBRARIES := libmedia_helper # for memory heap analysis LOCAL_STATIC_LIBRARIES := libc_malloc_debug_backtrace libc_logging LOCAL_MODULE:= libmedia LOCAL_MODULE:= libmedia LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk Loading
media/libmedia/MemoryLeakTrackUtil.cpp +62 −144 Original line number Original line Diff line number Diff line Loading @@ -14,166 +14,84 @@ * limitations under the License. * limitations under the License. */ */ #include <media/MemoryLeakTrackUtil.h> #include <stdio.h> //#define LOG_NDEBUG 0 #include <stdlib.h> #define LOG_TAG "MemoryLeackTrackUtil" #include <string.h> #include <utils/Log.h> #include <sys/types.h> #include <unistd.h> #include "media/MemoryLeakTrackUtil.h" #include <sstream> /* /* * The code here originally resided in MediaPlayerService.cpp and was * The code here originally resided in MediaPlayerService.cpp * shamelessly copied over to support memory leak tracking from * multiple places. */ */ namespace android { // Figure out the abi based on defined macros. #if defined(__arm__) #if defined(__arm__) #define ABI_STRING "arm" #elif defined(__aarch64__) #define ABI_STRING "arm64" #elif defined(__mips__) && !defined(__LP64__) #define ABI_STRING "mips" #elif defined(__mips__) && defined(__LP64__) #define ABI_STRING "mips64" #elif defined(__i386__) #define ABI_STRING "x86" #elif defined(__x86_64__) #define ABI_STRING "x86_64" #else #error "Unsupported ABI" #endif extern std::string backtrace_string(const uintptr_t* frames, size_t frame_count); namespace android { extern "C" void get_malloc_leak_info(uint8_t** info, size_t* overallSize, extern "C" void get_malloc_leak_info(uint8_t** info, size_t* overallSize, size_t* infoSize, size_t* totalMemory, size_t* backtraceSize); size_t* infoSize, size_t* totalMemory, size_t* backtraceSize); extern "C" void free_malloc_leak_info(uint8_t* info); extern "C" void free_malloc_leak_info(uint8_t* info); // Use the String-class below instead of String8 to allocate all memory std::string dumpMemoryAddresses(size_t limit) // beforehand and not reenter the heap while we are examining it... struct MyString8 { static const size_t MAX_SIZE = 256 * 1024; MyString8() : mPtr((char *)malloc(MAX_SIZE)) { *mPtr = '\0'; } ~MyString8() { free(mPtr); } void append(const char *s) { strncat(mPtr, s, MAX_SIZE - size() - 1); } const char *string() const { return mPtr; } size_t size() const { return strlen(mPtr); } void clear() { *mPtr = '\0'; } private: char *mPtr; MyString8(const MyString8 &); MyString8 &operator=(const MyString8 &); }; void dumpMemoryAddresses(int fd) { { const size_t SIZE = 256; uint8_t *info; char buffer[SIZE]; size_t overallSize; MyString8 result; size_t infoSize; size_t totalMemory; typedef struct { size_t backtraceSize; size_t size; size_t dups; intptr_t * backtrace; } AllocEntry; uint8_t *info = NULL; size_t overallSize = 0; size_t infoSize = 0; size_t totalMemory = 0; size_t backtraceSize = 0; get_malloc_leak_info(&info, &overallSize, &infoSize, &totalMemory, &backtraceSize); get_malloc_leak_info(&info, &overallSize, &infoSize, &totalMemory, &backtraceSize); if (info) { uint8_t *ptr = info; size_t count = overallSize / infoSize; snprintf(buffer, SIZE, " Allocation count %i\n", count); result.append(buffer); snprintf(buffer, SIZE, " Total memory %i\n", totalMemory); result.append(buffer); AllocEntry * entries = new AllocEntry[count]; for (size_t i = 0; i < count; i++) { // Each entry should be size_t, size_t, intptr_t[backtraceSize] AllocEntry *e = &entries[i]; e->size = *reinterpret_cast<size_t *>(ptr); size_t count; ptr += sizeof(size_t); if (info == nullptr || overallSize == 0 || infoSize == 0 || (count = overallSize / infoSize) == 0) { e->dups = *reinterpret_cast<size_t *>(ptr); ALOGD("no malloc info, libc.debug.malloc.program property should be set"); ptr += sizeof(size_t); return std::string(); e->backtrace = reinterpret_cast<intptr_t *>(ptr); ptr += sizeof(intptr_t) * backtraceSize; } // Now we need to sort the entries. They come sorted by size but // not by stack trace which causes problems using diff. bool moved; do { moved = false; for (size_t i = 0; i < (count - 1); i++) { AllocEntry *e1 = &entries[i]; AllocEntry *e2 = &entries[i+1]; bool swap = e1->size < e2->size; if (e1->size == e2->size) { for(size_t j = 0; j < backtraceSize; j++) { if (e1->backtrace[j] == e2->backtrace[j]) { continue; } swap = e1->backtrace[j] < e2->backtrace[j]; break; } } } if (swap) { AllocEntry t = entries[i]; entries[i] = entries[i+1]; entries[i+1] = t; moved = true; } } } while (moved); write(fd, result.string(), result.size()); std::ostringstream oss; result.clear(); oss << totalMemory << " bytes in " << count << " allocations\n"; oss << " ABI: '" ABI_STRING "'" << "\n\n"; if (count > limit) count = limit; // The memory is sorted based on total size which is useful for finding // worst memory offenders. For diffs, sometimes it is preferable to sort // based on the backtrace. for (size_t i = 0; i < count; i++) { for (size_t i = 0; i < count; i++) { AllocEntry *e = &entries[i]; struct AllocEntry { size_t size; // bit 31 is set if this is zygote allocated memory size_t allocations; uintptr_t backtrace[]; }; snprintf(buffer, SIZE, "size %8i, dup %4i, ", e->size, e->dups); const AllocEntry * const e = (AllocEntry *)(info + i * infoSize); result.append(buffer); for (size_t ct = 0; (ct < backtraceSize) && e->backtrace[ct]; ct++) { if (ct) { result.append(", "); } snprintf(buffer, SIZE, "0x%08x", e->backtrace[ct]); result.append(buffer); } result.append("\n"); write(fd, result.string(), result.size()); oss << (e->size * e->allocations) result.clear(); << " bytes ( " << e->size << " bytes * " << e->allocations << " allocations )\n"; oss << backtrace_string(e->backtrace, backtraceSize) << "\n"; } } oss << "\n"; delete[] entries; free_malloc_leak_info(info); free_malloc_leak_info(info); } return oss.str(); } } #else // Does nothing void dumpMemoryAddresses(int fd __unused) {} #endif } // namespace android } // namespace android
media/libmediaplayerservice/MediaPlayerService.cpp +3 −1 Original line number Original line Diff line number Diff line Loading @@ -536,7 +536,9 @@ status_t MediaPlayerService::dump(int fd, const Vector<String16>& args) } } } } if (dumpMem) { if (dumpMem) { dumpMemoryAddresses(fd); result.append("\nDumping memory:\n"); std::string s = dumpMemoryAddresses(100 /* limit */); result.append(s.c_str(), s.size()); } } if (unreachableMemory) { if (unreachableMemory) { result.append("\nDumping unreachable memory:\n"); result.append("\nDumping unreachable memory:\n"); Loading