diff options
45 files changed, 975 insertions, 363 deletions
diff --git a/aidl/gui/android/view/Surface.aidl b/aidl/gui/android/view/Surface.aidl index bb3faaff79..668671760c 100644 --- a/aidl/gui/android/view/Surface.aidl +++ b/aidl/gui/android/view/Surface.aidl @@ -17,4 +17,4 @@ package android.view; -@JavaOnlyStableParcelable @NdkOnlyStableParcelable parcelable Surface cpp_header "gui/view/Surface.h" ndk_header "android/native_window_aidl.h"; +@JavaOnlyStableParcelable @NdkOnlyStableParcelable @RustOnlyStableParcelable parcelable Surface cpp_header "gui/view/Surface.h" ndk_header "android/native_window_aidl.h" rust_type "nativewindow::Surface"; diff --git a/cmds/servicemanager/main.cpp b/cmds/servicemanager/main.cpp index ae56cb0ed3..07908ba5b3 100644 --- a/cmds/servicemanager/main.cpp +++ b/cmds/servicemanager/main.cpp @@ -40,15 +40,12 @@ class BinderCallback : public LooperCallback { public: static sp<BinderCallback> setupTo(const sp<Looper>& looper) { sp<BinderCallback> cb = sp<BinderCallback>::make(); + cb->mLooper = looper; - int binder_fd = -1; - IPCThreadState::self()->setupPolling(&binder_fd); - LOG_ALWAYS_FATAL_IF(binder_fd < 0, "Failed to setupPolling: %d", binder_fd); + IPCThreadState::self()->setupPolling(&cb->mBinderFd); + LOG_ALWAYS_FATAL_IF(cb->mBinderFd < 0, "Failed to setupPolling: %d", cb->mBinderFd); - int ret = looper->addFd(binder_fd, - Looper::POLL_CALLBACK, - Looper::EVENT_INPUT, - cb, + int ret = looper->addFd(cb->mBinderFd, Looper::POLL_CALLBACK, Looper::EVENT_INPUT, cb, nullptr /*data*/); LOG_ALWAYS_FATAL_IF(ret != 1, "Failed to add binder FD to Looper"); @@ -59,13 +56,26 @@ public: IPCThreadState::self()->handlePolledCommands(); return 1; // Continue receiving callbacks. } + + void repoll() { + if (!mLooper->repoll(mBinderFd)) { + ALOGE("Failed to repoll binder FD."); + } + } + +private: + sp<Looper> mLooper; + int mBinderFd = -1; }; // LooperCallback for IClientCallback class ClientCallbackCallback : public LooperCallback { public: - static sp<ClientCallbackCallback> setupTo(const sp<Looper>& looper, const sp<ServiceManager>& manager) { + static sp<ClientCallbackCallback> setupTo(const sp<Looper>& looper, + const sp<ServiceManager>& manager, + sp<BinderCallback> binderCallback) { sp<ClientCallbackCallback> cb = sp<ClientCallbackCallback>::make(manager); + cb->mBinderCallback = binderCallback; int fdTimer = timerfd_create(CLOCK_MONOTONIC, 0 /*flags*/); LOG_ALWAYS_FATAL_IF(fdTimer < 0, "Failed to timerfd_create: fd: %d err: %d", fdTimer, errno); @@ -102,12 +112,15 @@ public: } mManager->handleClientCallbacks(); + mBinderCallback->repoll(); // b/316829336 + return 1; // Continue receiving callbacks. } private: friend sp<ClientCallbackCallback>; ClientCallbackCallback(const sp<ServiceManager>& manager) : mManager(manager) {} sp<ServiceManager> mManager; + sp<BinderCallback> mBinderCallback; }; int main(int argc, char** argv) { @@ -139,8 +152,8 @@ int main(int argc, char** argv) { sp<Looper> looper = Looper::prepare(false /*allowNonCallbacks*/); - BinderCallback::setupTo(looper); - ClientCallbackCallback::setupTo(looper, manager); + sp<BinderCallback> binderCallback = BinderCallback::setupTo(looper); + ClientCallbackCallback::setupTo(looper, manager, binderCallback); #ifndef VENDORSERVICEMANAGER if (!SetProperty("servicemanager.ready", "true")) { diff --git a/include/android/asset_manager.h b/include/android/asset_manager.h index 2ac7d4d350..6420cd0064 100644 --- a/include/android/asset_manager.h +++ b/include/android/asset_manager.h @@ -29,6 +29,10 @@ #include <sys/cdefs.h> #include <sys/types.h> +#if defined(__APPLE__) +typedef off_t off64_t; // Mac OSX does not define off64_t +#endif + #ifdef __cplusplus extern "C" { #endif diff --git a/include/android/performance_hint.h b/include/android/performance_hint.h index 30200c7e79..08d339b176 100644 --- a/include/android/performance_hint.h +++ b/include/android/performance_hint.h @@ -240,7 +240,7 @@ int APerformanceHint_setPreferPowerEfficiency( * the actual GPU duration is not measured. * * @return 0 on success. - * EINVAL if session is nullptr or any duration is an invalid number. + * EINVAL if any duration is an invalid number. * EPIPE if communication with the system service has failed. */ int APerformanceHint_reportActualWorkDuration2( @@ -269,7 +269,7 @@ void AWorkDuration_release(AWorkDuration* _Nonnull aWorkDuration) * * @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. + * CLOCK_MONOTONIC about when the work starts. This timestamp must be greater than zero. */ void AWorkDuration_setWorkPeriodStartTimestampNanos(AWorkDuration* _Nonnull aWorkDuration, int64_t workPeriodStartTimestampNanos) __INTRODUCED_IN(__ANDROID_API_V__); @@ -278,8 +278,8 @@ void AWorkDuration_setWorkPeriodStartTimestampNanos(AWorkDuration* _Nonnull aWor * 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. + * @param actualTotalDurationNanos The actual total work duration in nanoseconds. This number must + * be greater than zero. */ void AWorkDuration_setActualTotalDurationNanos(AWorkDuration* _Nonnull aWorkDuration, int64_t actualTotalDurationNanos) __INTRODUCED_IN(__ANDROID_API_V__); @@ -288,8 +288,8 @@ void AWorkDuration_setActualTotalDurationNanos(AWorkDuration* _Nonnull aWorkDura * 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. + * @param actualCpuDurationNanos The actual CPU work duration in nanoseconds. This number must be + * greater than zero. */ void AWorkDuration_setActualCpuDurationNanos(AWorkDuration* _Nonnull aWorkDuration, int64_t actualCpuDurationNanos) __INTRODUCED_IN(__ANDROID_API_V__); diff --git a/include/powermanager/PowerHalController.h b/include/powermanager/PowerHalController.h index 9e426d3ea3..c50bc4a188 100644 --- a/include/powermanager/PowerHalController.h +++ b/include/powermanager/PowerHalController.h @@ -62,7 +62,15 @@ public: 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<std::shared_ptr<aidl::android::hardware::power::IPowerHintSession>> + createHintSessionWithConfig(int32_t tgid, int32_t uid, const std::vector<int32_t>& threadIds, + int64_t durationNanos, + aidl::android::hardware::power::SessionTag tag, + aidl::android::hardware::power::SessionConfig* config) override; virtual HalResult<int64_t> getHintSessionPreferredRate() override; + virtual HalResult<aidl::android::hardware::power::ChannelConfig> getSessionChannel( + int tgid, int uid) override; + virtual HalResult<void> closeSessionChannel(int tgid, int uid) override; private: std::mutex mConnectedHalMutex; @@ -75,7 +83,7 @@ private: std::shared_ptr<HalWrapper> initHal(); template <typename T> - HalResult<T> processHalResult(HalResult<T> result, const char* functionName); + HalResult<T> processHalResult(HalResult<T>&& result, const char* functionName); }; // ------------------------------------------------------------------------------------------------- diff --git a/include/powermanager/PowerHalWrapper.h b/include/powermanager/PowerHalWrapper.h index 4e4a1b000d..e2da014606 100644 --- a/include/powermanager/PowerHalWrapper.h +++ b/include/powermanager/PowerHalWrapper.h @@ -14,19 +14,22 @@ * limitations under the License. */ -#ifndef ANDROID_POWERHALWRAPPER_H -#define ANDROID_POWERHALWRAPPER_H +#pragma once #include <aidl/android/hardware/power/Boost.h> +#include <aidl/android/hardware/power/ChannelConfig.h> #include <aidl/android/hardware/power/IPower.h> #include <aidl/android/hardware/power/IPowerHintSession.h> #include <aidl/android/hardware/power/Mode.h> +#include <aidl/android/hardware/power/SessionConfig.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 <binder/Status.h> +#include <utility> + namespace android { namespace power { @@ -42,44 +45,63 @@ enum class HalSupport { template <typename T> class HalResult { public: - static HalResult<T> ok(T value) { return HalResult(value); } - static HalResult<T> failed(std::string msg) { - return HalResult(std::move(msg), /* unsupported= */ false); - } + static HalResult<T> ok(T&& value) { return HalResult(std::forward<T>(value)); } + static HalResult<T> ok(T& value) { return HalResult<T>::ok(T{value}); } + static HalResult<T> failed(std::string msg) { return HalResult(msg, /* unsupported= */ false); } static HalResult<T> unsupported() { return HalResult("", /* unsupported= */ true); } - static HalResult<T> fromStatus(const 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(); } if (status.isOk()) { - return HalResult<T>::ok(data); + return HalResult<T>::ok(std::forward<T>(data)); } return HalResult<T>::failed(std::string(status.toString8().c_str())); } - static HalResult<T> fromStatus(const ndk::ScopedAStatus& status, T data) { + static HalResult<T> fromStatus(const binder::Status& status, T& data) { + return HalResult<T>::fromStatus(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>::ok(std::forward<T>(data)); } return HalResult<T>::failed(std::string(status.getDescription())); } + static HalResult<T> fromStatus(const ndk::ScopedAStatus& status, T& data) { + return HalResult<T>::fromStatus(status, T{data}); + } + template <typename R> - static HalResult<T> fromReturn(hardware::Return<R>& ret, T data) { - return ret.isOk() ? HalResult<T>::ok(data) : HalResult<T>::failed(ret.description()); + static HalResult<T> fromReturn(hardware::Return<R>& ret, T&& data) { + return ret.isOk() ? HalResult<T>::ok(std::forward<T>(data)) + : HalResult<T>::failed(ret.description()); + } + + template <typename R> + static HalResult<T> fromReturn(hardware::Return<R>& ret, T& data) { + return HalResult<T>::fromReturn(ret, T{data}); } template <typename R> static HalResult<T> fromReturn(hardware::Return<R>& ret, hardware::power::V1_0::Status status, - T data) { - return ret.isOk() ? HalResult<T>::fromStatus(status, data) + T&& data) { + return ret.isOk() ? HalResult<T>::fromStatus(status, std::forward<T>(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) { + return HalResult<T>::fromReturn(ret, status, T{data}); + } + // This will throw std::bad_optional_access if this result is not ok. const T& value() const { return mValue.value(); } bool isOk() const { return !mUnsupported && mValue.has_value(); } @@ -92,8 +114,8 @@ private: std::string mErrorMessage; bool mUnsupported; - explicit HalResult(T value) - : mValue(std::make_optional(value)), mErrorMessage(), mUnsupported(false) {} + explicit HalResult(T&& value) + : mValue{std::move(value)}, mErrorMessage(), mUnsupported(false) {} explicit HalResult(std::string errorMessage, bool unsupported) : mValue(), mErrorMessage(std::move(errorMessage)), mUnsupported(unsupported) {} }; @@ -158,7 +180,15 @@ public: 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<std::shared_ptr<aidl::android::hardware::power::IPowerHintSession>> + createHintSessionWithConfig(int32_t tgid, int32_t uid, const std::vector<int32_t>& threadIds, + int64_t durationNanos, + aidl::android::hardware::power::SessionTag tag, + aidl::android::hardware::power::SessionConfig* config) = 0; virtual HalResult<int64_t> getHintSessionPreferredRate() = 0; + virtual HalResult<aidl::android::hardware::power::ChannelConfig> getSessionChannel(int tgid, + int uid) = 0; + virtual HalResult<void> closeSessionChannel(int tgid, int uid) = 0; }; // Empty Power HAL wrapper that ignores all api calls. @@ -173,11 +203,22 @@ public: 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; + HalResult<std::shared_ptr<aidl::android::hardware::power::IPowerHintSession>> + createHintSessionWithConfig(int32_t tgid, int32_t uid, const std::vector<int32_t>& threadIds, + int64_t durationNanos, + aidl::android::hardware::power::SessionTag tag, + aidl::android::hardware::power::SessionConfig* config) override; HalResult<int64_t> getHintSessionPreferredRate() override; + HalResult<aidl::android::hardware::power::ChannelConfig> getSessionChannel(int tgid, + int uid) override; + HalResult<void> closeSessionChannel(int tgid, int uid) override; + +protected: + virtual const char* getUnsupportedMessage(); }; // Wrapper for the HIDL Power HAL v1.0. -class HidlHalWrapperV1_0 : public HalWrapper { +class HidlHalWrapperV1_0 : public EmptyHalWrapper { public: explicit HidlHalWrapperV1_0(sp<hardware::power::V1_0::IPower> handleV1_0) : mHandleV1_0(std::move(handleV1_0)) {} @@ -186,14 +227,11 @@ public: 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; - HalResult<int64_t> getHintSessionPreferredRate() override; protected: const sp<hardware::power::V1_0::IPower> mHandleV1_0; virtual HalResult<void> sendPowerHint(hardware::power::V1_3::PowerHint hintId, uint32_t data); + const char* getUnsupportedMessage(); private: HalResult<void> setInteractive(bool enabled); @@ -238,7 +276,7 @@ protected: }; // Wrapper for the AIDL Power HAL. -class AidlHalWrapper : public HalWrapper { +class AidlHalWrapper : public EmptyHalWrapper { public: explicit AidlHalWrapper(std::shared_ptr<aidl::android::hardware::power::IPower> handle) : mHandle(std::move(handle)) {} @@ -250,7 +288,19 @@ public: 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; + HalResult<std::shared_ptr<aidl::android::hardware::power::IPowerHintSession>> + createHintSessionWithConfig(int32_t tgid, int32_t uid, const std::vector<int32_t>& threadIds, + int64_t durationNanos, + aidl::android::hardware::power::SessionTag tag, + aidl::android::hardware::power::SessionConfig* config) override; + HalResult<int64_t> getHintSessionPreferredRate() override; + HalResult<aidl::android::hardware::power::ChannelConfig> getSessionChannel(int tgid, + int uid) override; + HalResult<void> closeSessionChannel(int tgid, int uid) override; + +protected: + const char* getUnsupportedMessage() override; private: // Control access to the boost and mode supported arrays. @@ -274,5 +324,3 @@ private: }; // namespace power }; // namespace android - -#endif // ANDROID_POWERHALWRAPPER_H diff --git a/libs/input/input_flags.aconfig b/libs/input/input_flags.aconfig index 576d9d569d..0c850fe0ee 100644 --- a/libs/input/input_flags.aconfig +++ b/libs/input/input_flags.aconfig @@ -97,3 +97,10 @@ flag { description: "Change the acceleration curves for mouse pointer movements to match the touchpad ones" bug: "315313622" } + +flag { + name: "rate_limit_user_activity_poke_in_dispatcher" + namespace: "input" + description: "Move user-activity poke rate-limiting from PowerManagerService to InputDispatcher." + bug: "320499729" +} diff --git a/libs/nativewindow/rust/src/lib.rs b/libs/nativewindow/rust/src/lib.rs index aab7df0c2c..22ad83463c 100644 --- a/libs/nativewindow/rust/src/lib.rs +++ b/libs/nativewindow/rust/src/lib.rs @@ -16,6 +16,8 @@ extern crate nativewindow_bindgen as ffi; +pub mod surface; + pub use ffi::{AHardwareBuffer_Format, AHardwareBuffer_UsageFlags}; use binder::{ @@ -210,7 +212,7 @@ impl Drop for HardwareBuffer { } impl Debug for HardwareBuffer { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { f.debug_struct("HardwareBuffer").field("id", &self.id()).finish() } } diff --git a/libs/nativewindow/rust/src/surface.rs b/libs/nativewindow/rust/src/surface.rs new file mode 100644 index 0000000000..c812612d40 --- /dev/null +++ b/libs/nativewindow/rust/src/surface.rs @@ -0,0 +1,140 @@ +// Copyright (C) 2024 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Rust wrapper for `ANativeWindow` and related types. + +use binder::{ + binder_impl::{BorrowedParcel, UnstructuredParcelable}, + impl_deserialize_for_unstructured_parcelable, impl_serialize_for_unstructured_parcelable, + unstable_api::{status_result, AsNative}, + StatusCode, +}; +use nativewindow_bindgen::{ + AHardwareBuffer_Format, ANativeWindow, ANativeWindow_acquire, ANativeWindow_getFormat, + ANativeWindow_getHeight, ANativeWindow_getWidth, ANativeWindow_readFromParcel, + ANativeWindow_release, ANativeWindow_writeToParcel, +}; +use std::error::Error; +use std::fmt::{self, Debug, Display, Formatter}; +use std::ptr::{null_mut, NonNull}; + +/// Wrapper around an opaque C `ANativeWindow`. +#[derive(PartialEq, Eq)] +pub struct Surface(NonNull<ANativeWindow>); + +impl Surface { + /// Returns the current width in pixels of the window surface. + pub fn width(&self) -> Result<u32, ErrorCode> { + // SAFETY: The ANativeWindow pointer we pass is guaranteed to be non-null and valid because + // it must have been allocated by `ANativeWindow_allocate` or `ANativeWindow_readFromParcel` + // and we have not yet released it. + let width = unsafe { ANativeWindow_getWidth(self.0.as_ptr()) }; + width.try_into().map_err(|_| ErrorCode(width)) + } + + /// Returns the current height in pixels of the window surface. + pub fn height(&self) -> Result<u32, ErrorCode> { + // SAFETY: The ANativeWindow pointer we pass is guaranteed to be non-null and valid because + // it must have been allocated by `ANativeWindow_allocate` or `ANativeWindow_readFromParcel` + // and we have not yet released it. + let height = unsafe { ANativeWindow_getHeight(self.0.as_ptr()) }; + height.try_into().map_err(|_| ErrorCode(height)) + } + + /// Returns the current pixel format of the window surface. + pub fn format(&self) -> Result<AHardwareBuffer_Format::Type, ErrorCode> { + // SAFETY: The ANativeWindow pointer we pass is guaranteed to be non-null and valid because + // it must have been allocated by `ANativeWindow_allocate` or `ANativeWindow_readFromParcel` + // and we have not yet released it. + let format = unsafe { ANativeWindow_getFormat(self.0.as_ptr()) }; + format.try_into().map_err(|_| ErrorCode(format)) + } +} + +impl Drop for Surface { + fn drop(&mut self) { + // SAFETY: The ANativeWindow pointer we pass is guaranteed to be non-null and valid because + // it must have been allocated by `ANativeWindow_allocate` or `ANativeWindow_readFromParcel` + // and we have not yet released it. + unsafe { ANativeWindow_release(self.0.as_ptr()) } + } +} + +impl Debug for Surface { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + f.debug_struct("Surface") + .field("width", &self.width()) + .field("height", &self.height()) + .field("format", &self.format()) + .finish() + } +} + +impl Clone for Surface { + fn clone(&self) -> Self { + // SAFETY: The ANativeWindow pointer we pass is guaranteed to be non-null and valid because + // it must have been allocated by `ANativeWindow_allocate` or `ANativeWindow_readFromParcel` + // and we have not yet released it. + unsafe { ANativeWindow_acquire(self.0.as_ptr()) }; + Self(self.0) + } +} + +impl UnstructuredParcelable for Surface { + fn write_to_parcel(&self, parcel: &mut BorrowedParcel) -> Result<(), StatusCode> { + let status = + // SAFETY: The ANativeWindow pointer we pass is guaranteed to be non-null and valid because + // it must have been allocated by `ANativeWindow_allocate` or `ANativeWindow_readFromParcel` + // and we have not yet released it. + unsafe { ANativeWindow_writeToParcel(self.0.as_ptr(), parcel.as_native_mut()) }; + status_result(status) + } + + fn from_parcel(parcel: &BorrowedParcel) -> Result<Self, StatusCode> { + let mut buffer = null_mut(); + + let status = + // SAFETY: Both pointers must be valid because they are obtained from references. + // `ANativeWindow_readFromParcel` doesn't store them or do anything else special + // with them. If it returns success then it will have allocated a new + // `ANativeWindow` and incremented the reference count, so we can use it until we + // release it. + unsafe { ANativeWindow_readFromParcel(parcel.as_native(), &mut buffer) }; + + status_result(status)?; + + Ok(Self( + NonNull::new(buffer) + .expect("ANativeWindow_readFromParcel returned success but didn't allocate buffer"), + )) + } +} + +impl_deserialize_for_unstructured_parcelable!(Surface); +impl_serialize_for_unstructured_parcelable!(Surface); + +// SAFETY: The underlying *ANativeWindow can be moved between threads. +unsafe impl Send for Surface {} + +/// An error code returned by methods on [`Surface`]. +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub struct ErrorCode(i32); + +impl Error for ErrorCode {} + +impl Display for ErrorCode { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + write!(f, "Error {}", self.0) + } +} diff --git a/libs/nativewindow/rust/sys/nativewindow_bindings.h b/libs/nativewindow/rust/sys/nativewindow_bindings.h index 4525a42502..5689f7df94 100644 --- a/libs/nativewindow/rust/sys/nativewindow_bindings.h +++ b/libs/nativewindow/rust/sys/nativewindow_bindings.h @@ -19,3 +19,4 @@ #include <android/hardware_buffer_aidl.h> #include <android/hdr_metadata.h> #include <android/native_window.h> +#include <android/native_window_aidl.h> diff --git a/services/inputflinger/PointerChoreographer.cpp b/services/inputflinger/PointerChoreographer.cpp index 4571ef4481..3ac4285304 100644 --- a/services/inputflinger/PointerChoreographer.cpp +++ b/services/inputflinger/PointerChoreographer.cpp @@ -109,7 +109,9 @@ NotifyMotionArgs PointerChoreographer::processMouseEventLocked(const NotifyMotio const float deltaX = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X); const float deltaY = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y); pc.move(deltaX, deltaY); - pc.unfade(PointerControllerInterface::Transition::IMMEDIATE); + if (canUnfadeOnDisplay(displayId)) { + pc.unfade(PointerControllerInterface::Transition::IMMEDIATE); + } const auto [x, y] = pc.getPosition(); NotifyMotionArgs newArgs(args); @@ -131,7 +133,9 @@ NotifyMotionArgs PointerChoreographer::processTouchpadEventLocked(const NotifyMo const float deltaX = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X); const float deltaY = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y); pc.move(deltaX, deltaY); - pc.unfade(PointerControllerInterface::Transition::IMMEDIATE); + if (canUnfadeOnDisplay(displayId)) { + pc.unfade(PointerControllerInterface::Transition::IMMEDIATE); + } const auto [x, y] = pc.getPosition(); newArgs.pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, x); @@ -140,7 +144,9 @@ NotifyMotionArgs PointerChoreographer::processTouchpadEventLocked(const NotifyMo newArgs.yCursorPosition = y; } else { // This is a trackpad gesture with fake finger(s) that should not move the mouse pointer. - pc.unfade(PointerControllerInterface::Transition::IMMEDIATE); + if (canUnfadeOnDisplay(displayId)) { + pc.unfade(PointerControllerInterface::Transition::IMMEDIATE); + } const auto [x, y] = pc.getPosition(); for (uint32_t i = 0; i < newArgs.getPointerCount(); i++) { @@ -223,7 +229,7 @@ void PointerChoreographer::processStylusHoverEventLocked(const NotifyMotionArgs& if (args.action == AMOTION_EVENT_ACTION_HOVER_EXIT) { pc.fade(PointerControllerInterface::Transition::IMMEDIATE); pc.updatePointerIcon(PointerIconStyle::TYPE_NOT_SPECIFIED); - } else { + } else if (canUnfadeOnDisplay(args.displayId)) { pc.unfade(PointerControllerInterface::Transition::IMMEDIATE); } } @@ -323,6 +329,10 @@ InputDeviceInfo* PointerChoreographer::findInputDeviceLocked(DeviceId deviceId) return it != mInputDeviceInfos.end() ? &(*it) : nullptr; } +bool PointerChoreographer::canUnfadeOnDisplay(int32_t displayId) { + return mDisplaysWithPointersHidden.find(displayId) == mDisplaysWithPointersHidden.end(); +} + void PointerChoreographer::updatePointerControllersLocked() { std::set<int32_t /*displayId*/> mouseDisplaysToKeep; std::set<DeviceId> touchDevicesToKeep; @@ -342,7 +352,7 @@ void PointerChoreographer::updatePointerControllersLocked() { mMousePointersByDisplay.try_emplace(displayId, getMouseControllerConstructor(displayId)); auto [_, isNewMouseDevice] = mMouseDevices.emplace(info.getId()); - if (isNewMouseDevice || isNewMousePointer) { + if ((isNewMouseDevice || isNewMousePointer) && canUnfadeOnDisplay(displayId)) { mousePointerIt->second->unfade(PointerControllerInterface::Transition::IMMEDIATE); } } @@ -513,6 +523,28 @@ bool PointerChoreographer::setPointerIcon( return true; } +void PointerChoreographer::setPointerIconVisibility(int32_t displayId, bool visible) { + std::scoped_lock lock(mLock); + if (visible) { + mDisplaysWithPointersHidden.erase(displayId); + // We do not unfade the icons here, because we don't know when the last event happened. + return; + } + + mDisplaysWithPointersHidden.emplace(displayId); + + // Hide any icons that are currently visible on the display. + if (auto it = mMousePointersByDisplay.find(displayId); it != mMousePointersByDisplay.end()) { + const auto& [_, controller] = *it; + controller->fade(PointerControllerInterface::Transition::IMMEDIATE); + } + for (const auto& [_, controller] : mStylusPointersByDevice) { + if (controller->getDisplayId() == displayId) { + controller->fade(PointerControllerInterface::Transition::IMMEDIATE); + } + } +} + PointerChoreographer::ControllerConstructor PointerChoreographer::getMouseControllerConstructor( int32_t displayId) { std::function<std::shared_ptr<PointerControllerInterface>()> ctor = diff --git a/services/inputflinger/PointerChoreographer.h b/services/inputflinger/PointerChoreographer.h index f46419ec2e..6aab3aade0 100644 --- a/services/inputflinger/PointerChoreographer.h +++ b/services/inputflinger/PointerChoreographer.h @@ -67,6 +67,11 @@ public: */ virtual bool setPointerIcon(std::variant<std::unique_ptr<SpriteIcon>, PointerIconStyle> icon, int32_t displayId, DeviceId deviceId) = 0; + /** + * Set whether pointer icons for mice, touchpads, and styluses should be visible on the + * given display. + */ + virtual void setPointerIconVisibility(int32_t displayId, bool visible) = 0; /** * This method may be called on any thread (usually by the input manager on a binder thread). @@ -89,6 +94,7 @@ public: void setStylusPointerIconEnabled(bool enabled) override; bool setPointerIcon(std::variant<std::unique_ptr<SpriteIcon>, PointerIconStyle> icon, int32_t displayId, DeviceId deviceId) override; + void setPointerIconVisibility(int32_t displayId, bool visible) override; void notifyInputDevicesChanged(const NotifyInputDevicesChangedArgs& args) override; void notifyConfigurationChanged(const NotifyConfigurationChangedArgs& args) override; @@ -110,6 +116,7 @@ private: std::pair<int32_t, PointerControllerInterface&> getDisplayIdAndMouseControllerLocked( int32_t associatedDisplayId) REQUIRES(mLock); InputDeviceInfo* findInputDeviceLocked(DeviceId deviceId) REQUIRES(mLock); + bool canUnfadeOnDisplay(int32_t displayId) REQUIRES(mLock); NotifyMotionArgs processMotion(const NotifyMotionArgs& args); NotifyMotionArgs processMouseEventLocked(const NotifyMotionArgs& args) REQUIRES(mLock); @@ -143,6 +150,7 @@ private: std::vector<DisplayViewport> mViewports GUARDED_BY(mLock); bool mShowTouchesEnabled GUARDED_BY(mLock); bool mStylusPointerIconEnabled GUARDED_BY(mLock); + std::set<int32_t /*displayId*/> mDisplaysWithPointersHidden; }; } // namespace android diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 1085c942dd..c349a5857f 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -35,7 +35,6 @@ #include <input/PrintTools.h> #include <input/TraceTools.h> #include <openssl/mem.h> -#include <powermanager/PowerManager.h> #include <unistd.h> #include <utils/Trace.h> @@ -100,6 +99,9 @@ const std::chrono::duration DEFAULT_INPUT_DISPATCHING_TIMEOUT = std::chrono::mil android::os::IInputConstants::UNMULTIPLIED_DEFAULT_DISPATCHING_TIMEOUT_MILLIS * HwTimeoutMultiplier()); +// The default minimum time gap between two user activity poke events. +const std::chrono::milliseconds DEFAULT_USER_ACTIVITY_POKE_INTERVAL = 100ms; + const std::chrono::duration STALE_EVENT_TIMEOUT = std::chrono::seconds(10) * HwTimeoutMultiplier(); // Log a warning when an event takes longer than this to process, even if an ANR does not occur. @@ -778,6 +780,25 @@ Result<void> validateWindowInfosUpdate(const gui::WindowInfosUpdate& update) { return {}; } +int32_t getUserActivityEventType(const EventEntry& eventEntry) { + switch (eventEntry.type) { + case EventEntry::Type::KEY: { + return USER_ACTIVITY_EVENT_BUTTON; + } + case EventEntry::Type::MOTION: { + const MotionEntry& motionEntry = static_cast<const MotionEntry&>(eventEntry); + if (MotionEvent::isTouchEvent(motionEntry.source, motionEntry.action)) { + return USER_ACTIVITY_EVENT_TOUCH; + } + return USER_ACTIVITY_EVENT_OTHER; + } + default: { + LOG_ALWAYS_FATAL("%s events are not user activity", + ftl::enum_string(eventEntry.type).c_str()); + } + } +} + } // namespace // --- InputDispatcher --- @@ -791,6 +812,7 @@ InputDispatcher::InputDispatcher(InputDispatcherPolicyInterface& policy, mPendingEvent(nullptr), mLastDropReason(DropReason::NOT_DROPPED), mIdGenerator(IdGenerator::Source::INPUT_DISPATCHER), + mMinTimeBetweenUserActivityPokes(DEFAULT_USER_ACTIVITY_POKE_INTERVAL), mNextUnblockedEvent(nullptr), mMonitorDispatchingTimeout(DEFAULT_INPUT_DISPATCHING_TIMEOUT), mDispatchEnabled(false), @@ -813,6 +835,8 @@ InputDispatcher::InputDispatcher(InputDispatcherPolicyInterface& policy, if (traceBackend) { // TODO: Create input tracer instance. } + + mLastUserActivityTimes.fill(0); } InputDispatcher::~InputDispatcher() { @@ -3140,6 +3164,21 @@ void InputDispatcher::pokeUserActivityLocked(const EventEntry& eventEntry) { // Not poking user activity if the event type does not represent a user activity return; } + + const int32_t eventType = getUserActivityEventType(eventEntry); + if (input_flags::rate_limit_user_activity_poke_in_dispatcher()) { + // Note that we're directly getting the time diff between the current event and the previous + // event. This is assuming that the first user event always happens at a timestamp that is + // greater than `mMinTimeBetweenUserActivityPokes` (otherwise, the first user event will + // wrongly be dropped). In real life, `mMinTimeBetweenUserActivityPokes` is a much smaller + // value than the potential first user activity event time, so this is ok. + std::chrono::nanoseconds timeSinceLastEvent = + std::chrono::nanoseconds(eventEntry.eventTime - mLastUserActivityTimes[eventType]); + if (timeSinceLastEvent < mMinTimeBetweenUserActivityPokes) { + return; + } + } + int32_t displayId = getTargetDisplayId(eventEntry); sp<WindowInfoHandle> focusedWindowHandle = getFocusedWindowHandleLocked(displayId); const WindowInfo* windowDisablingUserActivityInfo = nullptr; @@ -3150,7 +3189,6 @@ void InputDispatcher::pokeUserActivityLocked(const EventEntry& eventEntry) { } } - int32_t eventType = USER_ACTIVITY_EVENT_OTHER; switch (eventEntry.type) { case EventEntry::Type::MOTION: { const MotionEntry& motionEntry = static_cast<const MotionEntry&>(eventEntry); @@ -3164,9 +3202,6 @@ void InputDispatcher::pokeUserActivityLocked(const EventEntry& eventEntry) { } return; } - if (MotionEvent::isTouchEvent(motionEntry.source, motionEntry.action)) { - eventType = USER_ACTIVITY_EVENT_TOUCH; - } break; } case EventEntry::Type::KEY: { @@ -3190,7 +3225,6 @@ void InputDispatcher::pokeUserActivityLocked(const EventEntry& eventEntry) { return; } - eventType = USER_ACTIVITY_EVENT_BUTTON; break; } default: { @@ -3200,6 +3234,7 @@ void InputDispatcher::pokeUserActivityLocked(const EventEntry& eventEntry) { } } + mLastUserActivityTimes[eventType] = eventEntry.eventTime; auto command = [this, eventTime = eventEntry.eventTime, eventType, displayId]() REQUIRES(mLock) { scoped_unlock unlock(mLock); @@ -5292,6 +5327,14 @@ void InputDispatcher::setFocusedApplicationLocked( resetNoFocusedWindowTimeoutLocked(); } +void InputDispatcher::setMinTimeBetweenUserActivityPokes(std::chrono::milliseconds interval) { + if (interval.count() < 0) { + LOG_ALWAYS_FATAL("Minimum time between user activity pokes should be >= 0"); + } + std::scoped_lock _l(mLock); + mMinTimeBetweenUserActivityPokes = interval; +} + /** * Sets the focused display, which is responsible for receiving focus-dispatched input events where * the display not specified. diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h index 1e11b27d2f..e635852662 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.h +++ b/services/inputflinger/dispatcher/InputDispatcher.h @@ -41,6 +41,7 @@ #include <input/Input.h> #include <input/InputTransport.h> #include <limits.h> +#include <powermanager/PowerManager.h> #include <stddef.h> #include <unistd.h> #include <utils/BitSet.h> @@ -116,6 +117,7 @@ public: int32_t displayId, const std::shared_ptr<InputApplicationHandle>& inputApplicationHandle) override; void setFocusedDisplay(int32_t displayId) override; + void setMinTimeBetweenUserActivityPokes(std::chrono::milliseconds interval) override; void setInputDispatchMode(bool enabled, bool frozen) override; void setInputFilterEnabled(bool enabled) override; bool setInTouchMode(bool inTouchMode, gui::Pid pid, gui::Uid uid, bool hasPermission, @@ -211,6 +213,11 @@ private: int64_t mWindowInfosVsyncId GUARDED_BY(mLock); + std::chrono::milliseconds mMinTimeBetweenUserActivityPokes GUARDED_BY(mLock); + + /** Stores the latest user-activity poke event times per user activity types. */ + std::array<nsecs_t, USER_ACTIVITY_EVENT_LAST + 1> mLastUserActivityTimes GUARDED_BY(mLock); + // With each iteration, InputDispatcher nominally processes one queued event, // a timeout, or a response from an input consumer. // This method should only be called on the input dispatcher's own thread. diff --git a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h index 001dc6cf7b..c8f3d05ade 100644 --- a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h +++ b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h @@ -101,6 +101,9 @@ public: */ virtual void setFocusedDisplay(int32_t displayId) = 0; + /** Sets the minimum time between user activity pokes. */ + virtual void setMinTimeBetweenUserActivityPokes(std::chrono::milliseconds interval) = 0; + /* Sets the input dispatching mode. * * This method may be called on any thread (usually by the input manager). diff --git a/services/inputflinger/include/InputReaderBase.h b/services/inputflinger/include/InputReaderBase.h index 40359a42c9..9abfef14dc 100644 --- a/services/inputflinger/include/InputReaderBase.h +++ b/services/inputflinger/include/InputReaderBase.h @@ -131,10 +131,10 @@ struct InputReaderConfiguration { // Currently only used when the enable_new_mouse_pointer_ballistics flag is enabled. int32_t mousePointerSpeed; - // Whether to apply an acceleration curve to pointer movements from mice. + // Displays on which an acceleration curve shouldn't be applied for pointer movements from mice. // // Currently only used when the enable_new_mouse_pointer_ballistics flag is enabled. - bool mousePointerAccelerationEnabled; + std::set<int32_t> displaysWithMousePointerAccelerationDisabled; // Velocity control parameters for mouse pointer movements. // @@ -243,7 +243,7 @@ struct InputReaderConfiguration { InputReaderConfiguration() : virtualKeyQuietTime(0), mousePointerSpeed(0), - mousePointerAccelerationEnabled(true), + displaysWithMousePointerAccelerationDisabled(), pointerVelocityControlParameters(1.0f, 500.0f, 3000.0f, static_cast<float>( android::os::IInputConstants:: diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.cpp b/services/inputflinger/reader/mapper/CursorInputMapper.cpp index 4cebd646db..d207ed1655 100644 --- a/services/inputflinger/reader/mapper/CursorInputMapper.cpp +++ b/services/inputflinger/reader/mapper/CursorInputMapper.cpp @@ -159,14 +159,14 @@ std::list<NotifyArgs> CursorInputMapper::reconfigure(nsecs_t when, out.push_back(NotifyDeviceResetArgs(getContext()->getNextId(), when, getDeviceId())); } - if (!changes.any() || changes.test(InputReaderConfiguration::Change::POINTER_SPEED) || + if (!changes.any() || changes.test(InputReaderConfiguration::Change::DISPLAY_INFO) || configurePointerCapture) { - configureOnChangePointerSpeed(readerConfig); + configureOnChangeDisplayInfo(readerConfig); } - if (!changes.any() || changes.test(InputReaderConfiguration::Change::DISPLAY_INFO) || + if (!changes.any() || changes.test(InputReaderConfiguration::Change::POINTER_SPEED) || configurePointerCapture) { - configureOnChangeDisplayInfo(readerConfig); + configureOnChangePointerSpeed(readerConfig); } return out; } @@ -510,7 +510,8 @@ void CursorInputMapper::configureOnChangePointerSpeed(const InputReaderConfigura } else { if (mEnableNewMousePointerBallistics) { mNewPointerVelocityControl.setAccelerationEnabled( - config.mousePointerAccelerationEnabled); + config.displaysWithMousePointerAccelerationDisabled.count( + mDisplayId.value_or(ADISPLAY_ID_NONE)) == 0); mNewPointerVelocityControl.setCurve( createAccelerationCurveForPointerSensitivity(config.mousePointerSpeed)); } else { diff --git a/services/inputflinger/reader/mapper/SlopController.cpp b/services/inputflinger/reader/mapper/SlopController.cpp index f79219f151..9ec02a6f86 100644 --- a/services/inputflinger/reader/mapper/SlopController.cpp +++ b/services/inputflinger/reader/mapper/SlopController.cpp @@ -54,11 +54,13 @@ float SlopController::consumeEvent(nsecs_t eventTimeNanos, float value) { mCumulativeValue += value; if (abs(mCumulativeValue) >= mSlopThreshold) { + ALOGD("SlopController: did not drop event with value .%3f", value); mHasSlopBeenMet = true; // Return the amount of value that exceeds the slop. return signOf(value) * (abs(mCumulativeValue) - mSlopThreshold); } + ALOGD("SlopController: dropping event with value .%3f", value); return 0; } diff --git a/services/inputflinger/tests/CursorInputMapper_test.cpp b/services/inputflinger/tests/CursorInputMapper_test.cpp index e104543523..7b793d8e86 100644 --- a/services/inputflinger/tests/CursorInputMapper_test.cpp +++ b/services/inputflinger/tests/CursorInputMapper_test.cpp @@ -1324,6 +1324,42 @@ TEST_F(CursorInputMapperUnitTestWithNewBallistics, PointerCaptureDisablesVelocit ASSERT_EQ(20, relY2); } +TEST_F(CursorInputMapperUnitTestWithNewBallistics, ConfigureAccelerationWithAssociatedViewport) { + mPropertyMap.addProperty("cursor.mode", "pointer"); + DisplayViewport primaryViewport = createPrimaryViewport(ui::Rotation::Rotation0); + mReaderConfiguration.setDisplayViewports({primaryViewport}); + createDevice(); + ViewportFakingInputDeviceContext deviceContext(*mDevice, EVENTHUB_ID, primaryViewport); + mMapper = createInputMapper<CursorInputMapper>(deviceContext, mReaderConfiguration); + + std::list<NotifyArgs> args; + + // Verify that acceleration is being applied by default by checking that the movement is scaled. + args += process(ARBITRARY_TIME, EV_REL, REL_X, 10); + args += process(ARBITRARY_TIME, EV_REL, REL_Y, 20); + args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0); + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(HOVER_MOVE), WithDisplayId(DISPLAY_ID))))); + const auto& coords = get<NotifyMotionArgs>(args.back()).pointerCoords[0]; + ASSERT_GT(coords.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X), 10.f); + ASSERT_GT(coords.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y), 20.f); + + // Disable acceleration for the display, and verify that acceleration is no longer applied. + mReaderConfiguration.displaysWithMousePointerAccelerationDisabled.emplace(DISPLAY_ID); + args += mMapper->reconfigure(ARBITRARY_TIME, mReaderConfiguration, + InputReaderConfiguration::Change::POINTER_SPEED); + args.clear(); + + args += process(ARBITRARY_TIME, EV_REL, REL_X, 10); + args += process(ARBITRARY_TIME, EV_REL, REL_Y, 20); + args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0); + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(HOVER_MOVE), WithDisplayId(DISPLAY_ID), + WithRelativeMotion(10, 20))))); +} + namespace { // Minimum timestamp separation between subsequent input events from a Bluetooth device. diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index b6ae0b3d69..f1f4a61e73 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -156,6 +156,20 @@ class FakeInputDispatcherPolicy : public InputDispatcherPolicyInterface { sp<IBinder> token{}; gui::Pid pid{gui::Pid::INVALID}; }; + /* Stores data about a user-activity-poke event from the dispatcher. */ + struct UserActivityPokeEvent { + nsecs_t eventTime; + int32_t eventType; + int32_t displayId; + + bool operator==(const UserActivityPokeEvent& rhs) const = default; + + friend std::ostream& operator<<(std::ostream& os, const UserActivityPokeEvent& ev) { + os << "UserActivityPokeEvent[time=" << ev.eventTime << ", eventType=" << ev.eventType + << ", displayId=" << ev.displayId << "]"; + return os; + } + }; public: FakeInputDispatcherPolicy() = default; @@ -351,14 +365,36 @@ public: void setStaleEventTimeout(std::chrono::nanoseconds timeout) { mStaleEventTimeout = timeout; } - void assertUserActivityPoked() { - std::scoped_lock lock(mLock); - ASSERT_TRUE(mPokedUserActivity) << "Expected user activity to have been poked"; + void assertUserActivityNotPoked() { + std::unique_lock lock(mLock); + base::ScopedLockAssertion assumeLocked(mLock); + + std::optional<UserActivityPokeEvent> pokeEvent = + getItemFromStorageLockedInterruptible(500ms, mUserActivityPokeEvents, lock, + mNotifyUserActivity); + + ASSERT_FALSE(pokeEvent) << "Expected user activity not to have been poked"; } - void assertUserActivityNotPoked() { - std::scoped_lock lock(mLock); - ASSERT_FALSE(mPokedUserActivity) << "Expected user activity not to have been poked"; + /** + * Asserts that a user activity poke has happened. The earliest recorded poke event will be + * cleared after this call. + * + * If an expected UserActivityPokeEvent is provided, asserts that the given event is the + * earliest recorded poke event. + */ + void assertUserActivityPoked(std::optional<UserActivityPokeEvent> expectedPokeEvent = {}) { + std::unique_lock lock(mLock); + base::ScopedLockAssertion assumeLocked(mLock); + + std::optional<UserActivityPokeEvent> pokeEvent = + getItemFromStorageLockedInterruptible(500ms, mUserActivityPokeEvents, lock, + mNotifyUserActivity); + ASSERT_TRUE(pokeEvent) << "Expected a user poke event"; + + if (expectedPokeEvent) { + ASSERT_EQ(expectedPokeEvent, *pokeEvent); + } } void assertNotifyDeviceInteractionWasCalled(int32_t deviceId, std::set<gui::Uid> uids) { @@ -414,7 +450,9 @@ private: sp<IBinder> mDropTargetWindowToken GUARDED_BY(mLock); bool mNotifyDropWindowWasCalled GUARDED_BY(mLock) = false; - bool mPokedUserActivity GUARDED_BY(mLock) = false; + + std::condition_variable mNotifyUserActivity; + std::queue<UserActivityPokeEvent> mUserActivityPokeEvents; std::chrono::milliseconds mInterceptKeyTimeout = 0ms; @@ -576,9 +614,10 @@ private: NotifySwitchArgs(InputEvent::nextId(), when, policyFlags, switchValues, switchMask); } - void pokeUserActivity(nsecs_t, int32_t, int32_t) override { + void pokeUserActivity(nsecs_t eventTime, int32_t eventType, int32_t displayId) override { std::scoped_lock lock(mLock); - mPokedUserActivity = true; + mNotifyUserActivity.notify_all(); + mUserActivityPokeEvents.push({eventTime, eventType, displayId}); } bool isStaleEvent(nsecs_t currentTime, nsecs_t eventTime) override { @@ -7690,6 +7729,130 @@ TEST_F(InputFilterInjectionPolicyTest, RegularInjectedEvents_ReceiveVirtualDevic /*resolvedDeviceId=*/VIRTUAL_KEYBOARD_ID, /*flags=*/0); } +class InputDispatcherUserActivityPokeTests : public InputDispatcherTest { +protected: + virtual void SetUp() override { + InputDispatcherTest::SetUp(); + + std::shared_ptr<FakeApplicationHandle> application = + std::make_shared<FakeApplicationHandle>(); + application->setDispatchingTimeout(100ms); + mWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "TestWindow", + ADISPLAY_ID_DEFAULT); + mWindow->setFrame(Rect(0, 0, 100, 100)); + mWindow->setDispatchingTimeout(100ms); + mWindow->setFocusable(true); + + // Set focused application. + mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); + + mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0}); + setFocusedWindow(mWindow); + mWindow->consumeFocusEvent(true); + } + + void notifyAndConsumeMotion(int32_t action, uint32_t source, int32_t displayId, + nsecs_t eventTime) { + mDispatcher->notifyMotion(MotionArgsBuilder(action, source) + .displayId(displayId) + .eventTime(eventTime) + .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50)) + .build()); + mWindow->consumeMotionEvent(WithMotionAction(action)); + } + +private: + sp<FakeWindowHandle> mWindow; +}; + +TEST_F_WITH_FLAGS( + InputDispatcherUserActivityPokeTests, MinPokeTimeObserved, + REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(com::android::input::flags, + rate_limit_user_activity_poke_in_dispatcher))) { + mDispatcher->setMinTimeBetweenUserActivityPokes(50ms); + + // First event of type TOUCH. Should poke. + notifyAndConsumeMotion(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + milliseconds_to_nanoseconds(50)); + mFakePolicy->assertUserActivityPoked( + {{milliseconds_to_nanoseconds(50), USER_ACTIVITY_EVENT_TOUCH, ADISPLAY_ID_DEFAULT}}); + + // 80ns > 50ns has passed since previous TOUCH event. Should poke. + notifyAndConsumeMotion(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + milliseconds_to_nanoseconds(130)); + mFakePolicy->assertUserActivityPoked( + {{milliseconds_to_nanoseconds(130), USER_ACTIVITY_EVENT_TOUCH, ADISPLAY_ID_DEFAULT}}); + + // First event of type OTHER. Should poke (despite being within 50ns of previous TOUCH event). + notifyAndConsumeMotion(ACTION_SCROLL, AINPUT_SOURCE_ROTARY_ENCODER, ADISPLAY_ID_DEFAULT, + milliseconds_to_nanoseconds(135)); + mFakePolicy->assertUserActivityPoked( + {{milliseconds_to_nanoseconds(135), USER_ACTIVITY_EVENT_OTHER, ADISPLAY_ID_DEFAULT}}); + + // Within 50ns of previous TOUCH event. Should NOT poke. + notifyAndConsumeMotion(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + milliseconds_to_nanoseconds(140)); + mFakePolicy->assertUserActivityNotPoked(); + + // Within 50ns of previous OTHER event. Should NOT poke. + notifyAndConsumeMotion(ACTION_SCROLL, AINPUT_SOURCE_ROTARY_ENCODER, ADISPLAY_ID_DEFAULT, + milliseconds_to_nanoseconds(150)); + mFakePolicy->assertUserActivityNotPoked(); + + // Within 50ns of previous TOUCH event (which was at time 130). Should NOT poke. + // Note that STYLUS is mapped to TOUCH user activity, since it's a pointer-type source. + notifyAndConsumeMotion(ACTION_DOWN, AINPUT_SOURCE_STYLUS, ADISPLAY_ID_DEFAULT, + milliseconds_to_nanoseconds(160)); + mFakePolicy->assertUserActivityNotPoked(); + + // 65ns > 50ns has passed since previous OTHER event. Should poke. + notifyAndConsumeMotion(ACTION_SCROLL, AINPUT_SOURCE_ROTARY_ENCODER, ADISPLAY_ID_DEFAULT, + milliseconds_to_nanoseconds(200)); + mFakePolicy->assertUserActivityPoked( + {{milliseconds_to_nanoseconds(200), USER_ACTIVITY_EVENT_OTHER, ADISPLAY_ID_DEFAULT}}); + + // 170ns > 50ns has passed since previous TOUCH event. Should poke. + notifyAndConsumeMotion(ACTION_UP, AINPUT_SOURCE_STYLUS, ADISPLAY_ID_DEFAULT, + milliseconds_to_nanoseconds(300)); + mFakePolicy->assertUserActivityPoked( + {{milliseconds_to_nanoseconds(300), USER_ACTIVITY_EVENT_TOUCH, ADISPLAY_ID_DEFAULT}}); + + // Assert that there's no more user activity poke event. + mFakePolicy->assertUserActivityNotPoked(); +} + +TEST_F_WITH_FLAGS( + InputDispatcherUserActivityPokeTests, DefaultMinPokeTimeOf100MsUsed, + REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(com::android::input::flags, + rate_limit_user_activity_poke_in_dispatcher))) { + notifyAndConsumeMotion(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + milliseconds_to_nanoseconds(200)); + mFakePolicy->assertUserActivityPoked( + {{milliseconds_to_nanoseconds(200), USER_ACTIVITY_EVENT_TOUCH, ADISPLAY_ID_DEFAULT}}); + + notifyAndConsumeMotion(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + milliseconds_to_nanoseconds(280)); + mFakePolicy->assertUserActivityNotPoked(); + + notifyAndConsumeMotion(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + milliseconds_to_nanoseconds(340)); + mFakePolicy->assertUserActivityPoked( + {{milliseconds_to_nanoseconds(340), USER_ACTIVITY_EVENT_TOUCH, ADISPLAY_ID_DEFAULT}}); +} + +TEST_F_WITH_FLAGS( + InputDispatcherUserActivityPokeTests, ZeroMinPokeTimeDisablesRateLimiting, + REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(com::android::input::flags, + rate_limit_user_activity_poke_in_dispatcher))) { + mDispatcher->setMinTimeBetweenUserActivityPokes(0ms); + + notifyAndConsumeMotion(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, 20); + mFakePolicy->assertUserActivityPoked(); + + notifyAndConsumeMotion(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, 30); + mFakePolicy->assertUserActivityPoked(); +} + class InputDispatcherOnPointerDownOutsideFocus : public InputDispatcherTest { virtual void SetUp() override { InputDispatcherTest::SetUp(); diff --git a/services/inputflinger/tests/PointerChoreographer_test.cpp b/services/inputflinger/tests/PointerChoreographer_test.cpp index 1ac043c679..e9e50619ee 100644 --- a/services/inputflinger/tests/PointerChoreographer_test.cpp +++ b/services/inputflinger/tests/PointerChoreographer_test.cpp @@ -1557,4 +1557,122 @@ TEST_F(PointerChoreographerTest, SetsPointerIconForMouseAndStylus) { mousePc->assertPointerIconNotSet(); } +TEST_F(PointerChoreographerTest, SetPointerIconVisibilityHidesPointerOnDisplay) { + // Make sure there are two PointerControllers on different displays. + mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID, ANOTHER_DISPLAY_ID})); + mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID); + mChoreographer.notifyInputDevicesChanged( + {/*id=*/0, + {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, ADISPLAY_ID_NONE), + generateTestDeviceInfo(SECOND_DEVICE_ID, AINPUT_SOURCE_MOUSE, ANOTHER_DISPLAY_ID)}}); + auto firstMousePc = assertPointerControllerCreated(ControllerType::MOUSE); + ASSERT_EQ(DISPLAY_ID, firstMousePc->getDisplayId()); + auto secondMousePc = assertPointerControllerCreated(ControllerType::MOUSE); + ASSERT_EQ(ANOTHER_DISPLAY_ID, secondMousePc->getDisplayId()); + + // Both pointers should be visible. + ASSERT_TRUE(firstMousePc->isPointerShown()); + ASSERT_TRUE(secondMousePc->isPointerShown()); + + // Hide the icon on the second display. + mChoreographer.setPointerIconVisibility(ANOTHER_DISPLAY_ID, false); + ASSERT_TRUE(firstMousePc->isPointerShown()); + ASSERT_FALSE(secondMousePc->isPointerShown()); + + // Move and set pointer icons for both mice. The second pointer should still be hidden. + mChoreographer.notifyMotion( + MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE) + .pointer(MOUSE_POINTER) + .deviceId(DEVICE_ID) + .displayId(DISPLAY_ID) + .build()); + mChoreographer.notifyMotion( + MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE) + .pointer(MOUSE_POINTER) + .deviceId(SECOND_DEVICE_ID) + .displayId(ANOTHER_DISPLAY_ID) + .build()); + ASSERT_TRUE(mChoreographer.setPointerIcon(PointerIconStyle::TYPE_TEXT, DISPLAY_ID, DEVICE_ID)); + ASSERT_TRUE(mChoreographer.setPointerIcon(PointerIconStyle::TYPE_TEXT, ANOTHER_DISPLAY_ID, + SECOND_DEVICE_ID)); + firstMousePc->assertPointerIconSet(PointerIconStyle::TYPE_TEXT); + secondMousePc->assertPointerIconSet(PointerIconStyle::TYPE_TEXT); + ASSERT_TRUE(firstMousePc->isPointerShown()); + ASSERT_FALSE(secondMousePc->isPointerShown()); + + // Allow the icon to be visible on the second display, and move the mouse. + mChoreographer.setPointerIconVisibility(ANOTHER_DISPLAY_ID, true); + mChoreographer.notifyMotion( + MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE) + .pointer(MOUSE_POINTER) + .deviceId(SECOND_DEVICE_ID) + .displayId(ANOTHER_DISPLAY_ID) + .build()); + ASSERT_TRUE(firstMousePc->isPointerShown()); + ASSERT_TRUE(secondMousePc->isPointerShown()); +} + +TEST_F(PointerChoreographerTest, SetPointerIconVisibilityHidesPointerWhenDeviceConnected) { + mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID})); + mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID); + + // Hide the pointer on the display, and then connect the mouse. + mChoreographer.setPointerIconVisibility(DISPLAY_ID, false); + mChoreographer.notifyInputDevicesChanged( + {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, ADISPLAY_ID_NONE)}}); + auto mousePc = assertPointerControllerCreated(ControllerType::MOUSE); + ASSERT_EQ(DISPLAY_ID, mousePc->getDisplayId()); + + // The pointer should not be visible. + ASSERT_FALSE(mousePc->isPointerShown()); +} + +TEST_F(PointerChoreographerTest, SetPointerIconVisibilityHidesPointerForTouchpad) { + mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID})); + mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID); + + // Hide the pointer on the display. + mChoreographer.setPointerIconVisibility(DISPLAY_ID, false); + + mChoreographer.notifyInputDevicesChanged( + {/*id=*/0, + {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD, + ADISPLAY_ID_NONE)}}); + auto touchpadPc = assertPointerControllerCreated(ControllerType::MOUSE); + ASSERT_EQ(DISPLAY_ID, touchpadPc->getDisplayId()); + + mChoreographer.notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, + AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD) + .pointer(TOUCHPAD_POINTER) + .deviceId(DEVICE_ID) + .displayId(DISPLAY_ID) + .build()); + + // The pointer should not be visible. + ASSERT_FALSE(touchpadPc->isPointerShown()); +} + +TEST_F(PointerChoreographerTest, SetPointerIconVisibilityHidesPointerForStylus) { + mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID})); + mChoreographer.setStylusPointerIconEnabled(true); + + // Hide the pointer on the display. + mChoreographer.setPointerIconVisibility(DISPLAY_ID, false); + + mChoreographer.notifyInputDevicesChanged( + {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_STYLUS, DISPLAY_ID)}}); + mChoreographer.notifyMotion( + MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS) + .pointer(STYLUS_POINTER) + .deviceId(DEVICE_ID) + .displayId(DISPLAY_ID) + .build()); + ASSERT_TRUE(mChoreographer.setPointerIcon(PointerIconStyle::TYPE_TEXT, DISPLAY_ID, DEVICE_ID)); + auto pc = assertPointerControllerCreated(ControllerType::STYLUS); + pc->assertPointerIconSet(PointerIconStyle::TYPE_TEXT); + + // The pointer should not be visible. + ASSERT_FALSE(pc->isPointerShown()); +} + } // namespace android diff --git a/services/powermanager/PowerHalController.cpp b/services/powermanager/PowerHalController.cpp index 9a23c848c9..bc178bce8f 100644 --- a/services/powermanager/PowerHalController.cpp +++ b/services/powermanager/PowerHalController.cpp @@ -80,7 +80,7 @@ std::shared_ptr<HalWrapper> PowerHalController::initHal() { // Check if a call to Power HAL function failed; if so, log the failure and // invalidate the current Power HAL handle. template <typename T> -HalResult<T> PowerHalController::processHalResult(HalResult<T> result, const char* fnName) { +HalResult<T> PowerHalController::processHalResult(HalResult<T>&& result, const char* fnName) { if (result.isFailed()) { ALOGE("%s failed: %s", fnName, result.errorMessage()); std::lock_guard<std::mutex> lock(mConnectedHalMutex); @@ -88,21 +88,19 @@ HalResult<T> PowerHalController::processHalResult(HalResult<T> result, const cha mConnectedHal = nullptr; mHalConnector->reset(); } - return result; + return std::move(result); } HalResult<void> PowerHalController::setBoost(aidl::android::hardware::power::Boost boost, int32_t durationMs) { std::shared_ptr<HalWrapper> handle = initHal(); - auto result = handle->setBoost(boost, durationMs); - return processHalResult(result, "setBoost"); + return processHalResult(handle->setBoost(boost, durationMs), "setBoost"); } HalResult<void> PowerHalController::setMode(aidl::android::hardware::power::Mode mode, bool enabled) { std::shared_ptr<HalWrapper> handle = initHal(); - auto result = handle->setMode(mode, enabled); - return processHalResult(result, "setMode"); + return processHalResult(handle->setMode(mode, enabled), "setMode"); } HalResult<std::shared_ptr<aidl::android::hardware::power::IPowerHintSession>> @@ -110,14 +108,35 @@ PowerHalController::createHintSession(int32_t tgid, int32_t uid, const std::vector<int32_t>& threadIds, int64_t durationNanos) { std::shared_ptr<HalWrapper> handle = initHal(); - auto result = handle->createHintSession(tgid, uid, threadIds, durationNanos); - return processHalResult(result, "createHintSession"); + return processHalResult(handle->createHintSession(tgid, uid, threadIds, durationNanos), + "createHintSession"); +} + +HalResult<std::shared_ptr<aidl::android::hardware::power::IPowerHintSession>> +PowerHalController::createHintSessionWithConfig( + int32_t tgid, int32_t uid, const std::vector<int32_t>& threadIds, int64_t durationNanos, + aidl::android::hardware::power::SessionTag tag, + aidl::android::hardware::power::SessionConfig* config) { + std::shared_ptr<HalWrapper> handle = initHal(); + return processHalResult(handle->createHintSessionWithConfig(tgid, uid, threadIds, durationNanos, + tag, config), + "createHintSessionWithConfig"); } HalResult<int64_t> PowerHalController::getHintSessionPreferredRate() { std::shared_ptr<HalWrapper> handle = initHal(); - auto result = handle->getHintSessionPreferredRate(); - return processHalResult(result, "getHintSessionPreferredRate"); + return processHalResult(handle->getHintSessionPreferredRate(), "getHintSessionPreferredRate"); +} + +HalResult<aidl::android::hardware::power::ChannelConfig> PowerHalController::getSessionChannel( + int tgid, int uid) { + std::shared_ptr<HalWrapper> handle = initHal(); + return processHalResult(handle->getSessionChannel(tgid, uid), "getSessionChannel"); +} + +HalResult<void> PowerHalController::closeSessionChannel(int tgid, int uid) { + std::shared_ptr<HalWrapper> handle = initHal(); + return processHalResult(handle->closeSessionChannel(tgid, uid), "closeSessionChannel"); } } // namespace power diff --git a/services/powermanager/PowerHalWrapper.cpp b/services/powermanager/PowerHalWrapper.cpp index 76afbfc646..1009100cc2 100644 --- a/services/powermanager/PowerHalWrapper.cpp +++ b/services/powermanager/PowerHalWrapper.cpp @@ -42,37 +42,58 @@ inline HalResult<void> toHalResult(const ndk::ScopedAStatus& result) { // ------------------------------------------------------------------------------------------------- HalResult<void> EmptyHalWrapper::setBoost(Aidl::Boost boost, int32_t durationMs) { - ALOGV("Skipped setBoost %s with duration %dms because Power HAL not available", - toString(boost).c_str(), durationMs); + ALOGV("Skipped setBoost %s with duration %dms because %s", toString(boost).c_str(), durationMs, + getUnsupportedMessage()); return HalResult<void>::unsupported(); } HalResult<void> EmptyHalWrapper::setMode(Aidl::Mode mode, bool enabled) { - ALOGV("Skipped setMode %s to %s because Power HAL not available", toString(mode).c_str(), - enabled ? "true" : "false"); + ALOGV("Skipped setMode %s to %s because %s", toString(mode).c_str(), enabled ? "true" : "false", + getUnsupportedMessage()); return HalResult<void>::unsupported(); } HalResult<std::shared_ptr<Aidl::IPowerHintSession>> EmptyHalWrapper::createHintSession( int32_t, int32_t, const std::vector<int32_t>& threadIds, int64_t) { - ALOGV("Skipped createHintSession(task num=%zu) because Power HAL not available", - threadIds.size()); + ALOGV("Skipped createHintSession(task num=%zu) because %s", threadIds.size(), + getUnsupportedMessage()); + return HalResult<std::shared_ptr<Aidl::IPowerHintSession>>::unsupported(); +} + +HalResult<std::shared_ptr<Aidl::IPowerHintSession>> EmptyHalWrapper::createHintSessionWithConfig( + int32_t, int32_t, const std::vector<int32_t>& threadIds, int64_t, Aidl::SessionTag, + Aidl::SessionConfig*) { + ALOGV("Skipped createHintSessionWithConfig(task num=%zu) because %s", threadIds.size(), + getUnsupportedMessage()); return HalResult<std::shared_ptr<Aidl::IPowerHintSession>>::unsupported(); } HalResult<int64_t> EmptyHalWrapper::getHintSessionPreferredRate() { - ALOGV("Skipped getHintSessionPreferredRate because Power HAL not available"); + ALOGV("Skipped getHintSessionPreferredRate because %s", getUnsupportedMessage()); return HalResult<int64_t>::unsupported(); } +HalResult<Aidl::ChannelConfig> EmptyHalWrapper::getSessionChannel(int, int) { + ALOGV("Skipped getSessionChannel because %s", getUnsupportedMessage()); + return HalResult<Aidl::ChannelConfig>::unsupported(); +} + +HalResult<void> EmptyHalWrapper::closeSessionChannel(int, int) { + ALOGV("Skipped closeSessionChannel because %s", getUnsupportedMessage()); + return HalResult<void>::unsupported(); +} + +const char* EmptyHalWrapper::getUnsupportedMessage() { + return "Power HAL is not supported"; +} + // ------------------------------------------------------------------------------------------------- HalResult<void> HidlHalWrapperV1_0::setBoost(Aidl::Boost boost, int32_t durationMs) { if (boost == Aidl::Boost::INTERACTION) { return sendPowerHint(V1_3::PowerHint::INTERACTION, durationMs); } else { - ALOGV("Skipped setBoost %s because Power HAL AIDL not available", toString(boost).c_str()); - return HalResult<void>::unsupported(); + return EmptyHalWrapper::setBoost(boost, durationMs); } } @@ -92,9 +113,7 @@ HalResult<void> HidlHalWrapperV1_0::setMode(Aidl::Mode mode, bool enabled) { case Aidl::Mode::DOUBLE_TAP_TO_WAKE: return setFeature(V1_0::Feature::POWER_FEATURE_DOUBLE_TAP_TO_WAKE, enabled); default: - ALOGV("Skipped setMode %s because Power HAL AIDL not available", - toString(mode).c_str()); - return HalResult<void>::unsupported(); + return EmptyHalWrapper::setMode(mode, enabled); } } @@ -113,16 +132,8 @@ HalResult<void> HidlHalWrapperV1_0::setFeature(V1_0::Feature feature, bool enabl return HalResult<void>::fromReturn(ret); } -HalResult<std::shared_ptr<Aidl::IPowerHintSession>> HidlHalWrapperV1_0::createHintSession( - int32_t, int32_t, const std::vector<int32_t>& threadIds, int64_t) { - ALOGV("Skipped createHintSession(task num=%zu) because Power HAL not available", - threadIds.size()); - return HalResult<std::shared_ptr<Aidl::IPowerHintSession>>::unsupported(); -} - -HalResult<int64_t> HidlHalWrapperV1_0::getHintSessionPreferredRate() { - ALOGV("Skipped getHintSessionPreferredRate because Power HAL not available"); - return HalResult<int64_t>::unsupported(); +const char* HidlHalWrapperV1_0::getUnsupportedMessage() { + return "Power HAL AIDL is not supported"; } // ------------------------------------------------------------------------------------------------- @@ -191,7 +202,7 @@ HalResult<void> AidlHalWrapper::setBoost(Aidl::Boost boost, int32_t durationMs) // Quick return if boost is not supported by HAL if (idx >= mBoostSupportedArray.size() || mBoostSupportedArray[idx] == HalSupport::OFF) { - ALOGV("Skipped setBoost %s because Power HAL doesn't support it", toString(boost).c_str()); + ALOGV("Skipped setBoost %s because %s", toString(boost).c_str(), getUnsupportedMessage()); return HalResult<void>::unsupported(); } @@ -207,8 +218,8 @@ HalResult<void> AidlHalWrapper::setBoost(Aidl::Boost boost, int32_t durationMs) mBoostSupportedArray[idx] = isSupported ? HalSupport::ON : HalSupport::OFF; if (!isSupported) { - ALOGV("Skipped setBoost %s because Power HAL doesn't support it", - toString(boost).c_str()); + ALOGV("Skipped setBoost %s because %s", toString(boost).c_str(), + getUnsupportedMessage()); return HalResult<void>::unsupported(); } } @@ -223,7 +234,7 @@ HalResult<void> AidlHalWrapper::setMode(Aidl::Mode mode, bool enabled) { // Quick return if mode is not supported by HAL if (idx >= mModeSupportedArray.size() || mModeSupportedArray[idx] == HalSupport::OFF) { - ALOGV("Skipped setMode %s because Power HAL doesn't support it", toString(mode).c_str()); + ALOGV("Skipped setMode %s because %s", toString(mode).c_str(), getUnsupportedMessage()); return HalResult<void>::unsupported(); } @@ -236,8 +247,7 @@ HalResult<void> AidlHalWrapper::setMode(Aidl::Mode mode, bool enabled) { mModeSupportedArray[idx] = isSupported ? HalSupport::ON : HalSupport::OFF; if (!isSupported) { - ALOGV("Skipped setMode %s because Power HAL doesn't support it", - toString(mode).c_str()); + ALOGV("Skipped setMode %s because %s", toString(mode).c_str(), getUnsupportedMessage()); return HalResult<void>::unsupported(); } } @@ -251,7 +261,17 @@ HalResult<std::shared_ptr<Aidl::IPowerHintSession>> AidlHalWrapper::createHintSe std::shared_ptr<Aidl::IPowerHintSession> appSession; return HalResult<std::shared_ptr<Aidl::IPowerHintSession>>:: fromStatus(mHandle->createHintSession(tgid, uid, threadIds, durationNanos, &appSession), - appSession); + std::move(appSession)); +} + +HalResult<std::shared_ptr<Aidl::IPowerHintSession>> AidlHalWrapper::createHintSessionWithConfig( + int32_t tgid, int32_t uid, const std::vector<int32_t>& threadIds, int64_t durationNanos, + Aidl::SessionTag tag, Aidl::SessionConfig* config) { + std::shared_ptr<Aidl::IPowerHintSession> appSession; + return HalResult<std::shared_ptr<Aidl::IPowerHintSession>>:: + fromStatus(mHandle->createHintSessionWithConfig(tgid, uid, threadIds, durationNanos, + tag, config, &appSession), + std::move(appSession)); } HalResult<int64_t> AidlHalWrapper::getHintSessionPreferredRate() { @@ -260,6 +280,20 @@ HalResult<int64_t> AidlHalWrapper::getHintSessionPreferredRate() { return HalResult<int64_t>::fromStatus(result, rate); } +HalResult<Aidl::ChannelConfig> AidlHalWrapper::getSessionChannel(int tgid, int uid) { + Aidl::ChannelConfig config; + auto result = mHandle->getSessionChannel(tgid, uid, &config); + return HalResult<Aidl::ChannelConfig>::fromStatus(result, std::move(config)); +} + +HalResult<void> AidlHalWrapper::closeSessionChannel(int tgid, int uid) { + return toHalResult(mHandle->closeSessionChannel(tgid, uid)); +} + +const char* AidlHalWrapper::getUnsupportedMessage() { + return "Power HAL doesn't support it"; +} + // ------------------------------------------------------------------------------------------------- } // namespace power diff --git a/services/powermanager/tests/PowerHalWrapperAidlTest.cpp b/services/powermanager/tests/PowerHalWrapperAidlTest.cpp index 3d2cf293ed..a7202969ad 100644 --- a/services/powermanager/tests/PowerHalWrapperAidlTest.cpp +++ b/services/powermanager/tests/PowerHalWrapperAidlTest.cpp @@ -256,6 +256,23 @@ TEST_F(PowerHalWrapperAidlTest, TestCreateHintSessionSuccessful) { ASSERT_TRUE(result.isOk()); } +TEST_F(PowerHalWrapperAidlTest, TestCreateHintSessionWithConfigSuccessful) { + std::vector<int> threadIds{gettid()}; + int32_t tgid = 999; + int32_t uid = 1001; + int64_t durationNanos = 16666666L; + SessionTag tag = SessionTag::OTHER; + SessionConfig out; + EXPECT_CALL(*mMockHal.get(), + createHintSessionWithConfig(Eq(tgid), Eq(uid), Eq(threadIds), Eq(durationNanos), + Eq(tag), _, _)) + .Times(Exactly(1)) + .WillOnce(Return(testing::ByMove(ndk::ScopedAStatus::ok()))); + auto result = + mWrapper->createHintSessionWithConfig(tgid, uid, threadIds, durationNanos, tag, &out); + ASSERT_TRUE(result.isOk()); +} + TEST_F(PowerHalWrapperAidlTest, TestCreateHintSessionFailed) { int32_t tgid = 999; int32_t uid = 1001; @@ -279,3 +296,18 @@ TEST_F(PowerHalWrapperAidlTest, TestGetHintSessionPreferredRate) { int64_t rate = result.value(); ASSERT_GE(0, rate); } + +TEST_F(PowerHalWrapperAidlTest, TestSessionChannel) { + int32_t tgid = 999; + int32_t uid = 1001; + EXPECT_CALL(*mMockHal.get(), getSessionChannel(Eq(tgid), Eq(uid), _)) + .Times(Exactly(1)) + .WillOnce(Return(testing::ByMove(ndk::ScopedAStatus::ok()))); + EXPECT_CALL(*mMockHal.get(), closeSessionChannel(Eq(tgid), Eq(uid))) + .Times(Exactly(1)) + .WillOnce(Return(testing::ByMove(ndk::ScopedAStatus::ok()))); + auto createResult = mWrapper->getSessionChannel(tgid, uid); + ASSERT_TRUE(createResult.isOk()); + auto closeResult = mWrapper->closeSessionChannel(tgid, uid); + ASSERT_TRUE(closeResult.isOk()); +} diff --git a/services/surfaceflinger/Display/DisplayModeRequest.h b/services/surfaceflinger/Display/DisplayModeRequest.h index c0e77bb5fc..d07cdf55d2 100644 --- a/services/surfaceflinger/Display/DisplayModeRequest.h +++ b/services/surfaceflinger/Display/DisplayModeRequest.h @@ -27,9 +27,6 @@ struct DisplayModeRequest { // Whether to emit DisplayEventReceiver::DISPLAY_EVENT_MODE_CHANGE. bool emitEvent = false; - - // Whether to force the request to be applied, even if the mode is unchanged. - bool force = false; }; inline bool operator==(const DisplayModeRequest& lhs, const DisplayModeRequest& rhs) { diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index ef9d1184da..4f81482814 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -24,7 +24,6 @@ #define ATRACE_TAG ATRACE_TAG_GRAPHICS -#include <common/FlagManager.h> #include <compositionengine/CompositionEngine.h> #include <compositionengine/Display.h> #include <compositionengine/DisplayColorProfile.h> @@ -215,17 +214,6 @@ void DisplayDevice::setActiveMode(DisplayModeId modeId, Fps vsyncRate, Fps rende bool DisplayDevice::initiateModeChange(display::DisplayModeRequest&& desiredMode, const hal::VsyncPeriodChangeConstraints& constraints, hal::VsyncPeriodChangeTimeline& outTimeline) { - // TODO(b/255635711): Flow the DisplayModeRequest through the desired/pending/active states. For - // now, `desiredMode` and `mDesiredModeOpt` are one and the same, but the latter is not cleared - // until the next `SF::initiateDisplayModeChanges`. However, the desired mode has been consumed - // at this point, so clear the `force` flag to prevent an endless loop of `initiateModeChange`. - if (FlagManager::getInstance().connected_display()) { - std::scoped_lock lock(mDesiredModeLock); - if (mDesiredModeOpt) { - mDesiredModeOpt->force = false; - } - } - mPendingModeOpt = std::move(desiredMode); mIsModeSetPending = true; @@ -531,7 +519,8 @@ void DisplayDevice::animateOverlay() { } } -auto DisplayDevice::setDesiredMode(display::DisplayModeRequest&& desiredMode) -> DesiredModeAction { +auto DisplayDevice::setDesiredMode(display::DisplayModeRequest&& desiredMode, bool force) + -> DesiredModeAction { ATRACE_CALL(); const auto& desiredModePtr = desiredMode.mode.modePtr; @@ -539,26 +528,20 @@ auto DisplayDevice::setDesiredMode(display::DisplayModeRequest&& desiredMode) -> LOG_ALWAYS_FATAL_IF(getPhysicalId() != desiredModePtr->getPhysicalDisplayId(), "DisplayId mismatch"); - // TODO (b/318533819): Stringize DisplayModeRequest. - ALOGD("%s(%s, force=%s)", __func__, to_string(*desiredModePtr).c_str(), - desiredMode.force ? "true" : "false"); + ALOGV("%s(%s)", __func__, to_string(*desiredModePtr).c_str()); std::scoped_lock lock(mDesiredModeLock); if (mDesiredModeOpt) { // A mode transition was already scheduled, so just override the desired mode. const bool emitEvent = mDesiredModeOpt->emitEvent; - const bool force = mDesiredModeOpt->force; mDesiredModeOpt = std::move(desiredMode); mDesiredModeOpt->emitEvent |= emitEvent; - if (FlagManager::getInstance().connected_display()) { - mDesiredModeOpt->force |= force; - } return DesiredModeAction::None; } // If the desired mode is already active... const auto activeMode = refreshRateSelector().getActiveMode(); - if (!desiredMode.force && activeMode.modePtr->getId() == desiredModePtr->getId()) { + if (!force && activeMode.modePtr->getId() == desiredModePtr->getId()) { if (activeMode == desiredMode.mode) { return DesiredModeAction::None; } diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index edd57cce91..4ab6321064 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -189,7 +189,8 @@ public: enum class DesiredModeAction { None, InitiateDisplayModeSwitch, InitiateRenderRateSwitch }; - DesiredModeAction setDesiredMode(display::DisplayModeRequest&&) EXCLUDES(mDesiredModeLock); + DesiredModeAction setDesiredMode(display::DisplayModeRequest&&, bool force = false) + EXCLUDES(mDesiredModeLock); using DisplayModeRequestOpt = ftl::Optional<display::DisplayModeRequest>; diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp index db66f5b549..704ece516d 100644 --- a/services/surfaceflinger/DisplayHardware/HWC2.cpp +++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp @@ -27,7 +27,6 @@ #include "HWC2.h" #include <android/configuration.h> -#include <common/FlagManager.h> #include <ui/Fence.h> #include <ui/FloatRect.h> #include <ui/GraphicBuffer.h> @@ -417,19 +416,7 @@ Error Display::setActiveConfigWithConstraints(hal::HWConfigId configId, VsyncPeriodChangeTimeline* outTimeline) { ALOGV("[%" PRIu64 "] setActiveConfigWithConstraints", mId); - // FIXME (b/319505580): At least the first config set on an external display must be - // `setActiveConfig`, so skip over the block that calls `setActiveConfigWithConstraints` - // for simplicity. - ui::DisplayConnectionType type = ui::DisplayConnectionType::Internal; - const bool connected_display = FlagManager::getInstance().connected_display(); - if (connected_display) { - if (auto err = getConnectionType(&type); err != Error::NONE) { - return err; - } - } - - if (isVsyncPeriodSwitchSupported() && - (!connected_display || type != ui::DisplayConnectionType::External)) { + if (isVsyncPeriodSwitchSupported()) { Hwc2::IComposerClient::VsyncPeriodChangeConstraints hwc2Constraints; hwc2Constraints.desiredTimeNanos = constraints.desiredTimeNanos; hwc2Constraints.seamlessRequired = constraints.seamlessRequired; diff --git a/services/surfaceflinger/FpsReporter.cpp b/services/surfaceflinger/FpsReporter.cpp index 155cf4da58..a47348fbc4 100644 --- a/services/surfaceflinger/FpsReporter.cpp +++ b/services/surfaceflinger/FpsReporter.cpp @@ -26,13 +26,12 @@ namespace android { -FpsReporter::FpsReporter(frametimeline::FrameTimeline& frameTimeline, SurfaceFlinger& flinger, - std::unique_ptr<Clock> clock) - : mFrameTimeline(frameTimeline), mFlinger(flinger), mClock(std::move(clock)) { +FpsReporter::FpsReporter(frametimeline::FrameTimeline& frameTimeline, std::unique_ptr<Clock> clock) + : mFrameTimeline(frameTimeline), mClock(std::move(clock)) { LOG_ALWAYS_FATAL_IF(mClock == nullptr, "Passed in null clock when constructing FpsReporter!"); } -void FpsReporter::dispatchLayerFps() { +void FpsReporter::dispatchLayerFps(const frontend::LayerHierarchy& layerHierarchy) { const auto now = mClock->now(); if (now - mLastDispatch < kMinDispatchDuration) { return; @@ -52,31 +51,42 @@ void FpsReporter::dispatchLayerFps() { } std::unordered_set<int32_t> seenTasks; - std::vector<std::pair<TrackedListener, sp<Layer>>> listenersAndLayersToReport; + std::vector<std::pair<TrackedListener, const frontend::LayerHierarchy*>> + listenersAndLayersToReport; - mFlinger.mCurrentState.traverse([&](Layer* layer) { - auto& currentState = layer->getDrawingState(); - if (currentState.metadata.has(gui::METADATA_TASK_ID)) { - int32_t taskId = currentState.metadata.getInt32(gui::METADATA_TASK_ID, 0); + layerHierarchy.traverse([&](const frontend::LayerHierarchy& hierarchy, + const frontend::LayerHierarchy::TraversalPath& traversalPath) { + if (traversalPath.variant == frontend::LayerHierarchy::Variant::Detached) { + return false; + } + const auto& metadata = hierarchy.getLayer()->metadata; + if (metadata.has(gui::METADATA_TASK_ID)) { + int32_t taskId = metadata.getInt32(gui::METADATA_TASK_ID, 0); if (seenTasks.count(taskId) == 0) { // localListeners is expected to be tiny for (TrackedListener& listener : localListeners) { if (listener.taskId == taskId) { seenTasks.insert(taskId); - listenersAndLayersToReport.push_back( - {listener, sp<Layer>::fromExisting(layer)}); + listenersAndLayersToReport.push_back({listener, &hierarchy}); break; } } } } + return true; }); - for (const auto& [listener, layer] : listenersAndLayersToReport) { + for (const auto& [listener, hierarchy] : listenersAndLayersToReport) { std::unordered_set<int32_t> layerIds; - layer->traverse(LayerVector::StateSet::Current, - [&](Layer* layer) { layerIds.insert(layer->getSequence()); }); + hierarchy->traverse([&](const frontend::LayerHierarchy& hierarchy, + const frontend::LayerHierarchy::TraversalPath& traversalPath) { + if (traversalPath.variant == frontend::LayerHierarchy::Variant::Detached) { + return false; + } + layerIds.insert(static_cast<int32_t>(hierarchy.getLayer()->id)); + return true; + }); listener.listener->onFpsReported(mFrameTimeline.computeFps(layerIds)); } diff --git a/services/surfaceflinger/FpsReporter.h b/services/surfaceflinger/FpsReporter.h index 438b1aa362..01f1e07b26 100644 --- a/services/surfaceflinger/FpsReporter.h +++ b/services/surfaceflinger/FpsReporter.h @@ -24,6 +24,7 @@ #include "Clock.h" #include "FrameTimeline/FrameTimeline.h" +#include "FrontEnd/LayerHierarchy.h" #include "WpHash.h" namespace android { @@ -33,13 +34,13 @@ class SurfaceFlinger; class FpsReporter : public IBinder::DeathRecipient { public: - FpsReporter(frametimeline::FrameTimeline& frameTimeline, SurfaceFlinger& flinger, + FpsReporter(frametimeline::FrameTimeline& frameTimeline, std::unique_ptr<Clock> clock = std::make_unique<SteadyClock>()); // Dispatches updated layer fps values for the registered listeners // This method promotes Layer weak pointers and performs layer stack traversals, so mStateLock // must be held when calling this method. - void dispatchLayerFps() EXCLUDES(mMutex); + void dispatchLayerFps(const frontend::LayerHierarchy&) EXCLUDES(mMutex); // Override for IBinder::DeathRecipient void binderDied(const wp<IBinder>&) override; @@ -58,7 +59,6 @@ private: }; frametimeline::FrameTimeline& mFrameTimeline; - SurfaceFlinger& mFlinger; static const constexpr std::chrono::steady_clock::duration kMinDispatchDuration = std::chrono::milliseconds(500); std::unique_ptr<Clock> mClock; diff --git a/services/surfaceflinger/Scheduler/MessageQueue.cpp b/services/surfaceflinger/Scheduler/MessageQueue.cpp index cf8b3bfdbd..a145e59eb5 100644 --- a/services/surfaceflinger/Scheduler/MessageQueue.cpp +++ b/services/surfaceflinger/Scheduler/MessageQueue.cpp @@ -75,9 +75,9 @@ void MessageQueue::vsyncCallback(nsecs_t vsyncTime, nsecs_t targetWakeupTime, ns mHandler->dispatchFrame(vsyncId, expectedVsyncTime); } -void MessageQueue::initVsync(std::shared_ptr<scheduler::VSyncDispatch> dispatch, - frametimeline::TokenManager& tokenManager, - std::chrono::nanoseconds workDuration) { +void MessageQueue::initVsyncInternal(std::shared_ptr<scheduler::VSyncDispatch> dispatch, + frametimeline::TokenManager& tokenManager, + std::chrono::nanoseconds workDuration) { std::unique_ptr<scheduler::VSyncCallbackRegistration> oldRegistration; { std::lock_guard lock(mVsync.mutex); @@ -87,7 +87,7 @@ void MessageQueue::initVsync(std::shared_ptr<scheduler::VSyncDispatch> dispatch, } // See comments in onNewVsyncSchedule. Today, oldRegistration should be - // empty, but nothing prevents us from calling initVsync multiple times, so + // empty, but nothing prevents us from calling initVsyncInternal multiple times, so // go ahead and destruct it outside the lock for safety. oldRegistration.reset(); } diff --git a/services/surfaceflinger/Scheduler/MessageQueue.h b/services/surfaceflinger/Scheduler/MessageQueue.h index a523147733..edb424b5b9 100644 --- a/services/surfaceflinger/Scheduler/MessageQueue.h +++ b/services/surfaceflinger/Scheduler/MessageQueue.h @@ -65,8 +65,9 @@ class MessageQueue { public: virtual ~MessageQueue() = default; - virtual void initVsync(std::shared_ptr<scheduler::VSyncDispatch>, frametimeline::TokenManager&, - std::chrono::nanoseconds workDuration) = 0; + virtual void initVsyncInternal(std::shared_ptr<scheduler::VSyncDispatch>, + frametimeline::TokenManager&, + std::chrono::nanoseconds workDuration) = 0; virtual void destroyVsync() = 0; virtual void setDuration(std::chrono::nanoseconds workDuration) = 0; virtual void waitMessage() = 0; @@ -137,8 +138,8 @@ private: public: explicit MessageQueue(ICompositor&); - void initVsync(std::shared_ptr<scheduler::VSyncDispatch>, frametimeline::TokenManager&, - std::chrono::nanoseconds workDuration) override; + void initVsyncInternal(std::shared_ptr<scheduler::VSyncDispatch>, frametimeline::TokenManager&, + std::chrono::nanoseconds workDuration) override; void destroyVsync() override; void setDuration(std::chrono::nanoseconds workDuration) override; diff --git a/services/surfaceflinger/Scheduler/RefreshRateStats.h b/services/surfaceflinger/Scheduler/RefreshRateStats.h index 67e1b9c2ea..d51af9ac88 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateStats.h +++ b/services/surfaceflinger/Scheduler/RefreshRateStats.h @@ -49,10 +49,10 @@ class RefreshRateStats { public: // TODO(b/185535769): Inject clock to avoid sleeping in tests. - RefreshRateStats(TimeStats& timeStats, Fps currentRefreshRate, PowerMode currentPowerMode) + RefreshRateStats(TimeStats& timeStats, Fps currentRefreshRate) : mTimeStats(timeStats), mCurrentRefreshRate(currentRefreshRate), - mCurrentPowerMode(currentPowerMode) {} + mCurrentPowerMode(PowerMode::OFF) {} void setPowerMode(PowerMode mode) { if (mCurrentPowerMode == mode) { diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index 27ca17f481..fff97f7e0a 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -77,8 +77,7 @@ Scheduler::Scheduler(ICompositor& compositor, ISchedulerCallback& callback, Feat mFeatures(features), mVsyncConfiguration(factory.createVsyncConfiguration(activeRefreshRate)), mVsyncModulator(sp<VsyncModulator>::make(mVsyncConfiguration->getCurrentConfigs())), - mRefreshRateStats(std::make_unique<RefreshRateStats>(timeStats, activeRefreshRate, - hal::PowerMode::OFF)), + mRefreshRateStats(std::make_unique<RefreshRateStats>(timeStats, activeRefreshRate)), mSchedulerCallback(callback), mVsyncTrackerCallback(vsyncTrackerCallback) {} @@ -96,6 +95,11 @@ Scheduler::~Scheduler() { demotePacesetterDisplay(); } +void Scheduler::initVsync(frametimeline::TokenManager& tokenManager, + std::chrono::nanoseconds workDuration) { + Impl::initVsyncInternal(getVsyncSchedule()->getDispatch(), tokenManager, workDuration); +} + void Scheduler::startTimers() { using namespace sysprop; using namespace std::string_literals; diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index f62f1baf7c..99126220b0 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -131,7 +131,7 @@ public: void run(); - using Impl::initVsync; + void initVsync(frametimeline::TokenManager&, std::chrono::nanoseconds workDuration); using Impl::getScheduledFrameTime; using Impl::setDuration; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 8eff1b6f17..9426f975be 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1227,10 +1227,8 @@ status_t SurfaceFlinger::getDisplayStats(const sp<IBinder>& displayToken, return NO_ERROR; } -void SurfaceFlinger::setDesiredMode(display::DisplayModeRequest&& desiredMode) { - const auto mode = desiredMode.mode; - const auto displayId = mode.modePtr->getPhysicalDisplayId(); - +void SurfaceFlinger::setDesiredMode(display::DisplayModeRequest&& request, bool force) { + const auto displayId = request.mode.modePtr->getPhysicalDisplayId(); ATRACE_NAME(ftl::Concat(__func__, ' ', displayId.value).c_str()); const auto display = getDisplayDeviceLocked(displayId); @@ -1239,9 +1237,10 @@ void SurfaceFlinger::setDesiredMode(display::DisplayModeRequest&& desiredMode) { return; } - const bool emitEvent = desiredMode.emitEvent; + const auto mode = request.mode; + const bool emitEvent = request.emitEvent; - switch (display->setDesiredMode(std::move(desiredMode))) { + switch (display->setDesiredMode(std::move(request), force)) { case DisplayDevice::DesiredModeAction::InitiateDisplayModeSwitch: // DisplayDevice::setDesiredMode updated the render rate, so inform Scheduler. mScheduler->setRenderRate(displayId, @@ -1427,8 +1426,7 @@ void SurfaceFlinger::initiateDisplayModeChanges() { to_string(displayModePtrOpt->get()->getVsyncRate()).c_str(), to_string(display->getId()).c_str()); - if ((!FlagManager::getInstance().connected_display() || !desiredModeOpt->force) && - display->getActiveMode() == desiredModeOpt->mode) { + if (display->getActiveMode() == desiredModeOpt->mode) { applyActiveMode(display); continue; } @@ -3097,7 +3095,7 @@ void SurfaceFlinger::onCompositionPresented(PhysicalDisplayId pacesetterId, { Mutex::Autolock lock(mStateLock); if (mFpsReporter) { - mFpsReporter->dispatchLayerFps(); + mFpsReporter->dispatchLayerFps(mLayerHierarchyBuilder.getHierarchy()); } if (mTunnelModeEnabledReporter) { @@ -3294,88 +3292,14 @@ std::pair<DisplayModes, DisplayModePtr> SurfaceFlinger::loadDisplayModes( std::vector<HWComposer::HWCDisplayMode> hwcModes; std::optional<hal::HWDisplayId> activeModeHwcId; - const bool isExternalDisplay = FlagManager::getInstance().connected_display() && - getHwComposer().getDisplayConnectionType(displayId) == - ui::DisplayConnectionType::External; - int attempt = 0; constexpr int kMaxAttempts = 3; do { hwcModes = getHwComposer().getModes(displayId, scheduler::RefreshRateSelector::kMinSupportedFrameRate .getPeriodNsecs()); - activeModeHwcId = getHwComposer().getActiveMode(displayId); - if (isExternalDisplay) { - constexpr nsecs_t k59HzVsyncPeriod = 16949153; - constexpr nsecs_t k60HzVsyncPeriod = 16666667; - - // DM sets the initial mode for an external display to 1080p@60, but - // this comes after SF creates its own state (including the - // DisplayDevice). For now, pick the same mode in order to avoid - // inconsistent state and unnecessary mode switching. - // TODO (b/318534874): Let DM decide the initial mode. - // - // Try to find 1920x1080 @ 60 Hz - if (const auto iter = std::find_if(hwcModes.begin(), hwcModes.end(), - [](const auto& mode) { - return mode.width == 1920 && - mode.height == 1080 && - mode.vsyncPeriod == k60HzVsyncPeriod; - }); - iter != hwcModes.end()) { - activeModeHwcId = iter->hwcId; - break; - } - - // Try to find 1920x1080 @ 59-60 Hz - if (const auto iter = std::find_if(hwcModes.begin(), hwcModes.end(), - [](const auto& mode) { - return mode.width == 1920 && - mode.height == 1080 && - mode.vsyncPeriod >= k60HzVsyncPeriod && - mode.vsyncPeriod <= k59HzVsyncPeriod; - }); - iter != hwcModes.end()) { - activeModeHwcId = iter->hwcId; - break; - } - - // The display does not support 1080p@60, and this is the last attempt to pick a display - // mode. Prefer 60 Hz if available, with the closest resolution to 1080p. - if (attempt + 1 == kMaxAttempts) { - std::vector<HWComposer::HWCDisplayMode> hwcModeOpts; - - for (const auto& mode : hwcModes) { - if (mode.width <= 1920 && mode.height <= 1080 && - mode.vsyncPeriod >= k60HzVsyncPeriod && - mode.vsyncPeriod <= k59HzVsyncPeriod) { - hwcModeOpts.push_back(mode); - } - } - - if (const auto iter = std::max_element(hwcModeOpts.begin(), hwcModeOpts.end(), - [](const auto& a, const auto& b) { - const auto aSize = a.width * a.height; - const auto bSize = b.width * b.height; - if (aSize < bSize) - return true; - else if (aSize == bSize) - return a.vsyncPeriod > b.vsyncPeriod; - else - return false; - }); - iter != hwcModeOpts.end()) { - activeModeHwcId = iter->hwcId; - break; - } - - // hwcModeOpts was empty, use hwcModes[0] as the last resort - activeModeHwcId = hwcModes[0].hwcId; - } - } - const auto isActiveMode = [activeModeHwcId](const HWComposer::HWCDisplayMode& mode) { return mode.hwcId == activeModeHwcId; }; @@ -3435,10 +3359,6 @@ std::pair<DisplayModes, DisplayModePtr> SurfaceFlinger::loadDisplayModes( return pair.second->getHwcId() == activeModeHwcId; })->second; - if (isExternalDisplay) { - ALOGI("External display %s initial mode: {%s}", to_string(displayId).c_str(), - to_string(*activeMode).c_str()); - } return {modes, activeMode}; } @@ -3743,27 +3663,6 @@ void SurfaceFlinger::processDisplayAdded(const wp<IBinder>& displayToken, } mDisplays.try_emplace(displayToken, std::move(display)); - - // For an external display, loadDisplayModes already selected the same mode - // as DM, but SF still needs to be updated to match. - // TODO (b/318534874): Let DM decide the initial mode. - if (const auto& physical = state.physical; - mScheduler && physical && FlagManager::getInstance().connected_display()) { - const bool isInternalDisplay = mPhysicalDisplays.get(physical->id) - .transform(&PhysicalDisplay::isInternal) - .value_or(false); - - if (!isInternalDisplay) { - auto activeModePtr = physical->activeMode; - const auto fps = activeModePtr->getPeakFps(); - - setDesiredMode( - {.mode = scheduler::FrameRateMode{fps, - ftl::as_non_null(std::move(activeModePtr))}, - .emitEvent = false, - .force = true}); - } - } } void SurfaceFlinger::processDisplayRemoved(const wp<IBinder>& displayToken) { @@ -4332,13 +4231,12 @@ void SurfaceFlinger::initScheduler(const sp<const DisplayDevice>& display) { /* workDuration */ activeRefreshRate.getPeriod(), /* readyDuration */ configs.late.sfWorkDuration); - mScheduler->initVsync(mScheduler->getVsyncSchedule()->getDispatch(), - *mFrameTimeline->getTokenManager(), configs.late.sfWorkDuration); + mScheduler->initVsync(*mFrameTimeline->getTokenManager(), configs.late.sfWorkDuration); mRegionSamplingThread = sp<RegionSamplingThread>::make(*this, RegionSamplingThread::EnvironmentTimingTunables()); - mFpsReporter = sp<FpsReporter>::make(*mFrameTimeline, *this); + mFpsReporter = sp<FpsReporter>::make(*mFrameTimeline); } void SurfaceFlinger::doCommitTransactions() { @@ -8431,7 +8329,7 @@ status_t SurfaceFlinger::applyRefreshRateSelectorPolicy( return INVALID_OPERATION; } - setDesiredMode({std::move(preferredMode), .emitEvent = true, .force = force}); + setDesiredMode({std::move(preferredMode), .emitEvent = true}, force); // Update the frameRateOverride list as the display render rate might have changed if (mScheduler->updateFrameRateOverrides(scheduler::GlobalSignals{}, preferredFps)) { diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index c4cf425eb7..7cfe46cbea 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -718,7 +718,7 @@ private: // Show hdr sdr ratio overlay bool mHdrSdrRatioOverlay = false; - void setDesiredMode(display::DisplayModeRequest&&) REQUIRES(mStateLock); + void setDesiredMode(display::DisplayModeRequest&&, bool force = false) REQUIRES(mStateLock); status_t setActiveModeFromBackdoor(const sp<display::DisplayToken>&, DisplayModeId, Fps minFps, Fps maxFps); diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp index 8a5500f167..c098ddad24 100644 --- a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp +++ b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp @@ -405,8 +405,8 @@ void SchedulerFuzzer::fuzzRefreshRateSelector() { Fps::fromValue(mFdp.ConsumeFloatingPoint<float>())); android::mock::TimeStats timeStats; - RefreshRateStats refreshRateStats(timeStats, Fps::fromValue(mFdp.ConsumeFloatingPoint<float>()), - PowerMode::OFF); + RefreshRateStats refreshRateStats(timeStats, + Fps::fromValue(mFdp.ConsumeFloatingPoint<float>())); const auto fpsOpt = displayModes.get(modeId).transform( [](const DisplayModePtr& mode) { return mode->getVsyncRate(); }); diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h index f26336a655..387d2f26e6 100644 --- a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h +++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h @@ -461,11 +461,9 @@ struct HwcDisplayVariant { ? IComposerClient::DisplayConnectionType::INTERNAL : IComposerClient::DisplayConnectionType::EXTERNAL; - using ::testing::AtLeast; EXPECT_CALL(*test->mComposer, getDisplayConnectionType(HWC_DISPLAY_ID, _)) - .Times(AtLeast(1)) - .WillRepeatedly(DoAll(SetArgPointee<1>(CONNECTION_TYPE), - Return(hal::V2_4::Error::NONE))); + .WillOnce(DoAll(SetArgPointee<1>(CONNECTION_TYPE), + Return(hal::V2_4::Error::NONE))); } EXPECT_CALL(*test->mComposer, setClientTargetSlotCount(_)) diff --git a/services/surfaceflinger/tests/unittests/FpsReporterTest.cpp b/services/surfaceflinger/tests/unittests/FpsReporterTest.cpp index f695b096a7..9e8e306621 100644 --- a/services/surfaceflinger/tests/unittests/FpsReporterTest.cpp +++ b/services/surfaceflinger/tests/unittests/FpsReporterTest.cpp @@ -24,7 +24,11 @@ #include <gtest/gtest.h> #include <gui/LayerMetadata.h> +#include "Client.h" // temporarily needed for LayerCreationArgs #include "FpsReporter.h" +#include "FrontEnd/LayerCreationArgs.h" +#include "FrontEnd/LayerHierarchy.h" +#include "FrontEnd/LayerLifecycleManager.h" #include "Layer.h" #include "TestableSurfaceFlinger.h" #include "fake/FakeClock.h" @@ -76,7 +80,15 @@ protected: sp<Layer> createBufferStateLayer(LayerMetadata metadata); - TestableSurfaceFlinger mFlinger; + LayerCreationArgs createArgs(uint32_t id, bool canBeRoot, uint32_t parentId, + LayerMetadata metadata); + + void createRootLayer(uint32_t id, LayerMetadata metadata); + + void createLayer(uint32_t id, uint32_t parentId, LayerMetadata metadata); + + frontend::LayerLifecycleManager mLifecycleManager; + mock::FrameTimeline mFrameTimeline = mock::FrameTimeline(std::make_shared<impl::TimeStats>(), 0); @@ -89,8 +101,8 @@ protected: sp<TestableFpsListener> mFpsListener; fake::FakeClock* mClock = new fake::FakeClock(); - sp<FpsReporter> mFpsReporter = sp<FpsReporter>::make(mFrameTimeline, *(mFlinger.flinger()), - std::unique_ptr<Clock>(mClock)); + sp<FpsReporter> mFpsReporter = + sp<FpsReporter>::make(mFrameTimeline, std::unique_ptr<Clock>(mClock)); }; FpsReporterTest::FpsReporterTest() { @@ -98,9 +110,6 @@ FpsReporterTest::FpsReporterTest() { ::testing::UnitTest::GetInstance()->current_test_info(); ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name()); - mFlinger.setupMockScheduler(); - mFlinger.setupComposer(std::make_unique<Hwc2::mock::Composer>()); - mFpsListener = sp<TestableFpsListener>::make(); } @@ -110,76 +119,94 @@ FpsReporterTest::~FpsReporterTest() { ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name()); } -sp<Layer> FpsReporterTest::createBufferStateLayer(LayerMetadata metadata = {}) { +LayerCreationArgs FpsReporterTest::createArgs(uint32_t id, bool canBeRoot, uint32_t parentId, + LayerMetadata metadata) { sp<Client> client; - LayerCreationArgs args(mFlinger.flinger(), client, "buffer-state-layer", LAYER_FLAGS, metadata); - return sp<Layer>::make(args); + LayerCreationArgs args(std::make_optional(id)); + args.name = "testlayer"; + args.addToRoot = canBeRoot; + args.flags = LAYER_FLAGS; + args.metadata = metadata; + args.parentId = parentId; + return args; +} + +void FpsReporterTest::createRootLayer(uint32_t id, LayerMetadata metadata = LayerMetadata()) { + std::vector<std::unique_ptr<frontend::RequestedLayerState>> layers; + layers.emplace_back(std::make_unique<frontend::RequestedLayerState>( + createArgs(/*id=*/id, /*canBeRoot=*/true, /*parent=*/UNASSIGNED_LAYER_ID, + /*metadata=*/metadata))); + mLifecycleManager.addLayers(std::move(layers)); +} + +void FpsReporterTest::createLayer(uint32_t id, uint32_t parentId, + LayerMetadata metadata = LayerMetadata()) { + std::vector<std::unique_ptr<frontend::RequestedLayerState>> layers; + layers.emplace_back(std::make_unique<frontend::RequestedLayerState>( + createArgs(/*id=*/id, /*canBeRoot=*/false, /*parent=*/parentId, + /*mirror=*/metadata))); + mLifecycleManager.addLayers(std::move(layers)); } namespace { TEST_F(FpsReporterTest, callsListeners) { - mParent = createBufferStateLayer(); constexpr int32_t kTaskId = 12; LayerMetadata targetMetadata; targetMetadata.setInt32(gui::METADATA_TASK_ID, kTaskId); - mTarget = createBufferStateLayer(targetMetadata); - mChild = createBufferStateLayer(); - mGrandChild = createBufferStateLayer(); - mUnrelated = createBufferStateLayer(); - mParent->addChild(mTarget); - mTarget->addChild(mChild); - mChild->addChild(mGrandChild); - mParent->commitChildList(); - mFlinger.mutableCurrentState().layersSortedByZ.add(mParent); - mFlinger.mutableCurrentState().layersSortedByZ.add(mTarget); - mFlinger.mutableCurrentState().layersSortedByZ.add(mChild); - mFlinger.mutableCurrentState().layersSortedByZ.add(mGrandChild); + + createRootLayer(1, targetMetadata); + createLayer(11, 1); + createLayer(111, 11); + + frontend::LayerHierarchyBuilder hierarchyBuilder; + hierarchyBuilder.update(mLifecycleManager); float expectedFps = 44.0; - EXPECT_CALL(mFrameTimeline, - computeFps(UnorderedElementsAre(mTarget->getSequence(), mChild->getSequence(), - mGrandChild->getSequence()))) + EXPECT_CALL(mFrameTimeline, computeFps(UnorderedElementsAre(1, 11, 111))) .WillOnce(Return(expectedFps)); mFpsReporter->addListener(mFpsListener, kTaskId); mClock->advanceTime(600ms); - mFpsReporter->dispatchLayerFps(); + mFpsReporter->dispatchLayerFps(hierarchyBuilder.getHierarchy()); EXPECT_EQ(expectedFps, mFpsListener->lastReportedFps); mFpsReporter->removeListener(mFpsListener); Mock::VerifyAndClearExpectations(&mFrameTimeline); EXPECT_CALL(mFrameTimeline, computeFps(_)).Times(0); - mFpsReporter->dispatchLayerFps(); + mFpsReporter->dispatchLayerFps(hierarchyBuilder.getHierarchy()); } TEST_F(FpsReporterTest, rateLimits) { const constexpr int32_t kTaskId = 12; LayerMetadata targetMetadata; targetMetadata.setInt32(gui::METADATA_TASK_ID, kTaskId); - mTarget = createBufferStateLayer(targetMetadata); - mFlinger.mutableCurrentState().layersSortedByZ.add(mTarget); + createRootLayer(1); + createLayer(11, 1, targetMetadata); + + frontend::LayerHierarchyBuilder hierarchyBuilder; + hierarchyBuilder.update(mLifecycleManager); float firstFps = 44.0; float secondFps = 53.0; - EXPECT_CALL(mFrameTimeline, computeFps(UnorderedElementsAre(mTarget->getSequence()))) + EXPECT_CALL(mFrameTimeline, computeFps(UnorderedElementsAre(11))) .WillOnce(Return(firstFps)) .WillOnce(Return(secondFps)); mFpsReporter->addListener(mFpsListener, kTaskId); mClock->advanceTime(600ms); - mFpsReporter->dispatchLayerFps(); + mFpsReporter->dispatchLayerFps(hierarchyBuilder.getHierarchy()); EXPECT_EQ(firstFps, mFpsListener->lastReportedFps); mClock->advanceTime(200ms); - mFpsReporter->dispatchLayerFps(); + mFpsReporter->dispatchLayerFps(hierarchyBuilder.getHierarchy()); EXPECT_EQ(firstFps, mFpsListener->lastReportedFps); mClock->advanceTime(200ms); - mFpsReporter->dispatchLayerFps(); + mFpsReporter->dispatchLayerFps(hierarchyBuilder.getHierarchy()); EXPECT_EQ(firstFps, mFpsListener->lastReportedFps); mClock->advanceTime(200ms); - mFpsReporter->dispatchLayerFps(); + mFpsReporter->dispatchLayerFps(hierarchyBuilder.getHierarchy()); EXPECT_EQ(secondFps, mFpsListener->lastReportedFps); } diff --git a/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp b/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp index e9c4d801a9..249ed4017d 100644 --- a/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp +++ b/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp @@ -72,7 +72,8 @@ struct MockTokenManager : frametimeline::TokenManager { struct MessageQueueTest : testing::Test { void SetUp() override { EXPECT_CALL(*mVSyncDispatch, registerCallback(_, "sf")).WillOnce(Return(mCallbackToken)); - EXPECT_NO_FATAL_FAILURE(mEventQueue.initVsync(mVSyncDispatch, mTokenManager, kDuration)); + EXPECT_NO_FATAL_FAILURE( + mEventQueue.initVsyncInternal(mVSyncDispatch, mTokenManager, kDuration)); EXPECT_CALL(*mVSyncDispatch, unregisterCallback(mCallbackToken)).Times(1); } diff --git a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp index e2e3d7b12b..fba77e997c 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp @@ -37,7 +37,7 @@ protected: ~RefreshRateStatsTest(); void resetStats(Fps fps) { - mRefreshRateStats = std::make_unique<RefreshRateStats>(mTimeStats, fps, PowerMode::OFF); + mRefreshRateStats = std::make_unique<RefreshRateStats>(mTimeStats, fps); } mock::TimeStats mTimeStats; diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp index 82b4ad0b4f..8b16a8a480 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp @@ -21,13 +21,9 @@ #include "mock/DisplayHardware/MockDisplayMode.h" #include "mock/MockDisplayModeSpecs.h" -#include <com_android_graphics_surfaceflinger_flags.h> -#include <common/test/FlagUtils.h> #include <ftl/fake_guard.h> #include <scheduler/Fps.h> -using namespace com::android::graphics::surfaceflinger; - namespace android { namespace { @@ -364,13 +360,6 @@ MATCHER_P(ModeSettledTo, modeId, "") { } TEST_F(DisplayModeSwitchingTest, innerXorOuterDisplay) { - SET_FLAG_FOR_TEST(flags::connected_display, true); - - // For the inner display, this is handled by setupHwcHotplugCallExpectations. - EXPECT_CALL(*mComposer, getDisplayConnectionType(kOuterDisplayHwcId, _)) - .WillOnce(DoAll(SetArgPointee<1>(IComposerClient::DisplayConnectionType::INTERNAL), - Return(hal::V2_4::Error::NONE))); - const auto [innerDisplay, outerDisplay] = injectOuterDisplay(); EXPECT_TRUE(innerDisplay->isPoweredOn()); @@ -440,12 +429,6 @@ TEST_F(DisplayModeSwitchingTest, innerXorOuterDisplay) { } TEST_F(DisplayModeSwitchingTest, innerAndOuterDisplay) { - SET_FLAG_FOR_TEST(flags::connected_display, true); - - // For the inner display, this is handled by setupHwcHotplugCallExpectations. - EXPECT_CALL(*mComposer, getDisplayConnectionType(kOuterDisplayHwcId, _)) - .WillOnce(DoAll(SetArgPointee<1>(IComposerClient::DisplayConnectionType::INTERNAL), - Return(hal::V2_4::Error::NONE))); const auto [innerDisplay, outerDisplay] = injectOuterDisplay(); EXPECT_TRUE(innerDisplay->isPoweredOn()); @@ -529,13 +512,6 @@ TEST_F(DisplayModeSwitchingTest, powerOffDuringModeSet) { } TEST_F(DisplayModeSwitchingTest, powerOffDuringConcurrentModeSet) { - SET_FLAG_FOR_TEST(flags::connected_display, true); - - // For the inner display, this is handled by setupHwcHotplugCallExpectations. - EXPECT_CALL(*mComposer, getDisplayConnectionType(kOuterDisplayHwcId, _)) - .WillOnce(DoAll(SetArgPointee<1>(IComposerClient::DisplayConnectionType::INTERNAL), - Return(hal::V2_4::Error::NONE))); - const auto [innerDisplay, outerDisplay] = injectOuterDisplay(); EXPECT_TRUE(innerDisplay->isPoweredOn()); diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index 4e73733d1d..9ef0749dc6 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -268,7 +268,7 @@ public: vsyncTrackerCallback); } - mScheduler->initVsync(mScheduler->getVsyncSchedule()->getDispatch(), *mTokenManager, 0ms); + mScheduler->initVsync(*mTokenManager, 0ms); mScheduler->mutableAppConnectionHandle() = mScheduler->createConnection(std::move(appEventThread)); diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerHalController.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerHalController.h index b17c8adf6c..ae41e7ea75 100644 --- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerHalController.h +++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerHalController.h @@ -34,8 +34,6 @@ class IPower; namespace android::Hwc2::mock { -using aidl::android::hardware::power::Boost; -using aidl::android::hardware::power::Mode; using android::power::HalResult; class MockPowerHalController : public power::PowerHalController { @@ -43,12 +41,22 @@ public: MockPowerHalController(); ~MockPowerHalController() override; MOCK_METHOD(void, init, (), (override)); - MOCK_METHOD(HalResult<void>, setBoost, (Boost, int32_t), (override)); - MOCK_METHOD(HalResult<void>, setMode, (Mode, bool), (override)); + MOCK_METHOD(HalResult<void>, setBoost, (aidl::android::hardware::power::Boost, int32_t), + (override)); + MOCK_METHOD(HalResult<void>, setMode, (aidl::android::hardware::power::Mode, bool), (override)); MOCK_METHOD(HalResult<std::shared_ptr<aidl::android::hardware::power::IPowerHintSession>>, createHintSession, (int32_t, int32_t, const std::vector<int32_t>&, int64_t), (override)); + MOCK_METHOD(HalResult<std::shared_ptr<aidl::android::hardware::power::IPowerHintSession>>, + createHintSessionWithConfig, + (int32_t tgid, int32_t uid, const std::vector<int32_t>& threadIds, + int64_t durationNanos, aidl::android::hardware::power::SessionTag tag, + aidl::android::hardware::power::SessionConfig* config), + (override)); MOCK_METHOD(HalResult<int64_t>, getHintSessionPreferredRate, (), (override)); + MOCK_METHOD(HalResult<aidl::android::hardware::power::ChannelConfig>, getSessionChannel, + (int tgid, int uid), (override)); + MOCK_METHOD(HalResult<void>, closeSessionChannel, (int tgid, int uid), (override)); }; } // namespace android::Hwc2::mock
\ No newline at end of file |