Merge "Fix fs-verity API for secondary users" into main
diff --git a/cmds/idlcli/vibrator.h b/cmds/idlcli/vibrator.h
index dfbb886..e100eac 100644
--- a/cmds/idlcli/vibrator.h
+++ b/cmds/idlcli/vibrator.h
@@ -74,7 +74,7 @@
 }
 
 template <typename I>
-using shared_ptr = std::result_of_t<decltype(getService<I>)&(std::string)>;
+using shared_ptr = std::invoke_result_t<decltype(getService<I>)&, std::string>;
 
 template <typename I>
 class HalWrapper {
diff --git a/cmds/lshal/Timeout.h b/cmds/lshal/Timeout.h
index 805e8dc..d97ba89 100644
--- a/cmds/lshal/Timeout.h
+++ b/cmds/lshal/Timeout.h
@@ -16,83 +16,44 @@
 
 #pragma once
 
-#include <condition_variable>
 #include <chrono>
-#include <functional>
-#include <mutex>
-#include <thread>
+#include <future>
 
 #include <hidl/Status.h>
+#include <utils/Errors.h>
 
 namespace android {
 namespace lshal {
 
-class BackgroundTaskState {
-public:
-    explicit BackgroundTaskState(std::function<void(void)> &&func)
-            : mFunc(std::forward<decltype(func)>(func)) {}
-    void notify() {
-        std::unique_lock<std::mutex> lock(mMutex);
-        mFinished = true;
-        lock.unlock();
-        mCondVar.notify_all();
-    }
-    template<class C, class D>
-    bool wait(std::chrono::time_point<C, D> end) {
-        std::unique_lock<std::mutex> lock(mMutex);
-        mCondVar.wait_until(lock, end, [this](){ return this->mFinished; });
-        return mFinished;
-    }
-    void operator()() {
-        mFunc();
-    }
-private:
-    std::mutex mMutex;
-    std::condition_variable mCondVar;
-    bool mFinished = false;
-    std::function<void(void)> mFunc;
-};
-
-void *callAndNotify(void *data) {
-    BackgroundTaskState &state = *static_cast<BackgroundTaskState *>(data);
-    state();
-    state.notify();
-    return nullptr;
-}
-
-template<class R, class P>
-bool timeout(std::chrono::duration<R, P> delay, std::function<void(void)> &&func) {
-    auto now = std::chrono::system_clock::now();
-    BackgroundTaskState state{std::forward<decltype(func)>(func)};
-    pthread_t thread;
-    if (pthread_create(&thread, nullptr, callAndNotify, &state)) {
-        std::cerr << "FATAL: could not create background thread." << std::endl;
-        return false;
-    }
-    bool success = state.wait(now + delay);
-    if (!success) {
-        pthread_kill(thread, SIGINT);
-    }
-    pthread_join(thread, nullptr);
-    return success;
-}
-
+// Call function on interfaceObject and wait for result until the given timeout has reached.
+// Callback functions pass to timeoutIPC() may be executed after the this function
+// has returned, especially if deadline has been reached. Hence, care must be taken when passing
+// data between the background thread and the main thread. See b/311143089.
 template<class R, class P, class Function, class I, class... Args>
-typename std::result_of<Function(I *, Args...)>::type
+typename std::invoke_result<Function, I *, Args...>::type
 timeoutIPC(std::chrono::duration<R, P> wait, const sp<I> &interfaceObject, Function &&func,
            Args &&... args) {
     using ::android::hardware::Status;
-    typename std::result_of<Function(I *, Args...)>::type ret{Status::ok()};
-    auto boundFunc = std::bind(std::forward<Function>(func),
-            interfaceObject.get(), std::forward<Args>(args)...);
-    bool success = timeout(wait, [&ret, &boundFunc] {
-        ret = std::move(boundFunc());
-    });
-    if (!success) {
+
+    // Execute on a background thread but do not defer execution.
+    auto future =
+            std::async(std::launch::async, func, interfaceObject, std::forward<Args>(args)...);
+    auto status = future.wait_for(wait);
+    if (status == std::future_status::ready) {
+        return future.get();
+    }
+
+    // This future belongs to a background thread that we no longer care about.
+    // Putting this in the global list avoids std::future::~future() that may wait for the
+    // result to come back.
+    // This leaks memory, but lshal is a debugging tool, so this is fine.
+    static std::vector<decltype(future)> gDeadPool{};
+    gDeadPool.emplace_back(std::move(future));
+
+    if (status == std::future_status::timeout) {
         return Status::fromStatusT(TIMED_OUT);
     }
-    return ret;
+    return Status::fromExceptionCode(Status::Exception::EX_ILLEGAL_STATE, "Illegal future_status");
 }
-
-}  // namespace lshal
-}  // namespace android
+} // namespace lshal
+} // namespace android
diff --git a/cmds/lshal/main.cpp b/cmds/lshal/main.cpp
index 366c938..bd5fa32 100644
--- a/cmds/lshal/main.cpp
+++ b/cmds/lshal/main.cpp
@@ -18,5 +18,6 @@
 
 int main(int argc, char **argv) {
     using namespace ::android::lshal;
-    return Lshal{}.main(Arg{argc, argv});
+    // Use _exit() to force terminate background threads in Timeout.h
+    _exit(Lshal{}.main(Arg{argc, argv}));
 }
diff --git a/cmds/lshal/test.cpp b/cmds/lshal/test.cpp
index cba7c4b..c24f827 100644
--- a/cmds/lshal/test.cpp
+++ b/cmds/lshal/test.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+#include <chrono>
+#include <future>
+#include <mutex>
+#include "android/hidl/base/1.0/IBase.h"
 #define LOG_TAG "Lshal"
 #include <android-base/logging.h>
 
@@ -36,6 +40,8 @@
 
 using namespace testing;
 
+using std::chrono_literals::operator""ms;
+
 using ::android::hidl::base::V1_0::DebugInfo;
 using ::android::hidl::base::V1_0::IBase;
 using ::android::hidl::manager::V1_0::IServiceManager;
@@ -934,12 +940,9 @@
         return hardware::Void();
     }));
     EXPECT_CALL(*serviceManager, get(_, _))
-            .WillRepeatedly(
-                    Invoke([&](const hidl_string&, const hidl_string& instance) -> sp<IBase> {
-                        int id = getIdFromInstanceName(instance);
-                        if (id > inheritanceLevel) return nullptr;
-                        return sp<IBase>(service);
-                    }));
+            .WillRepeatedly(Invoke([&](const hidl_string&, const hidl_string&) -> sp<IBase> {
+                return sp<IBase>(service);
+            }));
 
     const std::string expected = "[fake description 0]\n"
                                  "Interface\n"
@@ -957,6 +960,110 @@
     EXPECT_EQ("", err.str());
 }
 
+// In SlowService, everything goes slooooooow. Each IPC call will wait for
+// the specified time before calling the callback function or returning.
+class SlowService : public IBase {
+public:
+    explicit SlowService(std::chrono::milliseconds wait) : mWait(wait) {}
+    android::hardware::Return<void> interfaceDescriptor(interfaceDescriptor_cb cb) override {
+        std::this_thread::sleep_for(mWait);
+        cb(getInterfaceName(1));
+        storeHistory("interfaceDescriptor");
+        return hardware::Void();
+    }
+    android::hardware::Return<void> interfaceChain(interfaceChain_cb cb) override {
+        std::this_thread::sleep_for(mWait);
+        std::vector<hidl_string> ret;
+        ret.push_back(getInterfaceName(1));
+        ret.push_back(IBase::descriptor);
+        cb(ret);
+        storeHistory("interfaceChain");
+        return hardware::Void();
+    }
+    android::hardware::Return<void> getHashChain(getHashChain_cb cb) override {
+        std::this_thread::sleep_for(mWait);
+        std::vector<hidl_hash> ret;
+        ret.push_back(getHashFromId(0));
+        ret.push_back(getHashFromId(0xff));
+        cb(ret);
+        storeHistory("getHashChain");
+        return hardware::Void();
+    }
+    android::hardware::Return<void> debug(const hidl_handle&,
+                                          const hidl_vec<hidl_string>&) override {
+        std::this_thread::sleep_for(mWait);
+        storeHistory("debug");
+        return Void();
+    }
+
+    template <class R, class P, class Pred>
+    bool waitForHistory(std::chrono::duration<R, P> wait, Pred predicate) {
+        std::unique_lock<std::mutex> lock(mLock);
+        return mCv.wait_for(lock, wait, [&]() { return predicate(mCallHistory); });
+    }
+
+private:
+    void storeHistory(std::string hist) {
+        {
+            std::lock_guard<std::mutex> lock(mLock);
+            mCallHistory.emplace_back(std::move(hist));
+        }
+        mCv.notify_all();
+    }
+
+    const std::chrono::milliseconds mWait;
+    std::mutex mLock;
+    std::condition_variable mCv;
+    // List of functions that have finished being called on this interface.
+    std::vector<std::string> mCallHistory;
+};
+
+class TimeoutTest : public ListTest {
+public:
+    void setMockServiceManager(sp<IBase> service) {
+        EXPECT_CALL(*serviceManager, list(_))
+                .WillRepeatedly(Invoke([&](IServiceManager::list_cb cb) {
+                    std::vector<hidl_string> ret;
+                    ret.push_back(getInterfaceName(1) + "/default");
+                    cb(ret);
+                    return hardware::Void();
+                }));
+        EXPECT_CALL(*serviceManager, get(_, _))
+                .WillRepeatedly(Invoke([&](const hidl_string&, const hidl_string&) -> sp<IBase> {
+                    return service;
+                }));
+    }
+};
+
+TEST_F(TimeoutTest, BackgroundThreadIsKept) {
+    auto lshalIpcTimeout = 100ms;
+    auto serviceIpcTimeout = 200ms;
+    lshal->setWaitTimeForTest(lshalIpcTimeout, lshalIpcTimeout);
+    sp<SlowService> service = new SlowService(serviceIpcTimeout);
+    setMockServiceManager(service);
+
+    optind = 1; // mimic Lshal::parseArg()
+    EXPECT_NE(0u, mockList->main(createArg({"lshal", "--types=b", "-i", "--neat"})));
+    EXPECT_THAT(err.str(), HasSubstr("Skipping \"a.h.foo1@1.0::IFoo/default\""));
+    EXPECT_TRUE(service->waitForHistory(serviceIpcTimeout * 5, [](const auto& hist) {
+        return hist.size() == 1 && hist[0] == "interfaceChain";
+    })) << "The background thread should continue after the main thread moves on, but it is killed";
+}
+
+TEST_F(TimeoutTest, BackgroundThreadDoesNotBlockMainThread) {
+    auto lshalIpcTimeout = 100ms;
+    auto serviceIpcTimeout = 2000ms;
+    auto start = std::chrono::system_clock::now();
+    lshal->setWaitTimeForTest(lshalIpcTimeout, lshalIpcTimeout);
+    sp<SlowService> service = new SlowService(serviceIpcTimeout);
+    setMockServiceManager(service);
+
+    optind = 1; // mimic Lshal::parseArg()
+    EXPECT_NE(0u, mockList->main(createArg({"lshal", "--types=b", "-i", "--neat"})));
+    EXPECT_LE(std::chrono::system_clock::now(), start + 5 * lshalIpcTimeout)
+            << "The main thread should not be blocked by the background task";
+}
+
 class ListVintfTest : public ListTest {
 public:
     virtual void SetUp() override {
@@ -1079,5 +1186,6 @@
 
 int main(int argc, char **argv) {
     ::testing::InitGoogleMock(&argc, argv);
-    return RUN_ALL_TESTS();
+    // Use _exit() to force terminate background threads in Timeout.h
+    _exit(RUN_ALL_TESTS());
 }
diff --git a/include/android/performance_hint.h b/include/android/performance_hint.h
index 9d2c791..30200c7 100644
--- a/include/android/performance_hint.h
+++ b/include/android/performance_hint.h
@@ -123,7 +123,8 @@
   *
   * @return APerformanceHintManager instance on success, nullptr on failure.
   */
-APerformanceHintManager* _Nullable APerformanceHint_getManager() __INTRODUCED_IN(__ANDROID_API_T__);
+APerformanceHintManager* _Nullable APerformanceHint_getManager()
+                         __INTRODUCED_IN(__ANDROID_API_T__);
 
 /**
  * Creates a session for the given set of threads and sets their initial target work
@@ -260,7 +261,8 @@
  *
  * @param aWorkDuration The {@link AWorkDuration} created by calling {@link AWorkDuration_create()}
  */
-void AWorkDuration_release(AWorkDuration* _Nonnull WorkDuration) __INTRODUCED_IN(__ANDROID_API_V__);
+void AWorkDuration_release(AWorkDuration* _Nonnull aWorkDuration)
+     __INTRODUCED_IN(__ANDROID_API_V__);
 
 /**
  * Sets the work period start timestamp in nanoseconds.
diff --git a/include/android/thermal.h b/include/android/thermal.h
index 0b57e93..fa168cd 100644
--- a/include/android/thermal.h
+++ b/include/android/thermal.h
@@ -111,7 +111,7 @@
  * It's passed the updated thermal status as parameter, as well as the
  * pointer provided by the client that registered a callback.
  */
-typedef void (*AThermal_StatusCallback)(void* data, AThermalStatus status);
+typedef void (*AThermal_StatusCallback)(void* _Nullable data, AThermalStatus status);
 
 /**
   * Acquire an instance of the thermal manager. This must be freed using
@@ -121,7 +121,7 @@
   *
   * @return manager instance on success, nullptr on failure.
   */
-AThermalManager* AThermal_acquireManager() __INTRODUCED_IN(30);
+AThermalManager* _Nonnull AThermal_acquireManager() __INTRODUCED_IN(30);
 
 /**
  * Release the thermal manager pointer acquired via
@@ -131,7 +131,7 @@
  *
  * @param manager The manager to be released.
  */
-void AThermal_releaseManager(AThermalManager *manager) __INTRODUCED_IN(30);
+void AThermal_releaseManager(AThermalManager* _Nonnull manager) __INTRODUCED_IN(30);
 
 /**
   * Gets the current thermal status.
@@ -143,7 +143,8 @@
   *
   * @return current thermal status, ATHERMAL_STATUS_ERROR on failure.
   */
-AThermalStatus AThermal_getCurrentThermalStatus(AThermalManager *manager) __INTRODUCED_IN(30);
+AThermalStatus
+AThermal_getCurrentThermalStatus(AThermalManager* _Nonnull manager) __INTRODUCED_IN(30);
 
 /**
  * Register the thermal status listener for thermal status change.
@@ -160,8 +161,9 @@
  *         EPERM if the required permission is not held.
  *         EPIPE if communication with the system service has failed.
  */
-int AThermal_registerThermalStatusListener(AThermalManager *manager,
-        AThermal_StatusCallback callback, void *data) __INTRODUCED_IN(30);
+int AThermal_registerThermalStatusListener(AThermalManager* _Nonnull manager,
+                                           AThermal_StatusCallback _Nullable callback,
+                                           void* _Nullable data) __INTRODUCED_IN(30);
 
 /**
  * Unregister the thermal status listener previously resgistered.
@@ -178,8 +180,9 @@
  *         EPERM if the required permission is not held.
  *         EPIPE if communication with the system service has failed.
  */
-int AThermal_unregisterThermalStatusListener(AThermalManager *manager,
-        AThermal_StatusCallback callback, void *data) __INTRODUCED_IN(30);
+int AThermal_unregisterThermalStatusListener(AThermalManager* _Nonnull manager,
+                                             AThermal_StatusCallback _Nullable callback,
+                                             void* _Nullable data) __INTRODUCED_IN(30);
 
 /**
  * Provides an estimate of how much thermal headroom the device currently has before
@@ -219,8 +222,8 @@
  *         as described above. Returns NaN if the device does not support this functionality or
  *         if this function is called significantly faster than once per second.
   */
-float AThermal_getThermalHeadroom(AThermalManager *manager,
-        int forecastSeconds) __INTRODUCED_IN(31);
+float AThermal_getThermalHeadroom(AThermalManager* _Nonnull manager,
+                                  int forecastSeconds) __INTRODUCED_IN(31);
 
 /**
  * This struct defines an instance of headroom threshold value and its status.
@@ -282,9 +285,10 @@
  *         EPIPE if communication with the system service has failed.
  *         ENOSYS if the feature is disabled by the current system.
  */
-int AThermal_getThermalHeadroomThresholds(AThermalManager* manager,
-                                          const AThermalHeadroomThreshold ** outThresholds,
-                                          size_t* size) __INTRODUCED_IN(35);
+int AThermal_getThermalHeadroomThresholds(AThermalManager* _Nonnull manager,
+                                          const AThermalHeadroomThreshold* _Nonnull
+                                          * _Nullable outThresholds,
+                                          size_t* _Nonnull size) __INTRODUCED_IN(35);
 
 #ifdef __cplusplus
 }
diff --git a/include/input/VirtualInputDevice.h b/include/input/VirtualInputDevice.h
index 21a2877..222dac8 100644
--- a/include/input/VirtualInputDevice.h
+++ b/include/input/VirtualInputDevice.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2023 The Android Open Source Project
+ * 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.
@@ -64,6 +64,8 @@
 
 class VirtualMouse : public VirtualInputDevice {
 public:
+    // Expose to share with VirtualStylus.
+    static const std::map<int, UinputAction> BUTTON_ACTION_MAPPING;
     VirtualMouse(android::base::unique_fd fd);
     virtual ~VirtualMouse() override;
     bool writeButtonEvent(int32_t androidButtonCode, int32_t androidAction,
@@ -74,12 +76,13 @@
                           std::chrono::nanoseconds eventTime);
 
 private:
-    static const std::map<int, UinputAction> BUTTON_ACTION_MAPPING;
     static const std::map<int, int> BUTTON_CODE_MAPPING;
 };
 
 class VirtualTouchscreen : public VirtualInputDevice {
 public:
+    // Expose to share with VirtualStylus.
+    static const std::map<int, UinputAction> TOUCH_ACTION_MAPPING;
     VirtualTouchscreen(android::base::unique_fd fd);
     virtual ~VirtualTouchscreen() override;
     // TODO(b/259554911): changing float parameters to int32_t.
@@ -88,9 +91,7 @@
                          std::chrono::nanoseconds eventTime);
 
 private:
-    static const std::map<int, UinputAction> TOUCH_ACTION_MAPPING;
     static const std::map<int, int> TOOL_TYPE_MAPPING;
-
     /* The set of active touch pointers on this device.
      * We only allow pointer id to go up to MAX_POINTERS because the maximum slots of virtual
      * touchscreen is set up with MAX_POINTERS. Note that in other cases Android allows pointer id
@@ -101,4 +102,24 @@
     bool handleTouchDown(int32_t pointerId, std::chrono::nanoseconds eventTime);
     bool handleTouchUp(int32_t pointerId, std::chrono::nanoseconds eventTime);
 };
+
+class VirtualStylus : public VirtualInputDevice {
+public:
+    VirtualStylus(android::base::unique_fd fd);
+    ~VirtualStylus() override;
+    bool writeMotionEvent(int32_t toolType, int32_t action, int32_t locationX, int32_t locationY,
+                          int32_t pressure, int32_t tiltX, int32_t tiltY,
+                          std::chrono::nanoseconds eventTime);
+    bool writeButtonEvent(int32_t androidButtonCode, int32_t androidAction,
+                          std::chrono::nanoseconds eventTime);
+
+private:
+    static const std::map<int, int> TOOL_TYPE_MAPPING;
+    static const std::map<int, int> BUTTON_CODE_MAPPING;
+    // True if the stylus is touching or hovering on the screen.
+    bool mIsStylusDown;
+    bool handleStylusDown(uint16_t tool, std::chrono::nanoseconds eventTime);
+    bool handleStylusUp(uint16_t tool, std::chrono::nanoseconds eventTime);
+};
+
 } // namespace android
diff --git a/include/private/performance_hint_private.h b/include/private/performance_hint_private.h
index d50c5f8..d8f9db4 100644
--- a/include/private/performance_hint_private.h
+++ b/include/private/performance_hint_private.h
@@ -53,6 +53,26 @@
      * CPU resources to what was used previously, and must wake up if inactive.
      */
     CPU_LOAD_RESUME = 3,
+
+    /**
+     * This hint indicates an increase in GPU workload intensity. It means that
+     * this hint session needs extra GPU resources to meet the target duration.
+     * This hint must be sent before reporting the actual duration to the session.
+     */
+    GPU_LOAD_UP = 5,
+
+    /**
+     * This hint indicates a decrease in GPU workload intensity. It means that
+     * this hint session can reduce GPU resources and still meet the target duration.
+     */
+    GPU_LOAD_DOWN = 6,
+
+    /*
+     * This hint indicates an upcoming GPU workload that is completely changed and
+     * unknown. It means that the hint session should reset GPU resources to a known
+     * baseline to prepare for an arbitrary load, and must wake up if inactive.
+     */
+    GPU_LOAD_RESET = 7,
 };
 
 /**
diff --git a/libs/binder/UtilsHost.h b/libs/binder/UtilsHost.h
index b582f17..d6fe9fa 100644
--- a/libs/binder/UtilsHost.h
+++ b/libs/binder/UtilsHost.h
@@ -16,6 +16,7 @@
 
 #pragma once
 
+#include <functional>
 #include <optional>
 #include <ostream>
 #include <string>
diff --git a/libs/binder/ndk/include_ndk/android/persistable_bundle.h b/libs/binder/ndk/include_ndk/android/persistable_bundle.h
index eff8104..98c0cb2 100644
--- a/libs/binder/ndk/include_ndk/android/persistable_bundle.h
+++ b/libs/binder/ndk/include_ndk/android/persistable_bundle.h
@@ -13,7 +13,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
+#pragma once
+
 #include <android/binder_parcel.h>
+#include <stdbool.h>
+#include <stdint.h>
 #include <sys/cdefs.h>
 #include <sys/types.h>
 
@@ -31,14 +36,30 @@
 struct APersistableBundle;
 typedef struct APersistableBundle APersistableBundle;
 
+enum {
+    /**
+     * This can be returned from functions that need to distinguish between an empty
+     * value and a non-existent key.
+     */
+    APERSISTABLEBUNDLE_KEY_NOT_FOUND = -1,
+
+    /**
+     * This can be returned from functions that take a APersistableBundle_stringAllocator.
+     * This means the allocator has failed and returned a nullptr.
+     */
+    APERSISTABLEBUNDLE_ALLOCATOR_FAILED = -2,
+};
+
 /**
  * This is a user supplied allocator that allocates a buffer for the
- * APersistableBundle APIs to fill in with a string.
+ * APersistableBundle APIs to fill in with a UTF-8 string.
+ * The caller that supplies this function is responsible for freeing the
+ * returned data.
  *
  * \param the required size in bytes for the allocated buffer
- * \param  void* _Nullable context if needed by the callback
+ * \param context pointer if needed by the callback
  *
- * \return allocated buffer of sizeBytes. Null if allocation failed.
+ * \return allocated buffer of sizeBytes for a UTF-8 string. Null if allocation failed.
  */
 typedef char* _Nullable (*_Nonnull APersistableBundle_stringAllocator)(int32_t sizeBytes,
                                                                        void* _Nullable context);
@@ -54,10 +75,12 @@
 
 /**
  * Create a new APersistableBundle based off an existing APersistableBundle.
+ * This is a deep copy, so the new APersistableBundle has its own values from
+ * copying the original underlying PersistableBundle.
  *
  * Available since API level __ANDROID_API_V__.
  *
- * \param bundle to duplicate
+ * \param pBundle to duplicate
  *
  * \return Pointer to a new APersistableBundle
  */
@@ -68,11 +91,11 @@
  * Delete an APersistableBundle. This must always be called when finished using
  * the object.
  *
- * \param bundle to delete
+ * \param pBundle to delete. No-op if null.
  *
  * Available since API level __ANDROID_API_V__.
  */
-void APersistableBundle_delete(APersistableBundle* _Nonnull pBundle)
+void APersistableBundle_delete(APersistableBundle* _Nullable pBundle)
         __INTRODUCED_IN(__ANDROID_API_V__);
 
 /**
@@ -80,8 +103,8 @@
  *
  * Available since API level __ANDROID_API_V__.
  *
- * \param lhs bundle to compare agains the other param
- * \param rhs bundle to compare agains the other param
+ * \param lhs bundle to compare against the other param
+ * \param rhs bundle to compare against the other param
  *
  * \return true when equal, false when not
  */
@@ -134,11 +157,11 @@
  *
  * Available since API level __ANDROID_API_V__.
  *
- * \param bundle to get the size of (number of mappings)
+ * \param pBundle to get the size of (number of mappings)
  *
  * \return number of mappings in the object
  */
-int32_t APersistableBundle_size(APersistableBundle* _Nonnull pBundle)
+int32_t APersistableBundle_size(const APersistableBundle* _Nonnull pBundle)
         __INTRODUCED_IN(__ANDROID_API_V__);
 
 /**
@@ -146,8 +169,8 @@
  *
  * Available since API level __ANDROID_API_V__.
  *
- * \param bundle to operate on
- * \param key for the mapping to erase
+ * \param pBundle to operate on
+ * \param key for the mapping in UTF-8 to erase
  *
  * \return number of entries erased. Either 0 or 1.
  */
@@ -158,8 +181,8 @@
  * Put a boolean associated with the provided key.
  * New values with the same key will overwrite existing values.
  *
- * \param bundle to operate on
- * \param key for the mapping
+ * \param pBundle to operate on
+ * \param key for the mapping in UTF-8
  * \param value to put for the mapping
  *
  * Available since API level __ANDROID_API_V__.
@@ -171,9 +194,9 @@
  * Put an int32_t associated with the provided key.
  * New values with the same key will overwrite existing values.
  *
- * \param bundle to operate on
- * \param key for the mapping
- * \param value to put for the mapping
+ * \param pBundle to operate on
+ * \param key for the mapping in UTF-8
+ * \param val value to put for the mapping
  *
  * Available since API level __ANDROID_API_V__.
  */
@@ -184,9 +207,9 @@
  * Put an int64_t associated with the provided key.
  * New values with the same key will overwrite existing values.
  *
- * \param bundle to operate on
- * \param key for the mapping
- * \param value to put for the mapping
+ * \param pBundle to operate on
+ * \param key for the mapping in UTF-8
+ * \param val value to put for the mapping
  *
  * Available since API level __ANDROID_API_V__.
  */
@@ -197,9 +220,9 @@
  * Put a double associated with the provided key.
  * New values with the same key will overwrite existing values.
  *
- * \param bundle to operate on
- * \param key for the mapping
- * \param value to put for the mapping
+ * \param pBundle to operate on
+ * \param key for the mapping in UTF-8
+ * \param val value to put for the mapping
  *
  * Available since API level __ANDROID_API_V__.
  */
@@ -209,10 +232,11 @@
 /**
  * Put a string associated with the provided key.
  * New values with the same key will overwrite existing values.
+ * The value is copied.
  *
- * \param bundle to operate on
- * \param key for the mapping
- * \param value to put for the mapping
+ * \param pBundle to operate on
+ * \param key for the mapping in UTF-8
+ * \param vec vector to put for the mapping
  *
  * Available since API level __ANDROID_API_V__.
  */
@@ -222,11 +246,12 @@
 /**
  * Put a boolean vector associated with the provided key.
  * New values with the same key will overwrite existing values.
+ * The values are copied.
  *
- * \param bundle to operate on
- * \param key for the mapping
- * \param value to put for the mapping
- * \param size in number of elements in the vector
+ * \param pBundle to operate on
+ * \param key for the mapping in UTF-8
+ * \param vec vector to put for the mapping
+ * \param num number of elements in the vector
  *
  * Available since API level __ANDROID_API_V__.
  */
@@ -237,11 +262,12 @@
 /**
  * Put an int32_t vector associated with the provided key.
  * New values with the same key will overwrite existing values.
+ * The values are copied.
  *
- * \param bundle to operate on
- * \param key for the mapping
- * \param value to put for the mapping
- * \param size in number of elements in the vector
+ * \param pBundle to operate on
+ * \param key for the mapping in UTF-8
+ * \param vec vector to put for the mapping
+ * \param num number of elements in the vector
  *
  * Available since API level __ANDROID_API_V__.
  */
@@ -252,11 +278,12 @@
 /**
  * Put an int64_t vector associated with the provided key.
  * New values with the same key will overwrite existing values.
+ * The values are copied.
  *
- * \param bundle to operate on
- * \param key for the mapping
- * \param value to put for the mapping
- * \param size in number of elements in the vector
+ * \param pBundle to operate on
+ * \param key for the mapping in UTF-8
+ * \param vec vector to put for the mapping
+ * \param num number of elements in the vector
  *
  * Available since API level __ANDROID_API_V__.
  */
@@ -267,11 +294,12 @@
 /**
  * Put a double vector associated with the provided key.
  * New values with the same key will overwrite existing values.
+ * The values are copied.
  *
- * \param bundle to operate on
- * \param key for the mapping
- * \param value to put for the mapping
- * \param size in number of elements in the vector
+ * \param pBundle to operate on
+ * \param key for the mapping in UTF-8
+ * \param vec vector to put for the mapping
+ * \param num number of elements in the vector
  *
  * Available since API level __ANDROID_API_V__.
  */
@@ -282,11 +310,12 @@
 /**
  * Put a string vector associated with the provided key.
  * New values with the same key will overwrite existing values.
+ * The values are copied.
  *
- * \param bundle to operate on
- * \param key for the mapping
- * \param value to put for the mapping
- * \param size in number of elements in the vector
+ * \param pBundle to operate on
+ * \param key for the mapping in UTF-8
+ * \param vec vector to put for the mapping
+ * \param num number of elements in the vector
  *
  * Available since API level __ANDROID_API_V__.
  */
@@ -298,10 +327,11 @@
 /**
  * Put an APersistableBundle associated with the provided key.
  * New values with the same key will overwrite existing values.
+ * The value is deep-copied.
  *
- * \param bundle to operate on
- * \param key for the mapping
- * \param value to put for the mapping
+ * \param pBundle to operate on
+ * \param key for the mapping in UTF-8
+ * \param val value to put for the mapping
  *
  * Available since API level __ANDROID_API_V__.
  */
@@ -315,9 +345,9 @@
  *
  * Available since API level __ANDROID_API_V__.
  *
- * \param bundle to operate on
- * \param key for the mapping
- * \param nonnull pointer to write the value to
+ * \param pBundle to operate on
+ * \param key for the mapping in UTF-8
+ * \param val pointer to write the value to
  *
  * \return true if a value exists for the provided key
  */
@@ -330,9 +360,9 @@
  *
  * Available since API level __ANDROID_API_V__.
  *
- * \param bundle to operate on
- * \param key for the mapping
- * \param nonnull pointer to write the value to
+ * \param pBundle to operate on
+ * \param key for the mapping in UTF-8
+ * \param val pointer to write the value to
  *
  * \return true if a value exists for the provided key
  */
@@ -344,9 +374,9 @@
  *
  * Available since API level __ANDROID_API_V__.
  *
- * \param bundle to operate on
- * \param key for the mapping
- * \param nonnull pointer to write the value to
+ * \param pBundle to operate on
+ * \param key for the mapping in UTF-8
+ * \param val pointer to write the value to
  *
  * \return true if a value exists for the provided key
  */
@@ -359,9 +389,9 @@
  *
  * Available since API level __ANDROID_API_V__.
  *
- * \param bundle to operate on
- * \param key for the mapping
- * \param nonnull pointer to write the value to
+ * \param pBundle to operate on
+ * \param key for the mapping in UTF-8
+ * \param val pointer to write the value to
  *
  * \return true if a value exists for the provided key
  */
@@ -371,17 +401,19 @@
 
 /**
  * Get a string associated with the provided key.
+ * The caller is responsible for freeing the returned data.
  *
  * Available since API level __ANDROID_API_V__.
  *
- * \param bundle to operate on
- * \param key for the mapping
- * \param nonnull pointer to write the value to
- * \param function pointer to the string dup allocator
+ * \param pBundle to operate on
+ * \param key for the mapping in UTF-8
+ * \param val pointer to write the value to in UTF-8
+ * \param stringAllocator function pointer to the string allocator
+ * \param context pointer that will be passed to the stringAllocator
  *
- * \return size of string associated with the provided key on success
- *         0 if no string exists for the provided key
- *         -1 if the provided allocator fails and returns false
+ * \return size of string in bytes associated with the provided key on success
+ *         APERSISTABLEBUNDLE_KEY_NOT_FOUND if the key was not found
+ *         APERSISTABLEBUNDLE_ALLOCATOR_FAILED if the provided allocator fails
  */
 int32_t APersistableBundle_getString(const APersistableBundle* _Nonnull pBundle,
                                      const char* _Nonnull key, char* _Nullable* _Nonnull val,
@@ -393,7 +425,7 @@
  * provided pre-allocated buffer from the user.
  *
  * This function returns the size in bytes of stored vector.
- * The supplied buffer will be filled in based on the smaller of the suplied
+ * The supplied buffer will be filled in based on the smaller of the supplied
  * bufferSizeBytes or the actual size of the stored data.
  * If the buffer is null or if the supplied bufferSizeBytes is smaller than the
  * actual stored data, then not all of the stored data will be returned.
@@ -401,13 +433,14 @@
  * Users can call this function with null buffer and 0 bufferSizeBytes to get
  * the required size of the buffer to use on a subsequent call.
  *
- * \param bundle to operate on
- * \param key for the mapping
- * \param nonnull pointer to a pre-allocated buffer to write the values to
- * \param size of the pre-allocated buffer
+ * \param pBundle to operate on
+ * \param key for the mapping in UTF-8
+ * \param buffer pointer to a pre-allocated buffer to write the values to
+ * \param bufferSizeBytes size of the pre-allocated buffer
  *
  * \return size of the stored vector in bytes. This is the required size of the
  * pre-allocated user supplied buffer if all of the stored contents are desired.
+ *         APERSISTABLEBUNDLE_KEY_NOT_FOUND if the key was not found
  */
 int32_t APersistableBundle_getBooleanVector(const APersistableBundle* _Nonnull pBundle,
                                             const char* _Nonnull key, bool* _Nullable buffer,
@@ -419,7 +452,7 @@
  * provided pre-allocated buffer from the user.
  *
  * This function returns the size in bytes of stored vector.
- * The supplied buffer will be filled in based on the smaller of the suplied
+ * The supplied buffer will be filled in based on the smaller of the supplied
  * bufferSizeBytes or the actual size of the stored data.
  * If the buffer is null or if the supplied bufferSizeBytes is smaller than the
  * actual stored data, then not all of the stored data will be returned.
@@ -427,13 +460,14 @@
  * Users can call this function with null buffer and 0 bufferSizeBytes to get
  * the required size of the buffer to use on a subsequent call.
  *
- * \param bundle to operate on
- * \param key for the mapping
- * \param nonnull pointer to a pre-allocated buffer to write the values to
- * \param size of the pre-allocated buffer
+ * \param pBundle to operate on
+ * \param key for the mapping in UTF-8
+ * \param buffer pointer to a pre-allocated buffer to write the values to
+ * \param bufferSizeBytes size of the pre-allocated buffer
  *
  * \return size of the stored vector in bytes. This is the required size of the
  * pre-allocated user supplied buffer if all of the stored contents are desired.
+ *         APERSISTABLEBUNDLE_KEY_NOT_FOUND if the key was not found
  */
 int32_t APersistableBundle_getIntVector(const APersistableBundle* _Nonnull pBundle,
                                         const char* _Nonnull key, int32_t* _Nullable buffer,
@@ -444,7 +478,7 @@
  * provided pre-allocated buffer from the user.
  *
  * This function returns the size in bytes of stored vector.
- * The supplied buffer will be filled in based on the smaller of the suplied
+ * The supplied buffer will be filled in based on the smaller of the supplied
  * bufferSizeBytes or the actual size of the stored data.
  * If the buffer is null or if the supplied bufferSizeBytes is smaller than the
  * actual stored data, then not all of the stored data will be returned.
@@ -452,13 +486,14 @@
  * Users can call this function with null buffer and 0 bufferSizeBytes to get
  * the required size of the buffer to use on a subsequent call.
  *
- * \param bundle to operate on
- * \param key for the mapping
- * \param nonnull pointer to a pre-allocated buffer to write the values to
- * \param size of the pre-allocated buffer
+ * \param pBundle to operate on
+ * \param key for the mapping in UTF-8
+ * \param buffer pointer to a pre-allocated buffer to write the values to
+ * \param bufferSizeBytes size of the pre-allocated buffer
  *
  * \return size of the stored vector in bytes. This is the required size of the
  * pre-allocated user supplied buffer if all of the stored contents are desired.
+ *         APERSISTABLEBUNDLE_KEY_NOT_FOUND if the key was not found
  */
 int32_t APersistableBundle_getLongVector(const APersistableBundle* _Nonnull pBundle,
                                          const char* _Nonnull key, int64_t* _Nullable buffer,
@@ -470,7 +505,7 @@
  * provided pre-allocated buffer from the user.
  *
  * This function returns the size in bytes of stored vector.
- * The supplied buffer will be filled in based on the smaller of the suplied
+ * The supplied buffer will be filled in based on the smaller of the supplied
  * bufferSizeBytes or the actual size of the stored data.
  * If the buffer is null or if the supplied bufferSizeBytes is smaller than the
  * actual stored data, then not all of the stored data will be returned.
@@ -478,13 +513,14 @@
  * Users can call this function with null buffer and 0 bufferSizeBytes to get
  * the required size of the buffer to use on a subsequent call.
  *
- * \param bundle to operate on
- * \param key for the mapping
- * \param nonnull pointer to a pre-allocated buffer to write the values to
- * \param size of the pre-allocated buffer
+ * \param pBundle to operate on
+ * \param key for the mapping in UTF-8
+ * \param buffer pointer to a pre-allocated buffer to write the values to
+ * \param bufferSizeBytes size of the pre-allocated buffer
  *
  * \return size of the stored vector in bytes. This is the required size of the
  * pre-allocated user supplied buffer if all of the stored contents are desired.
+ *         APERSISTABLEBUNDLE_KEY_NOT_FOUND if the key was not found
  */
 int32_t APersistableBundle_getDoubleVector(const APersistableBundle* _Nonnull pBundle,
                                            const char* _Nonnull key, double* _Nullable buffer,
@@ -496,9 +532,10 @@
  * provided pre-allocated buffer from the user. The user must provide an
  * APersistableBundle_stringAllocator for the individual strings to be
  * allocated.
+ * The caller is responsible for freeing the returned data.
  *
  * This function returns the size in bytes of stored vector.
- * The supplied buffer will be filled in based on the smaller of the suplied
+ * The supplied buffer will be filled in based on the smaller of the supplied
  * bufferSizeBytes or the actual size of the stored data.
  * If the buffer is null or if the supplied bufferSizeBytes is smaller than the
  * actual stored data, then not all of the stored data will be returned.
@@ -506,17 +543,18 @@
  * Users can call this function with null buffer and 0 bufferSizeBytes to get
  * the required size of the buffer to use on a subsequent call.
  *
- * \param bundle to operate on
- * \param key for the mapping
- * \param nonnull pointer to a pre-allocated buffer to write the values to
- * \param size of the pre-allocated buffer
- * \param function pointer to the string dup allocator
+ * \param pBundle to operate on
+ * \param key for the mapping in UTF-8
+ * \param buffer pointer to a pre-allocated buffer to write the string pointers to
+ * \param bufferSizeBytes size of the pre-allocated buffer
+ * \param stringAllocator function pointer to the string allocator
+ * \param context pointer that will be passed to the stringAllocator
  *
  * \return size of the stored vector in bytes. This is the required size of the
  * pre-allocated user supplied buffer if all of the stored contents are desired.
  *         0 if no string vector exists for the provided key
- *         -1 if the user supplied APersistableBundle_stringAllocator returns
- *         false
+ *         APERSISTABLEBUNDLE_KEY_NOT_FOUND if the key was not found
+ *         APERSISTABLEBUNDLE_ALLOCATOR_FAILED if the provided allocator fails
  */
 int32_t APersistableBundle_getStringVector(const APersistableBundle* _Nonnull pBundle,
                                            const char* _Nonnull key,
@@ -531,9 +569,9 @@
  *
  * Available since API level __ANDROID_API_V__.
  *
- * \param bundle to operate on
- * \param key for the mapping
- * \param nonnull pointer to an APersistableBundle pointer to write to point to
+ * \param pBundle to operate on
+ * \param key for the mapping in UTF-8
+ * \param val pointer to an APersistableBundle pointer to write to point to
  * a new copy of the stored APersistableBundle. The caller takes ownership of
  * the new APersistableBundle and must be deleted with
  * APersistableBundle_delete.
@@ -550,9 +588,10 @@
  * provided pre-allocated buffer from the user. The user must provide an
  * APersistableBundle_stringAllocator for the individual strings to be
  * allocated.
+ * The caller is responsible for freeing the returned data.
  *
  * This function returns the size in bytes required to fit the fill list of keys.
- * The supplied buffer will be filled in based on the smaller of the suplied
+ * The supplied buffer will be filled in based on the smaller of the supplied
  * bufferSizeBytes or the actual size of the stored data.
  * If the buffer is null or if the supplied bufferSizeBytes is smaller than the
  * actual stored data, then not all of the stored data will be returned.
@@ -560,16 +599,15 @@
  * Users can call this function with null buffer and 0 bufferSizeBytes to get
  * the required size of the buffer to use on a subsequent call.
  *
- * \param bundle to operate on
- * \param nonnull pointer to a pre-allocated buffer to write the values to
- * \param size of the pre-allocated buffer
- * \param function pointer to the string dup allocator
+ * \param pBundle to operate on
+ * \param outKeys pointer to a pre-allocated buffer to write the UTF-8 keys to
+ * \param bufferSizeBytes size of the pre-allocated buffer
+ * \param stringAllocator function pointer to the string allocator
+ * \param context pointer that will be passed to the stringAllocator
  *
  * \return size of the buffer of keys in bytes. This is the required size of the
  * pre-allocated user supplied buffer if all of the stored contents are desired.
- *         0 if no string vector exists for the provided key
- *         -1 if the user supplied APersistableBundle_stringAllocator returns
- *         false
+ *         APERSISTABLEBUNDLE_ALLOCATOR_FAILED if the provided allocator fails
  */
 int32_t APersistableBundle_getBooleanKeys(const APersistableBundle* _Nonnull pBundle,
                                           char* _Nullable* _Nullable outKeys,
@@ -583,9 +621,10 @@
  * provided pre-allocated buffer from the user. The user must provide an
  * APersistableBundle_stringAllocator for the individual strings to be
  * allocated.
+ * The caller is responsible for freeing the returned data.
  *
  * This function returns the size in bytes required to fit the fill list of keys.
- * The supplied buffer will be filled in based on the smaller of the suplied
+ * The supplied buffer will be filled in based on the smaller of the supplied
  * bufferSizeBytes or the actual size of the stored data.
  * If the buffer is null or if the supplied bufferSizeBytes is smaller than the
  * actual stored data, then not all of the stored data will be returned.
@@ -593,16 +632,15 @@
  * Users can call this function with null buffer and 0 bufferSizeBytes to get
  * the required size of the buffer to use on a subsequent call.
  *
- * \param bundle to operate on
- * \param nonnull pointer to a pre-allocated buffer to write the values to
- * \param size of the pre-allocated buffer
- * \param function pointer to the string dup allocator
+ * \param pBundle to operate on
+ * \param outKeys pointer to a pre-allocated buffer to write the UTF-8 keys to
+ * \param bufferSizeBytes size of the pre-allocated buffer
+ * \param stringAllocator function pointer to the string allocator
+ * \param context pointer that will be passed to the stringAllocator
  *
  * \return size of the buffer of keys in bytes. This is the required size of the
  * pre-allocated user supplied buffer if all of the stored contents are desired.
- *         0 if no string vector exists for the provided key
- *         -1 if the user supplied APersistableBundle_stringAllocator returns
- *         false
+ *         APERSISTABLEBUNDLE_ALLOCATOR_FAILED if the provided allocator fails
  */
 int32_t APersistableBundle_getIntKeys(const APersistableBundle* _Nonnull pBundle,
                                       char* _Nullable* _Nullable outKeys, int32_t bufferSizeBytes,
@@ -614,9 +652,10 @@
  * provided pre-allocated buffer from the user. The user must provide an
  * APersistableBundle_stringAllocator for the individual strings to be
  * allocated.
+ * The caller is responsible for freeing the returned data.
  *
  * This function returns the size in bytes required to fit the fill list of keys.
- * The supplied buffer will be filled in based on the smaller of the suplied
+ * The supplied buffer will be filled in based on the smaller of the supplied
  * bufferSizeBytes or the actual size of the stored data.
  * If the buffer is null or if the supplied bufferSizeBytes is smaller than the
  * actual stored data, then not all of the stored data will be returned.
@@ -624,16 +663,15 @@
  * Users can call this function with null buffer and 0 bufferSizeBytes to get
  * the required size of the buffer to use on a subsequent call.
  *
- * \param bundle to operate on
- * \param nonnull pointer to a pre-allocated buffer to write the values to
- * \param size of the pre-allocated buffer
- * \param function pointer to the string dup allocator
+ * \param pBundle to operate on
+ * \param outKeys pointer to a pre-allocated buffer to write the UTF-8 keys to
+ * \param bufferSizeBytes size of the pre-allocated buffer
+ * \param stringAllocator function pointer to the string allocator
+ * \param context pointer that will be passed to the stringAllocator
  *
  * \return size of the buffer of keys in bytes. This is the required size of the
  * pre-allocated user supplied buffer if all of the stored contents are desired.
- *         0 if no string vector exists for the provided key
- *         -1 if the user supplied APersistableBundle_stringAllocator returns
- *         false
+ *         APERSISTABLEBUNDLE_ALLOCATOR_FAILED if the provided allocator fails
  */
 int32_t APersistableBundle_getLongKeys(const APersistableBundle* _Nonnull pBundle,
                                        char* _Nullable* _Nullable outKeys, int32_t bufferSizeBytes,
@@ -645,9 +683,10 @@
  * provided pre-allocated buffer from the user. The user must provide an
  * APersistableBundle_stringAllocator for the individual strings to be
  * allocated.
+ * The caller is responsible for freeing the returned data.
  *
  * This function returns the size in bytes required to fit the fill list of keys.
- * The supplied buffer will be filled in based on the smaller of the suplied
+ * The supplied buffer will be filled in based on the smaller of the supplied
  * bufferSizeBytes or the actual size of the stored data.
  * If the buffer is null or if the supplied bufferSizeBytes is smaller than the
  * actual stored data, then not all of the stored data will be returned.
@@ -655,16 +694,15 @@
  * Users can call this function with null buffer and 0 bufferSizeBytes to get
  * the required size of the buffer to use on a subsequent call.
  *
- * \param bundle to operate on
- * \param nonnull pointer to a pre-allocated buffer to write the values to
- * \param size of the pre-allocated buffer
- * \param function pointer to the string dup allocator
+ * \param pBundle to operate on
+ * \param outKeys pointer to a pre-allocated buffer to write the UTF-8 keys to
+ * \param bufferSizeBytes size of the pre-allocated buffer
+ * \param stringAllocator function pointer to the string allocator
+ * \param context pointer that will be passed to the stringAllocator
  *
  * \return size of the buffer of keys in bytes. This is the required size of the
  * pre-allocated user supplied buffer if all of the stored contents are desired.
- *         0 if no string vector exists for the provided key
- *         -1 if the user supplied APersistableBundle_stringAllocator returns
- *         false
+ *         APERSISTABLEBUNDLE_ALLOCATOR_FAILED if the provided allocator fails
  */
 int32_t APersistableBundle_getDoubleKeys(const APersistableBundle* _Nonnull pBundle,
                                          char* _Nullable* _Nullable outKeys,
@@ -678,9 +716,10 @@
  * provided pre-allocated buffer from the user. The user must provide an
  * APersistableBundle_stringAllocator for the individual strings to be
  * allocated.
+ * The caller is responsible for freeing the returned data.
  *
  * This function returns the size in bytes required to fit the fill list of keys.
- * The supplied buffer will be filled in based on the smaller of the suplied
+ * The supplied buffer will be filled in based on the smaller of the supplied
  * bufferSizeBytes or the actual size of the stored data.
  * If the buffer is null or if the supplied bufferSizeBytes is smaller than the
  * actual stored data, then not all of the stored data will be returned.
@@ -688,16 +727,15 @@
  * Users can call this function with null buffer and 0 bufferSizeBytes to get
  * the required size of the buffer to use on a subsequent call.
  *
- * \param bundle to operate on
- * \param nonnull pointer to a pre-allocated buffer to write the values to
- * \param size of the pre-allocated buffer
- * \param function pointer to the string dup allocator
+ * \param pBundle to operate on
+ * \param outKeys pointer to a pre-allocated buffer to write the UTF-8 keys to
+ * \param bufferSizeBytes size of the pre-allocated buffer
+ * \param stringAllocator function pointer to the string allocator
+ * \param context pointer that will be passed to the stringAllocator
  *
  * \return size of the buffer of keys in bytes. This is the required size of the
  * pre-allocated user supplied buffer if all of the stored contents are desired.
- *         0 if no string vector exists for the provided key
- *         -1 if the user supplied APersistableBundle_stringAllocator returns
- *         false
+ *         APERSISTABLEBUNDLE_ALLOCATOR_FAILED if the provided allocator fails
  */
 int32_t APersistableBundle_getStringKeys(const APersistableBundle* _Nonnull pBundle,
                                          char* _Nullable* _Nullable outKeys,
@@ -711,9 +749,10 @@
  * provided pre-allocated buffer from the user. The user must provide an
  * APersistableBundle_stringAllocator for the individual strings to be
  * allocated.
+ * The caller is responsible for freeing the returned data.
  *
  * This function returns the size in bytes required to fit the fill list of keys.
- * The supplied buffer will be filled in based on the smaller of the suplied
+ * The supplied buffer will be filled in based on the smaller of the supplied
  * bufferSizeBytes or the actual size of the stored data.
  * If the buffer is null or if the supplied bufferSizeBytes is smaller than the
  * actual stored data, then not all of the stored data will be returned.
@@ -721,16 +760,15 @@
  * Users can call this function with null buffer and 0 bufferSizeBytes to get
  * the required size of the buffer to use on a subsequent call.
  *
- * \param bundle to operate on
- * \param nonnull pointer to a pre-allocated buffer to write the values to
- * \param size of the pre-allocated buffer
- * \param function pointer to the string dup allocator
+ * \param pBundle to operate on
+ * \param outKeys pointer to a pre-allocated buffer to write the UTF-8 keys to
+ * \param bufferSizeBytes size of the pre-allocated buffer
+ * \param stringAllocator function pointer to the string allocator
+ * \param context pointer that will be passed to the stringAllocator
  *
  * \return size of the buffer of keys in bytes. This is the required size of the
  * pre-allocated user supplied buffer if all of the stored contents are desired.
- *         0 if no string vector exists for the provided key
- *         -1 if the user supplied APersistableBundle_stringAllocator returns
- *         false
+ *         APERSISTABLEBUNDLE_ALLOCATOR_FAILED if the provided allocator fails
  */
 int32_t APersistableBundle_getBooleanVectorKeys(const APersistableBundle* _Nonnull pBundle,
                                                 char* _Nullable* _Nullable outKeys,
@@ -744,9 +782,10 @@
  * provided pre-allocated buffer from the user. The user must provide an
  * APersistableBundle_stringAllocator for the individual strings to be
  * allocated.
+ * The caller is responsible for freeing the returned data.
  *
  * This function returns the size in bytes required to fit the fill list of keys.
- * The supplied buffer will be filled in based on the smaller of the suplied
+ * The supplied buffer will be filled in based on the smaller of the supplied
  * bufferSizeBytes or the actual size of the stored data.
  * If the buffer is null or if the supplied bufferSizeBytes is smaller than the
  * actual stored data, then not all of the stored data will be returned.
@@ -754,16 +793,15 @@
  * Users can call this function with null buffer and 0 bufferSizeBytes to get
  * the required size of the buffer to use on a subsequent call.
  *
- * \param bundle to operate on
- * \param nonnull pointer to a pre-allocated buffer to write the values to
- * \param size of the pre-allocated buffer
- * \param function pointer to the string dup allocator
+ * \param pBundle to operate on
+ * \param outKeys pointer to a pre-allocated buffer to write the UTF-8 keys to
+ * \param bufferSizeBytes size of the pre-allocated buffer
+ * \param stringAllocator function pointer to the string allocator
+ * \param context pointer that will be passed to the stringAllocator
  *
  * \return size of the buffer of keys in bytes. This is the required size of the
  * pre-allocated user supplied buffer if all of the stored contents are desired.
- *         0 if no string vector exists for the provided key
- *         -1 if the user supplied APersistableBundle_stringAllocator returns
- *         false
+ *         APERSISTABLEBUNDLE_ALLOCATOR_FAILED if the provided allocator fails
  */
 int32_t APersistableBundle_getIntVectorKeys(const APersistableBundle* _Nonnull pBundle,
                                             char* _Nullable* _Nullable outKeys,
@@ -777,9 +815,10 @@
  * provided pre-allocated buffer from the user. The user must provide an
  * APersistableBundle_stringAllocator for the individual strings to be
  * allocated.
+ * The caller is responsible for freeing the returned data.
  *
  * This function returns the size in bytes required to fit the fill list of keys.
- * The supplied buffer will be filled in based on the smaller of the suplied
+ * The supplied buffer will be filled in based on the smaller of the supplied
  * bufferSizeBytes or the actual size of the stored data.
  * If the buffer is null or if the supplied bufferSizeBytes is smaller than the
  * actual stored data, then not all of the stored data will be returned.
@@ -787,16 +826,15 @@
  * Users can call this function with null buffer and 0 bufferSizeBytes to get
  * the required size of the buffer to use on a subsequent call.
  *
- * \param bundle to operate on
- * \param nonnull pointer to a pre-allocated buffer to write the values to
- * \param size of the pre-allocated buffer
- * \param function pointer to the string dup allocator
+ * \param pBundle to operate on
+ * \param outKeys pointer to a pre-allocated buffer to write the UTF-8 keys to
+ * \param bufferSizeBytes size of the pre-allocated buffer
+ * \param stringAllocator function pointer to the string allocator
+ * \param context pointer that will be passed to the stringAllocator
  *
  * \return size of the buffer of keys in bytes. This is the required size of the
  * pre-allocated user supplied buffer if all of the stored contents are desired.
- *         0 if no string vector exists for the provided key
- *         -1 if the user supplied APersistableBundle_stringAllocator returns
- *         false
+ *         APERSISTABLEBUNDLE_ALLOCATOR_FAILED if the provided allocator fails
  */
 int32_t APersistableBundle_getLongVectorKeys(const APersistableBundle* _Nonnull pBundle,
                                              char* _Nullable* _Nullable outKeys,
@@ -810,9 +848,10 @@
  * provided pre-allocated buffer from the user. The user must provide an
  * APersistableBundle_stringAllocator for the individual strings to be
  * allocated.
+ * The caller is responsible for freeing the returned data.
  *
  * This function returns the size in bytes required to fit the fill list of keys.
- * The supplied buffer will be filled in based on the smaller of the suplied
+ * The supplied buffer will be filled in based on the smaller of the supplied
  * bufferSizeBytes or the actual size of the stored data.
  * If the buffer is null or if the supplied bufferSizeBytes is smaller than the
  * actual stored data, then not all of the stored data will be returned.
@@ -820,16 +859,14 @@
  * Users can call this function with null buffer and 0 bufferSizeBytes to get
  * the required size of the buffer to use on a subsequent call.
  *
- * \param bundle to operate on
- * \param nonnull pointer to a pre-allocated buffer to write the values to
- * \param size of the pre-allocated buffer
- * \param function pointer to the string dup allocator
+ * \param pBundle to operate on
+ * \param outKeys pointer to a pre-allocated buffer to write the UTF-8 keys to
+ * \param bufferSizeBytes size of the pre-allocated buffer
+ * \param stringAllocator function pointer to the string allocator
+ * \param context pointer that will be passed to the stringAllocator
  *
  * \return size of the buffer of keys in bytes. This is the required size of the
  * pre-allocated user supplied buffer if all of the stored contents are desired.
- *         0 if no string vector exists for the provided key
- *         -1 if the user supplied APersistableBundle_stringAllocator returns
- *         false
  */
 int32_t APersistableBundle_getDoubleVectorKeys(const APersistableBundle* _Nonnull pBundle,
                                                char* _Nullable* _Nullable outKeys,
@@ -843,9 +880,10 @@
  * provided pre-allocated buffer from the user. The user must provide an
  * APersistableBundle_stringAllocator for the individual strings to be
  * allocated.
+ * The caller is responsible for freeing the returned data.
  *
  * This function returns the size in bytes required to fit the fill list of keys.
- * The supplied buffer will be filled in based on the smaller of the suplied
+ * The supplied buffer will be filled in based on the smaller of the supplied
  * bufferSizeBytes or the actual size of the stored data.
  * If the buffer is null or if the supplied bufferSizeBytes is smaller than the
  * actual stored data, then not all of the stored data will be returned.
@@ -853,15 +891,14 @@
  * Users can call this function with null buffer and 0 bufferSizeBytes to get
  * the required size of the buffer to use on a subsequent call.
  *
- * \param bundle to operate on
- * \param nonnull pointer to a pre-allocated buffer to write the values to
- * \param size of the pre-allocated buffer
- * \param function pointer to the string dup allocator
+ * \param pBundle to operate on
+ * \param outKeys pointer to a pre-allocated buffer to write the UTF-8 keys to
+ * \param bufferSizeBytes size of the pre-allocated buffer
+ * \param stringAllocator function pointer to the string allocator
+ * \param context pointer that will be passed to the stringAllocator
  *
  * \return size of the buffer of keys in bytes. This is the required size of the
  * pre-allocated user supplied buffer if all of the stored contents are desired.
- *         0 if no string vector exists for the provided key
- *         -1 if the user supplied APersistableBundle_stringAllocator returns
  *         false
  */
 int32_t APersistableBundle_getStringVectorKeys(const APersistableBundle* _Nonnull pBundle,
@@ -876,9 +913,10 @@
  * provided pre-allocated buffer from the user. The user must provide an
  * APersistableBundle_stringAllocator for the individual strings to be
  * allocated.
+ * The caller is responsible for freeing the returned data in bytes.
  *
  * This function returns the size in bytes required to fit the fill list of keys.
- * The supplied buffer will be filled in based on the smaller of the suplied
+ * The supplied buffer will be filled in based on the smaller of the supplied
  * bufferSizeBytes or the actual size of the stored data.
  * If the buffer is null or if the supplied bufferSizeBytes is smaller than the
  * actual stored data, then not all of the stored data will be returned.
@@ -886,16 +924,15 @@
  * Users can call this function with null buffer and 0 bufferSizeBytes to get
  * the required size of the buffer to use on a subsequent call.
  *
- * \param bundle to operate on
- * \param nonnull pointer to a pre-allocated buffer to write the values to
- * \param size of the pre-allocated buffer
- * \param function pointer to the string dup allocator
+ * \param pBundle to operate on
+ * \param outKeys pointer to a pre-allocated buffer to write the UTF-8 keys to
+ * \param bufferSizeBytes size of the pre-allocated buffer
+ * \param stringAllocator function pointer to the string allocator
+ * \param context pointer that will be passed to the stringAllocator
  *
  * \return size of the buffer of keys in bytes. This is the required size of the
  * pre-allocated user supplied buffer if all of the stored contents are desired.
- *         0 if no string vector exists for the provided key
- *         -1 if the user supplied APersistableBundle_stringAllocator returns
- *         false
+ *         APERSISTABLEBUNDLE_ALLOCATOR_FAILED if the provided allocator fails
  */
 int32_t APersistableBundle_getPersistableBundleKeys(
         const APersistableBundle* _Nonnull pBundle, char* _Nullable* _Nullable outKeys,
diff --git a/libs/binder/ndk/persistable_bundle.cpp b/libs/binder/ndk/persistable_bundle.cpp
index 404611c..9b6877d 100644
--- a/libs/binder/ndk/persistable_bundle.cpp
+++ b/libs/binder/ndk/persistable_bundle.cpp
@@ -76,7 +76,7 @@
     return pBundle->mPBundle.writeToParcel(AParcel_viewPlatformParcel(parcel));
 }
 
-int32_t APersistableBundle_size(APersistableBundle* pBundle) {
+int32_t APersistableBundle_size(const APersistableBundle* pBundle) {
     size_t size = pBundle->mPBundle.size();
     LOG_ALWAYS_FATAL_IF(size > INT32_MAX,
                         "The APersistableBundle has gotten too large! There will be an overflow in "
@@ -167,40 +167,42 @@
                                      void* context) {
     android::String16 outVal;
     bool ret = pBundle->mPBundle.getString(android::String16(key), &outVal);
-    if (ret) {
-        android::String8 tmp8(outVal);
-        *val = stringAllocator(tmp8.bytes() + 1, context);
-        if (*val) {
-            strncpy(*val, tmp8.c_str(), tmp8.bytes() + 1);
-            return tmp8.bytes();
-        } else {
-            return -1;
-        }
+    if (!ret) return APERSISTABLEBUNDLE_KEY_NOT_FOUND;
+    android::String8 tmp8(outVal);
+    *val = stringAllocator(tmp8.bytes() + 1, context);
+    if (*val) {
+        strncpy(*val, tmp8.c_str(), tmp8.bytes() + 1);
+        return tmp8.bytes();
+    } else {
+        return APERSISTABLEBUNDLE_ALLOCATOR_FAILED;
     }
-    return 0;
 }
 int32_t APersistableBundle_getBooleanVector(const APersistableBundle* pBundle, const char* key,
                                             bool* buffer, int32_t bufferSizeBytes) {
     std::vector<bool> newVec;
-    pBundle->mPBundle.getBooleanVector(android::String16(key), &newVec);
+    bool ret = pBundle->mPBundle.getBooleanVector(android::String16(key), &newVec);
+    if (!ret) return APERSISTABLEBUNDLE_KEY_NOT_FOUND;
     return getVecInternal<bool>(newVec, buffer, bufferSizeBytes);
 }
 int32_t APersistableBundle_getIntVector(const APersistableBundle* pBundle, const char* key,
                                         int32_t* buffer, int32_t bufferSizeBytes) {
     std::vector<int32_t> newVec;
-    pBundle->mPBundle.getIntVector(android::String16(key), &newVec);
+    bool ret = pBundle->mPBundle.getIntVector(android::String16(key), &newVec);
+    if (!ret) return APERSISTABLEBUNDLE_KEY_NOT_FOUND;
     return getVecInternal<int32_t>(newVec, buffer, bufferSizeBytes);
 }
 int32_t APersistableBundle_getLongVector(const APersistableBundle* pBundle, const char* key,
                                          int64_t* buffer, int32_t bufferSizeBytes) {
     std::vector<int64_t> newVec;
-    pBundle->mPBundle.getLongVector(android::String16(key), &newVec);
+    bool ret = pBundle->mPBundle.getLongVector(android::String16(key), &newVec);
+    if (!ret) return APERSISTABLEBUNDLE_KEY_NOT_FOUND;
     return getVecInternal<int64_t>(newVec, buffer, bufferSizeBytes);
 }
 int32_t APersistableBundle_getDoubleVector(const APersistableBundle* pBundle, const char* key,
                                            double* buffer, int32_t bufferSizeBytes) {
     std::vector<double> newVec;
-    pBundle->mPBundle.getDoubleVector(android::String16(key), &newVec);
+    bool ret = pBundle->mPBundle.getDoubleVector(android::String16(key), &newVec);
+    if (!ret) return APERSISTABLEBUNDLE_KEY_NOT_FOUND;
     return getVecInternal<double>(newVec, buffer, bufferSizeBytes);
 }
 int32_t APersistableBundle_getStringVector(const APersistableBundle* pBundle, const char* key,
@@ -208,7 +210,8 @@
                                            APersistableBundle_stringAllocator stringAllocator,
                                            void* context) {
     std::vector<android::String16> newVec;
-    pBundle->mPBundle.getStringVector(android::String16(key), &newVec);
+    bool ret = pBundle->mPBundle.getStringVector(android::String16(key), &newVec);
+    if (!ret) return APERSISTABLEBUNDLE_KEY_NOT_FOUND;
     return getStringsInternal<std::vector<android::String16>>(newVec, vec, bufferSizeBytes,
                                                               stringAllocator, context);
 }
diff --git a/libs/binder/ndk/persistable_bundle_internal.h b/libs/binder/ndk/persistable_bundle_internal.h
index 279c66f..bee10fd 100644
--- a/libs/binder/ndk/persistable_bundle_internal.h
+++ b/libs/binder/ndk/persistable_bundle_internal.h
@@ -61,7 +61,7 @@
     int32_t numAvailable = bufferSizeBytes / sizeof(char*);
     int32_t numFill = numAvailable < num ? numAvailable : num;
     if (!stringAllocator) {
-        return -1;
+        return APERSISTABLEBUNDLE_ALLOCATOR_FAILED;
     }
 
     if (numFill > 0 && buffer) {
@@ -70,7 +70,7 @@
             android::String8 tmp8 = android::String8(val);
             buffer[i] = stringAllocator(tmp8.bytes() + 1, context);
             if (buffer[i] == nullptr) {
-                return -1;
+                return APERSISTABLEBUNDLE_ALLOCATOR_FAILED;
             }
             strncpy(buffer[i], tmp8.c_str(), tmp8.bytes() + 1);
             i++;
diff --git a/libs/binder/tests/binderThroughputTest.cpp b/libs/binder/tests/binderThroughputTest.cpp
index d7f6318..10912c7 100644
--- a/libs/binder/tests/binderThroughputTest.cpp
+++ b/libs/binder/tests/binderThroughputTest.cpp
@@ -220,29 +220,34 @@
         workers.push_back(serviceMgr->waitForService(generateServiceName(i)));
     }
 
-    // Run the benchmark if client
+    p.signal();
+    p.wait();
+
     ProcResults results(iterations);
-
     chrono::time_point<chrono::high_resolution_clock> start, end;
-    for (int i = 0; (!cs_pair || num >= server_count) && i < iterations; i++) {
-        Parcel data, reply;
-        int target = cs_pair ? num % server_count : rand() % workers.size();
-        int sz = payload_size;
 
-        while (sz >= sizeof(uint32_t)) {
-            data.writeInt32(0);
-            sz -= sizeof(uint32_t);
-        }
-        start = chrono::high_resolution_clock::now();
-        status_t ret = workers[target]->transact(BINDER_NOP, data, &reply);
-        end = chrono::high_resolution_clock::now();
+    // Skip the benchmark if server of a cs_pair.
+    if (!(cs_pair && num < server_count)) {
+        for (int i = 0; i < iterations; i++) {
+            Parcel data, reply;
+            int target = cs_pair ? num % server_count : rand() % workers.size();
+            int sz = payload_size;
 
-        uint64_t cur_time = uint64_t(chrono::duration_cast<chrono::nanoseconds>(end - start).count());
-        results.add_time(cur_time);
+            while (sz >= sizeof(uint32_t)) {
+                data.writeInt32(0);
+                sz -= sizeof(uint32_t);
+            }
+            start = chrono::high_resolution_clock::now();
+            status_t ret = workers[target]->transact(BINDER_NOP, data, &reply);
+            end = chrono::high_resolution_clock::now();
 
-        if (ret != NO_ERROR) {
-           cout << "thread " << num << " failed " << ret << "i : " << i << endl;
-           exit(EXIT_FAILURE);
+            uint64_t cur_time = uint64_t(chrono::duration_cast<chrono::nanoseconds>(end - start).count());
+            results.add_time(cur_time);
+
+            if (ret != NO_ERROR) {
+               cout << "thread " << num << " failed " << ret << "i : " << i << endl;
+               exit(EXIT_FAILURE);
+            }
         }
     }
 
@@ -300,8 +305,15 @@
         pipes.push_back(make_worker(i, iterations, workers, payload_size, cs_pair));
     }
     wait_all(pipes);
+    // All workers have now been spawned and added themselves to service
+    // manager. Signal each worker to obtain a handle to the server workers from
+    // servicemanager.
+    signal_all(pipes);
+    // Wait for each worker to finish obtaining a handle to all server workers
+    // from servicemanager.
+    wait_all(pipes);
 
-    // Run the workers and wait for completion.
+    // Run the benchmark and wait for completion.
     chrono::time_point<chrono::high_resolution_clock> start, end;
     cout << "waiting for workers to complete" << endl;
     start = chrono::high_resolution_clock::now();
diff --git a/libs/binder/tests/format.h b/libs/binder/tests/format.h
index b5440a4..c588de7 100644
--- a/libs/binder/tests/format.h
+++ b/libs/binder/tests/format.h
@@ -18,7 +18,7 @@
 // ETA for this blocker is 2023-10-27~2023-11-10.
 // Also, remember to remove fmtlib's format.cc from trusty makefiles.
 
-#if __has_include(<format>)
+#if __has_include(<format>) && !defined(_LIBCPP_HAS_NO_INCOMPLETE_FORMAT)
 #include <format>
 #else
 #include <fmt/format.h>
diff --git a/libs/gui/WindowInfo.cpp b/libs/gui/WindowInfo.cpp
index ba1d196..95b2641 100644
--- a/libs/gui/WindowInfo.cpp
+++ b/libs/gui/WindowInfo.cpp
@@ -258,8 +258,7 @@
     mInfo = handle->mInfo;
 }
 
-std::ostream& operator<<(std::ostream& out, const WindowInfoHandle& window) {
-    const WindowInfo& info = *window.getInfo();
+std::ostream& operator<<(std::ostream& out, const WindowInfo& info) {
     std::string transform;
     info.transform.dump(transform, "transform", "    ");
     out << "name=" << info.name << ", id=" << info.id << ", displayId=" << info.displayId
@@ -277,4 +276,10 @@
     return out;
 }
 
+std::ostream& operator<<(std::ostream& out, const WindowInfoHandle& window) {
+    const WindowInfo& info = *window.getInfo();
+    out << info;
+    return out;
+}
+
 } // namespace android::gui
diff --git a/libs/gui/include/gui/WindowInfo.h b/libs/gui/include/gui/WindowInfo.h
index b72b71a..e72fd59 100644
--- a/libs/gui/include/gui/WindowInfo.h
+++ b/libs/gui/include/gui/WindowInfo.h
@@ -269,6 +269,8 @@
     status_t readFromParcel(const android::Parcel* parcel) override;
 };
 
+std::ostream& operator<<(std::ostream& out, const WindowInfo& window);
+
 /*
  * Handle for a window that can receive input.
  *
diff --git a/libs/input/Android.bp b/libs/input/Android.bp
index dd8dc8d..b74c3b2 100644
--- a/libs/input/Android.bp
+++ b/libs/input/Android.bp
@@ -220,7 +220,7 @@
         "libPlatformProperties",
         "libtinyxml2",
         "libutils",
-        "libvintf",
+        "libz", // needed by libkernelconfigs
         "server_configurable_flags",
     ],
 
@@ -239,6 +239,7 @@
         "libgui_window_info_static",
         "libui-types",
         "libtflite_static",
+        "libkernelconfigs",
     ],
 
     whole_static_libs: [
diff --git a/libs/input/KeyLayoutMap.cpp b/libs/input/KeyLayoutMap.cpp
index 3c1ae3e..ab8c341 100644
--- a/libs/input/KeyLayoutMap.cpp
+++ b/libs/input/KeyLayoutMap.cpp
@@ -27,8 +27,7 @@
 #include <utils/Timers.h>
 #include <utils/Tokenizer.h>
 #if defined(__ANDROID__)
-#include <vintf/RuntimeInfo.h>
-#include <vintf/VintfObject.h>
+#include <vintf/KernelConfigs.h>
 #endif
 
 #include <cstdlib>
@@ -98,12 +97,10 @@
 
 bool kernelConfigsArePresent(const std::set<std::string>& configs) {
 #if defined(__ANDROID__)
-    std::shared_ptr<const android::vintf::RuntimeInfo> runtimeInfo =
-            android::vintf::VintfObject::GetInstance()->getRuntimeInfo(
-                    vintf::RuntimeInfo::FetchFlag::CONFIG_GZ);
-    LOG_ALWAYS_FATAL_IF(runtimeInfo == nullptr, "Kernel configs could not be fetched");
+    std::map<std::string, std::string> kernelConfigs;
+    const status_t result = android::kernelconfigs::LoadKernelConfigs(&kernelConfigs);
+    LOG_ALWAYS_FATAL_IF(result != OK, "Kernel configs could not be fetched");
 
-    const std::map<std::string, std::string>& kernelConfigs = runtimeInfo->kernelConfigs();
     for (const std::string& requiredConfig : configs) {
         const auto configIt = kernelConfigs.find(requiredConfig);
         if (configIt == kernelConfigs.end()) {
diff --git a/libs/input/VirtualInputDevice.cpp b/libs/input/VirtualInputDevice.cpp
index db7031a..eea06f1 100644
--- a/libs/input/VirtualInputDevice.cpp
+++ b/libs/input/VirtualInputDevice.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2023 The Android Open Source Project
+ * 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.
@@ -39,7 +39,9 @@
 }
 
 namespace android {
+
 VirtualInputDevice::VirtualInputDevice(unique_fd fd) : mFd(std::move(fd)) {}
+
 VirtualInputDevice::~VirtualInputDevice() {
     ioctl(mFd, UI_DEV_DESTROY);
 }
@@ -56,7 +58,7 @@
     return TEMP_FAILURE_RETRY(write(mFd, &ev, sizeof(struct input_event))) == sizeof(ev);
 }
 
-/** Utility method to write keyboard key events or mouse button events. */
+/** Utility method to write keyboard key events or mouse/stylus button events. */
 bool VirtualInputDevice::writeEvKeyEvent(int32_t androidCode, int32_t androidAction,
                                          const std::map<int, int>& evKeyCodeMapping,
                                          const std::map<int, UinputAction>& actionMapping,
@@ -68,13 +70,17 @@
     }
     auto actionIterator = actionMapping.find(androidAction);
     if (actionIterator == actionMapping.end()) {
+        ALOGE("Unsupported native action for android action %d", androidAction);
         return false;
     }
-    if (!writeInputEvent(EV_KEY, static_cast<uint16_t>(evKeyCodeIterator->second),
-                         static_cast<int32_t>(actionIterator->second), eventTime)) {
+    int32_t action = static_cast<int32_t>(actionIterator->second);
+    uint16_t evKeyCode = static_cast<uint16_t>(evKeyCodeIterator->second);
+    if (!writeInputEvent(EV_KEY, evKeyCode, action, eventTime)) {
+        ALOGE("Failed to write native action %d and EV keycode %u.", action, evKeyCode);
         return false;
     }
     if (!writeInputEvent(EV_SYN, SYN_REPORT, 0, eventTime)) {
+        ALOGE("Failed to write SYN_REPORT for EV_KEY event.");
         return false;
     }
     return true;
@@ -85,6 +91,7 @@
         {AKEY_EVENT_ACTION_DOWN, UinputAction::PRESS},
         {AKEY_EVENT_ACTION_UP, UinputAction::RELEASE},
 };
+
 // Keycode mapping from https://source.android.com/devices/input/keyboard-devices
 const std::map<int, int> VirtualKeyboard::KEY_CODE_MAPPING = {
         {AKEYCODE_0, KEY_0},
@@ -195,7 +202,9 @@
         {AKEYCODE_NUMPAD_COMMA, KEY_KPCOMMA},
         {AKEYCODE_LANGUAGE_SWITCH, KEY_LANGUAGE},
 };
+
 VirtualKeyboard::VirtualKeyboard(unique_fd fd) : VirtualInputDevice(std::move(fd)) {}
+
 VirtualKeyboard::~VirtualKeyboard() {}
 
 bool VirtualKeyboard::writeKeyEvent(int32_t androidKeyCode, int32_t androidAction,
@@ -275,6 +284,7 @@
         {AMOTION_EVENT_ACTION_MOVE, UinputAction::MOVE},
         {AMOTION_EVENT_ACTION_CANCEL, UinputAction::CANCEL},
 };
+
 // Tool type mapping from https://source.android.com/devices/input/touch-devices
 const std::map<int, int> VirtualTouchscreen::TOOL_TYPE_MAPPING = {
         {AMOTION_EVENT_TOOL_TYPE_FINGER, MT_TOOL_FINGER},
@@ -393,4 +403,110 @@
     return true;
 }
 
+// --- VirtualStylus ---
+const std::map<int, int> VirtualStylus::TOOL_TYPE_MAPPING = {
+        {AMOTION_EVENT_TOOL_TYPE_STYLUS, BTN_TOOL_PEN},
+        {AMOTION_EVENT_TOOL_TYPE_ERASER, BTN_TOOL_RUBBER},
+};
+
+// Button code mapping from https://source.android.com/devices/input/touch-devices
+const std::map<int, int> VirtualStylus::BUTTON_CODE_MAPPING = {
+        {AMOTION_EVENT_BUTTON_STYLUS_PRIMARY, BTN_STYLUS},
+        {AMOTION_EVENT_BUTTON_STYLUS_SECONDARY, BTN_STYLUS2},
+};
+
+VirtualStylus::VirtualStylus(unique_fd fd)
+      : VirtualInputDevice(std::move(fd)), mIsStylusDown(false) {}
+
+VirtualStylus::~VirtualStylus() {}
+
+bool VirtualStylus::writeMotionEvent(int32_t toolType, int32_t action, int32_t locationX,
+                                     int32_t locationY, int32_t pressure, int32_t tiltX,
+                                     int32_t tiltY, std::chrono::nanoseconds eventTime) {
+    auto actionIterator = VirtualTouchscreen::TOUCH_ACTION_MAPPING.find(action);
+    if (actionIterator == VirtualTouchscreen::TOUCH_ACTION_MAPPING.end()) {
+        ALOGE("Unsupported action passed for stylus: %d.", action);
+        return false;
+    }
+    UinputAction uinputAction = actionIterator->second;
+    auto toolTypeIterator = TOOL_TYPE_MAPPING.find(toolType);
+    if (toolTypeIterator == TOOL_TYPE_MAPPING.end()) {
+        ALOGE("Unsupported tool type passed for stylus: %d.", toolType);
+        return false;
+    }
+    uint16_t tool = static_cast<uint16_t>(toolTypeIterator->second);
+    if (uinputAction == UinputAction::PRESS && !handleStylusDown(tool, eventTime)) {
+        return false;
+    }
+    if (!mIsStylusDown) {
+        ALOGE("Action UP or MOVE received with no prior action DOWN for stylus %d.", mFd.get());
+        return false;
+    }
+    if (uinputAction == UinputAction::RELEASE && !handleStylusUp(tool, eventTime)) {
+        return false;
+    }
+    if (!writeInputEvent(EV_ABS, ABS_X, locationX, eventTime)) {
+        ALOGE("Unsupported x-axis location passed for stylus: %d.", locationX);
+        return false;
+    }
+    if (!writeInputEvent(EV_ABS, ABS_Y, locationY, eventTime)) {
+        ALOGE("Unsupported y-axis location passed for stylus: %d.", locationY);
+        return false;
+    }
+    if (!writeInputEvent(EV_ABS, ABS_TILT_X, tiltX, eventTime)) {
+        ALOGE("Unsupported x-axis tilt passed for stylus: %d.", tiltX);
+        return false;
+    }
+    if (!writeInputEvent(EV_ABS, ABS_TILT_Y, tiltY, eventTime)) {
+        ALOGE("Unsupported y-axis tilt passed for stylus: %d.", tiltY);
+        return false;
+    }
+    if (!writeInputEvent(EV_ABS, ABS_PRESSURE, pressure, eventTime)) {
+        ALOGE("Unsupported pressure passed for stylus: %d.", pressure);
+        return false;
+    }
+    if (!writeInputEvent(EV_SYN, SYN_REPORT, 0, eventTime)) {
+        ALOGE("Failed to write SYN_REPORT for stylus motion event.");
+        return false;
+    }
+    return true;
+}
+
+bool VirtualStylus::writeButtonEvent(int32_t androidButtonCode, int32_t androidAction,
+                                     std::chrono::nanoseconds eventTime) {
+    return writeEvKeyEvent(androidButtonCode, androidAction, BUTTON_CODE_MAPPING,
+                           VirtualMouse::BUTTON_ACTION_MAPPING, eventTime);
+}
+
+bool VirtualStylus::handleStylusDown(uint16_t tool, std::chrono::nanoseconds eventTime) {
+    if (mIsStylusDown) {
+        ALOGE("Repetitive action DOWN event received for a stylus that is already down.");
+        return false;
+    }
+    if (!writeInputEvent(EV_KEY, tool, static_cast<int32_t>(UinputAction::PRESS), eventTime)) {
+        ALOGE("Failed to write EV_KEY for stylus tool type: %u.", tool);
+        return false;
+    }
+    if (!writeInputEvent(EV_KEY, BTN_TOUCH, static_cast<int32_t>(UinputAction::PRESS), eventTime)) {
+        ALOGE("Failed to write BTN_TOUCH for stylus press.");
+        return false;
+    }
+    mIsStylusDown = true;
+    return true;
+}
+
+bool VirtualStylus::handleStylusUp(uint16_t tool, std::chrono::nanoseconds eventTime) {
+    if (!writeInputEvent(EV_KEY, tool, static_cast<int32_t>(UinputAction::RELEASE), eventTime)) {
+        ALOGE("Failed to write EV_KEY for stylus tool type: %u.", tool);
+        return false;
+    }
+    if (!writeInputEvent(EV_KEY, BTN_TOUCH, static_cast<int32_t>(UinputAction::RELEASE),
+                         eventTime)) {
+        ALOGE("Failed to write BTN_TOUCH for stylus release.");
+        return false;
+    }
+    mIsStylusDown = false;
+    return true;
+}
+
 } // namespace android
diff --git a/libs/input/tests/Android.bp b/libs/input/tests/Android.bp
index 138898f..13cfb49 100644
--- a/libs/input/tests/Android.bp
+++ b/libs/input/tests/Android.bp
@@ -36,8 +36,10 @@
         "libgmock",
         "libgui_window_info_static",
         "libinput",
+        "libkernelconfigs",
         "libtflite_static",
         "libui-types",
+        "libz", // needed by libkernelconfigs
     ],
     cflags: [
         "-Wall",
@@ -61,7 +63,6 @@
         "libPlatformProperties",
         "libtinyxml2",
         "libutils",
-        "libvintf",
         "server_configurable_flags",
     ],
     data: [
diff --git a/libs/renderengine/skia/AutoBackendTexture.cpp b/libs/renderengine/skia/AutoBackendTexture.cpp
index 92fe4c0..ee95e59 100644
--- a/libs/renderengine/skia/AutoBackendTexture.cpp
+++ b/libs/renderengine/skia/AutoBackendTexture.cpp
@@ -77,7 +77,7 @@
                                                                  backendFormat,
                                                                  isOutputBuffer);
     } else {
-        LOG_ALWAYS_FATAL("Unexpected backend %d", backend);
+        LOG_ALWAYS_FATAL("Unexpected backend %u", static_cast<unsigned>(backend));
     }
 
     mColorType = GrAHardwareBufferUtils::GetSkColorTypeFromBufferFormat(desc.format);
@@ -145,8 +145,8 @@
                              "\n\tGrBackendTexture: (%i x %i) hasMipmaps: %i isProtected: %i "
                              "texType: %i\n\t\tVkImageInfo: success: %i fFormat: %i "
                              "fSampleCount: %u fLevelCount: %u colorType %i",
-                             msg, tex.isValid(), dataspace, tex.width(), tex.height(),
-                             tex.hasMipmaps(), tex.isProtected(),
+                             msg, tex.isValid(), static_cast<int32_t>(dataspace), tex.width(),
+                             tex.height(), tex.hasMipmaps(), tex.isProtected(),
                              static_cast<int>(tex.textureType()), retrievedImageInfo,
                              imageInfo.fFormat, imageInfo.fSampleCount, imageInfo.fLevelCount,
                              colorType);
diff --git a/libs/sensor/SensorManager.cpp b/libs/sensor/SensorManager.cpp
index f8ee3fc..b82a79f 100644
--- a/libs/sensor/SensorManager.cpp
+++ b/libs/sensor/SensorManager.cpp
@@ -88,49 +88,51 @@
     SensorManager* sensorManager;
     auto iterator = sPackageInstances.find(packageName);
 
+    const uid_t uid = IPCThreadState::self()->getCallingUid();
+    const int deviceId = getDeviceIdForUid(uid);
+
+    // Return the cached instance if the device association of the package has not changed.
     if (iterator != sPackageInstances.end()) {
         sensorManager = iterator->second;
-    } else {
-        String16 opPackageName = packageName;
-        const uid_t uid = IPCThreadState::self()->getCallingUid();
-
-        // It is possible that the calling code has no access to the package name.
-        // In this case we will get the packages for the calling UID and pick the
-        // first one for attributing the app op. This will work correctly for
-        // runtime permissions as for legacy apps we will toggle the app op for
-        // all packages in the UID. The caveat is that the operation may be attributed
-        // to the wrong package and stats based on app ops may be slightly off.
-        if (opPackageName.size() <= 0) {
-            sp<IBinder> binder = defaultServiceManager()->getService(String16("permission"));
-            if (binder != nullptr) {
-                Vector<String16> packages;
-                interface_cast<IPermissionController>(binder)->getPackagesForUid(uid, packages);
-                if (!packages.isEmpty()) {
-                    opPackageName = packages[0];
-                } else {
-                    ALOGE("No packages for calling UID");
-                }
-            } else {
-                ALOGE("Cannot get permission service");
-            }
+        if (sensorManager->mDeviceId == deviceId) {
+            return *sensorManager;
         }
-
-        // Check if the calling UID is observed on a virtual device. If so, provide that device's
-        // sensors by default instead of the default device's sensors.
-        const int deviceId = getDeviceIdForUid(uid);
-        sensorManager = new SensorManager(opPackageName, deviceId);
-
-        // If we had no package name, we looked it up from the UID and the sensor
-        // manager instance we created should also be mapped to the empty package
-        // name, to avoid looking up the packages for a UID and get the same result.
-        if (packageName.size() <= 0) {
-            sPackageInstances.insert(std::make_pair(String16(), sensorManager));
-        }
-
-        // Stash the per package sensor manager.
-        sPackageInstances.insert(std::make_pair(opPackageName, sensorManager));
     }
 
+    // It is possible that the calling code has no access to the package name.
+    // In this case we will get the packages for the calling UID and pick the
+    // first one for attributing the app op. This will work correctly for
+    // runtime permissions as for legacy apps we will toggle the app op for
+    // all packages in the UID. The caveat is that the operation may be attributed
+    // to the wrong package and stats based on app ops may be slightly off.
+    String16 opPackageName = packageName;
+    if (opPackageName.size() <= 0) {
+        sp<IBinder> binder = defaultServiceManager()->getService(String16("permission"));
+        if (binder != nullptr) {
+            Vector<String16> packages;
+            interface_cast<IPermissionController>(binder)->getPackagesForUid(uid, packages);
+            if (!packages.isEmpty()) {
+                opPackageName = packages[0];
+            } else {
+                ALOGE("No packages for calling UID");
+            }
+        } else {
+            ALOGE("Cannot get permission service");
+        }
+    }
+
+    sensorManager = new SensorManager(opPackageName, deviceId);
+
+    // If we had no package name, we looked it up from the UID and the sensor
+    // manager instance we created should also be mapped to the empty package
+    // name, to avoid looking up the packages for a UID and get the same result.
+    if (packageName.size() <= 0) {
+        sPackageInstances.insert(std::make_pair(String16(), sensorManager));
+    }
+
+    // Stash the per package sensor manager.
+    sPackageInstances.insert(std::make_pair(opPackageName, sensorManager));
+
     return *sensorManager;
 }
 
diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp
index 69f42bc..a7955cf 100644
--- a/services/inputflinger/Android.bp
+++ b/services/inputflinger/Android.bp
@@ -104,6 +104,8 @@
         "libprotobuf-cpp-lite",
         "libstatslog",
         "libutils",
+        "libstatspull",
+        "libstatssocket",
         "server_configurable_flags",
     ],
     static_libs: [
@@ -123,14 +125,6 @@
         android: {
             shared_libs: [
                 "libgui",
-                "libstatspull",
-                "libstatssocket",
-            ],
-        },
-        host: {
-            static_libs: [
-                "libstatspull",
-                "libstatssocket",
             ],
         },
     },
diff --git a/services/inputflinger/dispatcher/Android.bp b/services/inputflinger/dispatcher/Android.bp
index 8b57730..c7bacee 100644
--- a/services/inputflinger/dispatcher/Android.bp
+++ b/services/inputflinger/dispatcher/Android.bp
@@ -65,6 +65,8 @@
         "libprotobuf-cpp-lite",
         "libstatslog",
         "libutils",
+        "libstatspull",
+        "libstatssocket",
         "server_configurable_flags",
     ],
     static_libs: [
@@ -75,14 +77,6 @@
         android: {
             shared_libs: [
                 "libgui",
-                "libstatspull",
-                "libstatssocket",
-            ],
-        },
-        host: {
-            static_libs: [
-                "libstatspull",
-                "libstatssocket",
             ],
         },
     },
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 162a7bd..e998d91 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -763,6 +763,21 @@
     return state.hasActiveStylus();
 }
 
+Result<void> validateWindowInfosUpdate(const gui::WindowInfosUpdate& update) {
+    struct HashFunction {
+        size_t operator()(const WindowInfo& info) const { return info.id; }
+    };
+
+    std::unordered_set<WindowInfo, HashFunction> windowSet;
+    for (const WindowInfo& info : update.windowInfos) {
+        const auto [_, inserted] = windowSet.insert(info);
+        if (!inserted) {
+            return Error() << "Duplicate entry for " << info;
+        }
+    }
+    return {};
+}
+
 } // namespace
 
 // --- InputDispatcher ---
@@ -3841,8 +3856,7 @@
               connection->getInputChannelName().c_str(), seq, toString(handled));
     }
 
-    if (connection->status == Connection::Status::BROKEN ||
-        connection->status == Connection::Status::ZOMBIE) {
+    if (connection->status != Connection::Status::NORMAL) {
         return;
     }
 
@@ -4003,7 +4017,7 @@
 
 void InputDispatcher::synthesizeCancelationEventsForConnectionLocked(
         const std::shared_ptr<Connection>& connection, const CancelationOptions& options) {
-    if (connection->status == Connection::Status::BROKEN) {
+    if (connection->status != Connection::Status::NORMAL) {
         return;
     }
 
@@ -4115,7 +4129,7 @@
 void InputDispatcher::synthesizePointerDownEventsForConnectionLocked(
         const nsecs_t downTime, const std::shared_ptr<Connection>& connection,
         ftl::Flags<InputTarget::Flags> targetFlags) {
-    if (connection->status == Connection::Status::BROKEN) {
+    if (connection->status != Connection::Status::NORMAL) {
         return;
     }
 
@@ -6762,6 +6776,15 @@
 }
 
 void InputDispatcher::onWindowInfosChanged(const gui::WindowInfosUpdate& update) {
+    if (auto result = validateWindowInfosUpdate(update); !result.ok()) {
+        {
+            // acquire lock
+            std::scoped_lock _l(mLock);
+            logDispatchStateLocked();
+        }
+        LOG_ALWAYS_FATAL("Incorrect WindowInfosUpdate provided: %s",
+                         result.error().message().c_str());
+    };
     // The listener sends the windows as a flattened array. Separate the windows by display for
     // more convenient parsing.
     std::unordered_map<int32_t, std::vector<sp<WindowInfoHandle>>> handlesPerDisplay;
diff --git a/services/inputflinger/reader/Android.bp b/services/inputflinger/reader/Android.bp
index e1806a0..f954370 100644
--- a/services/inputflinger/reader/Android.bp
+++ b/services/inputflinger/reader/Android.bp
@@ -86,6 +86,7 @@
         "liblog",
         "libPlatformProperties",
         "libstatslog",
+        "libstatspull",
         "libutils",
     ],
     static_libs: [
@@ -99,15 +100,9 @@
         "libinputreader_headers",
     ],
     target: {
-        android: {
-            shared_libs: [
-                "libstatspull",
-            ],
-        },
         host: {
             static_libs: [
                 "libbinder",
-                "libstatspull",
             ],
         },
     },
diff --git a/services/inputflinger/reader/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp
index f7bbc51..3ca691e 100644
--- a/services/inputflinger/reader/EventHub.cpp
+++ b/services/inputflinger/reader/EventHub.cpp
@@ -810,14 +810,20 @@
         case EV_SYN: {
             switch (event.code) {
                 case SYN_REPORT:
-                    currentFrameDropped = false;
+                    if (currentFrameDropped) {
+                        // To recover after a SYN_DROPPED, we need to query the state of the device
+                        // to synchronize our device state with the kernel's to account for the
+                        // dropped events on receiving the next SYN_REPORT.
+                        // Note we don't drop the SYN_REPORT at this point but it is used by the
+                        // InputDevice to reset and repopulate mapper state
+                        readDeviceState();
+                        currentFrameDropped = false;
+                    }
                     break;
                 case SYN_DROPPED:
                     // When we receive SYN_DROPPED, all events in the current frame should be
-                    // dropped. We query the state of the device to synchronize our device state
-                    // with the kernel's to account for the dropped events.
+                    // dropped up to and including next SYN_REPORT
                     currentFrameDropped = true;
-                    readDeviceState();
                     break;
                 default:
                     break;
@@ -1141,6 +1147,22 @@
     return OK;
 }
 
+base::Result<std::vector<int32_t>> EventHub::getMtSlotValues(int32_t deviceId, int32_t axis,
+                                                             size_t slotCount) const {
+    std::scoped_lock _l(mLock);
+    const Device* device = getDeviceLocked(deviceId);
+    if (device == nullptr || !device->hasValidFd() || !device->absBitmask.test(axis)) {
+        return base::ResultError("device problem or axis not supported", NAME_NOT_FOUND);
+    }
+    std::vector<int32_t> outValues(slotCount + 1);
+    outValues[0] = axis;
+    const size_t bufferSize = outValues.size() * sizeof(int32_t);
+    if (ioctl(device->fd, EVIOCGMTSLOTS(bufferSize), outValues.data()) != OK) {
+        return base::ErrnoError();
+    }
+    return std::move(outValues);
+}
+
 bool EventHub::markSupportedKeyCodes(int32_t deviceId, const std::vector<int32_t>& keyCodes,
                                      uint8_t* outFlags) const {
     std::scoped_lock _l(mLock);
diff --git a/services/inputflinger/reader/InputDevice.cpp b/services/inputflinger/reader/InputDevice.cpp
index fb32f96..a41064b 100644
--- a/services/inputflinger/reader/InputDevice.cpp
+++ b/services/inputflinger/reader/InputDevice.cpp
@@ -350,6 +350,7 @@
 
         if (mDropUntilNextSync) {
             if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
+                out += reset(rawEvent->when);
                 mDropUntilNextSync = false;
                 ALOGD_IF(debugRawEvents(), "Recovered from input event buffer overrun.");
             } else {
@@ -359,7 +360,6 @@
         } else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_DROPPED) {
             ALOGI("Detected input event buffer overrun for device %s.", getName().c_str());
             mDropUntilNextSync = true;
-            out += reset(rawEvent->when);
         } else {
             for_each_mapper_in_subdevice(rawEvent->deviceId, [&](InputMapper& mapper) {
                 out += mapper.process(rawEvent);
diff --git a/services/inputflinger/reader/include/EventHub.h b/services/inputflinger/reader/include/EventHub.h
index 0bcab42..a7e0675 100644
--- a/services/inputflinger/reader/include/EventHub.h
+++ b/services/inputflinger/reader/include/EventHub.h
@@ -336,6 +336,10 @@
     virtual int32_t getSwitchState(int32_t deviceId, int32_t sw) const = 0;
     virtual status_t getAbsoluteAxisValue(int32_t deviceId, int32_t axis,
                                           int32_t* outValue) const = 0;
+    /* Query Multi-Touch slot values for an axis. Returns error or an 1 indexed array of size
+     * (slotCount + 1). The value at the 0 index is set to queried axis. */
+    virtual base::Result<std::vector<int32_t>> getMtSlotValues(int32_t deviceId, int32_t axis,
+                                                               size_t slotCount) const = 0;
     virtual int32_t getKeyCodeForKeyLocation(int32_t deviceId, int32_t locationKeyCode) const = 0;
 
     /*
@@ -552,6 +556,8 @@
                                      int32_t locationKeyCode) const override final;
     status_t getAbsoluteAxisValue(int32_t deviceId, int32_t axis,
                                   int32_t* outValue) const override final;
+    base::Result<std::vector<int32_t>> getMtSlotValues(int32_t deviceId, int32_t axis,
+                                                       size_t slotCount) const override final;
 
     bool markSupportedKeyCodes(int32_t deviceId, const std::vector<int32_t>& keyCodes,
                                uint8_t* outFlags) const override final;
diff --git a/services/inputflinger/reader/include/InputDevice.h b/services/inputflinger/reader/include/InputDevice.h
index cbd719c..ba7234b 100644
--- a/services/inputflinger/reader/include/InputDevice.h
+++ b/services/inputflinger/reader/include/InputDevice.h
@@ -372,6 +372,10 @@
     inline status_t getAbsoluteAxisValue(int32_t code, int32_t* outValue) const {
         return mEventHub->getAbsoluteAxisValue(mId, code, outValue);
     }
+    inline base::Result<std::vector<int32_t>> getMtSlotValues(int32_t axis,
+                                                              size_t slotCount) const {
+        return mEventHub->getMtSlotValues(mId, axis, slotCount);
+    }
     inline bool markSupportedKeyCodes(const std::vector<int32_t>& keyCodes,
                                       uint8_t* outFlags) const {
         return mEventHub->markSupportedKeyCodes(mId, keyCodes, outFlags);
diff --git a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
index f068cc8..9e7e956 100644
--- a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
@@ -61,6 +61,36 @@
             scanCode >= BTN_WHEEL;
 }
 
+static bool isMediaKey(int32_t keyCode) {
+    switch (keyCode) {
+        case AKEYCODE_MEDIA_PLAY:
+        case AKEYCODE_MEDIA_PAUSE:
+        case AKEYCODE_MEDIA_PLAY_PAUSE:
+        case AKEYCODE_MUTE:
+        case AKEYCODE_HEADSETHOOK:
+        case AKEYCODE_MEDIA_STOP:
+        case AKEYCODE_MEDIA_NEXT:
+        case AKEYCODE_MEDIA_PREVIOUS:
+        case AKEYCODE_MEDIA_REWIND:
+        case AKEYCODE_MEDIA_RECORD:
+        case AKEYCODE_MEDIA_FAST_FORWARD:
+        case AKEYCODE_MEDIA_SKIP_FORWARD:
+        case AKEYCODE_MEDIA_SKIP_BACKWARD:
+        case AKEYCODE_MEDIA_STEP_FORWARD:
+        case AKEYCODE_MEDIA_STEP_BACKWARD:
+        case AKEYCODE_MEDIA_AUDIO_TRACK:
+        case AKEYCODE_VOLUME_UP:
+        case AKEYCODE_VOLUME_DOWN:
+        case AKEYCODE_VOLUME_MUTE:
+        case AKEYCODE_TV_AUDIO_DESCRIPTION:
+        case AKEYCODE_TV_AUDIO_DESCRIPTION_MIX_UP:
+        case AKEYCODE_TV_AUDIO_DESCRIPTION_MIX_DOWN:
+            return true;
+        default:
+            return false;
+    }
+}
+
 // --- KeyboardInputMapper ---
 
 KeyboardInputMapper::KeyboardInputMapper(InputDeviceContext& deviceContext,
@@ -301,7 +331,8 @@
     // For internal keyboards and devices for which the default wake behavior is explicitly
     // prevented (e.g. TV remotes), the key layout file should specify the policy flags for each
     // wake key individually.
-    if (down && getDeviceContext().isExternal() && !mParameters.doNotWakeByDefault) {
+    if (down && getDeviceContext().isExternal() && !mParameters.doNotWakeByDefault &&
+        !(mKeyboardType != AINPUT_KEYBOARD_TYPE_ALPHABETIC && isMediaKey(keyCode))) {
         policyFlags |= POLICY_FLAG_WAKE;
     }
 
diff --git a/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp b/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp
index 2dd05f5..0c58dab 100644
--- a/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp
@@ -35,12 +35,8 @@
 MultiTouchInputMapper::~MultiTouchInputMapper() {}
 
 std::list<NotifyArgs> MultiTouchInputMapper::reset(nsecs_t when) {
-    // The evdev multi-touch protocol does not allow userspace applications to query the initial or
-    // current state of the pointers at any time. This means if we clear our accumulated state when
-    // resetting the input mapper, there's no way to rebuild the full initial state of the pointers.
-    // We can only wait for updates to all the pointers and axes. Rather than clearing the state and
-    // rebuilding the state from scratch, we work around this kernel API limitation by never
-    // fully clearing any state specific to the multi-touch protocol.
+    mPointerIdBits.clear();
+    mMultiTouchMotionAccumulator.reset(mDeviceContext);
     return TouchInputMapper::reset(when);
 }
 
diff --git a/services/inputflinger/reader/mapper/accumulator/MultiTouchMotionAccumulator.cpp b/services/inputflinger/reader/mapper/accumulator/MultiTouchMotionAccumulator.cpp
index b0fc903..b3f1700 100644
--- a/services/inputflinger/reader/mapper/accumulator/MultiTouchMotionAccumulator.cpp
+++ b/services/inputflinger/reader/mapper/accumulator/MultiTouchMotionAccumulator.cpp
@@ -30,24 +30,12 @@
                                             size_t slotCount, bool usingSlotsProtocol) {
     mUsingSlotsProtocol = usingSlotsProtocol;
     mSlots = std::vector<Slot>(slotCount);
+    populateCurrentSlot(deviceContext);
+}
 
-    mCurrentSlot = -1;
-    if (mUsingSlotsProtocol) {
-        // Query the driver for the current slot index and use it as the initial slot before we
-        // start reading events from the device.  It is possible that the current slot index will
-        // not be the same as it was when the first event was written into the evdev buffer, which
-        // means the input mapper could start out of sync with the initial state of the events in
-        // the evdev buffer. In the extremely unlikely case that this happens, the data from two
-        // slots will be confused until the next ABS_MT_SLOT event is received. This can cause the
-        // touch point to "jump", but at least there will be no stuck touches.
-        int32_t initialSlot;
-        if (const auto status = deviceContext.getAbsoluteAxisValue(ABS_MT_SLOT, &initialSlot);
-            status == OK) {
-            mCurrentSlot = initialSlot;
-        } else {
-            ALOGD("Could not retrieve current multi-touch slot index. status=%d", status);
-        }
-    }
+void MultiTouchMotionAccumulator::reset(const InputDeviceContext& deviceContext) {
+    resetSlots();
+    syncSlots(deviceContext);
 }
 
 void MultiTouchMotionAccumulator::resetSlots() {
@@ -84,54 +72,10 @@
             if (!mUsingSlotsProtocol) {
                 slot.mInUse = true;
             }
-
-            switch (rawEvent->code) {
-                case ABS_MT_POSITION_X:
-                    slot.mAbsMtPositionX = rawEvent->value;
-                    warnIfNotInUse(*rawEvent, slot);
-                    break;
-                case ABS_MT_POSITION_Y:
-                    slot.mAbsMtPositionY = rawEvent->value;
-                    warnIfNotInUse(*rawEvent, slot);
-                    break;
-                case ABS_MT_TOUCH_MAJOR:
-                    slot.mAbsMtTouchMajor = rawEvent->value;
-                    break;
-                case ABS_MT_TOUCH_MINOR:
-                    slot.mAbsMtTouchMinor = rawEvent->value;
-                    slot.mHaveAbsMtTouchMinor = true;
-                    break;
-                case ABS_MT_WIDTH_MAJOR:
-                    slot.mAbsMtWidthMajor = rawEvent->value;
-                    break;
-                case ABS_MT_WIDTH_MINOR:
-                    slot.mAbsMtWidthMinor = rawEvent->value;
-                    slot.mHaveAbsMtWidthMinor = true;
-                    break;
-                case ABS_MT_ORIENTATION:
-                    slot.mAbsMtOrientation = rawEvent->value;
-                    break;
-                case ABS_MT_TRACKING_ID:
-                    if (mUsingSlotsProtocol && rawEvent->value < 0) {
-                        // The slot is no longer in use but it retains its previous contents,
-                        // which may be reused for subsequent touches.
-                        slot.mInUse = false;
-                    } else {
-                        slot.mInUse = true;
-                        slot.mAbsMtTrackingId = rawEvent->value;
-                    }
-                    break;
-                case ABS_MT_PRESSURE:
-                    slot.mAbsMtPressure = rawEvent->value;
-                    break;
-                case ABS_MT_DISTANCE:
-                    slot.mAbsMtDistance = rawEvent->value;
-                    break;
-                case ABS_MT_TOOL_TYPE:
-                    slot.mAbsMtToolType = rawEvent->value;
-                    slot.mHaveAbsMtToolType = true;
-                    break;
+            if (rawEvent->code == ABS_MT_POSITION_X || rawEvent->code == ABS_MT_POSITION_Y) {
+                warnIfNotInUse(*rawEvent, slot);
             }
+            slot.populateAxisValue(rawEvent->code, rawEvent->value);
         }
     } else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_MT_REPORT) {
         // MultiTouch Sync: The driver has returned all data for *one* of the pointers.
@@ -139,6 +83,36 @@
     }
 }
 
+void MultiTouchMotionAccumulator::syncSlots(const InputDeviceContext& deviceContext) {
+    if (!mUsingSlotsProtocol) {
+        return;
+    }
+    constexpr std::array<int32_t, 11> axisCodes = {ABS_MT_POSITION_X,  ABS_MT_POSITION_Y,
+                                                   ABS_MT_TOUCH_MAJOR, ABS_MT_TOUCH_MINOR,
+                                                   ABS_MT_WIDTH_MAJOR, ABS_MT_WIDTH_MINOR,
+                                                   ABS_MT_ORIENTATION, ABS_MT_TRACKING_ID,
+                                                   ABS_MT_PRESSURE,    ABS_MT_DISTANCE,
+                                                   ABS_MT_TOOL_TYPE};
+    const size_t numSlots = mSlots.size();
+    for (int32_t axisCode : axisCodes) {
+        if (!deviceContext.hasAbsoluteAxis(axisCode)) {
+            continue;
+        }
+        const auto result = deviceContext.getMtSlotValues(axisCode, numSlots);
+        if (result.ok()) {
+            const std::vector<int32_t>& mtSlotValues = result.value();
+            for (size_t i = 1; i <= numSlots; ++i) {
+                // The returned slot values are in a 1-indexed vector of size numSlots + 1.
+                mSlots[i - 1].populateAxisValue(axisCode, mtSlotValues[i]);
+            }
+        } else {
+            ALOGE("Could not retrieve multi-touch slot value for axis=%d error=%s status=%d",
+                  axisCode, result.error().message().c_str(), result.error().code().value());
+        }
+    }
+    populateCurrentSlot(deviceContext);
+}
+
 void MultiTouchMotionAccumulator::finishSync() {
     if (!mUsingSlotsProtocol) {
         resetSlots();
@@ -160,6 +134,21 @@
                          [](const Slot& slot) { return slot.mInUse; });
 }
 
+void MultiTouchMotionAccumulator::populateCurrentSlot(
+        const android::InputDeviceContext& deviceContext) {
+    if (!mUsingSlotsProtocol) {
+        return;
+    }
+    int32_t initialSlot;
+    if (const auto status = deviceContext.getAbsoluteAxisValue(ABS_MT_SLOT, &initialSlot);
+        status == OK) {
+        mCurrentSlot = initialSlot;
+    } else {
+        ALOGE("Could not retrieve current multi-touch slot index. status=%s",
+              statusToString(status).c_str());
+    }
+}
+
 // --- MultiTouchMotionAccumulator::Slot ---
 
 ToolType MultiTouchMotionAccumulator::Slot::getToolType() const {
@@ -176,4 +165,52 @@
     return ToolType::UNKNOWN;
 }
 
+void MultiTouchMotionAccumulator::Slot::populateAxisValue(int32_t axisCode, int32_t value) {
+    switch (axisCode) {
+        case ABS_MT_POSITION_X:
+            mAbsMtPositionX = value;
+            break;
+        case ABS_MT_POSITION_Y:
+            mAbsMtPositionY = value;
+            break;
+        case ABS_MT_TOUCH_MAJOR:
+            mAbsMtTouchMajor = value;
+            break;
+        case ABS_MT_TOUCH_MINOR:
+            mAbsMtTouchMinor = value;
+            mHaveAbsMtTouchMinor = true;
+            break;
+        case ABS_MT_WIDTH_MAJOR:
+            mAbsMtWidthMajor = value;
+            break;
+        case ABS_MT_WIDTH_MINOR:
+            mAbsMtWidthMinor = value;
+            mHaveAbsMtWidthMinor = true;
+            break;
+        case ABS_MT_ORIENTATION:
+            mAbsMtOrientation = value;
+            break;
+        case ABS_MT_TRACKING_ID:
+            if (value < 0) {
+                // The slot is no longer in use but it retains its previous contents,
+                // which may be reused for subsequent touches.
+                mInUse = false;
+            } else {
+                mInUse = true;
+                mAbsMtTrackingId = value;
+            }
+            break;
+        case ABS_MT_PRESSURE:
+            mAbsMtPressure = value;
+            break;
+        case ABS_MT_DISTANCE:
+            mAbsMtDistance = value;
+            break;
+        case ABS_MT_TOOL_TYPE:
+            mAbsMtToolType = value;
+            mHaveAbsMtToolType = true;
+            break;
+    }
+}
+
 } // namespace android
diff --git a/services/inputflinger/reader/mapper/accumulator/MultiTouchMotionAccumulator.h b/services/inputflinger/reader/mapper/accumulator/MultiTouchMotionAccumulator.h
index 0e3e2bb..a0f2147 100644
--- a/services/inputflinger/reader/mapper/accumulator/MultiTouchMotionAccumulator.h
+++ b/services/inputflinger/reader/mapper/accumulator/MultiTouchMotionAccumulator.h
@@ -68,12 +68,14 @@
         int32_t mAbsMtToolType = 0;
 
         void clear() { *this = Slot(); }
+        void populateAxisValue(int32_t axisCode, int32_t value);
     };
 
     MultiTouchMotionAccumulator();
 
     void configure(const InputDeviceContext& deviceContext, size_t slotCount,
                    bool usingSlotsProtocol);
+    void reset(const InputDeviceContext& deviceContext);
     void process(const RawEvent* rawEvent);
     void finishSync();
 
@@ -85,12 +87,14 @@
     }
 
 private:
-    int32_t mCurrentSlot;
+    int32_t mCurrentSlot{-1};
     std::vector<Slot> mSlots;
     bool mUsingSlotsProtocol;
 
     void resetSlots();
+    void syncSlots(const InputDeviceContext& deviceContext);
     void warnIfNotInUse(const RawEvent& event, const Slot& slot);
+    void populateCurrentSlot(const android::InputDeviceContext& deviceContext);
 };
 
 } // namespace android
diff --git a/services/inputflinger/tests/Android.bp b/services/inputflinger/tests/Android.bp
index db31ded..55aa226 100644
--- a/services/inputflinger/tests/Android.bp
+++ b/services/inputflinger/tests/Android.bp
@@ -68,6 +68,7 @@
         "TimerProvider_test.cpp",
         "TestInputListener.cpp",
         "TouchpadInputMapper_test.cpp",
+        "MultiTouchInputMapper_test.cpp",
         "KeyboardInputMapper_test.cpp",
         "UinputDevice.cpp",
         "UnwantedInteractionBlocker_test.cpp",
diff --git a/services/inputflinger/tests/FakeEventHub.cpp b/services/inputflinger/tests/FakeEventHub.cpp
index 212fceb..daa000f 100644
--- a/services/inputflinger/tests/FakeEventHub.cpp
+++ b/services/inputflinger/tests/FakeEventHub.cpp
@@ -431,6 +431,38 @@
     return -1;
 }
 
+void FakeEventHub::setMtSlotValues(int32_t deviceId, int32_t axis,
+                                   const std::vector<int32_t>& values) {
+    Device* device = getDevice(deviceId);
+    if (!device) {
+        FAIL() << "Missing device";
+    }
+    device->mtSlotValues[axis] = values;
+}
+
+base::Result<std::vector<int32_t>> FakeEventHub::getMtSlotValues(int32_t deviceId, int32_t axis,
+                                                                 size_t slotCount) const {
+    Device* device = getDevice(deviceId);
+    if (!device) {
+        ADD_FAILURE() << "Missing device";
+        return base::ResultError("Missing device", UNKNOWN_ERROR);
+    }
+    const auto& mtSlotValuesIterator = device->mtSlotValues.find(axis);
+    if (mtSlotValuesIterator == device->mtSlotValues.end()) {
+        return base::ResultError("axis not supported", NAME_NOT_FOUND);
+    }
+    const auto& mtSlotValues = mtSlotValuesIterator->second;
+    if (mtSlotValues.size() != slotCount) {
+        ADD_FAILURE() << "MtSlot values specified for " << mtSlotValues.size()
+                      << " slots but expected for " << slotCount << " Slots";
+        return base::ResultError("Slot count mismatch", NAME_NOT_FOUND);
+    }
+    std::vector<int32_t> outValues(slotCount + 1);
+    outValues[0] = axis;
+    std::copy(mtSlotValues.begin(), mtSlotValues.end(), outValues.begin() + 1);
+    return std::move(outValues);
+}
+
 int32_t FakeEventHub::getKeyCodeForKeyLocation(int32_t deviceId, int32_t locationKeyCode) const {
     Device* device = getDevice(deviceId);
     if (!device) {
diff --git a/services/inputflinger/tests/FakeEventHub.h b/services/inputflinger/tests/FakeEventHub.h
index 8e06940..f07b344 100644
--- a/services/inputflinger/tests/FakeEventHub.h
+++ b/services/inputflinger/tests/FakeEventHub.h
@@ -65,6 +65,7 @@
         bool enabled;
         std::optional<RawLayoutInfo> layoutInfo;
         std::string sysfsRootPath;
+        std::unordered_map<int32_t, std::vector<int32_t>> mtSlotValues;
 
         status_t enable() {
             enabled = true;
@@ -154,6 +155,11 @@
                       int32_t value);
     void assertQueueIsEmpty();
     void setSysfsRootPath(int32_t deviceId, std::string sysfsRootPath) const;
+    // Populate fake slot values to be returned by the getter, size of the values should be equal to
+    // the slot count
+    void setMtSlotValues(int32_t deviceId, int32_t axis, const std::vector<int32_t>& values);
+    base::Result<std::vector<int32_t>> getMtSlotValues(int32_t deviceId, int32_t axis,
+                                                       size_t slotCount) const override;
 
 private:
     Device* getDevice(int32_t deviceId) const;
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 8be1b3b..48d7e55 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -1680,6 +1680,24 @@
     window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
 }
 
+using InputDispatcherDeathTest = InputDispatcherTest;
+
+/**
+ * When 'onWindowInfosChanged' arguments contain a duplicate entry for the same window, dispatcher
+ * should crash.
+ */
+TEST_F(InputDispatcherDeathTest, DuplicateWindowInfosAbortDispatcher) {
+    testing::GTEST_FLAG(death_test_style) = "threadsafe";
+    ScopedSilentDeath _silentDeath;
+
+    std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
+    sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
+                                                             "Fake Window", ADISPLAY_ID_DEFAULT);
+    ASSERT_DEATH(mDispatcher->onWindowInfosChanged(
+                         {{*window->getInfo(), *window->getInfo()}, {}, 0, 0}),
+                 "Incorrect WindowInfosUpdate provided");
+}
+
 TEST_F(InputDispatcherTest, WhenDisplayNotSpecified_InjectMotionToDefaultDisplay) {
     std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
     sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
@@ -6974,6 +6992,39 @@
     mWindow->assertNoEvents();
 }
 
+TEST_F(InputDispatcherFallbackKeyTest, WindowRemovedDuringPolicyCall) {
+    setFallback(AKEYCODE_B);
+    mDispatcher->notifyKey(
+            KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
+
+    // Do not handle this key event.
+    consumeKey(/*handled=*/false,
+               AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
+    ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
+    consumeKey(/*handled=*/true,
+               AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
+                     WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
+
+    mFakePolicy->setUnhandledKeyHandler([&](const KeyEvent& event) {
+        // When the unhandled key is reported to the policy next, remove the input channel.
+        mDispatcher->removeInputChannel(mWindow->getToken());
+        return KeyEventBuilder(event).keyCode(AKEYCODE_B).build();
+    });
+    // Release the original key, and let the app now handle the previously unhandled key.
+    // This should result in the previously generated fallback key to be cancelled.
+    // Since the policy was notified of the unhandled DOWN event earlier, it will also be notified
+    // of the UP event for consistency. The Dispatcher calls into the policy from its own thread
+    // without holding the lock, because it need to synchronously fetch the fallback key. While in
+    // the policy call, we will now remove the input channel. Once the policy call returns, the
+    // Dispatcher will no longer have a channel to send cancellation events to. Ensure this does
+    // not cause any crashes.
+    mDispatcher->notifyKey(
+            KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
+    consumeKey(/*handled=*/true,
+               AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A), WithFlags(0)));
+    ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
+}
+
 class InputDispatcherKeyRepeatTest : public InputDispatcherTest {
 protected:
     static constexpr std::chrono::nanoseconds KEY_REPEAT_TIMEOUT = 40ms;
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 86e57bc..460a7b1 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -2919,13 +2919,11 @@
     mapper.assertProcessWasCalled();
 
     // Simulate a kernel buffer overflow, which generates a SYN_DROPPED event.
-    // This should reset the mapper.
     event.type = EV_SYN;
     event.code = SYN_DROPPED;
     event.value = 0;
     unused = mDevice->process(&event, /*count=*/1);
     mapper.assertProcessWasNotCalled();
-    mapper.assertResetWasCalled();
 
     // All events until the next SYN_REPORT should be dropped.
     event.type = EV_KEY;
@@ -2935,11 +2933,13 @@
     mapper.assertProcessWasNotCalled();
 
     // We get the SYN_REPORT event now, which is not forwarded to mappers.
+    // This should reset the mapper.
     event.type = EV_SYN;
     event.code = SYN_REPORT;
     event.value = 0;
     unused = mDevice->process(&event, /*count=*/1);
     mapper.assertProcessWasNotCalled();
+    mapper.assertResetWasCalled();
 
     // The mapper receives events normally now.
     event.type = EV_KEY;
@@ -4100,7 +4100,7 @@
     void SetUp() override { InputMapperTest::SetUp(DEVICE_CLASSES | InputDeviceClass::EXTERNAL); }
 };
 
-TEST_F(KeyboardInputMapperTest_ExternalDevice, WakeBehavior) {
+TEST_F(KeyboardInputMapperTest_ExternalDevice, WakeBehavior_AlphabeticKeyboard) {
     // For external devices, keys will trigger wake on key down. Media keys should also trigger
     // wake if triggered from external devices.
 
@@ -4139,6 +4139,36 @@
     ASSERT_EQ(POLICY_FLAG_WAKE, args.policyFlags);
 }
 
+TEST_F(KeyboardInputMapperTest_ExternalDevice, WakeBehavior_NoneAlphabeticKeyboard) {
+    // For external devices, keys will trigger wake on key down. Media keys should not trigger
+    // wake if triggered from external non-alphaebtic keyboard (e.g. headsets).
+
+    mFakeEventHub->addKey(EVENTHUB_ID, KEY_PLAY, 0, AKEYCODE_MEDIA_PLAY, 0);
+    mFakeEventHub->addKey(EVENTHUB_ID, KEY_PLAYPAUSE, 0, AKEYCODE_MEDIA_PLAY_PAUSE,
+                          POLICY_FLAG_WAKE);
+
+    KeyboardInputMapper& mapper =
+            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD,
+                                                       AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC);
+
+    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_PLAY, 1);
+    NotifyKeyArgs args;
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
+    ASSERT_EQ(uint32_t(0), args.policyFlags);
+
+    process(mapper, ARBITRARY_TIME + 1, READ_TIME, EV_KEY, KEY_PLAY, 0);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
+    ASSERT_EQ(uint32_t(0), args.policyFlags);
+
+    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_PLAYPAUSE, 1);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
+    ASSERT_EQ(POLICY_FLAG_WAKE, args.policyFlags);
+
+    process(mapper, ARBITRARY_TIME + 1, READ_TIME, EV_KEY, KEY_PLAYPAUSE, 0);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
+    ASSERT_EQ(POLICY_FLAG_WAKE, args.policyFlags);
+}
+
 TEST_F(KeyboardInputMapperTest_ExternalDevice, DoNotWakeByDefaultBehavior) {
     // Tv Remote key's wake behavior is prescribed by the keylayout file.
 
@@ -9498,15 +9528,16 @@
     ASSERT_EQ(uint32_t(1), motionArgs.getPointerCount());
 }
 
-TEST_F(MultiTouchInputMapperTest, Reset_PreservesLastTouchState) {
+TEST_F(MultiTouchInputMapperTest, Reset_RepopulatesMultiTouchState) {
     addConfigurationProperty("touch.deviceType", "touchScreen");
     prepareDisplay(ui::ROTATION_0);
     prepareAxes(POSITION | ID | SLOT | PRESSURE);
     MultiTouchInputMapper& mapper = constructAndAddMapper<MultiTouchInputMapper>();
 
     // First finger down.
+    constexpr int32_t x1 = 100, y1 = 200, x2 = 300, y2 = 400;
     processId(mapper, FIRST_TRACKING_ID);
-    processPosition(mapper, 100, 200);
+    processPosition(mapper, x1, y1);
     processPressure(mapper, RAW_PRESSURE_MAX);
     processSync(mapper);
     ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(
@@ -9515,14 +9546,32 @@
     // Second finger down.
     processSlot(mapper, SECOND_SLOT);
     processId(mapper, SECOND_TRACKING_ID);
-    processPosition(mapper, 300, 400);
+    processPosition(mapper, x2, y2);
     processPressure(mapper, RAW_PRESSURE_MAX);
     processSync(mapper);
     ASSERT_NO_FATAL_FAILURE(
             mFakeListener->assertNotifyMotionWasCalled(WithMotionAction(ACTION_POINTER_1_DOWN)));
 
+    // Set MT Slot state to be repopulated for the required slots
+    std::vector<int32_t> mtSlotValues(RAW_SLOT_MAX + 1, -1);
+    mtSlotValues[0] = FIRST_TRACKING_ID;
+    mtSlotValues[1] = SECOND_TRACKING_ID;
+    mFakeEventHub->setMtSlotValues(EVENTHUB_ID, ABS_MT_TRACKING_ID, mtSlotValues);
+
+    mtSlotValues[0] = x1;
+    mtSlotValues[1] = x2;
+    mFakeEventHub->setMtSlotValues(EVENTHUB_ID, ABS_MT_POSITION_X, mtSlotValues);
+
+    mtSlotValues[0] = y1;
+    mtSlotValues[1] = y2;
+    mFakeEventHub->setMtSlotValues(EVENTHUB_ID, ABS_MT_POSITION_Y, mtSlotValues);
+
+    mtSlotValues[0] = RAW_PRESSURE_MAX;
+    mtSlotValues[1] = RAW_PRESSURE_MAX;
+    mFakeEventHub->setMtSlotValues(EVENTHUB_ID, ABS_MT_PRESSURE, mtSlotValues);
+
     // Reset the mapper. When the mapper is reset, we expect the current multi-touch state to be
-    // preserved. Resetting should cancel the ongoing gesture.
+    // repopulated. Resetting should cancel the ongoing gesture.
     resetMapper(mapper, ARBITRARY_TIME);
     ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(
             WithMotionAction(AMOTION_EVENT_ACTION_CANCEL)));
diff --git a/services/inputflinger/tests/InterfaceMocks.h b/services/inputflinger/tests/InterfaceMocks.h
index 9de80af..db89168 100644
--- a/services/inputflinger/tests/InterfaceMocks.h
+++ b/services/inputflinger/tests/InterfaceMocks.h
@@ -132,6 +132,9 @@
 
     MOCK_METHOD(status_t, getAbsoluteAxisValue, (int32_t deviceId, int32_t axis, int32_t* outValue),
                 (const, override));
+    MOCK_METHOD(base::Result<std::vector<int32_t>>, getMtSlotValues,
+                (int32_t deviceId, int32_t axis, size_t slotCount), (const, override));
+
     MOCK_METHOD(int32_t, getKeyCodeForKeyLocation, (int32_t deviceId, int32_t locationKeyCode),
                 (const, override));
     MOCK_METHOD(bool, markSupportedKeyCodes,
diff --git a/services/inputflinger/tests/MultiTouchInputMapper_test.cpp b/services/inputflinger/tests/MultiTouchInputMapper_test.cpp
new file mode 100644
index 0000000..d726385
--- /dev/null
+++ b/services/inputflinger/tests/MultiTouchInputMapper_test.cpp
@@ -0,0 +1,276 @@
+/*
+ * 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.
+ */
+
+#include "MultiTouchInputMapper.h"
+
+#include <android-base/logging.h>
+#include <gtest/gtest.h>
+#include <list>
+#include <optional>
+
+#include "InputMapperTest.h"
+#include "InterfaceMocks.h"
+#include "TestEventMatchers.h"
+
+#define TAG "MultiTouchpadInputMapperUnit_test"
+
+namespace android {
+
+using testing::_;
+using testing::IsEmpty;
+using testing::Return;
+using testing::SetArgPointee;
+using testing::VariantWith;
+
+static constexpr int32_t DISPLAY_ID = 0;
+static constexpr int32_t DISPLAY_WIDTH = 480;
+static constexpr int32_t DISPLAY_HEIGHT = 800;
+static constexpr std::optional<uint8_t> NO_PORT = std::nullopt; // no physical port is specified
+static constexpr int32_t SLOT_COUNT = 5;
+
+static constexpr int32_t ACTION_POINTER_0_UP =
+        AMOTION_EVENT_ACTION_POINTER_UP | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
+static constexpr int32_t ACTION_POINTER_1_DOWN =
+        AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
+
+/**
+ * Unit tests for MultiTouchInputMapper.
+ */
+class MultiTouchInputMapperUnitTest : public InputMapperUnitTest {
+protected:
+    void SetUp() override {
+        InputMapperUnitTest::SetUp();
+
+        // Present scan codes
+        expectScanCodes(/*present=*/true,
+                        {BTN_TOUCH, BTN_TOOL_FINGER, BTN_TOOL_DOUBLETAP, BTN_TOOL_TRIPLETAP,
+                         BTN_TOOL_QUADTAP, BTN_TOOL_QUINTTAP});
+
+        // Missing scan codes that the mapper checks for.
+        expectScanCodes(/*present=*/false,
+                        {BTN_TOOL_PEN, BTN_TOOL_RUBBER, BTN_TOOL_BRUSH, BTN_TOOL_PENCIL,
+                         BTN_TOOL_AIRBRUSH});
+
+        // Current scan code state - all keys are UP by default
+        setScanCodeState(KeyState::UP, {BTN_LEFT,           BTN_RIGHT,        BTN_MIDDLE,
+                                        BTN_BACK,           BTN_SIDE,         BTN_FORWARD,
+                                        BTN_EXTRA,          BTN_TASK,         BTN_TOUCH,
+                                        BTN_STYLUS,         BTN_STYLUS2,      BTN_0,
+                                        BTN_TOOL_FINGER,    BTN_TOOL_PEN,     BTN_TOOL_RUBBER,
+                                        BTN_TOOL_BRUSH,     BTN_TOOL_PENCIL,  BTN_TOOL_AIRBRUSH,
+                                        BTN_TOOL_MOUSE,     BTN_TOOL_LENS,    BTN_TOOL_DOUBLETAP,
+                                        BTN_TOOL_TRIPLETAP, BTN_TOOL_QUADTAP, BTN_TOOL_QUINTTAP});
+
+        setKeyCodeState(KeyState::UP,
+                        {AKEYCODE_STYLUS_BUTTON_PRIMARY, AKEYCODE_STYLUS_BUTTON_SECONDARY});
+
+        // Input properties - only INPUT_PROP_DIRECT for touchscreen
+        EXPECT_CALL(mMockEventHub, hasInputProperty(EVENTHUB_ID, _)).WillRepeatedly(Return(false));
+        EXPECT_CALL(mMockEventHub, hasInputProperty(EVENTHUB_ID, INPUT_PROP_DIRECT))
+                .WillRepeatedly(Return(true));
+
+        // Axes that the device has
+        setupAxis(ABS_MT_SLOT, /*valid=*/true, /*min=*/0, /*max=*/SLOT_COUNT - 1, /*resolution=*/0);
+        setupAxis(ABS_MT_TRACKING_ID, /*valid=*/true, /*min*/ 0, /*max=*/255, /*resolution=*/0);
+        setupAxis(ABS_MT_POSITION_X, /*valid=*/true, /*min=*/0, /*max=*/2000, /*resolution=*/24);
+        setupAxis(ABS_MT_POSITION_Y, /*valid=*/true, /*min=*/0, /*max=*/1000, /*resolution=*/24);
+
+        // Axes that the device does not have
+        setupAxis(ABS_MT_PRESSURE, /*valid=*/false, /*min*/ 0, /*max=*/255, /*resolution=*/0);
+        setupAxis(ABS_MT_ORIENTATION, /*valid=*/false, /*min=*/0, /*max=*/0, /*resolution=*/0);
+        setupAxis(ABS_MT_DISTANCE, /*valid=*/false, /*min=*/0, /*max=*/0, /*resolution=*/0);
+        setupAxis(ABS_MT_TOUCH_MAJOR, /*valid=*/false, /*min=*/0, /*max=*/0, /*resolution=*/0);
+        setupAxis(ABS_MT_TOUCH_MINOR, /*valid=*/false, /*min=*/0, /*max=*/0, /*resolution=*/0);
+        setupAxis(ABS_MT_WIDTH_MAJOR, /*valid=*/false, /*min=*/0, /*max=*/0, /*resolution=*/0);
+        setupAxis(ABS_MT_WIDTH_MINOR, /*valid=*/false, /*min=*/0, /*max=*/0, /*resolution=*/0);
+        setupAxis(ABS_MT_TOOL_TYPE, /*valid=*/false, /*min=*/0, /*max=*/0, /*resolution=*/0);
+
+        // reset current slot at the beginning
+        EXPECT_CALL(mMockEventHub, getAbsoluteAxisValue(EVENTHUB_ID, ABS_MT_SLOT, _))
+                .WillRepeatedly([](int32_t, int32_t, int32_t* outValue) {
+                    *outValue = 0;
+                    return OK;
+                });
+
+        // mark all slots not in use
+        mockSlotValues({});
+
+        mFakePolicy->setDefaultPointerDisplayId(DISPLAY_ID);
+        mFakePolicy->addDisplayViewport(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, ui::ROTATION_0,
+                                        /*isActive=*/true, "local:0", NO_PORT,
+                                        ViewportType::INTERNAL);
+        createDevice();
+        mMapper = createInputMapper<MultiTouchInputMapper>(*mDeviceContext,
+                                                           mFakePolicy->getReaderConfiguration());
+    }
+
+    // Mocks position and tracking Ids for the provided slots. Remaining slots will be marked
+    // unused.
+    void mockSlotValues(
+            const std::unordered_map<int32_t /*slotIndex*/,
+                                     std::pair<Point /*position*/, int32_t /*trackingId*/>>&
+                    slotValues) {
+        EXPECT_CALL(mMockEventHub, getMtSlotValues(EVENTHUB_ID, _, SLOT_COUNT))
+                .WillRepeatedly([=](int32_t, int32_t axis,
+                                    size_t slotCount) -> base::Result<std::vector<int32_t>> {
+                    // tracking Id for the unused slots must set to be < 0
+                    std::vector<int32_t> outMtSlotValues(slotCount + 1, -1);
+                    outMtSlotValues[0] = axis;
+                    switch (axis) {
+                        case ABS_MT_POSITION_X:
+                            for (const auto& [slotIndex, valuePair] : slotValues) {
+                                outMtSlotValues[slotIndex] = valuePair.first.x;
+                            }
+                            return outMtSlotValues;
+                        case ABS_MT_POSITION_Y:
+                            for (const auto& [slotIndex, valuePair] : slotValues) {
+                                outMtSlotValues[slotIndex] = valuePair.first.y;
+                            }
+                            return outMtSlotValues;
+                        case ABS_MT_TRACKING_ID:
+                            for (const auto& [slotIndex, valuePair] : slotValues) {
+                                outMtSlotValues[slotIndex] = valuePair.second;
+                            }
+                            return outMtSlotValues;
+                        default:
+                            return base::ResultError("Axis not supported", NAME_NOT_FOUND);
+                    }
+                });
+    }
+
+    std::list<NotifyArgs> processPosition(int32_t x, int32_t y) {
+        std::list<NotifyArgs> args;
+        args += process(EV_ABS, ABS_MT_POSITION_X, x);
+        args += process(EV_ABS, ABS_MT_POSITION_Y, y);
+        return args;
+    }
+
+    std::list<NotifyArgs> processId(int32_t id) { return process(EV_ABS, ABS_MT_TRACKING_ID, id); }
+
+    std::list<NotifyArgs> processKey(int32_t code, int32_t value) {
+        return process(EV_KEY, code, value);
+    }
+
+    std::list<NotifyArgs> processSlot(int32_t slot) { return process(EV_ABS, ABS_MT_SLOT, slot); }
+
+    std::list<NotifyArgs> processSync() { return process(EV_SYN, SYN_REPORT, 0); }
+};
+
+// This test simulates a multi-finger gesture with unexpected reset in between. This might happen
+// due to buffer overflow and device with report a SYN_DROPPED. In this case we expect mapper to be
+// reset, MT slot state to be re-populated and the gesture should be cancelled and restarted.
+TEST_F(MultiTouchInputMapperUnitTest, MultiFingerGestureWithUnexpectedReset) {
+    std::list<NotifyArgs> args;
+
+    // Two fingers down at once.
+    constexpr int32_t FIRST_TRACKING_ID = 1, SECOND_TRACKING_ID = 2;
+    int32_t x1 = 100, y1 = 125, x2 = 200, y2 = 225;
+    processKey(BTN_TOUCH, 1);
+    args += processPosition(x1, y1);
+    args += processId(FIRST_TRACKING_ID);
+    args += processSlot(1);
+    args += processPosition(x2, y2);
+    args += processId(SECOND_TRACKING_ID);
+    ASSERT_THAT(args, IsEmpty());
+
+    args = processSync();
+    ASSERT_THAT(args,
+                ElementsAre(VariantWith<NotifyMotionArgs>(
+                                    WithMotionAction(AMOTION_EVENT_ACTION_DOWN)),
+                            VariantWith<NotifyMotionArgs>(
+                                    WithMotionAction(ACTION_POINTER_1_DOWN))));
+
+    // Move.
+    x1 += 10;
+    y1 += 15;
+    x2 += 5;
+    y2 -= 10;
+    args = processSlot(0);
+    args += processPosition(x1, y1);
+    args += processSlot(1);
+    args += processPosition(x2, y2);
+    ASSERT_THAT(args, IsEmpty());
+
+    args = processSync();
+    ASSERT_THAT(args,
+                ElementsAre(VariantWith<NotifyMotionArgs>(
+                        WithMotionAction(AMOTION_EVENT_ACTION_MOVE))));
+    const auto pointerCoordsBeforeReset = std::get<NotifyMotionArgs>(args.back()).pointerCoords;
+
+    // On buffer overflow mapper will be reset and MT slots data will be repopulated
+    EXPECT_CALL(mMockEventHub, getAbsoluteAxisValue(EVENTHUB_ID, ABS_MT_SLOT, _))
+            .WillRepeatedly([=](int32_t, int32_t, int32_t* outValue) {
+                *outValue = 1;
+                return OK;
+            });
+
+    mockSlotValues(
+            {{1, {Point{x1, y1}, FIRST_TRACKING_ID}}, {2, {Point{x2, y2}, SECOND_TRACKING_ID}}});
+
+    setScanCodeState(KeyState::DOWN, {BTN_TOUCH});
+
+    args = mMapper->reset(systemTime(SYSTEM_TIME_MONOTONIC));
+    ASSERT_THAT(args,
+                ElementsAre(VariantWith<NotifyMotionArgs>(
+                        WithMotionAction(AMOTION_EVENT_ACTION_CANCEL))));
+
+    // SYN_REPORT should restart the gesture again
+    args = processSync();
+    ASSERT_THAT(args,
+                ElementsAre(VariantWith<NotifyMotionArgs>(
+                                    WithMotionAction(AMOTION_EVENT_ACTION_DOWN)),
+                            VariantWith<NotifyMotionArgs>(
+                                    WithMotionAction(ACTION_POINTER_1_DOWN))));
+    ASSERT_EQ(std::get<NotifyMotionArgs>(args.back()).pointerCoords, pointerCoordsBeforeReset);
+
+    // Move.
+    x1 += 10;
+    y1 += 15;
+    x2 += 5;
+    y2 -= 10;
+    args = processSlot(0);
+    args += processPosition(x1, y1);
+    args += processSlot(1);
+    args += processPosition(x2, y2);
+    ASSERT_THAT(args, IsEmpty());
+
+    args = processSync();
+    ASSERT_THAT(args,
+                ElementsAre(VariantWith<NotifyMotionArgs>(
+                        WithMotionAction(AMOTION_EVENT_ACTION_MOVE))));
+
+    // First finger up.
+    args = processSlot(0);
+    args += processId(-1);
+    ASSERT_THAT(args, IsEmpty());
+
+    args = processSync();
+    ASSERT_THAT(args,
+                ElementsAre(VariantWith<NotifyMotionArgs>(WithMotionAction(ACTION_POINTER_0_UP))));
+
+    // Second finger up.
+    processKey(BTN_TOUCH, 0);
+    args = processSlot(1);
+    args += processId(-1);
+    ASSERT_THAT(args, IsEmpty());
+
+    args = processSync();
+    ASSERT_THAT(args,
+                ElementsAre(
+                        VariantWith<NotifyMotionArgs>(WithMotionAction(AMOTION_EVENT_ACTION_UP))));
+}
+
+} // namespace android
diff --git a/services/inputflinger/tests/TouchpadInputMapper_test.cpp b/services/inputflinger/tests/TouchpadInputMapper_test.cpp
index 4be1e8c..fbafbad 100644
--- a/services/inputflinger/tests/TouchpadInputMapper_test.cpp
+++ b/services/inputflinger/tests/TouchpadInputMapper_test.cpp
@@ -103,12 +103,19 @@
         setupAxis(ABS_MT_TOUCH_MINOR, /*valid=*/false, /*min=*/0, /*max=*/0, /*resolution=*/0);
         setupAxis(ABS_MT_WIDTH_MAJOR, /*valid=*/false, /*min=*/0, /*max=*/0, /*resolution=*/0);
         setupAxis(ABS_MT_WIDTH_MINOR, /*valid=*/false, /*min=*/0, /*max=*/0, /*resolution=*/0);
+        setupAxis(ABS_MT_TRACKING_ID, /*valid=*/false, /*min=*/0, /*max=*/0, /*resolution=*/0);
+        setupAxis(ABS_MT_DISTANCE, /*valid=*/false, /*min=*/0, /*max=*/0, /*resolution=*/0);
+        setupAxis(ABS_MT_TOOL_TYPE, /*valid=*/false, /*min=*/0, /*max=*/0, /*resolution=*/0);
 
         EXPECT_CALL(mMockEventHub, getAbsoluteAxisValue(EVENTHUB_ID, ABS_MT_SLOT, testing::_))
                 .WillRepeatedly([](int32_t eventHubId, int32_t, int32_t* outValue) {
                     *outValue = 0;
                     return OK;
                 });
+        EXPECT_CALL(mMockEventHub, getMtSlotValues(EVENTHUB_ID, testing::_, testing::_))
+                .WillRepeatedly([]() -> base::Result<std::vector<int32_t>> {
+                    return base::ResultError("Axis not supported", NAME_NOT_FOUND);
+                });
         createDevice();
         mMapper = createInputMapper<TouchpadInputMapper>(*mDeviceContext, mReaderConfiguration);
     }
diff --git a/services/inputflinger/tests/fuzzers/MapperHelpers.h b/services/inputflinger/tests/fuzzers/MapperHelpers.h
index 81c570d..7898126 100644
--- a/services/inputflinger/tests/fuzzers/MapperHelpers.h
+++ b/services/inputflinger/tests/fuzzers/MapperHelpers.h
@@ -201,6 +201,18 @@
                                   int32_t* outValue) const override {
         return mFdp->ConsumeIntegral<status_t>();
     }
+    base::Result<std::vector<int32_t>> getMtSlotValues(int32_t deviceId, int32_t axis,
+                                                       size_t slotCount) const override {
+        if (mFdp->ConsumeBool()) {
+            std::vector<int32_t> outValues(slotCount + 1);
+            for (size_t i = 0; i < outValues.size(); i++) {
+                outValues.push_back(mFdp->ConsumeIntegral<int32_t>());
+            }
+            return std::move(outValues);
+        } else {
+            return base::ResultError("Fuzzer", UNKNOWN_ERROR);
+        }
+    }
     bool markSupportedKeyCodes(int32_t deviceId, const std::vector<int32_t>& keyCodes,
                                uint8_t* outFlags) const override {
         return mFdp->ConsumeBool();
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index 30ba9e4..a7296f3 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -3370,7 +3370,6 @@
     static const mat4 kDefaultColorTransformMat;
 
     static const Region kDebugRegion;
-    static const compositionengine::CompositionRefreshArgs kDefaultRefreshArgs;
     static const HdrCapabilities kHdrCapabilities;
 
     StrictMock<mock::CompositionEngine> mCompositionEngine;
@@ -3393,7 +3392,6 @@
 const Rect OutputComposeSurfacesTest::kDefaultOutputViewport{1005, 1006, 1007, 1008};
 const Rect OutputComposeSurfacesTest::kDefaultOutputDestinationClip{1013, 1014, 1015, 1016};
 const mat4 OutputComposeSurfacesTest::kDefaultColorTransformMat{mat4() * 0.5f};
-const compositionengine::CompositionRefreshArgs OutputComposeSurfacesTest::kDefaultRefreshArgs;
 const Region OutputComposeSurfacesTest::kDebugRegion{Rect{100, 101, 102, 103}};
 
 const HdrCapabilities OutputComposeSurfacesTest::
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
index ad5e42b..bb32afa 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
@@ -1217,8 +1217,8 @@
             Rect inputBoundsInDisplaySpace =
                     getInputBoundsInDisplaySpace(*cropLayerSnapshot, inputBounds,
                                                  displayInfo.transform);
-            snapshot->inputInfo.touchableRegion = snapshot->inputInfo.touchableRegion.intersect(
-                    displayInfo.transform.transform(inputBoundsInDisplaySpace));
+            snapshot->inputInfo.touchableRegion =
+                    snapshot->inputInfo.touchableRegion.intersect(inputBoundsInDisplaySpace);
         }
 
         // If the layer is a clone, we need to crop the input region to cloned root to prevent
diff --git a/services/surfaceflinger/tests/unittests/FrameTracerTest.cpp b/services/surfaceflinger/tests/unittests/FrameTracerTest.cpp
index 2c71a2e..99062f0 100644
--- a/services/surfaceflinger/tests/unittests/FrameTracerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/FrameTracerTest.cpp
@@ -179,23 +179,35 @@
         tracingSession->StopBlocking();
 
         auto packets = readGraphicsFramePacketsBlocking(tracingSession.get());
-        EXPECT_EQ(packets.size(), 1);
+        ASSERT_EQ(packets.size(), 2);
 
-        const auto& packet = packets[0];
-        ASSERT_TRUE(packet.has_timestamp());
-        EXPECT_EQ(packet.timestamp(), timestamp);
-        ASSERT_TRUE(packet.has_graphics_frame_event());
-        const auto& frame_event = packet.graphics_frame_event();
-        ASSERT_TRUE(frame_event.has_buffer_event());
-        const auto& buffer_event = frame_event.buffer_event();
-        ASSERT_TRUE(buffer_event.has_buffer_id());
-        EXPECT_EQ(buffer_event.buffer_id(), bufferID);
-        ASSERT_TRUE(buffer_event.has_frame_number());
-        EXPECT_EQ(buffer_event.frame_number(), frameNumber);
-        ASSERT_TRUE(buffer_event.has_type());
-        EXPECT_EQ(buffer_event.type(), perfetto::protos::GraphicsFrameEvent_BufferEventType(type));
-        ASSERT_TRUE(buffer_event.has_duration_ns());
-        EXPECT_EQ(buffer_event.duration_ns(), duration);
+        const auto& packet1 = packets[0];
+        ASSERT_TRUE(packet1.has_timestamp());
+        EXPECT_EQ(packet1.timestamp(), timestamp);
+        ASSERT_TRUE(packet1.has_graphics_frame_event());
+        const auto& frame_event1 = packet1.graphics_frame_event();
+        ASSERT_TRUE(frame_event1.has_buffer_event());
+        const auto& buffer_event1 = frame_event1.buffer_event();
+        ASSERT_TRUE(buffer_event1.has_buffer_id());
+        EXPECT_EQ(buffer_event1.buffer_id(), bufferID);
+        ASSERT_TRUE(buffer_event1.has_frame_number());
+        EXPECT_EQ(buffer_event1.frame_number(), frameNumber);
+        ASSERT_TRUE(buffer_event1.has_type());
+        EXPECT_EQ(buffer_event1.type(), perfetto::protos::GraphicsFrameEvent_BufferEventType(type));
+        ASSERT_TRUE(buffer_event1.has_duration_ns());
+        EXPECT_EQ(buffer_event1.duration_ns(), duration);
+
+        const auto& packet2 = packets[1];
+        ASSERT_TRUE(packet2.has_timestamp());
+        EXPECT_EQ(packet2.timestamp(), 0);
+        ASSERT_TRUE(packet2.has_graphics_frame_event());
+        const auto& frame_event2 = packet2.graphics_frame_event();
+        ASSERT_TRUE(frame_event2.has_buffer_event());
+        const auto& buffer_event2 = frame_event2.buffer_event();
+        ASSERT_TRUE(buffer_event2.has_type());
+        EXPECT_EQ(buffer_event2.type(),
+                  perfetto::protos::GraphicsFrameEvent_BufferEventType(
+                          FrameTracer::FrameEvent::UNSPECIFIED));
     }
 }
 
@@ -219,7 +231,18 @@
         tracingSession->StopBlocking();
 
         auto packets = readGraphicsFramePacketsBlocking(tracingSession.get());
-        EXPECT_EQ(packets.size(), 0);
+        ASSERT_EQ(packets.size(), 1);
+        const auto& packet = packets[0];
+        ASSERT_TRUE(packet.has_timestamp());
+        EXPECT_EQ(packet.timestamp(), 0);
+        ASSERT_TRUE(packet.has_graphics_frame_event());
+        const auto& frame_event = packet.graphics_frame_event();
+        ASSERT_TRUE(frame_event.has_buffer_event());
+        const auto& buffer_event = frame_event.buffer_event();
+        ASSERT_TRUE(buffer_event.has_type());
+        EXPECT_EQ(buffer_event.type(),
+                  perfetto::protos::GraphicsFrameEvent_BufferEventType(
+                          FrameTracer::FrameEvent::UNSPECIFIED));
     }
 
     {
@@ -235,22 +258,56 @@
         tracingSession->StopBlocking();
 
         auto packets = readGraphicsFramePacketsBlocking(tracingSession.get());
-        EXPECT_EQ(packets.size(), 2); // Two packets because of the extra trace made above.
+        ASSERT_EQ(packets.size(), 3);
 
-        const auto& packet = packets[1];
-        ASSERT_TRUE(packet.has_timestamp());
-        EXPECT_EQ(packet.timestamp(), timestamp);
-        ASSERT_TRUE(packet.has_graphics_frame_event());
-        const auto& frame_event = packet.graphics_frame_event();
-        ASSERT_TRUE(frame_event.has_buffer_event());
-        const auto& buffer_event = frame_event.buffer_event();
-        ASSERT_TRUE(buffer_event.has_buffer_id());
-        EXPECT_EQ(buffer_event.buffer_id(), bufferID);
-        ASSERT_TRUE(buffer_event.has_frame_number());
-        EXPECT_EQ(buffer_event.frame_number(), frameNumber);
-        ASSERT_TRUE(buffer_event.has_type());
-        EXPECT_EQ(buffer_event.type(), perfetto::protos::GraphicsFrameEvent_BufferEventType(type));
-        EXPECT_FALSE(buffer_event.has_duration_ns());
+        const auto& packet1 = packets[0];
+        ASSERT_TRUE(packet1.has_timestamp());
+        EXPECT_EQ(packet1.timestamp(), timestamp);
+        ASSERT_TRUE(packet1.has_graphics_frame_event());
+        const auto& frame_event1 = packet1.graphics_frame_event();
+        ASSERT_TRUE(frame_event1.has_buffer_event());
+        const auto& buffer_event1 = frame_event1.buffer_event();
+        ASSERT_TRUE(buffer_event1.has_buffer_id());
+        EXPECT_EQ(buffer_event1.buffer_id(), bufferID);
+        ASSERT_TRUE(buffer_event1.has_frame_number());
+        EXPECT_EQ(buffer_event1.frame_number(), frameNumber);
+        ASSERT_TRUE(buffer_event1.has_type());
+        EXPECT_EQ(buffer_event1.type(),
+                  perfetto::protos::GraphicsFrameEvent::BufferEventType(type));
+        EXPECT_FALSE(buffer_event1.has_duration_ns());
+
+        const auto& packet2 = packets[1];
+        ASSERT_TRUE(packet2.has_timestamp());
+        EXPECT_EQ(packet2.timestamp(), timestamp);
+        ASSERT_TRUE(packet2.has_graphics_frame_event());
+        const auto& frame_event2 = packet2.graphics_frame_event();
+        ASSERT_TRUE(frame_event2.has_buffer_event());
+        const auto& buffer_event2 = frame_event2.buffer_event();
+        ASSERT_TRUE(buffer_event2.has_buffer_id());
+        EXPECT_EQ(buffer_event2.buffer_id(), bufferID);
+        ASSERT_TRUE(buffer_event2.has_frame_number());
+        EXPECT_EQ(buffer_event2.frame_number(), frameNumber);
+        ASSERT_TRUE(buffer_event2.has_type());
+        EXPECT_EQ(buffer_event2.type(),
+                  perfetto::protos::GraphicsFrameEvent::BufferEventType(type));
+        EXPECT_FALSE(buffer_event2.has_duration_ns());
+
+        const auto& packet3 = packets[2];
+        ASSERT_TRUE(packet3.has_timestamp());
+        EXPECT_EQ(packet3.timestamp(), 0);
+        ASSERT_TRUE(packet3.has_graphics_frame_event());
+        const auto& frame_event3 = packet3.graphics_frame_event();
+        ASSERT_TRUE(frame_event3.has_buffer_event());
+        const auto& buffer_event3 = frame_event3.buffer_event();
+        ASSERT_TRUE(buffer_event3.has_buffer_id());
+        EXPECT_EQ(buffer_event3.buffer_id(), bufferID);
+        ASSERT_TRUE(buffer_event3.has_frame_number());
+        EXPECT_EQ(buffer_event3.frame_number(), 0);
+        ASSERT_TRUE(buffer_event3.has_type());
+        EXPECT_EQ(buffer_event3.type(),
+                  perfetto::protos::GraphicsFrameEvent::BufferEventType(
+                          FrameTracer::FrameEvent::UNSPECIFIED));
+        EXPECT_FALSE(buffer_event3.has_duration_ns());
     }
 }
 
@@ -285,7 +342,7 @@
     tracingSession->StopBlocking();
 
     auto packets = readGraphicsFramePacketsBlocking(tracingSession.get());
-    EXPECT_EQ(packets.size(), 2);
+    ASSERT_EQ(packets.size(), 3);
 
     const auto& packet1 = packets[0];
     ASSERT_TRUE(packet1.has_timestamp());
@@ -293,6 +350,8 @@
     ASSERT_TRUE(packet1.has_graphics_frame_event());
     ASSERT_TRUE(packet1.graphics_frame_event().has_buffer_event());
     ASSERT_FALSE(packet1.graphics_frame_event().buffer_event().has_duration_ns());
+    EXPECT_EQ(packet1.graphics_frame_event().buffer_event().type(),
+              perfetto::protos::GraphicsFrameEvent::BufferEventType(type));
 
     const auto& packet2 = packets[1];
     ASSERT_TRUE(packet2.has_timestamp());
@@ -300,6 +359,17 @@
     ASSERT_TRUE(packet2.has_graphics_frame_event());
     ASSERT_TRUE(packet2.graphics_frame_event().has_buffer_event());
     ASSERT_FALSE(packet2.graphics_frame_event().buffer_event().has_duration_ns());
+    EXPECT_EQ(packet2.graphics_frame_event().buffer_event().type(),
+              perfetto::protos::GraphicsFrameEvent::BufferEventType(type));
+
+    const auto& packet3 = packets[2];
+    ASSERT_TRUE(packet3.has_timestamp());
+    EXPECT_EQ(packet3.timestamp(), 0);
+    ASSERT_TRUE(packet3.has_graphics_frame_event());
+    ASSERT_TRUE(packet3.graphics_frame_event().has_buffer_event());
+    EXPECT_EQ(packet3.graphics_frame_event().buffer_event().type(),
+              perfetto::protos::GraphicsFrameEvent::BufferEventType(
+                      FrameTracer::FrameEvent::UNSPECIFIED));
 }
 
 TEST_F(FrameTracerTest, traceFenceOlderThanDeadline_ShouldBeIgnored) {
@@ -322,7 +392,15 @@
     tracingSession->StopBlocking();
 
     auto packets = readGraphicsFramePacketsBlocking(tracingSession.get());
-    EXPECT_EQ(packets.size(), 0);
+    ASSERT_EQ(packets.size(), 1);
+    const auto& packet = packets[0];
+    ASSERT_TRUE(packet.has_timestamp());
+    EXPECT_EQ(packet.timestamp(), 0);
+    ASSERT_TRUE(packet.has_graphics_frame_event());
+    ASSERT_TRUE(packet.graphics_frame_event().has_buffer_event());
+    EXPECT_EQ(packet.graphics_frame_event().buffer_event().type(),
+              perfetto::protos::GraphicsFrameEvent::BufferEventType(
+                      FrameTracer::FrameEvent::UNSPECIFIED));
 }
 
 TEST_F(FrameTracerTest, traceFenceWithValidStartTime_ShouldHaveCorrectDuration) {
@@ -357,7 +435,7 @@
     tracingSession->StopBlocking();
 
     auto packets = readGraphicsFramePacketsBlocking(tracingSession.get());
-    EXPECT_EQ(packets.size(), 2);
+    ASSERT_EQ(packets.size(), 3);
 
     const auto& packet1 = packets[0];
     ASSERT_TRUE(packet1.has_timestamp());
@@ -367,6 +445,7 @@
     ASSERT_TRUE(packet1.graphics_frame_event().buffer_event().has_duration_ns());
     const auto& buffer_event1 = packet1.graphics_frame_event().buffer_event();
     EXPECT_EQ(buffer_event1.duration_ns(), duration);
+    EXPECT_EQ(buffer_event1.type(), perfetto::protos::GraphicsFrameEvent::BufferEventType(type));
 
     const auto& packet2 = packets[1];
     ASSERT_TRUE(packet2.has_timestamp());
@@ -376,6 +455,17 @@
     ASSERT_TRUE(packet2.graphics_frame_event().buffer_event().has_duration_ns());
     const auto& buffer_event2 = packet2.graphics_frame_event().buffer_event();
     EXPECT_EQ(buffer_event2.duration_ns(), duration);
+    EXPECT_EQ(buffer_event2.type(), perfetto::protos::GraphicsFrameEvent::BufferEventType(type));
+
+    const auto& packet3 = packets[2];
+    ASSERT_TRUE(packet3.has_timestamp());
+    EXPECT_EQ(packet3.timestamp(), 0);
+    ASSERT_TRUE(packet3.has_graphics_frame_event());
+    ASSERT_TRUE(packet3.graphics_frame_event().has_buffer_event());
+    const auto& buffer_event3 = packet3.graphics_frame_event().buffer_event();
+    EXPECT_EQ(buffer_event3.type(),
+              perfetto::protos::GraphicsFrameEvent::BufferEventType(
+                      FrameTracer::FrameEvent::UNSPECIFIED));
 }
 
 } // namespace
diff --git a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
index 55b20b3..6394d63 100644
--- a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
@@ -353,6 +353,23 @@
     EXPECT_EQ(getSnapshot({.id = 111})->inputInfo.touchableRegion.bounds(), modifiedTouchCrop);
 }
 
+TEST_F(LayerSnapshotTest, CanCropTouchableRegionWithDisplayTransform) {
+    DisplayInfo displayInfo;
+    displayInfo.transform = ui::Transform(ui::Transform::RotationFlags::ROT_90, 1000, 1000);
+    mFrontEndDisplayInfos.emplace_or_replace(ui::LayerStack::fromValue(1), displayInfo);
+
+    Rect touchCrop{300, 300, 400, 500};
+    createRootLayer(3);
+    setCrop(3, touchCrop);
+    setLayerStack(3, 1);
+    Region touch{Rect{0, 0, 1000, 1000}};
+    setTouchableRegionCrop(3, touch, /*touchCropId=*/3, /*replaceTouchableRegionWithCrop=*/false);
+
+    UPDATE_AND_VERIFY(mSnapshotBuilder, {1, 11, 111, 12, 121, 122, 1221, 13, 2, 3});
+    Rect rotatedCrop = {500, 300, 700, 400};
+    EXPECT_EQ(getSnapshot({.id = 3})->inputInfo.touchableRegion.bounds(), rotatedCrop);
+}
+
 TEST_F(LayerSnapshotTest, blurUpdatesWhenAlphaChanges) {
     int blurRadius = 42;
     setBackgroundBlurRadius(1221, static_cast<uint32_t>(blurRadius));
diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp
index 0e45d2d..81fd118 100644
--- a/vulkan/libvulkan/driver.cpp
+++ b/vulkan/libvulkan/driver.cpp
@@ -340,8 +340,9 @@
     ALOGD("Unload builtin Vulkan driver.");
 
     // Close the opened device
-    ALOG_ASSERT(!hal_.dev_->common.close(hal_.dev_->common),
-                "hw_device_t::close() failed.");
+    int err = hal_.dev_->common.close(
+        const_cast<struct hw_device_t*>(&hal_.dev_->common));
+    ALOG_ASSERT(!err, "hw_device_t::close() failed.");
 
     // Close the opened shared library in the hw_module_t
     android_unload_sphal_library(hal_.dev_->common.module->dso);