Add dumpsys info

Print a list of looper-handler pairs and the number of messages
they've processed, and optionally break those stats out by
message type.

Change-Id: I68ce4a7003152d5c9b5cb3f42e6f3949b471aa6e
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 1936218..694f1a4 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -59,6 +59,7 @@
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/AudioPlayer.h>
 #include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/ALooperRoster.h>
 
 #include <system/audio.h>
 
@@ -247,6 +248,9 @@
 
 namespace android {
 
+extern ALooperRoster gLooperRoster;
+
+
 static bool checkPermission(const char* permissionString) {
 #ifndef HAVE_ANDROID_OS
     return true;
@@ -428,6 +432,10 @@
     return NO_ERROR;
 }
 
+/**
+ * The only arguments this understands right now are -c, -von and -voff,
+ * which are parsed by ALooperRoster::dump()
+ */
 status_t MediaPlayerService::dump(int fd, const Vector<String16>& args)
 {
     const size_t SIZE = 256;
@@ -461,7 +469,7 @@
         }
 
         result.append(" Files opened and/or mapped:\n");
-        snprintf(buffer, SIZE, "/proc/%d/maps", gettid());
+        snprintf(buffer, SIZE, "/proc/%d/maps", getpid());
         FILE *f = fopen(buffer, "r");
         if (f) {
             while (!feof(f)) {
@@ -481,13 +489,13 @@
             result.append("\n");
         }
 
-        snprintf(buffer, SIZE, "/proc/%d/fd", gettid());
+        snprintf(buffer, SIZE, "/proc/%d/fd", getpid());
         DIR *d = opendir(buffer);
         if (d) {
             struct dirent *ent;
             while((ent = readdir(d)) != NULL) {
                 if (strcmp(ent->d_name,".") && strcmp(ent->d_name,"..")) {
-                    snprintf(buffer, SIZE, "/proc/%d/fd/%s", gettid(), ent->d_name);
+                    snprintf(buffer, SIZE, "/proc/%d/fd/%s", getpid(), ent->d_name);
                     struct stat s;
                     if (lstat(buffer, &s) == 0) {
                         if ((s.st_mode & S_IFMT) == S_IFLNK) {
@@ -528,6 +536,8 @@
             result.append("\n");
         }
 
+        gLooperRoster.dump(fd, args);
+
         bool dumpMem = false;
         for (size_t i = 0; i < args.size(); i++) {
             if (args[i] == String16("-m")) {
diff --git a/media/libstagefright/foundation/ALooperRoster.cpp b/media/libstagefright/foundation/ALooperRoster.cpp
index e0dc768..2d57aee 100644
--- a/media/libstagefright/foundation/ALooperRoster.cpp
+++ b/media/libstagefright/foundation/ALooperRoster.cpp
@@ -17,6 +17,7 @@
 //#define LOG_NDEBUG 0
 #define LOG_TAG "ALooperRoster"
 #include <utils/Log.h>
+#include <utils/String8.h>
 
 #include "ALooperRoster.h"
 
@@ -26,6 +27,8 @@
 
 namespace android {
 
+static bool verboseStats = false;
+
 ALooperRoster::ALooperRoster()
     : mNextHandlerID(1),
       mNextReplyID(1) {
@@ -136,6 +139,17 @@
     }
 
     handler->onMessageReceived(msg);
+    handler->mMessageCounter++;
+
+    if (verboseStats) {
+        uint32_t what = msg->what();
+        ssize_t idx = handler->mMessages.indexOfKey(what);
+        if (idx < 0) {
+            handler->mMessages.add(what, 1);
+        } else {
+            handler->mMessages.editValueAt(idx)++;
+        }
+    }
 }
 
 sp<ALooper> ALooperRoster::findLooper(ALooper::handler_id handlerID) {
@@ -196,4 +210,72 @@
     mRepliesCondition.broadcast();
 }
 
+static void makeFourCC(uint32_t fourcc, char *s) {
+    s[0] = (fourcc >> 24) & 0xff;
+    if (s[0]) {
+        s[1] = (fourcc >> 16) & 0xff;
+        s[2] = (fourcc >> 8) & 0xff;
+        s[3] = fourcc & 0xff;
+        s[4] = 0;
+    } else {
+        sprintf(s, "%u", fourcc);
+    }
+}
+
+void ALooperRoster::dump(int fd, const Vector<String16>& args) {
+    bool clear = false;
+    bool oldVerbose = verboseStats;
+    for (size_t i = 0;i < args.size(); i++) {
+        if (args[i] == String16("-c")) {
+            clear = true;
+        } else if (args[i] == String16("-von")) {
+            verboseStats = true;
+        } else if (args[i] == String16("-voff")) {
+            verboseStats = false;
+        }
+    }
+    String8 s;
+    if (verboseStats && !oldVerbose) {
+        s.append("(verbose stats collection enabled, stats will be cleared)\n");
+    }
+
+    Mutex::Autolock autoLock(mLock);
+    size_t n = mHandlers.size();
+    s.appendFormat(" %zd registered handlers:\n", n);
+
+    for (size_t i = 0; i < n; i++) {
+        s.appendFormat("  %zd: ", i);
+        HandlerInfo &info = mHandlers.editValueAt(i);
+        sp<ALooper> looper = info.mLooper.promote();
+        if (looper != NULL) {
+            s.append(looper->mName.c_str());
+            sp<AHandler> handler = info.mHandler.promote();
+            if (handler != NULL) {
+                s.appendFormat(": %u messages processed", handler->mMessageCounter);
+                if (verboseStats) {
+                    for (size_t j = 0; j < handler->mMessages.size(); j++) {
+                        char fourcc[15];
+                        makeFourCC(handler->mMessages.keyAt(j), fourcc);
+                        s.appendFormat("\n    %s: %d",
+                                fourcc,
+                                handler->mMessages.valueAt(j));
+                    }
+                } else {
+                    handler->mMessages.clear();
+                }
+                if (clear || (verboseStats && !oldVerbose)) {
+                    handler->mMessageCounter = 0;
+                    handler->mMessages.clear();
+                }
+            } else {
+                s.append(": <stale handler>");
+            }
+        } else {
+            s.append("<stale>");
+        }
+        s.append("\n");
+    }
+    write(fd, s.string(), s.size());
+}
+
 }  // namespace android