Merge "IAudioManager: add audio session ID to trackPlayer()" into sc-dev
diff --git a/include/OWNERS b/include/OWNERS
index db52850..c98e87a 100644
--- a/include/OWNERS
+++ b/include/OWNERS
@@ -1,3 +1,4 @@
+alecmouri@google.com
 alexeykuzmin@google.com
 dangittik@google.com
 jreck@google.com
@@ -8,7 +9,6 @@
 racarr@google.com
 romainguy@android.com
 santoscordon@google.com
-stoza@google.com
 svv@google.com
 
 # For multinetwork.h only.
diff --git a/libs/adbd_auth/include/adbd_auth.h b/libs/adbd_auth/include/adbd_auth.h
index 8f834df..1dcf540 100644
--- a/libs/adbd_auth/include/adbd_auth.h
+++ b/libs/adbd_auth/include/adbd_auth.h
@@ -26,7 +26,6 @@
 #endif
 
 __BEGIN_DECLS
-#if !defined(__ANDROID__) || __ANDROID_API__ >= 30
 
 // The transport type of the device connection.
 enum AdbTransportType : int32_t {
@@ -186,5 +185,4 @@
  */
 bool adbd_auth_supports_feature(AdbdAuthFeature feature);
 
-#endif  //!__ANDROID__ || __ANDROID_API__ >= 30
 __END_DECLS
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index 91033e9..b585ad2 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -32,6 +32,11 @@
         "libcutils_headers",
         "libutils_headers",
     ],
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.media",
+        "com.android.media.swcodec",
+    ],
     min_sdk_version: "29",
     target: {
         darwin: {
diff --git a/libs/binder/ndk/Android.bp b/libs/binder/ndk/Android.bp
index d76a1f9..897c72a 100644
--- a/libs/binder/ndk/Android.bp
+++ b/libs/binder/ndk/Android.bp
@@ -141,14 +141,12 @@
             enabled: false,
         },
     },
-    min_sdk_version: "29",
     apex_available: [
         "//apex_available:platform",
-        // TODO(b/166468760) remove these three
         "com.android.media",
         "com.android.media.swcodec",
-        "test_com.android.media.swcodec",
     ],
+    min_sdk_version: "29",
 }
 
 ndk_headers {
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index 988f7f3..259417a 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -220,3 +220,15 @@
     test_suites: ["device-tests"],
     require_root: true,
 }
+
+cc_benchmark {
+    name: "binderParcelBenchmark",
+    defaults: ["binder_test_defaults"],
+    srcs: ["binderParcelBenchmark.cpp"],
+    shared_libs: [
+        "libbase",
+        "libbinder",
+        "liblog",
+        "libutils",
+    ],
+}
diff --git a/libs/binder/tests/binderParcelBenchmark.cpp b/libs/binder/tests/binderParcelBenchmark.cpp
new file mode 100644
index 0000000..ec69c36
--- /dev/null
+++ b/libs/binder/tests/binderParcelBenchmark.cpp
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <binder/Parcel.h>
+#include <benchmark/benchmark.h>
+
+// Usage: atest binderParcelBenchmark
+
+// For static assert(false) we need a template version to avoid early failure.
+// See: https://stackoverflow.com/questions/51523965/template-dependent-false
+template <typename T>
+constexpr bool dependent_false_v = false;
+
+template <template <typename ...> class V, typename T, typename... Args>
+void writeVector(android::Parcel &p, const V<T, Args...> &v) {
+    if constexpr (std::is_same_v<T, bool>) {
+        p.writeBoolVector(v);
+    } else if constexpr (std::is_same_v<T, uint8_t>) {
+        p.writeByteVector(v);
+    } else if constexpr (std::is_same_v<T, char16_t>) {
+        p.writeCharVector(v);
+    } else if constexpr (std::is_same_v<T, int32_t>) {
+        p.writeInt32Vector(v);
+    } else if constexpr (std::is_same_v<T, int64_t>) {
+        p.writeInt64Vector(v);
+    } else {
+        static_assert(dependent_false_v<V<T>>);
+    }
+}
+
+template <template <typename ...> class V, typename T, typename... Args>
+void readVector(android::Parcel &p, V<T, Args...> *v) {
+    if constexpr (std::is_same_v<T, bool>) {
+        p.readBoolVector(v);
+    } else if constexpr (std::is_same_v<T, uint8_t>) {
+        p.readByteVector(v);
+    } else if constexpr (std::is_same_v<T, char16_t>) {
+        p.readCharVector(v);
+    } else if constexpr (std::is_same_v<T, int32_t>) {
+        p.readInt32Vector(v);
+    } else if constexpr (std::is_same_v<T, int64_t>) {
+        p.readInt64Vector(v);
+    } else {
+        static_assert(dependent_false_v<V<T>>);
+    }
+}
+
+// Construct a series of args { 1 << 0, 1 << 1, ..., 1 << 10 }
+static void VectorArgs(benchmark::internal::Benchmark* b) {
+    for (int i = 0; i < 10; ++i) {
+        b->Args({1 << i});
+    }
+}
+
+template <typename T>
+static void BM_ParcelVector(benchmark::State& state) {
+    const size_t elements = state.range(0);
+
+    std::vector<T> v1(elements);
+    std::vector<T> v2(elements);
+    android::Parcel p;
+    while (state.KeepRunning()) {
+        p.setDataPosition(0);
+        writeVector(p, v1);
+
+        p.setDataPosition(0);
+        readVector(p, &v2);
+
+        benchmark::DoNotOptimize(v2[0]);
+        benchmark::ClobberMemory();
+    }
+    state.SetComplexityN(elements);
+}
+
+/*
+  Parcel vector write than read.
+  The read and write vectors are fixed, no resizing required.
+
+  Results on Crosshatch Pixel 3XL
+
+  #BM_BoolVector/1         40 ns      40 ns     17261011
+  #BM_BoolVector/2         46 ns      46 ns     15029619
+  #BM_BoolVector/4         65 ns      64 ns     10888021
+  #BM_BoolVector/8        114 ns     114 ns      6130937
+  #BM_BoolVector/16       179 ns     179 ns      3902462
+  #BM_BoolVector/32       328 ns     327 ns      2138812
+  #BM_BoolVector/64       600 ns     598 ns      1169414
+  #BM_BoolVector/128     1168 ns    1165 ns       601281
+  #BM_BoolVector/256     2288 ns    2281 ns       305737
+  #BM_BoolVector/512     4535 ns    4521 ns       154668
+  #BM_ByteVector/1         53 ns      52 ns     13212196
+  #BM_ByteVector/2         53 ns      53 ns     13194050
+  #BM_ByteVector/4         50 ns      50 ns     13768037
+  #BM_ByteVector/8         50 ns      50 ns     13890210
+  #BM_ByteVector/16        50 ns      50 ns     13897305
+  #BM_ByteVector/32        51 ns      51 ns     13679862
+  #BM_ByteVector/64        54 ns      53 ns     12988544
+  #BM_ByteVector/128       64 ns      64 ns     10921227
+  #BM_ByteVector/256       82 ns      81 ns      8542549
+  #BM_ByteVector/512      118 ns     118 ns      5862931
+  #BM_CharVector/1         32 ns      32 ns     21783579
+  #BM_CharVector/2         38 ns      38 ns     18200971
+  #BM_CharVector/4         53 ns      53 ns     13111785
+  #BM_CharVector/8         80 ns      80 ns      8698331
+  #BM_CharVector/16       159 ns     159 ns      4390738
+  #BM_CharVector/32       263 ns     262 ns      2667310
+  #BM_CharVector/64       486 ns     485 ns      1441118
+  #BM_CharVector/128      937 ns     934 ns       749006
+  #BM_CharVector/256     1848 ns    1843 ns       379537
+  #BM_CharVector/512     3650 ns    3639 ns       191713
+  #BM_Int32Vector/1        31 ns      31 ns     22104147
+  #BM_Int32Vector/2        38 ns      38 ns     18075471
+  #BM_Int32Vector/4        53 ns      52 ns     13249969
+  #BM_Int32Vector/8        80 ns      80 ns      8719798
+  #BM_Int32Vector/16      161 ns     160 ns      4350096
+  #BM_Int32Vector/32      271 ns     270 ns      2591896
+  #BM_Int32Vector/64      499 ns     498 ns      1406201
+  #BM_Int32Vector/128     948 ns     945 ns       740052
+  #BM_Int32Vector/256    1855 ns    1849 ns       379127
+  #BM_Int32Vector/512    3665 ns    3653 ns       191533
+  #BM_Int64Vector/1        31 ns      31 ns     22388370
+  #BM_Int64Vector/2        38 ns      38 ns     18300347
+  #BM_Int64Vector/4        53 ns      53 ns     13137818
+  #BM_Int64Vector/8        81 ns      81 ns      8599613
+  #BM_Int64Vector/16      167 ns     166 ns      4195953
+  #BM_Int64Vector/32      280 ns     280 ns      2499271
+  #BM_Int64Vector/64      523 ns     522 ns      1341380
+  #BM_Int64Vector/128     991 ns     988 ns       707437
+  #BM_Int64Vector/256    1940 ns    1934 ns       361704
+  #BM_Int64Vector/512    3843 ns    3831 ns       183204
+*/
+
+static void BM_BoolVector(benchmark::State& state) {
+    BM_ParcelVector<bool>(state);
+}
+
+static void BM_ByteVector(benchmark::State& state) {
+    BM_ParcelVector<uint8_t>(state);
+}
+
+static void BM_CharVector(benchmark::State& state) {
+    BM_ParcelVector<char16_t>(state);
+}
+
+static void BM_Int32Vector(benchmark::State& state) {
+    BM_ParcelVector<int32_t>(state);
+}
+
+static void BM_Int64Vector(benchmark::State& state) {
+    BM_ParcelVector<int64_t>(state);
+}
+
+BENCHMARK(BM_BoolVector)->Apply(VectorArgs);
+BENCHMARK(BM_ByteVector)->Apply(VectorArgs);
+BENCHMARK(BM_CharVector)->Apply(VectorArgs);
+BENCHMARK(BM_Int32Vector)->Apply(VectorArgs);
+BENCHMARK(BM_Int64Vector)->Apply(VectorArgs);
+
+BENCHMARK_MAIN();
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index c62d9ad..c2ec0fe 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -142,7 +142,7 @@
     mBufferItemConsumer->setFrameAvailableListener(this);
     mBufferItemConsumer->setBufferFreedListener(this);
     mBufferItemConsumer->setDefaultBufferSize(mSize.width, mSize.height);
-    mBufferItemConsumer->setDefaultBufferFormat(format);
+    mBufferItemConsumer->setDefaultBufferFormat(convertBufferFormat(format));
 
     mTransformHint = mSurfaceControl->getTransformHint();
     mBufferItemConsumer->setTransformHint(mTransformHint);
@@ -175,7 +175,7 @@
     std::unique_lock _lock{mMutex};
     if (mFormat != format) {
         mFormat = format;
-        mBufferItemConsumer->setDefaultBufferFormat(format);
+        mBufferItemConsumer->setDefaultBufferFormat(convertBufferFormat(format));
     }
 
     SurfaceComposerClient::Transaction t;
@@ -683,4 +683,18 @@
     *outConsumer = consumer;
 }
 
+PixelFormat BLASTBufferQueue::convertBufferFormat(PixelFormat& format) {
+    PixelFormat convertedFormat = format;
+    switch (format) {
+        case PIXEL_FORMAT_TRANSPARENT:
+        case PIXEL_FORMAT_TRANSLUCENT:
+            convertedFormat = PIXEL_FORMAT_RGBA_8888;
+            break;
+        case PIXEL_FORMAT_OPAQUE:
+            convertedFormat = PIXEL_FORMAT_RGBX_8888;
+            break;
+    }
+    return convertedFormat;
+}
+
 } // namespace android
diff --git a/libs/gui/OWNERS b/libs/gui/OWNERS
index 1667fb0..45c958e 100644
--- a/libs/gui/OWNERS
+++ b/libs/gui/OWNERS
@@ -1,5 +1,4 @@
 adyabr@google.com
-akrulec@google.com
 alecmouri@google.com
 chaviw@google.com
 chrisforbes@google.com
@@ -7,7 +6,6 @@
 lpy@google.com
 mathias@google.com
 racarr@google.com
-stoza@google.com
 vishnun@google.com
 
 per-file EndToEndNativeInputTest.cpp = svv@google.com
diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h
index fa3efe1..bccb71b 100644
--- a/libs/gui/include/gui/BLASTBufferQueue.h
+++ b/libs/gui/include/gui/BLASTBufferQueue.h
@@ -110,6 +110,7 @@
     // Return true if we need to reject the buffer based on the scaling mode and the buffer size.
     bool rejectBuffer(const BufferItem& item) REQUIRES(mMutex);
     bool maxBuffersAcquired(bool includeExtraAcquire) const REQUIRES(mMutex);
+    static PixelFormat convertBufferFormat(PixelFormat& format);
 
     std::string mName;
     sp<SurfaceControl> mSurfaceControl;
diff --git a/libs/renderengine/OWNERS b/libs/renderengine/OWNERS
index b44456b..08cf2de 100644
--- a/libs/renderengine/OWNERS
+++ b/libs/renderengine/OWNERS
@@ -1,4 +1,3 @@
 alecmouri@google.com
 jreck@google.com
 lpy@google.com
-stoza@google.com
diff --git a/libs/ui/OWNERS b/libs/ui/OWNERS
index b1317b1..5110a6c 100644
--- a/libs/ui/OWNERS
+++ b/libs/ui/OWNERS
@@ -4,4 +4,3 @@
 lpy@google.com
 mathias@google.com
 romainguy@google.com
-stoza@google.com
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index 5219787..3615a02 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -282,8 +282,7 @@
             mConsumer->mergeSurfaceDamage(mQueueItems[0].item.mSurfaceDamage);
             mFlinger->mTimeStats->removeTimeRecord(layerId, mQueueItems[0].item.mFrameNumber);
             if (mQueueItems[0].surfaceFrame) {
-                mQueueItems[0].surfaceFrame->setPresentState(PresentState::Dropped);
-                mFlinger->mFrameTimeline->addSurfaceFrame(mQueueItems[0].surfaceFrame);
+                addSurfaceFrameDroppedForBuffer(mQueueItems[0].surfaceFrame);
             }
             mQueueItems.erase(mQueueItems.begin());
             mQueuedFrames--;
@@ -298,8 +297,7 @@
             Mutex::Autolock lock(mQueueItemLock);
             for (auto& [item, surfaceFrame] : mQueueItems) {
                 if (surfaceFrame) {
-                    surfaceFrame->setPresentState(PresentState::Dropped);
-                    mFlinger->mFrameTimeline->addSurfaceFrame(surfaceFrame);
+                    addSurfaceFrameDroppedForBuffer(surfaceFrame);
                 }
             }
             mQueueItems.clear();
@@ -329,8 +327,7 @@
             mConsumer->mergeSurfaceDamage(mQueueItems[0].item.mSurfaceDamage);
             mFlinger->mTimeStats->removeTimeRecord(layerId, mQueueItems[0].item.mFrameNumber);
             if (mQueueItems[0].surfaceFrame) {
-                mQueueItems[0].surfaceFrame->setPresentState(PresentState::Dropped);
-                mFlinger->mFrameTimeline->addSurfaceFrame(mQueueItems[0].surfaceFrame);
+                addSurfaceFrameDroppedForBuffer(mQueueItems[0].surfaceFrame);
             }
             mQueueItems.erase(mQueueItems.begin());
             mQueuedFrames--;
@@ -342,11 +339,9 @@
                                                FrameTracer::FrameEvent::LATCH);
 
         if (mQueueItems[0].surfaceFrame) {
-            mQueueItems[0].surfaceFrame->setAcquireFenceTime(
-                    mQueueItems[0].item.mFenceTime->getSignalTime());
-            mQueueItems[0].surfaceFrame->setPresentState(PresentState::Presented, mLastLatchTime);
-            mFlinger->mFrameTimeline->addSurfaceFrame(mQueueItems[0].surfaceFrame);
-            mLastLatchTime = latchTime;
+            addSurfaceFramePresentedForBuffer(mQueueItems[0].surfaceFrame,
+                                              mQueueItems[0].item.mFenceTime->getSignalTime(),
+                                              latchTime);
         }
         mQueueItems.erase(mQueueItems.begin());
     }
@@ -444,10 +439,7 @@
             }
         }
 
-        auto surfaceFrame =
-                mFlinger->mFrameTimeline->createSurfaceFrameForToken(mFrameTimelineInfo, mOwnerPid,
-                                                                     mOwnerUid, mName, mName);
-        surfaceFrame->setActualQueueTime(systemTime());
+        auto surfaceFrame = createSurfaceFrameForBuffer(mFrameTimelineInfo, systemTime(), mName);
 
         mQueueItems.push_back({item, surfaceFrame});
         mQueuedFrames++;
@@ -483,10 +475,7 @@
             return;
         }
 
-        auto surfaceFrame =
-                mFlinger->mFrameTimeline->createSurfaceFrameForToken(mFrameTimelineInfo, mOwnerPid,
-                                                                     mOwnerUid, mName, mName);
-        surfaceFrame->setActualQueueTime(systemTime());
+        auto surfaceFrame = createSurfaceFrameForBuffer(mFrameTimelineInfo, systemTime(), mName);
         mQueueItems[mQueueItems.size() - 1].item = item;
         mQueueItems[mQueueItems.size() - 1].surfaceFrame = std::move(surfaceFrame);
 
diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h
index 41ff012..0ea02e1 100644
--- a/services/surfaceflinger/BufferQueueLayer.h
+++ b/services/surfaceflinger/BufferQueueLayer.h
@@ -149,11 +149,6 @@
     // a buffer to correlate the buffer with the vsync id. Can only be accessed
     // with the SF state lock held.
     FrameTimelineInfo mFrameTimelineInfo;
-
-    // Keeps track of the time SF latched the last buffer from this layer.
-    // Used in buffer stuffing analysis in FrameTimeline.
-    // TODO(b/176106798): Find a way to do this for BLASTBufferQueue as well.
-    nsecs_t mLastLatchTime = 0;
 };
 
 } // namespace android
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 3dc62e3..e470eb9 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -28,6 +28,7 @@
 
 #include <limits>
 
+#include <FrameTimeline/FrameTimeline.h>
 #include <compositionengine/LayerFECompositionState.h>
 #include <gui/BufferQueue.h>
 #include <private/gui/SyncFeatures.h>
@@ -38,6 +39,7 @@
 
 namespace android {
 
+using PresentState = frametimeline::SurfaceFrame::PresentState;
 // clang-format off
 const std::array<float, 16> BufferStateLayer::IDENTITY_MATRIX{
         1, 0, 0, 0,
@@ -335,7 +337,8 @@
 bool BufferStateLayer::setBuffer(const sp<GraphicBuffer>& buffer, const sp<Fence>& acquireFence,
                                  nsecs_t postTime, nsecs_t desiredPresentTime, bool isAutoTimestamp,
                                  const client_cache_t& clientCacheId, uint64_t frameNumber,
-                                 std::optional<nsecs_t> /* dequeueTime */) {
+                                 std::optional<nsecs_t> /* dequeueTime */,
+                                 const FrameTimelineInfo& info) {
     ATRACE_CALL();
 
     if (mCurrentState.buffer) {
@@ -345,6 +348,10 @@
             // before swapping to drawing state, then the first buffer will be
             // dropped and we should decrement the pending buffer count.
             decrementPendingBufferCount();
+            if (mCurrentState.bufferSurfaceFrameTX != nullptr) {
+                addSurfaceFrameDroppedForBuffer(mCurrentState.bufferSurfaceFrameTX);
+                mCurrentState.bufferSurfaceFrameTX.reset();
+            }
         }
     }
 
@@ -365,6 +372,11 @@
                                              LayerHistory::LayerUpdateType::Buffer);
 
     addFrameEvent(acquireFence, postTime, isAutoTimestamp ? 0 : desiredPresentTime);
+
+    if (info.vsyncId != FrameTimelineInfo::INVALID_VSYNC_ID) {
+        setFrameTimelineVsyncForBufferTransaction(info, postTime);
+    }
+
     return true;
 }
 
@@ -620,6 +632,17 @@
                                           std::make_shared<FenceTime>(mDrawingState.acquireFence));
     mFlinger->mTimeStats->setLatchTime(layerId, mDrawingState.frameNumber, latchTime);
 
+    auto& bufferSurfaceFrame = mDrawingState.bufferSurfaceFrameTX;
+    if (bufferSurfaceFrame != nullptr &&
+        bufferSurfaceFrame->getPresentState() != PresentState::Presented) {
+        // Update only if the bufferSurfaceFrame wasn't already presented. A Presented
+        // bufferSurfaceFrame could be seen here if a pending state was applied successfully and we
+        // are processing the next state.
+        addSurfaceFramePresentedForBuffer(bufferSurfaceFrame,
+                                          mDrawingState.acquireFence->getSignalTime(), latchTime);
+        bufferSurfaceFrame.reset();
+    }
+
     mCurrentStateModified = false;
 
     return NO_ERROR;
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index b93d567..ea832a2 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -72,7 +72,7 @@
     bool setBuffer(const sp<GraphicBuffer>& buffer, const sp<Fence>& acquireFence, nsecs_t postTime,
                    nsecs_t desiredPresentTime, bool isAutoTimestamp,
                    const client_cache_t& clientCacheId, uint64_t frameNumber,
-                   std::optional<nsecs_t> dequeueTime) override;
+                   std::optional<nsecs_t> dequeueTime, const FrameTimelineInfo& info) override;
     bool setAcquireFence(const sp<Fence>& fence) override;
     bool setDataspace(ui::Dataspace dataspace) override;
     bool setHdrMetadata(const HdrMetadata& hdrMetadata) override;
@@ -124,6 +124,8 @@
 
 private:
     friend class SlotGenerationTest;
+    friend class TransactionSurfaceFrameTest;
+
     inline void tracePendingBufferCount();
 
     bool updateFrameEventHistory(const sp<Fence>& acquireFence, nsecs_t postedTime,
diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
index 3743716..3f833f4 100644
--- a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
+++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
@@ -312,6 +312,10 @@
 
 void SurfaceFrame::setPresentState(PresentState presentState, nsecs_t lastLatchTime) {
     std::scoped_lock lock(mMutex);
+    LOG_ALWAYS_FATAL_IF(mPresentState != PresentState::Unknown,
+                        "setPresentState called on a SurfaceFrame from Layer - %s, that has a "
+                        "PresentState - %s set already.",
+                        mDebugName.c_str(), toString(mPresentState).c_str());
     mPresentState = presentState;
     mLastLatchTime = lastLatchTime;
 }
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 08a5f0f..df14003 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -841,13 +841,35 @@
         setTransactionFlags(eTransactionNeeded);
         mFlinger->setTransactionFlags(eTraversalNeeded);
     }
+    if (mCurrentState.bufferlessSurfaceFramesTX.size() >= State::kStateSurfaceFramesThreshold) {
+        // Ideally, the currentState would only contain one SurfaceFrame per transaction (assuming
+        // each Tx uses a different token). We don't expect the current state to hold a huge amount
+        // of SurfaceFrames. However, in the event it happens, this debug statement will leave a
+        // trail that can help in debugging.
+        ALOGW("Bufferless SurfaceFrames size on current state of layer %s is %" PRIu32 "",
+              mName.c_str(), static_cast<uint32_t>(mCurrentState.bufferlessSurfaceFramesTX.size()));
+    }
     mPendingStates.push_back(mCurrentState);
+    // Since the current state along with the SurfaceFrames has been pushed into the pendingState,
+    // we no longer need to retain them. If multiple states are pushed and applied together, we have
+    // a merging logic to address the SurfaceFrames at mergeSurfaceFrames().
+    mCurrentState.bufferlessSurfaceFramesTX.clear();
     ATRACE_INT(mTransactionName.c_str(), mPendingStates.size());
 }
 
+void Layer::mergeSurfaceFrames(State& source, State& target) {
+    // No need to merge BufferSurfaceFrame as the target's surfaceFrame, if it exists, will be used
+    // directly. Dropping of source's SurfaceFrame is taken care of at setBuffer().
+    target.bufferlessSurfaceFramesTX.merge(source.bufferlessSurfaceFramesTX);
+    source.bufferlessSurfaceFramesTX.clear();
+}
+
 void Layer::popPendingState(State* stateToCommit) {
     ATRACE_CALL();
 
+    if (stateToCommit != nullptr) {
+        mergeSurfaceFrames(*stateToCommit, mPendingStates[0]);
+    }
     *stateToCommit = mPendingStates[0];
     mPendingStates.pop_front();
     ATRACE_INT(mTransactionName.c_str(), mPendingStates.size());
@@ -906,20 +928,6 @@
         mFlinger->setTraversalNeeded();
     }
 
-    if (stateUpdateAvailable) {
-        mSurfaceFrame =
-                mFlinger->mFrameTimeline
-                        ->createSurfaceFrameForToken(stateToCommit->frameTimelineInfo, mOwnerPid,
-                                                     mOwnerUid, mName, mTransactionName);
-        mSurfaceFrame->setActualQueueTime(stateToCommit->postTime);
-        // For transactions we set the acquire fence time to the post time as we
-        // don't have a buffer. For BufferStateLayer it is overridden in
-        // BufferStateLayer::applyPendingStates
-        mSurfaceFrame->setAcquireFenceTime(stateToCommit->postTime);
-
-        onSurfaceFrameCreated(mSurfaceFrame);
-    }
-
     mCurrentState.modified = false;
     return stateUpdateAvailable;
 }
@@ -1048,10 +1056,22 @@
     return flags;
 }
 
-void Layer::commitTransaction(const State& stateToCommit) {
+void Layer::commitTransaction(State& stateToCommit) {
     mDrawingState = stateToCommit;
-    mSurfaceFrame->setPresentState(PresentState::Presented);
-    mFlinger->mFrameTimeline->addSurfaceFrame(mSurfaceFrame);
+
+    // Set the present state for all bufferlessSurfaceFramesTX to Presented. The
+    // bufferSurfaceFrameTX will be presented in latchBuffer.
+    for (auto& [token, surfaceFrame] : mDrawingState.bufferlessSurfaceFramesTX) {
+        if (surfaceFrame->getPresentState() != PresentState::Presented) {
+            // With applyPendingStates, we could end up having presented surfaceframes from previous
+            // states
+            surfaceFrame->setPresentState(PresentState::Presented);
+            mFlinger->mFrameTimeline->addSurfaceFrame(surfaceFrame);
+        }
+    }
+    // Clear the surfaceFrames from the old state now that it has been copied into DrawingState.
+    stateToCommit.bufferSurfaceFrameTX.reset();
+    stateToCommit.bufferlessSurfaceFramesTX.clear();
 }
 
 uint32_t Layer::getTransactionFlags(uint32_t flags) {
@@ -1474,11 +1494,94 @@
     return true;
 }
 
-void Layer::setFrameTimelineInfoForTransaction(const FrameTimelineInfo& info, nsecs_t postTime) {
+void Layer::setFrameTimelineVsyncForBufferTransaction(const FrameTimelineInfo& info,
+                                                      nsecs_t postTime) {
+    mCurrentState.postTime = postTime;
+
+    // Check if one of the bufferlessSurfaceFramesTX contains the same vsyncId. This can happen if
+    // there are two transactions with the same token, the first one without a buffer and the
+    // second one with a buffer. We promote the bufferlessSurfaceFrame to a bufferSurfaceFrameTX
+    // in that case.
+    auto it = mCurrentState.bufferlessSurfaceFramesTX.find(info.vsyncId);
+    if (it != mCurrentState.bufferlessSurfaceFramesTX.end()) {
+        // Promote the bufferlessSurfaceFrame to a bufferSurfaceFrameTX
+        mCurrentState.bufferSurfaceFrameTX = it->second;
+        mCurrentState.bufferlessSurfaceFramesTX.erase(it);
+        mCurrentState.bufferSurfaceFrameTX->setActualQueueTime(postTime);
+    } else {
+        mCurrentState.bufferSurfaceFrameTX =
+                createSurfaceFrameForBuffer(info, postTime, mTransactionName);
+    }
+}
+
+void Layer::setFrameTimelineVsyncForBufferlessTransaction(const FrameTimelineInfo& info,
+                                                          nsecs_t postTime) {
     mCurrentState.frameTimelineInfo = info;
     mCurrentState.postTime = postTime;
     mCurrentState.modified = true;
     setTransactionFlags(eTransactionNeeded);
+
+    if (const auto& bufferSurfaceFrameTX = mCurrentState.bufferSurfaceFrameTX;
+        bufferSurfaceFrameTX != nullptr) {
+        if (bufferSurfaceFrameTX->getToken() == info.vsyncId) {
+            // BufferSurfaceFrame takes precedence over BufferlessSurfaceFrame. If the same token is
+            // being used for BufferSurfaceFrame, don't create a new one.
+            return;
+        }
+    }
+    // For Transactions without a buffer, we create only one SurfaceFrame per vsyncId. If multiple
+    // transactions use the same vsyncId, we just treat them as one SurfaceFrame (unless they are
+    // targeting different vsyncs).
+    auto it = mCurrentState.bufferlessSurfaceFramesTX.find(info.vsyncId);
+    if (it == mCurrentState.bufferlessSurfaceFramesTX.end()) {
+        auto surfaceFrame = createSurfaceFrameForTransaction(info, postTime);
+        mCurrentState.bufferlessSurfaceFramesTX[info.vsyncId] = surfaceFrame;
+    } else {
+        if (it->second->getPresentState() == PresentState::Presented) {
+            // If the SurfaceFrame was already presented, its safe to overwrite it since it must
+            // have been from previous vsync.
+            it->second = createSurfaceFrameForTransaction(info, postTime);
+        }
+    }
+}
+
+void Layer::addSurfaceFrameDroppedForBuffer(
+        std::shared_ptr<frametimeline::SurfaceFrame>& surfaceFrame) {
+    surfaceFrame->setPresentState(PresentState::Dropped);
+    mFlinger->mFrameTimeline->addSurfaceFrame(surfaceFrame);
+}
+
+void Layer::addSurfaceFramePresentedForBuffer(
+        std::shared_ptr<frametimeline::SurfaceFrame>& surfaceFrame, nsecs_t acquireFenceTime,
+        nsecs_t currentLatchTime) {
+    surfaceFrame->setAcquireFenceTime(acquireFenceTime);
+    surfaceFrame->setPresentState(PresentState::Presented, mLastLatchTime);
+    mFlinger->mFrameTimeline->addSurfaceFrame(surfaceFrame);
+    mLastLatchTime = currentLatchTime;
+}
+
+std::shared_ptr<frametimeline::SurfaceFrame> Layer::createSurfaceFrameForTransaction(
+        const FrameTimelineInfo& info, nsecs_t postTime) {
+    auto surfaceFrame =
+            mFlinger->mFrameTimeline->createSurfaceFrameForToken(info, mOwnerPid, mOwnerUid, mName,
+                                                                 mTransactionName);
+    // For Transactions, the post time is considered to be both queue and acquire fence time.
+    surfaceFrame->setActualQueueTime(postTime);
+    surfaceFrame->setAcquireFenceTime(postTime);
+    onSurfaceFrameCreated(surfaceFrame);
+    return surfaceFrame;
+}
+
+std::shared_ptr<frametimeline::SurfaceFrame> Layer::createSurfaceFrameForBuffer(
+        const FrameTimelineInfo& info, nsecs_t queueTime, std::string debugName) {
+    auto surfaceFrame =
+            mFlinger->mFrameTimeline->createSurfaceFrameForToken(info, mOwnerPid, mOwnerUid, mName,
+                                                                 debugName);
+    // For buffers, acquire fence time will set during latch.
+    surfaceFrame->setActualQueueTime(queueTime);
+    // TODO(b/178542907): Implement onSurfaceFrameCreated for BQLayer as well.
+    onSurfaceFrameCreated(surfaceFrame);
+    return surfaceFrame;
 }
 
 Layer::FrameRate Layer::getFrameRateForLayerTree() const {
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 3930a81..9cd15e8 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -309,6 +309,20 @@
 
         // When the transaction was posted
         nsecs_t postTime;
+
+        // SurfaceFrame that tracks the timeline of Transactions that contain a Buffer. Only one
+        // such SurfaceFrame exists because only one buffer can be presented on the layer per vsync.
+        // If multiple buffers are queued, the prior ones will be dropped, along with the
+        // SurfaceFrame that's tracking them.
+        std::shared_ptr<frametimeline::SurfaceFrame> bufferSurfaceFrameTX;
+        // A map of token(frametimelineVsyncId) to the SurfaceFrame that's tracking a transaction
+        // that contains the token. Only one SurfaceFrame exisits for transactions that share the
+        // same token, unless they are presented in different vsyncs.
+        std::unordered_map<int64_t, std::shared_ptr<frametimeline::SurfaceFrame>>
+                bufferlessSurfaceFramesTX;
+        // An arbitrary threshold for the number of BufferlessSurfaceFrames in the state. Used to
+        // trigger a warning if the number of SurfaceFrames crosses the threshold.
+        static constexpr uint32_t kStateSurfaceFramesThreshold = 25;
     };
 
     /*
@@ -447,7 +461,8 @@
     virtual bool setBuffer(const sp<GraphicBuffer>& /*buffer*/, const sp<Fence>& /*acquireFence*/,
                            nsecs_t /*postTime*/, nsecs_t /*desiredPresentTime*/,
                            bool /*isAutoTimestamp*/, const client_cache_t& /*clientCacheId*/,
-                           uint64_t /* frameNumber */, std::optional<nsecs_t> /* dequeueTime */) {
+                           uint64_t /* frameNumber */, std::optional<nsecs_t> /* dequeueTime */,
+                           const FrameTimelineInfo& /*info*/) {
         return false;
     };
     virtual bool setAcquireFence(const sp<Fence>& /*fence*/) { return false; };
@@ -611,6 +626,12 @@
 
     virtual void pushPendingState();
 
+    /*
+     * Merges the BufferlessSurfaceFrames from source with the target. If the same token exists in
+     * both source and target, target's SurfaceFrame will be retained.
+     */
+    void mergeSurfaceFrames(State& source, State& target);
+
     /**
      * Returns active buffer size in the correct orientation. Buffer size is determined by undoing
      * any buffer transformations. If the layer has no buffer then return INVALID_RECT.
@@ -866,8 +887,20 @@
     bool setFrameRate(FrameRate);
 
     virtual void setFrameTimelineInfoForBuffer(const FrameTimelineInfo& /*info*/) {}
-    void setFrameTimelineInfoForTransaction(const FrameTimelineInfo& frameTimelineInfo,
-                                            nsecs_t postTime);
+    void setFrameTimelineVsyncForBufferTransaction(const FrameTimelineInfo& info, nsecs_t postTime);
+    void setFrameTimelineVsyncForBufferlessTransaction(const FrameTimelineInfo& info,
+                                                       nsecs_t postTime);
+
+    void addSurfaceFrameDroppedForBuffer(
+            std::shared_ptr<frametimeline::SurfaceFrame>& surfaceFrame);
+    void addSurfaceFramePresentedForBuffer(
+            std::shared_ptr<frametimeline::SurfaceFrame>& surfaceFrame, nsecs_t acquireFenceTime,
+            nsecs_t currentLatchTime);
+
+    std::shared_ptr<frametimeline::SurfaceFrame> createSurfaceFrameForTransaction(
+            const FrameTimelineInfo& info, nsecs_t postTime);
+    std::shared_ptr<frametimeline::SurfaceFrame> createSurfaceFrameForBuffer(
+            const FrameTimelineInfo& info, nsecs_t queueTime, std::string debugName);
 
     // Creates a new handle each time, so we only expect
     // this to be called once.
@@ -971,6 +1004,7 @@
     friend class TestableSurfaceFlinger;
     friend class RefreshRateSelectionTest;
     friend class SetFrameRateTest;
+    friend class TransactionSurfaceFrameTest;
 
     virtual void setInitialValuesForClone(const sp<Layer>& clonedFrom);
     virtual std::optional<compositionengine::LayerFE::LayerSettings> prepareClientComposition(
@@ -979,7 +1013,7 @@
             const LayerFE::LayerSettings&, const Rect& layerStackRect,
             ui::Dataspace outputDataspace);
     virtual void preparePerFrameCompositionState();
-    virtual void commitTransaction(const State& stateToCommit);
+    virtual void commitTransaction(State& stateToCommit);
     virtual bool applyPendingStates(State* stateToCommit);
     virtual uint32_t doTransactionResize(uint32_t flags, Layer::State* stateToCommit);
     virtual void onSurfaceFrameCreated(const std::shared_ptr<frametimeline::SurfaceFrame>&) {}
@@ -1115,6 +1149,10 @@
     // If created from a system process, the value can be passed in.
     pid_t mOwnerPid;
 
+    // Keeps track of the time SF latched the last buffer from this layer.
+    // Used in buffer stuffing analysis in FrameTimeline.
+    nsecs_t mLastLatchTime = 0;
+
 private:
     virtual void setTransformHint(ui::Transform::RotationFlags) {}
 
diff --git a/services/surfaceflinger/OWNERS b/services/surfaceflinger/OWNERS
index f273725..43a6e55 100644
--- a/services/surfaceflinger/OWNERS
+++ b/services/surfaceflinger/OWNERS
@@ -1,8 +1,6 @@
 adyabr@google.com
-akrulec@google.com
 alecmouri@google.com
 chaviw@google.com
 lpy@google.com
 racarr@google.com
-stoza@google.com
 vishnun@google.com
diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp
index 9230e72..49ffc81 100644
--- a/services/surfaceflinger/RefreshRateOverlay.cpp
+++ b/services/surfaceflinger/RefreshRateOverlay.cpp
@@ -238,7 +238,7 @@
     auto buffer = getOrCreateBuffers(*mCurrentFps)[mFrame];
     mLayer->setBuffer(buffer, Fence::NO_FENCE, 0, 0, true, {},
                       mLayer->getHeadFrameNumber(-1 /* expectedPresentTime */),
-                      std::nullopt /* dequeueTime */);
+                      std::nullopt /* dequeueTime */, FrameTimelineInfo{});
 
     mFlinger.mTransactionFlags.fetch_or(eTransactionMask);
 }
@@ -251,7 +251,7 @@
     auto buffer = buffers[mFrame];
     mLayer->setBuffer(buffer, Fence::NO_FENCE, 0, 0, true, {},
                       mLayer->getHeadFrameNumber(-1 /* expectedPresentTime */),
-                      std::nullopt /* dequeueTime */);
+                      std::nullopt /* dequeueTime */, FrameTimelineInfo{});
 
     mFlinger.mTransactionFlags.fetch_or(eTransactionMask);
 }
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index cf7d1e1..689a302 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -3939,10 +3939,11 @@
             flags |= eTraversalNeeded;
         }
     }
+    FrameTimelineInfo info;
     if (what & layer_state_t::eFrameTimelineInfoChanged) {
-        layer->setFrameTimelineInfoForTransaction(s.frameTimelineInfo, postTime);
+        info = s.frameTimelineInfo;
     } else if (frameTimelineInfo.vsyncId != FrameTimelineInfo::INVALID_VSYNC_ID) {
-        layer->setFrameTimelineInfoForTransaction(frameTimelineInfo, postTime);
+        info = frameTimelineInfo;
     }
     if (what & layer_state_t::eFixedTransformHintChanged) {
         if (layer->setFixedTransformHint(s.fixedTransformHint)) {
@@ -4001,9 +4002,11 @@
                 : layer->getHeadFrameNumber(-1 /* expectedPresentTime */) + 1;
 
         if (layer->setBuffer(buffer, s.acquireFence, postTime, desiredPresentTime, isAutoTimestamp,
-                             s.cachedBuffer, frameNumber, dequeueBufferTimestamp)) {
+                             s.cachedBuffer, frameNumber, dequeueBufferTimestamp, info)) {
             flags |= eTraversalNeeded;
         }
+    } else if (info.vsyncId != FrameTimelineInfo::INVALID_VSYNC_ID) {
+        layer->setFrameTimelineVsyncForBufferlessTransaction(info, postTime);
     }
 
     if (layer->setTransactionCompletedListeners(callbackHandles)) flags |= eTraversalNeeded;
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index 9b29b70..17928a0 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -73,6 +73,7 @@
         "FrameTracerTest.cpp",
         "TimerTest.cpp",
         "TransactionApplicationTest.cpp",
+        "TransactionSurfaceFrameTest.cpp",
         "StrongTypingTest.cpp",
         "VSyncDispatchTimerQueueTest.cpp",
         "VSyncDispatchRealtimeTest.cpp",
diff --git a/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp b/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp
new file mode 100644
index 0000000..aa6798d
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp
@@ -0,0 +1,367 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "LibSurfaceFlingerUnittests"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <gui/SurfaceComposerClient.h>
+#include <log/log.h>
+#include <utils/String8.h>
+
+#include "TestableSurfaceFlinger.h"
+#include "mock/DisplayHardware/MockComposer.h"
+#include "mock/MockEventThread.h"
+#include "mock/MockVsyncController.h"
+
+namespace android {
+
+using testing::_;
+using testing::Mock;
+using testing::Return;
+using FakeHwcDisplayInjector = TestableSurfaceFlinger::FakeHwcDisplayInjector;
+using PresentState = frametimeline::SurfaceFrame::PresentState;
+
+class TransactionSurfaceFrameTest : public testing::Test {
+public:
+    TransactionSurfaceFrameTest() {
+        const ::testing::TestInfo* const test_info =
+                ::testing::UnitTest::GetInstance()->current_test_info();
+        ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
+        setupScheduler();
+        setupComposer(0);
+    }
+
+    ~TransactionSurfaceFrameTest() {
+        const ::testing::TestInfo* const test_info =
+                ::testing::UnitTest::GetInstance()->current_test_info();
+        ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
+    }
+
+    sp<BufferStateLayer> createBufferStateLayer() {
+        sp<Client> client;
+        LayerCreationArgs args(mFlinger.flinger(), client, "buffer-state-layer", 100, 100, 0,
+                               LayerMetadata());
+        return new BufferStateLayer(args);
+    }
+
+    void commitTransaction(Layer* layer) {
+        layer->pushPendingState();
+        // After pushing the state, the currentState should not store any BufferlessSurfaceFrames
+        EXPECT_EQ(0u, layer->mCurrentState.bufferlessSurfaceFramesTX.size());
+        auto c = layer->getCurrentState();
+        if (layer->applyPendingStates(&c)) {
+            layer->commitTransaction(c);
+        }
+    }
+
+    void setupScheduler() {
+        auto eventThread = std::make_unique<mock::EventThread>();
+        auto sfEventThread = std::make_unique<mock::EventThread>();
+
+        EXPECT_CALL(*eventThread, registerDisplayEventConnection(_));
+        EXPECT_CALL(*eventThread, createEventConnection(_, _))
+                .WillOnce(Return(new EventThreadConnection(eventThread.get(), /*callingUid=*/0,
+                                                           ResyncCallback())));
+
+        EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_));
+        EXPECT_CALL(*sfEventThread, createEventConnection(_, _))
+                .WillOnce(Return(new EventThreadConnection(sfEventThread.get(), /*callingUid=*/0,
+                                                           ResyncCallback())));
+
+        auto vsyncController = std::make_unique<mock::VsyncController>();
+        auto vsyncTracker = std::make_unique<mock::VSyncTracker>();
+
+        EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0));
+        EXPECT_CALL(*vsyncTracker, currentPeriod())
+                .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD));
+        EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0));
+        mFlinger.setupScheduler(std::move(vsyncController), std::move(vsyncTracker),
+                                std::move(eventThread), std::move(sfEventThread));
+    }
+
+    void setupComposer(uint32_t virtualDisplayCount) {
+        mComposer = new Hwc2::mock::Composer();
+        EXPECT_CALL(*mComposer, getMaxVirtualDisplayCount()).WillOnce(Return(virtualDisplayCount));
+        mFlinger.setupComposer(std::unique_ptr<Hwc2::Composer>(mComposer));
+
+        Mock::VerifyAndClear(mComposer);
+    }
+
+    TestableSurfaceFlinger mFlinger;
+    Hwc2::mock::Composer* mComposer = nullptr;
+    FenceToFenceTimeMap fenceFactory;
+    client_cache_t mClientCache;
+
+    void PresentedSurfaceFrameForBufferlessTransaction() {
+        sp<BufferStateLayer> layer = createBufferStateLayer();
+        layer->setFrameTimelineVsyncForBufferlessTransaction({/*vsyncId*/ 1, /*inputEventId*/ 0},
+                                                             10);
+        EXPECT_EQ(1u, layer->mCurrentState.bufferlessSurfaceFramesTX.size());
+        ASSERT_TRUE(layer->mCurrentState.bufferSurfaceFrameTX == nullptr);
+        const auto surfaceFrame = layer->mCurrentState.bufferlessSurfaceFramesTX.at(/*token*/ 1);
+        commitTransaction(layer.get());
+        EXPECT_EQ(1, surfaceFrame->getToken());
+        EXPECT_EQ(PresentState::Presented, surfaceFrame->getPresentState());
+    }
+
+    void PresentedSurfaceFrameForBufferTransaction() {
+        sp<BufferStateLayer> layer = createBufferStateLayer();
+        sp<Fence> fence(new Fence());
+        auto acquireFence = fenceFactory.createFenceTimeForTest(fence);
+        sp<GraphicBuffer> buffer{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)};
+        layer->setBuffer(buffer, fence, 10, 20, false, mClientCache, 1, std::nullopt,
+                         {/*vsyncId*/ 1, /*inputEventId*/ 0});
+        acquireFence->signalForTest(12);
+
+        commitTransaction(layer.get());
+        EXPECT_EQ(0u, layer->mCurrentState.bufferlessSurfaceFramesTX.size());
+        ASSERT_NE(nullptr, layer->mCurrentState.bufferSurfaceFrameTX);
+        const auto& surfaceFrame = layer->mCurrentState.bufferSurfaceFrameTX;
+        // Buffers are presented only at latch time.
+        EXPECT_EQ(PresentState::Unknown, surfaceFrame->getPresentState());
+
+        bool computeVisisbleRegions;
+        layer->updateTexImage(computeVisisbleRegions, 15, 0);
+
+        EXPECT_EQ(1, surfaceFrame->getToken());
+        EXPECT_EQ(PresentState::Presented, surfaceFrame->getPresentState());
+    }
+
+    void DroppedSurfaceFrameForBufferTransaction() {
+        sp<BufferStateLayer> layer = createBufferStateLayer();
+
+        sp<Fence> fence1(new Fence());
+        auto acquireFence1 = fenceFactory.createFenceTimeForTest(fence1);
+        sp<GraphicBuffer> buffer1{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)};
+        layer->setBuffer(buffer1, fence1, 10, 20, false, mClientCache, 1, std::nullopt,
+                         {/*vsyncId*/ 1, /*inputEventId*/ 0});
+        EXPECT_EQ(0u, layer->mCurrentState.bufferlessSurfaceFramesTX.size());
+        ASSERT_NE(nullptr, layer->mCurrentState.bufferSurfaceFrameTX);
+        const auto droppedSurfaceFrame = layer->mCurrentState.bufferSurfaceFrameTX;
+
+        sp<Fence> fence2(new Fence());
+        auto acquireFence2 = fenceFactory.createFenceTimeForTest(fence2);
+        sp<GraphicBuffer> buffer2{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)};
+        layer->setBuffer(buffer2, fence2, 10, 20, false, mClientCache, 1, std::nullopt,
+                         {/*vsyncId*/ 1, /*inputEventId*/ 0});
+        acquireFence2->signalForTest(12);
+
+        EXPECT_EQ(0u, layer->mCurrentState.bufferlessSurfaceFramesTX.size());
+        ASSERT_NE(nullptr, layer->mCurrentState.bufferSurfaceFrameTX);
+        const auto& presentedSurfaceFrame = layer->mCurrentState.bufferSurfaceFrameTX;
+
+        commitTransaction(layer.get());
+        bool computeVisisbleRegions;
+        layer->updateTexImage(computeVisisbleRegions, 15, 0);
+
+        EXPECT_EQ(1, droppedSurfaceFrame->getToken());
+        EXPECT_EQ(PresentState::Dropped, droppedSurfaceFrame->getPresentState());
+
+        EXPECT_EQ(1, presentedSurfaceFrame->getToken());
+        EXPECT_EQ(PresentState::Presented, presentedSurfaceFrame->getPresentState());
+    }
+
+    void BufferlessSurfaceFramePromotedToBufferSurfaceFrame() {
+        sp<BufferStateLayer> layer = createBufferStateLayer();
+
+        layer->setFrameTimelineVsyncForBufferlessTransaction({/*vsyncId*/ 1, /*inputEventId*/ 0},
+                                                             10);
+
+        EXPECT_EQ(1u, layer->mCurrentState.bufferlessSurfaceFramesTX.size());
+        ASSERT_EQ(nullptr, layer->mCurrentState.bufferSurfaceFrameTX);
+
+        sp<Fence> fence(new Fence());
+        auto acquireFence = fenceFactory.createFenceTimeForTest(fence);
+        sp<GraphicBuffer> buffer{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)};
+
+        layer->setBuffer(buffer, fence, 10, 20, false, mClientCache, 1, std::nullopt,
+                         {/*vsyncId*/ 1, /*inputEventId*/ 0});
+        acquireFence->signalForTest(12);
+
+        EXPECT_EQ(0u, layer->mCurrentState.bufferlessSurfaceFramesTX.size());
+        ASSERT_NE(nullptr, layer->mCurrentState.bufferSurfaceFrameTX);
+        const auto& surfaceFrame = layer->mCurrentState.bufferSurfaceFrameTX;
+
+        commitTransaction(layer.get());
+        EXPECT_EQ(1, surfaceFrame->getToken());
+        // Buffers are presented only at latch time.
+        EXPECT_EQ(PresentState::Unknown, surfaceFrame->getPresentState());
+
+        bool computeVisisbleRegions;
+        layer->updateTexImage(computeVisisbleRegions, 15, 0);
+
+        EXPECT_EQ(PresentState::Presented, surfaceFrame->getPresentState());
+    }
+
+    void BufferlessSurfaceFrameNotCreatedIfBufferSufaceFrameExists() {
+        sp<BufferStateLayer> layer = createBufferStateLayer();
+        sp<Fence> fence(new Fence());
+        auto acquireFence = fenceFactory.createFenceTimeForTest(fence);
+        sp<GraphicBuffer> buffer{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)};
+
+        layer->setBuffer(buffer, fence, 10, 20, false, mClientCache, 1, std::nullopt,
+                         {/*vsyncId*/ 1, /*inputEventId*/ 0});
+        EXPECT_EQ(0u, layer->mCurrentState.bufferlessSurfaceFramesTX.size());
+        ASSERT_NE(nullptr, layer->mCurrentState.bufferSurfaceFrameTX);
+
+        layer->setFrameTimelineVsyncForBufferlessTransaction({/*vsyncId*/ 1, /*inputEventId*/ 0},
+                                                             10);
+        EXPECT_EQ(0u, layer->mCurrentState.bufferlessSurfaceFramesTX.size());
+        ASSERT_NE(nullptr, layer->mCurrentState.bufferSurfaceFrameTX);
+    }
+
+    void MultipleSurfaceFramesPresentedTogether() {
+        sp<BufferStateLayer> layer = createBufferStateLayer();
+        layer->setFrameTimelineVsyncForBufferlessTransaction({/*vsyncId*/ 1, /*inputEventId*/ 0},
+                                                             10);
+        EXPECT_EQ(1u, layer->mCurrentState.bufferlessSurfaceFramesTX.size());
+        ASSERT_EQ(nullptr, layer->mCurrentState.bufferSurfaceFrameTX);
+        const auto bufferlessSurfaceFrame1 =
+                layer->mCurrentState.bufferlessSurfaceFramesTX.at(/*token*/ 1);
+
+        layer->setFrameTimelineVsyncForBufferlessTransaction({/*vsyncId*/ 4, /*inputEventId*/ 0},
+                                                             10);
+        EXPECT_EQ(2u, layer->mCurrentState.bufferlessSurfaceFramesTX.size());
+        ASSERT_EQ(nullptr, layer->mCurrentState.bufferSurfaceFrameTX);
+        const auto bufferlessSurfaceFrame2 = layer->mCurrentState.bufferlessSurfaceFramesTX[4];
+
+        sp<Fence> fence(new Fence());
+        auto acquireFence = fenceFactory.createFenceTimeForTest(fence);
+        sp<GraphicBuffer> buffer{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)};
+
+        layer->setBuffer(buffer, fence, 10, 20, false, mClientCache, 1, std::nullopt,
+                         {/*vsyncId*/ 3, /*inputEventId*/ 0});
+        EXPECT_EQ(2u, layer->mCurrentState.bufferlessSurfaceFramesTX.size());
+        ASSERT_NE(nullptr, layer->mCurrentState.bufferSurfaceFrameTX);
+        const auto& bufferSurfaceFrameTX = layer->mCurrentState.bufferSurfaceFrameTX;
+
+        acquireFence->signalForTest(12);
+
+        commitTransaction(layer.get());
+
+        EXPECT_EQ(1, bufferlessSurfaceFrame1->getToken());
+        EXPECT_EQ(PresentState::Presented, bufferlessSurfaceFrame1->getPresentState());
+
+        EXPECT_EQ(4, bufferlessSurfaceFrame2->getToken());
+        EXPECT_EQ(PresentState::Presented, bufferlessSurfaceFrame2->getPresentState());
+
+        EXPECT_EQ(3, bufferSurfaceFrameTX->getToken());
+        // Buffers are presented only at latch time.
+        EXPECT_EQ(PresentState::Unknown, bufferSurfaceFrameTX->getPresentState());
+
+        bool computeVisisbleRegions;
+        layer->updateTexImage(computeVisisbleRegions, 15, 0);
+
+        EXPECT_EQ(PresentState::Presented, bufferSurfaceFrameTX->getPresentState());
+    }
+
+    void MergePendingStates_BufferlessSurfaceFramesWithoutOverlappingToken() {
+        sp<BufferStateLayer> layer = createBufferStateLayer();
+        layer->setFrameTimelineVsyncForBufferlessTransaction({/*vsyncId*/ 1, /*inputEventId*/ 0},
+                                                             10);
+        EXPECT_EQ(1u, layer->mCurrentState.bufferlessSurfaceFramesTX.size());
+        ASSERT_EQ(nullptr, layer->mCurrentState.bufferSurfaceFrameTX);
+        const auto bufferlessSurfaceFrame1 =
+                layer->mCurrentState.bufferlessSurfaceFramesTX.at(/*token*/ 1);
+
+        layer->pushPendingState();
+        EXPECT_EQ(0u, layer->mCurrentState.bufferlessSurfaceFramesTX.size());
+
+        layer->setFrameTimelineVsyncForBufferlessTransaction({/*vsyncId*/ 2, /*inputEventId*/ 0},
+                                                             12);
+        EXPECT_EQ(1u, layer->mCurrentState.bufferlessSurfaceFramesTX.size());
+        ASSERT_EQ(nullptr, layer->mCurrentState.bufferSurfaceFrameTX);
+        const auto bufferlessSurfaceFrame2 =
+                layer->mCurrentState.bufferlessSurfaceFramesTX.at(/*token*/ 2);
+
+        commitTransaction(layer.get());
+
+        EXPECT_EQ(1, bufferlessSurfaceFrame1->getToken());
+        EXPECT_EQ(PresentState::Presented, bufferlessSurfaceFrame1->getPresentState());
+        EXPECT_EQ(10, bufferlessSurfaceFrame1->getActuals().endTime);
+
+        EXPECT_EQ(2, bufferlessSurfaceFrame2->getToken());
+        EXPECT_EQ(PresentState::Presented, bufferlessSurfaceFrame2->getPresentState());
+        EXPECT_EQ(12, bufferlessSurfaceFrame2->getActuals().endTime);
+    }
+
+    void MergePendingStates_BufferlessSurfaceFramesWithOverlappingToken() {
+        sp<BufferStateLayer> layer = createBufferStateLayer();
+        layer->setFrameTimelineVsyncForBufferlessTransaction({/*vsyncId*/ 1, /*inputEventId*/ 0},
+                                                             10);
+        EXPECT_EQ(1u, layer->mCurrentState.bufferlessSurfaceFramesTX.size());
+        ASSERT_EQ(nullptr, layer->mCurrentState.bufferSurfaceFrameTX);
+        const auto bufferlessSurfaceFrame1 =
+                layer->mCurrentState.bufferlessSurfaceFramesTX.at(/*token*/ 1);
+
+        layer->pushPendingState();
+        EXPECT_EQ(0u, layer->mCurrentState.bufferlessSurfaceFramesTX.size());
+
+        layer->setFrameTimelineVsyncForBufferlessTransaction({/*vsyncId*/ 1, /*inputEventId*/ 0},
+                                                             12);
+        EXPECT_EQ(1u, layer->mCurrentState.bufferlessSurfaceFramesTX.size());
+        ASSERT_EQ(nullptr, layer->mCurrentState.bufferSurfaceFrameTX);
+        const auto bufferlessSurfaceFrame2 =
+                layer->mCurrentState.bufferlessSurfaceFramesTX.at(/*token*/ 1);
+
+        commitTransaction(layer.get());
+
+        EXPECT_EQ(1, bufferlessSurfaceFrame1->getToken());
+        EXPECT_EQ(PresentState::Unknown, bufferlessSurfaceFrame1->getPresentState());
+
+        EXPECT_EQ(1, bufferlessSurfaceFrame2->getToken());
+        EXPECT_EQ(PresentState::Presented, bufferlessSurfaceFrame2->getPresentState());
+        EXPECT_EQ(12, bufferlessSurfaceFrame2->getActuals().endTime);
+    }
+};
+
+TEST_F(TransactionSurfaceFrameTest, PresentedBufferlessSurfaceFrame) {
+    PresentedSurfaceFrameForBufferlessTransaction();
+}
+
+TEST_F(TransactionSurfaceFrameTest, PresentedBufferSurfaceFrame) {
+    PresentedSurfaceFrameForBufferTransaction();
+}
+
+TEST_F(TransactionSurfaceFrameTest, DroppedBufferSurfaceFrame) {
+    DroppedSurfaceFrameForBufferTransaction();
+}
+
+TEST_F(TransactionSurfaceFrameTest, BufferlessSurfaceFramePromotedToBufferSurfaceFrame) {
+    BufferlessSurfaceFramePromotedToBufferSurfaceFrame();
+}
+
+TEST_F(TransactionSurfaceFrameTest, BufferlessSurfaceFrameNotCreatedIfBufferSufaceFrameExists) {
+    BufferlessSurfaceFrameNotCreatedIfBufferSufaceFrameExists();
+}
+
+TEST_F(TransactionSurfaceFrameTest, MultipleSurfaceFramesPresentedTogether) {
+    MultipleSurfaceFramesPresentedTogether();
+}
+
+TEST_F(TransactionSurfaceFrameTest,
+       MergePendingStates_BufferlessSurfaceFramesWithoutOverlappingToken) {
+    MergePendingStates_BufferlessSurfaceFramesWithoutOverlappingToken();
+}
+
+TEST_F(TransactionSurfaceFrameTest,
+       MergePendingStates_BufferlessSurfaceFramesWithOverlappingToken) {
+    MergePendingStates_BufferlessSurfaceFramesWithOverlappingToken();
+}
+
+} // namespace android
\ No newline at end of file