MemoryLeakTrackUtil.cpp revision f1063e2659cad01ec334a265c31734c63c319cc4
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 */
30namespace android {
31
32#if defined(__arm__)
33
34extern "C" void get_malloc_leak_info(uint8_t** info, size_t* overallSize,
35        size_t* infoSize, size_t* totalMemory, size_t* backtraceSize);
36
37extern "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...
41struct 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
69private:
70    char *mPtr;
71
72    MyString8(const MyString8 &);
73    MyString8 &operator=(const MyString8 &);
74};
75
76void 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
176void dumpMemoryAddresses(int fd __unused) {}
177
178#endif
179}  // namespace android
180