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 <sys/types.h>
22 #include <unistd.h>
23
24 /*
25 * The code here originally resided in MediaPlayerService.cpp and was
26 * shamelessly copied over to support memory leak tracking from
27 * multiple places.
28 */
29 namespace android {
30
31 #if defined(__arm__)
32
33 extern "C" void get_malloc_leak_info(uint8_t** info, size_t* overallSize,
34 size_t* infoSize, size_t* totalMemory, size_t* backtraceSize);
35
36 extern "C" void free_malloc_leak_info(uint8_t* info);
37
38 // Use the String-class below instead of String8 to allocate all memory
39 // beforehand and not reenter the heap while we are examining it...
40 struct MyString8 {
41 static const size_t MAX_SIZE = 256 * 1024;
42
MyString8android::MyString843 MyString8()
44 : mPtr((char *)malloc(MAX_SIZE)) {
45 *mPtr = '\0';
46 }
47
~MyString8android::MyString848 ~MyString8() {
49 free(mPtr);
50 }
51
appendandroid::MyString852 void append(const char *s) {
53 strncat(mPtr, s, MAX_SIZE - size() - 1);
54 }
55
stringandroid::MyString856 const char *string() const {
57 return mPtr;
58 }
59
sizeandroid::MyString860 size_t size() const {
61 return strlen(mPtr);
62 }
63
clearandroid::MyString864 void clear() {
65 *mPtr = '\0';
66 }
67
68 private:
69 char *mPtr;
70
71 MyString8(const MyString8 &);
72 MyString8 &operator=(const MyString8 &);
73 };
74
dumpMemoryAddresses(int fd)75 void dumpMemoryAddresses(int fd)
76 {
77 const size_t SIZE = 256;
78 char buffer[SIZE];
79 MyString8 result;
80
81 typedef struct {
82 size_t size;
83 size_t dups;
84 intptr_t * backtrace;
85 } AllocEntry;
86
87 uint8_t *info = NULL;
88 size_t overallSize = 0;
89 size_t infoSize = 0;
90 size_t totalMemory = 0;
91 size_t backtraceSize = 0;
92
93 get_malloc_leak_info(&info, &overallSize, &infoSize, &totalMemory, &backtraceSize);
94 if (info) {
95 uint8_t *ptr = info;
96 size_t count = overallSize / infoSize;
97
98 snprintf(buffer, SIZE, " Allocation count %i\n", count);
99 result.append(buffer);
100 snprintf(buffer, SIZE, " Total memory %i\n", totalMemory);
101 result.append(buffer);
102
103 AllocEntry * entries = new AllocEntry[count];
104
105 for (size_t i = 0; i < count; i++) {
106 // Each entry should be size_t, size_t, intptr_t[backtraceSize]
107 AllocEntry *e = &entries[i];
108
109 e->size = *reinterpret_cast<size_t *>(ptr);
110 ptr += sizeof(size_t);
111
112 e->dups = *reinterpret_cast<size_t *>(ptr);
113 ptr += sizeof(size_t);
114
115 e->backtrace = reinterpret_cast<intptr_t *>(ptr);
116 ptr += sizeof(intptr_t) * backtraceSize;
117 }
118
119 // Now we need to sort the entries. They come sorted by size but
120 // not by stack trace which causes problems using diff.
121 bool moved;
122 do {
123 moved = false;
124 for (size_t i = 0; i < (count - 1); i++) {
125 AllocEntry *e1 = &entries[i];
126 AllocEntry *e2 = &entries[i+1];
127
128 bool swap = e1->size < e2->size;
129 if (e1->size == e2->size) {
130 for(size_t j = 0; j < backtraceSize; j++) {
131 if (e1->backtrace[j] == e2->backtrace[j]) {
132 continue;
133 }
134 swap = e1->backtrace[j] < e2->backtrace[j];
135 break;
136 }
137 }
138 if (swap) {
139 AllocEntry t = entries[i];
140 entries[i] = entries[i+1];
141 entries[i+1] = t;
142 moved = true;
143 }
144 }
145 } while (moved);
146
147 write(fd, result.string(), result.size());
148 result.clear();
149
150 for (size_t i = 0; i < count; i++) {
151 AllocEntry *e = &entries[i];
152
153 snprintf(buffer, SIZE, "size %8i, dup %4i, ", e->size, e->dups);
154 result.append(buffer);
155 for (size_t ct = 0; (ct < backtraceSize) && e->backtrace[ct]; ct++) {
156 if (ct) {
157 result.append(", ");
158 }
159 snprintf(buffer, SIZE, "0x%08x", e->backtrace[ct]);
160 result.append(buffer);
161 }
162 result.append("\n");
163
164 write(fd, result.string(), result.size());
165 result.clear();
166 }
167
168 delete[] entries;
169 free_malloc_leak_info(info);
170 }
171 }
172
173 #else
174 // Does nothing
175 void dumpMemoryAddresses(int fd) {}
176
177 #endif
178 } // namespace android
179