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