diff options
51 files changed, 1000 insertions, 274 deletions
diff --git a/cmds/dumpstate/Android.bp b/cmds/dumpstate/Android.bp index 23f33d85a2..4a77967bb2 100644 --- a/cmds/dumpstate/Android.bp +++ b/cmds/dumpstate/Android.bp @@ -79,7 +79,10 @@ filegroup { 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/include/android/choreographer.h b/include/android/choreographer.h index f999708f04..6a91d9836e 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 @@ typedef void (*AChoreographer_refreshRateCallback)(int64_t vsyncPeriodNanos, voi 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 @@ void AChoreographer_postFrameCallback64(AChoreographer* choreographer, __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 @@ void AChoreographer_postFrameCallbackDelayed64(AChoreographer* choreographer, 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 e50730d5c1..d80a3660a6 100644 --- a/include/android/looper.h +++ b/include/android/looper.h @@ -35,7 +35,7 @@ extern "C" { // 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 @@ typedef int (*ALooper_callbackFunc)(int fd, int events, void* data); * 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 @@ int ALooper_pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outDa * 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 a618393e66..e3c1ccfc6c 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 @@ typedef ASensorRef const* ASensorList; * 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 443cb7e51f..14167e6467 100644 --- a/include/android/surface_control.h +++ b/include/android/surface_control.h @@ -62,16 +62,18 @@ typedef struct ASurfaceControl ASurfaceControl; * * 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 @@ ASurfaceControl* ASurfaceControl_create(ASurfaceControl* parent, const char* deb * * 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 @@ void ASurfaceControl_acquire(ASurfaceControl* surface_control) __INTRODUCED_IN(3 * * 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 @@ typedef struct ASurfaceTransaction ASurfaceTransaction; * * 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 @@ void ASurfaceTransaction_delete(ASurfaceTransaction* transaction) __INTRODUCED_I * * 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 @@ typedef struct ASurfaceTransactionStats ASurfaceTransactionStats; * * 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 @@ typedef void (*ASurfaceTransaction_OnComplete)(void* context, ASurfaceTransactio * * 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 @@ typedef void (*ASurfaceTransaction_OnCommit)(void* context, ASurfaceTransactionS * * 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 @@ int64_t ASurfaceTransactionStats_getLatchTime(ASurfaceTransactionStats* surface_ * * 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 @@ int ASurfaceTransactionStats_getPresentFenceFd(ASurfaceTransactionStats* surface * * \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 @@ void ASurfaceTransactionStats_releaseASurfaceControls(ASurfaceControl** surface_ * * 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 @@ int64_t ASurfaceTransactionStats_getAcquireTime(ASurfaceTransactionStats* surfac * 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 @@ int ASurfaceTransactionStats_getPreviousReleaseFenceFd( * * 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 @@ void ASurfaceTransaction_setOnComplete(ASurfaceTransaction* transaction, void* c * * 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 @@ void ASurfaceTransaction_setOnCommit(ASurfaceTransaction* transaction, void* con * * 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 @@ enum ASurfaceTransactionVisibility : int8_t { * * 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 @@ void ASurfaceTransaction_setVisibility(ASurfaceTransaction* transaction, * * 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 @@ void ASurfaceTransaction_setZOrder(ASurfaceTransaction* transaction, * * 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 @@ void ASurfaceTransaction_setBuffer(ASurfaceTransaction* transaction, * * 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 @@ void ASurfaceTransaction_setColor(ASurfaceTransaction* transaction, * 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 @@ void ASurfaceTransaction_setGeometry(ASurfaceTransaction* transaction, * * 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 @@ void ASurfaceTransaction_setCrop(ASurfaceTransaction* transaction, * * 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 @@ void ASurfaceTransaction_setPosition(ASurfaceTransaction* transaction, * * 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 @@ void ASurfaceTransaction_setBufferTransform(ASurfaceTransaction* transaction, * * 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 @@ enum ASurfaceTransactionTransparency : int8_t { * * 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 @@ void ASurfaceTransaction_setBufferTransparency(ASurfaceTransaction* transaction, * * 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 @@ void ASurfaceTransaction_setDamageRegion(ASurfaceTransaction* transaction, * * 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 @@ void ASurfaceTransaction_setDesiredPresentTime(ASurfaceTransaction* transaction, * * 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 @@ void ASurfaceTransaction_setBufferAlpha(ASurfaceTransaction* transaction, * * 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 @@ void ASurfaceTransaction_setBufferDataSpace(ASurfaceTransaction* transaction, * * 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 @@ void ASurfaceTransaction_setHdrMetadata_smpte2086(ASurfaceTransaction* transacti * * 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 @@ void ASurfaceTransaction_setHdrMetadata_cta861_3(ASurfaceTransaction* transactio * * 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 @@ void ASurfaceTransaction_setExtendedRangeBrightness(ASurfaceTransaction* transac * * 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 @@ void ASurfaceTransaction_setFrameRate(ASurfaceTransaction* transaction, * * 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 @@ void ASurfaceTransaction_setFrameRateWithChangeStrategy(ASurfaceTransaction* tra * * 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 @@ void ASurfaceTransaction_clearFrameRate(ASurfaceTransaction* transaction, * \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 @@ void ASurfaceTransaction_setEnableBackPressure(ASurfaceTransaction* transaction, * 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 index f848c82c42..f848c82c42 100644 --- a/services/inputflinger/BlockingQueue.h +++ b/include/input/BlockingQueue.h diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp index 57a48d7e92..090e35bc37 100644 --- a/libs/binder/Android.bp +++ b/libs/binder/Android.bp @@ -446,7 +446,7 @@ cc_library_host_shared { }, } -cc_library_static { +cc_library { name: "libbinder_rpc_no_kernel", vendor_available: true, defaults: [ @@ -458,7 +458,7 @@ cc_library_static { ], } -cc_library_static { +cc_library { name: "libbinder_rpc_no_blob", vendor_available: true, defaults: [ @@ -474,7 +474,7 @@ cc_library_static { ], } -cc_library_static { +cc_library { name: "libbinder_rpc_no_native_handle", vendor_available: true, defaults: [ @@ -490,7 +490,7 @@ cc_library_static { ], } -cc_library_static { +cc_library { name: "libbinder_rpc_single_threaded", defaults: [ "libbinder_common_defaults", @@ -505,7 +505,7 @@ cc_library_static { ], } -cc_library_static { +cc_library { name: "libbinder_rpc_single_threaded_no_kernel", defaults: [ "libbinder_common_defaults", diff --git a/libs/binder/liblog_stub/include/log/log.h b/libs/binder/liblog_stub/include/log/log.h index 91c9632c1b..dad0020ace 100644 --- a/libs/binder/liblog_stub/include/log/log.h +++ b/libs/binder/liblog_stub/include/log/log.h @@ -54,16 +54,16 @@ int __android_log_print(int prio, const char* tag, const char* fmt, ...) #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 b1ab7b0f9a..2929bce897 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 @@ binder_status_t AIBinder_getExtension(AIBinder* binder, AIBinder** outExt) __INT * 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 c665ad82ad..52edae4a38 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/binder_tokio/lib.rs b/libs/binder/rust/binder_tokio/lib.rs index 1dc0b2471d..71bb95bc0e 100644 --- a/libs/binder/rust/binder_tokio/lib.rs +++ b/libs/binder/rust/binder_tokio/lib.rs @@ -34,6 +34,7 @@ use std::future::Future; /// 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 @@ pub async fn get_interface<T: FromIBinder + ?Sized + 'static>( } } +/// 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/src/lib.rs b/libs/binder/rust/src/lib.rs index 0f9c58c0a2..e70f4f0232 100644 --- a/libs/binder/rust/src/lib.rs +++ b/libs/binder/rust/src/lib.rs @@ -114,9 +114,9 @@ pub use parcel::{ParcelFileDescriptor, Parcelable, ParcelableHolder}; pub use proxy::{DeathRecipient, SpIBinder, WpIBinder}; #[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(trusty))] pub use state::{ProcessState, ThreadState}; diff --git a/libs/binder/rust/src/service.rs b/libs/binder/rust/src/service.rs index 3ca3b540c4..29dd8e1f58 100644 --- a/libs/binder/rust/src/service.rs +++ b/libs/binder/rust/src/service.rs @@ -144,6 +144,7 @@ fn interface_cast<T: FromIBinder + ?Sized>(service: Option<SpIBinder>) -> Result /// 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 @@ pub fn get_service(name: &str) -> Option<SpIBinder> { 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 @@ pub fn wait_for_service(name: &str) -> Option<SpIBinder> { /// 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/tests/integration.rs b/libs/binder/rust/tests/integration.rs index c87fa89756..15ae56fdd7 100644 --- a/libs/binder/rust/tests/integration.rs +++ b/libs/binder/rust/tests/integration.rs @@ -421,7 +421,7 @@ mod tests { } #[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 @@ mod tests { } #[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 @@ mod tests { } #[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 35002eb3c5..6800a8d36c 100644 --- a/libs/binder/tests/Android.bp +++ b/libs/binder/tests/Android.bp @@ -200,9 +200,11 @@ cc_library_static { defaults: [ "binder_test_defaults", ], + header_libs: [ + "libbinder_headers_base", + ], shared_libs: [ "libbase", - "liblog", ], srcs: [ "FileUtils.cpp", diff --git a/libs/binder/tests/binderThroughputTest.cpp b/libs/binder/tests/binderThroughputTest.cpp index 10912c7363..f912348689 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 @@ struct ProcResults { 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 signal_all(vector<Pipe>& v) } } -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 @@ void run_main(int iterations, 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 @@ int main(int argc, char *argv[]) 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 @@ int main(int argc, char *argv[]) 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 @@ int main(int argc, char *argv[]) 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/trusty/ndk/include/android/llndk-versioning.h b/libs/binder/trusty/ndk/include/android/llndk-versioning.h new file mode 100644 index 0000000000..3ae3d8f577 --- /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 7528f2bb45..4e9b0e83c6 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_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 0000000000..22cba44975 --- /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 0000000000..ae26355521 --- /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 3c1e784418..baea5a827b 100644 --- a/libs/binder/trusty/rust/binder_rpc_test/main.rs +++ b/libs/binder/trusty/rust/binder_rpc_test/main.rs @@ -15,8 +15,11 @@ */ #![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}; @@ -25,19 +28,190 @@ test::init!(); const SERVICE_PORT: &str = "com.android.trusty.binderRpcTestService.V1"; const RUST_SERVICE_PORT: &str = "com.android.trusty.rust.binderRpcTestService.V1"; +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(SERVICE_PORT); - 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()); } -#[test] -fn ping_rust() { - let srv = get_service(RUST_SERVICE_PORT); - assert_eq!(srv.as_binder().ping_binder(), Ok(())); +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 c2ecaa4fe3..384ed441c6 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 192a1591ae..8347a359db 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 @@ MODULE_LIBRARY_DEPS += \ $(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 index b9a86bf240..c4a758a214 100644 --- a/libs/binder/trusty/rust/binder_rpc_test/service/main.rs +++ b/libs/binder/trusty/rust/binder_rpc_test/service/main.rs @@ -13,61 +13,126 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -use binder::{BinderFeatures, Interface, ParcelFileDescriptor, SpIBinder, Status, Strong}; +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::IBinderRpcSession; +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; +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> { - todo!() + // This is a oneway function, so caller returned immediately and gives back an Ok(()) regardless of what this returns + Ok(()) } - fn doubleString(&self, _: &str) -> Result<String, Status> { - todo!() + fn doubleString(&self, s: &str) -> Result<String, Status> { + let ss = [s, s].concat(); + Ok(ss) } fn getClientPort(&self) -> Result<i32, Status> { - todo!() + Ok(self.port) } fn countBinders(&self) -> Result<Vec<i32>, Status> { todo!() } fn getNullBinder(&self) -> Result<SpIBinder, Status> { - todo!() + Err(Status::from(StatusCode::UNKNOWN_TRANSACTION)) } - fn pingMe(&self, _: &SpIBinder) -> Result<i32, Status> { - todo!() + 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, _: Option<&SpIBinder>) -> Result<Option<SpIBinder>, Status> { - todo!() + 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, _: Option<&SpIBinder>) -> Result<(), Status> { - todo!() + fn holdBinder(&self, binder: Option<&SpIBinder>) -> Result<(), Status> { + *HOLD_BINDER.lock().unwrap() = binder.cloned(); + Ok(()) } fn getHeldBinder(&self) -> Result<Option<SpIBinder>, Status> { - todo!() + Ok((*HOLD_BINDER.lock().unwrap()).clone()) } - fn nestMe(&self, _: &Strong<(dyn IBinderRpcTest + 'static)>, _: i32) -> Result<(), 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, _: &str) -> Result<Strong<(dyn IBinderRpcSession + 'static)>, Status> { - todo!() + 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> { - todo!() + let count = MyBinderRpcSession::get_instance_count(); + Ok(count) } fn lock(&self) -> Result<(), Status> { todo!() @@ -78,11 +143,21 @@ impl IBinderRpcTest for TestService { fn lockUnlock(&self) -> Result<(), Status> { todo!() } - fn sleepMs(&self, _: i32) -> 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, _: i32) -> Result<(), Status> { - todo!() + fn sleepMsAsync(&self, ms: i32) -> Result<(), Status> { + self.sleepMs(ms) } fn doCallback( &self, @@ -103,7 +178,7 @@ impl IBinderRpcTest for TestService { todo!() } fn die(&self, _: bool) -> Result<(), Status> { - todo!() + Err(Status::from(StatusCode::UNKNOWN_TRANSACTION)) } fn scheduleShutdown(&self) -> Result<(), Status> { todo!() diff --git a/libs/binder/trusty/rust/binder_rpc_test/service/rules.mk b/libs/binder/trusty/rust/binder_rpc_test/service/rules.mk index 1ddc382197..f71ee9bcbd 100644 --- a/libs/binder/trusty/rust/binder_rpc_test/service/rules.mk +++ b/libs/binder/trusty/rust/binder_rpc_test/service/rules.mk @@ -25,7 +25,10 @@ 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 diff --git a/libs/binder/trusty/rust/rules.mk b/libs/binder/trusty/rust/rules.mk index c5e671a4f5..36bd3a2e75 100644 --- a/libs/binder/trusty/rust/rules.mk +++ b/libs/binder/trusty/rust/rules.mk @@ -28,6 +28,7 @@ MODULE_LIBRARY_DEPS += \ $(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 += \ diff --git a/libs/bufferstreams/Android.bp b/libs/bufferstreams/Android.bp index 365fc457d1..6c2a980f71 100644 --- a/libs/bufferstreams/Android.bp +++ b/libs/bufferstreams/Android.bp @@ -19,6 +19,7 @@ package { 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 e258725e3d..d0f7812d21 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 846105dacd..c5c1fd37c1 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 6ccc6cafb6..81f6a585ab 100644 --- a/libs/cputimeinstate/testtimeinstate.cpp +++ b/libs/cputimeinstate/testtimeinstate.cpp @@ -40,6 +40,9 @@ namespace bpf { 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 @@ uint64_t timeNanos() { // 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 86431484d6..059e19ebb8 100644 --- a/libs/gui/Android.bp +++ b/libs/gui/Android.bp @@ -23,6 +23,7 @@ package { 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 b081030c9f..38646992da 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 252040d1b0..20b35383bc 100644 --- a/libs/input/Android.bp +++ b/libs/input/Android.bp @@ -39,6 +39,7 @@ filegroup { 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 54eeb39935..dbc002ccb3 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 13cfb491b5..9137a3468f 100644 --- a/libs/input/tests/Android.bp +++ b/libs/input/tests/Android.bp @@ -13,6 +13,7 @@ cc_test { 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 index 754a5c451e..924b937080 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 @@ TEST(BlockingQueueTest, Queue_AllowsMultipleThreads) { 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 @@ TEST(BlockingQueueTest, Queue_BlocksWhileWaitingForElements) { 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/services/gpuservice/GpuService.cpp b/services/gpuservice/GpuService.cpp index 48d793a4d4..080e62b164 100644 --- a/services/gpuservice/GpuService.cpp +++ b/services/gpuservice/GpuService.cpp @@ -70,6 +70,9 @@ GpuService::GpuService() }; 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 141fe021ee..d0783df109 100644 --- a/services/gpuservice/gpumem/GpuMem.cpp +++ b/services/gpuservice/gpumem/GpuMem.cpp @@ -61,6 +61,7 @@ void GpuMem::initialize() { 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 9aa74d6863..16b201f516 100644 --- a/services/gpuservice/gpumem/include/gpumem/GpuMem.h +++ b/services/gpuservice/gpumem/include/gpumem/GpuMem.h @@ -34,6 +34,7 @@ public: // 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 @@ private: // 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 fd703239e9..1a744abc6d 100644 --- a/services/gpuservice/gpuwork/GpuWork.cpp +++ b/services/gpuservice/gpuwork/GpuWork.cpp @@ -243,6 +243,7 @@ bool GpuWork::attachTracepoint(const char* programPath, const char* tracepointGr 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 cece9999c6..e70da540b9 100644 --- a/services/gpuservice/gpuwork/include/gpuwork/GpuWork.h +++ b/services/gpuservice/gpuwork/include/gpuwork/GpuWork.h @@ -40,6 +40,7 @@ public: ~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 @@ public: 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 @@ private: // 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 dcbfebc62f..7a00a2dae8 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 2a03ecc62b..9c9f643656 100644 --- a/services/inputflinger/tests/Android.bp +++ b/services/inputflinger/tests/Android.bp @@ -39,7 +39,6 @@ cc_test { ], 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 5002391f61..c2e67fa788 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 219b662ffb..863d0a165e 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 0989863b7d..dcef9a3775 100644 --- a/services/surfaceflinger/Android.bp +++ b/services/surfaceflinger/Android.bp @@ -10,6 +10,7 @@ package { 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 ae2f2dbbf5..0a70d4299d 100644 --- a/services/surfaceflinger/CompositionEngine/Android.bp +++ b/services/surfaceflinger/CompositionEngine/Android.bp @@ -10,6 +10,7 @@ package { 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_flags.aconfig b/services/surfaceflinger/surfaceflinger_flags.aconfig index 1a28b81483..abe7ec708f 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/vibratorservice/VibratorCallbackScheduler.cpp b/services/vibratorservice/VibratorCallbackScheduler.cpp index 7eda9ef0c7..b2b1988d97 100644 --- a/services/vibratorservice/VibratorCallbackScheduler.cpp +++ b/services/vibratorservice/VibratorCallbackScheduler.cpp @@ -87,13 +87,13 @@ void CallbackScheduler::loop() { 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 426cd426f7..881e32152c 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 @@ using namespace testing; // ------------------------------------------------------------------------------------------------- // 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 @@ protected: } 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 1933a118ef..c08cfc6bfa 100644 --- a/services/vibratorservice/test/test_utils.h +++ b/services/vibratorservice/test/test_utils.h @@ -85,6 +85,34 @@ private: ~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 |