summaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
Diffstat (limited to 'include')
-rw-r--r--include/android/display_luts.h167
-rw-r--r--include/android/keycodes.h38
-rw-r--r--include/android/performance_hint.h450
-rw-r--r--include/android/surface_control.h24
-rw-r--r--include/android/surface_control_input_receiver.h9
-rw-r--r--include/android/system_health.h449
-rw-r--r--include/android/thermal.h111
-rw-r--r--include/audiomanager/AudioManager.h11
-rw-r--r--include/audiomanager/IAudioManager.h2
-rw-r--r--include/ftl/finalizer.h211
-rw-r--r--include/ftl/flags.h10
-rw-r--r--include/ftl/non_null.h9
-rw-r--r--include/input/AccelerationCurve.h11
-rw-r--r--include/input/CoordinateFilter.h54
-rw-r--r--include/input/DisplayTopologyGraph.h57
-rw-r--r--include/input/Input.h11
-rw-r--r--include/input/InputConsumerNoResampling.h42
-rw-r--r--include/input/InputDevice.h24
-rw-r--r--include/input/InputEventBuilders.h105
-rw-r--r--include/input/KeyCharacterMap.h5
-rw-r--r--include/input/OneEuroFilter.h101
-rw-r--r--include/input/Resampler.h205
-rw-r--r--include/powermanager/PowerHalController.h1
-rw-r--r--include/powermanager/PowerHalWrapper.h3
-rw-r--r--include/private/display_luts_private.h66
-rw-r--r--include/private/performance_hint_private.h51
26 files changed, 2146 insertions, 81 deletions
diff --git a/include/android/display_luts.h b/include/android/display_luts.h
new file mode 100644
index 0000000000..eae2bfd351
--- /dev/null
+++ b/include/android/display_luts.h
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @addtogroup NativeActivity Native Activity
+ * @{
+ */
+
+/**
+ * @file display_luts.h
+ */
+#pragma once
+
+#include <inttypes.h>
+
+__BEGIN_DECLS
+
+/**
+ * The dimension of the lut
+ */
+enum ADisplayLuts_Dimension : int32_t {
+ ADISPLAYLUTS_ONE_DIMENSION = 1,
+ ADISPLAYLUTS_THREE_DIMENSION = 3,
+};
+typedef enum ADisplayLuts_Dimension ADisplayLuts_Dimension;
+
+/**
+ * The sampling key used by the lut
+ */
+enum ADisplayLuts_SamplingKey : int32_t {
+ ADISPLAYLUTS_SAMPLINGKEY_RGB = 0,
+ ADISPLAYLUTS_SAMPLINGKEY_MAX_RGB = 1,
+ ADISPLAYLUTS_SAMPLINGKEY_CIE_Y = 2,
+};
+typedef enum ADisplayLuts_SamplingKey ADisplayLuts_SamplingKey;
+
+/**
+ * Used to get and set display luts entry
+ */
+typedef struct ADisplayLutsEntry ADisplayLutsEntry;
+
+/**
+ * Used to get and set display luts
+ */
+typedef struct ADisplayLuts ADisplayLuts;
+
+/**
+ * Creates a \a ADisplayLutsEntry entry.
+ *
+ * You are responsible for mamanging the memory of the returned object.
+ * Always call \a ADisplayLutsEntry_destroy to release it after use.
+ *
+ * Functions like \a ADisplayLuts_set create their own copies of entries,
+ * therefore they don't take the ownership of the instance created by
+ * \a ADisplayLutsEntry_create.
+ *
+ * @param buffer The lut raw buffer. The function creates a copy of it and does not need to
+ * outlive the life of the ADisplayLutsEntry.
+ * @param length The length of lut raw buffer
+ * @param dimension The dimension of the lut. see \a ADisplayLuts_Dimension
+ * @param key The sampling key used by the lut. see \a ADisplayLuts_SamplingKey
+ * @return a new \a ADisplayLutsEntry instance.
+ */
+ADisplayLutsEntry* _Nonnull ADisplayLutsEntry_createEntry(float* _Nonnull buffer,
+ int32_t length, ADisplayLuts_Dimension dimension, ADisplayLuts_SamplingKey key)
+ __INTRODUCED_IN(36);
+
+/**
+ * Destroy the \a ADisplayLutsEntry instance.
+ *
+ * @param entry The entry to be destroyed
+ */
+void ADisplayLutsEntry_destroy(ADisplayLutsEntry* _Nullable entry) __INTRODUCED_IN(36);
+
+/**
+ * Gets the dimension of the entry.
+ *
+ * The function is only valid for the lifetime of the `entry`.
+ *
+ * @param entry The entry to query
+ * @return the dimension of the lut
+ */
+ADisplayLuts_Dimension ADisplayLutsEntry_getDimension(const ADisplayLutsEntry* _Nonnull entry)
+ __INTRODUCED_IN(36);
+
+/**
+ * Gets the size for each dimension of the entry.
+ *
+ * The function is only valid for the lifetime of the `entry`.
+ *
+ * @param entry The entry to query
+ * @return the size of each dimension of the lut
+ */
+int32_t ADisplayLutsEntry_getSize(const ADisplayLutsEntry* _Nonnull entry)
+ __INTRODUCED_IN(36);
+
+/**
+ * Gets the sampling key used by the entry.
+ *
+ * The function is only valid for the lifetime of the `entry`.
+ *
+ * @param entry The entry to query
+ * @return the sampling key used by the lut
+ */
+ADisplayLuts_SamplingKey ADisplayLutsEntry_getSamplingKey(const ADisplayLutsEntry* _Nonnull entry)
+ __INTRODUCED_IN(36);
+
+/**
+ * Gets the lut buffer of the entry.
+ *
+ * The function is only valid for the lifetime of the `entry`.
+ *
+ * @param entry The entry to query
+ * @return a pointer to the raw lut buffer
+ */
+const float* _Nonnull ADisplayLutsEntry_getBuffer(const ADisplayLutsEntry* _Nonnull entry)
+ __INTRODUCED_IN(36);
+
+/**
+ * Creates a \a ADisplayLuts instance.
+ *
+ * You are responsible for mamanging the memory of the returned object.
+ * Always call \a ADisplayLuts_destroy to release it after use. E.g., after calling
+ * the function \a ASurfaceTransaction_setLuts.
+ *
+ * @return a new \a ADisplayLuts instance
+ */
+ADisplayLuts* _Nonnull ADisplayLuts_create() __INTRODUCED_IN(36);
+
+/**
+ * Sets Luts in order to be applied.
+ *
+ * The function accepts a single 1D Lut, or a single 3D Lut or both 1D and 3D Lut in order.
+ * And the function will replace any previously set lut(s).
+ * If you want to clear the previously set lut(s), set `entries` to be nullptr,
+ * and `numEntries` will be internally ignored.
+ *
+ * @param luts the pointer of the \a ADisplayLuts instance
+ * @param entries the pointer of the array of lut entries to be applied
+ * @param numEntries the number of lut entries. The value should be either 1 or 2.
+ */
+void ADisplayLuts_setEntries(ADisplayLuts* _Nonnull luts,
+ ADisplayLutsEntry* _Nullable *_Nullable entries, int32_t numEntries) __INTRODUCED_IN(36);
+
+/**
+ * Deletes the \a ADisplayLuts instance.
+ *
+ * @param luts The luts to be destroyed
+ */
+void ADisplayLuts_destroy(ADisplayLuts* _Nullable luts) __INTRODUCED_IN(36);
+
+__END_DECLS
+
+/** @} */ \ No newline at end of file
diff --git a/include/android/keycodes.h b/include/android/keycodes.h
index 79cdbcaf7b..495e0bdb1f 100644
--- a/include/android/keycodes.h
+++ b/include/android/keycodes.h
@@ -843,6 +843,44 @@ enum {
AKEYCODE_EMOJI_PICKER = 317,
/** Take Screenshot */
AKEYCODE_SCREENSHOT = 318,
+ /** To start dictate to an input field */
+ AKEYCODE_DICTATE = 319,
+ /** AC New */
+ AKEYCODE_NEW = 320,
+ /** AC Close */
+ AKEYCODE_CLOSE = 321,
+ /** To toggle 'Do Not Disturb' mode */
+ AKEYCODE_DO_NOT_DISTURB = 322,
+ /** To Print */
+ AKEYCODE_PRINT = 323,
+ /** To Lock the screen */
+ AKEYCODE_LOCK = 324,
+ /** To toggle fullscreen mode (on the current application) */
+ AKEYCODE_FULLSCREEN = 325,
+ /** F13 key */
+ AKEYCODE_F13 = 326,
+ /** F14 key */
+ AKEYCODE_F14 = 327,
+ /** F15 key */
+ AKEYCODE_F15 = 328,
+ /** F16 key */
+ AKEYCODE_F16 = 329,
+ /** F17 key */
+ AKEYCODE_F17 = 330,
+ /** F18 key */
+ AKEYCODE_F18 = 331,
+ /** F19 key */
+ AKEYCODE_F19 = 332,
+ /** F20 key */
+ AKEYCODE_F20 = 333,
+ /** F21 key */
+ AKEYCODE_F21 = 334,
+ /** F22 key */
+ AKEYCODE_F22 = 335,
+ /** F23 key */
+ AKEYCODE_F23 = 336,
+ /** F24 key */
+ AKEYCODE_F24 = 337,
// NOTE: If you add a new keycode here you must also add it to several other files.
// Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list.
diff --git a/include/android/performance_hint.h b/include/android/performance_hint.h
index 3486e9b1d7..52dbb61ac5 100644
--- a/include/android/performance_hint.h
+++ b/include/android/performance_hint.h
@@ -19,9 +19,23 @@
*
* APerformanceHint allows apps to create performance hint sessions for groups
* of threads, and provide hints to the system about the workload of those threads,
- * to help the system more accurately allocate power for them. It is the NDK
+ * to help the system more accurately allocate resources for them. It is the NDK
* counterpart to the Java PerformanceHintManager SDK API.
*
+ * This API is intended for periodic workloads, such as frame production. Clients are
+ * expected to create an instance of APerformanceHintManager, create a session with
+ * that, and then set a target duration for the session. Then, they can report the actual
+ * work duration at the end of each cycle to inform the framework about how long those
+ * workloads are taking. The framework will then compare the actual durations to the target
+ * duration and attempt to help the client reach a steady state under the target.
+ *
+ * Unlike reportActualWorkDuration, the "notifyWorkload..." hints are intended to be sent in
+ * advance of large changes in the workload, to prevent them from going over the target
+ * when there is a sudden, unforseen change. Their effects are intended to last for only
+ * one cycle, after which reportActualWorkDuration will have a chance to catch up.
+ * These hints should be used judiciously, only in cases where the workload is changing
+ * substantially. To enforce that, they are tracked using a per-app rate limiter to avoid
+ * excessive hinting and encourage clients to be mindful about when to send them.
* @{
*/
@@ -35,6 +49,7 @@
#define ANDROID_NATIVE_PERFORMANCE_HINT_H
#include <sys/cdefs.h>
+#include <jni.h>
/******************************************************************
*
@@ -56,11 +71,17 @@
#include <stdint.h>
#include <unistd.h>
+#if !defined(__DEPRECATED_IN)
+#define __DEPRECATED_IN(__api_level, ...) __attribute__((__deprecated__))
+#endif
+
__BEGIN_DECLS
struct APerformanceHintManager;
struct APerformanceHintSession;
struct AWorkDuration;
+struct ANativeWindow;
+struct ASurfaceControl;
/**
* {@link AWorkDuration} is an opaque type that represents the breakdown of the
@@ -96,9 +117,24 @@ typedef struct AWorkDuration AWorkDuration;
typedef struct APerformanceHintManager APerformanceHintManager;
/**
+ * An opaque type representing a handle to a performance hint session creation configuration.
+ * It is consumed by {@link APerformanceHint_createSessionUsingConfig}.
+ *
+ * A session creation config encapsulates the required information for creating a session. The only
+ * mandatory parameter is the set of TIDs, set using {@link ASessionCreationConfig_setTids}. Only
+ * parameters relevant to the session need to be set, and any unspecified functionality will be
+ * treated as unused on the session. Configurations without a valid set of TIDs, or which try to
+ * enable automatic timing without the graphics pipeline mode, are considered invalid.
+ *
+ * The caller may reuse this object and modify the settings in it to create additional sessions.
+ */
+typedef struct ASessionCreationConfig ASessionCreationConfig;
+
+/**
* An opaque type representing a handle to a performance hint session.
* A session can only be acquired from a {@link APerformanceHintManager}
- * with {@link APerformanceHint_createSession}. It must be
+ * with {@link APerformanceHint_createSession}
+ * or {@link APerformanceHint_createSessionUsingConfig}. 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
@@ -120,6 +156,9 @@ typedef struct APerformanceHintManager APerformanceHintManager;
*/
typedef struct APerformanceHintSession APerformanceHintSession;
+typedef struct ANativeWindow ANativeWindow;
+typedef struct ASurfaceControl ASurfaceControl;
+
/**
* Acquire an instance of the performance hint manager.
*
@@ -138,7 +177,7 @@ APerformanceHintManager* _Nullable APerformanceHint_getManager()
* @param size The size of the list of threadIds.
* @param initialTargetWorkDurationNanos The target duration in nanoseconds for the new session.
* This must be positive if using the work duration API, or 0 otherwise.
- * @return APerformanceHintManager instance on success, nullptr on failure.
+ * @return APerformanceHintSession pointer on success, nullptr on failure.
*/
APerformanceHintSession* _Nullable APerformanceHint_createSession(
APerformanceHintManager* _Nonnull manager,
@@ -146,21 +185,62 @@ APerformanceHintSession* _Nullable APerformanceHint_createSession(
int64_t initialTargetWorkDurationNanos) __INTRODUCED_IN(__ANDROID_API_T__);
/**
+ * Creates a session using arguments from a corresponding {@link ASessionCreationConfig}.
+ *
+ * Note: when using graphics pipeline mode, using too many cumulative graphics pipeline threads is
+ * not a failure and will still create a session, but it will cause all graphics pipeline sessions
+ * to have undefined behavior and the method will return EBUSY.
+ *
+ * @param manager The performance hint manager instance.
+ * @param config The configuration struct containing required information
+ * to create a session.
+ * @param sessionOut A client-provided pointer, which will be set to the new APerformanceHintSession
+ * on success or EBUSY, and to nullptr on failure.
+ *
+ * @return 0 on success.
+ * EINVAL if the creation config is in an invalid state.
+ * EPIPE if communication failed.
+ * ENOTSUP if hint sessions are not supported, or if auto timing is enabled but unsupported.
+ * EBUSY if too many graphics pipeline threads are passed.
+ */
+int APerformanceHint_createSessionUsingConfig(
+ APerformanceHintManager* _Nonnull manager,
+ ASessionCreationConfig* _Nonnull config,
+ APerformanceHintSession * _Nullable * _Nonnull sessionOut) __INTRODUCED_IN(36);
+
+/**
* Get preferred update rate information for this device.
*
+ * @deprecated Client side rate limiting is not necessary, rate limiting is handled in the
+ * framework. If you were using this to check for hint session support, please use
+ * {@link APerformanceHint_isFeatureSupported} instead.
+ *
* @param manager The performance hint manager instance.
* @return the preferred update rate supported by device software.
*/
int64_t APerformanceHint_getPreferredUpdateRateNanos(
- APerformanceHintManager* _Nonnull manager) __INTRODUCED_IN(__ANDROID_API_T__);
+ APerformanceHintManager* _Nonnull manager)
+ __INTRODUCED_IN(__ANDROID_API_T__) __DEPRECATED_IN(36, "Client-side rate limiting is not"
+ " necessary, use APerformanceHint_isFeatureSupported for support checking.");
+
+/**
+ * Get maximum number of graphics pipieline threads per-app for this device.
+ *
+ * @param manager The performance hint manager instance.
+ * @return the maximum number of graphics pipeline threads supported by device.
+ */
+ int APerformanceHint_getMaxGraphicsPipelineThreadsCount(
+ APerformanceHintManager* _Nonnull manager) __INTRODUCED_IN(36);
/**
* 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.
+ * @param targetDurationNanos The new desired duration in nanoseconds. This must be positive for the
+ * session to report work durations, and may be zero to disable this functionality.
+ *
* @return 0 on success.
- * EINVAL if targetDurationNanos is not positive.
+ * EINVAL if targetDurationNanos is less than zero.
* EPIPE if communication with the system service has failed.
*/
int APerformanceHint_updateTargetWorkDuration(
@@ -177,7 +257,7 @@ int APerformanceHint_updateTargetWorkDuration(
* @param actualDurationNanos The duration of time 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.
+ * EINVAL if actualDurationNanos is not positive or the target it not positive.
* EPIPE if communication with the system service has failed.
*/
int APerformanceHint_reportActualWorkDuration(
@@ -188,6 +268,9 @@ int APerformanceHint_reportActualWorkDuration(
* Release the performance hint manager pointer acquired via
* {@link APerformanceHint_createSession}.
*
+ * This cannot be used to close a Java PerformanceHintManager.Session, as its
+ * lifecycle is tied to the object in the SDK.
+ *
* @param session The performance hint session instance to release.
*/
void APerformanceHint_closeSession(
@@ -197,15 +280,20 @@ void APerformanceHint_closeSession(
* Set a list of threads to the performance hint session. This operation will replace
* the current list of threads with the given list of threads.
*
+ * Note: when using a session with the graphics pipeline mode enabled, using too many cumulative
+ * graphics pipeline threads is not a failure, but it will cause all graphics pipeline sessions to
+ * have undefined behavior and the method will return EBUSY.
+ *
* @param session The performance hint session instance to update.
* @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 the list of threadIds.
* @return 0 on success.
* EINVAL if the list of thread ids is empty or if any of the thread ids are not part of
- the thread group.
+ * the thread group.
* EPIPE if communication with the system service has failed.
* EPERM if any thread id doesn't belong to the application.
+ * EBUSY if too many graphics pipeline threads were passed.
*/
int APerformanceHint_setThreads(
APerformanceHintSession* _Nonnull session,
@@ -250,16 +338,196 @@ int APerformanceHint_reportActualWorkDuration2(
AWorkDuration* _Nonnull workDuration) __INTRODUCED_IN(__ANDROID_API_V__);
/**
+ * Informs the framework of an upcoming increase in the workload of this session.
+ * The user can specify whether the increase is expected to be on the CPU, GPU, or both.
+ *
+ * These hints should be sent shortly before the start of the cycle where the workload is going to
+ * change, or as early as possible during that cycle for maximum effect. Hints sent towards the end
+ * of the cycle may be interpreted as applying to the next cycle. Any unsupported hints will be
+ * silently dropped, to avoid the need for excessive support checking each time they are sent, and
+ * sending a hint for both CPU and GPU will count as two separate hints for the rate limiter. These
+ * hints should not be sent repeatedly for an ongoing expensive workload, as workload time reporting
+ * is intended to handle this.
+ *
+ * @param session The {@link APerformanceHintSession} instance to send a hint for.
+ * @param cpu Indicates if the workload increase is expected to affect the CPU.
+ * @param gpu Indicates if the workload increase is expected to affect the GPU.
+ * @param identifier A required string used to distinguish this specific hint, using utf-8 encoding.
+ * This string will only be held for the duration of the method, and can be discarded after.
+ *
+ * @return 0 on success.
+ * EBUSY if the hint was rate limited.
+ * EPIPE if communication with the system service has failed.
+ */
+int APerformanceHint_notifyWorkloadIncrease(
+ APerformanceHintSession* _Nonnull session,
+ bool cpu, bool gpu, const char* _Nonnull identifier) __INTRODUCED_IN(36);
+
+/**
+ * Informs the framework that the workload associated with this session is about to start, or that
+ * it is about to completely change, and that the system should discard any assumptions about its
+ * characteristics inferred from previous activity. The user can specify whether the reset is
+ * expected to affect the CPU, GPU, or both.
+ *
+ * These hints should be sent shortly before the start of the cycle where the workload is going to
+ * change, or as early as possible during that cycle for maximum effect. Hints sent towards the end
+ * of the cycle may be interpreted as applying to the next cycle. Any unsupported hints will be
+ * silently dropped, to avoid the need for excessive support checking each time they are sent, and
+ * sending a hint for both CPU and GPU will count as two separate hints for the rate limiter. These
+ * hints should not be sent repeatedly for an ongoing expensive workload, as workload time reporting
+ * is intended to handle this.
+ *
+ * @param session The {@link APerformanceHintSession} instance to send a hint for.
+ * @param cpu Indicates if the workload reset is expected to affect the CPU.
+ * @param gpu Indicates if the workload reset is expected to affect the GPU.
+ * @param identifier A required string used to distinguish this specific hint, using utf-8 encoding.
+ * This string will only be held for the duration of the method, and can be discarded after.
+ *
+ * @return 0 on success.
+ * EBUSY if the hint was rate limited.
+ * EPIPE if communication with the system service has failed.
+ */
+int APerformanceHint_notifyWorkloadReset(
+ APerformanceHintSession* _Nonnull session,
+ bool cpu, bool gpu, const char* _Nonnull identifier) __INTRODUCED_IN(36);
+
+/**
+ * Informs the framework of an upcoming one-off expensive workload cycle for a given session.
+ * This cycle will be treated as not representative of the workload as a whole, and it will be
+ * discarded the purposes of load tracking. The user can specify whether the workload spike is
+ * expected to be on the CPU, GPU, or both.
+ *
+ * These hints should be sent shortly before the start of the cycle where the workload is going to
+ * change, or as early as possible during that cycle for maximum effect. Hints sent towards the end
+ * of the cycle may be interpreted as applying to the next cycle. Any unsupported hints will be
+ * silently dropped, to avoid the need for excessive support checking each time they are sent, and
+ * sending a hint for both CPU and GPU will count as two separate hints for the rate limiter. These
+ * hints should not be sent repeatedly for an ongoing expensive workload, as workload time reporting
+ * is intended to handle this.
+ *
+ * @param session The {@link APerformanceHintSession} instance to send a hint for.
+ * @param cpu Indicates if the workload spike is expected to affect the CPU.
+ * @param gpu Indicates if the workload spike is expected to affect the GPU.
+ * @param identifier A required string used to distinguish this specific hint, using utf-8 encoding.
+ * This string will only be held for the duration of the method, and can be discarded after.
+ *
+ * @return 0 on success.
+ * EBUSY if the hint was rate limited.
+ * EPIPE if communication with the system service has failed.
+ */
+int APerformanceHint_notifyWorkloadSpike(
+ APerformanceHintSession* _Nonnull session,
+ bool cpu, bool gpu, const char* _Nonnull identifier) __INTRODUCED_IN(36);
+
+/**
+ * Associates a session with any {@link ASurfaceControl} or {@link ANativeWindow}
+ * instances managed by this session. Any previously associated objects that are not passed
+ * in again lose their association. Invalid or dead instances are ignored, and passing both
+ * lists as null drops all current associations.
+ *
+ * This method is primarily intended for sessions that manage the timing of an entire
+ * graphics pipeline end-to-end for frame pacing, such as those using the
+ * {@link ASessionCreationConfig_setGraphicsPipeline} API. However, any session directly
+ * or indirectly managing a graphics pipeline should still associate themselves with
+ * directly relevant ASurfaceControl or ANativeWindow instances for better optimization.
+ * Additionally, if the surface associated with a session changes, this method should be called
+ * again to re-create the association.
+ *
+ * To see any benefit from this method, the client must make sure they are updating the frame rate
+ * of attached surfaces using methods such as {@link ANativeWindow_setFrameRate}, or by updating
+ * any associated ASurfaceControls with transactions that have {ASurfaceTransaction_setFrameRate}.
+ *
+ * @param session The {@link APerformanceHintSession} instance to update.
+ * @param nativeWindows A pointer to a list of ANativeWindows associated with this session.
+ * nullptr can be passed to indicate there are no associated ANativeWindows.
+ * @param nativeWindowsSize The number of ANativeWindows in the list.
+ * @param surfaceControls A pointer to a list of ASurfaceControls associated with this session.
+ * nullptr can be passed to indicate there are no associated ASurfaceControls.
+ * @param surfaceControlsSize The number of ASurfaceControls in the list.
+ *
+ * @return 0 on success.
+ * EPIPE if communication has failed.
+ * ENOTSUP if this is not supported on the device.
+ */
+
+int APerformanceHint_setNativeSurfaces(APerformanceHintSession* _Nonnull session,
+ ANativeWindow* _Nonnull* _Nullable nativeWindows, size_t nativeWindowsSize,
+ ASurfaceControl* _Nonnull* _Nullable surfaceControls, size_t surfaceControlsSize)
+ __INTRODUCED_IN(36);
+
+/**
+ * This enum represents different aspects of performance hint functionality. These can be passed
+ * to {@link APerformanceHint_isFeatureSupported} to determine whether the device exposes support
+ * for that feature.
+ *
+ * Some of these features will not expose failure to the client if used when unsupported, to prevent
+ * the client from needing to worry about handling different logic for each possible support
+ * configuration. The exception to this is features with important user-facing side effects, such as
+ * {@link APERF_HINT_AUTO_CPU} and {@link APERF_HINT_AUTO_GPU} modes which expect the client not to
+ * report durations while they are active.
+ */
+typedef enum APerformanceHintFeature : int32_t {
+ /**
+ * This value represents all APerformanceHintSession functionality. Using the Performance Hint
+ * API at all if this is not enabled will likely result in either
+ * {@link APerformanceHintManager} or {@link APerformanceHintSession} failing to create, or the
+ * session having little to no benefit even if creation succeeds.
+ */
+ APERF_HINT_SESSIONS,
+
+ /**
+ * This value represents the power efficiency mode, as exposed by
+ * {@link ASessionCreationConfig_setPreferPowerEfficiency} and
+ * {@link APerformanceHint_setPreferPowerEfficiency}.
+ */
+ APERF_HINT_POWER_EFFICIENCY,
+
+ /**
+ * This value the ability for sessions to bind to surfaces using
+ * {@link APerformanceHint_setNativeSurfaces} or
+ * {@link ASessionCreationConfig_setNativeSurfaces}
+ */
+ APERF_HINT_SURFACE_BINDING,
+
+ /**
+ * This value represents the "graphics pipeline" mode, as exposed by
+ * {@link ASessionCreationConfig_setGraphicsPipeline}.
+ */
+ APERF_HINT_GRAPHICS_PIPELINE,
+
+ /**
+ * This value represents the automatic CPU timing feature, as exposed by
+ * {@link ASessionCreationConfig_setUseAutoTiming}.
+ */
+ APERF_HINT_AUTO_CPU,
+
+ /**
+ * This value represents the automatic GPU timing feature, as exposed by
+ * {@link ASessionCreationConfig_setUseAutoTiming}.
+ */
+ APERF_HINT_AUTO_GPU,
+} APerformanceHintFeature;
+
+/**
+ * Checks whether the device exposes support for a specific feature.
+ *
+ * @param feature The specific feature enum to check.
+ *
+ * @return false if unsupported, true if supported.
+ */
+bool APerformanceHint_isFeatureSupported(APerformanceHintFeature feature) __INTRODUCED_IN(36);
+
+/**
* Creates a new AWorkDuration. When the client finishes using {@link AWorkDuration}, it should
* call {@link AWorkDuration_release()} to destroy {@link AWorkDuration} and release all resources
* associated with it.
*
- * @return AWorkDuration on success and nullptr otherwise.
+ * @return AWorkDuration pointer.
*/
AWorkDuration* _Nonnull AWorkDuration_create() __INTRODUCED_IN(__ANDROID_API_V__);
/**
- * Destroys {@link AWorkDuration} and free all resources associated to it.
+ * Destroys a {@link AWorkDuration} and frees all resources associated with it.
*
* @param aWorkDuration The {@link AWorkDuration} created by calling {@link AWorkDuration_create()}
*/
@@ -308,6 +576,168 @@ void AWorkDuration_setActualCpuDurationNanos(AWorkDuration* _Nonnull aWorkDurati
void AWorkDuration_setActualGpuDurationNanos(AWorkDuration* _Nonnull aWorkDuration,
int64_t actualGpuDurationNanos) __INTRODUCED_IN(__ANDROID_API_V__);
+/**
+ * Return the APerformanceHintSession wrapped by a Java PerformanceHintManager.Session object.
+ *
+ * The Java session maintains ownership over the wrapped native session, so it cannot be closed
+ * using {@link APerformanceHint_closeSession}. The return value is valid until the Java object
+ * containing this value dies.
+ *
+ * The returned pointer is intended to be used by JNI calls to access native performance APIs using
+ * a Java hint session wrapper, and then immediately discarded. Using the pointer after the death of
+ * the Java container results in undefined behavior.
+ *
+ * @param env The Java environment where the PerformanceHintManager.Session lives.
+ * @param sessionObj The Java Session to unwrap.
+ *
+ * @return A pointer to the APerformanceHintManager that backs the Java Session.
+ */
+APerformanceHintSession* _Nonnull APerformanceHint_borrowSessionFromJava(
+ JNIEnv* _Nonnull env, jobject _Nonnull sessionObj) __INTRODUCED_IN(36);
+
+/*
+ * Creates a new ASessionCreationConfig.
+ *
+ * When the client finishes using {@link ASessionCreationConfig}, it should
+ * call {@link ASessionCreationConfig_release()} to destroy
+ * {@link ASessionCreationConfig} and release all resources
+ * associated with it.
+ *
+ * @return ASessionCreationConfig pointer.
+ */
+ASessionCreationConfig* _Nonnull ASessionCreationConfig_create()
+ __INTRODUCED_IN(36);
+
+/**
+ * Destroys a {@link ASessionCreationConfig} and frees all
+ * resources associated with it.
+ *
+ * @param config The {@link ASessionCreationConfig}
+ * created by calling {@link ASessionCreationConfig_create()}.
+ */
+void ASessionCreationConfig_release(
+ ASessionCreationConfig* _Nonnull config) __INTRODUCED_IN(36);
+
+/**
+ * Sets the tids to be associated with the session to be created.
+ *
+ * @param config The {@link ASessionCreationConfig}
+ * created by calling {@link ASessionCreationConfig_create()}
+ * @param tids The list of tids to be associated with this session. They must be part of
+ * this process' thread group.
+ * @param size The size of the list of tids.
+ */
+void ASessionCreationConfig_setTids(
+ ASessionCreationConfig* _Nonnull config,
+ const pid_t* _Nonnull tids, size_t size) __INTRODUCED_IN(36);
+
+/**
+ * Sets the initial target work duration in nanoseconds for the session to be created.
+ *
+ * @param config The {@link ASessionCreationConfig}
+ * created by calling {@link ASessionCreationConfig_create()}.
+ * @param targetWorkDurationNanos The parameter to specify a target duration in nanoseconds for the
+ * new session; this value must be positive to use the work duration API, and may be ignored
+ * otherwise or set to zero. Negative values are invalid.
+ */
+void ASessionCreationConfig_setTargetWorkDurationNanos(
+ ASessionCreationConfig* _Nonnull config,
+ int64_t targetWorkDurationNanos) __INTRODUCED_IN(36);
+
+/**
+ * Sets whether power efficiency mode will be enabled for the session.
+ * This tells the session that these threads can be
+ * safely scheduled to prefer power efficiency over performance.
+ *
+ * @param config The {@link ASessionCreationConfig}
+ * created by calling {@link ASessionCreationConfig_create()}.
+ * @param enabled Whether power efficiency mode will be enabled.
+ */
+void ASessionCreationConfig_setPreferPowerEfficiency(
+ ASessionCreationConfig* _Nonnull config, bool enabled) __INTRODUCED_IN(36);
+
+/**
+ * Sessions setting this hint are expected to time the critical path of
+ * graphics pipeline from end to end, with the total work duration
+ * representing the time from the start of frame production until the
+ * buffer is fully finished drawing.
+ *
+ * It should include any threads on the critical path of that pipeline,
+ * up to a limit accessible from {@link APerformanceHint_getMaxGraphicsPipelineThreadsCount()}.
+ *
+ * @param config The {@link ASessionCreationConfig}
+ * created by calling {@link ASessionCreationConfig_create()}.
+ * @param enabled Whether this session manages a graphics pipeline's critical path.
+ */
+void ASessionCreationConfig_setGraphicsPipeline(
+ ASessionCreationConfig* _Nonnull config, bool enabled) __INTRODUCED_IN(36);
+
+/**
+ * Associates the created session with any {@link ASurfaceControl} or {@link ANativeWindow}
+ * instances it will be managing. Invalid or dead instances are ignored.
+ *
+ * This method is primarily intended for sessions that manage the timing of an entire
+ * graphics pipeline end-to-end for frame pacing, such as those using the
+ * {@link ASessionCreationConfig_setGraphicsPipeline} API. However, any session directly
+ * or indirectly managing a graphics pipeline should still associate themselves with
+ * directly relevant ASurfaceControl or ANativeWindow instances for better optimization.
+ * Additionally, if the surface associated with a session changes, this method should be called
+ * again to re-create the association.
+ *
+ * To see any benefit from this method, the client must make sure they are updating the frame rate
+ * of attached surfaces using methods such as {@link ANativeWindow_setFrameRate}, or by updating
+ * any associated ASurfaceControls with transactions that have {ASurfaceTransaction_setFrameRate}.
+ *
+ *
+ * @param config The {@link ASessionCreationConfig}
+ * created by calling {@link ASessionCreationConfig_create()}.
+ * @param nativeWindows A pointer to a list of ANativeWindows associated with this session.
+ * nullptr can be passed to indicate there are no associated ANativeWindows.
+ * @param nativeWindowsSize The number of ANativeWindows in the list.
+ * @param surfaceControls A pointer to a list of ASurfaceControls associated with this session.
+ * nullptr can be passed to indicate there are no associated ASurfaceControls.
+ * @param surfaceControlsSize The number of ASurfaceControls in the list.
+ */
+void ASessionCreationConfig_setNativeSurfaces(
+ ASessionCreationConfig* _Nonnull config,
+ ANativeWindow* _Nonnull* _Nullable nativeWindows, size_t nativeWindowsSize,
+ ASurfaceControl* _Nonnull* _Nullable surfaceControls, size_t surfaceControlsSize)
+ __INTRODUCED_IN(36);
+
+/**
+ * Enable automatic timing mode for sessions using the GRAPHICS_PIPELINE API with an attached
+ * surface. In this mode, sessions do not need to report timing data for the CPU, GPU, or both
+ * depending on the configuration. To use this mode, sessions should set a native surface
+ * using {@ASessionCreationConfig_setNativeSurfaces}, enable graphics pipeline mode with
+ * {@link ASessionCreationConfig_setGraphicsPipeline()}, and then call this method to set whether
+ * automatic timing is desired for the CPU, GPU, or both. Trying to enable this without also
+ * enabling the graphics pipeline mode will cause session creation to fail.
+ *
+ * It is still be beneficial to set an accurate target time, as this may help determine
+ * timing information for some workloads where there is less information available from
+ * the framework, such as games. Additionally, reported CPU durations will be ignored
+ * while automatic CPU timing is enabled, and similarly GPU durations will be ignored
+ * when automatic GPU timing is enabled. When both are enabled, the entire
+ * {@link APerformanceHint_reportActualWorkDuration} call will be ignored, and the session will be
+ * managed completely automatically.
+ *
+ * If the client is manually controlling their frame rate for those surfaces, then they must make
+ * sure they are updating the frame rate with {@link ANativeWindow_setFrameRate}, or updating any
+ * associated ASurfaceControls with transactions that have {ASurfaceTransaction_setFrameRate} set.
+ *
+ * The user of this API should ensure this feature is supported by checking
+ * {@link APERF_HINT_AUTO_CPU} and {@link APERF_HINT_AUTO_GPU} with
+ * {@link APerformanceHint_isFeatureSupported} and falling back to manual timing if it is not.
+ * Trying to use automatic timing when it is unsupported will cause session creation to fail.
+ *
+ * @param config The {@link ASessionCreationConfig}
+ * created by calling {@link ASessionCreationConfig_create()}.
+ * @param cpu Whether to enable automatic timing for the CPU for this session.
+ * @param gpu Whether to enable automatic timing for the GPU for this session.
+ */
+void ASessionCreationConfig_setUseAutoTiming(
+ ASessionCreationConfig* _Nonnull config, bool cpu, bool gpu) __INTRODUCED_IN(36);
+
__END_DECLS
#endif // ANDROID_NATIVE_PERFORMANCE_HINT_H
diff --git a/include/android/surface_control.h b/include/android/surface_control.h
index bf9acb37da..6323333429 100644
--- a/include/android/surface_control.h
+++ b/include/android/surface_control.h
@@ -28,6 +28,7 @@
#include <sys/cdefs.h>
+#include <android/display_luts.h>
#include <android/choreographer.h>
#include <android/data_space.h>
#include <android/hardware_buffer.h>
@@ -156,8 +157,6 @@ typedef struct ASurfaceTransactionStats ASurfaceTransactionStats;
*
* THREADING
* The transaction completed callback can be invoked on any thread.
- *
- * Available since API level 29.
*/
typedef void (*ASurfaceTransaction_OnComplete)(void* _Null_unspecified context,
ASurfaceTransactionStats* _Nonnull stats);
@@ -184,8 +183,6 @@ typedef void (*ASurfaceTransaction_OnComplete)(void* _Null_unspecified context,
*
* THREADING
* The transaction committed callback can be invoked on any thread.
- *
- * Available since API level 31.
*/
typedef void (*ASurfaceTransaction_OnCommit)(void* _Null_unspecified context,
ASurfaceTransactionStats* _Nonnull stats);
@@ -213,8 +210,6 @@ typedef void (*ASurfaceTransaction_OnCommit)(void* _Null_unspecified context,
*
* THREADING
* The callback can be invoked on any thread.
- *
- * Available since API level 36.
*/
typedef void (*ASurfaceTransaction_OnBufferRelease)(void* _Null_unspecified context,
int release_fence_fd);
@@ -719,6 +714,23 @@ void ASurfaceTransaction_setDesiredHdrHeadroom(ASurfaceTransaction* _Nonnull tra
__INTRODUCED_IN(__ANDROID_API_V__);
/**
+ * Sets the Lut(s) to be applied for the layer.
+ *
+ * The function makes a deep copy of the provided `luts`.
+ * Any modifications made to the `luts` object after calling this function
+ * will not affect the Lut(s) applied to the layer.
+ *
+ * @param surface_control The layer where Lut(s) is being applied
+ * @param luts The Lut(s) to be applied
+ *
+ * Available since API level 36.
+ */
+void ASurfaceTransaction_setLuts(ASurfaceTransaction* _Nonnull transaction,
+ ASurfaceControl* _Nonnull surface_control,
+ const struct ADisplayLuts* _Nullable luts)
+ __INTRODUCED_IN(36);
+
+/**
* Same as ASurfaceTransaction_setFrameRateWithChangeStrategy(transaction, surface_control,
* frameRate, compatibility, ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS).
*
diff --git a/include/android/surface_control_input_receiver.h b/include/android/surface_control_input_receiver.h
index f0503f6324..59d3a31b30 100644
--- a/include/android/surface_control_input_receiver.h
+++ b/include/android/surface_control_input_receiver.h
@@ -39,11 +39,11 @@ __BEGIN_DECLS
*
* \param motionEvent The motion event. This must be released with AInputEvent_release.
*
+ * \return true if the event is handled by the client, false otherwise.
* Available since API level 35.
*/
typedef bool (*AInputReceiver_onMotionEvent)(void *_Null_unspecified context,
- AInputEvent *_Nonnull motionEvent)
- __INTRODUCED_IN(__ANDROID_API_V__);
+ AInputEvent *_Nonnull motionEvent);
/**
* The AInputReceiver_onKeyEvent callback is invoked when the registered input channel receives
* a key event.
@@ -53,11 +53,12 @@ typedef bool (*AInputReceiver_onMotionEvent)(void *_Null_unspecified context,
*
* \param keyEvent The key event. This must be released with AInputEvent_release.
*
+ * \return true if the event is handled by the client, false otherwise. System may generate
+ * a fallback key event if the event is not handled.
* Available since API level 35.
*/
typedef bool (*AInputReceiver_onKeyEvent)(void *_Null_unspecified context,
- AInputEvent *_Nonnull keyEvent)
- __INTRODUCED_IN(__ANDROID_API_V__);
+ AInputEvent *_Nonnull keyEvent);
typedef struct AInputReceiverCallbacks AInputReceiverCallbacks;
diff --git a/include/android/system_health.h b/include/android/system_health.h
new file mode 100644
index 0000000000..6d59706490
--- /dev/null
+++ b/include/android/system_health.h
@@ -0,0 +1,449 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+* @defgroup SystemHealth
+*
+ * SystemHealth provides access to data about how various system resources are used by applications.
+ *
+ * CPU/GPU headroom APIs are designed to be best used by applications with consistent and intense
+ * workload such as games to query the remaining capacity headroom over a short period and perform
+ * optimization accordingly. Due to the nature of the fast job scheduling and frequency scaling of
+ * CPU and GPU, the headroom by nature will have "TOCTOU" problem which makes it less suitable for
+ * apps with inconsistent or low workload to take any useful action but simply monitoring. And to
+ * avoid oscillation it's not recommended to adjust workload too frequent (on each polling request)
+ * or too aggressively. As the headroom calculation is more based on reflecting past history usage
+ * than predicting future capacity. Take game as an example, if the API returns CPU headroom of 0 in
+ * one scenario (especially if it's constant across multiple calls), or some value significantly
+ * smaller than other scenarios, then it can reason that the recent performance result is more CPU
+ * bottlenecked. Then reducing the CPU workload intensity can help reserve some headroom to handle
+ * the load variance better, which can result in less frame drops or smooth FPS value. On the other
+ * hand, if the API returns large CPU headroom constantly, the app can be more confident to increase
+ * the workload and expect higher possibility of device meeting its performance expectation.
+ * App can also use thermal APIs to read the current thermal status and headroom first, then poll
+ * the CPU and GPU headroom if the device is (about to) getting thermal throttled. If the CPU/GPU
+ * headrooms provide enough significance such as one valued at 0 while the other at 100, then it can
+ * be used to infer that reducing CPU workload could be more efficient to cool down the device.
+ * There is a caveat that the power controller may scale down the frequency of the CPU and GPU due
+ * to thermal and other reasons, which can result in a higher than usual percentage usage of the
+ * capacity.
+ *
+* @{
+*/
+
+/**
+ * @file system_health.h
+ */
+
+#ifndef _ANDROID_SYSTEM_HEALTH_H
+#define _ANDROID_SYSTEM_HEALTH_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 <stdint.h>
+#include <sys/types.h>
+
+#if !defined(__INTRODUCED_IN)
+#define __INTRODUCED_IN(__api_level) /* nothing */
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Params used to customize the calculation of CPU headroom.
+ *
+ * Also see {@link ASystemHealth_getCpuHeadroom}.
+ */
+typedef struct ACpuHeadroomParams ACpuHeadroomParams;
+
+/**
+ * Params used to customize the calculation of GPU headroom.
+ *
+ * Also see {@link ASystemHealth_getGpuHeadroom}.
+ */
+typedef struct AGpuHeadroomParams AGpuHeadroomParams;
+
+typedef enum ACpuHeadroomCalculationType : int32_t {
+ /**
+ * The headroom calculation type bases on minimum value over a specified window.
+ * Introduced in API level 36.
+ */
+ ACPU_HEADROOM_CALCULATION_TYPE_MIN = 0,
+ /**
+ * The headroom calculation type bases on average value over a specified window.
+ * Introduced in API level 36.
+ */
+ ACPU_HEADROOM_CALCULATION_TYPE_AVERAGE = 1,
+} ACpuHeadroomCalculationType;
+
+typedef enum AGpuHeadroomCalculationType : int32_t {
+ /**
+ * The headroom calculation type bases on minimum value over a specified window.
+ * Introduced in API level 36.
+ */
+ AGPU_HEADROOM_CALCULATION_TYPE_MIN = 0,
+ /**
+ * The headroom calculation type bases on average value over a specified window.
+ * Introduced in API level 36.
+ */
+ AGPU_HEADROOM_CALCULATION_TYPE_AVERAGE = 1,
+} AGpuHeadroomCalculationType;
+
+/**
+ * Sets the CPU headroom calculation window size in milliseconds.
+ *
+ * Available since API level 36.
+ *
+ * @param params The params to be set.
+ * @param windowMillis The window size in milliseconds ranges from
+ * {@link ASystemHealth_getCpuHeadroomCalculationWindowRange}. The smaller the
+ * window size, the larger fluctuation in the headroom value should be expected.
+ * The default value can be retrieved from the
+ * {@link #ACpuHeadroomParams_getCalculationWindowMillis} if not set. The device
+ * will try to use the closest feasible window size to this param.
+ */
+void ACpuHeadroomParams_setCalculationWindowMillis(ACpuHeadroomParams *_Nonnull params,
+ int windowMillis)
+__INTRODUCED_IN(36);
+
+/**
+ * Gets the CPU headroom calculation window size in milliseconds.
+ *
+ * This will return the default value chosen by the device if not set.
+ *
+ * Available since API level 36.
+ *
+ * @param params The params to read from.
+ * @return This will return the default value chosen by the device if the params is not set.
+ */
+int ACpuHeadroomParams_getCalculationWindowMillis(ACpuHeadroomParams* _Nonnull params)
+__INTRODUCED_IN(36);
+
+/**
+ * Sets the GPU headroom calculation window size in milliseconds.
+ *
+ * Available since API level 36.
+ *
+ * @param params The params to be set.
+ * @param windowMillis The window size in milliseconds ranges from
+ * {@link ASystemHealth_getGpuHeadroomCalculationWindowRange}. The smaller the
+ * window size, the larger fluctuation in the headroom value should be expected.
+ * The default value can be retrieved from the
+ * {@link #AGpuHeadroomParams_getCalculationWindowMillis} if not set. The device
+ * will try to use the closest feasible window size to this param.
+ */
+void AGpuHeadroomParams_setCalculationWindowMillis(AGpuHeadroomParams* _Nonnull params,
+ int windowMillis)
+__INTRODUCED_IN(36);
+
+/**
+ * Gets the GPU headroom calculation window size in milliseconds.
+ *
+ * This will return the default value chosen by the device if not set.
+ *
+ * Available since API level 36.
+ *
+ * @param params The params to read from.
+ * @return This will return the default value chosen by the device if the params is not set.
+ */
+int AGpuHeadroomParams_getCalculationWindowMillis(AGpuHeadroomParams* _Nonnull params)
+__INTRODUCED_IN(36);
+
+/**
+ * Sets the CPU headroom calculation type in {@link ACpuHeadroomParams}.
+ *
+ * Available since API level 36.
+ *
+ * @param params The params to be set.
+ * @param calculationType The headroom calculation type.
+ */
+void ACpuHeadroomParams_setCalculationType(ACpuHeadroomParams* _Nonnull params,
+ ACpuHeadroomCalculationType calculationType)
+__INTRODUCED_IN(36);
+
+/**
+ * Gets the CPU headroom calculation type in {@link ACpuHeadroomParams}.
+ *
+ * This will return the default value chosen by the device if not set.
+ *
+ * Available since API level 36.
+ *
+ * @param params The params to read from.
+ * @return The headroom calculation type.
+ */
+ACpuHeadroomCalculationType
+ACpuHeadroomParams_getCalculationType(ACpuHeadroomParams* _Nonnull params)
+__INTRODUCED_IN(36);
+
+/**
+ * Sets the GPU headroom calculation type in {@link AGpuHeadroomParams}.
+ *
+ * Available since API level 36.
+ *
+ * @param params The params to be set.
+ * @param calculationType The headroom calculation type.
+ */
+void AGpuHeadroomParams_setCalculationType(AGpuHeadroomParams* _Nonnull params,
+ AGpuHeadroomCalculationType calculationType)
+__INTRODUCED_IN(36);
+
+/**
+ * Gets the GPU headroom calculation type in {@link AGpuHeadroomParams}.
+ *
+ * This will return the default value chosen by the device if not set.
+ *
+ * Available since API level 36.
+ *
+ * @param params The params to read from.
+ * @return The headroom calculation type.
+ */
+AGpuHeadroomCalculationType
+AGpuHeadroomParams_getCalculationType(AGpuHeadroomParams* _Nonnull params)
+__INTRODUCED_IN(36);
+
+/**
+ * Sets the thread TIDs to track in {@link ACpuHeadroomParams}.
+ *
+ * The TIDs should belong to the same of the process that will make the headroom call. And they
+ * should not have different core affinity.
+ *
+ * If not set or set to empty, the headroom will be based on the PID of the process making the call.
+ *
+ * Available since API level 36.
+ *
+ * @param params The params to be set.
+ * @param tids Non-null array of TIDs, where maximum size can be read from
+ * {@link ASystemHealth_getMaxCpuHeadroomTidsSize}.
+ * @param tidsSize The size of the tids array.
+ */
+void ACpuHeadroomParams_setTids(ACpuHeadroomParams* _Nonnull params, const int* _Nonnull tids,
+ size_t tidsSize)
+__INTRODUCED_IN(36);
+
+/**
+ * Creates a new instance of {@link ACpuHeadroomParams}.
+ *
+ * When the client finishes using {@link ACpuHeadroomParams},
+ * {@link ACpuHeadroomParams_destroy} must be called to destroy
+ * and free up the resources associated with {@link ACpuHeadroomParams}.
+ *
+ * Available since API level 36.
+ *
+ * @return A new instance of {@link ACpuHeadroomParams}.
+ */
+ACpuHeadroomParams* _Nonnull ACpuHeadroomParams_create(void)
+__INTRODUCED_IN(36);
+
+/**
+ * Creates a new instance of {@link AGpuHeadroomParams}.
+ *
+ * When the client finishes using {@link AGpuHeadroomParams},
+ * {@link AGpuHeadroomParams_destroy} must be called to destroy
+ * and free up the resources associated with {@link AGpuHeadroomParams}.
+ *
+ * Available since API level 36.
+ *
+ * @return A new instance of {@link AGpuHeadroomParams}.
+ */
+AGpuHeadroomParams* _Nonnull AGpuHeadroomParams_create(void)
+__INTRODUCED_IN(36);
+
+/**
+ * Deletes the {@link ACpuHeadroomParams} instance.
+ *
+ * Available since API level 36.
+ *
+ * @param params The params to be deleted.
+ */
+void ACpuHeadroomParams_destroy(ACpuHeadroomParams* _Nullable params)
+__INTRODUCED_IN(36);
+
+/**
+ * Deletes the {@link AGpuHeadroomParams} instance.
+ *
+ * Available since API level 36.
+ *
+ * @param params The params to be deleted.
+ */
+void AGpuHeadroomParams_destroy(AGpuHeadroomParams* _Nullable params)
+__INTRODUCED_IN(36);
+
+/**
+ * Gets the maximum number of TIDs this device supports for getting CPU headroom.
+ *
+ * See {@link ACpuHeadroomParams_setTids}.
+ *
+ * Available since API level 36.
+ *
+ * @param outSize Non-null output pointer to the max size.
+ * @return 0 on success.
+ * ENOTSUP if the CPU headroom API is unsupported.
+ */
+int ASystemHealth_getMaxCpuHeadroomTidsSize(size_t* _Nonnull outSize);
+
+/**
+ * Gets the range of the calculation window size for CPU headroom.
+ *
+ * In API version 36, the range will be a superset of [50, 10000].
+ *
+ * Available since API level 36.
+ *
+ * @param outMinMillis Non-null output pointer to be set to the minimum window size in milliseconds.
+ * @param outMaxMillis Non-null output pointer to be set to the maximum window size in milliseconds.
+ * @return 0 on success.
+ * ENOTSUP if API is unsupported.
+ */
+int ASystemHealth_getCpuHeadroomCalculationWindowRange(int32_t* _Nonnull outMinMillis,
+ int32_t* _Nonnull outMaxMillis)
+__INTRODUCED_IN(36);
+
+/**
+ * Gets the range of the calculation window size for GPU headroom.
+ *
+ * In API version 36, the range will be a superset of [50, 10000].
+ *
+ * Available since API level 36.
+ *
+ * @param outMinMillis Non-null output pointer to be set to the minimum window size in milliseconds.
+ * @param outMaxMillis Non-null output pointer to be set to the maximum window size in milliseconds.
+ * @return 0 on success.
+ * ENOTSUP if API is unsupported.
+ */
+int ASystemHealth_getGpuHeadroomCalculationWindowRange(int32_t* _Nonnull outMinMillis,
+ int32_t* _Nonnull outMaxMillis)
+__INTRODUCED_IN(36);
+
+/**
+ * Provides an estimate of available CPU capacity headroom of the device.
+ *
+ * The value can be used by the calling application to determine if the workload was CPU bound and
+ * then take action accordingly to ensure that the workload can be completed smoothly. It can also
+ * be used with the thermal status and headroom to determine if reducing the CPU bound workload can
+ * help reduce the device temperature to avoid thermal throttling.
+ *
+ * If the params are valid, each call will perform at least one synchronous binder transaction that
+ * can take more than 1ms. So it's not recommended to call or wait for this on critical threads.
+ * Some devices may implement this as an on-demand API with lazy initialization, so the caller
+ * should expect higher latency when making the first call (especially with non-default params)
+ * since app starts or after changing params, as the device may need to change its data collection.
+ *
+ * Available since API level 36.
+ *
+ * @param params The params to customize the CPU headroom calculation, or nullptr to use default.
+ * @param outHeadroom Non-null output pointer to a single float, which will be set to the CPU
+ * headroom value. The value will be a single value or `Float.NaN` if it's
+ * temporarily unavailable due to server error or not enough user CPU workload.
+ * Each valid value ranges from [0, 100], where 0 indicates no more cpu resources
+ * can be granted.
+ * @return 0 on success.
+ * EPIPE if failed to get the CPU headroom.
+ * EPERM if the TIDs do not belong to the same process.
+ * ENOTSUP if API or requested params is unsupported.
+ */
+int ASystemHealth_getCpuHeadroom(const ACpuHeadroomParams* _Nullable params,
+ float* _Nonnull outHeadroom)
+__INTRODUCED_IN(36);
+
+/**
+ * Provides an estimate of available GPU capacity headroom of the device.
+ *
+ * The value can be used by the calling application to determine if the workload was GPU bound and
+ * then take action accordingly to ensure that the workload can be completed smoothly. It can also
+ * be used with the thermal status and headroom to determine if reducing the GPU bound workload can
+ * help reduce the device temperature to avoid thermal throttling.
+ *
+ * If the params are valid, each call will perform at least one synchronous binder transaction that
+ * can take more than 1ms. So it's not recommended to call or wait for this on critical threads.
+ * Some devices may implement this as an on-demand API with lazy initialization, so the caller
+ * should expect higher latency when making the first call (especially with non-default params)
+ * since app starts or after changing params, as the device may need to change its data collection.
+ *
+ * Available since API level 36
+ *
+ * @param params The params to customize the GPU headroom calculation, or nullptr to use default
+ * @param outHeadroom Non-null output pointer to a single float, which will be set to the GPU
+ * headroom value. The value will be a single value or `Float.NaN` if it's
+ * temporarily unavailable.
+ * Each valid value ranges from [0, 100], where 0 indicates no more gpu resources
+ * can be granted.
+ * @return 0 on success.
+ * EPIPE if failed to get the GPU headroom.
+ * ENOTSUP if API or requested params is unsupported.
+ */
+int ASystemHealth_getGpuHeadroom(const AGpuHeadroomParams* _Nullable params,
+ float* _Nonnull outHeadroom)
+__INTRODUCED_IN(36);
+
+/**
+ * Gets minimum polling interval for calling {@link ASystemHealth_getCpuHeadroom} in milliseconds.
+ *
+ * The {@link ASystemHealth_getCpuHeadroom} API may return cached result if called more frequently
+ * than the interval.
+ *
+ * Available since API level 36.
+ *
+ * @param outMinIntervalMillis Non-null output pointer to a int64_t, which
+ * will be set to the minimum polling interval in milliseconds.
+ * @return 0 on success.
+ * EPIPE if failed to get the minimum polling interval.
+ * ENOTSUP if API is unsupported.
+ */
+int ASystemHealth_getCpuHeadroomMinIntervalMillis(int64_t* _Nonnull outMinIntervalMillis)
+__INTRODUCED_IN(36);
+
+/**
+ * Gets minimum polling interval for calling {@link ASystemHealth_getGpuHeadroom} in milliseconds.
+ *
+ * The {@link ASystemHealth_getGpuHeadroom} API may return cached result if called more frequently
+ * than the interval.
+ *
+ * Available since API level 36.
+ *
+ * @param outMinIntervalMillis Non-null output pointer to a int64_t, which
+ * will be set to the minimum polling interval in milliseconds.
+ * @return 0 on success.
+ * EPIPE if failed to get the minimum polling interval.
+ * ENOTSUP if API is unsupported.
+ */
+int ASystemHealth_getGpuHeadroomMinIntervalMillis(int64_t* _Nonnull outMinIntervalMillis)
+__INTRODUCED_IN(36);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // _ANDROID_SYSTEM_HEALTH_H
+
+/** @} */
diff --git a/include/android/thermal.h b/include/android/thermal.h
index 1d7ad12294..e5d46b5b8a 100644
--- a/include/android/thermal.h
+++ b/include/android/thermal.h
@@ -140,45 +140,47 @@ void AThermal_releaseManager(AThermalManager* _Nonnull manager) __INTRODUCED_IN(
* Available since API level 30.
*
* @param manager The manager instance to use to query the thermal status.
- * Acquired via {@link AThermal_acquireManager}.
+ * Acquired via {@link AThermal_acquireManager}.
*
* @return current thermal status, ATHERMAL_STATUS_ERROR on failure.
*/
AThermalStatus
-AThermal_getCurrentThermalStatus(AThermalManager* _Nonnull manager) __INTRODUCED_IN(30);
+AThermal_getCurrentThermalStatus(AThermalManager *_Nonnull manager) __INTRODUCED_IN(30);
/**
- * Register the thermal status listener for thermal status change.
+ * Register a thermal status listener for thermal status change.
*
* Available since API level 30.
*
* @param manager The manager instance to use to register.
- * Acquired via {@link AThermal_acquireManager}.
- * @param callback The callback function to be called when thermal status updated.
+ * Acquired via {@link AThermal_acquireManager}.
+ * @param callback The callback function to be called on system binder thread pool when thermal
+ * status updated.
* @param data The data pointer to be passed when callback is called.
*
* @return 0 on success
* EINVAL if the listener and data pointer were previously added and not removed.
- * EPERM if the required permission is not held.
- * EPIPE if communication with the system service has failed.
+ * EPIPE if communication with the system service has failed, the listener will not get
+ * removed and this call should be retried
*/
-int AThermal_registerThermalStatusListener(AThermalManager* _Nonnull manager,
+int AThermal_registerThermalStatusListener(AThermalManager *_Nonnull manager,
AThermal_StatusCallback _Nullable callback,
void* _Nullable data) __INTRODUCED_IN(30);
/**
- * Unregister the thermal status listener previously resgistered.
+ * Unregister a thermal status listener previously registered.
+ *
+ * No subsequent invocations of the callback will occur after this function returns successfully.
*
* Available since API level 30.
*
* @param manager The manager instance to use to unregister.
- * Acquired via {@link AThermal_acquireManager}.
- * @param callback The callback function to be called when thermal status updated.
+ * Acquired via {@link AThermal_acquireManager}.
+ * @param callback The callback function that was previously registered.
* @param data The data pointer to be passed when callback is called.
*
* @return 0 on success
* EINVAL if the listener and data pointer were not previously added.
- * EPERM if the required permission is not held.
* EPIPE if communication with the system service has failed.
*/
int AThermal_unregisterThermalStatusListener(AThermalManager* _Nonnull manager,
@@ -254,7 +256,7 @@ typedef struct AThermalHeadroomThreshold AThermalHeadroomThreshold;
* The headroom threshold is used to interpret the possible thermal throttling status based on
* the headroom prediction. For example, if the headroom threshold for
* {@link ATHERMAL_STATUS_LIGHT} is 0.7, and a headroom prediction in 10s returns 0.75
- * (or `AThermal_getThermalHeadroom(10)=0.75`), one can expect that in 10 seconds the system
+ * (or `AThermal_getThermalHeadroom(10)=0.75}`, one can expect that in 10 seconds the system
* could be in lightly throttled state if the workload remains the same. The app can consider
* taking actions according to the nearest throttling status the difference between the headroom and
* the threshold.
@@ -262,7 +264,7 @@ typedef struct AThermalHeadroomThreshold AThermalHeadroomThreshold;
* For new devices it's guaranteed to have a single sensor, but for older devices with multiple
* sensors reporting different threshold values, the minimum threshold is taken to be conservative
* on predictions. Thus, when reading real-time headroom, it's not guaranteed that a real-time value
- * of 0.75 (or `AThermal_getThermalHeadroom(0)`=0.75) exceeding the threshold of 0.7 above
+ * of 0.75 (or `AThermal_getThermalHeadroom(0)=0.75`) exceeding the threshold of 0.7 above
* will always come with lightly throttled state
* (or `AThermal_getCurrentThermalStatus()=ATHERMAL_STATUS_LIGHT`) but it can be lower
* (or `AThermal_getCurrentThermalStatus()=ATHERMAL_STATUS_NONE`).
@@ -271,15 +273,21 @@ typedef struct AThermalHeadroomThreshold AThermalHeadroomThreshold;
* {@link #ATHERMAL_STATUS_MODERATE} but always lower, and 0.65 will never come with
* {@link ATHERMAL_STATUS_LIGHT} but {@link #ATHERMAL_STATUS_NONE}.
* <p>
- * The returned list of thresholds is cached on first successful query and owned by the thermal
- * manager, which will not change between calls to this function. The caller should only need to
- * free the manager with {@link AThermal_releaseManager}.
+ * Starting in Android 16, this polling API may return different results when called depending on
+ * the device. The new headroom listener API {@link #AThermal_HeadroomCallback} can be used to
+ * detect headroom thresholds changes.
+ * <p>
+ * Before API level 36 the returned list of thresholds is cached on first successful query and owned
+ * by the thermal manager, which will not change between calls to this function. The caller should
+ * only need to free the manager with {@link AThermal_releaseManager}.
+ * <p>
*
* @param manager The manager instance to use.
* Acquired via {@link AThermal_acquireManager}.
* @param outThresholds non-null output pointer to null AThermalHeadroomThreshold pointer, which
- * will be set to the cached array of thresholds if thermal thresholds are supported
- * by the system or device, otherwise nullptr or unmodified.
+ * will be set to a new array of thresholds if thermal thresholds are supported
+ * by the system or device, otherwise nullptr or unmodified. The client should
+ * clean up the thresholds by array-deleting the threshold pointer.
* @param size non-null output pointer whose value will be set to the size of the threshold array
* or 0 if it's not supported.
* @return 0 on success
@@ -292,6 +300,71 @@ int AThermal_getThermalHeadroomThresholds(AThermalManager* _Nonnull manager,
* _Nullable outThresholds,
size_t* _Nonnull size) __INTRODUCED_IN(35);
+/**
+ * Prototype of the function that is called when thermal headroom or thresholds changes.
+ * It's passed the updated thermal headroom and thresholds as parameters, as well as the
+ * pointer provided by the client that registered a callback.
+ *
+ * @param data The data pointer to be passed when callback is called.
+ * @param headroom The current non-negative normalized headroom value, also see
+ * {@link AThermal_getThermalHeadroom}.
+ * @param forecastHeadroom The forecasted non-negative normalized headroom value, also see
+ * {@link AThermal_getThermalHeadroom}.
+ * @param forecastSeconds The seconds used for the forecast by the system.
+ * @param thresholds The current headroom thresholds. The thresholds pointer will be a constant
+ * shared across all callbacks registered from the same process, and it will be
+ * destroyed after all the callbacks are finished. If the client intents to
+ * persist the values, it should make a copy of it during the callback.
+ * @param thresholdsCount The count of thresholds.
+ */
+typedef void (*AThermal_HeadroomCallback)(void *_Nullable data,
+ float headroom,
+ float forecastHeadroom,
+ int forecastSeconds,
+ const AThermalHeadroomThreshold* _Nullable thresholds,
+ size_t thresholdsCount);
+
+/**
+ * Register a thermal headroom listener for thermal headroom or thresholds change.
+ *
+ * Available since API level 36.
+ *
+ * @param manager The manager instance to use to register.
+ * Acquired via {@link AThermal_acquireManager}.
+ * @param callback The callback function to be called on system binder thread pool when thermal
+ * headroom or thresholds update.
+ * @param data The data pointer to be passed when callback is called.
+ *
+ * @return 0 on success
+ * EINVAL if the listener and data pointer were previously added and not removed.
+ * EPIPE if communication with the system service has failed.
+ */
+int AThermal_registerThermalHeadroomListener(AThermalManager* _Nonnull manager,
+ AThermal_HeadroomCallback _Nullable callback,
+ void* _Nullable data) __INTRODUCED_IN(36);
+
+/**
+ * Unregister a thermal headroom listener previously registered.
+ *
+ * No subsequent invocations of the callback will occur after this function returns successfully.
+ *
+ * Available since API level 36.
+ *
+ * @param manager The manager instance to use to unregister.
+ * Acquired via {@link AThermal_acquireManager}.
+ * @param callback The callback function that was previously registered.
+ * @param data The data pointer that was previously registered.
+ *
+ * @return 0 on success
+ * EINVAL if the listener and data pointer were not previously added.
+ * EPIPE if communication with the system service has failed, the listener will not get
+ * removed and this call should be retried
+ */
+
+int AThermal_unregisterThermalHeadroomListener(AThermalManager* _Nonnull manager,
+ AThermal_HeadroomCallback _Nullable callback,
+ void* _Nullable data) __INTRODUCED_IN(36);
+
#ifdef __cplusplus
}
#endif
diff --git a/include/audiomanager/AudioManager.h b/include/audiomanager/AudioManager.h
index 43048dbff0..203623dea7 100644
--- a/include/audiomanager/AudioManager.h
+++ b/include/audiomanager/AudioManager.h
@@ -22,6 +22,7 @@ namespace android {
// must be kept in sync with definitions in AudioPlaybackConfiguration.java
#define PLAYER_PIID_INVALID -1
+// TODO (b/309532236) remove manual IAudioManager impl in favor of AIDL.
typedef enum {
PLAYER_TYPE_SLES_AUDIOPLAYER_BUFFERQUEUE = 11,
PLAYER_TYPE_SLES_AUDIOPLAYER_URI_FD = 12,
@@ -59,6 +60,8 @@ enum {
PLAYER_MUTE_PLAYBACK_RESTRICTED = (1 << 3),
PLAYER_MUTE_CLIENT_VOLUME = (1 << 4),
PLAYER_MUTE_VOLUME_SHAPER = (1 << 5),
+ PLAYER_MUTE_PORT_VOLUME = (1 << 6),
+ PLAYER_MUTE_OP_AUDIO_CONTROL = (1 << 7),
};
struct mute_state_t {
@@ -72,8 +75,12 @@ struct mute_state_t {
bool muteFromPlaybackRestricted = false;
/** Flag used when audio track was muted by client volume. */
bool muteFromClientVolume = false;
- /** Flag used when volume is muted by volume shaper. */
+ /** Flag used when volume is muted by volume shaper. */
bool muteFromVolumeShaper = false;
+ /** Flag used when volume is muted by port volume. */
+ bool muteFromPortVolume = false;
+ /** Flag used when volume is muted by audio control op. */
+ bool muteFromOpAudioControl = false;
explicit operator int() const
{
@@ -83,6 +90,8 @@ struct mute_state_t {
result |= muteFromPlaybackRestricted * PLAYER_MUTE_PLAYBACK_RESTRICTED;
result |= muteFromClientVolume * PLAYER_MUTE_CLIENT_VOLUME;
result |= muteFromVolumeShaper * PLAYER_MUTE_VOLUME_SHAPER;
+ result |= muteFromPortVolume * PLAYER_MUTE_PORT_VOLUME;
+ result |= muteFromOpAudioControl * PLAYER_MUTE_OP_AUDIO_CONTROL;
return result;
}
diff --git a/include/audiomanager/IAudioManager.h b/include/audiomanager/IAudioManager.h
index 0b7e16bc7d..a35a145084 100644
--- a/include/audiomanager/IAudioManager.h
+++ b/include/audiomanager/IAudioManager.h
@@ -56,7 +56,7 @@ public:
/*oneway*/ virtual status_t playerAttributes(audio_unique_id_t piid, audio_usage_t usage,
audio_content_type_t content)= 0;
/*oneway*/ virtual status_t playerEvent(audio_unique_id_t piid, player_state_t event,
- audio_port_handle_t eventId) = 0;
+ const std::vector<audio_port_handle_t>& eventIds) = 0;
/*oneway*/ virtual status_t releasePlayer(audio_unique_id_t piid) = 0;
virtual audio_unique_id_t trackRecorder(const sp<IBinder>& recorder) = 0;
/*oneway*/ virtual status_t recorderEvent(audio_unique_id_t riid, recorder_state_t event) = 0;
diff --git a/include/ftl/finalizer.h b/include/ftl/finalizer.h
new file mode 100644
index 0000000000..0251957ad0
--- /dev/null
+++ b/include/ftl/finalizer.h
@@ -0,0 +1,211 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <cstddef>
+
+#include <functional>
+#include <type_traits>
+#include <utility>
+
+#include <ftl/function.h>
+
+namespace android::ftl {
+
+// An RAII wrapper that invokes a function object as a finalizer when destroyed.
+//
+// The function object must take no arguments, and must return void. If the function object needs
+// any context for the call, it must store it itself, for example with a lambda capture.
+//
+// The stored function object will be called once (unless canceled via the `cancel()` member
+// function) at the first of:
+//
+// - The Finalizer instance is destroyed.
+// - `operator()` is used to invoke the contained function.
+// - The Finalizer instance is move-assigned a new value. The function being replaced will be
+// invoked, and the replacement will be stored to be called later.
+//
+// The intent with this class is to keep cleanup code next to the code that requires that
+// cleanup be performed.
+//
+// bool read_file(std::string filename) {
+// FILE* f = fopen(filename.c_str(), "rb");
+// if (f == nullptr) return false;
+// const auto cleanup = ftl::Finalizer([f]() { fclose(f); });
+// // fread(...), etc
+// return true;
+// }
+//
+// The `FinalFunction` template argument to Finalizer<FinalFunction> allows a polymorphic function
+// type for storing the finalization function, such as `std::function` or `ftl::Function`.
+//
+// For convenience, this header defines a few useful aliases for using those types.
+//
+// - `FinalizerStd`, an alias for `Finalizer<std::function<void()>>`
+// - `FinalizerFtl`, an alias for `Finalizer<ftl::Function<void()>>`
+// - `FinalizerFtl1`, an alias for `Finalizer<ftl::Function<void(), 1>>`
+// - `FinalizerFtl2`, an alias for `Finalizer<ftl::Function<void(), 2>>`
+// - `FinalizerFtl3`, an alias for `Finalizer<ftl::Function<void(), 3>>`
+//
+// Clients of this header are free to define other aliases they need.
+//
+// A Finalizer that uses a polymorphic function type can be returned from a function call and/or
+// stored as member data (to be destroyed along with the containing class).
+//
+// auto register(Observer* observer) -> ftl::FinalizerStd<void()> {
+// const auto id = observers.add(observer);
+// return ftl::Finalizer([id]() { observers.remove(id); });
+// }
+//
+// {
+// const auto _ = register(observer);
+// // do the things that required the registered observer.
+// }
+// // the observer is removed.
+//
+// Cautions:
+//
+// 1. When a Finalizer is stored as member data, you will almost certainly want that cleanup to
+// happen first, before the rest of the other member data is destroyed. For safety you should
+// assume that the finalization function will access that data directly or indirectly.
+//
+// This means that Finalizers should be defined last, after all other normal member data in a
+// class.
+//
+// class MyClass {
+// public:
+// bool initialize() {
+// ready_ = true;
+// cleanup_ = ftl::Finalizer([this]() { ready_ = false; });
+// return true;
+// }
+//
+// bool ready_ = false;
+//
+// // Finalizers should be last so other class members can be accessed before being
+// // destroyed.
+// ftl::FinalizerStd<void()> cleanup_;
+// };
+//
+// 2. Care must be taken to use `ftl::Finalizer()` when constructing locally from a lambda. If you
+// forget to do so, you are just creating a lambda that won't be automatically invoked!
+//
+// const auto bad = [&counter](){ ++counter; }; // Just a lambda instance
+// const auto good = ftl::Finalizer([&counter](){ ++counter; });
+//
+template <typename FinalFunction>
+class Finalizer final {
+ // requires(std::is_invocable_r_v<void, FinalFunction>)
+ static_assert(std::is_invocable_r_v<void, FinalFunction>);
+
+ public:
+ // A default constructed Finalizer does nothing when destroyed.
+ // requires(std::is_default_constructible_v<FinalFunction>)
+ constexpr Finalizer() = default;
+
+ // Constructs a Finalizer from a function object.
+ // requires(std::is_invocable_v<F>)
+ template <typename F, typename = std::enable_if_t<std::is_invocable_v<F>>>
+ [[nodiscard]] explicit constexpr Finalizer(F&& function)
+ : Finalizer(std::forward<F>(function), false) {}
+
+ constexpr ~Finalizer() { maybe_invoke(); }
+
+ // Disallow copying.
+ Finalizer(const Finalizer& that) = delete;
+ auto operator=(const Finalizer& that) = delete;
+
+ // Move construction
+ // requires(std::is_move_constructible_v<FinalFunction>)
+ [[nodiscard]] constexpr Finalizer(Finalizer&& that)
+ : Finalizer(std::move(that.function_), std::exchange(that.canceled_, true)) {}
+
+ // Implicit conversion move construction
+ // requires(!std::is_same_v<Finalizer, Finalizer<F>>)
+ template <typename F, typename = std::enable_if_t<!std::is_same_v<Finalizer, Finalizer<F>>>>
+ // NOLINTNEXTLINE(google-explicit-constructor, cppcoreguidelines-rvalue-reference-param-not-moved)
+ [[nodiscard]] constexpr Finalizer(Finalizer<F>&& that)
+ : Finalizer(std::move(that.function_), std::exchange(that.canceled_, true)) {}
+
+ // Move assignment
+ // requires(std::is_move_assignable_v<FinalFunction>)
+ constexpr auto operator=(Finalizer&& that) -> Finalizer& {
+ maybe_invoke();
+
+ function_ = std::move(that.function_);
+ canceled_ = std::exchange(that.canceled_, true);
+
+ return *this;
+ }
+
+ // Implicit conversion move assignment
+ // requires(!std::is_same_v<Finalizer, Finalizer<F>>)
+ template <typename F, typename = std::enable_if_t<!std::is_same_v<Finalizer, Finalizer<F>>>>
+ // NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved)
+ constexpr auto operator=(Finalizer<F>&& that) -> Finalizer& {
+ *this = Finalizer(std::move(that.function_), std::exchange(that.canceled_, true));
+ return *this;
+ }
+
+ // Cancels the final function, preventing it from being invoked.
+ constexpr void cancel() {
+ canceled_ = true;
+ maybe_nullify_function();
+ }
+
+ // Invokes the final function now, if not already invoked.
+ constexpr void operator()() { maybe_invoke(); }
+
+ private:
+ template <typename>
+ friend class Finalizer;
+
+ template <typename F, typename = std::enable_if_t<std::is_invocable_v<F>>>
+ [[nodiscard]] explicit constexpr Finalizer(F&& function, bool canceled)
+ : function_(std::forward<F>(function)), canceled_(canceled) {}
+
+ constexpr void maybe_invoke() {
+ if (!std::exchange(canceled_, true)) {
+ std::invoke(function_);
+ maybe_nullify_function();
+ }
+ }
+
+ constexpr void maybe_nullify_function() {
+ // Sets function_ to nullptr if that is supported for the backing type.
+ if constexpr (std::is_assignable_v<FinalFunction, nullptr_t>) {
+ function_ = nullptr;
+ }
+ }
+
+ FinalFunction function_;
+ bool canceled_ = true;
+};
+
+template <typename F>
+Finalizer(F&&) -> Finalizer<std::decay_t<F>>;
+
+// A standard alias for using `std::function` as the polymorphic function type.
+using FinalizerStd = Finalizer<std::function<void()>>;
+
+// Helpful aliases for using `ftl::Function` as the polymorphic function type.
+using FinalizerFtl = Finalizer<Function<void()>>;
+using FinalizerFtl1 = Finalizer<Function<void(), 1>>;
+using FinalizerFtl2 = Finalizer<Function<void(), 2>>;
+using FinalizerFtl3 = Finalizer<Function<void(), 3>>;
+
+} // namespace android::ftl \ No newline at end of file
diff --git a/include/ftl/flags.h b/include/ftl/flags.h
index dbe3148fc5..a2a22ebebe 100644
--- a/include/ftl/flags.h
+++ b/include/ftl/flags.h
@@ -22,6 +22,7 @@
#include <bitset>
#include <cstdint>
#include <iterator>
+#include <initializer_list>
#include <string>
#include <type_traits>
@@ -40,6 +41,7 @@ class Flags {
public:
constexpr Flags(F f) : mFlags(static_cast<U>(f)) {}
+ constexpr Flags(std::initializer_list<F> fs) : mFlags(combine(fs)) {}
constexpr Flags() : mFlags(0) {}
constexpr Flags(const Flags<F>& f) : mFlags(f.mFlags) {}
@@ -197,6 +199,14 @@ public:
private:
U mFlags;
+ static constexpr U combine(std::initializer_list<F> fs) {
+ U result = 0;
+ for (const F f : fs) {
+ result |= static_cast<U>(f);
+ }
+ return result;
+ }
+
static void appendFlag(std::string& str, const std::string_view& flag, bool& first) {
if (first) {
first = false;
diff --git a/include/ftl/non_null.h b/include/ftl/non_null.h
index 4a5d8bffd0..e68428810b 100644
--- a/include/ftl/non_null.h
+++ b/include/ftl/non_null.h
@@ -68,6 +68,15 @@ class NonNull final {
constexpr NonNull(const NonNull&) = default;
constexpr NonNull& operator=(const NonNull&) = default;
+ template <typename U, typename = std::enable_if_t<std::is_convertible_v<U, Pointer>>>
+ constexpr NonNull(const NonNull<U>& other) : pointer_(other.get()) {}
+
+ template <typename U, typename = std::enable_if_t<std::is_convertible_v<U, Pointer>>>
+ constexpr NonNull& operator=(const NonNull<U>& other) {
+ pointer_ = other.get();
+ return *this;
+ }
+
[[nodiscard]] constexpr const Pointer& get() const { return pointer_; }
[[nodiscard]] constexpr explicit operator const Pointer&() const { return get(); }
diff --git a/include/input/AccelerationCurve.h b/include/input/AccelerationCurve.h
index 0cf648a2f7..8a4a5d429b 100644
--- a/include/input/AccelerationCurve.h
+++ b/include/input/AccelerationCurve.h
@@ -46,4 +46,15 @@ struct AccelerationCurveSegment {
std::vector<AccelerationCurveSegment> createAccelerationCurveForPointerSensitivity(
int32_t sensitivity);
+/*
+ * Creates a flat acceleration curve for disabling pointer acceleration.
+ *
+ * This method generates a single AccelerationCurveSegment with specific values
+ * to effectively disable acceleration for both mice and touchpads.
+ * A flat acceleration curve ensures a constant gain, meaning that the output
+ * velocity is directly proportional to the input velocity, resulting in
+ * a 1:1 movement ratio between the input device and the on-screen pointer.
+ */
+std::vector<AccelerationCurveSegment> createFlatAccelerationCurve(int32_t sensitivity);
+
} // namespace android
diff --git a/include/input/CoordinateFilter.h b/include/input/CoordinateFilter.h
new file mode 100644
index 0000000000..8f2e605e85
--- /dev/null
+++ b/include/input/CoordinateFilter.h
@@ -0,0 +1,54 @@
+/**
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <chrono>
+
+#include <input/Input.h>
+#include <input/OneEuroFilter.h>
+
+namespace android {
+
+/**
+ * Pair of OneEuroFilters that independently filter X and Y coordinates. Both filters share the same
+ * constructor's parameters. The minimum cutoff frequency is the base cutoff frequency, that is, the
+ * resulting cutoff frequency in the absence of signal's speed. Likewise, beta is a scaling factor
+ * of the signal's speed that sets how much the signal's speed contributes to the resulting cutoff
+ * frequency. The adaptive cutoff frequency criterion is f_c = f_c_min + β|̇x_filtered|
+ */
+class CoordinateFilter {
+public:
+ explicit CoordinateFilter(float minCutoffFreq, float beta);
+
+ /**
+ * Filters in place only the AXIS_X and AXIS_Y fields from coords. Each call to filter must
+ * provide a timestamp strictly greater than the timestamp of the previous call. The first time
+ * this method is invoked no filtering takes place. Subsequent calls do overwrite `coords` with
+ * filtered data.
+ *
+ * @param timestamp The timestamps at which to filter. It must be greater than the one passed in
+ * the previous call.
+ * @param coords Coordinates to be overwritten by the corresponding filtered coordinates.
+ */
+ void filter(std::chrono::nanoseconds timestamp, PointerCoords& coords);
+
+private:
+ OneEuroFilter mXFilter;
+ OneEuroFilter mYFilter;
+};
+
+} // namespace android \ No newline at end of file
diff --git a/include/input/DisplayTopologyGraph.h b/include/input/DisplayTopologyGraph.h
new file mode 100644
index 0000000000..90427bd76d
--- /dev/null
+++ b/include/input/DisplayTopologyGraph.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <ftl/enum.h>
+#include <ui/LogicalDisplayId.h>
+
+#include <cinttypes>
+#include <unordered_map>
+#include <vector>
+
+namespace android {
+
+/**
+ * The edge of the current display, where adjacent display is attached to.
+ */
+enum class DisplayTopologyPosition : int32_t {
+ LEFT = 0,
+ TOP = 1,
+ RIGHT = 2,
+ BOTTOM = 3,
+
+ ftl_last = BOTTOM
+};
+
+/**
+ * Directed edge in the graph of adjacent displays.
+ */
+struct DisplayTopologyAdjacentDisplay {
+ ui::LogicalDisplayId displayId = ui::LogicalDisplayId::INVALID;
+ DisplayTopologyPosition position;
+ float offsetPx;
+};
+
+/**
+ * Directed Graph representation of Display Topology.
+ */
+struct DisplayTopologyGraph {
+ ui::LogicalDisplayId primaryDisplayId = ui::LogicalDisplayId::INVALID;
+ std::unordered_map<ui::LogicalDisplayId, std::vector<DisplayTopologyAdjacentDisplay>> graph;
+};
+
+} // namespace android
diff --git a/include/input/Input.h b/include/input/Input.h
index a8684bd19b..2cabd56204 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -294,6 +294,8 @@ enum class KeyboardType {
NONE = AINPUT_KEYBOARD_TYPE_NONE,
NON_ALPHABETIC = AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC,
ALPHABETIC = AINPUT_KEYBOARD_TYPE_ALPHABETIC,
+ ftl_first = NONE,
+ ftl_last = ALPHABETIC,
};
bool isStylusToolType(ToolType toolType);
@@ -994,6 +996,15 @@ protected:
std::vector<PointerProperties> mPointerProperties;
std::vector<nsecs_t> mSampleEventTimes;
std::vector<PointerCoords> mSamplePointerCoords;
+
+private:
+ /**
+ * Create a human-readable string representation of the event's data for debugging purposes.
+ *
+ * Unlike operator<<, this method does not assume that the event data is valid or consistent, or
+ * call any accessor methods that might themselves call safeDump in the case of invalid data.
+ */
+ std::string safeDump() const;
};
std::ostream& operator<<(std::ostream& out, const MotionEvent& event);
diff --git a/include/input/InputConsumerNoResampling.h b/include/input/InputConsumerNoResampling.h
index c98b9cf8c1..70d00d16f4 100644
--- a/include/input/InputConsumerNoResampling.h
+++ b/include/input/InputConsumerNoResampling.h
@@ -16,6 +16,7 @@
#pragma once
+#include <functional>
#include <map>
#include <memory>
#include <optional>
@@ -75,12 +76,13 @@ public:
* the event is ready to consume.
* @param looper needs to be sp and not shared_ptr because it inherits from
* RefBase
- * @param resampler the resampling strategy to use. If null, no resampling will be
- * performed.
+ * @param resamplerCreator callable that returns the resampling strategy to be used. If null, no
+ * resampling will be performed. resamplerCreator must never return nullptr.
*/
- explicit InputConsumerNoResampling(const std::shared_ptr<InputChannel>& channel,
- sp<Looper> looper, InputConsumerCallbacks& callbacks,
- std::unique_ptr<Resampler> resampler);
+ explicit InputConsumerNoResampling(
+ const std::shared_ptr<InputChannel>& channel, sp<Looper> looper,
+ InputConsumerCallbacks& callbacks,
+ std::function<std::unique_ptr<Resampler>()> resamplerCreator);
~InputConsumerNoResampling();
@@ -117,7 +119,13 @@ private:
std::shared_ptr<InputChannel> mChannel;
sp<Looper> mLooper;
InputConsumerCallbacks& mCallbacks;
- std::unique_ptr<Resampler> mResampler;
+ const std::function<std::unique_ptr<Resampler>()> mResamplerCreator;
+
+ /**
+ * A map to manage multidevice resampling. Each contained resampler is never null. This map is
+ * only modified by handleMessages.
+ */
+ std::map<DeviceId, std::unique_ptr<Resampler>> mResamplers;
// Looper-related infrastructure
/**
@@ -133,7 +141,7 @@ private:
}
private:
- std::function<int(int events)> mCallback;
+ const std::function<int(int events)> mCallback;
};
sp<LooperEventCallback> mCallback;
/**
@@ -190,7 +198,10 @@ private:
/**
* Batch messages that can be batched. When an unbatchable message is encountered, send it
* to the InputConsumerCallbacks immediately. If there are batches remaining,
- * notify InputConsumerCallbacks.
+ * notify InputConsumerCallbacks. If a resampleable ACTION_DOWN message is received, then a
+ * resampler is inserted for that deviceId in mResamplers. If a resampleable ACTION_UP or
+ * ACTION_CANCEL message is received then the resampler associated to that deviceId is erased
+ * from mResamplers.
*/
void handleMessages(std::vector<InputMessage>&& messages);
/**
@@ -200,16 +211,17 @@ private:
* `consumeBatchedInputEvents`.
*/
std::map<DeviceId, std::queue<InputMessage>> mBatches;
+
/**
- * Creates a MotionEvent by consuming samples from the provided queue. If one message has
- * eventTime > adjustedFrameTime, all subsequent messages in the queue will be skipped. It is
- * assumed that messages are queued in chronological order. In other words, only events that
- * occurred prior to the adjustedFrameTime will be consumed.
- * @param requestedFrameTime the time up to which to consume events.
- * @param messages the queue of messages to consume from
+ * Creates a MotionEvent by consuming samples from the provided queue. Consumes all messages
+ * with eventTime <= requestedFrameTime - resampleLatency, where `resampleLatency` is latency
+ * introduced by the resampler. Assumes that messages are queued in chronological order.
+ * @param requestedFrameTime The time up to which consume messages, as given by the inequality
+ * above. If std::nullopt, everything in messages will be consumed.
+ * @param messages the queue of messages to consume from.
*/
std::pair<std::unique_ptr<MotionEvent>, std::optional<uint32_t>> createBatchedMotionEvent(
- const nsecs_t requestedFrameTime, std::queue<InputMessage>& messages);
+ const std::optional<nsecs_t> requestedFrameTime, std::queue<InputMessage>& messages);
/**
* Consumes the batched input events, optionally allowing the caller to specify a device id
diff --git a/include/input/InputDevice.h b/include/input/InputDevice.h
index 1a482396ee..ea1e4aee01 100644
--- a/include/input/InputDevice.h
+++ b/include/input/InputDevice.h
@@ -111,12 +111,12 @@ enum class InputDeviceSensorType : int32_t {
};
enum class InputDeviceSensorAccuracy : int32_t {
- ACCURACY_NONE = 0,
- ACCURACY_LOW = 1,
- ACCURACY_MEDIUM = 2,
- ACCURACY_HIGH = 3,
+ NONE = 0,
+ LOW = 1,
+ MEDIUM = 2,
+ HIGH = 3,
- ftl_last = ACCURACY_HIGH,
+ ftl_last = HIGH,
};
enum class InputDeviceSensorReportingMode : int32_t {
@@ -131,8 +131,9 @@ enum class InputDeviceLightType : int32_t {
PLAYER_ID = 1,
KEYBOARD_BACKLIGHT = 2,
KEYBOARD_MIC_MUTE = 3,
+ KEYBOARD_VOLUME_MUTE = 4,
- ftl_last = KEYBOARD_MIC_MUTE
+ ftl_last = KEYBOARD_VOLUME_MUTE
};
enum class InputDeviceLightCapability : uint32_t {
@@ -266,6 +267,7 @@ class InputDeviceInfo {
public:
InputDeviceInfo();
InputDeviceInfo(const InputDeviceInfo& other);
+ InputDeviceInfo& operator=(const InputDeviceInfo& other);
~InputDeviceInfo();
struct MotionRange {
@@ -315,13 +317,11 @@ public:
inline const InputDeviceViewBehavior& getViewBehavior() const { return mViewBehavior; }
- inline void setKeyCharacterMap(const std::shared_ptr<KeyCharacterMap> value) {
- mKeyCharacterMap = value;
+ inline void setKeyCharacterMap(std::unique_ptr<KeyCharacterMap> value) {
+ mKeyCharacterMap = std::move(value);
}
- inline const std::shared_ptr<KeyCharacterMap> getKeyCharacterMap() const {
- return mKeyCharacterMap;
- }
+ inline const KeyCharacterMap* getKeyCharacterMap() const { return mKeyCharacterMap.get(); }
inline void setVibrator(bool hasVibrator) { mHasVibrator = hasVibrator; }
inline bool hasVibrator() const { return mHasVibrator; }
@@ -364,7 +364,7 @@ private:
std::optional<KeyboardLayoutInfo> mKeyboardLayoutInfo;
uint32_t mSources;
int32_t mKeyboardType;
- std::shared_ptr<KeyCharacterMap> mKeyCharacterMap;
+ std::unique_ptr<KeyCharacterMap> mKeyCharacterMap;
std::optional<InputDeviceUsiVersion> mUsiVersion;
ui::LogicalDisplayId mAssociatedDisplayId{ui::LogicalDisplayId::INVALID};
bool mEnabled;
diff --git a/include/input/InputEventBuilders.h b/include/input/InputEventBuilders.h
index 5bd5070488..1696a62693 100644
--- a/include/input/InputEventBuilders.h
+++ b/include/input/InputEventBuilders.h
@@ -21,6 +21,7 @@
#include <input/Input.h>
#include <input/InputTransport.h>
#include <ui/LogicalDisplayId.h>
+#include <ui/Transform.h>
#include <utils/Timers.h> // for nsecs_t, systemTime
#include <vector>
@@ -94,16 +95,81 @@ public:
return *this;
}
+ InputMessageBuilder& hmac(const std::array<uint8_t, 32>& hmac) {
+ mHmac = hmac;
+ return *this;
+ }
+
InputMessageBuilder& action(int32_t action) {
mAction = action;
return *this;
}
+ InputMessageBuilder& actionButton(int32_t actionButton) {
+ mActionButton = actionButton;
+ return *this;
+ }
+
+ InputMessageBuilder& flags(int32_t flags) {
+ mFlags = flags;
+ return *this;
+ }
+
+ InputMessageBuilder& metaState(int32_t metaState) {
+ mMetaState = metaState;
+ return *this;
+ }
+
+ InputMessageBuilder& buttonState(int32_t buttonState) {
+ mButtonState = buttonState;
+ return *this;
+ }
+
+ InputMessageBuilder& classification(MotionClassification classification) {
+ mClassification = classification;
+ return *this;
+ }
+
+ InputMessageBuilder& edgeFlags(int32_t edgeFlags) {
+ mEdgeFlags = edgeFlags;
+ return *this;
+ }
+
InputMessageBuilder& downTime(nsecs_t downTime) {
mDownTime = downTime;
return *this;
}
+ InputMessageBuilder& transform(const ui::Transform& transform) {
+ mTransform = transform;
+ return *this;
+ }
+
+ InputMessageBuilder& xPrecision(float xPrecision) {
+ mXPrecision = xPrecision;
+ return *this;
+ }
+
+ InputMessageBuilder& yPrecision(float yPrecision) {
+ mYPrecision = yPrecision;
+ return *this;
+ }
+
+ InputMessageBuilder& xCursorPosition(float xCursorPosition) {
+ mXCursorPosition = xCursorPosition;
+ return *this;
+ }
+
+ InputMessageBuilder& yCursorPosition(float yCursorPosition) {
+ mYCursorPosition = yCursorPosition;
+ return *this;
+ }
+
+ InputMessageBuilder& rawTransform(const ui::Transform& rawTransform) {
+ mRawTransform = rawTransform;
+ return *this;
+ }
+
InputMessageBuilder& pointer(PointerBuilder pointerBuilder) {
mPointers.push_back(pointerBuilder);
return *this;
@@ -121,8 +187,30 @@ public:
message.body.motion.deviceId = mDeviceId;
message.body.motion.source = mSource;
message.body.motion.displayId = mDisplayId.val();
+ message.body.motion.hmac = std::move(mHmac);
message.body.motion.action = mAction;
+ message.body.motion.actionButton = mActionButton;
+ message.body.motion.flags = mFlags;
+ message.body.motion.metaState = mMetaState;
+ message.body.motion.buttonState = mButtonState;
+ message.body.motion.edgeFlags = mEdgeFlags;
message.body.motion.downTime = mDownTime;
+ message.body.motion.dsdx = mTransform.dsdx();
+ message.body.motion.dtdx = mTransform.dtdx();
+ message.body.motion.dtdy = mTransform.dtdy();
+ message.body.motion.dsdy = mTransform.dsdy();
+ message.body.motion.tx = mTransform.ty();
+ message.body.motion.ty = mTransform.tx();
+ message.body.motion.xPrecision = mXPrecision;
+ message.body.motion.yPrecision = mYPrecision;
+ message.body.motion.xCursorPosition = mXCursorPosition;
+ message.body.motion.yCursorPosition = mYCursorPosition;
+ message.body.motion.dsdxRaw = mRawTransform.dsdx();
+ message.body.motion.dtdxRaw = mRawTransform.dtdx();
+ message.body.motion.dtdyRaw = mRawTransform.dtdy();
+ message.body.motion.dsdyRaw = mRawTransform.dsdy();
+ message.body.motion.txRaw = mRawTransform.ty();
+ message.body.motion.tyRaw = mRawTransform.tx();
for (size_t i = 0; i < mPointers.size(); ++i) {
message.body.motion.pointers[i].properties = mPointers[i].buildProperties();
@@ -140,9 +228,21 @@ private:
DeviceId mDeviceId{DEFAULT_DEVICE_ID};
int32_t mSource{AINPUT_SOURCE_TOUCHSCREEN};
ui::LogicalDisplayId mDisplayId{ui::LogicalDisplayId::DEFAULT};
+ std::array<uint8_t, 32> mHmac{INVALID_HMAC};
int32_t mAction{AMOTION_EVENT_ACTION_MOVE};
+ int32_t mActionButton{0};
+ int32_t mFlags{0};
+ int32_t mMetaState{AMETA_NONE};
+ int32_t mButtonState{0};
+ MotionClassification mClassification{MotionClassification::NONE};
+ int32_t mEdgeFlags{0};
nsecs_t mDownTime{mEventTime};
-
+ ui::Transform mTransform{};
+ float mXPrecision{1.0f};
+ float mYPrecision{1.0f};
+ float mXCursorPosition{AMOTION_EVENT_INVALID_CURSOR_POSITION};
+ float mYCursorPosition{AMOTION_EVENT_INVALID_CURSOR_POSITION};
+ ui::Transform mRawTransform{};
std::vector<PointerBuilder> mPointers;
};
@@ -150,6 +250,9 @@ class MotionEventBuilder {
public:
MotionEventBuilder(int32_t action, int32_t source) {
mAction = action;
+ if (mAction == AMOTION_EVENT_ACTION_CANCEL) {
+ mFlags |= AMOTION_EVENT_FLAG_CANCELED;
+ }
mSource = source;
mEventTime = systemTime(SYSTEM_TIME_MONOTONIC);
mDownTime = mEventTime;
diff --git a/include/input/KeyCharacterMap.h b/include/input/KeyCharacterMap.h
index 67b37b1213..0a9e74f73b 100644
--- a/include/input/KeyCharacterMap.h
+++ b/include/input/KeyCharacterMap.h
@@ -72,7 +72,7 @@ public:
};
/* Loads a key character map from a file. */
- static base::Result<std::shared_ptr<KeyCharacterMap>> load(const std::string& filename,
+ static base::Result<std::unique_ptr<KeyCharacterMap>> load(const std::string& filename,
Format format);
/* Loads a key character map from its string contents. */
@@ -137,6 +137,9 @@ public:
/* Returns keycode after applying Android key code remapping defined in mKeyRemapping */
int32_t applyKeyRemapping(int32_t fromKeyCode) const;
+ /** Returns list of keycodes that remap to provided keycode (@see setKeyRemapping()) */
+ std::vector<int32_t> findKeyCodesMappedToKeyCode(int32_t toKeyCode) const;
+
/* Returns the <keyCode, metaState> pair after applying key behavior defined in the kcm file,
* that tries to find a replacement key code based on current meta state */
std::pair<int32_t /*keyCode*/, int32_t /*metaState*/> applyKeyBehavior(int32_t keyCode,
diff --git a/include/input/OneEuroFilter.h b/include/input/OneEuroFilter.h
new file mode 100644
index 0000000000..bdd82b2ee8
--- /dev/null
+++ b/include/input/OneEuroFilter.h
@@ -0,0 +1,101 @@
+/**
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <chrono>
+#include <optional>
+
+#include <input/Input.h>
+
+namespace android {
+
+/**
+ * Low pass filter with adaptive low pass frequency based on the signal's speed. The signal's cutoff
+ * frequency is determined by f_c = f_c_min + β|̇x_filtered|. Refer to
+ * https://dl.acm.org/doi/10.1145/2207676.2208639 for details on how the filter works and how to
+ * tune it.
+ */
+class OneEuroFilter {
+public:
+ /**
+ * Default cutoff frequency of the filtered signal's speed. 1.0 Hz is the value in the filter's
+ * paper.
+ */
+ static constexpr float kDefaultSpeedCutoffFreq = 1.0;
+
+ OneEuroFilter() = delete;
+
+ explicit OneEuroFilter(float minCutoffFreq, float beta,
+ float speedCutoffFreq = kDefaultSpeedCutoffFreq);
+
+ OneEuroFilter(const OneEuroFilter&) = delete;
+ OneEuroFilter& operator=(const OneEuroFilter&) = delete;
+ OneEuroFilter(OneEuroFilter&&) = delete;
+ OneEuroFilter& operator=(OneEuroFilter&&) = delete;
+
+ /**
+ * Returns the filtered value of rawPosition. Each call to filter must provide a timestamp
+ * strictly greater than the timestamp of the previous call. The first time the method is
+ * called, it returns the value of rawPosition. Any subsequent calls provide a filtered value.
+ *
+ * @param timestamp The timestamp at which to filter. It must be strictly greater than the one
+ * provided in the previous call.
+ * @param rawPosition Position to be filtered.
+ */
+ float filter(std::chrono::nanoseconds timestamp, float rawPosition);
+
+private:
+ /**
+ * Minimum cutoff frequency. This is the constant term in the adaptive cutoff frequency
+ * criterion. Units are Hertz.
+ */
+ const float mMinCutoffFreq;
+
+ /**
+ * Slope of the cutoff frequency criterion. This is the term scaling the absolute value of the
+ * filtered signal's speed. Units are 1 / position.
+ */
+ const float mBeta;
+
+ /**
+ * Cutoff frequency of the signal's speed. This is the cutoff frequency applied to the filtering
+ * of the signal's speed. Units are Hertz.
+ */
+ const float mSpeedCutoffFreq;
+
+ /**
+ * The timestamp from the previous call.
+ */
+ std::optional<std::chrono::nanoseconds> mPrevTimestamp;
+
+ /**
+ * The raw position from the previous call.
+ */
+ std::optional<float> mPrevRawPosition;
+
+ /**
+ * The filtered velocity from the previous call. Units are position per nanosecond.
+ */
+ std::optional<float> mPrevFilteredVelocity;
+
+ /**
+ * The filtered position from the previous call.
+ */
+ std::optional<float> mPrevFilteredPosition;
+};
+
+} // namespace android
diff --git a/include/input/Resampler.h b/include/input/Resampler.h
index dcb25b729f..155097732c 100644
--- a/include/input/Resampler.h
+++ b/include/input/Resampler.h
@@ -16,10 +16,16 @@
#pragma once
+#include <array>
#include <chrono>
+#include <iterator>
+#include <map>
#include <optional>
#include <vector>
+#include <android-base/logging.h>
+#include <ftl/mixins.h>
+#include <input/CoordinateFilter.h>
#include <input/Input.h>
#include <input/InputTransport.h>
#include <input/RingBuffer.h>
@@ -65,7 +71,8 @@ public:
* extrapolation takes place and `resampleTime` is too far in the future. If `futureSample` is
* not null, interpolation will occur. If `futureSample` is null and there is enough historical
* data, LegacyResampler will extrapolate. Otherwise, no resampling takes place and
- * `motionEvent` is unmodified.
+ * `motionEvent` is unmodified. Furthermore, motionEvent is not resampled if resampleTime equals
+ * the last sample eventTime of motionEvent.
*/
void resampleMotionEvent(std::chrono::nanoseconds frameTime, MotionEvent& motionEvent,
const InputMessage* futureSample) override;
@@ -78,13 +85,127 @@ private:
PointerCoords coords;
};
+ /**
+ * Container that stores pointers as an associative array, supporting O(1) lookup by pointer id,
+ * as well as forward iteration in the order in which the pointer or pointers were inserted in
+ * the container. PointerMap has a maximum capacity equal to MAX_POINTERS.
+ */
+ class PointerMap {
+ public:
+ struct PointerId : ftl::DefaultConstructible<PointerId, int32_t>,
+ ftl::Equatable<PointerId> {
+ using DefaultConstructible::DefaultConstructible;
+ };
+
+ /**
+ * Custom iterator to enable use of range-based for loops.
+ */
+ template <typename T>
+ class iterator {
+ public:
+ using iterator_category = std::forward_iterator_tag;
+ using value_type = T;
+ using difference_type = std::ptrdiff_t;
+ using pointer = T*;
+ using reference = T&;
+
+ explicit iterator(pointer element) : mElement{element} {}
+
+ friend bool operator==(const iterator& lhs, const iterator& rhs) {
+ return lhs.mElement == rhs.mElement;
+ }
+
+ friend bool operator!=(const iterator& lhs, const iterator& rhs) {
+ return !(lhs == rhs);
+ }
+
+ iterator operator++() {
+ ++mElement;
+ return *this;
+ }
+
+ reference operator*() const { return *mElement; }
+
+ private:
+ pointer mElement;
+ };
+
+ PointerMap() {
+ idToIndex.fill(std::nullopt);
+ for (Pointer& pointer : pointers) {
+ pointer.properties.clear();
+ pointer.coords.clear();
+ }
+ }
+
+ /**
+ * Forward iterators to traverse the pointers in `pointers`. The order of the pointers is
+ * determined by the order in which they were inserted (not by id).
+ */
+ iterator<Pointer> begin() { return iterator<Pointer>{&pointers[0]}; }
+
+ iterator<const Pointer> begin() const { return iterator<const Pointer>{&pointers[0]}; }
+
+ iterator<Pointer> end() { return iterator<Pointer>{&pointers[nextPointerIndex]}; }
+
+ iterator<const Pointer> end() const {
+ return iterator<const Pointer>{&pointers[nextPointerIndex]};
+ }
+
+ /**
+ * Inserts the given pointer into the PointerMap. Precondition: The current number of
+ * contained pointers must be less than MAX_POINTERS when this function is called. It
+ * fatally logs if the user tries to insert more than MAX_POINTERS, or if pointer id is out
+ * of bounds.
+ */
+ void insert(const Pointer& pointer) {
+ LOG_IF(FATAL, nextPointerIndex >= pointers.size())
+ << "Cannot insert more than " << MAX_POINTERS << " in PointerMap.";
+ LOG_IF(FATAL, (pointer.properties.id < 0) || (pointer.properties.id > MAX_POINTER_ID))
+ << "Invalid pointer id.";
+ idToIndex[pointer.properties.id] = std::optional<size_t>{nextPointerIndex};
+ pointers[nextPointerIndex] = pointer;
+ ++nextPointerIndex;
+ }
+
+ /**
+ * Returns the pointer associated with the provided id if it exists.
+ * Otherwise, std::nullopt is returned.
+ */
+ std::optional<Pointer> find(PointerId id) const {
+ const int32_t idValue = ftl::to_underlying(id);
+ LOG_IF(FATAL, (idValue < 0) || (idValue > MAX_POINTER_ID)) << "Invalid pointer id.";
+ const std::optional<size_t> index = idToIndex[idValue];
+ return index.has_value() ? std::optional{pointers[*index]} : std::nullopt;
+ }
+
+ private:
+ /**
+ * The index at which a pointer is inserted in `pointers`. Likewise, it represents the
+ * number of pointers in PointerMap.
+ */
+ size_t nextPointerIndex{0};
+
+ /**
+ * Sequentially stores pointers. Each pointer's position is determined by the value of
+ * nextPointerIndex at insertion time.
+ */
+ std::array<Pointer, MAX_POINTERS + 1> pointers;
+
+ /**
+ * Maps each pointer id to its associated index in pointers. If no pointer with the id
+ * exists in pointers, the mapped value is std::nullopt.
+ */
+ std::array<std::optional<size_t>, MAX_POINTER_ID + 1> idToIndex;
+ };
+
struct Sample {
std::chrono::nanoseconds eventTime;
- std::vector<Pointer> pointers;
+ PointerMap pointerMap;
std::vector<PointerCoords> asPointerCoords() const {
std::vector<PointerCoords> pointersCoords;
- for (const Pointer& pointer : pointers) {
+ for (const Pointer& pointer : pointerMap) {
pointersCoords.push_back(pointer.coords);
}
return pointersCoords;
@@ -92,12 +213,6 @@ private:
};
/**
- * Keeps track of the previous MotionEvent deviceId to enable comparison between the previous
- * and the current deviceId.
- */
- std::optional<DeviceId> mPreviousDeviceId;
-
- /**
* Up to two latest samples from MotionEvent. Updated every time resampleMotionEvent is called.
* Note: We store up to two samples in order to simplify the implementation. Although,
* calculations are possible with only one previous sample.
@@ -105,6 +220,16 @@ private:
RingBuffer<Sample> mLatestSamples{/*capacity=*/2};
/**
+ * Latest sample in mLatestSamples after resampling motion event.
+ */
+ std::optional<Sample> mLastRealSample;
+
+ /**
+ * Latest prediction. That is, the latest extrapolated sample.
+ */
+ std::optional<Sample> mPreviousPrediction;
+
+ /**
* Adds up to mLatestSamples.capacity() of motionEvent's latest samples to mLatestSamples. If
* motionEvent has fewer samples than mLatestSamples.capacity(), then the available samples are
* added to mLatestSamples.
@@ -128,12 +253,12 @@ private:
bool canInterpolate(const InputMessage& futureSample) const;
/**
- * Returns a sample interpolated between the latest sample of mLatestSamples and futureSample,
+ * Returns a sample interpolated between the latest sample of mLatestSamples and futureMessage,
* if the conditions from canInterpolate are satisfied. Otherwise, returns nullopt.
* mLatestSamples must have at least one sample when attemptInterpolation is called.
*/
std::optional<Sample> attemptInterpolation(std::chrono::nanoseconds resampleTime,
- const InputMessage& futureSample) const;
+ const InputMessage& futureMessage) const;
/**
* Checks if there are necessary conditions to extrapolate. That is, there are at least two
@@ -149,6 +274,64 @@ private:
*/
std::optional<Sample> attemptExtrapolation(std::chrono::nanoseconds resampleTime) const;
+ /**
+ * Iterates through motion event samples, and replaces real coordinates with resampled
+ * coordinates to avoid jerkiness in certain conditions.
+ */
+ void overwriteMotionEventSamples(MotionEvent& motionEvent) const;
+
+ /**
+ * Overwrites with resampled data the pointer coordinates that did not move between motion event
+ * samples, that is, both x and y values are identical to mLastRealSample.
+ */
+ void overwriteStillPointers(MotionEvent& motionEvent, size_t sampleIndex) const;
+
+ /**
+ * Overwrites the pointer coordinates of a sample with event time older than
+ * that of mPreviousPrediction.
+ */
+ void overwriteOldPointers(MotionEvent& motionEvent, size_t sampleIndex) const;
+
inline static void addSampleToMotionEvent(const Sample& sample, MotionEvent& motionEvent);
};
+
+/**
+ * Resampler that first applies the LegacyResampler resampling algorithm, then independently filters
+ * the X and Y coordinates with a pair of One Euro filters.
+ */
+class FilteredLegacyResampler final : public Resampler {
+public:
+ /**
+ * Creates a resampler, using the given minCutoffFreq and beta to instantiate its One Euro
+ * filters.
+ */
+ explicit FilteredLegacyResampler(float minCutoffFreq, float beta);
+
+ void resampleMotionEvent(std::chrono::nanoseconds requestedFrameTime, MotionEvent& motionEvent,
+ const InputMessage* futureMessage) override;
+
+ std::chrono::nanoseconds getResampleLatency() const override;
+
+private:
+ LegacyResampler mResampler;
+
+ /**
+ * Minimum cutoff frequency of the value's low pass filter. Refer to OneEuroFilter class for a
+ * more detailed explanation.
+ */
+ const float mMinCutoffFreq;
+
+ /**
+ * Scaling factor of the adaptive cutoff frequency criterion. Refer to OneEuroFilter class for a
+ * more detailed explanation.
+ */
+ const float mBeta;
+
+ /*
+ * Note: an associative array with constant insertion and lookup times would be more efficient.
+ * When this was implemented, there was no container with these properties.
+ */
+ std::map<int32_t /*pointerId*/, CoordinateFilter> mFilteredPointers;
+};
+
} // namespace android
diff --git a/include/powermanager/PowerHalController.h b/include/powermanager/PowerHalController.h
index 7e0bd5bedc..f4f4d5e05c 100644
--- a/include/powermanager/PowerHalController.h
+++ b/include/powermanager/PowerHalController.h
@@ -72,6 +72,7 @@ public:
virtual HalResult<aidl::android::hardware::power::ChannelConfig> getSessionChannel(
int tgid, int uid) override;
virtual HalResult<void> closeSessionChannel(int tgid, int uid) override;
+ virtual HalResult<aidl::android::hardware::power::SupportInfo> getSupportInfo() override;
private:
std::mutex mConnectedHalMutex;
diff --git a/include/powermanager/PowerHalWrapper.h b/include/powermanager/PowerHalWrapper.h
index 6e347a9ce9..42901821bc 100644
--- a/include/powermanager/PowerHalWrapper.h
+++ b/include/powermanager/PowerHalWrapper.h
@@ -63,6 +63,7 @@ public:
virtual HalResult<aidl::android::hardware::power::ChannelConfig> getSessionChannel(int tgid,
int uid) = 0;
virtual HalResult<void> closeSessionChannel(int tgid, int uid) = 0;
+ virtual HalResult<aidl::android::hardware::power::SupportInfo> getSupportInfo() = 0;
};
// Empty Power HAL wrapper that ignores all api calls.
@@ -85,6 +86,7 @@ public:
HalResult<aidl::android::hardware::power::ChannelConfig> getSessionChannel(int tgid,
int uid) override;
HalResult<void> closeSessionChannel(int tgid, int uid) override;
+ HalResult<aidl::android::hardware::power::SupportInfo> getSupportInfo() override;
protected:
virtual const char* getUnsupportedMessage();
@@ -170,6 +172,7 @@ public:
HalResult<aidl::android::hardware::power::ChannelConfig> getSessionChannel(int tgid,
int uid) override;
HalResult<void> closeSessionChannel(int tgid, int uid) override;
+ HalResult<aidl::android::hardware::power::SupportInfo> getSupportInfo() override;
protected:
const char* getUnsupportedMessage() override;
diff --git a/include/private/display_luts_private.h b/include/private/display_luts_private.h
new file mode 100644
index 0000000000..c347a0c85d
--- /dev/null
+++ b/include/private/display_luts_private.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/display_luts.h>
+#include <stdint.h>
+#include <vector>
+#include <utils/RefBase.h>
+
+using namespace android;
+
+__BEGIN_DECLS
+
+struct ADisplayLutsEntry_buffer {
+ std::vector<float> data;
+};
+
+struct ADisplayLutsEntry_properties {
+ ADisplayLuts_Dimension dimension;
+ int32_t size;
+ ADisplayLuts_SamplingKey samplingKey;
+};
+
+struct ADisplayLutsEntry: public RefBase {
+ struct ADisplayLutsEntry_buffer buffer;
+ struct ADisplayLutsEntry_properties properties;
+ ADisplayLutsEntry() {}
+
+ // copy constructor
+ ADisplayLutsEntry(const ADisplayLutsEntry& other) :
+ buffer(other.buffer),
+ properties(other.properties) {}
+
+ // copy operator
+ ADisplayLutsEntry& operator=(const ADisplayLutsEntry& other) {
+ if (this != &other) { // Protect against self-assignment
+ buffer = other.buffer;
+ properties = other.properties;
+ }
+ return *this;
+ }
+};
+
+struct ADisplayLuts: public RefBase {
+ int32_t totalBufferSize;
+ std::vector<int32_t> offsets;
+ std::vector<sp<ADisplayLutsEntry>> entries;
+
+ ADisplayLuts() : totalBufferSize(0) {}
+};
+
+__END_DECLS \ No newline at end of file
diff --git a/include/private/performance_hint_private.h b/include/private/performance_hint_private.h
index e5eee340ca..a468313341 100644
--- a/include/private/performance_hint_private.h
+++ b/include/private/performance_hint_private.h
@@ -74,6 +74,20 @@ enum SessionHint: int32_t {
* baseline to prepare for an arbitrary load, and must wake up if inactive.
*/
GPU_LOAD_RESET = 7,
+
+ /**
+ * This hint indicates an upcoming CPU workload that is abnormally large and
+ * not representative of the workload. This should be used for rare, one-time
+ * operations and should be ignored by any load tracking or session hysteresis.
+ */
+ CPU_LOAD_SPIKE = 8,
+
+ /**
+ * This hint indicates an upcoming GPU workload that is abnormally large and
+ * not representative of the workload. This should be used for rare, one-time
+ * operations and should be ignored by any load tracking or session hysteresis.
+ */
+ GPU_LOAD_SPIKE = 9,
};
// Allows access to PowerHAL's SessionTags without needing to import its AIDL
@@ -83,6 +97,7 @@ enum class SessionTag : int32_t {
HWUI = 2,
GAME = 3,
APP = 4,
+ SYSUI = 5,
};
/**
@@ -107,12 +122,48 @@ int APerformanceHint_getThreadIds(APerformanceHintSession* session,
APerformanceHintSession* APerformanceHint_createSessionInternal(APerformanceHintManager* manager,
const int32_t* threadIds, size_t size,
int64_t initialTargetWorkDurationNanos, SessionTag tag);
+/**
+ * Creates a session using ASessionCreationConfig
+ */
+int APerformanceHint_createSessionUsingConfigInternal(
+ APerformanceHintManager* manager,
+ ASessionCreationConfig* config,
+ APerformanceHintSession** sessionOut,
+ SessionTag tag);
+
+/**
+ * Creates a session from the Java SDK implementation
+ */
+APerformanceHintSession* APerformanceHint_createSessionFromJava(APerformanceHintManager* manager,
+ const int32_t* threadIds, size_t size,
+ int64_t initialTargetWorkDurationNanos);
+
+/**
+ * Special method for Java SDK implementation to kill sessions
+ */
+void APerformanceHint_closeSessionFromJava(APerformanceHintSession* session);
/**
* Forces FMQ to be enabled or disabled, for testing only.
*/
void APerformanceHint_setUseFMQForTesting(bool enabled);
+/**
+ * Get the rate limiter properties for testing.
+ */
+void APerformanceHint_getRateLimiterPropertiesForTesting(
+ int32_t* maxLoadHintsPerInterval, int64_t* loadHintInterval);
+
+/*
+ * Forces the "new load hint" flag to be disabled for testing.
+ */
+void APerformanceHint_setUseNewLoadHintBehaviorForTesting(bool newBehavior);
+
+/*
+ * Forces the graphics pipeline flag to be enabled or disabled, for testing only.
+ */
+void APerformanceHint_setUseGraphicsPipelineForTesting(bool enabled);
+
__END_DECLS
#endif // ANDROID_PRIVATE_NATIVE_PERFORMANCE_HINT_PRIVATE_H