Recover from buffer stuffing for canned animations

Buffer stuffing occurs when SurfaceFlinger misses a frame, but the
client continues to produce buffers at the same rate, causing a
greater risk for jank to occur. Recovery is achieved for canned
animations by adjusting the animation timeline on the client side so
that SurfaceFlinger is no longer behind.

Use SF backdoor command 1045 to inject jank.
Usage: adb shell service call SurfaceFlinger 1045 f 1

Bug: b/294922229
Test: atest EventThreadTest
Test: presubmit, manually check perfetto traces
Flag: android.view.flags.buffer_stuffing_recovery
Change-Id: I38f0eb3d6ef1331e07d6022fa3a0e16c556ba06f
diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
index 625d2e6..268a6c4 100644
--- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
+++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
@@ -23,6 +23,7 @@
 
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
+#include <gui/DisplayEventReceiver.h>
 #include <log/log.h>
 #include <scheduler/VsyncConfig.h>
 #include <utils/Errors.h>
@@ -111,6 +112,8 @@
     void expectOnExpectedPresentTimePosted(nsecs_t expectedPresentTime);
     void expectUidFrameRateMappingEventReceivedByConnection(PhysicalDisplayId expectedDisplayId,
                                                             std::vector<FrameRateOverride>);
+    void expectQueuedBufferCountReceivedByConnection(
+            ConnectionEventRecorder& connectionEventRecorder, uint32_t expectedBufferCount);
 
     void onVSyncEvent(nsecs_t timestamp, nsecs_t expectedPresentationTime,
                       nsecs_t deadlineTimestamp) {
@@ -144,6 +147,7 @@
     sp<MockEventThreadConnection> mConnection;
     sp<MockEventThreadConnection> mThrottledConnection;
     std::unique_ptr<frametimeline::impl::TokenManager> mTokenManager;
+    std::vector<ConnectionEventRecorder*> mBufferStuffedConnectionRecorders;
 
     std::chrono::nanoseconds mVsyncPeriod;
 
@@ -376,6 +380,14 @@
     EXPECT_EQ(expectedDisplayId, event.header.displayId);
 }
 
+void EventThreadTest::expectQueuedBufferCountReceivedByConnection(
+        ConnectionEventRecorder& connectionEventRecorder, uint32_t expectedBufferCount) {
+    auto args = connectionEventRecorder.waitForCall();
+    ASSERT_TRUE(args.has_value());
+    const auto& event = std::get<0>(args.value());
+    EXPECT_EQ(expectedBufferCount, event.vsync.vsyncData.numberQueuedBuffers);
+}
+
 namespace {
 
 using namespace testing;
@@ -868,6 +880,63 @@
     EXPECT_EQ(HDCP_V2, event.hdcpLevelsChange.maxLevel);
 }
 
+TEST_F(EventThreadTest, connectionReceivesBufferStuffing) {
+    setupEventThread();
+
+    // Create a connection that will experience buffer stuffing.
+    ConnectionEventRecorder stuffedConnectionEventRecorder{0};
+    sp<MockEventThreadConnection> stuffedConnection =
+            createConnection(stuffedConnectionEventRecorder,
+                             gui::ISurfaceComposer::EventRegistration::modeChanged |
+                                     gui::ISurfaceComposer::EventRegistration::frameRateOverride,
+                             111);
+
+    // Add a connection and buffer count to the list of stuffed Uids that will receive
+    // data in the next vsync event.
+    BufferStuffingMap bufferStuffedUids;
+    bufferStuffedUids.try_emplace(stuffedConnection->mOwnerUid, 3);
+    mThread->addBufferStuffedUids(bufferStuffedUids);
+    mBufferStuffedConnectionRecorders.emplace_back(&stuffedConnectionEventRecorder);
+
+    // Signal that we want the next vsync event to be posted to two connections.
+    mThread->requestNextVsync(mConnection);
+    mThread->requestNextVsync(stuffedConnection);
+    onVSyncEvent(123, 456, 789);
+
+    // Vsync event data contains number of queued buffers.
+    expectQueuedBufferCountReceivedByConnection(mConnectionEventCallRecorder, 0);
+    expectQueuedBufferCountReceivedByConnection(stuffedConnectionEventRecorder, 3);
+}
+
+TEST_F(EventThreadTest, connectionsWithSameUidReceiveBufferStuffing) {
+    setupEventThread();
+
+    // Create a connection with the same Uid as another connection.
+    ConnectionEventRecorder secondConnectionEventRecorder{0};
+    sp<MockEventThreadConnection> secondConnection =
+            createConnection(secondConnectionEventRecorder,
+                             gui::ISurfaceComposer::EventRegistration::modeChanged |
+                                     gui::ISurfaceComposer::EventRegistration::frameRateOverride,
+                             mConnectionUid);
+
+    // Add connection Uid and buffer count to the list of stuffed Uids that will receive
+    // data in the next vsync event.
+    BufferStuffingMap bufferStuffedUids;
+    bufferStuffedUids.try_emplace(mConnectionUid, 3);
+    mThread->addBufferStuffedUids(bufferStuffedUids);
+    mBufferStuffedConnectionRecorders.emplace_back(&mConnectionEventCallRecorder);
+    mBufferStuffedConnectionRecorders.emplace_back(&secondConnectionEventRecorder);
+
+    // Signal that we want the next vsync event to be posted to two connections.
+    mThread->requestNextVsync(mConnection);
+    mThread->requestNextVsync(secondConnection);
+    onVSyncEvent(123, 456, 789);
+
+    // Vsync event data contains number of queued buffers.
+    expectQueuedBufferCountReceivedByConnection(mConnectionEventCallRecorder, 3);
+    expectQueuedBufferCountReceivedByConnection(secondConnectionEventRecorder, 3);
+}
+
 } // namespace
 } // namespace android