Merge "Fix AIBinder_setMinSchedulerPolicy failed to set sched policy" into main
diff --git a/aidl/gui/android/view/Surface.aidl b/aidl/gui/android/view/Surface.aidl
index bb3faaf..6686717 100644
--- a/aidl/gui/android/view/Surface.aidl
+++ b/aidl/gui/android/view/Surface.aidl
@@ -17,4 +17,4 @@
 
 package android.view;
 
-@JavaOnlyStableParcelable @NdkOnlyStableParcelable parcelable Surface cpp_header "gui/view/Surface.h" ndk_header "android/native_window_aidl.h";
+@JavaOnlyStableParcelable @NdkOnlyStableParcelable @RustOnlyStableParcelable parcelable Surface cpp_header "gui/view/Surface.h" ndk_header "android/native_window_aidl.h" rust_type "nativewindow::Surface";
diff --git a/cmds/cmd/cmd.cpp b/cmds/cmd/cmd.cpp
index 0ce7711..9695e07 100644
--- a/cmds/cmd/cmd.cpp
+++ b/cmds/cmd/cmd.cpp
@@ -95,7 +95,7 @@
             flags = O_RDWR;
             checkRead = checkWrite = true;
         } else {
-            mErrorLog << "Invalid mode requested: " << mode.c_str() << endl;
+            mErrorLog << "Invalid mode requested: " << mode << endl;
             return -EINVAL;
         }
         int fd = open(fullPath.c_str(), flags, S_IRWXU|S_IRWXG);
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 522442f..326f927 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -198,6 +198,7 @@
 static const std::string TOMBSTONE_FILE_PREFIX = "tombstone_";
 static const std::string ANR_DIR = "/data/anr/";
 static const std::string ANR_FILE_PREFIX = "anr_";
+static const std::string ANR_TRACE_FILE_PREFIX = "trace_";
 static const std::string SHUTDOWN_CHECKPOINTS_DIR = "/data/system/shutdown-checkpoints/";
 static const std::string SHUTDOWN_CHECKPOINTS_FILE_PREFIX = "checkpoints-";
 
@@ -1179,6 +1180,10 @@
     } else {
         printf("*** NO ANRs to dump in %s\n\n", ANR_DIR.c_str());
     }
+
+    // Add Java anr traces (such as generated by the Finalizer Watchdog).
+    AddDumps(ds.anr_trace_data_.begin(), ds.anr_trace_data_.end(), "JAVA ANR TRACES",
+             true /* add_to_zip */);
 }
 
 static void AddAnrTraceFiles() {
@@ -1905,6 +1910,7 @@
     if (!PropertiesHelper::IsDryRun()) {
         ds.tombstone_data_ = GetDumpFds(TOMBSTONE_DIR, TOMBSTONE_FILE_PREFIX);
         ds.anr_data_ = GetDumpFds(ANR_DIR, ANR_FILE_PREFIX);
+        ds.anr_trace_data_ = GetDumpFds(ANR_DIR, ANR_TRACE_FILE_PREFIX);
         ds.shutdown_checkpoints_ = GetDumpFds(
             SHUTDOWN_CHECKPOINTS_DIR, SHUTDOWN_CHECKPOINTS_FILE_PREFIX);
     }
@@ -3046,6 +3052,7 @@
     }
     tombstone_data_.clear();
     anr_data_.clear();
+    anr_trace_data_.clear();
     shutdown_checkpoints_.clear();
 
     // Instead of shutdown the pool, we delete temporary files directly since
@@ -3341,6 +3348,7 @@
 
     tombstone_data_.clear();
     anr_data_.clear();
+    anr_trace_data_.clear();
     shutdown_checkpoints_.clear();
 
     return (consent_callback_ != nullptr &&
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index 8a31c31..596aa76 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -526,6 +526,9 @@
     // List of open ANR dump files.
     std::vector<DumpData> anr_data_;
 
+    // List of open Java traces files in the anr directory.
+    std::vector<DumpData> anr_trace_data_;
+
     // List of open shutdown checkpoint files.
     std::vector<DumpData> shutdown_checkpoints_;
 
diff --git a/cmds/flatland/Android.bp b/cmds/flatland/Android.bp
new file mode 100644
index 0000000..39a0d75
--- /dev/null
+++ b/cmds/flatland/Android.bp
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package {
+    // See: http://go/android-license-faq
+    default_applicable_licenses: [
+        "frameworks_native_license",
+    ],
+}
+
+cc_benchmark {
+    name: "flatland",
+    auto_gen_config: false,
+    srcs: [
+        "Composers.cpp",
+        "GLHelper.cpp",
+        "Renderers.cpp",
+        "Main.cpp",
+    ],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+    compile_multilib: "both",
+    multilib: {
+        lib32: {
+            stem: "flatland",
+        },
+        lib64: {
+            stem: "flatland64",
+        },
+    },
+    shared_libs: [
+        "libEGL",
+        "libGLESv2",
+        "libcutils",
+        "libgui",
+        "libui",
+        "libutils",
+    ],
+}
diff --git a/cmds/flatland/Android.mk b/cmds/flatland/Android.mk
deleted file mode 100644
index 754a99c..0000000
--- a/cmds/flatland/Android.mk
+++ /dev/null
@@ -1,32 +0,0 @@
-local_target_dir := $(TARGET_OUT_DATA)/local/tmp
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:=   \
-    Composers.cpp   \
-    GLHelper.cpp    \
-    Renderers.cpp   \
-    Main.cpp        \
-
-LOCAL_CFLAGS := -Wall -Werror
-
-LOCAL_MODULE:= flatland
-LOCAL_LICENSE_KINDS:= SPDX-license-identifier-Apache-2.0
-LOCAL_LICENSE_CONDITIONS:= notice
-LOCAL_NOTICE_FILE:= $(LOCAL_PATH)/../../NOTICE
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_MODULE_PATH := $(local_target_dir)
-LOCAL_MULTILIB := both
-LOCAL_MODULE_STEM_32 := flatland
-LOCAL_MODULE_STEM_64 := flatland64
-LOCAL_SHARED_LIBRARIES := \
-    libEGL      \
-    libGLESv2   \
-    libcutils   \
-    libgui      \
-    libui       \
-    libutils    \
-
-include $(BUILD_EXECUTABLE)
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/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index cad7787..71a8740 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -234,12 +234,12 @@
     return ok();
 }
 
-binder::Status checkUidInAppRange(int32_t appUid) {
-    if (FIRST_APPLICATION_UID <= appUid && appUid <= LAST_APPLICATION_UID) {
+binder::Status checkArgumentAppId(int32_t appId) {
+    if (FIRST_APPLICATION_UID <= appId && appId <= LAST_APPLICATION_UID) {
         return ok();
     }
     return exception(binder::Status::EX_ILLEGAL_ARGUMENT,
-                     StringPrintf("UID %d is outside of the range", appUid));
+                     StringPrintf("appId %d is outside of the range", appId));
 }
 
 #define ENFORCE_UID(uid) {                                  \
@@ -302,12 +302,12 @@
         }                                                      \
     }
 
-#define CHECK_ARGUMENT_UID_IN_APP_RANGE(uid)               \
-    {                                                      \
-        binder::Status status = checkUidInAppRange((uid)); \
-        if (!status.isOk()) {                              \
-            return status;                                 \
-        }                                                  \
+#define CHECK_ARGUMENT_APP_ID(appId)                         \
+    {                                                        \
+        binder::Status status = checkArgumentAppId((appId)); \
+        if (!status.isOk()) {                                \
+            return status;                                   \
+        }                                                    \
     }
 
 #ifdef GRANULAR_LOCKS
@@ -411,7 +411,7 @@
 }  // namespace
 
 binder::Status InstalldNativeService::FsveritySetupAuthToken::authenticate(
-        const ParcelFileDescriptor& authFd, int32_t appUid, int32_t userId) {
+        const ParcelFileDescriptor& authFd, int32_t uid) {
     int open_flags = fcntl(authFd.get(), F_GETFL);
     if (open_flags < 0) {
         return exception(binder::Status::EX_SERVICE_SPECIFIC, "fcntl failed");
@@ -426,9 +426,8 @@
         return exception(binder::Status::EX_SECURITY, "Not a regular file");
     }
     // Don't accept a file owned by a different app.
-    uid_t uid = multiuser_get_uid(userId, appUid);
-    if (this->mStatFromAuthFd.st_uid != uid) {
-        return exception(binder::Status::EX_SERVICE_SPECIFIC, "File not owned by appUid");
+    if (this->mStatFromAuthFd.st_uid != (uid_t)uid) {
+        return exception(binder::Status::EX_SERVICE_SPECIFIC, "File not owned by uid");
     }
     return ok();
 }
@@ -3986,7 +3985,7 @@
 // attacker-in-the-middle cannot enable fs-verity on arbitrary app files. If the FD is not writable,
 // return null.
 //
-// appUid and userId are passed for additional ownership check, such that one app can not be
+// app process uid is passed for additional ownership check, such that one app can not be
 // authenticated for another app's file. These parameters are assumed trusted for this purpose of
 // consistency check.
 //
@@ -3994,13 +3993,13 @@
 // Since enabling fs-verity to a file requires no outstanding writable FD, passing the authFd to the
 // server allows the server to hold the only reference (as long as the client app doesn't).
 binder::Status InstalldNativeService::createFsveritySetupAuthToken(
-        const ParcelFileDescriptor& authFd, int32_t appUid, int32_t userId,
+        const ParcelFileDescriptor& authFd, int32_t uid,
         sp<IFsveritySetupAuthToken>* _aidl_return) {
-    CHECK_ARGUMENT_UID_IN_APP_RANGE(appUid);
-    ENFORCE_VALID_USER(userId);
+    CHECK_ARGUMENT_APP_ID(multiuser_get_app_id(uid));
+    ENFORCE_VALID_USER(multiuser_get_user_id(uid));
 
     auto token = sp<FsveritySetupAuthToken>::make();
-    binder::Status status = token->authenticate(authFd, appUid, userId);
+    binder::Status status = token->authenticate(authFd, uid);
     if (!status.isOk()) {
         return status;
     }
diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h
index 1ec092d..88caba7 100644
--- a/cmds/installd/InstalldNativeService.h
+++ b/cmds/installd/InstalldNativeService.h
@@ -44,8 +44,7 @@
     public:
         FsveritySetupAuthToken() : mStatFromAuthFd() {}
 
-        binder::Status authenticate(const android::os::ParcelFileDescriptor& authFd, int32_t appUid,
-                                    int32_t userId);
+        binder::Status authenticate(const android::os::ParcelFileDescriptor& authFd, int32_t uid);
         bool isSameStat(const struct stat& st) const;
 
     private:
@@ -213,7 +212,7 @@
                                      int32_t* _aidl_return);
 
     binder::Status createFsveritySetupAuthToken(const android::os::ParcelFileDescriptor& authFd,
-                                                int32_t appUid, int32_t userId,
+                                                int32_t uid,
                                                 android::sp<IFsveritySetupAuthToken>* _aidl_return);
     binder::Status enableFsverity(const android::sp<IFsveritySetupAuthToken>& authToken,
                                   const std::string& filePath, const std::string& packageName,
diff --git a/cmds/installd/OWNERS b/cmds/installd/OWNERS
index 643b2c2..e9fb85b 100644
--- a/cmds/installd/OWNERS
+++ b/cmds/installd/OWNERS
@@ -1,11 +1,10 @@
 set noparent
 
-calin@google.com
 jsharkey@android.com
 maco@google.com
 mast@google.com
+jiakaiz@google.com
 narayan@google.com
 ngeoffray@google.com
 rpl@google.com
-toddke@google.com
 patb@google.com
diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl
index 8893e38..120d61d 100644
--- a/cmds/installd/binder/android/os/IInstalld.aidl
+++ b/cmds/installd/binder/android/os/IInstalld.aidl
@@ -145,8 +145,7 @@
         //
         // We don't necessarily need a method here, so it's left blank intentionally.
     }
-    IFsveritySetupAuthToken createFsveritySetupAuthToken(in ParcelFileDescriptor authFd, int appUid,
-            int userId);
+    IFsveritySetupAuthToken createFsveritySetupAuthToken(in ParcelFileDescriptor authFd, int uid);
     int enableFsverity(in IFsveritySetupAuthToken authToken, @utf8InCpp String filePath,
             @utf8InCpp String packageName);
 
diff --git a/cmds/installd/tests/installd_service_test.cpp b/cmds/installd/tests/installd_service_test.cpp
index 4bc92af..f2b578a 100644
--- a/cmds/installd/tests/installd_service_test.cpp
+++ b/cmds/installd/tests/installd_service_test.cpp
@@ -548,8 +548,7 @@
         unique_fd ufd(open(path.c_str(), open_mode));
         EXPECT_GE(ufd.get(), 0) << "open failed: " << strerror(errno);
         ParcelFileDescriptor rfd(std::move(ufd));
-        return service->createFsveritySetupAuthToken(std::move(rfd), kTestAppId, kTestUserId,
-                                                     _aidl_return);
+        return service->createFsveritySetupAuthToken(std::move(rfd), kTestAppId, _aidl_return);
     }
 };
 
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/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp
index 77989d1..f2f0a0f 100644
--- a/cmds/servicemanager/ServiceManager.cpp
+++ b/cmds/servicemanager/ServiceManager.cpp
@@ -150,7 +150,7 @@
     std::optional<std::string> updatableViaApex;
 
     forEachManifest([&](const ManifestWithDescription& mwd) {
-        mwd.manifest->forEachInstance([&](const auto& manifestInstance) {
+        bool cont = mwd.manifest->forEachInstance([&](const auto& manifestInstance) {
             if (manifestInstance.format() != vintf::HalFormat::AIDL) return true;
             if (manifestInstance.package() != aname.package) return true;
             if (manifestInstance.interface() != aname.iface) return true;
@@ -158,8 +158,7 @@
             updatableViaApex = manifestInstance.updatableViaApex();
             return false; // break (libvintf uses opposite convention)
         });
-        if (updatableViaApex.has_value()) return true; // break (found match)
-        return false; // continue
+        return !cont;
     });
 
     return updatableViaApex;
diff --git a/cmds/servicemanager/main.cpp b/cmds/servicemanager/main.cpp
index ae56cb0..07908ba 100644
--- a/cmds/servicemanager/main.cpp
+++ b/cmds/servicemanager/main.cpp
@@ -40,15 +40,12 @@
 public:
     static sp<BinderCallback> setupTo(const sp<Looper>& looper) {
         sp<BinderCallback> cb = sp<BinderCallback>::make();
+        cb->mLooper = looper;
 
-        int binder_fd = -1;
-        IPCThreadState::self()->setupPolling(&binder_fd);
-        LOG_ALWAYS_FATAL_IF(binder_fd < 0, "Failed to setupPolling: %d", binder_fd);
+        IPCThreadState::self()->setupPolling(&cb->mBinderFd);
+        LOG_ALWAYS_FATAL_IF(cb->mBinderFd < 0, "Failed to setupPolling: %d", cb->mBinderFd);
 
-        int ret = looper->addFd(binder_fd,
-                                Looper::POLL_CALLBACK,
-                                Looper::EVENT_INPUT,
-                                cb,
+        int ret = looper->addFd(cb->mBinderFd, Looper::POLL_CALLBACK, Looper::EVENT_INPUT, cb,
                                 nullptr /*data*/);
         LOG_ALWAYS_FATAL_IF(ret != 1, "Failed to add binder FD to Looper");
 
@@ -59,13 +56,26 @@
         IPCThreadState::self()->handlePolledCommands();
         return 1;  // Continue receiving callbacks.
     }
+
+    void repoll() {
+        if (!mLooper->repoll(mBinderFd)) {
+            ALOGE("Failed to repoll binder FD.");
+        }
+    }
+
+private:
+    sp<Looper> mLooper;
+    int mBinderFd = -1;
 };
 
 // LooperCallback for IClientCallback
 class ClientCallbackCallback : public LooperCallback {
 public:
-    static sp<ClientCallbackCallback> setupTo(const sp<Looper>& looper, const sp<ServiceManager>& manager) {
+    static sp<ClientCallbackCallback> setupTo(const sp<Looper>& looper,
+                                              const sp<ServiceManager>& manager,
+                                              sp<BinderCallback> binderCallback) {
         sp<ClientCallbackCallback> cb = sp<ClientCallbackCallback>::make(manager);
+        cb->mBinderCallback = binderCallback;
 
         int fdTimer = timerfd_create(CLOCK_MONOTONIC, 0 /*flags*/);
         LOG_ALWAYS_FATAL_IF(fdTimer < 0, "Failed to timerfd_create: fd: %d err: %d", fdTimer, errno);
@@ -102,12 +112,15 @@
         }
 
         mManager->handleClientCallbacks();
+        mBinderCallback->repoll(); // b/316829336
+
         return 1;  // Continue receiving callbacks.
     }
 private:
     friend sp<ClientCallbackCallback>;
     ClientCallbackCallback(const sp<ServiceManager>& manager) : mManager(manager) {}
     sp<ServiceManager> mManager;
+    sp<BinderCallback> mBinderCallback;
 };
 
 int main(int argc, char** argv) {
@@ -139,8 +152,8 @@
 
     sp<Looper> looper = Looper::prepare(false /*allowNonCallbacks*/);
 
-    BinderCallback::setupTo(looper);
-    ClientCallbackCallback::setupTo(looper, manager);
+    sp<BinderCallback> binderCallback = BinderCallback::setupTo(looper);
+    ClientCallbackCallback::setupTo(looper, manager, binderCallback);
 
 #ifndef VENDORSERVICEMANAGER
     if (!SetProperty("servicemanager.ready", "true")) {
diff --git a/cmds/servicemanager/servicemanager.rc b/cmds/servicemanager/servicemanager.rc
index 4f92b3a..6c450ab 100644
--- a/cmds/servicemanager/servicemanager.rc
+++ b/cmds/servicemanager/servicemanager.rc
@@ -11,5 +11,5 @@
     onrestart class_restart --only-enabled main
     onrestart class_restart --only-enabled hal
     onrestart class_restart --only-enabled early_hal
-    task_profiles ServiceCapacityLow
+    task_profiles ProcessCapacityHigh
     shutdown critical
diff --git a/include/android/input.h b/include/android/input.h
index 9a0eb4d..16d86af 100644
--- a/include/android/input.h
+++ b/include/android/input.h
@@ -54,16 +54,12 @@
 #include <stdint.h>
 #include <sys/types.h>
 #include <android/keycodes.h>
-
-// This file is included by modules that have host support but android/looper.h is not supported
-// on host. __REMOVED_IN needs to be defined in order for android/looper.h to be compiled.
-#ifndef __BIONIC__
-#define __REMOVED_IN(x) __attribute__((deprecated))
-#endif
 #include <android/looper.h>
 
 #include <jni.h>
 
+// This file may also be built on glibc or on Windows/MacOS libc's, so no-op
+// definitions are provided.
 #if !defined(__INTRODUCED_IN)
 #define __INTRODUCED_IN(__api_level) /* nothing */
 #endif
diff --git a/include/android/looper.h b/include/android/looper.h
index 4fe142a..e50730d 100644
--- a/include/android/looper.h
+++ b/include/android/looper.h
@@ -26,10 +26,18 @@
 #ifndef ANDROID_LOOPER_H
 #define ANDROID_LOOPER_H
 
+#include <sys/cdefs.h>
+
 #ifdef __cplusplus
 extern "C" {
 #endif
 
+// This file may also be built on glibc or on Windows/MacOS libc's, so
+// deprecated definitions are provided.
+#if !defined(__REMOVED_IN)
+#define __REMOVED_IN(__api_level) __attribute__((__deprecated__))
+#endif
+
 struct ALooper;
 /**
  * ALooper
diff --git a/include/android/sensor.h b/include/android/sensor.h
index 16c5dde..0cc7834 100644
--- a/include/android/sensor.h
+++ b/include/android/sensor.h
@@ -29,6 +29,8 @@
 #ifndef ANDROID_SENSOR_H
 #define ANDROID_SENSOR_H
 
+#include <sys/cdefs.h>
+
 /******************************************************************
  *
  * IMPORTANT NOTICE:
@@ -45,11 +47,6 @@
  *   - DO NOT CHANGE THE LAYOUT OR SIZE OF STRUCTURES
  */
 
-// This file is included by modules that have host support but android/looper.h is not supported
-// on host. __REMOVED_IN needs to be defined in order for android/looper.h to be compiled.
-#ifndef __BIONIC__
-#define __REMOVED_IN(x) __attribute__((deprecated))
-#endif
 #include <android/looper.h>
 
 #include <stdbool.h>
@@ -57,6 +54,8 @@
 #include <math.h>
 #include <stdint.h>
 
+// This file may also be built on glibc or on Windows/MacOS libc's, so no-op
+// and deprecated definitions are provided.
 #if !defined(__INTRODUCED_IN)
 #define __INTRODUCED_IN(__api_level) /* nothing */
 #endif
diff --git a/include/input/Input.h b/include/input/Input.h
index 527a477..88d1c11 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -284,6 +284,16 @@
     // the touch firmware or driver.  Causes touch events from the same device to be canceled.
     POLICY_FLAG_GESTURE = 0x00000008,
 
+    // Indicates that key usage mapping represents a fallback mapping.
+    // Fallback mappings cannot be used to definitively determine whether a device
+    // supports a key code. For example, a HID device can report a key press
+    // as a HID usage code if it is not mapped to any linux key code in the kernel.
+    // However, we cannot know which HID usage codes that device supports from
+    // userspace through the evdev. We can use fallback mappings to convert HID
+    // usage codes to Android key codes without needing to know if a device can
+    // actually report the usage code.
+    POLICY_FLAG_FALLBACK_USAGE_MAPPING = 0x00000010,
+
     POLICY_FLAG_RAW_MASK = 0x0000ffff,
 
 #ifdef __linux__
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_cpp/android/persistable_bundle_aidl.h b/libs/binder/ndk/include_cpp/android/persistable_bundle_aidl.h
index f178027..864ff50 100644
--- a/libs/binder/ndk/include_cpp/android/persistable_bundle_aidl.h
+++ b/libs/binder/ndk/include_cpp/android/persistable_bundle_aidl.h
@@ -31,7 +31,11 @@
  */
 class PersistableBundle {
    public:
-    PersistableBundle() noexcept : mPBundle(APersistableBundle_new()) {}
+    PersistableBundle() noexcept {
+        if (__builtin_available(android __ANDROID_API_V__, *)) {
+            mPBundle = APersistableBundle_new();
+        }
+    }
     // takes ownership of the APersistableBundle*
     PersistableBundle(APersistableBundle* _Nonnull bundle) noexcept : mPBundle(bundle) {}
     // takes ownership of the APersistableBundle*
@@ -57,7 +61,7 @@
         if (__builtin_available(android __ANDROID_API_V__, *)) {
             return APersistableBundle_readFromParcel(parcel, &mPBundle);
         } else {
-            return STATUS_FAILED_TRANSACTION;
+            return STATUS_INVALID_OPERATION;
         }
     }
 
@@ -68,7 +72,7 @@
         if (__builtin_available(android __ANDROID_API_V__, *)) {
             return APersistableBundle_writeToParcel(mPBundle, parcel);
         } else {
-            return STATUS_FAILED_TRANSACTION;
+            return STATUS_INVALID_OPERATION;
         }
     }
 
@@ -327,20 +331,32 @@
     }
 
     bool getBooleanVector(const std::string& key, std::vector<bool>* _Nonnull vec) {
-        return getVecInternal<bool>(&APersistableBundle_getBooleanVector, mPBundle, key.c_str(),
-                                    vec);
+        if (__builtin_available(android __ANDROID_API_V__, *)) {
+            return getVecInternal<bool>(&APersistableBundle_getBooleanVector, mPBundle, key.c_str(),
+                                        vec);
+        }
+        return false;
     }
     bool getIntVector(const std::string& key, std::vector<int32_t>* _Nonnull vec) {
-        return getVecInternal<int32_t>(&APersistableBundle_getIntVector, mPBundle, key.c_str(),
-                                       vec);
+        if (__builtin_available(android __ANDROID_API_V__, *)) {
+            return getVecInternal<int32_t>(&APersistableBundle_getIntVector, mPBundle, key.c_str(),
+                                           vec);
+        }
+        return false;
     }
     bool getLongVector(const std::string& key, std::vector<int64_t>* _Nonnull vec) {
-        return getVecInternal<int64_t>(&APersistableBundle_getLongVector, mPBundle, key.c_str(),
-                                       vec);
+        if (__builtin_available(android __ANDROID_API_V__, *)) {
+            return getVecInternal<int64_t>(&APersistableBundle_getLongVector, mPBundle, key.c_str(),
+                                           vec);
+        }
+        return false;
     }
     bool getDoubleVector(const std::string& key, std::vector<double>* _Nonnull vec) {
-        return getVecInternal<double>(&APersistableBundle_getDoubleVector, mPBundle, key.c_str(),
-                                      vec);
+        if (__builtin_available(android __ANDROID_API_V__, *)) {
+            return getVecInternal<double>(&APersistableBundle_getDoubleVector, mPBundle,
+                                          key.c_str(), vec);
+        }
+        return false;
     }
 
     // Takes ownership of and frees the char** and its elements.
@@ -361,15 +377,17 @@
     }
 
     bool getStringVector(const std::string& key, std::vector<std::string>* _Nonnull vec) {
-        int32_t bytes = APersistableBundle_getStringVector(mPBundle, key.c_str(), nullptr, 0,
-                                                           &stringAllocator, nullptr);
-        if (bytes > 0) {
-            char** strings = (char**)malloc(bytes);
-            if (strings) {
-                bytes = APersistableBundle_getStringVector(mPBundle, key.c_str(), strings, bytes,
-                                                           &stringAllocator, nullptr);
-                *vec = moveStringsInternal<std::vector<std::string>>(strings, bytes);
-                return true;
+        if (__builtin_available(android __ANDROID_API_V__, *)) {
+            int32_t bytes = APersistableBundle_getStringVector(mPBundle, key.c_str(), nullptr, 0,
+                                                               &stringAllocator, nullptr);
+            if (bytes > 0) {
+                char** strings = (char**)malloc(bytes);
+                if (strings) {
+                    bytes = APersistableBundle_getStringVector(mPBundle, key.c_str(), strings,
+                                                               bytes, &stringAllocator, nullptr);
+                    *vec = moveStringsInternal<std::vector<std::string>>(strings, bytes);
+                    return true;
+                }
             }
         }
         return false;
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/ndk/stability.cpp b/libs/binder/ndk/stability.cpp
index 73eb863..ca3d5e6 100644
--- a/libs/binder/ndk/stability.cpp
+++ b/libs/binder/ndk/stability.cpp
@@ -27,7 +27,7 @@
 #error libbinder_ndk should only be built in a system context
 #endif
 
-#ifdef __ANDROID_VENDOR__
+#if defined(__ANDROID_VENDOR__) && !defined(__TRUSTY__)
 #error libbinder_ndk should only be built in a system context
 #endif
 
diff --git a/libs/binder/rust/src/lib.rs b/libs/binder/rust/src/lib.rs
index 7f9348d..16049f2 100644
--- a/libs/binder/rust/src/lib.rs
+++ b/libs/binder/rust/src/lib.rs
@@ -136,8 +136,8 @@
     pub use crate::native::Binder;
     pub use crate::parcel::{
         BorrowedParcel, Deserialize, DeserializeArray, DeserializeOption, Parcel,
-        ParcelableMetadata, Serialize, SerializeArray, SerializeOption, NON_NULL_PARCELABLE_FLAG,
-        NULL_PARCELABLE_FLAG,
+        ParcelableMetadata, Serialize, SerializeArray, SerializeOption, UnstructuredParcelable,
+        NON_NULL_PARCELABLE_FLAG, NULL_PARCELABLE_FLAG,
     };
     pub use crate::proxy::{AssociateClass, Proxy};
 }
diff --git a/libs/binder/rust/src/parcel.rs b/libs/binder/rust/src/parcel.rs
index f9f135d..3bfc425 100644
--- a/libs/binder/rust/src/parcel.rs
+++ b/libs/binder/rust/src/parcel.rs
@@ -34,7 +34,7 @@
 pub use self::file_descriptor::ParcelFileDescriptor;
 pub use self::parcelable::{
     Deserialize, DeserializeArray, DeserializeOption, Parcelable, Serialize, SerializeArray,
-    SerializeOption, NON_NULL_PARCELABLE_FLAG, NULL_PARCELABLE_FLAG,
+    SerializeOption, UnstructuredParcelable, NON_NULL_PARCELABLE_FLAG, NULL_PARCELABLE_FLAG,
 };
 pub use self::parcelable_holder::{ParcelableHolder, ParcelableMetadata};
 
diff --git a/libs/binder/rust/src/parcel/parcelable.rs b/libs/binder/rust/src/parcel/parcelable.rs
index 9008a3c..33dfe19 100644
--- a/libs/binder/rust/src/parcel/parcelable.rs
+++ b/libs/binder/rust/src/parcel/parcelable.rs
@@ -27,7 +27,7 @@
 use std::ptr;
 use std::slice;
 
-/// Super-trait for Binder parcelables.
+/// Super-trait for structured Binder parcelables, i.e. those generated from AIDL.
 ///
 /// This trait is equivalent `android::Parcelable` in C++,
 /// and defines a common interface that all parcelables need
@@ -50,6 +50,35 @@
     fn read_from_parcel(&mut self, parcel: &BorrowedParcel<'_>) -> Result<()>;
 }
 
+/// Super-trait for unstructured Binder parcelables, i.e. those implemented manually.
+///
+/// These differ from structured parcelables in that they may not have a reasonable default value
+/// and so aren't required to implement `Default`.
+pub trait UnstructuredParcelable: Sized {
+    /// Internal serialization function for parcelables.
+    ///
+    /// This method is mainly for internal use. `Serialize::serialize` and its variants are
+    /// generally preferred over calling this function, since the former also prepend a header.
+    fn write_to_parcel(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()>;
+
+    /// Internal deserialization function for parcelables.
+    ///
+    /// This method is mainly for internal use. `Deserialize::deserialize` and its variants are
+    /// generally preferred over calling this function, since the former also parse the additional
+    /// header.
+    fn from_parcel(parcel: &BorrowedParcel<'_>) -> Result<Self>;
+
+    /// Internal deserialization function for parcelables.
+    ///
+    /// This method is mainly for internal use. `Deserialize::deserialize_from` and its variants are
+    /// generally preferred over calling this function, since the former also parse the additional
+    /// header.
+    fn read_from_parcel(&mut self, parcel: &BorrowedParcel<'_>) -> Result<()> {
+        *self = Self::from_parcel(parcel)?;
+        Ok(())
+    }
+}
+
 /// A struct whose instances can be written to a [`crate::parcel::Parcel`].
 // Might be able to hook this up as a serde backend in the future?
 pub trait Serialize {
@@ -1002,6 +1031,125 @@
     };
 }
 
+/// Implements `Serialize` trait and friends for an unstructured parcelable.
+///
+/// The target type must implement the `UnstructuredParcelable` trait.
+#[macro_export]
+macro_rules! impl_serialize_for_unstructured_parcelable {
+    ($parcelable:ident) => {
+        $crate::impl_serialize_for_unstructured_parcelable!($parcelable < >);
+    };
+    ($parcelable:ident < $( $param:ident ),* , >) => {
+        $crate::impl_serialize_for_unstructured_parcelable!($parcelable < $($param),* >);
+    };
+    ($parcelable:ident < $( $param:ident ),* > ) => {
+        impl < $($param),* > $crate::binder_impl::Serialize for $parcelable < $($param),* > {
+            fn serialize(
+                &self,
+                parcel: &mut $crate::binder_impl::BorrowedParcel<'_>,
+            ) -> std::result::Result<(), $crate::StatusCode> {
+                <Self as $crate::binder_impl::SerializeOption>::serialize_option(Some(self), parcel)
+            }
+        }
+
+        impl < $($param),* > $crate::binder_impl::SerializeArray for $parcelable < $($param),* > {}
+
+        impl < $($param),* > $crate::binder_impl::SerializeOption for $parcelable < $($param),* > {
+            fn serialize_option(
+                this: Option<&Self>,
+                parcel: &mut $crate::binder_impl::BorrowedParcel<'_>,
+            ) -> std::result::Result<(), $crate::StatusCode> {
+                if let Some(this) = this {
+                    use $crate::binder_impl::UnstructuredParcelable;
+                    parcel.write(&$crate::binder_impl::NON_NULL_PARCELABLE_FLAG)?;
+                    this.write_to_parcel(parcel)
+                } else {
+                    parcel.write(&$crate::binder_impl::NULL_PARCELABLE_FLAG)
+                }
+            }
+        }
+    };
+}
+
+/// Implement `Deserialize` trait and friends for an unstructured parcelable
+///
+/// The target type must implement the `UnstructuredParcelable` trait.
+#[macro_export]
+macro_rules! impl_deserialize_for_unstructured_parcelable {
+    ($parcelable:ident) => {
+        $crate::impl_deserialize_for_unstructured_parcelable!($parcelable < >);
+    };
+    ($parcelable:ident < $( $param:ident ),* , >) => {
+        $crate::impl_deserialize_for_unstructured_parcelable!($parcelable < $($param),* >);
+    };
+    ($parcelable:ident < $( $param:ident ),* > ) => {
+        impl < $($param: Default),* > $crate::binder_impl::Deserialize for $parcelable < $($param),* > {
+            type UninitType = Option<Self>;
+            fn uninit() -> Self::UninitType { None }
+            fn from_init(value: Self) -> Self::UninitType { Some(value) }
+            fn deserialize(
+                parcel: &$crate::binder_impl::BorrowedParcel<'_>,
+            ) -> std::result::Result<Self, $crate::StatusCode> {
+                $crate::binder_impl::DeserializeOption::deserialize_option(parcel)
+                    .transpose()
+                    .unwrap_or(Err($crate::StatusCode::UNEXPECTED_NULL))
+            }
+            fn deserialize_from(
+                &mut self,
+                parcel: &$crate::binder_impl::BorrowedParcel<'_>,
+            ) -> std::result::Result<(), $crate::StatusCode> {
+                let status: i32 = parcel.read()?;
+                if status == $crate::binder_impl::NULL_PARCELABLE_FLAG {
+                    Err($crate::StatusCode::UNEXPECTED_NULL)
+                } else {
+                    use $crate::binder_impl::UnstructuredParcelable;
+                    self.read_from_parcel(parcel)
+                }
+            }
+        }
+
+        impl < $($param: Default),* > $crate::binder_impl::DeserializeArray for $parcelable < $($param),* > {}
+
+        impl < $($param: Default),* > $crate::binder_impl::DeserializeOption for $parcelable < $($param),* > {
+            fn deserialize_option(
+                parcel: &$crate::binder_impl::BorrowedParcel<'_>,
+            ) -> std::result::Result<Option<Self>, $crate::StatusCode> {
+                let present: i32 = parcel.read()?;
+                match present {
+                    $crate::binder_impl::NULL_PARCELABLE_FLAG => Ok(None),
+                    $crate::binder_impl::NON_NULL_PARCELABLE_FLAG => {
+                        use $crate::binder_impl::UnstructuredParcelable;
+                        Ok(Some(Self::from_parcel(parcel)?))
+                    }
+                    _ => Err(StatusCode::BAD_VALUE),
+                }
+            }
+            fn deserialize_option_from(
+                this: &mut Option<Self>,
+                parcel: &$crate::binder_impl::BorrowedParcel<'_>,
+            ) -> std::result::Result<(), $crate::StatusCode> {
+                let present: i32 = parcel.read()?;
+                match present {
+                    $crate::binder_impl::NULL_PARCELABLE_FLAG => {
+                        *this = None;
+                        Ok(())
+                    }
+                    $crate::binder_impl::NON_NULL_PARCELABLE_FLAG => {
+                        use $crate::binder_impl::UnstructuredParcelable;
+                        if let Some(this) = this {
+                            this.read_from_parcel(parcel)?;
+                        } else {
+                            *this = Some(Self::from_parcel(parcel)?);
+                        }
+                        Ok(())
+                    }
+                    _ => Err(StatusCode::BAD_VALUE),
+                }
+            }
+        }
+    };
+}
+
 impl<T: Serialize> Serialize for Box<T> {
     fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
         Serialize::serialize(&**self, parcel)
diff --git a/libs/binder/tests/binderThroughputTest.cpp b/libs/binder/tests/binderThroughputTest.cpp
index 0ea4a3f..10912c7 100644
--- a/libs/binder/tests/binderThroughputTest.cpp
+++ b/libs/binder/tests/binderThroughputTest.cpp
@@ -49,6 +49,63 @@
     }
 };
 
+static uint64_t warn_latency = std::numeric_limits<uint64_t>::max();
+
+struct ProcResults {
+    vector<uint64_t> data;
+
+    ProcResults(size_t capacity) { data.reserve(capacity); }
+
+    void add_time(uint64_t time) { data.push_back(time); }
+    void combine_with(const ProcResults& append) {
+        data.insert(data.end(), append.data.begin(), append.data.end());
+    }
+    uint64_t worst() {
+        return *max_element(data.begin(), data.end());
+    }
+    void dump() {
+        if (data.size() == 0) {
+            // This avoids index-out-of-bounds below.
+            cout << "error: no data\n" << endl;
+            return;
+        }
+
+        size_t num_long_transactions = 0;
+        for (uint64_t elem : data) {
+            if (elem > warn_latency) {
+                num_long_transactions += 1;
+            }
+        }
+
+        if (num_long_transactions > 0) {
+            cout << (double)num_long_transactions / data.size() << "% of transactions took longer "
+                "than estimated max latency. Consider setting -m to be higher than "
+                << worst() / 1000 << " microseconds" << endl;
+        }
+
+        sort(data.begin(), data.end());
+
+        uint64_t total_time = 0;
+        for (uint64_t elem : data) {
+            total_time += elem;
+        }
+
+        double best = (double)data[0] / 1.0E6;
+        double worst = (double)data.back() / 1.0E6;
+        double average = (double)total_time / data.size() / 1.0E6;
+        cout << "average:" << average << "ms worst:" << worst << "ms best:" << best << "ms" << endl;
+
+        double percentile_50 = data[(50 * data.size()) / 100] / 1.0E6;
+        double percentile_90 = data[(90 * data.size()) / 100] / 1.0E6;
+        double percentile_95 = data[(95 * data.size()) / 100] / 1.0E6;
+        double percentile_99 = data[(99 * data.size()) / 100] / 1.0E6;
+        cout << "50%: " << percentile_50 << " ";
+        cout << "90%: " << percentile_90 << " ";
+        cout << "95%: " << percentile_95 << " ";
+        cout << "99%: " << percentile_99 << endl;
+    }
+};
+
 class Pipe {
     int m_readFd;
     int m_writeFd;
@@ -79,13 +136,37 @@
         int error = read(m_readFd, &val, sizeof(val));
         ASSERT_TRUE(error >= 0);
     }
-    template <typename T> void send(const T& v) {
-        int error = write(m_writeFd, &v, sizeof(T));
+    void send(const ProcResults& v) {
+        size_t num_elems = v.data.size();
+
+        int error = write(m_writeFd, &num_elems, sizeof(size_t));
         ASSERT_TRUE(error >= 0);
+
+        char* to_write = (char*)v.data.data();
+        size_t num_bytes = sizeof(uint64_t) * num_elems;
+
+        while (num_bytes > 0) {
+            int ret = write(m_writeFd, to_write, num_bytes);
+            ASSERT_TRUE(ret >= 0);
+            num_bytes -= ret;
+            to_write += ret;
+        }
     }
-    template <typename T> void recv(T& v) {
-        int error = read(m_readFd, &v, sizeof(T));
+    void recv(ProcResults& v) {
+        size_t num_elems = 0;
+        int error = read(m_readFd, &num_elems, sizeof(size_t));
         ASSERT_TRUE(error >= 0);
+
+        v.data.resize(num_elems);
+        char* read_to = (char*)v.data.data();
+        size_t num_bytes = sizeof(uint64_t) * num_elems;
+
+        while (num_bytes > 0) {
+            int ret = read(m_readFd, read_to, num_bytes);
+            ASSERT_TRUE(ret >= 0);
+            num_bytes -= ret;
+            read_to += ret;
+        }
     }
     static tuple<Pipe, Pipe> createPipePair() {
         int a[2];
@@ -100,74 +181,6 @@
     }
 };
 
-static const uint32_t num_buckets = 128;
-static uint64_t max_time_bucket = 50ull * 1000000;
-static uint64_t time_per_bucket = max_time_bucket / num_buckets;
-
-struct ProcResults {
-    uint64_t m_worst = 0;
-    uint32_t m_buckets[num_buckets] = {0};
-    uint64_t m_transactions = 0;
-    uint64_t m_long_transactions = 0;
-    uint64_t m_total_time = 0;
-    uint64_t m_best = max_time_bucket;
-
-    void add_time(uint64_t time) {
-        if (time > max_time_bucket) {
-            m_long_transactions++;
-        }
-        m_buckets[min((uint32_t)(time / time_per_bucket), num_buckets - 1)] += 1;
-        m_best = min(time, m_best);
-        m_worst = max(time, m_worst);
-        m_transactions += 1;
-        m_total_time += time;
-    }
-    static ProcResults combine(const ProcResults& a, const ProcResults& b) {
-        ProcResults ret;
-        for (int i = 0; i < num_buckets; i++) {
-            ret.m_buckets[i] = a.m_buckets[i] + b.m_buckets[i];
-        }
-        ret.m_worst = max(a.m_worst, b.m_worst);
-        ret.m_best = min(a.m_best, b.m_best);
-        ret.m_transactions = a.m_transactions + b.m_transactions;
-        ret.m_long_transactions = a.m_long_transactions + b.m_long_transactions;
-        ret.m_total_time = a.m_total_time + b.m_total_time;
-        return ret;
-    }
-    void dump() {
-        if (m_long_transactions > 0) {
-            cout << (double)m_long_transactions / m_transactions << "% of transactions took longer "
-                "than estimated max latency. Consider setting -m to be higher than "
-                 << m_worst / 1000 << " microseconds" << endl;
-        }
-
-        double best = (double)m_best / 1.0E6;
-        double worst = (double)m_worst / 1.0E6;
-        double average = (double)m_total_time / m_transactions / 1.0E6;
-        cout << "average:" << average << "ms worst:" << worst << "ms best:" << best << "ms" << endl;
-
-        uint64_t cur_total = 0;
-        float time_per_bucket_ms = time_per_bucket / 1.0E6;
-        for (int i = 0; i < num_buckets; i++) {
-            float cur_time = time_per_bucket_ms * i + 0.5f * time_per_bucket_ms;
-            if ((cur_total < 0.5f * m_transactions) && (cur_total + m_buckets[i] >= 0.5f * m_transactions)) {
-                cout << "50%: " << cur_time << " ";
-            }
-            if ((cur_total < 0.9f * m_transactions) && (cur_total + m_buckets[i] >= 0.9f * m_transactions)) {
-                cout << "90%: " << cur_time << " ";
-            }
-            if ((cur_total < 0.95f * m_transactions) && (cur_total + m_buckets[i] >= 0.95f * m_transactions)) {
-                cout << "95%: " << cur_time << " ";
-            }
-            if ((cur_total < 0.99f * m_transactions) && (cur_total + m_buckets[i] >= 0.99f * m_transactions)) {
-                cout << "99%: " << cur_time << " ";
-            }
-            cur_total += m_buckets[i];
-        }
-        cout << endl;
-    }
-};
-
 String16 generateServiceName(int num)
 {
     char num_str[32];
@@ -204,34 +217,37 @@
     for (int i = 0; i < server_count; i++) {
         if (num == i)
             continue;
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wdeprecated-declarations"
-        workers.push_back(serviceMgr->getService(generateServiceName(i)));
-#pragma clang diagnostic pop
+        workers.push_back(serviceMgr->waitForService(generateServiceName(i)));
     }
 
-    // Run the benchmark if client
-    ProcResults results;
+    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);
+            }
         }
     }
 
@@ -289,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();
@@ -305,11 +328,10 @@
     // Collect all results from the workers.
     cout << "collecting results" << endl;
     signal_all(pipes);
-    ProcResults tot_results;
+    ProcResults tot_results(0), tmp_results(0);
     for (int i = 0; i < workers; i++) {
-        ProcResults tmp_results;
         pipes[i].recv(tmp_results);
-        tot_results = ProcResults::combine(tot_results, tmp_results);
+        tot_results.combine_with(tmp_results);
     }
 
     // Kill all the workers.
@@ -323,13 +345,11 @@
         }
     }
     if (training_round) {
-        // sets max_time_bucket to 2 * m_worst from the training round.
-        // Also needs to adjust time_per_bucket accordingly.
-        max_time_bucket = 2 * tot_results.m_worst;
-        time_per_bucket = max_time_bucket / num_buckets;
-        cout << "Max latency during training: " << tot_results.m_worst / 1.0E6 << "ms" << endl;
+        // Sets warn_latency to 2 * worst from the training round.
+        warn_latency = 2 * tot_results.worst();
+        cout << "Max latency during training: " << tot_results.worst() / 1.0E6 << "ms" << endl;
     } else {
-            tot_results.dump();
+        tot_results.dump();
     }
 }
 
@@ -340,8 +360,7 @@
     int payload_size = 0;
     bool cs_pair = false;
     bool training_round = false;
-    (void)argc;
-    (void)argv;
+    int max_time_us;
 
     // Parse arguments.
     for (int i = 1; i < argc; i++) {
@@ -351,46 +370,65 @@
             cout << "\t-m N    : Specify expected max latency in microseconds." << endl;
             cout << "\t-p      : Split workers into client/server pairs." << endl;
             cout << "\t-s N    : Specify payload size." << endl;
-            cout << "\t-t N    : Run training round." << endl;
+            cout << "\t-t      : Run training round." << endl;
             cout << "\t-w N    : Specify total number of workers." << endl;
             return 0;
         }
         if (string(argv[i]) == "-w") {
+            if (i + 1 == argc) {
+                cout << "-w requires an argument\n" << endl;
+                exit(EXIT_FAILURE);
+            }
             workers = atoi(argv[i+1]);
             i++;
             continue;
         }
         if (string(argv[i]) == "-i") {
+            if (i + 1 == argc) {
+                cout << "-i requires an argument\n" << endl;
+                exit(EXIT_FAILURE);
+            }
             iterations = atoi(argv[i+1]);
             i++;
             continue;
         }
         if (string(argv[i]) == "-s") {
+            if (i + 1 == argc) {
+                cout << "-s requires an argument\n" << endl;
+                exit(EXIT_FAILURE);
+            }
             payload_size = atoi(argv[i+1]);
             i++;
+            continue;
         }
         if (string(argv[i]) == "-p") {
             // client/server pairs instead of spreading
             // requests to all workers. If true, half
             // the workers become clients and half servers
             cs_pair = true;
+            continue;
         }
         if (string(argv[i]) == "-t") {
             // Run one training round before actually collecting data
             // to get an approximation of max latency.
             training_round = true;
+            continue;
         }
         if (string(argv[i]) == "-m") {
+            if (i + 1 == argc) {
+                cout << "-m requires an argument\n" << endl;
+                exit(EXIT_FAILURE);
+            }
             // Caller specified the max latency in microseconds.
             // No need to run training round in this case.
-            if (atoi(argv[i+1]) > 0) {
-                max_time_bucket = strtoull(argv[i+1], (char **)nullptr, 10) * 1000;
-                time_per_bucket = max_time_bucket / num_buckets;
-                i++;
-            } else {
+            max_time_us = atoi(argv[i+1]);
+            if (max_time_us <= 0) {
                 cout << "Max latency -m must be positive." << endl;
                 exit(EXIT_FAILURE);
             }
+            warn_latency = max_time_us * 1000ull;
+            i++;
+            continue;
         }
     }
 
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/binder/trusty/rust/rules.mk b/libs/binder/trusty/rust/rules.mk
index 6de7eb5..d343f14 100644
--- a/libs/binder/trusty/rust/rules.mk
+++ b/libs/binder/trusty/rust/rules.mk
@@ -30,6 +30,9 @@
 	external/rust/crates/downcast-rs \
 	trusty/user/base/lib/trusty-sys \
 
+MODULE_RUSTFLAGS += \
+	--cfg 'android_vendor' \
+
 # Trusty does not have `ProcessState`, so there are a few
 # doc links in `IBinder` that are still broken.
 MODULE_RUSTFLAGS += \
diff --git a/libs/dumputils/dump_utils.cpp b/libs/dumputils/dump_utils.cpp
index 5eb3308..f4cf11e 100644
--- a/libs/dumputils/dump_utils.cpp
+++ b/libs/dumputils/dump_utils.cpp
@@ -89,6 +89,9 @@
 
 /* list of hal interface to dump containing process during native dumps */
 static const std::vector<std::string> aidl_interfaces_to_dump {
+        "android.hardware.audio.core.IConfig",
+        "android.hardware.audio.core.IModule",
+        "android.hardware.audio.effect.IFactory",
         "android.hardware.automotive.audiocontrol.IAudioControl",
         "android.hardware.automotive.can.ICanController",
         "android.hardware.automotive.evs.IEvsEnumerator",
diff --git a/libs/input/Android.bp b/libs/input/Android.bp
index 022dfad..a67ed29 100644
--- a/libs/input/Android.bp
+++ b/libs/input/Android.bp
@@ -221,7 +221,7 @@
         "liblog",
         "libPlatformProperties",
         "libtinyxml2",
-        "libvintf",
+        "libz", // needed by libkernelconfigs
     ],
 
     ldflags: [
@@ -238,6 +238,7 @@
         "inputconstants-cpp",
         "libui-types",
         "libtflite_static",
+        "libkernelconfigs",
     ],
 
     whole_static_libs: [
diff --git a/libs/input/InputEventLabels.cpp b/libs/input/InputEventLabels.cpp
index bade686..b25e06c 100644
--- a/libs/input/InputEventLabels.cpp
+++ b/libs/input/InputEventLabels.cpp
@@ -429,7 +429,8 @@
     DEFINE_FLAG(VIRTUAL), \
     DEFINE_FLAG(FUNCTION), \
     DEFINE_FLAG(GESTURE), \
-    DEFINE_FLAG(WAKE)
+    DEFINE_FLAG(WAKE), \
+    DEFINE_FLAG(FALLBACK_USAGE_MAPPING)
 
 // clang-format on
 
diff --git a/libs/input/KeyLayoutMap.cpp b/libs/input/KeyLayoutMap.cpp
index ddc9ea4..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()) {
@@ -250,7 +247,7 @@
 std::vector<int32_t> KeyLayoutMap::findUsageCodesForKey(int32_t keyCode) const {
     std::vector<int32_t> usageCodes;
     for (const auto& [usageCode, key] : mKeysByUsageCode) {
-        if (keyCode == key.keyCode) {
+        if (keyCode == key.keyCode && !(key.flags & POLICY_FLAG_FALLBACK_USAGE_MAPPING)) {
             usageCodes.push_back(usageCode);
         }
     }
diff --git a/libs/input/tests/Android.bp b/libs/input/tests/Android.bp
index e7224ff..3fc7d9d 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",
     ],
     data: [
         "data/*",
diff --git a/libs/input/tests/InputDevice_test.cpp b/libs/input/tests/InputDevice_test.cpp
index ee961f0..5c44366 100644
--- a/libs/input/tests/InputDevice_test.cpp
+++ b/libs/input/tests/InputDevice_test.cpp
@@ -147,6 +147,41 @@
     ASSERT_FALSE(ret.ok()) << "Should not be able to load KeyLayout at " << klPath;
 }
 
+TEST(InputDeviceKeyLayoutTest, HidUsageCodesFallbackMapping) {
+    std::string klPath = base::GetExecutableDirectory() + "/data/hid_fallback_mapping.kl";
+    base::Result<std::shared_ptr<KeyLayoutMap>> ret = KeyLayoutMap::load(klPath);
+    ASSERT_TRUE(ret.ok()) << "Unable to load KeyLayout at " << klPath;
+    const std::shared_ptr<KeyLayoutMap>& keyLayoutMap = *ret;
+
+    static constexpr std::array<int32_t, 5> hidUsageCodesWithoutFallback = {0x0c0067, 0x0c0070,
+                                                                            0x0c006F, 0x0c0079,
+                                                                            0x0c007A};
+    for (int32_t hidUsageCode : hidUsageCodesWithoutFallback) {
+        int32_t outKeyCode;
+        uint32_t outFlags;
+        keyLayoutMap->mapKey(0, hidUsageCode, &outKeyCode, &outFlags);
+        ASSERT_FALSE(outFlags & POLICY_FLAG_FALLBACK_USAGE_MAPPING)
+                << "HID usage code should not be marked as fallback";
+        std::vector<int32_t> usageCodes = keyLayoutMap->findUsageCodesForKey(outKeyCode);
+        ASSERT_NE(std::find(usageCodes.begin(), usageCodes.end(), hidUsageCode), usageCodes.end())
+                << "Fallback usage code should be mapped to key";
+    }
+
+    static constexpr std::array<int32_t, 6> hidUsageCodesWithFallback = {0x0c007C, 0x0c0173,
+                                                                         0x0c019C, 0x0c01A2,
+                                                                         0x0d0044, 0x0d005a};
+    for (int32_t hidUsageCode : hidUsageCodesWithFallback) {
+        int32_t outKeyCode;
+        uint32_t outFlags;
+        keyLayoutMap->mapKey(0, hidUsageCode, &outKeyCode, &outFlags);
+        ASSERT_TRUE(outFlags & POLICY_FLAG_FALLBACK_USAGE_MAPPING)
+                << "HID usage code should be marked as fallback";
+        std::vector<int32_t> usageCodes = keyLayoutMap->findUsageCodesForKey(outKeyCode);
+        ASSERT_EQ(std::find(usageCodes.begin(), usageCodes.end(), hidUsageCode), usageCodes.end())
+                << "Fallback usage code should not be mapped to key";
+    }
+}
+
 TEST(InputDeviceKeyLayoutTest, DoesNotLoadWhenRequiredKernelConfigIsMissing) {
 #if !defined(__ANDROID__)
     GTEST_SKIP() << "Can't check kernel configs on host";
diff --git a/libs/input/tests/data/hid_fallback_mapping.kl b/libs/input/tests/data/hid_fallback_mapping.kl
new file mode 100644
index 0000000..b4ca9ef
--- /dev/null
+++ b/libs/input/tests/data/hid_fallback_mapping.kl
@@ -0,0 +1,32 @@
+# Copyright 2023 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# test key layout file for InputDeviceKeyMapTest#HidUsageCodesUseFallbackMapping
+#
+
+# Keys defined by HID usages without fallback mapping flag
+key usage 0x0c0067 WINDOW
+key usage 0x0c006F BRIGHTNESS_UP
+key usage 0x0c0070 BRIGHTNESS_DOWN
+key usage 0x0c0079 KEYBOARD_BACKLIGHT_UP
+key usage 0x0c007A KEYBOARD_BACKLIGHT_DOWN
+
+# Keys defined by HID usages with fallback mapping flag
+key usage 0x0c007C KEYBOARD_BACKLIGHT_TOGGLE FALLBACK_USAGE_MAPPING
+key usage 0x0c0173 MEDIA_AUDIO_TRACK         FALLBACK_USAGE_MAPPING
+key usage 0x0c019C PROFILE_SWITCH            FALLBACK_USAGE_MAPPING
+key usage 0x0c01A2 ALL_APPS                  FALLBACK_USAGE_MAPPING
+key usage 0x0d0044 STYLUS_BUTTON_PRIMARY     FALLBACK_USAGE_MAPPING
+key usage 0x0d005a STYLUS_BUTTON_SECONDARY   FALLBACK_USAGE_MAPPING
\ No newline at end of file
diff --git a/libs/nativewindow/include/android/data_space.h b/libs/nativewindow/include/android/data_space.h
index eab21fb..9f8ae86 100644
--- a/libs/nativewindow/include/android/data_space.h
+++ b/libs/nativewindow/include/android/data_space.h
@@ -29,6 +29,7 @@
 #define ANDROID_DATA_SPACE_H
 
 #include <inttypes.h>
+#include <stdint.h>
 
 #include <sys/cdefs.h>
 
@@ -37,7 +38,7 @@
 /**
  * ADataSpace.
  */
-enum ADataSpace {
+enum ADataSpace : int32_t {
     /**
      * Default-assumption data space, when not explicitly specified.
      *
diff --git a/libs/nativewindow/include/android/native_window_aidl.h b/libs/nativewindow/include/android/native_window_aidl.h
index 78f7590..ef3d280 100644
--- a/libs/nativewindow/include/android/native_window_aidl.h
+++ b/libs/nativewindow/include/android/native_window_aidl.h
@@ -100,7 +100,7 @@
         if (__builtin_available(android __ANDROID_API_U__, *)) {
             return ANativeWindow_readFromParcel(parcel, &mWindow);
         } else {
-            return STATUS_FAILED_TRANSACTION;
+            return STATUS_INVALID_OPERATION;
         }
     }
 
@@ -111,7 +111,7 @@
         if (__builtin_available(android __ANDROID_API_U__, *)) {
             return ANativeWindow_writeToParcel(mWindow, parcel);
         } else {
-            return STATUS_FAILED_TRANSACTION;
+            return STATUS_INVALID_OPERATION;
         }
     }
 
diff --git a/libs/nativewindow/rust/src/lib.rs b/libs/nativewindow/rust/src/lib.rs
index 6f86c4a..22ad834 100644
--- a/libs/nativewindow/rust/src/lib.rs
+++ b/libs/nativewindow/rust/src/lib.rs
@@ -16,13 +16,13 @@
 
 extern crate nativewindow_bindgen as ffi;
 
+pub mod surface;
+
 pub use ffi::{AHardwareBuffer_Format, AHardwareBuffer_UsageFlags};
 
 use binder::{
-    binder_impl::{
-        BorrowedParcel, Deserialize, DeserializeArray, DeserializeOption, Serialize,
-        SerializeArray, SerializeOption, NON_NULL_PARCELABLE_FLAG, NULL_PARCELABLE_FLAG,
-    },
+    binder_impl::{BorrowedParcel, UnstructuredParcelable},
+    impl_deserialize_for_unstructured_parcelable, impl_serialize_for_unstructured_parcelable,
     unstable_api::{status_result, AsNative},
     StatusCode,
 };
@@ -102,20 +102,35 @@
         }
     }
 
-    /// Adopts the raw pointer and wraps it in a Rust AHardwareBuffer.
-    ///
-    /// # Errors
-    ///
-    /// Will panic if buffer_ptr is null.
+    /// Adopts the given raw pointer and wraps it in a Rust HardwareBuffer.
     ///
     /// # Safety
     ///
-    /// This function adopts the pointer but does NOT increment the refcount on the buffer. If the
-    /// caller uses the pointer after the created object is dropped it will cause a memory leak.
+    /// This function takes ownership of the pointer and does NOT increment the refcount on the
+    /// buffer. If the caller uses the pointer after the created object is dropped it will cause
+    /// undefined behaviour. If the caller wants to continue using the pointer after calling this
+    /// then use [`clone_from_raw`](Self::clone_from_raw) instead.
     pub unsafe fn from_raw(buffer_ptr: NonNull<AHardwareBuffer>) -> Self {
         Self(buffer_ptr)
     }
 
+    /// Creates a new Rust HardwareBuffer to wrap the given AHardwareBuffer without taking ownership
+    /// of it.
+    ///
+    /// Unlike [`from_raw`](Self::from_raw) this method will increment the refcount on the buffer.
+    /// This means that the caller can continue to use the raw buffer it passed in, and must call
+    /// [`AHardwareBuffer_release`](ffi::AHardwareBuffer_release) when it is finished with it to
+    /// avoid a memory leak.
+    ///
+    /// # Safety
+    ///
+    /// The buffer pointer must point to a valid `AHardwareBuffer`.
+    pub unsafe fn clone_from_raw(buffer: NonNull<AHardwareBuffer>) -> Self {
+        // SAFETY: The caller guarantees that the AHardwareBuffer pointer is valid.
+        unsafe { ffi::AHardwareBuffer_acquire(buffer.as_ptr()) };
+        Self(buffer)
+    }
+
     /// Get the internal |AHardwareBuffer| pointer without decrementing the refcount. This can
     /// be used to provide a pointer to the AHB for a C/C++ API over the FFI.
     pub fn into_raw(self) -> NonNull<AHardwareBuffer> {
@@ -197,7 +212,7 @@
 }
 
 impl Debug for HardwareBuffer {
-    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
+    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
         f.debug_struct("HardwareBuffer").field("id", &self.id()).finish()
     }
 }
@@ -210,81 +225,40 @@
     }
 }
 
-impl Serialize for HardwareBuffer {
-    fn serialize(&self, parcel: &mut BorrowedParcel) -> Result<(), StatusCode> {
-        SerializeOption::serialize_option(Some(self), parcel)
+impl UnstructuredParcelable for HardwareBuffer {
+    fn write_to_parcel(&self, parcel: &mut BorrowedParcel) -> Result<(), StatusCode> {
+        let status =
+        // SAFETY: The AHardwareBuffer pointer we pass is guaranteed to be non-null and valid
+        // because it must have been allocated by `AHardwareBuffer_allocate`,
+        // `AHardwareBuffer_readFromParcel` or the caller of `from_raw` and we have not yet
+        // released it.
+            unsafe { AHardwareBuffer_writeToParcel(self.0.as_ptr(), parcel.as_native_mut()) };
+        status_result(status)
+    }
+
+    fn from_parcel(parcel: &BorrowedParcel) -> Result<Self, StatusCode> {
+        let mut buffer = null_mut();
+
+        let status =
+        // SAFETY: Both pointers must be valid because they are obtained from references.
+        // `AHardwareBuffer_readFromParcel` doesn't store them or do anything else special
+        // with them. If it returns success then it will have allocated a new
+        // `AHardwareBuffer` and incremented the reference count, so we can use it until we
+        // release it.
+            unsafe { AHardwareBuffer_readFromParcel(parcel.as_native(), &mut buffer) };
+
+        status_result(status)?;
+
+        Ok(Self(
+            NonNull::new(buffer).expect(
+                "AHardwareBuffer_readFromParcel returned success but didn't allocate buffer",
+            ),
+        ))
     }
 }
 
-impl SerializeOption for HardwareBuffer {
-    fn serialize_option(
-        this: Option<&Self>,
-        parcel: &mut BorrowedParcel,
-    ) -> Result<(), StatusCode> {
-        if let Some(this) = this {
-            parcel.write(&NON_NULL_PARCELABLE_FLAG)?;
-
-            let status =
-            // SAFETY: The AHardwareBuffer pointer we pass is guaranteed to be non-null and valid
-            // because it must have been allocated by `AHardwareBuffer_allocate`,
-            // `AHardwareBuffer_readFromParcel` or the caller of `from_raw` and we have not yet
-            // released it.
-                unsafe { AHardwareBuffer_writeToParcel(this.0.as_ptr(), parcel.as_native_mut()) };
-            status_result(status)
-        } else {
-            parcel.write(&NULL_PARCELABLE_FLAG)
-        }
-    }
-}
-
-impl Deserialize for HardwareBuffer {
-    type UninitType = Option<Self>;
-
-    fn uninit() -> Option<Self> {
-        None
-    }
-
-    fn from_init(value: Self) -> Option<Self> {
-        Some(value)
-    }
-
-    fn deserialize(parcel: &BorrowedParcel) -> Result<Self, StatusCode> {
-        DeserializeOption::deserialize_option(parcel)
-            .transpose()
-            .unwrap_or(Err(StatusCode::UNEXPECTED_NULL))
-    }
-}
-
-impl DeserializeOption for HardwareBuffer {
-    fn deserialize_option(parcel: &BorrowedParcel) -> Result<Option<Self>, StatusCode> {
-        let present: i32 = parcel.read()?;
-        match present {
-            NULL_PARCELABLE_FLAG => Ok(None),
-            NON_NULL_PARCELABLE_FLAG => {
-                let mut buffer = null_mut();
-
-                let status =
-                // SAFETY: Both pointers must be valid because they are obtained from references.
-                // `AHardwareBuffer_readFromParcel` doesn't store them or do anything else special
-                // with them. If it returns success then it will have allocated a new
-                // `AHardwareBuffer` and incremented the reference count, so we can use it until we
-                // release it.
-                    unsafe { AHardwareBuffer_readFromParcel(parcel.as_native(), &mut buffer) };
-
-                status_result(status)?;
-
-                Ok(Some(Self(NonNull::new(buffer).expect(
-                    "AHardwareBuffer_readFromParcel returned success but didn't allocate buffer",
-                ))))
-            }
-            _ => Err(StatusCode::BAD_VALUE),
-        }
-    }
-}
-
-impl SerializeArray for HardwareBuffer {}
-
-impl DeserializeArray for HardwareBuffer {}
+impl_deserialize_for_unstructured_parcelable!(HardwareBuffer);
+impl_serialize_for_unstructured_parcelable!(HardwareBuffer);
 
 // SAFETY: The underlying *AHardwareBuffers can be moved between threads.
 unsafe impl Send for HardwareBuffer {}
diff --git a/libs/nativewindow/rust/src/surface.rs b/libs/nativewindow/rust/src/surface.rs
new file mode 100644
index 0000000..25fea80
--- /dev/null
+++ b/libs/nativewindow/rust/src/surface.rs
@@ -0,0 +1,143 @@
+// Copyright (C) 2024 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//! Rust wrapper for `ANativeWindow` and related types.
+
+use binder::{
+    binder_impl::{BorrowedParcel, UnstructuredParcelable},
+    impl_deserialize_for_unstructured_parcelable, impl_serialize_for_unstructured_parcelable,
+    unstable_api::{status_result, AsNative},
+    StatusCode,
+};
+use nativewindow_bindgen::{
+    AHardwareBuffer_Format, ANativeWindow, ANativeWindow_acquire, ANativeWindow_getFormat,
+    ANativeWindow_getHeight, ANativeWindow_getWidth, ANativeWindow_readFromParcel,
+    ANativeWindow_release, ANativeWindow_writeToParcel,
+};
+use std::error::Error;
+use std::fmt::{self, Debug, Display, Formatter};
+use std::ptr::{null_mut, NonNull};
+
+/// Wrapper around an opaque C `ANativeWindow`.
+#[derive(PartialEq, Eq)]
+pub struct Surface(NonNull<ANativeWindow>);
+
+impl Surface {
+    /// Returns the current width in pixels of the window surface.
+    pub fn width(&self) -> Result<u32, ErrorCode> {
+        // SAFETY: The ANativeWindow pointer we pass is guaranteed to be non-null and valid because
+        // it must have been allocated by `ANativeWindow_allocate` or `ANativeWindow_readFromParcel`
+        // and we have not yet released it.
+        let width = unsafe { ANativeWindow_getWidth(self.0.as_ptr()) };
+        width.try_into().map_err(|_| ErrorCode(width))
+    }
+
+    /// Returns the current height in pixels of the window surface.
+    pub fn height(&self) -> Result<u32, ErrorCode> {
+        // SAFETY: The ANativeWindow pointer we pass is guaranteed to be non-null and valid because
+        // it must have been allocated by `ANativeWindow_allocate` or `ANativeWindow_readFromParcel`
+        // and we have not yet released it.
+        let height = unsafe { ANativeWindow_getHeight(self.0.as_ptr()) };
+        height.try_into().map_err(|_| ErrorCode(height))
+    }
+
+    /// Returns the current pixel format of the window surface.
+    pub fn format(&self) -> Result<AHardwareBuffer_Format::Type, ErrorCode> {
+        // SAFETY: The ANativeWindow pointer we pass is guaranteed to be non-null and valid because
+        // it must have been allocated by `ANativeWindow_allocate` or `ANativeWindow_readFromParcel`
+        // and we have not yet released it.
+        let format = unsafe { ANativeWindow_getFormat(self.0.as_ptr()) };
+        format.try_into().map_err(|_| ErrorCode(format))
+    }
+}
+
+impl Drop for Surface {
+    fn drop(&mut self) {
+        // SAFETY: The ANativeWindow pointer we pass is guaranteed to be non-null and valid because
+        // it must have been allocated by `ANativeWindow_allocate` or `ANativeWindow_readFromParcel`
+        // and we have not yet released it.
+        unsafe { ANativeWindow_release(self.0.as_ptr()) }
+    }
+}
+
+impl Debug for Surface {
+    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
+        f.debug_struct("Surface")
+            .field("width", &self.width())
+            .field("height", &self.height())
+            .field("format", &self.format())
+            .finish()
+    }
+}
+
+impl Clone for Surface {
+    fn clone(&self) -> Self {
+        // SAFETY: The ANativeWindow pointer we pass is guaranteed to be non-null and valid because
+        // it must have been allocated by `ANativeWindow_allocate` or `ANativeWindow_readFromParcel`
+        // and we have not yet released it.
+        unsafe { ANativeWindow_acquire(self.0.as_ptr()) };
+        Self(self.0)
+    }
+}
+
+impl UnstructuredParcelable for Surface {
+    fn write_to_parcel(&self, parcel: &mut BorrowedParcel) -> Result<(), StatusCode> {
+        let status =
+        // SAFETY: The ANativeWindow pointer we pass is guaranteed to be non-null and valid because
+        // it must have been allocated by `ANativeWindow_allocate` or `ANativeWindow_readFromParcel`
+        // and we have not yet released it.
+        unsafe { ANativeWindow_writeToParcel(self.0.as_ptr(), parcel.as_native_mut()) };
+        status_result(status)
+    }
+
+    fn from_parcel(parcel: &BorrowedParcel) -> Result<Self, StatusCode> {
+        let mut buffer = null_mut();
+
+        let status =
+        // SAFETY: Both pointers must be valid because they are obtained from references.
+        // `ANativeWindow_readFromParcel` doesn't store them or do anything else special
+        // with them. If it returns success then it will have allocated a new
+        // `ANativeWindow` and incremented the reference count, so we can use it until we
+        // release it.
+            unsafe { ANativeWindow_readFromParcel(parcel.as_native(), &mut buffer) };
+
+        status_result(status)?;
+
+        Ok(Self(
+            NonNull::new(buffer)
+                .expect("ANativeWindow_readFromParcel returned success but didn't allocate buffer"),
+        ))
+    }
+}
+
+impl_deserialize_for_unstructured_parcelable!(Surface);
+impl_serialize_for_unstructured_parcelable!(Surface);
+
+// SAFETY: The underlying *ANativeWindow can be moved between threads.
+unsafe impl Send for Surface {}
+
+// SAFETY: The underlying *ANativeWindow can be used from multiple threads concurrently.
+unsafe impl Sync for Surface {}
+
+/// An error code returned by methods on [`Surface`].
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+pub struct ErrorCode(i32);
+
+impl Error for ErrorCode {}
+
+impl Display for ErrorCode {
+    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
+        write!(f, "Error {}", self.0)
+    }
+}
diff --git a/libs/nativewindow/rust/sys/nativewindow_bindings.h b/libs/nativewindow/rust/sys/nativewindow_bindings.h
index 4525a42..5689f7d 100644
--- a/libs/nativewindow/rust/sys/nativewindow_bindings.h
+++ b/libs/nativewindow/rust/sys/nativewindow_bindings.h
@@ -19,3 +19,4 @@
 #include <android/hardware_buffer_aidl.h>
 #include <android/hdr_metadata.h>
 #include <android/native_window.h>
+#include <android/native_window_aidl.h>
diff --git a/libs/renderengine/skia/SkiaRenderEngine.cpp b/libs/renderengine/skia/SkiaRenderEngine.cpp
index d71e55f..a733fd0 100644
--- a/libs/renderengine/skia/SkiaRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaRenderEngine.cpp
@@ -1022,7 +1022,7 @@
                                                   .fakeOutputDataspace = fakeDataspace}));
 
             // Turn on dithering when dimming beyond this (arbitrary) threshold...
-            static constexpr float kDimmingThreshold = 0.2f;
+            static constexpr float kDimmingThreshold = 0.9f;
             // ...or we're rendering an HDR layer down to an 8-bit target
             // Most HDR standards require at least 10-bits of color depth for source content, so we
             // can just extract the transfer function rather than dig into precise gralloc layout.
diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp
index dc7c75a..84b6fa9 100644
--- a/services/inputflinger/Android.bp
+++ b/services/inputflinger/Android.bp
@@ -84,6 +84,8 @@
         "libprotobuf-cpp-lite",
         "libstatslog",
         "libutils",
+        "libstatspull",
+        "libstatssocket",
         "server_configurable_flags",
     ],
     static_libs: [
@@ -96,15 +98,11 @@
             shared_libs: [
                 "libgui",
                 "libinput",
-                "libstatspull",
-                "libstatssocket",
             ],
         },
         host: {
             static_libs: [
                 "libinput",
-                "libstatspull",
-                "libstatssocket",
             ],
             include_dirs: [
                 "bionic/libc/kernel/android/uapi/",
diff --git a/services/inputflinger/dispatcher/Android.bp b/services/inputflinger/dispatcher/Android.bp
index 492551e..7fa33f6 100644
--- a/services/inputflinger/dispatcher/Android.bp
+++ b/services/inputflinger/dispatcher/Android.bp
@@ -64,6 +64,8 @@
         "libprotobuf-cpp-lite",
         "libstatslog",
         "libutils",
+        "libstatspull",
+        "libstatssocket",
         "server_configurable_flags",
     ],
     static_libs: [
@@ -75,15 +77,11 @@
             shared_libs: [
                 "libgui",
                 "libinput",
-                "libstatspull",
-                "libstatssocket",
             ],
         },
         host: {
             static_libs: [
                 "libinput",
-                "libstatspull",
-                "libstatssocket",
             ],
         },
     },
diff --git a/services/inputflinger/reader/Android.bp b/services/inputflinger/reader/Android.bp
index ccb8773..1ae36e7 100644
--- a/services/inputflinger/reader/Android.bp
+++ b/services/inputflinger/reader/Android.bp
@@ -82,6 +82,7 @@
         "liblog",
         "libPlatformProperties",
         "libstatslog",
+        "libstatspull",
         "libutils",
     ],
     static_libs: [
@@ -98,14 +99,12 @@
         android: {
             shared_libs: [
                 "libinput",
-                "libstatspull",
             ],
         },
         host: {
             static_libs: [
                 "libinput",
                 "libbinder",
-                "libstatspull",
             ],
         },
     },
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index 9e0e7b5..bf2d568 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -3403,7 +3403,6 @@
     static const mat4 kDefaultColorTransformMat;
 
     static const Region kDebugRegion;
-    static const compositionengine::CompositionRefreshArgs kDefaultRefreshArgs;
     static const HdrCapabilities kHdrCapabilities;
 
     StrictMock<mock::CompositionEngine> mCompositionEngine;
@@ -3426,7 +3425,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/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