/* * Copyright 2011, The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include /* * The code here originally resided in MediaPlayerService.cpp and was * shamelessly copied over to support memory leak tracking from * multiple places. */ namespace android { #if defined(__arm__) 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); // Use the String-class below instead of String8 to allocate all memory // 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; char buffer[SIZE]; MyString8 result; typedef struct { 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); 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(ptr); ptr += sizeof(size_t); e->dups = *reinterpret_cast(ptr); ptr += sizeof(size_t); e->backtrace = reinterpret_cast(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()); result.clear(); for (size_t i = 0; i < count; i++) { AllocEntry *e = &entries[i]; snprintf(buffer, SIZE, "size %8i, dup %4i, ", e->size, e->dups); 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()); result.clear(); } delete[] entries; free_malloc_leak_info(info); } } #else // Does nothing void dumpMemoryAddresses(int fd __unused) {} #endif } // namespace android