MemoryLeakTrackUtil.cpp revision 8635b7b095fbf7ffc63d3ce791891a9116ace1f6
18635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong/*
28635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong * Copyright 2011, The Android Open Source Project
38635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong *
48635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong * Licensed under the Apache License, Version 2.0 (the "License");
58635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong * you may not use this file except in compliance with the License.
68635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong * You may obtain a copy of the License at
78635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong *
88635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong *     http://www.apache.org/licenses/LICENSE-2.0
98635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong *
108635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong * Unless required by applicable law or agreed to in writing, software
118635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong * distributed under the License is distributed on an "AS IS" BASIS,
128635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
138635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong * See the License for the specific language governing permissions and
148635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong * limitations under the License.
158635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong */
168635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong
178635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong#include <media/MemoryLeakTrackUtil.h>
188635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong
198635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong#include <stdio.h>
208635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong#include <sys/types.h>
218635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong#include <unistd.h>
228635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong
238635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong/*
248635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong * The code here originally resided in MediaPlayerService.cpp and was
258635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong * shamelessly copied over to support memory leak tracking from
268635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong * multiple places.
278635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong */
288635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dongnamespace android {
298635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong
308635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong#if defined(__arm__)
318635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong
328635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dongextern "C" void get_malloc_leak_info(uint8_t** info, size_t* overallSize,
338635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong        size_t* infoSize, size_t* totalMemory, size_t* backtraceSize);
348635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong
358635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dongextern "C" void free_malloc_leak_info(uint8_t* info);
368635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong
378635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong// Use the String-class below instead of String8 to allocate all memory
388635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong// beforehand and not reenter the heap while we are examining it...
398635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dongstruct MyString8 {
408635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong    static const size_t MAX_SIZE = 256 * 1024;
418635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong
428635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong    MyString8()
438635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong        : mPtr((char *)malloc(MAX_SIZE)) {
448635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong        *mPtr = '\0';
458635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong    }
468635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong
478635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong    ~MyString8() {
488635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong        free(mPtr);
498635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong    }
508635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong
518635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong    void append(const char *s) {
528635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong        strcat(mPtr, s);
538635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong    }
548635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong
558635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong    const char *string() const {
568635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong        return mPtr;
578635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong    }
588635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong
598635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong    size_t size() const {
608635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong        return strlen(mPtr);
618635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong    }
628635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong
638635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dongprivate:
648635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong    char *mPtr;
658635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong
668635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong    MyString8(const MyString8 &);
678635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong    MyString8 &operator=(const MyString8 &);
688635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong};
698635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong
708635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dongvoid dumpMemoryAddresses(int fd)
718635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong{
728635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong    const size_t SIZE = 256;
738635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong    char buffer[SIZE];
748635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong    MyString8 result;
758635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong
768635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong    typedef struct {
778635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong        size_t size;
788635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong        size_t dups;
798635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong        intptr_t * backtrace;
808635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong    } AllocEntry;
818635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong
828635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong    uint8_t *info = NULL;
838635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong    size_t overallSize = 0;
848635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong    size_t infoSize = 0;
858635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong    size_t totalMemory = 0;
868635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong    size_t backtraceSize = 0;
878635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong
888635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong    get_malloc_leak_info(&info, &overallSize, &infoSize, &totalMemory, &backtraceSize);
898635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong    if (info) {
908635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong        uint8_t *ptr = info;
918635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong        size_t count = overallSize / infoSize;
928635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong
938635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong        snprintf(buffer, SIZE, " Allocation count %i\n", count);
948635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong        result.append(buffer);
958635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong        snprintf(buffer, SIZE, " Total memory %i\n", totalMemory);
968635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong        result.append(buffer);
978635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong
988635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong        AllocEntry * entries = new AllocEntry[count];
998635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong
1008635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong        for (size_t i = 0; i < count; i++) {
1018635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong            // Each entry should be size_t, size_t, intptr_t[backtraceSize]
1028635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong            AllocEntry *e = &entries[i];
1038635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong
1048635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong            e->size = *reinterpret_cast<size_t *>(ptr);
1058635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong            ptr += sizeof(size_t);
1068635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong
1078635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong            e->dups = *reinterpret_cast<size_t *>(ptr);
1088635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong            ptr += sizeof(size_t);
1098635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong
1108635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong            e->backtrace = reinterpret_cast<intptr_t *>(ptr);
1118635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong            ptr += sizeof(intptr_t) * backtraceSize;
1128635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong        }
1138635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong
1148635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong        // Now we need to sort the entries.  They come sorted by size but
1158635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong        // not by stack trace which causes problems using diff.
1168635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong        bool moved;
1178635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong        do {
1188635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong            moved = false;
1198635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong            for (size_t i = 0; i < (count - 1); i++) {
1208635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong                AllocEntry *e1 = &entries[i];
1218635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong                AllocEntry *e2 = &entries[i+1];
1228635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong
1238635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong                bool swap = e1->size < e2->size;
1248635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong                if (e1->size == e2->size) {
1258635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong                    for(size_t j = 0; j < backtraceSize; j++) {
1268635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong                        if (e1->backtrace[j] == e2->backtrace[j]) {
1278635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong                            continue;
1288635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong                        }
1298635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong                        swap = e1->backtrace[j] < e2->backtrace[j];
1308635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong                        break;
1318635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong                    }
1328635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong                }
1338635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong                if (swap) {
1348635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong                    AllocEntry t = entries[i];
1358635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong                    entries[i] = entries[i+1];
1368635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong                    entries[i+1] = t;
1378635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong                    moved = true;
1388635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong                }
1398635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong            }
1408635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong        } while (moved);
1418635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong
1428635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong        for (size_t i = 0; i < count; i++) {
1438635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong            AllocEntry *e = &entries[i];
1448635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong
1458635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong            snprintf(buffer, SIZE, "size %8i, dup %4i, ", e->size, e->dups);
1468635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong            result.append(buffer);
1478635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong            for (size_t ct = 0; (ct < backtraceSize) && e->backtrace[ct]; ct++) {
1488635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong                if (ct) {
1498635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong                    result.append(", ");
1508635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong                }
1518635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong                snprintf(buffer, SIZE, "0x%08x", e->backtrace[ct]);
1528635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong                result.append(buffer);
1538635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong            }
1548635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong            result.append("\n");
1558635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong        }
1568635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong
1578635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong        delete[] entries;
1588635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong        free_malloc_leak_info(info);
1598635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong    }
1608635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong
1618635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong    write(fd, result.string(), result.size());
1628635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong}
1638635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong
1648635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong#else
1658635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong// Does nothing
1668635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dongvoid dumpMemoryAddresses(int fd) {}
1678635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong
1688635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong#endif
1698635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong}  // namespace android
170