dumpsys: add --json option to media.audio_flinger.

Currently only extracting audio performance data.

Test: dumpsys media.audio_flinger --json
Bug: 68148948
Change-Id: If207e7e20683dcf8d8d5874417cd7466c78a5df0
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 53a4ce9..0237aee 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -20,9 +20,11 @@
 //#define LOG_NDEBUG 0
 
 #include "Configuration.h"
+#include <algorithm>    // std::any_of
 #include <dirent.h>
 #include <math.h>
 #include <signal.h>
+#include <string>
 #include <sys/time.h>
 #include <sys/resource.h>
 
@@ -434,6 +436,15 @@
     if (!dumpAllowed()) {
         dumpPermissionDenial(fd, args);
     } else {
+        // XXX This is sort of hacky for now.
+        const bool formatJson = std::any_of(args.begin(), args.end(),
+                [](const String16 &arg) { return arg == String16("--json"); });
+        if (formatJson) {
+            // XXX consider buffering if the string happens to be too long.
+            dprintf(fd, "%s", getJsonString().c_str());
+            return NO_ERROR;
+        }
+
         // get state of hardware lock
         bool hardwareLocked = dumpTryLock(mHardwareLock);
         if (!hardwareLocked) {
@@ -443,7 +454,7 @@
             mHardwareLock.unlock();
         }
 
-        bool locked = dumpTryLock(mLock);
+        const bool locked = dumpTryLock(mLock);
 
         // failed to lock - AudioFlinger is probably deadlocked
         if (!locked) {
@@ -545,6 +556,36 @@
     return NO_ERROR;
 }
 
+std::string AudioFlinger::getJsonString()
+{
+    std::string jsonStr = "{\n";
+    const bool locked = dumpTryLock(mLock);
+
+    // failed to lock - AudioFlinger is probably deadlocked
+    if (!locked) {
+        jsonStr += "    \"deadlock_message\": ";
+        jsonStr += kDeadlockedString;
+        jsonStr += ",\n";
+    }
+    // FIXME risky to access data structures without a lock held?
+
+    jsonStr += "  \"Playback_Threads\": [\n";
+    // dump playback threads
+    for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
+        if (i != 0) {
+            jsonStr += ",\n";
+        }
+        jsonStr += mPlaybackThreads.valueAt(i)->getJsonString();
+    }
+    jsonStr += "\n  ]\n}\n";
+
+    if (locked) {
+        mLock.unlock();
+    }
+
+    return jsonStr;
+}
+
 sp<AudioFlinger::Client> AudioFlinger::registerPid(pid_t pid)
 {
     Mutex::Autolock _cl(mClientLock);