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        strcat(mPtr, s);
53    }
54
55    const char *string() const {
56        return mPtr;
57    }
58
59    size_t size() const {
60        return strlen(mPtr);
61    }
62
63private:
64    char *mPtr;
65
66    MyString8(const MyString8 &);
67    MyString8 &operator=(const MyString8 &);
68};
69
70void dumpMemoryAddresses(int fd)
71{
72    const size_t SIZE = 256;
73    char buffer[SIZE];
74    MyString8 result;
75
76    typedef struct {
77        size_t size;
78        size_t dups;
79        intptr_t * backtrace;
80    } AllocEntry;
81
82    uint8_t *info = NULL;
83    size_t overallSize = 0;
84    size_t infoSize = 0;
85    size_t totalMemory = 0;
86    size_t backtraceSize = 0;
87
88    get_malloc_leak_info(&info, &overallSize, &infoSize, &totalMemory, &backtraceSize);
89    if (info) {
90        uint8_t *ptr = info;
91        size_t count = overallSize / infoSize;
92
93        snprintf(buffer, SIZE, " Allocation count %i\n", count);
94        result.append(buffer);
95        snprintf(buffer, SIZE, " Total memory %i\n", totalMemory);
96        result.append(buffer);
97
98        AllocEntry * entries = new AllocEntry[count];
99
100        for (size_t i = 0; i < count; i++) {
101            // Each entry should be size_t, size_t, intptr_t[backtraceSize]
102            AllocEntry *e = &entries[i];
103
104            e->size = *reinterpret_cast<size_t *>(ptr);
105            ptr += sizeof(size_t);
106
107            e->dups = *reinterpret_cast<size_t *>(ptr);
108            ptr += sizeof(size_t);
109
110            e->backtrace = reinterpret_cast<intptr_t *>(ptr);
111            ptr += sizeof(intptr_t) * backtraceSize;
112        }
113
114        // Now we need to sort the entries.  They come sorted by size but
115        // not by stack trace which causes problems using diff.
116        bool moved;
117        do {
118            moved = false;
119            for (size_t i = 0; i < (count - 1); i++) {
120                AllocEntry *e1 = &entries[i];
121                AllocEntry *e2 = &entries[i+1];
122
123                bool swap = e1->size < e2->size;
124                if (e1->size == e2->size) {
125                    for(size_t j = 0; j < backtraceSize; j++) {
126                        if (e1->backtrace[j] == e2->backtrace[j]) {
127                            continue;
128                        }
129                        swap = e1->backtrace[j] < e2->backtrace[j];
130                        break;
131                    }
132                }
133                if (swap) {
134                    AllocEntry t = entries[i];
135                    entries[i] = entries[i+1];
136                    entries[i+1] = t;
137                    moved = true;
138                }
139            }
140        } while (moved);
141
142        for (size_t i = 0; i < count; i++) {
143            AllocEntry *e = &entries[i];
144
145            snprintf(buffer, SIZE, "size %8i, dup %4i, ", e->size, e->dups);
146            result.append(buffer);
147            for (size_t ct = 0; (ct < backtraceSize) && e->backtrace[ct]; ct++) {
148                if (ct) {
149                    result.append(", ");
150                }
151                snprintf(buffer, SIZE, "0x%08x", e->backtrace[ct]);
152                result.append(buffer);
153            }
154            result.append("\n");
155        }
156
157        delete[] entries;
158        free_malloc_leak_info(info);
159    }
160
161    write(fd, result.string(), result.size());
162}
163
164#else
165// Does nothing
166void dumpMemoryAddresses(int fd) {}
167
168#endif
169}  // namespace android
170