C2BqPool: Expire waiters on Surface switching

Wake up and expire C2Fence waiters for the old Surface when the Surface
is switched to a new Surface.

Bug: 235330851
Change-Id: I8f0a9adace5f53fe7f47179b425bb899abcec64f
diff --git a/media/codec2/hal/client/client.cpp b/media/codec2/hal/client/client.cpp
index 09452c4..f5128ca 100644
--- a/media/codec2/hal/client/client.cpp
+++ b/media/codec2/hal/client/client.cpp
@@ -1722,6 +1722,8 @@
                     static_cast<uint64_t>(blockPoolId),
                     bqId == 0 ? nullHgbp : igbp);
 
+    mOutputBufferQueue->expireOldWaiters();
+
     if (!transStatus.isOk()) {
         LOG(ERROR) << "setOutputSurface -- transaction failed.";
         return C2_TRANSACTION_FAILED;
@@ -1763,6 +1765,7 @@
                        << status << ".";
         }
     }
+    mOutputBufferQueue->expireOldWaiters();
 }
 
 c2_status_t Codec2Client::Component::connectToInputSurface(
diff --git a/media/codec2/hal/client/include/codec2/hidl/output.h b/media/codec2/hal/client/include/codec2/hidl/output.h
index a13edf3..c208df0 100644
--- a/media/codec2/hal/client/include/codec2/hidl/output.h
+++ b/media/codec2/hal/client/include/codec2/hidl/output.h
@@ -50,6 +50,10 @@
                    int maxDequeueBufferCount,
                    std::shared_ptr<V1_2::SurfaceSyncObj> *syncObj);
 
+    // If there are waiters to allocate from the old surface, wake up and expire
+    // them.
+    void expireOldWaiters();
+
     // Stop using the current output surface. Pending buffer opeations will not
     // perform anymore.
     void stop();
@@ -86,6 +90,8 @@
     std::weak_ptr<_C2BlockPoolData> mPoolDatas[BufferQueueDefs::NUM_BUFFER_SLOTS];
     std::shared_ptr<C2SurfaceSyncMemory> mSyncMem;
     bool mStopped;
+    std::mutex mOldMutex;
+    std::shared_ptr<C2SurfaceSyncMemory> mOldMem;
 
     bool registerBuffer(const C2ConstGraphicBlock& block);
 };
diff --git a/media/codec2/hal/client/output.cpp b/media/codec2/hal/client/output.cpp
index f789030..6aaf9ab 100644
--- a/media/codec2/hal/client/output.cpp
+++ b/media/codec2/hal/client/output.cpp
@@ -217,6 +217,7 @@
     sp<GraphicBuffer> buffers[BufferQueueDefs::NUM_BUFFER_SLOTS];
     std::weak_ptr<_C2BlockPoolData>
             poolDatas[BufferQueueDefs::NUM_BUFFER_SLOTS];
+    std::shared_ptr<C2SurfaceSyncMemory> oldMem;
     {
         std::scoped_lock<std::mutex> l(mMutex);
         bool stopped = mStopped;
@@ -238,7 +239,7 @@
             }
             return false;
         }
-        std::shared_ptr<C2SurfaceSyncMemory> oldMem = mSyncMem;
+        oldMem = mSyncMem;
         C2SyncVariables *oldSync = mSyncMem ? mSyncMem->mem() : nullptr;
         if (oldSync) {
             oldSync->lock();
@@ -314,11 +315,26 @@
             newSync->unlock();
         }
     }
+    {
+        std::scoped_lock<std::mutex> l(mOldMutex);
+        mOldMem = oldMem;
+    }
     ALOGD("remote graphic buffer migration %zu/%zu",
           success, tryNum);
     return true;
 }
 
+void OutputBufferQueue::expireOldWaiters() {
+    std::scoped_lock<std::mutex> l(mOldMutex);
+    if (mOldMem) {
+        C2SyncVariables *oldSync = mOldMem->mem();
+        if (oldSync) {
+            oldSync->notifyAll();
+        }
+        mOldMem.reset();
+    }
+}
+
 void OutputBufferQueue::stop() {
     std::scoped_lock<std::mutex> l(mMutex);
     mStopped = true;
diff --git a/media/codec2/vndk/include/C2SurfaceSyncObj.h b/media/codec2/vndk/include/C2SurfaceSyncObj.h
index d858f27..b193b4a 100644
--- a/media/codec2/vndk/include/C2SurfaceSyncObj.h
+++ b/media/codec2/vndk/include/C2SurfaceSyncObj.h
@@ -112,6 +112,11 @@
      */
     c2_status_t waitForChange(uint32_t waitId, c2_nsecs_t timeoutNs);
 
+    /**
+     * Wake up and expire all waitors.
+     */
+    void notifyAll();
+
     C2SyncVariables() {}
 
 private:
diff --git a/media/codec2/vndk/platform/C2SurfaceSyncObj.cpp b/media/codec2/vndk/platform/C2SurfaceSyncObj.cpp
index bf4ca32..d55a3d8 100644
--- a/media/codec2/vndk/platform/C2SurfaceSyncObj.cpp
+++ b/media/codec2/vndk/platform/C2SurfaceSyncObj.cpp
@@ -244,6 +244,12 @@
     return C2_BAD_VALUE;
 }
 
+void C2SyncVariables::notifyAll() {
+    this->lock();
+    this->broadcast();
+    this->unlock();
+}
+
 int C2SyncVariables::signal() {
     mCond++;