Add memory leak tracking/debugging code to drm server

bug - 4099038

Change-Id: I6c048eaf3d7f34bc144b8daaa5fdef1ed474af66
diff --git a/drm/drmserver/Android.mk b/drm/drmserver/Android.mk
index 5df2ff8..b5ad147 100644
--- a/drm/drmserver/Android.mk
+++ b/drm/drmserver/Android.mk
@@ -23,6 +23,7 @@
     StringTokenizer.cpp
 
 LOCAL_SHARED_LIBRARIES := \
+    libmedia \
     libutils \
     libbinder
 
diff --git a/drm/drmserver/DrmManagerService.cpp b/drm/drmserver/DrmManagerService.cpp
index 0901a44..583669e 100644
--- a/drm/drmserver/DrmManagerService.cpp
+++ b/drm/drmserver/DrmManagerService.cpp
@@ -19,6 +19,7 @@
 #include <utils/Log.h>
 
 #include <private/android_filesystem_config.h>
+#include <media/MemoryLeakTrackUtil.h>
 
 #include <errno.h>
 #include <utils/threads.h>
@@ -256,3 +257,31 @@
     return mDrmManager->pread(uniqueId, decryptHandle, buffer, numBytes, offset);
 }
 
+status_t DrmManagerService::dump(int fd, const Vector<String16>& args)
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+    if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
+        snprintf(buffer, SIZE, "Permission Denial: "
+                "can't dump DrmManagerService from pid=%d, uid=%d\n",
+                IPCThreadState::self()->getCallingPid(),
+                IPCThreadState::self()->getCallingUid());
+        result.append(buffer);
+    } else {
+#if DRM_MEMORY_LEAK_TRACK
+        bool dumpMem = false;
+        for (size_t i = 0; i < args.size(); i++) {
+            if (args[i] == String16("-m")) {
+                dumpMem = true;
+            }
+        }
+        if (dumpMem) {
+            dumpMemoryAddresses(fd);
+        }
+#endif
+    }
+    write(fd, result.string(), result.size());
+    return NO_ERROR;
+}
+
diff --git a/drm/libdrmframework/include/DrmManagerService.h b/drm/libdrmframework/include/DrmManagerService.h
index d0a0db7..227496a 100644
--- a/drm/libdrmframework/include/DrmManagerService.h
+++ b/drm/libdrmframework/include/DrmManagerService.h
@@ -115,6 +115,8 @@
     ssize_t pread(int uniqueId, DecryptHandle* decryptHandle,
             void* buffer, ssize_t numBytes, off64_t offset);
 
+    virtual status_t dump(int fd, const Vector<String16>& args);
+
 private:
     DrmManager* mDrmManager;
 };
diff --git a/include/media/MemoryLeakTrackUtil.h b/include/media/MemoryLeakTrackUtil.h
new file mode 100644
index 0000000..290b748
--- /dev/null
+++ b/include/media/MemoryLeakTrackUtil.h
@@ -0,0 +1,28 @@
+
+/*
+ * Copyright 2011, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef MEMORY_LEAK_TRACK_UTIL_H
+#define MEMORY_LEAK_TRACK_UTIL_H
+
+namespace android {
+/*
+ * Dump the memory adddress of the calling process to the given fd.
+ */
+extern void dumpMemoryAddresses(int fd);
+
+};
+
+#endif  // MEMORY_LEAK_TRACK_UTIL_H
diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk
index fd4c6c6..a04fbd2 100644
--- a/media/libmedia/Android.mk
+++ b/media/libmedia/Android.mk
@@ -33,6 +33,7 @@
     IEffectClient.cpp \
     AudioEffect.cpp \
     Visualizer.cpp \
+    MemoryLeakTrackUtil.cpp \
     fixedfft.cpp.arm
 
 LOCAL_SHARED_LIBRARIES := \
diff --git a/media/libmedia/MemoryLeakTrackUtil.cpp b/media/libmedia/MemoryLeakTrackUtil.cpp
new file mode 100644
index 0000000..6a108ae
--- /dev/null
+++ b/media/libmedia/MemoryLeakTrackUtil.cpp
@@ -0,0 +1,169 @@
+/*
+ * Copyright 2011, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <media/MemoryLeakTrackUtil.h>
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+/*
+ * The code here originally resided in MediaPlayerService.cpp and was
+ * shamelessly copied over to support memory leak tracking from
+ * multiple places.
+ */
+namespace android {
+
+#if defined(__arm__)
+
+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) {
+        strcat(mPtr, s);
+    }
+
+    const char *string() const {
+        return mPtr;
+    }
+
+    size_t size() const {
+        return strlen(mPtr);
+    }
+
+private:
+    char *mPtr;
+
+    MyString8(const MyString8 &);
+    MyString8 &operator=(const MyString8 &);
+};
+
+void dumpMemoryAddresses(int fd)
+{
+    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;
+
+    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;
+                    }
+                }
+                if (swap) {
+                    AllocEntry t = entries[i];
+                    entries[i] = entries[i+1];
+                    entries[i+1] = t;
+                    moved = true;
+                }
+            }
+        } while (moved);
+
+        for (size_t i = 0; i < count; i++) {
+            AllocEntry *e = &entries[i];
+
+            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");
+        }
+
+        delete[] entries;
+        free_malloc_leak_info(info);
+    }
+
+    write(fd, result.string(), result.size());
+}
+
+#else
+// Does nothing
+void dumpMemoryAddresses(int fd) {}
+
+#endif
+}  // namespace android
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index a42cca5..f075706 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -51,6 +51,7 @@
 #include <media/MediaMetadataRetrieverInterface.h>
 #include <media/Metadata.h>
 #include <media/AudioTrack.h>
+#include <media/MemoryLeakTrackUtil.h>
 
 #include <private/android_filesystem_config.h>
 
@@ -392,139 +393,6 @@
 #endif
 }
 
-#if defined(__arm__)
-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) {
-        strcat(mPtr, s);
-    }
-
-    const char *string() const {
-        return mPtr;
-    }
-
-    size_t size() const {
-        return strlen(mPtr);
-    }
-
-private:
-    char *mPtr;
-
-    MyString8(const MyString8 &);
-    MyString8 &operator=(const MyString8 &);
-};
-
-void memStatus(int fd, const Vector<String16>& args)
-{
-    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;
-
-    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;
-                    }
-                }
-                if (swap) {
-                    AllocEntry t = entries[i];
-                    entries[i] = entries[i+1];
-                    entries[i+1] = t;
-                    moved = true;
-                }
-            }
-        } while (moved);
-
-        for (size_t i = 0; i < count; i++) {
-            AllocEntry *e = &entries[i];
-
-            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");
-        }
-
-        delete[] entries;
-        free_malloc_leak_info(info);
-    }
-
-    write(fd, result.string(), result.size());
-}
-#endif
-
 status_t MediaPlayerService::dump(int fd, const Vector<String16>& args)
 {
     const size_t SIZE = 256;
@@ -623,7 +491,6 @@
             result.append("\n");
         }
 
-#if defined(__arm__)
         bool dumpMem = false;
         for (size_t i = 0; i < args.size(); i++) {
             if (args[i] == String16("-m")) {
@@ -631,9 +498,8 @@
             }
         }
         if (dumpMem) {
-            memStatus(fd, args);
+            dumpMemoryAddresses(fd);
         }
-#endif
     }
     write(fd, result.string(), result.size());
     return NO_ERROR;