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 <sys/types.h>
     22 #include <unistd.h>
     23 
     24 /*
     25  * The code here originally resided in MediaPlayerService.cpp and was
     26  * shamelessly copied over to support memory leak tracking from
     27  * multiple places.
     28  */
     29 namespace android {
     30 
     31 #if defined(__arm__)
     32 
     33 extern "C" void get_malloc_leak_info(uint8_t** info, size_t* overallSize,
     34         size_t* infoSize, size_t* totalMemory, size_t* backtraceSize);
     35 
     36 extern "C" void free_malloc_leak_info(uint8_t* info);
     37 
     38 // Use the String-class below instead of String8 to allocate all memory
     39 // beforehand and not reenter the heap while we are examining it...
     40 struct MyString8 {
     41     static const size_t MAX_SIZE = 256 * 1024;
     42 
     43     MyString8()
     44         : mPtr((char *)malloc(MAX_SIZE)) {
     45         *mPtr = '\0';
     46     }
     47 
     48     ~MyString8() {
     49         free(mPtr);
     50     }
     51 
     52     void append(const char *s) {
     53         strncat(mPtr, s, MAX_SIZE - size() - 1);
     54     }
     55 
     56     const char *string() const {
     57         return mPtr;
     58     }
     59 
     60     size_t size() const {
     61         return strlen(mPtr);
     62     }
     63 
     64     void clear() {
     65         *mPtr = '\0';
     66     }
     67 
     68 private:
     69     char *mPtr;
     70 
     71     MyString8(const MyString8 &);
     72     MyString8 &operator=(const MyString8 &);
     73 };
     74 
     75 void dumpMemoryAddresses(int fd)
     76 {
     77     const size_t SIZE = 256;
     78     char buffer[SIZE];
     79     MyString8 result;
     80 
     81     typedef struct {
     82         size_t size;
     83         size_t dups;
     84         intptr_t * backtrace;
     85     } AllocEntry;
     86 
     87     uint8_t *info = NULL;
     88     size_t overallSize = 0;
     89     size_t infoSize = 0;
     90     size_t totalMemory = 0;
     91     size_t backtraceSize = 0;
     92 
     93     get_malloc_leak_info(&info, &overallSize, &infoSize, &totalMemory, &backtraceSize);
     94     if (info) {
     95         uint8_t *ptr = info;
     96         size_t count = overallSize / infoSize;
     97 
     98         snprintf(buffer, SIZE, " Allocation count %i\n", count);
     99         result.append(buffer);
    100         snprintf(buffer, SIZE, " Total memory %i\n", totalMemory);
    101         result.append(buffer);
    102 
    103         AllocEntry * entries = new AllocEntry[count];
    104 
    105         for (size_t i = 0; i < count; i++) {
    106             // Each entry should be size_t, size_t, intptr_t[backtraceSize]
    107             AllocEntry *e = &entries[i];
    108 
    109             e->size = *reinterpret_cast<size_t *>(ptr);
    110             ptr += sizeof(size_t);
    111 
    112             e->dups = *reinterpret_cast<size_t *>(ptr);
    113             ptr += sizeof(size_t);
    114 
    115             e->backtrace = reinterpret_cast<intptr_t *>(ptr);
    116             ptr += sizeof(intptr_t) * backtraceSize;
    117         }
    118 
    119         // Now we need to sort the entries.  They come sorted by size but
    120         // not by stack trace which causes problems using diff.
    121         bool moved;
    122         do {
    123             moved = false;
    124             for (size_t i = 0; i < (count - 1); i++) {
    125                 AllocEntry *e1 = &entries[i];
    126                 AllocEntry *e2 = &entries[i+1];
    127 
    128                 bool swap = e1->size < e2->size;
    129                 if (e1->size == e2->size) {
    130                     for(size_t j = 0; j < backtraceSize; j++) {
    131                         if (e1->backtrace[j] == e2->backtrace[j]) {
    132                             continue;
    133                         }
    134                         swap = e1->backtrace[j] < e2->backtrace[j];
    135                         break;
    136                     }
    137                 }
    138                 if (swap) {
    139                     AllocEntry t = entries[i];
    140                     entries[i] = entries[i+1];
    141                     entries[i+1] = t;
    142                     moved = true;
    143                 }
    144             }
    145         } while (moved);
    146 
    147         write(fd, result.string(), result.size());
    148         result.clear();
    149 
    150         for (size_t i = 0; i < count; i++) {
    151             AllocEntry *e = &entries[i];
    152 
    153             snprintf(buffer, SIZE, "size %8i, dup %4i, ", e->size, e->dups);
    154             result.append(buffer);
    155             for (size_t ct = 0; (ct < backtraceSize) && e->backtrace[ct]; ct++) {
    156                 if (ct) {
    157                     result.append(", ");
    158                 }
    159                 snprintf(buffer, SIZE, "0x%08x", e->backtrace[ct]);
    160                 result.append(buffer);
    161             }
    162             result.append("\n");
    163 
    164             write(fd, result.string(), result.size());
    165             result.clear();
    166         }
    167 
    168         delete[] entries;
    169         free_malloc_leak_info(info);
    170     }
    171 }
    172 
    173 #else
    174 // Does nothing
    175 void dumpMemoryAddresses(int fd) {}
    176 
    177 #endif
    178 }  // namespace android
    179