summaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
Diffstat (limited to 'include')
-rw-r--r--include/android/performance_hint.h226
-rw-r--r--include/android/sensor.h2
-rw-r--r--include/android/thermal.h66
-rw-r--r--include/ftl/details/function.h135
-rw-r--r--include/ftl/enum.h79
-rw-r--r--include/ftl/function.h297
-rw-r--r--include/input/Input.h54
-rw-r--r--include/input/InputEventBuilders.h86
-rw-r--r--include/input/InputEventLabels.h6
-rw-r--r--include/input/InputVerifier.h4
-rw-r--r--include/input/KeyCharacterMap.h2
-rw-r--r--include/input/KeyLayoutMap.h4
-rw-r--r--include/input/MotionPredictor.h16
-rw-r--r--include/input/MotionPredictorMetricsManager.h47
-rw-r--r--include/input/PrintTools.h29
-rw-r--r--include/input/RingBuffer.h12
-rw-r--r--include/input/TraceTools.h29
-rw-r--r--include/input/VelocityControl.h2
-rw-r--r--include/input/VelocityTracker.h151
-rw-r--r--include/powermanager/PowerHalController.h20
-rw-r--r--include/powermanager/PowerHalLoader.h6
-rw-r--r--include/powermanager/PowerHalWrapper.h146
-rw-r--r--include/private/thermal_private.h31
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