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);
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 0276cad..fb83d75 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -23,6 +23,8 @@
 #include <mutex>
 #include <deque>
 #include <map>
+#include <memory>
+#include <string>
 #include <vector>
 #include <stdint.h>
 #include <sys/types.h>
@@ -111,6 +113,7 @@
     static const char* getServiceName() ANDROID_API { return "media.audio_flinger"; }
 
     virtual     status_t    dump(int fd, const Vector<String16>& args);
+                std::string getJsonString();
 
     // IAudioFlinger interface, in binder opcode order
     virtual sp<IAudioTrack> createTrack(const CreateTrackInput& input,
diff --git a/services/audioflinger/Configuration.h b/services/audioflinger/Configuration.h
index ede8e3f..64bb426 100644
--- a/services/audioflinger/Configuration.h
+++ b/services/audioflinger/Configuration.h
@@ -27,7 +27,7 @@
 //#define AUDIO_WATCHDOG
 
 // uncomment to display CPU load adjusted for CPU frequency
-//#define CPU_FREQUENCY_STATISTICS
+#define CPU_FREQUENCY_STATISTICS
 
 // uncomment to enable fast threads to take performance samples for later statistical analysis
 #define FAST_THREAD_STATISTICS
diff --git a/services/audioflinger/FastMixerDumpState.cpp b/services/audioflinger/FastMixerDumpState.cpp
index d60643c..c0f9f0f 100644
--- a/services/audioflinger/FastMixerDumpState.cpp
+++ b/services/audioflinger/FastMixerDumpState.cpp
@@ -24,6 +24,7 @@
 #include <cpustats/ThreadCpuUsage.h>
 #endif
 #endif
+#include <string>
 #include <utils/Debug.h>
 #include <utils/Log.h>
 #include "FastMixerDumpState.h"
@@ -76,14 +77,14 @@
     dprintf(fd, "  FastMixer Timestamp stats: %s\n", mTimestampVerifier.toString().c_str());
 #ifdef FAST_THREAD_STATISTICS
     // find the interval of valid samples
-    uint32_t bounds = mBounds;
-    uint32_t newestOpen = bounds & 0xFFFF;
+    const uint32_t bounds = mBounds;
+    const uint32_t newestOpen = bounds & 0xFFFF;
     uint32_t oldestClosed = bounds >> 16;
 
     //uint32_t n = (newestOpen - oldestClosed) & 0xFFFF;
     uint32_t n;
     __builtin_sub_overflow(newestOpen, oldestClosed, &n);
-    n = n & 0xFFFF;
+    n &= 0xFFFF;
 
     if (n > mSamplingN) {
         ALOGE("too many samples %u", n);
@@ -204,4 +205,56 @@
     }
 }
 
+// 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
+{
+    if (mCommand == FastMixerState::INITIAL) {
+        return "    {\n      \"status\": \"uninitialized\"\n    }";
+    }
+    std::string jsonStr = "    {\n";
+#ifdef FAST_THREAD_STATISTICS
+    // find the interval of valid samples
+    const uint32_t bounds = mBounds;
+    const uint32_t newestOpen = bounds & 0xFFFF;
+    uint32_t oldestClosed = bounds >> 16;
+
+    //uint32_t n = (newestOpen - oldestClosed) & 0xFFFF;
+    uint32_t n;
+    __builtin_sub_overflow(newestOpen, oldestClosed, &n);
+    n &= 0xFFFF;
+
+    if (n > mSamplingN) {
+        ALOGE("too many samples %u", n);
+        n = mSamplingN;
+    }
+    // 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\":[";
+    // 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);
+        uint32_t sampleLoadNs = mLoadNs[i];
+        jsonLoadNsStr += std::to_string(sampleLoadNs);
+    }
+    jsonWallStr += ']';
+    jsonLoadNsStr += ']';
+    if (n) {
+        jsonStr += jsonWallStr + ",\n" + jsonLoadNsStr + "\n";
+    } else {
+        //dprintf(fd, "  No FastMixer statistics available currently\n");
+    }
+#endif
+    jsonStr += "    }";
+    return jsonStr;
+}
+
 }   // android
diff --git a/services/audioflinger/FastMixerDumpState.h b/services/audioflinger/FastMixerDumpState.h
index 9b91cbc..81c4175 100644
--- a/services/audioflinger/FastMixerDumpState.h
+++ b/services/audioflinger/FastMixerDumpState.h
@@ -18,6 +18,7 @@
 #define ANDROID_AUDIO_FAST_MIXER_DUMP_STATE_H
 
 #include <stdint.h>
+#include <string>
 #include <audio_utils/TimestampVerifier.h>
 #include "Configuration.h"
 #include "FastThreadDumpState.h"
@@ -65,7 +66,8 @@
     FastMixerDumpState();
     /*virtual*/ ~FastMixerDumpState();
 
-    void dump(int fd) const;    // should only be called on a stable copy, not the original
+    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
 
     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 70af5c6..5cc8c31 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -23,6 +23,8 @@
 #include "Configuration.h"
 #include <math.h>
 #include <fcntl.h>
+#include <memory>
+#include <string>
 #include <linux/futex.h>
 #include <sys/stat.h>
 #include <sys/syscall.h>
@@ -1760,6 +1762,11 @@
     mLocalLog.dump(fd, "   " /* prefix */, 40 /* lines */);
 }
 
+std::string AudioFlinger::PlaybackThread::getJsonString() const
+{
+    return "{}";
+}
+
 void AudioFlinger::PlaybackThread::dumpTracks(int fd, const Vector<String16>& args __unused)
 {
     String8 result;
@@ -5098,9 +5105,8 @@
         // 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 FastMixerDumpState *copy = new FastMixerDumpState(mFastMixerDumpState);
+        const std::unique_ptr<FastMixerDumpState> copy(new FastMixerDumpState(mFastMixerDumpState));
         copy->dump(fd);
-        delete copy;
 
 #ifdef STATE_QUEUE_DUMP
         // Similar for state queue
@@ -5123,6 +5129,16 @@
     }
 }
 
+std::string AudioFlinger::MixerThread::getJsonString() 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();
+}
+
 uint32_t AudioFlinger::MixerThread::idleSleepTimeUs() const
 {
     return (uint32_t)(((mNormalFrameCount * 1000) / mSampleRate) * 1000) / 2;
@@ -7423,9 +7439,8 @@
     // 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 FastCaptureDumpState *copy = new FastCaptureDumpState(mFastCaptureDumpState);
+    std::unique_ptr<FastCaptureDumpState> copy(new FastCaptureDumpState(mFastCaptureDumpState));
     copy->dump(fd);
-    delete copy;
 }
 
 void AudioFlinger::RecordThread::dumpTracks(int fd, const Vector<String16>& args __unused)
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 064e291..734a7bd 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -658,6 +658,8 @@
     virtual             ~PlaybackThread();
 
                 void        dump(int fd, const Vector<String16>& args);
+                // returns a string of audio performance related data in JSON format.
+    virtual     std::string getJsonString() const;
 
     // Thread virtuals
     virtual     bool        threadLoop();
@@ -1103,6 +1105,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;
 
     virtual     bool        isTrackAllowed_l(
                                     audio_channel_mask_t channelMask, audio_format_t format,