SF: Track starting layer state with transaction tracing

In order to recreate the layer state from transaction traces,
we need to know the starting layer state. We need to start
with an initial state, then replay the transactions from the
trace to recreate the layer states.

Keeping track of the initial layer state while maintaining
a ring buffer of transactions is expensive since it would
require accessing the drawing state from the tracing
thread.

This cl builds and updates a transaction that will
recreate the layer's starting state. As transactions are
evicted from the ring buffer, they are used to update
the starting state transactions.

Test: presubmit
Bug: 200284593
Change-Id: Ifaba8fb061fca4acc15df661483217552011aa09
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 7a8968b..522ae44 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -4355,6 +4355,16 @@
         return result;
     }
 
+    int parentId = -1;
+    // We can safely promote the layer in binder thread because we have a strong reference
+    // to the layer's handle inside this scope or we were passed in a sp reference to the layer.
+    sp<Layer> parentSp = parent.promote();
+    if (parentSp != nullptr) {
+        parentId = parentSp->getSequence();
+    }
+    mTransactionTracing.onLayerAdded((*outHandle)->localBinder(), layer->sequence, args.name,
+                                     args.flags, parentId);
+
     setTransactionFlags(eTransactionNeeded);
     *outLayerId = layer->sequence;
     return result;
@@ -6592,6 +6602,7 @@
     if (!layer->isRemovedFromCurrentState()) {
         mScheduler->deregisterLayer(layer);
     }
+    mTransactionTracing.onLayerRemoved(layer->getSequence());
 }
 
 void SurfaceFlinger::onLayerUpdate() {
diff --git a/services/surfaceflinger/Tracing/LayerTracing.cpp b/services/surfaceflinger/Tracing/LayerTracing.cpp
index 84890ee..d136e0b 100644
--- a/services/surfaceflinger/Tracing/LayerTracing.cpp
+++ b/services/surfaceflinger/Tracing/LayerTracing.cpp
@@ -53,6 +53,7 @@
     mEnabled = false;
     LayersTraceFileProto fileProto = createTraceFileProto();
     mBuffer->writeToFile(fileProto, FILE_NAME);
+    mBuffer->reset();
     return true;
 }
 
diff --git a/services/surfaceflinger/Tracing/RingBuffer.h b/services/surfaceflinger/Tracing/RingBuffer.h
index 63a2786..281cd19 100644
--- a/services/surfaceflinger/Tracing/RingBuffer.h
+++ b/services/surfaceflinger/Tracing/RingBuffer.h
@@ -39,26 +39,28 @@
     void setSize(size_t newSize) { mSizeInBytes = newSize; }
     EntryProto& front() { return mStorage.front(); }
     const EntryProto& front() const { return mStorage.front(); }
+    const EntryProto& back() const { return mStorage.back(); }
 
-    void reset(size_t newSize) {
+    void reset() {
         // use the swap trick to make sure memory is released
-        std::queue<EntryProto>().swap(mStorage);
-        mSizeInBytes = newSize;
+        std::deque<EntryProto>().swap(mStorage);
         mUsedInBytes = 0U;
     }
-    void flush(FileProto& fileProto) {
-        fileProto.mutable_entry()->Reserve(static_cast<int>(mStorage.size()));
-        while (!mStorage.empty()) {
-            auto entry = fileProto.add_entry();
-            entry->Swap(&mStorage.front());
-            mStorage.pop();
+
+    void writeToProto(FileProto& fileProto) {
+        fileProto.mutable_entry()->Reserve(static_cast<int>(mStorage.size()) +
+                                           fileProto.entry().size());
+        for (const EntryProto& entry : mStorage) {
+            EntryProto* entryProto = fileProto.add_entry();
+            *entryProto = entry;
         }
     }
 
     status_t writeToFile(FileProto& fileProto, std::string filename) {
         ATRACE_CALL();
+        writeToProto(fileProto);
         std::string output;
-        if (!writeToString(fileProto, &output)) {
+        if (!fileProto.SerializeToString(&output)) {
             ALOGE("Could not serialize proto.");
             return UNKNOWN_ERROR;
         }
@@ -72,13 +74,6 @@
         return NO_ERROR;
     }
 
-    bool writeToString(FileProto& fileProto, std::string* outString) {
-        ATRACE_CALL();
-        flush(fileProto);
-        reset(mSizeInBytes);
-        return fileProto.SerializeToString(outString);
-    }
-
     std::vector<EntryProto> emplace(EntryProto&& proto) {
         std::vector<EntryProto> replacedEntries;
         size_t protoSize = static_cast<size_t>(proto.ByteSize());
@@ -88,10 +83,10 @@
             }
             mUsedInBytes -= static_cast<size_t>(mStorage.front().ByteSize());
             replacedEntries.emplace_back(mStorage.front());
-            mStorage.pop();
+            mStorage.pop_front();
         }
         mUsedInBytes += protoSize;
-        mStorage.emplace();
+        mStorage.emplace_back();
         mStorage.back().Swap(&proto);
         return replacedEntries;
     }
@@ -112,7 +107,7 @@
 private:
     size_t mUsedInBytes = 0U;
     size_t mSizeInBytes = 0U;
-    std::queue<EntryProto> mStorage;
+    std::deque<EntryProto> mStorage;
 };
 
 } // namespace android
diff --git a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
index d1dc076..7e12313 100644
--- a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
+++ b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
@@ -43,7 +43,7 @@
 }
 
 proto::TransactionState TransactionProtoParser::toProto(
-        std::vector<std::pair<int32_t /* layerId */, TracingLayerState>> states) {
+        const std::unordered_map<int32_t /* layerId */, TracingLayerState> states) {
     proto::TransactionState proto;
     for (auto& [layerId, state] : states) {
         proto::LayerState layerProto = toProto(state, nullptr);
diff --git a/services/surfaceflinger/Tracing/TransactionProtoParser.h b/services/surfaceflinger/Tracing/TransactionProtoParser.h
index e8a139f..619ee05 100644
--- a/services/surfaceflinger/Tracing/TransactionProtoParser.h
+++ b/services/surfaceflinger/Tracing/TransactionProtoParser.h
@@ -51,7 +51,7 @@
     static proto::TransactionState toProto(const TransactionState&, LayerHandleToIdFn getLayerIdFn,
                                            DisplayHandleToIdFn getDisplayIdFn);
     static proto::TransactionState toProto(
-            std::vector<std::pair<int32_t /* layerId */, TracingLayerState>>);
+            const std::unordered_map<int32_t /* layerId */, TracingLayerState>);
 
     static proto::LayerCreationArgs toProto(const TracingLayerCreationArgs& args);
 
diff --git a/services/surfaceflinger/Tracing/TransactionTracing.cpp b/services/surfaceflinger/Tracing/TransactionTracing.cpp
index 758bd31..cf488c2 100644
--- a/services/surfaceflinger/Tracing/TransactionTracing.cpp
+++ b/services/surfaceflinger/Tracing/TransactionTracing.cpp
@@ -41,6 +41,7 @@
         return false;
     }
     mBuffer->setSize(mBufferSizeInBytes);
+    mStartingTimestamp = systemTime();
     mEnabled = true;
     {
         std::scoped_lock lock(mMainThreadLock);
@@ -68,9 +69,11 @@
     }
     mEnabled = false;
 
-    proto::TransactionTraceFile fileProto = createTraceFileProto();
-    mBuffer->writeToFile(fileProto, FILE_NAME);
+    writeToFileLocked();
+    mBuffer->reset();
     mQueuedTransactions.clear();
+    mStartingStates.clear();
+    mLayerHandles.clear();
     return true;
 }
 
@@ -84,7 +87,12 @@
     if (!mEnabled) {
         return STATUS_OK;
     }
+    return writeToFileLocked();
+}
+
+status_t TransactionTracing::writeToFileLocked() {
     proto::TransactionTraceFile fileProto = createTraceFileProto();
+    addStartingStateToProtoLocked(fileProto);
     return mBuffer->writeToFile(fileProto, FILE_NAME);
 }
 
@@ -105,8 +113,10 @@
     std::scoped_lock lock(mTraceLock);
     base::StringAppendF(&result, "Transaction tracing state: %s\n",
                         mEnabled ? "enabled" : "disabled");
-    base::StringAppendF(&result, "  queued transactions: %d\n",
-                        static_cast<uint32_t>(mQueuedTransactions.size()));
+    base::StringAppendF(&result,
+                        "  queued transactions=%zu created layers=%zu handles=%zu states=%zu\n",
+                        mQueuedTransactions.size(), mCreatedLayers.size(), mLayerHandles.size(),
+                        mStartingStates.size());
     mBuffer->dump(result);
 }
 
@@ -117,7 +127,10 @@
         return;
     }
     mQueuedTransactions[transaction.id] =
-            TransactionProtoParser::toProto(transaction, nullptr, nullptr);
+            TransactionProtoParser::toProto(transaction,
+                                            std::bind(&TransactionTracing::getLayerIdLocked, this,
+                                                      std::placeholders::_1),
+                                            nullptr);
 }
 
 void TransactionTracing::addCommittedTransactions(std::vector<TransactionState>& transactions,
@@ -130,25 +143,14 @@
         committedTransactions.transactionIds.emplace_back(transaction.id);
     }
 
-    // Try to acquire the lock from main thread, but don't block if we cannot acquire the lock. Add
-    // it to pending transactions that we can collect later.
-    if (mMainThreadLock.try_lock()) {
-        // We got the lock! Collect any pending transactions and continue.
-        mCommittedTransactions.insert(mCommittedTransactions.end(),
-                                      std::make_move_iterator(mPendingTransactions.begin()),
-                                      std::make_move_iterator(mPendingTransactions.end()));
-        mPendingTransactions.clear();
-        mCommittedTransactions.emplace_back(committedTransactions);
-        mTransactionsAvailableCv.notify_one();
-        mMainThreadLock.unlock();
-    } else {
-        mPendingTransactions.emplace_back(committedTransactions);
-    }
+    mPendingTransactions.emplace_back(committedTransactions);
+    tryPushToTracingThread();
 }
 
 void TransactionTracing::loop() {
     while (true) {
         std::vector<CommittedTransactions> committedTransactions;
+        std::vector<int32_t> removedLayers;
         {
             std::unique_lock<std::mutex> lock(mMainThreadLock);
             base::ScopedLockAssertion assumeLocked(mMainThreadLock);
@@ -157,19 +159,22 @@
             });
             if (mDone) {
                 mCommittedTransactions.clear();
+                mRemovedLayers.clear();
                 break;
             }
+
+            removedLayers = std::move(mRemovedLayers);
+            mRemovedLayers.clear();
             committedTransactions = std::move(mCommittedTransactions);
             mCommittedTransactions.clear();
         } // unlock mMainThreadLock
 
-        addEntry(committedTransactions);
-
-        mTransactionsAddedToBufferCv.notify_one();
+        addEntry(committedTransactions, removedLayers);
     }
 }
 
-void TransactionTracing::addEntry(const std::vector<CommittedTransactions>& committedTransactions) {
+void TransactionTracing::addEntry(const std::vector<CommittedTransactions>& committedTransactions,
+                                  const std::vector<int32_t>& removedLayers) {
     ATRACE_CALL();
     std::scoped_lock lock(mTraceLock);
     std::vector<proto::TransactionTraceEntry> removedEntries;
@@ -177,6 +182,15 @@
         proto::TransactionTraceEntry entryProto;
         entryProto.set_elapsed_realtime_nanos(entry.timestamp);
         entryProto.set_vsync_id(entry.vsyncId);
+        entryProto.mutable_added_layers()->Reserve(static_cast<int32_t>(mCreatedLayers.size()));
+        for (auto& newLayer : mCreatedLayers) {
+            entryProto.mutable_added_layers()->Add(std::move(newLayer));
+        }
+        entryProto.mutable_removed_layers()->Reserve(static_cast<int32_t>(removedLayers.size()));
+        for (auto& removedLayer : removedLayers) {
+            entryProto.mutable_removed_layers()->Add(removedLayer);
+        }
+        mCreatedLayers.clear();
         entryProto.mutable_transactions()->Reserve(
                 static_cast<int32_t>(entry.transactionIds.size()));
         for (const uint64_t& id : entry.transactionIds) {
@@ -188,16 +202,128 @@
                 ALOGE("Could not find transaction id %" PRIu64, id);
             }
         }
-        mBuffer->emplace(std::move(entryProto));
+        std::vector<proto::TransactionTraceEntry> entries = mBuffer->emplace(std::move(entryProto));
+        removedEntries.insert(removedEntries.end(), std::make_move_iterator(entries.begin()),
+                              std::make_move_iterator(entries.end()));
+    }
+
+    for (const proto::TransactionTraceEntry& removedEntry : removedEntries) {
+        updateStartingStateLocked(removedEntry);
+    }
+    mTransactionsAddedToBufferCv.notify_one();
+}
+
+void TransactionTracing::flush(int64_t vsyncId) {
+    while (!mPendingTransactions.empty() || !mPendingRemovedLayers.empty()) {
+        tryPushToTracingThread();
+    }
+    std::unique_lock<std::mutex> lock(mTraceLock);
+    base::ScopedLockAssertion assumeLocked(mTraceLock);
+    mTransactionsAddedToBufferCv.wait(lock, [&]() REQUIRES(mTraceLock) {
+        return mBuffer->used() > 0 && mBuffer->back().vsync_id() >= vsyncId;
+    });
+}
+
+void TransactionTracing::onLayerAdded(BBinder* layerHandle, int layerId, const std::string& name,
+                                      uint32_t flags, int parentId) {
+    std::scoped_lock lock(mTraceLock);
+    TracingLayerCreationArgs args{layerId, name, flags, parentId};
+    mLayerHandles[layerHandle] = layerId;
+    mCreatedLayers.emplace_back(TransactionProtoParser::toProto(args));
+}
+
+void TransactionTracing::onLayerRemoved(int32_t layerId) {
+    mPendingRemovedLayers.emplace_back(layerId);
+    tryPushToTracingThread();
+}
+
+void TransactionTracing::tryPushToTracingThread() {
+    // Try to acquire the lock from main thread.
+    if (mMainThreadLock.try_lock()) {
+        // We got the lock! Collect any pending transactions and continue.
+        mCommittedTransactions.insert(mCommittedTransactions.end(),
+                                      std::make_move_iterator(mPendingTransactions.begin()),
+                                      std::make_move_iterator(mPendingTransactions.end()));
+        mPendingTransactions.clear();
+        mRemovedLayers.insert(mRemovedLayers.end(), mPendingRemovedLayers.begin(),
+                              mPendingRemovedLayers.end());
+        mPendingRemovedLayers.clear();
+        mTransactionsAvailableCv.notify_one();
+        mMainThreadLock.unlock();
+    } else {
+        ALOGV("Couldn't get lock");
     }
 }
 
-void TransactionTracing::flush() {
-    std::unique_lock<std::mutex> lock(mMainThreadLock);
-    base::ScopedLockAssertion assumeLocked(mMainThreadLock);
-    mTransactionsAddedToBufferCv.wait(lock, [&]() REQUIRES(mMainThreadLock) {
-        return mCommittedTransactions.empty();
-    });
+int32_t TransactionTracing::getLayerIdLocked(const sp<IBinder>& layerHandle) {
+    if (layerHandle == nullptr) {
+        return -1;
+    }
+    auto it = mLayerHandles.find(layerHandle->localBinder());
+    return it == mLayerHandles.end() ? -1 : it->second;
+}
+
+void TransactionTracing::updateStartingStateLocked(
+        const proto::TransactionTraceEntry& removedEntry) {
+    // Keep track of layer starting state so we can reconstruct the layer state as we purge
+    // transactions from the buffer.
+    for (const proto::LayerCreationArgs& addedLayer : removedEntry.added_layers()) {
+        TracingLayerState& startingState = mStartingStates[addedLayer.layer_id()];
+        startingState.layerId = addedLayer.layer_id();
+        startingState.name = addedLayer.name();
+        startingState.layerCreationFlags = addedLayer.flags();
+        startingState.parentId = addedLayer.parent_id();
+    }
+
+    // Merge layer states to starting transaction state.
+    for (const proto::TransactionState& transaction : removedEntry.transactions()) {
+        for (const proto::LayerState& layerState : transaction.layer_changes()) {
+            auto it = mStartingStates.find(layerState.layer_id());
+            if (it == mStartingStates.end()) {
+                ALOGE("Could not find layer id %d", layerState.layer_id());
+                continue;
+            }
+            TransactionProtoParser::fromProto(layerState, nullptr, it->second);
+        }
+    }
+
+    // Clean up stale starting states since the layer has been removed and the buffer does not
+    // contain any references to the layer.
+    for (const int32_t removedLayerId : removedEntry.removed_layers()) {
+        auto it = std::find_if(mLayerHandles.begin(), mLayerHandles.end(),
+                               [removedLayerId](auto& layer) {
+                                   return layer.second == removedLayerId;
+                               });
+        if (it != mLayerHandles.end()) {
+            mLayerHandles.erase(it);
+        }
+        mStartingStates.erase(removedLayerId);
+    }
+}
+
+void TransactionTracing::addStartingStateToProtoLocked(proto::TransactionTraceFile& proto) {
+    proto::TransactionTraceEntry* entryProto = proto.add_entry();
+    entryProto->set_elapsed_realtime_nanos(mStartingTimestamp);
+    entryProto->set_vsync_id(0);
+    entryProto->mutable_added_layers()->Reserve(static_cast<int32_t>(mStartingStates.size()));
+    for (auto& [layerId, state] : mStartingStates) {
+        TracingLayerCreationArgs args{layerId, state.name, state.layerCreationFlags,
+                                      state.parentId};
+        entryProto->mutable_added_layers()->Add(TransactionProtoParser::toProto(args));
+    }
+
+    proto::TransactionState transactionProto = TransactionProtoParser::toProto(mStartingStates);
+    transactionProto.set_vsync_id(0);
+    transactionProto.set_post_time(mStartingTimestamp);
+    entryProto->mutable_transactions()->Add(std::move(transactionProto));
+}
+
+proto::TransactionTraceFile TransactionTracing::writeToProto() {
+    std::scoped_lock<std::mutex> lock(mTraceLock);
+    proto::TransactionTraceFile proto = createTraceFileProto();
+    addStartingStateToProtoLocked(proto);
+    mBuffer->writeToProto(proto);
+    return proto;
 }
 
 } // namespace android
diff --git a/services/surfaceflinger/Tracing/TransactionTracing.h b/services/surfaceflinger/Tracing/TransactionTracing.h
index d92ab01..0aa22ed 100644
--- a/services/surfaceflinger/Tracing/TransactionTracing.h
+++ b/services/surfaceflinger/Tracing/TransactionTracing.h
@@ -62,6 +62,9 @@
     void addCommittedTransactions(std::vector<TransactionState>& transactions, int64_t vsyncId);
     status_t writeToFile();
     void setBufferSize(size_t bufferSizeInBytes);
+    void onLayerAdded(BBinder* layerHandle, int layerId, const std::string& name, uint32_t flags,
+                      int parentId);
+    void onLayerRemoved(int layerId);
     void dump(std::string&) const;
     static constexpr auto CONTINUOUS_TRACING_BUFFER_SIZE = 512 * 1024;
     static constexpr auto ACTIVE_TRACING_BUFFER_SIZE = 100 * 1024 * 1024;
@@ -78,6 +81,12 @@
     size_t mBufferSizeInBytes GUARDED_BY(mTraceLock) = CONTINUOUS_TRACING_BUFFER_SIZE;
     std::unordered_map<uint64_t, proto::TransactionState> mQueuedTransactions
             GUARDED_BY(mTraceLock);
+    nsecs_t mStartingTimestamp GUARDED_BY(mTraceLock);
+    std::vector<proto::LayerCreationArgs> mCreatedLayers GUARDED_BY(mTraceLock);
+    std::unordered_map<BBinder* /* layerHandle */, int32_t /* layerId */> mLayerHandles
+            GUARDED_BY(mTraceLock);
+    std::unordered_map<int32_t /* layerId */, TracingLayerState> mStartingStates
+            GUARDED_BY(mTraceLock);
 
     // We do not want main thread to block so main thread will try to acquire mMainThreadLock,
     // otherwise will push data to temporary container.
@@ -93,15 +102,25 @@
     };
     std::vector<CommittedTransactions> mCommittedTransactions GUARDED_BY(mMainThreadLock);
     std::vector<CommittedTransactions> mPendingTransactions; // only accessed by main thread
-    proto::TransactionTraceFile createTraceFileProto() const;
 
+    std::vector<int32_t /* layerId */> mRemovedLayers GUARDED_BY(mMainThreadLock);
+    std::vector<int32_t /* layerId */> mPendingRemovedLayers; // only accessed by main thread
+
+    proto::TransactionTraceFile createTraceFileProto() const;
     void loop();
-    void addEntry(const std::vector<CommittedTransactions>& committedTransactions)
-            EXCLUDES(mTraceLock);
+    void addEntry(const std::vector<CommittedTransactions>& committedTransactions,
+                  const std::vector<int32_t>& removedLayers) EXCLUDES(mTraceLock);
+    int32_t getLayerIdLocked(const sp<IBinder>& layerHandle) REQUIRES(mTraceLock);
+    void tryPushToTracingThread() EXCLUDES(mMainThreadLock);
+    void addStartingStateToProtoLocked(proto::TransactionTraceFile& proto) REQUIRES(mTraceLock);
+    void updateStartingStateLocked(const proto::TransactionTraceEntry& entry) REQUIRES(mTraceLock);
+    status_t writeToFileLocked() REQUIRES(mTraceLock);
 
     // TEST
-    // Wait until all the committed transactions are added to the buffer.
-    void flush() EXCLUDES(mMainThreadLock);
+    // Wait until all the committed transactions for the specified vsync id are added to the buffer.
+    void flush(int64_t vsyncId) EXCLUDES(mMainThreadLock);
+    // Return buffer contents as trace file proto
+    proto::TransactionTraceFile writeToProto() EXCLUDES(mMainThreadLock);
 };
 
 } // namespace android
diff --git a/services/surfaceflinger/layerproto/transactions.proto b/services/surfaceflinger/layerproto/transactions.proto
index edeacfa..10222cc 100644
--- a/services/surfaceflinger/layerproto/transactions.proto
+++ b/services/surfaceflinger/layerproto/transactions.proto
@@ -42,8 +42,10 @@
     int64 elapsed_realtime_nanos = 1;
     int64 vsync_id = 2;
     repeated TransactionState transactions = 3;
-    repeated LayerCreationArgs new_layers = 4;
-    repeated DisplayState new_displays = 5;
+    repeated LayerCreationArgs added_layers = 4;
+    repeated int32 removed_layers = 5;
+    repeated DisplayState added_displays = 6;
+    repeated int32 removed_displays = 7;
 }
 
 message LayerCreationArgs {
diff --git a/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp b/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp
index 2afa68a..ffe5671 100644
--- a/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp
@@ -28,11 +28,14 @@
 
 class TransactionTracingTest : public testing::Test {
 protected:
+    static constexpr size_t SMALL_BUFFER_SIZE = 1024;
     std::unique_ptr<android::TransactionTracing> mTracing;
-
     void SetUp() override { mTracing = std::make_unique<android::TransactionTracing>(); }
 
-    void TearDown() override { mTracing.reset(); }
+    void TearDown() override {
+        mTracing->disable();
+        mTracing.reset();
+    }
 
     auto getCommittedTransactions() {
         std::scoped_lock<std::mutex> lock(mTracing->mMainThreadLock);
@@ -49,7 +52,7 @@
         return mTracing->mBuffer->used();
     }
 
-    auto flush() { return mTracing->flush(); }
+    auto flush(int64_t vsyncId) { return mTracing->flush(vsyncId); }
 
     auto bufferFront() {
         std::scoped_lock<std::mutex> lock(mTracing->mTraceLock);
@@ -61,12 +64,28 @@
         return mTracing->mThread.joinable();
     }
 
-    std::string writeToString() {
+    proto::TransactionTraceFile writeToProto() { return mTracing->writeToProto(); }
+
+    auto getCreatedLayers() {
         std::scoped_lock<std::mutex> lock(mTracing->mTraceLock);
-        std::string output;
-        proto::TransactionTraceFile fileProto = mTracing->createTraceFileProto();
-        mTracing->mBuffer->writeToString(fileProto, &output);
-        return output;
+        return mTracing->mCreatedLayers;
+    }
+
+    auto getStartingStates() {
+        std::scoped_lock<std::mutex> lock(mTracing->mTraceLock);
+        return mTracing->mStartingStates;
+    }
+
+    void queueAndCommitTransaction(int64_t vsyncId) {
+        TransactionState transaction;
+        transaction.id = static_cast<uint64_t>(vsyncId * 3);
+        transaction.originUid = 1;
+        transaction.originPid = 2;
+        mTracing->addQueuedTransaction(transaction);
+        std::vector<TransactionState> transactions;
+        transactions.emplace_back(transaction);
+        mTracing->addCommittedTransactions(transactions, vsyncId);
+        flush(vsyncId);
     }
 
     // Test that we clean up the tracing thread and free any memory allocated.
@@ -76,6 +95,7 @@
         EXPECT_EQ(getCommittedTransactions().size(), 0u);
         EXPECT_EQ(getQueuedTransactions().size(), 0u);
         EXPECT_EQ(getUsedBufferSize(), 0u);
+        EXPECT_EQ(getStartingStates().size(), 0u);
     }
 
     void verifyEntry(const proto::TransactionTraceEntry& actualProto,
@@ -122,17 +142,150 @@
     std::vector<TransactionState> secondTransactionSet =
             std::vector<TransactionState>(transactions.begin(), transactions.begin() + 50);
     mTracing->addCommittedTransactions(secondTransactionSet, secondTransactionSetVsyncId);
-    flush();
+    flush(secondTransactionSetVsyncId);
 
-    std::string protoString = writeToString();
-    proto::TransactionTraceFile proto;
-    proto.ParseFromString(protoString);
-    EXPECT_EQ(proto.entry().size(), 2);
-    verifyEntry(proto.entry(0), firstTransactionSet, firstTransactionSetVsyncId);
-    verifyEntry(proto.entry(1), secondTransactionSet, secondTransactionSetVsyncId);
+    proto::TransactionTraceFile proto = writeToProto();
+    EXPECT_EQ(proto.entry().size(), 3);
+    // skip starting entry
+    verifyEntry(proto.entry(1), firstTransactionSet, firstTransactionSetVsyncId);
+    verifyEntry(proto.entry(2), secondTransactionSet, secondTransactionSetVsyncId);
 
     mTracing->disable();
     verifyDisabledTracingState();
 }
 
+class TransactionTracingLayerHandlingTest : public TransactionTracingTest {
+protected:
+    void SetUp() override {
+        TransactionTracingTest::SetUp();
+        mTracing->enable();
+        // add layers
+        mTracing->setBufferSize(SMALL_BUFFER_SIZE);
+        const sp<IBinder> fakeLayerHandle = new BBinder();
+        mTracing->onLayerAdded(fakeLayerHandle->localBinder(), mParentLayerId, "parent",
+                               123 /* flags */, -1 /* parentId */);
+        const sp<IBinder> fakeChildLayerHandle = new BBinder();
+        mTracing->onLayerAdded(fakeChildLayerHandle->localBinder(), 2 /* layerId */, "child",
+                               456 /* flags */, mParentLayerId);
+
+        // add some layer transaction
+        {
+            TransactionState transaction;
+            transaction.id = 50;
+            ComposerState layerState;
+            layerState.state.surface = fakeLayerHandle;
+            layerState.state.what = layer_state_t::eLayerChanged;
+            layerState.state.z = 42;
+            transaction.states.add(layerState);
+            ComposerState childState;
+            childState.state.surface = fakeChildLayerHandle;
+            layerState.state.z = 43;
+            transaction.states.add(childState);
+            mTracing->addQueuedTransaction(transaction);
+
+            std::vector<TransactionState> transactions;
+            transactions.emplace_back(transaction);
+            VSYNC_ID_FIRST_LAYER_CHANGE = ++mVsyncId;
+            mTracing->addCommittedTransactions(transactions, VSYNC_ID_FIRST_LAYER_CHANGE);
+            flush(VSYNC_ID_FIRST_LAYER_CHANGE);
+        }
+
+        // add transactions that modify the layer state further so we can test that layer state
+        // gets merged
+        {
+            TransactionState transaction;
+            transaction.id = 51;
+            ComposerState layerState;
+            layerState.state.surface = fakeLayerHandle;
+            layerState.state.what = layer_state_t::eLayerChanged | layer_state_t::ePositionChanged;
+            layerState.state.z = 41;
+            layerState.state.x = 22;
+            transaction.states.add(layerState);
+            mTracing->addQueuedTransaction(transaction);
+
+            std::vector<TransactionState> transactions;
+            transactions.emplace_back(transaction);
+            VSYNC_ID_SECOND_LAYER_CHANGE = ++mVsyncId;
+            mTracing->addCommittedTransactions(transactions, VSYNC_ID_SECOND_LAYER_CHANGE);
+            flush(VSYNC_ID_SECOND_LAYER_CHANGE);
+        }
+
+        // remove child layer
+        mTracing->onLayerRemoved(2);
+        VSYNC_ID_CHILD_LAYER_REMOVED = ++mVsyncId;
+        queueAndCommitTransaction(VSYNC_ID_CHILD_LAYER_REMOVED);
+
+        // remove layer
+        mTracing->onLayerRemoved(1);
+        queueAndCommitTransaction(++mVsyncId);
+    }
+
+    void TearDown() override {
+        mTracing->disable();
+        verifyDisabledTracingState();
+        TransactionTracingTest::TearDown();
+    }
+
+    int mParentLayerId = 1;
+    int64_t mVsyncId = 0;
+    int64_t VSYNC_ID_FIRST_LAYER_CHANGE;
+    int64_t VSYNC_ID_SECOND_LAYER_CHANGE;
+    int64_t VSYNC_ID_CHILD_LAYER_REMOVED;
+};
+
+TEST_F(TransactionTracingLayerHandlingTest, addStartingState) {
+    // add transactions until we drop the transaction with the first layer change
+    while (bufferFront().vsync_id() <= VSYNC_ID_FIRST_LAYER_CHANGE) {
+        queueAndCommitTransaction(++mVsyncId);
+    }
+    proto::TransactionTraceFile proto = writeToProto();
+    // verify we can still retrieve the layer change from the first entry containing starting
+    // states.
+    EXPECT_GT(proto.entry().size(), 0);
+    EXPECT_GT(proto.entry(0).transactions().size(), 0);
+    EXPECT_GT(proto.entry(0).added_layers().size(), 0);
+    EXPECT_GT(proto.entry(0).transactions(0).layer_changes().size(), 0);
+    EXPECT_EQ(proto.entry(0).transactions(0).layer_changes(0).z(), 42);
+}
+
+TEST_F(TransactionTracingLayerHandlingTest, updateStartingState) {
+    // add transactions until we drop the transaction with the second layer change
+    while (bufferFront().vsync_id() <= VSYNC_ID_SECOND_LAYER_CHANGE) {
+        queueAndCommitTransaction(++mVsyncId);
+    }
+    proto::TransactionTraceFile proto = writeToProto();
+    // verify starting states are updated correctly
+    EXPECT_EQ(proto.entry(0).transactions(0).layer_changes(0).z(), 41);
+}
+
+TEST_F(TransactionTracingLayerHandlingTest, removeStartingState) {
+    // add transactions until we drop the transaction which removes the child layer
+    while (bufferFront().vsync_id() <= VSYNC_ID_CHILD_LAYER_REMOVED) {
+        queueAndCommitTransaction(++mVsyncId);
+    }
+    proto::TransactionTraceFile proto = writeToProto();
+    // verify the child layer has been removed from the trace
+    EXPECT_EQ(proto.entry(0).transactions(0).layer_changes().size(), 1);
+    EXPECT_EQ(proto.entry(0).transactions(0).layer_changes(0).layer_id(), mParentLayerId);
+}
+
+TEST_F(TransactionTracingLayerHandlingTest, startingStateSurvivesBufferFlush) {
+    // add transactions until we drop the transaction with the second layer change
+    while (bufferFront().vsync_id() <= VSYNC_ID_SECOND_LAYER_CHANGE) {
+        queueAndCommitTransaction(++mVsyncId);
+    }
+    proto::TransactionTraceFile proto = writeToProto();
+    // verify we have two starting states
+    EXPECT_EQ(proto.entry(0).transactions(0).layer_changes().size(), 2);
+
+    // Continue adding transactions until child layer is removed
+    while (bufferFront().vsync_id() <= VSYNC_ID_CHILD_LAYER_REMOVED) {
+        queueAndCommitTransaction(++mVsyncId);
+    }
+    proto = writeToProto();
+    // verify we still have the parent layer state
+    EXPECT_EQ(proto.entry(0).transactions(0).layer_changes().size(), 1);
+    EXPECT_EQ(proto.entry(0).transactions(0).layer_changes(0).layer_id(), mParentLayerId);
+}
+
 } // namespace android