Blocking client thread during animation frames

Since the main UI thread will never block on prior animation
frames if applying a transaction, we need the client thread to be
blocked when it is trying to apply another animation frame.

Bug: 129130064
Test: build, boot, manual, SurfaceFlinger_test
Change-Id: I20c7351d5b6aa13810990099f71d4e1771a2ef7b
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 3744f8b..2d53609 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -3486,7 +3486,12 @@
             flushedATransaction = true;
         }
 
-        it = (transactionQueue.empty()) ? mTransactionQueues.erase(it) : std::next(it, 1);
+        if (transactionQueue.empty()) {
+            it = mTransactionQueues.erase(it);
+            mTransactionCV.broadcast();
+        } else {
+            std::next(it, 1);
+        }
     }
     return flushedATransaction;
 }
@@ -3559,7 +3564,22 @@
     }
 
     // If its TransactionQueue already has a pending TransactionState or if it is pending
-    if (mTransactionQueues.find(applyToken) != mTransactionQueues.end() ||
+    auto itr = mTransactionQueues.find(applyToken);
+    // if this is an animation frame, wait until prior animation frame has
+    // been applied by SF
+    if (flags & eAnimation) {
+        while (itr != mTransactionQueues.end()) {
+            status_t err = mTransactionCV.waitRelative(mStateLock, s2ns(5));
+            if (CC_UNLIKELY(err != NO_ERROR)) {
+                ALOGW_IF(err == TIMED_OUT,
+                         "setTransactionState timed out "
+                         "waiting for animation frame to apply");
+                break;
+            }
+            itr = mTransactionQueues.find(applyToken);
+        }
+    }
+    if (itr != mTransactionQueues.end() ||
         !transactionIsReadyToBeApplied(desiredPresentTime, states)) {
         mTransactionQueues[applyToken].emplace(states, displays, flags, desiredPresentTime,
                                                uncacheBuffer, listenerCallbacks, postTime,