diff options
Diffstat (limited to 'include')
-rw-r--r-- | include/android/performance_hint.h | 226 | ||||
-rw-r--r-- | include/android/sensor.h | 2 | ||||
-rw-r--r-- | include/android/thermal.h | 66 | ||||
-rw-r--r-- | include/ftl/details/function.h | 135 | ||||
-rw-r--r-- | include/ftl/enum.h | 79 | ||||
-rw-r--r-- | include/ftl/function.h | 297 | ||||
-rw-r--r-- | include/input/Input.h | 54 | ||||
-rw-r--r-- | include/input/InputEventBuilders.h | 86 | ||||
-rw-r--r-- | include/input/InputEventLabels.h | 6 | ||||
-rw-r--r-- | include/input/InputVerifier.h | 4 | ||||
-rw-r--r-- | include/input/KeyCharacterMap.h | 2 | ||||
-rw-r--r-- | include/input/KeyLayoutMap.h | 4 | ||||
-rw-r--r-- | include/input/MotionPredictor.h | 16 | ||||
-rw-r--r-- | include/input/MotionPredictorMetricsManager.h | 47 | ||||
-rw-r--r-- | include/input/PrintTools.h | 29 | ||||
-rw-r--r-- | include/input/RingBuffer.h | 12 | ||||
-rw-r--r-- | include/input/TraceTools.h | 29 | ||||
-rw-r--r-- | include/input/VelocityControl.h | 2 | ||||
-rw-r--r-- | include/input/VelocityTracker.h | 151 | ||||
-rw-r--r-- | include/powermanager/PowerHalController.h | 20 | ||||
-rw-r--r-- | include/powermanager/PowerHalLoader.h | 6 | ||||
-rw-r--r-- | include/powermanager/PowerHalWrapper.h | 146 | ||||
-rw-r--r-- | include/private/thermal_private.h | 31 |
23 files changed, 1179 insertions, 271 deletions
diff --git a/include/android/performance_hint.h b/include/android/performance_hint.h index b494f897d5..9d2c79139f 100644 --- a/include/android/performance_hint.h +++ b/include/android/performance_hint.h @@ -14,6 +14,23 @@ * limitations under the License. */ + /** + * @defgroup APerformanceHint Performance Hint Manager + * + * 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 + * counterpart to the Java PerformanceHintManager SDK API. + * + * @{ + */ + +/** + * @file performance_hint.h + * @brief API for creating and managing a hint session. + */ + + #ifndef ANDROID_NATIVE_PERFORMANCE_HINT_H #define ANDROID_NATIVE_PERFORMANCE_HINT_H @@ -43,12 +60,33 @@ __BEGIN_DECLS struct APerformanceHintManager; struct APerformanceHintSession; +struct AWorkDuration; + +/** + * {@link AWorkDuration} is an opaque type that represents the breakdown of the + * actual workload duration in each component internally. + * + * A new {@link AWorkDuration} can be obtained using + * {@link AWorkDuration_create()}, when the client finishes using + * {@link AWorkDuration}, {@link AWorkDuration_release()} must be + * called to destroy and free up the resources associated with + * {@link AWorkDuration}. + * + * This file provides a set of functions to allow clients to set the measured + * work duration of each component on {@link AWorkDuration}. + * + * - AWorkDuration_setWorkPeriodStartTimestampNanos() + * - AWorkDuration_setActualTotalDurationNanos() + * - AWorkDuration_setActualCpuDurationNanos() + * - AWorkDuration_setActualGpuDurationNanos() + */ +typedef struct AWorkDuration AWorkDuration; /** * An opaque type representing a handle to a performance hint manager. * It must be released after use. * - * <p>To use:<ul> + * To use:<ul> * <li>Obtain the performance hint manager instance by calling * {@link APerformanceHint_getManager} function.</li> * <li>Create an {@link APerformanceHintSession} with @@ -61,54 +99,47 @@ typedef struct APerformanceHintManager APerformanceHintManager; /** * An opaque type representing a handle to a performance hint session. * A session can only be acquired from a {@link APerformanceHintManager} - * with {@link APerformanceHint_getPreferredUpdateRateNanos}. It must be + * with {@link APerformanceHint_createSession}. It must be * freed with {@link APerformanceHint_closeSession} after use. * * A Session represents a group of threads with an inter-related workload such that hints for * their performance should be considered as a unit. The threads in a given session should be - * long-life and not created or destroyed dynamically. - * - * <p>Each session is expected to have a periodic workload with a target duration for each - * cycle. The cycle duration is likely greater than the target work duration to allow other - * parts of the pipeline to run within the available budget. For example, a renderer thread may - * work at 60hz in order to produce frames at the display's frame but have a target work - * duration of only 6ms.</p> - * - * <p>After each cycle of work, the client is expected to use - * {@link APerformanceHint_reportActualWorkDuration} to report the actual time taken to - * complete.</p> - * - * <p>To use:<ul> - * <li>Update a sessions target duration for each cycle of work - * with {@link APerformanceHint_updateTargetWorkDuration}.</li> - * <li>Report the actual duration for the last cycle of work with - * {@link APerformanceHint_reportActualWorkDuration}.</li> - * <li>Release the session instance with - * {@link APerformanceHint_closeSession}.</li></ul></p> + * long-lived and not created or destroyed dynamically. + * + * The work duration API can be used with periodic workloads to dynamically adjust thread + * performance and keep the work on schedule while optimizing the available power budget. + * When using the work duration API, the starting target duration should be specified + * while creating the session, and can later be adjusted with + * {@link APerformanceHint_updateTargetWorkDuration}. While using the work duration + * API, the client is expected to call {@link APerformanceHint_reportActualWorkDuration} each + * cycle to report the actual time taken to complete to the system. + * + * All timings should be from `std::chrono::steady_clock` or `clock_gettime(CLOCK_MONOTONIC, ...)` */ typedef struct APerformanceHintSession APerformanceHintSession; /** * Acquire an instance of the performance hint manager. * - * @return manager instance on success, nullptr on failure. + * @return APerformanceHintManager instance on success, nullptr on failure. */ -APerformanceHintManager* APerformanceHint_getManager() __INTRODUCED_IN(__ANDROID_API_T__); +APerformanceHintManager* _Nullable APerformanceHint_getManager() __INTRODUCED_IN(__ANDROID_API_T__); /** * Creates a session for the given set of threads and sets their initial target work * duration. + * * @param manager The performance hint manager instance. * @param threadIds The list of threads to be associated with this session. They must be part of - * this app's thread group. - * @param size the size of threadIds. - * @param initialTargetWorkDurationNanos The desired duration in nanoseconds for the new session. - * This must be positive. - * @return manager instance on success, nullptr on failure. - */ -APerformanceHintSession* APerformanceHint_createSession( - APerformanceHintManager* manager, - const int32_t* threadIds, size_t size, + * this process' thread group. + * @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. + */ +APerformanceHintSession* _Nullable APerformanceHint_createSession( + APerformanceHintManager* _Nonnull manager, + const int32_t* _Nonnull threadIds, size_t size, int64_t initialTargetWorkDurationNanos) __INTRODUCED_IN(__ANDROID_API_T__); /** @@ -118,37 +149,36 @@ APerformanceHintSession* APerformanceHint_createSession( * @return the preferred update rate supported by device software. */ int64_t APerformanceHint_getPreferredUpdateRateNanos( - APerformanceHintManager* manager) __INTRODUCED_IN(__ANDROID_API_T__); + APerformanceHintManager* _Nonnull manager) __INTRODUCED_IN(__ANDROID_API_T__); /** * Updates this session's target duration for each cycle of work. * * @param session The performance hint session instance to update. - * @param targetDurationNanos the new desired duration in nanoseconds. This must be positive. - * @return 0 on success + * @param targetDurationNanos The new desired duration in nanoseconds. This must be positive. + * @return 0 on success. * EINVAL if targetDurationNanos is not positive. * EPIPE if communication with the system service has failed. */ int APerformanceHint_updateTargetWorkDuration( - APerformanceHintSession* session, + APerformanceHintSession* _Nonnull session, int64_t targetDurationNanos) __INTRODUCED_IN(__ANDROID_API_T__); /** * Reports the actual duration for the last cycle of work. * - * <p>The system will attempt to adjust the core placement of the threads within the thread - * group and/or the frequency of the core on which they are run to bring the actual duration - * close to the target duration.</p> + * The system will attempt to adjust the scheduling and performance of the + * threads within the thread group to bring the actual duration close to the target duration. * * @param session The performance hint session instance to update. - * @param actualDurationNanos how long the thread group took to complete its last task in - * nanoseconds. This must be positive. - * @return 0 on success + * @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. * EPIPE if communication with the system service has failed. */ int APerformanceHint_reportActualWorkDuration( - APerformanceHintSession* session, + APerformanceHintSession* _Nonnull session, int64_t actualDurationNanos) __INTRODUCED_IN(__ANDROID_API_T__); /** @@ -158,25 +188,123 @@ int APerformanceHint_reportActualWorkDuration( * @param session The performance hint session instance to release. */ void APerformanceHint_closeSession( - APerformanceHintSession* session) __INTRODUCED_IN(__ANDROID_API_T__); + APerformanceHintSession* _Nonnull session) __INTRODUCED_IN(__ANDROID_API_T__); /** * 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. * - * @param session The performance hint session instance for the threads. + * @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. + * @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 is not part of the thread group. + * EINVAL if the list of thread ids is empty or if any of the thread ids are not part of + the thread group. * EPIPE if communication with the system service has failed. + * EPERM if any thread id doesn't belong to the application. */ int APerformanceHint_setThreads( - APerformanceHintSession* session, - const pid_t* threadIds, + APerformanceHintSession* _Nonnull session, + const pid_t* _Nonnull threadIds, size_t size) __INTRODUCED_IN(__ANDROID_API_U__); +/** + * This tells the session that these threads can be + * safely scheduled to prefer power efficiency over performance. + * + * @param session The performance hint session instance to update. + * @param enabled The flag which sets whether this session will use power-efficient scheduling. + * @return 0 on success. + * EPIPE if communication with the system service has failed. + */ +int APerformanceHint_setPreferPowerEfficiency( + APerformanceHintSession* _Nonnull session, + bool enabled) __INTRODUCED_IN(__ANDROID_API_V__); + +/** + * Reports the durations for the last cycle of work. + * + * The system will attempt to adjust the scheduling and performance of the + * threads within the thread group to bring the actual duration close to the target duration. + * + * @param session The {@link APerformanceHintSession} instance to update. + * @param workDuration The {@link AWorkDuration} structure of times the thread group took to + * complete its last task in nanoseconds breaking down into different components. + * + * The work period start timestamp, actual total duration and actual CPU duration must be + * positive. + * + * The actual GPU duration must be non-negative. If the actual GPU duration is 0, it means + * the actual GPU duration is not measured. + * + * @return 0 on success. + * EINVAL if session is nullptr or any duration is an invalid number. + * EPIPE if communication with the system service has failed. + */ +int APerformanceHint_reportActualWorkDuration2( + APerformanceHintSession* _Nonnull session, + AWorkDuration* _Nonnull workDuration) __INTRODUCED_IN(__ANDROID_API_V__); + +/** + * 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. + */ +AWorkDuration* _Nonnull AWorkDuration_create() __INTRODUCED_IN(__ANDROID_API_V__); + +/** + * Destroys {@link AWorkDuration} and free all resources associated to it. + * + * @param aWorkDuration The {@link AWorkDuration} created by calling {@link AWorkDuration_create()} + */ +void AWorkDuration_release(AWorkDuration* _Nonnull WorkDuration) __INTRODUCED_IN(__ANDROID_API_V__); + +/** + * Sets the work period start timestamp in nanoseconds. + * + * @param aWorkDuration The {@link AWorkDuration} created by calling {@link AWorkDuration_create()} + * @param workPeriodStartTimestampNanos The work period start timestamp in nanoseconds based on + * CLOCK_MONOTONIC about when the work starts, the timestamp must be positive. + */ +void AWorkDuration_setWorkPeriodStartTimestampNanos(AWorkDuration* _Nonnull aWorkDuration, + int64_t workPeriodStartTimestampNanos) __INTRODUCED_IN(__ANDROID_API_V__); + +/** + * Sets the actual total work duration in nanoseconds. + * + * @param aWorkDuration The {@link AWorkDuration} created by calling {@link AWorkDuration_create()} + * @param actualTotalDurationNanos The actual total work duration in nanoseconds, the number must be + * positive. + */ +void AWorkDuration_setActualTotalDurationNanos(AWorkDuration* _Nonnull aWorkDuration, + int64_t actualTotalDurationNanos) __INTRODUCED_IN(__ANDROID_API_V__); + +/** + * Sets the actual CPU work duration in nanoseconds. + * + * @param aWorkDuration The {@link AWorkDuration} created by calling {@link AWorkDuration_create()} + * @param actualCpuDurationNanos The actual CPU work duration in nanoseconds, the number must be + * positive. + */ +void AWorkDuration_setActualCpuDurationNanos(AWorkDuration* _Nonnull aWorkDuration, + int64_t actualCpuDurationNanos) __INTRODUCED_IN(__ANDROID_API_V__); + +/** + * Sets the actual GPU work duration in nanoseconds. + * + * @param aWorkDuration The {@link AWorkDuration} created by calling {@link AWorkDuration_create()}. + * @param actualGpuDurationNanos The actual GPU work duration in nanoseconds, the number must be + * non-negative. If the actual GPU duration is 0, it means the actual GPU duration is + * measured. + */ +void AWorkDuration_setActualGpuDurationNanos(AWorkDuration* _Nonnull aWorkDuration, + int64_t actualGpuDurationNanos) __INTRODUCED_IN(__ANDROID_API_V__); + __END_DECLS #endif // ANDROID_NATIVE_PERFORMANCE_HINT_H + +/** @} */ diff --git a/include/android/sensor.h b/include/android/sensor.h index 0cc7834420..a618393e66 100644 --- a/include/android/sensor.h +++ b/include/android/sensor.h @@ -657,7 +657,7 @@ typedef struct ASensorEvent { uint32_t flags; int32_t reserved1[3]; } ASensorEvent; -// LINT.ThenChange (hardware/libhardware/include/hardware/sensors.h) +// LINT.ThenChange(hardware/libhardware/include/hardware/sensors.h) struct ASensorManager; /** diff --git a/include/android/thermal.h b/include/android/thermal.h index 1f477f8233..0b57e9376d 100644 --- a/include/android/thermal.h +++ b/include/android/thermal.h @@ -111,7 +111,7 @@ typedef struct AThermalManager AThermalManager; * It's passed the updated thermal status as parameter, as well as the * pointer provided by the client that registered a callback. */ -typedef void (*AThermal_StatusCallback)(void *data, AThermalStatus status); +typedef void (*AThermal_StatusCallback)(void* data, AThermalStatus status); /** * Acquire an instance of the thermal manager. This must be freed using @@ -222,6 +222,70 @@ int AThermal_unregisterThermalStatusListener(AThermalManager *manager, float AThermal_getThermalHeadroom(AThermalManager *manager, int forecastSeconds) __INTRODUCED_IN(31); +/** + * This struct defines an instance of headroom threshold value and its status. + * <p> + * The value should be monotonically non-decreasing as the thermal status increases. + * For {@link ATHERMAL_STATUS_SEVERE}, its headroom threshold is guaranteed to + * be 1.0f. For status below severe status, the value should be lower or equal + * to 1.0f, and for status above severe, the value should be larger or equal to 1.0f. + * <p> + * Also see {@link AThermal_getThermalHeadroom} for explanation on headroom, and + * {@link AThermal_getThermalHeadroomThresholds} for how to use this. + */ +struct AThermalHeadroomThreshold { + float headroom; + AThermalStatus thermalStatus; +}; + +/** + * Gets the thermal headroom thresholds for all available thermal status. + * + * A thermal status will only exist in output if the device manufacturer has the + * corresponding threshold defined for at least one of its slow-moving skin temperature + * sensors. If it's set, one should also expect to get it from + * {@link #AThermal_getCurrentThermalStatus} or {@link AThermal_StatusCallback}. + * <p> + * 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 {@code 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. + * <p> + * 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 {@code AThermal_getThermalHeadroom(0)}=0.75) exceeding the threshold of 0.7 above + * will always come with lightly throttled state + * (or {@code AThermal_getCurrentThermalStatus()=ATHERMAL_STATUS_LIGHT}) but it can be lower + * (or {@code AThermal_getCurrentThermalStatus()=ATHERMAL_STATUS_NONE}). + * While it's always guaranteed that the device won't be throttled heavier than the unmet + * threshold's state, so a real-time headroom of 0.75 will never come with + * {@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}. + * + * @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. + * @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 + * EINVAL if outThresholds or size_t is nullptr, or *outThresholds is not nullptr. + * EPIPE if communication with the system service has failed. + * ENOSYS if the feature is disabled by the current system. + */ +int AThermal_getThermalHeadroomThresholds(AThermalManager* manager, + const AThermalHeadroomThreshold ** outThresholds, + size_t* size) __INTRODUCED_IN(35); + #ifdef __cplusplus } #endif diff --git a/include/ftl/details/function.h b/include/ftl/details/function.h new file mode 100644 index 0000000000..35c5a8b302 --- /dev/null +++ b/include/ftl/details/function.h @@ -0,0 +1,135 @@ +/* + * Copyright 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <array> +#include <cstddef> +#include <cstdint> +#include <cstring> +#include <type_traits> + +namespace android::ftl::details { + +// The maximum allowed value for the template argument `N` in +// `ftl::Function<F, N>`. +constexpr size_t kFunctionMaximumN = 14; + +// Converts a member function pointer type `Ret(Class::*)(Args...)` to an equivalent non-member +// function type `Ret(Args...)`. + +template <typename> +struct remove_member_function_pointer; + +template <typename Class, typename Ret, typename... Args> +struct remove_member_function_pointer<Ret (Class::*)(Args...)> { + using type = Ret(Args...); +}; + +template <typename Class, typename Ret, typename... Args> +struct remove_member_function_pointer<Ret (Class::*)(Args...) const> { + using type = Ret(Args...); +}; + +template <auto MemberFunction> +using remove_member_function_pointer_t = + typename remove_member_function_pointer<decltype(MemberFunction)>::type; + +// Helper functions for binding to the supported targets. + +template <typename Ret, typename... Args> +auto bind_opaque_no_op() -> Ret (*)(void*, Args...) { + return [](void*, Args...) -> Ret { + if constexpr (!std::is_void_v<Ret>) { + return Ret{}; + } + }; +} + +template <typename F, typename Ret, typename... Args> +auto bind_opaque_function_object(const F&) -> Ret (*)(void*, Args...) { + return [](void* opaque, Args... args) -> Ret { + return std::invoke(*static_cast<F*>(opaque), std::forward<Args>(args)...); + }; +} + +template <auto MemberFunction, typename Class, typename Ret, typename... Args> +auto bind_member_function(Class* instance, Ret (*)(Args...) = nullptr) { + return [instance](Args... args) -> Ret { + return std::invoke(MemberFunction, instance, std::forward<Args>(args)...); + }; +} + +template <auto FreeFunction, typename Ret, typename... Args> +auto bind_free_function(Ret (*)(Args...) = nullptr) { + return [](Args... args) -> Ret { return std::invoke(FreeFunction, std::forward<Args>(args)...); }; +} + +// Traits class for the opaque storage used by Function. + +template <std::size_t N> +struct function_opaque_storage { + // The actual type used for the opaque storage. An `N` of zero specifies the minimum useful size, + // which allows a lambda with zero or one capture args. + using type = std::array<std::intptr_t, N + 1>; + + template <typename S> + static constexpr bool require_trivially_copyable = std::is_trivially_copyable_v<S>; + + template <typename S> + static constexpr bool require_trivially_destructible = std::is_trivially_destructible_v<S>; + + template <typename S> + static constexpr bool require_will_fit_in_opaque_storage = sizeof(S) <= sizeof(type); + + template <typename S> + static constexpr bool require_alignment_compatible = + std::alignment_of_v<S> <= std::alignment_of_v<type>; + + // Copies `src` into the opaque storage, and returns that storage. + template <typename S> + static type opaque_copy(const S& src) { + // TODO: Replace with C++20 concepts/constraints which can give more details. + static_assert(require_trivially_copyable<S>, + "ftl::Function can only store lambdas that capture trivially copyable data."); + static_assert( + require_trivially_destructible<S>, + "ftl::Function can only store lambdas that capture trivially destructible data."); + static_assert(require_will_fit_in_opaque_storage<S>, + "ftl::Function has limited storage for lambda captured state. Maybe you need to " + "increase N?"); + static_assert(require_alignment_compatible<S>); + + type opaque; + std::memcpy(opaque.data(), &src, sizeof(S)); + return opaque; + } +}; + +// Traits class to help determine the template parameters to use for a ftl::Function, given a +// function object. + +template <typename F, typename = decltype(&F::operator())> +struct function_traits { + // The function type `F` with which to instantiate the `Function<F, N>` template. + using type = remove_member_function_pointer_t<&F::operator()>; + + // The (minimum) size `N` with which to instantiate the `Function<F, N>` template. + static constexpr std::size_t size = + (std::max(sizeof(std::intptr_t), sizeof(F)) - 1) / sizeof(std::intptr_t); +}; + +} // namespace android::ftl::details diff --git a/include/ftl/enum.h b/include/ftl/enum.h index 075d12bd17..2c86e2e4c9 100644 --- a/include/ftl/enum.h +++ b/include/ftl/enum.h @@ -25,12 +25,12 @@ #include <ftl/string.h> -// Returns the name of enumerator E::V (i.e. "V") as std::optional<std::string_view> by parsing the -// compiler-generated string literal for the signature of this function. The function is defined in -// the global namespace with a short name and inferred return type to reduce bloat in the read-only -// data segment. -template <typename E, E V> -constexpr auto ftl_enum() { +// Returns the name of enumerator E::V and optionally the class (i.e. "E::V" or "V") as +// std::optional<std::string_view> by parsing the compiler-generated string literal for the +// signature of this function. The function is defined in the global namespace with a short name +// and inferred return type to reduce bloat in the read-only data segment. +template <bool S, typename E, E V> +constexpr auto ftl_enum_builder() { static_assert(std::is_enum_v<E>); using R = std::optional<std::string_view>; @@ -58,7 +58,9 @@ constexpr auto ftl_enum() { // V = android::test::Enum::kValue // view = view.substr(value_begin); - const auto name_begin = view.rfind("::"sv); + const auto pos = S ? view.rfind("::"sv) - 2 : view.npos; + + const auto name_begin = view.rfind("::"sv, pos); if (name_begin == view.npos) return R{}; // Chop off the leading "::". @@ -68,6 +70,18 @@ constexpr auto ftl_enum() { return name.find(')') == view.npos ? R{name} : R{}; } +// Returns the name of enumerator E::V (i.e. "V") as std::optional<std::string_view> +template <typename E, E V> +constexpr auto ftl_enum() { + return ftl_enum_builder<false, E, V>(); +} + +// Returns the name of enumerator and class E::V (i.e. "E::V") as std::optional<std::string_view> +template <typename E, E V> +constexpr auto ftl_enum_full() { + return ftl_enum_builder<true, E, V>(); +} + namespace android::ftl { // Trait for determining whether a type is specifically a scoped enum or not. By definition, a @@ -191,6 +205,11 @@ struct EnumName { static constexpr auto value = ftl_enum<decltype(V), V>(); }; +template <auto V> +struct EnumNameFull { + static constexpr auto value = ftl_enum_full<decltype(V), V>(); +}; + template <auto I> struct FlagName { using E = decltype(I); @@ -230,6 +249,18 @@ constexpr std::string_view enum_name() { return *kName; } +// Returns a stringified enumerator with class at compile time. +// +// enum class E { A, B, C }; +// static_assert(ftl::enum_name<E::B>() == "E::B"); +// +template <auto V> +constexpr std::string_view enum_name_full() { + constexpr auto kName = ftl_enum_full<decltype(V), V>(); + static_assert(kName, "Unknown enumerator"); + return *kName; +} + // Returns a stringified enumerator, possibly at compile time. // // enum class E { A, B, C, F = 5, ftl_last = F }; @@ -249,6 +280,25 @@ constexpr std::optional<std::string_view> enum_name(E v) { return kRange.values[value - kBegin]; } +// Returns a stringified enumerator with class, possibly at compile time. +// +// enum class E { A, B, C, F = 5, ftl_last = F }; +// +// static_assert(ftl::enum_name(E::C).value_or("?") == "E::C"); +// static_assert(ftl::enum_name(E{3}).value_or("?") == "?"); +// +template <typename E> +constexpr std::optional<std::string_view> enum_name_full(E v) { + const auto value = to_underlying(v); + + constexpr auto kBegin = to_underlying(enum_begin_v<E>); + constexpr auto kLast = to_underlying(enum_last_v<E>); + if (value < kBegin || value > kLast) return {}; + + constexpr auto kRange = details::EnumRange<E, details::EnumNameFull>{}; + return kRange.values[value - kBegin]; +} + // Returns a stringified flag enumerator, possibly at compile time. // // enum class F : std::uint16_t { X = 0b1, Y = 0b10, Z = 0b100 }; @@ -282,6 +332,21 @@ inline std::string enum_string(E v) { return to_string(to_underlying(v)); } +// Returns a stringified enumerator with class, or its integral value if not named. +// +// enum class E { A, B, C, F = 5, ftl_last = F }; +// +// assert(ftl::enum_string(E::C) == "E::C"); +// assert(ftl::enum_string(E{3}) == "3"); +// +template <typename E> +inline std::string enum_string_full(E v) { + if (const auto name = enum_name_full(v)) { + return std::string(*name); + } + return to_string(to_underlying(v)); +} + // Returns a stringified flag enumerator, or its integral value if not named. // // enum class F : std::uint16_t { X = 0b1, Y = 0b10, Z = 0b100 }; diff --git a/include/ftl/function.h b/include/ftl/function.h new file mode 100644 index 0000000000..3538ca4eae --- /dev/null +++ b/include/ftl/function.h @@ -0,0 +1,297 @@ +/* + * Copyright 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <cstddef> +#include <functional> +#include <type_traits> +#include <utility> + +#include <ftl/details/function.h> + +namespace android::ftl { + +// ftl::Function<F, N> is a container for function object, and can mostly be used in place of +// std::function<F>. +// +// Unlike std::function<F>, a ftl::Function<F, N>: +// +// * Uses a static amount of memory (controlled by N), and never any dynamic allocation. +// * Satisfies the std::is_trivially_copyable<> trait. +// * Satisfies the std::is_trivially_destructible<> trait. +// +// However those same limits are also required from the contained function object in turn. +// +// The size of a ftl::Function<F, N> is guaranteed to be: +// +// sizeof(std::intptr_t) * (N + 2) +// +// A ftl::Function<F, N> can always be implicitly converted to a larger size ftl::Function<F, M>. +// Trying to convert the other way leads to a compilation error. +// +// A default-constructed ftl::Function is in an empty state. The operator bool() overload returns +// false in this state. It is undefined behavior to attempt to invoke the function in this state. +// +// The ftl::Function<F, N> can also be constructed or assigned from ftl::no_op. This sets up the +// ftl::Function to be non-empty, with a function that when called does nothing except +// default-constructs a return value. +// +// The ftl::make_function() helpers construct a ftl::Function<F, N>, including deducing the +// values of F and N from the arguments it is given. +// +// The static ftl::Function<F, N>::make() helpers construct a ftl::Function<F, N> without that +// deduction, and also allow for implicit argument conversion if the target being called needs them. +// +// The construction helpers allow any of the following types of functions to be stored: +// +// * Any SMALL function object (as defined by the C++ Standard), such as a lambda with a small +// capture, or other "functor". The requirements are: +// +// 1) The function object must be trivial to destroy (in fact, the destructor will never +// actually be called once copied to the internal storage). +// 2) The function object must be trivial to copy (the raw bytes will be copied as the +// ftl::Function<F, N> is copied/moved). +// 3) The size of the function object cannot be larger than sizeof(std::intptr_t) * (N + 1), +// and it cannot require stricter alignment than alignof(std::intptr_t). +// +// With the default of N=0, a lambda can only capture a single pointer-sized argument. This is +// enough to capture `this`, which is why N=0 is the default. +// +// * A member function, with the address passed as the template value argument to the construction +// helper function, along with the instance pointer needed to invoke it passed as an ordinary +// argument. +// +// ftl::make_function<&Class::member_function>(this); +// +// Note that the indicated member function will be invoked non-virtually. If you need it to be +// invoked virtually, you should invoke it yourself with a small lambda like so: +// +// ftl::function([this] { virtual_member_function(); }); +// +// * An ordinary function ("free function"), with the address of the function passed as a template +// value argument. +// +// ftl::make_function<&std::atoi>(); +// +// As with the member function helper, as the function is known at compile time, it will be called +// directly. +// +// Example usage: +// +// class MyClass { +// public: +// void on_event() const {} +// int on_string(int*, std::string_view) { return 1; } +// +// auto get_function() { +// return ftl::function([this] { on_event(); }); +// } +// } cls; +// +// // A function container with no arguments, and returning no value. +// ftl::Function<void()> f; +// +// // Construct a ftl::Function containing a small lambda. +// f = cls.get_function(); +// +// // Construct a ftl::Function that calls `cls.on_event()`. +// f = ftl::function<&MyClass::on_event>(&cls); +// +// // Create a do-nothing function. +// f = ftl::no_op; +// +// // Invoke the contained function. +// f(); +// +// // Also invokes it. +// std::invoke(f); +// +// // Create a typedef to give a more meaningful name and bound the size. +// using MyFunction = ftl::Function<int(std::string_view), 2>; +// int* ptr = nullptr; +// auto f1 = MyFunction::make_function( +// [cls = &cls, ptr](std::string_view sv) { +// return cls->on_string(ptr, sv); +// }); +// int r = f1("abc"sv); +// +// // Returns a default-constructed int (0). +// f1 = ftl::no_op; +// r = f1("abc"sv); +// assert(r == 0); + +template <typename F, std::size_t N = 0> +class Function; + +// Used to construct a Function that does nothing. +struct NoOpTag {}; + +constexpr NoOpTag no_op; + +// Detects that a type is a `ftl::Function<F, N>` regardless of what `F` and `N` are. +template <typename> +struct is_function : public std::false_type {}; + +template <typename F, std::size_t N> +struct is_function<Function<F, N>> : public std::true_type {}; + +template <typename T> +constexpr bool is_function_v = is_function<T>::value; + +template <typename Ret, typename... Args, std::size_t N> +class Function<Ret(Args...), N> final { + // Enforce a valid size, with an arbitrary maximum allowed size for the container of + // sizeof(std::intptr_t) * 16, though that maximum can be relaxed. + static_assert(N <= details::kFunctionMaximumN); + + using OpaqueStorageTraits = details::function_opaque_storage<N>; + + public: + // Defining result_type allows ftl::Function to be substituted for std::function. + using result_type = Ret; + + // Constructs an empty ftl::Function. + Function() = default; + + // Constructing or assigning from nullptr_t also creates an empty ftl::Function. + Function(std::nullptr_t) {} + Function& operator=(std::nullptr_t) { return *this = Function(nullptr); } + + // Constructing from NoOpTag sets up a a special no-op function which is valid to call, and which + // returns a default constructed return value. + Function(NoOpTag) : function_(details::bind_opaque_no_op<Ret, Args...>()) {} + Function& operator=(NoOpTag) { return *this = Function(no_op); } + + // Constructing/assigning from a function object stores a copy of that function object, however: + // * It must be trivially copyable, as the implementation makes a copy with memcpy(). + // * It must be trivially destructible, as the implementation doesn't destroy the copy! + // * It must fit in the limited internal storage, which enforces size/alignment restrictions. + + template <typename F, typename = std::enable_if_t<std::is_invocable_r_v<Ret, F, Args...>>> + Function(const F& f) + : opaque_(OpaqueStorageTraits::opaque_copy(f)), + function_(details::bind_opaque_function_object<F, Ret, Args...>(f)) {} + + template <typename F, typename = std::enable_if_t<std::is_invocable_r_v<Ret, F, Args...>>> + Function& operator=(const F& f) noexcept { + return *this = Function{OpaqueStorageTraits::opaque_copy(f), + details::bind_opaque_function_object<F, Ret, Args...>(f)}; + } + + // Constructing/assigning from a smaller ftl::Function is allowed, but not anything else. + + template <std::size_t M> + Function(const Function<Ret(Args...), M>& other) + : opaque_{OpaqueStorageTraits::opaque_copy(other.opaque_)}, function_(other.function_) {} + + template <std::size_t M> + auto& operator=(const Function<Ret(Args...), M>& other) { + return *this = Function{OpaqueStorageTraits::opaque_copy(other.opaque_), other.function_}; + } + + // Returns true if a function is set. + explicit operator bool() const { return function_ != nullptr; } + + // Checks if the other function has the same contents as this one. + bool operator==(const Function& other) const { + return other.opaque_ == opaque_ && other.function_ == function_; + } + bool operator!=(const Function& other) const { return !operator==(other); } + + // Alternative way of testing for a function being set. + bool operator==(std::nullptr_t) const { return function_ == nullptr; } + bool operator!=(std::nullptr_t) const { return function_ != nullptr; } + + // Invokes the function. + Ret operator()(Args... args) const { + return std::invoke(function_, opaque_.data(), std::forward<Args>(args)...); + } + + // Creation helper for function objects, such as lambdas. + template <typename F> + static auto make(const F& f) -> decltype(Function{f}) { + return Function{f}; + } + + // Creation helper for a class pointer and a compile-time chosen member function to call. + template <auto MemberFunction, typename Class> + static auto make(Class* instance) -> decltype(Function{ + details::bind_member_function<MemberFunction>(instance, + static_cast<Ret (*)(Args...)>(nullptr))}) { + return Function{details::bind_member_function<MemberFunction>( + instance, static_cast<Ret (*)(Args...)>(nullptr))}; + } + + // Creation helper for a compile-time chosen free function to call. + template <auto FreeFunction> + static auto make() -> decltype(Function{ + details::bind_free_function<FreeFunction>(static_cast<Ret (*)(Args...)>(nullptr))}) { + return Function{ + details::bind_free_function<FreeFunction>(static_cast<Ret (*)(Args...)>(nullptr))}; + } + + private: + // Needed so a Function<F, M> can be converted to a Function<F, N>. + template <typename, std::size_t> + friend class Function; + + // The function pointer type of function stored in `function_`. The first argument is always + // `&opaque_`. + using StoredFunction = Ret(void*, Args...); + + // The type of the opaque storage, used to hold an appropriate function object. + // The type stored here is ONLY known to the StoredFunction. + // We always use at least one std::intptr_t worth of storage, and always a multiple of that size. + using OpaqueStorage = typename OpaqueStorageTraits::type; + + // Internal constructor for creating from a raw opaque blob + function pointer. + Function(const OpaqueStorage& opaque, StoredFunction* function) + : opaque_(opaque), function_(function) {} + + // Note: `mutable` so that `operator() const` can use it. + mutable OpaqueStorage opaque_{}; + StoredFunction* function_{nullptr}; +}; + +// Makes a ftl::Function given a function object `F`. +template <typename F, typename T = details::function_traits<F>> +Function(const F&) -> Function<typename T::type, T::size>; + +template <typename F> +auto make_function(const F& f) -> decltype(Function{f}) { + return Function{f}; +} + +// Makes a ftl::Function given a `MemberFunction` and a instance pointer to the associated `Class`. +template <auto MemberFunction, typename Class> +auto make_function(Class* instance) + -> decltype(Function{details::bind_member_function<MemberFunction>( + instance, + static_cast<details::remove_member_function_pointer_t<MemberFunction>*>(nullptr))}) { + return Function{details::bind_member_function<MemberFunction>( + instance, static_cast<details::remove_member_function_pointer_t<MemberFunction>*>(nullptr))}; +} + +// Makes a ftl::Function given an ordinary free function. +template <auto FreeFunction> +auto make_function() -> decltype(Function{ + details::bind_free_function<FreeFunction>(static_cast<decltype(FreeFunction)>(nullptr))}) { + return Function{ + details::bind_free_function<FreeFunction>(static_cast<decltype(FreeFunction)>(nullptr))}; +} + +} // namespace android::ftl diff --git a/include/input/Input.h b/include/input/Input.h index 88d1c11090..1c4ea6b416 100644 --- a/include/input/Input.h +++ b/include/input/Input.h @@ -257,6 +257,10 @@ enum class KeyState { bool isStylusToolType(ToolType toolType); +struct PointerProperties; + +bool isStylusEvent(uint32_t source, const std::vector<PointerProperties>& properties); + /* * Flags that flow alongside events in the input dispatch system to help with certain * policy decisions such as waking from device sleep. @@ -282,6 +286,7 @@ enum { // Indicates that the key represents a special gesture that has been detected by // the touch firmware or driver. Causes touch events from the same device to be canceled. + // This policy flag prevents key events from changing touch mode state. POLICY_FLAG_GESTURE = 0x00000008, // Indicates that key usage mapping represents a fallback mapping. @@ -502,14 +507,17 @@ struct PointerProperties { toolType = ToolType::UNKNOWN; } - bool operator==(const PointerProperties& other) const; + bool operator==(const PointerProperties& other) const = default; inline bool operator!=(const PointerProperties& other) const { return !(*this == other); } - void copyFrom(const PointerProperties& other); + PointerProperties& operator=(const PointerProperties&) = default; }; +// TODO(b/211379801) : Use a strong type from ftl/mixins.h instead +using DeviceId = int32_t; + /* * Input events. */ @@ -521,7 +529,7 @@ public: inline int32_t getId() const { return mId; } - inline int32_t getDeviceId() const { return mDeviceId; } + inline DeviceId getDeviceId() const { return mDeviceId; } inline uint32_t getSource() const { return mSource; } @@ -536,13 +544,13 @@ public: static int32_t nextId(); protected: - void initialize(int32_t id, int32_t deviceId, uint32_t source, int32_t displayId, + void initialize(int32_t id, DeviceId deviceId, uint32_t source, int32_t displayId, std::array<uint8_t, 32> hmac); void initialize(const InputEvent& from); int32_t mId; - int32_t mDeviceId; + DeviceId mDeviceId; uint32_t mSource; int32_t mDisplayId; std::array<uint8_t, 32> mHmac; @@ -557,7 +565,7 @@ class KeyEvent : public InputEvent { public: virtual ~KeyEvent() { } - virtual InputEventType getType() const { return InputEventType::KEY; } + InputEventType getType() const override { return InputEventType::KEY; } inline int32_t getAction() const { return mAction; } @@ -580,7 +588,7 @@ public: static const char* getLabel(int32_t keyCode); static std::optional<int> getKeyCodeFromLabel(const char* label); - void initialize(int32_t id, int32_t deviceId, uint32_t source, int32_t displayId, + void initialize(int32_t id, DeviceId deviceId, uint32_t source, int32_t displayId, std::array<uint8_t, 32> hmac, int32_t action, int32_t flags, int32_t keyCode, int32_t scanCode, int32_t metaState, int32_t repeatCount, nsecs_t downTime, nsecs_t eventTime); @@ -608,7 +616,7 @@ class MotionEvent : public InputEvent { public: virtual ~MotionEvent() { } - virtual InputEventType getType() const { return InputEventType::MOTION; } + InputEventType getType() const override { return InputEventType::MOTION; } inline int32_t getAction() const { return mAction; } @@ -844,7 +852,7 @@ public: ssize_t findPointerIndex(int32_t pointerId) const; - void initialize(int32_t id, int32_t deviceId, uint32_t source, int32_t displayId, + void initialize(int32_t id, DeviceId deviceId, uint32_t source, int32_t displayId, std::array<uint8_t, 32> hmac, int32_t action, int32_t actionButton, int32_t flags, int32_t edgeFlags, int32_t metaState, int32_t buttonState, MotionClassification classification, const ui::Transform& transform, @@ -936,7 +944,7 @@ class FocusEvent : public InputEvent { public: virtual ~FocusEvent() {} - virtual InputEventType getType() const override { return InputEventType::FOCUS; } + InputEventType getType() const override { return InputEventType::FOCUS; } inline bool getHasFocus() const { return mHasFocus; } @@ -955,7 +963,7 @@ class CaptureEvent : public InputEvent { public: virtual ~CaptureEvent() {} - virtual InputEventType getType() const override { return InputEventType::CAPTURE; } + InputEventType getType() const override { return InputEventType::CAPTURE; } inline bool getPointerCaptureEnabled() const { return mPointerCaptureEnabled; } @@ -974,7 +982,7 @@ class DragEvent : public InputEvent { public: virtual ~DragEvent() {} - virtual InputEventType getType() const override { return InputEventType::DRAG; } + InputEventType getType() const override { return InputEventType::DRAG; } inline bool isExiting() const { return mIsExiting; } @@ -998,7 +1006,7 @@ class TouchModeEvent : public InputEvent { public: virtual ~TouchModeEvent() {} - virtual InputEventType getType() const override { return InputEventType::TOUCH_MODE; } + InputEventType getType() const override { return InputEventType::TOUCH_MODE; } inline bool isInTouchMode() const { return mIsInTouchMode; } @@ -1022,7 +1030,7 @@ struct __attribute__((__packed__)) VerifiedInputEvent { }; Type type; - int32_t deviceId; + DeviceId deviceId; nsecs_t eventTimeNanos; uint32_t source; int32_t displayId; @@ -1130,6 +1138,24 @@ private: std::queue<std::unique_ptr<TouchModeEvent>> mTouchModeEventPool; }; +/** + * An input event factory implementation that simply creates the input events on the heap, when + * needed. The caller is responsible for destroying the returned references. + * It is recommended that the caller wrap these return values into std::unique_ptr. + */ +class DynamicInputEventFactory : public InputEventFactoryInterface { +public: + explicit DynamicInputEventFactory(){}; + ~DynamicInputEventFactory(){}; + + KeyEvent* createKeyEvent() override { return new KeyEvent(); }; + MotionEvent* createMotionEvent() override { return new MotionEvent(); }; + FocusEvent* createFocusEvent() override { return new FocusEvent(); }; + CaptureEvent* createCaptureEvent() override { return new CaptureEvent(); }; + DragEvent* createDragEvent() override { return new DragEvent(); }; + TouchModeEvent* createTouchModeEvent() override { return new TouchModeEvent(); }; +}; + /* * Describes a unique request to enable or disable Pointer Capture. */ diff --git a/include/input/InputEventBuilders.h b/include/input/InputEventBuilders.h index 9c0c10e603..2d23b97386 100644 --- a/include/input/InputEventBuilders.h +++ b/include/input/InputEventBuilders.h @@ -160,4 +160,90 @@ private: std::vector<PointerBuilder> mPointers; }; +class KeyEventBuilder { +public: + KeyEventBuilder(int32_t action, int32_t source) { + mAction = action; + mSource = source; + mEventTime = systemTime(SYSTEM_TIME_MONOTONIC); + mDownTime = mEventTime; + } + + KeyEventBuilder(const KeyEvent& event) { + mAction = event.getAction(); + mDeviceId = event.getDeviceId(); + mSource = event.getSource(); + mDownTime = event.getDownTime(); + mEventTime = event.getEventTime(); + mDisplayId = event.getDisplayId(); + mFlags = event.getFlags(); + mKeyCode = event.getKeyCode(); + mScanCode = event.getScanCode(); + mMetaState = event.getMetaState(); + mRepeatCount = event.getRepeatCount(); + } + + KeyEventBuilder& deviceId(int32_t deviceId) { + mDeviceId = deviceId; + return *this; + } + + KeyEventBuilder& downTime(nsecs_t downTime) { + mDownTime = downTime; + return *this; + } + + KeyEventBuilder& eventTime(nsecs_t eventTime) { + mEventTime = eventTime; + return *this; + } + + KeyEventBuilder& displayId(int32_t displayId) { + mDisplayId = displayId; + return *this; + } + + KeyEventBuilder& policyFlags(int32_t policyFlags) { + mPolicyFlags = policyFlags; + return *this; + } + + KeyEventBuilder& addFlag(uint32_t flags) { + mFlags |= flags; + return *this; + } + + KeyEventBuilder& keyCode(int32_t keyCode) { + mKeyCode = keyCode; + return *this; + } + + KeyEventBuilder& repeatCount(int32_t repeatCount) { + mRepeatCount = repeatCount; + return *this; + } + + KeyEvent build() const { + KeyEvent event{}; + event.initialize(InputEvent::nextId(), mDeviceId, mSource, mDisplayId, INVALID_HMAC, + mAction, mFlags, mKeyCode, mScanCode, mMetaState, mRepeatCount, mDownTime, + mEventTime); + return event; + } + +private: + int32_t mAction; + int32_t mDeviceId = DEFAULT_DEVICE_ID; + uint32_t mSource; + nsecs_t mDownTime; + nsecs_t mEventTime; + int32_t mDisplayId{ADISPLAY_ID_DEFAULT}; + uint32_t mPolicyFlags = DEFAULT_POLICY_FLAGS; + int32_t mFlags{0}; + int32_t mKeyCode{AKEYCODE_UNKNOWN}; + int32_t mScanCode{0}; + int32_t mMetaState{AMETA_NONE}; + int32_t mRepeatCount{0}; +}; + } // namespace android diff --git a/include/input/InputEventLabels.h b/include/input/InputEventLabels.h index 909bf087dd..44247c1249 100644 --- a/include/input/InputEventLabels.h +++ b/include/input/InputEventLabels.h @@ -69,6 +69,12 @@ public: static EvdevEventLabel getLinuxEvdevLabel(int32_t type, int32_t code, int32_t value); + static std::optional<int> getLinuxEvdevEventTypeByLabel(const char* label); + + static std::optional<int> getLinuxEvdevEventCodeByLabel(int32_t type, const char* label); + + static std::optional<int> getLinuxEvdevInputPropByLabel(const char* label); + private: InputEventLookup(); diff --git a/include/input/InputVerifier.h b/include/input/InputVerifier.h index 3715408388..14dd463425 100644 --- a/include/input/InputVerifier.h +++ b/include/input/InputVerifier.h @@ -46,11 +46,13 @@ class InputVerifier { public: InputVerifier(const std::string& name); - android::base::Result<void> processMovement(int32_t deviceId, int32_t action, + android::base::Result<void> processMovement(int32_t deviceId, int32_t source, int32_t action, uint32_t pointerCount, const PointerProperties* pointerProperties, const PointerCoords* pointerCoords, int32_t flags); + void resetDevice(int32_t deviceId); + private: rust::Box<android::input::verifier::InputVerifier> mVerifier; }; diff --git a/include/input/KeyCharacterMap.h b/include/input/KeyCharacterMap.h index b2e8baade3..dfcf766402 100644 --- a/include/input/KeyCharacterMap.h +++ b/include/input/KeyCharacterMap.h @@ -146,7 +146,7 @@ public: #ifdef __linux__ /* Reads a key map from a parcel. */ - static std::shared_ptr<KeyCharacterMap> readFromParcel(Parcel* parcel); + static std::unique_ptr<KeyCharacterMap> readFromParcel(Parcel* parcel); /* Writes a key map to a parcel. */ void writeToParcel(Parcel* parcel) const; diff --git a/include/input/KeyLayoutMap.h b/include/input/KeyLayoutMap.h index 8c3c74af20..b126abecea 100644 --- a/include/input/KeyLayoutMap.h +++ b/include/input/KeyLayoutMap.h @@ -17,13 +17,13 @@ #pragma once #include <android-base/result.h> +#include <input/InputDevice.h> + #include <stdint.h> #include <utils/Errors.h> #include <utils/Tokenizer.h> #include <set> -#include <input/InputDevice.h> - namespace android { struct AxisInfo { diff --git a/include/input/MotionPredictor.h b/include/input/MotionPredictor.h index 8797962886..3b6e40183f 100644 --- a/include/input/MotionPredictor.h +++ b/include/input/MotionPredictor.h @@ -19,6 +19,7 @@ #include <cstdint> #include <memory> #include <mutex> +#include <optional> #include <string> #include <unordered_map> @@ -57,20 +58,23 @@ static inline bool isMotionPredictionEnabled() { */ class MotionPredictor { public: + using ReportAtomFunction = MotionPredictorMetricsManager::ReportAtomFunction; + /** * Parameters: * predictionTimestampOffsetNanos: additional, constant shift to apply to the target * prediction time. The prediction will target the time t=(prediction time + * predictionTimestampOffsetNanos). * - * modelPath: filesystem path to a TfLiteMotionPredictorModel flatbuffer, or nullptr to use the - * default model path. - * - * checkEnableMotionPredition: the function to check whether the prediction should run. Used to + * checkEnableMotionPrediction: the function to check whether the prediction should run. Used to * provide an additional way of turning prediction on and off. Can be toggled at runtime. + * + * reportAtomFunction: the function that will be called to report prediction metrics. If + * omitted, the implementation will choose a default metrics reporting mechanism. */ MotionPredictor(nsecs_t predictionTimestampOffsetNanos, - std::function<bool()> checkEnableMotionPrediction = isMotionPredictionEnabled); + std::function<bool()> checkEnableMotionPrediction = isMotionPredictionEnabled, + ReportAtomFunction reportAtomFunction = {}); /** * Record the actual motion received by the view. This event will be used for calculating the @@ -95,6 +99,8 @@ private: std::optional<MotionEvent> mLastEvent; std::optional<MotionPredictorMetricsManager> mMetricsManager; + + const ReportAtomFunction mReportAtomFunction; }; } // namespace android diff --git a/include/input/MotionPredictorMetricsManager.h b/include/input/MotionPredictorMetricsManager.h index 12e50ba3b4..38472d8df7 100644 --- a/include/input/MotionPredictorMetricsManager.h +++ b/include/input/MotionPredictorMetricsManager.h @@ -18,7 +18,6 @@ #include <cstdint> #include <functional> #include <limits> -#include <optional> #include <vector> #include <input/Input.h> // for MotionEvent @@ -37,15 +36,33 @@ namespace android { * * This class stores AggregatedStrokeMetrics, updating them as new MotionEvents are passed in. When * onRecord receives an UP or CANCEL event, this indicates the end of the stroke, and the final - * AtomFields are computed and reported to the stats library. + * AtomFields are computed and reported to the stats library. The number of atoms reported is equal + * to the value of `maxNumPredictions` passed to the constructor. Each atom corresponds to one + * "prediction time bucket" — the amount of time into the future being predicted. * * If mMockLoggedAtomFields is set, the batch of AtomFields that are reported to the stats library * for one stroke are also stored in mMockLoggedAtomFields at the time they're reported. */ class MotionPredictorMetricsManager { public: - // Note: the MetricsManager assumes that the input interval equals the prediction interval. - MotionPredictorMetricsManager(nsecs_t predictionInterval, size_t maxNumPredictions); + struct AtomFields; + + using ReportAtomFunction = std::function<void(const AtomFields&)>; + + static void defaultReportAtomFunction(const AtomFields& atomFields); + + // Parameters: + // • predictionInterval: the time interval between successive prediction target timestamps. + // Note: the MetricsManager assumes that the input interval equals the prediction interval. + // • maxNumPredictions: the maximum number of distinct target timestamps the prediction model + // will generate predictions for. The MetricsManager reports this many atoms per stroke. + // • [Optional] reportAtomFunction: the function that will be called to report metrics. If + // omitted (or if an empty function is given), the `stats_write(…)` function from the Android + // stats library will be used. + MotionPredictorMetricsManager( + nsecs_t predictionInterval, + size_t maxNumPredictions, + ReportAtomFunction reportAtomFunction = defaultReportAtomFunction); // This method should be called once for each call to MotionPredictor::record, receiving the // forwarded MotionEvent argument. @@ -121,7 +138,7 @@ public: // magnitude makes it unobtainable in practice.) static const int NO_DATA_SENTINEL = std::numeric_limits<int32_t>::min(); - // Final metrics reported in the atom. + // Final metric values reported in the atom. struct AtomFields { int deltaTimeBucketMilliseconds = 0; @@ -140,15 +157,6 @@ public: int scaleInvariantOffTrajectoryRmse = NO_DATA_SENTINEL; // millipixels }; - // Allow tests to pass in a mock AtomFields pointer. - // - // When metrics are reported to the stats library on stroke end, they will also be written to - // mockLoggedAtomFields, overwriting existing data. The size of mockLoggedAtomFields will equal - // the number of calls to stats_write for that stroke. - void setMockLoggedAtomFields(std::vector<AtomFields>* mockLoggedAtomFields) { - mMockLoggedAtomFields = mockLoggedAtomFields; - } - private: // The interval between consecutive predictions' target timestamps. We assume that the input // interval also equals this value. @@ -172,11 +180,7 @@ private: std::vector<AggregatedStrokeMetrics> mAggregatedMetrics; std::vector<AtomFields> mAtomFields; - // Non-owning pointer to the location of mock AtomFields. If present, will be filled with the - // values reported to stats_write on each batch of reported metrics. - // - // This pointer must remain valid as long as the MotionPredictorMetricsManager exists. - std::vector<AtomFields>* mMockLoggedAtomFields = nullptr; + const ReportAtomFunction mReportAtomFunction; // Helper methods for the implementation of onRecord and onPredict. @@ -196,10 +200,7 @@ private: // Computes the atom fields to mAtomFields from the values in mAggregatedMetrics. void computeAtomFields(); - // Reports the metrics given by the current data in mAtomFields: - // • If on an Android device, reports the metrics to stats_write. - // • If mMockLoggedAtomFields is present, it will be overwritten with logged metrics, with one - // AtomFields element per call to stats_write. + // Reports the current data in mAtomFields by calling mReportAtomFunction. void reportMetrics(); }; diff --git a/include/input/PrintTools.h b/include/input/PrintTools.h index 0e3fbb1982..83fffa37c6 100644 --- a/include/input/PrintTools.h +++ b/include/input/PrintTools.h @@ -20,6 +20,7 @@ #include <map> #include <optional> #include <set> +#include <sstream> #include <string> #include <vector> @@ -33,6 +34,13 @@ std::string bitsetToString(const std::bitset<N>& bitset) { return bitset.to_string(); } +template <class T> +std::string streamableToString(const T& streamable) { + std::stringstream out; + out << streamable; + return out.str(); +} + template <typename T> inline std::string constToString(const T& v) { return std::to_string(v); @@ -75,11 +83,12 @@ std::string dumpSet(const std::set<T>& v, std::string (*toString)(const T&) = co } /** - * Convert a map to string. Both keys and values of the map should be integral type. + * Convert a map or multimap to string. Both keys and values of the map should be integral type. */ -template <typename K, typename V> -std::string dumpMap(const std::map<K, V>& map, std::string (*keyToString)(const K&) = constToString, - std::string (*valueToString)(const V&) = constToString) { +template <typename T> +std::string dumpMap(const T& map, + std::string (*keyToString)(const typename T::key_type&) = constToString, + std::string (*valueToString)(const typename T::mapped_type&) = constToString) { std::string out; for (const auto& [k, v] : map) { if (!out.empty()) { @@ -104,15 +113,13 @@ std::string dumpMapKeys(const std::map<K, V>& map, return out.empty() ? "{}" : (out + "}"); } -/** - * Convert a vector to a string. The values of the vector should be of a type supported by - * constToString. - */ +/** Convert a vector to a string. */ template <typename T> -std::string dumpVector(std::vector<T> values) { - std::string dump = constToString(values[0]); +std::string dumpVector(const std::vector<T>& values, + std::string (*valueToString)(const T&) = constToString) { + std::string dump = valueToString(values[0]); for (size_t i = 1; i < values.size(); i++) { - dump += ", " + constToString(values[i]); + dump += ", " + valueToString(values[i]); } return dump; } diff --git a/include/input/RingBuffer.h b/include/input/RingBuffer.h index 37fe5afeea..d2747d6fad 100644 --- a/include/input/RingBuffer.h +++ b/include/input/RingBuffer.h @@ -24,7 +24,6 @@ #include <type_traits> #include <utility> -#include <android-base/logging.h> #include <android-base/stringprintf.h> namespace android { @@ -277,15 +276,16 @@ private: // Converts the index of an element in [0, size()] to its corresponding index in mBuffer. size_type bufferIndex(size_type elementIndex) const { - CHECK_LE(elementIndex, size()); + if (elementIndex > size()) { + abort(); + } size_type index = mBegin + elementIndex; if (index >= capacity()) { index -= capacity(); } - CHECK_LT(index, capacity()) - << android::base::StringPrintf("Invalid index calculated for element (%zu) " - "in buffer of size %zu", - elementIndex, size()); + if (index >= capacity()) { + abort(); + } return index; } diff --git a/include/input/TraceTools.h b/include/input/TraceTools.h new file mode 100644 index 0000000000..81fc7af4ae --- /dev/null +++ b/include/input/TraceTools.h @@ -0,0 +1,29 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <utils/Trace.h> +#include <optional> + +// A macro for tracing when the given condition is true. +// This macro relies on the fact that only one branch of the ternary operator is evaluated. That +// means if `message` is an expression that evaluates to a std::string value, the value will +// not be computed unless the condition is true. +#define ATRACE_NAME_IF(condition, message) \ + const auto _trace_token = condition \ + ? std::make_optional<android::ScopedTrace>(ATRACE_TAG, (message).c_str()) \ + : std::nullopt diff --git a/include/input/VelocityControl.h b/include/input/VelocityControl.h index f3c201e7c4..b78f63e1ae 100644 --- a/include/input/VelocityControl.h +++ b/include/input/VelocityControl.h @@ -88,7 +88,7 @@ public: VelocityControl(); /* Gets the various parameters. */ - VelocityControlParameters& getParameters(); + const VelocityControlParameters& getParameters() const; /* Sets the various parameters. */ void setParameters(const VelocityControlParameters& parameters); diff --git a/include/input/VelocityTracker.h b/include/input/VelocityTracker.h index 4257cb5e05..ee7445544b 100644 --- a/include/input/VelocityTracker.h +++ b/include/input/VelocityTracker.h @@ -16,7 +16,9 @@ #pragma once +#include <android/os/IInputConstants.h> #include <input/Input.h> +#include <input/RingBuffer.h> #include <utils/BitSet.h> #include <utils/Timers.h> #include <map> @@ -31,40 +33,25 @@ class VelocityTrackerStrategy; */ class VelocityTracker { public: + static const size_t MAX_DEGREE = 4; + enum class Strategy : int32_t { - DEFAULT = -1, - MIN = 0, - IMPULSE = 0, - LSQ1 = 1, - LSQ2 = 2, - LSQ3 = 3, - WLSQ2_DELTA = 4, - WLSQ2_CENTRAL = 5, - WLSQ2_RECENT = 6, - INT1 = 7, - INT2 = 8, - LEGACY = 9, + DEFAULT = android::os::IInputConstants::VELOCITY_TRACKER_STRATEGY_DEFAULT, + IMPULSE = android::os::IInputConstants::VELOCITY_TRACKER_STRATEGY_IMPULSE, + LSQ1 = android::os::IInputConstants::VELOCITY_TRACKER_STRATEGY_LSQ1, + LSQ2 = android::os::IInputConstants::VELOCITY_TRACKER_STRATEGY_LSQ2, + LSQ3 = android::os::IInputConstants::VELOCITY_TRACKER_STRATEGY_LSQ3, + WLSQ2_DELTA = android::os::IInputConstants::VELOCITY_TRACKER_STRATEGY_WLSQ2_DELTA, + WLSQ2_CENTRAL = android::os::IInputConstants::VELOCITY_TRACKER_STRATEGY_WLSQ2_CENTRAL, + WLSQ2_RECENT = android::os::IInputConstants::VELOCITY_TRACKER_STRATEGY_WLSQ2_RECENT, + INT1 = android::os::IInputConstants::VELOCITY_TRACKER_STRATEGY_INT1, + INT2 = android::os::IInputConstants::VELOCITY_TRACKER_STRATEGY_INT2, + LEGACY = android::os::IInputConstants::VELOCITY_TRACKER_STRATEGY_LEGACY, + MIN = IMPULSE, MAX = LEGACY, ftl_last = LEGACY, }; - struct Estimator { - static const size_t MAX_DEGREE = 4; - - // Estimator time base. - nsecs_t time = 0; - - // Polynomial coefficients describing motion. - std::array<float, MAX_DEGREE + 1> coeff{}; - - // Polynomial degree (number of coefficients), or zero if no information is - // available. - uint32_t degree = 0; - - // Confidence (coefficient of determination), between 0 (no fit) and 1 (perfect fit). - float confidence = 0; - }; - /* * Contains all available velocity data from a VelocityTracker. */ @@ -111,7 +98,7 @@ public: void addMovement(nsecs_t eventTime, int32_t pointerId, int32_t axis, float position); // Adds movement information for all pointers in a MotionEvent, including historical samples. - void addMovement(const MotionEvent* event); + void addMovement(const MotionEvent& event); // Returns the velocity of the specified pointer id and axis in position units per second. // Returns empty optional if there is insufficient movement information for the pointer, or if @@ -123,11 +110,6 @@ public: // [-maxVelocity, maxVelocity], inclusive. ComputedVelocity getComputedVelocity(int32_t units, float maxVelocity); - // Gets an estimator for the recent movements of the specified pointer id for the given axis. - // Returns false and clears the estimator if there is no information available - // about the pointer. - std::optional<Estimator> getEstimator(int32_t axis, int32_t pointerId) const; - // Gets the active pointer id, or -1 if none. inline int32_t getActivePointerId() const { return mActivePointerId.value_or(-1); } @@ -168,14 +150,48 @@ public: virtual void clearPointer(int32_t pointerId) = 0; virtual void addMovement(nsecs_t eventTime, int32_t pointerId, float position) = 0; - virtual std::optional<VelocityTracker::Estimator> getEstimator(int32_t pointerId) const = 0; + virtual std::optional<float> getVelocity(int32_t pointerId) const = 0; }; +/** + * A `VelocityTrackerStrategy` that accumulates added data points and processes the accumulated data + * points when getting velocity. + */ +class AccumulatingVelocityTrackerStrategy : public VelocityTrackerStrategy { +public: + AccumulatingVelocityTrackerStrategy(nsecs_t horizonNanos, bool maintainHorizonDuringAdd); + + void addMovement(nsecs_t eventTime, int32_t pointerId, float position) override; + void clearPointer(int32_t pointerId) override; + +protected: + struct Movement { + nsecs_t eventTime; + float position; + }; + + // Number of samples to keep. + // If different strategies would like to maintain different history size, we can make this a + // protected const field. + static constexpr uint32_t HISTORY_SIZE = 20; + + /** + * Duration, in nanoseconds, since the latest movement where a movement may be considered for + * velocity calculation. + */ + const nsecs_t mHorizonNanos; + /** + * If true, data points outside of horizon (see `mHorizonNanos`) will be cleared after each + * addition of a new movement. + */ + const bool mMaintainHorizonDuringAdd; + std::map<int32_t /*pointerId*/, RingBuffer<Movement>> mMovements; +}; /* * Velocity tracker algorithm based on least-squares linear regression. */ -class LeastSquaresVelocityTrackerStrategy : public VelocityTrackerStrategy { +class LeastSquaresVelocityTrackerStrategy : public AccumulatingVelocityTrackerStrategy { public: enum class Weighting { // No weights applied. All data points are equally reliable. @@ -192,13 +208,11 @@ public: RECENT, }; - // Degree must be no greater than Estimator::MAX_DEGREE. + // Degree must be no greater than VelocityTracker::MAX_DEGREE. LeastSquaresVelocityTrackerStrategy(uint32_t degree, Weighting weighting = Weighting::NONE); ~LeastSquaresVelocityTrackerStrategy() override; - void clearPointer(int32_t pointerId) override; - void addMovement(nsecs_t eventTime, int32_t pointerId, float position) override; - std::optional<VelocityTracker::Estimator> getEstimator(int32_t pointerId) const override; + std::optional<float> getVelocity(int32_t pointerId) const override; private: // Sample horizon. @@ -206,23 +220,19 @@ private: // changes in direction. static const nsecs_t HORIZON = 100 * 1000000; // 100 ms - // Number of samples to keep. - static const uint32_t HISTORY_SIZE = 20; - - struct Movement { - nsecs_t eventTime; - float position; - }; - float chooseWeight(int32_t pointerId, uint32_t index) const; + /** + * An optimized least-squares solver for degree 2 and no weight (i.e. `Weighting.NONE`). + * The provided container of movements shall NOT be empty, and shall have the movements in + * chronological order. + */ + std::optional<float> solveUnweightedLeastSquaresDeg2( + const RingBuffer<Movement>& movements) const; const uint32_t mDegree; const Weighting mWeighting; - std::map<int32_t /*pointerId*/, size_t /*positionInArray*/> mIndex; - std::map<int32_t /*pointerId*/, std::array<Movement, HISTORY_SIZE>> mMovements; }; - /* * Velocity tracker algorithm that uses an IIR filter. */ @@ -234,7 +244,7 @@ public: void clearPointer(int32_t pointerId) override; void addMovement(nsecs_t eventTime, int32_t pointerId, float positions) override; - std::optional<VelocityTracker::Estimator> getEstimator(int32_t pointerId) const override; + std::optional<float> getVelocity(int32_t pointerId) const override; private: // Current state estimate for a particular pointer. @@ -251,49 +261,33 @@ private: void initState(State& state, nsecs_t eventTime, float pos) const; void updateState(State& state, nsecs_t eventTime, float pos) const; - void populateEstimator(const State& state, VelocityTracker::Estimator* outEstimator) const; }; /* * Velocity tracker strategy used prior to ICS. */ -class LegacyVelocityTrackerStrategy : public VelocityTrackerStrategy { +class LegacyVelocityTrackerStrategy : public AccumulatingVelocityTrackerStrategy { public: LegacyVelocityTrackerStrategy(); ~LegacyVelocityTrackerStrategy() override; - void clearPointer(int32_t pointerId) override; - void addMovement(nsecs_t eventTime, int32_t pointerId, float position) override; - std::optional<VelocityTracker::Estimator> getEstimator(int32_t pointerId) const override; + std::optional<float> getVelocity(int32_t pointerId) const override; private: // Oldest sample to consider when calculating the velocity. static const nsecs_t HORIZON = 200 * 1000000; // 100 ms - // Number of samples to keep. - static const uint32_t HISTORY_SIZE = 20; - // The minimum duration between samples when estimating velocity. static const nsecs_t MIN_DURATION = 10 * 1000000; // 10 ms - - struct Movement { - nsecs_t eventTime; - float position; - }; - - std::map<int32_t /*pointerId*/, size_t /*positionInArray*/> mIndex; - std::map<int32_t /*pointerId*/, std::array<Movement, HISTORY_SIZE>> mMovements; }; -class ImpulseVelocityTrackerStrategy : public VelocityTrackerStrategy { +class ImpulseVelocityTrackerStrategy : public AccumulatingVelocityTrackerStrategy { public: ImpulseVelocityTrackerStrategy(bool deltaValues); ~ImpulseVelocityTrackerStrategy() override; - void clearPointer(int32_t pointerId) override; - void addMovement(nsecs_t eventTime, int32_t pointerId, float position) override; - std::optional<VelocityTracker::Estimator> getEstimator(int32_t pointerId) const override; + std::optional<float> getVelocity(int32_t pointerId) const override; private: // Sample horizon. @@ -301,21 +295,10 @@ private: // changes in direction. static constexpr nsecs_t HORIZON = 100 * 1000000; // 100 ms - // Number of samples to keep. - static constexpr size_t HISTORY_SIZE = 20; - - struct Movement { - nsecs_t eventTime; - float position; - }; - // Whether or not the input movement values for the strategy come in the form of delta values. // If the input values are not deltas, the strategy needs to calculate deltas as part of its // velocity calculation. const bool mDeltaValues; - - std::map<int32_t /*pointerId*/, size_t /*positionInArray*/> mIndex; - std::map<int32_t /*pointerId*/, std::array<Movement, HISTORY_SIZE>> mMovements; }; } // namespace android diff --git a/include/powermanager/PowerHalController.h b/include/powermanager/PowerHalController.h index 82e4551c3c..9e426d3ea3 100644 --- a/include/powermanager/PowerHalController.h +++ b/include/powermanager/PowerHalController.h @@ -17,11 +17,11 @@ #ifndef ANDROID_POWERHALCONTROLLER_H #define ANDROID_POWERHALCONTROLLER_H +#include <aidl/android/hardware/power/Boost.h> +#include <aidl/android/hardware/power/IPower.h> +#include <aidl/android/hardware/power/IPowerHintSession.h> +#include <aidl/android/hardware/power/Mode.h> #include <android-base/thread_annotations.h> -#include <android/hardware/power/Boost.h> -#include <android/hardware/power/IPower.h> -#include <android/hardware/power/IPowerHintSession.h> -#include <android/hardware/power/Mode.h> #include <powermanager/PowerHalWrapper.h> namespace android { @@ -55,11 +55,13 @@ public: virtual void init(); - virtual HalResult<void> setBoost(hardware::power::Boost boost, int32_t durationMs) override; - virtual HalResult<void> setMode(hardware::power::Mode mode, bool enabled) override; - virtual HalResult<sp<hardware::power::IPowerHintSession>> createHintSession( - int32_t tgid, int32_t uid, const std::vector<int32_t>& threadIds, - int64_t durationNanos) override; + virtual HalResult<void> setBoost(aidl::android::hardware::power::Boost boost, + int32_t durationMs) override; + virtual HalResult<void> setMode(aidl::android::hardware::power::Mode mode, + bool enabled) override; + virtual HalResult<std::shared_ptr<aidl::android::hardware::power::IPowerHintSession>> + createHintSession(int32_t tgid, int32_t uid, const std::vector<int32_t>& threadIds, + int64_t durationNanos) override; virtual HalResult<int64_t> getHintSessionPreferredRate() override; private: diff --git a/include/powermanager/PowerHalLoader.h b/include/powermanager/PowerHalLoader.h index e0384f31db..cbbfa597ba 100644 --- a/include/powermanager/PowerHalLoader.h +++ b/include/powermanager/PowerHalLoader.h @@ -17,11 +17,11 @@ #ifndef ANDROID_POWERHALLOADER_H #define ANDROID_POWERHALLOADER_H +#include <aidl/android/hardware/power/IPower.h> #include <android-base/thread_annotations.h> #include <android/hardware/power/1.1/IPower.h> #include <android/hardware/power/1.2/IPower.h> #include <android/hardware/power/1.3/IPower.h> -#include <android/hardware/power/IPower.h> namespace android { @@ -31,7 +31,7 @@ namespace power { class PowerHalLoader { public: static void unloadAll(); - static sp<hardware::power::IPower> loadAidl(); + static std::shared_ptr<aidl::android::hardware::power::IPower> loadAidl(); static sp<hardware::power::V1_0::IPower> loadHidlV1_0(); static sp<hardware::power::V1_1::IPower> loadHidlV1_1(); static sp<hardware::power::V1_2::IPower> loadHidlV1_2(); @@ -39,7 +39,7 @@ public: private: static std::mutex gHalMutex; - static sp<hardware::power::IPower> gHalAidl GUARDED_BY(gHalMutex); + static std::shared_ptr<aidl::android::hardware::power::IPower> gHalAidl GUARDED_BY(gHalMutex); static sp<hardware::power::V1_0::IPower> gHalHidlV1_0 GUARDED_BY(gHalMutex); static sp<hardware::power::V1_1::IPower> gHalHidlV1_1 GUARDED_BY(gHalMutex); static sp<hardware::power::V1_2::IPower> gHalHidlV1_2 GUARDED_BY(gHalMutex); diff --git a/include/powermanager/PowerHalWrapper.h b/include/powermanager/PowerHalWrapper.h index 8028aa86e1..4e4a1b000d 100644 --- a/include/powermanager/PowerHalWrapper.h +++ b/include/powermanager/PowerHalWrapper.h @@ -17,14 +17,15 @@ #ifndef ANDROID_POWERHALWRAPPER_H #define ANDROID_POWERHALWRAPPER_H +#include <aidl/android/hardware/power/Boost.h> +#include <aidl/android/hardware/power/IPower.h> +#include <aidl/android/hardware/power/IPowerHintSession.h> +#include <aidl/android/hardware/power/Mode.h> #include <android-base/thread_annotations.h> #include <android/hardware/power/1.1/IPower.h> #include <android/hardware/power/1.2/IPower.h> #include <android/hardware/power/1.3/IPower.h> -#include <android/hardware/power/Boost.h> -#include <android/hardware/power/IPower.h> -#include <android/hardware/power/IPowerHintSession.h> -#include <android/hardware/power/Mode.h> +#include <binder/Status.h> namespace android { @@ -47,7 +48,7 @@ public: } static HalResult<T> unsupported() { return HalResult("", /* unsupported= */ true); } - static HalResult<T> fromStatus(binder::Status status, T data) { + static HalResult<T> fromStatus(const binder::Status& status, T data) { if (status.exceptionCode() == binder::Status::EX_UNSUPPORTED_OPERATION) { return HalResult<T>::unsupported(); } @@ -56,14 +57,28 @@ public: } return HalResult<T>::failed(std::string(status.toString8().c_str())); } - static HalResult<T> fromStatus(hardware::power::V1_0::Status status, T data); + + static HalResult<T> fromStatus(const ndk::ScopedAStatus& status, T data) { + if (status.getExceptionCode() == binder::Status::EX_UNSUPPORTED_OPERATION) { + return HalResult<T>::unsupported(); + } + if (status.isOk()) { + return HalResult<T>::ok(data); + } + return HalResult<T>::failed(std::string(status.getDescription())); + } template <typename R> - static HalResult<T> fromReturn(hardware::Return<R>& ret, T data); + static HalResult<T> fromReturn(hardware::Return<R>& ret, T data) { + return ret.isOk() ? HalResult<T>::ok(data) : HalResult<T>::failed(ret.description()); + } template <typename R> static HalResult<T> fromReturn(hardware::Return<R>& ret, hardware::power::V1_0::Status status, - T data); + T data) { + return ret.isOk() ? HalResult<T>::fromStatus(status, data) + : HalResult<T>::failed(ret.description()); + } // This will throw std::bad_optional_access if this result is not ok. const T& value() const { return mValue.value(); } @@ -91,12 +106,30 @@ public: static HalResult<void> failed(std::string msg) { return HalResult(std::move(msg)); } static HalResult<void> unsupported() { return HalResult(/* unsupported= */ true); } - static HalResult<void> fromStatus(status_t status); - static HalResult<void> fromStatus(binder::Status status); - static HalResult<void> fromStatus(hardware::power::V1_0::Status status); + static HalResult<void> fromStatus(const binder::Status& status) { + if (status.exceptionCode() == binder::Status::EX_UNSUPPORTED_OPERATION) { + return HalResult<void>::unsupported(); + } + if (status.isOk()) { + return HalResult<void>::ok(); + } + return HalResult<void>::failed(std::string(status.toString8().c_str())); + } + + static HalResult<void> fromStatus(const ndk::ScopedAStatus& status) { + if (status.getExceptionCode() == binder::Status::EX_UNSUPPORTED_OPERATION) { + return HalResult<void>::unsupported(); + } + if (status.isOk()) { + return HalResult<void>::ok(); + } + return HalResult<void>::failed(std::string(status.getDescription())); + } template <typename R> - static HalResult<void> fromReturn(hardware::Return<R>& ret); + static HalResult<void> fromReturn(hardware::Return<R>& ret) { + return ret.isOk() ? HalResult<void>::ok() : HalResult<void>::failed(ret.description()); + } bool isOk() const { return !mUnsupported && !mFailed; } bool isFailed() const { return !mUnsupported && mFailed; } @@ -119,11 +152,12 @@ class HalWrapper { public: virtual ~HalWrapper() = default; - virtual HalResult<void> setBoost(hardware::power::Boost boost, int32_t durationMs) = 0; - virtual HalResult<void> setMode(hardware::power::Mode mode, bool enabled) = 0; - virtual HalResult<sp<hardware::power::IPowerHintSession>> createHintSession( - int32_t tgid, int32_t uid, const std::vector<int32_t>& threadIds, - int64_t durationNanos) = 0; + virtual HalResult<void> setBoost(aidl::android::hardware::power::Boost boost, + int32_t durationMs) = 0; + virtual HalResult<void> setMode(aidl::android::hardware::power::Mode mode, bool enabled) = 0; + virtual HalResult<std::shared_ptr<aidl::android::hardware::power::IPowerHintSession>> + createHintSession(int32_t tgid, int32_t uid, const std::vector<int32_t>& threadIds, + int64_t durationNanos) = 0; virtual HalResult<int64_t> getHintSessionPreferredRate() = 0; }; @@ -131,14 +165,15 @@ public: class EmptyHalWrapper : public HalWrapper { public: EmptyHalWrapper() = default; - ~EmptyHalWrapper() = default; + ~EmptyHalWrapper() override = default; - virtual HalResult<void> setBoost(hardware::power::Boost boost, int32_t durationMs) override; - virtual HalResult<void> setMode(hardware::power::Mode mode, bool enabled) override; - virtual HalResult<sp<hardware::power::IPowerHintSession>> createHintSession( + HalResult<void> setBoost(aidl::android::hardware::power::Boost boost, + int32_t durationMs) override; + HalResult<void> setMode(aidl::android::hardware::power::Mode mode, bool enabled) override; + HalResult<std::shared_ptr<aidl::android::hardware::power::IPowerHintSession>> createHintSession( int32_t tgid, int32_t uid, const std::vector<int32_t>& threadIds, int64_t durationNanos) override; - virtual HalResult<int64_t> getHintSessionPreferredRate() override; + HalResult<int64_t> getHintSessionPreferredRate() override; }; // Wrapper for the HIDL Power HAL v1.0. @@ -146,14 +181,15 @@ class HidlHalWrapperV1_0 : public HalWrapper { public: explicit HidlHalWrapperV1_0(sp<hardware::power::V1_0::IPower> handleV1_0) : mHandleV1_0(std::move(handleV1_0)) {} - virtual ~HidlHalWrapperV1_0() = default; + ~HidlHalWrapperV1_0() override = default; - virtual HalResult<void> setBoost(hardware::power::Boost boost, int32_t durationMs) override; - virtual HalResult<void> setMode(hardware::power::Mode mode, bool enabled) override; - virtual HalResult<sp<hardware::power::IPowerHintSession>> createHintSession( + HalResult<void> setBoost(aidl::android::hardware::power::Boost boost, + int32_t durationMs) override; + HalResult<void> setMode(aidl::android::hardware::power::Mode mode, bool enabled) override; + HalResult<std::shared_ptr<aidl::android::hardware::power::IPowerHintSession>> createHintSession( int32_t tgid, int32_t uid, const std::vector<int32_t>& threadIds, int64_t durationNanos) override; - virtual HalResult<int64_t> getHintSessionPreferredRate() override; + HalResult<int64_t> getHintSessionPreferredRate() override; protected: const sp<hardware::power::V1_0::IPower> mHandleV1_0; @@ -167,67 +203,71 @@ private: // Wrapper for the HIDL Power HAL v1.1. class HidlHalWrapperV1_1 : public HidlHalWrapperV1_0 { public: - HidlHalWrapperV1_1(sp<hardware::power::V1_1::IPower> handleV1_1) + explicit HidlHalWrapperV1_1(sp<hardware::power::V1_1::IPower> handleV1_1) : HidlHalWrapperV1_0(std::move(handleV1_1)) {} - virtual ~HidlHalWrapperV1_1() = default; + ~HidlHalWrapperV1_1() override = default; protected: - virtual HalResult<void> sendPowerHint(hardware::power::V1_3::PowerHint hintId, - uint32_t data) override; + HalResult<void> sendPowerHint(hardware::power::V1_3::PowerHint hintId, uint32_t data) override; }; // Wrapper for the HIDL Power HAL v1.2. class HidlHalWrapperV1_2 : public HidlHalWrapperV1_1 { public: - virtual HalResult<void> setBoost(hardware::power::Boost boost, int32_t durationMs) override; - virtual HalResult<void> setMode(hardware::power::Mode mode, bool enabled) override; - HidlHalWrapperV1_2(sp<hardware::power::V1_2::IPower> handleV1_2) + HalResult<void> setBoost(aidl::android::hardware::power::Boost boost, + int32_t durationMs) override; + HalResult<void> setMode(aidl::android::hardware::power::Mode mode, bool enabled) override; + explicit HidlHalWrapperV1_2(sp<hardware::power::V1_2::IPower> handleV1_2) : HidlHalWrapperV1_1(std::move(handleV1_2)) {} - virtual ~HidlHalWrapperV1_2() = default; + ~HidlHalWrapperV1_2() override = default; protected: - virtual HalResult<void> sendPowerHint(hardware::power::V1_3::PowerHint hintId, - uint32_t data) override; + HalResult<void> sendPowerHint(hardware::power::V1_3::PowerHint hintId, uint32_t data) override; }; // Wrapper for the HIDL Power HAL v1.3. class HidlHalWrapperV1_3 : public HidlHalWrapperV1_2 { public: - virtual HalResult<void> setMode(hardware::power::Mode mode, bool enabled) override; - HidlHalWrapperV1_3(sp<hardware::power::V1_3::IPower> handleV1_3) + HalResult<void> setMode(aidl::android::hardware::power::Mode mode, bool enabled) override; + explicit HidlHalWrapperV1_3(sp<hardware::power::V1_3::IPower> handleV1_3) : HidlHalWrapperV1_2(std::move(handleV1_3)) {} - virtual ~HidlHalWrapperV1_3() = default; + ~HidlHalWrapperV1_3() override = default; protected: - virtual HalResult<void> sendPowerHint(hardware::power::V1_3::PowerHint hintId, - uint32_t data) override; + HalResult<void> sendPowerHint(hardware::power::V1_3::PowerHint hintId, uint32_t data) override; }; // Wrapper for the AIDL Power HAL. class AidlHalWrapper : public HalWrapper { public: - explicit AidlHalWrapper(sp<hardware::power::IPower> handle) : mHandle(std::move(handle)) {} - virtual ~AidlHalWrapper() = default; - - virtual HalResult<void> setBoost(hardware::power::Boost boost, int32_t durationMs) override; - virtual HalResult<void> setMode(hardware::power::Mode mode, bool enabled) override; - virtual HalResult<sp<hardware::power::IPowerHintSession>> createHintSession( + explicit AidlHalWrapper(std::shared_ptr<aidl::android::hardware::power::IPower> handle) + : mHandle(std::move(handle)) {} + ~AidlHalWrapper() override = default; + + HalResult<void> setBoost(aidl::android::hardware::power::Boost boost, + int32_t durationMs) override; + HalResult<void> setMode(aidl::android::hardware::power::Mode mode, bool enabled) override; + HalResult<std::shared_ptr<aidl::android::hardware::power::IPowerHintSession>> createHintSession( int32_t tgid, int32_t uid, const std::vector<int32_t>& threadIds, int64_t durationNanos) override; - virtual HalResult<int64_t> getHintSessionPreferredRate() override; + HalResult<int64_t> getHintSessionPreferredRate() override; private: // Control access to the boost and mode supported arrays. std::mutex mBoostMutex; std::mutex mModeMutex; - sp<hardware::power::IPower> mHandle; + std::shared_ptr<aidl::android::hardware::power::IPower> mHandle; // Android framework only sends boost upto DISPLAY_UPDATE_IMMINENT. // Need to increase the array size if more boost supported. - std::array<std::atomic<HalSupport>, - static_cast<int32_t>(hardware::power::Boost::DISPLAY_UPDATE_IMMINENT) + 1> + std::array< + std::atomic<HalSupport>, + static_cast<int32_t>(aidl::android::hardware::power::Boost::DISPLAY_UPDATE_IMMINENT) + + 1> mBoostSupportedArray GUARDED_BY(mBoostMutex) = {HalSupport::UNKNOWN}; std::array<std::atomic<HalSupport>, - static_cast<int32_t>(*(android::enum_range<hardware::power::Mode>().end() - 1)) + 1> + static_cast<int32_t>( + *(ndk::enum_range<aidl::android::hardware::power::Mode>().end() - 1)) + + 1> mModeSupportedArray GUARDED_BY(mModeMutex) = {HalSupport::UNKNOWN}; }; diff --git a/include/private/thermal_private.h b/include/private/thermal_private.h new file mode 100644 index 0000000000..951d953267 --- /dev/null +++ b/include/private/thermal_private.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_PRIVATE_NATIVE_THERMAL_H +#define ANDROID_PRIVATE_NATIVE_THERMAL_H + +#include <stdint.h> + +__BEGIN_DECLS + +/** + * For testing only. + */ +void AThermal_setIThermalServiceForTesting(void* iThermalService); + +__END_DECLS + +#endif // ANDROID_PRIVATE_NATIVE_THERMAL_H
\ No newline at end of file |