diff options
Diffstat (limited to 'include')
36 files changed, 2164 insertions, 990 deletions
diff --git a/include/android/bitmap.h b/include/android/bitmap.h index 6704a1ddf2..35f87f96ae 100644 --- a/include/android/bitmap.h +++ b/include/android/bitmap.h @@ -68,6 +68,8 @@ enum AndroidBitmapFormat { ANDROID_BITMAP_FORMAT_A_8 = 8, /** Each component is stored as a half float. **/ ANDROID_BITMAP_FORMAT_RGBA_F16 = 9, + /** Red: 10 bits, Green: 10 bits, Blue: 10 bits, Alpha: 2 bits. **/ + ANDROID_BITMAP_FORMAT_RGBA_1010102 = 10, }; /** Bitmap alpha format */ diff --git a/include/android/choreographer.h b/include/android/choreographer.h index b743f491e4..63aa7ff6c0 100644 --- a/include/android/choreographer.h +++ b/include/android/choreographer.h @@ -39,6 +39,18 @@ struct AChoreographer; */ typedef struct AChoreographer AChoreographer; + +/** + * The identifier of a frame timeline. + */ +typedef int64_t AVsyncId; + +struct AChoreographerFrameCallbackData; +/** + * Opaque type that provides access to an AChoreographerFrameCallbackData object. + */ +typedef struct AChoreographerFrameCallbackData AChoreographerFrameCallbackData; + /** * Prototype of the function that is called when a new frame is being rendered. * It's passed the time that the frame is being rendered as nanoseconds in the @@ -60,6 +72,14 @@ typedef void (*AChoreographer_frameCallback)(long frameTimeNanos, void* data); typedef void (*AChoreographer_frameCallback64)(int64_t frameTimeNanos, void* data); /** + * Prototype of the function that is called when a new frame is being rendered. + * It's passed the frame data that should not outlive the callback, as well as the data pointer + * provided by the application that registered a callback. + */ +typedef void (*AChoreographer_vsyncCallback)( + const AChoreographerFrameCallbackData* callbackData, void* data); + +/** * Prototype of the function that is called when the display refresh rate * changes. It's passed the new vsync period in nanoseconds, as well as the data * pointer provided by the application that registered a callback. @@ -111,6 +131,14 @@ void AChoreographer_postFrameCallbackDelayed64(AChoreographer* choreographer, uint32_t delayMillis) __INTRODUCED_IN(29); /** + * Posts a callback to run on the next frame. The data pointer provided will + * be passed to the callback function when it's called. + */ +void AChoreographer_postVsyncCallback(AChoreographer* choreographer, + AChoreographer_vsyncCallback callback, void* data) + __INTRODUCED_IN(33); + +/** * Registers a callback to be run when the display refresh rate changes. The * data pointer provided will be passed to the callback function when it's * called. The same callback may be registered multiple times, provided that a @@ -160,6 +188,42 @@ void AChoreographer_unregisterRefreshRateCallback(AChoreographer* choreographer, AChoreographer_refreshRateCallback, void* data) __INTRODUCED_IN(30); +/** + * The time in nanoseconds when the frame started being rendered. + */ +int64_t AChoreographerFrameCallbackData_getFrameTimeNanos( + const AChoreographerFrameCallbackData* data) __INTRODUCED_IN(33); + +/** + * The number of possible frame timelines. + */ +size_t AChoreographerFrameCallbackData_getFrameTimelinesLength( + const AChoreographerFrameCallbackData* data) __INTRODUCED_IN(33); + +/** + * Get index of the platform-preferred FrameTimeline. + */ +size_t AChoreographerFrameCallbackData_getPreferredFrameTimelineIndex( + const AChoreographerFrameCallbackData* data) __INTRODUCED_IN(33); + +/** + * The vsync ID token used to map Choreographer data. + */ +AVsyncId AChoreographerFrameCallbackData_getFrameTimelineVsyncId( + const AChoreographerFrameCallbackData* data, size_t index) __INTRODUCED_IN(33); + +/** + * The time in nanoseconds which the frame at given index is expected to be presented. + */ +int64_t AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentationTimeNanos( + const AChoreographerFrameCallbackData* data, size_t index) __INTRODUCED_IN(33); + +/** + * The time in nanoseconds which the frame at given index needs to be ready by. + */ +int64_t AChoreographerFrameCallbackData_getFrameTimelineDeadlineNanos( + const AChoreographerFrameCallbackData* data, size_t index) __INTRODUCED_IN(33); + __END_DECLS #endif // ANDROID_CHOREOGRAPHER_H diff --git a/include/android/input.h b/include/android/input.h index bb98beb41a..38b27bc587 100644 --- a/include/android/input.h +++ b/include/android/input.h @@ -169,6 +169,9 @@ enum { /** Drag event */ AINPUT_EVENT_TYPE_DRAG = 5, + + /** TouchMode event */ + AINPUT_EVENT_TYPE_TOUCH_MODE = 6, }; /** @@ -805,6 +808,34 @@ enum { }; /** + * Constants that identify different gesture classification types. + */ +enum AMotionClassification : uint32_t { + /** + * Classification constant: None. + * + * No additional information is available about the current motion event stream. + */ + AMOTION_EVENT_CLASSIFICATION_NONE = 0, + /** + * Classification constant: Ambiguous gesture. + * + * The user's intent with respect to the current event stream is not yet determined. Events + * starting in AMBIGUOUS_GESTURE will eventually resolve into either DEEP_PRESS or NONE. + * Gestural actions, such as scrolling, should be inhibited until the classification resolves + * to another value or the event stream ends. + */ + AMOTION_EVENT_CLASSIFICATION_AMBIGUOUS_GESTURE = 1, + /** + * Classification constant: Deep press. + * + * The current event stream represents the user intentionally pressing harder on the screen. + * This classification type should be used to accelerate the long press behaviour. + */ + AMOTION_EVENT_CLASSIFICATION_DEEP_PRESS = 2, +}; + +/** * Input source masks. * * Refer to the documentation on android.view.InputDevice for more details about input sources @@ -874,6 +905,7 @@ enum { * Keyboard types. * * Refer to the documentation on android.view.InputDevice for more details. + * Note: When adding a new keyboard type here InputDeviceInfo::setKeyboardType needs to be updated. */ enum { /** none */ @@ -947,9 +979,10 @@ int32_t AInputEvent_getSource(const AInputEvent* event); * and {@link AMotionEvent_fromJava()}. * After returning, the specified AInputEvent* object becomes invalid and should no longer be used. * The underlying Java object remains valid and does not change its state. + * + * Available since API level 31. */ - -void AInputEvent_release(const AInputEvent* event); +void AInputEvent_release(const AInputEvent* event) __INTRODUCED_IN(31); /*** Accessors for key events only. ***/ @@ -1001,8 +1034,10 @@ int64_t AKeyEvent_getEventTime(const AInputEvent* key_event); * Creates a native AInputEvent* object that is a copy of the specified Java android.view.KeyEvent. * The result may be used with generic and KeyEvent-specific AInputEvent_* functions. The object * returned by this function must be disposed using {@link AInputEvent_release()}. + * + * Available since API level 31. */ -const AInputEvent* AKeyEvent_fromJava(JNIEnv* env, jobject keyEvent); +const AInputEvent* AKeyEvent_fromJava(JNIEnv* env, jobject keyEvent) __INTRODUCED_IN(31); /*** Accessors for motion events only. ***/ @@ -1320,12 +1355,41 @@ float AMotionEvent_getHistoricalAxisValue(const AInputEvent* motion_event, int32_t axis, size_t pointer_index, size_t history_index); /** + * Get the action button for the motion event. Returns a valid action button when the + * event is associated with a button press or button release action. For other actions + * the return value is undefined. + * + * @see #AMOTION_EVENT_BUTTON_PRIMARY + * @see #AMOTION_EVENT_BUTTON_SECONDARY + * @see #AMOTION_EVENT_BUTTON_TERTIARY + * @see #AMOTION_EVENT_BUTTON_BACK + * @see #AMOTION_EVENT_BUTTON_FORWARD + * @see #AMOTION_EVENT_BUTTON_STYLUS_PRIMARY + * @see #AMOTION_EVENT_BUTTON_STYLUS_SECONDARY + */ +int32_t AMotionEvent_getActionButton(const AInputEvent* motion_event) + __INTRODUCED_IN(__ANDROID_API_T__); + +/** + * Returns the classification for the current gesture. + * The classification may change as more events become available for the same gesture. + * + * @see #AMOTION_EVENT_CLASSIFICATION_NONE + * @see #AMOTION_EVENT_CLASSIFICATION_AMBIGUOUS_GESTURE + * @see #AMOTION_EVENT_CLASSIFICATION_DEEP_PRESS +*/ +int32_t AMotionEvent_getClassification(const AInputEvent* motion_event) + __INTRODUCED_IN(__ANDROID_API_T__); + +/** * Creates a native AInputEvent* object that is a copy of the specified Java * android.view.MotionEvent. The result may be used with generic and MotionEvent-specific * AInputEvent_* functions. The object returned by this function must be disposed using * {@link AInputEvent_release()}. + * + * Available since API level 31. */ -const AInputEvent* AMotionEvent_fromJava(JNIEnv* env, jobject motionEvent); +const AInputEvent* AMotionEvent_fromJava(JNIEnv* env, jobject motionEvent) __INTRODUCED_IN(31); struct AInputQueue; /** @@ -1377,6 +1441,17 @@ int32_t AInputQueue_preDispatchEvent(AInputQueue* queue, AInputEvent* event); */ void AInputQueue_finishEvent(AInputQueue* queue, AInputEvent* event, int handled); +/** + * Returns the AInputQueue* object associated with the supplied Java InputQueue + * object. The returned native object holds a weak reference to the Java object, + * and is only valid as long as the Java object has not yet been disposed. You + * should ensure that there is a strong reference to the Java object and that it + * has not been disposed before using the returned object. + * + * Available since API level 33. + */ +AInputQueue* AInputQueue_fromJava(JNIEnv* env, jobject inputQueue) __INTRODUCED_IN(33); + #ifdef __cplusplus } #endif diff --git a/include/android/multinetwork.h b/include/android/multinetwork.h index 509ee0e49b..ee392fc401 100644 --- a/include/android/multinetwork.h +++ b/include/android/multinetwork.h @@ -216,6 +216,79 @@ int android_res_nresult(int fd, */ void android_res_cancel(int nsend_fd) __INTRODUCED_IN(29); +/* + * Set the socket tag and owning UID for traffic statistics on the specified + * socket. + * + * Subsequent calls always replace any existing parameters. The socket tag and + * uid (if set) are kept when the socket is sent to another process using binder + * IPCs or other mechanisms such as UNIX socket fd passing. Any app can accept + * blame for future traffic performed on a socket originally created by another + * app by calling this method with its own UID (or calling + * android_tag_socket(int sockfd, int tag)). However, only apps holding the + * android.Manifest.permission#UPDATE_DEVICE_STATS permission may assign blame + * to another UIDs. If unset (default) the socket tag is 0, and the uid is the + * socket creator's uid. + * + * Returns 0 on success, or a negative POSIX error code (see errno.h) on + * failure. + * + * Available since API level 33. + */ +int android_tag_socket_with_uid(int sockfd, uint32_t tag, uid_t uid) __INTRODUCED_IN(33); + +/* + * Set the socket tag for traffic statistics on the specified socket. + * + * This function tags the socket with the caller's UID (accepting blame for + * future traffic performed on this socket) even if the socket was originally + * opened by another UID or was previously tagged by another UID. Subsequent + * calls always replace any existing parameters. The socket tag is kept when the + * socket is sent to another process using binder IPCs or other mechanisms such + * as UNIX socket fd passing. The tag is a value defined by the caller and used + * together with uid for data traffic accounting, so that the function callers + * can account different types of data usage for a uid. + * + * Returns 0 on success, or a negative POSIX error code (see errno.h) on + * failure. + * + * Some possible error codes: + * -EBADF Bad socketfd. + * -EPERM No permission. + * -EAFNOSUPPORT Socket family is neither AF_INET nor AF_INET6. + * -EPROTONOSUPPORT Socket protocol is neither IPPROTO_UDP nor IPPROTO_TCP. + * -EMFILE Too many stats entries. + * There are still other error codes that may provided by -errno of + * [getsockopt()](https://man7.org/linux/man-pages/man2/getsockopt.2.html) or by + * BPF maps read/write sys calls, which are set appropriately. + * + * Available since API level 33. + */ +int android_tag_socket(int sockfd, uint32_t tag) __INTRODUCED_IN(33); + +/* + * Untag a network socket. + * + * Future traffic on this socket will no longer be associated with any + * previously configured tag and uid. If the socket was created by another UID + * or was previously tagged by another UID, calling this function will clear the + * statistics parameters, and thus the UID blamed for traffic on the socket will + * be the UID that originally created the socket, even if the socket was + * subsequently tagged by a different UID. + * + * Returns 0 on success, or a negative POSIX error code (see errno.h) on + * failure. + * + * One of possible error code: + * -EBADF Bad socketfd. + * Other error codes are either provided by -errno of + * [getsockopt()](https://man7.org/linux/man-pages/man2/getsockopt.2.html) or by + * BPF map element deletion sys call, which are set appropriately. + * + * Available since API level 33. + */ +int android_untag_socket(int sockfd) __INTRODUCED_IN(33); + __END_DECLS #endif // ANDROID_MULTINETWORK_H diff --git a/include/android/performance_hint.h b/include/android/performance_hint.h new file mode 100644 index 0000000000..5fa47f64be --- /dev/null +++ b/include/android/performance_hint.h @@ -0,0 +1,164 @@ +/* + * Copyright (C) 2021 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. + */ + +#ifndef ANDROID_NATIVE_PERFORMANCE_HINT_H +#define ANDROID_NATIVE_PERFORMANCE_HINT_H + +#include <sys/cdefs.h> + +/****************************************************************** + * + * IMPORTANT NOTICE: + * + * This file is part of Android's set of stable system headers + * exposed by the Android NDK (Native Development Kit). + * + * Third-party source AND binary code relies on the definitions + * here to be FROZEN ON ALL UPCOMING PLATFORM RELEASES. + * + * - DO NOT MODIFY ENUMS (EXCEPT IF YOU ADD NEW 32-BIT VALUES) + * - DO NOT MODIFY CONSTANTS OR FUNCTIONAL MACROS + * - DO NOT CHANGE THE SIGNATURE OF FUNCTIONS IN ANY WAY + * - DO NOT CHANGE THE LAYOUT OR SIZE OF STRUCTURES + */ + +#include <android/api-level.h> +#include <stdint.h> + +__BEGIN_DECLS + +struct APerformanceHintManager; +struct APerformanceHintSession; + +/** + * An opaque type representing a handle to a performance hint manager. + * It must be released after use. + * + * <p>To use:<ul> + * <li>Obtain the performance hint manager instance by calling + * {@link APerformanceHint_getManager} function.</li> + * <li>Create an {@link APerformanceHintSession} with + * {@link APerformanceHint_createSession}.</li> + * <li>Get the preferred update rate in nanoseconds with + * {@link APerformanceHint_getPreferredUpdateRateNanos}.</li> + */ +typedef struct APerformanceHintManager APerformanceHintManager; + +/** + * An opaque type representing a handle to a performance hint session. + * A session can only be acquired from a {@link APerformanceHintManager} + * with {@link APerformanceHint_getPreferredUpdateRateNanos}. It must be + * freed with {@link APerformanceHint_closeSession} after use. + * + * A Session represents a group of threads with an inter-related workload such that hints for + * their performance should be considered as a unit. The threads in a given session should be + * long-life and not created or destroyed dynamically. + * + * <p>Each session is expected to have a periodic workload with a target duration for each + * cycle. The cycle duration is likely greater than the target work duration to allow other + * parts of the pipeline to run within the available budget. For example, a renderer thread may + * work at 60hz in order to produce frames at the display's frame but have a target work + * duration of only 6ms.</p> + * + * <p>After each cycle of work, the client is expected to use + * {@link APerformanceHint_reportActualWorkDuration} to report the actual time taken to + * complete.</p> + * + * <p>To use:<ul> + * <li>Update a sessions target duration for each cycle of work + * with {@link APerformanceHint_updateTargetWorkDuration}.</li> + * <li>Report the actual duration for the last cycle of work with + * {@link APerformanceHint_reportActualWorkDuration}.</li> + * <li>Release the session instance with + * {@link APerformanceHint_closeSession}.</li></ul></p> + */ +typedef struct APerformanceHintSession APerformanceHintSession; + +/** + * Acquire an instance of the performance hint manager. + * + * @return manager instance on success, nullptr on failure. + */ +APerformanceHintManager* APerformanceHint_getManager() __INTRODUCED_IN(__ANDROID_API_T__); + +/** + * Creates a session for the given set of threads and sets their initial target work + * duration. + * @param manager The performance hint manager instance. + * @param threadIds The list of threads to be associated with this session. They must be part of + * this app's thread group. + * @param size the size of threadIds. + * @param initialTargetWorkDurationNanos The desired duration in nanoseconds for the new session. + * This must be positive. + * @return manager instance on success, nullptr on failure. + */ +APerformanceHintSession* APerformanceHint_createSession( + APerformanceHintManager* manager, + const int32_t* threadIds, size_t size, + int64_t initialTargetWorkDurationNanos) __INTRODUCED_IN(__ANDROID_API_T__); + +/** + * Get preferred update rate information for this device. + * + * @param manager The performance hint manager instance. + * @return the preferred update rate supported by device software. + */ +int64_t APerformanceHint_getPreferredUpdateRateNanos( + APerformanceHintManager* manager) __INTRODUCED_IN(__ANDROID_API_T__); + +/** + * Updates this session's target duration for each cycle of work. + * + * @param session The performance hint session instance to update. + * @param targetDurationNanos the new desired duration in nanoseconds. This must be positive. + * @return 0 on success + * EINVAL if targetDurationNanos is not positive. + * EPIPE if communication with the system service has failed. + */ +int APerformanceHint_updateTargetWorkDuration( + APerformanceHintSession* session, + int64_t targetDurationNanos) __INTRODUCED_IN(__ANDROID_API_T__); + +/** + * Reports the actual duration for the last cycle of work. + * + * <p>The system will attempt to adjust the core placement of the threads within the thread + * group and/or the frequency of the core on which they are run to bring the actual duration + * close to the target duration.</p> + * + * @param session The performance hint session instance to update. + * @param actualDurationNanos how long the thread group took to complete its last task in + * nanoseconds. This must be positive. + * @return 0 on success + * EINVAL if actualDurationNanos is not positive. + * EPIPE if communication with the system service has failed. + */ +int APerformanceHint_reportActualWorkDuration( + APerformanceHintSession* session, + int64_t actualDurationNanos) __INTRODUCED_IN(__ANDROID_API_T__); + +/** + * Release the performance hint manager pointer acquired via + * {@link APerformanceHint_createSession}. + * + * @param session The performance hint session instance to release. + */ +void APerformanceHint_closeSession( + APerformanceHintSession* session) __INTRODUCED_IN(__ANDROID_API_T__); + +__END_DECLS + +#endif // ANDROID_NATIVE_PERFORMANCE_HINT_H diff --git a/include/android/sensor.h b/include/android/sensor.h index 9dc6983e50..eef69f4b32 100644 --- a/include/android/sensor.h +++ b/include/android/sensor.h @@ -213,6 +213,13 @@ enum { */ ASENSOR_TYPE_HEART_BEAT = 31, /** + * A constant describing a dynamic sensor meta event sensor. + * + * A sensor event of this type is received when a dynamic sensor is added to or removed from + * the system. This sensor type should always use special trigger report mode. + */ + ASENSOR_TYPE_DYNAMIC_SENSOR_META = 32, + /** * This sensor type is for delivering additional sensor information aside * from sensor event data. * @@ -256,6 +263,60 @@ enum { * The hinge angle sensor value is returned in degrees. */ ASENSOR_TYPE_HINGE_ANGLE = 36, + /** + * {@link ASENSOR_TYPE_HEAD_TRACKER} + * reporting-mode: continuous + * + * Measures the orientation and rotational velocity of a user's head. Only for internal use + * within the Android system. + */ + ASENSOR_TYPE_HEAD_TRACKER = 37, + /** + * {@link ASENSOR_TYPE_ACCELEROMETER_LIMITED_AXES} + * reporting-mode: continuous + * + * The first three values are in SI units (m/s^2) and measure the acceleration of the device + * minus the force of gravity. The last three values indicate which acceleration axes are + * supported. A value of 1.0 means supported and a value of 0 means not supported. + */ + ASENSOR_TYPE_ACCELEROMETER_LIMITED_AXES = 38, + /** + * {@link ASENSOR_TYPE_GYROSCOPE_LIMITED_AXES} + * reporting-mode: continuous + * + * The first three values are in radians/second and measure the rate of rotation around the X, + * Y and Z axis. The last three values indicate which rotation axes are supported. A value of + * 1.0 means supported and a value of 0 means not supported. + */ + ASENSOR_TYPE_GYROSCOPE_LIMITED_AXES = 39, + /** + * {@link ASENSOR_TYPE_ACCELEROMETER_LIMITED_AXES_UNCALIBRATED} + * reporting-mode: continuous + * + * The first three values are in SI units (m/s^2) and measure the acceleration of the device + * minus the force of gravity. The middle three values represent the estimated bias for each + * axis. The last three values indicate which acceleration axes are supported. A value of 1.0 + * means supported and a value of 0 means not supported. + */ + ASENSOR_TYPE_ACCELEROMETER_LIMITED_AXES_UNCALIBRATED = 40, + /** + * {@link ASENSOR_TYPE_GYROSCOPE_LIMITED_AXES_UNCALIBRATED} + * reporting-mode: continuous + * + * The first three values are in radians/second and measure the rate of rotation around the X, + * Y and Z axis. The middle three values represent the estimated drift around each axis in + * rad/s. The last three values indicate which rotation axes are supported. A value of 1.0 means + * supported and a value of 0 means not supported. + */ + ASENSOR_TYPE_GYROSCOPE_LIMITED_AXES_UNCALIBRATED = 41, + /** + * {@link ASENSOR_TYPE_HEADING} + * reporting-mode: continuous + * + * A heading sensor measures the direction in which the device is pointing + * relative to true north in degrees. + */ + ASENSOR_TYPE_HEADING = 42, }; /** @@ -440,6 +501,101 @@ typedef struct AAdditionalInfoEvent { }; } AAdditionalInfoEvent; +typedef struct AHeadTrackerEvent { + /** + * The fields rx, ry, rz are an Euler vector (rotation vector, i.e. a vector + * whose direction indicates the axis of rotation and magnitude indicates + * the angle to rotate around that axis) representing the transform from + * the (arbitrary, possibly slowly drifting) reference frame to the + * head frame. Expressed in radians. Magnitude of the vector must be + * in the range [0, pi], while the value of individual axes are + * in the range [-pi, pi]. + */ + float rx; + float ry; + float rz; + + /** + * The fields vx, vy, vz are an Euler vector (rotation vector) representing + * the angular velocity of the head (relative to itself), in radians per + * second. The direction of this vector indicates the axis of rotation, and + * the magnitude indicates the rate of rotation. + */ + float vx; + float vy; + float vz; + + /** + * This value changes each time the reference frame is suddenly and + * significantly changed, for example if an orientation filter algorithm + * used for determining the orientation has had its state reset. + */ + int32_t discontinuity_count; +} AHeadTrackerEvent; + +typedef struct ALimitedAxesImuEvent { + union { + float calib[3]; + struct { + float x; + float y; + float z; + }; + }; + union { + float supported[3]; + struct { + float x_supported; + float y_supported; + float z_supported; + }; + }; +} ALimitedAxesImuEvent; + +typedef struct ALimitedAxesImuUncalibratedEvent { + union { + float uncalib[3]; + struct { + float x_uncalib; + float y_uncalib; + float z_uncalib; + }; + }; + union { + float bias[3]; + struct { + float x_bias; + float y_bias; + float z_bias; + }; + }; + union { + float supported[3]; + struct { + float x_supported; + float y_supported; + float z_supported; + }; + }; +} ALimitedAxesImuUncalibratedEvent; + +typedef struct AHeadingEvent { + /** + * The direction in which the device is pointing relative to true north in + * degrees. The value must be between 0.0 (inclusive) and 360.0 (exclusive), + * with 0 indicating north, 90 east, 180 south, and 270 west. + */ + float heading; + /** + * Accuracy is defined at 68% confidence. In the case where the underlying + * distribution is assumed Gaussian normal, this would be considered one + * standard deviation. For example, if the heading returns 60 degrees, and + * accuracy returns 10 degrees, then there is a 68 percent probability of + * the true heading being between 50 degrees and 70 degrees. + */ + float accuracy; +} AHeadingEvent; + /** * Information that describes a sensor event, refer to * <a href="/reference/android/hardware/SensorEvent">SensorEvent</a> for additional @@ -476,6 +632,10 @@ typedef struct ASensorEvent { AHeartRateEvent heart_rate; ADynamicSensorEvent dynamic_sensor_meta; AAdditionalInfoEvent additional_info; + AHeadTrackerEvent head_tracker; + ALimitedAxesImuEvent limited_axes_imu; + ALimitedAxesImuUncalibratedEvent limited_axes_imu_uncalibrated; + AHeadingEvent heading; }; union { uint64_t data[8]; @@ -591,11 +751,40 @@ ASensorManager* ASensorManager_getInstance() __DEPRECATED_IN(26); ASensorManager* ASensorManager_getInstanceForPackage(const char* packageName) __INTRODUCED_IN(26); /** - * Returns the list of available sensors. + * Returns the list of available sensors. The returned list is owned by the + * sensor manager and will not change between calls to this function. + * + * \param manager the {@link ASensorManager} instance obtained from + * {@link ASensorManager_getInstanceForPackage}. + * \param list the returned list of sensors. + * \return positive number of returned sensors or negative error code. + * BAD_VALUE: manager is NULL. */ int ASensorManager_getSensorList(ASensorManager* manager, ASensorList* list); /** + * Returns the list of available dynamic sensors. If there are no dynamic + * sensors available, returns nullptr in list. + * + * Each time this is called, the previously returned list is deallocated and + * must no longer be used. + * + * Clients should call this if they receive a sensor update from + * {@link ASENSOR_TYPE_DYNAMIC_SENSOR_META} indicating the sensors have changed. + * If this happens, previously received lists from this method will be stale. + * + * Available since API level 33. + * + * \param manager the {@link ASensorManager} instance obtained from + * {@link ASensorManager_getInstanceForPackage}. + * \param list the returned list of dynamic sensors. + * \return positive number of returned sensors or negative error code. + * BAD_VALUE: manager is NULL. + */ +ssize_t ASensorManager_getDynamicSensorList( + ASensorManager* manager, ASensorList* list) __INTRODUCED_IN(33); + +/** * Returns the default sensor for the given type, or NULL if no sensor * of that type exists. */ diff --git a/include/android/storage_manager.h b/include/android/storage_manager.h index 7f2ee08d62..270570e0df 100644 --- a/include/android/storage_manager.h +++ b/include/android/storage_manager.h @@ -124,6 +124,12 @@ typedef void (*AStorageManager_obbCallbackFunc)(const char* filename, const int3 /** * Attempts to mount an OBB file. This is an asynchronous operation. + * + * Since API level 33, this function can only be used to mount unencrypted OBBs, + * i.e. the {@code key} parameter must be {@code null} or an empty string. Note + * that even before API level 33, mounting encrypted OBBs didn't work on many + * Android device implementations. Applications should not assume any particular + * behavior when {@code key} is nonempty. */ void AStorageManager_mountObb(AStorageManager* mgr, const char* filename, const char* key, AStorageManager_obbCallbackFunc cb, void* data); diff --git a/include/android/surface_control.h b/include/android/surface_control.h index 059bc41f9a..9a36ecb537 100644 --- a/include/android/surface_control.h +++ b/include/android/surface_control.h @@ -28,6 +28,7 @@ #include <sys/cdefs.h> +#include <android/choreographer.h> #include <android/data_space.h> #include <android/hardware_buffer.h> #include <android/hdr_metadata.h> @@ -595,6 +596,25 @@ void ASurfaceTransaction_setEnableBackPressure(ASurfaceTransaction* transaction, bool enableBackPressure) __INTRODUCED_IN(31); +/** + * Sets the frame timeline to use in Surface Flinger. + * + * A frame timeline should be chosen based on what frame deadline the application + * can meet when rendering the frame and the application's desired present time. + * By setting a frame timeline, Surface Flinger tries to present the frame at the corresponding + * expected present time. + * + * To receive frame timelines, a callback must be posted to Choreographer using + * AChoreographer_postExtendedFrameCallback(). The \a vsnycId can then be extracted from the + * callback payload using AChoreographerFrameCallbackData_getFrameTimelineVsyncId(). + * + * \param vsyncId The vsync ID received from AChoreographer, setting the frame's present target to + * the corresponding expected present time and deadline from the frame to be rendered. A stale or + * invalid value will be ignored. + */ +void ASurfaceTransaction_setFrameTimeline(ASurfaceTransaction* transaction, + AVsyncId vsyncId) __INTRODUCED_IN(33); + __END_DECLS #endif // ANDROID_SURFACE_CONTROL_H diff --git a/include/binder/Enum.h b/include/binder/Enum.h deleted file mode 100644 index 4c256546f6..0000000000 --- a/include/binder/Enum.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (C) 2020 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 - -#error Do not rely on global include files. All Android cc_* programs are given access to \ - include_dirs for frameworks/native/include via global configuration, but this is legacy \ - configuration. Instead, you should have a direct dependency on libbinder OR one of your \ - dependencies should re-export libbinder headers with export_shared_lib_headers. diff --git a/include/ftl/cast.h b/include/ftl/cast.h new file mode 100644 index 0000000000..ff1b58ad56 --- /dev/null +++ b/include/ftl/cast.h @@ -0,0 +1,84 @@ +/* + * Copyright 2021 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 <limits> +#include <type_traits> + +#include <ftl/details/cast.h> + +namespace android::ftl { + +enum class CastSafety { kSafe, kUnderflow, kOverflow }; + +// Returns whether static_cast<R>(v) is safe, or would result in underflow or overflow. +// +// static_assert(ftl::cast_safety<uint8_t>(-1) == ftl::CastSafety::kUnderflow); +// static_assert(ftl::cast_safety<int8_t>(128u) == ftl::CastSafety::kOverflow); +// +// static_assert(ftl::cast_safety<uint32_t>(-.1f) == ftl::CastSafety::kUnderflow); +// static_assert(ftl::cast_safety<int32_t>(static_cast<float>(INT32_MAX)) == +// ftl::CastSafety::kOverflow); +// +// static_assert(ftl::cast_safety<float>(-DBL_MAX) == ftl::CastSafety::kUnderflow); +// +template <typename R, typename T> +constexpr CastSafety cast_safety(T v) { + static_assert(std::is_arithmetic_v<T>); + static_assert(std::is_arithmetic_v<R>); + + constexpr bool kFromSigned = std::is_signed_v<T>; + constexpr bool kToSigned = std::is_signed_v<R>; + + using details::max_exponent; + + // If the R range contains the T range, then casting is always safe. + if constexpr ((kFromSigned == kToSigned && max_exponent<R> >= max_exponent<T>) || + (!kFromSigned && kToSigned && max_exponent<R> > max_exponent<T>)) { + return CastSafety::kSafe; + } + + using C = std::common_type_t<R, T>; + + if constexpr (kFromSigned) { + using L = details::safe_limits<R, T>; + + if constexpr (kToSigned) { + // Signed to signed. + if (v < L::lowest()) return CastSafety::kUnderflow; + return v <= L::max() ? CastSafety::kSafe : CastSafety::kOverflow; + } else { + // Signed to unsigned. + if (v < 0) return CastSafety::kUnderflow; + return static_cast<C>(v) <= static_cast<C>(L::max()) ? CastSafety::kSafe + : CastSafety::kOverflow; + } + } else { + using L = std::numeric_limits<R>; + + if constexpr (kToSigned) { + // Unsigned to signed. + return static_cast<C>(v) <= static_cast<C>(L::max()) ? CastSafety::kSafe + : CastSafety::kOverflow; + } else { + // Unsigned to unsigned. + return v <= L::max() ? CastSafety::kSafe : CastSafety::kOverflow; + } + } +} + +} // namespace android::ftl diff --git a/include/ftl/concat.h b/include/ftl/concat.h new file mode 100644 index 0000000000..ded48f7c8c --- /dev/null +++ b/include/ftl/concat.h @@ -0,0 +1,84 @@ +/* + * Copyright 2021 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 <ftl/details/concat.h> + +namespace android::ftl { + +// Lightweight (not allocating nor sprintf-based) concatenation. +// +// std::string_view name = "Volume"; +// ftl::Concat string(ftl::truncated<3>(name), ": ", -3, " dB"); +// +// assert(string.str() == "Vol: -3 dB"); +// assert(string.c_str()[string.size()] == '\0'); +// +template <std::size_t, typename... Ts> +struct Concat; + +template <std::size_t N, typename T, typename... Ts> +struct Concat<N, T, Ts...> : Concat<N + details::StaticString<T>::N, Ts...> { + explicit constexpr Concat(T v, Ts... args) { append(v, args...); } + + protected: + constexpr Concat() = default; + + constexpr void append(T v, Ts... args) { + using Str = details::StaticString<T>; + const Str str(v); + + // TODO: Replace with constexpr std::copy in C++20. + for (auto it = str.view.begin(); it != str.view.end();) { + *this->end_++ = *it++; + } + + using Base = Concat<N + Str::N, Ts...>; + this->Base::append(args...); + } +}; + +template <std::size_t N> +struct Concat<N> { + static constexpr std::size_t max_size() { return N; } + constexpr std::size_t size() const { return end_ - buffer_; } + + constexpr const char* c_str() const { return buffer_; } + + constexpr std::string_view str() const { + // TODO: Replace with {buffer_, end_} in C++20. + return {buffer_, size()}; + } + + protected: + constexpr Concat() : end_(buffer_) {} + constexpr void append() { *end_ = '\0'; } + + char buffer_[N + 1]; + char* end_; +}; + +// Deduction guide. +template <typename... Ts> +Concat(Ts&&...) -> Concat<0, Ts...>; + +template <std::size_t N> +constexpr auto truncated(std::string_view v) { + return details::Truncated<N>{v}; +} + +} // namespace android::ftl diff --git a/include/ftl/array_traits.h b/include/ftl/details/array_traits.h index 1265fa15fe..5234c383a7 100644 --- a/include/ftl/array_traits.h +++ b/include/ftl/details/array_traits.h @@ -21,9 +21,9 @@ #include <new> #include <type_traits> -#define FTL_ARRAY_TRAIT(T, U) using U = typename ArrayTraits<T>::U +#define FTL_ARRAY_TRAIT(T, U) using U = typename details::ArrayTraits<T>::U -namespace android::ftl { +namespace android::ftl::details { template <typename T> struct ArrayTraits { @@ -42,7 +42,7 @@ struct ArrayTraits { using const_reverse_iterator = std::reverse_iterator<const_iterator>; template <typename... Args> - static pointer construct_at(const_iterator it, Args&&... args) { + static constexpr pointer construct_at(const_iterator it, Args&&... args) { void* const ptr = const_cast<void*>(static_cast<const void*>(it)); if constexpr (std::is_constructible_v<value_type, Args...>) { // TODO: Replace with std::construct_at in C++20. @@ -52,6 +52,42 @@ struct ArrayTraits { return new (ptr) value_type{std::forward<Args>(args)...}; } } + + // TODO: Make constexpr in C++20. + template <typename... Args> + static reference replace_at(const_iterator it, Args&&... args) { + value_type element{std::forward<Args>(args)...}; + return replace_at(it, std::move(element)); + } + + // TODO: Make constexpr in C++20. + static reference replace_at(const_iterator it, value_type&& value) { + std::destroy_at(it); + // This is only safe because exceptions are disabled. + return *construct_at(it, std::move(value)); + } + + // TODO: Make constexpr in C++20. + static void in_place_swap(reference a, reference b) { + value_type c{std::move(a)}; + replace_at(&a, std::move(b)); + replace_at(&b, std::move(c)); + } + + // TODO: Make constexpr in C++20. + static void in_place_swap_ranges(iterator first1, iterator last1, iterator first2) { + while (first1 != last1) { + in_place_swap(*first1++, *first2++); + } + } + + // TODO: Replace with std::uninitialized_copy in C++20. + template <typename Iterator> + static void uninitialized_copy(Iterator first, Iterator last, const_iterator out) { + while (first != last) { + construct_at(out++, *first++); + } + } }; // CRTP mixin to define iterator functions in terms of non-const Self::begin and Self::end. @@ -101,35 +137,35 @@ class ArrayIterators { // TODO: Replace with operator<=> in C++20. template <template <typename, std::size_t> class Array> struct ArrayComparators { - template <typename T, std::size_t N, std::size_t M> - friend bool operator==(const Array<T, N>& lhs, const Array<T, M>& rhs) { + template <typename T, typename U, std::size_t N, std::size_t M> + friend bool operator==(const Array<T, N>& lhs, const Array<U, M>& rhs) { return lhs.size() == rhs.size() && std::equal(lhs.begin(), lhs.end(), rhs.begin()); } - template <typename T, std::size_t N, std::size_t M> - friend bool operator<(const Array<T, N>& lhs, const Array<T, M>& rhs) { + template <typename T, typename U, std::size_t N, std::size_t M> + friend bool operator<(const Array<T, N>& lhs, const Array<U, M>& rhs) { return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); } - template <typename T, std::size_t N, std::size_t M> - friend bool operator>(const Array<T, N>& lhs, const Array<T, M>& rhs) { + template <typename T, typename U, std::size_t N, std::size_t M> + friend bool operator>(const Array<T, N>& lhs, const Array<U, M>& rhs) { return rhs < lhs; } - template <typename T, std::size_t N, std::size_t M> - friend bool operator!=(const Array<T, N>& lhs, const Array<T, M>& rhs) { + template <typename T, typename U, std::size_t N, std::size_t M> + friend bool operator!=(const Array<T, N>& lhs, const Array<U, M>& rhs) { return !(lhs == rhs); } - template <typename T, std::size_t N, std::size_t M> - friend bool operator>=(const Array<T, N>& lhs, const Array<T, M>& rhs) { + template <typename T, typename U, std::size_t N, std::size_t M> + friend bool operator>=(const Array<T, N>& lhs, const Array<U, M>& rhs) { return !(lhs < rhs); } - template <typename T, std::size_t N, std::size_t M> - friend bool operator<=(const Array<T, N>& lhs, const Array<T, M>& rhs) { + template <typename T, typename U, std::size_t N, std::size_t M> + friend bool operator<=(const Array<T, N>& lhs, const Array<U, M>& rhs) { return !(lhs > rhs); } }; -} // namespace android::ftl +} // namespace android::ftl::details diff --git a/include/ftl/details/cast.h b/include/ftl/details/cast.h new file mode 100644 index 0000000000..87b9f1e20a --- /dev/null +++ b/include/ftl/details/cast.h @@ -0,0 +1,57 @@ +/* + * Copyright 2021 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 <limits> +#include <type_traits> + +namespace android::ftl::details { + +// Exponent whose power of 2 is the (exclusive) upper bound of T. +template <typename T, typename L = std::numeric_limits<T>> +constexpr int max_exponent = std::is_floating_point_v<T> ? L::max_exponent : L::digits; + +// Extension of std::numeric_limits<T> that reduces the maximum for integral types T such that it +// has an exact representation for floating-point types F. For example, the maximum int32_t value +// is 2'147'483'647, but casting it to float commonly rounds up to 2'147'483'650.f, which cannot +// be safely converted back lest the signed overflow invokes undefined behavior. This pitfall is +// avoided by clearing the lower (31 - 24 =) 7 bits of precision to 2'147'483'520. Note that the +// minimum is representable. +template <typename T, typename F> +struct safe_limits : std::numeric_limits<T> { + static constexpr T max() { + using Base = std::numeric_limits<T>; + + if constexpr (std::is_integral_v<T> && std::is_floating_point_v<F>) { + // Assume the mantissa is 24 bits for float, or 53 bits for double. + using Float = std::numeric_limits<F>; + static_assert(Float::is_iec559); + + // If the integer is wider than the mantissa, clear the excess bits of precision. + constexpr int kShift = Base::digits - Float::digits; + if constexpr (kShift > 0) { + using U = std::make_unsigned_t<T>; + constexpr U kOne = static_cast<U>(1); + return static_cast<U>(Base::max()) & ~((kOne << kShift) - kOne); + } + } + + return Base::max(); + } +}; + +} // namespace android::ftl::details diff --git a/include/ftl/details/concat.h b/include/ftl/details/concat.h new file mode 100644 index 0000000000..8ce949ef05 --- /dev/null +++ b/include/ftl/details/concat.h @@ -0,0 +1,62 @@ +/* + * Copyright 2021 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 <functional> +#include <string_view> + +#include <ftl/string.h> + +namespace android::ftl::details { + +template <typename T, typename = void> +struct StaticString; + +template <typename T> +struct StaticString<T, std::enable_if_t<std::is_integral_v<T>>> { + static constexpr std::size_t N = to_chars_length_v<T>; + + explicit StaticString(T v) : view(to_chars(buffer, v)) {} + + to_chars_buffer_t<T> buffer; + const std::string_view view; +}; + +template <std::size_t M> +struct StaticString<const char (&)[M], void> { + static constexpr std::size_t N = M - 1; + + explicit constexpr StaticString(const char (&str)[M]) : view(str, N) {} + + const std::string_view view; +}; + +template <std::size_t N> +struct Truncated { + std::string_view view; +}; + +template <std::size_t M> +struct StaticString<Truncated<M>, void> { + static constexpr std::size_t N = M; + + explicit constexpr StaticString(Truncated<M> str) : view(str.view.substr(0, N)) {} + + const std::string_view view; +}; + +} // namespace android::ftl::details diff --git a/include/ftl/details/future.h b/include/ftl/details/future.h new file mode 100644 index 0000000000..df1323e8be --- /dev/null +++ b/include/ftl/details/future.h @@ -0,0 +1,98 @@ +/* + * Copyright 2022 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 + +namespace android::ftl { + +template <typename, template <typename> class> +class Future; + +namespace details { + +template <typename T> +struct future_result { + using type = T; +}; + +template <typename T> +struct future_result<std::future<T>> { + using type = T; +}; + +template <typename T> +struct future_result<std::shared_future<T>> { + using type = T; +}; + +template <typename T, template <typename> class FutureImpl> +struct future_result<Future<T, FutureImpl>> { + using type = T; +}; + +template <typename T> +using future_result_t = typename future_result<T>::type; + +struct ValueTag {}; + +template <typename, typename T, template <typename> class> +class BaseFuture; + +template <typename Self, typename T> +class BaseFuture<Self, T, std::future> { + using Impl = std::future<T>; + + public: + Future<T, std::shared_future> share() { + if (T* value = std::get_if<T>(&self())) { + return {ValueTag{}, std::move(*value)}; + } + + return std::get<Impl>(self()).share(); + } + + protected: + T get() { + if (T* value = std::get_if<T>(&self())) { + return std::move(*value); + } + + return std::get<Impl>(self()).get(); + } + + private: + auto& self() { return static_cast<Self&>(*this).future_; } +}; + +template <typename Self, typename T> +class BaseFuture<Self, T, std::shared_future> { + using Impl = std::shared_future<T>; + + protected: + const T& get() const { + if (const T* value = std::get_if<T>(&self())) { + return *value; + } + + return std::get<Impl>(self()).get(); + } + + private: + const auto& self() const { return static_cast<const Self&>(*this).future_; } +}; + +} // namespace details +} // namespace android::ftl diff --git a/include/ftl/enum.h b/include/ftl/enum.h new file mode 100644 index 0000000000..82af1d6cf8 --- /dev/null +++ b/include/ftl/enum.h @@ -0,0 +1,301 @@ +/* + * Copyright 2021 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 <cstddef> +#include <limits> +#include <optional> +#include <string_view> +#include <type_traits> +#include <utility> + +#include <ftl/string.h> + +// Returns the name of enumerator E::V (i.e. "V") as std::optional<std::string_view> by parsing the +// compiler-generated string literal for the signature of this function. The function is defined in +// the global namespace with a short name and inferred return type to reduce bloat in the read-only +// data segment. +template <typename E, E V> +constexpr auto ftl_enum() { + static_assert(std::is_enum_v<E>); + + using R = std::optional<std::string_view>; + using namespace std::literals; + + // The "pretty" signature has the following format: + // + // auto ftl_enum() [E = android::test::Enum, V = android::test::Enum::kValue] + // + std::string_view view = __PRETTY_FUNCTION__; + const auto template_begin = view.rfind('['); + const auto template_end = view.rfind(']'); + if (template_begin == view.npos || template_end == view.npos) return R{}; + + // Extract the template parameters without the enclosing brackets. Example (cont'd): + // + // E = android::test::Enum, V = android::test::Enum::kValue + // + view = view.substr(template_begin + 1, template_end - template_begin - 1); + const auto value_begin = view.rfind("V = "sv); + if (value_begin == view.npos) return R{}; + + // Example (cont'd): + // + // V = android::test::Enum::kValue + // + view = view.substr(value_begin); + const auto name_begin = view.rfind("::"sv); + if (name_begin == view.npos) return R{}; + + // Chop off the leading "::". + const auto name = view.substr(name_begin + 2); + + // A value that is not enumerated has the format "Enum)42". + return name.find(')') == view.npos ? R{name} : R{}; +} + +namespace android::ftl { + +// Trait for determining whether a type is specifically a scoped enum or not. By definition, a +// scoped enum is one that is not implicitly convertible to its underlying type. +// +// TODO: Replace with std::is_scoped_enum in C++23. +// +template <typename T, bool = std::is_enum_v<T>> +struct is_scoped_enum : std::false_type {}; + +template <typename T> +struct is_scoped_enum<T, true> : std::negation<std::is_convertible<T, std::underlying_type_t<T>>> { +}; + +template <typename T> +inline constexpr bool is_scoped_enum_v = is_scoped_enum<T>::value; + +// Shorthand for casting an enumerator to its integral value. +// +// TODO: Replace with std::to_underlying in C++23. +// +// enum class E { A, B, C }; +// static_assert(ftl::to_underlying(E::B) == 1); +// +template <typename E> +constexpr auto to_underlying(E v) { + return static_cast<std::underlying_type_t<E>>(v); +} + +// Traits for retrieving an enum's range. An enum specifies its range by defining enumerators named +// ftl_first and ftl_last. If omitted, ftl_first defaults to 0, whereas ftl_last defaults to N - 1 +// where N is the bit width of the underlying type, but only if that type is unsigned, assuming the +// enumerators are flags. Also, note that unscoped enums must define both bounds, as casting out-of- +// range values results in undefined behavior if the underlying type is not fixed. +// +// enum class E { A, B, C, F = 5, ftl_last = F }; +// +// static_assert(ftl::enum_begin_v<E> == E::A); +// static_assert(ftl::enum_last_v<E> == E::F); +// static_assert(ftl::enum_size_v<E> == 6); +// +// enum class F : std::uint16_t { X = 0b1, Y = 0b10, Z = 0b100 }; +// +// static_assert(ftl::enum_begin_v<F> == F{0}); +// static_assert(ftl::enum_last_v<F> == F{15}); +// static_assert(ftl::enum_size_v<F> == 16); +// +template <typename E, typename = void> +struct enum_begin { + static_assert(is_scoped_enum_v<E>, "Missing ftl_first enumerator"); + static constexpr E value{0}; +}; + +template <typename E> +struct enum_begin<E, std::void_t<decltype(E::ftl_first)>> { + static constexpr E value = E::ftl_first; +}; + +template <typename E> +inline constexpr E enum_begin_v = enum_begin<E>::value; + +template <typename E, typename = void> +struct enum_end { + using U = std::underlying_type_t<E>; + static_assert(is_scoped_enum_v<E> && std::is_unsigned_v<U>, "Missing ftl_last enumerator"); + + static constexpr E value{std::numeric_limits<U>::digits}; +}; + +template <typename E> +struct enum_end<E, std::void_t<decltype(E::ftl_last)>> { + static constexpr E value = E{to_underlying(E::ftl_last) + 1}; +}; + +template <typename E> +inline constexpr E enum_end_v = enum_end<E>::value; + +template <typename E> +inline constexpr E enum_last_v = E{to_underlying(enum_end_v<E>) - 1}; + +template <typename E> +struct enum_size { + static constexpr auto kBegin = to_underlying(enum_begin_v<E>); + static constexpr auto kEnd = to_underlying(enum_end_v<E>); + static_assert(kBegin < kEnd, "Invalid range"); + + static constexpr std::size_t value = kEnd - kBegin; + static_assert(value <= 64, "Excessive range size"); +}; + +template <typename E> +inline constexpr std::size_t enum_size_v = enum_size<E>::value; + +namespace details { + +template <auto V> +struct Identity { + static constexpr auto value = V; +}; + +template <typename E> +using make_enum_sequence = std::make_integer_sequence<std::underlying_type_t<E>, enum_size_v<E>>; + +template <typename E, template <E> class = Identity, typename = make_enum_sequence<E>> +struct EnumRange; + +template <typename E, template <E> class F, typename T, T... Vs> +struct EnumRange<E, F, std::integer_sequence<T, Vs...>> { + static constexpr auto kBegin = to_underlying(enum_begin_v<E>); + static constexpr auto kSize = enum_size_v<E>; + + using R = decltype(F<E{}>::value); + const R values[kSize] = {F<static_cast<E>(Vs + kBegin)>::value...}; + + constexpr const auto* begin() const { return values; } + constexpr const auto* end() const { return values + kSize; } +}; + +template <auto V> +struct EnumName { + static constexpr auto value = ftl_enum<decltype(V), V>(); +}; + +template <auto I> +struct FlagName { + using E = decltype(I); + using U = std::underlying_type_t<E>; + + static constexpr E V{U{1} << to_underlying(I)}; + static constexpr auto value = ftl_enum<E, V>(); +}; + +} // namespace details + +// Returns an iterable over the range of an enum. +// +// enum class E { A, B, C, F = 5, ftl_last = F }; +// +// std::string string; +// for (E v : ftl::enum_range<E>()) { +// string += ftl::enum_name(v).value_or("?"); +// } +// +// assert(string == "ABC??F"); +// +template <typename E> +constexpr auto enum_range() { + return details::EnumRange<E>{}; +} + +// Returns a stringified enumerator at compile time. +// +// enum class E { A, B, C }; +// static_assert(ftl::enum_name<E::B>() == "B"); +// +template <auto V> +constexpr std::string_view enum_name() { + constexpr auto kName = ftl_enum<decltype(V), V>(); + static_assert(kName, "Unknown enumerator"); + return *kName; +} + +// Returns a stringified enumerator, possibly at compile time. +// +// enum class E { A, B, C, F = 5, ftl_last = F }; +// +// static_assert(ftl::enum_name(E::C).value_or("?") == "C"); +// static_assert(ftl::enum_name(E{3}).value_or("?") == "?"); +// +template <typename E> +constexpr std::optional<std::string_view> enum_name(E v) { + const auto value = to_underlying(v); + + constexpr auto kBegin = to_underlying(enum_begin_v<E>); + constexpr auto kLast = to_underlying(enum_last_v<E>); + if (value < kBegin || value > kLast) return {}; + + constexpr auto kRange = details::EnumRange<E, details::EnumName>{}; + return kRange.values[value - kBegin]; +} + +// Returns a stringified flag enumerator, possibly at compile time. +// +// enum class F : std::uint16_t { X = 0b1, Y = 0b10, Z = 0b100 }; +// +// static_assert(ftl::flag_name(F::Z).value_or("?") == "Z"); +// static_assert(ftl::flag_name(F{0b111}).value_or("?") == "?"); +// +template <typename E> +constexpr std::optional<std::string_view> flag_name(E v) { + const auto value = to_underlying(v); + + // TODO: Replace with std::popcount and std::countr_zero in C++20. + if (__builtin_popcountll(value) != 1) return {}; + + constexpr auto kRange = details::EnumRange<E, details::FlagName>{}; + return kRange.values[__builtin_ctzll(value)]; +} + +// Returns a stringified enumerator, or its integral value if not named. +// +// enum class E { A, B, C, F = 5, ftl_last = F }; +// +// assert(ftl::enum_string(E::C) == "C"); +// assert(ftl::enum_string(E{3}) == "3"); +// +template <typename E> +inline std::string enum_string(E v) { + if (const auto name = enum_name(v)) { + return std::string(*name); + } + return to_string(to_underlying(v)); +} + +// Returns a stringified flag enumerator, or its integral value if not named. +// +// enum class F : std::uint16_t { X = 0b1, Y = 0b10, Z = 0b100 }; +// +// assert(ftl::flag_string(F::Z) == "Z"); +// assert(ftl::flag_string(F{7}) == "0b111"); +// +template <typename E> +inline std::string flag_string(E v) { + if (const auto name = flag_name(v)) { + return std::string(*name); + } + constexpr auto radix = sizeof(E) == 1 ? Radix::kBin : Radix::kHex; + return to_string(to_underlying(v), radix); +} + +} // namespace android::ftl diff --git a/include/ftl/fake_guard.h b/include/ftl/fake_guard.h new file mode 100644 index 0000000000..bacd1b29ef --- /dev/null +++ b/include/ftl/fake_guard.h @@ -0,0 +1,90 @@ +/* + * Copyright 2022 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 FTL_ATTRIBUTE(a) __attribute__((a)) + +namespace android::ftl { + +// Granular alternative to [[clang::no_thread_safety_analysis]]. Given a std::mutex-like object, +// FakeGuard suppresses enforcement of thread-safe access to guarded variables within its scope. +// While FakeGuard is scoped to a block, there are macro shorthands for a single expression, as +// well as function/lambda scope (though calls must be indirect, e.g. virtual or std::function): +// +// struct { +// std::mutex mutex; +// int x FTL_ATTRIBUTE(guarded_by(mutex)) = -1; +// +// int f() { +// { +// ftl::FakeGuard guard(mutex); +// x = 0; +// } +// +// return FTL_FAKE_GUARD(mutex, x + 1); +// } +// +// std::function<int()> g() const { +// return [this]() FTL_FAKE_GUARD(mutex) { return x; }; +// } +// } s; +// +// assert(s.f() == 1); +// assert(s.g()() == 0); +// +// An example of a situation where FakeGuard helps is a mutex that guards writes on Thread 1, and +// reads on Thread 2. Reads on Thread 1, which is the only writer, need not be under lock, so can +// use FakeGuard to appease the thread safety analyzer. Another example is enforcing and documenting +// exclusive access by a single thread. This is done by defining a global constant that represents a +// thread context, and annotating guarded variables as if it were a mutex (though without any effect +// at run time): +// +// constexpr class [[clang::capability("mutex")]] { +// } kMainThreadContext; +// +template <typename Mutex> +struct [[clang::scoped_lockable]] FakeGuard final { + explicit FakeGuard(const Mutex& mutex) FTL_ATTRIBUTE(acquire_capability(mutex)) {} + [[clang::release_capability()]] ~FakeGuard() {} + + FakeGuard(const FakeGuard&) = delete; + FakeGuard& operator=(const FakeGuard&) = delete; +}; + +} // namespace android::ftl + +// TODO: Enable in C++23 once standard attributes can be used on lambdas. +#if 0 +#define FTL_FAKE_GUARD1(mutex) [[using clang: acquire_capability(mutex), release_capability(mutex)]] +#else +#define FTL_FAKE_GUARD1(mutex) \ + FTL_ATTRIBUTE(acquire_capability(mutex)) \ + FTL_ATTRIBUTE(release_capability(mutex)) +#endif + +// The parentheses around `expr` are needed to deduce an lvalue or rvalue reference. +#define FTL_FAKE_GUARD2(mutex, expr) \ + [&]() -> decltype(auto) { \ + const android::ftl::FakeGuard guard(mutex); \ + return (expr); \ + }() + +#define FTL_MAKE_FAKE_GUARD(arg1, arg2, guard, ...) guard + +// The void argument suppresses a warning about zero variadic macro arguments. +#define FTL_FAKE_GUARD(...) \ + FTL_MAKE_FAKE_GUARD(__VA_ARGS__, FTL_FAKE_GUARD2, FTL_FAKE_GUARD1, void)(__VA_ARGS__) diff --git a/include/input/Flags.h b/include/ftl/flags.h index b12a9ed2c5..70aaa0e6dd 100644 --- a/include/input/Flags.h +++ b/include/ftl/flags.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 The Android Open Source Project + * Copyright 2020 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. @@ -14,79 +14,20 @@ * limitations under the License. */ -#include <android-base/stringprintf.h> +#pragma once -#include <array> +#include <ftl/enum.h> +#include <ftl/string.h> + +#include <bitset> #include <cstdint> -#include <optional> +#include <iterator> #include <string> #include <type_traits> -#include "NamedEnum.h" -#include "utils/BitSet.h" - -#ifndef __UI_INPUT_FLAGS_H -#define __UI_INPUT_FLAGS_H - -namespace android { - -namespace details { - -template <typename F> -inline constexpr auto flag_count = sizeof(F) * __CHAR_BIT__; - -template <typename F, typename T, T... I> -constexpr auto generate_flag_values(std::integer_sequence<T, I...> seq) { - constexpr size_t count = seq.size(); - - std::array<F, count> values{}; - for (size_t i = 0, v = 0; v < count; ++i) { - values[v++] = static_cast<F>(T{1} << i); - } - - return values; -} - -template <typename F> -inline constexpr auto flag_values = generate_flag_values<F>( - std::make_integer_sequence<std::underlying_type_t<F>, flag_count<F>>{}); - -template <typename F, std::size_t... I> -constexpr auto generate_flag_names(std::index_sequence<I...>) noexcept { - return std::array<std::optional<std::string_view>, sizeof...(I)>{ - {enum_value_name<F, flag_values<F>[I]>()...}}; -} - -template <typename F> -inline constexpr auto flag_names = - generate_flag_names<F>(std::make_index_sequence<flag_count<F>>{}); - -// A trait for determining whether a type is specifically an enum class or not. -template <typename T, bool = std::is_enum_v<T>> -struct is_enum_class : std::false_type {}; - -// By definition, an enum class is an enum that is not implicitly convertible to its underlying -// type. -template <typename T> -struct is_enum_class<T, true> - : std::bool_constant<!std::is_convertible_v<T, std::underlying_type_t<T>>> {}; - -template <typename T> -inline constexpr bool is_enum_class_v = is_enum_class<T>::value; -} // namespace details - -template <auto V> -constexpr auto flag_name() { - using F = decltype(V); - return details::enum_value_name<F, V>(); -} +// TODO(b/185536303): Align with FTL style. -template <typename F> -constexpr std::optional<std::string_view> flag_name(F flag) { - using U = std::underlying_type_t<F>; - auto idx = static_cast<size_t>(__builtin_ctzl(static_cast<U>(flag))); - return details::flag_names<F>[idx]; -} +namespace android::ftl { /* A class for handling flags defined by an enum or enum class in a type-safe way. */ template <typename F> @@ -95,7 +36,7 @@ class Flags { // further to avoid this restriction but in general we want to encourage the use of enums // anyways. static_assert(std::is_enum_v<F>, "Flags type must be an enum"); - using U = typename std::underlying_type_t<F>; + using U = std::underlying_type_t<F>; public: constexpr Flags(F f) : mFlags(static_cast<U>(f)) {} @@ -107,29 +48,29 @@ public: // should force them to be explicitly constructed from their underlying types to make full use // of the type checker. template <typename T = U> - constexpr Flags(T t, typename std::enable_if_t<!details::is_enum_class_v<F>, T>* = nullptr) - : mFlags(t) {} + constexpr Flags(T t, std::enable_if_t<!is_scoped_enum_v<F>, T>* = nullptr) : mFlags(t) {} + template <typename T = U> - explicit constexpr Flags(T t, - typename std::enable_if_t<details::is_enum_class_v<F>, T>* = nullptr) + explicit constexpr Flags(T t, std::enable_if_t<is_scoped_enum_v<F>, T>* = nullptr) : mFlags(t) {} class Iterator { - // The type can't be larger than 64-bits otherwise it won't fit in BitSet64. - static_assert(sizeof(U) <= sizeof(uint64_t)); + using Bits = std::uint64_t; + static_assert(sizeof(U) <= sizeof(Bits)); public: + constexpr Iterator() = default; Iterator(Flags<F> flags) : mRemainingFlags(flags.mFlags) { (*this)++; } - Iterator() : mRemainingFlags(0), mCurrFlag(static_cast<F>(0)) {} // Pre-fix ++ Iterator& operator++() { - if (mRemainingFlags.isEmpty()) { - mCurrFlag = static_cast<F>(0); + if (mRemainingFlags.none()) { + mCurrFlag = 0; } else { - uint64_t bit = mRemainingFlags.clearLastMarkedBit(); // counts from left - const U flag = 1 << (64 - bit - 1); - mCurrFlag = static_cast<F>(flag); + // TODO: Replace with std::countr_zero in C++20. + const Bits bit = static_cast<Bits>(__builtin_ctzll(mRemainingFlags.to_ullong())); + mRemainingFlags.reset(static_cast<std::size_t>(bit)); + mCurrFlag = static_cast<U>(static_cast<Bits>(1) << bit); } return *this; } @@ -147,7 +88,7 @@ public: bool operator!=(Iterator other) const { return !(*this == other); } - F operator*() { return mCurrFlag; } + F operator*() const { return F{mCurrFlag}; } // iterator traits @@ -166,8 +107,8 @@ public: using pointer = void; private: - BitSet64 mRemainingFlags; - F mCurrFlag; + std::bitset<sizeof(Bits) * 8> mRemainingFlags; + U mCurrFlag = 0; }; /* @@ -179,10 +120,10 @@ public: } /* Tests whether any of the given flags are set */ - bool any(Flags<F> f) { return (mFlags & f.mFlags) != 0; } + bool any(Flags<F> f) const { return (mFlags & f.mFlags) != 0; } /* Tests whether all of the given flags are set */ - bool all(Flags<F> f) { return (mFlags & f.mFlags) == f.mFlags; } + bool all(Flags<F> f) const { return (mFlags & f.mFlags) == f.mFlags; } Flags<F> operator|(Flags<F> rhs) const { return static_cast<F>(mFlags | rhs.mFlags); } Flags<F>& operator|=(Flags<F> rhs) { @@ -212,6 +153,10 @@ public: return *this; } + inline Flags<F>& clear(Flags<F> f = static_cast<F>(~static_cast<U>(0))) { + return *this &= ~f; + } + Iterator begin() const { return Iterator(*this); } Iterator end() const { return Iterator(); } @@ -230,16 +175,16 @@ public: bool first = true; U unstringified = 0; for (const F f : *this) { - std::optional<std::string_view> flagString = flag_name(f); - if (flagString) { - appendFlag(result, flagString.value(), first); + if (const auto flagName = flag_name(f)) { + appendFlag(result, flagName.value(), first); } else { unstringified |= static_cast<U>(f); } } if (unstringified != 0) { - appendFlag(result, base::StringPrintf("0x%08x", unstringified), first); + constexpr auto radix = sizeof(U) == 1 ? Radix::kBin : Radix::kHex; + appendFlag(result, to_string(unstringified, radix), first); } if (first) { @@ -266,18 +211,15 @@ private: // as flags. In order to use these, add them via a `using namespace` declaration. namespace flag_operators { -template <typename F, typename = std::enable_if_t<details::is_enum_class_v<F>>> +template <typename F, typename = std::enable_if_t<is_scoped_enum_v<F>>> inline Flags<F> operator~(F f) { - using U = typename std::underlying_type_t<F>; - return static_cast<F>(~static_cast<U>(f)); + return static_cast<F>(~to_underlying(f)); } -template <typename F, typename = std::enable_if_t<details::is_enum_class_v<F>>> + +template <typename F, typename = std::enable_if_t<is_scoped_enum_v<F>>> Flags<F> operator|(F lhs, F rhs) { - using U = typename std::underlying_type_t<F>; - return static_cast<F>(static_cast<U>(lhs) | static_cast<U>(rhs)); + return static_cast<F>(to_underlying(lhs) | to_underlying(rhs)); } } // namespace flag_operators -} // namespace android - -#endif // __UI_INPUT_FLAGS_H +} // namespace android::ftl diff --git a/include/ftl/future.h b/include/ftl/future.h index dd6358fa7d..c78f9b76b6 100644 --- a/include/ftl/future.h +++ b/include/ftl/future.h @@ -19,91 +19,115 @@ #include <future> #include <type_traits> #include <utility> +#include <variant> + +#include <ftl/details/future.h> namespace android::ftl { -// Creates a future that defers a function call until its result is queried. +// Thin wrapper around FutureImpl<T> (concretely std::future<T> or std::shared_future<T>) with +// extensions for pure values (created via ftl::yield) and continuations. // -// auto future = ftl::defer([](int x) { return x + 1; }, 99); -// assert(future.get() == 100); +// See also SharedFuture<T> shorthand below. // -template <typename F, typename... Args> -inline auto defer(F&& f, Args&&... args) { - return std::async(std::launch::deferred, std::forward<F>(f), std::forward<Args>(args)...); -} +template <typename T, template <typename> class FutureImpl = std::future> +class Future final : public details::BaseFuture<Future<T, FutureImpl>, T, FutureImpl> { + using Base = details::BaseFuture<Future, T, FutureImpl>; -// Creates a future that wraps a value. -// -// auto future = ftl::yield(42); -// assert(future.get() == 42); -// -// auto ptr = std::make_unique<char>('!'); -// auto future = ftl::yield(std::move(ptr)); -// assert(*future.get() == '!'); -// -template <typename T> -inline std::future<T> yield(T&& v) { - return defer([](T&& v) { return std::forward<T>(v); }, std::forward<T>(v)); -} - -namespace details { - -template <typename T> -struct future_result { - using type = T; -}; + friend Base; // For BaseFuture<...>::self. + friend details::BaseFuture<Future<T>, T, std::future>; // For BaseFuture<...>::share. -template <typename T> -struct future_result<std::future<T>> { - using type = T; -}; - -template <typename T> -using future_result_t = typename future_result<T>::type; + public: + // Constructs an invalid future. + Future() : future_(std::in_place_type<FutureImpl<T>>) {} -// Attaches a continuation to a future. The continuation is a function that maps T to either R or -// std::future<R>. In the former case, the chain wraps the result in a future as if by ftl::yield. -// -// auto future = ftl::yield(123); -// std::future<char> futures[] = {ftl::yield('a'), ftl::yield('b')}; -// -// std::future<char> chain = -// ftl::chain(std::move(future)) -// .then([](int x) { return static_cast<std::size_t>(x % 2); }) -// .then([&futures](std::size_t i) { return std::move(futures[i]); }); -// -// assert(chain.get() == 'b'); -// -template <typename T> -struct Chain { - // Implicit conversion. - Chain(std::future<T>&& f) : future(std::move(f)) {} - operator std::future<T>&&() && { return std::move(future); } + // Constructs a future from its standard counterpart, implicitly. + Future(FutureImpl<T>&& f) : future_(std::move(f)) {} - T get() && { return future.get(); } + bool valid() const { + return std::holds_alternative<T>(future_) || std::get<FutureImpl<T>>(future_).valid(); + } + // Forwarding functions. Base::share is only defined when FutureImpl is std::future, whereas the + // following are defined for either FutureImpl: + using Base::get; + + // Attaches a continuation to the future. The continuation is a function that maps T to either R + // or ftl::Future<R>. In the former case, the chain wraps the result in a future as if by + // ftl::yield. + // + // auto future = ftl::yield(123); + // ftl::Future<char> futures[] = {ftl::yield('a'), ftl::yield('b')}; + // + // auto chain = + // ftl::Future(std::move(future)) + // .then([](int x) { return static_cast<std::size_t>(x % 2); }) + // .then([&futures](std::size_t i) { return std::move(futures[i]); }); + // + // assert(chain.get() == 'b'); + // template <typename F, typename R = std::invoke_result_t<F, T>> - auto then(F&& op) && -> Chain<future_result_t<R>> { + auto then(F&& op) && -> Future<details::future_result_t<R>> { return defer( [](auto&& f, F&& op) { R r = op(f.get()); - if constexpr (std::is_same_v<R, future_result_t<R>>) { + if constexpr (std::is_same_v<R, details::future_result_t<R>>) { return r; } else { return r.get(); } }, - std::move(future), std::forward<F>(op)); + std::move(*this), std::forward<F>(op)); } - std::future<T> future; -}; + private: + template <typename V> + friend Future<V> yield(V&&); -} // namespace details + template <typename V, typename... Args> + friend Future<V> yield(Args&&...); + + template <typename... Args> + Future(details::ValueTag, Args&&... args) + : future_(std::in_place_type<T>, std::forward<Args>(args)...) {} + + std::variant<T, FutureImpl<T>> future_; +}; template <typename T> -inline auto chain(std::future<T>&& f) -> details::Chain<T> { - return std::move(f); +using SharedFuture = Future<T, std::shared_future>; + +// Deduction guide for implicit conversion. +template <typename T, template <typename> class FutureImpl> +Future(FutureImpl<T>&&) -> Future<T, FutureImpl>; + +// Creates a future that wraps a value. +// +// auto future = ftl::yield(42); +// assert(future.get() == 42); +// +// auto ptr = std::make_unique<char>('!'); +// auto future = ftl::yield(std::move(ptr)); +// assert(*future.get() == '!'); +// +template <typename V> +inline Future<V> yield(V&& value) { + return {details::ValueTag{}, std::move(value)}; +} + +template <typename V, typename... Args> +inline Future<V> yield(Args&&... args) { + return {details::ValueTag{}, std::forward<Args>(args)...}; +} + +// Creates a future that defers a function call until its result is queried. +// +// auto future = ftl::defer([](int x) { return x + 1; }, 99); +// assert(future.get() == 100); +// +template <typename F, typename... Args> +inline auto defer(F&& f, Args&&... args) { + return Future(std::async(std::launch::deferred, std::forward<F>(f), std::forward<Args>(args)...)); } } // namespace android::ftl diff --git a/include/ftl/initializer_list.h b/include/ftl/initializer_list.h index 769c09ff11..2102c253f1 100644 --- a/include/ftl/initializer_list.h +++ b/include/ftl/initializer_list.h @@ -16,6 +16,7 @@ #pragma once +#include <functional> #include <tuple> #include <utility> @@ -65,18 +66,18 @@ struct InitializerList<T, std::index_sequence<Sizes...>, Types...> { std::tuple<Types...> tuple; }; -template <typename K, typename V> +template <typename K, typename V, typename KeyEqual = std::equal_to<K>> struct KeyValue {}; // Shorthand for key-value pairs that assigns the first argument to the key, and the rest to the // value. The specialization is on KeyValue rather than std::pair, so that ftl::init::list works // with the latter. -template <typename K, typename V, std::size_t... Sizes, typename... Types> -struct InitializerList<KeyValue<K, V>, std::index_sequence<Sizes...>, Types...> { +template <typename K, typename V, typename E, std::size_t... Sizes, typename... Types> +struct InitializerList<KeyValue<K, V, E>, std::index_sequence<Sizes...>, Types...> { // Accumulate the three arguments to std::pair's piecewise constructor. template <typename... Args> [[nodiscard]] constexpr auto operator()(K&& k, Args&&... args) && -> InitializerList< - KeyValue<K, V>, std::index_sequence<Sizes..., 3>, Types..., std::piecewise_construct_t, + KeyValue<K, V, E>, std::index_sequence<Sizes..., 3>, Types..., std::piecewise_construct_t, std::tuple<K&&>, std::tuple<Args&&...>> { return {std::tuple_cat( std::move(tuple), @@ -94,9 +95,9 @@ template <typename T, typename... Args> return InitializerList<T>{}(std::forward<Args>(args)...); } -template <typename K, typename V, typename... Args> +template <typename K, typename V, typename E = std::equal_to<K>, typename... Args> [[nodiscard]] constexpr auto map(Args&&... args) { - return list<KeyValue<K, V>>(std::forward<Args>(args)...); + return list<KeyValue<K, V, E>>(std::forward<Args>(args)...); } template <typename K, typename V> diff --git a/include/ftl/small_map.h b/include/ftl/small_map.h index 84c15ebdca..5217e76064 100644 --- a/include/ftl/small_map.h +++ b/include/ftl/small_map.h @@ -19,6 +19,7 @@ #include <ftl/initializer_list.h> #include <ftl/small_vector.h> +#include <algorithm> #include <functional> #include <optional> #include <type_traits> @@ -28,7 +29,10 @@ namespace android::ftl { // Associative container with unique, unordered keys. Unlike std::unordered_map, key-value pairs are // stored in contiguous storage for cache efficiency. The map is allocated statically until its size -// exceeds N, at which point mappings are relocated to dynamic memory. +// exceeds N, at which point mappings are relocated to dynamic memory. The try_emplace operation has +// a non-standard analogue try_replace that destructively emplaces. The API also defines an in-place +// counterpart to insert_or_assign: emplace_or_replace. Lookup is done not via a subscript operator, +// but immutable getters that can optionally transform the value. // // SmallMap<K, V, 0> unconditionally allocates on the heap. // @@ -43,21 +47,27 @@ namespace android::ftl { // assert(!map.dynamic()); // // assert(map.contains(123)); -// assert(map.find(42, [](const std::string& s) { return s.size(); }) == 3u); +// assert(map.get(42, [](const std::string& s) { return s.size(); }) == 3u); // -// const auto opt = map.find(-1); +// const auto opt = map.get(-1); // assert(opt); // // std::string& ref = *opt; // assert(ref.empty()); // ref = "xyz"; // -// assert(map == SmallMap(ftl::init::map(-1, "xyz")(42, "???")(123, "abc"))); +// map.emplace_or_replace(0, "vanilla", 2u, 3u); +// assert(map.dynamic()); // -template <typename K, typename V, std::size_t N> +// assert(map == SmallMap(ftl::init::map(-1, "xyz")(0, "nil")(42, "???")(123, "abc"))); +// +template <typename K, typename V, std::size_t N, typename KeyEqual = std::equal_to<K>> class SmallMap final { using Map = SmallVector<std::pair<const K, V>, N>; + template <typename, typename, std::size_t, typename> + friend class SmallMap; + public: using key_type = K; using mapped_type = V; @@ -80,12 +90,7 @@ class SmallMap final { // The syntax for listing pairs is as follows: // // ftl::SmallMap map = ftl::init::map<int, std::string>(123, "abc")(-1)(42, 3u, '?'); - // // static_assert(std::is_same_v<decltype(map), ftl::SmallMap<int, std::string, 3>>); - // assert(map.size() == 3u); - // assert(map.contains(-1) && map.find(-1)->get().empty()); - // assert(map.contains(42) && map.find(42)->get() == "???"); - // assert(map.contains(123) && map.find(123)->get() == "abc"); // // The types of the key and value are deduced if the first pair contains exactly two arguments: // @@ -95,9 +100,13 @@ class SmallMap final { template <typename U, std::size_t... Sizes, typename... Types> SmallMap(InitializerList<U, std::index_sequence<Sizes...>, Types...>&& list) : map_(std::move(list)) { - // TODO: Enforce unique keys. + deduplicate(); } + // Copies or moves key-value pairs from a convertible map. + template <typename Q, typename W, std::size_t M, typename E> + SmallMap(SmallMap<Q, W, M, E> other) : map_(std::move(other.map_)) {} + size_type max_size() const { return map_.max_size(); } size_type size() const { return map_.size(); } bool empty() const { return map_.empty(); } @@ -115,27 +124,27 @@ class SmallMap final { // Returns whether a mapping exists for the given key. bool contains(const key_type& key) const { - return find(key, [](const mapped_type&) {}); + return get(key, [](const mapped_type&) {}); } // Returns a reference to the value for the given key, or std::nullopt if the key was not found. // // ftl::SmallMap map = ftl::init::map('a', 'A')('b', 'B')('c', 'C'); // - // const auto opt = map.find('c'); + // const auto opt = map.get('c'); // assert(opt == 'C'); // // char d = 'd'; - // const auto ref = map.find('d').value_or(std::ref(d)); + // const auto ref = map.get('d').value_or(std::ref(d)); // ref.get() = 'D'; // assert(d == 'D'); // - auto find(const key_type& key) const -> std::optional<std::reference_wrapper<const mapped_type>> { - return find(key, [](const mapped_type& v) { return std::cref(v); }); + auto get(const key_type& key) const -> std::optional<std::reference_wrapper<const mapped_type>> { + return get(key, [](const mapped_type& v) { return std::cref(v); }); } - auto find(const key_type& key) -> std::optional<std::reference_wrapper<mapped_type>> { - return find(key, [](mapped_type& v) { return std::ref(v); }); + auto get(const key_type& key) -> std::optional<std::reference_wrapper<mapped_type>> { + return get(key, [](mapped_type& v) { return std::ref(v); }); } // Returns the result R of a unary operation F on (a constant or mutable reference to) the value @@ -144,14 +153,14 @@ class SmallMap final { // // ftl::SmallMap map = ftl::init::map('a', 'x')('b', 'y')('c', 'z'); // - // assert(map.find('c', [](char c) { return std::toupper(c); }) == 'Z'); - // assert(map.find('c', [](char& c) { c = std::toupper(c); })); + // assert(map.get('c', [](char c) { return std::toupper(c); }) == 'Z'); + // assert(map.get('c', [](char& c) { c = std::toupper(c); })); // template <typename F, typename R = std::invoke_result_t<F, const mapped_type&>> - auto find(const key_type& key, F f) const + auto get(const key_type& key, F f) const -> std::conditional_t<std::is_void_v<R>, bool, std::optional<R>> { for (auto& [k, v] : *this) { - if (k == key) { + if (KeyEqual{}(k, key)) { if constexpr (std::is_void_v<R>) { f(v); return true; @@ -165,28 +174,119 @@ class SmallMap final { } template <typename F> - auto find(const key_type& key, F f) { - return std::as_const(*this).find( + auto get(const key_type& key, F f) { + return std::as_const(*this).get( key, [&f](const mapped_type& v) { return f(const_cast<mapped_type&>(v)); }); } + // Returns an iterator to an existing mapping for the given key, or the end() iterator otherwise. + const_iterator find(const key_type& key) const { return const_cast<SmallMap&>(*this).find(key); } + iterator find(const key_type& key) { return find(key, begin()); } + + // Inserts a mapping unless it exists. Returns an iterator to the inserted or existing mapping, + // and whether the mapping was inserted. + // + // On emplace, if the map reaches its static or dynamic capacity, then all iterators are + // invalidated. Otherwise, only the end() iterator is invalidated. + // + template <typename... Args> + std::pair<iterator, bool> try_emplace(const key_type& key, Args&&... args) { + if (const auto it = find(key); it != end()) { + return {it, false}; + } + + auto& ref = map_.emplace_back(std::piecewise_construct, std::forward_as_tuple(key), + std::forward_as_tuple(std::forward<Args>(args)...)); + return {&ref, true}; + } + + // Replaces a mapping if it exists, and returns an iterator to it. Returns the end() iterator + // otherwise. + // + // The value is replaced via move constructor, so type V does not need to define copy/move + // assignment, e.g. its data members may be const. + // + // The arguments may directly or indirectly refer to the mapping being replaced. + // + // Iterators to the replaced mapping point to its replacement, and others remain valid. + // + template <typename... Args> + iterator try_replace(const key_type& key, Args&&... args) { + const auto it = find(key); + if (it == end()) return it; + map_.replace(it, std::piecewise_construct, std::forward_as_tuple(key), + std::forward_as_tuple(std::forward<Args>(args)...)); + return it; + } + + // In-place counterpart of std::unordered_map's insert_or_assign. Returns true on emplace, or + // false on replace. + // + // The value is emplaced and replaced via move constructor, so type V does not need to define + // copy/move assignment, e.g. its data members may be const. + // + // On emplace, if the map reaches its static or dynamic capacity, then all iterators are + // invalidated. Otherwise, only the end() iterator is invalidated. On replace, iterators + // to the replaced mapping point to its replacement, and others remain valid. + // + template <typename... Args> + std::pair<iterator, bool> emplace_or_replace(const key_type& key, Args&&... args) { + const auto [it, ok] = try_emplace(key, std::forward<Args>(args)...); + if (ok) return {it, ok}; + map_.replace(it, std::piecewise_construct, std::forward_as_tuple(key), + std::forward_as_tuple(std::forward<Args>(args)...)); + return {it, ok}; + } + + // Removes a mapping if it exists, and returns whether it did. + // + // The last() and end() iterators, as well as those to the erased mapping, are invalidated. + // + bool erase(const key_type& key) { return erase(key, begin()); } + + // Removes all mappings. + // + // All iterators are invalidated. + // + void clear() { map_.clear(); } + private: + iterator find(const key_type& key, iterator first) { + return std::find_if(first, end(), + [&key](const auto& pair) { return KeyEqual{}(pair.first, key); }); + } + + bool erase(const key_type& key, iterator first) { + const auto it = find(key, first); + if (it == end()) return false; + map_.unstable_erase(it); + return true; + } + + void deduplicate() { + for (auto it = begin(); it != end();) { + if (const auto key = it->first; ++it != end()) { + while (erase(key, it)); + } + } + } + Map map_; }; // Deduction guide for in-place constructor. -template <typename K, typename V, std::size_t... Sizes, typename... Types> -SmallMap(InitializerList<KeyValue<K, V>, std::index_sequence<Sizes...>, Types...>&&) - -> SmallMap<K, V, sizeof...(Sizes)>; +template <typename K, typename V, typename E, std::size_t... Sizes, typename... Types> +SmallMap(InitializerList<KeyValue<K, V, E>, std::index_sequence<Sizes...>, Types...>&&) + -> SmallMap<K, V, sizeof...(Sizes), E>; // Returns whether the key-value pairs of two maps are equal. -template <typename K, typename V, std::size_t N, typename Q, typename W, std::size_t M> -bool operator==(const SmallMap<K, V, N>& lhs, const SmallMap<Q, W, M>& rhs) { +template <typename K, typename V, std::size_t N, typename Q, typename W, std::size_t M, typename E> +bool operator==(const SmallMap<K, V, N, E>& lhs, const SmallMap<Q, W, M, E>& rhs) { if (lhs.size() != rhs.size()) return false; for (const auto& [k, v] : lhs) { const auto& lv = v; - if (!rhs.find(k, [&lv](const auto& rv) { return lv == rv; }).value_or(false)) { + if (!rhs.get(k, [&lv](const auto& rv) { return lv == rv; }).value_or(false)) { return false; } } @@ -195,8 +295,8 @@ bool operator==(const SmallMap<K, V, N>& lhs, const SmallMap<Q, W, M>& rhs) { } // TODO: Remove in C++20. -template <typename K, typename V, std::size_t N, typename Q, typename W, std::size_t M> -inline bool operator!=(const SmallMap<K, V, N>& lhs, const SmallMap<Q, W, M>& rhs) { +template <typename K, typename V, std::size_t N, typename Q, typename W, std::size_t M, typename E> +inline bool operator!=(const SmallMap<K, V, N, E>& lhs, const SmallMap<Q, W, M, E>& rhs) { return !(lhs == rhs); } diff --git a/include/ftl/small_vector.h b/include/ftl/small_vector.h index cb0ae359eb..339726e4ea 100644 --- a/include/ftl/small_vector.h +++ b/include/ftl/small_vector.h @@ -16,7 +16,7 @@ #pragma once -#include <ftl/array_traits.h> +#include <ftl/details/array_traits.h> #include <ftl/static_vector.h> #include <algorithm> @@ -37,6 +37,9 @@ struct is_small_vector; // augmented by an unstable_erase operation that does not preserve order, and a replace operation // that destructively emplaces. // +// Unlike std::vector, T does not require copy/move assignment, so may be an object with const data +// members, or be const itself. +// // SmallVector<T, 0> is a specialization that thinly wraps std::vector. // // Example usage: @@ -73,7 +76,7 @@ struct is_small_vector; // assert(strings[2] == "???"); // template <typename T, std::size_t N> -class SmallVector final : ArrayTraits<T>, ArrayComparators<SmallVector> { +class SmallVector final : details::ArrayTraits<T>, details::ArrayComparators<SmallVector> { using Static = StaticVector<T, N>; using Dynamic = SmallVector<T, 0>; @@ -105,10 +108,9 @@ class SmallVector final : ArrayTraits<T>, ArrayComparators<SmallVector> { SmallVector(Arg&& arg, Args&&... args) : vector_(std::in_place_type<Static>, std::forward<Arg>(arg), std::forward<Args>(args)...) {} - // Copies at most N elements from a smaller convertible vector. - template <typename U, std::size_t M, typename = std::enable_if_t<M <= N>> - SmallVector(const SmallVector<U, M>& other) - : SmallVector(kIteratorRange, other.begin(), other.end()) {} + // Copies or moves elements from a smaller convertible vector. + template <typename U, std::size_t M, typename = std::enable_if_t<(M > 0)>> + SmallVector(SmallVector<U, M> other) : vector_(convert(std::move(other))) {} void swap(SmallVector& other) { vector_.swap(other.vector_); } @@ -151,8 +153,6 @@ class SmallVector final : ArrayTraits<T>, ArrayComparators<SmallVector> { DISPATCH(reference, back, noexcept) DISPATCH(const_reference, back, const) -#undef DISPATCH - reference operator[](size_type i) { return dynamic() ? std::get<Dynamic>(vector_)[i] : std::get<Static>(vector_)[i]; } @@ -214,13 +214,15 @@ class SmallVector final : ArrayTraits<T>, ArrayComparators<SmallVector> { // // The last() and end() iterators are invalidated. // - void pop_back() { - if (dynamic()) { - std::get<Dynamic>(vector_).pop_back(); - } else { - std::get<Static>(vector_).pop_back(); - } - } + DISPATCH(void, pop_back, noexcept) + + // Removes all elements. + // + // All iterators are invalidated. + // + DISPATCH(void, clear, noexcept) + +#undef DISPATCH // Erases an element, but does not preserve order. Rather than shifting subsequent elements, // this moves the last element to the slot of the erased element. @@ -235,7 +237,30 @@ class SmallVector final : ArrayTraits<T>, ArrayComparators<SmallVector> { } } + // Extracts the elements as std::vector. + std::vector<T> promote() && { + if (dynamic()) { + return std::get<Dynamic>(std::move(vector_)).promote(); + } else { + return {std::make_move_iterator(begin()), std::make_move_iterator(end())}; + } + } + private: + template <typename, std::size_t> + friend class SmallVector; + + template <typename U, std::size_t M> + static std::variant<Static, Dynamic> convert(SmallVector<U, M>&& other) { + using Other = SmallVector<U, M>; + + if (other.dynamic()) { + return std::get<typename Other::Dynamic>(std::move(other.vector_)); + } else { + return std::get<typename Other::Static>(std::move(other.vector_)); + } + } + template <auto InsertStatic, auto InsertDynamic, typename... Args> auto insert(Args&&... args) { if (Dynamic* const vector = std::get_if<Dynamic>(&vector_)) { @@ -266,12 +291,13 @@ class SmallVector final : ArrayTraits<T>, ArrayComparators<SmallVector> { // Partial specialization without static storage. template <typename T> -class SmallVector<T, 0> final : ArrayTraits<T>, - ArrayIterators<SmallVector<T, 0>, T>, +class SmallVector<T, 0> final : details::ArrayTraits<T>, + details::ArrayComparators<SmallVector>, + details::ArrayIterators<SmallVector<T, 0>, T>, std::vector<T> { - using ArrayTraits<T>::construct_at; + using details::ArrayTraits<T>::replace_at; - using Iter = ArrayIterators<SmallVector, T>; + using Iter = details::ArrayIterators<SmallVector, T>; using Impl = std::vector<T>; friend Iter; @@ -291,8 +317,30 @@ class SmallVector<T, 0> final : ArrayTraits<T>, FTL_ARRAY_TRAIT(T, const_iterator); FTL_ARRAY_TRAIT(T, const_reverse_iterator); + // See std::vector for underlying constructors. using Impl::Impl; + // Copies and moves a vector, respectively. + SmallVector(const SmallVector&) = default; + SmallVector(SmallVector&&) = default; + + // Constructs elements in place. See StaticVector for underlying constructor. + template <typename U, std::size_t... Sizes, typename... Types> + SmallVector(InitializerList<U, std::index_sequence<Sizes...>, Types...>&& list) + : SmallVector(SmallVector<T, sizeof...(Sizes)>(std::move(list))) {} + + // Copies or moves elements from a convertible vector. + template <typename U, std::size_t M> + SmallVector(SmallVector<U, M> other) : Impl(convert(std::move(other))) {} + + SmallVector& operator=(SmallVector other) { + // Define copy/move assignment in terms of copy/move construction. + swap(other); + return *this; + } + + void swap(SmallVector& other) { Impl::swap(other); } + using Impl::empty; using Impl::max_size; using Impl::size; @@ -324,10 +372,7 @@ class SmallVector<T, 0> final : ArrayTraits<T>, template <typename... Args> reference replace(const_iterator it, Args&&... args) { - value_type element{std::forward<Args>(args)...}; - std::destroy_at(it); - // This is only safe because exceptions are disabled. - return *construct_at(it, std::move(element)); + return replace_at(it, std::forward<Args>(args)...); } template <typename... Args> @@ -345,14 +390,34 @@ class SmallVector<T, 0> final : ArrayTraits<T>, return true; } + using Impl::clear; using Impl::pop_back; void unstable_erase(iterator it) { - if (it != last()) std::iter_swap(it, last()); + if (it != last()) replace(it, std::move(back())); pop_back(); } - void swap(SmallVector& other) { Impl::swap(other); } + std::vector<T> promote() && { return std::move(*this); } + + private: + template <typename U, std::size_t M> + static Impl convert(SmallVector<U, M>&& other) { + if constexpr (std::is_constructible_v<Impl, std::vector<U>&&>) { + return std::move(other).promote(); + } else { + SmallVector vector(other.size()); + + // Consistently with StaticVector, T only requires copy/move construction from U, rather than + // copy/move assignment. + auto it = vector.begin(); + for (auto& element : other) { + vector.replace(it++, std::move(element)); + } + + return vector; + } + } }; template <typename> diff --git a/include/ftl/static_vector.h b/include/ftl/static_vector.h index 96a1ae853d..eb83b85bfe 100644 --- a/include/ftl/static_vector.h +++ b/include/ftl/static_vector.h @@ -16,7 +16,7 @@ #pragma once -#include <ftl/array_traits.h> +#include <ftl/details/array_traits.h> #include <ftl/initializer_list.h> #include <algorithm> @@ -39,6 +39,9 @@ constexpr struct IteratorRangeTag { // adheres to standard containers, except the unstable_erase operation that does not preserve order, // and the replace operation that destructively emplaces. // +// Unlike std::vector, T does not require copy/move assignment, so may be an object with const data +// members, or be const itself. +// // StaticVector<T, 1> is analogous to an iterable std::optional. // StaticVector<T, 0> is an error. // @@ -73,14 +76,21 @@ constexpr struct IteratorRangeTag { // assert(strings[2] == "???"); // template <typename T, std::size_t N> -class StaticVector final : ArrayTraits<T>, - ArrayIterators<StaticVector<T, N>, T>, - ArrayComparators<StaticVector> { +class StaticVector final : details::ArrayTraits<T>, + details::ArrayIterators<StaticVector<T, N>, T>, + details::ArrayComparators<StaticVector> { static_assert(N > 0); - using ArrayTraits<T>::construct_at; + // For constructor that moves from a smaller convertible vector. + template <typename, std::size_t> + friend class StaticVector; + + using details::ArrayTraits<T>::construct_at; + using details::ArrayTraits<T>::replace_at; + using details::ArrayTraits<T>::in_place_swap_ranges; + using details::ArrayTraits<T>::uninitialized_copy; - using Iter = ArrayIterators<StaticVector, T>; + using Iter = details::ArrayIterators<StaticVector, T>; friend Iter; // There is ambiguity when constructing from two iterator-like elements like pointers: @@ -117,14 +127,18 @@ class StaticVector final : ArrayTraits<T>, StaticVector(StaticVector&& other) { swap<true>(other); } // Copies at most N elements from a smaller convertible vector. - template <typename U, std::size_t M, typename = std::enable_if_t<M <= N>> + template <typename U, std::size_t M> StaticVector(const StaticVector<U, M>& other) - : StaticVector(kIteratorRange, other.begin(), other.end()) {} + : StaticVector(kIteratorRange, other.begin(), other.end()) { + static_assert(N >= M, "Insufficient capacity"); + } - // Copies at most N elements from an array. + // Copies at most N elements from a smaller convertible array. template <typename U, std::size_t M> explicit StaticVector(U (&array)[M]) - : StaticVector(kIteratorRange, std::begin(array), std::end(array)) {} + : StaticVector(kIteratorRange, std::begin(array), std::end(array)) { + static_assert(N >= M, "Insufficient capacity"); + } // Copies at most N elements from the range [first, last). // @@ -139,7 +153,18 @@ class StaticVector final : ArrayTraits<T>, template <typename Iterator> StaticVector(IteratorRangeTag, Iterator first, Iterator last) : size_(std::min(max_size(), static_cast<size_type>(std::distance(first, last)))) { - std::uninitialized_copy(first, first + size_, begin()); + uninitialized_copy(first, first + size_, begin()); + } + + // Moves at most N elements from a smaller convertible vector. + template <typename U, std::size_t M> + StaticVector(StaticVector<U, M>&& other) { + static_assert(N >= M, "Insufficient capacity"); + + // Same logic as swap<true>, though M need not be equal to N. + std::uninitialized_move(other.begin(), other.end(), begin()); + std::destroy(other.begin(), other.end()); + std::swap(size_, other.size_); } // Constructs at most N elements. The template arguments T and N are inferred using the @@ -178,7 +203,9 @@ class StaticVector final : ArrayTraits<T>, template <typename U, std::size_t Size, std::size_t... Sizes, typename... Types> StaticVector(InitializerList<U, std::index_sequence<Size, Sizes...>, Types...>&& list) : StaticVector(std::index_sequence<0, 0, Size>{}, std::make_index_sequence<Size>{}, - std::index_sequence<Sizes...>{}, list.tuple) {} + std::index_sequence<Sizes...>{}, list.tuple) { + static_assert(sizeof...(Sizes) < N, "Too many elements"); + } ~StaticVector() { std::destroy(begin(), end()); } @@ -189,8 +216,7 @@ class StaticVector final : ArrayTraits<T>, } StaticVector& operator=(StaticVector&& other) { - std::destroy(begin(), end()); - size_ = 0; + clear(); swap<true>(other); return *this; } @@ -239,10 +265,7 @@ class StaticVector final : ArrayTraits<T>, // template <typename... Args> reference replace(const_iterator it, Args&&... args) { - value_type element{std::forward<Args>(args)...}; - std::destroy_at(it); - // This is only safe because exceptions are disabled. - return *construct_at(it, std::move(element)); + return replace_at(it, std::forward<Args>(args)...); } // Appends an element, and returns an iterator to it. If the vector is full, the element is not @@ -280,6 +303,15 @@ class StaticVector final : ArrayTraits<T>, // void pop_back() { unstable_erase(last()); } + // Removes all elements. + // + // All iterators are invalidated. + // + void clear() { + std::destroy(begin(), end()); + size_ = 0; + } + // Erases an element, but does not preserve order. Rather than shifting subsequent elements, // this moves the last element to the slot of the erased element. // @@ -372,7 +404,7 @@ void StaticVector<T, N>::swap(StaticVector& other) { } // Swap elements [0, min). - std::swap_ranges(begin(), begin() + min, other.begin()); + in_place_swap_ranges(begin(), begin() + min, other.begin()); // No elements to move if sizes are equal. if (min == max) return; diff --git a/include/ftl/string.h b/include/ftl/string.h new file mode 100644 index 0000000000..2d96b06a2f --- /dev/null +++ b/include/ftl/string.h @@ -0,0 +1,101 @@ +/* + * Copyright 2021 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 <cassert> +#include <charconv> +#include <limits> +#include <string> +#include <string_view> +#include <type_traits> + +namespace android::ftl { + +enum class Radix { kBin = 2, kDec = 10, kHex = 16 }; + +template <typename T> +struct to_chars_length { + static_assert(std::is_integral_v<T>); + // Maximum binary digits, plus minus sign and radix prefix. + static constexpr std::size_t value = std::numeric_limits<std::make_unsigned_t<T>>::digits + 3; +}; + +template <typename T> +constexpr std::size_t to_chars_length_v = to_chars_length<T>::value; + +template <typename T = std::int64_t> +using to_chars_buffer_t = char[to_chars_length_v<T>]; + +// Lightweight (not allocating nor sprintf-based) alternative to std::to_string for integers, with +// optional radix. See also ftl::to_string below. +// +// ftl::to_chars_buffer_t<> buffer; +// +// assert(ftl::to_chars(buffer, 123u) == "123"); +// assert(ftl::to_chars(buffer, -42, ftl::Radix::kBin) == "-0b101010"); +// assert(ftl::to_chars(buffer, 0xcafe, ftl::Radix::kHex) == "0xcafe"); +// assert(ftl::to_chars(buffer, '*', ftl::Radix::kHex) == "0x2a"); +// +template <typename T, std::size_t N> +std::string_view to_chars(char (&buffer)[N], T v, Radix radix = Radix::kDec) { + static_assert(N >= to_chars_length_v<T>); + + auto begin = buffer + 2; + const auto [end, err] = std::to_chars(begin, buffer + N, v, static_cast<int>(radix)); + assert(err == std::errc()); + + if (radix == Radix::kDec) { + // TODO: Replace with {begin, end} in C++20. + return {begin, static_cast<std::size_t>(end - begin)}; + } + + const auto prefix = radix == Radix::kBin ? 'b' : 'x'; + if constexpr (std::is_unsigned_v<T>) { + buffer[0] = '0'; + buffer[1] = prefix; + } else { + if (*begin == '-') { + *buffer = '-'; + } else { + --begin; + } + + *begin-- = prefix; + *begin = '0'; + } + + // TODO: Replace with {buffer, end} in C++20. + return {buffer, static_cast<std::size_t>(end - buffer)}; +} + +// Lightweight (not sprintf-based) alternative to std::to_string for integers, with optional radix. +// +// assert(ftl::to_string(123u) == "123"); +// assert(ftl::to_string(-42, ftl::Radix::kBin) == "-0b101010"); +// assert(ftl::to_string(0xcafe, ftl::Radix::kHex) == "0xcafe"); +// assert(ftl::to_string('*', ftl::Radix::kHex) == "0x2a"); +// +template <typename T> +inline std::string to_string(T v, Radix radix = Radix::kDec) { + to_chars_buffer_t<T> buffer; + return std::string(to_chars(buffer, v, radix)); +} + +std::string to_string(bool) = delete; +std::string to_string(bool, Radix) = delete; + +} // namespace android::ftl diff --git a/include/input/DisplayViewport.h b/include/input/DisplayViewport.h index 5e40ca7ece..9148fee532 100644 --- a/include/input/DisplayViewport.h +++ b/include/input/DisplayViewport.h @@ -18,8 +18,10 @@ #define _LIBINPUT_DISPLAY_VIEWPORT_H #include <android-base/stringprintf.h> +#include <ftl/enum.h> +#include <ftl/string.h> +#include <gui/constants.h> #include <input/Input.h> -#include <input/NamedEnum.h> #include <cinttypes> #include <optional> @@ -43,6 +45,8 @@ enum class ViewportType : int32_t { INTERNAL = 1, EXTERNAL = 2, VIRTUAL = 3, + + ftl_last = VIRTUAL }; /* @@ -131,9 +135,8 @@ struct DisplayViewport { "physicalFrame=[%d, %d, %d, %d], " "deviceSize=[%d, %d], " "isActive=[%d]", - NamedEnum::string(type).c_str(), displayId, uniqueId.c_str(), - physicalPort ? StringPrintf("%" PRIu8, *physicalPort).c_str() - : "<none>", + ftl::enum_string(type).c_str(), displayId, uniqueId.c_str(), + physicalPort ? ftl::to_string(*physicalPort).c_str() : "<none>", orientation, logicalLeft, logicalTop, logicalRight, logicalBottom, physicalLeft, physicalTop, physicalRight, physicalBottom, deviceWidth, deviceHeight, isActive); diff --git a/include/input/Input.h b/include/input/Input.h index 2e326cb102..e7d68fc349 100644 --- a/include/input/Input.h +++ b/include/input/Input.h @@ -31,10 +31,8 @@ #include <stdint.h> #include <ui/Transform.h> #include <utils/BitSet.h> -#include <utils/KeyedVector.h> #include <utils/RefBase.h> #include <utils/Timers.h> -#include <utils/Vector.h> #include <array> #include <limits> #include <queue> @@ -88,7 +86,7 @@ enum { */ AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE = 0x40, -#ifdef __linux__ +#if defined(__linux__) /** * This event was generated or modified by accessibility service. */ @@ -124,15 +122,6 @@ constexpr int32_t VERIFIED_MOTION_EVENT_FLAGS = AMOTION_EVENT_FLAG_WINDOW_IS_OBS constexpr int32_t AMOTION_EVENT_FLAG_CANCELED = 0x20; enum { - /* Used when a motion event is not associated with any display. - * Typically used for non-pointer events. */ - ADISPLAY_ID_NONE = -1, - - /* The default display id. */ - ADISPLAY_ID_DEFAULT = 0, -}; - -enum { /* * Indicates that an input device has switches. * This input source flag is hidden from the API because switches are only used by the system @@ -175,7 +164,7 @@ enum { * (We want at least 10 but some touch controllers obstensibly configured for 10 pointers * will occasionally emit 11. There is not much harm making this constant bigger.) */ -#define MAX_POINTERS 16 +static constexpr size_t MAX_POINTERS = 16; /* * Maximum number of samples supported per motion event. @@ -210,8 +199,17 @@ namespace android { class Parcel; #endif +/* + * Apply the given transform to the point without applying any translation/offset. + */ +vec2 transformWithoutTranslation(const ui::Transform& transform, const vec2& xy); + const char* inputEventTypeToString(int32_t type); +std::string inputEventSourceToString(int32_t source); + +bool isFromSource(uint32_t source, uint32_t test); + /* * Flags that flow alongside events in the input dispatch system to help with certain * policy decisions such as waking from device sleep. @@ -277,23 +275,21 @@ enum { /** * Classifications of the current gesture, if available. - * - * The following values must be kept in sync with MotionEvent.java */ enum class MotionClassification : uint8_t { /** * No classification is available. */ - NONE = 0, + NONE = AMOTION_EVENT_CLASSIFICATION_NONE, /** * Too early to classify the current gesture. Need more events. Look for changes in the * upcoming motion events. */ - AMBIGUOUS_GESTURE = 1, + AMBIGUOUS_GESTURE = AMOTION_EVENT_CLASSIFICATION_AMBIGUOUS_GESTURE, /** * The current gesture likely represents a user intentionally exerting force on the touchscreen. */ - DEEP_PRESS = 2, + DEEP_PRESS = AMOTION_EVENT_CLASSIFICATION_DEEP_PRESS, }; /** @@ -354,12 +350,6 @@ private: */ constexpr float AMOTION_EVENT_INVALID_CURSOR_POSITION = std::numeric_limits<float>::quiet_NaN(); -/** - * Invalid value for display size. Used when display size isn't available for an event or doesn't - * matter. This is just a constant 0 so that it has no effect if unused. - */ -constexpr int32_t AMOTION_EVENT_INVALID_DISPLAY_SIZE = 0; - /* * Pointer coordinate data. */ @@ -384,13 +374,10 @@ struct PointerCoords { float getAxisValue(int32_t axis) const; status_t setAxisValue(int32_t axis, float value); - void scale(float globalScale); - // Scale the pointer coordinates according to a global scale and a // window scale. The global scale will be applied to TOUCH/TOOL_MAJOR/MINOR // axes, however the window scaling will not. void scale(float globalScale, float windowXScale, float windowYScale); - void applyOffset(float xOffset, float yOffset); void transform(const ui::Transform& transform); @@ -541,13 +528,17 @@ public: inline int32_t getAction() const { return mAction; } - inline int32_t getActionMasked() const { return mAction & AMOTION_EVENT_ACTION_MASK; } + static int32_t getActionMasked(int32_t action) { return action & AMOTION_EVENT_ACTION_MASK; } + + inline int32_t getActionMasked() const { return getActionMasked(mAction); } - inline int32_t getActionIndex() const { - return (mAction & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) - >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; + static uint8_t getActionIndex(int32_t action) { + return (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> + AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; } + inline int32_t getActionIndex() const { return getActionIndex(mAction); } + inline void setAction(int32_t action) { mAction = action; } inline int32_t getFlags() const { return mFlags; } @@ -576,7 +567,9 @@ public: inline float getYOffset() const { return mTransform.ty(); } - inline ui::Transform getTransform() const { return mTransform; } + inline const ui::Transform& getTransform() const { return mTransform; } + + int getSurfaceRotation() const; inline float getXPrecision() const { return mXPrecision; } @@ -592,7 +585,7 @@ public: void setCursorPosition(float x, float y); - int2 getDisplaySize() const { return {mDisplayWidth, mDisplayHeight}; } + inline const ui::Transform& getRawTransform() const { return mRawTransform; } static inline bool isValidCursorPosition(float x, float y) { return !isnan(x) && !isnan(y); } @@ -768,8 +761,8 @@ public: int32_t flags, int32_t edgeFlags, int32_t metaState, int32_t buttonState, MotionClassification classification, const ui::Transform& transform, float xPrecision, float yPrecision, float rawXCursorPosition, - float rawYCursorPosition, int32_t displayWidth, int32_t displayHeight, - nsecs_t downTime, nsecs_t eventTime, size_t pointerCount, + float rawYCursorPosition, const ui::Transform& rawTransform, nsecs_t downTime, + nsecs_t eventTime, size_t pointerCount, const PointerProperties* pointerProperties, const PointerCoords* pointerCoords); void copyFrom(const MotionEvent* other, bool keepHistory); @@ -802,11 +795,11 @@ public: // Low-level accessors. inline const PointerProperties* getPointerProperties() const { - return mPointerProperties.array(); + return mPointerProperties.data(); } inline const nsecs_t* getSampleEventTimes() const { return mSampleEventTimes.data(); } inline const PointerCoords* getSamplePointerCoords() const { - return mSamplePointerCoords.array(); + return mSamplePointerCoords.data(); } static const char* getLabel(int32_t axis); @@ -814,6 +807,16 @@ public: static std::string actionToString(int32_t action); + // MotionEvent will transform various axes in different ways, based on the source. For + // example, the x and y axes will not have any offsets/translations applied if it comes from a + // relative mouse device (since SOURCE_RELATIVE_MOUSE is a non-pointer source). These methods + // are used to apply these transformations for different axes. + static vec2 calculateTransformedXY(uint32_t source, const ui::Transform&, const vec2& xy); + static float calculateTransformedAxisValue(int32_t axis, uint32_t source, const ui::Transform&, + const PointerCoords&); + static PointerCoords calculateTransformedCoords(uint32_t source, const ui::Transform&, + const PointerCoords&); + protected: int32_t mAction; int32_t mActionButton; @@ -827,14 +830,15 @@ protected: float mYPrecision; float mRawXCursorPosition; float mRawYCursorPosition; - int32_t mDisplayWidth; - int32_t mDisplayHeight; + ui::Transform mRawTransform; nsecs_t mDownTime; - Vector<PointerProperties> mPointerProperties; + std::vector<PointerProperties> mPointerProperties; std::vector<nsecs_t> mSampleEventTimes; - Vector<PointerCoords> mSamplePointerCoords; + std::vector<PointerCoords> mSamplePointerCoords; }; +std::ostream& operator<<(std::ostream& out, const MotionEvent& event); + /* * Focus events. */ @@ -846,15 +850,12 @@ public: inline bool getHasFocus() const { return mHasFocus; } - inline bool getInTouchMode() const { return mInTouchMode; } - - void initialize(int32_t id, bool hasFocus, bool inTouchMode); + void initialize(int32_t id, bool hasFocus); void initialize(const FocusEvent& from); protected: bool mHasFocus; - bool mInTouchMode; }; /* @@ -900,6 +901,25 @@ protected: float mX, mY; }; +/* + * Touch mode events. + */ +class TouchModeEvent : public InputEvent { +public: + virtual ~TouchModeEvent() {} + + virtual int32_t getType() const override { return AINPUT_EVENT_TYPE_TOUCH_MODE; } + + inline bool isInTouchMode() const { return mIsInTouchMode; } + + void initialize(int32_t id, bool isInTouchMode); + + void initialize(const TouchModeEvent& from); + +protected: + bool mIsInTouchMode; +}; + /** * Base class for verified events. * Do not create a VerifiedInputEvent explicitly. @@ -924,8 +944,8 @@ struct __attribute__((__packed__)) VerifiedInputEvent { */ struct __attribute__((__packed__)) VerifiedKeyEvent : public VerifiedInputEvent { int32_t action; - nsecs_t downTimeNanos; int32_t flags; + nsecs_t downTimeNanos; int32_t keyCode; int32_t scanCode; int32_t metaState; @@ -940,8 +960,8 @@ struct __attribute__((__packed__)) VerifiedMotionEvent : public VerifiedInputEve float rawX; float rawY; int32_t actionMasked; - nsecs_t downTimeNanos; int32_t flags; + nsecs_t downTimeNanos; int32_t metaState; int32_t buttonState; }; @@ -964,6 +984,7 @@ public: virtual FocusEvent* createFocusEvent() = 0; virtual CaptureEvent* createCaptureEvent() = 0; virtual DragEvent* createDragEvent() = 0; + virtual TouchModeEvent* createTouchModeEvent() = 0; }; /* @@ -980,6 +1001,7 @@ public: virtual FocusEvent* createFocusEvent() override { return &mFocusEvent; } virtual CaptureEvent* createCaptureEvent() override { return &mCaptureEvent; } virtual DragEvent* createDragEvent() override { return &mDragEvent; } + virtual TouchModeEvent* createTouchModeEvent() override { return &mTouchModeEvent; } private: KeyEvent mKeyEvent; @@ -987,6 +1009,7 @@ private: FocusEvent mFocusEvent; CaptureEvent mCaptureEvent; DragEvent mDragEvent; + TouchModeEvent mTouchModeEvent; }; /* @@ -1002,6 +1025,7 @@ public: virtual FocusEvent* createFocusEvent() override; virtual CaptureEvent* createCaptureEvent() override; virtual DragEvent* createDragEvent() override; + virtual TouchModeEvent* createTouchModeEvent() override; void recycle(InputEvent* event); @@ -1013,6 +1037,26 @@ private: std::queue<std::unique_ptr<FocusEvent>> mFocusEventPool; std::queue<std::unique_ptr<CaptureEvent>> mCaptureEventPool; std::queue<std::unique_ptr<DragEvent>> mDragEventPool; + std::queue<std::unique_ptr<TouchModeEvent>> mTouchModeEventPool; +}; + +/* + * Describes a unique request to enable or disable Pointer Capture. + */ +struct PointerCaptureRequest { +public: + inline PointerCaptureRequest() : enable(false), seq(0) {} + inline PointerCaptureRequest(bool enable, uint32_t seq) : enable(enable), seq(seq) {} + inline bool operator==(const PointerCaptureRequest& other) const { + return enable == other.enable && seq == other.seq; + } + explicit inline operator bool() const { return enable; } + + // True iff this is a request to enable Pointer Capture. + bool enable; + + // The sequence number for the request. + uint32_t seq; }; } // namespace android diff --git a/include/input/InputApplication.h b/include/input/InputApplication.h deleted file mode 100644 index 8e4fe796a5..0000000000 --- a/include/input/InputApplication.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (C) 2011 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. - */ - -#ifndef _UI_INPUT_APPLICATION_H -#define _UI_INPUT_APPLICATION_H - -#include <string> - -#include <android/InputApplicationInfo.h> - -#include <binder/IBinder.h> -#include <binder/Parcel.h> -#include <binder/Parcelable.h> - -#include <input/Input.h> -#include <utils/RefBase.h> -#include <utils/Timers.h> - -namespace android { -/* - * Handle for an application that can receive input. - * - * Used by the native input dispatcher as a handle for the window manager objects - * that describe an application. - */ -class InputApplicationHandle { -public: - inline const InputApplicationInfo* getInfo() const { - return &mInfo; - } - - inline std::string getName() const { - return !mInfo.name.empty() ? mInfo.name : "<invalid>"; - } - - inline std::chrono::nanoseconds getDispatchingTimeout( - std::chrono::nanoseconds defaultValue) const { - return mInfo.token ? std::chrono::milliseconds(mInfo.dispatchingTimeoutMillis) - : defaultValue; - } - - inline sp<IBinder> getApplicationToken() const { - return mInfo.token; - } - - bool operator==(const InputApplicationHandle& other) const { - return getName() == other.getName() && getApplicationToken() == other.getApplicationToken(); - } - - bool operator!=(const InputApplicationHandle& other) const { return !(*this == other); } - - /** - * Requests that the state of this object be updated to reflect - * the most current available information about the application. - * - * This method should only be called from within the input dispatcher's - * critical section. - * - * Returns true on success, or false if the handle is no longer valid. - */ - virtual bool updateInfo() = 0; - -protected: - InputApplicationHandle() = default; - virtual ~InputApplicationHandle() = default; - - InputApplicationInfo mInfo; -}; - -} // namespace android - -#endif // _UI_INPUT_APPLICATION_H diff --git a/include/input/InputDevice.h b/include/input/InputDevice.h index 7f0324a4a8..c4f03c9119 100644 --- a/include/input/InputDevice.h +++ b/include/input/InputDevice.h @@ -84,6 +84,9 @@ enum class InputDeviceSensorType : int32_t { GAME_ROTATION_VECTOR = ASENSOR_TYPE_GAME_ROTATION_VECTOR, GYROSCOPE_UNCALIBRATED = ASENSOR_TYPE_GYROSCOPE_UNCALIBRATED, SIGNIFICANT_MOTION = ASENSOR_TYPE_SIGNIFICANT_MOTION, + + ftl_first = ACCELEROMETER, + ftl_last = SIGNIFICANT_MOTION }; enum class InputDeviceSensorAccuracy : int32_t { @@ -105,6 +108,8 @@ enum class InputDeviceLightType : int32_t { PLAYER_ID = 1, RGB = 2, MULTI_COLOR = 3, + + ftl_last = MULTI_COLOR }; struct InputDeviceSensorInfo { @@ -230,7 +235,7 @@ public: void addBatteryInfo(const InputDeviceBatteryInfo& info); void addLightInfo(const InputDeviceLightInfo& info); - inline void setKeyboardType(int32_t keyboardType) { mKeyboardType = keyboardType; } + void setKeyboardType(int32_t keyboardType); inline int32_t getKeyboardType() const { return mKeyboardType; } inline void setKeyCharacterMap(const std::shared_ptr<KeyCharacterMap> value) { diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h index 360dfbfd73..5f9a37d69c 100644 --- a/include/input/InputTransport.h +++ b/include/input/InputTransport.h @@ -72,6 +72,9 @@ struct InputMessage { CAPTURE, DRAG, TIMELINE, + TOUCH_MODE, + + ftl_last = TOUCH_MODE }; struct Header { @@ -111,7 +114,7 @@ struct InputMessage { struct Motion { int32_t eventId; - uint32_t empty1; + uint32_t pointerCount; nsecs_t eventTime __attribute__((aligned(8))); int32_t deviceId; int32_t source; @@ -126,20 +129,22 @@ struct InputMessage { uint8_t empty2[3]; // 3 bytes to fill gap created by classification int32_t edgeFlags; nsecs_t downTime __attribute__((aligned(8))); - float dsdx; - float dtdx; - float dtdy; - float dsdy; - float tx; - float ty; + float dsdx; // Begin window transform + float dtdx; // + float dtdy; // + float dsdy; // + float tx; // + float ty; // End window transform float xPrecision; float yPrecision; float xCursorPosition; float yCursorPosition; - int32_t displayWidth; - int32_t displayHeight; - uint32_t pointerCount; - uint32_t empty3; + float dsdxRaw; // Begin raw transform + float dtdxRaw; // + float dtdyRaw; // + float dsdyRaw; // + float txRaw; // + float tyRaw; // End raw transform /** * The "pointers" field must be the last field of the struct InputMessage. * When we send the struct InputMessage across the socket, we are not @@ -173,10 +178,9 @@ struct InputMessage { struct Focus { int32_t eventId; - // The following 3 fields take up 4 bytes total + // The following 2 fields take up 4 bytes total bool hasFocus; - bool inTouchMode; - uint8_t empty[2]; + uint8_t empty[3]; inline size_t size() const { return sizeof(Focus); } } focus; @@ -206,6 +210,15 @@ struct InputMessage { inline size_t size() const { return sizeof(Timeline); } } timeline; + + struct TouchMode { + int32_t eventId; + // The following 2 fields take up 4 bytes total + bool isInTouchMode; + uint8_t empty[3]; + + inline size_t size() const { return sizeof(TouchMode); } + } touchMode; } __attribute__((aligned(8))) body; bool isValid(size_t actualSize) const; @@ -355,7 +368,7 @@ public: int32_t metaState, int32_t buttonState, MotionClassification classification, const ui::Transform& transform, float xPrecision, float yPrecision, float xCursorPosition, - float yCursorPosition, int32_t displayWidth, int32_t displayHeight, + float yCursorPosition, const ui::Transform& rawTransform, nsecs_t downTime, nsecs_t eventTime, uint32_t pointerCount, const PointerProperties* pointerProperties, const PointerCoords* pointerCoords); @@ -367,7 +380,7 @@ public: * Returns DEAD_OBJECT if the channel's peer has been closed. * Other errors probably indicate that the channel is broken. */ - status_t publishFocusEvent(uint32_t seq, int32_t eventId, bool hasFocus, bool inTouchMode); + status_t publishFocusEvent(uint32_t seq, int32_t eventId, bool hasFocus); /* Publishes a capture event to the input channel. * @@ -387,6 +400,15 @@ public: */ status_t publishDragEvent(uint32_t seq, int32_t eventId, float x, float y, bool isExiting); + /* Publishes a touch mode event to the input channel. + * + * Returns OK on success. + * Returns WOULD_BLOCK if the channel is full. + * Returns DEAD_OBJECT if the channel's peer has been closed. + * Other errors probably indicate that the channel is broken. + */ + status_t publishTouchModeEvent(uint32_t seq, int32_t eventId, bool isInTouchMode); + struct Finished { uint32_t seq; bool handled; @@ -478,24 +500,6 @@ public: status_t sendTimeline(int32_t inputEventId, std::array<nsecs_t, GraphicsTimeline::SIZE> timeline); - /* Returns true if there is a deferred event waiting. - * - * Should be called after calling consume() to determine whether the consumer - * has a deferred event to be processed. Deferred events are somewhat special in - * that they have already been removed from the input channel. If the input channel - * becomes empty, the client may need to do extra work to ensure that it processes - * the deferred event despite the fact that the input channel's file descriptor - * is not readable. - * - * One option is simply to call consume() in a loop until it returns WOULD_BLOCK. - * This guarantees that all deferred events will be processed. - * - * Alternately, the caller can call hasDeferredEvent() to determine whether there is - * a deferred event waiting and then ensure that its event loop wakes up at least - * one more time to consume the deferred event. - */ - bool hasDeferredEvent() const; - /* Returns true if there is a pending batch. * * Should be called after calling consume() with consumeBatches == false to determine @@ -657,6 +661,7 @@ private: static void initializeFocusEvent(FocusEvent* event, const InputMessage* msg); static void initializeCaptureEvent(CaptureEvent* event, const InputMessage* msg); static void initializeDragEvent(DragEvent* event, const InputMessage* msg); + static void initializeTouchModeEvent(TouchModeEvent* event, const InputMessage* msg); static void addSample(MotionEvent* event, const InputMessage* msg); static bool canAddSample(const Batch& batch, const InputMessage* msg); static ssize_t findSampleNoLaterThan(const Batch& batch, nsecs_t time); diff --git a/include/input/InputWindow.h b/include/input/InputWindow.h deleted file mode 100644 index cea57ec10d..0000000000 --- a/include/input/InputWindow.h +++ /dev/null @@ -1,280 +0,0 @@ -/* - * Copyright (C) 2011 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. - */ - -#ifndef _UI_INPUT_WINDOW_H -#define _UI_INPUT_WINDOW_H - -#include <android/os/TouchOcclusionMode.h> -#include <binder/Parcel.h> -#include <binder/Parcelable.h> -#include <input/Flags.h> -#include <input/Input.h> -#include <input/InputTransport.h> -#include <ui/Rect.h> -#include <ui/Region.h> -#include <ui/Transform.h> -#include <utils/RefBase.h> -#include <utils/Timers.h> - -#include "InputApplication.h" - -using android::os::TouchOcclusionMode; - -namespace android { - -/* - * Describes the properties of a window that can receive input. - */ -struct InputWindowInfo : public Parcelable { - InputWindowInfo() = default; - - // Window flags from WindowManager.LayoutParams - enum class Flag : uint32_t { - ALLOW_LOCK_WHILE_SCREEN_ON = 0x00000001, - DIM_BEHIND = 0x00000002, - BLUR_BEHIND = 0x00000004, - NOT_FOCUSABLE = 0x00000008, - NOT_TOUCHABLE = 0x00000010, - NOT_TOUCH_MODAL = 0x00000020, - TOUCHABLE_WHEN_WAKING = 0x00000040, - KEEP_SCREEN_ON = 0x00000080, - LAYOUT_IN_SCREEN = 0x00000100, - LAYOUT_NO_LIMITS = 0x00000200, - FULLSCREEN = 0x00000400, - FORCE_NOT_FULLSCREEN = 0x00000800, - DITHER = 0x00001000, - SECURE = 0x00002000, - SCALED = 0x00004000, - IGNORE_CHEEK_PRESSES = 0x00008000, - LAYOUT_INSET_DECOR = 0x00010000, - ALT_FOCUSABLE_IM = 0x00020000, - WATCH_OUTSIDE_TOUCH = 0x00040000, - SHOW_WHEN_LOCKED = 0x00080000, - SHOW_WALLPAPER = 0x00100000, - TURN_SCREEN_ON = 0x00200000, - DISMISS_KEYGUARD = 0x00400000, - SPLIT_TOUCH = 0x00800000, - HARDWARE_ACCELERATED = 0x01000000, - LAYOUT_IN_OVERSCAN = 0x02000000, - TRANSLUCENT_STATUS = 0x04000000, - TRANSLUCENT_NAVIGATION = 0x08000000, - LOCAL_FOCUS_MODE = 0x10000000, - SLIPPERY = 0x20000000, - LAYOUT_ATTACHED_IN_DECOR = 0x40000000, - DRAWS_SYSTEM_BAR_BACKGROUNDS = 0x80000000, - }; // Window types from WindowManager.LayoutParams - - enum class Type : int32_t { - UNKNOWN = 0, - FIRST_APPLICATION_WINDOW = 1, - BASE_APPLICATION = 1, - APPLICATION = 2, - APPLICATION_STARTING = 3, - LAST_APPLICATION_WINDOW = 99, - FIRST_SUB_WINDOW = 1000, - APPLICATION_PANEL = FIRST_SUB_WINDOW, - APPLICATION_MEDIA = FIRST_SUB_WINDOW + 1, - APPLICATION_SUB_PANEL = FIRST_SUB_WINDOW + 2, - APPLICATION_ATTACHED_DIALOG = FIRST_SUB_WINDOW + 3, - APPLICATION_MEDIA_OVERLAY = FIRST_SUB_WINDOW + 4, - LAST_SUB_WINDOW = 1999, - FIRST_SYSTEM_WINDOW = 2000, - STATUS_BAR = FIRST_SYSTEM_WINDOW, - SEARCH_BAR = FIRST_SYSTEM_WINDOW + 1, - PHONE = FIRST_SYSTEM_WINDOW + 2, - SYSTEM_ALERT = FIRST_SYSTEM_WINDOW + 3, - KEYGUARD = FIRST_SYSTEM_WINDOW + 4, - TOAST = FIRST_SYSTEM_WINDOW + 5, - SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW + 6, - PRIORITY_PHONE = FIRST_SYSTEM_WINDOW + 7, - SYSTEM_DIALOG = FIRST_SYSTEM_WINDOW + 8, - KEYGUARD_DIALOG = FIRST_SYSTEM_WINDOW + 9, - SYSTEM_ERROR = FIRST_SYSTEM_WINDOW + 10, - INPUT_METHOD = FIRST_SYSTEM_WINDOW + 11, - INPUT_METHOD_DIALOG = FIRST_SYSTEM_WINDOW + 12, - WALLPAPER = FIRST_SYSTEM_WINDOW + 13, - STATUS_BAR_PANEL = FIRST_SYSTEM_WINDOW + 14, - SECURE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW + 15, - DRAG = FIRST_SYSTEM_WINDOW + 16, - STATUS_BAR_SUB_PANEL = FIRST_SYSTEM_WINDOW + 17, - POINTER = FIRST_SYSTEM_WINDOW + 18, - NAVIGATION_BAR = FIRST_SYSTEM_WINDOW + 19, - VOLUME_OVERLAY = FIRST_SYSTEM_WINDOW + 20, - BOOT_PROGRESS = FIRST_SYSTEM_WINDOW + 21, - INPUT_CONSUMER = FIRST_SYSTEM_WINDOW + 22, - NAVIGATION_BAR_PANEL = FIRST_SYSTEM_WINDOW + 24, - MAGNIFICATION_OVERLAY = FIRST_SYSTEM_WINDOW + 27, - ACCESSIBILITY_OVERLAY = FIRST_SYSTEM_WINDOW + 32, - DOCK_DIVIDER = FIRST_SYSTEM_WINDOW + 34, - ACCESSIBILITY_MAGNIFICATION_OVERLAY = FIRST_SYSTEM_WINDOW + 39, - NOTIFICATION_SHADE = FIRST_SYSTEM_WINDOW + 40, - LAST_SYSTEM_WINDOW = 2999, - }; - - enum class Feature { - DISABLE_TOUCH_PAD_GESTURES = 0x00000001, - NO_INPUT_CHANNEL = 0x00000002, - DISABLE_USER_ACTIVITY = 0x00000004, - DROP_INPUT = 0x00000008, - }; - - /* These values are filled in by the WM and passed through SurfaceFlinger - * unless specified otherwise. - */ - // This value should NOT be used to uniquely identify the window. There may be different - // input windows that have the same token. - sp<IBinder> token; - // This uniquely identifies the input window. - int32_t id = -1; - std::string name; - Flags<Flag> flags; - Type type = Type::UNKNOWN; - std::chrono::nanoseconds dispatchingTimeout = std::chrono::seconds(5); - - /* These values are filled in by SurfaceFlinger. */ - int32_t frameLeft = -1; - int32_t frameTop = -1; - int32_t frameRight = -1; - int32_t frameBottom = -1; - - /* - * SurfaceFlinger consumes this value to shrink the computed frame. This is - * different from shrinking the touchable region in that it DOES shift the coordinate - * space where-as the touchable region does not and is more like "cropping". This - * is used for window shadows. - */ - int32_t surfaceInset = 0; - - // A global scaling factor for all windows. Unlike windowScaleX/Y this results - // in scaling of the TOUCH_MAJOR/TOUCH_MINOR axis. - float globalScaleFactor = 1.0f; - - // The opacity of this window, from 0.0 to 1.0 (inclusive). - // An alpha of 1.0 means fully opaque and 0.0 means fully transparent. - float alpha; - - // Transform applied to individual windows. - ui::Transform transform; - - // Display size in its natural rotation. Used to rotate raw coordinates for compatibility. - int32_t displayWidth = AMOTION_EVENT_INVALID_DISPLAY_SIZE; - int32_t displayHeight = AMOTION_EVENT_INVALID_DISPLAY_SIZE; - - /* - * This is filled in by the WM relative to the frame and then translated - * to absolute coordinates by SurfaceFlinger once the frame is computed. - */ - Region touchableRegion; - bool visible = false; - bool focusable = false; - bool hasWallpaper = false; - bool paused = false; - /* This flag is set when the window is of a trusted type that is allowed to silently - * overlay other windows for the purpose of implementing the secure views feature. - * Trusted overlays, such as IME windows, can partly obscure other windows without causing - * motion events to be delivered to them with AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED. - */ - bool trustedOverlay = false; - TouchOcclusionMode touchOcclusionMode = TouchOcclusionMode::BLOCK_UNTRUSTED; - int32_t ownerPid = -1; - int32_t ownerUid = -1; - std::string packageName; - Flags<Feature> inputFeatures; - int32_t displayId = ADISPLAY_ID_NONE; - int32_t portalToDisplayId = ADISPLAY_ID_NONE; - InputApplicationInfo applicationInfo; - bool replaceTouchableRegionWithCrop = false; - wp<IBinder> touchableRegionCropHandle; - - void addTouchableRegion(const Rect& region); - - bool touchableRegionContainsPoint(int32_t x, int32_t y) const; - - bool frameContainsPoint(int32_t x, int32_t y) const; - - bool supportsSplitTouch() const; - - bool overlaps(const InputWindowInfo* other) const; - - bool operator==(const InputWindowInfo& inputChannel) const; - - status_t writeToParcel(android::Parcel* parcel) const override; - - status_t readFromParcel(const android::Parcel* parcel) override; -}; - -/* - * Handle for a window that can receive input. - * - * Used by the native input dispatcher to indirectly refer to the window manager objects - * that describe a window. - */ -class InputWindowHandle : public RefBase { -public: - explicit InputWindowHandle(); - InputWindowHandle(const InputWindowHandle& other); - InputWindowHandle(const InputWindowInfo& other); - - inline const InputWindowInfo* getInfo() const { return &mInfo; } - - sp<IBinder> getToken() const; - - int32_t getId() const { return mInfo.id; } - - sp<IBinder> getApplicationToken() { return mInfo.applicationInfo.token; } - - inline std::string getName() const { return !mInfo.name.empty() ? mInfo.name : "<invalid>"; } - - inline std::chrono::nanoseconds getDispatchingTimeout( - std::chrono::nanoseconds defaultValue) const { - return mInfo.token ? std::chrono::nanoseconds(mInfo.dispatchingTimeout) : defaultValue; - } - - /** - * Requests that the state of this object be updated to reflect - * the most current available information about the application. - * As this class is created as RefBase object, no pure virtual function is allowed. - * - * This method should only be called from within the input dispatcher's - * critical section. - * - * Returns true on success, or false if the handle is no longer valid. - */ - virtual bool updateInfo() { return false; } - - /** - * Updates from another input window handle. - */ - void updateFrom(const sp<InputWindowHandle> handle); - - /** - * Releases the channel used by the associated information when it is - * no longer needed. - */ - void releaseChannel(); - - // Not override since this class is not derrived from Parcelable. - status_t readFromParcel(const android::Parcel* parcel); - status_t writeToParcel(android::Parcel* parcel) const; - -protected: - virtual ~InputWindowHandle(); - - InputWindowInfo mInfo; -}; -} // namespace android - -#endif // _UI_INPUT_WINDOW_H diff --git a/include/input/KeyCharacterMap.h b/include/input/KeyCharacterMap.h index 451ca3c6cd..f6f8939b7a 100644 --- a/include/input/KeyCharacterMap.h +++ b/include/input/KeyCharacterMap.h @@ -84,7 +84,7 @@ public: const std::string getLoadFileName() const; - /* Combines this key character map with an overlay. */ + /* Combines this key character map with the provided overlay. */ void combine(const KeyCharacterMap& overlay); /* Gets the keyboard type. */ @@ -144,6 +144,8 @@ public: bool operator==(const KeyCharacterMap& other) const; + bool operator!=(const KeyCharacterMap& other) const; + KeyCharacterMap(const KeyCharacterMap& other); virtual ~KeyCharacterMap(); @@ -230,11 +232,12 @@ private: KeyedVector<int32_t, Key*> mKeys; KeyboardType mType; std::string mLoadFileName; + bool mLayoutOverlayApplied; KeyedVector<int32_t, int32_t> mKeysByScanCode; KeyedVector<int32_t, int32_t> mKeysByUsageCode; - KeyCharacterMap(); + KeyCharacterMap(const std::string& filename); bool getKey(int32_t keyCode, const Key** outKey) const; bool getKeyBehavior(int32_t keyCode, int32_t metaState, @@ -243,8 +246,6 @@ private: bool findKey(char16_t ch, int32_t* outKeyCode, int32_t* outMetaState) const; - static base::Result<std::shared_ptr<KeyCharacterMap>> load(Tokenizer* tokenizer, Format format); - static void addKey(Vector<KeyEvent>& outEvents, int32_t deviceId, int32_t keyCode, int32_t metaState, bool down, nsecs_t time); static void addMetaKeys(Vector<KeyEvent>& outEvents, @@ -264,6 +265,15 @@ private: int32_t deviceId, int32_t metaState, nsecs_t time, int32_t keyCode, int32_t keyMetaState, int32_t* currentMetaState); + + /* Clears all data stored in this key character map */ + void clear(); + + /* Loads the KeyCharacterMap provided by the tokenizer into this instance. */ + status_t load(Tokenizer* tokenizer, Format format); + + /* Reloads the data from mLoadFileName and unapplies any overlay. */ + status_t reloadBaseFromFile(); }; } // namespace android diff --git a/include/input/NamedEnum.h b/include/input/NamedEnum.h deleted file mode 100644 index 6562348701..0000000000 --- a/include/input/NamedEnum.h +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright (C) 2020 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-base/stringprintf.h> - -#include <array> -#include <cstdint> -#include <optional> -#include <string> - -#ifndef __UI_INPUT_NAMEDENUM_H -#define __UI_INPUT_NAMEDENUM_H - -namespace android { - -namespace details { -template <typename E, E V> -constexpr std::optional<std::string_view> enum_value_name() { - // Should look something like (but all on one line): - // std::optional<std::string_view> - // android::details::enum_value_name() - // [E = android::test::TestEnums, V = android::test::TestEnums::ONE] - std::string_view view = __PRETTY_FUNCTION__; - size_t templateStart = view.rfind("["); - size_t templateEnd = view.rfind("]"); - if (templateStart == std::string::npos || templateEnd == std::string::npos) { - return std::nullopt; - } - - // Extract the template parameters without the enclosing braces. - // Example (cont'd): E = android::test::TestEnums, V = android::test::TestEnums::ONE - view = view.substr(templateStart + 1, templateEnd - templateStart - 1); - size_t valStart = view.rfind("V = "); - if (valStart == std::string::npos) { - return std::nullopt; - } - - // Example (cont'd): V = android::test::TestEnums::ONE - view = view.substr(valStart); - size_t nameStart = view.rfind("::"); - if (nameStart == std::string::npos) { - return std::nullopt; - } - - // Chop off the initial "::" - nameStart += 2; - return view.substr(nameStart); -} - -template <typename E, typename T, T... I> -constexpr auto generate_enum_values(std::integer_sequence<T, I...> seq) { - constexpr size_t count = seq.size(); - - std::array<E, count> values{}; - for (size_t i = 0, v = 0; v < count; ++i) { - values[v++] = static_cast<E>(T{0} + i); - } - - return values; -} - -template <typename E, std::size_t N> -inline constexpr auto enum_values = - generate_enum_values<E>(std::make_integer_sequence<std::underlying_type_t<E>, N>{}); - -template <typename E, std::size_t N, std::size_t... I> -constexpr auto generate_enum_names(std::index_sequence<I...>) noexcept { - return std::array<std::optional<std::string_view>, sizeof...(I)>{ - {enum_value_name<E, enum_values<E, N>[I]>()...}}; -} - -template <typename E, std::size_t N> -inline constexpr auto enum_names = generate_enum_names<E, N>(std::make_index_sequence<N>{}); - -} // namespace details - -class NamedEnum { -public: - // By default allowed enum value range is 0 ~ 7. - template <typename E> - static constexpr size_t max = 8; - - template <auto V> - static constexpr auto enum_name() { - using E = decltype(V); - return details::enum_value_name<E, V>(); - } - - template <typename E> - static constexpr std::optional<std::string_view> enum_name(E val) { - auto idx = static_cast<size_t>(val); - return idx < max<E> ? details::enum_names<E, max<E>>[idx] : std::nullopt; - } - - // Helper function for parsing enum value to string. - // Example : enum class TestEnums { ZERO = 0x0 }; - // NamedEnum::string(TestEnums::ZERO) returns string of "ZERO". - // Note the default maximum enum is 8, if the enum ID to be parsed if greater than 8 like 16, - // it should be declared to specialized the maximum enum by below: - // template <> constexpr size_t NamedEnum::max<TestEnums> = 16; - // If the enum class definition is sparse and contains enum values starting from a large value, - // Do not specialize it to a large number to avoid performance issues. - // The recommended maximum enum number to specialize is 64. - template <typename E> - static const std::string string(E val, const char* fallbackFormat = "%02d") { - std::string result; - std::optional<std::string_view> enumString = enum_name(val); - result += enumString ? enumString.value() : base::StringPrintf(fallbackFormat, val); - return result; - } -}; - -} // namespace android - -#endif // __UI_INPUT_NAMEDENUM_H
\ No newline at end of file diff --git a/include/input/PrintTools.h b/include/input/PrintTools.h new file mode 100644 index 0000000000..0a75278494 --- /dev/null +++ b/include/input/PrintTools.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2022 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 <map> +#include <set> +#include <string> + +namespace android { + +template <typename T> +std::string constToString(const T& v) { + return std::to_string(v); +} + +/** + * Convert a set of integral types to string. + */ +template <typename T> +std::string dumpSet(const std::set<T>& v, std::string (*toString)(const T&) = constToString) { + std::string out; + for (const T& entry : v) { + out += out.empty() ? "{" : ", "; + out += toString(entry); + } + return out.empty() ? "{}" : (out + "}"); +} + +/** + * Convert a map to string. Both keys and values of the map should be integral type. + */ +template <typename K, typename V> +std::string dumpMap(const std::map<K, V>& map, std::string (*keyToString)(const K&) = constToString, + std::string (*valueToString)(const V&) = constToString) { + std::string out; + for (const auto& [k, v] : map) { + if (!out.empty()) { + out += "\n"; + } + out += keyToString(k) + ":" + valueToString(v); + } + return out; +} + +const char* toString(bool value); + +/** + * Add "prefix" to the beginning of each line in the provided string + * "str". + * The string 'str' is typically multi-line. + * The most common use case for this function is to add some padding + * when dumping state. + */ +std::string addLinePrefix(std::string str, const std::string& prefix); + +} // namespace android
\ No newline at end of file diff --git a/include/powermanager/PowerHalWrapper.h b/include/powermanager/PowerHalWrapper.h index 2c6eacbfaa..dfb0ff59a0 100644 --- a/include/powermanager/PowerHalWrapper.h +++ b/include/powermanager/PowerHalWrapper.h @@ -201,10 +201,8 @@ private: std::array<std::atomic<HalSupport>, static_cast<int32_t>(hardware::power::Boost::DISPLAY_UPDATE_IMMINENT) + 1> mBoostSupportedArray GUARDED_BY(mBoostMutex) = {HalSupport::UNKNOWN}; - // Android framework only sends mode upto DISPLAY_INACTIVE. - // Need to increase the array if more mode supported. std::array<std::atomic<HalSupport>, - static_cast<int32_t>(hardware::power::Mode::DISPLAY_INACTIVE) + 1> + static_cast<int32_t>(*(android::enum_range<hardware::power::Mode>().end() - 1)) + 1> mModeSupportedArray GUARDED_BY(mModeMutex) = {HalSupport::UNKNOWN}; }; diff --git a/include/private/performance_hint_private.h b/include/private/performance_hint_private.h index 5832bf49bd..f27f5f150f 100644 --- a/include/private/performance_hint_private.h +++ b/include/private/performance_hint_private.h @@ -17,124 +17,8 @@ #ifndef ANDROID_PRIVATE_NATIVE_PERFORMANCE_HINT_PRIVATE_H #define ANDROID_PRIVATE_NATIVE_PERFORMANCE_HINT_PRIVATE_H -#include <stdint.h> - __BEGIN_DECLS -struct APerformanceHintManager; -struct APerformanceHintSession; - -/** - * An opaque type representing a handle to a performance hint manager. - * It must be released after use. - * - * <p>To use:<ul> - * <li>Obtain the performance hint manager instance by calling - * {@link APerformanceHint_getManager} function.</li> - * <li>Create an {@link APerformanceHintSession} with - * {@link APerformanceHint_createSession}.</li> - * <li>Get the preferred update rate in nanoseconds with - * {@link APerformanceHint_getPreferredUpdateRateNanos}.</li> - */ -typedef struct APerformanceHintManager APerformanceHintManager; - -/** - * An opaque type representing a handle to a performance hint session. - * A session can only be acquired from a {@link APerformanceHintManager} - * with {@link APerformanceHint_getPreferredUpdateRateNanos}. It must be - * freed with {@link APerformanceHint_closeSession} after use. - * - * A Session represents a group of threads with an inter-related workload such that hints for - * their performance should be considered as a unit. The threads in a given session should be - * long-life and not created or destroyed dynamically. - * - * <p>Each session is expected to have a periodic workload with a target duration for each - * cycle. The cycle duration is likely greater than the target work duration to allow other - * parts of the pipeline to run within the available budget. For example, a renderer thread may - * work at 60hz in order to produce frames at the display's frame but have a target work - * duration of only 6ms.</p> - * - * <p>After each cycle of work, the client is expected to use - * {@link APerformanceHint_reportActualWorkDuration} to report the actual time taken to - * complete.</p> - * - * <p>To use:<ul> - * <li>Update a sessions target duration for each cycle of work - * with {@link APerformanceHint_updateTargetWorkDuration}.</li> - * <li>Report the actual duration for the last cycle of work with - * {@link APerformanceHint_reportActualWorkDuration}.</li> - * <li>Release the session instance with - * {@link APerformanceHint_closeSession}.</li></ul></p> - */ -typedef struct APerformanceHintSession APerformanceHintSession; - -/** - * Acquire an instance of the performance hint manager. - * - * @return manager instance on success, nullptr on failure. - */ -APerformanceHintManager* APerformanceHint_getManager(); - -/** - * Creates a session for the given set of threads and sets their initial target work - * duration. - * @param manager The performance hint manager instance. - * @param threadIds The list of threads to be associated with this session. They must be part of - * this app's thread group. - * @param size the size of threadIds. - * @param initialTargetWorkDurationNanos The desired duration in nanoseconds for the new session. - * This must be positive. - * @return manager instance on success, nullptr on failure. - */ -APerformanceHintSession* APerformanceHint_createSession(APerformanceHintManager* manager, - const int32_t* threadIds, size_t size, - int64_t initialTargetWorkDurationNanos); - -/** - * Get preferred update rate information for this device. - * - * @param manager The performance hint manager instance. - * @return the preferred update rate supported by device software. - */ -int64_t APerformanceHint_getPreferredUpdateRateNanos(APerformanceHintManager* manager); - -/** - * Updates this session's target duration for each cycle of work. - * - * @param session The performance hint session instance to update. - * @param targetDurationNanos the new desired duration in nanoseconds. This must be positive. - * @return 0 on success - * EINVAL if targetDurationNanos is not positive. - * EPIPE if communication with the system service has failed. - */ -int APerformanceHint_updateTargetWorkDuration(APerformanceHintSession* session, - int64_t targetDurationNanos); - -/** - * Reports the actual duration for the last cycle of work. - * - * <p>The system will attempt to adjust the core placement of the threads within the thread - * group and/or the frequency of the core on which they are run to bring the actual duration - * close to the target duration.</p> - * - * @param session The performance hint session instance to update. - * @param actualDurationNanos how long the thread group took to complete its last task in - * nanoseconds. This must be positive. - * @return 0 on success - * EINVAL if actualDurationNanos is not positive. - * EPIPE if communication with the system service has failed. - */ -int APerformanceHint_reportActualWorkDuration(APerformanceHintSession* session, - int64_t actualDurationNanos); - -/** - * Release the performance hint manager pointer acquired via - * {@link APerformanceHint_createSession}. - * - * @param session The performance hint session instance to release. - */ -void APerformanceHint_closeSession(APerformanceHintSession* session); - /** * For testing only. */ diff --git a/include/private/surface_control_private.h b/include/private/surface_control_private.h index 37a476e679..7e6c51587d 100644 --- a/include/private/surface_control_private.h +++ b/include/private/surface_control_private.h @@ -29,8 +29,8 @@ typedef struct ASurfaceControlStats ASurfaceControlStats; /** * Callback to be notified when surface stats for a specific surface control are available. */ -typedef void (*ASurfaceControl_SurfaceStatsListener)(void* context, - ASurfaceControl* control, ASurfaceControlStats* stats); +typedef void (*ASurfaceControl_SurfaceStatsListener)(void* context, int32_t id, + ASurfaceControlStats* stats); /** * Registers a callback to be invoked when surface stats from a specific surface are available. @@ -42,7 +42,7 @@ typedef void (*ASurfaceControl_SurfaceStatsListener)(void* context, * * \param func The callback to be invoked when surface stats are available. */ -void ASurfaceControl_registerSurfaceStatsListener(ASurfaceControl* control, void* context, +void ASurfaceControl_registerSurfaceStatsListener(ASurfaceControl* control, int32_t id, void* context, ASurfaceControl_SurfaceStatsListener func); /** |