Audioflinger dumpsys: Use libjsoncpp for json dump

Test: dumpsys media.audio_flinger --json
Bug: 68148948
Change-Id: Ieebe2c52e3613e48a5ec5cbb2b1f167a32d5a47d
diff --git a/services/audioflinger/Android.mk b/services/audioflinger/Android.mk
index c0aa477..2c26ba4 100644
--- a/services/audioflinger/Android.mk
+++ b/services/audioflinger/Android.mk
@@ -42,6 +42,7 @@
 
 LOCAL_STATIC_LIBRARIES := \
     libcpustats \
+    libjsoncpp \
     libsndfile \
 
 LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB)
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 9234364..9dd92a3 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -58,6 +58,8 @@
 
 #include <audio_utils/primitives.h>
 
+#include <json/json.h>
+
 #include <powermanager/PowerManager.h>
 
 #include <media/IMediaLogService.h>
@@ -440,8 +442,11 @@
         const bool formatJson = std::any_of(args.begin(), args.end(),
                 [](const String16 &arg) { return arg == String16("--json"); });
         if (formatJson) {
+            Json::Value root = getJsonDump();
+            Json::FastWriter writer;
+            std::string rootStr = writer.write(root);
             // XXX consider buffering if the string happens to be too long.
-            dprintf(fd, "%s", getJsonString().c_str());
+            dprintf(fd, "%s", rootStr.c_str());
             return NO_ERROR;
         }
 
@@ -556,34 +561,30 @@
     return NO_ERROR;
 }
 
-std::string AudioFlinger::getJsonString()
+Json::Value AudioFlinger::getJsonDump()
 {
-    std::string jsonStr = "{\n";
+    Json::Value root(Json::objectValue);
     const bool locked = dumpTryLock(mLock);
 
     // failed to lock - AudioFlinger is probably deadlocked
     if (!locked) {
-        jsonStr += "    \"deadlock_message\": ";
-        jsonStr += kDeadlockedString;
-        jsonStr += ",\n";
+        root["deadlock_message"] = kDeadlockedString;
     }
     // FIXME risky to access data structures without a lock held?
 
-    jsonStr += "  \"Playback_Threads\": [\n";
+    Json::Value playbackThreads = Json::arrayValue;
     // dump playback threads
     for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
-        if (i != 0) {
-            jsonStr += ",\n";
-        }
-        jsonStr += mPlaybackThreads.valueAt(i)->getJsonString();
+        playbackThreads.append(mPlaybackThreads.valueAt(i)->getJsonDump());
     }
-    jsonStr += "\n  ]\n}\n";
 
     if (locked) {
         mLock.unlock();
     }
 
-    return jsonStr;
+    root["playback_threads"] = playbackThreads;
+
+    return root;
 }
 
 sp<AudioFlinger::Client> AudioFlinger::registerPid(pid_t pid)
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 95b947c..a7fdf41 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -79,6 +79,7 @@
 
 #include <powermanager/IPowerManager.h>
 
+#include <json/json.h>
 #include <media/nblog/NBLog.h>
 #include <private/media/AudioEffectShared.h>
 #include <private/media/AudioTrackShared.h>
@@ -114,7 +115,7 @@
     static const char* getServiceName() ANDROID_API { return "media.audio_flinger"; }
 
     virtual     status_t    dump(int fd, const Vector<String16>& args);
-                std::string getJsonString();
+                Json::Value getJsonDump();
 
     // IAudioFlinger interface, in binder opcode order
     virtual sp<IAudioTrack> createTrack(const CreateTrackInput& input,
diff --git a/services/audioflinger/FastMixerDumpState.cpp b/services/audioflinger/FastMixerDumpState.cpp
index ffdc117..c67ddad 100644
--- a/services/audioflinger/FastMixerDumpState.cpp
+++ b/services/audioflinger/FastMixerDumpState.cpp
@@ -24,6 +24,7 @@
 #include <cpustats/ThreadCpuUsage.h>
 #endif
 #endif
+#include <json/json.h>
 #include <string>
 #include <utils/Debug.h>
 #include <utils/Log.h>
@@ -205,14 +206,13 @@
     }
 }
 
-// TODO get rid of extraneous lines and use better key names.
-// TODO may go back to using a library to do the json formatting.
-std::string FastMixerDumpState::getJsonString() const
+Json::Value FastMixerDumpState::getJsonDump() const
 {
+    Json::Value root(Json::objectValue);
     if (mCommand == FastMixerState::INITIAL) {
-        return "    {\n      \"status\": \"uninitialized\"\n    }";
+        root["status"] = "uninitialized";
+        return root;
     }
-    std::string jsonStr = "    {\n";
 #ifdef FAST_THREAD_STATISTICS
     // find the interval of valid samples
     const uint32_t bounds = mBounds;
@@ -230,31 +230,25 @@
     }
     // statistics for monotonic (wall clock) time, thread raw CPU load in time, CPU clock frequency,
     // and adjusted CPU load in MHz normalized for CPU clock frequency
-    std::string jsonWallStr = "      \"wall_clock_time\":[";
-    std::string jsonLoadNsStr = "      \"raw_cpu_load\":[";
+    Json::Value jsonWall(Json::arrayValue);
+    Json::Value jsonLoadNs(Json::arrayValue);
     // loop over all the samples
     for (uint32_t j = 0; j < n; ++j) {
         size_t i = oldestClosed++ & (mSamplingN - 1);
         uint32_t wallNs = mMonotonicNs[i];
-        if (j != 0) {
-            jsonWallStr += ',';
-            jsonLoadNsStr += ',';
-        }
-        /* jsonObject["wall"].append(wallNs); */
-        jsonWallStr += std::to_string(wallNs);
+        jsonWall.append(wallNs);
         uint32_t sampleLoadNs = mLoadNs[i];
-        jsonLoadNsStr += std::to_string(sampleLoadNs);
+        jsonLoadNs.append(sampleLoadNs);
     }
-    jsonWallStr += ']';
-    jsonLoadNsStr += ']';
     if (n) {
-        jsonStr += jsonWallStr + ",\n" + jsonLoadNsStr + "\n";
+        root["wall_clock_time_ns"] = jsonWall;
+        root["raw_cpu_load_ns"] = jsonLoadNs;
+        root["status"] = "ok";
     } else {
-        //dprintf(fd, "  No FastMixer statistics available currently\n");
+        root["status"] = "unavailable";
     }
 #endif
-    jsonStr += "    }";
-    return jsonStr;
+    return root;
 }
 
 }   // android
diff --git a/services/audioflinger/FastMixerDumpState.h b/services/audioflinger/FastMixerDumpState.h
index 81c4175..69c2e4e 100644
--- a/services/audioflinger/FastMixerDumpState.h
+++ b/services/audioflinger/FastMixerDumpState.h
@@ -20,6 +20,7 @@
 #include <stdint.h>
 #include <string>
 #include <audio_utils/TimestampVerifier.h>
+#include <json/json.h>
 #include "Configuration.h"
 #include "FastThreadDumpState.h"
 #include "FastMixerState.h"
@@ -67,7 +68,7 @@
     /*virtual*/ ~FastMixerDumpState();
 
     void dump(int fd) const;             // should only be called on a stable copy, not the original
-    std::string getJsonString() const;   // should only be called on a stable copy, not the original
+    Json::Value getJsonDump() const;     // should only be called on a stable copy, not the original
 
     double   mLatencyMs = 0.;   // measured latency, default of 0 if no valid timestamp read.
     uint32_t mWriteSequence;    // incremented before and after each write()
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 6c7179e..3111585 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -42,6 +42,7 @@
 #include <audio_utils/primitives.h>
 #include <audio_utils/format.h>
 #include <audio_utils/minifloat.h>
+#include <json/json.h>
 #include <system/audio_effects/effect_ns.h>
 #include <system/audio_effects/effect_aec.h>
 #include <system/audio.h>
@@ -1763,9 +1764,9 @@
     mLocalLog.dump(fd, "   " /* prefix */, 40 /* lines */);
 }
 
-std::string AudioFlinger::PlaybackThread::getJsonString() const
+Json::Value AudioFlinger::PlaybackThread::getJsonDump() const
 {
-    return "{}";
+    return Json::Value(Json::objectValue);
 }
 
 void AudioFlinger::PlaybackThread::dumpTracks(int fd, const Vector<String16>& args __unused)
@@ -5141,14 +5142,20 @@
     }
 }
 
-std::string AudioFlinger::MixerThread::getJsonString() const
+Json::Value AudioFlinger::MixerThread::getJsonDump() const
 {
-    // Make a non-atomic copy of fast mixer dump state so it won't change underneath us
-    // while we are dumping it.  It may be inconsistent, but it won't mutate!
-    // This is a large object so we place it on the heap.
-    // FIXME 25972958: Need an intelligent copy constructor that does not touch unused pages.
-    return std::unique_ptr<FastMixerDumpState>(new FastMixerDumpState(mFastMixerDumpState))
-        ->getJsonString();
+    Json::Value root;
+    if (hasFastMixer()) {
+        // Make a non-atomic copy of fast mixer dump state so it won't change underneath us
+        // while we are dumping it.  It may be inconsistent, but it won't mutate!
+        // This is a large object so we place it on the heap.
+        // FIXME 25972958: Need an intelligent copy constructor that does not touch unused pages.
+        const std::unique_ptr<FastMixerDumpState> copy(new FastMixerDumpState(mFastMixerDumpState));
+        root["fastmixer_stats"] = copy->getJsonDump();
+    } else {
+        root["fastmixer_stats"] = "no_fastmixer";
+    }
+    return root;
 }
 
 uint32_t AudioFlinger::MixerThread::idleSleepTimeUs() const
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index dc23717..09a5530 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -662,7 +662,7 @@
 
                 void        dump(int fd, const Vector<String16>& args);
                 // returns a string of audio performance related data in JSON format.
-    virtual     std::string getJsonString() const;
+    virtual     Json::Value getJsonDump() const;
 
     // Thread virtuals
     virtual     bool        threadLoop();
@@ -1108,7 +1108,7 @@
     virtual     bool        checkForNewParameter_l(const String8& keyValuePair,
                                                    status_t& status);
     virtual     void        dumpInternals(int fd, const Vector<String16>& args);
-                std::string getJsonString() const override;
+                Json::Value getJsonDump() const override;
 
     virtual     bool        isTrackAllowed_l(
                                     audio_channel_mask_t channelMask, audio_format_t format,