Merge "Ignore touchpad contacts that are marked as palms" into udc-dev
diff --git a/libs/gui/Choreographer.cpp b/libs/gui/Choreographer.cpp
index 99bf6ba..46fb068 100644
--- a/libs/gui/Choreographer.cpp
+++ b/libs/gui/Choreographer.cpp
@@ -15,8 +15,10 @@
  */
 
 // #define LOG_NDEBUG 0
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
 
 #include <gui/Choreographer.h>
+#include <gui/TraceUtils.h>
 #include <jni.h>
 
 #undef LOG_TAG
@@ -297,6 +299,8 @@
     mLastVsyncEventData = vsyncEventData;
     for (const auto& cb : callbacks) {
         if (cb.vsyncCallback != nullptr) {
+            ATRACE_FORMAT("AChoreographer_vsyncCallback %" PRId64,
+                          vsyncEventData.preferredVsyncId());
             const ChoreographerFrameCallbackDataImpl frameCallbackData =
                     createFrameCallbackData(timestamp);
             registerStartTime();
@@ -306,8 +310,10 @@
                              cb.data);
             mInCallback = false;
         } else if (cb.callback64 != nullptr) {
+            ATRACE_FORMAT("AChoreographer_frameCallback64");
             cb.callback64(timestamp, cb.data);
         } else if (cb.callback != nullptr) {
+            ATRACE_FORMAT("AChoreographer_frameCallback");
             cb.callback(timestamp, cb.data);
         }
     }
diff --git a/libs/renderengine/skia/SkiaVkRenderEngine.cpp b/libs/renderengine/skia/SkiaVkRenderEngine.cpp
index 8d99f3d..936e316 100644
--- a/libs/renderengine/skia/SkiaVkRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaVkRenderEngine.cpp
@@ -444,8 +444,11 @@
     ALOGD("Trying to create Vk device with protectedContent=%d (success)", protectedContent);
 
     VkQueue graphicsQueue;
-    VK_GET_DEV_PROC(device, GetDeviceQueue);
-    vkGetDeviceQueue(device, graphicsQueueIndex, 0, &graphicsQueue);
+    VK_GET_DEV_PROC(device, GetDeviceQueue2);
+    const VkDeviceQueueInfo2 deviceQueueInfo2 = {VK_STRUCTURE_TYPE_DEVICE_QUEUE_INFO_2, nullptr,
+                                                 deviceQueueCreateFlags,
+                                                 (uint32_t)graphicsQueueIndex, 0};
+    vkGetDeviceQueue2(device, &deviceQueueInfo2, &graphicsQueue);
 
     VK_GET_DEV_PROC(device, DeviceWaitIdle);
     VK_GET_DEV_PROC(device, DestroyDevice);
diff --git a/libs/sensor/ISensorServer.cpp b/libs/sensor/ISensorServer.cpp
index e2aac8c..019d6cb 100644
--- a/libs/sensor/ISensorServer.cpp
+++ b/libs/sensor/ISensorServer.cpp
@@ -139,10 +139,12 @@
     }
 
     virtual sp<ISensorEventConnection> createSensorDirectConnection(const String16& opPackageName,
-            uint32_t size, int32_t type, int32_t format, const native_handle_t *resource) {
+            int deviceId, uint32_t size, int32_t type, int32_t format,
+            const native_handle_t *resource) {
         Parcel data, reply;
         data.writeInterfaceToken(ISensorServer::getInterfaceDescriptor());
         data.writeString16(opPackageName);
+        data.writeInt32(deviceId);
         data.writeUint32(size);
         data.writeInt32(type);
         data.writeInt32(format);
@@ -237,6 +239,7 @@
         case CREATE_SENSOR_DIRECT_CONNECTION: {
             CHECK_INTERFACE(ISensorServer, data, reply);
             const String16& opPackageName = data.readString16();
+            const int deviceId = data.readInt32();
             uint32_t size = data.readUint32();
             int32_t type = data.readInt32();
             int32_t format = data.readInt32();
@@ -246,8 +249,8 @@
                 return BAD_VALUE;
             }
             native_handle_set_fdsan_tag(resource);
-            sp<ISensorEventConnection> ch =
-                    createSensorDirectConnection(opPackageName, size, type, format, resource);
+            sp<ISensorEventConnection> ch = createSensorDirectConnection(
+                    opPackageName, deviceId, size, type, format, resource);
             native_handle_close_with_tag(resource);
             native_handle_delete(resource);
             reply->writeStrongBinder(IInterface::asBinder(ch));
diff --git a/libs/sensor/SensorManager.cpp b/libs/sensor/SensorManager.cpp
index 44a208d..ba190e0 100644
--- a/libs/sensor/SensorManager.cpp
+++ b/libs/sensor/SensorManager.cpp
@@ -315,6 +315,12 @@
 
 int SensorManager::createDirectChannel(
         size_t size, int channelType, const native_handle_t *resourceHandle) {
+    static constexpr int DEFAULT_DEVICE_ID = 0;
+    return createDirectChannel(DEFAULT_DEVICE_ID, size, channelType, resourceHandle);
+}
+
+int SensorManager::createDirectChannel(
+        int deviceId, size_t size, int channelType, const native_handle_t *resourceHandle) {
     Mutex::Autolock _l(mLock);
     if (assertStateLocked() != NO_ERROR) {
         return NO_INIT;
@@ -327,7 +333,7 @@
     }
 
     sp<ISensorEventConnection> conn =
-              mSensorServer->createSensorDirectConnection(mOpPackageName,
+              mSensorServer->createSensorDirectConnection(mOpPackageName, deviceId,
                   static_cast<uint32_t>(size),
                   static_cast<int32_t>(channelType),
                   SENSOR_DIRECT_FMT_SENSORS_EVENT, resourceHandle);
diff --git a/libs/sensor/include/sensor/ISensorServer.h b/libs/sensor/include/sensor/ISensorServer.h
index 3295196..5815728 100644
--- a/libs/sensor/include/sensor/ISensorServer.h
+++ b/libs/sensor/include/sensor/ISensorServer.h
@@ -50,7 +50,8 @@
     virtual int32_t isDataInjectionEnabled() = 0;
 
     virtual sp<ISensorEventConnection> createSensorDirectConnection(const String16& opPackageName,
-            uint32_t size, int32_t type, int32_t format, const native_handle_t *resource) = 0;
+            int deviceId, uint32_t size, int32_t type, int32_t format,
+            const native_handle_t *resource) = 0;
 
     virtual int setOperationParameter(
             int32_t handle, int32_t type, const Vector<float> &floats, const Vector<int32_t> &ints) = 0;
diff --git a/libs/sensor/include/sensor/SensorManager.h b/libs/sensor/include/sensor/SensorManager.h
index c31f648..bb44cb8 100644
--- a/libs/sensor/include/sensor/SensorManager.h
+++ b/libs/sensor/include/sensor/SensorManager.h
@@ -66,6 +66,8 @@
         String8 packageName = String8(""), int mode = 0, String16 attributionTag = String16(""));
     bool isDataInjectionEnabled();
     int createDirectChannel(size_t size, int channelType, const native_handle_t *channelData);
+    int createDirectChannel(
+        int deviceId, size_t size, int channelType, const native_handle_t *channelData);
     void destroyDirectChannel(int channelNativeHandle);
     int configureDirectChannel(int channelNativeHandle, int sensorHandle, int rateLevel);
     int setOperationParameter(int handle, int type, const Vector<float> &floats, const Vector<int32_t> &ints);
diff --git a/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp b/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp
index 8ab6748..d3af402 100644
--- a/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp
@@ -31,6 +31,15 @@
 
 namespace {
 
+/**
+ * Log details of each gesture output by the gestures library.
+ * Enable this via "adb shell setprop log.tag.TouchpadInputMapperGestures DEBUG" (requires
+ * restarting the shell)
+ */
+const bool DEBUG_TOUCHPAD_GESTURES =
+        __android_log_is_loggable(ANDROID_LOG_DEBUG, "TouchpadInputMapperGestures",
+                                  ANDROID_LOG_INFO);
+
 // Describes a segment of the acceleration curve.
 struct CurveSegment {
     // The maximum pointer speed which this segment should apply. The last segment in a curve should
@@ -251,6 +260,7 @@
 
 std::list<NotifyArgs> TouchpadInputMapper::sendHardwareState(nsecs_t when, nsecs_t readTime,
                                                              SelfContainedHardwareState schs) {
+    ALOGD_IF(DEBUG_TOUCHPAD_GESTURES, "New hardware state: %s", schs.state.String().c_str());
     mProcessing = true;
     mGestureInterpreter->PushHardwareState(&schs.state);
     mProcessing = false;
@@ -259,7 +269,7 @@
 }
 
 void TouchpadInputMapper::consumeGesture(const Gesture* gesture) {
-    ALOGD("Gesture ready: %s", gesture->String().c_str());
+    ALOGD_IF(DEBUG_TOUCHPAD_GESTURES, "Gesture ready: %s", gesture->String().c_str());
     if (!mProcessing) {
         ALOGE("Received gesture outside of the normal processing flow; ignoring it.");
         return;
diff --git a/services/sensorservice/SensorDirectConnection.cpp b/services/sensorservice/SensorDirectConnection.cpp
index 4ac9651..4fff8bb 100644
--- a/services/sensorservice/SensorDirectConnection.cpp
+++ b/services/sensorservice/SensorDirectConnection.cpp
@@ -28,10 +28,10 @@
 
 SensorService::SensorDirectConnection::SensorDirectConnection(const sp<SensorService>& service,
         uid_t uid, const sensors_direct_mem_t *mem, int32_t halChannelHandle,
-        const String16& opPackageName)
+        const String16& opPackageName, int deviceId)
         : mService(service), mUid(uid), mMem(*mem),
         mHalChannelHandle(halChannelHandle),
-        mOpPackageName(opPackageName), mDestroyed(false) {
+        mOpPackageName(opPackageName), mDeviceId(deviceId), mDestroyed(false) {
     mUserId = multiuser_get_user_id(mUid);
     ALOGD_IF(DEBUG_CONNECTIONS, "Created SensorDirectConnection");
 }
@@ -180,8 +180,7 @@
     };
 
     Mutex::Autolock _l(mConnectionLock);
-    SensorDevice& dev(SensorDevice::getInstance());
-    int ret = dev.configureDirectChannel(handle, getHalChannelHandle(), &config);
+    int ret = configure(handle, &config);
 
     if (rateLevel == SENSOR_DIRECT_RATE_STOP) {
         if (ret == NO_ERROR) {
@@ -224,7 +223,6 @@
     std::unordered_map<int, int>& existingConnections =
                     (!temporarilyStopped) ? mActivated : mActivatedBackup;
 
-    SensorDevice& dev(SensorDevice::getInstance());
     for (auto &i : existingConnections) {
         int handle = i.first;
         int rateLevel = i.second;
@@ -239,8 +237,8 @@
                 // Only reconfigure the channel if it's ongoing
                 if (!temporarilyStopped) {
                     // Stopping before reconfiguring is the well-tested path in CTS
-                    dev.configureDirectChannel(handle, getHalChannelHandle(), &stopConfig);
-                    dev.configureDirectChannel(handle, getHalChannelHandle(), &capConfig);
+                    configure(handle, &stopConfig);
+                    configure(handle, &capConfig);
                 }
             }
         }
@@ -258,7 +256,6 @@
     const struct sensors_direct_cfg_t stopConfig = {
         .rate_level = SENSOR_DIRECT_RATE_STOP
     };
-    SensorDevice& dev(SensorDevice::getInstance());
     for (auto &i : mMicRateBackup) {
         int handle = i.first;
         int rateLevel = i.second;
@@ -273,13 +270,23 @@
         // Only reconfigure the channel if it's ongoing
         if (!temporarilyStopped) {
             // Stopping before reconfiguring is the well-tested path in CTS
-            dev.configureDirectChannel(handle, getHalChannelHandle(), &stopConfig);
-            dev.configureDirectChannel(handle, getHalChannelHandle(), &config);
+            configure(handle, &stopConfig);
+            configure(handle, &config);
         }
     }
     mMicRateBackup.clear();
 }
 
+int SensorService::SensorDirectConnection::configure(
+        int handle, const sensors_direct_cfg_t* config) {
+    if (mDeviceId == RuntimeSensor::DEFAULT_DEVICE_ID) {
+        SensorDevice& dev(SensorDevice::getInstance());
+        return dev.configureDirectChannel(handle, getHalChannelHandle(), config);
+    } else {
+        return mService->configureRuntimeSensorDirectChannel(handle, this, config);
+    }
+}
+
 void SensorService::SensorDirectConnection::stopAll(bool backupRecord) {
     Mutex::Autolock _l(mConnectionLock);
     stopAllLocked(backupRecord);
@@ -290,9 +297,8 @@
         .rate_level = SENSOR_DIRECT_RATE_STOP
     };
 
-    SensorDevice& dev(SensorDevice::getInstance());
     for (auto &i : mActivated) {
-        dev.configureDirectChannel(i.first, getHalChannelHandle(), &config);
+        configure(i.first, &config);
     }
 
     if (backupRecord && mActivatedBackup.empty()) {
@@ -306,8 +312,6 @@
     if (!mActivatedBackup.empty()) {
         stopAllLocked(false);
 
-        SensorDevice& dev(SensorDevice::getInstance());
-
         // recover list of report from backup
         ALOG_ASSERT(mActivated.empty(),
                     "mActivated must be empty if mActivatedBackup was non-empty");
@@ -319,7 +323,7 @@
             struct sensors_direct_cfg_t config = {
                 .rate_level = i.second
             };
-            dev.configureDirectChannel(i.first, getHalChannelHandle(), &config);
+            configure(i.first, &config);
         }
     }
 }
diff --git a/services/sensorservice/SensorDirectConnection.h b/services/sensorservice/SensorDirectConnection.h
index d39a073..bfaf811 100644
--- a/services/sensorservice/SensorDirectConnection.h
+++ b/services/sensorservice/SensorDirectConnection.h
@@ -39,7 +39,7 @@
 public:
     SensorDirectConnection(const sp<SensorService>& service, uid_t uid,
             const sensors_direct_mem_t *mem, int32_t halChannelHandle,
-            const String16& opPackageName);
+            const String16& opPackageName, int deviceId);
     void dump(String8& result) const;
     void dump(util::ProtoOutputStream* proto) const;
     uid_t getUid() const { return mUid; }
@@ -53,6 +53,7 @@
     void onSensorAccessChanged(bool hasAccess);
     void onMicSensorAccessChanged(bool isMicToggleOn);
     userid_t getUserId() const { return mUserId; }
+    int getDeviceId() const { return mDeviceId; }
 
 protected:
     virtual ~SensorDirectConnection();
@@ -68,6 +69,9 @@
 private:
     bool hasSensorAccess() const;
 
+    // Sends the configuration to the relevant sensor device.
+    int configure(int handle, const sensors_direct_cfg_t* config);
+
     // Stops all active sensor direct report requests.
     //
     // If backupRecord is true, stopped requests can be recovered
@@ -95,6 +99,7 @@
     const sensors_direct_mem_t mMem;
     const int32_t mHalChannelHandle;
     const String16 mOpPackageName;
+    const int mDeviceId;
 
     mutable Mutex mConnectionLock;
     std::unordered_map<int, int> mActivated;
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index 3a0329c..0fb3cad 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -181,7 +181,7 @@
             handle, sensor.type, sensor.name);
 
     sp<RuntimeSensor::SensorCallback> runtimeSensorCallback(
-        new RuntimeSensorCallbackProxy(std::move(callback)));
+            new RuntimeSensorCallbackProxy(callback));
     sensor_t runtimeSensor = sensor;
     // force the handle to be consistent
     runtimeSensor.handle = handle;
@@ -193,11 +193,15 @@
         return mSensors.getNonSensor().getHandle();
     }
 
+    if (mRuntimeSensorCallbacks.find(deviceId) == mRuntimeSensorCallbacks.end()) {
+        mRuntimeSensorCallbacks.emplace(deviceId, callback);
+    }
     return handle;
 }
 
 status_t SensorService::unregisterRuntimeSensor(int handle) {
     ALOGI("Unregistering runtime sensor handle 0x%x disconnected", handle);
+    int deviceId = getDeviceIdFromHandle(handle);
     {
         Mutex::Autolock _l(mLock);
         if (!unregisterDynamicSensorLocked(handle)) {
@@ -210,6 +214,20 @@
     for (const sp<SensorEventConnection>& connection : connLock.getActiveConnections()) {
         connection->removeSensor(handle);
     }
+
+    // If this was the last sensor for this device, remove its callback.
+    bool deviceHasSensors = false;
+    mSensors.forEachEntry(
+            [&deviceId, &deviceHasSensors] (const SensorServiceUtil::SensorList::Entry& e) -> bool {
+                if (e.deviceId == deviceId) {
+                    deviceHasSensors = true;
+                    return false;  // stop iterating
+                }
+                return true;
+            });
+    if (!deviceHasSensors) {
+        mRuntimeSensorCallbacks.erase(deviceId);
+    }
     return OK;
 }
 
@@ -1517,7 +1535,7 @@
 }
 
 sp<ISensorEventConnection> SensorService::createSensorDirectConnection(
-        const String16& opPackageName, uint32_t size, int32_t type, int32_t format,
+        const String16& opPackageName, int deviceId, uint32_t size, int32_t type, int32_t format,
         const native_handle *resource) {
     resetTargetSdkVersionCache(opPackageName);
     ConnectionSafeAutolock connLock = mConnectionHolder.lock(mLock);
@@ -1593,14 +1611,25 @@
     native_handle_set_fdsan_tag(clone);
 
     sp<SensorDirectConnection> conn;
-    SensorDevice& dev(SensorDevice::getInstance());
-    int channelHandle = dev.registerDirectChannel(&mem);
+    int channelHandle = 0;
+    if (deviceId == RuntimeSensor::DEFAULT_DEVICE_ID) {
+        SensorDevice& dev(SensorDevice::getInstance());
+        channelHandle = dev.registerDirectChannel(&mem);
+    } else {
+        auto runtimeSensorCallback = mRuntimeSensorCallbacks.find(deviceId);
+        if (runtimeSensorCallback == mRuntimeSensorCallbacks.end()) {
+            ALOGE("Runtime sensor callback for deviceId %d not found", deviceId);
+        } else {
+            int fd = dup(clone->data[0]);
+            channelHandle = runtimeSensorCallback->second->onDirectChannelCreated(fd);
+        }
+    }
 
     if (channelHandle <= 0) {
         ALOGE("SensorDevice::registerDirectChannel returns %d", channelHandle);
     } else {
         mem.handle = clone;
-        conn = new SensorDirectConnection(this, uid, &mem, channelHandle, opPackageName);
+        conn = new SensorDirectConnection(this, uid, &mem, channelHandle, opPackageName, deviceId);
     }
 
     if (conn == nullptr) {
@@ -1614,6 +1643,24 @@
     return conn;
 }
 
+int SensorService::configureRuntimeSensorDirectChannel(
+        int sensorHandle, const SensorDirectConnection* c, const sensors_direct_cfg_t* config) {
+    int deviceId = c->getDeviceId();
+    int sensorDeviceId = getDeviceIdFromHandle(sensorHandle);
+    if (sensorDeviceId != c->getDeviceId()) {
+        ALOGE("Cannot configure direct channel created for device %d with a sensor that belongs"
+              "to device %d", c->getDeviceId(), sensorDeviceId);
+        return BAD_VALUE;
+    }
+    auto runtimeSensorCallback = mRuntimeSensorCallbacks.find(deviceId);
+    if (runtimeSensorCallback == mRuntimeSensorCallbacks.end()) {
+        ALOGE("Runtime sensor callback for deviceId %d not found", deviceId);
+        return BAD_VALUE;
+    }
+    return runtimeSensorCallback->second->onDirectChannelConfigured(
+            c->getHalChannelHandle(), sensorHandle, config->rate_level);
+}
+
 int SensorService::setOperationParameter(
             int32_t handle, int32_t type,
             const Vector<float> &floats, const Vector<int32_t> &ints) {
@@ -1769,8 +1816,18 @@
 void SensorService::cleanupConnection(SensorDirectConnection* c) {
     Mutex::Autolock _l(mLock);
 
-    SensorDevice& dev(SensorDevice::getInstance());
-    dev.unregisterDirectChannel(c->getHalChannelHandle());
+    int deviceId = c->getDeviceId();
+    if (deviceId == RuntimeSensor::DEFAULT_DEVICE_ID) {
+        SensorDevice& dev(SensorDevice::getInstance());
+        dev.unregisterDirectChannel(c->getHalChannelHandle());
+    } else {
+        auto runtimeSensorCallback = mRuntimeSensorCallbacks.find(deviceId);
+        if (runtimeSensorCallback != mRuntimeSensorCallbacks.end()) {
+            runtimeSensorCallback->second->onDirectChannelDestroyed(c->getHalChannelHandle());
+        } else {
+            ALOGE("Runtime sensor callback for deviceId %d not found", deviceId);
+        }
+    }
     mConnectionHolder.removeDirectConnection(c);
 }
 
@@ -1848,6 +1905,19 @@
     return mSensors.getInterface(handle);
 }
 
+int SensorService::getDeviceIdFromHandle(int handle) const {
+    int deviceId = RuntimeSensor::DEFAULT_DEVICE_ID;
+    mSensors.forEachEntry(
+            [&deviceId, handle] (const SensorServiceUtil::SensorList::Entry& e) -> bool {
+                if (e.si->getSensor().getHandle() == handle) {
+                    deviceId = e.deviceId;
+                    return false;  // stop iterating
+                }
+                return true;
+            });
+    return deviceId;
+}
+
 status_t SensorService::enable(const sp<SensorEventConnection>& connection,
         int handle, nsecs_t samplingPeriodNs, nsecs_t maxBatchReportLatencyNs, int reservedFlags,
         const String16& opPackageName) {
diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h
index 3f6a895..fe72a69 100644
--- a/services/sensorservice/SensorService.h
+++ b/services/sensorservice/SensorService.h
@@ -154,6 +154,10 @@
         virtual status_t onConfigurationChanged(int handle, bool enabled,
                                                 int64_t samplingPeriodNanos,
                                                 int64_t batchReportLatencyNanos) = 0;
+        virtual int onDirectChannelCreated(int fd) = 0;
+        virtual void onDirectChannelDestroyed(int channelHandle) = 0;
+        virtual int onDirectChannelConfigured(int channelHandle, int sensorHandle,
+                                              int rateLevel) = 0;
     };
 
     static char const* getServiceName() ANDROID_API { return "sensorservice"; }
@@ -187,6 +191,9 @@
     status_t unregisterRuntimeSensor(int handle) ANDROID_API;
     status_t sendRuntimeSensorEvent(const sensors_event_t& event) ANDROID_API;
 
+    int configureRuntimeSensorDirectChannel(int sensorHandle, const SensorDirectConnection* c,
+                                            const sensors_direct_cfg_t* config);
+
     // Returns true if a sensor should be throttled according to our rate-throttling rules.
     static bool isSensorInCappedSet(int sensorType);
 
@@ -370,7 +377,8 @@
             int requestedMode, const String16& opPackageName, const String16& attributionTag);
     virtual int isDataInjectionEnabled();
     virtual sp<ISensorEventConnection> createSensorDirectConnection(const String16& opPackageName,
-            uint32_t size, int32_t type, int32_t format, const native_handle *resource);
+            int deviceId, uint32_t size, int32_t type, int32_t format,
+            const native_handle *resource);
     virtual int setOperationParameter(
             int32_t handle, int32_t type, const Vector<float> &floats, const Vector<int32_t> &ints);
     virtual status_t dump(int fd, const Vector<String16>& args);
@@ -380,6 +388,7 @@
     String8 getSensorStringType(int handle) const;
     bool isVirtualSensor(int handle) const;
     std::shared_ptr<SensorInterface> getSensorInterfaceFromHandle(int handle) const;
+    int getDeviceIdFromHandle(int handle) const;
     bool isWakeUpSensor(int type) const;
     void recordLastValueLocked(sensors_event_t const* buffer, size_t count);
     static void sortEventBuffer(sensors_event_t* buffer, size_t count);
@@ -517,6 +526,7 @@
     std::unordered_map<int, SensorServiceUtil::RecentEventLogger*> mRecentEvent;
     Mode mCurrentOperatingMode;
     std::queue<sensors_event_t> mRuntimeSensorEventQueue;
+    std::unordered_map</*deviceId*/int, sp<RuntimeSensorCallback>> mRuntimeSensorCallbacks;
 
     // true if the head tracker sensor type is currently restricted to system usage only
     // (can only be unrestricted for testing, via shell cmd)
diff --git a/services/surfaceflinger/FrontEnd/LayerHierarchy.cpp b/services/surfaceflinger/FrontEnd/LayerHierarchy.cpp
index 14d67c6..c30465f 100644
--- a/services/surfaceflinger/FrontEnd/LayerHierarchy.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerHierarchy.cpp
@@ -130,6 +130,14 @@
     return mLayer;
 }
 
+const LayerHierarchy* LayerHierarchy::getRelativeParent() const {
+    return mRelativeParent;
+}
+
+const LayerHierarchy* LayerHierarchy::getParent() const {
+    return mParent;
+}
+
 std::string LayerHierarchy::getDebugStringShort() const {
     std::string debug = "LayerHierarchy{";
     debug += ((mLayer) ? mLayer->getDebugString() : "root") + " ";
diff --git a/services/surfaceflinger/FrontEnd/LayerHierarchy.h b/services/surfaceflinger/FrontEnd/LayerHierarchy.h
index 0f700a9..3dd89ba 100644
--- a/services/surfaceflinger/FrontEnd/LayerHierarchy.h
+++ b/services/surfaceflinger/FrontEnd/LayerHierarchy.h
@@ -144,6 +144,8 @@
     }
 
     const RequestedLayerState* getLayer() const;
+    const LayerHierarchy* getRelativeParent() const;
+    const LayerHierarchy* getParent() const;
     std::string getDebugString(const char* prefix = "") const;
     std::string getDebugStringShort() const;
     // Traverse the hierarchy and return true if loops are found. The outInvalidRelativeRoot
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp
index 85b00d7..8a45093 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp
@@ -27,12 +27,16 @@
 LayerSnapshot::LayerSnapshot(const RequestedLayerState& state,
                              const LayerHierarchy::TraversalPath& path)
       : path(path) {
+    static uint32_t sUniqueSequenceId = 0;
+    // Provide a unique id for clones otherwise keeping using the sequence id.
+    // The seq id can still be useful for debugging if its available.
+    uniqueSequence = (path.isClone()) ? sUniqueSequenceId++ : state.id;
     sequence = static_cast<int32_t>(state.id);
     name = state.name;
     textureName = state.textureName;
     premultipliedAlpha = state.premultipliedAlpha;
     inputInfo.name = state.name;
-    inputInfo.id = static_cast<int32_t>(state.id);
+    inputInfo.id = static_cast<int32_t>(uniqueSequence);
     inputInfo.ownerUid = static_cast<int32_t>(state.ownerUid);
     inputInfo.ownerPid = state.ownerPid;
     changes = RequestedLayerState::Changes::Created;
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshot.h b/services/surfaceflinger/FrontEnd/LayerSnapshot.h
index 07aa122..e069a63 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshot.h
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshot.h
@@ -57,6 +57,12 @@
     bool isHiddenByPolicyFromParent = false;
     bool isHiddenByPolicyFromRelativeParent = false;
     ftl::Flags<RequestedLayerState::Changes> changes;
+    // Some consumers of this snapshot (input, layer traces) rely on each snapshot to be unique.
+    // For mirrored layers, snapshots will have the same sequence so this unique id provides
+    // an alternative identifier when needed.
+    uint32_t uniqueSequence;
+    // Layer id used to create this snapshot. Multiple snapshots will have the same sequence if they
+    // generated from the same layer, for example when mirroring.
     int32_t sequence;
     std::string name;
     uint32_t textureName;
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
index db6e716..344dab4 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
@@ -957,7 +957,7 @@
     }
 
     snapshot.inputInfo.name = requested.name;
-    snapshot.inputInfo.id = static_cast<int32_t>(requested.id);
+    snapshot.inputInfo.id = static_cast<int32_t>(snapshot.uniqueSequence);
     snapshot.inputInfo.ownerUid = static_cast<int32_t>(requested.ownerUid);
     snapshot.inputInfo.ownerPid = requested.ownerPid;
     snapshot.inputInfo.displayId = static_cast<int32_t>(snapshot.outputFilter.layerStack.id);
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 5a4193d..433606a 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -2096,15 +2096,7 @@
     writeToProtoCommonState(layerProto, LayerVector::StateSet::Drawing, traceFlags);
 
     if (traceFlags & LayerTracing::TRACE_COMPOSITION) {
-        ftl::FakeGuard guard(mFlinger->mStateLock); // Called from the main thread.
-
-        // Only populate for the primary display.
-        if (const auto display = mFlinger->getDefaultDisplayDeviceLocked()) {
-            const auto compositionType = getCompositionType(*display);
-            layerProto->set_hwc_composition_type(static_cast<HwcCompositionType>(compositionType));
-            LayerProtoHelper::writeToProto(getVisibleRegion(display.get()),
-                                           [&]() { return layerProto->mutable_visible_region(); });
-        }
+        writeCompositionStateToProto(layerProto);
     }
 
     for (const sp<Layer>& layer : mDrawingChildren) {
@@ -2114,6 +2106,18 @@
     return layerProto;
 }
 
+void Layer::writeCompositionStateToProto(LayerProto* layerProto) {
+    ftl::FakeGuard guard(mFlinger->mStateLock); // Called from the main thread.
+
+    // Only populate for the primary display.
+    if (const auto display = mFlinger->getDefaultDisplayDeviceLocked()) {
+        const auto compositionType = getCompositionType(*display);
+        layerProto->set_hwc_composition_type(static_cast<HwcCompositionType>(compositionType));
+        LayerProtoHelper::writeToProto(getVisibleRegion(display.get()),
+                                       [&]() { return layerProto->mutable_visible_region(); });
+    }
+}
+
 void Layer::writeToProtoDrawingState(LayerProto* layerInfo) {
     const ui::Transform transform = getTransform();
     auto buffer = getExternalTexture();
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 597f8ad..4309aca 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -608,6 +608,7 @@
     bool isRemovedFromCurrentState() const;
 
     LayerProto* writeToProto(LayersProto& layersProto, uint32_t traceFlags);
+    void writeCompositionStateToProto(LayerProto* layerProto);
 
     // Write states that are modified by the main thread. This includes drawing
     // state as well as buffer data. This should be called in the main or tracing
diff --git a/services/surfaceflinger/LayerProtoHelper.cpp b/services/surfaceflinger/LayerProtoHelper.cpp
index 0506c47..55281fa 100644
--- a/services/surfaceflinger/LayerProtoHelper.cpp
+++ b/services/surfaceflinger/LayerProtoHelper.cpp
@@ -247,6 +247,153 @@
     outRegion.right = proto.right();
     outRegion.bottom = proto.bottom();
 }
+
+void LayerProtoHelper::writeHierarchyToProto(
+        LayersProto& outLayersProto, const frontend::LayerHierarchy& root,
+        const frontend::LayerSnapshotBuilder& snapshotBuilder,
+        const std::unordered_map<uint32_t, sp<Layer>>& legacyLayers, uint32_t traceFlags) {
+    using Variant = frontend::LayerHierarchy::Variant;
+    frontend::LayerSnapshot defaultSnapshot;
+
+    LayerProto* layerProto = outLayersProto.add_layers();
+    const frontend::RequestedLayerState& layer = *root.getLayer();
+    frontend::LayerSnapshot* snapshot = snapshotBuilder.getSnapshot(layer.id);
+
+    if (!snapshot) {
+        defaultSnapshot.uniqueSequence = layer.id;
+        snapshot = &defaultSnapshot;
+    }
+    writeSnapshotToProto(layerProto, layer, *snapshot, traceFlags);
+    for (const auto& [child, variant] : root.mChildren) {
+        if (variant == Variant::Attached || variant == Variant::Detached) {
+            layerProto->add_children(child->getLayer()->id);
+        } else if (variant == Variant::Relative) {
+            layerProto->add_relatives(child->getLayer()->id);
+        }
+    }
+
+    auto parent = root.getParent();
+    if (parent && parent->getLayer()) {
+        layerProto->set_parent(parent->getLayer()->id);
+    } else {
+        layerProto->set_parent(-1);
+    }
+
+    auto relativeParent = root.getRelativeParent();
+    if (relativeParent && relativeParent->getLayer()) {
+        layerProto->set_z_order_relative_of(relativeParent->getLayer()->id);
+    } else {
+        layerProto->set_z_order_relative_of(-1);
+    }
+
+    if (traceFlags & LayerTracing::TRACE_COMPOSITION) {
+        auto it = legacyLayers.find(layer.id);
+        if (it != legacyLayers.end()) {
+            it->second->writeCompositionStateToProto(layerProto);
+        }
+    }
+
+    for (const auto& [child, variant] : root.mChildren) {
+        // avoid visiting relative layers twice
+        if (variant == Variant::Detached) {
+            continue;
+        }
+        writeHierarchyToProto(outLayersProto, *child, snapshotBuilder, legacyLayers, traceFlags);
+    }
+}
+
+void LayerProtoHelper::writeSnapshotToProto(LayerProto* layerInfo,
+                                            const frontend::RequestedLayerState& requestedState,
+                                            const frontend::LayerSnapshot& snapshot,
+                                            uint32_t traceFlags) {
+    const ui::Transform transform = snapshot.geomLayerTransform;
+    auto buffer = requestedState.externalTexture;
+    if (buffer != nullptr) {
+        LayerProtoHelper::writeToProto(*buffer,
+                                       [&]() { return layerInfo->mutable_active_buffer(); });
+        LayerProtoHelper::writeToProtoDeprecated(ui::Transform(requestedState.bufferTransform),
+                                                 layerInfo->mutable_buffer_transform());
+    }
+    layerInfo->set_invalidate(snapshot.contentDirty);
+    layerInfo->set_is_protected(snapshot.hasProtectedContent);
+    layerInfo->set_dataspace(dataspaceDetails(static_cast<android_dataspace>(snapshot.dataspace)));
+    layerInfo->set_curr_frame(requestedState.bufferData->frameNumber);
+    layerInfo->set_requested_corner_radius(requestedState.cornerRadius);
+    layerInfo->set_corner_radius(
+            (snapshot.roundedCorner.radius.x + snapshot.roundedCorner.radius.y) / 2.0);
+    layerInfo->set_background_blur_radius(snapshot.backgroundBlurRadius);
+    layerInfo->set_is_trusted_overlay(snapshot.isTrustedOverlay);
+    LayerProtoHelper::writeToProtoDeprecated(transform, layerInfo->mutable_transform());
+    LayerProtoHelper::writePositionToProto(transform.tx(), transform.ty(),
+                                           [&]() { return layerInfo->mutable_position(); });
+    LayerProtoHelper::writeToProto(snapshot.geomLayerBounds,
+                                   [&]() { return layerInfo->mutable_bounds(); });
+    LayerProtoHelper::writeToProto(snapshot.surfaceDamage,
+                                   [&]() { return layerInfo->mutable_damage_region(); });
+
+    if (requestedState.hasColorTransform) {
+        LayerProtoHelper::writeToProto(snapshot.colorTransform,
+                                       layerInfo->mutable_color_transform());
+    }
+
+    LayerProtoHelper::writeToProto(snapshot.croppedBufferSize.toFloatRect(),
+                                   [&]() { return layerInfo->mutable_source_bounds(); });
+    LayerProtoHelper::writeToProto(snapshot.transformedBounds,
+                                   [&]() { return layerInfo->mutable_screen_bounds(); });
+    LayerProtoHelper::writeToProto(snapshot.roundedCorner.cropRect,
+                                   [&]() { return layerInfo->mutable_corner_radius_crop(); });
+    layerInfo->set_shadow_radius(snapshot.shadowRadius);
+
+    layerInfo->set_id(snapshot.uniqueSequence);
+    layerInfo->set_name(requestedState.name);
+    layerInfo->set_type("Layer");
+
+    LayerProtoHelper::writeToProto(requestedState.transparentRegion,
+                                   [&]() { return layerInfo->mutable_transparent_region(); });
+
+    layerInfo->set_layer_stack(snapshot.outputFilter.layerStack.id);
+    layerInfo->set_z(requestedState.z);
+
+    ui::Transform requestedTransform = requestedState.getTransform(0);
+    LayerProtoHelper::writePositionToProto(requestedTransform.tx(), requestedTransform.ty(), [&]() {
+        return layerInfo->mutable_requested_position();
+    });
+
+    LayerProtoHelper::writeToProto(requestedState.crop,
+                                   [&]() { return layerInfo->mutable_crop(); });
+
+    layerInfo->set_is_opaque(snapshot.contentOpaque);
+    if (requestedState.externalTexture)
+        layerInfo->set_pixel_format(
+                decodePixelFormat(requestedState.externalTexture->getPixelFormat()));
+    LayerProtoHelper::writeToProto(snapshot.color, [&]() { return layerInfo->mutable_color(); });
+    LayerProtoHelper::writeToProto(requestedState.color,
+                                   [&]() { return layerInfo->mutable_requested_color(); });
+    layerInfo->set_flags(requestedState.flags);
+
+    LayerProtoHelper::writeToProtoDeprecated(requestedTransform,
+                                             layerInfo->mutable_requested_transform());
+
+    layerInfo->set_is_relative_of(requestedState.isRelativeOf);
+
+    layerInfo->set_owner_uid(requestedState.ownerUid);
+
+    if ((traceFlags & LayerTracing::TRACE_INPUT) && snapshot.hasInputInfo()) {
+        LayerProtoHelper::writeToProto(snapshot.inputInfo, {},
+                                       [&]() { return layerInfo->mutable_input_window_info(); });
+    }
+
+    if (traceFlags & LayerTracing::TRACE_EXTRA) {
+        auto protoMap = layerInfo->mutable_metadata();
+        for (const auto& entry : requestedState.metadata.mMap) {
+            (*protoMap)[entry.first] = std::string(entry.second.cbegin(), entry.second.cend());
+        }
+    }
+
+    LayerProtoHelper::writeToProto(requestedState.destinationFrame,
+                                   [&]() { return layerInfo->mutable_destination_frame(); });
+}
+
 } // namespace surfaceflinger
 } // namespace android
 
diff --git a/services/surfaceflinger/LayerProtoHelper.h b/services/surfaceflinger/LayerProtoHelper.h
index 6ade143..de4bd01 100644
--- a/services/surfaceflinger/LayerProtoHelper.h
+++ b/services/surfaceflinger/LayerProtoHelper.h
@@ -58,6 +58,15 @@
     static void readFromProto(const ColorTransformProto& colorTransformProto, mat4& matrix);
     static void writeToProto(const android::BlurRegion region, BlurRegion*);
     static void readFromProto(const BlurRegion& proto, android::BlurRegion& outRegion);
+    static void writeHierarchyToProto(LayersProto& layersProto,
+                                      const frontend::LayerHierarchy& root,
+                                      const frontend::LayerSnapshotBuilder& snapshotBuilder,
+                                      const std::unordered_map<uint32_t, sp<Layer>>& mLegacyLayers,
+                                      uint32_t traceFlags);
+
+    static void writeSnapshotToProto(LayerProto* outProto,
+                                     const frontend::RequestedLayerState& requestedState,
+                                     const frontend::LayerSnapshot& snapshot, uint32_t traceFlags);
 };
 
 } // namespace surfaceflinger
diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp
index 839500f..327ca3f 100644
--- a/services/surfaceflinger/RegionSamplingThread.cpp
+++ b/services/surfaceflinger/RegionSamplingThread.cpp
@@ -285,46 +285,72 @@
 
     std::unordered_set<sp<IRegionSamplingListener>, SpHash<IRegionSamplingListener>> listeners;
 
-    auto traverseLayers = [&](const LayerVector::Visitor& visitor) {
-        bool stopLayerFound = false;
-        auto filterVisitor = [&](Layer* layer) {
-            // We don't want to capture any layers beyond the stop layer
-            if (stopLayerFound) return;
+    auto layerFilterFn = [&](const char* layerName, uint32_t layerId, const Rect& bounds,
+                             const ui::Transform transform, bool& outStopTraversal) -> bool {
+        // Likewise if we just found a stop layer, set the flag and abort
+        for (const auto& [area, stopLayerId, listener] : descriptors) {
+            if (stopLayerId != UNASSIGNED_LAYER_ID && layerId == stopLayerId) {
+                outStopTraversal = true;
+                return false;
+            }
+        }
 
-            // Likewise if we just found a stop layer, set the flag and abort
-            for (const auto& [area, stopLayerId, listener] : descriptors) {
-                if (stopLayerId != UNASSIGNED_LAYER_ID && layer->getSequence() == stopLayerId) {
-                    stopLayerFound = true;
+        // Compute the layer's position on the screen
+        constexpr bool roundOutwards = true;
+        Rect transformed = transform.transform(bounds, roundOutwards);
+
+        // If this layer doesn't intersect with the larger sampledBounds, skip capturing it
+        Rect ignore;
+        if (!transformed.intersect(sampledBounds, &ignore)) return false;
+
+        // If the layer doesn't intersect a sampling area, skip capturing it
+        bool intersectsAnyArea = false;
+        for (const auto& [area, stopLayer, listener] : descriptors) {
+            if (transformed.intersect(area, &ignore)) {
+                intersectsAnyArea = true;
+                listeners.insert(listener);
+            }
+        }
+        if (!intersectsAnyArea) return false;
+
+        ALOGV("Traversing [%s] [%d, %d, %d, %d]", layerName, bounds.left, bounds.top, bounds.right,
+              bounds.bottom);
+
+        return true;
+    };
+
+    std::function<std::vector<std::pair<Layer*, sp<LayerFE>>>()> getLayerSnapshots;
+    if (mFlinger.mLayerLifecycleManagerEnabled) {
+        auto filterFn = [&](const frontend::LayerSnapshot& snapshot,
+                            bool& outStopTraversal) -> bool {
+            const Rect bounds =
+                    frontend::RequestedLayerState::reduce(Rect(snapshot.geomLayerBounds),
+                                                          snapshot.transparentRegionHint);
+            const ui::Transform transform = snapshot.geomLayerTransform;
+            return layerFilterFn(snapshot.name.c_str(), snapshot.path.id, bounds, transform,
+                                 outStopTraversal);
+        };
+        getLayerSnapshots =
+                mFlinger.getLayerSnapshotsForScreenshots(layerStack, CaptureArgs::UNSET_UID,
+                                                         filterFn);
+    } else {
+        auto traverseLayers = [&](const LayerVector::Visitor& visitor) {
+            bool stopLayerFound = false;
+            auto filterVisitor = [&](Layer* layer) {
+                // We don't want to capture any layers beyond the stop layer
+                if (stopLayerFound) return;
+
+                if (!layerFilterFn(layer->getDebugName(), layer->getSequence(),
+                                   Rect(layer->getBounds()), layer->getTransform(),
+                                   stopLayerFound)) {
                     return;
                 }
-            }
-
-            // Compute the layer's position on the screen
-            const Rect bounds = Rect(layer->getBounds());
-            const ui::Transform transform = layer->getTransform();
-            constexpr bool roundOutwards = true;
-            Rect transformed = transform.transform(bounds, roundOutwards);
-
-            // If this layer doesn't intersect with the larger sampledBounds, skip capturing it
-            Rect ignore;
-            if (!transformed.intersect(sampledBounds, &ignore)) return;
-
-            // If the layer doesn't intersect a sampling area, skip capturing it
-            bool intersectsAnyArea = false;
-            for (const auto& [area, stopLayer, listener] : descriptors) {
-                if (transformed.intersect(area, &ignore)) {
-                    intersectsAnyArea = true;
-                    listeners.insert(listener);
-                }
-            }
-            if (!intersectsAnyArea) return;
-
-            ALOGV("Traversing [%s] [%d, %d, %d, %d]", layer->getDebugName(), bounds.left,
-                  bounds.top, bounds.right, bounds.bottom);
-            visitor(layer);
+                visitor(layer);
+            };
+            mFlinger.traverseLayersInLayerStack(layerStack, CaptureArgs::UNSET_UID, filterVisitor);
         };
-        mFlinger.traverseLayersInLayerStack(layerStack, CaptureArgs::UNSET_UID, filterVisitor);
-    };
+        getLayerSnapshots = RenderArea::fromTraverseLayersLambda(traverseLayers);
+    }
 
     std::shared_ptr<renderengine::ExternalTexture> buffer = nullptr;
     if (mCachedBuffer && mCachedBuffer->getBuffer()->getWidth() == sampledBounds.getWidth() &&
@@ -344,7 +370,6 @@
                                                      renderengine::impl::ExternalTexture::Usage::
                                                              WRITEABLE);
     }
-    auto getLayerSnapshots = RenderArea::fromTraverseLayersLambda(traverseLayers);
 
     constexpr bool kRegionSampling = true;
     constexpr bool kGrayscale = false;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index dbaf1fb..eecfeb6 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -2275,12 +2275,13 @@
             mLayerLifecycleManager.commitChanges();
         }
 
+        commitTransactions();
+
         // enter boot animation on first buffer latch
         if (CC_UNLIKELY(mBootStage == BootStage::BOOTLOADER && newDataLatched)) {
             ALOGI("Enter boot animation");
             mBootStage = BootStage::BOOTANIMATION;
         }
-        commitTransactions();
     }
     mustComposite |= (getTransactionFlags() & ~eTransactionFlushNeeded) || newDataLatched;
     return mustComposite;
@@ -5227,8 +5228,18 @@
     const sp<IBinder> token = display->getDisplayToken().promote();
     LOG_ALWAYS_FATAL_IF(token == nullptr);
 
+    TransactionState state;
+    state.inputWindowCommands = mInputWindowCommands;
+    nsecs_t now = systemTime();
+    state.desiredPresentTime = now;
+    state.postTime = now;
+    state.permissions = layer_state_t::ACCESS_SURFACE_FLINGER;
+    state.originPid = mPid;
+    state.originUid = static_cast<int>(getuid());
+    uint64_t transactionId = (((uint64_t)mPid) << 32) | mUniqueTransactionId++;
+    state.id = transactionId;
+
     // reset screen orientation and use primary layer stack
-    std::vector<ResolvedComposerState> state;
     Vector<DisplayState> displays;
     DisplayState d;
     d.what = DisplayState::eDisplayProjectionChanged |
@@ -5240,15 +5251,17 @@
     d.layerStackSpaceRect.makeInvalid();
     d.width = 0;
     d.height = 0;
-    displays.add(d);
+    state.displays.add(d);
 
-    nsecs_t now = systemTime();
+    std::vector<TransactionState> transactions;
+    transactions.emplace_back(state);
 
-    int64_t transactionId = (((int64_t)mPid) << 32) | mUniqueTransactionId++;
     // It should be on the main thread, apply it directly.
-    applyTransactionState(FrameTimelineInfo{}, state, displays, 0, mInputWindowCommands,
-                          /* desiredPresentTime */ now, true, {}, /* postTime */ now, true, false,
-                          {}, mPid, getuid(), transactionId);
+    if (mLegacyFrontEndEnabled) {
+        applyTransactionsLocked(transactions, /*vsyncId=*/{0});
+    } else {
+        applyAndCommitDisplayTransactionStates(transactions);
+    }
 
     setPowerModeInternal(display, hal::PowerMode::ON);
 }
@@ -5687,14 +5700,27 @@
         }
     }
 
-    LayersProto layersProto;
-    for (const sp<Layer>& layer : mDrawingState.layersSortedByZ) {
-        if (stackIdsToSkip.find(layer->getLayerStack().id) != stackIdsToSkip.end()) {
-            continue;
+    if (mLegacyFrontEndEnabled) {
+        LayersProto layersProto;
+        for (const sp<Layer>& layer : mDrawingState.layersSortedByZ) {
+            if (stackIdsToSkip.find(layer->getLayerStack().id) != stackIdsToSkip.end()) {
+                continue;
+            }
+            layer->writeToProto(layersProto, traceFlags);
         }
-        layer->writeToProto(layersProto, traceFlags);
+        return layersProto;
     }
 
+    const frontend::LayerHierarchy& root = mLayerHierarchyBuilder.getHierarchy();
+    LayersProto layersProto;
+    for (auto& [child, variant] : root.mChildren) {
+        if (variant != frontend::LayerHierarchy::Variant::Attached ||
+            stackIdsToSkip.find(child->getLayer()->layerStack.id) != stackIdsToSkip.end()) {
+            continue;
+        }
+        LayerProtoHelper::writeHierarchyToProto(layersProto, *child, mLayerSnapshotBuilder,
+                                                mLegacyLayers, traceFlags);
+    }
     return layersProto;
 }
 
@@ -6776,7 +6802,8 @@
 
     GetLayerSnapshotsFunction getLayerSnapshots;
     if (mLayerLifecycleManagerEnabled) {
-        getLayerSnapshots = getLayerSnapshotsForScreenshots(layerStack, args.uid);
+        getLayerSnapshots =
+                getLayerSnapshotsForScreenshots(layerStack, args.uid, /*snapshotFilterFn=*/nullptr);
     } else {
         auto traverseLayers = [this, args, layerStack](const LayerVector::Visitor& visitor) {
             traverseLayersInLayerStack(layerStack, args.uid, visitor);
@@ -6818,7 +6845,8 @@
 
     GetLayerSnapshotsFunction getLayerSnapshots;
     if (mLayerLifecycleManagerEnabled) {
-        getLayerSnapshots = getLayerSnapshotsForScreenshots(layerStack, CaptureArgs::UNSET_UID);
+        getLayerSnapshots = getLayerSnapshotsForScreenshots(layerStack, CaptureArgs::UNSET_UID,
+                                                            /*snapshotFilterFn=*/nullptr);
     } else {
         auto traverseLayers = [this, layerStack](const LayerVector::Visitor& visitor) {
             traverseLayersInLayerStack(layerStack, CaptureArgs::UNSET_UID, visitor);
@@ -7847,12 +7875,18 @@
 }
 
 std::function<std::vector<std::pair<Layer*, sp<LayerFE>>>()>
-SurfaceFlinger::getLayerSnapshotsForScreenshots(std::optional<ui::LayerStack> layerStack,
-                                                uint32_t uid) {
+SurfaceFlinger::getLayerSnapshotsForScreenshots(
+        std::optional<ui::LayerStack> layerStack, uint32_t uid,
+        std::function<bool(const frontend::LayerSnapshot&, bool& outStopTraversal)>
+                snapshotFilterFn) {
     return [&, layerStack, uid]() {
         std::vector<std::pair<Layer*, sp<LayerFE>>> layers;
+        bool stopTraversal = false;
         mLayerSnapshotBuilder.forEachVisibleSnapshot(
                 [&](std::unique_ptr<frontend::LayerSnapshot>& snapshot) {
+                    if (stopTraversal) {
+                        return;
+                    }
                     if (layerStack && snapshot->outputFilter.layerStack != *layerStack) {
                         return;
                     }
@@ -7862,6 +7896,9 @@
                     if (!snapshot->hasSomethingToDraw()) {
                         return;
                     }
+                    if (snapshotFilterFn && !snapshotFilterFn(*snapshot, stopTraversal)) {
+                        return;
+                    }
 
                     auto it = mLegacyLayers.find(snapshot->sequence);
                     LOG_ALWAYS_FATAL_IF(it == mLegacyLayers.end(),
@@ -7900,7 +7937,8 @@
                      .genericLayerMetadataKeyMap = getGenericLayerMetadataKeyMap()};
         mLayerSnapshotBuilder.update(args);
 
-        auto getLayerSnapshotsFn = getLayerSnapshotsForScreenshots({}, uid);
+        auto getLayerSnapshotsFn =
+                getLayerSnapshotsForScreenshots({}, uid, /*snapshotFilterFn=*/nullptr);
         std::vector<std::pair<Layer*, sp<LayerFE>>> layers = getLayerSnapshotsFn();
         args.root = mLayerHierarchyBuilder.getHierarchy();
         args.parentCrop.reset();
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 094b2cc..b353a48 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -1396,7 +1396,9 @@
                 [](const auto& display) { return display.isRefreshRateOverlayEnabled(); });
     }
     std::function<std::vector<std::pair<Layer*, sp<LayerFE>>>()> getLayerSnapshotsForScreenshots(
-            std::optional<ui::LayerStack> layerStack, uint32_t uid);
+            std::optional<ui::LayerStack> layerStack, uint32_t uid,
+            std::function<bool(const frontend::LayerSnapshot&, bool& outStopTraversal)>
+                    snapshotFilterFn);
     std::function<std::vector<std::pair<Layer*, sp<LayerFE>>>()> getLayerSnapshotsForScreenshots(
             uint32_t rootLayerId, uint32_t uid, std::unordered_set<uint32_t> excludeLayerIds,
             bool childrenOnly, const FloatRect& parentCrop);