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