media codec2: Expire waiters from HAL during stop()/release()

Expire C2Fence waiting from HAL during stop()/release().

Bug: 300350761
Test: atest android.media.decoder.cts.AdaptivePlaybackTest
Test: atest android.media.codec.cts.MediaCodecTest#testAsyncRelease
Test: atest android.media.codec.cts.MediaCodecTest#testAsyncStopAndReset

Change-Id: I68aeafee2c4be95b78dd2fc98db01f231748e5da
diff --git a/media/codec2/hal/client/output.cpp b/media/codec2/hal/client/output.cpp
index 4eebd1c..48f9756 100644
--- a/media/codec2/hal/client/output.cpp
+++ b/media/codec2/hal/client/output.cpp
@@ -336,9 +336,25 @@
 }
 
 void OutputBufferQueue::stop() {
-    std::scoped_lock<std::mutex> l(mMutex);
-    mStopped = true;
-    mOwner.reset(); // destructor of the block will not triger IGBP::cancel()
+    std::shared_ptr<C2SurfaceSyncMemory> oldMem;
+    {
+        std::scoped_lock<std::mutex> l(mMutex);
+        if (mStopped) {
+            return;
+        }
+        mStopped = true;
+        mOwner.reset(); // destructor of the block will not trigger IGBP::cancel()
+        // basically configuring null surface
+        oldMem = mSyncMem;
+        mSyncMem.reset();
+        mIgbp.clear();
+        mGeneration = 0;
+        mBqId = 0;
+    }
+    {
+        std::scoped_lock<std::mutex> l(mOldMutex);
+        mOldMem = oldMem;
+    }
 }
 
 bool OutputBufferQueue::registerBuffer(const C2ConstGraphicBlock& block) {
diff --git a/media/codec2/sfplugin/CCodec.cpp b/media/codec2/sfplugin/CCodec.cpp
index 86fd8ab..8082dd7 100644
--- a/media/codec2/sfplugin/CCodec.cpp
+++ b/media/codec2/sfplugin/CCodec.cpp
@@ -1915,8 +1915,16 @@
         }
         comp = state->comp;
     }
-    status_t err = comp->stop();
+
+    // Note: Logically mChannel->stopUseOutputSurface() should be after comp->stop().
+    // But in the case some HAL implementations hang forever on comp->stop().
+    // (HAL is waiting for C2Fence until fetchGraphicBlock unblocks and not
+    // completing stop()).
+    // So we reverse their order for stopUseOutputSurface() to notify C2Fence waiters
+    // prior to comp->stop().
+    // See also b/300350761.
     mChannel->stopUseOutputSurface(pushBlankBuffer);
+    status_t err = comp->stop();
     if (err != C2_OK) {
         // TODO: convert err into status_t
         mCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL);
@@ -2004,8 +2012,15 @@
         }
         comp = state->comp;
     }
-    comp->release();
+    // Note: Logically mChannel->stopUseOutputSurface() should be after comp->release().
+    // But in the case some HAL implementations hang forever on comp->release().
+    // (HAL is waiting for C2Fence until fetchGraphicBlock unblocks and not
+    // completing release()).
+    // So we reverse their order for stopUseOutputSurface() to notify C2Fence waiters
+    // prior to comp->release().
+    // See also b/300350761.
     mChannel->stopUseOutputSurface(pushBlankBuffer);
+    comp->release();
 
     {
         Mutexed<State>::Locked state(mState);