Merge changes from topics "identify_a_pip", "writeStateToHWC_update" into sc-dev

* changes:
  SF rounded corners: include geometry when reordering
  SF: only hole punch through opaque layers
  SF: Ignore rounded corners if the layer can peek through
  Reorder the layers sent to HWC
  Identify a PIP window and implement hole punch
diff --git a/cmds/dumpsys/tests/dumpsys_test.cpp b/cmds/dumpsys/tests/dumpsys_test.cpp
index 39af7df..c9d2dbb 100644
--- a/cmds/dumpsys/tests/dumpsys_test.cpp
+++ b/cmds/dumpsys/tests/dumpsys_test.cpp
@@ -59,6 +59,7 @@
     MOCK_METHOD1(waitForService, sp<IBinder>(const String16&));
     MOCK_METHOD1(isDeclared, bool(const String16&));
     MOCK_METHOD1(getDeclaredInstances, Vector<String16>(const String16&));
+    MOCK_METHOD1(updatableViaApex, std::optional<String16>(const String16&));
   protected:
     MOCK_METHOD0(onAsBinder, IBinder*());
 };
diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp
index 2f55249..b429fb3 100644
--- a/cmds/servicemanager/ServiceManager.cpp
+++ b/cmds/servicemanager/ServiceManager.cpp
@@ -58,22 +58,34 @@
     return false;
 }
 
-static bool isVintfDeclared(const std::string& name) {
-    size_t firstSlash = name.find('/');
-    size_t lastDot = name.rfind('.', firstSlash);
-    if (firstSlash == std::string::npos || lastDot == std::string::npos) {
-        LOG(ERROR) << "VINTF HALs require names in the format type/instance (e.g. "
-                   << "some.package.foo.IFoo/default) but got: " << name;
-        return false;
-    }
-    const std::string package = name.substr(0, lastDot);
-    const std::string iface = name.substr(lastDot+1, firstSlash-lastDot-1);
-    const std::string instance = name.substr(firstSlash+1);
+struct AidlName {
+    std::string package;
+    std::string iface;
+    std::string instance;
 
-    bool found = forEachManifest([&] (const ManifestWithDescription& mwd) {
-        if (mwd.manifest->hasAidlInstance(package, iface, instance)) {
+    static bool fill(const std::string& name, AidlName* aname) {
+        size_t firstSlash = name.find('/');
+        size_t lastDot = name.rfind('.', firstSlash);
+        if (firstSlash == std::string::npos || lastDot == std::string::npos) {
+            LOG(ERROR) << "VINTF HALs require names in the format type/instance (e.g. "
+                       << "some.package.foo.IFoo/default) but got: " << name;
+            return false;
+        }
+        aname->package = name.substr(0, lastDot);
+        aname->iface = name.substr(lastDot + 1, firstSlash - lastDot - 1);
+        aname->instance = name.substr(firstSlash + 1);
+        return true;
+    }
+};
+
+static bool isVintfDeclared(const std::string& name) {
+    AidlName aname;
+    if (!AidlName::fill(name, &aname)) return false;
+
+    bool found = forEachManifest([&](const ManifestWithDescription& mwd) {
+        if (mwd.manifest->hasAidlInstance(aname.package, aname.iface, aname.instance)) {
             LOG(INFO) << "Found " << name << " in " << mwd.description << " VINTF manifest.";
-            return true;
+            return true; // break
         }
         return false;  // continue
     });
@@ -81,13 +93,34 @@
     if (!found) {
         // Although it is tested, explicitly rebuilding qualified name, in case it
         // becomes something unexpected.
-        LOG(ERROR) << "Could not find " << package << "." << iface << "/" << instance
-                   << " in the VINTF manifest.";
+        LOG(ERROR) << "Could not find " << aname.package << "." << aname.iface << "/"
+                   << aname.instance << " in the VINTF manifest.";
     }
 
     return found;
 }
 
+static std::optional<std::string> getVintfUpdatableApex(const std::string& name) {
+    AidlName aname;
+    if (!AidlName::fill(name, &aname)) return std::nullopt;
+
+    std::optional<std::string> updatableViaApex;
+
+    forEachManifest([&](const ManifestWithDescription& mwd) {
+        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;
+            if (manifestInstance.instance() != aname.instance) return true;
+            updatableViaApex = manifestInstance.updatableViaApex();
+            return false; // break (libvintf uses opposite convention)
+        });
+        return false; // continue
+    });
+
+    return updatableViaApex;
+}
+
 static std::vector<std::string> getVintfInstances(const std::string& interface) {
     size_t lastDot = interface.rfind('.');
     if (lastDot == std::string::npos) {
@@ -388,6 +421,22 @@
     return Status::ok();
 }
 
+Status ServiceManager::updatableViaApex(const std::string& name,
+                                        std::optional<std::string>* outReturn) {
+    auto ctx = mAccess->getCallingContext();
+
+    if (!mAccess->canFind(ctx, name)) {
+        return Status::fromExceptionCode(Status::EX_SECURITY);
+    }
+
+    *outReturn = std::nullopt;
+
+#ifndef VENDORSERVICEMANAGER
+    *outReturn = getVintfUpdatableApex(name);
+#endif
+    return Status::ok();
+}
+
 void ServiceManager::removeRegistrationCallback(const wp<IBinder>& who,
                                     ServiceCallbackMap::iterator* it,
                                     bool* found) {
diff --git a/cmds/servicemanager/ServiceManager.h b/cmds/servicemanager/ServiceManager.h
index c089115..4f23c21 100644
--- a/cmds/servicemanager/ServiceManager.h
+++ b/cmds/servicemanager/ServiceManager.h
@@ -46,6 +46,8 @@
 
     binder::Status isDeclared(const std::string& name, bool* outReturn) override;
     binder::Status getDeclaredInstances(const std::string& interface, std::vector<std::string>* outReturn) override;
+    binder::Status updatableViaApex(const std::string& name,
+                                    std::optional<std::string>* outReturn) override;
     binder::Status registerClientCallback(const std::string& name, const sp<IBinder>& service,
                                           const sp<IClientCallback>& cb) override;
     binder::Status tryUnregisterService(const std::string& name, const sp<IBinder>& binder) override;
diff --git a/include/android/surface_control.h b/include/android/surface_control.h
index c349024..b7eafcd 100644
--- a/include/android/surface_control.h
+++ b/include/android/surface_control.h
@@ -147,6 +147,28 @@
 typedef void (*ASurfaceTransaction_OnComplete)(void* context, ASurfaceTransactionStats* stats)
                                                __INTRODUCED_IN(29);
 
+
+/**
+ * The ASurfaceTransaction_OnCommit callback is invoked when transaction is applied and the updates
+ * are ready to be presented. This callback will be invoked before the
+ * ASurfaceTransaction_OnComplete callback.
+ *
+ * \param context Optional context provided by the client that is passed into the callback.
+ *
+ * \param stats Opaque handle that can be passed to ASurfaceTransactionStats functions to query
+ * information about the transaction. The handle is only valid during the callback.
+ * Present and release fences are not available for this callback. Querying them using
+ * ASurfaceTransactionStats_getPresentFenceFd and ASurfaceTransactionStats_getPreviousReleaseFenceFd
+ * will result in failure.
+ *
+ * THREADING
+ * The transaction committed callback can be invoked on any thread.
+ *
+ * Available since API level 31.
+ */
+typedef void (*ASurfaceTransaction_OnCommit)(void* context, ASurfaceTransactionStats* stats)
+                                               __INTRODUCED_IN(31);
+
 /**
  * Returns the timestamp of when the frame was latched by the framework. Once a frame is
  * latched by the framework, it is presented at the following hardware vsync.
@@ -161,6 +183,8 @@
  * The recipient of the callback takes ownership of the fence and is responsible for closing
  * it. If a device does not support present fences, a -1 will be returned.
  *
+ * This query is not valid for ASurfaceTransaction_OnCommit callback.
+ *
  * Available since API level 29.
  */
 int ASurfaceTransactionStats_getPresentFenceFd(ASurfaceTransactionStats* surface_transaction_stats)
@@ -218,6 +242,8 @@
  * The client must ensure that all pending refs on a buffer are released before attempting to reuse
  * this buffer, otherwise synchronization errors may occur.
  *
+ * This query is not valid for ASurfaceTransaction_OnCommit callback.
+ *
  * Available since API level 29.
  */
 int ASurfaceTransactionStats_getPreviousReleaseFenceFd(
@@ -236,6 +262,16 @@
                                        ASurfaceTransaction_OnComplete func) __INTRODUCED_IN(29);
 
 /**
+ * Sets the callback that will be invoked when the updates from this transaction are applied and are
+ * ready to be presented. This callback will be invoked before the ASurfaceTransaction_OnComplete
+ * callback.
+ *
+ * Available since API level 31.
+ */
+void ASurfaceTransaction_setOnCommit(ASurfaceTransaction* transaction, void* context,
+                                    ASurfaceTransaction_OnCommit func) __INTRODUCED_IN(31);
+
+/**
  * Reparents the \a surface_control from its old parent to the \a new_parent surface control.
  * Any children of the reparented \a surface_control will remain children of the \a surface_control.
  *
diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp
index 61f4581..f684cf6 100644
--- a/libs/binder/IServiceManager.cpp
+++ b/libs/binder/IServiceManager.cpp
@@ -75,6 +75,7 @@
     sp<IBinder> waitForService(const String16& name16) override;
     bool isDeclared(const String16& name) override;
     Vector<String16> getDeclaredInstances(const String16& interface) override;
+    std::optional<String16> updatableViaApex(const String16& name) override;
 
     // for legacy ABI
     const String16& getInterfaceDescriptor() const override {
@@ -388,4 +389,12 @@
     return res;
 }
 
+std::optional<String16> ServiceManagerShim::updatableViaApex(const String16& name) {
+    std::optional<std::string> declared;
+    if (!mTheRealServiceManager->updatableViaApex(String8(name).c_str(), &declared).isOk()) {
+        return std::nullopt;
+    }
+    return declared ? std::optional<String16>(String16(declared.value().c_str())) : std::nullopt;
+}
+
 } // namespace android
diff --git a/libs/binder/aidl/android/os/IServiceManager.aidl b/libs/binder/aidl/android/os/IServiceManager.aidl
index 2fabf94..75c4092 100644
--- a/libs/binder/aidl/android/os/IServiceManager.aidl
+++ b/libs/binder/aidl/android/os/IServiceManager.aidl
@@ -108,6 +108,11 @@
     @utf8InCpp String[] getDeclaredInstances(@utf8InCpp String iface);
 
     /**
+     * If updatable-via-apex, returns the APEX via which this is updated.
+     */
+    @nullable @utf8InCpp String updatableViaApex(@utf8InCpp String name);
+
+    /**
      * Request a callback when the number of clients of the service changes.
      * Used by LazyServiceRegistrar to dynamically stop services that have no clients.
      */
diff --git a/libs/binder/include/binder/IServiceManager.h b/libs/binder/include/binder/IServiceManager.h
index 5f0d056..3dbe2c4 100644
--- a/libs/binder/include/binder/IServiceManager.h
+++ b/libs/binder/include/binder/IServiceManager.h
@@ -20,6 +20,8 @@
 #include <utils/Vector.h>
 #include <utils/String16.h>
 
+#include <optional>
+
 namespace android {
 
 // ----------------------------------------------------------------------
@@ -99,6 +101,12 @@
      * Get all instances of a service as declared in the VINTF manifest
      */
     virtual Vector<String16> getDeclaredInstances(const String16& interface) = 0;
+
+    /**
+     * If this instance is updatable via an APEX, returns the APEX with which
+     * this can be updated.
+     */
+    virtual std::optional<String16> updatableViaApex(const String16& name) = 0;
 };
 
 sp<IServiceManager> defaultServiceManager();
diff --git a/libs/binder/ndk/include_platform/android/binder_manager.h b/libs/binder/ndk/include_platform/android/binder_manager.h
index 5516914..a90b4aa 100644
--- a/libs/binder/ndk/include_platform/android/binder_manager.h
+++ b/libs/binder/ndk/include_platform/android/binder_manager.h
@@ -124,6 +124,15 @@
         __INTRODUCED_IN(31);
 
 /**
+ * Check if a service is updatable via an APEX module.
+ *
+ * \param instance identifier of the service
+ *
+ * \return whether the interface is updatable via APEX
+ */
+bool AServiceManager_isUpdatableViaApex(const char* instance) __INTRODUCED_IN(31);
+
+/**
  * Prevent lazy services without client from shutting down their process
  *
  * \param persist 'true' if the process should not exit.
diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt
index 67c85b6..7d4b82e 100644
--- a/libs/binder/ndk/libbinder_ndk.map.txt
+++ b/libs/binder/ndk/libbinder_ndk.map.txt
@@ -118,14 +118,15 @@
     AIBinder_getCallingSid; # apex
     AIBinder_setRequestingSid; # apex
     AParcel_markSensitive; # llndk
-    AServiceManager_isDeclared; # apex llndk
     AServiceManager_forEachDeclaredInstance; # apex llndk
-    AServiceManager_registerLazyService; # llndk
-    AServiceManager_waitForService; # apex llndk
     AServiceManager_forceLazyServicesPersist; # llndk
+    AServiceManager_isDeclared; # apex llndk
+    AServiceManager_isUpdatableViaApex; # apex
+    AServiceManager_reRegister; # llndk
+    AServiceManager_registerLazyService; # llndk
     AServiceManager_setActiveServicesCallback; # llndk
     AServiceManager_tryUnregister; # llndk
-    AServiceManager_reRegister; # llndk
+    AServiceManager_waitForService; # apex llndk
 
     AIBinder_forceDowngradeToSystemStability; # apex
     AIBinder_forceDowngradeToVendorStability; # llndk
diff --git a/libs/binder/ndk/service_manager.cpp b/libs/binder/ndk/service_manager.cpp
index 1ccd0d2..7649a26 100644
--- a/libs/binder/ndk/service_manager.cpp
+++ b/libs/binder/ndk/service_manager.cpp
@@ -105,6 +105,14 @@
         callback(String8(instance).c_str(), context);
     }
 }
+bool AServiceManager_isUpdatableViaApex(const char* instance) {
+    if (instance == nullptr) {
+        return false;
+    }
+
+    sp<IServiceManager> sm = defaultServiceManager();
+    return sm->updatableViaApex(String16(instance)) != std::nullopt;
+}
 void AServiceManager_forceLazyServicesPersist(bool persist) {
     auto serviceRegistrar = android::binder::LazyServiceRegistrar::getInstance();
     serviceRegistrar.forcePersist(persist);
diff --git a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
index 6a88401..62db3cf 100644
--- a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
+++ b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
@@ -300,6 +300,11 @@
     EXPECT_EQ(STATUS_OK, AIBinder_ping(binder.get()));
 }
 
+TEST(NdkBinder, IsUpdatable) {
+    bool isUpdatable = AServiceManager_isUpdatableViaApex("android.hardware.light.ILights/default");
+    EXPECT_EQ(isUpdatable, false);
+}
+
 // This is too slow
 TEST(NdkBinder, CheckLazyServiceShutDown) {
     ndk::SpAIBinder binder(AServiceManager_waitForService(kLazyBinderNdkUnitTestService));
diff --git a/libs/binder/rust/src/binder.rs b/libs/binder/rust/src/binder.rs
index 321b422..695a83e 100644
--- a/libs/binder/rust/src/binder.rs
+++ b/libs/binder/rust/src/binder.rs
@@ -548,6 +548,28 @@
     }
 }
 
+/// The features to enable when creating a native Binder.
+///
+/// This should always be initialised with a default value, e.g.:
+/// ```
+/// # use binder::BinderFeatures;
+/// BinderFeatures {
+///   set_requesting_sid: true,
+///   ..BinderFeatures::default(),
+/// }
+/// ```
+#[derive(Clone, Debug, Default, Eq, PartialEq)]
+pub struct BinderFeatures {
+    /// Indicates that the service intends to receive caller security contexts. This must be true
+    /// for `ThreadState::with_calling_sid` to work.
+    pub set_requesting_sid: bool,
+    // Ensure that clients include a ..BinderFeatures::default() to preserve backwards compatibility
+    // when new fields are added. #[non_exhaustive] doesn't work because it prevents struct
+    // expressions entirely.
+    #[doc(hidden)]
+    pub _non_exhaustive: (),
+}
+
 /// Declare typed interfaces for a binder object.
 ///
 /// Given an interface trait and descriptor string, create a native and remote
@@ -730,8 +752,9 @@
 
         impl $native {
             /// Create a new binder service.
-            pub fn new_binder<T: $interface + Sync + Send + 'static>(inner: T) -> $crate::Strong<dyn $interface> {
-                let binder = $crate::Binder::new_with_stability($native(Box::new(inner)), $stability);
+            pub fn new_binder<T: $interface + Sync + Send + 'static>(inner: T, features: $crate::BinderFeatures) -> $crate::Strong<dyn $interface> {
+                let mut binder = $crate::Binder::new_with_stability($native(Box::new(inner)), $stability);
+                $crate::IBinderInternal::set_requesting_sid(&mut binder, features.set_requesting_sid);
                 $crate::Strong::new(Box::new(binder))
             }
         }
diff --git a/libs/binder/rust/src/lib.rs b/libs/binder/rust/src/lib.rs
index 30928a5..2694cba 100644
--- a/libs/binder/rust/src/lib.rs
+++ b/libs/binder/rust/src/lib.rs
@@ -107,10 +107,9 @@
 pub mod parcel;
 
 pub use crate::binder::{
-    FromIBinder, IBinder, IBinderInternal, Interface, InterfaceClass, Remotable,
-    Stability, Strong, TransactionCode, TransactionFlags, Weak,
-    FIRST_CALL_TRANSACTION, FLAG_CLEAR_BUF, FLAG_ONEWAY, FLAG_PRIVATE_LOCAL,
-    LAST_CALL_TRANSACTION,
+    BinderFeatures, FromIBinder, IBinder, IBinderInternal, Interface, InterfaceClass, Remotable,
+    Stability, Strong, TransactionCode, TransactionFlags, Weak, FIRST_CALL_TRANSACTION,
+    FLAG_CLEAR_BUF, FLAG_ONEWAY, FLAG_PRIVATE_LOCAL, LAST_CALL_TRANSACTION,
 };
 pub use error::{status_t, ExceptionCode, Result, Status, StatusCode};
 pub use native::add_service;
@@ -125,8 +124,8 @@
     pub use super::parcel::ParcelFileDescriptor;
     pub use super::{add_service, get_interface};
     pub use super::{
-        DeathRecipient, ExceptionCode, IBinder, Interface, ProcessState, SpIBinder, Status,
-        StatusCode, Strong, ThreadState, Weak, WpIBinder,
+        BinderFeatures, DeathRecipient, ExceptionCode, IBinder, Interface, ProcessState, SpIBinder,
+        Status, StatusCode, Strong, ThreadState, Weak, WpIBinder,
     };
 
     /// Binder result containing a [`Status`] on error.
diff --git a/libs/binder/rust/tests/integration.rs b/libs/binder/rust/tests/integration.rs
index 60e3502..0332007 100644
--- a/libs/binder/rust/tests/integration.rs
+++ b/libs/binder/rust/tests/integration.rs
@@ -19,7 +19,7 @@
 use binder::declare_binder_interface;
 use binder::parcel::Parcel;
 use binder::{
-    Binder, IBinderInternal, Interface, StatusCode, ThreadState, TransactionCode,
+    Binder, BinderFeatures, IBinderInternal, Interface, StatusCode, ThreadState, TransactionCode,
     FIRST_CALL_TRANSACTION,
 };
 use std::convert::{TryFrom, TryInto};
@@ -55,7 +55,8 @@
         })));
         service.set_requesting_sid(true);
         if let Some(extension_name) = extension_name {
-            let extension = BnTest::new_binder(TestService { s: extension_name });
+            let extension =
+                BnTest::new_binder(TestService { s: extension_name }, BinderFeatures::default());
             service
                 .set_extension(&mut extension.as_binder())
                 .expect("Could not add extension");
@@ -212,8 +213,8 @@
     use std::time::Duration;
 
     use binder::{
-        Binder, DeathRecipient, FromIBinder, IBinder, IBinderInternal, Interface, SpIBinder,
-        StatusCode, Strong,
+        Binder, BinderFeatures, DeathRecipient, FromIBinder, IBinder, IBinderInternal, Interface,
+        SpIBinder, StatusCode, Strong,
     };
 
     use super::{BnTest, ITest, ITestSameDescriptor, TestService, RUST_SERVICE_BINARY};
@@ -495,9 +496,12 @@
     #[test]
     fn reassociate_rust_binder() {
         let service_name = "testing_service";
-        let service_ibinder = BnTest::new_binder(TestService {
-            s: service_name.to_string(),
-        })
+        let service_ibinder = BnTest::new_binder(
+            TestService {
+                s: service_name.to_string(),
+            },
+            BinderFeatures::default(),
+        )
         .as_binder();
 
         let service: Strong<dyn ITest> = service_ibinder
@@ -510,9 +514,12 @@
     #[test]
     fn weak_binder_upgrade() {
         let service_name = "testing_service";
-        let service = BnTest::new_binder(TestService {
-            s: service_name.to_string(),
-        });
+        let service = BnTest::new_binder(
+            TestService {
+                s: service_name.to_string(),
+            },
+            BinderFeatures::default(),
+        );
 
         let weak = Strong::downgrade(&service);
 
@@ -525,9 +532,12 @@
     fn weak_binder_upgrade_dead() {
         let service_name = "testing_service";
         let weak = {
-            let service = BnTest::new_binder(TestService {
-                s: service_name.to_string(),
-            });
+            let service = BnTest::new_binder(
+                TestService {
+                    s: service_name.to_string(),
+                },
+                BinderFeatures::default(),
+            );
 
             Strong::downgrade(&service)
         };
@@ -538,9 +548,12 @@
     #[test]
     fn weak_binder_clone() {
         let service_name = "testing_service";
-        let service = BnTest::new_binder(TestService {
-            s: service_name.to_string(),
-        });
+        let service = BnTest::new_binder(
+            TestService {
+                s: service_name.to_string(),
+            },
+            BinderFeatures::default(),
+        );
 
         let weak = Strong::downgrade(&service);
         let cloned = weak.clone();
@@ -556,12 +569,18 @@
     #[test]
     #[allow(clippy::eq_op)]
     fn binder_ord() {
-        let service1 = BnTest::new_binder(TestService {
-            s: "testing_service1".to_string(),
-        });
-        let service2 = BnTest::new_binder(TestService {
-            s: "testing_service2".to_string(),
-        });
+        let service1 = BnTest::new_binder(
+            TestService {
+                s: "testing_service1".to_string(),
+            },
+            BinderFeatures::default(),
+        );
+        let service2 = BnTest::new_binder(
+            TestService {
+                s: "testing_service2".to_string(),
+            },
+            BinderFeatures::default(),
+        );
 
         assert!(!(service1 < service1));
         assert!(!(service1 > service1));
diff --git a/libs/binder/rust/tests/ndk_rust_interop.rs b/libs/binder/rust/tests/ndk_rust_interop.rs
index ce75ab7..4702e45 100644
--- a/libs/binder/rust/tests/ndk_rust_interop.rs
+++ b/libs/binder/rust/tests/ndk_rust_interop.rs
@@ -16,15 +16,13 @@
 
 //! Rust Binder NDK interop tests
 
-use std::ffi::CStr;
-use std::os::raw::{c_char, c_int};
-use ::IBinderRustNdkInteropTest::binder::{self, Interface, StatusCode};
 use ::IBinderRustNdkInteropTest::aidl::IBinderRustNdkInteropTest::{
     BnBinderRustNdkInteropTest, IBinderRustNdkInteropTest,
 };
-use ::IBinderRustNdkInteropTest::aidl::IBinderRustNdkInteropTestOther::{
-    IBinderRustNdkInteropTestOther,
-};
+use ::IBinderRustNdkInteropTest::aidl::IBinderRustNdkInteropTestOther::IBinderRustNdkInteropTestOther;
+use ::IBinderRustNdkInteropTest::binder::{self, BinderFeatures, Interface, StatusCode};
+use std::ffi::CStr;
+use std::os::raw::{c_char, c_int};
 
 /// Look up the provided AIDL service and call its echo method.
 ///
@@ -37,18 +35,21 @@
 
     // The Rust class descriptor pointer will not match the NDK one, but the
     // descriptor strings match so this needs to still associate.
-    let service: binder::Strong<dyn IBinderRustNdkInteropTest> = match binder::get_interface(service_name) {
-        Err(e) => {
-            eprintln!("Could not find Ndk service {}: {:?}", service_name, e);
-            return StatusCode::NAME_NOT_FOUND as c_int;
-        }
-        Ok(service) => service,
-    };
+    let service: binder::Strong<dyn IBinderRustNdkInteropTest> =
+        match binder::get_interface(service_name) {
+            Err(e) => {
+                eprintln!("Could not find Ndk service {}: {:?}", service_name, e);
+                return StatusCode::NAME_NOT_FOUND as c_int;
+            }
+            Ok(service) => service,
+        };
 
     match service.echo("testing") {
-        Ok(s) => if s != "testing" {
-            return StatusCode::BAD_VALUE as c_int;
-        },
+        Ok(s) => {
+            if s != "testing" {
+                return StatusCode::BAD_VALUE as c_int;
+            }
+        }
         Err(e) => return e.into(),
     }
 
@@ -88,7 +89,7 @@
 #[no_mangle]
 pub unsafe extern "C" fn rust_start_service(service_name: *const c_char) -> c_int {
     let service_name = CStr::from_ptr(service_name).to_str().unwrap();
-    let service = BnBinderRustNdkInteropTest::new_binder(Service);
+    let service = BnBinderRustNdkInteropTest::new_binder(Service, BinderFeatures::default());
     match binder::add_service(&service_name, service.as_binder()) {
         Ok(_) => StatusCode::OK as c_int,
         Err(e) => e as c_int,
diff --git a/libs/binder/rust/tests/serialization.rs b/libs/binder/rust/tests/serialization.rs
index f1b068e..66ba846 100644
--- a/libs/binder/rust/tests/serialization.rs
+++ b/libs/binder/rust/tests/serialization.rs
@@ -18,11 +18,11 @@
 //! access.
 
 use binder::declare_binder_interface;
+use binder::parcel::ParcelFileDescriptor;
 use binder::{
-    Binder, ExceptionCode, Interface, Parcel, Result, SpIBinder, Status,
+    Binder, BinderFeatures, ExceptionCode, Interface, Parcel, Result, SpIBinder, Status,
     StatusCode, TransactionCode,
 };
-use binder::parcel::ParcelFileDescriptor;
 
 use std::ffi::{c_void, CStr, CString};
 use std::sync::Once;
@@ -85,7 +85,7 @@
 pub extern "C" fn rust_service() -> *mut c_void {
     unsafe {
         SERVICE_ONCE.call_once(|| {
-            SERVICE = Some(BnReadParcelTest::new_binder(()).as_binder());
+            SERVICE = Some(BnReadParcelTest::new_binder((), BinderFeatures::default()).as_binder());
         });
         SERVICE.as_ref().unwrap().as_raw().cast()
     }
@@ -108,8 +108,12 @@
 impl ReadParcelTest for () {}
 
 #[allow(clippy::float_cmp)]
-fn on_transact(_service: &dyn ReadParcelTest, code: TransactionCode,
-               parcel: &Parcel, reply: &mut Parcel) -> Result<()> {
+fn on_transact(
+    _service: &dyn ReadParcelTest,
+    code: TransactionCode,
+    parcel: &Parcel,
+    reply: &mut Parcel,
+) -> Result<()> {
     match code {
         bindings::Transaction_TEST_BOOL => {
             assert_eq!(parcel.read::<bool>()?, true);
diff --git a/libs/binder/tests/binderStabilityTest.cpp b/libs/binder/tests/binderStabilityTest.cpp
index cb309bd..2ce13df 100644
--- a/libs/binder/tests/binderStabilityTest.cpp
+++ b/libs/binder/tests/binderStabilityTest.cpp
@@ -192,6 +192,8 @@
         EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT,
             android::defaultServiceManager()->addService(String16("."), vintfServer)) << instance8;
         EXPECT_FALSE(android::defaultServiceManager()->isDeclared(instance)) << instance8;
+        EXPECT_EQ(std::nullopt, android::defaultServiceManager()->updatableViaApex(instance))
+                << instance8;
     }
 }
 
diff --git a/libs/fakeservicemanager/ServiceManager.cpp b/libs/fakeservicemanager/ServiceManager.cpp
index 4ecbe53..761e45c 100644
--- a/libs/fakeservicemanager/ServiceManager.cpp
+++ b/libs/fakeservicemanager/ServiceManager.cpp
@@ -73,4 +73,9 @@
     return out;
 }
 
+std::optional<String16> ServiceManager::updatableViaApex(const String16& name) {
+    (void)name;
+    return std::nullopt;
+}
+
 }  // namespace android
diff --git a/libs/fakeservicemanager/ServiceManager.h b/libs/fakeservicemanager/ServiceManager.h
index 4ef47fb..e26c21b 100644
--- a/libs/fakeservicemanager/ServiceManager.h
+++ b/libs/fakeservicemanager/ServiceManager.h
@@ -19,6 +19,7 @@
 #include <binder/IServiceManager.h>
 
 #include <map>
+#include <optional>
 
 namespace android {
 
@@ -48,6 +49,8 @@
 
     Vector<String16> getDeclaredInstances(const String16& iface) override;
 
+    std::optional<String16> updatableViaApex(const String16& name) override;
+
 private:
     std::map<String16, sp<IBinder>> mNameToService;
 };
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 6ca2487..53721cf 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -99,7 +99,7 @@
         SAFE_PARCEL(data.writeVectorSize, listenerCallbacks);
         for (const auto& [listener, callbackIds] : listenerCallbacks) {
             SAFE_PARCEL(data.writeStrongBinder, listener);
-            SAFE_PARCEL(data.writeInt64Vector, callbackIds);
+            SAFE_PARCEL(data.writeParcelableVector, callbackIds);
         }
 
         SAFE_PARCEL(data.writeUint64, transactionId);
@@ -1268,7 +1268,7 @@
             for (int32_t i = 0; i < listenersSize; i++) {
                 SAFE_PARCEL(data.readStrongBinder, &tmpBinder);
                 std::vector<CallbackId> callbackIds;
-                SAFE_PARCEL(data.readInt64Vector, &callbackIds);
+                SAFE_PARCEL(data.readParcelableVector, &callbackIds);
                 listenerCallbacks.emplace_back(tmpBinder, callbackIds);
             }
 
diff --git a/libs/gui/ITransactionCompletedListener.cpp b/libs/gui/ITransactionCompletedListener.cpp
index b42793b..f74f91e 100644
--- a/libs/gui/ITransactionCompletedListener.cpp
+++ b/libs/gui/ITransactionCompletedListener.cpp
@@ -152,7 +152,7 @@
 }
 
 status_t TransactionStats::writeToParcel(Parcel* output) const {
-    status_t err = output->writeInt64Vector(callbackIds);
+    status_t err = output->writeParcelableVector(callbackIds);
     if (err != NO_ERROR) {
         return err;
     }
@@ -176,7 +176,7 @@
 }
 
 status_t TransactionStats::readFromParcel(const Parcel* input) {
-    status_t err = input->readInt64Vector(&callbackIds);
+    status_t err = input->readParcelableVector(&callbackIds);
     if (err != NO_ERROR) {
         return err;
     }
@@ -227,8 +227,9 @@
     return NO_ERROR;
 }
 
-ListenerStats ListenerStats::createEmpty(const sp<IBinder>& listener,
-                                         const std::unordered_set<CallbackId>& callbackIds) {
+ListenerStats ListenerStats::createEmpty(
+        const sp<IBinder>& listener,
+        const std::unordered_set<CallbackId, CallbackIdHash>& callbackIds) {
     ListenerStats listenerStats;
     listenerStats.listener = listener;
     listenerStats.transactionStats.emplace_back(callbackIds);
@@ -278,4 +279,28 @@
     }
 }
 
+ListenerCallbacks ListenerCallbacks::filter(CallbackId::Type type) const {
+    std::vector<CallbackId> filteredCallbackIds;
+    for (const auto& callbackId : callbackIds) {
+        if (callbackId.type == type) {
+            filteredCallbackIds.push_back(callbackId);
+        }
+    }
+    return ListenerCallbacks(transactionCompletedListener, filteredCallbackIds);
+}
+
+status_t CallbackId::writeToParcel(Parcel* output) const {
+    SAFE_PARCEL(output->writeInt64, id);
+    SAFE_PARCEL(output->writeInt32, static_cast<int32_t>(type));
+    return NO_ERROR;
+}
+
+status_t CallbackId::readFromParcel(const Parcel* input) {
+    SAFE_PARCEL(input->readInt64, &id);
+    int32_t typeAsInt;
+    SAFE_PARCEL(input->readInt32, &typeAsInt);
+    type = static_cast<CallbackId::Type>(typeAsInt);
+    return NO_ERROR;
+}
+
 }; // namespace android
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 55ed7fe..517b49e 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -140,7 +140,7 @@
 
     for (auto listener : listeners) {
         SAFE_PARCEL(output.writeStrongBinder, listener.transactionCompletedListener);
-        SAFE_PARCEL(output.writeInt64Vector, listener.callbackIds);
+        SAFE_PARCEL(output.writeParcelableVector, listener.callbackIds);
     }
     SAFE_PARCEL(output.writeFloat, shadowRadius);
     SAFE_PARCEL(output.writeInt32, frameRateSelectionPriority);
@@ -258,7 +258,7 @@
         sp<IBinder> listener;
         std::vector<CallbackId> callbackIds;
         SAFE_PARCEL(input.readNullableStrongBinder, &listener);
-        SAFE_PARCEL(input.readInt64Vector, &callbackIds);
+        SAFE_PARCEL(input.readParcelableVector, &callbackIds);
         listeners.emplace_back(listener, callbackIds);
     }
     SAFE_PARCEL(input.readFloat, &shadowRadius);
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 9b2e10b..5db0eae 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -139,7 +139,7 @@
 // 0 is an invalid callback id
 TransactionCompletedListener::TransactionCompletedListener() : mCallbackIdCounter(1) {}
 
-CallbackId TransactionCompletedListener::getNextIdLocked() {
+int64_t TransactionCompletedListener::getNextIdLocked() {
     return mCallbackIdCounter++;
 }
 
@@ -163,13 +163,13 @@
 CallbackId TransactionCompletedListener::addCallbackFunction(
         const TransactionCompletedCallback& callbackFunction,
         const std::unordered_set<sp<SurfaceControl>, SurfaceComposerClient::SCHash>&
-                surfaceControls) {
+                surfaceControls,
+        CallbackId::Type callbackType) {
     std::lock_guard<std::mutex> lock(mMutex);
     startListeningLocked();
 
-    CallbackId callbackId = getNextIdLocked();
+    CallbackId callbackId(getNextIdLocked(), callbackType);
     mCallbacks[callbackId].callbackFunction = callbackFunction;
-
     auto& callbackSurfaceControls = mCallbacks[callbackId].surfaceControls;
 
     for (const auto& surfaceControl : surfaceControls) {
@@ -228,7 +228,7 @@
 
 void TransactionCompletedListener::addSurfaceControlToCallbacks(
         const sp<SurfaceControl>& surfaceControl,
-        const std::unordered_set<CallbackId>& callbackIds) {
+        const std::unordered_set<CallbackId, CallbackIdHash>& callbackIds) {
     std::lock_guard<std::mutex> lock(mMutex);
 
     for (auto callbackId : callbackIds) {
@@ -240,7 +240,7 @@
 }
 
 void TransactionCompletedListener::onTransactionCompleted(ListenerStats listenerStats) {
-    std::unordered_map<CallbackId, CallbackTranslation> callbacksMap;
+    std::unordered_map<CallbackId, CallbackTranslation, CallbackIdHash> callbacksMap;
     std::multimap<sp<IBinder>, sp<JankDataListener>> jankListenersMap;
     std::multimap<sp<IBinder>, SurfaceStatsCallbackEntry> surfaceListeners;
     {
@@ -267,7 +267,36 @@
         }
     }
     for (const auto& transactionStats : listenerStats.transactionStats) {
+        // handle on commit callbacks
         for (auto callbackId : transactionStats.callbackIds) {
+            if (callbackId.type != CallbackId::Type::ON_COMMIT) {
+                continue;
+            }
+            auto& [callbackFunction, callbackSurfaceControls] = callbacksMap[callbackId];
+            if (!callbackFunction) {
+                ALOGE("cannot call null callback function, skipping");
+                continue;
+            }
+            std::vector<SurfaceControlStats> surfaceControlStats;
+            for (const auto& surfaceStats : transactionStats.surfaceStats) {
+                surfaceControlStats
+                        .emplace_back(callbacksMap[callbackId]
+                                              .surfaceControls[surfaceStats.surfaceControl],
+                                      transactionStats.latchTime, surfaceStats.acquireTime,
+                                      transactionStats.presentFence,
+                                      surfaceStats.previousReleaseFence, surfaceStats.transformHint,
+                                      surfaceStats.eventStats);
+            }
+
+            callbackFunction(transactionStats.latchTime, transactionStats.presentFence,
+                             surfaceControlStats);
+        }
+
+        // handle on complete callbacks
+        for (auto callbackId : transactionStats.callbackIds) {
+            if (callbackId.type != CallbackId::Type::ON_COMPLETE) {
+                continue;
+            }
             auto& [callbackFunction, callbackSurfaceControls] = callbacksMap[callbackId];
             if (!callbackFunction) {
                 ALOGE("cannot call null callback function, skipping");
@@ -542,7 +571,9 @@
             return BAD_VALUE;
         }
         for (size_t j = 0; j < numCallbackIds; j++) {
-            listenerCallbacks[listener].callbackIds.insert(parcel->readInt64());
+            CallbackId id;
+            parcel->readParcelable(&id);
+            listenerCallbacks[listener].callbackIds.insert(id);
         }
         size_t numSurfaces = parcel->readUint32();
         if (numSurfaces > parcel->dataSize()) {
@@ -628,7 +659,7 @@
         parcel->writeStrongBinder(ITransactionCompletedListener::asBinder(listener));
         parcel->writeUint32(static_cast<uint32_t>(callbackInfo.callbackIds.size()));
         for (auto callbackId : callbackInfo.callbackIds) {
-            parcel->writeInt64(callbackId);
+            parcel->writeParcelable(callbackId);
         }
         parcel->writeUint32(static_cast<uint32_t>(callbackInfo.surfaceControls.size()));
         for (auto surfaceControl : callbackInfo.surfaceControls) {
@@ -1389,9 +1420,9 @@
     return *this;
 }
 
-SurfaceComposerClient::Transaction&
-SurfaceComposerClient::Transaction::addTransactionCompletedCallback(
-        TransactionCompletedCallbackTakesContext callback, void* callbackContext) {
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::addTransactionCallback(
+        TransactionCompletedCallbackTakesContext callback, void* callbackContext,
+        CallbackId::Type callbackType) {
     auto listener = TransactionCompletedListener::getInstance();
 
     auto callbackWithContext = std::bind(callback, callbackContext, std::placeholders::_1,
@@ -1399,13 +1430,26 @@
     const auto& surfaceControls =
             mListenerCallbacks[TransactionCompletedListener::getIInstance()].surfaceControls;
 
-    CallbackId callbackId = listener->addCallbackFunction(callbackWithContext, surfaceControls);
+    CallbackId callbackId =
+            listener->addCallbackFunction(callbackWithContext, surfaceControls, callbackType);
 
     mListenerCallbacks[TransactionCompletedListener::getIInstance()].callbackIds.emplace(
             callbackId);
     return *this;
 }
 
+SurfaceComposerClient::Transaction&
+SurfaceComposerClient::Transaction::addTransactionCompletedCallback(
+        TransactionCompletedCallbackTakesContext callback, void* callbackContext) {
+    return addTransactionCallback(callback, callbackContext, CallbackId::Type::ON_COMPLETE);
+}
+
+SurfaceComposerClient::Transaction&
+SurfaceComposerClient::Transaction::addTransactionCommittedCallback(
+        TransactionCompletedCallbackTakesContext callback, void* callbackContext) {
+    return addTransactionCallback(callback, callbackContext, CallbackId::Type::ON_COMMIT);
+}
+
 SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::notifyProducerDisconnect(
         const sp<SurfaceControl>& sc) {
     layer_state_t* s = getLayerState(sc);
@@ -1796,7 +1840,8 @@
         }
         ALOGE_IF(err, "SurfaceComposerClient::createSurface error %s", strerror(-err));
         if (err == NO_ERROR) {
-            *outSurface = new SurfaceControl(this, handle, gbp, id, w, h, format, transformHint);
+            *outSurface =
+                    new SurfaceControl(this, handle, gbp, id, w, h, format, transformHint, flags);
         }
     }
     return err;
diff --git a/libs/gui/include/gui/ITransactionCompletedListener.h b/libs/gui/include/gui/ITransactionCompletedListener.h
index 098760e..2d71194 100644
--- a/libs/gui/include/gui/ITransactionCompletedListener.h
+++ b/libs/gui/include/gui/ITransactionCompletedListener.h
@@ -36,7 +36,22 @@
 class ITransactionCompletedListener;
 class ListenerCallbacks;
 
-using CallbackId = int64_t;
+class CallbackId : public Parcelable {
+public:
+    int64_t id;
+    enum class Type : int32_t { ON_COMPLETE, ON_COMMIT } type;
+
+    CallbackId() {}
+    CallbackId(int64_t id, Type type) : id(id), type(type) {}
+    status_t writeToParcel(Parcel* output) const override;
+    status_t readFromParcel(const Parcel* input) override;
+
+    bool operator==(const CallbackId& rhs) const { return id == rhs.id && type == rhs.type; }
+};
+
+struct CallbackIdHash {
+    std::size_t operator()(const CallbackId& key) const { return std::hash<int64_t>()(key.id); }
+};
 
 class FrameEventHistoryStats : public Parcelable {
 public:
@@ -112,7 +127,7 @@
 
     TransactionStats() = default;
     TransactionStats(const std::vector<CallbackId>& ids) : callbackIds(ids) {}
-    TransactionStats(const std::unordered_set<CallbackId>& ids)
+    TransactionStats(const std::unordered_set<CallbackId, CallbackIdHash>& ids)
           : callbackIds(ids.begin(), ids.end()) {}
     TransactionStats(const std::vector<CallbackId>& ids, nsecs_t latch, const sp<Fence>& present,
                      const std::vector<SurfaceStats>& surfaces)
@@ -129,8 +144,9 @@
     status_t writeToParcel(Parcel* output) const override;
     status_t readFromParcel(const Parcel* input) override;
 
-    static ListenerStats createEmpty(const sp<IBinder>& listener,
-                                     const std::unordered_set<CallbackId>& callbackIds);
+    static ListenerStats createEmpty(
+            const sp<IBinder>& listener,
+            const std::unordered_set<CallbackId, CallbackIdHash>& callbackIds);
 
     sp<IBinder> listener;
     std::vector<TransactionStats> transactionStats;
@@ -156,7 +172,8 @@
 
 class ListenerCallbacks {
 public:
-    ListenerCallbacks(const sp<IBinder>& listener, const std::unordered_set<CallbackId>& callbacks)
+    ListenerCallbacks(const sp<IBinder>& listener,
+                      const std::unordered_set<CallbackId, CallbackIdHash>& callbacks)
           : transactionCompletedListener(listener),
             callbackIds(callbacks.begin(), callbacks.end()) {}
 
@@ -170,9 +187,12 @@
         if (callbackIds.empty()) {
             return rhs.callbackIds.empty();
         }
-        return callbackIds.front() == rhs.callbackIds.front();
+        return callbackIds.front().id == rhs.callbackIds.front().id;
     }
 
+    // Returns a new ListenerCallbacks filtered by type
+    ListenerCallbacks filter(CallbackId::Type type) const;
+
     sp<IBinder> transactionCompletedListener;
     std::vector<CallbackId> callbackIds;
 };
@@ -191,7 +211,7 @@
     // same members. It is sufficient to just check the first CallbackId in the vectors. If
     // they match, they are the same. If they do not match, they are not the same.
     std::size_t operator()(const std::vector<CallbackId>& callbackIds) const {
-        return std::hash<CallbackId>{}((callbackIds.empty()) ? 0 : callbackIds.front());
+        return std::hash<int64_t>{}((callbackIds.empty()) ? 0 : callbackIds.front().id);
     }
 };
 
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index d3f6ff0..5bbd8e3 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -336,7 +336,7 @@
     struct CallbackInfo {
         // All the callbacks that have been requested for a TransactionCompletedListener in the
         // Transaction
-        std::unordered_set<CallbackId> callbackIds;
+        std::unordered_set<CallbackId, CallbackIdHash> callbackIds;
         // All the SurfaceControls that have been modified in this TransactionCompletedListener's
         // process that require a callback if there is one or more callbackIds set.
         std::unordered_set<sp<SurfaceControl>, SCHash> surfaceControls;
@@ -484,9 +484,15 @@
         // Sets information about the priority of the frame.
         Transaction& setFrameRateSelectionPriority(const sp<SurfaceControl>& sc, int32_t priority);
 
+        Transaction& addTransactionCallback(TransactionCompletedCallbackTakesContext callback,
+                                            void* callbackContext, CallbackId::Type callbackType);
+
         Transaction& addTransactionCompletedCallback(
                 TransactionCompletedCallbackTakesContext callback, void* callbackContext);
 
+        Transaction& addTransactionCommittedCallback(
+                TransactionCompletedCallbackTakesContext callback, void* callbackContext);
+
         // ONLY FOR BLAST ADAPTER
         Transaction& notifyProducerDisconnect(const sp<SurfaceControl>& sc);
         // Set the framenumber generated by the graphics producer to mimic BufferQueue behaviour.
@@ -621,14 +627,13 @@
 class TransactionCompletedListener : public BnTransactionCompletedListener {
     TransactionCompletedListener();
 
-    CallbackId getNextIdLocked() REQUIRES(mMutex);
+    int64_t getNextIdLocked() REQUIRES(mMutex);
 
     std::mutex mMutex;
 
     bool mListening GUARDED_BY(mMutex) = false;
 
-    CallbackId mCallbackIdCounter GUARDED_BY(mMutex) = 1;
-
+    int64_t mCallbackIdCounter GUARDED_BY(mMutex) = 1;
     struct CallbackTranslation {
         TransactionCompletedCallback callbackFunction;
         std::unordered_map<sp<IBinder>, sp<SurfaceControl>, SurfaceComposerClient::IBinderHash>
@@ -646,7 +651,8 @@
         SurfaceStatsCallback callback;
     };
 
-    std::unordered_map<CallbackId, CallbackTranslation> mCallbacks GUARDED_BY(mMutex);
+    std::unordered_map<CallbackId, CallbackTranslation, CallbackIdHash> mCallbacks
+            GUARDED_BY(mMutex);
     std::multimap<sp<IBinder>, sp<JankDataListener>> mJankListeners GUARDED_BY(mMutex);
     std::unordered_map<uint64_t /* graphicsBufferId */, ReleaseBufferCallback>
             mReleaseBufferCallbacks GUARDED_BY(mMutex);
@@ -662,10 +668,12 @@
     CallbackId addCallbackFunction(
             const TransactionCompletedCallback& callbackFunction,
             const std::unordered_set<sp<SurfaceControl>, SurfaceComposerClient::SCHash>&
-                    surfaceControls);
+                    surfaceControls,
+            CallbackId::Type callbackType);
 
-    void addSurfaceControlToCallbacks(const sp<SurfaceControl>& surfaceControl,
-                                      const std::unordered_set<CallbackId>& callbackIds);
+    void addSurfaceControlToCallbacks(
+            const sp<SurfaceControl>& surfaceControl,
+            const std::unordered_set<CallbackId, CallbackIdHash>& callbackIds);
 
     /*
      * Adds a jank listener to be informed about SurfaceFlinger's jank classification for a specific
diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp
index d63c88b..34ef0a4 100644
--- a/libs/renderengine/tests/RenderEngineTest.cpp
+++ b/libs/renderengine/tests/RenderEngineTest.cpp
@@ -1402,7 +1402,8 @@
     fillBufferColorTransformZeroLayerAlpha<ColorSourceVariant>();
 }
 
-TEST_P(RenderEngineTest, drawLayers_fillBufferAndBlurBackground_colorSource) {
+// TODO(b/186010146): reenable once swiftshader is happy with this test
+TEST_P(RenderEngineTest, DISABLED_drawLayers_fillBufferAndBlurBackground_colorSource) {
     initializeRenderEngine();
     fillBufferAndBlurBackground<ColorSourceVariant>();
 }
@@ -1477,7 +1478,8 @@
     fillBufferColorTransformZeroLayerAlpha<BufferSourceVariant<ForceOpaqueBufferVariant>>();
 }
 
-TEST_P(RenderEngineTest, drawLayers_fillBufferAndBlurBackground_opaqueBufferSource) {
+// TODO(b/186010146): reenable once swiftshader is happy with this test
+TEST_P(RenderEngineTest, DISABLED_drawLayers_fillBufferAndBlurBackground_opaqueBufferSource) {
     initializeRenderEngine();
     fillBufferAndBlurBackground<BufferSourceVariant<ForceOpaqueBufferVariant>>();
 }
@@ -1552,7 +1554,8 @@
     fillBufferColorTransformZeroLayerAlpha<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
 }
 
-TEST_P(RenderEngineTest, drawLayers_fillBufferAndBlurBackground_bufferSource) {
+// TODO(b/186010146): reenable once swiftshader is happy with this test
+TEST_P(RenderEngineTest, DISABLED_drawLayers_fillBufferAndBlurBackground_bufferSource) {
     initializeRenderEngine();
     fillBufferAndBlurBackground<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
 }
diff --git a/libs/sensorprivacy/SensorPrivacyManager.cpp b/libs/sensorprivacy/SensorPrivacyManager.cpp
index 4714469..b3537ce 100644
--- a/libs/sensorprivacy/SensorPrivacyManager.cpp
+++ b/libs/sensorprivacy/SensorPrivacyManager.cpp
@@ -55,6 +55,22 @@
     return service;
 }
 
+bool SensorPrivacyManager::supportsSensorToggle(int sensor) {
+    if (mSupportedCache.find(sensor) == mSupportedCache.end()) {
+        sp<hardware::ISensorPrivacyManager> service = getService();
+        if (service != nullptr) {
+            bool result;
+            service->supportsSensorToggle(sensor, &result);
+            mSupportedCache[sensor] = result;
+            return result;
+        }
+        // if the SensorPrivacyManager is not available then assume sensor privacy feature isn't
+        // supported
+        return false;
+    }
+    return mSupportedCache[sensor];
+}
+
 void SensorPrivacyManager::addSensorPrivacyListener(
         const sp<hardware::ISensorPrivacyListener>& listener)
 {
diff --git a/libs/sensorprivacy/aidl/android/hardware/ISensorPrivacyManager.aidl b/libs/sensorprivacy/aidl/android/hardware/ISensorPrivacyManager.aidl
index 629b8c2..c8ceeb8 100644
--- a/libs/sensorprivacy/aidl/android/hardware/ISensorPrivacyManager.aidl
+++ b/libs/sensorprivacy/aidl/android/hardware/ISensorPrivacyManager.aidl
@@ -20,6 +20,8 @@
 
 /** @hide */
 interface ISensorPrivacyManager {
+    boolean supportsSensorToggle(int sensor);
+
     void addSensorPrivacyListener(in ISensorPrivacyListener listener);
 
     void addIndividualSensorPrivacyListener(int userId, int sensor, in ISensorPrivacyListener listener);
diff --git a/libs/sensorprivacy/include/sensorprivacy/SensorPrivacyManager.h b/libs/sensorprivacy/include/sensorprivacy/SensorPrivacyManager.h
index 12778e1..fb4cbe9 100644
--- a/libs/sensorprivacy/include/sensorprivacy/SensorPrivacyManager.h
+++ b/libs/sensorprivacy/include/sensorprivacy/SensorPrivacyManager.h
@@ -22,6 +22,8 @@
 
 #include <utils/threads.h>
 
+#include <unordered_map>
+
 // ---------------------------------------------------------------------------
 namespace android {
 
@@ -35,6 +37,7 @@
 
     SensorPrivacyManager();
 
+    bool supportsSensorToggle(int sensor);
     void addSensorPrivacyListener(const sp<hardware::ISensorPrivacyListener>& listener);
     status_t addIndividualSensorPrivacyListener(int userId, int sensor,
             const sp<hardware::ISensorPrivacyListener>& listener);
@@ -50,6 +53,8 @@
     Mutex mLock;
     sp<hardware::ISensorPrivacyManager> mService;
     sp<hardware::ISensorPrivacyManager> getService();
+
+    std::unordered_map<int, bool> mSupportedCache;
 };
 
 
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index a2915c9..7a5b20d 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -674,6 +674,11 @@
                                           latchTime);
     }
 
+    std::deque<sp<CallbackHandle>> remainingHandles;
+    mFlinger->getTransactionCallbackInvoker()
+            .finalizeOnCommitCallbackHandles(mDrawingState.callbackHandles, remainingHandles);
+    mDrawingState.callbackHandles = remainingHandles;
+
     mCurrentStateModified = false;
 
     return NO_ERROR;
diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
index 7468ac3..be552c6 100644
--- a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
+++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
@@ -653,8 +653,10 @@
             // If prediction is expired, we can't use the predicted start time. Instead, just use a
             // start time a little earlier than the end time so that we have some info about this
             // frame in the trace.
+            nsecs_t endTime =
+                    (mPresentState == PresentState::Dropped ? mDropTime : mActuals.endTime);
             packet->set_timestamp(
-                    static_cast<uint64_t>(mActuals.endTime - kPredictionExpiredStartTimeDelta));
+                    static_cast<uint64_t>(endTime - kPredictionExpiredStartTimeDelta));
         } else {
             packet->set_timestamp(static_cast<uint64_t>(mPredictions.startTime));
         }
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 9da23a6..b048682 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -2034,6 +2034,9 @@
     ATRACE_CALL();
     bool refreshNeeded = handlePageFlip();
 
+    // Send on commit callbacks
+    mTransactionCallbackInvoker.sendCallbacks();
+
     if (mVisibleRegionsDirty) {
         computeLayerBounds();
     }
@@ -3763,14 +3766,30 @@
 uint32_t SurfaceFlinger::setClientStateLocked(
         const FrameTimelineInfo& frameTimelineInfo, const ComposerState& composerState,
         int64_t desiredPresentTime, bool isAutoTimestamp, int64_t postTime, uint32_t permissions,
-        std::unordered_set<ListenerCallbacks, ListenerCallbacksHash>& listenerCallbacks) {
+        std::unordered_set<ListenerCallbacks, ListenerCallbacksHash>& outListenerCallbacks) {
     const layer_state_t& s = composerState.state;
     const bool privileged = permissions & Permission::ACCESS_SURFACE_FLINGER;
+
+    std::vector<ListenerCallbacks> filteredListeners;
     for (auto& listener : s.listeners) {
+        // Starts a registration but separates the callback ids according to callback type. This
+        // allows the callback invoker to send on latch callbacks earlier.
         // note that startRegistration will not re-register if the listener has
         // already be registered for a prior surface control
-        mTransactionCallbackInvoker.startRegistration(listener);
-        listenerCallbacks.insert(listener);
+
+        ListenerCallbacks onCommitCallbacks = listener.filter(CallbackId::Type::ON_COMMIT);
+        if (!onCommitCallbacks.callbackIds.empty()) {
+            mTransactionCallbackInvoker.startRegistration(onCommitCallbacks);
+            filteredListeners.push_back(onCommitCallbacks);
+            outListenerCallbacks.insert(onCommitCallbacks);
+        }
+
+        ListenerCallbacks onCompleteCallbacks = listener.filter(CallbackId::Type::ON_COMPLETE);
+        if (!onCompleteCallbacks.callbackIds.empty()) {
+            mTransactionCallbackInvoker.startRegistration(onCompleteCallbacks);
+            filteredListeners.push_back(onCompleteCallbacks);
+            outListenerCallbacks.insert(onCompleteCallbacks);
+        }
     }
 
     const uint64_t what = s.what;
@@ -4031,8 +4050,8 @@
         }
     }
     std::vector<sp<CallbackHandle>> callbackHandles;
-    if ((what & layer_state_t::eHasListenerCallbacksChanged) && (!s.listeners.empty())) {
-        for (auto& [listener, callbackIds] : s.listeners) {
+    if ((what & layer_state_t::eHasListenerCallbacksChanged) && (!filteredListeners.empty())) {
+        for (auto& [listener, callbackIds] : filteredListeners) {
             callbackHandles.emplace_back(new CallbackHandle(listener, callbackIds, s.surface));
         }
     }
@@ -5095,17 +5114,15 @@
         // captureLayers and captureDisplay will handle the permission check in the function
         case CAPTURE_LAYERS:
         case CAPTURE_DISPLAY:
-        case SET_DISPLAY_BRIGHTNESS:
         case SET_FRAME_TIMELINE_INFO:
         case GET_GPU_CONTEXT_PRIORITY:
         case GET_EXTRA_BUFFER_COUNT: {
             // This is not sensitive information, so should not require permission control.
             return OK;
         }
+        case SET_DISPLAY_BRIGHTNESS:
         case ADD_HDR_LAYER_INFO_LISTENER:
         case REMOVE_HDR_LAYER_INFO_LISTENER: {
-            // TODO (b/183985553): Should getting & setting brightness be part of this...?
-            // codes that require permission check
             IPCThreadState* ipc = IPCThreadState::self();
             const int pid = ipc->getCallingPid();
             const int uid = ipc->getCallingUid();
diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp
index 16c6bb3..3d82afa 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.cpp
+++ b/services/surfaceflinger/TimeStats/TimeStats.cpp
@@ -745,7 +745,7 @@
 static const constexpr int32_t kValidJankyReason = JankType::DisplayHAL |
         JankType::SurfaceFlingerCpuDeadlineMissed | JankType::SurfaceFlingerGpuDeadlineMissed |
         JankType::AppDeadlineMissed | JankType::PredictionError |
-        JankType::SurfaceFlingerScheduling | JankType::BufferStuffing;
+        JankType::SurfaceFlingerScheduling;
 
 template <class T>
 static void updateJankPayload(T& t, int32_t reasons) {
@@ -771,9 +771,11 @@
         if ((reasons & JankType::SurfaceFlingerScheduling) != 0) {
             t.jankPayload.totalSFScheduling++;
         }
-        if ((reasons & JankType::BufferStuffing) != 0) {
-            t.jankPayload.totalAppBufferStuffing++;
-        }
+    }
+
+    // We want to track BufferStuffing separately as it can provide info on latency issues
+    if (reasons & JankType::BufferStuffing) {
+        t.jankPayload.totalAppBufferStuffing++;
     }
 }
 
diff --git a/services/surfaceflinger/TransactionCallbackInvoker.cpp b/services/surfaceflinger/TransactionCallbackInvoker.cpp
index 3590e76..4f4c02b 100644
--- a/services/surfaceflinger/TransactionCallbackInvoker.cpp
+++ b/services/surfaceflinger/TransactionCallbackInvoker.cpp
@@ -36,13 +36,17 @@
 //         <0 if the first id that doesn't match is lower in c2 or all ids match but c2 is shorter
 //         >0 if the first id that doesn't match is greater in c2 or all ids match but c2 is longer
 //
-// See CallbackIdsHash for a explaniation of why this works
+// See CallbackIdsHash for a explanation of why this works
 static int compareCallbackIds(const std::vector<CallbackId>& c1,
                               const std::vector<CallbackId>& c2) {
     if (c1.empty()) {
         return !c2.empty();
     }
-    return c1.front() - c2.front();
+    return c1.front().id - c2.front().id;
+}
+
+static bool containsOnCommitCallbacks(const std::vector<CallbackId>& callbacks) {
+    return !callbacks.empty() && callbacks.front().type == CallbackId::Type::ON_COMMIT;
 }
 
 TransactionCallbackInvoker::~TransactionCallbackInvoker() {
@@ -114,39 +118,69 @@
     return NO_ERROR;
 }
 
+status_t TransactionCallbackInvoker::finalizeCallbackHandle(const sp<CallbackHandle>& handle,
+                                                            const std::vector<JankData>& jankData) {
+    auto listener = mPendingTransactions.find(handle->listener);
+    if (listener != mPendingTransactions.end()) {
+        auto& pendingCallbacks = listener->second;
+        auto pendingCallback = pendingCallbacks.find(handle->callbackIds);
+
+        if (pendingCallback != pendingCallbacks.end()) {
+            auto& pendingCount = pendingCallback->second;
+
+            // Decrease the pending count for this listener
+            if (--pendingCount == 0) {
+                pendingCallbacks.erase(pendingCallback);
+            }
+        } else {
+            ALOGW("there are more latched callbacks than there were registered callbacks");
+        }
+        if (listener->second.size() == 0) {
+            mPendingTransactions.erase(listener);
+        }
+    } else {
+        ALOGW("cannot find listener in mPendingTransactions");
+    }
+
+    status_t err = addCallbackHandle(handle, jankData);
+    if (err != NO_ERROR) {
+        ALOGE("could not add callback handle");
+        return err;
+    }
+    return NO_ERROR;
+}
+
+status_t TransactionCallbackInvoker::finalizeOnCommitCallbackHandles(
+        const std::deque<sp<CallbackHandle>>& handles,
+        std::deque<sp<CallbackHandle>>& outRemainingHandles) {
+    if (handles.empty()) {
+        return NO_ERROR;
+    }
+    std::lock_guard lock(mMutex);
+    const std::vector<JankData>& jankData = std::vector<JankData>();
+    for (const auto& handle : handles) {
+        if (!containsOnCommitCallbacks(handle->callbackIds)) {
+            outRemainingHandles.push_back(handle);
+            continue;
+        }
+        status_t err = finalizeCallbackHandle(handle, jankData);
+        if (err != NO_ERROR) {
+            return err;
+        }
+    }
+
+    return NO_ERROR;
+}
+
 status_t TransactionCallbackInvoker::finalizePendingCallbackHandles(
         const std::deque<sp<CallbackHandle>>& handles, const std::vector<JankData>& jankData) {
     if (handles.empty()) {
         return NO_ERROR;
     }
     std::lock_guard lock(mMutex);
-
     for (const auto& handle : handles) {
-        auto listener = mPendingTransactions.find(handle->listener);
-        if (listener != mPendingTransactions.end()) {
-            auto& pendingCallbacks = listener->second;
-            auto pendingCallback = pendingCallbacks.find(handle->callbackIds);
-
-            if (pendingCallback != pendingCallbacks.end()) {
-                auto& pendingCount = pendingCallback->second;
-
-                // Decrease the pending count for this listener
-                if (--pendingCount == 0) {
-                    pendingCallbacks.erase(pendingCallback);
-                }
-            } else {
-                ALOGW("there are more latched callbacks than there were registered callbacks");
-            }
-            if (listener->second.size() == 0) {
-                mPendingTransactions.erase(listener);
-            }
-        } else {
-            ALOGW("cannot find listener in mPendingTransactions");
-        }
-
-        status_t err = addCallbackHandle(handle, jankData);
+        status_t err = finalizeCallbackHandle(handle, jankData);
         if (err != NO_ERROR) {
-            ALOGE("could not add callback handle");
             return err;
         }
     }
@@ -243,7 +277,8 @@
             }
 
             // If the transaction has been latched
-            if (transactionStats.latchTime >= 0) {
+            if (transactionStats.latchTime >= 0 &&
+                !containsOnCommitCallbacks(transactionStats.callbackIds)) {
                 if (!mPresentFence) {
                     break;
                 }
diff --git a/services/surfaceflinger/TransactionCallbackInvoker.h b/services/surfaceflinger/TransactionCallbackInvoker.h
index caa8a4f..184b151 100644
--- a/services/surfaceflinger/TransactionCallbackInvoker.h
+++ b/services/surfaceflinger/TransactionCallbackInvoker.h
@@ -74,6 +74,8 @@
     // Notifies the TransactionCallbackInvoker that a pending CallbackHandle has been presented.
     status_t finalizePendingCallbackHandles(const std::deque<sp<CallbackHandle>>& handles,
                                             const std::vector<JankData>& jankData);
+    status_t finalizeOnCommitCallbackHandles(const std::deque<sp<CallbackHandle>>& handles,
+                                             std::deque<sp<CallbackHandle>>& outRemainingHandles);
 
     // Adds the Transaction CallbackHandle from a layer that does not need to be relatched and
     // presented this frame.
@@ -95,6 +97,9 @@
     status_t addCallbackHandle(const sp<CallbackHandle>& handle,
                                const std::vector<JankData>& jankData) REQUIRES(mMutex);
 
+    status_t finalizeCallbackHandle(const sp<CallbackHandle>& handle,
+                                    const std::vector<JankData>& jankData) REQUIRES(mMutex);
+
     class CallbackDeathRecipient : public IBinder::DeathRecipient {
     public:
         // This function is a no-op. isBinderAlive needs a linked DeathRecipient to work.
diff --git a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
index 7727052..8a3f561 100644
--- a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
+++ b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
@@ -1347,6 +1347,81 @@
     validateTraceEvent(actualSurfaceFrameEnd, protoActualSurfaceFrameEnd);
 }
 
+TEST_F(FrameTimelineTest, traceSurfaceFrame_predictionExpiredDroppedFramesTracedProperly) {
+    auto tracingSession = getTracingSessionForTest();
+    auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+
+    tracingSession->StartBlocking();
+    constexpr nsecs_t appStartTime = std::chrono::nanoseconds(10ms).count();
+    constexpr nsecs_t appEndTime = std::chrono::nanoseconds(20ms).count();
+    constexpr nsecs_t appPresentTime = std::chrono::nanoseconds(30ms).count();
+    int64_t surfaceFrameToken =
+            mTokenManager->generateTokenForPredictions({appStartTime, appEndTime, appPresentTime});
+
+    // Flush the token so that it would expire
+    flushTokens(systemTime() + maxTokenRetentionTime);
+    auto surfaceFrame1 =
+            mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, /*inputEventId*/ 0},
+                                                       sPidOne, sUidOne, sLayerIdOne, sLayerNameOne,
+                                                       sLayerNameOne, /*isBuffer*/ true);
+
+    constexpr nsecs_t sfStartTime = std::chrono::nanoseconds(22ms).count();
+    constexpr nsecs_t sfEndTime = std::chrono::nanoseconds(30ms).count();
+    constexpr nsecs_t sfPresentTime = std::chrono::nanoseconds(30ms).count();
+    int64_t displayFrameToken =
+            mTokenManager->generateTokenForPredictions({sfStartTime, sfEndTime, sfPresentTime});
+
+    // First 2 cookies will be used by the DisplayFrame
+    int64_t traceCookie = snoopCurrentTraceCookie() + 2;
+
+    auto protoActualSurfaceFrameStart =
+            createProtoActualSurfaceFrameStart(traceCookie + 1, surfaceFrameToken,
+                                               displayFrameToken, sPidOne, sLayerNameOne,
+                                               FrameTimelineEvent::PRESENT_DROPPED, false, false,
+                                               FrameTimelineEvent::JANK_NONE,
+                                               FrameTimelineEvent::PREDICTION_EXPIRED);
+    auto protoActualSurfaceFrameEnd = createProtoFrameEnd(traceCookie + 1);
+
+    // Set up the display frame
+    mFrameTimeline->setSfWakeUp(displayFrameToken, sfStartTime, Fps::fromPeriodNsecs(11));
+    surfaceFrame1->setDropTime(sfStartTime);
+    surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Dropped);
+    mFrameTimeline->addSurfaceFrame(surfaceFrame1);
+    mFrameTimeline->setSfPresent(sfEndTime, presentFence1);
+    presentFence1->signalForTest(sfPresentTime);
+
+    addEmptyDisplayFrame();
+    flushTrace();
+    tracingSession->StopBlocking();
+
+    auto packets = readFrameTimelinePacketsBlocking(tracingSession.get());
+    // Display Frame 4 packets + SurfaceFrame 2 packets
+    ASSERT_EQ(packets.size(), 6u);
+
+    // Packet - 4 : ActualSurfaceFrameStart
+    const auto& packet4 = packets[4];
+    ASSERT_TRUE(packet4.has_timestamp());
+    EXPECT_EQ(packet4.timestamp(),
+              static_cast<uint64_t>(sfStartTime - SurfaceFrame::kPredictionExpiredStartTimeDelta));
+    ASSERT_TRUE(packet4.has_frame_timeline_event());
+
+    const auto& event4 = packet4.frame_timeline_event();
+    ASSERT_TRUE(event4.has_actual_surface_frame_start());
+    const auto& actualSurfaceFrameStart = event4.actual_surface_frame_start();
+    validateTraceEvent(actualSurfaceFrameStart, protoActualSurfaceFrameStart);
+
+    // Packet - 5 : FrameEnd (ActualSurfaceFrame)
+    const auto& packet5 = packets[5];
+    ASSERT_TRUE(packet5.has_timestamp());
+    EXPECT_EQ(packet5.timestamp(), static_cast<uint64_t>(sfStartTime));
+    ASSERT_TRUE(packet5.has_frame_timeline_event());
+
+    const auto& event5 = packet5.frame_timeline_event();
+    ASSERT_TRUE(event5.has_frame_end());
+    const auto& actualSurfaceFrameEnd = event5.frame_end();
+    validateTraceEvent(actualSurfaceFrameEnd, protoActualSurfaceFrameEnd);
+}
+
 // Tests for Jank classification
 TEST_F(FrameTimelineTest, jankClassification_presentOnTimeDoesNotClassify) {
     // Layer specific increment
diff --git a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
index 4e73cbc..188ea75 100644
--- a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
@@ -1051,6 +1051,8 @@
                                       JankType::AppDeadlineMissed | JankType::BufferStuffing, 1, 2,
                                       3});
     mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+                                      JankType::BufferStuffing, 1, 2, 3});
+    mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
                                       JankType::None, 1, 2, 3});
 
     std::string pulledData;
@@ -1069,7 +1071,7 @@
     EXPECT_EQ(atom.event_connection_count(), DISPLAY_EVENT_CONNECTIONS);
     EXPECT_THAT(atom.frame_duration(), HistogramEq(buildExpectedHistogram({2}, {1})));
     EXPECT_THAT(atom.render_engine_timing(), HistogramEq(buildExpectedHistogram({1, 2}, {1, 1})));
-    EXPECT_EQ(atom.total_timeline_frames(), 8);
+    EXPECT_EQ(atom.total_timeline_frames(), 9);
     EXPECT_EQ(atom.total_janky_frames(), 7);
     EXPECT_EQ(atom.total_janky_frames_with_long_cpu(), 1);
     EXPECT_EQ(atom.total_janky_frames_with_long_gpu(), 1);
@@ -1077,7 +1079,7 @@
     EXPECT_EQ(atom.total_janky_frames_app_unattributed(), 2);
     EXPECT_EQ(atom.total_janky_frames_sf_scheduling(), 1);
     EXPECT_EQ(atom.total_jank_frames_sf_prediction_error(), 1);
-    EXPECT_EQ(atom.total_jank_frames_app_buffer_stuffing(), 1);
+    EXPECT_EQ(atom.total_jank_frames_app_buffer_stuffing(), 2);
     EXPECT_EQ(atom.display_refresh_rate_bucket(), REFRESH_RATE_BUCKET_0);
     EXPECT_THAT(atom.sf_deadline_misses(), HistogramEq(buildExpectedHistogram({1}, {7})));
     EXPECT_THAT(atom.sf_prediction_errors(), HistogramEq(buildExpectedHistogram({2}, {7})));
@@ -1096,7 +1098,7 @@
     const std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING));
     std::string expectedResult = "totalTimelineFrames = " + std::to_string(0);
     EXPECT_THAT(result, HasSubstr(expectedResult));
-    expectedResult = "totalTimelineFrames = " + std::to_string(8);
+    expectedResult = "totalTimelineFrames = " + std::to_string(9);
     EXPECT_THAT(result, HasSubstr(expectedResult));
     expectedResult = "jankyFrames = " + std::to_string(0);
     EXPECT_THAT(result, HasSubstr(expectedResult));
@@ -1128,7 +1130,7 @@
     EXPECT_THAT(result, HasSubstr(expectedResult));
     expectedResult = "appBufferStuffingJankyFrames = " + std::to_string(0);
     EXPECT_THAT(result, HasSubstr(expectedResult));
-    expectedResult = "appBufferStuffingJankyFrames = " + std::to_string(1);
+    expectedResult = "appBufferStuffingJankyFrames = " + std::to_string(2);
     EXPECT_THAT(result, HasSubstr(expectedResult));
 }