Add "adb shell cmd stats" support to statsd.

Test: adb shell cmd stats
Change-Id: Idcca995af208153019be5faa1acd573037f931cb
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index 13c6f67..5ee07b4 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -23,6 +23,7 @@
 #include <cutils/log.h>
 #include <private/android_filesystem_config.h>
 #include <utils/Looper.h>
+#include <utils/String16.h>
 
 #include <unistd.h>
 #include <stdio.h>
@@ -39,6 +40,60 @@
 {
 }
 
+// Implement our own because the default binder implementation isn't
+// properly handling SHELL_COMMAND_TRANSACTION
+status_t
+StatsService::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+    status_t err;
+
+    switch (code) {
+        case SHELL_COMMAND_TRANSACTION: {
+            int in = data.readFileDescriptor();
+            int out = data.readFileDescriptor();
+            int err = data.readFileDescriptor();
+            int argc = data.readInt32();
+            Vector<String8> args;
+            for (int i = 0; i < argc && data.dataAvail() > 0; i++) {
+                args.add(String8(data.readString16()));
+            }
+            sp<IShellCallback> shellCallback = IShellCallback::asInterface(
+                    data.readStrongBinder());
+            sp<IResultReceiver> resultReceiver = IResultReceiver::asInterface(
+                    data.readStrongBinder());
+
+            FILE* fin = fdopen(in, "r");
+            FILE* fout = fdopen(out, "w");
+            FILE* ferr = fdopen(err, "w");
+
+            if (fin == NULL || fout == NULL || ferr == NULL) {
+                resultReceiver->send(NO_MEMORY);
+            } else {
+                err = command(fin, fout, ferr, args);
+                resultReceiver->send(err);
+            }
+
+            if (fin != NULL) {
+                fflush(fin);
+                fclose(fin);
+            }
+            if (fout != NULL) {
+                fflush(fout);
+                fclose(fout);
+            }
+            if (fout != NULL) {
+                fflush(ferr);
+                fclose(ferr);
+            }
+
+            return NO_ERROR;
+        }
+        default: {
+            return BnStatsManager::onTransact(code, data, reply, flags);
+        }
+    }
+}
+
 status_t
 StatsService::dump(int fd, const Vector<String16>& args)
 {
@@ -60,6 +115,21 @@
     return NO_ERROR;
 }
 
+status_t
+StatsService::command(FILE* in, FILE* out, FILE* err, Vector<String8>& args)
+{
+    fprintf(out, "StatsService::command:");
+    ALOGD("StatsService::command:");
+    const int N = args.size();
+    for (int i=0; i<N; i++) {
+        fprintf(out, " %s", String8(args[i]).string());
+        ALOGD("   %s", String8(args[i]).string());
+    }
+    fprintf(out, "\n");
+
+    return NO_ERROR;
+}
+
 Status
 StatsService::systemRunning()
 {