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>
2080a5d305a8408651fbc9b11e9d21125887da8c40Igor Chernyshev#include <stdlib.h>
218635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong#include <sys/types.h>
228635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong#include <unistd.h>
238635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong
248635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong/*
258635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong * The code here originally resided in MediaPlayerService.cpp and was
268635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong * shamelessly copied over to support memory leak tracking from
278635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong * multiple places.
288635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong */
298635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dongnamespace android {
308635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong
318635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong#if defined(__arm__)
328635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong
338635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dongextern "C" void get_malloc_leak_info(uint8_t** info, size_t* overallSize,
348635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong        size_t* infoSize, size_t* totalMemory, size_t* backtraceSize);
358635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong
368635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dongextern "C" void free_malloc_leak_info(uint8_t* info);
378635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong
388635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong// Use the String-class below instead of String8 to allocate all memory
398635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong// beforehand and not reenter the heap while we are examining it...
408635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dongstruct MyString8 {
418635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong    static const size_t MAX_SIZE = 256 * 1024;
428635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong
438635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong    MyString8()
448635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong        : mPtr((char *)malloc(MAX_SIZE)) {
458635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong        *mPtr = '\0';
468635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong    }
478635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong
488635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong    ~MyString8() {
498635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong        free(mPtr);
508635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong    }
518635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong
528635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong    void append(const char *s) {
536d39eb9d7da2ca8eb733f2d2eba686c56b24885bOscar Rydhé        strncat(mPtr, s, MAX_SIZE - size() - 1);
548635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong    }
558635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong
568635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong    const char *string() const {
578635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong        return mPtr;
588635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong    }
598635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong
608635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong    size_t size() const {
618635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong        return strlen(mPtr);
628635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong    }
638635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong
646d39eb9d7da2ca8eb733f2d2eba686c56b24885bOscar Rydhé    void clear() {
656d39eb9d7da2ca8eb733f2d2eba686c56b24885bOscar Rydhé        *mPtr = '\0';
666d39eb9d7da2ca8eb733f2d2eba686c56b24885bOscar Rydhé    }
676d39eb9d7da2ca8eb733f2d2eba686c56b24885bOscar Rydhé
688635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dongprivate:
698635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong    char *mPtr;
708635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong
718635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong    MyString8(const MyString8 &);
728635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong    MyString8 &operator=(const MyString8 &);
738635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong};
748635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong
758635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dongvoid dumpMemoryAddresses(int fd)
768635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong{
778635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong    const size_t SIZE = 256;
788635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong    char buffer[SIZE];
798635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong    MyString8 result;
808635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong
818635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong    typedef struct {
828635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong        size_t size;
838635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong        size_t dups;
848635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong        intptr_t * backtrace;
858635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong    } AllocEntry;
868635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong
878635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong    uint8_t *info = NULL;
888635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong    size_t overallSize = 0;
898635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong    size_t infoSize = 0;
908635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong    size_t totalMemory = 0;
918635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong    size_t backtraceSize = 0;
928635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong
938635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong    get_malloc_leak_info(&info, &overallSize, &infoSize, &totalMemory, &backtraceSize);
948635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong    if (info) {
958635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong        uint8_t *ptr = info;
968635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong        size_t count = overallSize / infoSize;
978635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong
988635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong        snprintf(buffer, SIZE, " Allocation count %i\n", count);
998635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong        result.append(buffer);
1008635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong        snprintf(buffer, SIZE, " Total memory %i\n", totalMemory);
1018635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong        result.append(buffer);
1028635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong
1038635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong        AllocEntry * entries = new AllocEntry[count];
1048635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong
1058635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong        for (size_t i = 0; i < count; i++) {
1068635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong            // Each entry should be size_t, size_t, intptr_t[backtraceSize]
1078635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong            AllocEntry *e = &entries[i];
1088635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong
1098635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong            e->size = *reinterpret_cast<size_t *>(ptr);
1108635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong            ptr += sizeof(size_t);
1118635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong
1128635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong            e->dups = *reinterpret_cast<size_t *>(ptr);
1138635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong            ptr += sizeof(size_t);
1148635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong
1158635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong            e->backtrace = reinterpret_cast<intptr_t *>(ptr);
1168635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong            ptr += sizeof(intptr_t) * backtraceSize;
1178635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong        }
1188635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong
1198635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong        // Now we need to sort the entries.  They come sorted by size but
1208635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong        // not by stack trace which causes problems using diff.
1218635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong        bool moved;
1228635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong        do {
1238635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong            moved = false;
1248635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong            for (size_t i = 0; i < (count - 1); i++) {
1258635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong                AllocEntry *e1 = &entries[i];
1268635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong                AllocEntry *e2 = &entries[i+1];
1278635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong
1288635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong                bool swap = e1->size < e2->size;
1298635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong                if (e1->size == e2->size) {
1308635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong                    for(size_t j = 0; j < backtraceSize; j++) {
1318635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong                        if (e1->backtrace[j] == e2->backtrace[j]) {
1328635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong                            continue;
1338635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong                        }
1348635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong                        swap = e1->backtrace[j] < e2->backtrace[j];
1358635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong                        break;
1368635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong                    }
1378635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong                }
1388635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong                if (swap) {
1398635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong                    AllocEntry t = entries[i];
1408635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong                    entries[i] = entries[i+1];
1418635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong                    entries[i+1] = t;
1428635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong                    moved = true;
1438635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong                }
1448635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong            }
1458635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong        } while (moved);
1468635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong
1476d39eb9d7da2ca8eb733f2d2eba686c56b24885bOscar Rydhé        write(fd, result.string(), result.size());
1486d39eb9d7da2ca8eb733f2d2eba686c56b24885bOscar Rydhé        result.clear();
1496d39eb9d7da2ca8eb733f2d2eba686c56b24885bOscar Rydhé
1508635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong        for (size_t i = 0; i < count; i++) {
1518635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong            AllocEntry *e = &entries[i];
1528635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong
1538635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong            snprintf(buffer, SIZE, "size %8i, dup %4i, ", e->size, e->dups);
1548635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong            result.append(buffer);
1558635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong            for (size_t ct = 0; (ct < backtraceSize) && e->backtrace[ct]; ct++) {
1568635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong                if (ct) {
1578635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong                    result.append(", ");
1588635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong                }
1598635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong                snprintf(buffer, SIZE, "0x%08x", e->backtrace[ct]);
1608635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong                result.append(buffer);
1618635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong            }
1628635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong            result.append("\n");
1636d39eb9d7da2ca8eb733f2d2eba686c56b24885bOscar Rydhé
1646d39eb9d7da2ca8eb733f2d2eba686c56b24885bOscar Rydhé            write(fd, result.string(), result.size());
1656d39eb9d7da2ca8eb733f2d2eba686c56b24885bOscar Rydhé            result.clear();
1668635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong        }
1678635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong
1688635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong        delete[] entries;
1698635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong        free_malloc_leak_info(info);
1708635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong    }
1718635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong}
1728635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong
1738635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong#else
1748635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong// Does nothing
1758635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dongvoid dumpMemoryAddresses(int fd) {}
1768635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong
1778635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong#endif
1788635b7b095fbf7ffc63d3ce791891a9116ace1f6James Dong}  // namespace android
179