diff options
65 files changed, 1457 insertions, 799 deletions
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp index 342f132f0c..d7e7eb8ea1 100644 --- a/libs/gui/Android.bp +++ b/libs/gui/Android.bp @@ -73,6 +73,7 @@ filegroup { "android/gui/FocusRequest.aidl", "android/gui/InputApplicationInfo.aidl", "android/gui/IWindowInfosListener.aidl", + "android/gui/IWindowInfosPublisher.aidl", "android/gui/IWindowInfosReportedListener.aidl", "android/gui/WindowInfo.aidl", "android/gui/WindowInfosUpdate.aidl", @@ -90,6 +91,7 @@ cc_library_static { "android/gui/FocusRequest.aidl", "android/gui/InputApplicationInfo.aidl", "android/gui/IWindowInfosListener.aidl", + "android/gui/IWindowInfosPublisher.aidl", "android/gui/IWindowInfosReportedListener.aidl", "android/gui/WindowInfosUpdate.aidl", "android/gui/WindowInfo.aidl", @@ -136,6 +138,7 @@ aidl_library { "android/gui/FocusRequest.aidl", "android/gui/InputApplicationInfo.aidl", "android/gui/IWindowInfosListener.aidl", + "android/gui/IWindowInfosPublisher.aidl", "android/gui/IWindowInfosReportedListener.aidl", "android/gui/WindowInfo.aidl", "android/gui/WindowInfosUpdate.aidl", diff --git a/libs/gui/FrameTimestamps.cpp b/libs/gui/FrameTimestamps.cpp index f3eb4e83aa..afb09de94b 100644 --- a/libs/gui/FrameTimestamps.cpp +++ b/libs/gui/FrameTimestamps.cpp @@ -255,7 +255,6 @@ void ProducerFrameEventHistory::updateAcquireFence( uint64_t frameNumber, std::shared_ptr<FenceTime>&& acquire) { FrameEvents* frame = getFrame(frameNumber, &mAcquireOffset); if (frame == nullptr) { - ALOGE("updateAcquireFence: Did not find frame."); return; } diff --git a/libs/gui/WindowInfosListenerReporter.cpp b/libs/gui/WindowInfosListenerReporter.cpp index 76e7b6e162..0929b8e120 100644 --- a/libs/gui/WindowInfosListenerReporter.cpp +++ b/libs/gui/WindowInfosListenerReporter.cpp @@ -22,7 +22,6 @@ namespace android { using gui::DisplayInfo; -using gui::IWindowInfosReportedListener; using gui::WindowInfo; using gui::WindowInfosListener; using gui::aidl_utils::statusTFromBinderStatus; @@ -40,8 +39,13 @@ status_t WindowInfosListenerReporter::addWindowInfosListener( { std::scoped_lock lock(mListenersMutex); if (mWindowInfosListeners.empty()) { - binder::Status s = surfaceComposer->addWindowInfosListener(this); + gui::WindowInfosListenerInfo listenerInfo; + binder::Status s = surfaceComposer->addWindowInfosListener(this, &listenerInfo); status = statusTFromBinderStatus(s); + if (status == OK) { + mWindowInfosPublisher = std::move(listenerInfo.windowInfosPublisher); + mListenerId = listenerInfo.listenerId; + } } if (status == OK) { @@ -85,8 +89,7 @@ status_t WindowInfosListenerReporter::removeWindowInfosListener( } binder::Status WindowInfosListenerReporter::onWindowInfosChanged( - const gui::WindowInfosUpdate& update, - const sp<IWindowInfosReportedListener>& windowInfosReportedListener) { + const gui::WindowInfosUpdate& update) { std::unordered_set<sp<WindowInfosListener>, gui::SpHash<WindowInfosListener>> windowInfosListeners; @@ -104,9 +107,7 @@ binder::Status WindowInfosListenerReporter::onWindowInfosChanged( listener->onWindowInfosChanged(update); } - if (windowInfosReportedListener) { - windowInfosReportedListener->onWindowInfosReported(); - } + mWindowInfosPublisher->ackWindowInfosReceived(update.vsyncId, mListenerId); return binder::Status::ok(); } @@ -114,7 +115,10 @@ binder::Status WindowInfosListenerReporter::onWindowInfosChanged( void WindowInfosListenerReporter::reconnect(const sp<gui::ISurfaceComposer>& composerService) { std::scoped_lock lock(mListenersMutex); if (!mWindowInfosListeners.empty()) { - composerService->addWindowInfosListener(this); + gui::WindowInfosListenerInfo listenerInfo; + composerService->addWindowInfosListener(this, &listenerInfo); + mWindowInfosPublisher = std::move(listenerInfo.windowInfosPublisher); + mListenerId = listenerInfo.listenerId; } } diff --git a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl index ec3266ca83..539a1c140e 100644 --- a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl +++ b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl @@ -40,12 +40,14 @@ import android.gui.IScreenCaptureListener; import android.gui.ISurfaceComposerClient; import android.gui.ITunnelModeEnabledListener; import android.gui.IWindowInfosListener; +import android.gui.IWindowInfosPublisher; import android.gui.LayerCaptureArgs; import android.gui.LayerDebugInfo; import android.gui.OverlayProperties; import android.gui.PullAtomData; import android.gui.ARect; import android.gui.StaticDisplayInfo; +import android.gui.WindowInfosListenerInfo; /** @hide */ interface ISurfaceComposer { @@ -500,7 +502,7 @@ interface ISurfaceComposer { */ int getMaxAcquiredBufferCount(); - void addWindowInfosListener(IWindowInfosListener windowInfosListener); + WindowInfosListenerInfo addWindowInfosListener(IWindowInfosListener windowInfosListener); void removeWindowInfosListener(IWindowInfosListener windowInfosListener); diff --git a/libs/gui/aidl/android/gui/WindowInfosListenerInfo.aidl b/libs/gui/aidl/android/gui/WindowInfosListenerInfo.aidl new file mode 100644 index 0000000000..0ca13b768a --- /dev/null +++ b/libs/gui/aidl/android/gui/WindowInfosListenerInfo.aidl @@ -0,0 +1,25 @@ +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.gui; + +import android.gui.IWindowInfosPublisher; + +/** @hide */ +parcelable WindowInfosListenerInfo { + long listenerId; + IWindowInfosPublisher windowInfosPublisher; +}
\ No newline at end of file diff --git a/libs/gui/android/gui/IWindowInfosListener.aidl b/libs/gui/android/gui/IWindowInfosListener.aidl index 400229d99f..07cb5ed0e6 100644 --- a/libs/gui/android/gui/IWindowInfosListener.aidl +++ b/libs/gui/android/gui/IWindowInfosListener.aidl @@ -16,11 +16,9 @@ package android.gui; -import android.gui.IWindowInfosReportedListener; import android.gui.WindowInfosUpdate; /** @hide */ oneway interface IWindowInfosListener { - void onWindowInfosChanged( - in WindowInfosUpdate update, in @nullable IWindowInfosReportedListener windowInfosReportedListener); + void onWindowInfosChanged(in WindowInfosUpdate update); } diff --git a/libs/gui/android/gui/IWindowInfosPublisher.aidl b/libs/gui/android/gui/IWindowInfosPublisher.aidl new file mode 100644 index 0000000000..5a9c32845e --- /dev/null +++ b/libs/gui/android/gui/IWindowInfosPublisher.aidl @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.gui; + +/** @hide */ +oneway interface IWindowInfosPublisher +{ + void ackWindowInfosReceived(long vsyncId, long listenerId); +} diff --git a/libs/gui/fuzzer/libgui_fuzzer_utils.h b/libs/gui/fuzzer/libgui_fuzzer_utils.h index 8c003d8ad4..4c7d0562af 100644 --- a/libs/gui/fuzzer/libgui_fuzzer_utils.h +++ b/libs/gui/fuzzer/libgui_fuzzer_utils.h @@ -153,8 +153,8 @@ public: MOCK_METHOD(binder::Status, setOverrideFrameRate, (int32_t, float), (override)); MOCK_METHOD(binder::Status, getGpuContextPriority, (int32_t*), (override)); MOCK_METHOD(binder::Status, getMaxAcquiredBufferCount, (int32_t*), (override)); - MOCK_METHOD(binder::Status, addWindowInfosListener, (const sp<gui::IWindowInfosListener>&), - (override)); + MOCK_METHOD(binder::Status, addWindowInfosListener, + (const sp<gui::IWindowInfosListener>&, gui::WindowInfosListenerInfo*), (override)); MOCK_METHOD(binder::Status, removeWindowInfosListener, (const sp<gui::IWindowInfosListener>&), (override)); MOCK_METHOD(binder::Status, getOverlaySupport, (gui::OverlayProperties*), (override)); diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index 7c150d53d9..3ff6735926 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -26,6 +26,7 @@ #include <android/gui/IScreenCaptureListener.h> #include <android/gui/ITunnelModeEnabledListener.h> #include <android/gui/IWindowInfosListener.h> +#include <android/gui/IWindowInfosPublisher.h> #include <binder/IBinder.h> #include <binder/IInterface.h> #include <gui/ITransactionCompletedListener.h> diff --git a/libs/gui/include/gui/WindowInfosListenerReporter.h b/libs/gui/include/gui/WindowInfosListenerReporter.h index 38cb108912..684e21ad96 100644 --- a/libs/gui/include/gui/WindowInfosListenerReporter.h +++ b/libs/gui/include/gui/WindowInfosListenerReporter.h @@ -18,7 +18,7 @@ #include <android/gui/BnWindowInfosListener.h> #include <android/gui/ISurfaceComposer.h> -#include <android/gui/IWindowInfosReportedListener.h> +#include <android/gui/IWindowInfosPublisher.h> #include <binder/IBinder.h> #include <gui/SpHash.h> #include <gui/WindowInfosListener.h> @@ -30,8 +30,7 @@ namespace android { class WindowInfosListenerReporter : public gui::BnWindowInfosListener { public: static sp<WindowInfosListenerReporter> getInstance(); - binder::Status onWindowInfosChanged(const gui::WindowInfosUpdate& update, - const sp<gui::IWindowInfosReportedListener>&) override; + binder::Status onWindowInfosChanged(const gui::WindowInfosUpdate& update) override; status_t addWindowInfosListener( const sp<gui::WindowInfosListener>& windowInfosListener, const sp<gui::ISurfaceComposer>&, @@ -47,5 +46,8 @@ private: std::vector<gui::WindowInfo> mLastWindowInfos GUARDED_BY(mListenersMutex); std::vector<gui::DisplayInfo> mLastDisplayInfos GUARDED_BY(mListenersMutex); + + sp<gui::IWindowInfosPublisher> mWindowInfosPublisher; + int64_t mListenerId; }; } // namespace android diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index 90c0a63286..567604dbec 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -1002,7 +1002,8 @@ public: } binder::Status addWindowInfosListener( - const sp<gui::IWindowInfosListener>& /*windowInfosListener*/) override { + const sp<gui::IWindowInfosListener>& /*windowInfosListener*/, + gui::WindowInfosListenerInfo* /*outInfo*/) override { return binder::Status::ok(); } diff --git a/libs/input/Android.bp b/libs/input/Android.bp index 769677c6ff..757cde2074 100644 --- a/libs/input/Android.bp +++ b/libs/input/Android.bp @@ -65,6 +65,10 @@ rust_bindgen { bindgen_flags: [ "--verbose", "--allowlist-var=AMOTION_EVENT_FLAG_CANCELED", + "--allowlist-var=AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED", + "--allowlist-var=AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED", + "--allowlist-var=AMOTION_EVENT_FLAG_IS_ACCESSIBILITY_EVENT", + "--allowlist-var=AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE", "--allowlist-var=AMOTION_EVENT_ACTION_CANCEL", "--allowlist-var=AMOTION_EVENT_ACTION_UP", "--allowlist-var=AMOTION_EVENT_ACTION_POINTER_DOWN", diff --git a/libs/input/InputVerifier.cpp b/libs/input/InputVerifier.cpp index 851babfb54..341eb6f920 100644 --- a/libs/input/InputVerifier.cpp +++ b/libs/input/InputVerifier.cpp @@ -44,7 +44,7 @@ Result<void> InputVerifier::processMovement(DeviceId deviceId, int32_t action, rust::Slice<const RustPointerProperties> properties{rpp.data(), rpp.size()}; rust::String errorMessage = android::input::verifier::process_movement(*mVerifier, deviceId, action, properties, - flags); + static_cast<uint32_t>(flags)); if (errorMessage.empty()) { return {}; } else { diff --git a/libs/input/rust/input.rs b/libs/input/rust/input.rs index a308c26b2e..9d3b38693a 100644 --- a/libs/input/rust/input.rs +++ b/libs/input/rust/input.rs @@ -119,8 +119,18 @@ impl MotionAction { bitflags! { /// MotionEvent flags. - pub struct MotionFlags: i32 { + pub struct MotionFlags: u32 { /// FLAG_CANCELED - const CANCELED = input_bindgen::AMOTION_EVENT_FLAG_CANCELED; + const CANCELED = input_bindgen::AMOTION_EVENT_FLAG_CANCELED as u32; + /// FLAG_WINDOW_IS_OBSCURED + const WINDOW_IS_OBSCURED = input_bindgen::AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED; + /// FLAG_WINDOW_IS_PARTIALLY_OBSCURED + const WINDOW_IS_PARTIALLY_OBSCURED = + input_bindgen::AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED; + /// FLAG_IS_ACCESSIBILITY_EVENT + const IS_ACCESSIBILITY_EVENT = + input_bindgen::AMOTION_EVENT_FLAG_IS_ACCESSIBILITY_EVENT; + /// FLAG_NO_FOCUS_CHANGE + const NO_FOCUS_CHANGE = input_bindgen::AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE; } } diff --git a/libs/input/rust/lib.rs b/libs/input/rust/lib.rs index 892f558da6..688d941bf6 100644 --- a/libs/input/rust/lib.rs +++ b/libs/input/rust/lib.rs @@ -52,7 +52,7 @@ mod ffi { device_id: i32, action: u32, pointer_properties: &[RustPointerProperties], - flags: i32, + flags: u32, ) -> String; fn reset_device(verifier: &mut InputVerifier, device_id: i32); } @@ -74,7 +74,7 @@ fn process_movement( device_id: i32, action: u32, pointer_properties: &[RustPointerProperties], - flags: i32, + flags: u32, ) -> String { let result = verifier.process_movement( DeviceId(device_id), diff --git a/libs/nativewindow/AHardwareBuffer.cpp b/libs/nativewindow/AHardwareBuffer.cpp index 80607055ed..e7b2195056 100644 --- a/libs/nativewindow/AHardwareBuffer.cpp +++ b/libs/nativewindow/AHardwareBuffer.cpp @@ -40,6 +40,80 @@ static constexpr int kFdBufferSize = 128 * sizeof(int); // 128 ints using namespace android; // ---------------------------------------------------------------------------- +// Validate hardware_buffer.h and PixelFormat.aidl agree +// ---------------------------------------------------------------------------- + +static_assert(HAL_PIXEL_FORMAT_RGBA_8888 == AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, + "HAL and AHardwareBuffer pixel format don't match"); +static_assert(HAL_PIXEL_FORMAT_RGBX_8888 == AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM, + "HAL and AHardwareBuffer pixel format don't match"); +static_assert(HAL_PIXEL_FORMAT_RGB_565 == AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM, + "HAL and AHardwareBuffer pixel format don't match"); +static_assert(HAL_PIXEL_FORMAT_RGB_888 == AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM, + "HAL and AHardwareBuffer pixel format don't match"); +static_assert(HAL_PIXEL_FORMAT_RGBA_FP16 == AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT, + "HAL and AHardwareBuffer pixel format don't match"); +static_assert(HAL_PIXEL_FORMAT_RGBA_1010102 == AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM, + "HAL and AHardwareBuffer pixel format don't match"); +static_assert(HAL_PIXEL_FORMAT_BLOB == AHARDWAREBUFFER_FORMAT_BLOB, + "HAL and AHardwareBuffer pixel format don't match"); +static_assert(HAL_PIXEL_FORMAT_DEPTH_16 == AHARDWAREBUFFER_FORMAT_D16_UNORM, + "HAL and AHardwareBuffer pixel format don't match"); +static_assert(HAL_PIXEL_FORMAT_DEPTH_24 == AHARDWAREBUFFER_FORMAT_D24_UNORM, + "HAL and AHardwareBuffer pixel format don't match"); +static_assert(HAL_PIXEL_FORMAT_DEPTH_24_STENCIL_8 == AHARDWAREBUFFER_FORMAT_D24_UNORM_S8_UINT, + "HAL and AHardwareBuffer pixel format don't match"); +static_assert(HAL_PIXEL_FORMAT_DEPTH_32F == AHARDWAREBUFFER_FORMAT_D32_FLOAT, + "HAL and AHardwareBuffer pixel format don't match"); +static_assert(HAL_PIXEL_FORMAT_DEPTH_32F_STENCIL_8 == AHARDWAREBUFFER_FORMAT_D32_FLOAT_S8_UINT, + "HAL and AHardwareBuffer pixel format don't match"); +static_assert(HAL_PIXEL_FORMAT_STENCIL_8 == AHARDWAREBUFFER_FORMAT_S8_UINT, + "HAL and AHardwareBuffer pixel format don't match"); +static_assert(HAL_PIXEL_FORMAT_BGRA_8888 == AHARDWAREBUFFER_FORMAT_B8G8R8A8_UNORM, + "HAL and AHardwareBuffer pixel format don't match"); +static_assert(HAL_PIXEL_FORMAT_YV12 == AHARDWAREBUFFER_FORMAT_YV12, + "HAL and AHardwareBuffer pixel format don't match"); +static_assert(HAL_PIXEL_FORMAT_Y8 == AHARDWAREBUFFER_FORMAT_Y8, + "HAL and AHardwareBuffer pixel format don't match"); +static_assert(HAL_PIXEL_FORMAT_Y16 == AHARDWAREBUFFER_FORMAT_Y16, + "HAL and AHardwareBuffer pixel format don't match"); +static_assert(HAL_PIXEL_FORMAT_RAW16 == AHARDWAREBUFFER_FORMAT_RAW16, + "HAL and AHardwareBuffer pixel format don't match"); +static_assert(HAL_PIXEL_FORMAT_RAW10 == AHARDWAREBUFFER_FORMAT_RAW10, + "HAL and AHardwareBuffer pixel format don't match"); +static_assert(HAL_PIXEL_FORMAT_RAW12 == AHARDWAREBUFFER_FORMAT_RAW12, + "HAL and AHardwareBuffer pixel format don't match"); +static_assert(HAL_PIXEL_FORMAT_RAW_OPAQUE == AHARDWAREBUFFER_FORMAT_RAW_OPAQUE, + "HAL and AHardwareBuffer pixel format don't match"); +static_assert(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED == + AHARDWAREBUFFER_FORMAT_IMPLEMENTATION_DEFINED, + "HAL and AHardwareBuffer pixel format don't match"); +static_assert(HAL_PIXEL_FORMAT_YCBCR_420_888 == AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420, + "HAL and AHardwareBuffer pixel format don't match"); +static_assert(HAL_PIXEL_FORMAT_YCBCR_422_SP == AHARDWAREBUFFER_FORMAT_YCbCr_422_SP, + "HAL and AHardwareBuffer pixel format don't match"); +static_assert(HAL_PIXEL_FORMAT_YCRCB_420_SP == AHARDWAREBUFFER_FORMAT_YCrCb_420_SP, + "HAL and AHardwareBuffer pixel format don't match"); +static_assert(HAL_PIXEL_FORMAT_YCBCR_422_I == AHARDWAREBUFFER_FORMAT_YCbCr_422_I, + "HAL and AHardwareBuffer pixel format don't match"); +static_assert(HAL_PIXEL_FORMAT_YCBCR_P010 == AHARDWAREBUFFER_FORMAT_YCbCr_P010, + "HAL and AHardwareBuffer pixel format don't match"); +static_assert(static_cast<int>(aidl::android::hardware::graphics::common::PixelFormat::R_8) == + AHARDWAREBUFFER_FORMAT_R8_UNORM, + "HAL and AHardwareBuffer pixel format don't match"); +static_assert(static_cast<int>(aidl::android::hardware::graphics::common::PixelFormat::R_16_UINT) == + AHARDWAREBUFFER_FORMAT_R16_UINT, + "HAL and AHardwareBuffer pixel format don't match"); +static_assert( + static_cast<int>(aidl::android::hardware::graphics::common::PixelFormat::RG_1616_UINT) == + AHARDWAREBUFFER_FORMAT_R16G16_UINT, + "HAL and AHardwareBuffer pixel format don't match"); +static_assert( + static_cast<int>(aidl::android::hardware::graphics::common::PixelFormat::RGBA_10101010) == + AHARDWAREBUFFER_FORMAT_R10G10B10A10_UNORM, + "HAL and AHardwareBuffer pixel format don't match"); + +// ---------------------------------------------------------------------------- // Public functions // ---------------------------------------------------------------------------- @@ -227,11 +301,14 @@ int AHardwareBuffer_lockPlanes(AHardwareBuffer* buffer, uint64_t usage, } return result; } else { - const uint32_t pixelStride = AHardwareBuffer_bytesPerPixel(format); + int32_t bytesPerPixel; + int32_t bytesPerStride; + int result = gBuffer->lockAsync(usage, usage, bounds, &outPlanes->planes[0].data, fence, + &bytesPerPixel, &bytesPerStride); outPlanes->planeCount = 1; - outPlanes->planes[0].pixelStride = pixelStride; - outPlanes->planes[0].rowStride = gBuffer->getStride() * pixelStride; - return gBuffer->lockAsync(usage, usage, bounds, &outPlanes->planes[0].data, fence); + outPlanes->planes[0].pixelStride = bytesPerPixel; + outPlanes->planes[0].rowStride = bytesPerStride; + return result; } } @@ -487,12 +564,6 @@ bool AHardwareBuffer_isValidDescription(const AHardwareBuffer_Desc* desc, bool l return false; } - if (!AHardwareBuffer_isValidPixelFormat(desc->format)) { - ALOGE_IF(log, "Invalid AHardwareBuffer pixel format %u (%#x))", - desc->format, desc->format); - return false; - } - if (desc->rfu0 != 0 || desc->rfu1 != 0) { ALOGE_IF(log, "AHardwareBuffer_Desc::rfu fields must be 0"); return false; @@ -557,114 +628,6 @@ bool AHardwareBuffer_isValidDescription(const AHardwareBuffer_Desc* desc, bool l return true; } -bool AHardwareBuffer_isValidPixelFormat(uint32_t format) { - static_assert(HAL_PIXEL_FORMAT_RGBA_8888 == AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, - "HAL and AHardwareBuffer pixel format don't match"); - static_assert(HAL_PIXEL_FORMAT_RGBX_8888 == AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM, - "HAL and AHardwareBuffer pixel format don't match"); - static_assert(HAL_PIXEL_FORMAT_RGB_565 == AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM, - "HAL and AHardwareBuffer pixel format don't match"); - static_assert(HAL_PIXEL_FORMAT_RGB_888 == AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM, - "HAL and AHardwareBuffer pixel format don't match"); - static_assert(HAL_PIXEL_FORMAT_RGBA_FP16 == AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT, - "HAL and AHardwareBuffer pixel format don't match"); - static_assert(HAL_PIXEL_FORMAT_RGBA_1010102 == AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM, - "HAL and AHardwareBuffer pixel format don't match"); - static_assert(HAL_PIXEL_FORMAT_BLOB == AHARDWAREBUFFER_FORMAT_BLOB, - "HAL and AHardwareBuffer pixel format don't match"); - static_assert(HAL_PIXEL_FORMAT_DEPTH_16 == AHARDWAREBUFFER_FORMAT_D16_UNORM, - "HAL and AHardwareBuffer pixel format don't match"); - static_assert(HAL_PIXEL_FORMAT_DEPTH_24 == AHARDWAREBUFFER_FORMAT_D24_UNORM, - "HAL and AHardwareBuffer pixel format don't match"); - static_assert(HAL_PIXEL_FORMAT_DEPTH_24_STENCIL_8 == AHARDWAREBUFFER_FORMAT_D24_UNORM_S8_UINT, - "HAL and AHardwareBuffer pixel format don't match"); - static_assert(HAL_PIXEL_FORMAT_DEPTH_32F == AHARDWAREBUFFER_FORMAT_D32_FLOAT, - "HAL and AHardwareBuffer pixel format don't match"); - static_assert(HAL_PIXEL_FORMAT_DEPTH_32F_STENCIL_8 == AHARDWAREBUFFER_FORMAT_D32_FLOAT_S8_UINT, - "HAL and AHardwareBuffer pixel format don't match"); - static_assert(HAL_PIXEL_FORMAT_STENCIL_8 == AHARDWAREBUFFER_FORMAT_S8_UINT, - "HAL and AHardwareBuffer pixel format don't match"); - static_assert(HAL_PIXEL_FORMAT_BGRA_8888 == AHARDWAREBUFFER_FORMAT_B8G8R8A8_UNORM, - "HAL and AHardwareBuffer pixel format don't match"); - static_assert(HAL_PIXEL_FORMAT_YV12 == AHARDWAREBUFFER_FORMAT_YV12, - "HAL and AHardwareBuffer pixel format don't match"); - static_assert(HAL_PIXEL_FORMAT_Y8 == AHARDWAREBUFFER_FORMAT_Y8, - "HAL and AHardwareBuffer pixel format don't match"); - static_assert(HAL_PIXEL_FORMAT_Y16 == AHARDWAREBUFFER_FORMAT_Y16, - "HAL and AHardwareBuffer pixel format don't match"); - static_assert(HAL_PIXEL_FORMAT_RAW16 == AHARDWAREBUFFER_FORMAT_RAW16, - "HAL and AHardwareBuffer pixel format don't match"); - static_assert(HAL_PIXEL_FORMAT_RAW10 == AHARDWAREBUFFER_FORMAT_RAW10, - "HAL and AHardwareBuffer pixel format don't match"); - static_assert(HAL_PIXEL_FORMAT_RAW12 == AHARDWAREBUFFER_FORMAT_RAW12, - "HAL and AHardwareBuffer pixel format don't match"); - static_assert(HAL_PIXEL_FORMAT_RAW_OPAQUE == AHARDWAREBUFFER_FORMAT_RAW_OPAQUE, - "HAL and AHardwareBuffer pixel format don't match"); - static_assert(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED == AHARDWAREBUFFER_FORMAT_IMPLEMENTATION_DEFINED, - "HAL and AHardwareBuffer pixel format don't match"); - static_assert(HAL_PIXEL_FORMAT_YCBCR_420_888 == AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420, - "HAL and AHardwareBuffer pixel format don't match"); - static_assert(HAL_PIXEL_FORMAT_YCBCR_422_SP == AHARDWAREBUFFER_FORMAT_YCbCr_422_SP, - "HAL and AHardwareBuffer pixel format don't match"); - static_assert(HAL_PIXEL_FORMAT_YCRCB_420_SP == AHARDWAREBUFFER_FORMAT_YCrCb_420_SP, - "HAL and AHardwareBuffer pixel format don't match"); - static_assert(HAL_PIXEL_FORMAT_YCBCR_422_I == AHARDWAREBUFFER_FORMAT_YCbCr_422_I, - "HAL and AHardwareBuffer pixel format don't match"); - static_assert(HAL_PIXEL_FORMAT_YCBCR_P010 == AHARDWAREBUFFER_FORMAT_YCbCr_P010, - "HAL and AHardwareBuffer pixel format don't match"); - static_assert(static_cast<int>(aidl::android::hardware::graphics::common::PixelFormat::R_8) == - AHARDWAREBUFFER_FORMAT_R8_UNORM, - "HAL and AHardwareBuffer pixel format don't match"); - static_assert(static_cast<int>(aidl::android::hardware::graphics::common::PixelFormat::R_16_UINT) == - AHARDWAREBUFFER_FORMAT_R16_UINT, - "HAL and AHardwareBuffer pixel format don't match"); - static_assert(static_cast<int>(aidl::android::hardware::graphics::common::PixelFormat::RG_1616_UINT) == - AHARDWAREBUFFER_FORMAT_R16G16_UINT, - "HAL and AHardwareBuffer pixel format don't match"); - static_assert(static_cast<int>(aidl::android::hardware::graphics::common::PixelFormat::RGBA_10101010) == - AHARDWAREBUFFER_FORMAT_R10G10B10A10_UNORM, - "HAL and AHardwareBuffer pixel format don't match"); - - switch (format) { - case AHARDWAREBUFFER_FORMAT_R8_UNORM: - case AHARDWAREBUFFER_FORMAT_R16_UINT: - case AHARDWAREBUFFER_FORMAT_R16G16_UINT: - case AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM: - case AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM: - case AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM: - case AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM: - case AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT: - case AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM: - case AHARDWAREBUFFER_FORMAT_R10G10B10A10_UNORM: - case AHARDWAREBUFFER_FORMAT_BLOB: - case AHARDWAREBUFFER_FORMAT_D16_UNORM: - case AHARDWAREBUFFER_FORMAT_D24_UNORM: - case AHARDWAREBUFFER_FORMAT_D24_UNORM_S8_UINT: - case AHARDWAREBUFFER_FORMAT_D32_FLOAT: - case AHARDWAREBUFFER_FORMAT_D32_FLOAT_S8_UINT: - case AHARDWAREBUFFER_FORMAT_S8_UINT: - case AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420: - // VNDK formats only -- unfortunately we can't differentiate from where we're called - case AHARDWAREBUFFER_FORMAT_B8G8R8A8_UNORM: - case AHARDWAREBUFFER_FORMAT_YV12: - case AHARDWAREBUFFER_FORMAT_Y8: - case AHARDWAREBUFFER_FORMAT_Y16: - case AHARDWAREBUFFER_FORMAT_RAW16: - case AHARDWAREBUFFER_FORMAT_RAW10: - case AHARDWAREBUFFER_FORMAT_RAW12: - case AHARDWAREBUFFER_FORMAT_RAW_OPAQUE: - case AHARDWAREBUFFER_FORMAT_IMPLEMENTATION_DEFINED: - case AHARDWAREBUFFER_FORMAT_YCbCr_422_SP: - case AHARDWAREBUFFER_FORMAT_YCrCb_420_SP: - case AHARDWAREBUFFER_FORMAT_YCbCr_422_I: - case AHARDWAREBUFFER_FORMAT_YCbCr_P010: - return true; - - default: - return false; - } -} - bool AHardwareBuffer_formatIsYuv(uint32_t format) { switch (format) { case AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420: @@ -681,32 +644,6 @@ bool AHardwareBuffer_formatIsYuv(uint32_t format) { } } -uint32_t AHardwareBuffer_bytesPerPixel(uint32_t format) { - switch (format) { - case AHARDWAREBUFFER_FORMAT_R8_UNORM: - return 1; - case AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM: - case AHARDWAREBUFFER_FORMAT_D16_UNORM: - case AHARDWAREBUFFER_FORMAT_R16_UINT: - return 2; - case AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM: - case AHARDWAREBUFFER_FORMAT_D24_UNORM: - return 3; - case AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM: - case AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM: - case AHARDWAREBUFFER_FORMAT_D32_FLOAT: - case AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM: - case AHARDWAREBUFFER_FORMAT_D24_UNORM_S8_UINT: - case AHARDWAREBUFFER_FORMAT_R16G16_UINT: - return 4; - case AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT: - case AHARDWAREBUFFER_FORMAT_R10G10B10A10_UNORM: - return 8; - default: - return 0; - } -} - uint32_t AHardwareBuffer_convertFromPixelFormat(uint32_t hal_format) { return hal_format; } diff --git a/libs/nativewindow/TEST_MAPPING b/libs/nativewindow/TEST_MAPPING index 3d7f3c28f4..9d6425bfe0 100644 --- a/libs/nativewindow/TEST_MAPPING +++ b/libs/nativewindow/TEST_MAPPING @@ -1,7 +1,13 @@ { "presubmit": [ { + "name": "libnativewindow_bindgen_test" + }, + { "name": "libnativewindow_test" + }, + { + "name": "libnativewindow_rs-internal_test" } ] } diff --git a/libs/nativewindow/include-private/private/android/AHardwareBufferHelpers.h b/libs/nativewindow/include-private/private/android/AHardwareBufferHelpers.h index 6d3d295a0c..880c694934 100644 --- a/libs/nativewindow/include-private/private/android/AHardwareBufferHelpers.h +++ b/libs/nativewindow/include-private/private/android/AHardwareBufferHelpers.h @@ -37,15 +37,9 @@ namespace android { // parameters. Note: this does not verify any platform-specific contraints. bool AHardwareBuffer_isValidDescription(const AHardwareBuffer_Desc* desc, bool log); -// whether this AHardwareBuffer format is valid -bool AHardwareBuffer_isValidPixelFormat(uint32_t ahardwarebuffer_format); - // whether this is a YUV type format bool AHardwareBuffer_formatIsYuv(uint32_t format); -// number of bytes per pixel or 0 if unknown or multi-planar -uint32_t AHardwareBuffer_bytesPerPixel(uint32_t format); - // convert AHardwareBuffer format to HAL format (note: this is a no-op) uint32_t AHardwareBuffer_convertFromPixelFormat(uint32_t format); diff --git a/libs/nativewindow/libnativewindow.map.txt b/libs/nativewindow/libnativewindow.map.txt index c2fd6efcdb..dcb506815c 100644 --- a/libs/nativewindow/libnativewindow.map.txt +++ b/libs/nativewindow/libnativewindow.map.txt @@ -65,7 +65,6 @@ LIBNATIVEWINDOW { LIBNATIVEWINDOW_PLATFORM { global: extern "C++" { - android::AHardwareBuffer_isValidPixelFormat*; android::AHardwareBuffer_convertFromPixelFormat*; android::AHardwareBuffer_convertToPixelFormat*; android::AHardwareBuffer_convertFromGrallocUsageBits*; diff --git a/libs/nativewindow/rust/Android.bp b/libs/nativewindow/rust/Android.bp new file mode 100644 index 0000000000..dc1575ca33 --- /dev/null +++ b/libs/nativewindow/rust/Android.bp @@ -0,0 +1,87 @@ +// Copyright (C) 2023 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package { + default_applicable_licenses: [ + "frameworks_native_libs_nativewindow_license", + ], +} + +rust_bindgen { + name: "libnativewindow_bindgen", + crate_name: "nativewindow_bindgen", + wrapper_src: "sys/nativewindow_bindings.h", + source_stem: "bindings", + bindgen_flags: [ + "--constified-enum-module=AHardwareBuffer_Format", + "--bitfield-enum=AHardwareBuffer_UsageFlags", + + "--allowlist-file=.*/nativewindow/include/.*\\.h", + + "--with-derive-eq", + "--with-derive-partialeq", + ], + shared_libs: [ + "libnativewindow", + ], + + // Currently necessary for host builds + // TODO(b/31559095): bionic on host should define this + target: { + darwin: { + enabled: false, + }, + }, + min_sdk_version: "VanillaIceCream", +} + +rust_test { + name: "libnativewindow_bindgen_test", + srcs: [":libnativewindow_bindgen"], + crate_name: "nativewindow_bindgen_test", + test_suites: ["general-tests"], + auto_gen_config: true, + clippy_lints: "none", + lints: "none", +} + +rust_defaults { + name: "libnativewindow_defaults", + srcs: ["src/lib.rs"], + rustlibs: [ + "libnativewindow_bindgen", + ], +} + +rust_library { + name: "libnativewindow_rs", + crate_name: "nativewindow", + defaults: ["libnativewindow_defaults"], + + // Currently necessary for host builds + // TODO(b/31559095): bionic on host should define this + target: { + darwin: { + enabled: false, + }, + }, + min_sdk_version: "VanillaIceCream", +} + +rust_test { + name: "libnativewindow_rs-internal_test", + crate_name: "nativewindow", + defaults: ["libnativewindow_defaults"], + test_suites: ["general-tests"], +} diff --git a/libs/nativewindow/rust/src/lib.rs b/libs/nativewindow/rust/src/lib.rs new file mode 100644 index 0000000000..a5bcc6293a --- /dev/null +++ b/libs/nativewindow/rust/src/lib.rs @@ -0,0 +1,260 @@ +// Copyright (C) 2023 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Pleasant Rust bindings for libnativewindow, including AHardwareBuffer + +extern crate nativewindow_bindgen as ffi; + +pub use ffi::{AHardwareBuffer_Format, AHardwareBuffer_UsageFlags}; + +use std::os::raw::c_void; +use std::ptr; + +/// Wrapper around an opaque C AHardwareBuffer. +pub struct AHardwareBuffer(*mut ffi::AHardwareBuffer); + +impl AHardwareBuffer { + /// Test whether the given format and usage flag combination is allocatable. If this function + /// returns true, it means that a buffer with the given description can be allocated on this + /// implementation, unless resource exhaustion occurs. If this function returns false, it means + /// that the allocation of the given description will never succeed. + /// + /// Available since API 29 + pub fn is_supported( + width: u32, + height: u32, + layers: u32, + format: AHardwareBuffer_Format::Type, + usage: AHardwareBuffer_UsageFlags, + stride: u32, + ) -> bool { + let buffer_desc = ffi::AHardwareBuffer_Desc { + width, + height, + layers, + format, + usage: usage.0, + stride, + rfu0: 0, + rfu1: 0, + }; + // SAFETY: *buffer_desc will never be null. + let status = unsafe { ffi::AHardwareBuffer_isSupported(&buffer_desc) }; + + status == 1 + } + + /// Allocates a buffer that matches the passed AHardwareBuffer_Desc. If allocation succeeds, the + /// buffer can be used according to the usage flags specified in its description. If a buffer is + /// used in ways not compatible with its usage flags, the results are undefined and may include + /// program termination. + /// + /// Available since API level 26. + pub fn new( + width: u32, + height: u32, + layers: u32, + format: AHardwareBuffer_Format::Type, + usage: AHardwareBuffer_UsageFlags, + ) -> Option<Self> { + let buffer_desc = ffi::AHardwareBuffer_Desc { + width, + height, + layers, + format, + usage: usage.0, + stride: 0, + rfu0: 0, + rfu1: 0, + }; + let mut buffer = ptr::null_mut(); + // SAFETY: The returned pointer is valid until we drop/deallocate it. The function may fail + // and return a status, but we check it later. + let status = unsafe { ffi::AHardwareBuffer_allocate(&buffer_desc, &mut buffer) }; + + if status == 0 { + Some(Self(buffer)) + } else { + None + } + } + + /// Adopts the raw pointer and wraps it in a Rust AHardwareBuffer. + /// + /// # Errors + /// + /// Will panic if buffer_ptr is null. + /// + /// # Safety + /// + /// This function adopts the pointer but does NOT increment the refcount on the buffer. If the + /// caller uses the pointer after the created object is dropped it will cause a memory leak. + pub unsafe fn take_from_raw(buffer_ptr: *mut c_void) -> Self { + assert!(!buffer_ptr.is_null()); + Self(buffer_ptr as *mut ffi::AHardwareBuffer) + } + + /// Get the system wide unique id for an AHardwareBuffer. This function may panic in extreme + /// and undocumented circumstances. + /// + /// Available since API level 31. + pub fn id(&self) -> u64 { + let mut out_id = 0; + // SAFETY: Neither pointers can be null. + let status = unsafe { ffi::AHardwareBuffer_getId(self.0, &mut out_id) }; + assert_eq!(status, 0, "id() failed for AHardwareBuffer with error code: {status}"); + + out_id + } + + /// Get the width of this buffer + pub fn width(&self) -> u32 { + self.description().width + } + + /// Get the height of this buffer + pub fn height(&self) -> u32 { + self.description().height + } + + /// Get the number of layers of this buffer + pub fn layers(&self) -> u32 { + self.description().layers + } + + /// Get the format of this buffer + pub fn format(&self) -> AHardwareBuffer_Format::Type { + self.description().format + } + + /// Get the usage bitvector of this buffer + pub fn usage(&self) -> AHardwareBuffer_UsageFlags { + AHardwareBuffer_UsageFlags(self.description().usage) + } + + /// Get the stride of this buffer + pub fn stride(&self) -> u32 { + self.description().stride + } + + fn description(&self) -> ffi::AHardwareBuffer_Desc { + let mut buffer_desc = ffi::AHardwareBuffer_Desc { + width: 0, + height: 0, + layers: 0, + format: 0, + usage: 0, + stride: 0, + rfu0: 0, + rfu1: 0, + }; + // SAFETY: neither the buffer nor AHardwareBuffer_Desc pointers will be null. + unsafe { ffi::AHardwareBuffer_describe(self.0, &mut buffer_desc) }; + buffer_desc + } +} + +impl Drop for AHardwareBuffer { + fn drop(&mut self) { + // SAFETY: self.0 will never be null. AHardwareBuffers allocated from within Rust will have + // a refcount of one, and there is a safety warning on taking an AHardwareBuffer from a raw + // pointer requiring callers to ensure the refcount is managed appropriately. + unsafe { ffi::AHardwareBuffer_release(self.0) } + } +} + +#[cfg(test)] +mod ahardwarebuffer_tests { + use super::*; + + #[test] + fn create_valid_buffer_returns_ok() { + let buffer = AHardwareBuffer::new( + 512, + 512, + 1, + AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, + AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN, + ); + assert!(buffer.is_some()); + } + + #[test] + fn create_invalid_buffer_returns_err() { + let buffer = AHardwareBuffer::new(512, 512, 1, 0, AHardwareBuffer_UsageFlags(0)); + assert!(buffer.is_none()); + } + + #[test] + #[should_panic] + fn take_from_raw_panics_on_null() { + unsafe { AHardwareBuffer::take_from_raw(ptr::null_mut()) }; + } + + #[test] + fn take_from_raw_allows_getters() { + let buffer_desc = ffi::AHardwareBuffer_Desc { + width: 1024, + height: 512, + layers: 1, + format: AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, + usage: AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN.0, + stride: 0, + rfu0: 0, + rfu1: 0, + }; + let mut raw_buffer_ptr = ptr::null_mut(); + + let status = unsafe { ffi::AHardwareBuffer_allocate(&buffer_desc, &mut raw_buffer_ptr) }; + assert_eq!(status, 0); + + let buffer = unsafe { AHardwareBuffer::take_from_raw(raw_buffer_ptr as *mut c_void) }; + assert_eq!(buffer.width(), 1024); + } + + #[test] + fn basic_getters() { + let buffer = AHardwareBuffer::new( + 1024, + 512, + 1, + AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, + AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN, + ) + .expect("Buffer with some basic parameters was not created successfully"); + + assert_eq!(buffer.width(), 1024); + assert_eq!(buffer.height(), 512); + assert_eq!(buffer.layers(), 1); + assert_eq!(buffer.format(), AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM); + assert_eq!( + buffer.usage(), + AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN + ); + } + + #[test] + fn id_getter() { + let buffer = AHardwareBuffer::new( + 1024, + 512, + 1, + AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, + AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN, + ) + .expect("Buffer with some basic parameters was not created successfully"); + + assert_ne!(0, buffer.id()); + } +} diff --git a/libs/nativewindow/rust/sys/nativewindow_bindings.h b/libs/nativewindow/rust/sys/nativewindow_bindings.h new file mode 100644 index 0000000000..e652aee711 --- /dev/null +++ b/libs/nativewindow/rust/sys/nativewindow_bindings.h @@ -0,0 +1,20 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <android/data_space.h> +#include <android/hardware_buffer.h> +#include <android/hdr_metadata.h> +#include <android/native_window.h> diff --git a/libs/permission/aidl/android/content/AttributionSourceState.aidl b/libs/permission/aidl/android/content/AttributionSourceState.aidl index ed1b37dc0b..b3fb7a7719 100644 --- a/libs/permission/aidl/android/content/AttributionSourceState.aidl +++ b/libs/permission/aidl/android/content/AttributionSourceState.aidl @@ -27,6 +27,10 @@ parcelable AttributionSourceState { int pid = -1; /** The UID that is accessing the permission protected data. */ int uid = -1; + /** The default device ID from where the permission protected data is read. + * @see Context#DEVICE_ID_DEFAULT + */ + int deviceId = 0; /** The package that is accessing the permission protected data. */ @nullable @utf8InCpp String packageName; /** The attribution tag of the app accessing the permission protected data. */ diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 7611d681a6..619ecdc773 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -119,6 +119,10 @@ inline nsecs_t now() { return systemTime(SYSTEM_TIME_MONOTONIC); } +bool isEmpty(const std::stringstream& ss) { + return ss.rdbuf()->in_avail() == 0; +} + inline const std::string binderToString(const sp<IBinder>& binder) { if (binder == nullptr) { return "<null>"; @@ -130,11 +134,6 @@ static std::string uidString(const gui::Uid& uid) { return uid.toString(); } -inline int32_t getMotionEventActionPointerIndex(int32_t action) { - return (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> - AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; -} - Result<void> checkKeyAction(int32_t action) { switch (action) { case AKEY_EVENT_ACTION_DOWN: @@ -602,7 +601,7 @@ std::pair<float, float> resolveTouchedPosition(const MotionEntry& entry) { return {entry.xCursorPosition, entry.yCursorPosition}; } - const int32_t pointerIndex = getMotionEventActionPointerIndex(entry.action); + const int32_t pointerIndex = MotionEvent::getActionIndex(entry.action); return {entry.pointerCoords[pointerIndex].getAxisValue(AMOTION_EVENT_AXIS_X), entry.pointerCoords[pointerIndex].getAxisValue(AMOTION_EVENT_AXIS_Y)}; } @@ -2305,7 +2304,7 @@ std::vector<InputTarget> InputDispatcher::findTouchedWindowTargetsLocked( if (newGesture || (isSplit && maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN)) { /* Case 1: New splittable pointer going down, or need target for hover or scroll. */ const auto [x, y] = resolveTouchedPosition(entry); - const int32_t pointerIndex = getMotionEventActionPointerIndex(action); + const int32_t pointerIndex = MotionEvent::getActionIndex(action); // Outside targets should be added upon first dispatched DOWN event. That means, this should // be a pointer that would generate ACTION_DOWN, *and* touch should not already be down. const bool isStylus = isPointerFromStylus(entry, pointerIndex); @@ -2338,6 +2337,8 @@ std::vector<InputTarget> InputDispatcher::findTouchedWindowTargetsLocked( } else if (isSplit) { // New window does not support splitting but we have already split events. // Ignore the new window. + LOG(INFO) << "Skipping " << newTouchedWindowHandle->getName() + << " because it doesn't support split touch"; newTouchedWindowHandle = nullptr; } } else { @@ -2552,15 +2553,16 @@ std::vector<InputTarget> InputDispatcher::findTouchedWindowTargetsLocked( // Update the pointerIds for non-splittable when it received pointer down. if (!isSplit && maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN) { // If no split, we suppose all touched windows should receive pointer down. - const int32_t pointerIndex = getMotionEventActionPointerIndex(action); + const int32_t pointerIndex = MotionEvent::getActionIndex(action); for (size_t i = 0; i < tempTouchState.windows.size(); i++) { TouchedWindow& touchedWindow = tempTouchState.windows[i]; // Ignore drag window for it should just track one pointer. if (mDragState && mDragState->dragWindow == touchedWindow.windowHandle) { continue; } - touchedWindow.addTouchingPointer(entry.deviceId, - entry.pointerProperties[pointerIndex].id); + std::bitset<MAX_POINTER_ID + 1> touchingPointers; + touchingPointers.set(entry.pointerProperties[pointerIndex].id); + touchedWindow.addTouchingPointers(entry.deviceId, touchingPointers); } } } @@ -2704,18 +2706,9 @@ std::vector<InputTarget> InputDispatcher::findTouchedWindowTargetsLocked( } } else if (maskedAction == AMOTION_EVENT_ACTION_POINTER_UP) { // One pointer went up. - int32_t pointerIndex = getMotionEventActionPointerIndex(action); - uint32_t pointerId = entry.pointerProperties[pointerIndex].id; - - for (size_t i = 0; i < tempTouchState.windows.size();) { - TouchedWindow& touchedWindow = tempTouchState.windows[i]; - touchedWindow.removeTouchingPointer(entry.deviceId, pointerId); - if (!touchedWindow.hasTouchingPointers(entry.deviceId)) { - tempTouchState.windows.erase(tempTouchState.windows.begin() + i); - continue; - } - i += 1; - } + const int32_t pointerIndex = MotionEvent::getActionIndex(action); + const uint32_t pointerId = entry.pointerProperties[pointerIndex].id; + tempTouchState.removeTouchingPointer(entry.deviceId, pointerId); } // Save changes unless the action was scroll in which case the temporary touch @@ -2814,7 +2807,7 @@ void InputDispatcher::addDragEventLocked(const MotionEntry& entry) { } case AMOTION_EVENT_ACTION_POINTER_UP: - if (getMotionEventActionPointerIndex(entry.action) != pointerIndex) { + if (MotionEvent::getActionIndex(entry.action) != pointerIndex) { break; } // The drag pointer is up. @@ -4108,7 +4101,7 @@ std::unique_ptr<MotionEntry> InputDispatcher::splitMotionEvent( int32_t maskedAction = action & AMOTION_EVENT_ACTION_MASK; if (maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN || maskedAction == AMOTION_EVENT_ACTION_POINTER_UP) { - int32_t originalPointerIndex = getMotionEventActionPointerIndex(action); + int32_t originalPointerIndex = MotionEvent::getActionIndex(action); const PointerProperties& pointerProperties = originalMotionEntry.pointerProperties[originalPointerIndex]; uint32_t pointerId = uint32_t(pointerProperties.id); @@ -5777,6 +5770,12 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) const { } else { dump += INDENT3 "WaitQueue: <empty>\n"; } + std::stringstream inputStateDump; + inputStateDump << connection->inputState; + if (!isEmpty(inputStateDump)) { + dump += INDENT3 "InputState: "; + dump += inputStateDump.str() + "\n"; + } } } else { dump += INDENT "Connections: <none>\n"; diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h index cb87067ec2..909c683d1b 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.h +++ b/services/inputflinger/dispatcher/InputDispatcher.h @@ -25,7 +25,6 @@ #include "InputDispatcherConfiguration.h" #include "InputDispatcherInterface.h" #include "InputDispatcherPolicyInterface.h" -#include "InputState.h" #include "InputTarget.h" #include "InputThread.h" #include "LatencyAggregator.h" diff --git a/services/inputflinger/dispatcher/InputState.cpp b/services/inputflinger/dispatcher/InputState.cpp index e6941ef027..ccffe26d57 100644 --- a/services/inputflinger/dispatcher/InputState.cpp +++ b/services/inputflinger/dispatcher/InputState.cpp @@ -525,4 +525,14 @@ bool InputState::shouldCancelMotion(const MotionMemento& memento, } } +std::ostream& operator<<(std::ostream& out, const InputState& state) { + if (!state.mMotionMementos.empty()) { + out << "mMotionMementos: "; + for (const InputState::MotionMemento& memento : state.mMotionMementos) { + out << "{deviceId= " << memento.deviceId << ", hovering=" << memento.hovering << "}, "; + } + } + return out; +} + } // namespace android::inputdispatcher diff --git a/services/inputflinger/dispatcher/InputState.h b/services/inputflinger/dispatcher/InputState.h index e741137103..32df034f67 100644 --- a/services/inputflinger/dispatcher/InputState.h +++ b/services/inputflinger/dispatcher/InputState.h @@ -128,7 +128,10 @@ private: std::vector<std::unique_ptr<MotionEntry>> synthesizeCancelationEventsForPointers( const MotionMemento& memento, std::bitset<MAX_POINTER_ID + 1> pointerIds, nsecs_t currentTime); + friend std::ostream& operator<<(std::ostream& out, const InputState& state); }; +std::ostream& operator<<(std::ostream& out, const InputState& state); + } // namespace inputdispatcher } // namespace android diff --git a/services/inputflinger/dispatcher/InputTarget.cpp b/services/inputflinger/dispatcher/InputTarget.cpp index fc8b785aa5..11f3413df8 100644 --- a/services/inputflinger/dispatcher/InputTarget.cpp +++ b/services/inputflinger/dispatcher/InputTarget.cpp @@ -76,4 +76,24 @@ std::string InputTarget::getPointerInfoString() const { } return out; } + +std::ostream& operator<<(std::ostream& out, const InputTarget& target) { + out << "{inputChannel="; + if (target.inputChannel != nullptr) { + out << target.inputChannel->getName(); + } else { + out << "<null>"; + } + out << ", windowHandle="; + if (target.windowHandle != nullptr) { + out << target.windowHandle->getName(); + } else { + out << "<null>"; + } + out << ", targetFlags=" << target.flags.string(); + out << ", pointers=" << target.getPointerInfoString(); + out << "}"; + return out; +} + } // namespace android::inputdispatcher diff --git a/services/inputflinger/dispatcher/InputTarget.h b/services/inputflinger/dispatcher/InputTarget.h index 3bf8b68f0e..8b8a35aea8 100644 --- a/services/inputflinger/dispatcher/InputTarget.h +++ b/services/inputflinger/dispatcher/InputTarget.h @@ -139,6 +139,6 @@ struct InputTarget { std::string getPointerInfoString() const; }; -std::string dispatchModeToString(int32_t dispatchMode); +std::ostream& operator<<(std::ostream& out, const InputTarget& target); } // namespace android::inputdispatcher diff --git a/services/inputflinger/dispatcher/TouchState.h b/services/inputflinger/dispatcher/TouchState.h index 25b9643528..39e63e5894 100644 --- a/services/inputflinger/dispatcher/TouchState.h +++ b/services/inputflinger/dispatcher/TouchState.h @@ -38,9 +38,9 @@ struct TouchState { void reset(); void clearWindowsWithoutPointers(); - std::set<int32_t> getActiveDeviceIds() const; + std::set<DeviceId> getActiveDeviceIds() const; - bool hasTouchingPointers(int32_t device) const; + bool hasTouchingPointers(DeviceId deviceId) const; void removeTouchingPointer(DeviceId deviceId, int32_t pointerId); void removeTouchingPointerFromWindow(DeviceId deviceId, int32_t pointerId, const sp<android::gui::WindowInfoHandle>& windowHandle); diff --git a/services/inputflinger/dispatcher/TouchedWindow.cpp b/services/inputflinger/dispatcher/TouchedWindow.cpp index ae165209bd..9807a6da9b 100644 --- a/services/inputflinger/dispatcher/TouchedWindow.cpp +++ b/services/inputflinger/dispatcher/TouchedWindow.cpp @@ -35,7 +35,7 @@ bool TouchedWindow::hasHoveringPointers() const { return false; } -bool TouchedWindow::hasHoveringPointers(int32_t deviceId) const { +bool TouchedWindow::hasHoveringPointers(DeviceId deviceId) const { const auto stateIt = mDeviceStates.find(deviceId); if (stateIt == mDeviceStates.end()) { return false; @@ -53,7 +53,7 @@ void TouchedWindow::clearHoveringPointers() { std::erase_if(mDeviceStates, [](const auto& pair) { return !pair.second.hasPointers(); }); } -bool TouchedWindow::hasHoveringPointer(int32_t deviceId, int32_t pointerId) const { +bool TouchedWindow::hasHoveringPointer(DeviceId deviceId, int32_t pointerId) const { const auto stateIt = mDeviceStates.find(deviceId); if (stateIt == mDeviceStates.end()) { return false; @@ -63,15 +63,11 @@ bool TouchedWindow::hasHoveringPointer(int32_t deviceId, int32_t pointerId) cons return state.hoveringPointerIds.test(pointerId); } -void TouchedWindow::addHoveringPointer(int32_t deviceId, int32_t pointerId) { +void TouchedWindow::addHoveringPointer(DeviceId deviceId, int32_t pointerId) { mDeviceStates[deviceId].hoveringPointerIds.set(pointerId); } -void TouchedWindow::addTouchingPointer(int32_t deviceId, int32_t pointerId) { - mDeviceStates[deviceId].touchingPointerIds.set(pointerId); -} - -void TouchedWindow::addTouchingPointers(int32_t deviceId, +void TouchedWindow::addTouchingPointers(DeviceId deviceId, std::bitset<MAX_POINTER_ID + 1> pointers) { mDeviceStates[deviceId].touchingPointerIds |= pointers; } @@ -85,15 +81,15 @@ bool TouchedWindow::hasTouchingPointers() const { return false; } -bool TouchedWindow::hasTouchingPointers(int32_t deviceId) const { +bool TouchedWindow::hasTouchingPointers(DeviceId deviceId) const { return getTouchingPointers(deviceId).any(); } -bool TouchedWindow::hasTouchingPointer(int32_t deviceId, int32_t pointerId) const { +bool TouchedWindow::hasTouchingPointer(DeviceId deviceId, int32_t pointerId) const { return getTouchingPointers(deviceId).test(pointerId); } -std::bitset<MAX_POINTER_ID + 1> TouchedWindow::getTouchingPointers(int32_t deviceId) const { +std::bitset<MAX_POINTER_ID + 1> TouchedWindow::getTouchingPointers(DeviceId deviceId) const { const auto stateIt = mDeviceStates.find(deviceId); if (stateIt == mDeviceStates.end()) { return {}; @@ -103,14 +99,14 @@ std::bitset<MAX_POINTER_ID + 1> TouchedWindow::getTouchingPointers(int32_t devic return state.touchingPointerIds; } -void TouchedWindow::removeTouchingPointer(int32_t deviceId, int32_t pointerId) { +void TouchedWindow::removeTouchingPointer(DeviceId deviceId, int32_t pointerId) { std::bitset<MAX_POINTER_ID + 1> pointerIds; pointerIds.set(pointerId, true); removeTouchingPointers(deviceId, pointerIds); } -void TouchedWindow::removeTouchingPointers(int32_t deviceId, +void TouchedWindow::removeTouchingPointers(DeviceId deviceId, std::bitset<MAX_POINTER_ID + 1> pointers) { const auto stateIt = mDeviceStates.find(deviceId); if (stateIt == mDeviceStates.end()) { @@ -126,23 +122,23 @@ void TouchedWindow::removeTouchingPointers(int32_t deviceId, } } -std::set<int32_t> TouchedWindow::getTouchingDeviceIds() const { - std::set<int32_t> deviceIds; +std::set<DeviceId> TouchedWindow::getTouchingDeviceIds() const { + std::set<DeviceId> deviceIds; for (const auto& [deviceId, _] : mDeviceStates) { deviceIds.insert(deviceId); } return deviceIds; } -std::set<int32_t> TouchedWindow::getActiveDeviceIds() const { - std::set<int32_t> out; +std::set<DeviceId> TouchedWindow::getActiveDeviceIds() const { + std::set<DeviceId> out; for (const auto& [deviceId, _] : mDeviceStates) { out.emplace(deviceId); } return out; } -bool TouchedWindow::hasPilferingPointers(int32_t deviceId) const { +bool TouchedWindow::hasPilferingPointers(DeviceId deviceId) const { const auto stateIt = mDeviceStates.find(deviceId); if (stateIt == mDeviceStates.end()) { return false; @@ -152,16 +148,16 @@ bool TouchedWindow::hasPilferingPointers(int32_t deviceId) const { return state.pilferingPointerIds.any(); } -void TouchedWindow::addPilferingPointers(int32_t deviceId, +void TouchedWindow::addPilferingPointers(DeviceId deviceId, std::bitset<MAX_POINTER_ID + 1> pointerIds) { mDeviceStates[deviceId].pilferingPointerIds |= pointerIds; } -void TouchedWindow::addPilferingPointer(int32_t deviceId, int32_t pointerId) { +void TouchedWindow::addPilferingPointer(DeviceId deviceId, int32_t pointerId) { mDeviceStates[deviceId].pilferingPointerIds.set(pointerId); } -std::bitset<MAX_POINTER_ID + 1> TouchedWindow::getPilferingPointers(int32_t deviceId) const { +std::bitset<MAX_POINTER_ID + 1> TouchedWindow::getPilferingPointers(DeviceId deviceId) const { const auto stateIt = mDeviceStates.find(deviceId); if (stateIt == mDeviceStates.end()) { return {}; @@ -171,15 +167,15 @@ std::bitset<MAX_POINTER_ID + 1> TouchedWindow::getPilferingPointers(int32_t devi return state.pilferingPointerIds; } -std::map<int32_t, std::bitset<MAX_POINTER_ID + 1>> TouchedWindow::getPilferingPointers() const { - std::map<int32_t, std::bitset<MAX_POINTER_ID + 1>> out; +std::map<DeviceId, std::bitset<MAX_POINTER_ID + 1>> TouchedWindow::getPilferingPointers() const { + std::map<DeviceId, std::bitset<MAX_POINTER_ID + 1>> out; for (const auto& [deviceId, state] : mDeviceStates) { out.emplace(deviceId, state.pilferingPointerIds); } return out; } -std::optional<nsecs_t> TouchedWindow::getDownTimeInTarget(int32_t deviceId) const { +std::optional<nsecs_t> TouchedWindow::getDownTimeInTarget(DeviceId deviceId) const { const auto stateIt = mDeviceStates.find(deviceId); if (stateIt == mDeviceStates.end()) { return {}; @@ -188,7 +184,7 @@ std::optional<nsecs_t> TouchedWindow::getDownTimeInTarget(int32_t deviceId) cons return state.downTimeInTarget; } -void TouchedWindow::trySetDownTimeInTarget(int32_t deviceId, nsecs_t downTime) { +void TouchedWindow::trySetDownTimeInTarget(DeviceId deviceId, nsecs_t downTime) { auto [stateIt, _] = mDeviceStates.try_emplace(deviceId); DeviceState& state = stateIt->second; @@ -197,7 +193,7 @@ void TouchedWindow::trySetDownTimeInTarget(int32_t deviceId, nsecs_t downTime) { } } -void TouchedWindow::removeAllTouchingPointersForDevice(int32_t deviceId) { +void TouchedWindow::removeAllTouchingPointersForDevice(DeviceId deviceId) { const auto stateIt = mDeviceStates.find(deviceId); if (stateIt == mDeviceStates.end()) { return; @@ -213,7 +209,7 @@ void TouchedWindow::removeAllTouchingPointersForDevice(int32_t deviceId) { } } -void TouchedWindow::removeHoveringPointer(int32_t deviceId, int32_t pointerId) { +void TouchedWindow::removeHoveringPointer(DeviceId deviceId, int32_t pointerId) { const auto stateIt = mDeviceStates.find(deviceId); if (stateIt == mDeviceStates.end()) { return; @@ -227,7 +223,7 @@ void TouchedWindow::removeHoveringPointer(int32_t deviceId, int32_t pointerId) { } } -void TouchedWindow::removeAllHoveringPointersForDevice(int32_t deviceId) { +void TouchedWindow::removeAllHoveringPointersForDevice(DeviceId deviceId) { const auto stateIt = mDeviceStates.find(deviceId); if (stateIt == mDeviceStates.end()) { return; diff --git a/services/inputflinger/dispatcher/TouchedWindow.h b/services/inputflinger/dispatcher/TouchedWindow.h index 81393fc2fc..0a38f9f5cd 100644 --- a/services/inputflinger/dispatcher/TouchedWindow.h +++ b/services/inputflinger/dispatcher/TouchedWindow.h @@ -34,43 +34,42 @@ struct TouchedWindow { // Hovering bool hasHoveringPointers() const; - bool hasHoveringPointers(int32_t deviceId) const; - bool hasHoveringPointer(int32_t deviceId, int32_t pointerId) const; - void addHoveringPointer(int32_t deviceId, int32_t pointerId); - void removeHoveringPointer(int32_t deviceId, int32_t pointerId); + bool hasHoveringPointers(DeviceId deviceId) const; + bool hasHoveringPointer(DeviceId deviceId, int32_t pointerId) const; + void addHoveringPointer(DeviceId deviceId, int32_t pointerId); + void removeHoveringPointer(DeviceId deviceId, int32_t pointerId); // Touching - bool hasTouchingPointer(int32_t deviceId, int32_t pointerId) const; + bool hasTouchingPointer(DeviceId deviceId, int32_t pointerId) const; bool hasTouchingPointers() const; - bool hasTouchingPointers(int32_t deviceId) const; - std::bitset<MAX_POINTER_ID + 1> getTouchingPointers(int32_t deviceId) const; - void addTouchingPointer(int32_t deviceId, int32_t pointerId); - void addTouchingPointers(int32_t deviceId, std::bitset<MAX_POINTER_ID + 1> pointers); - void removeTouchingPointer(int32_t deviceId, int32_t pointerId); - void removeTouchingPointers(int32_t deviceId, std::bitset<MAX_POINTER_ID + 1> pointers); + bool hasTouchingPointers(DeviceId deviceId) const; + std::bitset<MAX_POINTER_ID + 1> getTouchingPointers(DeviceId deviceId) const; + void addTouchingPointers(DeviceId deviceId, std::bitset<MAX_POINTER_ID + 1> pointers); + void removeTouchingPointer(DeviceId deviceId, int32_t pointerId); + void removeTouchingPointers(DeviceId deviceId, std::bitset<MAX_POINTER_ID + 1> pointers); /** * Get the currently active touching device id. If there isn't exactly 1 touching device, return * nullopt. */ - std::set<int32_t> getTouchingDeviceIds() const; + std::set<DeviceId> getTouchingDeviceIds() const; /** * The ids of devices that are currently touching or hovering. */ - std::set<int32_t> getActiveDeviceIds() const; + std::set<DeviceId> getActiveDeviceIds() const; // Pilfering pointers - bool hasPilferingPointers(int32_t deviceId) const; - void addPilferingPointers(int32_t deviceId, std::bitset<MAX_POINTER_ID + 1> pointerIds); - void addPilferingPointer(int32_t deviceId, int32_t pointerId); - std::bitset<MAX_POINTER_ID + 1> getPilferingPointers(int32_t deviceId) const; - std::map<int32_t, std::bitset<MAX_POINTER_ID + 1>> getPilferingPointers() const; + bool hasPilferingPointers(DeviceId deviceId) const; + void addPilferingPointers(DeviceId deviceId, std::bitset<MAX_POINTER_ID + 1> pointerIds); + void addPilferingPointer(DeviceId deviceId, int32_t pointerId); + std::bitset<MAX_POINTER_ID + 1> getPilferingPointers(DeviceId deviceId) const; + std::map<DeviceId, std::bitset<MAX_POINTER_ID + 1>> getPilferingPointers() const; // Down time - std::optional<nsecs_t> getDownTimeInTarget(int32_t deviceId) const; - void trySetDownTimeInTarget(int32_t deviceId, nsecs_t downTime); + std::optional<nsecs_t> getDownTimeInTarget(DeviceId deviceId) const; + void trySetDownTimeInTarget(DeviceId deviceId, nsecs_t downTime); - void removeAllTouchingPointersForDevice(int32_t deviceId); - void removeAllHoveringPointersForDevice(int32_t deviceId); + void removeAllTouchingPointersForDevice(DeviceId deviceId); + void removeAllHoveringPointersForDevice(DeviceId deviceId); void clearHoveringPointers(); std::string dump() const; @@ -88,7 +87,7 @@ private: bool hasPointers() const { return touchingPointerIds.any() || hoveringPointerIds.any(); }; }; - std::map<int32_t /*deviceId*/, DeviceState> mDeviceStates; + std::map<DeviceId, DeviceState> mDeviceStates; static std::string deviceStateToString(const TouchedWindow::DeviceState& state); }; diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index d367cd71f0..70516808f4 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -2386,7 +2386,6 @@ TEST_F(InputDispatcherTest, MultiDeviceSplitTouch) { const int32_t touchDeviceId = 4; const int32_t mouseDeviceId = 6; - NotifyMotionArgs args; // Start hovering over the left window mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE) @@ -2462,7 +2461,6 @@ TEST_F(InputDispatcherTest, MixedTouchAndMouseWithPointerDown) { const int32_t touchDeviceId = 4; const int32_t mouseDeviceId = 6; - NotifyMotionArgs args; // First touch pointer down mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) @@ -2528,7 +2526,6 @@ TEST_F(InputDispatcherTest, UnfinishedInjectedEvent) { mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); const int32_t touchDeviceId = 4; - NotifyMotionArgs args; // Pretend a test injects an ACTION_DOWN mouse event, but forgets to lift up the touch after // completion. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, @@ -2696,9 +2693,7 @@ TEST_F(InputDispatcherTest, StylusHoverAndTouchTap) { MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS) .deviceId(stylusDeviceId) - .pointer(PointerBuilder(0, ToolType::STYLUS) - .x(50) - .y(50)) + .pointer(PointerBuilder(0, ToolType::STYLUS).x(60).y(60)) .build())); // No event should be sent. This event should be ignored because a pointer from another device // is already down. @@ -2721,9 +2716,7 @@ TEST_F(InputDispatcherTest, StylusHoverAndTouchTap) { MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS) .deviceId(stylusDeviceId) - .pointer(PointerBuilder(0, ToolType::STYLUS) - .x(50) - .y(50)) + .pointer(PointerBuilder(0, ToolType::STYLUS).x(70).y(70)) .build())); window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER)); // No more events @@ -3808,6 +3801,44 @@ TEST_F(InputDispatcherTest, NonSplitTouchableWindowReceivesMultiTouch) { EXPECT_EQ(-10, event->getY(1)); // -50 + 40 } +/** + * Two windows: a splittable and a non-splittable. + * The non-splittable window shouldn't receive any "incomplete" gestures. + * Send the first pointer to the splittable window, and then touch the non-splittable window. + * The second pointer should be dropped because the initial window is splittable, so it won't get + * any pointers outside of it, and the second window is non-splittable, so it shouldn't get any + * "incomplete" gestures. + */ +TEST_F(InputDispatcherTest, SplittableAndNonSplittableWindows) { + std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); + sp<FakeWindowHandle> leftWindow = + sp<FakeWindowHandle>::make(application, mDispatcher, "Left splittable Window", + ADISPLAY_ID_DEFAULT); + leftWindow->setPreventSplitting(false); + leftWindow->setFrame(Rect(0, 0, 100, 100)); + sp<FakeWindowHandle> rightWindow = + sp<FakeWindowHandle>::make(application, mDispatcher, "Right non-splittable Window", + ADISPLAY_ID_DEFAULT); + rightWindow->setPreventSplitting(true); + rightWindow->setFrame(Rect(100, 100, 200, 200)); + mDispatcher->onWindowInfosChanged( + {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0}); + + // Touch down on left, splittable window + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50)) + .build()); + leftWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); + + mDispatcher->notifyMotion( + MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50)) + .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(150)) + .build()); + leftWindow->assertNoEvents(); + rightWindow->assertNoEvents(); +} + TEST_F(InputDispatcherTest, TouchpadThreeFingerSwipeOnlySentToTrustedOverlays) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); sp<FakeWindowHandle> window = @@ -8984,6 +9015,7 @@ using InputDispatcherSpyWindowDeathTest = InputDispatcherSpyWindowTest; * Adding a spy window that is not a trusted overlay causes Dispatcher to abort. */ TEST_F(InputDispatcherSpyWindowDeathTest, UntrustedSpy_AbortsDispatcher) { + testing::GTEST_FLAG(death_test_style) = "threadsafe"; ScopedSilentDeath _silentDeath; auto spy = createSpy(); diff --git a/services/inputflinger/tests/fuzzers/CursorInputFuzzer.cpp b/services/inputflinger/tests/fuzzers/CursorInputFuzzer.cpp index e93b5929c7..af20a271b8 100644 --- a/services/inputflinger/tests/fuzzers/CursorInputFuzzer.cpp +++ b/services/inputflinger/tests/fuzzers/CursorInputFuzzer.cpp @@ -15,38 +15,47 @@ */ #include <CursorInputMapper.h> -#include <FuzzContainer.h> +#include <InputDevice.h> #include <InputReaderBase.h> #include <MapperHelpers.h> namespace android { -static void addProperty(FuzzContainer& fuzzer, std::shared_ptr<ThreadSafeFuzzedDataProvider> fdp) { +static void addProperty(FuzzEventHub& eventHub, std::shared_ptr<ThreadSafeFuzzedDataProvider> fdp) { // Pick a random property to set for the mapper to have set. fdp->PickValueInArray<std::function<void()>>( - {[&]() -> void { fuzzer.addProperty("cursor.mode", "pointer"); }, - [&]() -> void { fuzzer.addProperty("cursor.mode", "navigation"); }, + {[&]() -> void { eventHub.addProperty("cursor.mode", "pointer"); }, + [&]() -> void { eventHub.addProperty("cursor.mode", "navigation"); }, [&]() -> void { - fuzzer.addProperty("cursor.mode", fdp->ConsumeRandomLengthString(100).data()); + eventHub.addProperty("cursor.mode", fdp->ConsumeRandomLengthString(100).data()); }, [&]() -> void { - fuzzer.addProperty("cursor.orientationAware", - fdp->ConsumeRandomLengthString(100).data()); + eventHub.addProperty("cursor.orientationAware", + fdp->ConsumeRandomLengthString(100).data()); }})(); } extern "C" int LLVMFuzzerTestOneInput(uint8_t* data, size_t size) { std::shared_ptr<ThreadSafeFuzzedDataProvider> fdp = std::make_shared<ThreadSafeFuzzedDataProvider>(data, size); - FuzzContainer fuzzer(fdp); + + // Create mocked objects to support the fuzzed input mapper. + std::shared_ptr<FuzzEventHub> eventHub = std::make_shared<FuzzEventHub>(fdp); + FuzzInputReaderContext context(eventHub, fdp); + InputDevice device = getFuzzedInputDevice(*fdp, &context); InputReaderConfiguration policyConfig; - CursorInputMapper& mapper = fuzzer.getMapper<CursorInputMapper>(policyConfig); + CursorInputMapper& mapper = + getMapperForDevice<ThreadSafeFuzzedDataProvider, CursorInputMapper>(*fdp.get(), device, + policyConfig); // Loop through mapper operations until randomness is exhausted. while (fdp->remaining_bytes() > 0) { fdp->PickValueInArray<std::function<void()>>({ - [&]() -> void { addProperty(fuzzer, fdp); }, + [&]() -> void { + addProperty(*eventHub.get(), fdp); + configureAndResetDevice(*fdp, device); + }, [&]() -> void { std::string dump; mapper.dump(dump); diff --git a/services/inputflinger/tests/fuzzers/FuzzContainer.h b/services/inputflinger/tests/fuzzers/FuzzContainer.h deleted file mode 100644 index ade53281a6..0000000000 --- a/services/inputflinger/tests/fuzzers/FuzzContainer.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include <InputDevice.h> -#include <InputMapper.h> -#include <InputReader.h> -#include <MapperHelpers.h> - -namespace android { - -class FuzzContainer { - std::shared_ptr<FuzzEventHub> mFuzzEventHub; - FuzzInputListener mFuzzListener; - std::unique_ptr<FuzzInputReaderContext> mFuzzContext; - std::unique_ptr<InputDevice> mFuzzDevice; - std::shared_ptr<ThreadSafeFuzzedDataProvider> mFdp; - -public: - FuzzContainer(std::shared_ptr<ThreadSafeFuzzedDataProvider> fdp) : mFdp(fdp) { - // Setup parameters. - std::string deviceName = mFdp->ConsumeRandomLengthString(16); - std::string deviceLocation = mFdp->ConsumeRandomLengthString(12); - int32_t deviceID = mFdp->ConsumeIntegralInRange<int32_t>(0, 5); - int32_t deviceGeneration = mFdp->ConsumeIntegralInRange<int32_t>(/*from=*/0, /*to=*/5); - - // Create mocked objects. - mFuzzEventHub = std::make_shared<FuzzEventHub>(mFdp); - sp<FuzzInputReaderPolicy> policy = sp<FuzzInputReaderPolicy>::make(mFdp); - mFuzzContext = std::make_unique<FuzzInputReaderContext>(mFuzzEventHub, policy, - mFuzzListener, mFdp); - - InputDeviceIdentifier identifier; - identifier.name = deviceName; - identifier.location = deviceLocation; - mFuzzDevice = std::make_unique<InputDevice>(mFuzzContext.get(), deviceID, deviceGeneration, - identifier); - } - - ~FuzzContainer() {} - - void configureDevice() { - nsecs_t arbitraryTime = mFdp->ConsumeIntegral<nsecs_t>(); - std::list<NotifyArgs> out; - out += mFuzzDevice->configure(arbitraryTime, /*readerConfig=*/{}, /*changes=*/{}); - out += mFuzzDevice->reset(arbitraryTime); - for (const NotifyArgs& args : out) { - mFuzzListener.notify(args); - } - } - - void addProperty(std::string key, std::string value) { - mFuzzEventHub->addProperty(key, value); - configureDevice(); - } - - void setAbsoluteAxisInfo(int axis, const RawAbsoluteAxisInfo& axisInfo) { - mFuzzEventHub->setAbsoluteAxisInfo(mFuzzDevice->getId(), axis, axisInfo); - } - - template <class T, typename... Args> - T& getMapper(Args... args) { - int32_t eventhubId = mFdp->ConsumeIntegral<int32_t>(); - // ensure a device entry exists for this eventHubId - mFuzzDevice->addEmptyEventHubDevice(eventhubId); - configureDevice(); - - return mFuzzDevice->template constructAndAddMapper<T>(eventhubId, args...); - } -}; - -} // namespace android diff --git a/services/inputflinger/tests/fuzzers/KeyboardInputFuzzer.cpp b/services/inputflinger/tests/fuzzers/KeyboardInputFuzzer.cpp index 54977df2ed..922cbdfb87 100644 --- a/services/inputflinger/tests/fuzzers/KeyboardInputFuzzer.cpp +++ b/services/inputflinger/tests/fuzzers/KeyboardInputFuzzer.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#include <FuzzContainer.h> +#include <InputDevice.h> #include <InputReaderBase.h> #include <KeyboardInputMapper.h> #include <MapperHelpers.h> @@ -23,38 +23,43 @@ namespace android { const int32_t kMaxKeycodes = 100; -static void addProperty(FuzzContainer& fuzzer, std::shared_ptr<ThreadSafeFuzzedDataProvider> fdp) { +static void addProperty(FuzzEventHub& eventHub, std::shared_ptr<ThreadSafeFuzzedDataProvider> fdp) { // Pick a random property to set for the mapper to have set. fdp->PickValueInArray<std::function<void()>>( - {[&]() -> void { fuzzer.addProperty("keyboard.orientationAware", "1"); }, + {[&]() -> void { eventHub.addProperty("keyboard.orientationAware", "1"); }, [&]() -> void { - fuzzer.addProperty("keyboard.orientationAware", - fdp->ConsumeRandomLengthString(100).data()); + eventHub.addProperty("keyboard.orientationAware", + fdp->ConsumeRandomLengthString(100).data()); }, [&]() -> void { - fuzzer.addProperty("keyboard.doNotWakeByDefault", - fdp->ConsumeRandomLengthString(100).data()); + eventHub.addProperty("keyboard.doNotWakeByDefault", + fdp->ConsumeRandomLengthString(100).data()); }, [&]() -> void { - fuzzer.addProperty("keyboard.handlesKeyRepeat", - fdp->ConsumeRandomLengthString(100).data()); + eventHub.addProperty("keyboard.handlesKeyRepeat", + fdp->ConsumeRandomLengthString(100).data()); }})(); } extern "C" int LLVMFuzzerTestOneInput(uint8_t* data, size_t size) { std::shared_ptr<ThreadSafeFuzzedDataProvider> fdp = std::make_shared<ThreadSafeFuzzedDataProvider>(data, size); - FuzzContainer fuzzer(fdp); - KeyboardInputMapper& mapper = - fuzzer.getMapper<KeyboardInputMapper>(InputReaderConfiguration{}, - fdp->ConsumeIntegral<uint32_t>(), - fdp->ConsumeIntegral<int32_t>()); + // Create mocked objects to support the fuzzed input mapper. + std::shared_ptr<FuzzEventHub> eventHub = std::make_shared<FuzzEventHub>(fdp); + FuzzInputReaderContext context(eventHub, fdp); + InputDevice device = getFuzzedInputDevice(*fdp, &context); + + KeyboardInputMapper& mapper = getMapperForDevice< + ThreadSafeFuzzedDataProvider, + KeyboardInputMapper>(*fdp.get(), device, InputReaderConfiguration{}, + /*source=*/fdp->ConsumeIntegral<uint32_t>(), + /*keyboardType=*/fdp->ConsumeIntegral<int32_t>()); // Loop through mapper operations until randomness is exhausted. while (fdp->remaining_bytes() > 0) { fdp->PickValueInArray<std::function<void()>>({ - [&]() -> void { addProperty(fuzzer, fdp); }, + [&]() -> void { addProperty(*eventHub.get(), fdp); }, [&]() -> void { std::string dump; mapper.dump(dump); diff --git a/services/inputflinger/tests/fuzzers/MapperHelpers.h b/services/inputflinger/tests/fuzzers/MapperHelpers.h index 5039d1a5f1..e88731aafd 100644 --- a/services/inputflinger/tests/fuzzers/MapperHelpers.h +++ b/services/inputflinger/tests/fuzzers/MapperHelpers.h @@ -16,6 +16,7 @@ #pragma once #include <map> +#include <memory> #include <EventHub.h> #include <InputDevice.h> @@ -328,10 +329,8 @@ class FuzzInputReaderContext : public InputReaderContext { public: FuzzInputReaderContext(std::shared_ptr<EventHubInterface> eventHub, - const sp<InputReaderPolicyInterface>& policy, - InputListenerInterface& listener, - std::shared_ptr<ThreadSafeFuzzedDataProvider> mFdp) - : mEventHub(eventHub), mPolicy(policy), mFdp(mFdp) {} + std::shared_ptr<ThreadSafeFuzzedDataProvider> fdp) + : mEventHub(eventHub), mPolicy(sp<FuzzInputReaderPolicy>::make(fdp)), mFdp(fdp) {} ~FuzzInputReaderContext() {} void updateGlobalMetaState() override {} int32_t getGlobalMetaState() { return mFdp->ConsumeIntegral<int32_t>(); } @@ -358,4 +357,32 @@ public: void notifyStylusGestureStarted(int32_t, nsecs_t) {} }; +template <class Fdp> +InputDevice getFuzzedInputDevice(Fdp& fdp, FuzzInputReaderContext* context) { + InputDeviceIdentifier identifier; + identifier.name = fdp.ConsumeRandomLengthString(16); + identifier.location = fdp.ConsumeRandomLengthString(12); + int32_t deviceID = fdp.ConsumeIntegralInRange(0, 5); + int32_t deviceGeneration = fdp.ConsumeIntegralInRange(0, 5); + return InputDevice(context, deviceID, deviceGeneration, identifier); +} + +template <class Fdp> +void configureAndResetDevice(Fdp& fdp, InputDevice& device) { + nsecs_t arbitraryTime = fdp.template ConsumeIntegral<nsecs_t>(); + std::list<NotifyArgs> out; + out += device.configure(arbitraryTime, /*readerConfig=*/{}, /*changes=*/{}); + out += device.reset(arbitraryTime); +} + +template <class Fdp, class T, typename... Args> +T& getMapperForDevice(Fdp& fdp, InputDevice& device, Args... args) { + int32_t eventhubId = fdp.template ConsumeIntegral<int32_t>(); + // ensure a device entry exists for this eventHubId + device.addEmptyEventHubDevice(eventhubId); + configureAndResetDevice(fdp, device); + + return device.template constructAndAddMapper<T>(eventhubId, args...); +} + } // namespace android diff --git a/services/inputflinger/tests/fuzzers/MultiTouchInputFuzzer.cpp b/services/inputflinger/tests/fuzzers/MultiTouchInputFuzzer.cpp index 569767f8c0..d3f66900da 100644 --- a/services/inputflinger/tests/fuzzers/MultiTouchInputFuzzer.cpp +++ b/services/inputflinger/tests/fuzzers/MultiTouchInputFuzzer.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#include <FuzzContainer.h> +#include <InputDevice.h> #include <InputReaderBase.h> #include <MapperHelpers.h> #include <MultiTouchInputMapper.h> @@ -23,53 +23,63 @@ namespace android { const int32_t kMaxKeycodes = 100; -static void addProperty(FuzzContainer& fuzzer, std::shared_ptr<ThreadSafeFuzzedDataProvider> fdp) { +static void addProperty(FuzzEventHub& eventHub, std::shared_ptr<ThreadSafeFuzzedDataProvider> fdp) { // Pick a random property to set for the mapper to have set. fdp->PickValueInArray<std::function<void()>>( - {[&]() -> void { fuzzer.addProperty("touch.deviceType", "touchScreen"); }, + {[&]() -> void { eventHub.addProperty("touch.deviceType", "touchScreen"); }, [&]() -> void { - fuzzer.addProperty("touch.deviceType", fdp->ConsumeRandomLengthString(8).data()); + eventHub.addProperty("touch.deviceType", fdp->ConsumeRandomLengthString(8).data()); }, [&]() -> void { - fuzzer.addProperty("touch.size.scale", fdp->ConsumeRandomLengthString(8).data()); + eventHub.addProperty("touch.size.scale", fdp->ConsumeRandomLengthString(8).data()); }, [&]() -> void { - fuzzer.addProperty("touch.size.bias", fdp->ConsumeRandomLengthString(8).data()); + eventHub.addProperty("touch.size.bias", fdp->ConsumeRandomLengthString(8).data()); }, [&]() -> void { - fuzzer.addProperty("touch.size.isSummed", - fdp->ConsumeRandomLengthString(8).data()); + eventHub.addProperty("touch.size.isSummed", + fdp->ConsumeRandomLengthString(8).data()); }, [&]() -> void { - fuzzer.addProperty("touch.size.calibration", - fdp->ConsumeRandomLengthString(8).data()); + eventHub.addProperty("touch.size.calibration", + fdp->ConsumeRandomLengthString(8).data()); }, [&]() -> void { - fuzzer.addProperty("touch.pressure.scale", - fdp->ConsumeRandomLengthString(8).data()); + eventHub.addProperty("touch.pressure.scale", + fdp->ConsumeRandomLengthString(8).data()); }, [&]() -> void { - fuzzer.addProperty("touch.size.calibration", - fdp->ConsumeBool() ? "diameter" : "area"); + eventHub.addProperty("touch.size.calibration", + fdp->ConsumeBool() ? "diameter" : "area"); }, [&]() -> void { - fuzzer.addProperty("touch.pressure.calibration", - fdp->ConsumeRandomLengthString(8).data()); + eventHub.addProperty("touch.pressure.calibration", + fdp->ConsumeRandomLengthString(8).data()); }})(); } extern "C" int LLVMFuzzerTestOneInput(uint8_t* data, size_t size) { std::shared_ptr<ThreadSafeFuzzedDataProvider> fdp = std::make_shared<ThreadSafeFuzzedDataProvider>(data, size); - FuzzContainer fuzzer(fdp); + + // Create mocked objects to support the fuzzed input mapper. + std::shared_ptr<FuzzEventHub> eventHub = std::make_shared<FuzzEventHub>(fdp); + FuzzInputReaderContext context(eventHub, fdp); + InputDevice device = getFuzzedInputDevice(*fdp, &context); InputReaderConfiguration policyConfig; - MultiTouchInputMapper& mapper = fuzzer.getMapper<MultiTouchInputMapper>(policyConfig); + MultiTouchInputMapper& mapper = + getMapperForDevice<ThreadSafeFuzzedDataProvider, MultiTouchInputMapper>(*fdp.get(), + device, + policyConfig); // Loop through mapper operations until randomness is exhausted. while (fdp->remaining_bytes() > 0) { fdp->PickValueInArray<std::function<void()>>({ - [&]() -> void { addProperty(fuzzer, fdp); }, + [&]() -> void { + addProperty(*eventHub.get(), fdp); + configureAndResetDevice(*fdp, device); + }, [&]() -> void { std::string dump; mapper.dump(dump); diff --git a/services/inputflinger/tests/fuzzers/SwitchInputFuzzer.cpp b/services/inputflinger/tests/fuzzers/SwitchInputFuzzer.cpp index 80eebd58e3..ac2030afd3 100644 --- a/services/inputflinger/tests/fuzzers/SwitchInputFuzzer.cpp +++ b/services/inputflinger/tests/fuzzers/SwitchInputFuzzer.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#include <FuzzContainer.h> +#include <InputDevice.h> #include <InputReaderBase.h> #include <MapperHelpers.h> #include <SwitchInputMapper.h> @@ -24,9 +24,15 @@ namespace android { extern "C" int LLVMFuzzerTestOneInput(uint8_t* data, size_t size) { std::shared_ptr<ThreadSafeFuzzedDataProvider> fdp = std::make_shared<ThreadSafeFuzzedDataProvider>(data, size); - FuzzContainer fuzzer(fdp); - SwitchInputMapper& mapper = fuzzer.getMapper<SwitchInputMapper>(InputReaderConfiguration{}); + // Create mocked objects to support the fuzzed input mapper. + std::shared_ptr<FuzzEventHub> eventHub = std::make_shared<FuzzEventHub>(fdp); + FuzzInputReaderContext context(eventHub, fdp); + InputDevice device = getFuzzedInputDevice(*fdp, &context); + + SwitchInputMapper& mapper = + getMapperForDevice<ThreadSafeFuzzedDataProvider, + SwitchInputMapper>(*fdp.get(), device, InputReaderConfiguration{}); // Loop through mapper operations until randomness is exhausted. while (fdp->remaining_bytes() > 0) { diff --git a/services/inputflinger/tests/fuzzers/TouchpadInputFuzzer.cpp b/services/inputflinger/tests/fuzzers/TouchpadInputFuzzer.cpp index 796178addd..be765cc364 100644 --- a/services/inputflinger/tests/fuzzers/TouchpadInputFuzzer.cpp +++ b/services/inputflinger/tests/fuzzers/TouchpadInputFuzzer.cpp @@ -15,12 +15,13 @@ */ #include <limits> +#include <memory> #include <string> #include <vector> #include <linux/input-event-codes.h> -#include <FuzzContainer.h> +#include <InputDevice.h> #include <InputReaderBase.h> #include <MapperHelpers.h> #include <TouchpadInputMapper.h> @@ -29,30 +30,30 @@ namespace android { namespace { -void setAxisInfo(ThreadSafeFuzzedDataProvider& fdp, FuzzContainer& fuzzer, int axis) { +void setAxisInfo(ThreadSafeFuzzedDataProvider& fdp, FuzzEventHub& eventHub, int32_t id, int axis) { if (fdp.ConsumeBool()) { - fuzzer.setAbsoluteAxisInfo(axis, - RawAbsoluteAxisInfo{ - .valid = fdp.ConsumeBool(), - .minValue = fdp.ConsumeIntegral<int32_t>(), - .maxValue = fdp.ConsumeIntegral<int32_t>(), - .flat = fdp.ConsumeIntegral<int32_t>(), - .fuzz = fdp.ConsumeIntegral<int32_t>(), - .resolution = fdp.ConsumeIntegral<int32_t>(), - }); + eventHub.setAbsoluteAxisInfo(id, axis, + RawAbsoluteAxisInfo{ + .valid = fdp.ConsumeBool(), + .minValue = fdp.ConsumeIntegral<int32_t>(), + .maxValue = fdp.ConsumeIntegral<int32_t>(), + .flat = fdp.ConsumeIntegral<int32_t>(), + .fuzz = fdp.ConsumeIntegral<int32_t>(), + .resolution = fdp.ConsumeIntegral<int32_t>(), + }); } } -void setAxisInfos(ThreadSafeFuzzedDataProvider& fdp, FuzzContainer& fuzzer) { - setAxisInfo(fdp, fuzzer, ABS_MT_SLOT); - setAxisInfo(fdp, fuzzer, ABS_MT_POSITION_X); - setAxisInfo(fdp, fuzzer, ABS_MT_POSITION_Y); - setAxisInfo(fdp, fuzzer, ABS_MT_PRESSURE); - setAxisInfo(fdp, fuzzer, ABS_MT_ORIENTATION); - setAxisInfo(fdp, fuzzer, ABS_MT_TOUCH_MAJOR); - setAxisInfo(fdp, fuzzer, ABS_MT_TOUCH_MINOR); - setAxisInfo(fdp, fuzzer, ABS_MT_WIDTH_MAJOR); - setAxisInfo(fdp, fuzzer, ABS_MT_WIDTH_MINOR); +void setAxisInfos(ThreadSafeFuzzedDataProvider& fdp, FuzzEventHub& eventHub, int32_t id) { + setAxisInfo(fdp, eventHub, id, ABS_MT_SLOT); + setAxisInfo(fdp, eventHub, id, ABS_MT_POSITION_X); + setAxisInfo(fdp, eventHub, id, ABS_MT_POSITION_Y); + setAxisInfo(fdp, eventHub, id, ABS_MT_PRESSURE); + setAxisInfo(fdp, eventHub, id, ABS_MT_ORIENTATION); + setAxisInfo(fdp, eventHub, id, ABS_MT_TOUCH_MAJOR); + setAxisInfo(fdp, eventHub, id, ABS_MT_TOUCH_MINOR); + setAxisInfo(fdp, eventHub, id, ABS_MT_WIDTH_MAJOR); + setAxisInfo(fdp, eventHub, id, ABS_MT_WIDTH_MINOR); } const std::vector<std::string> boolPropertiesToFuzz = { @@ -89,32 +90,32 @@ const std::vector<std::string> doublePropertiesToFuzz = { "gestureProp.Two_Finger_Vertical_Close_Distance_Thresh", }; -void setDeviceSpecificConfig(ThreadSafeFuzzedDataProvider& fdp, FuzzContainer& fuzzer) { +void setDeviceSpecificConfig(ThreadSafeFuzzedDataProvider& fdp, FuzzEventHub& eventHub) { // There are a great many gesture properties offered by the Gestures library, all of which could // potentially be set in Input Device Configuration files. Maintaining a complete list is // impractical, so instead we only fuzz properties which are used in at least one IDC file, or // which are likely to be used in future (e.g. ones for controlling palm rejection). if (fdp.ConsumeBool()) { - fuzzer.addProperty("gestureProp.Touchpad_Stack_Version", - std::to_string(fdp.ConsumeIntegral<int>())); + eventHub.addProperty("gestureProp.Touchpad_Stack_Version", + std::to_string(fdp.ConsumeIntegral<int>())); } for (auto& propertyName : boolPropertiesToFuzz) { if (fdp.ConsumeBool()) { - fuzzer.addProperty(propertyName, fdp.ConsumeBool() ? "1" : "0"); + eventHub.addProperty(propertyName, fdp.ConsumeBool() ? "1" : "0"); } } for (auto& propertyName : doublePropertiesToFuzz) { if (fdp.ConsumeBool()) { - fuzzer.addProperty(propertyName, std::to_string(fdp.ConsumeFloatingPoint<double>())); + eventHub.addProperty(propertyName, std::to_string(fdp.ConsumeFloatingPoint<double>())); } } if (fdp.ConsumeBool()) { - fuzzer.addProperty("gestureProp." + fdp.ConsumeRandomLengthString(), - std::to_string(fdp.ConsumeIntegral<int>())); + eventHub.addProperty("gestureProp." + fdp.ConsumeRandomLengthString(), + std::to_string(fdp.ConsumeIntegral<int>())); } } @@ -130,16 +131,23 @@ void setTouchpadSettings(ThreadSafeFuzzedDataProvider& fdp, InputReaderConfigura extern "C" int LLVMFuzzerTestOneInput(uint8_t* data, size_t size) { std::shared_ptr<ThreadSafeFuzzedDataProvider> fdp = std::make_shared<ThreadSafeFuzzedDataProvider>(data, size); - FuzzContainer fuzzer(fdp); - setAxisInfos(*fdp, fuzzer); - setDeviceSpecificConfig(*fdp, fuzzer); + + // Create mocked objects to support the fuzzed input mapper. + std::shared_ptr<FuzzEventHub> eventHub = std::make_shared<FuzzEventHub>(fdp); + FuzzInputReaderContext context(eventHub, fdp); + InputDevice device = getFuzzedInputDevice(*fdp, &context); + + setAxisInfos(*fdp, *eventHub.get(), device.getId()); + setDeviceSpecificConfig(*fdp, *eventHub.get()); InputReaderConfiguration policyConfig; // Some settings are fuzzed here, as well as in the main loop, to provide randomized data to the // TouchpadInputMapper constructor. setTouchpadSettings(*fdp, policyConfig); policyConfig.pointerCaptureRequest.enable = fdp->ConsumeBool(); - TouchpadInputMapper& mapper = fuzzer.getMapper<TouchpadInputMapper>(policyConfig); + TouchpadInputMapper& mapper = + getMapperForDevice<ThreadSafeFuzzedDataProvider, TouchpadInputMapper>(*fdp, device, + policyConfig); // Loop through mapper operations until randomness is exhausted. while (fdp->remaining_bytes() > 0) { diff --git a/services/sensorservice/AidlSensorHalWrapper.cpp b/services/sensorservice/AidlSensorHalWrapper.cpp index f5b360f3b6..e60db93431 100644 --- a/services/sensorservice/AidlSensorHalWrapper.cpp +++ b/services/sensorservice/AidlSensorHalWrapper.cpp @@ -308,8 +308,12 @@ status_t AidlSensorHalWrapper::configureDirectChannel(int32_t sensorHandle, int3 } int32_t token; - mSensors->configDirectReport(sensorHandle, channelHandle, rate, &token); - return token; + status_t status = convertToStatus( + mSensors->configDirectReport(sensorHandle, channelHandle, rate, &token)); + if (status == OK && rate != ISensors::RateLevel::STOP) { + status = static_cast<status_t>(token); + } + return status; } void AidlSensorHalWrapper::writeWakeLockHandled(uint32_t count) { diff --git a/services/surfaceflinger/BackgroundExecutor.cpp b/services/surfaceflinger/BackgroundExecutor.cpp index 6ddf790d47..5a1ec6f501 100644 --- a/services/surfaceflinger/BackgroundExecutor.cpp +++ b/services/surfaceflinger/BackgroundExecutor.cpp @@ -20,6 +20,7 @@ #define ATRACE_TAG ATRACE_TAG_GRAPHICS #include <utils/Log.h> +#include <mutex> #include "BackgroundExecutor.h" @@ -60,4 +61,17 @@ void BackgroundExecutor::sendCallbacks(Callbacks&& tasks) { LOG_ALWAYS_FATAL_IF(sem_post(&mSemaphore), "sem_post failed"); } +void BackgroundExecutor::flushQueue() { + std::mutex mutex; + std::condition_variable cv; + bool flushComplete = false; + sendCallbacks({[&]() { + std::scoped_lock lock{mutex}; + flushComplete = true; + cv.notify_one(); + }}); + std::unique_lock<std::mutex> lock{mutex}; + cv.wait(lock, [&]() { return flushComplete; }); +} + } // namespace android diff --git a/services/surfaceflinger/BackgroundExecutor.h b/services/surfaceflinger/BackgroundExecutor.h index 0fae5a5c93..66b7d7a1fc 100644 --- a/services/surfaceflinger/BackgroundExecutor.h +++ b/services/surfaceflinger/BackgroundExecutor.h @@ -34,6 +34,7 @@ public: // Queues callbacks onto a work queue to be executed by a background thread. // This is safe to call from multiple threads. void sendCallbacks(Callbacks&& tasks); + void flushQueue(); private: sem_t mSemaphore; diff --git a/services/surfaceflinger/OWNERS b/services/surfaceflinger/OWNERS index 4e7da829f2..473409715f 100644 --- a/services/surfaceflinger/OWNERS +++ b/services/surfaceflinger/OWNERS @@ -1,6 +1,7 @@ adyabr@google.com alecmouri@google.com chaviw@google.com +domlaskowski@google.com lpy@google.com pdwilliams@google.com racarr@google.com diff --git a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp index 7951c33d79..2529095f99 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp +++ b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp @@ -1223,10 +1223,19 @@ void RefreshRateSelector::constructAvailableRefreshRates() { (supportsFrameRateOverride() || ranges.render.includes(mode.getFps())); }; - const auto frameRateModes = createFrameRateModes(filterModes, ranges.render); + auto frameRateModes = createFrameRateModes(filterModes, ranges.render); + if (frameRateModes.empty()) { + ALOGW("No matching frame rate modes for %s range. policy: %s", rangeName, + policy->toString().c_str()); + // TODO(b/292105422): Ideally DisplayManager should not send render ranges smaller than + // the min supported. See b/292047939. + // For not we just ignore the render ranges. + frameRateModes = createFrameRateModes(filterModes, {}); + } LOG_ALWAYS_FATAL_IF(frameRateModes.empty(), - "No matching frame rate modes for %s range. policy: %s", rangeName, - policy->toString().c_str()); + "No matching frame rate modes for %s range even after ignoring the " + "render range. policy: %s", + rangeName, policy->toString().c_str()); const auto stringifyModes = [&] { std::string str; diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index 08667bfdec..d6d7725f6c 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -25,6 +25,7 @@ #include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h> #include <android/hardware/configstore/1.1/ISurfaceFlingerConfigs.h> #include <configstore/Utils.h> +#include <ftl/concat.h> #include <ftl/enum.h> #include <ftl/fake_guard.h> #include <ftl/small_map.h> @@ -130,8 +131,8 @@ void Scheduler::registerDisplayInternal(PhysicalDisplayId displayId, auto [pacesetterVsyncSchedule, isNew] = [&]() FTL_FAKE_GUARD(kMainThreadContext) { std::scoped_lock lock(mDisplayLock); const bool isNew = mDisplays - .emplace_or_replace(displayId, std::move(selectorPtr), - std::move(schedulePtr)) + .emplace_or_replace(displayId, displayId, std::move(selectorPtr), + std::move(schedulePtr), mFeatures) .second; return std::make_pair(promotePacesetterDisplayLocked(), isNew); @@ -171,21 +172,43 @@ void Scheduler::run() { void Scheduler::onFrameSignal(ICompositor& compositor, VsyncId vsyncId, TimePoint expectedVsyncTime) { - mPacesetterFrameTargeter.beginFrame({.frameBeginTime = SchedulerClock::now(), - .vsyncId = vsyncId, - .expectedVsyncTime = expectedVsyncTime, - .sfWorkDuration = - mVsyncModulator->getVsyncConfig().sfWorkDuration}, - *getVsyncSchedule()); - - if (!compositor.commit(mPacesetterFrameTargeter.target())) { - return; + const FrameTargeter::BeginFrameArgs beginFrameArgs = + {.frameBeginTime = SchedulerClock::now(), + .vsyncId = vsyncId, + // TODO(b/255601557): Calculate per display. + .expectedVsyncTime = expectedVsyncTime, + .sfWorkDuration = mVsyncModulator->getVsyncConfig().sfWorkDuration}; + + LOG_ALWAYS_FATAL_IF(!mPacesetterDisplayId); + const auto pacesetterId = *mPacesetterDisplayId; + const auto pacesetterOpt = mDisplays.get(pacesetterId); + + FrameTargeter& pacesetterTargeter = *pacesetterOpt->get().targeterPtr; + pacesetterTargeter.beginFrame(beginFrameArgs, *pacesetterOpt->get().schedulePtr); + + if (!compositor.commit(pacesetterTargeter.target())) return; + + // TODO(b/256196556): Choose the frontrunner display. + FrameTargeters targeters; + targeters.try_emplace(pacesetterId, &pacesetterTargeter); + + for (auto& [id, display] : mDisplays) { + if (id == pacesetterId) continue; + + FrameTargeter& targeter = *display.targeterPtr; + targeter.beginFrame(beginFrameArgs, *display.schedulePtr); + + targeters.try_emplace(id, &targeter); } - const auto compositeResult = compositor.composite(mPacesetterFrameTargeter); + const auto resultsPerDisplay = compositor.composite(pacesetterId, targeters); compositor.sample(); - mPacesetterFrameTargeter.endFrame(compositeResult); + for (const auto& [id, targeter] : targeters) { + const auto resultOpt = resultsPerDisplay.get(id); + LOG_ALWAYS_FATAL_IF(!resultOpt); + targeter->endFrame(*resultOpt); + } } std::optional<Fps> Scheduler::getFrameRateOverride(uid_t uid) const { @@ -539,8 +562,16 @@ bool Scheduler::addResyncSample(PhysicalDisplayId id, nsecs_t timestamp, } void Scheduler::addPresentFence(PhysicalDisplayId id, std::shared_ptr<FenceTime> fence) { - auto schedule = getVsyncSchedule(id); - LOG_ALWAYS_FATAL_IF(!schedule); + const auto scheduleOpt = + (ftl::FakeGuard(mDisplayLock), mDisplays.get(id)).and_then([](const Display& display) { + return display.powerMode == hal::PowerMode::OFF + ? std::nullopt + : std::make_optional(display.schedulePtr); + }); + + if (!scheduleOpt) return; + const auto& schedule = scheduleOpt->get(); + if (const bool needMoreSignals = schedule->getController().addPresentFence(std::move(fence))) { schedule->enableHardwareVsync(); } else { @@ -750,7 +781,23 @@ void Scheduler::dump(utils::Dumper& dumper) const { mFrameRateOverrideMappings.dump(dumper); dumper.eol(); - mPacesetterFrameTargeter.dump(dumper); + { + utils::Dumper::Section section(dumper, "Frame Targeting"sv); + + std::scoped_lock lock(mDisplayLock); + ftl::FakeGuard guard(kMainThreadContext); + + for (const auto& [id, display] : mDisplays) { + utils::Dumper::Section + section(dumper, + id == mPacesetterDisplayId + ? ftl::Concat("Pacesetter Display ", id.value).c_str() + : ftl::Concat("Follower Display ", id.value).c_str()); + + display.targeterPtr->dump(dumper); + dumper.eol(); + } + } } void Scheduler::dumpVsync(std::string& out) const { @@ -771,6 +818,12 @@ void Scheduler::dumpVsync(std::string& out) const { } bool Scheduler::updateFrameRateOverrides(GlobalSignals consideredSignals, Fps displayRefreshRate) { + std::scoped_lock lock(mPolicyLock); + return updateFrameRateOverridesLocked(consideredSignals, displayRefreshRate); +} + +bool Scheduler::updateFrameRateOverridesLocked(GlobalSignals consideredSignals, + Fps displayRefreshRate) { if (consideredSignals.idle) return false; const auto frameRateOverrides = @@ -989,7 +1042,7 @@ auto Scheduler::applyPolicy(S Policy::*statePtr, T&& newState) -> GlobalSignals .emitEvent = !choice.consideredSignals.idle}); } - frameRateOverridesChanged = updateFrameRateOverrides(consideredSignals, modeOpt->fps); + frameRateOverridesChanged = updateFrameRateOverridesLocked(consideredSignals, modeOpt->fps); if (mPolicy.modeOpt != modeOpt) { mPolicy.modeOpt = modeOpt; diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index 0ffa2d2022..85d0f9add5 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -222,7 +222,7 @@ public: // otherwise. bool addResyncSample(PhysicalDisplayId, nsecs_t timestamp, std::optional<nsecs_t> hwcVsyncPeriod); - void addPresentFence(PhysicalDisplayId, std::shared_ptr<FenceTime>) EXCLUDES(mDisplayLock) + void addPresentFence(PhysicalDisplayId, std::shared_ptr<FenceTime>) REQUIRES(kMainThreadContext); // Layers are registered on creation, and unregistered when the weak reference expires. @@ -254,7 +254,14 @@ public: return std::const_pointer_cast<VsyncSchedule>(std::as_const(*this).getVsyncSchedule(idOpt)); } - const FrameTarget& pacesetterFrameTarget() { return mPacesetterFrameTargeter.target(); } + TimePoint expectedPresentTimeForPacesetter() const EXCLUDES(mDisplayLock) { + std::scoped_lock lock(mDisplayLock); + return pacesetterDisplayLocked() + .transform([](const Display& display) { + return display.targeterPtr->target().expectedPresentTime(); + }) + .value_or(TimePoint()); + } // Returns true if a given vsync timestamp is considered valid vsync // for a given uid @@ -300,6 +307,8 @@ public: return mLayerHistory.getLayerFramerate(now, id); } + bool updateFrameRateOverrides(GlobalSignals, Fps displayRefreshRate) EXCLUDES(mPolicyLock); + private: friend class TestableScheduler; @@ -308,7 +317,8 @@ private: enum class TouchState { Inactive, Active }; // impl::MessageQueue overrides: - void onFrameSignal(ICompositor&, VsyncId, TimePoint expectedVsyncTime) override; + void onFrameSignal(ICompositor&, VsyncId, TimePoint expectedVsyncTime) override + REQUIRES(kMainThreadContext, mDisplayLock); // Create a connection on the given EventThread. ConnectionHandle createConnection(std::unique_ptr<EventThread>); @@ -384,7 +394,8 @@ private: GlobalSignals makeGlobalSignals() const REQUIRES(mPolicyLock); - bool updateFrameRateOverrides(GlobalSignals, Fps displayRefreshRate) REQUIRES(mPolicyLock); + bool updateFrameRateOverridesLocked(GlobalSignals, Fps displayRefreshRate) + REQUIRES(mPolicyLock); void updateAttachedChoreographers(const surfaceflinger::frontend::LayerHierarchy&, Fps displayRefreshRate); int updateAttachedChoreographersInternal(const surfaceflinger::frontend::LayerHierarchy&, @@ -434,13 +445,24 @@ private: // must lock for writes but not reads. See also mPolicyLock for locking order. mutable std::mutex mDisplayLock; + using FrameTargeterPtr = std::unique_ptr<FrameTargeter>; + struct Display { - Display(RefreshRateSelectorPtr selectorPtr, VsyncSchedulePtr schedulePtr) - : selectorPtr(std::move(selectorPtr)), schedulePtr(std::move(schedulePtr)) {} + Display(PhysicalDisplayId displayId, RefreshRateSelectorPtr selectorPtr, + VsyncSchedulePtr schedulePtr, FeatureFlags features) + : displayId(displayId), + selectorPtr(std::move(selectorPtr)), + schedulePtr(std::move(schedulePtr)), + targeterPtr(std::make_unique< + FrameTargeter>(displayId, + features.test(Feature::kBackpressureGpuComposition))) {} + + const PhysicalDisplayId displayId; // Effectively const except in move constructor. RefreshRateSelectorPtr selectorPtr; VsyncSchedulePtr schedulePtr; + FrameTargeterPtr targeterPtr; hal::PowerMode powerMode = hal::PowerMode::OFF; }; @@ -454,8 +476,6 @@ private: ftl::Optional<PhysicalDisplayId> mPacesetterDisplayId GUARDED_BY(mDisplayLock) GUARDED_BY(kMainThreadContext); - FrameTargeter mPacesetterFrameTargeter{mFeatures.test(Feature::kBackpressureGpuComposition)}; - ftl::Optional<DisplayRef> pacesetterDisplayLocked() REQUIRES(mDisplayLock) { return static_cast<const Scheduler*>(this)->pacesetterDisplayLocked().transform( [](const Display& display) { return std::ref(const_cast<Display&>(display)); }); diff --git a/services/surfaceflinger/Scheduler/include/scheduler/FrameTargeter.h b/services/surfaceflinger/Scheduler/include/scheduler/FrameTargeter.h index 85f2e64faa..ae74205720 100644 --- a/services/surfaceflinger/Scheduler/include/scheduler/FrameTargeter.h +++ b/services/surfaceflinger/Scheduler/include/scheduler/FrameTargeter.h @@ -20,6 +20,7 @@ #include <atomic> #include <memory> +#include <ui/DisplayId.h> #include <ui/Fence.h> #include <ui/FenceTime.h> @@ -75,16 +76,17 @@ public: bool didMissHwcFrame() const { return mHwcFrameMissed && !mGpuFrameMissed; } protected: + explicit FrameTarget(const std::string& displayLabel); ~FrameTarget() = default; VsyncId mVsyncId; TimePoint mFrameBeginTime; TimePoint mExpectedPresentTime; - TracedOrdinal<bool> mFramePending{"PrevFramePending", false}; - TracedOrdinal<bool> mFrameMissed{"PrevFrameMissed", false}; - TracedOrdinal<bool> mHwcFrameMissed{"PrevHwcFrameMissed", false}; - TracedOrdinal<bool> mGpuFrameMissed{"PrevGpuFrameMissed", false}; + TracedOrdinal<bool> mFramePending; + TracedOrdinal<bool> mFrameMissed; + TracedOrdinal<bool> mHwcFrameMissed; + TracedOrdinal<bool> mGpuFrameMissed; struct FenceWithFenceTime { sp<Fence> fence = Fence::NO_FENCE; @@ -103,8 +105,9 @@ private: // Computes a display's per-frame metrics about past/upcoming targeting of present deadlines. class FrameTargeter final : private FrameTarget { public: - explicit FrameTargeter(bool backpressureGpuComposition) - : mBackpressureGpuComposition(backpressureGpuComposition) {} + FrameTargeter(PhysicalDisplayId displayId, bool backpressureGpuComposition) + : FrameTarget(to_string(displayId)), + mBackpressureGpuComposition(backpressureGpuComposition) {} const FrameTarget& target() const { return *this; } diff --git a/services/surfaceflinger/Scheduler/include/scheduler/interface/CompositeResult.h b/services/surfaceflinger/Scheduler/include/scheduler/interface/CompositeResult.h index f795f1f09d..87c704ece3 100644 --- a/services/surfaceflinger/Scheduler/include/scheduler/interface/CompositeResult.h +++ b/services/surfaceflinger/Scheduler/include/scheduler/interface/CompositeResult.h @@ -16,6 +16,9 @@ #pragma once +#include <ui/DisplayId.h> +#include <ui/DisplayMap.h> + #include <scheduler/interface/CompositionCoverage.h> namespace android { @@ -24,4 +27,6 @@ struct CompositeResult { CompositionCoverageFlags compositionCoverage; }; +using CompositeResultsPerDisplay = ui::PhysicalDisplayMap<PhysicalDisplayId, CompositeResult>; + } // namespace android diff --git a/services/surfaceflinger/Scheduler/include/scheduler/interface/CompositionCoverage.h b/services/surfaceflinger/Scheduler/include/scheduler/interface/CompositionCoverage.h index 3d0f1a9d33..767462dfce 100644 --- a/services/surfaceflinger/Scheduler/include/scheduler/interface/CompositionCoverage.h +++ b/services/surfaceflinger/Scheduler/include/scheduler/interface/CompositionCoverage.h @@ -19,6 +19,8 @@ #include <cstdint> #include <ftl/flags.h> +#include <ui/DisplayId.h> +#include <ui/DisplayMap.h> namespace android { @@ -34,4 +36,14 @@ enum class CompositionCoverage : std::uint8_t { using CompositionCoverageFlags = ftl::Flags<CompositionCoverage>; +using CompositionCoveragePerDisplay = ui::DisplayMap<DisplayId, CompositionCoverageFlags>; + +inline CompositionCoverageFlags multiDisplayUnion(const CompositionCoveragePerDisplay& displays) { + CompositionCoverageFlags coverage; + for (const auto& [id, flags] : displays) { + coverage |= flags; + } + return coverage; +} + } // namespace android diff --git a/services/surfaceflinger/Scheduler/include/scheduler/interface/ICompositor.h b/services/surfaceflinger/Scheduler/include/scheduler/interface/ICompositor.h index 26960766e5..6fe813a181 100644 --- a/services/surfaceflinger/Scheduler/include/scheduler/interface/ICompositor.h +++ b/services/surfaceflinger/Scheduler/include/scheduler/interface/ICompositor.h @@ -16,6 +16,9 @@ #pragma once +#include <ui/DisplayId.h> +#include <ui/DisplayMap.h> + #include <scheduler/Time.h> #include <scheduler/VsyncId.h> #include <scheduler/interface/CompositeResult.h> @@ -26,6 +29,8 @@ namespace scheduler { class FrameTarget; class FrameTargeter; +using FrameTargeters = ui::PhysicalDisplayMap<PhysicalDisplayId, scheduler::FrameTargeter*>; + } // namespace scheduler struct ICompositor { @@ -38,7 +43,8 @@ struct ICompositor { // Composites a frame for each display. CompositionEngine performs GPU and/or HAL composition // via RenderEngine and the Composer HAL, respectively. - virtual CompositeResult composite(scheduler::FrameTargeter&) = 0; + virtual CompositeResultsPerDisplay composite(PhysicalDisplayId pacesetterId, + const scheduler::FrameTargeters&) = 0; // Samples the composited frame via RegionSamplingThread. virtual void sample() = 0; diff --git a/services/surfaceflinger/Scheduler/src/FrameTargeter.cpp b/services/surfaceflinger/Scheduler/src/FrameTargeter.cpp index 7138afdf8b..7a18654346 100644 --- a/services/surfaceflinger/Scheduler/src/FrameTargeter.cpp +++ b/services/surfaceflinger/Scheduler/src/FrameTargeter.cpp @@ -21,6 +21,12 @@ namespace android::scheduler { +FrameTarget::FrameTarget(const std::string& displayLabel) + : mFramePending("PrevFramePending " + displayLabel, false), + mFrameMissed("PrevFrameMissed " + displayLabel, false), + mHwcFrameMissed("PrevHwcFrameMissed " + displayLabel, false), + mGpuFrameMissed("PrevGpuFrameMissed " + displayLabel, false) {} + TimePoint FrameTarget::pastVsyncTime(Period vsyncPeriod) const { // TODO(b/267315508): Generalize to N VSYNCs. const int shift = static_cast<int>(targetsVsyncsAhead<2>(vsyncPeriod)); @@ -130,10 +136,6 @@ FenceTimePtr FrameTargeter::setPresentFence(sp<Fence> presentFence, FenceTimePtr } void FrameTargeter::dump(utils::Dumper& dumper) const { - using namespace std::string_view_literals; - - utils::Dumper::Section section(dumper, "Frame Targeting"sv); - // There are scripts and tests that expect this (rather than "name=value") format. dumper.dump({}, "Total missed frame count: " + std::to_string(mFrameMissedCount)); dumper.dump({}, "HWC missed frame count: " + std::to_string(mHwcFrameMissedCount)); diff --git a/services/surfaceflinger/Scheduler/tests/FrameTargeterTest.cpp b/services/surfaceflinger/Scheduler/tests/FrameTargeterTest.cpp index 908f214e85..1e038d1753 100644 --- a/services/surfaceflinger/Scheduler/tests/FrameTargeterTest.cpp +++ b/services/surfaceflinger/Scheduler/tests/FrameTargeterTest.cpp @@ -96,7 +96,7 @@ private: FenceToFenceTimeMap mFenceMap; static constexpr bool kBackpressureGpuComposition = true; - FrameTargeter mTargeter{kBackpressureGpuComposition}; + FrameTargeter mTargeter{PhysicalDisplayId::fromPort(13), kBackpressureGpuComposition}; }; TEST_F(FrameTargeterTest, targetsFrames) { diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index a9a1d80830..e339978e3f 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -2181,7 +2181,7 @@ void SurfaceFlinger::onRefreshRateChangedDebug(const RefreshRateChangedDebugData } } -void SurfaceFlinger::configure() FTL_FAKE_GUARD(kMainThreadContext) { +void SurfaceFlinger::configure() { Mutex::Autolock lock(mStateLock); if (configureLocked()) { setTransactionFlags(eDisplayTransactionNeeded); @@ -2401,8 +2401,7 @@ bool SurfaceFlinger::updateLayerSnapshots(VsyncId vsyncId, nsecs_t frameTimeNs, return mustComposite; } -bool SurfaceFlinger::commit(const scheduler::FrameTarget& pacesetterFrameTarget) - FTL_FAKE_GUARD(kMainThreadContext) { +bool SurfaceFlinger::commit(const scheduler::FrameTarget& pacesetterFrameTarget) { const VsyncId vsyncId = pacesetterFrameTarget.vsyncId(); ATRACE_NAME(ftl::Concat(__func__, ' ', ftl::to_underlying(vsyncId)).c_str()); @@ -2538,31 +2537,42 @@ bool SurfaceFlinger::commit(const scheduler::FrameTarget& pacesetterFrameTarget) return mustComposite && CC_LIKELY(mBootStage != BootStage::BOOTLOADER); } -CompositeResult SurfaceFlinger::composite(scheduler::FrameTargeter& pacesetterFrameTargeter) - FTL_FAKE_GUARD(kMainThreadContext) { - const scheduler::FrameTarget& pacesetterFrameTarget = pacesetterFrameTargeter.target(); +CompositeResultsPerDisplay SurfaceFlinger::composite( + PhysicalDisplayId pacesetterId, const scheduler::FrameTargeters& frameTargeters) { + const scheduler::FrameTarget& pacesetterTarget = + frameTargeters.get(pacesetterId)->get()->target(); - const VsyncId vsyncId = pacesetterFrameTarget.vsyncId(); + const VsyncId vsyncId = pacesetterTarget.vsyncId(); ATRACE_NAME(ftl::Concat(__func__, ' ', ftl::to_underlying(vsyncId)).c_str()); compositionengine::CompositionRefreshArgs refreshArgs; refreshArgs.powerCallback = this; const auto& displays = FTL_FAKE_GUARD(mStateLock, mDisplays); refreshArgs.outputs.reserve(displays.size()); + + // Add outputs for physical displays. + for (const auto& [id, targeter] : frameTargeters) { + ftl::FakeGuard guard(mStateLock); + + if (const auto display = getCompositionDisplayLocked(id)) { + refreshArgs.outputs.push_back(display); + } + } + std::vector<DisplayId> displayIds; for (const auto& [_, display] : displays) { displayIds.push_back(display->getId()); display->tracePowerMode(); + // Add outputs for virtual displays. if (display->isVirtual()) { const Fps refreshRate = display->getAdjustedRefreshRate(); - if (refreshRate.isValid() && - !mScheduler->isVsyncInPhase(pacesetterFrameTarget.frameBeginTime(), refreshRate)) { - continue; + + if (!refreshRate.isValid() || + mScheduler->isVsyncInPhase(pacesetterTarget.frameBeginTime(), refreshRate)) { + refreshArgs.outputs.push_back(display->getCompositionDisplay()); } } - - refreshArgs.outputs.push_back(display->getCompositionDisplay()); } mPowerAdvisor->setDisplays(displayIds); @@ -2622,15 +2632,16 @@ CompositeResult SurfaceFlinger::composite(scheduler::FrameTargeter& pacesetterFr if (!getHwComposer().getComposer()->isSupported( Hwc2::Composer::OptionalFeature::ExpectedPresentTime) && - pacesetterFrameTarget.wouldPresentEarly(vsyncPeriod)) { + pacesetterTarget.wouldPresentEarly(vsyncPeriod)) { const auto hwcMinWorkDuration = mVsyncConfiguration->getCurrentConfigs().hwcMinWorkDuration; + // TODO(b/255601557): Calculate and pass per-display values for each FrameTarget. refreshArgs.earliestPresentTime = - pacesetterFrameTarget.previousFrameVsyncTime(vsyncPeriod) - hwcMinWorkDuration; + pacesetterTarget.previousFrameVsyncTime(vsyncPeriod) - hwcMinWorkDuration; } refreshArgs.scheduledFrameTime = mScheduler->getScheduledFrameTime(); - refreshArgs.expectedPresentTime = pacesetterFrameTarget.expectedPresentTime().ns(); + refreshArgs.expectedPresentTime = pacesetterTarget.expectedPresentTime().ns(); refreshArgs.hasTrustedPresentationListener = mNumTrustedPresentationListeners > 0; // Store the present time just before calling to the composition engine so we could notify @@ -2656,14 +2667,14 @@ CompositeResult SurfaceFlinger::composite(scheduler::FrameTargeter& pacesetterFr } } - mTimeStats->recordFrameDuration(pacesetterFrameTarget.frameBeginTime().ns(), systemTime()); + mTimeStats->recordFrameDuration(pacesetterTarget.frameBeginTime().ns(), systemTime()); // Send a power hint after presentation is finished. if (mPowerHintSessionEnabled) { // Now that the current frame has been presented above, PowerAdvisor needs the present time // of the previous frame (whose fence is signaled by now) to determine how long the HWC had // waited on that fence to retire before presenting. - const auto& previousPresentFence = pacesetterFrameTarget.presentFenceForPreviousFrame(); + const auto& previousPresentFence = pacesetterTarget.presentFenceForPreviousFrame(); mPowerAdvisor->setSfPresentTiming(TimePoint::fromNs(previousPresentFence->getSignalTime()), TimePoint::now()); @@ -2674,23 +2685,27 @@ CompositeResult SurfaceFlinger::composite(scheduler::FrameTargeter& pacesetterFr scheduleComposite(FrameHint::kNone); } - postComposition(pacesetterFrameTargeter, presentTime); + postComposition(pacesetterId, frameTargeters, presentTime); - const bool hadGpuComposited = mCompositionCoverage.test(CompositionCoverage::Gpu); + const bool hadGpuComposited = + multiDisplayUnion(mCompositionCoverage).test(CompositionCoverage::Gpu); mCompositionCoverage.clear(); TimeStats::ClientCompositionRecord clientCompositionRecord; + for (const auto& [_, display] : displays) { const auto& state = display->getCompositionDisplay()->getState(); + CompositionCoverageFlags& flags = + mCompositionCoverage.try_emplace(display->getId()).first->second; if (state.usesDeviceComposition) { - mCompositionCoverage |= CompositionCoverage::Hwc; + flags |= CompositionCoverage::Hwc; } if (state.reusedClientComposition) { - mCompositionCoverage |= CompositionCoverage::GpuReuse; + flags |= CompositionCoverage::GpuReuse; } else if (state.usesClientComposition) { - mCompositionCoverage |= CompositionCoverage::Gpu; + flags |= CompositionCoverage::Gpu; } clientCompositionRecord.predicted |= @@ -2699,10 +2714,11 @@ CompositeResult SurfaceFlinger::composite(scheduler::FrameTargeter& pacesetterFr (state.strategyPrediction == CompositionStrategyPredictionState::SUCCESS); } - const bool hasGpuComposited = mCompositionCoverage.test(CompositionCoverage::Gpu); + const auto coverage = multiDisplayUnion(mCompositionCoverage); + const bool hasGpuComposited = coverage.test(CompositionCoverage::Gpu); clientCompositionRecord.hadClientComposition = hasGpuComposited; - clientCompositionRecord.reused = mCompositionCoverage.test(CompositionCoverage::GpuReuse); + clientCompositionRecord.reused = coverage.test(CompositionCoverage::GpuReuse); clientCompositionRecord.changed = hadGpuComposited != hasGpuComposited; mTimeStats->pushCompositionStrategyState(clientCompositionRecord); @@ -2711,16 +2727,16 @@ CompositeResult SurfaceFlinger::composite(scheduler::FrameTargeter& pacesetterFr // TODO(b/160583065): Enable skip validation when SF caches all client composition layers. const bool hasGpuUseOrReuse = - mCompositionCoverage.any(CompositionCoverage::Gpu | CompositionCoverage::GpuReuse); + coverage.any(CompositionCoverage::Gpu | CompositionCoverage::GpuReuse); mScheduler->modulateVsync({}, &VsyncModulator::onDisplayRefresh, hasGpuUseOrReuse); mLayersWithQueuedFrames.clear(); if (mLayerTracingEnabled && mLayerTracing.flagIsSet(LayerTracing::TRACE_COMPOSITION)) { // This will block and should only be used for debugging. - addToLayerTracing(mVisibleRegionsDirty, pacesetterFrameTarget.frameBeginTime(), vsyncId); + addToLayerTracing(mVisibleRegionsDirty, pacesetterTarget.frameBeginTime(), vsyncId); } - updateInputFlinger(vsyncId, pacesetterFrameTarget.frameBeginTime()); + updateInputFlinger(vsyncId, pacesetterTarget.frameBeginTime()); if (mVisibleRegionsDirty) mHdrLayerInfoChanged = true; mVisibleRegionsDirty = false; @@ -2733,7 +2749,16 @@ CompositeResult SurfaceFlinger::composite(scheduler::FrameTargeter& pacesetterFr mPowerAdvisor->setCompositeEnd(TimePoint::now()); } - return {mCompositionCoverage}; + CompositeResultsPerDisplay resultsPerDisplay; + + // Filter out virtual displays. + for (const auto& [id, coverage] : mCompositionCoverage) { + if (const auto idOpt = PhysicalDisplayId::tryCast(id)) { + resultsPerDisplay.try_emplace(*idOpt, CompositeResult{coverage}); + } + } + + return resultsPerDisplay; } void SurfaceFlinger::updateLayerGeometry() { @@ -2817,35 +2842,56 @@ ui::Rotation SurfaceFlinger::getPhysicalDisplayOrientation(DisplayId displayId, return ui::ROTATION_0; } -void SurfaceFlinger::postComposition(scheduler::FrameTargeter& pacesetterFrameTargeter, +void SurfaceFlinger::postComposition(PhysicalDisplayId pacesetterId, + const scheduler::FrameTargeters& frameTargeters, nsecs_t presentStartTime) { ATRACE_CALL(); ALOGV(__func__); - const auto* defaultDisplay = FTL_FAKE_GUARD(mStateLock, getDefaultDisplayDeviceLocked()).get(); + ui::PhysicalDisplayMap<PhysicalDisplayId, std::shared_ptr<FenceTime>> presentFences; + ui::PhysicalDisplayMap<PhysicalDisplayId, const sp<Fence>> gpuCompositionDoneFences; - std::shared_ptr<FenceTime> glCompositionDoneFenceTime; - if (defaultDisplay && - defaultDisplay->getCompositionDisplay()->getState().usesClientComposition) { - glCompositionDoneFenceTime = - std::make_shared<FenceTime>(defaultDisplay->getCompositionDisplay() - ->getRenderSurface() - ->getClientTargetAcquireFence()); - } else { - glCompositionDoneFenceTime = FenceTime::NO_FENCE; + for (const auto& [id, targeter] : frameTargeters) { + auto presentFence = getHwComposer().getPresentFence(id); + + if (id == pacesetterId) { + mTransactionCallbackInvoker.addPresentFence(presentFence); + } + + if (auto fenceTime = targeter->setPresentFence(std::move(presentFence)); + fenceTime->isValid()) { + presentFences.try_emplace(id, std::move(fenceTime)); + } + + ftl::FakeGuard guard(mStateLock); + if (const auto display = getCompositionDisplayLocked(id); + display && display->getState().usesClientComposition) { + gpuCompositionDoneFences + .try_emplace(id, display->getRenderSurface()->getClientTargetAcquireFence()); + } } - auto presentFence = defaultDisplay - ? getHwComposer().getPresentFence(defaultDisplay->getPhysicalId()) - : Fence::NO_FENCE; + const auto pacesetterDisplay = FTL_FAKE_GUARD(mStateLock, getDisplayDeviceLocked(pacesetterId)); + + std::shared_ptr<FenceTime> pacesetterPresentFenceTime = + presentFences.get(pacesetterId) + .transform([](const FenceTimePtr& ptr) { return ptr; }) + .value_or(FenceTime::NO_FENCE); + + std::shared_ptr<FenceTime> pacesetterGpuCompositionDoneFenceTime = + gpuCompositionDoneFences.get(pacesetterId) + .transform([](sp<Fence> fence) { + return std::make_shared<FenceTime>(std::move(fence)); + }) + .value_or(FenceTime::NO_FENCE); - auto presentFenceTime = pacesetterFrameTargeter.setPresentFence(presentFence); const TimePoint presentTime = TimePoint::now(); // Set presentation information before calling Layer::releasePendingBuffer, such that jank // information from previous' frame classification is already available when sending jank info // to clients, so they get jank classification as early as possible. - mFrameTimeline->setSfPresent(presentTime.ns(), presentFenceTime, glCompositionDoneFenceTime); + mFrameTimeline->setSfPresent(presentTime.ns(), pacesetterPresentFenceTime, + pacesetterGpuCompositionDoneFenceTime); // We use the CompositionEngine::getLastFrameRefreshTimestamp() which might // be sampled a little later than when we started doing work for this frame, @@ -2853,9 +2899,9 @@ void SurfaceFlinger::postComposition(scheduler::FrameTargeter& pacesetterFrameTa const TimePoint compositeTime = TimePoint::fromNs(mCompositionEngine->getLastFrameRefreshTimestamp()); const Duration presentLatency = - !getHwComposer().hasCapability(Capability::PRESENT_FENCE_IS_NOT_RELIABLE) - ? mPresentLatencyTracker.trackPendingFrame(compositeTime, presentFenceTime) - : Duration::zero(); + getHwComposer().hasCapability(Capability::PRESENT_FENCE_IS_NOT_RELIABLE) + ? Duration::zero() + : mPresentLatencyTracker.trackPendingFrame(compositeTime, pacesetterPresentFenceTime); const auto schedule = mScheduler->getVsyncSchedule(); const TimePoint vsyncDeadline = schedule->vsyncDeadlineAfter(presentTime); @@ -2892,8 +2938,8 @@ void SurfaceFlinger::postComposition(scheduler::FrameTargeter& pacesetterFrameTa mLayersWithBuffersRemoved.clear(); for (const auto& layer: mLayersWithQueuedFrames) { - layer->onPostComposition(defaultDisplay, glCompositionDoneFenceTime, presentFenceTime, - compositorTiming); + layer->onPostComposition(pacesetterDisplay.get(), pacesetterGpuCompositionDoneFenceTime, + pacesetterPresentFenceTime, compositorTiming); layer->releasePendingBuffer(presentTime.ns()); } @@ -2980,38 +3026,32 @@ void SurfaceFlinger::postComposition(scheduler::FrameTargeter& pacesetterFrameTa mHdrLayerInfoChanged = false; - mTransactionCallbackInvoker.addPresentFence(std::move(presentFence)); mTransactionCallbackInvoker.sendCallbacks(false /* onCommitOnly */); mTransactionCallbackInvoker.clearCompletedTransactions(); mTimeStats->incrementTotalFrames(); - mTimeStats->setPresentFenceGlobal(presentFenceTime); + mTimeStats->setPresentFenceGlobal(pacesetterPresentFenceTime); - { + for (auto&& [id, presentFence] : presentFences) { ftl::FakeGuard guard(mStateLock); - for (const auto& [id, physicalDisplay] : mPhysicalDisplays) { - if (auto displayDevice = getDisplayDeviceLocked(id); - displayDevice && displayDevice->isPoweredOn() && physicalDisplay.isInternal()) { - auto presentFenceTimeI = defaultDisplay && defaultDisplay->getPhysicalId() == id - ? std::move(presentFenceTime) - : std::make_shared<FenceTime>(getHwComposer().getPresentFence(id)); - if (presentFenceTimeI->isValid()) { - mScheduler->addPresentFence(id, std::move(presentFenceTimeI)); - } - } + const bool isInternalDisplay = + mPhysicalDisplays.get(id).transform(&PhysicalDisplay::isInternal).value_or(false); + + if (isInternalDisplay) { + mScheduler->addPresentFence(id, std::move(presentFence)); } } - const bool isDisplayConnected = - defaultDisplay && getHwComposer().isConnected(defaultDisplay->getPhysicalId()); + const bool hasPacesetterDisplay = + pacesetterDisplay && getHwComposer().isConnected(pacesetterId); if (!hasSyncFramework) { - if (isDisplayConnected && defaultDisplay->isPoweredOn()) { - mScheduler->enableHardwareVsync(defaultDisplay->getPhysicalId()); + if (hasPacesetterDisplay && pacesetterDisplay->isPoweredOn()) { + mScheduler->enableHardwareVsync(pacesetterId); } } - if (isDisplayConnected && !defaultDisplay->isPoweredOn()) { + if (hasPacesetterDisplay && !pacesetterDisplay->isPoweredOn()) { getRenderEngine().cleanupPostRender(); return; } @@ -4298,7 +4338,7 @@ TransactionHandler::TransactionReadiness SurfaceFlinger::transactionReadyTimelin const auto& transaction = *flushState.transaction; const TimePoint desiredPresentTime = TimePoint::fromNs(transaction.desiredPresentTime); - const TimePoint expectedPresentTime = mScheduler->pacesetterFrameTarget().expectedPresentTime(); + const TimePoint expectedPresentTime = mScheduler->expectedPresentTimeForPacesetter(); using TransactionReadiness = TransactionHandler::TransactionReadiness; @@ -6347,8 +6387,7 @@ void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, const std::string& comp ftl::to_underlying(windowInfosDebug.maxSendDelayVsyncId)); StringAppendF(&result, " max send delay (ns): %" PRId64 " ns\n", windowInfosDebug.maxSendDelayDuration); - StringAppendF(&result, " unsent messages: %" PRIu32 "\n", - windowInfosDebug.pendingMessageCount); + StringAppendF(&result, " unsent messages: %zu\n", windowInfosDebug.pendingMessageCount); result.append("\n"); } @@ -7629,7 +7668,10 @@ ftl::SharedFuture<FenceResult> SurfaceFlinger::renderScreenImpl( renderArea->getHintForSeamlessTransition()); sdrWhitePointNits = state.sdrWhitePointNits; displayBrightnessNits = state.displayBrightnessNits; - if (sdrWhitePointNits > 1.0f) { + // Only clamp the display brightness if this is not a seamless transition. Otherwise + // for seamless transitions it's important to match the current display state as the + // buffer will be shown under these same conditions, and we want to avoid any flickers + if (sdrWhitePointNits > 1.0f && !renderArea->getHintForSeamlessTransition()) { // Restrict the amount of HDR "headroom" in the screenshot to avoid over-dimming // the SDR portion. 2.0 chosen by experimentation constexpr float kMaxScreenshotHeadroom = 2.0f; @@ -7880,7 +7922,13 @@ status_t SurfaceFlinger::applyRefreshRateSelectorPolicy( return INVALID_OPERATION; } - setDesiredActiveMode({std::move(preferredMode), .emitEvent = true}, force); + setDesiredActiveMode({preferredMode, .emitEvent = true}, force); + + // Update the frameRateOverride list as the display render rate might have changed + if (mScheduler->updateFrameRateOverrides(/*consideredSignals*/ {}, preferredMode.fps)) { + triggerOnFrameRateOverridesChanged(); + } + return NO_ERROR; } @@ -8214,9 +8262,9 @@ void SurfaceFlinger::onActiveDisplayChangedLocked(const DisplayDevice* inactiveD forceApplyPolicy); } -status_t SurfaceFlinger::addWindowInfosListener( - const sp<IWindowInfosListener>& windowInfosListener) { - mWindowInfosListenerInvoker->addWindowInfosListener(windowInfosListener); +status_t SurfaceFlinger::addWindowInfosListener(const sp<IWindowInfosListener>& windowInfosListener, + gui::WindowInfosListenerInfo* outInfo) { + mWindowInfosListenerInvoker->addWindowInfosListener(windowInfosListener, outInfo); setTransactionFlags(eInputInfoUpdateNeeded); return NO_ERROR; } @@ -9300,7 +9348,8 @@ binder::Status SurfaceComposerAIDL::getMaxAcquiredBufferCount(int32_t* buffers) } binder::Status SurfaceComposerAIDL::addWindowInfosListener( - const sp<gui::IWindowInfosListener>& windowInfosListener) { + const sp<gui::IWindowInfosListener>& windowInfosListener, + gui::WindowInfosListenerInfo* outInfo) { status_t status; const int pid = IPCThreadState::self()->getCallingPid(); const int uid = IPCThreadState::self()->getCallingUid(); @@ -9308,7 +9357,7 @@ binder::Status SurfaceComposerAIDL::addWindowInfosListener( // WindowInfosListeners if (uid == AID_SYSTEM || uid == AID_GRAPHICS || checkPermission(sAccessSurfaceFlinger, pid, uid)) { - status = mFlinger->addWindowInfosListener(windowInfosListener); + status = mFlinger->addWindowInfosListener(windowInfosListener, outInfo); } else { status = PERMISSION_DENIED; } diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index aeaeb47210..d1b6660063 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -617,7 +617,8 @@ private: status_t getMaxAcquiredBufferCount(int* buffers) const; - status_t addWindowInfosListener(const sp<gui::IWindowInfosListener>& windowInfosListener); + status_t addWindowInfosListener(const sp<gui::IWindowInfosListener>& windowInfosListener, + gui::WindowInfosListenerInfo* outResult); status_t removeWindowInfosListener( const sp<gui::IWindowInfosListener>& windowInfosListener) const; @@ -636,9 +637,12 @@ private: void onRefreshRateChangedDebug(const RefreshRateChangedDebugData&) override; // ICompositor overrides: - void configure() override; - bool commit(const scheduler::FrameTarget&) override; - CompositeResult composite(scheduler::FrameTargeter&) override; + void configure() override REQUIRES(kMainThreadContext); + bool commit(const scheduler::FrameTarget&) override REQUIRES(kMainThreadContext); + CompositeResultsPerDisplay composite(PhysicalDisplayId pacesetterId, + const scheduler::FrameTargeters&) override + REQUIRES(kMainThreadContext); + void sample() override; // ISchedulerCallback overrides: @@ -891,6 +895,14 @@ private: return findDisplay([id](const auto& display) { return display.getId() == id; }); } + std::shared_ptr<compositionengine::Display> getCompositionDisplayLocked(DisplayId id) const + REQUIRES(mStateLock) { + if (const auto display = getDisplayDeviceLocked(id)) { + return display->getCompositionDisplay(); + } + return nullptr; + } + // Returns the primary display or (for foldables) the active display, assuming that the inner // and outer displays have mutually exclusive power states. sp<const DisplayDevice> getDefaultDisplayDeviceLocked() const REQUIRES(mStateLock) { @@ -964,8 +976,8 @@ private: /* * Compositing */ - void postComposition(scheduler::FrameTargeter&, nsecs_t presentStartTime) - REQUIRES(kMainThreadContext); + void postComposition(PhysicalDisplayId pacesetterId, const scheduler::FrameTargeters&, + nsecs_t presentStartTime) REQUIRES(kMainThreadContext); /* * Display management @@ -1298,7 +1310,7 @@ private: std::unique_ptr<compositionengine::CompositionEngine> mCompositionEngine; - CompositionCoverageFlags mCompositionCoverage; + CompositionCoveragePerDisplay mCompositionCoverage; // mMaxRenderTargetSize is only set once in init() so it doesn't need to be protected by // any mutex. @@ -1541,8 +1553,8 @@ public: binder::Status setOverrideFrameRate(int32_t uid, float frameRate) override; binder::Status getGpuContextPriority(int32_t* outPriority) override; binder::Status getMaxAcquiredBufferCount(int32_t* buffers) override; - binder::Status addWindowInfosListener( - const sp<gui::IWindowInfosListener>& windowInfosListener) override; + binder::Status addWindowInfosListener(const sp<gui::IWindowInfosListener>& windowInfosListener, + gui::WindowInfosListenerInfo* outInfo) override; binder::Status removeWindowInfosListener( const sp<gui::IWindowInfosListener>& windowInfosListener) override; diff --git a/services/surfaceflinger/WindowInfosListenerInvoker.cpp b/services/surfaceflinger/WindowInfosListenerInvoker.cpp index 20699ef123..7062a4e3a7 100644 --- a/services/surfaceflinger/WindowInfosListenerInvoker.cpp +++ b/services/surfaceflinger/WindowInfosListenerInvoker.cpp @@ -14,7 +14,9 @@ * limitations under the License. */ -#include <ftl/small_vector.h> +#include <android/gui/BnWindowInfosPublisher.h> +#include <android/gui/IWindowInfosPublisher.h> +#include <android/gui/WindowInfosListenerInfo.h> #include <gui/ISurfaceComposer.h> #include <gui/TraceUtils.h> #include <gui/WindowInfosUpdate.h> @@ -23,162 +25,130 @@ #include "BackgroundExecutor.h" #include "WindowInfosListenerInvoker.h" +#undef ATRACE_TAG +#define ATRACE_TAG ATRACE_TAG_GRAPHICS + namespace android { using gui::DisplayInfo; using gui::IWindowInfosListener; using gui::WindowInfo; -using WindowInfosListenerVector = ftl::SmallVector<const sp<gui::IWindowInfosListener>, 3>; - -struct WindowInfosReportedListenerInvoker : gui::BnWindowInfosReportedListener, - IBinder::DeathRecipient { - WindowInfosReportedListenerInvoker(WindowInfosListenerVector windowInfosListeners, - WindowInfosReportedListenerSet windowInfosReportedListeners) - : mCallbacksPending(windowInfosListeners.size()), - mWindowInfosListeners(std::move(windowInfosListeners)), - mWindowInfosReportedListeners(std::move(windowInfosReportedListeners)) {} +void WindowInfosListenerInvoker::addWindowInfosListener(sp<IWindowInfosListener> listener, + gui::WindowInfosListenerInfo* outInfo) { + int64_t listenerId = mNextListenerId++; + outInfo->listenerId = listenerId; + outInfo->windowInfosPublisher = sp<gui::IWindowInfosPublisher>::fromExisting(this); - binder::Status onWindowInfosReported() override { - if (--mCallbacksPending == 0) { - for (const auto& listener : mWindowInfosReportedListeners) { + BackgroundExecutor::getInstance().sendCallbacks( + {[this, listener = std::move(listener), listenerId]() { + ATRACE_NAME("WindowInfosListenerInvoker::addWindowInfosListener"); sp<IBinder> asBinder = IInterface::asBinder(listener); - if (asBinder->isBinderAlive()) { - listener->onWindowInfosReported(); - } - } - - auto wpThis = wp<WindowInfosReportedListenerInvoker>::fromExisting(this); - for (const auto& listener : mWindowInfosListeners) { - sp<IBinder> binder = IInterface::asBinder(listener); - binder->unlinkToDeath(wpThis); - } - } - return binder::Status::ok(); - } - - void binderDied(const wp<IBinder>&) { onWindowInfosReported(); } - -private: - std::atomic<size_t> mCallbacksPending; - static constexpr size_t kStaticCapacity = 3; - const WindowInfosListenerVector mWindowInfosListeners; - WindowInfosReportedListenerSet mWindowInfosReportedListeners; -}; - -void WindowInfosListenerInvoker::addWindowInfosListener(sp<IWindowInfosListener> listener) { - sp<IBinder> asBinder = IInterface::asBinder(listener); - asBinder->linkToDeath(sp<DeathRecipient>::fromExisting(this)); - - std::scoped_lock lock(mListenersMutex); - mWindowInfosListeners.try_emplace(asBinder, std::move(listener)); + asBinder->linkToDeath(sp<DeathRecipient>::fromExisting(this)); + mWindowInfosListeners.try_emplace(asBinder, + std::make_pair(listenerId, std::move(listener))); + }}); } void WindowInfosListenerInvoker::removeWindowInfosListener( const sp<IWindowInfosListener>& listener) { - sp<IBinder> asBinder = IInterface::asBinder(listener); - - std::scoped_lock lock(mListenersMutex); - asBinder->unlinkToDeath(sp<DeathRecipient>::fromExisting(this)); - mWindowInfosListeners.erase(asBinder); + BackgroundExecutor::getInstance().sendCallbacks({[this, listener]() { + ATRACE_NAME("WindowInfosListenerInvoker::removeWindowInfosListener"); + sp<IBinder> asBinder = IInterface::asBinder(listener); + asBinder->unlinkToDeath(sp<DeathRecipient>::fromExisting(this)); + mWindowInfosListeners.erase(asBinder); + }}); } void WindowInfosListenerInvoker::binderDied(const wp<IBinder>& who) { - std::scoped_lock lock(mListenersMutex); - mWindowInfosListeners.erase(who); + BackgroundExecutor::getInstance().sendCallbacks({[this, who]() { + ATRACE_NAME("WindowInfosListenerInvoker::binderDied"); + auto it = mWindowInfosListeners.find(who); + int64_t listenerId = it->second.first; + mWindowInfosListeners.erase(who); + + std::vector<int64_t> vsyncIds; + for (auto& [vsyncId, state] : mUnackedState) { + if (std::find(state.unackedListenerIds.begin(), state.unackedListenerIds.end(), + listenerId) != state.unackedListenerIds.end()) { + vsyncIds.push_back(vsyncId); + } + } + + for (int64_t vsyncId : vsyncIds) { + ackWindowInfosReceived(vsyncId, listenerId); + } + }}); } void WindowInfosListenerInvoker::windowInfosChanged( gui::WindowInfosUpdate update, WindowInfosReportedListenerSet reportedListeners, bool forceImmediateCall) { - WindowInfosListenerVector listeners; - { - std::scoped_lock lock{mMessagesMutex}; - - if (!mDelayInfo) { - mDelayInfo = DelayInfo{ - .vsyncId = update.vsyncId, - .frameTime = update.timestamp, - }; - } - - // If there are unacked messages and this isn't a forced call, then return immediately. - // If a forced window infos change doesn't happen first, the update will be sent after - // the WindowInfosReportedListeners are called. If a forced window infos change happens or - // if there are subsequent delayed messages before this update is sent, then this message - // will be dropped and the listeners will only be called with the latest info. This is done - // to reduce the amount of binder memory used. - if (mActiveMessageCount > 0 && !forceImmediateCall) { - mDelayedUpdate = std::move(update); - mReportedListeners.merge(reportedListeners); - return; - } - - if (mDelayedUpdate) { - mDelayedUpdate.reset(); - } + if (!mDelayInfo) { + mDelayInfo = DelayInfo{ + .vsyncId = update.vsyncId, + .frameTime = update.timestamp, + }; + } - { - std::scoped_lock lock{mListenersMutex}; - for (const auto& [_, listener] : mWindowInfosListeners) { - listeners.push_back(listener); - } - } - if (CC_UNLIKELY(listeners.empty())) { - mReportedListeners.merge(reportedListeners); - mDelayInfo.reset(); - return; - } + // If there are unacked messages and this isn't a forced call, then return immediately. + // If a forced window infos change doesn't happen first, the update will be sent after + // the WindowInfosReportedListeners are called. If a forced window infos change happens or + // if there are subsequent delayed messages before this update is sent, then this message + // will be dropped and the listeners will only be called with the latest info. This is done + // to reduce the amount of binder memory used. + if (!mUnackedState.empty() && !forceImmediateCall) { + mDelayedUpdate = std::move(update); + mReportedListeners.merge(reportedListeners); + return; + } - reportedListeners.insert(sp<WindowInfosListenerInvoker>::fromExisting(this)); - reportedListeners.merge(mReportedListeners); - mReportedListeners.clear(); + if (mDelayedUpdate) { + mDelayedUpdate.reset(); + } - mActiveMessageCount++; - updateMaxSendDelay(); + if (CC_UNLIKELY(mWindowInfosListeners.empty())) { + mReportedListeners.merge(reportedListeners); mDelayInfo.reset(); + return; } - auto reportedInvoker = - sp<WindowInfosReportedListenerInvoker>::make(listeners, std::move(reportedListeners)); - - for (const auto& listener : listeners) { - sp<IBinder> asBinder = IInterface::asBinder(listener); + reportedListeners.merge(mReportedListeners); + mReportedListeners.clear(); + + // Update mUnackedState to include the message we're about to send + auto [it, _] = mUnackedState.try_emplace(update.vsyncId, + UnackedState{.reportedListeners = + std::move(reportedListeners)}); + auto& unackedState = it->second; + for (auto& pair : mWindowInfosListeners) { + int64_t listenerId = pair.second.first; + unackedState.unackedListenerIds.push_back(listenerId); + } - // linkToDeath is used here to ensure that the windowInfosReportedListeners - // are called even if one of the windowInfosListeners dies before - // calling onWindowInfosReported. - asBinder->linkToDeath(reportedInvoker); + mDelayInfo.reset(); + updateMaxSendDelay(); - auto status = listener->onWindowInfosChanged(update, reportedInvoker); + // Call the listeners + for (auto& pair : mWindowInfosListeners) { + auto& [listenerId, listener] = pair.second; + auto status = listener->onWindowInfosChanged(update); if (!status.isOk()) { - reportedInvoker->onWindowInfosReported(); + ackWindowInfosReceived(update.vsyncId, listenerId); } } } -binder::Status WindowInfosListenerInvoker::onWindowInfosReported() { - BackgroundExecutor::getInstance().sendCallbacks({[this]() { - gui::WindowInfosUpdate update; - { - std::scoped_lock lock{mMessagesMutex}; - mActiveMessageCount--; - if (!mDelayedUpdate || mActiveMessageCount > 0) { - return; - } - update = std::move(*mDelayedUpdate); - mDelayedUpdate.reset(); - } - windowInfosChanged(std::move(update), {}, false); - }}); - return binder::Status::ok(); -} - WindowInfosListenerInvoker::DebugInfo WindowInfosListenerInvoker::getDebugInfo() { - std::scoped_lock lock{mMessagesMutex}; - updateMaxSendDelay(); - mDebugInfo.pendingMessageCount = mActiveMessageCount; - return mDebugInfo; + DebugInfo result; + BackgroundExecutor::getInstance().sendCallbacks({[&, this]() { + ATRACE_NAME("WindowInfosListenerInvoker::getDebugInfo"); + updateMaxSendDelay(); + result = mDebugInfo; + result.pendingMessageCount = mUnackedState.size(); + }}); + BackgroundExecutor::getInstance().flushQueue(); + return result; } void WindowInfosListenerInvoker::updateMaxSendDelay() { @@ -192,4 +162,41 @@ void WindowInfosListenerInvoker::updateMaxSendDelay() { } } +binder::Status WindowInfosListenerInvoker::ackWindowInfosReceived(int64_t vsyncId, + int64_t listenerId) { + BackgroundExecutor::getInstance().sendCallbacks({[this, vsyncId, listenerId]() { + ATRACE_NAME("WindowInfosListenerInvoker::ackWindowInfosReceived"); + auto it = mUnackedState.find(vsyncId); + if (it == mUnackedState.end()) { + return; + } + + auto& state = it->second; + state.unackedListenerIds.unstable_erase(std::find(state.unackedListenerIds.begin(), + state.unackedListenerIds.end(), + listenerId)); + if (!state.unackedListenerIds.empty()) { + return; + } + + WindowInfosReportedListenerSet reportedListeners{std::move(state.reportedListeners)}; + mUnackedState.erase(vsyncId); + + for (const auto& reportedListener : reportedListeners) { + sp<IBinder> asBinder = IInterface::asBinder(reportedListener); + if (asBinder->isBinderAlive()) { + reportedListener->onWindowInfosReported(); + } + } + + if (!mDelayedUpdate || !mUnackedState.empty()) { + return; + } + gui::WindowInfosUpdate update{std::move(*mDelayedUpdate)}; + mDelayedUpdate.reset(); + windowInfosChanged(std::move(update), {}, false); + }}); + return binder::Status::ok(); +} + } // namespace android diff --git a/services/surfaceflinger/WindowInfosListenerInvoker.h b/services/surfaceflinger/WindowInfosListenerInvoker.h index bc465a3a2b..f36b0edd7d 100644 --- a/services/surfaceflinger/WindowInfosListenerInvoker.h +++ b/services/surfaceflinger/WindowInfosListenerInvoker.h @@ -19,11 +19,12 @@ #include <optional> #include <unordered_set> -#include <android/gui/BnWindowInfosReportedListener.h> +#include <android/gui/BnWindowInfosPublisher.h> #include <android/gui/IWindowInfosListener.h> #include <android/gui/IWindowInfosReportedListener.h> #include <binder/IBinder.h> #include <ftl/small_map.h> +#include <ftl/small_vector.h> #include <gui/SpHash.h> #include <utils/Mutex.h> @@ -35,22 +36,22 @@ using WindowInfosReportedListenerSet = std::unordered_set<sp<gui::IWindowInfosReportedListener>, gui::SpHash<gui::IWindowInfosReportedListener>>; -class WindowInfosListenerInvoker : public gui::BnWindowInfosReportedListener, +class WindowInfosListenerInvoker : public gui::BnWindowInfosPublisher, public IBinder::DeathRecipient { public: - void addWindowInfosListener(sp<gui::IWindowInfosListener>); + void addWindowInfosListener(sp<gui::IWindowInfosListener>, gui::WindowInfosListenerInfo*); void removeWindowInfosListener(const sp<gui::IWindowInfosListener>& windowInfosListener); void windowInfosChanged(gui::WindowInfosUpdate update, WindowInfosReportedListenerSet windowInfosReportedListeners, bool forceImmediateCall); - binder::Status onWindowInfosReported() override; + binder::Status ackWindowInfosReceived(int64_t, int64_t) override; struct DebugInfo { VsyncId maxSendDelayVsyncId; nsecs_t maxSendDelayDuration; - uint32_t pendingMessageCount; + size_t pendingMessageCount; }; DebugInfo getDebugInfo(); @@ -58,24 +59,28 @@ protected: void binderDied(const wp<IBinder>& who) override; private: - std::mutex mListenersMutex; - static constexpr size_t kStaticCapacity = 3; - ftl::SmallMap<wp<IBinder>, const sp<gui::IWindowInfosListener>, kStaticCapacity> - mWindowInfosListeners GUARDED_BY(mListenersMutex); + std::atomic<int64_t> mNextListenerId{0}; + ftl::SmallMap<wp<IBinder>, const std::pair<int64_t, sp<gui::IWindowInfosListener>>, + kStaticCapacity> + mWindowInfosListeners; - std::mutex mMessagesMutex; - uint32_t mActiveMessageCount GUARDED_BY(mMessagesMutex) = 0; - std::optional<gui::WindowInfosUpdate> mDelayedUpdate GUARDED_BY(mMessagesMutex); + std::optional<gui::WindowInfosUpdate> mDelayedUpdate; WindowInfosReportedListenerSet mReportedListeners; - DebugInfo mDebugInfo GUARDED_BY(mMessagesMutex); + struct UnackedState { + ftl::SmallVector<int64_t, kStaticCapacity> unackedListenerIds; + WindowInfosReportedListenerSet reportedListeners; + }; + ftl::SmallMap<int64_t /* vsyncId */, UnackedState, 5> mUnackedState; + + DebugInfo mDebugInfo; struct DelayInfo { int64_t vsyncId; nsecs_t frameTime; }; - std::optional<DelayInfo> mDelayInfo GUARDED_BY(mMessagesMutex); - void updateMaxSendDelay() REQUIRES(mMessagesMutex); + std::optional<DelayInfo> mDelayInfo; + void updateMaxSendDelay(); }; } // namespace android diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h index 00e92a18ff..28ac664ba3 100644 --- a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h +++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h @@ -287,7 +287,10 @@ private: // ICompositor overrides: void configure() override {} bool commit(const scheduler::FrameTarget&) override { return false; } - CompositeResult composite(scheduler::FrameTargeter&) override { return {}; } + CompositeResultsPerDisplay composite(PhysicalDisplayId, + const scheduler::FrameTargeters&) override { + return {}; + } void sample() override {} // MessageQueue overrides: @@ -474,25 +477,25 @@ public: &outWideColorGamutPixelFormat); } - void overrideHdrTypes(sp<IBinder> &display, FuzzedDataProvider *fdp) { + void overrideHdrTypes(const sp<IBinder>& display, FuzzedDataProvider* fdp) { std::vector<ui::Hdr> hdrTypes; hdrTypes.push_back(fdp->PickValueInArray(kHdrTypes)); mFlinger->overrideHdrTypes(display, hdrTypes); } - void getDisplayedContentSample(sp<IBinder> &display, FuzzedDataProvider *fdp) { + void getDisplayedContentSample(const sp<IBinder>& display, FuzzedDataProvider* fdp) { DisplayedFrameStats outDisplayedFrameStats; mFlinger->getDisplayedContentSample(display, fdp->ConsumeIntegral<uint64_t>(), fdp->ConsumeIntegral<uint64_t>(), &outDisplayedFrameStats); } - void getDisplayStats(sp<IBinder> &display) { + void getDisplayStats(const sp<IBinder>& display) { android::DisplayStatInfo stats; mFlinger->getDisplayStats(display, &stats); } - void getDisplayState(sp<IBinder> &display) { + void getDisplayState(const sp<IBinder>& display) { ui::DisplayState displayState; mFlinger->getDisplayState(display, &displayState); } @@ -506,12 +509,12 @@ public: android::ui::DynamicDisplayInfo dynamicDisplayInfo; mFlinger->getDynamicDisplayInfoFromId(displayId, &dynamicDisplayInfo); } - void getDisplayNativePrimaries(sp<IBinder> &display) { + void getDisplayNativePrimaries(const sp<IBinder>& display) { android::ui::DisplayPrimaries displayPrimaries; mFlinger->getDisplayNativePrimaries(display, displayPrimaries); } - void getDesiredDisplayModeSpecs(sp<IBinder> &display) { + void getDesiredDisplayModeSpecs(const sp<IBinder>& display) { gui::DisplayModeSpecs _; mFlinger->getDesiredDisplayModeSpecs(display, &_); } @@ -523,7 +526,7 @@ public: return ids.front(); } - std::pair<sp<IBinder>, int64_t> fuzzBoot(FuzzedDataProvider *fdp) { + std::pair<sp<IBinder>, PhysicalDisplayId> fuzzBoot(FuzzedDataProvider* fdp) { mFlinger->callingThreadHasUnscopedSurfaceFlingerAccess(fdp->ConsumeBool()); const sp<Client> client = sp<Client>::make(mFlinger); @@ -550,13 +553,13 @@ public: mFlinger->bootFinished(); - return {display, physicalDisplayId.value}; + return {display, physicalDisplayId}; } void fuzzSurfaceFlinger(const uint8_t *data, size_t size) { FuzzedDataProvider mFdp(data, size); - auto [display, displayId] = fuzzBoot(&mFdp); + const auto [display, displayId] = fuzzBoot(&mFdp); sp<IGraphicBufferProducer> bufferProducer = sp<mock::GraphicBufferProducer>::make(); @@ -564,8 +567,8 @@ public: getDisplayStats(display); getDisplayState(display); - getStaticDisplayInfo(displayId); - getDynamicDisplayInfo(displayId); + getStaticDisplayInfo(displayId.value); + getDynamicDisplayInfo(displayId.value); getDisplayNativePrimaries(display); mFlinger->setAutoLowLatencyMode(display, mFdp.ConsumeBool()); @@ -605,8 +608,9 @@ public: mFlinger->commitTransactions(); mFlinger->flushTransactionQueues(getFuzzedVsyncId(mFdp)); - scheduler::FrameTargeter frameTargeter(mFdp.ConsumeBool()); - mFlinger->postComposition(frameTargeter, mFdp.ConsumeIntegral<nsecs_t>()); + scheduler::FrameTargeter frameTargeter(displayId, mFdp.ConsumeBool()); + mFlinger->postComposition(displayId, ftl::init::map(displayId, &frameTargeter), + mFdp.ConsumeIntegral<nsecs_t>()); } mFlinger->setTransactionFlags(mFdp.ConsumeIntegral<uint32_t>()); diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp index b1fd06f998..4d1a5ffa67 100644 --- a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp +++ b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp @@ -50,7 +50,7 @@ constexpr PowerMode kPowerModes[] = {PowerMode::ON, PowerMode::DOZE, PowerMode:: constexpr uint16_t kRandomStringLength = 256; constexpr std::chrono::duration kSyncPeriod(16ms); -constexpr PhysicalDisplayId DEFAULT_DISPLAY_ID = PhysicalDisplayId::fromPort(42u); +constexpr PhysicalDisplayId kDisplayId = PhysicalDisplayId::fromPort(42u); template <typename T> void dump(T* component, FuzzedDataProvider* fdp) { @@ -177,9 +177,8 @@ void SchedulerFuzzer::fuzzVSyncPredictor() { uint16_t now = mFdp.ConsumeIntegral<uint16_t>(); uint16_t historySize = mFdp.ConsumeIntegralInRange<uint16_t>(1, UINT16_MAX); uint16_t minimumSamplesForPrediction = mFdp.ConsumeIntegralInRange<uint16_t>(1, UINT16_MAX); - scheduler::VSyncPredictor tracker{DEFAULT_DISPLAY_ID, - mFdp.ConsumeIntegral<uint16_t>() /*period*/, historySize, - minimumSamplesForPrediction, + scheduler::VSyncPredictor tracker{kDisplayId, mFdp.ConsumeIntegral<uint16_t>() /*period*/, + historySize, minimumSamplesForPrediction, mFdp.ConsumeIntegral<uint32_t>() /*outlierTolerancePercent*/}; uint16_t period = mFdp.ConsumeIntegral<uint16_t>(); tracker.setPeriod(period); @@ -251,7 +250,7 @@ void SchedulerFuzzer::fuzzLayerHistory() { void SchedulerFuzzer::fuzzVSyncReactor() { std::shared_ptr<FuzzImplVSyncTracker> vSyncTracker = std::make_shared<FuzzImplVSyncTracker>(); - scheduler::VSyncReactor reactor(DEFAULT_DISPLAY_ID, + scheduler::VSyncReactor reactor(kDisplayId, std::make_unique<ClockWrapper>( std::make_shared<FuzzImplClock>()), *vSyncTracker, mFdp.ConsumeIntegral<uint8_t>() /*pendingLimit*/, @@ -408,7 +407,7 @@ void SchedulerFuzzer::fuzzPresentLatencyTracker() { } void SchedulerFuzzer::fuzzFrameTargeter() { - scheduler::FrameTargeter frameTargeter(mFdp.ConsumeBool()); + scheduler::FrameTargeter frameTargeter(kDisplayId, mFdp.ConsumeBool()); const struct VsyncSource final : scheduler::IVsyncSource { explicit VsyncSource(FuzzedDataProvider& fuzzer) : fuzzer(fuzzer) {} diff --git a/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp b/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp index 359e2ab7fb..1dcf222834 100644 --- a/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp +++ b/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp @@ -36,7 +36,10 @@ using CallbackToken = scheduler::VSyncDispatch::CallbackToken; struct NoOpCompositor final : ICompositor { void configure() override {} bool commit(const scheduler::FrameTarget&) override { return false; } - CompositeResult composite(scheduler::FrameTargeter&) override { return {}; } + CompositeResultsPerDisplay composite(PhysicalDisplayId, + const scheduler::FrameTargeters&) override { + return {}; + } void sample() override {} } gNoOpCompositor; diff --git a/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp index d63e187ac4..646d9cc0a0 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp @@ -3042,5 +3042,20 @@ TEST_P(RefreshRateSelectorTest, frameRateNotInRange) { EXPECT_FRAME_RATE_MODE(kMode60, 60_Hz, selector.getBestScoredFrameRate(layers).frameRateMode); } +TEST_P(RefreshRateSelectorTest, frameRateIsLowerThanMinSupported) { + if (GetParam() != Config::FrameRateOverride::Enabled) { + return; + } + + auto selector = createSelector(kModes_60_90, kModeId60); + + constexpr Fps kMin = RefreshRateSelector::kMinSupportedFrameRate; + constexpr FpsRanges kLowerThanMin = {{60_Hz, 90_Hz}, {kMin / 2, kMin / 2}}; + + EXPECT_EQ(SetPolicyResult::Changed, + selector.setDisplayManagerPolicy( + {DisplayModeId(kModeId60), kLowerThanMin, kLowerThanMin})); +} + } // namespace } // namespace android::scheduler diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h index fa7a94735f..f3c9d0dd44 100644 --- a/services/surfaceflinger/tests/unittests/TestableScheduler.h +++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h @@ -181,7 +181,10 @@ private: // ICompositor overrides: void configure() override {} bool commit(const scheduler::FrameTarget&) override { return false; } - CompositeResult composite(scheduler::FrameTargeter&) override { return {}; } + CompositeResultsPerDisplay composite(PhysicalDisplayId, + const scheduler::FrameTargeters&) override { + return {}; + } void sample() override {} }; diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index 909b8b8964..9b3a893409 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -359,7 +359,10 @@ public: * Forwarding for functions being tested */ - void configure() { mFlinger->configure(); } + void configure() { + ftl::FakeGuard guard(kMainThreadContext); + mFlinger->configure(); + } void configureAndCommit() { configure(); @@ -368,8 +371,14 @@ public: void commit(TimePoint frameTime, VsyncId vsyncId, TimePoint expectedVsyncTime, bool composite = false) { + ftl::FakeGuard guard(kMainThreadContext); + + const auto displayIdOpt = mScheduler->pacesetterDisplayId(); + LOG_ALWAYS_FATAL_IF(!displayIdOpt); + const auto displayId = *displayIdOpt; + constexpr bool kBackpressureGpuComposition = true; - scheduler::FrameTargeter frameTargeter(kBackpressureGpuComposition); + scheduler::FrameTargeter frameTargeter(displayId, kBackpressureGpuComposition); frameTargeter.beginFrame({.frameBeginTime = frameTime, .vsyncId = vsyncId, @@ -380,7 +389,7 @@ public: mFlinger->commit(frameTargeter.target()); if (composite) { - mFlinger->composite(frameTargeter); + mFlinger->composite(displayId, ftl::init::map(displayId, &frameTargeter)); } } diff --git a/services/surfaceflinger/tests/unittests/WindowInfosListenerInvokerTest.cpp b/services/surfaceflinger/tests/unittests/WindowInfosListenerInvokerTest.cpp index af4971b063..c7b845e668 100644 --- a/services/surfaceflinger/tests/unittests/WindowInfosListenerInvokerTest.cpp +++ b/services/surfaceflinger/tests/unittests/WindowInfosListenerInvokerTest.cpp @@ -15,35 +15,23 @@ protected: WindowInfosListenerInvokerTest() : mInvoker(sp<WindowInfosListenerInvoker>::make()) {} ~WindowInfosListenerInvokerTest() { - std::mutex mutex; - std::condition_variable cv; - bool flushComplete = false; // Flush the BackgroundExecutor thread to ensure any scheduled tasks are complete. // Otherwise, references those tasks hold may go out of scope before they are done // executing. - BackgroundExecutor::getInstance().sendCallbacks({[&]() { - std::scoped_lock lock{mutex}; - flushComplete = true; - cv.notify_one(); - }}); - std::unique_lock<std::mutex> lock{mutex}; - cv.wait(lock, [&]() { return flushComplete; }); + BackgroundExecutor::getInstance().flushQueue(); } sp<WindowInfosListenerInvoker> mInvoker; }; -using WindowInfosUpdateConsumer = std::function<void(const gui::WindowInfosUpdate&, - const sp<gui::IWindowInfosReportedListener>&)>; +using WindowInfosUpdateConsumer = std::function<void(const gui::WindowInfosUpdate&)>; class Listener : public gui::BnWindowInfosListener { public: Listener(WindowInfosUpdateConsumer consumer) : mConsumer(std::move(consumer)) {} - binder::Status onWindowInfosChanged( - const gui::WindowInfosUpdate& update, - const sp<gui::IWindowInfosReportedListener>& reportedListener) override { - mConsumer(update, reportedListener); + binder::Status onWindowInfosChanged(const gui::WindowInfosUpdate& update) override { + mConsumer(update); return binder::Status::ok(); } @@ -58,15 +46,17 @@ TEST_F(WindowInfosListenerInvokerTest, callsSingleListener) { int callCount = 0; - mInvoker->addWindowInfosListener( - sp<Listener>::make([&](const gui::WindowInfosUpdate&, - const sp<gui::IWindowInfosReportedListener>& reportedListener) { - std::scoped_lock lock{mutex}; - callCount++; - cv.notify_one(); + gui::WindowInfosListenerInfo listenerInfo; + mInvoker->addWindowInfosListener(sp<Listener>::make([&](const gui::WindowInfosUpdate& update) { + std::scoped_lock lock{mutex}; + callCount++; + cv.notify_one(); - reportedListener->onWindowInfosReported(); - })); + listenerInfo.windowInfosPublisher + ->ackWindowInfosReceived(update.vsyncId, + listenerInfo.listenerId); + }), + &listenerInfo); BackgroundExecutor::getInstance().sendCallbacks( {[this]() { mInvoker->windowInfosChanged({}, {}, false); }}); @@ -81,21 +71,27 @@ TEST_F(WindowInfosListenerInvokerTest, callsMultipleListeners) { std::mutex mutex; std::condition_variable cv; - int callCount = 0; - const int expectedCallCount = 3; - - for (int i = 0; i < expectedCallCount; i++) { - mInvoker->addWindowInfosListener(sp<Listener>::make( - [&](const gui::WindowInfosUpdate&, - const sp<gui::IWindowInfosReportedListener>& reportedListener) { - std::scoped_lock lock{mutex}; - callCount++; - if (callCount == expectedCallCount) { - cv.notify_one(); - } - - reportedListener->onWindowInfosReported(); - })); + size_t callCount = 0; + const size_t expectedCallCount = 3; + std::vector<gui::WindowInfosListenerInfo> listenerInfos{expectedCallCount, + gui::WindowInfosListenerInfo{}}; + + for (size_t i = 0; i < expectedCallCount; i++) { + mInvoker->addWindowInfosListener(sp<Listener>::make([&, &listenerInfo = listenerInfos[i]]( + const gui::WindowInfosUpdate& + update) { + std::scoped_lock lock{mutex}; + callCount++; + if (callCount == expectedCallCount) { + cv.notify_one(); + } + + listenerInfo.windowInfosPublisher + ->ackWindowInfosReceived(update.vsyncId, + listenerInfo + .listenerId); + }), + &listenerInfos[i]); } BackgroundExecutor::getInstance().sendCallbacks( @@ -114,17 +110,20 @@ TEST_F(WindowInfosListenerInvokerTest, delaysUnackedCall) { int callCount = 0; - // Simulate a slow ack by not calling the WindowInfosReportedListener. - mInvoker->addWindowInfosListener(sp<Listener>::make( - [&](const gui::WindowInfosUpdate&, const sp<gui::IWindowInfosReportedListener>&) { - std::scoped_lock lock{mutex}; - callCount++; - cv.notify_one(); - })); + // Simulate a slow ack by not calling IWindowInfosPublisher.ackWindowInfosReceived + gui::WindowInfosListenerInfo listenerInfo; + mInvoker->addWindowInfosListener(sp<Listener>::make([&](const gui::WindowInfosUpdate&) { + std::scoped_lock lock{mutex}; + callCount++; + cv.notify_one(); + }), + &listenerInfo); BackgroundExecutor::getInstance().sendCallbacks({[&]() { - mInvoker->windowInfosChanged({}, {}, false); - mInvoker->windowInfosChanged({}, {}, false); + mInvoker->windowInfosChanged(gui::WindowInfosUpdate{{}, {}, /* vsyncId= */ 0, 0}, {}, + false); + mInvoker->windowInfosChanged(gui::WindowInfosUpdate{{}, {}, /* vsyncId= */ 1, 0}, {}, + false); }}); { @@ -134,7 +133,7 @@ TEST_F(WindowInfosListenerInvokerTest, delaysUnackedCall) { EXPECT_EQ(callCount, 1); // Ack the first message. - mInvoker->onWindowInfosReported(); + listenerInfo.windowInfosPublisher->ackWindowInfosReceived(0, listenerInfo.listenerId); { std::unique_lock lock{mutex}; @@ -152,19 +151,21 @@ TEST_F(WindowInfosListenerInvokerTest, sendsForcedMessage) { int callCount = 0; const int expectedCallCount = 2; - // Simulate a slow ack by not calling the WindowInfosReportedListener. - mInvoker->addWindowInfosListener(sp<Listener>::make( - [&](const gui::WindowInfosUpdate&, const sp<gui::IWindowInfosReportedListener>&) { - std::scoped_lock lock{mutex}; - callCount++; - if (callCount == expectedCallCount) { - cv.notify_one(); - } - })); + // Simulate a slow ack by not calling IWindowInfosPublisher.ackWindowInfosReceived + gui::WindowInfosListenerInfo listenerInfo; + mInvoker->addWindowInfosListener(sp<Listener>::make([&](const gui::WindowInfosUpdate&) { + std::scoped_lock lock{mutex}; + callCount++; + if (callCount == expectedCallCount) { + cv.notify_one(); + } + }), + &listenerInfo); BackgroundExecutor::getInstance().sendCallbacks({[&]() { - mInvoker->windowInfosChanged({}, {}, false); - mInvoker->windowInfosChanged({}, {}, true); + mInvoker->windowInfosChanged(gui::WindowInfosUpdate{{}, {}, /* vsyncId= */ 0, 0}, {}, + false); + mInvoker->windowInfosChanged(gui::WindowInfosUpdate{{}, {}, /* vsyncId= */ 1, 0}, {}, true); }}); { @@ -182,14 +183,14 @@ TEST_F(WindowInfosListenerInvokerTest, skipsDelayedMessage) { int64_t lastUpdateId = -1; - // Simulate a slow ack by not calling the WindowInfosReportedListener. - mInvoker->addWindowInfosListener( - sp<Listener>::make([&](const gui::WindowInfosUpdate& update, - const sp<gui::IWindowInfosReportedListener>&) { - std::scoped_lock lock{mutex}; - lastUpdateId = update.vsyncId; - cv.notify_one(); - })); + // Simulate a slow ack by not calling IWindowInfosPublisher.ackWindowInfosReceived + gui::WindowInfosListenerInfo listenerInfo; + mInvoker->addWindowInfosListener(sp<Listener>::make([&](const gui::WindowInfosUpdate& update) { + std::scoped_lock lock{mutex}; + lastUpdateId = update.vsyncId; + cv.notify_one(); + }), + &listenerInfo); BackgroundExecutor::getInstance().sendCallbacks({[&]() { mInvoker->windowInfosChanged({{}, {}, /* vsyncId= */ 1, 0}, {}, false); @@ -204,7 +205,7 @@ TEST_F(WindowInfosListenerInvokerTest, skipsDelayedMessage) { EXPECT_EQ(lastUpdateId, 1); // Ack the first message. The third update should be sent. - mInvoker->onWindowInfosReported(); + listenerInfo.windowInfosPublisher->ackWindowInfosReceived(1, listenerInfo.listenerId); { std::unique_lock lock{mutex}; @@ -225,14 +226,17 @@ TEST_F(WindowInfosListenerInvokerTest, noListeners) { // delayed. BackgroundExecutor::getInstance().sendCallbacks({[&]() { mInvoker->windowInfosChanged({}, {}, false); - mInvoker->addWindowInfosListener(sp<Listener>::make( - [&](const gui::WindowInfosUpdate&, const sp<gui::IWindowInfosReportedListener>&) { - std::scoped_lock lock{mutex}; - callCount++; - cv.notify_one(); - })); - mInvoker->windowInfosChanged({}, {}, false); + gui::WindowInfosListenerInfo listenerInfo; + mInvoker->addWindowInfosListener(sp<Listener>::make([&](const gui::WindowInfosUpdate&) { + std::scoped_lock lock{mutex}; + callCount++; + cv.notify_one(); + }), + &listenerInfo); }}); + BackgroundExecutor::getInstance().flushQueue(); + BackgroundExecutor::getInstance().sendCallbacks( + {[&]() { mInvoker->windowInfosChanged({}, {}, false); }}); { std::unique_lock lock{mutex}; diff --git a/services/vibratorservice/OWNERS b/services/vibratorservice/OWNERS index d073e2bd46..031b333fab 100644 --- a/services/vibratorservice/OWNERS +++ b/services/vibratorservice/OWNERS @@ -1 +1,3 @@ +# Bug component: 345036 + include platform/frameworks/base:/services/core/java/com/android/server/vibrator/OWNERS |