Merge "Sync disabling of touchpad taps with hiding pointer" into main
diff --git a/include/input/Input.h b/include/input/Input.h
index 17672d1..77d7448 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -196,11 +196,11 @@
 #define MAX_POINTER_ID 31
 
 /*
- * Number of high resolution mouse scroll units for one detent (mouse wheel click), as defined in
+ * Number of high resolution scroll units for one detent (scroll wheel click), as defined in
  * evdev. This is relevant when an input device is emitting REL_WHEEL_HI_RES or REL_HWHEEL_HI_RES
  * events.
  */
-constexpr int32_t kEvdevMouseHighResScrollUnitsPerDetent = 120;
+constexpr int32_t kEvdevHighResScrollUnitsPerDetent = 120;
 
 /*
  * Declare a concrete type for the NDK's input event forward declaration.
diff --git a/include/input/VirtualInputDevice.h b/include/input/VirtualInputDevice.h
index 9fbae73..dabe45c 100644
--- a/include/input/VirtualInputDevice.h
+++ b/include/input/VirtualInputDevice.h
@@ -129,6 +129,9 @@
     VirtualRotaryEncoder(android::base::unique_fd fd);
     virtual ~VirtualRotaryEncoder() override;
     bool writeScrollEvent(float scrollAmount, std::chrono::nanoseconds eventTime);
+
+private:
+    int32_t mAccumulatedHighResScrollAmount;
 };
 
 } // namespace android
diff --git a/libs/binder/include/binder/IBinder.h b/libs/binder/include/binder/IBinder.h
index 17248ce..4eb1c08 100644
--- a/libs/binder/include/binder/IBinder.h
+++ b/libs/binder/include/binder/IBinder.h
@@ -102,6 +102,10 @@
      */
     virtual const String16& getInterfaceDescriptor() const = 0;
 
+    /**
+     * Last known alive status, from last call. May be arbitrarily stale.
+     * May be incorrect if a service returns an incorrect status code.
+     */
     virtual bool            isBinderAlive() const = 0;
     virtual status_t        pingBinder() = 0;
     virtual status_t        dump(int fd, const Vector<String16>& args) = 0;
diff --git a/libs/binder/ndk/include_cpp/android/persistable_bundle_aidl.h b/libs/binder/ndk/include_cpp/android/persistable_bundle_aidl.h
index cf7dc1a..bfba79f 100644
--- a/libs/binder/ndk/include_cpp/android/persistable_bundle_aidl.h
+++ b/libs/binder/ndk/include_cpp/android/persistable_bundle_aidl.h
@@ -264,7 +264,7 @@
         }
     }
 
-    bool getBoolean(const std::string& key, bool* _Nonnull val) {
+    bool getBoolean(const std::string& key, bool* _Nonnull val) const {
         if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) {
             return APersistableBundle_getBoolean(mPBundle, key.c_str(), val);
         } else {
@@ -272,7 +272,7 @@
         }
     }
 
-    bool getInt(const std::string& key, int32_t* _Nonnull val) {
+    bool getInt(const std::string& key, int32_t* _Nonnull val) const {
         if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) {
             return APersistableBundle_getInt(mPBundle, key.c_str(), val);
         } else {
@@ -280,7 +280,7 @@
         }
     }
 
-    bool getLong(const std::string& key, int64_t* _Nonnull val) {
+    bool getLong(const std::string& key, int64_t* _Nonnull val) const {
         if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) {
             return APersistableBundle_getLong(mPBundle, key.c_str(), val);
         } else {
@@ -288,7 +288,7 @@
         }
     }
 
-    bool getDouble(const std::string& key, double* _Nonnull val) {
+    bool getDouble(const std::string& key, double* _Nonnull val) const {
         if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) {
             return APersistableBundle_getDouble(mPBundle, key.c_str(), val);
         } else {
@@ -300,7 +300,7 @@
         return (char*)malloc(bufferSizeBytes);
     }
 
-    bool getString(const std::string& key, std::string* _Nonnull val) {
+    bool getString(const std::string& key, std::string* _Nonnull val) const {
         if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) {
             char* outString = nullptr;
             bool ret = APersistableBundle_getString(mPBundle, key.c_str(), &outString,
@@ -318,7 +318,7 @@
     bool getVecInternal(int32_t (*_Nonnull getVec)(const APersistableBundle* _Nonnull,
                                                    const char* _Nonnull, T* _Nullable, int32_t),
                         const APersistableBundle* _Nonnull pBundle, const char* _Nonnull key,
-                        std::vector<T>* _Nonnull vec) {
+                        std::vector<T>* _Nonnull vec) const {
         if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) {
             int32_t bytes = 0;
             // call first with nullptr to get required size in bytes
@@ -340,28 +340,28 @@
         return false;
     }
 
-    bool getBooleanVector(const std::string& key, std::vector<bool>* _Nonnull vec) {
+    bool getBooleanVector(const std::string& key, std::vector<bool>* _Nonnull vec) const {
         if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) {
             return getVecInternal<bool>(&APersistableBundle_getBooleanVector, mPBundle, key.c_str(),
                                         vec);
         }
         return false;
     }
-    bool getIntVector(const std::string& key, std::vector<int32_t>* _Nonnull vec) {
+    bool getIntVector(const std::string& key, std::vector<int32_t>* _Nonnull vec) const {
         if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) {
             return getVecInternal<int32_t>(&APersistableBundle_getIntVector, mPBundle, key.c_str(),
                                            vec);
         }
         return false;
     }
-    bool getLongVector(const std::string& key, std::vector<int64_t>* _Nonnull vec) {
+    bool getLongVector(const std::string& key, std::vector<int64_t>* _Nonnull vec) const {
         if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) {
             return getVecInternal<int64_t>(&APersistableBundle_getLongVector, mPBundle, key.c_str(),
                                            vec);
         }
         return false;
     }
-    bool getDoubleVector(const std::string& key, std::vector<double>* _Nonnull vec) {
+    bool getDoubleVector(const std::string& key, std::vector<double>* _Nonnull vec) const {
         if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) {
             return getVecInternal<double>(&APersistableBundle_getDoubleVector, mPBundle,
                                           key.c_str(), vec);
@@ -372,7 +372,7 @@
     // Takes ownership of and frees the char** and its elements.
     // Creates a new set or vector based on the array of char*.
     template <typename T>
-    T moveStringsInternal(char* _Nullable* _Nonnull strings, int32_t bufferSizeBytes) {
+    T moveStringsInternal(char* _Nullable* _Nonnull strings, int32_t bufferSizeBytes) const {
         if (strings && bufferSizeBytes > 0) {
             int32_t num = bufferSizeBytes / sizeof(char*);
             T ret;
@@ -386,7 +386,7 @@
         return T();
     }
 
-    bool getStringVector(const std::string& key, std::vector<std::string>* _Nonnull vec) {
+    bool getStringVector(const std::string& key, std::vector<std::string>* _Nonnull vec) const {
         if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) {
             int32_t bytes = APersistableBundle_getStringVector(mPBundle, key.c_str(), nullptr, 0,
                                                                &stringAllocator, nullptr);
@@ -403,7 +403,7 @@
         return false;
     }
 
-    bool getPersistableBundle(const std::string& key, PersistableBundle* _Nonnull val) {
+    bool getPersistableBundle(const std::string& key, PersistableBundle* _Nonnull val) const {
         if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) {
             APersistableBundle* bundle = nullptr;
             bool ret = APersistableBundle_getPersistableBundle(mPBundle, key.c_str(), &bundle);
@@ -422,7 +422,7 @@
                                              int32_t bufferSizeBytes,
                                              APersistableBundle_stringAllocator stringAllocator,
                                              void* _Nullable),
-            const APersistableBundle* _Nonnull pBundle) {
+            const APersistableBundle* _Nonnull pBundle) const {
         // call first with nullptr to get required size in bytes
         int32_t bytes = getTypedKeys(pBundle, nullptr, 0, &stringAllocator, nullptr);
         if (bytes > 0) {
@@ -435,84 +435,84 @@
         return {};
     }
 
-    std::set<std::string> getBooleanKeys() {
+    std::set<std::string> getBooleanKeys() const {
         if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) {
             return getKeys(&APersistableBundle_getBooleanKeys, mPBundle);
         } else {
             return {};
         }
     }
-    std::set<std::string> getIntKeys() {
+    std::set<std::string> getIntKeys() const {
         if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) {
             return getKeys(&APersistableBundle_getIntKeys, mPBundle);
         } else {
             return {};
         }
     }
-    std::set<std::string> getLongKeys() {
+    std::set<std::string> getLongKeys() const {
         if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) {
             return getKeys(&APersistableBundle_getLongKeys, mPBundle);
         } else {
             return {};
         }
     }
-    std::set<std::string> getDoubleKeys() {
+    std::set<std::string> getDoubleKeys() const {
         if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) {
             return getKeys(&APersistableBundle_getDoubleKeys, mPBundle);
         } else {
             return {};
         }
     }
-    std::set<std::string> getStringKeys() {
+    std::set<std::string> getStringKeys() const {
         if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) {
             return getKeys(&APersistableBundle_getStringKeys, mPBundle);
         } else {
             return {};
         }
     }
-    std::set<std::string> getBooleanVectorKeys() {
+    std::set<std::string> getBooleanVectorKeys() const {
         if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) {
             return getKeys(&APersistableBundle_getBooleanVectorKeys, mPBundle);
         } else {
             return {};
         }
     }
-    std::set<std::string> getIntVectorKeys() {
+    std::set<std::string> getIntVectorKeys() const {
         if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) {
             return getKeys(&APersistableBundle_getIntVectorKeys, mPBundle);
         } else {
             return {};
         }
     }
-    std::set<std::string> getLongVectorKeys() {
+    std::set<std::string> getLongVectorKeys() const {
         if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) {
             return getKeys(&APersistableBundle_getLongVectorKeys, mPBundle);
         } else {
             return {};
         }
     }
-    std::set<std::string> getDoubleVectorKeys() {
+    std::set<std::string> getDoubleVectorKeys() const {
         if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) {
             return getKeys(&APersistableBundle_getDoubleVectorKeys, mPBundle);
         } else {
             return {};
         }
     }
-    std::set<std::string> getStringVectorKeys() {
+    std::set<std::string> getStringVectorKeys() const {
         if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) {
             return getKeys(&APersistableBundle_getStringVectorKeys, mPBundle);
         } else {
             return {};
         }
     }
-    std::set<std::string> getPersistableBundleKeys() {
+    std::set<std::string> getPersistableBundleKeys() const {
         if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) {
             return getKeys(&APersistableBundle_getPersistableBundleKeys, mPBundle);
         } else {
             return {};
         }
     }
-    std::set<std::string> getMonKeys() {
+    std::set<std::string> getMonKeys() const {
         // :P
         return {"c(o,o)b", "c(o,o)b"};
     }
diff --git a/libs/input/VirtualInputDevice.cpp b/libs/input/VirtualInputDevice.cpp
index 2e3e1a0..0579967 100644
--- a/libs/input/VirtualInputDevice.cpp
+++ b/libs/input/VirtualInputDevice.cpp
@@ -279,13 +279,17 @@
 bool VirtualMouse::writeScrollEvent(float xAxisMovement, float yAxisMovement,
                                     std::chrono::nanoseconds eventTime) {
     if (!vd_flags::high_resolution_scroll()) {
-        return writeInputEvent(EV_REL, REL_HWHEEL, xAxisMovement, eventTime) &&
-                writeInputEvent(EV_REL, REL_WHEEL, yAxisMovement, eventTime) &&
+        return writeInputEvent(EV_REL, REL_HWHEEL, static_cast<int32_t>(xAxisMovement),
+                               eventTime) &&
+                writeInputEvent(EV_REL, REL_WHEEL, static_cast<int32_t>(yAxisMovement),
+                                eventTime) &&
                 writeInputEvent(EV_SYN, SYN_REPORT, 0, eventTime);
     }
 
-    const int32_t highResScrollX = xAxisMovement * kEvdevMouseHighResScrollUnitsPerDetent;
-    const int32_t highResScrollY = yAxisMovement * kEvdevMouseHighResScrollUnitsPerDetent;
+    const auto highResScrollX =
+            static_cast<int32_t>(xAxisMovement * kEvdevHighResScrollUnitsPerDetent);
+    const auto highResScrollY =
+            static_cast<int32_t>(yAxisMovement * kEvdevHighResScrollUnitsPerDetent);
     bool highResScrollResult =
             writeInputEvent(EV_REL, REL_HWHEEL_HI_RES, highResScrollX, eventTime) &&
             writeInputEvent(EV_REL, REL_WHEEL_HI_RES, highResScrollY, eventTime);
@@ -299,19 +303,19 @@
     // (single mouse wheel click).
     mAccumulatedHighResScrollX += highResScrollX;
     mAccumulatedHighResScrollY += highResScrollY;
-    const int32_t scrollX = mAccumulatedHighResScrollX / kEvdevMouseHighResScrollUnitsPerDetent;
-    const int32_t scrollY = mAccumulatedHighResScrollY / kEvdevMouseHighResScrollUnitsPerDetent;
+    const int32_t scrollX = mAccumulatedHighResScrollX / kEvdevHighResScrollUnitsPerDetent;
+    const int32_t scrollY = mAccumulatedHighResScrollY / kEvdevHighResScrollUnitsPerDetent;
     if (scrollX != 0) {
         if (!writeInputEvent(EV_REL, REL_HWHEEL, scrollX, eventTime)) {
             return false;
         }
-        mAccumulatedHighResScrollX %= kEvdevMouseHighResScrollUnitsPerDetent;
+        mAccumulatedHighResScrollX %= kEvdevHighResScrollUnitsPerDetent;
     }
     if (scrollY != 0) {
         if (!writeInputEvent(EV_REL, REL_WHEEL, scrollY, eventTime)) {
             return false;
         }
-        mAccumulatedHighResScrollY %= kEvdevMouseHighResScrollUnitsPerDetent;
+        mAccumulatedHighResScrollY %= kEvdevHighResScrollUnitsPerDetent;
     }
 
     return writeInputEvent(EV_SYN, SYN_REPORT, 0, eventTime);
@@ -550,14 +554,38 @@
 }
 
 // --- VirtualRotaryEncoder ---
-VirtualRotaryEncoder::VirtualRotaryEncoder(unique_fd fd) : VirtualInputDevice(std::move(fd)) {}
+VirtualRotaryEncoder::VirtualRotaryEncoder(unique_fd fd)
+      : VirtualInputDevice(std::move(fd)), mAccumulatedHighResScrollAmount(0) {}
 
 VirtualRotaryEncoder::~VirtualRotaryEncoder() {}
 
 bool VirtualRotaryEncoder::writeScrollEvent(float scrollAmount,
                                             std::chrono::nanoseconds eventTime) {
-    return writeInputEvent(EV_REL, REL_WHEEL, static_cast<int32_t>(scrollAmount), eventTime) &&
-            writeInputEvent(EV_SYN, SYN_REPORT, 0, eventTime);
+    if (!vd_flags::high_resolution_scroll()) {
+        return writeInputEvent(EV_REL, REL_WHEEL, static_cast<int32_t>(scrollAmount), eventTime) &&
+                writeInputEvent(EV_SYN, SYN_REPORT, 0, eventTime);
+    }
+
+    const auto highResScrollAmount =
+            static_cast<int32_t>(scrollAmount * kEvdevHighResScrollUnitsPerDetent);
+    if (!writeInputEvent(EV_REL, REL_WHEEL_HI_RES, highResScrollAmount, eventTime)) {
+        return false;
+    }
+
+    // According to evdev spec, a high-resolution scroll device needs to emit REL_WHEEL / REL_HWHEEL
+    // events in addition to high-res scroll events. Regular scroll events can approximate high-res
+    // scroll events, so we send a regular scroll event when the accumulated scroll motion reaches a
+    // detent (single wheel click).
+    mAccumulatedHighResScrollAmount += highResScrollAmount;
+    const int32_t scroll = mAccumulatedHighResScrollAmount / kEvdevHighResScrollUnitsPerDetent;
+    if (scroll != 0) {
+        if (!writeInputEvent(EV_REL, REL_WHEEL, scroll, eventTime)) {
+            return false;
+        }
+        mAccumulatedHighResScrollAmount %= kEvdevHighResScrollUnitsPerDetent;
+    }
+
+    return writeInputEvent(EV_SYN, SYN_REPORT, 0, eventTime);
 }
 
 } // namespace android
diff --git a/libs/input/input_flags.aconfig b/libs/input/input_flags.aconfig
index a2192cb..cbe021b 100644
--- a/libs/input/input_flags.aconfig
+++ b/libs/input/input_flags.aconfig
@@ -15,13 +15,6 @@
   bug: "271455682"
 }
 
-flag {
-  name: "enable_gestures_library_timer_provider"
-  namespace: "input"
-  description: "Set to true to enable timer support for the touchpad Gestures library"
-  bug: "297192727"
- }
-
  flag {
   name: "enable_input_event_tracing"
   namespace: "input"
@@ -87,13 +80,6 @@
 }
 
 flag {
-  name: "remove_pointer_event_tracking_in_wm"
-  namespace: "input"
-  description: "Remove pointer event tracking in WM after the Pointer Icon Refactor"
-  bug: "315321016"
-}
-
-flag {
   name: "enable_new_mouse_pointer_ballistics"
   namespace: "input"
   description: "Change the acceleration curves for mouse pointer movements to match the touchpad ones"
diff --git a/libs/nativewindow/AHardwareBuffer.cpp b/libs/nativewindow/AHardwareBuffer.cpp
index 5261287..dd78049 100644
--- a/libs/nativewindow/AHardwareBuffer.cpp
+++ b/libs/nativewindow/AHardwareBuffer.cpp
@@ -300,7 +300,9 @@
       if (result == 0) {
         outPlanes->planeCount = 3;
         outPlanes->planes[0].data = yuvData.y;
-        if (format == AHARDWAREBUFFER_FORMAT_YCbCr_P010) {
+        // P010 is word-aligned 10-bit semiplaner, and YCbCr_422_I is a single interleaved plane
+        if (format == AHARDWAREBUFFER_FORMAT_YCbCr_P010 ||
+            format == AHARDWAREBUFFER_FORMAT_YCbCr_422_I) {
             outPlanes->planes[0].pixelStride = 2;
         } else {
             outPlanes->planes[0].pixelStride = 1;
diff --git a/libs/tracing_perfetto/Android.bp b/libs/tracing_perfetto/Android.bp
index 3a4c869..b5c56c5 100644
--- a/libs/tracing_perfetto/Android.bp
+++ b/libs/tracing_perfetto/Android.bp
@@ -40,6 +40,7 @@
     ],
 
     shared_libs: [
+        "libbase",
         "libcutils",
         "libperfetto_c",
         "android.os.flags-aconfig-cc-host",
diff --git a/libs/tracing_perfetto/include/trace_result.h b/libs/tracing_perfetto/include/trace_result.h
deleted file mode 100644
index f7581fc..0000000
--- a/libs/tracing_perfetto/include/trace_result.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef TRACE_RESULT_H
-#define TRACE_RESULT_H
-
-namespace tracing_perfetto {
-
-enum class Result {
-  SUCCESS,
-  NOT_SUPPORTED,
-  INVALID_INPUT,
-};
-
-}
-
-#endif  // TRACE_RESULT_H
diff --git a/libs/tracing_perfetto/include/tracing_perfetto.h b/libs/tracing_perfetto/include/tracing_perfetto.h
index 2c1c2a4..0b2b0af 100644
--- a/libs/tracing_perfetto/include/tracing_perfetto.h
+++ b/libs/tracing_perfetto/include/tracing_perfetto.h
@@ -19,35 +19,32 @@
 
 #include <stdint.h>
 
-#include "trace_result.h"
-
 namespace tracing_perfetto {
 
 void registerWithPerfetto(bool test = false);
 
-Result traceBegin(uint64_t category, const char* name);
+void traceBegin(uint64_t category, const char* name);
 
-Result traceEnd(uint64_t category);
+void traceEnd(uint64_t category);
 
-Result traceAsyncBegin(uint64_t category, const char* name, int32_t cookie);
+void traceAsyncBegin(uint64_t category, const char* name, int32_t cookie);
 
-Result traceAsyncEnd(uint64_t category, const char* name, int32_t cookie);
+void traceAsyncEnd(uint64_t category, const char* name, int32_t cookie);
 
-Result traceAsyncBeginForTrack(uint64_t category, const char* name,
+void traceAsyncBeginForTrack(uint64_t category, const char* name,
                                const char* trackName, int32_t cookie);
 
-Result traceAsyncEndForTrack(uint64_t category, const char* trackName,
+void traceAsyncEndForTrack(uint64_t category, const char* trackName,
                              int32_t cookie);
 
-Result traceInstant(uint64_t category, const char* name);
+void traceInstant(uint64_t category, const char* name);
 
-Result traceInstantForTrack(uint64_t category, const char* trackName,
+void traceInstantForTrack(uint64_t category, const char* trackName,
                             const char* name);
 
-Result traceCounter(uint64_t category, const char* name, int64_t value);
+void traceCounter(uint64_t category, const char* name, int64_t value);
 
 bool isTagEnabled(uint64_t category);
-
 }  // namespace tracing_perfetto
 
 #endif  // TRACING_PERFETTO_H
diff --git a/libs/tracing_perfetto/tests/Android.bp b/libs/tracing_perfetto/tests/Android.bp
index a35b0e0..d203467 100644
--- a/libs/tracing_perfetto/tests/Android.bp
+++ b/libs/tracing_perfetto/tests/Android.bp
@@ -26,6 +26,7 @@
     static_libs: [
         "libflagtest",
         "libgmock",
+        "perfetto_trace_protos",
     ],
     cflags: [
         "-Wall",
@@ -35,6 +36,8 @@
         "android.os.flags-aconfig-cc-host",
         "libbase",
         "libperfetto_c",
+        "liblog",
+        "libprotobuf-cpp-lite",
         "libtracing_perfetto",
     ],
     srcs: [
diff --git a/libs/tracing_perfetto/tests/tracing_perfetto_test.cpp b/libs/tracing_perfetto/tests/tracing_perfetto_test.cpp
index 7716b9a..e9fee2e 100644
--- a/libs/tracing_perfetto/tests/tracing_perfetto_test.cpp
+++ b/libs/tracing_perfetto/tests/tracing_perfetto_test.cpp
@@ -16,10 +16,10 @@
 
 #include "tracing_perfetto.h"
 
-#include <thread>
-
 #include <android_os.h>
 #include <flag_macros.h>
+#include <thread>
+#include <unistd.h>
 
 #include "gtest/gtest.h"
 #include "perfetto/public/abi/data_source_abi.h"
@@ -45,67 +45,182 @@
 #include "trace_categories.h"
 #include "utils.h"
 
+#include "protos/perfetto/trace/trace.pb.h"
+#include "protos/perfetto/trace/trace_packet.pb.h"
+#include "protos/perfetto/trace/interned_data/interned_data.pb.h"
+
+#include <fstream>
+#include <iterator>
 namespace tracing_perfetto {
 
-using ::perfetto::shlib::test_utils::AllFieldsWithId;
-using ::perfetto::shlib::test_utils::FieldView;
-using ::perfetto::shlib::test_utils::IdFieldView;
-using ::perfetto::shlib::test_utils::MsgField;
-using ::perfetto::shlib::test_utils::PbField;
-using ::perfetto::shlib::test_utils::StringField;
+using ::perfetto::protos::Trace;
+using ::perfetto::protos::TracePacket;
+using ::perfetto::protos::EventCategory;
+using ::perfetto::protos::EventName;
+using ::perfetto::protos::FtraceEvent;
+using ::perfetto::protos::FtraceEventBundle;
+using ::perfetto::protos::InternedData;
+
 using ::perfetto::shlib::test_utils::TracingSession;
-using ::perfetto::shlib::test_utils::VarIntField;
-using ::testing::_;
-using ::testing::ElementsAre;
-using ::testing::UnorderedElementsAre;
 
 const auto PERFETTO_SDK_TRACING = ACONFIG_FLAG(android::os, perfetto_sdk_tracing);
 
+// TODO(b/303199244): Add tests for all the library functions.
 class TracingPerfettoTest : public testing::Test {
  protected:
   void SetUp() override {
-    tracing_perfetto::registerWithPerfetto(true /* test */);
+    tracing_perfetto::registerWithPerfetto(false /* test */);
   }
 };
 
-// TODO(b/303199244): Add tests for all the library functions.
-
-TEST_F_WITH_FLAGS(TracingPerfettoTest, traceInstant,
-                  REQUIRES_FLAGS_ENABLED(PERFETTO_SDK_TRACING)) {
-  TracingSession tracing_session =
-      TracingSession::Builder().set_data_source_name("track_event").Build();
-  tracing_perfetto::traceInstant(TRACE_CATEGORY_INPUT, "");
-
+Trace stopSession(TracingSession& tracing_session) {
+  tracing_session.FlushBlocking(5000);
   tracing_session.StopBlocking();
   std::vector<uint8_t> data = tracing_session.ReadBlocking();
+  std::string data_string(data.begin(), data.end());
+
+  perfetto::protos::Trace trace;
+  trace.ParseFromString(data_string);
+
+  return trace;
+}
+
+void verifyTrackEvent(const Trace& trace, const std::string expected_category,
+                      const std::string& expected_name) {
   bool found = false;
-  for (struct PerfettoPbDecoderField trace_field : FieldView(data)) {
-    ASSERT_THAT(trace_field, PbField(perfetto_protos_Trace_packet_field_number,
-                                     MsgField(_)));
-    IdFieldView track_event(
-        trace_field, perfetto_protos_TracePacket_track_event_field_number);
-    if (track_event.size() == 0) {
-      continue;
+  for (const TracePacket& packet: trace.packet()) {
+    if (packet.has_track_event() && packet.has_interned_data()) {
+
+      const InternedData& interned_data = packet.interned_data();
+      if (interned_data.event_categories_size() > 0) {
+        const EventCategory& event_category = packet.interned_data().event_categories(0);
+        if (event_category.name() == expected_category) {
+          found = true;
+        }
+      }
+
+      if (interned_data.event_names_size() > 0) {
+        const EventName& event_name = packet.interned_data().event_names(0);
+        if (event_name.name() == expected_name) {
+          found &= true;
+        }
+      }
+
+      if (found) {
+        break;
+      }
     }
-    found = true;
-    IdFieldView cat_iid_fields(
-        track_event.front(),
-        perfetto_protos_TrackEvent_category_iids_field_number);
-    ASSERT_THAT(cat_iid_fields, ElementsAre(VarIntField(_)));
-    uint64_t cat_iid = cat_iid_fields.front().value.integer64;
-    EXPECT_THAT(
-        trace_field,
-        AllFieldsWithId(
-            perfetto_protos_TracePacket_interned_data_field_number,
-            ElementsAre(AllFieldsWithId(
-                perfetto_protos_InternedData_event_categories_field_number,
-                ElementsAre(MsgField(UnorderedElementsAre(
-                    PbField(perfetto_protos_EventCategory_iid_field_number,
-                            VarIntField(cat_iid)),
-                    PbField(perfetto_protos_EventCategory_name_field_number,
-                            StringField("input")))))))));
   }
   EXPECT_TRUE(found);
 }
 
-}  // namespace tracing_perfetto
\ No newline at end of file
+void verifyAtraceEvent(const Trace& trace, const std::string& expected_name) {
+  std::string expected_print_buf = "I|" + std::to_string(gettid()) + "|" + expected_name + "\n";
+
+  bool found = false;
+  for (const TracePacket& packet: trace.packet()) {
+    if (packet.has_ftrace_events()) {
+      const FtraceEventBundle& ftrace_events_bundle = packet.ftrace_events();
+
+      if (ftrace_events_bundle.event_size() > 0) {
+        const FtraceEvent& ftrace_event = ftrace_events_bundle.event(0);
+        if (ftrace_event.has_print() && (ftrace_event.print().buf() == expected_print_buf)) {
+          found = true;
+          break;
+        }
+      }
+    }
+  }
+  EXPECT_TRUE(found);
+}
+
+TEST_F_WITH_FLAGS(TracingPerfettoTest, traceInstantWithPerfetto,
+                  REQUIRES_FLAGS_ENABLED(PERFETTO_SDK_TRACING)) {
+  std::string event_category = "input";
+  std::string event_name = "traceInstantWithPerfetto";
+
+  TracingSession tracing_session =
+      TracingSession::Builder().add_enabled_category(event_category).Build();
+
+  tracing_perfetto::traceInstant(TRACE_CATEGORY_INPUT, event_name.c_str());
+
+  Trace trace = stopSession(tracing_session);
+
+  verifyTrackEvent(trace, event_category, event_name);
+}
+
+TEST_F_WITH_FLAGS(TracingPerfettoTest, traceInstantWithAtrace,
+                  REQUIRES_FLAGS_ENABLED(PERFETTO_SDK_TRACING)) {
+  std::string event_category = "input";
+  std::string event_name = "traceInstantWithAtrace";
+
+  TracingSession tracing_session =
+      TracingSession::Builder().add_atrace_category(event_category).Build();
+
+  tracing_perfetto::traceInstant(TRACE_CATEGORY_INPUT, event_name.c_str());
+
+  Trace trace = stopSession(tracing_session);
+
+  verifyAtraceEvent(trace, event_name);
+}
+
+TEST_F_WITH_FLAGS(TracingPerfettoTest, traceInstantWithPerfettoAndAtrace,
+                  REQUIRES_FLAGS_ENABLED(PERFETTO_SDK_TRACING)) {
+  std::string event_category = "input";
+  std::string event_name = "traceInstantWithPerfettoAndAtrace";
+
+  TracingSession tracing_session =
+      TracingSession::Builder()
+      .add_atrace_category(event_category)
+      .add_enabled_category(event_category).Build();
+
+  tracing_perfetto::traceInstant(TRACE_CATEGORY_INPUT, event_name.c_str());
+
+  Trace trace = stopSession(tracing_session);
+
+  verifyAtraceEvent(trace, event_name);
+}
+
+TEST_F_WITH_FLAGS(TracingPerfettoTest, traceInstantWithPerfettoAndAtraceAndPreferTrackEvent,
+                  REQUIRES_FLAGS_ENABLED(PERFETTO_SDK_TRACING)) {
+  std::string event_category = "input";
+  std::string event_name = "traceInstantWithPerfettoAndAtraceAndPreferTrackEvent";
+
+  TracingSession tracing_session =
+      TracingSession::Builder()
+      .add_atrace_category(event_category)
+      .add_atrace_category_prefer_sdk(event_category)
+      .add_enabled_category(event_category).Build();
+
+  tracing_perfetto::traceInstant(TRACE_CATEGORY_INPUT, event_name.c_str());
+
+  Trace trace = stopSession(tracing_session);
+
+  verifyTrackEvent(trace, event_category, event_name);
+}
+
+TEST_F_WITH_FLAGS(TracingPerfettoTest, traceInstantWithPerfettoAndAtraceConcurrently,
+                  REQUIRES_FLAGS_ENABLED(PERFETTO_SDK_TRACING)) {
+  std::string event_category = "input";
+  std::string event_name = "traceInstantWithPerfettoAndAtraceConcurrently";
+
+  TracingSession perfetto_tracing_session =
+      TracingSession::Builder()
+      .add_atrace_category(event_category)
+      .add_atrace_category_prefer_sdk(event_category)
+      .add_enabled_category(event_category).Build();
+
+  TracingSession atrace_tracing_session =
+      TracingSession::Builder()
+      .add_atrace_category(event_category)
+      .add_enabled_category(event_category).Build();
+
+  tracing_perfetto::traceInstant(TRACE_CATEGORY_INPUT, event_name.c_str());
+
+  Trace atrace_trace = stopSession(atrace_tracing_session);
+  Trace perfetto_trace = stopSession(perfetto_tracing_session);
+
+  verifyAtraceEvent(atrace_trace, event_name);
+  verifyAtraceEvent(perfetto_trace, event_name);
+}
+}  // namespace tracing_perfetto
diff --git a/libs/tracing_perfetto/tests/utils.cpp b/libs/tracing_perfetto/tests/utils.cpp
index 9c42028..8c4d4a8 100644
--- a/libs/tracing_perfetto/tests/utils.cpp
+++ b/libs/tracing_perfetto/tests/utils.cpp
@@ -26,6 +26,11 @@
 #include "perfetto/public/protos/config/track_event/track_event_config.pzc.h"
 #include "perfetto/public/tracing_session.h"
 
+#include "protos/perfetto/config/ftrace/ftrace_config.pb.h"
+#include "protos/perfetto/config/track_event/track_event_config.pb.h"
+#include "protos/perfetto/config/data_source_config.pb.h"
+#include "protos/perfetto/config/trace_config.pb.h"
+
 namespace perfetto {
 namespace shlib {
 namespace test_utils {
@@ -44,63 +49,54 @@
 }  // namespace
 
 TracingSession TracingSession::Builder::Build() {
-  struct PerfettoPbMsgWriter writer;
-  struct PerfettoHeapBuffer* hb = PerfettoHeapBufferCreate(&writer.writer);
+  perfetto::protos::TraceConfig trace_config;
+  trace_config.add_buffers()->set_size_kb(1024);
 
-  struct perfetto_protos_TraceConfig cfg;
-  PerfettoPbMsgInit(&cfg.msg, &writer);
+  auto* track_event_ds_config = trace_config.add_data_sources()->mutable_config();
+  auto* ftrace_ds_config = trace_config.add_data_sources()->mutable_config();
+
+  track_event_ds_config->set_name("track_event");
+  track_event_ds_config->set_target_buffer(0);
+
+  ftrace_ds_config->set_name("linux.ftrace");
+  ftrace_ds_config->set_target_buffer(0);
 
   {
-    struct perfetto_protos_TraceConfig_BufferConfig buffers;
-    perfetto_protos_TraceConfig_begin_buffers(&cfg, &buffers);
-
-    perfetto_protos_TraceConfig_BufferConfig_set_size_kb(&buffers, 1024);
-
-    perfetto_protos_TraceConfig_end_buffers(&cfg, &buffers);
-  }
-
-  {
-    struct perfetto_protos_TraceConfig_DataSource data_sources;
-    perfetto_protos_TraceConfig_begin_data_sources(&cfg, &data_sources);
-
-    {
-      struct perfetto_protos_DataSourceConfig ds_cfg;
-      perfetto_protos_TraceConfig_DataSource_begin_config(&data_sources,
-                                                          &ds_cfg);
-
-      perfetto_protos_DataSourceConfig_set_cstr_name(&ds_cfg,
-                                                     data_source_name_.c_str());
-      if (!enabled_categories_.empty() && !disabled_categories_.empty()) {
-        perfetto_protos_TrackEventConfig te_cfg;
-        perfetto_protos_DataSourceConfig_begin_track_event_config(&ds_cfg,
-                                                                  &te_cfg);
-        for (const std::string& cat : enabled_categories_) {
-          perfetto_protos_TrackEventConfig_set_enabled_categories(
-              &te_cfg, cat.data(), cat.size());
-        }
-        for (const std::string& cat : disabled_categories_) {
-          perfetto_protos_TrackEventConfig_set_disabled_categories(
-              &te_cfg, cat.data(), cat.size());
-        }
-        perfetto_protos_DataSourceConfig_end_track_event_config(&ds_cfg,
-                                                                &te_cfg);
+    auto* ftrace_config = ftrace_ds_config->mutable_ftrace_config();
+    if (!atrace_categories_.empty()) {
+      ftrace_config->add_ftrace_events("ftrace/print");
+      for (const std::string& cat : atrace_categories_) {
+        ftrace_config->add_atrace_categories(cat);
       }
 
-      perfetto_protos_TraceConfig_DataSource_end_config(&data_sources, &ds_cfg);
+      for (const std::string& cat : atrace_categories_prefer_sdk_) {
+        ftrace_config->add_atrace_categories_prefer_sdk(cat);
+      }
     }
-
-    perfetto_protos_TraceConfig_end_data_sources(&cfg, &data_sources);
   }
-  size_t cfg_size = PerfettoStreamWriterGetWrittenSize(&writer.writer);
-  std::unique_ptr<uint8_t[]> ser(new uint8_t[cfg_size]);
-  PerfettoHeapBufferCopyInto(hb, &writer.writer, ser.get(), cfg_size);
-  PerfettoHeapBufferDestroy(hb, &writer.writer);
+
+  {
+    auto* track_event_config = track_event_ds_config->mutable_track_event_config();
+    if (!enabled_categories_.empty() || !disabled_categories_.empty()) {
+      for (const std::string& cat : enabled_categories_) {
+        track_event_config->add_enabled_categories(cat);
+      }
+
+      for (const std::string& cat : disabled_categories_) {
+        track_event_config->add_disabled_categories(cat);
+      }
+    }
+  }
 
   struct PerfettoTracingSessionImpl* ts =
-      PerfettoTracingSessionCreate(PERFETTO_BACKEND_IN_PROCESS);
+      PerfettoTracingSessionCreate(PERFETTO_BACKEND_SYSTEM);
 
-  PerfettoTracingSessionSetup(ts, ser.get(), cfg_size);
+  std::string trace_config_string;
+  trace_config.SerializeToString(&trace_config_string);
 
+  PerfettoTracingSessionSetup(ts, trace_config_string.data(), trace_config_string.length());
+
+  // Fails to start here
   PerfettoTracingSessionStartBlocking(ts);
 
   return TracingSession::Adopt(ts);
diff --git a/libs/tracing_perfetto/tests/utils.h b/libs/tracing_perfetto/tests/utils.h
index 4353554..8edb414 100644
--- a/libs/tracing_perfetto/tests/utils.h
+++ b/libs/tracing_perfetto/tests/utils.h
@@ -74,10 +74,6 @@
   class Builder {
    public:
     Builder() = default;
-    Builder& set_data_source_name(std::string data_source_name) {
-      data_source_name_ = std::move(data_source_name);
-      return *this;
-    }
     Builder& add_enabled_category(std::string category) {
       enabled_categories_.push_back(std::move(category));
       return *this;
@@ -86,12 +82,21 @@
       disabled_categories_.push_back(std::move(category));
       return *this;
     }
+    Builder& add_atrace_category(std::string category) {
+      atrace_categories_.push_back(std::move(category));
+      return *this;
+    }
+    Builder& add_atrace_category_prefer_sdk(std::string category) {
+      atrace_categories_prefer_sdk_.push_back(std::move(category));
+      return *this;
+    }
     TracingSession Build();
 
    private:
-    std::string data_source_name_;
     std::vector<std::string> enabled_categories_;
     std::vector<std::string> disabled_categories_;
+    std::vector<std::string> atrace_categories_;
+    std::vector<std::string> atrace_categories_prefer_sdk_;
   };
 
   static TracingSession Adopt(struct PerfettoTracingSessionImpl*);
diff --git a/libs/tracing_perfetto/tracing_perfetto.cpp b/libs/tracing_perfetto/tracing_perfetto.cpp
index 6f716ee..fc5336d 100644
--- a/libs/tracing_perfetto/tracing_perfetto.cpp
+++ b/libs/tracing_perfetto/tracing_perfetto.cpp
@@ -28,116 +28,112 @@
   internal::registerWithPerfetto(test);
 }
 
-Result traceBegin(uint64_t category, const char* name) {
+void traceBegin(uint64_t category, const char* name) {
   struct PerfettoTeCategory* perfettoTeCategory =
       internal::toPerfettoCategory(category);
-  if (perfettoTeCategory != nullptr) {
-    return internal::perfettoTraceBegin(*perfettoTeCategory, name);
-  } else {
+
+  if (internal::shouldPreferAtrace(perfettoTeCategory, category)) {
     atrace_begin(category, name);
-    return Result::SUCCESS;
+  } else if (internal::isPerfettoCategoryEnabled(perfettoTeCategory)) {
+    internal::perfettoTraceBegin(*perfettoTeCategory, name);
   }
 }
 
-Result traceEnd(uint64_t category) {
+void traceEnd(uint64_t category) {
   struct PerfettoTeCategory* perfettoTeCategory =
       internal::toPerfettoCategory(category);
-  if (perfettoTeCategory != nullptr) {
-    return internal::perfettoTraceEnd(*perfettoTeCategory);
-  } else {
+
+  if (internal::shouldPreferAtrace(perfettoTeCategory, category)) {
     atrace_end(category);
-    return Result::SUCCESS;
+  } else if (internal::isPerfettoCategoryEnabled(perfettoTeCategory)) {
+    internal::perfettoTraceEnd(*perfettoTeCategory);
   }
 }
 
-Result traceAsyncBegin(uint64_t category, const char* name, int32_t cookie) {
+void traceAsyncBegin(uint64_t category, const char* name, int32_t cookie) {
   struct PerfettoTeCategory* perfettoTeCategory =
       internal::toPerfettoCategory(category);
-  if (perfettoTeCategory != nullptr) {
-    return internal::perfettoTraceAsyncBegin(*perfettoTeCategory, name, cookie);
-  } else {
+
+  if (internal::shouldPreferAtrace(perfettoTeCategory, category)) {
     atrace_async_begin(category, name, cookie);
-    return Result::SUCCESS;
+  } else if (internal::isPerfettoCategoryEnabled(perfettoTeCategory)) {
+    internal::perfettoTraceAsyncBegin(*perfettoTeCategory, name, cookie);
   }
 }
 
-Result traceAsyncEnd(uint64_t category, const char* name, int32_t cookie) {
+void traceAsyncEnd(uint64_t category, const char* name, int32_t cookie) {
   struct PerfettoTeCategory* perfettoTeCategory =
       internal::toPerfettoCategory(category);
-  if (perfettoTeCategory != nullptr) {
-    return internal::perfettoTraceAsyncEnd(*perfettoTeCategory, name, cookie);
-  } else {
+
+  if (internal::shouldPreferAtrace(perfettoTeCategory, category)) {
     atrace_async_end(category, name, cookie);
-    return Result::SUCCESS;
+  } else if (internal::isPerfettoCategoryEnabled(perfettoTeCategory)) {
+    internal::perfettoTraceAsyncEnd(*perfettoTeCategory, name, cookie);
   }
 }
 
-Result traceAsyncBeginForTrack(uint64_t category, const char* name,
+void traceAsyncBeginForTrack(uint64_t category, const char* name,
                                const char* trackName, int32_t cookie) {
   struct PerfettoTeCategory* perfettoTeCategory =
       internal::toPerfettoCategory(category);
-  if (perfettoTeCategory != nullptr) {
-    return internal::perfettoTraceAsyncBeginForTrack(*perfettoTeCategory, name, trackName, cookie);
-  } else {
+
+  if (internal::shouldPreferAtrace(perfettoTeCategory, category)) {
     atrace_async_for_track_begin(category, trackName, name, cookie);
-    return Result::SUCCESS;
+  } else if (internal::isPerfettoCategoryEnabled(perfettoTeCategory)) {
+    internal::perfettoTraceAsyncBeginForTrack(*perfettoTeCategory, name, trackName, cookie);
   }
 }
 
-Result traceAsyncEndForTrack(uint64_t category, const char* trackName,
+void traceAsyncEndForTrack(uint64_t category, const char* trackName,
                              int32_t cookie) {
   struct PerfettoTeCategory* perfettoTeCategory =
       internal::toPerfettoCategory(category);
-  if (perfettoTeCategory != nullptr) {
-    return internal::perfettoTraceAsyncEndForTrack(*perfettoTeCategory, trackName, cookie);
-  } else {
+
+  if (internal::shouldPreferAtrace(perfettoTeCategory, category)) {
     atrace_async_for_track_end(category, trackName, cookie);
-    return Result::SUCCESS;
+  } else if (internal::isPerfettoCategoryEnabled(perfettoTeCategory)) {
+    internal::perfettoTraceAsyncEndForTrack(*perfettoTeCategory, trackName, cookie);
   }
 }
 
-Result traceInstant(uint64_t category, const char* name) {
+void traceInstant(uint64_t category, const char* name) {
   struct PerfettoTeCategory* perfettoTeCategory =
       internal::toPerfettoCategory(category);
-  if (perfettoTeCategory != nullptr) {
-    return internal::perfettoTraceInstant(*perfettoTeCategory, name);
-  } else {
+
+  if (internal::shouldPreferAtrace(perfettoTeCategory, category)) {
     atrace_instant(category, name);
-    return Result::SUCCESS;
+  } else if (internal::isPerfettoCategoryEnabled(perfettoTeCategory)) {
+    internal::perfettoTraceInstant(*perfettoTeCategory, name);
   }
 }
 
-Result traceInstantForTrack(uint64_t category, const char* trackName,
+void traceInstantForTrack(uint64_t category, const char* trackName,
                             const char* name) {
   struct PerfettoTeCategory* perfettoTeCategory =
       internal::toPerfettoCategory(category);
-  if (perfettoTeCategory != nullptr) {
-    return internal::perfettoTraceInstantForTrack(*perfettoTeCategory, trackName, name);
-  } else {
+
+  if (internal::shouldPreferAtrace(perfettoTeCategory, category)) {
     atrace_instant_for_track(category, trackName, name);
-    return Result::SUCCESS;
+  } else if (internal::isPerfettoCategoryEnabled(perfettoTeCategory)) {
+    internal::perfettoTraceInstantForTrack(*perfettoTeCategory, trackName, name);
   }
 }
 
-Result traceCounter(uint64_t category, const char* name, int64_t value) {
+void traceCounter(uint64_t category, const char* name, int64_t value) {
   struct PerfettoTeCategory* perfettoTeCategory =
       internal::toPerfettoCategory(category);
-  if (perfettoTeCategory != nullptr) {
-    return internal::perfettoTraceCounter(*perfettoTeCategory, name, value);
-  } else {
+
+  if (internal::shouldPreferAtrace(perfettoTeCategory, category)) {
     atrace_int64(category, name, value);
-    return Result::SUCCESS;
+  } else if (internal::isPerfettoCategoryEnabled(perfettoTeCategory)) {
+    internal::perfettoTraceCounter(*perfettoTeCategory, name, value);
   }
 }
 
 bool isTagEnabled(uint64_t category) {
   struct PerfettoTeCategory* perfettoTeCategory =
       internal::toPerfettoCategory(category);
-  if (perfettoTeCategory != nullptr) {
-    return true;
-  } else {
-    return (atrace_get_enabled_tags() & category) != 0;
-  }
+  return internal::isPerfettoCategoryEnabled(perfettoTeCategory)
+      || atrace_is_tag_enabled(category);
 }
-
 }  // namespace tracing_perfetto
diff --git a/libs/tracing_perfetto/tracing_perfetto_internal.cpp b/libs/tracing_perfetto/tracing_perfetto_internal.cpp
index 758ace6..9a0042a 100644
--- a/libs/tracing_perfetto/tracing_perfetto_internal.cpp
+++ b/libs/tracing_perfetto/tracing_perfetto_internal.cpp
@@ -44,13 +44,13 @@
   C(rro, "rro", "RRO category")                                  \
   C(thermal, "thermal", "Thermal category")
 
-#include "tracing_perfetto_internal.h"
-
-#include <inttypes.h>
-
+#include <atomic>
 #include <mutex>
 
 #include <android_os.h>
+#include <android-base/properties.h>
+#include <cutils/trace.h>
+#include <inttypes.h>
 
 #include "perfetto/public/compiler.h"
 #include "perfetto/public/producer.h"
@@ -58,19 +58,42 @@
 #include "perfetto/public/te_macros.h"
 #include "perfetto/public/track_event.h"
 #include "trace_categories.h"
-#include "trace_result.h"
+#include "tracing_perfetto_internal.h"
+
+#ifdef __BIONIC__
+#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
+#include <sys/_system_properties.h>
+#endif
 
 namespace tracing_perfetto {
 
 namespace internal {
 
 namespace {
-
 PERFETTO_TE_CATEGORIES_DECLARE(FRAMEWORK_CATEGORIES);
 
 PERFETTO_TE_CATEGORIES_DEFINE(FRAMEWORK_CATEGORIES);
 
-std::atomic_bool is_perfetto_registered = false;
+static constexpr char kPreferFlagProperty[] = "debug.atrace.prefer_sdk";
+static std::atomic<const prop_info*> prefer_property_info = nullptr;
+static std::atomic_uint32_t last_prefer_seq_num = 0;
+static std::atomic_uint64_t prefer_flags = 0;
+
+static const prop_info* system_property_find(const char* name [[maybe_unused]]) {
+  #ifdef __BIONIC__
+  return __system_property_find(name);
+  #endif
+
+  return nullptr;
+}
+
+static uint32_t system_property_serial(const prop_info* pi [[maybe_unused]]) {
+  #ifdef __BIONIC__
+  return __system_property_serial(pi);
+  #endif
+
+  return last_prefer_seq_num;
+}
 
 struct PerfettoTeCategory* toCategory(uint64_t inCategory) {
   switch (inCategory) {
@@ -137,8 +160,60 @@
 
 }  // namespace
 
-bool isPerfettoRegistered() {
-  return is_perfetto_registered;
+bool isPerfettoCategoryEnabled(PerfettoTeCategory* category) {
+  return category != nullptr;
+}
+
+/**
+ * Updates the cached |prefer_flags|.
+ *
+ * We cache the prefer_flags because reading it on every trace event is expensive.
+ * The cache is invalidated when a sys_prop sequence number changes.
+ */
+void updatePreferFlags() {
+  if (!prefer_property_info.load(std::memory_order_acquire)) {
+    auto* new_prefer_property_info = system_property_find(kPreferFlagProperty);
+    prefer_flags.store(android::base::GetIntProperty(kPreferFlagProperty, 0),
+                       std::memory_order_relaxed);
+
+    if (!new_prefer_property_info) {
+      // This should never happen. If it does, we fail gracefully and end up reading the property
+      // traced event.
+      return;
+    }
+
+    last_prefer_seq_num = system_property_serial(new_prefer_property_info);
+    prefer_property_info.store(new_prefer_property_info, std::memory_order_release);
+  }
+
+  uint32_t prefer_seq_num =  system_property_serial(prefer_property_info);
+  if (prefer_seq_num != last_prefer_seq_num.load(std::memory_order_acquire)) {
+    prefer_flags.store(android::base::GetIntProperty(kPreferFlagProperty, 0),
+                       std::memory_order_relaxed);
+    last_prefer_seq_num.store(prefer_seq_num, std::memory_order_release);
+  }
+}
+
+bool shouldPreferAtrace(PerfettoTeCategory *perfettoCategory, uint64_t atraceCategory) {
+  // There are 3 cases:
+  // 1. Atrace is not enabled.
+  if (!atrace_is_tag_enabled(atraceCategory)) {
+    return false;
+  }
+
+  // 2. Atrace is enabled but perfetto is not enabled.
+  if (!isPerfettoCategoryEnabled(perfettoCategory)) {
+    return true;
+  }
+
+  // Update prefer_flags before checking it below
+  updatePreferFlags();
+
+  // 3. Atrace and perfetto are enabled.
+  // Even though this category is enabled for track events, the config mandates that we downgrade
+  // it to atrace if the same atrace category is currently enabled. This prevents missing the
+  // event from a concurrent session that needs the same category in atrace.
+  return (atraceCategory & prefer_flags.load(std::memory_order_relaxed)) == 0;
 }
 
 struct PerfettoTeCategory* toPerfettoCategory(uint64_t category) {
@@ -148,7 +223,7 @@
   }
 
   bool enabled = PERFETTO_UNLIKELY(PERFETTO_ATOMIC_LOAD_EXPLICIT(
-      (*perfettoCategory).enabled, PERFETTO_MEMORY_ORDER_RELAXED));
+       (*perfettoCategory).enabled, PERFETTO_MEMORY_ORDER_RELAXED));
   return enabled ? perfettoCategory : nullptr;
 }
 
@@ -164,70 +239,57 @@
     PerfettoProducerInit(args);
     PerfettoTeInit();
     PERFETTO_TE_REGISTER_CATEGORIES(FRAMEWORK_CATEGORIES);
-    is_perfetto_registered = true;
   });
 }
 
-Result perfettoTraceBegin(const struct PerfettoTeCategory& category, const char* name) {
+void perfettoTraceBegin(const struct PerfettoTeCategory& category, const char* name) {
   PERFETTO_TE(category, PERFETTO_TE_SLICE_BEGIN(name));
-  return Result::SUCCESS;
 }
 
-Result perfettoTraceEnd(const struct PerfettoTeCategory& category) {
+void perfettoTraceEnd(const struct PerfettoTeCategory& category) {
   PERFETTO_TE(category, PERFETTO_TE_SLICE_END());
-  return Result::SUCCESS;
 }
 
-Result perfettoTraceAsyncBeginForTrack(const struct PerfettoTeCategory& category, const char* name,
+void perfettoTraceAsyncBeginForTrack(const struct PerfettoTeCategory& category, const char* name,
                                        const char* trackName, uint64_t cookie) {
   PERFETTO_TE(
       category, PERFETTO_TE_SLICE_BEGIN(name),
       PERFETTO_TE_NAMED_TRACK(trackName, cookie, PerfettoTeProcessTrackUuid()));
-  return Result::SUCCESS;
 }
 
-Result perfettoTraceAsyncEndForTrack(const struct PerfettoTeCategory& category,
+void perfettoTraceAsyncEndForTrack(const struct PerfettoTeCategory& category,
                                      const char* trackName, uint64_t cookie) {
   PERFETTO_TE(
       category, PERFETTO_TE_SLICE_END(),
       PERFETTO_TE_NAMED_TRACK(trackName, cookie, PerfettoTeProcessTrackUuid()));
-  return Result::SUCCESS;
 }
 
-Result perfettoTraceAsyncBegin(const struct PerfettoTeCategory& category, const char* name,
+void perfettoTraceAsyncBegin(const struct PerfettoTeCategory& category, const char* name,
                                uint64_t cookie) {
-  return perfettoTraceAsyncBeginForTrack(category, name, name, cookie);
+  perfettoTraceAsyncBeginForTrack(category, name, name, cookie);
 }
 
-Result perfettoTraceAsyncEnd(const struct PerfettoTeCategory& category, const char* name,
+void perfettoTraceAsyncEnd(const struct PerfettoTeCategory& category, const char* name,
                              uint64_t cookie) {
-  return perfettoTraceAsyncEndForTrack(category, name, cookie);
+  perfettoTraceAsyncEndForTrack(category, name, cookie);
 }
 
-Result perfettoTraceInstant(const struct PerfettoTeCategory& category, const char* name) {
+void perfettoTraceInstant(const struct PerfettoTeCategory& category, const char* name) {
   PERFETTO_TE(category, PERFETTO_TE_INSTANT(name));
-  return Result::SUCCESS;
 }
 
-Result perfettoTraceInstantForTrack(const struct PerfettoTeCategory& category,
+void perfettoTraceInstantForTrack(const struct PerfettoTeCategory& category,
                                     const char* trackName, const char* name) {
   PERFETTO_TE(
       category, PERFETTO_TE_INSTANT(name),
       PERFETTO_TE_NAMED_TRACK(trackName, 1, PerfettoTeProcessTrackUuid()));
-  return Result::SUCCESS;
 }
 
-Result perfettoTraceCounter(const struct PerfettoTeCategory& category,
+void perfettoTraceCounter(const struct PerfettoTeCategory& category,
                             [[maybe_unused]] const char* name, int64_t value) {
   PERFETTO_TE(category, PERFETTO_TE_COUNTER(),
               PERFETTO_TE_INT_COUNTER(value));
-  return Result::SUCCESS;
 }
-
-uint64_t getDefaultCategories() {
-  return TRACE_CATEGORIES;
-}
-
 }  // namespace internal
 
 }  // namespace tracing_perfetto
diff --git a/libs/tracing_perfetto/tracing_perfetto_internal.h b/libs/tracing_perfetto/tracing_perfetto_internal.h
index 79e4b8f..3e1ac2a 100644
--- a/libs/tracing_perfetto/tracing_perfetto_internal.h
+++ b/libs/tracing_perfetto/tracing_perfetto_internal.h
@@ -19,7 +19,6 @@
 
 #include <stdint.h>
 
-#include "include/trace_result.h"
 #include "perfetto/public/te_category_macros.h"
 
 namespace tracing_perfetto {
@@ -32,31 +31,33 @@
 
 void registerWithPerfetto(bool test = false);
 
-Result perfettoTraceBegin(const struct PerfettoTeCategory& category, const char* name);
+void perfettoTraceBegin(const struct PerfettoTeCategory& category, const char* name);
 
-Result perfettoTraceEnd(const struct PerfettoTeCategory& category);
+void perfettoTraceEnd(const struct PerfettoTeCategory& category);
 
-Result perfettoTraceAsyncBegin(const struct PerfettoTeCategory& category, const char* name,
+void perfettoTraceAsyncBegin(const struct PerfettoTeCategory& category, const char* name,
                                uint64_t cookie);
 
-Result perfettoTraceAsyncEnd(const struct PerfettoTeCategory& category, const char* name,
+void perfettoTraceAsyncEnd(const struct PerfettoTeCategory& category, const char* name,
                              uint64_t cookie);
 
-Result perfettoTraceAsyncBeginForTrack(const struct PerfettoTeCategory& category, const char* name,
+void perfettoTraceAsyncBeginForTrack(const struct PerfettoTeCategory& category, const char* name,
                                        const char* trackName, uint64_t cookie);
 
-Result perfettoTraceAsyncEndForTrack(const struct PerfettoTeCategory& category,
+void perfettoTraceAsyncEndForTrack(const struct PerfettoTeCategory& category,
                                      const char* trackName, uint64_t cookie);
 
-Result perfettoTraceInstant(const struct PerfettoTeCategory& category, const char* name);
+void perfettoTraceInstant(const struct PerfettoTeCategory& category, const char* name);
 
-Result perfettoTraceInstantForTrack(const struct PerfettoTeCategory& category,
+void perfettoTraceInstantForTrack(const struct PerfettoTeCategory& category,
                                     const char* trackName, const char* name);
 
-Result perfettoTraceCounter(const struct PerfettoTeCategory& category, const char* name,
+void perfettoTraceCounter(const struct PerfettoTeCategory& category, const char* name,
                             int64_t value);
 
-uint64_t getDefaultCategories();
+bool isPerfettoCategoryEnabled(PerfettoTeCategory *perfettoTeCategory);
+
+bool shouldPreferAtrace(PerfettoTeCategory *perfettoTeCategory, uint64_t category);
 
 }  // namespace internal
 
diff --git a/services/inputflinger/dispatcher/InputEventTimeline.cpp b/services/inputflinger/dispatcher/InputEventTimeline.cpp
index a7c6d16..a365003 100644
--- a/services/inputflinger/dispatcher/InputEventTimeline.cpp
+++ b/services/inputflinger/dispatcher/InputEventTimeline.cpp
@@ -68,7 +68,7 @@
 
 InputEventTimeline::InputEventTimeline(bool isDown, nsecs_t eventTime, nsecs_t readTime,
                                        uint16_t vendorId, uint16_t productId,
-                                       std::set<InputDeviceUsageSource> sources)
+                                       const std::set<InputDeviceUsageSource>& sources)
       : isDown(isDown),
         eventTime(eventTime),
         readTime(readTime),
diff --git a/services/inputflinger/dispatcher/InputEventTimeline.h b/services/inputflinger/dispatcher/InputEventTimeline.h
index e9deb2d..1756944 100644
--- a/services/inputflinger/dispatcher/InputEventTimeline.h
+++ b/services/inputflinger/dispatcher/InputEventTimeline.h
@@ -76,7 +76,7 @@
 
 struct InputEventTimeline {
     InputEventTimeline(bool isDown, nsecs_t eventTime, nsecs_t readTime, uint16_t vendorId,
-                       uint16_t productId, std::set<InputDeviceUsageSource> sources);
+                       uint16_t productId, const std::set<InputDeviceUsageSource>& sources);
     const bool isDown; // True if this is an ACTION_DOWN event
     const nsecs_t eventTime;
     const nsecs_t readTime;
diff --git a/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp b/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp
index 20fd359..b72cc6e 100644
--- a/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp
@@ -27,11 +27,14 @@
 
 namespace android {
 
+constexpr float kDefaultScaleFactor = 1.0f;
+
 RotaryEncoderInputMapper::RotaryEncoderInputMapper(InputDeviceContext& deviceContext,
                                                    const InputReaderConfiguration& readerConfig)
-      : InputMapper(deviceContext, readerConfig), mOrientation(ui::ROTATION_0) {
-    mSource = AINPUT_SOURCE_ROTARY_ENCODER;
-}
+      : InputMapper(deviceContext, readerConfig),
+        mSource(AINPUT_SOURCE_ROTARY_ENCODER),
+        mScalingFactor(kDefaultScaleFactor),
+        mOrientation(ui::ROTATION_0) {}
 
 RotaryEncoderInputMapper::~RotaryEncoderInputMapper() {}
 
@@ -51,9 +54,10 @@
         std::optional<float> scalingFactor = config.getFloat("device.scalingFactor");
         if (!scalingFactor.has_value()) {
             ALOGW("Rotary Encoder device configuration file didn't specify scaling factor,"
-                  "default to 1.0!\n");
+                  "default to %f!\n",
+                  kDefaultScaleFactor);
         }
-        mScalingFactor = scalingFactor.value_or(1.0f);
+        mScalingFactor = scalingFactor.value_or(kDefaultScaleFactor);
         info.addMotionRange(AMOTION_EVENT_AXIS_SCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f,
                             res.value_or(0.0f) * mScalingFactor);
     }
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
index beba3b8..984e217 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
@@ -977,8 +977,9 @@
         viewportChanged = mViewport != newViewport;
     }
 
+    const bool deviceModeChanged = mDeviceMode != oldDeviceMode;
     bool skipViewportUpdate = false;
-    if (viewportChanged) {
+    if (viewportChanged || deviceModeChanged) {
         const bool viewportOrientationChanged = mViewport.orientation != newViewport.orientation;
         const bool viewportDisplayIdChanged = mViewport.displayId != newViewport.displayId;
         mViewport = newViewport;
@@ -1020,7 +1021,6 @@
     }
 
     // If moving between pointer modes, need to reset some state.
-    bool deviceModeChanged = mDeviceMode != oldDeviceMode;
     if (deviceModeChanged) {
         mOrientedRanges.clear();
     }
diff --git a/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp b/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp
index daab636..5c5fd3f 100644
--- a/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp
@@ -258,11 +258,9 @@
     // 2) TouchpadInputMapper is stored as a unique_ptr and not moved.
     mGestureInterpreter->SetPropProvider(const_cast<GesturesPropProvider*>(&gesturePropProvider),
                                          &mPropertyProvider);
-    if (input_flags::enable_gestures_library_timer_provider()) {
-        mGestureInterpreter->SetTimerProvider(const_cast<GesturesTimerProvider*>(
-                                                      &kGestureTimerProvider),
-                                              &mTimerProvider);
-    }
+    mGestureInterpreter->SetTimerProvider(const_cast<GesturesTimerProvider*>(
+                                                  &kGestureTimerProvider),
+                                          &mTimerProvider);
     mGestureInterpreter->SetCallback(gestureInterpreterCallback, this);
 }
 
@@ -300,12 +298,8 @@
     dump += addLinePrefix(mGestureConverter.dump(), INDENT4);
     dump += INDENT3 "Gesture properties:\n";
     dump += addLinePrefix(mPropertyProvider.dump(), INDENT4);
-    if (input_flags::enable_gestures_library_timer_provider()) {
-        dump += INDENT3 "Timer provider:\n";
-        dump += addLinePrefix(mTimerProvider.dump(), INDENT4);
-    } else {
-        dump += INDENT3 "Timer provider: disabled by flag\n";
-    }
+    dump += INDENT3 "Timer provider:\n";
+    dump += addLinePrefix(mTimerProvider.dump(), INDENT4);
     dump += INDENT3 "Captured event converter:\n";
     dump += addLinePrefix(mCapturedEventConverter.dump(), INDENT4);
     dump += StringPrintf(INDENT3 "DisplayId: %s\n",
@@ -468,9 +462,6 @@
 }
 
 std::list<NotifyArgs> TouchpadInputMapper::timeoutExpired(nsecs_t when) {
-    if (!input_flags::enable_gestures_library_timer_provider()) {
-        return {};
-    }
     mTimerProvider.triggerCallbacks(when);
     return processGestures(when, when);
 }
diff --git a/services/inputflinger/reader/mapper/accumulator/CursorScrollAccumulator.cpp b/services/inputflinger/reader/mapper/accumulator/CursorScrollAccumulator.cpp
index 06315e2..5373440 100644
--- a/services/inputflinger/reader/mapper/accumulator/CursorScrollAccumulator.cpp
+++ b/services/inputflinger/reader/mapper/accumulator/CursorScrollAccumulator.cpp
@@ -55,14 +55,14 @@
         switch (rawEvent.code) {
             case REL_WHEEL_HI_RES:
                 if (mHaveRelWheelHighRes) {
-                    mRelWheel = rawEvent.value /
-                            static_cast<float>(kEvdevMouseHighResScrollUnitsPerDetent);
+                    mRelWheel =
+                            rawEvent.value / static_cast<float>(kEvdevHighResScrollUnitsPerDetent);
                 }
                 break;
             case REL_HWHEEL_HI_RES:
                 if (mHaveRelHWheelHighRes) {
-                    mRelHWheel = rawEvent.value /
-                            static_cast<float>(kEvdevMouseHighResScrollUnitsPerDetent);
+                    mRelHWheel =
+                            rawEvent.value / static_cast<float>(kEvdevHighResScrollUnitsPerDetent);
                 }
                 break;
             case REL_WHEEL:
diff --git a/services/inputflinger/reader/mapper/accumulator/CursorScrollAccumulator.h b/services/inputflinger/reader/mapper/accumulator/CursorScrollAccumulator.h
index 6990d20..d3373cc 100644
--- a/services/inputflinger/reader/mapper/accumulator/CursorScrollAccumulator.h
+++ b/services/inputflinger/reader/mapper/accumulator/CursorScrollAccumulator.h
@@ -16,8 +16,6 @@
 
 #pragma once
 
-#include <stdint.h>
-
 namespace android {
 
 class InputDeviceContext;
@@ -36,8 +34,6 @@
     inline bool haveRelativeVWheel() const { return mHaveRelWheel; }
     inline bool haveRelativeHWheel() const { return mHaveRelHWheel; }
 
-    inline int32_t getRelativeX() const { return mRelX; }
-    inline int32_t getRelativeY() const { return mRelY; }
     inline float getRelativeVWheel() const { return mRelWheel; }
     inline float getRelativeHWheel() const { return mRelHWheel; }
 
@@ -47,8 +43,6 @@
     bool mHaveRelWheelHighRes;
     bool mHaveRelHWheelHighRes;
 
-    int32_t mRelX;
-    int32_t mRelY;
     float mRelWheel;
     float mRelHWheel;
 
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index fa9d263..8cc34e9 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -56,6 +56,7 @@
 
 using namespace ftl::flag_operators;
 using testing::AllOf;
+using testing::VariantWith;
 using std::chrono_literals::operator""ms;
 using std::chrono_literals::operator""s;
 
@@ -4487,15 +4488,15 @@
     void prepareButtons();
     void prepareAxes(int axes);
 
-    void processDown(SingleTouchInputMapper& mapper, int32_t x, int32_t y);
-    void processMove(SingleTouchInputMapper& mapper, int32_t x, int32_t y);
-    void processUp(SingleTouchInputMapper& mappery);
-    void processPressure(SingleTouchInputMapper& mapper, int32_t pressure);
-    void processToolMajor(SingleTouchInputMapper& mapper, int32_t toolMajor);
-    void processDistance(SingleTouchInputMapper& mapper, int32_t distance);
-    void processTilt(SingleTouchInputMapper& mapper, int32_t tiltX, int32_t tiltY);
-    void processKey(SingleTouchInputMapper& mapper, int32_t code, int32_t value);
-    void processSync(SingleTouchInputMapper& mapper);
+    std::list<NotifyArgs> processDown(SingleTouchInputMapper& mapper, int32_t x, int32_t y);
+    std::list<NotifyArgs> processMove(SingleTouchInputMapper& mapper, int32_t x, int32_t y);
+    std::list<NotifyArgs> processUp(SingleTouchInputMapper& mappery);
+    std::list<NotifyArgs> processPressure(SingleTouchInputMapper& mapper, int32_t pressure);
+    std::list<NotifyArgs> processToolMajor(SingleTouchInputMapper& mapper, int32_t toolMajor);
+    std::list<NotifyArgs> processDistance(SingleTouchInputMapper& mapper, int32_t distance);
+    std::list<NotifyArgs> processTilt(SingleTouchInputMapper& mapper, int32_t tiltX, int32_t tiltY);
+    std::list<NotifyArgs> processKey(SingleTouchInputMapper& mapper, int32_t code, int32_t value);
+    std::list<NotifyArgs> processSync(SingleTouchInputMapper& mapper);
 };
 
 void SingleTouchInputMapperTest::prepareButtons() {
@@ -4525,47 +4526,57 @@
     }
 }
 
-void SingleTouchInputMapperTest::processDown(SingleTouchInputMapper& mapper, int32_t x, int32_t y) {
-    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, BTN_TOUCH, 1);
-    process(mapper, ARBITRARY_TIME, READ_TIME, EV_ABS, ABS_X, x);
-    process(mapper, ARBITRARY_TIME, READ_TIME, EV_ABS, ABS_Y, y);
+std::list<NotifyArgs> SingleTouchInputMapperTest::processDown(SingleTouchInputMapper& mapper,
+                                                              int32_t x, int32_t y) {
+    std::list<NotifyArgs> args;
+    args += process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, BTN_TOUCH, 1);
+    args += process(mapper, ARBITRARY_TIME, READ_TIME, EV_ABS, ABS_X, x);
+    args += process(mapper, ARBITRARY_TIME, READ_TIME, EV_ABS, ABS_Y, y);
+    return args;
 }
 
-void SingleTouchInputMapperTest::processMove(SingleTouchInputMapper& mapper, int32_t x, int32_t y) {
-    process(mapper, ARBITRARY_TIME, READ_TIME, EV_ABS, ABS_X, x);
-    process(mapper, ARBITRARY_TIME, READ_TIME, EV_ABS, ABS_Y, y);
+std::list<NotifyArgs> SingleTouchInputMapperTest::processMove(SingleTouchInputMapper& mapper,
+                                                              int32_t x, int32_t y) {
+    std::list<NotifyArgs> args;
+    args += process(mapper, ARBITRARY_TIME, READ_TIME, EV_ABS, ABS_X, x);
+    args += process(mapper, ARBITRARY_TIME, READ_TIME, EV_ABS, ABS_Y, y);
+    return args;
 }
 
-void SingleTouchInputMapperTest::processUp(SingleTouchInputMapper& mapper) {
-    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, BTN_TOUCH, 0);
+std::list<NotifyArgs> SingleTouchInputMapperTest::processUp(SingleTouchInputMapper& mapper) {
+    return process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, BTN_TOUCH, 0);
 }
 
-void SingleTouchInputMapperTest::processPressure(SingleTouchInputMapper& mapper, int32_t pressure) {
-    process(mapper, ARBITRARY_TIME, READ_TIME, EV_ABS, ABS_PRESSURE, pressure);
+std::list<NotifyArgs> SingleTouchInputMapperTest::processPressure(SingleTouchInputMapper& mapper,
+                                                                  int32_t pressure) {
+    return process(mapper, ARBITRARY_TIME, READ_TIME, EV_ABS, ABS_PRESSURE, pressure);
 }
 
-void SingleTouchInputMapperTest::processToolMajor(SingleTouchInputMapper& mapper,
-                                                  int32_t toolMajor) {
-    process(mapper, ARBITRARY_TIME, READ_TIME, EV_ABS, ABS_TOOL_WIDTH, toolMajor);
+std::list<NotifyArgs> SingleTouchInputMapperTest::processToolMajor(SingleTouchInputMapper& mapper,
+                                                                   int32_t toolMajor) {
+    return process(mapper, ARBITRARY_TIME, READ_TIME, EV_ABS, ABS_TOOL_WIDTH, toolMajor);
 }
 
-void SingleTouchInputMapperTest::processDistance(SingleTouchInputMapper& mapper, int32_t distance) {
-    process(mapper, ARBITRARY_TIME, READ_TIME, EV_ABS, ABS_DISTANCE, distance);
+std::list<NotifyArgs> SingleTouchInputMapperTest::processDistance(SingleTouchInputMapper& mapper,
+                                                                  int32_t distance) {
+    return process(mapper, ARBITRARY_TIME, READ_TIME, EV_ABS, ABS_DISTANCE, distance);
 }
 
-void SingleTouchInputMapperTest::processTilt(SingleTouchInputMapper& mapper, int32_t tiltX,
-                                             int32_t tiltY) {
-    process(mapper, ARBITRARY_TIME, READ_TIME, EV_ABS, ABS_TILT_X, tiltX);
-    process(mapper, ARBITRARY_TIME, READ_TIME, EV_ABS, ABS_TILT_Y, tiltY);
+std::list<NotifyArgs> SingleTouchInputMapperTest::processTilt(SingleTouchInputMapper& mapper,
+                                                              int32_t tiltX, int32_t tiltY) {
+    std::list<NotifyArgs> args;
+    args += process(mapper, ARBITRARY_TIME, READ_TIME, EV_ABS, ABS_TILT_X, tiltX);
+    args += process(mapper, ARBITRARY_TIME, READ_TIME, EV_ABS, ABS_TILT_Y, tiltY);
+    return args;
 }
 
-void SingleTouchInputMapperTest::processKey(SingleTouchInputMapper& mapper, int32_t code,
-                                            int32_t value) {
-    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, code, value);
+std::list<NotifyArgs> SingleTouchInputMapperTest::processKey(SingleTouchInputMapper& mapper,
+                                                             int32_t code, int32_t value) {
+    return process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, code, value);
 }
 
-void SingleTouchInputMapperTest::processSync(SingleTouchInputMapper& mapper) {
-    process(mapper, ARBITRARY_TIME, READ_TIME, EV_SYN, SYN_REPORT, 0);
+std::list<NotifyArgs> SingleTouchInputMapperTest::processSync(SingleTouchInputMapper& mapper) {
+    return process(mapper, ARBITRARY_TIME, READ_TIME, EV_SYN, SYN_REPORT, 0);
 }
 
 TEST_F(SingleTouchInputMapperTest, GetSources_WhenDeviceTypeIsNotSpecifiedAndNotACursor_ReturnsPointer) {
@@ -4656,6 +4667,42 @@
     ASSERT_FALSE(flags[1]);
 }
 
+TEST_F(SingleTouchInputMapperTest, DeviceTypeChange_RecalculatesRawToDisplayTransform) {
+    prepareDisplay(ui::ROTATION_0);
+    prepareAxes(POSITION);
+    addConfigurationProperty("touch.deviceType", "touchScreen");
+    SingleTouchInputMapper& mapper = constructAndAddMapper<SingleTouchInputMapper>();
+
+    const int32_t x = 900;
+    const int32_t y = 75;
+    std::list<NotifyArgs> args;
+    args += processDown(mapper, x, y);
+    args += processSync(mapper);
+
+    // Assert that motion event is received in display coordinate space for deviceType touchScreen.
+    ASSERT_THAT(args,
+                ElementsAre(VariantWith<NotifyMotionArgs>(
+                        AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
+                              WithCoords(toDisplayX(x), toDisplayY(y))))));
+
+    // Add device type association after the device was created.
+    mFakePolicy->addDeviceTypeAssociation(DEVICE_LOCATION, "touchNavigation");
+    // Send update to the mapper.
+    std::list<NotifyArgs> unused =
+            mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
+                               InputReaderConfiguration::Change::DEVICE_TYPE /*changes*/);
+
+    args.clear();
+    args += processDown(mapper, x, y);
+    args += processSync(mapper);
+
+    // Assert that motion event is received in raw coordinate space for deviceType touchNavigation.
+    ASSERT_THAT(args,
+                ElementsAre(VariantWith<NotifyMotionArgs>(
+                        AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
+                              WithCoords(x - RAW_X_MIN, y - RAW_Y_MIN)))));
+}
+
 TEST_F(SingleTouchInputMapperTest, Process_WhenVirtualKeyIsPressedAndReleasedNormally_SendsKeyDownAndKeyUp) {
     addConfigurationProperty("touch.deviceType", "touchScreen");
     prepareDisplay(ui::ROTATION_0);
diff --git a/services/inputflinger/tests/RotaryEncoderInputMapper_test.cpp b/services/inputflinger/tests/RotaryEncoderInputMapper_test.cpp
index 2b8071b..366b3dc 100644
--- a/services/inputflinger/tests/RotaryEncoderInputMapper_test.cpp
+++ b/services/inputflinger/tests/RotaryEncoderInputMapper_test.cpp
@@ -22,6 +22,7 @@
 #include <variant>
 
 #include <android-base/logging.h>
+#include <android_companion_virtualdevice_flags.h>
 #include <gtest/gtest.h>
 #include <input/DisplayViewport.h>
 #include <linux/input-event-codes.h>
@@ -109,6 +110,8 @@
 
 } // namespace
 
+namespace vd_flags = android::companion::virtualdevice::flags;
+
 /**
  * Unit tests for RotaryEncoderInputMapper.
  */
@@ -170,4 +173,53 @@
                               WithDisplayId(ui::LogicalDisplayId::INVALID)))));
 }
 
+TEST_F(RotaryEncoderInputMapperTest, ProcessRegularScroll) {
+    createDevice();
+    mMapper = createInputMapper<RotaryEncoderInputMapper>(*mDeviceContext, mReaderConfiguration);
+
+    std::list<NotifyArgs> args;
+    args += process(ARBITRARY_TIME, EV_REL, REL_WHEEL, 1);
+    args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
+
+    EXPECT_THAT(args,
+                ElementsAre(VariantWith<NotifyMotionArgs>(
+                        AllOf(WithSource(AINPUT_SOURCE_ROTARY_ENCODER),
+                              WithMotionAction(AMOTION_EVENT_ACTION_SCROLL), WithScroll(1.0f)))));
+}
+
+TEST_F(RotaryEncoderInputMapperTest, ProcessHighResScroll) {
+    vd_flags::high_resolution_scroll(true);
+    EXPECT_CALL(mMockEventHub, hasRelativeAxis(EVENTHUB_ID, REL_WHEEL_HI_RES))
+            .WillRepeatedly(Return(true));
+    createDevice();
+    mMapper = createInputMapper<RotaryEncoderInputMapper>(*mDeviceContext, mReaderConfiguration);
+
+    std::list<NotifyArgs> args;
+    args += process(ARBITRARY_TIME, EV_REL, REL_WHEEL_HI_RES, 60);
+    args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
+
+    EXPECT_THAT(args,
+                ElementsAre(VariantWith<NotifyMotionArgs>(
+                        AllOf(WithSource(AINPUT_SOURCE_ROTARY_ENCODER),
+                              WithMotionAction(AMOTION_EVENT_ACTION_SCROLL), WithScroll(0.5f)))));
+}
+
+TEST_F(RotaryEncoderInputMapperTest, HighResScrollIgnoresRegularScroll) {
+    vd_flags::high_resolution_scroll(true);
+    EXPECT_CALL(mMockEventHub, hasRelativeAxis(EVENTHUB_ID, REL_WHEEL_HI_RES))
+            .WillRepeatedly(Return(true));
+    createDevice();
+    mMapper = createInputMapper<RotaryEncoderInputMapper>(*mDeviceContext, mReaderConfiguration);
+
+    std::list<NotifyArgs> args;
+    args += process(ARBITRARY_TIME, EV_REL, REL_WHEEL_HI_RES, 60);
+    args += process(ARBITRARY_TIME, EV_REL, REL_WHEEL, 1);
+    args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
+
+    EXPECT_THAT(args,
+                ElementsAre(VariantWith<NotifyMotionArgs>(
+                        AllOf(WithSource(AINPUT_SOURCE_ROTARY_ENCODER),
+                              WithMotionAction(AMOTION_EVENT_ACTION_SCROLL), WithScroll(0.5f)))));
+}
+
 } // namespace android
\ No newline at end of file
diff --git a/services/inputflinger/tests/TestEventMatchers.h b/services/inputflinger/tests/TestEventMatchers.h
index f643fb1..f8e3c22 100644
--- a/services/inputflinger/tests/TestEventMatchers.h
+++ b/services/inputflinger/tests/TestEventMatchers.h
@@ -697,6 +697,12 @@
     return argDistance == distance;
 }
 
+MATCHER_P(WithScroll, scroll, "InputEvent with specified scroll value") {
+    const auto argScroll = arg.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_SCROLL);
+    *result_listener << "expected scroll value " << scroll << ", but got " << argScroll;
+    return argScroll == scroll;
+}
+
 MATCHER_P2(WithScroll, scrollX, scrollY, "InputEvent with specified scroll values") {
     const auto argScrollX = arg.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_HSCROLL);
     const auto argScrollY = arg.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_VSCROLL);
diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
index da56014..334c104 100644
--- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
+++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
@@ -211,7 +211,7 @@
         return;
     }
     SFTRACE_CALL();
-    if (sTraceHintSessionData) ATRACE_INT("Session hint", static_cast<int>(hint));
+    if (sTraceHintSessionData) SFTRACE_INT("Session hint", static_cast<int>(hint));
     {
         std::scoped_lock lock(mHintSessionMutex);
         if (!ensurePowerHintSessionRunning()) {
@@ -298,7 +298,7 @@
     SFTRACE_CALL();
     {
         mTargetDuration = targetDuration;
-        if (sTraceHintSessionData) ATRACE_INT64("Time target", targetDuration.ns());
+        if (sTraceHintSessionData) SFTRACE_INT64("Time target", targetDuration.ns());
         if (targetDuration == mLastTargetDurationSent) return;
         std::scoped_lock lock(mHintSessionMutex);
         if (!ensurePowerHintSessionRunning()) {
diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
index bc4a41b..1076b2b 100644
--- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
+++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
@@ -300,7 +300,7 @@
     bool mSessionConfigSupported = true;
     bool mFirstConfigSupportCheck = true;
 
-    // Whether we should emit ATRACE_INT data for hint sessions
+    // Whether we should emit SFTRACE_INT data for hint sessions
     static const bool sTraceHintSessionData;
 
     // Default target duration for the hint session
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 86c7d16..a6d2b15 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -3060,6 +3060,8 @@
         callReleaseBufferCallback(mDrawingState.releaseBufferListener,
                                   mDrawingState.buffer->getBuffer(), mDrawingState.frameNumber,
                                   mDrawingState.acquireFence);
+        const int32_t layerId = getSequence();
+        mFlinger->mTimeStats->removeTimeRecord(layerId, mDrawingState.frameNumber);
         decrementPendingBufferCount();
         if (mDrawingState.bufferSurfaceFrameTX != nullptr &&
             mDrawingState.bufferSurfaceFrameTX->getPresentState() != PresentState::Presented) {
@@ -3238,7 +3240,7 @@
         return static_cast<nsecs_t>(0);
     }();
 
-    if (ATRACE_ENABLED() && presentTime > 0) {
+    if (SFTRACE_ENABLED() && presentTime > 0) {
         const auto presentIn = TimePoint::fromNs(presentTime) - TimePoint::now();
         SFTRACE_FORMAT_INSTANT("presentIn %s", to_string(presentIn).c_str());
     }
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index d3b56f8..52f169e 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -1265,7 +1265,7 @@
     const std::string mBlastTransactionName{"BufferTX - " + mName};
     // This integer is incremented everytime a buffer arrives at the server for this layer,
     // and decremented when a buffer is dropped or latched. When changed the integer is exported
-    // to systrace with ATRACE_INT and mBlastTransactionName. This way when debugging perf it is
+    // to systrace with SFTRACE_INT and mBlastTransactionName. This way when debugging perf it is
     // possible to see when a buffer arrived at the server, and in which frame it latched.
     //
     // You can understand the trace this way:
diff --git a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
index 0b17c84..a20cf9a 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
@@ -1065,7 +1065,7 @@
         ALOGV("%s: overriding to %s for uid=%d", __func__, to_string(overrideFps).c_str(), uid);
         SFTRACE_FORMAT_INSTANT("%s: overriding to %s for uid=%d", __func__,
                                to_string(overrideFps).c_str(), uid);
-        if (ATRACE_ENABLED() && FlagManager::getInstance().trace_frame_rate_override()) {
+        if (SFTRACE_ENABLED() && FlagManager::getInstance().trace_frame_rate_override()) {
             std::stringstream ss;
             ss << "FrameRateOverride " << uid;
             SFTRACE_INT(ss.str().c_str(), overrideFps.getIntValue());
diff --git a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
index 8dae3ca..900bce0 100644
--- a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
@@ -45,7 +45,7 @@
 }
 
 void traceEntry(const VSyncDispatchTimerQueueEntry& entry, nsecs_t now) {
-    if (!ATRACE_ENABLED() || !entry.wakeupTime().has_value() || !entry.targetVsync().has_value()) {
+    if (!SFTRACE_ENABLED() || !entry.wakeupTime().has_value() || !entry.targetVsync().has_value()) {
         return;
     }
 
diff --git a/services/surfaceflinger/Scheduler/src/Timer.cpp b/services/surfaceflinger/Scheduler/src/Timer.cpp
index fba3d58..20c58eb 100644
--- a/services/surfaceflinger/Scheduler/src/Timer.cpp
+++ b/services/surfaceflinger/Scheduler/src/Timer.cpp
@@ -188,7 +188,7 @@
         int nfds = epoll_wait(mEpollFd, events, DispatchType::MAX_DISPATCH_TYPE, -1);
 
         setDebugState(DebugState::Running);
-        if (ATRACE_ENABLED()) {
+        if (SFTRACE_ENABLED()) {
             ftl::Concat trace("TimerIteration #", iteration++);
             SFTRACE_NAME(trace.c_str());
         }
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index d00e762..c75c9f5 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -3320,9 +3320,9 @@
         });
     }
 
-    // Even though ATRACE_INT64 already checks if tracing is enabled, it doesn't prevent the
+    // Even though SFTRACE_INT64 already checks if tracing is enabled, it doesn't prevent the
     // side-effect of getTotalSize(), so we check that again here
-    if (ATRACE_ENABLED()) {
+    if (SFTRACE_ENABLED()) {
         // getTotalSize returns the total number of buffers that were allocated by SurfaceFlinger
         SFTRACE_INT64("Total Buffer Size", GraphicBufferAllocator::get().getTotalSize());
     }
@@ -4259,6 +4259,11 @@
     getHwComposer().setVsyncEnabled(displayId, enable ? hal::Vsync::ENABLE : hal::Vsync::DISABLE);
 }
 
+// This callback originates from Scheduler::applyPolicy, whose thread context may be the main thread
+// (via Scheduler::chooseRefreshRateForContent) or a OneShotTimer thread. The latter case imposes a
+// deadlock prevention rule: If the main thread is processing hotplug, then mStateLock is locked as
+// the main thread stops the OneShotTimer and joins with its thread. Hence, the OneShotTimer thread
+// must not lock mStateLock in this callback, which would deadlock with the join.
 void SurfaceFlinger::requestDisplayModes(std::vector<display::DisplayModeRequest> modeRequests) {
     if (mBootStage != BootStage::FINISHED) {
         ALOGV("Currently in the boot stage, skipping display mode changes");
@@ -4267,21 +4272,14 @@
 
     SFTRACE_CALL();
 
-    // If this is called from the main thread mStateLock must be locked before
-    // Currently the only way to call this function from the main thread is from
-    // Scheduler::chooseRefreshRateForContent
-
-    ConditionalLock lock(mStateLock, std::this_thread::get_id() != mMainThreadId);
-
     for (auto& request : modeRequests) {
         const auto& modePtr = request.mode.modePtr;
-
         const auto displayId = modePtr->getPhysicalDisplayId();
-        const auto display = getDisplayDeviceLocked(displayId);
 
-        if (!display) continue;
+        const auto selectorPtr = mDisplayModeController.selectorPtrFor(displayId);
+        if (!selectorPtr) continue;
 
-        if (display->refreshRateSelector().isModeAllowed(request.mode)) {
+        if (selectorPtr->isModeAllowed(request.mode)) {
             setDesiredMode(std::move(request));
         } else {
             ALOGV("%s: Mode %d is disallowed for display %s", __func__,
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 8242844..65bfce2 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -733,7 +733,7 @@
     // Show hdr sdr ratio overlay
     bool mHdrSdrRatioOverlay = false;
 
-    void setDesiredMode(display::DisplayModeRequest&&) REQUIRES(mStateLock);
+    void setDesiredMode(display::DisplayModeRequest&&);
 
     status_t setActiveModeFromBackdoor(const sp<display::DisplayToken>&, DisplayModeId, Fps minFps,
                                        Fps maxFps);
diff --git a/services/surfaceflinger/TracedOrdinal.h b/services/surfaceflinger/TracedOrdinal.h
index eba1ecf..51f33a6 100644
--- a/services/surfaceflinger/TracedOrdinal.h
+++ b/services/surfaceflinger/TracedOrdinal.h
@@ -79,7 +79,7 @@
 
 private:
     void trace() {
-        if (CC_LIKELY(!ATRACE_ENABLED())) {
+        if (CC_LIKELY(!SFTRACE_ENABLED())) {
             return;
         }
 
diff --git a/services/surfaceflinger/common/include/common/trace.h b/services/surfaceflinger/common/include/common/trace.h
index c13cdde..344359e 100644
--- a/services/surfaceflinger/common/include/common/trace.h
+++ b/services/surfaceflinger/common/include/common/trace.h
@@ -20,6 +20,10 @@
 #include <cutils/trace.h>
 #include <stdint.h>
 
+#ifndef ATRACE_TAG
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+#endif
+
 #define SFTRACE_ENABLED() ATRACE_ENABLED()
 #define SFTRACE_BEGIN(name) ATRACE_BEGIN(name)
 #define SFTRACE_END() ATRACE_END()