Fast track dumpsys

Bug: 6591648
Change-Id: I696f51c682e7233ba690d97da26012084989b412
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index dee67d0..a61b8ea 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -1605,6 +1605,7 @@
     snprintf(buffer, SIZE, "mix buffer : %p\n", mMixBuffer);
     result.append(buffer);
     write(fd, result.string(), result.size());
+    fdprintf(fd, "Fast track availMask=%#x\n", mFastTrackAvailMask);
 
     dumpBase(fd, args);
 
@@ -2847,7 +2848,8 @@
 
             // Determine whether the track is currently in underrun condition,
             // and whether it had a recent underrun.
-            FastTrackUnderruns underruns = mFastMixerDumpState.mTracks[j].mUnderruns;
+            FastTrackDump *ftDump = &mFastMixerDumpState.mTracks[j];
+            FastTrackUnderruns underruns = ftDump->mUnderruns;
             uint32_t recentFull = (underruns.mBitFields.mFull -
                     track->mObservedUnderruns.mBitFields.mFull) & UNDERRUN_MASK;
             uint32_t recentPartial = (underruns.mBitFields.mPartial -
diff --git a/services/audioflinger/FastMixer.cpp b/services/audioflinger/FastMixer.cpp
index b0af6ed..d8bed40 100644
--- a/services/audioflinger/FastMixer.cpp
+++ b/services/audioflinger/FastMixer.cpp
@@ -239,6 +239,7 @@
 
             // check for change in active track set
             unsigned currentTrackMask = current->mTrackMask;
+            dumpState->mTrackMask = currentTrackMask;
             if (current->mFastTracksGen != fastTracksGen) {
                 ALOG_ASSERT(mixBuffer != NULL);
                 int name;
@@ -387,6 +388,7 @@
                     mixer->enable(name);
                 }
                 ftDump->mUnderruns = underruns;
+                ftDump->mFramesReady = framesReady;
             }
             // process() is CPU-bound
             mixer->process(AudioBufferProvider::kInvalidPTS);
@@ -562,7 +564,8 @@
 FastMixerDumpState::FastMixerDumpState() :
     mCommand(FastMixerState::INITIAL), mWriteSequence(0), mFramesWritten(0),
     mNumTracks(0), mWriteErrors(0), mUnderruns(0), mOverruns(0),
-    mSampleRate(0), mFrameCount(0), /* mMeasuredWarmupTs({0, 0}), */ mWarmupCycles(0)
+    mSampleRate(0), mFrameCount(0), /* mMeasuredWarmupTs({0, 0}), */ mWarmupCycles(0),
+    mTrackMask(0)
 #ifdef FAST_MIXER_STATISTICS
     , mBounds(0)
 #endif
@@ -671,6 +674,40 @@
                  "    mean=%.1f min=%.1f max=%.1f stddev=%.1f\n",
                  loadMHz.mean(), loadMHz.minimum(), loadMHz.maximum(), loadMHz.stddev());
 #endif
+    // The active track mask and track states are updated non-atomically.
+    // So if we relied on isActive to decide whether to display,
+    // then we might display an obsolete track or omit an active track.
+    // Instead we always display all tracks, with an indication
+    // of whether we think the track is active.
+    uint32_t trackMask = mTrackMask;
+    fdprintf(fd, "Fast tracks: kMaxFastTracks=%u activeMask=%#x\n",
+            FastMixerState::kMaxFastTracks, trackMask);
+    fdprintf(fd, "Index Active Full Partial Empty  Recent Ready\n");
+    for (uint32_t i = 0; i < FastMixerState::kMaxFastTracks; ++i, trackMask >>= 1) {
+        bool isActive = trackMask & 1;
+        const FastTrackDump *ftDump = &mTracks[i];
+        const FastTrackUnderruns& underruns = ftDump->mUnderruns;
+        const char *mostRecent;
+        switch (underruns.mBitFields.mMostRecent) {
+        case UNDERRUN_FULL:
+            mostRecent = "full";
+            break;
+        case UNDERRUN_PARTIAL:
+            mostRecent = "partial";
+            break;
+        case UNDERRUN_EMPTY:
+            mostRecent = "empty";
+            break;
+        default:
+            mostRecent = "?";
+            break;
+        }
+        fdprintf(fd, "%5u %6s %4u %7u %5u %7s %5u\n", i, isActive ? "yes" : "no",
+                (underruns.mBitFields.mFull) & UNDERRUN_MASK,
+                (underruns.mBitFields.mPartial) & UNDERRUN_MASK,
+                (underruns.mBitFields.mEmpty) & UNDERRUN_MASK,
+                mostRecent, ftDump->mFramesReady);
+    }
 }
 
 }   // namespace android
diff --git a/services/audioflinger/FastMixer.h b/services/audioflinger/FastMixer.h
index e95abf6..06e76d5 100644
--- a/services/audioflinger/FastMixer.h
+++ b/services/audioflinger/FastMixer.h
@@ -72,9 +72,10 @@
 
 // Represents the dump state of a fast track
 struct FastTrackDump {
-    FastTrackDump() { }
+    FastTrackDump() : mFramesReady(0) { }
     /*virtual*/ ~FastTrackDump() { }
     FastTrackUnderruns mUnderruns;
+    size_t mFramesReady;        // most recent value only; no long-term statistics kept
 };
 
 // The FastMixerDumpState keeps a cache of FastMixer statistics that can be logged by dumpsys.
@@ -100,6 +101,7 @@
     size_t   mFrameCount;
     struct timespec mMeasuredWarmupTs;  // measured warmup time
     uint32_t mWarmupCycles;     // number of loop cycles required to warmup
+    uint32_t mTrackMask;        // mask of active tracks
     FastTrackDump   mTracks[FastMixerState::kMaxFastTracks];
 
 #ifdef FAST_MIXER_STATISTICS