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