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