Merge "Replace duplicate with onWindowInfosChanged" into main
diff --git a/libs/gui/FrameTimestamps.cpp b/libs/gui/FrameTimestamps.cpp
index f3eb4e8..afb09de 100644
--- a/libs/gui/FrameTimestamps.cpp
+++ b/libs/gui/FrameTimestamps.cpp
@@ -255,7 +255,6 @@
         uint64_t frameNumber, std::shared_ptr<FenceTime>&& acquire) {
     FrameEvents* frame = getFrame(frameNumber, &mAcquireOffset);
     if (frame == nullptr) {
-        ALOGE("updateAcquireFence: Did not find frame.");
         return;
     }
 
diff --git a/libs/nativewindow/TEST_MAPPING b/libs/nativewindow/TEST_MAPPING
index 3d7f3c2..9d6425b 100644
--- a/libs/nativewindow/TEST_MAPPING
+++ b/libs/nativewindow/TEST_MAPPING
@@ -1,7 +1,13 @@
 {
   "presubmit": [
     {
+      "name": "libnativewindow_bindgen_test"
+    },
+    {
       "name": "libnativewindow_test"
+    },
+    {
+      "name": "libnativewindow_rs-internal_test"
     }
   ]
 }
diff --git a/libs/nativewindow/rust/Android.bp b/libs/nativewindow/rust/Android.bp
new file mode 100644
index 0000000..dc1575c
--- /dev/null
+++ b/libs/nativewindow/rust/Android.bp
@@ -0,0 +1,87 @@
+// Copyright (C) 2023 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.
+
+package {
+    default_applicable_licenses: [
+        "frameworks_native_libs_nativewindow_license",
+    ],
+}
+
+rust_bindgen {
+    name: "libnativewindow_bindgen",
+    crate_name: "nativewindow_bindgen",
+    wrapper_src: "sys/nativewindow_bindings.h",
+    source_stem: "bindings",
+    bindgen_flags: [
+        "--constified-enum-module=AHardwareBuffer_Format",
+        "--bitfield-enum=AHardwareBuffer_UsageFlags",
+
+        "--allowlist-file=.*/nativewindow/include/.*\\.h",
+
+        "--with-derive-eq",
+        "--with-derive-partialeq",
+    ],
+    shared_libs: [
+        "libnativewindow",
+    ],
+
+    // Currently necessary for host builds
+    // TODO(b/31559095): bionic on host should define this
+    target: {
+        darwin: {
+            enabled: false,
+        },
+    },
+    min_sdk_version: "VanillaIceCream",
+}
+
+rust_test {
+    name: "libnativewindow_bindgen_test",
+    srcs: [":libnativewindow_bindgen"],
+    crate_name: "nativewindow_bindgen_test",
+    test_suites: ["general-tests"],
+    auto_gen_config: true,
+    clippy_lints: "none",
+    lints: "none",
+}
+
+rust_defaults {
+    name: "libnativewindow_defaults",
+    srcs: ["src/lib.rs"],
+    rustlibs: [
+        "libnativewindow_bindgen",
+    ],
+}
+
+rust_library {
+    name: "libnativewindow_rs",
+    crate_name: "nativewindow",
+    defaults: ["libnativewindow_defaults"],
+
+    // Currently necessary for host builds
+    // TODO(b/31559095): bionic on host should define this
+    target: {
+        darwin: {
+            enabled: false,
+        },
+    },
+    min_sdk_version: "VanillaIceCream",
+}
+
+rust_test {
+    name: "libnativewindow_rs-internal_test",
+    crate_name: "nativewindow",
+    defaults: ["libnativewindow_defaults"],
+    test_suites: ["general-tests"],
+}
diff --git a/libs/nativewindow/rust/src/lib.rs b/libs/nativewindow/rust/src/lib.rs
new file mode 100644
index 0000000..a5bcc62
--- /dev/null
+++ b/libs/nativewindow/rust/src/lib.rs
@@ -0,0 +1,260 @@
+// Copyright (C) 2023 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.
+
+//! Pleasant Rust bindings for libnativewindow, including AHardwareBuffer
+
+extern crate nativewindow_bindgen as ffi;
+
+pub use ffi::{AHardwareBuffer_Format, AHardwareBuffer_UsageFlags};
+
+use std::os::raw::c_void;
+use std::ptr;
+
+/// Wrapper around an opaque C AHardwareBuffer.
+pub struct AHardwareBuffer(*mut ffi::AHardwareBuffer);
+
+impl AHardwareBuffer {
+    /// Test whether the given format and usage flag combination is allocatable.  If this function
+    /// returns true, it means that a buffer with the given description can be allocated on this
+    /// implementation, unless resource exhaustion occurs. If this function returns false, it means
+    /// that the allocation of the given description will never succeed.
+    ///
+    /// Available since API 29
+    pub fn is_supported(
+        width: u32,
+        height: u32,
+        layers: u32,
+        format: AHardwareBuffer_Format::Type,
+        usage: AHardwareBuffer_UsageFlags,
+        stride: u32,
+    ) -> bool {
+        let buffer_desc = ffi::AHardwareBuffer_Desc {
+            width,
+            height,
+            layers,
+            format,
+            usage: usage.0,
+            stride,
+            rfu0: 0,
+            rfu1: 0,
+        };
+        // SAFETY: *buffer_desc will never be null.
+        let status = unsafe { ffi::AHardwareBuffer_isSupported(&buffer_desc) };
+
+        status == 1
+    }
+
+    /// Allocates a buffer that matches the passed AHardwareBuffer_Desc. If allocation succeeds, the
+    /// buffer can be used according to the usage flags specified in its description. If a buffer is
+    /// used in ways not compatible with its usage flags, the results are undefined and may include
+    /// program termination.
+    ///
+    /// Available since API level 26.
+    pub fn new(
+        width: u32,
+        height: u32,
+        layers: u32,
+        format: AHardwareBuffer_Format::Type,
+        usage: AHardwareBuffer_UsageFlags,
+    ) -> Option<Self> {
+        let buffer_desc = ffi::AHardwareBuffer_Desc {
+            width,
+            height,
+            layers,
+            format,
+            usage: usage.0,
+            stride: 0,
+            rfu0: 0,
+            rfu1: 0,
+        };
+        let mut buffer = ptr::null_mut();
+        // SAFETY: The returned pointer is valid until we drop/deallocate it. The function may fail
+        // and return a status, but we check it later.
+        let status = unsafe { ffi::AHardwareBuffer_allocate(&buffer_desc, &mut buffer) };
+
+        if status == 0 {
+            Some(Self(buffer))
+        } else {
+            None
+        }
+    }
+
+    /// Adopts the raw pointer and wraps it in a Rust AHardwareBuffer.
+    ///
+    /// # Errors
+    ///
+    /// Will panic if buffer_ptr is null.
+    ///
+    /// # Safety
+    ///
+    /// This function adopts the pointer but does NOT increment the refcount on the buffer. If the
+    /// caller uses the pointer after the created object is dropped it will cause a memory leak.
+    pub unsafe fn take_from_raw(buffer_ptr: *mut c_void) -> Self {
+        assert!(!buffer_ptr.is_null());
+        Self(buffer_ptr as *mut ffi::AHardwareBuffer)
+    }
+
+    /// Get the system wide unique id for an AHardwareBuffer. This function may panic in extreme
+    /// and undocumented circumstances.
+    ///
+    /// Available since API level 31.
+    pub fn id(&self) -> u64 {
+        let mut out_id = 0;
+        // SAFETY: Neither pointers can be null.
+        let status = unsafe { ffi::AHardwareBuffer_getId(self.0, &mut out_id) };
+        assert_eq!(status, 0, "id() failed for AHardwareBuffer with error code: {status}");
+
+        out_id
+    }
+
+    /// Get the width of this buffer
+    pub fn width(&self) -> u32 {
+        self.description().width
+    }
+
+    /// Get the height of this buffer
+    pub fn height(&self) -> u32 {
+        self.description().height
+    }
+
+    /// Get the number of layers of this buffer
+    pub fn layers(&self) -> u32 {
+        self.description().layers
+    }
+
+    /// Get the format of this buffer
+    pub fn format(&self) -> AHardwareBuffer_Format::Type {
+        self.description().format
+    }
+
+    /// Get the usage bitvector of this buffer
+    pub fn usage(&self) -> AHardwareBuffer_UsageFlags {
+        AHardwareBuffer_UsageFlags(self.description().usage)
+    }
+
+    /// Get the stride of this buffer
+    pub fn stride(&self) -> u32 {
+        self.description().stride
+    }
+
+    fn description(&self) -> ffi::AHardwareBuffer_Desc {
+        let mut buffer_desc = ffi::AHardwareBuffer_Desc {
+            width: 0,
+            height: 0,
+            layers: 0,
+            format: 0,
+            usage: 0,
+            stride: 0,
+            rfu0: 0,
+            rfu1: 0,
+        };
+        // SAFETY: neither the buffer nor AHardwareBuffer_Desc pointers will be null.
+        unsafe { ffi::AHardwareBuffer_describe(self.0, &mut buffer_desc) };
+        buffer_desc
+    }
+}
+
+impl Drop for AHardwareBuffer {
+    fn drop(&mut self) {
+        // SAFETY: self.0 will never be null. AHardwareBuffers allocated from within Rust will have
+        // a refcount of one, and there is a safety warning on taking an AHardwareBuffer from a raw
+        // pointer requiring callers to ensure the refcount is managed appropriately.
+        unsafe { ffi::AHardwareBuffer_release(self.0) }
+    }
+}
+
+#[cfg(test)]
+mod ahardwarebuffer_tests {
+    use super::*;
+
+    #[test]
+    fn create_valid_buffer_returns_ok() {
+        let buffer = AHardwareBuffer::new(
+            512,
+            512,
+            1,
+            AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
+            AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN,
+        );
+        assert!(buffer.is_some());
+    }
+
+    #[test]
+    fn create_invalid_buffer_returns_err() {
+        let buffer = AHardwareBuffer::new(512, 512, 1, 0, AHardwareBuffer_UsageFlags(0));
+        assert!(buffer.is_none());
+    }
+
+    #[test]
+    #[should_panic]
+    fn take_from_raw_panics_on_null() {
+        unsafe { AHardwareBuffer::take_from_raw(ptr::null_mut()) };
+    }
+
+    #[test]
+    fn take_from_raw_allows_getters() {
+        let buffer_desc = ffi::AHardwareBuffer_Desc {
+            width: 1024,
+            height: 512,
+            layers: 1,
+            format: AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
+            usage: AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN.0,
+            stride: 0,
+            rfu0: 0,
+            rfu1: 0,
+        };
+        let mut raw_buffer_ptr = ptr::null_mut();
+
+        let status = unsafe { ffi::AHardwareBuffer_allocate(&buffer_desc, &mut raw_buffer_ptr) };
+        assert_eq!(status, 0);
+
+        let buffer = unsafe { AHardwareBuffer::take_from_raw(raw_buffer_ptr as *mut c_void) };
+        assert_eq!(buffer.width(), 1024);
+    }
+
+    #[test]
+    fn basic_getters() {
+        let buffer = AHardwareBuffer::new(
+            1024,
+            512,
+            1,
+            AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
+            AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN,
+        )
+        .expect("Buffer with some basic parameters was not created successfully");
+
+        assert_eq!(buffer.width(), 1024);
+        assert_eq!(buffer.height(), 512);
+        assert_eq!(buffer.layers(), 1);
+        assert_eq!(buffer.format(), AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM);
+        assert_eq!(
+            buffer.usage(),
+            AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN
+        );
+    }
+
+    #[test]
+    fn id_getter() {
+        let buffer = AHardwareBuffer::new(
+            1024,
+            512,
+            1,
+            AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
+            AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN,
+        )
+        .expect("Buffer with some basic parameters was not created successfully");
+
+        assert_ne!(0, buffer.id());
+    }
+}
diff --git a/libs/nativewindow/rust/sys/nativewindow_bindings.h b/libs/nativewindow/rust/sys/nativewindow_bindings.h
new file mode 100644
index 0000000..e652aee
--- /dev/null
+++ b/libs/nativewindow/rust/sys/nativewindow_bindings.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2023 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 <android/data_space.h>
+#include <android/hardware_buffer.h>
+#include <android/hdr_metadata.h>
+#include <android/native_window.h>
diff --git a/opengl/libs/EGL/egl_platform_entries.cpp b/opengl/libs/EGL/egl_platform_entries.cpp
index 88001b2..440eb17 100644
--- a/opengl/libs/EGL/egl_platform_entries.cpp
+++ b/opengl/libs/EGL/egl_platform_entries.cpp
@@ -49,6 +49,7 @@
 #include "egl_trace.h"
 
 using namespace android;
+using PixelFormat = aidl::android::hardware::graphics::common::PixelFormat;
 
 // ----------------------------------------------------------------------------
 
@@ -406,7 +407,7 @@
 // ----------------------------------------------------------------------------
 
 // Translates EGL color spaces to Android data spaces.
-static android_dataspace dataSpaceFromEGLColorSpace(EGLint colorspace) {
+static android_dataspace dataSpaceFromEGLColorSpace(EGLint colorspace, PixelFormat pixelFormat) {
     if (colorspace == EGL_GL_COLORSPACE_LINEAR_KHR) {
         return HAL_DATASPACE_UNKNOWN;
     } else if (colorspace == EGL_GL_COLORSPACE_SRGB_KHR) {
@@ -424,7 +425,13 @@
     } else if (colorspace == EGL_GL_COLORSPACE_BT2020_HLG_EXT) {
         return static_cast<android_dataspace>(HAL_DATASPACE_BT2020_HLG);
     } else if (colorspace == EGL_GL_COLORSPACE_BT2020_LINEAR_EXT) {
-        return HAL_DATASPACE_BT2020_LINEAR;
+        if (pixelFormat == PixelFormat::RGBA_FP16) {
+            return static_cast<android_dataspace>(HAL_DATASPACE_STANDARD_BT2020 |
+                                                  HAL_DATASPACE_TRANSFER_LINEAR |
+                                                  HAL_DATASPACE_RANGE_EXTENDED);
+        } else {
+            return HAL_DATASPACE_BT2020_LINEAR;
+        }
     } else if (colorspace == EGL_GL_COLORSPACE_BT2020_PQ_EXT) {
         return HAL_DATASPACE_BT2020_PQ;
     }
@@ -573,8 +580,6 @@
     newList.push_back(EGL_NONE);
 }
 
-using PixelFormat = aidl::android::hardware::graphics::common::PixelFormat;
-
 // Gets the native pixel format corrsponding to the passed EGLConfig.
 void getNativePixelFormat(EGLDisplay dpy, egl_connection_t* cnx, EGLConfig config,
                           PixelFormat* format) {
@@ -714,7 +719,7 @@
             return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
         }
 
-        android_dataspace dataSpace = dataSpaceFromEGLColorSpace(colorSpace);
+        android_dataspace dataSpace = dataSpaceFromEGLColorSpace(colorSpace, format);
         // Set dataSpace even if it could be HAL_DATASPACE_UNKNOWN.
         // HAL_DATASPACE_UNKNOWN is the default value, but it may have changed
         // at this point.
diff --git a/services/inputflinger/reader/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp
index 4e72c4c..bc4cdd1 100644
--- a/services/inputflinger/reader/EventHub.cpp
+++ b/services/inputflinger/reader/EventHub.cpp
@@ -625,6 +625,36 @@
     if (readDeviceBitMask(EVIOCGSW(0), swState) < 0) {
         ALOGD("Unable to query the global switch state for %s: %s", path.c_str(), strerror(errno));
     }
+
+    // Read absolute axis info and values for all available axes for the device.
+    populateAbsoluteAxisStates();
+}
+
+void EventHub::Device::populateAbsoluteAxisStates() {
+    absState.clear();
+
+    for (int axis = 0; axis <= ABS_MAX; axis++) {
+        if (!absBitmask.test(axis)) {
+            continue;
+        }
+        struct input_absinfo info {};
+        if (ioctl(fd, EVIOCGABS(axis), &info)) {
+            ALOGE("Error reading absolute controller %d for device %s fd %d: %s", axis,
+                  identifier.name.c_str(), fd, strerror(errno));
+            continue;
+        }
+        if (info.minimum == info.maximum) {
+            continue;
+        }
+        auto& [axisInfo, value] = absState[axis];
+        axisInfo.valid = true;
+        axisInfo.minValue = info.minimum;
+        axisInfo.maxValue = info.maximum;
+        axisInfo.flat = info.flat;
+        axisInfo.fuzz = info.fuzz;
+        axisInfo.resolution = info.resolution;
+        value = info.value;
+    }
 }
 
 bool EventHub::Device::hasKeycodeLocked(int keycode) const {
@@ -762,6 +792,15 @@
                                         .code.c_str());
             break;
         }
+        case EV_ABS: {
+            auto it = absState.find(event.code);
+            LOG_ALWAYS_FATAL_IF(!currentFrameDropped && it == absState.end(),
+                                "%s: received invalid EV_ABS event code: %s", __func__,
+                                InputEventLookup::getLinuxEvdevLabel(EV_ABS, event.code, 0)
+                                        .code.c_str());
+            it->second.value = event.value;
+            break;
+        }
         case EV_SYN: {
             switch (event.code) {
                 case SYN_REPORT:
@@ -919,30 +958,6 @@
                         strerror(errno));
 }
 
-void EventHub::populateDeviceAbsoluteAxisInfo(Device& device) {
-    for (int axis = 0; axis <= ABS_MAX; axis++) {
-        if (!device.absBitmask.test(axis)) {
-            continue;
-        }
-        struct input_absinfo info {};
-        if (ioctl(device.fd, EVIOCGABS(axis), &info)) {
-            ALOGE("Error reading absolute controller %d for device %s fd %d, errno=%d", axis,
-                  device.identifier.name.c_str(), device.fd, errno);
-            continue;
-        }
-        if (info.minimum == info.maximum) {
-            continue;
-        }
-        RawAbsoluteAxisInfo& outAxisInfo = device.rawAbsoluteAxisInfoCache[axis];
-        outAxisInfo.valid = true;
-        outAxisInfo.minValue = info.minimum;
-        outAxisInfo.maxValue = info.maximum;
-        outAxisInfo.flat = info.flat;
-        outAxisInfo.fuzz = info.fuzz;
-        outAxisInfo.resolution = info.resolution;
-    }
-}
-
 InputDeviceIdentifier EventHub::getDeviceIdentifier(int32_t deviceId) const {
     std::scoped_lock _l(mLock);
     Device* device = getDeviceLocked(deviceId);
@@ -974,18 +989,21 @@
                                        RawAbsoluteAxisInfo* outAxisInfo) const {
     outAxisInfo->clear();
     if (axis < 0 || axis > ABS_MAX) {
-        return -1;
+        return NAME_NOT_FOUND;
     }
     std::scoped_lock _l(mLock);
-    Device* device = getDeviceLocked(deviceId);
+    const Device* device = getDeviceLocked(deviceId);
     if (device == nullptr) {
-        return -1;
+        return NAME_NOT_FOUND;
     }
-    auto it = device->rawAbsoluteAxisInfoCache.find(axis);
-    if (it == device->rawAbsoluteAxisInfoCache.end()) {
-        return -1;
+    // We can read the RawAbsoluteAxisInfo even if the device is disabled and doesn't have a valid
+    // fd, because the info is populated once when the device is first opened, and it doesn't change
+    // throughout the device lifecycle.
+    auto it = device->absState.find(axis);
+    if (it == device->absState.end()) {
+        return NAME_NOT_FOUND;
     }
-    *outAxisInfo = it->second;
+    *outAxisInfo = it->second.info;
     return OK;
 }
 
@@ -1101,24 +1119,20 @@
 
 status_t EventHub::getAbsoluteAxisValue(int32_t deviceId, int32_t axis, int32_t* outValue) const {
     *outValue = 0;
-
-    if (axis >= 0 && axis <= ABS_MAX) {
-        std::scoped_lock _l(mLock);
-
-        Device* device = getDeviceLocked(deviceId);
-        if (device != nullptr && device->hasValidFd() && device->absBitmask.test(axis)) {
-            struct input_absinfo info;
-            if (ioctl(device->fd, EVIOCGABS(axis), &info)) {
-                ALOGW("Error reading absolute controller %d for device %s fd %d, errno=%d", axis,
-                      device->identifier.name.c_str(), device->fd, errno);
-                return -errno;
-            }
-
-            *outValue = info.value;
-            return OK;
-        }
+    if (axis < 0 || axis > ABS_MAX) {
+        return NAME_NOT_FOUND;
     }
-    return -1;
+    std::scoped_lock _l(mLock);
+    const Device* device = getDeviceLocked(deviceId);
+    if (device == nullptr || !device->hasValidFd()) {
+        return NAME_NOT_FOUND;
+    }
+    const auto it = device->absState.find(axis);
+    if (it == device->absState.end()) {
+        return NAME_NOT_FOUND;
+    }
+    *outValue = it->second.value;
+    return OK;
 }
 
 bool EventHub::markSupportedKeyCodes(int32_t deviceId, const std::vector<int32_t>& keyCodes,
@@ -2498,9 +2512,6 @@
 
     device->configureFd();
 
-    // read absolute axis info for all available axes for the device
-    populateDeviceAbsoluteAxisInfo(*device);
-
     ALOGI("New device: id=%d, fd=%d, path='%s', name='%s', classes=%s, "
           "configuration='%s', keyLayout='%s', keyCharacterMap='%s', builtinKeyboard=%s, ",
           deviceId, fd, devicePath.c_str(), device->identifier.name.c_str(),
@@ -2852,6 +2863,31 @@
                                  device->associatedDevice
                                          ? device->associatedDevice->sysfsRootPath.c_str()
                                          : "<none>");
+            if (device->keyBitmask.any(0, KEY_MAX + 1)) {
+                const auto pressedKeys = device->keyState.dumpSetIndices(", ", [](int i) {
+                    return InputEventLookup::getLinuxEvdevLabel(EV_KEY, i, 1).code;
+                });
+                dump += StringPrintf(INDENT3 "KeyState (pressed): %s\n", pressedKeys.c_str());
+            }
+            if (device->swBitmask.any(0, SW_MAX + 1)) {
+                const auto pressedSwitches = device->swState.dumpSetIndices(", ", [](int i) {
+                    return InputEventLookup::getLinuxEvdevLabel(EV_SW, i, 1).code;
+                });
+                dump += StringPrintf(INDENT3 "SwState (pressed): %s\n", pressedSwitches.c_str());
+            }
+            if (!device->absState.empty()) {
+                std::string axisValues;
+                for (const auto& [axis, state] : device->absState) {
+                    if (!axisValues.empty()) {
+                        axisValues += ", ";
+                    }
+                    axisValues += StringPrintf("%s=%d",
+                                               InputEventLookup::getLinuxEvdevLabel(EV_ABS, axis, 0)
+                                                       .code.c_str(),
+                                               state.value);
+                }
+                dump += INDENT3 "AbsState: " + axisValues + "\n";
+            }
         }
 
         dump += INDENT "Unattached video devices:\n";
diff --git a/services/inputflinger/reader/include/EventHub.h b/services/inputflinger/reader/include/EventHub.h
index 6e647db..8347df8 100644
--- a/services/inputflinger/reader/include/EventHub.h
+++ b/services/inputflinger/reader/include/EventHub.h
@@ -19,6 +19,8 @@
 #include <bitset>
 #include <climits>
 #include <filesystem>
+#include <functional>
+#include <map>
 #include <ostream>
 #include <string>
 #include <unordered_map>
@@ -469,6 +471,20 @@
             mData[i] = std::bitset<WIDTH>(buffer[i]);
         }
     }
+    /* Dump the indices in the bit array that are set. */
+    inline std::string dumpSetIndices(std::string separator,
+                                      std::function<std::string(size_t /*index*/)> format) {
+        std::string dmp;
+        for (size_t i = 0; i < BITS; i++) {
+            if (test(i)) {
+                if (!dmp.empty()) {
+                    dmp += separator;
+                }
+                dmp += format(i);
+            }
+        }
+        return dmp.empty() ? "<none>" : dmp;
+    }
 
 private:
     std::array<std::bitset<WIDTH>, COUNT> mData;
@@ -612,7 +628,6 @@
 
         BitArray<KEY_MAX> keyBitmask;
         BitArray<KEY_MAX> keyState;
-        BitArray<ABS_MAX> absBitmask;
         BitArray<REL_MAX> relBitmask;
         BitArray<SW_MAX> swBitmask;
         BitArray<SW_MAX> swState;
@@ -620,12 +635,17 @@
         BitArray<FF_MAX> ffBitmask;
         BitArray<INPUT_PROP_MAX> propBitmask;
         BitArray<MSC_MAX> mscBitmask;
+        BitArray<ABS_MAX> absBitmask;
+        struct AxisState {
+            RawAbsoluteAxisInfo info;
+            int value;
+        };
+        std::map<int /*axis*/, AxisState> absState;
 
         std::string configurationFile;
         std::unique_ptr<PropertyMap> configuration;
         std::unique_ptr<VirtualKeyMap> virtualKeyMap;
         KeyMap keyMap;
-        std::unordered_map<int /*axis*/, RawAbsoluteAxisInfo> rawAbsoluteAxisInfoCache;
 
         bool ffEffectPlaying;
         int16_t ffEffectId; // initially -1
@@ -654,6 +674,7 @@
         status_t readDeviceBitMask(unsigned long ioctlCode, BitArray<N>& bitArray);
 
         void configureFd();
+        void populateAbsoluteAxisStates();
         bool hasKeycodeLocked(int keycode) const;
         void loadConfigurationLocked();
         bool loadVirtualKeyMapLocked();
@@ -732,13 +753,6 @@
     void addDeviceInputInotify();
     void addDeviceInotify();
 
-    /**
-     * AbsoluteAxisInfo remains unchanged for the lifetime of the device, hence
-     * we can read and store it with device
-     * @param device target device
-     */
-    static void populateDeviceAbsoluteAxisInfo(Device& device);
-
     // Protect all internal state.
     mutable std::mutex mLock;
 
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
index 7e678b9..23cfe928 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
@@ -540,7 +540,7 @@
                         primaryDisplayRotationFlags);
         snapshot->changes |= RequestedLayerState::Changes::Created;
     }
-    scheduler::LayerInfo::FrameRate oldFrameRate = snapshot->frameRate;
+
     if (traversalPath.isRelative()) {
         bool parentIsRelative = traversalPath.variant == LayerHierarchy::Variant::Relative;
         updateRelativeState(*snapshot, parentSnapshot, parentIsRelative, args);
@@ -561,9 +561,6 @@
         updateFrameRateFromChildSnapshot(*snapshot, childSnapshot, args);
     }
 
-    if (oldFrameRate == snapshot->frameRate) {
-        snapshot->changes.clear(RequestedLayerState::Changes::FrameRate);
-    }
     return *snapshot;
 }
 
@@ -670,8 +667,10 @@
                                                             const LayerSnapshot& childSnapshot,
                                                             const Args& args) {
     if (args.forceUpdate == ForceUpdateFlags::NONE &&
-        !childSnapshot.changes.any(RequestedLayerState::Changes::FrameRate |
-                                   RequestedLayerState::Changes::Hierarchy)) {
+        !args.layerLifecycleManager.getGlobalChanges().any(
+                RequestedLayerState::Changes::Hierarchy) &&
+        !childSnapshot.changes.any(RequestedLayerState::Changes::FrameRate) &&
+        !snapshot.changes.any(RequestedLayerState::Changes::FrameRate)) {
         return;
     }
 
@@ -817,6 +816,8 @@
     }
 
     if (forceUpdate ||
+        args.layerLifecycleManager.getGlobalChanges().any(
+                RequestedLayerState::Changes::Hierarchy) ||
         snapshot.changes.any(RequestedLayerState::Changes::FrameRate |
                              RequestedLayerState::Changes::Hierarchy)) {
         snapshot.frameRate = (requested.requestedFrameRate.rate.isValid() ||
@@ -824,6 +825,7 @@
                                scheduler::LayerInfo::FrameRateCompatibility::NoVote))
                 ? requested.requestedFrameRate
                 : parentSnapshot.frameRate;
+        snapshot.changes |= RequestedLayerState::Changes::FrameRate;
     }
 
     if (forceUpdate || snapshot.clientChanges & layer_state_t::eFrameRateSelectionPriority) {
diff --git a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
index 7951c33..2529095 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
@@ -1223,10 +1223,19 @@
                     (supportsFrameRateOverride() || ranges.render.includes(mode.getFps()));
         };
 
-        const auto frameRateModes = createFrameRateModes(filterModes, ranges.render);
+        auto frameRateModes = createFrameRateModes(filterModes, ranges.render);
+        if (frameRateModes.empty()) {
+            ALOGW("No matching frame rate modes for %s range. policy: %s", rangeName,
+                  policy->toString().c_str());
+            // TODO(b/292105422): Ideally DisplayManager should not send render ranges smaller than
+            // the min supported. See b/292047939.
+            //  For not we just ignore the render ranges.
+            frameRateModes = createFrameRateModes(filterModes, {});
+        }
         LOG_ALWAYS_FATAL_IF(frameRateModes.empty(),
-                            "No matching frame rate modes for %s range. policy: %s", rangeName,
-                            policy->toString().c_str());
+                            "No matching frame rate modes for %s range even after ignoring the "
+                            "render range. policy: %s",
+                            rangeName, policy->toString().c_str());
 
         const auto stringifyModes = [&] {
             std::string str;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index e339978..eb0f5ce 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -487,7 +487,7 @@
     mIgnoreHdrCameraLayers = ignore_hdr_camera_layers(false);
 
     mLayerLifecycleManagerEnabled =
-            base::GetBoolProperty("persist.debug.sf.enable_layer_lifecycle_manager"s, false);
+            base::GetBoolProperty("persist.debug.sf.enable_layer_lifecycle_manager"s, true);
     mLegacyFrontEndEnabled = !mLayerLifecycleManagerEnabled ||
             base::GetBoolProperty("persist.debug.sf.enable_legacy_frontend"s, false);
 }
diff --git a/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h b/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h
index 3234483..e475b84 100644
--- a/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h
+++ b/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h
@@ -319,6 +319,20 @@
         mLifecycleManager.applyTransactions(transactions);
     }
 
+    void setFrameRate(uint32_t id, float frameRate, int8_t compatibility,
+                      int8_t changeFrameRateStrategy) {
+        std::vector<TransactionState> transactions;
+        transactions.emplace_back();
+        transactions.back().states.push_back({});
+
+        transactions.back().states.front().state.what = layer_state_t::eFrameRateChanged;
+        transactions.back().states.front().layerId = id;
+        transactions.back().states.front().state.frameRate = frameRate;
+        transactions.back().states.front().state.frameRateCompatibility = compatibility;
+        transactions.back().states.front().state.changeFrameRateStrategy = changeFrameRateStrategy;
+        mLifecycleManager.applyTransactions(transactions);
+    }
+
     LayerLifecycleManager mLifecycleManager;
 };
 
diff --git a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
index d6c4b72..a581d5b 100644
--- a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
@@ -512,4 +512,88 @@
     EXPECT_EQ(getSnapshot({.id = 1221})->frameRateSelectionPriority, 1);
 }
 
+TEST_F(LayerSnapshotTest, framerate) {
+    setFrameRate(11, 244.f, 0, 0);
+
+    UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+    // verify parent is gets no vote
+    EXPECT_FALSE(getSnapshot({.id = 1})->frameRate.rate.isValid());
+    EXPECT_EQ(getSnapshot({.id = 1})->frameRate.type,
+              scheduler::LayerInfo::FrameRateCompatibility::NoVote);
+    EXPECT_TRUE(getSnapshot({.id = 1})->changes.test(RequestedLayerState::Changes::FrameRate));
+
+    // verify layer and children get the requested votes
+    EXPECT_TRUE(getSnapshot({.id = 11})->frameRate.rate.isValid());
+    EXPECT_EQ(getSnapshot({.id = 11})->frameRate.rate.getValue(), 244.f);
+    EXPECT_EQ(getSnapshot({.id = 11})->frameRate.type,
+              scheduler::LayerInfo::FrameRateCompatibility::Default);
+    EXPECT_TRUE(getSnapshot({.id = 11})->changes.test(RequestedLayerState::Changes::FrameRate));
+
+    EXPECT_TRUE(getSnapshot({.id = 111})->frameRate.rate.isValid());
+    EXPECT_EQ(getSnapshot({.id = 111})->frameRate.rate.getValue(), 244.f);
+    EXPECT_EQ(getSnapshot({.id = 111})->frameRate.type,
+              scheduler::LayerInfo::FrameRateCompatibility::Default);
+    EXPECT_TRUE(getSnapshot({.id = 111})->changes.test(RequestedLayerState::Changes::FrameRate));
+
+    // reparent and verify the child gets the new parent's framerate
+    reparentLayer(122, 11);
+
+    std::vector<uint32_t> expected = {1, 11, 111, 122, 1221, 12, 121, 13, 2};
+    UPDATE_AND_VERIFY(mSnapshotBuilder, expected);
+    // verify parent is gets no vote
+    EXPECT_FALSE(getSnapshot({.id = 1})->frameRate.rate.isValid());
+    EXPECT_EQ(getSnapshot({.id = 1})->frameRate.type,
+              scheduler::LayerInfo::FrameRateCompatibility::NoVote);
+
+    // verify layer and children get the requested votes
+    EXPECT_TRUE(getSnapshot({.id = 11})->frameRate.rate.isValid());
+    EXPECT_EQ(getSnapshot({.id = 11})->frameRate.rate.getValue(), 244.f);
+    EXPECT_EQ(getSnapshot({.id = 11})->frameRate.type,
+              scheduler::LayerInfo::FrameRateCompatibility::Default);
+
+    EXPECT_TRUE(getSnapshot({.id = 111})->frameRate.rate.isValid());
+    EXPECT_EQ(getSnapshot({.id = 111})->frameRate.rate.getValue(), 244.f);
+    EXPECT_EQ(getSnapshot({.id = 111})->frameRate.type,
+              scheduler::LayerInfo::FrameRateCompatibility::Default);
+
+    EXPECT_TRUE(getSnapshot({.id = 122})->frameRate.rate.isValid());
+    EXPECT_EQ(getSnapshot({.id = 122})->frameRate.rate.getValue(), 244.f);
+    EXPECT_EQ(getSnapshot({.id = 122})->frameRate.type,
+              scheduler::LayerInfo::FrameRateCompatibility::Default);
+    EXPECT_TRUE(getSnapshot({.id = 122})->changes.test(RequestedLayerState::Changes::FrameRate));
+
+    // reparent and verify the new parent gets no vote
+    reparentLayer(11, 2);
+    expected = {1, 12, 121, 13, 2, 11, 111, 122, 1221};
+    UPDATE_AND_VERIFY(mSnapshotBuilder, expected);
+
+    // verify old parent has invalid framerate (default)
+    EXPECT_FALSE(getSnapshot({.id = 1})->frameRate.rate.isValid());
+    EXPECT_EQ(getSnapshot({.id = 1})->frameRate.type,
+              scheduler::LayerInfo::FrameRateCompatibility::Default);
+    EXPECT_TRUE(getSnapshot({.id = 1})->changes.test(RequestedLayerState::Changes::FrameRate));
+
+    // verify new parent get no vote
+    EXPECT_FALSE(getSnapshot({.id = 2})->frameRate.rate.isValid());
+    EXPECT_EQ(getSnapshot({.id = 2})->frameRate.type,
+              scheduler::LayerInfo::FrameRateCompatibility::NoVote);
+    EXPECT_TRUE(getSnapshot({.id = 2})->changes.test(RequestedLayerState::Changes::FrameRate));
+
+    // verify layer and children get the requested votes (unchanged)
+    EXPECT_TRUE(getSnapshot({.id = 11})->frameRate.rate.isValid());
+    EXPECT_EQ(getSnapshot({.id = 11})->frameRate.rate.getValue(), 244.f);
+    EXPECT_EQ(getSnapshot({.id = 11})->frameRate.type,
+              scheduler::LayerInfo::FrameRateCompatibility::Default);
+
+    EXPECT_TRUE(getSnapshot({.id = 111})->frameRate.rate.isValid());
+    EXPECT_EQ(getSnapshot({.id = 111})->frameRate.rate.getValue(), 244.f);
+    EXPECT_EQ(getSnapshot({.id = 111})->frameRate.type,
+              scheduler::LayerInfo::FrameRateCompatibility::Default);
+
+    EXPECT_TRUE(getSnapshot({.id = 122})->frameRate.rate.isValid());
+    EXPECT_EQ(getSnapshot({.id = 122})->frameRate.rate.getValue(), 244.f);
+    EXPECT_EQ(getSnapshot({.id = 122})->frameRate.type,
+              scheduler::LayerInfo::FrameRateCompatibility::Default);
+}
+
 } // namespace android::surfaceflinger::frontend
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp
index d63e187..646d9cc 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp
@@ -3042,5 +3042,20 @@
     EXPECT_FRAME_RATE_MODE(kMode60, 60_Hz, selector.getBestScoredFrameRate(layers).frameRateMode);
 }
 
+TEST_P(RefreshRateSelectorTest, frameRateIsLowerThanMinSupported) {
+    if (GetParam() != Config::FrameRateOverride::Enabled) {
+        return;
+    }
+
+    auto selector = createSelector(kModes_60_90, kModeId60);
+
+    constexpr Fps kMin = RefreshRateSelector::kMinSupportedFrameRate;
+    constexpr FpsRanges kLowerThanMin = {{60_Hz, 90_Hz}, {kMin / 2, kMin / 2}};
+
+    EXPECT_EQ(SetPolicyResult::Changed,
+              selector.setDisplayManagerPolicy(
+                      {DisplayModeId(kModeId60), kLowerThanMin, kLowerThanMin}));
+}
+
 } // namespace
 } // namespace android::scheduler
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index 114f863..07b9569 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -532,7 +532,8 @@
     return native_format;
 }
 
-android_dataspace GetNativeDataspace(VkColorSpaceKHR colorspace) {
+android_dataspace GetNativeDataspace(VkColorSpaceKHR colorspace,
+                                     PixelFormat pixelFormat) {
     switch (colorspace) {
         case VK_COLOR_SPACE_SRGB_NONLINEAR_KHR:
             return HAL_DATASPACE_V0_SRGB;
@@ -551,7 +552,14 @@
         case VK_COLOR_SPACE_BT709_NONLINEAR_EXT:
             return HAL_DATASPACE_V0_SRGB;
         case VK_COLOR_SPACE_BT2020_LINEAR_EXT:
-            return HAL_DATASPACE_BT2020_LINEAR;
+            if (pixelFormat == PixelFormat::RGBA_FP16) {
+                return static_cast<android_dataspace>(
+                    HAL_DATASPACE_STANDARD_BT2020 |
+                    HAL_DATASPACE_TRANSFER_LINEAR |
+                    HAL_DATASPACE_RANGE_EXTENDED);
+            } else {
+                return HAL_DATASPACE_BT2020_LINEAR;
+            }
         case VK_COLOR_SPACE_HDR10_ST2084_EXT:
             return static_cast<android_dataspace>(
                 HAL_DATASPACE_STANDARD_BT2020 | HAL_DATASPACE_TRANSFER_ST2084 |
@@ -561,9 +569,7 @@
                 HAL_DATASPACE_STANDARD_BT2020 | HAL_DATASPACE_TRANSFER_ST2084 |
                 HAL_DATASPACE_RANGE_FULL);
         case VK_COLOR_SPACE_HDR10_HLG_EXT:
-            return static_cast<android_dataspace>(
-                HAL_DATASPACE_STANDARD_BT2020 | HAL_DATASPACE_TRANSFER_HLG |
-                HAL_DATASPACE_RANGE_FULL);
+            return static_cast<android_dataspace>(HAL_DATASPACE_BT2020_HLG);
         case VK_COLOR_SPACE_ADOBERGB_LINEAR_EXT:
             return static_cast<android_dataspace>(
                 HAL_DATASPACE_STANDARD_ADOBE_RGB |
@@ -1364,7 +1370,7 @@
     PixelFormat native_pixel_format =
         GetNativePixelFormat(create_info->imageFormat);
     android_dataspace native_dataspace =
-        GetNativeDataspace(create_info->imageColorSpace);
+        GetNativeDataspace(create_info->imageColorSpace, native_pixel_format);
     if (native_dataspace == HAL_DATASPACE_UNKNOWN) {
         ALOGE(
             "CreateSwapchainKHR(VkSwapchainCreateInfoKHR.imageColorSpace = %d) "