Merge "Add test for simultaneous mouse and touch with transfer" into main
diff --git a/aidl/binder/android/os/PersistableBundle.aidl b/aidl/binder/android/os/PersistableBundle.aidl
index 248e973..9b11109 100644
--- a/aidl/binder/android/os/PersistableBundle.aidl
+++ b/aidl/binder/android/os/PersistableBundle.aidl
@@ -17,4 +17,4 @@
 
 package android.os;
 
-@JavaOnlyStableParcelable @NdkOnlyStableParcelable parcelable PersistableBundle cpp_header "binder/PersistableBundle.h" ndk_header "android/persistable_bundle_aidl.h";
+@JavaOnlyStableParcelable @NdkOnlyStableParcelable @RustOnlyStableParcelable parcelable PersistableBundle cpp_header "binder/PersistableBundle.h" ndk_header "android/persistable_bundle_aidl.h" rust_type "binder::PersistableBundle";
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 4486bd6..db56551 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -119,7 +119,6 @@
  */
 static constexpr const char* kAppDataIsolationEnabledProperty = "persist.zygote.app_data_isolation";
 static constexpr const char* kMntSdcardfs = "/mnt/runtime/default/";
-static constexpr const char* kMntFuse = "/mnt/pass_through/0/";
 
 static std::atomic<bool> sAppDataIsolationEnabled(false);
 
@@ -3697,7 +3696,9 @@
         std::getline(in, ignored);
 
         if (android::base::GetBoolProperty(kFuseProp, false)) {
-            if (target.find(kMntFuse) == 0) {
+            const std::regex kMntFuseRe =
+                    std::regex(R"(^/mnt/pass_through/(0|[0-9]+/[A-Z0-9]{4}-[A-Z0-9]{4}).*)");
+            if (std::regex_match(target, kMntFuseRe)) {
                 LOG(DEBUG) << "Found storage mount " << source << " at " << target;
                 mStorageMounts[source] = target;
             }
diff --git a/libs/binder/rust/src/lib.rs b/libs/binder/rust/src/lib.rs
index e08a763..77b80fe 100644
--- a/libs/binder/rust/src/lib.rs
+++ b/libs/binder/rust/src/lib.rs
@@ -99,6 +99,8 @@
 mod error;
 mod native;
 mod parcel;
+#[cfg(not(trusty))]
+mod persistable_bundle;
 mod proxy;
 #[cfg(not(any(trusty, android_ndk)))]
 mod service;
@@ -113,6 +115,8 @@
 pub use binder::{BinderFeatures, FromIBinder, IBinder, Interface, Strong, Weak};
 pub use error::{ExceptionCode, IntoBinderResult, Status, StatusCode};
 pub use parcel::{ParcelFileDescriptor, Parcelable, ParcelableHolder};
+#[cfg(not(trusty))]
+pub use persistable_bundle::PersistableBundle;
 pub use proxy::{DeathRecipient, SpIBinder, WpIBinder};
 #[cfg(not(any(trusty, android_ndk)))]
 pub use service::{
diff --git a/libs/binder/rust/src/persistable_bundle.rs b/libs/binder/rust/src/persistable_bundle.rs
new file mode 100644
index 0000000..367f334
--- /dev/null
+++ b/libs/binder/rust/src/persistable_bundle.rs
@@ -0,0 +1,583 @@
+/*
+ * Copyright (C) 2025 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.
+ */
+
+use crate::{
+    binder::AsNative,
+    error::{status_result, StatusCode},
+    impl_deserialize_for_unstructured_parcelable, impl_serialize_for_unstructured_parcelable,
+    parcel::{BorrowedParcel, UnstructuredParcelable},
+};
+use binder_ndk_sys::{
+    APersistableBundle, APersistableBundle_delete, APersistableBundle_dup,
+    APersistableBundle_erase, APersistableBundle_getBoolean, APersistableBundle_getDouble,
+    APersistableBundle_getInt, APersistableBundle_getLong, APersistableBundle_getPersistableBundle,
+    APersistableBundle_isEqual, APersistableBundle_new, APersistableBundle_putBoolean,
+    APersistableBundle_putBooleanVector, APersistableBundle_putDouble,
+    APersistableBundle_putDoubleVector, APersistableBundle_putInt, APersistableBundle_putIntVector,
+    APersistableBundle_putLong, APersistableBundle_putLongVector,
+    APersistableBundle_putPersistableBundle, APersistableBundle_putString,
+    APersistableBundle_putStringVector, APersistableBundle_readFromParcel, APersistableBundle_size,
+    APersistableBundle_writeToParcel,
+};
+use std::ffi::{CString, NulError};
+use std::ptr::{null_mut, NonNull};
+
+/// A mapping from string keys to values of various types.
+#[derive(Debug)]
+pub struct PersistableBundle(NonNull<APersistableBundle>);
+
+impl PersistableBundle {
+    /// Creates a new `PersistableBundle`.
+    pub fn new() -> Self {
+        // SAFETY: APersistableBundle_new doesn't actually have any safety requirements.
+        let bundle = unsafe { APersistableBundle_new() };
+        Self(NonNull::new(bundle).expect("Allocated APersistableBundle was null"))
+    }
+
+    /// Returns the number of mappings in the bundle.
+    pub fn size(&self) -> usize {
+        // SAFETY: The wrapped `APersistableBundle` pointer is guaranteed to be valid for the
+        // lifetime of the `PersistableBundle`.
+        unsafe { APersistableBundle_size(self.0.as_ptr()) }
+            .try_into()
+            .expect("APersistableBundle_size returned a negative size")
+    }
+
+    /// Removes any entry with the given key.
+    ///
+    /// Returns an error if the given key contains a NUL character, otherwise returns whether there
+    /// was any entry to remove.
+    pub fn remove(&mut self, key: &str) -> Result<bool, NulError> {
+        let key = CString::new(key)?;
+        // SAFETY: The wrapped `APersistableBundle` pointer is guaranteed to be valid for the
+        // lifetime of the `PersistableBundle`. The pointer returned by `key.as_ptr()` is guaranteed
+        // to be valid for the duration of this call.
+        Ok(unsafe { APersistableBundle_erase(self.0.as_ptr(), key.as_ptr()) != 0 })
+    }
+
+    /// Inserts a key-value pair into the bundle.
+    ///
+    /// If the key is already present then its value will be overwritten by the given value.
+    ///
+    /// Returns an error if the key contains a NUL character.
+    pub fn insert_bool(&mut self, key: &str, value: bool) -> Result<(), NulError> {
+        let key = CString::new(key)?;
+        // SAFETY: The wrapped `APersistableBundle` pointer is guaranteed to be valid for the
+        // lifetime of the `PersistableBundle`. The pointer returned by `key.as_ptr()` is guaranteed
+        // to be valid for the duration of this call.
+        unsafe {
+            APersistableBundle_putBoolean(self.0.as_ptr(), key.as_ptr(), value);
+        }
+        Ok(())
+    }
+
+    /// Inserts a key-value pair into the bundle.
+    ///
+    /// If the key is already present then its value will be overwritten by the given value.
+    ///
+    /// Returns an error if the key contains a NUL character.
+    pub fn insert_int(&mut self, key: &str, value: i32) -> Result<(), NulError> {
+        let key = CString::new(key)?;
+        // SAFETY: The wrapped `APersistableBundle` pointer is guaranteed to be valid for the
+        // lifetime of the `PersistableBundle`. The pointer returned by `key.as_ptr()` is guaranteed
+        // to be valid for the duration of this call.
+        unsafe {
+            APersistableBundle_putInt(self.0.as_ptr(), key.as_ptr(), value);
+        }
+        Ok(())
+    }
+
+    /// Inserts a key-value pair into the bundle.
+    ///
+    /// If the key is already present then its value will be overwritten by the given value.
+    ///
+    /// Returns an error if the key contains a NUL character.
+    pub fn insert_long(&mut self, key: &str, value: i64) -> Result<(), NulError> {
+        let key = CString::new(key)?;
+        // SAFETY: The wrapped `APersistableBundle` pointer is guaranteed to be valid for the
+        // lifetime of the `PersistableBundle`. The pointer returned by `key.as_ptr()` is guaranteed
+        // to be valid for the duration of this call.
+        unsafe {
+            APersistableBundle_putLong(self.0.as_ptr(), key.as_ptr(), value);
+        }
+        Ok(())
+    }
+
+    /// Inserts a key-value pair into the bundle.
+    ///
+    /// If the key is already present then its value will be overwritten by the given value.
+    ///
+    /// Returns an error if the key contains a NUL character.
+    pub fn insert_double(&mut self, key: &str, value: f64) -> Result<(), NulError> {
+        let key = CString::new(key)?;
+        // SAFETY: The wrapped `APersistableBundle` pointer is guaranteed to be valid for the
+        // lifetime of the `PersistableBundle`. The pointer returned by `key.as_ptr()` is guaranteed
+        // to be valid for the duration of this call.
+        unsafe {
+            APersistableBundle_putDouble(self.0.as_ptr(), key.as_ptr(), value);
+        }
+        Ok(())
+    }
+
+    /// Inserts a key-value pair into the bundle.
+    ///
+    /// If the key is already present then its value will be overwritten by the given value.
+    ///
+    /// Returns an error if the key or value contains a NUL character.
+    pub fn insert_string(&mut self, key: &str, value: &str) -> Result<(), NulError> {
+        let key = CString::new(key)?;
+        let value = CString::new(value)?;
+        // SAFETY: The wrapped `APersistableBundle` pointer is guaranteed to be valid for the
+        // lifetime of the `PersistableBundle`. The pointer returned by `CStr::as_ptr` is guaranteed
+        // to be valid for the duration of this call.
+        unsafe {
+            APersistableBundle_putString(self.0.as_ptr(), key.as_ptr(), value.as_ptr());
+        }
+        Ok(())
+    }
+
+    /// Inserts a key-value pair into the bundle.
+    ///
+    /// If the key is already present then its value will be overwritten by the given value.
+    ///
+    /// Returns an error if the key contains a NUL character.
+    pub fn insert_bool_vec(&mut self, key: &str, value: &[bool]) -> Result<(), NulError> {
+        let key = CString::new(key)?;
+        // SAFETY: The wrapped `APersistableBundle` pointer is guaranteed to be valid for the
+        // lifetime of the `PersistableBundle`. The pointer returned by `key.as_ptr()` is guaranteed
+        // to be valid for the duration of this call, and likewise the pointer returned by
+        // `value.as_ptr()` is guaranteed to be valid for at least `value.len()` values for the
+        // duration of the call.
+        unsafe {
+            APersistableBundle_putBooleanVector(
+                self.0.as_ptr(),
+                key.as_ptr(),
+                value.as_ptr(),
+                value.len().try_into().unwrap(),
+            );
+        }
+        Ok(())
+    }
+
+    /// Inserts a key-value pair into the bundle.
+    ///
+    /// If the key is already present then its value will be overwritten by the given value.
+    ///
+    /// Returns an error if the key contains a NUL character.
+    pub fn insert_int_vec(&mut self, key: &str, value: &[i32]) -> Result<(), NulError> {
+        let key = CString::new(key)?;
+        // SAFETY: The wrapped `APersistableBundle` pointer is guaranteed to be valid for the
+        // lifetime of the `PersistableBundle`. The pointer returned by `key.as_ptr()` is guaranteed
+        // to be valid for the duration of this call, and likewise the pointer returned by
+        // `value.as_ptr()` is guaranteed to be valid for at least `value.len()` values for the
+        // duration of the call.
+        unsafe {
+            APersistableBundle_putIntVector(
+                self.0.as_ptr(),
+                key.as_ptr(),
+                value.as_ptr(),
+                value.len().try_into().unwrap(),
+            );
+        }
+        Ok(())
+    }
+
+    /// Inserts a key-value pair into the bundle.
+    ///
+    /// If the key is already present then its value will be overwritten by the given value.
+    ///
+    /// Returns an error if the key contains a NUL character.
+    pub fn insert_long_vec(&mut self, key: &str, value: &[i64]) -> Result<(), NulError> {
+        let key = CString::new(key)?;
+        // SAFETY: The wrapped `APersistableBundle` pointer is guaranteed to be valid for the
+        // lifetime of the `PersistableBundle`. The pointer returned by `key.as_ptr()` is guaranteed
+        // to be valid for the duration of this call, and likewise the pointer returned by
+        // `value.as_ptr()` is guaranteed to be valid for at least `value.len()` values for the
+        // duration of the call.
+        unsafe {
+            APersistableBundle_putLongVector(
+                self.0.as_ptr(),
+                key.as_ptr(),
+                value.as_ptr(),
+                value.len().try_into().unwrap(),
+            );
+        }
+        Ok(())
+    }
+
+    /// Inserts a key-value pair into the bundle.
+    ///
+    /// If the key is already present then its value will be overwritten by the given value.
+    ///
+    /// Returns an error if the key contains a NUL character.
+    pub fn insert_double_vec(&mut self, key: &str, value: &[f64]) -> Result<(), NulError> {
+        let key = CString::new(key)?;
+        // SAFETY: The wrapped `APersistableBundle` pointer is guaranteed to be valid for the
+        // lifetime of the `PersistableBundle`. The pointer returned by `key.as_ptr()` is guaranteed
+        // to be valid for the duration of this call, and likewise the pointer returned by
+        // `value.as_ptr()` is guaranteed to be valid for at least `value.len()` values for the
+        // duration of the call.
+        unsafe {
+            APersistableBundle_putDoubleVector(
+                self.0.as_ptr(),
+                key.as_ptr(),
+                value.as_ptr(),
+                value.len().try_into().unwrap(),
+            );
+        }
+        Ok(())
+    }
+
+    /// Inserts a key-value pair into the bundle.
+    ///
+    /// If the key is already present then its value will be overwritten by the given value.
+    ///
+    /// Returns an error if the key contains a NUL character.
+    pub fn insert_string_vec<'a, T: ToString + 'a>(
+        &mut self,
+        key: &str,
+        value: impl IntoIterator<Item = &'a T>,
+    ) -> Result<(), NulError> {
+        let key = CString::new(key)?;
+        // We need to collect the new `CString`s into something first so that they live long enough
+        // for their pointers to be valid for the `APersistableBundle_putStringVector` call below.
+        let c_strings = value
+            .into_iter()
+            .map(|s| CString::new(s.to_string()))
+            .collect::<Result<Vec<_>, NulError>>()?;
+        let char_pointers = c_strings.iter().map(|s| s.as_ptr()).collect::<Vec<_>>();
+        // SAFETY: The wrapped `APersistableBundle` pointer is guaranteed to be valid for the
+        // lifetime of the `PersistableBundle`. The pointer returned by `key.as_ptr()` is guaranteed
+        // to be valid for the duration of this call, and likewise the pointer returned by
+        // `value.as_ptr()` is guaranteed to be valid for at least `value.len()` values for the
+        // duration of the call.
+        unsafe {
+            APersistableBundle_putStringVector(
+                self.0.as_ptr(),
+                key.as_ptr(),
+                char_pointers.as_ptr(),
+                char_pointers.len().try_into().unwrap(),
+            );
+        }
+        Ok(())
+    }
+
+    /// Inserts a key-value pair into the bundle.
+    ///
+    /// If the key is already present then its value will be overwritten by the given value.
+    ///
+    /// Returns an error if the key contains a NUL character.
+    pub fn insert_persistable_bundle(
+        &mut self,
+        key: &str,
+        value: &PersistableBundle,
+    ) -> Result<(), NulError> {
+        let key = CString::new(key)?;
+        // SAFETY: The wrapped `APersistableBundle` pointers are guaranteed to be valid for the
+        // lifetime of the `PersistableBundle`s. The pointer returned by `CStr::as_ptr` is
+        // guaranteed to be valid for the duration of this call, and
+        // `APersistableBundle_putPersistableBundle` does a deep copy so that is all that is
+        // required.
+        unsafe {
+            APersistableBundle_putPersistableBundle(
+                self.0.as_ptr(),
+                key.as_ptr(),
+                value.0.as_ptr(),
+            );
+        }
+        Ok(())
+    }
+
+    /// Gets the boolean value associated with the given key.
+    ///
+    /// Returns an error if the key contains a NUL character, or `Ok(None)` if the key doesn't exist
+    /// in the bundle.
+    pub fn get_bool(&self, key: &str) -> Result<Option<bool>, NulError> {
+        let key = CString::new(key)?;
+        let mut value = false;
+        // SAFETY: The wrapped `APersistableBundle` pointer is guaranteed to be valid for the
+        // lifetime of the `PersistableBundle`. The pointer returned by `key.as_ptr()` is guaranteed
+        // to be valid for the duration of this call. The value pointer must be valid because it
+        // comes from a reference.
+        if unsafe { APersistableBundle_getBoolean(self.0.as_ptr(), key.as_ptr(), &mut value) } {
+            Ok(Some(value))
+        } else {
+            Ok(None)
+        }
+    }
+
+    /// Gets the i32 value associated with the given key.
+    ///
+    /// Returns an error if the key contains a NUL character, or `Ok(None)` if the key doesn't exist
+    /// in the bundle.
+    pub fn get_int(&self, key: &str) -> Result<Option<i32>, NulError> {
+        let key = CString::new(key)?;
+        let mut value = 0;
+        // SAFETY: The wrapped `APersistableBundle` pointer is guaranteed to be valid for the
+        // lifetime of the `PersistableBundle`. The pointer returned by `key.as_ptr()` is guaranteed
+        // to be valid for the duration of this call. The value pointer must be valid because it
+        // comes from a reference.
+        if unsafe { APersistableBundle_getInt(self.0.as_ptr(), key.as_ptr(), &mut value) } {
+            Ok(Some(value))
+        } else {
+            Ok(None)
+        }
+    }
+
+    /// Gets the i64 value associated with the given key.
+    ///
+    /// Returns an error if the key contains a NUL character, or `Ok(None)` if the key doesn't exist
+    /// in the bundle.
+    pub fn get_long(&self, key: &str) -> Result<Option<i64>, NulError> {
+        let key = CString::new(key)?;
+        let mut value = 0;
+        // SAFETY: The wrapped `APersistableBundle` pointer is guaranteed to be valid for the
+        // lifetime of the `PersistableBundle`. The pointer returned by `key.as_ptr()` is guaranteed
+        // to be valid for the duration of this call. The value pointer must be valid because it
+        // comes from a reference.
+        if unsafe { APersistableBundle_getLong(self.0.as_ptr(), key.as_ptr(), &mut value) } {
+            Ok(Some(value))
+        } else {
+            Ok(None)
+        }
+    }
+
+    /// Gets the f64 value associated with the given key.
+    ///
+    /// Returns an error if the key contains a NUL character, or `Ok(None)` if the key doesn't exist
+    /// in the bundle.
+    pub fn get_double(&self, key: &str) -> Result<Option<f64>, NulError> {
+        let key = CString::new(key)?;
+        let mut value = 0.0;
+        // SAFETY: The wrapped `APersistableBundle` pointer is guaranteed to be valid for the
+        // lifetime of the `PersistableBundle`. The pointer returned by `key.as_ptr()` is guaranteed
+        // to be valid for the duration of this call. The value pointer must be valid because it
+        // comes from a reference.
+        if unsafe { APersistableBundle_getDouble(self.0.as_ptr(), key.as_ptr(), &mut value) } {
+            Ok(Some(value))
+        } else {
+            Ok(None)
+        }
+    }
+
+    /// Gets the `PersistableBundle` value associated with the given key.
+    ///
+    /// Returns an error if the key contains a NUL character, or `Ok(None)` if the key doesn't exist
+    /// in the bundle.
+    pub fn get_persistable_bundle(&self, key: &str) -> Result<Option<Self>, NulError> {
+        let key = CString::new(key)?;
+        let mut value = null_mut();
+        // SAFETY: The wrapped `APersistableBundle` pointer is guaranteed to be valid for the
+        // lifetime of the `PersistableBundle`. The pointer returned by `key.as_ptr()` is guaranteed
+        // to be valid for the lifetime of `key`. The value pointer must be valid because it comes
+        // from a reference.
+        if unsafe {
+            APersistableBundle_getPersistableBundle(self.0.as_ptr(), key.as_ptr(), &mut value)
+        } {
+            Ok(Some(Self(NonNull::new(value).expect(
+                "APersistableBundle_getPersistableBundle returned true but didn't set outBundle",
+            ))))
+        } else {
+            Ok(None)
+        }
+    }
+}
+
+// SAFETY: The underlying *APersistableBundle can be moved between threads.
+unsafe impl Send for PersistableBundle {}
+
+// SAFETY: The underlying *APersistableBundle can be read from multiple threads, and we require
+// `&mut PersistableBundle` for any operations which mutate it.
+unsafe impl Sync for PersistableBundle {}
+
+impl Default for PersistableBundle {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+impl Drop for PersistableBundle {
+    fn drop(&mut self) {
+        // SAFETY: The wrapped `APersistableBundle` pointer is guaranteed to be valid for the
+        // lifetime of this `PersistableBundle`.
+        unsafe { APersistableBundle_delete(self.0.as_ptr()) };
+    }
+}
+
+impl Clone for PersistableBundle {
+    fn clone(&self) -> Self {
+        // SAFETY: The wrapped `APersistableBundle` pointer is guaranteed to be valid for the
+        // lifetime of the `PersistableBundle`.
+        let duplicate = unsafe { APersistableBundle_dup(self.0.as_ptr()) };
+        Self(NonNull::new(duplicate).expect("Duplicated APersistableBundle was null"))
+    }
+}
+
+impl PartialEq for PersistableBundle {
+    fn eq(&self, other: &Self) -> bool {
+        // SAFETY: The wrapped `APersistableBundle` pointers are guaranteed to be valid for the
+        // lifetime of the `PersistableBundle`s.
+        unsafe { APersistableBundle_isEqual(self.0.as_ptr(), other.0.as_ptr()) }
+    }
+}
+
+impl UnstructuredParcelable for PersistableBundle {
+    fn write_to_parcel(&self, parcel: &mut BorrowedParcel) -> Result<(), StatusCode> {
+        let status =
+        // SAFETY: The wrapped `APersistableBundle` pointer is guaranteed to be valid for the
+        // lifetime of the `PersistableBundle`. `parcel.as_native_mut()` always returns a valid
+        // parcel pointer.
+            unsafe { APersistableBundle_writeToParcel(self.0.as_ptr(), parcel.as_native_mut()) };
+        status_result(status)
+    }
+
+    fn from_parcel(parcel: &BorrowedParcel) -> Result<Self, StatusCode> {
+        let mut bundle = null_mut();
+
+        // SAFETY: The wrapped `APersistableBundle` pointer is guaranteed to be valid for the
+        // lifetime of the `PersistableBundle`. `parcel.as_native()` always returns a valid parcel
+        // pointer.
+        let status = unsafe { APersistableBundle_readFromParcel(parcel.as_native(), &mut bundle) };
+        status_result(status)?;
+
+        Ok(Self(NonNull::new(bundle).expect(
+            "APersistableBundle_readFromParcel returned success but didn't allocate bundle",
+        )))
+    }
+}
+
+impl_deserialize_for_unstructured_parcelable!(PersistableBundle);
+impl_serialize_for_unstructured_parcelable!(PersistableBundle);
+
+#[cfg(test)]
+mod test {
+    use super::*;
+
+    #[test]
+    fn create_delete() {
+        let bundle = PersistableBundle::new();
+        drop(bundle);
+    }
+
+    #[test]
+    fn duplicate_equal() {
+        let bundle = PersistableBundle::new();
+        let duplicate = bundle.clone();
+        assert_eq!(bundle, duplicate);
+    }
+
+    #[test]
+    fn get_empty() {
+        let bundle = PersistableBundle::new();
+        assert_eq!(bundle.get_bool("foo"), Ok(None));
+        assert_eq!(bundle.get_int("foo"), Ok(None));
+        assert_eq!(bundle.get_long("foo"), Ok(None));
+        assert_eq!(bundle.get_double("foo"), Ok(None));
+    }
+
+    #[test]
+    fn remove_empty() {
+        let mut bundle = PersistableBundle::new();
+        assert_eq!(bundle.remove("foo"), Ok(false));
+    }
+
+    #[test]
+    fn insert_get_primitives() {
+        let mut bundle = PersistableBundle::new();
+
+        assert_eq!(bundle.insert_bool("bool", true), Ok(()));
+        assert_eq!(bundle.insert_int("int", 42), Ok(()));
+        assert_eq!(bundle.insert_long("long", 66), Ok(()));
+        assert_eq!(bundle.insert_double("double", 123.4), Ok(()));
+
+        assert_eq!(bundle.get_bool("bool"), Ok(Some(true)));
+        assert_eq!(bundle.get_int("int"), Ok(Some(42)));
+        assert_eq!(bundle.get_long("long"), Ok(Some(66)));
+        assert_eq!(bundle.get_double("double"), Ok(Some(123.4)));
+        assert_eq!(bundle.size(), 4);
+
+        // Getting the wrong type should return nothing.
+        assert_eq!(bundle.get_int("bool"), Ok(None));
+        assert_eq!(bundle.get_long("bool"), Ok(None));
+        assert_eq!(bundle.get_double("bool"), Ok(None));
+        assert_eq!(bundle.get_bool("int"), Ok(None));
+        assert_eq!(bundle.get_long("int"), Ok(None));
+        assert_eq!(bundle.get_double("int"), Ok(None));
+        assert_eq!(bundle.get_bool("long"), Ok(None));
+        assert_eq!(bundle.get_int("long"), Ok(None));
+        assert_eq!(bundle.get_double("long"), Ok(None));
+        assert_eq!(bundle.get_bool("double"), Ok(None));
+        assert_eq!(bundle.get_int("double"), Ok(None));
+        assert_eq!(bundle.get_long("double"), Ok(None));
+
+        // If they are removed they should no longer be present.
+        assert_eq!(bundle.remove("bool"), Ok(true));
+        assert_eq!(bundle.remove("int"), Ok(true));
+        assert_eq!(bundle.remove("long"), Ok(true));
+        assert_eq!(bundle.remove("double"), Ok(true));
+        assert_eq!(bundle.get_bool("bool"), Ok(None));
+        assert_eq!(bundle.get_int("int"), Ok(None));
+        assert_eq!(bundle.get_long("long"), Ok(None));
+        assert_eq!(bundle.get_double("double"), Ok(None));
+        assert_eq!(bundle.size(), 0);
+    }
+
+    #[test]
+    fn insert_string() {
+        let mut bundle = PersistableBundle::new();
+        assert_eq!(bundle.insert_string("string", "foo"), Ok(()));
+        assert_eq!(bundle.size(), 1);
+    }
+
+    #[test]
+    fn insert_vec() {
+        let mut bundle = PersistableBundle::new();
+
+        assert_eq!(bundle.insert_bool_vec("bool", &[]), Ok(()));
+        assert_eq!(bundle.insert_int_vec("int", &[42]), Ok(()));
+        assert_eq!(bundle.insert_long_vec("long", &[66, 67, 68]), Ok(()));
+        assert_eq!(bundle.insert_double_vec("double", &[123.4]), Ok(()));
+        assert_eq!(bundle.insert_string_vec("string", &["foo", "bar", "baz"]), Ok(()));
+        assert_eq!(
+            bundle.insert_string_vec(
+                "string",
+                &[&"foo".to_string(), &"bar".to_string(), &"baz".to_string()]
+            ),
+            Ok(())
+        );
+        assert_eq!(
+            bundle.insert_string_vec(
+                "string",
+                &["foo".to_string(), "bar".to_string(), "baz".to_string()]
+            ),
+            Ok(())
+        );
+
+        assert_eq!(bundle.size(), 5);
+    }
+
+    #[test]
+    fn insert_get_bundle() {
+        let mut bundle = PersistableBundle::new();
+
+        let mut sub_bundle = PersistableBundle::new();
+        assert_eq!(sub_bundle.insert_int("int", 42), Ok(()));
+        assert_eq!(sub_bundle.size(), 1);
+        assert_eq!(bundle.insert_persistable_bundle("bundle", &sub_bundle), Ok(()));
+
+        assert_eq!(bundle.get_persistable_bundle("bundle"), Ok(Some(sub_bundle)));
+    }
+}
diff --git a/libs/binder/rust/sys/BinderBindings.hpp b/libs/binder/rust/sys/BinderBindings.hpp
index 557f0e8..deeaa37 100644
--- a/libs/binder/rust/sys/BinderBindings.hpp
+++ b/libs/binder/rust/sys/BinderBindings.hpp
@@ -17,6 +17,7 @@
 #include <android/binder_ibinder.h>
 #include <android/binder_parcel.h>
 #include <android/binder_status.h>
+#include <android/persistable_bundle.h>
 
 /* Platform only */
 #if defined(ANDROID_PLATFORM) || defined(__ANDROID_VENDOR__)
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index c6ba7d8..852885b 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -19,6 +19,7 @@
 #include <semaphore.h>
 #include <stdint.h>
 #include <sys/types.h>
+#include <algorithm>
 
 #include <android/gui/BnWindowInfosReportedListener.h>
 #include <android/gui/DisplayState.h>
@@ -844,7 +845,7 @@
 
 void SurfaceComposerClient::Transaction::sanitize(int pid, int uid) {
     uint32_t permissions = LayerStatePermissions::getTransactionPermissions(pid, uid);
-    for (auto & [handle, composerState] : mComposerStates) {
+    for (auto& composerState : mComposerStates) {
         composerState.state.sanitize(permissions);
     }
     if (!mInputWindowCommands.empty() &&
@@ -879,7 +880,7 @@
     if (count > parcel->dataSize()) {
         return BAD_VALUE;
     }
-    SortedVector<DisplayState> displayStates;
+    Vector<DisplayState> displayStates;
     displayStates.setCapacity(count);
     for (size_t i = 0; i < count; i++) {
         DisplayState displayState;
@@ -922,17 +923,14 @@
     if (count > parcel->dataSize()) {
         return BAD_VALUE;
     }
-    std::unordered_map<sp<IBinder>, ComposerState, IBinderHash> composerStates;
-    composerStates.reserve(count);
+    Vector<ComposerState> composerStates;
+    composerStates.setCapacity(count);
     for (size_t i = 0; i < count; i++) {
-        sp<IBinder> surfaceControlHandle;
-        SAFE_PARCEL(parcel->readStrongBinder, &surfaceControlHandle);
-
         ComposerState composerState;
         if (composerState.read(*parcel) == BAD_VALUE) {
             return BAD_VALUE;
         }
-        composerStates[surfaceControlHandle] = composerState;
+        composerStates.add(composerState);
     }
 
     InputWindowCommands inputWindowCommands;
@@ -965,9 +963,9 @@
     mDesiredPresentTime = desiredPresentTime;
     mIsAutoTimestamp = isAutoTimestamp;
     mFrameTimelineInfo = frameTimelineInfo;
-    mDisplayStates = displayStates;
+    mDisplayStates = std::move(displayStates);
     mListenerCallbacks = listenerCallbacks;
-    mComposerStates = composerStates;
+    mComposerStates = std::move(composerStates);
     mInputWindowCommands = inputWindowCommands;
     mApplyToken = applyToken;
     mUncacheBuffers = std::move(uncacheBuffers);
@@ -1015,8 +1013,7 @@
     }
 
     parcel->writeUint32(static_cast<uint32_t>(mComposerStates.size()));
-    for (auto const& [handle, composerState] : mComposerStates) {
-        SAFE_PARCEL(parcel->writeStrongBinder, handle);
+    for (auto const& composerState : mComposerStates) {
         composerState.write(*parcel);
     }
 
@@ -1073,23 +1070,31 @@
     }
     mMergedTransactionIds.insert(mMergedTransactionIds.begin(), other.mId);
 
-    for (auto const& [handle, composerState] : other.mComposerStates) {
-        if (mComposerStates.count(handle) == 0) {
-            mComposerStates[handle] = composerState;
-        } else {
-            if (composerState.state.what & layer_state_t::eBufferChanged) {
-                releaseBufferIfOverwriting(mComposerStates[handle].state);
+    for (auto const& otherState : other.mComposerStates) {
+        if (auto it = std::find_if(mComposerStates.begin(), mComposerStates.end(),
+                                   [&otherState](const auto& composerState) {
+                                       return composerState.state.surface ==
+                                               otherState.state.surface;
+                                   });
+            it != mComposerStates.end()) {
+            if (otherState.state.what & layer_state_t::eBufferChanged) {
+                releaseBufferIfOverwriting(it->state);
             }
-            mComposerStates[handle].state.merge(composerState.state);
+            it->state.merge(otherState.state);
+        } else {
+            mComposerStates.add(otherState);
         }
     }
 
     for (auto const& state : other.mDisplayStates) {
-        ssize_t index = mDisplayStates.indexOf(state);
-        if (index < 0) {
-            mDisplayStates.add(state);
+        if (auto it = std::find_if(mDisplayStates.begin(), mDisplayStates.end(),
+                                   [&state](const auto& displayState) {
+                                       return displayState.token == state.token;
+                                   });
+            it != mDisplayStates.end()) {
+            it->merge(state);
         } else {
-            mDisplayStates.editItemAt(static_cast<size_t>(index)).merge(state);
+            mDisplayStates.add(state);
         }
     }
 
@@ -1186,8 +1191,8 @@
     }
 
     size_t count = 0;
-    for (auto& [handle, cs] : mComposerStates) {
-        layer_state_t* s = &(mComposerStates[handle].state);
+    for (auto& cs : mComposerStates) {
+        layer_state_t* s = &cs.state;
         if (!(s->what & layer_state_t::eBufferChanged)) {
             continue;
         } else if (s->bufferData &&
@@ -1312,15 +1317,6 @@
 
     cacheBuffers();
 
-    Vector<ComposerState> composerStates;
-    Vector<DisplayState> displayStates;
-
-    for (auto const& kv : mComposerStates) {
-        composerStates.add(kv.second);
-    }
-
-    displayStates = std::move(mDisplayStates);
-
     if (oneWay) {
         if (synchronous) {
             ALOGE("Transaction attempted to set synchronous and one way at the same time"
@@ -1340,7 +1336,7 @@
 
     sp<ISurfaceComposer> sf(ComposerService::getComposerService());
     status_t binderStatus =
-            sf->setTransactionState(mFrameTimelineInfo, composerStates, displayStates, mFlags,
+            sf->setTransactionState(mFrameTimelineInfo, mComposerStates, mDisplayStates, mFlags,
                                     applyToken, mInputWindowCommands, mDesiredPresentTime,
                                     mIsAutoTimestamp, mUncacheBuffers, hasListenerCallbacks,
                                     listenerCallbacks, mId, mMergedTransactionIds);
@@ -1456,18 +1452,21 @@
 
 layer_state_t* SurfaceComposerClient::Transaction::getLayerState(const sp<SurfaceControl>& sc) {
     auto handle = sc->getLayerStateHandle();
-
-    if (mComposerStates.count(handle) == 0) {
-        // we don't have it, add an initialized layer_state to our list
-        ComposerState s;
-
-        s.state.surface = handle;
-        s.state.layerId = sc->getLayerId();
-
-        mComposerStates[handle] = s;
+    if (auto it = std::find_if(mComposerStates.begin(), mComposerStates.end(),
+                               [&handle](const auto& composerState) {
+                                   return composerState.state.surface == handle;
+                               });
+        it != mComposerStates.end()) {
+        return &it->state;
     }
 
-    return &(mComposerStates[handle].state);
+    // we don't have it, add an initialized layer_state to our list
+    ComposerState s;
+    s.state.surface = handle;
+    s.state.layerId = sc->getLayerId();
+    mComposerStates.add(s);
+
+    return &mComposerStates.editItemAt(mComposerStates.size() - 1).state;
 }
 
 void SurfaceComposerClient::Transaction::registerSurfaceControlForCallback(
@@ -2492,15 +2491,17 @@
 // ---------------------------------------------------------------------------
 
 DisplayState& SurfaceComposerClient::Transaction::getDisplayState(const sp<IBinder>& token) {
+    if (auto it = std::find_if(mDisplayStates.begin(), mDisplayStates.end(),
+                               [token](const auto& display) { return display.token == token; });
+        it != mDisplayStates.end()) {
+        return *it;
+    }
+
+    // If display state doesn't exist, add a new one.
     DisplayState s;
     s.token = token;
-    ssize_t index = mDisplayStates.indexOf(s);
-    if (index < 0) {
-        // we don't have it, add an initialized layer_state to our list
-        s.what = 0;
-        index = mDisplayStates.add(s);
-    }
-    return mDisplayStates.editItemAt(static_cast<size_t>(index));
+    mDisplayStates.add(s);
+    return mDisplayStates.editItemAt(mDisplayStates.size() - 1);
 }
 
 status_t SurfaceComposerClient::Transaction::setDisplaySurface(const sp<IBinder>& token,
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 2215632..d30a830 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -455,8 +455,8 @@
         bool mLogCallPoints = false;
 
     protected:
-        std::unordered_map<sp<IBinder>, ComposerState, IBinderHash> mComposerStates;
-        SortedVector<DisplayState> mDisplayStates;
+        Vector<ComposerState> mComposerStates;
+        Vector<DisplayState> mDisplayStates;
         std::unordered_map<sp<ITransactionCompletedListener>, CallbackInfo, TCLHash>
                 mListenerCallbacks;
         std::vector<client_cache_t> mUncacheBuffers;
diff --git a/libs/renderengine/threaded/RenderEngineThreaded.cpp b/libs/renderengine/threaded/RenderEngineThreaded.cpp
index ea5605d..67f4aa1 100644
--- a/libs/renderengine/threaded/RenderEngineThreaded.cpp
+++ b/libs/renderengine/threaded/RenderEngineThreaded.cpp
@@ -23,6 +23,7 @@
 #include <future>
 
 #include <android-base/stringprintf.h>
+#include <common/FlagManager.h>
 #include <common/trace.h>
 #include <private/gui/SyncFeatures.h>
 #include <processgroup/processgroup.h>
@@ -60,7 +61,7 @@
 
     struct sched_param param = {0};
     int sched_policy;
-    if (enabled) {
+    if (enabled && !FlagManager::getInstance().disable_sched_fifo_re()) {
         sched_policy = SCHED_FIFO;
         param.sched_priority = kFifoPriority;
     } else {
diff --git a/services/inputflinger/include/InputReaderBase.h b/services/inputflinger/include/InputReaderBase.h
index f54b76b..608bec4 100644
--- a/services/inputflinger/include/InputReaderBase.h
+++ b/services/inputflinger/include/InputReaderBase.h
@@ -150,6 +150,11 @@
     // speed setting still affects the scaling factor.
     bool mousePointerAccelerationEnabled;
 
+    // True if the touchpad should exhibit pointer acceleration. If false,
+    // a flat acceleration curve (linear scaling) is used, but the user's pointer
+    // speed setting still affects the scaling factor.
+    bool touchpadAccelerationEnabled;
+
     // Velocity control parameters for touchpad pointer movements on the old touchpad stack (based
     // on TouchInputMapper).
     //
@@ -284,6 +289,7 @@
             mousePointerSpeed(0),
             displaysWithMouseScalingDisabled(),
             mousePointerAccelerationEnabled(true),
+            touchpadAccelerationEnabled(true),
             pointerVelocityControlParameters(1.0f, 500.0f, 3000.0f,
                                              static_cast<float>(
                                                      android::os::IInputConstants::
diff --git a/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp b/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp
index 0c094e6..0df3364 100644
--- a/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp
@@ -59,9 +59,11 @@
                                   ANDROID_LOG_INFO);
 
 std::vector<double> createAccelerationCurveForSensitivity(int32_t sensitivity,
+                                                          bool accelerationEnabled,
                                                           size_t propertySize) {
-    std::vector<AccelerationCurveSegment> segments =
-            createAccelerationCurveForPointerSensitivity(sensitivity);
+    std::vector<AccelerationCurveSegment> segments = accelerationEnabled
+            ? createAccelerationCurveForPointerSensitivity(sensitivity)
+            : createFlatAccelerationCurve(sensitivity);
     LOG_ALWAYS_FATAL_IF(propertySize < 4 * segments.size());
     std::vector<double> output(propertySize, 0);
 
@@ -358,12 +360,14 @@
         GesturesProp accelCurveProp = mPropertyProvider.getProperty("Pointer Accel Curve");
         accelCurveProp.setRealValues(
                 createAccelerationCurveForSensitivity(config.touchpadPointerSpeed,
+                                                      config.touchpadAccelerationEnabled,
                                                       accelCurveProp.getCount()));
         mPropertyProvider.getProperty("Use Custom Touchpad Scroll Accel Curve")
                 .setBoolValues({true});
         GesturesProp scrollCurveProp = mPropertyProvider.getProperty("Scroll Accel Curve");
         scrollCurveProp.setRealValues(
                 createAccelerationCurveForSensitivity(config.touchpadPointerSpeed,
+                                                      config.touchpadAccelerationEnabled,
                                                       scrollCurveProp.getCount()));
         mPropertyProvider.getProperty("Scroll X Out Scale").setRealValues({1.0});
         mPropertyProvider.getProperty("Scroll Y Out Scale").setRealValues({1.0});
@@ -510,4 +514,12 @@
     return mHardwareProperties;
 }
 
+std::optional<GesturesProp> TouchpadInputMapper::getGesturePropertyForTesting(
+        const std::string& name) {
+    if (!mPropertyProvider.hasProperty(name)) {
+        return std::nullopt;
+    }
+    return mPropertyProvider.getProperty(name);
+}
+
 } // namespace android
diff --git a/services/inputflinger/reader/mapper/TouchpadInputMapper.h b/services/inputflinger/reader/mapper/TouchpadInputMapper.h
index a2c4be9..56553c9 100644
--- a/services/inputflinger/reader/mapper/TouchpadInputMapper.h
+++ b/services/inputflinger/reader/mapper/TouchpadInputMapper.h
@@ -70,6 +70,8 @@
 
     std::optional<HardwareProperties> getTouchpadHardwareProperties() override;
 
+    std::optional<GesturesProp> getGesturePropertyForTesting(const std::string& name);
+
 private:
     void resetGestureInterpreter(nsecs_t when);
     explicit TouchpadInputMapper(InputDeviceContext& deviceContext,
diff --git a/services/inputflinger/tests/TouchpadInputMapper_test.cpp b/services/inputflinger/tests/TouchpadInputMapper_test.cpp
index ea69fff..0789114 100644
--- a/services/inputflinger/tests/TouchpadInputMapper_test.cpp
+++ b/services/inputflinger/tests/TouchpadInputMapper_test.cpp
@@ -18,10 +18,13 @@
 
 #include <android-base/logging.h>
 #include <gtest/gtest.h>
+#include <input/AccelerationCurve.h>
 
+#include <log/log.h>
 #include <thread>
 #include "InputMapperTest.h"
 #include "InterfaceMocks.h"
+#include "TestConstants.h"
 #include "TestEventMatchers.h"
 
 #define TAG "TouchpadInputMapper_test"
@@ -190,4 +193,67 @@
     mFakePolicy->assertTouchpadHardwareStateNotified();
 }
 
+TEST_F(TouchpadInputMapperTest, TouchpadAccelerationDisabled) {
+    mReaderConfiguration.touchpadAccelerationEnabled = false;
+    mReaderConfiguration.touchpadPointerSpeed = 3;
+
+    std::list<NotifyArgs> args =
+            mMapper->reconfigure(ARBITRARY_TIME, mReaderConfiguration,
+                                 InputReaderConfiguration::Change::TOUCHPAD_SETTINGS);
+    auto* touchpadMapper = static_cast<TouchpadInputMapper*>(mMapper.get());
+
+    const auto accelCurvePropsDisabled =
+            touchpadMapper->getGesturePropertyForTesting("Pointer Accel Curve");
+    ASSERT_TRUE(accelCurvePropsDisabled.has_value());
+    std::vector<double> curveValuesDisabled = accelCurvePropsDisabled.value().getRealValues();
+    std::vector<AccelerationCurveSegment> curve =
+            createFlatAccelerationCurve(mReaderConfiguration.touchpadPointerSpeed);
+    double expectedBaseGain = curve[0].baseGain;
+    ASSERT_EQ(curveValuesDisabled[0], std::numeric_limits<double>::infinity());
+    ASSERT_EQ(curveValuesDisabled[1], 0);
+    ASSERT_NEAR(curveValuesDisabled[2], expectedBaseGain, EPSILON);
+    ASSERT_EQ(curveValuesDisabled[3], 0);
+}
+
+TEST_F(TouchpadInputMapperTest, TouchpadAccelerationEnabled) {
+    // Enable touchpad acceleration.
+    mReaderConfiguration.touchpadAccelerationEnabled = true;
+    mReaderConfiguration.touchpadPointerSpeed = 3;
+
+    std::list<NotifyArgs> args =
+            mMapper->reconfigure(ARBITRARY_TIME, mReaderConfiguration,
+                                 InputReaderConfiguration::Change::TOUCHPAD_SETTINGS);
+    ASSERT_THAT(args, testing::IsEmpty());
+
+    auto* touchpadMapper = static_cast<TouchpadInputMapper*>(mMapper.get());
+
+    // Get the acceleration curve properties when acceleration is enabled.
+    const auto accelCurvePropsEnabled =
+            touchpadMapper->getGesturePropertyForTesting("Pointer Accel Curve");
+    ASSERT_TRUE(accelCurvePropsEnabled.has_value());
+
+    // Get the curve values.
+    std::vector<double> curveValuesEnabled = accelCurvePropsEnabled.value().getRealValues();
+
+    // Use createAccelerationCurveForPointerSensitivity to get expected curve segments.
+    std::vector<AccelerationCurveSegment> expectedCurveSegments =
+            createAccelerationCurveForPointerSensitivity(mReaderConfiguration.touchpadPointerSpeed);
+
+    // Iterate through the segments and compare the values.
+    for (size_t i = 0; i < expectedCurveSegments.size(); ++i) {
+        // Check max speed.
+        if (std::isinf(expectedCurveSegments[i].maxPointerSpeedMmPerS)) {
+            ASSERT_TRUE(std::isinf(curveValuesEnabled[i * 4 + 0]));
+        } else {
+            ASSERT_NEAR(curveValuesEnabled[i * 4 + 0],
+                        expectedCurveSegments[i].maxPointerSpeedMmPerS, EPSILON);
+        }
+
+        // Check that the x^2 term is zero.
+        ASSERT_NEAR(curveValuesEnabled[i * 4 + 1], 0, EPSILON);
+        ASSERT_NEAR(curveValuesEnabled[i * 4 + 2], expectedCurveSegments[i].baseGain, EPSILON);
+        ASSERT_NEAR(curveValuesEnabled[i * 4 + 3], expectedCurveSegments[i].reciprocal, EPSILON);
+    }
+}
+
 } // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
index 5cef051..bb6bebe 100644
--- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
@@ -357,7 +357,9 @@
     mAidlComposerCallback = ndk::SharedRefBase::make<AidlIComposerCallbackWrapper>(callback);
 
     ndk::SpAIBinder binder = mAidlComposerCallback->asBinder();
-    AIBinder_setMinSchedulerPolicy(binder.get(), SCHED_FIFO, 2);
+    if (!FlagManager::getInstance().disable_sched_fifo_composer_callback()) {
+        AIBinder_setMinSchedulerPolicy(binder.get(), SCHED_FIFO, 2);
+    }
 
     const auto status = mAidlComposerClient->registerCallback(mAidlComposerCallback);
     if (!status.isOk()) {
diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
index fc317f3..a010353 100644
--- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
@@ -28,6 +28,7 @@
 #include <aidl/android/hardware/graphics/common/DisplayHotplugEvent.h>
 #include <android/binder_manager.h>
 #include <android/hardware/graphics/composer/2.1/types.h>
+#include <common/FlagManager.h>
 #include <common/trace.h>
 #include <composer-command-buffer/2.2/ComposerCommandBuffer.h>
 #include <hidl/HidlTransportSupport.h>
@@ -301,7 +302,9 @@
 }
 
 void HidlComposer::registerCallback(const sp<IComposerCallback>& callback) {
-    android::hardware::setMinSchedulerPolicy(callback, SCHED_FIFO, 2);
+    if (!FlagManager::getInstance().disable_sched_fifo_composer_callback()) {
+        android::hardware::setMinSchedulerPolicy(callback, SCHED_FIFO, 2);
+    }
 
     auto ret = [&]() {
         if (mClient_2_4) {
diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp
index c6d7160..0efc396 100644
--- a/services/surfaceflinger/Scheduler/EventThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventThread.cpp
@@ -344,7 +344,8 @@
     auto connection = sp<EventThreadConnection>::make(const_cast<EventThread*>(this),
                                                       IPCThreadState::self()->getCallingUid(),
                                                       eventRegistration);
-    if (FlagManager::getInstance().misc1()) {
+    if (FlagManager::getInstance().misc1() &&
+        !FlagManager::getInstance().disable_sched_fifo_sf_sched()) {
         const int policy = SCHED_FIFO;
         connection->setMinSchedulerPolicy(policy, sched_get_priority_min(policy));
     }
diff --git a/services/surfaceflinger/Scheduler/src/Timer.cpp b/services/surfaceflinger/Scheduler/src/Timer.cpp
index 20c58eb..6a5eeba 100644
--- a/services/surfaceflinger/Scheduler/src/Timer.cpp
+++ b/services/surfaceflinger/Scheduler/src/Timer.cpp
@@ -24,6 +24,7 @@
 #include <sys/timerfd.h>
 #include <sys/unistd.h>
 
+#include <common/FlagManager.h>
 #include <common/trace.h>
 #include <ftl/concat.h>
 #include <ftl/enum.h>
@@ -155,8 +156,10 @@
     setDebugState(DebugState::Running);
     struct sched_param param = {0};
     param.sched_priority = 2;
-    if (pthread_setschedparam(pthread_self(), SCHED_FIFO, &param) != 0) {
-        ALOGW("Failed to set SCHED_FIFO on dispatch thread");
+    if (!FlagManager::getInstance().disable_sched_fifo_sf_sched()) {
+        if (pthread_setschedparam(pthread_self(), SCHED_FIFO, &param) != 0) {
+            ALOGW("Failed to set SCHED_FIFO on dispatch thread");
+        }
     }
 
     if (pthread_setname_np(pthread_self(), "TimerDispatch") != 0) {
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index d6225e2..becfab9 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -7116,7 +7116,7 @@
 
     struct sched_param param = {0};
     int sched_policy;
-    if (enabled) {
+    if (enabled && !FlagManager::getInstance().disable_sched_fifo_sf()) {
         sched_policy = SCHED_FIFO;
         param.sched_priority = kFifoPriority;
     } else {
diff --git a/services/surfaceflinger/common/FlagManager.cpp b/services/surfaceflinger/common/FlagManager.cpp
index e80cd78..15df152 100644
--- a/services/surfaceflinger/common/FlagManager.cpp
+++ b/services/surfaceflinger/common/FlagManager.cpp
@@ -104,9 +104,19 @@
     dumpFlag(result, (aconfig), #name, std::bind(&FlagManager::name, this))
 #define DUMP_LEGACY_SERVER_FLAG(name) DUMP_FLAG_INTERNAL(name, false)
 #define DUMP_ACONFIG_FLAG(name) DUMP_FLAG_INTERNAL(name, true)
+#define DUMP_SYSPROP_FLAG(name) \
+    dumpFlag(result, (true), "debug.sf." #name, std::bind(&FlagManager::name, this))
 
     base::StringAppendF(&result, "FlagManager values: \n");
 
+    /// Sysprop flags ///
+    DUMP_SYSPROP_FLAG(disable_sched_fifo_sf);
+    DUMP_SYSPROP_FLAG(disable_sched_fifo_sf_binder);
+    DUMP_SYSPROP_FLAG(disable_sched_fifo_sf_sched);
+    DUMP_SYSPROP_FLAG(disable_sched_fifo_re);
+    DUMP_SYSPROP_FLAG(disable_sched_fifo_composer);
+    DUMP_SYSPROP_FLAG(disable_sched_fifo_composer_callback);
+
     /// Legacy server flags ///
     DUMP_LEGACY_SERVER_FLAG(use_adpf_cpu_hint);
     DUMP_LEGACY_SERVER_FLAG(use_skia_tracing);
@@ -185,6 +195,12 @@
     const auto res = parseBool(value.c_str());
     return res.has_value() && res.value();
 }
+#define FLAG_MANAGER_SYSPROP_FLAG(name, defaultVal)                                      \
+    bool FlagManager::name() const {                                                     \
+        static const bool kFlagValue =                                                   \
+                base::GetBoolProperty("debug.sf." #name, /* default value*/ defaultVal); \
+        return kFlagValue;                                                               \
+    }
 
 #define FLAG_MANAGER_LEGACY_SERVER_FLAG(name, syspropOverride, serverFlagName)              \
     bool FlagManager::name() const {                                                        \
@@ -215,6 +231,14 @@
 #define FLAG_MANAGER_ACONFIG_FLAG_IMPORTED(name, syspropOverride, owner) \
     FLAG_MANAGER_ACONFIG_INTERNAL(name, syspropOverride, owner)
 
+/// Debug sysprop flags - default value is always false ///
+FLAG_MANAGER_SYSPROP_FLAG(disable_sched_fifo_sf, /* default */ false)
+FLAG_MANAGER_SYSPROP_FLAG(disable_sched_fifo_sf_binder, /* default */ false)
+FLAG_MANAGER_SYSPROP_FLAG(disable_sched_fifo_sf_sched, /* default */ false)
+FLAG_MANAGER_SYSPROP_FLAG(disable_sched_fifo_re, /* default */ false)
+FLAG_MANAGER_SYSPROP_FLAG(disable_sched_fifo_composer, /* default */ false)
+FLAG_MANAGER_SYSPROP_FLAG(disable_sched_fifo_composer_callback, /* default */ false)
+
 /// Legacy server flags ///
 FLAG_MANAGER_LEGACY_SERVER_FLAG(test_flag, "", "")
 FLAG_MANAGER_LEGACY_SERVER_FLAG(use_adpf_cpu_hint, "debug.sf.enable_adpf_cpu_hint",
diff --git a/services/surfaceflinger/common/include/common/FlagManager.h b/services/surfaceflinger/common/include/common/FlagManager.h
index c7f97b4..147e79e 100644
--- a/services/surfaceflinger/common/include/common/FlagManager.h
+++ b/services/surfaceflinger/common/include/common/FlagManager.h
@@ -42,6 +42,14 @@
 
     void setUnitTestMode();
 
+    /// Debug sysprop flags ///
+    bool disable_sched_fifo_sf() const;
+    bool disable_sched_fifo_sf_binder() const;
+    bool disable_sched_fifo_sf_sched() const;
+    bool disable_sched_fifo_re() const;
+    bool disable_sched_fifo_composer() const;
+    bool disable_sched_fifo_composer_callback() const;
+
     /// Legacy server flags ///
     bool test_flag() const;
     bool use_adpf_cpu_hint() const;
diff --git a/services/surfaceflinger/main_surfaceflinger.cpp b/services/surfaceflinger/main_surfaceflinger.cpp
index 6c8972f..73dfa9f 100644
--- a/services/surfaceflinger/main_surfaceflinger.cpp
+++ b/services/surfaceflinger/main_surfaceflinger.cpp
@@ -132,7 +132,8 @@
     // Set the minimum policy of surfaceflinger node to be SCHED_FIFO.
     // So any thread with policy/priority lower than {SCHED_FIFO, 1}, will run
     // at least with SCHED_FIFO policy and priority 1.
-    if (errorInPriorityModification == 0) {
+    if (errorInPriorityModification == 0 &&
+        !FlagManager::getInstance().disable_sched_fifo_sf_binder()) {
         flinger->setMinSchedulerPolicy(SCHED_FIFO, newPriority);
     }
 
@@ -150,7 +151,8 @@
 
     // publish gui::ISurfaceComposer, the new AIDL interface
     sp<SurfaceComposerAIDL> composerAIDL = sp<SurfaceComposerAIDL>::make(flinger);
-    if (FlagManager::getInstance().misc1()) {
+    if (FlagManager::getInstance().misc1() &&
+        !FlagManager::getInstance().disable_sched_fifo_composer()) {
         composerAIDL->setMinSchedulerPolicy(SCHED_FIFO, newPriority);
     }
     sm->addService(String16("SurfaceFlingerAIDL"), composerAIDL, false,
diff --git a/services/vibratorservice/VibratorHalWrapper.cpp b/services/vibratorservice/VibratorHalWrapper.cpp
index 3ddc4f2..536a6b3 100644
--- a/services/vibratorservice/VibratorHalWrapper.cpp
+++ b/services/vibratorservice/VibratorHalWrapper.cpp
@@ -131,9 +131,10 @@
     return HalResult<void>::unsupported();
 }
 
-HalResult<void> HalWrapper::composePwleV2(const CompositePwleV2&, const std::function<void()>&) {
+HalResult<milliseconds> HalWrapper::composePwleV2(const CompositePwleV2&,
+                                                  const std::function<void()>&) {
     ALOGV("Skipped composePwleV2 because it's not available in Vibrator HAL");
-    return HalResult<void>::unsupported();
+    return HalResult<milliseconds>::unsupported();
 }
 
 HalResult<Capabilities> HalWrapper::getCapabilities() {
@@ -359,11 +360,18 @@
     return HalResultFactory::fromStatus(getHal()->composePwle(primitives, cb));
 }
 
-HalResult<void> AidlHalWrapper::composePwleV2(const CompositePwleV2& composite,
-                                              const std::function<void()>& completionCallback) {
+HalResult<milliseconds> AidlHalWrapper::composePwleV2(
+        const CompositePwleV2& composite, const std::function<void()>& completionCallback) {
     // This method should always support callbacks, so no need to double check.
     auto cb = ndk::SharedRefBase::make<HalCallbackWrapper>(completionCallback);
-    return HalResultFactory::fromStatus(getHal()->composePwleV2(composite, cb));
+
+    milliseconds totalDuration(0);
+    for (const auto& primitive : composite.pwlePrimitives) {
+        totalDuration += milliseconds(primitive.timeMillis);
+    }
+
+    return HalResultFactory::fromStatus<milliseconds>(getHal()->composePwleV2(composite, cb),
+                                                      totalDuration);
 }
 
 HalResult<Capabilities> AidlHalWrapper::getCapabilitiesInternal() {
diff --git a/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h b/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h
index 339a6e1..9a39ad4 100644
--- a/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h
+++ b/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h
@@ -423,8 +423,8 @@
     virtual HalResult<void> performPwleEffect(const std::vector<PrimitivePwle>& primitives,
                                               const std::function<void()>& completionCallback);
 
-    virtual HalResult<void> composePwleV2(const CompositePwleV2& composite,
-                                          const std::function<void()>& completionCallback);
+    virtual HalResult<std::chrono::milliseconds> composePwleV2(
+            const CompositePwleV2& composite, const std::function<void()>& completionCallback);
 
 protected:
     // Shared pointer to allow CallbackScheduler to outlive this wrapper.
@@ -511,8 +511,9 @@
             const std::vector<PrimitivePwle>& primitives,
             const std::function<void()>& completionCallback) override final;
 
-    HalResult<void> composePwleV2(const CompositePwleV2& composite,
-                                  const std::function<void()>& completionCallback) override final;
+    HalResult<std::chrono::milliseconds> composePwleV2(
+            const CompositePwleV2& composite,
+            const std::function<void()>& completionCallback) override final;
 
 protected:
     HalResult<Capabilities> getCapabilitiesInternal() override final;
diff --git a/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp b/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp
index c58e05c..7545148 100644
--- a/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp
+++ b/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp
@@ -787,5 +787,6 @@
 
     result = mWrapper->composePwleV2(composite, callback);
     ASSERT_TRUE(result.isOk());
+    ASSERT_EQ(300ms, result.value());
     ASSERT_EQ(1, *callbackCounter.get());
 }