| /* |
| * 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 <media/MemoryLeakTrackUtil.h> |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <sys/types.h> |
| #include <unistd.h> |
| |
| /* |
| * 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<size_t *>(ptr); |
| ptr += sizeof(size_t); |
| |
| e->dups = *reinterpret_cast<size_t *>(ptr); |
| ptr += sizeof(size_t); |
| |
| 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()); |
| 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 |