1 /* 2 * Copyright 2011, The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include <media/MemoryLeakTrackUtil.h> 18 19 #include <stdio.h> 20 #include <stdlib.h> 21 #include <string.h> 22 #include <sys/types.h> 23 #include <unistd.h> 24 25 /* 26 * The code here originally resided in MediaPlayerService.cpp and was 27 * shamelessly copied over to support memory leak tracking from 28 * multiple places. 29 */ 30 namespace android { 31 32 #if defined(__arm__) 33 34 extern "C" void get_malloc_leak_info(uint8_t** info, size_t* overallSize, 35 size_t* infoSize, size_t* totalMemory, size_t* backtraceSize); 36 37 extern "C" void free_malloc_leak_info(uint8_t* info); 38 39 // Use the String-class below instead of String8 to allocate all memory 40 // beforehand and not reenter the heap while we are examining it... 41 struct MyString8 { 42 static const size_t MAX_SIZE = 256 * 1024; 43 44 MyString8() 45 : mPtr((char *)malloc(MAX_SIZE)) { 46 *mPtr = '\0'; 47 } 48 49 ~MyString8() { 50 free(mPtr); 51 } 52 53 void append(const char *s) { 54 strncat(mPtr, s, MAX_SIZE - size() - 1); 55 } 56 57 const char *string() const { 58 return mPtr; 59 } 60 61 size_t size() const { 62 return strlen(mPtr); 63 } 64 65 void clear() { 66 *mPtr = '\0'; 67 } 68 69 private: 70 char *mPtr; 71 72 MyString8(const MyString8 &); 73 MyString8 &operator=(const MyString8 &); 74 }; 75 76 void dumpMemoryAddresses(int fd) 77 { 78 const size_t SIZE = 256; 79 char buffer[SIZE]; 80 MyString8 result; 81 82 typedef struct { 83 size_t size; 84 size_t dups; 85 intptr_t * backtrace; 86 } AllocEntry; 87 88 uint8_t *info = NULL; 89 size_t overallSize = 0; 90 size_t infoSize = 0; 91 size_t totalMemory = 0; 92 size_t backtraceSize = 0; 93 94 get_malloc_leak_info(&info, &overallSize, &infoSize, &totalMemory, &backtraceSize); 95 if (info) { 96 uint8_t *ptr = info; 97 size_t count = overallSize / infoSize; 98 99 snprintf(buffer, SIZE, " Allocation count %i\n", count); 100 result.append(buffer); 101 snprintf(buffer, SIZE, " Total memory %i\n", totalMemory); 102 result.append(buffer); 103 104 AllocEntry * entries = new AllocEntry[count]; 105 106 for (size_t i = 0; i < count; i++) { 107 // Each entry should be size_t, size_t, intptr_t[backtraceSize] 108 AllocEntry *e = &entries[i]; 109 110 e->size = *reinterpret_cast<size_t *>(ptr); 111 ptr += sizeof(size_t); 112 113 e->dups = *reinterpret_cast<size_t *>(ptr); 114 ptr += sizeof(size_t); 115 116 e->backtrace = reinterpret_cast<intptr_t *>(ptr); 117 ptr += sizeof(intptr_t) * backtraceSize; 118 } 119 120 // Now we need to sort the entries. They come sorted by size but 121 // not by stack trace which causes problems using diff. 122 bool moved; 123 do { 124 moved = false; 125 for (size_t i = 0; i < (count - 1); i++) { 126 AllocEntry *e1 = &entries[i]; 127 AllocEntry *e2 = &entries[i+1]; 128 129 bool swap = e1->size < e2->size; 130 if (e1->size == e2->size) { 131 for(size_t j = 0; j < backtraceSize; j++) { 132 if (e1->backtrace[j] == e2->backtrace[j]) { 133 continue; 134 } 135 swap = e1->backtrace[j] < e2->backtrace[j]; 136 break; 137 } 138 } 139 if (swap) { 140 AllocEntry t = entries[i]; 141 entries[i] = entries[i+1]; 142 entries[i+1] = t; 143 moved = true; 144 } 145 } 146 } while (moved); 147 148 write(fd, result.string(), result.size()); 149 result.clear(); 150 151 for (size_t i = 0; i < count; i++) { 152 AllocEntry *e = &entries[i]; 153 154 snprintf(buffer, SIZE, "size %8i, dup %4i, ", e->size, e->dups); 155 result.append(buffer); 156 for (size_t ct = 0; (ct < backtraceSize) && e->backtrace[ct]; ct++) { 157 if (ct) { 158 result.append(", "); 159 } 160 snprintf(buffer, SIZE, "0x%08x", e->backtrace[ct]); 161 result.append(buffer); 162 } 163 result.append("\n"); 164 165 write(fd, result.string(), result.size()); 166 result.clear(); 167 } 168 169 delete[] entries; 170 free_malloc_leak_info(info); 171 } 172 } 173 174 #else 175 // Does nothing 176 void dumpMemoryAddresses(int fd __unused) {} 177 178 #endif 179 } // namespace android 180