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,