Merge "Revert "Fix ping pong progress in the Kawase implementation."" into main
diff --git a/cmds/dumpstate/Android.bp b/cmds/dumpstate/Android.bp
index 23f33d8..4a77967 100644
--- a/cmds/dumpstate/Android.bp
+++ b/cmds/dumpstate/Android.bp
@@ -79,7 +79,10 @@
 
 cc_defaults {
     name: "dumpstate_defaults",
-    defaults: ["dumpstate_cflag_defaults"],
+    defaults: [
+        "aconfig_lib_cc_static_link.defaults",
+        "dumpstate_cflag_defaults",
+    ],
     shared_libs: [
         "android.hardware.dumpstate@1.0",
         "android.hardware.dumpstate@1.1",
diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp
index a5c0c60..95a05cd 100644
--- a/cmds/servicemanager/ServiceManager.cpp
+++ b/cmds/servicemanager/ServiceManager.cpp
@@ -790,7 +790,8 @@
 
     if (OK !=
         IInterface::asBinder(cb)->linkToDeath(sp<ServiceManager>::fromExisting(this))) {
-        ALOGE("%s Could not linkToDeath when adding client callback for %s", name.c_str());
+        ALOGE("%s Could not linkToDeath when adding client callback for %s",
+              ctx.toDebugString().c_str(), name.c_str());
         return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE, "Couldn't linkToDeath.");
     }
 
diff --git a/include/android/choreographer.h b/include/android/choreographer.h
index f999708..6a91d98 100644
--- a/include/android/choreographer.h
+++ b/include/android/choreographer.h
@@ -17,8 +17,20 @@
 /**
  * @addtogroup Choreographer
  *
- * Choreographer coordinates the timing of frame rendering. This is the C version of the
- * android.view.Choreographer object in Java.
+ * Choreographer coordinates the timing of frame rendering. This is the C
+ * version of the android.view.Choreographer object in Java. If you do not use
+ * Choreographer to pace your render loop, you may render too quickly for the
+ * display, increasing latency between frame submission and presentation.
+ *
+ * Input events are guaranteed to be processed before the frame callback is
+ * called, and will not be run concurrently. Input and sensor events should not
+ * be handled in the Choregrapher callback.
+ *
+ * The frame callback is also the appropriate place to run any per-frame state
+ * update logic. For example, in a game, the frame callback should be
+ * responsible for updating things like physics, AI, game state, and rendering
+ * the frame. Input and sensors should be handled separately via callbacks
+ * registered with AInputQueue and ASensorManager.
  *
  * As of API level 33, apps can follow proper frame pacing and even choose a future frame to render.
  * The API is used as follows:
@@ -38,6 +50,11 @@
  * 4. SurfaceFlinger attempts to follow the chosen frame timeline, by not applying transactions or
  * latching buffers before the desired presentation time.
  *
+ * On older devices, AChoreographer_postFrameCallback64 or
+ * AChoreographer_postFrameCallback can be used to lesser effect. They cannot be
+ * used to precisely plan your render timeline, but will rate limit to avoid
+ * overloading the display pipeline and increasing frame latency.
+ *
  * @{
  */
 
@@ -119,23 +136,60 @@
 AChoreographer* AChoreographer_getInstance() __INTRODUCED_IN(24);
 
 /**
- * Deprecated: Use AChoreographer_postFrameCallback64 instead.
+ * Post a callback to be run when the application should begin rendering the
+ * next frame. The data pointer provided will be passed to the callback function
+ * when it's called.
+ *
+ * The callback will only be run for the next frame, not all subsequent frames,
+ * so to render continuously the callback should itself call
+ * AChoreographer_postFrameCallback.
+ *
+ * \bug The callback receives the frame time in nanoseconds as a long. On 32-bit
+ * systems, long is 32-bit, so the frame time will roll over roughly every two
+ * seconds. If your minSdkVersion is 29 or higher, switch to
+ * AChoreographer_postFrameCallback64, which uses a 64-bit frame time for all
+ * platforms. For older OS versions, you must combine the argument with the
+ * upper bits of clock_gettime(CLOCK_MONOTONIC, ...) on 32-bit systems.
+ *
+ * \deprecated Use AChoreographer_postFrameCallback64, which does not have the
+ * bug described above.
  */
 void AChoreographer_postFrameCallback(AChoreographer* choreographer,
                                       AChoreographer_frameCallback callback, void* data)
-        __INTRODUCED_IN(24) __DEPRECATED_IN(29);
+        __INTRODUCED_IN(24) __DEPRECATED_IN(29, "Use AChoreographer_postFrameCallback64 instead");
 
 /**
- * Deprecated: Use AChoreographer_postFrameCallbackDelayed64 instead.
+ * Post a callback to be run when the application should begin rendering the
+ * next frame following the specified delay. The data pointer provided will be
+ * passed to the callback function when it's called.
+ *
+ * The callback will only be run for the next frame after the delay, not all
+ * subsequent frames, so to render continuously the callback should itself call
+ * AChoreographer_postFrameCallbackDelayed.
+ *
+ * \bug The callback receives the frame time in nanoseconds as a long. On 32-bit
+ * systems, long is 32-bit, so the frame time will roll over roughly every two
+ * seconds. If your minSdkVersion is 29 or higher, switch to
+ * AChoreographer_postFrameCallbackDelayed64, which uses a 64-bit frame time for
+ * all platforms. For older OS versions, you must combine the argument with the
+ * upper bits of clock_gettime(CLOCK_MONOTONIC, ...) on 32-bit systems.
+ *
+ * \deprecated Use AChoreographer_postFrameCallbackDelayed64, which does not
+ * have the bug described above.
  */
 void AChoreographer_postFrameCallbackDelayed(AChoreographer* choreographer,
                                              AChoreographer_frameCallback callback, void* data,
                                              long delayMillis) __INTRODUCED_IN(24)
-        __DEPRECATED_IN(29);
+        __DEPRECATED_IN(29, "Use AChoreographer_postFrameCallbackDelayed64 instead");
 
 /**
- * Post a callback to be run on the next frame.  The data pointer provided will
- * be passed to the callback function when it's called.
+ * Post a callback to be run when the application should begin rendering the
+ * next frame. The data pointer provided will be passed to the callback function
+ * when it's called.
+ *
+ * The callback will only be run on the next frame, not all subsequent frames,
+ * so to render continuously the callback should itself call
+ * AChoreographer_postFrameCallback64.
  *
  * Available since API level 29.
  */
@@ -144,9 +198,13 @@
         __INTRODUCED_IN(29);
 
 /**
- * Post a callback to be run on the frame following the specified delay.  The
- * data pointer provided will be passed to the callback function when it's
- * called.
+ * Post a callback to be run when the application should begin rendering the
+ * next frame following the specified delay. The data pointer provided will be
+ * passed to the callback function when it's called.
+ *
+ * The callback will only be run for the next frame after the delay, not all
+ * subsequent frames, so to render continuously the callback should itself call
+ * AChoreographer_postFrameCallbackDelayed64.
  *
  * Available since API level 29.
  */
@@ -155,8 +213,13 @@
                                                uint32_t delayMillis) __INTRODUCED_IN(29);
 
 /**
- * Posts a callback to be run on the next frame. The data pointer provided will
- * be passed to the callback function when it's called.
+ * Posts a callback to be run when the application should begin rendering the
+ * next frame. The data pointer provided will be passed to the callback function
+ * when it's called.
+ *
+ * The callback will only be run for the next frame, not all subsequent frames,
+ * so to render continuously the callback should itself call
+ * AChoreographer_postVsyncCallback.
  *
  * Available since API level 33.
  */
diff --git a/include/android/looper.h b/include/android/looper.h
index e50730d..d80a366 100644
--- a/include/android/looper.h
+++ b/include/android/looper.h
@@ -35,7 +35,7 @@
 // This file may also be built on glibc or on Windows/MacOS libc's, so
 // deprecated definitions are provided.
 #if !defined(__REMOVED_IN)
-#define __REMOVED_IN(__api_level) __attribute__((__deprecated__))
+#define __REMOVED_IN(__api_level, msg) __attribute__((__deprecated__(msg)))
 #endif
 
 struct ALooper;
@@ -182,23 +182,27 @@
  * If the timeout is zero, returns immediately without blocking.
  * If the timeout is negative, waits indefinitely until an event appears.
  *
- * Returns ALOOPER_POLL_WAKE if the poll was awoken using wake() before
+ * Returns ALOOPER_POLL_WAKE if the poll was awoken using ALooper_wake() before
  * the timeout expired and no callbacks were invoked and no other file
- * descriptors were ready.
+ * descriptors were ready. **All return values may also imply
+ * ALOOPER_POLL_WAKE.**
  *
- * Returns ALOOPER_POLL_CALLBACK if one or more callbacks were invoked.
+ * Returns ALOOPER_POLL_CALLBACK if one or more callbacks were invoked. The poll
+ * may also have been explicitly woken by ALooper_wake.
  *
- * Returns ALOOPER_POLL_TIMEOUT if there was no data before the given
- * timeout expired.
+ * Returns ALOOPER_POLL_TIMEOUT if there was no data before the given timeout
+ * expired. The poll may also have been explicitly woken by ALooper_wake.
  *
- * Returns ALOOPER_POLL_ERROR if an error occurred.
+ * Returns ALOOPER_POLL_ERROR if the calling thread has no associated Looper or
+ * for unrecoverable internal errors. The poll may also have been explicitly
+ * woken by ALooper_wake.
  *
- * Returns a value >= 0 containing an identifier (the same identifier
- * `ident` passed to ALooper_addFd()) if its file descriptor has data
- * and it has no callback function (requiring the caller here to
- * handle it).  In this (and only this) case outFd, outEvents and
- * outData will contain the poll events and data associated with the
- * fd, otherwise they will be set to NULL.
+ * Returns a value >= 0 containing an identifier (the same identifier `ident`
+ * passed to ALooper_addFd()) if its file descriptor has data and it has no
+ * callback function (requiring the caller here to handle it).  In this (and
+ * only this) case outFd, outEvents and outData will contain the poll events and
+ * data associated with the fd, otherwise they will be set to NULL. The poll may
+ * also have been explicitly woken by ALooper_wake.
  *
  * This method does not return until it has finished invoking the appropriate callbacks
  * for all file descriptors that were signalled.
@@ -210,10 +214,21 @@
  * data has been consumed or a file descriptor is available with no callback.
  * This function will never return ALOOPER_POLL_CALLBACK.
  *
- * Removed in API 34 as ALooper_pollAll can swallow ALooper_wake calls.
- * Use ALooper_pollOnce instead.
+ * This API cannot be used safely, but a safe alternative exists (see below). As
+ * such, new builds will not be able to call this API and must migrate to the
+ * safe API. Binary compatibility is preserved to support already-compiled apps.
+ *
+ * \bug ALooper_pollAll will not wake in response to ALooper_wake calls if it
+ * also handles another event at the same time.
+ *
+ * \deprecated Calls to ALooper_pollAll should be replaced with
+ * ALooper_pollOnce. If you call ALooper_pollOnce in a loop, you *must* treat
+ * all return values as if they also indicate ALOOPER_POLL_WAKE.
  */
-int ALooper_pollAll(int timeoutMillis, int* outFd, int* outEvents, void** outData) __REMOVED_IN(1);
+int ALooper_pollAll(int timeoutMillis, int* outFd, int* outEvents, void** outData)
+        __REMOVED_IN(1,
+                     "ALooper_pollAll may ignore wakes. Use ALooper_pollOnce instead. See "
+                     "The API documentation for more information");
 
 /**
  * Wakes the poll asynchronously.
diff --git a/include/android/sensor.h b/include/android/sensor.h
index a618393..e3c1ccf 100644
--- a/include/android/sensor.h
+++ b/include/android/sensor.h
@@ -60,7 +60,7 @@
 #define __INTRODUCED_IN(__api_level) /* nothing */
 #endif
 #if !defined(__DEPRECATED_IN)
-#define __DEPRECATED_IN(__api_level) __attribute__((__deprecated__))
+#define __DEPRECATED_IN(__api_level, msg) __attribute__((__deprecated__(msg)))
 #endif
 
 #ifdef __cplusplus
@@ -748,7 +748,8 @@
  *     ASensorManager* sensorManager = ASensorManager_getInstance();
  *
  */
-ASensorManager* ASensorManager_getInstance() __DEPRECATED_IN(26);
+ASensorManager* ASensorManager_getInstance()
+        __DEPRECATED_IN(26, "Use ASensorManager_getInstanceForPackage instead");
 
 /**
  * Get a reference to the sensor manager. ASensorManager is a singleton
diff --git a/include/android/surface_control.h b/include/android/surface_control.h
index 443cb7e..14167e6 100644
--- a/include/android/surface_control.h
+++ b/include/android/surface_control.h
@@ -62,16 +62,18 @@
  *
  * Available since API level 29.
  */
-ASurfaceControl* ASurfaceControl_createFromWindow(ANativeWindow* parent, const char* debug_name)
-                                                  __INTRODUCED_IN(29);
+ASurfaceControl* _Nullable ASurfaceControl_createFromWindow(ANativeWindow* _Nonnull parent,
+                                                            const char* _Nonnull debug_name)
+        __INTRODUCED_IN(29);
 
 /**
  * See ASurfaceControl_createFromWindow.
  *
  * Available since API level 29.
  */
-ASurfaceControl* ASurfaceControl_create(ASurfaceControl* parent, const char* debug_name)
-                                        __INTRODUCED_IN(29);
+ASurfaceControl* _Nullable ASurfaceControl_create(ASurfaceControl* _Nonnull parent,
+                                                  const char* _Nonnull debug_name)
+        __INTRODUCED_IN(29);
 
 /**
  * Acquires a reference on the given ASurfaceControl object.  This prevents the object
@@ -81,7 +83,7 @@
  *
  * Available since API level 31.
  */
-void ASurfaceControl_acquire(ASurfaceControl* surface_control) __INTRODUCED_IN(31);
+void ASurfaceControl_acquire(ASurfaceControl* _Nonnull surface_control) __INTRODUCED_IN(31);
 
 /**
  * Removes a reference that was previously acquired with one of the following functions:
@@ -92,7 +94,7 @@
  *
  * Available since API level 29.
  */
-void ASurfaceControl_release(ASurfaceControl* surface_control) __INTRODUCED_IN(29);
+void ASurfaceControl_release(ASurfaceControl* _Nonnull surface_control) __INTRODUCED_IN(29);
 
 struct ASurfaceTransaction;
 
@@ -108,14 +110,14 @@
  *
  * Available since API level 29.
  */
-ASurfaceTransaction* ASurfaceTransaction_create() __INTRODUCED_IN(29);
+ASurfaceTransaction* _Nonnull ASurfaceTransaction_create() __INTRODUCED_IN(29);
 
 /**
  * Destroys the \a transaction object.
  *
  * Available since API level 29.
  */
-void ASurfaceTransaction_delete(ASurfaceTransaction* transaction) __INTRODUCED_IN(29);
+void ASurfaceTransaction_delete(ASurfaceTransaction* _Nullable transaction) __INTRODUCED_IN(29);
 
 /**
  * Applies the updates accumulated in \a transaction.
@@ -126,7 +128,7 @@
  *
  * Available since API level 29.
  */
-void ASurfaceTransaction_apply(ASurfaceTransaction* transaction) __INTRODUCED_IN(29);
+void ASurfaceTransaction_apply(ASurfaceTransaction* _Nonnull transaction) __INTRODUCED_IN(29);
 
 /**
  * An opaque handle returned during a callback that can be used to query general stats and stats for
@@ -154,9 +156,9 @@
  *
  * Available since API level 29.
  */
-typedef void (*ASurfaceTransaction_OnComplete)(void* context, ASurfaceTransactionStats* stats)
-                                               __INTRODUCED_IN(29);
-
+typedef void (*ASurfaceTransaction_OnComplete)(void* _Null_unspecified context,
+                                               ASurfaceTransactionStats* _Nonnull stats)
+        __INTRODUCED_IN(29);
 
 /**
  * The ASurfaceTransaction_OnCommit callback is invoked when transaction is applied and the updates
@@ -183,8 +185,9 @@
  *
  * Available since API level 31.
  */
-typedef void (*ASurfaceTransaction_OnCommit)(void* context, ASurfaceTransactionStats* stats)
-                                               __INTRODUCED_IN(31);
+typedef void (*ASurfaceTransaction_OnCommit)(void* _Null_unspecified context,
+                                             ASurfaceTransactionStats* _Nonnull stats)
+        __INTRODUCED_IN(31);
 
 /**
  * Returns the timestamp of when the frame was latched by the framework. Once a frame is
@@ -192,8 +195,8 @@
  *
  * Available since API level 29.
  */
-int64_t ASurfaceTransactionStats_getLatchTime(ASurfaceTransactionStats* surface_transaction_stats)
-                                              __INTRODUCED_IN(29);
+int64_t ASurfaceTransactionStats_getLatchTime(
+        ASurfaceTransactionStats* _Nonnull surface_transaction_stats) __INTRODUCED_IN(29);
 
 /**
  * Returns a sync fence that signals when the transaction has been presented.
@@ -204,8 +207,8 @@
  *
  * Available since API level 29.
  */
-int ASurfaceTransactionStats_getPresentFenceFd(ASurfaceTransactionStats* surface_transaction_stats)
-                                               __INTRODUCED_IN(29);
+int ASurfaceTransactionStats_getPresentFenceFd(
+        ASurfaceTransactionStats* _Nonnull surface_transaction_stats) __INTRODUCED_IN(29);
 
 /**
  * \a outASurfaceControls returns an array of ASurfaceControl pointers that were updated during the
@@ -217,18 +220,18 @@
  *
  * \a outASurfaceControlsSize returns the size of the ASurfaceControls array.
  */
-void ASurfaceTransactionStats_getASurfaceControls(ASurfaceTransactionStats* surface_transaction_stats,
-                                                  ASurfaceControl*** outASurfaceControls,
-                                                  size_t* outASurfaceControlsSize)
-                                                  __INTRODUCED_IN(29);
+void ASurfaceTransactionStats_getASurfaceControls(
+        ASurfaceTransactionStats* _Nonnull surface_transaction_stats,
+        ASurfaceControl* _Nullable* _Nullable* _Nonnull outASurfaceControls,
+        size_t* _Nonnull outASurfaceControlsSize) __INTRODUCED_IN(29);
 /**
  * Releases the array of ASurfaceControls that were returned by
  * ASurfaceTransactionStats_getASurfaceControls().
  *
  * Available since API level 29.
  */
-void ASurfaceTransactionStats_releaseASurfaceControls(ASurfaceControl** surface_controls)
-                                                      __INTRODUCED_IN(29);
+void ASurfaceTransactionStats_releaseASurfaceControls(
+        ASurfaceControl* _Nonnull* _Nonnull surface_controls) __INTRODUCED_IN(29);
 
 /**
  * Returns the timestamp of when the CURRENT buffer was acquired. A buffer is considered
@@ -237,9 +240,9 @@
  *
  * Available since API level 29.
  */
-int64_t ASurfaceTransactionStats_getAcquireTime(ASurfaceTransactionStats* surface_transaction_stats,
-                                                ASurfaceControl* surface_control)
-                                                __INTRODUCED_IN(29);
+int64_t ASurfaceTransactionStats_getAcquireTime(
+        ASurfaceTransactionStats* _Nonnull surface_transaction_stats,
+        ASurfaceControl* _Nonnull surface_control) __INTRODUCED_IN(29);
 
 /**
  * The returns the fence used to signal the release of the PREVIOUS buffer set on
@@ -264,9 +267,8 @@
  * Available since API level 29.
  */
 int ASurfaceTransactionStats_getPreviousReleaseFenceFd(
-                                                ASurfaceTransactionStats* surface_transaction_stats,
-                                                ASurfaceControl* surface_control)
-                                                __INTRODUCED_IN(29);
+        ASurfaceTransactionStats* _Nonnull surface_transaction_stats,
+        ASurfaceControl* _Nonnull surface_control) __INTRODUCED_IN(29);
 
 /**
  * Sets the callback that will be invoked when the updates from this transaction
@@ -275,8 +277,10 @@
  *
  * Available since API level 29.
  */
-void ASurfaceTransaction_setOnComplete(ASurfaceTransaction* transaction, void* context,
-                                       ASurfaceTransaction_OnComplete func) __INTRODUCED_IN(29);
+void ASurfaceTransaction_setOnComplete(ASurfaceTransaction* _Nonnull transaction,
+                                       void* _Null_unspecified context,
+                                       ASurfaceTransaction_OnComplete _Nonnull func)
+        __INTRODUCED_IN(29);
 
 /**
  * Sets the callback that will be invoked when the updates from this transaction are applied and are
@@ -285,8 +289,10 @@
  *
  * Available since API level 31.
  */
-void ASurfaceTransaction_setOnCommit(ASurfaceTransaction* transaction, void* context,
-                                    ASurfaceTransaction_OnCommit func) __INTRODUCED_IN(31);
+void ASurfaceTransaction_setOnCommit(ASurfaceTransaction* _Nonnull transaction,
+                                     void* _Null_unspecified context,
+                                     ASurfaceTransaction_OnCommit _Nonnull func)
+        __INTRODUCED_IN(31);
 
 /**
  * Reparents the \a surface_control from its old parent to the \a new_parent surface control.
@@ -296,9 +302,9 @@
  *
  * Available since API level 29.
  */
-void ASurfaceTransaction_reparent(ASurfaceTransaction* transaction,
-                                  ASurfaceControl* surface_control, ASurfaceControl* new_parent)
-                                  __INTRODUCED_IN(29);
+void ASurfaceTransaction_reparent(ASurfaceTransaction* _Nonnull transaction,
+                                  ASurfaceControl* _Nonnull surface_control,
+                                  ASurfaceControl* _Nullable new_parent) __INTRODUCED_IN(29);
 
 /**
  * Parameter for ASurfaceTransaction_setVisibility().
@@ -314,10 +320,10 @@
  *
  * Available since API level 29.
  */
-void ASurfaceTransaction_setVisibility(ASurfaceTransaction* transaction,
-                                       ASurfaceControl* surface_control,
+void ASurfaceTransaction_setVisibility(ASurfaceTransaction* _Nonnull transaction,
+                                       ASurfaceControl* _Nonnull surface_control,
                                        enum ASurfaceTransactionVisibility visibility)
-                                       __INTRODUCED_IN(29);
+        __INTRODUCED_IN(29);
 
 /**
  * Updates the z order index for \a surface_control. Note that the z order for a surface
@@ -328,9 +334,9 @@
  *
  * Available since API level 29.
  */
-void ASurfaceTransaction_setZOrder(ASurfaceTransaction* transaction,
-                                   ASurfaceControl* surface_control, int32_t z_order)
-                                   __INTRODUCED_IN(29);
+void ASurfaceTransaction_setZOrder(ASurfaceTransaction* _Nonnull transaction,
+                                   ASurfaceControl* _Nonnull surface_control, int32_t z_order)
+        __INTRODUCED_IN(29);
 
 /**
  * Updates the AHardwareBuffer displayed for \a surface_control. If not -1, the
@@ -345,9 +351,10 @@
  *
  * Available since API level 29.
  */
-void ASurfaceTransaction_setBuffer(ASurfaceTransaction* transaction,
-                                   ASurfaceControl* surface_control, AHardwareBuffer* buffer,
-                                   int acquire_fence_fd) __INTRODUCED_IN(29);
+void ASurfaceTransaction_setBuffer(ASurfaceTransaction* _Nonnull transaction,
+                                   ASurfaceControl* _Nonnull surface_control,
+                                   AHardwareBuffer* _Nonnull buffer, int acquire_fence_fd)
+        __INTRODUCED_IN(29);
 
 /**
  * Updates the color for \a surface_control.  This will make the background color for the
@@ -357,23 +364,23 @@
  *
  * Available since API level 29.
  */
-void ASurfaceTransaction_setColor(ASurfaceTransaction* transaction,
-                                  ASurfaceControl* surface_control, float r, float g, float b,
-                                  float alpha, enum ADataSpace dataspace)
-                                  __INTRODUCED_IN(29);
+void ASurfaceTransaction_setColor(ASurfaceTransaction* _Nonnull transaction,
+                                  ASurfaceControl* _Nonnull surface_control, float r, float g,
+                                  float b, float alpha, enum ADataSpace dataspace)
+        __INTRODUCED_IN(29);
 
 /**
  * \param source The sub-rect within the buffer's content to be rendered inside the surface's area
  * The surface's source rect is clipped by the bounds of its current buffer. The source rect's width
  * and height must be > 0.
  *
- * \param destination Specifies the rect in the parent's space where this surface will be drawn. The post
- * source rect bounds are scaled to fit the destination rect. The surface's destination rect is
+ * \param destination Specifies the rect in the parent's space where this surface will be drawn. The
+ * post source rect bounds are scaled to fit the destination rect. The surface's destination rect is
  * clipped by the bounds of its parent. The destination rect's width and height must be > 0.
  *
- * \param transform The transform applied after the source rect is applied to the buffer. This parameter
- * should be set to 0 for no transform. To specify a transfrom use the NATIVE_WINDOW_TRANSFORM_*
- * enum.
+ * \param transform The transform applied after the source rect is applied to the buffer. This
+ * parameter should be set to 0 for no transform. To specify a transfrom use the
+ * NATIVE_WINDOW_TRANSFORM_* enum.
  *
  * Available since API level 29.
  *
@@ -382,10 +389,10 @@
  * to set different properties at different times, instead of having to specify all the desired
  * properties at once.
  */
-void ASurfaceTransaction_setGeometry(ASurfaceTransaction* transaction,
-                                     ASurfaceControl* surface_control, const ARect& source,
+void ASurfaceTransaction_setGeometry(ASurfaceTransaction* _Nonnull transaction,
+                                     ASurfaceControl* _Nonnull surface_control, const ARect& source,
                                      const ARect& destination, int32_t transform)
-                                     __INTRODUCED_IN(29);
+        __INTRODUCED_IN(29);
 
 /**
  * Bounds the surface and its children to the bounds specified. The crop and buffer size will be
@@ -396,9 +403,9 @@
  *
  * Available since API level 31.
  */
-void ASurfaceTransaction_setCrop(ASurfaceTransaction* transaction,
-                                       ASurfaceControl* surface_control, const ARect& crop)
-                                       __INTRODUCED_IN(31);
+void ASurfaceTransaction_setCrop(ASurfaceTransaction* _Nonnull transaction,
+                                 ASurfaceControl* _Nonnull surface_control, const ARect& crop)
+        __INTRODUCED_IN(31);
 
 /**
  * Specifies the position in the parent's space where the surface will be drawn.
@@ -408,9 +415,9 @@
  *
  * Available since API level 31.
  */
-void ASurfaceTransaction_setPosition(ASurfaceTransaction* transaction,
-                                     ASurfaceControl* surface_control, int32_t x, int32_t y)
-                                     __INTRODUCED_IN(31);
+void ASurfaceTransaction_setPosition(ASurfaceTransaction* _Nonnull transaction,
+                                     ASurfaceControl* _Nonnull surface_control, int32_t x,
+                                     int32_t y) __INTRODUCED_IN(31);
 
 /**
  * \param transform The transform applied after the source rect is applied to the buffer. This
@@ -419,9 +426,9 @@
  *
  * Available since API level 31.
  */
-void ASurfaceTransaction_setBufferTransform(ASurfaceTransaction* transaction,
-                                      ASurfaceControl* surface_control, int32_t transform)
-                                      __INTRODUCED_IN(31);
+void ASurfaceTransaction_setBufferTransform(ASurfaceTransaction* _Nonnull transaction,
+                                            ASurfaceControl* _Nonnull surface_control,
+                                            int32_t transform) __INTRODUCED_IN(31);
 
 /**
  * Sets an x and y scale of a surface with (0, 0) as the centerpoint of the scale.
@@ -431,9 +438,9 @@
  *
  * Available since API level 31.
  */
-void ASurfaceTransaction_setScale(ASurfaceTransaction* transaction,
-                                      ASurfaceControl* surface_control, float xScale, float yScale)
-                                      __INTRODUCED_IN(31);
+void ASurfaceTransaction_setScale(ASurfaceTransaction* _Nonnull transaction,
+                                  ASurfaceControl* _Nonnull surface_control, float xScale,
+                                  float yScale) __INTRODUCED_IN(31);
 /**
  * Parameter for ASurfaceTransaction_setBufferTransparency().
  */
@@ -449,8 +456,8 @@
  *
  * Available since API level 29.
  */
-void ASurfaceTransaction_setBufferTransparency(ASurfaceTransaction* transaction,
-                                               ASurfaceControl* surface_control,
+void ASurfaceTransaction_setBufferTransparency(ASurfaceTransaction* _Nonnull transaction,
+                                               ASurfaceControl* _Nonnull surface_control,
                                                enum ASurfaceTransactionTransparency transparency)
                                                __INTRODUCED_IN(29);
 
@@ -460,9 +467,10 @@
  *
  * Available since API level 29.
  */
-void ASurfaceTransaction_setDamageRegion(ASurfaceTransaction* transaction,
-                                         ASurfaceControl* surface_control, const ARect rects[],
-                                         uint32_t count) __INTRODUCED_IN(29);
+void ASurfaceTransaction_setDamageRegion(ASurfaceTransaction* _Nonnull transaction,
+                                         ASurfaceControl* _Nonnull surface_control,
+                                         const ARect* _Nullable rects, uint32_t count)
+                                         __INTRODUCED_IN(29);
 
 /**
  * Specifies a desiredPresentTime for the transaction. The framework will try to present
@@ -476,7 +484,7 @@
  *
  * Available since API level 29.
  */
-void ASurfaceTransaction_setDesiredPresentTime(ASurfaceTransaction* transaction,
+void ASurfaceTransaction_setDesiredPresentTime(ASurfaceTransaction* _Nonnull transaction,
                                                int64_t desiredPresentTime) __INTRODUCED_IN(29);
 
 /**
@@ -486,8 +494,8 @@
  *
  * Available since API level 29.
  */
-void ASurfaceTransaction_setBufferAlpha(ASurfaceTransaction* transaction,
-                                        ASurfaceControl* surface_control, float alpha)
+void ASurfaceTransaction_setBufferAlpha(ASurfaceTransaction* _Nonnull transaction,
+                                        ASurfaceControl* _Nonnull surface_control, float alpha)
                                         __INTRODUCED_IN(29);
 
 /**
@@ -497,9 +505,9 @@
  *
  * Available since API level 29.
  */
-void ASurfaceTransaction_setBufferDataSpace(ASurfaceTransaction* transaction,
-                                            ASurfaceControl* surface_control, enum ADataSpace data_space)
-                                            __INTRODUCED_IN(29);
+void ASurfaceTransaction_setBufferDataSpace(ASurfaceTransaction* _Nonnull transaction,
+                                            ASurfaceControl* _Nonnull surface_control,
+                                            enum ADataSpace data_space) __INTRODUCED_IN(29);
 
 /**
  * SMPTE ST 2086 "Mastering Display Color Volume" static metadata
@@ -509,9 +517,9 @@
  *
  * Available since API level 29.
  */
-void ASurfaceTransaction_setHdrMetadata_smpte2086(ASurfaceTransaction* transaction,
-                                                  ASurfaceControl* surface_control,
-                                                  struct AHdrMetadata_smpte2086* metadata)
+void ASurfaceTransaction_setHdrMetadata_smpte2086(ASurfaceTransaction* _Nonnull transaction,
+                                                  ASurfaceControl* _Nonnull surface_control,
+                                                  struct AHdrMetadata_smpte2086* _Nullable metadata)
                                                   __INTRODUCED_IN(29);
 
 /**
@@ -522,9 +530,9 @@
  *
  * Available since API level 29.
  */
-void ASurfaceTransaction_setHdrMetadata_cta861_3(ASurfaceTransaction* transaction,
-                                                 ASurfaceControl* surface_control,
-                                                 struct AHdrMetadata_cta861_3* metadata)
+void ASurfaceTransaction_setHdrMetadata_cta861_3(ASurfaceTransaction* _Nonnull transaction,
+                                                 ASurfaceControl* _Nonnull surface_control,
+                                                 struct AHdrMetadata_cta861_3* _Nullable metadata)
                                                  __INTRODUCED_IN(29);
 
 /**
@@ -569,10 +577,10 @@
  *
  * Available since API level 34.
  */
-void ASurfaceTransaction_setExtendedRangeBrightness(ASurfaceTransaction* transaction,
-                                            ASurfaceControl* surface_control,
-                                            float currentBufferRatio,
-                                            float desiredRatio) __INTRODUCED_IN(__ANDROID_API_U__);
+void ASurfaceTransaction_setExtendedRangeBrightness(ASurfaceTransaction* _Nonnull transaction,
+                                                    ASurfaceControl* _Nonnull surface_control,
+                                                    float currentBufferRatio, float desiredRatio)
+                                                    __INTRODUCED_IN(__ANDROID_API_U__);
 
 /**
  * Same as ASurfaceTransaction_setFrameRateWithChangeStrategy(transaction, surface_control,
@@ -582,8 +590,8 @@
  *
  * Available since API level 30.
  */
-void ASurfaceTransaction_setFrameRate(ASurfaceTransaction* transaction,
-                                      ASurfaceControl* surface_control, float frameRate,
+void ASurfaceTransaction_setFrameRate(ASurfaceTransaction* _Nonnull transaction,
+                                      ASurfaceControl* _Nonnull surface_control, float frameRate,
                                       int8_t compatibility) __INTRODUCED_IN(30);
 
 /**
@@ -618,10 +626,11 @@
  *
  * Available since API level 31.
  */
-void ASurfaceTransaction_setFrameRateWithChangeStrategy(ASurfaceTransaction* transaction,
-                                      ASurfaceControl* surface_control, float frameRate,
-                                      int8_t compatibility, int8_t changeFrameRateStrategy)
-                                      __INTRODUCED_IN(31);
+void ASurfaceTransaction_setFrameRateWithChangeStrategy(ASurfaceTransaction* _Nonnull transaction,
+                                                        ASurfaceControl* _Nonnull surface_control,
+                                                        float frameRate, int8_t compatibility,
+                                                        int8_t changeFrameRateStrategy)
+                                                        __INTRODUCED_IN(31);
 
 /**
  * Clears the frame rate which is set for \a surface_control.
@@ -644,8 +653,8 @@
  *
  * Available since API level 34.
  */
-void ASurfaceTransaction_clearFrameRate(ASurfaceTransaction* transaction,
-                                        ASurfaceControl* surface_control)
+void ASurfaceTransaction_clearFrameRate(ASurfaceTransaction* _Nonnull transaction,
+                                        ASurfaceControl* _Nonnull surface_control)
                                         __INTRODUCED_IN(__ANDROID_API_U__);
 
 /**
@@ -674,10 +683,9 @@
  * \param surface_control The ASurfaceControl on which to control buffer backpressure behavior.
  * \param enableBackPressure Whether to enable back pressure.
  */
-void ASurfaceTransaction_setEnableBackPressure(ASurfaceTransaction* transaction,
-                                               ASurfaceControl* surface_control,
-                                               bool enableBackPressure)
-                                               __INTRODUCED_IN(31);
+void ASurfaceTransaction_setEnableBackPressure(ASurfaceTransaction* _Nonnull transaction,
+                                               ASurfaceControl* _Nonnull surface_control,
+                                               bool enableBackPressure) __INTRODUCED_IN(31);
 
 /**
  * Sets the frame timeline to use in SurfaceFlinger.
@@ -697,7 +705,7 @@
  * to the corresponding expected presentation time and deadline from the frame to be rendered. A
  * stale or invalid value will be ignored.
  */
-void ASurfaceTransaction_setFrameTimeline(ASurfaceTransaction* transaction,
+void ASurfaceTransaction_setFrameTimeline(ASurfaceTransaction* _Nonnull transaction,
                                           AVsyncId vsyncId) __INTRODUCED_IN(33);
 
 __END_DECLS
diff --git a/services/inputflinger/BlockingQueue.h b/include/input/BlockingQueue.h
similarity index 100%
rename from services/inputflinger/BlockingQueue.h
rename to include/input/BlockingQueue.h
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index 9c24dc5..090e35b 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -229,6 +229,7 @@
 cc_library_headers {
     name: "trusty_mock_headers",
     host_supported: true,
+    vendor_available: true,
 
     export_include_dirs: [
         "trusty/include",
@@ -243,12 +244,18 @@
 cc_defaults {
     name: "trusty_mock_defaults",
     host_supported: true,
+    vendor_available: true,
 
     header_libs: [
         "libbinder_headers_base",
         "liblog_stub",
         "trusty_mock_headers",
     ],
+    export_header_lib_headers: [
+        "libbinder_headers_base",
+        "liblog_stub",
+        "trusty_mock_headers",
+    ],
 
     shared_libs: [
         "libutils_binder_sdk",
@@ -439,7 +446,7 @@
     },
 }
 
-cc_library_static {
+cc_library {
     name: "libbinder_rpc_no_kernel",
     vendor_available: true,
     defaults: [
@@ -451,7 +458,7 @@
     ],
 }
 
-cc_library_static {
+cc_library {
     name: "libbinder_rpc_no_blob",
     vendor_available: true,
     defaults: [
@@ -467,7 +474,7 @@
     ],
 }
 
-cc_library_static {
+cc_library {
     name: "libbinder_rpc_no_native_handle",
     vendor_available: true,
     defaults: [
@@ -483,7 +490,7 @@
     ],
 }
 
-cc_library_static {
+cc_library {
     name: "libbinder_rpc_single_threaded",
     defaults: [
         "libbinder_common_defaults",
@@ -498,7 +505,7 @@
     ],
 }
 
-cc_library_static {
+cc_library {
     name: "libbinder_rpc_single_threaded_no_kernel",
     defaults: [
         "libbinder_common_defaults",
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 2dd310e..84ef489 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -30,6 +30,7 @@
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <unistd.h>
+#include <algorithm>
 
 #include <binder/Binder.h>
 #include <binder/BpBinder.h>
diff --git a/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
index f8a8843..3ddfefa 100644
--- a/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
+++ b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
@@ -43,6 +43,18 @@
     @utf8InCpp String[] getNamesForUids(in int[] uids);
 
     /**
+     * Return the UID associated with the given package name.
+     * Note that the same package will have different UIDs under different UserHandle on
+     * the same device.
+     * @param packageName The full name (i.e. com.google.apps.contacts) of the desired package.
+     * @param flags Additional option flags to modify the data returned.
+     * @param userId The user handle identifier to look up the package under.
+     * @return Returns an integer UID who owns the given package name, or -1 if no such package is
+     *            available to the caller.
+     */
+     int getPackageUid(in @utf8InCpp String packageName, in long flags, in int userId);
+
+    /**
      * Returns the name of the installer (a package) which installed the named
      * package. Preloaded packages return the string "preload". Sideloaded packages
      * return an empty string. Unknown or unknowable are returned as empty strings.
diff --git a/libs/binder/binder_module.h b/libs/binder/binder_module.h
index eef07ae..b3a2d9e 100644
--- a/libs/binder/binder_module.h
+++ b/libs/binder/binder_module.h
@@ -32,77 +32,4 @@
 #include <linux/android/binder.h>
 #include <sys/ioctl.h>
 
-#ifndef BR_FROZEN_REPLY
-// Temporary definition of BR_FROZEN_REPLY. For production
-// this will come from UAPI binder.h
-#define BR_FROZEN_REPLY _IO('r', 18)
-#endif // BR_FROZEN_REPLY
-
-#ifndef BINDER_FREEZE
-/*
- * Temporary definitions for freeze support. For the final version
- * these will be defined in the UAPI binder.h file from upstream kernel.
- */
-#define BINDER_FREEZE _IOW('b', 14, struct binder_freeze_info)
-
-struct binder_freeze_info {
-    //
-    // Group-leader PID of process to be frozen
-    //
-    uint32_t pid;
-    //
-    // Enable(1) / Disable(0) freeze for given PID
-    //
-    uint32_t enable;
-    //
-    // Timeout to wait for transactions to drain.
-    // 0: don't wait (ioctl will return EAGAIN if not drained)
-    // N: number of ms to wait
-    uint32_t timeout_ms;
-};
-#endif // BINDER_FREEZE
-
-#ifndef BINDER_GET_FROZEN_INFO
-
-#define BINDER_GET_FROZEN_INFO _IOWR('b', 15, struct binder_frozen_status_info)
-
-struct binder_frozen_status_info {
-    //
-    // Group-leader PID of process to be queried
-    //
-    __u32 pid;
-    //
-    // Indicates whether the process has received any sync calls since last
-    // freeze (cleared at freeze/unfreeze)
-    // bit 0: received sync transaction after being frozen
-    // bit 1: new pending sync transaction during freezing
-    //
-    __u32 sync_recv;
-    //
-    // Indicates whether the process has received any async calls since last
-    // freeze (cleared at freeze/unfreeze)
-    //
-    __u32 async_recv;
-};
-#endif // BINDER_GET_FROZEN_INFO
-
-#ifndef BR_ONEWAY_SPAM_SUSPECT
-// Temporary definition of BR_ONEWAY_SPAM_SUSPECT. For production
-// this will come from UAPI binder.h
-#define BR_ONEWAY_SPAM_SUSPECT _IO('r', 19)
-#endif // BR_ONEWAY_SPAM_SUSPECT
-
-#ifndef BINDER_ENABLE_ONEWAY_SPAM_DETECTION
-/*
- * Temporary definitions for oneway spam detection support. For the final version
- * these will be defined in the UAPI binder.h file from upstream kernel.
- */
-#define BINDER_ENABLE_ONEWAY_SPAM_DETECTION _IOW('b', 16, __u32)
-#endif // BINDER_ENABLE_ONEWAY_SPAM_DETECTION
-
-#ifndef BR_TRANSACTION_PENDING_FROZEN
-// Temporary definition of BR_TRANSACTION_PENDING_FROZEN until UAPI binder.h includes it.
-#define BR_TRANSACTION_PENDING_FROZEN _IO('r', 20)
-#endif // BR_TRANSACTION_PENDING_FROZEN
-
 #endif // _BINDER_MODULE_H_
diff --git a/libs/binder/include_rpc_unstable/binder_rpc_unstable.hpp b/libs/binder/include_rpc_unstable/binder_rpc_unstable.hpp
index 7d0acd1..392ebb5 100644
--- a/libs/binder/include_rpc_unstable/binder_rpc_unstable.hpp
+++ b/libs/binder/include_rpc_unstable/binder_rpc_unstable.hpp
@@ -73,6 +73,17 @@
         const ARpcSession_FileDescriptorTransportMode modes[],
         size_t modes_len);
 
+// Sets the maximum number of threads that the Server will use for
+// incoming client connections.
+//
+// This must be called before adding a client session. This corresponds
+// to the number of incoming connections to RpcSession objects in the
+// server, which will correspond to the number of outgoing connections
+// in client RpcSession objects.
+//
+// If this is not specified, this will be a single-threaded server.
+void ARpcServer_setMaxThreads(ARpcServer* server, size_t threads);
+
 // Runs ARpcServer_join() in a background thread. Immediately returns.
 void ARpcServer_start(ARpcServer* server);
 
diff --git a/libs/binder/libbinder_rpc_unstable.cpp b/libs/binder/libbinder_rpc_unstable.cpp
index cb44c58..21537fc 100644
--- a/libs/binder/libbinder_rpc_unstable.cpp
+++ b/libs/binder/libbinder_rpc_unstable.cpp
@@ -167,6 +167,10 @@
     server->setSupportedFileDescriptorTransportModes(modevec);
 }
 
+void ARpcServer_setMaxThreads(ARpcServer* handle, size_t threads) {
+    handleToStrongPointer<RpcServer>(handle)->setMaxThreads(threads);
+}
+
 void ARpcServer_start(ARpcServer* handle) {
     handleToStrongPointer<RpcServer>(handle)->start();
 }
diff --git a/libs/binder/liblog_stub/include/log/log.h b/libs/binder/liblog_stub/include/log/log.h
index 91c9632..dad0020 100644
--- a/libs/binder/liblog_stub/include/log/log.h
+++ b/libs/binder/liblog_stub/include/log/log.h
@@ -54,16 +54,16 @@
 #define IF_ALOGW() IF_ALOG(LOG_WARN, LOG_TAG)
 #define IF_ALOGE() IF_ALOG(LOG_ERROR, LOG_TAG)
 
-#define ALOG(priority, tag, fmt, ...)                                          \
-    do {                                                                       \
-        if (false)[[/*VERY*/ unlikely]] { /* ignore unused __VA_ARGS__ */      \
-            std::fprintf(stderr, fmt __VA_OPT__(, ) __VA_ARGS__);              \
-        }                                                                      \
-        IF_ALOG(priority, tag) {                                               \
-            __android_log_print(ANDROID_##priority, tag,                       \
-                                tag ": " fmt "\n" __VA_OPT__(, ) __VA_ARGS__); \
-        }                                                                      \
-        if constexpr (ANDROID_##priority == ANDROID_LOG_FATAL) std::abort();   \
+#define ALOG(priority, tag, fmt, ...)                                        \
+    do {                                                                     \
+        if (false)[[/*VERY*/ unlikely]] { /* ignore unused __VA_ARGS__ */    \
+            std::fprintf(stderr, fmt __VA_OPT__(, ) __VA_ARGS__);            \
+        }                                                                    \
+        IF_ALOG(priority, tag) {                                             \
+            __android_log_print(ANDROID_##priority, tag, "%s: " fmt "\n",    \
+                                (tag)__VA_OPT__(, ) __VA_ARGS__);            \
+        }                                                                    \
+        if constexpr (ANDROID_##priority == ANDROID_LOG_FATAL) std::abort(); \
     } while (false)
 #define ALOGV(...) ALOG(LOG_VERBOSE, LOG_TAG, __VA_ARGS__)
 #define ALOGD(...) ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__)
diff --git a/libs/binder/ndk/include_ndk/android/binder_ibinder.h b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
index b1ab7b0..2929bce 100644
--- a/libs/binder/ndk/include_ndk/android/binder_ibinder.h
+++ b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
@@ -718,9 +718,17 @@
  *     When registering the interface, add:
  *         std::shared_ptr<MyFoo> foo = new MyFoo; // class in AOSP codebase
  *         std::shared_ptr<MyBar> bar = new MyBar; // custom extension class
- *         ... = AIBinder_setExtension(foo->asBinder().get(), bar->asBinder().get());
+ *         SpAIBinder binder = foo->asBinder(); // target binder to extend
+ *         ... = AIBinder_setExtension(binder.get(), bar->asBinder().get());
+ *         ... = AServiceManager_addService(binder.get(), instanceName);
  *         // handle error
  *
+ *         Do not use foo->asBinder().get() as the target binder argument to
+ *         AIBinder_setExtensions because asBinder it creates a new binder
+ *         object that will be destroyed after the function is called. The same
+ *         binder object must be used for AIBinder_setExtension and
+ *         AServiceManager_addService to register the service with an extension.
+ *
  *     Then, clients of IFoo can get this extension:
  *         SpAIBinder binder = ...;
  *         std::shared_ptr<IFoo> foo = IFoo::fromBinder(binder); // handle if null
diff --git a/libs/binder/ndk/include_platform/android/binder_manager.h b/libs/binder/ndk/include_platform/android/binder_manager.h
index c665ad8..52edae4 100644
--- a/libs/binder/ndk/include_platform/android/binder_manager.h
+++ b/libs/binder/ndk/include_platform/android/binder_manager.h
@@ -18,11 +18,8 @@
 
 #include <android/binder_ibinder.h>
 #include <android/binder_status.h>
-#include <sys/cdefs.h>
-
-#ifndef __TRUSTY__
 #include <android/llndk-versioning.h>
-#endif
+#include <sys/cdefs.h>
 
 __BEGIN_DECLS
 
diff --git a/libs/binder/rust/Android.bp b/libs/binder/rust/Android.bp
index 57a38dc..ef556d7 100644
--- a/libs/binder/rust/Android.bp
+++ b/libs/binder/rust/Android.bp
@@ -35,6 +35,21 @@
 }
 
 rust_library {
+    name: "libbinder_rs_on_trusty_mock",
+    crate_name: "binder",
+    srcs: ["src/lib.rs"],
+    cfgs: [
+        "trusty",
+    ],
+    rustlibs: [
+        "libbinder_ndk_sys_on_trusty_mock",
+        "libdowncast_rs",
+        "liblibc",
+    ],
+    vendor: true,
+}
+
+rust_library {
     name: "libbinder_tokio_rs",
     crate_name: "binder_tokio",
     srcs: ["binder_tokio/lib.rs"],
@@ -89,6 +104,26 @@
     visibility: [":__subpackages__"],
 }
 
+rust_library {
+    name: "libbinder_ndk_sys_on_trusty_mock",
+    crate_name: "binder_ndk_sys",
+    srcs: [
+        "sys/lib.rs",
+        ":libbinder_ndk_bindgen_on_trusty_mock",
+    ],
+    cfgs: [
+        "trusty",
+    ],
+    shared_libs: [
+        "libbinder_ndk_on_trusty_mock",
+    ],
+    vendor: true,
+    // Lints are checked separately for libbinder_ndk_sys.
+    // The Trusty mock copy pulls in extra headers that
+    // don't pass the lints for the bindgen output.
+    lints: "none",
+}
+
 rust_bindgen {
     name: "libbinder_ndk_bindgen",
     crate_name: "binder_ndk_bindgen",
@@ -125,6 +160,28 @@
     min_sdk_version: "Tiramisu",
 }
 
+rust_bindgen {
+    name: "libbinder_ndk_bindgen_on_trusty_mock",
+    crate_name: "binder_ndk_bindgen",
+    wrapper_src: "sys/BinderBindings.hpp",
+    source_stem: "bindings",
+    defaults: [
+        "trusty_mock_defaults",
+    ],
+
+    bindgen_flag_files: [
+        // Unfortunately the only way to specify the rust_non_exhaustive enum
+        // style for a type is to make it the default
+        // and then specify constified enums for the enums we don't want
+        // rustified
+        "libbinder_ndk_bindgen_flags.txt",
+    ],
+    shared_libs: [
+        "libbinder_ndk_on_trusty_mock",
+        "libc++",
+    ],
+}
+
 rust_test {
     name: "libbinder_rs-internal_test",
     crate_name: "binder",
diff --git a/libs/binder/rust/binder_tokio/lib.rs b/libs/binder/rust/binder_tokio/lib.rs
index 1dc0b24..71bb95b 100644
--- a/libs/binder/rust/binder_tokio/lib.rs
+++ b/libs/binder/rust/binder_tokio/lib.rs
@@ -34,6 +34,7 @@
 
 /// Retrieve an existing service for a particular interface, sleeping for a few
 /// seconds if it doesn't yet exist.
+#[deprecated = "this polls 5s, use wait_for_interface or check_interface"]
 pub async fn get_interface<T: FromIBinder + ?Sized + 'static>(
     name: &str,
 ) -> Result<Strong<T>, StatusCode> {
@@ -56,6 +57,32 @@
     }
 }
 
+/// Retrieve an existing service for a particular interface. Returns
+/// `Err(StatusCode::NAME_NOT_FOUND)` immediately if the service is not available.
+///
+/// NOTE: "immediately" above does not mean the future will complete the first time it is polled.
+pub async fn check_interface<T: FromIBinder + ?Sized + 'static>(
+    name: &str,
+) -> Result<Strong<T>, StatusCode> {
+    if binder::is_handling_transaction() {
+        // See comment in the BinderAsyncPool impl.
+        return binder::check_interface::<T>(name);
+    }
+
+    let name = name.to_string();
+    let res = tokio::task::spawn_blocking(move || binder::check_interface::<T>(&name)).await;
+
+    // The `is_panic` branch is not actually reachable in Android as we compile
+    // with `panic = abort`.
+    match res {
+        Ok(Ok(service)) => Ok(service),
+        Ok(Err(err)) => Err(err),
+        Err(e) if e.is_panic() => std::panic::resume_unwind(e.into_panic()),
+        Err(e) if e.is_cancelled() => Err(StatusCode::FAILED_TRANSACTION),
+        Err(_) => Err(StatusCode::UNKNOWN_ERROR),
+    }
+}
+
 /// Retrieve an existing service for a particular interface, or start it if it
 /// is configured as a dynamic service and isn't yet started.
 pub async fn wait_for_interface<T: FromIBinder + ?Sized + 'static>(
diff --git a/libs/binder/rust/rpcbinder/Android.bp b/libs/binder/rust/rpcbinder/Android.bp
index 535ce01..2e46345 100644
--- a/libs/binder/rust/rpcbinder/Android.bp
+++ b/libs/binder/rust/rpcbinder/Android.bp
@@ -18,6 +18,7 @@
         "libbinder_ndk_sys",
         "libbinder_rpc_unstable_bindgen_sys",
         "libbinder_rs",
+        "libcfg_if",
         "libdowncast_rs",
         "libforeign_types",
         "liblibc",
diff --git a/libs/binder/rust/rpcbinder/src/lib.rs b/libs/binder/rust/rpcbinder/src/lib.rs
index 163f000..7e5c9dd 100644
--- a/libs/binder/rust/rpcbinder/src/lib.rs
+++ b/libs/binder/rust/rpcbinder/src/lib.rs
@@ -16,10 +16,10 @@
 
 //! API for RPC Binder services.
 
-#[cfg(not(target_os = "trusty"))]
 mod server;
 mod session;
 
+pub use server::RpcServer;
 #[cfg(not(target_os = "trusty"))]
-pub use server::{RpcServer, RpcServerRef};
+pub use server::RpcServerRef;
 pub use session::{FileDescriptorTransportMode, RpcSession, RpcSessionRef};
diff --git a/libs/binder/rust/rpcbinder/src/server.rs b/libs/binder/rust/rpcbinder/src/server.rs
index 6fda878..d6bdbd8 100644
--- a/libs/binder/rust/rpcbinder/src/server.rs
+++ b/libs/binder/rust/rpcbinder/src/server.rs
@@ -14,160 +14,12 @@
  * limitations under the License.
  */
 
-use crate::session::FileDescriptorTransportMode;
-use binder::{unstable_api::AsNative, SpIBinder};
-use binder_rpc_unstable_bindgen::ARpcServer;
-use foreign_types::{foreign_type, ForeignType, ForeignTypeRef};
-use std::ffi::CString;
-use std::io::{Error, ErrorKind};
-use std::os::unix::io::{IntoRawFd, OwnedFd};
-
-foreign_type! {
-    type CType = binder_rpc_unstable_bindgen::ARpcServer;
-    fn drop = binder_rpc_unstable_bindgen::ARpcServer_free;
-
-    /// A type that represents a foreign instance of RpcServer.
-    #[derive(Debug)]
-    pub struct RpcServer;
-    /// A borrowed RpcServer.
-    pub struct RpcServerRef;
-}
-
-/// SAFETY: The opaque handle can be cloned freely.
-unsafe impl Send for RpcServer {}
-/// SAFETY: The underlying C++ RpcServer class is thread-safe.
-unsafe impl Sync for RpcServer {}
-
-impl RpcServer {
-    /// Creates a binder RPC server, serving the supplied binder service implementation on the given
-    /// vsock port. Only connections from the given CID are accepted.
-    ///
-    // Set `cid` to libc::VMADDR_CID_ANY to accept connections from any client.
-    // Set `cid` to libc::VMADDR_CID_LOCAL to only bind to the local vsock interface.
-    pub fn new_vsock(mut service: SpIBinder, cid: u32, port: u32) -> Result<RpcServer, Error> {
-        let service = service.as_native_mut();
-
-        // SAFETY: Service ownership is transferring to the server and won't be valid afterward.
-        // Plus the binder objects are threadsafe.
-        unsafe {
-            Self::checked_from_ptr(binder_rpc_unstable_bindgen::ARpcServer_newVsock(
-                service, cid, port,
-            ))
-        }
-    }
-
-    /// Creates a binder RPC server, serving the supplied binder service implementation on the given
-    /// socket file descriptor. The socket should be bound to an address before calling this
-    /// function.
-    pub fn new_bound_socket(
-        mut service: SpIBinder,
-        socket_fd: OwnedFd,
-    ) -> Result<RpcServer, Error> {
-        let service = service.as_native_mut();
-
-        // SAFETY: Service ownership is transferring to the server and won't be valid afterward.
-        // Plus the binder objects are threadsafe.
-        // The server takes ownership of the socket FD.
-        unsafe {
-            Self::checked_from_ptr(binder_rpc_unstable_bindgen::ARpcServer_newBoundSocket(
-                service,
-                socket_fd.into_raw_fd(),
-            ))
-        }
-    }
-
-    /// Creates a binder RPC server that bootstraps sessions using an existing Unix domain socket
-    /// pair, with a given root IBinder object. Callers should create a pair of SOCK_STREAM Unix
-    /// domain sockets, pass one to the server and the other to the client. Multiple client session
-    /// can be created from the client end of the pair.
-    pub fn new_unix_domain_bootstrap(
-        mut service: SpIBinder,
-        bootstrap_fd: OwnedFd,
-    ) -> Result<RpcServer, Error> {
-        let service = service.as_native_mut();
-
-        // SAFETY: Service ownership is transferring to the server and won't be valid afterward.
-        // Plus the binder objects are threadsafe.
-        // The server takes ownership of the bootstrap FD.
-        unsafe {
-            Self::checked_from_ptr(binder_rpc_unstable_bindgen::ARpcServer_newUnixDomainBootstrap(
-                service,
-                bootstrap_fd.into_raw_fd(),
-            ))
-        }
-    }
-
-    /// Creates a binder RPC server, serving the supplied binder service implementation on the given
-    /// IP address and port.
-    pub fn new_inet(mut service: SpIBinder, address: &str, port: u32) -> Result<RpcServer, Error> {
-        let address = match CString::new(address) {
-            Ok(s) => s,
-            Err(e) => {
-                log::error!("Cannot convert {} to CString. Error: {:?}", address, e);
-                return Err(Error::from(ErrorKind::InvalidInput));
-            }
-        };
-        let service = service.as_native_mut();
-
-        // SAFETY: Service ownership is transferring to the server and won't be valid afterward.
-        // Plus the binder objects are threadsafe.
-        unsafe {
-            Self::checked_from_ptr(binder_rpc_unstable_bindgen::ARpcServer_newInet(
-                service,
-                address.as_ptr(),
-                port,
-            ))
-        }
-    }
-
-    unsafe fn checked_from_ptr(ptr: *mut ARpcServer) -> Result<RpcServer, Error> {
-        if ptr.is_null() {
-            return Err(Error::new(ErrorKind::Other, "Failed to start server"));
-        }
-        // SAFETY: Our caller must pass us a valid or null pointer, and we've checked that it's not
-        // null.
-        Ok(unsafe { RpcServer::from_ptr(ptr) })
-    }
-}
-
-impl RpcServerRef {
-    /// Sets the list of file descriptor transport modes supported by this server.
-    pub fn set_supported_file_descriptor_transport_modes(
-        &self,
-        modes: &[FileDescriptorTransportMode],
-    ) {
-        // SAFETY: Does not keep the pointer after returning does, nor does it
-        // read past its boundary. Only passes the 'self' pointer as an opaque handle.
-        unsafe {
-            binder_rpc_unstable_bindgen::ARpcServer_setSupportedFileDescriptorTransportModes(
-                self.as_ptr(),
-                modes.as_ptr(),
-                modes.len(),
-            )
-        }
-    }
-
-    /// Starts a new background thread and calls join(). Returns immediately.
-    pub fn start(&self) {
-        // SAFETY: RpcServerRef wraps a valid pointer to an ARpcServer.
-        unsafe { binder_rpc_unstable_bindgen::ARpcServer_start(self.as_ptr()) };
-    }
-
-    /// Joins the RpcServer thread. The call blocks until the server terminates.
-    /// This must be called from exactly one thread.
-    pub fn join(&self) {
-        // SAFETY: RpcServerRef wraps a valid pointer to an ARpcServer.
-        unsafe { binder_rpc_unstable_bindgen::ARpcServer_join(self.as_ptr()) };
-    }
-
-    /// Shuts down the running RpcServer. Can be called multiple times and from
-    /// multiple threads. Called automatically during drop().
-    pub fn shutdown(&self) -> Result<(), Error> {
-        // SAFETY: RpcServerRef wraps a valid pointer to an ARpcServer.
-        if unsafe { binder_rpc_unstable_bindgen::ARpcServer_shutdown(self.as_ptr()) } {
-            Ok(())
-        } else {
-            Err(Error::from(ErrorKind::UnexpectedEof))
-        }
+cfg_if::cfg_if! {
+    if #[cfg(target_os = "trusty")] {
+        mod trusty;
+        pub use trusty::*;
+    } else {
+        mod android;
+        pub use android::*;
     }
 }
diff --git a/libs/binder/rust/rpcbinder/src/server/android.rs b/libs/binder/rust/rpcbinder/src/server/android.rs
new file mode 100644
index 0000000..2ab3447
--- /dev/null
+++ b/libs/binder/rust/rpcbinder/src/server/android.rs
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+use crate::session::FileDescriptorTransportMode;
+use binder::{unstable_api::AsNative, SpIBinder};
+use binder_rpc_unstable_bindgen::ARpcServer;
+use foreign_types::{foreign_type, ForeignType, ForeignTypeRef};
+use std::ffi::CString;
+use std::io::{Error, ErrorKind};
+use std::os::unix::io::{IntoRawFd, OwnedFd};
+
+foreign_type! {
+    type CType = binder_rpc_unstable_bindgen::ARpcServer;
+    fn drop = binder_rpc_unstable_bindgen::ARpcServer_free;
+
+    /// A type that represents a foreign instance of RpcServer.
+    #[derive(Debug)]
+    pub struct RpcServer;
+    /// A borrowed RpcServer.
+    pub struct RpcServerRef;
+}
+
+/// SAFETY: The opaque handle can be cloned freely.
+unsafe impl Send for RpcServer {}
+/// SAFETY: The underlying C++ RpcServer class is thread-safe.
+unsafe impl Sync for RpcServer {}
+
+impl RpcServer {
+    /// Creates a binder RPC server, serving the supplied binder service implementation on the given
+    /// vsock port. Only connections from the given CID are accepted.
+    ///
+    // Set `cid` to libc::VMADDR_CID_ANY to accept connections from any client.
+    // Set `cid` to libc::VMADDR_CID_LOCAL to only bind to the local vsock interface.
+    pub fn new_vsock(mut service: SpIBinder, cid: u32, port: u32) -> Result<RpcServer, Error> {
+        let service = service.as_native_mut();
+
+        // SAFETY: Service ownership is transferring to the server and won't be valid afterward.
+        // Plus the binder objects are threadsafe.
+        unsafe {
+            Self::checked_from_ptr(binder_rpc_unstable_bindgen::ARpcServer_newVsock(
+                service, cid, port,
+            ))
+        }
+    }
+
+    /// Creates a binder RPC server, serving the supplied binder service implementation on the given
+    /// socket file descriptor. The socket should be bound to an address before calling this
+    /// function.
+    pub fn new_bound_socket(
+        mut service: SpIBinder,
+        socket_fd: OwnedFd,
+    ) -> Result<RpcServer, Error> {
+        let service = service.as_native_mut();
+
+        // SAFETY: Service ownership is transferring to the server and won't be valid afterward.
+        // Plus the binder objects are threadsafe.
+        // The server takes ownership of the socket FD.
+        unsafe {
+            Self::checked_from_ptr(binder_rpc_unstable_bindgen::ARpcServer_newBoundSocket(
+                service,
+                socket_fd.into_raw_fd(),
+            ))
+        }
+    }
+
+    /// Creates a binder RPC server that bootstraps sessions using an existing Unix domain socket
+    /// pair, with a given root IBinder object. Callers should create a pair of SOCK_STREAM Unix
+    /// domain sockets, pass one to the server and the other to the client. Multiple client session
+    /// can be created from the client end of the pair.
+    pub fn new_unix_domain_bootstrap(
+        mut service: SpIBinder,
+        bootstrap_fd: OwnedFd,
+    ) -> Result<RpcServer, Error> {
+        let service = service.as_native_mut();
+
+        // SAFETY: Service ownership is transferring to the server and won't be valid afterward.
+        // Plus the binder objects are threadsafe.
+        // The server takes ownership of the bootstrap FD.
+        unsafe {
+            Self::checked_from_ptr(binder_rpc_unstable_bindgen::ARpcServer_newUnixDomainBootstrap(
+                service,
+                bootstrap_fd.into_raw_fd(),
+            ))
+        }
+    }
+
+    /// Creates a binder RPC server, serving the supplied binder service implementation on the given
+    /// IP address and port.
+    pub fn new_inet(mut service: SpIBinder, address: &str, port: u32) -> Result<RpcServer, Error> {
+        let address = match CString::new(address) {
+            Ok(s) => s,
+            Err(e) => {
+                log::error!("Cannot convert {} to CString. Error: {:?}", address, e);
+                return Err(Error::from(ErrorKind::InvalidInput));
+            }
+        };
+        let service = service.as_native_mut();
+
+        // SAFETY: Service ownership is transferring to the server and won't be valid afterward.
+        // Plus the binder objects are threadsafe.
+        unsafe {
+            Self::checked_from_ptr(binder_rpc_unstable_bindgen::ARpcServer_newInet(
+                service,
+                address.as_ptr(),
+                port,
+            ))
+        }
+    }
+
+    unsafe fn checked_from_ptr(ptr: *mut ARpcServer) -> Result<RpcServer, Error> {
+        if ptr.is_null() {
+            return Err(Error::new(ErrorKind::Other, "Failed to start server"));
+        }
+        // SAFETY: Our caller must pass us a valid or null pointer, and we've checked that it's not
+        // null.
+        Ok(unsafe { RpcServer::from_ptr(ptr) })
+    }
+}
+
+impl RpcServerRef {
+    /// Sets the list of file descriptor transport modes supported by this server.
+    pub fn set_supported_file_descriptor_transport_modes(
+        &self,
+        modes: &[FileDescriptorTransportMode],
+    ) {
+        // SAFETY: Does not keep the pointer after returning does, nor does it
+        // read past its boundary. Only passes the 'self' pointer as an opaque handle.
+        unsafe {
+            binder_rpc_unstable_bindgen::ARpcServer_setSupportedFileDescriptorTransportModes(
+                self.as_ptr(),
+                modes.as_ptr(),
+                modes.len(),
+            )
+        }
+    }
+
+    /// Sets the max number of threads this Server uses for incoming client connections.
+    ///
+    /// This must be called before adding a client session. This corresponds
+    /// to the number of incoming connections to RpcSession objects in the
+    /// server, which will correspond to the number of outgoing connections
+    /// in client RpcSession objects. Specifically this is useful for handling
+    /// client-side callback connections.
+    ///
+    /// If this is not specified, this will be a single-threaded server.
+    pub fn set_max_threads(&self, count: usize) {
+        // SAFETY: RpcServerRef wraps a valid pointer to an ARpcServer.
+        unsafe { binder_rpc_unstable_bindgen::ARpcServer_setMaxThreads(self.as_ptr(), count) };
+    }
+
+    /// Starts a new background thread and calls join(). Returns immediately.
+    pub fn start(&self) {
+        // SAFETY: RpcServerRef wraps a valid pointer to an ARpcServer.
+        unsafe { binder_rpc_unstable_bindgen::ARpcServer_start(self.as_ptr()) };
+    }
+
+    /// Joins the RpcServer thread. The call blocks until the server terminates.
+    /// This must be called from exactly one thread.
+    pub fn join(&self) {
+        // SAFETY: RpcServerRef wraps a valid pointer to an ARpcServer.
+        unsafe { binder_rpc_unstable_bindgen::ARpcServer_join(self.as_ptr()) };
+    }
+
+    /// Shuts down the running RpcServer. Can be called multiple times and from
+    /// multiple threads. Called automatically during drop().
+    pub fn shutdown(&self) -> Result<(), Error> {
+        // SAFETY: RpcServerRef wraps a valid pointer to an ARpcServer.
+        if unsafe { binder_rpc_unstable_bindgen::ARpcServer_shutdown(self.as_ptr()) } {
+            Ok(())
+        } else {
+            Err(Error::from(ErrorKind::UnexpectedEof))
+        }
+    }
+}
diff --git a/libs/binder/rust/rpcbinder/src/server/trusty.rs b/libs/binder/rust/rpcbinder/src/server/trusty.rs
new file mode 100644
index 0000000..fe45dec
--- /dev/null
+++ b/libs/binder/rust/rpcbinder/src/server/trusty.rs
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+use binder::{unstable_api::AsNative, SpIBinder};
+use libc::size_t;
+use std::ffi::{c_char, c_void};
+use std::ptr;
+use tipc::{ConnectResult, Handle, MessageResult, PortCfg, TipcError, UnbufferedService, Uuid};
+
+pub trait PerSessionCallback: Fn(Uuid) -> Option<SpIBinder> + Send + Sync + 'static {}
+impl<T> PerSessionCallback for T where T: Fn(Uuid) -> Option<SpIBinder> + Send + Sync + 'static {}
+
+pub struct RpcServer {
+    inner: *mut binder_rpc_server_bindgen::ARpcServerTrusty,
+}
+
+/// SAFETY: The opaque handle points to a heap allocation
+/// that should be process-wide and not tied to the current thread.
+unsafe impl Send for RpcServer {}
+/// SAFETY: The underlying C++ RpcServer class is thread-safe.
+unsafe impl Sync for RpcServer {}
+
+impl Drop for RpcServer {
+    fn drop(&mut self) {
+        // SAFETY: `ARpcServerTrusty_delete` is the correct destructor to call
+        // on pointers returned by `ARpcServerTrusty_new`.
+        unsafe {
+            binder_rpc_server_bindgen::ARpcServerTrusty_delete(self.inner);
+        }
+    }
+}
+
+impl RpcServer {
+    /// Allocates a new RpcServer object.
+    pub fn new(service: SpIBinder) -> RpcServer {
+        Self::new_per_session(move |_uuid| Some(service.clone()))
+    }
+
+    /// Allocates a new per-session RpcServer object.
+    ///
+    /// Per-session objects take a closure that gets called once
+    /// for every new connection. The closure gets the UUID of
+    /// the peer and can accept or reject that connection.
+    pub fn new_per_session<F: PerSessionCallback>(f: F) -> RpcServer {
+        // SAFETY: Takes ownership of the returned handle, which has correct refcount.
+        let inner = unsafe {
+            binder_rpc_server_bindgen::ARpcServerTrusty_newPerSession(
+                Some(per_session_callback_wrapper::<F>),
+                Box::into_raw(Box::new(f)).cast(),
+                Some(per_session_callback_deleter::<F>),
+            )
+        };
+        RpcServer { inner }
+    }
+}
+
+unsafe extern "C" fn per_session_callback_wrapper<F: PerSessionCallback>(
+    uuid_ptr: *const c_void,
+    len: size_t,
+    cb_ptr: *mut c_char,
+) -> *mut binder_rpc_server_bindgen::AIBinder {
+    // SAFETY: This callback should only get called while the RpcServer is alive.
+    let cb = unsafe { &mut *cb_ptr.cast::<F>() };
+
+    if len != std::mem::size_of::<Uuid>() {
+        return ptr::null_mut();
+    }
+
+    // SAFETY: On the previous lines we check that we got exactly the right amount of bytes.
+    let uuid = unsafe {
+        let mut uuid = std::mem::MaybeUninit::<Uuid>::uninit();
+        uuid.as_mut_ptr().copy_from(uuid_ptr.cast(), 1);
+        uuid.assume_init()
+    };
+
+    cb(uuid).map_or_else(ptr::null_mut, |b| {
+        // Prevent AIBinder_decStrong from being called before AIBinder_toPlatformBinder.
+        // The per-session callback in C++ is supposed to call AIBinder_decStrong on the
+        // pointer we return here.
+        std::mem::ManuallyDrop::new(b).as_native_mut().cast()
+    })
+}
+
+unsafe extern "C" fn per_session_callback_deleter<F: PerSessionCallback>(cb: *mut c_char) {
+    // SAFETY: shared_ptr calls this to delete the pointer we gave it.
+    // It should only get called once the last shared reference goes away.
+    unsafe {
+        drop(Box::<F>::from_raw(cb.cast()));
+    }
+}
+
+pub struct RpcServerConnection {
+    ctx: *mut c_void,
+}
+
+impl Drop for RpcServerConnection {
+    fn drop(&mut self) {
+        // We do not need to close handle_fd since we do not own it.
+        unsafe {
+            binder_rpc_server_bindgen::ARpcServerTrusty_handleChannelCleanup(self.ctx);
+        }
+    }
+}
+
+impl UnbufferedService for RpcServer {
+    type Connection = RpcServerConnection;
+
+    fn on_connect(
+        &self,
+        _port: &PortCfg,
+        handle: &Handle,
+        peer: &Uuid,
+    ) -> tipc::Result<ConnectResult<Self::Connection>> {
+        let mut conn = RpcServerConnection { ctx: std::ptr::null_mut() };
+        let rc = unsafe {
+            binder_rpc_server_bindgen::ARpcServerTrusty_handleConnect(
+                self.inner,
+                handle.as_raw_fd(),
+                peer.as_ptr().cast(),
+                &mut conn.ctx,
+            )
+        };
+        if rc < 0 {
+            Err(TipcError::from_uapi(rc.into()))
+        } else {
+            Ok(ConnectResult::Accept(conn))
+        }
+    }
+
+    fn on_message(
+        &self,
+        conn: &Self::Connection,
+        _handle: &Handle,
+        buffer: &mut [u8],
+    ) -> tipc::Result<MessageResult> {
+        assert!(buffer.is_empty());
+        let rc = unsafe { binder_rpc_server_bindgen::ARpcServerTrusty_handleMessage(conn.ctx) };
+        if rc < 0 {
+            Err(TipcError::from_uapi(rc.into()))
+        } else {
+            Ok(MessageResult::MaintainConnection)
+        }
+    }
+
+    fn on_disconnect(&self, conn: &Self::Connection) {
+        unsafe { binder_rpc_server_bindgen::ARpcServerTrusty_handleDisconnect(conn.ctx) };
+    }
+}
diff --git a/libs/binder/rust/src/lib.rs b/libs/binder/rust/src/lib.rs
index 0540ed3..e70f4f0 100644
--- a/libs/binder/rust/src/lib.rs
+++ b/libs/binder/rust/src/lib.rs
@@ -100,9 +100,9 @@
 mod native;
 mod parcel;
 mod proxy;
-#[cfg(not(target_os = "trusty"))]
+#[cfg(not(trusty))]
 mod service;
-#[cfg(not(target_os = "trusty"))]
+#[cfg(not(trusty))]
 mod state;
 
 use binder_ndk_sys as sys;
@@ -112,13 +112,13 @@
 pub use error::{ExceptionCode, IntoBinderResult, Status, StatusCode};
 pub use parcel::{ParcelFileDescriptor, Parcelable, ParcelableHolder};
 pub use proxy::{DeathRecipient, SpIBinder, WpIBinder};
-#[cfg(not(target_os = "trusty"))]
+#[cfg(not(trusty))]
 pub use service::{
-    add_service, force_lazy_services_persist, get_declared_instances, get_interface, get_service,
-    is_declared, is_handling_transaction, register_lazy_service, wait_for_interface,
-    wait_for_service, LazyServiceGuard,
+    add_service, check_interface, check_service, force_lazy_services_persist,
+    get_declared_instances, get_interface, get_service, is_declared, is_handling_transaction,
+    register_lazy_service, wait_for_interface, wait_for_service, LazyServiceGuard,
 };
-#[cfg(not(target_os = "trusty"))]
+#[cfg(not(trusty))]
 pub use state::{ProcessState, ThreadState};
 
 /// Binder result containing a [`Status`] on error.
diff --git a/libs/binder/rust/src/native.rs b/libs/binder/rust/src/native.rs
index da9d7dc..c87cc94 100644
--- a/libs/binder/rust/src/native.rs
+++ b/libs/binder/rust/src/native.rs
@@ -327,7 +327,7 @@
     /// contains a `T` pointer in its user data. fd should be a non-owned file
     /// descriptor, and args must be an array of null-terminated string
     /// pointers with length num_args.
-    #[cfg(not(target_os = "trusty"))]
+    #[cfg(not(trusty))]
     unsafe extern "C" fn on_dump(
         binder: *mut sys::AIBinder,
         fd: i32,
@@ -374,7 +374,7 @@
     }
 
     /// Called to handle the `dump` transaction.
-    #[cfg(target_os = "trusty")]
+    #[cfg(trusty)]
     unsafe extern "C" fn on_dump(
         _binder: *mut sys::AIBinder,
         _fd: i32,
diff --git a/libs/binder/rust/src/service.rs b/libs/binder/rust/src/service.rs
index 3ca3b54..29dd8e1 100644
--- a/libs/binder/rust/src/service.rs
+++ b/libs/binder/rust/src/service.rs
@@ -144,6 +144,7 @@
 
 /// Retrieve an existing service, blocking for a few seconds if it doesn't yet
 /// exist.
+#[deprecated = "this polls 5s, use wait_for_service or check_service"]
 pub fn get_service(name: &str) -> Option<SpIBinder> {
     let name = CString::new(name).ok()?;
     // Safety: `AServiceManager_getService` returns either a null pointer or a
@@ -152,6 +153,15 @@
     unsafe { SpIBinder::from_raw(sys::AServiceManager_getService(name.as_ptr())) }
 }
 
+/// Retrieve an existing service. Returns `None` immediately if the service is not available.
+pub fn check_service(name: &str) -> Option<SpIBinder> {
+    let name = CString::new(name).ok()?;
+    // Safety: `AServiceManager_checkService` returns either a null pointer or
+    // a valid pointer to an owned `AIBinder`. Either of these values is safe to
+    // pass to `SpIBinder::from_raw`.
+    unsafe { SpIBinder::from_raw(sys::AServiceManager_checkService(name.as_ptr())) }
+}
+
 /// Retrieve an existing service, or start it if it is configured as a dynamic
 /// service and isn't yet started.
 pub fn wait_for_service(name: &str) -> Option<SpIBinder> {
@@ -164,10 +174,17 @@
 
 /// Retrieve an existing service for a particular interface, blocking for a few
 /// seconds if it doesn't yet exist.
+#[deprecated = "this polls 5s, use wait_for_interface or check_interface"]
 pub fn get_interface<T: FromIBinder + ?Sized>(name: &str) -> Result<Strong<T>> {
     interface_cast(get_service(name))
 }
 
+/// Retrieve an existing service for a particular interface. Returns
+/// `Err(StatusCode::NAME_NOT_FOUND)` immediately if the service is not available.
+pub fn check_interface<T: FromIBinder + ?Sized>(name: &str) -> Result<Strong<T>> {
+    interface_cast(check_service(name))
+}
+
 /// Retrieve an existing service for a particular interface, or start it if it
 /// is configured as a dynamic service and isn't yet started.
 pub fn wait_for_interface<T: FromIBinder + ?Sized>(name: &str) -> Result<Strong<T>> {
diff --git a/libs/binder/rust/sys/lib.rs b/libs/binder/rust/sys/lib.rs
index c5c847b..5352473 100644
--- a/libs/binder/rust/sys/lib.rs
+++ b/libs/binder/rust/sys/lib.rs
@@ -25,7 +25,9 @@
 }
 
 // Trusty puts the full path to the auto-generated file in BINDGEN_INC_FILE
-// and builds it with warnings-as-errors, so we need to use #[allow(bad_style)]
+// and builds it with warnings-as-errors, so we need to use #[allow(bad_style)].
+// We need to use cfg(target_os) instead of cfg(trusty) here because of
+// the difference between the two build systems, which we cannot mock.
 #[cfg(target_os = "trusty")]
 #[allow(bad_style)]
 mod bindings {
diff --git a/libs/binder/rust/tests/integration.rs b/libs/binder/rust/tests/integration.rs
index c87fa89..15ae56f 100644
--- a/libs/binder/rust/tests/integration.rs
+++ b/libs/binder/rust/tests/integration.rs
@@ -421,7 +421,7 @@
     }
 
     #[test]
-    fn check_services() {
+    fn check_get_service() {
         let mut sm = binder::get_service("manager").expect("Did not get manager binder service");
         assert!(sm.is_binder_alive());
         assert!(sm.ping_binder().is_ok());
@@ -445,7 +445,7 @@
     }
 
     #[tokio::test]
-    async fn check_services_async() {
+    async fn check_get_service_async() {
         let mut sm = binder::get_service("manager").expect("Did not get manager binder service");
         assert!(sm.is_binder_alive());
         assert!(sm.ping_binder().is_ok());
@@ -474,6 +474,62 @@
     }
 
     #[test]
+    fn check_check_service() {
+        let mut sm = binder::check_service("manager").expect("Did not find manager binder service");
+        assert!(sm.is_binder_alive());
+        assert!(sm.ping_binder().is_ok());
+
+        assert!(binder::check_service("this_service_does_not_exist").is_none());
+        assert_eq!(
+            binder::check_interface::<dyn ITest>("this_service_does_not_exist").err(),
+            Some(StatusCode::NAME_NOT_FOUND)
+        );
+        assert_eq!(
+            binder::check_interface::<dyn IATest<Tokio>>("this_service_does_not_exist").err(),
+            Some(StatusCode::NAME_NOT_FOUND)
+        );
+
+        // The service manager service isn't an ITest, so this must fail.
+        assert_eq!(
+            binder::check_interface::<dyn ITest>("manager").err(),
+            Some(StatusCode::BAD_TYPE)
+        );
+        assert_eq!(
+            binder::check_interface::<dyn IATest<Tokio>>("manager").err(),
+            Some(StatusCode::BAD_TYPE)
+        );
+    }
+
+    #[tokio::test]
+    async fn check_check_service_async() {
+        let mut sm = binder::check_service("manager").expect("Did not find manager binder service");
+        assert!(sm.is_binder_alive());
+        assert!(sm.ping_binder().is_ok());
+
+        assert!(binder::check_service("this_service_does_not_exist").is_none());
+        assert_eq!(
+            binder_tokio::check_interface::<dyn ITest>("this_service_does_not_exist").await.err(),
+            Some(StatusCode::NAME_NOT_FOUND)
+        );
+        assert_eq!(
+            binder_tokio::check_interface::<dyn IATest<Tokio>>("this_service_does_not_exist")
+                .await
+                .err(),
+            Some(StatusCode::NAME_NOT_FOUND)
+        );
+
+        // The service manager service isn't an ITest, so this must fail.
+        assert_eq!(
+            binder_tokio::check_interface::<dyn ITest>("manager").await.err(),
+            Some(StatusCode::BAD_TYPE)
+        );
+        assert_eq!(
+            binder_tokio::check_interface::<dyn IATest<Tokio>>("manager").await.err(),
+            Some(StatusCode::BAD_TYPE)
+        );
+    }
+
+    #[test]
     fn check_wait_for_service() {
         let mut sm =
             binder::wait_for_service("manager").expect("Did not get manager binder service");
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index 424ff84..6800a8d 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -200,9 +200,11 @@
     defaults: [
         "binder_test_defaults",
     ],
+    header_libs: [
+        "libbinder_headers_base",
+    ],
     shared_libs: [
         "libbase",
-        "liblog",
     ],
     srcs: [
         "FileUtils.cpp",
@@ -436,6 +438,7 @@
     required: [
         "libbinder_on_trusty_mock",
         "libbinder_ndk_on_trusty_mock",
+        "libbinder_rs_on_trusty_mock",
         "binderRpcTestService_on_trusty_mock",
         "binderRpcTest_on_trusty_mock",
     ],
diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp
index 2cea14f..1f61f18 100644
--- a/libs/binder/tests/binderLibTest.cpp
+++ b/libs/binder/tests/binderLibTest.cpp
@@ -506,10 +506,11 @@
 
     // Pass test on devices where BINDER_FREEZE ioctl is not supported
     int ret = IPCThreadState::self()->freeze(pid, false, 0);
-    if (ret != 0) {
+    if (ret == -EINVAL) {
         GTEST_SKIP();
         return;
     }
+    EXPECT_EQ(NO_ERROR, ret);
 
     EXPECT_EQ(-EAGAIN, IPCThreadState::self()->freeze(pid, true, 0));
 
diff --git a/libs/binder/tests/binderThroughputTest.cpp b/libs/binder/tests/binderThroughputTest.cpp
index 10912c7..f912348 100644
--- a/libs/binder/tests/binderThroughputTest.cpp
+++ b/libs/binder/tests/binderThroughputTest.cpp
@@ -7,9 +7,10 @@
 #include <cstdlib>
 #include <cstdio>
 
+#include <fstream>
 #include <iostream>
-#include <vector>
 #include <tuple>
+#include <vector>
 
 #include <unistd.h>
 #include <sys/wait.h>
@@ -63,6 +64,18 @@
     uint64_t worst() {
         return *max_element(data.begin(), data.end());
     }
+    void dump_to_file(string filename) {
+        ofstream output;
+        output.open(filename);
+        if (!output.is_open()) {
+            cerr << "Failed to open '" << filename << "'." << endl;
+            exit(EXIT_FAILURE);
+        }
+        for (uint64_t value : data) {
+            output << value << "\n";
+        }
+        output.close();
+    }
     void dump() {
         if (data.size() == 0) {
             // This avoids index-out-of-bounds below.
@@ -293,12 +306,8 @@
     }
 }
 
-void run_main(int iterations,
-              int workers,
-              int payload_size,
-              int cs_pair,
-              bool training_round=false)
-{
+void run_main(int iterations, int workers, int payload_size, int cs_pair,
+              bool training_round = false, bool dump_to_file = false, string dump_filename = "") {
     vector<Pipe> pipes;
     // Create all the workers and wait for them to spawn.
     for (int i = 0; i < workers; i++) {
@@ -349,6 +358,9 @@
         warn_latency = 2 * tot_results.worst();
         cout << "Max latency during training: " << tot_results.worst() / 1.0E6 << "ms" << endl;
     } else {
+        if (dump_to_file) {
+            tot_results.dump_to_file(dump_filename);
+        }
         tot_results.dump();
     }
 }
@@ -361,6 +373,8 @@
     bool cs_pair = false;
     bool training_round = false;
     int max_time_us;
+    bool dump_to_file = false;
+    string dump_filename;
 
     // Parse arguments.
     for (int i = 1; i < argc; i++) {
@@ -372,6 +386,7 @@
             cout << "\t-s N    : Specify payload size." << endl;
             cout << "\t-t      : Run training round." << endl;
             cout << "\t-w N    : Specify total number of workers." << endl;
+            cout << "\t-d FILE : Dump raw data to file." << endl;
             return 0;
         }
         if (string(argv[i]) == "-w") {
@@ -430,14 +445,24 @@
             i++;
             continue;
         }
+        if (string(argv[i]) == "-d") {
+            if (i + 1 == argc) {
+                cout << "-d requires an argument\n" << endl;
+                exit(EXIT_FAILURE);
+            }
+            dump_to_file = true;
+            dump_filename = argv[i + 1];
+            i++;
+            continue;
+        }
     }
 
     if (training_round) {
         cout << "Start training round" << endl;
-        run_main(iterations, workers, payload_size, cs_pair, training_round=true);
+        run_main(iterations, workers, payload_size, cs_pair, true);
         cout << "Completed training round" << endl << endl;
     }
 
-    run_main(iterations, workers, payload_size, cs_pair);
+    run_main(iterations, workers, payload_size, cs_pair, false, dump_to_file, dump_filename);
     return 0;
 }
diff --git a/libs/binder/tests/unit_fuzzers/Android.bp b/libs/binder/tests/unit_fuzzers/Android.bp
index a881582..6871cca 100644
--- a/libs/binder/tests/unit_fuzzers/Android.bp
+++ b/libs/binder/tests/unit_fuzzers/Android.bp
@@ -52,6 +52,18 @@
             enabled: false,
         },
     },
+    fuzz_config: {
+        cc: [
+            "smoreland@google.com",
+            "waghpawan@google.com",
+        ],
+        componentid: 32456,
+        description: "The fuzzer targets the APIs of libbinder",
+        vector: "local_no_privileges_required",
+        service_privilege: "privileged",
+        users: "multi_user",
+        fuzzed_code_usage: "shipped",
+    },
 }
 
 cc_fuzz {
diff --git a/libs/binder/trusty/include/binder/ARpcServerTrusty.h b/libs/binder/trusty/include/binder/ARpcServerTrusty.h
new file mode 100644
index 0000000..c82268b
--- /dev/null
+++ b/libs/binder/trusty/include/binder/ARpcServerTrusty.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <lib/tipc/tipc_srv.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+struct AIBinder;
+struct ARpcServerTrusty;
+
+struct ARpcServerTrusty* ARpcServerTrusty_newPerSession(struct AIBinder* (*)(const void*, size_t,
+                                                                             char*),
+                                                        char*, void (*)(char*));
+void ARpcServerTrusty_delete(struct ARpcServerTrusty*);
+int ARpcServerTrusty_handleConnect(struct ARpcServerTrusty*, handle_t, const struct uuid*, void**);
+int ARpcServerTrusty_handleMessage(void*);
+void ARpcServerTrusty_handleDisconnect(void*);
+void ARpcServerTrusty_handleChannelCleanup(void*);
+
+#if defined(__cplusplus)
+}
+#endif
diff --git a/libs/binder/trusty/include/binder/RpcServerTrusty.h b/libs/binder/trusty/include/binder/RpcServerTrusty.h
index bd1d90f..fe44ea5 100644
--- a/libs/binder/trusty/include/binder/RpcServerTrusty.h
+++ b/libs/binder/trusty/include/binder/RpcServerTrusty.h
@@ -16,6 +16,7 @@
 
 #pragma once
 
+#include <binder/ARpcServerTrusty.h>
 #include <binder/IBinder.h>
 #include <binder/RpcServer.h>
 #include <binder/RpcSession.h>
@@ -100,6 +101,16 @@
         return rpcServer;
     }
 
+    friend struct ::ARpcServerTrusty;
+    friend ::ARpcServerTrusty* ::ARpcServerTrusty_newPerSession(::AIBinder* (*)(const void*, size_t,
+                                                                                char*),
+                                                                char*, void (*)(char*));
+    friend void ::ARpcServerTrusty_delete(::ARpcServerTrusty*);
+    friend int ::ARpcServerTrusty_handleConnect(::ARpcServerTrusty*, handle_t, const uuid*, void**);
+    friend int ::ARpcServerTrusty_handleMessage(void*);
+    friend void ::ARpcServerTrusty_handleDisconnect(void*);
+    friend void ::ARpcServerTrusty_handleChannelCleanup(void*);
+
     // The Rpc-specific context maintained for every open TIPC channel.
     struct ChannelContext {
         sp<RpcSession> session;
diff --git a/libs/binder/trusty/ndk/include/android/llndk-versioning.h b/libs/binder/trusty/ndk/include/android/llndk-versioning.h
new file mode 100644
index 0000000..3ae3d8f
--- /dev/null
+++ b/libs/binder/trusty/ndk/include/android/llndk-versioning.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#define __INTRODUCED_IN_LLNDK(x) /* nothing on Trusty */
diff --git a/libs/binder/trusty/ndk/include/sys/cdefs.h b/libs/binder/trusty/ndk/include/sys/cdefs.h
index 7528f2b..4e9b0e8 100644
--- a/libs/binder/trusty/ndk/include/sys/cdefs.h
+++ b/libs/binder/trusty/ndk/include/sys/cdefs.h
@@ -27,4 +27,3 @@
 #endif
 
 #define __INTRODUCED_IN(x) /* nothing on Trusty */
-#define __INTRODUCED_IN_LLNDK(x) /* nothing on Trusty */
diff --git a/libs/binder/trusty/rust/binder_ndk_sys/rules.mk b/libs/binder/trusty/rust/binder_ndk_sys/rules.mk
index 672d9b7..2aaa061 100644
--- a/libs/binder/trusty/rust/binder_ndk_sys/rules.mk
+++ b/libs/binder/trusty/rust/binder_ndk_sys/rules.mk
@@ -29,6 +29,10 @@
 	$(LIBBINDER_DIR)/trusty/ndk \
 	trusty/user/base/lib/trusty-sys \
 
+MODULE_RUSTFLAGS += \
+	--cfg 'android_vendor' \
+	--cfg 'trusty' \
+
 MODULE_BINDGEN_SRC_HEADER := $(LIBBINDER_DIR)/rust/sys/BinderBindings.hpp
 
 # Add the flags from the flag file
diff --git a/libs/binder/trusty/rust/binder_rpc_server_bindgen/cpp/ARpcServerTrusty.cpp b/libs/binder/trusty/rust/binder_rpc_server_bindgen/cpp/ARpcServerTrusty.cpp
new file mode 100644
index 0000000..451383a
--- /dev/null
+++ b/libs/binder/trusty/rust/binder_rpc_server_bindgen/cpp/ARpcServerTrusty.cpp
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android/binder_libbinder.h>
+#include <binder/RpcServer.h>
+#include <binder/RpcServerTrusty.h>
+#include <binder/RpcSession.h>
+#include <binder/RpcTransportTipcTrusty.h>
+
+using android::RpcServer;
+using android::RpcServerTrusty;
+using android::RpcSession;
+using android::RpcTransportCtxFactoryTipcTrusty;
+using android::sp;
+using android::wp;
+
+struct ARpcServerTrusty {
+    sp<RpcServer> mRpcServer;
+
+    ARpcServerTrusty() = delete;
+    ARpcServerTrusty(sp<RpcServer> rpcServer) : mRpcServer(std::move(rpcServer)) {}
+};
+
+ARpcServerTrusty* ARpcServerTrusty_newPerSession(AIBinder* (*cb)(const void*, size_t, char*),
+                                                 char* cbArg, void (*cbArgDeleter)(char*)) {
+    std::shared_ptr<char> cbArgSp(cbArg, cbArgDeleter);
+
+    auto rpcTransportCtxFactory = RpcTransportCtxFactoryTipcTrusty::make();
+    if (rpcTransportCtxFactory == nullptr) {
+        return nullptr;
+    }
+
+    auto ctx = rpcTransportCtxFactory->newServerCtx();
+    if (ctx == nullptr) {
+        return nullptr;
+    }
+
+    auto rpcServer = RpcServerTrusty::makeRpcServer(std::move(ctx));
+    if (rpcServer == nullptr) {
+        return nullptr;
+    }
+
+    rpcServer->setPerSessionRootObject(
+            [cb, cbArgSp](wp<RpcSession> /*session*/, const void* addrPtr, size_t len) {
+                auto* aib = (*cb)(addrPtr, len, cbArgSp.get());
+                auto b = AIBinder_toPlatformBinder(aib);
+
+                // We have a new sp<IBinder> backed by the same binder, so we can
+                // finally release the AIBinder* from the callback
+                AIBinder_decStrong(aib);
+
+                return b;
+            });
+
+    return new (std::nothrow) ARpcServerTrusty(std::move(rpcServer));
+}
+
+void ARpcServerTrusty_delete(ARpcServerTrusty* rstr) {
+    delete rstr;
+}
+
+int ARpcServerTrusty_handleConnect(ARpcServerTrusty* rstr, handle_t chan, const uuid* peer,
+                                   void** ctx_p) {
+    return RpcServerTrusty::handleConnectInternal(rstr->mRpcServer.get(), chan, peer, ctx_p);
+}
+
+int ARpcServerTrusty_handleMessage(void* ctx) {
+    return RpcServerTrusty::handleMessageInternal(ctx);
+}
+
+void ARpcServerTrusty_handleDisconnect(void* ctx) {
+    RpcServerTrusty::handleDisconnectInternal(ctx);
+}
+
+void ARpcServerTrusty_handleChannelCleanup(void* ctx) {
+    RpcServerTrusty::handleChannelCleanup(ctx);
+}
diff --git a/libs/binder/trusty/rust/binder_rpc_server_bindgen/cpp/rules.mk b/libs/binder/trusty/rust/binder_rpc_server_bindgen/cpp/rules.mk
new file mode 100644
index 0000000..6def634
--- /dev/null
+++ b/libs/binder/trusty/rust/binder_rpc_server_bindgen/cpp/rules.mk
@@ -0,0 +1,29 @@
+# Copyright (C) 2024 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_DIR := $(GET_LOCAL_DIR)
+LIBBINDER_DIR := $(LOCAL_DIR)/../../../..
+
+MODULE := $(LOCAL_DIR)
+
+MODULE_SRCS := \
+	$(LOCAL_DIR)/ARpcServerTrusty.cpp \
+
+MODULE_LIBRARY_DEPS += \
+	$(LIBBINDER_DIR)/trusty \
+	$(LIBBINDER_DIR)/trusty/ndk \
+	trusty/user/base/lib/libstdc++-trusty \
+
+include make/library.mk
diff --git a/libs/binder/trusty/rust/binder_rpc_server_bindgen/lib.rs b/libs/binder/trusty/rust/binder_rpc_server_bindgen/lib.rs
new file mode 100644
index 0000000..2e8b3ec
--- /dev/null
+++ b/libs/binder/trusty/rust/binder_rpc_server_bindgen/lib.rs
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//! Generated Rust bindings to binder_rpc_server
+
+#[allow(bad_style)]
+mod sys {
+    include!(env!("BINDGEN_INC_FILE"));
+}
+
+pub use sys::*;
diff --git a/libs/binder/trusty/rust/binder_rpc_server_bindgen/rules.mk b/libs/binder/trusty/rust/binder_rpc_server_bindgen/rules.mk
new file mode 100644
index 0000000..4ee333f
--- /dev/null
+++ b/libs/binder/trusty/rust/binder_rpc_server_bindgen/rules.mk
@@ -0,0 +1,37 @@
+# Copyright (C) 2024 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_DIR := $(GET_LOCAL_DIR)
+LIBBINDER_DIR := $(LOCAL_DIR)/../../..
+
+MODULE := $(LOCAL_DIR)
+
+MODULE_SRCS := $(LOCAL_DIR)/lib.rs
+
+MODULE_CRATE_NAME := binder_rpc_server_bindgen
+
+MODULE_LIBRARY_DEPS += \
+	$(LOCAL_DIR)/cpp \
+	trusty/user/base/lib/libstdc++-trusty \
+	trusty/user/base/lib/trusty-sys \
+
+MODULE_BINDGEN_SRC_HEADER := \
+	$(LIBBINDER_DIR)/trusty/include/binder/ARpcServerTrusty.h
+
+MODULE_BINDGEN_FLAGS += \
+	--allowlist-type="ARpcServerTrusty" \
+	--allowlist-function="ARpcServerTrusty_.*" \
+
+include make/library.mk
diff --git a/libs/binder/trusty/rust/binder_rpc_test/binder_rpc_test_session/lib.rs b/libs/binder/trusty/rust/binder_rpc_test/binder_rpc_test_session/lib.rs
new file mode 100644
index 0000000..22cba44
--- /dev/null
+++ b/libs/binder/trusty/rust/binder_rpc_test/binder_rpc_test_session/lib.rs
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+use binder::{Interface, ParcelFileDescriptor, SpIBinder, Status, StatusCode, Strong};
+use binder_rpc_test_aidl::aidl::IBinderRpcCallback::IBinderRpcCallback;
+use binder_rpc_test_aidl::aidl::IBinderRpcSession::IBinderRpcSession;
+use binder_rpc_test_aidl::aidl::IBinderRpcTest::IBinderRpcTest;
+use std::sync::Mutex;
+
+static G_NUM: Mutex<i32> = Mutex::new(0);
+
+#[derive(Debug, Default)]
+pub struct MyBinderRpcSession {
+    name: String,
+}
+
+impl MyBinderRpcSession {
+    pub fn new(name: &str) -> Self {
+        Self::increment_instance_count();
+        Self { name: name.to_string() }
+    }
+
+    pub fn get_instance_count() -> i32 {
+        *G_NUM.lock().unwrap()
+    }
+
+    fn increment_instance_count() {
+        *G_NUM.lock().unwrap() += 1;
+    }
+
+    fn decrement_instance_count() {
+        *G_NUM.lock().unwrap() -= 1;
+    }
+}
+
+impl Drop for MyBinderRpcSession {
+    fn drop(&mut self) {
+        MyBinderRpcSession::decrement_instance_count();
+    }
+}
+
+impl Interface for MyBinderRpcSession {}
+
+impl IBinderRpcSession for MyBinderRpcSession {
+    fn getName(&self) -> Result<String, Status> {
+        Ok(self.name.clone())
+    }
+}
+
+impl IBinderRpcTest for MyBinderRpcSession {
+    fn sendString(&self, _: &str) -> Result<(), Status> {
+        todo!()
+    }
+    fn doubleString(&self, _s: &str) -> Result<String, Status> {
+        todo!()
+    }
+    fn getClientPort(&self) -> Result<i32, Status> {
+        todo!()
+    }
+    fn countBinders(&self) -> Result<Vec<i32>, Status> {
+        todo!()
+    }
+    fn getNullBinder(&self) -> Result<SpIBinder, Status> {
+        todo!()
+    }
+    fn pingMe(&self, _binder: &SpIBinder) -> Result<i32, Status> {
+        todo!()
+    }
+    fn repeatBinder(&self, _binder: Option<&SpIBinder>) -> Result<Option<SpIBinder>, Status> {
+        todo!()
+    }
+    fn holdBinder(&self, _binder: Option<&SpIBinder>) -> Result<(), Status> {
+        todo!()
+    }
+    fn getHeldBinder(&self) -> Result<Option<SpIBinder>, Status> {
+        todo!()
+    }
+    fn nestMe(
+        &self,
+        binder: &Strong<(dyn IBinderRpcTest + 'static)>,
+        count: i32,
+    ) -> Result<(), Status> {
+        if count < 0 {
+            Ok(())
+        } else {
+            binder.nestMe(binder, count - 1)
+        }
+    }
+    fn alwaysGiveMeTheSameBinder(&self) -> Result<SpIBinder, Status> {
+        todo!()
+    }
+    fn openSession(
+        &self,
+        _name: &str,
+    ) -> Result<Strong<(dyn IBinderRpcSession + 'static)>, Status> {
+        todo!()
+    }
+    fn getNumOpenSessions(&self) -> Result<i32, Status> {
+        todo!()
+    }
+    fn lock(&self) -> Result<(), Status> {
+        todo!()
+    }
+    fn unlockInMsAsync(&self, _: i32) -> Result<(), Status> {
+        todo!()
+    }
+    fn lockUnlock(&self) -> Result<(), Status> {
+        todo!()
+    }
+    fn sleepMs(&self, _: i32) -> Result<(), Status> {
+        todo!()
+    }
+    fn sleepMsAsync(&self, _: i32) -> Result<(), Status> {
+        todo!()
+    }
+    fn doCallback(
+        &self,
+        _: &Strong<(dyn IBinderRpcCallback + 'static)>,
+        _: bool,
+        _: bool,
+        _: &str,
+    ) -> Result<(), Status> {
+        todo!()
+    }
+    fn doCallbackAsync(
+        &self,
+        _: &Strong<(dyn IBinderRpcCallback + 'static)>,
+        _: bool,
+        _: bool,
+        _: &str,
+    ) -> Result<(), Status> {
+        todo!()
+    }
+    fn die(&self, _: bool) -> Result<(), Status> {
+        Err(Status::from(StatusCode::UNKNOWN_TRANSACTION))
+    }
+    fn scheduleShutdown(&self) -> Result<(), Status> {
+        todo!()
+    }
+    fn useKernelBinderCallingId(&self) -> Result<(), Status> {
+        todo!()
+    }
+    fn echoAsFile(&self, _: &str) -> Result<ParcelFileDescriptor, Status> {
+        todo!()
+    }
+    fn concatFiles(&self, _: &[ParcelFileDescriptor]) -> Result<ParcelFileDescriptor, Status> {
+        todo!()
+    }
+    fn blockingSendFdOneway(&self, _: &ParcelFileDescriptor) -> Result<(), Status> {
+        todo!()
+    }
+    fn blockingRecvFd(&self) -> Result<ParcelFileDescriptor, Status> {
+        todo!()
+    }
+    fn blockingSendIntOneway(&self, _: i32) -> Result<(), Status> {
+        todo!()
+    }
+    fn blockingRecvInt(&self) -> Result<i32, Status> {
+        todo!()
+    }
+}
diff --git a/libs/binder/trusty/rust/binder_rpc_test/binder_rpc_test_session/rules.mk b/libs/binder/trusty/rust/binder_rpc_test/binder_rpc_test_session/rules.mk
new file mode 100644
index 0000000..ae26355
--- /dev/null
+++ b/libs/binder/trusty/rust/binder_rpc_test/binder_rpc_test_session/rules.mk
@@ -0,0 +1,32 @@
+# Copyright (C) 2023 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_DIR := $(GET_LOCAL_DIR)
+LIBBINDER_DIR := $(LOCAL_DIR)/../../../..
+
+MODULE := $(LOCAL_DIR)
+
+MODULE_SRCS := $(LOCAL_DIR)/lib.rs
+
+MODULE_CRATE_NAME := binder_rpc_test_session
+
+MODULE_LIBRARY_DEPS += \
+	$(LIBBINDER_DIR)/trusty/rust \
+	$(LIBBINDER_DIR)/trusty/rust/rpcbinder \
+	$(LOCAL_DIR)/../aidl \
+	$(call FIND_CRATE,log) \
+	trusty/user/base/lib/trusty-std \
+
+include make/library.mk
diff --git a/libs/binder/trusty/rust/binder_rpc_test/main.rs b/libs/binder/trusty/rust/binder_rpc_test/main.rs
index a71ce2c..baea5a8 100644
--- a/libs/binder/trusty/rust/binder_rpc_test/main.rs
+++ b/libs/binder/trusty/rust/binder_rpc_test/main.rs
@@ -15,22 +15,203 @@
  */
 #![cfg(test)]
 
-use binder::{IBinder, Strong};
-use binder_rpc_test_aidl::aidl::IBinderRpcTest::IBinderRpcTest;
+use binder::{BinderFeatures, IBinder, Status, StatusCode, Strong};
+use binder_rpc_test_aidl::aidl::IBinderRpcSession::{BnBinderRpcSession, IBinderRpcSession};
+use binder_rpc_test_aidl::aidl::IBinderRpcTest::{BnBinderRpcTest, IBinderRpcTest};
+use binder_rpc_test_session::MyBinderRpcSession;
+use libc::{clock_gettime, CLOCK_REALTIME};
 use rpcbinder::RpcSession;
 use trusty_std::ffi::{CString, FallibleCString};
 
 test::init!();
 
 const SERVICE_PORT: &str = "com.android.trusty.binderRpcTestService.V1";
+const RUST_SERVICE_PORT: &str = "com.android.trusty.rust.binderRpcTestService.V1";
 
-fn get_service() -> Strong<dyn IBinderRpcTest> {
-    let port = CString::try_new(SERVICE_PORT).expect("Failed to allocate port name");
+macro_rules! service_test {
+    ($c_name:ident, $rust_name:ident, $body:expr) => {
+        #[test]
+        fn $c_name() {
+            $body(get_service(SERVICE_PORT))
+        }
+        #[test]
+        fn $rust_name() {
+            $body(get_service(RUST_SERVICE_PORT))
+        }
+    };
+}
+
+fn get_service(port: &str) -> Strong<dyn IBinderRpcTest> {
+    let port = CString::try_new(port).expect("Failed to allocate port name");
     RpcSession::new().setup_trusty_client(port.as_c_str()).expect("Failed to create session")
 }
 
-#[test]
-fn ping() {
-    let srv = get_service();
-    assert_eq!(srv.as_binder().ping_binder(), Ok(()));
+fn expect_sessions(expected: i32, srv: &Strong<dyn IBinderRpcTest>) {
+    let count = srv.getNumOpenSessions();
+    assert!(count.is_ok());
+    assert_eq!(expected, count.unwrap());
 }
+
+fn get_time_ns() -> u64 {
+    let mut ts = libc::timespec { tv_sec: 0, tv_nsec: 0 };
+
+    // Safety: Passing valid pointer to variable ts which lives past end of call
+    assert_eq!(unsafe { clock_gettime(CLOCK_REALTIME, &mut ts) }, 0);
+
+    ts.tv_sec as u64 * 1_000_000_000u64 + ts.tv_nsec as u64
+}
+
+fn get_time_ms() -> u64 {
+    get_time_ns() / 1_000_000u64
+}
+
+// ----------
+
+service_test! {ping, ping_rust, |srv: Strong<dyn IBinderRpcTest>| {
+    assert_eq!(srv.as_binder().ping_binder(), Ok(()));
+}}
+
+service_test! {send_something_oneway, send_something_oneway_rust, |srv: Strong<dyn IBinderRpcTest>| {
+    assert_eq!(srv.sendString("Foo"), Ok(()));
+}}
+
+service_test! {send_and_get_result_back, send_and_get_result_back_rust, |srv: Strong<dyn IBinderRpcTest>| {
+    assert_eq!(srv.doubleString("Foo"), Ok(String::from("FooFoo")));
+}}
+
+service_test! {send_and_get_result_back_big, send_and_get_result_back_big_rust, |srv: Strong<dyn IBinderRpcTest>| {
+    let single_len = 512;
+    let single = "a".repeat(single_len);
+    assert_eq!(srv.doubleString(&single), Ok(String::from(single.clone() + &single)));
+}}
+
+service_test! {invalid_null_binder_return, invalid_null_binder_return_rust, |srv: Strong<dyn IBinderRpcTest>| {
+    let binder = srv.getNullBinder();
+    assert!(binder == Err(Status::from(StatusCode::UNEXPECTED_NULL)) || binder == Err(Status::from(StatusCode::UNKNOWN_TRANSACTION)));
+}}
+
+service_test! {call_me_back, call_me_back_rust, |srv: Strong<dyn IBinderRpcTest>| {
+    let binder =
+        BnBinderRpcSession::new_binder(MyBinderRpcSession::new("Foo"), BinderFeatures::default())
+            .as_binder();
+    let result = srv.pingMe(&binder);
+    assert_eq!(result, Ok(0));
+}}
+
+service_test! {repeat_binder, repeat_binder_rust, |srv: Strong<dyn IBinderRpcTest>| {
+    let in_binder =
+        BnBinderRpcSession::new_binder(MyBinderRpcSession::new("Foo"), BinderFeatures::default())
+            .as_binder();
+    let result = srv.repeatBinder(Some(&in_binder));
+    assert_eq!(result.unwrap().unwrap(), in_binder);
+}}
+
+service_test! {repeat_their_binder, repeat_their_binder_rust, |srv: Strong<dyn IBinderRpcTest>| {
+    let session = srv.openSession("Test");
+    assert!(session.is_ok());
+
+    let in_binder = session.unwrap().as_binder();
+    let out_binder = srv.repeatBinder(Some(&in_binder));
+    assert_eq!(out_binder.unwrap().unwrap(), in_binder);
+}}
+
+service_test! {hold_binder, hold_binder_rust, |srv: Strong<dyn IBinderRpcTest>| {
+    let name = "Foo";
+
+    let binder =
+        BnBinderRpcSession::new_binder(MyBinderRpcSession::new(name), BinderFeatures::default())
+            .as_binder();
+    assert!(srv.holdBinder(Some(&binder)).is_ok());
+
+    let held = srv.getHeldBinder();
+    assert!(held.is_ok());
+    let held = held.unwrap();
+    assert!(held.is_some());
+    let held = held.unwrap();
+    assert_eq!(binder, held);
+
+    let session = held.into_interface::<dyn IBinderRpcSession>();
+    assert!(session.is_ok());
+
+    let session_name = session.unwrap().getName();
+    assert!(session_name.is_ok());
+    let session_name = session_name.unwrap();
+    assert_eq!(session_name, name);
+
+    assert!(srv.holdBinder(None).is_ok());
+}}
+
+service_test! {nested_transactions, nested_transactions_rust, |srv: Strong<dyn IBinderRpcTest>| {
+    let binder =
+        BnBinderRpcTest::new_binder(MyBinderRpcSession::new("Nest"), BinderFeatures::default());
+    assert!(srv.nestMe(&binder, 10).is_ok());
+}}
+
+service_test! {same_binder_equality, same_binder_equality_rust, |srv: Strong<dyn IBinderRpcTest>| {
+    let a = srv.alwaysGiveMeTheSameBinder();
+    assert!(a.is_ok());
+
+    let b = srv.alwaysGiveMeTheSameBinder();
+    assert!(b.is_ok());
+
+    assert_eq!(a.unwrap(), b.unwrap());
+}}
+
+service_test! {single_session, single_session_rust, |srv: Strong<dyn IBinderRpcTest>| {
+    let session = srv.openSession("aoeu");
+    assert!(session.is_ok());
+    let session = session.unwrap();
+    let name = session.getName();
+    assert!(name.is_ok());
+    assert_eq!(name.unwrap(), "aoeu");
+
+    let count = srv.getNumOpenSessions();
+    assert!(count.is_ok());
+    assert_eq!(count.unwrap(), 1);
+
+    drop(session);
+    let count = srv.getNumOpenSessions();
+    assert!(count.is_ok());
+    assert_eq!(count.unwrap(), 0);
+}}
+
+service_test! {many_session, many_session_rust, |srv: Strong<dyn IBinderRpcTest>| {
+    let mut sessions = Vec::new();
+
+    for i in 0..15 {
+        expect_sessions(i, &srv);
+
+        let session = srv.openSession(&(i.to_string()));
+        assert!(session.is_ok());
+        sessions.push(session.unwrap());
+    }
+
+    expect_sessions(sessions.len() as i32, &srv);
+
+    for i in 0..sessions.len() {
+        let name = sessions[i].getName();
+        assert!(name.is_ok());
+        assert_eq!(name.unwrap(), i.to_string());
+    }
+
+    expect_sessions(sessions.len() as i32, &srv);
+
+    while !sessions.is_empty() {
+        sessions.pop();
+
+        expect_sessions(sessions.len() as i32, &srv);
+    }
+
+    expect_sessions(0, &srv);
+}}
+
+service_test! {one_way_call_does_not_wait, one_way_call_does_not_wait_rust, |srv: Strong<dyn IBinderRpcTest>| {
+    let really_long_time_ms = 100;
+    let sleep_ms = really_long_time_ms * 5;
+
+    let before = get_time_ms();
+    let _ = srv.sleepMsAsync(sleep_ms);
+    let after = get_time_ms();
+
+    assert!(after < before + really_long_time_ms as u64);
+}}
diff --git a/libs/binder/trusty/rust/binder_rpc_test/manifest.json b/libs/binder/trusty/rust/binder_rpc_test/manifest.json
index c2ecaa4..384ed44 100644
--- a/libs/binder/trusty/rust/binder_rpc_test/manifest.json
+++ b/libs/binder/trusty/rust/binder_rpc_test/manifest.json
@@ -1,7 +1,7 @@
 {
     "uuid": "91eed949-8a9e-4569-9c83-5935fb624025",
     "app_name": "rust_binder_rpc_test",
-    "min_heap": 16384,
+    "min_heap": 32768,
     "min_stack": 16384,
     "mgmt_flags": {
         "non_critical_app": true
diff --git a/libs/binder/trusty/rust/binder_rpc_test/rules.mk b/libs/binder/trusty/rust/binder_rpc_test/rules.mk
index 192a159..8347a35 100644
--- a/libs/binder/trusty/rust/binder_rpc_test/rules.mk
+++ b/libs/binder/trusty/rust/binder_rpc_test/rules.mk
@@ -26,6 +26,8 @@
 	$(LIBBINDER_DIR)/trusty/rust \
 	$(LIBBINDER_DIR)/trusty/rust/rpcbinder \
 	$(LOCAL_DIR)/aidl \
+	$(LOCAL_DIR)/binder_rpc_test_session \
+	$(call FIND_CRATE,log) \
 	trusty/user/base/lib/trusty-std \
 
 MODULE_RUST_TESTS := true
diff --git a/libs/binder/trusty/rust/binder_rpc_test/service/main.rs b/libs/binder/trusty/rust/binder_rpc_test/service/main.rs
new file mode 100644
index 0000000..c4a758a
--- /dev/null
+++ b/libs/binder/trusty/rust/binder_rpc_test/service/main.rs
@@ -0,0 +1,234 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+use binder::{
+    BinderFeatures, IBinder, Interface, ParcelFileDescriptor, SpIBinder, Status, StatusCode, Strong,
+};
+use binder_rpc_test_aidl::aidl::IBinderRpcCallback::IBinderRpcCallback;
+use binder_rpc_test_aidl::aidl::IBinderRpcSession::{BnBinderRpcSession, IBinderRpcSession};
+use binder_rpc_test_aidl::aidl::IBinderRpcTest::{BnBinderRpcTest, IBinderRpcTest};
+use binder_rpc_test_session::MyBinderRpcSession;
+use libc::{c_long, nanosleep, timespec};
+use rpcbinder::RpcServer;
+use std::rc::Rc;
+use std::sync::Mutex;
+use tipc::{service_dispatcher, wrap_service, Manager, PortCfg};
+
+const RUST_SERVICE_PORT: &str = "com.android.trusty.rust.binderRpcTestService.V1";
+
+// -----------------------------------------------------------------------------
+
+static SESSION_COUNT: Mutex<i32> = Mutex::new(0);
+static HOLD_BINDER: Mutex<Option<SpIBinder>> = Mutex::new(None);
+static SAME_BINDER: Mutex<Option<SpIBinder>> = Mutex::new(None);
+
+#[derive(Debug, Default)]
+struct TestService {
+    port: i32,
+    name: String,
+}
+
+#[allow(dead_code)]
+impl TestService {
+    fn new(name: &str) -> Self {
+        *SESSION_COUNT.lock().unwrap() += 1;
+        Self { name: name.to_string(), ..Default::default() }
+    }
+
+    fn get_instance_count() -> i32 {
+        *SESSION_COUNT.lock().unwrap()
+    }
+}
+
+impl Drop for TestService {
+    fn drop(&mut self) {
+        *SESSION_COUNT.lock().unwrap() -= 1;
+    }
+}
+
+impl Interface for TestService {}
+
+impl IBinderRpcSession for TestService {
+    fn getName(&self) -> Result<String, Status> {
+        Ok(self.name.clone())
+    }
+}
+
+impl IBinderRpcTest for TestService {
+    fn sendString(&self, _: &str) -> Result<(), Status> {
+        // This is a oneway function, so caller returned immediately and gives back an Ok(()) regardless of what this returns
+        Ok(())
+    }
+    fn doubleString(&self, s: &str) -> Result<String, Status> {
+        let ss = [s, s].concat();
+        Ok(ss)
+    }
+    fn getClientPort(&self) -> Result<i32, Status> {
+        Ok(self.port)
+    }
+    fn countBinders(&self) -> Result<Vec<i32>, Status> {
+        todo!()
+    }
+    fn getNullBinder(&self) -> Result<SpIBinder, Status> {
+        Err(Status::from(StatusCode::UNKNOWN_TRANSACTION))
+    }
+    fn pingMe(&self, binder: &SpIBinder) -> Result<i32, Status> {
+        match binder.clone().ping_binder() {
+            Ok(()) => Ok(StatusCode::OK as i32),
+            Err(e) => Err(Status::from(e)),
+        }
+    }
+    fn repeatBinder(&self, binder: Option<&SpIBinder>) -> Result<Option<SpIBinder>, Status> {
+        match binder {
+            Some(x) => Ok(Some(x.clone())),
+            None => Err(Status::from(StatusCode::BAD_VALUE)),
+        }
+    }
+    fn holdBinder(&self, binder: Option<&SpIBinder>) -> Result<(), Status> {
+        *HOLD_BINDER.lock().unwrap() = binder.cloned();
+        Ok(())
+    }
+    fn getHeldBinder(&self) -> Result<Option<SpIBinder>, Status> {
+        Ok((*HOLD_BINDER.lock().unwrap()).clone())
+    }
+    fn nestMe(
+        &self,
+        binder: &Strong<(dyn IBinderRpcTest + 'static)>,
+        count: i32,
+    ) -> Result<(), Status> {
+        if count < 0 {
+            Ok(())
+        } else {
+            binder.nestMe(binder, count - 1)
+        }
+    }
+    fn alwaysGiveMeTheSameBinder(&self) -> Result<SpIBinder, Status> {
+        let mut locked = SAME_BINDER.lock().unwrap();
+        Ok((*locked)
+            .get_or_insert_with(|| {
+                BnBinderRpcTest::new_binder(TestService::default(), BinderFeatures::default())
+                    .as_binder()
+            })
+            .clone())
+    }
+    fn openSession(&self, name: &str) -> Result<Strong<(dyn IBinderRpcSession + 'static)>, Status> {
+        let s = BnBinderRpcSession::new_binder(
+            MyBinderRpcSession::new(name),
+            BinderFeatures::default(),
+        );
+        Ok(s)
+    }
+    fn getNumOpenSessions(&self) -> Result<i32, Status> {
+        let count = MyBinderRpcSession::get_instance_count();
+        Ok(count)
+    }
+    fn lock(&self) -> Result<(), Status> {
+        todo!()
+    }
+    fn unlockInMsAsync(&self, _: i32) -> Result<(), Status> {
+        todo!()
+    }
+    fn lockUnlock(&self) -> Result<(), Status> {
+        todo!()
+    }
+    fn sleepMs(&self, ms: i32) -> Result<(), Status> {
+        let ts = timespec {
+            tv_sec: (ms / 1000) as c_long,
+            tv_nsec: (ms % 1000) as c_long * 1_000_000 as c_long,
+        };
+
+        let mut rem = timespec { tv_sec: 0, tv_nsec: 0 };
+
+        // Safety: Passing valid pointers to variables ts & rem which live past end of call
+        assert_eq!(unsafe { nanosleep(&ts, &mut rem) }, 0);
+
+        Ok(())
+    }
+    fn sleepMsAsync(&self, ms: i32) -> Result<(), Status> {
+        self.sleepMs(ms)
+    }
+    fn doCallback(
+        &self,
+        _: &Strong<(dyn IBinderRpcCallback + 'static)>,
+        _: bool,
+        _: bool,
+        _: &str,
+    ) -> Result<(), Status> {
+        todo!()
+    }
+    fn doCallbackAsync(
+        &self,
+        _: &Strong<(dyn IBinderRpcCallback + 'static)>,
+        _: bool,
+        _: bool,
+        _: &str,
+    ) -> Result<(), Status> {
+        todo!()
+    }
+    fn die(&self, _: bool) -> Result<(), Status> {
+        Err(Status::from(StatusCode::UNKNOWN_TRANSACTION))
+    }
+    fn scheduleShutdown(&self) -> Result<(), Status> {
+        todo!()
+    }
+    fn useKernelBinderCallingId(&self) -> Result<(), Status> {
+        todo!()
+    }
+    fn echoAsFile(&self, _: &str) -> Result<ParcelFileDescriptor, Status> {
+        todo!()
+    }
+    fn concatFiles(&self, _: &[ParcelFileDescriptor]) -> Result<ParcelFileDescriptor, Status> {
+        todo!()
+    }
+    fn blockingSendFdOneway(&self, _: &ParcelFileDescriptor) -> Result<(), Status> {
+        todo!()
+    }
+    fn blockingRecvFd(&self) -> Result<ParcelFileDescriptor, Status> {
+        todo!()
+    }
+    fn blockingSendIntOneway(&self, _: i32) -> Result<(), Status> {
+        todo!()
+    }
+    fn blockingRecvInt(&self) -> Result<i32, Status> {
+        todo!()
+    }
+}
+
+wrap_service!(TestRpcServer(RpcServer: UnbufferedService));
+
+service_dispatcher! {
+    enum TestDispatcher {
+        TestRpcServer,
+    }
+}
+
+fn main() {
+    let mut dispatcher = TestDispatcher::<1>::new().expect("Could not create test dispatcher");
+
+    let service = BnBinderRpcTest::new_binder(TestService::default(), BinderFeatures::default());
+    let rpc_server =
+        TestRpcServer::new(RpcServer::new_per_session(move |_uuid| Some(service.as_binder())));
+
+    let cfg = PortCfg::new(RUST_SERVICE_PORT)
+        .expect("Could not create port config")
+        .allow_ta_connect()
+        .allow_ns_connect();
+    dispatcher.add_service(Rc::new(rpc_server), cfg).expect("Could not add service to dispatcher");
+
+    Manager::<_, _, 1, 4>::new_with_dispatcher(dispatcher, [])
+        .expect("Could not create service manager")
+        .run_event_loop()
+        .expect("Test event loop failed");
+}
diff --git a/libs/binder/trusty/rust/binder_rpc_test/service/manifest.json b/libs/binder/trusty/rust/binder_rpc_test/service/manifest.json
new file mode 100644
index 0000000..121ba11
--- /dev/null
+++ b/libs/binder/trusty/rust/binder_rpc_test/service/manifest.json
@@ -0,0 +1,10 @@
+{
+    "uuid": "4741fc65-8b65-4893-ba55-b182c003c8b7",
+    "app_name": "rust_binder_rpc_test_service",
+    "min_heap": 16384,
+    "min_stack": 16384,
+    "mgmt_flags": {
+        "non_critical_app": true,
+        "restart_on_exit": true
+    }
+}
diff --git a/libs/binder/trusty/rust/binder_rpc_test/service/rules.mk b/libs/binder/trusty/rust/binder_rpc_test/service/rules.mk
new file mode 100644
index 0000000..f71ee9b
--- /dev/null
+++ b/libs/binder/trusty/rust/binder_rpc_test/service/rules.mk
@@ -0,0 +1,36 @@
+# Copyright (C) 2023 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_DIR := $(GET_LOCAL_DIR)
+LIBBINDER_DIR := $(LOCAL_DIR)/../../../..
+
+MODULE := $(LOCAL_DIR)
+
+MODULE_SRCS := $(LOCAL_DIR)/main.rs
+
+MODULE_CRATE_NAME := binder_rpc_test_service
+
+MODULE_LIBRARY_DEPS += \
+	$(LIBBINDER_DIR)/trusty/rust \
+	$(LIBBINDER_DIR)/trusty/rust/rpcbinder \
+	$(LIBBINDER_DIR)/trusty/rust/binder_rpc_server \
+	$(LOCAL_DIR)/../aidl \
+	$(LOCAL_DIR)/../binder_rpc_test_session \
+	$(LOCAL_DIR)/.. \
+	trusty/user/base/lib/tipc/rust \
+
+MANIFEST := $(LOCAL_DIR)/manifest.json
+
+include make/trusted_app.mk
diff --git a/libs/binder/trusty/rust/rpcbinder/rules.mk b/libs/binder/trusty/rust/rpcbinder/rules.mk
index 76f3b94..97f5c03 100644
--- a/libs/binder/trusty/rust/rpcbinder/rules.mk
+++ b/libs/binder/trusty/rust/rpcbinder/rules.mk
@@ -28,6 +28,8 @@
 	$(LIBBINDER_DIR)/trusty/rust \
 	$(LIBBINDER_DIR)/trusty/rust/binder_ndk_sys \
 	$(LIBBINDER_DIR)/trusty/rust/binder_rpc_unstable_bindgen \
+	$(LIBBINDER_DIR)/trusty/rust/binder_rpc_server_bindgen \
+	external/rust/crates/cfg-if \
 	external/rust/crates/foreign-types \
 	trusty/user/base/lib/tipc/rust \
 	trusty/user/base/lib/trusty-sys \
diff --git a/libs/binder/trusty/rust/rules.mk b/libs/binder/trusty/rust/rules.mk
index d343f14..36bd3a2 100644
--- a/libs/binder/trusty/rust/rules.mk
+++ b/libs/binder/trusty/rust/rules.mk
@@ -28,10 +28,12 @@
 	$(LIBBINDER_DIR)/trusty/rust/binder_ndk_sys \
 	$(LIBBINDER_DIR)/trusty/rust/binder_rpc_unstable_bindgen \
 	external/rust/crates/downcast-rs \
+	external/rust/crates/libc \
 	trusty/user/base/lib/trusty-sys \
 
 MODULE_RUSTFLAGS += \
 	--cfg 'android_vendor' \
+	--cfg 'trusty' \
 
 # Trusty does not have `ProcessState`, so there are a few
 # doc links in `IBinder` that are still broken.
diff --git a/libs/binder/trusty/usertests-inc.mk b/libs/binder/trusty/usertests-inc.mk
index 241e668..833d209 100644
--- a/libs/binder/trusty/usertests-inc.mk
+++ b/libs/binder/trusty/usertests-inc.mk
@@ -16,6 +16,7 @@
 TRUSTY_USER_TESTS += \
 	frameworks/native/libs/binder/trusty/binderRpcTest \
 	frameworks/native/libs/binder/trusty/binderRpcTest/service \
+	frameworks/native/libs/binder/trusty/rust/binder_rpc_test/service \
 
 TRUSTY_RUST_USER_TESTS += \
 	frameworks/native/libs/binder/trusty/rust/binder_rpc_test \
diff --git a/libs/bufferstreams/Android.bp b/libs/bufferstreams/Android.bp
index 365fc45..6c2a980 100644
--- a/libs/bufferstreams/Android.bp
+++ b/libs/bufferstreams/Android.bp
@@ -19,6 +19,7 @@
 aconfig_declarations {
     name: "bufferstreams_flags",
     package: "com.android.graphics.bufferstreams.flags",
+    container: "system",
     srcs: [
         "aconfig/bufferstreams_flags.aconfig",
     ],
diff --git a/libs/bufferstreams/aconfig/bufferstreams_flags.aconfig b/libs/bufferstreams/aconfig/bufferstreams_flags.aconfig
index e258725..d0f7812 100644
--- a/libs/bufferstreams/aconfig/bufferstreams_flags.aconfig
+++ b/libs/bufferstreams/aconfig/bufferstreams_flags.aconfig
@@ -1,4 +1,5 @@
 package: "com.android.graphics.bufferstreams.flags"
+container: "system"
 
 flag {
   name: "bufferstreams_steel_thread"
diff --git a/libs/bufferstreams/rust/src/publishers/buffer_pool_publisher.rs b/libs/bufferstreams/rust/src/publishers/buffer_pool_publisher.rs
index 846105d..c5c1fd3 100644
--- a/libs/bufferstreams/rust/src/publishers/buffer_pool_publisher.rs
+++ b/libs/bufferstreams/rust/src/publishers/buffer_pool_publisher.rs
@@ -12,8 +12,6 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-//!
-
 use std::time::Instant;
 
 use crate::{
diff --git a/libs/cputimeinstate/testtimeinstate.cpp b/libs/cputimeinstate/testtimeinstate.cpp
index 6ccc6ca..81f6a58 100644
--- a/libs/cputimeinstate/testtimeinstate.cpp
+++ b/libs/cputimeinstate/testtimeinstate.cpp
@@ -40,6 +40,9 @@
 static constexpr uint64_t NSEC_PER_SEC = 1000000000;
 static constexpr uint64_t NSEC_PER_YEAR = NSEC_PER_SEC * 60 * 60 * 24 * 365;
 
+// Declare busy loop variable globally to prevent removal during optimization
+static long sum __attribute__((used)) = 0;
+
 using std::vector;
 
 class TimeInStateTest : public testing::Test {
@@ -576,7 +579,7 @@
 
 // Keeps CPU busy with some number crunching
 void useCpu() {
-    long sum = 0;
+    sum = 0;
     for (int i = 0; i < 100000; i++) {
         sum *= i;
     }
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index 8643148..059e19e 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -23,6 +23,7 @@
 aconfig_declarations {
     name: "libgui_flags",
     package: "com.android.graphics.libgui.flags",
+    container: "system",
     srcs: ["libgui_flags.aconfig"],
 }
 
diff --git a/libs/gui/libgui_flags.aconfig b/libs/gui/libgui_flags.aconfig
index b081030..3864699 100644
--- a/libs/gui/libgui_flags.aconfig
+++ b/libs/gui/libgui_flags.aconfig
@@ -1,4 +1,5 @@
 package: "com.android.graphics.libgui.flags"
+container: "system"
 
 flag {
   name: "bq_setframerate"
diff --git a/libs/input/Android.bp b/libs/input/Android.bp
index 252040d..20b3538 100644
--- a/libs/input/Android.bp
+++ b/libs/input/Android.bp
@@ -39,6 +39,7 @@
 aconfig_declarations {
     name: "com.android.input.flags-aconfig",
     package: "com.android.input.flags",
+    container: "system",
     srcs: ["input_flags.aconfig"],
 }
 
diff --git a/libs/input/input_flags.aconfig b/libs/input/input_flags.aconfig
index 54eeb39..dbc002c 100644
--- a/libs/input/input_flags.aconfig
+++ b/libs/input/input_flags.aconfig
@@ -1,4 +1,5 @@
 package: "com.android.input.flags"
+container: "system"
 
 flag {
   name: "enable_outbound_event_verification"
diff --git a/libs/input/tests/Android.bp b/libs/input/tests/Android.bp
index 13cfb49..9137a34 100644
--- a/libs/input/tests/Android.bp
+++ b/libs/input/tests/Android.bp
@@ -13,6 +13,7 @@
     cpp_std: "c++20",
     host_supported: true,
     srcs: [
+        "BlockingQueue_test.cpp",
         "IdGenerator_test.cpp",
         "InputChannel_test.cpp",
         "InputDevice_test.cpp",
diff --git a/services/inputflinger/tests/BlockingQueue_test.cpp b/libs/input/tests/BlockingQueue_test.cpp
similarity index 97%
rename from services/inputflinger/tests/BlockingQueue_test.cpp
rename to libs/input/tests/BlockingQueue_test.cpp
index 754a5c4..924b937 100644
--- a/services/inputflinger/tests/BlockingQueue_test.cpp
+++ b/libs/input/tests/BlockingQueue_test.cpp
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#include "../BlockingQueue.h"
-
+#include <input/BlockingQueue.h>
 
 #include <gtest/gtest.h>
 #include <thread>
@@ -109,7 +108,7 @@
     BlockingQueue<int> queue(capacity);
 
     // Fill queue from a different thread
-    std::thread fillQueue([&queue](){
+    std::thread fillQueue([&queue]() {
         for (size_t i = 0; i < capacity; i++) {
             ASSERT_TRUE(queue.push(static_cast<int>(i)));
         }
@@ -136,7 +135,7 @@
     std::atomic_bool hasReceivedElement = false;
 
     // fill queue from a different thread
-    std::thread waitUntilHasElements([&queue, &hasReceivedElement](){
+    std::thread waitUntilHasElements([&queue, &hasReceivedElement]() {
         queue.pop(); // This should block until an element has been added
         hasReceivedElement = true;
     });
diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h
index 818d035..b41fa1d 100644
--- a/libs/renderengine/include/renderengine/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/RenderEngine.h
@@ -33,7 +33,7 @@
 #include <memory>
 
 /**
- * Allows to set RenderEngine backend to GLES (default) or SkiaGL (NOT yet supported).
+ * Allows to override the RenderEngine backend.
  */
 #define PROPERTY_DEBUG_RENDERENGINE_BACKEND "debug.renderengine.backend"
 
diff --git a/libs/renderengine/skia/AutoBackendTexture.cpp b/libs/renderengine/skia/AutoBackendTexture.cpp
index 92fe4c0..ee95e59 100644
--- a/libs/renderengine/skia/AutoBackendTexture.cpp
+++ b/libs/renderengine/skia/AutoBackendTexture.cpp
@@ -77,7 +77,7 @@
                                                                  backendFormat,
                                                                  isOutputBuffer);
     } else {
-        LOG_ALWAYS_FATAL("Unexpected backend %d", backend);
+        LOG_ALWAYS_FATAL("Unexpected backend %u", static_cast<unsigned>(backend));
     }
 
     mColorType = GrAHardwareBufferUtils::GetSkColorTypeFromBufferFormat(desc.format);
@@ -145,8 +145,8 @@
                              "\n\tGrBackendTexture: (%i x %i) hasMipmaps: %i isProtected: %i "
                              "texType: %i\n\t\tVkImageInfo: success: %i fFormat: %i "
                              "fSampleCount: %u fLevelCount: %u colorType %i",
-                             msg, tex.isValid(), dataspace, tex.width(), tex.height(),
-                             tex.hasMipmaps(), tex.isProtected(),
+                             msg, tex.isValid(), static_cast<int32_t>(dataspace), tex.width(),
+                             tex.height(), tex.hasMipmaps(), tex.isProtected(),
                              static_cast<int>(tex.textureType()), retrievedImageInfo,
                              imageInfo.fFormat, imageInfo.fSampleCount, imageInfo.fLevelCount,
                              colorType);
diff --git a/services/gpuservice/GpuService.cpp b/services/gpuservice/GpuService.cpp
index 48d793a..080e62b 100644
--- a/services/gpuservice/GpuService.cpp
+++ b/services/gpuservice/GpuService.cpp
@@ -70,6 +70,9 @@
 };
 
 GpuService::~GpuService() {
+    mGpuMem->stop();
+    mGpuWork->stop();
+
     mGpuWorkAsyncInitThread->join();
     mGpuMemAsyncInitThread->join();
 }
diff --git a/services/gpuservice/gpumem/GpuMem.cpp b/services/gpuservice/gpumem/GpuMem.cpp
index 141fe02..d0783df 100644
--- a/services/gpuservice/gpumem/GpuMem.cpp
+++ b/services/gpuservice/gpumem/GpuMem.cpp
@@ -61,6 +61,7 @@
             return;
         }
         // Retry until GPU driver loaded or timeout.
+        if (mStop.load()) return;
         sleep(1);
     }
 
diff --git a/services/gpuservice/gpumem/include/gpumem/GpuMem.h b/services/gpuservice/gpumem/include/gpumem/GpuMem.h
index 9aa74d6..16b201f 100644
--- a/services/gpuservice/gpumem/include/gpumem/GpuMem.h
+++ b/services/gpuservice/gpumem/include/gpumem/GpuMem.h
@@ -34,6 +34,7 @@
     // dumpsys interface
     void dump(const Vector<String16>& args, std::string* result);
     bool isInitialized() { return mInitialized.load(); }
+    void stop() { mStop.store(true); }
 
     // Traverse the gpu memory total map to feed the callback function.
     void traverseGpuMemTotals(const std::function<void(int64_t ts, uint32_t gpuId, uint32_t pid,
@@ -48,6 +49,10 @@
 
     // indicate whether ebpf has been initialized
     std::atomic<bool> mInitialized = false;
+
+    // whether initialization should be stopped
+    std::atomic<bool> mStop = false;
+
     // bpf map for GPU memory total data
     android::bpf::BpfMapRO<uint64_t, uint64_t> mGpuMemTotalMap;
 
diff --git a/services/gpuservice/gpuwork/GpuWork.cpp b/services/gpuservice/gpuwork/GpuWork.cpp
index fd70323..1a744ab 100644
--- a/services/gpuservice/gpuwork/GpuWork.cpp
+++ b/services/gpuservice/gpuwork/GpuWork.cpp
@@ -243,6 +243,7 @@
             return false;
         }
         // Retry until GPU driver loaded or timeout.
+        if (mStop.load()) return false;
         sleep(1);
         errno = 0;
     }
diff --git a/services/gpuservice/gpuwork/include/gpuwork/GpuWork.h b/services/gpuservice/gpuwork/include/gpuwork/GpuWork.h
index cece999..e70da54 100644
--- a/services/gpuservice/gpuwork/include/gpuwork/GpuWork.h
+++ b/services/gpuservice/gpuwork/include/gpuwork/GpuWork.h
@@ -40,6 +40,7 @@
     ~GpuWork();
 
     void initialize();
+    void stop() { mStop.store(true); }
 
     // Dumps the GPU work information.
     void dump(const Vector<String16>& args, std::string* result);
@@ -47,7 +48,7 @@
 private:
     // Attaches tracepoint |tracepoint_group|/|tracepoint_name| to BPF program at path
     // |program_path|. The tracepoint is also enabled.
-    static bool attachTracepoint(const char* program_path, const char* tracepoint_group,
+    bool attachTracepoint(const char* program_path, const char* tracepoint_group,
                                  const char* tracepoint_name);
 
     // Native atom puller callback registered in statsd.
@@ -80,6 +81,9 @@
     // Indicates whether our eBPF components have been initialized.
     std::atomic<bool> mInitialized = false;
 
+    // Indicates whether eBPF initialization should be stopped.
+    std::atomic<bool> mStop = false;
+
     // A thread that periodically checks whether |mGpuWorkMap| is nearly full
     // and, if so, clears it.
     std::thread mMapClearerThread;
diff --git a/services/inputflinger/InputProcessor.h b/services/inputflinger/InputProcessor.h
index dcbfebc..7a00a2d 100644
--- a/services/inputflinger/InputProcessor.h
+++ b/services/inputflinger/InputProcessor.h
@@ -22,7 +22,7 @@
 #include <unordered_map>
 
 #include <aidl/android/hardware/input/processor/IInputProcessor.h>
-#include "BlockingQueue.h"
+#include <input/BlockingQueue.h>
 #include "InputListener.h"
 namespace android {
 
diff --git a/services/inputflinger/tests/Android.bp b/services/inputflinger/tests/Android.bp
index 2a03ecc..9c9f643 100644
--- a/services/inputflinger/tests/Android.bp
+++ b/services/inputflinger/tests/Android.bp
@@ -39,7 +39,6 @@
     ],
     srcs: [
         "AnrTracker_test.cpp",
-        "BlockingQueue_test.cpp",
         "CapturedTouchpadEventConverter_test.cpp",
         "CursorInputMapper_test.cpp",
         "EventHub_test.cpp",
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 5002391..c2e67fa 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -15,7 +15,6 @@
  */
 
 #include "../dispatcher/InputDispatcher.h"
-#include "../BlockingQueue.h"
 #include "FakeApplicationHandle.h"
 #include "TestEventMatchers.h"
 
@@ -31,6 +30,7 @@
 #include <flag_macros.h>
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
+#include <input/BlockingQueue.h>
 #include <input/Input.h>
 #include <input/PrintTools.h>
 #include <linux/input.h>
diff --git a/services/inputflinger/tests/fuzzers/BlockingQueueFuzzer.cpp b/services/inputflinger/tests/fuzzers/BlockingQueueFuzzer.cpp
index 219b662..863d0a1 100644
--- a/services/inputflinger/tests/fuzzers/BlockingQueueFuzzer.cpp
+++ b/services/inputflinger/tests/fuzzers/BlockingQueueFuzzer.cpp
@@ -15,8 +15,8 @@
  */
 
 #include <fuzzer/FuzzedDataProvider.h>
+#include <input/BlockingQueue.h>
 #include <thread>
-#include "BlockingQueue.h"
 
 // Chosen to be a number large enough for variation in fuzzer runs, but not consume too much memory.
 static constexpr size_t MAX_CAPACITY = 1024;
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index 0989863..dcef9a3 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -10,6 +10,7 @@
 aconfig_declarations {
     name: "surfaceflinger_flags",
     package: "com.android.graphics.surfaceflinger.flags",
+    container: "system",
     srcs: ["surfaceflinger_flags.aconfig"],
 }
 
diff --git a/services/surfaceflinger/CompositionEngine/Android.bp b/services/surfaceflinger/CompositionEngine/Android.bp
index ae2f2db..0a70d42 100644
--- a/services/surfaceflinger/CompositionEngine/Android.bp
+++ b/services/surfaceflinger/CompositionEngine/Android.bp
@@ -10,6 +10,7 @@
 cc_defaults {
     name: "libcompositionengine_defaults",
     defaults: [
+        "aconfig_lib_cc_static_link.defaults",
         "android.hardware.graphics.composer3-ndk_shared",
         "android.hardware.power-ndk_shared",
         "librenderengine_deps",
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index f7cc13e..b980a65 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -2252,7 +2252,7 @@
     outTransactionsAreEmpty = !needsTraversal;
     const bool shouldCommit = (getTransactionFlags() & ~eTransactionFlushNeeded) || needsTraversal;
     if (shouldCommit) {
-        commitTransactions();
+        commitTransactionsLegacy();
     }
 
     bool mustComposite = latchBuffers() || shouldCommit;
@@ -2380,8 +2380,14 @@
         }
     }
 
+    // Keep a copy of the drawing state (that is going to be overwritten
+    // by commitTransactionsLocked) outside of mStateLock so that the side
+    // effects of the State assignment don't happen with mStateLock held,
+    // which can cause deadlocks.
+    State drawingState(mDrawingState);
+    Mutex::Autolock lock(mStateLock);
     bool mustComposite = false;
-    mustComposite |= applyAndCommitDisplayTransactionStates(update.transactions);
+    mustComposite |= applyAndCommitDisplayTransactionStatesLocked(update.transactions);
 
     {
         ATRACE_NAME("LayerSnapshotBuilder:update");
@@ -2420,7 +2426,7 @@
     bool newDataLatched = false;
     if (!mLegacyFrontEndEnabled) {
         ATRACE_NAME("DisplayCallbackAndStatsUpdates");
-        mustComposite |= applyTransactions(update.transactions, vsyncId);
+        mustComposite |= applyTransactionsLocked(update.transactions, vsyncId);
         traverseLegacyLayers([&](Layer* layer) { layer->commitTransaction(); });
         const nsecs_t latchTime = systemTime();
         bool unused = false;
@@ -3266,6 +3272,19 @@
 
 void SurfaceFlinger::commitTransactions() {
     ATRACE_CALL();
+    mDebugInTransaction = systemTime();
+
+    // Here we're guaranteed that some transaction flags are set
+    // so we can call commitTransactionsLocked unconditionally.
+    // We clear the flags with mStateLock held to guarantee that
+    // mCurrentState won't change until the transaction is committed.
+    mScheduler->modulateVsync({}, &VsyncModulator::onTransactionCommit);
+    commitTransactionsLocked(clearTransactionFlags(eTransactionMask));
+    mDebugInTransaction = 0;
+}
+
+void SurfaceFlinger::commitTransactionsLegacy() {
+    ATRACE_CALL();
 
     // Keep a copy of the drawing state (that is going to be overwritten
     // by commitTransactionsLocked) outside of mStateLock so that the side
@@ -5070,9 +5089,8 @@
     return needsTraversal;
 }
 
-bool SurfaceFlinger::applyAndCommitDisplayTransactionStates(
+bool SurfaceFlinger::applyAndCommitDisplayTransactionStatesLocked(
         std::vector<TransactionState>& transactions) {
-    Mutex::Autolock lock(mStateLock);
     bool needsTraversal = false;
     uint32_t transactionFlags = 0;
     for (auto& transaction : transactions) {
@@ -5864,7 +5882,8 @@
     if (mLegacyFrontEndEnabled) {
         applyTransactions(transactions, VsyncId{0});
     } else {
-        applyAndCommitDisplayTransactionStates(transactions);
+        Mutex::Autolock lock(mStateLock);
+        applyAndCommitDisplayTransactionStatesLocked(transactions);
     }
 
     {
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 6b44401..61360a7 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -751,7 +751,8 @@
                                             bool force = false)
             REQUIRES(mStateLock, kMainThreadContext);
 
-    void commitTransactions() EXCLUDES(mStateLock) REQUIRES(kMainThreadContext);
+    void commitTransactionsLegacy() EXCLUDES(mStateLock) REQUIRES(kMainThreadContext);
+    void commitTransactions() REQUIRES(kMainThreadContext, mStateLock);
     void commitTransactionsLocked(uint32_t transactionFlags)
             REQUIRES(mStateLock, kMainThreadContext);
     void doCommitTransactions() REQUIRES(mStateLock);
@@ -804,8 +805,8 @@
     bool flushTransactionQueues(VsyncId) REQUIRES(kMainThreadContext);
 
     bool applyTransactions(std::vector<TransactionState>&, VsyncId) REQUIRES(kMainThreadContext);
-    bool applyAndCommitDisplayTransactionStates(std::vector<TransactionState>& transactions)
-            REQUIRES(kMainThreadContext);
+    bool applyAndCommitDisplayTransactionStatesLocked(std::vector<TransactionState>& transactions)
+            REQUIRES(kMainThreadContext, mStateLock);
 
     // Returns true if there is at least one transaction that needs to be flushed
     bool transactionFlushNeeded();
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
index 4fc39cc..81fbc84 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
@@ -610,7 +610,7 @@
         {
             ftl::FakeGuard guard(kMainThreadContext);
 
-            mFlinger->commitTransactions();
+            mFlinger->commitTransactionsLegacy();
             mFlinger->flushTransactionQueues(getFuzzedVsyncId(mFdp));
 
             scheduler::FrameTargeter frameTargeter(displayId, mFdp.ConsumeBool());
diff --git a/services/surfaceflinger/surfaceflinger_flags.aconfig b/services/surfaceflinger/surfaceflinger_flags.aconfig
index 1a28b81..abe7ec7 100644
--- a/services/surfaceflinger/surfaceflinger_flags.aconfig
+++ b/services/surfaceflinger/surfaceflinger_flags.aconfig
@@ -1,4 +1,5 @@
 package: "com.android.graphics.surfaceflinger.flags"
+container: "system"
 
 flag {
   name: "misc1"
diff --git a/services/surfaceflinger/tests/OWNERS b/services/surfaceflinger/tests/OWNERS
new file mode 100644
index 0000000..56f2f1b
--- /dev/null
+++ b/services/surfaceflinger/tests/OWNERS
@@ -0,0 +1,8 @@
+per-file HdrSdrRatioOverlay_test.cpp = alecmouri@google.com, sallyqi@google.com, jreck@google.com
+
+# Most layer-related files are owned by WM
+per-file Layer* = set noparent
+per-file Layer* = pdwilliams@google.com, vishnun@google.com, melodymhsu@google.com
+
+per-file LayerHistoryTest.cpp = file:/services/surfaceflinger/OWNERS
+per-file LayerInfoTest.cpp = file:/services/surfaceflinger/OWNERS
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_NotifyPowerBoostTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_NotifyPowerBoostTest.cpp
index 22b72f9..f2e2c8a 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_NotifyPowerBoostTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_NotifyPowerBoostTest.cpp
@@ -33,24 +33,45 @@
 TEST_F(DisplayTransactionTest, notifyPowerBoostNotifiesTouchEvent) {
     using namespace std::chrono_literals;
 
+    std::mutex timerMutex;
+    std::condition_variable cv;
+
     injectDefaultInternalDisplay([](FakeDisplayDeviceInjector&) {});
 
-    mFlinger.scheduler()->replaceTouchTimer(100);
-    std::this_thread::sleep_for(10ms);                  // wait for callback to be triggered
+    std::unique_lock lock(timerMutex);
+    bool didReset = false; // keeps track of what the most recent call was
+
+    auto waitForTimerReset = [&] { cv.wait_for(lock, 100ms, [&] { return didReset; }); };
+    auto waitForTimerExpired = [&] { cv.wait_for(lock, 100ms, [&] { return !didReset; }); };
+
+    // Add extra logic to unblock the test when the timer callbacks get called
+    mFlinger.scheduler()->replaceTouchTimer(10, [&](bool isReset) {
+        {
+            std::unique_lock lock(timerMutex); // guarantee we're waiting on the cv
+            didReset = isReset;
+        }
+        cv.notify_one();                   // wake the cv
+        std::unique_lock lock(timerMutex); // guarantee we finished the cv logic
+    });
+
+    waitForTimerReset();
     EXPECT_TRUE(mFlinger.scheduler()->isTouchActive()); // Starting timer activates touch
 
-    std::this_thread::sleep_for(110ms); // wait for reset touch timer to expire and trigger callback
-    EXPECT_FALSE(mFlinger.scheduler()->isTouchActive());
+    waitForTimerExpired();
+    EXPECT_FALSE(mFlinger.scheduler()->isTouchActive()); // Stopping timer deactivates touch
 
     EXPECT_EQ(NO_ERROR, mFlinger.notifyPowerBoost(static_cast<int32_t>(Boost::CAMERA_SHOT)));
-    std::this_thread::sleep_for(10ms); // wait for callback to maybe be triggered
-    EXPECT_FALSE(mFlinger.scheduler()->isTouchActive());
 
-    std::this_thread::sleep_for(110ms); // wait for reset touch timer to expire and trigger callback
+    EXPECT_FALSE(mFlinger.scheduler()->isTouchActive());
+    // Wait for the timer to start just in case
+    waitForTimerReset();
+    EXPECT_FALSE(mFlinger.scheduler()->isTouchActive());
+    // Wait for the timer to stop, again just in case
+    waitForTimerExpired();
     EXPECT_FALSE(mFlinger.scheduler()->isTouchActive());
 
     EXPECT_EQ(NO_ERROR, mFlinger.notifyPowerBoost(static_cast<int32_t>(Boost::INTERACTION)));
-    std::this_thread::sleep_for(10ms); // wait for callback to be triggered.
+    waitForTimerReset();
     EXPECT_TRUE(mFlinger.scheduler()->isTouchActive());
 }
 
diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h
index 2a1b88e..c0255d3 100644
--- a/services/surfaceflinger/tests/unittests/TestableScheduler.h
+++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h
@@ -136,14 +136,25 @@
         return mLayerHistory.mActiveLayerInfos.size();
     }
 
-    void replaceTouchTimer(int64_t millis) {
+    void replaceTouchTimer(int64_t millis,
+                           std::function<void(bool isReset)>&& testCallback = nullptr) {
         if (mTouchTimer) {
             mTouchTimer.reset();
         }
         mTouchTimer.emplace(
                 "Testable Touch timer", std::chrono::milliseconds(millis),
-                [this] { touchTimerCallback(TimerState::Reset); },
-                [this] { touchTimerCallback(TimerState::Expired); });
+                [this, testCallback] {
+                    touchTimerCallback(TimerState::Reset);
+                    if (testCallback != nullptr) {
+                        testCallback(true);
+                    }
+                },
+                [this, testCallback] {
+                    touchTimerCallback(TimerState::Expired);
+                    if (testCallback != nullptr) {
+                        testCallback(false);
+                    }
+                });
         mTouchTimer->start();
     }
 
diff --git a/services/vibratorservice/VibratorCallbackScheduler.cpp b/services/vibratorservice/VibratorCallbackScheduler.cpp
index 7eda9ef..b2b1988 100644
--- a/services/vibratorservice/VibratorCallbackScheduler.cpp
+++ b/services/vibratorservice/VibratorCallbackScheduler.cpp
@@ -87,13 +87,13 @@
             lock.lock();
         }
         if (mQueue.empty()) {
-            // Wait until a new callback is scheduled.
-            mCondition.wait(mMutex);
+            // Wait until a new callback is scheduled or destructor was called.
+            mCondition.wait(lock, [this] { return mFinished || !mQueue.empty(); });
         } else {
-            // Wait until next callback expires, or a new one is scheduled.
+            // Wait until next callback expires or a new one is scheduled.
             // Use the monotonic steady clock to wait for the measured delay interval via wait_for
             // instead of using a wall clock via wait_until.
-            mCondition.wait_for(mMutex, mQueue.top().getWaitForExpirationDuration());
+            mCondition.wait_for(lock, mQueue.top().getWaitForExpirationDuration());
         }
     }
 }
diff --git a/services/vibratorservice/test/VibratorCallbackSchedulerTest.cpp b/services/vibratorservice/test/VibratorCallbackSchedulerTest.cpp
index 426cd42..881e321 100644
--- a/services/vibratorservice/test/VibratorCallbackSchedulerTest.cpp
+++ b/services/vibratorservice/test/VibratorCallbackSchedulerTest.cpp
@@ -14,20 +14,13 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "VibratorHalWrapperAidlTest"
-
-#include <android-base/thread_annotations.h>
-#include <android/hardware/vibrator/IVibrator.h>
-#include <condition_variable>
-
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
 
-#include <utils/Log.h>
-#include <thread>
-
 #include <vibratorservice/VibratorCallbackScheduler.h>
 
+#include "test_utils.h"
+
 using std::chrono::milliseconds;
 using std::chrono::steady_clock;
 using std::chrono::time_point;
@@ -39,29 +32,25 @@
 // -------------------------------------------------------------------------------------------------
 
 // Delay allowed for the scheduler to process callbacks during this test.
-static const auto TEST_TIMEOUT = 50ms;
+static const auto TEST_TIMEOUT = 100ms;
 
 class VibratorCallbackSchedulerTest : public Test {
 public:
-    void SetUp() override {
-        mScheduler = std::make_unique<vibrator::CallbackScheduler>();
-        std::lock_guard<std::mutex> lock(mMutex);
-        mExpiredCallbacks.clear();
-    }
+    void SetUp() override { mScheduler = std::make_unique<vibrator::CallbackScheduler>(); }
 
 protected:
     std::mutex mMutex;
-    std::condition_variable_any mCondition;
     std::unique_ptr<vibrator::CallbackScheduler> mScheduler = nullptr;
+    vibrator::TestCounter mCallbackCounter;
     std::vector<int32_t> mExpiredCallbacks GUARDED_BY(mMutex);
 
     std::function<void()> createCallback(int32_t id) {
-        return [=]() {
+        return [this, id]() {
             {
                 std::lock_guard<std::mutex> lock(mMutex);
                 mExpiredCallbacks.push_back(id);
             }
-            mCondition.notify_all();
+            mCallbackCounter.increment();
         };
     }
 
@@ -71,56 +60,42 @@
     }
 
     int32_t waitForCallbacks(int32_t callbackCount, milliseconds timeout) {
-        time_point<steady_clock> expirationTime = steady_clock::now() + timeout + TEST_TIMEOUT;
-        int32_t expiredCallbackCount = 0;
-        while (steady_clock::now() < expirationTime) {
-            std::lock_guard<std::mutex> lock(mMutex);
-            expiredCallbackCount = mExpiredCallbacks.size();
-            if (callbackCount <= expiredCallbackCount) {
-                return expiredCallbackCount;
-            }
-            auto currentTimeout = std::chrono::duration_cast<std::chrono::milliseconds>(
-                    expirationTime - steady_clock::now());
-            if (currentTimeout > currentTimeout.zero()) {
-                // Use the monotonic steady clock to wait for the requested timeout via wait_for
-                // instead of using a wall clock via wait_until.
-                mCondition.wait_for(mMutex, currentTimeout);
-            }
-        }
-        return expiredCallbackCount;
+        mCallbackCounter.tryWaitUntilCountIsAtLeast(callbackCount, timeout);
+        return mCallbackCounter.get();
     }
 };
 
 // -------------------------------------------------------------------------------------------------
 
 TEST_F(VibratorCallbackSchedulerTest, TestScheduleRunsOnlyAfterDelay) {
+    auto callbackDuration = 50ms;
     time_point<steady_clock> startTime = steady_clock::now();
-    mScheduler->schedule(createCallback(1), 50ms);
+    mScheduler->schedule(createCallback(1), callbackDuration);
 
-    ASSERT_EQ(1, waitForCallbacks(1, 50ms));
+    ASSERT_THAT(waitForCallbacks(1, callbackDuration + TEST_TIMEOUT), Eq(1));
     time_point<steady_clock> callbackTime = steady_clock::now();
 
-    // Callback happened at least 50ms after the beginning of the test.
-    ASSERT_TRUE(startTime + 50ms <= callbackTime);
-    ASSERT_THAT(getExpiredCallbacks(), ElementsAre(1));
+    // Callback took at least the required duration to trigger.
+    ASSERT_THAT(callbackTime, Ge(startTime + callbackDuration));
 }
 
 TEST_F(VibratorCallbackSchedulerTest, TestScheduleMultipleCallbacksRunsInDelayOrder) {
     // Schedule first callbacks long enough that all 3 will be scheduled together and run in order.
-    mScheduler->schedule(createCallback(1), 50ms);
-    mScheduler->schedule(createCallback(2), 40ms);
-    mScheduler->schedule(createCallback(3), 10ms);
+    mScheduler->schedule(createCallback(1), 50ms + 2 * TEST_TIMEOUT);
+    mScheduler->schedule(createCallback(2), 50ms + TEST_TIMEOUT);
+    mScheduler->schedule(createCallback(3), 50ms);
 
-    ASSERT_EQ(3, waitForCallbacks(3, 50ms));
+    // Callbacks triggered in the expected order based on the requested durations.
+    ASSERT_THAT(waitForCallbacks(3, 50ms + 3 * TEST_TIMEOUT), Eq(3));
     ASSERT_THAT(getExpiredCallbacks(), ElementsAre(3, 2, 1));
 }
 
 TEST_F(VibratorCallbackSchedulerTest, TestDestructorDropsPendingCallbacksAndKillsThread) {
     // Schedule callback long enough that scheduler will be destroyed while it's still scheduled.
-    mScheduler->schedule(createCallback(1), 50ms);
+    mScheduler->schedule(createCallback(1), 100ms);
     mScheduler.reset(nullptr);
 
     // Should timeout waiting for callback to run.
-    ASSERT_EQ(0, waitForCallbacks(1, 50ms));
-    ASSERT_TRUE(getExpiredCallbacks().empty());
+    ASSERT_THAT(waitForCallbacks(1, 100ms + TEST_TIMEOUT), Eq(0));
+    ASSERT_THAT(getExpiredCallbacks(), IsEmpty());
 }
diff --git a/services/vibratorservice/test/test_utils.h b/services/vibratorservice/test/test_utils.h
index 1933a11..c08cfc6 100644
--- a/services/vibratorservice/test/test_utils.h
+++ b/services/vibratorservice/test/test_utils.h
@@ -85,6 +85,34 @@
     ~TestFactory() = delete;
 };
 
+class TestCounter {
+public:
+    TestCounter(int32_t init = 0) : mMutex(), mCondVar(), mCount(init) {}
+
+    int32_t get() {
+        std::lock_guard<std::mutex> lock(mMutex);
+        return mCount;
+    }
+
+    void increment() {
+        {
+            std::lock_guard<std::mutex> lock(mMutex);
+            mCount += 1;
+        }
+        mCondVar.notify_all();
+    }
+
+    void tryWaitUntilCountIsAtLeast(int32_t count, std::chrono::milliseconds timeout) {
+        std::unique_lock<std::mutex> lock(mMutex);
+        mCondVar.wait_for(lock, timeout, [&] { return mCount >= count; });
+    }
+
+private:
+    std::mutex mMutex;
+    std::condition_variable mCondVar;
+    int32_t mCount GUARDED_BY(mMutex);
+};
+
 // -------------------------------------------------------------------------------------------------
 
 } // namespace vibrator