diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2022-03-23 10:10:28 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2022-03-23 10:10:28 +0000 |
commit | c3e6bd2fb2223973f26325d11c28b32b8685cfbd (patch) | |
tree | da46aa45ad59a45a9fbbc5ea8610cb3878411436 | |
parent | fa715fbb081b1c548160bbf9b3b483f2e532960c (diff) | |
parent | 169d2b5244b662e05dee2595acaef912fa553c38 (diff) |
Snap for 8343869 from 169d2b5244b662e05dee2595acaef912fa553c38 to s-keystone-qcom-release
Change-Id: I3a2a1c3b8551e1c6af02b7c5426bffa4d5835511
217 files changed, 7490 insertions, 2437 deletions
diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc index e3c4edebbd..01c4723f29 100644 --- a/cmds/atrace/atrace.rc +++ b/cmds/atrace/atrace.rc @@ -265,6 +265,22 @@ on late-init chmod 0666 /sys/kernel/tracing/per_cpu/cpu14/trace chmod 0666 /sys/kernel/debug/tracing/per_cpu/cpu15/trace chmod 0666 /sys/kernel/tracing/per_cpu/cpu15/trace + chmod 0666 /sys/kernel/debug/tracing/per_cpu/cpu16/trace + chmod 0666 /sys/kernel/tracing/per_cpu/cpu16/trace + chmod 0666 /sys/kernel/debug/tracing/per_cpu/cpu17/trace + chmod 0666 /sys/kernel/tracing/per_cpu/cpu17/trace + chmod 0666 /sys/kernel/debug/tracing/per_cpu/cpu18/trace + chmod 0666 /sys/kernel/tracing/per_cpu/cpu18/trace + chmod 0666 /sys/kernel/debug/tracing/per_cpu/cpu19/trace + chmod 0666 /sys/kernel/tracing/per_cpu/cpu19/trace + chmod 0666 /sys/kernel/debug/tracing/per_cpu/cpu20/trace + chmod 0666 /sys/kernel/tracing/per_cpu/cpu20/trace + chmod 0666 /sys/kernel/debug/tracing/per_cpu/cpu21/trace + chmod 0666 /sys/kernel/tracing/per_cpu/cpu21/trace + chmod 0666 /sys/kernel/debug/tracing/per_cpu/cpu22/trace + chmod 0666 /sys/kernel/tracing/per_cpu/cpu22/trace + chmod 0666 /sys/kernel/debug/tracing/per_cpu/cpu23/trace + chmod 0666 /sys/kernel/tracing/per_cpu/cpu23/trace # Only create the tracing instance if persist.mm_events.enabled # Attempting to remove the tracing instance after it has been created @@ -337,6 +353,22 @@ on post-fs-data && property:persist.mm_events.enabled=true chmod 0666 /sys/kernel/tracing/instances/mm_events/per_cpu/cpu14/trace chmod 0666 /sys/kernel/debug/tracing/instances/mm_events/per_cpu/cpu15/trace chmod 0666 /sys/kernel/tracing/instances/mm_events/per_cpu/cpu15/trace + chmod 0666 /sys/kernel/debug/tracing/instances/mm_events/per_cpu/cpu16/trace + chmod 0666 /sys/kernel/tracing/instances/mm_events/per_cpu/cpu16/trace + chmod 0666 /sys/kernel/debug/tracing/instances/mm_events/per_cpu/cpu17/trace + chmod 0666 /sys/kernel/tracing/instances/mm_events/per_cpu/cpu17/trace + chmod 0666 /sys/kernel/debug/tracing/instances/mm_events/per_cpu/cpu18/trace + chmod 0666 /sys/kernel/tracing/instances/mm_events/per_cpu/cpu18/trace + chmod 0666 /sys/kernel/debug/tracing/instances/mm_events/per_cpu/cpu19/trace + chmod 0666 /sys/kernel/tracing/instances/mm_events/per_cpu/cpu19/trace + chmod 0666 /sys/kernel/debug/tracing/instances/mm_events/per_cpu/cpu20/trace + chmod 0666 /sys/kernel/tracing/instances/mm_events/per_cpu/cpu20/trace + chmod 0666 /sys/kernel/debug/tracing/instances/mm_events/per_cpu/cpu21/trace + chmod 0666 /sys/kernel/tracing/instances/mm_events/per_cpu/cpu21/trace + chmod 0666 /sys/kernel/debug/tracing/instances/mm_events/per_cpu/cpu22/trace + chmod 0666 /sys/kernel/tracing/instances/mm_events/per_cpu/cpu22/trace + chmod 0666 /sys/kernel/debug/tracing/instances/mm_events/per_cpu/cpu23/trace + chmod 0666 /sys/kernel/tracing/instances/mm_events/per_cpu/cpu23/trace on property:persist.debug.atrace.boottrace=1 start boottrace diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp index 74be7cedc7..95d9377a89 100644 --- a/cmds/installd/InstalldNativeService.cpp +++ b/cmds/installd/InstalldNativeService.cpp @@ -1748,7 +1748,18 @@ static void collectManualExternalStatsForUser(const std::string& path, struct st } fts_close(fts); } - +static bool ownsExternalStorage(int32_t appId) { + // Fetch external storage owner appid and check if it is the same as the + // current appId whose size is calculated + struct stat s; + auto _picDir = StringPrintf("%s/Pictures", create_data_media_path(nullptr, 0).c_str()); + // check if the stat are present + if (stat(_picDir.c_str(), &s) == 0) { + // fetch the appId from the uid of the media app + return ((int32_t)multiuser_get_app_id(s.st_uid) == appId); + } + return false; +} binder::Status InstalldNativeService::getAppSize(const std::optional<std::string>& uuid, const std::vector<std::string>& packageNames, int32_t userId, int32_t flags, int32_t appId, const std::vector<int64_t>& ceDataInodes, @@ -1803,8 +1814,10 @@ binder::Status InstalldNativeService::getAppSize(const std::optional<std::string calculate_tree_size(obbCodePath, &extStats.codeSize); } ATRACE_END(); - - if (flags & FLAG_USE_QUOTA && appId >= AID_APP_START) { + // Calculating the app size of the external storage owning app in a manual way, since + // calculating it through quota apis also includes external media storage in the app storage + // numbers + if (flags & FLAG_USE_QUOTA && appId >= AID_APP_START && !ownsExternalStorage(appId)) { ATRACE_BEGIN("code"); for (const auto& codePath : codePaths) { calculate_tree_size(codePath, &stats.codeSize, -1, diff --git a/cmds/installd/tests/Android.bp b/cmds/installd/tests/Android.bp index 70820172b7..024e3af9d3 100644 --- a/cmds/installd/tests/Android.bp +++ b/cmds/installd/tests/Android.bp @@ -13,7 +13,10 @@ cc_test { test_suites: ["device-tests"], clang: true, srcs: ["installd_utils_test.cpp"], - cflags: ["-Wall", "-Werror"], + cflags: [ + "-Wall", + "-Werror", + ], shared_libs: [ "libbase", "libutils", @@ -33,7 +36,10 @@ cc_test { test_suites: ["device-tests"], clang: true, srcs: ["installd_cache_test.cpp"], - cflags: ["-Wall", "-Werror"], + cflags: [ + "-Wall", + "-Werror", + ], shared_libs: [ "libbase", "libbinder", @@ -74,7 +80,10 @@ cc_test { test_suites: ["device-tests"], clang: true, srcs: ["installd_service_test.cpp"], - cflags: ["-Wall", "-Werror"], + cflags: [ + "-Wall", + "-Werror", + ], shared_libs: [ "libbase", "libbinder", @@ -115,7 +124,10 @@ cc_test { test_suites: ["device-tests"], clang: true, srcs: ["installd_dexopt_test.cpp"], - cflags: ["-Wall", "-Werror"], + cflags: [ + "-Wall", + "-Werror", + ], shared_libs: [ "libbase", "libbinder", @@ -158,7 +170,10 @@ cc_test { test_suites: ["device-tests"], clang: true, srcs: ["installd_otapreopt_test.cpp"], - cflags: ["-Wall", "-Werror"], + cflags: [ + "-Wall", + "-Werror", + ], shared_libs: [ "libbase", "libcutils", @@ -167,6 +182,6 @@ cc_test { ], static_libs: [ "liblog", - "libotapreoptparameters" + "libotapreoptparameters", ], } diff --git a/cmds/installd/tests/installd_service_test.cpp b/cmds/installd/tests/installd_service_test.cpp index 1e7559d174..36574974d9 100644 --- a/cmds/installd/tests/installd_service_test.cpp +++ b/cmds/installd/tests/installd_service_test.cpp @@ -18,10 +18,11 @@ #include <string> #include <fcntl.h> +#include <pwd.h> #include <stdlib.h> #include <string.h> -#include <sys/statvfs.h> #include <sys/stat.h> +#include <sys/statvfs.h> #include <sys/xattr.h> #include <android-base/file.h> @@ -32,8 +33,10 @@ #include <cutils/properties.h> #include <gtest/gtest.h> -#include "binder_test_utils.h" +#include <android/content/pm/IPackageManagerNative.h> +#include <binder/IServiceManager.h> #include "InstalldNativeService.h" +#include "binder_test_utils.h" #include "dexopt.h" #include "globals.h" #include "utils.h" @@ -41,6 +44,34 @@ using android::base::StringPrintf; namespace android { +std::string get_package_name(uid_t uid) { + sp<IServiceManager> sm = defaultServiceManager(); + sp<content::pm::IPackageManagerNative> package_mgr; + if (sm.get() == nullptr) { + LOG(INFO) << "Cannot find service manager"; + } else { + sp<IBinder> binder = sm->getService(String16("package_native")); + if (binder.get() == nullptr) { + LOG(INFO) << "Cannot find package_native"; + } else { + package_mgr = interface_cast<content::pm::IPackageManagerNative>(binder); + } + } + // find package name + std::string pkg; + if (package_mgr != nullptr) { + std::vector<std::string> names; + binder::Status status = package_mgr->getNamesForUids({(int)uid}, &names); + if (!status.isOk()) { + LOG(INFO) << "getNamesForUids failed: %s", status.exceptionMessage().c_str(); + } else { + if (!names[0].empty()) { + pkg = names[0].c_str(); + } + } + } + return pkg; +} namespace installd { constexpr const char* kTestUuid = "TEST"; @@ -247,7 +278,50 @@ TEST_F(ServiceTest, CalculateCache) { EXPECT_TRUE(create_cache_path(buf, "/path/to/file.apk", "isa")); EXPECT_EQ("/data/dalvik-cache/isa/path@to@file.apk@classes.dex", std::string(buf)); } - +TEST_F(ServiceTest, GetAppSize) { + struct stat s; + + std::string externalPicDir = + StringPrintf("%s/Pictures", create_data_media_path(nullptr, 0).c_str()); + if (stat(externalPicDir.c_str(), &s) == 0) { + // fetch the appId from the uid of the external storage owning app + int32_t externalStorageAppId = multiuser_get_app_id(s.st_uid); + // Fetch Package Name for the external storage owning app uid + std::string pkg = get_package_name(s.st_uid); + + std::vector<int64_t> externalStorageSize, externalStorageSizeAfterAddingExternalFile; + std::vector<int64_t> ceDataInodes; + + std::vector<std::string> codePaths; + std::vector<std::string> packageNames; + // set up parameters + packageNames.push_back(pkg); + ceDataInodes.push_back(0); + // initialise the mounts + service->invalidateMounts(); + // call the getAppSize to get the current size of the external storage owning app + service->getAppSize(std::nullopt, packageNames, 0, InstalldNativeService::FLAG_USE_QUOTA, + externalStorageAppId, ceDataInodes, codePaths, &externalStorageSize); + // add a file with 20MB size to the external storage + std::string externalFileLocation = + StringPrintf("%s/Pictures/%s", getenv("EXTERNAL_STORAGE"), "External.jpg"); + std::string externalFileContentCommand = + StringPrintf("dd if=/dev/zero of=%s bs=1M count=20", externalFileLocation.c_str()); + system(externalFileContentCommand.c_str()); + // call the getAppSize again to get the new size of the external storage owning app + service->getAppSize(std::nullopt, packageNames, 0, InstalldNativeService::FLAG_USE_QUOTA, + externalStorageAppId, ceDataInodes, codePaths, + &externalStorageSizeAfterAddingExternalFile); + // check that the size before adding the file and after should be the same, as the app size + // is not changed. + for (size_t i = 0; i < externalStorageSize.size(); i++) { + ASSERT_TRUE(externalStorageSize[i] == externalStorageSizeAfterAddingExternalFile[i]); + } + // remove the external file + std::string removeCommand = StringPrintf("rm -f %s", externalFileLocation.c_str()); + system(removeCommand.c_str()); + } +} static bool mkdirs(const std::string& path, mode_t mode) { struct stat sb; if (stat(path.c_str(), &sb) != -1 && S_ISDIR(sb.st_mode)) { 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 9d88ca64e6..c0cbad8d4f 100644 --- a/data/etc/Android.bp +++ b/data/etc/Android.bp @@ -14,3 +14,11 @@ prebuilt_etc { src: "android.hardware.biometrics.face.xml", filename_from_src: true, } + +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 6562348701..f50ff46fe2 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 { @@ -124,5 +123,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 dce6ccb3d5..4adaa5b1c5 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 e8ffc64535..c0f8aa0a28 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/include/input/KeyCharacterMap.h b/include/input/KeyCharacterMap.h index 451ca3c6cd..f6f8939b7a 100644 --- a/include/input/KeyCharacterMap.h +++ b/include/input/KeyCharacterMap.h @@ -84,7 +84,7 @@ public: const std::string getLoadFileName() const; - /* Combines this key character map with an overlay. */ + /* Combines this key character map with the provided overlay. */ void combine(const KeyCharacterMap& overlay); /* Gets the keyboard type. */ @@ -144,6 +144,8 @@ public: bool operator==(const KeyCharacterMap& other) const; + bool operator!=(const KeyCharacterMap& other) const; + KeyCharacterMap(const KeyCharacterMap& other); virtual ~KeyCharacterMap(); @@ -230,11 +232,12 @@ private: KeyedVector<int32_t, Key*> mKeys; KeyboardType mType; std::string mLoadFileName; + bool mLayoutOverlayApplied; KeyedVector<int32_t, int32_t> mKeysByScanCode; KeyedVector<int32_t, int32_t> mKeysByUsageCode; - KeyCharacterMap(); + KeyCharacterMap(const std::string& filename); bool getKey(int32_t keyCode, const Key** outKey) const; bool getKeyBehavior(int32_t keyCode, int32_t metaState, @@ -243,8 +246,6 @@ private: bool findKey(char16_t ch, int32_t* outKeyCode, int32_t* outMetaState) const; - static base::Result<std::shared_ptr<KeyCharacterMap>> load(Tokenizer* tokenizer, Format format); - static void addKey(Vector<KeyEvent>& outEvents, int32_t deviceId, int32_t keyCode, int32_t metaState, bool down, nsecs_t time); static void addMetaKeys(Vector<KeyEvent>& outEvents, @@ -264,6 +265,15 @@ private: int32_t deviceId, int32_t metaState, nsecs_t time, int32_t keyCode, int32_t keyMetaState, int32_t* currentMetaState); + + /* Clears all data stored in this key character map */ + void clear(); + + /* Loads the KeyCharacterMap provided by the tokenizer into this instance. */ + status_t load(Tokenizer* tokenizer, Format format); + + /* Reloads the data from mLoadFileName and unapplies any overlay. */ + status_t reloadBaseFromFile(); }; } // namespace android 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 f734582377..d97225910d 100644 --- a/libs/gui/Android.bp +++ b/libs/gui/Android.bp @@ -51,6 +51,60 @@ cc_library_headers { ], } +// AIDL files that should be exposed to java +filegroup { + name: "guiconstants_aidl", + srcs: [ + "android/**/DropInputMode.aidl", + "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,6 +131,10 @@ cc_library_static { "libbinder", ], + static_libs: [ + "libui-types", + ], + aidl: { export_aidl_headers: true } @@ -91,9 +149,11 @@ cc_defaults { static_libs: [ "libgui_aidl_static", + "libgui_window_info_static", ], export_static_lib_headers: [ "libgui_aidl_static", + "libgui_window_info_static", ], srcs: [ @@ -134,6 +194,7 @@ cc_defaults { "SyncFeatures.cpp", "TransactionTracing.cpp", "view/Surface.cpp", + "WindowInfosListenerReporter.cpp", "bufferqueue/1.0/B2HProducerListener.cpp", "bufferqueue/1.0/H2BGraphicBufferProducer.cpp", "bufferqueue/2.0/B2HProducerListener.cpp", @@ -145,13 +206,11 @@ cc_defaults { "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: [ @@ -163,7 +222,6 @@ cc_defaults { vendor: { cflags: [ "-DNO_BUFFERHUB", - "-DNO_INPUT", ], exclude_srcs: [ "BufferHubConsumer.cpp", @@ -173,7 +231,6 @@ cc_defaults { "android.frameworks.bufferhub@1.0", "libbufferhub", "libbufferhubqueue", - "libinput", "libpdx_default_transport", ], }, diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index 84a1a6c90a..242c378cfa 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -40,7 +40,7 @@ using namespace std::chrono_literals; namespace { -inline const char* toString(bool b) { +inline const char* boolToString(bool b) { return b ? "true" : "false"; } } // namespace @@ -48,6 +48,8 @@ inline const char* toString(bool b) { namespace android { // Macros to include adapter info in log messages +#define BQA_LOGD(x, ...) \ + ALOGD("[%s](f:%u,a:%u) " x, mName.c_str(), mNumFrameAvailable, mNumAcquired, ##__VA_ARGS__) #define BQA_LOGV(x, ...) \ ALOGV("[%s](f:%u,a:%u) " x, mName.c_str(), mNumFrameAvailable, mNumAcquired, ##__VA_ARGS__) // enable logs for a single layer @@ -119,25 +121,19 @@ void BLASTBufferItemConsumer::getConnectionEvents(uint64_t frameNumber, bool* ne if (needsDisconnect != nullptr) *needsDisconnect = disconnect; } -void BLASTBufferItemConsumer::setBlastBufferQueue(BLASTBufferQueue* blastbufferqueue) { - std::scoped_lock lock(mBufferQueueMutex); - mBLASTBufferQueue = blastbufferqueue; -} - void BLASTBufferItemConsumer::onSidebandStreamChanged() { - std::scoped_lock lock(mBufferQueueMutex); - if (mBLASTBufferQueue != nullptr) { + sp<BLASTBufferQueue> bbq = mBLASTBufferQueue.promote(); + if (bbq != nullptr) { sp<NativeHandle> stream = getSidebandStream(); - mBLASTBufferQueue->setSidebandStream(stream); + bbq->setSidebandStream(stream); } } -BLASTBufferQueue::BLASTBufferQueue(const std::string& name, const sp<SurfaceControl>& surface, - int width, int height, int32_t format) - : mSurfaceControl(surface), - mSize(width, height), +BLASTBufferQueue::BLASTBufferQueue(const std::string& name) + : mSurfaceControl(nullptr), + mSize(1, 1), mRequestedSize(mSize), - mFormat(format), + mFormat(PIXEL_FORMAT_RGBA_8888), mNextTransaction(nullptr) { createBufferQueue(&mProducer, &mConsumer); // since the adapter is in the client process, set dequeue timeout @@ -149,7 +145,7 @@ BLASTBufferQueue::BLASTBufferQueue(const std::string& name, const sp<SurfaceCont mBufferItemConsumer = new BLASTBufferItemConsumer(mConsumer, GraphicBuffer::USAGE_HW_COMPOSER | GraphicBuffer::USAGE_HW_TEXTURE, - 1, false); + 1, false, this); static int32_t id = 0; mName = name + "#" + std::to_string(id); auto consumerName = mName + "(BLAST Consumer)" + std::to_string(id); @@ -158,46 +154,21 @@ BLASTBufferQueue::BLASTBufferQueue(const std::string& name, const sp<SurfaceCont mBufferItemConsumer->setName(String8(consumerName.c_str())); mBufferItemConsumer->setFrameAvailableListener(this); mBufferItemConsumer->setBufferFreedListener(this); - mBufferItemConsumer->setDefaultBufferSize(mSize.width, mSize.height); - mBufferItemConsumer->setDefaultBufferFormat(convertBufferFormat(format)); - mBufferItemConsumer->setBlastBufferQueue(this); ComposerService::getComposerService()->getMaxAcquiredBufferCount(&mMaxAcquiredBuffers); mBufferItemConsumer->setMaxAcquiredBufferCount(mMaxAcquiredBuffers); - if(strstr(mName.c_str(),"ScreenDecorOverlay") != nullptr){ - sp<SurfaceComposerClient> client = mSurfaceControl->getClient(); - if (client != nullptr) { - const sp<IBinder> display = client->getInternalDisplayToken(); - if (display != nullptr) { - bool isDeviceRCSupported = false; - status_t err = client->isDeviceRCSupported(display, &isDeviceRCSupported); - if (!err && isDeviceRCSupported) { - // retain original flags and append SW Flags - uint64_t usage = GraphicBuffer::USAGE_HW_COMPOSER | - GraphicBuffer::USAGE_HW_TEXTURE | - GraphicBuffer::USAGE_SW_READ_RARELY | - GraphicBuffer::USAGE_SW_WRITE_RARELY; - mConsumer->setConsumerUsageBits(usage); - } - } - } - } - - mTransformHint = mSurfaceControl->getTransformHint(); - mBufferItemConsumer->setTransformHint(mTransformHint); - SurfaceComposerClient::Transaction() - .setFlags(surface, layer_state_t::eEnableBackpressure, - layer_state_t::eEnableBackpressure) - .setApplyToken(mApplyToken) - .apply(); mNumAcquired = 0; mNumFrameAvailable = 0; - BQA_LOGV("BLASTBufferQueue created width=%d height=%d format=%d mTransformHint=%d", width, - height, format, mTransformHint); + BQA_LOGV("BLASTBufferQueue created"); +} + +BLASTBufferQueue::BLASTBufferQueue(const std::string& name, const sp<SurfaceControl>& surface, + int width, int height, int32_t format) + : BLASTBufferQueue(name) { + update(surface, width, height, format); } BLASTBufferQueue::~BLASTBufferQueue() { - mBufferItemConsumer->setBlastBufferQueue(nullptr); if (mPendingTransactions.empty()) { return; } @@ -245,12 +216,9 @@ void BLASTBufferQueue::update(const sp<SurfaceControl>& surface, uint32_t width, // If the buffer supports scaling, update the frame immediately since the client may // want to scale the existing buffer to the new size. mSize = mRequestedSize; - // We only need to update the scale if we've received at least one buffer. The reason - // for this is the scale is calculated based on the requested size and buffer size. - // If there's no buffer, the scale will always be 1. SurfaceComposerClient::Transaction* destFrameTransaction = (outTransaction) ? outTransaction : &t; - if (mSurfaceControl != nullptr && mLastBufferInfo.hasBuffer) { + if (mSurfaceControl != nullptr) { destFrameTransaction->setDestinationFrame(mSurfaceControl, Rect(0, 0, newSize.getWidth(), newSize.getHeight())); @@ -261,6 +229,85 @@ void BLASTBufferQueue::update(const sp<SurfaceControl>& surface, uint32_t width, if (applyTransaction) { t.setApplyToken(mApplyToken).apply(); } + if(strstr(mName.c_str(),"ScreenDecorOverlay") != nullptr){ + sp<SurfaceComposerClient> client = mSurfaceControl->getClient(); + if (client != nullptr) { + const sp<IBinder> display = client->getInternalDisplayToken(); + if (display != nullptr) { + bool isDeviceRCSupported = false; + status_t err = client->isDeviceRCSupported(display, &isDeviceRCSupported); + if (!err && isDeviceRCSupported) { + // retain original flags and append SW Flags + uint64_t usage = GraphicBuffer::USAGE_HW_COMPOSER | + GraphicBuffer::USAGE_HW_TEXTURE | + GraphicBuffer::USAGE_SW_READ_RARELY | + GraphicBuffer::USAGE_SW_WRITE_RARELY; + mConsumer->setConsumerUsageBits(usage); + } + } + } + } +} + +static std::optional<SurfaceControlStats> findMatchingStat( + const std::vector<SurfaceControlStats>& stats, const sp<SurfaceControl>& sc) { + for (auto stat : stats) { + if (SurfaceControl::isSameSurface(sc, stat.surfaceControl)) { + return stat; + } + } + return std::nullopt; +} + +static void transactionCommittedCallbackThunk(void* context, nsecs_t latchTime, + const sp<Fence>& presentFence, + const std::vector<SurfaceControlStats>& stats) { + if (context == nullptr) { + return; + } + sp<BLASTBufferQueue> bq = static_cast<BLASTBufferQueue*>(context); + bq->transactionCommittedCallback(latchTime, presentFence, stats); +} + +void BLASTBufferQueue::transactionCommittedCallback(nsecs_t /*latchTime*/, + const sp<Fence>& /*presentFence*/, + const std::vector<SurfaceControlStats>& stats) { + { + std::unique_lock _lock{mMutex}; + ATRACE_CALL(); + BQA_LOGV("transactionCommittedCallback"); + if (!mSurfaceControlsWithPendingCallback.empty()) { + sp<SurfaceControl> pendingSC = mSurfaceControlsWithPendingCallback.front(); + std::optional<SurfaceControlStats> stat = findMatchingStat(stats, pendingSC); + if (stat) { + uint64_t currFrameNumber = stat->frameEventStats.frameNumber; + + // We need to check if we were waiting for a transaction callback in order to + // process any pending buffers and unblock. It's possible to get transaction + // callbacks for previous requests so we need to ensure the frame from this + // transaction callback matches the last acquired buffer. Since acquireNextBuffer + // will stop processing buffers when mWaitForTransactionCallback is set, we know + // that mLastAcquiredFrameNumber is the frame we're waiting on. + // We also want to check if mNextTransaction is null because it's possible another + // sync request came in while waiting, but it hasn't started processing yet. In that + // case, we don't actually want to flush the frames in between since they will get + // processed and merged with the sync transaction and released earlier than if they + // were sent to SF + if (mWaitForTransactionCallback && mNextTransaction == nullptr && + currFrameNumber >= mLastAcquiredFrameNumber) { + mWaitForTransactionCallback = false; + flushShadowQueueLocked(); + } + } else { + BQA_LOGE("Failed to find matching SurfaceControl in transactionCommittedCallback"); + } + } else { + BQA_LOGE("No matching SurfaceControls found: mSurfaceControlsWithPendingCallback was " + "empty."); + } + + decStrong((void*)transactionCommittedCallbackThunk); + } } static void transactionCallbackThunk(void* context, nsecs_t latchTime, @@ -286,12 +333,9 @@ void BLASTBufferQueue::transactionCallback(nsecs_t /*latchTime*/, const sp<Fence if (!mSurfaceControlsWithPendingCallback.empty()) { sp<SurfaceControl> pendingSC = mSurfaceControlsWithPendingCallback.front(); mSurfaceControlsWithPendingCallback.pop(); - bool found = false; - for (auto stat : stats) { - if (!SurfaceControl::isSameSurface(pendingSC, stat.surfaceControl)) { - continue; - } - + std::optional<SurfaceControlStats> statsOptional = findMatchingStat(stats, pendingSC); + if (statsOptional) { + SurfaceControlStats stat = *statsOptional; mTransformHint = stat.transformHint; mBufferItemConsumer->setTransformHint(mTransformHint); BQA_LOGV("updated mTransformHint=%d", mTransformHint); @@ -319,19 +363,25 @@ void BLASTBufferQueue::transactionCallback(nsecs_t /*latchTime*/, const sp<Fence transactionCompleteCallback = std::move(mTransactionCompleteCallback); mTransactionCompleteFrameNumber = 0; } - - found = true; - break; - } - - if (!found) { - BQA_LOGE("Failed to find matching SurfaceControl in transaction callback"); + std::vector<ReleaseCallbackId> staleReleases; + for (const auto& [key, value]: mSubmitted) { + if (currFrameNumber > key.framenumber) { + staleReleases.push_back(key); + } + } + for (const auto& staleRelease : staleReleases) { + releaseBufferCallbackLocked(staleRelease, stat.previousReleaseFence ? stat.previousReleaseFence : Fence::NO_FENCE, + stat.transformHint, stat.currentMaxAcquiredBufferCount); + } + } else { + BQA_LOGE("Failed to find matching SurfaceControl in transactionCallback"); } } else { BQA_LOGE("No matching SurfaceControls found: mSurfaceControlsWithPendingCallback was " "empty."); } + decStrong((void*)transactionCallbackThunk); } @@ -356,11 +406,31 @@ static void releaseBufferCallbackThunk(wp<BLASTBufferQueue> context, const Relea } } +void BLASTBufferQueue::flushShadowQueueLocked() { + BQA_LOGV("flushShadowQueueLocked"); + int numFramesToFlush = mNumFrameAvailable; + while (numFramesToFlush > 0) { + acquireNextBufferLocked(std::nullopt); + numFramesToFlush--; + } +} + +void BLASTBufferQueue::flushShadowQueue() { + std::unique_lock _lock{mMutex}; + flushShadowQueueLocked(); +} + void BLASTBufferQueue::releaseBufferCallback(const ReleaseCallbackId& id, const sp<Fence>& releaseFence, uint32_t transformHint, uint32_t currentMaxAcquiredBufferCount) { - ATRACE_CALL(); std::unique_lock _lock{mMutex}; + releaseBufferCallbackLocked(id, releaseFence, transformHint, currentMaxAcquiredBufferCount); +} + +void BLASTBufferQueue::releaseBufferCallbackLocked(const ReleaseCallbackId& id, + const sp<Fence>& releaseFence, uint32_t transformHint, + uint32_t currentMaxAcquiredBufferCount) { + ATRACE_CALL(); BQA_LOGV("releaseBufferCallback %s", id.to_string().c_str()); if (mSurfaceControl != nullptr) { @@ -381,7 +451,10 @@ void BLASTBufferQueue::releaseBufferCallback(const ReleaseCallbackId& id, const auto numPendingBuffersToHold = isEGL ? std::max(0u, mMaxAcquiredBuffers - currentMaxAcquiredBufferCount) : 0; - mPendingRelease.emplace_back(ReleasedBuffer{id, releaseFence}); + auto rb = ReleasedBuffer{id, releaseFence}; + if (std::find(mPendingRelease.begin(), mPendingRelease.end(), rb) == mPendingRelease.end()) { + mPendingRelease.emplace_back(rb); + } // Release all buffers that are beyond the ones that we need to hold while (mPendingRelease.size() > numPendingBuffersToHold) { @@ -398,7 +471,11 @@ void BLASTBufferQueue::releaseBufferCallback(const ReleaseCallbackId& id, mBufferItemConsumer->releaseBuffer(it->second, releaseBuffer.releaseFence); mSubmitted.erase(it); mNumUndequeued++; - processNextBufferLocked(false /* useNextTransaction */); + // Don't process the transactions here if mWaitForTransactionCallback is set. Instead, let + // onFrameAvailable handle processing them since it will merge with the nextTransaction. + if (!mWaitForTransactionCallback) { + acquireNextBufferLocked(std::nullopt); + } } ATRACE_INT("PendingRelease", mPendingRelease.size()); @@ -407,13 +484,15 @@ void BLASTBufferQueue::releaseBufferCallback(const ReleaseCallbackId& id, mCallbackCV.notify_all(); } -void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) { +void BLASTBufferQueue::acquireNextBufferLocked( + const std::optional<SurfaceComposerClient::Transaction*> transaction) { ATRACE_CALL(); // If the next transaction is set, we want to guarantee the our acquire will not fail, so don't // include the extra buffer when checking if we can acquire the next buffer. - const bool includeExtraAcquire = !useNextTransaction; - if (mNumFrameAvailable == 0 || maxBuffersAcquired(includeExtraAcquire)) { - mCallbackCV.notify_all(); + const bool includeExtraAcquire = !transaction; + const bool maxAcquired = maxBuffersAcquired(includeExtraAcquire); + if (mNumFrameAvailable == 0 || maxAcquired) { + BQA_LOGV("Can't process next buffer maxBuffersAcquired=%s", boolToString(maxAcquired)); return; } @@ -425,9 +504,8 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) { SurfaceComposerClient::Transaction localTransaction; bool applyTransaction = true; SurfaceComposerClient::Transaction* t = &localTransaction; - if (mNextTransaction != nullptr && useNextTransaction) { - t = mNextTransaction; - mNextTransaction = nullptr; + if (transaction) { + t = *transaction; applyTransaction = false; } @@ -457,7 +535,7 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) { mSize.width, mSize.height, mRequestedSize.width, mRequestedSize.height, buffer->getWidth(), buffer->getHeight(), bufferItem.mTransform); mBufferItemConsumer->releaseBuffer(bufferItem, Fence::NO_FENCE); - processNextBufferLocked(useNextTransaction); + acquireNextBufferLocked(transaction); return; } @@ -477,10 +555,9 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) { // Ensure BLASTBufferQueue stays alive until we receive the transaction complete callback. incStrong((void*)transactionCallbackThunk); + const bool updateDestinationFrame = mRequestedSize != mSize; + mSize = mRequestedSize; Rect crop = computeCrop(bufferItem); - const bool updateDestinationFrame = - bufferItem.mScalingMode == NATIVE_WINDOW_SCALING_MODE_FREEZE || - !mLastBufferInfo.hasBuffer; mLastBufferInfo.update(true /* hasBuffer */, bufferItem.mGraphicBuffer->getWidth(), bufferItem.mGraphicBuffer->getHeight(), bufferItem.mTransform, bufferItem.mScalingMode, crop); @@ -496,6 +573,7 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) { t->setAcquireFence(mSurfaceControl, bufferItem.mFence ? new Fence(bufferItem.mFence->dup()) : Fence::NO_FENCE); t->addTransactionCompletedCallback(transactionCallbackThunk, static_cast<void*>(this)); + mSurfaceControlsWithPendingCallback.push(mSurfaceControl); if (updateDestinationFrame) { @@ -548,10 +626,10 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) { t->setApplyToken(mApplyToken).apply(); } - BQA_LOGV("processNextBufferLocked size=%dx%d mFrameNumber=%" PRIu64 + BQA_LOGV("acquireNextBufferLocked 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); @@ -564,25 +642,75 @@ Rect BLASTBufferQueue::computeCrop(const BufferItem& item) { return item.mCrop; } +void BLASTBufferQueue::acquireAndReleaseBuffer() { + BufferItem bufferItem; + status_t status = + mBufferItemConsumer->acquireBuffer(&bufferItem, 0 /* expectedPresent */, false); + if (status != OK) { + BQA_LOGE("Failed to acquire a buffer in acquireAndReleaseBuffer, err=%s", + statusToString(status).c_str()); + return; + } + mNumFrameAvailable--; + mBufferItemConsumer->releaseBuffer(bufferItem, bufferItem.mFence); +} + void BLASTBufferQueue::onFrameAvailable(const BufferItem& item) { ATRACE_CALL(); std::unique_lock _lock{mMutex}; const bool nextTransactionSet = mNextTransaction != nullptr; + BQA_LOGV("onFrameAvailable-start nextTransactionSet=%s", boolToString(nextTransactionSet)); if (nextTransactionSet) { - while (mNumFrameAvailable > 0 || maxBuffersAcquired(false /* includeExtraAcquire */)) { - BQA_LOGV("waiting in onFrameAvailable..."); + if (mWaitForTransactionCallback) { + // We are waiting on a previous sync's transaction callback so allow another sync + // transaction to proceed. + // + // We need to first flush out the transactions that were in between the two syncs. + // We do this by merging them into mNextTransaction so any buffer merging will get + // a release callback invoked. The release callback will be async so we need to wait + // on max acquired to make sure we have the capacity to acquire another buffer. + if (maxBuffersAcquired(false /* includeExtraAcquire */)) { + BQA_LOGD("waiting to flush shadow queue..."); + mCallbackCV.wait(_lock); + } + while (mNumFrameAvailable > 0) { + // flush out the shadow queue + acquireAndReleaseBuffer(); + } + } + + while (maxBuffersAcquired(false /* includeExtraAcquire */)) { + BQA_LOGD("waiting for free buffer."); mCallbackCV.wait(_lock); } } + // add to shadow queue mNumFrameAvailable++; + if (mWaitForTransactionCallback && mNumFrameAvailable == 2) { + acquireAndReleaseBuffer(); + } ATRACE_INT(mQueuedBufferTrace.c_str(), mNumFrameAvailable + mNumAcquired - mPendingRelease.size()); BQA_LOGV("onFrameAvailable framenumber=%" PRIu64 " nextTransactionSet=%s", item.mFrameNumber, - toString(nextTransactionSet)); - processNextBufferLocked(nextTransactionSet /* useNextTransaction */); + boolToString(nextTransactionSet)); + + if (nextTransactionSet) { + acquireNextBufferLocked(std::move(mNextTransaction)); + + // Only need a commit callback when syncing to ensure the buffer that's synced has been sent + // to SF + incStrong((void*)transactionCommittedCallbackThunk); + mNextTransaction->addTransactionCommittedCallback(transactionCommittedCallbackThunk, + static_cast<void*>(this)); + + mNextTransaction = nullptr; + mWaitForTransactionCallback = true; + } else if (!mWaitForTransactionCallback) { + acquireNextBufferLocked(std::nullopt); + } } void BLASTBufferQueue::onFrameReplaced(const BufferItem& item) { @@ -608,7 +736,6 @@ void BLASTBufferQueue::setNextTransaction(SurfaceComposerClient::Transaction* t) bool BLASTBufferQueue::rejectBuffer(const BufferItem& item) { if (item.mScalingMode != NATIVE_WINDOW_SCALING_MODE_FREEZE) { - mSize = mRequestedSize; // Only reject buffers if scaling mode is freeze. return false; } @@ -622,7 +749,6 @@ bool BLASTBufferQueue::rejectBuffer(const BufferItem& item) { } ui::Size bufferSize(bufWidth, bufHeight); if (mRequestedSize != mSize && mRequestedSize == bufferSize) { - mSize = mRequestedSize; return false; } @@ -760,14 +886,26 @@ private: std::unique_lock<std::mutex> lock(mMutex); while (!mDone) { while (!mRunnables.empty()) { - std::function<void()> runnable = mRunnables.front(); - mRunnables.pop_front(); - runnable(); + std::deque<std::function<void()>> runnables = std::move(mRunnables); + mRunnables.clear(); + lock.unlock(); + // Run outside the lock since the runnable might trigger another + // post to the async worker. + execute(runnables); + lock.lock(); } mCv.wait(lock); } } + void execute(std::deque<std::function<void()>>& runnables) { + while (!runnables.empty()) { + std::function<void()> runnable = runnables.front(); + runnables.pop_front(); + runnable(); + } + } + public: AsyncWorker() : Singleton<AsyncWorker>() { mThread = std::thread(&AsyncWorker::run, this); } @@ -878,4 +1016,9 @@ uint32_t BLASTBufferQueue::getLastTransformHint() const { } } +uint64_t BLASTBufferQueue::getLastAcquiredFrameNum() { + std::unique_lock _lock{mMutex}; + return mLastAcquiredFrameNumber; +} + } // namespace android 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 01d7abd376..9ce64e7111 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> @@ -291,6 +292,17 @@ public: return {}; } + status_t getPrimaryPhysicalDisplayId(PhysicalDisplayId* displayId) const override { + Parcel data, reply; + SAFE_PARCEL(data.writeInterfaceToken, ISurfaceComposer::getInterfaceDescriptor()); + SAFE_PARCEL(remote()->transact, BnSurfaceComposer::GET_PRIMARY_PHYSICAL_DISPLAY_ID, data, + &reply); + uint64_t rawId; + SAFE_PARCEL(reply.readUint64, &rawId); + *displayId = PhysicalDisplayId(rawId); + return NO_ERROR; + } + sp<IBinder> getPhysicalDisplayToken(PhysicalDisplayId displayId) const override { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); @@ -1246,6 +1258,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 @@ -1746,6 +1774,16 @@ status_t BnSurfaceComposer::onTransact( [](PhysicalDisplayId id) { return id.value; }); return reply->writeUint64Vector(rawIds); } + case GET_PRIMARY_PHYSICAL_DISPLAY_ID: { + CHECK_INTERFACE(ISurfaceComposer, data, reply); + PhysicalDisplayId id; + status_t result = getPrimaryPhysicalDisplayId(&id); + if (result != NO_ERROR) { + ALOGE("getPrimaryPhysicalDisplayId: Failed to get id"); + return result; + } + return reply->writeUint64(id.value); + } case ADD_REGION_SAMPLING_LISTENER: { CHECK_INTERFACE(ISurfaceComposer, data, reply); Rect samplingArea; @@ -2140,6 +2178,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..77a883b332 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), @@ -67,7 +70,8 @@ layer_state_t::layer_state_t() isTrustedOverlay(false), bufferCrop(Rect::INVALID_RECT), destinationFrame(Rect::INVALID_RECT), - releaseBufferListener(nullptr) { + releaseBufferListener(nullptr), + dropInputMode(gui::DropInputMode::NONE) { matrix.dsdx = matrix.dtdy = 1.0f; matrix.dsdy = matrix.dtdx = 0.0f; hdrMetadata.validTypes = 0; @@ -95,9 +99,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 +175,8 @@ status_t layer_state_t::write(Parcel& output) const SAFE_PARCEL(output.write, destinationFrame); SAFE_PARCEL(output.writeBool, isTrustedOverlay); + SAFE_PARCEL(output.writeStrongBinder, releaseBufferEndpoint); + SAFE_PARCEL(output.writeUint32, static_cast<uint32_t>(dropInputMode)); return NO_ERROR; } @@ -207,9 +211,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 +306,11 @@ status_t layer_state_t::read(const Parcel& input) SAFE_PARCEL(input.read, destinationFrame); SAFE_PARCEL(input.readBool, &isTrustedOverlay); + SAFE_PARCEL(input.readNullableStrongBinder, &releaseBufferEndpoint); + + uint32_t mode; + SAFE_PARCEL(input.readUint32, &mode); + dropInputMode = static_cast<gui::DropInputMode>(mode); return NO_ERROR; } @@ -318,6 +325,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 +336,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 +353,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 +374,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 +469,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,17 +502,14 @@ 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; + releaseBufferEndpoint = other.releaseBufferEndpoint; } if (other.what & eBackgroundColorChanged) { what |= eBackgroundColorChanged; @@ -558,6 +570,14 @@ void layer_state_t::merge(const layer_state_t& other) { what |= eDestinationFrameChanged; destinationFrame = other.destinationFrame; } + if (other.what & eDropInputModeChanged) { + what |= eDropInputModeChanged; + dropInputMode = other.dropInputMode; + } + if (other.what & eColorChanged) { + what |= eColorChanged; + color = other.color; + } if ((other.what & what) != other.what) { ALOGE("Unmerged SurfaceComposer Transaction properties. LayerState::merge needs updating? " "other.what=0x%" PRIu64 " what=0x%" PRIu64, @@ -593,11 +613,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 +623,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 adcd1bf27b..7a75d2d339 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); @@ -285,7 +296,7 @@ void TransactionCompletedListener::onTransactionCompleted(ListenerStats listener transactionStats.latchTime, surfaceStats.acquireTime, transactionStats.presentFence, surfaceStats.previousReleaseFence, surfaceStats.transformHint, - surfaceStats.eventStats); + surfaceStats.eventStats, surfaceStats.currentMaxAcquiredBufferCount); } callbackFunction(transactionStats.latchTime, transactionStats.presentFence, @@ -310,7 +321,7 @@ void TransactionCompletedListener::onTransactionCompleted(ListenerStats listener transactionStats.latchTime, surfaceStats.acquireTime, transactionStats.presentFence, surfaceStats.previousReleaseFence, surfaceStats.transformHint, - surfaceStats.eventStats); + surfaceStats.eventStats, surfaceStats.currentMaxAcquiredBufferCount); if (callbacksMap[callbackId].surfaceControls[surfaceStats.surfaceControl]) { callbacksMap[callbackId] .surfaceControls[surfaceStats.surfaceControl] @@ -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); } @@ -913,6 +937,10 @@ std::vector<PhysicalDisplayId> SurfaceComposerClient::getPhysicalDisplayIds() { return ComposerService::getComposerService()->getPhysicalDisplayIds(); } +status_t SurfaceComposerClient::getPrimaryPhysicalDisplayId(PhysicalDisplayId* id) { + return ComposerService::getComposerService()->getPrimaryPhysicalDisplayId(id); +} + std::optional<PhysicalDisplayId> SurfaceComposerClient::getInternalDisplayId() { return ComposerService::getComposerService()->getInternalDisplayId(); } @@ -1271,6 +1299,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 +1520,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 +1543,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); @@ -1718,6 +1743,21 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setDesti return *this; } +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setDropInputMode( + const sp<SurfaceControl>& sc, gui::DropInputMode mode) { + layer_state_t* s = getLayerState(sc); + if (!s) { + mStatus = BAD_INDEX; + return *this; + } + + s->what |= layer_state_t::eDropInputModeChanged; + s->dropInputMode = mode; + + registerSurfaceControlForCallback(sc); + return *this; +} + // --------------------------------------------------------------------------- DisplayState& SurfaceComposerClient::Transaction::getDisplayState(const sp<IBinder>& token) { @@ -1758,6 +1798,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 +1825,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()); @@ -2159,6 +2200,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/gui/android/gui/DropInputMode.aidl b/libs/gui/android/gui/DropInputMode.aidl new file mode 100644 index 0000000000..2b31744ca2 --- /dev/null +++ b/libs/gui/android/gui/DropInputMode.aidl @@ -0,0 +1,45 @@ +/** + * 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. + */ + +package android.gui; + + +/** + * Input event drop modes: Input event drop options for windows and its children. + * + * @hide + */ +@Backing(type="int") +enum DropInputMode { + /** + * Default mode, input events are sent to the target as usual. + */ + NONE, + + /** + * Window and its children will not receive any input even if it has a valid input channel. + * Touches and keys will be dropped. If a window is focused, it will remain focused but will + * not receive any keys. If the window has a touchable region and is the target of an input + * event, the event will be dropped and will not go to the window behind. ref: b/197296414 + */ + ALL, + + /** + * Similar to DROP but input events are only dropped if the window is considered to be + * obscured. ref: b/197364677 + */ + OBSCURED +} 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/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h index baf028150a..46cb764c3c 100644 --- a/libs/gui/include/gui/BLASTBufferQueue.h +++ b/libs/gui/include/gui/BLASTBufferQueue.h @@ -38,11 +38,11 @@ class BufferItemConsumer; class BLASTBufferItemConsumer : public BufferItemConsumer { public: BLASTBufferItemConsumer(const sp<IGraphicBufferConsumer>& consumer, uint64_t consumerUsage, - int bufferCount, bool controlledByApp) + int bufferCount, bool controlledByApp, wp<BLASTBufferQueue> bbq) : BufferItemConsumer(consumer, consumerUsage, bufferCount, controlledByApp), + mBLASTBufferQueue(std::move(bbq)), mCurrentlyConnected(false), - mPreviouslyConnected(false), - mBLASTBufferQueue(nullptr) {} + mPreviouslyConnected(false) {} void onDisconnect() override; void addAndGetFrameTimestamps(const NewFrameEventsEntry* newTimestamps, @@ -53,27 +53,27 @@ public: CompositorTiming compositorTiming, nsecs_t latchTime, nsecs_t dequeueReadyTime) REQUIRES(mMutex); void getConnectionEvents(uint64_t frameNumber, bool* needsDisconnect); - void setBlastBufferQueue(BLASTBufferQueue* blastbufferqueue) REQUIRES(mMutex); protected: void onSidebandStreamChanged() override REQUIRES(mMutex); private: + const wp<BLASTBufferQueue> mBLASTBufferQueue; + uint64_t mCurrentFrameNumber = 0; Mutex mMutex; - std::mutex mBufferQueueMutex; ConsumerFrameEventHistory mFrameEventHistory GUARDED_BY(mMutex); std::queue<uint64_t> mDisconnectEvents GUARDED_BY(mMutex); bool mCurrentlyConnected GUARDED_BY(mMutex); bool mPreviouslyConnected GUARDED_BY(mMutex); - BLASTBufferQueue* mBLASTBufferQueue GUARDED_BY(mBufferQueueMutex); }; class BLASTBufferQueue : public ConsumerBase::FrameAvailableListener, public BufferItemConsumer::BufferFreedListener { public: + BLASTBufferQueue(const std::string& name); BLASTBufferQueue(const std::string& name, const sp<SurfaceControl>& surface, int width, int height, int32_t format); @@ -95,10 +95,14 @@ public: void onFrameDequeued(const uint64_t) override; void onFrameCancelled(const uint64_t) override; + void transactionCommittedCallback(nsecs_t latchTime, const sp<Fence>& presentFence, + const std::vector<SurfaceControlStats>& stats); void transactionCallback(nsecs_t latchTime, const sp<Fence>& presentFence, const std::vector<SurfaceControlStats>& stats); void releaseBufferCallback(const ReleaseCallbackId& id, const sp<Fence>& releaseFence, uint32_t transformHint, uint32_t currentMaxAcquiredBufferCount); + void releaseBufferCallbackLocked(const ReleaseCallbackId& id, const sp<Fence>& releaseFence, + uint32_t transformHint, uint32_t currentMaxAcquiredBufferCount); void setNextTransaction(SurfaceComposerClient::Transaction *t); void mergeWithNextTransaction(SurfaceComposerClient::Transaction* t, uint64_t frameNumber); void setTransactionCompleteCallback(uint64_t frameNumber, @@ -106,7 +110,6 @@ public: void update(const sp<SurfaceControl>& surface, uint32_t width, uint32_t height, int32_t format, SurfaceComposerClient::Transaction* outTransaction = nullptr); - void flushShadowQueue() {} status_t setFrameRate(float frameRate, int8_t compatibility, bool shouldBeSeamless); status_t setFrameTimelineInfo(const FrameTimelineInfo& info); @@ -114,6 +117,9 @@ public: void setSidebandStream(const sp<NativeHandle>& stream); uint32_t getLastTransformHint() const; + void flushShadowQueue(); + + uint64_t getLastAcquiredFrameNum(); virtual ~BLASTBufferQueue(); @@ -126,13 +132,17 @@ private: void createBufferQueue(sp<IGraphicBufferProducer>* outProducer, sp<IGraphicBufferConsumer>* outConsumer); - void processNextBufferLocked(bool useNextTransaction) REQUIRES(mMutex); + void acquireNextBufferLocked( + const std::optional<SurfaceComposerClient::Transaction*> transaction) REQUIRES(mMutex); Rect computeCrop(const BufferItem& item) REQUIRES(mMutex); // Return true if we need to reject the buffer based on the scaling mode and the buffer size. bool rejectBuffer(const BufferItem& item) REQUIRES(mMutex); bool maxBuffersAcquired(bool includeExtraAcquire) const REQUIRES(mMutex); static PixelFormat convertBufferFormat(PixelFormat& format); + void flushShadowQueueLocked() REQUIRES(mMutex); + void acquireAndReleaseBuffer() REQUIRES(mMutex); + std::string mName; // Represents the queued buffer count from buffer queue, // pre-BLAST. This is mNumFrameAvailable (buffers that queued to blast) + @@ -163,6 +173,12 @@ private: struct ReleasedBuffer { ReleaseCallbackId callbackId; sp<Fence> releaseFence; + bool operator==(const ReleasedBuffer& rhs) const { + // Only compare Id so if we somehow got two callbacks + // with different fences we don't decrement mNumAcquired + // too far. + return rhs.callbackId == callbackId; + } }; std::deque<ReleasedBuffer> mPendingRelease GUARDED_BY(mMutex); @@ -241,6 +257,9 @@ private: // Keep track of SurfaceControls that have submitted a transaction and BBQ is waiting on a // callback for them. std::queue<sp<SurfaceControl>> mSurfaceControlsWithPendingCallback GUARDED_BY(mMutex); + + uint32_t mCurrentMaxAcquiredBufferCount; + bool mWaitForTransactionCallback = false; }; } // namespace android diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index c7034ecab2..766e6f08a8 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> @@ -140,6 +141,8 @@ public: */ virtual std::vector<PhysicalDisplayId> getPhysicalDisplayIds() const = 0; + virtual status_t getPrimaryPhysicalDisplayId(PhysicalDisplayId*) const = 0; + // TODO(b/74619554): Remove this stopgap once the framework is display-agnostic. std::optional<PhysicalDisplayId> getInternalDisplayId() const { const auto displayIds = getPhysicalDisplayIds(); @@ -558,6 +561,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; }; // ---------------------------------------------------------------------------- @@ -631,6 +639,9 @@ public: ON_PULL_ATOM, ADD_TUNNEL_MODE_ENABLED_LISTENER, REMOVE_TUNNEL_MODE_ENABLED_LISTENER, + ADD_WINDOW_INFOS_LISTENER, + REMOVE_WINDOW_INFOS_LISTENER, + GET_PRIMARY_PHYSICAL_DISPLAY_ID, // 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..03e4aacdbe 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -26,14 +26,13 @@ #include <gui/ITransactionCompletedListener.h> #include <math/mat4.h> -#ifndef NO_INPUT -#include <android/FocusRequest.h> -#include <input/InputWindow.h> -#endif +#include <android/gui/DropInputMode.h> +#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> @@ -119,6 +118,7 @@ struct layer_state_t { eAutoRefreshChanged = 0x1000'00000000, eStretchChanged = 0x2000'00000000, eTrustedOverlayChanged = 0x4000'00000000, + eDropInputModeChanged = 0x8000'00000000, }; layer_state_t(); @@ -178,9 +178,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 +244,14 @@ 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; + + // Force inputflinger to drop all input events for the layer and its children. + gui::DropInputMode dropInputMode; }; struct ComposerState { @@ -259,7 +265,8 @@ struct DisplayState { eSurfaceChanged = 0x01, eLayerStackChanged = 0x02, eDisplayProjectionChanged = 0x04, - eDisplaySizeChanged = 0x08 + eDisplaySizeChanged = 0x08, + eFlagsChanged = 0x10 }; DisplayState(); @@ -269,6 +276,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 +300,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 ea07eba2bb..8969d52a41 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 { @@ -56,14 +57,15 @@ class Region; struct SurfaceControlStats { SurfaceControlStats(const sp<SurfaceControl>& sc, nsecs_t latchTime, nsecs_t acquireTime, const sp<Fence>& presentFence, const sp<Fence>& prevReleaseFence, - uint32_t hint, FrameEventHistoryStats eventStats) + uint32_t hint, FrameEventHistoryStats eventStats, uint32_t currentMaxAcquiredBufferCount) : surfaceControl(sc), latchTime(latchTime), acquireTime(acquireTime), presentFence(presentFence), previousReleaseFence(prevReleaseFence), transformHint(hint), - frameEventStats(eventStats) {} + frameEventStats(eventStats), + currentMaxAcquiredBufferCount(currentMaxAcquiredBufferCount) {} sp<SurfaceControl> surfaceControl; nsecs_t latchTime = -1; @@ -72,6 +74,7 @@ struct SurfaceControlStats { sp<Fence> previousReleaseFence; uint32_t transformHint = 0; FrameEventHistoryStats frameEventStats; + uint32_t currentMaxAcquiredBufferCount = 0; }; using TransactionCompletedCallbackTakesContext = @@ -310,6 +313,7 @@ public: //! Get stable IDs for connected physical displays static std::vector<PhysicalDisplayId> getPhysicalDisplayIds(); + static status_t getPrimaryPhysicalDisplayId(PhysicalDisplayId*); static std::optional<PhysicalDisplayId> getInternalDisplayId(); //! Get token for a physical display given its stable ID @@ -505,11 +509,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, @@ -566,12 +568,15 @@ public: Transaction& setBufferCrop(const sp<SurfaceControl>& sc, const Rect& bufferCrop); Transaction& setDestinationFrame(const sp<SurfaceControl>& sc, const Rect& destinationFrame); + Transaction& setDropInputMode(const sp<SurfaceControl>& sc, gui::DropInputMode mode); status_t setDisplaySurface(const sp<IBinder>& token, const sp<IGraphicBufferProducer>& bufferProducer); 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. * @@ -625,6 +630,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(); @@ -654,8 +662,10 @@ public: }; class TransactionCompletedListener : public BnTransactionCompletedListener { +public: TransactionCompletedListener(); +protected: int64_t getNextIdLocked() REQUIRES(mMutex); std::mutex mMutex; @@ -685,13 +695,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(); @@ -733,8 +743,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..4727740ab5 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 { @@ -125,9 +121,11 @@ struct InputWindowInfo : public Parcelable { }; enum class Feature { - DISABLE_TOUCH_PAD_GESTURES = 0x00000001, - NO_INPUT_CHANNEL = 0x00000002, - DISABLE_USER_ACTIVITY = 0x00000004, + DISABLE_TOUCH_PAD_GESTURES = 1u << 0, + NO_INPUT_CHANNEL = 1u << 1, + DISABLE_USER_ACTIVITY = 1u << 2, + DROP_INPUT = 1u << 3, + DROP_INPUT_IF_OBSCURED = 1u << 4, }; /* These values are filled in by the WM and passed through SurfaceFlinger @@ -136,6 +134,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 +170,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 +211,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 +226,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 +248,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 +263,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/services/surfaceflinger/tests/utils/CallbackUtils.h b/libs/gui/include/gui/test/CallbackUtils.h index 459b35c544..d2e04268dc 100644 --- a/services/surfaceflinger/tests/utils/CallbackUtils.h +++ b/libs/gui/include/gui/test/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 { @@ -130,10 +134,8 @@ private: void verifySurfaceControlStats(const SurfaceControlStats& surfaceControlStats, nsecs_t latchTime) const { - const auto& - [surfaceControl, latch, acquireTime, presentFence, previousReleaseFence, - transformHint, - frameEvents] = surfaceControlStats; + const auto& [surfaceControl, latch, acquireTime, presentFence, previousReleaseFence, + transformHint, frameEvents, ignore] = surfaceControlStats; ASSERT_EQ(acquireTime > 0, mBufferResult == ExpectedResult::Buffer::ACQUIRED) << "bad acquire time"; @@ -195,7 +197,7 @@ public: std::this_thread::sleep_for(500ms); std::lock_guard lock(mMutex); - EXPECT_EQ(mCallbackDataQueue.size(), 0) << "extra callbacks received"; + EXPECT_EQ(mCallbackDataQueue.size(), 0U) << "extra callbacks received"; mCallbackDataQueue = {}; } @@ -205,5 +207,5 @@ public: std::condition_variable mConditionVariable; std::queue<CallbackData> mCallbackDataQueue; }; -} +} // namespace } // namespace android 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/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp index 9082d275a2..fc7548511d 100644 --- a/libs/gui/tests/BLASTBufferQueue_test.cpp +++ b/libs/gui/tests/BLASTBufferQueue_test.cpp @@ -27,6 +27,7 @@ #include <gui/Surface.h> #include <gui/SurfaceComposerClient.h> #include <gui/SyncScreenCaptureListener.h> +#include <gui/test/CallbackUtils.h> #include <private/gui/ComposerService.h> #include <ui/DisplayMode.h> #include <ui/GraphicBuffer.h> @@ -42,6 +43,29 @@ namespace android { using Transaction = SurfaceComposerClient::Transaction; using android::hardware::graphics::common::V1_2::BufferUsage; +class CountProducerListener : public BnProducerListener { +public: + void onBufferReleased() override { + std::scoped_lock<std::mutex> lock(mMutex); + mNumReleased++; + mReleaseCallback.notify_one(); + } + + void waitOnNumberReleased(int32_t expectedNumReleased) { + std::unique_lock<std::mutex> lock(mMutex); + while (mNumReleased < expectedNumReleased) { + ASSERT_NE(mReleaseCallback.wait_for(lock, std::chrono::seconds(3)), + std::cv_status::timeout) + << "did not receive release"; + } + } + +private: + std::mutex mMutex; + std::condition_variable mReleaseCallback; + int32_t mNumReleased GUARDED_BY(mMutex) = 0; +}; + class BLASTBufferQueueHelper { public: BLASTBufferQueueHelper(const sp<SurfaceControl>& sc, int width, int height) { @@ -152,18 +176,19 @@ protected: mCaptureArgs.dataspace = ui::Dataspace::V0_SRGB; } - void setUpProducer(BLASTBufferQueueHelper& adapter, sp<IGraphicBufferProducer>& producer) { + void setUpProducer(BLASTBufferQueueHelper& adapter, sp<IGraphicBufferProducer>& producer, + int32_t maxBufferCount = 2) { producer = adapter.getIGraphicBufferProducer(); - setUpProducer(producer); + setUpProducer(producer, maxBufferCount); } - void setUpProducer(sp<IGraphicBufferProducer>& igbProducer) { + void setUpProducer(sp<IGraphicBufferProducer>& igbProducer, int32_t maxBufferCount) { ASSERT_NE(nullptr, igbProducer.get()); - ASSERT_EQ(NO_ERROR, igbProducer->setMaxDequeuedBufferCount(2)); + ASSERT_EQ(NO_ERROR, igbProducer->setMaxDequeuedBufferCount(maxBufferCount)); IGraphicBufferProducer::QueueBufferOutput qbOutput; + mProducerListener = new CountProducerListener(); ASSERT_EQ(NO_ERROR, - igbProducer->connect(new StubProducerListener, NATIVE_WINDOW_API_CPU, false, - &qbOutput)); + igbProducer->connect(mProducerListener, NATIVE_WINDOW_API_CPU, false, &qbOutput)); ASSERT_NE(ui::Transform::ROT_INVALID, qbOutput.transformHint); } @@ -287,6 +312,7 @@ protected: DisplayCaptureArgs mCaptureArgs; ScreenCaptureResults mCaptureResults; + sp<CountProducerListener> mProducerListener; }; TEST_F(BLASTBufferQueueTest, CreateBLASTBufferQueue) { @@ -672,6 +698,317 @@ TEST_F(BLASTBufferQueueTest, ScaleCroppedBufferToWindowSize) { /*border*/ 0, /*outsideRegion*/ true)); } +// b/196339769 verify we can can update the requested size while the in FREEZE scaling mode and +// scale the buffer properly when the mode changes to SCALE_TO_WINDOW +TEST_F(BLASTBufferQueueTest, ScalingModeChanges) { + uint8_t r = 255; + uint8_t g = 0; + uint8_t b = 0; + + BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight / 4); + sp<IGraphicBufferProducer> igbProducer; + setUpProducer(adapter, igbProducer); + { + int slot; + sp<Fence> fence; + sp<GraphicBuffer> buf; + auto ret = igbProducer->dequeueBuffer(&slot, &fence, mDisplayWidth, mDisplayHeight / 4, + PIXEL_FORMAT_RGBA_8888, GRALLOC_USAGE_SW_WRITE_OFTEN, + nullptr, nullptr); + ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, ret); + ASSERT_EQ(OK, igbProducer->requestBuffer(slot, &buf)); + + uint32_t* bufData; + buf->lock(static_cast<uint32_t>(GraphicBuffer::USAGE_SW_WRITE_OFTEN), + reinterpret_cast<void**>(&bufData)); + fillBuffer(bufData, Rect(buf->getWidth(), buf->getHeight()), buf->getStride(), r, g, b); + buf->unlock(); + + IGraphicBufferProducer::QueueBufferOutput qbOutput; + IGraphicBufferProducer::QueueBufferInput input(systemTime(), true /* autotimestamp */, + HAL_DATASPACE_UNKNOWN, {}, + NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, + Fence::NO_FENCE); + igbProducer->queueBuffer(slot, input, &qbOutput); + adapter.waitForCallbacks(); + } + // capture screen and verify that it is red + ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults)); + + ASSERT_NO_FATAL_FAILURE( + checkScreenCapture(r, g, b, + {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight / 4})); + + // update the size to half the display and dequeue a buffer quarter of the display. + adapter.update(mSurfaceControl, mDisplayWidth, mDisplayHeight / 2); + + { + int slot; + sp<Fence> fence; + sp<GraphicBuffer> buf; + auto ret = igbProducer->dequeueBuffer(&slot, &fence, mDisplayWidth, mDisplayHeight / 8, + PIXEL_FORMAT_RGBA_8888, GRALLOC_USAGE_SW_WRITE_OFTEN, + nullptr, nullptr); + ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, ret); + ASSERT_EQ(OK, igbProducer->requestBuffer(slot, &buf)); + + uint32_t* bufData; + buf->lock(static_cast<uint32_t>(GraphicBuffer::USAGE_SW_WRITE_OFTEN), + reinterpret_cast<void**>(&bufData)); + g = 255; + fillBuffer(bufData, Rect(buf->getWidth(), buf->getHeight()), buf->getStride(), r, g, b); + buf->unlock(); + + IGraphicBufferProducer::QueueBufferOutput qbOutput; + IGraphicBufferProducer::QueueBufferInput input(systemTime(), true /* autotimestamp */, + HAL_DATASPACE_UNKNOWN, {}, + NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW, + 0, Fence::NO_FENCE); + igbProducer->queueBuffer(slot, input, &qbOutput); + adapter.waitForCallbacks(); + } + // capture screen and verify that it is red + ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults)); + // verify we still scale the buffer to the new size (half the screen height) + ASSERT_NO_FATAL_FAILURE( + checkScreenCapture(r, g, b, + {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight / 2})); +} + +TEST_F(BLASTBufferQueueTest, SyncThenNoSync) { + uint8_t r = 255; + uint8_t g = 0; + uint8_t b = 0; + + BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight); + + sp<IGraphicBufferProducer> igbProducer; + setUpProducer(adapter, igbProducer); + + Transaction next; + adapter.setNextTransaction(&next); + queueBuffer(igbProducer, 0, 255, 0, 0); + + // queue non sync buffer, so this one should get blocked + // Add a present delay to allow the first screenshot to get taken. + nsecs_t presentTimeDelay = std::chrono::nanoseconds(500ms).count(); + queueBuffer(igbProducer, r, g, b, presentTimeDelay); + + CallbackHelper transactionCallback; + next.addTransactionCompletedCallback(transactionCallback.function, + transactionCallback.getContext()) + .apply(); + + CallbackData callbackData; + transactionCallback.getCallbackData(&callbackData); + + // capture screen and verify that it is red + ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults)); + ASSERT_NO_FATAL_FAILURE( + checkScreenCapture(0, 255, 0, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight})); + + mProducerListener->waitOnNumberReleased(1); + ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults)); + ASSERT_NO_FATAL_FAILURE( + checkScreenCapture(r, g, b, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight})); +} + +TEST_F(BLASTBufferQueueTest, MultipleSyncTransactions) { + uint8_t r = 255; + uint8_t g = 0; + uint8_t b = 0; + + BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight); + + sp<IGraphicBufferProducer> igbProducer; + setUpProducer(adapter, igbProducer); + + Transaction mainTransaction; + + Transaction next; + adapter.setNextTransaction(&next); + queueBuffer(igbProducer, 0, 255, 0, 0); + + mainTransaction.merge(std::move(next)); + + adapter.setNextTransaction(&next); + queueBuffer(igbProducer, r, g, b, 0); + + mainTransaction.merge(std::move(next)); + // Expect 1 buffer to be released even before sending to SurfaceFlinger + mProducerListener->waitOnNumberReleased(1); + + CallbackHelper transactionCallback; + mainTransaction + .addTransactionCompletedCallback(transactionCallback.function, + transactionCallback.getContext()) + .apply(); + + CallbackData callbackData; + transactionCallback.getCallbackData(&callbackData); + + // capture screen and verify that it is red + ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults)); + ASSERT_NO_FATAL_FAILURE( + checkScreenCapture(r, g, b, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight})); +} + +TEST_F(BLASTBufferQueueTest, MultipleSyncTransactionWithNonSync) { + uint8_t r = 255; + uint8_t g = 0; + uint8_t b = 0; + + BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight); + + sp<IGraphicBufferProducer> igbProducer; + setUpProducer(adapter, igbProducer); + + Transaction mainTransaction; + + Transaction next; + // queue a sync transaction + adapter.setNextTransaction(&next); + queueBuffer(igbProducer, 0, 255, 0, 0); + + mainTransaction.merge(std::move(next)); + + // queue another buffer without setting next transaction + queueBuffer(igbProducer, 0, 0, 255, 0); + + // queue another sync transaction + adapter.setNextTransaction(&next); + queueBuffer(igbProducer, r, g, b, 0); + // Expect 1 buffer to be released because the non sync transaction should merge + // with the sync + mProducerListener->waitOnNumberReleased(1); + + mainTransaction.merge(std::move(next)); + // Expect 2 buffers to be released due to merging the two syncs. + mProducerListener->waitOnNumberReleased(2); + + CallbackHelper transactionCallback; + mainTransaction + .addTransactionCompletedCallback(transactionCallback.function, + transactionCallback.getContext()) + .apply(); + + CallbackData callbackData; + transactionCallback.getCallbackData(&callbackData); + + // capture screen and verify that it is red + ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults)); + ASSERT_NO_FATAL_FAILURE( + checkScreenCapture(r, g, b, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight})); +} + +TEST_F(BLASTBufferQueueTest, MultipleSyncRunOutOfBuffers) { + uint8_t r = 255; + uint8_t g = 0; + uint8_t b = 0; + + BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight); + + sp<IGraphicBufferProducer> igbProducer; + setUpProducer(adapter, igbProducer, 3); + + Transaction mainTransaction; + + Transaction next; + // queue a sync transaction + adapter.setNextTransaction(&next); + queueBuffer(igbProducer, 0, 255, 0, 0); + + mainTransaction.merge(std::move(next)); + + // queue a few buffers without setting next transaction + queueBuffer(igbProducer, 0, 0, 255, 0); + queueBuffer(igbProducer, 0, 0, 255, 0); + queueBuffer(igbProducer, 0, 0, 255, 0); + + // queue another sync transaction + adapter.setNextTransaction(&next); + queueBuffer(igbProducer, r, g, b, 0); + // Expect 3 buffers to be released because the non sync transactions should merge + // with the sync + mProducerListener->waitOnNumberReleased(3); + + mainTransaction.merge(std::move(next)); + // Expect 4 buffers to be released due to merging the two syncs. + mProducerListener->waitOnNumberReleased(4); + + CallbackHelper transactionCallback; + mainTransaction + .addTransactionCompletedCallback(transactionCallback.function, + transactionCallback.getContext()) + .apply(); + + CallbackData callbackData; + transactionCallback.getCallbackData(&callbackData); + + // capture screen and verify that it is red + ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults)); + ASSERT_NO_FATAL_FAILURE( + checkScreenCapture(r, g, b, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight})); +} + +// Tests BBQ with a sync transaction when the buffers acquired reaches max and the only way to +// continue processing is for a release callback from SurfaceFlinger. +// This is done by sending a buffer to SF so it can release the previous one and allow BBQ to +// continue acquiring buffers. +TEST_F(BLASTBufferQueueTest, RunOutOfBuffersWaitingOnSF) { + uint8_t r = 255; + uint8_t g = 0; + uint8_t b = 0; + + BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight); + + sp<IGraphicBufferProducer> igbProducer; + setUpProducer(adapter, igbProducer, 4); + + Transaction mainTransaction; + + // Send a buffer to SF + queueBuffer(igbProducer, 0, 255, 0, 0); + + Transaction next; + // queue a sync transaction + adapter.setNextTransaction(&next); + queueBuffer(igbProducer, 0, 255, 0, 0); + + mainTransaction.merge(std::move(next)); + + // queue a few buffers without setting next transaction + queueBuffer(igbProducer, 0, 0, 255, 0); + queueBuffer(igbProducer, 0, 0, 255, 0); + queueBuffer(igbProducer, 0, 0, 255, 0); + + // apply the first synced buffer to ensure we have to wait on SF + mainTransaction.apply(); + + // queue another sync transaction + adapter.setNextTransaction(&next); + queueBuffer(igbProducer, r, g, b, 0); + // Expect 2 buffers to be released because the non sync transactions should merge + // with the sync + mProducerListener->waitOnNumberReleased(3); + + mainTransaction.merge(std::move(next)); + + CallbackHelper transactionCallback; + mainTransaction + .addTransactionCompletedCallback(transactionCallback.function, + transactionCallback.getContext()) + .apply(); + + CallbackData callbackData; + transactionCallback.getCallbackData(&callbackData); + + // capture screen and verify that it is red + ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults)); + ASSERT_NO_FATAL_FAILURE( + checkScreenCapture(r, g, b, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight})); +} + class TestProducerListener : public BnProducerListener { public: sp<IGraphicBufferProducer> mIgbp; diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp index e9ad011b8e..743c8433cd 100644 --- a/libs/gui/tests/EndToEndNativeInputTest.cpp +++ b/libs/gui/tests/EndToEndNativeInputTest.cpp @@ -24,6 +24,7 @@ #include <memory> +#include <android/keycodes.h> #include <android/native_window.h> #include <binder/Binder.h> @@ -37,9 +38,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 +50,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; @@ -115,8 +121,8 @@ public: return std::make_unique<InputSurface>(surfaceControl, width, height); } - InputEvent* consumeEvent() { - waitForEventAvailable(); + InputEvent *consumeEvent(int timeoutMs = 3000) { + waitForEventAvailable(timeoutMs); InputEvent *ev; uint32_t seqId; @@ -177,6 +183,24 @@ public: EXPECT_EQ(flags, mev->getFlags() & flags); } + void expectKey(uint32_t keycode) { + InputEvent *ev = consumeEvent(); + ASSERT_NE(ev, nullptr); + ASSERT_EQ(AINPUT_EVENT_TYPE_KEY, ev->getType()); + KeyEvent *keyEvent = static_cast<KeyEvent *>(ev); + EXPECT_EQ(AMOTION_EVENT_ACTION_DOWN, keyEvent->getAction()); + EXPECT_EQ(keycode, keyEvent->getKeyCode()); + EXPECT_EQ(0, keyEvent->getFlags() & VERIFIED_KEY_EVENT_FLAGS); + + ev = consumeEvent(); + ASSERT_NE(ev, nullptr); + ASSERT_EQ(AINPUT_EVENT_TYPE_KEY, ev->getType()); + keyEvent = static_cast<KeyEvent *>(ev); + EXPECT_EQ(AMOTION_EVENT_ACTION_UP, keyEvent->getAction()); + EXPECT_EQ(keycode, keyEvent->getKeyCode()); + EXPECT_EQ(0, keyEvent->getFlags() & VERIFIED_KEY_EVENT_FLAGS); + } + virtual ~InputSurface() { mInputFlinger->removeInputChannel(mClientChannel->getConnectionToken()); } @@ -214,19 +238,19 @@ public: } private: - void waitForEventAvailable() { + void waitForEventAvailable(int timeoutMs) { struct pollfd fd; fd.fd = mClientChannel->getFd(); fd.events = POLLIN; - poll(&fd, 1, 3000); + poll(&fd, 1, timeoutMs); } 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; @@ -253,7 +277,7 @@ public: std::shared_ptr<InputChannel> mClientChannel; sp<IInputFlinger> mInputFlinger; - InputWindowInfo mInputInfo; + WindowInfo mInputInfo; PreallocatedInputEventFactory mInputEventFactory; InputConsumer* mInputConsumer; @@ -362,6 +386,14 @@ void injectTap(int x, int y) { } } +void injectKey(uint32_t keycode) { + char *buf1; + asprintf(&buf1, "%d", keycode); + if (fork() == 0) { + execlp("input", "input", "keyevent", buf1, NULL); + } +} + TEST_F(InputSurfacesTest, can_receive_input) { std::unique_ptr<InputSurface> surface = makeSurface(100, 100); surface->showAt(100, 100); @@ -613,6 +645,9 @@ TEST_F(InputSurfacesTest, can_be_focused) { surface->requestFocus(); surface->assertFocusChange(true); + + injectKey(AKEYCODE_V); + surface->expectKey(AKEYCODE_V); } TEST_F(InputSurfacesTest, rotate_surface) { @@ -690,7 +725,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. @@ -710,8 +745,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); @@ -734,8 +769,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); @@ -755,7 +790,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); @@ -770,7 +805,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); @@ -780,4 +815,153 @@ TEST_F(InputSurfacesTest, touch_not_obscured_with_zero_sized_blast) { surface->expectTap(1, 1); } +TEST_F(InputSurfacesTest, strict_unobscured_input_unobscured_window) { + std::unique_ptr<InputSurface> surface = makeSurface(100, 100); + surface->doTransaction( + [&](auto &t, auto &sc) { t.setDropInputMode(sc, gui::DropInputMode::OBSCURED); }); + surface->showAt(100, 100); + + injectTap(101, 101); + + EXPECT_NE(surface->consumeEvent(), nullptr); + EXPECT_NE(surface->consumeEvent(), nullptr); + + surface->requestFocus(); + surface->assertFocusChange(true); + injectKey(AKEYCODE_V); + surface->expectKey(AKEYCODE_V); +} + +TEST_F(InputSurfacesTest, strict_unobscured_input_scaled_without_crop_window) { + std::unique_ptr<InputSurface> surface = makeSurface(100, 100); + surface->doTransaction([&](auto &t, auto &sc) { + t.setDropInputMode(sc, gui::DropInputMode::OBSCURED); + t.setMatrix(sc, 2.0, 0, 0, 2.0); + }); + surface->showAt(100, 100); + + injectTap(101, 101); + + EXPECT_NE(surface->consumeEvent(), nullptr); + EXPECT_NE(surface->consumeEvent(), nullptr); + + surface->requestFocus(); + surface->assertFocusChange(true); + injectKey(AKEYCODE_V); + surface->expectKey(AKEYCODE_V); +} + +TEST_F(InputSurfacesTest, strict_unobscured_input_obscured_window) { + std::unique_ptr<InputSurface> surface = makeSurface(100, 100); + surface->mInputInfo.ownerUid = 11111; + surface->doTransaction( + [&](auto &t, auto &sc) { t.setDropInputMode(sc, gui::DropInputMode::OBSCURED); }); + surface->showAt(100, 100); + std::unique_ptr<InputSurface> obscuringSurface = makeSurface(100, 100); + obscuringSurface->mInputInfo.flags = WindowInfo::Flag::NOT_TOUCHABLE; + obscuringSurface->mInputInfo.ownerUid = 22222; + obscuringSurface->showAt(100, 100); + injectTap(101, 101); + EXPECT_EQ(surface->consumeEvent(100), nullptr); + + surface->requestFocus(); + surface->assertFocusChange(true); + injectKey(AKEYCODE_V); + EXPECT_EQ(surface->consumeEvent(100), nullptr); +} + +TEST_F(InputSurfacesTest, strict_unobscured_input_partially_obscured_window) { + std::unique_ptr<InputSurface> surface = makeSurface(100, 100); + surface->mInputInfo.ownerUid = 11111; + surface->doTransaction( + [&](auto &t, auto &sc) { t.setDropInputMode(sc, gui::DropInputMode::OBSCURED); }); + surface->showAt(100, 100); + std::unique_ptr<InputSurface> obscuringSurface = makeSurface(100, 100); + obscuringSurface->mInputInfo.flags = WindowInfo::Flag::NOT_TOUCHABLE; + obscuringSurface->mInputInfo.ownerUid = 22222; + obscuringSurface->showAt(190, 190); + + injectTap(101, 101); + + EXPECT_EQ(surface->consumeEvent(100), nullptr); + + surface->requestFocus(); + surface->assertFocusChange(true); + injectKey(AKEYCODE_V); + EXPECT_EQ(surface->consumeEvent(100), nullptr); +} + +TEST_F(InputSurfacesTest, strict_unobscured_input_alpha_window) { + std::unique_ptr<InputSurface> parentSurface = makeSurface(300, 300); + parentSurface->showAt(0, 0, Rect(0, 0, 300, 300)); + + std::unique_ptr<InputSurface> surface = makeSurface(100, 100); + surface->showAt(100, 100); + surface->doTransaction([&](auto &t, auto &sc) { + t.setDropInputMode(sc, gui::DropInputMode::OBSCURED); + t.reparent(sc, parentSurface->mSurfaceControl); + t.setAlpha(parentSurface->mSurfaceControl, 0.9f); + }); + + injectTap(101, 101); + + EXPECT_EQ(surface->consumeEvent(100), nullptr); + + surface->requestFocus(); + surface->assertFocusChange(true); + injectKey(AKEYCODE_V); + EXPECT_EQ(surface->consumeEvent(100), nullptr); +} + +TEST_F(InputSurfacesTest, strict_unobscured_input_cropped_window) { + std::unique_ptr<InputSurface> parentSurface = makeSurface(300, 300); + parentSurface->showAt(0, 0, Rect(0, 0, 300, 300)); + + std::unique_ptr<InputSurface> surface = makeSurface(100, 100); + surface->doTransaction([&](auto &t, auto &sc) { + t.setDropInputMode(sc, gui::DropInputMode::OBSCURED); + t.reparent(sc, parentSurface->mSurfaceControl); + t.setCrop(parentSurface->mSurfaceControl, Rect(10, 10, 100, 100)); + }); + surface->showAt(100, 100); + + injectTap(111, 111); + + EXPECT_EQ(surface->consumeEvent(100), nullptr); + + surface->requestFocus(); + surface->assertFocusChange(true); + injectKey(AKEYCODE_V); + EXPECT_EQ(surface->consumeEvent(100), nullptr); +} + +TEST_F(InputSurfacesTest, ignore_touch_region_with_zero_sized_blast) { + std::unique_ptr<InputSurface> surface = makeSurface(100, 100); + + std::unique_ptr<BlastInputSurface> bufferSurface = + BlastInputSurface::makeBlastInputSurface(mComposerClient, 0, 0); + + surface->showAt(100, 100); + bufferSurface->mInputInfo.touchableRegion.orSelf(Rect(0, 0, 200, 200)); + bufferSurface->showAt(100, 100, Rect::EMPTY_RECT); + + injectTap(101, 101); + surface->expectTap(1, 1); +} + +TEST_F(InputSurfacesTest, drop_input_policy) { + std::unique_ptr<InputSurface> surface = makeSurface(100, 100); + surface->doTransaction( + [&](auto &t, auto &sc) { t.setDropInputMode(sc, gui::DropInputMode::ALL); }); + surface->showAt(100, 100); + + injectTap(101, 101); + + EXPECT_EQ(surface->consumeEvent(100), nullptr); + + surface->requestFocus(); + surface->assertFocusChange(true); + injectKey(AKEYCODE_V); + EXPECT_EQ(surface->consumeEvent(100), nullptr); +} } // namespace android::test diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index 37c1497857..be3dbcd710 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -694,6 +694,7 @@ public: bool /*secure*/) override { return nullptr; } void destroyDisplay(const sp<IBinder>& /*display */) override {} std::vector<PhysicalDisplayId> getPhysicalDisplayIds() const override { return {}; } + status_t getPrimaryPhysicalDisplayId(PhysicalDisplayId*) const override { return NO_ERROR; } sp<IBinder> getPhysicalDisplayToken(PhysicalDisplayId) const override { return nullptr; } status_t setTransactionState(const FrameTimelineInfo& /*frameTimelineInfo*/, const Vector<ComposerState>& /*state*/, @@ -905,6 +906,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..5f440b77e2 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> @@ -66,23 +67,15 @@ float transformAngle(const ui::Transform& transform, float angleRadians) { transformedPoint.y -= origin.y; // Derive the transformed vector's clockwise angle from vertical. - float result = atan2f(transformedPoint.x, -transformedPoint.y); - if (result < -M_PI_2) { - result += M_PI; - } else if (result > M_PI_2) { - result -= M_PI; - } - return result; + // The return value of atan2f is in range [-pi, pi] which conforms to the orientation API. + return atan2f(transformedPoint.x, -transformedPoint.y); } -// 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 +94,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 +321,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 +391,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 +427,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 +444,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 +470,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 +540,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 +637,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 +704,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 +766,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 97f4e66e38..b25f578dc8 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; @@ -1372,9 +1376,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..2039fa6553 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 @@ -85,10 +86,13 @@ static String8 toString(const char16_t* chars, size_t numChars) { // --- KeyCharacterMap --- -KeyCharacterMap::KeyCharacterMap() : mType(KeyboardType::UNKNOWN) {} +KeyCharacterMap::KeyCharacterMap(const std::string& filename) + : mType(KeyboardType::UNKNOWN), mLoadFileName(filename) {} KeyCharacterMap::KeyCharacterMap(const KeyCharacterMap& other) : mType(other.mType), + mLoadFileName(other.mLoadFileName), + mLayoutOverlayApplied(other.mLayoutOverlayApplied), mKeysByScanCode(other.mKeysByScanCode), mKeysByUsageCode(other.mKeysByUsageCode) { for (size_t i = 0; i < other.mKeys.size(); i++) { @@ -97,16 +101,19 @@ KeyCharacterMap::KeyCharacterMap(const KeyCharacterMap& other) } KeyCharacterMap::~KeyCharacterMap() { - for (size_t i = 0; i < mKeys.size(); i++) { - Key* key = mKeys.editValueAt(i); - delete key; - } + clear(); } bool KeyCharacterMap::operator==(const KeyCharacterMap& other) const { if (mType != other.mType) { return false; } + if (mLoadFileName != other.mLoadFileName) { + return false; + } + if (mLayoutOverlayApplied != other.mLayoutOverlayApplied) { + return false; + } if (mKeys.size() != other.mKeys.size() || mKeysByScanCode.size() != other.mKeysByScanCode.size() || mKeysByUsageCode.size() != other.mKeysByUsageCode.size()) { @@ -145,6 +152,10 @@ bool KeyCharacterMap::operator==(const KeyCharacterMap& other) const { return true; } +bool KeyCharacterMap::operator!=(const KeyCharacterMap& other) const { + return !(*this == other); +} + base::Result<std::shared_ptr<KeyCharacterMap>> KeyCharacterMap::load(const std::string& filename, Format format) { Tokenizer* tokenizer; @@ -152,12 +163,18 @@ base::Result<std::shared_ptr<KeyCharacterMap>> KeyCharacterMap::load(const std:: if (status) { return Errorf("Error {} opening key character map file {}.", status, filename.c_str()); } + std::shared_ptr<KeyCharacterMap> map = + std::shared_ptr<KeyCharacterMap>(new KeyCharacterMap(filename)); + if (!map.get()) { + ALOGE("Error allocating key character map."); + return Errorf("Error allocating key character map."); + } std::unique_ptr<Tokenizer> t(tokenizer); - auto ret = load(t.get(), format); - if (ret.ok()) { - (*ret)->mLoadFileName = filename; + status = map->load(t.get(), format); + if (status == OK) { + return map; } - return ret; + return Errorf("Load KeyCharacterMap failed {}.", status); } base::Result<std::shared_ptr<KeyCharacterMap>> KeyCharacterMap::loadContents( @@ -168,40 +185,67 @@ base::Result<std::shared_ptr<KeyCharacterMap>> KeyCharacterMap::loadContents( ALOGE("Error %d opening key character map.", status); return Errorf("Error {} opening key character map.", status); } + std::shared_ptr<KeyCharacterMap> map = + std::shared_ptr<KeyCharacterMap>(new KeyCharacterMap(filename)); + if (!map.get()) { + ALOGE("Error allocating key character map."); + return Errorf("Error allocating key character map."); + } std::unique_ptr<Tokenizer> t(tokenizer); - auto ret = load(t.get(), format); - if (ret.ok()) { - (*ret)->mLoadFileName = filename; + status = map->load(t.get(), format); + if (status == OK) { + return map; } - return ret; + return Errorf("Load KeyCharacterMap failed {}.", status); } -base::Result<std::shared_ptr<KeyCharacterMap>> KeyCharacterMap::load(Tokenizer* tokenizer, - Format format) { +status_t KeyCharacterMap::load(Tokenizer* tokenizer, Format format) { status_t status = OK; - std::shared_ptr<KeyCharacterMap> map = std::shared_ptr<KeyCharacterMap>(new KeyCharacterMap()); - if (!map.get()) { - ALOGE("Error allocating key character map."); - return Errorf("Error allocating key character map."); - } #if DEBUG_PARSER_PERFORMANCE nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC); #endif - Parser parser(map.get(), tokenizer, format); + Parser parser(this, tokenizer, format); status = parser.parse(); #if DEBUG_PARSER_PERFORMANCE nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime; ALOGD("Parsed key character map file '%s' %d lines in %0.3fms.", tokenizer->getFilename().string(), tokenizer->getLineNumber(), elapsedTime / 1000000.0); #endif - if (status == OK) { - return map; + if (status != OK) { + ALOGE("Loading KeyCharacterMap failed with status %s", statusToString(status).c_str()); } + return status; +} - return Errorf("Load KeyCharacterMap failed {}.", status); +void KeyCharacterMap::clear() { + mKeysByScanCode.clear(); + mKeysByUsageCode.clear(); + for (size_t i = 0; i < mKeys.size(); i++) { + Key* key = mKeys.editValueAt(i); + delete key; + } + mKeys.clear(); + mLayoutOverlayApplied = false; + mType = KeyboardType::UNKNOWN; +} + +status_t KeyCharacterMap::reloadBaseFromFile() { + clear(); + Tokenizer* tokenizer; + status_t status = Tokenizer::open(String8(mLoadFileName.c_str()), &tokenizer); + if (status) { + ALOGE("Error %s opening key character map file %s.", statusToString(status).c_str(), + mLoadFileName.c_str()); + return status; + } + std::unique_ptr<Tokenizer> t(tokenizer); + return load(t.get(), KeyCharacterMap::Format::BASE); } void KeyCharacterMap::combine(const KeyCharacterMap& overlay) { + if (mLayoutOverlayApplied) { + reloadBaseFromFile(); + } for (size_t i = 0; i < overlay.mKeys.size(); i++) { int32_t keyCode = overlay.mKeys.keyAt(i); Key* key = overlay.mKeys.valueAt(i); @@ -223,7 +267,7 @@ void KeyCharacterMap::combine(const KeyCharacterMap& overlay) { mKeysByUsageCode.replaceValueFor(overlay.mKeysByUsageCode.keyAt(i), overlay.mKeysByUsageCode.valueAt(i)); } - mLoadFileName = overlay.mLoadFileName; + mLayoutOverlayApplied = true; } KeyCharacterMap::KeyboardType KeyCharacterMap::getKeyboardType() const { @@ -635,8 +679,11 @@ std::shared_ptr<KeyCharacterMap> KeyCharacterMap::readFromParcel(Parcel* parcel) ALOGE("%s: Null parcel", __func__); return nullptr; } - std::shared_ptr<KeyCharacterMap> map = std::shared_ptr<KeyCharacterMap>(new KeyCharacterMap()); + std::string loadFileName = parcel->readCString(); + std::shared_ptr<KeyCharacterMap> map = + std::shared_ptr<KeyCharacterMap>(new KeyCharacterMap(loadFileName)); map->mType = static_cast<KeyCharacterMap::KeyboardType>(parcel->readInt32()); + map->mLayoutOverlayApplied = parcel->readBool(); size_t numKeys = parcel->readInt32(); if (parcel->errorCheck()) { return nullptr; @@ -686,6 +733,30 @@ std::shared_ptr<KeyCharacterMap> KeyCharacterMap::readFromParcel(Parcel* parcel) return nullptr; } } + size_t numKeysByScanCode = parcel->readInt32(); + if (parcel->errorCheck()) { + return nullptr; + } + for (size_t i = 0; i < numKeysByScanCode; i++) { + int32_t key = parcel->readInt32(); + int32_t value = parcel->readInt32(); + map->mKeysByScanCode.add(key, value); + if (parcel->errorCheck()) { + return nullptr; + } + } + size_t numKeysByUsageCode = parcel->readInt32(); + if (parcel->errorCheck()) { + return nullptr; + } + for (size_t i = 0; i < numKeysByUsageCode; i++) { + int32_t key = parcel->readInt32(); + int32_t value = parcel->readInt32(); + map->mKeysByUsageCode.add(key, value); + if (parcel->errorCheck()) { + return nullptr; + } + } return map; } @@ -694,7 +765,9 @@ void KeyCharacterMap::writeToParcel(Parcel* parcel) const { ALOGE("%s: Null parcel", __func__); return; } + parcel->writeCString(mLoadFileName.c_str()); parcel->writeInt32(static_cast<int32_t>(mType)); + parcel->writeBool(mLayoutOverlayApplied); size_t numKeys = mKeys.size(); parcel->writeInt32(numKeys); @@ -714,6 +787,18 @@ void KeyCharacterMap::writeToParcel(Parcel* parcel) const { } parcel->writeInt32(0); } + size_t numKeysByScanCode = mKeysByScanCode.size(); + parcel->writeInt32(numKeysByScanCode); + for (size_t i = 0; i < numKeysByScanCode; i++) { + parcel->writeInt32(mKeysByScanCode.keyAt(i)); + parcel->writeInt32(mKeysByScanCode.valueAt(i)); + } + size_t numKeysByUsageCode = mKeysByUsageCode.size(); + parcel->writeInt32(numKeysByUsageCode); + for (size_t i = 0; i < numKeysByUsageCode; i++) { + parcel->writeInt32(mKeysByUsageCode.keyAt(i)); + parcel->writeInt32(mKeysByUsageCode.valueAt(i)); + } } #endif // __linux__ 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..6ffe8518b6 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", @@ -39,6 +37,7 @@ cc_test { "libui", "libutils", ], + data: ["data/*.kcm"], test_suites: ["device-tests"], } @@ -61,5 +60,5 @@ cc_library_static { "libbinder", "libui", "libbase", - ] + ], } diff --git a/libs/input/tests/InputDevice_test.cpp b/libs/input/tests/InputDevice_test.cpp index f8f2f4e931..61e88df11d 100644 --- a/libs/input/tests/InputDevice_test.cpp +++ b/libs/input/tests/InputDevice_test.cpp @@ -20,6 +20,7 @@ #include <input/InputDevice.h> #include <input/KeyLayoutMap.h> #include <input/Keyboard.h> +#include "android-base/file.h" namespace android { @@ -82,4 +83,53 @@ TEST_F(InputDeviceKeyMapTest, keyCharacterMapParcelingTest) { ASSERT_EQ(*map, *mKeyMap.keyCharacterMap); } +TEST_F(InputDeviceKeyMapTest, keyCharacterMapWithOverlayParcelingTest) { + Parcel parcel; + std::string overlayPath = base::GetExecutableDirectory() + "/data/german.kcm"; + base::Result<std::shared_ptr<KeyCharacterMap>> overlay = + KeyCharacterMap::load(overlayPath, KeyCharacterMap::Format::OVERLAY); + ASSERT_TRUE(overlay.ok()) << "Cannot load KeyCharacterMap at " << overlayPath; + mKeyMap.keyCharacterMap->combine(*overlay->get()); + mKeyMap.keyCharacterMap->writeToParcel(&parcel); + parcel.setDataPosition(0); + std::shared_ptr<KeyCharacterMap> map = KeyCharacterMap::readFromParcel(&parcel); + ASSERT_EQ(*map, *mKeyMap.keyCharacterMap); +} + +TEST_F(InputDeviceKeyMapTest, keyCharacteMapApplyMultipleOverlaysTest) { + std::string frenchOverlayPath = base::GetExecutableDirectory() + "/data/french.kcm"; + std::string englishOverlayPath = base::GetExecutableDirectory() + "/data/english_us.kcm"; + std::string germanOverlayPath = base::GetExecutableDirectory() + "/data/german.kcm"; + base::Result<std::shared_ptr<KeyCharacterMap>> frenchOverlay = + KeyCharacterMap::load(frenchOverlayPath, KeyCharacterMap::Format::OVERLAY); + ASSERT_TRUE(frenchOverlay.ok()) << "Cannot load KeyCharacterMap at " << frenchOverlayPath; + base::Result<std::shared_ptr<KeyCharacterMap>> englishOverlay = + KeyCharacterMap::load(englishOverlayPath, KeyCharacterMap::Format::OVERLAY); + ASSERT_TRUE(englishOverlay.ok()) << "Cannot load KeyCharacterMap at " << englishOverlayPath; + base::Result<std::shared_ptr<KeyCharacterMap>> germanOverlay = + KeyCharacterMap::load(germanOverlayPath, KeyCharacterMap::Format::OVERLAY); + ASSERT_TRUE(germanOverlay.ok()) << "Cannot load KeyCharacterMap at " << germanOverlayPath; + + // Apply the French overlay + mKeyMap.keyCharacterMap->combine(*frenchOverlay->get()); + // Copy the result for later + std::shared_ptr<KeyCharacterMap> frenchOverlaidKeyCharacterMap = + std::make_shared<KeyCharacterMap>(*mKeyMap.keyCharacterMap); + + // Apply the English overlay + mKeyMap.keyCharacterMap->combine(*englishOverlay->get()); + // Verify that the result is different from the French overlay result + ASSERT_NE(*mKeyMap.keyCharacterMap, *frenchOverlaidKeyCharacterMap); + + // Apply the German overlay + mKeyMap.keyCharacterMap->combine(*germanOverlay->get()); + // Verify that the result is different from the French overlay result + ASSERT_NE(*mKeyMap.keyCharacterMap, *frenchOverlaidKeyCharacterMap); + + // Apply the French overlay + mKeyMap.keyCharacterMap->combine(*frenchOverlay->get()); + // Verify that the result is the same like after applying it initially + ASSERT_EQ(*mKeyMap.keyCharacterMap, *frenchOverlaidKeyCharacterMap); +} + } // namespace android 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 2e85d24712..db16ffd58a 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> @@ -166,6 +167,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; @@ -196,9 +198,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"; @@ -239,6 +241,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()); @@ -480,8 +483,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"; } @@ -496,8 +500,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"; } @@ -517,8 +522,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/input/tests/data/english_us.kcm b/libs/input/tests/data/english_us.kcm new file mode 100644 index 0000000000..d0ef027f85 --- /dev/null +++ b/libs/input/tests/data/english_us.kcm @@ -0,0 +1,311 @@ +# 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. + +# +# English (US) keyboard layout. +# Unlike the default (generic) keyboard layout, English (US) does not contain any +# special ALT characters. +# + +type OVERLAY + +### ROW 1 + +key GRAVE { + label: '`' + base: '`' + shift: '~' +} + +key 1 { + label: '1' + base: '1' + shift: '!' +} + +key 2 { + label: '2' + base: '2' + shift: '@' +} + +key 3 { + label: '3' + base: '3' + shift: '#' +} + +key 4 { + label: '4' + base: '4' + shift: '$' +} + +key 5 { + label: '5' + base: '5' + shift: '%' +} + +key 6 { + label: '6' + base: '6' + shift: '^' +} + +key 7 { + label: '7' + base: '7' + shift: '&' +} + +key 8 { + label: '8' + base: '8' + shift: '*' +} + +key 9 { + label: '9' + base: '9' + shift: '(' +} + +key 0 { + label: '0' + base: '0' + shift: ')' +} + +key MINUS { + label: '-' + base: '-' + shift: '_' +} + +key EQUALS { + label: '=' + base: '=' + shift: '+' +} + +### ROW 2 + +key Q { + label: 'Q' + base: 'q' + shift, capslock: 'Q' +} + +key W { + label: 'W' + base: 'w' + shift, capslock: 'W' +} + +key E { + label: 'E' + base: 'e' + shift, capslock: 'E' +} + +key R { + label: 'R' + base: 'r' + shift, capslock: 'R' +} + +key T { + label: 'T' + base: 't' + shift, capslock: 'T' +} + +key Y { + label: 'Y' + base: 'y' + shift, capslock: 'Y' +} + +key U { + label: 'U' + base: 'u' + shift, capslock: 'U' +} + +key I { + label: 'I' + base: 'i' + shift, capslock: 'I' +} + +key O { + label: 'O' + base: 'o' + shift, capslock: 'O' +} + +key P { + label: 'P' + base: 'p' + shift, capslock: 'P' +} + +key LEFT_BRACKET { + label: '[' + base: '[' + shift: '{' +} + +key RIGHT_BRACKET { + label: ']' + base: ']' + shift: '}' +} + +key BACKSLASH { + label: '\\' + base: '\\' + shift: '|' +} + +### ROW 3 + +key A { + label: 'A' + base: 'a' + shift, capslock: 'A' +} + +key S { + label: 'S' + base: 's' + shift, capslock: 'S' +} + +key D { + label: 'D' + base: 'd' + shift, capslock: 'D' +} + +key F { + label: 'F' + base: 'f' + shift, capslock: 'F' +} + +key G { + label: 'G' + base: 'g' + shift, capslock: 'G' +} + +key H { + label: 'H' + base: 'h' + shift, capslock: 'H' +} + +key J { + label: 'J' + base: 'j' + shift, capslock: 'J' +} + +key K { + label: 'K' + base: 'k' + shift, capslock: 'K' +} + +key L { + label: 'L' + base: 'l' + shift, capslock: 'L' +} + +key SEMICOLON { + label: ';' + base: ';' + shift: ':' +} + +key APOSTROPHE { + label: '\'' + base: '\'' + shift: '"' +} + +### ROW 4 + +key Z { + label: 'Z' + base: 'z' + shift, capslock: 'Z' +} + +key X { + label: 'X' + base: 'x' + shift, capslock: 'X' +} + +key C { + label: 'C' + base: 'c' + shift, capslock: 'C' +} + +key V { + label: 'V' + base: 'v' + shift, capslock: 'V' +} + +key B { + label: 'B' + base: 'b' + shift, capslock: 'B' +} + +key N { + label: 'N' + base: 'n' + shift, capslock: 'N' +} + +key M { + label: 'M' + base: 'm' + shift, capslock: 'M' +} + +key COMMA { + label: ',' + base: ',' + shift: '<' +} + +key PERIOD { + label: '.' + base: '.' + shift: '>' +} + +key SLASH { + label: '/' + base: '/' + shift: '?' +}
\ No newline at end of file diff --git a/libs/input/tests/data/french.kcm b/libs/input/tests/data/french.kcm new file mode 100644 index 0000000000..db69ea0430 --- /dev/null +++ b/libs/input/tests/data/french.kcm @@ -0,0 +1,336 @@ +# 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. + +# +# French keyboard layout, AZERTY style. +# + +type OVERLAY + +map key 16 A +map key 17 Z +map key 30 Q +map key 39 M +map key 44 W +map key 50 COMMA +map key 51 SEMICOLON +map key 86 PLUS + +### ROW 1 + +key GRAVE { + label: '\u00b2' + base: '\u00b2' +} + +key 1 { + label: '1' + base: '&' + shift: '1' +} + +key 2 { + label: '2' + base: '\u00e9' + shift: '2' + ralt: '~' +} + +key 3 { + label: '3' + base: '"' + shift: '3' + ralt: '#' +} + +key 4 { + label: '4' + base: '\'' + shift: '4' + ralt: '{' +} + +key 5 { + label: '5' + base: '(' + shift: '5' + ralt: '[' +} + +key 6 { + label: '6' + base: '-' + shift: '6' + ralt: '|' +} + +key 7 { + label: '7' + base: '\u00e8' + shift: '7' + ralt: '`' +} + +key 8 { + label: '8' + base: '_' + shift: '8' + ralt: '\\' +} + +key 9 { + label: '9' + base: '\u00e7' + shift: '9' + ralt: '^' +} + +key 0 { + label: '0' + base: '\u00e0' + shift: '0' + ralt: '@' +} + +key MINUS { + label: ')' + base: ')' + shift: '\u00b0' + ralt: ']' +} + +key EQUALS { + label: '=' + base: '=' + shift: '+' + ralt: '}' +} + +### ROW 2 + +key A { + label: 'A' + base: 'a' + shift, capslock: 'A' +} + +key Z { + label: 'Z' + base: 'z' + shift, capslock: 'Z' +} + +key E { + label: 'E' + base: 'e' + shift, capslock: 'E' + ralt: '\u20ac' +} + +key R { + label: 'R' + base: 'r' + shift, capslock: 'R' +} + +key T { + label: 'T' + base: 't' + shift, capslock: 'T' +} + +key Y { + label: 'Y' + base: 'y' + shift, capslock: 'Y' +} + +key U { + label: 'U' + base: 'u' + shift, capslock: 'U' +} + +key I { + label: 'I' + base: 'i' + shift, capslock: 'I' +} + +key O { + label: 'O' + base: 'o' + shift, capslock: 'O' +} + +key P { + label: 'P' + base: 'p' + shift, capslock: 'P' +} + +key LEFT_BRACKET { + label: '\u02c6' + base: '\u0302' + shift: '\u0308' +} + +key RIGHT_BRACKET { + label: '$' + base: '$' + shift: '\u00a3' + ralt: '\u00a4' +} + +### ROW 3 + +key Q { + label: 'Q' + base: 'q' + shift, capslock: 'Q' +} + +key S { + label: 'S' + base: 's' + shift, capslock: 'S' +} + +key D { + label: 'D' + base: 'd' + shift, capslock: 'D' +} + +key F { + label: 'F' + base: 'f' + shift, capslock: 'F' +} + +key G { + label: 'G' + base: 'g' + shift, capslock: 'G' +} + +key H { + label: 'H' + base: 'h' + shift, capslock: 'H' +} + +key J { + label: 'J' + base: 'j' + shift, capslock: 'J' +} + +key K { + label: 'K' + base: 'k' + shift, capslock: 'K' +} + +key L { + label: 'L' + base: 'l' + shift, capslock: 'L' +} + +key M { + label: 'M' + base: 'm' + shift, capslock: 'M' +} + +key APOSTROPHE { + label: '\u00f9' + base: '\u00f9' + shift: '%' +} + +key BACKSLASH { + label: '*' + base: '*' + shift: '\u00b5' +} + +### ROW 4 + +key PLUS { + label: '<' + base: '<' + shift: '>' +} + +key W { + label: 'W' + base: 'w' + shift, capslock: 'W' +} + +key X { + label: 'X' + base: 'x' + shift, capslock: 'X' +} + +key C { + label: 'C' + base: 'c' + shift, capslock: 'C' +} + +key V { + label: 'V' + base: 'v' + shift, capslock: 'V' +} + +key B { + label: 'B' + base: 'b' + shift, capslock: 'B' +} + +key N { + label: 'N' + base: 'n' + shift, capslock: 'N' +} + +key COMMA { + label: ',' + base: ',' + shift: '?' +} + +key SEMICOLON { + label: ';' + base: ';' + shift: '.' +} + +key PERIOD { + label: ':' + base: ':' + shift: '/' +} + +key SLASH { + label: '!' + base: '!' + shift: '\u00a7' +}
\ No newline at end of file diff --git a/libs/input/tests/data/german.kcm b/libs/input/tests/data/german.kcm new file mode 100644 index 0000000000..2fbc5e54e3 --- /dev/null +++ b/libs/input/tests/data/german.kcm @@ -0,0 +1,336 @@ +# 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. + +# +# German keyboard layout, QWERTZ style. +# + +type OVERLAY + +map key 12 SLASH # � ? \ +map key 21 Z +map key 44 Y +map key 53 MINUS # - _ +map key 86 PLUS # < > | + +map key usage 32 A # for testing purposes only +map key usage 67 B # for testing purposes only + +### ROW 1 + +key GRAVE { + label: '^' + base: '^' + shift: '\u00b0' +} + +key 1 { + label: '1' + base: '1' + shift: '!' +} + +key 2 { + label: '2' + base: '2' + shift: '"' + ralt: '\u00b2' +} + +key 3 { + label: '3' + base: '3' + shift: '\u00a7' + ralt: '\u00b3' +} + +key 4 { + label: '4' + base: '4' + shift: '$' +} + +key 5 { + label: '5' + base: '5' + shift: '%' +} + +key 6 { + label: '6' + base: '6' + shift: '&' +} + +key 7 { + label: '7' + base: '7' + shift: '/' + ralt: '{' +} + +key 8 { + label: '8' + base: '8' + shift: '(' + ralt: '[' +} + +key 9 { + label: '9' + base: '9' + shift: ')' + ralt: ']' +} + +key 0 { + label: '0' + base: '0' + shift: '=' + ralt: '}' +} + +key SLASH { + label: '\u00df' + base: '\u00df' + shift: '?' + ralt: '\\' +} + +key EQUALS { + label: '\u00b4' + base: '\u0301' + shift: '\u0300' +} + +### ROW 2 + +key Q { + label: 'Q' + base: 'q' + shift, capslock: 'Q' + ralt: '@' +} + +key W { + label: 'W' + base: 'w' + shift, capslock: 'W' +} + +key E { + label: 'E' + base: 'e' + shift, capslock: 'E' + ralt: '\u20ac' +} + +key R { + label: 'R' + base: 'r' + shift, capslock: 'R' +} + +key T { + label: 'T' + base: 't' + shift, capslock: 'T' +} + +key Z { + label: 'Z' + base: 'z' + shift, capslock: 'Z' +} + +key U { + label: 'U' + base: 'u' + shift, capslock: 'U' +} + +key I { + label: 'I' + base: 'i' + shift, capslock: 'I' +} + +key O { + label: 'O' + base: 'o' + shift, capslock: 'O' +} + +key P { + label: 'P' + base: 'p' + shift, capslock: 'P' +} + +key LEFT_BRACKET { + label: '\u00dc' + base: '\u00fc' + shift, capslock: '\u00dc' +} + +key RIGHT_BRACKET { + label: '+' + base: '+' + shift: '*' + ralt: '~' +} + +### ROW 3 + +key A { + label: 'A' + base: 'a' + shift, capslock: 'A' +} + +key S { + label: 'S' + base: 's' + shift, capslock: 'S' +} + +key D { + label: 'D' + base: 'd' + shift, capslock: 'D' +} + +key F { + label: 'F' + base: 'f' + shift, capslock: 'F' +} + +key G { + label: 'G' + base: 'g' + shift, capslock: 'G' +} + +key H { + label: 'H' + base: 'h' + shift, capslock: 'H' +} + +key J { + label: 'J' + base: 'j' + shift, capslock: 'J' +} + +key K { + label: 'K' + base: 'k' + shift, capslock: 'K' +} + +key L { + label: 'L' + base: 'l' + shift, capslock: 'L' +} + +key SEMICOLON { + label: '\u00d6' + base: '\u00f6' + shift, capslock: '\u00d6' +} + +key APOSTROPHE { + label: '\u00c4' + base: '\u00e4' + shift, capslock: '\u00c4' +} + +key BACKSLASH { + label: '#' + base: '#' + shift: '\'' +} + +### ROW 4 + +key PLUS { + label: '<' + base: '<' + shift: '>' + ralt: '|' +} + +key Y { + label: 'Y' + base: 'y' + shift, capslock: 'Y' +} + +key X { + label: 'X' + base: 'x' + shift, capslock: 'X' +} + +key C { + label: 'C' + base: 'c' + shift, capslock: 'C' +} + +key V { + label: 'V' + base: 'v' + shift, capslock: 'V' +} + +key B { + label: 'B' + base: 'b' + shift, capslock: 'B' +} + +key N { + label: 'N' + base: 'n' + shift, capslock: 'N' +} + +key M { + label: 'M' + base: 'm' + shift, capslock: 'M' + ralt: '\u00b5' +} + +key COMMA { + label: ',' + base: ',' + shift: ';' +} + +key PERIOD { + label: '.' + base: '.' + shift: ':' +} + +key MINUS { + label: '-' + base: '-' + shift: '_' +} 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 118030b0a7..0c6e8d8e0d 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 6c88b8c8aa..b750385714 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; virtual void setViewportAndProjection(Rect viewPort, Rect sourceCrop) =0; diff --git a/libs/renderengine/include/renderengine/mock/RenderEngine.h b/libs/renderengine/include/renderengine/mock/RenderEngine.h index cad57cd576..3e1f86b661 100644 --- a/libs/renderengine/include/renderengine/mock/RenderEngine.h +++ b/libs/renderengine/include/renderengine/mock/RenderEngine.h @@ -56,7 +56,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)); MOCK_METHOD0(getRETid, int()); protected: 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 283f2703a8..c8d22a8744 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; int getRETid() { return gettid(); } diff --git a/libs/renderengine/threaded/RenderEngineThreaded.cpp b/libs/renderengine/threaded/RenderEngineThreaded.cpp index d2bd0fc6fe..fabd6e5409 100644 --- a/libs/renderengine/threaded/RenderEngineThreaded.cpp +++ b/libs/renderengine/threaded/RenderEngineThreaded.cpp @@ -356,14 +356,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 c0847a3ee4..7ea72538e6 100644 --- a/libs/renderengine/threaded/RenderEngineThreaded.h +++ b/libs/renderengine/threaded/RenderEngineThreaded.h @@ -66,7 +66,7 @@ public: void cleanFramebufferCache() override; int getContextPriority() override; bool supportsBackgroundBlur() override; - void onPrimaryDisplaySizeChanged(ui::Size size) override; + void onActiveDisplaySizeChanged(ui::Size size) override; int getRETid() override; protected: diff --git a/libs/ui/Gralloc4.cpp b/libs/ui/Gralloc4.cpp index 3323a505eb..5dd1955861 100644 --- a/libs/ui/Gralloc4.cpp +++ b/libs/ui/Gralloc4.cpp @@ -940,7 +940,7 @@ status_t Gralloc4Mapper::bufferDumpHelper(const BufferDump& bufferDump, std::ost << "KiB, w/h:" << width << "x" << height << ", usage: 0x" << std::hex << usage << std::dec << ", req fmt:" << static_cast<int32_t>(pixelFormatRequested) << ", fourcc/mod:" << pixelFormatFourCC << "/" << pixelFormatModifier - << ", dataspace: 0x" << std::hex << static_cast<uint32_t>(dataspace) + << ", dataspace: 0x" << std::hex << static_cast<uint32_t>(dataspace) << std::dec << ", compressed: "; if (less) { 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/gpuservice/gpuservice.rc b/services/gpuservice/gpuservice.rc index 65a5c2776a..0da8bd3812 100644 --- a/services/gpuservice/gpuservice.rc +++ b/services/gpuservice/gpuservice.rc @@ -1,4 +1,4 @@ service gpu /system/bin/gpuservice class core user gpu_service - group graphics + group graphics readtracefs 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 d34482f506..05ef489133 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 aa8cc302c7..6ce0313929 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 5c3747e2ec..82b4fe476e 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 6f1dfadf59..ffe3bb691c 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 ce1f266cfb..464236dfb3 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; } @@ -550,6 +559,10 @@ InputDispatcher::~InputDispatcher() { } } +void InputDispatcher::onFirstRef() { + SurfaceComposerClient::getDefault()->addWindowInfosListener(this); +} + status_t InputDispatcher::start() { if (mThread) { return ALREADY_EXISTS; @@ -623,7 +636,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. @@ -672,7 +685,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); } @@ -884,7 +897,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() != @@ -989,29 +1002,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 && @@ -1028,7 +1041,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)); @@ -1040,13 +1053,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); @@ -1604,7 +1617,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); } @@ -1622,7 +1635,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. @@ -1802,7 +1815,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); @@ -1815,6 +1828,11 @@ InputEventInjectionResult InputDispatcher::findFocusedWindowTargetsLocked( return InputEventInjectionResult::FAILED; } + // Drop key events if requested by input feature + if (focusedWindowHandle != nullptr && shouldDropInput(entry, focusedWindowHandle)) { + return InputEventInjectionResult::FAILED; + } + // Compatibility behavior: raise ANR if there is a focused application, but no focused window. // Only start counting when we have a focused event to dispatch. The ANR is canceled if we // start interacting with another application via touch (app switch). This code can be removed @@ -1929,8 +1947,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. @@ -2003,10 +2021,6 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( findTouchedWindowAtLocked(displayId, x, y, &tempTouchState, isDown /*addOutsideTargets*/, true /*addPortalWindows*/); - std::vector<TouchedMonitor> newGestureMonitors = isDown - ? findTouchedGestureMonitorsLocked(displayId, tempTouchState.portalWindows) - : std::vector<TouchedMonitor>{}; - // Figure out whether splitting will be allowed for this window. if (newTouchedWindowHandle != nullptr && newTouchedWindowHandle->getInfo()->supportsSplitTouch()) { @@ -2061,8 +2075,15 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( } } - // Also don't send the new touch event to unresponsive gesture monitors - newGestureMonitors = selectResponsiveMonitorsLocked(newGestureMonitors); + // Drop touch events if requested by input feature + if (newTouchedWindowHandle != nullptr && shouldDropInput(entry, newTouchedWindowHandle)) { + newTouchedWindowHandle = nullptr; + } + + const std::vector<TouchedMonitor> newGestureMonitors = isDown + ? selectResponsiveMonitorsLocked( + findTouchedGestureMonitorsLocked(displayId, tempTouchState.portalWindows)) + : tempTouchState.gestureMonitors; if (newTouchedWindowHandle == nullptr && newGestureMonitors.empty()) { ALOGI("Dropping event because there is no touchable window or gesture monitor at " @@ -2098,9 +2119,14 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( pointerIds.markBit(pointerId); } tempTouchState.addOrUpdateWindow(newTouchedWindowHandle, targetFlags, pointerIds); + } else if (tempTouchState.windows.empty()) { + // If no window is touched, set split to true. This will allow the next pointer down to + // be delivered to a new window which supports split touch. + tempTouchState.split = true; + } + if (isDown) { + tempTouchState.addGestureMonitors(newGestureMonitors); } - - tempTouchState.addGestureMonitors(newGestureMonitors); } else { /* Case 2: Pointer move, up, cancel or non-splittable pointer down. */ @@ -2123,9 +2149,16 @@ 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); + + // Drop touch events if requested by input feature + if (newTouchedWindowHandle != nullptr && + shouldDropInput(entry, newTouchedWindowHandle)) { + newTouchedWindowHandle = nullptr; + } + if (oldTouchedWindowHandle != newTouchedWindowHandle && oldTouchedWindowHandle != nullptr && newTouchedWindowHandle != nullptr) { if (DEBUG_FOCUS) { @@ -2222,15 +2255,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)); } @@ -2246,15 +2279,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 | @@ -2373,7 +2406,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*/); @@ -2408,7 +2441,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*/); @@ -2433,7 +2466,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 = @@ -2443,7 +2476,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; @@ -2456,6 +2489,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); @@ -2494,7 +2528,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 || @@ -2519,8 +2553,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; @@ -2529,8 +2563,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 @@ -2568,20 +2601,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) { @@ -2620,7 +2653,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, " @@ -2654,15 +2687,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; @@ -2671,15 +2704,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; @@ -2689,8 +2722,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(); @@ -2713,10 +2745,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 @@ -3171,6 +3203,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, @@ -3487,10 +3520,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; } @@ -3554,10 +3587,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; } @@ -3883,8 +3916,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; @@ -4328,22 +4361,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; } @@ -4352,13 +4385,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; } @@ -4366,11 +4399,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) { @@ -4386,15 +4419,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()); @@ -4424,8 +4457,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; @@ -4433,26 +4466,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()); @@ -4468,7 +4496,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 { @@ -4481,7 +4509,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) { @@ -4500,19 +4528,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()); @@ -4521,18 +4549,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()) { @@ -4581,8 +4609,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()]) { @@ -4601,7 +4629,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()); @@ -4611,7 +4639,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) { @@ -4789,6 +4817,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) { @@ -4801,58 +4841,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) { @@ -4880,27 +4905,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 @@ -4947,7 +4965,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"; @@ -5003,7 +5021,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()); } @@ -5020,13 +5038,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, " @@ -5054,12 +5072,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 { @@ -5398,6 +5417,7 @@ status_t InputDispatcher::pilferPointers(const sp<IBinder>& token) { canceledWindows.c_str()); // Then clear the current touch state so we stop dispatching to them as well. + state.split = false; state.filterNonMonitors(); } return OK; @@ -5407,7 +5427,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"); @@ -5577,7 +5597,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); @@ -6245,4 +6265,31 @@ 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); +} + +bool InputDispatcher::shouldDropInput( + const EventEntry& entry, const sp<android::gui::WindowInfoHandle>& windowHandle) const { + if (windowHandle->getInfo()->inputFeatures.test(WindowInfo::Feature::DROP_INPUT) || + (windowHandle->getInfo()->inputFeatures.test(WindowInfo::Feature::DROP_INPUT_IF_OBSCURED) && + isWindowObscuredLocked(windowHandle))) { + ALOGW("Dropping %s event targeting %s as requested by input feature %s on display " + "%" PRId32 ".", + NamedEnum::string(entry.type).c_str(), windowHandle->getName().c_str(), + windowHandle->getInfo()->inputFeatures.string().c_str(), + windowHandle->getInfo()->displayId); + return true; + } + return false; +} + } // namespace android::inputdispatcher diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h index 30652c65ee..04913d479a 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); @@ -473,7 +481,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); @@ -492,20 +500,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 @@ -520,15 +529,22 @@ 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); + + bool shouldDropInput(const EventEntry& entry, + const sp<android::gui::WindowInfoHandle>& windowHandle) const + REQUIRES(mLock); // Manage the dispatch cycle for a single connection. // These methods are deliberately not Interruptible because doing all of the work @@ -607,8 +623,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) @@ -643,6 +659,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); @@ -652,6 +672,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 fd591e0e1c..3c1e6370b7 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/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp index b19b4195d1..1c76dbb386 100644 --- a/services/inputflinger/reader/EventHub.cpp +++ b/services/inputflinger/reader/EventHub.cpp @@ -1227,12 +1227,11 @@ const std::shared_ptr<KeyCharacterMap> EventHub::getKeyCharacterMap(int32_t devi bool EventHub::setKeyboardLayoutOverlay(int32_t deviceId, std::shared_ptr<KeyCharacterMap> map) { std::scoped_lock _l(mLock); Device* device = getDeviceLocked(deviceId); - if (device != nullptr && map != nullptr && device->keyMap.keyCharacterMap != nullptr) { - device->keyMap.keyCharacterMap->combine(*map); - device->keyMap.keyCharacterMapFile = device->keyMap.keyCharacterMap->getLoadFileName(); - return true; + if (device == nullptr || map == nullptr || device->keyMap.keyCharacterMap == nullptr) { + return false; } - return false; + device->keyMap.keyCharacterMap->combine(*map); + return true; } static std::string generateDescriptor(InputDeviceIdentifier& identifier) { 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 410a7063ea..1016a2c409 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 8733540e53..29a0fc748e 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 0f446532ca..eca6ebc1f5 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; @@ -473,8 +477,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(); @@ -531,8 +535,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, @@ -545,9 +549,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)) @@ -558,9 +562,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)) @@ -572,9 +576,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)) @@ -585,9 +589,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)) @@ -597,8 +601,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, @@ -608,8 +612,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, @@ -621,8 +625,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, @@ -633,8 +637,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, @@ -647,8 +651,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, @@ -899,7 +903,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; @@ -921,7 +925,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; @@ -941,7 +945,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; } @@ -955,9 +966,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; } @@ -971,11 +980,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); @@ -1109,7 +1118,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) @@ -1274,8 +1283,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; } @@ -1290,8 +1300,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; }; @@ -1418,7 +1429,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, @@ -1441,7 +1452,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}}}); @@ -1477,11 +1488,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); @@ -1588,7 +1599,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); @@ -1670,11 +1681,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); @@ -1868,15 +1879,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}}}); @@ -1942,15 +1951,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}}}); @@ -2007,6 +2014,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 = @@ -2068,15 +2203,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}}}); @@ -2171,6 +2304,18 @@ public: expectedDisplayId, expectedFlags); } + void consumeMotionCancel(int32_t expectedDisplayId, int32_t expectedFlags = 0) { + mInputReceiver->consumeEvent(AINPUT_EVENT_TYPE_MOTION, AMOTION_EVENT_ACTION_CANCEL, + expectedDisplayId, expectedFlags); + } + + void consumeMotionPointerDown(int32_t pointerIdx) { + int32_t action = AMOTION_EVENT_ACTION_POINTER_DOWN | + (pointerIdx << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); + mInputReceiver->consumeEvent(AINPUT_EVENT_TYPE_MOTION, action, ADISPLAY_ID_DEFAULT, + 0 /*expectedFlags*/); + } + MotionEvent* consumeMotion() { InputEvent* event = mInputReceiver->consume(); if (!event) { @@ -2317,6 +2462,91 @@ TEST_F(InputDispatcherTest, TestMoveEvent) { 0 /*expectedFlags*/); } +TEST_F(InputDispatcherTest, GestureMonitor_SplitIfNoWindowTouched) { + FakeMonitorReceiver monitor = FakeMonitorReceiver(mDispatcher, "GM_1", ADISPLAY_ID_DEFAULT, + true /*isGestureMonitor*/); + + std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); + // Create a non touch modal window that supports split touch + sp<FakeWindowHandle> window = + new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT); + window->setFrame(Rect(0, 0, 100, 100)); + window->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); + + // First finger down, no window touched. + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + {100, 200})) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT); + window->assertNoEvents(); + + // Second finger down on window, the window should receive touch down. + const MotionEvent secondFingerDownEvent = + MotionEventBuilder(AMOTION_EVENT_ACTION_POINTER_DOWN | + (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + AINPUT_SOURCE_TOUCHSCREEN) + .displayId(ADISPLAY_ID_DEFAULT) + .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) + .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER) + .x(100) + .y(200)) + .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50)) + .build(); + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, + InputEventInjectionSync::WAIT_FOR_RESULT)) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + + window->consumeMotionDown(ADISPLAY_ID_DEFAULT); + monitor.consumeMotionPointerDown(1 /* pointerIndex */); +} + +TEST_F(InputDispatcherTest, GestureMonitor_NoSplitAfterPilfer) { + FakeMonitorReceiver monitor = FakeMonitorReceiver(mDispatcher, "GM_1", ADISPLAY_ID_DEFAULT, + true /*isGestureMonitor*/); + + std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); + // Create a non touch modal window that supports split touch + sp<FakeWindowHandle> window = + new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT); + window->setFrame(Rect(0, 0, 100, 100)); + window->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); + + // First finger down, no window touched. + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + {100, 200})) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT); + window->assertNoEvents(); + + // Gesture monitor pilfer the pointers. + mDispatcher->pilferPointers(monitor.getToken()); + + // Second finger down on window, the window should not receive touch down. + const MotionEvent secondFingerDownEvent = + MotionEventBuilder(AMOTION_EVENT_ACTION_POINTER_DOWN | + (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + AINPUT_SOURCE_TOUCHSCREEN) + .displayId(ADISPLAY_ID_DEFAULT) + .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) + .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER) + .x(100) + .y(200)) + .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50)) + .build(); + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, + InputEventInjectionSync::WAIT_FOR_RESULT)) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + + window->assertNoEvents(); + monitor.consumeMotionPointerDown(1 /* pointerIndex */); +} + /** * Dispatcher has touch mode enabled by default. Typically, the policy overrides that value to * the device default right away. In the test scenario, we check both the default value, @@ -2440,7 +2670,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); @@ -2460,20 +2690,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(); @@ -2745,8 +2974,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 @@ -2921,7 +3149,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(); @@ -3084,8 +3311,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; @@ -3219,9 +3444,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; @@ -3279,12 +3504,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); @@ -3393,14 +3618,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}}}); @@ -3411,7 +3634,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}; } @@ -3599,7 +3822,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); @@ -4000,16 +4223,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); @@ -4377,7 +4599,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 @@ -4419,7 +4641,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}}}); @@ -4740,10 +4962,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; @@ -4857,7 +5079,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(); @@ -4868,7 +5090,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(); @@ -5122,11 +5344,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}}}); @@ -5334,4 +5556,134 @@ TEST_F(InputDispatcherDragTests, DragAndDrop_InvalidWindow) { mSecondWindow->assertNoEvents(); } +class InputDispatcherDropInputFeatureTest : public InputDispatcherTest {}; + +TEST_F(InputDispatcherDropInputFeatureTest, WindowDropsInput) { + std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); + sp<FakeWindowHandle> window = + new FakeWindowHandle(application, mDispatcher, "Test window", ADISPLAY_ID_DEFAULT); + window->setInputFeatures(WindowInfo::Feature::DROP_INPUT); + mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); + window->setFocusable(true); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); + setFocusedWindow(window); + window->consumeFocusEvent(true /*hasFocus*/, true /*inTouchMode*/); + + // With the flag set, window should not get any input + NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT); + mDispatcher->notifyKey(&keyArgs); + window->assertNoEvents(); + + NotifyMotionArgs motionArgs = + generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, + ADISPLAY_ID_DEFAULT); + mDispatcher->notifyMotion(&motionArgs); + window->assertNoEvents(); + + // With the flag cleared, the window should get input + window->setInputFeatures({}); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); + + keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT); + mDispatcher->notifyKey(&keyArgs); + window->consumeKeyUp(ADISPLAY_ID_DEFAULT); + + motionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, + ADISPLAY_ID_DEFAULT); + mDispatcher->notifyMotion(&motionArgs); + window->consumeMotionDown(ADISPLAY_ID_DEFAULT); + window->assertNoEvents(); +} + +TEST_F(InputDispatcherDropInputFeatureTest, ObscuredWindowDropsInput) { + std::shared_ptr<FakeApplicationHandle> obscuringApplication = + std::make_shared<FakeApplicationHandle>(); + sp<FakeWindowHandle> obscuringWindow = + new FakeWindowHandle(obscuringApplication, mDispatcher, "obscuringWindow", + ADISPLAY_ID_DEFAULT); + obscuringWindow->setFrame(Rect(0, 0, 50, 50)); + obscuringWindow->setOwnerInfo(111, 111); + obscuringWindow->setFlags(WindowInfo::Flag::NOT_TOUCHABLE); + std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); + sp<FakeWindowHandle> window = + new FakeWindowHandle(application, mDispatcher, "Test window", ADISPLAY_ID_DEFAULT); + window->setInputFeatures(WindowInfo::Feature::DROP_INPUT_IF_OBSCURED); + window->setOwnerInfo(222, 222); + mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); + window->setFocusable(true); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {obscuringWindow, window}}}); + setFocusedWindow(window); + window->consumeFocusEvent(true /*hasFocus*/, true /*inTouchMode*/); + + // With the flag set, window should not get any input + NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT); + mDispatcher->notifyKey(&keyArgs); + window->assertNoEvents(); + + NotifyMotionArgs motionArgs = + generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, + ADISPLAY_ID_DEFAULT); + mDispatcher->notifyMotion(&motionArgs); + window->assertNoEvents(); + + // With the flag cleared, the window should get input + window->setInputFeatures({}); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {obscuringWindow, window}}}); + + keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT); + mDispatcher->notifyKey(&keyArgs); + window->consumeKeyUp(ADISPLAY_ID_DEFAULT); + + motionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, + ADISPLAY_ID_DEFAULT); + mDispatcher->notifyMotion(&motionArgs); + window->consumeMotionDown(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED); + window->assertNoEvents(); +} + +TEST_F(InputDispatcherDropInputFeatureTest, UnobscuredWindowGetsInput) { + std::shared_ptr<FakeApplicationHandle> obscuringApplication = + std::make_shared<FakeApplicationHandle>(); + sp<FakeWindowHandle> obscuringWindow = + new FakeWindowHandle(obscuringApplication, mDispatcher, "obscuringWindow", + ADISPLAY_ID_DEFAULT); + obscuringWindow->setFrame(Rect(0, 0, 50, 50)); + obscuringWindow->setOwnerInfo(111, 111); + obscuringWindow->setFlags(WindowInfo::Flag::NOT_TOUCHABLE); + std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); + sp<FakeWindowHandle> window = + new FakeWindowHandle(application, mDispatcher, "Test window", ADISPLAY_ID_DEFAULT); + window->setInputFeatures(WindowInfo::Feature::DROP_INPUT_IF_OBSCURED); + window->setOwnerInfo(222, 222); + mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); + window->setFocusable(true); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {obscuringWindow, window}}}); + setFocusedWindow(window); + window->consumeFocusEvent(true /*hasFocus*/, true /*inTouchMode*/); + + // With the flag set, window should not get any input + NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT); + mDispatcher->notifyKey(&keyArgs); + window->assertNoEvents(); + + NotifyMotionArgs motionArgs = + generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, + ADISPLAY_ID_DEFAULT); + mDispatcher->notifyMotion(&motionArgs); + window->assertNoEvents(); + + // When the window is no longer obscured because it went on top, it should get input + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window, obscuringWindow}}}); + + keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT); + mDispatcher->notifyKey(&keyArgs); + window->consumeKeyUp(ADISPLAY_ID_DEFAULT); + + motionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, + ADISPLAY_ID_DEFAULT); + mDispatcher->notifyMotion(&motionArgs); + window->consumeMotionDown(ADISPLAY_ID_DEFAULT); + window->assertNoEvents(); +} + } // namespace android::inputdispatcher 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 38dfe4041f..b419d9ab3d 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 { @@ -2662,6 +2675,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; @@ -2678,11 +2692,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) { @@ -2794,6 +2816,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 --- @@ -4090,8 +4114,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); @@ -4105,9 +4132,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); @@ -4121,14 +4149,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)); @@ -4141,14 +4169,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) { @@ -4634,6 +4662,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); @@ -4716,6 +4746,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; @@ -5370,11 +5408,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; @@ -5393,10 +5432,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; @@ -5418,7 +5460,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)); @@ -5446,7 +5488,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)); @@ -5458,6 +5500,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); @@ -7808,7 +8016,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>(); @@ -7818,6 +8026,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(); @@ -7827,12 +8061,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>(); @@ -7849,8 +8087,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); } @@ -8404,18 +8670,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. @@ -8424,16 +8697,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. @@ -8442,16 +8718,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; @@ -8463,16 +8742,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/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp index c233bf06cf..e4efde2448 100644 --- a/services/sensorservice/SensorDevice.cpp +++ b/services/sensorservice/SensorDevice.cpp @@ -326,7 +326,7 @@ void SensorDevice::reconnect() { mActivationCount.clear(); mSensorList.clear(); - if (connectHidlServiceV2_0() == HalConnectionStatus::CONNECTED) { + if (connectHidlService()) { initializeSensorList(); if (sensorHandlesChanged(previousSensorList, mSensorList)) { @@ -614,6 +614,8 @@ ssize_t SensorDevice::pollFmq(sensors_event_t* buffer, size_t maxNumEventsToRead Return<void> SensorDevice::onDynamicSensorsConnected( const hidl_vec<SensorInfo> &dynamicSensorsAdded) { + std::unique_lock<std::mutex> lock(mDynamicSensorsMutex); + // Allocate a sensor_t structure for each dynamic sensor added and insert // it into the dictionary of connected dynamic sensors keyed by handle. for (size_t i = 0; i < dynamicSensorsAdded.size(); ++i) { @@ -629,6 +631,8 @@ Return<void> SensorDevice::onDynamicSensorsConnected( std::make_pair(sensor->handle, sensor)); } + mDynamicSensorsCv.notify_all(); + return Return<void>(); } @@ -1174,8 +1178,20 @@ void SensorDevice::convertToSensorEvent( dst->dynamic_sensor_meta.connected = dyn.connected; dst->dynamic_sensor_meta.handle = dyn.sensorHandle; if (dyn.connected) { + std::unique_lock<std::mutex> lock(mDynamicSensorsMutex); + // Give MAX_DYN_SENSOR_WAIT_SEC for onDynamicSensorsConnected to be invoked since it + // can be received out of order from this event due to a bug in the HIDL spec that + // marks it as oneway. auto it = mConnectedDynamicSensors.find(dyn.sensorHandle); - CHECK(it != mConnectedDynamicSensors.end()); + if (it == mConnectedDynamicSensors.end()) { + mDynamicSensorsCv.wait_for(lock, MAX_DYN_SENSOR_WAIT, + [&, dyn]{ + return mConnectedDynamicSensors.find(dyn.sensorHandle) + != mConnectedDynamicSensors.end(); + }); + it = mConnectedDynamicSensors.find(dyn.sensorHandle); + CHECK(it != mConnectedDynamicSensors.end()); + } dst->dynamic_sensor_meta.sensor = it->second; diff --git a/services/sensorservice/SensorDevice.h b/services/sensorservice/SensorDevice.h index 75da7bb0a1..bc8d20fbf6 100644 --- a/services/sensorservice/SensorDevice.h +++ b/services/sensorservice/SensorDevice.h @@ -139,6 +139,14 @@ private: Vector<sensor_t> mSensorList; std::unordered_map<int32_t, sensor_t*> mConnectedDynamicSensors; + // A bug in the Sensors HIDL spec which marks onDynamicSensorsConnected as oneway causes dynamic + // meta events and onDynamicSensorsConnected to be received out of order. This mutex + CV are + // used to block meta event processing until onDynamicSensorsConnected is received to simplify + // HAL implementations. + std::mutex mDynamicSensorsMutex; + std::condition_variable mDynamicSensorsCv; + static constexpr std::chrono::seconds MAX_DYN_SENSOR_WAIT{5}; + static const nsecs_t MINIMUM_EVENTS_PERIOD = 1000000; // 1000 Hz mutable Mutex mLock; // protect mActivationCount[].batchParams // fixed-size array after construction diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp index 13eeb852c7..ce41c3c8c0 100644 --- a/services/surfaceflinger/Android.bp +++ b/services/surfaceflinger/Android.bp @@ -217,6 +217,7 @@ filegroup { "DisplayHardware/ComposerHal.cpp", "DisplayHardware/DisplayIdentification.cpp", "DisplayHardware/FramebufferSurface.cpp", + "DisplayHardware/Hash.cpp", "DisplayHardware/HWC2.cpp", "DisplayHardware/HWComposer.cpp", "DisplayHardware/PowerAdvisor.cpp", @@ -228,6 +229,7 @@ filegroup { "FrameTracer/FrameTracer.cpp", "FrameTracker.cpp", "HdrLayerInfoReporter.cpp", + "WindowInfosListenerInvoker.cpp", "Layer.cpp", "LayerProtoHelper.cpp", "LayerRejecter.cpp", @@ -282,7 +284,6 @@ cc_defaults { "libcutils", "libdisplayservicehidl", "libhidlbase", - "libinput", "liblayers_proto", "liblog", "libprocessgroup", diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp index ddf6f10d2b..28443a64a6 100644 --- a/services/surfaceflinger/BufferLayer.cpp +++ b/services/surfaceflinger/BufferLayer.cpp @@ -61,6 +61,8 @@ namespace android { +using gui::WindowInfo; + static constexpr float defaultMaxLuminance = 1000.0; BufferLayer::BufferLayer(const LayerCreationArgs& args) @@ -426,33 +428,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(); @@ -845,9 +849,9 @@ 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; + cloneDrawingState(clonedFrom.get()); mDrawingState.touchableRegionCrop = tmpTouchableRegionCrop; mDrawingState.zOrderRelativeOf = tmpZOrderRelativeOf; diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp index 795ea959d3..e701fa9ed9 100644 --- a/services/surfaceflinger/BufferQueueLayer.cpp +++ b/services/surfaceflinger/BufferQueueLayer.cpp @@ -516,13 +516,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 930a4ac5c0..aa6bc96768 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -66,7 +66,7 @@ BufferStateLayer::~BufferStateLayer() { // one of the layers, in this case the original layer, needs to handle the deletion. The // original layer and the clone should be removed at the same time so there shouldn't be any // issue with the clone layer trying to use the texture. - if (mBufferInfo.mBuffer != nullptr && !isClone()) { + if (mBufferInfo.mBuffer != nullptr) { callReleaseBufferCallback(mDrawingState.releaseBufferListener, mBufferInfo.mBuffer->getBuffer(), mBufferInfo.mFrameNumber, mBufferInfo.mFence, mTransformHint, @@ -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; } @@ -431,7 +427,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) { @@ -496,6 +493,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 68c7c860b2..4e47e13d51 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h @@ -168,6 +168,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 2938da5cfc..2679bcf7a0 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 0a4bd88353..3791bfeee4 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 fc15bc47a8..a63fd84463 100644 --- a/services/surfaceflinger/CompositionEngine/src/Output.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp @@ -150,6 +150,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(); @@ -823,6 +829,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 4d2315b1ca..7121011529 100644 --- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h +++ b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h @@ -51,9 +51,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 bee0c8cfac..156e799b48 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,10 +68,13 @@ 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), - mIsPowerModeOverride(false){ + mIsPowerModeOverride(false), + mRefreshRateConfigs(std::move(args.refreshRateConfigs)) { mCompositionDisplay->editState().isSecure = args.isSecure; mCompositionDisplay->createRenderSurface( compositionengine::RenderSurfaceCreationArgsBuilder() @@ -156,21 +162,30 @@ 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; resetVsyncPeriod(); + 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 { @@ -247,12 +262,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, @@ -292,7 +318,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, @@ -322,6 +348,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 { @@ -408,6 +438,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 43d8a2a8b2..b1e56d75d6 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -40,17 +40,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; @@ -65,6 +72,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); @@ -79,6 +87,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. @@ -91,6 +102,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; } @@ -103,6 +115,7 @@ public: const Rect& getOrientedDisplaySpaceRect() const; bool needsFiltering() const; ui::LayerStack getLayerStack() const; + bool receivesInput() const { return mFlags & eReceivesInput; } DisplayId getId() const; @@ -173,10 +186,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. @@ -188,6 +219,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; @@ -215,6 +262,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; @@ -235,11 +284,22 @@ 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; bool mIsPowerModeOverride; + + 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 { @@ -262,6 +322,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; @@ -284,6 +345,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; @@ -299,6 +361,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 ecf2492edb..c893d8cd16 100644 --- a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp +++ b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp @@ -324,7 +324,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 5cfe0b84d4..5876077b44 100644 --- a/services/surfaceflinger/DisplayHardware/ComposerHal.h +++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h @@ -101,7 +101,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; @@ -356,7 +356,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/DisplayIdentification.cpp b/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp index 98209bb9e4..83c2b2e789 100644 --- a/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp +++ b/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp @@ -25,6 +25,7 @@ #include <log/log.h> #include "DisplayIdentification.h" +#include "Hash.h" namespace android { namespace { @@ -262,8 +263,9 @@ std::optional<Edid> parseEdid(const DisplayIdentificationData& edid) { } // Hash model string instead of using product code or (integer) serial number, since the latter - // have been observed to change on some displays with multiple inputs. - const auto modelHash = static_cast<uint32_t>(std::hash<std::string_view>()(modelString)); + // have been observed to change on some displays with multiple inputs. Use a stable hash instead + // of std::hash which is only required to be same within a single execution of a program. + const uint32_t modelHash = static_cast<uint32_t>(cityHash64Len0To16(modelString)); // Parse extension blocks. std::optional<Cea861ExtensionBlock> cea861Block; 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 f2ed281207..07de93f49b 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 bbcafc4fd9..9280649627 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.h +++ b/services/surfaceflinger/DisplayHardware/HWComposer.h @@ -117,11 +117,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; @@ -277,8 +273,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/DisplayHardware/Hal.h b/services/surfaceflinger/DisplayHardware/Hal.h index bb2888e0fb..02d065881b 100644 --- a/services/surfaceflinger/DisplayHardware/Hal.h +++ b/services/surfaceflinger/DisplayHardware/Hal.h @@ -166,4 +166,15 @@ inline std::string to_string(hardware::graphics::composer::hal::PowerMode mode) } } +inline std::string to_string(hardware::graphics::composer::hal::Vsync vsync) { + switch (vsync) { + case hardware::graphics::composer::hal::Vsync::ENABLE: + return "Enable"; + case hardware::graphics::composer::hal::Vsync::DISABLE: + return "Disable"; + default: + return "Unknown"; + } +} + } // namespace android diff --git a/services/surfaceflinger/DisplayHardware/Hash.cpp b/services/surfaceflinger/DisplayHardware/Hash.cpp new file mode 100644 index 0000000000..6056c8d6f8 --- /dev/null +++ b/services/surfaceflinger/DisplayHardware/Hash.cpp @@ -0,0 +1,93 @@ +/* + * 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 "DisplayIdentification" + +#include <cstring> +#include <type_traits> + +#include <log/log.h> + +#include "Hash.h" + +namespace android { +namespace { + +template <class T> +inline T load(const void* p) { + static_assert(std::is_integral<T>::value, "T must be integral"); + + T r; + std::memcpy(&r, p, sizeof(r)); + return r; +} + +uint64_t rotateByAtLeast1(uint64_t val, uint8_t shift) { + return (val >> shift) | (val << (64 - shift)); +} + +uint64_t shiftMix(uint64_t val) { + return val ^ (val >> 47); +} + +uint64_t hash64Len16(uint64_t u, uint64_t v) { + constexpr uint64_t kMul = 0x9ddfea08eb382d69; + uint64_t a = (u ^ v) * kMul; + a ^= (a >> 47); + uint64_t b = (v ^ a) * kMul; + b ^= (b >> 47); + b *= kMul; + return b; +} + +uint64_t hash64Len0To16(const char* s, uint64_t len) { + constexpr uint64_t k2 = 0x9ae16a3b2f90404f; + constexpr uint64_t k3 = 0xc949d7c7509e6557; + + if (len > 8) { + const uint64_t a = load<uint64_t>(s); + const uint64_t b = load<uint64_t>(s + len - 8); + return hash64Len16(a, rotateByAtLeast1(b + len, static_cast<uint8_t>(len))) ^ b; + } + if (len >= 4) { + const uint32_t a = load<uint32_t>(s); + const uint32_t b = load<uint32_t>(s + len - 4); + return hash64Len16(len + (a << 3), b); + } + if (len > 0) { + const unsigned char a = static_cast<unsigned char>(s[0]); + const unsigned char b = static_cast<unsigned char>(s[len >> 1]); + const unsigned char c = static_cast<unsigned char>(s[len - 1]); + const uint32_t y = static_cast<uint32_t>(a) + (static_cast<uint32_t>(b) << 8); + const uint32_t z = static_cast<uint32_t>(len) + (static_cast<uint32_t>(c) << 2); + return shiftMix(y * k2 ^ z * k3) * k2; + } + return k2; +} + +} // namespace + +uint64_t cityHash64Len0To16(std::string_view sv) { + auto len = sv.length(); + if (len > 16) { + ALOGE("%s called with length %zu. Only hashing the first 16 chars", __FUNCTION__, len); + len = 16; + } + return hash64Len0To16(sv.data(), len); +} + +} // namespace android
\ No newline at end of file diff --git a/services/surfaceflinger/DisplayHardware/Hash.h b/services/surfaceflinger/DisplayHardware/Hash.h new file mode 100644 index 0000000000..a7b6c717f6 --- /dev/null +++ b/services/surfaceflinger/DisplayHardware/Hash.h @@ -0,0 +1,27 @@ +/* + * 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 <cstdint> +#include <string_view> + +namespace android { + +// CityHash64 implementation that only hashes at most the first 16 characters of the given string. +uint64_t cityHash64Len0To16(std::string_view sv); + +} // namespace android
\ No newline at end of file diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 46d88de810..316144c0d1 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" #include "QtiGralloc.h" #define DEBUG_RESIZE 0 @@ -85,6 +84,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}; @@ -92,8 +92,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; @@ -137,6 +137,7 @@ Layer::Layer(const LayerCreationArgs& args) mDrawingState.postTime = -1; mDrawingState.destinationFrame.makeInvalid(); mDrawingState.isTrustedOverlay = false; + mDrawingState.dropInputMode = gui::DropInputMode::NONE; if (args.flags & ISurfaceComposerClient::eNoColorFill) { // Set an invalid color so there is no color fill. @@ -423,8 +424,6 @@ void Layer::prepareBasicGeometryCompositionState() { compositionState->blendMode = static_cast<Hwc2::IComposerClient::BlendMode>(blendMode); compositionState->alpha = alpha; - compositionState->backgroundBlurRadius = drawingState.backgroundBlurRadius; - compositionState->blurRegions = drawingState.blurRegions; compositionState->stretchEffect = getStretchEffect(); } @@ -505,6 +504,9 @@ void Layer::preparePerFrameCompositionState() { compositionState->stretchEffect.hasEffect()) { compositionState->forceClientComposition = true; } + // If there are no visible region changes, we still need to update blur parameters. + compositionState->blurRegions = drawingState.blurRegions; + compositionState->backgroundBlurRadius = drawingState.backgroundBlurRadius; } void Layer::prepareCursorCompositionState() { @@ -967,8 +969,11 @@ bool Layer::setCornerRadius(float cornerRadius) { bool Layer::setBackgroundBlurRadius(int backgroundBlurRadius) { if (mDrawingState.backgroundBlurRadius == backgroundBlurRadius) return false; - - mDrawingState.sequence++; + // If we start or stop drawing blur then the layer's visibility state may change so increment + // the magic sequence number. + if (mDrawingState.backgroundBlurRadius == 0 || backgroundBlurRadius == 0) { + mDrawingState.sequence++; + } mDrawingState.backgroundBlurRadius = backgroundBlurRadius; mDrawingState.modified = true; setTransactionFlags(eTransactionNeeded); @@ -1001,6 +1006,11 @@ bool Layer::setTransparentRegionHint(const Region& transparent) { } bool Layer::setBlurRegions(const std::vector<BlurRegion>& blurRegions) { + // If we start or stop drawing blur then the layer's visibility state may change so increment + // the magic sequence number. + if (mDrawingState.blurRegions.size() == 0 || blurRegions.size() == 0) { + mDrawingState.sequence++; + } mDrawingState.blurRegions = blurRegions; mDrawingState.modified = true; setTransactionFlags(eTransactionNeeded); @@ -1953,27 +1963,49 @@ const std::vector<BlurRegion> Layer::getBlurRegions() const { } Layer::RoundedCornerState Layer::getRoundedCornerState() const { - const auto& p = mDrawingParent.promote(); - if (p != nullptr) { - RoundedCornerState parentState = p->getRoundedCornerState(); - if (parentState.radius > 0) { + // Get parent settings + RoundedCornerState parentSettings; + const auto& parent = mDrawingParent.promote(); + if (parent != nullptr) { + parentSettings = parent->getRoundedCornerState(); + if (parentSettings.radius > 0) { ui::Transform t = getActiveTransform(getDrawingState()); t = t.inverse(); - parentState.cropRect = t.transform(parentState.cropRect); + parentSettings.cropRect = t.transform(parentSettings.cropRect); // The rounded corners shader only accepts 1 corner radius for performance reasons, // but a transform matrix can define horizontal and vertical scales. // Let's take the average between both of them and pass into the shader, practically we // never do this type of transformation on windows anyway. auto scaleX = sqrtf(t[0][0] * t[0][0] + t[0][1] * t[0][1]); auto scaleY = sqrtf(t[1][0] * t[1][0] + t[1][1] * t[1][1]); - parentState.radius *= (scaleX + scaleY) / 2.0f; - return parentState; + parentSettings.radius *= (scaleX + scaleY) / 2.0f; } } + + // Get layer settings + Rect layerCropRect = getCroppedBufferSize(getDrawingState()); const float radius = getDrawingState().cornerRadius; - return radius > 0 && getCroppedBufferSize(getDrawingState()).isValid() - ? RoundedCornerState(getCroppedBufferSize(getDrawingState()).toFloatRect(), radius) - : RoundedCornerState(); + RoundedCornerState layerSettings(layerCropRect.toFloatRect(), radius); + const bool layerSettingsValid = layerSettings.radius > 0 && layerCropRect.isValid(); + + if (layerSettingsValid && parentSettings.radius > 0) { + // If the parent and the layer have rounded corner settings, use the parent settings if the + // parent crop is entirely inside the layer crop. + // This has limitations and cause rendering artifacts. See b/200300845 for correct fix. + if (parentSettings.cropRect.left > layerCropRect.left && + parentSettings.cropRect.top > layerCropRect.top && + parentSettings.cropRect.right < layerCropRect.right && + parentSettings.cropRect.bottom < layerCropRect.bottom) { + return parentSettings; + } else { + return layerSettings; + } + } else if (layerSettingsValid) { + return layerSettings; + } else if (parentSettings.radius > 0) { + return parentSettings; + } + return {}; } void Layer::prepareShadowClientComposition(LayerFE::LayerSettings& caster, @@ -2019,7 +2051,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; @@ -2058,8 +2090,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()); @@ -2069,10 +2101,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(); }); @@ -2147,8 +2180,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) { @@ -2170,7 +2203,7 @@ void Layer::writeToProtoCommonState(LayerProto* layerInfo, LayerVector::StateSet } if (traceFlags & SurfaceTracing::TRACE_INPUT) { - InputWindowInfo info; + WindowInfo info; if (useDrawing) { info = fillInputInfo({nullptr}); } else { @@ -2201,7 +2234,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 @@ -2218,16 +2251,18 @@ void Layer::fillInputFrameInfo(InputWindowInfo& info, const ui::Transform& toPhy info.frameRight = 0; info.frameBottom = 0; info.transform.reset(); + info.touchableRegion = Region(); + info.flags = WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::NOT_FOCUSABLE; return; } 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(); @@ -2296,7 +2331,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(); @@ -2306,32 +2341,115 @@ void Layer::fillTouchOcclusionMode(InputWindowInfo& info) { } } -InputWindowInfo Layer::fillInputInfo(const sp<DisplayDevice>& display) { +gui::DropInputMode Layer::getDropInputMode() const { + gui::DropInputMode mode = mDrawingState.dropInputMode; + if (mode == gui::DropInputMode::ALL) { + return mode; + } + sp<Layer> parent = mDrawingParent.promote(); + if (parent) { + gui::DropInputMode parentMode = parent->getDropInputMode(); + if (parentMode != gui::DropInputMode::NONE) { + return parentMode; + } + } + return mode; +} + +void Layer::handleDropInputMode(gui::WindowInfo& info) const { + if (mDrawingState.inputInfo.inputFeatures.test(WindowInfo::Feature::NO_INPUT_CHANNEL)) { + return; + } + + // Check if we need to drop input unconditionally + gui::DropInputMode dropInputMode = getDropInputMode(); + if (dropInputMode == gui::DropInputMode::ALL) { + info.inputFeatures |= WindowInfo::Feature::DROP_INPUT; + ALOGV("Dropping input for %s as requested by policy.", getDebugName()); + return; + } + + // Check if we need to check if the window is obscured by parent + if (dropInputMode != gui::DropInputMode::OBSCURED) { + return; + } + + // Check if the parent has set an alpha on the layer + sp<Layer> parent = mDrawingParent.promote(); + if (parent && parent->getAlpha() != 1.0_hf) { + info.inputFeatures |= WindowInfo::Feature::DROP_INPUT; + ALOGV("Dropping input for %s as requested by policy because alpha=%f", getDebugName(), + static_cast<float>(getAlpha())); + } + + // Check if the parent has cropped the buffer + Rect bufferSize = getCroppedBufferSize(getDrawingState()); + if (!bufferSize.isValid()) { + info.inputFeatures |= WindowInfo::Feature::DROP_INPUT_IF_OBSCURED; + return; + } + + // Screenbounds are the layer bounds cropped by parents, transformed to screenspace. + // To check if the layer has been cropped, we take the buffer bounds, apply the local + // layer crop and apply the same set of transforms to move to screenspace. If the bounds + // match then the layer has not been cropped by its parents. + Rect bufferInScreenSpace(getTransform().transform(bufferSize)); + bool croppedByParent = bufferInScreenSpace != Rect{mScreenBounds}; + + if (croppedByParent) { + info.inputFeatures |= WindowInfo::Feature::DROP_INPUT; + ALOGV("Dropping input for %s as requested by policy because buffer is cropped by parent", + getDebugName()); + } else { + // If the layer is not obscured by its parents (by setting an alpha or crop), then only drop + // input if the window is obscured. This check should be done in surfaceflinger but the + // logic currently resides in inputflinger. So pass the if_obscured check to input to only + // drop input events if the window is obscured. + info.inputFeatures |= WindowInfo::Feature::DROP_INPUT_IF_OBSCURED; + } +} + +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 @@ -2344,18 +2462,19 @@ InputWindowInfo Layer::fillInputInfo(const sp<DisplayDevice>& display) { info.visible = hasInputInfo() ? canReceiveInput() : isVisible(); info.alpha = getAlpha(); fillTouchOcclusionMode(info); + handleDropInputMode(info); 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 @@ -2368,7 +2487,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); } } @@ -2406,8 +2525,7 @@ Region Layer::getVisibleRegion(const DisplayDevice* display) const { } void Layer::setInitialValuesForClone(const sp<Layer>& clonedFrom) { - // copy drawing state from cloned layer - mDrawingState = clonedFrom->mDrawingState; + cloneDrawingState(clonedFrom.get()); mClonedFrom = clonedFrom; } @@ -2442,7 +2560,7 @@ void Layer::updateClonedDrawingState(std::map<sp<Layer>, sp<Layer>>& clonedLayer // since we may be able to pull out other children that are still alive. if (isClonedFromAlive()) { sp<Layer> clonedFrom = getClonedFrom(); - mDrawingState = clonedFrom->mDrawingState; + cloneDrawingState(clonedFrom.get()); clonedLayersMap.emplace(clonedFrom, this); } @@ -2495,7 +2613,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) { @@ -2601,6 +2719,21 @@ wp<Layer> Layer::fromHandle(const sp<IBinder>& handleBinder) { return handle->owner; } +bool Layer::setDropInputMode(gui::DropInputMode mode) { + if (mDrawingState.dropInputMode == mode) { + return false; + } + mDrawingState.dropInputMode = mode; + return true; +} + +void Layer::cloneDrawingState(const Layer* from) { + mDrawingState = from->mDrawingState; + // Skip callback info since they are not applicable for cloned layers. + mDrawingState.releaseBufferListener = nullptr; + mDrawingState.callbackHandles = {}; +} + // --------------------------------------------------------------------------- std::ostream& operator<<(std::ostream& stream, const Layer::FrameRate& rate) { diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 0365efbe06..512dd6e5d3 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -17,11 +17,12 @@ #pragma once +#include <android/gui/DropInputMode.h> #include <compositionengine/LayerFE.h> #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 +187,7 @@ public: float cornerRadius; int backgroundBlurRadius; - InputWindowInfo inputInfo; + gui::WindowInfo inputInfo; wp<Layer> touchableRegionCrop; // dataspace is only used by BufferStateLayer and EffectLayer @@ -280,6 +281,10 @@ public: Rect bufferCrop; Rect destinationFrame; + + sp<IBinder> releaseBufferEndpoint; + + gui::DropInputMode dropInputMode; }; /* @@ -422,7 +427,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; }; @@ -444,6 +450,8 @@ public: virtual bool setFrameRateSelectionPriority(int32_t priority); virtual bool setFixedTransformHint(ui::Transform::RotationFlags fixedTransformHint); virtual void setAutoRefresh(bool /* autoRefresh */) {} + bool setDropInputMode(gui::DropInputMode); + // If the variable is not set on the layer, it traverses up the tree to inherit the frame // rate priority from its parent. virtual int32_t getFrameRateSelectionPriority() const; @@ -604,10 +612,8 @@ public: virtual bool getTransformToDisplayInverse() const { return false; } // Returns how rounded corners should be drawn for this layer. - // This will traverse the hierarchy until it reaches its root, finding topmost rounded - // corner definition and converting it into current layer's coordinates. - // As of now, only 1 corner radius per display list is supported. Subsequent ones will be - // ignored. + // A layer can override its parent's rounded corner settings if the parent's rounded + // corner crop does not intersect with its own rounded corner crop. virtual RoundedCornerState getRoundedCornerState() const; bool hasRoundedCorners() const override { return getRoundedCornerState().radius > .0f; } @@ -701,7 +707,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; @@ -852,9 +858,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. */ @@ -929,6 +935,7 @@ protected: bool isClone() { return mClonedFrom != nullptr; } bool isClonedFromAlive() { return getClonedFrom() != nullptr; } + void cloneDrawingState(const Layer* from); void updateClonedDrawingState(std::map<sp<Layer>, sp<Layer>>& clonedLayersMap); void updateClonedChildren(const sp<Layer>& mirrorRoot, std::map<sp<Layer>, sp<Layer>>& clonedLayersMap); @@ -1024,7 +1031,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,6 +1074,8 @@ private: bool setFrameRateForLayerTree(FrameRate); void setZOrderRelativeOf(const wp<Layer>& relativeOf); bool isTrustedOverlay() const; + gui::DropInputMode getDropInputMode() const; + void handleDropInputMode(gui::WindowInfo& info) const; // Find the root of the cloned hierarchy, this means the first non cloned parent. // This will return null if first non cloned parent is not found. @@ -1078,10 +1087,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/LayerRenderArea.cpp b/services/surfaceflinger/LayerRenderArea.cpp index e84508febc..11fe6d0755 100644 --- a/services/surfaceflinger/LayerRenderArea.cpp +++ b/services/surfaceflinger/LayerRenderArea.cpp @@ -94,8 +94,22 @@ void LayerRenderArea::render(std::function<void()> drawLayers) { // no need to check rotation because there is none mNeedsFiltering = sourceCrop.width() != getReqWidth() || sourceCrop.height() != getReqHeight(); + // If layer is offscreen, update mirroring info if it exists + if (mLayer->isRemovedFromCurrentState()) { + mLayer->traverse(LayerVector::StateSet::Drawing, + [&](Layer* layer) { layer->updateMirrorInfo(); }); + mLayer->traverse(LayerVector::StateSet::Drawing, + [&](Layer* layer) { layer->updateCloneBufferInfo(); }); + } + if (!mChildrenOnly) { mTransform = mLayer->getTransform().inverse(); + // If the layer is offscreen, compute bounds since we don't compute bounds for offscreen + // layers in a regular cycles. + if (mLayer->isRemovedFromCurrentState()) { + FloatRect maxBounds = mFlinger.getMaxDisplayBounds(); + mLayer->computeBounds(maxBounds, ui::Transform(), 0.f /* shadowRadius */); + } drawLayers(); } else { uint32_t w = static_cast<uint32_t>(getWidth()); 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 6a58cbe0f4..10b20b5a03 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 39e951affa..9a899c37d8 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"); - auto vote = info->getRefreshRateVote(now); + 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 3c62011146..995e5e9ad1 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 43b536b9de..c66af84e03 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp @@ -22,6 +22,7 @@ #pragma clang diagnostic ignored "-Wextra" #include "RefreshRateConfigs.h" +#include <android-base/properties.h> #include <android-base/stringprintf.h> #include <utils/Trace.h> #include <chrono> @@ -113,7 +114,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 +147,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 +464,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; @@ -683,9 +684,30 @@ void RefreshRateConfigs::setCurrentModeId(DisplayModeId modeId) { RefreshRateConfigs::RefreshRateConfigs(const DisplayModes& modes, DisplayModeId currentModeId, Config config) : mKnownFrameRates(constructKnownFrameRates(modes)), mConfig(config) { + initializeIdleTimer(); updateDisplayModes(modes, currentModeId); } +void RefreshRateConfigs::initializeIdleTimer() { + if (mConfig.idleTimerTimeoutMs > 0) { + const auto getCallback = [this]() -> std::optional<IdleTimerCallbacks::Callbacks> { + std::scoped_lock lock(mIdleTimerCallbacksMutex); + if (!mIdleTimerCallbacks.has_value()) return {}; + return mConfig.supportKernelIdleTimer ? mIdleTimerCallbacks->kernel + : mIdleTimerCallbacks->platform; + }; + + mIdleTimer.emplace( + "IdleTimer", std::chrono::milliseconds(mConfig.idleTimerTimeoutMs), + [getCallback] { + if (const auto callback = getCallback()) callback->onReset(); + }, + [getCallback] { + if (const auto callback = getCallback()) callback->onExpired(); + }); + } +} + void RefreshRateConfigs::updateDisplayModes(const DisplayModes& modes, DisplayModeId currentModeId) { std::lock_guard lock(mLock); @@ -703,8 +725,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(); } @@ -797,7 +818,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; } } @@ -812,7 +833,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()); } } @@ -949,6 +970,9 @@ void RefreshRateConfigs::dump(std::string& result) const { base::StringAppendF(&result, "Supports Frame Rate Override: %s\n", mSupportsFrameRateOverride ? "yes" : "no"); + base::StringAppendF(&result, "Idle timer: (%s) %s\n", + mConfig.supportKernelIdleTimer ? "kernel" : "platform", + mIdleTimer ? mIdleTimer->dump().c_str() : "off"); result.append("\n"); } diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h index a4680526ec..dfb0ffba34 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h @@ -27,6 +27,7 @@ #include "DisplayHardware/DisplayMode.h" #include "DisplayHardware/HWComposer.h" #include "Fps.h" +#include "Scheduler/OneShotTimer.h" #include "Scheduler/SchedulerUtils.h" #include "Scheduler/Seamlessness.h" #include "Scheduler/StrongTyping.h" @@ -64,25 +65,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 +98,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 = @@ -313,13 +309,19 @@ public: // or heuristic, such that refresh rates higher than this value will not be voted for. 0 if // no threshold is set. int frameRateMultipleThreshold = 0; + + // The Idle Timer timeout. 0 timeout means no idle timer. + int32_t idleTimerTimeoutMs = 0; + + // Whether to use idle timer callbacks that support the kernel timer. + bool supportKernelIdleTimer = false; }; - RefreshRateConfigs(const DisplayModes& modes, DisplayModeId currentModeId, + RefreshRateConfigs(const DisplayModes&, DisplayModeId, Config config = {.enableFrameRateOverride = false, - .frameRateMultipleThreshold = 0}); - - void updateDisplayModes(const DisplayModes& mode, DisplayModeId currentModeId) EXCLUDES(mLock); + .frameRateMultipleThreshold = 0, + .idleTimerTimeoutMs = 0, + .supportKernelIdleTimer = false}); // 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 @@ -355,8 +357,47 @@ public: Fps displayFrameRate, bool touch) const EXCLUDES(mLock); + bool supportsKernelIdleTimer() const { return mConfig.supportKernelIdleTimer; } + + void setIdleTimerCallbacks(std::function<void()> platformTimerReset, + std::function<void()> platformTimerExpired, + std::function<void()> kernelTimerReset, + std::function<void()> kernelTimerExpired) { + std::scoped_lock lock(mIdleTimerCallbacksMutex); + mIdleTimerCallbacks.emplace(); + mIdleTimerCallbacks->platform.onReset = std::move(platformTimerReset); + mIdleTimerCallbacks->platform.onExpired = std::move(platformTimerExpired); + mIdleTimerCallbacks->kernel.onReset = std::move(kernelTimerReset); + mIdleTimerCallbacks->kernel.onExpired = std::move(kernelTimerExpired); + } + + void startIdleTimer() { + if (mIdleTimer) { + mIdleTimer->start(); + } + } + + void stopIdleTimer() { + if (mIdleTimer) { + mIdleTimer->stop(); + } + } + + void resetIdleTimer(bool kernelOnly) { + if (!mIdleTimer) { + return; + } + if (kernelOnly && !mConfig.supportKernelIdleTimer) { + return; + } + mIdleTimer->reset(); + }; + void dump(std::string& result) const EXCLUDES(mLock); + RefreshRateConfigs(const RefreshRateConfigs&) = delete; + void operator=(const RefreshRateConfigs&) = delete; + private: friend class RefreshRateConfigsTest; @@ -408,6 +449,10 @@ private: float calculateLayerScoreLocked(const LayerRequirement&, const RefreshRate&, bool isSeamlessSwitch) const REQUIRES(mLock); + void updateDisplayModes(const DisplayModes& mode, DisplayModeId currentModeId) EXCLUDES(mLock); + + void initializeIdleTimer(); + // The list of refresh rates, indexed by display modes ID. This may change after this // object is initialized. AllRefreshRatesMapType mRefreshRates GUARDED_BY(mLock); @@ -451,6 +496,22 @@ private: }; mutable std::optional<GetBestRefreshRateInvocation> lastBestRefreshRateInvocation GUARDED_BY(mLock); + + // Timer that records time between requests for next vsync. + std::optional<scheduler::OneShotTimer> mIdleTimer; + + struct IdleTimerCallbacks { + struct Callbacks { + std::function<void()> onReset; + std::function<void()> onExpired; + }; + + Callbacks platform; + Callbacks kernel; + }; + + std::mutex mIdleTimerCallbacksMutex; + std::optional<IdleTimerCallbacks> mIdleTimerCallbacks GUARDED_BY(mIdleTimerCallbacksMutex); }; } // namespace android::scheduler diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index 7195b6c68a..d1bfebf7df 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,30 +117,18 @@ 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)}) { + {.useContentDetection = sysprop::use_content_detection_for_refresh_rate(false)}) { } -Scheduler::Scheduler(const scheduler::RefreshRateConfigs& configs, ISchedulerCallback& callback, - Options options) - : Scheduler(createVsyncSchedule(options.supportKernelTimer), configs, callback, - createLayerHistory(configs), options) { +Scheduler::Scheduler(const std::shared_ptr<scheduler::RefreshRateConfigs>& configs, + ISchedulerCallback& callback, Options options) + : Scheduler(createVsyncSchedule(configs->supportsKernelIdleTimer()), configs, callback, + createLayerHistory(), options) { using namespace sysprop; - const int setIdleTimerMs = base::GetIntProperty("debug.sf.set_idle_timer_ms"s, 0); - - if (const auto millis = setIdleTimerMs ? setIdleTimerMs : set_idle_timer_ms(0); millis > 0) { - const auto callback = mOptions.supportKernelTimer ? &Scheduler::kernelIdleTimerCallback - : &Scheduler::idleTimerCallback; - mIdleTimer.emplace( - "IdleTimer", std::chrono::milliseconds(millis), - [this, callback] { std::invoke(callback, this, TimerState::Reset); }, - [this, callback] { std::invoke(callback, this, TimerState::Expired); }); - mIdleTimer->start(); - } - if (const int64_t millis = set_touch_timer_ms(0); millis > 0) { // Touch events are coming to SF every 100ms, so the timer needs to be higher than that mTouchTimer.emplace( @@ -157,18 +147,19 @@ 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), mVsyncSchedule(std::move(schedule)), mLayerHistory(std::move(layerHistory)), mSchedulerCallback(schedulerCallback), - mRefreshRateConfigs(configs), mPredictedVsyncTracer( base::GetBoolProperty("debug.sf.show_predicted_vsync", false) ? std::make_unique<PredictedVsyncTracer>(*mVsyncSchedule.dispatch) : nullptr) { + setRefreshRateConfigs(configs); mSchedulerCallback.setVsyncEnabled(false); } @@ -176,7 +167,7 @@ Scheduler::~Scheduler() { // Ensure the OneShotTimer threads are joined before we start destroying state. mDisplayPowerTimer.reset(); mTouchTimer.reset(); - mIdleTimer.reset(); + mRefreshRateConfigs.reset(); } Scheduler::VsyncSchedule Scheduler::createVsyncSchedule(bool supportKernelTimer) { @@ -192,9 +183,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 +195,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 +230,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 +242,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; } @@ -335,6 +333,7 @@ void Scheduler::onScreenAcquired(ConnectionHandle handle) { thread = mConnections[handle].thread.get(); } thread->onScreenAcquired(); + mScreenAcquired = true; } void Scheduler::onScreenReleased(ConnectionHandle handle) { @@ -345,12 +344,13 @@ void Scheduler::onScreenReleased(ConnectionHandle handle) { thread = mConnections[handle].thread.get(); } thread->onScreenReleased(); + mScreenAcquired = false; } 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()}); } @@ -369,23 +369,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; } @@ -394,39 +393,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) { @@ -547,7 +539,10 @@ void Scheduler::resyncAndRefresh() { } ATRACE_CALL(); - const auto& refreshRate = mRefreshRateConfigs.getCurrentRefreshRate(); + const auto refreshRate = [&] { + std::scoped_lock lock(mRefreshRateConfigsLock); + return mRefreshRateConfigs->getCurrentRefreshRate(); + }(); mSchedulerCallback.repaintEverythingForHWC(); resyncToHardwareVsync(true /* makeAvailable */, refreshRate.getVsyncPeriod(), true); mDisplayIdle = false; @@ -560,7 +555,12 @@ void Scheduler::resync() { const nsecs_t last = mLastResyncTime.exchange(now); if (now - last > kIgnoreDelay) { - resyncToHardwareVsync(false, mSchedulerCallback.getVsyncPeriodFromHWCcb()); + const auto vsyncPeriod = [&] { + // b/223439401: Add the right lock for getVsyncPeriodFromHWCcb + //std::scoped_lock lock(mRefreshRateConfigsLock); + return mSchedulerCallback.getVsyncPeriodFromHWCcb(); + }(); + resyncToHardwareVsync(false, vsyncPeriod); } } @@ -609,10 +609,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 { @@ -631,9 +630,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) { @@ -641,25 +643,30 @@ 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); + const RefreshRate& newRefreshRate = + refreshRateConfigs->getRefreshRateFromModeId(newMode->getId()); + 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) { @@ -667,27 +674,27 @@ void Scheduler::chooseRefreshRateForContent() { } frameRateChanged = false; } else { - mFeatures.modeId = newModeId; + mFeatures.mode = newMode; if (mThermalFps > 0 && (int32_t)newRefreshRate.getFps().getValue() > (int32_t)mThermalFps) { DisplayModePtr mode; mSchedulerCallback.getModeFromFps(mThermalFps, mode); - mFeatures.modeId = mode->getId(); + mFeatures.mode = mode; } frameRateChanged = true; } } if (frameRateChanged) { - auto newRefreshRate = mRefreshRateConfigs.getRefreshRateFromModeId(newModeId); - + const RefreshRate& newRefreshRate = + refreshRateConfigs->getRefreshRateFromModeId(newMode->getId()); if (mThermalFps > 0 && (int32_t)newRefreshRate.getFps().getValue() > (int32_t)mThermalFps) { DisplayModePtr mode; mSchedulerCallback.getModeFromFps(mThermalFps, mode); - auto newThermalRefreshRate = mRefreshRateConfigs. - getRefreshRateFromModeId(mode->getId()); + auto newThermalRefreshRate = + refreshRateConfigs->getRefreshRateFromModeId(mode->getId()); mSchedulerCallback.changeRefreshRate(newThermalRefreshRate, consideredSignals.idle ? ModeEvent::None : ModeEvent::Changed); @@ -703,18 +710,16 @@ void Scheduler::chooseRefreshRateForContent() { } void Scheduler::resetIdleTimer() { - if (mIdleTimer) { - mIdleTimer->reset(); - } + std::scoped_lock lock(mRefreshRateConfigsLock); + mRefreshRateConfigs->resetIdleTimer(/*kernelOnly*/ false); } void Scheduler::notifyTouchEvent() { if (mTouchTimer) { mTouchTimer->reset(); - if (mOptions.supportKernelTimer && mIdleTimer) { - mIdleTimer->reset(); - } + std::scoped_lock lock(mRefreshRateConfigsLock); + mRefreshRateConfigs->resetIdleTimer(/*kernelOnly*/ true); } } @@ -738,7 +743,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)) { @@ -784,7 +793,6 @@ void Scheduler::displayPowerTimerCallback(TimerState state) { void Scheduler::dump(std::string& result) const { using base::StringAppendF; - StringAppendF(&result, "+ Idle timer: %s\n", mIdleTimer ? mIdleTimer->dump().c_str() : "off"); StringAppendF(&result, "+ Touch timer: %s\n", mTouchTimer ? mTouchTimer->dump().c_str() : "off"); StringAppendF(&result, "+ Content detection: %s %s\n\n", @@ -792,7 +800,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()); @@ -805,6 +813,13 @@ void Scheduler::dump(std::string& result) const { } StringAppendF(&result, "}\n"); } + + { + std::lock_guard lock(mHWVsyncLock); + StringAppendF(&result, + "mScreenAcquired=%d mPrimaryHWVsyncEnabled=%d mHWVsyncAvailable=%d\n", + mScreenAcquired.load(), mPrimaryHWVsyncEnabled, mHWVsyncAvailable); + } } void Scheduler::dumpVsync(std::string& s) const { @@ -818,16 +833,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) { @@ -842,48 +858,50 @@ 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); + const RefreshRate& newRefreshRate = + refreshRateConfigs->getRefreshRateFromModeId(newMode->getId()); + 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; if (mThermalFps > 0 && (int32_t)newRefreshRate.getFps().getValue() > (int32_t)mThermalFps) { DisplayModePtr mode; mSchedulerCallback.getModeFromFps(mThermalFps, mode); - mFeatures.modeId = mode->getId(); + mFeatures.mode = mode; } refreshRateChanged = true; } } if (refreshRateChanged) { - const RefreshRate& newRefreshRate = mRefreshRateConfigs.getRefreshRateFromModeId(newModeId); + const RefreshRate& newRefreshRate = + refreshRateConfigs->getRefreshRateFromModeId(newMode->getId()); if (mThermalFps > 0 && (int32_t)newRefreshRate.getFps().getValue() > (int32_t)mThermalFps) { DisplayModePtr mode; mSchedulerCallback.getModeFromFps(mThermalFps, mode); - auto newThermalRefreshRate = mRefreshRateConfigs. - getRefreshRateFromModeId(mode->getId()); + auto newThermalRefreshRate = + refreshRateConfigs->getRefreshRateFromModeId(mode->getId()); mSchedulerCallback.changeRefreshRate(newThermalRefreshRate, consideredSignals.idle ? ModeEvent::None : ModeEvent::Changed); @@ -899,35 +917,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; + const bool idle = 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) { @@ -963,7 +982,7 @@ void Scheduler::onDisplayRefreshed(nsecs_t timestamp) { } } -void Scheduler::onPrimaryDisplayAreaChanged(uint32_t displayArea) { +void Scheduler::onActiveDisplayAreaChanged(uint32_t displayArea) { mLayerHistory->setDisplayArea(displayArea); } @@ -972,7 +991,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 3b3f5f1f14..a5067ce59c 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -74,7 +74,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; @@ -89,15 +89,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, @@ -118,7 +116,7 @@ public: // no-op. // The period is the vsync period from the current display configuration. void resyncToHardwareVsync(bool makeAvailable, nsecs_t period, bool force_resync = false); - void resync(); + void resync() EXCLUDES(mRefreshRateConfigsLock); void resyncAndRefresh(); // Passes a vsync sample to VsyncController. periodFlushed will be true if @@ -130,14 +128,14 @@ 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(); void handleIdleTimeout(bool enable) { mHandleIdleTimeout = enable; } @@ -151,7 +149,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; @@ -160,7 +158,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); @@ -169,7 +167,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); @@ -180,12 +178,49 @@ 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) { + // We need to stop the idle timer on the previous RefreshRateConfigs instance + // and cleanup the scheduler's state before we switch to the other RefreshRateConfigs. + { + std::scoped_lock lock(mRefreshRateConfigsLock); + if (mRefreshRateConfigs) mRefreshRateConfigs->stopIdleTimer(); + } + { + std::scoped_lock lock(mFeatureStateLock); + mFeatures = {}; + } + { + std::scoped_lock lock(mRefreshRateConfigsLock); + mRefreshRateConfigs = std::move(refreshRateConfigs); + mRefreshRateConfigs->setIdleTimerCallbacks( + [this] { std::invoke(&Scheduler::idleTimerCallback, this, TimerState::Reset); }, + [this] { + std::invoke(&Scheduler::idleTimerCallback, this, TimerState::Expired); + }, + [this] { + std::invoke(&Scheduler::kernelIdleTimerCallback, this, TimerState::Reset); + }, + [this] { + std::invoke(&Scheduler::kernelIdleTimerCallback, this, TimerState::Expired); + }); + mRefreshRateConfigs->startIdleTimer(); + } + } + + nsecs_t getVsyncPeriodFromRefreshRateConfigs() const EXCLUDES(mRefreshRateConfigsLock) { + std::scoped_lock lock(mRefreshRateConfigsLock); + return mRefreshRateConfigs->getCurrentRefreshRate().getVsyncPeriod(); + } + void setIdleState(); void updateThermalFps(float fps); - private: friend class TestableScheduler; @@ -196,8 +231,6 @@ private: enum class TouchState { Inactive, Active }; struct Options { - // Whether to use idle timer callbacks that support the kernel timer. - bool supportKernelTimer; // Whether to use content detection at all. bool useContentDetection; }; @@ -209,14 +242,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>, bool triggerRefresh); @@ -224,7 +257,7 @@ private: 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); @@ -238,18 +271,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; @@ -264,7 +304,7 @@ private: InjectVSyncSource* mVSyncInjector = nullptr; ConnectionHandle mInjectorConnectionHandle; - std::mutex mHWVsyncLock; + mutable std::mutex mHWVsyncLock; bool mPrimaryHWVsyncEnabled GUARDED_BY(mHWVsyncLock) = false; bool mHWVsyncAvailable GUARDED_BY(mHWVsyncLock) = false; @@ -276,8 +316,6 @@ private: // Used to choose refresh rate if content detection is enabled. std::unique_ptr<LayerHistory> mLayerHistory; - // Timer that records time between requests for next vsync. - std::optional<scheduler::OneShotTimer> mIdleTimer; // Timer used to monitor touch events. std::optional<scheduler::OneShotTimer> mTouchTimer; // Timer used to monitor display power mode. @@ -294,7 +332,7 @@ private: TouchState touch = TouchState::Inactive; TimerState displayPowerTimer = TimerState::Expired; - std::optional<DisplayModeId> modeId; + DisplayModePtr mode; LayerHistory::Summary contentRequirements; bool isDisplayPowerStateNormal = true; @@ -302,15 +340,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 @@ -321,14 +359,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); // This flag indicates display in idle. Refresh as and when vsync is requested. bool mDisplayIdle; @@ -337,6 +375,9 @@ private: // Cache thermal Fps, and limit to the given level float mThermalFps = 0.0f; + + // Keeps track of whether the screen is acquired for debug + std::atomic<bool> mScreenAcquired = false; }; } // namespace android diff --git a/services/surfaceflinger/Scheduler/VSyncReactor.cpp b/services/surfaceflinger/Scheduler/VSyncReactor.cpp index 7b5d4626dc..ee973f718a 100644 --- a/services/surfaceflinger/Scheduler/VSyncReactor.cpp +++ b/services/surfaceflinger/Scheduler/VSyncReactor.cpp @@ -42,6 +42,7 @@ VSyncReactor::VSyncReactor(std::unique_ptr<Clock> clock, VSyncTracker& tracker, : mClock(std::move(clock)), mTracker(tracker), mPendingLimit(pendingFenceLimit), + // TODO(adyabr): change mSupportKernelIdleTimer when the active display changes mSupportKernelIdleTimer(supportKernelIdleTimer) {} VSyncReactor::~VSyncReactor() = default; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 05340a7678..20efaca251 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -36,7 +36,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> @@ -122,6 +121,7 @@ #include "FrameTracer/FrameTracer.h" #include "HdrLayerInfoReporter.h" #include "Layer.h" +#include "LayerProtoHelper.h" #include "LayerRenderArea.h" #include "LayerVector.h" #include "MonitoredProducer.h" @@ -140,6 +140,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" @@ -166,6 +167,13 @@ class ClientInterface; return (expr); \ }() +#define MAIN_THREAD_GUARD(expr) \ + [&] { \ + LOG_FATAL_IF(std::this_thread::get_id() != mMainThreadId); \ + MainThreadScopedGuard lock(SF_MAIN_THREAD); \ + return (expr); \ + }() + // TODO(b/157175504): Restore NO_THREAD_SAFETY_ANALYSIS prohibition and fix all // identified issues. //#undef NO_THREAD_SAFETY_ANALYSIS @@ -191,6 +199,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; @@ -351,20 +361,40 @@ class DisplayConfigAidlCallbackHandler: public BnDisplayConfigCallback { #endif } // namespace anonymous -struct SetInputWindowsListener : os::BnSetInputWindowsListener { - explicit SetInputWindowsListener(std::function<void()> listenerCb) : mListenerCb(listenerCb) {} +struct IdleTimerConfig { + int32_t timeoutMs; + bool supportKernelIdleTimer; +}; - binder::Status onSetInputWindowsFinished() override; +IdleTimerConfig getIdleTimerConfiguration(DisplayId displayId) { + // TODO(adyabr): use ro.surface_flinger.* namespace - std::function<void()> mListenerCb; -}; + const auto displayIdleTimerMsKey = [displayId] { + std::stringstream ss; + ss << "debug.sf.set_idle_timer_ms_" << displayId.value; + return ss.str(); + }(); + + const auto displaySupportKernelIdleTimerKey = [displayId] { + std::stringstream ss; + ss << "debug.sf.support_kernel_idle_timer_" << displayId.value; + return ss.str(); + }(); + + const int32_t displayIdleTimerMs = base::GetIntProperty(displayIdleTimerMsKey, 0); + const auto displaySupportKernelIdleTimer = + base::GetBoolProperty(displaySupportKernelIdleTimerKey, false); -binder::Status SetInputWindowsListener::onSetInputWindowsFinished() { - if (mListenerCb != nullptr) { - mListenerCb(); + if (displayIdleTimerMs > 0) { + return {displayIdleTimerMs, displaySupportKernelIdleTimer}; } - return binder::Status::ok(); -} + + const int32_t setIdleTimerMs = base::GetIntProperty("debug.sf.set_idle_timer_ms", 0); + const int32_t millis = setIdleTimerMs ? setIdleTimerMs : sysprop::set_idle_timer_ms(0); + + return {millis, sysprop::support_kernel_idle_timer(false)}; + +} // namespace anonymous // --------------------------------------------------------------------------- @@ -543,10 +573,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) { @@ -718,8 +747,6 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipI #endif } #endif - mKernelIdleTimerEnabled = mSupportKernelIdleTimer = sysprop::support_kernel_idle_timer(false); - base::SetProperty(KERNEL_IDLE_TIMER_PROP, mKernelIdleTimerEnabled ? "true" : "false"); mRefreshRateOverlaySpinner = property_get_bool("sf.debug.show_refresh_rate_overlay_spinner", 0); @@ -861,20 +888,11 @@ void SurfaceFlinger::enableHalVirtualDisplays(bool enable) { } VirtualDisplayId SurfaceFlinger::acquireVirtualDisplay(ui::Size resolution, ui::PixelFormat format, - ui::LayerStack layerStack, bool canAllocateHwcForVDS) { auto& generator = mVirtualDisplayIdGenerators.hal; if (canAllocateHwcForVDS && generator) { 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; } @@ -904,20 +922,18 @@ void SurfaceFlinger::releaseVirtualDisplay(VirtualDisplayId displayId) { mVirtualDisplayIdGenerators.gpu.releaseId(*id); } -std::vector<PhysicalDisplayId> SurfaceFlinger::getPhysicalDisplayIds() const { - Mutex::Autolock lock(mStateLock); - - const auto internalDisplayId = getInternalDisplayIdLocked(); - if (!internalDisplayId) { +std::vector<PhysicalDisplayId> SurfaceFlinger::getPhysicalDisplayIdsLocked() const { + const auto display = getDefaultDisplayDeviceLocked(); + if (!display) { return {}; } std::vector<PhysicalDisplayId> displayIds; displayIds.reserve(mPhysicalDisplayTokens.size()); - displayIds.push_back(*internalDisplayId); + displayIds.push_back(display->getPhysicalId()); for (const auto& [id, token] : mPhysicalDisplayTokens) { - if (id != *internalDisplayId) { + if (id != display->getPhysicalId()) { displayIds.push_back(id); } } @@ -925,6 +941,17 @@ std::vector<PhysicalDisplayId> SurfaceFlinger::getPhysicalDisplayIds() const { return displayIds; } +status_t SurfaceFlinger::getPrimaryPhysicalDisplayId(PhysicalDisplayId* id) const { + Mutex::Autolock lock(mStateLock); + const auto display = getInternalDisplayIdLocked(); + if (!display) { + return NAME_NOT_FOUND; + } + + *id = *display; + return NO_ERROR; +} + sp<IBinder> SurfaceFlinger::getPhysicalDisplayToken(PhysicalDisplayId displayId) const { Mutex::Autolock lock(mStateLock); return getPhysicalDisplayTokenLocked(displayId); @@ -1000,7 +1027,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)); } if (mUseFbScaling) { Mutex::Autolock _l(mStateLock); @@ -1082,6 +1109,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"})) { @@ -1136,7 +1165,7 @@ void SurfaceFlinger::init() { } } - getRenderEngine().onPrimaryDisplaySizeChanged(display->getSize()); + onActiveDisplaySizeChanged(display); // Inform native graphics APIs whether the present timestamp is supported: @@ -1234,7 +1263,8 @@ void SurfaceFlinger::createSmomoInstance(const DisplayDeviceState& state) { setRefreshRateTo(refreshRate); }); - setRefreshRates(mRefreshRateConfigs); + // b/223439401 Fix the following value-add + // setRefreshRates(mRefreshRateConfigs); if (mSmomoInstances.size() > 1) { // Disable DRC on all instances. @@ -1315,14 +1345,6 @@ void SurfaceFlinger::startBootAnim() { } } -size_t SurfaceFlinger::getMaxTextureSize() const { - return getRenderEngine().getMaxTextureSize(); -} - -size_t SurfaceFlinger::getMaxViewportDims() const { - return getRenderEngine().getMaxViewportDims(); -} - // ---------------------------------------------------------------------------- bool SurfaceFlinger::authenticateSurfaceTexture( @@ -1515,7 +1537,7 @@ bool SurfaceFlinger::isFpsDeferNeeded(const ActiveModeInfo& info) { return false; } - auto requestedRefreshRate = mRefreshRateConfigs->getRefreshRateFromModeId(info.modeId); + auto requestedRefreshRate = display->refreshRateConfigs().getRefreshRateFromModeId(info.mode->getId()); float newFpsRequest = requestedRefreshRate.getFps().getValue(); if (mAllowThermalFpsChange) { return false; @@ -1536,42 +1558,38 @@ void SurfaceFlinger::setDesiredActiveMode(const ActiveModeInfo& info) { return; } - auto refreshRate = mRefreshRateConfigs->getRefreshRateFromModeId(info.modeId); + 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; + } + + auto refreshRate = display->refreshRateConfigs().getRefreshRateFromModeId(info.mode->getId()); + mVsyncPeriod = refreshRate.getVsyncPeriod(); if (mDolphinWrapper.dolphinSetVsyncPeriod) { mDolphinWrapper.dolphinSetVsyncPeriod(mVsyncPeriod); } ALOGV("setDesiredActiveConfig(%s)", refreshRate.getName().c_str()); - std::lock_guard<std::mutex> lock(mActiveModeLock); - if (mDesiredActiveModeChanged) { - // If a config change is pending, just cache the latest request in - // mDesiredActiveConfig - 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 (display->setDesiredActiveMode(info)) { display->resetVsyncPeriod(); // 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); } setContentFps(static_cast<uint32_t>(refreshRate.getFps().getValue())); @@ -1607,7 +1625,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}}; @@ -1627,128 +1645,127 @@ 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, getCurrentVsyncSource()->isPrimary() ? refreshRate.getPeriodNsecs() : getVsyncPeriodFromHWC()); + updatePhaseConfiguration(refreshRate); } 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() { @@ -2311,7 +2328,7 @@ nsecs_t SurfaceFlinger::getVsyncPeriodFromHWCcb() { return display->getVsyncPeriodFromHWC(); } - return mRefreshRateConfigs->getCurrentRefreshRate().getVsyncPeriod(); + return display->refreshRateConfigs().getCurrentRefreshRate().getVsyncPeriod(); } void SurfaceFlinger::onComposerHalVsync(hal::HWDisplayId hwcDisplayId, int64_t timestamp, @@ -2319,10 +2336,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); } @@ -2330,6 +2347,13 @@ void SurfaceFlinger::onComposerHalVsync(hal::HWDisplayId hwcDisplayId, int64_t t return; } + const bool isActiveDisplay = + displayId && getPhysicalDisplayTokenLocked(*displayId) == mActiveDisplayToken; + if (!isActiveDisplay) { + // For now, we don't do anything with non active display vsyncs. + return; + } + bool periodFlushed = false; mScheduler->addResyncSample(timestamp, vsyncPeriod, &periodFlushed); if (periodFlushed) { @@ -2342,10 +2366,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(); @@ -2355,13 +2375,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}); uint32_t hwcDisplayId; if (isDisplayExtnEnabled() && getHwcDisplayId(display, &hwcDisplayId)) { @@ -2370,10 +2390,11 @@ void SurfaceFlinger::changeRefreshRateLocked(const RefreshRate& refreshRate, } void SurfaceFlinger::setRefreshRateTo(int32_t refreshRate) { - auto currentRefreshRate = mRefreshRateConfigs->getCurrentRefreshRate(); + const auto display = getDefaultDisplayDevice(); + auto currentRefreshRate = display->refreshRateConfigs().getCurrentRefreshRate(); - auto iter = mRefreshRateConfigs->getAllRefreshRates().cbegin(); - while (iter != mRefreshRateConfigs->getAllRefreshRates().cend()) { + auto iter = display->refreshRateConfigs().getAllRefreshRates().cbegin(); + while (iter != display->refreshRateConfigs().getAllRefreshRates().cend()) { if (iter->second->inPolicy(static_cast<android::Fps>(refreshRate), static_cast<android::Fps>(refreshRate))) { break; } @@ -2452,14 +2473,14 @@ void SurfaceFlinger::setVsyncEnabledInternal(bool enabled) { // Disable current vsync source before enabling the next source if (mActiveVsyncSource) { *displayId = mActiveVsyncSource->getPhysicalId(); - getHwComposer().setVsyncEnabled(*displayId, hal::Vsync::DISABLE); + setHWCVsyncEnabled(*displayId, hal::Vsync::DISABLE); } *displayId = mNextVsyncSource->getPhysicalId(); } else if (mActiveVsyncSource) { *displayId = mActiveVsyncSource->getPhysicalId(); } if (displayId) { - getHwComposer().setVsyncEnabled(*displayId, mHWCVsyncPendingState); + setHWCVsyncEnabled(*displayId, mHWCVsyncPendingState); } if (mNextVsyncSource) { mActiveVsyncSource = mNextVsyncSource; @@ -2672,8 +2693,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__); + } } } @@ -3288,7 +3314,7 @@ void SurfaceFlinger::UpdateSmomoState() { std::vector<smomo::SmomoLayerStats> layers; if (enableSmomo && instance.active) { - fps = mRefreshRateConfigs->getCurrentRefreshRate().getFps().getValue(); + fps = device->refreshRateConfigs().getCurrentRefreshRate().getFps().getValue(); mDrawingState.traverse([&](Layer* layer) { if (layer->findOutputLayerForDisplay(device.get())) { smomo::SmomoLayerStats layerStats; @@ -3317,24 +3343,34 @@ void SurfaceFlinger::UpdateSmomoState() { } } -FloatRect SurfaceFlinger::getLayerClipBoundsForDisplay(const DisplayDevice& displayDevice) const { - return displayDevice.getLayerStackSpaceRect().toFloatRect(); -} - -void SurfaceFlinger::computeLayerBounds() { +FloatRect SurfaceFlinger::getMaxDisplayBounds() { + // 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 = FloatRect(-maxDisplayWidth * 10, -maxDisplayHeight * 10, + maxDisplayWidth * 10, maxDisplayHeight * 10); + return maxBounds; +} + +void SurfaceFlinger::computeLayerBounds() { + FloatRect maxBounds = getMaxDisplayBounds(); + for (const auto& layer : mDrawingState.layersSortedByZ) { + layer->computeBounds(maxBounds, ui::Transform(), 0.f /* shadowRadius */); + } } sp<DisplayDevice> SurfaceFlinger::getVsyncSource() { @@ -3429,7 +3465,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); @@ -3480,6 +3515,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) @@ -3543,11 +3579,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()); @@ -3618,6 +3649,18 @@ sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal( if (const auto& physical = state.physical) { creationArgs.connectionType = physical->type; creationArgs.supportedModes = physical->supportedModes; + creationArgs.activeModeId = physical->activeMode->getId(); + const auto [idleTimerTimeoutMs, supportKernelIdleTimer] = + getIdleTimerConfiguration(compositionDisplay->getId()); + scheduler::RefreshRateConfigs::Config config = + {.enableFrameRateOverride = android::sysprop::enable_frame_rate_override(false), + .frameRateMultipleThreshold = + base::GetIntProperty("debug.sf.frame_rate_multiple_threshold", 0), + .idleTimerTimeoutMs = idleTimerTimeoutMs, + .supportKernelIdleTimer = supportKernelIdleTimer}; + creationArgs.refreshRateConfigs = + std::make_shared<scheduler::RefreshRateConfigs>(creationArgs.supportedModes, + creationArgs.activeModeId, config); } if (const auto id = PhysicalDisplayId::tryCast(compositionDisplay->getId())) { @@ -3674,7 +3717,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); } @@ -3731,8 +3774,7 @@ void SurfaceFlinger::processDisplayAdded(const wp<IBinder>& displayToken, builder.setId(physical->id); builder.setConnectionType(physical->type); } else { - builder.setId(acquireVirtualDisplay(resolution, pixelFormat, state.layerStack, - canAllocateHwcForVDS)); + builder.setId(acquireVirtualDisplay(resolution, pixelFormat, canAllocateHwcForVDS)); } builder.setPixels(resolution); @@ -3790,6 +3832,9 @@ void SurfaceFlinger::processDisplayAdded(const wp<IBinder>& displayToken, display->setPowerModeOverrideConfig(true); } #endif + if (display->isPrimary()) { + initScheduler(display); + } if (!state.isVirtual()) { sp<DisplayDevice> displayNew = getDisplayDeviceLocked(displayToken); if (mPluggableVsyncPrioritized && !isInternalDisplay(displayNew)) { @@ -3818,10 +3863,6 @@ void SurfaceFlinger::processDisplayAdded(const wp<IBinder>& displayToken, } } - if (display->isPrimary()) { - mScheduler->onPrimaryDisplayAreaChanged(display->getWidth() * display->getHeight()); - getRenderEngine().onPrimaryDisplaySizeChanged(display->getSize()); - } #ifdef QTI_UNIFIED_DRAW const auto id = HalDisplayId::tryCast(display->getId()); if (mDisplayExtnIntf && id) { @@ -3900,16 +3941,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; @@ -3927,6 +3959,9 @@ void SurfaceFlinger::processDisplayChanged(const wp<IBinder>& displayToken, } } } + if (currentState.flags != drawingState.flags) { + display->setFlags(currentState.flags); + } if ((currentState.orientation != drawingState.orientation) || (currentState.layerStackSpaceRect != drawingState.layerStackSpaceRect) || (currentState.orientedDisplaySpaceRect != drawingState.orientedDisplaySpaceRect)) { @@ -3939,8 +3974,8 @@ void SurfaceFlinger::processDisplayChanged(const wp<IBinder>& displayToken, 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 || @@ -3948,19 +3983,21 @@ void SurfaceFlinger::processDisplayChanged(const wp<IBinder>& displayToken, if (!displaySizeChanged) { 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::setFrameBufferSizeForScaling(sp<DisplayDevice> displayDevice, DisplayDeviceState& currentState, const DisplayDeviceState& drawingState) { @@ -4168,11 +4205,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) { @@ -4187,31 +4224,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() { @@ -4243,24 +4269,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); @@ -4268,7 +4286,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 = @@ -4297,9 +4315,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( @@ -4529,9 +4545,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); @@ -5070,6 +5086,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; @@ -5328,10 +5350,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; @@ -5404,6 +5426,16 @@ uint32_t SurfaceFlinger::setClientStateLocked( flags |= eTraversalNeeded; } } + if (what & layer_state_t::eDropInputModeChanged) { + if (privileged) { + if (layer->setDropInputMode(s.dropInputMode)) { + flags |= eTraversalNeeded; + mInputInfoChanged = true; + } + } else { + ALOGE("Attempt to update InputPolicyFlags without permission ACCESS_SURFACE_FLINGER"); + } + } // This has to happen after we reparent children because when we reparent to null we remove // child layers from current state and remove its relative z. If the children are reparented in // the same transaction, then we have to make sure we reparent the children first so we do not @@ -5429,17 +5461,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 @@ -5448,7 +5493,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) { @@ -5751,9 +5796,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}; @@ -5765,6 +5811,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__); @@ -5781,6 +5847,12 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, hal: mActiveVsyncSource = getVsyncSource(); + const auto activeDisplay = getDisplayDeviceLocked(mActiveDisplayToken); + if (activeDisplay != display && display->isInternal() && activeDisplay && + activeDisplay->isPoweredOn()) { + ALOGW("Trying to change power mode on non active display while the active display is ON"); + } + display->setPowerMode(mode); // Dummy display created by LibSurfaceFlinger unit test @@ -5791,8 +5863,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) { + // Turn on the display + 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) { @@ -5803,8 +5879,8 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, hal: } getHwComposer().setPowerMode(displayId, mode); if (isDummyDisplay) { - if (display->isPrimary() && mode != hal::PowerMode::DOZE_SUSPEND) { - getHwComposer().setVsyncEnabled(displayId, mHWCVsyncPendingState); + if (isDisplayActiveLocked(display) && mode != hal::PowerMode::DOZE_SUSPEND) { + setHWCVsyncEnabled(displayId, mHWCVsyncPendingState); mScheduler->onScreenAcquired(mAppConnectionHandle); mScheduler->resyncToHardwareVsync(true, vsyncPeriod); } @@ -5830,7 +5906,7 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, hal: mScheduler->onScreenReleased(mAppConnectionHandle); } // Make sure HWVsync is disabled before turning off the display - getHwComposer().setVsyncEnabled(displayId, hal::Vsync::DISABLE); + setHWCVsyncEnabled(displayId, hal::Vsync::DISABLE); } else { updateVsyncSource(); } @@ -5842,7 +5918,7 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, hal: // Update display while dozing getHwComposer().setPowerMode(displayId, mode); if (isDummyDisplay) { - if (display->isPrimary() && currentMode == hal::PowerMode::DOZE_SUSPEND) { + if (isDisplayActiveLocked(display) && currentMode == hal::PowerMode::DOZE_SUSPEND) { mScheduler->onScreenAcquired(mAppConnectionHandle); mScheduler->resyncToHardwareVsync(true, vsyncPeriod); } @@ -5852,7 +5928,7 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, hal: } else if (mode == hal::PowerMode::DOZE_SUSPEND) { // Leave display going to doze if (isDummyDisplay) { - if (display->isPrimary()) { + if (isDisplayActiveLocked(display)) { mScheduler->disableHardwareVsync(true); mScheduler->onScreenReleased(mAppConnectionHandle); } @@ -5878,7 +5954,7 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, hal: } } - if (display->isPrimary()) { + if (isDisplayActiveLocked(display)) { mTimeStats->setPowerMode(mode); mRefreshRateStats->setPowerMode(mode); mScheduler->setDisplayPowerState(mode == hal::PowerMode::ON); @@ -6028,12 +6104,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); @@ -6250,13 +6331,13 @@ 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"); mScheduler->dump(mAppConnectionHandle, result); mScheduler->dumpVsync(result); + StringAppendF(&result, "mHWCVsyncPendingState=%s mLastHWCVsyncState=%s\n", + to_string(mHWCVsyncPendingState).c_str(), to_string(mLastHWCVsyncState).c_str()); } void SurfaceFlinger::dumpPlannerInfo(const DumpArgs& args, std::string& result) const { @@ -6427,6 +6508,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); } @@ -6651,7 +6748,8 @@ void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, std::string& result) co continue; } - StringAppendF(&result, "Display %s HWC layers:\n", to_string(*displayId).c_str()); + StringAppendF(&result, "Display %s (%s) HWC layers:\n", to_string(*displayId).c_str(), + (isDisplayActiveLocked(display) ? "active" : "inactive")); Layer::miniDumpHeader(result); const DisplayDevice& ref = *display; @@ -6743,6 +6841,7 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { case REMOVE_TUNNEL_MODE_ENABLED_LISTENER: case NOTIFY_POWER_BOOST: case SET_GLOBAL_SHADOW_SETTINGS: + case GET_PRIMARY_PHYSICAL_DISPLAY_ID: case ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN: { // ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN and OVERRIDE_HDR_TYPES are used by CTS tests, // which acquire the necessary permission dynamically. Don't use the permission cache @@ -6853,6 +6952,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 @@ -7166,22 +7273,24 @@ 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: { const int modeId = data.readInt32(); mDebugDisplayModeSetByBackdoor = false; - const auto numConfigs = mRefreshRateConfigs->getAllRefreshRates().size(); + const auto display = getDefaultDisplayDevice(); + const auto numConfigs = display->refreshRateConfigs().getAllRefreshRates().size(); if ((modeId >= 0) && (modeId < numConfigs)) { const auto displayId = getInternalDisplayId(); if (!displayId) { @@ -7212,7 +7321,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) { @@ -7495,22 +7604,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(); } })); @@ -7519,12 +7631,19 @@ void SurfaceFlinger::kernelTimerChanged(bool expired) { void SurfaceFlinger::toggleKernelIdleTimer() { using KernelIdleTimerAction = scheduler::RefreshRateConfigs::KernelIdleTimerAction; - // If the support for kernel idle timer is disabled in SF code, don't do anything. - if (!mSupportKernelIdleTimer) { + const auto display = getDefaultDisplayDeviceLocked(); + if (!display) { + ALOGW("%s: default display is null", __func__); + return; + } + + // If the support for kernel idle timer is disabled for the active display, + // don't do anything. + if (!display->refreshRateConfigs().supportsKernelIdleTimer()) { return; } - const KernelIdleTimerAction action = mRefreshRateConfigs->getIdleTimerAction(); + const KernelIdleTimerAction action = display->refreshRateConfigs().getIdleTimerAction(); switch (action) { case KernelIdleTimerAction::TurnOff: if (mKernelIdleTimerEnabled) { @@ -7761,9 +7880,7 @@ status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args, sp<Layer> parent; Rect crop(args.sourceCrop); std::unordered_set<sp<Layer>, ISurfaceComposer::SpHash<Layer>> excludeLayers; - Rect layerStackSpaceRect; ui::Dataspace dataspace; - bool captureSecureLayers; // Call this before holding mStateLock to avoid any deadlocking. bool canCaptureBlackoutContent = hasCaptureBlackoutContentPermission(); @@ -7772,7 +7889,7 @@ status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args, Mutex::Autolock lock(mStateLock); parent = fromHandle(args.layerHandle).promote(); - if (parent == nullptr || parent->isRemovedFromCurrentState()) { + if (parent == nullptr) { ALOGE("captureLayers called with an invalid or removed parent"); return NAME_NOT_FOUND; } @@ -7811,39 +7928,36 @@ status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args, } } - const auto display = findDisplay(WithLayerStack(parent->getLayerStack())); - if (!display) { - return NAME_NOT_FOUND; - } - - layerStackSpaceRect = display->getLayerStackSpaceRect(); - // The dataspace is depended on the color mode of display, that could use non-native mode // (ex. displayP3) to enhance the content, but some cases are checking native RGB in bytes, // and failed if display is not in native mode. This provide a way to force using native // colors when capture. dataspace = args.dataspace; if (dataspace == ui::Dataspace::UNKNOWN) { + auto display = findDisplay(WithLayerStack(parent->getLayerStack())); + if (!display) { + // If the layer is not on a display, use the dataspace for the default display. + display = getDefaultDisplayDeviceLocked(); + } + const ui::ColorMode colorMode = display->getCompositionDisplay()->getState().colorMode; dataspace = pickDataspaceFromColorMode(colorMode); } - captureSecureLayers = args.captureSecureLayers && display->isSecure(); } // mStateLock // really small crop or frameScale - if (reqSize.width <= 0) { - reqSize.width = 1; - } - if (reqSize.height <= 0) { - reqSize.height = 1; + if (reqSize.width <= 0 || reqSize.height <= 0) { + ALOGW("Failed to captureLayes: crop or scale too small"); + return BAD_VALUE; } + Rect layerStackSpaceRect(0, 0, reqSize.width, reqSize.height); bool childrenOnly = args.childrenOnly; RenderAreaFuture renderAreaFuture = ftl::defer([=]() -> std::unique_ptr<RenderArea> { return std::make_unique<LayerRenderArea>(*this, parent, crop, reqSize, dataspace, childrenOnly, layerStackSpaceRect, - captureSecureLayers); + args.captureSecureLayers); }); auto traverseLayers = [parent, args, excludeLayers](const LayerVector::Visitor& visitor) { @@ -7880,6 +7994,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 @@ -8108,7 +8229,7 @@ status_t SurfaceFlinger::renderScreenImplLocked( return NO_ERROR; } -void SurfaceFlinger::setInputWindowsFinished() { +void SurfaceFlinger::windowInfosReported() { Mutex::Autolock _l(mStateLock); signalSynchronousTransactions(CountDownLatch::eSyncInputWindows); } @@ -8156,98 +8277,64 @@ 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()) { - if (!isInternalDisplay(display)) { - return NO_ERROR; - } - - // 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); - - uint32_t hwcDisplayId; - if (isDisplayExtnEnabled() && getHwcDisplayId(display, &hwcDisplayId)) { - setDisplayExtnActiveConfig(hwcDisplayId, policy->defaultMode.value()); - } - - 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(); + 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); + }(); - 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); 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}); uint32_t hwcDisplayId; if (isDisplayExtnEnabled() && getHwcDisplayId(display, &hwcDisplayId)) { - setDisplayExtnActiveConfig(hwcDisplayId, preferredRefreshRate.getModeId().value()); + setDisplayExtnActiveConfig(hwcDisplayId, preferredDisplayMode->getId().value()); if (mDynamicSfIdleEnabled) { setupIdleTimeoutHandling(hwcDisplayId); } } } else { LOG_ALWAYS_FATAL("Desired display mode not allowed: %d", - preferredRefreshRate.getModeId().value()); + preferredDisplayMode->getId().value()); } - setRefreshRates(mRefreshRateConfigs); return NO_ERROR; } @@ -8326,29 +8413,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 { @@ -8467,7 +8544,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); @@ -8535,25 +8613,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); + for (const auto& [ignored, display] : mDisplays) { + if (display->isInternal()) { + display->enableRefreshRateOverlay(enable, 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()); - } - } - })); + } } status_t SurfaceFlinger::addTransactionTraceListener( @@ -8581,7 +8645,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; } @@ -8592,7 +8663,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); } @@ -8679,7 +8757,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); @@ -8904,7 +8982,6 @@ void SurfaceFlinger::createPhaseOffsetExtn() { g_comp_ext_intf_.phaseOffsetExtnIntf->GetAdvancedSfOffsets(&advancedSfOffsets); // Update the Advanced SF Offsets - std::lock_guard<std::mutex> lock(mActiveModeLock); mVsyncConfiguration->UpdateSfOffsets(advancedSfOffsets); const auto vsyncConfig = mVsyncModulator->setVsyncConfigSet(mVsyncConfiguration->getCurrentConfigs()); @@ -8976,7 +9053,7 @@ void SurfaceFlinger::setupDisplayExtnFeatures() { bool enableEarlyWakeUp = (atoi(propValue) == 1); property_get("vendor.display.disable_dynamic_sf_idle", propValue, "0"); - bool enableDynamicSfIdle = mScheduler->isIdleTimerEnabled() && (atoi(propValue) == 0); + bool enableDynamicSfIdle = (atoi(propValue) == 0); if (enableEarlyWakeUp || enableDynamicSfIdle) { for (const auto& display : mDisplaysList) { @@ -9066,7 +9143,7 @@ void SurfaceFlinger::setDesiredModeByThermalLevel(float newLevelFps) { const auto display = ON_MAIN_THREAD(getDisplayDeviceLocked (getPhysicalDisplayToken(*displayId)) ); - auto currRefreshRate = mRefreshRateConfigs->getRefreshRateFromModeId + auto currRefreshRate = display->refreshRateConfigs().getRefreshRateFromModeId (display->getActiveMode()->getId()); float currFps = currRefreshRate.getFps().getValue(); @@ -9104,7 +9181,7 @@ void SurfaceFlinger::setDesiredModeByThermalLevel(float newLevelFps) { return INVALID_OPERATION; } scheduler::RefreshRateConfigs::Policy policy = - mRefreshRateConfigs->getCurrentPolicy(); + display->refreshRateConfigs().getCurrentPolicy(); if (fps < policy.primaryRange.min.getValue() || fps < policy.appRequestRange.min.getValue()) { @@ -9123,6 +9200,47 @@ void SurfaceFlinger::setDesiredModeByThermalLevel(float newLevelFps) { }); } +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(); + + // Update the kernel timer for the current active display, since the policy + // for this display might have changed when it was not the active display. + toggleKernelIdleTimer(); +} + +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 9825345051..dad158d89b 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -113,7 +113,6 @@ class FpsReporter; class TunnelModeEnabledReporter; class HdrLayerInfoReporter; class HWComposer; -struct SetInputWindowsListener; class IGraphicBufferProducer; class Layer; class MessageBase; @@ -122,6 +121,7 @@ class RegionSamplingThread; class RenderArea; class TimeStats; class FrameTracer; +class WindowInfosListenerInvoker; using gui::ScreenCaptureResults; @@ -399,11 +399,12 @@ 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 void disableExpensiveRendering(); + FloatRect getMaxDisplayBounds(); nsecs_t mVsyncTimeStamp = -1; void NotifyIdleStatus(); @@ -421,12 +422,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; @@ -539,14 +542,7 @@ private: DolphinWrapper mDolphinWrapper; }; - 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, @@ -677,7 +673,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); } } @@ -696,7 +692,12 @@ 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(); + } + status_t getPrimaryPhysicalDisplayId(PhysicalDisplayId*) const override EXCLUDES(mStateLock); + sp<IBinder> getPhysicalDisplayToken(PhysicalDisplayId displayId) const override; status_t setTransactionState(const FrameTimelineInfo& frameTimelineInfo, const Vector<ComposerState>& state, @@ -809,6 +810,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; @@ -840,12 +846,10 @@ 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; - // Keeps track of whether the kernel timer is supported on the SF side. - bool mSupportKernelIdleTimer = false; // Show spinner with refresh rate overlay bool mRefreshRateOverlaySpinner = false; @@ -870,9 +874,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); @@ -907,13 +911,13 @@ private: void handleTransactionLocked(uint32_t transactionFlags) REQUIRES(mStateLock); void updateInputFlinger(); - void updateInputWindowInfo(); + void notifyWindowInfos(); void commitInputWindowCommands() REQUIRES(mStateLock); void updateCursorAsync(); void updateFrameScheduler(); void syncToDisplayHardware(); - 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); @@ -1034,8 +1038,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; @@ -1057,6 +1062,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); } @@ -1068,13 +1077,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(); } @@ -1093,10 +1107,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) const REQUIRES(mStateLock) { + return display->getDisplayToken() == mActiveDisplayToken; + } + /* * H/W composer */ @@ -1136,8 +1158,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, @@ -1156,14 +1176,17 @@ private: nsecs_t getVsyncPeriodFromHWCcb(); sp<DisplayDevice> getCurrentVsyncSource(); + void setHWCVsyncEnabled(PhysicalDisplayId id, hal::Vsync enabled) { + mLastHWCVsyncState = enabled; + getHwComposer().setVsyncEnabled(id, enabled); + } + // Sets the refresh rate by switching active configs, if they are available for // the desired refresh rate. void changeRefreshRateLocked(const RefreshRate&, Scheduler::ModeEvent) REQUIRES(mStateLock); void setRefreshRateTo(int32_t refreshRate); - bool isDisplayModeAllowed(DisplayModeId) const REQUIRES(mStateLock); - struct FenceWithFenceTime { sp<Fence> fence = Fence::NO_FENCE; std::shared_ptr<FenceTime> fenceTime = FenceTime::NO_FENCE; @@ -1224,11 +1247,15 @@ private: void enableHalVirtualDisplays(bool); // Virtual display lifecycle for ID generation and HAL allocation. - VirtualDisplayId acquireVirtualDisplay(ui::Size, ui::PixelFormat, ui::LayerStack, - bool canAllocateHwcForVDS) + VirtualDisplayId acquireVirtualDisplay(ui::Size, ui::PixelFormat, bool canAllocateHwcForVDS) REQUIRES(mStateLock); + void releaseVirtualDisplay(VirtualDisplayId); + void onActiveDisplayChangedLocked(const sp<DisplayDevice>& activeDisplay) REQUIRES(mStateLock); + + void onActiveDisplaySizeChanged(const sp<DisplayDevice>& activeDisplay); + /* * Debugging & dumpsys */ @@ -1256,6 +1283,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) @@ -1339,13 +1368,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); @@ -1357,6 +1379,9 @@ private: virtual void getModeFromFps(float fps,DisplayModePtr& outMode); void handleNewLevelFps(float currFps, float newLevelFps, float* fpsToSet); + void updateInternalDisplayVsyncLocked(const sp<DisplayDevice>& activeDisplay) + REQUIRES(mStateLock); + sp<StartPropertySetThread> mStartPropertySetThread; surfaceflinger::Factory& mFactory; @@ -1552,6 +1577,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; @@ -1570,24 +1598,14 @@ 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); + hal::Vsync mLastHWCVsyncState = hal::Vsync::DISABLE; // below flags are set by main thread only - TracedOrdinal<bool> mDesiredActiveModeChanged - GUARDED_BY(mActiveModeLock) = {"DesiredActiveModeChanged", false}; bool mSetActiveModePending = false; bool mLumaSampling = true; @@ -1603,15 +1621,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; @@ -1662,13 +1677,22 @@ 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(); void setRefreshRates(std::unique_ptr<scheduler::RefreshRateConfigs> &refreshRateConfigs); void UpdateSmomoState(); + 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; public: nsecs_t mVsyncPeriod = -1; DolphinWrapper mDolphinWrapper; 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/SurfaceFlingerProperties.cpp b/services/surfaceflinger/SurfaceFlingerProperties.cpp index 4a69c8f0c3..e15eae8c36 100644 --- a/services/surfaceflinger/SurfaceFlingerProperties.cpp +++ b/services/surfaceflinger/SurfaceFlingerProperties.cpp @@ -34,6 +34,8 @@ using android::hardware::graphics::common::V1_2::Dataspace; using android::hardware::graphics::common::V1_2::PixelFormat; using android::ui::DisplayPrimaries; +// Keep logic in sync with WindowManagerService functions that query SurfaceFlinger properties. +// Consider exposing properties via ISurfaceComposer instead. int64_t vsync_event_phase_offset_ns(int64_t defaultValue) { auto temp = SurfaceFlingerProperties::vsync_event_phase_offset_ns(); if (temp.has_value()) { 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 b96725fa12..26c91faa18 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/IPC_test.cpp b/services/surfaceflinger/tests/IPC_test.cpp index 9fa3d4c417..84fea6c751 100644 --- a/services/surfaceflinger/tests/IPC_test.cpp +++ b/services/surfaceflinger/tests/IPC_test.cpp @@ -28,8 +28,8 @@ #include <limits> +#include <gui/test/CallbackUtils.h> #include "BufferGenerator.h" -#include "utils/CallbackUtils.h" #include "utils/ColorUtils.h" #include "utils/TransactionUtils.h" diff --git a/services/surfaceflinger/tests/InvalidHandles_test.cpp b/services/surfaceflinger/tests/InvalidHandles_test.cpp index 9cf7c0909b..d192a2d83d 100644 --- a/services/surfaceflinger/tests/InvalidHandles_test.cpp +++ b/services/surfaceflinger/tests/InvalidHandles_test.cpp @@ -52,17 +52,6 @@ protected: } }; -TEST_F(InvalidHandleTest, createSurfaceInvalidParentHandle) { - // The createSurface is scheduled now, we could still get a created surface from createSurface. - // Should verify if it actually added into current state by checking the screenshot. - auto notSc = mScc->createSurface(String8("lolcats"), 19, 47, PIXEL_FORMAT_RGBA_8888, 0, - mNotSc->getHandle()); - LayerCaptureArgs args; - args.layerHandle = notSc->getHandle(); - ScreenCaptureResults captureResults; - ASSERT_EQ(NAME_NOT_FOUND, ScreenCapture::captureLayers(args, captureResults)); -} - TEST_F(InvalidHandleTest, captureLayersInvalidHandle) { LayerCaptureArgs args; args.layerHandle = mNotSc->getHandle(); diff --git a/services/surfaceflinger/tests/LayerCallback_test.cpp b/services/surfaceflinger/tests/LayerCallback_test.cpp index 965aac301d..7ff041ea57 100644 --- a/services/surfaceflinger/tests/LayerCallback_test.cpp +++ b/services/surfaceflinger/tests/LayerCallback_test.cpp @@ -18,8 +18,8 @@ #include <gui/DisplayEventReceiver.h> +#include <gui/test/CallbackUtils.h> #include "LayerTransactionTest.h" -#include "utils/CallbackUtils.h" using namespace std::chrono_literals; diff --git a/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp index 43d957cf7a..25f3bb91ae 100644 --- a/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp +++ b/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp @@ -208,6 +208,37 @@ TEST_P(LayerTypeAndRenderTypeTransactionTest, SetCornerRadius) { } } +// b/200781179 - don't round a layer without a valid crop +// This behaviour should be fixed since we treat buffer layers differently than +// effect or container layers. +TEST_P(LayerTypeAndRenderTypeTransactionTest, SetCornerRadiusInvalidCrop) { + sp<SurfaceControl> parent; + sp<SurfaceControl> child; + const uint8_t size = 64; + const uint8_t testArea = 4; + const float cornerRadius = 20.0f; + ASSERT_NO_FATAL_FAILURE(parent = createLayer("parent", size, size)); + ASSERT_NO_FATAL_FAILURE(fillLayerColor(parent, Color::GREEN, size, size)); + ASSERT_NO_FATAL_FAILURE(child = createColorLayer("child", Color::RED)); + + Transaction().setCornerRadius(child, cornerRadius).reparent(child, parent).show(child).apply(); + { + const uint8_t bottom = size - 1; + const uint8_t right = size - 1; + auto shot = getScreenCapture(); + std::this_thread::sleep_for(std::chrono::seconds(5)); + // Solid corners since we don't round a layer without a valid crop + shot->expectColor(Rect(0, 0, testArea, testArea), Color::RED); + shot->expectColor(Rect(size - testArea, 0, right, testArea), Color::RED); + shot->expectColor(Rect(0, bottom - testArea, testArea, bottom), Color::RED); + shot->expectColor(Rect(size - testArea, bottom - testArea, right, bottom), Color::RED); + // Solid center + shot->expectColor(Rect(size / 2 - testArea / 2, size / 2 - testArea / 2, + size / 2 + testArea / 2, size / 2 + testArea / 2), + Color::RED); + } +} + TEST_P(LayerTypeAndRenderTypeTransactionTest, SetCornerRadiusRotated) { sp<SurfaceControl> parent; sp<SurfaceControl> child; @@ -465,6 +496,95 @@ TEST_P(LayerTypeAndRenderTypeTransactionTest, SetCornerRadiusChildBufferRotation } } +TEST_P(LayerTypeAndRenderTypeTransactionTest, ChildCornerRadiusTakesPrecedence) { + sp<SurfaceControl> parent; + sp<SurfaceControl> child; + const uint32_t size = 64; + const uint32_t parentSize = size * 3; + const uint32_t testLength = 4; + const float cornerRadius = 20.0f; + ASSERT_NO_FATAL_FAILURE(parent = createLayer("parent", parentSize, parentSize)); + ASSERT_NO_FATAL_FAILURE(fillLayerColor(parent, Color::RED, parentSize, parentSize)); + ASSERT_NO_FATAL_FAILURE(child = createLayer("child", size, size)); + ASSERT_NO_FATAL_FAILURE(fillLayerColor(child, Color::GREEN, size, size)); + + Transaction() + .setCornerRadius(parent, cornerRadius) + .setCornerRadius(child, cornerRadius) + .reparent(child, parent) + .setPosition(child, size, size) + .apply(); + + { + const uint32_t top = size - 1; + const uint32_t left = size - 1; + const uint32_t bottom = size * 2 - 1; + const uint32_t right = size * 2 - 1; + auto shot = getScreenCapture(); + // Edges are transparent + // TL + shot->expectColor(Rect(left, top, testLength, testLength), Color::RED); + // TR + shot->expectColor(Rect(right - testLength, top, right, testLength), Color::RED); + // BL + shot->expectColor(Rect(left, bottom - testLength, testLength, bottom - testLength), + Color::RED); + // BR + shot->expectColor(Rect(right - testLength, bottom - testLength, right, bottom), Color::RED); + // Solid center + shot->expectColor(Rect(parentSize / 2 - testLength / 2, parentSize / 2 - testLength / 2, + parentSize / 2 + testLength / 2, parentSize / 2 + testLength / 2), + Color::GREEN); + } +} + +// Test if ParentCornerRadiusTakesPrecedence if the parent corner radius crop is fully contained by +// the child corner radius crop. +TEST_P(LayerTypeAndRenderTypeTransactionTest, ParentCornerRadiusTakesPrecedence) { + sp<SurfaceControl> parent; + sp<SurfaceControl> child; + const uint32_t size = 64; + const uint32_t parentSize = size * 3; + const Rect parentCrop(size + 1, size + 1, size * 2 - 1, size * 2 - 1); + const uint32_t testLength = 4; + const float cornerRadius = 20.0f; + ASSERT_NO_FATAL_FAILURE(parent = createLayer("parent", parentSize, parentSize)); + ASSERT_NO_FATAL_FAILURE(fillLayerColor(parent, Color::RED, parentSize, parentSize)); + ASSERT_NO_FATAL_FAILURE(child = createLayer("child", size, size)); + ASSERT_NO_FATAL_FAILURE(fillLayerColor(child, Color::GREEN, size, size)); + + Transaction() + .setCornerRadius(parent, cornerRadius) + .setCrop(parent, parentCrop) + .setCornerRadius(child, cornerRadius) + .reparent(child, parent) + .setPosition(child, size, size) + .apply(); + + { + const uint32_t top = size - 1; + const uint32_t left = size - 1; + const uint32_t bottom = size * 2 - 1; + const uint32_t right = size * 2 - 1; + auto shot = getScreenCapture(); + // Edges are transparent + // TL + shot->expectColor(Rect(left, top, testLength, testLength), Color::BLACK); + // TR + shot->expectColor(Rect(right - testLength, top, right, testLength), Color::BLACK); + // BL + shot->expectColor(Rect(left, bottom - testLength, testLength, bottom - testLength), + Color::BLACK); + // BR + shot->expectColor(Rect(right - testLength, bottom - testLength, right, bottom), + Color::BLACK); + // Solid center + shot->expectColor(Rect(parentSize / 2 - testLength / 2, parentSize / 2 - testLength / 2, + parentSize / 2 + testLength / 2, parentSize / 2 + testLength / 2), + Color::GREEN); + } +} + TEST_P(LayerTypeAndRenderTypeTransactionTest, SetBackgroundBlurRadiusSimple) { if (!deviceSupportsBlurs()) GTEST_SKIP(); if (!deviceUsesSkiaRenderEngine()) GTEST_SKIP(); diff --git a/services/surfaceflinger/tests/MirrorLayer_test.cpp b/services/surfaceflinger/tests/MirrorLayer_test.cpp index d02786504e..b7a927129d 100644 --- a/services/surfaceflinger/tests/MirrorLayer_test.cpp +++ b/services/surfaceflinger/tests/MirrorLayer_test.cpp @@ -273,6 +273,61 @@ TEST_F(MirrorLayerTest, InitialMirrorState) { } } +// Test that a mirror layer can be screenshot when offscreen +TEST_F(MirrorLayerTest, OffscreenMirrorScreenshot) { + const auto display = SurfaceComposerClient::getInternalDisplayToken(); + ui::DisplayMode mode; + SurfaceComposerClient::getActiveDisplayMode(display, &mode); + const ui::Size& size = mode.resolution; + + sp<SurfaceControl> grandchild = + createLayer("Grandchild layer", 50, 50, ISurfaceComposerClient::eFXSurfaceBufferState, + mChildLayer.get()); + ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(grandchild, Color::BLUE, 50, 50)); + Rect childBounds = Rect(50, 50, 450, 450); + + asTransaction([&](Transaction& t) { + t.setCrop(grandchild, Rect(0, 0, 50, 50)).show(grandchild); + t.setFlags(grandchild, layer_state_t::eLayerOpaque, layer_state_t::eLayerOpaque); + }); + + sp<SurfaceControl> mirrorLayer = nullptr; + { + // Run as system to get the ACCESS_SURFACE_FLINGER permission when mirroring + UIDFaker f(AID_SYSTEM); + // Mirror mChildLayer + mirrorLayer = mClient->mirrorSurface(mChildLayer.get()); + ASSERT_NE(mirrorLayer, nullptr); + } + + // Show the mirror layer, but don't reparent to a layer on screen. + Transaction().show(mirrorLayer).apply(); + + { + SCOPED_TRACE("Offscreen Mirror"); + auto shot = screenshot(); + shot->expectColor(Rect(0, 0, size.getWidth(), 50), Color::RED); + shot->expectColor(Rect(0, 0, 50, size.getHeight()), Color::RED); + shot->expectColor(Rect(450, 0, size.getWidth(), size.getHeight()), Color::RED); + shot->expectColor(Rect(0, 450, size.getWidth(), size.getHeight()), Color::RED); + shot->expectColor(Rect(100, 100, 450, 450), Color::GREEN); + shot->expectColor(Rect(50, 50, 100, 100), Color::BLUE); + } + + { + SCOPED_TRACE("Capture Mirror"); + // Capture just the mirror layer and child. + LayerCaptureArgs captureArgs; + captureArgs.layerHandle = mirrorLayer->getHandle(); + captureArgs.sourceCrop = childBounds; + std::unique_ptr<ScreenCapture> shot; + ScreenCapture::captureLayers(&shot, captureArgs); + shot->expectSize(childBounds.width(), childBounds.height()); + shot->expectColor(Rect(0, 0, 50, 50), Color::BLUE); + shot->expectColor(Rect(50, 50, 400, 400), Color::GREEN); + } +} + } // 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..309ab2f0db 100644 --- a/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp +++ b/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp @@ -14,8 +14,8 @@ * limitations under the License. */ +#include <gui/test/CallbackUtils.h> #include "LayerTransactionTest.h" -#include "utils/CallbackUtils.h" using namespace std::chrono_literals; @@ -61,7 +61,7 @@ public: std::this_thread::sleep_for(300ms); std::lock_guard lock(mMutex); - EXPECT_EQ(mCallbackDataQueue.size(), 0) << "extra callbacks received"; + EXPECT_EQ(mCallbackDataQueue.size(), 0U) << "extra callbacks received"; mCallbackDataQueue = {}; } @@ -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..2d5b50238c 100644 --- a/services/surfaceflinger/tests/ScreenCapture_test.cpp +++ b/services/surfaceflinger/tests/ScreenCapture_test.cpp @@ -37,6 +37,8 @@ protected: ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayMode(display, &mode)); const ui::Size& resolution = mode.resolution; + mDisplaySize = resolution; + // Background surface mBGSurfaceControl = createLayer(String8("BG Test Surface"), resolution.getWidth(), resolution.getHeight(), 0); @@ -72,6 +74,7 @@ protected: sp<SurfaceControl> mBGSurfaceControl; sp<SurfaceControl> mFGSurfaceControl; std::unique_ptr<ScreenCapture> mCapture; + ui::Size mDisplaySize; }; TEST_F(ScreenCaptureTest, SetFlagsSecureEUidSystem) { @@ -515,21 +518,27 @@ TEST_F(ScreenCaptureTest, CaptureSize) { } TEST_F(ScreenCaptureTest, CaptureInvalidLayer) { - sp<SurfaceControl> redLayer = createLayer(String8("Red surface"), 60, 60, 0); + LayerCaptureArgs args; + args.layerHandle = new BBinder(); + ScreenCaptureResults captureResults; + // Layer was deleted so captureLayers should fail with NAME_NOT_FOUND + 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)); - auto redLayerHandle = redLayer->getHandle(); - Transaction().reparent(redLayer, nullptr).apply(); - redLayer.clear(); - SurfaceComposerClient::Transaction().apply(true); + Transaction().show(redLayer).setLayer(redLayer, INT32_MAX).apply(true); - LayerCaptureArgs args; - args.layerHandle = redLayerHandle; + LayerCaptureArgs captureArgs; + captureArgs.layerHandle = redLayer->getHandle(); + captureArgs.frameScaleX = INT32_MAX / 60; + captureArgs.frameScaleY = INT32_MAX / 60; ScreenCaptureResults captureResults; - // Layer was deleted so captureLayers should fail with NAME_NOT_FOUND - ASSERT_EQ(NAME_NOT_FOUND, ScreenCapture::captureLayers(args, captureResults)); + ASSERT_EQ(BAD_VALUE, ScreenCapture::captureLayers(captureArgs, captureResults)); } TEST_F(ScreenCaptureTest, CaptureSecureLayer) { @@ -824,6 +833,33 @@ TEST_F(ScreenCaptureTest, CaptureWithGrayscale) { Color{expectedColor, expectedColor, expectedColor, 255}, tolerance); } +TEST_F(ScreenCaptureTest, CaptureOffscreen) { + sp<SurfaceControl> layer; + ASSERT_NO_FATAL_FAILURE(layer = createLayer("test layer", 32, 32, + ISurfaceComposerClient::eFXSurfaceBufferState, + mBGSurfaceControl.get())); + ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32)); + + Transaction().show(layer).hide(mFGSurfaceControl).reparent(layer, nullptr).apply(); + + DisplayCaptureArgs displayCaptureArgs; + displayCaptureArgs.displayToken = mDisplay; + + { + // Validate that the red layer is not on screen + ScreenCapture::captureDisplay(&mCapture, displayCaptureArgs); + mCapture->expectColor(Rect(0, 0, mDisplaySize.width, mDisplaySize.height), + {63, 63, 195, 255}); + } + + LayerCaptureArgs captureArgs; + captureArgs.layerHandle = layer->getHandle(); + + ScreenCapture::captureLayers(&mCapture, captureArgs); + mCapture->expectSize(32, 32); + mCapture->expectColor(Rect(0, 0, 32, 32), Color::RED); +} + // In the following tests we verify successful skipping of a parent layer, // so we use the same verification logic and only change how we mutate // the parent layer to verify that various properties are ignored. 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..15b79be06c --- /dev/null +++ b/services/surfaceflinger/tests/WindowInfosListener_test.cpp @@ -0,0 +1,137 @@ +/* + * 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); + const Rect crop(0, 0, 100, 100); + Transaction() + .setLayerStack(surfaceControl, 0) + .show(surfaceControl) + .setLayer(surfaceControl, INT32_MAX - 1) + .setCrop(surfaceControl, crop) + .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 a59e91993a..64008bed09 100644 --- a/services/surfaceflinger/tests/unittests/Android.bp +++ b/services/surfaceflinger/tests/unittests/Android.bp @@ -56,6 +56,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/DisplayIdentificationTest.cpp b/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.cpp index dc04b6d91d..cd4a5c961d 100644 --- a/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.cpp +++ b/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.cpp @@ -25,6 +25,7 @@ #include <gtest/gtest.h> #include "DisplayHardware/DisplayIdentification.h" +#include "DisplayHardware/Hash.h" using ::testing::ElementsAre; @@ -134,7 +135,7 @@ DisplayIdentificationData asDisplayIdentificationData(const unsigned char (&byte } uint32_t hash(const char* str) { - return static_cast<uint32_t>(std::hash<std::string_view>()(str)); + return static_cast<uint32_t>(cityHash64Len0To16(str)); } } // namespace @@ -309,9 +310,9 @@ TEST(DisplayIdentificationTest, parseDisplayIdentificationData) { ASSERT_TRUE(tertiaryInfo); // Display IDs should be unique. - EXPECT_NE(primaryInfo->id, secondaryInfo->id); - EXPECT_NE(primaryInfo->id, tertiaryInfo->id); - EXPECT_NE(secondaryInfo->id, tertiaryInfo->id); + EXPECT_EQ(4633257497453176576, primaryInfo->id.value); + EXPECT_EQ(4621520285560261121, secondaryInfo->id.value); + EXPECT_EQ(4633127902230889474, tertiaryInfo->id.value); } TEST(DisplayIdentificationTest, deviceProductInfo) { 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 e6a76500f9..dc8bb8e222 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; @@ -172,7 +175,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(); @@ -183,7 +186,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); @@ -195,20 +200,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) { @@ -226,7 +232,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()); @@ -236,7 +244,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/SurfaceFlinger_SetPowerModeInternalTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp index 65024202b8..eea1002236 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp @@ -260,6 +260,11 @@ struct DisplayPowerCase { auto display = Display::makeFakeExistingDisplayInjector(test); display.inject(); display.mutableDisplayDevice()->setPowerMode(mode); + if (display.mutableDisplayDevice()->isInternal()) { + test->mFlinger.mutableActiveDisplayToken() = + display.mutableDisplayDevice()->getDisplayToken(); + } + return display; } diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h index e42e96d13c..0944497b6e 100644 --- a/services/surfaceflinger/tests/unittests/TestableScheduler.h +++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h @@ -32,16 +32,19 @@ 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), - {.supportKernelTimer = false, .useContentDetection = true}) {} + const std::shared_ptr<scheduler::RefreshRateConfigs>& refreshRateConfigs, + ISchedulerCallback& callback) + : Scheduler({std::move(vsyncController), std::move(vsyncTracker), nullptr}, + refreshRateConfigs, callback, createLayerHistory(), + {.useContentDetection = true}) {} // Used to inject mock event thread. ConnectionHandle createConnection(std::unique_ptr<EventThread> eventThread) { @@ -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 c5f7c579d5..8656c16198 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,12 +435,14 @@ 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; } auto& mutableInternalHwcDisplayId() { return getHwComposer().mInternalHwcDisplayId; } auto& mutableExternalHwcDisplayId() { return getHwComposer().mExternalHwcDisplayId; } auto& mutableUseFrameRateApi() { return mFlinger->useFrameRateApi; } + auto& mutableActiveDisplayToken() { return mFlinger->mActiveDisplayToken; } auto fromHandle(const sp<IBinder>& handle) { return mFlinger->fromHandle(handle); @@ -644,6 +646,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 +657,7 @@ public: DisplayModes modes{activeMode}; mCreationArgs.supportedModes = modes; + mCreationArgs.refreshRateConfigs = flinger.mRefreshRateConfigs; } sp<IBinder> token() const { return mDisplayToken; } @@ -723,7 +727,7 @@ public: return *this; } - sp<DisplayDevice> inject() { + sp<DisplayDevice> inject() NO_THREAD_SAFETY_ANALYSIS { const auto displayId = mCreationArgs.compositionDisplay->getDisplayId(); DisplayDeviceState state; @@ -772,6 +776,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 314ec13693..8b9c1dc75f 100644 --- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h +++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h @@ -56,8 +56,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/ScreenshotUtils.h b/services/surfaceflinger/tests/utils/ScreenshotUtils.h index ddaa5a166e..cae76849bf 100644 --- a/services/surfaceflinger/tests/utils/ScreenshotUtils.h +++ b/services/surfaceflinger/tests/utils/ScreenshotUtils.h @@ -175,6 +175,11 @@ public: void expectChildColor(uint32_t x, uint32_t y) { checkPixel(x, y, 200, 200, 200); } + void expectSize(uint32_t width, uint32_t height) { + EXPECT_EQ(width, mOutBuffer->getWidth()); + EXPECT_EQ(height, mOutBuffer->getHeight()); + } + explicit ScreenCapture(const sp<GraphicBuffer>& outBuffer) : mOutBuffer(outBuffer) { if (mOutBuffer) { mOutBuffer->lock(GRALLOC_USAGE_SW_READ_OFTEN, reinterpret_cast<void**>(&mPixels)); |