Merge "Add new SF backdoor option: hdr/sdr ratio overlay" into main
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index c6132e8..b302f52 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -236,6 +236,16 @@
     }                                                       \
 }
 
+// we could have tighter checks, but this is only to avoid hard errors. Negative values are defined
+// in UserHandle.java and carry specific meanings that may not be handled by certain APIs here.
+#define ENFORCE_VALID_USER(userId)                                     \
+    {                                                                  \
+        if (static_cast<uid_t>(std::abs(userId)) >=                    \
+            std::numeric_limits<uid_t>::max() / AID_USER_OFFSET) {     \
+            return error("userId invalid: " + std::to_string(userId)); \
+        }                                                              \
+    }
+
 #define CHECK_ARGUMENT_UUID(uuid) {                         \
     binder::Status status = checkArgumentUuid((uuid));      \
     if (!status.isOk()) {                                   \
@@ -696,6 +706,7 @@
         int32_t flags, int32_t appId, int32_t previousAppId, const std::string& seInfo,
         int32_t targetSdkVersion, int64_t* _aidl_return) {
     ENFORCE_UID(AID_SYSTEM);
+    ENFORCE_VALID_USER(userId);
     CHECK_ARGUMENT_UUID(uuid);
     CHECK_ARGUMENT_PACKAGE_NAME(packageName);
 
@@ -790,6 +801,8 @@
 binder::Status InstalldNativeService::createSdkSandboxDataPackageDirectory(
         const std::optional<std::string>& uuid, const std::string& packageName, int32_t userId,
         int32_t appId, int32_t flags) {
+    ENFORCE_VALID_USER(userId);
+
     int32_t sdkSandboxUid = multiuser_get_sdk_sandbox_uid(userId, appId);
     if (sdkSandboxUid == -1) {
         // There no valid sdk sandbox process for this app. Skip creation of data directory
@@ -828,6 +841,7 @@
         int32_t flags, int32_t appId, int32_t previousAppId, const std::string& seInfo,
         int32_t targetSdkVersion, int64_t* _aidl_return) {
     ENFORCE_UID(AID_SYSTEM);
+    ENFORCE_VALID_USER(userId);
     CHECK_ARGUMENT_UUID(uuid);
     CHECK_ARGUMENT_PACKAGE_NAME(packageName);
     LOCK_PACKAGE_USER();
@@ -839,6 +853,7 @@
         const android::os::CreateAppDataArgs& args,
         android::os::CreateAppDataResult* _aidl_return) {
     ENFORCE_UID(AID_SYSTEM);
+    ENFORCE_VALID_USER(args.userId);
     // Locking is performed depeer in the callstack.
 
     int64_t ceDataInode = -1;
@@ -854,6 +869,10 @@
         const std::vector<android::os::CreateAppDataArgs>& args,
         std::vector<android::os::CreateAppDataResult>* _aidl_return) {
     ENFORCE_UID(AID_SYSTEM);
+    for (const auto& arg : args) {
+        ENFORCE_VALID_USER(arg.userId);
+    }
+
     // Locking is performed depeer in the callstack.
 
     std::vector<android::os::CreateAppDataResult> results;
@@ -868,6 +887,7 @@
 
 binder::Status InstalldNativeService::reconcileSdkData(
         const android::os::ReconcileSdkDataArgs& args) {
+    ENFORCE_VALID_USER(args.userId);
     // Locking is performed depeer in the callstack.
 
     return reconcileSdkData(args.uuid, args.packageName, args.subDirNames, args.userId, args.appId,
@@ -891,6 +911,7 @@
                                                        int userId, int appId, int previousAppId,
                                                        const std::string& seInfo, int flags) {
     ENFORCE_UID(AID_SYSTEM);
+    ENFORCE_VALID_USER(userId);
     CHECK_ARGUMENT_UUID(uuid);
     CHECK_ARGUMENT_PACKAGE_NAME(packageName);
     LOCK_PACKAGE_USER();
@@ -974,6 +995,7 @@
 binder::Status InstalldNativeService::migrateAppData(const std::optional<std::string>& uuid,
         const std::string& packageName, int32_t userId, int32_t flags) {
     ENFORCE_UID(AID_SYSTEM);
+    ENFORCE_VALID_USER(userId);
     CHECK_ARGUMENT_UUID(uuid);
     CHECK_ARGUMENT_PACKAGE_NAME(packageName);
     LOCK_PACKAGE_USER();
@@ -1041,6 +1063,7 @@
 binder::Status InstalldNativeService::clearAppData(const std::optional<std::string>& uuid,
         const std::string& packageName, int32_t userId, int32_t flags, int64_t ceDataInode) {
     ENFORCE_UID(AID_SYSTEM);
+    ENFORCE_VALID_USER(userId);
     CHECK_ARGUMENT_UUID(uuid);
     CHECK_ARGUMENT_PACKAGE_NAME(packageName);
     LOCK_PACKAGE_USER();
@@ -1132,6 +1155,7 @@
 binder::Status InstalldNativeService::clearSdkSandboxDataPackageDirectory(
         const std::optional<std::string>& uuid, const std::string& packageName, int32_t userId,
         int32_t flags) {
+    ENFORCE_VALID_USER(userId);
     const char* uuid_ = uuid ? uuid->c_str() : nullptr;
     const char* pkgname = packageName.c_str();
 
@@ -1218,6 +1242,7 @@
 binder::Status InstalldNativeService::destroyAppData(const std::optional<std::string>& uuid,
         const std::string& packageName, int32_t userId, int32_t flags, int64_t ceDataInode) {
     ENFORCE_UID(AID_SYSTEM);
+    ENFORCE_VALID_USER(userId);
     CHECK_ARGUMENT_UUID(uuid);
     CHECK_ARGUMENT_PACKAGE_NAME(packageName);
     LOCK_PACKAGE_USER();
@@ -1288,6 +1313,8 @@
 binder::Status InstalldNativeService::destroySdkSandboxDataPackageDirectory(
         const std::optional<std::string>& uuid, const std::string& packageName, int32_t userId,
         int32_t flags) {
+    ENFORCE_VALID_USER(userId);
+
     const char* uuid_ = uuid ? uuid->c_str() : nullptr;
     const char* pkgname = packageName.c_str();
 
@@ -1435,6 +1462,7 @@
                                                       int32_t userId, int32_t snapshotId,
                                                       int32_t storageFlags, int64_t* _aidl_return) {
     ENFORCE_UID(AID_SYSTEM);
+    ENFORCE_VALID_USER(userId);
     CHECK_ARGUMENT_UUID_IS_TEST_OR_NULL(volumeUuid);
     CHECK_ARGUMENT_PACKAGE_NAME(packageName);
     LOCK_PACKAGE_USER();
@@ -1569,6 +1597,7 @@
         const int32_t appId, const std::string& seInfo, const int32_t userId,
         const int32_t snapshotId, int32_t storageFlags) {
     ENFORCE_UID(AID_SYSTEM);
+    ENFORCE_VALID_USER(userId);
     CHECK_ARGUMENT_UUID_IS_TEST_OR_NULL(volumeUuid);
     CHECK_ARGUMENT_PACKAGE_NAME(packageName);
     LOCK_PACKAGE_USER();
@@ -1641,6 +1670,7 @@
         const int32_t userId, const int64_t ceSnapshotInode, const int32_t snapshotId,
         int32_t storageFlags) {
     ENFORCE_UID(AID_SYSTEM);
+    ENFORCE_VALID_USER(userId);
     CHECK_ARGUMENT_UUID_IS_TEST_OR_NULL(volumeUuid);
     CHECK_ARGUMENT_PACKAGE_NAME(packageName);
     LOCK_PACKAGE_USER();
@@ -1674,6 +1704,7 @@
         const std::optional<std::string>& volumeUuid, const int32_t userId,
         const std::vector<int32_t>& retainSnapshotIds) {
     ENFORCE_UID(AID_SYSTEM);
+    ENFORCE_VALID_USER(userId);
     CHECK_ARGUMENT_UUID_IS_TEST_OR_NULL(volumeUuid);
     LOCK_USER();
 
@@ -1864,6 +1895,7 @@
 binder::Status InstalldNativeService::createUserData(const std::optional<std::string>& uuid,
         int32_t userId, int32_t userSerial ATTRIBUTE_UNUSED, int32_t flags) {
     ENFORCE_UID(AID_SYSTEM);
+    ENFORCE_VALID_USER(userId);
     CHECK_ARGUMENT_UUID(uuid);
     LOCK_USER();
 
@@ -1884,6 +1916,7 @@
 binder::Status InstalldNativeService::destroyUserData(const std::optional<std::string>& uuid,
         int32_t userId, int32_t flags) {
     ENFORCE_UID(AID_SYSTEM);
+    ENFORCE_VALID_USER(userId);
     CHECK_ARGUMENT_UUID(uuid);
     LOCK_USER();
 
@@ -2671,6 +2704,7 @@
         int32_t userId, int32_t flags, const std::vector<int32_t>& appIds,
         std::vector<int64_t>* _aidl_return) {
     ENFORCE_UID(AID_SYSTEM);
+    ENFORCE_VALID_USER(userId);
     CHECK_ARGUMENT_UUID(uuid);
     // NOTE: Locking is relaxed on this method, since it's limited to
     // read-only measurements without mutation.
@@ -2806,6 +2840,7 @@
         int32_t userId, int32_t flags, const std::vector<int32_t>& appIds,
         std::vector<int64_t>* _aidl_return) {
     ENFORCE_UID(AID_SYSTEM);
+    ENFORCE_VALID_USER(userId);
     CHECK_ARGUMENT_UUID(uuid);
     // NOTE: Locking is relaxed on this method, since it's limited to
     // read-only measurements without mutation.
@@ -2926,6 +2961,7 @@
         const std::vector<std::string>& packageNames, int32_t userId,
         std::optional<std::vector<std::optional<CrateMetadata>>>* _aidl_return) {
     ENFORCE_UID(AID_SYSTEM);
+    ENFORCE_VALID_USER(userId);
     CHECK_ARGUMENT_UUID(uuid);
     for (const auto& packageName : packageNames) {
         CHECK_ARGUMENT_PACKAGE_NAME(packageName);
@@ -2975,6 +3011,7 @@
         const std::optional<std::string>& uuid, int32_t userId,
         std::optional<std::vector<std::optional<CrateMetadata>>>* _aidl_return) {
     ENFORCE_UID(AID_SYSTEM);
+    ENFORCE_VALID_USER(userId);
     CHECK_ARGUMENT_UUID(uuid);
 #ifdef ENABLE_STORAGE_CRATES
     LOCK_USER();
@@ -3018,6 +3055,7 @@
 binder::Status InstalldNativeService::setAppQuota(const std::optional<std::string>& uuid,
         int32_t userId, int32_t appId, int64_t cacheQuota) {
     ENFORCE_UID(AID_SYSTEM);
+    ENFORCE_VALID_USER(userId);
     CHECK_ARGUMENT_UUID(uuid);
     std::lock_guard<std::recursive_mutex> lock(mQuotasLock);
 
@@ -3261,6 +3299,7 @@
         const std::string& packageName, int32_t userId, int32_t flags, int32_t appId,
         const std::string& seInfo) {
     ENFORCE_UID(AID_SYSTEM);
+    ENFORCE_VALID_USER(userId);
     CHECK_ARGUMENT_UUID(uuid);
     CHECK_ARGUMENT_PACKAGE_NAME(packageName);
     LOCK_PACKAGE_USER();
@@ -3271,6 +3310,7 @@
         const std::optional<std::string>& uuid, const std::string& packageName, int32_t userId,
         int32_t flags, int32_t appId, const std::string& seInfo) {
     ENFORCE_UID(AID_SYSTEM);
+    ENFORCE_VALID_USER(userId);
     CHECK_ARGUMENT_UUID(uuid);
     CHECK_ARGUMENT_PACKAGE_NAME(packageName);
 
@@ -3302,6 +3342,7 @@
         const std::optional<std::string>& uuid, const std::string& packageName, int32_t userId,
         int32_t flags, int32_t appId, const std::string& seInfo) {
     ENFORCE_UID(AID_SYSTEM);
+    ENFORCE_VALID_USER(userId);
     CHECK_ARGUMENT_UUID(uuid);
     CHECK_ARGUMENT_PACKAGE_NAME(packageName);
 
@@ -3753,6 +3794,7 @@
         int32_t userId, int32_t appId, const std::string& profileName, const std::string& codePath,
         const std::optional<std::string>& dexMetadata, bool* _aidl_return) {
     ENFORCE_UID(AID_SYSTEM);
+    ENFORCE_VALID_USER(userId);
     CHECK_ARGUMENT_PACKAGE_NAME(packageName);
     CHECK_ARGUMENT_PATH(codePath);
     LOCK_PACKAGE_USER();
@@ -3775,6 +3817,7 @@
 
 binder::Status InstalldNativeService::cleanupInvalidPackageDirs(
         const std::optional<std::string>& uuid, int32_t userId, int32_t flags) {
+    ENFORCE_VALID_USER(userId);
     const char* uuid_cstr = uuid ? uuid->c_str() : nullptr;
 
     if (flags & FLAG_STORAGE_CE) {
diff --git a/include/android/input.h b/include/android/input.h
index 9a0eb4d..16d86af 100644
--- a/include/android/input.h
+++ b/include/android/input.h
@@ -54,16 +54,12 @@
 #include <stdint.h>
 #include <sys/types.h>
 #include <android/keycodes.h>
-
-// This file is included by modules that have host support but android/looper.h is not supported
-// on host. __REMOVED_IN needs to be defined in order for android/looper.h to be compiled.
-#ifndef __BIONIC__
-#define __REMOVED_IN(x) __attribute__((deprecated))
-#endif
 #include <android/looper.h>
 
 #include <jni.h>
 
+// This file may also be built on glibc or on Windows/MacOS libc's, so no-op
+// definitions are provided.
 #if !defined(__INTRODUCED_IN)
 #define __INTRODUCED_IN(__api_level) /* nothing */
 #endif
diff --git a/include/android/looper.h b/include/android/looper.h
index 4fe142a..e50730d 100644
--- a/include/android/looper.h
+++ b/include/android/looper.h
@@ -26,10 +26,18 @@
 #ifndef ANDROID_LOOPER_H
 #define ANDROID_LOOPER_H
 
+#include <sys/cdefs.h>
+
 #ifdef __cplusplus
 extern "C" {
 #endif
 
+// This file may also be built on glibc or on Windows/MacOS libc's, so
+// deprecated definitions are provided.
+#if !defined(__REMOVED_IN)
+#define __REMOVED_IN(__api_level) __attribute__((__deprecated__))
+#endif
+
 struct ALooper;
 /**
  * ALooper
diff --git a/include/android/sensor.h b/include/android/sensor.h
index 16c5dde..a618393 100644
--- a/include/android/sensor.h
+++ b/include/android/sensor.h
@@ -29,6 +29,8 @@
 #ifndef ANDROID_SENSOR_H
 #define ANDROID_SENSOR_H
 
+#include <sys/cdefs.h>
+
 /******************************************************************
  *
  * IMPORTANT NOTICE:
@@ -45,11 +47,6 @@
  *   - DO NOT CHANGE THE LAYOUT OR SIZE OF STRUCTURES
  */
 
-// This file is included by modules that have host support but android/looper.h is not supported
-// on host. __REMOVED_IN needs to be defined in order for android/looper.h to be compiled.
-#ifndef __BIONIC__
-#define __REMOVED_IN(x) __attribute__((deprecated))
-#endif
 #include <android/looper.h>
 
 #include <stdbool.h>
@@ -57,6 +54,8 @@
 #include <math.h>
 #include <stdint.h>
 
+// This file may also be built on glibc or on Windows/MacOS libc's, so no-op
+// and deprecated definitions are provided.
 #if !defined(__INTRODUCED_IN)
 #define __INTRODUCED_IN(__api_level) /* nothing */
 #endif
@@ -658,7 +657,7 @@
     uint32_t flags;
     int32_t reserved1[3];
 } ASensorEvent;
-// LINT.ThenChange (hardware/libhardware/include/hardware/sensors.h)
+// LINT.ThenChange(hardware/libhardware/include/hardware/sensors.h)
 
 struct ASensorManager;
 /**
diff --git a/include/input/Input.h b/include/input/Input.h
index ea856c8..a271f0c 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -493,14 +493,17 @@
         toolType = ToolType::UNKNOWN;
     }
 
-    bool operator==(const PointerProperties& other) const;
+    bool operator==(const PointerProperties& other) const = default;
     inline bool operator!=(const PointerProperties& other) const {
         return !(*this == other);
     }
 
-    void copyFrom(const PointerProperties& other);
+    PointerProperties& operator=(const PointerProperties&) = default;
 };
 
+// TODO(b/211379801) : Use a strong type from ftl/mixins.h instead
+using DeviceId = int32_t;
+
 /*
  * Input events.
  */
@@ -512,7 +515,7 @@
 
     inline int32_t getId() const { return mId; }
 
-    inline int32_t getDeviceId() const { return mDeviceId; }
+    inline DeviceId getDeviceId() const { return mDeviceId; }
 
     inline uint32_t getSource() const { return mSource; }
 
@@ -527,13 +530,13 @@
     static int32_t nextId();
 
 protected:
-    void initialize(int32_t id, int32_t deviceId, uint32_t source, int32_t displayId,
+    void initialize(int32_t id, DeviceId deviceId, uint32_t source, int32_t displayId,
                     std::array<uint8_t, 32> hmac);
 
     void initialize(const InputEvent& from);
 
     int32_t mId;
-    int32_t mDeviceId;
+    DeviceId mDeviceId;
     uint32_t mSource;
     int32_t mDisplayId;
     std::array<uint8_t, 32> mHmac;
@@ -571,7 +574,7 @@
     static const char* getLabel(int32_t keyCode);
     static std::optional<int> getKeyCodeFromLabel(const char* label);
 
-    void initialize(int32_t id, int32_t deviceId, uint32_t source, int32_t displayId,
+    void initialize(int32_t id, DeviceId deviceId, uint32_t source, int32_t displayId,
                     std::array<uint8_t, 32> hmac, int32_t action, int32_t flags, int32_t keyCode,
                     int32_t scanCode, int32_t metaState, int32_t repeatCount, nsecs_t downTime,
                     nsecs_t eventTime);
@@ -835,7 +838,7 @@
 
     ssize_t findPointerIndex(int32_t pointerId) const;
 
-    void initialize(int32_t id, int32_t deviceId, uint32_t source, int32_t displayId,
+    void initialize(int32_t id, DeviceId deviceId, uint32_t source, int32_t displayId,
                     std::array<uint8_t, 32> hmac, int32_t action, int32_t actionButton,
                     int32_t flags, int32_t edgeFlags, int32_t metaState, int32_t buttonState,
                     MotionClassification classification, const ui::Transform& transform,
@@ -1013,7 +1016,7 @@
     };
 
     Type type;
-    int32_t deviceId;
+    DeviceId deviceId;
     nsecs_t eventTimeNanos;
     uint32_t source;
     int32_t displayId;
diff --git a/include/input/InputEventBuilders.h b/include/input/InputEventBuilders.h
new file mode 100644
index 0000000..9c0c10e
--- /dev/null
+++ b/include/input/InputEventBuilders.h
@@ -0,0 +1,163 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <android/input.h>
+#include <attestation/HmacKeyManager.h>
+#include <gui/constants.h>
+#include <input/Input.h>
+#include <utils/Timers.h> // for nsecs_t, systemTime
+
+#include <vector>
+
+namespace android {
+
+// An arbitrary device id.
+static constexpr uint32_t DEFAULT_DEVICE_ID = 1;
+
+// The default policy flags to use for event injection by tests.
+static constexpr uint32_t DEFAULT_POLICY_FLAGS = POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER;
+
+class PointerBuilder {
+public:
+    PointerBuilder(int32_t id, ToolType toolType) {
+        mProperties.clear();
+        mProperties.id = id;
+        mProperties.toolType = toolType;
+        mCoords.clear();
+    }
+
+    PointerBuilder& x(float x) { return axis(AMOTION_EVENT_AXIS_X, x); }
+
+    PointerBuilder& y(float y) { return axis(AMOTION_EVENT_AXIS_Y, y); }
+
+    PointerBuilder& axis(int32_t axis, float value) {
+        mCoords.setAxisValue(axis, value);
+        return *this;
+    }
+
+    PointerProperties buildProperties() const { return mProperties; }
+
+    PointerCoords buildCoords() const { return mCoords; }
+
+private:
+    PointerProperties mProperties;
+    PointerCoords mCoords;
+};
+
+class MotionEventBuilder {
+public:
+    MotionEventBuilder(int32_t action, int32_t source) {
+        mAction = action;
+        mSource = source;
+        mEventTime = systemTime(SYSTEM_TIME_MONOTONIC);
+        mDownTime = mEventTime;
+    }
+
+    MotionEventBuilder& deviceId(int32_t deviceId) {
+        mDeviceId = deviceId;
+        return *this;
+    }
+
+    MotionEventBuilder& downTime(nsecs_t downTime) {
+        mDownTime = downTime;
+        return *this;
+    }
+
+    MotionEventBuilder& eventTime(nsecs_t eventTime) {
+        mEventTime = eventTime;
+        return *this;
+    }
+
+    MotionEventBuilder& displayId(int32_t displayId) {
+        mDisplayId = displayId;
+        return *this;
+    }
+
+    MotionEventBuilder& actionButton(int32_t actionButton) {
+        mActionButton = actionButton;
+        return *this;
+    }
+
+    MotionEventBuilder& buttonState(int32_t buttonState) {
+        mButtonState = buttonState;
+        return *this;
+    }
+
+    MotionEventBuilder& rawXCursorPosition(float rawXCursorPosition) {
+        mRawXCursorPosition = rawXCursorPosition;
+        return *this;
+    }
+
+    MotionEventBuilder& rawYCursorPosition(float rawYCursorPosition) {
+        mRawYCursorPosition = rawYCursorPosition;
+        return *this;
+    }
+
+    MotionEventBuilder& pointer(PointerBuilder pointer) {
+        mPointers.push_back(pointer);
+        return *this;
+    }
+
+    MotionEventBuilder& addFlag(uint32_t flags) {
+        mFlags |= flags;
+        return *this;
+    }
+
+    MotionEvent build() {
+        std::vector<PointerProperties> pointerProperties;
+        std::vector<PointerCoords> pointerCoords;
+        for (const PointerBuilder& pointer : mPointers) {
+            pointerProperties.push_back(pointer.buildProperties());
+            pointerCoords.push_back(pointer.buildCoords());
+        }
+
+        // Set mouse cursor position for the most common cases to avoid boilerplate.
+        if (mSource == AINPUT_SOURCE_MOUSE &&
+            !MotionEvent::isValidCursorPosition(mRawXCursorPosition, mRawYCursorPosition)) {
+            mRawXCursorPosition = pointerCoords[0].getX();
+            mRawYCursorPosition = pointerCoords[0].getY();
+        }
+
+        MotionEvent event;
+        static const ui::Transform kIdentityTransform;
+        event.initialize(InputEvent::nextId(), mDeviceId, mSource, mDisplayId, INVALID_HMAC,
+                         mAction, mActionButton, mFlags, /*edgeFlags=*/0, AMETA_NONE, mButtonState,
+                         MotionClassification::NONE, kIdentityTransform,
+                         /*xPrecision=*/0, /*yPrecision=*/0, mRawXCursorPosition,
+                         mRawYCursorPosition, kIdentityTransform, mDownTime, mEventTime,
+                         mPointers.size(), pointerProperties.data(), pointerCoords.data());
+        return event;
+    }
+
+private:
+    int32_t mAction;
+    int32_t mDeviceId{DEFAULT_DEVICE_ID};
+    int32_t mSource;
+    nsecs_t mDownTime;
+    nsecs_t mEventTime;
+    int32_t mDisplayId{ADISPLAY_ID_DEFAULT};
+    int32_t mActionButton{0};
+    int32_t mButtonState{0};
+    int32_t mFlags{0};
+    float mRawXCursorPosition{AMOTION_EVENT_INVALID_CURSOR_POSITION};
+    float mRawYCursorPosition{AMOTION_EVENT_INVALID_CURSOR_POSITION};
+
+    std::vector<PointerBuilder> mPointers;
+};
+
+} // namespace android
diff --git a/libs/binder/rust/rpcbinder/src/server.rs b/libs/binder/rust/rpcbinder/src/server.rs
index 81f68f5..6fda878 100644
--- a/libs/binder/rust/rpcbinder/src/server.rs
+++ b/libs/binder/rust/rpcbinder/src/server.rs
@@ -33,9 +33,9 @@
     pub struct RpcServerRef;
 }
 
-/// SAFETY - The opaque handle can be cloned freely.
+/// SAFETY: The opaque handle can be cloned freely.
 unsafe impl Send for RpcServer {}
-/// SAFETY - The underlying C++ RpcServer class is thread-safe.
+/// SAFETY: The underlying C++ RpcServer class is thread-safe.
 unsafe impl Sync for RpcServer {}
 
 impl RpcServer {
@@ -59,7 +59,10 @@
     /// Creates a binder RPC server, serving the supplied binder service implementation on the given
     /// socket file descriptor. The socket should be bound to an address before calling this
     /// function.
-    pub fn new_bound_socket(mut service: SpIBinder, socket_fd: OwnedFd) -> Result<RpcServer, Error> {
+    pub fn new_bound_socket(
+        mut service: SpIBinder,
+        socket_fd: OwnedFd,
+    ) -> Result<RpcServer, Error> {
         let service = service.as_native_mut();
 
         // SAFETY: Service ownership is transferring to the server and won't be valid afterward.
@@ -67,7 +70,8 @@
         // The server takes ownership of the socket FD.
         unsafe {
             Self::checked_from_ptr(binder_rpc_unstable_bindgen::ARpcServer_newBoundSocket(
-                service, socket_fd.into_raw_fd(),
+                service,
+                socket_fd.into_raw_fd(),
             ))
         }
     }
@@ -120,7 +124,9 @@
         if ptr.is_null() {
             return Err(Error::new(ErrorKind::Other, "Failed to start server"));
         }
-        Ok(RpcServer::from_ptr(ptr))
+        // SAFETY: Our caller must pass us a valid or null pointer, and we've checked that it's not
+        // null.
+        Ok(unsafe { RpcServer::from_ptr(ptr) })
     }
 }
 
@@ -130,7 +136,7 @@
         &self,
         modes: &[FileDescriptorTransportMode],
     ) {
-        // SAFETY - Does not keep the pointer after returning does, nor does it
+        // SAFETY: Does not keep the pointer after returning does, nor does it
         // read past its boundary. Only passes the 'self' pointer as an opaque handle.
         unsafe {
             binder_rpc_unstable_bindgen::ARpcServer_setSupportedFileDescriptorTransportModes(
@@ -143,18 +149,21 @@
 
     /// Starts a new background thread and calls join(). Returns immediately.
     pub fn start(&self) {
+        // SAFETY: RpcServerRef wraps a valid pointer to an ARpcServer.
         unsafe { binder_rpc_unstable_bindgen::ARpcServer_start(self.as_ptr()) };
     }
 
     /// Joins the RpcServer thread. The call blocks until the server terminates.
     /// This must be called from exactly one thread.
     pub fn join(&self) {
+        // SAFETY: RpcServerRef wraps a valid pointer to an ARpcServer.
         unsafe { binder_rpc_unstable_bindgen::ARpcServer_join(self.as_ptr()) };
     }
 
     /// Shuts down the running RpcServer. Can be called multiple times and from
     /// multiple threads. Called automatically during drop().
     pub fn shutdown(&self) -> Result<(), Error> {
+        // SAFETY: RpcServerRef wraps a valid pointer to an ARpcServer.
         if unsafe { binder_rpc_unstable_bindgen::ARpcServer_shutdown(self.as_ptr()) } {
             Ok(())
         } else {
diff --git a/libs/binder/rust/rpcbinder/src/session.rs b/libs/binder/rust/rpcbinder/src/session.rs
index 28c5390..79a9510 100644
--- a/libs/binder/rust/rpcbinder/src/session.rs
+++ b/libs/binder/rust/rpcbinder/src/session.rs
@@ -36,15 +36,15 @@
     pub struct RpcSessionRef;
 }
 
-/// SAFETY - The opaque handle can be cloned freely.
+/// SAFETY: The opaque handle can be cloned freely.
 unsafe impl Send for RpcSession {}
-/// SAFETY - The underlying C++ RpcSession class is thread-safe.
+/// SAFETY: The underlying C++ RpcSession class is thread-safe.
 unsafe impl Sync for RpcSession {}
 
 impl RpcSession {
     /// Allocates a new RpcSession object.
     pub fn new() -> RpcSession {
-        // SAFETY - Takes ownership of the returned handle, which has correct refcount.
+        // SAFETY: Takes ownership of the returned handle, which has correct refcount.
         unsafe { RpcSession::from_ptr(binder_rpc_unstable_bindgen::ARpcSession_new()) }
     }
 }
@@ -58,7 +58,7 @@
 impl RpcSessionRef {
     /// Sets the file descriptor transport mode for this session.
     pub fn set_file_descriptor_transport_mode(&self, mode: FileDescriptorTransportMode) {
-        // SAFETY - Only passes the 'self' pointer as an opaque handle.
+        // SAFETY: Only passes the 'self' pointer as an opaque handle.
         unsafe {
             binder_rpc_unstable_bindgen::ARpcSession_setFileDescriptorTransportMode(
                 self.as_ptr(),
@@ -69,7 +69,7 @@
 
     /// Sets the maximum number of incoming threads.
     pub fn set_max_incoming_threads(&self, threads: usize) {
-        // SAFETY - Only passes the 'self' pointer as an opaque handle.
+        // SAFETY: Only passes the 'self' pointer as an opaque handle.
         unsafe {
             binder_rpc_unstable_bindgen::ARpcSession_setMaxIncomingThreads(self.as_ptr(), threads)
         };
@@ -77,7 +77,7 @@
 
     /// Sets the maximum number of outgoing connections.
     pub fn set_max_outgoing_connections(&self, connections: usize) {
-        // SAFETY - Only passes the 'self' pointer as an opaque handle.
+        // SAFETY: Only passes the 'self' pointer as an opaque handle.
         unsafe {
             binder_rpc_unstable_bindgen::ARpcSession_setMaxOutgoingConnections(
                 self.as_ptr(),
@@ -210,10 +210,10 @@
 type RequestFd<'a> = &'a mut dyn FnMut() -> Option<RawFd>;
 
 unsafe extern "C" fn request_fd_wrapper(param: *mut c_void) -> c_int {
+    let request_fd_ptr = param as *mut RequestFd;
     // SAFETY: This is only ever called by RpcPreconnectedClient, within the lifetime of the
     // BinderFdFactory reference, with param being a properly aligned non-null pointer to an
     // initialized instance.
-    let request_fd_ptr = param as *mut RequestFd;
-    let request_fd = request_fd_ptr.as_mut().unwrap();
+    let request_fd = unsafe { request_fd_ptr.as_mut().unwrap() };
     request_fd().unwrap_or(-1)
 }
diff --git a/libs/binder/rust/src/binder.rs b/libs/binder/rust/src/binder.rs
index b90b40b..0bd0781 100644
--- a/libs/binder/rust/src/binder.rs
+++ b/libs/binder/rust/src/binder.rs
@@ -97,8 +97,8 @@
 
 /// Interface stability promise
 ///
-/// An interface can promise to be a stable vendor interface ([`Vintf`]), or
-/// makes no stability guarantees ([`Local`]). [`Local`] is
+/// An interface can promise to be a stable vendor interface ([`Stability::Vintf`]),
+/// or makes no stability guarantees ([`Stability::Local`]). [`Stability::Local`] is
 /// currently the default stability.
 #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Default)]
 pub enum Stability {
@@ -139,8 +139,8 @@
 /// via `Binder::new(object)`.
 ///
 /// This is a low-level interface that should normally be automatically
-/// generated from AIDL via the [`declare_binder_interface!`] macro. When using
-/// the AIDL backend, users need only implement the high-level AIDL-defined
+/// generated from AIDL via the [`crate::declare_binder_interface!`] macro.
+/// When using the AIDL backend, users need only implement the high-level AIDL-defined
 /// interface. The AIDL compiler then generates a container struct that wraps
 /// the user-defined service and implements `Remotable`.
 pub trait Remotable: Send + Sync {
@@ -260,7 +260,14 @@
     /// Trying to use this function on a local binder will result in an
     /// INVALID_OPERATION code being returned and nothing happening.
     ///
-    /// This link always holds a weak reference to its recipient.
+    /// This link only holds a weak reference to its recipient. If the
+    /// `DeathRecipient` is dropped then it will be unlinked.
+    ///
+    /// Note that the notifications won't work if you don't first start at least
+    /// one Binder thread by calling
+    /// [`ProcessState::start_thread_pool`](crate::ProcessState::start_thread_pool)
+    /// or
+    /// [`ProcessState::join_thread_pool`](crate::ProcessState::join_thread_pool).
     fn link_to_death(&mut self, recipient: &mut DeathRecipient) -> Result<()>;
 
     /// Remove a previously registered death notification.
@@ -290,18 +297,17 @@
     /// Note: the returned pointer will not be constant. Calling this method
     /// multiple times for the same type will result in distinct class
     /// pointers. A static getter for this value is implemented in
-    /// [`declare_binder_interface!`].
+    /// [`crate::declare_binder_interface!`].
     pub fn new<I: InterfaceClassMethods>() -> InterfaceClass {
         let descriptor = CString::new(I::get_descriptor()).unwrap();
+        // Safety: `AIBinder_Class_define` expects a valid C string, and three
+        // valid callback functions, all non-null pointers. The C string is
+        // copied and need not be valid for longer than the call, so we can drop
+        // it after the call. We can safely assign null to the onDump and
+        // handleShellCommand callbacks as long as the class pointer was
+        // non-null. Rust None for a Option<fn> is guaranteed to be a NULL
+        // pointer. Rust retains ownership of the pointer after it is defined.
         let ptr = unsafe {
-            // Safety: `AIBinder_Class_define` expects a valid C string, and
-            // three valid callback functions, all non-null pointers. The C
-            // string is copied and need not be valid for longer than the call,
-            // so we can drop it after the call. We can safely assign null to
-            // the onDump and handleShellCommand callbacks as long as the class
-            // pointer was non-null. Rust None for a Option<fn> is guaranteed to
-            // be a NULL pointer. Rust retains ownership of the pointer after it
-            // is defined.
             let class = sys::AIBinder_Class_define(
                 descriptor.as_ptr(),
                 Some(I::on_create),
@@ -331,13 +337,12 @@
 
     /// Get the interface descriptor string of this class.
     pub fn get_descriptor(&self) -> String {
+        // SAFETY: The descriptor returned by AIBinder_Class_getDescriptor is
+        // always a two-byte null terminated sequence of u16s. Thus, we can
+        // continue reading from the pointer until we hit a null value, and this
+        // pointer can be a valid slice if the slice length is <= the number of
+        // u16 elements before the null terminator.
         unsafe {
-            // SAFETY: The descriptor returned by AIBinder_Class_getDescriptor
-            // is always a two-byte null terminated sequence of u16s. Thus, we
-            // can continue reading from the pointer until we hit a null value,
-            // and this pointer can be a valid slice if the slice length is <=
-            // the number of u16 elements before the null terminator.
-
             let raw_descriptor: *const c_char = sys::AIBinder_Class_getDescriptor(self.0);
             CStr::from_ptr(raw_descriptor)
                 .to_str()
@@ -535,17 +540,15 @@
             static CLASS_INIT: std::sync::Once = std::sync::Once::new();
             static mut CLASS: Option<$crate::binder_impl::InterfaceClass> = None;
 
+            // Safety: This assignment is guarded by the `CLASS_INIT` `Once`
+            // variable, and therefore is thread-safe, as it can only occur
+            // once.
             CLASS_INIT.call_once(|| unsafe {
-                // Safety: This assignment is guarded by the `CLASS_INIT` `Once`
-                // variable, and therefore is thread-safe, as it can only occur
-                // once.
                 CLASS = Some($constructor);
             });
-            unsafe {
-                // Safety: The `CLASS` variable can only be mutated once, above,
-                // and is subsequently safe to read from any thread.
-                CLASS.unwrap()
-            }
+            // Safety: The `CLASS` variable can only be mutated once, above, and
+            // is subsequently safe to read from any thread.
+            unsafe { CLASS.unwrap() }
         }
     };
 }
@@ -657,6 +660,8 @@
     fn as_native_mut(&mut self) -> *mut T;
 }
 
+// Safety: If V is a valid Android C++ type then we can either use that or a
+// null pointer.
 unsafe impl<T, V: AsNative<T>> AsNative<T> for Option<V> {
     fn as_native(&self) -> *const T {
         self.as_ref().map_or(ptr::null(), |v| v.as_native())
@@ -917,15 +922,15 @@
                 static CLASS_INIT: std::sync::Once = std::sync::Once::new();
                 static mut CLASS: Option<$crate::binder_impl::InterfaceClass> = None;
 
+                // Safety: This assignment is guarded by the `CLASS_INIT` `Once`
+                // variable, and therefore is thread-safe, as it can only occur
+                // once.
                 CLASS_INIT.call_once(|| unsafe {
-                    // Safety: This assignment is guarded by the `CLASS_INIT` `Once`
-                    // variable, and therefore is thread-safe, as it can only occur
-                    // once.
                     CLASS = Some($crate::binder_impl::InterfaceClass::new::<$crate::binder_impl::Binder<$native>>());
                 });
+                // Safety: The `CLASS` variable can only be mutated once, above,
+                // and is subsequently safe to read from any thread.
                 unsafe {
-                    // Safety: The `CLASS` variable can only be mutated once, above,
-                    // and is subsequently safe to read from any thread.
                     CLASS.unwrap()
                 }
             }
diff --git a/libs/binder/rust/src/error.rs b/libs/binder/rust/src/error.rs
index ba26062..8d9ce0e 100644
--- a/libs/binder/rust/src/error.rs
+++ b/libs/binder/rust/src/error.rs
@@ -112,41 +112,35 @@
 impl Status {
     /// Create a status object representing a successful transaction.
     pub fn ok() -> Self {
-        let ptr = unsafe {
-            // Safety: `AStatus_newOk` always returns a new, heap allocated
-            // pointer to an `ASTatus` object, so we know this pointer will be
-            // valid.
-            //
-            // Rust takes ownership of the returned pointer.
-            sys::AStatus_newOk()
-        };
+        // Safety: `AStatus_newOk` always returns a new, heap allocated
+        // pointer to an `ASTatus` object, so we know this pointer will be
+        // valid.
+        //
+        // Rust takes ownership of the returned pointer.
+        let ptr = unsafe { sys::AStatus_newOk() };
         Self(ptr::NonNull::new(ptr).expect("Unexpected null AStatus pointer"))
     }
 
     /// Create a status object from a service specific error
     pub fn new_service_specific_error(err: i32, message: Option<&CStr>) -> Status {
         let ptr = if let Some(message) = message {
-            unsafe {
-                // Safety: Any i32 is a valid service specific error for the
-                // error code parameter. We construct a valid, null-terminated
-                // `CString` from the message, which must be a valid C-style
-                // string to pass as the message. This function always returns a
-                // new, heap allocated pointer to an `AStatus` object, so we
-                // know the returned pointer will be valid.
-                //
-                // Rust takes ownership of the returned pointer.
-                sys::AStatus_fromServiceSpecificErrorWithMessage(err, message.as_ptr())
-            }
+            // Safety: Any i32 is a valid service specific error for the
+            // error code parameter. We construct a valid, null-terminated
+            // `CString` from the message, which must be a valid C-style
+            // string to pass as the message. This function always returns a
+            // new, heap allocated pointer to an `AStatus` object, so we
+            // know the returned pointer will be valid.
+            //
+            // Rust takes ownership of the returned pointer.
+            unsafe { sys::AStatus_fromServiceSpecificErrorWithMessage(err, message.as_ptr()) }
         } else {
-            unsafe {
-                // Safety: Any i32 is a valid service specific error for the
-                // error code parameter. This function always returns a new,
-                // heap allocated pointer to an `AStatus` object, so we know the
-                // returned pointer will be valid.
-                //
-                // Rust takes ownership of the returned pointer.
-                sys::AStatus_fromServiceSpecificError(err)
-            }
+            // Safety: Any i32 is a valid service specific error for the
+            // error code parameter. This function always returns a new,
+            // heap allocated pointer to an `AStatus` object, so we know the
+            // returned pointer will be valid.
+            //
+            // Rust takes ownership of the returned pointer.
+            unsafe { sys::AStatus_fromServiceSpecificError(err) }
         };
         Self(ptr::NonNull::new(ptr).expect("Unexpected null AStatus pointer"))
     }
@@ -159,6 +153,8 @@
     /// Create a status object from an exception code
     pub fn new_exception(exception: ExceptionCode, message: Option<&CStr>) -> Status {
         if let Some(message) = message {
+            // Safety: the C string pointer is valid and not retained by the
+            // function.
             let ptr = unsafe {
                 sys::AStatus_fromExceptionCodeWithMessage(exception as i32, message.as_ptr())
             };
@@ -187,37 +183,31 @@
 
     /// Returns `true` if this status represents a successful transaction.
     pub fn is_ok(&self) -> bool {
-        unsafe {
-            // Safety: `Status` always contains a valid `AStatus` pointer, so we
-            // are always passing a valid pointer to `AStatus_isOk` here.
-            sys::AStatus_isOk(self.as_native())
-        }
+        // Safety: `Status` always contains a valid `AStatus` pointer, so we
+        // are always passing a valid pointer to `AStatus_isOk` here.
+        unsafe { sys::AStatus_isOk(self.as_native()) }
     }
 
     /// Returns a description of the status.
     pub fn get_description(&self) -> String {
-        let description_ptr = unsafe {
-            // Safety: `Status` always contains a valid `AStatus` pointer, so we
-            // are always passing a valid pointer to `AStatus_getDescription`
-            // here.
-            //
-            // `AStatus_getDescription` always returns a valid pointer to a null
-            // terminated C string. Rust is responsible for freeing this pointer
-            // via `AStatus_deleteDescription`.
-            sys::AStatus_getDescription(self.as_native())
-        };
-        let description = unsafe {
-            // Safety: `AStatus_getDescription` always returns a valid C string,
-            // which can be safely converted to a `CStr`.
-            CStr::from_ptr(description_ptr)
-        };
+        // Safety: `Status` always contains a valid `AStatus` pointer, so we
+        // are always passing a valid pointer to `AStatus_getDescription`
+        // here.
+        //
+        // `AStatus_getDescription` always returns a valid pointer to a null
+        // terminated C string. Rust is responsible for freeing this pointer
+        // via `AStatus_deleteDescription`.
+        let description_ptr = unsafe { sys::AStatus_getDescription(self.as_native()) };
+        // Safety: `AStatus_getDescription` always returns a valid C string,
+        // which can be safely converted to a `CStr`.
+        let description = unsafe { CStr::from_ptr(description_ptr) };
         let description = description.to_string_lossy().to_string();
+        // Safety: `description_ptr` was returned from
+        // `AStatus_getDescription` above, and must be freed via
+        // `AStatus_deleteDescription`. We must not access the pointer after
+        // this call, so we copy it into an owned string above and return
+        // that string.
         unsafe {
-            // Safety: `description_ptr` was returned from
-            // `AStatus_getDescription` above, and must be freed via
-            // `AStatus_deleteDescription`. We must not access the pointer after
-            // this call, so we copy it into an owned string above and return
-            // that string.
             sys::AStatus_deleteDescription(description_ptr);
         }
         description
@@ -225,12 +215,10 @@
 
     /// Returns the exception code of the status.
     pub fn exception_code(&self) -> ExceptionCode {
-        let code = unsafe {
-            // Safety: `Status` always contains a valid `AStatus` pointer, so we
-            // are always passing a valid pointer to `AStatus_getExceptionCode`
-            // here.
-            sys::AStatus_getExceptionCode(self.as_native())
-        };
+        // Safety: `Status` always contains a valid `AStatus` pointer, so we
+        // are always passing a valid pointer to `AStatus_getExceptionCode`
+        // here.
+        let code = unsafe { sys::AStatus_getExceptionCode(self.as_native()) };
         parse_exception_code(code)
     }
 
@@ -241,11 +229,9 @@
     /// exception or a service specific error. To find out if this transaction
     /// as a whole is okay, use [`is_ok`](Self::is_ok) instead.
     pub fn transaction_error(&self) -> StatusCode {
-        let code = unsafe {
-            // Safety: `Status` always contains a valid `AStatus` pointer, so we
-            // are always passing a valid pointer to `AStatus_getStatus` here.
-            sys::AStatus_getStatus(self.as_native())
-        };
+        // Safety: `Status` always contains a valid `AStatus` pointer, so we
+        // are always passing a valid pointer to `AStatus_getStatus` here.
+        let code = unsafe { sys::AStatus_getStatus(self.as_native()) };
         parse_status_code(code)
     }
 
@@ -258,12 +244,10 @@
     /// find out if this transaction as a whole is okay, use
     /// [`is_ok`](Self::is_ok) instead.
     pub fn service_specific_error(&self) -> i32 {
-        unsafe {
-            // Safety: `Status` always contains a valid `AStatus` pointer, so we
-            // are always passing a valid pointer to
-            // `AStatus_getServiceSpecificError` here.
-            sys::AStatus_getServiceSpecificError(self.as_native())
-        }
+        // Safety: `Status` always contains a valid `AStatus` pointer, so we
+        // are always passing a valid pointer to
+        // `AStatus_getServiceSpecificError` here.
+        unsafe { sys::AStatus_getServiceSpecificError(self.as_native()) }
     }
 
     /// Calls `op` if the status was ok, otherwise returns an `Err` value of
@@ -321,24 +305,20 @@
 
 impl From<status_t> for Status {
     fn from(status: status_t) -> Status {
-        let ptr = unsafe {
-            // Safety: `AStatus_fromStatus` expects any `status_t` integer, so
-            // this is a safe FFI call. Unknown values will be coerced into
-            // UNKNOWN_ERROR.
-            sys::AStatus_fromStatus(status)
-        };
+        // Safety: `AStatus_fromStatus` expects any `status_t` integer, so
+        // this is a safe FFI call. Unknown values will be coerced into
+        // UNKNOWN_ERROR.
+        let ptr = unsafe { sys::AStatus_fromStatus(status) };
         Self(ptr::NonNull::new(ptr).expect("Unexpected null AStatus pointer"))
     }
 }
 
 impl From<ExceptionCode> for Status {
     fn from(code: ExceptionCode) -> Status {
-        let ptr = unsafe {
-            // Safety: `AStatus_fromExceptionCode` expects any
-            // `binder_exception_t` (i32) integer, so this is a safe FFI call.
-            // Unknown values will be coerced into EX_TRANSACTION_FAILED.
-            sys::AStatus_fromExceptionCode(code as i32)
-        };
+        // Safety: `AStatus_fromExceptionCode` expects any
+        // `binder_exception_t` (i32) integer, so this is a safe FFI call.
+        // Unknown values will be coerced into EX_TRANSACTION_FAILED.
+        let ptr = unsafe { sys::AStatus_fromExceptionCode(code as i32) };
         Self(ptr::NonNull::new(ptr).expect("Unexpected null AStatus pointer"))
     }
 }
@@ -363,20 +343,18 @@
 
 impl Drop for Status {
     fn drop(&mut self) {
+        // Safety: `Status` manages the lifetime of its inner `AStatus`
+        // pointee, so we need to delete it here. We know that the pointer
+        // will be valid here since `Status` always contains a valid pointer
+        // while it is alive.
         unsafe {
-            // Safety: `Status` manages the lifetime of its inner `AStatus`
-            // pointee, so we need to delete it here. We know that the pointer
-            // will be valid here since `Status` always contains a valid pointer
-            // while it is alive.
             sys::AStatus_delete(self.0.as_mut());
         }
     }
 }
 
-/// # Safety
-///
-/// `Status` always contains a valid pointer to an `AStatus` object, so we can
-/// trivially convert it to a correctly-typed raw pointer.
+/// Safety: `Status` always contains a valid pointer to an `AStatus` object, so
+/// we can trivially convert it to a correctly-typed raw pointer.
 ///
 /// Care must be taken that the returned pointer is only dereferenced while the
 /// `Status` object is still alive.
@@ -386,11 +364,9 @@
     }
 
     fn as_native_mut(&mut self) -> *mut sys::AStatus {
-        unsafe {
-            // Safety: The pointer will be valid here since `Status` always
-            // contains a valid and initialized pointer while it is alive.
-            self.0.as_mut()
-        }
+        // Safety: The pointer will be valid here since `Status` always contains
+        // a valid and initialized pointer while it is alive.
+        unsafe { self.0.as_mut() }
     }
 }
 
diff --git a/libs/binder/rust/src/native.rs b/libs/binder/rust/src/native.rs
index 5557168..b248f5e 100644
--- a/libs/binder/rust/src/native.rs
+++ b/libs/binder/rust/src/native.rs
@@ -42,7 +42,7 @@
     rust_object: *mut T,
 }
 
-/// # Safety
+/// Safety:
 ///
 /// A `Binder<T>` is a pair of unique owning pointers to two values:
 ///   * a C++ ABBinder which the C++ API guarantees can be passed between threads
@@ -54,7 +54,7 @@
 /// to how `Box<T>` is `Send` if `T` is `Send`.
 unsafe impl<T: Remotable> Send for Binder<T> {}
 
-/// # Safety
+/// Safety:
 ///
 /// A `Binder<T>` is a pair of unique owning pointers to two values:
 ///   * a C++ ABBinder which is thread-safe, i.e. `Send + Sync`
@@ -89,15 +89,13 @@
     pub fn new_with_stability(rust_object: T, stability: Stability) -> Binder<T> {
         let class = T::get_class();
         let rust_object = Box::into_raw(Box::new(rust_object));
-        let ibinder = unsafe {
-            // Safety: `AIBinder_new` expects a valid class pointer (which we
-            // initialize via `get_class`), and an arbitrary pointer
-            // argument. The caller owns the returned `AIBinder` pointer, which
-            // is a strong reference to a `BBinder`. This reference should be
-            // decremented via `AIBinder_decStrong` when the reference lifetime
-            // ends.
-            sys::AIBinder_new(class.into(), rust_object as *mut c_void)
-        };
+        // Safety: `AIBinder_new` expects a valid class pointer (which we
+        // initialize via `get_class`), and an arbitrary pointer
+        // argument. The caller owns the returned `AIBinder` pointer, which
+        // is a strong reference to a `BBinder`. This reference should be
+        // decremented via `AIBinder_decStrong` when the reference lifetime
+        // ends.
+        let ibinder = unsafe { sys::AIBinder_new(class.into(), rust_object as *mut c_void) };
         let mut binder = Binder { ibinder, rust_object };
         binder.mark_stability(stability);
         binder
@@ -176,15 +174,14 @@
     ///        }
     ///        # }
     pub fn set_extension(&mut self, extension: &mut SpIBinder) -> Result<()> {
-        let status = unsafe {
-            // Safety: `AIBinder_setExtension` expects two valid, mutable
-            // `AIBinder` pointers. We are guaranteed that both `self` and
-            // `extension` contain valid `AIBinder` pointers, because they
-            // cannot be initialized without a valid
-            // pointer. `AIBinder_setExtension` does not take ownership of
-            // either parameter.
-            sys::AIBinder_setExtension(self.as_native_mut(), extension.as_native_mut())
-        };
+        let status =
+        // Safety: `AIBinder_setExtension` expects two valid, mutable
+        // `AIBinder` pointers. We are guaranteed that both `self` and
+        // `extension` contain valid `AIBinder` pointers, because they
+        // cannot be initialized without a valid
+        // pointer. `AIBinder_setExtension` does not take ownership of
+        // either parameter.
+            unsafe { sys::AIBinder_setExtension(self.as_native_mut(), extension.as_native_mut()) };
         status_result(status)
     }
 
@@ -199,9 +196,9 @@
         match stability {
             Stability::Local => self.mark_local_stability(),
             Stability::Vintf => {
+                // Safety: Self always contains a valid `AIBinder` pointer, so
+                // we can always call this C API safely.
                 unsafe {
-                    // Safety: Self always contains a valid `AIBinder` pointer, so
-                    // we can always call this C API safely.
                     sys::AIBinder_markVintfStability(self.as_native_mut());
                 }
             }
@@ -212,9 +209,9 @@
     /// building for android_vendor and system otherwise.
     #[cfg(android_vendor)]
     fn mark_local_stability(&mut self) {
+        // Safety: Self always contains a valid `AIBinder` pointer, so we can
+        // always call this C API safely.
         unsafe {
-            // Safety: Self always contains a valid `AIBinder` pointer, so
-            // we can always call this C API safely.
             sys::AIBinder_markVendorStability(self.as_native_mut());
         }
     }
@@ -223,9 +220,9 @@
     /// building for android_vendor and system otherwise.
     #[cfg(not(android_vendor))]
     fn mark_local_stability(&mut self) {
+        // Safety: Self always contains a valid `AIBinder` pointer, so we can
+        // always call this C API safely.
         unsafe {
-            // Safety: Self always contains a valid `AIBinder` pointer, so
-            // we can always call this C API safely.
             sys::AIBinder_markSystemStability(self.as_native_mut());
         }
     }
@@ -239,13 +236,13 @@
     /// remotable object, which will prevent the object from being dropped while
     /// the `SpIBinder` is alive.
     fn as_binder(&self) -> SpIBinder {
+        // Safety: `self.ibinder` is guaranteed to always be a valid pointer
+        // to an `AIBinder` by the `Binder` constructor. We are creating a
+        // copy of the `self.ibinder` strong reference, but
+        // `SpIBinder::from_raw` assumes it receives an owned pointer with
+        // its own strong reference. We first increment the reference count,
+        // so that the new `SpIBinder` will be tracked as a new reference.
         unsafe {
-            // Safety: `self.ibinder` is guaranteed to always be a valid pointer
-            // to an `AIBinder` by the `Binder` constructor. We are creating a
-            // copy of the `self.ibinder` strong reference, but
-            // `SpIBinder::from_raw` assumes it receives an owned pointer with
-            // its own strong reference. We first increment the reference count,
-            // so that the new `SpIBinder` will be tracked as a new reference.
             sys::AIBinder_incStrong(self.ibinder);
             SpIBinder::from_raw(self.ibinder).unwrap()
         }
@@ -275,10 +272,20 @@
         reply: *mut sys::AParcel,
     ) -> status_t {
         let res = {
-            let mut reply = BorrowedParcel::from_raw(reply).unwrap();
-            let data = BorrowedParcel::from_raw(data as *mut sys::AParcel).unwrap();
-            let object = sys::AIBinder_getUserData(binder);
-            let binder: &T = &*(object as *const T);
+            // Safety: The caller must give us a parcel pointer which is either
+            // null or valid at least for the duration of this function call. We
+            // don't keep the resulting value beyond the function.
+            let mut reply = unsafe { BorrowedParcel::from_raw(reply).unwrap() };
+            // Safety: The caller must give us a parcel pointer which is either
+            // null or valid at least for the duration of this function call. We
+            // don't keep the resulting value beyond the function.
+            let data = unsafe { BorrowedParcel::from_raw(data as *mut sys::AParcel).unwrap() };
+            // Safety: Our caller promised that `binder` is a non-null, valid
+            // pointer to a local `AIBinder`.
+            let object = unsafe { sys::AIBinder_getUserData(binder) };
+            // Safety: Our caller promised that the binder has a `T` pointer in
+            // its user data.
+            let binder: &T = unsafe { &*(object as *const T) };
             binder.on_transact(code, &data, &mut reply)
         };
         match res {
@@ -295,7 +302,9 @@
     /// Must be called with a valid pointer to a `T` object. After this call,
     /// the pointer will be invalid and should not be dereferenced.
     unsafe extern "C" fn on_destroy(object: *mut c_void) {
-        drop(Box::from_raw(object as *mut T));
+        // Safety: Our caller promised that `object` is a valid pointer to a
+        // `T`.
+        drop(unsafe { Box::from_raw(object as *mut T) });
     }
 
     /// Called whenever a new, local `AIBinder` object is needed of a specific
@@ -320,7 +329,7 @@
     /// Must be called with a non-null, valid pointer to a local `AIBinder` that
     /// contains a `T` pointer in its user data. fd should be a non-owned file
     /// descriptor, and args must be an array of null-terminated string
-    /// poiinters with length num_args.
+    /// pointers with length num_args.
     unsafe extern "C" fn on_dump(
         binder: *mut sys::AIBinder,
         fd: i32,
@@ -330,8 +339,9 @@
         if fd < 0 {
             return StatusCode::UNEXPECTED_NULL as status_t;
         }
-        // We don't own this file, so we need to be careful not to drop it.
-        let file = ManuallyDrop::new(File::from_raw_fd(fd));
+        // Safety: Our caller promised that fd is a file descriptor. We don't
+        // own this file descriptor, so we need to be careful not to drop it.
+        let file = unsafe { ManuallyDrop::new(File::from_raw_fd(fd)) };
 
         if args.is_null() && num_args != 0 {
             return StatusCode::UNEXPECTED_NULL as status_t;
@@ -340,14 +350,22 @@
         let args = if args.is_null() || num_args == 0 {
             vec![]
         } else {
-            slice::from_raw_parts(args, num_args as usize)
-                .iter()
-                .map(|s| CStr::from_ptr(*s))
-                .collect()
+            // Safety: Our caller promised that `args` is an array of
+            // null-terminated string pointers with length `num_args`.
+            unsafe {
+                slice::from_raw_parts(args, num_args as usize)
+                    .iter()
+                    .map(|s| CStr::from_ptr(*s))
+                    .collect()
+            }
         };
 
-        let object = sys::AIBinder_getUserData(binder);
-        let binder: &T = &*(object as *const T);
+        // Safety: Our caller promised that `binder` is a non-null, valid
+        // pointer to a local `AIBinder`.
+        let object = unsafe { sys::AIBinder_getUserData(binder) };
+        // Safety: Our caller promised that the binder has a `T` pointer in its
+        // user data.
+        let binder: &T = unsafe { &*(object as *const T) };
         let res = binder.on_dump(&file, &args);
 
         match res {
@@ -363,11 +381,11 @@
     // actually destroys the object, it calls `on_destroy` and we can drop the
     // `rust_object` then.
     fn drop(&mut self) {
+        // Safety: When `self` is dropped, we can no longer access the
+        // reference, so can decrement the reference count. `self.ibinder` is
+        // always a valid `AIBinder` pointer, so is valid to pass to
+        // `AIBinder_decStrong`.
         unsafe {
-            // Safety: When `self` is dropped, we can no longer access the
-            // reference, so can decrement the reference count. `self.ibinder`
-            // is always a valid `AIBinder` pointer, so is valid to pass to
-            // `AIBinder_decStrong`.
             sys::AIBinder_decStrong(self.ibinder);
         }
     }
@@ -377,14 +395,11 @@
     type Target = T;
 
     fn deref(&self) -> &Self::Target {
-        unsafe {
-            // Safety: While `self` is alive, the reference count of the
-            // underlying object is > 0 and therefore `on_destroy` cannot be
-            // called. Therefore while `self` is alive, we know that
-            // `rust_object` is still a valid pointer to a heap allocated object
-            // of type `T`.
-            &*self.rust_object
-        }
+        // Safety: While `self` is alive, the reference count of the underlying
+        // object is > 0 and therefore `on_destroy` cannot be called. Therefore
+        // while `self` is alive, we know that `rust_object` is still a valid
+        // pointer to a heap allocated object of type `T`.
+        unsafe { &*self.rust_object }
     }
 }
 
@@ -405,13 +420,10 @@
         if Some(class) != ibinder.get_class() {
             return Err(StatusCode::BAD_TYPE);
         }
-        let userdata = unsafe {
-            // Safety: `SpIBinder` always holds a valid pointer pointer to an
-            // `AIBinder`, which we can safely pass to
-            // `AIBinder_getUserData`. `ibinder` retains ownership of the
-            // returned pointer.
-            sys::AIBinder_getUserData(ibinder.as_native_mut())
-        };
+        // Safety: `SpIBinder` always holds a valid pointer pointer to an
+        // `AIBinder`, which we can safely pass to `AIBinder_getUserData`.
+        // `ibinder` retains ownership of the returned pointer.
+        let userdata = unsafe { sys::AIBinder_getUserData(ibinder.as_native_mut()) };
         if userdata.is_null() {
             return Err(StatusCode::UNEXPECTED_NULL);
         }
@@ -422,12 +434,10 @@
     }
 }
 
-/// # Safety
-///
-/// The constructor for `Binder` guarantees that `self.ibinder` will contain a
-/// valid, non-null pointer to an `AIBinder`, so this implementation is type
-/// safe. `self.ibinder` will remain valid for the entire lifetime of `self`
-/// because we hold a strong reference to the `AIBinder` until `self` is
+/// Safety: The constructor for `Binder` guarantees that `self.ibinder` will
+/// contain a valid, non-null pointer to an `AIBinder`, so this implementation
+/// is type safe. `self.ibinder` will remain valid for the entire lifetime of
+/// `self` because we hold a strong reference to the `AIBinder` until `self` is
 /// dropped.
 unsafe impl<B: Remotable> AsNative<sys::AIBinder> for Binder<B> {
     fn as_native(&self) -> *const sys::AIBinder {
@@ -447,14 +457,12 @@
 /// This function will panic if the identifier contains a 0 byte (NUL).
 pub fn add_service(identifier: &str, mut binder: SpIBinder) -> Result<()> {
     let instance = CString::new(identifier).unwrap();
-    let status = unsafe {
-        // Safety: `AServiceManager_addService` expects valid `AIBinder` and C
-        // string pointers. Caller retains ownership of both
-        // pointers. `AServiceManager_addService` creates a new strong reference
-        // and copies the string, so both pointers need only be valid until the
-        // call returns.
-        sys::AServiceManager_addService(binder.as_native_mut(), instance.as_ptr())
-    };
+    let status =
+    // Safety: `AServiceManager_addService` expects valid `AIBinder` and C
+    // string pointers. Caller retains ownership of both pointers.
+    // `AServiceManager_addService` creates a new strong reference and copies
+    // the string, so both pointers need only be valid until the call returns.
+        unsafe { sys::AServiceManager_addService(binder.as_native_mut(), instance.as_ptr()) };
     status_result(status)
 }
 
@@ -470,13 +478,12 @@
 /// This function will panic if the identifier contains a 0 byte (NUL).
 pub fn register_lazy_service(identifier: &str, mut binder: SpIBinder) -> Result<()> {
     let instance = CString::new(identifier).unwrap();
+    // Safety: `AServiceManager_registerLazyService` expects valid `AIBinder` and C
+    // string pointers. Caller retains ownership of both
+    // pointers. `AServiceManager_registerLazyService` creates a new strong reference
+    // and copies the string, so both pointers need only be valid until the
+    // call returns.
     let status = unsafe {
-        // Safety: `AServiceManager_registerLazyService` expects valid `AIBinder` and C
-        // string pointers. Caller retains ownership of both
-        // pointers. `AServiceManager_registerLazyService` creates a new strong reference
-        // and copies the string, so both pointers need only be valid until the
-        // call returns.
-
         sys::AServiceManager_registerLazyService(binder.as_native_mut(), instance.as_ptr())
     };
     status_result(status)
@@ -491,10 +498,8 @@
 ///
 /// Consider using [`LazyServiceGuard`] rather than calling this directly.
 pub fn force_lazy_services_persist(persist: bool) {
-    unsafe {
-        // Safety: No borrowing or transfer of ownership occurs here.
-        sys::AServiceManager_forceLazyServicesPersist(persist)
-    }
+    // Safety: No borrowing or transfer of ownership occurs here.
+    unsafe { sys::AServiceManager_forceLazyServicesPersist(persist) }
 }
 
 /// An RAII object to ensure a process which registers lazy services is not killed. During the
@@ -576,8 +581,6 @@
 /// Determine whether the current thread is currently executing an incoming
 /// transaction.
 pub fn is_handling_transaction() -> bool {
-    unsafe {
-        // Safety: This method is always safe to call.
-        sys::AIBinder_isHandlingTransaction()
-    }
+    // Safety: This method is always safe to call.
+    unsafe { sys::AIBinder_isHandlingTransaction() }
 }
diff --git a/libs/binder/rust/src/parcel.rs b/libs/binder/rust/src/parcel.rs
index e4c568e..0b0f9f9 100644
--- a/libs/binder/rust/src/parcel.rs
+++ b/libs/binder/rust/src/parcel.rs
@@ -52,11 +52,8 @@
     ptr: NonNull<sys::AParcel>,
 }
 
-/// # Safety
-///
-/// This type guarantees that it owns the AParcel and that all access to
-/// the AParcel happens through the Parcel, so it is ok to send across
-/// threads.
+/// Safety: This type guarantees that it owns the AParcel and that all access to
+/// the AParcel happens through the Parcel, so it is ok to send across threads.
 unsafe impl Send for Parcel {}
 
 /// Container for a message (data and object references) that can be sent
@@ -73,11 +70,9 @@
 impl Parcel {
     /// Create a new empty `Parcel`.
     pub fn new() -> Parcel {
-        let ptr = unsafe {
-            // Safety: If `AParcel_create` succeeds, it always returns
-            // a valid pointer. If it fails, the process will crash.
-            sys::AParcel_create()
-        };
+        // Safety: If `AParcel_create` succeeds, it always returns
+        // a valid pointer. If it fails, the process will crash.
+        let ptr = unsafe { sys::AParcel_create() };
         Self { ptr: NonNull::new(ptr).expect("AParcel_create returned null pointer") }
     }
 
@@ -171,10 +166,8 @@
     }
 }
 
-/// # Safety
-///
-/// The `Parcel` constructors guarantee that a `Parcel` object will always
-/// contain a valid pointer to an `AParcel`.
+/// Safety: The `Parcel` constructors guarantee that a `Parcel` object will
+/// always contain a valid pointer to an `AParcel`.
 unsafe impl AsNative<sys::AParcel> for Parcel {
     fn as_native(&self) -> *const sys::AParcel {
         self.ptr.as_ptr()
@@ -185,10 +178,8 @@
     }
 }
 
-/// # Safety
-///
-/// The `BorrowedParcel` constructors guarantee that a `BorrowedParcel` object
-/// will always contain a valid pointer to an `AParcel`.
+/// Safety: The `BorrowedParcel` constructors guarantee that a `BorrowedParcel`
+/// object will always contain a valid pointer to an `AParcel`.
 unsafe impl<'a> AsNative<sys::AParcel> for BorrowedParcel<'a> {
     fn as_native(&self) -> *const sys::AParcel {
         self.ptr.as_ptr()
@@ -203,10 +194,8 @@
 impl<'a> BorrowedParcel<'a> {
     /// Data written to parcelable is zero'd before being deleted or reallocated.
     pub fn mark_sensitive(&mut self) {
-        unsafe {
-            // Safety: guaranteed to have a parcel object, and this method never fails
-            sys::AParcel_markSensitive(self.as_native())
-        }
+        // Safety: guaranteed to have a parcel object, and this method never fails
+        unsafe { sys::AParcel_markSensitive(self.as_native()) }
     }
 
     /// Write a type that implements [`Serialize`] to the parcel.
@@ -265,11 +254,15 @@
             f(&mut subparcel)?;
         }
         let end = self.get_data_position();
+        // Safety: start is less than the current size of the parcel data
+        // buffer, because we just got it with `get_data_position`.
         unsafe {
             self.set_data_position(start)?;
         }
         assert!(end >= start);
         self.write(&(end - start))?;
+        // Safety: end is less than the current size of the parcel data
+        // buffer, because we just got it with `get_data_position`.
         unsafe {
             self.set_data_position(end)?;
         }
@@ -278,20 +271,16 @@
 
     /// Returns the current position in the parcel data.
     pub fn get_data_position(&self) -> i32 {
-        unsafe {
-            // Safety: `BorrowedParcel` always contains a valid pointer to an
-            // `AParcel`, and this call is otherwise safe.
-            sys::AParcel_getDataPosition(self.as_native())
-        }
+        // Safety: `BorrowedParcel` always contains a valid pointer to an
+        // `AParcel`, and this call is otherwise safe.
+        unsafe { sys::AParcel_getDataPosition(self.as_native()) }
     }
 
     /// Returns the total size of the parcel.
     pub fn get_data_size(&self) -> i32 {
-        unsafe {
-            // Safety: `BorrowedParcel` always contains a valid pointer to an
-            // `AParcel`, and this call is otherwise safe.
-            sys::AParcel_getDataSize(self.as_native())
-        }
+        // Safety: `BorrowedParcel` always contains a valid pointer to an
+        // `AParcel`, and this call is otherwise safe.
+        unsafe { sys::AParcel_getDataSize(self.as_native()) }
     }
 
     /// Move the current read/write position in the parcel.
@@ -304,7 +293,9 @@
     /// accesses are bounds checked, this call is still safe, but we can't rely
     /// on that.
     pub unsafe fn set_data_position(&self, pos: i32) -> Result<()> {
-        status_result(sys::AParcel_setDataPosition(self.as_native(), pos))
+        // Safety: `BorrowedParcel` always contains a valid pointer to an
+        // `AParcel`, and the caller guarantees that `pos` is within bounds.
+        status_result(unsafe { sys::AParcel_setDataPosition(self.as_native(), pos) })
     }
 
     /// Append a subset of another parcel.
@@ -317,10 +308,10 @@
         start: i32,
         size: i32,
     ) -> Result<()> {
+        // Safety: `Parcel::appendFrom` from C++ checks that `start`
+        // and `size` are in bounds, and returns an error otherwise.
+        // Both `self` and `other` always contain valid pointers.
         let status = unsafe {
-            // Safety: `Parcel::appendFrom` from C++ checks that `start`
-            // and `size` are in bounds, and returns an error otherwise.
-            // Both `self` and `other` always contain valid pointers.
             sys::AParcel_appendFrom(other.as_native(), self.as_native_mut(), start, size)
         };
         status_result(status)
@@ -418,7 +409,9 @@
     /// accesses are bounds checked, this call is still safe, but we can't rely
     /// on that.
     pub unsafe fn set_data_position(&self, pos: i32) -> Result<()> {
-        self.borrowed_ref().set_data_position(pos)
+        // Safety: We have the same safety requirements as
+        // `BorrowedParcel::set_data_position`.
+        unsafe { self.borrowed_ref().set_data_position(pos) }
     }
 
     /// Append a subset of another parcel.
@@ -461,7 +454,7 @@
     /// and call a closure with the sub-parcel as its parameter.
     /// The closure can keep reading data from the sub-parcel
     /// until it runs out of input data. The closure is responsible
-    /// for calling [`ReadableSubParcel::has_more_data`] to check for
+    /// for calling `ReadableSubParcel::has_more_data` to check for
     /// more data before every read, at least until Rust generators
     /// are stabilized.
     /// After the closure returns, skip to the end of the current
@@ -504,7 +497,10 @@
         f(subparcel)?;
 
         // Advance the data position to the actual end,
-        // in case the closure read less data than was available
+        // in case the closure read less data than was available.
+        //
+        // Safety: end must be less than the current size of the parcel, because
+        // we checked above against `get_data_size`.
         unsafe {
             self.set_data_position(end)?;
         }
@@ -595,7 +591,7 @@
     /// and call a closure with the sub-parcel as its parameter.
     /// The closure can keep reading data from the sub-parcel
     /// until it runs out of input data. The closure is responsible
-    /// for calling [`ReadableSubParcel::has_more_data`] to check for
+    /// for calling `ReadableSubParcel::has_more_data` to check for
     /// more data before every read, at least until Rust generators
     /// are stabilized.
     /// After the closure returns, skip to the end of the current
@@ -649,17 +645,17 @@
 // Internal APIs
 impl<'a> BorrowedParcel<'a> {
     pub(crate) fn write_binder(&mut self, binder: Option<&SpIBinder>) -> Result<()> {
+        // Safety: `BorrowedParcel` always contains a valid pointer to an
+        // `AParcel`. `AsNative` for `Option<SpIBinder`> will either return
+        // null or a valid pointer to an `AIBinder`, both of which are
+        // valid, safe inputs to `AParcel_writeStrongBinder`.
+        //
+        // This call does not take ownership of the binder. However, it does
+        // require a mutable pointer, which we cannot extract from an
+        // immutable reference, so we clone the binder, incrementing the
+        // refcount before the call. The refcount will be immediately
+        // decremented when this temporary is dropped.
         unsafe {
-            // Safety: `BorrowedParcel` always contains a valid pointer to an
-            // `AParcel`. `AsNative` for `Option<SpIBinder`> will either return
-            // null or a valid pointer to an `AIBinder`, both of which are
-            // valid, safe inputs to `AParcel_writeStrongBinder`.
-            //
-            // This call does not take ownership of the binder. However, it does
-            // require a mutable pointer, which we cannot extract from an
-            // immutable reference, so we clone the binder, incrementing the
-            // refcount before the call. The refcount will be immediately
-            // decremented when this temporary is dropped.
             status_result(sys::AParcel_writeStrongBinder(
                 self.as_native_mut(),
                 binder.cloned().as_native_mut(),
@@ -669,33 +665,28 @@
 
     pub(crate) fn read_binder(&self) -> Result<Option<SpIBinder>> {
         let mut binder = ptr::null_mut();
-        let status = unsafe {
-            // Safety: `BorrowedParcel` always contains a valid pointer to an
-            // `AParcel`. We pass a valid, mutable out pointer to the `binder`
-            // parameter. After this call, `binder` will be either null or a
-            // valid pointer to an `AIBinder` owned by the caller.
-            sys::AParcel_readStrongBinder(self.as_native(), &mut binder)
-        };
+        // Safety: `BorrowedParcel` always contains a valid pointer to an
+        // `AParcel`. We pass a valid, mutable out pointer to the `binder`
+        // parameter. After this call, `binder` will be either null or a
+        // valid pointer to an `AIBinder` owned by the caller.
+        let status = unsafe { sys::AParcel_readStrongBinder(self.as_native(), &mut binder) };
 
         status_result(status)?;
 
-        Ok(unsafe {
-            // Safety: `binder` is either null or a valid, owned pointer at this
-            // point, so can be safely passed to `SpIBinder::from_raw`.
-            SpIBinder::from_raw(binder)
-        })
+        // Safety: `binder` is either null or a valid, owned pointer at this
+        // point, so can be safely passed to `SpIBinder::from_raw`.
+        Ok(unsafe { SpIBinder::from_raw(binder) })
     }
 }
 
 impl Drop for Parcel {
     fn drop(&mut self) {
         // Run the C++ Parcel complete object destructor
-        unsafe {
-            // Safety: `Parcel` always contains a valid pointer to an
-            // `AParcel`. Since we own the parcel, we can safely delete it
-            // here.
-            sys::AParcel_delete(self.ptr.as_ptr())
-        }
+        //
+        // Safety: `Parcel` always contains a valid pointer to an
+        // `AParcel`. Since we own the parcel, we can safely delete it
+        // here.
+        unsafe { sys::AParcel_delete(self.ptr.as_ptr()) }
     }
 }
 
diff --git a/libs/binder/rust/src/parcel/file_descriptor.rs b/libs/binder/rust/src/parcel/file_descriptor.rs
index 7fe37f3..5c688fa 100644
--- a/libs/binder/rust/src/parcel/file_descriptor.rs
+++ b/libs/binder/rust/src/parcel/file_descriptor.rs
@@ -73,14 +73,12 @@
 impl Serialize for ParcelFileDescriptor {
     fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
         let fd = self.0.as_raw_fd();
-        let status = unsafe {
-            // Safety: `Parcel` always contains a valid pointer to an
-            // `AParcel`. Likewise, `ParcelFileDescriptor` always contains a
-            // valid file, so we can borrow a valid file
-            // descriptor. `AParcel_writeParcelFileDescriptor` does NOT take
-            // ownership of the fd, so we need not duplicate it first.
-            sys::AParcel_writeParcelFileDescriptor(parcel.as_native_mut(), fd)
-        };
+        // Safety: `Parcel` always contains a valid pointer to an
+        // `AParcel`. Likewise, `ParcelFileDescriptor` always contains a
+        // valid file, so we can borrow a valid file
+        // descriptor. `AParcel_writeParcelFileDescriptor` does NOT take
+        // ownership of the fd, so we need not duplicate it first.
+        let status = unsafe { sys::AParcel_writeParcelFileDescriptor(parcel.as_native_mut(), fd) };
         status_result(status)
     }
 }
@@ -92,13 +90,12 @@
         if let Some(f) = this {
             f.serialize(parcel)
         } else {
-            let status = unsafe {
-                // Safety: `Parcel` always contains a valid pointer to an
-                // `AParcel`. `AParcel_writeParcelFileDescriptor` accepts the
-                // value `-1` as the file descriptor to signify serializing a
-                // null file descriptor.
-                sys::AParcel_writeParcelFileDescriptor(parcel.as_native_mut(), -1i32)
-            };
+            let status =
+            // Safety: `Parcel` always contains a valid pointer to an
+            // `AParcel`. `AParcel_writeParcelFileDescriptor` accepts the
+            // value `-1` as the file descriptor to signify serializing a
+            // null file descriptor.
+                unsafe { sys::AParcel_writeParcelFileDescriptor(parcel.as_native_mut(), -1i32) };
             status_result(status)
         }
     }
@@ -107,25 +104,23 @@
 impl DeserializeOption for ParcelFileDescriptor {
     fn deserialize_option(parcel: &BorrowedParcel<'_>) -> Result<Option<Self>> {
         let mut fd = -1i32;
+        // Safety: `Parcel` always contains a valid pointer to an
+        // `AParcel`. We pass a valid mutable pointer to an i32, which
+        // `AParcel_readParcelFileDescriptor` assigns the valid file
+        // descriptor into, or `-1` if deserializing a null file
+        // descriptor. The read function passes ownership of the file
+        // descriptor to its caller if it was non-null, so we must take
+        // ownership of the file and ensure that it is eventually closed.
         unsafe {
-            // Safety: `Parcel` always contains a valid pointer to an
-            // `AParcel`. We pass a valid mutable pointer to an i32, which
-            // `AParcel_readParcelFileDescriptor` assigns the valid file
-            // descriptor into, or `-1` if deserializing a null file
-            // descriptor. The read function passes ownership of the file
-            // descriptor to its caller if it was non-null, so we must take
-            // ownership of the file and ensure that it is eventually closed.
             status_result(sys::AParcel_readParcelFileDescriptor(parcel.as_native(), &mut fd))?;
         }
         if fd < 0 {
             Ok(None)
         } else {
-            let file = unsafe {
-                // Safety: At this point, we know that the file descriptor was
-                // not -1, so must be a valid, owned file descriptor which we
-                // can safely turn into a `File`.
-                File::from_raw_fd(fd)
-            };
+            // Safety: At this point, we know that the file descriptor was
+            // not -1, so must be a valid, owned file descriptor which we
+            // can safely turn into a `File`.
+            let file = unsafe { File::from_raw_fd(fd) };
             Ok(Some(ParcelFileDescriptor::new(file)))
         }
     }
diff --git a/libs/binder/rust/src/parcel/parcelable.rs b/libs/binder/rust/src/parcel/parcelable.rs
index 5d8c11c..038f198 100644
--- a/libs/binder/rust/src/parcel/parcelable.rs
+++ b/libs/binder/rust/src/parcel/parcelable.rs
@@ -50,14 +50,14 @@
     fn read_from_parcel(&mut self, parcel: &BorrowedParcel<'_>) -> Result<()>;
 }
 
-/// A struct whose instances can be written to a [`Parcel`].
+/// A struct whose instances can be written to a [`crate::parcel::Parcel`].
 // Might be able to hook this up as a serde backend in the future?
 pub trait Serialize {
-    /// Serialize this instance into the given [`Parcel`].
+    /// Serialize this instance into the given [`crate::parcel::Parcel`].
     fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()>;
 }
 
-/// A struct whose instances can be restored from a [`Parcel`].
+/// A struct whose instances can be restored from a [`crate::parcel::Parcel`].
 // Might be able to hook this up as a serde backend in the future?
 pub trait Deserialize: Sized {
     /// Type for the uninitialized value of this type. Will be either `Self`
@@ -80,10 +80,10 @@
     /// Convert an initialized value of type `Self` into `Self::UninitType`.
     fn from_init(value: Self) -> Self::UninitType;
 
-    /// Deserialize an instance from the given [`Parcel`].
+    /// Deserialize an instance from the given [`crate::parcel::Parcel`].
     fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self>;
 
-    /// Deserialize an instance from the given [`Parcel`] onto the
+    /// Deserialize an instance from the given [`crate::parcel::Parcel`] onto the
     /// current object. This operation will overwrite the old value
     /// partially or completely, depending on how much data is available.
     fn deserialize_from(&mut self, parcel: &BorrowedParcel<'_>) -> Result<()> {
@@ -102,8 +102,8 @@
 pub trait SerializeArray: Serialize + Sized {
     /// Serialize an array of this type into the given parcel.
     fn serialize_array(slice: &[Self], parcel: &mut BorrowedParcel<'_>) -> Result<()> {
+        // Safety: Safe FFI, slice will always be a safe pointer to pass.
         let res = unsafe {
-            // Safety: Safe FFI, slice will always be a safe pointer to pass.
             sys::AParcel_writeParcelableArray(
                 parcel.as_native_mut(),
                 slice.as_ptr() as *const c_void,
@@ -117,7 +117,9 @@
 
 /// Callback to serialize an element of a generic parcelable array.
 ///
-/// Safety: We are relying on binder_ndk to not overrun our slice. As long as it
+/// # Safety
+///
+/// We are relying on binder_ndk to not overrun our slice. As long as it
 /// doesn't provide an index larger than the length of the original slice in
 /// serialize_array, this operation is safe. The index provided is zero-based.
 unsafe extern "C" fn serialize_element<T: Serialize>(
@@ -125,9 +127,14 @@
     array: *const c_void,
     index: usize,
 ) -> status_t {
-    let slice: &[T] = slice::from_raw_parts(array.cast(), index + 1);
+    // Safety: The caller guarantees that `array` is a valid pointer of the
+    // appropriate type.
+    let slice: &[T] = unsafe { slice::from_raw_parts(array.cast(), index + 1) };
 
-    let mut parcel = match BorrowedParcel::from_raw(parcel) {
+    // Safety: The caller must give us a parcel pointer which is either null or
+    // valid at least for the duration of this function call. We don't keep the
+    // resulting value beyond the function.
+    let mut parcel = match unsafe { BorrowedParcel::from_raw(parcel) } {
         None => return StatusCode::UNEXPECTED_NULL as status_t,
         Some(p) => p,
     };
@@ -142,9 +149,9 @@
     /// Deserialize an array of type from the given parcel.
     fn deserialize_array(parcel: &BorrowedParcel<'_>) -> Result<Option<Vec<Self>>> {
         let mut vec: Option<Vec<Self::UninitType>> = None;
+        // Safety: Safe FFI, vec is the correct opaque type expected by
+        // allocate_vec and deserialize_element.
         let res = unsafe {
-            // Safety: Safe FFI, vec is the correct opaque type expected by
-            // allocate_vec and deserialize_element.
             sys::AParcel_readParcelableArray(
                 parcel.as_native(),
                 &mut vec as *mut _ as *mut c_void,
@@ -153,21 +160,21 @@
             )
         };
         status_result(res)?;
-        let vec: Option<Vec<Self>> = unsafe {
-            // Safety: We are assuming that the NDK correctly initialized every
-            // element of the vector by now, so we know that all the
-            // UninitTypes are now properly initialized. We can transmute from
-            // Vec<T::UninitType> to Vec<T> because T::UninitType has the same
-            // alignment and size as T, so the pointer to the vector allocation
-            // will be compatible.
-            mem::transmute(vec)
-        };
+        // Safety: We are assuming that the NDK correctly initialized every
+        // element of the vector by now, so we know that all the
+        // UninitTypes are now properly initialized. We can transmute from
+        // Vec<T::UninitType> to Vec<T> because T::UninitType has the same
+        // alignment and size as T, so the pointer to the vector allocation
+        // will be compatible.
+        let vec: Option<Vec<Self>> = unsafe { mem::transmute(vec) };
         Ok(vec)
     }
 }
 
 /// Callback to deserialize a parcelable element.
 ///
+/// # Safety
+///
 /// The opaque array data pointer must be a mutable pointer to an
 /// `Option<Vec<T::UninitType>>` with at least enough elements for `index` to be valid
 /// (zero-based).
@@ -176,13 +183,18 @@
     array: *mut c_void,
     index: usize,
 ) -> status_t {
-    let vec = &mut *(array as *mut Option<Vec<T::UninitType>>);
+    // Safety: The caller guarantees that `array` is a valid pointer of the
+    // appropriate type.
+    let vec = unsafe { &mut *(array as *mut Option<Vec<T::UninitType>>) };
     let vec = match vec {
         Some(v) => v,
         None => return StatusCode::BAD_INDEX as status_t,
     };
 
-    let parcel = match BorrowedParcel::from_raw(parcel as *mut _) {
+    // Safety: The caller must give us a parcel pointer which is either null or
+    // valid at least for the duration of this function call. We don't keep the
+    // resulting value beyond the function.
+    let parcel = match unsafe { BorrowedParcel::from_raw(parcel as *mut _) } {
         None => return StatusCode::UNEXPECTED_NULL as status_t,
         Some(p) => p,
     };
@@ -254,16 +266,21 @@
 ///
 /// The opaque data pointer passed to the array read function must be a mutable
 /// pointer to an `Option<Vec<T::UninitType>>`. `buffer` will be assigned a mutable pointer
-/// to the allocated vector data if this function returns true.
+/// to the allocated vector data if this function returns true. `buffer` must be a valid pointer.
 unsafe extern "C" fn allocate_vec_with_buffer<T: Deserialize>(
     data: *mut c_void,
     len: i32,
     buffer: *mut *mut T,
 ) -> bool {
-    let res = allocate_vec::<T>(data, len);
-    let vec = &mut *(data as *mut Option<Vec<T::UninitType>>);
+    // Safety: We have the same safety requirements as `allocate_vec` for `data`.
+    let res = unsafe { allocate_vec::<T>(data, len) };
+    // Safety: The caller guarantees that `data` is a valid mutable pointer to the appropriate type.
+    let vec = unsafe { &mut *(data as *mut Option<Vec<T::UninitType>>) };
     if let Some(new_vec) = vec {
-        *buffer = new_vec.as_mut_ptr() as *mut T;
+        // Safety: The caller guarantees that `buffer` is a valid pointer.
+        unsafe {
+            *buffer = new_vec.as_mut_ptr() as *mut T;
+        }
     }
     res
 }
@@ -275,7 +292,8 @@
 /// The opaque data pointer passed to the array read function must be a mutable
 /// pointer to an `Option<Vec<T::UninitType>>`.
 unsafe extern "C" fn allocate_vec<T: Deserialize>(data: *mut c_void, len: i32) -> bool {
-    let vec = &mut *(data as *mut Option<Vec<T::UninitType>>);
+    // Safety: The caller guarantees that `data` is a valid mutable pointer to the appropriate type.
+    let vec = unsafe { &mut *(data as *mut Option<Vec<T::UninitType>>) };
     if len < 0 {
         *vec = None;
         return true;
@@ -286,7 +304,10 @@
     let mut new_vec: Vec<T::UninitType> = Vec::with_capacity(len as usize);
     new_vec.resize_with(len as usize, T::uninit);
 
-    ptr::write(vec, Some(new_vec));
+    // Safety: The caller guarantees that vec is a valid mutable pointer to the appropriate type.
+    unsafe {
+        ptr::write(vec, Some(new_vec));
+    }
     true
 }
 
@@ -305,21 +326,21 @@
     // Assert at compile time that `T` and `T::UninitType` have the same size and alignment.
     let _ = T::ASSERT_UNINIT_SIZE_AND_ALIGNMENT;
 
-    // We can convert from Vec<T::UninitType> to Vec<T> because T::UninitType
-    // has the same alignment and size as T, so the pointer to the vector
-    // allocation will be compatible.
     let mut vec = ManuallyDrop::new(vec);
-    Vec::from_raw_parts(vec.as_mut_ptr().cast(), vec.len(), vec.capacity())
+    // Safety: We can convert from Vec<T::UninitType> to Vec<T> because
+    // T::UninitType has the same alignment and size as T, so the pointer to the
+    // vector allocation will be compatible.
+    unsafe { Vec::from_raw_parts(vec.as_mut_ptr().cast(), vec.len(), vec.capacity()) }
 }
 
 macro_rules! impl_parcelable {
     {Serialize, $ty:ty, $write_fn:path} => {
         impl Serialize for $ty {
             fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
+                // Safety: `Parcel` always contains a valid pointer to an
+                // `AParcel`, and any `$ty` literal value is safe to pass to
+                // `$write_fn`.
                 unsafe {
-                    // Safety: `Parcel` always contains a valid pointer to an
-                    // `AParcel`, and any `$ty` literal value is safe to pass to
-                    // `$write_fn`.
                     status_result($write_fn(parcel.as_native_mut(), *self))
                 }
             }
@@ -333,11 +354,11 @@
             fn from_init(value: Self) -> Self::UninitType { value }
             fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> {
                 let mut val = Self::default();
+                // Safety: `Parcel` always contains a valid pointer to an
+                // `AParcel`. We pass a valid, mutable pointer to `val`, a
+                // literal of type `$ty`, and `$read_fn` will write the
+                // value read into `val` if successful
                 unsafe {
-                    // Safety: `Parcel` always contains a valid pointer to an
-                    // `AParcel`. We pass a valid, mutable pointer to `val`, a
-                    // literal of type `$ty`, and `$read_fn` will write the
-                    // value read into `val` if successful
                     status_result($read_fn(parcel.as_native(), &mut val))?
                 };
                 Ok(val)
@@ -348,13 +369,13 @@
     {SerializeArray, $ty:ty, $write_array_fn:path} => {
         impl SerializeArray for $ty {
             fn serialize_array(slice: &[Self], parcel: &mut BorrowedParcel<'_>) -> Result<()> {
+                // Safety: `Parcel` always contains a valid pointer to an
+                // `AParcel`. If the slice is > 0 length, `slice.as_ptr()`
+                // will be a valid pointer to an array of elements of type
+                // `$ty`. If the slice length is 0, `slice.as_ptr()` may be
+                // dangling, but this is safe since the pointer is not
+                // dereferenced if the length parameter is 0.
                 let status = unsafe {
-                    // Safety: `Parcel` always contains a valid pointer to an
-                    // `AParcel`. If the slice is > 0 length, `slice.as_ptr()`
-                    // will be a valid pointer to an array of elements of type
-                    // `$ty`. If the slice length is 0, `slice.as_ptr()` may be
-                    // dangling, but this is safe since the pointer is not
-                    // dereferenced if the length parameter is 0.
                     $write_array_fn(
                         parcel.as_native_mut(),
                         slice.as_ptr(),
@@ -373,11 +394,11 @@
         impl DeserializeArray for $ty {
             fn deserialize_array(parcel: &BorrowedParcel<'_>) -> Result<Option<Vec<Self>>> {
                 let mut vec: Option<Vec<Self::UninitType>> = None;
+                // Safety: `Parcel` always contains a valid pointer to an
+                // `AParcel`. `allocate_vec<T>` expects the opaque pointer to
+                // be of type `*mut Option<Vec<T::UninitType>>`, so `&mut vec` is
+                // correct for it.
                 let status = unsafe {
-                    // Safety: `Parcel` always contains a valid pointer to an
-                    // `AParcel`. `allocate_vec<T>` expects the opaque pointer to
-                    // be of type `*mut Option<Vec<T::UninitType>>`, so `&mut vec` is
-                    // correct for it.
                     $read_array_fn(
                         parcel.as_native(),
                         &mut vec as *mut _ as *mut c_void,
@@ -385,11 +406,11 @@
                     )
                 };
                 status_result(status)?;
+                // Safety: We are assuming that the NDK correctly
+                // initialized every element of the vector by now, so we
+                // know that all the UninitTypes are now properly
+                // initialized.
                 let vec: Option<Vec<Self>> = unsafe {
-                    // Safety: We are assuming that the NDK correctly
-                    // initialized every element of the vector by now, so we
-                    // know that all the UninitTypes are now properly
-                    // initialized.
                     vec.map(|vec| vec_assume_init(vec))
                 };
                 Ok(vec)
@@ -479,13 +500,13 @@
 
 impl SerializeArray for u8 {
     fn serialize_array(slice: &[Self], parcel: &mut BorrowedParcel<'_>) -> Result<()> {
+        // Safety: `Parcel` always contains a valid pointer to an
+        // `AParcel`. If the slice is > 0 length, `slice.as_ptr()` will be a
+        // valid pointer to an array of elements of type `$ty`. If the slice
+        // length is 0, `slice.as_ptr()` may be dangling, but this is safe
+        // since the pointer is not dereferenced if the length parameter is
+        // 0.
         let status = unsafe {
-            // Safety: `Parcel` always contains a valid pointer to an
-            // `AParcel`. If the slice is > 0 length, `slice.as_ptr()` will be a
-            // valid pointer to an array of elements of type `$ty`. If the slice
-            // length is 0, `slice.as_ptr()` may be dangling, but this is safe
-            // since the pointer is not dereferenced if the length parameter is
-            // 0.
             sys::AParcel_writeByteArray(
                 parcel.as_native_mut(),
                 slice.as_ptr() as *const i8,
@@ -518,13 +539,13 @@
 
 impl SerializeArray for i16 {
     fn serialize_array(slice: &[Self], parcel: &mut BorrowedParcel<'_>) -> Result<()> {
+        // Safety: `Parcel` always contains a valid pointer to an
+        // `AParcel`. If the slice is > 0 length, `slice.as_ptr()` will be a
+        // valid pointer to an array of elements of type `$ty`. If the slice
+        // length is 0, `slice.as_ptr()` may be dangling, but this is safe
+        // since the pointer is not dereferenced if the length parameter is
+        // 0.
         let status = unsafe {
-            // Safety: `Parcel` always contains a valid pointer to an
-            // `AParcel`. If the slice is > 0 length, `slice.as_ptr()` will be a
-            // valid pointer to an array of elements of type `$ty`. If the slice
-            // length is 0, `slice.as_ptr()` may be dangling, but this is safe
-            // since the pointer is not dereferenced if the length parameter is
-            // 0.
             sys::AParcel_writeCharArray(
                 parcel.as_native_mut(),
                 slice.as_ptr() as *const u16,
@@ -538,22 +559,22 @@
 impl SerializeOption for str {
     fn serialize_option(this: Option<&Self>, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
         match this {
+            // Safety: `Parcel` always contains a valid pointer to an
+            // `AParcel`. If the string pointer is null,
+            // `AParcel_writeString` requires that the length is -1 to
+            // indicate that we want to serialize a null string.
             None => unsafe {
-                // Safety: `Parcel` always contains a valid pointer to an
-                // `AParcel`. If the string pointer is null,
-                // `AParcel_writeString` requires that the length is -1 to
-                // indicate that we want to serialize a null string.
                 status_result(sys::AParcel_writeString(parcel.as_native_mut(), ptr::null(), -1))
             },
+            // Safety: `Parcel` always contains a valid pointer to an
+            // `AParcel`. `AParcel_writeString` assumes that we pass a utf-8
+            // string pointer of `length` bytes, which is what str in Rust
+            // is. The docstring for `AParcel_writeString` says that the
+            // string input should be null-terminated, but it doesn't
+            // actually rely on that fact in the code. If this ever becomes
+            // necessary, we will need to null-terminate the str buffer
+            // before sending it.
             Some(s) => unsafe {
-                // Safety: `Parcel` always contains a valid pointer to an
-                // `AParcel`. `AParcel_writeString` assumes that we pass a utf-8
-                // string pointer of `length` bytes, which is what str in Rust
-                // is. The docstring for `AParcel_writeString` says that the
-                // string input should be null-terminated, but it doesn't
-                // actually rely on that fact in the code. If this ever becomes
-                // necessary, we will need to null-terminate the str buffer
-                // before sending it.
                 status_result(sys::AParcel_writeString(
                     parcel.as_native_mut(),
                     s.as_ptr() as *const c_char,
@@ -597,11 +618,11 @@
 
     fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> {
         let mut vec: Option<Vec<u8>> = None;
+        // Safety: `Parcel` always contains a valid pointer to an `AParcel`.
+        // `Option<Vec<u8>>` is equivalent to the expected `Option<Vec<i8>>`
+        // for `allocate_vec`, so `vec` is safe to pass as the opaque data
+        // pointer on platforms where char is signed.
         let status = unsafe {
-            // Safety: `Parcel` always contains a valid pointer to an `AParcel`.
-            // `Option<Vec<u8>>` is equivalent to the expected `Option<Vec<i8>>`
-            // for `allocate_vec`, so `vec` is safe to pass as the opaque data
-            // pointer on platforms where char is signed.
             sys::AParcel_readString(
                 parcel.as_native(),
                 &mut vec as *mut _ as *mut c_void,
@@ -751,11 +772,11 @@
 
 impl Serialize for Status {
     fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
+        // Safety: `Parcel` always contains a valid pointer to an `AParcel`
+        // and `Status` always contains a valid pointer to an `AStatus`, so
+        // both parameters are valid and safe. This call does not take
+        // ownership of either of its parameters.
         unsafe {
-            // Safety: `Parcel` always contains a valid pointer to an `AParcel`
-            // and `Status` always contains a valid pointer to an `AStatus`, so
-            // both parameters are valid and safe. This call does not take
-            // ownership of either of its parameters.
             status_result(sys::AParcel_writeStatusHeader(parcel.as_native_mut(), self.as_native()))
         }
     }
@@ -772,21 +793,18 @@
 
     fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> {
         let mut status_ptr = ptr::null_mut();
-        let ret_status = unsafe {
-            // Safety: `Parcel` always contains a valid pointer to an
-            // `AParcel`. We pass a mutable out pointer which will be
-            // assigned a valid `AStatus` pointer if the function returns
-            // status OK. This function passes ownership of the status
-            // pointer to the caller, if it was assigned.
-            sys::AParcel_readStatusHeader(parcel.as_native(), &mut status_ptr)
-        };
+        let ret_status =
+        // Safety: `Parcel` always contains a valid pointer to an
+        // `AParcel`. We pass a mutable out pointer which will be
+        // assigned a valid `AStatus` pointer if the function returns
+        // status OK. This function passes ownership of the status
+        // pointer to the caller, if it was assigned.
+            unsafe { sys::AParcel_readStatusHeader(parcel.as_native(), &mut status_ptr) };
         status_result(ret_status)?;
-        Ok(unsafe {
-            // Safety: At this point, the return status of the read call was ok,
-            // so we know that `status_ptr` is a valid, owned pointer to an
-            // `AStatus`, from which we can safely construct a `Status` object.
-            Status::from_ptr(status_ptr)
-        })
+        // Safety: At this point, the return status of the read call was ok,
+        // so we know that `status_ptr` is a valid, owned pointer to an
+        // `AStatus`, from which we can safely construct a `Status` object.
+        Ok(unsafe { Status::from_ptr(status_ptr) })
     }
 }
 
@@ -880,7 +898,6 @@
 /// `Serialize`, `SerializeArray` and `SerializeOption` for
 /// structured parcelables. The target type must implement the
 /// `Parcelable` trait.
-/// ```
 #[macro_export]
 macro_rules! impl_serialize_for_parcelable {
     ($parcelable:ident) => {
diff --git a/libs/binder/rust/src/parcel/parcelable_holder.rs b/libs/binder/rust/src/parcel/parcelable_holder.rs
index eb82fb7..f906113 100644
--- a/libs/binder/rust/src/parcel/parcelable_holder.rs
+++ b/libs/binder/rust/src/parcel/parcelable_holder.rs
@@ -133,8 +133,8 @@
                 }
             }
             ParcelableHolderData::Parcel(ref mut parcel) => {
+                // Safety: 0 should always be a valid position.
                 unsafe {
-                    // Safety: 0 should always be a valid position.
                     parcel.set_data_position(0)?;
                 }
 
@@ -214,15 +214,15 @@
                 parcelable.write_to_parcel(parcel)?;
 
                 let end = parcel.get_data_position();
+                // Safety: we got the position from `get_data_position`.
                 unsafe {
-                    // Safety: we got the position from `get_data_position`.
                     parcel.set_data_position(length_start)?;
                 }
 
                 assert!(end >= data_start);
                 parcel.write(&(end - data_start))?;
+                // Safety: we got the position from `get_data_position`.
                 unsafe {
-                    // Safety: we got the position from `get_data_position`.
                     parcel.set_data_position(end)?;
                 }
 
@@ -260,11 +260,11 @@
         new_parcel.append_from(parcel, data_start, data_size)?;
         *self.data.get_mut().unwrap() = ParcelableHolderData::Parcel(new_parcel);
 
+        // Safety: `append_from` checks if `data_size` overflows
+        // `parcel` and returns `BAD_VALUE` if that happens. We also
+        // explicitly check for negative and zero `data_size` above,
+        // so `data_end` is guaranteed to be greater than `data_start`.
         unsafe {
-            // Safety: `append_from` checks if `data_size` overflows
-            // `parcel` and returns `BAD_VALUE` if that happens. We also
-            // explicitly check for negative and zero `data_size` above,
-            // so `data_end` is guaranteed to be greater than `data_start`.
             parcel.set_data_position(data_end)?;
         }
 
diff --git a/libs/binder/rust/src/proxy.rs b/libs/binder/rust/src/proxy.rs
index 036f6b4..dad3379 100644
--- a/libs/binder/rust/src/proxy.rs
+++ b/libs/binder/rust/src/proxy.rs
@@ -49,14 +49,12 @@
     }
 }
 
-/// # Safety
-///
-/// An `SpIBinder` is an immutable handle to a C++ IBinder, which is thread-safe
+/// Safety: An `SpIBinder` is an immutable handle to a C++ IBinder, which is
+/// thread-safe.
 unsafe impl Send for SpIBinder {}
 
-/// # Safety
-///
-/// An `SpIBinder` is an immutable handle to a C++ IBinder, which is thread-safe
+/// Safety: An `SpIBinder` is an immutable handle to a C++ IBinder, which is
+/// thread-safe.
 unsafe impl Sync for SpIBinder {}
 
 impl SpIBinder {
@@ -97,11 +95,9 @@
     /// Return true if this binder object is hosted in a different process than
     /// the current one.
     pub fn is_remote(&self) -> bool {
-        unsafe {
-            // Safety: `SpIBinder` guarantees that it always contains a valid
-            // `AIBinder` pointer.
-            sys::AIBinder_isRemote(self.as_native())
-        }
+        // Safety: `SpIBinder` guarantees that it always contains a valid
+        // `AIBinder` pointer.
+        unsafe { sys::AIBinder_isRemote(self.as_native()) }
     }
 
     /// Try to convert this Binder object into a trait object for the given
@@ -116,12 +112,12 @@
     /// Return the interface class of this binder object, if associated with
     /// one.
     pub fn get_class(&mut self) -> Option<InterfaceClass> {
+        // Safety: `SpIBinder` guarantees that it always contains a valid
+        // `AIBinder` pointer. `AIBinder_getClass` returns either a null
+        // pointer or a valid pointer to an `AIBinder_Class`. After mapping
+        // null to None, we can safely construct an `InterfaceClass` if the
+        // pointer was non-null.
         unsafe {
-            // Safety: `SpIBinder` guarantees that it always contains a valid
-            // `AIBinder` pointer. `AIBinder_getClass` returns either a null
-            // pointer or a valid pointer to an `AIBinder_Class`. After mapping
-            // null to None, we can safely construct an `InterfaceClass` if the
-            // pointer was non-null.
             let class = sys::AIBinder_getClass(self.as_native_mut());
             class.as_ref().map(|p| InterfaceClass::from_ptr(p))
         }
@@ -152,7 +148,8 @@
     ///
     /// See `SpIBinder::from_raw`.
     pub unsafe fn new_spibinder(ptr: *mut sys::AIBinder) -> Option<SpIBinder> {
-        SpIBinder::from_raw(ptr)
+        // Safety: The caller makes the same guarantees as this requires.
+        unsafe { SpIBinder::from_raw(ptr) }
     }
 }
 
@@ -171,30 +168,24 @@
 
 impl AssociateClass for SpIBinder {
     fn associate_class(&mut self, class: InterfaceClass) -> bool {
-        unsafe {
-            // Safety: `SpIBinder` guarantees that it always contains a valid
-            // `AIBinder` pointer. An `InterfaceClass` can always be converted
-            // into a valid `AIBinder_Class` pointer, so these parameters are
-            // always safe.
-            sys::AIBinder_associateClass(self.as_native_mut(), class.into())
-        }
+        // Safety: `SpIBinder` guarantees that it always contains a valid
+        // `AIBinder` pointer. An `InterfaceClass` can always be converted
+        // into a valid `AIBinder_Class` pointer, so these parameters are
+        // always safe.
+        unsafe { sys::AIBinder_associateClass(self.as_native_mut(), class.into()) }
     }
 }
 
 impl Ord for SpIBinder {
     fn cmp(&self, other: &Self) -> Ordering {
-        let less_than = unsafe {
-            // Safety: SpIBinder always holds a valid `AIBinder` pointer, so
-            // this pointer is always safe to pass to `AIBinder_lt` (null is
-            // also safe to pass to this function, but we should never do that).
-            sys::AIBinder_lt(self.0.as_ptr(), other.0.as_ptr())
-        };
-        let greater_than = unsafe {
-            // Safety: SpIBinder always holds a valid `AIBinder` pointer, so
-            // this pointer is always safe to pass to `AIBinder_lt` (null is
-            // also safe to pass to this function, but we should never do that).
-            sys::AIBinder_lt(other.0.as_ptr(), self.0.as_ptr())
-        };
+        // Safety: SpIBinder always holds a valid `AIBinder` pointer, so this
+        // pointer is always safe to pass to `AIBinder_lt` (null is also safe to
+        // pass to this function, but we should never do that).
+        let less_than = unsafe { sys::AIBinder_lt(self.0.as_ptr(), other.0.as_ptr()) };
+        // Safety: SpIBinder always holds a valid `AIBinder` pointer, so this
+        // pointer is always safe to pass to `AIBinder_lt` (null is also safe to
+        // pass to this function, but we should never do that).
+        let greater_than = unsafe { sys::AIBinder_lt(other.0.as_ptr(), self.0.as_ptr()) };
         if !less_than && !greater_than {
             Ordering::Equal
         } else if less_than {
@@ -221,10 +212,10 @@
 
 impl Clone for SpIBinder {
     fn clone(&self) -> Self {
+        // Safety: Cloning a strong reference must increment the reference
+        // count. We are guaranteed by the `SpIBinder` constructor
+        // invariants that `self.0` is always a valid `AIBinder` pointer.
         unsafe {
-            // Safety: Cloning a strong reference must increment the reference
-            // count. We are guaranteed by the `SpIBinder` constructor
-            // invariants that `self.0` is always a valid `AIBinder` pointer.
             sys::AIBinder_incStrong(self.0.as_ptr());
         }
         Self(self.0)
@@ -235,9 +226,9 @@
     // We hold a strong reference to the IBinder in SpIBinder and need to give up
     // this reference on drop.
     fn drop(&mut self) {
+        // Safety: SpIBinder always holds a valid `AIBinder` pointer, so we
+        // know this pointer is safe to pass to `AIBinder_decStrong` here.
         unsafe {
-            // Safety: SpIBinder always holds a valid `AIBinder` pointer, so we
-            // know this pointer is safe to pass to `AIBinder_decStrong` here.
             sys::AIBinder_decStrong(self.as_native_mut());
         }
     }
@@ -246,26 +237,24 @@
 impl<T: AsNative<sys::AIBinder>> IBinderInternal for T {
     fn prepare_transact(&self) -> Result<Parcel> {
         let mut input = ptr::null_mut();
+        // Safety: `SpIBinder` guarantees that `self` always contains a
+        // valid pointer to an `AIBinder`. It is safe to cast from an
+        // immutable pointer to a mutable pointer here, because
+        // `AIBinder_prepareTransaction` only calls immutable `AIBinder`
+        // methods but the parameter is unfortunately not marked as const.
+        //
+        // After the call, input will be either a valid, owned `AParcel`
+        // pointer, or null.
         let status = unsafe {
-            // Safety: `SpIBinder` guarantees that `self` always contains a
-            // valid pointer to an `AIBinder`. It is safe to cast from an
-            // immutable pointer to a mutable pointer here, because
-            // `AIBinder_prepareTransaction` only calls immutable `AIBinder`
-            // methods but the parameter is unfortunately not marked as const.
-            //
-            // After the call, input will be either a valid, owned `AParcel`
-            // pointer, or null.
             sys::AIBinder_prepareTransaction(self.as_native() as *mut sys::AIBinder, &mut input)
         };
 
         status_result(status)?;
 
-        unsafe {
-            // Safety: At this point, `input` is either a valid, owned `AParcel`
-            // pointer, or null. `OwnedParcel::from_raw` safely handles both cases,
-            // taking ownership of the parcel.
-            Parcel::from_raw(input).ok_or(StatusCode::UNEXPECTED_NULL)
-        }
+        // Safety: At this point, `input` is either a valid, owned `AParcel`
+        // pointer, or null. `OwnedParcel::from_raw` safely handles both cases,
+        // taking ownership of the parcel.
+        unsafe { Parcel::from_raw(input).ok_or(StatusCode::UNEXPECTED_NULL) }
     }
 
     fn submit_transact(
@@ -275,23 +264,23 @@
         flags: TransactionFlags,
     ) -> Result<Parcel> {
         let mut reply = ptr::null_mut();
+        // Safety: `SpIBinder` guarantees that `self` always contains a
+        // valid pointer to an `AIBinder`. Although `IBinder::transact` is
+        // not a const method, it is still safe to cast our immutable
+        // pointer to mutable for the call. First, `IBinder::transact` is
+        // thread-safe, so concurrency is not an issue. The only way that
+        // `transact` can affect any visible, mutable state in the current
+        // process is by calling `onTransact` for a local service. However,
+        // in order for transactions to be thread-safe, this method must
+        // dynamically lock its data before modifying it. We enforce this
+        // property in Rust by requiring `Sync` for remotable objects and
+        // only providing `on_transact` with an immutable reference to
+        // `self`.
+        //
+        // This call takes ownership of the `data` parcel pointer, and
+        // passes ownership of the `reply` out parameter to its caller. It
+        // does not affect ownership of the `binder` parameter.
         let status = unsafe {
-            // Safety: `SpIBinder` guarantees that `self` always contains a
-            // valid pointer to an `AIBinder`. Although `IBinder::transact` is
-            // not a const method, it is still safe to cast our immutable
-            // pointer to mutable for the call. First, `IBinder::transact` is
-            // thread-safe, so concurrency is not an issue. The only way that
-            // `transact` can affect any visible, mutable state in the current
-            // process is by calling `onTransact` for a local service. However,
-            // in order for transactions to be thread-safe, this method must
-            // dynamically lock its data before modifying it. We enforce this
-            // property in Rust by requiring `Sync` for remotable objects and
-            // only providing `on_transact` with an immutable reference to
-            // `self`.
-            //
-            // This call takes ownership of the `data` parcel pointer, and
-            // passes ownership of the `reply` out parameter to its caller. It
-            // does not affect ownership of the `binder` parameter.
             sys::AIBinder_transact(
                 self.as_native() as *mut sys::AIBinder,
                 code,
@@ -302,45 +291,45 @@
         };
         status_result(status)?;
 
-        unsafe {
-            // Safety: `reply` is either a valid `AParcel` pointer or null
-            // after the call to `AIBinder_transact` above, so we can
-            // construct a `Parcel` out of it. `AIBinder_transact` passes
-            // ownership of the `reply` parcel to Rust, so we need to
-            // construct an owned variant.
-            Parcel::from_raw(reply).ok_or(StatusCode::UNEXPECTED_NULL)
-        }
+        // Safety: `reply` is either a valid `AParcel` pointer or null
+        // after the call to `AIBinder_transact` above, so we can
+        // construct a `Parcel` out of it. `AIBinder_transact` passes
+        // ownership of the `reply` parcel to Rust, so we need to
+        // construct an owned variant.
+        unsafe { Parcel::from_raw(reply).ok_or(StatusCode::UNEXPECTED_NULL) }
     }
 
     fn is_binder_alive(&self) -> bool {
-        unsafe {
-            // Safety: `SpIBinder` guarantees that `self` always contains a
-            // valid pointer to an `AIBinder`.
-            //
-            // This call does not affect ownership of its pointer parameter.
-            sys::AIBinder_isAlive(self.as_native())
-        }
+        // Safety: `SpIBinder` guarantees that `self` always contains a valid
+        // pointer to an `AIBinder`.
+        //
+        // This call does not affect ownership of its pointer parameter.
+        unsafe { sys::AIBinder_isAlive(self.as_native()) }
     }
 
     #[cfg(not(android_vndk))]
     fn set_requesting_sid(&mut self, enable: bool) {
+        // Safety: `SpIBinder` guarantees that `self` always contains a valid
+        // pointer to an `AIBinder`.
+        //
+        // This call does not affect ownership of its pointer parameter.
         unsafe { sys::AIBinder_setRequestingSid(self.as_native_mut(), enable) };
     }
 
     fn dump<F: AsRawFd>(&mut self, fp: &F, args: &[&str]) -> Result<()> {
         let args: Vec<_> = args.iter().map(|a| CString::new(*a).unwrap()).collect();
         let mut arg_ptrs: Vec<_> = args.iter().map(|a| a.as_ptr()).collect();
+        // Safety: `SpIBinder` guarantees that `self` always contains a
+        // valid pointer to an `AIBinder`. `AsRawFd` guarantees that the
+        // file descriptor parameter is always be a valid open file. The
+        // `args` pointer parameter is a valid pointer to an array of C
+        // strings that will outlive the call since `args` lives for the
+        // whole function scope.
+        //
+        // This call does not affect ownership of its binder pointer
+        // parameter and does not take ownership of the file or args array
+        // parameters.
         let status = unsafe {
-            // Safety: `SpIBinder` guarantees that `self` always contains a
-            // valid pointer to an `AIBinder`. `AsRawFd` guarantees that the
-            // file descriptor parameter is always be a valid open file. The
-            // `args` pointer parameter is a valid pointer to an array of C
-            // strings that will outlive the call since `args` lives for the
-            // whole function scope.
-            //
-            // This call does not affect ownership of its binder pointer
-            // parameter and does not take ownership of the file or args array
-            // parameters.
             sys::AIBinder_dump(
                 self.as_native_mut(),
                 fp.as_raw_fd(),
@@ -353,22 +342,18 @@
 
     fn get_extension(&mut self) -> Result<Option<SpIBinder>> {
         let mut out = ptr::null_mut();
-        let status = unsafe {
-            // Safety: `SpIBinder` guarantees that `self` always contains a
-            // valid pointer to an `AIBinder`. After this call, the `out`
-            // parameter will be either null, or a valid pointer to an
-            // `AIBinder`.
-            //
-            // This call passes ownership of the out pointer to its caller
-            // (assuming it is set to a non-null value).
-            sys::AIBinder_getExtension(self.as_native_mut(), &mut out)
-        };
-        let ibinder = unsafe {
-            // Safety: The call above guarantees that `out` is either null or a
-            // valid, owned pointer to an `AIBinder`, both of which are safe to
-            // pass to `SpIBinder::from_raw`.
-            SpIBinder::from_raw(out)
-        };
+        // Safety: `SpIBinder` guarantees that `self` always contains a
+        // valid pointer to an `AIBinder`. After this call, the `out`
+        // parameter will be either null, or a valid pointer to an
+        // `AIBinder`.
+        //
+        // This call passes ownership of the out pointer to its caller
+        // (assuming it is set to a non-null value).
+        let status = unsafe { sys::AIBinder_getExtension(self.as_native_mut(), &mut out) };
+        // Safety: The call above guarantees that `out` is either null or a
+        // valid, owned pointer to an `AIBinder`, both of which are safe to
+        // pass to `SpIBinder::from_raw`.
+        let ibinder = unsafe { SpIBinder::from_raw(out) };
 
         status_result(status)?;
         Ok(ibinder)
@@ -377,17 +362,17 @@
 
 impl<T: AsNative<sys::AIBinder>> IBinder for T {
     fn link_to_death(&mut self, recipient: &mut DeathRecipient) -> Result<()> {
+        // Safety: `SpIBinder` guarantees that `self` always contains a
+        // valid pointer to an `AIBinder`. `recipient` can always be
+        // converted into a valid pointer to an
+        // `AIBinder_DeathRecipient`.
+        //
+        // The cookie is also the correct pointer, and by calling new_cookie,
+        // we have created a new ref-count to the cookie, which linkToDeath
+        // takes ownership of. Once the DeathRecipient is unlinked for any
+        // reason (including if this call fails), the onUnlinked callback
+        // will consume that ref-count.
         status_result(unsafe {
-            // Safety: `SpIBinder` guarantees that `self` always contains a
-            // valid pointer to an `AIBinder`. `recipient` can always be
-            // converted into a valid pointer to an
-            // `AIBinder_DeathRecipient`.
-            //
-            // The cookie is also the correct pointer, and by calling new_cookie,
-            // we have created a new ref-count to the cookie, which linkToDeath
-            // takes ownership of. Once the DeathRecipient is unlinked for any
-            // reason (including if this call fails), the onUnlinked callback
-            // will consume that ref-count.
             sys::AIBinder_linkToDeath(
                 self.as_native_mut(),
                 recipient.as_native_mut(),
@@ -397,13 +382,13 @@
     }
 
     fn unlink_to_death(&mut self, recipient: &mut DeathRecipient) -> Result<()> {
+        // Safety: `SpIBinder` guarantees that `self` always contains a
+        // valid pointer to an `AIBinder`. `recipient` can always be
+        // converted into a valid pointer to an
+        // `AIBinder_DeathRecipient`. Any value is safe to pass as the
+        // cookie, although we depend on this value being set by
+        // `get_cookie` when the death recipient callback is called.
         status_result(unsafe {
-            // Safety: `SpIBinder` guarantees that `self` always contains a
-            // valid pointer to an `AIBinder`. `recipient` can always be
-            // converted into a valid pointer to an
-            // `AIBinder_DeathRecipient`. Any value is safe to pass as the
-            // cookie, although we depend on this value being set by
-            // `get_cookie` when the death recipient callback is called.
             sys::AIBinder_unlinkToDeath(
                 self.as_native_mut(),
                 recipient.as_native_mut(),
@@ -413,13 +398,11 @@
     }
 
     fn ping_binder(&mut self) -> Result<()> {
-        let status = unsafe {
-            // Safety: `SpIBinder` guarantees that `self` always contains a
-            // valid pointer to an `AIBinder`.
-            //
-            // This call does not affect ownership of its pointer parameter.
-            sys::AIBinder_ping(self.as_native_mut())
-        };
+        // Safety: `SpIBinder` guarantees that `self` always contains a
+        // valid pointer to an `AIBinder`.
+        //
+        // This call does not affect ownership of its pointer parameter.
+        let status = unsafe { sys::AIBinder_ping(self.as_native_mut()) };
         status_result(status)
     }
 }
@@ -472,35 +455,31 @@
     }
 }
 
-/// # Safety
-///
-/// A `WpIBinder` is an immutable handle to a C++ IBinder, which is thread-safe.
+/// Safety: A `WpIBinder` is an immutable handle to a C++ IBinder, which is
+/// thread-safe.
 unsafe impl Send for WpIBinder {}
 
-/// # Safety
-///
-/// A `WpIBinder` is an immutable handle to a C++ IBinder, which is thread-safe.
+/// Safety: A `WpIBinder` is an immutable handle to a C++ IBinder, which is
+/// thread-safe.
 unsafe impl Sync for WpIBinder {}
 
 impl WpIBinder {
     /// Create a new weak reference from an object that can be converted into a
     /// raw `AIBinder` pointer.
     fn new<B: AsNative<sys::AIBinder>>(binder: &mut B) -> WpIBinder {
-        let ptr = unsafe {
-            // Safety: `SpIBinder` guarantees that `binder` always contains a
-            // valid pointer to an `AIBinder`.
-            sys::AIBinder_Weak_new(binder.as_native_mut())
-        };
+        // Safety: `SpIBinder` guarantees that `binder` always contains a valid
+        // pointer to an `AIBinder`.
+        let ptr = unsafe { sys::AIBinder_Weak_new(binder.as_native_mut()) };
         Self(ptr::NonNull::new(ptr).expect("Unexpected null pointer from AIBinder_Weak_new"))
     }
 
     /// Promote this weak reference to a strong reference to the binder object.
     pub fn promote(&self) -> Option<SpIBinder> {
+        // Safety: `WpIBinder` always contains a valid weak reference, so we can
+        // pass this pointer to `AIBinder_Weak_promote`. Returns either null or
+        // an AIBinder owned by the caller, both of which are valid to pass to
+        // `SpIBinder::from_raw`.
         unsafe {
-            // Safety: `WpIBinder` always contains a valid weak reference, so we
-            // can pass this pointer to `AIBinder_Weak_promote`. Returns either
-            // null or an AIBinder owned by the caller, both of which are valid
-            // to pass to `SpIBinder::from_raw`.
             let ptr = sys::AIBinder_Weak_promote(self.0.as_ptr());
             SpIBinder::from_raw(ptr)
         }
@@ -509,35 +488,27 @@
 
 impl Clone for WpIBinder {
     fn clone(&self) -> Self {
-        let ptr = unsafe {
-            // Safety: WpIBinder always holds a valid `AIBinder_Weak` pointer,
-            // so this pointer is always safe to pass to `AIBinder_Weak_clone`
-            // (although null is also a safe value to pass to this API).
-            //
-            // We get ownership of the returned pointer, so can construct a new
-            // WpIBinder object from it.
-            sys::AIBinder_Weak_clone(self.0.as_ptr())
-        };
+        // Safety: WpIBinder always holds a valid `AIBinder_Weak` pointer, so
+        // this pointer is always safe to pass to `AIBinder_Weak_clone`
+        // (although null is also a safe value to pass to this API).
+        //
+        // We get ownership of the returned pointer, so can construct a new
+        // WpIBinder object from it.
+        let ptr = unsafe { sys::AIBinder_Weak_clone(self.0.as_ptr()) };
         Self(ptr::NonNull::new(ptr).expect("Unexpected null pointer from AIBinder_Weak_clone"))
     }
 }
 
 impl Ord for WpIBinder {
     fn cmp(&self, other: &Self) -> Ordering {
-        let less_than = unsafe {
-            // Safety: WpIBinder always holds a valid `AIBinder_Weak` pointer,
-            // so this pointer is always safe to pass to `AIBinder_Weak_lt`
-            // (null is also safe to pass to this function, but we should never
-            // do that).
-            sys::AIBinder_Weak_lt(self.0.as_ptr(), other.0.as_ptr())
-        };
-        let greater_than = unsafe {
-            // Safety: WpIBinder always holds a valid `AIBinder_Weak` pointer,
-            // so this pointer is always safe to pass to `AIBinder_Weak_lt`
-            // (null is also safe to pass to this function, but we should never
-            // do that).
-            sys::AIBinder_Weak_lt(other.0.as_ptr(), self.0.as_ptr())
-        };
+        // Safety: WpIBinder always holds a valid `AIBinder_Weak` pointer, so
+        // this pointer is always safe to pass to `AIBinder_Weak_lt` (null is
+        // also safe to pass to this function, but we should never do that).
+        let less_than = unsafe { sys::AIBinder_Weak_lt(self.0.as_ptr(), other.0.as_ptr()) };
+        // Safety: WpIBinder always holds a valid `AIBinder_Weak` pointer, so
+        // this pointer is always safe to pass to `AIBinder_Weak_lt` (null is
+        // also safe to pass to this function, but we should never do that).
+        let greater_than = unsafe { sys::AIBinder_Weak_lt(other.0.as_ptr(), self.0.as_ptr()) };
         if !less_than && !greater_than {
             Ordering::Equal
         } else if less_than {
@@ -564,9 +535,9 @@
 
 impl Drop for WpIBinder {
     fn drop(&mut self) {
+        // Safety: WpIBinder always holds a valid `AIBinder_Weak` pointer, so we
+        // know this pointer is safe to pass to `AIBinder_Weak_delete` here.
         unsafe {
-            // Safety: WpIBinder always holds a valid `AIBinder_Weak` pointer, so we
-            // know this pointer is safe to pass to `AIBinder_Weak_delete` here.
             sys::AIBinder_Weak_delete(self.0.as_ptr());
         }
     }
@@ -574,7 +545,7 @@
 
 /// Rust wrapper around DeathRecipient objects.
 ///
-/// The cookie in this struct represents an Arc<F> for the owned callback.
+/// The cookie in this struct represents an `Arc<F>` for the owned callback.
 /// This struct owns a ref-count of it, and so does every binder that we
 /// have been linked with.
 ///
@@ -592,17 +563,13 @@
     cookie_decr_refcount: unsafe extern "C" fn(*mut c_void),
 }
 
-/// # Safety
-///
-/// A `DeathRecipient` is a wrapper around `AIBinder_DeathRecipient` and a pointer
-/// to a `Fn` which is `Sync` and `Send` (the cookie field). As
+/// Safety: A `DeathRecipient` is a wrapper around `AIBinder_DeathRecipient` and
+/// a pointer to a `Fn` which is `Sync` and `Send` (the cookie field). As
 /// `AIBinder_DeathRecipient` is threadsafe, this structure is too.
 unsafe impl Send for DeathRecipient {}
 
-/// # Safety
-///
-/// A `DeathRecipient` is a wrapper around `AIBinder_DeathRecipient` and a pointer
-/// to a `Fn` which is `Sync` and `Send` (the cookie field). As
+/// Safety: A `DeathRecipient` is a wrapper around `AIBinder_DeathRecipient` and
+/// a pointer to a `Fn` which is `Sync` and `Send` (the cookie field). As
 /// `AIBinder_DeathRecipient` is threadsafe, this structure is too.
 unsafe impl Sync for DeathRecipient {}
 
@@ -614,19 +581,17 @@
         F: Fn() + Send + Sync + 'static,
     {
         let callback: *const F = Arc::into_raw(Arc::new(callback));
-        let recipient = unsafe {
-            // Safety: The function pointer is a valid death recipient callback.
-            //
-            // This call returns an owned `AIBinder_DeathRecipient` pointer
-            // which must be destroyed via `AIBinder_DeathRecipient_delete` when
-            // no longer needed.
-            sys::AIBinder_DeathRecipient_new(Some(Self::binder_died::<F>))
-        };
+        // Safety: The function pointer is a valid death recipient callback.
+        //
+        // This call returns an owned `AIBinder_DeathRecipient` pointer which
+        // must be destroyed via `AIBinder_DeathRecipient_delete` when no longer
+        // needed.
+        let recipient = unsafe { sys::AIBinder_DeathRecipient_new(Some(Self::binder_died::<F>)) };
+        // Safety: The function pointer is a valid onUnlinked callback.
+        //
+        // All uses of linkToDeath in this file correctly increment the
+        // ref-count that this onUnlinked callback will decrement.
         unsafe {
-            // Safety: The function pointer is a valid onUnlinked callback.
-            //
-            // All uses of linkToDeath in this file correctly increment the
-            // ref-count that this onUnlinked callback will decrement.
             sys::AIBinder_DeathRecipient_setOnUnlinked(
                 recipient,
                 Some(Self::cookie_decr_refcount::<F>),
@@ -648,7 +613,12 @@
     ///
     /// The caller must handle the returned ref-count correctly.
     unsafe fn new_cookie(&self) -> *mut c_void {
-        (self.vtable.cookie_incr_refcount)(self.cookie);
+        // Safety: `cookie_incr_refcount` points to
+        // `Self::cookie_incr_refcount`, and `self.cookie` is the cookie for an
+        // Arc<F>.
+        unsafe {
+            (self.vtable.cookie_incr_refcount)(self.cookie);
+        }
 
         // Return a raw pointer with ownership of a ref-count
         self.cookie
@@ -667,13 +637,14 @@
     ///
     /// # Safety
     ///
-    /// The `cookie` parameter must be the cookie for an Arc<F> and
+    /// The `cookie` parameter must be the cookie for an `Arc<F>` and
     /// the caller must hold a ref-count to it.
     unsafe extern "C" fn binder_died<F>(cookie: *mut c_void)
     where
         F: Fn() + Send + Sync + 'static,
     {
-        let callback = (cookie as *const F).as_ref().unwrap();
+        // Safety: The caller promises that `cookie` is for an Arc<F>.
+        let callback = unsafe { (cookie as *const F).as_ref().unwrap() };
         callback();
     }
 
@@ -682,34 +653,34 @@
     ///
     /// # Safety
     ///
-    /// The `cookie` parameter must be the cookie for an Arc<F> and
+    /// The `cookie` parameter must be the cookie for an `Arc<F>` and
     /// the owner must give up a ref-count to it.
     unsafe extern "C" fn cookie_decr_refcount<F>(cookie: *mut c_void)
     where
         F: Fn() + Send + Sync + 'static,
     {
-        drop(Arc::from_raw(cookie as *const F));
+        // Safety: The caller promises that `cookie` is for an Arc<F>.
+        drop(unsafe { Arc::from_raw(cookie as *const F) });
     }
 
     /// Callback that increments the ref-count.
     ///
     /// # Safety
     ///
-    /// The `cookie` parameter must be the cookie for an Arc<F> and
+    /// The `cookie` parameter must be the cookie for an `Arc<F>` and
     /// the owner must handle the created ref-count properly.
     unsafe extern "C" fn cookie_incr_refcount<F>(cookie: *mut c_void)
     where
         F: Fn() + Send + Sync + 'static,
     {
-        let arc = mem::ManuallyDrop::new(Arc::from_raw(cookie as *const F));
+        // Safety: The caller promises that `cookie` is for an Arc<F>.
+        let arc = mem::ManuallyDrop::new(unsafe { Arc::from_raw(cookie as *const F) });
         mem::forget(Arc::clone(&arc));
     }
 }
 
-/// # Safety
-///
-/// A `DeathRecipient` is always constructed with a valid raw pointer to an
-/// `AIBinder_DeathRecipient`, so it is always type-safe to extract this
+/// Safety: A `DeathRecipient` is always constructed with a valid raw pointer to
+/// an `AIBinder_DeathRecipient`, so it is always type-safe to extract this
 /// pointer.
 unsafe impl AsNative<sys::AIBinder_DeathRecipient> for DeathRecipient {
     fn as_native(&self) -> *const sys::AIBinder_DeathRecipient {
@@ -723,18 +694,19 @@
 
 impl Drop for DeathRecipient {
     fn drop(&mut self) {
+        // Safety: `self.recipient` is always a valid, owned
+        // `AIBinder_DeathRecipient` pointer returned by
+        // `AIBinder_DeathRecipient_new` when `self` was created. This delete
+        // method can only be called once when `self` is dropped.
         unsafe {
-            // Safety: `self.recipient` is always a valid, owned
-            // `AIBinder_DeathRecipient` pointer returned by
-            // `AIBinder_DeathRecipient_new` when `self` was created. This
-            // delete method can only be called once when `self` is dropped.
             sys::AIBinder_DeathRecipient_delete(self.recipient);
+        }
 
-            // Safety: We own a ref-count to the cookie, and so does every
-            // linked binder. This call gives up our ref-count. The linked
-            // binders should already have given up their ref-count, or should
-            // do so shortly.
-            (self.vtable.cookie_decr_refcount)(self.cookie)
+        // Safety: We own a ref-count to the cookie, and so does every linked
+        // binder. This call gives up our ref-count. The linked binders should
+        // already have given up their ref-count, or should do so shortly.
+        unsafe {
+            (self.vtable.cookie_decr_refcount)(self.cookie);
         }
     }
 }
@@ -754,11 +726,9 @@
     fn from_binder(binder: SpIBinder) -> Result<Self>;
 }
 
-/// # Safety
-///
-/// This is a convenience method that wraps `AsNative` for `SpIBinder` to allow
-/// invocation of `IBinder` methods directly from `Interface` objects. It shares
-/// the same safety as the implementation for `SpIBinder`.
+/// Safety: This is a convenience method that wraps `AsNative` for `SpIBinder`
+/// to allow invocation of `IBinder` methods directly from `Interface` objects.
+/// It shares the same safety as the implementation for `SpIBinder`.
 unsafe impl<T: Proxy> AsNative<sys::AIBinder> for T {
     fn as_native(&self) -> *const sys::AIBinder {
         self.as_binder().as_native()
@@ -773,24 +743,20 @@
 /// exist.
 pub fn get_service(name: &str) -> Option<SpIBinder> {
     let name = CString::new(name).ok()?;
-    unsafe {
-        // Safety: `AServiceManager_getService` returns either a null pointer or
-        // a valid pointer to an owned `AIBinder`. Either of these values is
-        // safe to pass to `SpIBinder::from_raw`.
-        SpIBinder::from_raw(sys::AServiceManager_getService(name.as_ptr()))
-    }
+    // Safety: `AServiceManager_getService` returns either a null pointer or a
+    // valid pointer to an owned `AIBinder`. Either of these values is safe to
+    // pass to `SpIBinder::from_raw`.
+    unsafe { SpIBinder::from_raw(sys::AServiceManager_getService(name.as_ptr())) }
 }
 
 /// Retrieve an existing service, or start it if it is configured as a dynamic
 /// service and isn't yet started.
 pub fn wait_for_service(name: &str) -> Option<SpIBinder> {
     let name = CString::new(name).ok()?;
-    unsafe {
-        // Safety: `AServiceManager_waitforService` returns either a null
-        // pointer or a valid pointer to an owned `AIBinder`. Either of these
-        // values is safe to pass to `SpIBinder::from_raw`.
-        SpIBinder::from_raw(sys::AServiceManager_waitForService(name.as_ptr()))
-    }
+    // Safety: `AServiceManager_waitforService` returns either a null pointer or
+    // a valid pointer to an owned `AIBinder`. Either of these values is safe to
+    // pass to `SpIBinder::from_raw`.
+    unsafe { SpIBinder::from_raw(sys::AServiceManager_waitForService(name.as_ptr())) }
 }
 
 /// Retrieve an existing service for a particular interface, blocking for a few
@@ -809,12 +775,10 @@
 pub fn is_declared(interface: &str) -> Result<bool> {
     let interface = CString::new(interface).or(Err(StatusCode::UNEXPECTED_NULL))?;
 
-    unsafe {
-        // Safety: `interface` is a valid null-terminated C-style string and is
-        // only borrowed for the lifetime of the call. The `interface` local
-        // outlives this call as it lives for the function scope.
-        Ok(sys::AServiceManager_isDeclared(interface.as_ptr()))
-    }
+    // Safety: `interface` is a valid null-terminated C-style string and is only
+    // borrowed for the lifetime of the call. The `interface` local outlives
+    // this call as it lives for the function scope.
+    unsafe { Ok(sys::AServiceManager_isDeclared(interface.as_ptr())) }
 }
 
 /// Retrieve all declared instances for a particular interface
@@ -827,11 +791,13 @@
         // CString, and outlives this callback. The null handling here is just
         // to avoid the possibility of unwinding across C code if this crate is
         // ever compiled with panic=unwind.
-        if let Some(instances) = opaque.cast::<Vec<CString>>().as_mut() {
+        if let Some(instances) = unsafe { opaque.cast::<Vec<CString>>().as_mut() } {
             // Safety: instance is a valid null-terminated C string with a
             // lifetime at least as long as this function, and we immediately
             // copy it into an owned CString.
-            instances.push(CStr::from_ptr(instance).to_owned());
+            unsafe {
+                instances.push(CStr::from_ptr(instance).to_owned());
+            }
         } else {
             eprintln!("Opaque pointer was null in get_declared_instances callback!");
         }
@@ -839,10 +805,10 @@
 
     let interface = CString::new(interface).or(Err(StatusCode::UNEXPECTED_NULL))?;
     let mut instances: Vec<CString> = vec![];
+    // Safety: `interface` and `instances` are borrowed for the length of this
+    // call and both outlive the call. `interface` is guaranteed to be a valid
+    // null-terminated C-style string.
     unsafe {
-        // Safety: `interface` and `instances` are borrowed for the length of
-        // this call and both outlive the call. `interface` is guaranteed to be
-        // a valid null-terminated C-style string.
         sys::AServiceManager_forEachDeclaredInstance(
             interface.as_ptr(),
             &mut instances as *mut _ as *mut c_void,
@@ -860,10 +826,8 @@
         })
 }
 
-/// # Safety
-///
-/// `SpIBinder` guarantees that `binder` always contains a valid pointer to an
-/// `AIBinder`, so we can trivially extract this pointer here.
+/// Safety: `SpIBinder` guarantees that `binder` always contains a valid pointer
+/// to an `AIBinder`, so we can trivially extract this pointer here.
 unsafe impl AsNative<sys::AIBinder> for SpIBinder {
     fn as_native(&self) -> *const sys::AIBinder {
         self.0.as_ptr()
diff --git a/libs/binder/rust/src/state.rs b/libs/binder/rust/src/state.rs
index b35511d..a3a2562 100644
--- a/libs/binder/rust/src/state.rs
+++ b/libs/binder/rust/src/state.rs
@@ -22,35 +22,48 @@
 pub struct ProcessState;
 
 impl ProcessState {
-    /// Start the Binder IPC thread pool
+    /// Starts the Binder IPC thread pool.
     ///
-    /// Starts 1 thread, plus allows the kernel to lazily start up to 'num_threads'
-    /// additional threads as specified by set_thread_pool_max_thread_count.
+    /// Starts 1 thread, plus allows the kernel to lazily start up to
+    /// `num_threads` additional threads as specified by
+    /// [`set_thread_pool_max_thread_count`](Self::set_thread_pool_max_thread_count).
+    ///
+    /// This should be done before creating any Binder client or server. If
+    /// neither this nor [`join_thread_pool`](Self::join_thread_pool) are
+    /// called, then some things (such as callbacks and
+    /// [`IBinder::link_to_death`](crate::IBinder::link_to_death)) will silently
+    /// not work: the callbacks will be queued but never called as there is no
+    /// thread to call them on.
     pub fn start_thread_pool() {
+        // Safety: Safe FFI
         unsafe {
-            // Safety: Safe FFI
             sys::ABinderProcess_startThreadPool();
         }
     }
 
-    /// Set the maximum number of threads that can be started in the threadpool.
+    /// Sets the maximum number of threads that can be started in the
+    /// threadpool.
     ///
-    /// By default, after startThreadPool is called, this is 15. If it is called
-    /// additional times, the thread pool size can only be increased.
+    /// By default, after [`start_thread_pool`](Self::start_thread_pool) is
+    /// called, this is 15. If it is called additional times, the thread pool
+    /// size can only be increased.
     pub fn set_thread_pool_max_thread_count(num_threads: u32) {
+        // Safety: Safe FFI
         unsafe {
-            // Safety: Safe FFI
             sys::ABinderProcess_setThreadPoolMaxThreadCount(num_threads);
         }
     }
 
-    /// Block on the Binder IPC thread pool
+    /// Blocks on the Binder IPC thread pool by adding the current thread to the
+    /// pool.
     ///
-    /// This adds additional threads in addition to what is created by
-    /// set_thread_pool_max_thread_count and start_thread_pool.
+    /// Note that this adds the current thread in addition to those that are
+    /// created by
+    /// [`set_thread_pool_max_thread_count`](Self::set_thread_pool_max_thread_count)
+    /// and [`start_thread_pool`](Self::start_thread_pool).
     pub fn join_thread_pool() {
+        // Safety: Safe FFI
         unsafe {
-            // Safety: Safe FFI
             sys::ABinderProcess_joinThreadPool();
         }
     }
@@ -73,10 +86,8 @@
     /// \return calling uid or the current process's UID if this thread isn't
     /// processing a transaction.
     pub fn get_calling_uid() -> uid_t {
-        unsafe {
-            // Safety: Safe FFI
-            sys::AIBinder_getCallingUid()
-        }
+        // Safety: Safe FFI
+        unsafe { sys::AIBinder_getCallingUid() }
     }
 
     /// This returns the calling PID assuming that this thread is called from a
@@ -98,10 +109,8 @@
     /// If the transaction being processed is a oneway transaction, then this
     /// method will return 0.
     pub fn get_calling_pid() -> pid_t {
-        unsafe {
-            // Safety: Safe FFI
-            sys::AIBinder_getCallingPid()
-        }
+        // Safety: Safe FFI
+        unsafe { sys::AIBinder_getCallingPid() }
     }
 
     /// Determine whether the current thread is currently executing an incoming transaction.
@@ -109,10 +118,8 @@
     /// \return true if the current thread is currently executing an incoming transaction, and false
     /// otherwise.
     pub fn is_handling_transaction() -> bool {
-        unsafe {
-            // Safety: Safe FFI
-            sys::AIBinder_isHandlingTransaction()
-        }
+        // Safety: Safe FFI
+        unsafe { sys::AIBinder_isHandlingTransaction() }
     }
 
     /// This function makes the client's security context available to the
diff --git a/libs/bufferstreams/README.md b/libs/bufferstreams/README.md
new file mode 100644
index 0000000..860adef
--- /dev/null
+++ b/libs/bufferstreams/README.md
@@ -0,0 +1,13 @@
+# libbufferstreams: Reactive Streams for Graphics Buffers
+
+This library is currently **experimental** and **under active development**.
+It is not production ready yet.
+
+For more information on reactive streams, please see <https://www.reactive-streams.org/>
+
+## Contributing
+
+This library is natively written in Rust and exposes a C API. If you make changes to the Rust API,
+you **must** update the C API in turn. To do so, with cbindgen installed, run:
+
+```$ ./update_include.sh```
diff --git a/libs/bufferstreams/include/bufferstreams.h b/libs/bufferstreams/include/bufferstreams.h
new file mode 100644
index 0000000..5308de2
--- /dev/null
+++ b/libs/bufferstreams/include/bufferstreams.h
@@ -0,0 +1,13 @@
+/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */
+
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+
+/**
+ * This function will print Hello World.
+ */
+bool hello(void);
diff --git a/libs/bufferstreams/rust/Android.bp b/libs/bufferstreams/rust/Android.bp
new file mode 100644
index 0000000..95a85b5
--- /dev/null
+++ b/libs/bufferstreams/rust/Android.bp
@@ -0,0 +1,23 @@
+// 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.
+
+rust_library {
+    name: "libbufferstreams",
+    crate_name: "bufferstreams",
+    srcs: ["src/lib.rs"],
+    edition: "2021",
+    vendor_available: true,
+    host_supported: true,
+    min_sdk_version: "30",
+}
diff --git a/libs/bufferstreams/rust/Cargo.lock b/libs/bufferstreams/rust/Cargo.lock
new file mode 100644
index 0000000..4482dba
--- /dev/null
+++ b/libs/bufferstreams/rust/Cargo.lock
@@ -0,0 +1,7 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "bufferstreams"
+version = "0.1.0"
diff --git a/libs/bufferstreams/rust/Cargo.toml b/libs/bufferstreams/rust/Cargo.toml
new file mode 100644
index 0000000..d30c55c
--- /dev/null
+++ b/libs/bufferstreams/rust/Cargo.toml
@@ -0,0 +1,6 @@
+[package]
+name = "bufferstreams"
+version = "0.1.0"
+edition = "2021"
+
+[dependencies]
diff --git a/libs/bufferstreams/rust/cbindgen.toml b/libs/bufferstreams/rust/cbindgen.toml
new file mode 100644
index 0000000..eda837f
--- /dev/null
+++ b/libs/bufferstreams/rust/cbindgen.toml
@@ -0,0 +1,149 @@
+# See https://github.com/eqrion/cbindgen/blob/master/docs.md#cbindgentoml
+# for detailed documentation of every option here.
+
+
+
+language = "C"
+
+
+
+############## Options for Wrapping the Contents of the Header #################
+
+# header = "/* Text to put at the beginning of the generated file. Probably a license. */"
+# trailer = "/* Text to put at the end of the generated file */"
+# include_guard = "my_bindings_h"
+# pragma_once = true
+autogen_warning = "/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */"
+include_version = false
+# namespace = "my_namespace"
+namespaces = []
+using_namespaces = []
+sys_includes = []
+includes = []
+no_includes = false
+after_includes = ""
+
+
+
+
+############################ Code Style Options ################################
+
+braces = "SameLine"
+line_length = 100
+tab_width = 2
+documentation = true
+documentation_style = "auto"
+documentation_length = "full"
+line_endings = "LF" # also "CR", "CRLF", "Native"
+
+
+
+
+############################# Codegen Options ##################################
+
+style = "both"
+sort_by = "Name" # default for `fn.sort_by` and `const.sort_by`
+usize_is_size_t = true
+
+
+
+[defines]
+# "target_os = freebsd" = "DEFINE_FREEBSD"
+# "feature = serde" = "DEFINE_SERDE"
+
+
+
+[export]
+include = []
+exclude = []
+# prefix = "CAPI_"
+item_types = []
+renaming_overrides_prefixing = false
+
+
+
+[export.rename]
+
+
+
+[export.body]
+
+
+[export.mangle]
+
+
+[fn]
+rename_args = "None"
+# must_use = "MUST_USE_FUNC"
+# no_return = "NO_RETURN"
+# prefix = "START_FUNC"
+# postfix = "END_FUNC"
+args = "auto"
+sort_by = "Name"
+
+
+
+
+[struct]
+rename_fields = "None"
+# must_use = "MUST_USE_STRUCT"
+derive_constructor = false
+derive_eq = false
+derive_neq = false
+derive_lt = false
+derive_lte = false
+derive_gt = false
+derive_gte = false
+
+
+
+
+[enum]
+rename_variants = "None"
+# must_use = "MUST_USE_ENUM"
+add_sentinel = false
+prefix_with_name = false
+derive_helper_methods = false
+derive_const_casts = false
+derive_mut_casts = false
+# cast_assert_name = "ASSERT"
+derive_tagged_enum_destructor = false
+derive_tagged_enum_copy_constructor = false
+enum_class = true
+private_default_tagged_enum_constructor = false
+
+
+
+
+[const]
+allow_static_const = true
+allow_constexpr = false
+sort_by = "Name"
+
+
+
+
+[macro_expansion]
+bitflags = false
+
+
+
+
+
+
+############## Options for How Your Rust library Should Be Parsed ##############
+
+[parse]
+parse_deps = false
+# include = []
+exclude = []
+clean = false
+extra_bindings = []
+
+
+
+[parse.expand]
+crates = []
+all_features = false
+default_features = true
+features = []
\ No newline at end of file
diff --git a/libs/bufferstreams/rust/src/lib.rs b/libs/bufferstreams/rust/src/lib.rs
new file mode 100644
index 0000000..51f1c73
--- /dev/null
+++ b/libs/bufferstreams/rust/src/lib.rs
@@ -0,0 +1,22 @@
+// 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.
+
+//! libbufferstreams: Reactive Streams for Graphics Buffers
+
+/// This function will print Hello World.
+#[no_mangle]
+pub extern "C" fn hello() -> bool {
+    println!("Hello world.");
+    true
+}
diff --git a/libs/bufferstreams/update_include.sh b/libs/bufferstreams/update_include.sh
new file mode 100755
index 0000000..e986e9f
--- /dev/null
+++ b/libs/bufferstreams/update_include.sh
@@ -0,0 +1,2 @@
+cd rust
+cbindgen --config cbindgen.toml --crate bufferstreams --output ../include/bufferstreams.h
diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp
index 80ac2a9..715822b 100644
--- a/libs/graphicsenv/GraphicsEnv.cpp
+++ b/libs/graphicsenv/GraphicsEnv.cpp
@@ -120,6 +120,16 @@
     return base::Join(soNames, ':');
 }
 
+static sp<IGpuService> getGpuService() {
+    static const sp<IBinder> binder = defaultServiceManager()->checkService(String16("gpu"));
+    if (!binder) {
+        ALOGE("Failed to get gpu service");
+        return nullptr;
+    }
+
+    return interface_cast<IGpuService>(binder);
+}
+
 /*static*/ GraphicsEnv& GraphicsEnv::getInstance() {
     static GraphicsEnv env;
     return env;
@@ -142,6 +152,10 @@
     return appDebuggable || platformDebuggable;
 }
 
+/**
+ * APIs for updatable graphics drivers
+ */
+
 void GraphicsEnv::setDriverPathAndSphalLibraries(const std::string& path,
                                                  const std::string& sphalLibraries) {
     if (!mDriverPath.empty() || !mSphalLibraries.empty()) {
@@ -156,6 +170,108 @@
     mSphalLibraries = sphalLibraries;
 }
 
+// Return true if all the required libraries from vndk and sphal namespace are
+// linked to the driver namespace correctly.
+bool GraphicsEnv::linkDriverNamespaceLocked(android_namespace_t* destNamespace,
+                                            android_namespace_t* vndkNamespace,
+                                            const std::string& sharedSphalLibraries) {
+    const std::string llndkLibraries = getSystemNativeLibraries(NativeLibrary::LLNDK);
+    if (llndkLibraries.empty()) {
+        return false;
+    }
+    if (!android_link_namespaces(destNamespace, nullptr, llndkLibraries.c_str())) {
+        ALOGE("Failed to link default namespace[%s]", dlerror());
+        return false;
+    }
+
+    const std::string vndkspLibraries = getSystemNativeLibraries(NativeLibrary::VNDKSP);
+    if (vndkspLibraries.empty()) {
+        return false;
+    }
+    if (!android_link_namespaces(destNamespace, vndkNamespace, vndkspLibraries.c_str())) {
+        ALOGE("Failed to link vndk namespace[%s]", dlerror());
+        return false;
+    }
+
+    if (sharedSphalLibraries.empty()) {
+        return true;
+    }
+
+    // Make additional libraries in sphal to be accessible
+    auto sphalNamespace = android_get_exported_namespace("sphal");
+    if (!sphalNamespace) {
+        ALOGE("Depend on these libraries[%s] in sphal, but failed to get sphal namespace",
+              sharedSphalLibraries.c_str());
+        return false;
+    }
+
+    if (!android_link_namespaces(destNamespace, sphalNamespace, sharedSphalLibraries.c_str())) {
+        ALOGE("Failed to link sphal namespace[%s]", dlerror());
+        return false;
+    }
+
+    return true;
+}
+
+android_namespace_t* GraphicsEnv::getDriverNamespace() {
+    std::lock_guard<std::mutex> lock(mNamespaceMutex);
+
+    if (mDriverNamespace) {
+        return mDriverNamespace;
+    }
+
+    if (mDriverPath.empty()) {
+        // For an application process, driver path is empty means this application is not opted in
+        // to use updatable driver. Application process doesn't have the ability to set up
+        // environment variables and hence before `getenv` call will return.
+        // For a process that is not an application process, if it's run from an environment,
+        // for example shell, where environment variables can be set, then it can opt into using
+        // udpatable driver by setting UPDATABLE_GFX_DRIVER to 1. By setting to 1 the developer
+        // driver will be used currently.
+        // TODO(b/159240322) Support the production updatable driver.
+        const char* id = getenv("UPDATABLE_GFX_DRIVER");
+        if (id == nullptr || std::strcmp(id, "1") != 0) {
+            return nullptr;
+        }
+        const sp<IGpuService> gpuService = getGpuService();
+        if (!gpuService) {
+            return nullptr;
+        }
+        mDriverPath = gpuService->getUpdatableDriverPath();
+        if (mDriverPath.empty()) {
+            return nullptr;
+        }
+        mDriverPath.append(UPDATABLE_DRIVER_ABI);
+        ALOGI("Driver path is setup via UPDATABLE_GFX_DRIVER: %s", mDriverPath.c_str());
+    }
+
+    auto vndkNamespace = android_get_exported_namespace("vndk");
+    if (!vndkNamespace) {
+        return nullptr;
+    }
+
+    mDriverNamespace = android_create_namespace("updatable gfx driver",
+                                                mDriverPath.c_str(), // ld_library_path
+                                                mDriverPath.c_str(), // default_library_path
+                                                ANDROID_NAMESPACE_TYPE_ISOLATED,
+                                                nullptr, // permitted_when_isolated_path
+                                                nullptr);
+
+    if (!linkDriverNamespaceLocked(mDriverNamespace, vndkNamespace, mSphalLibraries)) {
+        mDriverNamespace = nullptr;
+    }
+
+    return mDriverNamespace;
+}
+
+std::string GraphicsEnv::getDriverPath() const {
+    return mDriverPath;
+}
+
+/**
+ * APIs for GpuStats
+ */
+
 void GraphicsEnv::hintActivityLaunch() {
     ATRACE_CALL();
 
@@ -310,16 +426,6 @@
                         extensionHashes, numStats);
 }
 
-static sp<IGpuService> getGpuService() {
-    static const sp<IBinder> binder = defaultServiceManager()->checkService(String16("gpu"));
-    if (!binder) {
-        ALOGE("Failed to get gpu service");
-        return nullptr;
-    }
-
-    return interface_cast<IGpuService>(binder);
-}
-
 bool GraphicsEnv::readyToSendGpuStatsLocked() {
     // Only send stats for processes having at least one activity launched and that process doesn't
     // skip the GraphicsEnvironment setup.
@@ -392,6 +498,10 @@
     return true;
 }
 
+/**
+ * APIs for ANGLE
+ */
+
 bool GraphicsEnv::shouldUseAngle() {
     // Make sure we are init'ed
     if (mPackageName.empty()) {
@@ -402,11 +512,7 @@
     return mShouldUseAngle;
 }
 
-// Set ANGLE information.
-// If path is "system", it means system ANGLE must be used for the process.
-// If shouldUseNativeDriver is true, it means native GLES drivers must be used for the process.
-// If path is set to nonempty and shouldUseNativeDriver is true, ANGLE will be used regardless.
-void GraphicsEnv::setAngleInfo(const std::string& path, const bool shouldUseNativeDriver,
+void GraphicsEnv::setAngleInfo(const std::string& path, const bool shouldUseSystemAngle,
                                const std::string& packageName,
                                const std::vector<std::string> eglFeatures) {
     if (mShouldUseAngle) {
@@ -423,28 +529,8 @@
     mAnglePath = std::move(path);
     ALOGV("setting app package name to '%s'", packageName.c_str());
     mPackageName = std::move(packageName);
-    if (path == "system") {
-        mShouldUseSystemAngle = true;
-    }
-    if (!path.empty()) {
-        mShouldUseAngle = true;
-    }
-    mShouldUseNativeDriver = shouldUseNativeDriver;
-}
-
-void GraphicsEnv::setLayerPaths(NativeLoaderNamespace* appNamespace,
-                                const std::string& layerPaths) {
-    if (mLayerPaths.empty()) {
-        mLayerPaths = layerPaths;
-        mAppNamespace = appNamespace;
-    } else {
-        ALOGV("Vulkan layer search path already set, not clobbering with '%s' for namespace %p'",
-              layerPaths.c_str(), appNamespace);
-    }
-}
-
-NativeLoaderNamespace* GraphicsEnv::getAppNamespace() {
-    return mAppNamespace;
+    mShouldUseAngle = true;
+    mShouldUseSystemAngle = shouldUseSystemAngle;
 }
 
 std::string& GraphicsEnv::getPackageName() {
@@ -455,124 +541,6 @@
     return mAngleEglFeatures;
 }
 
-const std::string& GraphicsEnv::getLayerPaths() {
-    return mLayerPaths;
-}
-
-const std::string& GraphicsEnv::getDebugLayers() {
-    return mDebugLayers;
-}
-
-const std::string& GraphicsEnv::getDebugLayersGLES() {
-    return mDebugLayersGLES;
-}
-
-void GraphicsEnv::setDebugLayers(const std::string& layers) {
-    mDebugLayers = layers;
-}
-
-void GraphicsEnv::setDebugLayersGLES(const std::string& layers) {
-    mDebugLayersGLES = layers;
-}
-
-// Return true if all the required libraries from vndk and sphal namespace are
-// linked to the driver namespace correctly.
-bool GraphicsEnv::linkDriverNamespaceLocked(android_namespace_t* destNamespace,
-                                            android_namespace_t* vndkNamespace,
-                                            const std::string& sharedSphalLibraries) {
-    const std::string llndkLibraries = getSystemNativeLibraries(NativeLibrary::LLNDK);
-    if (llndkLibraries.empty()) {
-        return false;
-    }
-    if (!android_link_namespaces(destNamespace, nullptr, llndkLibraries.c_str())) {
-        ALOGE("Failed to link default namespace[%s]", dlerror());
-        return false;
-    }
-
-    const std::string vndkspLibraries = getSystemNativeLibraries(NativeLibrary::VNDKSP);
-    if (vndkspLibraries.empty()) {
-        return false;
-    }
-    if (!android_link_namespaces(destNamespace, vndkNamespace, vndkspLibraries.c_str())) {
-        ALOGE("Failed to link vndk namespace[%s]", dlerror());
-        return false;
-    }
-
-    if (sharedSphalLibraries.empty()) {
-        return true;
-    }
-
-    // Make additional libraries in sphal to be accessible
-    auto sphalNamespace = android_get_exported_namespace("sphal");
-    if (!sphalNamespace) {
-        ALOGE("Depend on these libraries[%s] in sphal, but failed to get sphal namespace",
-              sharedSphalLibraries.c_str());
-        return false;
-    }
-
-    if (!android_link_namespaces(destNamespace, sphalNamespace, sharedSphalLibraries.c_str())) {
-        ALOGE("Failed to link sphal namespace[%s]", dlerror());
-        return false;
-    }
-
-    return true;
-}
-
-android_namespace_t* GraphicsEnv::getDriverNamespace() {
-    std::lock_guard<std::mutex> lock(mNamespaceMutex);
-
-    if (mDriverNamespace) {
-        return mDriverNamespace;
-    }
-
-    if (mDriverPath.empty()) {
-        // For an application process, driver path is empty means this application is not opted in
-        // to use updatable driver. Application process doesn't have the ability to set up
-        // environment variables and hence before `getenv` call will return.
-        // For a process that is not an application process, if it's run from an environment,
-        // for example shell, where environment variables can be set, then it can opt into using
-        // udpatable driver by setting UPDATABLE_GFX_DRIVER to 1. By setting to 1 the developer
-        // driver will be used currently.
-        // TODO(b/159240322) Support the production updatable driver.
-        const char* id = getenv("UPDATABLE_GFX_DRIVER");
-        if (id == nullptr || std::strcmp(id, "1")) {
-            return nullptr;
-        }
-        const sp<IGpuService> gpuService = getGpuService();
-        if (!gpuService) {
-            return nullptr;
-        }
-        mDriverPath = gpuService->getUpdatableDriverPath();
-        if (mDriverPath.empty()) {
-            return nullptr;
-        }
-        mDriverPath.append(UPDATABLE_DRIVER_ABI);
-        ALOGI("Driver path is setup via UPDATABLE_GFX_DRIVER: %s", mDriverPath.c_str());
-    }
-
-    auto vndkNamespace = android_get_exported_namespace("vndk");
-    if (!vndkNamespace) {
-        return nullptr;
-    }
-
-    mDriverNamespace = android_create_namespace("updatable gfx driver",
-                                                mDriverPath.c_str(), // ld_library_path
-                                                mDriverPath.c_str(), // default_library_path
-                                                ANDROID_NAMESPACE_TYPE_ISOLATED,
-                                                nullptr, // permitted_when_isolated_path
-                                                nullptr);
-
-    if (!linkDriverNamespaceLocked(mDriverNamespace, vndkNamespace, mSphalLibraries)) {
-        mDriverNamespace = nullptr;
-    }
-
-    return mDriverNamespace;
-}
-
-std::string GraphicsEnv::getDriverPath() const {
-    return mDriverPath;
-}
-
 android_namespace_t* GraphicsEnv::getAngleNamespace() {
     std::lock_guard<std::mutex> lock(mNamespaceMutex);
 
@@ -639,8 +607,43 @@
     return mShouldUseSystemAngle;
 }
 
-bool GraphicsEnv::shouldUseNativeDriver() {
-    return mShouldUseNativeDriver;
+/**
+ * APIs for debuggable layers
+ */
+
+void GraphicsEnv::setLayerPaths(NativeLoaderNamespace* appNamespace,
+                                const std::string& layerPaths) {
+    if (mLayerPaths.empty()) {
+        mLayerPaths = layerPaths;
+        mAppNamespace = appNamespace;
+    } else {
+        ALOGV("Vulkan layer search path already set, not clobbering with '%s' for namespace %p'",
+              layerPaths.c_str(), appNamespace);
+    }
+}
+
+NativeLoaderNamespace* GraphicsEnv::getAppNamespace() {
+    return mAppNamespace;
+}
+
+const std::string& GraphicsEnv::getLayerPaths() {
+    return mLayerPaths;
+}
+
+const std::string& GraphicsEnv::getDebugLayers() {
+    return mDebugLayers;
+}
+
+const std::string& GraphicsEnv::getDebugLayersGLES() {
+    return mDebugLayersGLES;
+}
+
+void GraphicsEnv::setDebugLayers(const std::string& layers) {
+    mDebugLayers = layers;
+}
+
+void GraphicsEnv::setDebugLayersGLES(const std::string& layers) {
+    mDebugLayersGLES = layers;
 }
 
 } // namespace android
diff --git a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
index 6cce3f6..fbf2902 100644
--- a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
+++ b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
@@ -108,10 +108,7 @@
     // (libraries must be stored uncompressed and page aligned); such elements
     // in the search path must have a '!' after the zip filename, e.g.
     //     /system/app/ANGLEPrebuilt/ANGLEPrebuilt.apk!/lib/arm64-v8a
-    // If the search patch is "system", then it means the system ANGLE should be used.
-    // If shouldUseNativeDriver is true, it means native GLES drivers must be used for the process.
-    // If path is set to nonempty and shouldUseNativeDriver is true, ANGLE will be used regardless.
-    void setAngleInfo(const std::string& path, const bool shouldUseNativeDriver,
+    void setAngleInfo(const std::string& path, const bool useSystemAngle,
                       const std::string& packageName, const std::vector<std::string> eglFeatures);
     // Get the ANGLE driver namespace.
     android_namespace_t* getAngleNamespace();
@@ -121,7 +118,6 @@
     // Set the persist.graphics.egl system property value.
     void nativeToggleAngleAsSystemDriver(bool enabled);
     bool shouldUseSystemAngle();
-    bool shouldUseNativeDriver();
 
     /*
      * Apis for debug layer
@@ -179,8 +175,6 @@
     bool mShouldUseAngle = false;
     // Whether loader should load system ANGLE.
     bool mShouldUseSystemAngle = false;
-    // Whether loader should load native GLES driver.
-    bool mShouldUseNativeDriver = false;
     // ANGLE namespace.
     android_namespace_t* mAngleNamespace = nullptr;
 
diff --git a/libs/gui/fuzzer/Android.bp b/libs/gui/fuzzer/Android.bp
index 75bae76..073cc08 100644
--- a/libs/gui/fuzzer/Android.bp
+++ b/libs/gui/fuzzer/Android.bp
@@ -90,6 +90,7 @@
     ],
     defaults: [
         "libgui_fuzzer_defaults",
+        "service_fuzzer_defaults",
     ],
 }
 
@@ -100,6 +101,7 @@
     ],
     defaults: [
         "libgui_fuzzer_defaults",
+        "service_fuzzer_defaults",
     ],
 }
 
diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp
index 00925ba..c127411 100644
--- a/libs/input/Input.cpp
+++ b/libs/input/Input.cpp
@@ -497,19 +497,6 @@
     }
 }
 
-// --- PointerProperties ---
-
-bool PointerProperties::operator==(const PointerProperties& other) const {
-    return id == other.id
-            && toolType == other.toolType;
-}
-
-void PointerProperties::copyFrom(const PointerProperties& other) {
-    id = other.id;
-    toolType = other.toolType;
-}
-
-
 // --- MotionEvent ---
 
 void MotionEvent::initialize(int32_t id, int32_t deviceId, uint32_t source, int32_t displayId,
diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp
index 0b0309e..d9b7700 100644
--- a/libs/input/InputTransport.cpp
+++ b/libs/input/InputTransport.cpp
@@ -692,8 +692,8 @@
     msg.body.motion.eventTime = eventTime;
     msg.body.motion.pointerCount = pointerCount;
     for (uint32_t i = 0; i < pointerCount; i++) {
-        msg.body.motion.pointers[i].properties.copyFrom(pointerProperties[i]);
-        msg.body.motion.pointers[i].coords.copyFrom(pointerCoords[i]);
+        msg.body.motion.pointers[i].properties = pointerProperties[i];
+        msg.body.motion.pointers[i].coords = pointerCoords[i];
     }
 
     return mChannel->sendMessage(&msg);
@@ -1270,13 +1270,13 @@
             // We know here that the coordinates for the pointer haven't changed because we
             // would've cleared the resampled bit in rewriteMessage if they had. We can't modify
             // lastResample in place becasue the mapping from pointer ID to index may have changed.
-            touchState.lastResample.pointers[i].copyFrom(oldLastResample.getPointerById(id));
+            touchState.lastResample.pointers[i] = oldLastResample.getPointerById(id);
             continue;
         }
 
         PointerCoords& resampledCoords = touchState.lastResample.pointers[i];
         const PointerCoords& currentCoords = current->getPointerById(id);
-        resampledCoords.copyFrom(currentCoords);
+        resampledCoords = currentCoords;
         if (other->idBits.hasBit(id) && shouldResampleTool(event->getToolType(i))) {
             const PointerCoords& otherCoords = other->getPointerById(id);
             resampledCoords.setAxisValue(AMOTION_EVENT_AXIS_X,
@@ -1454,8 +1454,8 @@
     PointerProperties pointerProperties[pointerCount];
     PointerCoords pointerCoords[pointerCount];
     for (uint32_t i = 0; i < pointerCount; i++) {
-        pointerProperties[i].copyFrom(msg->body.motion.pointers[i].properties);
-        pointerCoords[i].copyFrom(msg->body.motion.pointers[i].coords);
+        pointerProperties[i] = msg->body.motion.pointers[i].properties;
+        pointerCoords[i] = msg->body.motion.pointers[i].coords;
     }
 
     ui::Transform transform;
@@ -1484,7 +1484,7 @@
     uint32_t pointerCount = msg->body.motion.pointerCount;
     PointerCoords pointerCoords[pointerCount];
     for (uint32_t i = 0; i < pointerCount; i++) {
-        pointerCoords[i].copyFrom(msg->body.motion.pointers[i].coords);
+        pointerCoords[i] = msg->body.motion.pointers[i].coords;
     }
 
     event->setMetaState(event->getMetaState() | msg->body.motion.metaState);
diff --git a/libs/input/OWNERS b/libs/input/OWNERS
new file mode 100644
index 0000000..c88bfe9
--- /dev/null
+++ b/libs/input/OWNERS
@@ -0,0 +1 @@
+include platform/frameworks/base:/INPUT_OWNERS
diff --git a/libs/input/rust/input_verifier.rs b/libs/input/rust/input_verifier.rs
index fdb6230..64c0466 100644
--- a/libs/input/rust/input_verifier.rs
+++ b/libs/input/rust/input_verifier.rs
@@ -144,7 +144,7 @@
                 self.touching_pointer_ids_by_device.remove(&device_id);
             }
             MotionAction::Cancel => {
-                if flags.contains(MotionFlags::CANCELED) {
+                if !flags.contains(MotionFlags::CANCELED) {
                     return Err(format!(
                         "{}: For ACTION_CANCEL, must set FLAG_CANCELED",
                         self.name
@@ -323,7 +323,51 @@
     }
 
     #[test]
-    fn test_invalid_up() {
+    fn action_cancel() {
+        let mut verifier = InputVerifier::new("Test", /*should_log*/ false);
+        let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
+        assert!(verifier
+            .process_movement(
+                DeviceId(1),
+                input_bindgen::AMOTION_EVENT_ACTION_DOWN,
+                &pointer_properties,
+                MotionFlags::empty(),
+            )
+            .is_ok());
+        assert!(verifier
+            .process_movement(
+                DeviceId(1),
+                input_bindgen::AMOTION_EVENT_ACTION_CANCEL,
+                &pointer_properties,
+                MotionFlags::CANCELED,
+            )
+            .is_ok());
+    }
+
+    #[test]
+    fn invalid_action_cancel() {
+        let mut verifier = InputVerifier::new("Test", /*should_log*/ false);
+        let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
+        assert!(verifier
+            .process_movement(
+                DeviceId(1),
+                input_bindgen::AMOTION_EVENT_ACTION_DOWN,
+                &pointer_properties,
+                MotionFlags::empty(),
+            )
+            .is_ok());
+        assert!(verifier
+            .process_movement(
+                DeviceId(1),
+                input_bindgen::AMOTION_EVENT_ACTION_CANCEL,
+                &pointer_properties,
+                MotionFlags::empty(), // forgot to set FLAG_CANCELED
+            )
+            .is_err());
+    }
+
+    #[test]
+    fn invalid_up() {
         let mut verifier = InputVerifier::new("Test", /*should_log*/ false);
         let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
         assert!(verifier
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index 654e5b7..8d0eb59 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -169,11 +169,6 @@
         }
     }
 
-    // Return true if native GLES drivers should be used and ANGLE is already loaded.
-    if (android::GraphicsEnv::getInstance().shouldUseNativeDriver() && cnx->angleLoaded) {
-        return true;
-    }
-
     // Return true if updated driver namespace is set.
     ns = android::GraphicsEnv::getInstance().getDriverNamespace();
     if (ns) {
@@ -245,28 +240,16 @@
     if (!hnd) {
         // Secondly, try to load from driver apk.
         hnd = attempt_to_load_updated_driver(cnx);
-
-        // If updated driver apk is set but fail to load, abort here.
-        LOG_ALWAYS_FATAL_IF(android::GraphicsEnv::getInstance().getDriverNamespace(),
-                            "couldn't find an OpenGL ES implementation from %s",
-                            android::GraphicsEnv::getInstance().getDriverPath().c_str());
     }
 
-    // Attempt to load native GLES drivers specified by ro.hardware.egl if native is selected.
-    // If native is selected but fail to load, abort.
-    if (!hnd && android::GraphicsEnv::getInstance().shouldUseNativeDriver()) {
-        auto driverSuffix = base::GetProperty(RO_DRIVER_SUFFIX_PROPERTY, "");
-        LOG_ALWAYS_FATAL_IF(driverSuffix.empty(),
-                            "Native GLES driver is selected but not specified in %s",
-                            RO_DRIVER_SUFFIX_PROPERTY);
-        hnd = attempt_to_load_system_driver(cnx, driverSuffix.c_str(), true);
-        LOG_ALWAYS_FATAL_IF(!hnd, "Native GLES driver is selected but failed to load. %s=%s",
-                            RO_DRIVER_SUFFIX_PROPERTY, driverSuffix.c_str());
-    }
-
-    // Finally, try to load default driver.
     bool failToLoadFromDriverSuffixProperty = false;
     if (!hnd) {
+        // If updated driver apk is set but fail to load, abort here.
+        if (android::GraphicsEnv::getInstance().getDriverNamespace()) {
+            LOG_ALWAYS_FATAL("couldn't find an OpenGL ES implementation from %s",
+                             android::GraphicsEnv::getInstance().getDriverPath().c_str());
+        }
+        // Finally, try to load system driver.
         // Start by searching for the library name appended by the system
         // properties of the GLES userspace driver in both locations.
         // i.e.:
diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp
index ee03d94..f749b0e 100644
--- a/services/inputflinger/Android.bp
+++ b/services/inputflinger/Android.bp
@@ -243,6 +243,7 @@
         "inputflinger_keyboard_input_fuzzer",
         "inputflinger_multitouch_input_fuzzer",
         "inputflinger_switch_input_fuzzer",
+        "inputflinger_touchpad_input_fuzzer",
         "inputflinger_input_reader_fuzzer",
         "inputflinger_blocking_queue_fuzzer",
         "inputflinger_input_classifier_fuzzer",
diff --git a/services/inputflinger/InputDeviceMetricsCollector.cpp b/services/inputflinger/InputDeviceMetricsCollector.cpp
index 89e37db..7c99a1c 100644
--- a/services/inputflinger/InputDeviceMetricsCollector.cpp
+++ b/services/inputflinger/InputDeviceMetricsCollector.cpp
@@ -31,7 +31,7 @@
 
 namespace {
 
-constexpr nanoseconds DEFAULT_USAGE_SESSION_TIMEOUT = std::chrono::seconds(5);
+constexpr nanoseconds DEFAULT_USAGE_SESSION_TIMEOUT = std::chrono::minutes(2);
 
 /**
  * Log debug messages about metrics events logged to statsd.
@@ -39,6 +39,8 @@
  */
 const bool DEBUG = __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO);
 
+constexpr size_t INTERACTIONS_QUEUE_CAPACITY = 500;
+
 int32_t linuxBusToInputDeviceBusEnum(int32_t linuxBus) {
     // When adding cases to this switch, also add them to the copy of this method in
     // TouchpadInputMapper.cpp.
@@ -201,7 +203,10 @@
 InputDeviceMetricsCollector::InputDeviceMetricsCollector(InputListenerInterface& listener,
                                                          InputDeviceMetricsLogger& logger,
                                                          nanoseconds usageSessionTimeout)
-      : mNextListener(listener), mLogger(logger), mUsageSessionTimeout(usageSessionTimeout) {}
+      : mNextListener(listener),
+        mLogger(logger),
+        mUsageSessionTimeout(usageSessionTimeout),
+        mInteractionsQueue(INTERACTIONS_QUEUE_CAPACITY) {}
 
 void InputDeviceMetricsCollector::notifyInputDevicesChanged(
         const NotifyInputDevicesChangedArgs& args) {
@@ -262,6 +267,9 @@
 
 void InputDeviceMetricsCollector::notifyDeviceInteraction(int32_t deviceId, nsecs_t timestamp,
                                                           const std::set<Uid>& uids) {
+    if (isIgnoredInputDeviceId(deviceId)) {
+        return;
+    }
     mInteractionsQueue.push(DeviceId{deviceId}, timestamp, uids);
 }
 
diff --git a/services/inputflinger/InputManager.cpp b/services/inputflinger/InputManager.cpp
index 09c88ba..c903564 100644
--- a/services/inputflinger/InputManager.cpp
+++ b/services/inputflinger/InputManager.cpp
@@ -34,7 +34,7 @@
 namespace android {
 
 static const bool ENABLE_INPUT_DEVICE_USAGE_METRICS =
-        sysprop::InputProperties::enable_input_device_usage_metrics().value_or(false);
+        sysprop::InputProperties::enable_input_device_usage_metrics().value_or(true);
 
 using gui::FocusRequest;
 
diff --git a/services/inputflinger/NotifyArgs.cpp b/services/inputflinger/NotifyArgs.cpp
index 0fa47d1..c34cd53 100644
--- a/services/inputflinger/NotifyArgs.cpp
+++ b/services/inputflinger/NotifyArgs.cpp
@@ -91,8 +91,8 @@
         readTime(readTime),
         videoFrames(videoFrames) {
     for (uint32_t i = 0; i < pointerCount; i++) {
-        this->pointerProperties.push_back(pointerProperties[i]);
-        this->pointerCoords.push_back(pointerCoords[i]);
+        this->pointerProperties.emplace_back(pointerProperties[i]);
+        this->pointerCoords.emplace_back(pointerCoords[i]);
     }
 }
 
diff --git a/services/inputflinger/OWNERS b/services/inputflinger/OWNERS
index c88bfe9..21d208f 100644
--- a/services/inputflinger/OWNERS
+++ b/services/inputflinger/OWNERS
@@ -1 +1,2 @@
+# Bug component: 136048
 include platform/frameworks/base:/INPUT_OWNERS
diff --git a/services/inputflinger/SyncQueue.h b/services/inputflinger/SyncQueue.h
index 62efd55..84ccace 100644
--- a/services/inputflinger/SyncQueue.h
+++ b/services/inputflinger/SyncQueue.h
@@ -27,6 +27,10 @@
 template <class T>
 class SyncQueue {
 public:
+    SyncQueue() = default;
+
+    SyncQueue(size_t capacity) : mCapacity(capacity) {}
+
     /** Retrieve and remove the oldest object. Returns std::nullopt if the queue is empty. */
     std::optional<T> pop() {
         std::scoped_lock lock(mLock);
@@ -38,14 +42,23 @@
         return t;
     };
 
-    /** Add a new object to the queue. */
+    /**
+     * Add a new object to the queue.
+     * Return true if an element was successfully added.
+     * Return false if the queue is full.
+     */
     template <class... Args>
-    void push(Args&&... args) {
+    bool push(Args&&... args) {
         std::scoped_lock lock(mLock);
+        if (mCapacity && mQueue.size() == mCapacity) {
+            return false;
+        }
         mQueue.emplace_back(args...);
+        return true;
     };
 
 private:
+    const std::optional<size_t> mCapacity;
     std::mutex mLock;
     std::list<T> mQueue GUARDED_BY(mLock);
 };
diff --git a/services/inputflinger/dispatcher/Entry.cpp b/services/inputflinger/dispatcher/Entry.cpp
index a670ebe..cb369a8 100644
--- a/services/inputflinger/dispatcher/Entry.cpp
+++ b/services/inputflinger/dispatcher/Entry.cpp
@@ -235,8 +235,8 @@
         downTime(downTime),
         pointerCount(pointerCount) {
     for (uint32_t i = 0; i < pointerCount; i++) {
-        this->pointerProperties[i].copyFrom(pointerProperties[i]);
-        this->pointerCoords[i].copyFrom(pointerCoords[i]);
+        this->pointerProperties[i] = pointerProperties[i];
+        this->pointerCoords[i] = pointerCoords[i];
     }
 }
 
@@ -321,7 +321,28 @@
         globalScaleFactor(globalScaleFactor),
         deliveryTime(0),
         resolvedAction(0),
-        resolvedFlags(0) {}
+        resolvedFlags(0) {
+    switch (this->eventEntry->type) {
+        case EventEntry::Type::KEY: {
+            const KeyEntry& keyEntry = static_cast<KeyEntry&>(*this->eventEntry);
+            resolvedEventId = keyEntry.id;
+            resolvedAction = keyEntry.action;
+            resolvedFlags = keyEntry.flags;
+
+            break;
+        }
+        case EventEntry::Type::MOTION: {
+            const MotionEntry& motionEntry = static_cast<MotionEntry&>(*this->eventEntry);
+            resolvedEventId = motionEntry.id;
+            resolvedAction = motionEntry.action;
+            resolvedFlags = motionEntry.flags;
+            break;
+        }
+        default: {
+            break;
+        }
+    }
+}
 
 uint32_t DispatchEntry::nextSeq() {
     // Sequence number 0 is reserved and will never be returned.
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 482e23f..7611d68 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -2257,7 +2257,6 @@
         const bool anotherDeviceIsActive =
                 oldActiveDevices.count(entry.deviceId) == 0 && !oldActiveDevices.empty();
         switchedDevice |= anotherDeviceIsActive;
-        switchedDevice |= oldState->source != entry.source;
     }
 
     const bool isHoverAction = (maskedAction == AMOTION_EVENT_ACTION_HOVER_MOVE ||
@@ -2287,7 +2286,6 @@
     if (newGesture) {
         // If a new gesture is starting, clear the touch state completely.
         tempTouchState.reset();
-        tempTouchState.source = entry.source;
         isSplit = false;
     } else if (switchedDevice && maskedAction == AMOTION_EVENT_ACTION_MOVE) {
         ALOGI("Dropping move event because a pointer for a different device is already active "
@@ -2692,10 +2690,6 @@
                      "Conflicting pointer actions: Hover received while pointer was down.");
             *outConflictingPointerActions = true;
         }
-        if (maskedAction == AMOTION_EVENT_ACTION_HOVER_ENTER ||
-            maskedAction == AMOTION_EVENT_ACTION_HOVER_MOVE) {
-            tempTouchState.source = entry.source;
-        }
     } else if (maskedAction == AMOTION_EVENT_ACTION_UP) {
         // Pointer went up.
         tempTouchState.removeTouchingPointer(entry.deviceId, entry.pointerProperties[0].id);
@@ -2983,7 +2977,7 @@
             !haveSameApplicationToken(windowInfo, otherInfo)) {
             if (DEBUG_TOUCH_OCCLUSION) {
                 info.debugInfo.push_back(
-                        dumpWindowForTouchOcclusion(otherInfo, /* isTouchedWindow */ false));
+                        dumpWindowForTouchOcclusion(otherInfo, /*isTouchedWindow=*/false));
             }
             // canBeObscuredBy() has returned true above, which means this window is untrusted, so
             // we perform the checks below to see if the touch can be propagated or not based on the
@@ -3011,8 +3005,7 @@
         }
     }
     if (DEBUG_TOUCH_OCCLUSION) {
-        info.debugInfo.push_back(
-                dumpWindowForTouchOcclusion(windowInfo, /* isTouchedWindow */ true));
+        info.debugInfo.push_back(dumpWindowForTouchOcclusion(windowInfo, /*isTouchedWindow=*/true));
     }
     return info;
 }
@@ -3306,10 +3299,6 @@
     switch (newEntry.type) {
         case EventEntry::Type::KEY: {
             const KeyEntry& keyEntry = static_cast<const KeyEntry&>(newEntry);
-            dispatchEntry->resolvedEventId = keyEntry.id;
-            dispatchEntry->resolvedAction = keyEntry.action;
-            dispatchEntry->resolvedFlags = keyEntry.flags;
-
             if (!connection->inputState.trackKey(keyEntry, dispatchEntry->resolvedAction,
                                                  dispatchEntry->resolvedFlags)) {
                 LOG(WARNING) << "channel " << connection->getInputChannelName()
@@ -3337,7 +3326,6 @@
             } else if (dispatchMode.test(InputTarget::Flags::DISPATCH_AS_SLIPPERY_ENTER)) {
                 dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_DOWN;
             } else {
-                dispatchEntry->resolvedAction = motionEntry.action;
                 dispatchEntry->resolvedEventId = motionEntry.id;
             }
             if (dispatchEntry->resolvedAction == AMOTION_EVENT_ACTION_HOVER_MOVE &&
@@ -3353,7 +3341,6 @@
                 dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_HOVER_ENTER;
             }
 
-            dispatchEntry->resolvedFlags = motionEntry.flags;
             if (dispatchEntry->resolvedAction == AMOTION_EVENT_ACTION_CANCEL) {
                 dispatchEntry->resolvedFlags |= AMOTION_EVENT_FLAG_CANCELED;
             }
@@ -4097,9 +4084,9 @@
         uint32_t pointerId = uint32_t(pointerProperties.id);
         if (pointerIds.test(pointerId)) {
             splitPointerIndexMap[splitPointerCount] = originalPointerIndex;
-            splitPointerProperties[splitPointerCount].copyFrom(pointerProperties);
-            splitPointerCoords[splitPointerCount].copyFrom(
-                    originalMotionEntry.pointerCoords[originalPointerIndex]);
+            splitPointerProperties[splitPointerCount] = pointerProperties;
+            splitPointerCoords[splitPointerCount] =
+                    originalMotionEntry.pointerCoords[originalPointerIndex];
             splitPointerCount += 1;
         }
     }
@@ -6573,7 +6560,7 @@
     }
 }
 
-void InputDispatcher::dump(std::string& dump) {
+void InputDispatcher::dump(std::string& dump) const {
     std::scoped_lock _l(mLock);
 
     dump += "Input Dispatcher State:\n";
@@ -6708,7 +6695,7 @@
     { // acquire lock
         std::scoped_lock _l(mLock);
         // Set an empty list to remove all handles from the specific display.
-        setInputWindowsLocked(/* window handles */ {}, displayId);
+        setInputWindowsLocked(/*windowInfoHandles=*/{}, displayId);
         setFocusedApplicationLocked(displayId, nullptr);
         // Call focus resolver to clean up stale requests. This must be called after input windows
         // have been removed for the removed display.
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index 9cd1666..cb87067 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -87,7 +87,7 @@
                              std::chrono::nanoseconds staleEventTimeout);
     ~InputDispatcher() override;
 
-    void dump(std::string& dump) override;
+    void dump(std::string& dump) const override;
     void monitor() override;
     bool waitForIdle() const override;
     status_t start() override;
diff --git a/services/inputflinger/dispatcher/InputState.cpp b/services/inputflinger/dispatcher/InputState.cpp
index 2fcb89a..e6941ef 100644
--- a/services/inputflinger/dispatcher/InputState.cpp
+++ b/services/inputflinger/dispatcher/InputState.cpp
@@ -28,7 +28,7 @@
 
 InputState::~InputState() {}
 
-bool InputState::isHovering(int32_t deviceId, uint32_t source, int32_t displayId) const {
+bool InputState::isHovering(DeviceId deviceId, uint32_t source, int32_t displayId) const {
     for (const MotionMemento& memento : mMotionMementos) {
         if (memento.deviceId == deviceId && memento.source == source &&
             memento.displayId == displayId && memento.hovering) {
@@ -240,8 +240,8 @@
                 continue;
             }
         }
-        pointerProperties[pointerCount].copyFrom(entry.pointerProperties[i]);
-        pointerCoords[pointerCount].copyFrom(entry.pointerCoords[i]);
+        pointerProperties[pointerCount] = entry.pointerProperties[i];
+        pointerCoords[pointerCount] = entry.pointerCoords[i];
         pointerCount++;
     }
 }
@@ -251,8 +251,8 @@
         if (other.firstNewPointerIdx < 0) {
             other.firstNewPointerIdx = other.pointerCount;
         }
-        other.pointerProperties[other.pointerCount].copyFrom(pointerProperties[i]);
-        other.pointerCoords[other.pointerCount].copyFrom(pointerCoords[i]);
+        other.pointerProperties[other.pointerCount] = pointerProperties[i];
+        other.pointerCoords[other.pointerCount] = pointerCoords[i];
         other.pointerCount++;
     }
 }
@@ -324,17 +324,16 @@
 
         // We will deliver all pointers the target already knows about
         for (uint32_t i = 0; i < static_cast<uint32_t>(memento.firstNewPointerIdx); i++) {
-            pointerProperties[i].copyFrom(memento.pointerProperties[i]);
-            pointerCoords[i].copyFrom(memento.pointerCoords[i]);
+            pointerProperties[i] = memento.pointerProperties[i];
+            pointerCoords[i] = memento.pointerCoords[i];
             pointerCount++;
         }
 
         // We will send explicit events for all pointers the target doesn't know about
         for (uint32_t i = static_cast<uint32_t>(memento.firstNewPointerIdx);
                 i < memento.pointerCount; i++) {
-
-            pointerProperties[i].copyFrom(memento.pointerProperties[i]);
-            pointerCoords[i].copyFrom(memento.pointerCoords[i]);
+            pointerProperties[i] = memento.pointerProperties[i];
+            pointerCoords[i] = memento.pointerCoords[i];
             pointerCount++;
 
             // Down only if the first pointer, pointer down otherwise
@@ -370,8 +369,8 @@
     std::vector<PointerCoords> pointerCoords(MAX_POINTERS);
     for (uint32_t pointerIdx = 0; pointerIdx < memento.pointerCount; pointerIdx++) {
         uint32_t pointerId = uint32_t(memento.pointerProperties[pointerIdx].id);
-        pointerProperties[pointerIdx].copyFrom(memento.pointerProperties[pointerIdx]);
-        pointerCoords[pointerIdx].copyFrom(memento.pointerCoords[pointerIdx]);
+        pointerProperties[pointerIdx] = memento.pointerProperties[pointerIdx];
+        pointerCoords[pointerIdx] = memento.pointerCoords[pointerIdx];
         if (pointerIds.test(pointerId)) {
             canceledPointerIndices.push_back(pointerIdx);
         }
diff --git a/services/inputflinger/dispatcher/InputState.h b/services/inputflinger/dispatcher/InputState.h
index af2a3cb..e741137 100644
--- a/services/inputflinger/dispatcher/InputState.h
+++ b/services/inputflinger/dispatcher/InputState.h
@@ -36,7 +36,7 @@
 
     // Returns true if the specified source is known to have received a hover enter
     // motion event.
-    bool isHovering(int32_t deviceId, uint32_t source, int32_t displayId) const;
+    bool isHovering(DeviceId deviceId, uint32_t source, int32_t displayId) const;
 
     // Records tracking information for a key event that has just been published.
     // Returns true if the event should be delivered, false if it is inconsistent
@@ -76,7 +76,7 @@
 
 private:
     struct KeyMemento {
-        int32_t deviceId;
+        DeviceId deviceId;
         uint32_t source;
         int32_t displayId;
         int32_t keyCode;
@@ -88,7 +88,7 @@
     };
 
     struct MotionMemento {
-        int32_t deviceId;
+        DeviceId deviceId;
         uint32_t source;
         int32_t displayId;
         int32_t flags;
diff --git a/services/inputflinger/dispatcher/TouchState.cpp b/services/inputflinger/dispatcher/TouchState.cpp
index dcbb366..4221e42 100644
--- a/services/inputflinger/dispatcher/TouchState.cpp
+++ b/services/inputflinger/dispatcher/TouchState.cpp
@@ -40,25 +40,25 @@
     return out;
 }
 
-bool TouchState::hasTouchingPointers(int32_t deviceId) const {
+bool TouchState::hasTouchingPointers(DeviceId deviceId) const {
     return std::any_of(windows.begin(), windows.end(), [&](const TouchedWindow& window) {
         return window.hasTouchingPointers(deviceId);
     });
 }
 
-void TouchState::removeTouchingPointer(int32_t removedDeviceId, int32_t pointerId) {
+void TouchState::removeTouchingPointer(DeviceId deviceId, int32_t pointerId) {
     for (TouchedWindow& touchedWindow : windows) {
-        touchedWindow.removeTouchingPointer(removedDeviceId, pointerId);
+        touchedWindow.removeTouchingPointer(deviceId, pointerId);
     }
     clearWindowsWithoutPointers();
 }
 
 void TouchState::removeTouchingPointerFromWindow(
-        int32_t removedDeviceId, int32_t pointerId,
+        DeviceId deviceId, int32_t pointerId,
         const sp<android::gui::WindowInfoHandle>& windowHandle) {
     for (TouchedWindow& touchedWindow : windows) {
         if (touchedWindow.windowHandle == windowHandle) {
-            touchedWindow.removeTouchingPointer(removedDeviceId, pointerId);
+            touchedWindow.removeTouchingPointer(deviceId, pointerId);
             clearWindowsWithoutPointers();
             return;
         }
@@ -79,8 +79,7 @@
 }
 
 void TouchState::addOrUpdateWindow(const sp<WindowInfoHandle>& windowHandle,
-                                   ftl::Flags<InputTarget::Flags> targetFlags,
-                                   int32_t addedDeviceId,
+                                   ftl::Flags<InputTarget::Flags> targetFlags, DeviceId deviceId,
                                    std::bitset<MAX_POINTER_ID + 1> touchingPointerIds,
                                    std::optional<nsecs_t> firstDownTimeInTarget) {
     for (TouchedWindow& touchedWindow : windows) {
@@ -94,9 +93,9 @@
             // For cases like hover enter/exit or DISPATCH_AS_OUTSIDE a touch window might not have
             // downTime set initially. Need to update existing window when a pointer is down for the
             // window.
-            touchedWindow.addTouchingPointers(addedDeviceId, touchingPointerIds);
+            touchedWindow.addTouchingPointers(deviceId, touchingPointerIds);
             if (firstDownTimeInTarget) {
-                touchedWindow.trySetDownTimeInTarget(addedDeviceId, *firstDownTimeInTarget);
+                touchedWindow.trySetDownTimeInTarget(deviceId, *firstDownTimeInTarget);
             }
             return;
         }
@@ -104,25 +103,25 @@
     TouchedWindow touchedWindow;
     touchedWindow.windowHandle = windowHandle;
     touchedWindow.targetFlags = targetFlags;
-    touchedWindow.addTouchingPointers(addedDeviceId, touchingPointerIds);
+    touchedWindow.addTouchingPointers(deviceId, touchingPointerIds);
     if (firstDownTimeInTarget) {
-        touchedWindow.trySetDownTimeInTarget(addedDeviceId, *firstDownTimeInTarget);
+        touchedWindow.trySetDownTimeInTarget(deviceId, *firstDownTimeInTarget);
     }
     windows.push_back(touchedWindow);
 }
 
 void TouchState::addHoveringPointerToWindow(const sp<WindowInfoHandle>& windowHandle,
-                                            int32_t hoveringDeviceId, int32_t hoveringPointerId) {
+                                            DeviceId deviceId, int32_t hoveringPointerId) {
     for (TouchedWindow& touchedWindow : windows) {
         if (touchedWindow.windowHandle == windowHandle) {
-            touchedWindow.addHoveringPointer(hoveringDeviceId, hoveringPointerId);
+            touchedWindow.addHoveringPointer(deviceId, hoveringPointerId);
             return;
         }
     }
 
     TouchedWindow touchedWindow;
     touchedWindow.windowHandle = windowHandle;
-    touchedWindow.addHoveringPointer(hoveringDeviceId, hoveringPointerId);
+    touchedWindow.addHoveringPointer(deviceId, hoveringPointerId);
     windows.push_back(touchedWindow);
 }
 
@@ -149,12 +148,12 @@
     }
 }
 
-void TouchState::cancelPointersForWindowsExcept(int32_t touchedDeviceId,
+void TouchState::cancelPointersForWindowsExcept(DeviceId deviceId,
                                                 std::bitset<MAX_POINTER_ID + 1> pointerIds,
                                                 const sp<IBinder>& token) {
     std::for_each(windows.begin(), windows.end(), [&](TouchedWindow& w) {
         if (w.windowHandle->getToken() != token) {
-            w.removeTouchingPointers(touchedDeviceId, pointerIds);
+            w.removeTouchingPointers(deviceId, pointerIds);
         }
     });
     clearWindowsWithoutPointers();
@@ -168,10 +167,10 @@
  */
 void TouchState::cancelPointersForNonPilferingWindows() {
     // First, find all pointers that are being pilfered, across all windows
-    std::map<int32_t /*deviceId*/, std::bitset<MAX_POINTER_ID + 1>> allPilferedPointerIdsByDevice;
+    std::map<DeviceId, std::bitset<MAX_POINTER_ID + 1>> allPilferedPointerIdsByDevice;
     for (const TouchedWindow& w : windows) {
-        for (const auto& [iterDeviceId, pilferedPointerIds] : w.getPilferingPointers()) {
-            allPilferedPointerIdsByDevice[iterDeviceId] |= pilferedPointerIds;
+        for (const auto& [deviceId, pilferedPointerIds] : w.getPilferingPointers()) {
+            allPilferedPointerIdsByDevice[deviceId] |= pilferedPointerIds;
         }
     };
 
@@ -183,12 +182,12 @@
     // (only), the remove pointer 2 from window A and pointer 1 from window B. Usually, the set of
     // pilfered pointers will be disjoint across all windows, but there's no reason to cause that
     // limitation here.
-    for (const auto& [iterDeviceId, allPilferedPointerIds] : allPilferedPointerIdsByDevice) {
+    for (const auto& [deviceId, allPilferedPointerIds] : allPilferedPointerIdsByDevice) {
         std::for_each(windows.begin(), windows.end(), [&](TouchedWindow& w) {
             std::bitset<MAX_POINTER_ID + 1> pilferedByOtherWindows =
-                    w.getPilferingPointers(iterDeviceId) ^ allPilferedPointerIds;
+                    w.getPilferingPointers(deviceId) ^ allPilferedPointerIds;
             // Remove all pointers pilfered by other windows
-            w.removeTouchingPointers(iterDeviceId, pilferedByOtherWindows);
+            w.removeTouchingPointers(deviceId, pilferedByOtherWindows);
         });
     }
     clearWindowsWithoutPointers();
@@ -248,11 +247,11 @@
                        [](const TouchedWindow& window) { return window.hasHoveringPointers(); });
 }
 
-std::set<sp<WindowInfoHandle>> TouchState::getWindowsWithHoveringPointer(int32_t hoveringDeviceId,
+std::set<sp<WindowInfoHandle>> TouchState::getWindowsWithHoveringPointer(DeviceId deviceId,
                                                                          int32_t pointerId) const {
     std::set<sp<WindowInfoHandle>> out;
     for (const TouchedWindow& window : windows) {
-        if (window.hasHoveringPointer(hoveringDeviceId, pointerId)) {
+        if (window.hasHoveringPointer(deviceId, pointerId)) {
             out.insert(window.windowHandle);
         }
     }
@@ -266,10 +265,10 @@
     clearWindowsWithoutPointers();
 }
 
-void TouchState::removeAllPointersForDevice(int32_t removedDeviceId) {
+void TouchState::removeAllPointersForDevice(DeviceId deviceId) {
     for (TouchedWindow& window : windows) {
-        window.removeAllHoveringPointersForDevice(removedDeviceId);
-        window.removeAllTouchingPointersForDevice(removedDeviceId);
+        window.removeAllHoveringPointersForDevice(deviceId);
+        window.removeAllTouchingPointersForDevice(deviceId);
     }
 
     clearWindowsWithoutPointers();
@@ -277,7 +276,6 @@
 
 std::string TouchState::dump() const {
     std::string out;
-    out += StringPrintf("source=%s\n", inputEventSourceToString(source).c_str());
     if (!windows.empty()) {
         out += "  Windows:\n";
         for (size_t i = 0; i < windows.size(); i++) {
diff --git a/services/inputflinger/dispatcher/TouchState.h b/services/inputflinger/dispatcher/TouchState.h
index 1bda0fb..25b9643 100644
--- a/services/inputflinger/dispatcher/TouchState.h
+++ b/services/inputflinger/dispatcher/TouchState.h
@@ -29,9 +29,6 @@
 namespace inputdispatcher {
 
 struct TouchState {
-    // source of the device that is current down, others are rejected
-    uint32_t source = 0;
-
     std::vector<TouchedWindow> windows;
 
     TouchState() = default;
@@ -44,24 +41,24 @@
     std::set<int32_t> getActiveDeviceIds() const;
 
     bool hasTouchingPointers(int32_t device) const;
-    void removeTouchingPointer(int32_t deviceId, int32_t pointerId);
-    void removeTouchingPointerFromWindow(int32_t deviceId, int32_t pointerId,
+    void removeTouchingPointer(DeviceId deviceId, int32_t pointerId);
+    void removeTouchingPointerFromWindow(DeviceId deviceId, int32_t pointerId,
                                          const sp<android::gui::WindowInfoHandle>& windowHandle);
     void addOrUpdateWindow(const sp<android::gui::WindowInfoHandle>& windowHandle,
-                           ftl::Flags<InputTarget::Flags> targetFlags, int32_t deviceId,
+                           ftl::Flags<InputTarget::Flags> targetFlags, DeviceId deviceId,
                            std::bitset<MAX_POINTER_ID + 1> touchingPointerIds,
                            std::optional<nsecs_t> firstDownTimeInTarget = std::nullopt);
     void addHoveringPointerToWindow(const sp<android::gui::WindowInfoHandle>& windowHandle,
-                                    int32_t deviceId, int32_t hoveringPointerId);
-    void removeHoveringPointer(int32_t deviceId, int32_t hoveringPointerId);
+                                    DeviceId deviceId, int32_t hoveringPointerId);
+    void removeHoveringPointer(DeviceId deviceId, int32_t hoveringPointerId);
     void clearHoveringPointers();
 
-    void removeAllPointersForDevice(int32_t deviceId);
+    void removeAllPointersForDevice(DeviceId deviceId);
     void removeWindowByToken(const sp<IBinder>& token);
     void filterNonAsIsTouchWindows();
 
     // Cancel pointers for current set of windows except the window with particular binder token.
-    void cancelPointersForWindowsExcept(int32_t deviceId,
+    void cancelPointersForWindowsExcept(DeviceId deviceId,
                                         std::bitset<MAX_POINTER_ID + 1> pointerIds,
                                         const sp<IBinder>& token);
     // Cancel pointers for current set of non-pilfering windows i.e. windows with isPilferingWindow
@@ -78,7 +75,7 @@
     bool hasHoveringPointers() const;
 
     std::set<sp<android::gui::WindowInfoHandle>> getWindowsWithHoveringPointer(
-            int32_t deviceId, int32_t pointerId) const;
+            DeviceId deviceId, int32_t pointerId) const;
     std::string dump() const;
 };
 
diff --git a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
index f13885a..4ddfee0 100644
--- a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
+++ b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
@@ -39,7 +39,7 @@
     /* Dumps the state of the input dispatcher.
      *
      * This method may be called on any thread (usually by the input manager). */
-    virtual void dump(std::string& dump) = 0;
+    virtual void dump(std::string& dump) const = 0;
 
     /* Called by the heatbeat to ensures that the dispatcher has not deadlocked. */
     virtual void monitor() = 0;
diff --git a/include/input/EventBuilders.h b/services/inputflinger/include/NotifyArgsBuilders.h
similarity index 60%
rename from include/input/EventBuilders.h
rename to services/inputflinger/include/NotifyArgsBuilders.h
index 09438e9..e4363a4 100644
--- a/include/input/EventBuilders.h
+++ b/services/inputflinger/include/NotifyArgsBuilders.h
@@ -19,145 +19,15 @@
 #include <NotifyArgs.h>
 #include <android/input.h>
 #include <attestation/HmacKeyManager.h>
+#include <gui/constants.h>
 #include <input/Input.h>
+#include <input/InputEventBuilders.h>
+#include <utils/Timers.h> // for nsecs_t, systemTime
+
 #include <vector>
 
 namespace android {
 
-// An arbitrary device id.
-static constexpr uint32_t DEFAULT_DEVICE_ID = 1;
-
-// The default policy flags to use for event injection by tests.
-static constexpr uint32_t DEFAULT_POLICY_FLAGS = POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER;
-
-class PointerBuilder {
-public:
-    PointerBuilder(int32_t id, ToolType toolType) {
-        mProperties.clear();
-        mProperties.id = id;
-        mProperties.toolType = toolType;
-        mCoords.clear();
-    }
-
-    PointerBuilder& x(float x) { return axis(AMOTION_EVENT_AXIS_X, x); }
-
-    PointerBuilder& y(float y) { return axis(AMOTION_EVENT_AXIS_Y, y); }
-
-    PointerBuilder& axis(int32_t axis, float value) {
-        mCoords.setAxisValue(axis, value);
-        return *this;
-    }
-
-    PointerProperties buildProperties() const { return mProperties; }
-
-    PointerCoords buildCoords() const { return mCoords; }
-
-private:
-    PointerProperties mProperties;
-    PointerCoords mCoords;
-};
-
-class MotionEventBuilder {
-public:
-    MotionEventBuilder(int32_t action, int32_t source) {
-        mAction = action;
-        mSource = source;
-        mEventTime = systemTime(SYSTEM_TIME_MONOTONIC);
-        mDownTime = mEventTime;
-    }
-
-    MotionEventBuilder& deviceId(int32_t deviceId) {
-        mDeviceId = deviceId;
-        return *this;
-    }
-
-    MotionEventBuilder& downTime(nsecs_t downTime) {
-        mDownTime = downTime;
-        return *this;
-    }
-
-    MotionEventBuilder& eventTime(nsecs_t eventTime) {
-        mEventTime = eventTime;
-        return *this;
-    }
-
-    MotionEventBuilder& displayId(int32_t displayId) {
-        mDisplayId = displayId;
-        return *this;
-    }
-
-    MotionEventBuilder& actionButton(int32_t actionButton) {
-        mActionButton = actionButton;
-        return *this;
-    }
-
-    MotionEventBuilder& buttonState(int32_t buttonState) {
-        mButtonState = buttonState;
-        return *this;
-    }
-
-    MotionEventBuilder& rawXCursorPosition(float rawXCursorPosition) {
-        mRawXCursorPosition = rawXCursorPosition;
-        return *this;
-    }
-
-    MotionEventBuilder& rawYCursorPosition(float rawYCursorPosition) {
-        mRawYCursorPosition = rawYCursorPosition;
-        return *this;
-    }
-
-    MotionEventBuilder& pointer(PointerBuilder pointer) {
-        mPointers.push_back(pointer);
-        return *this;
-    }
-
-    MotionEventBuilder& addFlag(uint32_t flags) {
-        mFlags |= flags;
-        return *this;
-    }
-
-    MotionEvent build() {
-        std::vector<PointerProperties> pointerProperties;
-        std::vector<PointerCoords> pointerCoords;
-        for (const PointerBuilder& pointer : mPointers) {
-            pointerProperties.push_back(pointer.buildProperties());
-            pointerCoords.push_back(pointer.buildCoords());
-        }
-
-        // Set mouse cursor position for the most common cases to avoid boilerplate.
-        if (mSource == AINPUT_SOURCE_MOUSE &&
-            !MotionEvent::isValidCursorPosition(mRawXCursorPosition, mRawYCursorPosition)) {
-            mRawXCursorPosition = pointerCoords[0].getX();
-            mRawYCursorPosition = pointerCoords[0].getY();
-        }
-
-        MotionEvent event;
-        static const ui::Transform kIdentityTransform;
-        event.initialize(InputEvent::nextId(), mDeviceId, mSource, mDisplayId, INVALID_HMAC,
-                         mAction, mActionButton, mFlags, /*edgeFlags=*/0, AMETA_NONE, mButtonState,
-                         MotionClassification::NONE, kIdentityTransform,
-                         /*xPrecision=*/0, /*yPrecision=*/0, mRawXCursorPosition,
-                         mRawYCursorPosition, kIdentityTransform, mDownTime, mEventTime,
-                         mPointers.size(), pointerProperties.data(), pointerCoords.data());
-        return event;
-    }
-
-private:
-    int32_t mAction;
-    int32_t mDeviceId{DEFAULT_DEVICE_ID};
-    int32_t mSource;
-    nsecs_t mDownTime;
-    nsecs_t mEventTime;
-    int32_t mDisplayId{ADISPLAY_ID_DEFAULT};
-    int32_t mActionButton{0};
-    int32_t mButtonState{0};
-    int32_t mFlags{0};
-    float mRawXCursorPosition{AMOTION_EVENT_INVALID_CURSOR_POSITION};
-    float mRawYCursorPosition{AMOTION_EVENT_INVALID_CURSOR_POSITION};
-
-    std::vector<PointerBuilder> mPointers;
-};
-
 class MotionArgsBuilder {
 public:
     MotionArgsBuilder(int32_t action, int32_t source) {
diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.cpp b/services/inputflinger/reader/mapper/CursorInputMapper.cpp
index c684ed4..79f07a5 100644
--- a/services/inputflinger/reader/mapper/CursorInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/CursorInputMapper.cpp
@@ -347,7 +347,7 @@
                                                AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
                                                &pointerCoords, mXPrecision, mYPrecision,
                                                xCursorPosition, yCursorPosition, downTime,
-                                               /* videoFrames */ {}));
+                                               /*videoFrames=*/{}));
             }
         }
 
@@ -357,7 +357,7 @@
                                        AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
                                        &pointerCoords, mXPrecision, mYPrecision, xCursorPosition,
                                        yCursorPosition, downTime,
-                                       /* videoFrames */ {}));
+                                       /*videoFrames=*/{}));
 
         if (buttonsPressed) {
             BitSet32 pressed(buttonsPressed);
@@ -371,7 +371,7 @@
                                                AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
                                                &pointerCoords, mXPrecision, mYPrecision,
                                                xCursorPosition, yCursorPosition, downTime,
-                                               /* videoFrames */ {}));
+                                               /*videoFrames=*/{}));
             }
         }
 
@@ -386,7 +386,7 @@
                                            AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
                                            &pointerCoords, mXPrecision, mYPrecision,
                                            xCursorPosition, yCursorPosition, downTime,
-                                           /* videoFrames */ {}));
+                                           /*videoFrames=*/{}));
         }
 
         // Send scroll events.
@@ -401,7 +401,7 @@
                                            AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
                                            &pointerCoords, mXPrecision, mYPrecision,
                                            xCursorPosition, yCursorPosition, downTime,
-                                           /* videoFrames */ {}));
+                                           /*videoFrames=*/{}));
         }
     }
 
diff --git a/services/inputflinger/reader/mapper/JoystickInputMapper.cpp b/services/inputflinger/reader/mapper/JoystickInputMapper.cpp
index 099a955..8a9ea75 100644
--- a/services/inputflinger/reader/mapper/JoystickInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/JoystickInputMapper.cpp
@@ -352,7 +352,7 @@
                                    MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1,
                                    &pointerProperties, &pointerCoords, 0, 0,
                                    AMOTION_EVENT_INVALID_CURSOR_POSITION,
-                                   AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, /* videoFrames */ {}));
+                                   AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, /*videoFrames=*/{}));
     return out;
 }
 
diff --git a/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp b/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp
index 7251830..07ae5b1 100644
--- a/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp
@@ -148,10 +148,10 @@
         out.push_back(
                 NotifyMotionArgs(getContext()->getNextId(), when, readTime, getDeviceId(), mSource,
                                  displayId, policyFlags, AMOTION_EVENT_ACTION_SCROLL, 0, 0,
-                                 metaState, /* buttonState */ 0, MotionClassification::NONE,
+                                 metaState, /*buttonState=*/0, MotionClassification::NONE,
                                  AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
                                  &pointerCoords, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
-                                 AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, /* videoFrames */ {}));
+                                 AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, /*videoFrames=*/{}));
     }
 
     mRotaryEncoderScrollAccumulator.finishSync();
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
index 44538f1..b565454 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
@@ -2009,12 +2009,12 @@
         PointerCoords& curOutCoords = outCoords[outIndex];
 
         if (curInProperties != curOutProperties) {
-            curOutProperties.copyFrom(curInProperties);
+            curOutProperties = curInProperties;
             changed = true;
         }
 
         if (curInCoords != curOutCoords) {
-            curOutCoords.copyFrom(curInCoords);
+            curOutCoords = curInCoords;
             changed = true;
         }
     }
@@ -2744,7 +2744,7 @@
                                        buttonState, MotionClassification::NONE,
                                        AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
                                        &pointerCoords, 0, 0, x, y, mPointerGesture.downTime,
-                                       /* videoFrames */ {}));
+                                       /*videoFrames=*/{}));
     }
 
     // Update state.
@@ -2756,10 +2756,9 @@
         for (BitSet32 idBits(mPointerGesture.currentGestureIdBits); !idBits.isEmpty();) {
             uint32_t id = idBits.clearFirstMarkedBit();
             uint32_t index = mPointerGesture.currentGestureIdToIndex[id];
-            mPointerGesture.lastGestureProperties[index].copyFrom(
-                    mPointerGesture.currentGestureProperties[index]);
-            mPointerGesture.lastGestureCoords[index].copyFrom(
-                    mPointerGesture.currentGestureCoords[index]);
+            mPointerGesture.lastGestureProperties[index] =
+                    mPointerGesture.currentGestureProperties[index];
+            mPointerGesture.lastGestureCoords[index] = mPointerGesture.currentGestureCoords[index];
             mPointerGesture.lastGestureIdToIndex[id] = index;
         }
     }
@@ -3543,8 +3542,7 @@
             std::tie(x, y) = mPointerController->getPosition();
         }
 
-        mPointerSimple.currentCoords.copyFrom(
-                mCurrentCookedState.cookedPointerData.pointerCoords[index]);
+        mPointerSimple.currentCoords = mCurrentCookedState.cookedPointerData.pointerCoords[index];
         mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x);
         mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y);
         mPointerSimple.currentProperties.id = 0;
@@ -3582,8 +3580,8 @@
 
         const auto [x, y] = mPointerController->getPosition();
         const uint32_t currentIndex = mCurrentRawState.rawPointerData.idToIndex[id];
-        mPointerSimple.currentCoords.copyFrom(
-                mCurrentCookedState.cookedPointerData.pointerCoords[currentIndex]);
+        mPointerSimple.currentCoords =
+                mCurrentCookedState.cookedPointerData.pointerCoords[currentIndex];
         mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x);
         mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y);
         mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE,
@@ -3643,7 +3641,7 @@
                                        mOrientedXPrecision, mOrientedYPrecision,
                                        mPointerSimple.lastCursorX, mPointerSimple.lastCursorY,
                                        mPointerSimple.downTime,
-                                       /* videoFrames */ {}));
+                                       /*videoFrames=*/{}));
     }
 
     if (mPointerSimple.hovering && !hovering) {
@@ -3658,7 +3656,7 @@
                                  &mPointerSimple.lastCoords, mOrientedXPrecision,
                                  mOrientedYPrecision, mPointerSimple.lastCursorX,
                                  mPointerSimple.lastCursorY, mPointerSimple.downTime,
-                                 /* videoFrames */ {}));
+                                 /*videoFrames=*/{}));
     }
 
     if (down) {
@@ -3675,7 +3673,7 @@
                                            &mPointerSimple.currentProperties,
                                            &mPointerSimple.currentCoords, mOrientedXPrecision,
                                            mOrientedYPrecision, cursorPosition.x, cursorPosition.y,
-                                           mPointerSimple.downTime, /* videoFrames */ {}));
+                                           mPointerSimple.downTime, /*videoFrames=*/{}));
         }
 
         // Send move.
@@ -3686,7 +3684,7 @@
                                        &mPointerSimple.currentProperties,
                                        &mPointerSimple.currentCoords, mOrientedXPrecision,
                                        mOrientedYPrecision, cursorPosition.x, cursorPosition.y,
-                                       mPointerSimple.downTime, /* videoFrames */ {}));
+                                       mPointerSimple.downTime, /*videoFrames=*/{}));
     }
 
     if (hovering) {
@@ -3702,7 +3700,7 @@
                                            &mPointerSimple.currentProperties,
                                            &mPointerSimple.currentCoords, mOrientedXPrecision,
                                            mOrientedYPrecision, cursorPosition.x, cursorPosition.y,
-                                           mPointerSimple.downTime, /* videoFrames */ {}));
+                                           mPointerSimple.downTime, /*videoFrames=*/{}));
         }
 
         // Send hover move.
@@ -3713,7 +3711,7 @@
                                  MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1,
                                  &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
                                  mOrientedXPrecision, mOrientedYPrecision, cursorPosition.x,
-                                 cursorPosition.y, mPointerSimple.downTime, /* videoFrames */ {}));
+                                 cursorPosition.y, mPointerSimple.downTime, /*videoFrames=*/{}));
     }
 
     if (mCurrentRawState.rawVScroll || mCurrentRawState.rawHScroll) {
@@ -3723,8 +3721,7 @@
         mWheelXVelocityControl.move(when, &hscroll, nullptr);
 
         // Send scroll.
-        PointerCoords pointerCoords;
-        pointerCoords.copyFrom(mPointerSimple.currentCoords);
+        PointerCoords pointerCoords = mPointerSimple.currentCoords;
         pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_VSCROLL, vscroll);
         pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll);
 
@@ -3735,13 +3732,13 @@
                                        &mPointerSimple.currentProperties, &pointerCoords,
                                        mOrientedXPrecision, mOrientedYPrecision, cursorPosition.x,
                                        cursorPosition.y, mPointerSimple.downTime,
-                                       /* videoFrames */ {}));
+                                       /*videoFrames=*/{}));
     }
 
     // Save state.
     if (down || hovering) {
-        mPointerSimple.lastCoords.copyFrom(mPointerSimple.currentCoords);
-        mPointerSimple.lastProperties.copyFrom(mPointerSimple.currentProperties);
+        mPointerSimple.lastCoords = mPointerSimple.currentCoords;
+        mPointerSimple.lastProperties = mPointerSimple.currentProperties;
         mPointerSimple.displayId = displayId;
         mPointerSimple.source = mSource;
         mPointerSimple.lastCursorX = cursorPosition.x;
@@ -3766,7 +3763,7 @@
                                        mOrientedXPrecision, mOrientedYPrecision,
                                        mPointerSimple.lastCursorX, mPointerSimple.lastCursorY,
                                        mPointerSimple.downTime,
-                                       /* videoFrames */ {}));
+                                       /*videoFrames=*/{}));
         if (mPointerController != nullptr) {
             mPointerController->fade(PointerControllerInterface::Transition::GRADUAL);
         }
@@ -3795,8 +3792,8 @@
     while (!idBits.isEmpty()) {
         uint32_t id = idBits.clearFirstMarkedBit();
         uint32_t index = idToIndex[id];
-        pointerProperties[pointerCount].copyFrom(properties[index]);
-        pointerCoords[pointerCount].copyFrom(coords[index]);
+        pointerProperties[pointerCount] = properties[index];
+        pointerCoords[pointerCount] = coords[index];
 
         if (changedId >= 0 && id == uint32_t(changedId)) {
             action |= pointerCount << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
diff --git a/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp b/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp
index ca4dd1e..986dabb 100644
--- a/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp
@@ -58,13 +58,14 @@
 };
 
 const std::vector<CurveSegment> segments = {
-        {10.922, 3.19, 0},
-        {31.750, 4.79, -17.526},
-        {98.044, 7.28, -96.52},
-        {std::numeric_limits<double>::infinity(), 15.04, -857.758},
+        {32.002, 3.19, 0},
+        {52.83, 4.79, -51.254},
+        {119.124, 7.28, -182.737},
+        {std::numeric_limits<double>::infinity(), 15.04, -1107.556},
 };
 
-const std::vector<double> sensitivityFactors = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 16, 18};
+const std::vector<double> sensitivityFactors = {1,  2,  4,  6,  7,  8,  9, 10,
+                                                11, 12, 13, 14, 16, 18, 20};
 
 std::vector<double> createAccelerationCurveForSensitivity(int32_t sensitivity,
                                                           size_t propertySize) {
diff --git a/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp b/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp
index 1088821..e826341 100644
--- a/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp
+++ b/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp
@@ -239,6 +239,11 @@
         out.push_back(makeMotionArgs(when, readTime, AMOTION_EVENT_ACTION_UP, /* actionButton= */ 0,
                                      newButtonState, /* pointerCount= */ 1, mFingerProps.data(),
                                      &coords, xCursorPosition, yCursorPosition));
+        // Send a HOVER_MOVE to tell the application that the mouse is hovering again.
+        out.push_back(makeMotionArgs(when, readTime, AMOTION_EVENT_ACTION_HOVER_MOVE,
+                                     /*actionButton=*/0, newButtonState, /*pointerCount=*/1,
+                                     mFingerProps.data(), &coords, xCursorPosition,
+                                     yCursorPosition));
     }
     mButtonState = newButtonState;
     return out;
diff --git a/services/inputflinger/tests/GestureConverter_test.cpp b/services/inputflinger/tests/GestureConverter_test.cpp
index a3994f0..482a266 100644
--- a/services/inputflinger/tests/GestureConverter_test.cpp
+++ b/services/inputflinger/tests/GestureConverter_test.cpp
@@ -169,7 +169,7 @@
                            /* down= */ GESTURES_BUTTON_NONE, /* up= */ GESTURES_BUTTON_RIGHT,
                            /* is_tap= */ false);
     args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, rightUpGesture);
-    ASSERT_EQ(2u, args.size());
+    ASSERT_EQ(3u, args.size());
 
     ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()),
                 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE),
@@ -181,6 +181,10 @@
                 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithButtonState(0),
                       WithCoords(POINTER_X, POINTER_Y),
                       WithToolType(ToolType::FINGER)));
+    args.pop_front();
+    ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()),
+                AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), WithButtonState(0),
+                      WithCoords(POINTER_X, POINTER_Y), WithToolType(ToolType::FINGER)));
 }
 
 TEST_F(GestureConverterTest, DragWithButton) {
@@ -225,7 +229,7 @@
                       /* down= */ GESTURES_BUTTON_NONE, /* up= */ GESTURES_BUTTON_LEFT,
                       /* is_tap= */ false);
     args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, upGesture);
-    ASSERT_EQ(2u, args.size());
+    ASSERT_EQ(3u, args.size());
 
     ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()),
                 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE),
@@ -237,6 +241,10 @@
                 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithButtonState(0),
                       WithCoords(POINTER_X - 5, POINTER_Y + 10),
                       WithToolType(ToolType::FINGER)));
+    args.pop_front();
+    ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()),
+                AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), WithButtonState(0),
+                      WithCoords(POINTER_X - 5, POINTER_Y + 10), WithToolType(ToolType::FINGER)));
 }
 
 TEST_F(GestureConverterTest, Scroll) {
diff --git a/services/inputflinger/tests/InputDeviceMetricsCollector_test.cpp b/services/inputflinger/tests/InputDeviceMetricsCollector_test.cpp
index 0aa5e23..2ff64c8 100644
--- a/services/inputflinger/tests/InputDeviceMetricsCollector_test.cpp
+++ b/services/inputflinger/tests/InputDeviceMetricsCollector_test.cpp
@@ -16,9 +16,10 @@
 
 #include "../InputDeviceMetricsCollector.h"
 
+#include <NotifyArgsBuilders.h>
 #include <gtest/gtest.h>
 #include <gui/constants.h>
-#include <input/EventBuilders.h>
+#include <input/InputEventBuilders.h>
 #include <linux/input.h>
 
 #include <array>
@@ -421,6 +422,7 @@
         // Device was used.
         mMetricsCollector.notifyMotion(generateMotionArgs(ignoredDeviceId));
         mTestListener.assertNotifyMotionWasCalled();
+        mMetricsCollector.notifyDeviceInteraction(ignoredDeviceId, TIME.count(), uids({0, 1, 2}));
         ASSERT_NO_FATAL_FAILURE(assertUsageNotLogged());
 
         // Device was used again after the usage timeout expired, but we still don't log usage.
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 2950656..d367cd7 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -17,6 +17,7 @@
 #include "../dispatcher/InputDispatcher.h"
 #include "../BlockingQueue.h"
 
+#include <NotifyArgsBuilders.h>
 #include <android-base/properties.h>
 #include <android-base/silent_death_test.h>
 #include <android-base/stringprintf.h>
@@ -25,7 +26,6 @@
 #include <fcntl.h>
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
-#include <input/EventBuilders.h>
 #include <input/Input.h>
 #include <linux/input.h>
 #include <sys/epoll.h>
@@ -641,7 +641,7 @@
     void SetUp() override {
         mFakePolicy = std::make_unique<FakeInputDispatcherPolicy>();
         mDispatcher = std::make_unique<InputDispatcher>(*mFakePolicy, STALE_EVENT_TIMEOUT);
-        mDispatcher->setInputDispatchMode(/*enabled*/ true, /*frozen*/ false);
+        mDispatcher->setInputDispatchMode(/*enabled=*/true, /*frozen=*/false);
         // Start InputDispatcher thread
         ASSERT_EQ(OK, mDispatcher->start());
     }
@@ -682,7 +682,7 @@
     // Rejects undefined key actions.
     event.initialize(InputEvent::nextId(), DEVICE_ID, AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_NONE,
                      INVALID_HMAC,
-                     /*action*/ -1, 0, AKEYCODE_A, KEY_A, AMETA_NONE, 0, ARBITRARY_TIME,
+                     /*action=*/-1, 0, AKEYCODE_A, KEY_A, AMETA_NONE, 0, ARBITRARY_TIME,
                      ARBITRARY_TIME);
     ASSERT_EQ(InputEventInjectionResult::FAILED,
               mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
@@ -718,11 +718,11 @@
     ui::Transform identityTransform;
     // Rejects undefined motion actions.
     event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
-                     /*action*/ -1, 0, 0, edgeFlags, metaState, 0, classification,
+                     /*action=*/-1, 0, 0, edgeFlags, metaState, 0, classification,
                      identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
                      AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME,
                      ARBITRARY_TIME,
-                     /*pointerCount*/ 1, pointerProperties, pointerCoords);
+                     /*pointerCount=*/1, pointerProperties, pointerCoords);
     ASSERT_EQ(InputEventInjectionResult::FAILED,
               mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
                                             0ms, 0))
@@ -734,7 +734,7 @@
                      identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
                      AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME,
                      ARBITRARY_TIME,
-                     /*pointerCount*/ 1, pointerProperties, pointerCoords);
+                     /*pointerCount=*/1, pointerProperties, pointerCoords);
     ASSERT_EQ(InputEventInjectionResult::FAILED,
               mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
                                             0ms, 0))
@@ -746,7 +746,7 @@
                      0, 0, edgeFlags, metaState, 0, classification, identityTransform, 0, 0,
                      AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION,
                      identityTransform, ARBITRARY_TIME, ARBITRARY_TIME,
-                     /*pointerCount*/ 1, pointerProperties, pointerCoords);
+                     /*pointerCount=*/1, pointerProperties, pointerCoords);
     ASSERT_EQ(InputEventInjectionResult::FAILED,
               mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
                                             0ms, 0))
@@ -758,7 +758,7 @@
                      0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
                      AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME,
                      ARBITRARY_TIME,
-                     /*pointerCount*/ 1, pointerProperties, pointerCoords);
+                     /*pointerCount=*/1, pointerProperties, pointerCoords);
     ASSERT_EQ(InputEventInjectionResult::FAILED,
               mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
                                             0ms, 0))
@@ -770,7 +770,7 @@
                      0, 0, edgeFlags, metaState, 0, classification, identityTransform, 0, 0,
                      AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION,
                      identityTransform, ARBITRARY_TIME, ARBITRARY_TIME,
-                     /*pointerCount*/ 1, pointerProperties, pointerCoords);
+                     /*pointerCount=*/1, pointerProperties, pointerCoords);
     ASSERT_EQ(InputEventInjectionResult::FAILED,
               mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
                                             0ms, 0))
@@ -782,7 +782,7 @@
                      identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
                      AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME,
                      ARBITRARY_TIME,
-                     /*pointerCount*/ 0, pointerProperties, pointerCoords);
+                     /*pointerCount=*/0, pointerProperties, pointerCoords);
     ASSERT_EQ(InputEventInjectionResult::FAILED,
               mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
                                             0ms, 0))
@@ -793,7 +793,7 @@
                      identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
                      AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME,
                      ARBITRARY_TIME,
-                     /*pointerCount*/ MAX_POINTERS + 1, pointerProperties, pointerCoords);
+                     /*pointerCount=*/MAX_POINTERS + 1, pointerProperties, pointerCoords);
     ASSERT_EQ(InputEventInjectionResult::FAILED,
               mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
                                             0ms, 0))
@@ -806,7 +806,7 @@
                      identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
                      AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME,
                      ARBITRARY_TIME,
-                     /*pointerCount*/ 1, pointerProperties, pointerCoords);
+                     /*pointerCount=*/1, pointerProperties, pointerCoords);
     ASSERT_EQ(InputEventInjectionResult::FAILED,
               mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
                                             0ms, 0))
@@ -818,7 +818,7 @@
                      identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
                      AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME,
                      ARBITRARY_TIME,
-                     /*pointerCount*/ 1, pointerProperties, pointerCoords);
+                     /*pointerCount=*/1, pointerProperties, pointerCoords);
     ASSERT_EQ(InputEventInjectionResult::FAILED,
               mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
                                             0ms, 0))
@@ -832,7 +832,7 @@
                      identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
                      AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME,
                      ARBITRARY_TIME,
-                     /*pointerCount*/ 2, pointerProperties, pointerCoords);
+                     /*pointerCount=*/2, pointerProperties, pointerCoords);
     ASSERT_EQ(InputEventInjectionResult::FAILED,
               mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
                                             0ms, 0))
@@ -1551,8 +1551,8 @@
     nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
     // Define a valid key event.
     NotifyKeyArgs args(/*id=*/0, currentTime, /*readTime=*/0, DEVICE_ID, AINPUT_SOURCE_KEYBOARD,
-                       displayId, POLICY_FLAG_PASS_TO_USER, action, /* flags */ 0, AKEYCODE_A,
-                       KEY_A, AMETA_NONE, currentTime);
+                       displayId, POLICY_FLAG_PASS_TO_USER, action, /*flags=*/0, AKEYCODE_A, KEY_A,
+                       AMETA_NONE, currentTime);
 
     return args;
 }
@@ -1562,7 +1562,7 @@
     nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
     // Define a valid key event.
     NotifyKeyArgs args(/*id=*/0, currentTime, /*readTime=*/0, DEVICE_ID, AINPUT_SOURCE_KEYBOARD,
-                       displayId, 0, action, /* flags */ 0, AKEYCODE_C, KEY_C, AMETA_META_ON,
+                       displayId, 0, action, /*flags=*/0, AKEYCODE_C, KEY_C, AMETA_META_ON,
                        currentTime);
 
     return args;
@@ -1573,7 +1573,7 @@
     nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
     // Define a valid key event.
     NotifyKeyArgs args(/*id=*/0, currentTime, /*readTime=*/0, DEVICE_ID, AINPUT_SOURCE_KEYBOARD,
-                       displayId, 0, action, /* flags */ 0, AKEYCODE_ASSIST, KEY_ASSISTANT,
+                       displayId, 0, action, /*flags=*/0, AKEYCODE_ASSIST, KEY_ASSISTANT,
                        AMETA_NONE, currentTime);
 
     return args;
@@ -1603,12 +1603,12 @@
     nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
     // Define a valid motion event.
     NotifyMotionArgs args(/*id=*/0, currentTime, /*readTime=*/0, DEVICE_ID, source, displayId,
-                          POLICY_FLAG_PASS_TO_USER, action, /* actionButton */ 0, /* flags */ 0,
-                          AMETA_NONE, /* buttonState */ 0, MotionClassification::NONE,
+                          POLICY_FLAG_PASS_TO_USER, action, /*actionButton=*/0, /*flags=*/0,
+                          AMETA_NONE, /*buttonState=*/0, MotionClassification::NONE,
                           AMOTION_EVENT_EDGE_FLAG_NONE, pointerCount, pointerProperties,
-                          pointerCoords, /* xPrecision */ 0, /* yPrecision */ 0,
+                          pointerCoords, /*xPrecision=*/0, /*yPrecision=*/0,
                           AMOTION_EVENT_INVALID_CURSOR_POSITION,
-                          AMOTION_EVENT_INVALID_CURSOR_POSITION, currentTime, /* videoFrames */ {});
+                          AMOTION_EVENT_INVALID_CURSOR_POSITION, currentTime, /*videoFrames=*/{});
 
     return args;
 }
@@ -1923,8 +1923,7 @@
                                                    AINPUT_SOURCE_TOUCHSCREEN)
                                         .displayId(ADISPLAY_ID_DEFAULT)
                                         .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
-                                        .pointer(PointerBuilder(/* id */ 1,
-                                                                ToolType::FINGER)
+                                        .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER)
                                                          .x(100)
                                                          .y(100))
                                         .build(),
@@ -5700,7 +5699,7 @@
     virtual void SetUp() override {
         mFakePolicy = std::make_unique<FakeInputDispatcherPolicy>();
         mDispatcher = std::make_unique<InputDispatcher>(*mFakePolicy);
-        mDispatcher->setInputDispatchMode(/*enabled*/ true, /*frozen*/ false);
+        mDispatcher->setInputDispatchMode(/*enabled=*/true, /*frozen=*/false);
         mDispatcher->setKeyRepeatConfiguration(KEY_REPEAT_TIMEOUT, KEY_REPEAT_DELAY);
         ASSERT_EQ(OK, mDispatcher->start());
 
@@ -6092,36 +6091,36 @@
 // Test InputFilter for MotionEvent
 TEST_F(InputFilterTest, MotionEvent_InputFilter) {
     // Since the InputFilter is disabled by default, check if touch events aren't filtered.
-    testNotifyMotion(ADISPLAY_ID_DEFAULT, /*expectToBeFiltered*/ false);
-    testNotifyMotion(SECOND_DISPLAY_ID, /*expectToBeFiltered*/ false);
+    testNotifyMotion(ADISPLAY_ID_DEFAULT, /*expectToBeFiltered=*/false);
+    testNotifyMotion(SECOND_DISPLAY_ID, /*expectToBeFiltered=*/false);
 
     // Enable InputFilter
     mDispatcher->setInputFilterEnabled(true);
     // Test touch on both primary and second display, and check if both events are filtered.
-    testNotifyMotion(ADISPLAY_ID_DEFAULT, /*expectToBeFiltered*/ true);
-    testNotifyMotion(SECOND_DISPLAY_ID, /*expectToBeFiltered*/ true);
+    testNotifyMotion(ADISPLAY_ID_DEFAULT, /*expectToBeFiltered=*/true);
+    testNotifyMotion(SECOND_DISPLAY_ID, /*expectToBeFiltered=*/true);
 
     // Disable InputFilter
     mDispatcher->setInputFilterEnabled(false);
     // Test touch on both primary and second display, and check if both events aren't filtered.
-    testNotifyMotion(ADISPLAY_ID_DEFAULT, /*expectToBeFiltered*/ false);
-    testNotifyMotion(SECOND_DISPLAY_ID, /*expectToBeFiltered*/ false);
+    testNotifyMotion(ADISPLAY_ID_DEFAULT, /*expectToBeFiltered=*/false);
+    testNotifyMotion(SECOND_DISPLAY_ID, /*expectToBeFiltered=*/false);
 }
 
 // Test InputFilter for KeyEvent
 TEST_F(InputFilterTest, KeyEvent_InputFilter) {
     // Since the InputFilter is disabled by default, check if key event aren't filtered.
-    testNotifyKey(/*expectToBeFiltered*/ false);
+    testNotifyKey(/*expectToBeFiltered=*/false);
 
     // Enable InputFilter
     mDispatcher->setInputFilterEnabled(true);
     // Send a key event, and check if it is filtered.
-    testNotifyKey(/*expectToBeFiltered*/ true);
+    testNotifyKey(/*expectToBeFiltered=*/true);
 
     // Disable InputFilter
     mDispatcher->setInputFilterEnabled(false);
     // Send a key event, and check if it isn't filtered.
-    testNotifyKey(/*expectToBeFiltered*/ false);
+    testNotifyKey(/*expectToBeFiltered=*/false);
 }
 
 // Ensure that MotionEvents sent to the InputFilter through InputListener are converted to the
@@ -6144,8 +6143,8 @@
     mDispatcher->setInputFilterEnabled(true);
 
     // Ensure the correct transforms are used for the displays.
-    testNotifyMotion(ADISPLAY_ID_DEFAULT, /*expectToBeFiltered*/ true, firstDisplayTransform);
-    testNotifyMotion(SECOND_DISPLAY_ID, /*expectToBeFiltered*/ true, secondDisplayTransform);
+    testNotifyMotion(ADISPLAY_ID_DEFAULT, /*expectToBeFiltered=*/true, firstDisplayTransform);
+    testNotifyMotion(SECOND_DISPLAY_ID, /*expectToBeFiltered=*/true, secondDisplayTransform);
 }
 
 class InputFilterInjectionPolicyTest : public InputDispatcherTest {
@@ -6214,7 +6213,7 @@
                          identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
                          AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, eventTime,
                          eventTime,
-                         /*pointerCount*/ 1, pointerProperties, pointerCoords);
+                         /*pointerCount=*/1, pointerProperties, pointerCoords);
 
         const int32_t additionalPolicyFlags = POLICY_FLAG_PASS_TO_USER;
         ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
@@ -6607,11 +6606,11 @@
         InputDispatcherTest::SetUp();
 
         mApplication = std::make_shared<FakeApplicationHandle>();
-        mApplication->setDispatchingTimeout(20ms);
+        mApplication->setDispatchingTimeout(100ms);
         mWindow = sp<FakeWindowHandle>::make(mApplication, mDispatcher, "TestWindow",
                                              ADISPLAY_ID_DEFAULT);
         mWindow->setFrame(Rect(0, 0, 30, 30));
-        mWindow->setDispatchingTimeout(30ms);
+        mWindow->setDispatchingTimeout(100ms);
         mWindow->setFocusable(true);
 
         // Set focused application.
@@ -6677,7 +6676,7 @@
 
     InputEventInjectionResult result =
             injectKey(mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT,
-                      InputEventInjectionSync::NONE, /*injectionTimeout=*/10ms,
+                      InputEventInjectionSync::NONE, /*injectionTimeout=*/50ms,
                       /*allowKeyRepeat=*/false);
     ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, result);
     // Key will not go to window because we have no focused window.
@@ -6741,7 +6740,7 @@
     // injection times out (instead of failing).
     const InputEventInjectionResult result =
             injectKey(mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT,
-                      InputEventInjectionSync::WAIT_FOR_RESULT, 10ms, /*allowKeyRepeat=*/false);
+                      InputEventInjectionSync::WAIT_FOR_RESULT, 50ms, /*allowKeyRepeat=*/false);
     ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, result);
     const std::chrono::duration timeout = mApplication->getDispatchingTimeout(DISPATCHING_TIMEOUT);
     mFakePolicy->assertNotifyNoFocusedWindowAnrWasCalled(timeout, mApplication);
@@ -6763,7 +6762,7 @@
 
     // Define a valid key down event that is stale (too old).
     event.initialize(InputEvent::nextId(), DEVICE_ID, AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_NONE,
-                     INVALID_HMAC, AKEY_EVENT_ACTION_DOWN, /* flags */ 0, AKEYCODE_A, KEY_A,
+                     INVALID_HMAC, AKEY_EVENT_ACTION_DOWN, /*flags=*/0, AKEYCODE_A, KEY_A,
                      AMETA_NONE, /*repeatCount=*/1, eventTime, eventTime);
 
     const int32_t policyFlags = POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER;
@@ -6792,7 +6791,7 @@
     // injection times out (instead of failing).
     const InputEventInjectionResult result =
             injectKey(mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT,
-                      InputEventInjectionSync::WAIT_FOR_RESULT, 10ms, /*allowKeyRepeat=*/false);
+                      InputEventInjectionSync::WAIT_FOR_RESULT, 50ms, /*allowKeyRepeat=*/false);
     ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, result);
     const std::chrono::duration appTimeout =
             mApplication->getDispatchingTimeout(DISPATCHING_TIMEOUT);
@@ -6816,7 +6815,7 @@
     // Once a focused event arrives, we get an ANR for this application
     const InputEventInjectionResult result =
             injectKey(mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT,
-                      InputEventInjectionSync::WAIT_FOR_RESULT, 10ms);
+                      InputEventInjectionSync::WAIT_FOR_RESULT, 50ms);
     ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, result);
 
     const std::chrono::duration timeout = mApplication->getDispatchingTimeout(DISPATCHING_TIMEOUT);
@@ -7032,7 +7031,7 @@
 
     InputEventInjectionResult result =
             injectKey(mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT,
-                      InputEventInjectionSync::WAIT_FOR_RESULT, 10ms);
+                      InputEventInjectionSync::WAIT_FOR_RESULT, 50ms);
     ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, result);
     // Key will not be sent to the window, yet, because the window is still processing events
     // and the key remains pending, waiting for the touch events to be processed
@@ -7137,7 +7136,7 @@
         InputDispatcherTest::SetUp();
 
         mApplication = std::make_shared<FakeApplicationHandle>();
-        mApplication->setDispatchingTimeout(10ms);
+        mApplication->setDispatchingTimeout(100ms);
         mUnfocusedWindow = sp<FakeWindowHandle>::make(mApplication, mDispatcher, "Unfocused",
                                                       ADISPLAY_ID_DEFAULT);
         mUnfocusedWindow->setFrame(Rect(0, 0, 30, 30));
@@ -7146,7 +7145,7 @@
 
         mFocusedWindow = sp<FakeWindowHandle>::make(mApplication, mDispatcher, "Focused",
                                                     ADISPLAY_ID_DEFAULT);
-        mFocusedWindow->setDispatchingTimeout(30ms);
+        mFocusedWindow->setDispatchingTimeout(100ms);
         mFocusedWindow->setFrame(Rect(50, 50, 100, 100));
 
         // Set focused application.
@@ -7232,20 +7231,21 @@
 // But we should receive ANR for both.
 TEST_F(InputDispatcherMultiWindowAnr, TwoWindows_BothUnresponsiveWithSameTimeout) {
     // Set the timeout for unfocused window to match the focused window
-    mUnfocusedWindow->setDispatchingTimeout(10ms);
+    mUnfocusedWindow->setDispatchingTimeout(
+            mFocusedWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT));
     mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mUnfocusedWindow, mFocusedWindow}}});
 
     tapOnFocusedWindow();
     // we should have ACTION_DOWN/ACTION_UP on focused window and ACTION_OUTSIDE on unfocused window
-    sp<IBinder> anrConnectionToken1, anrConnectionToken2;
-    ASSERT_NO_FATAL_FAILURE(anrConnectionToken1 = mFakePolicy->getUnresponsiveWindowToken(10ms));
-    ASSERT_NO_FATAL_FAILURE(anrConnectionToken2 = mFakePolicy->getUnresponsiveWindowToken(0ms));
-
     // We don't know which window will ANR first. But both of them should happen eventually.
-    ASSERT_TRUE(mFocusedWindow->getToken() == anrConnectionToken1 ||
-                mFocusedWindow->getToken() == anrConnectionToken2);
-    ASSERT_TRUE(mUnfocusedWindow->getToken() == anrConnectionToken1 ||
-                mUnfocusedWindow->getToken() == anrConnectionToken2);
+    std::array<sp<IBinder>, 2> anrConnectionTokens = {mFakePolicy->getUnresponsiveWindowToken(
+                                                              mFocusedWindow->getDispatchingTimeout(
+                                                                      DISPATCHING_TIMEOUT)),
+                                                      mFakePolicy->getUnresponsiveWindowToken(0ms)};
+
+    ASSERT_THAT(anrConnectionTokens,
+                ::testing::UnorderedElementsAre(testing::Eq(mFocusedWindow->getToken()),
+                                                testing::Eq(mUnfocusedWindow->getToken())));
 
     ASSERT_TRUE(mDispatcher->waitForIdle());
     mFakePolicy->assertNotifyAnrWasNotCalled();
@@ -7254,15 +7254,13 @@
     mFocusedWindow->consumeMotionUp();
     mUnfocusedWindow->consumeMotionOutside();
 
-    sp<IBinder> responsiveToken1, responsiveToken2;
-    ASSERT_NO_FATAL_FAILURE(responsiveToken1 = mFakePolicy->getResponsiveWindowToken());
-    ASSERT_NO_FATAL_FAILURE(responsiveToken2 = mFakePolicy->getResponsiveWindowToken());
+    std::array<sp<IBinder>, 2> responsiveTokens = {mFakePolicy->getResponsiveWindowToken(),
+                                                   mFakePolicy->getResponsiveWindowToken()};
 
     // Both applications should be marked as responsive, in any order
-    ASSERT_TRUE(mFocusedWindow->getToken() == responsiveToken1 ||
-                mFocusedWindow->getToken() == responsiveToken2);
-    ASSERT_TRUE(mUnfocusedWindow->getToken() == responsiveToken1 ||
-                mUnfocusedWindow->getToken() == responsiveToken2);
+    ASSERT_THAT(responsiveTokens,
+                ::testing::UnorderedElementsAre(testing::Eq(mFocusedWindow->getToken()),
+                                                testing::Eq(mUnfocusedWindow->getToken())));
     mFakePolicy->assertNotifyAnrWasNotCalled();
 }
 
@@ -7362,7 +7360,7 @@
 
     InputEventInjectionResult result =
             injectKey(mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT,
-                      InputEventInjectionSync::NONE, /*injectionTimeout=*/10ms);
+                      InputEventInjectionSync::NONE, /*injectionTimeout=*/50ms);
     ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, result);
     // Key will not be sent to the window, yet, because the window is still processing events
     // and the key remains pending, waiting for the touch events to be processed
@@ -7450,7 +7448,7 @@
 TEST_F(InputDispatcherMultiWindowAnr, FocusedWindowWithoutSetFocusedApplication_NoAnr) {
     std::shared_ptr<FakeApplicationHandle> focusedApplication =
             std::make_shared<FakeApplicationHandle>();
-    focusedApplication->setDispatchingTimeout(60ms);
+    focusedApplication->setDispatchingTimeout(100ms);
     mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, focusedApplication);
     // The application that owns 'mFocusedWindow' and 'mUnfocusedWindow' is not focused.
     mFocusedWindow->setFocusable(false);
@@ -7463,7 +7461,7 @@
     // Key will not be sent anywhere because we have no focused window. It will remain pending.
     InputEventInjectionResult result =
             injectKey(mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT,
-                      InputEventInjectionSync::NONE, /*injectionTimeout=*/10ms,
+                      InputEventInjectionSync::NONE, /*injectionTimeout=*/50ms,
                       /*allowKeyRepeat=*/false);
     ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, result);
 
@@ -7474,7 +7472,7 @@
     // simply be added to the queue without 'shouldPruneInboundQueueLocked' returning 'true'.
     // For this test, it means that the key would get delivered to the window once it becomes
     // focused.
-    std::this_thread::sleep_for(10ms);
+    std::this_thread::sleep_for(50ms);
 
     // Touch unfocused window. This should force the pending key to get dropped.
     mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
@@ -9435,8 +9433,8 @@
 
     // Spy window pilfers the pointers.
     EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken()));
-    window->consumeMotionPointerUp(/* idx */ 2, ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_CANCELED);
-    window->consumeMotionPointerUp(/* idx */ 1, ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_CANCELED);
+    window->consumeMotionPointerUp(/*idx=*/2, ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_CANCELED);
+    window->consumeMotionPointerUp(/*idx=*/1, ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_CANCELED);
 
     spy->assertNoEvents();
     window->assertNoEvents();
diff --git a/services/inputflinger/tests/SyncQueue_test.cpp b/services/inputflinger/tests/SyncQueue_test.cpp
index af2f961..b57ccc2 100644
--- a/services/inputflinger/tests/SyncQueue_test.cpp
+++ b/services/inputflinger/tests/SyncQueue_test.cpp
@@ -50,6 +50,18 @@
     }
 }
 
+// Make sure the queue has strict capacity limits.
+TEST(SyncQueueTest, QueueReachesCapacity) {
+    constexpr size_t capacity = 3;
+    SyncQueue<int> queue(capacity);
+
+    // First 3 elements should be added successfully
+    ASSERT_TRUE(queue.push(1));
+    ASSERT_TRUE(queue.push(2));
+    ASSERT_TRUE(queue.push(3));
+    ASSERT_FALSE(queue.push(4)) << "Queue should reach capacity at size " << capacity;
+}
+
 TEST(SyncQueueTest, AllowsMultipleThreads) {
     SyncQueue<int> queue;
 
diff --git a/services/inputflinger/tests/TouchpadInputMapper_test.cpp b/services/inputflinger/tests/TouchpadInputMapper_test.cpp
index 92cd462..02abf9f 100644
--- a/services/inputflinger/tests/TouchpadInputMapper_test.cpp
+++ b/services/inputflinger/tests/TouchpadInputMapper_test.cpp
@@ -139,7 +139,8 @@
                             VariantWith<NotifyMotionArgs>(WithMotionAction(ACTION_DOWN)),
                             VariantWith<NotifyMotionArgs>(WithMotionAction(BUTTON_PRESS)),
                             VariantWith<NotifyMotionArgs>(WithMotionAction(BUTTON_RELEASE)),
-                            VariantWith<NotifyMotionArgs>(WithMotionAction(ACTION_UP))));
+                            VariantWith<NotifyMotionArgs>(WithMotionAction(ACTION_UP)),
+                            VariantWith<NotifyMotionArgs>(WithMotionAction(HOVER_MOVE))));
 
     // Liftoff
     args.clear();
diff --git a/services/inputflinger/tests/UnwantedInteractionBlocker_test.cpp b/services/inputflinger/tests/UnwantedInteractionBlocker_test.cpp
index da0815f..7cfcf71 100644
--- a/services/inputflinger/tests/UnwantedInteractionBlocker_test.cpp
+++ b/services/inputflinger/tests/UnwantedInteractionBlocker_test.cpp
@@ -88,14 +88,13 @@
     }
 
     // Define a valid motion event.
-    NotifyMotionArgs args(/* id */ 0, eventTime, /*readTime=*/0, DEVICE_ID,
-                          AINPUT_SOURCE_TOUCHSCREEN, /*displayId=*/0, POLICY_FLAG_PASS_TO_USER,
-                          action, /* actionButton */ 0,
-                          /* flags */ 0, AMETA_NONE, /* buttonState */ 0,
-                          MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, pointerCount,
-                          pointerProperties, pointerCoords, /* xPrecision */ 0, /* yPrecision */ 0,
+    NotifyMotionArgs args(/*id=*/0, eventTime, /*readTime=*/0, DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
+                          /*displayId=*/0, POLICY_FLAG_PASS_TO_USER, action, /*actionButton=*/0,
+                          /*flags=*/0, AMETA_NONE, /*buttonState=*/0, MotionClassification::NONE,
+                          AMOTION_EVENT_EDGE_FLAG_NONE, pointerCount, pointerProperties,
+                          pointerCoords, /*xPrecision=*/0, /*yPrecision=*/0,
                           AMOTION_EVENT_INVALID_CURSOR_POSITION,
-                          AMOTION_EVENT_INVALID_CURSOR_POSITION, downTime, /* videoFrames */ {});
+                          AMOTION_EVENT_INVALID_CURSOR_POSITION, downTime, /*videoFrames=*/{});
 
     return args;
 }
@@ -104,15 +103,15 @@
     InputDeviceIdentifier identifier;
 
     auto info = InputDeviceInfo();
-    info.initialize(DEVICE_ID, /*generation*/ 1, /*controllerNumber*/ 1, identifier, "alias",
-                    /*isExternal*/ false, /*hasMic*/ false, ADISPLAY_ID_NONE);
+    info.initialize(DEVICE_ID, /*generation=*/1, /*controllerNumber=*/1, identifier, "alias",
+                    /*isExternal=*/false, /*hasMic=*/false, ADISPLAY_ID_NONE);
     info.addSource(AINPUT_SOURCE_TOUCHSCREEN);
-    info.addMotionRange(AMOTION_EVENT_AXIS_X, AINPUT_SOURCE_TOUCHSCREEN, 0, 1599, /*flat*/ 0,
-                        /*fuzz*/ 0, X_RESOLUTION);
-    info.addMotionRange(AMOTION_EVENT_AXIS_Y, AINPUT_SOURCE_TOUCHSCREEN, 0, 2559, /*flat*/ 0,
-                        /*fuzz*/ 0, Y_RESOLUTION);
+    info.addMotionRange(AMOTION_EVENT_AXIS_X, AINPUT_SOURCE_TOUCHSCREEN, 0, 1599, /*flat=*/0,
+                        /*fuzz=*/0, X_RESOLUTION);
+    info.addMotionRange(AMOTION_EVENT_AXIS_Y, AINPUT_SOURCE_TOUCHSCREEN, 0, 2559, /*flat=*/0,
+                        /*fuzz=*/0, Y_RESOLUTION);
     info.addMotionRange(AMOTION_EVENT_AXIS_TOUCH_MAJOR, AINPUT_SOURCE_TOUCHSCREEN, 0, 255,
-                        /*flat*/ 0, /*fuzz*/ 0, MAJOR_RESOLUTION);
+                        /*flat=*/0, /*fuzz=*/0, MAJOR_RESOLUTION);
 
     return info;
 }
@@ -152,7 +151,7 @@
 }
 
 TEST(RemovePointerIdsTest, RemoveOnePointer) {
-    NotifyMotionArgs args = generateMotionArgs(/*downTime*/ 0, /*eventTime*/ 0,
+    NotifyMotionArgs args = generateMotionArgs(/*downTime=*/0, /*eventTime=*/0,
                                                AMOTION_EVENT_ACTION_MOVE, {{1, 2, 3}, {4, 5, 6}});
 
     NotifyMotionArgs pointer1Only = removePointerIds(args, {0});
@@ -167,7 +166,7 @@
  */
 TEST(RemovePointerIdsTest, RemoveTwoPointers) {
     NotifyMotionArgs args =
-            generateMotionArgs(/*downTime*/ 0, /*eventTime*/ 0, AMOTION_EVENT_ACTION_MOVE,
+            generateMotionArgs(/*downTime=*/0, /*eventTime=*/0, AMOTION_EVENT_ACTION_MOVE,
                                {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}});
 
     NotifyMotionArgs pointer1Only = removePointerIds(args, {0, 2});
@@ -179,7 +178,7 @@
  * pointer during a POINTER_DOWN event.
  */
 TEST(RemovePointerIdsTest, ActionPointerDown) {
-    NotifyMotionArgs args = generateMotionArgs(/*downTime*/ 0, /*eventTime*/ 0, POINTER_1_DOWN,
+    NotifyMotionArgs args = generateMotionArgs(/*downTime=*/0, /*eventTime=*/0, POINTER_1_DOWN,
                                                {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}});
 
     NotifyMotionArgs pointers0And2 = removePointerIds(args, {1});
@@ -193,7 +192,7 @@
  * Remove all pointers during a MOVE event.
  */
 TEST(RemovePointerIdsTest, RemoveAllPointersDuringMove) {
-    NotifyMotionArgs args = generateMotionArgs(/*downTime*/ 0, /*eventTime*/ 0,
+    NotifyMotionArgs args = generateMotionArgs(/*downTime=*/0, /*eventTime=*/0,
                                                AMOTION_EVENT_ACTION_MOVE, {{1, 2, 3}, {4, 5, 6}});
 
     NotifyMotionArgs noPointers = removePointerIds(args, {0, 1});
@@ -205,7 +204,7 @@
  * then we should just have ACTION_DOWN. Likewise, a POINTER_UP event should become an UP event.
  */
 TEST(RemovePointerIdsTest, PointerDownBecomesDown) {
-    NotifyMotionArgs args = generateMotionArgs(/*downTime*/ 0, /*eventTime*/ 0, POINTER_1_DOWN,
+    NotifyMotionArgs args = generateMotionArgs(/*downTime=*/0, /*eventTime=*/0, POINTER_1_DOWN,
                                                {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}});
 
     NotifyMotionArgs pointer1 = removePointerIds(args, {0, 2});
@@ -220,11 +219,11 @@
  * If a pointer that is now going down is canceled, then we can just drop the POINTER_DOWN event.
  */
 TEST(CancelSuppressedPointersTest, CanceledPointerDownIsDropped) {
-    NotifyMotionArgs args = generateMotionArgs(/*downTime*/ 0, /*eventTime*/ 0, POINTER_1_DOWN,
+    NotifyMotionArgs args = generateMotionArgs(/*downTime=*/0, /*eventTime=*/0, POINTER_1_DOWN,
                                                {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}});
     std::vector<NotifyMotionArgs> result =
-            cancelSuppressedPointers(args, /*oldSuppressedPointerIds*/ {},
-                                     /*newSuppressedPointerIds*/ {1});
+            cancelSuppressedPointers(args, /*oldSuppressedPointerIds=*/{},
+                                     /*newSuppressedPointerIds=*/{1});
     ASSERT_TRUE(result.empty());
 }
 
@@ -232,11 +231,11 @@
  * If a pointer is already suppressed, the POINTER_UP event for this pointer should be dropped
  */
 TEST(CancelSuppressedPointersTest, SuppressedPointerUpIsDropped) {
-    NotifyMotionArgs args = generateMotionArgs(/*downTime*/ 0, /*eventTime*/ 0, POINTER_1_UP,
+    NotifyMotionArgs args = generateMotionArgs(/*downTime=*/0, /*eventTime=*/0, POINTER_1_UP,
                                                {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}});
     std::vector<NotifyMotionArgs> result =
-            cancelSuppressedPointers(args, /*oldSuppressedPointerIds*/ {1},
-                                     /*newSuppressedPointerIds*/ {1});
+            cancelSuppressedPointers(args, /*oldSuppressedPointerIds=*/{1},
+                                     /*newSuppressedPointerIds=*/{1});
     ASSERT_TRUE(result.empty());
 }
 
@@ -244,11 +243,11 @@
  * If a pointer is already suppressed, it should be removed from a MOVE event.
  */
 TEST(CancelSuppressedPointersTest, SuppressedPointerIsRemovedDuringMove) {
-    NotifyMotionArgs args = generateMotionArgs(/*downTime*/ 0, /*eventTime*/ 0, MOVE,
+    NotifyMotionArgs args = generateMotionArgs(/*downTime=*/0, /*eventTime=*/0, MOVE,
                                                {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}});
     std::vector<NotifyMotionArgs> result =
-            cancelSuppressedPointers(args, /*oldSuppressedPointerIds*/ {1},
-                                     /*newSuppressedPointerIds*/ {1});
+            cancelSuppressedPointers(args, /*oldSuppressedPointerIds=*/{1},
+                                     /*newSuppressedPointerIds=*/{1});
     ASSERT_EQ(1u, result.size());
     assertArgs(result[0], MOVE, {{0, {1, 2, 3}}, {2, {7, 8, 9}}});
 }
@@ -259,11 +258,11 @@
  * 2) A MOVE event without this pointer
  */
 TEST(CancelSuppressedPointersTest, NewlySuppressedPointerIsCanceled) {
-    NotifyMotionArgs args = generateMotionArgs(/*downTime*/ 0, /*eventTime*/ 0, MOVE,
+    NotifyMotionArgs args = generateMotionArgs(/*downTime=*/0, /*eventTime=*/0, MOVE,
                                                {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}});
     std::vector<NotifyMotionArgs> result =
-            cancelSuppressedPointers(args, /*oldSuppressedPointerIds*/ {},
-                                     /*newSuppressedPointerIds*/ {1});
+            cancelSuppressedPointers(args, /*oldSuppressedPointerIds=*/{},
+                                     /*newSuppressedPointerIds=*/{1});
     ASSERT_EQ(2u, result.size());
     assertArgs(result[0], POINTER_1_UP, {{0, {1, 2, 3}}, {1, {4, 5, 6}}, {2, {7, 8, 9}}});
     ASSERT_EQ(FLAG_CANCELED, result[0].flags);
@@ -275,10 +274,10 @@
  * should be canceled with ACTION_CANCEL.
  */
 TEST(CancelSuppressedPointersTest, SingleSuppressedPointerIsCanceled) {
-    NotifyMotionArgs args = generateMotionArgs(/*downTime*/ 0, /*eventTime*/ 0, MOVE, {{1, 2, 3}});
+    NotifyMotionArgs args = generateMotionArgs(/*downTime=*/0, /*eventTime=*/0, MOVE, {{1, 2, 3}});
     std::vector<NotifyMotionArgs> result =
-            cancelSuppressedPointers(args, /*oldSuppressedPointerIds*/ {},
-                                     /*newSuppressedPointerIds*/ {0});
+            cancelSuppressedPointers(args, /*oldSuppressedPointerIds=*/{},
+                                     /*newSuppressedPointerIds=*/{0});
     ASSERT_EQ(1u, result.size());
     assertArgs(result[0], CANCEL, {{0, {1, 2, 3}}});
     ASSERT_EQ(FLAG_CANCELED, result[0].flags);
@@ -289,11 +288,11 @@
  * but this event should also have FLAG_CANCELED to indicate that this pointer was unintentional.
  */
 TEST(CancelSuppressedPointersTest, SuppressedPointer1GoingUpIsCanceled) {
-    NotifyMotionArgs args = generateMotionArgs(/*downTime*/ 0, /*eventTime*/ 0, POINTER_1_UP,
+    NotifyMotionArgs args = generateMotionArgs(/*downTime=*/0, /*eventTime=*/0, POINTER_1_UP,
                                                {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}});
     std::vector<NotifyMotionArgs> result =
-            cancelSuppressedPointers(args, /*oldSuppressedPointerIds*/ {},
-                                     /*newSuppressedPointerIds*/ {1});
+            cancelSuppressedPointers(args, /*oldSuppressedPointerIds=*/{},
+                                     /*newSuppressedPointerIds=*/{1});
     ASSERT_EQ(1u, result.size());
     assertArgs(result[0], POINTER_1_UP, {{0, {1, 2, 3}}, {1, {4, 5, 6}}, {2, {7, 8, 9}}});
     ASSERT_EQ(FLAG_CANCELED, result[0].flags);
@@ -304,11 +303,11 @@
  * errors with handling pointer index inside the action.
  */
 TEST(CancelSuppressedPointersTest, SuppressedPointer0GoingUpIsCanceled) {
-    NotifyMotionArgs args = generateMotionArgs(/*downTime*/ 0, /*eventTime*/ 0, POINTER_0_UP,
+    NotifyMotionArgs args = generateMotionArgs(/*downTime=*/0, /*eventTime=*/0, POINTER_0_UP,
                                                {{1, 2, 3}, {4, 5, 6}});
     std::vector<NotifyMotionArgs> result =
-            cancelSuppressedPointers(args, /*oldSuppressedPointerIds*/ {},
-                                     /*newSuppressedPointerIds*/ {0});
+            cancelSuppressedPointers(args, /*oldSuppressedPointerIds=*/{},
+                                     /*newSuppressedPointerIds=*/{0});
     ASSERT_EQ(1u, result.size());
     assertArgs(result[0], POINTER_0_UP, {{0, {1, 2, 3}}, {1, {4, 5, 6}}});
     ASSERT_EQ(FLAG_CANCELED, result[0].flags);
@@ -320,10 +319,10 @@
  */
 TEST(CancelSuppressedPointersTest, TwoNewlySuppressedPointersAreBothCanceled) {
     NotifyMotionArgs args =
-            generateMotionArgs(/*downTime*/ 0, /*eventTime*/ 0, MOVE, {{1, 2, 3}, {4, 5, 6}});
+            generateMotionArgs(/*downTime=*/0, /*eventTime=*/0, MOVE, {{1, 2, 3}, {4, 5, 6}});
     std::vector<NotifyMotionArgs> result =
-            cancelSuppressedPointers(args, /*oldSuppressedPointerIds*/ {},
-                                     /*newSuppressedPointerIds*/ {0, 1});
+            cancelSuppressedPointers(args, /*oldSuppressedPointerIds=*/{},
+                                     /*newSuppressedPointerIds=*/{0, 1});
     ASSERT_EQ(1u, result.size());
     assertArgs(result[0], CANCEL, {{0, {1, 2, 3}}, {1, {4, 5, 6}}});
     ASSERT_EQ(FLAG_CANCELED, result[0].flags);
@@ -335,11 +334,11 @@
  * would undo the entire gesture.
  */
 TEST(CancelSuppressedPointersTest, TwoPointersAreCanceledDuringPointerUp) {
-    NotifyMotionArgs args = generateMotionArgs(/*downTime*/ 0, /*eventTime*/ 0, POINTER_1_UP,
+    NotifyMotionArgs args = generateMotionArgs(/*downTime=*/0, /*eventTime=*/0, POINTER_1_UP,
                                                {{1, 2, 3}, {4, 5, 6}});
     std::vector<NotifyMotionArgs> result =
-            cancelSuppressedPointers(args, /*oldSuppressedPointerIds*/ {1},
-                                     /*newSuppressedPointerIds*/ {0, 1});
+            cancelSuppressedPointers(args, /*oldSuppressedPointerIds=*/{1},
+                                     /*newSuppressedPointerIds=*/{0, 1});
     ASSERT_EQ(1u, result.size());
     assertArgs(result[0], CANCEL, {{0, {1, 2, 3}}});
     ASSERT_EQ(FLAG_CANCELED, result[0].flags);
@@ -350,11 +349,11 @@
  * this should become a regular DOWN event because it's the only pointer that will be valid now.
  */
 TEST(CancelSuppressedPointersTest, NewPointerDownBecomesDown) {
-    NotifyMotionArgs args = generateMotionArgs(/*downTime*/ 0, /*eventTime*/ 0, POINTER_2_DOWN,
+    NotifyMotionArgs args = generateMotionArgs(/*downTime=*/0, /*eventTime=*/0, POINTER_2_DOWN,
                                                {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}});
     std::vector<NotifyMotionArgs> result =
-            cancelSuppressedPointers(args, /*oldSuppressedPointerIds*/ {0, 1},
-                                     /*newSuppressedPointerIds*/ {0, 1});
+            cancelSuppressedPointers(args, /*oldSuppressedPointerIds=*/{0, 1},
+                                     /*newSuppressedPointerIds=*/{0, 1});
     ASSERT_EQ(1u, result.size());
     assertArgs(result[0], DOWN, {{2, {7, 8, 9}}});
     ASSERT_EQ(0, result[0].flags);
@@ -365,7 +364,7 @@
  * struct is populated as expected.
  */
 TEST(GetTouchesTest, ConvertDownEvent) {
-    NotifyMotionArgs args = generateMotionArgs(/*downTime*/ 0, /*eventTime*/ 0, DOWN, {{1, 2, 3}});
+    NotifyMotionArgs args = generateMotionArgs(/*downTime=*/0, /*eventTime=*/0, DOWN, {{1, 2, 3}});
     AndroidPalmFilterDeviceInfo deviceInfo = generatePalmFilterDeviceInfo();
     SlotState slotState;
     SlotState oldSlotState = slotState;
@@ -1024,7 +1023,7 @@
     mPalmRejector->processMotion(
             generateMotionArgs(downTime, downTime, DOWN, {{1342.0, 613.0, 79.0}}));
     mPalmRejector->processMotion(
-            generateMotionArgs(downTime, /*eventTime*/ 1, POINTER_1_DOWN,
+            generateMotionArgs(downTime, /*eventTime=*/1, POINTER_1_DOWN,
                                {{1417.0, 685.0, 41.0}, {1062.0, 697.0, 10.0}}));
     // Suppress both pointers!!
     suppressPointerAtPosition(1414, 702);
@@ -1058,13 +1057,13 @@
     mPalmRejector->processMotion(
             generateMotionArgs(downTime, downTime, DOWN, {{1342.0, 613.0, 79.0}}));
     mPalmRejector->processMotion(
-            generateMotionArgs(downTime, /*eventTime*/ 1, POINTER_1_DOWN,
+            generateMotionArgs(downTime, /*eventTime=*/1, POINTER_1_DOWN,
                                {{1417.0, 685.0, 41.0}, {1062.0, 697.0, 10.0}}));
 
     // Suppress second pointer (pointer 1)
     suppressPointerAtPosition(1060, 700);
     argsList = mPalmRejector->processMotion(
-            generateMotionArgs(downTime, /*eventTime*/ 1, MOVE,
+            generateMotionArgs(downTime, /*eventTime=*/1, MOVE,
                                {{1417.0, 685.0, 41.0}, {1060, 700, 10.0}}));
     ASSERT_EQ(2u, argsList.size());
     ASSERT_EQ(POINTER_1_UP, argsList[0].action);
@@ -1076,20 +1075,20 @@
     // A new pointer goes down and gets suppressed right away. It should just be dropped
     suppressPointerAtPosition(1001, 601);
     argsList = mPalmRejector->processMotion(
-            generateMotionArgs(downTime, /*eventTime*/ 1, POINTER_2_DOWN,
+            generateMotionArgs(downTime, /*eventTime=*/1, POINTER_2_DOWN,
                                {{1417.0, 685.0, 41.0}, {1062.0, 697.0, 10.0}, {1001, 601, 5}}));
 
     ASSERT_EQ(0u, argsList.size());
     // Likewise, pointer that's already canceled should be ignored
     argsList = mPalmRejector->processMotion(
-            generateMotionArgs(downTime, /*eventTime*/ 1, POINTER_2_UP,
+            generateMotionArgs(downTime, /*eventTime=*/1, POINTER_2_UP,
                                {{1417.0, 685.0, 41.0}, {1062.0, 697.0, 10.0}, {1001, 601, 5}}));
     ASSERT_EQ(0u, argsList.size());
 
     // Cancel all pointers when pointer 1 goes up. Pointer 1 was already canceled earlier.
     suppressPointerAtPosition(1417, 685);
     argsList = mPalmRejector->processMotion(
-            generateMotionArgs(downTime, /*eventTime*/ 1, POINTER_1_UP,
+            generateMotionArgs(downTime, /*eventTime=*/1, POINTER_1_UP,
                                {{1417.0, 685.0, 41.0}, {1062.0, 697.0, 10.0}}));
     ASSERT_EQ(1u, argsList.size());
     ASSERT_EQ(CANCEL, argsList[0].action);
diff --git a/services/inputflinger/tests/fuzzers/Android.bp b/services/inputflinger/tests/fuzzers/Android.bp
index 47b0824..d7980f5 100644
--- a/services/inputflinger/tests/fuzzers/Android.bp
+++ b/services/inputflinger/tests/fuzzers/Android.bp
@@ -100,6 +100,22 @@
 }
 
 cc_fuzz {
+    name: "inputflinger_touchpad_input_fuzzer",
+    defaults: [
+        "inputflinger_fuzz_defaults",
+    ],
+    srcs: [
+        "TouchpadInputFuzzer.cpp",
+    ],
+    static_libs: [
+        "libchrome-gestures",
+    ],
+    header_libs: [
+        "libchrome-gestures_headers",
+    ],
+}
+
+cc_fuzz {
     name: "inputflinger_input_reader_fuzzer",
     defaults: [
         "inputflinger_fuzz_defaults",
diff --git a/services/inputflinger/tests/fuzzers/CursorInputFuzzer.cpp b/services/inputflinger/tests/fuzzers/CursorInputFuzzer.cpp
index 993f6a8..e93b592 100644
--- a/services/inputflinger/tests/fuzzers/CursorInputFuzzer.cpp
+++ b/services/inputflinger/tests/fuzzers/CursorInputFuzzer.cpp
@@ -16,6 +16,7 @@
 
 #include <CursorInputMapper.h>
 #include <FuzzContainer.h>
+#include <InputReaderBase.h>
 #include <MapperHelpers.h>
 
 namespace android {
@@ -39,7 +40,7 @@
             std::make_shared<ThreadSafeFuzzedDataProvider>(data, size);
     FuzzContainer fuzzer(fdp);
 
-    auto policyConfig = fuzzer.getPolicyConfig();
+    InputReaderConfiguration policyConfig;
     CursorInputMapper& mapper = fuzzer.getMapper<CursorInputMapper>(policyConfig);
 
     // Loop through mapper operations until randomness is exhausted.
diff --git a/services/inputflinger/tests/fuzzers/FuzzContainer.h b/services/inputflinger/tests/fuzzers/FuzzContainer.h
index fd14e02..ade5328 100644
--- a/services/inputflinger/tests/fuzzers/FuzzContainer.h
+++ b/services/inputflinger/tests/fuzzers/FuzzContainer.h
@@ -25,11 +25,9 @@
 
 class FuzzContainer {
     std::shared_ptr<FuzzEventHub> mFuzzEventHub;
-    sp<FuzzInputReaderPolicy> mFuzzPolicy;
     FuzzInputListener mFuzzListener;
     std::unique_ptr<FuzzInputReaderContext> mFuzzContext;
     std::unique_ptr<InputDevice> mFuzzDevice;
-    InputReaderConfiguration mPolicyConfig;
     std::shared_ptr<ThreadSafeFuzzedDataProvider> mFdp;
 
 public:
@@ -42,8 +40,8 @@
 
         // Create mocked objects.
         mFuzzEventHub = std::make_shared<FuzzEventHub>(mFdp);
-        mFuzzPolicy = sp<FuzzInputReaderPolicy>::make(mFdp);
-        mFuzzContext = std::make_unique<FuzzInputReaderContext>(mFuzzEventHub, mFuzzPolicy,
+        sp<FuzzInputReaderPolicy> policy = sp<FuzzInputReaderPolicy>::make(mFdp);
+        mFuzzContext = std::make_unique<FuzzInputReaderContext>(mFuzzEventHub, policy,
                                                                 mFuzzListener, mFdp);
 
         InputDeviceIdentifier identifier;
@@ -51,7 +49,6 @@
         identifier.location = deviceLocation;
         mFuzzDevice = std::make_unique<InputDevice>(mFuzzContext.get(), deviceID, deviceGeneration,
                                                     identifier);
-        mFuzzPolicy->getReaderConfiguration(&mPolicyConfig);
     }
 
     ~FuzzContainer() {}
@@ -59,7 +56,7 @@
     void configureDevice() {
         nsecs_t arbitraryTime = mFdp->ConsumeIntegral<nsecs_t>();
         std::list<NotifyArgs> out;
-        out += mFuzzDevice->configure(arbitraryTime, mPolicyConfig, /*changes=*/{});
+        out += mFuzzDevice->configure(arbitraryTime, /*readerConfig=*/{}, /*changes=*/{});
         out += mFuzzDevice->reset(arbitraryTime);
         for (const NotifyArgs& args : out) {
             mFuzzListener.notify(args);
@@ -71,7 +68,9 @@
         configureDevice();
     }
 
-    InputReaderConfiguration& getPolicyConfig() { return mPolicyConfig; }
+    void setAbsoluteAxisInfo(int axis, const RawAbsoluteAxisInfo& axisInfo) {
+        mFuzzEventHub->setAbsoluteAxisInfo(mFuzzDevice->getId(), axis, axisInfo);
+    }
 
     template <class T, typename... Args>
     T& getMapper(Args... args) {
diff --git a/services/inputflinger/tests/fuzzers/KeyboardInputFuzzer.cpp b/services/inputflinger/tests/fuzzers/KeyboardInputFuzzer.cpp
index d11e8ae..54977df 100644
--- a/services/inputflinger/tests/fuzzers/KeyboardInputFuzzer.cpp
+++ b/services/inputflinger/tests/fuzzers/KeyboardInputFuzzer.cpp
@@ -15,6 +15,7 @@
  */
 
 #include <FuzzContainer.h>
+#include <InputReaderBase.h>
 #include <KeyboardInputMapper.h>
 #include <MapperHelpers.h>
 
@@ -45,9 +46,9 @@
             std::make_shared<ThreadSafeFuzzedDataProvider>(data, size);
     FuzzContainer fuzzer(fdp);
 
-    auto policyConfig = fuzzer.getPolicyConfig();
     KeyboardInputMapper& mapper =
-            fuzzer.getMapper<KeyboardInputMapper>(policyConfig, fdp->ConsumeIntegral<uint32_t>(),
+            fuzzer.getMapper<KeyboardInputMapper>(InputReaderConfiguration{},
+                                                  fdp->ConsumeIntegral<uint32_t>(),
                                                   fdp->ConsumeIntegral<int32_t>());
 
     // Loop through mapper operations until randomness is exhausted.
@@ -65,7 +66,7 @@
                 [&]() -> void { mapper.getSources(); },
                 [&]() -> void {
                     std::list<NotifyArgs> unused =
-                            mapper.reconfigure(fdp->ConsumeIntegral<nsecs_t>(), policyConfig,
+                            mapper.reconfigure(fdp->ConsumeIntegral<nsecs_t>(), /*readerConfig=*/{},
                                                InputReaderConfiguration::Change(
                                                        fdp->ConsumeIntegral<uint32_t>()));
                 },
diff --git a/services/inputflinger/tests/fuzzers/MapperHelpers.h b/services/inputflinger/tests/fuzzers/MapperHelpers.h
index 4a2c98c..5039d1a 100644
--- a/services/inputflinger/tests/fuzzers/MapperHelpers.h
+++ b/services/inputflinger/tests/fuzzers/MapperHelpers.h
@@ -15,6 +15,9 @@
  */
 #pragma once
 
+#include <map>
+
+#include <EventHub.h>
 #include <InputDevice.h>
 #include <InputMapper.h>
 #include <InputReader.h>
@@ -92,6 +95,7 @@
     InputDeviceIdentifier mIdentifier;
     std::vector<TouchVideoFrame> mVideoFrames;
     PropertyMap mFuzzConfig;
+    std::map<int32_t /* deviceId */, std::map<int /* axis */, RawAbsoluteAxisInfo>> mAxes;
     std::shared_ptr<ThreadSafeFuzzedDataProvider> mFdp;
 
 public:
@@ -111,8 +115,18 @@
     std::optional<PropertyMap> getConfiguration(int32_t deviceId) const override {
         return mFuzzConfig;
     }
+    void setAbsoluteAxisInfo(int32_t deviceId, int axis, const RawAbsoluteAxisInfo& axisInfo) {
+        mAxes[deviceId][axis] = axisInfo;
+    }
     status_t getAbsoluteAxisInfo(int32_t deviceId, int axis,
                                  RawAbsoluteAxisInfo* outAxisInfo) const override {
+        if (auto deviceAxesIt = mAxes.find(deviceId); deviceAxesIt != mAxes.end()) {
+            const std::map<int, RawAbsoluteAxisInfo>& deviceAxes = deviceAxesIt->second;
+            if (auto axisInfoIt = deviceAxes.find(axis); axisInfoIt != deviceAxes.end()) {
+                *outAxisInfo = axisInfoIt->second;
+                return OK;
+            }
+        }
         return mFdp->ConsumeIntegral<status_t>();
     }
     bool hasRelativeAxis(int32_t deviceId, int axis) const override { return mFdp->ConsumeBool(); }
diff --git a/services/inputflinger/tests/fuzzers/MultiTouchInputFuzzer.cpp b/services/inputflinger/tests/fuzzers/MultiTouchInputFuzzer.cpp
index 494b0ef..569767f 100644
--- a/services/inputflinger/tests/fuzzers/MultiTouchInputFuzzer.cpp
+++ b/services/inputflinger/tests/fuzzers/MultiTouchInputFuzzer.cpp
@@ -15,6 +15,7 @@
  */
 
 #include <FuzzContainer.h>
+#include <InputReaderBase.h>
 #include <MapperHelpers.h>
 #include <MultiTouchInputMapper.h>
 
@@ -62,7 +63,7 @@
             std::make_shared<ThreadSafeFuzzedDataProvider>(data, size);
     FuzzContainer fuzzer(fdp);
 
-    auto policyConfig = fuzzer.getPolicyConfig();
+    InputReaderConfiguration policyConfig;
     MultiTouchInputMapper& mapper = fuzzer.getMapper<MultiTouchInputMapper>(policyConfig);
 
     // Loop through mapper operations until randomness is exhausted.
diff --git a/services/inputflinger/tests/fuzzers/SwitchInputFuzzer.cpp b/services/inputflinger/tests/fuzzers/SwitchInputFuzzer.cpp
index 381e7b5..80eebd5 100644
--- a/services/inputflinger/tests/fuzzers/SwitchInputFuzzer.cpp
+++ b/services/inputflinger/tests/fuzzers/SwitchInputFuzzer.cpp
@@ -15,6 +15,7 @@
  */
 
 #include <FuzzContainer.h>
+#include <InputReaderBase.h>
 #include <MapperHelpers.h>
 #include <SwitchInputMapper.h>
 
@@ -25,8 +26,7 @@
             std::make_shared<ThreadSafeFuzzedDataProvider>(data, size);
     FuzzContainer fuzzer(fdp);
 
-    auto policyConfig = fuzzer.getPolicyConfig();
-    SwitchInputMapper& mapper = fuzzer.getMapper<SwitchInputMapper>(policyConfig);
+    SwitchInputMapper& mapper = fuzzer.getMapper<SwitchInputMapper>(InputReaderConfiguration{});
 
     // Loop through mapper operations until randomness is exhausted.
     while (fdp->remaining_bytes() > 0) {
diff --git a/services/inputflinger/tests/fuzzers/TouchpadInputFuzzer.cpp b/services/inputflinger/tests/fuzzers/TouchpadInputFuzzer.cpp
new file mode 100644
index 0000000..796178a
--- /dev/null
+++ b/services/inputflinger/tests/fuzzers/TouchpadInputFuzzer.cpp
@@ -0,0 +1,177 @@
+/*
+ * 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 <limits>
+#include <string>
+#include <vector>
+
+#include <linux/input-event-codes.h>
+
+#include <FuzzContainer.h>
+#include <InputReaderBase.h>
+#include <MapperHelpers.h>
+#include <TouchpadInputMapper.h>
+
+namespace android {
+
+namespace {
+
+void setAxisInfo(ThreadSafeFuzzedDataProvider& fdp, FuzzContainer& fuzzer, int axis) {
+    if (fdp.ConsumeBool()) {
+        fuzzer.setAbsoluteAxisInfo(axis,
+                                   RawAbsoluteAxisInfo{
+                                           .valid = fdp.ConsumeBool(),
+                                           .minValue = fdp.ConsumeIntegral<int32_t>(),
+                                           .maxValue = fdp.ConsumeIntegral<int32_t>(),
+                                           .flat = fdp.ConsumeIntegral<int32_t>(),
+                                           .fuzz = fdp.ConsumeIntegral<int32_t>(),
+                                           .resolution = fdp.ConsumeIntegral<int32_t>(),
+                                   });
+    }
+}
+
+void setAxisInfos(ThreadSafeFuzzedDataProvider& fdp, FuzzContainer& fuzzer) {
+    setAxisInfo(fdp, fuzzer, ABS_MT_SLOT);
+    setAxisInfo(fdp, fuzzer, ABS_MT_POSITION_X);
+    setAxisInfo(fdp, fuzzer, ABS_MT_POSITION_Y);
+    setAxisInfo(fdp, fuzzer, ABS_MT_PRESSURE);
+    setAxisInfo(fdp, fuzzer, ABS_MT_ORIENTATION);
+    setAxisInfo(fdp, fuzzer, ABS_MT_TOUCH_MAJOR);
+    setAxisInfo(fdp, fuzzer, ABS_MT_TOUCH_MINOR);
+    setAxisInfo(fdp, fuzzer, ABS_MT_WIDTH_MAJOR);
+    setAxisInfo(fdp, fuzzer, ABS_MT_WIDTH_MINOR);
+}
+
+const std::vector<std::string> boolPropertiesToFuzz = {
+        "gestureProp.Compute_Surface_Area_from_Pressure",
+        "gestureProp.Drumroll_Suppression_Enable",
+        "gestureProp.Fling_Buffer_Suppress_Zero_Length_Scrolls",
+        "gestureProp.Stationary_Wiggle_Filter_Enabled",
+};
+const std::vector<std::string> doublePropertiesToFuzz = {
+        "gestureProp.Fake_Timestamp_Delta",
+        "gestureProp.Finger_Moving_Energy",
+        "gestureProp.Finger_Moving_Hysteresis",
+        "gestureProp.IIR_a1",
+        "gestureProp.IIR_a2",
+        "gestureProp.IIR_b0",
+        "gestureProp.IIR_b1",
+        "gestureProp.IIR_b2",
+        "gestureProp.IIR_b3",
+        "gestureProp.Max_Allowed_Pressure_Change_Per_Sec",
+        "gestureProp.Max_Hysteresis_Pressure_Per_Sec",
+        "gestureProp.Max_Stationary_Move_Speed",
+        "gestureProp.Max_Stationary_Move_Speed_Hysteresis",
+        "gestureProp.Max_Stationary_Move_Suppress_Distance",
+        "gestureProp.Multiple_Palm_Width",
+        "gestureProp.Palm_Edge_Zone_Width",
+        "gestureProp.Palm_Eval_Timeout",
+        "gestureProp.Palm_Pressure",
+        "gestureProp.Palm_Width",
+        "gestureProp.Pressure_Calibration_Offset",
+        "gestureProp.Pressure_Calibration_Slope",
+        "gestureProp.Tap_Exclusion_Border_Width",
+        "gestureProp.Touchpad_Device_Output_Bias_on_X-Axis",
+        "gestureProp.Touchpad_Device_Output_Bias_on_Y-Axis",
+        "gestureProp.Two_Finger_Vertical_Close_Distance_Thresh",
+};
+
+void setDeviceSpecificConfig(ThreadSafeFuzzedDataProvider& fdp, FuzzContainer& fuzzer) {
+    // There are a great many gesture properties offered by the Gestures library, all of which could
+    // potentially be set in Input Device Configuration files. Maintaining a complete list is
+    // impractical, so instead we only fuzz properties which are used in at least one IDC file, or
+    // which are likely to be used in future (e.g. ones for controlling palm rejection).
+
+    if (fdp.ConsumeBool()) {
+        fuzzer.addProperty("gestureProp.Touchpad_Stack_Version",
+                           std::to_string(fdp.ConsumeIntegral<int>()));
+    }
+
+    for (auto& propertyName : boolPropertiesToFuzz) {
+        if (fdp.ConsumeBool()) {
+            fuzzer.addProperty(propertyName, fdp.ConsumeBool() ? "1" : "0");
+        }
+    }
+
+    for (auto& propertyName : doublePropertiesToFuzz) {
+        if (fdp.ConsumeBool()) {
+            fuzzer.addProperty(propertyName, std::to_string(fdp.ConsumeFloatingPoint<double>()));
+        }
+    }
+
+    if (fdp.ConsumeBool()) {
+        fuzzer.addProperty("gestureProp." + fdp.ConsumeRandomLengthString(),
+                           std::to_string(fdp.ConsumeIntegral<int>()));
+    }
+}
+
+void setTouchpadSettings(ThreadSafeFuzzedDataProvider& fdp, InputReaderConfiguration& config) {
+    config.touchpadPointerSpeed = fdp.ConsumeIntegralInRange(-7, 7);
+    config.touchpadNaturalScrollingEnabled = fdp.ConsumeBool();
+    config.touchpadTapToClickEnabled = fdp.ConsumeBool();
+    config.touchpadRightClickZoneEnabled = fdp.ConsumeBool();
+}
+
+} // namespace
+
+extern "C" int LLVMFuzzerTestOneInput(uint8_t* data, size_t size) {
+    std::shared_ptr<ThreadSafeFuzzedDataProvider> fdp =
+            std::make_shared<ThreadSafeFuzzedDataProvider>(data, size);
+    FuzzContainer fuzzer(fdp);
+    setAxisInfos(*fdp, fuzzer);
+    setDeviceSpecificConfig(*fdp, fuzzer);
+
+    InputReaderConfiguration policyConfig;
+    // Some settings are fuzzed here, as well as in the main loop, to provide randomized data to the
+    // TouchpadInputMapper constructor.
+    setTouchpadSettings(*fdp, policyConfig);
+    policyConfig.pointerCaptureRequest.enable = fdp->ConsumeBool();
+    TouchpadInputMapper& mapper = fuzzer.getMapper<TouchpadInputMapper>(policyConfig);
+
+    // Loop through mapper operations until randomness is exhausted.
+    while (fdp->remaining_bytes() > 0) {
+        fdp->PickValueInArray<std::function<void()>>({
+                [&]() -> void {
+                    std::string dump;
+                    mapper.dump(dump);
+                },
+                [&]() -> void {
+                    InputDeviceInfo info;
+                    mapper.populateDeviceInfo(info);
+                },
+                [&]() -> void { mapper.getSources(); },
+                [&]() -> void {
+                    setTouchpadSettings(*fdp, policyConfig);
+                    policyConfig.pointerCaptureRequest.enable = fdp->ConsumeBool();
+                    std::list<NotifyArgs> unused =
+                            mapper.reconfigure(fdp->ConsumeIntegral<nsecs_t>(), policyConfig,
+                                               InputReaderConfiguration::Change(
+                                                       fdp->ConsumeIntegral<uint32_t>()));
+                },
+                [&]() -> void {
+                    std::list<NotifyArgs> unused = mapper.reset(fdp->ConsumeIntegral<nsecs_t>());
+                },
+                [&]() -> void {
+                    RawEvent event = getFuzzedRawEvent(*fdp);
+                    std::list<NotifyArgs> unused = mapper.process(&event);
+                },
+        })();
+    }
+
+    return 0;
+}
+
+} // namespace android
diff --git a/services/sensorservice/tests/sensorservicetest.cpp b/services/sensorservice/tests/sensorservicetest.cpp
index b00d1a7..e939d51 100644
--- a/services/sensorservice/tests/sensorservicetest.cpp
+++ b/services/sensorservice/tests/sensorservicetest.cpp
@@ -141,7 +141,7 @@
                 printf("ALOOPER_POLL_TIMEOUT\n");
                 break;
             case ALOOPER_POLL_ERROR:
-                printf("ALOOPER_POLL_TIMEOUT\n");
+                printf("ALOOPER_POLL_ERROR\n");
                 break;
             default:
                 printf("ugh? poll returned %d\n", ret);
diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp
index 281b0ae..c70ed2c 100644
--- a/services/surfaceflinger/Scheduler/EventThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventThread.cpp
@@ -427,11 +427,6 @@
     mCondition.notify_all();
 }
 
-size_t EventThread::getEventThreadConnectionCount() {
-    std::lock_guard<std::mutex> lock(mMutex);
-    return mDisplayEventConnections.size();
-}
-
 void EventThread::threadMain(std::unique_lock<std::mutex>& lock) {
     DisplayEventConsumers consumers;
 
diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h
index 684745b..7023445 100644
--- a/services/surfaceflinger/Scheduler/EventThread.h
+++ b/services/surfaceflinger/Scheduler/EventThread.h
@@ -131,9 +131,6 @@
     virtual VsyncEventData getLatestVsyncEventData(
             const sp<EventThreadConnection>& connection) const = 0;
 
-    // Retrieves the number of event connections tracked by this EventThread.
-    virtual size_t getEventThreadConnectionCount() = 0;
-
     virtual void onNewVsyncSchedule(std::shared_ptr<scheduler::VsyncSchedule>) = 0;
 };
 
@@ -172,8 +169,6 @@
     void setDuration(std::chrono::nanoseconds workDuration,
                      std::chrono::nanoseconds readyDuration) override;
 
-    size_t getEventThreadConnectionCount() override;
-
     void onNewVsyncSchedule(std::shared_ptr<scheduler::VsyncSchedule>) override EXCLUDES(mMutex);
 
 private:
diff --git a/services/surfaceflinger/Scheduler/ISchedulerCallback.h b/services/surfaceflinger/Scheduler/ISchedulerCallback.h
index badbf53..3b61de7 100644
--- a/services/surfaceflinger/Scheduler/ISchedulerCallback.h
+++ b/services/surfaceflinger/Scheduler/ISchedulerCallback.h
@@ -29,6 +29,7 @@
     virtual void requestDisplayModes(std::vector<display::DisplayModeRequest>) = 0;
     virtual void kernelTimerChanged(bool expired) = 0;
     virtual void triggerOnFrameRateOverridesChanged() = 0;
+    virtual void onChoreographerAttached() = 0;
 
 protected:
     ~ISchedulerCallback() = default;
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp
index beaf972..5d00a26 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.cpp
+++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp
@@ -131,22 +131,6 @@
     const auto& info = layerPair->second;
     info->setLastPresentTime(presentTime, now, updateType, mModeChangePending, layerProps);
 
-    // Set frame rate to attached choreographer.
-    // TODO(b/260898223): Change to use layer hierarchy and handle frame rate vote.
-    if (updateType == LayerUpdateType::SetFrameRate) {
-        auto range = mAttachedChoreographers.equal_range(id);
-        auto it = range.first;
-        while (it != range.second) {
-            sp<EventThreadConnection> choreographerConnection = it->second.promote();
-            if (choreographerConnection) {
-                choreographerConnection->frameRate = layerProps.setFrameRateVote.rate;
-                it++;
-            } else {
-                it = mAttachedChoreographers.erase(it);
-            }
-        }
-    }
-
     // Activate layer if inactive.
     if (found == LayerStatus::LayerInInactiveMap) {
         mActiveLayerInfos.insert(
@@ -301,12 +285,6 @@
     return 0.f;
 }
 
-void LayerHistory::attachChoreographer(int32_t layerId,
-                                       const sp<EventThreadConnection>& choreographerConnection) {
-    std::lock_guard lock(mLock);
-    mAttachedChoreographers.insert({layerId, wp<EventThreadConnection>(choreographerConnection)});
-}
-
 auto LayerHistory::findLayer(int32_t id) -> std::pair<LayerStatus, LayerPair*> {
     // the layer could be in either the active or inactive map, try both
     auto it = mActiveLayerInfos.find(id);
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.h b/services/surfaceflinger/Scheduler/LayerHistory.h
index 69caf9f..d083fa2 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.h
+++ b/services/surfaceflinger/Scheduler/LayerHistory.h
@@ -84,9 +84,6 @@
     // return the frames per second of the layer with the given sequence id.
     float getLayerFramerate(nsecs_t now, int32_t id) const;
 
-    void attachChoreographer(int32_t layerId,
-                             const sp<EventThreadConnection>& choreographerConnection);
-
 private:
     friend class LayerHistoryTest;
     friend class TestableScheduler;
@@ -124,10 +121,6 @@
     LayerInfos mActiveLayerInfos GUARDED_BY(mLock);
     LayerInfos mInactiveLayerInfos GUARDED_BY(mLock);
 
-    // Map keyed by layer ID (sequence) to choreographer connections.
-    std::unordered_multimap<int32_t, wp<EventThreadConnection>> mAttachedChoreographers
-            GUARDED_BY(mLock);
-
     uint32_t mDisplayArea = 0;
 
     // Whether to emit systrace output and debug logs.
diff --git a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
index f136e9f..7951c33 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
@@ -853,6 +853,8 @@
                                       return lhs < rhs && !ScoredFrameRate::scoresEqual(lhs, rhs);
                                   });
         ALOGV("%s: overriding to %s for uid=%d", __func__, to_string(overrideFps).c_str(), uid);
+        ATRACE_FORMAT_INSTANT("%s: overriding to %s for uid=%d", __func__,
+                              to_string(overrideFps).c_str(), uid);
         frameRateOverrides.emplace(uid, overrideFps);
     }
 
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 41639b6..08667bf 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -260,29 +260,40 @@
     const ConnectionHandle handle = ConnectionHandle{mNextConnectionHandleId++};
     ALOGV("Creating a connection handle with ID %" PRIuPTR, handle.id);
 
-    auto connection = createConnectionInternal(eventThread.get());
+    auto connection = eventThread->createEventConnection([&] { resync(); });
 
     std::lock_guard<std::mutex> lock(mConnectionsLock);
     mConnections.emplace(handle, Connection{connection, std::move(eventThread)});
     return handle;
 }
 
-sp<EventThreadConnection> Scheduler::createConnectionInternal(
-        EventThread* eventThread, EventRegistrationFlags eventRegistration,
-        const sp<IBinder>& layerHandle) {
-    int32_t layerId = static_cast<int32_t>(LayerHandle::getLayerId(layerHandle));
-    auto connection = eventThread->createEventConnection([&] { resync(); }, eventRegistration);
-    mLayerHistory.attachChoreographer(layerId, connection);
-    return connection;
-}
-
 sp<IDisplayEventConnection> Scheduler::createDisplayEventConnection(
         ConnectionHandle handle, EventRegistrationFlags eventRegistration,
         const sp<IBinder>& layerHandle) {
-    std::lock_guard<std::mutex> lock(mConnectionsLock);
-    RETURN_IF_INVALID_HANDLE(handle, nullptr);
-    return createConnectionInternal(mConnections[handle].thread.get(), eventRegistration,
-                                    layerHandle);
+    const auto connection = [&]() -> sp<EventThreadConnection> {
+        std::scoped_lock lock(mConnectionsLock);
+        RETURN_IF_INVALID_HANDLE(handle, nullptr);
+
+        return mConnections[handle].thread->createEventConnection([&] { resync(); },
+                                                                  eventRegistration);
+    }();
+    const auto layerId = static_cast<int32_t>(LayerHandle::getLayerId(layerHandle));
+
+    if (layerId != static_cast<int32_t>(UNASSIGNED_LAYER_ID)) {
+        // TODO(b/290409668): Moving the choreographer attachment to be a transaction that will be
+        // processed on the main thread.
+        mSchedulerCallback.onChoreographerAttached();
+
+        std::scoped_lock lock(mChoreographerLock);
+        const auto [iter, emplaced] =
+                mAttachedChoreographers.emplace(layerId,
+                                                AttachedChoreographers{Fps(), {connection}});
+        if (!emplaced) {
+            iter->second.connections.emplace(connection);
+            connection->frameRate = iter->second.frameRate;
+        }
+    }
+    return connection;
 }
 
 sp<EventThreadConnection> Scheduler::getEventConnection(ConnectionHandle handle) {
@@ -382,12 +393,6 @@
     thread->onModeChanged(mode);
 }
 
-size_t Scheduler::getEventThreadConnectionCount(ConnectionHandle handle) {
-    std::lock_guard<std::mutex> lock(mConnectionsLock);
-    RETURN_IF_INVALID_HANDLE(handle, 0);
-    return mConnections[handle].thread->getEventThreadConnectionCount();
-}
-
 void Scheduler::dump(ConnectionHandle handle, std::string& result) const {
     android::EventThread* thread;
     {
@@ -555,6 +560,11 @@
     mLayerHistory.deregisterLayer(layer);
 }
 
+void Scheduler::onLayerDestroyed(Layer* layer) {
+    std::scoped_lock lock(mChoreographerLock);
+    mAttachedChoreographers.erase(layer->getSequence());
+}
+
 void Scheduler::recordLayerHistory(int32_t id, const LayerProps& layerProps, nsecs_t presentTime,
                                    LayerHistory::LayerUpdateType updateType) {
     if (pacesetterSelectorPtr()->canSwitch()) {
@@ -571,7 +581,9 @@
                                                    mFeatures.test(Feature::kContentDetection));
 }
 
-void Scheduler::chooseRefreshRateForContent() {
+void Scheduler::chooseRefreshRateForContent(
+        const surfaceflinger::frontend::LayerHierarchy* hierarchy,
+        bool updateAttachedChoreographer) {
     const auto selectorPtr = pacesetterSelectorPtr();
     if (!selectorPtr->canSwitch()) return;
 
@@ -579,6 +591,20 @@
 
     LayerHistory::Summary summary = mLayerHistory.summarize(*selectorPtr, systemTime());
     applyPolicy(&Policy::contentRequirements, std::move(summary));
+
+    if (updateAttachedChoreographer) {
+        LOG_ALWAYS_FATAL_IF(!hierarchy);
+
+        // update the attached choreographers after we selected the render rate.
+        const ftl::Optional<FrameRateMode> modeOpt = [&] {
+            std::scoped_lock lock(mPolicyLock);
+            return mPolicy.modeOpt;
+        }();
+
+        if (modeOpt) {
+            updateAttachedChoreographers(*hierarchy, modeOpt->fps);
+        }
+    }
 }
 
 void Scheduler::resetIdleTimer() {
@@ -822,6 +848,105 @@
     mPolicy = {};
 }
 
+void Scheduler::updateAttachedChoreographersFrameRate(
+        const surfaceflinger::frontend::RequestedLayerState& layer, Fps fps) {
+    std::scoped_lock lock(mChoreographerLock);
+
+    const auto layerId = static_cast<int32_t>(layer.id);
+    const auto choreographers = mAttachedChoreographers.find(layerId);
+    if (choreographers == mAttachedChoreographers.end()) {
+        return;
+    }
+
+    auto& layerChoreographers = choreographers->second;
+
+    layerChoreographers.frameRate = fps;
+    ATRACE_FORMAT_INSTANT("%s: %s for %s", __func__, to_string(fps).c_str(), layer.name.c_str());
+    ALOGV("%s: %s for %s", __func__, to_string(fps).c_str(), layer.name.c_str());
+
+    auto it = layerChoreographers.connections.begin();
+    while (it != layerChoreographers.connections.end()) {
+        sp<EventThreadConnection> choreographerConnection = it->promote();
+        if (choreographerConnection) {
+            choreographerConnection->frameRate = fps;
+            it++;
+        } else {
+            it = choreographers->second.connections.erase(it);
+        }
+    }
+
+    if (layerChoreographers.connections.empty()) {
+        mAttachedChoreographers.erase(choreographers);
+    }
+}
+
+int Scheduler::updateAttachedChoreographersInternal(
+        const surfaceflinger::frontend::LayerHierarchy& layerHierarchy, Fps displayRefreshRate,
+        int parentDivisor) {
+    const char* name = layerHierarchy.getLayer() ? layerHierarchy.getLayer()->name.c_str() : "Root";
+
+    int divisor = 0;
+    if (layerHierarchy.getLayer()) {
+        const auto frameRateCompatibility = layerHierarchy.getLayer()->frameRateCompatibility;
+        const auto frameRate = Fps::fromValue(layerHierarchy.getLayer()->frameRate);
+        ALOGV("%s: %s frameRate %s parentDivisor=%d", __func__, name, to_string(frameRate).c_str(),
+              parentDivisor);
+
+        if (frameRate.isValid()) {
+            if (frameRateCompatibility == ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE ||
+                frameRateCompatibility == ANATIVEWINDOW_FRAME_RATE_EXACT) {
+                // Since this layer wants an exact match, we would only set a frame rate if the
+                // desired rate is a divisor of the display refresh rate.
+                divisor = RefreshRateSelector::getFrameRateDivisor(displayRefreshRate, frameRate);
+            } else if (frameRateCompatibility == ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT) {
+                // find the closest frame rate divisor for the desired frame rate.
+                divisor = static_cast<int>(
+                        std::round(displayRefreshRate.getValue() / frameRate.getValue()));
+            }
+        }
+    }
+
+    // We start by traversing the children, updating their choreographers, and getting back the
+    // aggregated frame rate.
+    int childrenDivisor = 0;
+    for (const auto& [child, _] : layerHierarchy.mChildren) {
+        LOG_ALWAYS_FATAL_IF(child == nullptr || child->getLayer() == nullptr);
+
+        ALOGV("%s: %s traversing child %s", __func__, name, child->getLayer()->name.c_str());
+
+        const int childDivisor =
+                updateAttachedChoreographersInternal(*child, displayRefreshRate, divisor);
+        childrenDivisor = childrenDivisor > 0 ? childrenDivisor : childDivisor;
+        if (childDivisor > 0) {
+            childrenDivisor = std::gcd(childrenDivisor, childDivisor);
+        }
+        ALOGV("%s: %s childrenDivisor=%d", __func__, name, childrenDivisor);
+    }
+
+    ALOGV("%s: %s divisor=%d", __func__, name, divisor);
+
+    // If there is no explicit vote for this layer. Use the children's vote if exists
+    divisor = (divisor == 0) ? childrenDivisor : divisor;
+    ALOGV("%s: %s divisor=%d with children", __func__, name, divisor);
+
+    // If there is no explicit vote for this layer or its children, Use the parent vote if exists
+    divisor = (divisor == 0) ? parentDivisor : divisor;
+    ALOGV("%s: %s divisor=%d with parent", __func__, name, divisor);
+
+    if (layerHierarchy.getLayer()) {
+        Fps fps = divisor > 1 ? displayRefreshRate / (unsigned int)divisor : Fps();
+        updateAttachedChoreographersFrameRate(*layerHierarchy.getLayer(), fps);
+    }
+
+    return divisor;
+}
+
+void Scheduler::updateAttachedChoreographers(
+        const surfaceflinger::frontend::LayerHierarchy& layerHierarchy, Fps displayRefreshRate) {
+    ATRACE_CALL();
+    updateAttachedChoreographersInternal(layerHierarchy, displayRefreshRate, 0);
+}
+
 template <typename S, typename T>
 auto Scheduler::applyPolicy(S Policy::*statePtr, T&& newState) -> GlobalSignals {
     ATRACE_CALL();
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 17e9cea..0ffa2d2 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -52,6 +52,8 @@
 #include "Utils/Dumper.h"
 #include "VsyncModulator.h"
 
+#include <FrontEnd/LayerHierarchy.h>
+
 namespace android::scheduler {
 
 // Opaque handle to scheduler connection.
@@ -153,7 +155,7 @@
 
     sp<IDisplayEventConnection> createDisplayEventConnection(
             ConnectionHandle, EventRegistrationFlags eventRegistration = {},
-            const sp<IBinder>& layerHandle = nullptr);
+            const sp<IBinder>& layerHandle = nullptr) EXCLUDES(mChoreographerLock);
 
     sp<EventThreadConnection> getEventConnection(ConnectionHandle);
 
@@ -230,9 +232,11 @@
     void setModeChangePending(bool pending);
     void setDefaultFrameRateCompatibility(Layer*);
     void deregisterLayer(Layer*);
+    void onLayerDestroyed(Layer*) EXCLUDES(mChoreographerLock);
 
     // Detects content using layer history, and selects a matching refresh rate.
-    void chooseRefreshRateForContent() EXCLUDES(mDisplayLock);
+    void chooseRefreshRateForContent(const surfaceflinger::frontend::LayerHierarchy*,
+                                     bool updateAttachedChoreographer) EXCLUDES(mDisplayLock);
 
     void resetIdleTimer();
 
@@ -274,8 +278,6 @@
     // Notifies the scheduler when the display size has changed. Called from SF's main thread
     void onActiveDisplayAreaChanged(uint32_t displayArea);
 
-    size_t getEventThreadConnectionCount(ConnectionHandle handle);
-
     // Stores the preferred refresh rate that an app should run at.
     // FrameRateOverride.refreshRateHz == 0 means no preference.
     void setPreferredRefreshRateForUid(FrameRateOverride);
@@ -310,9 +312,6 @@
 
     // Create a connection on the given EventThread.
     ConnectionHandle createConnection(std::unique_ptr<EventThread>);
-    sp<EventThreadConnection> createConnectionInternal(
-            EventThread*, EventRegistrationFlags eventRegistration = {},
-            const sp<IBinder>& layerHandle = nullptr);
 
     // Update feature state machine to given state when corresponding timer resets or expires.
     void kernelIdleTimerCallback(TimerState) EXCLUDES(mDisplayLock);
@@ -386,6 +385,12 @@
     GlobalSignals makeGlobalSignals() const REQUIRES(mPolicyLock);
 
     bool updateFrameRateOverrides(GlobalSignals, Fps displayRefreshRate) REQUIRES(mPolicyLock);
+    void updateAttachedChoreographers(const surfaceflinger::frontend::LayerHierarchy&,
+                                      Fps displayRefreshRate);
+    int updateAttachedChoreographersInternal(const surfaceflinger::frontend::LayerHierarchy&,
+                                             Fps displayRefreshRate, int parentDivisor);
+    void updateAttachedChoreographersFrameRate(const surfaceflinger::frontend::RequestedLayerState&,
+                                               Fps fps) EXCLUDES(mChoreographerLock);
 
     void dispatchCachedReportedMode() REQUIRES(mPolicyLock) EXCLUDES(mDisplayLock);
 
@@ -506,6 +511,16 @@
         std::optional<ModeChangedParams> cachedModeChangedParams;
     } mPolicy GUARDED_BY(mPolicyLock);
 
+    std::mutex mChoreographerLock;
+
+    struct AttachedChoreographers {
+        Fps frameRate;
+        std::unordered_set<wp<EventThreadConnection>, WpHash> connections;
+    };
+    // Map keyed by layer ID (sequence) to choreographer connections.
+    std::unordered_map<int32_t, AttachedChoreographers> mAttachedChoreographers
+            GUARDED_BY(mChoreographerLock);
+
     std::mutex mVsyncTimelineLock;
     std::optional<hal::VsyncPeriodChangeTimeline> mLastVsyncPeriodChangeTimeline
             GUARDED_BY(mVsyncTimelineLock);
diff --git a/services/surfaceflinger/ScreenCaptureOutput.cpp b/services/surfaceflinger/ScreenCaptureOutput.cpp
index 09dac23..b345913 100644
--- a/services/surfaceflinger/ScreenCaptureOutput.cpp
+++ b/services/surfaceflinger/ScreenCaptureOutput.cpp
@@ -24,6 +24,24 @@
 
 namespace android {
 
+namespace {
+
+ui::Size getDisplaySize(ui::Rotation orientation, const Rect& sourceCrop) {
+    if (orientation == ui::Rotation::Rotation90 || orientation == ui::Rotation::Rotation270) {
+        return {sourceCrop.getHeight(), sourceCrop.getWidth()};
+    }
+    return {sourceCrop.getWidth(), sourceCrop.getHeight()};
+}
+
+Rect getOrientedDisplaySpaceRect(ui::Rotation orientation, int reqWidth, int reqHeight) {
+    if (orientation == ui::Rotation::Rotation90 || orientation == ui::Rotation::Rotation270) {
+        return {reqHeight, reqWidth};
+    }
+    return {reqWidth, reqHeight};
+}
+
+} // namespace
+
 std::shared_ptr<ScreenCaptureOutput> createScreenCaptureOutput(ScreenCaptureOutputArgs args) {
     std::shared_ptr<ScreenCaptureOutput> output = compositionengine::impl::createOutputTemplated<
             ScreenCaptureOutput, compositionengine::CompositionEngine, const RenderArea&,
@@ -45,10 +63,10 @@
 
     const Rect& sourceCrop = args.renderArea.getSourceCrop();
     const ui::Rotation orientation = ui::Transform::toRotation(args.renderArea.getRotationFlags());
-    const Rect orientedDisplaySpaceRect{args.renderArea.getReqWidth(),
-                                        args.renderArea.getReqHeight()};
-    output->setProjection(orientation, sourceCrop, orientedDisplaySpaceRect);
-    output->setDisplaySize({sourceCrop.getWidth(), sourceCrop.getHeight()});
+    output->setDisplaySize(getDisplaySize(orientation, sourceCrop));
+    output->setProjection(orientation, sourceCrop,
+                          getOrientedDisplaySpaceRect(orientation, args.renderArea.getReqWidth(),
+                                                      args.renderArea.getReqHeight()));
 
     {
         std::string name = args.regionSampling ? "RegionSampling" : "ScreenCaptureOutput";
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 8646c0c..8c8f7dd 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -2330,6 +2330,11 @@
                                                       Changes::Visibility)) {
         mVisibleRegionsDirty = true;
     }
+    if (mLayerLifecycleManager.getGlobalChanges().any(Changes::Hierarchy | Changes::FrameRate)) {
+        // The frame rate of attached choreographers can only change as a result of a
+        // FrameRate change (including when Hierarchy changes).
+        mUpdateAttachedChoreographer = true;
+    }
     outTransactionsAreEmpty = mLayerLifecycleManager.getGlobalChanges().get() == 0;
     mustComposite |= mLayerLifecycleManager.getGlobalChanges().get() != 0;
 
@@ -2506,8 +2511,14 @@
     // Hold mStateLock as chooseRefreshRateForContent promotes wp<Layer> to sp<Layer>
     // and may eventually call to ~Layer() if it holds the last reference
     {
+        bool updateAttachedChoreographer = mUpdateAttachedChoreographer;
+        mUpdateAttachedChoreographer = false;
+
         Mutex::Autolock lock(mStateLock);
-        mScheduler->chooseRefreshRateForContent();
+        mScheduler->chooseRefreshRateForContent(mLayerLifecycleManagerEnabled
+                                                        ? &mLayerHierarchyBuilder.getHierarchy()
+                                                        : nullptr,
+                                                updateAttachedChoreographer);
         setActiveModeInHwcIfNeeded();
     }
 
@@ -2996,10 +3007,6 @@
         }
     }
 
-    const size_t sfConnections = mScheduler->getEventThreadConnectionCount(mSfConnectionHandle);
-    const size_t appConnections = mScheduler->getEventThreadConnectionCount(mAppConnectionHandle);
-    mTimeStats->recordDisplayEventConnectionCount(sfConnections + appConnections);
-
     if (isDisplayConnected && !defaultDisplay->isPoweredOn()) {
         getRenderEngine().cleanupPostRender();
         return;
@@ -3929,6 +3936,14 @@
     mPowerAdvisor->notifyCpuLoadUp();
 }
 
+void SurfaceFlinger::onChoreographerAttached() {
+    ATRACE_CALL();
+    if (mLayerLifecycleManagerEnabled) {
+        mUpdateAttachedChoreographer = true;
+        scheduleCommit(FrameHint::kNone);
+    }
+}
+
 void SurfaceFlinger::initScheduler(const sp<const DisplayDevice>& display) {
     using namespace scheduler;
 
@@ -7961,6 +7976,7 @@
     if (mTransactionTracing) {
         mTransactionTracing->onLayerRemoved(layer->getSequence());
     }
+    mScheduler->onLayerDestroyed(layer);
 }
 
 void SurfaceFlinger::onLayerUpdate() {
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 49aff14..aeaeb47 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -646,6 +646,7 @@
     void requestDisplayModes(std::vector<display::DisplayModeRequest>) override;
     void kernelTimerChanged(bool expired) override;
     void triggerOnFrameRateOverridesChanged() override;
+    void onChoreographerAttached() override;
 
     // ICEPowerCallback overrides:
     void notifyCpuLoadUp() override;
@@ -1183,6 +1184,7 @@
     bool mUpdateInputInfo = false;
     bool mSomeChildrenChanged;
     bool mForceTransactionDisplayChange = false;
+    bool mUpdateAttachedChoreographer = false;
 
     // Set if LayerMetadata has changed since the last LayerMetadata snapshot.
     bool mLayerMetadataSnapshotNeeded = false;
diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp
index 630cef1..368cb41 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.cpp
+++ b/services/surfaceflinger/TimeStats/TimeStats.cpp
@@ -106,7 +106,8 @@
         atom->set_client_composition_frames(mTimeStats.clientCompositionFramesLegacy);
         atom->set_display_on_millis(mTimeStats.displayOnTimeLegacy);
         atom->set_animation_millis(mTimeStats.presentToPresentLegacy.totalTime());
-        atom->set_event_connection_count(mTimeStats.displayEventConnectionsCountLegacy);
+        // Deprecated
+        atom->set_event_connection_count(0);
         *atom->mutable_frame_duration() =
                 histogramToProto(mTimeStats.frameDurationLegacy.hist, mMaxPulledHistogramBuckets);
         *atom->mutable_render_engine_timing() =
@@ -356,16 +357,6 @@
     mTimeStats.refreshRateSwitchesLegacy++;
 }
 
-void TimeStats::recordDisplayEventConnectionCount(int32_t count) {
-    if (!mEnabled.load()) return;
-
-    ATRACE_CALL();
-
-    std::lock_guard<std::mutex> lock(mMutex);
-    mTimeStats.displayEventConnectionsCountLegacy =
-            std::max(mTimeStats.displayEventConnectionsCountLegacy, count);
-}
-
 static int32_t toMs(nsecs_t nanos) {
     int64_t millis =
             std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::nanoseconds(nanos))
@@ -1072,7 +1063,6 @@
     mTimeStats.compositionStrategyPredictedLegacy = 0;
     mTimeStats.compositionStrategyPredictionSucceededLegacy = 0;
     mTimeStats.refreshRateSwitchesLegacy = 0;
-    mTimeStats.displayEventConnectionsCountLegacy = 0;
     mTimeStats.displayOnTimeLegacy = 0;
     mTimeStats.presentToPresentLegacy.hist.clear();
     mTimeStats.frameDurationLegacy.hist.clear();
diff --git a/services/surfaceflinger/TimeStats/TimeStats.h b/services/surfaceflinger/TimeStats/TimeStats.h
index 5f58657..0c227d4 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.h
+++ b/services/surfaceflinger/TimeStats/TimeStats.h
@@ -57,9 +57,6 @@
     virtual void incrementMissedFrames() = 0;
     // Increments the number of times the display refresh rate changed.
     virtual void incrementRefreshRateSwitches() = 0;
-    // Records the most up-to-date count of display event connections.
-    // The stored count will be the maximum ever recoded.
-    virtual void recordDisplayEventConnectionCount(int32_t count) = 0;
 
     // Records the start and end times for a frame.
     // The start time is the same as the beginning of a SurfaceFlinger
@@ -253,7 +250,6 @@
     void incrementTotalFrames() override;
     void incrementMissedFrames() override;
     void incrementRefreshRateSwitches() override;
-    void recordDisplayEventConnectionCount(int32_t count) override;
 
     void recordFrameDuration(nsecs_t startTime, nsecs_t endTime) override;
     void recordRenderEngineDuration(nsecs_t startTime, nsecs_t endTime) override;
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
index 60aa810..9e97f0d 100644
--- a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
+++ b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
@@ -175,7 +175,6 @@
         int32_t clientCompositionReusedFramesLegacy = 0;
         int32_t refreshRateSwitchesLegacy = 0;
         int32_t compositionStrategyChangesLegacy = 0;
-        int32_t displayEventConnectionsCountLegacy = 0;
         int64_t displayOnTimeLegacy = 0;
         Histogram presentToPresentLegacy;
         Histogram frameDurationLegacy;
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
index 0c9a16b..00e92a1 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
@@ -792,6 +792,7 @@
     void requestDisplayModes(std::vector<display::DisplayModeRequest>) override {}
     void kernelTimerChanged(bool) override {}
     void triggerOnFrameRateOverridesChanged() override {}
+    void onChoreographerAttached() override {}
 
     surfaceflinger::test::Factory mFactory;
     sp<SurfaceFlinger> mFlinger =
diff --git a/services/surfaceflinger/tests/ScreenCapture_test.cpp b/services/surfaceflinger/tests/ScreenCapture_test.cpp
index 013694f..96cc333 100644
--- a/services/surfaceflinger/tests/ScreenCapture_test.cpp
+++ b/services/surfaceflinger/tests/ScreenCapture_test.cpp
@@ -19,6 +19,7 @@
 #pragma clang diagnostic ignored "-Wconversion"
 
 #include <private/android_filesystem_config.h>
+#include <ui/DisplayState.h>
 
 #include "LayerTransactionTest.h"
 
@@ -32,11 +33,11 @@
 
         const auto ids = SurfaceComposerClient::getPhysicalDisplayIds();
         ASSERT_FALSE(ids.empty());
-        const auto display = SurfaceComposerClient::getPhysicalDisplayToken(ids.front());
-        ASSERT_FALSE(display == nullptr);
+        mDisplayToken = SurfaceComposerClient::getPhysicalDisplayToken(ids.front());
+        ASSERT_FALSE(mDisplayToken == nullptr);
 
         ui::DisplayMode mode;
-        ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayMode(display, &mode));
+        ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayMode(mDisplayToken, &mode));
         const ui::Size& resolution = mode.resolution;
 
         mDisplaySize = resolution;
@@ -57,7 +58,7 @@
         TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63);
 
         asTransaction([&](Transaction& t) {
-            t.setDisplayLayerStack(display, ui::DEFAULT_LAYER_STACK);
+            t.setDisplayLayerStack(mDisplayToken, ui::DEFAULT_LAYER_STACK);
 
             t.setLayer(mBGSurfaceControl, INT32_MAX - 2).show(mBGSurfaceControl);
 
@@ -71,11 +72,18 @@
         LayerTransactionTest::TearDown();
         mBGSurfaceControl = 0;
         mFGSurfaceControl = 0;
+
+        // Restore display rotation
+        asTransaction([&](Transaction& t) {
+            Rect displayBounds{mDisplaySize};
+            t.setDisplayProjection(mDisplayToken, ui::ROTATION_0, displayBounds, displayBounds);
+        });
     }
 
     sp<SurfaceControl> mBGSurfaceControl;
     sp<SurfaceControl> mFGSurfaceControl;
     std::unique_ptr<ScreenCapture> mCapture;
+    sp<IBinder> mDisplayToken;
     ui::Size mDisplaySize;
 };
 
@@ -870,6 +878,42 @@
     mCapture->expectColor(Rect(0, 0, 32, 32), Color::RED);
 }
 
+TEST_F(ScreenCaptureTest, CaptureDisplayWith90DegRotation) {
+    asTransaction([&](Transaction& t) {
+        Rect newDisplayBounds{mDisplaySize.height, mDisplaySize.width};
+        t.setDisplayProjection(mDisplayToken, ui::ROTATION_90, newDisplayBounds, newDisplayBounds);
+    });
+
+    DisplayCaptureArgs displayCaptureArgs;
+    displayCaptureArgs.displayToken = mDisplayToken;
+    displayCaptureArgs.width = mDisplaySize.width;
+    displayCaptureArgs.height = mDisplaySize.height;
+    displayCaptureArgs.useIdentityTransform = true;
+    ScreenCapture::captureDisplay(&mCapture, displayCaptureArgs);
+
+    mCapture->expectBGColor(0, 0);
+    mCapture->expectFGColor(mDisplaySize.width - 65, 65);
+}
+
+TEST_F(ScreenCaptureTest, CaptureDisplayWith270DegRotation) {
+    asTransaction([&](Transaction& t) {
+        Rect newDisplayBounds{mDisplaySize.height, mDisplaySize.width};
+        t.setDisplayProjection(mDisplayToken, ui::ROTATION_270, newDisplayBounds, newDisplayBounds);
+    });
+
+    DisplayCaptureArgs displayCaptureArgs;
+    displayCaptureArgs.displayToken = mDisplayToken;
+    displayCaptureArgs.width = mDisplaySize.width;
+    displayCaptureArgs.height = mDisplaySize.height;
+    displayCaptureArgs.useIdentityTransform = true;
+    ScreenCapture::captureDisplay(&mCapture, displayCaptureArgs);
+
+    std::this_thread::sleep_for(std::chrono::seconds{5});
+
+    mCapture->expectBGColor(mDisplayWidth - 1, mDisplaySize.height - 1);
+    mCapture->expectFGColor(65, mDisplaySize.height - 65);
+}
+
 TEST_F(ScreenCaptureTest, CaptureNonHdrLayer) {
     sp<SurfaceControl> layer;
     ASSERT_NO_FATAL_FAILURE(layer = createLayer("test layer", 32, 32,
diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
index 5fed9b4..91c6239 100644
--- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
+++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
@@ -634,31 +634,6 @@
     expectVSyncCallbackScheduleReceived(false);
 }
 
-TEST_F(EventThreadTest, tracksEventConnections) {
-    setupEventThread(VSYNC_PERIOD);
-
-    EXPECT_EQ(2, mThread->getEventThreadConnectionCount());
-    ConnectionEventRecorder errorConnectionEventRecorder{NO_MEMORY};
-    sp<MockEventThreadConnection> errorConnection = createConnection(errorConnectionEventRecorder);
-    mThread->setVsyncRate(1, errorConnection);
-    EXPECT_EQ(3, mThread->getEventThreadConnectionCount());
-    ConnectionEventRecorder secondConnectionEventRecorder{0};
-    sp<MockEventThreadConnection> secondConnection =
-            createConnection(secondConnectionEventRecorder);
-    mThread->setVsyncRate(1, secondConnection);
-    EXPECT_EQ(4, mThread->getEventThreadConnectionCount());
-
-    // EventThread should enable vsync callbacks.
-    expectVSyncCallbackScheduleReceived(true);
-
-    // The first event will be seen by the connection, which then returns an error.
-    onVSyncEvent(123, 456, 789);
-    expectVsyncEventReceivedByConnection("errorConnection", errorConnectionEventRecorder, 123, 1u);
-    expectVsyncEventReceivedByConnection("successConnection", secondConnectionEventRecorder, 123,
-                                         1u);
-    EXPECT_EQ(3, mThread->getEventThreadConnectionCount());
-}
-
 TEST_F(EventThreadTest, eventsDroppedIfNonfatalEventDeliveryError) {
     setupEventThread(VSYNC_PERIOD);
 
diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
index fab3c0e..3200003 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -30,6 +30,10 @@
 #include "mock/MockLayer.h"
 #include "mock/MockSchedulerCallback.h"
 
+#include <FrontEnd/LayerHierarchy.h>
+
+#include "FpsOps.h"
+
 namespace android::scheduler {
 
 using android::mock::createDisplayMode;
@@ -42,6 +46,10 @@
 using MockEventThread = android::mock::EventThread;
 using MockLayer = android::mock::MockLayer;
 
+using LayerHierarchy = surfaceflinger::frontend::LayerHierarchy;
+using LayerHierarchyBuilder = surfaceflinger::frontend::LayerHierarchyBuilder;
+using RequestedLayerState = surfaceflinger::frontend::RequestedLayerState;
+
 class SchedulerTest : public testing::Test {
 protected:
     class MockEventThreadConnection : public android::EventThreadConnection {
@@ -83,6 +91,7 @@
 
     mock::SchedulerCallback mSchedulerCallback;
     TestableScheduler* mScheduler = new TestableScheduler{mSelector, mSchedulerCallback};
+    surfaceflinger::frontend::LayerHierarchyBuilder mLayerHierarchyBuilder{{}};
 
     ConnectionHandle mConnectionHandle;
     MockEventThread* mEventThread;
@@ -149,10 +158,6 @@
 
     EXPECT_CALL(*mEventThread, setDuration(10ns, 20ns)).Times(1);
     mScheduler->setDuration(mConnectionHandle, 10ns, 20ns);
-
-    static constexpr size_t kEventConnections = 5;
-    EXPECT_CALL(*mEventThread, getEventThreadConnectionCount()).WillOnce(Return(kEventConnections));
-    EXPECT_EQ(kEventConnections, mScheduler->getEventThreadConnectionCount(mConnectionHandle));
 }
 
 TEST_F(SchedulerTest, registerDisplay) FTL_FAKE_GUARD(kMainThreadContext) {
@@ -199,7 +204,8 @@
     mScheduler->onActiveDisplayAreaChanged(kDisplayArea);
 
     EXPECT_CALL(mSchedulerCallback, requestDisplayModes(_)).Times(0);
-    mScheduler->chooseRefreshRateForContent();
+    mScheduler->chooseRefreshRateForContent(/*LayerHierarchy*/ nullptr,
+                                            /*updateAttachedChoreographer*/ false);
 }
 
 TEST_F(SchedulerTest, updateDisplayModes) {
@@ -278,11 +284,13 @@
     mScheduler->onActiveDisplayAreaChanged(kDisplayArea);
 
     EXPECT_CALL(mSchedulerCallback, requestDisplayModes(Is120Hz())).Times(1);
-    mScheduler->chooseRefreshRateForContent();
+    mScheduler->chooseRefreshRateForContent(/*LayerHierarchy*/ nullptr,
+                                            /*updateAttachedChoreographer*/ false);
 
     // No-op if layer requirements have not changed.
     EXPECT_CALL(mSchedulerCallback, requestDisplayModes(_)).Times(0);
-    mScheduler->chooseRefreshRateForContent();
+    mScheduler->chooseRefreshRateForContent(/*LayerHierarchy*/ nullptr,
+                                            /*updateAttachedChoreographer*/ false);
 }
 
 TEST_F(SchedulerTest, chooseDisplayModesSingleDisplay) {
@@ -437,4 +445,344 @@
     }
 }
 
+class AttachedChoreographerTest : public SchedulerTest {
+protected:
+    void frameRateTestScenario(Fps layerFps, int8_t frameRateCompatibility, Fps displayFps,
+                               Fps expectedChoreographerFps);
+};
+
+TEST_F(AttachedChoreographerTest, registerSingle) {
+    EXPECT_TRUE(mScheduler->mutableAttachedChoreographers().empty());
+
+    const sp<MockLayer> layer = sp<MockLayer>::make(mFlinger.flinger());
+
+    EXPECT_CALL(mSchedulerCallback, onChoreographerAttached);
+    const sp<IDisplayEventConnection> connection =
+            mScheduler->createDisplayEventConnection(mConnectionHandle, {}, layer->getHandle());
+
+    EXPECT_EQ(1u, mScheduler->mutableAttachedChoreographers().size());
+    ASSERT_EQ(1u, mScheduler->mutableAttachedChoreographers().count(layer->getSequence()));
+    EXPECT_EQ(1u,
+              mScheduler->mutableAttachedChoreographers()[layer->getSequence()].connections.size());
+    EXPECT_FALSE(
+            mScheduler->mutableAttachedChoreographers()[layer->getSequence()].frameRate.isValid());
+}
+
+TEST_F(AttachedChoreographerTest, registerMultipleOnSameLayer) {
+    EXPECT_TRUE(mScheduler->mutableAttachedChoreographers().empty());
+
+    const sp<MockLayer> layer = sp<MockLayer>::make(mFlinger.flinger());
+    const auto handle = layer->getHandle();
+
+    EXPECT_CALL(mSchedulerCallback, onChoreographerAttached).Times(2);
+
+    EXPECT_CALL(*mEventThread, registerDisplayEventConnection(_))
+            .WillOnce(Return(0))
+            .WillOnce(Return(0));
+
+    const auto mockConnection1 = sp<MockEventThreadConnection>::make(mEventThread);
+    const auto mockConnection2 = sp<MockEventThreadConnection>::make(mEventThread);
+    EXPECT_CALL(*mEventThread, createEventConnection(_, _))
+            .WillOnce(Return(mockConnection1))
+            .WillOnce(Return(mockConnection2));
+
+    const sp<IDisplayEventConnection> connection1 =
+            mScheduler->createDisplayEventConnection(mConnectionHandle, {}, handle);
+    const sp<IDisplayEventConnection> connection2 =
+            mScheduler->createDisplayEventConnection(mConnectionHandle, {}, handle);
+
+    EXPECT_EQ(1u, mScheduler->mutableAttachedChoreographers().size());
+    ASSERT_EQ(1u, mScheduler->mutableAttachedChoreographers().count(layer->getSequence()));
+    EXPECT_EQ(2u,
+              mScheduler->mutableAttachedChoreographers()[layer->getSequence()].connections.size());
+    EXPECT_FALSE(
+            mScheduler->mutableAttachedChoreographers()[layer->getSequence()].frameRate.isValid());
+}
+
+TEST_F(AttachedChoreographerTest, registerMultipleOnDifferentLayers) {
+    EXPECT_TRUE(mScheduler->mutableAttachedChoreographers().empty());
+
+    const sp<MockLayer> layer1 = sp<MockLayer>::make(mFlinger.flinger());
+    const sp<MockLayer> layer2 = sp<MockLayer>::make(mFlinger.flinger());
+
+    EXPECT_CALL(mSchedulerCallback, onChoreographerAttached).Times(2);
+    const sp<IDisplayEventConnection> connection1 =
+            mScheduler->createDisplayEventConnection(mConnectionHandle, {}, layer1->getHandle());
+    const sp<IDisplayEventConnection> connection2 =
+            mScheduler->createDisplayEventConnection(mConnectionHandle, {}, layer2->getHandle());
+
+    EXPECT_EQ(2u, mScheduler->mutableAttachedChoreographers().size());
+
+    ASSERT_EQ(1u, mScheduler->mutableAttachedChoreographers().count(layer1->getSequence()));
+    EXPECT_EQ(1u,
+              mScheduler->mutableAttachedChoreographers()[layer1->getSequence()]
+                      .connections.size());
+    EXPECT_FALSE(
+            mScheduler->mutableAttachedChoreographers()[layer1->getSequence()].frameRate.isValid());
+
+    ASSERT_EQ(1u, mScheduler->mutableAttachedChoreographers().count(layer2->getSequence()));
+    EXPECT_EQ(1u,
+              mScheduler->mutableAttachedChoreographers()[layer2->getSequence()]
+                      .connections.size());
+    EXPECT_FALSE(
+            mScheduler->mutableAttachedChoreographers()[layer2->getSequence()].frameRate.isValid());
+}
+
+TEST_F(AttachedChoreographerTest, removedWhenConnectionIsGone) {
+    EXPECT_TRUE(mScheduler->mutableAttachedChoreographers().empty());
+
+    const sp<MockLayer> layer = sp<MockLayer>::make(mFlinger.flinger());
+
+    EXPECT_CALL(mSchedulerCallback, onChoreographerAttached);
+
+    sp<IDisplayEventConnection> connection =
+            mScheduler->createDisplayEventConnection(mConnectionHandle, {}, layer->getHandle());
+
+    ASSERT_EQ(1u, mScheduler->mutableAttachedChoreographers().count(layer->getSequence()));
+    EXPECT_EQ(1u,
+              mScheduler->mutableAttachedChoreographers()[layer->getSequence()].connections.size());
+
+    // The connection is used all over this test, so it is quite hard to release it from here.
+    // Instead, we just do a small shortcut.
+    {
+        EXPECT_CALL(*mEventThread, registerDisplayEventConnection(_)).WillOnce(Return(0));
+        sp<MockEventThreadConnection> mockConnection =
+                sp<MockEventThreadConnection>::make(mEventThread);
+        mScheduler->mutableAttachedChoreographers()[layer->getSequence()].connections.clear();
+        mScheduler->mutableAttachedChoreographers()[layer->getSequence()].connections.emplace(
+                mockConnection);
+    }
+
+    RequestedLayerState layerState(LayerCreationArgs(layer->getSequence()));
+    LayerHierarchy hierarchy(&layerState);
+    mScheduler->updateAttachedChoreographers(hierarchy, 60_Hz);
+    EXPECT_TRUE(mScheduler->mutableAttachedChoreographers().empty());
+}
+
+TEST_F(AttachedChoreographerTest, removedWhenLayerIsGone) {
+    EXPECT_TRUE(mScheduler->mutableAttachedChoreographers().empty());
+
+    sp<MockLayer> layer = sp<MockLayer>::make(mFlinger.flinger());
+
+    EXPECT_CALL(mSchedulerCallback, onChoreographerAttached);
+    const sp<IDisplayEventConnection> connection =
+            mScheduler->createDisplayEventConnection(mConnectionHandle, {}, layer->getHandle());
+
+    layer.clear();
+    mFlinger.mutableLayersPendingRemoval().clear();
+    EXPECT_TRUE(mScheduler->mutableAttachedChoreographers().empty());
+}
+
+void AttachedChoreographerTest::frameRateTestScenario(Fps layerFps, int8_t frameRateCompatibility,
+                                                      Fps displayFps,
+                                                      Fps expectedChoreographerFps) {
+    const sp<MockLayer> layer = sp<MockLayer>::make(mFlinger.flinger());
+
+    EXPECT_CALL(mSchedulerCallback, onChoreographerAttached);
+    sp<IDisplayEventConnection> connection =
+            mScheduler->createDisplayEventConnection(mConnectionHandle, {}, layer->getHandle());
+
+    RequestedLayerState layerState(LayerCreationArgs(layer->getSequence()));
+    LayerHierarchy hierarchy(&layerState);
+
+    layerState.frameRate = layerFps.getValue();
+    layerState.frameRateCompatibility = frameRateCompatibility;
+
+    mScheduler->updateAttachedChoreographers(hierarchy, displayFps);
+
+    ASSERT_EQ(1u, mScheduler->mutableAttachedChoreographers().count(layer->getSequence()));
+    EXPECT_EQ(expectedChoreographerFps,
+              mScheduler->mutableAttachedChoreographers()[layer->getSequence()].frameRate);
+    EXPECT_EQ(expectedChoreographerFps, mEventThreadConnection->frameRate);
+}
+
+TEST_F(AttachedChoreographerTest, setsFrameRateDefault) {
+    Fps layerFps = 30_Hz;
+    int8_t frameRateCompatibility = ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT;
+    Fps displayFps = 60_Hz;
+    Fps expectedChoreographerFps = 30_Hz;
+
+    frameRateTestScenario(layerFps, frameRateCompatibility, displayFps, expectedChoreographerFps);
+
+    layerFps = Fps::fromValue(32.7f);
+    frameRateTestScenario(layerFps, frameRateCompatibility, displayFps, expectedChoreographerFps);
+}
+
+TEST_F(AttachedChoreographerTest, setsFrameRateExact) {
+    Fps layerFps = 30_Hz;
+    int8_t frameRateCompatibility = ANATIVEWINDOW_FRAME_RATE_EXACT;
+    Fps displayFps = 60_Hz;
+    Fps expectedChoreographerFps = 30_Hz;
+
+    frameRateTestScenario(layerFps, frameRateCompatibility, displayFps, expectedChoreographerFps);
+
+    layerFps = Fps::fromValue(32.7f);
+    expectedChoreographerFps = {};
+    frameRateTestScenario(layerFps, frameRateCompatibility, displayFps, expectedChoreographerFps);
+}
+
+TEST_F(AttachedChoreographerTest, setsFrameRateExactOrMultiple) {
+    Fps layerFps = 30_Hz;
+    int8_t frameRateCompatibility = ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE;
+    Fps displayFps = 60_Hz;
+    Fps expectedChoreographerFps = 30_Hz;
+
+    frameRateTestScenario(layerFps, frameRateCompatibility, displayFps, expectedChoreographerFps);
+
+    layerFps = Fps::fromValue(32.7f);
+    expectedChoreographerFps = {};
+    frameRateTestScenario(layerFps, frameRateCompatibility, displayFps, expectedChoreographerFps);
+}
+
+TEST_F(AttachedChoreographerTest, setsFrameRateParent) {
+    const sp<MockLayer> layer = sp<MockLayer>::make(mFlinger.flinger());
+    const sp<MockLayer> parent = sp<MockLayer>::make(mFlinger.flinger());
+
+    EXPECT_CALL(mSchedulerCallback, onChoreographerAttached);
+    sp<IDisplayEventConnection> connection =
+            mScheduler->createDisplayEventConnection(mConnectionHandle, {}, parent->getHandle());
+
+    RequestedLayerState parentState(LayerCreationArgs(parent->getSequence()));
+    LayerHierarchy parentHierarchy(&parentState);
+
+    RequestedLayerState layerState(LayerCreationArgs(layer->getSequence()));
+    LayerHierarchy hierarchy(&layerState);
+    parentHierarchy.mChildren.push_back(
+            std::make_pair(&hierarchy, LayerHierarchy::Variant::Attached));
+
+    layerState.frameRate = (30_Hz).getValue();
+    layerState.frameRateCompatibility = ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT;
+
+    mScheduler->updateAttachedChoreographers(parentHierarchy, 120_Hz);
+
+    ASSERT_EQ(1u, mScheduler->mutableAttachedChoreographers().count(parent->getSequence()));
+
+    EXPECT_EQ(30_Hz, mScheduler->mutableAttachedChoreographers()[parent->getSequence()].frameRate);
+}
+
+TEST_F(AttachedChoreographerTest, setsFrameRateParent2Children) {
+    const sp<MockLayer> layer1 = sp<MockLayer>::make(mFlinger.flinger());
+    const sp<MockLayer> layer2 = sp<MockLayer>::make(mFlinger.flinger());
+    const sp<MockLayer> parent = sp<MockLayer>::make(mFlinger.flinger());
+
+    EXPECT_CALL(mSchedulerCallback, onChoreographerAttached);
+    sp<IDisplayEventConnection> connection =
+            mScheduler->createDisplayEventConnection(mConnectionHandle, {}, parent->getHandle());
+
+    RequestedLayerState parentState(LayerCreationArgs(parent->getSequence()));
+    LayerHierarchy parentHierarchy(&parentState);
+
+    RequestedLayerState layer1State(LayerCreationArgs(layer1->getSequence()));
+    LayerHierarchy layer1Hierarchy(&layer1State);
+    parentHierarchy.mChildren.push_back(
+            std::make_pair(&layer1Hierarchy, LayerHierarchy::Variant::Attached));
+
+    RequestedLayerState layer2State(LayerCreationArgs(layer1->getSequence()));
+    LayerHierarchy layer2Hierarchy(&layer2State);
+    parentHierarchy.mChildren.push_back(
+            std::make_pair(&layer2Hierarchy, LayerHierarchy::Variant::Attached));
+
+    layer1State.frameRate = (30_Hz).getValue();
+    layer1State.frameRateCompatibility = ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT;
+
+    layer2State.frameRate = (20_Hz).getValue();
+    layer2State.frameRateCompatibility = ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT;
+
+    mScheduler->updateAttachedChoreographers(parentHierarchy, 120_Hz);
+
+    ASSERT_EQ(1u, mScheduler->mutableAttachedChoreographers().count(parent->getSequence()));
+
+    EXPECT_EQ(60_Hz, mScheduler->mutableAttachedChoreographers()[parent->getSequence()].frameRate);
+}
+
+TEST_F(AttachedChoreographerTest, setsFrameRateParentConflictingChildren) {
+    const sp<MockLayer> layer1 = sp<MockLayer>::make(mFlinger.flinger());
+    const sp<MockLayer> layer2 = sp<MockLayer>::make(mFlinger.flinger());
+    const sp<MockLayer> parent = sp<MockLayer>::make(mFlinger.flinger());
+
+    EXPECT_CALL(mSchedulerCallback, onChoreographerAttached);
+    sp<IDisplayEventConnection> connection =
+            mScheduler->createDisplayEventConnection(mConnectionHandle, {}, parent->getHandle());
+
+    RequestedLayerState parentState(LayerCreationArgs(parent->getSequence()));
+    LayerHierarchy parentHierarchy(&parentState);
+
+    RequestedLayerState layer1State(LayerCreationArgs(layer1->getSequence()));
+    LayerHierarchy layer1Hierarchy(&layer1State);
+    parentHierarchy.mChildren.push_back(
+            std::make_pair(&layer1Hierarchy, LayerHierarchy::Variant::Attached));
+
+    RequestedLayerState layer2State(LayerCreationArgs(layer1->getSequence()));
+    LayerHierarchy layer2Hierarchy(&layer2State);
+    parentHierarchy.mChildren.push_back(
+            std::make_pair(&layer2Hierarchy, LayerHierarchy::Variant::Attached));
+
+    layer1State.frameRate = (30_Hz).getValue();
+    layer1State.frameRateCompatibility = ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT;
+
+    layer2State.frameRate = (25_Hz).getValue();
+    layer2State.frameRateCompatibility = ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT;
+
+    mScheduler->updateAttachedChoreographers(parentHierarchy, 120_Hz);
+
+    ASSERT_EQ(1u, mScheduler->mutableAttachedChoreographers().count(parent->getSequence()));
+
+    EXPECT_EQ(Fps(), mScheduler->mutableAttachedChoreographers()[parent->getSequence()].frameRate);
+}
+
+TEST_F(AttachedChoreographerTest, setsFrameRateChild) {
+    const sp<MockLayer> layer = sp<MockLayer>::make(mFlinger.flinger());
+    const sp<MockLayer> parent = sp<MockLayer>::make(mFlinger.flinger());
+
+    EXPECT_CALL(mSchedulerCallback, onChoreographerAttached);
+    sp<IDisplayEventConnection> connection =
+            mScheduler->createDisplayEventConnection(mConnectionHandle, {}, layer->getHandle());
+
+    RequestedLayerState parentState(LayerCreationArgs(parent->getSequence()));
+    LayerHierarchy parentHierarchy(&parentState);
+
+    RequestedLayerState layerState(LayerCreationArgs(layer->getSequence()));
+    LayerHierarchy hierarchy(&layerState);
+    parentHierarchy.mChildren.push_back(
+            std::make_pair(&hierarchy, LayerHierarchy::Variant::Attached));
+
+    parentState.frameRate = (30_Hz).getValue();
+    parentState.frameRateCompatibility = ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT;
+
+    mScheduler->updateAttachedChoreographers(parentHierarchy, 120_Hz);
+
+    ASSERT_EQ(1u, mScheduler->mutableAttachedChoreographers().count(layer->getSequence()));
+
+    EXPECT_EQ(30_Hz, mScheduler->mutableAttachedChoreographers()[layer->getSequence()].frameRate);
+}
+
+TEST_F(AttachedChoreographerTest, setsFrameRateChildNotOverriddenByParent) {
+    const sp<MockLayer> layer = sp<MockLayer>::make(mFlinger.flinger());
+    const sp<MockLayer> parent = sp<MockLayer>::make(mFlinger.flinger());
+
+    EXPECT_CALL(mSchedulerCallback, onChoreographerAttached);
+    sp<IDisplayEventConnection> connection =
+            mScheduler->createDisplayEventConnection(mConnectionHandle, {}, layer->getHandle());
+
+    RequestedLayerState parentState(LayerCreationArgs(parent->getSequence()));
+    LayerHierarchy parentHierarchy(&parentState);
+
+    RequestedLayerState layerState(LayerCreationArgs(layer->getSequence()));
+    LayerHierarchy hierarchy(&layerState);
+    parentHierarchy.mChildren.push_back(
+            std::make_pair(&hierarchy, LayerHierarchy::Variant::Attached));
+
+    parentState.frameRate = (30_Hz).getValue();
+    parentState.frameRateCompatibility = ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT;
+
+    layerState.frameRate = (60_Hz).getValue();
+    layerState.frameRateCompatibility = ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT;
+
+    mScheduler->updateAttachedChoreographers(parentHierarchy, 120_Hz);
+
+    ASSERT_EQ(1u, mScheduler->mutableAttachedChoreographers().count(layer->getSequence()));
+
+    EXPECT_EQ(60_Hz, mScheduler->mutableAttachedChoreographers()[layer->getSequence()].frameRate);
+}
+
 } // namespace android::scheduler
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp
index e176546..703bdda 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp
@@ -49,9 +49,17 @@
         mFlinger.onComposerHalHotplug(PrimaryDisplayVariant::HWC_DISPLAY_ID, Connection::CONNECTED);
         mFlinger.configureAndCommit();
 
+        auto vsyncController = std::make_unique<mock::VsyncController>();
+        auto vsyncTracker = std::make_shared<mock::VSyncTracker>();
+
+        EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0));
+        EXPECT_CALL(*vsyncTracker, currentPeriod())
+                .WillRepeatedly(Return(
+                        TestableSurfaceFlinger::FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD));
+
         mDisplay = PrimaryDisplayVariant::makeFakeExistingDisplayInjector(this)
                            .setRefreshRateSelector(std::move(selectorPtr))
-                           .inject();
+                           .inject(std::move(vsyncController), std::move(vsyncTracker));
 
         // isVsyncPeriodSwitchSupported should return true, otherwise the SF's HWC proxy
         // will call setActiveConfig instead of setActiveConfigWithConstraints.
diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h
index aac11c0..fa7a947 100644
--- a/services/surfaceflinger/tests/unittests/TestableScheduler.h
+++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h
@@ -39,7 +39,7 @@
     TestableScheduler(RefreshRateSelectorPtr selectorPtr, ISchedulerCallback& callback)
           : TestableScheduler(std::make_unique<mock::VsyncController>(),
                               std::make_shared<mock::VSyncTracker>(), std::move(selectorPtr),
-                              /* modulatorPtr */ nullptr, callback) {}
+                              sp<VsyncModulator>::make(VsyncConfigSet{}), callback) {}
 
     TestableScheduler(std::unique_ptr<VsyncController> controller,
                       std::shared_ptr<VSyncTracker> tracker, RefreshRateSelectorPtr selectorPtr,
@@ -104,6 +104,7 @@
 
     auto& mutableAppConnectionHandle() { return mAppConnectionHandle; }
     auto& mutableLayerHistory() { return mLayerHistory; }
+    auto& mutableAttachedChoreographers() { return mAttachedChoreographers; }
 
     size_t layerHistorySize() NO_THREAD_SAFETY_ANALYSIS {
         return mLayerHistory.mActiveLayerInfos.size() + mLayerHistory.mInactiveLayerInfos.size();
@@ -168,6 +169,12 @@
                                           : VsyncSchedule::HwVsyncState::Disabled;
     }
 
+    void updateAttachedChoreographers(
+            const surfaceflinger::frontend::LayerHierarchy& layerHierarchy,
+            Fps displayRefreshRate) {
+        Scheduler::updateAttachedChoreographers(layerHierarchy, displayRefreshRate);
+    }
+
     using Scheduler::onHardwareVsyncRequest;
 
 private:
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 156c40a..909b8b8 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -55,6 +55,12 @@
 #include "mock/MockSchedulerCallback.h"
 #include "mock/system/window/MockNativeWindow.h"
 
+#include "Scheduler/VSyncTracker.h"
+#include "Scheduler/VsyncController.h"
+#include "mock/MockVSyncDispatch.h"
+#include "mock/MockVSyncTracker.h"
+#include "mock/MockVsyncController.h"
+
 namespace android {
 
 struct DisplayStatInfo;
@@ -624,6 +630,8 @@
 
     auto& mutableMinAcquiredBuffers() { return SurfaceFlinger::minAcquiredBuffers; }
 
+    auto& mutableLayersPendingRemoval() { return mFlinger->mLayersPendingRemoval; }
+
     auto fromHandle(const sp<IBinder>& handle) { return LayerHandle::getLayer(handle); }
 
     ~TestableSurfaceFlinger() {
@@ -634,6 +642,7 @@
         mutableDisplays().clear();
         mutableCurrentState().displays.clear();
         mutableDrawingState().displays.clear();
+        mFlinger->mLayersPendingRemoval.clear();
         mFlinger->mScheduler.reset();
         mFlinger->mCompositionEngine->setHwComposer(std::unique_ptr<HWComposer>());
         mFlinger->mRenderEngine = std::unique_ptr<renderengine::RenderEngine>();
@@ -908,6 +917,13 @@
         }
 
         sp<DisplayDevice> inject() NO_THREAD_SAFETY_ANALYSIS {
+            return inject(std::make_unique<mock::VsyncController>(),
+                          std::make_shared<mock::VSyncTracker>());
+        }
+
+        sp<DisplayDevice> inject(std::unique_ptr<android::scheduler::VsyncController> controller,
+                                 std::shared_ptr<android::scheduler::VSyncTracker> tracker)
+                NO_THREAD_SAFETY_ANALYSIS {
             const auto displayId = mCreationArgs.compositionDisplay->getDisplayId();
 
             auto& modes = mDisplayModes;
@@ -972,7 +988,9 @@
 
                 if (mFlinger.scheduler() && mRegisterDisplay) {
                     mFlinger.scheduler()->registerDisplay(physicalId,
-                                                          display->holdRefreshRateSelector());
+                                                          display->holdRefreshRateSelector(),
+                                                          std::move(controller),
+                                                          std::move(tracker));
                 }
 
                 display->setActiveMode(activeModeId, fps, fps);
diff --git a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
index a9ae1d3..86ed233 100644
--- a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
@@ -1079,7 +1079,6 @@
     constexpr size_t TOTAL_FRAMES = 5;
     constexpr size_t MISSED_FRAMES = 4;
     constexpr size_t CLIENT_COMPOSITION_FRAMES = 3;
-    constexpr size_t DISPLAY_EVENT_CONNECTIONS = 14;
     constexpr nsecs_t DISPLAY_DEADLINE_DELTA = 1'000'000;
     constexpr nsecs_t DISPLAY_PRESENT_JITTER = 2'000'000;
     constexpr nsecs_t APP_DEADLINE_DELTA = 3'000'000;
@@ -1100,7 +1099,6 @@
 
     insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
 
-    mTimeStats->recordDisplayEventConnectionCount(DISPLAY_EVENT_CONNECTIONS);
     mTimeStats->setPowerMode(PowerMode::ON);
     mTimeStats->recordFrameDuration(1000000, 3000000);
     mTimeStats->recordRenderEngineDuration(2000000, 4000000);
@@ -1157,7 +1155,6 @@
     EXPECT_EQ(atom.client_composition_frames(), CLIENT_COMPOSITION_FRAMES);
     // Display on millis is not checked.
     EXPECT_EQ(atom.animation_millis(), 2);
-    EXPECT_EQ(atom.event_connection_count(), DISPLAY_EVENT_CONNECTIONS);
     EXPECT_THAT(atom.frame_duration(), HistogramEq(buildExpectedHistogram({2}, {1})));
     EXPECT_THAT(atom.render_engine_timing(), HistogramEq(buildExpectedHistogram({1, 2}, {1, 1})));
     EXPECT_EQ(atom.total_timeline_frames(), 9);
diff --git a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
index 8d57049..9a1a16d 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
@@ -49,7 +49,6 @@
                 (const sp<android::EventThreadConnection>&), (const, override));
     MOCK_METHOD(void, requestLatestConfig, (const sp<android::EventThreadConnection>&));
     MOCK_METHOD(void, pauseVsyncCallback, (bool));
-    MOCK_METHOD(size_t, getEventThreadConnectionCount, (), (override));
     MOCK_METHOD(void, onNewVsyncSchedule, (std::shared_ptr<scheduler::VsyncSchedule>), (override));
 };
 
diff --git a/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h b/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h
index 306eb4d..22b2ccc 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h
@@ -27,6 +27,7 @@
     MOCK_METHOD(void, requestDisplayModes, (std::vector<display::DisplayModeRequest>), (override));
     MOCK_METHOD(void, kernelTimerChanged, (bool), (override));
     MOCK_METHOD(void, triggerOnFrameRateOverridesChanged, (), (override));
+    MOCK_METHOD(void, onChoreographerAttached, (), (override));
 };
 
 struct NoOpSchedulerCallback final : ISchedulerCallback {
@@ -34,6 +35,7 @@
     void requestDisplayModes(std::vector<display::DisplayModeRequest>) override {}
     void kernelTimerChanged(bool) override {}
     void triggerOnFrameRateOverridesChanged() override {}
+    void onChoreographerAttached() override {}
 };
 
 } // namespace android::scheduler::mock
diff --git a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
index 86fbadc..c82e45b 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
@@ -34,7 +34,6 @@
     MOCK_METHOD0(incrementTotalFrames, void());
     MOCK_METHOD0(incrementMissedFrames, void());
     MOCK_METHOD0(incrementRefreshRateSwitches, void());
-    MOCK_METHOD1(recordDisplayEventConnectionCount, void(int32_t));
     MOCK_METHOD2(recordFrameDuration, void(nsecs_t, nsecs_t));
     MOCK_METHOD2(recordRenderEngineDuration, void(nsecs_t, nsecs_t));
     MOCK_METHOD2(recordRenderEngineDuration, void(nsecs_t, const std::shared_ptr<FenceTime>&));