Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5cb96b83 authored by Andy Hung's avatar Andy Hung Committed by android-build-merger
Browse files

Merge "Add memory heap checks for mediaserver and audioserver" into nyc-dev

am: f3d9908a

* commit 'f3d9908a':
  Add memory heap checks for mediaserver and audioserver

Change-Id: I8b5dda2e29da8651cbd9dbc77fa9ca6211b1a47d
parents 4d1522bd f3d9908a
Loading
Loading
Loading
Loading
+6 −2
Original line number Diff line number Diff line
@@ -337,7 +337,7 @@ ssize_t DrmManagerService::pread(int uniqueId, DecryptHandle* decryptHandle,
    return mDrmManager->pread(uniqueId, decryptHandle, buffer, numBytes, offset);
}

status_t DrmManagerService::dump(int fd, const Vector<String16>& /* args */)
status_t DrmManagerService::dump(int fd, const Vector<String16>& args)
{
    const size_t SIZE = 256;
    char buffer[SIZE];
@@ -357,8 +357,12 @@ status_t DrmManagerService::dump(int fd, const Vector<String16>& /* args */)
            }
        }
        if (dumpMem) {
            dumpMemoryAddresses(fd);
            result.append("\nDumping memory:\n");
            std::string s = dumpMemoryAddresses(100 /* limit */);
            result.append(s.c_str(), s.size());
        }
#else
        (void)args;
#endif
    }
    write(fd, result.string(), result.size());
+7 −2
Original line number Diff line number Diff line
@@ -16,11 +16,16 @@
#ifndef MEMORY_LEAK_TRACK_UTIL_H
#define MEMORY_LEAK_TRACK_UTIL_H

#include <iostream>

namespace android {
/*
 * Dump the memory address of the calling process to the given fd.
 * Dump the heap memory of the calling process, sorted by total size
 * (allocation size * number of allocations).
 *
 *    limit is the number of unique allocations to return.
 */
extern void dumpMemoryAddresses(int fd);
extern std::string dumpMemoryAddresses(size_t limit);

};

+3 −0
Original line number Diff line number Diff line
@@ -83,6 +83,9 @@ LOCAL_EXPORT_SHARED_LIBRARY_HEADERS := libbinder

LOCAL_WHOLE_STATIC_LIBRARIES := libmedia_helper

# for memory heap analysis
LOCAL_STATIC_LIBRARIES := libc_malloc_debug_backtrace libc_logging

LOCAL_MODULE:= libmedia

LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+62 −144
Original line number Diff line number Diff line
@@ -14,166 +14,84 @@
 * limitations under the License.
 */

#include <media/MemoryLeakTrackUtil.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
//#define LOG_NDEBUG 0
#define LOG_TAG "MemoryLeackTrackUtil"
#include <utils/Log.h>

#include "media/MemoryLeakTrackUtil.h"
#include <sstream>

/*
 * The code here originally resided in MediaPlayerService.cpp and was
 * shamelessly copied over to support memory leak tracking from
 * multiple places.
 * The code here originally resided in MediaPlayerService.cpp
 */
namespace android {

// Figure out the abi based on defined macros.
#if defined(__arm__)
#define ABI_STRING "arm"
#elif defined(__aarch64__)
#define ABI_STRING "arm64"
#elif defined(__mips__) && !defined(__LP64__)
#define ABI_STRING "mips"
#elif defined(__mips__) && defined(__LP64__)
#define ABI_STRING "mips64"
#elif defined(__i386__)
#define ABI_STRING "x86"
#elif defined(__x86_64__)
#define ABI_STRING "x86_64"
#else
#error "Unsupported ABI"
#endif

extern std::string backtrace_string(const uintptr_t* frames, size_t frame_count);

namespace android {

extern "C" void get_malloc_leak_info(uint8_t** info, size_t* overallSize,
        size_t* infoSize, size_t* totalMemory, size_t* backtraceSize);

extern "C" void free_malloc_leak_info(uint8_t* info);

// Use the String-class below instead of String8 to allocate all memory
// beforehand and not reenter the heap while we are examining it...
struct MyString8 {
    static const size_t MAX_SIZE = 256 * 1024;

    MyString8()
        : mPtr((char *)malloc(MAX_SIZE)) {
        *mPtr = '\0';
    }

    ~MyString8() {
        free(mPtr);
    }

    void append(const char *s) {
        strncat(mPtr, s, MAX_SIZE - size() - 1);
    }

    const char *string() const {
        return mPtr;
    }

    size_t size() const {
        return strlen(mPtr);
    }

    void clear() {
        *mPtr = '\0';
    }

private:
    char *mPtr;

    MyString8(const MyString8 &);
    MyString8 &operator=(const MyString8 &);
};

void dumpMemoryAddresses(int fd)
std::string dumpMemoryAddresses(size_t limit)
{
    const size_t SIZE = 256;
    char buffer[SIZE];
    MyString8 result;

    typedef struct {
        size_t size;
        size_t dups;
        intptr_t * backtrace;
    } AllocEntry;

    uint8_t *info = NULL;
    size_t overallSize = 0;
    size_t infoSize = 0;
    size_t totalMemory = 0;
    size_t backtraceSize = 0;

    uint8_t *info;
    size_t overallSize;
    size_t infoSize;
    size_t totalMemory;
    size_t backtraceSize;
    get_malloc_leak_info(&info, &overallSize, &infoSize, &totalMemory, &backtraceSize);
    if (info) {
        uint8_t *ptr = info;
        size_t count = overallSize / infoSize;

        snprintf(buffer, SIZE, " Allocation count %i\n", count);
        result.append(buffer);
        snprintf(buffer, SIZE, " Total memory %i\n", totalMemory);
        result.append(buffer);

        AllocEntry * entries = new AllocEntry[count];

        for (size_t i = 0; i < count; i++) {
            // Each entry should be size_t, size_t, intptr_t[backtraceSize]
            AllocEntry *e = &entries[i];

            e->size = *reinterpret_cast<size_t *>(ptr);
            ptr += sizeof(size_t);

            e->dups = *reinterpret_cast<size_t *>(ptr);
            ptr += sizeof(size_t);

            e->backtrace = reinterpret_cast<intptr_t *>(ptr);
            ptr += sizeof(intptr_t) * backtraceSize;
        }

        // Now we need to sort the entries.  They come sorted by size but
        // not by stack trace which causes problems using diff.
        bool moved;
        do {
            moved = false;
            for (size_t i = 0; i < (count - 1); i++) {
                AllocEntry *e1 = &entries[i];
                AllocEntry *e2 = &entries[i+1];

                bool swap = e1->size < e2->size;
                if (e1->size == e2->size) {
                    for(size_t j = 0; j < backtraceSize; j++) {
                        if (e1->backtrace[j] == e2->backtrace[j]) {
                            continue;
                        }
                        swap = e1->backtrace[j] < e2->backtrace[j];
                        break;
    size_t count;
    if (info == nullptr || overallSize == 0 || infoSize == 0
            || (count = overallSize / infoSize) == 0) {
        ALOGD("no malloc info, libc.debug.malloc.program property should be set");
        return std::string();
    }
                }
                if (swap) {
                    AllocEntry t = entries[i];
                    entries[i] = entries[i+1];
                    entries[i+1] = t;
                    moved = true;
                }
            }
        } while (moved);

        write(fd, result.string(), result.size());
        result.clear();
    std::ostringstream oss;
    oss << totalMemory << " bytes in " << count << " allocations\n";
    oss << "  ABI: '" ABI_STRING "'" << "\n\n";
    if (count > limit) count = limit;

    // The memory is sorted based on total size which is useful for finding
    // worst memory offenders. For diffs, sometimes it is preferable to sort
    // based on the backtrace.
    for (size_t i = 0; i < count; i++) {
            AllocEntry *e = &entries[i];
        struct AllocEntry {
            size_t size;  // bit 31 is set if this is zygote allocated memory
            size_t allocations;
            uintptr_t backtrace[];
        };

            snprintf(buffer, SIZE, "size %8i, dup %4i, ", e->size, e->dups);
            result.append(buffer);
            for (size_t ct = 0; (ct < backtraceSize) && e->backtrace[ct]; ct++) {
                if (ct) {
                    result.append(", ");
                }
                snprintf(buffer, SIZE, "0x%08x", e->backtrace[ct]);
                result.append(buffer);
            }
            result.append("\n");
        const AllocEntry * const e = (AllocEntry *)(info + i * infoSize);

            write(fd, result.string(), result.size());
            result.clear();
        oss << (e->size * e->allocations)
                << " bytes ( " << e->size << " bytes * " << e->allocations << " allocations )\n";
        oss << backtrace_string(e->backtrace, backtraceSize) << "\n";
    }

        delete[] entries;
    oss << "\n";
    free_malloc_leak_info(info);
    }
    return oss.str();
}

#else
// Does nothing
void dumpMemoryAddresses(int fd __unused) {}

#endif
}  // namespace android
+3 −1
Original line number Diff line number Diff line
@@ -536,7 +536,9 @@ status_t MediaPlayerService::dump(int fd, const Vector<String16>& args)
            }
        }
        if (dumpMem) {
            dumpMemoryAddresses(fd);
            result.append("\nDumping memory:\n");
            std::string s = dumpMemoryAddresses(100 /* limit */);
            result.append(s.c_str(), s.size());
        }
        if (unreachableMemory) {
            result.append("\nDumping unreachable memory:\n");
Loading