diff options
80 files changed, 1447 insertions, 796 deletions
diff --git a/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp b/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp index 45c3a90044..b268c5dcd4 100644 --- a/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp +++ b/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp @@ -21,6 +21,8 @@ #include <binder/IPCThreadState.h> #include <binder/ProcessState.h> +#include <private/android_filesystem_config.h> + namespace android { void fuzzService(const sp<IBinder>& binder, FuzzedDataProvider&& provider) { @@ -40,7 +42,12 @@ void fuzzService(const std::vector<sp<IBinder>>& binders, FuzzedDataProvider&& p // Always take so that a perturbation of just the one ConsumeBool byte will always // take the same path, but with a different UID. Without this, the fuzzer needs to // guess both the change in value and the shift at the same time. - int64_t maybeSetUid = provider.ConsumeIntegral<int64_t>(); + int64_t maybeSetUid = provider.PickValueInArray<int64_t>( + {static_cast<int64_t>(AID_ROOT) << 32, static_cast<int64_t>(AID_SYSTEM) << 32, + provider.ConsumeIntegralInRange<int64_t>(static_cast<int64_t>(AID_ROOT) << 32, + static_cast<int64_t>(AID_USER) << 32), + provider.ConsumeIntegral<int64_t>()}); + if (provider.ConsumeBool()) { // set calling uid IPCThreadState::self()->restoreCallingIdentity(maybeSetUid); diff --git a/libs/binder/tests/parcel_fuzzer/test_fuzzer/TestServiceFuzzer.cpp b/libs/binder/tests/parcel_fuzzer/test_fuzzer/TestServiceFuzzer.cpp index 7fbf2d0670..46205d7689 100644 --- a/libs/binder/tests/parcel_fuzzer/test_fuzzer/TestServiceFuzzer.cpp +++ b/libs/binder/tests/parcel_fuzzer/test_fuzzer/TestServiceFuzzer.cpp @@ -20,6 +20,8 @@ #include <binder/IPCThreadState.h> #include <log/log.h> +#include <private/android_filesystem_config.h> + using android::binder::Status; namespace android { @@ -29,6 +31,8 @@ enum class CrashType { ON_PLAIN, ON_BINDER, ON_KNOWN_UID, + ON_SYSTEM_AID, + ON_ROOT_AID, }; // This service is to verify that fuzzService is functioning properly @@ -48,6 +52,18 @@ public: } break; } + case CrashType::ON_SYSTEM_AID: { + if (IPCThreadState::self()->getCallingUid() == AID_SYSTEM) { + LOG_ALWAYS_FATAL("Expected crash, AID_SYSTEM."); + } + break; + } + case CrashType::ON_ROOT_AID: { + if (IPCThreadState::self()->getCallingUid() == AID_ROOT) { + LOG_ALWAYS_FATAL("Expected crash, AID_ROOT."); + } + break; + } default: break; } @@ -99,6 +115,10 @@ extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) { gCrashType = CrashType::ON_PLAIN; } else if (arg == "KNOWN_UID") { gCrashType = CrashType::ON_KNOWN_UID; + } else if (arg == "AID_SYSTEM") { + gCrashType = CrashType::ON_SYSTEM_AID; + } else if (arg == "AID_ROOT") { + gCrashType = CrashType::ON_ROOT_AID; } else if (arg == "BINDER") { gCrashType = CrashType::ON_BINDER; } else { diff --git a/libs/binder/tests/parcel_fuzzer/test_fuzzer/run_fuzz_service_test.sh b/libs/binder/tests/parcel_fuzzer/test_fuzzer/run_fuzz_service_test.sh index e568035af1..25906d8aeb 100755 --- a/libs/binder/tests/parcel_fuzzer/test_fuzzer/run_fuzz_service_test.sh +++ b/libs/binder/tests/parcel_fuzzer/test_fuzzer/run_fuzz_service_test.sh @@ -27,7 +27,7 @@ then exit 1 fi -for CRASH_TYPE in PLAIN KNOWN_UID BINDER; do +for CRASH_TYPE in PLAIN KNOWN_UID AID_SYSTEM AID_ROOT BINDER; do echo "INFO: Running fuzzer : test_service_fuzzer_should_crash $CRASH_TYPE" ./test_service_fuzzer_should_crash "$CRASH_TYPE" -max_total_time=30 &>"$FUZZER_OUT" 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/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 b7da35d4d3..e7b2195056 100644 --- a/libs/nativewindow/AHardwareBuffer.cpp +++ b/libs/nativewindow/AHardwareBuffer.cpp @@ -301,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; } } @@ -641,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/include-private/private/android/AHardwareBufferHelpers.h b/libs/nativewindow/include-private/private/android/AHardwareBufferHelpers.h index 6df4ea3050..880c694934 100644 --- a/libs/nativewindow/include-private/private/android/AHardwareBufferHelpers.h +++ b/libs/nativewindow/include-private/private/android/AHardwareBufferHelpers.h @@ -40,9 +40,6 @@ bool AHardwareBuffer_isValidDescription(const AHardwareBuffer_Desc* desc, bool l // 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/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/libs/ui/DebugUtils.cpp b/libs/ui/DebugUtils.cpp index 073da89758..8675f14d43 100644 --- a/libs/ui/DebugUtils.cpp +++ b/libs/ui/DebugUtils.cpp @@ -304,6 +304,12 @@ std::string decodePixelFormat(android::PixelFormat format) { return std::string("BGRA_8888"); case android::PIXEL_FORMAT_R_8: return std::string("R_8"); + case android::PIXEL_FORMAT_R_16_UINT: + return std::string("R_16_UINT"); + case android::PIXEL_FORMAT_RG_1616_UINT: + return std::string("RG_1616_UINT"); + case android::PIXEL_FORMAT_RGBA_10101010: + return std::string("RGBA_10101010"); default: return StringPrintf("Unknown %#08x", format); } 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/reader/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp index 4d0e13ed2f..4e72c4c84f 100644 --- a/services/inputflinger/reader/EventHub.cpp +++ b/services/inputflinger/reader/EventHub.cpp @@ -538,7 +538,8 @@ EventHub::Device::Device(int fd, int32_t id, std::string path, InputDeviceIdenti associatedDevice(std::move(assocDev)), controllerNumber(0), enabled(true), - isVirtual(fd < 0) {} + isVirtual(fd < 0), + currentFrameDropped(false) {} EventHub::Device::~Device() { close(); @@ -612,6 +613,18 @@ void EventHub::Device::configureFd() { } bool usingClockIoctl = !ioctl(fd, EVIOCSCLOCKID, &clockId); ALOGI("usingClockIoctl=%s", toString(usingClockIoctl)); + + // Query the initial state of keys and switches, which is tracked by EventHub. + readDeviceState(); +} + +void EventHub::Device::readDeviceState() { + if (readDeviceBitMask(EVIOCGKEY(0), keyState) < 0) { + ALOGD("Unable to query the global key state for %s: %s", path.c_str(), strerror(errno)); + } + if (readDeviceBitMask(EVIOCGSW(0), swState) < 0) { + ALOGD("Unable to query the global switch state for %s: %s", path.c_str(), strerror(errno)); + } } bool EventHub::Device::hasKeycodeLocked(int keycode) const { @@ -729,6 +742,48 @@ status_t EventHub::Device::mapLed(int32_t led, int32_t* outScanCode) const { return NAME_NOT_FOUND; } +void EventHub::Device::trackInputEvent(const struct input_event& event) { + switch (event.type) { + case EV_KEY: { + LOG_ALWAYS_FATAL_IF(!currentFrameDropped && + !keyState.set(static_cast<size_t>(event.code), + event.value != 0), + "%s: received invalid EV_KEY event code: %s", __func__, + InputEventLookup::getLinuxEvdevLabel(EV_KEY, event.code, 1) + .code.c_str()); + break; + } + case EV_SW: { + LOG_ALWAYS_FATAL_IF(!currentFrameDropped && + !swState.set(static_cast<size_t>(event.code), + event.value != 0), + "%s: received invalid EV_SW event code: %s", __func__, + InputEventLookup::getLinuxEvdevLabel(EV_SW, event.code, 1) + .code.c_str()); + break; + } + case EV_SYN: { + switch (event.code) { + case SYN_REPORT: + currentFrameDropped = false; + break; + case SYN_DROPPED: + // When we receive SYN_DROPPED, all events in the current frame should be + // dropped. We query the state of the device to synchronize our device state + // with the kernel's to account for the dropped events. + currentFrameDropped = true; + readDeviceState(); + break; + default: + break; + } + break; + } + default: + break; + } +} + /** * Get the capabilities for the current process. * Crashes the system if unable to create / check / destroy the capabilities object. @@ -962,38 +1017,34 @@ bool EventHub::hasMscEvent(int32_t deviceId, int mscEvent) const { } int32_t EventHub::getScanCodeState(int32_t deviceId, int32_t scanCode) const { - if (scanCode >= 0 && scanCode <= KEY_MAX) { - std::scoped_lock _l(mLock); - - Device* device = getDeviceLocked(deviceId); - if (device != nullptr && device->hasValidFd() && device->keyBitmask.test(scanCode)) { - if (device->readDeviceBitMask(EVIOCGKEY(0), device->keyState) >= 0) { - return device->keyState.test(scanCode) ? AKEY_STATE_DOWN : AKEY_STATE_UP; - } - } + if (scanCode < 0 || scanCode > KEY_MAX) { + return AKEY_STATE_UNKNOWN; + } + std::scoped_lock _l(mLock); + const Device* device = getDeviceLocked(deviceId); + if (device == nullptr || !device->hasValidFd() || !device->keyBitmask.test(scanCode)) { + return AKEY_STATE_UNKNOWN; } - return AKEY_STATE_UNKNOWN; + return device->keyState.test(scanCode) ? AKEY_STATE_DOWN : AKEY_STATE_UP; } int32_t EventHub::getKeyCodeState(int32_t deviceId, int32_t keyCode) const { std::scoped_lock _l(mLock); - - Device* device = getDeviceLocked(deviceId); - if (device != nullptr && device->hasValidFd() && device->keyMap.haveKeyLayout()) { - std::vector<int32_t> scanCodes = device->keyMap.keyLayoutMap->findScanCodesForKey(keyCode); - if (scanCodes.size() != 0) { - if (device->readDeviceBitMask(EVIOCGKEY(0), device->keyState) >= 0) { - for (size_t i = 0; i < scanCodes.size(); i++) { - int32_t sc = scanCodes[i]; - if (sc >= 0 && sc <= KEY_MAX && device->keyState.test(sc)) { - return AKEY_STATE_DOWN; - } - } - return AKEY_STATE_UP; - } - } + const Device* device = getDeviceLocked(deviceId); + if (device == nullptr || !device->hasValidFd() || !device->keyMap.haveKeyLayout()) { + return AKEY_STATE_UNKNOWN; + } + const std::vector<int32_t> scanCodes = + device->keyMap.keyLayoutMap->findScanCodesForKey(keyCode); + if (scanCodes.empty()) { + return AKEY_STATE_UNKNOWN; } - return AKEY_STATE_UNKNOWN; + return std::any_of(scanCodes.begin(), scanCodes.end(), + [&device](const int32_t sc) { + return sc >= 0 && sc <= KEY_MAX && device->keyState.test(sc); + }) + ? AKEY_STATE_DOWN + : AKEY_STATE_UP; } int32_t EventHub::getKeyCodeForKeyLocation(int32_t deviceId, int32_t locationKeyCode) const { @@ -1037,17 +1088,15 @@ int32_t EventHub::getKeyCodeForKeyLocation(int32_t deviceId, int32_t locationKey } int32_t EventHub::getSwitchState(int32_t deviceId, int32_t sw) const { - if (sw >= 0 && sw <= SW_MAX) { - std::scoped_lock _l(mLock); - - Device* device = getDeviceLocked(deviceId); - if (device != nullptr && device->hasValidFd() && device->swBitmask.test(sw)) { - if (device->readDeviceBitMask(EVIOCGSW(0), device->swState) >= 0) { - return device->swState.test(sw) ? AKEY_STATE_DOWN : AKEY_STATE_UP; - } - } + if (sw < 0 || sw > SW_MAX) { + return AKEY_STATE_UNKNOWN; + } + std::scoped_lock _l(mLock); + const Device* device = getDeviceLocked(deviceId); + if (device == nullptr || !device->hasValidFd() || !device->swBitmask.test(sw)) { + return AKEY_STATE_UNKNOWN; } - return AKEY_STATE_UNKNOWN; + return device->swState.test(sw) ? AKEY_STATE_DOWN : AKEY_STATE_UP; } status_t EventHub::getAbsoluteAxisValue(int32_t deviceId, int32_t axis, int32_t* outValue) const { @@ -1922,6 +1971,7 @@ std::vector<RawEvent> EventHub::getEvents(int timeoutMillis) { const size_t count = size_t(readSize) / sizeof(struct input_event); for (size_t i = 0; i < count; i++) { struct input_event& iev = readBuffer[i]; + device->trackInputEvent(iev); events.push_back({ .when = processEventTimestamp(iev), .readTime = systemTime(SYSTEM_TIME_MONOTONIC), diff --git a/services/inputflinger/reader/include/EventHub.h b/services/inputflinger/reader/include/EventHub.h index 024187f5b5..6e647db18e 100644 --- a/services/inputflinger/reader/include/EventHub.h +++ b/services/inputflinger/reader/include/EventHub.h @@ -411,7 +411,17 @@ public: * Note the parameter "bit" is an index to the bit, 0 <= bit < BITS. */ inline bool test(size_t bit) const { - return (bit < BITS) ? mData[bit / WIDTH].test(bit % WIDTH) : false; + return (bit < BITS) && mData[bit / WIDTH].test(bit % WIDTH); + } + /* Sets the given bit in the bit array to given value. + * Returns true if the given bit is a valid index and thus was set successfully. + */ + inline bool set(size_t bit, bool value) { + if (bit >= BITS) { + return false; + } + mData[bit / WIDTH].set(bit % WIDTH, value); + return true; } /* Returns total number of bytes needed for the array */ inline size_t bytes() { return (BITS + CHAR_BIT - 1) / CHAR_BIT; } @@ -653,6 +663,10 @@ private: void setLedForControllerLocked(); status_t mapLed(int32_t led, int32_t* outScanCode) const; void setLedStateLocked(int32_t led, bool on); + + bool currentFrameDropped; + void trackInputEvent(const struct input_event& event); + void readDeviceState(); }; /** 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/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp index e751c89c4e..477beaf7f6 100644 --- a/services/inputflinger/tests/InputReader_test.cpp +++ b/services/inputflinger/tests/InputReader_test.cpp @@ -1886,7 +1886,7 @@ using StylusButtonIntegrationTestTypes = ::testing::Types<UinputTouchScreen, UinputExternalStylus, UinputExternalStylusWithPressure>; TYPED_TEST_SUITE(StylusButtonIntegrationTest, StylusButtonIntegrationTestTypes); -TYPED_TEST(StylusButtonIntegrationTest, DISABLED_StylusButtonsGenerateKeyEvents) { +TYPED_TEST(StylusButtonIntegrationTest, StylusButtonsGenerateKeyEvents) { const auto stylusId = TestFixture::mStylusInfo.getId(); TestFixture::mStylus->pressKey(BTN_STYLUS); @@ -1900,7 +1900,7 @@ TYPED_TEST(StylusButtonIntegrationTest, DISABLED_StylusButtonsGenerateKeyEvents) WithKeyCode(AKEYCODE_STYLUS_BUTTON_PRIMARY), WithDeviceId(stylusId)))); } -TYPED_TEST(StylusButtonIntegrationTest, DISABLED_StylusButtonsSurroundingTouchGesture) { +TYPED_TEST(StylusButtonIntegrationTest, StylusButtonsSurroundingTouchGesture) { const Point centerPoint = TestFixture::mTouchscreen->getCenterPoint(); const auto touchscreenId = TestFixture::mTouchscreenInfo.getId(); const auto stylusId = TestFixture::mStylusInfo.getId(); @@ -1946,7 +1946,7 @@ TYPED_TEST(StylusButtonIntegrationTest, DISABLED_StylusButtonsSurroundingTouchGe WithKeyCode(AKEYCODE_STYLUS_BUTTON_PRIMARY), WithDeviceId(stylusId)))); } -TYPED_TEST(StylusButtonIntegrationTest, DISABLED_StylusButtonsSurroundingHoveringTouchGesture) { +TYPED_TEST(StylusButtonIntegrationTest, StylusButtonsSurroundingHoveringTouchGesture) { const Point centerPoint = TestFixture::mTouchscreen->getCenterPoint(); const auto touchscreenId = TestFixture::mTouchscreenInfo.getId(); const auto stylusId = TestFixture::mStylusInfo.getId(); @@ -2022,7 +2022,7 @@ TYPED_TEST(StylusButtonIntegrationTest, DISABLED_StylusButtonsSurroundingHoverin WithKeyCode(AKEYCODE_STYLUS_BUTTON_PRIMARY), WithDeviceId(stylusId)))); } -TYPED_TEST(StylusButtonIntegrationTest, DISABLED_StylusButtonsWithinTouchGesture) { +TYPED_TEST(StylusButtonIntegrationTest, StylusButtonsWithinTouchGesture) { const Point centerPoint = TestFixture::mTouchscreen->getCenterPoint(); const auto touchscreenId = TestFixture::mTouchscreenInfo.getId(); const auto stylusId = TestFixture::mStylusInfo.getId(); @@ -2076,7 +2076,7 @@ TYPED_TEST(StylusButtonIntegrationTest, DISABLED_StylusButtonsWithinTouchGesture WithDeviceId(touchscreenId)))); } -TYPED_TEST(StylusButtonIntegrationTest, DISABLED_StylusButtonMotionEventsDisabled) { +TYPED_TEST(StylusButtonIntegrationTest, StylusButtonMotionEventsDisabled) { TestFixture::mFakePolicy->setStylusButtonMotionEventsEnabled(false); TestFixture::mReader->requestRefreshConfiguration( InputReaderConfiguration::Change::STYLUS_BUTTON_REPORTING); @@ -2133,7 +2133,7 @@ TYPED_TEST(StylusButtonIntegrationTest, DISABLED_StylusButtonMotionEventsDisable // ongoing stylus gesture that is being emitted by the touchscreen. using ExternalStylusIntegrationTest = TouchIntegrationTest; -TEST_F(ExternalStylusIntegrationTest, DISABLED_FusedExternalStylusPressureReported) { +TEST_F(ExternalStylusIntegrationTest, FusedExternalStylusPressureReported) { const Point centerPoint = mDevice->getCenterPoint(); // Create an external stylus capable of reporting pressure data that @@ -2179,7 +2179,7 @@ TEST_F(ExternalStylusIntegrationTest, DISABLED_FusedExternalStylusPressureReport ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyKeyWasNotCalled()); } -TEST_F(ExternalStylusIntegrationTest, DISABLED_FusedExternalStylusPressureNotReported) { +TEST_F(ExternalStylusIntegrationTest, FusedExternalStylusPressureNotReported) { const Point centerPoint = mDevice->getCenterPoint(); // Create an external stylus capable of reporting pressure data that @@ -2247,7 +2247,7 @@ TEST_F(ExternalStylusIntegrationTest, DISABLED_FusedExternalStylusPressureNotRep ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyKeyWasNotCalled()); } -TEST_F(ExternalStylusIntegrationTest, DISABLED_UnfusedExternalStylus) { +TEST_F(ExternalStylusIntegrationTest, UnfusedExternalStylus) { const Point centerPoint = mDevice->getCenterPoint(); // Create an external stylus device that does not support pressure. It should not affect any 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/DisplayHardware/AidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp index c0eb36dc02..311820c3ed 100644 --- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp +++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp @@ -244,14 +244,13 @@ AidlComposer::AidlComposer(const std::string& serviceName) { addReader(translate<Display>(kSingleReaderKey)); // If unable to read interface version, then become backwards compatible. - int32_t version = 1; - const auto status = mAidlComposerClient->getInterfaceVersion(&version); + const auto status = mAidlComposerClient->getInterfaceVersion(&mComposerInterfaceVersion); if (!status.isOk()) { ALOGE("getInterfaceVersion for AidlComposer constructor failed %s", status.getDescription().c_str()); } - mSupportsBufferSlotsToClear = version > 1; - if (!mSupportsBufferSlotsToClear) { + + if (mComposerInterfaceVersion <= 1) { if (sysprop::clear_slots_with_set_layer_buffer(false)) { mClearSlotBuffer = sp<GraphicBuffer>::make(1, 1, PIXEL_FORMAT_RGBX_8888, GraphicBuffer::USAGE_HW_COMPOSER | @@ -281,6 +280,10 @@ bool AidlComposer::isSupported(OptionalFeature feature) const { } } +bool AidlComposer::getDisplayConfigurationsSupported() const { + return mComposerInterfaceVersion >= 3; +} + std::vector<Capability> AidlComposer::getCapabilities() { std::vector<Capability> capabilities; const auto status = mAidlComposer->getCapabilities(&capabilities); @@ -489,6 +492,18 @@ Error AidlComposer::getDisplayConfigs(Display display, std::vector<Config>* outC return Error::NONE; } +Error AidlComposer::getDisplayConfigurations(Display display, + std::vector<DisplayConfiguration>* outConfigs) { + const auto status = + mAidlComposerClient->getDisplayConfigurations(translate<int64_t>(display), outConfigs); + if (!status.isOk()) { + ALOGE("getDisplayConfigurations failed %s", status.getDescription().c_str()); + return static_cast<Error>(status.getServiceSpecificError()); + } + + return Error::NONE; +} + Error AidlComposer::getDisplayName(Display display, std::string* outName) { const auto status = mAidlComposerClient->getDisplayName(translate<int64_t>(display), outName); if (!status.isOk()) { @@ -848,7 +863,7 @@ Error AidlComposer::setLayerBufferSlotsToClear(Display display, Layer layer, Error error = Error::NONE; mMutex.lock_shared(); if (auto writer = getWriter(display)) { - if (mSupportsBufferSlotsToClear) { + if (mComposerInterfaceVersion > 1) { writer->get().setLayerBufferSlotsToClear(translate<int64_t>(display), translate<int64_t>(layer), slotsToClear); // Backwards compatible way of clearing buffer slots is to set the layer buffer with a diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h index 8d21b491c3..e31ff812e3 100644 --- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h +++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h @@ -66,6 +66,7 @@ public: ~AidlComposer() override; bool isSupported(OptionalFeature) const; + bool getDisplayConfigurationsSupported() const; std::vector<aidl::android::hardware::graphics::composer3::Capability> getCapabilities() override; @@ -95,6 +96,7 @@ public: Error getDisplayAttribute(Display display, Config config, IComposerClient::Attribute attribute, int32_t* outValue) override; Error getDisplayConfigs(Display display, std::vector<Config>* outConfigs); + Error getDisplayConfigurations(Display, std::vector<DisplayConfiguration>*); Error getDisplayName(Display display, std::string* outName) override; Error getDisplayRequests(Display display, uint32_t* outDisplayRequestMask, @@ -285,8 +287,8 @@ private: // threading annotations. ftl::SharedMutex mMutex; - // Whether or not explicitly clearing buffer slots is supported. - bool mSupportsBufferSlotsToClear; + int32_t mComposerInterfaceVersion = 1; + // Buffer slots for layers are cleared by setting the slot buffer to this buffer. sp<GraphicBuffer> mClearSlotBuffer; diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h index cf677955bf..cc60fd0ec0 100644 --- a/services/surfaceflinger/DisplayHardware/ComposerHal.h +++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h @@ -39,6 +39,7 @@ #include <aidl/android/hardware/graphics/composer3/Color.h> #include <aidl/android/hardware/graphics/composer3/Composition.h> #include <aidl/android/hardware/graphics/composer3/DisplayCapability.h> +#include <aidl/android/hardware/graphics/composer3/DisplayConfiguration.h> #include <aidl/android/hardware/graphics/composer3/IComposerCallback.h> #include <aidl/android/hardware/graphics/composer3/OverlayProperties.h> @@ -85,6 +86,7 @@ using PerFrameMetadata = IComposerClient::PerFrameMetadata; using PerFrameMetadataKey = IComposerClient::PerFrameMetadataKey; using PerFrameMetadataBlob = IComposerClient::PerFrameMetadataBlob; using AidlTransform = ::aidl::android::hardware::graphics::common::Transform; +using DisplayConfiguration = V3_0::DisplayConfiguration; using aidl::android::hardware::graphics::common::Hdr; class Composer { @@ -103,6 +105,7 @@ public: }; virtual bool isSupported(OptionalFeature) const = 0; + virtual bool getDisplayConfigurationsSupported() const = 0; virtual std::vector<aidl::android::hardware::graphics::composer3::Capability> getCapabilities() = 0; @@ -130,6 +133,9 @@ public: virtual Error getDisplayAttribute(Display display, Config config, IComposerClient::Attribute attribute, int32_t* outValue) = 0; virtual Error getDisplayConfigs(Display display, std::vector<Config>* outConfigs) = 0; + + virtual Error getDisplayConfigurations(Display, std::vector<DisplayConfiguration>*) = 0; + virtual Error getDisplayName(Display display, std::string* outName) = 0; virtual Error getDisplayRequests(Display display, uint32_t* outDisplayRequestMask, diff --git a/services/surfaceflinger/DisplayHardware/DisplayMode.h b/services/surfaceflinger/DisplayHardware/DisplayMode.h index 61a9a08a5c..1810925c8e 100644 --- a/services/surfaceflinger/DisplayHardware/DisplayMode.h +++ b/services/surfaceflinger/DisplayHardware/DisplayMode.h @@ -80,20 +80,20 @@ public: return *this; } - Builder& setDpiX(int32_t dpiX) { - if (dpiX == -1) { + Builder& setDpiX(float dpiX) { + if (dpiX == -1.f) { mDisplayMode->mDpi.x = getDefaultDensity(); } else { - mDisplayMode->mDpi.x = dpiX / 1000.f; + mDisplayMode->mDpi.x = dpiX; } return *this; } - Builder& setDpiY(int32_t dpiY) { - if (dpiY == -1) { + Builder& setDpiY(float dpiY) { + if (dpiY == -1.f) { mDisplayMode->mDpi.y = getDefaultDensity(); } else { - mDisplayMode->mDpi.y = dpiY / 1000.f; + mDisplayMode->mDpi.y = dpiY; } return *this; } diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp index f350eba7ca..aefa7c3551 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp +++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp @@ -265,6 +265,46 @@ std::vector<HWComposer::HWCDisplayMode> HWComposer::getModes(PhysicalDisplayId d RETURN_IF_INVALID_DISPLAY(displayId, {}); const auto hwcDisplayId = mDisplayData.at(displayId).hwcDisplay->getId(); + + if (mComposer->getDisplayConfigurationsSupported()) { + return getModesFromDisplayConfigurations(hwcDisplayId); + } + + return getModesFromLegacyDisplayConfigs(hwcDisplayId); +} + +std::vector<HWComposer::HWCDisplayMode> HWComposer::getModesFromDisplayConfigurations( + uint64_t hwcDisplayId) const { + std::vector<hal::DisplayConfiguration> configs; + auto error = + static_cast<hal::Error>(mComposer->getDisplayConfigurations(hwcDisplayId, &configs)); + RETURN_IF_HWC_ERROR_FOR("getDisplayConfigurations", error, *toPhysicalDisplayId(hwcDisplayId), + {}); + + std::vector<HWCDisplayMode> modes; + modes.reserve(configs.size()); + for (auto config : configs) { + auto hwcMode = HWCDisplayMode{ + .hwcId = static_cast<hal::HWConfigId>(config.configId), + .width = config.width, + .height = config.height, + .vsyncPeriod = config.vsyncPeriod, + .configGroup = config.configGroup, + }; + + if (config.dpi) { + hwcMode.dpiX = config.dpi->x; + hwcMode.dpiY = config.dpi->y; + } + + modes.push_back(hwcMode); + } + + return modes; +} + +std::vector<HWComposer::HWCDisplayMode> HWComposer::getModesFromLegacyDisplayConfigs( + uint64_t hwcDisplayId) const { std::vector<hal::HWConfigId> configIds; auto error = static_cast<hal::Error>(mComposer->getDisplayConfigs(hwcDisplayId, &configIds)); RETURN_IF_HWC_ERROR_FOR("getDisplayConfigs", error, *toPhysicalDisplayId(hwcDisplayId), {}); @@ -272,17 +312,25 @@ std::vector<HWComposer::HWCDisplayMode> HWComposer::getModes(PhysicalDisplayId d std::vector<HWCDisplayMode> modes; modes.reserve(configIds.size()); for (auto configId : configIds) { - modes.push_back(HWCDisplayMode{ + auto hwcMode = HWCDisplayMode{ .hwcId = configId, .width = getAttribute(hwcDisplayId, configId, hal::Attribute::WIDTH), .height = getAttribute(hwcDisplayId, configId, hal::Attribute::HEIGHT), .vsyncPeriod = getAttribute(hwcDisplayId, configId, hal::Attribute::VSYNC_PERIOD), - .dpiX = getAttribute(hwcDisplayId, configId, hal::Attribute::DPI_X), - .dpiY = getAttribute(hwcDisplayId, configId, hal::Attribute::DPI_Y), .configGroup = getAttribute(hwcDisplayId, configId, hal::Attribute::CONFIG_GROUP), - }); - } + }; + const int32_t dpiX = getAttribute(hwcDisplayId, configId, hal::Attribute::DPI_X); + const int32_t dpiY = getAttribute(hwcDisplayId, configId, hal::Attribute::DPI_Y); + if (dpiX != -1) { + hwcMode.dpiX = static_cast<float>(dpiX) / 1000.f; + } + if (dpiY != -1) { + hwcMode.dpiY = static_cast<float>(dpiY) / 1000.f; + } + + modes.push_back(hwcMode); + } return modes; } diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h index 3702c62b65..8247d97005 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.h +++ b/services/surfaceflinger/DisplayHardware/HWComposer.h @@ -99,8 +99,8 @@ public: int32_t width = -1; int32_t height = -1; nsecs_t vsyncPeriod = -1; - int32_t dpiX = -1; - int32_t dpiY = -1; + float dpiX = -1.f; + float dpiY = -1.f; int32_t configGroup = -1; friend std::ostream& operator<<(std::ostream& os, const HWCDisplayMode& mode) { @@ -501,6 +501,9 @@ private: std::optional<DisplayIdentificationInfo> onHotplugDisconnect(hal::HWDisplayId); bool shouldIgnoreHotplugConnect(hal::HWDisplayId, bool hasDisplayIdentificationData) const; + std::vector<HWCDisplayMode> getModesFromDisplayConfigurations(uint64_t hwcDisplayId) const; + std::vector<HWCDisplayMode> getModesFromLegacyDisplayConfigs(uint64_t hwcDisplayId) const; + int32_t getAttribute(hal::HWDisplayId hwcDisplayId, hal::HWConfigId configId, hal::Attribute attribute) const; diff --git a/services/surfaceflinger/DisplayHardware/Hal.h b/services/surfaceflinger/DisplayHardware/Hal.h index bf3089f040..e95ae8934d 100644 --- a/services/surfaceflinger/DisplayHardware/Hal.h +++ b/services/surfaceflinger/DisplayHardware/Hal.h @@ -23,6 +23,7 @@ #include <aidl/android/hardware/graphics/common/Hdr.h> #include <aidl/android/hardware/graphics/composer3/Composition.h> #include <aidl/android/hardware/graphics/composer3/DisplayCapability.h> +#include <aidl/android/hardware/graphics/composer3/DisplayConfiguration.h> #define ERROR_HAS_CHANGES 5 @@ -34,6 +35,7 @@ namespace V2_1 = android::hardware::graphics::composer::V2_1; namespace V2_2 = android::hardware::graphics::composer::V2_2; namespace V2_3 = android::hardware::graphics::composer::V2_3; namespace V2_4 = android::hardware::graphics::composer::V2_4; +namespace V3_0 = ::aidl::android::hardware::graphics::composer3; using types::V1_0::ColorTransform; using types::V1_0::Transform; @@ -70,6 +72,7 @@ using PowerMode = IComposerClient::PowerMode; using Vsync = IComposerClient::Vsync; using VsyncPeriodChangeConstraints = IComposerClient::VsyncPeriodChangeConstraints; using Hdr = aidl::android::hardware::graphics::common::Hdr; +using DisplayConfiguration = V3_0::DisplayConfiguration; } // namespace hardware::graphics::composer::hal diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp index 9b41da5754..0655abc1c6 100644 --- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp +++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp @@ -269,6 +269,11 @@ bool HidlComposer::isSupported(OptionalFeature feature) const { } } +bool HidlComposer::getDisplayConfigurationsSupported() const { + // getDisplayConfigurations is not supported on the HIDL composer. + return false; +}; + std::vector<Capability> HidlComposer::getCapabilities() { std::vector<Capability> capabilities; mComposer->getCapabilities([&](const auto& tmpCapabilities) { @@ -477,6 +482,11 @@ Error HidlComposer::getDisplayConfigs(Display display, std::vector<Config>* outC return error; } +Error HidlComposer::getDisplayConfigurations(Display, std::vector<DisplayConfiguration>*) { + LOG_ALWAYS_FATAL("getDisplayConfigurations should not have been called on this, as " + "it's a HWC3 interface version 3 feature"); +} + Error HidlComposer::getDisplayName(Display display, std::string* outName) { Error error = kDefaultError; mClient->getDisplayName(display, [&](const auto& tmpError, const auto& tmpName) { diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.h b/services/surfaceflinger/DisplayHardware/HidlComposerHal.h index 0521acf9c4..ac96d9a81d 100644 --- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.h +++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.h @@ -167,6 +167,7 @@ public: ~HidlComposer() override; bool isSupported(OptionalFeature) const; + bool getDisplayConfigurationsSupported() const; std::vector<aidl::android::hardware::graphics::composer3::Capability> getCapabilities() override; @@ -196,6 +197,7 @@ public: Error getDisplayAttribute(Display display, Config config, IComposerClient::Attribute attribute, int32_t* outValue) override; Error getDisplayConfigs(Display display, std::vector<Config>* outConfigs); + Error getDisplayConfigurations(Display, std::vector<DisplayConfiguration>*); Error getDisplayName(Display display, std::string* outName) override; Error getDisplayRequests(Display display, uint32_t* outDisplayRequestMask, diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshot.h b/services/surfaceflinger/FrontEnd/LayerSnapshot.h index 1416872f95..1afcef9e44 100644 --- a/services/surfaceflinger/FrontEnd/LayerSnapshot.h +++ b/services/surfaceflinger/FrontEnd/LayerSnapshot.h @@ -41,10 +41,6 @@ struct RoundedCornerState { } }; -struct ChildState { - bool hasValidFrameRate = false; -}; - // LayerSnapshot stores Layer state used by CompositionEngine and RenderEngine. Composition // Engine uses a pointer to LayerSnapshot (as LayerFECompositionState*) and the LayerSettings // passed to Render Engine are created using properties stored on this struct. @@ -99,7 +95,6 @@ struct LayerSnapshot : public compositionengine::LayerFECompositionState { uint32_t touchCropId; gui::Uid uid = gui::Uid::INVALID; gui::Pid pid = gui::Pid::INVALID; - ChildState childState; enum class Reachablilty : uint32_t { // Can traverse the hierarchy from a root node and reach this snapshot Reachable, diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp index 3a19d0b389..7e678b98fa 100644 --- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp +++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp @@ -558,7 +558,7 @@ const LayerSnapshot& LayerSnapshotBuilder::updateSnapshotsInHierarchy( const LayerSnapshot& childSnapshot = updateSnapshotsInHierarchy(args, *childHierarchy, traversalPath, *snapshot, depth + 1); - updateChildState(*snapshot, childSnapshot, args); + updateFrameRateFromChildSnapshot(*snapshot, childSnapshot, args); } if (oldFrameRate == snapshot->frameRate) { @@ -666,36 +666,40 @@ void LayerSnapshotBuilder::updateRelativeState(LayerSnapshot& snapshot, } } -void LayerSnapshotBuilder::updateChildState(LayerSnapshot& snapshot, - const LayerSnapshot& childSnapshot, const Args& args) { - if (snapshot.childState.hasValidFrameRate) { +void LayerSnapshotBuilder::updateFrameRateFromChildSnapshot(LayerSnapshot& snapshot, + const LayerSnapshot& childSnapshot, + const Args& args) { + if (args.forceUpdate == ForceUpdateFlags::NONE && + !childSnapshot.changes.any(RequestedLayerState::Changes::FrameRate | + RequestedLayerState::Changes::Hierarchy)) { return; } - if (args.forceUpdate == ForceUpdateFlags::ALL || - childSnapshot.changes.test(RequestedLayerState::Changes::FrameRate)) { - // We return whether this layer ot its children has a vote. We ignore ExactOrMultiple votes - // for the same reason we are allowing touch boost for those layers. See - // RefreshRateSelector::rankFrameRates for details. - using FrameRateCompatibility = scheduler::LayerInfo::FrameRateCompatibility; - const auto layerVotedWithDefaultCompatibility = childSnapshot.frameRate.rate.isValid() && - childSnapshot.frameRate.type == FrameRateCompatibility::Default; - const auto layerVotedWithNoVote = - childSnapshot.frameRate.type == FrameRateCompatibility::NoVote; - const auto layerVotedWithExactCompatibility = childSnapshot.frameRate.rate.isValid() && - childSnapshot.frameRate.type == FrameRateCompatibility::Exact; - - snapshot.childState.hasValidFrameRate |= layerVotedWithDefaultCompatibility || - layerVotedWithNoVote || layerVotedWithExactCompatibility; - - // If we don't have a valid frame rate, but the children do, we set this - // layer as NoVote to allow the children to control the refresh rate - if (!snapshot.frameRate.rate.isValid() && - snapshot.frameRate.type != FrameRateCompatibility::NoVote && - snapshot.childState.hasValidFrameRate) { - snapshot.frameRate = - scheduler::LayerInfo::FrameRate(Fps(), FrameRateCompatibility::NoVote); - snapshot.changes |= childSnapshot.changes & RequestedLayerState::Changes::FrameRate; - } + + using FrameRateCompatibility = scheduler::LayerInfo::FrameRateCompatibility; + if (snapshot.frameRate.rate.isValid() || + snapshot.frameRate.type == FrameRateCompatibility::NoVote) { + // we already have a valid framerate. + return; + } + + // We return whether this layer or its children has a vote. We ignore ExactOrMultiple votes + // for the same reason we are allowing touch boost for those layers. See + // RefreshRateSelector::rankFrameRates for details. + const auto layerVotedWithDefaultCompatibility = childSnapshot.frameRate.rate.isValid() && + childSnapshot.frameRate.type == FrameRateCompatibility::Default; + const auto layerVotedWithNoVote = + childSnapshot.frameRate.type == FrameRateCompatibility::NoVote; + const auto layerVotedWithExactCompatibility = childSnapshot.frameRate.rate.isValid() && + childSnapshot.frameRate.type == FrameRateCompatibility::Exact; + + bool childHasValidFrameRate = layerVotedWithDefaultCompatibility || layerVotedWithNoVote || + layerVotedWithExactCompatibility; + + // If we don't have a valid frame rate, but the children do, we set this + // layer as NoVote to allow the children to control the refresh rate + if (childHasValidFrameRate) { + snapshot.frameRate = scheduler::LayerInfo::FrameRate(Fps(), FrameRateCompatibility::NoVote); + snapshot.changes |= RequestedLayerState::Changes::FrameRate; } } @@ -812,7 +816,9 @@ void LayerSnapshotBuilder::updateSnapshot(LayerSnapshot& snapshot, const Args& a } } - if (forceUpdate || snapshot.changes.any(RequestedLayerState::Changes::FrameRate)) { + if (forceUpdate || + snapshot.changes.any(RequestedLayerState::Changes::FrameRate | + RequestedLayerState::Changes::Hierarchy)) { snapshot.frameRate = (requested.requestedFrameRate.rate.isValid() || (requested.requestedFrameRate.type == scheduler::LayerInfo::FrameRateCompatibility::NoVote)) diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h index c81a5d2b9e..d361605875 100644 --- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h +++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h @@ -116,8 +116,8 @@ private: LayerSnapshot* createSnapshot(const LayerHierarchy::TraversalPath& id, const RequestedLayerState& layer, const LayerSnapshot& parentSnapshot); - void updateChildState(LayerSnapshot& snapshot, const LayerSnapshot& childSnapshot, - const Args& args); + void updateFrameRateFromChildSnapshot(LayerSnapshot& snapshot, + const LayerSnapshot& childSnapshot, const Args& args); void updateTouchableRegionCrop(const Args& args); std::unordered_map<LayerHierarchy::TraversalPath, LayerSnapshot*, 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/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/VSyncDispatchTimerQueue.h b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h index 6499d69969..e0fb8f9f86 100644 --- a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h +++ b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h @@ -146,13 +146,14 @@ private: void cancelTimer() REQUIRES(mMutex); ScheduleResult scheduleLocked(CallbackToken, ScheduleTiming) REQUIRES(mMutex); + std::mutex mutable mMutex; + static constexpr nsecs_t kInvalidTime = std::numeric_limits<int64_t>::max(); std::unique_ptr<TimeKeeper> const mTimeKeeper; VsyncSchedule::TrackerPtr mTracker; nsecs_t const mTimerSlack; nsecs_t const mMinVsyncDistance; - std::mutex mutable mMutex; size_t mCallbackToken GUARDED_BY(mMutex) = 0; CallbackMap mCallbacks GUARDED_BY(mMutex); 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 648409c40c..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()); @@ -2523,7 +2522,9 @@ bool SurfaceFlinger::commit(const scheduler::FrameTarget& pacesetterFrameTarget) } updateCursorAsync(); - updateInputFlinger(vsyncId, pacesetterFrameTarget.frameBeginTime()); + if (!mustComposite) { + updateInputFlinger(vsyncId, pacesetterFrameTarget.frameBeginTime()); + } if (mLayerTracingEnabled && !mLayerTracing.flagIsSet(LayerTracing::TRACE_COMPOSITION)) { // This will block and tracing should only be enabled for debugging. @@ -2536,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); @@ -2620,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 @@ -2654,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()); @@ -2672,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 |= @@ -2697,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); @@ -2709,15 +2727,17 @@ 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, pacesetterTarget.frameBeginTime()); + if (mVisibleRegionsDirty) mHdrLayerInfoChanged = true; mVisibleRegionsDirty = false; @@ -2729,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() { @@ -2813,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, @@ -2849,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); @@ -2888,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()); } @@ -2976,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; } @@ -4294,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; @@ -6343,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"); } @@ -7625,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; @@ -7876,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; } @@ -8210,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; } @@ -9296,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(); @@ -9304,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/HWComposerTest.cpp b/services/surfaceflinger/tests/unittests/HWComposerTest.cpp index da00377cae..ec8069d299 100644 --- a/services/surfaceflinger/tests/unittests/HWComposerTest.cpp +++ b/services/surfaceflinger/tests/unittests/HWComposerTest.cpp @@ -53,6 +53,7 @@ namespace aidl = aidl::android::hardware::graphics::composer3; using Hwc2::Config; using ::aidl::android::hardware::graphics::composer3::RefreshRateChangedDebugData; +using hal::IComposerClient; using ::testing::_; using ::testing::DoAll; using ::testing::ElementsAreArray; @@ -119,6 +120,155 @@ TEST_F(HWComposerTest, getActiveMode) { } } +TEST_F(HWComposerTest, getModesWithLegacyDisplayConfigs) { + constexpr hal::HWDisplayId kHwcDisplayId = 2; + constexpr hal::HWConfigId kConfigId = 42; + + expectHotplugConnect(kHwcDisplayId); + const auto info = mHwc.onHotplug(kHwcDisplayId, hal::Connection::CONNECTED); + ASSERT_TRUE(info); + + EXPECT_CALL(*mHal, getDisplayConfigurationsSupported()).WillRepeatedly(Return(false)); + + { + EXPECT_CALL(*mHal, getDisplayConfigs(kHwcDisplayId, _)) + .WillOnce(Return(HalError::BAD_DISPLAY)); + EXPECT_TRUE(mHwc.getModes(info->id).empty()); + } + { + constexpr int32_t kWidth = 480; + constexpr int32_t kHeight = 720; + constexpr int32_t kConfigGroup = 1; + constexpr int32_t kVsyncPeriod = 16666667; + + EXPECT_CALL(*mHal, + getDisplayAttribute(kHwcDisplayId, kConfigId, IComposerClient::Attribute::WIDTH, + _)) + .WillRepeatedly(DoAll(SetArgPointee<3>(kWidth), Return(HalError::NONE))); + EXPECT_CALL(*mHal, + getDisplayAttribute(kHwcDisplayId, kConfigId, + IComposerClient::Attribute::HEIGHT, _)) + .WillRepeatedly(DoAll(SetArgPointee<3>(kHeight), Return(HalError::NONE))); + EXPECT_CALL(*mHal, + getDisplayAttribute(kHwcDisplayId, kConfigId, + IComposerClient::Attribute::CONFIG_GROUP, _)) + .WillRepeatedly(DoAll(SetArgPointee<3>(kConfigGroup), Return(HalError::NONE))); + EXPECT_CALL(*mHal, + getDisplayAttribute(kHwcDisplayId, kConfigId, + IComposerClient::Attribute::VSYNC_PERIOD, _)) + .WillRepeatedly(DoAll(SetArgPointee<3>(kVsyncPeriod), Return(HalError::NONE))); + + // Optional Parameters UNSUPPORTED + EXPECT_CALL(*mHal, + getDisplayAttribute(kHwcDisplayId, kConfigId, IComposerClient::Attribute::DPI_X, + _)) + .WillOnce(Return(HalError::UNSUPPORTED)); + EXPECT_CALL(*mHal, + getDisplayAttribute(kHwcDisplayId, kConfigId, IComposerClient::Attribute::DPI_Y, + _)) + .WillOnce(Return(HalError::UNSUPPORTED)); + + EXPECT_CALL(*mHal, getDisplayConfigs(kHwcDisplayId, _)) + .WillRepeatedly(DoAll(SetArgPointee<1>(std::vector<hal::HWConfigId>{kConfigId}), + Return(HalError::NONE))); + + auto modes = mHwc.getModes(info->id); + EXPECT_EQ(modes.size(), size_t{1}); + EXPECT_EQ(modes.front().hwcId, kConfigId); + EXPECT_EQ(modes.front().width, kWidth); + EXPECT_EQ(modes.front().height, kHeight); + EXPECT_EQ(modes.front().configGroup, kConfigGroup); + EXPECT_EQ(modes.front().vsyncPeriod, kVsyncPeriod); + EXPECT_EQ(modes.front().dpiX, -1); + EXPECT_EQ(modes.front().dpiY, -1); + + // Optional parameters are supported + constexpr int32_t kDpi = 320; + EXPECT_CALL(*mHal, + getDisplayAttribute(kHwcDisplayId, kConfigId, IComposerClient::Attribute::DPI_X, + _)) + .WillOnce(DoAll(SetArgPointee<3>(kDpi), Return(HalError::NONE))); + EXPECT_CALL(*mHal, + getDisplayAttribute(kHwcDisplayId, kConfigId, IComposerClient::Attribute::DPI_Y, + _)) + .WillOnce(DoAll(SetArgPointee<3>(kDpi), Return(HalError::NONE))); + + modes = mHwc.getModes(info->id); + EXPECT_EQ(modes.size(), size_t{1}); + EXPECT_EQ(modes.front().hwcId, kConfigId); + EXPECT_EQ(modes.front().width, kWidth); + EXPECT_EQ(modes.front().height, kHeight); + EXPECT_EQ(modes.front().configGroup, kConfigGroup); + EXPECT_EQ(modes.front().vsyncPeriod, kVsyncPeriod); + // DPI values are scaled by 1000 in the legacy implementation. + EXPECT_EQ(modes.front().dpiX, kDpi / 1000.f); + EXPECT_EQ(modes.front().dpiY, kDpi / 1000.f); + } +} + +TEST_F(HWComposerTest, getModesWithDisplayConfigurations) { + constexpr hal::HWDisplayId kHwcDisplayId = 2; + constexpr hal::HWConfigId kConfigId = 42; + expectHotplugConnect(kHwcDisplayId); + const auto info = mHwc.onHotplug(kHwcDisplayId, hal::Connection::CONNECTED); + ASSERT_TRUE(info); + + EXPECT_CALL(*mHal, getDisplayConfigurationsSupported()).WillRepeatedly(Return(true)); + + { + EXPECT_CALL(*mHal, getDisplayConfigurations(kHwcDisplayId, _)) + .WillOnce(Return(HalError::BAD_DISPLAY)); + EXPECT_TRUE(mHwc.getModes(info->id).empty()); + } + { + constexpr int32_t kWidth = 480; + constexpr int32_t kHeight = 720; + constexpr int32_t kConfigGroup = 1; + constexpr int32_t kVsyncPeriod = 16666667; + hal::DisplayConfiguration displayConfiguration; + displayConfiguration.configId = kConfigId; + displayConfiguration.configGroup = kConfigGroup; + displayConfiguration.height = kHeight; + displayConfiguration.width = kWidth; + displayConfiguration.vsyncPeriod = kVsyncPeriod; + + EXPECT_CALL(*mHal, getDisplayConfigurations(kHwcDisplayId, _)) + .WillOnce(DoAll(SetArgPointee<1>(std::vector<hal::DisplayConfiguration>{ + displayConfiguration}), + Return(HalError::NONE))); + + // Optional dpi not supported + auto modes = mHwc.getModes(info->id); + EXPECT_EQ(modes.size(), size_t{1}); + EXPECT_EQ(modes.front().hwcId, kConfigId); + EXPECT_EQ(modes.front().width, kWidth); + EXPECT_EQ(modes.front().height, kHeight); + EXPECT_EQ(modes.front().configGroup, kConfigGroup); + EXPECT_EQ(modes.front().vsyncPeriod, kVsyncPeriod); + EXPECT_EQ(modes.front().dpiX, -1); + EXPECT_EQ(modes.front().dpiY, -1); + + // Supports optional dpi parameter + constexpr int32_t kDpi = 320; + displayConfiguration.dpi = {kDpi, kDpi}; + + EXPECT_CALL(*mHal, getDisplayConfigurations(kHwcDisplayId, _)) + .WillOnce(DoAll(SetArgPointee<1>(std::vector<hal::DisplayConfiguration>{ + displayConfiguration}), + Return(HalError::NONE))); + + modes = mHwc.getModes(info->id); + EXPECT_EQ(modes.size(), size_t{1}); + EXPECT_EQ(modes.front().hwcId, kConfigId); + EXPECT_EQ(modes.front().width, kWidth); + EXPECT_EQ(modes.front().height, kHeight); + EXPECT_EQ(modes.front().configGroup, kConfigGroup); + EXPECT_EQ(modes.front().vsyncPeriod, kVsyncPeriod); + EXPECT_EQ(modes.front().dpiX, kDpi); + EXPECT_EQ(modes.front().dpiY, kDpi); + } +} + TEST_F(HWComposerTest, onVsync) { constexpr hal::HWDisplayId kHwcDisplayId = 1; expectHotplugConnect(kHwcDisplayId); 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/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/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h index d3fb9fc3f8..8d48940aa9 100644 --- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h +++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h @@ -51,6 +51,7 @@ public: ~Composer() override; MOCK_METHOD(bool, isSupported, (OptionalFeature), (const, override)); + MOCK_METHOD(bool, getDisplayConfigurationsSupported, (), (const, override)); MOCK_METHOD0(getCapabilities, std::vector<aidl::android::hardware::graphics::composer3::Capability>()); MOCK_METHOD0(dumpDebugInfo, std::string()); @@ -70,6 +71,7 @@ public: MOCK_METHOD4(getDisplayAttribute, Error(Display, Config config, IComposerClient::Attribute, int32_t*)); MOCK_METHOD2(getDisplayConfigs, Error(Display, std::vector<Config>*)); + MOCK_METHOD2(getDisplayConfigurations, Error(Display, std::vector<DisplayConfiguration>*)); MOCK_METHOD2(getDisplayName, Error(Display, std::string*)); MOCK_METHOD4(getDisplayRequests, Error(Display, uint32_t*, std::vector<Layer>*, std::vector<uint32_t>*)); 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 diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp index b73d2cb68e..114f863fa8 100644 --- a/vulkan/libvulkan/swapchain.cpp +++ b/vulkan/libvulkan/swapchain.cpp @@ -16,6 +16,7 @@ #define ATRACE_TAG ATRACE_TAG_GRAPHICS +#include <aidl/android/hardware/graphics/common/PixelFormat.h> #include <android/hardware/graphics/common/1.0/types.h> #include <grallocusage/GrallocUsageConversion.h> #include <graphicsenv/GraphicsEnv.h> @@ -25,8 +26,6 @@ #include <sync/sync.h> #include <system/window.h> #include <ui/BufferQueueDefs.h> -#include <ui/DebugUtils.h> -#include <ui/PixelFormat.h> #include <utils/StrongPointer.h> #include <utils/Timers.h> #include <utils/Trace.h> @@ -37,6 +36,7 @@ #include "driver.h" +using PixelFormat = aidl::android::hardware::graphics::common::PixelFormat; using android::hardware::graphics::common::V1_0::BufferUsage; namespace vulkan { @@ -503,27 +503,27 @@ void copy_ready_timings(Swapchain& swapchain, *count = num_copied; } -android::PixelFormat GetNativePixelFormat(VkFormat format) { - android::PixelFormat native_format = android::PIXEL_FORMAT_RGBA_8888; +PixelFormat GetNativePixelFormat(VkFormat format) { + PixelFormat native_format = PixelFormat::RGBA_8888; switch (format) { case VK_FORMAT_R8G8B8A8_UNORM: case VK_FORMAT_R8G8B8A8_SRGB: - native_format = android::PIXEL_FORMAT_RGBA_8888; + native_format = PixelFormat::RGBA_8888; break; case VK_FORMAT_R5G6B5_UNORM_PACK16: - native_format = android::PIXEL_FORMAT_RGB_565; + native_format = PixelFormat::RGB_565; break; case VK_FORMAT_R16G16B16A16_SFLOAT: - native_format = android::PIXEL_FORMAT_RGBA_FP16; + native_format = PixelFormat::RGBA_FP16; break; case VK_FORMAT_A2B10G10R10_UNORM_PACK32: - native_format = android::PIXEL_FORMAT_RGBA_1010102; + native_format = PixelFormat::RGBA_1010102; break; case VK_FORMAT_R8_UNORM: - native_format = android::PIXEL_FORMAT_R_8; + native_format = PixelFormat::R_8; break; case VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16: - native_format = android::PIXEL_FORMAT_RGBA_10101010; + native_format = PixelFormat::RGBA_10101010; break; default: ALOGV("unsupported swapchain format %d", format); @@ -1361,7 +1361,7 @@ VkResult CreateSwapchainKHR(VkDevice device, if (!allocator) allocator = &GetData(device).allocator; - android::PixelFormat native_pixel_format = + PixelFormat native_pixel_format = GetNativePixelFormat(create_info->imageFormat); android_dataspace native_dataspace = GetNativeDataspace(create_info->imageColorSpace); @@ -1462,10 +1462,11 @@ VkResult CreateSwapchainKHR(VkDevice device, const auto& dispatch = GetData(device).driver; - err = native_window_set_buffers_format(window, native_pixel_format); + err = native_window_set_buffers_format( + window, static_cast<int>(native_pixel_format)); if (err != android::OK) { ALOGE("native_window_set_buffers_format(%s) failed: %s (%d)", - decodePixelFormat(native_pixel_format).c_str(), strerror(-err), err); + toString(native_pixel_format).c_str(), strerror(-err), err); return VK_ERROR_SURFACE_LOST_KHR; } |