Merge "audio flinger: fix wraparound issues in AudioRecord shared audi history implementation" into sc-dev
diff --git a/services/audioflinger/RecordTracks.h b/services/audioflinger/RecordTracks.h
index b953c0b..451c198 100644
--- a/services/audioflinger/RecordTracks.h
+++ b/services/audioflinger/RecordTracks.h
@@ -70,7 +70,7 @@
                                 audio_input_flags_t flags,
                                 track_type type,
                                 audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE,
-                                int64_t startTimeMs = -1);
+                                int32_t startFrames = -1);
     virtual             ~RecordTrack();
     virtual status_t    initCheck() const;
 
@@ -110,7 +110,7 @@
             status_t    setPreferredMicrophoneFieldDimension(float zoom);
             status_t    shareAudioHistory(const std::string& sharedAudioPackageName,
                                           int64_t sharedAudioStartMs);
-            int64_t     startTimeMs() { return mStartTimeMs; }
+            int32_t     startFrames() { return mStartFrames; }
 
     static  bool        checkServerLatencySupported(
                                 audio_format_t format, audio_input_flags_t flags) {
@@ -152,7 +152,7 @@
             // used to enforce OP_RECORD_AUDIO
             sp<OpRecordAudioMonitor>           mOpRecordAudioMonitor;
             std::string                        mSharedAudioPackageName = {};
-            int64_t                            mStartTimeMs = -1;
+            int32_t                            mStartFrames = -1;
 };
 
 // playback track, used by PatchPanel
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 50ef454..ef92492 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -7934,18 +7934,18 @@
 
     { // scope for mLock
         Mutex::Autolock _l(mLock);
-        long startTimeMs = -1;
+        int32_t startFrames = -1;
         if (!mSharedAudioPackageName.empty()
                 && mSharedAudioPackageName == checkedIdentity.packageName
                 && mSharedAudioSessionId == sessionId
                 && captureHotwordAllowed(checkedIdentity)) {
-            startTimeMs = mSharedAudioStartMs;
+            startFrames = mSharedAudioStartFrames;
         }
 
         track = new RecordTrack(this, client, attr, sampleRate,
                       format, channelMask, frameCount,
                       nullptr /* buffer */, (size_t)0 /* bufferSize */, sessionId, creatorPid,
-                      checkedIdentity, *flags, TrackBase::TYPE_DEFAULT, portId, startTimeMs);
+                      checkedIdentity, *flags, TrackBase::TYPE_DEFAULT, portId, startFrames);
 
         lStatus = track->initCheck();
         if (lStatus != NO_ERROR) {
@@ -8202,17 +8202,32 @@
     if ((hasAudioSession_l(sharedSessionId) & ThreadBase::TRACK_SESSION) == 0) {
         return BAD_VALUE;
     }
-    if (sharedAudioStartMs < 0 || sharedAudioStartMs * mSampleRate / 1000 > mRsmpInRear) {
+
+    if (sharedAudioStartMs < 0
+        || sharedAudioStartMs > INT64_MAX / mSampleRate) {
         return BAD_VALUE;
     }
 
+    // Current implementation of the input resampling buffer wraps around indexes at 32 bit.
+    // As we cannot detect more than one wraparound, only accept values up current write position
+    // after one wraparound
+    // We assume recent wraparounds on mRsmpInRear only given it is unlikely that the requesting
+    // app waits several hours after the start time was computed.
+    const int64_t sharedAudioStartFrames = sharedAudioStartMs * mSampleRate / 1000;
+    const int32_t sharedOffset = audio_utils::safe_sub_overflow(mRsmpInRear,
+          (int32_t)sharedAudioStartFrames);
+    if (sharedOffset < 0
+          || sharedOffset > mRsmpInFrames) {
+      return BAD_VALUE;
+    }
+
     mSharedAudioPackageName = sharedAudioPackageName;
     if (mSharedAudioPackageName.empty()) {
         mSharedAudioSessionId = AUDIO_SESSION_NONE;
-        mSharedAudioStartMs = -1;
+        mSharedAudioStartFrames = -1;
     } else {
         mSharedAudioSessionId = sharedSessionId;
-        mSharedAudioStartMs = sharedAudioStartMs;
+        mSharedAudioStartFrames = (int32_t)sharedAudioStartFrames;
     }
     return NO_ERROR;
 }
@@ -8359,14 +8374,14 @@
     mRsmpInUnrel = 0;
     const int32_t rear = recordThread->mRsmpInRear;
     ssize_t deltaFrames = 0;
-    if (mRecordTrack->startTimeMs() >= 0) {
-        int32_t startFrames = mRecordTrack->startTimeMs() * recordThread->sampleRate()  / 1000;
-        // start frame has to be in the past
-        //TODO: b/185972521 fix in case rear or startFrames wrap around
-        if (startFrames > rear) {
-            startFrames = rear;
+    if (mRecordTrack->startFrames() >= 0) {
+        int32_t startFrames = mRecordTrack->startFrames();
+        // Accept a recent wraparound of mRsmpInRear
+        if (startFrames <= rear) {
+            deltaFrames = rear - startFrames;
+        } else {
+            deltaFrames = (int32_t)((int64_t)rear + UINT32_MAX + 1 - startFrames);
         }
-        deltaFrames = rear - startFrames;
         // start frame cannot be further in the past than start of resampling buffer
         if ((size_t) deltaFrames > recordThread->mRsmpInFrames) {
             deltaFrames = recordThread->mRsmpInFrames;
@@ -8828,17 +8843,22 @@
     if (mTracks.size() == 0) {
         return 0;
     }
-    //TODO: b/185972521 fix in case of wrap around on one track:
-    //  want the max(rear - front) for all tracks.
-    int32_t front = INT_MAX;
+    int32_t oldestFront = mRsmpInRear;
+    int32_t maxFilled = 0;
     for (size_t i = 0; i < mTracks.size(); i++) {
-        front = std::min(front, mTracks[i]->mResamplerBufferProvider->getFront());
+        int32_t front = mTracks[i]->mResamplerBufferProvider->getFront();
+        int32_t filled;
+        if (front <= mRsmpInRear) {
+            filled = mRsmpInRear - front;
+        } else {
+            filled = (int32_t)((int64_t)mRsmpInRear + UINT32_MAX + 1 - front);
+        }
+        if (filled > maxFilled) {
+            oldestFront = front;
+            maxFilled = filled;
+        }
     }
-    // discard any audio past the buffer size
-    if (audio_utils::safe_add_overflow(front, (int32_t)mRsmpInFrames) < mRsmpInRear) {
-        front = audio_utils::safe_sub_overflow(mRsmpInRear, (int32_t)mRsmpInFrames);
-    }
-    return front;
+    return oldestFront;
 }
 
 void AudioFlinger::RecordThread::updateFronts_l(int32_t offset)
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 03ed6fd..b6f7f24 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -1863,7 +1863,7 @@
             DeviceDescriptorBaseVector          mOutDevices;
 
             std::string                         mSharedAudioPackageName = {};
-            long                                mSharedAudioStartMs = 0;
+            int32_t                             mSharedAudioStartFrames = -1;
             audio_session_t                     mSharedAudioSessionId = AUDIO_SESSION_NONE;
 };
 
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 6549236..3e04804 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -2378,7 +2378,7 @@
             audio_input_flags_t flags,
             track_type type,
             audio_port_handle_t portId,
-            int64_t startTimeMs)
+            int32_t startFrames)
     :   TrackBase(thread, client, attr, sampleRate, format,
                   channelMask, frameCount, buffer, bufferSize, sessionId,
                   creatorPid,
@@ -2396,7 +2396,7 @@
         mFlags(flags),
         mSilenced(false),
         mOpRecordAudioMonitor(OpRecordAudioMonitor::createIfNeeded(identity, attr)),
-        mStartTimeMs(startTimeMs)
+        mStartFrames(startFrames)
 {
     if (mCblk == NULL) {
         return;