AudioFlinger: Properly account for underruns

When the mixer status was MIXER_ENABLED twice in a row
zeroes were forced to the audio sink.

Test: aaudio test write_sine_callback -pl -n1 -r44100 -s20
      and then use rapid volume changes.
Bug: 131767115
Change-Id: I24b41084138210c63e8c551ae4a5f3adddb9e607
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index a48b733..7daa929 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -3277,6 +3277,7 @@
 
         Vector< sp<EffectChain> > effectChains;
         audio_session_t activeHapticSessionId = AUDIO_SESSION_NONE;
+        std::vector<sp<Track>> activeTracks;
 
         // If the device is AUDIO_DEVICE_OUT_BUS, check for downstream latency.
         //
@@ -3563,6 +3564,12 @@
                 }
             }
 
+            // Acquire a local copy of active tracks with lock (release w/o lock).
+            //
+            // Control methods on the track acquire the ThreadBase lock (e.g. start()
+            // stop(), pause(), etc.), but the threadLoop is entitled to call audio
+            // data / buffer methods on tracks from activeTracks without the ThreadBase lock.
+            activeTracks.insert(activeTracks.end(), mActiveTracks.begin(), mActiveTracks.end());
         } // mLock scope ends
 
         if (mBytesRemaining == 0) {
@@ -3577,6 +3584,13 @@
                 threadLoop_sleepTime();
                 if (mSleepTimeUs == 0) {
                     mCurrentWriteLength = mSinkBufferSize;
+
+                    // Tally underrun frames as we are inserting 0s here.
+                    for (const auto& track : activeTracks) {
+                        if (track->mFillingUpStatus == Track::FS_ACTIVE) {
+                            track->mAudioTrackServerProxy->tallyUnderrunFrames(mNormalFrameCount);
+                        }
+                    }
                 }
             }
             // Either threadLoop_mix() or threadLoop_sleepTime() should have set