diff options
185 files changed, 4161 insertions, 2111 deletions
diff --git a/cmds/surfacereplayer/proto/src/trace.proto b/cmds/surfacereplayer/proto/src/trace.proto index 03a2709075..a177027e5c 100644 --- a/cmds/surfacereplayer/proto/src/trace.proto +++ b/cmds/surfacereplayer/proto/src/trace.proto @@ -101,6 +101,10 @@ message LayerStackChange { required uint32 layer_stack = 1; } +message DisplayFlagsChange { + required uint32 flags = 1; +} + message HiddenFlagChange { required bool hidden_flag = 1; } @@ -121,6 +125,7 @@ message DisplayChange { LayerStackChange layer_stack = 3; SizeChange size = 4; ProjectionChange projection = 5; + DisplayFlagsChange flags = 6; } } @@ -217,4 +222,4 @@ message BlurRegionChange { message Origin { required int32 pid = 1; required int32 uid = 2; -}
\ No newline at end of file +} diff --git a/data/etc/Android.bp b/data/etc/Android.bp index 235990a574..164fc5dde3 100644 --- a/data/etc/Android.bp +++ b/data/etc/Android.bp @@ -231,3 +231,11 @@ prebuilt_etc { src: "handheld_core_hardware.xml", defaults: ["frameworks_native_data_etc_defaults"], } + +prebuilt_etc { + name: "android.software.app_compat_overrides.xml", + product_specific: true, + sub_dir: "permissions", + src: "android.software.app_compat_overrides.xml", + filename_from_src: true, +} diff --git a/data/etc/android.software.app_compat_overrides.xml b/data/etc/android.software.app_compat_overrides.xml new file mode 100644 index 0000000000..2f9726a3f0 --- /dev/null +++ b/data/etc/android.software.app_compat_overrides.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2021 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. +--> + +<!-- Feature for devices that are opted-in to receive per-app compatibility + overrides. --> +<permissions> + <feature name="android.software.app_compat_overrides" /> +</permissions> diff --git a/include/input/Flags.h b/include/ftl/Flags.h index b12a9ed2c5..27c84769cb 100644 --- a/include/input/Flags.h +++ b/include/ftl/Flags.h @@ -22,11 +22,10 @@ #include <string> #include <type_traits> -#include "NamedEnum.h" +#include <ftl/NamedEnum.h> #include "utils/BitSet.h" -#ifndef __UI_INPUT_FLAGS_H -#define __UI_INPUT_FLAGS_H +#pragma once namespace android { @@ -279,5 +278,3 @@ Flags<F> operator|(F lhs, F rhs) { } // namespace flag_operators } // namespace android - -#endif // __UI_INPUT_FLAGS_H diff --git a/include/input/NamedEnum.h b/include/ftl/NamedEnum.h index 8d3f6b7946..6e98feeb87 100644 --- a/include/input/NamedEnum.h +++ b/include/ftl/NamedEnum.h @@ -21,8 +21,7 @@ #include <optional> #include <string> -#ifndef __UI_INPUT_NAMEDENUM_H -#define __UI_INPUT_NAMEDENUM_H +#pragma once namespace android { @@ -128,5 +127,3 @@ public: }; } // namespace android - -#endif // __UI_INPUT_NAMEDENUM_H
\ No newline at end of file diff --git a/include/input/DisplayViewport.h b/include/input/DisplayViewport.h index 5e40ca7ece..a6213f3ddd 100644 --- a/include/input/DisplayViewport.h +++ b/include/input/DisplayViewport.h @@ -18,8 +18,9 @@ #define _LIBINPUT_DISPLAY_VIEWPORT_H #include <android-base/stringprintf.h> +#include <ftl/NamedEnum.h> +#include <gui/constants.h> #include <input/Input.h> -#include <input/NamedEnum.h> #include <cinttypes> #include <optional> diff --git a/include/input/Input.h b/include/input/Input.h index 2e326cb102..cd110e8c39 100644 --- a/include/input/Input.h +++ b/include/input/Input.h @@ -124,15 +124,6 @@ constexpr int32_t VERIFIED_MOTION_EVENT_FLAGS = AMOTION_EVENT_FLAG_WINDOW_IS_OBS constexpr int32_t AMOTION_EVENT_FLAG_CANCELED = 0x20; enum { - /* Used when a motion event is not associated with any display. - * Typically used for non-pointer events. */ - ADISPLAY_ID_NONE = -1, - - /* The default display id. */ - ADISPLAY_ID_DEFAULT = 0, -}; - -enum { /* * Indicates that an input device has switches. * This input source flag is hidden from the API because switches are only used by the system @@ -354,12 +345,6 @@ private: */ constexpr float AMOTION_EVENT_INVALID_CURSOR_POSITION = std::numeric_limits<float>::quiet_NaN(); -/** - * Invalid value for display size. Used when display size isn't available for an event or doesn't - * matter. This is just a constant 0 so that it has no effect if unused. - */ -constexpr int32_t AMOTION_EVENT_INVALID_DISPLAY_SIZE = 0; - /* * Pointer coordinate data. */ @@ -592,6 +577,8 @@ public: void setCursorPosition(float x, float y); + uint32_t getDisplayOrientation() const { return mDisplayOrientation; } + int2 getDisplaySize() const { return {mDisplayWidth, mDisplayHeight}; } static inline bool isValidCursorPosition(float x, float y) { return !isnan(x) && !isnan(y); } @@ -768,8 +755,8 @@ public: int32_t flags, int32_t edgeFlags, int32_t metaState, int32_t buttonState, MotionClassification classification, const ui::Transform& transform, float xPrecision, float yPrecision, float rawXCursorPosition, - float rawYCursorPosition, int32_t displayWidth, int32_t displayHeight, - nsecs_t downTime, nsecs_t eventTime, size_t pointerCount, + float rawYCursorPosition, uint32_t displayOrientation, int32_t displayWidth, + int32_t displayHeight, nsecs_t downTime, nsecs_t eventTime, size_t pointerCount, const PointerProperties* pointerProperties, const PointerCoords* pointerCoords); void copyFrom(const MotionEvent* other, bool keepHistory); @@ -827,6 +814,7 @@ protected: float mYPrecision; float mRawXCursorPosition; float mRawYCursorPosition; + uint32_t mDisplayOrientation; int32_t mDisplayWidth; int32_t mDisplayHeight; nsecs_t mDownTime; diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h index 360dfbfd73..a790b5637f 100644 --- a/include/input/InputTransport.h +++ b/include/input/InputTransport.h @@ -136,10 +136,10 @@ struct InputMessage { float yPrecision; float xCursorPosition; float yCursorPosition; + uint32_t displayOrientation; int32_t displayWidth; int32_t displayHeight; uint32_t pointerCount; - uint32_t empty3; /** * The "pointers" field must be the last field of the struct InputMessage. * When we send the struct InputMessage across the socket, we are not @@ -355,8 +355,9 @@ public: int32_t metaState, int32_t buttonState, MotionClassification classification, const ui::Transform& transform, float xPrecision, float yPrecision, float xCursorPosition, - float yCursorPosition, int32_t displayWidth, int32_t displayHeight, - nsecs_t downTime, nsecs_t eventTime, uint32_t pointerCount, + float yCursorPosition, uint32_t displayOrientation, + int32_t displayWidth, int32_t displayHeight, nsecs_t downTime, + nsecs_t eventTime, uint32_t pointerCount, const PointerProperties* pointerProperties, const PointerCoords* pointerCoords); diff --git a/libs/ftl/Android.bp b/libs/ftl/Android.bp index 97626bec7d..2524c5f6d2 100644 --- a/libs/ftl/Android.bp +++ b/libs/ftl/Android.bp @@ -14,7 +14,9 @@ cc_test { address: true, }, srcs: [ + "Flags_test.cpp", "future_test.cpp", + "NamedEnum_test.cpp", "small_map_test.cpp", "small_vector_test.cpp", "static_vector_test.cpp", @@ -25,4 +27,12 @@ cc_test { "-Wextra", "-Wpedantic", ], + + header_libs: [ + "libbase_headers", + ], + + shared_libs: [ + "libbase", + ], } diff --git a/libs/input/tests/Flags_test.cpp b/libs/ftl/Flags_test.cpp index 6de030f7cf..8c00b5299b 100644 --- a/libs/input/tests/Flags_test.cpp +++ b/libs/ftl/Flags_test.cpp @@ -15,7 +15,7 @@ */ #include <gtest/gtest.h> -#include <input/Flags.h> +#include <ftl/Flags.h> #include <type_traits> diff --git a/libs/input/tests/NamedEnum_test.cpp b/libs/ftl/NamedEnum_test.cpp index 74a0044387..dff2b8aaa1 100644 --- a/libs/input/tests/NamedEnum_test.cpp +++ b/libs/ftl/NamedEnum_test.cpp @@ -15,7 +15,7 @@ */ #include <gtest/gtest.h> -#include <input/NamedEnum.h> +#include <ftl/NamedEnum.h> namespace android { diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp index 64203f78a8..326da3a7b5 100644 --- a/libs/gui/Android.bp +++ b/libs/gui/Android.bp @@ -51,6 +51,59 @@ cc_library_headers { ], } +// AIDL files that should be exposed to java +filegroup { + name: "guiconstants_aidl", + srcs: [ + "android/**/TouchOcclusionMode.aidl", + ], +} + +cc_library_static { + name: "libgui_window_info_static", + vendor_available: true, + host_supported: true, + srcs: [ + ":guiconstants_aidl", + "android/gui/FocusRequest.aidl", + "android/gui/InputApplicationInfo.aidl", + "android/gui/IWindowInfosListener.aidl", + "android/gui/IWindowInfosReportedListener.aidl", + "android/gui/WindowInfo.aidl", + "WindowInfo.cpp", + ], + + shared_libs: [ + "libbinder", + ], + + local_include_dirs: [ + "include", + ], + + export_shared_lib_headers: [ + "libbinder", + ], + + static_libs: [ + "libui-types", + ], + + aidl: { + export_aidl_headers: true + }, + + include_dirs: [ + "frameworks/native/include", + ], + + target: { + darwin: { + enabled: false, + }, + }, +} + filegroup { name: "libgui_aidl", srcs: ["aidl/**/*.aidl"], @@ -77,12 +130,15 @@ cc_library_static { "libbinder", ], + static_libs: [ + "libui-types", + ], + aidl: { export_aidl_headers: true } } - cc_library_shared { name: "libgui", vendor_available: true, @@ -96,9 +152,11 @@ cc_library_shared { static_libs: [ "libgui_aidl_static", + "libgui_window_info_static", ], export_static_lib_headers: [ "libgui_aidl_static", + "libgui_window_info_static", ], srcs: [ @@ -139,6 +197,7 @@ cc_library_shared { "SyncFeatures.cpp", "TransactionTracing.cpp", "view/Surface.cpp", + "WindowInfosListenerReporter.cpp", "bufferqueue/1.0/B2HProducerListener.cpp", "bufferqueue/1.0/H2BGraphicBufferProducer.cpp", "bufferqueue/2.0/B2HProducerListener.cpp", @@ -150,13 +209,11 @@ cc_library_shared { "libbinder", "libbufferhub", "libbufferhubqueue", // TODO(b/70046255): Remove this once BufferHub is integrated into libgui. - "libinput", "libpdx_default_transport", ], export_shared_lib_headers: [ "libbinder", - "libinput", ], export_header_lib_headers: [ @@ -168,7 +225,6 @@ cc_library_shared { vendor: { cflags: [ "-DNO_BUFFERHUB", - "-DNO_INPUT", ], exclude_srcs: [ "BufferHubConsumer.cpp", @@ -178,7 +234,6 @@ cc_library_shared { "android.frameworks.bufferhub@1.0", "libbufferhub", "libbufferhubqueue", - "libinput", "libpdx_default_transport", ], }, diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index 94e1ae1c74..d1f57b03bc 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -38,7 +38,7 @@ using namespace std::chrono_literals; namespace { -inline const char* toString(bool b) { +inline const char* boolToString(bool b) { return b ? "true" : "false"; } } // namespace @@ -530,7 +530,7 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) { BQA_LOGV("processNextBufferLocked size=%dx%d mFrameNumber=%" PRIu64 " applyTransaction=%s mTimestamp=%" PRId64 "%s mPendingTransactions.size=%d" " graphicBufferId=%" PRIu64 "%s transform=%d", - mSize.width, mSize.height, bufferItem.mFrameNumber, toString(applyTransaction), + mSize.width, mSize.height, bufferItem.mFrameNumber, boolToString(applyTransaction), bufferItem.mTimestamp, bufferItem.mIsAutoTimestamp ? "(auto)" : "", static_cast<uint32_t>(mPendingTransactions.size()), bufferItem.mGraphicBuffer->getId(), bufferItem.mAutoRefresh ? " mAutoRefresh" : "", bufferItem.mTransform); @@ -560,7 +560,7 @@ void BLASTBufferQueue::onFrameAvailable(const BufferItem& item) { mNumFrameAvailable + mNumAcquired - mPendingRelease.size()); BQA_LOGV("onFrameAvailable framenumber=%" PRIu64 " nextTransactionSet=%s", item.mFrameNumber, - toString(nextTransactionSet)); + boolToString(nextTransactionSet)); processNextBufferLocked(nextTransactionSet /* useNextTransaction */); } diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp index 5023b6bb81..2930154ad4 100644 --- a/libs/gui/BufferQueueCore.cpp +++ b/libs/gui/BufferQueueCore.cpp @@ -34,7 +34,6 @@ #include <gui/BufferQueueCore.h> #include <gui/IConsumerListener.h> #include <gui/IProducerListener.h> -#include <gui/ISurfaceComposer.h> #include <private/gui/ComposerService.h> #include <system/window.h> diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index 0d7795e1ba..2a980bd118 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -44,6 +44,7 @@ namespace android { +using gui::IWindowInfosListener; using ui::ColorMode; class BpSurfaceComposer : public BpInterface<ISurfaceComposer> @@ -1227,6 +1228,22 @@ public: return reply.readInt32(buffers); } + + status_t addWindowInfosListener( + const sp<IWindowInfosListener>& windowInfosListener) const override { + Parcel data, reply; + SAFE_PARCEL(data.writeInterfaceToken, ISurfaceComposer::getInterfaceDescriptor()); + SAFE_PARCEL(data.writeStrongBinder, IInterface::asBinder(windowInfosListener)); + return remote()->transact(BnSurfaceComposer::ADD_WINDOW_INFOS_LISTENER, data, &reply); + } + + status_t removeWindowInfosListener( + const sp<IWindowInfosListener>& windowInfosListener) const override { + Parcel data, reply; + SAFE_PARCEL(data.writeInterfaceToken, ISurfaceComposer::getInterfaceDescriptor()); + SAFE_PARCEL(data.writeStrongBinder, IInterface::asBinder(windowInfosListener)); + return remote()->transact(BnSurfaceComposer::REMOVE_WINDOW_INFOS_LISTENER, data, &reply); + } }; // Out-of-line virtual method definition to trigger vtable emission in this @@ -2107,6 +2124,20 @@ status_t BnSurfaceComposer::onTransact( SAFE_PARCEL(reply->writeBool, success); return err; } + case ADD_WINDOW_INFOS_LISTENER: { + CHECK_INTERFACE(ISurfaceComposer, data, reply); + sp<IWindowInfosListener> listener; + SAFE_PARCEL(data.readStrongBinder, &listener); + + return addWindowInfosListener(listener); + } + case REMOVE_WINDOW_INFOS_LISTENER: { + CHECK_INTERFACE(ISurfaceComposer, data, reply); + sp<IWindowInfosListener> listener; + SAFE_PARCEL(data.readStrongBinder, &listener); + + return removeWindowInfosListener(listener); + } default: { return BBinder::onTransact(code, data, reply, flags); } diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 076c90dd23..8a7a8711bf 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -31,6 +31,9 @@ namespace android { +using gui::FocusRequest; +using gui::WindowInfoHandle; + layer_state_t::layer_state_t() : what(0), x(0), @@ -95,9 +98,7 @@ status_t layer_state_t::write(Parcel& output) const SAFE_PARCEL(output.writeFloat, color.r); SAFE_PARCEL(output.writeFloat, color.g); SAFE_PARCEL(output.writeFloat, color.b); -#ifndef NO_INPUT - SAFE_PARCEL(inputHandle->writeToParcel, &output); -#endif + SAFE_PARCEL(windowInfoHandle->writeToParcel, &output); SAFE_PARCEL(output.write, transparentRegion); SAFE_PARCEL(output.writeUint32, transform); SAFE_PARCEL(output.writeBool, transformToDisplayInverse); @@ -173,6 +174,7 @@ status_t layer_state_t::write(Parcel& output) const SAFE_PARCEL(output.write, destinationFrame); SAFE_PARCEL(output.writeBool, isTrustedOverlay); + SAFE_PARCEL(output.writeStrongBinder, releaseBufferEndpoint); return NO_ERROR; } @@ -207,9 +209,7 @@ status_t layer_state_t::read(const Parcel& input) color.g = tmpFloat; SAFE_PARCEL(input.readFloat, &tmpFloat); color.b = tmpFloat; -#ifndef NO_INPUT - SAFE_PARCEL(inputHandle->readFromParcel, &input); -#endif + SAFE_PARCEL(windowInfoHandle->readFromParcel, &input); SAFE_PARCEL(input.read, transparentRegion); SAFE_PARCEL(input.readUint32, &transform); @@ -304,6 +304,7 @@ status_t layer_state_t::read(const Parcel& input) SAFE_PARCEL(input.read, destinationFrame); SAFE_PARCEL(input.readBool, &isTrustedOverlay); + SAFE_PARCEL(input.readNullableStrongBinder, &releaseBufferEndpoint); return NO_ERROR; } @@ -318,6 +319,7 @@ status_t ComposerState::read(const Parcel& input) { DisplayState::DisplayState() : what(0), layerStack(0), + flags(0), layerStackSpaceRect(Rect::EMPTY_RECT), orientedDisplaySpaceRect(Rect::EMPTY_RECT), width(0), @@ -328,6 +330,7 @@ status_t DisplayState::write(Parcel& output) const { SAFE_PARCEL(output.writeStrongBinder, IInterface::asBinder(surface)); SAFE_PARCEL(output.writeUint32, what); SAFE_PARCEL(output.writeUint32, layerStack); + SAFE_PARCEL(output.writeUint32, flags); SAFE_PARCEL(output.writeUint32, toRotationInt(orientation)); SAFE_PARCEL(output.write, layerStackSpaceRect); SAFE_PARCEL(output.write, orientedDisplaySpaceRect); @@ -344,6 +347,7 @@ status_t DisplayState::read(const Parcel& input) { SAFE_PARCEL(input.readUint32, &what); SAFE_PARCEL(input.readUint32, &layerStack); + SAFE_PARCEL(input.readUint32, &flags); uint32_t tmpUint = 0; SAFE_PARCEL(input.readUint32, &tmpUint); orientation = ui::toRotation(tmpUint); @@ -364,6 +368,10 @@ void DisplayState::merge(const DisplayState& other) { what |= eLayerStackChanged; layerStack = other.layerStack; } + if (other.what & eFlagsChanged) { + what |= eFlagsChanged; + flags = other.flags; + } if (other.what & eDisplayProjectionChanged) { what |= eDisplayProjectionChanged; orientation = other.orientation; @@ -455,6 +463,7 @@ void layer_state_t::merge(const layer_state_t& other) { if (other.what & eBufferChanged) { what |= eBufferChanged; buffer = other.buffer; + releaseBufferEndpoint = other.releaseBufferEndpoint; } if (other.what & eAcquireFenceChanged) { what |= eAcquireFenceChanged; @@ -487,14 +496,10 @@ void layer_state_t::merge(const layer_state_t& other) { if (other.what & eHasListenerCallbacksChanged) { what |= eHasListenerCallbacksChanged; } - -#ifndef NO_INPUT if (other.what & eInputInfoChanged) { what |= eInputInfoChanged; - inputHandle = new InputWindowHandle(*other.inputHandle); + windowInfoHandle = new WindowInfoHandle(*other.windowInfoHandle); } -#endif - if (other.what & eCachedBufferChanged) { what |= eCachedBufferChanged; cachedBuffer = other.cachedBuffer; @@ -593,11 +598,9 @@ status_t layer_state_t::matrix22_t::read(const Parcel& input) { bool InputWindowCommands::merge(const InputWindowCommands& other) { bool changes = false; -#ifndef NO_INPUT changes |= !other.focusRequests.empty(); focusRequests.insert(focusRequests.end(), std::make_move_iterator(other.focusRequests.begin()), std::make_move_iterator(other.focusRequests.end())); -#endif changes |= other.syncInputWindows && !syncInputWindows; syncInputWindows |= other.syncInputWindows; return changes; @@ -605,31 +608,23 @@ bool InputWindowCommands::merge(const InputWindowCommands& other) { bool InputWindowCommands::empty() const { bool empty = true; -#ifndef NO_INPUT empty = focusRequests.empty() && !syncInputWindows; -#endif return empty; } void InputWindowCommands::clear() { -#ifndef NO_INPUT focusRequests.clear(); -#endif syncInputWindows = false; } status_t InputWindowCommands::write(Parcel& output) const { -#ifndef NO_INPUT SAFE_PARCEL(output.writeParcelableVector, focusRequests); -#endif SAFE_PARCEL(output.writeBool, syncInputWindows); return NO_ERROR; } status_t InputWindowCommands::read(const Parcel& input) { -#ifndef NO_INPUT SAFE_PARCEL(input.readParcelableVector, &focusRequests); -#endif SAFE_PARCEL(input.readBool, &syncInputWindows); return NO_ERROR; } diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 96da8efd19..a2037ac614 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -19,6 +19,7 @@ #include <stdint.h> #include <sys/types.h> +#include <android/gui/IWindowInfosListener.h> #include <utils/Errors.h> #include <utils/Log.h> #include <utils/SortedVector.h> @@ -39,14 +40,11 @@ #include <gui/LayerState.h> #include <gui/Surface.h> #include <gui/SurfaceComposerClient.h> +#include <gui/WindowInfo.h> #include <private/gui/ParcelUtils.h> #include <ui/DisplayMode.h> #include <ui/DynamicDisplayInfo.h> -#ifndef NO_INPUT -#include <input/InputWindow.h> -#endif - #include <private/gui/ComposerService.h> // This server size should always be smaller than the server cache size @@ -54,6 +52,10 @@ namespace android { +using gui::FocusRequest; +using gui::WindowInfo; +using gui::WindowInfoHandle; +using gui::WindowInfosListener; using ui::ColorMode; // --------------------------------------------------------------------------- @@ -95,6 +97,7 @@ bool ComposerService::connectLocked() { if (instance.mComposerService == nullptr) { if (ComposerService::getInstance().connectLocked()) { ALOGD("ComposerService reconnected"); + WindowInfosListenerReporter::getInstance()->reconnect(instance.mComposerService); } } return instance.mComposerService; @@ -144,8 +147,16 @@ int64_t TransactionCompletedListener::getNextIdLocked() { return mCallbackIdCounter++; } +sp<TransactionCompletedListener> TransactionCompletedListener::sInstance = nullptr; + +void TransactionCompletedListener::setInstance(const sp<TransactionCompletedListener>& listener) { + sInstance = listener; +} + sp<TransactionCompletedListener> TransactionCompletedListener::getInstance() { - static sp<TransactionCompletedListener> sInstance = new TransactionCompletedListener; + if (sInstance == nullptr) { + sInstance = new TransactionCompletedListener; + } return sInstance; } @@ -183,7 +194,7 @@ CallbackId TransactionCompletedListener::addCallbackFunction( void TransactionCompletedListener::addJankListener(const sp<JankDataListener>& listener, sp<SurfaceControl> surfaceControl) { std::lock_guard<std::mutex> lock(mMutex); - mJankListeners.insert({surfaceControl->getHandle(), listener}); + mJankListeners.insert({surfaceControl->getLayerId(), listener}); } void TransactionCompletedListener::removeJankListener(const sp<JankDataListener>& listener) { @@ -212,8 +223,8 @@ void TransactionCompletedListener::removeReleaseBufferCallback( void TransactionCompletedListener::addSurfaceStatsListener(void* context, void* cookie, sp<SurfaceControl> surfaceControl, SurfaceStatsCallback listener) { std::scoped_lock<std::recursive_mutex> lock(mSurfaceStatsListenerMutex); - mSurfaceStatsListeners.insert({surfaceControl->getHandle(), - SurfaceStatsCallbackEntry(context, cookie, listener)}); + mSurfaceStatsListeners.insert( + {surfaceControl->getLayerId(), SurfaceStatsCallbackEntry(context, cookie, listener)}); } void TransactionCompletedListener::removeSurfaceStatsListener(void* context, void* cookie) { @@ -243,7 +254,7 @@ void TransactionCompletedListener::addSurfaceControlToCallbacks( void TransactionCompletedListener::onTransactionCompleted(ListenerStats listenerStats) { std::unordered_map<CallbackId, CallbackTranslation, CallbackIdHash> callbacksMap; - std::multimap<sp<IBinder>, sp<JankDataListener>> jankListenersMap; + std::multimap<int32_t, sp<JankDataListener>> jankListenersMap; { std::lock_guard<std::mutex> lock(mMutex); @@ -341,13 +352,26 @@ void TransactionCompletedListener::onTransactionCompleted(ListenerStats listener callbackFunction(transactionStats.latchTime, transactionStats.presentFence, surfaceControlStats); } + for (const auto& surfaceStats : transactionStats.surfaceStats) { + // The callbackMap contains the SurfaceControl object, which we need to look up the + // layerId. Since we don't know which callback contains the SurfaceControl, iterate + // through all until the SC is found. + int32_t layerId = -1; + for (auto callbackId : transactionStats.callbackIds) { + sp<SurfaceControl> sc = + callbacksMap[callbackId].surfaceControls[surfaceStats.surfaceControl]; + if (sc != nullptr) { + layerId = sc->getLayerId(); + break; + } + } + { // Acquire surface stats listener lock such that we guarantee that after calling // unregister, there won't be any further callback. std::scoped_lock<std::recursive_mutex> lock(mSurfaceStatsListenerMutex); - auto listenerRange = mSurfaceStatsListeners.equal_range( - surfaceStats.surfaceControl); + auto listenerRange = mSurfaceStatsListeners.equal_range(layerId); for (auto it = listenerRange.first; it != listenerRange.second; it++) { auto entry = it->second; entry.callback(entry.context, transactionStats.latchTime, @@ -356,7 +380,7 @@ void TransactionCompletedListener::onTransactionCompleted(ListenerStats listener } if (surfaceStats.jankData.empty()) continue; - auto jankRange = jankListenersMap.equal_range(surfaceStats.surfaceControl); + auto jankRange = jankListenersMap.equal_range(layerId); for (auto it = jankRange.first; it != jankRange.second; it++) { it->second->onJankDataAvailable(surfaceStats.jankData); } @@ -1271,6 +1295,7 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setBuffe removeReleaseBufferCallback(s); s->what |= layer_state_t::eBufferChanged; s->buffer = buffer; + s->releaseBufferEndpoint = IInterface::asBinder(TransactionCompletedListener::getIInstance()); if (mIsAutoTimestamp) { mDesiredPresentTime = systemTime(); } @@ -1491,16 +1516,14 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrame return *this; } -#ifndef NO_INPUT SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setInputWindowInfo( - const sp<SurfaceControl>& sc, - const InputWindowInfo& info) { + const sp<SurfaceControl>& sc, const WindowInfo& info) { layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; return *this; } - s->inputHandle = new InputWindowHandle(info); + s->windowInfoHandle = new WindowInfoHandle(info); s->what |= layer_state_t::eInputInfoChanged; return *this; } @@ -1516,8 +1539,6 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::syncInpu return *this; } -#endif - SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setColorTransform( const sp<SurfaceControl>& sc, const mat3& matrix, const vec3& translation) { layer_state_t* s = getLayerState(sc); @@ -1758,6 +1779,12 @@ void SurfaceComposerClient::Transaction::setDisplayLayerStack(const sp<IBinder>& s.what |= DisplayState::eLayerStackChanged; } +void SurfaceComposerClient::Transaction::setDisplayFlags(const sp<IBinder>& token, uint32_t flags) { + DisplayState& s(getDisplayState(token)); + s.flags = flags; + s.what |= DisplayState::eFlagsChanged; +} + void SurfaceComposerClient::Transaction::setDisplayProjection(const sp<IBinder>& token, ui::Rotation orientation, const Rect& layerStackRect, @@ -1779,15 +1806,10 @@ void SurfaceComposerClient::Transaction::setDisplaySize(const sp<IBinder>& token // --------------------------------------------------------------------------- -SurfaceComposerClient::SurfaceComposerClient() - : mStatus(NO_INIT) -{ -} +SurfaceComposerClient::SurfaceComposerClient() : mStatus(NO_INIT) {} SurfaceComposerClient::SurfaceComposerClient(const sp<ISurfaceComposerClient>& client) - : mStatus(NO_ERROR), mClient(client) -{ -} + : mStatus(NO_ERROR), mClient(client) {} void SurfaceComposerClient::onFirstRef() { sp<ISurfaceComposer> sf(ComposerService::getComposerService()); @@ -2153,6 +2175,18 @@ int SurfaceComposerClient::getGPUContextPriority() { return ComposerService::getComposerService()->getGPUContextPriority(); } +status_t SurfaceComposerClient::addWindowInfosListener( + const sp<WindowInfosListener>& windowInfosListener) { + return WindowInfosListenerReporter::getInstance() + ->addWindowInfosListener(windowInfosListener, ComposerService::getComposerService()); +} + +status_t SurfaceComposerClient::removeWindowInfosListener( + const sp<WindowInfosListener>& windowInfosListener) { + return WindowInfosListenerReporter::getInstance() + ->removeWindowInfosListener(windowInfosListener, ComposerService::getComposerService()); +} + // ---------------------------------------------------------------------------- status_t ScreenshotClient::captureDisplay(const DisplayCaptureArgs& captureArgs, diff --git a/libs/input/InputWindow.cpp b/libs/gui/WindowInfo.cpp index 99477200db..b2ef7aabc9 100644 --- a/libs/input/InputWindow.cpp +++ b/libs/gui/WindowInfo.cpp @@ -15,50 +15,47 @@ */ #include <type_traits> -#define LOG_TAG "InputWindow" +#define LOG_TAG "WindowInfo" #define LOG_NDEBUG 0 #include <android-base/stringprintf.h> #include <binder/Parcel.h> -#include <input/InputTransport.h> -#include <input/InputWindow.h> +#include <gui/WindowInfo.h> #include <log/log.h> -namespace android { +namespace android::gui { - -// --- InputWindowInfo --- -void InputWindowInfo::addTouchableRegion(const Rect& region) { +// --- WindowInfo --- +void WindowInfo::addTouchableRegion(const Rect& region) { touchableRegion.orSelf(region); } -bool InputWindowInfo::touchableRegionContainsPoint(int32_t x, int32_t y) const { - return touchableRegion.contains(x,y); +bool WindowInfo::touchableRegionContainsPoint(int32_t x, int32_t y) const { + return touchableRegion.contains(x, y); } -bool InputWindowInfo::frameContainsPoint(int32_t x, int32_t y) const { - return x >= frameLeft && x < frameRight - && y >= frameTop && y < frameBottom; +bool WindowInfo::frameContainsPoint(int32_t x, int32_t y) const { + return x >= frameLeft && x < frameRight && y >= frameTop && y < frameBottom; } -bool InputWindowInfo::supportsSplitTouch() const { +bool WindowInfo::supportsSplitTouch() const { return flags.test(Flag::SPLIT_TOUCH); } -bool InputWindowInfo::overlaps(const InputWindowInfo* other) const { - return frameLeft < other->frameRight && frameRight > other->frameLeft - && frameTop < other->frameBottom && frameBottom > other->frameTop; +bool WindowInfo::overlaps(const WindowInfo* other) const { + return frameLeft < other->frameRight && frameRight > other->frameLeft && + frameTop < other->frameBottom && frameBottom > other->frameTop; } -bool InputWindowInfo::operator==(const InputWindowInfo& info) const { +bool WindowInfo::operator==(const WindowInfo& info) const { return info.token == token && info.id == id && info.name == name && info.flags == flags && info.type == type && info.dispatchingTimeout == dispatchingTimeout && info.frameLeft == frameLeft && info.frameTop == frameTop && info.frameRight == frameRight && info.frameBottom == frameBottom && info.surfaceInset == surfaceInset && info.globalScaleFactor == globalScaleFactor && - info.transform == transform && info.displayWidth == displayWidth && - info.displayHeight == displayHeight && + info.transform == transform && info.displayOrientation == displayOrientation && + info.displayWidth == displayWidth && info.displayHeight == displayHeight && info.touchableRegion.hasSameRects(touchableRegion) && info.visible == visible && info.trustedOverlay == trustedOverlay && info.focusable == focusable && info.touchOcclusionMode == touchOcclusionMode && info.hasWallpaper == hasWallpaper && @@ -69,7 +66,7 @@ bool InputWindowInfo::operator==(const InputWindowInfo& info) const { info.applicationInfo == applicationInfo; } -status_t InputWindowInfo::writeToParcel(android::Parcel* parcel) const { +status_t WindowInfo::writeToParcel(android::Parcel* parcel) const { if (parcel == nullptr) { ALOGE("%s: Null parcel", __func__); return BAD_VALUE; @@ -86,7 +83,7 @@ status_t InputWindowInfo::writeToParcel(android::Parcel* parcel) const { parcel->writeInt32(id) ?: parcel->writeUtf8AsUtf16(name) ?: parcel->writeInt32(flags.get()) ?: - parcel->writeInt32(static_cast<std::underlying_type_t<InputWindowInfo::Type>>(type)) ?: + parcel->writeInt32(static_cast<std::underlying_type_t<WindowInfo::Type>>(type)) ?: parcel->writeInt32(frameLeft) ?: parcel->writeInt32(frameTop) ?: parcel->writeInt32(frameRight) ?: @@ -100,6 +97,7 @@ status_t InputWindowInfo::writeToParcel(android::Parcel* parcel) const { parcel->writeFloat(transform.dtdy()) ?: parcel->writeFloat(transform.dsdy()) ?: parcel->writeFloat(transform.ty()) ?: + parcel->writeUint32(displayOrientation) ?: parcel->writeInt32(displayWidth) ?: parcel->writeInt32(displayHeight) ?: parcel->writeBool(visible) ?: @@ -117,12 +115,13 @@ status_t InputWindowInfo::writeToParcel(android::Parcel* parcel) const { applicationInfo.writeToParcel(parcel) ?: parcel->write(touchableRegion) ?: parcel->writeBool(replaceTouchableRegionWithCrop) ?: - parcel->writeStrongBinder(touchableRegionCropHandle.promote()); + parcel->writeStrongBinder(touchableRegionCropHandle.promote()) ?: + parcel->writeStrongBinder(windowToken); // clang-format on return status; } -status_t InputWindowInfo::readFromParcel(const android::Parcel* parcel) { +status_t WindowInfo::readFromParcel(const android::Parcel* parcel) { if (parcel == nullptr) { ALOGE("%s: Null parcel", __func__); return BAD_VALUE; @@ -156,6 +155,7 @@ status_t InputWindowInfo::readFromParcel(const android::Parcel* parcel) { parcel->readFloat(&dtdy) ?: parcel->readFloat(&dsdy) ?: parcel->readFloat(&ty) ?: + parcel->readUint32(&displayOrientation) ?: parcel->readInt32(&displayWidth) ?: parcel->readInt32(&displayHeight) ?: parcel->readBool(&visible) ?: @@ -176,11 +176,13 @@ status_t InputWindowInfo::readFromParcel(const android::Parcel* parcel) { touchOcclusionMode = static_cast<TouchOcclusionMode>(touchOcclusionModeInt); inputFeatures = Flags<Feature>(parcel->readInt32()); + // clang-format off status = parcel->readInt32(&displayId) ?: parcel->readInt32(&portalToDisplayId) ?: applicationInfo.readFromParcel(parcel) ?: parcel->read(touchableRegion) ?: parcel->readBool(&replaceTouchableRegionWithCrop); + // clang-format on if (status != OK) { return status; @@ -189,36 +191,37 @@ status_t InputWindowInfo::readFromParcel(const android::Parcel* parcel) { touchableRegionCropHandle = parcel->readStrongBinder(); transform.set({dsdx, dtdx, tx, dtdy, dsdy, ty, 0, 0, 1}); - return OK; + status = parcel->readNullableStrongBinder(&windowToken); + return status; } -// --- InputWindowHandle --- +// --- WindowInfoHandle --- -InputWindowHandle::InputWindowHandle() {} +WindowInfoHandle::WindowInfoHandle() {} -InputWindowHandle::~InputWindowHandle() {} +WindowInfoHandle::~WindowInfoHandle() {} -InputWindowHandle::InputWindowHandle(const InputWindowHandle& other) : mInfo(other.mInfo) {} +WindowInfoHandle::WindowInfoHandle(const WindowInfoHandle& other) : mInfo(other.mInfo) {} -InputWindowHandle::InputWindowHandle(const InputWindowInfo& other) : mInfo(other) {} +WindowInfoHandle::WindowInfoHandle(const WindowInfo& other) : mInfo(other) {} -status_t InputWindowHandle::writeToParcel(android::Parcel* parcel) const { +status_t WindowInfoHandle::writeToParcel(android::Parcel* parcel) const { return mInfo.writeToParcel(parcel); } -status_t InputWindowHandle::readFromParcel(const android::Parcel* parcel) { +status_t WindowInfoHandle::readFromParcel(const android::Parcel* parcel) { return mInfo.readFromParcel(parcel); } -void InputWindowHandle::releaseChannel() { +void WindowInfoHandle::releaseChannel() { mInfo.token.clear(); } -sp<IBinder> InputWindowHandle::getToken() const { +sp<IBinder> WindowInfoHandle::getToken() const { return mInfo.token; } -void InputWindowHandle::updateFrom(sp<InputWindowHandle> handle) { +void WindowInfoHandle::updateFrom(sp<WindowInfoHandle> handle) { mInfo = handle->mInfo; } -} // namespace android +} // namespace android::gui diff --git a/libs/gui/WindowInfosListenerReporter.cpp b/libs/gui/WindowInfosListenerReporter.cpp new file mode 100644 index 0000000000..c00a4389ad --- /dev/null +++ b/libs/gui/WindowInfosListenerReporter.cpp @@ -0,0 +1,98 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <gui/ISurfaceComposer.h> +#include <gui/WindowInfosListenerReporter.h> + +namespace android { + +using gui::IWindowInfosReportedListener; +using gui::WindowInfo; +using gui::WindowInfosListener; + +sp<WindowInfosListenerReporter> WindowInfosListenerReporter::getInstance() { + static sp<WindowInfosListenerReporter> sInstance = new WindowInfosListenerReporter; + return sInstance; +} + +status_t WindowInfosListenerReporter::addWindowInfosListener( + const sp<WindowInfosListener>& windowInfosListener, + const sp<ISurfaceComposer>& surfaceComposer) { + status_t status = OK; + { + std::scoped_lock lock(mListenersMutex); + if (mWindowInfosListeners.empty()) { + status = surfaceComposer->addWindowInfosListener(this); + } + + if (status == OK) { + mWindowInfosListeners.insert(windowInfosListener); + } + } + + return status; +} + +status_t WindowInfosListenerReporter::removeWindowInfosListener( + const sp<WindowInfosListener>& windowInfosListener, + const sp<ISurfaceComposer>& surfaceComposer) { + status_t status = OK; + { + std::scoped_lock lock(mListenersMutex); + if (mWindowInfosListeners.size() == 1) { + status = surfaceComposer->removeWindowInfosListener(this); + } + + if (status == OK) { + mWindowInfosListeners.erase(windowInfosListener); + } + } + + return status; +} + +binder::Status WindowInfosListenerReporter::onWindowInfosChanged( + const std::vector<WindowInfo>& windowInfos, + const sp<IWindowInfosReportedListener>& windowInfosReportedListener) { + std::unordered_set<sp<WindowInfosListener>, ISurfaceComposer::SpHash<WindowInfosListener>> + windowInfosListeners; + + { + std::scoped_lock lock(mListenersMutex); + for (auto listener : mWindowInfosListeners) { + windowInfosListeners.insert(listener); + } + } + + for (auto listener : windowInfosListeners) { + listener->onWindowInfosChanged(windowInfos); + } + + if (windowInfosReportedListener) { + windowInfosReportedListener->onWindowInfosReported(); + } + + return binder::Status::ok(); +} + +void WindowInfosListenerReporter::reconnect(const sp<ISurfaceComposer>& composerService) { + std::scoped_lock lock(mListenersMutex); + if (!mWindowInfosListeners.empty()) { + composerService->addWindowInfosListener(this); + } +} + +} // namespace android
\ No newline at end of file diff --git a/libs/input/android/FocusRequest.aidl b/libs/gui/android/gui/FocusRequest.aidl index 8812d34a72..90186351c5 100644 --- a/libs/input/android/FocusRequest.aidl +++ b/libs/gui/android/gui/FocusRequest.aidl @@ -14,7 +14,7 @@ * limitations under the License. */ -package android; +package android.gui; /** @hide */ parcelable FocusRequest { diff --git a/libs/gui/android/gui/IWindowInfosListener.aidl b/libs/gui/android/gui/IWindowInfosListener.aidl new file mode 100644 index 0000000000..d4553ca82d --- /dev/null +++ b/libs/gui/android/gui/IWindowInfosListener.aidl @@ -0,0 +1,26 @@ +/* + * Copyright 2021 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.IWindowInfosReportedListener; +import android.gui.WindowInfo; + +/** @hide */ +oneway interface IWindowInfosListener +{ + void onWindowInfosChanged(in WindowInfo[] windowInfos, in @nullable IWindowInfosReportedListener windowInfosReportedListener); +} diff --git a/libs/input/android/os/ISetInputWindowsListener.aidl b/libs/gui/android/gui/IWindowInfosReportedListener.aidl index bb58fb671b..0e4cce61a2 100644 --- a/libs/input/android/os/ISetInputWindowsListener.aidl +++ b/libs/gui/android/gui/IWindowInfosReportedListener.aidl @@ -14,10 +14,10 @@ * limitations under the License. */ -package android.os; +package android.gui; /** @hide */ -oneway interface ISetInputWindowsListener +oneway interface IWindowInfosReportedListener { - void onSetInputWindowsFinished(); + void onWindowInfosReported(); } diff --git a/libs/input/android/InputApplicationInfo.aidl b/libs/gui/android/gui/InputApplicationInfo.aidl index 933603916d..c0fd666543 100644 --- a/libs/input/android/InputApplicationInfo.aidl +++ b/libs/gui/android/gui/InputApplicationInfo.aidl @@ -14,7 +14,7 @@ * limitations under the License. */ -package android; +package android.gui; parcelable InputApplicationInfo { @nullable IBinder token; diff --git a/libs/input/android/os/TouchOcclusionMode.aidl b/libs/gui/android/gui/TouchOcclusionMode.aidl index 106f159a50..d91d052135 100644 --- a/libs/input/android/os/TouchOcclusionMode.aidl +++ b/libs/gui/android/gui/TouchOcclusionMode.aidl @@ -14,7 +14,7 @@ * limitations under the License. */ -package android.os; +package android.gui; /** diff --git a/libs/input/android/InputWindowInfo.aidl b/libs/gui/android/gui/WindowInfo.aidl index eeaf400227..2c85d155a8 100644 --- a/libs/input/android/InputWindowInfo.aidl +++ b/libs/gui/android/gui/WindowInfo.aidl @@ -1,5 +1,4 @@ -/* //device/java/android/android/view/InputChannel.aidl -** +/* ** Copyright 2020, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); @@ -15,6 +14,6 @@ ** limitations under the License. */ -package android; +package android.gui; -parcelable InputWindowInfo cpp_header "input/InputWindow.h"; +parcelable WindowInfo cpp_header "gui/WindowInfo.h"; diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index 2a3f6a43d9..ad7bcb7d12 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -22,11 +22,12 @@ #include <android/gui/IScreenCaptureListener.h> #include <android/gui/ITransactionTraceListener.h> #include <android/gui/ITunnelModeEnabledListener.h> +#include <android/gui/IWindowInfosListener.h> #include <binder/IBinder.h> #include <binder/IInterface.h> +#include <ftl/Flags.h> #include <gui/FrameTimelineInfo.h> #include <gui/ITransactionCompletedListener.h> -#include <input/Flags.h> #include <math/vec4.h> #include <stdint.h> #include <sys/types.h> @@ -552,6 +553,11 @@ public: * in MIN_UNDEQUEUED_BUFFERS. */ virtual status_t getMaxAcquiredBufferCount(int* buffers) const = 0; + + virtual status_t addWindowInfosListener( + const sp<gui::IWindowInfosListener>& windowInfosListener) const = 0; + virtual status_t removeWindowInfosListener( + const sp<gui::IWindowInfosListener>& windowInfosListener) const = 0; }; // ---------------------------------------------------------------------------- @@ -624,6 +630,8 @@ public: ON_PULL_ATOM, ADD_TUNNEL_MODE_ENABLED_LISTENER, REMOVE_TUNNEL_MODE_ENABLED_LISTENER, + ADD_WINDOW_INFOS_LISTENER, + REMOVE_WINDOW_INFOS_LISTENER, // Always append new enum to the end. }; diff --git a/include/input/InputApplication.h b/libs/gui/include/gui/InputApplication.h index 8e4fe796a5..679c2a1754 100644 --- a/include/input/InputApplication.h +++ b/libs/gui/include/gui/InputApplication.h @@ -19,17 +19,17 @@ #include <string> -#include <android/InputApplicationInfo.h> +#include <android/gui/InputApplicationInfo.h> #include <binder/IBinder.h> #include <binder/Parcel.h> #include <binder/Parcelable.h> -#include <input/Input.h> #include <utils/RefBase.h> #include <utils/Timers.h> namespace android { + /* * Handle for an application that can receive input. * @@ -38,13 +38,9 @@ namespace android { */ class InputApplicationHandle { public: - inline const InputApplicationInfo* getInfo() const { - return &mInfo; - } + inline const gui::InputApplicationInfo* getInfo() const { return &mInfo; } - inline std::string getName() const { - return !mInfo.name.empty() ? mInfo.name : "<invalid>"; - } + inline std::string getName() const { return !mInfo.name.empty() ? mInfo.name : "<invalid>"; } inline std::chrono::nanoseconds getDispatchingTimeout( std::chrono::nanoseconds defaultValue) const { @@ -52,9 +48,7 @@ public: : defaultValue; } - inline sp<IBinder> getApplicationToken() const { - return mInfo.token; - } + inline sp<IBinder> getApplicationToken() const { return mInfo.token; } bool operator==(const InputApplicationHandle& other) const { return getName() == other.getName() && getApplicationToken() == other.getApplicationToken(); @@ -77,7 +71,7 @@ protected: InputApplicationHandle() = default; virtual ~InputApplicationHandle() = default; - InputApplicationInfo mInfo; + gui::InputApplicationInfo mInfo; }; } // namespace android diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index 3e57ff611e..8dc8b9a87b 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -26,14 +26,12 @@ #include <gui/ITransactionCompletedListener.h> #include <math/mat4.h> -#ifndef NO_INPUT -#include <android/FocusRequest.h> -#include <input/InputWindow.h> -#endif +#include <android/gui/FocusRequest.h> #include <gui/ISurfaceComposer.h> #include <gui/LayerMetadata.h> #include <gui/SurfaceControl.h> +#include <gui/WindowInfo.h> #include <math/vec3.h> #include <ui/BlurRegion.h> #include <ui/GraphicTypes.h> @@ -178,9 +176,7 @@ struct layer_state_t { mat4 colorTransform; std::vector<BlurRegion> blurRegions; -#ifndef NO_INPUT - sp<InputWindowHandle> inputHandle = new InputWindowHandle(); -#endif + sp<gui::WindowInfoHandle> windowInfoHandle = new gui::WindowInfoHandle(); client_cache_t cachedBuffer; @@ -246,6 +242,11 @@ struct layer_state_t { // is used to remove the old callback from the client process map if it is // overwritten by another setBuffer call. ReleaseCallbackId releaseCallbackId; + + // Stores which endpoint the release information should be sent to. We don't want to send the + // releaseCallbackId and release fence to all listeners so we store which listener the setBuffer + // was called with. + sp<IBinder> releaseBufferEndpoint; }; struct ComposerState { @@ -259,7 +260,8 @@ struct DisplayState { eSurfaceChanged = 0x01, eLayerStackChanged = 0x02, eDisplayProjectionChanged = 0x04, - eDisplaySizeChanged = 0x08 + eDisplaySizeChanged = 0x08, + eFlagsChanged = 0x10 }; DisplayState(); @@ -269,6 +271,7 @@ struct DisplayState { sp<IBinder> token; sp<IGraphicBufferProducer> surface; uint32_t layerStack; + uint32_t flags; // These states define how layers are projected onto the physical display. // @@ -292,9 +295,7 @@ struct DisplayState { }; struct InputWindowCommands { -#ifndef NO_INPUT - std::vector<FocusRequest> focusRequests; -#endif + std::vector<gui::FocusRequest> focusRequests; bool syncInputWindows{false}; // Merges the passed in commands and returns true if there were any changes. diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index baa0567617..0f8a32b7fa 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -42,6 +42,7 @@ #include <gui/ITransactionCompletedListener.h> #include <gui/LayerState.h> #include <gui/SurfaceControl.h> +#include <gui/WindowInfosListenerReporter.h> #include <math/vec3.h> namespace android { @@ -502,11 +503,9 @@ public: // Set the framenumber generated by the graphics producer to mimic BufferQueue behaviour. Transaction& setFrameNumber(const sp<SurfaceControl>& sc, uint64_t frameNumber); -#ifndef NO_INPUT - Transaction& setInputWindowInfo(const sp<SurfaceControl>& sc, const InputWindowInfo& info); - Transaction& setFocusedWindow(const FocusRequest& request); + Transaction& setInputWindowInfo(const sp<SurfaceControl>& sc, const gui::WindowInfo& info); + Transaction& setFocusedWindow(const gui::FocusRequest& request); Transaction& syncInputWindows(); -#endif // Set a color transform matrix on the given layer on the built-in display. Transaction& setColorTransform(const sp<SurfaceControl>& sc, const mat3& matrix, @@ -569,6 +568,8 @@ public: void setDisplayLayerStack(const sp<IBinder>& token, uint32_t layerStack); + void setDisplayFlags(const sp<IBinder>& token, uint32_t flags); + /* setDisplayProjection() defines the projection of layer stacks * to a given display. * @@ -622,6 +623,9 @@ public: static status_t removeTunnelModeEnabledListener( const sp<gui::ITunnelModeEnabledListener>& listener); + status_t addWindowInfosListener(const sp<gui::WindowInfosListener>& windowInfosListener); + status_t removeWindowInfosListener(const sp<gui::WindowInfosListener>& windowInfosListener); + private: virtual void onFirstRef(); @@ -651,8 +655,10 @@ public: }; class TransactionCompletedListener : public BnTransactionCompletedListener { +public: TransactionCompletedListener(); +protected: int64_t getNextIdLocked() REQUIRES(mMutex); std::mutex mMutex; @@ -682,13 +688,13 @@ class TransactionCompletedListener : public BnTransactionCompletedListener { std::unordered_map<CallbackId, CallbackTranslation, CallbackIdHash> mCallbacks GUARDED_BY(mMutex); - std::multimap<sp<IBinder>, sp<JankDataListener>> mJankListeners GUARDED_BY(mMutex); + std::multimap<int32_t, sp<JankDataListener>> mJankListeners GUARDED_BY(mMutex); std::unordered_map<ReleaseCallbackId, ReleaseBufferCallback, ReleaseBufferCallbackIdHash> mReleaseBufferCallbacks GUARDED_BY(mMutex); // This is protected by mSurfaceStatsListenerMutex, but GUARDED_BY isn't supported for // std::recursive_mutex - std::multimap<sp<IBinder>, SurfaceStatsCallbackEntry> mSurfaceStatsListeners; + std::multimap<int32_t, SurfaceStatsCallbackEntry> mSurfaceStatsListeners; public: static sp<TransactionCompletedListener> getInstance(); @@ -730,8 +736,12 @@ public: void onReleaseBuffer(ReleaseCallbackId, sp<Fence> releaseFence, uint32_t transformHint, uint32_t currentMaxAcquiredBufferCount) override; + // For Testing Only + static void setInstance(const sp<TransactionCompletedListener>&); + private: ReleaseBufferCallback popReleaseBufferCallbackLocked(const ReleaseCallbackId&); + static sp<TransactionCompletedListener> sInstance; }; } // namespace android diff --git a/include/input/InputWindow.h b/libs/gui/include/gui/WindowInfo.h index 121be6d963..f090c63228 100644 --- a/include/input/InputWindow.h +++ b/libs/gui/include/gui/WindowInfo.h @@ -14,15 +14,13 @@ * limitations under the License. */ -#ifndef _UI_INPUT_WINDOW_H -#define _UI_INPUT_WINDOW_H +#pragma once -#include <android/os/TouchOcclusionMode.h> +#include <android/gui/TouchOcclusionMode.h> #include <binder/Parcel.h> #include <binder/Parcelable.h> -#include <input/Flags.h> -#include <input/Input.h> -#include <input/InputTransport.h> +#include <ftl/Flags.h> +#include <gui/constants.h> #include <ui/Rect.h> #include <ui/Region.h> #include <ui/Transform.h> @@ -31,15 +29,13 @@ #include "InputApplication.h" -using android::os::TouchOcclusionMode; - -namespace android { +namespace android::gui { /* * Describes the properties of a window that can receive input. */ -struct InputWindowInfo : public Parcelable { - InputWindowInfo() = default; +struct WindowInfo : public Parcelable { + WindowInfo() = default; // Window flags from WindowManager.LayoutParams enum class Flag : uint32_t { @@ -136,6 +132,10 @@ struct InputWindowInfo : public Parcelable { // This value should NOT be used to uniquely identify the window. There may be different // input windows that have the same token. sp<IBinder> token; + + // The token that identifies which client window this WindowInfo was created for. + sp<IBinder> windowToken; + // This uniquely identifies the input window. int32_t id = -1; std::string name; @@ -168,9 +168,12 @@ struct InputWindowInfo : public Parcelable { // Transform applied to individual windows. ui::Transform transform; + // Display orientation as ui::Transform::RotationFlags. Used for compatibility raw coordinates. + uint32_t displayOrientation = ui::Transform::ROT_0; + // Display size in its natural rotation. Used to rotate raw coordinates for compatibility. - int32_t displayWidth = AMOTION_EVENT_INVALID_DISPLAY_SIZE; - int32_t displayHeight = AMOTION_EVENT_INVALID_DISPLAY_SIZE; + int32_t displayWidth = 0; + int32_t displayHeight = 0; /* * This is filled in by the WM relative to the frame and then translated @@ -206,9 +209,9 @@ struct InputWindowInfo : public Parcelable { bool supportsSplitTouch() const; - bool overlaps(const InputWindowInfo* other) const; + bool overlaps(const WindowInfo* other) const; - bool operator==(const InputWindowInfo& inputChannel) const; + bool operator==(const WindowInfo& inputChannel) const; status_t writeToParcel(android::Parcel* parcel) const override; @@ -221,13 +224,13 @@ struct InputWindowInfo : public Parcelable { * Used by the native input dispatcher to indirectly refer to the window manager objects * that describe a window. */ -class InputWindowHandle : public RefBase { +class WindowInfoHandle : public RefBase { public: - explicit InputWindowHandle(); - InputWindowHandle(const InputWindowHandle& other); - InputWindowHandle(const InputWindowInfo& other); + explicit WindowInfoHandle(); + WindowInfoHandle(const WindowInfoHandle& other); + WindowInfoHandle(const WindowInfo& other); - inline const InputWindowInfo* getInfo() const { return &mInfo; } + inline const WindowInfo* getInfo() const { return &mInfo; } sp<IBinder> getToken() const; @@ -243,21 +246,9 @@ public: } /** - * Requests that the state of this object be updated to reflect - * the most current available information about the application. - * As this class is created as RefBase object, no pure virtual function is allowed. - * - * This method should only be called from within the input dispatcher's - * critical section. - * - * Returns true on success, or false if the handle is no longer valid. - */ - virtual bool updateInfo() { return false; } - - /** * Updates from another input window handle. */ - void updateFrom(const sp<InputWindowHandle> handle); + void updateFrom(const sp<WindowInfoHandle> handle); /** * Releases the channel used by the associated information when it is @@ -270,10 +261,8 @@ public: status_t writeToParcel(android::Parcel* parcel) const; protected: - virtual ~InputWindowHandle(); + virtual ~WindowInfoHandle(); - InputWindowInfo mInfo; + WindowInfo mInfo; }; -} // namespace android - -#endif // _UI_INPUT_WINDOW_H +} // namespace android::gui
\ No newline at end of file diff --git a/libs/gui/include/gui/WindowInfosListener.h b/libs/gui/include/gui/WindowInfosListener.h new file mode 100644 index 0000000000..8a70b9bb57 --- /dev/null +++ b/libs/gui/include/gui/WindowInfosListener.h @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2021 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 <gui/WindowInfo.h> +#include <utils/RefBase.h> + +namespace android::gui { + +class WindowInfosListener : public virtual RefBase { +public: + virtual void onWindowInfosChanged(const std::vector<WindowInfo>& /*windowInfos*/) = 0; +}; +} // namespace android::gui
\ No newline at end of file diff --git a/libs/gui/include/gui/WindowInfosListenerReporter.h b/libs/gui/include/gui/WindowInfosListenerReporter.h new file mode 100644 index 0000000000..7cb96e0a30 --- /dev/null +++ b/libs/gui/include/gui/WindowInfosListenerReporter.h @@ -0,0 +1,48 @@ +/* + * Copyright 2021 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 <android/gui/BnWindowInfosListener.h> +#include <android/gui/IWindowInfosReportedListener.h> +#include <binder/IBinder.h> +#include <gui/ISurfaceComposer.h> +#include <gui/WindowInfosListener.h> +#include <utils/Mutex.h> +#include <unordered_set> + +namespace android { +class ISurfaceComposer; + +class WindowInfosListenerReporter : public gui::BnWindowInfosListener { +public: + static sp<WindowInfosListenerReporter> getInstance(); + binder::Status onWindowInfosChanged(const std::vector<gui::WindowInfo>& windowInfos, + const sp<gui::IWindowInfosReportedListener>&) override; + + status_t addWindowInfosListener(const sp<gui::WindowInfosListener>& windowInfosListener, + const sp<ISurfaceComposer>&); + status_t removeWindowInfosListener(const sp<gui::WindowInfosListener>& windowInfosListener, + const sp<ISurfaceComposer>&); + void reconnect(const sp<ISurfaceComposer>&); + +private: + std::mutex mListenersMutex; + std::unordered_set<sp<gui::WindowInfosListener>, + ISurfaceComposer::SpHash<gui::WindowInfosListener>> + mWindowInfosListeners GUARDED_BY(mListenersMutex); +}; +} // namespace android
\ No newline at end of file diff --git a/libs/gui/include/gui/constants.h b/libs/gui/include/gui/constants.h new file mode 100644 index 0000000000..8eab3783e9 --- /dev/null +++ b/libs/gui/include/gui/constants.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2021 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 <stdint.h> + +namespace android { + +/** + * Invalid value for display size. Used when display size isn't available. + */ +constexpr int32_t INVALID_DISPLAY_SIZE = 0; + +enum { + /* Used when an event is not associated with any display. + * Typically used for non-pointer events. */ + ADISPLAY_ID_NONE = -1, + + /* The default display id. */ + ADISPLAY_ID_DEFAULT = 0, +}; + +} // namespace android
\ No newline at end of file diff --git a/libs/gui/tests/Android.bp b/libs/gui/tests/Android.bp index c801c6243a..3d26c3d858 100644 --- a/libs/gui/tests/Android.bp +++ b/libs/gui/tests/Android.bp @@ -43,6 +43,7 @@ cc_test { "SurfaceTextureMultiContextGL_test.cpp", "Surface_test.cpp", "TextureRenderer.cpp", + "WindowInfo_test.cpp", ], shared_libs: [ diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp index 49c44a78d1..fc84c1b619 100644 --- a/libs/gui/tests/EndToEndNativeInputTest.cpp +++ b/libs/gui/tests/EndToEndNativeInputTest.cpp @@ -37,9 +37,9 @@ #include <gui/SurfaceControl.h> #include <android/os/IInputFlinger.h> +#include <gui/WindowInfo.h> #include <input/Input.h> #include <input/InputTransport.h> -#include <input/InputWindow.h> #include <ui/DisplayMode.h> #include <ui/Rect.h> @@ -49,6 +49,11 @@ using android::os::IInputFlinger; using android::hardware::graphics::common::V1_1::BufferUsage; +using android::gui::FocusRequest; +using android::gui::InputApplicationInfo; +using android::gui::TouchOcclusionMode; +using android::gui::WindowInfo; + namespace android::test { using Transaction = SurfaceComposerClient::Transaction; @@ -221,8 +226,8 @@ private: void populateInputInfo(int width, int height) { mInputInfo.token = mClientChannel->getConnectionToken(); mInputInfo.name = "Test info"; - mInputInfo.flags = InputWindowInfo::Flag::NOT_TOUCH_MODAL; - mInputInfo.type = InputWindowInfo::Type::BASE_APPLICATION; + mInputInfo.flags = WindowInfo::Flag::NOT_TOUCH_MODAL; + mInputInfo.type = WindowInfo::Type::BASE_APPLICATION; mInputInfo.dispatchingTimeout = 5s; mInputInfo.globalScaleFactor = 1.0; mInputInfo.focusable = true; @@ -249,7 +254,7 @@ public: std::shared_ptr<InputChannel> mClientChannel; sp<IInputFlinger> mInputFlinger; - InputWindowInfo mInputInfo; + WindowInfo mInputInfo; PreallocatedInputEventFactory mInputEventFactory; InputConsumer* mInputConsumer; @@ -686,7 +691,7 @@ TEST_F(InputSurfacesTest, touch_flag_obscured) { // Add non touchable window to fully cover touchable window. Window behind gets touch, but // with flag AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED std::unique_ptr<InputSurface> nonTouchableSurface = makeSurface(100, 100); - nonTouchableSurface->mInputInfo.flags = InputWindowInfo::Flag::NOT_TOUCHABLE; + nonTouchableSurface->mInputInfo.flags = WindowInfo::Flag::NOT_TOUCHABLE; nonTouchableSurface->mInputInfo.ownerUid = 22222; // Overriding occlusion mode otherwise the touch would be discarded at InputDispatcher by // the default obscured/untrusted touch filter introduced in S. @@ -706,8 +711,8 @@ TEST_F(InputSurfacesTest, touch_flag_partially_obscured_with_crop) { // AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED std::unique_ptr<InputSurface> parentSurface = makeSurface(100, 100); std::unique_ptr<InputSurface> nonTouchableSurface = makeSurface(100, 100); - nonTouchableSurface->mInputInfo.flags = InputWindowInfo::Flag::NOT_TOUCHABLE; - parentSurface->mInputInfo.flags = InputWindowInfo::Flag::NOT_TOUCHABLE; + nonTouchableSurface->mInputInfo.flags = WindowInfo::Flag::NOT_TOUCHABLE; + parentSurface->mInputInfo.flags = WindowInfo::Flag::NOT_TOUCHABLE; nonTouchableSurface->mInputInfo.ownerUid = 22222; parentSurface->mInputInfo.ownerUid = 22222; nonTouchableSurface->showAt(0, 0); @@ -730,8 +735,8 @@ TEST_F(InputSurfacesTest, touch_not_obscured_with_crop) { // the touchable window. Window behind gets touch with no obscured flags. std::unique_ptr<InputSurface> parentSurface = makeSurface(100, 100); std::unique_ptr<InputSurface> nonTouchableSurface = makeSurface(100, 100); - nonTouchableSurface->mInputInfo.flags = InputWindowInfo::Flag::NOT_TOUCHABLE; - parentSurface->mInputInfo.flags = InputWindowInfo::Flag::NOT_TOUCHABLE; + nonTouchableSurface->mInputInfo.flags = WindowInfo::Flag::NOT_TOUCHABLE; + parentSurface->mInputInfo.flags = WindowInfo::Flag::NOT_TOUCHABLE; nonTouchableSurface->mInputInfo.ownerUid = 22222; parentSurface->mInputInfo.ownerUid = 22222; nonTouchableSurface->showAt(0, 0); @@ -751,7 +756,7 @@ TEST_F(InputSurfacesTest, touch_not_obscured_with_zero_sized_bql) { std::unique_ptr<InputSurface> bufferSurface = InputSurface::makeBufferInputSurface(mComposerClient, 0, 0); - bufferSurface->mInputInfo.flags = InputWindowInfo::Flag::NOT_TOUCHABLE; + bufferSurface->mInputInfo.flags = WindowInfo::Flag::NOT_TOUCHABLE; bufferSurface->mInputInfo.ownerUid = 22222; surface->showAt(10, 10); @@ -766,7 +771,7 @@ TEST_F(InputSurfacesTest, touch_not_obscured_with_zero_sized_blast) { std::unique_ptr<BlastInputSurface> bufferSurface = BlastInputSurface::makeBlastInputSurface(mComposerClient, 0, 0); - bufferSurface->mInputInfo.flags = InputWindowInfo::Flag::NOT_TOUCHABLE; + bufferSurface->mInputInfo.flags = WindowInfo::Flag::NOT_TOUCHABLE; bufferSurface->mInputInfo.ownerUid = 22222; surface->showAt(10, 10); diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index 59b0c04bc3..a02970c9bc 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -904,6 +904,16 @@ public: status_t getMaxAcquiredBufferCount(int* /*buffers*/) const override { return NO_ERROR; } + status_t addWindowInfosListener( + const sp<gui::IWindowInfosListener>& /*windowInfosListener*/) const override { + return NO_ERROR; + } + + status_t removeWindowInfosListener( + const sp<gui::IWindowInfosListener>& /*windowInfosListener*/) const override { + return NO_ERROR; + } + protected: IBinder* onAsBinder() override { return nullptr; } diff --git a/libs/input/tests/InputWindow_test.cpp b/libs/gui/tests/WindowInfo_test.cpp index 493f2f4495..a4f436cdba 100644 --- a/libs/input/tests/InputWindow_test.cpp +++ b/libs/gui/tests/WindowInfo_test.cpp @@ -19,16 +19,20 @@ #include <binder/Binder.h> #include <binder/Parcel.h> -#include <input/InputWindow.h> -#include <input/InputTransport.h> +#include <gui/WindowInfo.h> using std::chrono_literals::operator""s; namespace android { + +using gui::InputApplicationInfo; +using gui::TouchOcclusionMode; +using gui::WindowInfo; + namespace test { -TEST(InputWindowInfo, ParcellingWithoutToken) { - InputWindowInfo i, i2; +TEST(WindowInfo, ParcellingWithoutToken) { + WindowInfo i, i2; i.token = nullptr; Parcel p; @@ -38,14 +42,15 @@ TEST(InputWindowInfo, ParcellingWithoutToken) { ASSERT_TRUE(i2.token == nullptr); } -TEST(InputWindowInfo, Parcelling) { +TEST(WindowInfo, Parcelling) { sp<IBinder> touchableRegionCropHandle = new BBinder(); - InputWindowInfo i; + WindowInfo i; i.token = new BBinder(); + i.windowToken = new BBinder(); i.id = 1; i.name = "Foobar"; - i.flags = InputWindowInfo::Flag::SLIPPERY; - i.type = InputWindowInfo::Type::INPUT_METHOD; + i.flags = WindowInfo::Flag::SLIPPERY; + i.type = WindowInfo::Type::INPUT_METHOD; i.dispatchingTimeout = 12s; i.frameLeft = 93; i.frameTop = 34; @@ -55,6 +60,7 @@ TEST(InputWindowInfo, Parcelling) { i.globalScaleFactor = 0.3; i.alpha = 0.7; i.transform.set({0.4, -1, 100, 0.5, 0, 40, 0, 0, 1}); + i.displayOrientation = ui::Transform::ROT_0; i.displayWidth = 1000; i.displayHeight = 2000; i.visible = false; @@ -65,7 +71,7 @@ TEST(InputWindowInfo, Parcelling) { i.ownerPid = 19; i.ownerUid = 24; i.packageName = "com.example.package"; - i.inputFeatures = InputWindowInfo::Feature::DISABLE_USER_ACTIVITY; + i.inputFeatures = WindowInfo::Feature::DISABLE_USER_ACTIVITY; i.displayId = 34; i.portalToDisplayId = 2; i.replaceTouchableRegionWithCrop = true; @@ -77,9 +83,10 @@ TEST(InputWindowInfo, Parcelling) { Parcel p; i.writeToParcel(&p); p.setDataPosition(0); - InputWindowInfo i2; + WindowInfo i2; i2.readFromParcel(&p); ASSERT_EQ(i.token, i2.token); + ASSERT_EQ(i.windowToken, i2.windowToken); ASSERT_EQ(i.id, i2.id); ASSERT_EQ(i.name, i2.name); ASSERT_EQ(i.flags, i2.flags); diff --git a/libs/input/Android.bp b/libs/input/Android.bp index a63ec8fb2a..e73c3b8518 100644 --- a/libs/input/Android.bp +++ b/libs/input/Android.bp @@ -30,7 +30,6 @@ filegroup { "android/os/IInputConstants.aidl", "android/os/InputEventInjectionResult.aidl", "android/os/InputEventInjectionSync.aidl", - "android/os/TouchOcclusionMode.aidl", ], } @@ -79,16 +78,11 @@ cc_library { android: { srcs: [ "InputTransport.cpp", - "InputWindow.cpp", - "android/FocusRequest.aidl", - "android/InputApplicationInfo.aidl", "android/os/BlockUntrustedTouchesMode.aidl", "android/os/IInputConstants.aidl", "android/os/IInputFlinger.aidl", "android/os/InputEventInjectionResult.aidl", "android/os/InputEventInjectionSync.aidl", - "android/os/ISetInputWindowsListener.aidl", - "android/os/TouchOcclusionMode.aidl", ], export_shared_lib_headers: ["libbinder"], @@ -99,6 +93,14 @@ cc_library { "libui", ], + static_libs: [ + "libgui_window_info_static", + ], + + export_static_lib_headers: [ + "libgui_window_info_static", + ], + sanitize: { misc_undefined: ["integer"], }, @@ -114,26 +116,29 @@ cc_library { linux_glibc: { srcs: [ "InputTransport.cpp", - "InputWindow.cpp", - "android/FocusRequest.aidl", - "android/InputApplicationInfo.aidl", "android/os/IInputConstants.aidl", "android/os/IInputFlinger.aidl", - "android/os/ISetInputWindowsListener.aidl", - "android/os/TouchOcclusionMode.aidl", ], static_libs: [ "libhostgraphics", + "libgui_window_info_static", ], shared_libs: [ "libbinder", ], + + export_static_lib_headers: [ + "libgui_window_info_static", + ], }, }, aidl: { local_include_dirs: ["."], export_aidl_headers: true, + include_dirs: [ + "frameworks/native/libs/gui", + ], }, } diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp index d954d23507..35209f7a07 100644 --- a/libs/input/Input.cpp +++ b/libs/input/Input.cpp @@ -25,6 +25,7 @@ #include <android-base/properties.h> #include <android-base/stringprintf.h> +#include <gui/constants.h> #include <input/Input.h> #include <input/InputDevice.h> #include <input/InputEventLabels.h> @@ -75,14 +76,11 @@ float transformAngle(const ui::Transform& transform, float angleRadians) { return result; } -// Rotates the given point to the transform's orientation. If the display width and height are +// Rotates the given point to the specified orientation. If the display width and height are // provided, the point is rotated in the screen space. Otherwise, the point is rotated about the // origin. This helper is used to avoid the extra overhead of creating new Transforms. -vec2 rotatePoint(const ui::Transform& transform, float x, float y, int32_t displayWidth = 0, +vec2 rotatePoint(uint32_t orientation, float x, float y, int32_t displayWidth = 0, int32_t displayHeight = 0) { - // 0x7 encapsulates all 3 rotations (see ui::Transform::RotationFlags) - static const int ALL_ROTATIONS_MASK = 0x7; - const uint32_t orientation = (transform.getOrientation() & ALL_ROTATIONS_MASK); if (orientation == ui::Transform::ROT_0) { return {x, y}; } @@ -101,6 +99,19 @@ vec2 rotatePoint(const ui::Transform& transform, float x, float y, int32_t displ return xy; } +vec2 applyTransformWithoutTranslation(const ui::Transform& transform, float x, float y) { + const vec2 transformedXy = transform.transform(x, y); + const vec2 transformedOrigin = transform.transform(0, 0); + return transformedXy - transformedOrigin; +} + +bool shouldDisregardWindowTranslation(uint32_t source) { + // Pointer events are the only type of events that refer to absolute coordinates on the display, + // so we should apply the entire window transform. For other types of events, we should make + // sure to not apply the window translation/offset. + return (source & AINPUT_SOURCE_CLASS_POINTER) == 0; +} + } // namespace const char* motionClassificationToString(MotionClassification classification) { @@ -315,6 +326,8 @@ void PointerCoords::scale(float globalScaleFactor, float windowXScale, float win scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOUCH_MINOR, globalScaleFactor); scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOOL_MAJOR, globalScaleFactor); scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOOL_MINOR, globalScaleFactor); + scaleAxisValue(*this, AMOTION_EVENT_AXIS_RELATIVE_X, windowXScale); + scaleAxisValue(*this, AMOTION_EVENT_AXIS_RELATIVE_Y, windowYScale); } void PointerCoords::scale(float globalScaleFactor) { @@ -383,6 +396,15 @@ void PointerCoords::transform(const ui::Transform& transform) { setAxisValue(AMOTION_EVENT_AXIS_X, xy.x); setAxisValue(AMOTION_EVENT_AXIS_Y, xy.y); + if (BitSet64::hasBit(bits, AMOTION_EVENT_AXIS_RELATIVE_X) || + BitSet64::hasBit(bits, AMOTION_EVENT_AXIS_RELATIVE_Y)) { + const ui::Transform rotation(transform.getOrientation()); + const vec2 relativeXy = rotation.transform(getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X), + getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y)); + setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, relativeXy.x); + setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, relativeXy.y); + } + if (BitSet64::hasBit(bits, AMOTION_EVENT_AXIS_ORIENTATION)) { const float val = getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION); setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, transformAngle(transform, val)); @@ -410,9 +432,9 @@ void MotionEvent::initialize(int32_t id, int32_t deviceId, uint32_t source, int3 int32_t buttonState, MotionClassification classification, const ui::Transform& transform, float xPrecision, float yPrecision, float rawXCursorPosition, float rawYCursorPosition, - int32_t displayWidth, int32_t displayHeight, nsecs_t downTime, - nsecs_t eventTime, size_t pointerCount, - const PointerProperties* pointerProperties, + uint32_t displayOrientation, int32_t displayWidth, + int32_t displayHeight, nsecs_t downTime, nsecs_t eventTime, + size_t pointerCount, const PointerProperties* pointerProperties, const PointerCoords* pointerCoords) { InputEvent::initialize(id, deviceId, source, displayId, hmac); mAction = action; @@ -427,6 +449,7 @@ void MotionEvent::initialize(int32_t id, int32_t deviceId, uint32_t source, int3 mYPrecision = yPrecision; mRawXCursorPosition = rawXCursorPosition; mRawYCursorPosition = rawYCursorPosition; + mDisplayOrientation = displayOrientation; mDisplayWidth = displayWidth; mDisplayHeight = displayHeight; mDownTime = downTime; @@ -452,6 +475,7 @@ void MotionEvent::copyFrom(const MotionEvent* other, bool keepHistory) { mYPrecision = other->mYPrecision; mRawXCursorPosition = other->mRawXCursorPosition; mRawYCursorPosition = other->mRawYCursorPosition; + mDisplayOrientation = other->mDisplayOrientation; mDisplayWidth = other->mDisplayWidth; mDisplayHeight = other->mDisplayHeight; mDownTime = other->mDownTime; @@ -521,25 +545,48 @@ float MotionEvent::getHistoricalRawAxisValue(int32_t axis, size_t pointerIndex, if (axis == AMOTION_EVENT_AXIS_X || axis == AMOTION_EVENT_AXIS_Y) { // For compatibility, convert raw coordinates into "oriented screen space". Once app // developers are educated about getRaw, we can consider removing this. - const vec2 xy = rotatePoint(mTransform, coords->getX(), coords->getY(), mDisplayWidth, - mDisplayHeight); + const vec2 xy = shouldDisregardWindowTranslation(mSource) + ? rotatePoint(mDisplayOrientation, coords->getX(), coords->getY()) + : rotatePoint(mDisplayOrientation, coords->getX(), coords->getY(), mDisplayWidth, + mDisplayHeight); static_assert(AMOTION_EVENT_AXIS_X == 0 && AMOTION_EVENT_AXIS_Y == 1); return xy[axis]; } + if (axis == AMOTION_EVENT_AXIS_RELATIVE_X || axis == AMOTION_EVENT_AXIS_RELATIVE_Y) { + // For compatibility, since we convert raw coordinates into "oriented screen space", we + // need to convert the relative axes into the same orientation for consistency. + const vec2 relativeXy = rotatePoint(mDisplayOrientation, + coords->getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X), + coords->getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y)); + return axis == AMOTION_EVENT_AXIS_RELATIVE_X ? relativeXy.x : relativeXy.y; + } + return coords->getAxisValue(axis); } float MotionEvent::getHistoricalAxisValue(int32_t axis, size_t pointerIndex, - size_t historicalIndex) const { + size_t historicalIndex) const { const PointerCoords* coords = getHistoricalRawPointerCoords(pointerIndex, historicalIndex); if (axis == AMOTION_EVENT_AXIS_X || axis == AMOTION_EVENT_AXIS_Y) { - const vec2 xy = mTransform.transform(coords->getXYValue()); + const vec2 xy = shouldDisregardWindowTranslation(mSource) + ? applyTransformWithoutTranslation(mTransform, coords->getX(), coords->getY()) + : mTransform.transform(coords->getXYValue()); static_assert(AMOTION_EVENT_AXIS_X == 0 && AMOTION_EVENT_AXIS_Y == 1); return xy[axis]; } + if (axis == AMOTION_EVENT_AXIS_RELATIVE_X || axis == AMOTION_EVENT_AXIS_RELATIVE_Y) { + const vec2 relativeXy = + applyTransformWithoutTranslation(mTransform, + coords->getAxisValue( + AMOTION_EVENT_AXIS_RELATIVE_X), + coords->getAxisValue( + AMOTION_EVENT_AXIS_RELATIVE_Y)); + return axis == AMOTION_EVENT_AXIS_RELATIVE_X ? relativeXy.x : relativeXy.y; + } + return coords->getAxisValue(axis); } @@ -595,6 +642,13 @@ void MotionEvent::applyTransform(const std::array<float, 9>& matrix) { // Apply the transformation to all samples. std::for_each(mSamplePointerCoords.begin(), mSamplePointerCoords.end(), [&transform](PointerCoords& c) { c.transform(transform); }); + + if (mRawXCursorPosition != AMOTION_EVENT_INVALID_CURSOR_POSITION && + mRawYCursorPosition != AMOTION_EVENT_INVALID_CURSOR_POSITION) { + const vec2 cursor = transform.transform(mRawXCursorPosition, mRawYCursorPosition); + mRawXCursorPosition = cursor.x; + mRawYCursorPosition = cursor.y; + } } #ifdef __linux__ @@ -655,6 +709,7 @@ status_t MotionEvent::readFromParcel(Parcel* parcel) { mYPrecision = parcel->readFloat(); mRawXCursorPosition = parcel->readFloat(); mRawYCursorPosition = parcel->readFloat(); + mDisplayOrientation = parcel->readUint32(); mDisplayWidth = parcel->readInt32(); mDisplayHeight = parcel->readInt32(); mDownTime = parcel->readInt64(); @@ -716,6 +771,7 @@ status_t MotionEvent::writeToParcel(Parcel* parcel) const { parcel->writeFloat(mYPrecision); parcel->writeFloat(mRawXCursorPosition); parcel->writeFloat(mRawYCursorPosition); + parcel->writeUint32(mDisplayOrientation); parcel->writeInt32(mDisplayWidth); parcel->writeInt32(mDisplayHeight); parcel->writeInt64(mDownTime); diff --git a/libs/input/InputDevice.cpp b/libs/input/InputDevice.cpp index 30c42a3daa..220c8e1e6e 100644 --- a/libs/input/InputDevice.cpp +++ b/libs/input/InputDevice.cpp @@ -21,9 +21,9 @@ #include <ctype.h> #include <android-base/stringprintf.h> +#include <ftl/NamedEnum.h> #include <input/InputDevice.h> #include <input/InputEventLabels.h> -#include <input/NamedEnum.h> using android::base::StringPrintf; diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp index dd1c46265c..ea8b9a7ec8 100644 --- a/libs/input/InputTransport.cpp +++ b/libs/input/InputTransport.cpp @@ -33,8 +33,8 @@ static constexpr bool DEBUG_TRANSPORT_ACTIONS = false; #include <log/log.h> #include <utils/Trace.h> +#include <ftl/NamedEnum.h> #include <input/InputTransport.h> -#include <input/NamedEnum.h> using android::base::StringPrintf; @@ -242,9 +242,11 @@ void InputMessage::getSanitizedCopy(InputMessage* msg) const { msg->body.motion.xCursorPosition = body.motion.xCursorPosition; // float yCursorPosition msg->body.motion.yCursorPosition = body.motion.yCursorPosition; - // int32_t displayW + // uint32_t displayOrientation + msg->body.motion.displayOrientation = body.motion.displayOrientation; + // int32_t displayWidth msg->body.motion.displayWidth = body.motion.displayWidth; - // int32_t displayH + // int32_t displayHeight msg->body.motion.displayHeight = body.motion.displayHeight; // uint32_t pointerCount msg->body.motion.pointerCount = body.motion.pointerCount; @@ -533,9 +535,10 @@ status_t InputPublisher::publishMotionEvent( std::array<uint8_t, 32> hmac, int32_t action, int32_t actionButton, int32_t flags, int32_t edgeFlags, int32_t metaState, int32_t buttonState, MotionClassification classification, const ui::Transform& transform, float xPrecision, - float yPrecision, float xCursorPosition, float yCursorPosition, int32_t displayWidth, - int32_t displayHeight, nsecs_t downTime, nsecs_t eventTime, uint32_t pointerCount, - const PointerProperties* pointerProperties, const PointerCoords* pointerCoords) { + float yPrecision, float xCursorPosition, float yCursorPosition, uint32_t displayOrientation, + int32_t displayWidth, int32_t displayHeight, nsecs_t downTime, nsecs_t eventTime, + uint32_t pointerCount, const PointerProperties* pointerProperties, + const PointerCoords* pointerCoords) { if (ATRACE_ENABLED()) { std::string message = StringPrintf( "publishMotionEvent(inputChannel=%s, action=%" PRId32 ")", @@ -593,6 +596,7 @@ status_t InputPublisher::publishMotionEvent( msg.body.motion.yPrecision = yPrecision; msg.body.motion.xCursorPosition = xCursorPosition; msg.body.motion.yCursorPosition = yCursorPosition; + msg.body.motion.displayOrientation = displayOrientation; msg.body.motion.displayWidth = displayWidth; msg.body.motion.displayHeight = displayHeight; msg.body.motion.downTime = downTime; @@ -1361,9 +1365,9 @@ void InputConsumer::initializeMotionEvent(MotionEvent* event, const InputMessage msg->body.motion.buttonState, msg->body.motion.classification, transform, msg->body.motion.xPrecision, msg->body.motion.yPrecision, msg->body.motion.xCursorPosition, msg->body.motion.yCursorPosition, - msg->body.motion.displayWidth, msg->body.motion.displayHeight, - msg->body.motion.downTime, msg->body.motion.eventTime, pointerCount, - pointerProperties, pointerCoords); + msg->body.motion.displayOrientation, msg->body.motion.displayWidth, + msg->body.motion.displayHeight, msg->body.motion.downTime, + msg->body.motion.eventTime, pointerCount, pointerProperties, pointerCoords); } void InputConsumer::addSample(MotionEvent* event, const InputMessage* msg) { diff --git a/libs/input/KeyCharacterMap.cpp b/libs/input/KeyCharacterMap.cpp index 44f3f34994..3baeb55009 100644 --- a/libs/input/KeyCharacterMap.cpp +++ b/libs/input/KeyCharacterMap.cpp @@ -28,10 +28,11 @@ #include <input/KeyCharacterMap.h> #include <input/Keyboard.h> -#include <utils/Log.h> +#include <gui/constants.h> #include <utils/Errors.h> -#include <utils/Tokenizer.h> +#include <utils/Log.h> #include <utils/Timers.h> +#include <utils/Tokenizer.h> // Enables debug output for the parser. #define DEBUG_PARSER 0 diff --git a/libs/input/KeyLayoutMap.cpp b/libs/input/KeyLayoutMap.cpp index fa5a5412e6..c365ab070e 100644 --- a/libs/input/KeyLayoutMap.cpp +++ b/libs/input/KeyLayoutMap.cpp @@ -19,10 +19,10 @@ #include <stdlib.h> #include <android/keycodes.h> +#include <ftl/NamedEnum.h> #include <input/InputEventLabels.h> #include <input/KeyLayoutMap.h> #include <input/Keyboard.h> -#include <input/NamedEnum.h> #include <utils/Errors.h> #include <utils/Log.h> #include <utils/Timers.h> diff --git a/libs/input/android/os/IInputFlinger.aidl b/libs/input/android/os/IInputFlinger.aidl index 1771d192af..00ebd4d34f 100644 --- a/libs/input/android/os/IInputFlinger.aidl +++ b/libs/input/android/os/IInputFlinger.aidl @@ -16,20 +16,13 @@ package android.os; -import android.FocusRequest; import android.InputChannel; -import android.InputWindowInfo; -import android.os.ISetInputWindowsListener; +import android.gui.FocusRequest; +import android.gui.WindowInfo; /** @hide */ interface IInputFlinger { - // SurfaceFlinger is the caller of this method, it uses the listener callback to ensure the - // ordering when needed. - // SurfaceFlinger calls this only every VSync, so overflow of binder's oneway buffer - // shouldn't be a concern. - oneway void setInputWindows(in InputWindowInfo[] inputHandles, - in @nullable ISetInputWindowsListener setInputWindowsListener); InputChannel createInputChannel(in @utf8InCpp String name); void removeInputChannel(in IBinder connectionToken); /** diff --git a/libs/input/tests/Android.bp b/libs/input/tests/Android.bp index 6ffc6a8926..18ab1cb522 100644 --- a/libs/input/tests/Android.bp +++ b/libs/input/tests/Android.bp @@ -11,26 +11,24 @@ package { cc_test { name: "libinput_tests", srcs: [ - "NamedEnum_test.cpp", - "Flags_test.cpp", "IdGenerator_test.cpp", "InputChannel_test.cpp", "InputDevice_test.cpp", "InputEvent_test.cpp", "InputPublisherAndConsumer_test.cpp", - "InputWindow_test.cpp", "TouchVideoFrame_test.cpp", "VelocityTracker_test.cpp", "VerifiedInputEvent_test.cpp", ], + static_libs: [ + "libgui_window_info_static", + "libinput", + ], cflags: [ "-Wall", "-Wextra", "-Werror", ], - static_libs: [ - "libinput", - ], shared_libs: [ "libbase", "libbinder", diff --git a/libs/input/tests/InputEvent_test.cpp b/libs/input/tests/InputEvent_test.cpp index 3b76ddbb7c..b1ef7534e4 100644 --- a/libs/input/tests/InputEvent_test.cpp +++ b/libs/input/tests/InputEvent_test.cpp @@ -21,6 +21,7 @@ #include <attestation/HmacKeyManager.h> #include <binder/Parcel.h> #include <gtest/gtest.h> +#include <gui/constants.h> #include <input/Input.h> namespace android { @@ -293,7 +294,7 @@ void MotionEventTest::initializeEventWithHistory(MotionEvent* event) { AMOTION_EVENT_EDGE_FLAG_TOP, AMETA_ALT_ON, AMOTION_EVENT_BUTTON_PRIMARY, MotionClassification::NONE, mTransform, 2.0f, 2.1f, AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, - AMOTION_EVENT_INVALID_DISPLAY_SIZE, AMOTION_EVENT_INVALID_DISPLAY_SIZE, + ui::Transform::ROT_0, INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, ARBITRARY_DOWN_TIME, ARBITRARY_EVENT_TIME, 2, pointerProperties, pointerCoords); @@ -610,12 +611,12 @@ TEST_F(MotionEventTest, Transform) { } MotionEvent event; ui::Transform identityTransform; - event.initialize(InputEvent::nextId(), 0 /*deviceId*/, AINPUT_SOURCE_UNKNOWN, DISPLAY_ID, + event.initialize(InputEvent::nextId(), 0 /*deviceId*/, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID, INVALID_HMAC, AMOTION_EVENT_ACTION_MOVE, 0 /*actionButton*/, 0 /*flags*/, AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0 /*buttonState*/, MotionClassification::NONE, identityTransform, 0 /*xPrecision*/, 0 /*yPrecision*/, 3 + RADIUS /*xCursorPosition*/, 2 /*yCursorPosition*/, - AMOTION_EVENT_INVALID_DISPLAY_SIZE, AMOTION_EVENT_INVALID_DISPLAY_SIZE, + ui::Transform::ROT_0, INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, 0 /*downTime*/, 0 /*eventTime*/, pointerCount, pointerProperties, pointerCoords); float originalRawX = 0 + 3; @@ -658,13 +659,17 @@ TEST_F(MotionEventTest, Transform) { ASSERT_NEAR(originalRawY, event.getRawY(0), 0.001); } -MotionEvent createTouchDownEvent(int x, int y, ui::Transform transform) { +MotionEvent createTouchDownEvent(float x, float y, float dx, float dy, + const ui::Transform& transform, + uint32_t displayOrientation = ui::Transform::ROT_0) { std::vector<PointerProperties> pointerProperties; pointerProperties.push_back(PointerProperties{/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER}); std::vector<PointerCoords> pointerCoords; pointerCoords.emplace_back().clear(); pointerCoords.back().setAxisValue(AMOTION_EVENT_AXIS_X, x); pointerCoords.back().setAxisValue(AMOTION_EVENT_AXIS_Y, y); + pointerCoords.back().setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, dx); + pointerCoords.back().setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, dy); nsecs_t eventTime = systemTime(SYSTEM_TIME_MONOTONIC); MotionEvent event; event.initialize(InputEvent::nextId(), /* deviceId */ 1, AINPUT_SOURCE_TOUCHSCREEN, @@ -672,7 +677,8 @@ MotionEvent createTouchDownEvent(int x, int y, ui::Transform transform) { /* actionButton */ 0, /* flags */ 0, /* edgeFlags */ 0, AMETA_NONE, /* buttonState */ 0, MotionClassification::NONE, transform, /* xPrecision */ 0, /* yPrecision */ 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, - AMOTION_EVENT_INVALID_CURSOR_POSITION, /* displayWidth */ 400, + AMOTION_EVENT_INVALID_CURSOR_POSITION, displayOrientation, + /* displayWidth */ 400, /* displayHeight */ 800, eventTime, eventTime, pointerCoords.size(), pointerProperties.data(), pointerCoords.data()); return event; @@ -683,26 +689,56 @@ TEST_F(MotionEventTest, ApplyTransform) { ui::Transform identity; ui::Transform xform(ui::Transform::ROT_90, 800, 400); xform.set(xform.tx() + 20, xform.ty() + 40); - MotionEvent event = createTouchDownEvent(60, 100, xform); + MotionEvent event = createTouchDownEvent(60, 100, 42, 96, xform, ui::Transform::ROT_90); ASSERT_EQ(700, event.getRawX(0)); ASSERT_EQ(60, event.getRawY(0)); ASSERT_NE(event.getRawX(0), event.getX(0)); ASSERT_NE(event.getRawY(0), event.getY(0)); + // Relative values should be rotated but not translated. + ASSERT_EQ(-96, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0)); + ASSERT_EQ(42, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0)); - MotionEvent changedEvent = createTouchDownEvent(60, 100, identity); + MotionEvent changedEvent = createTouchDownEvent(60, 100, 42, 96, identity); const std::array<float, 9> rowMajor{xform[0][0], xform[1][0], xform[2][0], xform[0][1], xform[1][1], xform[2][1], xform[0][2], xform[1][2], xform[2][2]}; changedEvent.applyTransform(rowMajor); // transformContent effectively rotates the raw coordinates, so those should now include - // both rotation AND offset + // both rotation AND offset. ASSERT_EQ(720, changedEvent.getRawX(0)); ASSERT_EQ(100, changedEvent.getRawY(0)); + // Relative values should be rotated but not translated. + ASSERT_EQ(-96, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0)); + ASSERT_EQ(42, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0)); - // The transformed output should be the same then + // The transformed output should be the same then. ASSERT_NEAR(event.getX(0), changedEvent.getX(0), 0.001); ASSERT_NEAR(event.getY(0), changedEvent.getY(0), 0.001); + ASSERT_NEAR(event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0), + changedEvent.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0), 0.001); + ASSERT_NEAR(event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0), + changedEvent.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0), 0.001); +} + +TEST_F(MotionEventTest, NonPointerSourcesAreNotTranslated) { + constexpr static auto NON_POINTER_SOURCES = {AINPUT_SOURCE_TRACKBALL, + AINPUT_SOURCE_MOUSE_RELATIVE, + AINPUT_SOURCE_JOYSTICK}; + for (uint32_t source : NON_POINTER_SOURCES) { + // Create a rotate-90 transform with an offset (like a window which isn't fullscreen). + ui::Transform xform(ui::Transform::ROT_90, 800, 400); + xform.set(xform.tx() + 20, xform.ty() + 40); + MotionEvent event = createTouchDownEvent(60, 100, 42, 96, xform, ui::Transform::ROT_90); + event.setSource(source); + + // Since this event comes from a non-pointer source, it should include rotation but not + // translation/offset. + ASSERT_EQ(-100, event.getX(0)); + ASSERT_EQ(60, event.getY(0)); + ASSERT_EQ(event.getRawX(0), event.getX(0)); + ASSERT_EQ(event.getRawY(0), event.getY(0)); + } } TEST_F(MotionEventTest, RawCompatTransform) { @@ -710,11 +746,14 @@ TEST_F(MotionEventTest, RawCompatTransform) { // Make sure raw is raw regardless of transform translation. ui::Transform xform; xform.set(20, 40); - MotionEvent event = createTouchDownEvent(60, 100, xform); + MotionEvent event = createTouchDownEvent(60, 100, 42, 96, xform); ASSERT_EQ(60, event.getRawX(0)); ASSERT_EQ(100, event.getRawY(0)); ASSERT_NE(event.getRawX(0), event.getX(0)); ASSERT_NE(event.getRawY(0), event.getY(0)); + // Relative values should not be modified. + ASSERT_EQ(42, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0)); + ASSERT_EQ(96, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0)); } // Next check that getRaw contains rotation (for compatibility) but otherwise is still @@ -723,29 +762,50 @@ TEST_F(MotionEventTest, RawCompatTransform) { // Create a rotate-90 transform with an offset (like a window which isn't fullscreen). ui::Transform xform(ui::Transform::ROT_90, 800, 400); xform.set(xform.tx() + 20, xform.ty() + 40); - MotionEvent event = createTouchDownEvent(60, 100, xform); + MotionEvent event = createTouchDownEvent(60, 100, 42, 96, xform, ui::Transform::ROT_90); ASSERT_EQ(700, event.getRawX(0)); ASSERT_EQ(60, event.getRawY(0)); ASSERT_NE(event.getRawX(0), event.getX(0)); ASSERT_NE(event.getRawY(0), event.getY(0)); + // Relative values should be rotated but not translated. + ASSERT_EQ(-96, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0)); + ASSERT_EQ(42, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0)); } { // Same as above, but check rotate-180. ui::Transform xform(ui::Transform::ROT_180, 400, 800); xform.set(xform.tx() + 20, xform.ty() + 40); - MotionEvent event = createTouchDownEvent(60, 100, xform); + MotionEvent event = createTouchDownEvent(60, 100, 42, 96, xform, ui::Transform::ROT_180); ASSERT_EQ(340, event.getRawX(0)); ASSERT_EQ(700, event.getRawY(0)); + // Relative values should be rotated but not translated. + ASSERT_EQ(-42, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0)); + ASSERT_EQ(-96, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0)); } { // Same as above, but check rotate-270. ui::Transform xform(ui::Transform::ROT_270, 800, 400); xform.set(xform.tx() + 20, xform.ty() + 40); - MotionEvent event = createTouchDownEvent(60, 100, xform); + MotionEvent event = createTouchDownEvent(60, 100, 42, 96, xform, ui::Transform::ROT_270); ASSERT_EQ(100, event.getRawX(0)); ASSERT_EQ(340, event.getRawY(0)); + // Relative values should be rotated but not translated. + ASSERT_EQ(96, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0)); + ASSERT_EQ(-42, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0)); + } + + { + // Finally, check that raw isn't effected by transform + ui::Transform xform(ui::Transform::ROT_270, 800, 400); + xform.set(xform.tx() + 20, xform.ty() + 40); + MotionEvent event = createTouchDownEvent(60, 100, 42, 96, xform, ui::Transform::ROT_90); + ASSERT_EQ(700, event.getRawX(0)); + ASSERT_EQ(60, event.getRawY(0)); + // Relative values should be rotated but not translated. + ASSERT_EQ(96, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0)); + ASSERT_EQ(-42, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0)); } } @@ -772,9 +832,9 @@ TEST_F(MotionEventTest, Initialize_SetsClassification) { DISPLAY_ID, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0, 0, AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0, classification, identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, - AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_DISPLAY_SIZE, - AMOTION_EVENT_INVALID_DISPLAY_SIZE, 0 /*downTime*/, 0 /*eventTime*/, - pointerCount, pointerProperties, pointerCoords); + AMOTION_EVENT_INVALID_CURSOR_POSITION, ui::Transform::ROT_0, + INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, 0 /*downTime*/, + 0 /*eventTime*/, pointerCount, pointerProperties, pointerCoords); ASSERT_EQ(classification, event.getClassification()); } } @@ -794,10 +854,9 @@ TEST_F(MotionEventTest, Initialize_SetsCursorPosition) { event.initialize(InputEvent::nextId(), 0 /*deviceId*/, AINPUT_SOURCE_MOUSE, DISPLAY_ID, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0, 0, AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0, MotionClassification::NONE, identityTransform, 0, 0, - 280 /*xCursorPosition*/, 540 /*yCursorPosition*/, - AMOTION_EVENT_INVALID_DISPLAY_SIZE, AMOTION_EVENT_INVALID_DISPLAY_SIZE, - 0 /*downTime*/, 0 /*eventTime*/, pointerCount, pointerProperties, - pointerCoords); + 280 /*xCursorPosition*/, 540 /*yCursorPosition*/, ui::Transform::ROT_0, + INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, 0 /*downTime*/, 0 /*eventTime*/, + pointerCount, pointerProperties, pointerCoords); event.offsetLocation(20, 60); ASSERT_EQ(280, event.getRawXCursorPosition()); ASSERT_EQ(540, event.getRawYCursorPosition()); diff --git a/libs/input/tests/InputPublisherAndConsumer_test.cpp b/libs/input/tests/InputPublisherAndConsumer_test.cpp index a2cfaa1cc0..5d1f2c3bfc 100644 --- a/libs/input/tests/InputPublisherAndConsumer_test.cpp +++ b/libs/input/tests/InputPublisherAndConsumer_test.cpp @@ -23,6 +23,7 @@ #include <attestation/HmacKeyManager.h> #include <cutils/ashmem.h> #include <gtest/gtest.h> +#include <gui/constants.h> #include <input/InputTransport.h> #include <utils/StopWatch.h> #include <utils/Timers.h> @@ -162,6 +163,7 @@ void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent() { constexpr float yPrecision = 0.5; constexpr float xCursorPosition = 1.3; constexpr float yCursorPosition = 50.6; + constexpr uint32_t displayOrientation = ui::Transform::ROT_0; constexpr int32_t displayWidth = 1000; constexpr int32_t displayHeight = 2000; constexpr nsecs_t downTime = 3; @@ -192,9 +194,9 @@ void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent() { status = mPublisher->publishMotionEvent(seq, eventId, deviceId, source, displayId, hmac, action, actionButton, flags, edgeFlags, metaState, buttonState, classification, transform, xPrecision, yPrecision, - xCursorPosition, yCursorPosition, displayWidth, - displayHeight, downTime, eventTime, pointerCount, - pointerProperties, pointerCoords); + xCursorPosition, yCursorPosition, displayOrientation, + displayWidth, displayHeight, downTime, eventTime, + pointerCount, pointerProperties, pointerCoords); ASSERT_EQ(OK, status) << "publisher publishMotionEvent should return OK"; @@ -231,6 +233,7 @@ void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent() { EXPECT_EQ(yCursorPosition, motionEvent->getRawYCursorPosition()); EXPECT_EQ(xCursorPosition * xScale + xOffset, motionEvent->getXCursorPosition()); EXPECT_EQ(yCursorPosition * yScale + yOffset, motionEvent->getYCursorPosition()); + EXPECT_EQ(displayOrientation, motionEvent->getDisplayOrientation()); EXPECT_EQ(displayWidth, motionEvent->getDisplaySize().x); EXPECT_EQ(displayHeight, motionEvent->getDisplaySize().y); EXPECT_EQ(downTime, motionEvent->getDownTime()); @@ -460,8 +463,9 @@ TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenSequenceNumberIsZer status = mPublisher->publishMotionEvent(0, InputEvent::nextId(), 0, 0, 0, INVALID_HMAC, 0, 0, 0, 0, 0, 0, MotionClassification::NONE, identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, - AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, 0, 0, 0, - pointerCount, pointerProperties, pointerCoords); + AMOTION_EVENT_INVALID_CURSOR_POSITION, + ui::Transform::ROT_0, 0, 0, 0, 0, pointerCount, + pointerProperties, pointerCoords); ASSERT_EQ(BAD_VALUE, status) << "publisher publishMotionEvent should return BAD_VALUE"; } @@ -476,8 +480,9 @@ TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenPointerCountLessTha status = mPublisher->publishMotionEvent(1, InputEvent::nextId(), 0, 0, 0, INVALID_HMAC, 0, 0, 0, 0, 0, 0, MotionClassification::NONE, identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, - AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, 0, 0, 0, - pointerCount, pointerProperties, pointerCoords); + AMOTION_EVENT_INVALID_CURSOR_POSITION, + ui::Transform::ROT_0, 0, 0, 0, 0, pointerCount, + pointerProperties, pointerCoords); ASSERT_EQ(BAD_VALUE, status) << "publisher publishMotionEvent should return BAD_VALUE"; } @@ -497,8 +502,9 @@ TEST_F(InputPublisherAndConsumerTest, status = mPublisher->publishMotionEvent(1, InputEvent::nextId(), 0, 0, 0, INVALID_HMAC, 0, 0, 0, 0, 0, 0, MotionClassification::NONE, identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, - AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, 0, 0, 0, - pointerCount, pointerProperties, pointerCoords); + AMOTION_EVENT_INVALID_CURSOR_POSITION, + ui::Transform::ROT_0, 0, 0, 0, 0, pointerCount, + pointerProperties, pointerCoords); ASSERT_EQ(BAD_VALUE, status) << "publisher publishMotionEvent should return BAD_VALUE"; } diff --git a/libs/input/tests/StructLayout_test.cpp b/libs/input/tests/StructLayout_test.cpp index 5861d55156..59fed1fb41 100644 --- a/libs/input/tests/StructLayout_test.cpp +++ b/libs/input/tests/StructLayout_test.cpp @@ -74,10 +74,10 @@ void TestInputMessageAlignment() { CHECK_OFFSET(InputMessage::Body::Motion, yPrecision, 124); CHECK_OFFSET(InputMessage::Body::Motion, xCursorPosition, 128); CHECK_OFFSET(InputMessage::Body::Motion, yCursorPosition, 132); - CHECK_OFFSET(InputMessage::Body::Motion, displayWidth, 136); - CHECK_OFFSET(InputMessage::Body::Motion, displayHeight, 140); - CHECK_OFFSET(InputMessage::Body::Motion, pointerCount, 144); - CHECK_OFFSET(InputMessage::Body::Motion, empty3, 148); + CHECK_OFFSET(InputMessage::Body::Motion, displayOrientation, 136); + CHECK_OFFSET(InputMessage::Body::Motion, displayWidth, 140); + CHECK_OFFSET(InputMessage::Body::Motion, displayHeight, 144); + CHECK_OFFSET(InputMessage::Body::Motion, pointerCount, 148); CHECK_OFFSET(InputMessage::Body::Motion, pointers, 152); CHECK_OFFSET(InputMessage::Body::Focus, eventId, 0); diff --git a/libs/input/tests/VelocityTracker_test.cpp b/libs/input/tests/VelocityTracker_test.cpp index aefc2ec47d..13e2b02ca4 100644 --- a/libs/input/tests/VelocityTracker_test.cpp +++ b/libs/input/tests/VelocityTracker_test.cpp @@ -23,6 +23,7 @@ #include <android-base/stringprintf.h> #include <attestation/HmacKeyManager.h> #include <gtest/gtest.h> +#include <gui/constants.h> #include <input/VelocityTracker.h> using namespace std::chrono_literals; @@ -183,8 +184,8 @@ static std::vector<MotionEvent> createMotionEventStream( AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0 /*buttonState*/, MotionClassification::NONE, identityTransform, 0 /*xPrecision*/, 0 /*yPrecision*/, AMOTION_EVENT_INVALID_CURSOR_POSITION, - AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_DISPLAY_SIZE, - AMOTION_EVENT_INVALID_DISPLAY_SIZE, 0 /*downTime*/, + AMOTION_EVENT_INVALID_CURSOR_POSITION, ui::Transform::ROT_0, + INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, 0 /*downTime*/, entry.eventTime.count(), pointerCount, properties, coords); events.emplace_back(event); diff --git a/libs/input/tests/VerifiedInputEvent_test.cpp b/libs/input/tests/VerifiedInputEvent_test.cpp index f79098c63c..b29c9a4877 100644 --- a/libs/input/tests/VerifiedInputEvent_test.cpp +++ b/libs/input/tests/VerifiedInputEvent_test.cpp @@ -16,6 +16,7 @@ #include <attestation/HmacKeyManager.h> #include <gtest/gtest.h> +#include <gui/constants.h> #include <input/Input.h> namespace android { @@ -46,10 +47,9 @@ static MotionEvent getMotionEventWithFlags(int32_t flags) { INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0 /*actionButton*/, flags, AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0 /*buttonState*/, MotionClassification::NONE, transform, 0.1 /*xPrecision*/, 0.2 /*yPrecision*/, - 280 /*xCursorPosition*/, 540 /*yCursorPosition*/, - AMOTION_EVENT_INVALID_DISPLAY_SIZE, AMOTION_EVENT_INVALID_DISPLAY_SIZE, - 100 /*downTime*/, 200 /*eventTime*/, pointerCount, pointerProperties, - pointerCoords); + 280 /*xCursorPosition*/, 540 /*yCursorPosition*/, ui::Transform::ROT_0, + INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, 100 /*downTime*/, + 200 /*eventTime*/, pointerCount, pointerProperties, pointerCoords); return event; } diff --git a/libs/nativedisplay/AChoreographer.cpp b/libs/nativedisplay/AChoreographer.cpp index 0edb213089..2dd6c4fcaa 100644 --- a/libs/nativedisplay/AChoreographer.cpp +++ b/libs/nativedisplay/AChoreographer.cpp @@ -20,7 +20,6 @@ #include <android-base/thread_annotations.h> #include <gui/DisplayEventDispatcher.h> #include <gui/ISurfaceComposer.h> -#include <gui/SurfaceComposerClient.h> #include <jni.h> #include <private/android/choreographer.h> #include <utils/Looper.h> diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h index 4cb1b4259b..14627ce0ce 100644 --- a/libs/renderengine/gl/GLESRenderEngine.h +++ b/libs/renderengine/gl/GLESRenderEngine.h @@ -71,7 +71,7 @@ public: void cleanupPostRender() override; int getContextPriority() override; bool supportsBackgroundBlur() override { return mBlurFilter != nullptr; } - void onPrimaryDisplaySizeChanged(ui::Size size) override {} + void onActiveDisplaySizeChanged(ui::Size size) override {} EGLDisplay getEGLDisplay() const { return mEGLDisplay; } // Creates an output image for rendering to diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h index 5964bc3927..967cf5deff 100644 --- a/libs/renderengine/include/renderengine/RenderEngine.h +++ b/libs/renderengine/include/renderengine/RenderEngine.h @@ -129,9 +129,9 @@ public: // Attempt to switch RenderEngine into and out of protectedContext mode virtual void useProtectedContext(bool useProtectedContext) = 0; - // Notify RenderEngine of changes to the dimensions of the primary display + // Notify RenderEngine of changes to the dimensions of the active display // so that it can configure its internal caches accordingly. - virtual void onPrimaryDisplaySizeChanged(ui::Size size) = 0; + virtual void onActiveDisplaySizeChanged(ui::Size size) = 0; // Renders layers for a particular display via GPU composition. This method // should be called for every display that needs to be rendered via the GPU. diff --git a/libs/renderengine/include/renderengine/mock/RenderEngine.h b/libs/renderengine/include/renderengine/mock/RenderEngine.h index a4aa9ea488..0be3ba6b11 100644 --- a/libs/renderengine/include/renderengine/mock/RenderEngine.h +++ b/libs/renderengine/include/renderengine/mock/RenderEngine.h @@ -54,7 +54,7 @@ public: MOCK_METHOD0(cleanFramebufferCache, void()); MOCK_METHOD0(getContextPriority, int()); MOCK_METHOD0(supportsBackgroundBlur, bool()); - MOCK_METHOD1(onPrimaryDisplaySizeChanged, void(ui::Size)); + MOCK_METHOD1(onActiveDisplaySizeChanged, void(ui::Size)); protected: // mock renderengine still needs to implement these, but callers should never need to call them. diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp index 94023e6247..e42b5b9e79 100644 --- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp +++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp @@ -1413,7 +1413,7 @@ int SkiaGLRenderEngine::getContextPriority() { return value; } -void SkiaGLRenderEngine::onPrimaryDisplaySizeChanged(ui::Size size) { +void SkiaGLRenderEngine::onActiveDisplaySizeChanged(ui::Size size) { // This cache multiplier was selected based on review of cache sizes relative // to the screen resolution. Looking at the worst case memory needed by blur (~1.5x), // shadows (~1x), and general data structures (e.g. vertex buffers) we selected this as a diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.h b/libs/renderengine/skia/SkiaGLRenderEngine.h index 238ad8f452..e1162f5574 100644 --- a/libs/renderengine/skia/SkiaGLRenderEngine.h +++ b/libs/renderengine/skia/SkiaGLRenderEngine.h @@ -67,7 +67,7 @@ public: void useProtectedContext(bool useProtectedContext) override; bool supportsBackgroundBlur() override { return mBlurFilter != nullptr; } void assertShadersCompiled(int numShaders) override; - void onPrimaryDisplaySizeChanged(ui::Size size) override; + void onActiveDisplaySizeChanged(ui::Size size) override; int reportShadersCompiled() override; protected: diff --git a/libs/renderengine/threaded/RenderEngineThreaded.cpp b/libs/renderengine/threaded/RenderEngineThreaded.cpp index b9dabc1d05..8e666d5733 100644 --- a/libs/renderengine/threaded/RenderEngineThreaded.cpp +++ b/libs/renderengine/threaded/RenderEngineThreaded.cpp @@ -361,14 +361,14 @@ bool RenderEngineThreaded::supportsBackgroundBlur() { return mRenderEngine->supportsBackgroundBlur(); } -void RenderEngineThreaded::onPrimaryDisplaySizeChanged(ui::Size size) { +void RenderEngineThreaded::onActiveDisplaySizeChanged(ui::Size size) { // This function is designed so it can run asynchronously, so we do not need to wait // for the futures. { std::lock_guard lock(mThreadMutex); mFunctionCalls.push([size](renderengine::RenderEngine& instance) { - ATRACE_NAME("REThreaded::onPrimaryDisplaySizeChanged"); - instance.onPrimaryDisplaySizeChanged(size); + ATRACE_NAME("REThreaded::onActiveDisplaySizeChanged"); + instance.onActiveDisplaySizeChanged(size); }); } mCondition.notify_one(); diff --git a/libs/renderengine/threaded/RenderEngineThreaded.h b/libs/renderengine/threaded/RenderEngineThreaded.h index f2f5c0f7cd..b197df7e0f 100644 --- a/libs/renderengine/threaded/RenderEngineThreaded.h +++ b/libs/renderengine/threaded/RenderEngineThreaded.h @@ -65,7 +65,7 @@ public: void cleanFramebufferCache() override; int getContextPriority() override; bool supportsBackgroundBlur() override; - void onPrimaryDisplaySizeChanged(ui::Size size) override; + void onActiveDisplaySizeChanged(ui::Size size) override; protected: void mapExternalTextureBuffer(const sp<GraphicBuffer>& buffer, bool isRenderable) override; diff --git a/libs/vibrator/ExternalVibrationUtils.cpp b/libs/vibrator/ExternalVibrationUtils.cpp index 749c568457..980b08ba36 100644 --- a/libs/vibrator/ExternalVibrationUtils.cpp +++ b/libs/vibrator/ExternalVibrationUtils.cpp @@ -56,6 +56,36 @@ float getHapticMaxAmplitudeRatio(HapticScale scale) { } } +void applyHapticScale(float* buffer, size_t length, HapticScale scale) { + if (scale == HapticScale::MUTE) { + memset(buffer, 0, length * sizeof(float)); + return; + } + if (scale == HapticScale::NONE) { + return; + } + float gamma = getHapticScaleGamma(scale); + float maxAmplitudeRatio = getHapticMaxAmplitudeRatio(scale); + for (size_t i = 0; i < length; i++) { + float sign = buffer[i] >= 0 ? 1.0 : -1.0; + buffer[i] = powf(fabsf(buffer[i] / HAPTIC_MAX_AMPLITUDE_FLOAT), gamma) + * maxAmplitudeRatio * HAPTIC_MAX_AMPLITUDE_FLOAT * sign; + } +} + +void clipHapticData(float* buffer, size_t length, float limit) { + if (isnan(limit) || limit == 0) { + return; + } + limit = fabsf(limit); + for (size_t i = 0; i < length; i++) { + float sign = buffer[i] >= 0 ? 1.0 : -1.0; + if (fabsf(buffer[i]) > limit) { + buffer[i] = limit * sign; + } + } +} + } // namespace bool isValidHapticScale(HapticScale scale) { @@ -71,21 +101,11 @@ bool isValidHapticScale(HapticScale scale) { return false; } -void scaleHapticData(float* buffer, size_t length, HapticScale scale) { - if (!isValidHapticScale(scale) || scale == HapticScale::NONE) { - return; - } - if (scale == HapticScale::MUTE) { - memset(buffer, 0, length * sizeof(float)); - return; - } - float gamma = getHapticScaleGamma(scale); - float maxAmplitudeRatio = getHapticMaxAmplitudeRatio(scale); - for (size_t i = 0; i < length; i++) { - float sign = buffer[i] >= 0 ? 1.0 : -1.0; - buffer[i] = powf(fabsf(buffer[i] / HAPTIC_MAX_AMPLITUDE_FLOAT), gamma) - * maxAmplitudeRatio * HAPTIC_MAX_AMPLITUDE_FLOAT * sign; +void scaleHapticData(float* buffer, size_t length, HapticScale scale, float limit) { + if (isValidHapticScale(scale)) { + applyHapticScale(buffer, length, scale); } + clipHapticData(buffer, length, limit); } } // namespace android::os diff --git a/libs/vibrator/include/vibrator/ExternalVibrationUtils.h b/libs/vibrator/include/vibrator/ExternalVibrationUtils.h index 20045d0769..84357fcb35 100644 --- a/libs/vibrator/include/vibrator/ExternalVibrationUtils.h +++ b/libs/vibrator/include/vibrator/ExternalVibrationUtils.h @@ -32,7 +32,11 @@ enum class HapticScale { bool isValidHapticScale(HapticScale scale); -void scaleHapticData(float* buffer, size_t length, HapticScale scale); +/* Scales the haptic data in given buffer using the selected HapticScale and ensuring no absolute + * value will be larger than the absolute of given limit. + * The limit will be ignored if it is NaN or zero. + */ +void scaleHapticData(float* buffer, size_t length, HapticScale scale, float limit); } // namespace android::os diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp index 6612a932a0..73e57495e6 100644 --- a/services/inputflinger/Android.bp +++ b/services/inputflinger/Android.bp @@ -73,6 +73,7 @@ cc_defaults { "libui", "lib-platform-compat-native-api", "server_configurable_flags", + "InputFlingerProperties", ], static_libs: [ "libattestation", @@ -95,6 +96,7 @@ cc_library_shared { "libinputflinger_base", "libinputreporter", "libinputreader", + "libgui", ], static_libs: [ "libinputdispatcher", diff --git a/services/inputflinger/InputManager.cpp b/services/inputflinger/InputManager.cpp index a50e5c70f7..7b3658dfde 100644 --- a/services/inputflinger/InputManager.cpp +++ b/services/inputflinger/InputManager.cpp @@ -31,6 +31,10 @@ namespace android { +using gui::FocusRequest; +using gui::WindowInfo; +using gui::WindowInfoHandle; + static int32_t exceptionCodeFromStatusT(status_t status) { switch (status) { case OK: @@ -110,33 +114,6 @@ sp<InputDispatcherInterface> InputManager::getDispatcher() { return mDispatcher; } -class BinderWindowHandle : public InputWindowHandle { -public: - BinderWindowHandle(const InputWindowInfo& info) { mInfo = info; } - - bool updateInfo() override { - return true; - } -}; - -binder::Status InputManager::setInputWindows( - const std::vector<InputWindowInfo>& infos, - const sp<ISetInputWindowsListener>& setInputWindowsListener) { - std::unordered_map<int32_t, std::vector<sp<InputWindowHandle>>> handlesPerDisplay; - - std::vector<sp<InputWindowHandle>> handles; - for (const auto& info : infos) { - handlesPerDisplay.emplace(info.displayId, std::vector<sp<InputWindowHandle>>()); - handlesPerDisplay[info.displayId].push_back(new BinderWindowHandle(info)); - } - mDispatcher->setInputWindows(handlesPerDisplay); - - if (setInputWindowsListener) { - setInputWindowsListener->onSetInputWindowsFinished(); - } - return binder::Status::ok(); -} - // Used by tests only. binder::Status InputManager::createInputChannel(const std::string& name, InputChannel* outChannel) { IPCThreadState* ipc = IPCThreadState::self(); diff --git a/services/inputflinger/InputManager.h b/services/inputflinger/InputManager.h index 49bea132c8..4c07c22154 100644 --- a/services/inputflinger/InputManager.h +++ b/services/inputflinger/InputManager.h @@ -26,7 +26,6 @@ #include <InputDispatcherInterface.h> #include <InputDispatcherPolicyInterface.h> -#include <android/os/ISetInputWindowsListener.h> #include <input/Input.h> #include <input/InputTransport.h> @@ -38,7 +37,6 @@ #include <utils/Vector.h> using android::os::BnInputFlinger; -using android::os::ISetInputWindowsListener; namespace android { class InputChannel; @@ -104,13 +102,9 @@ public: sp<InputDispatcherInterface> getDispatcher() override; status_t dump(int fd, const Vector<String16>& args) override; - binder::Status setInputWindows( - const std::vector<InputWindowInfo>& handles, - const sp<ISetInputWindowsListener>& setInputWindowsListener) override; - binder::Status createInputChannel(const std::string& name, InputChannel* outChannel) override; binder::Status removeInputChannel(const sp<IBinder>& connectionToken) override; - binder::Status setFocusedWindow(const FocusRequest&) override; + binder::Status setFocusedWindow(const gui::FocusRequest&) override; private: sp<InputReaderInterface> mReader; diff --git a/services/inputflinger/InputReaderBase.cpp b/services/inputflinger/InputReaderBase.cpp index 9cc777d450..f26a9a986d 100644 --- a/services/inputflinger/InputReaderBase.cpp +++ b/services/inputflinger/InputReaderBase.cpp @@ -19,9 +19,9 @@ //#define LOG_NDEBUG 0 #include "InputReaderBase.h" +#include <ftl/NamedEnum.h> #include "input/DisplayViewport.h" #include "input/Input.h" -#include "input/NamedEnum.h" #include <android/log.h> #include <android-base/stringprintf.h> diff --git a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp index bc77b8aef4..5e9facf47e 100644 --- a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp +++ b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp @@ -18,8 +18,11 @@ #include <android/os/IInputConstants.h> #include <binder/Binder.h> +#include <gui/constants.h> #include "../dispatcher/InputDispatcher.h" +using android::gui::WindowInfo; +using android::gui::WindowInfoHandle; using android::os::IInputConstants; using android::os::InputEventInjectionResult; using android::os::InputEventInjectionSync; @@ -173,7 +176,7 @@ protected: PreallocatedInputEventFactory mEventFactory; }; -class FakeWindowHandle : public InputWindowHandle, public FakeInputReceiver { +class FakeWindowHandle : public WindowInfoHandle, public FakeInputReceiver { public: static const int32_t WIDTH = 200; static const int32_t HEIGHT = 200; @@ -182,13 +185,14 @@ public: const sp<InputDispatcher>& dispatcher, const std::string name) : FakeInputReceiver(dispatcher, name), mFrame(Rect(0, 0, WIDTH, HEIGHT)) { inputApplicationHandle->updateInfo(); + updateInfo(); mInfo.applicationInfo = *inputApplicationHandle->getInfo(); } - virtual bool updateInfo() override { + void updateInfo() { mInfo.token = mClientChannel->getConnectionToken(); mInfo.name = "FakeWindowHandle"; - mInfo.type = InputWindowInfo::Type::APPLICATION; + mInfo.type = WindowInfo::Type::APPLICATION; mInfo.dispatchingTimeout = DISPATCHING_TIMEOUT; mInfo.frameLeft = mFrame.left; mInfo.frameTop = mFrame.top; @@ -204,8 +208,6 @@ public: mInfo.ownerPid = INJECTOR_PID; mInfo.ownerUid = INJECTOR_UID; mInfo.displayId = ADISPLAY_ID_DEFAULT; - - return true; } protected: @@ -234,8 +236,8 @@ static MotionEvent generateMotionEvent() { /* edgeFlags */ 0, AMETA_NONE, /* buttonState */ 0, MotionClassification::NONE, identityTransform, /* xPrecision */ 0, /* yPrecision */ 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, - AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_DISPLAY_SIZE, - AMOTION_EVENT_INVALID_DISPLAY_SIZE, currentTime, currentTime, + AMOTION_EVENT_INVALID_CURSOR_POSITION, ui::Transform::ROT_0, + INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, currentTime, currentTime, /*pointerCount*/ 1, pointerProperties, pointerCoords); return event; } diff --git a/services/inputflinger/dispatcher/Android.bp b/services/inputflinger/dispatcher/Android.bp index 1b3888b340..171f2b5ce8 100644 --- a/services/inputflinger/dispatcher/Android.bp +++ b/services/inputflinger/dispatcher/Android.bp @@ -64,9 +64,11 @@ cc_defaults { "libstatspull", "libstatssocket", "libui", + "libgui", "libutils", "lib-platform-compat-native-api", "server_configurable_flags", + "InputFlingerProperties", ], static_libs: [ "libattestation", diff --git a/services/inputflinger/dispatcher/DragState.cpp b/services/inputflinger/dispatcher/DragState.cpp index 2e2df43009..e1844a4a3a 100644 --- a/services/inputflinger/dispatcher/DragState.cpp +++ b/services/inputflinger/dispatcher/DragState.cpp @@ -16,9 +16,7 @@ #include "DragState.h" #include <android-base/stringprintf.h> -#include <input/InputWindow.h> -using android::InputWindowHandle; using android::base::StringPrintf; namespace android::inputdispatcher { diff --git a/services/inputflinger/dispatcher/DragState.h b/services/inputflinger/dispatcher/DragState.h index 06453d8eee..b3c5709cbc 100644 --- a/services/inputflinger/dispatcher/DragState.h +++ b/services/inputflinger/dispatcher/DragState.h @@ -17,22 +17,22 @@ #ifndef _UI_INPUT_INPUTDISPATCHER_DRAGSTATE_H #define _UI_INPUT_INPUTDISPATCHER_DRAGSTATE_H +#include <gui/WindowInfo.h> #include <utils/RefBase.h> #include <string> namespace android { -class InputWindowHandle; - namespace inputdispatcher { + struct DragState { - DragState(const sp<android::InputWindowHandle>& windowHandle) : dragWindow(windowHandle) {} + DragState(const sp<android::gui::WindowInfoHandle>& windowHandle) : dragWindow(windowHandle) {} void dump(std::string& dump, const char* prefix = ""); // The window being dragged. - const sp<InputWindowHandle> dragWindow; + const sp<android::gui::WindowInfoHandle> dragWindow; // The last drag hover window which could receive the drag event. - sp<InputWindowHandle> dragHoverWindowHandle; + sp<android::gui::WindowInfoHandle> dragHoverWindowHandle; // Indicates the if received first event to check for button state. bool isStartDrag = false; // Indicate if the stylus button is down at the start of the drag. diff --git a/services/inputflinger/dispatcher/Entry.cpp b/services/inputflinger/dispatcher/Entry.cpp index 881024fc6e..b5ed0640cd 100644 --- a/services/inputflinger/dispatcher/Entry.cpp +++ b/services/inputflinger/dispatcher/Entry.cpp @@ -296,12 +296,14 @@ std::string SensorEntry::getDescription() const { volatile int32_t DispatchEntry::sNextSeqAtomic; DispatchEntry::DispatchEntry(std::shared_ptr<EventEntry> eventEntry, int32_t targetFlags, - ui::Transform transform, float globalScaleFactor, int2 displaySize) + ui::Transform transform, float globalScaleFactor, + uint32_t displayOrientation, int2 displaySize) : seq(nextSeq()), eventEntry(std::move(eventEntry)), targetFlags(targetFlags), transform(transform), globalScaleFactor(globalScaleFactor), + displayOrientation(displayOrientation), displaySize(displaySize), deliveryTime(0), resolvedAction(0), diff --git a/services/inputflinger/dispatcher/Entry.h b/services/inputflinger/dispatcher/Entry.h index ebbd8e93bf..1b7fcf2f75 100644 --- a/services/inputflinger/dispatcher/Entry.h +++ b/services/inputflinger/dispatcher/Entry.h @@ -20,8 +20,8 @@ #include "InjectionState.h" #include "InputTarget.h" +#include <gui/InputApplication.h> #include <input/Input.h> -#include <input/InputApplication.h> #include <stdint.h> #include <utils/Timers.h> #include <functional> @@ -215,6 +215,7 @@ struct DispatchEntry { int32_t targetFlags; ui::Transform transform; float globalScaleFactor; + uint32_t displayOrientation; int2 displaySize; // Both deliveryTime and timeoutTime are only populated when the entry is sent to the app, // and will be undefined before that. @@ -228,7 +229,8 @@ struct DispatchEntry { int32_t resolvedFlags; DispatchEntry(std::shared_ptr<EventEntry> eventEntry, int32_t targetFlags, - ui::Transform transform, float globalScaleFactor, int2 displaySize); + ui::Transform transform, float globalScaleFactor, uint32_t displayOrientation, + int2 displaySize); inline bool hasForegroundTarget() const { return targetFlags & InputTarget::FLAG_FOREGROUND; } diff --git a/services/inputflinger/dispatcher/FocusResolver.cpp b/services/inputflinger/dispatcher/FocusResolver.cpp index fb194355ba..4a75773201 100644 --- a/services/inputflinger/dispatcher/FocusResolver.cpp +++ b/services/inputflinger/dispatcher/FocusResolver.cpp @@ -27,12 +27,15 @@ static constexpr bool DEBUG_FOCUS = false; #include <android-base/stringprintf.h> #include <binder/Binder.h> -#include <input/InputWindow.h> -#include <input/NamedEnum.h> +#include <ftl/NamedEnum.h> +#include <gui/WindowInfo.h> #include <log/log.h> #include "FocusResolver.h" +using android::gui::FocusRequest; +using android::gui::WindowInfoHandle; + namespace android::inputdispatcher { sp<IBinder> FocusResolver::getFocusedWindowToken(int32_t displayId) const { @@ -52,7 +55,7 @@ std::optional<FocusRequest> FocusResolver::getFocusRequest(int32_t displayId) { * we will check if the previous focus request is eligible to receive focus. */ std::optional<FocusResolver::FocusChanges> FocusResolver::setInputWindows( - int32_t displayId, const std::vector<sp<InputWindowHandle>>& windows) { + int32_t displayId, const std::vector<sp<WindowInfoHandle>>& windows) { std::string removeFocusReason; // Check if the currently focused window is still focusable. @@ -87,7 +90,7 @@ std::optional<FocusResolver::FocusChanges> FocusResolver::setInputWindows( } std::optional<FocusResolver::FocusChanges> FocusResolver::setFocusedWindow( - const FocusRequest& request, const std::vector<sp<InputWindowHandle>>& windows) { + const FocusRequest& request, const std::vector<sp<WindowInfoHandle>>& windows) { const int32_t displayId = request.displayId; const sp<IBinder> currentFocus = getFocusedWindowToken(displayId); if (currentFocus == request.token) { @@ -136,11 +139,11 @@ std::optional<FocusResolver::FocusChanges> FocusResolver::setFocusedWindow( } FocusResolver::Focusability FocusResolver::isTokenFocusable( - const sp<IBinder>& token, const std::vector<sp<InputWindowHandle>>& windows) { + const sp<IBinder>& token, const std::vector<sp<WindowInfoHandle>>& windows) { bool allWindowsAreFocusable = true; bool visibleWindowFound = false; bool windowFound = false; - for (const sp<InputWindowHandle>& window : windows) { + for (const sp<WindowInfoHandle>& window : windows) { if (window->getToken() != token) { continue; } diff --git a/services/inputflinger/dispatcher/FocusResolver.h b/services/inputflinger/dispatcher/FocusResolver.h index afe16b3b45..1d6cd9a5fa 100644 --- a/services/inputflinger/dispatcher/FocusResolver.h +++ b/services/inputflinger/dispatcher/FocusResolver.h @@ -20,9 +20,9 @@ #include <optional> #include <unordered_map> -#include <android/FocusRequest.h> +#include <android/gui/FocusRequest.h> #include <binder/Binder.h> -#include <input/InputWindow.h> +#include <gui/WindowInfo.h> namespace android::inputdispatcher { @@ -58,9 +58,10 @@ public: std::string reason; }; std::optional<FocusResolver::FocusChanges> setInputWindows( - int32_t displayId, const std::vector<sp<InputWindowHandle>>& windows); + int32_t displayId, const std::vector<sp<android::gui::WindowInfoHandle>>& windows); std::optional<FocusResolver::FocusChanges> setFocusedWindow( - const FocusRequest& request, const std::vector<sp<InputWindowHandle>>& windows); + const android::gui::FocusRequest& request, + const std::vector<sp<android::gui::WindowInfoHandle>>& windows); // Display has been removed from the system, clean up old references. void displayRemoved(int32_t displayId); @@ -87,8 +88,9 @@ private: // we expect the focusability of the windows to match since its hard to reason why one window // can receive focus events and the other cannot when both are backed by the same input channel. // - static Focusability isTokenFocusable(const sp<IBinder>& token, - const std::vector<sp<InputWindowHandle>>& windows); + static Focusability isTokenFocusable( + const sp<IBinder>& token, + const std::vector<sp<android::gui::WindowInfoHandle>>& windows); // Focus tracking for keys, trackball, etc. A window token can be associated with one or // more InputWindowHandles. If a window is mirrored, the window and its mirror will share @@ -99,7 +101,7 @@ private: // This map will store the focus request per display. When the input window handles are updated, // the current request will be checked to see if it can be processed at that time. - std::unordered_map<int32_t /* displayId */, FocusRequest> mFocusRequestByDisplay; + std::unordered_map<int32_t /* displayId */, android::gui::FocusRequest> mFocusRequestByDisplay; // Last reason for not granting a focus request. This is used to add more debug information // in the event logs. @@ -108,7 +110,7 @@ private: std::optional<FocusResolver::FocusChanges> updateFocusedWindow( int32_t displayId, const std::string& reason, const sp<IBinder>& token, const std::string& tokenName = ""); - std::optional<FocusRequest> getFocusRequest(int32_t displayId); + std::optional<android::gui::FocusRequest> getFocusRequest(int32_t displayId); }; } // namespace android::inputdispatcher
\ No newline at end of file diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index a51978627f..e3912b3e79 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -47,6 +47,7 @@ static constexpr bool DEBUG_TOUCH_OCCLUSION = true; // Log debug messages about hover events. #define DEBUG_HOVER 0 +#include <InputFlingerProperties.sysprop.h> #include <android-base/chrono_utils.h> #include <android-base/properties.h> #include <android-base/stringprintf.h> @@ -54,8 +55,8 @@ static constexpr bool DEBUG_TOUCH_OCCLUSION = true; #include <binder/Binder.h> #include <binder/IServiceManager.h> #include <com/android/internal/compat/IPlatformCompatNative.h> +#include <gui/SurfaceComposerClient.h> #include <input/InputDevice.h> -#include <input/InputWindow.h> #include <log/log.h> #include <log/log_event_list.h> #include <powermanager/PowerManager.h> @@ -81,6 +82,10 @@ static constexpr bool DEBUG_TOUCH_OCCLUSION = true; using android::base::HwTimeoutMultiplier; using android::base::Result; using android::base::StringPrintf; +using android::gui::FocusRequest; +using android::gui::TouchOcclusionMode; +using android::gui::WindowInfo; +using android::gui::WindowInfoHandle; using android::os::BlockUntrustedTouchesMode; using android::os::IInputConstants; using android::os::InputEventInjectionResult; @@ -93,7 +98,8 @@ namespace android::inputdispatcher { // coordinates and SurfaceFlinger includes the display rotation in the input window transforms. static bool isPerWindowInputRotationEnabled() { static const bool PER_WINDOW_INPUT_ROTATION = - base::GetBoolProperty("persist.debug.per_window_input_rotation", false); + sysprop::InputFlingerProperties::per_window_input_rotation().value_or(false); + return PER_WINDOW_INPUT_ROTATION; } @@ -290,7 +296,7 @@ static V getValueByKey(const std::unordered_map<K, V>& map, K key) { return it != map.end() ? it->second : V{}; } -static bool haveSameToken(const sp<InputWindowHandle>& first, const sp<InputWindowHandle>& second) { +static bool haveSameToken(const sp<WindowInfoHandle>& first, const sp<WindowInfoHandle>& second) { if (first == second) { return true; } @@ -302,7 +308,7 @@ static bool haveSameToken(const sp<InputWindowHandle>& first, const sp<InputWind return first->getToken() == second->getToken(); } -static bool haveSameApplicationToken(const InputWindowInfo* first, const InputWindowInfo* second) { +static bool haveSameApplicationToken(const WindowInfo* first, const WindowInfo* second) { if (first == nullptr || second == nullptr) { return false; } @@ -319,13 +325,14 @@ static std::unique_ptr<DispatchEntry> createDispatchEntry(const InputTarget& inp int32_t inputTargetFlags) { if (eventEntry->type == EventEntry::Type::MOTION) { const MotionEntry& motionEntry = static_cast<const MotionEntry&>(*eventEntry); - if ((motionEntry.source & AINPUT_SOURCE_CLASS_POINTER) == 0) { + if ((motionEntry.source & AINPUT_SOURCE_CLASS_JOYSTICK) || + (motionEntry.source & AINPUT_SOURCE_CLASS_POSITION)) { const ui::Transform identityTransform; - // Use identity transform for events that are not pointer events because their axes - // values do not represent on-screen coordinates, so they should not have any window - // transformations applied to them. + // Use identity transform for joystick and position-based (touchpad) events because they + // don't depend on the window transform. return std::make_unique<DispatchEntry>(eventEntry, inputTargetFlags, identityTransform, 1.0f /*globalScaleFactor*/, + inputTarget.displayOrientation, inputTarget.displaySize); } } @@ -334,6 +341,7 @@ static std::unique_ptr<DispatchEntry> createDispatchEntry(const InputTarget& inp const ui::Transform& transform = inputTarget.getDefaultPointerTransform(); return std::make_unique<DispatchEntry>(eventEntry, inputTargetFlags, transform, inputTarget.globalScaleFactor, + inputTarget.displayOrientation, inputTarget.displaySize); } @@ -386,6 +394,7 @@ static std::unique_ptr<DispatchEntry> createDispatchEntry(const InputTarget& inp std::unique_ptr<DispatchEntry> dispatchEntry = std::make_unique<DispatchEntry>(std::move(combinedMotionEntry), inputTargetFlags, firstPointerTransform, inputTarget.globalScaleFactor, + inputTarget.displayOrientation, inputTarget.displaySize); return dispatchEntry; } @@ -551,6 +560,10 @@ InputDispatcher::~InputDispatcher() { } } +void InputDispatcher::onFirstRef() { + SurfaceComposerClient::getDefault()->addWindowInfosListener(this); +} + status_t InputDispatcher::start() { if (mThread) { return ALREADY_EXISTS; @@ -624,7 +637,7 @@ void InputDispatcher::processNoFocusedWindowAnrLocked() { return; // The focused application has changed. } - const sp<InputWindowHandle>& focusedWindowHandle = + const sp<WindowInfoHandle>& focusedWindowHandle = getFocusedWindowHandleLocked(mAwaitedApplicationDisplayId); if (focusedWindowHandle != nullptr) { return; // We now have a focused window. No need for ANR. @@ -673,7 +686,7 @@ nsecs_t InputDispatcher::processAnrsLocked() { } std::chrono::nanoseconds InputDispatcher::getDispatchingTimeoutLocked(const sp<IBinder>& token) { - sp<InputWindowHandle> window = getWindowHandleLocked(token); + sp<WindowInfoHandle> window = getWindowHandleLocked(token); if (window != nullptr) { return window->getDispatchingTimeout(DEFAULT_INPUT_DISPATCHING_TIMEOUT); } @@ -885,7 +898,7 @@ bool InputDispatcher::shouldPruneInboundQueueLocked(const MotionEntry& motionEnt motionEntry.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X)); int32_t y = static_cast<int32_t>( motionEntry.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y)); - sp<InputWindowHandle> touchedWindowHandle = + sp<WindowInfoHandle> touchedWindowHandle = findTouchedWindowAtLocked(displayId, x, y, nullptr); if (touchedWindowHandle != nullptr && touchedWindowHandle->getApplicationToken() != @@ -990,29 +1003,29 @@ void InputDispatcher::addRecentEventLocked(std::shared_ptr<EventEntry> entry) { } } -sp<InputWindowHandle> InputDispatcher::findTouchedWindowAtLocked(int32_t displayId, int32_t x, - int32_t y, TouchState* touchState, - bool addOutsideTargets, - bool addPortalWindows, - bool ignoreDragWindow) { +sp<WindowInfoHandle> InputDispatcher::findTouchedWindowAtLocked(int32_t displayId, int32_t x, + int32_t y, TouchState* touchState, + bool addOutsideTargets, + bool addPortalWindows, + bool ignoreDragWindow) { if ((addPortalWindows || addOutsideTargets) && touchState == nullptr) { LOG_ALWAYS_FATAL( "Must provide a valid touch state if adding portal windows or outside targets"); } // Traverse windows from front to back to find touched window. - const std::vector<sp<InputWindowHandle>>& windowHandles = getWindowHandlesLocked(displayId); - for (const sp<InputWindowHandle>& windowHandle : windowHandles) { + const std::vector<sp<WindowInfoHandle>>& windowHandles = getWindowHandlesLocked(displayId); + for (const sp<WindowInfoHandle>& windowHandle : windowHandles) { if (ignoreDragWindow && haveSameToken(windowHandle, mDragState->dragWindow)) { continue; } - const InputWindowInfo* windowInfo = windowHandle->getInfo(); + const WindowInfo* windowInfo = windowHandle->getInfo(); if (windowInfo->displayId == displayId) { auto flags = windowInfo->flags; if (windowInfo->visible) { - if (!flags.test(InputWindowInfo::Flag::NOT_TOUCHABLE)) { - bool isTouchModal = !flags.test(InputWindowInfo::Flag::NOT_FOCUSABLE) && - !flags.test(InputWindowInfo::Flag::NOT_TOUCH_MODAL); + if (!flags.test(WindowInfo::Flag::NOT_TOUCHABLE)) { + bool isTouchModal = !flags.test(WindowInfo::Flag::NOT_FOCUSABLE) && + !flags.test(WindowInfo::Flag::NOT_TOUCH_MODAL); if (isTouchModal || windowInfo->touchableRegionContainsPoint(x, y)) { int32_t portalToDisplayId = windowInfo->portalToDisplayId; if (portalToDisplayId != ADISPLAY_ID_NONE && @@ -1029,7 +1042,7 @@ sp<InputWindowHandle> InputDispatcher::findTouchedWindowAtLocked(int32_t display } } - if (addOutsideTargets && flags.test(InputWindowInfo::Flag::WATCH_OUTSIDE_TOUCH)) { + if (addOutsideTargets && flags.test(WindowInfo::Flag::WATCH_OUTSIDE_TOUCH)) { touchState->addOrUpdateWindow(windowHandle, InputTarget::FLAG_DISPATCH_AS_OUTSIDE, BitSet32(0)); @@ -1041,13 +1054,13 @@ sp<InputWindowHandle> InputDispatcher::findTouchedWindowAtLocked(int32_t display } std::vector<TouchedMonitor> InputDispatcher::findTouchedGestureMonitorsLocked( - int32_t displayId, const std::vector<sp<InputWindowHandle>>& portalWindows) const { + int32_t displayId, const std::vector<sp<WindowInfoHandle>>& portalWindows) const { std::vector<TouchedMonitor> touchedMonitors; std::vector<Monitor> monitors = getValueByKey(mGestureMonitorsByDisplay, displayId); addGestureMonitors(monitors, touchedMonitors); - for (const sp<InputWindowHandle>& portalWindow : portalWindows) { - const InputWindowInfo* windowInfo = portalWindow->getInfo(); + for (const sp<WindowInfoHandle>& portalWindow : portalWindows) { + const WindowInfo* windowInfo = portalWindow->getInfo(); monitors = getValueByKey(mGestureMonitorsByDisplay, windowInfo->portalToDisplayId); addGestureMonitors(monitors, touchedMonitors, -windowInfo->frameLeft, -windowInfo->frameTop); @@ -1596,7 +1609,7 @@ bool InputDispatcher::dispatchMotionLocked(nsecs_t currentTime, std::shared_ptr< // The event has gone through these portal windows, so we add monitoring targets of // the corresponding displays as well. for (size_t i = 0; i < state.portalWindows.size(); i++) { - const InputWindowInfo* windowInfo = state.portalWindows[i]->getInfo(); + const WindowInfo* windowInfo = state.portalWindows[i]->getInfo(); addGlobalMonitoringTargetsLocked(inputTargets, windowInfo->portalToDisplayId, -windowInfo->frameLeft, -windowInfo->frameTop); } @@ -1614,7 +1627,7 @@ bool InputDispatcher::dispatchMotionLocked(nsecs_t currentTime, std::shared_ptr< return true; } -void InputDispatcher::enqueueDragEventLocked(const sp<InputWindowHandle>& windowHandle, +void InputDispatcher::enqueueDragEventLocked(const sp<WindowInfoHandle>& windowHandle, bool isExiting, const MotionEntry& motionEntry) { // If the window needs enqueue a drag event, the pointerCount should be 1 and the action should // be AMOTION_EVENT_ACTION_MOVE, that could guarantee the first pointer is always valid. @@ -1794,7 +1807,7 @@ InputEventInjectionResult InputDispatcher::findFocusedWindowTargetsLocked( std::string reason; int32_t displayId = getTargetDisplayId(entry); - sp<InputWindowHandle> focusedWindowHandle = getFocusedWindowHandleLocked(displayId); + sp<WindowInfoHandle> focusedWindowHandle = getFocusedWindowHandleLocked(displayId); std::shared_ptr<InputApplicationHandle> focusedApplicationHandle = getValueByKey(mFocusedApplicationHandlesByDisplay, displayId); @@ -1921,8 +1934,8 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( // Update the touch state as needed based on the properties of the touch event. InputEventInjectionResult injectionResult = InputEventInjectionResult::PENDING; InjectionPermission injectionPermission = INJECTION_PERMISSION_UNKNOWN; - sp<InputWindowHandle> newHoverWindowHandle(mLastHoverWindowHandle); - sp<InputWindowHandle> newTouchedWindowHandle; + sp<WindowInfoHandle> newHoverWindowHandle(mLastHoverWindowHandle); + sp<WindowInfoHandle> newTouchedWindowHandle; // Copy current touch state into tempTouchState. // This state will be used to update mTouchStatesByDisplay at the end of this function. @@ -2115,7 +2128,7 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( int32_t x = int32_t(entry.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X)); int32_t y = int32_t(entry.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y)); - sp<InputWindowHandle> oldTouchedWindowHandle = + sp<WindowInfoHandle> oldTouchedWindowHandle = tempTouchState.getFirstForegroundWindowHandle(); newTouchedWindowHandle = findTouchedWindowAtLocked(displayId, x, y, &tempTouchState); if (oldTouchedWindowHandle != newTouchedWindowHandle && @@ -2214,15 +2227,15 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( // Check whether windows listening for outside touches are owned by the same UID. If it is // set the policy flag that we will not reveal coordinate information to this window. if (maskedAction == AMOTION_EVENT_ACTION_DOWN) { - sp<InputWindowHandle> foregroundWindowHandle = + sp<WindowInfoHandle> foregroundWindowHandle = tempTouchState.getFirstForegroundWindowHandle(); if (foregroundWindowHandle) { const int32_t foregroundWindowUid = foregroundWindowHandle->getInfo()->ownerUid; for (const TouchedWindow& touchedWindow : tempTouchState.windows) { if (touchedWindow.targetFlags & InputTarget::FLAG_DISPATCH_AS_OUTSIDE) { - sp<InputWindowHandle> inputWindowHandle = touchedWindow.windowHandle; - if (inputWindowHandle->getInfo()->ownerUid != foregroundWindowUid) { - tempTouchState.addOrUpdateWindow(inputWindowHandle, + sp<WindowInfoHandle> windowInfoHandle = touchedWindow.windowHandle; + if (windowInfoHandle->getInfo()->ownerUid != foregroundWindowUid) { + tempTouchState.addOrUpdateWindow(windowInfoHandle, InputTarget::FLAG_ZERO_COORDS, BitSet32(0)); } @@ -2238,15 +2251,15 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( // engine only supports touch events. We would need to add a mechanism similar // to View.onGenericMotionEvent to enable wallpapers to handle these events. if (maskedAction == AMOTION_EVENT_ACTION_DOWN) { - sp<InputWindowHandle> foregroundWindowHandle = + sp<WindowInfoHandle> foregroundWindowHandle = tempTouchState.getFirstForegroundWindowHandle(); if (foregroundWindowHandle && foregroundWindowHandle->getInfo()->hasWallpaper) { - const std::vector<sp<InputWindowHandle>>& windowHandles = + const std::vector<sp<WindowInfoHandle>>& windowHandles = getWindowHandlesLocked(displayId); - for (const sp<InputWindowHandle>& windowHandle : windowHandles) { - const InputWindowInfo* info = windowHandle->getInfo(); + for (const sp<WindowInfoHandle>& windowHandle : windowHandles) { + const WindowInfo* info = windowHandle->getInfo(); if (info->displayId == displayId && - windowHandle->getInfo()->type == InputWindowInfo::Type::WALLPAPER) { + windowHandle->getInfo()->type == WindowInfo::Type::WALLPAPER) { tempTouchState .addOrUpdateWindow(windowHandle, InputTarget::FLAG_WINDOW_IS_OBSCURED | @@ -2365,7 +2378,7 @@ Failed: } void InputDispatcher::finishDragAndDrop(int32_t displayId, float x, float y) { - const sp<InputWindowHandle> dropWindow = + const sp<WindowInfoHandle> dropWindow = findTouchedWindowAtLocked(displayId, x, y, nullptr /*touchState*/, false /*addOutsideTargets*/, false /*addPortalWindows*/, true /*ignoreDragWindow*/); @@ -2400,7 +2413,7 @@ void InputDispatcher::addDragEventLocked(const MotionEntry& entry) { return; } - const sp<InputWindowHandle> hoverWindowHandle = + const sp<WindowInfoHandle> hoverWindowHandle = findTouchedWindowAtLocked(entry.displayId, x, y, nullptr /*touchState*/, false /*addOutsideTargets*/, false /*addPortalWindows*/, true /*ignoreDragWindow*/); @@ -2425,7 +2438,7 @@ void InputDispatcher::addDragEventLocked(const MotionEntry& entry) { } } -void InputDispatcher::addWindowTargetLocked(const sp<InputWindowHandle>& windowHandle, +void InputDispatcher::addWindowTargetLocked(const sp<WindowInfoHandle>& windowHandle, int32_t targetFlags, BitSet32 pointerIds, std::vector<InputTarget>& inputTargets) { std::vector<InputTarget>::iterator it = @@ -2435,7 +2448,7 @@ void InputDispatcher::addWindowTargetLocked(const sp<InputWindowHandle>& windowH windowHandle->getToken(); }); - const InputWindowInfo* windowInfo = windowHandle->getInfo(); + const WindowInfo* windowInfo = windowHandle->getInfo(); if (it == inputTargets.end()) { InputTarget inputTarget; @@ -2448,6 +2461,7 @@ void InputDispatcher::addWindowTargetLocked(const sp<InputWindowHandle>& windowH inputTarget.inputChannel = inputChannel; inputTarget.flags = targetFlags; inputTarget.globalScaleFactor = windowInfo->globalScaleFactor; + inputTarget.displayOrientation = windowInfo->displayOrientation; inputTarget.displaySize = int2(windowHandle->getInfo()->displayWidth, windowHandle->getInfo()->displayHeight); inputTargets.push_back(inputTarget); @@ -2486,7 +2500,7 @@ void InputDispatcher::addMonitoringTargetLocked(const Monitor& monitor, float xO inputTargets.push_back(target); } -bool InputDispatcher::checkInjectionPermission(const sp<InputWindowHandle>& windowHandle, +bool InputDispatcher::checkInjectionPermission(const sp<WindowInfoHandle>& windowHandle, const InjectionState* injectionState) { if (injectionState && (windowHandle == nullptr || @@ -2511,8 +2525,8 @@ bool InputDispatcher::checkInjectionPermission(const sp<InputWindowHandle>& wind * another window handle. We only check a few preconditions. Actually * checking the bounds is left to the caller. */ -static bool canBeObscuredBy(const sp<InputWindowHandle>& windowHandle, - const sp<InputWindowHandle>& otherHandle) { +static bool canBeObscuredBy(const sp<WindowInfoHandle>& windowHandle, + const sp<WindowInfoHandle>& otherHandle) { // Compare by token so cloned layers aren't counted if (haveSameToken(windowHandle, otherHandle)) { return false; @@ -2521,8 +2535,7 @@ static bool canBeObscuredBy(const sp<InputWindowHandle>& windowHandle, auto otherInfo = otherHandle->getInfo(); if (!otherInfo->visible) { return false; - } else if (otherInfo->alpha == 0 && - otherInfo->flags.test(InputWindowInfo::Flag::NOT_TOUCHABLE)) { + } else if (otherInfo->alpha == 0 && otherInfo->flags.test(WindowInfo::Flag::NOT_TOUCHABLE)) { // Those act as if they were invisible, so we don't need to flag them. // We do want to potentially flag touchable windows even if they have 0 // opacity, since they can consume touches and alter the effects of the @@ -2560,20 +2573,20 @@ static bool canBeObscuredBy(const sp<InputWindowHandle>& windowHandle, * If neither of those is true, then it means the touch can be allowed. */ InputDispatcher::TouchOcclusionInfo InputDispatcher::computeTouchOcclusionInfoLocked( - const sp<InputWindowHandle>& windowHandle, int32_t x, int32_t y) const { - const InputWindowInfo* windowInfo = windowHandle->getInfo(); + const sp<WindowInfoHandle>& windowHandle, int32_t x, int32_t y) const { + const WindowInfo* windowInfo = windowHandle->getInfo(); int32_t displayId = windowInfo->displayId; - const std::vector<sp<InputWindowHandle>>& windowHandles = getWindowHandlesLocked(displayId); + const std::vector<sp<WindowInfoHandle>>& windowHandles = getWindowHandlesLocked(displayId); TouchOcclusionInfo info; info.hasBlockingOcclusion = false; info.obscuringOpacity = 0; info.obscuringUid = -1; std::map<int32_t, float> opacityByUid; - for (const sp<InputWindowHandle>& otherHandle : windowHandles) { + for (const sp<WindowInfoHandle>& otherHandle : windowHandles) { if (windowHandle == otherHandle) { break; // All future windows are below us. Exit early. } - const InputWindowInfo* otherInfo = otherHandle->getInfo(); + const WindowInfo* otherInfo = otherHandle->getInfo(); if (canBeObscuredBy(windowHandle, otherHandle) && otherInfo->frameContainsPoint(x, y) && !haveSameApplicationToken(windowInfo, otherInfo)) { if (DEBUG_TOUCH_OCCLUSION) { @@ -2612,7 +2625,7 @@ InputDispatcher::TouchOcclusionInfo InputDispatcher::computeTouchOcclusionInfoLo return info; } -std::string InputDispatcher::dumpWindowForTouchOcclusion(const InputWindowInfo* info, +std::string InputDispatcher::dumpWindowForTouchOcclusion(const WindowInfo* info, bool isTouchedWindow) const { return StringPrintf(INDENT2 "* %stype=%s, package=%s/%" PRId32 ", id=%" PRId32 ", mode=%s, alpha=%.2f, " @@ -2646,15 +2659,15 @@ bool InputDispatcher::isTouchTrustedLocked(const TouchOcclusionInfo& occlusionIn return true; } -bool InputDispatcher::isWindowObscuredAtPointLocked(const sp<InputWindowHandle>& windowHandle, +bool InputDispatcher::isWindowObscuredAtPointLocked(const sp<WindowInfoHandle>& windowHandle, int32_t x, int32_t y) const { int32_t displayId = windowHandle->getInfo()->displayId; - const std::vector<sp<InputWindowHandle>>& windowHandles = getWindowHandlesLocked(displayId); - for (const sp<InputWindowHandle>& otherHandle : windowHandles) { + const std::vector<sp<WindowInfoHandle>>& windowHandles = getWindowHandlesLocked(displayId); + for (const sp<WindowInfoHandle>& otherHandle : windowHandles) { if (windowHandle == otherHandle) { break; // All future windows are below us. Exit early. } - const InputWindowInfo* otherInfo = otherHandle->getInfo(); + const WindowInfo* otherInfo = otherHandle->getInfo(); if (canBeObscuredBy(windowHandle, otherHandle) && otherInfo->frameContainsPoint(x, y)) { return true; @@ -2663,15 +2676,15 @@ bool InputDispatcher::isWindowObscuredAtPointLocked(const sp<InputWindowHandle>& return false; } -bool InputDispatcher::isWindowObscuredLocked(const sp<InputWindowHandle>& windowHandle) const { +bool InputDispatcher::isWindowObscuredLocked(const sp<WindowInfoHandle>& windowHandle) const { int32_t displayId = windowHandle->getInfo()->displayId; - const std::vector<sp<InputWindowHandle>>& windowHandles = getWindowHandlesLocked(displayId); - const InputWindowInfo* windowInfo = windowHandle->getInfo(); - for (const sp<InputWindowHandle>& otherHandle : windowHandles) { + const std::vector<sp<WindowInfoHandle>>& windowHandles = getWindowHandlesLocked(displayId); + const WindowInfo* windowInfo = windowHandle->getInfo(); + for (const sp<WindowInfoHandle>& otherHandle : windowHandles) { if (windowHandle == otherHandle) { break; // All future windows are below us. Exit early. } - const InputWindowInfo* otherInfo = otherHandle->getInfo(); + const WindowInfo* otherInfo = otherHandle->getInfo(); if (canBeObscuredBy(windowHandle, otherHandle) && otherInfo->overlaps(windowInfo)) { return true; @@ -2681,8 +2694,7 @@ bool InputDispatcher::isWindowObscuredLocked(const sp<InputWindowHandle>& window } std::string InputDispatcher::getApplicationWindowLabel( - const InputApplicationHandle* applicationHandle, - const sp<InputWindowHandle>& windowHandle) { + const InputApplicationHandle* applicationHandle, const sp<WindowInfoHandle>& windowHandle) { if (applicationHandle != nullptr) { if (windowHandle != nullptr) { return applicationHandle->getName() + " - " + windowHandle->getName(); @@ -2705,10 +2717,10 @@ void InputDispatcher::pokeUserActivityLocked(const EventEntry& eventEntry) { return; } int32_t displayId = getTargetDisplayId(eventEntry); - sp<InputWindowHandle> focusedWindowHandle = getFocusedWindowHandleLocked(displayId); + sp<WindowInfoHandle> focusedWindowHandle = getFocusedWindowHandleLocked(displayId); if (focusedWindowHandle != nullptr) { - const InputWindowInfo* info = focusedWindowHandle->getInfo(); - if (info->inputFeatures.test(InputWindowInfo::Feature::DISABLE_USER_ACTIVITY)) { + const WindowInfo* info = focusedWindowHandle->getInfo(); + if (info->inputFeatures.test(WindowInfo::Feature::DISABLE_USER_ACTIVITY)) { #if DEBUG_DISPATCH_CYCLE ALOGD("Not poking user activity: disabled by window '%s'.", info->name.c_str()); #endif @@ -3163,6 +3175,7 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, motionEntry.xPrecision, motionEntry.yPrecision, motionEntry.xCursorPosition, motionEntry.yCursorPosition, + dispatchEntry->displayOrientation, dispatchEntry->displaySize.x, dispatchEntry->displaySize.y, motionEntry.downTime, motionEntry.eventTime, @@ -3479,10 +3492,10 @@ void InputDispatcher::synthesizeCancelationEventsForConnectionLocked( #endif InputTarget target; - sp<InputWindowHandle> windowHandle = + sp<WindowInfoHandle> windowHandle = getWindowHandleLocked(connection->inputChannel->getConnectionToken()); if (windowHandle != nullptr) { - const InputWindowInfo* windowInfo = windowHandle->getInfo(); + const WindowInfo* windowInfo = windowHandle->getInfo(); target.setDefaultPointerTransform(windowInfo->transform); target.globalScaleFactor = windowInfo->globalScaleFactor; } @@ -3546,10 +3559,10 @@ void InputDispatcher::synthesizePointerDownEventsForConnectionLocked( #endif InputTarget target; - sp<InputWindowHandle> windowHandle = + sp<WindowInfoHandle> windowHandle = getWindowHandleLocked(connection->inputChannel->getConnectionToken()); if (windowHandle != nullptr) { - const InputWindowInfo* windowInfo = windowHandle->getInfo(); + const WindowInfo* windowInfo = windowHandle->getInfo(); target.setDefaultPointerTransform(windowInfo->transform); target.globalScaleFactor = windowInfo->globalScaleFactor; } @@ -3875,8 +3888,8 @@ void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) { args->action, args->actionButton, args->flags, args->edgeFlags, args->metaState, args->buttonState, args->classification, transform, args->xPrecision, args->yPrecision, args->xCursorPosition, - args->yCursorPosition, AMOTION_EVENT_INVALID_DISPLAY_SIZE, - AMOTION_EVENT_INVALID_DISPLAY_SIZE, args->downTime, args->eventTime, + args->yCursorPosition, ui::Transform::ROT_0, INVALID_DISPLAY_SIZE, + INVALID_DISPLAY_SIZE, args->downTime, args->eventTime, args->pointerCount, args->pointerProperties, args->pointerCoords); policyFlags |= POLICY_FLAG_FILTERED; @@ -4320,22 +4333,22 @@ void InputDispatcher::decrementPendingForegroundDispatches(EventEntry& entry) { } } -const std::vector<sp<InputWindowHandle>>& InputDispatcher::getWindowHandlesLocked( +const std::vector<sp<WindowInfoHandle>>& InputDispatcher::getWindowHandlesLocked( int32_t displayId) const { - static const std::vector<sp<InputWindowHandle>> EMPTY_WINDOW_HANDLES; + static const std::vector<sp<WindowInfoHandle>> EMPTY_WINDOW_HANDLES; auto it = mWindowHandlesByDisplay.find(displayId); return it != mWindowHandlesByDisplay.end() ? it->second : EMPTY_WINDOW_HANDLES; } -sp<InputWindowHandle> InputDispatcher::getWindowHandleLocked( +sp<WindowInfoHandle> InputDispatcher::getWindowHandleLocked( const sp<IBinder>& windowHandleToken) const { if (windowHandleToken == nullptr) { return nullptr; } for (auto& it : mWindowHandlesByDisplay) { - const std::vector<sp<InputWindowHandle>>& windowHandles = it.second; - for (const sp<InputWindowHandle>& windowHandle : windowHandles) { + const std::vector<sp<WindowInfoHandle>>& windowHandles = it.second; + for (const sp<WindowInfoHandle>& windowHandle : windowHandles) { if (windowHandle->getToken() == windowHandleToken) { return windowHandle; } @@ -4344,13 +4357,13 @@ sp<InputWindowHandle> InputDispatcher::getWindowHandleLocked( return nullptr; } -sp<InputWindowHandle> InputDispatcher::getWindowHandleLocked(const sp<IBinder>& windowHandleToken, - int displayId) const { +sp<WindowInfoHandle> InputDispatcher::getWindowHandleLocked(const sp<IBinder>& windowHandleToken, + int displayId) const { if (windowHandleToken == nullptr) { return nullptr; } - for (const sp<InputWindowHandle>& windowHandle : getWindowHandlesLocked(displayId)) { + for (const sp<WindowInfoHandle>& windowHandle : getWindowHandlesLocked(displayId)) { if (windowHandle->getToken() == windowHandleToken) { return windowHandle; } @@ -4358,11 +4371,11 @@ sp<InputWindowHandle> InputDispatcher::getWindowHandleLocked(const sp<IBinder>& return nullptr; } -sp<InputWindowHandle> InputDispatcher::getWindowHandleLocked( - const sp<InputWindowHandle>& windowHandle) const { +sp<WindowInfoHandle> InputDispatcher::getWindowHandleLocked( + const sp<WindowInfoHandle>& windowHandle) const { for (auto& it : mWindowHandlesByDisplay) { - const std::vector<sp<InputWindowHandle>>& windowHandles = it.second; - for (const sp<InputWindowHandle>& handle : windowHandles) { + const std::vector<sp<WindowInfoHandle>>& windowHandles = it.second; + for (const sp<WindowInfoHandle>& handle : windowHandles) { if (handle->getId() == windowHandle->getId() && handle->getToken() == windowHandle->getToken()) { if (windowHandle->getInfo()->displayId != it.first) { @@ -4378,15 +4391,15 @@ sp<InputWindowHandle> InputDispatcher::getWindowHandleLocked( return nullptr; } -sp<InputWindowHandle> InputDispatcher::getFocusedWindowHandleLocked(int displayId) const { +sp<WindowInfoHandle> InputDispatcher::getFocusedWindowHandleLocked(int displayId) const { sp<IBinder> focusedToken = mFocusResolver.getFocusedWindowToken(displayId); return getWindowHandleLocked(focusedToken, displayId); } -bool InputDispatcher::hasResponsiveConnectionLocked(InputWindowHandle& windowHandle) const { +bool InputDispatcher::hasResponsiveConnectionLocked(WindowInfoHandle& windowHandle) const { sp<Connection> connection = getConnectionLocked(windowHandle.getToken()); const bool noInputChannel = - windowHandle.getInfo()->inputFeatures.test(InputWindowInfo::Feature::NO_INPUT_CHANNEL); + windowHandle.getInfo()->inputFeatures.test(WindowInfo::Feature::NO_INPUT_CHANNEL); if (connection != nullptr && noInputChannel) { ALOGW("%s has feature NO_INPUT_CHANNEL, but it matched to connection %s", windowHandle.getName().c_str(), connection->inputChannel->getName().c_str()); @@ -4416,8 +4429,8 @@ std::shared_ptr<InputChannel> InputDispatcher::getInputChannelLocked( } void InputDispatcher::updateWindowHandlesForDisplayLocked( - const std::vector<sp<InputWindowHandle>>& inputWindowHandles, int32_t displayId) { - if (inputWindowHandles.empty()) { + const std::vector<sp<WindowInfoHandle>>& windowInfoHandles, int32_t displayId) { + if (windowInfoHandles.empty()) { // Remove all handles on a display if there are no windows left. mWindowHandlesByDisplay.erase(displayId); return; @@ -4425,26 +4438,21 @@ void InputDispatcher::updateWindowHandlesForDisplayLocked( // Since we compare the pointer of input window handles across window updates, we need // to make sure the handle object for the same window stays unchanged across updates. - const std::vector<sp<InputWindowHandle>>& oldHandles = getWindowHandlesLocked(displayId); - std::unordered_map<int32_t /*id*/, sp<InputWindowHandle>> oldHandlesById; - for (const sp<InputWindowHandle>& handle : oldHandles) { + const std::vector<sp<WindowInfoHandle>>& oldHandles = getWindowHandlesLocked(displayId); + std::unordered_map<int32_t /*id*/, sp<WindowInfoHandle>> oldHandlesById; + for (const sp<WindowInfoHandle>& handle : oldHandles) { oldHandlesById[handle->getId()] = handle; } - std::vector<sp<InputWindowHandle>> newHandles; - for (const sp<InputWindowHandle>& handle : inputWindowHandles) { - if (!handle->updateInfo()) { - // handle no longer valid - continue; - } - - const InputWindowInfo* info = handle->getInfo(); + std::vector<sp<WindowInfoHandle>> newHandles; + for (const sp<WindowInfoHandle>& handle : windowInfoHandles) { + const WindowInfo* info = handle->getInfo(); if ((getInputChannelLocked(handle->getToken()) == nullptr && info->portalToDisplayId == ADISPLAY_ID_NONE)) { const bool noInputChannel = - info->inputFeatures.test(InputWindowInfo::Feature::NO_INPUT_CHANNEL); - const bool canReceiveInput = !info->flags.test(InputWindowInfo::Flag::NOT_TOUCHABLE) || - !info->flags.test(InputWindowInfo::Flag::NOT_FOCUSABLE); + info->inputFeatures.test(WindowInfo::Feature::NO_INPUT_CHANNEL); + const bool canReceiveInput = !info->flags.test(WindowInfo::Flag::NOT_TOUCHABLE) || + !info->flags.test(WindowInfo::Flag::NOT_FOCUSABLE); if (canReceiveInput && !noInputChannel) { ALOGV("Window handle %s has no registered input channel", handle->getName().c_str()); @@ -4460,7 +4468,7 @@ void InputDispatcher::updateWindowHandlesForDisplayLocked( if ((oldHandlesById.find(handle->getId()) != oldHandlesById.end()) && (oldHandlesById.at(handle->getId())->getToken() == handle->getToken())) { - const sp<InputWindowHandle>& oldHandle = oldHandlesById.at(handle->getId()); + const sp<WindowInfoHandle>& oldHandle = oldHandlesById.at(handle->getId()); oldHandle->updateFrom(handle); newHandles.push_back(oldHandle); } else { @@ -4473,7 +4481,7 @@ void InputDispatcher::updateWindowHandlesForDisplayLocked( } void InputDispatcher::setInputWindows( - const std::unordered_map<int32_t, std::vector<sp<InputWindowHandle>>>& handlesPerDisplay) { + const std::unordered_map<int32_t, std::vector<sp<WindowInfoHandle>>>& handlesPerDisplay) { { // acquire lock std::scoped_lock _l(mLock); for (const auto& [displayId, handles] : handlesPerDisplay) { @@ -4492,19 +4500,19 @@ void InputDispatcher::setInputWindows( * For removed handle, check if need to send a cancel event if already in touch. */ void InputDispatcher::setInputWindowsLocked( - const std::vector<sp<InputWindowHandle>>& inputWindowHandles, int32_t displayId) { + const std::vector<sp<WindowInfoHandle>>& windowInfoHandles, int32_t displayId) { if (DEBUG_FOCUS) { std::string windowList; - for (const sp<InputWindowHandle>& iwh : inputWindowHandles) { + for (const sp<WindowInfoHandle>& iwh : windowInfoHandles) { windowList += iwh->getName() + " "; } ALOGD("setInputWindows displayId=%" PRId32 " %s", displayId, windowList.c_str()); } // Ensure all tokens are null if the window has feature NO_INPUT_CHANNEL - for (const sp<InputWindowHandle>& window : inputWindowHandles) { + for (const sp<WindowInfoHandle>& window : windowInfoHandles) { const bool noInputWindow = - window->getInfo()->inputFeatures.test(InputWindowInfo::Feature::NO_INPUT_CHANNEL); + window->getInfo()->inputFeatures.test(WindowInfo::Feature::NO_INPUT_CHANNEL); if (noInputWindow && window->getToken() != nullptr) { ALOGE("%s has feature NO_INPUT_WINDOW, but a non-null token. Clearing", window->getName().c_str()); @@ -4513,18 +4521,18 @@ void InputDispatcher::setInputWindowsLocked( } // Copy old handles for release if they are no longer present. - const std::vector<sp<InputWindowHandle>> oldWindowHandles = getWindowHandlesLocked(displayId); + const std::vector<sp<WindowInfoHandle>> oldWindowHandles = getWindowHandlesLocked(displayId); // Save the old windows' orientation by ID before it gets updated. std::unordered_map<int32_t, uint32_t> oldWindowOrientations; - for (const sp<InputWindowHandle>& handle : oldWindowHandles) { + for (const sp<WindowInfoHandle>& handle : oldWindowHandles) { oldWindowOrientations.emplace(handle->getId(), handle->getInfo()->transform.getOrientation()); } - updateWindowHandlesForDisplayLocked(inputWindowHandles, displayId); + updateWindowHandlesForDisplayLocked(windowInfoHandles, displayId); - const std::vector<sp<InputWindowHandle>>& windowHandles = getWindowHandlesLocked(displayId); + const std::vector<sp<WindowInfoHandle>>& windowHandles = getWindowHandlesLocked(displayId); if (mLastHoverWindowHandle && std::find(windowHandles.begin(), windowHandles.end(), mLastHoverWindowHandle) == windowHandles.end()) { @@ -4573,8 +4581,8 @@ void InputDispatcher::setInputWindowsLocked( if (isPerWindowInputRotationEnabled()) { // Determine if the orientation of any of the input windows have changed, and cancel all // pointer events if necessary. - for (const sp<InputWindowHandle>& oldWindowHandle : oldWindowHandles) { - const sp<InputWindowHandle> newWindowHandle = getWindowHandleLocked(oldWindowHandle); + for (const sp<WindowInfoHandle>& oldWindowHandle : oldWindowHandles) { + const sp<WindowInfoHandle> newWindowHandle = getWindowHandleLocked(oldWindowHandle); if (newWindowHandle != nullptr && newWindowHandle->getInfo()->transform.getOrientation() != oldWindowOrientations[oldWindowHandle->getId()]) { @@ -4593,7 +4601,7 @@ void InputDispatcher::setInputWindowsLocked( // This ensures that unused input channels are released promptly. // Otherwise, they might stick around until the window handle is destroyed // which might not happen until the next GC. - for (const sp<InputWindowHandle>& oldWindowHandle : oldWindowHandles) { + for (const sp<WindowInfoHandle>& oldWindowHandle : oldWindowHandles) { if (getWindowHandleLocked(oldWindowHandle) == nullptr) { if (DEBUG_FOCUS) { ALOGD("Window went away: %s", oldWindowHandle->getName().c_str()); @@ -4603,7 +4611,7 @@ void InputDispatcher::setInputWindowsLocked( // check for window flags when windows are going away. // TODO(b/157929241) : delete this. This is only needed temporarily // in order to gather some data about the flag usage - if (oldWindowHandle->getInfo()->flags.test(InputWindowInfo::Flag::SLIPPERY)) { + if (oldWindowHandle->getInfo()->flags.test(WindowInfo::Flag::SLIPPERY)) { ALOGW("%s has FLAG_SLIPPERY. Please report this in b/157929241", oldWindowHandle->getName().c_str()); if (mCompatService != nullptr) { @@ -4781,6 +4789,18 @@ void InputDispatcher::setBlockUntrustedTouchesMode(BlockUntrustedTouchesMode mod mBlockUntrustedTouchesMode = mode; } +std::pair<TouchState*, TouchedWindow*> InputDispatcher::findTouchStateAndWindowLocked( + const sp<IBinder>& token) { + for (auto& [displayId, state] : mTouchStatesByDisplay) { + for (TouchedWindow& w : state.windows) { + if (w.windowHandle->getToken() == token) { + return std::make_pair(&state, &w); + } + } + } + return std::make_pair(nullptr, nullptr); +} + bool InputDispatcher::transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken, bool isDragDrop) { if (fromToken == toToken) { @@ -4793,58 +4813,43 @@ bool InputDispatcher::transferTouchFocus(const sp<IBinder>& fromToken, const sp< { // acquire lock std::scoped_lock _l(mLock); - sp<InputWindowHandle> fromWindowHandle = getWindowHandleLocked(fromToken); - sp<InputWindowHandle> toWindowHandle = getWindowHandleLocked(toToken); - if (fromWindowHandle == nullptr || toWindowHandle == nullptr) { - ALOGW("Cannot transfer focus because from or to window not found."); + // Find the target touch state and touched window by fromToken. + auto [state, touchedWindow] = findTouchStateAndWindowLocked(fromToken); + if (state == nullptr || touchedWindow == nullptr) { + ALOGD("Focus transfer failed because from window is not being touched."); return false; } - if (DEBUG_FOCUS) { - ALOGD("transferTouchFocus: fromWindowHandle=%s, toWindowHandle=%s", - fromWindowHandle->getName().c_str(), toWindowHandle->getName().c_str()); - } - if (fromWindowHandle->getInfo()->displayId != toWindowHandle->getInfo()->displayId) { - if (DEBUG_FOCUS) { - ALOGD("Cannot transfer focus because windows are on different displays."); - } + + const int32_t displayId = state->displayId; + sp<WindowInfoHandle> toWindowHandle = getWindowHandleLocked(toToken, displayId); + if (toWindowHandle == nullptr) { + ALOGW("Cannot transfer focus because to window not found."); return false; } - bool found = false; - for (std::pair<const int32_t, TouchState>& pair : mTouchStatesByDisplay) { - TouchState& state = pair.second; - for (size_t i = 0; i < state.windows.size(); i++) { - const TouchedWindow& touchedWindow = state.windows[i]; - if (touchedWindow.windowHandle == fromWindowHandle) { - int32_t oldTargetFlags = touchedWindow.targetFlags; - BitSet32 pointerIds = touchedWindow.pointerIds; - - state.windows.erase(state.windows.begin() + i); - - int32_t newTargetFlags = oldTargetFlags & - (InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_SPLIT | - InputTarget::FLAG_DISPATCH_AS_IS); - state.addOrUpdateWindow(toWindowHandle, newTargetFlags, pointerIds); + if (DEBUG_FOCUS) { + ALOGD("transferTouchFocus: fromWindowHandle=%s, toWindowHandle=%s", + touchedWindow->windowHandle->getName().c_str(), + toWindowHandle->getName().c_str()); + } - // Store the dragging window. - if (isDragDrop) { - mDragState = std::make_unique<DragState>(toWindowHandle); - } + // Erase old window. + int32_t oldTargetFlags = touchedWindow->targetFlags; + BitSet32 pointerIds = touchedWindow->pointerIds; + state->removeWindowByToken(fromToken); - found = true; - goto Found; - } - } - } - Found: + // Add new window. + int32_t newTargetFlags = oldTargetFlags & + (InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_SPLIT | + InputTarget::FLAG_DISPATCH_AS_IS); + state->addOrUpdateWindow(toWindowHandle, newTargetFlags, pointerIds); - if (!found) { - if (DEBUG_FOCUS) { - ALOGD("Focus transfer failed because from window did not have focus."); - } - return false; + // Store the dragging window. + if (isDragDrop) { + mDragState = std::make_unique<DragState>(toWindowHandle); } + // Synthesize cancel for old window and down for new window. sp<Connection> fromConnection = getConnectionLocked(fromToken); sp<Connection> toConnection = getConnectionLocked(toToken); if (fromConnection != nullptr && toConnection != nullptr) { @@ -4872,27 +4877,20 @@ bool InputDispatcher::transferTouch(const sp<IBinder>& destChannelToken) { { // acquire lock std::scoped_lock _l(mLock); - sp<InputWindowHandle> toWindowHandle = getWindowHandleLocked(destChannelToken); - if (toWindowHandle == nullptr) { - ALOGW("Could not find window associated with token=%p", destChannelToken.get()); + auto it = std::find_if(mTouchStatesByDisplay.begin(), mTouchStatesByDisplay.end(), + [](const auto& pair) { return pair.second.windows.size() == 1; }); + if (it == mTouchStatesByDisplay.end()) { + ALOGW("Cannot transfer touch state because there is no exact window being touched"); return false; } - - const int32_t displayId = toWindowHandle->getInfo()->displayId; - - auto touchStateIt = mTouchStatesByDisplay.find(displayId); - if (touchStateIt == mTouchStatesByDisplay.end()) { - ALOGD("Could not transfer touch because the display %" PRId32 " is not being touched", - displayId); + const int32_t displayId = it->first; + sp<WindowInfoHandle> toWindowHandle = getWindowHandleLocked(destChannelToken, displayId); + if (toWindowHandle == nullptr) { + ALOGW("Could not find window associated with token=%p", destChannelToken.get()); return false; } - TouchState& state = touchStateIt->second; - if (state.windows.size() != 1) { - ALOGW("Cannot transfer touch state because there are %zu windows being touched", - state.windows.size()); - return false; - } + TouchState& state = it->second; const TouchedWindow& touchedWindow = state.windows[0]; fromToken = touchedWindow.windowHandle->getToken(); } // release lock @@ -4939,7 +4937,7 @@ std::string InputDispatcher::dumpPointerCaptureStateLocked() { std::string windowName = "None"; if (mWindowTokenWithPointerCapture) { - const sp<InputWindowHandle> captureWindowHandle = + const sp<WindowInfoHandle> captureWindowHandle = getWindowHandleLocked(mWindowTokenWithPointerCapture); windowName = captureWindowHandle ? captureWindowHandle->getName().c_str() : "token has capture without window"; @@ -4995,7 +4993,7 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { if (!state.portalWindows.empty()) { dump += INDENT3 "Portal windows:\n"; for (size_t i = 0; i < state.portalWindows.size(); i++) { - const sp<InputWindowHandle> portalWindowHandle = state.portalWindows[i]; + const sp<WindowInfoHandle> portalWindowHandle = state.portalWindows[i]; dump += StringPrintf(INDENT4 "%zu: name='%s'\n", i, portalWindowHandle->getName().c_str()); } @@ -5012,13 +5010,13 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { if (!mWindowHandlesByDisplay.empty()) { for (auto& it : mWindowHandlesByDisplay) { - const std::vector<sp<InputWindowHandle>> windowHandles = it.second; + const std::vector<sp<WindowInfoHandle>> windowHandles = it.second; dump += StringPrintf(INDENT "Display: %" PRId32 "\n", it.first); if (!windowHandles.empty()) { dump += INDENT2 "Windows:\n"; for (size_t i = 0; i < windowHandles.size(); i++) { - const sp<InputWindowHandle>& windowHandle = windowHandles[i]; - const InputWindowInfo* windowInfo = windowHandle->getInfo(); + const sp<WindowInfoHandle>& windowHandle = windowHandles[i]; + const WindowInfo* windowInfo = windowHandle->getInfo(); dump += StringPrintf(INDENT3 "%zu: name='%s', id=%" PRId32 ", displayId=%d, " "portalToDisplayId=%d, paused=%s, focusable=%s, " @@ -5046,12 +5044,13 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { windowInfo->inputFeatures.string().c_str()); dump += StringPrintf(", ownerPid=%d, ownerUid=%d, dispatchingTimeout=%" PRId64 "ms, trustedOverlay=%s, hasToken=%s, " - "touchOcclusionMode=%s\n", + "touchOcclusionMode=%s, displayOrientation=%d\n", windowInfo->ownerPid, windowInfo->ownerUid, millis(windowInfo->dispatchingTimeout), toString(windowInfo->trustedOverlay), toString(windowInfo->token != nullptr), - toString(windowInfo->touchOcclusionMode).c_str()); + toString(windowInfo->touchOcclusionMode).c_str(), + windowInfo->displayOrientation); windowInfo->transform.dump(dump, "transform", INDENT4); } } else { @@ -5399,7 +5398,7 @@ void InputDispatcher::requestPointerCapture(const sp<IBinder>& windowToken, bool { // acquire lock std::scoped_lock _l(mLock); if (DEBUG_FOCUS) { - const sp<InputWindowHandle> windowHandle = getWindowHandleLocked(windowToken); + const sp<WindowInfoHandle> windowHandle = getWindowHandleLocked(windowToken); ALOGI("Request to %s Pointer Capture from: %s.", enabled ? "enable" : "disable", windowHandle != nullptr ? windowHandle->getName().c_str() : "token without window"); @@ -5570,7 +5569,7 @@ void InputDispatcher::onUntrustedTouchLocked(const std::string& obscuringPackage postCommandLocked(std::move(commandEntry)); } -void InputDispatcher::updateLastAnrStateLocked(const sp<InputWindowHandle>& window, +void InputDispatcher::updateLastAnrStateLocked(const sp<WindowInfoHandle>& window, const std::string& reason) { const std::string windowLabel = getApplicationWindowLabel(nullptr, window); updateLastAnrStateLocked(windowLabel, reason); @@ -6237,4 +6236,16 @@ void InputDispatcher::displayRemoved(int32_t displayId) { mLooper->wake(); } +void InputDispatcher::onWindowInfosChanged(const std::vector<gui::WindowInfo>& windowInfos) { + // The listener sends the windows as a flattened array. Separate the windows by display for + // more convenient parsing. + std::unordered_map<int32_t, std::vector<sp<WindowInfoHandle>>> handlesPerDisplay; + + for (const auto& info : windowInfos) { + handlesPerDisplay.emplace(info.displayId, std::vector<sp<WindowInfoHandle>>()); + handlesPerDisplay[info.displayId].push_back(new WindowInfoHandle(info)); + } + setInputWindows(handlesPerDisplay); +} + } // namespace android::inputdispatcher diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h index 9edf41c9c0..1aa78d9c90 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.h +++ b/services/inputflinger/dispatcher/InputDispatcher.h @@ -37,10 +37,10 @@ #include <attestation/HmacKeyManager.h> #include <com/android/internal/compat/IPlatformCompatNative.h> +#include <gui/InputApplication.h> +#include <gui/WindowInfo.h> #include <input/Input.h> -#include <input/InputApplication.h> #include <input/InputTransport.h> -#include <input/InputWindow.h> #include <limits.h> #include <stddef.h> #include <ui/Region.h> @@ -58,6 +58,7 @@ #include <InputListener.h> #include <InputReporterInterface.h> +#include <gui/WindowInfosListener.h> namespace android::inputdispatcher { @@ -80,7 +81,7 @@ class Connection; * * A 'LockedInterruptible' method may called a 'Locked' method, but NOT vice-versa. */ -class InputDispatcher : public android::InputDispatcherInterface { +class InputDispatcher : public android::InputDispatcherInterface, public gui::WindowInfosListener { protected: ~InputDispatcher() override; @@ -109,8 +110,9 @@ public: std::unique_ptr<VerifiedInputEvent> verifyInputEvent(const InputEvent& event) override; - void setInputWindows(const std::unordered_map<int32_t, std::vector<sp<InputWindowHandle>>>& - handlesPerDisplay) override; + void setInputWindows( + const std::unordered_map<int32_t, std::vector<sp<android::gui::WindowInfoHandle>>>& + handlesPerDisplay) override; void setFocusedApplication( int32_t displayId, const std::shared_ptr<InputApplicationHandle>& inputApplicationHandle) override; @@ -127,7 +129,7 @@ public: base::Result<std::unique_ptr<InputChannel>> createInputChannel( const std::string& name) override; - void setFocusedWindow(const FocusRequest&) override; + void setFocusedWindow(const android::gui::FocusRequest&) override; base::Result<std::unique_ptr<InputChannel>> createInputMonitor(int32_t displayId, bool isGestureMonitor, const std::string& name, @@ -141,6 +143,8 @@ public: void displayRemoved(int32_t displayId) override; + void onWindowInfosChanged(const std::vector<gui::WindowInfo>& windowInfos) override; + private: enum class DropReason { NOT_DROPPED, @@ -190,8 +194,8 @@ private: void enqueueFocusEventLocked(const sp<IBinder>& windowToken, bool hasFocus, const std::string& reason) REQUIRES(mLock); // Enqueues a drag event. - void enqueueDragEventLocked(const sp<InputWindowHandle>& windowToken, bool isExiting, - const MotionEntry& motionEntry) REQUIRES(mLock); + void enqueueDragEventLocked(const sp<android::gui::WindowInfoHandle>& windowToken, + bool isExiting, const MotionEntry& motionEntry) REQUIRES(mLock); // Adds an event to a queue of recent events for debugging purposes. void addRecentEventLocked(std::shared_ptr<EventEntry> entry) REQUIRES(mLock); @@ -208,11 +212,12 @@ private: // to transfer focus to a new application. std::shared_ptr<EventEntry> mNextUnblockedEvent GUARDED_BY(mLock); - sp<InputWindowHandle> findTouchedWindowAtLocked(int32_t displayId, int32_t x, int32_t y, - TouchState* touchState, - bool addOutsideTargets = false, - bool addPortalWindows = false, - bool ignoreDragWindow = false) REQUIRES(mLock); + sp<android::gui::WindowInfoHandle> findTouchedWindowAtLocked(int32_t displayId, int32_t x, + int32_t y, TouchState* touchState, + bool addOutsideTargets = false, + bool addPortalWindows = false, + bool ignoreDragWindow = false) + REQUIRES(mLock); sp<Connection> getConnectionLocked(const sp<IBinder>& inputConnectionToken) const REQUIRES(mLock); @@ -314,33 +319,36 @@ private: float mMaximumObscuringOpacityForTouch GUARDED_BY(mLock); android::os::BlockUntrustedTouchesMode mBlockUntrustedTouchesMode GUARDED_BY(mLock); - std::unordered_map<int32_t, std::vector<sp<InputWindowHandle>>> mWindowHandlesByDisplay - GUARDED_BY(mLock); - void setInputWindowsLocked(const std::vector<sp<InputWindowHandle>>& inputWindowHandles, - int32_t displayId) REQUIRES(mLock); + std::unordered_map<int32_t, std::vector<sp<android::gui::WindowInfoHandle>>> + mWindowHandlesByDisplay GUARDED_BY(mLock); + void setInputWindowsLocked( + const std::vector<sp<android::gui::WindowInfoHandle>>& inputWindowHandles, + int32_t displayId) REQUIRES(mLock); // Get a reference to window handles by display, return an empty vector if not found. - const std::vector<sp<InputWindowHandle>>& getWindowHandlesLocked(int32_t displayId) const - REQUIRES(mLock); - sp<InputWindowHandle> getWindowHandleLocked(const sp<IBinder>& windowHandleToken) const - REQUIRES(mLock); + const std::vector<sp<android::gui::WindowInfoHandle>>& getWindowHandlesLocked( + int32_t displayId) const REQUIRES(mLock); + sp<android::gui::WindowInfoHandle> getWindowHandleLocked( + const sp<IBinder>& windowHandleToken) const REQUIRES(mLock); // Same function as above, but faster. Since displayId is provided, this avoids the need // to loop through all displays. - sp<InputWindowHandle> getWindowHandleLocked(const sp<IBinder>& windowHandleToken, - int displayId) const REQUIRES(mLock); - sp<InputWindowHandle> getWindowHandleLocked(const sp<InputWindowHandle>& windowHandle) const - REQUIRES(mLock); + sp<android::gui::WindowInfoHandle> getWindowHandleLocked(const sp<IBinder>& windowHandleToken, + int displayId) const REQUIRES(mLock); + sp<android::gui::WindowInfoHandle> getWindowHandleLocked( + const sp<android::gui::WindowInfoHandle>& windowHandle) const REQUIRES(mLock); std::shared_ptr<InputChannel> getInputChannelLocked(const sp<IBinder>& windowToken) const REQUIRES(mLock); - sp<InputWindowHandle> getFocusedWindowHandleLocked(int displayId) const REQUIRES(mLock); - bool hasResponsiveConnectionLocked(InputWindowHandle& windowHandle) const REQUIRES(mLock); + sp<android::gui::WindowInfoHandle> getFocusedWindowHandleLocked(int displayId) const + REQUIRES(mLock); + bool hasResponsiveConnectionLocked(android::gui::WindowInfoHandle& windowHandle) const + REQUIRES(mLock); /* * Validate and update InputWindowHandles for a given display. */ void updateWindowHandlesForDisplayLocked( - const std::vector<sp<InputWindowHandle>>& inputWindowHandles, int32_t displayId) - REQUIRES(mLock); + const std::vector<sp<android::gui::WindowInfoHandle>>& inputWindowHandles, + int32_t displayId) REQUIRES(mLock); std::unordered_map<int32_t, TouchState> mTouchStatesByDisplay GUARDED_BY(mLock); std::unique_ptr<DragState> mDragState GUARDED_BY(mLock); @@ -471,7 +479,7 @@ private: AnrTracker mAnrTracker GUARDED_BY(mLock); // Contains the last window which received a hover event. - sp<InputWindowHandle> mLastHoverWindowHandle GUARDED_BY(mLock); + sp<android::gui::WindowInfoHandle> mLastHoverWindowHandle GUARDED_BY(mLock); void cancelEventsForAnrLocked(const sp<Connection>& connection) REQUIRES(mLock); nsecs_t getTimeSpentWaitingForApplicationLocked(nsecs_t currentTime) REQUIRES(mLock); @@ -490,20 +498,21 @@ private: nsecs_t currentTime, const MotionEntry& entry, std::vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime, bool* outConflictingPointerActions) REQUIRES(mLock); std::vector<TouchedMonitor> findTouchedGestureMonitorsLocked( - int32_t displayId, const std::vector<sp<InputWindowHandle>>& portalWindows) const + int32_t displayId, + const std::vector<sp<android::gui::WindowInfoHandle>>& portalWindows) const REQUIRES(mLock); std::vector<TouchedMonitor> selectResponsiveMonitorsLocked( const std::vector<TouchedMonitor>& gestureMonitors) const REQUIRES(mLock); - void addWindowTargetLocked(const sp<InputWindowHandle>& windowHandle, int32_t targetFlags, - BitSet32 pointerIds, std::vector<InputTarget>& inputTargets) - REQUIRES(mLock); + void addWindowTargetLocked(const sp<android::gui::WindowInfoHandle>& windowHandle, + int32_t targetFlags, BitSet32 pointerIds, + std::vector<InputTarget>& inputTargets) REQUIRES(mLock); void addMonitoringTargetLocked(const Monitor& monitor, float xOffset, float yOffset, std::vector<InputTarget>& inputTargets) REQUIRES(mLock); void addGlobalMonitoringTargetsLocked(std::vector<InputTarget>& inputTargets, int32_t displayId, float xOffset = 0, float yOffset = 0) REQUIRES(mLock); void pokeUserActivityLocked(const EventEntry& eventEntry) REQUIRES(mLock); - bool checkInjectionPermission(const sp<InputWindowHandle>& windowHandle, + bool checkInjectionPermission(const sp<android::gui::WindowInfoHandle>& windowHandle, const InjectionState* injectionState); // Enqueue a drag event if needed, and update the touch state. // Uses findTouchedWindowTargetsLocked to make the decision @@ -518,15 +527,18 @@ private: std::vector<std::string> debugInfo; }; - TouchOcclusionInfo computeTouchOcclusionInfoLocked(const sp<InputWindowHandle>& windowHandle, - int32_t x, int32_t y) const REQUIRES(mLock); + TouchOcclusionInfo computeTouchOcclusionInfoLocked( + const sp<android::gui::WindowInfoHandle>& windowHandle, int32_t x, int32_t y) const + REQUIRES(mLock); bool isTouchTrustedLocked(const TouchOcclusionInfo& occlusionInfo) const REQUIRES(mLock); - bool isWindowObscuredAtPointLocked(const sp<InputWindowHandle>& windowHandle, int32_t x, - int32_t y) const REQUIRES(mLock); - bool isWindowObscuredLocked(const sp<InputWindowHandle>& windowHandle) const REQUIRES(mLock); - std::string dumpWindowForTouchOcclusion(const InputWindowInfo* info, bool isTouchWindow) const; + bool isWindowObscuredAtPointLocked(const sp<android::gui::WindowInfoHandle>& windowHandle, + int32_t x, int32_t y) const REQUIRES(mLock); + bool isWindowObscuredLocked(const sp<android::gui::WindowInfoHandle>& windowHandle) const + REQUIRES(mLock); + std::string dumpWindowForTouchOcclusion(const android::gui::WindowInfo* info, + bool isTouchWindow) const; std::string getApplicationWindowLabel(const InputApplicationHandle* applicationHandle, - const sp<InputWindowHandle>& windowHandle); + const sp<android::gui::WindowInfoHandle>& windowHandle); // Manage the dispatch cycle for a single connection. // These methods are deliberately not Interruptible because doing all of the work @@ -605,8 +617,8 @@ private: void onAnrLocked(const sp<Connection>& connection) REQUIRES(mLock); void onAnrLocked(std::shared_ptr<InputApplicationHandle> application) REQUIRES(mLock); void onUntrustedTouchLocked(const std::string& obscuringPackage) REQUIRES(mLock); - void updateLastAnrStateLocked(const sp<InputWindowHandle>& window, const std::string& reason) - REQUIRES(mLock); + void updateLastAnrStateLocked(const sp<android::gui::WindowInfoHandle>& window, + const std::string& reason) REQUIRES(mLock); void updateLastAnrStateLocked(const InputApplicationHandle& application, const std::string& reason) REQUIRES(mLock); void updateLastAnrStateLocked(const std::string& windowLabel, const std::string& reason) @@ -641,6 +653,10 @@ private: void doPokeUserActivityLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock); void doOnPointerDownOutsideFocusLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock); + // Find touched state and touched window by token. + std::pair<TouchState*, TouchedWindow*> findTouchStateAndWindowLocked(const sp<IBinder>& token) + REQUIRES(mLock); + // Statistics gathering. LatencyAggregator mLatencyAggregator GUARDED_BY(mLock); LatencyTracker mLatencyTracker GUARDED_BY(mLock); @@ -650,6 +666,8 @@ private: sp<InputReporterInterface> mReporter; sp<com::android::internal::compat::IPlatformCompatNative> mCompatService; + + void onFirstRef() override; }; } // namespace android::inputdispatcher diff --git a/services/inputflinger/dispatcher/InputTarget.h b/services/inputflinger/dispatcher/InputTarget.h index 1c4980b302..7c463c8697 100644 --- a/services/inputflinger/dispatcher/InputTarget.h +++ b/services/inputflinger/dispatcher/InputTarget.h @@ -17,6 +17,7 @@ #ifndef _UI_INPUT_INPUTDISPATCHER_INPUTTARGET_H #define _UI_INPUT_INPUTDISPATCHER_INPUTTARGET_H +#include <gui/constants.h> #include <input/InputTransport.h> #include <ui/Transform.h> #include <utils/BitSet.h> @@ -100,8 +101,11 @@ struct InputTarget { // (ignored for KeyEvents) float globalScaleFactor = 1.0f; + // Current display orientation + uint32_t displayOrientation = ui::Transform::ROT_0; + // Display-size in its natural rotation. Used for compatibility transform of raw coordinates. - int2 displaySize = {AMOTION_EVENT_INVALID_DISPLAY_SIZE, AMOTION_EVENT_INVALID_DISPLAY_SIZE}; + int2 displaySize = {INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE}; // The subset of pointer ids to include in motion events dispatched to this input target // if FLAG_SPLIT is set. diff --git a/services/inputflinger/dispatcher/TouchState.cpp b/services/inputflinger/dispatcher/TouchState.cpp index 81b3cf025b..20b6eadf5b 100644 --- a/services/inputflinger/dispatcher/TouchState.cpp +++ b/services/inputflinger/dispatcher/TouchState.cpp @@ -14,13 +14,14 @@ * limitations under the License. */ -#include <input/InputWindow.h> +#include <gui/WindowInfo.h> #include "InputTarget.h" #include "TouchState.h" -using android::InputWindowHandle; +using android::gui::WindowInfo; +using android::gui::WindowInfoHandle; namespace android::inputdispatcher { @@ -51,7 +52,7 @@ void TouchState::copyFrom(const TouchState& other) { gestureMonitors = other.gestureMonitors; } -void TouchState::addOrUpdateWindow(const sp<InputWindowHandle>& windowHandle, int32_t targetFlags, +void TouchState::addOrUpdateWindow(const sp<WindowInfoHandle>& windowHandle, int32_t targetFlags, BitSet32 pointerIds) { if (targetFlags & InputTarget::FLAG_SPLIT) { split = true; @@ -76,7 +77,7 @@ void TouchState::addOrUpdateWindow(const sp<InputWindowHandle>& windowHandle, in windows.push_back(touchedWindow); } -void TouchState::addPortalWindow(const sp<InputWindowHandle>& windowHandle) { +void TouchState::addPortalWindow(const sp<android::gui::WindowInfoHandle>& windowHandle) { size_t numWindows = portalWindows.size(); for (size_t i = 0; i < numWindows; i++) { if (portalWindows[i] == windowHandle) { @@ -121,7 +122,7 @@ void TouchState::filterNonMonitors() { portalWindows.clear(); } -sp<InputWindowHandle> TouchState::getFirstForegroundWindowHandle() const { +sp<WindowInfoHandle> TouchState::getFirstForegroundWindowHandle() const { for (size_t i = 0; i < windows.size(); i++) { const TouchedWindow& window = windows[i]; if (window.targetFlags & InputTarget::FLAG_FOREGROUND) { @@ -137,7 +138,7 @@ bool TouchState::isSlippery() const { for (const TouchedWindow& window : windows) { if (window.targetFlags & InputTarget::FLAG_FOREGROUND) { if (haveSlipperyForegroundWindow || - !window.windowHandle->getInfo()->flags.test(InputWindowInfo::Flag::SLIPPERY)) { + !window.windowHandle->getInfo()->flags.test(WindowInfo::Flag::SLIPPERY)) { return false; } haveSlipperyForegroundWindow = true; diff --git a/services/inputflinger/dispatcher/TouchState.h b/services/inputflinger/dispatcher/TouchState.h index 623c6a824f..a4e52b0d83 100644 --- a/services/inputflinger/dispatcher/TouchState.h +++ b/services/inputflinger/dispatcher/TouchState.h @@ -22,7 +22,9 @@ namespace android { -class InputWindowHandle; +namespace gui { +class WindowInfoHandle; +} namespace inputdispatcher { @@ -37,7 +39,7 @@ struct TouchState { // This collects the portal windows that the touch has gone through. Each portal window // targets a display (embedded display for most cases). With this info, we can add the // monitoring channels of the displays touched. - std::vector<sp<android::InputWindowHandle>> portalWindows; + std::vector<sp<android::gui::WindowInfoHandle>> portalWindows; std::vector<TouchedMonitor> gestureMonitors; @@ -45,14 +47,14 @@ struct TouchState { ~TouchState(); void reset(); void copyFrom(const TouchState& other); - void addOrUpdateWindow(const sp<android::InputWindowHandle>& windowHandle, int32_t targetFlags, - BitSet32 pointerIds); - void addPortalWindow(const sp<android::InputWindowHandle>& windowHandle); + void addOrUpdateWindow(const sp<android::gui::WindowInfoHandle>& windowHandle, + int32_t targetFlags, BitSet32 pointerIds); + void addPortalWindow(const sp<android::gui::WindowInfoHandle>& windowHandle); void addGestureMonitors(const std::vector<TouchedMonitor>& monitors); void removeWindowByToken(const sp<IBinder>& token); void filterNonAsIsTouchWindows(); void filterNonMonitors(); - sp<InputWindowHandle> getFirstForegroundWindowHandle() const; + sp<android::gui::WindowInfoHandle> getFirstForegroundWindowHandle() const; bool isSlippery() const; }; diff --git a/services/inputflinger/dispatcher/TouchedWindow.h b/services/inputflinger/dispatcher/TouchedWindow.h index 8713aa3f56..4c31ec3acd 100644 --- a/services/inputflinger/dispatcher/TouchedWindow.h +++ b/services/inputflinger/dispatcher/TouchedWindow.h @@ -19,13 +19,15 @@ namespace android { -class InputWindowHandle; +namespace gui { +class WindowInfoHandle; +} namespace inputdispatcher { // Focus tracking for touch. struct TouchedWindow { - sp<android::InputWindowHandle> windowHandle; + sp<gui::WindowInfoHandle> windowHandle; int32_t targetFlags; BitSet32 pointerIds; // zero unless target flag FLAG_SPLIT is set }; diff --git a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h index 43428a0130..a7dccf0d19 100644 --- a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h +++ b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h @@ -19,18 +19,16 @@ #include <InputListener.h> #include <android-base/result.h> -#include <android/FocusRequest.h> +#include <android/gui/FocusRequest.h> #include <android/os/BlockUntrustedTouchesMode.h> -#include <android/os/ISetInputWindowsListener.h> #include <android/os/InputEventInjectionResult.h> #include <android/os/InputEventInjectionSync.h> -#include <input/InputApplication.h> +#include <gui/InputApplication.h> +#include <gui/WindowInfo.h> #include <input/InputDevice.h> #include <input/InputTransport.h> -#include <input/InputWindow.h> #include <unordered_map> - namespace android { /* Notifies the system about input events generated by the input reader. @@ -91,7 +89,7 @@ public: * This method may be called on any thread (usually by the input manager). */ virtual void setInputWindows( - const std::unordered_map<int32_t, std::vector<sp<InputWindowHandle>>>& + const std::unordered_map<int32_t, std::vector<sp<gui::WindowInfoHandle>>>& handlesPerDisplay) = 0; /* Sets the focused application on the given display. @@ -162,7 +160,7 @@ public: /** * Sets focus on the specified window. */ - virtual void setFocusedWindow(const FocusRequest&) = 0; + virtual void setFocusedWindow(const gui::FocusRequest&) = 0; /** * Creates an input channel that may be used as targets for input events. diff --git a/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h index 219f45a7c3..ebfcbe17b2 100644 --- a/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h +++ b/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h @@ -20,8 +20,8 @@ #include "InputDispatcherConfiguration.h" #include <binder/IBinder.h> +#include <gui/InputApplication.h> #include <input/Input.h> -#include <input/InputApplication.h> #include <utils/RefBase.h> namespace android { diff --git a/services/inputflinger/host/InputFlinger.h b/services/inputflinger/host/InputFlinger.h index 8112038b16..3cf1b2b797 100644 --- a/services/inputflinger/host/InputFlinger.h +++ b/services/inputflinger/host/InputFlinger.h @@ -23,15 +23,14 @@ #include "InputHost.h" #include <android/os/BnInputFlinger.h> -#include <android/os/ISetInputWindowsListener.h> #include <binder/Binder.h> #include <cutils/compiler.h> #include <utils/String16.h> #include <utils/String8.h> #include <utils/StrongPointer.h> +using android::gui::FocusRequest; using android::os::BnInputFlinger; -using android::os::ISetInputWindowsListener; namespace android { @@ -44,10 +43,6 @@ public: InputFlinger() ANDROID_API; status_t dump(int fd, const Vector<String16>& args) override; - binder::Status setInputWindows(const std::vector<InputWindowInfo>&, - const sp<ISetInputWindowsListener>&) override { - return binder::Status::ok(); - } binder::Status createInputChannel(const std::string&, InputChannel*) override { return binder::Status::ok(); } diff --git a/services/inputflinger/reader/Android.bp b/services/inputflinger/reader/Android.bp index 7db32e3071..ee7b392bcd 100644 --- a/services/inputflinger/reader/Android.bp +++ b/services/inputflinger/reader/Android.bp @@ -71,6 +71,7 @@ cc_defaults { "libstatslog", "libui", "libutils", + "InputFlingerProperties", ], static_libs: [ "libc++fs", diff --git a/services/inputflinger/reader/InputDevice.cpp b/services/inputflinger/reader/InputDevice.cpp index 7af014cb34..1e9ec54d5d 100644 --- a/services/inputflinger/reader/InputDevice.cpp +++ b/services/inputflinger/reader/InputDevice.cpp @@ -18,7 +18,7 @@ #include "InputDevice.h" -#include <input/Flags.h> +#include <ftl/Flags.h> #include <algorithm> #include "CursorInputMapper.h" diff --git a/services/inputflinger/reader/controller/PeripheralController.cpp b/services/inputflinger/reader/controller/PeripheralController.cpp index 16251ee0ca..9c8a29a059 100644 --- a/services/inputflinger/reader/controller/PeripheralController.cpp +++ b/services/inputflinger/reader/controller/PeripheralController.cpp @@ -19,8 +19,8 @@ #include "../Macros.h" +#include <ftl/NamedEnum.h> #include "PeripheralController.h" -#include "input/NamedEnum.h" // Log detailed debug messages about input device lights. static constexpr bool DEBUG_LIGHT_DETAILS = false; diff --git a/services/inputflinger/reader/include/EventHub.h b/services/inputflinger/reader/include/EventHub.h index d88b1bd704..3c3f88e36e 100644 --- a/services/inputflinger/reader/include/EventHub.h +++ b/services/inputflinger/reader/include/EventHub.h @@ -22,7 +22,7 @@ #include <unordered_map> #include <vector> -#include <input/Flags.h> +#include <ftl/Flags.h> #include <filesystem> #include <batteryservice/BatteryService.h> diff --git a/services/inputflinger/reader/include/InputDevice.h b/services/inputflinger/reader/include/InputDevice.h index 2f2eba78b1..f32472d37b 100644 --- a/services/inputflinger/reader/include/InputDevice.h +++ b/services/inputflinger/reader/include/InputDevice.h @@ -17,8 +17,8 @@ #ifndef _UI_INPUTREADER_INPUT_DEVICE_H #define _UI_INPUTREADER_INPUT_DEVICE_H +#include <ftl/Flags.h> #include <input/DisplayViewport.h> -#include <input/Flags.h> #include <input/InputDevice.h> #include <input/PropertyMap.h> #include <stdint.h> diff --git a/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h b/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h index da0fea4616..7347b2cec4 100644 --- a/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h +++ b/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h @@ -17,7 +17,7 @@ #ifndef _UI_INPUTREADER_TOUCH_CURSOR_INPUT_MAPPER_COMMON_H #define _UI_INPUTREADER_TOUCH_CURSOR_INPUT_MAPPER_COMMON_H -#include <android-base/properties.h> +#include <InputFlingerProperties.sysprop.h> #include <input/DisplayViewport.h> #include <stdint.h> @@ -33,9 +33,7 @@ namespace android { // projection are part of the input window's transform. This means InputReader should work in the // un-rotated coordinate space. static bool isPerWindowInputRotationEnabled() { - static const bool PER_WINDOW_INPUT_ROTATION = - base::GetBoolProperty("persist.debug.per_window_input_rotation", false); - return PER_WINDOW_INPUT_ROTATION; + return sysprop::InputFlingerProperties::per_window_input_rotation().value_or(false); } static int32_t getInverseRotation(int32_t orientation) { diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp index f45731527f..b63aed7d9b 100644 --- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp +++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp @@ -18,7 +18,7 @@ #include "../Macros.h" // clang-format on -#include <input/NamedEnum.h> +#include <ftl/NamedEnum.h> #include "TouchInputMapper.h" #include "CursorButtonAccumulator.h" @@ -470,6 +470,23 @@ void TouchInputMapper::configureParameters() { getDeviceContext().getConfiguration().tryGetProperty(String8("touch.orientationAware"), mParameters.orientationAware); + mParameters.orientation = Parameters::Orientation::ORIENTATION_0; + String8 orientationString; + if (getDeviceContext().getConfiguration().tryGetProperty(String8("touch.orientation"), + orientationString)) { + if (mParameters.deviceType != Parameters::DeviceType::TOUCH_SCREEN) { + ALOGW("The configuration 'touch.orientation' is only supported for touchscreens."); + } else if (orientationString == "ORIENTATION_90") { + mParameters.orientation = Parameters::Orientation::ORIENTATION_90; + } else if (orientationString == "ORIENTATION_180") { + mParameters.orientation = Parameters::Orientation::ORIENTATION_180; + } else if (orientationString == "ORIENTATION_270") { + mParameters.orientation = Parameters::Orientation::ORIENTATION_270; + } else if (orientationString != "ORIENTATION_0") { + ALOGW("Invalid value for touch.orientation: '%s'", orientationString.string()); + } + } + mParameters.hasAssociatedDisplay = false; mParameters.associatedDisplayIsExternal = false; if (mParameters.orientationAware || @@ -508,6 +525,7 @@ void TouchInputMapper::dumpParameters(std::string& dump) { toString(mParameters.associatedDisplayIsExternal), mParameters.uniqueDisplayId.c_str()); dump += StringPrintf(INDENT4 "OrientationAware: %s\n", toString(mParameters.orientationAware)); + dump += INDENT4 "Orientation: " + NamedEnum::string(mParameters.orientation) + "\n"; } void TouchInputMapper::configureRawPointerAxes() { @@ -669,7 +687,13 @@ void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) { int32_t naturalPhysicalWidth, naturalPhysicalHeight; int32_t naturalPhysicalLeft, naturalPhysicalTop; int32_t naturalDeviceWidth, naturalDeviceHeight; - switch (mViewport.orientation) { + + // Apply the inverse of the input device orientation so that the surface is configured + // in the same orientation as the device. The input device orientation will be + // re-applied to mSurfaceOrientation. + const int32_t naturalSurfaceOrientation = + (mViewport.orientation - static_cast<int32_t>(mParameters.orientation) + 4) % 4; + switch (naturalSurfaceOrientation) { case DISPLAY_ORIENTATION_90: naturalLogicalWidth = mViewport.logicalBottom - mViewport.logicalTop; naturalLogicalHeight = mViewport.logicalRight - mViewport.logicalLeft; @@ -752,6 +776,10 @@ void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) { mSurfaceOrientation = mParameters.orientationAware ? mViewport.orientation : DISPLAY_ORIENTATION_0; } + + // Apply the input device orientation for the device. + mSurfaceOrientation = + (mSurfaceOrientation + static_cast<int32_t>(mParameters.orientation)) % 4; } else { mPhysicalWidth = rawWidth; mPhysicalHeight = rawHeight; diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.h b/services/inputflinger/reader/mapper/TouchInputMapper.h index 920f8428f3..e104220e47 100644 --- a/services/inputflinger/reader/mapper/TouchInputMapper.h +++ b/services/inputflinger/reader/mapper/TouchInputMapper.h @@ -204,6 +204,15 @@ protected: bool hasAssociatedDisplay; bool associatedDisplayIsExternal; bool orientationAware; + + enum class Orientation : int32_t { + ORIENTATION_0 = DISPLAY_ORIENTATION_0, + ORIENTATION_90 = DISPLAY_ORIENTATION_90, + ORIENTATION_180 = DISPLAY_ORIENTATION_180, + ORIENTATION_270 = DISPLAY_ORIENTATION_270, + }; + Orientation orientation; + bool hasButtonUnderPad; std::string uniqueDisplayId; diff --git a/services/inputflinger/sysprop/Android.bp b/services/inputflinger/sysprop/Android.bp new file mode 100644 index 0000000000..b9d65ee246 --- /dev/null +++ b/services/inputflinger/sysprop/Android.bp @@ -0,0 +1,15 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + +sysprop_library { + name: "InputFlingerProperties", + srcs: ["*.sysprop"], + api_packages: ["android.sysprop"], + property_owner: "Platform", +} diff --git a/services/inputflinger/sysprop/InputFlingerProperties.sysprop b/services/inputflinger/sysprop/InputFlingerProperties.sysprop new file mode 100644 index 0000000000..1c7e724332 --- /dev/null +++ b/services/inputflinger/sysprop/InputFlingerProperties.sysprop @@ -0,0 +1,27 @@ +# Copyright (C) 2021 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. + +module: "android.sysprop.InputFlingerProperties" +owner: Platform + +# When per-window-input-rotation is enabled, InputReader works in the un-rotated +# display coordinate space, and the display rotation is encoded as part of the +# input window transform that is sent from SurfaceFlinger to InputDispatcher. +prop { + api_name: "per_window_input_rotation" + type: Boolean + scope: Internal + access: ReadWrite + prop_name: "persist.debug.per_window_input_rotation" +} diff --git a/services/inputflinger/tests/Android.bp b/services/inputflinger/tests/Android.bp index 918e1bef7a..e68692474d 100644 --- a/services/inputflinger/tests/Android.bp +++ b/services/inputflinger/tests/Android.bp @@ -52,6 +52,7 @@ cc_test { ], aidl: { include_dirs: [ + "frameworks/native/libs/gui", "frameworks/native/libs/input", ], }, diff --git a/services/inputflinger/tests/FocusResolver_test.cpp b/services/inputflinger/tests/FocusResolver_test.cpp index 9051ff12c2..662be8063e 100644 --- a/services/inputflinger/tests/FocusResolver_test.cpp +++ b/services/inputflinger/tests/FocusResolver_test.cpp @@ -26,9 +26,12 @@ // atest inputflinger_tests:FocusResolverTest +using android::gui::FocusRequest; +using android::gui::WindowInfoHandle; + namespace android::inputdispatcher { -class FakeWindowHandle : public InputWindowHandle { +class FakeWindowHandle : public WindowInfoHandle { public: FakeWindowHandle(const std::string& name, const sp<IBinder>& token, bool focusable, bool visible) { @@ -38,7 +41,6 @@ public: mInfo.focusable = focusable; } - bool updateInfo() { return true; } void setFocusable(bool focusable) { mInfo.focusable = focusable; } void setVisible(bool visible) { mInfo.visible = visible; } }; @@ -47,7 +49,7 @@ TEST(FocusResolverTest, SetFocusedWindow) { sp<IBinder> focusableWindowToken = new BBinder(); sp<IBinder> invisibleWindowToken = new BBinder(); sp<IBinder> unfocusableWindowToken = new BBinder(); - std::vector<sp<InputWindowHandle>> windows; + std::vector<sp<WindowInfoHandle>> windows; windows.push_back(new FakeWindowHandle("Focusable", focusableWindowToken, true /* focusable */, true /* visible */)); windows.push_back(new FakeWindowHandle("Invisible", invisibleWindowToken, true /* focusable */, @@ -82,7 +84,7 @@ TEST(FocusResolverTest, SetFocusedMirroredWindow) { sp<IBinder> focusableWindowToken = new BBinder(); sp<IBinder> invisibleWindowToken = new BBinder(); sp<IBinder> unfocusableWindowToken = new BBinder(); - std::vector<sp<InputWindowHandle>> windows; + std::vector<sp<WindowInfoHandle>> windows; windows.push_back(new FakeWindowHandle("Mirror1", focusableWindowToken, true /* focusable */, true /* visible */)); windows.push_back(new FakeWindowHandle("Mirror1", focusableWindowToken, true /* focusable */, @@ -120,7 +122,7 @@ TEST(FocusResolverTest, SetFocusedMirroredWindow) { TEST(FocusResolverTest, SetInputWindows) { sp<IBinder> focusableWindowToken = new BBinder(); - std::vector<sp<InputWindowHandle>> windows; + std::vector<sp<WindowInfoHandle>> windows; sp<FakeWindowHandle> window = new FakeWindowHandle("Focusable", focusableWindowToken, true /* focusable */, true /* visible */); windows.push_back(window); @@ -142,7 +144,7 @@ TEST(FocusResolverTest, SetInputWindows) { TEST(FocusResolverTest, FocusRequestsCanBePending) { sp<IBinder> invisibleWindowToken = new BBinder(); - std::vector<sp<InputWindowHandle>> windows; + std::vector<sp<WindowInfoHandle>> windows; sp<FakeWindowHandle> invisibleWindow = new FakeWindowHandle("Invisible", invisibleWindowToken, true /* focusable */, @@ -166,7 +168,7 @@ TEST(FocusResolverTest, FocusRequestsCanBePending) { TEST(FocusResolverTest, FocusRequestsArePersistent) { sp<IBinder> windowToken = new BBinder(); - std::vector<sp<InputWindowHandle>> windows; + std::vector<sp<WindowInfoHandle>> windows; sp<FakeWindowHandle> window = new FakeWindowHandle("Test Window", windowToken, false /* focusable */, true /* visible */); @@ -207,7 +209,7 @@ TEST(FocusResolverTest, FocusRequestsArePersistent) { TEST(FocusResolverTest, ConditionalFocusRequestsAreNotPersistent) { sp<IBinder> hostWindowToken = new BBinder(); - std::vector<sp<InputWindowHandle>> windows; + std::vector<sp<WindowInfoHandle>> windows; sp<FakeWindowHandle> hostWindow = new FakeWindowHandle("Host Window", hostWindowToken, true /* focusable */, @@ -258,7 +260,7 @@ TEST(FocusResolverTest, ConditionalFocusRequestsAreNotPersistent) { } TEST(FocusResolverTest, FocusRequestsAreClearedWhenWindowIsRemoved) { sp<IBinder> windowToken = new BBinder(); - std::vector<sp<InputWindowHandle>> windows; + std::vector<sp<WindowInfoHandle>> windows; sp<FakeWindowHandle> window = new FakeWindowHandle("Test Window", windowToken, true /* focusable */, true /* visible */); diff --git a/services/inputflinger/tests/IInputFlingerQuery.aidl b/services/inputflinger/tests/IInputFlingerQuery.aidl index 5c8a8da612..5aeb21f6b4 100644 --- a/services/inputflinger/tests/IInputFlingerQuery.aidl +++ b/services/inputflinger/tests/IInputFlingerQuery.aidl @@ -14,17 +14,14 @@ * limitations under the License. */ -import android.FocusRequest; import android.InputChannel; -import android.InputWindowInfo; -import android.os.ISetInputWindowsListener; +import android.gui.FocusRequest; +import android.gui.WindowInfo; /** @hide */ interface IInputFlingerQuery { /* Test interfaces */ - void getInputWindows(out InputWindowInfo[] inputHandles); void getInputChannels(out InputChannel[] channels); - void getLastFocusRequest(out FocusRequest request); void resetInputManager(); } diff --git a/services/inputflinger/tests/InputClassifierConverter_test.cpp b/services/inputflinger/tests/InputClassifierConverter_test.cpp index c0ada9d517..f626d56b8c 100644 --- a/services/inputflinger/tests/InputClassifierConverter_test.cpp +++ b/services/inputflinger/tests/InputClassifierConverter_test.cpp @@ -17,9 +17,9 @@ #include "../InputClassifierConverter.h" #include <gtest/gtest.h> +#include <gui/constants.h> #include <utils/BitSet.h> - using namespace android::hardware::input; namespace android { diff --git a/services/inputflinger/tests/InputClassifier_test.cpp b/services/inputflinger/tests/InputClassifier_test.cpp index a72df01ce6..3a9994eed9 100644 --- a/services/inputflinger/tests/InputClassifier_test.cpp +++ b/services/inputflinger/tests/InputClassifier_test.cpp @@ -16,6 +16,7 @@ #include "../InputClassifier.h" #include <gtest/gtest.h> +#include <gui/constants.h> #include "TestInputListener.h" diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index dff0752b59..8235ebff3e 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -29,9 +29,12 @@ #include <vector> using android::base::StringPrintf; +using android::gui::FocusRequest; +using android::gui::TouchOcclusionMode; +using android::gui::WindowInfo; +using android::gui::WindowInfoHandle; using android::os::InputEventInjectionResult; using android::os::InputEventInjectionSync; -using android::os::TouchOcclusionMode; using namespace android::flag_operators; namespace android::inputdispatcher { @@ -43,7 +46,8 @@ static const nsecs_t ARBITRARY_TIME = 1234; static const int32_t DEVICE_ID = 1; // An arbitrary display id. -static const int32_t DISPLAY_ID = ADISPLAY_ID_DEFAULT; +static constexpr int32_t DISPLAY_ID = ADISPLAY_ID_DEFAULT; +static constexpr int32_t SECOND_DISPLAY_ID = 1; // An arbitrary injector pid / uid pair that has permission to inject events. static const int32_t INJECTOR_PID = 999; @@ -469,8 +473,8 @@ protected: } } - void setFocusedWindow(const sp<InputWindowHandle>& window, - const sp<InputWindowHandle>& focusedWindow = nullptr) { + void setFocusedWindow(const sp<WindowInfoHandle>& window, + const sp<WindowInfoHandle>& focusedWindow = nullptr) { FocusRequest request; request.token = window->getToken(); request.windowName = window->getName(); @@ -527,8 +531,8 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC, /*action*/ -1, 0, 0, edgeFlags, metaState, 0, classification, identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, - AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_DISPLAY_SIZE, - AMOTION_EVENT_INVALID_DISPLAY_SIZE, ARBITRARY_TIME, ARBITRARY_TIME, + AMOTION_EVENT_INVALID_CURSOR_POSITION, ui::Transform::ROT_0, + INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords); ASSERT_EQ(InputEventInjectionResult::FAILED, mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, @@ -541,9 +545,9 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), 0, 0, edgeFlags, metaState, 0, classification, identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, - AMOTION_EVENT_INVALID_DISPLAY_SIZE, AMOTION_EVENT_INVALID_DISPLAY_SIZE, - ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, - pointerCoords); + ui::Transform::ROT_0, INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, + ARBITRARY_TIME, ARBITRARY_TIME, + /*pointerCount*/ 1, pointerProperties, pointerCoords); ASSERT_EQ(InputEventInjectionResult::FAILED, mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, InputEventInjectionSync::NONE, 0ms, 0)) @@ -554,9 +558,9 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { (~0U << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), 0, 0, edgeFlags, metaState, 0, classification, identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, - AMOTION_EVENT_INVALID_DISPLAY_SIZE, AMOTION_EVENT_INVALID_DISPLAY_SIZE, - ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, - pointerCoords); + ui::Transform::ROT_0, INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, + ARBITRARY_TIME, ARBITRARY_TIME, + /*pointerCount*/ 1, pointerProperties, pointerCoords); ASSERT_EQ(InputEventInjectionResult::FAILED, mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, InputEventInjectionSync::NONE, 0ms, 0)) @@ -568,9 +572,9 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), 0, 0, edgeFlags, metaState, 0, classification, identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, - AMOTION_EVENT_INVALID_DISPLAY_SIZE, AMOTION_EVENT_INVALID_DISPLAY_SIZE, - ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, - pointerCoords); + ui::Transform::ROT_0, INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, + ARBITRARY_TIME, ARBITRARY_TIME, + /*pointerCount*/ 1, pointerProperties, pointerCoords); ASSERT_EQ(InputEventInjectionResult::FAILED, mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, InputEventInjectionSync::NONE, 0ms, 0)) @@ -581,9 +585,9 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { (~0U << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), 0, 0, edgeFlags, metaState, 0, classification, identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, - AMOTION_EVENT_INVALID_DISPLAY_SIZE, AMOTION_EVENT_INVALID_DISPLAY_SIZE, - ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, - pointerCoords); + ui::Transform::ROT_0, INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, + ARBITRARY_TIME, ARBITRARY_TIME, + /*pointerCount*/ 1, pointerProperties, pointerCoords); ASSERT_EQ(InputEventInjectionResult::FAILED, mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, InputEventInjectionSync::NONE, 0ms, 0)) @@ -593,8 +597,8 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification, identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, - AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_DISPLAY_SIZE, - AMOTION_EVENT_INVALID_DISPLAY_SIZE, ARBITRARY_TIME, ARBITRARY_TIME, + AMOTION_EVENT_INVALID_CURSOR_POSITION, ui::Transform::ROT_0, + INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 0, pointerProperties, pointerCoords); ASSERT_EQ(InputEventInjectionResult::FAILED, mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, @@ -604,8 +608,8 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification, identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, - AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_DISPLAY_SIZE, - AMOTION_EVENT_INVALID_DISPLAY_SIZE, ARBITRARY_TIME, ARBITRARY_TIME, + AMOTION_EVENT_INVALID_CURSOR_POSITION, ui::Transform::ROT_0, + INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ MAX_POINTERS + 1, pointerProperties, pointerCoords); ASSERT_EQ(InputEventInjectionResult::FAILED, mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, @@ -617,8 +621,8 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification, identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, - AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_DISPLAY_SIZE, - AMOTION_EVENT_INVALID_DISPLAY_SIZE, ARBITRARY_TIME, ARBITRARY_TIME, + AMOTION_EVENT_INVALID_CURSOR_POSITION, ui::Transform::ROT_0, + INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords); ASSERT_EQ(InputEventInjectionResult::FAILED, mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, @@ -629,8 +633,8 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification, identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, - AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_DISPLAY_SIZE, - AMOTION_EVENT_INVALID_DISPLAY_SIZE, ARBITRARY_TIME, ARBITRARY_TIME, + AMOTION_EVENT_INVALID_CURSOR_POSITION, ui::Transform::ROT_0, + INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords); ASSERT_EQ(InputEventInjectionResult::FAILED, mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, @@ -643,8 +647,8 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification, identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, - AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_DISPLAY_SIZE, - AMOTION_EVENT_INVALID_DISPLAY_SIZE, ARBITRARY_TIME, ARBITRARY_TIME, + AMOTION_EVENT_INVALID_CURSOR_POSITION, ui::Transform::ROT_0, + INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 2, pointerProperties, pointerCoords); ASSERT_EQ(InputEventInjectionResult::FAILED, mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, @@ -892,7 +896,7 @@ protected: std::string mName; }; -class FakeWindowHandle : public InputWindowHandle { +class FakeWindowHandle : public WindowInfoHandle { public: static const int32_t WIDTH = 600; static const int32_t HEIGHT = 800; @@ -914,7 +918,7 @@ public: mInfo.token = *token; mInfo.id = sId++; mInfo.name = name; - mInfo.type = InputWindowInfo::Type::APPLICATION; + mInfo.type = WindowInfo::Type::APPLICATION; mInfo.dispatchingTimeout = DISPATCHING_TIMEOUT; mInfo.alpha = 1.0; mInfo.frameLeft = 0; @@ -934,7 +938,14 @@ public: mInfo.displayId = displayId; } - virtual bool updateInfo() { return true; } + sp<FakeWindowHandle> clone( + const std::shared_ptr<InputApplicationHandle>& inputApplicationHandle, + const sp<InputDispatcher>& dispatcher, int32_t displayId) { + sp<FakeWindowHandle> handle = + new FakeWindowHandle(inputApplicationHandle, dispatcher, mInfo.name + "(Mirror)", + displayId, mInfo.token); + return handle; + } void setFocusable(bool focusable) { mInfo.focusable = focusable; } @@ -948,9 +959,7 @@ public: void setAlpha(float alpha) { mInfo.alpha = alpha; } - void setTouchOcclusionMode(android::os::TouchOcclusionMode mode) { - mInfo.touchOcclusionMode = mode; - } + void setTouchOcclusionMode(TouchOcclusionMode mode) { mInfo.touchOcclusionMode = mode; } void setApplicationToken(sp<IBinder> token) { mInfo.applicationInfo.token = token; } @@ -964,11 +973,11 @@ public: mInfo.addTouchableRegion(frame); } - void addFlags(Flags<InputWindowInfo::Flag> flags) { mInfo.flags |= flags; } + void addFlags(Flags<WindowInfo::Flag> flags) { mInfo.flags |= flags; } - void setFlags(Flags<InputWindowInfo::Flag> flags) { mInfo.flags = flags; } + void setFlags(Flags<WindowInfo::Flag> flags) { mInfo.flags = flags; } - void setInputFeatures(InputWindowInfo::Feature features) { mInfo.inputFeatures = features; } + void setInputFeatures(WindowInfo::Feature features) { mInfo.inputFeatures = features; } void setWindowTransform(float dsdx, float dtdx, float dtdy, float dsdy) { mInfo.transform.set(dsdx, dtdx, dtdy, dsdy); @@ -1102,7 +1111,7 @@ public: void assertNoEvents() { if (mInputReceiver == nullptr && - mInfo.inputFeatures.test(InputWindowInfo::Feature::NO_INPUT_CHANNEL)) { + mInfo.inputFeatures.test(WindowInfo::Feature::NO_INPUT_CHANNEL)) { return; // Can't receive events if the window does not have input channel } ASSERT_NE(nullptr, mInputReceiver) @@ -1267,8 +1276,9 @@ public: mAction, mActionButton, mFlags, /* edgeFlags */ 0, AMETA_NONE, mButtonState, MotionClassification::NONE, identityTransform, /* xPrecision */ 0, /* yPrecision */ 0, mRawXCursorPosition, - mRawYCursorPosition, mDisplayWidth, mDisplayHeight, mEventTime, mEventTime, - mPointers.size(), pointerProperties.data(), pointerCoords.data()); + mRawYCursorPosition, mDisplayOrientation, mDisplayWidth, mDisplayHeight, + mEventTime, mEventTime, mPointers.size(), pointerProperties.data(), + pointerCoords.data()); return event; } @@ -1283,8 +1293,9 @@ private: int32_t mFlags{0}; float mRawXCursorPosition{AMOTION_EVENT_INVALID_CURSOR_POSITION}; float mRawYCursorPosition{AMOTION_EVENT_INVALID_CURSOR_POSITION}; - int32_t mDisplayWidth{AMOTION_EVENT_INVALID_DISPLAY_SIZE}; - int32_t mDisplayHeight{AMOTION_EVENT_INVALID_DISPLAY_SIZE}; + uint32_t mDisplayOrientation{ui::Transform::ROT_0}; + int32_t mDisplayWidth{INVALID_DISPLAY_SIZE}; + int32_t mDisplayHeight{INVALID_DISPLAY_SIZE}; std::vector<PointerBuilder> mPointers; }; @@ -1410,7 +1421,7 @@ TEST_F(InputDispatcherTest, SetInputWindowOnce_SingleWindowTouch) { sp<FakeWindowHandle> window = new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT); window->setFrame(Rect(0, 0, 100, 100)); - window->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL); + window->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, @@ -1433,7 +1444,7 @@ TEST_F(InputDispatcherTest, SetInputWindowTwice_SingleWindowTouch) { sp<FakeWindowHandle> window = new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT); window->setFrame(Rect(0, 0, 100, 100)); - window->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL); + window->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); @@ -1469,11 +1480,11 @@ TEST_F(InputDispatcherTest, HoverMoveEnterMouseClickAndHoverMoveExit) { sp<FakeWindowHandle> windowLeft = new FakeWindowHandle(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT); windowLeft->setFrame(Rect(0, 0, 600, 800)); - windowLeft->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL); + windowLeft->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); sp<FakeWindowHandle> windowRight = new FakeWindowHandle(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT); windowRight->setFrame(Rect(600, 0, 1200, 800)); - windowRight->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL); + windowRight->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); @@ -1580,7 +1591,7 @@ TEST_F(InputDispatcherTest, HoverEnterMouseClickAndHoverExit) { sp<FakeWindowHandle> window = new FakeWindowHandle(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); window->setFrame(Rect(0, 0, 1200, 800)); - window->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL); + window->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); @@ -1662,11 +1673,11 @@ TEST_F(InputDispatcherTest, DispatchMouseEventsUnderCursor) { sp<FakeWindowHandle> windowLeft = new FakeWindowHandle(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT); windowLeft->setFrame(Rect(0, 0, 600, 800)); - windowLeft->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL); + windowLeft->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); sp<FakeWindowHandle> windowRight = new FakeWindowHandle(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT); windowRight->setFrame(Rect(600, 0, 1200, 800)); - windowRight->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL); + windowRight->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); @@ -1860,15 +1871,13 @@ TEST_F(InputDispatcherTest, TransferTouchFocus_TwoPointersSplitTouch) { sp<FakeWindowHandle> firstWindow = new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT); firstWindow->setFrame(Rect(0, 0, 600, 400)); - firstWindow->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL | - InputWindowInfo::Flag::SPLIT_TOUCH); + firstWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH); // Create a non touch modal window that supports split touch sp<FakeWindowHandle> secondWindow = new FakeWindowHandle(application, mDispatcher, "Second Window", ADISPLAY_ID_DEFAULT); secondWindow->setFrame(Rect(0, 400, 600, 800)); - secondWindow->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL | - InputWindowInfo::Flag::SPLIT_TOUCH); + secondWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH); // Add the windows to the dispatcher mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {firstWindow, secondWindow}}}); @@ -1934,15 +1943,13 @@ TEST_F(InputDispatcherTest, TransferTouch_TwoPointersSplitTouch) { sp<FakeWindowHandle> firstWindow = new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT); firstWindow->setFrame(Rect(0, 0, 600, 400)); - firstWindow->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL | - InputWindowInfo::Flag::SPLIT_TOUCH); + firstWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH); // Create a non touch modal window that supports split touch sp<FakeWindowHandle> secondWindow = new FakeWindowHandle(application, mDispatcher, "Second Window", ADISPLAY_ID_DEFAULT); secondWindow->setFrame(Rect(0, 400, 600, 800)); - secondWindow->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL | - InputWindowInfo::Flag::SPLIT_TOUCH); + secondWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH); // Add the windows to the dispatcher mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {firstWindow, secondWindow}}}); @@ -1999,6 +2006,134 @@ TEST_F(InputDispatcherTest, TransferTouch_TwoPointersSplitTouch) { secondWindow->assertNoEvents(); } +// This case will create two windows and one mirrored window on the default display and mirror +// two windows on the second display. It will test if 'transferTouchFocus' works fine if we put +// the windows info of second display before default display. +TEST_F(InputDispatcherTest, TransferTouchFocus_CloneSurface) { + std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); + sp<FakeWindowHandle> firstWindowInPrimary = + new FakeWindowHandle(application, mDispatcher, "D_1_W1", ADISPLAY_ID_DEFAULT); + firstWindowInPrimary->setFrame(Rect(0, 0, 100, 100)); + firstWindowInPrimary->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); + sp<FakeWindowHandle> secondWindowInPrimary = + new FakeWindowHandle(application, mDispatcher, "D_1_W2", ADISPLAY_ID_DEFAULT); + secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100)); + secondWindowInPrimary->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); + + sp<FakeWindowHandle> mirrorWindowInPrimary = + firstWindowInPrimary->clone(application, mDispatcher, ADISPLAY_ID_DEFAULT); + mirrorWindowInPrimary->setFrame(Rect(0, 100, 100, 200)); + mirrorWindowInPrimary->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); + + sp<FakeWindowHandle> firstWindowInSecondary = + firstWindowInPrimary->clone(application, mDispatcher, SECOND_DISPLAY_ID); + firstWindowInSecondary->setFrame(Rect(0, 0, 100, 100)); + firstWindowInSecondary->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); + + sp<FakeWindowHandle> secondWindowInSecondary = + secondWindowInPrimary->clone(application, mDispatcher, SECOND_DISPLAY_ID); + secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100)); + secondWindowInPrimary->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); + + // Update window info, let it find window handle of second display first. + mDispatcher->setInputWindows( + {{SECOND_DISPLAY_ID, {firstWindowInSecondary, secondWindowInSecondary}}, + {ADISPLAY_ID_DEFAULT, + {mirrorWindowInPrimary, firstWindowInPrimary, secondWindowInPrimary}}}); + + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + {50, 50})) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + + // Window should receive motion event. + firstWindowInPrimary->consumeMotionDown(ADISPLAY_ID_DEFAULT); + + // Transfer touch focus + ASSERT_TRUE(mDispatcher->transferTouchFocus(firstWindowInPrimary->getToken(), + secondWindowInPrimary->getToken())); + // The first window gets cancel. + firstWindowInPrimary->consumeMotionCancel(); + secondWindowInPrimary->consumeMotionDown(); + + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, + ADISPLAY_ID_DEFAULT, {150, 50})) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + firstWindowInPrimary->assertNoEvents(); + secondWindowInPrimary->consumeMotionMove(); + + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionUp(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + {150, 50})) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + firstWindowInPrimary->assertNoEvents(); + secondWindowInPrimary->consumeMotionUp(); +} + +// Same as TransferTouchFocus_CloneSurface, but this touch on the secondary display and use +// 'transferTouch' api. +TEST_F(InputDispatcherTest, TransferTouch_CloneSurface) { + std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); + sp<FakeWindowHandle> firstWindowInPrimary = + new FakeWindowHandle(application, mDispatcher, "D_1_W1", ADISPLAY_ID_DEFAULT); + firstWindowInPrimary->setFrame(Rect(0, 0, 100, 100)); + firstWindowInPrimary->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); + sp<FakeWindowHandle> secondWindowInPrimary = + new FakeWindowHandle(application, mDispatcher, "D_1_W2", ADISPLAY_ID_DEFAULT); + secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100)); + secondWindowInPrimary->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); + + sp<FakeWindowHandle> mirrorWindowInPrimary = + firstWindowInPrimary->clone(application, mDispatcher, ADISPLAY_ID_DEFAULT); + mirrorWindowInPrimary->setFrame(Rect(0, 100, 100, 200)); + mirrorWindowInPrimary->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); + + sp<FakeWindowHandle> firstWindowInSecondary = + firstWindowInPrimary->clone(application, mDispatcher, SECOND_DISPLAY_ID); + firstWindowInSecondary->setFrame(Rect(0, 0, 100, 100)); + firstWindowInSecondary->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); + + sp<FakeWindowHandle> secondWindowInSecondary = + secondWindowInPrimary->clone(application, mDispatcher, SECOND_DISPLAY_ID); + secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100)); + secondWindowInPrimary->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); + + // Update window info, let it find window handle of second display first. + mDispatcher->setInputWindows( + {{SECOND_DISPLAY_ID, {firstWindowInSecondary, secondWindowInSecondary}}, + {ADISPLAY_ID_DEFAULT, + {mirrorWindowInPrimary, firstWindowInPrimary, secondWindowInPrimary}}}); + + // Touch on second display. + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID, {50, 50})) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + + // Window should receive motion event. + firstWindowInPrimary->consumeMotionDown(SECOND_DISPLAY_ID); + + // Transfer touch focus + ASSERT_TRUE(mDispatcher->transferTouch(secondWindowInSecondary->getToken())); + + // The first window gets cancel. + firstWindowInPrimary->consumeMotionCancel(SECOND_DISPLAY_ID); + secondWindowInPrimary->consumeMotionDown(SECOND_DISPLAY_ID); + + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, + SECOND_DISPLAY_ID, {150, 50})) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + firstWindowInPrimary->assertNoEvents(); + secondWindowInPrimary->consumeMotionMove(SECOND_DISPLAY_ID); + + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionUp(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID, {150, 50})) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + firstWindowInPrimary->assertNoEvents(); + secondWindowInPrimary->consumeMotionUp(SECOND_DISPLAY_ID); +} + TEST_F(InputDispatcherTest, FocusedWindow_ReceivesFocusEventAndKeyEvent) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); sp<FakeWindowHandle> window = @@ -2060,15 +2195,13 @@ TEST_F(InputDispatcherTest, PointerCancel_SendCancelWhenSplitTouch) { sp<FakeWindowHandle> firstWindow = new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT); firstWindow->setFrame(Rect(0, 0, 600, 400)); - firstWindow->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL | - InputWindowInfo::Flag::SPLIT_TOUCH); + firstWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH); // Create second non touch modal window that supports split touch sp<FakeWindowHandle> secondWindow = new FakeWindowHandle(application, mDispatcher, "Second Window", ADISPLAY_ID_DEFAULT); secondWindow->setFrame(Rect(0, 400, 600, 800)); - secondWindow->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL | - InputWindowInfo::Flag::SPLIT_TOUCH); + secondWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH); // Add the windows to the dispatcher mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {firstWindow, secondWindow}}}); @@ -2432,7 +2565,7 @@ TEST_F(InputDispatcherTest, VerifyInputEvent_MotionEvent) { EXPECT_EQ(motionArgs.buttonState, verifiedMotion.buttonState); } -TEST_F(InputDispatcherTest, NonPointerMotionEvent_NotTransformed) { +TEST_F(InputDispatcherTest, NonPointerMotionEvent_JoystickAndTouchpadNotTransformed) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); sp<FakeWindowHandle> window = new FakeWindowHandle(application, mDispatcher, "Test window", ADISPLAY_ID_DEFAULT); @@ -2452,20 +2585,19 @@ TEST_F(InputDispatcherTest, NonPointerMotionEvent_NotTransformed) { // Second, we consume focus event if it is right or wrong according to onFocusChangedLocked. window->consumeFocusEvent(true); - constexpr const std::array nonPointerSources = {AINPUT_SOURCE_TRACKBALL, - AINPUT_SOURCE_MOUSE_RELATIVE, - AINPUT_SOURCE_JOYSTICK}; - for (const int source : nonPointerSources) { - // Notify motion with a non-pointer source. - NotifyMotionArgs motionArgs = - generateMotionArgs(AMOTION_EVENT_ACTION_MOVE, source, ADISPLAY_ID_DEFAULT); + constexpr const std::array nonTransformedSources = {std::pair(AINPUT_SOURCE_TOUCHPAD, + AMOTION_EVENT_ACTION_DOWN), + std::pair(AINPUT_SOURCE_JOYSTICK, + AMOTION_EVENT_ACTION_MOVE)}; + for (const auto& [source, action] : nonTransformedSources) { + const NotifyMotionArgs motionArgs = generateMotionArgs(action, source, ADISPLAY_ID_DEFAULT); mDispatcher->notifyMotion(&motionArgs); MotionEvent* event = window->consumeMotion(); ASSERT_NE(event, nullptr); const MotionEvent& motionEvent = *event; - EXPECT_EQ(AMOTION_EVENT_ACTION_MOVE, motionEvent.getAction()); + EXPECT_EQ(action, motionEvent.getAction()); EXPECT_EQ(motionArgs.pointerCount, motionEvent.getPointerCount()); float expectedX = motionArgs.pointerCoords[0].getX(); @@ -2737,8 +2869,7 @@ TEST_F(InputDispatcherTest, SlipperyWindow_SetsFlagPartiallyObscured) { sp<FakeWindowHandle> slipperyExitWindow = new FakeWindowHandle(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT); - slipperyExitWindow->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL | - InputWindowInfo::Flag::SLIPPERY); + slipperyExitWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SLIPPERY); // Make sure this one overlaps the bottom window slipperyExitWindow->setFrame(Rect(25, 25, 75, 75)); // Change the owner uid/pid of the window so that it is considered to be occluding the bottom @@ -2923,7 +3054,6 @@ TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_RepeatKeyEventsUseUniqueEvent /* Test InputDispatcher for MultiDisplay */ class InputDispatcherFocusOnTwoDisplaysTest : public InputDispatcherTest { public: - static constexpr int32_t SECOND_DISPLAY_ID = 1; virtual void SetUp() override { InputDispatcherTest::SetUp(); @@ -3086,8 +3216,6 @@ TEST_F(InputDispatcherFocusOnTwoDisplaysTest, CanFocusWindowOnUnfocusedDisplay) class InputFilterTest : public InputDispatcherTest { protected: - static constexpr int32_t SECOND_DISPLAY_ID = 1; - void testNotifyMotion(int32_t displayId, bool expectToBeFiltered) { NotifyMotionArgs motionArgs; @@ -3221,9 +3349,9 @@ protected: DISPLAY_ID, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0, 0, AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0, MotionClassification::NONE, identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, - AMOTION_EVENT_INVALID_CURSOR_POSITION, - 0 /*AMOTION_EVENT_INVALID_DISPLAY_SIZE*/, - 0 /*AMOTION_EVENT_INVALID_DISPLAY_SIZE*/, eventTime, eventTime, + AMOTION_EVENT_INVALID_CURSOR_POSITION, ui::Transform::ROT_0, + 0 /*INVALID_DISPLAY_SIZE*/, 0 /*INVALID_DISPLAY_SIZE*/, eventTime, + eventTime, /*pointerCount*/ 1, pointerProperties, pointerCoords); const int32_t additionalPolicyFlags = POLICY_FLAG_PASS_TO_USER; @@ -3281,12 +3409,12 @@ class InputDispatcherOnPointerDownOutsideFocus : public InputDispatcherTest { mUnfocusedWindow->setFrame(Rect(0, 0, 30, 30)); // Adding FLAG_NOT_TOUCH_MODAL to ensure taps outside this window are not sent to this // window. - mUnfocusedWindow->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL); + mUnfocusedWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); mFocusedWindow = new FakeWindowHandle(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT); mFocusedWindow->setFrame(Rect(50, 50, 100, 100)); - mFocusedWindow->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL); + mFocusedWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); // Set focused application. mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); @@ -3395,14 +3523,12 @@ class InputDispatcherMultiWindowSameTokenTests : public InputDispatcherTest { ADISPLAY_ID_DEFAULT); // Adding FLAG_NOT_TOUCH_MODAL otherwise all taps will go to the top most window. // We also need FLAG_SPLIT_TOUCH or we won't be able to get touches for both windows. - mWindow1->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL | - InputWindowInfo::Flag::SPLIT_TOUCH); + mWindow1->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH); mWindow1->setFrame(Rect(0, 0, 100, 100)); mWindow2 = new FakeWindowHandle(application, mDispatcher, "Fake Window 2", ADISPLAY_ID_DEFAULT, mWindow1->getToken()); - mWindow2->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL | - InputWindowInfo::Flag::SPLIT_TOUCH); + mWindow2->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH); mWindow2->setFrame(Rect(100, 100, 200, 200)); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow1, mWindow2}}}); @@ -3413,7 +3539,7 @@ protected: sp<FakeWindowHandle> mWindow2; // Helper function to convert the point from screen coordinates into the window's space - static PointF getPointInWindow(const InputWindowInfo* windowInfo, const PointF& point) { + static PointF getPointInWindow(const WindowInfo* windowInfo, const PointF& point) { vec2 vals = windowInfo->transform.transform(point.x, point.y); return {vals.x, vals.y}; } @@ -3601,7 +3727,7 @@ class InputDispatcherSingleWindowAnr : public InputDispatcherTest { mWindow->setFocusable(true); // Adding FLAG_NOT_TOUCH_MODAL to ensure taps outside this window are not sent to this // window. - mWindow->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL); + mWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); // Set focused application. mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApplication); @@ -4002,16 +4128,15 @@ class InputDispatcherMultiWindowAnr : public InputDispatcherTest { // Adding FLAG_NOT_TOUCH_MODAL to ensure taps outside this window are not sent to this // window. // Adding FLAG_WATCH_OUTSIDE_TOUCH to receive ACTION_OUTSIDE when another window is tapped - mUnfocusedWindow->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL | - InputWindowInfo::Flag::WATCH_OUTSIDE_TOUCH | - InputWindowInfo::Flag::SPLIT_TOUCH); + mUnfocusedWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | + WindowInfo::Flag::WATCH_OUTSIDE_TOUCH | + WindowInfo::Flag::SPLIT_TOUCH); mFocusedWindow = new FakeWindowHandle(mApplication, mDispatcher, "Focused", ADISPLAY_ID_DEFAULT); mFocusedWindow->setDispatchingTimeout(30ms); mFocusedWindow->setFrame(Rect(50, 50, 100, 100)); - mFocusedWindow->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL | - InputWindowInfo::Flag::SPLIT_TOUCH); + mFocusedWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH); // Set focused application. mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApplication); @@ -4379,7 +4504,7 @@ class InputDispatcherMultiWindowOcclusionTests : public InputDispatcherTest { "Window without input channel", ADISPLAY_ID_DEFAULT, std::make_optional<sp<IBinder>>(nullptr) /*token*/); - mNoInputWindow->setInputFeatures(InputWindowInfo::Feature::NO_INPUT_CHANNEL); + mNoInputWindow->setInputFeatures(WindowInfo::Feature::NO_INPUT_CHANNEL); mNoInputWindow->setFrame(Rect(0, 0, 100, 100)); // It's perfectly valid for this window to not have an associated input channel @@ -4421,7 +4546,7 @@ TEST_F(InputDispatcherMultiWindowOcclusionTests, "Window with input channel and NO_INPUT_CHANNEL", ADISPLAY_ID_DEFAULT); - mNoInputWindow->setInputFeatures(InputWindowInfo::Feature::NO_INPUT_CHANNEL); + mNoInputWindow->setInputFeatures(WindowInfo::Feature::NO_INPUT_CHANNEL); mNoInputWindow->setFrame(Rect(0, 0, 100, 100)); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mNoInputWindow, mBottomWindow}}}); @@ -4721,10 +4846,10 @@ protected: mTouchWindow.clear(); } - sp<FakeWindowHandle> getOccludingWindow(int32_t uid, std::string name, - os::TouchOcclusionMode mode, float alpha = 1.0f) { + sp<FakeWindowHandle> getOccludingWindow(int32_t uid, std::string name, TouchOcclusionMode mode, + float alpha = 1.0f) { sp<FakeWindowHandle> window = getWindow(uid, name); - window->setFlags(InputWindowInfo::Flag::NOT_TOUCHABLE); + window->setFlags(WindowInfo::Flag::NOT_TOUCHABLE); window->setTouchOcclusionMode(mode); window->setAlpha(alpha); return window; @@ -4838,7 +4963,7 @@ TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithZeroOpacityAndWatchOutside_ReceivesOutsideEvent) { const sp<FakeWindowHandle>& w = getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, 0.0f); - w->addFlags(InputWindowInfo::Flag::WATCH_OUTSIDE_TOUCH); + w->addFlags(WindowInfo::Flag::WATCH_OUTSIDE_TOUCH); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w, mTouchWindow}}}); touch(); @@ -4849,7 +4974,7 @@ TEST_F(InputDispatcherUntrustedTouchesTest, TEST_F(InputDispatcherUntrustedTouchesTest, OutsideEvent_HasZeroCoordinates) { const sp<FakeWindowHandle>& w = getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, 0.0f); - w->addFlags(InputWindowInfo::Flag::WATCH_OUTSIDE_TOUCH); + w->addFlags(WindowInfo::Flag::WATCH_OUTSIDE_TOUCH); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w, mTouchWindow}}}); touch(); @@ -5103,11 +5228,11 @@ protected: mApp = std::make_shared<FakeApplicationHandle>(); mWindow = new FakeWindowHandle(mApp, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT); mWindow->setFrame(Rect(0, 0, 100, 100)); - mWindow->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL); + mWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); mSecondWindow = new FakeWindowHandle(mApp, mDispatcher, "TestWindow2", ADISPLAY_ID_DEFAULT); mSecondWindow->setFrame(Rect(100, 0, 200, 100)); - mSecondWindow->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL); + mSecondWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApp); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow, mSecondWindow}}}); diff --git a/services/inputflinger/tests/InputFlingerService_test.cpp b/services/inputflinger/tests/InputFlingerService_test.cpp index c368e79f41..454e531af6 100644 --- a/services/inputflinger/tests/InputFlingerService_test.cpp +++ b/services/inputflinger/tests/InputFlingerService_test.cpp @@ -18,9 +18,7 @@ #include <IInputFlingerQuery.h> #include <android/os/BnInputFlinger.h> -#include <android/os/BnSetInputWindowsListener.h> #include <android/os/IInputFlinger.h> -#include <android/os/ISetInputWindowsListener.h> #include <binder/Binder.h> #include <binder/IPCThreadState.h> @@ -30,7 +28,6 @@ #include <input/Input.h> #include <input/InputTransport.h> -#include <input/InputWindow.h> #include <gtest/gtest.h> #include <inttypes.h> @@ -44,56 +41,18 @@ #define TAG "InputFlingerServiceTest" +using android::gui::FocusRequest; using android::os::BnInputFlinger; -using android::os::BnSetInputWindowsListener; using android::os::IInputFlinger; -using android::os::ISetInputWindowsListener; using std::chrono_literals::operator""ms; using std::chrono_literals::operator""s; namespace android { -static const sp<IBinder> TestInfoToken = new BBinder(); -static const sp<IBinder> FocusedTestInfoToken = new BBinder(); -static constexpr int32_t TestInfoId = 1; -static const std::string TestInfoName = "InputFlingerServiceTestInputWindowInfo"; -static constexpr Flags<InputWindowInfo::Flag> TestInfoFlags = InputWindowInfo::Flag::NOT_FOCUSABLE; -static constexpr InputWindowInfo::Type TestInfoType = InputWindowInfo::Type::INPUT_METHOD; -static constexpr std::chrono::duration TestInfoDispatchingTimeout = 2532ms; -static constexpr int32_t TestInfoFrameLeft = 93; -static constexpr int32_t TestInfoFrameTop = 34; -static constexpr int32_t TestInfoFrameRight = 16; -static constexpr int32_t TestInfoFrameBottom = 19; -static constexpr int32_t TestInfoSurfaceInset = 17; -static constexpr float TestInfoGlobalScaleFactor = 0.3; -static constexpr float TestInfoWindowXScale = 0.4; -static constexpr float TestInfoWindowYScale = 0.5; -static const Rect TestInfoTouchableRegionRect = {100 /* left */, 150 /* top */, 400 /* right */, - 450 /* bottom */}; -static const Region TestInfoTouchableRegion(TestInfoTouchableRegionRect); -static constexpr bool TestInfoVisible = false; -static constexpr bool TestInfoTrustedOverlay = true; -static constexpr bool TestInfoFocusable = false; -static constexpr bool TestInfoHasWallpaper = false; -static constexpr bool TestInfoPaused = false; -static constexpr int32_t TestInfoOwnerPid = 19; -static constexpr int32_t TestInfoOwnerUid = 24; -static constexpr InputWindowInfo::Feature TestInfoInputFeatures = - InputWindowInfo::Feature::NO_INPUT_CHANNEL; -static constexpr int32_t TestInfoDisplayId = 34; -static constexpr int32_t TestInfoPortalToDisplayId = 2; -static constexpr bool TestInfoReplaceTouchableRegionWithCrop = true; -static const sp<IBinder> TestInfoTouchableRegionCropHandle = new BBinder(); - -static const std::string TestAppInfoName = "InputFlingerServiceTestInputApplicationInfo"; -static const sp<IBinder> TestAppInfoToken = new BBinder(); -static constexpr std::chrono::duration TestAppInfoDispatchingTimeout = 12345678ms; - static const String16 kTestServiceName = String16("InputFlingerService"); static const String16 kQueryServiceName = String16("InputFlingerQueryService"); -struct SetInputWindowsListener; // --- InputFlingerServiceTest --- class InputFlingerServiceTest : public testing::Test { public: @@ -102,32 +61,15 @@ public: protected: void InitializeInputFlinger(); - void setInputWindowsByInfos(const std::vector<InputWindowInfo>& infos); - void setFocusedWindow(const sp<IBinder> token, const sp<IBinder> focusedToken, - nsecs_t timestampNanos); - - void setInputWindowsFinished(); - void verifyInputWindowInfo(const InputWindowInfo& info) const; - InputWindowInfo& getInfo() const { return const_cast<InputWindowInfo&>(mInfo); } sp<IInputFlinger> mService; sp<IInputFlingerQuery> mQuery; private: - sp<SetInputWindowsListener> mSetInputWindowsListener; std::unique_ptr<InputChannel> mServerChannel, mClientChannel; - InputWindowInfo mInfo; std::mutex mLock; - std::condition_variable mSetInputWindowsFinishedCondition; }; -struct SetInputWindowsListener : BnSetInputWindowsListener { - explicit SetInputWindowsListener(std::function<void()> cbFunc) : mCbFunc(cbFunc) {} - - binder::Status onSetInputWindowsFinished() override; - - std::function<void()> mCbFunc; -}; class TestInputManager : public BnInputFlinger { protected: @@ -136,16 +78,10 @@ protected: public: TestInputManager(){}; - binder::Status getInputWindows(std::vector<::android::InputWindowInfo>* inputHandles); binder::Status getInputChannels(std::vector<::android::InputChannel>* channels); - binder::Status getLastFocusRequest(FocusRequest*); status_t dump(int fd, const Vector<String16>& args) override; - binder::Status setInputWindows( - const std::vector<InputWindowInfo>& handles, - const sp<ISetInputWindowsListener>& setInputWindowsListener) override; - binder::Status createInputChannel(const std::string& name, InputChannel* outChannel) override; binder::Status removeInputChannel(const sp<IBinder>& connectionToken) override; binder::Status setFocusedWindow(const FocusRequest&) override; @@ -154,63 +90,28 @@ public: private: mutable Mutex mLock; - std::unordered_map<int32_t, std::vector<sp<InputWindowHandle>>> mHandlesPerDisplay; std::vector<std::shared_ptr<InputChannel>> mInputChannels; - FocusRequest mFocusRequest; }; class TestInputQuery : public BnInputFlingerQuery { public: TestInputQuery(sp<android::TestInputManager> manager) : mManager(manager){}; - binder::Status getInputWindows(std::vector<::android::InputWindowInfo>* inputHandles) override; binder::Status getInputChannels(std::vector<::android::InputChannel>* channels) override; - binder::Status getLastFocusRequest(FocusRequest*) override; binder::Status resetInputManager() override; private: sp<android::TestInputManager> mManager; }; -binder::Status TestInputQuery::getInputWindows( - std::vector<::android::InputWindowInfo>* inputHandles) { - return mManager->getInputWindows(inputHandles); -} - binder::Status TestInputQuery::getInputChannels(std::vector<::android::InputChannel>* channels) { return mManager->getInputChannels(channels); } -binder::Status TestInputQuery::getLastFocusRequest(FocusRequest* request) { - return mManager->getLastFocusRequest(request); -} - binder::Status TestInputQuery::resetInputManager() { mManager->reset(); return binder::Status::ok(); } -binder::Status SetInputWindowsListener::onSetInputWindowsFinished() { - if (mCbFunc != nullptr) { - mCbFunc(); - } - return binder::Status::ok(); -} - -binder::Status TestInputManager::setInputWindows( - const std::vector<InputWindowInfo>& infos, - const sp<ISetInputWindowsListener>& setInputWindowsListener) { - AutoMutex _l(mLock); - - for (const auto& info : infos) { - mHandlesPerDisplay.emplace(info.displayId, std::vector<sp<InputWindowHandle>>()); - mHandlesPerDisplay[info.displayId].push_back(new InputWindowHandle(info)); - } - if (setInputWindowsListener) { - setInputWindowsListener->onSetInputWindowsFinished(); - } - return binder::Status::ok(); -} - binder::Status TestInputManager::createInputChannel(const std::string& name, InputChannel* outChannel) { AutoMutex _l(mLock); @@ -248,16 +149,6 @@ status_t TestInputManager::dump(int fd, const Vector<String16>& args) { return NO_ERROR; } -binder::Status TestInputManager::getInputWindows( - std::vector<::android::InputWindowInfo>* inputInfos) { - for (auto& [displayId, inputHandles] : mHandlesPerDisplay) { - for (auto& inputHandle : inputHandles) { - inputInfos->push_back(*inputHandle->getInfo()); - } - } - return binder::Status::ok(); -} - binder::Status TestInputManager::getInputChannels(std::vector<::android::InputChannel>* channels) { channels->clear(); for (std::shared_ptr<InputChannel>& channel : mInputChannels) { @@ -266,64 +157,16 @@ binder::Status TestInputManager::getInputChannels(std::vector<::android::InputCh return binder::Status::ok(); } -binder::Status TestInputManager::getLastFocusRequest(FocusRequest* request) { - *request = mFocusRequest; - return binder::Status::ok(); -} - binder::Status TestInputManager::setFocusedWindow(const FocusRequest& request) { - mFocusRequest = request; return binder::Status::ok(); } void TestInputManager::reset() { - mHandlesPerDisplay.clear(); mInputChannels.clear(); - mFocusRequest = FocusRequest(); } void InputFlingerServiceTest::SetUp() { - mSetInputWindowsListener = new SetInputWindowsListener([&]() { - std::unique_lock<std::mutex> lock(mLock); - mSetInputWindowsFinishedCondition.notify_all(); - }); InputChannel::openInputChannelPair("testchannels", mServerChannel, mClientChannel); - - mInfo.token = TestInfoToken; - mInfo.id = TestInfoId; - mInfo.name = TestInfoName; - mInfo.flags = TestInfoFlags; - mInfo.type = TestInfoType; - mInfo.dispatchingTimeout = TestInfoDispatchingTimeout; - mInfo.frameLeft = TestInfoFrameLeft; - mInfo.frameTop = TestInfoFrameTop; - mInfo.frameRight = TestInfoFrameRight; - mInfo.frameBottom = TestInfoFrameBottom; - mInfo.surfaceInset = TestInfoSurfaceInset; - mInfo.globalScaleFactor = TestInfoGlobalScaleFactor; - mInfo.transform.set({TestInfoWindowXScale, 0, TestInfoFrameLeft, 0, TestInfoWindowYScale, - TestInfoFrameTop, 0, 0, 1}); - mInfo.touchableRegion = TestInfoTouchableRegion; - mInfo.visible = TestInfoVisible; - mInfo.trustedOverlay = TestInfoTrustedOverlay; - mInfo.focusable = TestInfoFocusable; - - mInfo.hasWallpaper = TestInfoHasWallpaper; - mInfo.paused = TestInfoPaused; - mInfo.ownerPid = TestInfoOwnerPid; - mInfo.ownerUid = TestInfoOwnerUid; - mInfo.inputFeatures = TestInfoInputFeatures; - mInfo.displayId = TestInfoDisplayId; - mInfo.portalToDisplayId = TestInfoPortalToDisplayId; - mInfo.replaceTouchableRegionWithCrop = TestInfoReplaceTouchableRegionWithCrop; - mInfo.touchableRegionCropHandle = TestInfoTouchableRegionCropHandle; - - mInfo.applicationInfo.name = TestAppInfoName; - mInfo.applicationInfo.token = TestAppInfoToken; - mInfo.applicationInfo.dispatchingTimeoutMillis = - std::chrono::duration_cast<std::chrono::milliseconds>(TestAppInfoDispatchingTimeout) - .count(); - InitializeInputFlinger(); } @@ -331,10 +174,6 @@ void InputFlingerServiceTest::TearDown() { mQuery->resetInputManager(); } -void InputFlingerServiceTest::verifyInputWindowInfo(const InputWindowInfo& info) const { - EXPECT_EQ(mInfo, info); -} - void InputFlingerServiceTest::InitializeInputFlinger() { sp<IBinder> input(defaultServiceManager()->waitForService(kTestServiceName)); ASSERT_TRUE(input != nullptr); @@ -345,40 +184,6 @@ void InputFlingerServiceTest::InitializeInputFlinger() { mQuery = interface_cast<IInputFlingerQuery>(input); } -void InputFlingerServiceTest::setInputWindowsByInfos(const std::vector<InputWindowInfo>& infos) { - std::unique_lock<std::mutex> lock(mLock); - mService->setInputWindows(infos, mSetInputWindowsListener); - // Verify listener call - EXPECT_NE(mSetInputWindowsFinishedCondition.wait_for(lock, 1s), std::cv_status::timeout); -} - -void InputFlingerServiceTest::setFocusedWindow(const sp<IBinder> token, - const sp<IBinder> focusedToken, - nsecs_t timestampNanos) { - FocusRequest request; - request.token = TestInfoToken; - request.focusedToken = focusedToken; - request.timestamp = timestampNanos; - mService->setFocusedWindow(request); - // call set input windows and wait for the callback to drain the queue. - setInputWindowsByInfos(std::vector<InputWindowInfo>()); -} - -/** - * Test InputFlinger service interface SetInputWindows - */ -TEST_F(InputFlingerServiceTest, InputWindow_SetInputWindows) { - std::vector<InputWindowInfo> infos = {getInfo()}; - setInputWindowsByInfos(infos); - - // Verify input windows from service - std::vector<::android::InputWindowInfo> windowInfos; - mQuery->getInputWindows(&windowInfos); - for (const ::android::InputWindowInfo& windowInfo : windowInfos) { - verifyInputWindowInfo(windowInfo); - } -} - /** * Test InputFlinger service interface createInputChannel */ @@ -397,7 +202,7 @@ TEST_F(InputFlingerServiceTest, CreateInputChannelReturnsUnblockedFd) { EXPECT_EQ(result & O_NONBLOCK, O_NONBLOCK); } -TEST_F(InputFlingerServiceTest, InputWindow_CreateInputChannel) { +TEST_F(InputFlingerServiceTest, CreateInputChannel) { InputChannel channel; ASSERT_TRUE(mService->createInputChannel("testchannels", &channel).isOk()); @@ -411,30 +216,6 @@ TEST_F(InputFlingerServiceTest, InputWindow_CreateInputChannel) { EXPECT_EQ(channels.size(), 0UL); } -TEST_F(InputFlingerServiceTest, InputWindow_setFocusedWindow) { - nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); - setFocusedWindow(TestInfoToken, nullptr /* focusedToken */, now); - - FocusRequest request; - mQuery->getLastFocusRequest(&request); - - EXPECT_EQ(request.token, TestInfoToken); - EXPECT_EQ(request.focusedToken, nullptr); - EXPECT_EQ(request.timestamp, now); -} - -TEST_F(InputFlingerServiceTest, InputWindow_setFocusedWindowWithFocusedToken) { - nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); - setFocusedWindow(TestInfoToken, FocusedTestInfoToken, now); - - FocusRequest request; - mQuery->getLastFocusRequest(&request); - - EXPECT_EQ(request.token, TestInfoToken); - EXPECT_EQ(request.focusedToken, FocusedTestInfoToken); - EXPECT_EQ(request.timestamp, now); -} - } // namespace android int main(int argc, char** argv) { diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp index 997cbe88a1..91da0d5640 100644 --- a/services/inputflinger/tests/InputReader_test.cpp +++ b/services/inputflinger/tests/InputReader_test.cpp @@ -16,6 +16,7 @@ #include <CursorInputMapper.h> #include <InputDevice.h> +#include <InputFlingerProperties.sysprop.h> #include <InputMapper.h> #include <InputReader.h> #include <InputReaderBase.h> @@ -32,6 +33,7 @@ #include <VibratorInputMapper.h> #include <android-base/thread_annotations.h> #include <gtest/gtest.h> +#include <gui/constants.h> #include <inttypes.h> #include <math.h> @@ -94,6 +96,17 @@ const std::unordered_map<std::string, LightColor> LIGHT_COLORS = {{"red", LightC {"green", LightColor::GREEN}, {"blue", LightColor::BLUE}}; +static int32_t getInverseRotation(int32_t orientation) { + switch (orientation) { + case DISPLAY_ORIENTATION_90: + return DISPLAY_ORIENTATION_270; + case DISPLAY_ORIENTATION_270: + return DISPLAY_ORIENTATION_90; + default: + return orientation; + } +} + // --- FakePointerController --- class FakePointerController : public PointerControllerInterface { @@ -2659,6 +2672,7 @@ protected: static const int32_t DEVICE_CONTROLLER_NUMBER; static const Flags<InputDeviceClass> DEVICE_CLASSES; static const int32_t EVENTHUB_ID; + static const std::optional<bool> INITIAL_PER_WINDOW_INPUT_ROTATION_FLAG_VALUE; std::shared_ptr<FakeEventHub> mFakeEventHub; sp<FakeInputReaderPolicy> mFakePolicy; @@ -2675,11 +2689,19 @@ protected: mDevice = newDevice(DEVICE_ID, DEVICE_NAME, DEVICE_LOCATION, EVENTHUB_ID, classes); } - void SetUp() override { SetUp(DEVICE_CLASSES); } + void SetUp() override { + // Ensure per_window_input_rotation is enabled. + sysprop::InputFlingerProperties::per_window_input_rotation(true); + + SetUp(DEVICE_CLASSES); + } void TearDown() override { mFakeListener.clear(); mFakePolicy.clear(); + + sysprop::InputFlingerProperties::per_window_input_rotation( + INITIAL_PER_WINDOW_INPUT_ROTATION_FLAG_VALUE); } void addConfigurationProperty(const char* key, const char* value) { @@ -2791,6 +2813,8 @@ const int32_t InputMapperTest::DEVICE_CONTROLLER_NUMBER = 0; const Flags<InputDeviceClass> InputMapperTest::DEVICE_CLASSES = Flags<InputDeviceClass>(0); // not needed for current tests const int32_t InputMapperTest::EVENTHUB_ID = 1; +const std::optional<bool> InputMapperTest::INITIAL_PER_WINDOW_INPUT_ROTATION_FLAG_VALUE = + sysprop::InputFlingerProperties::per_window_input_rotation(); // --- SwitchInputMapperTest --- @@ -4087,8 +4111,11 @@ TEST_F(CursorInputMapperTest, Process_ShouldHandleCombinedXYAndButtonUpdates) { ASSERT_NO_FATAL_FAILURE(assertCursorPointerCoords(args.pointerCoords[0], 0.0f, 0.0f, 0.0f)); } -TEST_F(CursorInputMapperTest, Process_WhenNotOrientationAware_ShouldNotRotateMotions) { +TEST_F(CursorInputMapperTest, Process_WhenOrientationAware_ShouldNotRotateMotions) { addConfigurationProperty("cursor.mode", "navigation"); + // InputReader works in the un-rotated coordinate space, so orientation-aware devices do not + // need to be rotated. + addConfigurationProperty("cursor.orientationAware", "1"); CursorInputMapper& mapper = addMapperAndConfigure<CursorInputMapper>(); prepareDisplay(DISPLAY_ORIENTATION_90); @@ -4102,9 +4129,10 @@ TEST_F(CursorInputMapperTest, Process_WhenNotOrientationAware_ShouldNotRotateMot ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 1, -1, 1)); } -TEST_F(CursorInputMapperTest, Process_WhenOrientationAware_ShouldRotateMotions) { +TEST_F(CursorInputMapperTest, Process_WhenNotOrientationAware_ShouldRotateMotions) { addConfigurationProperty("cursor.mode", "navigation"); - addConfigurationProperty("cursor.orientationAware", "1"); + // Since InputReader works in the un-rotated coordinate space, only devices that are not + // orientation-aware are affected by display rotation. CursorInputMapper& mapper = addMapperAndConfigure<CursorInputMapper>(); prepareDisplay(DISPLAY_ORIENTATION_0); @@ -4118,14 +4146,14 @@ TEST_F(CursorInputMapperTest, Process_WhenOrientationAware_ShouldRotateMotions) ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 1, -1, 1)); prepareDisplay(DISPLAY_ORIENTATION_90); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, 1, 1, 0)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 1, 1, -1)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 0, 0, -1)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, -1, -1, -1)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, -1, -1, 0)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, -1, -1, 1)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 0, 0, 1)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 1, 1, 1)); + ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, 1, -1, 0)); + ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 1, -1, 1)); + ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 0, 0, 1)); + ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, -1, 1, 1)); + ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, -1, 1, 0)); + ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, -1, 1, -1)); + ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 0, 0, -1)); + ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 1, -1, -1)); prepareDisplay(DISPLAY_ORIENTATION_180); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, 1, 0, -1)); @@ -4138,14 +4166,14 @@ TEST_F(CursorInputMapperTest, Process_WhenOrientationAware_ShouldRotateMotions) ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 1, 1, -1)); prepareDisplay(DISPLAY_ORIENTATION_270); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, 1, -1, 0)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 1, -1, 1)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 0, 0, 1)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, -1, 1, 1)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, -1, 1, 0)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, -1, 1, -1)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 0, 0, -1)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 1, -1, -1)); + ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, 1, 1, 0)); + ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 1, 1, -1)); + ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 0, 0, -1)); + ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, -1, -1, -1)); + ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, -1, -1, 0)); + ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, -1, -1, 1)); + ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 0, 0, 1)); + ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 1, 1, 1)); } TEST_F(CursorInputMapperTest, Process_ShouldHandleAllButtons) { @@ -4631,6 +4659,8 @@ protected: void prepareLocationCalibration(); int32_t toRawX(float displayX); int32_t toRawY(float displayY); + int32_t toRotatedRawX(float displayX); + int32_t toRotatedRawY(float displayY); float toCookedX(float rawX, float rawY); float toCookedY(float rawX, float rawY); float toDisplayX(int32_t rawX); @@ -4713,6 +4743,14 @@ int32_t TouchInputMapperTest::toRawY(float displayY) { return int32_t(displayY * (RAW_Y_MAX - RAW_Y_MIN + 1) / DISPLAY_HEIGHT + RAW_Y_MIN); } +int32_t TouchInputMapperTest::toRotatedRawX(float displayX) { + return int32_t(displayX * (RAW_X_MAX - RAW_X_MIN + 1) / DISPLAY_HEIGHT + RAW_X_MIN); +} + +int32_t TouchInputMapperTest::toRotatedRawY(float displayY) { + return int32_t(displayY * (RAW_Y_MAX - RAW_Y_MIN + 1) / DISPLAY_WIDTH + RAW_Y_MIN); +} + float TouchInputMapperTest::toCookedX(float rawX, float rawY) { AFFINE_TRANSFORM.applyTo(rawX, rawY); return rawX; @@ -5367,11 +5405,12 @@ TEST_F(SingleTouchInputMapperTest, Process_NormalSingleTouchGesture) { ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled()); } -TEST_F(SingleTouchInputMapperTest, Process_WhenNotOrientationAware_DoesNotRotateMotions) { +TEST_F(SingleTouchInputMapperTest, Process_WhenOrientationAware_DoesNotRotateMotions) { addConfigurationProperty("touch.deviceType", "touchScreen"); prepareButtons(); prepareAxes(POSITION); - addConfigurationProperty("touch.orientationAware", "0"); + // InputReader works in the un-rotated coordinate space, so orientation-aware devices do not + // need to be rotated. Touchscreens are orientation-aware by default. SingleTouchInputMapper& mapper = addMapperAndConfigure<SingleTouchInputMapper>(); NotifyMotionArgs args; @@ -5390,10 +5429,13 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenNotOrientationAware_DoesNotRotate ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled()); } -TEST_F(SingleTouchInputMapperTest, Process_WhenOrientationAware_RotatesMotions) { +TEST_F(SingleTouchInputMapperTest, Process_WhenNotOrientationAware_RotatesMotions) { addConfigurationProperty("touch.deviceType", "touchScreen"); prepareButtons(); prepareAxes(POSITION); + // Since InputReader works in the un-rotated coordinate space, only devices that are not + // orientation-aware are affected by display rotation. + addConfigurationProperty("touch.orientationAware", "0"); SingleTouchInputMapper& mapper = addMapperAndConfigure<SingleTouchInputMapper>(); NotifyMotionArgs args; @@ -5415,7 +5457,7 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenOrientationAware_RotatesMotions) // Rotation 90. clearViewports(); prepareDisplay(DISPLAY_ORIENTATION_90); - processDown(mapper, RAW_X_MAX - toRawX(75) + RAW_X_MIN, toRawY(50)); + processDown(mapper, toRawX(75), RAW_Y_MAX - toRawY(50) + RAW_Y_MIN); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); @@ -5443,7 +5485,7 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenOrientationAware_RotatesMotions) // Rotation 270. clearViewports(); prepareDisplay(DISPLAY_ORIENTATION_270); - processDown(mapper, toRawX(75), RAW_Y_MAX - toRawY(50) + RAW_Y_MIN); + processDown(mapper, RAW_X_MAX - toRawX(75) + RAW_X_MIN, toRawY(50)); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); @@ -5455,6 +5497,172 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenOrientationAware_RotatesMotions) ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled()); } +TEST_F(SingleTouchInputMapperTest, Process_WhenOrientation0_RotatesMotions) { + addConfigurationProperty("touch.deviceType", "touchScreen"); + prepareButtons(); + prepareAxes(POSITION); + addConfigurationProperty("touch.orientationAware", "1"); + addConfigurationProperty("touch.orientation", "ORIENTATION_0"); + clearViewports(); + prepareDisplay(DISPLAY_ORIENTATION_0); + auto& mapper = addMapperAndConfigure<SingleTouchInputMapper>(); + NotifyMotionArgs args; + + // Orientation 0. + processDown(mapper, toRawX(50), toRawY(75)); + processSync(mapper); + + EXPECT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); + EXPECT_NEAR(50, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X), 1); + EXPECT_NEAR(75, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y), 1); + + processUp(mapper); + processSync(mapper); + EXPECT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled()); +} + +TEST_F(SingleTouchInputMapperTest, Process_WhenOrientation90_RotatesMotions) { + addConfigurationProperty("touch.deviceType", "touchScreen"); + prepareButtons(); + prepareAxes(POSITION); + addConfigurationProperty("touch.orientationAware", "1"); + addConfigurationProperty("touch.orientation", "ORIENTATION_90"); + clearViewports(); + prepareDisplay(DISPLAY_ORIENTATION_0); + auto& mapper = addMapperAndConfigure<SingleTouchInputMapper>(); + NotifyMotionArgs args; + + // Orientation 90. + processDown(mapper, RAW_X_MAX - toRotatedRawX(75) + RAW_X_MIN, toRotatedRawY(50)); + processSync(mapper); + + EXPECT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); + EXPECT_NEAR(50, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X), 1); + EXPECT_NEAR(75, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y), 1); + + processUp(mapper); + processSync(mapper); + EXPECT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled()); +} + +TEST_F(SingleTouchInputMapperTest, Process_WhenOrientation180_RotatesMotions) { + addConfigurationProperty("touch.deviceType", "touchScreen"); + prepareButtons(); + prepareAxes(POSITION); + addConfigurationProperty("touch.orientationAware", "1"); + addConfigurationProperty("touch.orientation", "ORIENTATION_180"); + clearViewports(); + prepareDisplay(DISPLAY_ORIENTATION_0); + auto& mapper = addMapperAndConfigure<SingleTouchInputMapper>(); + NotifyMotionArgs args; + + // Orientation 180. + processDown(mapper, RAW_X_MAX - toRawX(50) + RAW_X_MIN, RAW_Y_MAX - toRawY(75) + RAW_Y_MIN); + processSync(mapper); + + EXPECT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); + EXPECT_NEAR(50, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X), 1); + EXPECT_NEAR(75, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y), 1); + + processUp(mapper); + processSync(mapper); + EXPECT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled()); +} + +TEST_F(SingleTouchInputMapperTest, Process_WhenOrientation270_RotatesMotions) { + addConfigurationProperty("touch.deviceType", "touchScreen"); + prepareButtons(); + prepareAxes(POSITION); + addConfigurationProperty("touch.orientationAware", "1"); + addConfigurationProperty("touch.orientation", "ORIENTATION_270"); + clearViewports(); + prepareDisplay(DISPLAY_ORIENTATION_0); + auto& mapper = addMapperAndConfigure<SingleTouchInputMapper>(); + NotifyMotionArgs args; + + // Orientation 270. + processDown(mapper, toRotatedRawX(75), RAW_Y_MAX - toRotatedRawY(50) + RAW_Y_MIN); + processSync(mapper); + + EXPECT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); + EXPECT_NEAR(50, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X), 1); + EXPECT_NEAR(75, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y), 1); + + processUp(mapper); + processSync(mapper); + EXPECT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled()); +} + +TEST_F(SingleTouchInputMapperTest, Process_WhenOrientationSpecified_RotatesMotionWithDisplay) { + addConfigurationProperty("touch.deviceType", "touchScreen"); + prepareButtons(); + prepareAxes(POSITION); + // Since InputReader works in the un-rotated coordinate space, only devices that are not + // orientation-aware are affected by display rotation. + addConfigurationProperty("touch.orientationAware", "0"); + addConfigurationProperty("touch.orientation", "ORIENTATION_90"); + auto& mapper = addMapperAndConfigure<SingleTouchInputMapper>(); + + NotifyMotionArgs args; + + // Orientation 90, Rotation 0. + clearViewports(); + prepareDisplay(DISPLAY_ORIENTATION_0); + processDown(mapper, RAW_X_MAX - toRotatedRawX(75) + RAW_X_MIN, toRotatedRawY(50)); + processSync(mapper); + + EXPECT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); + EXPECT_NEAR(50, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X), 1); + EXPECT_NEAR(75, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y), 1); + + processUp(mapper); + processSync(mapper); + EXPECT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled()); + + // Orientation 90, Rotation 90. + clearViewports(); + prepareDisplay(DISPLAY_ORIENTATION_90); + processDown(mapper, toRotatedRawX(50), toRotatedRawY(75)); + processSync(mapper); + + EXPECT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); + EXPECT_NEAR(50, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X), 1); + EXPECT_NEAR(75, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y), 1); + + processUp(mapper); + processSync(mapper); + EXPECT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled()); + + // Orientation 90, Rotation 180. + clearViewports(); + prepareDisplay(DISPLAY_ORIENTATION_180); + processDown(mapper, toRotatedRawX(75), RAW_Y_MAX - toRotatedRawY(50) + RAW_Y_MIN); + processSync(mapper); + + EXPECT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); + EXPECT_NEAR(50, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X), 1); + EXPECT_NEAR(75, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y), 1); + + processUp(mapper); + processSync(mapper); + EXPECT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled()); + + // Orientation 90, Rotation 270. + clearViewports(); + prepareDisplay(DISPLAY_ORIENTATION_270); + processDown(mapper, RAW_X_MAX - toRotatedRawX(50) + RAW_X_MIN, + RAW_Y_MAX - toRotatedRawY(75) + RAW_Y_MIN); + processSync(mapper); + + EXPECT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); + EXPECT_NEAR(50, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X), 1); + EXPECT_NEAR(75, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y), 1); + + processUp(mapper); + processSync(mapper); + EXPECT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled()); +} + TEST_F(SingleTouchInputMapperTest, Process_AllAxes_DefaultCalibration) { addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); @@ -7805,7 +8013,7 @@ TEST_F(MultiTouchInputMapperTest, VideoFrames_ReceivedByListener) { ASSERT_EQ(std::vector<TouchVideoFrame>(), motionArgs.videoFrames); } -TEST_F(MultiTouchInputMapperTest, VideoFrames_AreRotated) { +TEST_F(MultiTouchInputMapperTest, VideoFrames_AreNotRotated) { prepareAxes(POSITION); addConfigurationProperty("touch.deviceType", "touchScreen"); MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>(); @@ -7815,6 +8023,32 @@ TEST_F(MultiTouchInputMapperTest, VideoFrames_AreRotated) { // Test all 4 orientations for (int32_t orientation : {DISPLAY_ORIENTATION_0, DISPLAY_ORIENTATION_90, + DISPLAY_ORIENTATION_180, DISPLAY_ORIENTATION_270}) { + SCOPED_TRACE("Orientation " + StringPrintf("%i", orientation)); + clearViewports(); + prepareDisplay(orientation); + std::vector<TouchVideoFrame> frames{frame}; + mFakeEventHub->setVideoFrames({{EVENTHUB_ID, frames}}); + processPosition(mapper, 100, 200); + processSync(mapper); + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(frames, motionArgs.videoFrames); + } +} + +TEST_F(MultiTouchInputMapperTest, VideoFrames_WhenNotOrientationAware_AreRotated) { + prepareAxes(POSITION); + addConfigurationProperty("touch.deviceType", "touchScreen"); + // Since InputReader works in the un-rotated coordinate space, only devices that are not + // orientation-aware are affected by display rotation. + addConfigurationProperty("touch.orientationAware", "0"); + MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>(); + // Unrotated video frame + TouchVideoFrame frame(3, 2, {1, 2, 3, 4, 5, 6}, {1, 2}); + NotifyMotionArgs motionArgs; + + // Test all 4 orientations + for (int32_t orientation : {DISPLAY_ORIENTATION_0, DISPLAY_ORIENTATION_90, DISPLAY_ORIENTATION_180, DISPLAY_ORIENTATION_270}) { SCOPED_TRACE("Orientation " + StringPrintf("%i", orientation)); clearViewports(); @@ -7824,12 +8058,16 @@ TEST_F(MultiTouchInputMapperTest, VideoFrames_AreRotated) { processPosition(mapper, 100, 200); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - frames[0].rotate(orientation); + // We expect the raw coordinates of the MotionEvent to be rotated in the inverse direction + // compared to the display. This is so that when the window transform (which contains the + // display rotation) is applied later by InputDispatcher, the coordinates end up in the + // window's coordinate space. + frames[0].rotate(getInverseRotation(orientation)); ASSERT_EQ(frames, motionArgs.videoFrames); } } -TEST_F(MultiTouchInputMapperTest, VideoFrames_MultipleFramesAreRotated) { +TEST_F(MultiTouchInputMapperTest, VideoFrames_MultipleFramesAreNotRotated) { prepareAxes(POSITION); addConfigurationProperty("touch.deviceType", "touchScreen"); MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>(); @@ -7846,8 +8084,36 @@ TEST_F(MultiTouchInputMapperTest, VideoFrames_MultipleFramesAreRotated) { processPosition(mapper, 100, 200); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - std::for_each(frames.begin(), frames.end(), - [](TouchVideoFrame& frame) { frame.rotate(DISPLAY_ORIENTATION_90); }); + ASSERT_EQ(frames, motionArgs.videoFrames); +} + +TEST_F(MultiTouchInputMapperTest, VideoFrames_WhenNotOrientationAware_MultipleFramesAreRotated) { + prepareAxes(POSITION); + addConfigurationProperty("touch.deviceType", "touchScreen"); + // Since InputReader works in the un-rotated coordinate space, only devices that are not + // orientation-aware are affected by display rotation. + addConfigurationProperty("touch.orientationAware", "0"); + MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>(); + // Unrotated video frames. There's no rule that they must all have the same dimensions, + // so mix these. + TouchVideoFrame frame1(3, 2, {1, 2, 3, 4, 5, 6}, {1, 2}); + TouchVideoFrame frame2(3, 3, {0, 1, 2, 3, 4, 5, 6, 7, 8}, {1, 3}); + TouchVideoFrame frame3(2, 2, {10, 20, 10, 0}, {1, 4}); + std::vector<TouchVideoFrame> frames{frame1, frame2, frame3}; + NotifyMotionArgs motionArgs; + + prepareDisplay(DISPLAY_ORIENTATION_90); + mFakeEventHub->setVideoFrames({{EVENTHUB_ID, frames}}); + processPosition(mapper, 100, 200); + processSync(mapper); + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); + std::for_each(frames.begin(), frames.end(), [](TouchVideoFrame& frame) { + // We expect the raw coordinates of the MotionEvent to be rotated in the inverse direction + // compared to the display. This is so that when the window transform (which contains the + // display rotation) is applied later by InputDispatcher, the coordinates end up in the + // window's coordinate space. + frame.rotate(getInverseRotation(DISPLAY_ORIENTATION_90)); + }); ASSERT_EQ(frames, motionArgs.videoFrames); } @@ -8401,18 +8667,25 @@ TEST_F(MultiTouchInputMapperTest_SurfaceRange, Viewports_SurfaceRange) { // Reset. mapper.reset(ARBITRARY_TIME); - // Let physical display be different to device, and make surface and physical could be 1:1. - halfDisplayToCenterHorizontal(DISPLAY_ORIENTATION_0); + // Let physical display be different to device, and make surface and physical could be 1:1 in + // all four orientations. + for (int orientation : {DISPLAY_ORIENTATION_0, DISPLAY_ORIENTATION_90, DISPLAY_ORIENTATION_180, + DISPLAY_ORIENTATION_270}) { + halfDisplayToCenterHorizontal(orientation); - const int32_t xExpected = (x + 1) - (DISPLAY_WIDTH / 4); - const int32_t yExpected = y; - processPositionAndVerify(mapper, x - 1, y, x + 1, y, xExpected, yExpected); + const int32_t xExpected = (x + 1) - (DISPLAY_WIDTH / 4); + const int32_t yExpected = y; + processPositionAndVerify(mapper, x - 1, y, x + 1, y, xExpected, yExpected); + } } -TEST_F(MultiTouchInputMapperTest_SurfaceRange, Viewports_SurfaceRange_90) { +TEST_F(MultiTouchInputMapperTest_SurfaceRange, Viewports_SurfaceRange_90_NotOrientationAware) { addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); prepareAxes(POSITION); + // Since InputReader works in the un-rotated coordinate space, only devices that are not + // orientation-aware are affected by display rotation. + addConfigurationProperty("touch.orientationAware", "0"); MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>(); // Half display to (width/4, 0, width * 3/4, height) and rotate 90-degrees. @@ -8421,16 +8694,19 @@ TEST_F(MultiTouchInputMapperTest_SurfaceRange, Viewports_SurfaceRange_90) { const int32_t x = DISPLAY_WIDTH / 4; const int32_t y = DISPLAY_HEIGHT / 2; - // expect x/y = swap x/y then reverse y. - const int32_t xExpected = y; - const int32_t yExpected = (DISPLAY_WIDTH * 3 / 4) - (x + 1); + // expect x/y = swap x/y then reverse x. + constexpr int32_t xExpected = DISPLAY_HEIGHT - y; + constexpr int32_t yExpected = (x + 1) - DISPLAY_WIDTH / 4; processPositionAndVerify(mapper, x - 1, y, x + 1, y, xExpected, yExpected); } -TEST_F(MultiTouchInputMapperTest_SurfaceRange, Viewports_SurfaceRange_270) { +TEST_F(MultiTouchInputMapperTest_SurfaceRange, Viewports_SurfaceRange_270_NotOrientationAware) { addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); prepareAxes(POSITION); + // Since InputReader works in the un-rotated coordinate space, only devices that are not + // orientation-aware are affected by display rotation. + addConfigurationProperty("touch.orientationAware", "0"); MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>(); // Half display to (width/4, 0, width * 3/4, height) and rotate 270-degrees. @@ -8439,16 +8715,19 @@ TEST_F(MultiTouchInputMapperTest_SurfaceRange, Viewports_SurfaceRange_270) { const int32_t x = DISPLAY_WIDTH / 4; const int32_t y = DISPLAY_HEIGHT / 2; - // expect x/y = swap x/y then reverse x. - constexpr int32_t xExpected = DISPLAY_HEIGHT - y; - constexpr int32_t yExpected = (x + 1) - DISPLAY_WIDTH / 4; + // expect x/y = swap x/y then reverse y. + const int32_t xExpected = y; + const int32_t yExpected = (DISPLAY_WIDTH * 3 / 4) - (x + 1); processPositionAndVerify(mapper, x - 1, y, x + 1, y, xExpected, yExpected); } -TEST_F(MultiTouchInputMapperTest_SurfaceRange, Viewports_SurfaceRange_Corner) { +TEST_F(MultiTouchInputMapperTest_SurfaceRange, Viewports_SurfaceRange_Corner_NotOrientationAware) { addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); prepareAxes(POSITION); + // Since InputReader works in the un-rotated coordinate space, only devices that are not + // orientation-aware are affected by display rotation. + addConfigurationProperty("touch.orientationAware", "0"); MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>(); const int32_t x = 0; @@ -8460,16 +8739,16 @@ TEST_F(MultiTouchInputMapperTest_SurfaceRange, Viewports_SurfaceRange_Corner) { clearViewports(); prepareDisplay(DISPLAY_ORIENTATION_90); - // expect x/y = swap x/y then reverse y. - const int32_t xExpected90 = y; - const int32_t yExpected90 = DISPLAY_WIDTH - 1; + // expect x/y = swap x/y then reverse x. + const int32_t xExpected90 = DISPLAY_HEIGHT - 1; + const int32_t yExpected90 = x; processPositionAndVerify(mapper, x - 1, y, x, y, xExpected90, yExpected90); clearViewports(); prepareDisplay(DISPLAY_ORIENTATION_270); - // expect x/y = swap x/y then reverse x. - const int32_t xExpected270 = DISPLAY_HEIGHT - 1; - const int32_t yExpected270 = x; + // expect x/y = swap x/y then reverse y. + const int32_t xExpected270 = y; + const int32_t yExpected270 = DISPLAY_WIDTH - 1; processPositionAndVerify(mapper, x - 1, y, x, y, xExpected270, yExpected270); } diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp index eb31e92645..eeb3f3a288 100644 --- a/services/surfaceflinger/Android.bp +++ b/services/surfaceflinger/Android.bp @@ -158,6 +158,7 @@ filegroup { "FrameTracer/FrameTracer.cpp", "FrameTracker.cpp", "HdrLayerInfoReporter.cpp", + "WindowInfosListenerInvoker.cpp", "Layer.cpp", "LayerProtoHelper.cpp", "LayerRejecter.cpp", @@ -212,7 +213,6 @@ cc_defaults { "libcutils", "libdisplayservicehidl", "libhidlbase", - "libinput", "liblayers_proto", "liblog", "libprocessgroup", diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp index 23779be73a..71db330f01 100644 --- a/services/surfaceflinger/BufferLayer.cpp +++ b/services/surfaceflinger/BufferLayer.cpp @@ -58,6 +58,8 @@ namespace android { +using gui::WindowInfo; + static constexpr float defaultMaxLuminance = 1000.0; BufferLayer::BufferLayer(const LayerCreationArgs& args) @@ -419,33 +421,35 @@ bool BufferLayer::onPostComposition(const DisplayDevice* display, mFrameTracker.setFrameReadyTime(desiredPresentTime); } - const Fps refreshRate = mFlinger->mRefreshRateConfigs->getCurrentRefreshRate().getFps(); - const std::optional<Fps> renderRate = mFlinger->mScheduler->getFrameRateOverride(getOwnerUid()); - if (presentFence->isValid()) { - mFlinger->mTimeStats->setPresentFence(layerId, mCurrentFrameNumber, presentFence, - refreshRate, renderRate, - frameRateToSetFrameRateVotePayload( - mDrawingState.frameRate), - getGameMode()); - mFlinger->mFrameTracer->traceFence(layerId, getCurrentBufferId(), mCurrentFrameNumber, - presentFence, FrameTracer::FrameEvent::PRESENT_FENCE); - mFrameTracker.setActualPresentFence(std::shared_ptr<FenceTime>(presentFence)); - } else if (!display) { - // Do nothing. - } else if (const auto displayId = PhysicalDisplayId::tryCast(display->getId()); - displayId && mFlinger->getHwComposer().isConnected(*displayId)) { - // The HWC doesn't support present fences, so use the refresh - // timestamp instead. - const nsecs_t actualPresentTime = display->getRefreshTimestamp(); - mFlinger->mTimeStats->setPresentTime(layerId, mCurrentFrameNumber, actualPresentTime, - refreshRate, renderRate, - frameRateToSetFrameRateVotePayload( - mDrawingState.frameRate), - getGameMode()); - mFlinger->mFrameTracer->traceTimestamp(layerId, getCurrentBufferId(), mCurrentFrameNumber, - actualPresentTime, + if (display) { + const Fps refreshRate = display->refreshRateConfigs().getCurrentRefreshRate().getFps(); + const std::optional<Fps> renderRate = + mFlinger->mScheduler->getFrameRateOverride(getOwnerUid()); + if (presentFence->isValid()) { + mFlinger->mTimeStats->setPresentFence(layerId, mCurrentFrameNumber, presentFence, + refreshRate, renderRate, + frameRateToSetFrameRateVotePayload( + mDrawingState.frameRate), + getGameMode()); + mFlinger->mFrameTracer->traceFence(layerId, getCurrentBufferId(), mCurrentFrameNumber, + presentFence, FrameTracer::FrameEvent::PRESENT_FENCE); - mFrameTracker.setActualPresentTime(actualPresentTime); + mFrameTracker.setActualPresentFence(std::shared_ptr<FenceTime>(presentFence)); + } else if (const auto displayId = PhysicalDisplayId::tryCast(display->getId()); + displayId && mFlinger->getHwComposer().isConnected(*displayId)) { + // The HWC doesn't support present fences, so use the refresh + // timestamp instead. + const nsecs_t actualPresentTime = display->getRefreshTimestamp(); + mFlinger->mTimeStats->setPresentTime(layerId, mCurrentFrameNumber, actualPresentTime, + refreshRate, renderRate, + frameRateToSetFrameRateVotePayload( + mDrawingState.frameRate), + getGameMode()); + mFlinger->mFrameTracer->traceTimestamp(layerId, getCurrentBufferId(), + mCurrentFrameNumber, actualPresentTime, + FrameTracer::FrameEvent::PRESENT_FENCE); + mFrameTracker.setActualPresentTime(actualPresentTime); + } } mFrameTracker.advanceFrame(); @@ -825,7 +829,7 @@ void BufferLayer::updateCloneBufferInfo() { wp<Layer> tmpZOrderRelativeOf = mDrawingState.zOrderRelativeOf; SortedVector<wp<Layer>> tmpZOrderRelatives = mDrawingState.zOrderRelatives; wp<Layer> tmpTouchableRegionCrop = mDrawingState.touchableRegionCrop; - InputWindowInfo tmpInputInfo = mDrawingState.inputInfo; + WindowInfo tmpInputInfo = mDrawingState.inputInfo; mDrawingState = clonedFrom->mDrawingState; diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp index 6b6d43425d..99e470dfe6 100644 --- a/services/surfaceflinger/BufferQueueLayer.cpp +++ b/services/surfaceflinger/BufferQueueLayer.cpp @@ -515,13 +515,10 @@ void BufferQueueLayer::onFirstRef() { } status_t BufferQueueLayer::setDefaultBufferProperties(uint32_t w, uint32_t h, PixelFormat format) { - uint32_t const maxSurfaceDims = - std::min(mFlinger->getMaxTextureSize(), mFlinger->getMaxViewportDims()); - // never allow a surface larger than what our underlying GL implementation // can handle. - if ((uint32_t(w) > maxSurfaceDims) || (uint32_t(h) > maxSurfaceDims)) { - ALOGE("dimensions too large %u x %u", uint32_t(w), uint32_t(h)); + if (mFlinger->exceedsMaxRenderTargetSize(w, h)) { + ALOGE("dimensions too large %" PRIu32 " x %" PRIu32, w, h); return BAD_VALUE; } diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index 8bc51dfa5d..cd531d6afc 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -158,7 +158,8 @@ void BufferStateLayer::onLayerDisplayed(const sp<Fence>& releaseFence) { // transaction doesn't need a previous release fence. sp<CallbackHandle> ch; for (auto& handle : mDrawingState.callbackHandles) { - if (handle->releasePreviousBuffer) { + if (handle->releasePreviousBuffer && + mDrawingState.releaseBufferEndpoint == handle->listener) { ch = handle; break; } @@ -199,14 +200,9 @@ void BufferStateLayer::releasePendingBuffer(nsecs_t dequeueReadyTime) { mFlinger->getMaxAcquiredBufferCountForCurrentRefreshRate(mOwnerUid); } - // If there are multiple transactions in this frame, set the previous id on the earliest - // transacton. We don't need to pass in the released buffer id to multiple transactions. - // The buffer id does not have to correspond to any particular transaction as long as the - // listening end point is the same but the client expects the first transaction callback that - // replaces the presented buffer to contain the release fence. This follows the same logic. - // see BufferStateLayer::onLayerDisplayed. for (auto& handle : mDrawingState.callbackHandles) { - if (handle->releasePreviousBuffer) { + if (handle->releasePreviousBuffer && + mDrawingState.releaseBufferEndpoint == handle->listener) { handle->previousReleaseCallbackId = mPreviousReleaseCallbackId; break; } @@ -420,7 +416,8 @@ bool BufferStateLayer::setBuffer(const std::shared_ptr<renderengine::ExternalTex nsecs_t desiredPresentTime, bool isAutoTimestamp, const client_cache_t& clientCacheId, uint64_t frameNumber, std::optional<nsecs_t> dequeueTime, const FrameTimelineInfo& info, - const sp<ITransactionCompletedListener>& releaseBufferListener) { + const sp<ITransactionCompletedListener>& releaseBufferListener, + const sp<IBinder>& releaseBufferEndpoint) { ATRACE_CALL(); if (mDrawingState.buffer) { @@ -485,6 +482,7 @@ bool BufferStateLayer::setBuffer(const std::shared_ptr<renderengine::ExternalTex mDrawingState.width = mDrawingState.buffer->getBuffer()->getWidth(); mDrawingState.height = mDrawingState.buffer->getBuffer()->getHeight(); + mDrawingState.releaseBufferEndpoint = releaseBufferEndpoint; return true; } diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h index cab48994b3..0a0527c1a9 100644 --- a/services/surfaceflinger/BufferStateLayer.h +++ b/services/surfaceflinger/BufferStateLayer.h @@ -59,7 +59,8 @@ public: const sp<Fence>& acquireFence, nsecs_t postTime, nsecs_t desiredPresentTime, bool isAutoTimestamp, const client_cache_t& clientCacheId, uint64_t frameNumber, std::optional<nsecs_t> dequeueTime, const FrameTimelineInfo& info, - const sp<ITransactionCompletedListener>& transactionListener) override; + const sp<ITransactionCompletedListener>& transactionListener, + const sp<IBinder>& releaseBufferEndpoint) override; bool setAcquireFence(const sp<Fence>& fence) override; bool setDataspace(ui::Dataspace dataspace) override; bool setHdrMetadata(const HdrMetadata& hdrMetadata) override; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h index 1416b1e3c0..0ef0b995c3 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h @@ -166,6 +166,9 @@ public: // Enables (or disables) layer caching on this output virtual void setLayerCachingEnabled(bool) = 0; + // Enables (or disables) layer caching texture pool on this output + virtual void setLayerCachingTexturePoolEnabled(bool) = 0; + // Sets the projection state to use virtual void setProjection(ui::Rotation orientation, const Rect& layerStackSpaceRect, const Rect& orientedDisplaySpaceRect) = 0; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h index f832084f39..ddcc907a91 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h @@ -41,6 +41,7 @@ public: std::optional<DisplayId> getDisplayId() const override; void setCompositionEnabled(bool) override; void setLayerCachingEnabled(bool) override; + void setLayerCachingTexturePoolEnabled(bool) override; void setProjection(ui::Rotation orientation, const Rect& layerStackSpaceRect, const Rect& orientedDisplaySpaceRect) override; void setDisplaySize(const ui::Size&) override; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h index 7534548d4a..a040fa93de 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h @@ -38,35 +38,56 @@ class Predictor; class Flattener { public: - struct CachedSetRenderSchedulingTunables { - // This default assumes that rendering a cached set takes about 3ms. That time is then cut - // in half - the next frame using the cached set would have the same workload, meaning that - // composition cost is the same. This is best illustrated with the following example: - // - // Suppose we're at a 120hz cadence so SurfaceFlinger is budgeted 8.3ms per-frame. If - // renderCachedSets costs 3ms, then two consecutive frames have timings: - // - // First frame: Start at 0ms, end at 6.8ms. - // renderCachedSets: Start at 6.8ms, end at 9.8ms. - // Second frame: Start at 9.8ms, end at 16.6ms. - // - // Now the second frame won't render a cached set afterwards, but the first frame didn't - // really steal time from the second frame. - static const constexpr std::chrono::nanoseconds kDefaultCachedSetRenderDuration = 1500us; - - static const constexpr size_t kDefaultMaxDeferRenderAttempts = 240; - - // Duration allocated for rendering a cached set. If we don't have enough time for rendering - // a cached set, then rendering is deferred to another frame. - const std::chrono::nanoseconds cachedSetRenderDuration; - // Maximum of times that we defer rendering a cached set. If we defer rendering a cached set - // too many times, then render it anyways so that future frames would benefit from the - // flattened cached set. - const size_t maxDeferRenderAttempts; + // Collection of tunables which are backed by sysprops + struct Tunables { + // Tunables that are specific to scheduling when a cached set should be rendered + struct RenderScheduling { + // This default assumes that rendering a cached set takes about 3ms. That time is then + // cut in half - the next frame using the cached set would have the same workload, + // meaning that composition cost is the same. This is best illustrated with the + // following example: + // + // Suppose we're at a 120hz cadence so SurfaceFlinger is budgeted 8.3ms per-frame. If + // renderCachedSets costs 3ms, then two consecutive frames have timings: + // + // First frame: Start at 0ms, end at 6.8ms. + // renderCachedSets: Start at 6.8ms, end at 9.8ms. + // Second frame: Start at 9.8ms, end at 16.6ms. + // + // Now the second frame won't render a cached set afterwards, but the first frame didn't + // really steal time from the second frame. + static const constexpr std::chrono::nanoseconds kDefaultCachedSetRenderDuration = + 1500us; + + static const constexpr size_t kDefaultMaxDeferRenderAttempts = 240; + + // Duration allocated for rendering a cached set. If we don't have enough time for + // rendering a cached set, then rendering is deferred to another frame. + const std::chrono::nanoseconds cachedSetRenderDuration; + // Maximum of times that we defer rendering a cached set. If we defer rendering a cached + // set too many times, then render it anyways so that future frames would benefit from + // the flattened cached set. + const size_t maxDeferRenderAttempts; + }; + + static const constexpr std::chrono::milliseconds kDefaultActiveLayerTimeout = 150ms; + + static const constexpr bool kDefaultEnableHolePunch = true; + + // Threshold for determing whether a layer is active. A layer whose properties, including + // the buffer, have not changed in at least this time is considered inactive and is + // therefore a candidate for flattening. + const std::chrono::milliseconds mActiveLayerTimeout; + + // Toggles for scheduling when it's safe to render a cached set. + // See: RenderScheduling + const std::optional<RenderScheduling> mRenderScheduling; + + // True if the hole punching feature should be enabled. + const bool mEnableHolePunch; }; - Flattener(renderengine::RenderEngine& renderEngine, bool enableHolePunch = false, - std::optional<CachedSetRenderSchedulingTunables> cachedSetRenderSchedulingTunables = - std::nullopt); + + Flattener(renderengine::RenderEngine& renderEngine, const Tunables& tunables); void setDisplaySize(ui::Size size) { mDisplaySize = size; @@ -80,6 +101,8 @@ public: void renderCachedSets(const OutputCompositionState& outputState, std::optional<std::chrono::steady_clock::time_point> renderDeadline); + void setTexturePoolEnabled(bool enabled) { mTexturePool.setEnabled(enabled); } + void dump(std::string& result) const; void dumpLayers(std::string& result) const; @@ -175,8 +198,7 @@ private: void buildCachedSets(std::chrono::steady_clock::time_point now); renderengine::RenderEngine& mRenderEngine; - const bool mEnableHolePunch; - const std::optional<CachedSetRenderSchedulingTunables> mCachedSetRenderSchedulingTunables; + const Tunables mTunables; TexturePool mTexturePool; @@ -200,9 +222,6 @@ private: size_t mCachedSetCreationCount = 0; size_t mCachedSetCreationCost = 0; std::unordered_map<size_t, size_t> mInvalidatedCachedSetAges; - std::chrono::nanoseconds mActiveLayerTimeout = kActiveLayerTimeout; - - static constexpr auto kActiveLayerTimeout = std::chrono::nanoseconds(150ms); }; } // namespace compositionengine::impl::planner diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h index bce438fa13..523752719d 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h @@ -21,7 +21,7 @@ #include <compositionengine/LayerFECompositionState.h> #include <compositionengine/OutputLayer.h> #include <compositionengine/impl/OutputLayerCompositionState.h> -#include <input/Flags.h> +#include <ftl/Flags.h> #include <string> diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Planner.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Planner.h index be34153d31..b7ebca60fd 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Planner.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Planner.h @@ -39,6 +39,9 @@ namespace compositionengine::impl::planner { // heuristically determining the composition strategy of the current layer stack, // and flattens inactive layers into an override buffer so it can be used // as a more efficient representation of parts of the layer stack. +// Implicitly, layer caching must also be enabled for the Planner to have any effect +// E.g., setprop debug.sf.enable_layer_caching 1, or +// adb shell service call SurfaceFlinger 1040 i32 1 [i64 <display ID>] class Planner { public: Planner(renderengine::RenderEngine& renderengine); @@ -64,6 +67,8 @@ public: void renderCachedSets(const OutputCompositionState& outputState, std::optional<std::chrono::steady_clock::time_point> renderDeadline); + void setTexturePoolEnabled(bool enabled) { mFlattener.setTexturePoolEnabled(enabled); } + void dump(const Vector<String16>& args, std::string&); private: diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/TexturePool.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/TexturePool.h index fb53ee04cd..d607c75325 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/TexturePool.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/TexturePool.h @@ -63,7 +63,8 @@ public: sp<Fence> mFence; }; - TexturePool(renderengine::RenderEngine& renderEngine) : mRenderEngine(renderEngine) {} + TexturePool(renderengine::RenderEngine& renderEngine) + : mRenderEngine(renderEngine), mEnabled(false) {} virtual ~TexturePool() = default; @@ -78,6 +79,12 @@ public: // to the pool. std::shared_ptr<AutoTexture> borrowTexture(); + // Enables or disables the pool. When the pool is disabled, no buffers will + // be held by the pool. This is useful when the active display changes. + void setEnabled(bool enable); + + void dump(std::string& out) const; + protected: // Proteted visibility so that they can be used for testing const static constexpr size_t kMinPoolSize = 3; @@ -95,8 +102,10 @@ private: // Returns a previously borrowed texture to the pool. void returnTexture(std::shared_ptr<renderengine::ExternalTexture>&& texture, const sp<Fence>& fence); + void allocatePool(); renderengine::RenderEngine& mRenderEngine; ui::Size mSize; + bool mEnabled; }; } // namespace android::compositionengine::impl::planner diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h index 8e777e3c9f..8fdf3ae887 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h @@ -37,6 +37,7 @@ public: MOCK_METHOD1(setCompositionEnabled, void(bool)); MOCK_METHOD1(setLayerCachingEnabled, void(bool)); + MOCK_METHOD1(setLayerCachingTexturePoolEnabled, void(bool)); MOCK_METHOD3(setProjection, void(ui::Rotation, const Rect&, const Rect&)); MOCK_METHOD1(setDisplaySize, void(const ui::Size&)); MOCK_METHOD2(setLayerStackFilter, void(uint32_t, bool)); diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp index cafcb40e80..95ae5e514e 100644 --- a/services/surfaceflinger/CompositionEngine/src/Output.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp @@ -146,6 +146,12 @@ void Output::setLayerCachingEnabled(bool enabled) { } } +void Output::setLayerCachingTexturePoolEnabled(bool enabled) { + if (mPlanner) { + mPlanner->setTexturePoolEnabled(enabled); + } +} + void Output::setProjection(ui::Rotation orientation, const Rect& layerStackSpaceRect, const Rect& orientedDisplaySpaceRect) { auto& outputState = editState(); @@ -783,6 +789,9 @@ compositionengine::OutputLayer* Output::findLayerRequestingBackgroundComposition if (compState->sidebandStream != nullptr) { return nullptr; } + if (compState->isOpaque) { + continue; + } if (compState->backgroundBlurRadius > 0 || compState->blurRegions.size() > 0) { layerRequestingBgComposition = layer; } diff --git a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp index f033279caa..ad5e93168d 100644 --- a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp +++ b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp @@ -60,19 +60,8 @@ bool isSameStack(const std::vector<const LayerState*>& incomingLayers, } // namespace -Flattener::Flattener( - renderengine::RenderEngine& renderEngine, bool enableHolePunch, - std::optional<CachedSetRenderSchedulingTunables> cachedSetRenderSchedulingTunables) - : mRenderEngine(renderEngine), - mEnableHolePunch(enableHolePunch), - mCachedSetRenderSchedulingTunables(cachedSetRenderSchedulingTunables), - mTexturePool(mRenderEngine) { - const int timeoutInMs = - base::GetIntProperty(std::string("debug.sf.layer_caching_active_layer_timeout_ms"), 0); - if (timeoutInMs != 0) { - mActiveLayerTimeout = std::chrono::milliseconds(timeoutInMs); - } -} +Flattener::Flattener(renderengine::RenderEngine& renderEngine, const Tunables& tunables) + : mRenderEngine(renderEngine), mTunables(tunables), mTexturePool(mRenderEngine) {} NonBufferHash Flattener::flattenLayers(const std::vector<const LayerState*>& layers, NonBufferHash hash, time_point now) { @@ -128,14 +117,14 @@ void Flattener::renderCachedSets( // If we have a render deadline, and the flattener is configured to skip rendering if we don't // have enough time, then we skip rendering the cached set if we think that we'll steal too much // time from the next frame. - if (renderDeadline && mCachedSetRenderSchedulingTunables) { + if (renderDeadline && mTunables.mRenderScheduling) { if (const auto estimatedRenderFinish = - now + mCachedSetRenderSchedulingTunables->cachedSetRenderDuration; + now + mTunables.mRenderScheduling->cachedSetRenderDuration; estimatedRenderFinish > *renderDeadline) { mNewCachedSet->incrementSkipCount(); if (mNewCachedSet->getSkipCount() <= - mCachedSetRenderSchedulingTunables->maxDeferRenderAttempts) { + mTunables.mRenderScheduling->maxDeferRenderAttempts) { ATRACE_FORMAT("DeadlinePassed: exceeded deadline by: %d us", std::chrono::duration_cast<std::chrono::microseconds>( estimatedRenderFinish - *renderDeadline) @@ -205,6 +194,9 @@ void Flattener::dump(std::string& result) const { durationString(lastUpdate).c_str()); dumpLayers(result); + + base::StringAppendF(&result, "\n"); + mTexturePool.dump(result); } size_t Flattener::calculateDisplayCost(const std::vector<const LayerState*>& layers) const { @@ -417,8 +409,10 @@ std::vector<Flattener::Run> Flattener::findCandidateRuns(time_point now) const { bool runHasFirstLayer = false; for (auto currentSet = mLayers.cbegin(); currentSet != mLayers.cend(); ++currentSet) { - const bool layerIsInactive = now - currentSet->getLastUpdate() > mActiveLayerTimeout; + const bool layerIsInactive = + now - currentSet->getLastUpdate() > mTunables.mActiveLayerTimeout; const bool layerHasBlur = currentSet->hasBlurBehind(); + if (layerIsInactive && (firstLayer || runHasFirstLayer || !layerHasBlur) && !currentSet->hasUnsupportedDataspace()) { if (isPartOfRun) { @@ -519,7 +513,7 @@ void Flattener::buildCachedSets(time_point now) { mNewCachedSet->addBackgroundBlurLayer(*bestRun->getBlurringLayer()); } - if (mEnableHolePunch && bestRun->getHolePunchCandidate() && + if (mTunables.mEnableHolePunch && bestRun->getHolePunchCandidate() && bestRun->getHolePunchCandidate()->requiresHolePunch()) { // Add the pip layer to mNewCachedSet, but in a special way - it should // replace the buffer with a clear round rect. diff --git a/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp b/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp index f077470c80..f5b1cee469 100644 --- a/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp +++ b/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp @@ -32,36 +32,46 @@ namespace android::compositionengine::impl::planner { namespace { -std::optional<Flattener::CachedSetRenderSchedulingTunables> buildFlattenerTuneables() { +std::optional<Flattener::Tunables::RenderScheduling> buildRenderSchedulingTunables() { if (!base::GetBoolProperty(std::string("debug.sf.enable_cached_set_render_scheduling"), true)) { return std::nullopt; } - auto renderDuration = std::chrono::nanoseconds( + const auto renderDuration = std::chrono::nanoseconds( base::GetUintProperty<uint64_t>(std::string("debug.sf.cached_set_render_duration_ns"), - Flattener::CachedSetRenderSchedulingTunables:: + Flattener::Tunables::RenderScheduling:: kDefaultCachedSetRenderDuration.count())); - auto maxDeferRenderAttempts = base::GetUintProperty< + const auto maxDeferRenderAttempts = base::GetUintProperty< size_t>(std::string("debug.sf.cached_set_max_defer_render_attmpts"), - Flattener::CachedSetRenderSchedulingTunables::kDefaultMaxDeferRenderAttempts); + Flattener::Tunables::RenderScheduling::kDefaultMaxDeferRenderAttempts); - return std::make_optional<Flattener::CachedSetRenderSchedulingTunables>( - Flattener::CachedSetRenderSchedulingTunables{ + return std::make_optional<Flattener::Tunables::RenderScheduling>( + Flattener::Tunables::RenderScheduling{ .cachedSetRenderDuration = renderDuration, .maxDeferRenderAttempts = maxDeferRenderAttempts, }); } +Flattener::Tunables buildFlattenerTuneables() { + const auto activeLayerTimeout = std::chrono::milliseconds( + base::GetIntProperty<int32_t>(std::string( + "debug.sf.layer_caching_active_layer_timeout_ms"), + Flattener::Tunables::kDefaultActiveLayerTimeout.count())); + const auto enableHolePunch = + base::GetBoolProperty(std::string("debug.sf.enable_hole_punch_pip"), + Flattener::Tunables::kDefaultEnableHolePunch); + return Flattener::Tunables{ + .mActiveLayerTimeout = activeLayerTimeout, + .mRenderScheduling = buildRenderSchedulingTunables(), + .mEnableHolePunch = enableHolePunch, + }; +} + } // namespace Planner::Planner(renderengine::RenderEngine& renderEngine) - // Implicitly, layer caching must also be enabled for the hole punch or - // predictor to have any effect. - // E.g., setprop debug.sf.enable_layer_caching 1, or - // adb shell service call SurfaceFlinger 1040 i32 1 [i64 <display ID>] : mFlattener(renderEngine, - base::GetBoolProperty(std::string("debug.sf.enable_hole_punch_pip"), true), buildFlattenerTuneables()) { mPredictorEnabled = base::GetBoolProperty(std::string("debug.sf.enable_planner_prediction"), false); diff --git a/services/surfaceflinger/CompositionEngine/src/planner/TexturePool.cpp b/services/surfaceflinger/CompositionEngine/src/planner/TexturePool.cpp index e3772a22d2..497c433c76 100644 --- a/services/surfaceflinger/CompositionEngine/src/planner/TexturePool.cpp +++ b/services/surfaceflinger/CompositionEngine/src/planner/TexturePool.cpp @@ -24,14 +24,22 @@ namespace android::compositionengine::impl::planner { +void TexturePool::allocatePool() { + mPool.clear(); + if (mEnabled && mSize.isValid()) { + mPool.resize(kMinPoolSize); + std::generate_n(mPool.begin(), kMinPoolSize, [&]() { + return Entry{genTexture(), nullptr}; + }); + } +} + void TexturePool::setDisplaySize(ui::Size size) { if (mSize == size) { return; } mSize = size; - mPool.clear(); - mPool.resize(kMinPoolSize); - std::generate_n(mPool.begin(), kMinPoolSize, [&]() { return Entry{genTexture(), nullptr}; }); + allocatePool(); } std::shared_ptr<TexturePool::AutoTexture> TexturePool::borrowTexture() { @@ -46,7 +54,12 @@ std::shared_ptr<TexturePool::AutoTexture> TexturePool::borrowTexture() { void TexturePool::returnTexture(std::shared_ptr<renderengine::ExternalTexture>&& texture, const sp<Fence>& fence) { - // Drop the texture on the floor if the pool is no longer tracking textures of the same size. + // Drop the texture on the floor if the pool is not enabled + if (!mEnabled) { + return; + } + + // Or the texture on the floor if the pool is no longer tracking textures of the same size. if (static_cast<int32_t>(texture->getBuffer()->getWidth()) != mSize.getWidth() || static_cast<int32_t>(texture->getBuffer()->getHeight()) != mSize.getHeight()) { ALOGV("Deallocating texture from Planner's pool - display size changed (previous: (%dx%d), " @@ -81,4 +94,15 @@ std::shared_ptr<renderengine::ExternalTexture> TexturePool::genTexture() { renderengine::ExternalTexture::Usage::WRITEABLE); } +void TexturePool::setEnabled(bool enabled) { + mEnabled = enabled; + allocatePool(); +} + +void TexturePool::dump(std::string& out) const { + base::StringAppendF(&out, + "TexturePool (%s) has %zu buffers of size [%" PRId32 ", %" PRId32 "]\n", + mEnabled ? "enabled" : "disabled", mPool.size(), mSize.width, mSize.height); +} + } // namespace android::compositionengine::impl::planner
\ No newline at end of file diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h index a195e5808a..ada5adfa12 100644 --- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h +++ b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h @@ -47,9 +47,7 @@ public: MOCK_CONST_METHOD0(getMaxVirtualDisplayCount, size_t()); MOCK_CONST_METHOD0(getMaxVirtualDisplayDimension, size_t()); - MOCK_METHOD4(allocateVirtualDisplay, - bool(HalVirtualDisplayId, ui::Size, ui::PixelFormat*, - std::optional<PhysicalDisplayId>)); + MOCK_METHOD3(allocateVirtualDisplay, bool(HalVirtualDisplayId, ui::Size, ui::PixelFormat*)); MOCK_METHOD2(allocatePhysicalDisplay, void(hal::HWDisplayId, PhysicalDisplayId)); MOCK_METHOD1(createLayer, std::shared_ptr<HWC2::Layer>(HalDisplayId)); MOCK_METHOD5(getDeviceCompositionChanges, diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp index ee73cfc0c1..09f5a5e51d 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp @@ -3606,6 +3606,7 @@ struct OutputComposeSurfacesTest_SetsExpensiveRendering_ForBlur : public OutputComposeSurfacesTest_SetsExpensiveRendering { OutputComposeSurfacesTest_SetsExpensiveRendering_ForBlur() { mLayer.layerFEState.backgroundBlurRadius = 10; + mLayer.layerFEState.isOpaque = false; mOutput.editState().isEnabled = true; EXPECT_CALL(mLayer.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0)); @@ -4225,6 +4226,37 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, kDisplayDataspace)); } +TEST_F(OutputUpdateAndWriteCompositionStateTest, noBackgroundBlurWhenOpaque) { + InjectedLayer layer1; + InjectedLayer layer2; + + uint32_t z = 0; + // Layer requesting blur, or below, should request client composition, unless opaque. + EXPECT_CALL(*layer1.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_0)); + EXPECT_CALL(*layer1.outputLayer, + writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, + /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); + EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_0)); + EXPECT_CALL(*layer2.outputLayer, + writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, + /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); + + layer2.layerFEState.backgroundBlurRadius = 10; + layer2.layerFEState.isOpaque = true; + + injectOutputLayer(layer1); + injectOutputLayer(layer2); + + mOutput->editState().isEnabled = true; + + CompositionRefreshArgs args; + args.updatingGeometryThisFrame = false; + args.devOptForceClientComposition = false; + mOutput->updateCompositionState(args); + mOutput->planComposition(); + mOutput->writeCompositionState(args); +} + TEST_F(OutputUpdateAndWriteCompositionStateTest, handlesBackgroundBlurRequests) { InjectedLayer layer1; InjectedLayer layer2; @@ -4246,6 +4278,7 @@ TEST_F(OutputUpdateAndWriteCompositionStateTest, handlesBackgroundBlurRequests) /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); layer2.layerFEState.backgroundBlurRadius = 10; + layer2.layerFEState.isOpaque = false; injectOutputLayer(layer1); injectOutputLayer(layer2); @@ -4283,6 +4316,7 @@ TEST_F(OutputUpdateAndWriteCompositionStateTest, handlesBlurRegionRequests) { BlurRegion region; layer2.layerFEState.blurRegions.push_back(region); + layer2.layerFEState.isOpaque = false; injectOutputLayer(layer1); injectOutputLayer(layer2); diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp index f5cfd2f115..a28fb2c652 100644 --- a/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp @@ -47,23 +47,24 @@ namespace { class TestableFlattener : public Flattener { public: - TestableFlattener(renderengine::RenderEngine& renderEngine, bool enableHolePunch, - std::optional<Flattener::CachedSetRenderSchedulingTunables> - cachedSetRenderSchedulingTunables = std::nullopt) - : Flattener(renderEngine, enableHolePunch, cachedSetRenderSchedulingTunables) {} + TestableFlattener(renderengine::RenderEngine& renderEngine, const Tunables& tunables) + : Flattener(renderEngine, tunables) {} const std::optional<CachedSet>& getNewCachedSetForTesting() const { return mNewCachedSet; } }; class FlattenerTest : public testing::Test { public: - FlattenerTest() : FlattenerTest(std::nullopt) {} + FlattenerTest() + : FlattenerTest(Flattener::Tunables{ + .mActiveLayerTimeout = 100ms, + .mRenderScheduling = std::nullopt, + .mEnableHolePunch = true, + }) {} void SetUp() override; protected: - FlattenerTest(std::optional<Flattener::CachedSetRenderSchedulingTunables> - cachedSetRenderSchedulingTunables) - : mFlattener(std::make_unique<TestableFlattener>(mRenderEngine, true, - cachedSetRenderSchedulingTunables)) {} + FlattenerTest(const Flattener::Tunables& tunables) + : mFlattener(std::make_unique<TestableFlattener>(mRenderEngine, tunables)) {} void initializeOverrideBuffer(const std::vector<const LayerState*>& layers); void initializeFlattener(const std::vector<const LayerState*>& layers); void expectAllLayersFlattened(const std::vector<const LayerState*>& layers); @@ -899,11 +900,13 @@ class FlattenerRenderSchedulingTest : public FlattenerTest { public: FlattenerRenderSchedulingTest() : FlattenerTest( - Flattener::CachedSetRenderSchedulingTunables{.cachedSetRenderDuration = + Flattener::Tunables{.mActiveLayerTimeout = 100ms, + .mRenderScheduling = Flattener::Tunables:: + RenderScheduling{.cachedSetRenderDuration = kCachedSetRenderDuration, .maxDeferRenderAttempts = - kMaxDeferRenderAttempts}) { - } + kMaxDeferRenderAttempts}, + .mEnableHolePunch = true}) {} }; TEST_F(FlattenerRenderSchedulingTest, flattenLayers_renderCachedSets_defersUpToMaxAttempts) { diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/TexturePoolTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/TexturePoolTest.cpp index b802e51234..6fc90fe5e5 100644 --- a/services/surfaceflinger/CompositionEngine/tests/planner/TexturePoolTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/planner/TexturePoolTest.cpp @@ -42,6 +42,7 @@ struct TexturePoolTest : public testing::Test { const ::testing::TestInfo* const test_info = ::testing::UnitTest::GetInstance()->current_test_info(); ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name()); + mTexturePool.setEnabled(true); mTexturePool.setDisplaySize(kDisplaySize); } @@ -130,5 +131,44 @@ TEST_F(TexturePoolTest, reallocatesWhenDisplaySizeChanges) { static_cast<int32_t>(texture->get()->getBuffer()->getHeight())); } +TEST_F(TexturePoolTest, freesBuffersWhenDisabled) { + EXPECT_EQ(mTexturePool.getPoolSize(), mTexturePool.getMinPoolSize()); + + std::deque<std::shared_ptr<TexturePool::AutoTexture>> textures; + for (size_t i = 0; i < mTexturePool.getMinPoolSize() - 1; i++) { + textures.emplace_back(mTexturePool.borrowTexture()); + } + + EXPECT_EQ(mTexturePool.getPoolSize(), 1u); + mTexturePool.setEnabled(false); + EXPECT_EQ(mTexturePool.getPoolSize(), 0u); + + textures.clear(); + EXPECT_EQ(mTexturePool.getPoolSize(), 0u); +} + +TEST_F(TexturePoolTest, doesNotHoldBuffersWhenDisabled) { + EXPECT_EQ(mTexturePool.getPoolSize(), mTexturePool.getMinPoolSize()); + mTexturePool.setEnabled(false); + EXPECT_EQ(mTexturePool.getPoolSize(), 0u); + + std::deque<std::shared_ptr<TexturePool::AutoTexture>> textures; + for (size_t i = 0; i < mTexturePool.getMinPoolSize() - 1; i++) { + textures.emplace_back(mTexturePool.borrowTexture()); + } + + EXPECT_EQ(mTexturePool.getPoolSize(), 0u); + textures.clear(); + EXPECT_EQ(mTexturePool.getPoolSize(), 0u); +} + +TEST_F(TexturePoolTest, reallocatesWhenReEnabled) { + EXPECT_EQ(mTexturePool.getPoolSize(), mTexturePool.getMinPoolSize()); + mTexturePool.setEnabled(false); + EXPECT_EQ(mTexturePool.getPoolSize(), 0u); + mTexturePool.setEnabled(true); + EXPECT_EQ(mTexturePool.getPoolSize(), mTexturePool.getMinPoolSize()); +} + } // namespace } // namespace android::compositionengine::impl::planner diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index ca4b6abc03..4445eea604 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -22,6 +22,8 @@ #undef LOG_TAG #define LOG_TAG "DisplayDevice" +#define ATRACE_TAG ATRACE_TAG_GRAPHICS + #include <android-base/stringprintf.h> #include <compositionengine/CompositionEngine.h> #include <compositionengine/Display.h> @@ -40,6 +42,7 @@ #include "DisplayDevice.h" #include "Layer.h" +#include "RefreshRateOverlay.h" #include "SurfaceFlinger.h" namespace android { @@ -65,9 +68,12 @@ DisplayDevice::DisplayDevice(DisplayDeviceCreationArgs& args) mSequenceId(args.sequenceId), mConnectionType(args.connectionType), mCompositionDisplay{args.compositionDisplay}, + mActiveModeFPSTrace("ActiveModeFPS -" + to_string(getId())), + mActiveModeFPSHwcTrace("ActiveModeFPS_HWC -" + to_string(getId())), mPhysicalOrientation(args.physicalOrientation), mSupportedModes(std::move(args.supportedModes)), - mIsPrimary(args.isPrimary) { + mIsPrimary(args.isPrimary), + mRefreshRateConfigs(std::move(args.refreshRateConfigs)) { mCompositionDisplay->editState().isSecure = args.isSecure; mCompositionDisplay->createRenderSurface( compositionengine::RenderSurfaceCreationArgsBuilder() @@ -154,20 +160,29 @@ bool DisplayDevice::isPoweredOn() const { void DisplayDevice::setActiveMode(DisplayModeId id) { const auto mode = getMode(id); LOG_FATAL_IF(!mode, "Cannot set active mode which is not supported."); + ATRACE_INT(mActiveModeFPSTrace.c_str(), mode->getFps().getIntValue()); mActiveMode = mode; + if (mRefreshRateConfigs) { + mRefreshRateConfigs->setCurrentModeId(mActiveMode->getId()); + } + if (mRefreshRateOverlay) { + mRefreshRateOverlay->changeRefreshRate(mActiveMode->getFps()); + } } -status_t DisplayDevice::initiateModeChange(DisplayModeId modeId, +status_t DisplayDevice::initiateModeChange(const ActiveModeInfo& info, const hal::VsyncPeriodChangeConstraints& constraints, - hal::VsyncPeriodChangeTimeline* outTimeline) const { - const auto mode = getMode(modeId); - if (!mode) { + hal::VsyncPeriodChangeTimeline* outTimeline) { + if (!info.mode || info.mode->getPhysicalDisplayId() != getPhysicalId()) { ALOGE("Trying to initiate a mode change to invalid mode %s on display %s", - std::to_string(modeId.value()).c_str(), to_string(getId()).c_str()); + info.mode ? std::to_string(info.mode->getId().value()).c_str() : "null", + to_string(getId()).c_str()); return BAD_VALUE; } - return mHwComposer.setActiveModeWithConstraints(getPhysicalId(), mode->getHwcId(), constraints, - outTimeline); + mUpcomingActiveMode = info; + ATRACE_INT(mActiveModeFPSHwcTrace.c_str(), info.mode->getFps().getIntValue()); + return mHwComposer.setActiveModeWithConstraints(getPhysicalId(), info.mode->getHwcId(), + constraints, outTimeline); } const DisplayModePtr& DisplayDevice::getActiveMode() const { @@ -217,12 +232,23 @@ ui::Dataspace DisplayDevice::getCompositionDataSpace() const { } void DisplayDevice::setLayerStack(ui::LayerStack stack) { - mCompositionDisplay->setLayerStackFilter(stack, isPrimary()); + mCompositionDisplay->setLayerStackFilter(stack, isInternal()); + if (mRefreshRateOverlay) { + mRefreshRateOverlay->setLayerStack(stack); + } +} + +void DisplayDevice::setFlags(uint32_t flags) { + mFlags = flags; } void DisplayDevice::setDisplaySize(int width, int height) { LOG_FATAL_IF(!isVirtual(), "Changing the display size is supported only for virtual displays."); - mCompositionDisplay->setDisplaySize(ui::Size(width, height)); + const auto size = ui::Size(width, height); + mCompositionDisplay->setDisplaySize(size); + if (mRefreshRateOverlay) { + mRefreshRateOverlay->setViewport(size); + } } void DisplayDevice::setProjection(ui::Rotation orientation, Rect layerStackSpaceRect, @@ -262,7 +288,7 @@ ui::Transform::RotationFlags DisplayDevice::getPrimaryDisplayRotationFlags() { std::string DisplayDevice::getDebugName() const { const char* type = "virtual"; if (mConnectionType) { - type = *mConnectionType == ui::DisplayConnectionType::Internal ? "internal" : "external"; + type = isInternal() ? "internal" : "external"; } return base::StringPrintf("DisplayDevice{%s, %s%s, \"%s\"}", to_string(getId()).c_str(), type, @@ -292,6 +318,10 @@ void DisplayDevice::dump(std::string& result) const { } result.append("\n"); getCompositionDisplay()->dump(result); + + if (mRefreshRateConfigs) { + mRefreshRateConfigs->dump(result); + } } bool DisplayDevice::hasRenderIntent(ui::RenderIntent intent) const { @@ -378,6 +408,80 @@ HdrCapabilities DisplayDevice::getHdrCapabilities() const { capabilities.getDesiredMinLuminance()); } +void DisplayDevice::enableRefreshRateOverlay(bool enable, bool showSpinnner) { + if (!enable) { + mRefreshRateOverlay.reset(); + return; + } + + const auto [lowFps, highFps] = mRefreshRateConfigs->getSupportedRefreshRateRange(); + mRefreshRateOverlay = std::make_unique<RefreshRateOverlay>(*mFlinger, lowFps.getIntValue(), + highFps.getIntValue(), showSpinnner); + mRefreshRateOverlay->setLayerStack(getLayerStack()); + mRefreshRateOverlay->setViewport(getSize()); + mRefreshRateOverlay->changeRefreshRate(getActiveMode()->getFps()); +} + +bool DisplayDevice::onKernelTimerChanged(std::optional<DisplayModeId> desiredModeId, + bool timerExpired) { + if (mRefreshRateConfigs && mRefreshRateOverlay) { + const auto newRefreshRate = + mRefreshRateConfigs->onKernelTimerChanged(desiredModeId, timerExpired); + if (newRefreshRate) { + mRefreshRateOverlay->changeRefreshRate(*newRefreshRate); + return true; + } + } + + return false; +} + +void DisplayDevice::onInvalidate() { + if (mRefreshRateOverlay) { + mRefreshRateOverlay->onInvalidate(); + } +} + +bool DisplayDevice::setDesiredActiveMode(const ActiveModeInfo& info) { + ATRACE_CALL(); + + LOG_ALWAYS_FATAL_IF(!info.mode, "desired mode not provided"); + LOG_ALWAYS_FATAL_IF(getPhysicalId() != info.mode->getPhysicalDisplayId(), "DisplayId mismatch"); + + ALOGV("%s(%s)", __func__, to_string(*info.mode).c_str()); + + std::scoped_lock lock(mActiveModeLock); + if (mDesiredActiveModeChanged) { + // If a mode change is pending, just cache the latest request in mDesiredActiveMode + const Scheduler::ModeEvent prevConfig = mDesiredActiveMode.event; + mDesiredActiveMode = info; + mDesiredActiveMode.event = mDesiredActiveMode.event | prevConfig; + return false; + } + + // Check if we are already at the desired mode + if (getActiveMode()->getId() == info.mode->getId()) { + return false; + } + + // Initiate a mode change. + mDesiredActiveModeChanged = true; + mDesiredActiveMode = info; + return true; +} + +std::optional<DisplayDevice::ActiveModeInfo> DisplayDevice::getDesiredActiveMode() const { + std::scoped_lock lock(mActiveModeLock); + if (mDesiredActiveModeChanged) return mDesiredActiveMode; + return std::nullopt; +} + +void DisplayDevice::clearDesiredActiveModeState() { + std::scoped_lock lock(mActiveModeLock); + mDesiredActiveMode.event = Scheduler::ModeEvent::None; + mDesiredActiveModeChanged = false; +} + std::atomic<int32_t> DisplayDeviceState::sNextSequenceId(1); } // namespace android diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index 7e4d92308c..4d435c7e47 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -39,17 +39,24 @@ #include <utils/RefBase.h> #include <utils/Timers.h> +#include "MainThreadGuard.h" + #include "DisplayHardware/DisplayIdentification.h" #include "DisplayHardware/DisplayMode.h" #include "DisplayHardware/Hal.h" #include "DisplayHardware/PowerAdvisor.h" +#include "Scheduler/RefreshRateConfigs.h" + +#include "TracedOrdinal.h" + namespace android { class Fence; class HWComposer; class IGraphicBufferProducer; class Layer; +class RefreshRateOverlay; class SurfaceFlinger; struct CompositionInfo; @@ -64,6 +71,7 @@ class DisplayDevice : public RefBase { public: constexpr static float sDefaultMinLumiance = 0.0; constexpr static float sDefaultMaxLumiance = 500.0; + enum { eReceivesInput = 0x01 }; explicit DisplayDevice(DisplayDeviceCreationArgs& args); @@ -78,6 +86,9 @@ public: bool isVirtual() const { return !mConnectionType; } bool isPrimary() const { return mIsPrimary; } + bool isInternal() const { + return !isVirtual() && mConnectionType == ui::DisplayConnectionType::Internal; + } // isSecure indicates whether this display can be trusted to display // secure surfaces. @@ -90,6 +101,7 @@ public: void setLayerStack(ui::LayerStack); void setDisplaySize(int width, int height); void setProjection(ui::Rotation orientation, Rect viewport, Rect frame); + void setFlags(uint32_t flags); ui::Rotation getPhysicalOrientation() const { return mPhysicalOrientation; } ui::Rotation getOrientation() const { return mOrientation; } @@ -102,6 +114,7 @@ public: const Rect& getOrientedDisplaySpaceRect() const; bool needsFiltering() const; ui::LayerStack getLayerStack() const; + bool receivesInput() const { return mFlags & eReceivesInput; } DisplayId getId() const; @@ -172,10 +185,28 @@ public: * Display mode management. */ const DisplayModePtr& getActiveMode() const; - void setActiveMode(DisplayModeId); - status_t initiateModeChange(DisplayModeId modeId, + + struct ActiveModeInfo { + DisplayModePtr mode; + scheduler::RefreshRateConfigEvent event = scheduler::RefreshRateConfigEvent::None; + + bool operator!=(const ActiveModeInfo& other) const { + return mode != other.mode || event != other.event; + } + }; + + bool setDesiredActiveMode(const ActiveModeInfo&) EXCLUDES(mActiveModeLock); + std::optional<ActiveModeInfo> getDesiredActiveMode() const EXCLUDES(mActiveModeLock); + void clearDesiredActiveModeState() EXCLUDES(mActiveModeLock); + ActiveModeInfo getUpcomingActiveMode() const REQUIRES(SF_MAIN_THREAD) { + return mUpcomingActiveMode; + } + + void setActiveMode(DisplayModeId) REQUIRES(SF_MAIN_THREAD); + status_t initiateModeChange(const ActiveModeInfo&, const hal::VsyncPeriodChangeConstraints& constraints, - hal::VsyncPeriodChangeTimeline* outTimeline) const; + hal::VsyncPeriodChangeTimeline* outTimeline) + REQUIRES(SF_MAIN_THREAD); // Return the immutable list of supported display modes. The HWC may report different modes // after a hotplug reconnect event, in which case the DisplayDevice object will be recreated. @@ -187,6 +218,22 @@ public: // set-top boxes after a hotplug reconnect. DisplayModePtr getMode(DisplayModeId) const; + // Returns the refresh rate configs for this display. + scheduler::RefreshRateConfigs& refreshRateConfigs() const { return *mRefreshRateConfigs; } + + // Returns a shared pointer to the refresh rate configs for this display. + // Clients can store this refresh rate configs and use it even if the DisplayDevice + // is destroyed. + std::shared_ptr<scheduler::RefreshRateConfigs> holdRefreshRateConfigs() const { + return mRefreshRateConfigs; + } + + // Enables an overlay to be displayed with the current refresh rate + void enableRefreshRateOverlay(bool enable, bool showSpinner); + bool isRefreshRateOverlayEnabled() const { return mRefreshRateOverlay != nullptr; } + bool onKernelTimerChanged(std::optional<DisplayModeId>, bool timerExpired); + void onInvalidate(); + void onVsync(nsecs_t timestamp); nsecs_t getVsyncPeriodFromHWC() const; nsecs_t getRefreshTimestamp() const; @@ -211,6 +258,8 @@ private: const std::shared_ptr<compositionengine::Display> mCompositionDisplay; std::string mDisplayName; + std::string mActiveModeFPSTrace; + std::string mActiveModeFPSHwcTrace; const ui::Rotation mPhysicalOrientation; ui::Rotation mOrientation = ui::ROTATION_0; @@ -227,9 +276,20 @@ private: // TODO(b/74619554): Remove special cases for primary display. const bool mIsPrimary; + uint32_t mFlags = 0; + std::optional<DeviceProductInfo> mDeviceProductInfo; std::vector<ui::Hdr> mOverrideHdrTypes; + + std::shared_ptr<scheduler::RefreshRateConfigs> mRefreshRateConfigs; + std::unique_ptr<RefreshRateOverlay> mRefreshRateOverlay; + + mutable std::mutex mActiveModeLock; + ActiveModeInfo mDesiredActiveMode GUARDED_BY(mActiveModeLock); + TracedOrdinal<bool> mDesiredActiveModeChanged + GUARDED_BY(mActiveModeLock) = {"DesiredActiveModeChanged", false}; + ActiveModeInfo mUpcomingActiveMode GUARDED_BY(SF_MAIN_THREAD); }; struct DisplayDeviceState { @@ -252,6 +312,7 @@ struct DisplayDeviceState { std::optional<Physical> physical; sp<IGraphicBufferProducer> surface; ui::LayerStack layerStack = ui::NO_LAYER_STACK; + uint32_t flags = 0; Rect layerStackSpaceRect; Rect orientedDisplaySpaceRect; ui::Rotation orientation = ui::ROTATION_0; @@ -274,6 +335,7 @@ struct DisplayDeviceCreationArgs { HWComposer& hwComposer; const wp<IBinder> displayToken; const std::shared_ptr<compositionengine::Display> compositionDisplay; + std::shared_ptr<scheduler::RefreshRateConfigs> refreshRateConfigs; int32_t sequenceId{0}; std::optional<ui::DisplayConnectionType> connectionType; @@ -289,6 +351,7 @@ struct DisplayDeviceCreationArgs { hardware::graphics::composer::hal::PowerMode::ON}; bool isPrimary{false}; DisplayModes supportedModes; + DisplayModeId activeModeId; }; // Predicates for display lookup. diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp index caf0294a56..09734c275f 100644 --- a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp +++ b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp @@ -212,7 +212,7 @@ uint32_t Composer::getMaxVirtualDisplayCount() } Error Composer::createVirtualDisplay(uint32_t width, uint32_t height, PixelFormat* format, - std::optional<Display>, Display* outDisplay) { + Display* outDisplay) { const uint32_t bufferSlotCount = 1; Error error = kDefaultError; if (mClient_2_2) { diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h index b525e63c66..fe114b9512 100644 --- a/services/surfaceflinger/DisplayHardware/ComposerHal.h +++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h @@ -96,7 +96,7 @@ public: virtual uint32_t getMaxVirtualDisplayCount() = 0; virtual Error createVirtualDisplay(uint32_t width, uint32_t height, PixelFormat*, - std::optional<Display> mirror, Display* outDisplay) = 0; + Display* outDisplay) = 0; virtual Error destroyVirtualDisplay(Display display) = 0; virtual Error acceptDisplayChanges(Display display) = 0; @@ -342,7 +342,7 @@ public: uint32_t getMaxVirtualDisplayCount() override; Error createVirtualDisplay(uint32_t width, uint32_t height, PixelFormat* format, - std::optional<Display> mirror, Display* outDisplay) override; + Display* outDisplay) override; Error destroyVirtualDisplay(Display display) override; Error acceptDisplayChanges(Display display) override; diff --git a/services/surfaceflinger/DisplayHardware/DisplayMode.h b/services/surfaceflinger/DisplayHardware/DisplayMode.h index 85cc993c67..5de622b318 100644 --- a/services/surfaceflinger/DisplayHardware/DisplayMode.h +++ b/services/surfaceflinger/DisplayHardware/DisplayMode.h @@ -22,6 +22,7 @@ #include <android-base/stringprintf.h> #include <android/configuration.h> +#include <ui/DisplayId.h> #include <ui/DisplayMode.h> #include <ui/Size.h> #include <utils/Timers.h> @@ -54,6 +55,11 @@ public: return *this; } + Builder& setPhysicalDisplayId(PhysicalDisplayId id) { + mDisplayMode->mPhysicalDisplayId = id; + return *this; + } + Builder& setWidth(int32_t width) { mDisplayMode->mWidth = width; return *this; @@ -112,6 +118,7 @@ public: DisplayModeId getId() const { return mId; } hal::HWConfigId getHwcId() const { return mHwcId; } + PhysicalDisplayId getPhysicalDisplayId() const { return mPhysicalDisplayId; } int32_t getWidth() const { return mWidth; } int32_t getHeight() const { return mHeight; } @@ -136,6 +143,7 @@ private: hal::HWConfigId mHwcId; DisplayModeId mId; + PhysicalDisplayId mPhysicalDisplayId; int32_t mWidth = -1; int32_t mHeight = -1; diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp index 7e45dabdea..a790b4c11e 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp +++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp @@ -245,8 +245,7 @@ size_t HWComposer::getMaxVirtualDisplayDimension() const { } bool HWComposer::allocateVirtualDisplay(HalVirtualDisplayId displayId, ui::Size resolution, - ui::PixelFormat* format, - std::optional<PhysicalDisplayId> mirror) { + ui::PixelFormat* format) { if (!resolution.isValid()) { ALOGE("%s: Invalid resolution %dx%d", __func__, resolution.width, resolution.height); return false; @@ -262,14 +261,9 @@ bool HWComposer::allocateVirtualDisplay(HalVirtualDisplayId displayId, ui::Size return false; } - std::optional<hal::HWDisplayId> hwcMirrorId; - if (mirror) { - hwcMirrorId = fromPhysicalDisplayId(*mirror); - } - hal::HWDisplayId hwcDisplayId; const auto error = static_cast<hal::Error>( - mComposer->createVirtualDisplay(width, height, format, hwcMirrorId, &hwcDisplayId)); + mComposer->createVirtualDisplay(width, height, format, &hwcDisplayId)); RETURN_IF_HWC_ERROR_FOR("createVirtualDisplay", error, displayId, false); auto display = std::make_unique<HWC2::impl::Display>(*mComposer.get(), mCapabilities, diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h index b1849e8c11..49f96d9614 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.h +++ b/services/surfaceflinger/DisplayHardware/HWComposer.h @@ -113,11 +113,7 @@ public: // Attempts to allocate a virtual display on the HWC. The maximum number of virtual displays // supported by the HWC can be queried in advance, but allocation may fail for other reasons. - // For virtualized compositors, the PhysicalDisplayId is a hint that this virtual display is - // a mirror of a physical display, and that the screen should be captured by the host rather - // than guest compositor. - virtual bool allocateVirtualDisplay(HalVirtualDisplayId, ui::Size, ui::PixelFormat*, - std::optional<PhysicalDisplayId> mirror) = 0; + virtual bool allocateVirtualDisplay(HalVirtualDisplayId, ui::Size, ui::PixelFormat*) = 0; virtual void allocatePhysicalDisplay(hal::HWDisplayId, PhysicalDisplayId) = 0; @@ -265,8 +261,7 @@ public: size_t getMaxVirtualDisplayCount() const override; size_t getMaxVirtualDisplayDimension() const override; - bool allocateVirtualDisplay(HalVirtualDisplayId, ui::Size, ui::PixelFormat*, - std::optional<PhysicalDisplayId>) override; + bool allocateVirtualDisplay(HalVirtualDisplayId, ui::Size, ui::PixelFormat*) override; // Called from SurfaceFlinger, when the state for a new physical display needs to be recreated. void allocatePhysicalDisplay(hal::HWDisplayId, PhysicalDisplayId) override; diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 6ee13ce508..7cfc321633 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -71,7 +71,6 @@ #include "SurfaceFlinger.h" #include "TimeStats/TimeStats.h" #include "TunnelModeEnabledReporter.h" -#include "input/InputWindow.h" #define DEBUG_RESIZE 0 @@ -83,6 +82,7 @@ constexpr int kDumpTableRowLength = 159; using base::StringAppendF; using namespace android::flag_operators; using PresentState = frametimeline::SurfaceFrame::PresentState; +using gui::WindowInfo; std::atomic<int32_t> Layer::sSequence{1}; @@ -90,8 +90,8 @@ Layer::Layer(const LayerCreationArgs& args) : mFlinger(args.flinger), mName(args.name), mClientRef(args.client), - mWindowType(static_cast<InputWindowInfo::Type>( - args.metadata.getInt32(METADATA_WINDOW_TYPE, 0))) { + mWindowType( + static_cast<WindowInfo::Type>(args.metadata.getInt32(METADATA_WINDOW_TYPE, 0))) { uint32_t layerFlags = 0; if (args.flags & ISurfaceComposerClient::eHidden) layerFlags |= layer_state_t::eLayerHidden; if (args.flags & ISurfaceComposerClient::eOpaque) layerFlags |= layer_state_t::eLayerOpaque; @@ -1981,7 +1981,7 @@ void Layer::commitChildList() { } -void Layer::setInputInfo(const InputWindowInfo& info) { +void Layer::setInputInfo(const WindowInfo& info) { mDrawingState.inputInfo = info; mDrawingState.touchableRegionCrop = fromHandle(info.touchableRegionCropHandle.promote()); mDrawingState.modified = true; @@ -2020,8 +2020,8 @@ void Layer::writeToProtoDrawingState(LayerProto* layerInfo, uint32_t traceFlags, if (buffer != nullptr) { LayerProtoHelper::writeToProto(buffer, [&]() { return layerInfo->mutable_active_buffer(); }); - LayerProtoHelper::writeToProto(ui::Transform(getBufferTransform()), - layerInfo->mutable_buffer_transform()); + LayerProtoHelper::writeToProtoDeprecated(ui::Transform(getBufferTransform()), + layerInfo->mutable_buffer_transform()); } layerInfo->set_invalidate(contentDirty); layerInfo->set_is_protected(isProtected()); @@ -2031,10 +2031,11 @@ void Layer::writeToProtoDrawingState(LayerProto* layerInfo, uint32_t traceFlags, layerInfo->set_curr_frame(mCurrentFrameNumber); layerInfo->set_effective_scaling_mode(getEffectiveScalingMode()); + layerInfo->set_requested_corner_radius(getDrawingState().cornerRadius); layerInfo->set_corner_radius(getRoundedCornerState().radius); layerInfo->set_background_blur_radius(getBackgroundBlurRadius()); layerInfo->set_is_trusted_overlay(isTrustedOverlay()); - LayerProtoHelper::writeToProto(transform, layerInfo->mutable_transform()); + LayerProtoHelper::writeToProtoDeprecated(transform, layerInfo->mutable_transform()); LayerProtoHelper::writePositionToProto(transform.tx(), transform.ty(), [&]() { return layerInfo->mutable_position(); }); LayerProtoHelper::writeToProto(mBounds, [&]() { return layerInfo->mutable_bounds(); }); @@ -2109,8 +2110,8 @@ void Layer::writeToProtoCommonState(LayerProto* layerInfo, LayerVector::StateSet [&]() { return layerInfo->mutable_requested_color(); }); layerInfo->set_flags(state.flags); - LayerProtoHelper::writeToProto(requestedTransform, - layerInfo->mutable_requested_transform()); + LayerProtoHelper::writeToProtoDeprecated(requestedTransform, + layerInfo->mutable_requested_transform()); auto parent = useDrawing ? mDrawingParent.promote() : mCurrentParent.promote(); if (parent != nullptr) { @@ -2132,7 +2133,7 @@ void Layer::writeToProtoCommonState(LayerProto* layerInfo, LayerVector::StateSet } if (traceFlags & SurfaceTracing::TRACE_INPUT) { - InputWindowInfo info; + WindowInfo info; if (useDrawing) { info = fillInputInfo({nullptr}); } else { @@ -2163,7 +2164,7 @@ Rect Layer::getInputBounds() const { return getCroppedBufferSize(getDrawingState()); } -void Layer::fillInputFrameInfo(InputWindowInfo& info, const ui::Transform& toPhysicalDisplay) { +void Layer::fillInputFrameInfo(WindowInfo& info, const ui::Transform& toNonRotatedDisplay) { // Transform layer size to screen space and inset it by surface insets. // If this is a portal window, set the touchableRegion to the layerBounds. Rect layerBounds = info.portalToDisplayId == ADISPLAY_ID_NONE @@ -2184,12 +2185,12 @@ void Layer::fillInputFrameInfo(InputWindowInfo& info, const ui::Transform& toPhy } ui::Transform layerToDisplay = getInputTransform(); - // Transform that takes window coordinates to unrotated display coordinates - ui::Transform t = toPhysicalDisplay * layerToDisplay; + // Transform that takes window coordinates to non-rotated display coordinates + ui::Transform t = toNonRotatedDisplay * layerToDisplay; int32_t xSurfaceInset = info.surfaceInset; int32_t ySurfaceInset = info.surfaceInset; - // Bring screenBounds into unrotated space - Rect screenBounds = toPhysicalDisplay.transform(Rect{mScreenBounds}); + // Bring screenBounds into non-rotated space + Rect screenBounds = toNonRotatedDisplay.transform(Rect{mScreenBounds}); const float xScale = t.getScaleX(); const float yScale = t.getScaleY(); @@ -2258,7 +2259,7 @@ void Layer::fillInputFrameInfo(InputWindowInfo& info, const ui::Transform& toPhy info.touchableRegion = inputTransform.transform(info.touchableRegion); } -void Layer::fillTouchOcclusionMode(InputWindowInfo& info) { +void Layer::fillTouchOcclusionMode(WindowInfo& info) { sp<Layer> p = this; while (p != nullptr && !p->hasInputInfo()) { p = p->mDrawingParent.promote(); @@ -2268,32 +2269,47 @@ void Layer::fillTouchOcclusionMode(InputWindowInfo& info) { } } -InputWindowInfo Layer::fillInputInfo(const sp<DisplayDevice>& display) { +WindowInfo Layer::fillInputInfo(const sp<DisplayDevice>& display) { if (!hasInputInfo()) { mDrawingState.inputInfo.name = getName(); mDrawingState.inputInfo.ownerUid = mOwnerUid; mDrawingState.inputInfo.ownerPid = mOwnerPid; - mDrawingState.inputInfo.inputFeatures = InputWindowInfo::Feature::NO_INPUT_CHANNEL; - mDrawingState.inputInfo.flags = InputWindowInfo::Flag::NOT_TOUCH_MODAL; + mDrawingState.inputInfo.inputFeatures = WindowInfo::Feature::NO_INPUT_CHANNEL; + mDrawingState.inputInfo.flags = WindowInfo::Flag::NOT_TOUCH_MODAL; mDrawingState.inputInfo.displayId = getLayerStack(); } - InputWindowInfo info = mDrawingState.inputInfo; + WindowInfo info = mDrawingState.inputInfo; info.id = sequence; + info.displayId = getLayerStack(); - if (info.displayId == ADISPLAY_ID_NONE) { - info.displayId = getLayerStack(); - } - - // Transform that goes from "logical(rotated)" display to physical/unrotated display. - // This is for when inputflinger operates in physical display-space. - ui::Transform toPhysicalDisplay; + // Transform that goes from "logical(rotated)" display to the non-rotated display. + ui::Transform toNonRotatedDisplay; if (display) { - toPhysicalDisplay = display->getTransform(); - info.displayWidth = display->getWidth(); - info.displayHeight = display->getHeight(); + // The physical orientation is set when the orientation of the display panel is different + // than the default orientation of the device. We do not need to expose the physical + // orientation of the panel outside of SurfaceFlinger. + const ui::Rotation inversePhysicalOrientation = + ui::ROTATION_0 - display->getPhysicalOrientation(); + auto width = display->getWidth(); + auto height = display->getHeight(); + if (inversePhysicalOrientation == ui::ROTATION_90 || + inversePhysicalOrientation == ui::ROTATION_270) { + std::swap(width, height); + } + const auto rotationFlags = ui::Transform::toRotationFlags(inversePhysicalOrientation); + const ui::Transform undoPhysicalOrientation(rotationFlags, width, height); + toNonRotatedDisplay = undoPhysicalOrientation * display->getTransform(); + + // Send the inverse of the display orientation so that input can transform points back to + // the rotated display space. + const ui::Rotation inverseOrientation = ui::ROTATION_0 - display->getOrientation(); + info.displayOrientation = ui::Transform::toRotationFlags(inverseOrientation); + + info.displayWidth = width; + info.displayHeight = height; } - fillInputFrameInfo(info, toPhysicalDisplay); + fillInputFrameInfo(info, toNonRotatedDisplay); // For compatibility reasons we let layers which can receive input // receive input before they have actually submitted a buffer. Because @@ -2310,14 +2326,14 @@ InputWindowInfo Layer::fillInputInfo(const sp<DisplayDevice>& display) { auto cropLayer = mDrawingState.touchableRegionCrop.promote(); if (info.replaceTouchableRegionWithCrop) { if (cropLayer == nullptr) { - info.touchableRegion = Region(toPhysicalDisplay.transform(Rect{mScreenBounds})); + info.touchableRegion = Region(toNonRotatedDisplay.transform(Rect{mScreenBounds})); } else { info.touchableRegion = - Region(toPhysicalDisplay.transform(Rect{cropLayer->mScreenBounds})); + Region(toNonRotatedDisplay.transform(Rect{cropLayer->mScreenBounds})); } } else if (cropLayer != nullptr) { info.touchableRegion = info.touchableRegion.intersect( - toPhysicalDisplay.transform(Rect{cropLayer->mScreenBounds})); + toNonRotatedDisplay.transform(Rect{cropLayer->mScreenBounds})); } // Inherit the trusted state from the parent hierarchy, but don't clobber the trusted state @@ -2330,7 +2346,7 @@ InputWindowInfo Layer::fillInputInfo(const sp<DisplayDevice>& display) { if (isClone()) { sp<Layer> clonedRoot = getClonedRoot(); if (clonedRoot != nullptr) { - Rect rect = toPhysicalDisplay.transform(Rect{clonedRoot->mScreenBounds}); + Rect rect = toNonRotatedDisplay.transform(Rect{clonedRoot->mScreenBounds}); info.touchableRegion = info.touchableRegion.intersect(rect); } } @@ -2457,7 +2473,7 @@ void Layer::updateClonedInputInfo(const std::map<sp<Layer>, sp<Layer>>& clonedLa } // Cloned layers shouldn't handle watch outside since their z order is not determined by // WM or the client. - mDrawingState.inputInfo.flags &= ~InputWindowInfo::Flag::WATCH_OUTSIDE_TOUCH; + mDrawingState.inputInfo.flags &= ~WindowInfo::Flag::WATCH_OUTSIDE_TOUCH; } void Layer::updateClonedRelatives(const std::map<sp<Layer>, sp<Layer>>& clonedLayersMap) { diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 8905548b64..470103c784 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -21,7 +21,7 @@ #include <gui/BufferQueue.h> #include <gui/ISurfaceComposerClient.h> #include <gui/LayerState.h> -#include <input/InputWindow.h> +#include <gui/WindowInfo.h> #include <layerproto/LayerProtoHeader.h> #include <math/vec4.h> #include <renderengine/Mesh.h> @@ -186,7 +186,7 @@ public: float cornerRadius; int backgroundBlurRadius; - InputWindowInfo inputInfo; + gui::WindowInfo inputInfo; wp<Layer> touchableRegionCrop; // dataspace is only used by BufferStateLayer and EffectLayer @@ -280,6 +280,8 @@ public: Rect bufferCrop; Rect destinationFrame; + + sp<IBinder> releaseBufferEndpoint; }; /* @@ -422,7 +424,8 @@ public: const client_cache_t& /*clientCacheId*/, uint64_t /* frameNumber */, std::optional<nsecs_t> /* dequeueTime */, const FrameTimelineInfo& /*info*/, - const sp<ITransactionCompletedListener>& /* releaseBufferListener */) { + const sp<ITransactionCompletedListener>& /* releaseBufferListener */, + const sp<IBinder>& /* releaseBufferEndpoint */) { return false; }; virtual bool setAcquireFence(const sp<Fence>& /*fence*/) { return false; }; @@ -695,7 +698,7 @@ public: void writeToProtoCommonState(LayerProto* layerInfo, LayerVector::StateSet, uint32_t traceFlags = SurfaceTracing::TRACE_ALL); - InputWindowInfo::Type getWindowType() const { return mWindowType; } + gui::WindowInfo::Type getWindowType() const { return mWindowType; } bool getPrimaryDisplayOnly() const; @@ -846,9 +849,9 @@ public: sp<IBinder> getHandle(); const std::string& getName() const { return mName; } bool getPremultipledAlpha() const; - void setInputInfo(const InputWindowInfo& info); + void setInputInfo(const gui::WindowInfo& info); - InputWindowInfo fillInputInfo(const sp<DisplayDevice>& display); + gui::WindowInfo fillInputInfo(const sp<DisplayDevice>& display); /** * Returns whether this layer has an explicitly set input-info. */ @@ -1013,7 +1016,7 @@ protected: wp<Layer> mDrawingParent; // Window types from WindowManager.LayoutParams - const InputWindowInfo::Type mWindowType; + const gui::WindowInfo::Type mWindowType; // The owner of the layer. If created from a non system process, it will be the calling uid. // If created from a system process, the value can be passed in. @@ -1067,10 +1070,10 @@ private: // Fills in the touch occlusion mode of the first parent (including this layer) that // hasInputInfo() or no-op if no such parent is found. - void fillTouchOcclusionMode(InputWindowInfo& info); + void fillTouchOcclusionMode(gui::WindowInfo& info); - // Fills in the frame and transform info for the InputWindowInfo - void fillInputFrameInfo(InputWindowInfo& info, const ui::Transform& toPhysicalDisplay); + // Fills in the frame and transform info for the gui::WindowInfo + void fillInputFrameInfo(gui::WindowInfo& info, const ui::Transform& toNonRotatedDisplay); // Cached properties computed from drawing state // Effective transform taking into account parent transforms and any parent scaling, which is diff --git a/services/surfaceflinger/LayerProtoHelper.cpp b/services/surfaceflinger/LayerProtoHelper.cpp index b1db6d34a3..1062126b58 100644 --- a/services/surfaceflinger/LayerProtoHelper.cpp +++ b/services/surfaceflinger/LayerProtoHelper.cpp @@ -22,6 +22,9 @@ #include "LayerProtoHelper.h" namespace android { + +using gui::WindowInfo; + namespace surfaceflinger { void LayerProtoHelper::writePositionToProto(const float x, const float y, @@ -95,8 +98,8 @@ void LayerProtoHelper::writeToProto(const half4 color, std::function<ColorProto* } } -void LayerProtoHelper::writeToProto(const ui::Transform& transform, - TransformProto* transformProto) { +void LayerProtoHelper::writeToProtoDeprecated(const ui::Transform& transform, + TransformProto* transformProto) { const uint32_t type = transform.getType() | (transform.getOrientation() << 8); transformProto->set_type(type); @@ -111,6 +114,22 @@ void LayerProtoHelper::writeToProto(const ui::Transform& transform, } } +void LayerProtoHelper::writeTransformToProto(const ui::Transform& transform, + TransformProto* transformProto) { + const uint32_t type = transform.getType() | (transform.getOrientation() << 8); + transformProto->set_type(type); + + // Rotations that are 90/180/270 have their own type so the transform matrix can be + // reconstructed later. All other rotation have the type UNKNOWN so we need to save the + // transform values in that case. + if (type & (ui::Transform::SCALE | ui::Transform::UNKNOWN)) { + transformProto->set_dsdx(transform.dsdx()); + transformProto->set_dtdx(transform.dtdx()); + transformProto->set_dtdy(transform.dtdy()); + transformProto->set_dsdy(transform.dsdy()); + } +} + void LayerProtoHelper::writeToProto(const sp<GraphicBuffer>& buffer, std::function<ActiveBufferProto*()> getActiveBufferProto) { if (buffer->getWidth() != 0 || buffer->getHeight() != 0 || buffer->getStride() != 0 || @@ -125,7 +144,7 @@ void LayerProtoHelper::writeToProto(const sp<GraphicBuffer>& buffer, } void LayerProtoHelper::writeToProto( - const InputWindowInfo& inputInfo, const wp<Layer>& touchableRegionBounds, + const WindowInfo& inputInfo, const wp<Layer>& touchableRegionBounds, std::function<InputWindowInfoProto*()> getInputWindowInfoProto) { if (inputInfo.token == nullptr) { return; @@ -133,7 +152,7 @@ void LayerProtoHelper::writeToProto( InputWindowInfoProto* proto = getInputWindowInfoProto(); proto->set_layout_params_flags(inputInfo.flags.get()); - using U = std::underlying_type_t<InputWindowInfo::Type>; + using U = std::underlying_type_t<WindowInfo::Type>; // TODO(b/129481165): This static assert can be safely removed once conversion warnings // are re-enabled. static_assert(std::is_same_v<U, int32_t>); @@ -151,7 +170,7 @@ void LayerProtoHelper::writeToProto( proto->set_has_wallpaper(inputInfo.hasWallpaper); proto->set_global_scale_factor(inputInfo.globalScaleFactor); - LayerProtoHelper::writeToProto(inputInfo.transform, proto->mutable_transform()); + LayerProtoHelper::writeToProtoDeprecated(inputInfo.transform, proto->mutable_transform()); proto->set_replace_touchable_region_with_crop(inputInfo.replaceTouchableRegionWithCrop); auto cropLayer = touchableRegionBounds.promote(); if (cropLayer != nullptr) { diff --git a/services/surfaceflinger/LayerProtoHelper.h b/services/surfaceflinger/LayerProtoHelper.h index 502238d389..36e06471ee 100644 --- a/services/surfaceflinger/LayerProtoHelper.h +++ b/services/surfaceflinger/LayerProtoHelper.h @@ -17,7 +17,7 @@ #include <layerproto/LayerProtoHeader.h> #include <Layer.h> -#include <input/InputWindow.h> +#include <gui/WindowInfo.h> #include <math/vec4.h> #include <ui/GraphicBuffer.h> #include <ui/Rect.h> @@ -37,10 +37,15 @@ public: std::function<FloatRectProto*()> getFloatRectProto); static void writeToProto(const Region& region, std::function<RegionProto*()> getRegionProto); static void writeToProto(const half4 color, std::function<ColorProto*()> getColorProto); - static void writeToProto(const ui::Transform& transform, TransformProto* transformProto); + // This writeToProto for transform is incorrect, but due to backwards compatibility, we can't + // update Layers to use it. Use writeTransformToProto for any new transform proto data. + static void writeToProtoDeprecated(const ui::Transform& transform, + TransformProto* transformProto); + static void writeTransformToProto(const ui::Transform& transform, + TransformProto* transformProto); static void writeToProto(const sp<GraphicBuffer>& buffer, std::function<ActiveBufferProto*()> getActiveBufferProto); - static void writeToProto(const InputWindowInfo& inputInfo, + static void writeToProto(const gui::WindowInfo& inputInfo, const wp<Layer>& touchableRegionBounds, std::function<InputWindowInfoProto*()> getInputWindowInfoProto); static void writeToProto(const mat4 matrix, ColorTransformProto* colorTransformProto); diff --git a/services/surfaceflinger/MainThreadGuard.h b/services/surfaceflinger/MainThreadGuard.h new file mode 100644 index 0000000000..c1aa118492 --- /dev/null +++ b/services/surfaceflinger/MainThreadGuard.h @@ -0,0 +1,35 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <utils/Mutex.h> + +namespace android { +namespace { + +// Helps to ensure that some functions runs on SF's main thread by using the +// clang thread safety annotations. +class CAPABILITY("mutex") MainThreadGuard { +} SF_MAIN_THREAD; + +struct SCOPED_CAPABILITY MainThreadScopedGuard { +public: + explicit MainThreadScopedGuard(MainThreadGuard& mutex) ACQUIRE(mutex) {} + ~MainThreadScopedGuard() RELEASE() {} +}; +} // namespace +} // namespace android diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp index 27a1c280fb..bc32a1d66c 100644 --- a/services/surfaceflinger/RefreshRateOverlay.cpp +++ b/services/surfaceflinger/RefreshRateOverlay.cpp @@ -175,10 +175,14 @@ std::vector<sp<GraphicBuffer>> RefreshRateOverlay::SevenSegmentDrawer::drawNumbe return buffers; } -RefreshRateOverlay::RefreshRateOverlay(SurfaceFlinger& flinger, bool showSpinner) - : mFlinger(flinger), mClient(new Client(&mFlinger)), mShowSpinner(showSpinner) { +RefreshRateOverlay::RefreshRateOverlay(SurfaceFlinger& flinger, uint32_t lowFps, uint32_t highFps, + bool showSpinner) + : mFlinger(flinger), + mClient(new Client(&mFlinger)), + mShowSpinner(showSpinner), + mLowFps(lowFps), + mHighFps(highFps) { createLayer(); - reset(); } bool RefreshRateOverlay::createLayer() { @@ -194,7 +198,6 @@ bool RefreshRateOverlay::createLayer() { return false; } - Mutex::Autolock _l(mFlinger.mStateLock); mLayer = mClient->getLayerUser(mIBinder); mLayer->setFrameRate(Layer::FrameRate(Fps(0.0f), Layer::FrameRateCompatibility::NoVote)); mLayer->setIsAtRoot(true); @@ -241,8 +244,11 @@ RefreshRateOverlay::getOrCreateBuffers(uint32_t fps) { } void RefreshRateOverlay::setViewport(ui::Size viewport) { - Rect frame((3 * viewport.width) >> 4, viewport.height >> 5); - frame.offsetBy(viewport.width >> 5, viewport.height >> 4); + constexpr int32_t kMaxWidth = 1000; + const auto width = std::min(kMaxWidth, std::min(viewport.width, viewport.height)); + const auto height = 2 * width; + Rect frame((3 * width) >> 4, height >> 5); + frame.offsetBy(width >> 5, height >> 4); layer_state_t::matrix22_t matrix; matrix.dsdx = frame.getWidth() / static_cast<float>(SevenSegmentDrawer::getWidth()); @@ -254,13 +260,18 @@ void RefreshRateOverlay::setViewport(ui::Size viewport) { mFlinger.mTransactionFlags.fetch_or(eTransactionMask); } +void RefreshRateOverlay::setLayerStack(uint32_t stack) { + mLayer->setLayerStack(stack); + mFlinger.mTransactionFlags.fetch_or(eTransactionMask); +} + void RefreshRateOverlay::changeRefreshRate(const Fps& fps) { mCurrentFps = fps.getIntValue(); auto buffer = getOrCreateBuffers(*mCurrentFps)[mFrame]; mLayer->setBuffer(buffer, Fence::NO_FENCE, 0, 0, true, {}, mLayer->getHeadFrameNumber(-1 /* expectedPresentTime */), std::nullopt /* dequeueTime */, FrameTimelineInfo{}, - nullptr /* releaseBufferListener */); + nullptr /* releaseBufferListener */, nullptr /* releaseBufferEndpoint */); mFlinger.mTransactionFlags.fetch_or(eTransactionMask); } @@ -274,18 +285,11 @@ void RefreshRateOverlay::onInvalidate() { mLayer->setBuffer(buffer, Fence::NO_FENCE, 0, 0, true, {}, mLayer->getHeadFrameNumber(-1 /* expectedPresentTime */), std::nullopt /* dequeueTime */, FrameTimelineInfo{}, - nullptr /* releaseBufferListener */); + nullptr /* releaseBufferListener */, nullptr /* releaseBufferEndpoint */); mFlinger.mTransactionFlags.fetch_or(eTransactionMask); } -void RefreshRateOverlay::reset() { - mBufferCache.clear(); - const auto range = mFlinger.mRefreshRateConfigs->getSupportedRefreshRateRange(); - mLowFps = range.min.getIntValue(); - mHighFps = range.max.getIntValue(); -} - } // namespace android // TODO(b/129481165): remove the #pragma below and fix conversion issues diff --git a/services/surfaceflinger/RefreshRateOverlay.h b/services/surfaceflinger/RefreshRateOverlay.h index aa8329c46a..f9baa898dc 100644 --- a/services/surfaceflinger/RefreshRateOverlay.h +++ b/services/surfaceflinger/RefreshRateOverlay.h @@ -37,12 +37,12 @@ class SurfaceFlinger; class RefreshRateOverlay { public: - RefreshRateOverlay(SurfaceFlinger&, bool showSpinner); + RefreshRateOverlay(SurfaceFlinger&, uint32_t lowFps, uint32_t highFps, bool showSpinner); + void setLayerStack(uint32_t stack); void setViewport(ui::Size); void changeRefreshRate(const Fps&); void onInvalidate(); - void reset(); private: class SevenSegmentDrawer { @@ -91,8 +91,8 @@ private: const bool mShowSpinner; // Interpolate the colors between these values. - uint32_t mLowFps; - uint32_t mHighFps; + const uint32_t mLowFps; + const uint32_t mHighFps; }; } // namespace android diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp index 2321e2d082..2bdcaf6ad0 100644 --- a/services/surfaceflinger/Scheduler/EventThread.cpp +++ b/services/surfaceflinger/Scheduler/EventThread.cpp @@ -118,12 +118,12 @@ DisplayEventReceiver::Event makeVSync(PhysicalDisplayId displayId, nsecs_t times return event; } -DisplayEventReceiver::Event makeModeChanged(PhysicalDisplayId displayId, DisplayModeId modeId, - nsecs_t vsyncPeriod) { +DisplayEventReceiver::Event makeModeChanged(DisplayModePtr mode) { DisplayEventReceiver::Event event; - event.header = {DisplayEventReceiver::DISPLAY_EVENT_MODE_CHANGE, displayId, systemTime()}; - event.modeChange.modeId = modeId.value(); - event.modeChange.vsyncPeriod = vsyncPeriod; + event.header = {DisplayEventReceiver::DISPLAY_EVENT_MODE_CHANGE, mode->getPhysicalDisplayId(), + systemTime()}; + event.modeChange.modeId = mode->getId().value(); + event.modeChange.vsyncPeriod = mode->getVsyncPeriod(); return event; } @@ -375,11 +375,10 @@ void EventThread::onHotplugReceived(PhysicalDisplayId displayId, bool connected) mCondition.notify_all(); } -void EventThread::onModeChanged(PhysicalDisplayId displayId, DisplayModeId modeId, - nsecs_t vsyncPeriod) { +void EventThread::onModeChanged(DisplayModePtr mode) { std::lock_guard<std::mutex> lock(mMutex); - mPendingEvents.push_back(makeModeChanged(displayId, modeId, vsyncPeriod)); + mPendingEvents.push_back(makeModeChanged(mode)); mCondition.notify_all(); } diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h index 1e6793f77c..9265a25b86 100644 --- a/services/surfaceflinger/Scheduler/EventThread.h +++ b/services/surfaceflinger/Scheduler/EventThread.h @@ -124,8 +124,7 @@ public: virtual void onHotplugReceived(PhysicalDisplayId displayId, bool connected) = 0; // called when SF changes the active mode and apps needs to be notified about the change - virtual void onModeChanged(PhysicalDisplayId displayId, DisplayModeId modeId, - nsecs_t vsyncPeriod) = 0; + virtual void onModeChanged(DisplayModePtr) = 0; // called when SF updates the Frame Rate Override list virtual void onFrameRateOverridesChanged(PhysicalDisplayId displayId, @@ -174,8 +173,7 @@ public: void onHotplugReceived(PhysicalDisplayId displayId, bool connected) override; - void onModeChanged(PhysicalDisplayId displayId, DisplayModeId modeId, - nsecs_t vsyncPeriod) override; + void onModeChanged(DisplayModePtr) override; void onFrameRateOverridesChanged(PhysicalDisplayId displayId, std::vector<FrameRateOverride> overrides) override; diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp index 0563795c79..84e3548b6e 100644 --- a/services/surfaceflinger/Scheduler/LayerHistory.cpp +++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp @@ -75,10 +75,9 @@ void trace(const LayerInfo& info, LayerHistory::LayerVoteType type, int fps) { } } // namespace -LayerHistory::LayerHistory(const RefreshRateConfigs& refreshRateConfigs) +LayerHistory::LayerHistory() : mTraceEnabled(traceEnabled()), mUseFrameRatePriority(useFrameRatePriority()) { LayerInfo::setTraceEnabled(mTraceEnabled); - LayerInfo::setRefreshRateConfigs(refreshRateConfigs); } LayerHistory::~LayerHistory() = default; @@ -138,7 +137,8 @@ void LayerHistory::record(Layer* layer, nsecs_t presentTime, nsecs_t now, } } -LayerHistory::Summary LayerHistory::summarize(nsecs_t now) { +LayerHistory::Summary LayerHistory::summarize(const RefreshRateConfigs& refreshRateConfigs, + nsecs_t now) { LayerHistory::Summary summary; std::lock_guard lock(mLock); @@ -151,7 +151,7 @@ LayerHistory::Summary LayerHistory::summarize(nsecs_t now) { ALOGV("%s has priority: %d %s focused", info->getName().c_str(), frameRateSelectionPriority, layerFocused ? "" : "not"); - const auto vote = info->getRefreshRateVote(now); + const auto vote = info->getRefreshRateVote(refreshRateConfigs, now); // Skip NoVote layer as those don't have any requirements if (vote.type == LayerHistory::LayerVoteType::NoVote) { continue; diff --git a/services/surfaceflinger/Scheduler/LayerHistory.h b/services/surfaceflinger/Scheduler/LayerHistory.h index 82f6c3907b..92236f560a 100644 --- a/services/surfaceflinger/Scheduler/LayerHistory.h +++ b/services/surfaceflinger/Scheduler/LayerHistory.h @@ -42,7 +42,7 @@ class LayerHistory { public: using LayerVoteType = RefreshRateConfigs::LayerVoteType; - LayerHistory(const RefreshRateConfigs&); + LayerHistory(); ~LayerHistory(); // Layers are unregistered when the weak reference expires. @@ -67,7 +67,7 @@ public: using Summary = std::vector<RefreshRateConfigs::LayerRequirement>; // Rebuilds sets of active/inactive layers, and accumulates stats for active layers. - Summary summarize(nsecs_t now); + Summary summarize(const RefreshRateConfigs&, nsecs_t now); void clear(); diff --git a/services/surfaceflinger/Scheduler/LayerInfo.cpp b/services/surfaceflinger/Scheduler/LayerInfo.cpp index 989bf4ef19..8a45b66b60 100644 --- a/services/surfaceflinger/Scheduler/LayerInfo.cpp +++ b/services/surfaceflinger/Scheduler/LayerInfo.cpp @@ -34,7 +34,6 @@ namespace android::scheduler { -const RefreshRateConfigs* LayerInfo::sRefreshRateConfigs = nullptr; bool LayerInfo::sTraceEnabled = false; LayerInfo::LayerInfo(const std::string& name, uid_t ownerUid, @@ -184,7 +183,8 @@ std::optional<nsecs_t> LayerInfo::calculateAverageFrameTime() const { return static_cast<nsecs_t>(averageFrameTime); } -std::optional<Fps> LayerInfo::calculateRefreshRateIfPossible(nsecs_t now) { +std::optional<Fps> LayerInfo::calculateRefreshRateIfPossible( + const RefreshRateConfigs& refreshRateConfigs, nsecs_t now) { static constexpr float MARGIN = 1.0f; // 1Hz if (!hasEnoughDataForHeuristic()) { ALOGV("Not enough data"); @@ -196,9 +196,7 @@ std::optional<Fps> LayerInfo::calculateRefreshRateIfPossible(nsecs_t now) { const auto refreshRate = Fps::fromPeriodNsecs(*averageFrameTime); const bool refreshRateConsistent = mRefreshRateHistory.add(refreshRate, now); if (refreshRateConsistent) { - const auto knownRefreshRate = - sRefreshRateConfigs->findClosestKnownFrameRate(refreshRate); - + const auto knownRefreshRate = refreshRateConfigs.findClosestKnownFrameRate(refreshRate); // To avoid oscillation, use the last calculated refresh rate if it is // close enough if (std::abs(mLastRefreshRate.calculated.getValue() - refreshRate.getValue()) > @@ -220,7 +218,8 @@ std::optional<Fps> LayerInfo::calculateRefreshRateIfPossible(nsecs_t now) { : std::nullopt; } -LayerInfo::LayerVote LayerInfo::getRefreshRateVote(nsecs_t now) { +LayerInfo::LayerVote LayerInfo::getRefreshRateVote(const RefreshRateConfigs& refreshRateConfigs, + nsecs_t now) { if (mLayerVote.type != LayerHistory::LayerVoteType::Heuristic) { ALOGV("%s voted %d ", mName.c_str(), static_cast<int>(mLayerVote.type)); return mLayerVote; @@ -247,7 +246,7 @@ LayerInfo::LayerVote LayerInfo::getRefreshRateVote(nsecs_t now) { clearHistory(now); } - auto refreshRate = calculateRefreshRateIfPossible(now); + auto refreshRate = calculateRefreshRateIfPossible(refreshRateConfigs, now); if (refreshRate.has_value()) { ALOGV("%s calculated refresh rate: %s", mName.c_str(), to_string(*refreshRate).c_str()); return {LayerHistory::LayerVoteType::Heuristic, refreshRate.value()}; diff --git a/services/surfaceflinger/Scheduler/LayerInfo.h b/services/surfaceflinger/Scheduler/LayerInfo.h index 34cc3890d3..ce9783c5a9 100644 --- a/services/surfaceflinger/Scheduler/LayerInfo.h +++ b/services/surfaceflinger/Scheduler/LayerInfo.h @@ -122,10 +122,6 @@ public: static void setTraceEnabled(bool enabled) { sTraceEnabled = enabled; } - static void setRefreshRateConfigs(const RefreshRateConfigs& refreshRateConfigs) { - sRefreshRateConfigs = &refreshRateConfigs; - } - LayerInfo(const std::string& name, uid_t ownerUid, LayerHistory::LayerVoteType defaultVote); LayerInfo(const LayerInfo&) = delete; @@ -161,7 +157,7 @@ public: uid_t getOwnerUid() const { return mOwnerUid; } - LayerVote getRefreshRateVote(nsecs_t now); + LayerVote getRefreshRateVote(const RefreshRateConfigs&, nsecs_t now); // Return the last updated time. If the present time is farther in the future than the // updated time, the updated time is the present time. @@ -263,7 +259,7 @@ private: bool isFrequent(nsecs_t now) const; bool isAnimating(nsecs_t now) const; bool hasEnoughDataForHeuristic() const; - std::optional<Fps> calculateRefreshRateIfPossible(nsecs_t now); + std::optional<Fps> calculateRefreshRateIfPossible(const RefreshRateConfigs&, nsecs_t now); std::optional<nsecs_t> calculateAverageFrameTime() const; bool isFrameTimeValid(const FrameTimeData&) const; @@ -300,7 +296,6 @@ private: mutable std::unordered_map<LayerHistory::LayerVoteType, std::string> mTraceTags; // Shared for all LayerInfo instances - static const RefreshRateConfigs* sRefreshRateConfigs; static bool sTraceEnabled; }; diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp index 73b7b6365c..81a669aa09 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp @@ -113,7 +113,7 @@ bool RefreshRateConfigs::isVoteAllowed(const LayerRequirement& layer, case LayerVoteType::ExplicitExactOrMultiple: case LayerVoteType::Heuristic: if (mConfig.frameRateMultipleThreshold != 0 && - refreshRate.fps.greaterThanOrEqualWithMargin( + refreshRate.getFps().greaterThanOrEqualWithMargin( Fps(mConfig.frameRateMultipleThreshold)) && layer.desiredRefreshRate.lessThanWithMargin( Fps(mConfig.frameRateMultipleThreshold / 2))) { @@ -146,8 +146,8 @@ float RefreshRateConfigs::calculateLayerScoreLocked(const LayerRequirement& laye // If the layer wants Max, give higher score to the higher refresh rate if (layer.vote == LayerVoteType::Max) { - const auto ratio = - refreshRate.fps.getValue() / mAppRequestRefreshRates.back()->fps.getValue(); + const auto ratio = refreshRate.getFps().getValue() / + mAppRequestRefreshRates.back()->getFps().getValue(); // use ratio^2 to get a lower score the more we get further from peak return ratio * ratio; } @@ -463,7 +463,7 @@ RefreshRate RefreshRateConfigs::getBestRefreshRateLocked( } }(); if (globalSignals.touch && explicitDefaultVoteLayers == 0 && touchBoostForExplicitExact && - bestRefreshRate->fps.lessThanWithMargin(touchRefreshRate.fps)) { + bestRefreshRate->getFps().lessThanWithMargin(touchRefreshRate.getFps())) { setTouchConsidered(); ALOGV("TouchBoost - choose %s", touchRefreshRate.getName().c_str()); return touchRefreshRate; @@ -699,8 +699,7 @@ void RefreshRateConfigs::updateDisplayModes(const DisplayModes& modes, for (const auto& mode : modes) { const auto modeId = mode->getId(); mRefreshRates.emplace(modeId, - std::make_unique<RefreshRate>(modeId, mode, mode->getFps(), - RefreshRate::ConstructorTag(0))); + std::make_unique<RefreshRate>(mode, RefreshRate::ConstructorTag(0))); if (modeId == currentModeId) { mCurrentRefreshRate = mRefreshRates.at(modeId).get(); } @@ -793,7 +792,7 @@ RefreshRateConfigs::Policy RefreshRateConfigs::getDisplayManagerPolicy() const { bool RefreshRateConfigs::isModeAllowed(DisplayModeId modeId) const { std::lock_guard lock(mLock); for (const RefreshRate* refreshRate : mAppRequestRefreshRates) { - if (refreshRate->modeId == modeId) { + if (refreshRate->getModeId() == modeId) { return true; } } @@ -808,7 +807,7 @@ void RefreshRateConfigs::getSortedRefreshRateListLocked( for (const auto& [type, refreshRate] : mRefreshRates) { if (shouldAddRefreshRate(*refreshRate)) { ALOGV("getSortedRefreshRateListLocked: mode %d added to list policy", - refreshRate->modeId.value()); + refreshRate->getModeId().value()); outRefreshRates->push_back(refreshRate.get()); } } diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h index dfd13953e7..4a9a1fd9fc 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h @@ -64,25 +64,23 @@ public: }; public: - RefreshRate(DisplayModeId modeId, DisplayModePtr mode, Fps fps, ConstructorTag) - : modeId(modeId), mode(mode), fps(std::move(fps)) {} + RefreshRate(DisplayModePtr mode, ConstructorTag) : mode(mode) {} - DisplayModeId getModeId() const { return modeId; } + DisplayModeId getModeId() const { return mode->getId(); } nsecs_t getVsyncPeriod() const { return mode->getVsyncPeriod(); } int32_t getModeGroup() const { return mode->getGroup(); } - std::string getName() const { return to_string(fps); } - Fps getFps() const { return fps; } + std::string getName() const { return to_string(getFps()); } + Fps getFps() const { return mode->getFps(); } + DisplayModePtr getMode() const { return mode; } // Checks whether the fps of this RefreshRate struct is within a given min and max refresh // rate passed in. Margin of error is applied to the boundaries for approximation. bool inPolicy(Fps minRefreshRate, Fps maxRefreshRate) const { - return minRefreshRate.lessThanOrEqualWithMargin(fps) && - fps.lessThanOrEqualWithMargin(maxRefreshRate); + return minRefreshRate.lessThanOrEqualWithMargin(getFps()) && + getFps().lessThanOrEqualWithMargin(maxRefreshRate); } - bool operator!=(const RefreshRate& other) const { - return modeId != other.modeId || mode != other.mode; - } + bool operator!=(const RefreshRate& other) const { return mode != other.mode; } bool operator<(const RefreshRate& other) const { return getFps().getValue() < other.getFps().getValue(); @@ -99,10 +97,7 @@ public: friend RefreshRateConfigs; friend class RefreshRateConfigsTest; - const DisplayModeId modeId; DisplayModePtr mode; - // Refresh rate in frames per second - const Fps fps{0.0f}; }; using AllRefreshRatesMapType = @@ -316,8 +311,6 @@ public: Config config = {.enableFrameRateOverride = false, .frameRateMultipleThreshold = 0}); - void updateDisplayModes(const DisplayModes& mode, DisplayModeId currentModeId) EXCLUDES(mLock); - // Returns whether switching modes (refresh rate or resolution) is possible. // TODO(b/158780872): Consider HAL support, and skip frame rate detection if the modes only // differ in resolution. @@ -354,6 +347,9 @@ public: void dump(std::string& result) const EXCLUDES(mLock); + RefreshRateConfigs(const RefreshRateConfigs&) = delete; + void operator=(const RefreshRateConfigs&) = delete; + private: friend class RefreshRateConfigsTest; @@ -405,6 +401,8 @@ private: float calculateLayerScoreLocked(const LayerRequirement&, const RefreshRate&, bool isSeamlessSwitch) const REQUIRES(mLock); + void updateDisplayModes(const DisplayModes& mode, DisplayModeId currentModeId) EXCLUDES(mLock); + // The list of refresh rates, indexed by display modes ID. This may change after this // object is initialized. AllRefreshRatesMapType mRefreshRates GUARDED_BY(mLock); diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index 64ad178b26..80b2504a2c 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -25,7 +25,7 @@ #include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h> #include <android/hardware/configstore/1.1/ISurfaceFlingerConfigs.h> #include <configstore/Utils.h> -#include <input/InputWindow.h> +#include <gui/WindowInfo.h> #include <system/window.h> #include <ui/DisplayStatInfo.h> #include <utils/Timers.h> @@ -64,6 +64,8 @@ using namespace std::string_literals; namespace android { +using gui::WindowInfo; + namespace { std::unique_ptr<scheduler::VSyncTracker> createVSyncTracker() { @@ -115,16 +117,17 @@ private: } }; -Scheduler::Scheduler(const scheduler::RefreshRateConfigs& configs, ISchedulerCallback& callback) +Scheduler::Scheduler(const std::shared_ptr<scheduler::RefreshRateConfigs>& configs, + ISchedulerCallback& callback) : Scheduler(configs, callback, {.supportKernelTimer = sysprop::support_kernel_idle_timer(false), .useContentDetection = sysprop::use_content_detection_for_refresh_rate(false)}) { } -Scheduler::Scheduler(const scheduler::RefreshRateConfigs& configs, ISchedulerCallback& callback, - Options options) +Scheduler::Scheduler(const std::shared_ptr<scheduler::RefreshRateConfigs>& configs, + ISchedulerCallback& callback, Options options) : Scheduler(createVsyncSchedule(options.supportKernelTimer), configs, callback, - createLayerHistory(configs), options) { + createLayerHistory(), options) { using namespace sysprop; const int setIdleTimerMs = base::GetIntProperty("debug.sf.set_idle_timer_ms"s, 0); @@ -157,7 +160,8 @@ Scheduler::Scheduler(const scheduler::RefreshRateConfigs& configs, ISchedulerCal } } -Scheduler::Scheduler(VsyncSchedule schedule, const scheduler::RefreshRateConfigs& configs, +Scheduler::Scheduler(VsyncSchedule schedule, + const std::shared_ptr<scheduler::RefreshRateConfigs>& configs, ISchedulerCallback& schedulerCallback, std::unique_ptr<LayerHistory> layerHistory, Options options) : mOptions(options), @@ -192,9 +196,8 @@ Scheduler::VsyncSchedule Scheduler::createVsyncSchedule(bool supportKernelTimer) return {std::move(controller), std::move(tracker), std::move(dispatch)}; } -std::unique_ptr<LayerHistory> Scheduler::createLayerHistory( - const scheduler::RefreshRateConfigs& configs) { - return std::make_unique<scheduler::LayerHistory>(configs); +std::unique_ptr<LayerHistory> Scheduler::createLayerHistory() { + return std::make_unique<scheduler::LayerHistory>(); } std::unique_ptr<VSyncSource> Scheduler::makePrimaryDispSyncSource( @@ -205,11 +208,14 @@ std::unique_ptr<VSyncSource> Scheduler::makePrimaryDispSyncSource( } std::optional<Fps> Scheduler::getFrameRateOverride(uid_t uid) const { - if (!mRefreshRateConfigs.supportsFrameRateOverride()) { - return std::nullopt; + { + std::scoped_lock lock(mRefreshRateConfigsLock); + if (!mRefreshRateConfigs->supportsFrameRateOverride()) { + return std::nullopt; + } } - std::lock_guard lock(mFrameRateOverridesMutex); + std::lock_guard lock(mFrameRateOverridesLock); { const auto iter = mFrameRateOverridesFromBackdoor.find(uid); if (iter != mFrameRateOverridesFromBackdoor.end()) { @@ -237,7 +243,8 @@ bool Scheduler::isVsyncValid(nsecs_t expectedVsyncTimestamp, uid_t uid) const { } impl::EventThread::ThrottleVsyncCallback Scheduler::makeThrottleVsyncCallback() const { - if (!mRefreshRateConfigs.supportsFrameRateOverride()) { + std::scoped_lock lock(mRefreshRateConfigsLock); + if (!mRefreshRateConfigs->supportsFrameRateOverride()) { return {}; } @@ -248,14 +255,18 @@ impl::EventThread::ThrottleVsyncCallback Scheduler::makeThrottleVsyncCallback() impl::EventThread::GetVsyncPeriodFunction Scheduler::makeGetVsyncPeriodFunction() const { return [this](uid_t uid) { - nsecs_t basePeriod = mRefreshRateConfigs.getCurrentRefreshRate().getVsyncPeriod(); + const auto refreshRateConfigs = holdRefreshRateConfigs(); + nsecs_t basePeriod = refreshRateConfigs->getCurrentRefreshRate().getVsyncPeriod(); const auto frameRate = getFrameRateOverride(uid); if (!frameRate.has_value()) { return basePeriod; } - const auto divider = scheduler::RefreshRateConfigs::getFrameRateDivider( - mRefreshRateConfigs.getCurrentRefreshRate().getFps(), *frameRate); + const auto divider = + scheduler::RefreshRateConfigs::getFrameRateDivider(refreshRateConfigs + ->getCurrentRefreshRate() + .getFps(), + *frameRate); if (divider <= 1) { return basePeriod; } @@ -341,7 +352,7 @@ void Scheduler::onScreenReleased(ConnectionHandle handle) { void Scheduler::onFrameRateOverridesChanged(ConnectionHandle handle, PhysicalDisplayId displayId) { std::vector<FrameRateOverride> overrides; { - std::lock_guard lock(mFrameRateOverridesMutex); + std::lock_guard lock(mFrameRateOverridesLock); for (const auto& [uid, frameRate] : mFrameRateOverridesFromBackdoor) { overrides.emplace_back(FrameRateOverride{uid, frameRate.getValue()}); } @@ -360,23 +371,22 @@ void Scheduler::onFrameRateOverridesChanged(ConnectionHandle handle, PhysicalDis thread->onFrameRateOverridesChanged(displayId, std::move(overrides)); } -void Scheduler::onPrimaryDisplayModeChanged(ConnectionHandle handle, PhysicalDisplayId displayId, - DisplayModeId modeId, nsecs_t vsyncPeriod) { +void Scheduler::onPrimaryDisplayModeChanged(ConnectionHandle handle, DisplayModePtr mode) { { std::lock_guard<std::mutex> lock(mFeatureStateLock); // Cache the last reported modes for primary display. - mFeatures.cachedModeChangedParams = {handle, displayId, modeId, vsyncPeriod}; + mFeatures.cachedModeChangedParams = {handle, mode}; // Invalidate content based refresh rate selection so it could be calculated // again for the new refresh rate. mFeatures.contentRequirements.clear(); } - onNonPrimaryDisplayModeChanged(handle, displayId, modeId, vsyncPeriod); + onNonPrimaryDisplayModeChanged(handle, mode); } void Scheduler::dispatchCachedReportedMode() { // Check optional fields first. - if (!mFeatures.modeId.has_value()) { + if (!mFeatures.mode) { ALOGW("No mode ID found, not dispatching cached mode."); return; } @@ -385,39 +395,32 @@ void Scheduler::dispatchCachedReportedMode() { return; } - const auto modeId = *mFeatures.modeId; - // If the modeId is not the current mode, this means that a + // If the mode is not the current mode, this means that a // mode change is in progress. In that case we shouldn't dispatch an event // as it will be dispatched when the current mode changes. - if (mRefreshRateConfigs.getCurrentRefreshRate().getModeId() != modeId) { + if (std::scoped_lock lock(mRefreshRateConfigsLock); + mRefreshRateConfigs->getCurrentRefreshRate().getMode() != mFeatures.mode) { return; } - const auto vsyncPeriod = mRefreshRateConfigs.getRefreshRateFromModeId(modeId).getVsyncPeriod(); - // If there is no change from cached mode, there is no need to dispatch an event - if (modeId == mFeatures.cachedModeChangedParams->modeId && - vsyncPeriod == mFeatures.cachedModeChangedParams->vsyncPeriod) { + if (mFeatures.mode == mFeatures.cachedModeChangedParams->mode) { return; } - mFeatures.cachedModeChangedParams->modeId = modeId; - mFeatures.cachedModeChangedParams->vsyncPeriod = vsyncPeriod; + mFeatures.cachedModeChangedParams->mode = mFeatures.mode; onNonPrimaryDisplayModeChanged(mFeatures.cachedModeChangedParams->handle, - mFeatures.cachedModeChangedParams->displayId, - mFeatures.cachedModeChangedParams->modeId, - mFeatures.cachedModeChangedParams->vsyncPeriod); + mFeatures.cachedModeChangedParams->mode); } -void Scheduler::onNonPrimaryDisplayModeChanged(ConnectionHandle handle, PhysicalDisplayId displayId, - DisplayModeId modeId, nsecs_t vsyncPeriod) { +void Scheduler::onNonPrimaryDisplayModeChanged(ConnectionHandle handle, DisplayModePtr mode) { android::EventThread* thread; { std::lock_guard<std::mutex> lock(mConnectionsLock); RETURN_IF_INVALID_HANDLE(handle); thread = mConnections[handle].thread.get(); } - thread->onModeChanged(displayId, modeId, vsyncPeriod); + thread->onModeChanged(mode); } size_t Scheduler::getEventThreadConnectionCount(ConnectionHandle handle) { @@ -537,7 +540,11 @@ void Scheduler::resync() { const nsecs_t last = mLastResyncTime.exchange(now); if (now - last > kIgnoreDelay) { - resyncToHardwareVsync(false, mRefreshRateConfigs.getCurrentRefreshRate().getVsyncPeriod()); + const auto vsyncPeriod = [&] { + std::scoped_lock lock(mRefreshRateConfigsLock); + return mRefreshRateConfigs->getCurrentRefreshRate().getVsyncPeriod(); + }(); + resyncToHardwareVsync(false, vsyncPeriod); } } @@ -586,10 +593,9 @@ void Scheduler::setIgnorePresentFences(bool ignore) { void Scheduler::registerLayer(Layer* layer) { scheduler::LayerHistory::LayerVoteType voteType; - if (!mOptions.useContentDetection || - layer->getWindowType() == InputWindowInfo::Type::STATUS_BAR) { + if (!mOptions.useContentDetection || layer->getWindowType() == WindowInfo::Type::STATUS_BAR) { voteType = scheduler::LayerHistory::LayerVoteType::NoVote; - } else if (layer->getWindowType() == InputWindowInfo::Type::WALLPAPER) { + } else if (layer->getWindowType() == WindowInfo::Type::WALLPAPER) { // Running Wallpaper at Min is considered as part of content detection. voteType = scheduler::LayerHistory::LayerVoteType::Min; } else { @@ -608,9 +614,12 @@ void Scheduler::deregisterLayer(Layer* layer) { void Scheduler::recordLayerHistory(Layer* layer, nsecs_t presentTime, LayerHistory::LayerUpdateType updateType) { - if (mRefreshRateConfigs.canSwitch()) { - mLayerHistory->record(layer, presentTime, systemTime(), updateType); + { + std::scoped_lock lock(mRefreshRateConfigsLock); + if (!mRefreshRateConfigs->canSwitch()) return; } + + mLayerHistory->record(layer, presentTime, systemTime(), updateType); } void Scheduler::setModeChangePending(bool pending) { @@ -618,25 +627,28 @@ void Scheduler::setModeChangePending(bool pending) { } void Scheduler::chooseRefreshRateForContent() { - if (!mRefreshRateConfigs.canSwitch()) return; + { + std::scoped_lock lock(mRefreshRateConfigsLock); + if (!mRefreshRateConfigs->canSwitch()) return; + } ATRACE_CALL(); - scheduler::LayerHistory::Summary summary = mLayerHistory->summarize(systemTime()); + const auto refreshRateConfigs = holdRefreshRateConfigs(); + scheduler::LayerHistory::Summary summary = + mLayerHistory->summarize(*refreshRateConfigs, systemTime()); scheduler::RefreshRateConfigs::GlobalSignals consideredSignals; - DisplayModeId newModeId; + DisplayModePtr newMode; bool frameRateChanged; bool frameRateOverridesChanged; { std::lock_guard<std::mutex> lock(mFeatureStateLock); mFeatures.contentRequirements = summary; - newModeId = calculateRefreshRateModeId(&consideredSignals); - auto newRefreshRate = mRefreshRateConfigs.getRefreshRateFromModeId(newModeId); - frameRateOverridesChanged = - updateFrameRateOverrides(consideredSignals, newRefreshRate.getFps()); + newMode = calculateRefreshRateModeId(&consideredSignals); + frameRateOverridesChanged = updateFrameRateOverrides(consideredSignals, newMode->getFps()); - if (mFeatures.modeId == newModeId) { + if (mFeatures.mode == newMode) { // We don't need to change the display mode, but we might need to send an event // about a mode change, since it was suppressed due to a previous idleConsidered if (!consideredSignals.idle) { @@ -644,12 +656,12 @@ void Scheduler::chooseRefreshRateForContent() { } frameRateChanged = false; } else { - mFeatures.modeId = newModeId; + mFeatures.mode = newMode; frameRateChanged = true; } } if (frameRateChanged) { - auto newRefreshRate = mRefreshRateConfigs.getRefreshRateFromModeId(newModeId); + auto newRefreshRate = refreshRateConfigs->getRefreshRateFromModeId(newMode->getId()); mSchedulerCallback.changeRefreshRate(newRefreshRate, consideredSignals.idle ? ModeEvent::None : ModeEvent::Changed); @@ -695,7 +707,11 @@ void Scheduler::kernelIdleTimerCallback(TimerState state) { // TODO(145561154): cleanup the kernel idle timer implementation and the refresh rate // magic number - const auto& refreshRate = mRefreshRateConfigs.getCurrentRefreshRate(); + const auto refreshRate = [&] { + std::scoped_lock lock(mRefreshRateConfigsLock); + return mRefreshRateConfigs->getCurrentRefreshRate(); + }(); + constexpr Fps FPS_THRESHOLD_FOR_KERNEL_TIMER{65.0f}; if (state == TimerState::Reset && refreshRate.getFps().greaterThanWithMargin(FPS_THRESHOLD_FOR_KERNEL_TIMER)) { @@ -747,7 +763,7 @@ void Scheduler::dump(std::string& result) const { mLayerHistory ? mLayerHistory->dump().c_str() : "(no layer history)"); { - std::lock_guard lock(mFrameRateOverridesMutex); + std::lock_guard lock(mFrameRateOverridesLock); StringAppendF(&result, "Frame Rate Overrides (backdoor): {"); for (const auto& [uid, frameRate] : mFrameRateOverridesFromBackdoor) { StringAppendF(&result, "[uid: %d frameRate: %s], ", uid, to_string(frameRate).c_str()); @@ -773,16 +789,17 @@ void Scheduler::dumpVsync(std::string& s) const { bool Scheduler::updateFrameRateOverrides( scheduler::RefreshRateConfigs::GlobalSignals consideredSignals, Fps displayRefreshRate) { - if (!mRefreshRateConfigs.supportsFrameRateOverride()) { + const auto refreshRateConfigs = holdRefreshRateConfigs(); + if (!refreshRateConfigs->supportsFrameRateOverride()) { return false; } if (!consideredSignals.idle) { const auto frameRateOverrides = - mRefreshRateConfigs.getFrameRateOverrides(mFeatures.contentRequirements, + refreshRateConfigs->getFrameRateOverrides(mFeatures.contentRequirements, displayRefreshRate, consideredSignals.touch); - std::lock_guard lock(mFrameRateOverridesMutex); + std::lock_guard lock(mFrameRateOverridesLock); if (!std::equal(mFrameRateOverridesByContent.begin(), mFrameRateOverridesByContent.end(), frameRateOverrides.begin(), frameRateOverrides.end(), [](const std::pair<uid_t, Fps>& a, const std::pair<uid_t, Fps>& b) { @@ -797,33 +814,33 @@ bool Scheduler::updateFrameRateOverrides( template <class T> bool Scheduler::handleTimerStateChanged(T* currentState, T newState) { - DisplayModeId newModeId; + DisplayModePtr newMode; bool refreshRateChanged = false; bool frameRateOverridesChanged; scheduler::RefreshRateConfigs::GlobalSignals consideredSignals; + const auto refreshRateConfigs = holdRefreshRateConfigs(); { std::lock_guard<std::mutex> lock(mFeatureStateLock); if (*currentState == newState) { return false; } *currentState = newState; - newModeId = calculateRefreshRateModeId(&consideredSignals); - const RefreshRate& newRefreshRate = mRefreshRateConfigs.getRefreshRateFromModeId(newModeId); - frameRateOverridesChanged = - updateFrameRateOverrides(consideredSignals, newRefreshRate.getFps()); - if (mFeatures.modeId == newModeId) { + newMode = calculateRefreshRateModeId(&consideredSignals); + frameRateOverridesChanged = updateFrameRateOverrides(consideredSignals, newMode->getFps()); + if (mFeatures.mode == newMode) { // We don't need to change the display mode, but we might need to send an event // about a mode change, since it was suppressed due to a previous idleConsidered if (!consideredSignals.idle) { dispatchCachedReportedMode(); } } else { - mFeatures.modeId = newModeId; + mFeatures.mode = newMode; refreshRateChanged = true; } } if (refreshRateChanged) { - const RefreshRate& newRefreshRate = mRefreshRateConfigs.getRefreshRateFromModeId(newModeId); + const RefreshRate& newRefreshRate = + refreshRateConfigs->getRefreshRateFromModeId(newMode->getId()); mSchedulerCallback.changeRefreshRate(newRefreshRate, consideredSignals.idle ? ModeEvent::None @@ -835,35 +852,36 @@ bool Scheduler::handleTimerStateChanged(T* currentState, T newState) { return consideredSignals.touch; } -DisplayModeId Scheduler::calculateRefreshRateModeId( +DisplayModePtr Scheduler::calculateRefreshRateModeId( scheduler::RefreshRateConfigs::GlobalSignals* consideredSignals) { ATRACE_CALL(); if (consideredSignals) *consideredSignals = {}; + const auto refreshRateConfigs = holdRefreshRateConfigs(); // If Display Power is not in normal operation we want to be in performance mode. When coming // back to normal mode, a grace period is given with DisplayPowerTimer. if (mDisplayPowerTimer && (!mFeatures.isDisplayPowerStateNormal || mFeatures.displayPowerTimer == TimerState::Reset)) { - return mRefreshRateConfigs.getMaxRefreshRateByPolicy().getModeId(); + return refreshRateConfigs->getMaxRefreshRateByPolicy().getMode(); } const bool touchActive = mTouchTimer && mFeatures.touch == TouchState::Active; const bool idle = mIdleTimer && mFeatures.idleTimer == TimerState::Expired; - return mRefreshRateConfigs - .getBestRefreshRate(mFeatures.contentRequirements, {.touch = touchActive, .idle = idle}, - consideredSignals) - .getModeId(); + return refreshRateConfigs + ->getBestRefreshRate(mFeatures.contentRequirements, + {.touch = touchActive, .idle = idle}, consideredSignals) + .getMode(); } -std::optional<DisplayModeId> Scheduler::getPreferredModeId() { +DisplayModePtr Scheduler::getPreferredDisplayMode() { std::lock_guard<std::mutex> lock(mFeatureStateLock); // Make sure that the default mode ID is first updated, before returned. - if (mFeatures.modeId.has_value()) { - mFeatures.modeId = calculateRefreshRateModeId(); + if (mFeatures.mode) { + mFeatures.mode = calculateRefreshRateModeId(); } - return mFeatures.modeId; + return mFeatures.mode; } void Scheduler::onNewVsyncPeriodChangeTimeline(const hal::VsyncPeriodChangeTimeline& timeline) { @@ -899,7 +917,7 @@ void Scheduler::onDisplayRefreshed(nsecs_t timestamp) { } } -void Scheduler::onPrimaryDisplayAreaChanged(uint32_t displayArea) { +void Scheduler::onActiveDisplayAreaChanged(uint32_t displayArea) { mLayerHistory->setDisplayArea(displayArea); } @@ -908,7 +926,7 @@ void Scheduler::setPreferredRefreshRateForUid(FrameRateOverride frameRateOverrid return; } - std::lock_guard lock(mFrameRateOverridesMutex); + std::lock_guard lock(mFrameRateOverridesLock); if (frameRateOverride.frameRateHz != 0.f) { mFrameRateOverridesFromBackdoor[frameRateOverride.uid] = Fps(frameRateOverride.frameRateHz); } else { diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index 30a32537ad..4b6905bc6d 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -72,7 +72,7 @@ public: using RefreshRate = scheduler::RefreshRateConfigs::RefreshRate; using ModeEvent = scheduler::RefreshRateConfigEvent; - Scheduler(const scheduler::RefreshRateConfigs&, ISchedulerCallback&); + Scheduler(const std::shared_ptr<scheduler::RefreshRateConfigs>&, ISchedulerCallback&); ~Scheduler(); using ConnectionHandle = scheduler::ConnectionHandle; @@ -87,15 +87,13 @@ public: sp<EventThreadConnection> getEventConnection(ConnectionHandle); void onHotplugReceived(ConnectionHandle, PhysicalDisplayId, bool connected); - void onPrimaryDisplayModeChanged(ConnectionHandle, PhysicalDisplayId, DisplayModeId, - nsecs_t vsyncPeriod) EXCLUDES(mFeatureStateLock); - void onNonPrimaryDisplayModeChanged(ConnectionHandle, PhysicalDisplayId, DisplayModeId, - nsecs_t vsyncPeriod); + void onPrimaryDisplayModeChanged(ConnectionHandle, DisplayModePtr) EXCLUDES(mFeatureStateLock); + void onNonPrimaryDisplayModeChanged(ConnectionHandle, DisplayModePtr); void onScreenAcquired(ConnectionHandle); void onScreenReleased(ConnectionHandle); void onFrameRateOverridesChanged(ConnectionHandle, PhysicalDisplayId) - EXCLUDES(mFrameRateOverridesMutex) EXCLUDES(mConnectionsLock); + EXCLUDES(mFrameRateOverridesLock) EXCLUDES(mConnectionsLock); // Modifies work duration in the event thread. void setDuration(ConnectionHandle, std::chrono::nanoseconds workDuration, @@ -116,7 +114,7 @@ public: // no-op. // The period is the vsync period from the current display configuration. void resyncToHardwareVsync(bool makeAvailable, nsecs_t period); - void resync(); + void resync() EXCLUDES(mRefreshRateConfigsLock); // Passes a vsync sample to VsyncController. periodFlushed will be true if // VsyncController detected that the vsync period changed, and false otherwise. @@ -127,12 +125,13 @@ public: // Layers are registered on creation, and unregistered when the weak reference expires. void registerLayer(Layer*); - void recordLayerHistory(Layer*, nsecs_t presentTime, LayerHistory::LayerUpdateType updateType); + void recordLayerHistory(Layer*, nsecs_t presentTime, LayerHistory::LayerUpdateType updateType) + EXCLUDES(mRefreshRateConfigsLock); void setModeChangePending(bool pending); void deregisterLayer(Layer*); // Detects content using layer history, and selects a matching refresh rate. - void chooseRefreshRateForContent(); + void chooseRefreshRateForContent() EXCLUDES(mRefreshRateConfigsLock); bool isIdleTimerEnabled() const { return mIdleTimer.has_value(); } void resetIdleTimer(); @@ -147,7 +146,7 @@ public: // Returns true if a given vsync timestamp is considered valid vsync // for a given uid bool isVsyncValid(nsecs_t expectedVsyncTimestamp, uid_t uid) const - EXCLUDES(mFrameRateOverridesMutex); + EXCLUDES(mFrameRateOverridesLock); std::chrono::steady_clock::time_point getPreviousVsyncFrom(nsecs_t expectedPresentTime) const; @@ -156,7 +155,7 @@ public: void dumpVsync(std::string&) const; // Get the appropriate refresh for current conditions. - std::optional<DisplayModeId> getPreferredModeId(); + DisplayModePtr getPreferredDisplayMode(); // Notifies the scheduler about a refresh rate timeline change. void onNewVsyncPeriodChangeTimeline(const hal::VsyncPeriodChangeTimeline& timeline); @@ -165,7 +164,7 @@ public: void onDisplayRefreshed(nsecs_t timestamp); // Notifies the scheduler when the display size has changed. Called from SF's main thread - void onPrimaryDisplayAreaChanged(uint32_t displayArea); + void onActiveDisplayAreaChanged(uint32_t displayArea); size_t getEventThreadConnectionCount(ConnectionHandle handle); @@ -176,9 +175,21 @@ public: // Stores the preferred refresh rate that an app should run at. // FrameRateOverride.refreshRateHz == 0 means no preference. - void setPreferredRefreshRateForUid(FrameRateOverride) EXCLUDES(mFrameRateOverridesMutex); + void setPreferredRefreshRateForUid(FrameRateOverride) EXCLUDES(mFrameRateOverridesLock); // Retrieves the overridden refresh rate for a given uid. - std::optional<Fps> getFrameRateOverride(uid_t uid) const EXCLUDES(mFrameRateOverridesMutex); + std::optional<Fps> getFrameRateOverride(uid_t uid) const + EXCLUDES(mRefreshRateConfigsLock, mFrameRateOverridesLock); + + void setRefreshRateConfigs(std::shared_ptr<scheduler::RefreshRateConfigs> refreshRateConfigs) + EXCLUDES(mRefreshRateConfigsLock) { + std::scoped_lock lock(mRefreshRateConfigsLock); + mRefreshRateConfigs = std::move(refreshRateConfigs); + } + + nsecs_t getVsyncPeriodFromRefreshRateConfigs() const EXCLUDES(mRefreshRateConfigsLock) { + std::scoped_lock lock(mRefreshRateConfigsLock); + return mRefreshRateConfigs->getCurrentRefreshRate().getVsyncPeriod(); + } private: friend class TestableScheduler; @@ -203,14 +214,14 @@ private: }; // Unlike the testing constructor, this creates the VsyncSchedule, LayerHistory, and timers. - Scheduler(const scheduler::RefreshRateConfigs&, ISchedulerCallback&, Options); + Scheduler(const std::shared_ptr<scheduler::RefreshRateConfigs>&, ISchedulerCallback&, Options); // Used by tests to inject mocks. - Scheduler(VsyncSchedule, const scheduler::RefreshRateConfigs&, ISchedulerCallback&, - std::unique_ptr<LayerHistory>, Options); + Scheduler(VsyncSchedule, const std::shared_ptr<scheduler::RefreshRateConfigs>&, + ISchedulerCallback&, std::unique_ptr<LayerHistory>, Options); static VsyncSchedule createVsyncSchedule(bool supportKernelIdleTimer); - static std::unique_ptr<LayerHistory> createLayerHistory(const scheduler::RefreshRateConfigs&); + static std::unique_ptr<LayerHistory> createLayerHistory(); // Create a connection on the given EventThread. ConnectionHandle createConnection(std::unique_ptr<EventThread>); @@ -218,7 +229,7 @@ private: EventThread*, ISurfaceComposer::EventRegistrationFlags eventRegistration = {}); // Update feature state machine to given state when corresponding timer resets or expires. - void kernelIdleTimerCallback(TimerState); + void kernelIdleTimerCallback(TimerState) EXCLUDES(mRefreshRateConfigsLock); void idleTimerCallback(TimerState); void touchTimerCallback(TimerState); void displayPowerTimerCallback(TimerState); @@ -232,18 +243,25 @@ private: // This function checks whether individual features that are affecting the refresh rate // selection were initialized, prioritizes them, and calculates the DisplayModeId // for the suggested refresh rate. - DisplayModeId calculateRefreshRateModeId( + DisplayModePtr calculateRefreshRateModeId( scheduler::RefreshRateConfigs::GlobalSignals* consideredSignals = nullptr) REQUIRES(mFeatureStateLock); - void dispatchCachedReportedMode() REQUIRES(mFeatureStateLock); + void dispatchCachedReportedMode() REQUIRES(mFeatureStateLock) EXCLUDES(mRefreshRateConfigsLock); bool updateFrameRateOverrides(scheduler::RefreshRateConfigs::GlobalSignals consideredSignals, Fps displayRefreshRate) REQUIRES(mFeatureStateLock) - EXCLUDES(mFrameRateOverridesMutex); + EXCLUDES(mFrameRateOverridesLock); - impl::EventThread::ThrottleVsyncCallback makeThrottleVsyncCallback() const; + impl::EventThread::ThrottleVsyncCallback makeThrottleVsyncCallback() const + EXCLUDES(mRefreshRateConfigsLock); impl::EventThread::GetVsyncPeriodFunction makeGetVsyncPeriodFunction() const; + std::shared_ptr<scheduler::RefreshRateConfigs> holdRefreshRateConfigs() const + EXCLUDES(mRefreshRateConfigsLock) { + std::scoped_lock lock(mRefreshRateConfigsLock); + return mRefreshRateConfigs; + } + // Stores EventThread associated with a given VSyncSource, and an initial EventThreadConnection. struct Connection { sp<EventThreadConnection> connection; @@ -288,7 +306,7 @@ private: TouchState touch = TouchState::Inactive; TimerState displayPowerTimer = TimerState::Expired; - std::optional<DisplayModeId> modeId; + DisplayModePtr mode; LayerHistory::Summary contentRequirements; bool isDisplayPowerStateNormal = true; @@ -296,15 +314,15 @@ private: // Used to cache the last parameters of onPrimaryDisplayModeChanged struct ModeChangedParams { ConnectionHandle handle; - PhysicalDisplayId displayId; - DisplayModeId modeId; - nsecs_t vsyncPeriod; + DisplayModePtr mode; }; std::optional<ModeChangedParams> cachedModeChangedParams; } mFeatures GUARDED_BY(mFeatureStateLock); - const scheduler::RefreshRateConfigs& mRefreshRateConfigs; + mutable std::mutex mRefreshRateConfigsLock; + std::shared_ptr<scheduler::RefreshRateConfigs> mRefreshRateConfigs + GUARDED_BY(mRefreshRateConfigsLock); std::mutex mVsyncTimelineLock; std::optional<hal::VsyncPeriodChangeTimeline> mLastVsyncPeriodChangeTimeline @@ -315,14 +333,14 @@ private: // The frame rate override lists need their own mutex as they are being read // by SurfaceFlinger, Scheduler and EventThread (as a callback) to prevent deadlocks - mutable std::mutex mFrameRateOverridesMutex; + mutable std::mutex mFrameRateOverridesLock; // mappings between a UID and a preferred refresh rate that this app would // run at. scheduler::RefreshRateConfigs::UidToFrameRateOverride mFrameRateOverridesByContent - GUARDED_BY(mFrameRateOverridesMutex); + GUARDED_BY(mFrameRateOverridesLock); scheduler::RefreshRateConfigs::UidToFrameRateOverride mFrameRateOverridesFromBackdoor - GUARDED_BY(mFrameRateOverridesMutex); + GUARDED_BY(mFrameRateOverridesLock); }; } // namespace android diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index fe43a2091d..594fde3c84 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -31,7 +31,6 @@ #include <android/hardware/configstore/1.1/types.h> #include <android/hardware/power/Boost.h> #include <android/native_window.h> -#include <android/os/BnSetInputWindowsListener.h> #include <android/os/IInputFlinger.h> #include <binder/IPCThreadState.h> #include <binder/IServiceManager.h> @@ -115,6 +114,7 @@ #include "FrameTracer/FrameTracer.h" #include "HdrLayerInfoReporter.h" #include "Layer.h" +#include "LayerProtoHelper.h" #include "LayerRenderArea.h" #include "LayerVector.h" #include "MonitoredProducer.h" @@ -133,6 +133,7 @@ #include "SurfaceInterceptor.h" #include "TimeStats/TimeStats.h" #include "TunnelModeEnabledReporter.h" +#include "WindowInfosListenerInvoker.h" #include "android-base/parseint.h" #include "android-base/stringprintf.h" #include "android-base/strings.h" @@ -146,6 +147,13 @@ return (expr); \ }() +#define MAIN_THREAD_GUARD(expr) \ + [&] { \ + LOG_FATAL_IF(std::this_thread::get_id() != mMainThreadId); \ + MainThreadScopedGuard lock(SF_MAIN_THREAD); \ + return (expr); \ + }() + #undef NO_THREAD_SAFETY_ANALYSIS #define NO_THREAD_SAFETY_ANALYSIS \ _Pragma("GCC error \"Prefer MAIN_THREAD macros or {Conditional,Timed,Unnecessary}Lock.\"") @@ -160,6 +168,8 @@ using namespace android::sysprop; using android::hardware::power::Boost; using base::StringAppendF; +using gui::IWindowInfosListener; +using gui::WindowInfo; using ui::ColorMode; using ui::Dataspace; using ui::DisplayPrimaries; @@ -267,21 +277,6 @@ enum Permission { } // namespace anonymous -struct SetInputWindowsListener : os::BnSetInputWindowsListener { - explicit SetInputWindowsListener(std::function<void()> listenerCb) : mListenerCb(listenerCb) {} - - binder::Status onSetInputWindowsFinished() override; - - std::function<void()> mListenerCb; -}; - -binder::Status SetInputWindowsListener::onSetInputWindowsFinished() { - if (mListenerCb != nullptr) { - mListenerCb(); - } - return binder::Status::ok(); -} - // --------------------------------------------------------------------------- const String16 sHardwareTest("android.permission.HARDWARE_TEST"); @@ -347,10 +342,9 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory, SkipInitializationTag) mTunnelModeEnabledReporter(new TunnelModeEnabledReporter()), mInternalDisplayDensity(getDensityFromProperty("ro.sf.lcd_density", true)), mEmulatedDisplayDensity(getDensityFromProperty("qemu.sf.lcd_density", false)), - mPowerAdvisor(*this) { + mPowerAdvisor(*this), + mWindowInfosListenerInvoker(new WindowInfosListenerInvoker(this)) { ALOGI("Using HWComposer service: %s", mHwcServiceName.c_str()); - - mSetInputWindowsListener = new SetInputWindowsListener([&]() { setInputWindowsFinished(); }); } SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipInitialization) { @@ -590,19 +584,11 @@ void SurfaceFlinger::enableHalVirtualDisplays(bool enable) { } } -VirtualDisplayId SurfaceFlinger::acquireVirtualDisplay(ui::Size resolution, ui::PixelFormat format, - ui::LayerStack layerStack) { +VirtualDisplayId SurfaceFlinger::acquireVirtualDisplay(ui::Size resolution, + ui::PixelFormat format) { if (auto& generator = mVirtualDisplayIdGenerators.hal) { if (const auto id = generator->generateId()) { - std::optional<PhysicalDisplayId> mirror; - - if (const auto display = findDisplay([layerStack](const auto& display) { - return !display.isVirtual() && display.getLayerStack() == layerStack; - })) { - mirror = display->getPhysicalId(); - } - - if (getHwComposer().allocateVirtualDisplay(*id, resolution, &format, mirror)) { + if (getHwComposer().allocateVirtualDisplay(*id, resolution, &format)) { return *id; } @@ -632,9 +618,7 @@ void SurfaceFlinger::releaseVirtualDisplay(VirtualDisplayId displayId) { mVirtualDisplayIdGenerators.gpu.releaseId(*id); } -std::vector<PhysicalDisplayId> SurfaceFlinger::getPhysicalDisplayIds() const { - Mutex::Autolock lock(mStateLock); - +std::vector<PhysicalDisplayId> SurfaceFlinger::getPhysicalDisplayIdsLocked() const { const auto internalDisplayId = getInternalDisplayIdLocked(); if (!internalDisplayId) { return {}; @@ -728,7 +712,7 @@ void SurfaceFlinger::bootFinished() { mBootStage = BootStage::FINISHED; if (property_get_bool("sf.debug.show_refresh_rate_overlay", false)) { - enableRefreshRateOverlay(true); + ON_MAIN_THREAD(enableRefreshRateOverlay(true)); } })); } @@ -792,6 +776,8 @@ void SurfaceFlinger::init() { ? renderengine::RenderEngine::ContextPriority::REALTIME : renderengine::RenderEngine::ContextPriority::MEDIUM) .build())); + mMaxRenderTargetSize = + std::min(getRenderEngine().getMaxTextureSize(), getRenderEngine().getMaxViewportDims()); // Set SF main policy after initializing RenderEngine which has its own policy. if (!SetTaskProfiles(0, {"SFMainPolicy"})) { @@ -837,7 +823,7 @@ void SurfaceFlinger::init() { } } - getRenderEngine().onPrimaryDisplaySizeChanged(display->getSize()); + onActiveDisplaySizeChanged(display); // Inform native graphics APIs whether the present timestamp is supported: @@ -879,14 +865,6 @@ void SurfaceFlinger::startBootAnim() { } } -size_t SurfaceFlinger::getMaxTextureSize() const { - return getRenderEngine().getMaxTextureSize(); -} - -size_t SurfaceFlinger::getMaxViewportDims() const { - return getRenderEngine().getMaxViewportDims(); -} - // ---------------------------------------------------------------------------- bool SurfaceFlinger::authenticateSurfaceTexture( @@ -1075,36 +1053,28 @@ status_t SurfaceFlinger::getDisplayStats(const sp<IBinder>&, DisplayStatInfo* st void SurfaceFlinger::setDesiredActiveMode(const ActiveModeInfo& info) { ATRACE_CALL(); - auto refreshRate = mRefreshRateConfigs->getRefreshRateFromModeId(info.modeId); - ALOGV("%s(%s)", __func__, refreshRate.getName().c_str()); - - std::lock_guard<std::mutex> lock(mActiveModeLock); - if (mDesiredActiveModeChanged) { - // If a mode change is pending, just cache the latest request in mDesiredActiveMode - const Scheduler::ModeEvent prevConfig = mDesiredActiveMode.event; - mDesiredActiveMode = info; - mDesiredActiveMode.event = mDesiredActiveMode.event | prevConfig; - } else { - // Check if we are already at the desired mode - const auto display = getDefaultDisplayDeviceLocked(); - if (!display || display->getActiveMode()->getId() == refreshRate.getModeId()) { - return; - } - // Initiate a mode change. - mDesiredActiveModeChanged = true; - mDesiredActiveMode = info; + if (!info.mode) { + ALOGW("requested display mode is null"); + return; + } + auto display = getDisplayDeviceLocked(info.mode->getPhysicalDisplayId()); + if (!display) { + ALOGW("%s: display is no longer valid", __func__); + return; + } + if (display->setDesiredActiveMode(info)) { // This will trigger HWC refresh without resetting the idle timer. repaintEverythingForHWC(); // Start receiving vsync samples now, so that we can detect a period // switch. - mScheduler->resyncToHardwareVsync(true, refreshRate.getVsyncPeriod()); + mScheduler->resyncToHardwareVsync(true, info.mode->getVsyncPeriod()); // As we called to set period, we will call to onRefreshRateChangeCompleted once // VsyncController model is locked. modulateVsync(&VsyncModulator::onRefreshRateChangeInitiated); - updatePhaseConfiguration(refreshRate.getFps()); + updatePhaseConfiguration(info.mode->getFps()); mScheduler->setModeChangePending(true); } } @@ -1138,7 +1108,7 @@ status_t SurfaceFlinger::setActiveMode(const sp<IBinder>& displayToken, int mode const auto fps = mode->getFps(); // Keep the old switching type. const auto allowGroupSwitching = - mRefreshRateConfigs->getCurrentPolicy().allowGroupSwitching; + display->refreshRateConfigs().getCurrentPolicy().allowGroupSwitching; const scheduler::RefreshRateConfigs::Policy policy{mode->getId(), allowGroupSwitching, {fps, fps}}; @@ -1158,63 +1128,49 @@ void SurfaceFlinger::setActiveModeInternal() { return; } - const auto upcomingMode = display->getMode(mUpcomingActiveMode.modeId); - if (!upcomingMode) { - ALOGW("Upcoming active mode is no longer supported. Mode ID = %d", - mUpcomingActiveMode.modeId.value()); - // TODO(b/159590486) Handle the error better. Some parts of SurfaceFlinger may - // have been already updated with the upcoming active mode. + const auto upcomingModeInfo = MAIN_THREAD_GUARD(display->getUpcomingActiveMode()); + if (!upcomingModeInfo.mode) { + // There is no pending mode change. This can happen if the active + // display changed and the mode change happened on a different display. return; } - if (display->getActiveMode()->getSize() != upcomingMode->getSize()) { + if (display->getActiveMode()->getSize() != upcomingModeInfo.mode->getSize()) { auto& state = mCurrentState.displays.editValueFor(display->getDisplayToken()); // We need to generate new sequenceId in order to recreate the display (and this // way the framebuffer). state.sequenceId = DisplayDeviceState{}.sequenceId; - state.physical->activeMode = upcomingMode; + state.physical->activeMode = upcomingModeInfo.mode; processDisplayChangesLocked(); // processDisplayChangesLocked will update all necessary components so we're done here. return; } - std::lock_guard<std::mutex> lock(mActiveModeLock); - mRefreshRateConfigs->setCurrentModeId(mUpcomingActiveMode.modeId); - display->setActiveMode(mUpcomingActiveMode.modeId); - - const Fps refreshRate = upcomingMode->getFps(); + // We just created this display so we can call even if we are not on + // the main thread + MainThreadScopedGuard fakeMainThreadGuard(SF_MAIN_THREAD); + display->setActiveMode(upcomingModeInfo.mode->getId()); + const Fps refreshRate = upcomingModeInfo.mode->getFps(); mRefreshRateStats->setRefreshRate(refreshRate); - updatePhaseConfiguration(refreshRate); - ATRACE_INT("ActiveConfigFPS", refreshRate.getValue()); - - if (mRefreshRateOverlay) { - mRefreshRateOverlay->changeRefreshRate(upcomingMode->getFps()); - } - if (mUpcomingActiveMode.event != Scheduler::ModeEvent::None) { - const nsecs_t vsyncPeriod = refreshRate.getPeriodNsecs(); - const auto physicalId = display->getPhysicalId(); - mScheduler->onPrimaryDisplayModeChanged(mAppConnectionHandle, physicalId, - mUpcomingActiveMode.modeId, vsyncPeriod); + if (upcomingModeInfo.event != Scheduler::ModeEvent::None) { + mScheduler->onPrimaryDisplayModeChanged(mAppConnectionHandle, upcomingModeInfo.mode); } } -void SurfaceFlinger::clearDesiredActiveModeState() { - std::lock_guard<std::mutex> lock(mActiveModeLock); - mDesiredActiveMode.event = Scheduler::ModeEvent::None; - mDesiredActiveModeChanged = false; - mScheduler->setModeChangePending(false); +void SurfaceFlinger::clearDesiredActiveModeState(const sp<DisplayDevice>& display) { + display->clearDesiredActiveModeState(); + if (isDisplayActiveLocked(display)) { + mScheduler->setModeChangePending(false); + } } -void SurfaceFlinger::desiredActiveModeChangeDone() { - const auto modeId = getDesiredActiveMode()->modeId; - - clearDesiredActiveModeState(); - - const auto refreshRate = getDefaultDisplayDeviceLocked()->getMode(modeId)->getFps(); +void SurfaceFlinger::desiredActiveModeChangeDone(const sp<DisplayDevice>& display) { + const auto refreshRate = display->getDesiredActiveMode()->mode->getFps(); + clearDesiredActiveModeState(display); mScheduler->resyncToHardwareVsync(true, refreshRate.getPeriodNsecs()); updatePhaseConfiguration(refreshRate); } @@ -1222,63 +1178,75 @@ void SurfaceFlinger::desiredActiveModeChangeDone() { void SurfaceFlinger::performSetActiveMode() { ATRACE_CALL(); ALOGV("%s", __FUNCTION__); - // Store the local variable to release the lock. - const auto desiredActiveMode = getDesiredActiveMode(); - if (!desiredActiveMode) { - // No desired active mode pending to be applied - return; - } - const auto display = getDefaultDisplayDeviceLocked(); - const auto desiredMode = display->getMode(desiredActiveMode->modeId); - if (!desiredMode) { - ALOGW("Desired display mode is no longer supported. Mode ID = %d", - desiredActiveMode->modeId.value()); - clearDesiredActiveModeState(); - return; - } - const auto refreshRate = desiredMode->getFps(); - ALOGV("%s changing active mode to %d(%s)", __FUNCTION__, desiredMode->getId().value(), - to_string(refreshRate).c_str()); + for (const auto& iter : mDisplays) { + const auto& display = iter.second; + if (!display || !display->isInternal()) { + continue; + } - if (!display || display->getActiveMode()->getId() == desiredActiveMode->modeId) { - // display is not valid or we are already in the requested mode - // on both cases there is nothing left to do - desiredActiveModeChangeDone(); - return; - } + // Store the local variable to release the lock. + const auto desiredActiveMode = display->getDesiredActiveMode(); + if (!desiredActiveMode) { + // No desired active mode pending to be applied + continue; + } - // Desired active mode was set, it is different than the mode currently in use, however - // allowed modes might have changed by the time we process the refresh. - // Make sure the desired mode is still allowed - if (!isDisplayModeAllowed(desiredActiveMode->modeId)) { - desiredActiveModeChangeDone(); - return; - } + if (!isDisplayActiveLocked(display)) { + // display is no longer the active display, so abort the mode change + clearDesiredActiveModeState(display); + continue; + } - mUpcomingActiveMode = *desiredActiveMode; + const auto desiredMode = display->getMode(desiredActiveMode->mode->getId()); + if (!desiredMode) { + ALOGW("Desired display mode is no longer supported. Mode ID = %d", + desiredActiveMode->mode->getId().value()); + clearDesiredActiveModeState(display); + continue; + } - ATRACE_INT("ActiveModeFPS_HWC", refreshRate.getValue()); + const auto refreshRate = desiredMode->getFps(); + ALOGV("%s changing active mode to %d(%s) for display %s", __func__, + desiredMode->getId().value(), to_string(refreshRate).c_str(), + to_string(display->getId()).c_str()); - // TODO(b/142753666) use constrains - hal::VsyncPeriodChangeConstraints constraints; - constraints.desiredTimeNanos = systemTime(); - constraints.seamlessRequired = false; + if (display->getActiveMode()->getId() == desiredActiveMode->mode->getId()) { + // display is not valid or we are already in the requested mode + // on both cases there is nothing left to do + desiredActiveModeChangeDone(display); + continue; + } - hal::VsyncPeriodChangeTimeline outTimeline; - const auto status = - display->initiateModeChange(mUpcomingActiveMode.modeId, constraints, &outTimeline); - if (status != NO_ERROR) { - // initiateModeChange may fail if a hotplug event is just about - // to be sent. We just log the error in this case. - ALOGW("initiateModeChange failed: %d", status); - return; - } + // Desired active mode was set, it is different than the mode currently in use, however + // allowed modes might have changed by the time we process the refresh. + // Make sure the desired mode is still allowed + const auto displayModeAllowed = + display->refreshRateConfigs().isModeAllowed(desiredActiveMode->mode->getId()); + if (!displayModeAllowed) { + desiredActiveModeChangeDone(display); + continue; + } - mScheduler->onNewVsyncPeriodChangeTimeline(outTimeline); + // TODO(b/142753666) use constrains + hal::VsyncPeriodChangeConstraints constraints; + constraints.desiredTimeNanos = systemTime(); + constraints.seamlessRequired = false; + hal::VsyncPeriodChangeTimeline outTimeline; + + const auto status = MAIN_THREAD_GUARD( + display->initiateModeChange(*desiredActiveMode, constraints, &outTimeline)); + if (status != NO_ERROR) { + // initiateModeChange may fail if a hotplug event is just about + // to be sent. We just log the error in this case. + ALOGW("initiateModeChange failed: %d", status); + continue; + } + mScheduler->onNewVsyncPeriodChangeTimeline(outTimeline); - // Scheduler will submit an empty frame to HWC if needed. - mSetActiveModePending = true; + // Scheduler will submit an empty frame to HWC if needed. + mSetActiveModePending = true; + } } void SurfaceFlinger::disableExpensiveRendering() { @@ -1720,10 +1688,10 @@ void SurfaceFlinger::onComposerHalVsync(hal::HWDisplayId hwcDisplayId, int64_t t ATRACE_CALL(); Mutex::Autolock lock(mStateLock); - - if (const auto displayId = getHwComposer().toPhysicalDisplayId(hwcDisplayId)) { - auto token = getPhysicalDisplayTokenLocked(*displayId); - auto display = getDisplayDeviceLocked(token); + const auto displayId = getHwComposer().toPhysicalDisplayId(hwcDisplayId); + if (displayId) { + const auto token = getPhysicalDisplayTokenLocked(*displayId); + const auto display = getDisplayDeviceLocked(token); display->onVsync(timestamp); } @@ -1731,8 +1699,10 @@ void SurfaceFlinger::onComposerHalVsync(hal::HWDisplayId hwcDisplayId, int64_t t return; } - if (hwcDisplayId != getHwComposer().getInternalHwcDisplayId()) { - // For now, we don't do anything with external display vsyncs. + const bool isActiveDisplay = + displayId && getPhysicalDisplayTokenLocked(*displayId) == mActiveDisplayToken; + if (!isActiveDisplay) { + // For now, we don't do anything with non active display vsyncs. return; } @@ -1748,10 +1718,6 @@ void SurfaceFlinger::getCompositorTiming(CompositorTiming* compositorTiming) { *compositorTiming = getBE().mCompositorTiming; } -bool SurfaceFlinger::isDisplayModeAllowed(DisplayModeId modeId) const { - return mRefreshRateConfigs->isModeAllowed(modeId); -} - void SurfaceFlinger::changeRefreshRateLocked(const RefreshRate& refreshRate, Scheduler::ModeEvent event) { const auto display = getDefaultDisplayDeviceLocked(); @@ -1761,13 +1727,13 @@ void SurfaceFlinger::changeRefreshRateLocked(const RefreshRate& refreshRate, ATRACE_CALL(); // Don't do any updating if the current fps is the same as the new one. - if (!isDisplayModeAllowed(refreshRate.getModeId())) { + if (!display->refreshRateConfigs().isModeAllowed(refreshRate.getModeId())) { ALOGV("Skipping mode %d as it is not part of allowed modes", refreshRate.getModeId().value()); return; } - setDesiredActiveMode({refreshRate.getModeId(), event}); + setDesiredActiveMode({refreshRate.getMode(), event}); } void SurfaceFlinger::onComposerHalHotplug(hal::HWDisplayId hwcDisplayId, @@ -1965,8 +1931,13 @@ void SurfaceFlinger::onMessageInvalidate(int64_t vsyncId, nsecs_t expectedVSyncT } if (mRefreshRateOverlaySpinner) { - if (Mutex::Autolock lock(mStateLock); mRefreshRateOverlay) { - mRefreshRateOverlay->onInvalidate(); + if (Mutex::Autolock lock(mStateLock); + const auto display = getDefaultDisplayDeviceLocked()) { + if (display) { + display->onInvalidate(); + } else { + ALOGW("%s: default display is null", __func__); + } } } @@ -2352,7 +2323,7 @@ void SurfaceFlinger::postComposition() { mTransactionCallbackInvoker.addPresentFence(mPreviousPresentFences[0].fence); mTransactionCallbackInvoker.sendCallbacks(); - if (display && display->isPrimary() && display->getPowerMode() == hal::PowerMode::ON && + if (display && display->isInternal() && display->getPowerMode() == hal::PowerMode::ON && mPreviousPresentFences[0].fenceTime->isValid()) { mScheduler->addPresentFence(mPreviousPresentFences[0].fenceTime); } @@ -2442,23 +2413,28 @@ void SurfaceFlinger::postComposition() { } } -FloatRect SurfaceFlinger::getLayerClipBoundsForDisplay(const DisplayDevice& displayDevice) const { - return displayDevice.getLayerStackSpaceRect().toFloatRect(); -} - void SurfaceFlinger::computeLayerBounds() { + // Find the largest width and height among all the displays. + int32_t maxDisplayWidth = 0; + int32_t maxDisplayHeight = 0; for (const auto& pair : ON_MAIN_THREAD(mDisplays)) { const auto& displayDevice = pair.second; - const auto display = displayDevice->getCompositionDisplay(); - for (const auto& layer : mDrawingState.layersSortedByZ) { - // only consider the layers on the given layer stack - if (!display->belongsInOutput(layer->getLayerStack(), layer->getPrimaryDisplayOnly())) { - continue; - } - - layer->computeBounds(getLayerClipBoundsForDisplay(*displayDevice), ui::Transform(), - 0.f /* shadowRadius */); + int32_t width = displayDevice->getWidth(); + int32_t height = displayDevice->getHeight(); + if (width > maxDisplayWidth) { + maxDisplayWidth = width; } + if (height > maxDisplayHeight) { + maxDisplayHeight = height; + } + } + + // Ignore display bounds for now since they will be computed later. Use a large Rect bound + // to ensure it's bigger than an actual display will be. + FloatRect maxBounds(-maxDisplayWidth * 10, -maxDisplayHeight * 10, maxDisplayWidth * 10, + maxDisplayHeight * 10); + for (const auto& layer : mDrawingState.layersSortedByZ) { + layer->computeBounds(maxBounds, ui::Transform(), 0.f /* shadowRadius */); } } @@ -2489,7 +2465,6 @@ void SurfaceFlinger::handleTransaction(uint32_t transactionFlags) { // We call getTransactionFlags(), which will also clear the flags, // with mStateLock held to guarantee that mCurrentState won't change // until the transaction is committed. - modulateVsync(&VsyncModulator::onTransactionCommit); transactionFlags = getTransactionFlags(eTransactionMask); handleTransactionLocked(transactionFlags); @@ -2540,6 +2515,7 @@ void SurfaceFlinger::loadDisplayModes(PhysicalDisplayId displayId, DisplayModes& for (const auto& hwcMode : hwcModes) { newModes.push_back(DisplayMode::Builder(hwcMode.hwcId) .setId(DisplayModeId{nextModeId++}) + .setPhysicalDisplayId(displayId) .setWidth(hwcMode.width) .setHeight(hwcMode.height) .setVsyncPeriod(hwcMode.vsyncPeriod) @@ -2601,11 +2577,6 @@ void SurfaceFlinger::processDisplayHotplugEventsLocked() { sp<IBinder> token = new BBinder(); mCurrentState.displays.add(token, state); mPhysicalDisplayTokens.emplace(displayId, std::move(token)); - - if (event.hwcDisplayId == getHwComposer().getInternalHwcDisplayId()) { - initScheduler(state); - } - mInterceptor->saveDisplayCreation(state); } else { ALOGV("Recreating display %s", to_string(displayId).c_str()); @@ -2660,6 +2631,14 @@ sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal( if (const auto& physical = state.physical) { creationArgs.connectionType = physical->type; creationArgs.supportedModes = physical->supportedModes; + creationArgs.activeModeId = physical->activeMode->getId(); + scheduler::RefreshRateConfigs::Config config = + {.enableFrameRateOverride = android::sysprop::enable_frame_rate_override(false), + .frameRateMultipleThreshold = + base::GetIntProperty("debug.sf.frame_rate_multiple_threshold", 0)}; + creationArgs.refreshRateConfigs = + std::make_shared<scheduler::RefreshRateConfigs>(creationArgs.supportedModes, + creationArgs.activeModeId, config); } if (const auto id = PhysicalDisplayId::tryCast(compositionDisplay->getId())) { @@ -2716,7 +2695,7 @@ sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal( RenderIntent::COLORIMETRIC, Dataspace::UNKNOWN}); if (!state.isVirtual()) { - display->setActiveMode(state.physical->activeMode->getId()); + MAIN_THREAD_GUARD(display->setActiveMode(state.physical->activeMode->getId())); display->setDeviceProductInfo(state.physical->deviceProductInfo); } @@ -2756,7 +2735,7 @@ void SurfaceFlinger::processDisplayAdded(const wp<IBinder>& displayToken, builder.setId(physical->id); builder.setConnectionType(physical->type); } else { - builder.setId(acquireVirtualDisplay(resolution, pixelFormat, state.layerStack)); + builder.setId(acquireVirtualDisplay(resolution, pixelFormat)); } builder.setPixels(resolution); @@ -2798,14 +2777,12 @@ void SurfaceFlinger::processDisplayAdded(const wp<IBinder>& displayToken, const auto display = setupNewDisplayDeviceInternal(displayToken, std::move(compositionDisplay), state, displaySurface, producer); mDisplays.emplace(displayToken, display); + if (display->isPrimary()) { + initScheduler(display); + } if (!state.isVirtual()) { dispatchDisplayHotplugEvent(display->getPhysicalId(), true); } - - if (display->isPrimary()) { - mScheduler->onPrimaryDisplayAreaChanged(display->getWidth() * display->getHeight()); - getRenderEngine().onPrimaryDisplaySizeChanged(display->getSize()); - } } void SurfaceFlinger::processDisplayRemoved(const wp<IBinder>& displayToken) { @@ -2870,16 +2847,7 @@ void SurfaceFlinger::processDisplayChanged(const wp<IBinder>& displayToken, // TODO(b/175678251) Call a listener instead. if (currentState.physical->hwcDisplayId == getHwComposer().getInternalHwcDisplayId()) { - mRefreshRateConfigs->updateDisplayModes(currentState.physical->supportedModes, - currentState.physical->activeMode->getId()); - mVsyncConfiguration->reset(); - const Fps refreshRate = currentState.physical->activeMode->getFps(); - updatePhaseConfiguration(refreshRate); - mRefreshRateStats->setRefreshRate(refreshRate); - - if (mRefreshRateOverlay) { - mRefreshRateOverlay->reset(); - } + updateInternalDisplayVsyncLocked(display); } } return; @@ -2889,29 +2857,34 @@ void SurfaceFlinger::processDisplayChanged(const wp<IBinder>& displayToken, if (currentState.layerStack != drawingState.layerStack) { display->setLayerStack(currentState.layerStack); } + if (currentState.flags != drawingState.flags) { + display->setFlags(currentState.flags); + } if ((currentState.orientation != drawingState.orientation) || (currentState.layerStackSpaceRect != drawingState.layerStackSpaceRect) || (currentState.orientedDisplaySpaceRect != drawingState.orientedDisplaySpaceRect)) { display->setProjection(currentState.orientation, currentState.layerStackSpaceRect, currentState.orientedDisplaySpaceRect); - if (display->isPrimary()) { - mDefaultDisplayTransformHint = display->getTransformHint(); + if (isDisplayActiveLocked(display)) { + mActiveDisplayTransformHint = display->getTransformHint(); } } if (currentState.width != drawingState.width || currentState.height != drawingState.height) { display->setDisplaySize(currentState.width, currentState.height); - if (display->isPrimary()) { - mScheduler->onPrimaryDisplayAreaChanged(currentState.width * currentState.height); - } - - if (mRefreshRateOverlay) { - mRefreshRateOverlay->setViewport(display->getSize()); + if (isDisplayActiveLocked(display)) { + onActiveDisplaySizeChanged(display); } } } } +void SurfaceFlinger::updateInternalDisplayVsyncLocked(const sp<DisplayDevice>& activeDisplay) { + mVsyncConfiguration->reset(); + const Fps refreshRate = activeDisplay->refreshRateConfigs().getCurrentRefreshRate().getFps(); + updatePhaseConfiguration(refreshRate); + mRefreshRateStats->setRefreshRate(refreshRate); +} void SurfaceFlinger::processDisplayChangesLocked() { // here we take advantage of Vector's copy-on-write semantics to @@ -3073,11 +3046,11 @@ void SurfaceFlinger::updateInputFlinger() { if (mVisibleRegionsDirty || mInputInfoChanged) { mInputInfoChanged = false; - updateInputWindowInfo(); + notifyWindowInfos(); } else if (mInputWindowCommands.syncInputWindows) { // If the caller requested to sync input windows, but there are no // changes to input windows, notify immediately. - setInputWindowsFinished(); + windowInfosReported(); } for (const auto& focusRequest : mInputWindowCommands.focusRequests) { @@ -3092,31 +3065,20 @@ bool enablePerWindowInputRotation() { return value; } -void SurfaceFlinger::updateInputWindowInfo() { - std::vector<InputWindowInfo> inputInfos; +void SurfaceFlinger::notifyWindowInfos() { + std::vector<WindowInfo> windowInfos; mDrawingState.traverseInReverseZOrder([&](Layer* layer) { if (!layer->needsInputInfo()) return; - sp<DisplayDevice> display; - if (enablePerWindowInputRotation()) { - for (const auto& pair : ON_MAIN_THREAD(mDisplays)) { - const auto& displayDevice = pair.second; - if (!displayDevice->getCompositionDisplay() - ->belongsInOutput(layer->getLayerStack(), - layer->getPrimaryDisplayOnly())) { - continue; - } - display = displayDevice; - } - } + sp<DisplayDevice> display = enablePerWindowInputRotation() + ? ON_MAIN_THREAD(getDisplayWithInputByLayer(layer)) + : nullptr; // When calculating the screen bounds we ignore the transparent region since it may // result in an unwanted offset. - inputInfos.push_back(layer->fillInputInfo(display)); + windowInfos.push_back(layer->fillInputInfo(display)); }); - - mInputFlinger->setInputWindows(inputInfos, - mInputWindowCommands.syncInputWindows ? mSetInputWindowsListener - : nullptr); + mWindowInfosListenerInvoker->windowInfosChanged(windowInfos, + mInputWindowCommands.syncInputWindows); } void SurfaceFlinger::updateCursorAsync() { @@ -3148,24 +3110,16 @@ void SurfaceFlinger::triggerOnFrameRateOverridesChanged() { mScheduler->onFrameRateOverridesChanged(mAppConnectionHandle, displayId); } -void SurfaceFlinger::initScheduler(const DisplayDeviceState& displayState) { +void SurfaceFlinger::initScheduler(const sp<DisplayDevice>& display) { if (mScheduler) { - // In practice it's not allowed to hotplug in/out the primary display once it's been - // connected during startup, but some tests do it, so just warn and return. - ALOGW("Can't re-init scheduler"); + // If the scheduler is already initialized, this means that we received + // a hotplug(connected) on the primary display. In that case we should + // update the scheduler with the most recent display information. + ALOGW("Scheduler already initialized, updating instead"); + mScheduler->setRefreshRateConfigs(display->holdRefreshRateConfigs()); return; } - const auto displayId = displayState.physical->id; - scheduler::RefreshRateConfigs::Config config = - {.enableFrameRateOverride = android::sysprop::enable_frame_rate_override(false), - .frameRateMultipleThreshold = - base::GetIntProperty("debug.sf.frame_rate_multiple_threshold", 0)}; - mRefreshRateConfigs = - std::make_unique<scheduler::RefreshRateConfigs>(displayState.physical->supportedModes, - displayState.physical->activeMode - ->getId(), - config); - const auto currRefreshRate = displayState.physical->activeMode->getFps(); + const auto currRefreshRate = display->getActiveMode()->getFps(); mRefreshRateStats = std::make_unique<scheduler::RefreshRateStats>(*mTimeStats, currRefreshRate, hal::PowerMode::OFF); @@ -3173,7 +3127,7 @@ void SurfaceFlinger::initScheduler(const DisplayDeviceState& displayState) { mVsyncModulator = sp<VsyncModulator>::make(mVsyncConfiguration->getCurrentConfigs()); // start the EventThread - mScheduler = getFactory().createScheduler(*mRefreshRateConfigs, *this); + mScheduler = getFactory().createScheduler(display->holdRefreshRateConfigs(), *this); const auto configs = mVsyncConfiguration->getCurrentConfigs(); const nsecs_t vsyncPeriod = currRefreshRate.getPeriodNsecs(); mAppConnectionHandle = @@ -3202,9 +3156,7 @@ void SurfaceFlinger::initScheduler(const DisplayDeviceState& displayState) { // This is a bit hacky, but this avoids a back-pointer into the main SF // classes from EventThread, and there should be no run-time binder cost // anyway since there are no connected apps at this point. - mScheduler->onPrimaryDisplayModeChanged(mAppConnectionHandle, displayId, - displayState.physical->activeMode->getId(), - vsyncPeriod); + mScheduler->onPrimaryDisplayModeChanged(mAppConnectionHandle, display->getActiveMode()); static auto ignorePresentFences = base::GetBoolProperty("debug.sf.vsync_reactor_ignore_present_fences"s, false); mScheduler->setIgnorePresentFences( @@ -3418,9 +3370,9 @@ status_t SurfaceFlinger::addClientLayer(const sp<Client>& client, const sp<IBind composerState.state.surface = handle; states.add(composerState); - lbc->updateTransformHint(mDefaultDisplayTransformHint); + lbc->updateTransformHint(mActiveDisplayTransformHint); if (outTransformHint) { - *outTransformHint = mDefaultDisplayTransformHint; + *outTransformHint = mActiveDisplayTransformHint; } // attach this layer to the client client->attachLayer(handle, lbc); @@ -3857,6 +3809,12 @@ uint32_t SurfaceFlinger::setDisplayStateLocked(const DisplayState& s) { flags |= eDisplayTransactionNeeded; } } + if (what & DisplayState::eFlagsChanged) { + if (state.flags != s.flags) { + state.flags = s.flags; + flags |= eDisplayTransactionNeeded; + } + } if (what & DisplayState::eDisplayProjectionChanged) { if (state.orientation != s.orientation) { state.orientation = s.orientation; @@ -4115,10 +4073,10 @@ uint32_t SurfaceFlinger::setClientStateLocked( } if (what & layer_state_t::eInputInfoChanged) { if (privileged) { - layer->setInputInfo(*s.inputHandle->getInfo()); + layer->setInputInfo(*s.windowInfoHandle->getInfo()); flags |= eTraversalNeeded; } else { - ALOGE("Attempt to update InputWindowInfo without permission ACCESS_SURFACE_FLINGER"); + ALOGE("Attempt to update WindowInfo without permission ACCESS_SURFACE_FLINGER"); } } std::optional<nsecs_t> dequeueBufferTimestamp; @@ -4216,17 +4174,30 @@ uint32_t SurfaceFlinger::setClientStateLocked( } bool bufferChanged = what & layer_state_t::eBufferChanged; bool cacheIdChanged = what & layer_state_t::eCachedBufferChanged; + bool bufferSizeExceedsLimit = false; std::shared_ptr<renderengine::ExternalTexture> buffer; if (bufferChanged && cacheIdChanged && s.buffer != nullptr) { - ClientCache::getInstance().add(s.cachedBuffer, s.buffer); - buffer = ClientCache::getInstance().get(s.cachedBuffer); + bufferSizeExceedsLimit = + exceedsMaxRenderTargetSize(s.buffer->getWidth(), s.buffer->getHeight()); + if (!bufferSizeExceedsLimit) { + ClientCache::getInstance().add(s.cachedBuffer, s.buffer); + buffer = ClientCache::getInstance().get(s.cachedBuffer); + } } else if (cacheIdChanged) { buffer = ClientCache::getInstance().get(s.cachedBuffer); } else if (bufferChanged && s.buffer != nullptr) { - buffer = std::make_shared< - renderengine::ExternalTexture>(s.buffer, getRenderEngine(), - renderengine::ExternalTexture::Usage::READABLE); - } + bufferSizeExceedsLimit = + exceedsMaxRenderTargetSize(s.buffer->getWidth(), s.buffer->getHeight()); + if (!bufferSizeExceedsLimit) { + buffer = std::make_shared< + renderengine::ExternalTexture>(s.buffer, getRenderEngine(), + renderengine::ExternalTexture::Usage::READABLE); + } + } + ALOGE_IF(bufferSizeExceedsLimit, + "Attempted to create an ExternalTexture for layer %s that exceeds render target size " + "limit.", + layer->getDebugName()); if (buffer) { const bool frameNumberChanged = what & layer_state_t::eFrameNumberChanged; const uint64_t frameNumber = frameNumberChanged @@ -4235,7 +4206,7 @@ uint32_t SurfaceFlinger::setClientStateLocked( if (layer->setBuffer(buffer, s.acquireFence, postTime, desiredPresentTime, isAutoTimestamp, s.cachedBuffer, frameNumber, dequeueBufferTimestamp, frameTimelineInfo, - s.releaseBufferListener)) { + s.releaseBufferListener, s.releaseBufferEndpoint)) { flags |= eTraversalNeeded; } } else if (frameTimelineInfo.vsyncId != FrameTimelineInfo::INVALID_VSYNC_ID) { @@ -4509,9 +4480,10 @@ void SurfaceFlinger::onInitializeDisplays() { {}, getpid(), getuid(), 0 /* Undefined transactionId */); setPowerModeInternal(display, hal::PowerMode::ON); - const nsecs_t vsyncPeriod = mRefreshRateConfigs->getCurrentRefreshRate().getVsyncPeriod(); + const nsecs_t vsyncPeriod = + display->refreshRateConfigs().getCurrentRefreshRate().getVsyncPeriod(); mAnimFrameTracker.setDisplayRefreshPeriod(vsyncPeriod); - mDefaultDisplayTransformHint = display->getTransformHint(); + mActiveDisplayTransformHint = display->getTransformHint(); // Use phase of 0 since phase is not known. // Use latency of 0, which will snap to the ideal latency. DisplayStatInfo stats{0 /* vsyncTime */, vsyncPeriod}; @@ -4523,6 +4495,26 @@ void SurfaceFlinger::initializeDisplays() { static_cast<void>(schedule([this]() MAIN_THREAD { onInitializeDisplays(); })); } +sp<DisplayDevice> SurfaceFlinger::getDisplayWithInputByLayer(Layer* layer) const { + sp<DisplayDevice> display; + for (const auto& pair : mDisplays) { + const auto& displayDevice = pair.second; + if (!displayDevice->receivesInput() || + !displayDevice->getCompositionDisplay() + ->belongsInOutput(layer->getLayerStack(), layer->getPrimaryDisplayOnly())) { + continue; + } + // Don't return immediately so that we can log duplicates. + if (display) { + ALOGE("Multiple display devices claim to accept input for the same layerstack: %d", + layer->getLayerStack()); + continue; + } + display = displayDevice; + } + return display; +} + void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, hal::PowerMode mode) { if (display->isVirtual()) { ALOGE("%s: Invalid operation on virtual display", __FUNCTION__); @@ -4542,8 +4534,12 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, hal: if (mInterceptor->isEnabled()) { mInterceptor->savePowerModeUpdate(display->getSequenceId(), static_cast<int32_t>(mode)); } - const auto vsyncPeriod = mRefreshRateConfigs->getCurrentRefreshRate().getVsyncPeriod(); + const auto vsyncPeriod = display->refreshRateConfigs().getCurrentRefreshRate().getVsyncPeriod(); if (currentMode == hal::PowerMode::OFF) { + const auto activeDisplay = getDisplayDeviceLocked(mActiveDisplayToken); + if (display->isInternal() && (!activeDisplay || !activeDisplay->isPoweredOn())) { + onActiveDisplayChangedLocked(display); + } // Keep uclamp in a separate syscall and set it before changing to RT due to b/190237315. // We can merge the syscall later. if (SurfaceFlinger::setSchedAttr(true) != NO_ERROR) { @@ -4553,7 +4549,7 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, hal: ALOGW("Couldn't set SCHED_FIFO on display on: %s\n", strerror(errno)); } getHwComposer().setPowerMode(displayId, mode); - if (display->isPrimary() && mode != hal::PowerMode::DOZE_SUSPEND) { + if (display->isInternal() && mode != hal::PowerMode::DOZE_SUSPEND) { getHwComposer().setVsyncEnabled(displayId, mHWCVsyncPendingState); mScheduler->onScreenAcquired(mAppConnectionHandle); mScheduler->resyncToHardwareVsync(true, vsyncPeriod); @@ -4570,7 +4566,7 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, hal: if (SurfaceFlinger::setSchedAttr(false) != NO_ERROR) { ALOGW("Couldn't set uclamp.min on display off: %s\n", strerror(errno)); } - if (display->isPrimary() && currentMode != hal::PowerMode::DOZE_SUSPEND) { + if (display->isInternal() && currentMode != hal::PowerMode::DOZE_SUSPEND) { mScheduler->disableHardwareVsync(true); mScheduler->onScreenReleased(mAppConnectionHandle); } @@ -4584,13 +4580,13 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, hal: } else if (mode == hal::PowerMode::DOZE || mode == hal::PowerMode::ON) { // Update display while dozing getHwComposer().setPowerMode(displayId, mode); - if (display->isPrimary() && currentMode == hal::PowerMode::DOZE_SUSPEND) { + if (display->isInternal() && currentMode == hal::PowerMode::DOZE_SUSPEND) { mScheduler->onScreenAcquired(mAppConnectionHandle); mScheduler->resyncToHardwareVsync(true, vsyncPeriod); } } else if (mode == hal::PowerMode::DOZE_SUSPEND) { // Leave display going to doze - if (display->isPrimary()) { + if (display->isInternal()) { mScheduler->disableHardwareVsync(true); mScheduler->onScreenReleased(mAppConnectionHandle); } @@ -4600,7 +4596,7 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, hal: getHwComposer().setPowerMode(displayId, mode); } - if (display->isPrimary()) { + if (display->isInternal()) { mTimeStats->setPowerMode(mode); mRefreshRateStats->setPowerMode(mode); mScheduler->setDisplayPowerState(mode == hal::PowerMode::ON); @@ -4670,12 +4666,17 @@ status_t SurfaceFlinger::doDump(int fd, const DumpArgs& args, bool asProto) { } if (dumpLayers) { - const LayersProto layersProto = dumpProtoFromMainThread(); + LayersTraceFileProto traceFileProto = SurfaceTracing::createLayersTraceFileProto(); + LayersTraceProto* layersTrace = traceFileProto.add_entry(); + LayersProto layersProto = dumpProtoFromMainThread(); + layersTrace->mutable_layers()->Swap(&layersProto); + dumpDisplayProto(*layersTrace); + if (asProto) { - result.append(layersProto.SerializeAsString()); + result.append(traceFileProto.SerializeAsString()); } else { // Dump info that we need to access from the main thread - const auto layerTree = LayerProtoParser::generateLayerTree(layersProto); + const auto layerTree = LayerProtoParser::generateLayerTree(layersTrace->layers()); result.append(LayerProtoParser::layerTreeToString(layerTree)); result.append("\n"); dumpOffscreenLayers(result); @@ -4769,8 +4770,6 @@ void SurfaceFlinger::dumpVSync(std::string& result) const { " present offset: %9" PRId64 " ns\t VSYNC period: %9" PRId64 " ns\n\n", dispSyncPresentTimeOffset, getVsyncPeriodFromHWC()); - mRefreshRateConfigs->dump(result); - StringAppendF(&result, "(mode override by backdoor: %s)\n\n", mDebugDisplayModeSetByBackdoor ? "yes" : "no"); @@ -4946,6 +4945,22 @@ LayersProto SurfaceFlinger::dumpDrawingStateProto(uint32_t traceFlags) const { return layersProto; } +void SurfaceFlinger::dumpDisplayProto(LayersTraceProto& layersTraceProto) const { + for (const auto& [_, display] : ON_MAIN_THREAD(mDisplays)) { + DisplayProto* displayProto = layersTraceProto.add_displays(); + displayProto->set_id(display->getId().value); + displayProto->set_name(display->getDisplayName()); + displayProto->set_layer_stack(display->getLayerStack()); + LayerProtoHelper::writeSizeToProto(display->getWidth(), display->getHeight(), + [&]() { return displayProto->mutable_size(); }); + LayerProtoHelper::writeToProto(display->getLayerStackSpaceRect(), [&]() { + return displayProto->mutable_layer_stack_space_rect(); + }); + LayerProtoHelper::writeTransformToProto(display->getTransform(), + displayProto->mutable_transform()); + } +} + void SurfaceFlinger::dumpHwc(std::string& result) const { getHwComposer().dump(result); } @@ -5333,6 +5348,14 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { } return PERMISSION_DENIED; } + case ADD_WINDOW_INFOS_LISTENER: + case REMOVE_WINDOW_INFOS_LISTENER: { + const int uid = IPCThreadState::self()->getCallingUid(); + if (uid == AID_SYSTEM || uid == AID_GRAPHICS) { + return OK; + } + return PERMISSION_DENIED; + } } // These codes are used for the IBinder protocol to either interrogate the recipient @@ -5646,16 +5669,17 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r return NO_ERROR; } case 1034: { - switch (n = data.readInt32()) { - case 0: - case 1: - enableRefreshRateOverlay(static_cast<bool>(n)); - break; - default: { - Mutex::Autolock lock(mStateLock); - reply->writeBool(mRefreshRateOverlay != nullptr); + schedule([&] { + switch (n = data.readInt32()) { + case 0: + case 1: + ON_MAIN_THREAD(enableRefreshRateOverlay(static_cast<bool>(n))); + break; + default: { + reply->writeBool(ON_MAIN_THREAD(isRefreshRateOverlayEnabled())); + } } - } + }).get(); return NO_ERROR; } case 1035: { @@ -5675,7 +5699,7 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r return std::make_optional<PhysicalDisplayId>(inputDisplayId); } - return getInternalDisplayId(); + return getDefaultDisplayDevice()->getPhysicalId(); }(); if (!displayId) { @@ -5801,22 +5825,25 @@ void SurfaceFlinger::kernelTimerChanged(bool expired) { static bool updateOverlay = property_get_bool("debug.sf.kernel_idle_timer_update_overlay", true); if (!updateOverlay) return; - if (Mutex::Autolock lock(mStateLock); !mRefreshRateOverlay) return; + if (Mutex::Autolock lock(mStateLock); !isRefreshRateOverlayEnabled()) return; // Update the overlay on the main thread to avoid race conditions with // mRefreshRateConfigs->getCurrentRefreshRate() static_cast<void>(schedule([=] { - const auto desiredActiveMode = getDesiredActiveMode(); - const std::optional<DisplayModeId> desiredModeId = - desiredActiveMode ? std::make_optional(desiredActiveMode->modeId) : std::nullopt; + const auto display = ON_MAIN_THREAD(getDefaultDisplayDeviceLocked()); + if (!display) { + ALOGW("%s: default display is null", __func__); + return; + } + + const auto desiredActiveMode = display->getDesiredActiveMode(); + const std::optional<DisplayModeId> desiredModeId = desiredActiveMode + ? std::make_optional(desiredActiveMode->mode->getId()) + : std::nullopt; const bool timerExpired = mKernelIdleTimerEnabled && expired; - const auto newRefreshRate = - mRefreshRateConfigs->onKernelTimerChanged(desiredModeId, timerExpired); - if (newRefreshRate) { - if (Mutex::Autolock lock(mStateLock); mRefreshRateOverlay) { - mRefreshRateOverlay->changeRefreshRate(*newRefreshRate); - } + + if (display->onKernelTimerChanged(desiredModeId, timerExpired)) { mEventQueue->invalidate(); } })); @@ -5829,8 +5856,13 @@ void SurfaceFlinger::toggleKernelIdleTimer() { if (!mSupportKernelIdleTimer) { return; } - const KernelIdleTimerAction action = mRefreshRateConfigs->getIdleTimerAction(); + const auto display = getDefaultDisplayDeviceLocked(); + if (!display) { + ALOGW("%s: default display is null", __func__); + return; + } + const KernelIdleTimerAction action = display->refreshRateConfigs().getIdleTimerAction(); switch (action) { case KernelIdleTimerAction::TurnOff: if (mKernelIdleTimerEnabled) { @@ -6186,6 +6218,13 @@ status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture, const sp<IScreenCaptureListener>& captureListener) { ATRACE_CALL(); + if (exceedsMaxRenderTargetSize(bufferSize.getWidth(), bufferSize.getHeight())) { + ALOGE("Attempted to capture screen with size (%" PRId32 ", %" PRId32 + ") that exceeds render target size limit.", + bufferSize.getWidth(), bufferSize.getHeight()); + return BAD_VALUE; + } + // Loop over all visible layers to see whether there's any protected layer. A protected layer is // typically a layer with DRM contents, or have the GRALLOC_USAGE_PROTECTED set on the buffer. // A protected layer has no implication on whether it's secure, which is explicitly set by @@ -6400,7 +6439,7 @@ status_t SurfaceFlinger::renderScreenImplLocked( return NO_ERROR; } -void SurfaceFlinger::setInputWindowsFinished() { +void SurfaceFlinger::windowInfosReported() { Mutex::Autolock _l(mStateLock); signalSynchronousTransactions(CountDownLatch::eSyncInputWindows); } @@ -6448,78 +6487,55 @@ status_t SurfaceFlinger::setDesiredDisplayModeSpecsInternal( const std::optional<scheduler::RefreshRateConfigs::Policy>& policy, bool overridePolicy) { Mutex::Autolock lock(mStateLock); - LOG_ALWAYS_FATAL_IF(!display->isPrimary() && overridePolicy, - "Can only set override policy on the primary display"); - LOG_ALWAYS_FATAL_IF(!policy && !overridePolicy, "Can only clear the override policy"); - if (mDebugDisplayModeSetByBackdoor) { // ignore this request as mode is overridden by backdoor return NO_ERROR; } - if (!display->isPrimary()) { - // TODO(b/144711714): For non-primary displays we should be able to set an active mode - // as well. For now, just call directly to initiateModeChange but ideally - // it should go thru setDesiredActiveMode, similar to primary display. - ALOGV("%s for non-primary display", __func__); - const auto displayId = display->getPhysicalId(); - - hal::VsyncPeriodChangeConstraints constraints; - constraints.desiredTimeNanos = systemTime(); - constraints.seamlessRequired = false; - - hal::VsyncPeriodChangeTimeline timeline = {0, 0, 0}; - if (display->initiateModeChange(policy->defaultMode, constraints, &timeline) != NO_ERROR) { - return BAD_VALUE; - } - if (timeline.refreshRequired) { - repaintEverythingForHWC(); - } - - display->setActiveMode(policy->defaultMode); - const nsecs_t vsyncPeriod = display->getMode(policy->defaultMode)->getVsyncPeriod(); - mScheduler->onNonPrimaryDisplayModeChanged(mAppConnectionHandle, displayId, - policy->defaultMode, vsyncPeriod); - return NO_ERROR; - } - status_t setPolicyResult = overridePolicy - ? mRefreshRateConfigs->setOverridePolicy(policy) - : mRefreshRateConfigs->setDisplayManagerPolicy(*policy); + ? display->refreshRateConfigs().setOverridePolicy(policy) + : display->refreshRateConfigs().setDisplayManagerPolicy(*policy); if (setPolicyResult < 0) { return BAD_VALUE; } if (setPolicyResult == scheduler::RefreshRateConfigs::CURRENT_POLICY_UNCHANGED) { return NO_ERROR; } - scheduler::RefreshRateConfigs::Policy currentPolicy = mRefreshRateConfigs->getCurrentPolicy(); + + scheduler::RefreshRateConfigs::Policy currentPolicy = + display->refreshRateConfigs().getCurrentPolicy(); ALOGV("Setting desired display mode specs: %s", currentPolicy.toString().c_str()); // TODO(b/140204874): Leave the event in until we do proper testing with all apps that might // be depending in this callback. const auto activeMode = display->getActiveMode(); - const nsecs_t vsyncPeriod = activeMode->getVsyncPeriod(); - const auto physicalId = display->getPhysicalId(); - mScheduler->onPrimaryDisplayModeChanged(mAppConnectionHandle, physicalId, activeMode->getId(), - vsyncPeriod); - toggleKernelIdleTimer(); - - auto modeId = mScheduler->getPreferredModeId(); - auto preferredRefreshRate = modeId - ? mRefreshRateConfigs->getRefreshRateFromModeId(*modeId) - // NOTE: Choose the default mode ID, if Scheduler doesn't have one in mind. - : mRefreshRateConfigs->getRefreshRateFromModeId(currentPolicy.defaultMode); + if (isDisplayActiveLocked(display)) { + mScheduler->onPrimaryDisplayModeChanged(mAppConnectionHandle, activeMode); + toggleKernelIdleTimer(); + } else { + mScheduler->onNonPrimaryDisplayModeChanged(mAppConnectionHandle, activeMode); + } + + const DisplayModePtr preferredDisplayMode = [&] { + const auto schedulerMode = mScheduler->getPreferredDisplayMode(); + if (schedulerMode && schedulerMode->getPhysicalDisplayId() == display->getPhysicalId()) { + return schedulerMode; + } + + return display->getMode(currentPolicy.defaultMode); + }(); + ALOGV("trying to switch to Scheduler preferred mode %d (%s)", - preferredRefreshRate.getModeId().value(), preferredRefreshRate.getName().c_str()); + preferredDisplayMode->getId().value(), to_string(preferredDisplayMode->getFps()).c_str()); - if (isDisplayModeAllowed(preferredRefreshRate.getModeId())) { + if (display->refreshRateConfigs().isModeAllowed(preferredDisplayMode->getId())) { ALOGV("switching to Scheduler preferred display mode %d", - preferredRefreshRate.getModeId().value()); - setDesiredActiveMode({preferredRefreshRate.getModeId(), Scheduler::ModeEvent::Changed}); + preferredDisplayMode->getId().value()); + setDesiredActiveMode({preferredDisplayMode, Scheduler::ModeEvent::Changed}); } else { LOG_ALWAYS_FATAL("Desired display mode not allowed: %d", - preferredRefreshRate.getModeId().value()); + preferredDisplayMode->getId().value()); } return NO_ERROR; @@ -6579,29 +6595,19 @@ status_t SurfaceFlinger::getDesiredDisplayModeSpecs(const sp<IBinder>& displayTo return NAME_NOT_FOUND; } - if (display->isPrimary()) { - scheduler::RefreshRateConfigs::Policy policy = - mRefreshRateConfigs->getDisplayManagerPolicy(); - *outDefaultMode = policy.defaultMode.value(); - *outAllowGroupSwitching = policy.allowGroupSwitching; - *outPrimaryRefreshRateMin = policy.primaryRange.min.getValue(); - *outPrimaryRefreshRateMax = policy.primaryRange.max.getValue(); - *outAppRequestRefreshRateMin = policy.appRequestRange.min.getValue(); - *outAppRequestRefreshRateMax = policy.appRequestRange.max.getValue(); - return NO_ERROR; - } else if (display->isVirtual()) { + if (display->isVirtual()) { return INVALID_OPERATION; - } else { - const auto activeMode = display->getActiveMode(); - *outDefaultMode = activeMode->getId().value(); - *outAllowGroupSwitching = false; - auto vsyncPeriod = activeMode->getVsyncPeriod(); - *outPrimaryRefreshRateMin = Fps::fromPeriodNsecs(vsyncPeriod).getValue(); - *outPrimaryRefreshRateMax = Fps::fromPeriodNsecs(vsyncPeriod).getValue(); - *outAppRequestRefreshRateMin = Fps::fromPeriodNsecs(vsyncPeriod).getValue(); - *outAppRequestRefreshRateMax = Fps::fromPeriodNsecs(vsyncPeriod).getValue(); - return NO_ERROR; } + + scheduler::RefreshRateConfigs::Policy policy = + display->refreshRateConfigs().getDisplayManagerPolicy(); + *outDefaultMode = policy.defaultMode.value(); + *outAllowGroupSwitching = policy.allowGroupSwitching; + *outPrimaryRefreshRateMin = policy.primaryRange.min.getValue(); + *outPrimaryRefreshRateMax = policy.primaryRange.max.getValue(); + *outAppRequestRefreshRateMin = policy.appRequestRange.min.getValue(); + *outAppRequestRefreshRateMax = policy.appRequestRange.max.getValue(); + return NO_ERROR; } wp<Layer> SurfaceFlinger::fromHandle(const sp<IBinder>& handle) const { @@ -6720,7 +6726,8 @@ status_t SurfaceFlinger::acquireFrameRateFlexibilityToken(sp<IBinder>* outToken) // matter for the override policy though, since we set allowGroupSwitching to // true, so it's not a problem. scheduler::RefreshRateConfigs::Policy overridePolicy; - overridePolicy.defaultMode = mRefreshRateConfigs->getDisplayManagerPolicy().defaultMode; + overridePolicy.defaultMode = + display->refreshRateConfigs().getDisplayManagerPolicy().defaultMode; overridePolicy.allowGroupSwitching = true; constexpr bool kOverridePolicy = true; result = setDesiredDisplayModeSpecsInternal(display, overridePolicy, kOverridePolicy); @@ -6788,25 +6795,11 @@ status_t SurfaceFlinger::setFrameTimelineInfo(const sp<IGraphicBufferProducer>& } void SurfaceFlinger::enableRefreshRateOverlay(bool enable) { - static_cast<void>(schedule([=] { - std::unique_ptr<RefreshRateOverlay> overlay; - if (enable) { - overlay = std::make_unique<RefreshRateOverlay>(*this, mRefreshRateOverlaySpinner); - } - - { - Mutex::Autolock lock(mStateLock); - - // Destroy the layer of the current overlay, if any, outside the lock. - mRefreshRateOverlay.swap(overlay); - if (!mRefreshRateOverlay) return; - - if (const auto display = getDefaultDisplayDeviceLocked()) { - mRefreshRateOverlay->setViewport(display->getSize()); - mRefreshRateOverlay->changeRefreshRate(display->getActiveMode()->getFps()); - } + for (const auto& [ignored, display] : mDisplays) { + if (display->isInternal()) { + display->enableRefreshRateOverlay(enable, mRefreshRateOverlaySpinner); } - })); + } } status_t SurfaceFlinger::addTransactionTraceListener( @@ -6834,7 +6827,14 @@ int SurfaceFlinger::calculateMaxAcquiredBufferCount(Fps refreshRate, } status_t SurfaceFlinger::getMaxAcquiredBufferCount(int* buffers) const { - const auto maxSupportedRefreshRate = mRefreshRateConfigs->getSupportedRefreshRateRange().max; + const auto maxSupportedRefreshRate = [&] { + const auto display = getDefaultDisplayDevice(); + if (display) { + return display->refreshRateConfigs().getSupportedRefreshRateRange().max; + } + ALOGW("%s: default display is null", __func__); + return Fps(60); + }(); *buffers = getMaxAcquiredBufferCountForRefreshRate(maxSupportedRefreshRate); return NO_ERROR; } @@ -6845,7 +6845,14 @@ int SurfaceFlinger::getMaxAcquiredBufferCountForCurrentRefreshRate(uid_t uid) co if (frameRateOverride.has_value()) { return frameRateOverride.value(); } - return mRefreshRateConfigs->getCurrentRefreshRate().getFps(); + + const auto display = ON_MAIN_THREAD(getDefaultDisplayDeviceLocked()); + if (display) { + return display->refreshRateConfigs().getCurrentRefreshRate().getFps(); + } + + ALOGW("%s: default display is null", __func__); + return Fps(60); }(); return getMaxAcquiredBufferCountForRefreshRate(refreshRate); } @@ -6932,7 +6939,7 @@ sp<Layer> SurfaceFlinger::handleLayerCreatedLocked(const sp<IBinder>& handle) { parent->addChild(layer); } - layer->updateTransformHint(mDefaultDisplayTransformHint); + layer->updateTransformHint(mActiveDisplayTransformHint); if (state->initialProducer != nullptr) { mGraphicBufferProducerList.insert(state->initialProducer); @@ -6962,6 +6969,43 @@ void SurfaceFlinger::notifyRegionSamplingThread() { mRegionSamplingThread->onCompositionComplete(mEventQueue->nextExpectedInvalidate()); } +void SurfaceFlinger::onActiveDisplaySizeChanged(const sp<DisplayDevice>& activeDisplay) { + mScheduler->onActiveDisplayAreaChanged(activeDisplay->getWidth() * activeDisplay->getHeight()); + getRenderEngine().onActiveDisplaySizeChanged(activeDisplay->getSize()); +} + +void SurfaceFlinger::onActiveDisplayChangedLocked(const sp<DisplayDevice>& activeDisplay) { + ATRACE_CALL(); + + if (const auto display = getDisplayDeviceLocked(mActiveDisplayToken)) { + display->getCompositionDisplay()->setLayerCachingTexturePoolEnabled(false); + } + + if (!activeDisplay) { + ALOGE("%s: activeDisplay is null", __func__); + return; + } + mActiveDisplayToken = activeDisplay->getDisplayToken(); + activeDisplay->getCompositionDisplay()->setLayerCachingTexturePoolEnabled(true); + updateInternalDisplayVsyncLocked(activeDisplay); + mScheduler->setModeChangePending(false); + mScheduler->setRefreshRateConfigs(activeDisplay->holdRefreshRateConfigs()); + onActiveDisplaySizeChanged(activeDisplay); + mActiveDisplayTransformHint = activeDisplay->getTransformHint(); +} + +status_t SurfaceFlinger::addWindowInfosListener( + const sp<IWindowInfosListener>& windowInfosListener) const { + mWindowInfosListenerInvoker->addWindowInfosListener(windowInfosListener); + return NO_ERROR; +} + +status_t SurfaceFlinger::removeWindowInfosListener( + const sp<IWindowInfosListener>& windowInfosListener) const { + mWindowInfosListenerInvoker->removeWindowInfosListener(windowInfosListener); + return NO_ERROR; +} + } // namespace android #if defined(__gl_h_) diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index c3d837e86c..bcfe626ecc 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -93,7 +93,6 @@ class FpsReporter; class TunnelModeEnabledReporter; class HdrLayerInfoReporter; class HWComposer; -struct SetInputWindowsListener; class IGraphicBufferProducer; class Layer; class MessageBase; @@ -102,6 +101,7 @@ class RegionSamplingThread; class RenderArea; class TimeStats; class FrameTracer; +class WindowInfosListenerInvoker; using gui::ScreenCaptureResults; @@ -332,7 +332,7 @@ public: // If set, disables reusing client composition buffers. This can be set by // debug.sf.disable_client_composition_cache bool mDisableClientCompositionCache = false; - void setInputWindowsFinished(); + void windowInfosReported(); // Disables expensive rendering for all displays // This is scheduled on the main thread @@ -350,12 +350,14 @@ protected: REQUIRES(mStateLock); virtual void commitTransactionLocked(); - // Used internally by computeLayerBounds() to gets the clip rectangle to use for the - // root layers on a particular display in layer-coordinate space. The - // layers (and effectively their children) will be clipped against this - // rectangle. The base behavior is to clip to the visible region of the - // display. - virtual FloatRect getLayerClipBoundsForDisplay(const DisplayDevice&) const; + virtual void processDisplayAdded(const wp<IBinder>& displayToken, const DisplayDeviceState&) + REQUIRES(mStateLock); + + // Returns true if any display matches a `bool(const DisplayDevice&)` predicate. + template <typename Predicate> + bool hasDisplay(Predicate p) const REQUIRES(mStateLock) { + return static_cast<bool>(findDisplay(p)); + } private: friend class BufferLayer; @@ -455,14 +457,7 @@ private: mCounterByLayerHandle GUARDED_BY(mLock); }; - struct ActiveModeInfo { - DisplayModeId modeId; - Scheduler::ModeEvent event = Scheduler::ModeEvent::None; - - bool operator!=(const ActiveModeInfo& other) const { - return modeId != other.modeId || event != other.event; - } - }; + using ActiveModeInfo = DisplayDevice::ActiveModeInfo; enum class BootStage { BOOTLOADER, @@ -593,7 +588,7 @@ private: typename Handler = VsyncModulator::VsyncConfigOpt (VsyncModulator::*)(Args...)> void modulateVsync(Handler handler, Args... args) { if (const auto config = (*mVsyncModulator.*handler)(args...)) { - const auto vsyncPeriod = mRefreshRateConfigs->getCurrentRefreshRate().getVsyncPeriod(); + const auto vsyncPeriod = mScheduler->getVsyncPeriodFromRefreshRateConfigs(); setVsyncConfig(*config, vsyncPeriod); } } @@ -612,7 +607,10 @@ private: sp<ISurfaceComposerClient> createConnection() override; sp<IBinder> createDisplay(const String8& displayName, bool secure) override; void destroyDisplay(const sp<IBinder>& displayToken) override; - std::vector<PhysicalDisplayId> getPhysicalDisplayIds() const override; + std::vector<PhysicalDisplayId> getPhysicalDisplayIds() const override EXCLUDES(mStateLock) { + Mutex::Autolock lock(mStateLock); + return getPhysicalDisplayIdsLocked(); + } sp<IBinder> getPhysicalDisplayToken(PhysicalDisplayId displayId) const override; status_t setTransactionState(const FrameTimelineInfo& frameTimelineInfo, const Vector<ComposerState>& state, @@ -720,6 +718,11 @@ private: status_t getMaxAcquiredBufferCount(int* buffers) const override; + status_t addWindowInfosListener( + const sp<gui::IWindowInfosListener>& windowInfosListener) const override; + status_t removeWindowInfosListener( + const sp<gui::IWindowInfosListener>& windowInfosListener) const override; + // Implements IBinder::DeathRecipient. void binderDied(const wp<IBinder>& who) override; @@ -750,7 +753,7 @@ private: // Called when the frame rate override list changed to trigger an event. void triggerOnFrameRateOverridesChanged() override; // Toggles the kernel idle timer on or off depending the policy decisions around refresh rates. - void toggleKernelIdleTimer(); + void toggleKernelIdleTimer() REQUIRES(mStateLock); // Keeps track of whether the kernel idle timer is currently enabled, so we don't have to // make calls to sys prop each time. bool mKernelIdleTimerEnabled = false; @@ -779,9 +782,9 @@ private: // Calls to setActiveMode on the main thread if there is a pending mode change // that needs to be applied. void performSetActiveMode() REQUIRES(mStateLock); - void clearDesiredActiveModeState() REQUIRES(mStateLock) EXCLUDES(mActiveModeLock); + void clearDesiredActiveModeState(const sp<DisplayDevice>&) REQUIRES(mStateLock); // Called when active mode is no longer is progress - void desiredActiveModeChangeDone() REQUIRES(mStateLock); + void desiredActiveModeChangeDone(const sp<DisplayDevice>&) REQUIRES(mStateLock); // Called on the main thread in response to setPowerMode() void setPowerModeInternal(const sp<DisplayDevice>& display, hal::PowerMode mode) REQUIRES(mStateLock); @@ -810,11 +813,11 @@ private: void handleTransactionLocked(uint32_t transactionFlags) REQUIRES(mStateLock); void updateInputFlinger(); - void updateInputWindowInfo(); + void notifyWindowInfos(); void commitInputWindowCommands() REQUIRES(mStateLock); void updateCursorAsync(); - void initScheduler(const DisplayDeviceState&) REQUIRES(mStateLock); + void initScheduler(const sp<DisplayDevice>& display) REQUIRES(mStateLock); void updatePhaseConfiguration(const Fps&) REQUIRES(mStateLock); void setVsyncConfig(const VsyncModulator::VsyncConfig&, nsecs_t vsyncPeriod); @@ -930,8 +933,9 @@ private: void readPersistentProperties(); - size_t getMaxTextureSize() const; - size_t getMaxViewportDims() const; + bool exceedsMaxRenderTargetSize(uint32_t width, uint32_t height) const { + return width > mMaxRenderTargetSize || height > mMaxRenderTargetSize; + } int getMaxAcquiredBufferCountForCurrentRefreshRate(uid_t uid) const; @@ -953,6 +957,10 @@ private: sp<const DisplayDevice> getDisplayDeviceLocked(PhysicalDisplayId id) const REQUIRES(mStateLock) { + return const_cast<SurfaceFlinger*>(this)->getDisplayDeviceLocked(id); + } + + sp<DisplayDevice> getDisplayDeviceLocked(PhysicalDisplayId id) REQUIRES(mStateLock) { if (const auto token = getPhysicalDisplayTokenLocked(id)) { return getDisplayDeviceLocked(token); } @@ -964,13 +972,18 @@ private: } sp<DisplayDevice> getDefaultDisplayDeviceLocked() REQUIRES(mStateLock) { + if (const auto display = getDisplayDeviceLocked(mActiveDisplayToken)) { + return display; + } + // The active display is outdated, fall back to the internal display + mActiveDisplayToken.clear(); if (const auto token = getInternalDisplayTokenLocked()) { return getDisplayDeviceLocked(token); } return nullptr; } - sp<const DisplayDevice> getDefaultDisplayDevice() EXCLUDES(mStateLock) { + sp<const DisplayDevice> getDefaultDisplayDevice() const EXCLUDES(mStateLock) { Mutex::Autolock lock(mStateLock); return getDefaultDisplayDeviceLocked(); } @@ -989,10 +1002,18 @@ private: return findDisplay([id](const auto& display) { return display.getId() == id; }); } + std::vector<PhysicalDisplayId> getPhysicalDisplayIdsLocked() const REQUIRES(mStateLock); + // mark a region of a layer stack dirty. this updates the dirty // region of all screens presenting this layer stack. void invalidateLayerStack(const sp<const Layer>& layer, const Region& dirty); + sp<DisplayDevice> getDisplayWithInputByLayer(Layer* layer) const REQUIRES(mStateLock); + + bool isDisplayActiveLocked(const sp<const DisplayDevice>& display) REQUIRES(mStateLock) { + return display->getDisplayToken() == mActiveDisplayToken; + } + /* * H/W composer */ @@ -1030,8 +1051,6 @@ private: const sp<compositionengine::DisplaySurface>& displaySurface, const sp<IGraphicBufferProducer>& producer) REQUIRES(mStateLock); void processDisplayChangesLocked() REQUIRES(mStateLock); - void processDisplayAdded(const wp<IBinder>& displayToken, const DisplayDeviceState&) - REQUIRES(mStateLock); void processDisplayRemoved(const wp<IBinder>& displayToken) REQUIRES(mStateLock); void processDisplayChanged(const wp<IBinder>& displayToken, const DisplayDeviceState& currentState, @@ -1049,8 +1068,6 @@ private: // the desired refresh rate. void changeRefreshRateLocked(const RefreshRate&, Scheduler::ModeEvent) REQUIRES(mStateLock); - bool isDisplayModeAllowed(DisplayModeId) const REQUIRES(mStateLock); - struct FenceWithFenceTime { sp<Fence> fence = Fence::NO_FENCE; std::shared_ptr<FenceTime> fenceTime = FenceTime::NO_FENCE; @@ -1111,10 +1128,13 @@ private: void enableHalVirtualDisplays(bool); // Virtual display lifecycle for ID generation and HAL allocation. - VirtualDisplayId acquireVirtualDisplay(ui::Size, ui::PixelFormat, ui::LayerStack) - REQUIRES(mStateLock); + VirtualDisplayId acquireVirtualDisplay(ui::Size, ui::PixelFormat) REQUIRES(mStateLock); void releaseVirtualDisplay(VirtualDisplayId); + void onActiveDisplayChangedLocked(const sp<DisplayDevice>& activeDisplay) REQUIRES(mStateLock); + + void onActiveDisplaySizeChanged(const sp<DisplayDevice>& activeDisplay); + /* * Debugging & dumpsys */ @@ -1142,6 +1162,8 @@ private: LayersProto dumpDrawingStateProto(uint32_t traceFlags) const; void dumpOffscreenLayersProto(LayersProto& layersProto, uint32_t traceFlags = SurfaceTracing::TRACE_ALL) const; + void dumpDisplayProto(LayersTraceProto& layersTraceProto) const; + // Dumps state from HW Composer void dumpHwc(std::string& result) const; LayersProto dumpProtoFromMainThread(uint32_t traceFlags = SurfaceTracing::TRACE_ALL) @@ -1180,13 +1202,6 @@ private: /* * Misc */ - - std::optional<ActiveModeInfo> getDesiredActiveMode() EXCLUDES(mActiveModeLock) { - std::lock_guard<std::mutex> lock(mActiveModeLock); - if (mDesiredActiveModeChanged) return mDesiredActiveMode; - return std::nullopt; - } - std::vector<ui::ColorMode> getDisplayColorModes(PhysicalDisplayId displayId) REQUIRES(mStateLock); @@ -1194,6 +1209,9 @@ private: std::chrono::nanoseconds presentLatency); int getMaxAcquiredBufferCountForRefreshRate(Fps refreshRate) const; + void updateInternalDisplayVsyncLocked(const sp<DisplayDevice>& activeDisplay) + REQUIRES(mStateLock); + sp<StartPropertySetThread> mStartPropertySetThread; surfaceflinger::Factory& mFactory; @@ -1378,6 +1396,9 @@ private: SurfaceFlingerBE mBE; std::unique_ptr<compositionengine::CompositionEngine> mCompositionEngine; + // mMaxRenderTargetSize is only set once in init() so it doesn't need to be protected by + // any mutex. + size_t mMaxRenderTargetSize{1}; const std::string mHwcServiceName; @@ -1396,24 +1417,13 @@ private: // Optional to defer construction until PhaseConfiguration is created. sp<VsyncModulator> mVsyncModulator; - std::unique_ptr<scheduler::RefreshRateConfigs> mRefreshRateConfigs; std::unique_ptr<scheduler::RefreshRateStats> mRefreshRateStats; std::atomic<nsecs_t> mExpectedPresentTime = 0; nsecs_t mScheduledPresentTime = 0; hal::Vsync mHWCVsyncPendingState = hal::Vsync::DISABLE; - std::mutex mActiveModeLock; - // This bit is set once we start setting the mode. We read from this bit during the - // process. If at the end, this bit is different than mDesiredActiveMode, we restart - // the process. - ActiveModeInfo mUpcomingActiveMode; // Always read and written on the main thread. - // This bit can be set at any point in time when the system wants the new mode. - ActiveModeInfo mDesiredActiveMode GUARDED_BY(mActiveModeLock); - // below flags are set by main thread only - TracedOrdinal<bool> mDesiredActiveModeChanged - GUARDED_BY(mActiveModeLock) = {"DesiredActiveModeChanged", false}; bool mSetActiveModePending = false; bool mLumaSampling = true; @@ -1429,15 +1439,12 @@ private: // Should only be accessed by the main thread. InputWindowCommands mInputWindowCommands; - sp<SetInputWindowsListener> mSetInputWindowsListener; - Hwc2::impl::PowerAdvisor mPowerAdvisor; // This should only be accessed on the main thread. nsecs_t mFrameStartTime = 0; - void enableRefreshRateOverlay(bool enable); - std::unique_ptr<RefreshRateOverlay> mRefreshRateOverlay GUARDED_BY(mStateLock); + void enableRefreshRateOverlay(bool enable) REQUIRES(mStateLock); // Flag used to set override desired display mode from backdoor bool mDebugDisplayModeSetByBackdoor = false; @@ -1488,10 +1495,21 @@ private: auto getLayerCreatedState(const sp<IBinder>& handle); sp<Layer> handleLayerCreatedLocked(const sp<IBinder>& handle) REQUIRES(mStateLock); - std::atomic<ui::Transform::RotationFlags> mDefaultDisplayTransformHint; + std::atomic<ui::Transform::RotationFlags> mActiveDisplayTransformHint; void scheduleRegionSamplingThread(); void notifyRegionSamplingThread(); + + bool isRefreshRateOverlayEnabled() const REQUIRES(mStateLock) { + return std::any_of(mDisplays.begin(), mDisplays.end(), + [](std::pair<wp<IBinder>, sp<DisplayDevice>> display) { + return display.second->isRefreshRateOverlayEnabled(); + }); + } + + wp<IBinder> mActiveDisplayToken GUARDED_BY(mStateLock); + + const sp<WindowInfosListenerInvoker> mWindowInfosListenerInvoker; }; } // namespace android diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp index 4a7518066f..89d1c4d327 100644 --- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp +++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp @@ -65,8 +65,9 @@ std::unique_ptr<scheduler::VsyncConfiguration> DefaultFactory::createVsyncConfig } std::unique_ptr<Scheduler> DefaultFactory::createScheduler( - const scheduler::RefreshRateConfigs& configs, ISchedulerCallback& callback) { - return std::make_unique<Scheduler>(configs, callback); + const std::shared_ptr<scheduler::RefreshRateConfigs>& refreshRateConfigs, + ISchedulerCallback& callback) { + return std::make_unique<Scheduler>(std::move(refreshRateConfigs), callback); } sp<SurfaceInterceptor> DefaultFactory::createSurfaceInterceptor() { diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.h b/services/surfaceflinger/SurfaceFlingerDefaultFactory.h index 24148ddf9d..b8bf2baa33 100644 --- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.h +++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.h @@ -30,8 +30,8 @@ public: std::unique_ptr<MessageQueue> createMessageQueue() override; std::unique_ptr<scheduler::VsyncConfiguration> createVsyncConfiguration( Fps currentRefreshRate) override; - std::unique_ptr<Scheduler> createScheduler(const scheduler::RefreshRateConfigs&, - ISchedulerCallback&) override; + std::unique_ptr<Scheduler> createScheduler( + const std::shared_ptr<scheduler::RefreshRateConfigs>&, ISchedulerCallback&) override; sp<SurfaceInterceptor> createSurfaceInterceptor() override; sp<StartPropertySetThread> createStartPropertySetThread(bool timestampPropertyValue) override; sp<DisplayDevice> createDisplayDevice(DisplayDeviceCreationArgs&) override; diff --git a/services/surfaceflinger/SurfaceFlingerFactory.h b/services/surfaceflinger/SurfaceFlingerFactory.h index 885297fc30..13c95ddd15 100644 --- a/services/surfaceflinger/SurfaceFlingerFactory.h +++ b/services/surfaceflinger/SurfaceFlingerFactory.h @@ -79,8 +79,8 @@ public: virtual std::unique_ptr<MessageQueue> createMessageQueue() = 0; virtual std::unique_ptr<scheduler::VsyncConfiguration> createVsyncConfiguration( Fps currentRefreshRate) = 0; - virtual std::unique_ptr<Scheduler> createScheduler(const scheduler::RefreshRateConfigs&, - ISchedulerCallback&) = 0; + virtual std::unique_ptr<Scheduler> createScheduler( + const std::shared_ptr<scheduler::RefreshRateConfigs>&, ISchedulerCallback&) = 0; virtual sp<SurfaceInterceptor> createSurfaceInterceptor() = 0; virtual sp<StartPropertySetThread> createStartPropertySetThread( diff --git a/services/surfaceflinger/SurfaceInterceptor.cpp b/services/surfaceflinger/SurfaceInterceptor.cpp index 837b2e8924..9be3abefab 100644 --- a/services/surfaceflinger/SurfaceInterceptor.cpp +++ b/services/surfaceflinger/SurfaceInterceptor.cpp @@ -161,6 +161,7 @@ void SurfaceInterceptor::addInitialDisplayStateLocked(Increment* increment, addDisplaySurfaceLocked(transaction, display.sequenceId, display.surface); addDisplayLayerStackLocked(transaction, display.sequenceId, display.layerStack); + addDisplayFlagsLocked(transaction, display.sequenceId, display.flags); addDisplaySizeLocked(transaction, display.sequenceId, display.width, display.height); addDisplayProjectionLocked(transaction, display.sequenceId, toRotationInt(display.orientation), display.layerStackSpaceRect, display.orientedDisplaySpaceRect); @@ -481,6 +482,9 @@ void SurfaceInterceptor::addDisplayChangesLocked(Transaction* transaction, if (state.what & DisplayState::eLayerStackChanged) { addDisplayLayerStackLocked(transaction, sequenceId, state.layerStack); } + if (state.what & DisplayState::eFlagsChanged) { + addDisplayFlagsLocked(transaction, sequenceId, state.flags); + } if (state.what & DisplayState::eDisplaySizeChanged) { addDisplaySizeLocked(transaction, sequenceId, state.width, state.height); } @@ -572,6 +576,13 @@ void SurfaceInterceptor::addDisplayLayerStackLocked(Transaction* transaction, layerStackChange->set_layer_stack(layerStack); } +void SurfaceInterceptor::addDisplayFlagsLocked(Transaction* transaction, int32_t sequenceId, + uint32_t flags) { + DisplayChange* dispChange(createDisplayChangeLocked(transaction, sequenceId)); + DisplayFlagsChange* flagsChange(dispChange->mutable_flags()); + flagsChange->set_flags(flags); +} + void SurfaceInterceptor::addDisplaySizeLocked(Transaction* transaction, int32_t sequenceId, uint32_t w, uint32_t h) { diff --git a/services/surfaceflinger/SurfaceInterceptor.h b/services/surfaceflinger/SurfaceInterceptor.h index c9555969dc..7b331b9f5f 100644 --- a/services/surfaceflinger/SurfaceInterceptor.h +++ b/services/surfaceflinger/SurfaceInterceptor.h @@ -48,7 +48,7 @@ using SurfaceChange = surfaceflinger::SurfaceChange; using Increment = surfaceflinger::Increment; using DisplayChange = surfaceflinger::DisplayChange; -constexpr auto DEFAULT_FILENAME = "/data/misc/wmtrace/transaction_trace.pb"; +constexpr auto DEFAULT_FILENAME = "/data/misc/wmtrace/transaction_trace.winscope"; class SurfaceInterceptor : public IBinder::DeathRecipient { public: @@ -185,6 +185,7 @@ private: const sp<const IGraphicBufferProducer>& surface); void addDisplayLayerStackLocked(Transaction* transaction, int32_t sequenceId, uint32_t layerStack); + void addDisplayFlagsLocked(Transaction* transaction, int32_t sequenceId, uint32_t flags); void addDisplaySizeLocked(Transaction* transaction, int32_t sequenceId, uint32_t w, uint32_t h); void addDisplayProjectionLocked(Transaction* transaction, int32_t sequenceId, diff --git a/services/surfaceflinger/SurfaceTracing.cpp b/services/surfaceflinger/SurfaceTracing.cpp index b4d8a9adce..596373732f 100644 --- a/services/surfaceflinger/SurfaceTracing.cpp +++ b/services/surfaceflinger/SurfaceTracing.cpp @@ -137,14 +137,19 @@ status_t SurfaceTracing::Runner::stop() { return writeToFile(); } +LayersTraceFileProto SurfaceTracing::createLayersTraceFileProto() { + LayersTraceFileProto fileProto; + fileProto.set_magic_number(uint64_t(LayersTraceFileProto_MagicNumber_MAGIC_NUMBER_H) << 32 | + LayersTraceFileProto_MagicNumber_MAGIC_NUMBER_L); + return fileProto; +} + status_t SurfaceTracing::Runner::writeToFile() { ATRACE_CALL(); - LayersTraceFileProto fileProto; + LayersTraceFileProto fileProto = createLayersTraceFileProto(); std::string output; - fileProto.set_magic_number(uint64_t(LayersTraceFileProto_MagicNumber_MAGIC_NUMBER_H) << 32 | - LayersTraceFileProto_MagicNumber_MAGIC_NUMBER_L); mBuffer.flush(&fileProto); mBuffer.reset(mConfig.bufferSize); @@ -186,7 +191,7 @@ LayersTraceProto SurfaceTracing::Runner::traceLayers(const char* where) { entry.set_excludes_composition_state(true); } entry.set_missed_entries(mMissedTraceEntries); - + mFlinger.dumpDisplayProto(entry); return entry; } diff --git a/services/surfaceflinger/SurfaceTracing.h b/services/surfaceflinger/SurfaceTracing.h index 15a503d834..cea1a3324e 100644 --- a/services/surfaceflinger/SurfaceTracing.h +++ b/services/surfaceflinger/SurfaceTracing.h @@ -73,11 +73,12 @@ public: }; void setTraceFlags(uint32_t flags) { mConfig.flags = flags; } bool flagIsSet(uint32_t flags) { return (mConfig.flags & flags) == flags; } + static LayersTraceFileProto createLayersTraceFileProto(); private: class Runner; static constexpr auto DEFAULT_BUFFER_SIZE = 5_MB; - static constexpr auto DEFAULT_FILE_NAME = "/data/misc/wmtrace/layers_trace.pb"; + static constexpr auto DEFAULT_FILE_NAME = "/data/misc/wmtrace/layers_trace.winscope"; SurfaceFlinger& mFlinger; mutable std::mutex mTraceLock; diff --git a/services/surfaceflinger/WindowInfosListenerInvoker.cpp b/services/surfaceflinger/WindowInfosListenerInvoker.cpp new file mode 100644 index 0000000000..dc2aa58c9a --- /dev/null +++ b/services/surfaceflinger/WindowInfosListenerInvoker.cpp @@ -0,0 +1,96 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "WindowInfosListenerInvoker.h" +#include <gui/ISurfaceComposer.h> +#include <unordered_set> +#include "SurfaceFlinger.h" + +namespace android { + +using gui::IWindowInfosListener; +using gui::WindowInfo; + +struct WindowInfosReportedListener : gui::BnWindowInfosReportedListener { + explicit WindowInfosReportedListener(std::function<void()> listenerCb) + : mListenerCb(listenerCb) {} + + binder::Status onWindowInfosReported() override { + if (mListenerCb != nullptr) { + mListenerCb(); + } + return binder::Status::ok(); + } + + std::function<void()> mListenerCb; +}; + +WindowInfosListenerInvoker::WindowInfosListenerInvoker(const sp<SurfaceFlinger>& sf) : mSf(sf) { + mWindowInfosReportedListener = + new WindowInfosReportedListener([&]() { windowInfosReported(); }); +} + +void WindowInfosListenerInvoker::addWindowInfosListener( + const sp<IWindowInfosListener>& windowInfosListener) { + sp<IBinder> asBinder = IInterface::asBinder(windowInfosListener); + + asBinder->linkToDeath(this); + std::scoped_lock lock(mListenersMutex); + mWindowInfosListeners.emplace(asBinder, windowInfosListener); +} + +void WindowInfosListenerInvoker::removeWindowInfosListener( + const sp<IWindowInfosListener>& windowInfosListener) { + sp<IBinder> asBinder = IInterface::asBinder(windowInfosListener); + + std::scoped_lock lock(mListenersMutex); + asBinder->unlinkToDeath(this); + mWindowInfosListeners.erase(asBinder); +} + +void WindowInfosListenerInvoker::binderDied(const wp<IBinder>& who) { + std::scoped_lock lock(mListenersMutex); + mWindowInfosListeners.erase(who); +} + +void WindowInfosListenerInvoker::windowInfosChanged(const std::vector<WindowInfo>& windowInfos, + bool shouldSync) { + std::unordered_set<sp<IWindowInfosListener>, ISurfaceComposer::SpHash<IWindowInfosListener>> + windowInfosListeners; + + { + std::scoped_lock lock(mListenersMutex); + for (const auto& [_, listener] : mWindowInfosListeners) { + windowInfosListeners.insert(listener); + } + } + + mCallbacksPending = windowInfosListeners.size(); + + for (const auto& listener : windowInfosListeners) { + listener->onWindowInfosChanged(windowInfos, + shouldSync ? mWindowInfosReportedListener : nullptr); + } +} + +void WindowInfosListenerInvoker::windowInfosReported() { + mCallbacksPending--; + if (mCallbacksPending == 0) { + mSf->windowInfosReported(); + } +} + +} // namespace android
\ No newline at end of file diff --git a/services/surfaceflinger/WindowInfosListenerInvoker.h b/services/surfaceflinger/WindowInfosListenerInvoker.h new file mode 100644 index 0000000000..5e5796fe2d --- /dev/null +++ b/services/surfaceflinger/WindowInfosListenerInvoker.h @@ -0,0 +1,57 @@ +/* + * Copyright 2021 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 <android/gui/BnWindowInfosReportedListener.h> +#include <android/gui/IWindowInfosListener.h> +#include <android/gui/IWindowInfosReportedListener.h> +#include <binder/IBinder.h> +#include <utils/Mutex.h> +#include <unordered_map> + +namespace android { + +class SurfaceFlinger; + +class WindowInfosListenerInvoker : public IBinder::DeathRecipient { +public: + WindowInfosListenerInvoker(const sp<SurfaceFlinger>& sf); + void addWindowInfosListener(const sp<gui::IWindowInfosListener>& windowInfosListener); + void removeWindowInfosListener(const sp<gui::IWindowInfosListener>& windowInfosListener); + + void windowInfosChanged(const std::vector<gui::WindowInfo>& windowInfos, bool shouldSync); + +protected: + void binderDied(const wp<IBinder>& who) override; + +private: + void windowInfosReported(); + + struct WpHash { + size_t operator()(const wp<IBinder>& p) const { + return std::hash<IBinder*>()(p.unsafe_get()); + } + }; + + const sp<SurfaceFlinger> mSf; + std::mutex mListenersMutex; + std::unordered_map<wp<IBinder>, const sp<gui::IWindowInfosListener>, WpHash> + mWindowInfosListeners GUARDED_BY(mListenersMutex); + sp<gui::IWindowInfosReportedListener> mWindowInfosReportedListener; + std::atomic<size_t> mCallbacksPending{0}; +}; +} // namespace android
\ No newline at end of file diff --git a/services/surfaceflinger/layerproto/Android.bp b/services/surfaceflinger/layerproto/Android.bp index c8a2b5eed6..973a4392a2 100644 --- a/services/surfaceflinger/layerproto/Android.bp +++ b/services/surfaceflinger/layerproto/Android.bp @@ -13,8 +13,7 @@ cc_library { srcs: [ "LayerProtoParser.cpp", - "layers.proto", - "layerstrace.proto", + "*.proto", ], shared_libs: [ diff --git a/services/surfaceflinger/layerproto/common.proto b/services/surfaceflinger/layerproto/common.proto new file mode 100644 index 0000000000..1c73a9f4a8 --- /dev/null +++ b/services/surfaceflinger/layerproto/common.proto @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2021 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. + */ + +syntax = "proto3"; +option optimize_for = LITE_RUNTIME; +package android.surfaceflinger; + +message RectProto { + int32 left = 1; + int32 top = 2; + int32 right = 3; + int32 bottom = 4; +} + +message SizeProto { + int32 w = 1; + int32 h = 2; +} + +message TransformProto { + float dsdx = 1; + float dtdx = 2; + float dsdy = 3; + float dtdy = 4; + int32 type = 5; +}
\ No newline at end of file diff --git a/services/surfaceflinger/layerproto/display.proto b/services/surfaceflinger/layerproto/display.proto new file mode 100644 index 0000000000..ee8830e7f2 --- /dev/null +++ b/services/surfaceflinger/layerproto/display.proto @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2021 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. + */ + +syntax = "proto3"; +option optimize_for = LITE_RUNTIME; + +import "frameworks/native/services/surfaceflinger/layerproto/common.proto"; + +package android.surfaceflinger; + +message DisplayProto { + uint64 id = 1; + + string name = 2; + + uint32 layer_stack = 3; + + SizeProto size = 4; + + RectProto layer_stack_space_rect = 5; + + TransformProto transform = 6; +} diff --git a/services/surfaceflinger/layerproto/layers.proto b/services/surfaceflinger/layerproto/layers.proto index dddc677715..057eabb8cc 100644 --- a/services/surfaceflinger/layerproto/layers.proto +++ b/services/surfaceflinger/layerproto/layers.proto @@ -2,6 +2,9 @@ syntax = "proto3"; option optimize_for = LITE_RUNTIME; + +import "frameworks/native/services/surfaceflinger/layerproto/common.proto"; + package android.surfaceflinger; // Contains a list of all layers. @@ -130,6 +133,9 @@ message LayerProto { repeated BlurRegion blur_regions = 54; bool is_trusted_overlay = 55; + + // Corner radius explicitly set on layer rather than inherited + float requested_corner_radius = 56; } message PositionProto { @@ -137,31 +143,11 @@ message PositionProto { float y = 2; } -message SizeProto { - int32 w = 1; - int32 h = 2; -} - -message TransformProto { - float dsdx = 1; - float dtdx = 2; - float dsdy = 3; - float dtdy = 4; - int32 type = 5; -} - message RegionProto { reserved 1; // Previously: uint64 id repeated RectProto rect = 2; } -message RectProto { - int32 left = 1; - int32 top = 2; - int32 right = 3; - int32 bottom = 4; -} - message FloatRectProto { float left = 1; float top = 2; @@ -228,4 +214,4 @@ message BlurRegion { int32 top = 8; int32 right = 9; int32 bottom = 10; -}
\ No newline at end of file +} diff --git a/services/surfaceflinger/layerproto/layerstrace.proto b/services/surfaceflinger/layerproto/layerstrace.proto index 990f3cffda..13647b669e 100644 --- a/services/surfaceflinger/layerproto/layerstrace.proto +++ b/services/surfaceflinger/layerproto/layerstrace.proto @@ -18,6 +18,7 @@ syntax = "proto2"; option optimize_for = LITE_RUNTIME; import "frameworks/native/services/surfaceflinger/layerproto/layers.proto"; +import "frameworks/native/services/surfaceflinger/layerproto/display.proto"; package android.surfaceflinger; @@ -57,4 +58,6 @@ message LayersTraceProto { /* Number of missed entries since the last entry was recorded. */ optional uint32 missed_entries = 6; + + repeated DisplayProto displays = 7; } diff --git a/services/surfaceflinger/tests/Android.bp b/services/surfaceflinger/tests/Android.bp index a36c6ed521..32ad8732ad 100644 --- a/services/surfaceflinger/tests/Android.bp +++ b/services/surfaceflinger/tests/Android.bp @@ -51,6 +51,7 @@ cc_test { "Stress_test.cpp", "SurfaceInterceptor_test.cpp", "VirtualDisplay_test.cpp", + "WindowInfosListener_test.cpp", ], data: ["SurfaceFlinger_test.filter"], static_libs: [ diff --git a/services/surfaceflinger/tests/EffectLayer_test.cpp b/services/surfaceflinger/tests/EffectLayer_test.cpp index af00ec7fc9..93656f3fd2 100644 --- a/services/surfaceflinger/tests/EffectLayer_test.cpp +++ b/services/surfaceflinger/tests/EffectLayer_test.cpp @@ -176,6 +176,15 @@ TEST_F(EffectLayerTest, BlurEffectLayerIsVisible) { } } +TEST_F(EffectLayerTest, EffectLayerWithColorNoCrop) { + const auto display = SurfaceComposerClient::getInternalDisplayToken(); + ui::DisplayMode mode; + ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayMode(display, &mode)); + const ui::Size& resolution = mode.resolution; + auto shot = screenshot(); + shot->expectColor(Rect(0, 0, resolution.getWidth(), resolution.getHeight()), Color::RED); +} + } // namespace android // TODO(b/129481165): remove the #pragma below and fix conversion issues diff --git a/services/surfaceflinger/tests/RefreshRateOverlay_test.cpp b/services/surfaceflinger/tests/RefreshRateOverlay_test.cpp index 05858bf839..fb4458a27e 100644 --- a/services/surfaceflinger/tests/RefreshRateOverlay_test.cpp +++ b/services/surfaceflinger/tests/RefreshRateOverlay_test.cpp @@ -20,6 +20,10 @@ #include <gui/SurfaceComposerClient.h> #include <private/gui/ComposerService.h> +#include <chrono> + +using ::std::literals::chrono_literals::operator""ms; +using ::std::literals::chrono_literals::operator""s; static constexpr int kRefreshRateOverlayCode = 1034; static constexpr int kRefreshRateOverlayEnable = 1; diff --git a/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp b/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp index 579a26ebf4..c4d42fad36 100644 --- a/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp +++ b/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp @@ -99,10 +99,10 @@ public: } static void waitForReleaseBufferCallback(ReleaseBufferCallbackHelper& releaseCallback, - const ReleaseCallbackId& expectedCallbackId) { + const ReleaseCallbackId& expectedReleaseBufferId) { ReleaseCallbackId actualReleaseBufferId; releaseCallback.getCallbackData(&actualReleaseBufferId); - EXPECT_EQ(expectedCallbackId, actualReleaseBufferId); + EXPECT_EQ(expectedReleaseBufferId, actualReleaseBufferId); releaseCallback.verifyNoCallbacks(); } static ReleaseBufferCallbackHelper* getReleaseBufferCallbackHelper() { @@ -333,4 +333,60 @@ TEST_F(ReleaseBufferCallbackTest, DISABLED_FrameDropping) { ASSERT_NO_FATAL_FAILURE(waitForReleaseBufferCallback(*releaseCallback, firstBufferCallbackId)); } +TEST_F(ReleaseBufferCallbackTest, DISABLED_Merge_Different_Processes) { + sp<TransactionCompletedListener> firstCompletedListener = new TransactionCompletedListener(); + sp<TransactionCompletedListener> secondCompletedListener = new TransactionCompletedListener(); + + CallbackHelper callback1, callback2; + + TransactionCompletedListener::setInstance(firstCompletedListener); + + sp<SurfaceControl> layer = createBufferStateLayer(); + ReleaseBufferCallbackHelper* releaseCallback = getReleaseBufferCallbackHelper(); + + sp<GraphicBuffer> firstBuffer = getBuffer(); + ReleaseCallbackId firstBufferCallbackId(firstBuffer->getId(), generateFrameNumber()); + + // Send initial buffer for the layer + submitBuffer(layer, firstBuffer, Fence::NO_FENCE, callback1, firstBufferCallbackId, + *releaseCallback); + + ExpectedResult expected; + expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer, + ExpectedResult::Buffer::NOT_ACQUIRED); + ASSERT_NO_FATAL_FAILURE(waitForCallback(callback1, expected)); + + // Sent a second buffer to allow the first buffer to get released. + sp<GraphicBuffer> secondBuffer = getBuffer(); + ReleaseCallbackId secondBufferCallbackId(secondBuffer->getId(), generateFrameNumber()); + + Transaction transaction1; + transaction1.setFrameNumber(layer, secondBufferCallbackId.framenumber); + transaction1.setBuffer(layer, secondBuffer, secondBufferCallbackId, + releaseCallback->getCallback()); + transaction1.setAcquireFence(layer, Fence::NO_FENCE); + transaction1.addTransactionCompletedCallback(callback1.function, callback1.getContext()); + + // Set a different TransactionCompletedListener to mimic a second process + TransactionCompletedListener::setInstance(secondCompletedListener); + + // Make sure the second "process" has a callback set up. + Transaction transaction2; + transaction2.addTransactionCompletedCallback(callback2.function, callback2.getContext()); + + // This merging order, merge transaction1 first then transaction2, seems to ensure the listener + // for transaction2 is ordered first. This makes sure the wrong process is added first to the + // layer's vector of listeners. With the bug, only the secondCompletedListener will get the + // release callback id, since it's ordered first. Then firstCompletedListener would fail to get + // the release callback id and not invoke the release callback. + Transaction().merge(std::move(transaction1)).merge(std::move(transaction2)).apply(); + + expected = ExpectedResult(); + expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer, + ExpectedResult::Buffer::NOT_ACQUIRED, + ExpectedResult::PreviousBuffer::RELEASED); + ASSERT_NO_FATAL_FAILURE(waitForCallback(callback1, expected)); + ASSERT_NO_FATAL_FAILURE(waitForReleaseBufferCallback(*releaseCallback, firstBufferCallbackId)); +} + } // namespace android diff --git a/services/surfaceflinger/tests/ScreenCapture_test.cpp b/services/surfaceflinger/tests/ScreenCapture_test.cpp index 6912fcf219..ab2064efd0 100644 --- a/services/surfaceflinger/tests/ScreenCapture_test.cpp +++ b/services/surfaceflinger/tests/ScreenCapture_test.cpp @@ -515,7 +515,8 @@ TEST_F(ScreenCaptureTest, CaptureSize) { } TEST_F(ScreenCaptureTest, CaptureInvalidLayer) { - sp<SurfaceControl> redLayer = createLayer(String8("Red surface"), 60, 60, 0); + sp<SurfaceControl> redLayer = createLayer(String8("Red surface"), 60, 60, + ISurfaceComposerClient::eFXSurfaceBufferState); ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(redLayer, Color::RED, 60, 60)); @@ -532,6 +533,21 @@ TEST_F(ScreenCaptureTest, CaptureInvalidLayer) { ASSERT_EQ(NAME_NOT_FOUND, ScreenCapture::captureLayers(args, captureResults)); } +TEST_F(ScreenCaptureTest, CaptureTooLargeLayer) { + sp<SurfaceControl> redLayer = createLayer(String8("Red surface"), 60, 60); + ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(redLayer, Color::RED, 60, 60)); + + Transaction().show(redLayer).setLayer(redLayer, INT32_MAX).apply(true); + + LayerCaptureArgs captureArgs; + captureArgs.layerHandle = redLayer->getHandle(); + captureArgs.frameScaleX = INT32_MAX / 60; + captureArgs.frameScaleY = INT32_MAX / 60; + + ScreenCaptureResults captureResults; + ASSERT_EQ(BAD_VALUE, ScreenCapture::captureLayers(captureArgs, captureResults)); +} + TEST_F(ScreenCaptureTest, CaptureSecureLayer) { sp<SurfaceControl> redLayer = createLayer(String8("Red surface"), 60, 60, ISurfaceComposerClient::eFXSurfaceBufferState); diff --git a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp index d5890ffa79..a42405989f 100644 --- a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp +++ b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp @@ -61,7 +61,7 @@ constexpr auto UNIQUE_TEST_FG_SURFACE_NAME = "FG Interceptor Test Surface#0"; constexpr auto LAYER_NAME = "Layer Create and Delete Test"; constexpr auto UNIQUE_LAYER_NAME = "Layer Create and Delete Test#0"; -constexpr auto DEFAULT_FILENAME = "/data/misc/wmtrace/transaction_trace.pb"; +constexpr auto DEFAULT_FILENAME = "/data/misc/wmtrace/transaction_trace.winscope"; // Fill an RGBA_8888 formatted surface with a single color. static void fillSurfaceRGBA8(const sp<SurfaceControl>& sc, uint8_t r, uint8_t g, uint8_t b) { diff --git a/services/surfaceflinger/tests/WindowInfosListener_test.cpp b/services/surfaceflinger/tests/WindowInfosListener_test.cpp new file mode 100644 index 0000000000..89228d55e5 --- /dev/null +++ b/services/surfaceflinger/tests/WindowInfosListener_test.cpp @@ -0,0 +1,136 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <gtest/gtest.h> +#include <gui/SurfaceComposerClient.h> +#include <private/android_filesystem_config.h> +#include <future> +#include "utils/TransactionUtils.h" + +namespace android { +using Transaction = SurfaceComposerClient::Transaction; +using gui::WindowInfo; + +class WindowInfosListenerTest : public ::testing::Test { +protected: + void SetUp() override { + seteuid(AID_SYSTEM); + mClient = new SurfaceComposerClient; + mWindowInfosListener = new SyncWindowInfosListener(); + mClient->addWindowInfosListener(mWindowInfosListener); + } + + void TearDown() override { + mClient->removeWindowInfosListener(mWindowInfosListener); + seteuid(AID_ROOT); + } + + struct SyncWindowInfosListener : public gui::WindowInfosListener { + public: + void onWindowInfosChanged(const std::vector<WindowInfo>& windowInfos) override { + windowInfosPromise.set_value(windowInfos); + } + + std::vector<WindowInfo> waitForWindowInfos() { + std::future<std::vector<WindowInfo>> windowInfosFuture = + windowInfosPromise.get_future(); + std::vector<WindowInfo> windowInfos = windowInfosFuture.get(); + windowInfosPromise = std::promise<std::vector<WindowInfo>>(); + return windowInfos; + } + + private: + std::promise<std::vector<WindowInfo>> windowInfosPromise; + }; + + sp<SurfaceComposerClient> mClient; + sp<SyncWindowInfosListener> mWindowInfosListener; +}; + +std::optional<WindowInfo> findMatchingWindowInfo(WindowInfo targetWindowInfo, + std::vector<WindowInfo> windowInfos) { + std::optional<WindowInfo> foundWindowInfo = std::nullopt; + for (WindowInfo windowInfo : windowInfos) { + if (windowInfo.token == targetWindowInfo.token) { + foundWindowInfo = std::make_optional<>(windowInfo); + break; + } + } + + return foundWindowInfo; +} + +TEST_F(WindowInfosListenerTest, WindowInfoAddedAndRemoved) { + std::string name = "Test Layer"; + sp<IBinder> token = new BBinder(); + WindowInfo windowInfo; + windowInfo.name = name; + windowInfo.token = token; + sp<SurfaceControl> surfaceControl = + mClient->createSurface(String8(name.c_str()), 100, 100, PIXEL_FORMAT_RGBA_8888, + ISurfaceComposerClient::eFXSurfaceBufferState); + + Transaction() + .setLayerStack(surfaceControl, 0) + .show(surfaceControl) + .setLayer(surfaceControl, INT32_MAX - 1) + .setInputWindowInfo(surfaceControl, windowInfo) + .apply(); + + std::vector<WindowInfo> windowInfos = mWindowInfosListener->waitForWindowInfos(); + std::optional<WindowInfo> foundWindowInfo = findMatchingWindowInfo(windowInfo, windowInfos); + ASSERT_NE(std::nullopt, foundWindowInfo); + + Transaction().reparent(surfaceControl, nullptr).apply(); + + windowInfos = mWindowInfosListener->waitForWindowInfos(); + foundWindowInfo = findMatchingWindowInfo(windowInfo, windowInfos); + ASSERT_EQ(std::nullopt, foundWindowInfo); +} + +TEST_F(WindowInfosListenerTest, WindowInfoChanged) { + std::string name = "Test Layer"; + sp<IBinder> token = new BBinder(); + WindowInfo windowInfo; + windowInfo.name = name; + windowInfo.token = token; + sp<SurfaceControl> surfaceControl = + mClient->createSurface(String8(name.c_str()), 100, 100, PIXEL_FORMAT_RGBA_8888, + ISurfaceComposerClient::eFXSurfaceBufferState); + + Transaction() + .setLayerStack(surfaceControl, 0) + .show(surfaceControl) + .setLayer(surfaceControl, INT32_MAX - 1) + .setInputWindowInfo(surfaceControl, windowInfo) + .apply(); + + std::vector<WindowInfo> windowInfos = mWindowInfosListener->waitForWindowInfos(); + std::optional<WindowInfo> foundWindowInfo = findMatchingWindowInfo(windowInfo, windowInfos); + ASSERT_NE(std::nullopt, foundWindowInfo); + ASSERT_TRUE(foundWindowInfo->touchableRegion.isEmpty()); + + Rect touchableRegions(0, 0, 50, 50); + windowInfo.addTouchableRegion(Rect(0, 0, 50, 50)); + Transaction().setInputWindowInfo(surfaceControl, windowInfo).apply(); + + windowInfos = mWindowInfosListener->waitForWindowInfos(); + foundWindowInfo = findMatchingWindowInfo(windowInfo, windowInfos); + ASSERT_NE(std::nullopt, foundWindowInfo); + ASSERT_TRUE(foundWindowInfo->touchableRegion.hasSameRects(windowInfo.touchableRegion)); +} + +} // namespace android diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp index b5086fafb7..9e704c32fc 100644 --- a/services/surfaceflinger/tests/unittests/Android.bp +++ b/services/surfaceflinger/tests/unittests/Android.bp @@ -51,6 +51,7 @@ cc_test { "DisplayIdGeneratorTest.cpp", "DisplayTransactionTest.cpp", "DisplayDevice_GetBestColorModeTest.cpp", + "DisplayDevice_InitiateModeChange.cpp", "DisplayDevice_SetProjectionTest.cpp", "EventThreadTest.cpp", "FpsReporterTest.cpp", diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp index 560f139719..52a36a2719 100644 --- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp +++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp @@ -108,6 +108,8 @@ public: mComposer = new Hwc2::mock::Composer(); mFlinger.setupComposer(std::unique_ptr<Hwc2::Composer>(mComposer)); + + mFlinger.mutableMaxRenderTargetSize() = 16384; } ~CompositionTest() { @@ -519,8 +521,6 @@ struct BaseLayerProperties { static void setupLatchedBuffer(CompositionTest* test, sp<BufferQueueLayer> layer) { // TODO: Eliminate the complexity of actually creating a buffer - EXPECT_CALL(*test->mRenderEngine, getMaxTextureSize()).WillOnce(Return(16384)); - EXPECT_CALL(*test->mRenderEngine, getMaxViewportDims()).WillOnce(Return(16384)); status_t err = layer->setDefaultBufferProperties(LayerProperties::WIDTH, LayerProperties::HEIGHT, LayerProperties::FORMAT); diff --git a/services/surfaceflinger/tests/unittests/DisplayDevice_InitiateModeChange.cpp b/services/surfaceflinger/tests/unittests/DisplayDevice_InitiateModeChange.cpp new file mode 100644 index 0000000000..d4cfbbbe0c --- /dev/null +++ b/services/surfaceflinger/tests/unittests/DisplayDevice_InitiateModeChange.cpp @@ -0,0 +1,173 @@ +/* + * Copyright 2021 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. + */ + +#undef LOG_TAG +#define LOG_TAG "LibSurfaceFlingerUnittests" + +#include "DisplayTransactionTestHelpers.h" + +#include <gmock/gmock.h> +#include <gtest/gtest.h> + +namespace android { +namespace { + +using FakeDisplayDeviceInjector = TestableSurfaceFlinger::FakeDisplayDeviceInjector; + +class InitiateModeChangeTest : public DisplayTransactionTest { +public: + using Event = scheduler::RefreshRateConfigEvent; + + void SetUp() override { + injectFakeBufferQueueFactory(); + injectFakeNativeWindowSurfaceFactory(); + + PrimaryDisplayVariant::setupHwcHotplugCallExpectations(this); + PrimaryDisplayVariant::setupFramebufferConsumerBufferQueueCallExpectations(this); + PrimaryDisplayVariant::setupFramebufferProducerBufferQueueCallExpectations(this); + PrimaryDisplayVariant::setupNativeWindowSurfaceCreationCallExpectations(this); + PrimaryDisplayVariant::setupHwcGetActiveConfigCallExpectations(this); + + mFlinger.onComposerHalHotplug(PrimaryDisplayVariant::HWC_DISPLAY_ID, Connection::CONNECTED); + + mDisplay = PrimaryDisplayVariant::makeFakeExistingDisplayInjector(this) + .setSupportedModes({kDisplayMode60, kDisplayMode90, kDisplayMode120}) + .setActiveMode(kDisplayModeId60) + .inject(); + } + +protected: + sp<DisplayDevice> mDisplay; + + const DisplayModeId kDisplayModeId60 = DisplayModeId(0); + const DisplayModePtr kDisplayMode60 = + DisplayMode::Builder(hal::HWConfigId(kDisplayModeId60.value())) + .setId(kDisplayModeId60) + .setPhysicalDisplayId(PrimaryDisplayVariant::DISPLAY_ID::get()) + .setVsyncPeriod(int32_t(16'666'667)) + .setGroup(0) + .setHeight(1000) + .setWidth(1000) + .build(); + + const DisplayModeId kDisplayModeId90 = DisplayModeId(1); + const DisplayModePtr kDisplayMode90 = + DisplayMode::Builder(hal::HWConfigId(kDisplayModeId90.value())) + .setId(kDisplayModeId90) + .setPhysicalDisplayId(PrimaryDisplayVariant::DISPLAY_ID::get()) + .setVsyncPeriod(int32_t(11'111'111)) + .setGroup(0) + .setHeight(1000) + .setWidth(1000) + .build(); + + const DisplayModeId kDisplayModeId120 = DisplayModeId(2); + const DisplayModePtr kDisplayMode120 = + DisplayMode::Builder(hal::HWConfigId(kDisplayModeId120.value())) + .setId(kDisplayModeId120) + .setPhysicalDisplayId(PrimaryDisplayVariant::DISPLAY_ID::get()) + .setVsyncPeriod(int32_t(8'333'333)) + .setGroup(0) + .setHeight(1000) + .setWidth(1000) + .build(); +}; + +TEST_F(InitiateModeChangeTest, setDesiredActiveMode_setCurrentMode) { + EXPECT_FALSE(mDisplay->setDesiredActiveMode({kDisplayMode60, Event::None})); + EXPECT_EQ(std::nullopt, mDisplay->getDesiredActiveMode()); +} + +TEST_F(InitiateModeChangeTest, setDesiredActiveMode_setNewMode) { + EXPECT_TRUE(mDisplay->setDesiredActiveMode({kDisplayMode90, Event::None})); + ASSERT_NE(std::nullopt, mDisplay->getDesiredActiveMode()); + EXPECT_EQ(kDisplayMode90, mDisplay->getDesiredActiveMode()->mode); + EXPECT_EQ(Event::None, mDisplay->getDesiredActiveMode()->event); + + // Setting another mode should be cached but return false + EXPECT_FALSE(mDisplay->setDesiredActiveMode({kDisplayMode120, Event::None})); + ASSERT_NE(std::nullopt, mDisplay->getDesiredActiveMode()); + EXPECT_EQ(kDisplayMode120, mDisplay->getDesiredActiveMode()->mode); + EXPECT_EQ(Event::None, mDisplay->getDesiredActiveMode()->event); +} + +TEST_F(InitiateModeChangeTest, clearDesiredActiveModeState) { + EXPECT_TRUE(mDisplay->setDesiredActiveMode({kDisplayMode90, Event::None})); + ASSERT_NE(std::nullopt, mDisplay->getDesiredActiveMode()); + + mDisplay->clearDesiredActiveModeState(); + ASSERT_EQ(std::nullopt, mDisplay->getDesiredActiveMode()); +} + +TEST_F(InitiateModeChangeTest, initiateModeChange) NO_THREAD_SAFETY_ANALYSIS { + EXPECT_TRUE(mDisplay->setDesiredActiveMode({kDisplayMode90, Event::None})); + ASSERT_NE(std::nullopt, mDisplay->getDesiredActiveMode()); + EXPECT_EQ(kDisplayMode90, mDisplay->getDesiredActiveMode()->mode); + EXPECT_EQ(Event::None, mDisplay->getDesiredActiveMode()->event); + + hal::VsyncPeriodChangeConstraints constraints{ + .desiredTimeNanos = systemTime(), + .seamlessRequired = false, + }; + hal::VsyncPeriodChangeTimeline timeline; + EXPECT_EQ(OK, + mDisplay->initiateModeChange(*mDisplay->getDesiredActiveMode(), constraints, + &timeline)); + EXPECT_EQ(kDisplayMode90, mDisplay->getUpcomingActiveMode().mode); + EXPECT_EQ(Event::None, mDisplay->getUpcomingActiveMode().event); + + mDisplay->clearDesiredActiveModeState(); + ASSERT_EQ(std::nullopt, mDisplay->getDesiredActiveMode()); +} + +TEST_F(InitiateModeChangeTest, getUpcomingActiveMode_desiredActiveModeChanged) +NO_THREAD_SAFETY_ANALYSIS { + EXPECT_TRUE(mDisplay->setDesiredActiveMode({kDisplayMode90, Event::None})); + ASSERT_NE(std::nullopt, mDisplay->getDesiredActiveMode()); + EXPECT_EQ(kDisplayMode90, mDisplay->getDesiredActiveMode()->mode); + EXPECT_EQ(Event::None, mDisplay->getDesiredActiveMode()->event); + + hal::VsyncPeriodChangeConstraints constraints{ + .desiredTimeNanos = systemTime(), + .seamlessRequired = false, + }; + hal::VsyncPeriodChangeTimeline timeline; + EXPECT_EQ(OK, + mDisplay->initiateModeChange(*mDisplay->getDesiredActiveMode(), constraints, + &timeline)); + EXPECT_EQ(kDisplayMode90, mDisplay->getUpcomingActiveMode().mode); + EXPECT_EQ(Event::None, mDisplay->getUpcomingActiveMode().event); + + EXPECT_FALSE(mDisplay->setDesiredActiveMode({kDisplayMode120, Event::None})); + ASSERT_NE(std::nullopt, mDisplay->getDesiredActiveMode()); + EXPECT_EQ(kDisplayMode120, mDisplay->getDesiredActiveMode()->mode); + EXPECT_EQ(Event::None, mDisplay->getDesiredActiveMode()->event); + + EXPECT_EQ(kDisplayMode90, mDisplay->getUpcomingActiveMode().mode); + EXPECT_EQ(Event::None, mDisplay->getUpcomingActiveMode().event); + + EXPECT_EQ(OK, + mDisplay->initiateModeChange(*mDisplay->getDesiredActiveMode(), constraints, + &timeline)); + EXPECT_EQ(kDisplayMode120, mDisplay->getUpcomingActiveMode().mode); + EXPECT_EQ(Event::None, mDisplay->getUpcomingActiveMode().event); + + mDisplay->clearDesiredActiveModeState(); + ASSERT_EQ(std::nullopt, mDisplay->getDesiredActiveMode()); +} + +} // namespace +} // namespace android diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h index 6ce281d403..de058a4f68 100644 --- a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h +++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h @@ -615,8 +615,8 @@ struct HwcVirtualDisplayVariant } static void setupHwcVirtualDisplayCreationCallExpectations(DisplayTransactionTest* test) { - EXPECT_CALL(*test->mComposer, createVirtualDisplay(Base::WIDTH, Base::HEIGHT, _, _, _)) - .WillOnce(DoAll(SetArgPointee<4>(Self::HWC_DISPLAY_ID), Return(Error::NONE))); + EXPECT_CALL(*test->mComposer, createVirtualDisplay(Base::WIDTH, Base::HEIGHT, _, _)) + .WillOnce(DoAll(SetArgPointee<3>(Self::HWC_DISPLAY_ID), Return(Error::NONE))); EXPECT_CALL(*test->mComposer, setClientTargetSlotCount(_)).WillOnce(Return(Error::NONE)); } }; diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp index b4a1481e9c..4ff7592b71 100644 --- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp +++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp @@ -543,17 +543,34 @@ TEST_F(EventThreadTest, postHotplugExternalConnect) { } TEST_F(EventThreadTest, postConfigChangedPrimary) { - mThread->onModeChanged(INTERNAL_DISPLAY_ID, DisplayModeId(7), 16666666); + const auto mode = DisplayMode::Builder(hal::HWConfigId(0)) + .setPhysicalDisplayId(INTERNAL_DISPLAY_ID) + .setId(DisplayModeId(7)) + .setVsyncPeriod(16666666) + .build(); + + mThread->onModeChanged(mode); expectConfigChangedEventReceivedByConnection(INTERNAL_DISPLAY_ID, 7, 16666666); } TEST_F(EventThreadTest, postConfigChangedExternal) { - mThread->onModeChanged(EXTERNAL_DISPLAY_ID, DisplayModeId(5), 16666666); + const auto mode = DisplayMode::Builder(hal::HWConfigId(0)) + .setPhysicalDisplayId(EXTERNAL_DISPLAY_ID) + .setId(DisplayModeId(5)) + .setVsyncPeriod(16666666) + .build(); + + mThread->onModeChanged(mode); expectConfigChangedEventReceivedByConnection(EXTERNAL_DISPLAY_ID, 5, 16666666); } TEST_F(EventThreadTest, postConfigChangedPrimary64bit) { - mThread->onModeChanged(DISPLAY_ID_64BIT, DisplayModeId(7), 16666666); + const auto mode = DisplayMode::Builder(hal::HWConfigId(0)) + .setPhysicalDisplayId(DISPLAY_ID_64BIT) + .setId(DisplayModeId(7)) + .setVsyncPeriod(16666666) + .build(); + mThread->onModeChanged(mode); expectConfigChangedEventReceivedByConnection(DISPLAY_ID_64BIT, 7, 16666666); } @@ -562,7 +579,13 @@ TEST_F(EventThreadTest, suppressConfigChanged) { sp<MockEventThreadConnection> suppressConnection = createConnection(suppressConnectionEventRecorder); - mThread->onModeChanged(INTERNAL_DISPLAY_ID, DisplayModeId(9), 16666666); + const auto mode = DisplayMode::Builder(hal::HWConfigId(0)) + .setPhysicalDisplayId(INTERNAL_DISPLAY_ID) + .setId(DisplayModeId(9)) + .setVsyncPeriod(16666666) + .build(); + + mThread->onModeChanged(mode); expectConfigChangedEventReceivedByConnection(INTERNAL_DISPLAY_ID, 9, 16666666); auto args = suppressConnectionEventRecorder.waitForCall(); diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp index b67ebcaa49..02ec7fc493 100644 --- a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp +++ b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp @@ -35,6 +35,7 @@ using testing::_; using testing::Return; +using testing::ReturnRef; namespace android { @@ -62,6 +63,10 @@ protected: LayerHistory& history() { return *mScheduler->mutableLayerHistory(); } const LayerHistory& history() const { return *mScheduler->mutableLayerHistory(); } + LayerHistory::Summary summarizeLayerHistory(nsecs_t now) { + return history().summarize(*mScheduler->refreshRateConfigs(), now); + } + size_t layerCount() const { return mScheduler->layerHistorySize(); } size_t activeLayerCount() const NO_THREAD_SAFETY_ANALYSIS { return history().mActiveLayersEnd; } @@ -101,7 +106,7 @@ protected: history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer); time += frameRate.getPeriodNsecs(); - summary = history().summarize(time); + summary = summarizeLayerHistory(time); } ASSERT_EQ(1, summary.size()); @@ -110,21 +115,24 @@ protected: << "Frame rate is " << frameRate; } - RefreshRateConfigs mConfigs{{DisplayMode::Builder(0) - .setId(DisplayModeId(0)) - .setVsyncPeriod(int32_t(LO_FPS_PERIOD)) - .setGroup(0) - .build(), - DisplayMode::Builder(1) - .setId(DisplayModeId(1)) - .setVsyncPeriod(int32_t(HI_FPS_PERIOD)) - .setGroup(0) - .build()}, - DisplayModeId(0)}; - - mock::NoOpSchedulerCallback mSchedulerCallback; - - TestableScheduler* const mScheduler = new TestableScheduler(mConfigs, mSchedulerCallback); + std::shared_ptr<RefreshRateConfigs> mConfigs = std::make_shared< + RefreshRateConfigs>(DisplayModes{DisplayMode::Builder(0) + .setId(DisplayModeId(0)) + .setPhysicalDisplayId(PhysicalDisplayId(0)) + .setVsyncPeriod(int32_t(LO_FPS_PERIOD)) + .setGroup(0) + .build(), + DisplayMode::Builder(1) + .setId(DisplayModeId(1)) + .setPhysicalDisplayId(PhysicalDisplayId(0)) + .setVsyncPeriod(int32_t(HI_FPS_PERIOD)) + .setGroup(0) + .build()}, + DisplayModeId(0)); + + mock::SchedulerCallback mSchedulerCallback; + + TestableScheduler* mScheduler = new TestableScheduler(mConfigs, mSchedulerCallback); TestableSurfaceFlinger mFlinger; }; @@ -142,22 +150,22 @@ TEST_F(LayerHistoryTest, oneLayer) { const nsecs_t time = systemTime(); // No layers returned if no layers are active. - EXPECT_TRUE(history().summarize(time).empty()); + EXPECT_TRUE(summarizeLayerHistory(time).empty()); EXPECT_EQ(0, activeLayerCount()); // Max returned if active layers have insufficient history. for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE - 1; i++) { history().record(layer.get(), 0, time, LayerHistory::LayerUpdateType::Buffer); - ASSERT_EQ(1, history().summarize(time).size()); - EXPECT_EQ(LayerHistory::LayerVoteType::Max, history().summarize(time)[0].vote); + ASSERT_EQ(1, summarizeLayerHistory(time).size()); + EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote); EXPECT_EQ(1, activeLayerCount()); } // Max is returned since we have enough history but there is no timestamp votes. for (int i = 0; i < 10; i++) { history().record(layer.get(), 0, time, LayerHistory::LayerUpdateType::Buffer); - ASSERT_EQ(1, history().summarize(time).size()); - EXPECT_EQ(LayerHistory::LayerVoteType::Max, history().summarize(time)[0].vote); + ASSERT_EQ(1, summarizeLayerHistory(time).size()); + EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote); EXPECT_EQ(1, activeLayerCount()); } } @@ -173,17 +181,17 @@ TEST_F(LayerHistoryTest, oneInvisibleLayer) { nsecs_t time = systemTime(); history().record(layer.get(), 0, time, LayerHistory::LayerUpdateType::Buffer); - auto summary = history().summarize(time); - ASSERT_EQ(1, history().summarize(time).size()); + auto summary = summarizeLayerHistory(time); + ASSERT_EQ(1, summarizeLayerHistory(time).size()); // Layer is still considered inactive so we expect to get Min - EXPECT_EQ(LayerHistory::LayerVoteType::Max, history().summarize(time)[0].vote); + EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote); EXPECT_EQ(1, activeLayerCount()); EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(false)); history().record(layer.get(), 0, time, LayerHistory::LayerUpdateType::Buffer); - summary = history().summarize(time); - EXPECT_TRUE(history().summarize(time).empty()); + summary = summarizeLayerHistory(time); + EXPECT_TRUE(summarizeLayerHistory(time).empty()); EXPECT_EQ(0, activeLayerCount()); } @@ -201,9 +209,9 @@ TEST_F(LayerHistoryTest, explicitTimestamp) { time += LO_FPS_PERIOD; } - ASSERT_EQ(1, history().summarize(time).size()); - EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, history().summarize(time)[0].vote); - EXPECT_TRUE(LO_FPS.equalsWithMargin(history().summarize(time)[0].desiredRefreshRate)); + ASSERT_EQ(1, summarizeLayerHistory(time).size()); + EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summarizeLayerHistory(time)[0].vote); + EXPECT_TRUE(LO_FPS.equalsWithMargin(summarizeLayerHistory(time)[0].desiredRefreshRate)); EXPECT_EQ(1, activeLayerCount()); EXPECT_EQ(1, frequentLayerCount(time)); } @@ -224,13 +232,13 @@ TEST_F(LayerHistoryTest, oneLayerNoVote) { time += HI_FPS_PERIOD; } - ASSERT_TRUE(history().summarize(time).empty()); + ASSERT_TRUE(summarizeLayerHistory(time).empty()); EXPECT_EQ(1, activeLayerCount()); EXPECT_EQ(1, frequentLayerCount(time)); // layer became inactive time += MAX_ACTIVE_LAYER_PERIOD_NS.count(); - ASSERT_TRUE(history().summarize(time).empty()); + ASSERT_TRUE(summarizeLayerHistory(time).empty()); EXPECT_EQ(0, activeLayerCount()); EXPECT_EQ(0, frequentLayerCount(time)); } @@ -251,14 +259,14 @@ TEST_F(LayerHistoryTest, oneLayerMinVote) { time += HI_FPS_PERIOD; } - ASSERT_EQ(1, history().summarize(time).size()); - EXPECT_EQ(LayerHistory::LayerVoteType::Min, history().summarize(time)[0].vote); + ASSERT_EQ(1, summarizeLayerHistory(time).size()); + EXPECT_EQ(LayerHistory::LayerVoteType::Min, summarizeLayerHistory(time)[0].vote); EXPECT_EQ(1, activeLayerCount()); EXPECT_EQ(1, frequentLayerCount(time)); // layer became inactive time += MAX_ACTIVE_LAYER_PERIOD_NS.count(); - ASSERT_TRUE(history().summarize(time).empty()); + ASSERT_TRUE(summarizeLayerHistory(time).empty()); EXPECT_EQ(0, activeLayerCount()); EXPECT_EQ(0, frequentLayerCount(time)); } @@ -279,14 +287,14 @@ TEST_F(LayerHistoryTest, oneLayerMaxVote) { time += LO_FPS_PERIOD; } - ASSERT_EQ(1, history().summarize(time).size()); - EXPECT_EQ(LayerHistory::LayerVoteType::Max, history().summarize(time)[0].vote); + ASSERT_EQ(1, summarizeLayerHistory(time).size()); + EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote); EXPECT_EQ(1, activeLayerCount()); EXPECT_EQ(1, frequentLayerCount(time)); // layer became inactive time += MAX_ACTIVE_LAYER_PERIOD_NS.count(); - ASSERT_TRUE(history().summarize(time).empty()); + ASSERT_TRUE(summarizeLayerHistory(time).empty()); EXPECT_EQ(0, activeLayerCount()); EXPECT_EQ(0, frequentLayerCount(time)); } @@ -307,18 +315,18 @@ TEST_F(LayerHistoryTest, oneLayerExplicitVote) { time += HI_FPS_PERIOD; } - ASSERT_EQ(1, history().summarize(time).size()); - EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitDefault, history().summarize(time)[0].vote); - EXPECT_TRUE(Fps(73.4f).equalsWithMargin(history().summarize(time)[0].desiredRefreshRate)); + ASSERT_EQ(1, summarizeLayerHistory(time).size()); + EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitDefault, summarizeLayerHistory(time)[0].vote); + EXPECT_TRUE(Fps(73.4f).equalsWithMargin(summarizeLayerHistory(time)[0].desiredRefreshRate)); EXPECT_EQ(1, activeLayerCount()); EXPECT_EQ(1, frequentLayerCount(time)); // layer became inactive, but the vote stays setDefaultLayerVote(layer.get(), LayerHistory::LayerVoteType::Heuristic); time += MAX_ACTIVE_LAYER_PERIOD_NS.count(); - ASSERT_EQ(1, history().summarize(time).size()); - EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitDefault, history().summarize(time)[0].vote); - EXPECT_TRUE(Fps(73.4f).equalsWithMargin(history().summarize(time)[0].desiredRefreshRate)); + ASSERT_EQ(1, summarizeLayerHistory(time).size()); + EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitDefault, summarizeLayerHistory(time)[0].vote); + EXPECT_TRUE(Fps(73.4f).equalsWithMargin(summarizeLayerHistory(time)[0].desiredRefreshRate)); EXPECT_EQ(1, activeLayerCount()); EXPECT_EQ(0, frequentLayerCount(time)); } @@ -339,20 +347,20 @@ TEST_F(LayerHistoryTest, oneLayerExplicitExactVote) { time += HI_FPS_PERIOD; } - ASSERT_EQ(1, history().summarize(time).size()); + ASSERT_EQ(1, summarizeLayerHistory(time).size()); EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitExactOrMultiple, - history().summarize(time)[0].vote); - EXPECT_TRUE(Fps(73.4f).equalsWithMargin(history().summarize(time)[0].desiredRefreshRate)); + summarizeLayerHistory(time)[0].vote); + EXPECT_TRUE(Fps(73.4f).equalsWithMargin(summarizeLayerHistory(time)[0].desiredRefreshRate)); EXPECT_EQ(1, activeLayerCount()); EXPECT_EQ(1, frequentLayerCount(time)); // layer became inactive, but the vote stays setDefaultLayerVote(layer.get(), LayerHistory::LayerVoteType::Heuristic); time += MAX_ACTIVE_LAYER_PERIOD_NS.count(); - ASSERT_EQ(1, history().summarize(time).size()); + ASSERT_EQ(1, summarizeLayerHistory(time).size()); EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitExactOrMultiple, - history().summarize(time)[0].vote); - EXPECT_TRUE(Fps(73.4f).equalsWithMargin(history().summarize(time)[0].desiredRefreshRate)); + summarizeLayerHistory(time)[0].vote); + EXPECT_TRUE(Fps(73.4f).equalsWithMargin(summarizeLayerHistory(time)[0].desiredRefreshRate)); EXPECT_EQ(1, activeLayerCount()); EXPECT_EQ(0, frequentLayerCount(time)); } @@ -383,7 +391,7 @@ TEST_F(LayerHistoryTest, multipleLayers) { for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) { history().record(layer1.get(), time, time, LayerHistory::LayerUpdateType::Buffer); time += MAX_FREQUENT_LAYER_PERIOD_NS.count(); - summary = history().summarize(time); + summary = summarizeLayerHistory(time); } ASSERT_EQ(1, summary.size()); @@ -395,7 +403,7 @@ TEST_F(LayerHistoryTest, multipleLayers) { for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) { history().record(layer2.get(), time, time, LayerHistory::LayerUpdateType::Buffer); time += HI_FPS_PERIOD; - summary = history().summarize(time); + summary = summarizeLayerHistory(time); } // layer1 is still active but infrequent. @@ -404,7 +412,7 @@ TEST_F(LayerHistoryTest, multipleLayers) { ASSERT_EQ(2, summary.size()); EXPECT_EQ(LayerHistory::LayerVoteType::Min, summary[0].vote); ASSERT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[1].vote); - EXPECT_TRUE(HI_FPS.equalsWithMargin(history().summarize(time)[1].desiredRefreshRate)); + EXPECT_TRUE(HI_FPS.equalsWithMargin(summarizeLayerHistory(time)[1].desiredRefreshRate)); EXPECT_EQ(2, activeLayerCount()); EXPECT_EQ(1, frequentLayerCount(time)); @@ -414,7 +422,7 @@ TEST_F(LayerHistoryTest, multipleLayers) { for (int i = 0; i < 2 * PRESENT_TIME_HISTORY_SIZE; i++) { history().record(layer2.get(), time, time, LayerHistory::LayerUpdateType::Buffer); time += LO_FPS_PERIOD; - summary = history().summarize(time); + summary = summarizeLayerHistory(time); } ASSERT_EQ(1, summary.size()); @@ -433,7 +441,7 @@ TEST_F(LayerHistoryTest, multipleLayers) { history().record(layer3.get(), time, time, LayerHistory::LayerUpdateType::Buffer); time += HI_FPS_PERIOD; - summary = history().summarize(time); + summary = summarizeLayerHistory(time); } ASSERT_EQ(2, summary.size()); @@ -445,7 +453,7 @@ TEST_F(LayerHistoryTest, multipleLayers) { // layer3 becomes recently active. history().record(layer3.get(), time, time, LayerHistory::LayerUpdateType::Buffer); - summary = history().summarize(time); + summary = summarizeLayerHistory(time); ASSERT_EQ(2, summary.size()); EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote); EXPECT_TRUE(LO_FPS.equalsWithMargin(summary[0].desiredRefreshRate)); @@ -456,7 +464,7 @@ TEST_F(LayerHistoryTest, multipleLayers) { // layer1 expires. layer1.clear(); - summary = history().summarize(time); + summary = summarizeLayerHistory(time); ASSERT_EQ(2, summary.size()); EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote); EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote); @@ -472,7 +480,7 @@ TEST_F(LayerHistoryTest, multipleLayers) { for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) { history().record(layer2.get(), time, time, LayerHistory::LayerUpdateType::Buffer); time += LO_FPS_PERIOD; - summary = history().summarize(time); + summary = summarizeLayerHistory(time); } ASSERT_EQ(1, summary.size()); @@ -483,7 +491,7 @@ TEST_F(LayerHistoryTest, multipleLayers) { // layer2 expires. layer2.clear(); - summary = history().summarize(time); + summary = summarizeLayerHistory(time); EXPECT_TRUE(summary.empty()); EXPECT_EQ(1, layerCount()); EXPECT_EQ(0, activeLayerCount()); @@ -493,7 +501,7 @@ TEST_F(LayerHistoryTest, multipleLayers) { for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE + FREQUENT_LAYER_WINDOW_SIZE + 1; i++) { history().record(layer3.get(), time, time, LayerHistory::LayerUpdateType::Buffer); time += HI_FPS_PERIOD; - summary = history().summarize(time); + summary = summarizeLayerHistory(time); } ASSERT_EQ(1, summary.size()); @@ -505,7 +513,7 @@ TEST_F(LayerHistoryTest, multipleLayers) { // layer3 expires. layer3.clear(); - summary = history().summarize(time); + summary = summarizeLayerHistory(time); EXPECT_TRUE(summary.empty()); EXPECT_EQ(0, layerCount()); EXPECT_EQ(0, activeLayerCount()); @@ -526,8 +534,8 @@ TEST_F(LayerHistoryTest, inactiveLayers) { time += MAX_FREQUENT_LAYER_PERIOD_NS.count(); EXPECT_EQ(1, layerCount()); - ASSERT_EQ(1, history().summarize(time).size()); - EXPECT_EQ(LayerHistory::LayerVoteType::Max, history().summarize(time)[0].vote); + ASSERT_EQ(1, summarizeLayerHistory(time).size()); + EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote); EXPECT_EQ(1, activeLayerCount()); EXPECT_EQ(1, frequentLayerCount(time)); } @@ -537,8 +545,8 @@ TEST_F(LayerHistoryTest, inactiveLayers) { time += MAX_FREQUENT_LAYER_PERIOD_NS.count(); EXPECT_EQ(1, layerCount()); - ASSERT_EQ(1, history().summarize(time).size()); - EXPECT_EQ(LayerHistory::LayerVoteType::Min, history().summarize(time)[0].vote); + ASSERT_EQ(1, summarizeLayerHistory(time).size()); + EXPECT_EQ(LayerHistory::LayerVoteType::Min, summarizeLayerHistory(time)[0].vote); EXPECT_EQ(1, activeLayerCount()); EXPECT_EQ(0, frequentLayerCount(time)); @@ -551,8 +559,8 @@ TEST_F(LayerHistoryTest, inactiveLayers) { time += HI_FPS_PERIOD; EXPECT_EQ(1, layerCount()); - ASSERT_EQ(1, history().summarize(time).size()); - EXPECT_EQ(LayerHistory::LayerVoteType::Min, history().summarize(time)[0].vote); + ASSERT_EQ(1, summarizeLayerHistory(time).size()); + EXPECT_EQ(LayerHistory::LayerVoteType::Min, summarizeLayerHistory(time)[0].vote); EXPECT_EQ(1, activeLayerCount()); EXPECT_EQ(0, frequentLayerCount(time)); } @@ -562,8 +570,8 @@ TEST_F(LayerHistoryTest, inactiveLayers) { time += HI_FPS_PERIOD; EXPECT_EQ(1, layerCount()); - ASSERT_EQ(1, history().summarize(time).size()); - EXPECT_EQ(LayerHistory::LayerVoteType::Max, history().summarize(time)[0].vote); + ASSERT_EQ(1, summarizeLayerHistory(time).size()); + EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote); EXPECT_EQ(1, activeLayerCount()); EXPECT_EQ(1, frequentLayerCount(time)); } @@ -590,10 +598,10 @@ TEST_F(LayerHistoryTest, invisibleExplicitLayer) { LayerHistory::LayerUpdateType::Buffer); EXPECT_EQ(2, layerCount()); - ASSERT_EQ(1, history().summarize(time).size()); + ASSERT_EQ(1, summarizeLayerHistory(time).size()); EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitExactOrMultiple, - history().summarize(time)[0].vote); - EXPECT_TRUE(Fps(60.0f).equalsWithMargin(history().summarize(time)[0].desiredRefreshRate)); + summarizeLayerHistory(time)[0].vote); + EXPECT_TRUE(Fps(60.0f).equalsWithMargin(summarizeLayerHistory(time)[0].desiredRefreshRate)); EXPECT_EQ(2, activeLayerCount()); EXPECT_EQ(2, frequentLayerCount(time)); } @@ -617,8 +625,8 @@ TEST_F(LayerHistoryTest, infrequentAnimatingLayer) { time += MAX_FREQUENT_LAYER_PERIOD_NS.count(); } - ASSERT_EQ(1, history().summarize(time).size()); - EXPECT_EQ(LayerHistory::LayerVoteType::Min, history().summarize(time)[0].vote); + ASSERT_EQ(1, summarizeLayerHistory(time).size()); + EXPECT_EQ(LayerHistory::LayerVoteType::Min, summarizeLayerHistory(time)[0].vote); EXPECT_EQ(1, activeLayerCount()); EXPECT_EQ(0, frequentLayerCount(time)); EXPECT_EQ(0, animatingLayerCount(time)); @@ -627,8 +635,8 @@ TEST_F(LayerHistoryTest, infrequentAnimatingLayer) { history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer); time += MAX_FREQUENT_LAYER_PERIOD_NS.count(); - ASSERT_EQ(1, history().summarize(time).size()); - EXPECT_EQ(LayerHistory::LayerVoteType::Min, history().summarize(time)[0].vote); + ASSERT_EQ(1, summarizeLayerHistory(time).size()); + EXPECT_EQ(LayerHistory::LayerVoteType::Min, summarizeLayerHistory(time)[0].vote); EXPECT_EQ(1, activeLayerCount()); EXPECT_EQ(0, frequentLayerCount(time)); EXPECT_EQ(0, animatingLayerCount(time)); @@ -637,8 +645,8 @@ TEST_F(LayerHistoryTest, infrequentAnimatingLayer) { history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::AnimationTX); time += MAX_FREQUENT_LAYER_PERIOD_NS.count(); - ASSERT_EQ(1, history().summarize(time).size()); - EXPECT_EQ(LayerHistory::LayerVoteType::Max, history().summarize(time)[0].vote); + ASSERT_EQ(1, summarizeLayerHistory(time).size()); + EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote); EXPECT_EQ(1, activeLayerCount()); EXPECT_EQ(0, frequentLayerCount(time)); EXPECT_EQ(1, animatingLayerCount(time)); @@ -727,13 +735,13 @@ TEST_P(LayerHistoryTestParameterized, HeuristicLayerWithInfrequentLayer) { } if (time - startTime > PRESENT_TIME_HISTORY_DURATION.count()) { - ASSERT_NE(0, history().summarize(time).size()); - ASSERT_GE(2, history().summarize(time).size()); + ASSERT_NE(0, summarizeLayerHistory(time).size()); + ASSERT_GE(2, summarizeLayerHistory(time).size()); bool max = false; bool min = false; Fps heuristic{0.0}; - for (const auto& layer : history().summarize(time)) { + for (const auto& layer : summarizeLayerHistory(time)) { if (layer.vote == LayerHistory::LayerVoteType::Heuristic) { heuristic = layer.desiredRefreshRate; } else if (layer.vote == LayerHistory::LayerVoteType::Max) { @@ -746,7 +754,7 @@ TEST_P(LayerHistoryTestParameterized, HeuristicLayerWithInfrequentLayer) { if (infrequentLayerUpdates > FREQUENT_LAYER_WINDOW_SIZE) { EXPECT_TRUE(Fps(24.0f).equalsWithMargin(heuristic)); EXPECT_FALSE(max); - if (history().summarize(time).size() == 2) { + if (summarizeLayerHistory(time).size() == 2) { EXPECT_TRUE(min); } } diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp index 3b2bd818b7..c1dba2bd61 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp @@ -51,8 +51,7 @@ protected: ~RefreshRateConfigsTest(); RefreshRate createRefreshRate(DisplayModePtr displayMode) { - return {displayMode->getId(), displayMode, displayMode->getFps(), - RefreshRate::ConstructorTag(0)}; + return {displayMode, RefreshRate::ConstructorTag(0)}; } Fps findClosestKnownFrameRate(const RefreshRateConfigs& refreshRateConfigs, Fps frameRate) { @@ -147,24 +146,17 @@ protected: DisplayModes m60_120Device = {mConfig60, mConfig120}; // Expected RefreshRate objects - RefreshRate mExpected60Config = {HWC_CONFIG_ID_60, mConfig60, Fps(60), - RefreshRate::ConstructorTag(0)}; - RefreshRate mExpectedAlmost60Config = {HWC_CONFIG_ID_60, - createDisplayMode(HWC_CONFIG_ID_60, 0, 16666665), - Fps(60), RefreshRate::ConstructorTag(0)}; - RefreshRate mExpected90Config = {HWC_CONFIG_ID_90, mConfig90, Fps(90), - RefreshRate::ConstructorTag(0)}; - RefreshRate mExpected90DifferentGroupConfig = {HWC_CONFIG_ID_90, mConfig90DifferentGroup, - Fps(90), RefreshRate::ConstructorTag(0)}; - RefreshRate mExpected90DifferentResolutionConfig = {HWC_CONFIG_ID_90, - mConfig90DifferentResolution, Fps(90), + RefreshRate mExpected60Config = {mConfig60, RefreshRate::ConstructorTag(0)}; + RefreshRate mExpectedAlmost60Config = {createDisplayMode(HWC_CONFIG_ID_60, 0, 16666665), + RefreshRate::ConstructorTag(0)}; + RefreshRate mExpected90Config = {mConfig90, RefreshRate::ConstructorTag(0)}; + RefreshRate mExpected90DifferentGroupConfig = {mConfig90DifferentGroup, + RefreshRate::ConstructorTag(0)}; + RefreshRate mExpected90DifferentResolutionConfig = {mConfig90DifferentResolution, RefreshRate::ConstructorTag(0)}; - RefreshRate mExpected72Config = {HWC_CONFIG_ID_72, mConfig72, Fps(72.0f), - RefreshRate::ConstructorTag(0)}; - RefreshRate mExpected30Config = {HWC_CONFIG_ID_30, mConfig30, Fps(30), - RefreshRate::ConstructorTag(0)}; - RefreshRate mExpected120Config = {HWC_CONFIG_ID_120, mConfig120, Fps(120), - RefreshRate::ConstructorTag(0)}; + RefreshRate mExpected72Config = {mConfig72, RefreshRate::ConstructorTag(0)}; + RefreshRate mExpected30Config = {mConfig30, RefreshRate::ConstructorTag(0)}; + RefreshRate mExpected120Config = {mConfig120, RefreshRate::ConstructorTag(0)}; private: DisplayModePtr createDisplayMode(DisplayModeId modeId, int32_t group, int64_t vsyncPeriod, @@ -189,6 +181,7 @@ DisplayModePtr RefreshRateConfigsTest::createDisplayMode(DisplayModeId modeId, i int64_t vsyncPeriod, ui::Size resolution) { return DisplayMode::Builder(hal::HWConfigId(modeId.value())) .setId(modeId) + .setPhysicalDisplayId(PhysicalDisplayId(0)) .setVsyncPeriod(int32_t(vsyncPeriod)) .setGroup(group) .setHeight(resolution.height) @@ -2276,26 +2269,6 @@ TEST_F(RefreshRateConfigsTest, getFrameRateOverrides_touch) { ASSERT_TRUE(frameRateOverrides.empty()); } -TEST_F(RefreshRateConfigsTest, updateDisplayModes) { - auto refreshRateConfigs = - std::make_unique<RefreshRateConfigs>(m30_60_72_90_120Device, - /*currentConfigId=*/HWC_CONFIG_ID_30); - refreshRateConfigs->setDisplayManagerPolicy({DisplayModeId(HWC_CONFIG_ID_30), - /* allowGroupSwitching */ false, - /* range */ {Fps(30.0f), Fps(30.0f)}}); - - refreshRateConfigs->updateDisplayModes(m60_90Device, HWC_CONFIG_ID_60); - - const auto currentRefreshRate = refreshRateConfigs->getCurrentRefreshRate(); - EXPECT_TRUE(currentRefreshRate.getFps().equalsWithMargin(Fps(60.0))); - EXPECT_EQ(currentRefreshRate.getModeId(), HWC_CONFIG_ID_60); - - EXPECT_TRUE( - getMaxSupportedRefreshRate(*refreshRateConfigs).getFps().equalsWithMargin(Fps(90.0))); - EXPECT_TRUE( - getMinSupportedRefreshRate(*refreshRateConfigs).getFps().equalsWithMargin(Fps(60.0))); -} - } // namespace } // namespace scheduler } // namespace android diff --git a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp index bf07106afd..12b155bd2c 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp @@ -81,6 +81,7 @@ DisplayModePtr RefreshRateStatsTest::createDisplayMode(DisplayModeId modeId, int int64_t vsyncPeriod) { return DisplayMode::Builder(static_cast<hal::HWConfigId>(modeId.value())) .setId(modeId) + .setPhysicalDisplayId(PhysicalDisplayId(0)) .setVsyncPeriod(static_cast<int32_t>(vsyncPeriod)) .setGroup(group) .build(); diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp index f680d802e6..5713c2f64a 100644 --- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp +++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp @@ -53,16 +53,19 @@ protected: const DisplayModePtr mode60 = DisplayMode::Builder(0) .setId(DisplayModeId(0)) + .setPhysicalDisplayId(PhysicalDisplayId(0)) .setVsyncPeriod(Fps(60.f).getPeriodNsecs()) .setGroup(0) .build(); const DisplayModePtr mode120 = DisplayMode::Builder(1) .setId(DisplayModeId(1)) + .setPhysicalDisplayId(PhysicalDisplayId(0)) .setVsyncPeriod(Fps(120.f).getPeriodNsecs()) .setGroup(0) .build(); - scheduler::RefreshRateConfigs mConfigs{{mode60}, mode60->getId()}; + std::shared_ptr<scheduler::RefreshRateConfigs> mConfigs = + std::make_shared<scheduler::RefreshRateConfigs>(DisplayModes{mode60}, mode60->getId()); mock::SchedulerCallback mSchedulerCallback; @@ -171,7 +174,7 @@ TEST_F(SchedulerTest, chooseRefreshRateForContentIsNoopWhenModeSwitchingIsNotSup mScheduler->setDisplayPowerState(kPowerStateNormal); constexpr uint32_t kDisplayArea = 999'999; - mScheduler->onPrimaryDisplayAreaChanged(kDisplayArea); + mScheduler->onActiveDisplayAreaChanged(kDisplayArea); EXPECT_CALL(mSchedulerCallback, changeRefreshRate(_, _)).Times(0); mScheduler->chooseRefreshRateForContent(); @@ -182,7 +185,9 @@ TEST_F(SchedulerTest, updateDisplayModes) { sp<mock::MockLayer> layer = sp<mock::MockLayer>::make(mFlinger.flinger()); ASSERT_EQ(static_cast<size_t>(1), mScheduler->layerHistorySize()); - mConfigs.updateDisplayModes({mode60, mode120}, /* activeMode */ mode60->getId()); + mScheduler->setRefreshRateConfigs( + std::make_shared<scheduler::RefreshRateConfigs>(DisplayModes{mode60, mode120}, + mode60->getId())); ASSERT_EQ(static_cast<size_t>(0), mScheduler->getNumActiveLayers()); mScheduler->recordLayerHistory(layer.get(), 0, LayerHistory::LayerUpdateType::Buffer); @@ -194,20 +199,21 @@ TEST_F(SchedulerTest, testDispatchCachedReportedMode) { // onModeChange is called. mScheduler->clearOptionalFieldsInFeatures(); EXPECT_NO_FATAL_FAILURE(mScheduler->dispatchCachedReportedMode()); - EXPECT_CALL(*mEventThread, onModeChanged(_, _, _)).Times(0); + EXPECT_CALL(*mEventThread, onModeChanged(_)).Times(0); } TEST_F(SchedulerTest, onNonPrimaryDisplayModeChanged_invalidParameters) { - DisplayModeId modeId = DisplayModeId(111); - nsecs_t vsyncPeriod = 111111; + const auto mode = DisplayMode::Builder(hal::HWConfigId(0)) + .setId(DisplayModeId(111)) + .setPhysicalDisplayId(PHYSICAL_DISPLAY_ID) + .setVsyncPeriod(111111) + .build(); // If the handle is incorrect, the function should return before // onModeChange is called. Scheduler::ConnectionHandle invalidHandle = {.id = 123}; - EXPECT_NO_FATAL_FAILURE(mScheduler->onNonPrimaryDisplayModeChanged(invalidHandle, - PHYSICAL_DISPLAY_ID, modeId, - vsyncPeriod)); - EXPECT_CALL(*mEventThread, onModeChanged(_, _, _)).Times(0); + EXPECT_NO_FATAL_FAILURE(mScheduler->onNonPrimaryDisplayModeChanged(invalidHandle, mode)); + EXPECT_CALL(*mEventThread, onModeChanged(_)).Times(0); } TEST_F(SchedulerTest, calculateMaxAcquiredBufferCount) { @@ -225,7 +231,9 @@ MATCHER(Is120Hz, "") { } TEST_F(SchedulerTest, chooseRefreshRateForContentSelectsMaxRefreshRate) { - mConfigs.updateDisplayModes({mode60, mode120}, /* activeMode */ mode60->getId()); + mScheduler->setRefreshRateConfigs( + std::make_shared<scheduler::RefreshRateConfigs>(DisplayModes{mode60, mode120}, + mode60->getId())); sp<mock::MockLayer> layer = sp<mock::MockLayer>::make(mFlinger.flinger()); @@ -235,7 +243,7 @@ TEST_F(SchedulerTest, chooseRefreshRateForContentSelectsMaxRefreshRate) { mScheduler->setDisplayPowerState(kPowerStateNormal); constexpr uint32_t kDisplayArea = 999'999; - mScheduler->onPrimaryDisplayAreaChanged(kDisplayArea); + mScheduler->onActiveDisplayAreaChanged(kDisplayArea); EXPECT_CALL(mSchedulerCallback, changeRefreshRate(Is120Hz(), _)).Times(1); mScheduler->chooseRefreshRateForContent(); diff --git a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp index 2761470c31..a4e9d20b75 100644 --- a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp +++ b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp @@ -479,7 +479,9 @@ TEST_P(SetFrameRateTest, SetOnParentActivatesTree) { ->record(child.get(), 0, 0, LayerHistory::LayerUpdateType::Buffer); const auto layerHistorySummary = - mFlinger.mutableScheduler().mutableLayerHistory()->summarize(0); + mFlinger.mutableScheduler() + .mutableLayerHistory() + ->summarize(*mFlinger.mutableScheduler().refreshRateConfigs(), 0); ASSERT_EQ(2u, layerHistorySummary.size()); EXPECT_TRUE(FRAME_RATE_VOTE1.rate.equalsWithMargin(layerHistorySummary[0].desiredRefreshRate)); EXPECT_TRUE(FRAME_RATE_VOTE1.rate.equalsWithMargin(layerHistorySummary[1].desiredRefreshRate)); diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetDisplayStateTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetDisplayStateTest.cpp index be019848fb..fc40818ad1 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetDisplayStateTest.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetDisplayStateTest.cpp @@ -224,6 +224,74 @@ TEST_F(SetDisplayStateLockedTest, setDisplayStateLockedRequestsUpdateIfLayerStac EXPECT_EQ(456u, display.getCurrentDisplayState().layerStack); } +TEST_F(SetDisplayStateLockedTest, setDisplayStateLockedDoesNothingIfFlagsNotChanged) { + using Case = SimplePrimaryDisplayCase; + + // -------------------------------------------------------------------- + // Preconditions + + // A display is set up + auto display = Case::Display::makeFakeExistingDisplayInjector(this); + display.inject(); + + // The display has flags set + display.mutableCurrentDisplayState().flags = 1u; + + // The incoming request sets a different layer stack + DisplayState state; + state.what = DisplayState::eFlagsChanged; + state.token = display.token(); + state.flags = 1u; + + // -------------------------------------------------------------------- + // Invocation + + uint32_t flags = mFlinger.setDisplayStateLocked(state); + + // -------------------------------------------------------------------- + // Postconditions + + // The returned flags are empty + EXPECT_EQ(0u, flags); + + // The desired display state has been set to the new value. + EXPECT_EQ(1u, display.getCurrentDisplayState().flags); +} + +TEST_F(SetDisplayStateLockedTest, setDisplayStateLockedRequestsUpdateIfFlagsChanged) { + using Case = SimplePrimaryDisplayCase; + + // -------------------------------------------------------------------- + // Preconditions + + // A display is set up + auto display = Case::Display::makeFakeExistingDisplayInjector(this); + display.inject(); + + // The display has a layer stack set + display.mutableCurrentDisplayState().flags = 0u; + + // The incoming request sets a different layer stack + DisplayState state; + state.what = DisplayState::eFlagsChanged; + state.token = display.token(); + state.flags = 1u; + + // -------------------------------------------------------------------- + // Invocation + + uint32_t flags = mFlinger.setDisplayStateLocked(state); + + // -------------------------------------------------------------------- + // Postconditions + + // The returned flags indicate a transaction is needed + EXPECT_EQ(eDisplayTransactionNeeded, flags); + + // The desired display state has been set to the new value. + EXPECT_EQ(1u, display.getCurrentDisplayState().flags); +} + TEST_F(SetDisplayStateLockedTest, setDisplayStateLockedDoesNothingIfProjectionDidNotChange) { using Case = SimplePrimaryDisplayCase; constexpr ui::Rotation initialOrientation = ui::ROTATION_180; diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h index 41fd6e316f..a99dabe420 100644 --- a/services/surfaceflinger/tests/unittests/TestableScheduler.h +++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h @@ -32,15 +32,18 @@ namespace android { class TestableScheduler : public Scheduler { public: - TestableScheduler(const scheduler::RefreshRateConfigs& configs, ISchedulerCallback& callback) + TestableScheduler(const std::shared_ptr<scheduler::RefreshRateConfigs>& refreshRateConfigs, + ISchedulerCallback& callback) : TestableScheduler(std::make_unique<mock::VsyncController>(), - std::make_unique<mock::VSyncTracker>(), configs, callback) {} + std::make_unique<mock::VSyncTracker>(), refreshRateConfigs, + callback) {} TestableScheduler(std::unique_ptr<scheduler::VsyncController> vsyncController, std::unique_ptr<scheduler::VSyncTracker> vsyncTracker, - const scheduler::RefreshRateConfigs& configs, ISchedulerCallback& callback) - : Scheduler({std::move(vsyncController), std::move(vsyncTracker), nullptr}, configs, - callback, createLayerHistory(configs), + const std::shared_ptr<scheduler::RefreshRateConfigs>& refreshRateConfigs, + ISchedulerCallback& callback) + : Scheduler({std::move(vsyncController), std::move(vsyncTracker), nullptr}, + refreshRateConfigs, callback, createLayerHistory(), {.supportKernelTimer = false, .useContentDetection = true}) {} // Used to inject mock event thread. @@ -64,6 +67,8 @@ public: return mutableLayerHistory()->mLayerInfos.size(); } + auto refreshRateConfigs() { return holdRefreshRateConfigs(); } + size_t getNumActiveLayers() NO_THREAD_SAFETY_ANALYSIS { if (!mLayerHistory) return 0; return mutableLayerHistory()->mActiveLayersEnd; @@ -95,9 +100,8 @@ public: mFeatures.cachedModeChangedParams.reset(); } - void onNonPrimaryDisplayModeChanged(ConnectionHandle handle, PhysicalDisplayId displayId, - DisplayModeId modeId, nsecs_t vsyncPeriod) { - return Scheduler::onNonPrimaryDisplayModeChanged(handle, displayId, modeId, vsyncPeriod); + void onNonPrimaryDisplayModeChanged(ConnectionHandle handle, DisplayModePtr mode) { + return Scheduler::onNonPrimaryDisplayModeChanged(handle, mode); } ~TestableScheduler() { diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index cf67593174..40c881e902 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -82,8 +82,8 @@ public: return std::make_unique<scheduler::FakePhaseOffsets>(); } - std::unique_ptr<Scheduler> createScheduler(const scheduler::RefreshRateConfigs&, - ISchedulerCallback&) override { + std::unique_ptr<Scheduler> createScheduler( + const std::shared_ptr<scheduler::RefreshRateConfigs>&, ISchedulerCallback&) override { return nullptr; } @@ -209,6 +209,7 @@ public: ISchedulerCallback* callback = nullptr, bool hasMultipleModes = false) { DisplayModes modes{DisplayMode::Builder(0) .setId(DisplayModeId(0)) + .setPhysicalDisplayId(PhysicalDisplayId(0)) .setVsyncPeriod(16'666'667) .setGroup(0) .build()}; @@ -216,25 +217,24 @@ public: if (hasMultipleModes) { modes.emplace_back(DisplayMode::Builder(1) .setId(DisplayModeId(1)) + .setPhysicalDisplayId(PhysicalDisplayId(0)) .setVsyncPeriod(11'111'111) .setGroup(0) .build()); } const auto currMode = DisplayModeId(0); - mFlinger->mRefreshRateConfigs = - std::make_unique<scheduler::RefreshRateConfigs>(modes, currMode); - const auto currFps = - mFlinger->mRefreshRateConfigs->getRefreshRateFromModeId(currMode).getFps(); - mFlinger->mRefreshRateStats = - std::make_unique<scheduler::RefreshRateStats>(*mFlinger->mTimeStats, currFps, - /*powerMode=*/hal::PowerMode::OFF); + mRefreshRateConfigs = std::make_shared<scheduler::RefreshRateConfigs>(modes, currMode); + const auto currFps = mRefreshRateConfigs->getCurrentRefreshRate().getFps(); mFlinger->mVsyncConfiguration = mFactory.createVsyncConfiguration(currFps); mFlinger->mVsyncModulator = sp<scheduler::VsyncModulator>::make( mFlinger->mVsyncConfiguration->getCurrentConfigs()); + mFlinger->mRefreshRateStats = + std::make_unique<scheduler::RefreshRateStats>(*mFlinger->mTimeStats, currFps, + /*powerMode=*/hal::PowerMode::OFF); mScheduler = new TestableScheduler(std::move(vsyncController), std::move(vsyncTracker), - *mFlinger->mRefreshRateConfigs, *(callback ?: this)); + mRefreshRateConfigs, *(callback ?: this)); mFlinger->mAppConnectionHandle = mScheduler->createConnection(std::move(appEventThread)); mFlinger->mSfConnectionHandle = mScheduler->createConnection(std::move(sfEventThread)); @@ -435,6 +435,7 @@ public: auto& mutableTransactionFlags() { return mFlinger->mTransactionFlags; } auto& mutablePowerAdvisor() { return mFlinger->mPowerAdvisor; } auto& mutableDebugDisableHWC() { return mFlinger->mDebugDisableHWC; } + auto& mutableMaxRenderTargetSize() { return mFlinger->mMaxRenderTargetSize; } auto& mutableHwcDisplayData() { return getHwComposer().mDisplayData; } auto& mutableHwcPhysicalDisplayIdMap() { return getHwComposer().mPhysicalDisplayIdMap; } @@ -644,6 +645,7 @@ public: DisplayModePtr activeMode = DisplayMode::Builder(FakeHwcDisplayInjector::DEFAULT_ACTIVE_CONFIG) .setId(mActiveModeId) + .setPhysicalDisplayId(PhysicalDisplayId(0)) .setWidth(FakeHwcDisplayInjector::DEFAULT_WIDTH) .setHeight(FakeHwcDisplayInjector::DEFAULT_HEIGHT) .setVsyncPeriod(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD) @@ -654,6 +656,7 @@ public: DisplayModes modes{activeMode}; mCreationArgs.supportedModes = modes; + mCreationArgs.refreshRateConfigs = flinger.mRefreshRateConfigs; } sp<IBinder> token() const { return mDisplayToken; } @@ -723,7 +726,7 @@ public: return *this; } - sp<DisplayDevice> inject() { + sp<DisplayDevice> inject() NO_THREAD_SAFETY_ANALYSIS { const auto displayId = mCreationArgs.compositionDisplay->getDisplayId(); DisplayDeviceState state; @@ -770,6 +773,7 @@ private: surfaceflinger::test::Factory mFactory; sp<SurfaceFlinger> mFlinger = new SurfaceFlinger(mFactory, SurfaceFlinger::SkipInitialization); TestableScheduler* mScheduler = nullptr; + std::shared_ptr<scheduler::RefreshRateConfigs> mRefreshRateConfigs; }; } // namespace android diff --git a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp index 7c431a077b..1a50427b93 100644 --- a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp +++ b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp @@ -74,6 +74,7 @@ public: EXPECT_CALL(*mVSyncTracker, currentPeriod()) .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD)); + mFlinger.setupComposer(std::make_unique<Hwc2::mock::Composer>()); mFlinger.setupScheduler(std::unique_ptr<mock::VsyncController>(mVsyncController), std::unique_ptr<mock::VSyncTracker>(mVSyncTracker), std::move(eventThread), std::move(sfEventThread)); diff --git a/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp b/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp index 2845d0ab14..a749ece835 100644 --- a/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp +++ b/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp @@ -119,7 +119,7 @@ public: FrameTracer::FrameEvent::QUEUE, /*duration*/ 0)); layer->setBuffer(buffer, fence, postTime, /*desiredPresentTime*/ 30, false, mClientCache, frameNumber, dequeueTime, FrameTimelineInfo{}, - nullptr /* releaseBufferCallback */); + nullptr /* releaseBufferCallback */, nullptr /* releaseBufferEndpoint*/); commitTransaction(layer.get()); bool computeVisisbleRegions; diff --git a/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp b/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp index 7bf224d557..2a7921f661 100644 --- a/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp +++ b/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp @@ -119,7 +119,8 @@ public: 1, 0), mRenderEngine, false); layer->setBuffer(buffer, fence, 10, 20, false, mClientCache, 1, std::nullopt, - {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */); + {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */, + nullptr /* releaseBufferEndpoint */); acquireFence->signalForTest(12); commitTransaction(layer.get()); @@ -147,7 +148,8 @@ public: 1, 0), mRenderEngine, false); layer->setBuffer(buffer1, fence1, 10, 20, false, mClientCache, 1, std::nullopt, - {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */); + {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */, + nullptr /* releaseBufferEndpoint */); EXPECT_EQ(0u, layer->mDrawingState.bufferlessSurfaceFramesTX.size()); ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX); const auto droppedSurfaceFrame = layer->mDrawingState.bufferSurfaceFrameTX; @@ -160,7 +162,8 @@ public: mRenderEngine, false); nsecs_t start = systemTime(); layer->setBuffer(buffer2, fence2, 10, 20, false, mClientCache, 1, std::nullopt, - {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */); + {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */, + nullptr /* releaseBufferEndpoint */); nsecs_t end = systemTime(); acquireFence2->signalForTest(12); @@ -200,7 +203,8 @@ public: 1, 0), mRenderEngine, false); layer->setBuffer(buffer, fence, 10, 20, false, mClientCache, 1, std::nullopt, - {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */); + {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */, + nullptr /* releaseBufferEndpoint */); acquireFence->signalForTest(12); EXPECT_EQ(0u, layer->mDrawingState.bufferlessSurfaceFramesTX.size()); @@ -228,7 +232,8 @@ public: 1, 0), mRenderEngine, false); layer->setBuffer(buffer, fence, 10, 20, false, mClientCache, 1, std::nullopt, - {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */); + {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */, + nullptr /* releaseBufferEndpoint */); EXPECT_EQ(0u, layer->mDrawingState.bufferlessSurfaceFramesTX.size()); ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX); @@ -260,7 +265,8 @@ public: 1, 0), mRenderEngine, false); layer->setBuffer(buffer, fence, 10, 20, false, mClientCache, 1, std::nullopt, - {/*vsyncId*/ 3, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */); + {/*vsyncId*/ 3, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */, + nullptr /* releaseBufferEndpoint */); EXPECT_EQ(2u, layer->mDrawingState.bufferlessSurfaceFramesTX.size()); ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX); const auto bufferSurfaceFrameTX = layer->mDrawingState.bufferSurfaceFrameTX; @@ -298,7 +304,8 @@ public: 1, 0), mRenderEngine, false); layer->setBuffer(buffer1, fence1, 10, 20, false, mClientCache, 1, std::nullopt, - {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */); + {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */, + nullptr /* releaseBufferEndpoint */); ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX); const auto droppedSurfaceFrame = layer->mDrawingState.bufferSurfaceFrameTX; @@ -309,7 +316,8 @@ public: 1, 0), mRenderEngine, false); layer->setBuffer(buffer2, fence2, 10, 20, false, mClientCache, 1, std::nullopt, - {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */); + {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */, + nullptr /* releaseBufferEndpoint */); acquireFence2->signalForTest(12); ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX); @@ -339,7 +347,8 @@ public: 1, 0), mRenderEngine, false); layer->setBuffer(buffer1, fence1, 10, 20, false, mClientCache, 1, std::nullopt, - {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */); + {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */, + nullptr /* releaseBufferEndpoint */); EXPECT_EQ(0u, layer->mDrawingState.bufferlessSurfaceFramesTX.size()); ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX); const auto droppedSurfaceFrame1 = layer->mDrawingState.bufferSurfaceFrameTX; @@ -353,7 +362,7 @@ public: auto dropStartTime1 = systemTime(); layer->setBuffer(buffer2, fence2, 10, 20, false, mClientCache, 1, std::nullopt, {/*vsyncId*/ FrameTimelineInfo::INVALID_VSYNC_ID, /*inputEventId*/ 0}, - nullptr /* releaseBufferCallback */); + nullptr /* releaseBufferCallback */, nullptr /* releaseBufferEndpoint */); auto dropEndTime1 = systemTime(); EXPECT_EQ(0u, layer->mDrawingState.bufferlessSurfaceFramesTX.size()); ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX); @@ -367,7 +376,8 @@ public: mRenderEngine, false); auto dropStartTime2 = systemTime(); layer->setBuffer(buffer3, fence3, 10, 20, false, mClientCache, 1, std::nullopt, - {/*vsyncId*/ 2, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */); + {/*vsyncId*/ 2, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */, + nullptr /* releaseBufferEndpoint */); auto dropEndTime2 = systemTime(); acquireFence3->signalForTest(12); @@ -411,7 +421,8 @@ public: mRenderEngine, false); layer->setBuffer(buffer1, fence1, 10, 20, false, mClientCache, 1, std::nullopt, {/*vsyncId*/ 1, /*inputEventId*/ 0}, - nullptr /* releaseBufferCallback */); + nullptr /* releaseBufferCallback */, + nullptr /* releaseBufferEndpoint */); layer->setFrameTimelineVsyncForBufferlessTransaction({/*vsyncId*/ 2, /*inputEventId*/ 0}, 10); diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h index cb3bd73920..1ba3c0f56e 100644 --- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h +++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h @@ -54,8 +54,7 @@ public: MOCK_METHOD0(resetCommands, void()); MOCK_METHOD0(executeCommands, Error()); MOCK_METHOD0(getMaxVirtualDisplayCount, uint32_t()); - MOCK_METHOD5(createVirtualDisplay, - Error(uint32_t, uint32_t, PixelFormat*, std::optional<Display>, Display*)); + MOCK_METHOD4(createVirtualDisplay, Error(uint32_t, uint32_t, PixelFormat*, Display*)); MOCK_METHOD1(destroyVirtualDisplay, Error(Display)); MOCK_METHOD1(acceptDisplayChanges, Error(Display)); MOCK_METHOD2(createLayer, Error(Display, Layer* outLayer)); diff --git a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h index 485b4acdce..d25973e1ce 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h +++ b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h @@ -33,7 +33,7 @@ public: MOCK_METHOD0(onScreenReleased, void()); MOCK_METHOD0(onScreenAcquired, void()); MOCK_METHOD2(onHotplugReceived, void(PhysicalDisplayId, bool)); - MOCK_METHOD3(onModeChanged, void(PhysicalDisplayId, DisplayModeId, nsecs_t)); + MOCK_METHOD1(onModeChanged, void(DisplayModePtr)); MOCK_METHOD2(onFrameRateOverridesChanged, void(PhysicalDisplayId, std::vector<FrameRateOverride>)); MOCK_CONST_METHOD1(dump, void(std::string&)); diff --git a/services/surfaceflinger/tests/utils/CallbackUtils.h b/services/surfaceflinger/tests/utils/CallbackUtils.h index 459b35c544..f4a3425b6a 100644 --- a/services/surfaceflinger/tests/utils/CallbackUtils.h +++ b/services/surfaceflinger/tests/utils/CallbackUtils.h @@ -20,8 +20,12 @@ #include <gui/SurfaceControl.h> #include <ui/Fence.h> #include <utils/Timers.h> +#include <chrono> #include <thread> +using ::std::literals::chrono_literals::operator""ms; +using ::std::literals::chrono_literals::operator""s; + namespace android { namespace { |