Merge "Add GTE compatibility logic for NoVote" into main
diff --git a/cmds/idlcli/Android.bp b/cmds/idlcli/Android.bp
index 50c2cd8..36dcbca 100644
--- a/cmds/idlcli/Android.bp
+++ b/cmds/idlcli/Android.bp
@@ -50,6 +50,7 @@
         "vibrator/CommandAlwaysOnEnable.cpp",
         "vibrator/CommandCompose.cpp",
         "vibrator/CommandComposePwle.cpp",
+        "vibrator/CommandGetFrequencyToOutputAccelerationMap.cpp",
         "vibrator/CommandGetBandwidthAmplitudeMap.cpp",
         "vibrator/CommandGetCapabilities.cpp",
         "vibrator/CommandGetCompositionDelayMax.cpp",
@@ -72,6 +73,11 @@
         "vibrator/CommandSetExternalControl.cpp",
         "vibrator/CommandSupportsAmplitudeControl.cpp",
         "vibrator/CommandSupportsExternalControl.cpp",
+        "vibrator/CommandGetPwleV2PrimitiveDurationMaxMillis.cpp",
+        "vibrator/CommandGetPwleV2CompositionSizeMax.cpp",
+        "vibrator/CommandGetPwleV2PrimitiveDurationMinMillis.cpp",
+        "vibrator/CommandComposePwleV2.cpp",
+        "vibrator/CommandPerformVendorEffect.cpp",
     ],
     visibility: [":__subpackages__"],
 }
diff --git a/cmds/idlcli/vibrator/CommandComposePwleV2.cpp b/cmds/idlcli/vibrator/CommandComposePwleV2.cpp
new file mode 100644
index 0000000..6d3cf84
--- /dev/null
+++ b/cmds/idlcli/vibrator/CommandComposePwleV2.cpp
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2024 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 <stdlib.h>
+
+#include <charconv>
+
+#include "utils.h"
+#include "vibrator.h"
+
+namespace android {
+namespace idlcli {
+
+class CommandVibrator;
+
+namespace vibrator {
+
+using aidl::CompositePwleV2;
+using aidl::PwleV2Primitive;
+
+class CommandComposePwleV2 : public Command {
+    std::string getDescription() const override { return "Compose normalized PWLE vibration."; }
+
+    std::string getUsageSummary() const override {
+        return "[options] <time> <frequency> <amplitude> ...";
+    }
+
+    UsageDetails getUsageDetails() const override {
+        UsageDetails details{
+                {"-b", {"Block for duration of vibration."}},
+                {"<time>", {"Segment duration in milliseconds"}},
+                {"<frequency>", {"Target frequency in Hz"}},
+                {"<amplitude>", {"Target amplitude in [0.0, 1.0]"}},
+                {"...", {"May repeat multiple times."}},
+        };
+        return details;
+    }
+
+    Status doArgs(Args& args) override {
+        while (args.get<std::string>().value_or("").find("-") == 0) {
+            auto opt = *args.pop<std::string>();
+            if (opt == "--") {
+                break;
+            } else if (opt == "-b") {
+                mBlocking = true;
+            } else {
+                std::cerr << "Invalid Option '" << opt << "'!" << std::endl;
+                return USAGE;
+            }
+        }
+
+        if (args.empty()) {
+            std::cerr << "Missing arguments! Please see usage" << std::endl;
+            return USAGE;
+        }
+
+        while (!args.empty()) {
+            PwleV2Primitive segment;
+
+            if (auto timeMs = args.pop<decltype(segment.timeMillis)>();
+                timeMs && *timeMs >= 0 && *timeMs <= 0x7ffff) {
+                segment.timeMillis = *timeMs;
+                std::cout << "Time: " << segment.timeMillis << std::endl;
+            } else {
+                std::cerr << "Missing or Invalid Time!" << std::endl;
+                return USAGE;
+            }
+
+            if (auto frequencyHz = args.pop<decltype(segment.frequencyHz)>();
+                frequencyHz && *frequencyHz >= 30 && *frequencyHz <= 300) {
+                segment.frequencyHz = *frequencyHz;
+                std::cout << "Frequency: " << segment.frequencyHz << std::endl;
+            } else {
+                std::cerr << "Missing or Invalid Frequency!" << std::endl;
+                return USAGE;
+            }
+
+            if (auto amplitude = args.pop<decltype(segment.amplitude)>();
+                amplitude && *amplitude >= 0 && *amplitude <= 1.0) {
+                segment.amplitude = *amplitude;
+                std::cout << "Amplitude: " << segment.amplitude << std::endl;
+            } else {
+                std::cerr << "Missing or Invalid Amplitude!" << std::endl;
+                return USAGE;
+            }
+
+            mCompositePwle.pwlePrimitives.emplace_back(std::move(segment));
+        }
+
+        if (!args.empty()) {
+            std::cerr << "Unexpected Arguments!" << std::endl;
+            return USAGE;
+        }
+
+        return OK;
+    }
+
+    Status doMain(Args&& /*args*/) override {
+        auto hal = getHal<aidl::IVibrator>();
+
+        if (!hal) {
+            return UNAVAILABLE;
+        }
+
+        ABinderProcess_setThreadPoolMaxThreadCount(1);
+        ABinderProcess_startThreadPool();
+
+        std::shared_ptr<VibratorCallback> callback;
+
+        if (mBlocking) {
+            callback = ndk::SharedRefBase::make<VibratorCallback>();
+        }
+
+        auto status = hal->call(&aidl::IVibrator::composePwleV2, mCompositePwle, callback);
+
+        if (status.isOk() && callback) {
+            callback->waitForComplete();
+        }
+
+        std::cout << "Status: " << status.getDescription() << std::endl;
+
+        return status.isOk() ? OK : ERROR;
+    }
+
+    bool mBlocking;
+    CompositePwleV2 mCompositePwle;
+};
+
+static const auto Command =
+        CommandRegistry<CommandVibrator>::Register<CommandComposePwleV2>("composePwleV2");
+
+} // namespace vibrator
+} // namespace idlcli
+} // namespace android
diff --git a/cmds/idlcli/vibrator/CommandGetFrequencyToOutputAccelerationMap.cpp b/cmds/idlcli/vibrator/CommandGetFrequencyToOutputAccelerationMap.cpp
new file mode 100644
index 0000000..2edd0ca
--- /dev/null
+++ b/cmds/idlcli/vibrator/CommandGetFrequencyToOutputAccelerationMap.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2024 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 "utils.h"
+#include "vibrator.h"
+
+namespace android {
+namespace idlcli {
+
+class CommandVibrator;
+
+namespace vibrator {
+
+using aidl::FrequencyAccelerationMapEntry;
+
+class CommandGetFrequencyToOutputAccelerationMap : public Command {
+    std::string getDescription() const override {
+        return "Retrieves vibrator frequency to output acceleration map.";
+    }
+
+    std::string getUsageSummary() const override { return ""; }
+
+    UsageDetails getUsageDetails() const override {
+        UsageDetails details{};
+        return details;
+    }
+
+    Status doArgs(Args& args) override {
+        if (!args.empty()) {
+            std::cerr << "Unexpected Arguments!" << std::endl;
+            return USAGE;
+        }
+        return OK;
+    }
+
+    Status doMain(Args&& /*args*/) override {
+        std::string statusStr;
+        std::vector<FrequencyAccelerationMapEntry> frequencyToOutputAccelerationMap;
+        Status ret;
+
+        if (auto hal = getHal<aidl::IVibrator>()) {
+            auto status = hal->call(&aidl::IVibrator::getFrequencyToOutputAccelerationMap,
+                                    &frequencyToOutputAccelerationMap);
+            statusStr = status.getDescription();
+            ret = (status.isOk() ? OK : ERROR);
+        } else {
+            return UNAVAILABLE;
+        }
+
+        std::cout << "Status: " << statusStr << std::endl;
+        std::cout << "Frequency to Output Amplitude Map: " << std::endl;
+        for (auto& entry : frequencyToOutputAccelerationMap) {
+            std::cout << entry.frequencyHz << " " << entry.maxOutputAccelerationGs << std::endl;
+        }
+
+        return ret;
+    }
+};
+
+static const auto Command =
+        CommandRegistry<CommandVibrator>::Register<CommandGetFrequencyToOutputAccelerationMap>(
+                "getFrequencyToOutputAccelerationMap");
+
+} // namespace vibrator
+} // namespace idlcli
+} // namespace android
diff --git a/cmds/idlcli/vibrator/CommandGetPwleV2CompositionSizeMax.cpp b/cmds/idlcli/vibrator/CommandGetPwleV2CompositionSizeMax.cpp
new file mode 100644
index 0000000..cca072c
--- /dev/null
+++ b/cmds/idlcli/vibrator/CommandGetPwleV2CompositionSizeMax.cpp
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2024 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 "utils.h"
+#include "vibrator.h"
+
+namespace android {
+namespace idlcli {
+
+class CommandVibrator;
+
+namespace vibrator {
+
+class CommandGetPwleV2CompositionSizeMax : public Command {
+    std::string getDescription() const override {
+        return "Retrieves vibrator PwleV2 max composition size.";
+    }
+
+    std::string getUsageSummary() const override { return ""; }
+
+    UsageDetails getUsageDetails() const override {
+        UsageDetails details{};
+        return details;
+    }
+
+    Status doArgs(Args& args) override {
+        if (!args.empty()) {
+            std::cerr << "Unexpected Arguments!" << std::endl;
+            return USAGE;
+        }
+        return OK;
+    }
+
+    Status doMain(Args&& /*args*/) override {
+        std::string statusStr;
+        int32_t maxSize;
+        Status ret;
+
+        if (auto hal = getHal<aidl::IVibrator>()) {
+            auto status = hal->call(&aidl::IVibrator::getPwleV2CompositionSizeMax, &maxSize);
+            statusStr = status.getDescription();
+            ret = status.isOk() ? OK : ERROR;
+        } else {
+            return UNAVAILABLE;
+        }
+
+        std::cout << "Status: " << statusStr << std::endl;
+        std::cout << "Max Size: " << maxSize << std::endl;
+
+        return ret;
+    }
+};
+
+static const auto Command =
+        CommandRegistry<CommandVibrator>::Register<CommandGetPwleV2CompositionSizeMax>(
+                "getPwleV2CompositionSizeMax");
+
+} // namespace vibrator
+} // namespace idlcli
+} // namespace android
diff --git a/cmds/idlcli/vibrator/CommandGetPwleV2PrimitiveDurationMaxMillis.cpp b/cmds/idlcli/vibrator/CommandGetPwleV2PrimitiveDurationMaxMillis.cpp
new file mode 100644
index 0000000..dbbfe1a
--- /dev/null
+++ b/cmds/idlcli/vibrator/CommandGetPwleV2PrimitiveDurationMaxMillis.cpp
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2024 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 "utils.h"
+#include "vibrator.h"
+
+namespace android {
+namespace idlcli {
+
+class CommandVibrator;
+
+namespace vibrator {
+
+class CommandGetPwleV2PrimitiveDurationMaxMillis : public Command {
+    std::string getDescription() const override {
+        return "Retrieves vibrator PwleV2 max primitive duration in milliseconds.";
+    }
+
+    std::string getUsageSummary() const override { return ""; }
+
+    UsageDetails getUsageDetails() const override {
+        UsageDetails details{};
+        return details;
+    }
+
+    Status doArgs(Args& args) override {
+        if (!args.empty()) {
+            std::cerr << "Unexpected Arguments!" << std::endl;
+            return USAGE;
+        }
+        return OK;
+    }
+
+    Status doMain(Args&& /*args*/) override {
+        std::string statusStr;
+        int32_t maxDurationMs;
+        Status ret;
+
+        if (auto hal = getHal<aidl::IVibrator>()) {
+            auto status = hal->call(&aidl::IVibrator::getPwleV2PrimitiveDurationMaxMillis,
+                                    &maxDurationMs);
+            statusStr = status.getDescription();
+            ret = status.isOk() ? OK : ERROR;
+        } else {
+            return UNAVAILABLE;
+        }
+
+        std::cout << "Status: " << statusStr << std::endl;
+        std::cout << "Primitive duration max: " << maxDurationMs << " ms" << std::endl;
+
+        return ret;
+    }
+};
+
+static const auto Command =
+        CommandRegistry<CommandVibrator>::Register<CommandGetPwleV2PrimitiveDurationMaxMillis>(
+                "getPwleV2PrimitiveDurationMaxMillis");
+
+} // namespace vibrator
+} // namespace idlcli
+} // namespace android
diff --git a/cmds/idlcli/vibrator/CommandGetPwleV2PrimitiveDurationMinMillis.cpp b/cmds/idlcli/vibrator/CommandGetPwleV2PrimitiveDurationMinMillis.cpp
new file mode 100644
index 0000000..09225c4
--- /dev/null
+++ b/cmds/idlcli/vibrator/CommandGetPwleV2PrimitiveDurationMinMillis.cpp
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2024 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 "utils.h"
+#include "vibrator.h"
+
+namespace android {
+namespace idlcli {
+
+class CommandVibrator;
+
+namespace vibrator {
+
+class CommandGetPwleV2PrimitiveDurationMinMillis : public Command {
+    std::string getDescription() const override {
+        return "Retrieves vibrator PwleV2 minimum primitive duration in milliseconds.";
+    }
+
+    std::string getUsageSummary() const override { return ""; }
+
+    UsageDetails getUsageDetails() const override {
+        UsageDetails details{};
+        return details;
+    }
+
+    Status doArgs(Args& args) override {
+        if (!args.empty()) {
+            std::cerr << "Unexpected Arguments!" << std::endl;
+            return USAGE;
+        }
+        return OK;
+    }
+
+    Status doMain(Args&& /*args*/) override {
+        std::string statusStr;
+        int32_t minDurationMs;
+        Status ret;
+
+        if (auto hal = getHal<aidl::IVibrator>()) {
+            auto status = hal->call(&aidl::IVibrator::getPwleV2PrimitiveDurationMinMillis,
+                                    &minDurationMs);
+            statusStr = status.getDescription();
+            ret = status.isOk() ? OK : ERROR;
+        } else {
+            return UNAVAILABLE;
+        }
+
+        std::cout << "Status: " << statusStr << std::endl;
+        std::cout << "Primitive duration min: " << minDurationMs << " ms" << std::endl;
+
+        return ret;
+    }
+};
+
+static const auto Command =
+        CommandRegistry<CommandVibrator>::Register<CommandGetPwleV2PrimitiveDurationMinMillis>(
+                "getPwleV2PrimitiveDurationMinMillis");
+
+} // namespace vibrator
+} // namespace idlcli
+} // namespace android
diff --git a/cmds/idlcli/vibrator/CommandPerformVendorEffect.cpp b/cmds/idlcli/vibrator/CommandPerformVendorEffect.cpp
new file mode 100644
index 0000000..9c25bd2
--- /dev/null
+++ b/cmds/idlcli/vibrator/CommandPerformVendorEffect.cpp
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2024 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 <thread>
+
+#include "utils.h"
+#include "vibrator.h"
+
+using std::chrono::milliseconds;
+using std::this_thread::sleep_for;
+
+namespace android {
+namespace idlcli {
+
+class CommandVibrator;
+
+namespace vibrator {
+
+using aidl::VendorEffect;
+
+class CommandPerformVendorEffect : public Command {
+    std::string getDescription() const override { return "Perform vendor vibration effect."; }
+
+    std::string getUsageSummary() const override { return "[options] <none>"; }
+
+    UsageDetails getUsageDetails() const override {
+        UsageDetails details{
+                {"-b", {"Block for duration of vibration."}},
+                {"<none>", {"No valid input."}},
+        };
+        return details;
+    }
+
+    Status doArgs(Args& args) override {
+        while (args.get<std::string>().value_or("").find("-") == 0) {
+            auto opt = *args.pop<std::string>();
+            if (opt == "--") {
+                break;
+            } else if (opt == "-b") {
+                mBlocking = true;
+            } else {
+                std::cerr << "Invalid Option '" << opt << "'!" << std::endl;
+                return USAGE;
+            }
+        }
+
+        return OK;
+    }
+
+    Status doMain(Args&& /*args*/) override { return UNAVAILABLE; }
+
+    bool mBlocking;
+    VendorEffect mEffect;
+};
+
+static const auto Command = CommandRegistry<CommandVibrator>::Register<CommandPerformVendorEffect>(
+        "performVendorEffect");
+
+} // namespace vibrator
+} // namespace idlcli
+} // namespace android
diff --git a/include/android/OWNERS b/include/android/OWNERS
index 5b014d0..9dfa279 100644
--- a/include/android/OWNERS
+++ b/include/android/OWNERS
@@ -9,4 +9,5 @@
 
 # ADPF
 per-file performance_hint.h = file:platform/frameworks/base:/ADPF_OWNERS
+per-file system_health.h = file:platform/frameworks/base:/ADPF_OWNERS
 per-file thermal.h = file:platform/frameworks/base:/ADPF_OWNERS
diff --git a/include/android/system_health.h b/include/android/system_health.h
new file mode 100644
index 0000000..69620df
--- /dev/null
+++ b/include/android/system_health.h
@@ -0,0 +1,351 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+/**
+* @defgroup SystemHealth
+* @{
+*/
+
+/**
+ * @file system_health.h
+ */
+
+#ifndef _ANDROID_SYSTEM_HEALTH_H
+#define _ANDROID_SYSTEM_HEALTH_H
+
+#include <sys/cdefs.h>
+
+/******************************************************************
+ *
+ * IMPORTANT NOTICE:
+ *
+ *   This file is part of Android's set of stable system headers
+ *   exposed by the Android NDK (Native Development Kit).
+ *
+ *   Third-party source AND binary code relies on the definitions
+ *   here to be FROZEN ON ALL UPCOMING PLATFORM RELEASES.
+ *
+ *   - DO NOT MODIFY ENUMS (EXCEPT IF YOU ADD NEW 32-BIT VALUES)
+ *   - DO NOT MODIFY CONSTANTS OR FUNCTIONAL MACROS
+ *   - DO NOT CHANGE THE SIGNATURE OF FUNCTIONS IN ANY WAY
+ *   - DO NOT CHANGE THE LAYOUT OR SIZE OF STRUCTURES
+ */
+
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#if !defined(__INTRODUCED_IN)
+#define __INTRODUCED_IN(__api_level) /* nothing */
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Params used to customize the calculation of CPU headroom.
+ *
+ * Also see {@link ASystemHealth_getCpuHeadroom}.
+ */
+typedef struct ACpuHeadroomParams ACpuHeadroomParams;
+
+/**
+ * Params used to customize the calculation of GPU headroom.
+ *
+ * Also see {@link ASystemHealth_getGpuHeadroom}.
+ */
+typedef struct AGpuHeadroomParams AGpuHeadroomParams;
+
+/**
+ * Creates a new instance of ACpuHeadroomParams.
+ *
+ * When the client finishes using {@link ACpuHeadroomParams},
+ * {@link ACpuHeadroomParams_destroy()} must be called to destroy
+ * and free up the resources associated with {@link ACpuHeadroomParams}.
+ *
+ * Available since API level 36.
+ *
+ * @return A new instance of ACpuHeadroomParams.
+ */
+ACpuHeadroomParams *_Nonnull ACpuHeadroomParams_create()
+__INTRODUCED_IN(36);
+
+enum ACpuHeadroomCalculationType {
+    /**
+     * Use the minimum headroom value within the calculation window.
+     * Introduced in API level 36.
+     */
+    ACPU_HEADROOM_CALCULATION_TYPE_MIN = 0,
+    /**
+     * Use the average headroom value within the calculation window.
+     * Introduced in API level 36.
+     */
+    ACPU_HEADROOM_CALCULATION_TYPE_AVERAGE = 1,
+};
+typedef enum ACpuHeadroomCalculationType ACpuHeadroomCalculationType;
+
+enum AGpuHeadroomCalculationType {
+    /**
+     * Use the minimum headroom value within the calculation window.
+     * Introduced in API level 36.
+     */
+    AGPU_HEADROOM_CALCULATION_TYPE_MIN = 0,
+    /**
+     * Use the average headroom value within the calculation window.
+     * Introduced in API level 36.
+     */
+    AGPU_HEADROOM_CALCULATION_TYPE_AVERAGE = 1,
+};
+typedef enum AGpuHeadroomCalculationType AGpuHeadroomCalculationType;
+
+/**
+ * Sets the headroom calculation window size in ACpuHeadroomParams.
+ *
+ * Available since API level 36.
+ *
+ * @param params The params to be set.
+ * @param windowMillis The window size in milliseconds ranged from [50, 10000]. The smaller the
+ *                     window size, the larger fluctuation in the headroom value should be expected.
+ *                     The default value can be retrieved from the
+ *                     {@link #ACpuHeadroomParams_getCalculationWindowMillis} if not set. The device
+ *                     will try to use the closest feasible window size to this param.
+ */
+void ACpuHeadroomParams_setCalculationWindowMillis(ACpuHeadroomParams *_Nonnull params,
+                                                   int windowMillis)
+__INTRODUCED_IN(36);
+
+/**
+ * Gets the headroom calculation window size in ACpuHeadroomParams.
+ *
+ * Available since API level 36.
+ *
+ * @param params The params to be set.
+ * @return This will return the default value chosen by the device if the params is not set.
+ */
+int ACpuHeadroomParams_getCalculationWindowMillis(ACpuHeadroomParams *_Nonnull params)
+__INTRODUCED_IN(36);
+
+/**
+ * Sets the headroom calculation window size in AGpuHeadroomParams.
+ *
+ * Available since API level 36.
+ *
+ * @param params The params to be set.
+ * @param windowMillis The window size in milliseconds ranged from [50, 10000]. The smaller the
+ *                     window size, the larger fluctuation in the headroom value should be expected.
+ *                     The default value can be retrieved from the
+ *                     {@link #AGpuHeadroomParams_getCalculationWindowMillis} if not set. The device
+ *                     will try to use the closest feasible window size to this param.
+ */
+void AGpuHeadroomParams_setCalculationWindowMillis(AGpuHeadroomParams *_Nonnull params,
+                                                   int windowMillis)
+__INTRODUCED_IN(36);
+
+/**
+ * Gets the headroom calculation window size in AGpuHeadroomParams.
+ *
+ * Available since API level 36.
+ *
+ * @param params The params to be set.
+ * @return This will return the default value chosen by the device if the params is not set.
+ */
+int AGpuHeadroomParams_getCalculationWindowMillis(AGpuHeadroomParams *_Nonnull params)
+__INTRODUCED_IN(36);
+
+/**
+ * Sets the headroom calculation type in ACpuHeadroomParams.
+ *
+ * Available since API level 36.
+ *
+ * @param params The params to be set.
+ * @param calculationType The headroom calculation type.
+ */
+void ACpuHeadroomParams_setCalculationType(ACpuHeadroomParams *_Nonnull params,
+                                           ACpuHeadroomCalculationType calculationType)
+__INTRODUCED_IN(36);
+
+/**
+ * Gets the headroom calculation type in ACpuHeadroomParams.
+ *
+ * Available since API level 36.
+ *
+ * @param params The params to be set.
+ * @return The headroom calculation type.
+ */
+ACpuHeadroomCalculationType
+ACpuHeadroomParams_getCalculationType(ACpuHeadroomParams *_Nonnull params)
+__INTRODUCED_IN(36);
+
+/**
+ * Sets the headroom calculation type in AGpuHeadroomParams.
+ *
+ * Available since API level 36.
+ *
+ * @param params The params to be set.
+ * @param calculationType The headroom calculation type.
+ */
+void AGpuHeadroomParams_setCalculationType(AGpuHeadroomParams *_Nonnull params,
+                                           AGpuHeadroomCalculationType calculationType)
+__INTRODUCED_IN(36);
+
+/**
+ * Gets the headroom calculation type in AGpuHeadroomParams.
+ *
+ * Available since API level 36.
+ *
+ * @param params The params to be set.
+ * @return The headroom calculation type.
+ */
+AGpuHeadroomCalculationType
+AGpuHeadroomParams_getCalculationType(AGpuHeadroomParams *_Nonnull params)
+__INTRODUCED_IN(36);
+
+/**
+ * Sets the thread TIDs to track in ACpuHeadroomParams.
+ *
+ * Available since API level 36.
+ *
+ * @param params The params to be set.
+ * @param tids Non-null array of TIDs, maximum 5.
+ * @param tidsSize The size of the tids array.
+ */
+void ACpuHeadroomParams_setTids(ACpuHeadroomParams *_Nonnull params, const int *_Nonnull tids,
+                                int tidsSize)
+__INTRODUCED_IN(36);
+
+/**
+ * Creates a new instance of AGpuHeadroomParams.
+ *
+ * When the client finishes using {@link AGpuHeadroomParams},
+ * {@link AGpuHeadroomParams_destroy()} must be called to destroy
+ * and free up the resources associated with {@link AGpuHeadroomParams}.
+ *
+ * Available since API level 36.
+ *
+ * @return A new instance of AGpuHeadroomParams.
+ */
+AGpuHeadroomParams *_Nonnull AGpuHeadroomParams_create()
+__INTRODUCED_IN(36);
+
+/**
+ * Deletes the ACpuHeadroomParams instance.
+ *
+ * Available since API level 36.
+ *
+ * @param params The params to be deleted.
+ */
+void ACpuHeadroomParams_destroy(ACpuHeadroomParams *_Nonnull params)
+__INTRODUCED_IN(36);
+
+/**
+ * Deletes the AGpuHeadroomParams instance.
+ *
+ * Available since API level 36.
+ *
+ * @param params The params to be deleted.
+ */
+void AGpuHeadroomParams_destroy(AGpuHeadroomParams *_Nonnull params)
+__INTRODUCED_IN(36);
+
+/**
+ * Provides an estimate of available CPU capacity headroom of the device.
+ *
+ * The value can be used by the calling application to determine if the workload was CPU bound and
+ * then take action accordingly to ensure that the workload can be completed smoothly. It can also
+ * be used with the thermal status and headroom to determine if reducing the CPU bound workload can
+ * help reduce the device temperature to avoid thermal throttling.
+ *
+ * Available since API level 36.
+ *
+ * @param params The params to customize the CPU headroom calculation, or nullptr to use the default
+ * @param outHeadroom Non-null output pointer to a single float, which will be set to the CPU
+ *                    headroom value. The value will be a single value or `Float.NaN` if it's
+ *                    temporarily unavailable.
+ *                    Each valid value ranges from [0, 100], where 0 indicates no more cpu resources
+ *                    can be granted.
+ * @return 0 on success
+ *         EPIPE if failed to get the CPU headroom.
+ *         EPERM if the TIDs do not belong to the same process.
+ *         ENOTSUP if API or requested params is unsupported.
+ */
+int ASystemHealth_getCpuHeadroom(const ACpuHeadroomParams *_Nullable params,
+                                 float *_Nonnull outHeadroom)
+__INTRODUCED_IN(36);
+
+/**
+ * Provides an estimate of available GPU capacity headroom of the device.
+ *
+ * The value can be used by the calling application to determine if the workload was GPU bound and
+ * then take action accordingly to ensure that the workload can be completed smoothly. It can also
+ * be used with the thermal status and headroom to determine if reducing the GPU bound workload can
+ * help reduce the device temperature to avoid thermal throttling.
+ *
+ * Available since API level 36
+ *
+ * @param params The params to customize the GPU headroom calculation, or nullptr to use the default
+ * @param outHeadroom Non-null output pointer to a single float, which will be set to the GPU
+ *                    headroom value. The value will be a single value or `Float.NaN` if it's
+ *                    temporarily unavailable.
+ *                    Each valid value ranges from [0, 100], where 0 indicates no more gpu resources
+ *                    can be granted.
+ * @return 0 on success
+ *         EPIPE if failed to get the GPU headroom.
+ *         ENOTSUP if API or requested params is unsupported.
+ */
+int ASystemHealth_getGpuHeadroom(const AGpuHeadroomParams *_Nullable params,
+                                 float *_Nonnull outHeadroom)
+__INTRODUCED_IN(36);
+
+/**
+ * Gets minimum polling interval for calling {@link ASystemHealth_getCpuHeadroom} in milliseconds.
+ *
+ * The getCpuHeadroom API may return cached result if called more frequently than the interval.
+ *
+ * Available since API level 36.
+ *
+ * @param outMinIntervalMillis Non-null output pointer to a int64_t, which
+ *                will be set to the minimum polling interval in milliseconds.
+ * @return 0 on success
+ *         EPIPE if failed to get the minimum polling interval.
+ *         ENOTSUP if API is unsupported.
+ */
+int ASystemHealth_getCpuHeadroomMinIntervalMillis(int64_t *_Nonnull outMinIntervalMillis)
+__INTRODUCED_IN(36);
+
+/**
+ * Gets minimum polling interval for calling {@link ASystemHealth_getGpuHeadroom} in milliseconds.
+ *
+ * The getGpuHeadroom API may return cached result if called more frequent than the interval.
+ *
+ * Available since API level 36.
+ *
+ * @param outMinIntervalMillis Non-null output pointer to a int64_t, which
+ *                will be set to the minimum polling interval in milliseconds.
+ * @return 0 on success
+ *         EPIPE if failed to get the minimum polling interval.
+ *         ENOTSUP if API is unsupported.
+ */
+int ASystemHealth_getGpuHeadroomMinIntervalMillis(int64_t *_Nonnull outMinIntervalMillis)
+__INTRODUCED_IN(36);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // _ANDROID_SYSTEM_HEALTH_H
+
+/** @} */
diff --git a/libs/binder/TEST_MAPPING b/libs/binder/TEST_MAPPING
index 99a9c91..9e5e79f 100644
--- a/libs/binder/TEST_MAPPING
+++ b/libs/binder/TEST_MAPPING
@@ -70,6 +70,9 @@
       "name": "CtsOsTestCases_ParcelAndBinderTests"
     },
     {
+      "name": "FrameworksCoreTests_all_binder"
+    },
+    {
       "name": "libbinder_rs-internal_test"
     },
     {
diff --git a/libs/binder/include/binder/IServiceManager.h b/libs/binder/include/binder/IServiceManager.h
index ca26a57..7d79baa 100644
--- a/libs/binder/include/binder/IServiceManager.h
+++ b/libs/binder/include/binder/IServiceManager.h
@@ -153,7 +153,7 @@
 
     /**
      * Directly enable or disable caching binder during addService calls.
-     * Only used for testing.
+     * Only used for testing. This is enabled by default.
      */
     virtual void enableAddServiceCache(bool value) = 0;
 };
diff --git a/libs/nativewindow/rust/src/lib.rs b/libs/nativewindow/rust/src/lib.rs
index 9876362..d760285 100644
--- a/libs/nativewindow/rust/src/lib.rs
+++ b/libs/nativewindow/rust/src/lib.rs
@@ -30,8 +30,8 @@
     StatusCode,
 };
 use ffi::{
-    AHardwareBuffer, AHardwareBuffer_Desc, AHardwareBuffer_readFromParcel,
-    AHardwareBuffer_writeToParcel, ARect,
+    AHardwareBuffer, AHardwareBuffer_Desc, AHardwareBuffer_Plane, AHardwareBuffer_Planes,
+    AHardwareBuffer_readFromParcel, AHardwareBuffer_writeToParcel, ARect,
 };
 use std::ffi::c_void;
 use std::fmt::{self, Debug, Formatter};
@@ -313,6 +313,57 @@
         })
     }
 
+    /// Lock a potentially multi-planar hardware buffer for direct CPU access.
+    ///
+    /// # Safety
+    ///
+    /// - If `fence` is `None`, the caller must ensure that all writes to the buffer have completed
+    ///   before calling this function.
+    /// - If the buffer has `AHARDWAREBUFFER_FORMAT_BLOB`, multiple threads or process may lock the
+    ///   buffer simultaneously, but the caller must ensure that they don't access it simultaneously
+    ///   and break Rust's aliasing rules, like any other shared memory.
+    /// - Otherwise if `usage` includes `AHARDWAREBUFFER_USAGE_CPU_WRITE_RARELY` or
+    ///   `AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN`, the caller must ensure that no other threads or
+    ///   processes lock the buffer simultaneously for any usage.
+    /// - Otherwise, the caller must ensure that no other threads lock the buffer for writing
+    ///   simultaneously.
+    /// - If `rect` is not `None`, the caller must not modify the buffer outside of that rectangle.
+    pub unsafe fn lock_planes<'a>(
+        &'a self,
+        usage: AHardwareBuffer_UsageFlags,
+        fence: Option<BorrowedFd>,
+        rect: Option<&ARect>,
+    ) -> Result<Vec<PlaneGuard<'a>>, StatusCode> {
+        let fence = if let Some(fence) = fence { fence.as_raw_fd() } else { -1 };
+        let rect = rect.map(ptr::from_ref).unwrap_or(null());
+        let mut planes = AHardwareBuffer_Planes {
+            planeCount: 0,
+            planes: [const { AHardwareBuffer_Plane { data: null_mut(), pixelStride: 0, rowStride: 0 } };
+                4],
+        };
+
+        // SAFETY: The `AHardwareBuffer` pointer we wrap is always valid, and the various out
+        // pointers are valid because they come from references. Our caller promises that writes have
+        // completed and there will be no simultaneous read/write locks.
+        let status = unsafe {
+            ffi::AHardwareBuffer_lockPlanes(self.0.as_ptr(), usage.0, fence, rect, &mut planes)
+        };
+        status_result(status)?;
+        let plane_count = planes.planeCount.try_into().unwrap();
+        Ok(planes.planes[..plane_count]
+            .iter()
+            .map(|plane| PlaneGuard {
+                guard: HardwareBufferGuard {
+                    buffer: self,
+                    address: NonNull::new(plane.data)
+                        .expect("AHardwareBuffer_lockAndGetInfo set a null outVirtualAddress"),
+                },
+                pixel_stride: plane.pixelStride,
+                row_stride: plane.rowStride,
+            })
+            .collect())
+    }
+
     /// Locks the hardware buffer for direct CPU access, returning information about the bytes per
     /// pixel and stride as well.
     ///
@@ -510,6 +561,18 @@
     pub stride: u32,
 }
 
+/// A guard for a single plane of a locked `HardwareBuffer`, with additional information about the
+/// stride.
+#[derive(Debug)]
+pub struct PlaneGuard<'a> {
+    /// The locked buffer guard.
+    pub guard: HardwareBufferGuard<'a>,
+    /// The stride in bytes between the color channel for one pixel to the next pixel.
+    pub pixel_stride: u32,
+    /// The stride in bytes between rows in the buffer.
+    pub row_stride: u32,
+}
+
 #[cfg(test)]
 mod test {
     use super::*;
diff --git a/libs/ui/PublicFormat.cpp b/libs/ui/PublicFormat.cpp
index c9663ed..dbc0884 100644
--- a/libs/ui/PublicFormat.cpp
+++ b/libs/ui/PublicFormat.cpp
@@ -30,6 +30,7 @@
         case PublicFormat::DEPTH_POINT_CLOUD:
         case PublicFormat::DEPTH_JPEG:
         case PublicFormat::HEIC:
+        case PublicFormat::HEIC_ULTRAHDR:
         case PublicFormat::JPEG_R:
             return HAL_PIXEL_FORMAT_BLOB;
         case PublicFormat::DEPTH16:
@@ -74,6 +75,9 @@
         case PublicFormat::HEIC:
             dataspace = Dataspace::HEIF;
             break;
+        case PublicFormat::HEIC_ULTRAHDR:
+            dataspace = Dataspace::HEIF_ULTRAHDR;
+            break;
         case PublicFormat::JPEG_R:
             dataspace = Dataspace::JPEG_R;
             break;
@@ -153,6 +157,9 @@
                         return PublicFormat::DEPTH_JPEG;
                     } else if (dataSpace == static_cast<android_dataspace>(Dataspace::JPEG_R)) {
                         return PublicFormat::JPEG_R;
+                    } else if (dataSpace == static_cast<android_dataspace>(
+                                Dataspace::HEIF_ULTRAHDR)) {
+                        return PublicFormat::HEIC_ULTRAHDR;
                     }else {
                         // Assume otherwise-marked blobs are also JPEG
                         return PublicFormat::JPEG;
diff --git a/libs/ui/include/ui/PublicFormat.h b/libs/ui/include/ui/PublicFormat.h
index 2248cca..e87931e 100644
--- a/libs/ui/include/ui/PublicFormat.h
+++ b/libs/ui/include/ui/PublicFormat.h
@@ -59,6 +59,7 @@
     DEPTH_JPEG = 0x69656963,
     JPEG_R = 0x1005,
     HEIC = 0x48454946,
+    HEIC_ULTRAHDR = 0x1006,
 };
 
 /* Convert from android.graphics.ImageFormat/PixelFormat enums to graphics.h HAL
diff --git a/services/inputflinger/PointerChoreographer.cpp b/services/inputflinger/PointerChoreographer.cpp
index 8eb6bdd..811692f 100644
--- a/services/inputflinger/PointerChoreographer.cpp
+++ b/services/inputflinger/PointerChoreographer.cpp
@@ -64,9 +64,8 @@
              !isFromSource(sources, AINPUT_SOURCE_STYLUS));
 }
 
-inline void notifyPointerDisplayChange(
-        std::optional<std::tuple<ui::LogicalDisplayId, FloatPoint>> change,
-        PointerChoreographerPolicyInterface& policy) {
+inline void notifyPointerDisplayChange(std::optional<std::tuple<ui::LogicalDisplayId, vec2>> change,
+                                       PointerChoreographerPolicyInterface& policy) {
     if (!change) {
         return;
     }
@@ -245,9 +244,9 @@
     if (MotionEvent::isValidCursorPosition(args.xCursorPosition, args.yCursorPosition)) {
         // This is an absolute mouse device that knows about the location of the cursor on the
         // display, so set the cursor position to the specified location.
-        const auto [x, y] = pc.getPosition();
-        const float deltaX = args.xCursorPosition - x;
-        const float deltaY = args.yCursorPosition - y;
+        const auto position = pc.getPosition();
+        const float deltaX = args.xCursorPosition - position.x;
+        const float deltaY = args.yCursorPosition - position.y;
         newArgs.pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, deltaX);
         newArgs.pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, deltaY);
         pc.setPosition(args.xCursorPosition, args.yCursorPosition);
@@ -273,15 +272,15 @@
         processPointerDeviceMotionEventLocked(/*byref*/ newArgs, /*byref*/ pc);
     } else {
         // This is a trackpad gesture with fake finger(s) that should not move the mouse pointer.
-        const auto [x, y] = pc.getPosition();
+        const auto position = pc.getPosition();
         for (uint32_t i = 0; i < newArgs.getPointerCount(); i++) {
             newArgs.pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_X,
-                                                  args.pointerCoords[i].getX() + x);
+                                                  args.pointerCoords[i].getX() + position.x);
             newArgs.pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_Y,
-                                                  args.pointerCoords[i].getY() + y);
+                                                  args.pointerCoords[i].getY() + position.y);
         }
-        newArgs.xCursorPosition = x;
-        newArgs.yCursorPosition = y;
+        newArgs.xCursorPosition = position.x;
+        newArgs.yCursorPosition = position.y;
     }
 
     // Note displayId may have changed if the cursor moved to a different display
@@ -296,7 +295,7 @@
     const float deltaX = newArgs.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X);
     const float deltaY = newArgs.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y);
 
-    FloatPoint unconsumedDelta = pc.move(deltaX, deltaY);
+    vec2 unconsumedDelta = pc.move(deltaX, deltaY);
     if (com::android::input::flags::connected_displays_cursor() &&
         (std::abs(unconsumedDelta.x) > 0 || std::abs(unconsumedDelta.y) > 0)) {
         handleUnconsumedDeltaLocked(pc, unconsumedDelta);
@@ -304,25 +303,23 @@
         newArgs.displayId = pc.getDisplayId();
     }
 
-    const auto [x, y] = pc.getPosition();
-    newArgs.pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, x);
-    newArgs.pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, y);
-    newArgs.xCursorPosition = x;
-    newArgs.yCursorPosition = y;
+    const auto position = pc.getPosition();
+    newArgs.pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, position.x);
+    newArgs.pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, position.y);
+    newArgs.xCursorPosition = position.x;
+    newArgs.yCursorPosition = position.y;
 }
 
 void PointerChoreographer::handleUnconsumedDeltaLocked(PointerControllerInterface& pc,
-                                                       const FloatPoint& unconsumedDelta) {
+                                                       const vec2& unconsumedDelta) {
     // Display topology is in rotated coordinate space and Pointer controller returns and expects
     // values in the un-rotated coordinate space. So we need to transform delta and cursor position
     // back to the rotated coordinate space to lookup adjacent display in the display topology.
     const auto& sourceDisplayTransform = pc.getDisplayTransform();
     const vec2 rotatedUnconsumedDelta =
-            transformWithoutTranslation(sourceDisplayTransform,
-                                        {unconsumedDelta.x, unconsumedDelta.y});
-    const FloatPoint cursorPosition = pc.getPosition();
-    const vec2 rotatedCursorPosition =
-            sourceDisplayTransform.transform(cursorPosition.x, cursorPosition.y);
+            transformWithoutTranslation(sourceDisplayTransform, unconsumedDelta);
+    const vec2 cursorPosition = pc.getPosition();
+    const vec2 rotatedCursorPosition = sourceDisplayTransform.transform(cursorPosition);
 
     // To find out the boundary that cursor is crossing we are checking delta in x and y direction
     // respectively. This prioritizes x direction over y.
@@ -769,7 +766,7 @@
 PointerChoreographer::PointerDisplayChange
 PointerChoreographer::calculatePointerDisplayChangeToNotify() {
     ui::LogicalDisplayId displayIdToNotify = ui::LogicalDisplayId::INVALID;
-    FloatPoint cursorPosition = {0, 0};
+    vec2 cursorPosition = {0, 0};
     if (const auto it = mMousePointersByDisplay.find(mDefaultMouseDisplayId);
         it != mMousePointersByDisplay.end()) {
         const auto& pointerController = it->second;
@@ -840,7 +837,7 @@
     return std::nullopt;
 }
 
-FloatPoint PointerChoreographer::getMouseCursorPosition(ui::LogicalDisplayId displayId) {
+vec2 PointerChoreographer::getMouseCursorPosition(ui::LogicalDisplayId displayId) {
     std::scoped_lock _l(getLock());
     const ui::LogicalDisplayId resolvedDisplayId = getTargetMouseDisplayLocked(displayId);
     if (auto it = mMousePointersByDisplay.find(resolvedDisplayId);
diff --git a/services/inputflinger/PointerChoreographer.h b/services/inputflinger/PointerChoreographer.h
index 4ca7323..939529f 100644
--- a/services/inputflinger/PointerChoreographer.h
+++ b/services/inputflinger/PointerChoreographer.h
@@ -59,7 +59,7 @@
     virtual void setDisplayViewports(const std::vector<DisplayViewport>& viewports) = 0;
     virtual std::optional<DisplayViewport> getViewportForPointerDevice(
             ui::LogicalDisplayId associatedDisplayId = ui::LogicalDisplayId::INVALID) = 0;
-    virtual FloatPoint getMouseCursorPosition(ui::LogicalDisplayId displayId) = 0;
+    virtual vec2 getMouseCursorPosition(ui::LogicalDisplayId displayId) = 0;
     virtual void setShowTouchesEnabled(bool enabled) = 0;
     virtual void setStylusPointerIconEnabled(bool enabled) = 0;
     /**
@@ -96,7 +96,7 @@
     void setDisplayViewports(const std::vector<DisplayViewport>& viewports) override;
     std::optional<DisplayViewport> getViewportForPointerDevice(
             ui::LogicalDisplayId associatedDisplayId) override;
-    FloatPoint getMouseCursorPosition(ui::LogicalDisplayId displayId) override;
+    vec2 getMouseCursorPosition(ui::LogicalDisplayId displayId) override;
     void setShowTouchesEnabled(bool enabled) override;
     void setStylusPointerIconEnabled(bool enabled) override;
     bool setPointerIcon(std::variant<std::unique_ptr<SpriteIcon>, PointerIconStyle> icon,
@@ -134,8 +134,8 @@
     void dump(std::string& dump) override;
 
 private:
-    using PointerDisplayChange = std::optional<
-            std::tuple<ui::LogicalDisplayId /*displayId*/, FloatPoint /*cursorPosition*/>>;
+    using PointerDisplayChange =
+            std::optional<std::tuple<ui::LogicalDisplayId /*displayId*/, vec2 /*cursorPosition*/>>;
 
     // PointerChoreographer's DisplayInfoListener can outlive the PointerChoreographer because when
     // the listener is registered and called from display thread, a strong pointer to the listener
@@ -171,8 +171,8 @@
             const std::unordered_set<ui::LogicalDisplayId>& privacySensitiveDisplays)
             REQUIRES(getLock());
 
-    void handleUnconsumedDeltaLocked(PointerControllerInterface& pc,
-                                     const FloatPoint& unconsumedDelta) REQUIRES(getLock());
+    void handleUnconsumedDeltaLocked(PointerControllerInterface& pc, const vec2& unconsumedDelta)
+            REQUIRES(getLock());
 
     void populateFakeDisplayTopologyLocked(const std::vector<gui::DisplayInfo>& displayInfos)
             REQUIRES(getLock());
diff --git a/services/inputflinger/include/PointerChoreographerPolicyInterface.h b/services/inputflinger/include/PointerChoreographerPolicyInterface.h
index e1f8fda..36614b2 100644
--- a/services/inputflinger/include/PointerChoreographerPolicyInterface.h
+++ b/services/inputflinger/include/PointerChoreographerPolicyInterface.h
@@ -54,7 +54,7 @@
      * @param position The new position of the mouse cursor on the logical display
      */
     virtual void notifyPointerDisplayIdChanged(ui::LogicalDisplayId displayId,
-                                               const FloatPoint& position) = 0;
+                                               const vec2& position) = 0;
 
     /* Returns true if any InputConnection is currently active. */
     virtual bool isInputMethodConnectionActive() = 0;
diff --git a/services/inputflinger/include/PointerControllerInterface.h b/services/inputflinger/include/PointerControllerInterface.h
index abca209..bd46490 100644
--- a/services/inputflinger/include/PointerControllerInterface.h
+++ b/services/inputflinger/include/PointerControllerInterface.h
@@ -24,20 +24,6 @@
 
 struct SpriteIcon;
 
-struct FloatPoint {
-    float x;
-    float y;
-
-    inline FloatPoint(float x, float y) : x(x), y(y) {}
-
-    inline explicit FloatPoint(vec2 p) : x(p.x), y(p.y) {}
-
-    template <typename T, typename U>
-    operator std::tuple<T, U>() {
-        return {x, y};
-    }
-};
-
 /**
  * Interface for tracking a mouse / touch pad pointer and touch pad spots.
  *
@@ -77,13 +63,13 @@
      *
      * Return value may be used to move pointer to corresponding adjacent display, if it exists in
      * the display-topology */
-    [[nodiscard]] virtual FloatPoint move(float deltaX, float deltaY) = 0;
+    [[nodiscard]] virtual vec2 move(float deltaX, float deltaY) = 0;
 
     /* Sets the absolute location of the pointer. */
     virtual void setPosition(float x, float y) = 0;
 
     /* Gets the absolute location of the pointer. */
-    virtual FloatPoint getPosition() const = 0;
+    virtual vec2 getPosition() const = 0;
 
     enum class Transition {
         // Fade/unfade immediately.
diff --git a/services/inputflinger/tests/FakePointerController.cpp b/services/inputflinger/tests/FakePointerController.cpp
index f53e63b..f033e57 100644
--- a/services/inputflinger/tests/FakePointerController.cpp
+++ b/services/inputflinger/tests/FakePointerController.cpp
@@ -43,7 +43,7 @@
     mY = y;
 }
 
-FloatPoint FakePointerController::getPosition() const {
+vec2 FakePointerController::getPosition() const {
     if (!mEnabled) {
         return {0, 0};
     }
@@ -96,9 +96,9 @@
 }
 
 void FakePointerController::assertPosition(float x, float y) {
-    const auto [actualX, actualY] = getPosition();
-    ASSERT_NEAR(x, actualX, 1);
-    ASSERT_NEAR(y, actualY, 1);
+    const auto actual = getPosition();
+    ASSERT_NEAR(x, actual.x, 1);
+    ASSERT_NEAR(y, actual.y, 1);
 }
 
 void FakePointerController::assertSpotCount(ui::LogicalDisplayId displayId, int32_t count) {
@@ -148,13 +148,13 @@
     return mIsPointerShown;
 }
 
-FloatPoint FakePointerController::move(float deltaX, float deltaY) {
+vec2 FakePointerController::move(float deltaX, float deltaY) {
     if (!mEnabled) return {0, 0};
 
     mX += deltaX;
     mY += deltaY;
 
-    const FloatPoint position(mX, mY);
+    const vec2 position(mX, mY);
 
     if (mX < mMinX) mX = mMinX;
     if (mX > mMaxX) mX = mMaxX;
diff --git a/services/inputflinger/tests/FakePointerController.h b/services/inputflinger/tests/FakePointerController.h
index 0ee3123..c526bb8 100644
--- a/services/inputflinger/tests/FakePointerController.h
+++ b/services/inputflinger/tests/FakePointerController.h
@@ -40,7 +40,7 @@
     const std::map<ui::LogicalDisplayId, std::vector<int32_t>>& getSpots();
 
     void setPosition(float x, float y) override;
-    FloatPoint getPosition() const override;
+    vec2 getPosition() const override;
     ui::LogicalDisplayId getDisplayId() const override;
     void setDisplayViewport(const DisplayViewport& viewport) override;
     void updatePointerIcon(PointerIconStyle iconId) override;
@@ -66,7 +66,7 @@
 
 private:
     std::string dump() override { return ""; }
-    FloatPoint move(float deltaX, float deltaY) override;
+    vec2 move(float deltaX, float deltaY) override;
     void unfade(Transition) override;
     void setPresentation(Presentation) override {}
     void setSpots(const PointerCoords*, const uint32_t*, BitSet32 spotIdBits,
diff --git a/services/inputflinger/tests/InterfaceMocks.h b/services/inputflinger/tests/InterfaceMocks.h
index 6f7c2e5..ac616d0 100644
--- a/services/inputflinger/tests/InterfaceMocks.h
+++ b/services/inputflinger/tests/InterfaceMocks.h
@@ -188,7 +188,7 @@
     MOCK_METHOD(std::shared_ptr<PointerControllerInterface>, createPointerController,
                 (PointerControllerInterface::ControllerType), (override));
     MOCK_METHOD(void, notifyPointerDisplayIdChanged,
-                (ui::LogicalDisplayId displayId, const FloatPoint& position), (override));
+                (ui::LogicalDisplayId displayId, const vec2& position), (override));
     MOCK_METHOD(bool, isInputMethodConnectionActive, (), (override));
     MOCK_METHOD(void, notifyMouseCursorFadedOnTyping, (), (override));
 };
diff --git a/services/inputflinger/tests/PointerChoreographer_test.cpp b/services/inputflinger/tests/PointerChoreographer_test.cpp
index 453c156..27da3d3 100644
--- a/services/inputflinger/tests/PointerChoreographer_test.cpp
+++ b/services/inputflinger/tests/PointerChoreographer_test.cpp
@@ -135,7 +135,7 @@
         });
 
         ON_CALL(mMockPolicy, notifyPointerDisplayIdChanged)
-                .WillByDefault([this](ui::LogicalDisplayId displayId, const FloatPoint& position) {
+                .WillByDefault([this](ui::LogicalDisplayId displayId, const vec2& position) {
                     mPointerDisplayIdNotified = displayId;
                 });
     }
@@ -2604,9 +2604,8 @@
 using PointerChoreographerDisplayTopologyTestFixtureParam =
         std::tuple<std::string_view /*name*/, int32_t /*source device*/,
                    ControllerType /*PointerController*/, ToolType /*pointer tool type*/,
-                   FloatPoint /*source position*/, FloatPoint /*hover move X/Y*/,
-                   ui::LogicalDisplayId /*destination display*/,
-                   FloatPoint /*destination position*/>;
+                   vec2 /*source position*/, vec2 /*hover move X/Y*/,
+                   ui::LogicalDisplayId /*destination display*/, vec2 /*destination position*/>;
 
 class PointerChoreographerDisplayTopologyTestFixture
       : public PointerChoreographerTest,
@@ -2708,67 +2707,63 @@
                 // Note: Upon viewport transition cursor will be positioned at the boundary of the
                 // destination, as we drop any unconsumed delta.
                 std::make_tuple("UnchangedDisplay", AINPUT_SOURCE_MOUSE, ControllerType::MOUSE,
-                                ToolType::MOUSE, FloatPoint(50, 50) /* initial x/y */,
-                                FloatPoint(25, 25) /* delta x/y */,
+                                ToolType::MOUSE, vec2(50, 50) /* initial x/y */,
+                                vec2(25, 25) /* delta x/y */,
                                 PointerChoreographerDisplayTopologyTestFixture::DISPLAY_CENTER_ID,
-                                FloatPoint(75, 75) /* destination x/y */),
-                std::make_tuple(
-                        "TransitionToRightDisplay", AINPUT_SOURCE_MOUSE, ControllerType::MOUSE,
-                        ToolType::MOUSE, FloatPoint(50, 50) /* initial x/y */,
-                        FloatPoint(100, 25) /* delta x/y */,
-                        PointerChoreographerDisplayTopologyTestFixture::DISPLAY_RIGHT_ID,
-                        FloatPoint(0, 50 + 25 - 10) /* Left edge: (0, source + delta - offset) */),
+                                vec2(75, 75) /* destination x/y */),
+                std::make_tuple("TransitionToRightDisplay", AINPUT_SOURCE_MOUSE,
+                                ControllerType::MOUSE, ToolType::MOUSE,
+                                vec2(50, 50) /* initial x/y */, vec2(100, 25) /* delta x/y */,
+                                PointerChoreographerDisplayTopologyTestFixture::DISPLAY_RIGHT_ID,
+                                vec2(0,
+                                     50 + 25 - 10) /* Left edge: (0, source + delta - offset) */),
                 std::make_tuple(
                         "TransitionToLeftDisplay", AINPUT_SOURCE_MOUSE, ControllerType::MOUSE,
-                        ToolType::MOUSE, FloatPoint(50, 50) /* initial x/y */,
-                        FloatPoint(-100, 25) /* delta x/y */,
+                        ToolType::MOUSE, vec2(50, 50) /* initial x/y */,
+                        vec2(-100, 25) /* delta x/y */,
                         PointerChoreographerDisplayTopologyTestFixture::DISPLAY_LEFT_ID,
-                        FloatPoint(90,
-                                   50 + 25 - 10) /* Right edge: (width, source + delta - offset*/),
-                std::make_tuple(
-                        "TransitionToTopDisplay", AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD,
-                        ControllerType::MOUSE, ToolType::FINGER,
-                        FloatPoint(50, 50) /* initial x/y */, FloatPoint(25, -100) /* delta x/y */,
-                        PointerChoreographerDisplayTopologyTestFixture::DISPLAY_TOP_ID,
-                        FloatPoint(50 + 25 - 10,
-                                   90) /* Bottom edge: (source + delta - offset, height) */),
-                std::make_tuple(
-                        "TransitionToBottomDisplay", AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD,
-                        ControllerType::MOUSE, ToolType::FINGER,
-                        FloatPoint(50, 50) /* initial x/y */, FloatPoint(25, 100) /* delta x/y */,
-                        PointerChoreographerDisplayTopologyTestFixture::DISPLAY_BOTTOM_ID,
-                        FloatPoint(50 + 25 - 10, 0) /* Top edge: (source + delta - offset, 0) */),
+                        vec2(90, 50 + 25 - 10) /* Right edge: (width, source + delta - offset*/),
+                std::make_tuple("TransitionToTopDisplay",
+                                AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD, ControllerType::MOUSE,
+                                ToolType::FINGER, vec2(50, 50) /* initial x/y */,
+                                vec2(25, -100) /* delta x/y */,
+                                PointerChoreographerDisplayTopologyTestFixture::DISPLAY_TOP_ID,
+                                vec2(50 + 25 - 10,
+                                     90) /* Bottom edge: (source + delta - offset, height) */),
+                std::make_tuple("TransitionToBottomDisplay",
+                                AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD, ControllerType::MOUSE,
+                                ToolType::FINGER, vec2(50, 50) /* initial x/y */,
+                                vec2(25, 100) /* delta x/y */,
+                                PointerChoreographerDisplayTopologyTestFixture::DISPLAY_BOTTOM_ID,
+                                vec2(50 + 25 - 10, 0) /* Top edge: (source + delta - offset, 0) */),
                 std::make_tuple("NoTransitionAtTopOffset", AINPUT_SOURCE_MOUSE,
                                 ControllerType::MOUSE, ToolType::MOUSE,
-                                FloatPoint(5, 50) /* initial x/y */,
-                                FloatPoint(0, -100) /* Move Up */,
+                                vec2(5, 50) /* initial x/y */, vec2(0, -100) /* Move Up */,
                                 PointerChoreographerDisplayTopologyTestFixture::DISPLAY_CENTER_ID,
-                                FloatPoint(5, 0) /* Top edge */),
+                                vec2(5, 0) /* Top edge */),
                 std::make_tuple("NoTransitionAtRightOffset", AINPUT_SOURCE_MOUSE,
                                 ControllerType::MOUSE, ToolType::MOUSE,
-                                FloatPoint(95, 5) /* initial x/y */,
-                                FloatPoint(100, 0) /* Move Right */,
+                                vec2(95, 5) /* initial x/y */, vec2(100, 0) /* Move Right */,
                                 PointerChoreographerDisplayTopologyTestFixture::DISPLAY_CENTER_ID,
-                                FloatPoint(99, 5) /* Top edge */),
+                                vec2(99, 5) /* Top edge */),
                 std::make_tuple("NoTransitionAtBottomOffset",
                                 AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD, ControllerType::MOUSE,
-                                ToolType::FINGER, FloatPoint(5, 95) /* initial x/y */,
-                                FloatPoint(0, 100) /* Move Down */,
+                                ToolType::FINGER, vec2(5, 95) /* initial x/y */,
+                                vec2(0, 100) /* Move Down */,
                                 PointerChoreographerDisplayTopologyTestFixture::DISPLAY_CENTER_ID,
-                                FloatPoint(5, 99) /* Bottom edge */),
+                                vec2(5, 99) /* Bottom edge */),
                 std::make_tuple("NoTransitionAtLeftOffset",
                                 AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD, ControllerType::MOUSE,
-                                ToolType::FINGER, FloatPoint(5, 5) /* initial x/y */,
-                                FloatPoint(-100, 0) /* Move Left */,
+                                ToolType::FINGER, vec2(5, 5) /* initial x/y */,
+                                vec2(-100, 0) /* Move Left */,
                                 PointerChoreographerDisplayTopologyTestFixture::DISPLAY_CENTER_ID,
-                                FloatPoint(0, 5) /* Left edge */),
+                                vec2(0, 5) /* Left edge */),
                 std::make_tuple(
                         "TransitionAtTopRightCorner", AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD,
-                        ControllerType::MOUSE, ToolType::FINGER,
-                        FloatPoint(95, 5) /* initial x/y */,
-                        FloatPoint(10, -10) /* Move dignally to top right corner */,
+                        ControllerType::MOUSE, ToolType::FINGER, vec2(95, 5) /* initial x/y */,
+                        vec2(10, -10) /* Move dignally to top right corner */,
                         PointerChoreographerDisplayTopologyTestFixture::DISPLAY_TOP_RIGHT_CORNER_ID,
-                        FloatPoint(0, 90) /* bottom left corner */)),
+                        vec2(0, 90) /* bottom left corner */)),
         [](const testing::TestParamInfo<PointerChoreographerDisplayTopologyTestFixtureParam>& p) {
             return std::string{std::get<0>(p.param)};
         });
diff --git a/services/sensorservice/Android.bp b/services/sensorservice/Android.bp
index 7b2596a..8c80dd8 100644
--- a/services/sensorservice/Android.bp
+++ b/services/sensorservice/Android.bp
@@ -92,7 +92,7 @@
         "libaidlcommonsupport",
         "android.hardware.sensors@1.0-convert",
         "android.hardware.sensors-V1-convert",
-        "android.hardware.sensors-V2-ndk",
+        "android.hardware.sensors-V3-ndk",
         "sensorservice_flags_c_lib",
     ],
 
diff --git a/services/sensorservice/aidl/Android.bp b/services/sensorservice/aidl/Android.bp
index 542fcae..b9a3491 100644
--- a/services/sensorservice/aidl/Android.bp
+++ b/services/sensorservice/aidl/Android.bp
@@ -28,7 +28,7 @@
         "libbinder_ndk",
         "libsensor",
         "android.frameworks.sensorservice-V1-ndk",
-        "android.hardware.sensors-V2-ndk",
+        "android.hardware.sensors-V3-ndk",
     ],
     export_include_dirs: [
         "include/",
diff --git a/services/sensorservice/aidl/fuzzer/Android.bp b/services/sensorservice/aidl/fuzzer/Android.bp
index b2dc89b..880df08 100644
--- a/services/sensorservice/aidl/fuzzer/Android.bp
+++ b/services/sensorservice/aidl/fuzzer/Android.bp
@@ -20,7 +20,7 @@
         "android.companion.virtual.virtualdevice_aidl-cpp",
         "android.frameworks.sensorservice-V1-ndk",
         "android.hardware.sensors-V1-convert",
-        "android.hardware.sensors-V2-ndk",
+        "android.hardware.sensors-V3-ndk",
         "android.hardware.common-V2-ndk",
         "libsensor",
         "libfakeservicemanager",
diff --git a/services/surfaceflinger/Scheduler/ISchedulerCallback.h b/services/surfaceflinger/Scheduler/ISchedulerCallback.h
index 2b9e88c..d02d149 100644
--- a/services/surfaceflinger/Scheduler/ISchedulerCallback.h
+++ b/services/surfaceflinger/Scheduler/ISchedulerCallback.h
@@ -31,7 +31,7 @@
     virtual void onChoreographerAttached() = 0;
     virtual void onExpectedPresentTimePosted(TimePoint, ftl::NonNull<DisplayModePtr>,
                                              Fps renderRate) = 0;
-    virtual void onCommitNotComposited(PhysicalDisplayId pacesetterDisplayId) = 0;
+    virtual void onCommitNotComposited() = 0;
     virtual void vrrDisplayIdle(bool idle) = 0;
 
 protected:
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 86d91d9..4da76f6 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -242,7 +242,7 @@
             if (FlagManager::getInstance().vrr_config()) {
                 compositor.sendNotifyExpectedPresentHint(pacesetterPtr->displayId);
             }
-            mSchedulerCallback.onCommitNotComposited(pacesetterPtr->displayId);
+            mSchedulerCallback.onCommitNotComposited();
             return;
         }
     }
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 8f41112..59b1917 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -4410,7 +4410,7 @@
     scheduleNotifyExpectedPresentHint(displayId);
 }
 
-void SurfaceFlinger::onCommitNotComposited(PhysicalDisplayId pacesetterDisplayId) {
+void SurfaceFlinger::onCommitNotComposited() {
     if (FlagManager::getInstance().commit_not_composited()) {
         mFrameTimeline->onCommitNotComposited();
     }
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index b20a894..1e2c087 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -701,7 +701,7 @@
     void onChoreographerAttached() override;
     void onExpectedPresentTimePosted(TimePoint expectedPresentTime, ftl::NonNull<DisplayModePtr>,
                                      Fps renderRate) override;
-    void onCommitNotComposited(PhysicalDisplayId pacesetterDisplayId) override
+    void onCommitNotComposited() override
             REQUIRES(kMainThreadContext);
     void vrrDisplayIdle(bool idle) override;
 
diff --git a/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h b/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h
index d45cc66..25dd68e 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h
@@ -29,7 +29,7 @@
     MOCK_METHOD(void, onChoreographerAttached, (), (override));
     MOCK_METHOD(void, onExpectedPresentTimePosted, (TimePoint, ftl::NonNull<DisplayModePtr>, Fps),
                 (override));
-    MOCK_METHOD(void, onCommitNotComposited, (PhysicalDisplayId), (override));
+    MOCK_METHOD(void, onCommitNotComposited, (), (override));
     MOCK_METHOD(void, vrrDisplayIdle, (bool), (override));
 };
 
@@ -39,7 +39,7 @@
     void kernelTimerChanged(bool) override {}
     void onChoreographerAttached() override {}
     void onExpectedPresentTimePosted(TimePoint, ftl::NonNull<DisplayModePtr>, Fps) override {}
-    void onCommitNotComposited(PhysicalDisplayId) override {}
+    void onCommitNotComposited() override {}
     void vrrDisplayIdle(bool) override {}
 };