diff options
83 files changed, 2538 insertions, 1574 deletions
diff --git a/cmds/flatland/Main.cpp b/cmds/flatland/Main.cpp index 6d14d568a4..277300d20f 100644 --- a/cmds/flatland/Main.cpp +++ b/cmds/flatland/Main.cpp @@ -772,8 +772,8 @@ int main(int argc, char** argv) { break; case 'i': - displayId = DisplayId::fromValue<PhysicalDisplayId>(atoll(optarg)); - if (!displayId) { + displayId = PhysicalDisplayId::fromValue(atoll(optarg)); + if (std::find(ids.begin(), ids.end(), displayId) == ids.end()) { fprintf(stderr, "Invalid display ID: %s.\n", optarg); exit(4); } diff --git a/include/android/input.h b/include/android/input.h index ee98d7aee9..5f445509fa 100644 --- a/include/android/input.h +++ b/include/android/input.h @@ -849,6 +849,7 @@ enum { * Refer to the documentation on the MotionEvent class for descriptions of each button. */ enum { + // LINT.IfChange(AMOTION_EVENT_BUTTON) /** primary */ AMOTION_EVENT_BUTTON_PRIMARY = 1 << 0, /** secondary */ @@ -861,6 +862,7 @@ enum { AMOTION_EVENT_BUTTON_FORWARD = 1 << 4, AMOTION_EVENT_BUTTON_STYLUS_PRIMARY = 1 << 5, AMOTION_EVENT_BUTTON_STYLUS_SECONDARY = 1 << 6, + // LINT.ThenChange(/frameworks/native/libs/input/rust/input.rs) }; /** diff --git a/include/input/DisplayTopologyGraph.h b/include/input/DisplayTopologyGraph.h index f3f5148540..3ae865a33a 100644 --- a/include/input/DisplayTopologyGraph.h +++ b/include/input/DisplayTopologyGraph.h @@ -42,7 +42,9 @@ enum class DisplayTopologyPosition : int32_t { */ struct DisplayTopologyAdjacentDisplay { ui::LogicalDisplayId displayId = ui::LogicalDisplayId::INVALID; + // Position of the adjacent display, relative to the source display. DisplayTopologyPosition position; + // The offset in DP of the adjacent display, relative to the source display. float offsetDp; }; diff --git a/include/input/InputVerifier.h b/include/input/InputVerifier.h index 14dd463425..7d3fb469c6 100644 --- a/include/input/InputVerifier.h +++ b/include/input/InputVerifier.h @@ -47,9 +47,10 @@ public: InputVerifier(const std::string& name); android::base::Result<void> processMovement(int32_t deviceId, int32_t source, int32_t action, - uint32_t pointerCount, + int32_t actionButton, uint32_t pointerCount, const PointerProperties* pointerProperties, - const PointerCoords* pointerCoords, int32_t flags); + const PointerCoords* pointerCoords, int32_t flags, + int32_t buttonState); void resetDevice(int32_t deviceId); diff --git a/libs/binder/IActivityManager.cpp b/libs/binder/IActivityManager.cpp index 152c815ec3..83f4719de2 100644 --- a/libs/binder/IActivityManager.cpp +++ b/libs/binder/IActivityManager.cpp @@ -147,9 +147,11 @@ public: data.writeInterfaceToken(IActivityManager::getInterfaceDescriptor()); data.writeInt32(uid); data.writeString16(callingPackage); - remote()->transact(IS_UID_ACTIVE_TRANSACTION, data, &reply); + status_t err = remote()->transact(IS_UID_ACTIVE_TRANSACTION, data, &reply); // fail on exception - if (reply.readExceptionCode() != 0) return false; + if (err != NO_ERROR || ((err = reply.readExceptionCode()) != NO_ERROR)) { + return false; + } return reply.readInt32() == 1; } @@ -159,9 +161,9 @@ public: data.writeInterfaceToken(IActivityManager::getInterfaceDescriptor()); data.writeInt32(uid); data.writeString16(callingPackage); - remote()->transact(GET_UID_PROCESS_STATE_TRANSACTION, data, &reply); + status_t err = remote()->transact(GET_UID_PROCESS_STATE_TRANSACTION, data, &reply); // fail on exception - if (reply.readExceptionCode() != 0) { + if (err != NO_ERROR || ((err = reply.readExceptionCode()) != NO_ERROR)) { return ActivityManager::PROCESS_STATE_UNKNOWN; } return reply.readInt32(); @@ -192,7 +194,7 @@ public: data.writeInt32(appPid); status_t err = remote()->transact(LOG_FGS_API_BEGIN_TRANSACTION, data, &reply, IBinder::FLAG_ONEWAY); - if (err != NO_ERROR || ((err = reply.readExceptionCode()) != NO_ERROR)) { + if (err != NO_ERROR) { ALOGD("%s: FGS Logger Transaction failed, %d", __func__, err); return err; } @@ -207,7 +209,7 @@ public: data.writeInt32(appPid); status_t err = remote()->transact(LOG_FGS_API_END_TRANSACTION, data, &reply, IBinder::FLAG_ONEWAY); - if (err != NO_ERROR || ((err = reply.readExceptionCode()) != NO_ERROR)) { + if (err != NO_ERROR) { ALOGD("%s: FGS Logger Transaction failed, %d", __func__, err); return err; } @@ -224,7 +226,7 @@ public: data.writeInt32(appPid); status_t err = remote()->transact(LOG_FGS_API_STATE_CHANGED_TRANSACTION, data, &reply, IBinder::FLAG_ONEWAY); - if (err != NO_ERROR || ((err = reply.readExceptionCode()) != NO_ERROR)) { + if (err != NO_ERROR) { ALOGD("%s: FGS Logger Transaction failed, %d", __func__, err); return err; } diff --git a/libs/binder/ndk/include_platform/android/binder_manager.h b/libs/binder/ndk/include_platform/android/binder_manager.h index f5df8d5c2f..2c2e2c8856 100644 --- a/libs/binder/ndk/include_platform/android/binder_manager.h +++ b/libs/binder/ndk/include_platform/android/binder_manager.h @@ -30,10 +30,14 @@ enum AServiceManager_AddServiceFlag : uint32_t { * not be added with this flag for privacy concerns. */ ADD_SERVICE_ALLOW_ISOLATED = 1 << 0, + /** + * Allows services to dump sections according to priorities and format + */ ADD_SERVICE_DUMP_FLAG_PRIORITY_CRITICAL = 1 << 1, ADD_SERVICE_DUMP_FLAG_PRIORITY_HIGH = 1 << 2, ADD_SERVICE_DUMP_FLAG_PRIORITY_NORMAL = 1 << 3, ADD_SERVICE_DUMP_FLAG_PRIORITY_DEFAULT = 1 << 4, + ADD_SERVICE_DUMP_FLAG_PROTO = 1 << 5, // All other bits are reserved for internal usage }; diff --git a/libs/binder/ndk/service_manager.cpp b/libs/binder/ndk/service_manager.cpp index d6ac4acc29..14bc5d2b75 100644 --- a/libs/binder/ndk/service_manager.cpp +++ b/libs/binder/ndk/service_manager.cpp @@ -63,6 +63,9 @@ binder_exception_t AServiceManager_addServiceWithFlags(AIBinder* binder, const c if (flags & AServiceManager_AddServiceFlag::ADD_SERVICE_DUMP_FLAG_PRIORITY_DEFAULT) { dumpFlags |= IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT; } + if (flags & AServiceManager_AddServiceFlag::ADD_SERVICE_DUMP_FLAG_PROTO) { + dumpFlags |= IServiceManager::DUMP_FLAG_PROTO; + } if (dumpFlags == 0) { dumpFlags = IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT; } diff --git a/libs/binder/rust/rpcbinder/Android.bp b/libs/binder/rust/rpcbinder/Android.bp index 4036551ef3..46651ceb48 100644 --- a/libs/binder/rust/rpcbinder/Android.bp +++ b/libs/binder/rust/rpcbinder/Android.bp @@ -26,6 +26,7 @@ rust_library { ], visibility: [ "//device/google/cuttlefish/shared/minidroid/sample", + "//hardware/interfaces/security/see:__subpackages__", "//packages/modules/Virtualization:__subpackages__", ], apex_available: [ diff --git a/libs/binder/tests/binderAllocationLimits.cpp b/libs/binder/tests/binderAllocationLimits.cpp index c0c0aae80b..339ce4bdf8 100644 --- a/libs/binder/tests/binderAllocationLimits.cpp +++ b/libs/binder/tests/binderAllocationLimits.cpp @@ -22,17 +22,33 @@ #include <binder/RpcServer.h> #include <binder/RpcSession.h> #include <cutils/trace.h> +#include <gtest/gtest-spi.h> #include <gtest/gtest.h> #include <utils/CallStack.h> #include <malloc.h> +#include <atomic> #include <functional> +#include <numeric> #include <vector> using namespace android::binder::impl; static android::String8 gEmpty(""); // make sure first allocation from optimization runs +struct State { + State(std::vector<size_t>&& expectedMallocs) : expectedMallocs(std::move(expectedMallocs)) {} + ~State() { + size_t num = numMallocs.load(); + if (expectedMallocs.size() != num) { + ADD_FAILURE() << "Expected " << expectedMallocs.size() << " allocations, but got " + << num; + } + } + const std::vector<size_t> expectedMallocs; + std::atomic<size_t> numMallocs; +}; + struct DestructionAction { DestructionAction(std::function<void()> f) : mF(std::move(f)) {} ~DestructionAction() { mF(); }; @@ -95,8 +111,7 @@ namespace LambdaHooks { // Action to execute when malloc is hit. Supports nesting. Malloc is not // restricted when the allocation hook is being processed. -__attribute__((warn_unused_result)) -DestructionAction OnMalloc(LambdaHooks::AllocationHook f) { +__attribute__((warn_unused_result)) DestructionAction OnMalloc(LambdaHooks::AllocationHook f) { MallocHooks before = MallocHooks::save(); LambdaHooks::lambdas.emplace_back(std::move(f)); LambdaHooks::lambda_malloc_hooks.overwrite(); @@ -106,6 +121,22 @@ DestructionAction OnMalloc(LambdaHooks::AllocationHook f) { }); } +DestructionAction setExpectedMallocs(std::vector<size_t>&& expected) { + auto state = std::make_shared<State>(std::move(expected)); + return OnMalloc([state = state](size_t bytes) { + size_t num = state->numMallocs.fetch_add(1); + if (num >= state->expectedMallocs.size() || state->expectedMallocs[num] != bytes) { + ADD_FAILURE() << "Unexpected allocation number " << num << " of size " << bytes + << " bytes" << std::endl + << android::CallStack::stackToString("UNEXPECTED ALLOCATION", + android::CallStack::getCurrent( + 4 /*ignoreDepth*/) + .get()) + << std::endl; + } + }); +} + // exported symbol, to force compiler not to optimize away pointers we set here const void* imaginary_use; @@ -119,16 +150,53 @@ TEST(TestTheTest, OnMalloc) { imaginary_use = new int[10]; } + delete[] reinterpret_cast<const int*>(imaginary_use); EXPECT_EQ(mallocs, 1u); } +TEST(TestTheTest, OnMallocWithExpectedMallocs) { + std::vector<size_t> expectedMallocs = { + 4, + 16, + 8, + }; + { + const auto on_malloc = setExpectedMallocs(std::move(expectedMallocs)); + imaginary_use = new int32_t[1]; + delete[] reinterpret_cast<const int*>(imaginary_use); + imaginary_use = new int32_t[4]; + delete[] reinterpret_cast<const int*>(imaginary_use); + imaginary_use = new int32_t[2]; + delete[] reinterpret_cast<const int*>(imaginary_use); + } +} + +TEST(TestTheTest, OnMallocWithExpectedMallocsWrongSize) { + std::vector<size_t> expectedMallocs = { + 4, + 16, + 100000, + }; + EXPECT_NONFATAL_FAILURE( + { + const auto on_malloc = setExpectedMallocs(std::move(expectedMallocs)); + imaginary_use = new int32_t[1]; + delete[] reinterpret_cast<const int*>(imaginary_use); + imaginary_use = new int32_t[4]; + delete[] reinterpret_cast<const int*>(imaginary_use); + imaginary_use = new int32_t[2]; + delete[] reinterpret_cast<const int*>(imaginary_use); + }, + "Unexpected allocation number 2 of size 8 bytes"); +} __attribute__((warn_unused_result)) DestructionAction ScopeDisallowMalloc() { return OnMalloc([&](size_t bytes) { - ADD_FAILURE() << "Unexpected allocation: " << bytes; + FAIL() << "Unexpected allocation: " << bytes; using android::CallStack; - std::cout << CallStack::stackToString("UNEXPECTED ALLOCATION", CallStack::getCurrent(4 /*ignoreDepth*/).get()) + std::cout << CallStack::stackToString("UNEXPECTED ALLOCATION", + CallStack::getCurrent(4 /*ignoreDepth*/).get()) << std::endl; }); } @@ -224,6 +292,51 @@ TEST(BinderAllocation, SmallTransaction) { EXPECT_EQ(mallocs, 1u); } +TEST(BinderAccessorAllocation, AddAccessorCheckService) { + // Need to call defaultServiceManager() before checking malloc because it + // will allocate an instance in the call_once + const auto sm = defaultServiceManager(); + const std::string kInstanceName1 = "foo.bar.IFoo/default"; + const std::string kInstanceName2 = "foo.bar.IFoo2/default"; + const String16 kInstanceName16(kInstanceName1.c_str()); + std::vector<size_t> expectedMallocs = { + // addAccessorProvider + 112, // new AccessorProvider + 16, // new AccessorProviderEntry + // checkService + 45, // String8 from String16 in CppShim::checkService + 128, // writeInterfaceToken + 16, // getInjectedAccessor, new AccessorProviderEntry + 66, // getInjectedAccessor, String16 + 45, // String8 from String16 in AccessorProvider::provide + }; + std::set<std::string> supportedInstances = {kInstanceName1, kInstanceName2}; + auto onMalloc = setExpectedMallocs(std::move(expectedMallocs)); + + auto receipt = + android::addAccessorProvider(std::move(supportedInstances), + [&](const String16&) -> sp<IBinder> { return nullptr; }); + EXPECT_FALSE(receipt.expired()); + + sp<IBinder> binder = sm->checkService(kInstanceName16); + + status_t status = android::removeAccessorProvider(receipt); +} + +TEST(BinderAccessorAllocation, AddAccessorEmpty) { + std::vector<size_t> expectedMallocs = { + 48, // From ALOGE with empty set of instances + }; + std::set<std::string> supportedInstances = {}; + auto onMalloc = setExpectedMallocs(std::move(expectedMallocs)); + + auto receipt = + android::addAccessorProvider(std::move(supportedInstances), + [&](const String16&) -> sp<IBinder> { return nullptr; }); + + EXPECT_TRUE(receipt.expired()); +} + TEST(RpcBinderAllocation, SetupRpcServer) { std::string tmp = getenv("TMPDIR") ?: "/tmp"; std::string addr = tmp + "/binderRpcBenchmark"; @@ -255,6 +368,7 @@ TEST(RpcBinderAllocation, SetupRpcServer) { } int main(int argc, char** argv) { + LOG(INFO) << "Priming static log variables for binderAllocationLimits."; if (getenv("LIBC_HOOKS_ENABLE") == nullptr) { CHECK(0 == setenv("LIBC_HOOKS_ENABLE", "1", true /*overwrite*/)); execv(argv[0], argv); diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 44aac9bfae..ebfc62f33f 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -67,7 +67,6 @@ layer_state_t::layer_state_t() reserved(0), cornerRadius(0.0f), clientDrawnCornerRadius(0.0f), - clientDrawnShadowRadius(0.0f), backgroundBlurRadius(0), color(0), bufferTransform(0), @@ -143,7 +142,6 @@ status_t layer_state_t::write(Parcel& output) const SAFE_PARCEL(output.write, colorTransform.asArray(), 16 * sizeof(float)); SAFE_PARCEL(output.writeFloat, cornerRadius); SAFE_PARCEL(output.writeFloat, clientDrawnCornerRadius); - SAFE_PARCEL(output.writeFloat, clientDrawnShadowRadius); SAFE_PARCEL(output.writeUint32, backgroundBlurRadius); SAFE_PARCEL(output.writeParcelable, metadata); SAFE_PARCEL(output.writeFloat, bgColor.r); @@ -279,7 +277,6 @@ status_t layer_state_t::read(const Parcel& input) SAFE_PARCEL(input.read, &colorTransform, 16 * sizeof(float)); SAFE_PARCEL(input.readFloat, &cornerRadius); SAFE_PARCEL(input.readFloat, &clientDrawnCornerRadius); - SAFE_PARCEL(input.readFloat, &clientDrawnShadowRadius); SAFE_PARCEL(input.readUint32, &backgroundBlurRadius); SAFE_PARCEL(input.readParcelable, &metadata); @@ -606,10 +603,6 @@ void layer_state_t::merge(const layer_state_t& other) { what |= eClientDrawnCornerRadiusChanged; clientDrawnCornerRadius = other.clientDrawnCornerRadius; } - if (other.what & eClientDrawnShadowsChanged) { - what |= eClientDrawnShadowsChanged; - clientDrawnShadowRadius = other.clientDrawnShadowRadius; - } if (other.what & eBackgroundBlurRadiusChanged) { what |= eBackgroundBlurRadiusChanged; backgroundBlurRadius = other.backgroundBlurRadius; @@ -824,7 +817,6 @@ uint64_t layer_state_t::diff(const layer_state_t& other) const { CHECK_DIFF(diff, eLayerStackChanged, other, layerStack); CHECK_DIFF(diff, eCornerRadiusChanged, other, cornerRadius); CHECK_DIFF(diff, eClientDrawnCornerRadiusChanged, other, clientDrawnCornerRadius); - CHECK_DIFF(diff, eClientDrawnShadowsChanged, other, clientDrawnShadowRadius); CHECK_DIFF(diff, eBackgroundBlurRadiusChanged, other, backgroundBlurRadius); if (other.what & eBlurRegionsChanged) diff |= eBlurRegionsChanged; if (other.what & eRelativeLayerChanged) { diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 852885be61..37ed23bd6b 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -1415,9 +1415,8 @@ std::vector<PhysicalDisplayId> SurfaceComposerClient::getPhysicalDisplayIds() { ComposerServiceAIDL::getComposerService()->getPhysicalDisplayIds(&displayIds); if (status.isOk()) { physicalDisplayIds.reserve(displayIds.size()); - for (auto item : displayIds) { - auto id = DisplayId::fromValue<PhysicalDisplayId>(static_cast<uint64_t>(item)); - physicalDisplayIds.push_back(*id); + for (auto id : displayIds) { + physicalDisplayIds.push_back(PhysicalDisplayId::fromValue(static_cast<uint64_t>(id))); } } return physicalDisplayIds; @@ -1688,17 +1687,6 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setClien return *this; } -SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setClientDrawnShadowRadius( - const sp<SurfaceControl>& sc, float clientDrawnShadowRadius) { - layer_state_t* s = getLayerState(sc); - if (!s) { - mStatus = BAD_INDEX; - return *this; - } - s->what |= layer_state_t::eClientDrawnShadowsChanged; - s->clientDrawnShadowRadius = clientDrawnShadowRadius; - return *this; -} SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setBackgroundBlurRadius( const sp<SurfaceControl>& sc, int backgroundBlurRadius) { layer_state_t* s = getLayerState(sc); diff --git a/libs/gui/include/gui/InputTransferToken.h b/libs/gui/include/gui/InputTransferToken.h index 6530b5069a..fb4aaa73ae 100644 --- a/libs/gui/include/gui/InputTransferToken.h +++ b/libs/gui/include/gui/InputTransferToken.h @@ -25,7 +25,7 @@ namespace android { struct InputTransferToken : public RefBase, Parcelable { public: - InputTransferToken() { mToken = new BBinder(); } + InputTransferToken() { mToken = sp<BBinder>::make(); } InputTransferToken(const sp<IBinder>& token) { mToken = token; } @@ -50,4 +50,4 @@ static inline bool operator==(const sp<InputTransferToken>& token1, return token1->mToken == token2->mToken; } -} // namespace android
\ No newline at end of file +} // namespace android diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index 100261423a..d04b8618f7 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -232,7 +232,6 @@ struct layer_state_t { ePictureProfileHandleChanged = 0x80000'00000000, eAppContentPriorityChanged = 0x100000'00000000, eClientDrawnCornerRadiusChanged = 0x200000'00000000, - eClientDrawnShadowsChanged = 0x400000'00000000, }; layer_state_t(); @@ -276,7 +275,7 @@ struct layer_state_t { layer_state_t::eColorSpaceAgnosticChanged | layer_state_t::eColorTransformChanged | layer_state_t::eCornerRadiusChanged | layer_state_t::eDimmingEnabledChanged | layer_state_t::eHdrMetadataChanged | layer_state_t::eShadowRadiusChanged | - layer_state_t::eClientDrawnShadowsChanged | layer_state_t::eStretchChanged | + layer_state_t::eStretchChanged | layer_state_t::ePictureProfileHandleChanged | layer_state_t::eAppContentPriorityChanged; // Changes which invalidates the layer's visible region in CE. @@ -336,7 +335,6 @@ struct layer_state_t { matrix22_t matrix; float cornerRadius; float clientDrawnCornerRadius; - float clientDrawnShadowRadius; uint32_t backgroundBlurRadius; sp<SurfaceControl> relativeLayerSurfaceControl; diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index d30a830863..10225cc114 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -569,10 +569,6 @@ public: // radius is drawn by the client and not SurfaceFlinger. Transaction& setClientDrawnCornerRadius(const sp<SurfaceControl>& sc, float clientDrawnCornerRadius); - // Sets the client drawn shadow radius for the layer. This indicates that the shadows - // are drawn by the client and not SurfaceFlinger. - Transaction& setClientDrawnShadowRadius(const sp<SurfaceControl>& sc, - float clientDrawnShadowRadius); Transaction& setBackgroundBlurRadius(const sp<SurfaceControl>& sc, int backgroundBlurRadius); Transaction& setBlurRegions(const sp<SurfaceControl>& sc, diff --git a/libs/input/Android.bp b/libs/input/Android.bp index 389fb7f6ab..d2e432063a 100644 --- a/libs/input/Android.bp +++ b/libs/input/Android.bp @@ -27,9 +27,9 @@ filegroup { name: "inputconstants_aidl", srcs: [ "android/os/IInputConstants.aidl", + "android/os/InputConfig.aidl", "android/os/InputEventInjectionResult.aidl", "android/os/InputEventInjectionSync.aidl", - "android/os/InputConfig.aidl", "android/os/MotionEventFlag.aidl", "android/os/PointerIconType.aidl", ], @@ -85,56 +85,63 @@ rust_bindgen { source_stem: "bindings", bindgen_flags: [ - "--verbose", - "--allowlist-var=AMOTION_EVENT_ACTION_CANCEL", - "--allowlist-var=AMOTION_EVENT_ACTION_UP", - "--allowlist-var=AMOTION_EVENT_ACTION_POINTER_DOWN", - "--allowlist-var=AMOTION_EVENT_ACTION_DOWN", - "--allowlist-var=AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT", - "--allowlist-var=MAX_POINTER_ID", - "--allowlist-var=AINPUT_SOURCE_CLASS_NONE", + "--allowlist-var=AINPUT_KEYBOARD_TYPE_ALPHABETIC", + "--allowlist-var=AINPUT_KEYBOARD_TYPE_NONE", + "--allowlist-var=AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC", + "--allowlist-var=AINPUT_SOURCE_BLUETOOTH_STYLUS", "--allowlist-var=AINPUT_SOURCE_CLASS_BUTTON", - "--allowlist-var=AINPUT_SOURCE_CLASS_POINTER", + "--allowlist-var=AINPUT_SOURCE_CLASS_JOYSTICK", "--allowlist-var=AINPUT_SOURCE_CLASS_NAVIGATION", + "--allowlist-var=AINPUT_SOURCE_CLASS_NONE", + "--allowlist-var=AINPUT_SOURCE_CLASS_POINTER", "--allowlist-var=AINPUT_SOURCE_CLASS_POSITION", - "--allowlist-var=AINPUT_SOURCE_CLASS_JOYSTICK", - "--allowlist-var=AINPUT_SOURCE_UNKNOWN", - "--allowlist-var=AINPUT_SOURCE_KEYBOARD", "--allowlist-var=AINPUT_SOURCE_DPAD", "--allowlist-var=AINPUT_SOURCE_GAMEPAD", - "--allowlist-var=AINPUT_SOURCE_TOUCHSCREEN", + "--allowlist-var=AINPUT_SOURCE_HDMI", + "--allowlist-var=AINPUT_SOURCE_JOYSTICK", + "--allowlist-var=AINPUT_SOURCE_KEYBOARD", "--allowlist-var=AINPUT_SOURCE_MOUSE", - "--allowlist-var=AINPUT_SOURCE_STYLUS", - "--allowlist-var=AINPUT_SOURCE_BLUETOOTH_STYLUS", - "--allowlist-var=AINPUT_SOURCE_TRACKBALL", "--allowlist-var=AINPUT_SOURCE_MOUSE_RELATIVE", + "--allowlist-var=AINPUT_SOURCE_ROTARY_ENCODER", + "--allowlist-var=AINPUT_SOURCE_SENSOR", + "--allowlist-var=AINPUT_SOURCE_STYLUS", "--allowlist-var=AINPUT_SOURCE_TOUCHPAD", + "--allowlist-var=AINPUT_SOURCE_TOUCHSCREEN", "--allowlist-var=AINPUT_SOURCE_TOUCH_NAVIGATION", - "--allowlist-var=AINPUT_SOURCE_JOYSTICK", - "--allowlist-var=AINPUT_SOURCE_HDMI", - "--allowlist-var=AINPUT_SOURCE_SENSOR", - "--allowlist-var=AINPUT_SOURCE_ROTARY_ENCODER", - "--allowlist-var=AINPUT_KEYBOARD_TYPE_NONE", - "--allowlist-var=AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC", - "--allowlist-var=AINPUT_KEYBOARD_TYPE_ALPHABETIC", - "--allowlist-var=AMETA_NONE", - "--allowlist-var=AMETA_ALT_ON", + "--allowlist-var=AINPUT_SOURCE_TRACKBALL", + "--allowlist-var=AINPUT_SOURCE_UNKNOWN", "--allowlist-var=AMETA_ALT_LEFT_ON", + "--allowlist-var=AMETA_ALT_ON", "--allowlist-var=AMETA_ALT_RIGHT_ON", - "--allowlist-var=AMETA_SHIFT_ON", - "--allowlist-var=AMETA_SHIFT_LEFT_ON", - "--allowlist-var=AMETA_SHIFT_RIGHT_ON", - "--allowlist-var=AMETA_SYM_ON", - "--allowlist-var=AMETA_FUNCTION_ON", - "--allowlist-var=AMETA_CTRL_ON", + "--allowlist-var=AMETA_CAPS_LOCK_ON", "--allowlist-var=AMETA_CTRL_LEFT_ON", + "--allowlist-var=AMETA_CTRL_ON", "--allowlist-var=AMETA_CTRL_RIGHT_ON", - "--allowlist-var=AMETA_META_ON", + "--allowlist-var=AMETA_FUNCTION_ON", "--allowlist-var=AMETA_META_LEFT_ON", + "--allowlist-var=AMETA_META_ON", "--allowlist-var=AMETA_META_RIGHT_ON", - "--allowlist-var=AMETA_CAPS_LOCK_ON", + "--allowlist-var=AMETA_NONE", "--allowlist-var=AMETA_NUM_LOCK_ON", "--allowlist-var=AMETA_SCROLL_LOCK_ON", + "--allowlist-var=AMETA_SHIFT_LEFT_ON", + "--allowlist-var=AMETA_SHIFT_ON", + "--allowlist-var=AMETA_SHIFT_RIGHT_ON", + "--allowlist-var=AMETA_SYM_ON", + "--allowlist-var=AMOTION_EVENT_ACTION_CANCEL", + "--allowlist-var=AMOTION_EVENT_ACTION_DOWN", + "--allowlist-var=AMOTION_EVENT_ACTION_POINTER_DOWN", + "--allowlist-var=AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT", + "--allowlist-var=AMOTION_EVENT_ACTION_UP", + "--allowlist-var=AMOTION_EVENT_BUTTON_BACK", + "--allowlist-var=AMOTION_EVENT_BUTTON_FORWARD", + "--allowlist-var=AMOTION_EVENT_BUTTON_PRIMARY", + "--allowlist-var=AMOTION_EVENT_BUTTON_SECONDARY", + "--allowlist-var=AMOTION_EVENT_BUTTON_STYLUS_PRIMARY", + "--allowlist-var=AMOTION_EVENT_BUTTON_STYLUS_SECONDARY", + "--allowlist-var=AMOTION_EVENT_BUTTON_TERTIARY", + "--allowlist-var=MAX_POINTER_ID", + "--verbose", ], static_libs: [ @@ -143,9 +150,9 @@ rust_bindgen { ], shared_libs: ["libc++"], header_libs: [ - "native_headers", - "jni_headers", "flatbuffer_headers", + "jni_headers", + "native_headers", ], } @@ -179,8 +186,8 @@ cc_library_static { host_supported: true, cflags: [ "-Wall", - "-Wextra", "-Werror", + "-Wextra", ], srcs: [ "FromRustToCpp.cpp", @@ -205,15 +212,15 @@ cc_library { cpp_std: "c++20", host_supported: true, cflags: [ + "-DANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION", "-Wall", - "-Wextra", "-Werror", + "-Wextra", "-Wno-unused-parameter", - "-Wthread-safety", "-Wshadow", "-Wshadow-field-in-constructor-modified", "-Wshadow-uncaptured-local", - "-DANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION", + "-Wthread-safety", ], srcs: [ "AccelerationCurve.cpp", @@ -225,10 +232,10 @@ cc_library { "InputEventLabels.cpp", "InputTransport.cpp", "InputVerifier.cpp", - "Keyboard.cpp", "KeyCharacterMap.cpp", - "KeyboardClassifier.cpp", "KeyLayoutMap.cpp", + "Keyboard.cpp", + "KeyboardClassifier.cpp", "MotionPredictor.cpp", "MotionPredictorMetricsManager.cpp", "OneEuroFilter.cpp", @@ -262,13 +269,13 @@ cc_library { shared_libs: [ "android.companion.virtualdevice.flags-aconfig-cc", + "libPlatformProperties", "libaconfig_storage_read_api_cc", "libbase", "libbinder", "libbinder_ndk", "libcutils", "liblog", - "libPlatformProperties", "libtinyxml2", "libutils", "libz", // needed by libkernelconfigs @@ -287,15 +294,15 @@ cc_library { static_libs: [ "inputconstants-cpp", - "libui-types", - "libtflite_static", "libkernelconfigs", + "libtflite_static", + "libui-types", ], whole_static_libs: [ "com.android.input.flags-aconfig-cc", - "libinput_rust_ffi", "iinputflinger_aidl_lib_static", + "libinput_rust_ffi", ], export_static_lib_headers: [ @@ -310,8 +317,8 @@ cc_library { target: { android: { required: [ - "motion_predictor_model_prebuilt", "motion_predictor_model_config", + "motion_predictor_model_prebuilt", ], static_libs: [ "libstatslog_libinput", @@ -372,9 +379,9 @@ cc_defaults { cpp_std: "c++20", host_supported: true, shared_libs: [ - "libutils", "libbase", "liblog", + "libutils", ], } diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp index 56ccaab9ad..d388d48e8d 100644 --- a/libs/input/InputTransport.cpp +++ b/libs/input/InputTransport.cpp @@ -651,9 +651,9 @@ status_t InputPublisher::publishMotionEvent( const status_t status = mChannel->sendMessage(&msg); if (status == OK && verifyEvents()) { - Result<void> result = - mInputVerifier.processMovement(deviceId, source, action, pointerCount, - pointerProperties, pointerCoords, flags); + Result<void> result = mInputVerifier.processMovement(deviceId, source, action, actionButton, + pointerCount, pointerProperties, + pointerCoords, flags, buttonState); if (!result.ok()) { LOG(ERROR) << "Bad stream: " << result.error(); return BAD_VALUE; diff --git a/libs/input/InputVerifier.cpp b/libs/input/InputVerifier.cpp index cec244539e..7811acefd0 100644 --- a/libs/input/InputVerifier.cpp +++ b/libs/input/InputVerifier.cpp @@ -17,6 +17,7 @@ #define LOG_TAG "InputVerifier" #include <android-base/logging.h> +#include <com_android_input_flags.h> #include <input/InputVerifier.h> #include "input_cxx_bridge.rs.h" @@ -26,17 +27,23 @@ using android::input::RustPointerProperties; using DeviceId = int32_t; +namespace input_flags = com::android::input::flags; + namespace android { // --- InputVerifier --- InputVerifier::InputVerifier(const std::string& name) - : mVerifier(android::input::verifier::create(rust::String::lossy(name))){}; + : mVerifier( + android::input::verifier::create(rust::String::lossy(name), + input_flags::enable_button_state_verification())) { +} Result<void> InputVerifier::processMovement(DeviceId deviceId, int32_t source, int32_t action, - uint32_t pointerCount, + int32_t actionButton, uint32_t pointerCount, const PointerProperties* pointerProperties, - const PointerCoords* pointerCoords, int32_t flags) { + const PointerCoords* pointerCoords, int32_t flags, + int32_t buttonState) { std::vector<RustPointerProperties> rpp; for (size_t i = 0; i < pointerCount; i++) { rpp.emplace_back(RustPointerProperties{.id = pointerProperties[i].id}); @@ -44,7 +51,9 @@ Result<void> InputVerifier::processMovement(DeviceId deviceId, int32_t source, i rust::Slice<const RustPointerProperties> properties{rpp.data(), rpp.size()}; rust::String errorMessage = android::input::verifier::process_movement(*mVerifier, deviceId, source, action, - properties, static_cast<uint32_t>(flags)); + actionButton, properties, + static_cast<uint32_t>(flags), + static_cast<uint32_t>(buttonState)); if (errorMessage.empty()) { return {}; } else { diff --git a/libs/input/input_flags.aconfig b/libs/input/input_flags.aconfig index 72a6fdf1bb..4e187ed333 100644 --- a/libs/input/input_flags.aconfig +++ b/libs/input/input_flags.aconfig @@ -16,6 +16,16 @@ flag { } flag { + name: "enable_button_state_verification" + namespace: "input" + description: "Set to true to enable crashing whenever bad inbound events are going into InputDispatcher" + bug: "392870542" + metadata { + purpose: PURPOSE_BUGFIX + } +} + +flag { name: "remove_input_channel_from_windowstate" namespace: "input" description: "Do not store a copy of input channel inside WindowState." diff --git a/libs/input/rust/Android.bp b/libs/input/rust/Android.bp index 63853f77fa..fae9074c4d 100644 --- a/libs/input/rust/Android.bp +++ b/libs/input/rust/Android.bp @@ -18,12 +18,12 @@ rust_defaults { srcs: ["lib.rs"], host_supported: true, rustlibs: [ + "inputconstants-rust", "libbitflags", "libcxx", "libinput_bindgen", - "liblogger", "liblog_rust", - "inputconstants-rust", + "liblogger", "libserde", "libserde_json", ], diff --git a/libs/input/rust/input.rs b/libs/input/rust/input.rs index 6956a84d40..6eb2d73b1f 100644 --- a/libs/input/rust/input.rs +++ b/libs/input/rust/input.rs @@ -101,6 +101,7 @@ bitflags! { /// A rust enum representation of a MotionEvent action. #[repr(u32)] +#[derive(Eq, PartialEq)] pub enum MotionAction { /// ACTION_DOWN Down = input_bindgen::AMOTION_EVENT_ACTION_DOWN, @@ -194,6 +195,27 @@ impl MotionAction { } bitflags! { + /// MotionEvent buttons. + #[derive(Clone, Copy, Debug, Default, Eq, PartialEq)] + pub struct MotionButton: u32 { + /// Primary button (e.g. the left mouse button) + const Primary = input_bindgen::AMOTION_EVENT_BUTTON_PRIMARY; + /// Secondary button (e.g. the right mouse button) + const Secondary = input_bindgen::AMOTION_EVENT_BUTTON_SECONDARY; + /// Tertiary button (e.g. the middle mouse button) + const Tertiary = input_bindgen::AMOTION_EVENT_BUTTON_TERTIARY; + /// Back button + const Back = input_bindgen::AMOTION_EVENT_BUTTON_BACK; + /// Forward button + const Forward = input_bindgen::AMOTION_EVENT_BUTTON_FORWARD; + /// Primary stylus button + const StylusPrimary = input_bindgen::AMOTION_EVENT_BUTTON_STYLUS_PRIMARY; + /// Secondary stylus button + const StylusSecondary = input_bindgen::AMOTION_EVENT_BUTTON_STYLUS_SECONDARY; + } +} + +bitflags! { /// MotionEvent flags. /// The source of truth for the flag definitions are the MotionEventFlag AIDL enum. /// The flag values are redefined here as a bitflags API. diff --git a/libs/input/rust/input_verifier.rs b/libs/input/rust/input_verifier.rs index bddd2a7927..6d94316272 100644 --- a/libs/input/rust/input_verifier.rs +++ b/libs/input/rust/input_verifier.rs @@ -17,20 +17,30 @@ //! Contains the InputVerifier, used to validate a stream of input events. use crate::ffi::RustPointerProperties; -use crate::input::{DeviceId, MotionAction, MotionFlags, Source, SourceClass}; +use crate::input::{DeviceId, MotionAction, MotionButton, MotionFlags, Source, SourceClass}; use log::info; use std::collections::HashMap; use std::collections::HashSet; fn verify_event( action: MotionAction, + action_button: MotionButton, pointer_properties: &[RustPointerProperties], flags: &MotionFlags, + verify_buttons: bool, ) -> Result<(), String> { let pointer_count = pointer_properties.len(); if pointer_count < 1 { return Err(format!("Invalid {} event: no pointers", action)); } + if action_button != MotionButton::empty() + && action != MotionAction::ButtonPress + && action != MotionAction::ButtonRelease + { + return Err(format!( + "Invalid {action} event: has action button {action_button:?} but is not a button action" + )); + } match action { MotionAction::Down | MotionAction::HoverEnter @@ -58,22 +68,126 @@ fn verify_event( } } + MotionAction::ButtonPress | MotionAction::ButtonRelease => { + if verify_buttons { + let button_count = action_button.iter().count(); + if button_count != 1 { + return Err(format!( + "Invalid {action} event: must specify a single action button, not \ + {button_count} action buttons" + )); + } + } + } + _ => {} } Ok(()) } +/// Keeps track of the button state for a single device and verifies events against it. +#[derive(Default)] +struct ButtonVerifier { + /// The current button state of the device. + button_state: MotionButton, + + /// The set of "pending buttons", which were seen in the last DOWN event's button state but + /// for which we haven't seen BUTTON_PRESS events yet. + /// + /// We allow DOWN events to include buttons in their state for which BUTTON_PRESS events haven't + /// been sent yet. In that case, the DOWN should be immediately followed by BUTTON_PRESS events + /// for those buttons, building up to a button state matching that of the DOWN. For example, if + /// the user presses the primary and secondary buttons at exactly the same time, we'd expect + /// this sequence: + /// + /// | Action | Action button | Button state | + /// |----------------|---------------|------------------------| + /// | `HOVER_EXIT` | - | - | + /// | `DOWN` | - | `PRIMARY`, `SECONDARY` | + /// | `BUTTON_PRESS` | `PRIMARY` | `PRIMARY` | + /// | `BUTTON_PRESS` | `SECONDARY` | `PRIMARY`, `SECONDARY` | + /// | `MOVE` | - | `PRIMARY`, `SECONDARY` | + pending_buttons: MotionButton, +} + +impl ButtonVerifier { + pub fn process_action( + &mut self, + action: MotionAction, + action_button: MotionButton, + button_state: MotionButton, + ) -> Result<(), String> { + if !self.pending_buttons.is_empty() { + // We just saw a DOWN with some additional buttons in its state, so it should be + // immediately followed by ButtonPress events for those buttons. + if action != MotionAction::ButtonPress || !self.pending_buttons.contains(action_button) + { + return Err(format!( + "After DOWN event, expected BUTTON_PRESS event(s) for {:?}, but got {} with \ + action button {:?}", + self.pending_buttons, action, action_button + )); + } else { + self.pending_buttons -= action_button; + } + } + let expected_state = match action { + MotionAction::Down => { + if self.button_state - button_state != MotionButton::empty() { + return Err(format!( + "DOWN event button state is missing {:?}", + self.button_state - button_state + )); + } + self.pending_buttons = button_state - self.button_state; + // We've already checked that the state isn't missing any already-down buttons, and + // extra buttons are valid on DOWN actions, so bypass the expected state check. + button_state + } + MotionAction::ButtonPress => { + if self.button_state.contains(action_button) { + return Err(format!( + "Duplicate BUTTON_PRESS; button state already contains {action_button:?}" + )); + } + self.button_state | action_button + } + MotionAction::ButtonRelease => { + if !self.button_state.contains(action_button) { + return Err(format!( + "Invalid BUTTON_RELEASE; button state doesn't contain {action_button:?}" + )); + } + self.button_state - action_button + } + _ => self.button_state, + }; + if button_state != expected_state { + return Err(format!( + "Expected {action} button state to be {expected_state:?}, but was {button_state:?}" + )); + } + // DOWN events can have pending buttons, so don't update the state for them. + if action != MotionAction::Down { + self.button_state = button_state; + } + Ok(()) + } +} + /// The InputVerifier is used to validate a stream of input events. pub struct InputVerifier { name: String, should_log: bool, + verify_buttons: bool, touching_pointer_ids_by_device: HashMap<DeviceId, HashSet<i32>>, hovering_pointer_ids_by_device: HashMap<DeviceId, HashSet<i32>>, + button_verifier_by_device: HashMap<DeviceId, ButtonVerifier>, } impl InputVerifier { /// Create a new InputVerifier. - pub fn new(name: &str, should_log: bool) -> Self { + pub fn new(name: &str, should_log: bool, verify_buttons: bool) -> Self { logger::init( logger::Config::default() .with_tag_on_device("InputVerifier") @@ -82,20 +196,25 @@ impl InputVerifier { Self { name: name.to_owned(), should_log, + verify_buttons, touching_pointer_ids_by_device: HashMap::new(), hovering_pointer_ids_by_device: HashMap::new(), + button_verifier_by_device: HashMap::new(), } } /// Process a pointer movement event from an InputDevice. /// If the event is not valid, we return an error string that describes the issue. + #[allow(clippy::too_many_arguments)] pub fn process_movement( &mut self, device_id: DeviceId, source: Source, action: u32, + action_button: MotionButton, pointer_properties: &[RustPointerProperties], flags: MotionFlags, + button_state: MotionButton, ) -> Result<(), String> { if !source.is_from_class(SourceClass::Pointer) { // Skip non-pointer sources like MOUSE_RELATIVE for now @@ -112,7 +231,21 @@ impl InputVerifier { ); } - verify_event(action.into(), pointer_properties, &flags)?; + verify_event( + action.into(), + action_button, + pointer_properties, + &flags, + self.verify_buttons, + )?; + + if self.verify_buttons { + self.button_verifier_by_device.entry(device_id).or_default().process_action( + action.into(), + action_button, + button_state, + )?; + } match action.into() { MotionAction::Down => { @@ -286,6 +419,7 @@ impl InputVerifier { #[cfg(test)] mod tests { + use crate::input::MotionButton; use crate::input_verifier::InputVerifier; use crate::DeviceId; use crate::MotionFlags; @@ -297,7 +431,8 @@ mod tests { * Send a DOWN event with 2 pointers and ensure that it's marked as invalid. */ fn bad_down_event() { - let mut verifier = InputVerifier::new("Test", /*should_log*/ true); + let mut verifier = + InputVerifier::new("Test", /*should_log*/ true, /*verify_buttons*/ true); let pointer_properties = Vec::from([RustPointerProperties { id: 0 }, RustPointerProperties { id: 1 }]); assert!(verifier @@ -305,23 +440,28 @@ mod tests { DeviceId(1), Source::Touchscreen, input_bindgen::AMOTION_EVENT_ACTION_DOWN, + MotionButton::empty(), &pointer_properties, MotionFlags::empty(), + MotionButton::empty(), ) .is_err()); } #[test] fn single_pointer_stream() { - let mut verifier = InputVerifier::new("Test", /*should_log*/ false); + let mut verifier = + InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true); let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]); assert!(verifier .process_movement( DeviceId(1), Source::Touchscreen, input_bindgen::AMOTION_EVENT_ACTION_DOWN, + MotionButton::empty(), &pointer_properties, MotionFlags::empty(), + MotionButton::empty(), ) .is_ok()); assert!(verifier @@ -329,8 +469,10 @@ mod tests { DeviceId(1), Source::Touchscreen, input_bindgen::AMOTION_EVENT_ACTION_MOVE, + MotionButton::empty(), &pointer_properties, MotionFlags::empty(), + MotionButton::empty(), ) .is_ok()); assert!(verifier @@ -338,23 +480,28 @@ mod tests { DeviceId(1), Source::Touchscreen, input_bindgen::AMOTION_EVENT_ACTION_UP, + MotionButton::empty(), &pointer_properties, MotionFlags::empty(), + MotionButton::empty(), ) .is_ok()); } #[test] fn two_pointer_stream() { - let mut verifier = InputVerifier::new("Test", /*should_log*/ false); + let mut verifier = + InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true); let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]); assert!(verifier .process_movement( DeviceId(1), Source::Touchscreen, input_bindgen::AMOTION_EVENT_ACTION_DOWN, + MotionButton::empty(), &pointer_properties, MotionFlags::empty(), + MotionButton::empty(), ) .is_ok()); // POINTER 1 DOWN @@ -366,8 +513,10 @@ mod tests { Source::Touchscreen, input_bindgen::AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << input_bindgen::AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + MotionButton::empty(), &two_pointer_properties, MotionFlags::empty(), + MotionButton::empty(), ) .is_ok()); // POINTER 0 UP @@ -377,8 +526,10 @@ mod tests { Source::Touchscreen, input_bindgen::AMOTION_EVENT_ACTION_POINTER_UP | (0 << input_bindgen::AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + MotionButton::empty(), &two_pointer_properties, MotionFlags::empty(), + MotionButton::empty(), ) .is_ok()); // ACTION_UP for pointer id=1 @@ -388,23 +539,28 @@ mod tests { DeviceId(1), Source::Touchscreen, input_bindgen::AMOTION_EVENT_ACTION_UP, + MotionButton::empty(), &pointer_1_properties, MotionFlags::empty(), + MotionButton::empty(), ) .is_ok()); } #[test] fn multi_device_stream() { - let mut verifier = InputVerifier::new("Test", /*should_log*/ false); + let mut verifier = + InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true); let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]); assert!(verifier .process_movement( DeviceId(1), Source::Touchscreen, input_bindgen::AMOTION_EVENT_ACTION_DOWN, + MotionButton::empty(), &pointer_properties, MotionFlags::empty(), + MotionButton::empty(), ) .is_ok()); assert!(verifier @@ -412,8 +568,10 @@ mod tests { DeviceId(1), Source::Touchscreen, input_bindgen::AMOTION_EVENT_ACTION_MOVE, + MotionButton::empty(), &pointer_properties, MotionFlags::empty(), + MotionButton::empty(), ) .is_ok()); assert!(verifier @@ -421,8 +579,10 @@ mod tests { DeviceId(2), Source::Touchscreen, input_bindgen::AMOTION_EVENT_ACTION_DOWN, + MotionButton::empty(), &pointer_properties, MotionFlags::empty(), + MotionButton::empty(), ) .is_ok()); assert!(verifier @@ -430,8 +590,10 @@ mod tests { DeviceId(2), Source::Touchscreen, input_bindgen::AMOTION_EVENT_ACTION_MOVE, + MotionButton::empty(), &pointer_properties, MotionFlags::empty(), + MotionButton::empty(), ) .is_ok()); assert!(verifier @@ -439,23 +601,28 @@ mod tests { DeviceId(1), Source::Touchscreen, input_bindgen::AMOTION_EVENT_ACTION_UP, + MotionButton::empty(), &pointer_properties, MotionFlags::empty(), + MotionButton::empty(), ) .is_ok()); } #[test] fn action_cancel() { - let mut verifier = InputVerifier::new("Test", /*should_log*/ false); + let mut verifier = + InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true); let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]); assert!(verifier .process_movement( DeviceId(1), Source::Touchscreen, input_bindgen::AMOTION_EVENT_ACTION_DOWN, + MotionButton::empty(), &pointer_properties, MotionFlags::empty(), + MotionButton::empty(), ) .is_ok()); assert!(verifier @@ -463,23 +630,28 @@ mod tests { DeviceId(1), Source::Touchscreen, input_bindgen::AMOTION_EVENT_ACTION_CANCEL, + MotionButton::empty(), &pointer_properties, MotionFlags::CANCELED, + MotionButton::empty(), ) .is_ok()); } #[test] fn invalid_action_cancel() { - let mut verifier = InputVerifier::new("Test", /*should_log*/ false); + let mut verifier = + InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true); let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]); assert!(verifier .process_movement( DeviceId(1), Source::Touchscreen, input_bindgen::AMOTION_EVENT_ACTION_DOWN, + MotionButton::empty(), &pointer_properties, MotionFlags::empty(), + MotionButton::empty(), ) .is_ok()); assert!(verifier @@ -487,38 +659,46 @@ mod tests { DeviceId(1), Source::Touchscreen, input_bindgen::AMOTION_EVENT_ACTION_CANCEL, + MotionButton::empty(), &pointer_properties, MotionFlags::empty(), // forgot to set FLAG_CANCELED + MotionButton::empty(), ) .is_err()); } #[test] fn invalid_up() { - let mut verifier = InputVerifier::new("Test", /*should_log*/ false); + let mut verifier = + InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true); let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]); assert!(verifier .process_movement( DeviceId(1), Source::Touchscreen, input_bindgen::AMOTION_EVENT_ACTION_UP, + MotionButton::empty(), &pointer_properties, MotionFlags::empty(), + MotionButton::empty(), ) .is_err()); } #[test] fn correct_hover_sequence() { - let mut verifier = InputVerifier::new("Test", /*should_log*/ false); + let mut verifier = + InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true); let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]); assert!(verifier .process_movement( DeviceId(1), Source::Touchscreen, input_bindgen::AMOTION_EVENT_ACTION_HOVER_ENTER, + MotionButton::empty(), &pointer_properties, MotionFlags::empty(), + MotionButton::empty(), ) .is_ok()); @@ -527,8 +707,10 @@ mod tests { DeviceId(1), Source::Touchscreen, input_bindgen::AMOTION_EVENT_ACTION_HOVER_MOVE, + MotionButton::empty(), &pointer_properties, MotionFlags::empty(), + MotionButton::empty(), ) .is_ok()); @@ -537,8 +719,10 @@ mod tests { DeviceId(1), Source::Touchscreen, input_bindgen::AMOTION_EVENT_ACTION_HOVER_EXIT, + MotionButton::empty(), &pointer_properties, MotionFlags::empty(), + MotionButton::empty(), ) .is_ok()); @@ -547,23 +731,28 @@ mod tests { DeviceId(1), Source::Touchscreen, input_bindgen::AMOTION_EVENT_ACTION_HOVER_ENTER, + MotionButton::empty(), &pointer_properties, MotionFlags::empty(), + MotionButton::empty(), ) .is_ok()); } #[test] fn double_hover_enter() { - let mut verifier = InputVerifier::new("Test", /*should_log*/ false); + let mut verifier = + InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true); let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]); assert!(verifier .process_movement( DeviceId(1), Source::Touchscreen, input_bindgen::AMOTION_EVENT_ACTION_HOVER_ENTER, + MotionButton::empty(), &pointer_properties, MotionFlags::empty(), + MotionButton::empty(), ) .is_ok()); @@ -572,8 +761,10 @@ mod tests { DeviceId(1), Source::Touchscreen, input_bindgen::AMOTION_EVENT_ACTION_HOVER_ENTER, + MotionButton::empty(), &pointer_properties, MotionFlags::empty(), + MotionButton::empty(), ) .is_err()); } @@ -582,15 +773,18 @@ mod tests { // MOUSE_RELATIVE, which is used during pointer capture. The verifier should allow such event. #[test] fn relative_mouse_move() { - let mut verifier = InputVerifier::new("Test", /*should_log*/ false); + let mut verifier = + InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true); let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]); assert!(verifier .process_movement( DeviceId(2), Source::MouseRelative, input_bindgen::AMOTION_EVENT_ACTION_MOVE, + MotionButton::empty(), &pointer_properties, MotionFlags::empty(), + MotionButton::empty(), ) .is_ok()); } @@ -598,15 +792,18 @@ mod tests { // Send a MOVE event with incorrect number of pointers (one of the pointers is missing). #[test] fn move_with_wrong_number_of_pointers() { - let mut verifier = InputVerifier::new("Test", /*should_log*/ false); + let mut verifier = + InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true); let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]); assert!(verifier .process_movement( DeviceId(1), Source::Touchscreen, input_bindgen::AMOTION_EVENT_ACTION_DOWN, + MotionButton::empty(), &pointer_properties, MotionFlags::empty(), + MotionButton::empty(), ) .is_ok()); // POINTER 1 DOWN @@ -618,8 +815,10 @@ mod tests { Source::Touchscreen, input_bindgen::AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << input_bindgen::AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + MotionButton::empty(), &two_pointer_properties, MotionFlags::empty(), + MotionButton::empty(), ) .is_ok()); // MOVE event with 1 pointer missing (the pointer with id = 1). It should be rejected @@ -628,8 +827,487 @@ mod tests { DeviceId(1), Source::Touchscreen, input_bindgen::AMOTION_EVENT_ACTION_MOVE, + MotionButton::empty(), + &pointer_properties, + MotionFlags::empty(), + MotionButton::empty(), + ) + .is_err()); + } + + #[test] + fn correct_button_press() { + let mut verifier = + InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true); + let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]); + assert!(verifier + .process_movement( + DeviceId(1), + Source::Mouse, + input_bindgen::AMOTION_EVENT_ACTION_BUTTON_PRESS, + MotionButton::Primary, + &pointer_properties, + MotionFlags::empty(), + MotionButton::Primary, + ) + .is_ok()); + } + + #[test] + fn button_press_without_action_button() { + let mut verifier = + InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true); + let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]); + assert!(verifier + .process_movement( + DeviceId(1), + Source::Mouse, + input_bindgen::AMOTION_EVENT_ACTION_BUTTON_PRESS, + MotionButton::empty(), + &pointer_properties, + MotionFlags::empty(), + MotionButton::empty(), + ) + .is_err()); + } + + #[test] + fn button_press_with_multiple_action_buttons() { + let mut verifier = + InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true); + let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]); + assert!(verifier + .process_movement( + DeviceId(1), + Source::Mouse, + input_bindgen::AMOTION_EVENT_ACTION_BUTTON_PRESS, + MotionButton::Back | MotionButton::Forward, + &pointer_properties, + MotionFlags::empty(), + MotionButton::Back | MotionButton::Forward, + ) + .is_err()); + } + + #[test] + fn button_press_without_action_button_in_state() { + let mut verifier = + InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true); + let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]); + assert!(verifier + .process_movement( + DeviceId(1), + Source::Mouse, + input_bindgen::AMOTION_EVENT_ACTION_BUTTON_PRESS, + MotionButton::Primary, + &pointer_properties, + MotionFlags::empty(), + MotionButton::empty(), + ) + .is_err()); + } + + #[test] + fn button_release_with_action_button_in_state() { + let mut verifier = + InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true); + let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]); + assert!(verifier + .process_movement( + DeviceId(1), + Source::Mouse, + input_bindgen::AMOTION_EVENT_ACTION_BUTTON_PRESS, + MotionButton::Primary, + &pointer_properties, + MotionFlags::empty(), + MotionButton::Primary, + ) + .is_ok()); + assert!(verifier + .process_movement( + DeviceId(1), + Source::Mouse, + input_bindgen::AMOTION_EVENT_ACTION_BUTTON_RELEASE, + MotionButton::Primary, + &pointer_properties, + MotionFlags::empty(), + MotionButton::Primary, + ) + .is_err()); + } + + #[test] + fn nonbutton_action_with_action_button() { + let mut verifier = + InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true); + let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]); + assert!(verifier + .process_movement( + DeviceId(1), + Source::Mouse, + input_bindgen::AMOTION_EVENT_ACTION_HOVER_ENTER, + MotionButton::Primary, + &pointer_properties, + MotionFlags::empty(), + MotionButton::empty(), + ) + .is_err()); + } + + #[test] + fn nonbutton_action_with_action_button_and_state() { + let mut verifier = + InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true); + let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]); + assert!(verifier + .process_movement( + DeviceId(1), + Source::Mouse, + input_bindgen::AMOTION_EVENT_ACTION_HOVER_ENTER, + MotionButton::Primary, + &pointer_properties, + MotionFlags::empty(), + MotionButton::Primary, + ) + .is_err()); + } + + #[test] + fn nonbutton_action_with_button_state_change() { + let mut verifier = + InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true); + let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]); + assert!(verifier + .process_movement( + DeviceId(1), + Source::Mouse, + input_bindgen::AMOTION_EVENT_ACTION_HOVER_ENTER, + MotionButton::empty(), + &pointer_properties, + MotionFlags::empty(), + MotionButton::empty(), + ) + .is_ok()); + assert!(verifier + .process_movement( + DeviceId(1), + Source::Mouse, + input_bindgen::AMOTION_EVENT_ACTION_HOVER_MOVE, + MotionButton::empty(), + &pointer_properties, + MotionFlags::empty(), + MotionButton::Back, + ) + .is_err()); + } + + #[test] + fn nonbutton_action_missing_button_state() { + let mut verifier = + InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true); + let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]); + assert!(verifier + .process_movement( + DeviceId(1), + Source::Mouse, + input_bindgen::AMOTION_EVENT_ACTION_HOVER_ENTER, + MotionButton::empty(), + &pointer_properties, + MotionFlags::empty(), + MotionButton::empty(), + ) + .is_ok()); + assert!(verifier + .process_movement( + DeviceId(1), + Source::Mouse, + input_bindgen::AMOTION_EVENT_ACTION_BUTTON_PRESS, + MotionButton::Back, + &pointer_properties, + MotionFlags::empty(), + MotionButton::Back, + ) + .is_ok()); + assert!(verifier + .process_movement( + DeviceId(1), + Source::Mouse, + input_bindgen::AMOTION_EVENT_ACTION_HOVER_MOVE, + MotionButton::empty(), + &pointer_properties, + MotionFlags::empty(), + MotionButton::empty(), + ) + .is_err()); + } + + #[test] + fn up_without_button_release() { + let mut verifier = + InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true); + let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]); + assert!(verifier + .process_movement( + DeviceId(1), + Source::Mouse, + input_bindgen::AMOTION_EVENT_ACTION_DOWN, + MotionButton::empty(), + &pointer_properties, + MotionFlags::empty(), + MotionButton::Primary, + ) + .is_ok()); + assert!(verifier + .process_movement( + DeviceId(1), + Source::Mouse, + input_bindgen::AMOTION_EVENT_ACTION_BUTTON_PRESS, + MotionButton::Primary, + &pointer_properties, + MotionFlags::empty(), + MotionButton::Primary, + ) + .is_ok()); + // This UP event shouldn't change the button state; a BUTTON_RELEASE before it should. + assert!(verifier + .process_movement( + DeviceId(1), + Source::Mouse, + input_bindgen::AMOTION_EVENT_ACTION_UP, + MotionButton::empty(), + &pointer_properties, + MotionFlags::empty(), + MotionButton::empty(), + ) + .is_err()); + } + + #[test] + fn button_press_for_already_pressed_button() { + let mut verifier = + InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true); + let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]); + assert!(verifier + .process_movement( + DeviceId(1), + Source::Mouse, + input_bindgen::AMOTION_EVENT_ACTION_BUTTON_PRESS, + MotionButton::Back, + &pointer_properties, + MotionFlags::empty(), + MotionButton::Back, + ) + .is_ok()); + assert!(verifier + .process_movement( + DeviceId(1), + Source::Mouse, + input_bindgen::AMOTION_EVENT_ACTION_BUTTON_PRESS, + MotionButton::Back, + &pointer_properties, + MotionFlags::empty(), + MotionButton::Back, + ) + .is_err()); + } + + #[test] + fn button_release_for_unpressed_button() { + let mut verifier = + InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true); + let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]); + assert!(verifier + .process_movement( + DeviceId(1), + Source::Mouse, + input_bindgen::AMOTION_EVENT_ACTION_BUTTON_RELEASE, + MotionButton::Back, + &pointer_properties, + MotionFlags::empty(), + MotionButton::empty(), + ) + .is_err()); + } + + #[test] + fn correct_multiple_button_presses_without_down() { + let mut verifier = + InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true); + let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]); + assert!(verifier + .process_movement( + DeviceId(1), + Source::Mouse, + input_bindgen::AMOTION_EVENT_ACTION_BUTTON_PRESS, + MotionButton::Back, + &pointer_properties, + MotionFlags::empty(), + MotionButton::Back, + ) + .is_ok()); + assert!(verifier + .process_movement( + DeviceId(1), + Source::Mouse, + input_bindgen::AMOTION_EVENT_ACTION_BUTTON_PRESS, + MotionButton::Forward, + &pointer_properties, + MotionFlags::empty(), + MotionButton::Back | MotionButton::Forward, + ) + .is_ok()); + } + + #[test] + fn correct_down_with_button_press() { + let mut verifier = + InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true); + let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]); + assert!(verifier + .process_movement( + DeviceId(1), + Source::Mouse, + input_bindgen::AMOTION_EVENT_ACTION_DOWN, + MotionButton::empty(), + &pointer_properties, + MotionFlags::empty(), + MotionButton::Primary | MotionButton::Secondary, + ) + .is_ok()); + assert!(verifier + .process_movement( + DeviceId(1), + Source::Mouse, + input_bindgen::AMOTION_EVENT_ACTION_BUTTON_PRESS, + MotionButton::Primary, + &pointer_properties, + MotionFlags::empty(), + MotionButton::Primary, + ) + .is_ok()); + assert!(verifier + .process_movement( + DeviceId(1), + Source::Mouse, + input_bindgen::AMOTION_EVENT_ACTION_BUTTON_PRESS, + MotionButton::Secondary, + &pointer_properties, + MotionFlags::empty(), + MotionButton::Primary | MotionButton::Secondary, + ) + .is_ok()); + // Also check that the MOVE afterwards is OK, as that's where errors would be raised if not + // enough BUTTON_PRESSes were sent. + assert!(verifier + .process_movement( + DeviceId(1), + Source::Mouse, + input_bindgen::AMOTION_EVENT_ACTION_MOVE, + MotionButton::empty(), + &pointer_properties, + MotionFlags::empty(), + MotionButton::Primary | MotionButton::Secondary, + ) + .is_ok()); + } + + #[test] + fn down_with_button_state_change_not_followed_by_button_press() { + let mut verifier = + InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true); + let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]); + assert!(verifier + .process_movement( + DeviceId(1), + Source::Mouse, + input_bindgen::AMOTION_EVENT_ACTION_DOWN, + MotionButton::empty(), + &pointer_properties, + MotionFlags::empty(), + MotionButton::Primary, + ) + .is_ok()); + // The DOWN event itself is OK, but it needs to be immediately followed by a BUTTON_PRESS. + assert!(verifier + .process_movement( + DeviceId(1), + Source::Mouse, + input_bindgen::AMOTION_EVENT_ACTION_MOVE, + MotionButton::empty(), + &pointer_properties, + MotionFlags::empty(), + MotionButton::Primary, + ) + .is_err()); + } + + #[test] + fn down_with_button_state_change_not_followed_by_enough_button_presses() { + let mut verifier = + InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true); + let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]); + assert!(verifier + .process_movement( + DeviceId(1), + Source::Mouse, + input_bindgen::AMOTION_EVENT_ACTION_DOWN, + MotionButton::empty(), + &pointer_properties, + MotionFlags::empty(), + MotionButton::Primary | MotionButton::Secondary, + ) + .is_ok()); + // The DOWN event itself is OK, but it needs to be immediately followed by two + // BUTTON_PRESSes, one for each button. + assert!(verifier + .process_movement( + DeviceId(1), + Source::Mouse, + input_bindgen::AMOTION_EVENT_ACTION_BUTTON_PRESS, + MotionButton::Primary, + &pointer_properties, + MotionFlags::empty(), + MotionButton::Primary, + ) + .is_ok()); + assert!(verifier + .process_movement( + DeviceId(1), + Source::Mouse, + input_bindgen::AMOTION_EVENT_ACTION_MOVE, + MotionButton::empty(), + &pointer_properties, + MotionFlags::empty(), + MotionButton::Primary, + ) + .is_err()); + } + + #[test] + fn down_missing_already_pressed_button() { + let mut verifier = + InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true); + let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]); + assert!(verifier + .process_movement( + DeviceId(1), + Source::Mouse, + input_bindgen::AMOTION_EVENT_ACTION_BUTTON_PRESS, + MotionButton::Back, + &pointer_properties, + MotionFlags::empty(), + MotionButton::Back, + ) + .is_ok()); + assert!(verifier + .process_movement( + DeviceId(1), + Source::Mouse, + input_bindgen::AMOTION_EVENT_ACTION_DOWN, + MotionButton::empty(), &pointer_properties, MotionFlags::empty(), + MotionButton::empty(), ) .is_err()); } diff --git a/libs/input/rust/lib.rs b/libs/input/rust/lib.rs index 4f4ea8568b..6db4356da1 100644 --- a/libs/input/rust/lib.rs +++ b/libs/input/rust/lib.rs @@ -24,8 +24,8 @@ mod keyboard_classifier; pub use data_store::{DataStore, DefaultFileReaderWriter}; pub use input::{ - DeviceClass, DeviceId, InputDevice, KeyboardType, ModifierState, MotionAction, MotionFlags, - Source, + DeviceClass, DeviceId, InputDevice, KeyboardType, ModifierState, MotionAction, MotionButton, + MotionFlags, Source, }; pub use input_verifier::InputVerifier; pub use keyboard_classifier::KeyboardClassifier; @@ -57,14 +57,17 @@ mod ffi { /// ``` type InputVerifier; #[cxx_name = create] - fn create_input_verifier(name: String) -> Box<InputVerifier>; + fn create_input_verifier(name: String, verify_buttons: bool) -> Box<InputVerifier>; + #[allow(clippy::too_many_arguments)] fn process_movement( verifier: &mut InputVerifier, device_id: i32, source: u32, action: u32, + action_button: u32, pointer_properties: &[RustPointerProperties], flags: u32, + button_state: u32, ) -> String; fn reset_device(verifier: &mut InputVerifier, device_id: i32); } @@ -115,17 +118,20 @@ mod ffi { use crate::ffi::{RustInputDeviceIdentifier, RustPointerProperties}; -fn create_input_verifier(name: String) -> Box<InputVerifier> { - Box::new(InputVerifier::new(&name, ffi::shouldLog("InputVerifierLogEvents"))) +fn create_input_verifier(name: String, verify_buttons: bool) -> Box<InputVerifier> { + Box::new(InputVerifier::new(&name, ffi::shouldLog("InputVerifierLogEvents"), verify_buttons)) } +#[allow(clippy::too_many_arguments)] fn process_movement( verifier: &mut InputVerifier, device_id: i32, source: u32, action: u32, + action_button: u32, pointer_properties: &[RustPointerProperties], flags: u32, + button_state: u32, ) -> String { let motion_flags = MotionFlags::from_bits(flags); if motion_flags.is_none() { @@ -135,12 +141,28 @@ fn process_movement( flags ); } + let motion_action_button = MotionButton::from_bits(action_button); + if motion_action_button.is_none() { + panic!( + "The conversion of action button 0x{action_button:08x} failed, please check if some \ + buttons need to be added to MotionButton." + ); + } + let motion_button_state = MotionButton::from_bits(button_state); + if motion_button_state.is_none() { + panic!( + "The conversion of button state 0x{button_state:08x} failed, please check if some \ + buttons need to be added to MotionButton." + ); + } let result = verifier.process_movement( DeviceId(device_id), Source::from_bits(source).unwrap(), action, + motion_action_button.unwrap(), pointer_properties, motion_flags.unwrap(), + motion_button_state.unwrap(), ); match result { Ok(()) => "".to_string(), diff --git a/libs/input/tests/Android.bp b/libs/input/tests/Android.bp index 85a37fe04a..968fa5fc1a 100644 --- a/libs/input/tests/Android.bp +++ b/libs/input/tests/Android.bp @@ -16,16 +16,16 @@ cc_test { "BlockingQueue_test.cpp", "IdGenerator_test.cpp", "InputChannel_test.cpp", - "InputConsumer_test.cpp", "InputConsumerFilteredResampling_test.cpp", "InputConsumerResampling_test.cpp", + "InputConsumer_test.cpp", "InputDevice_test.cpp", "InputEvent_test.cpp", - "InputPublisherAndConsumer_test.cpp", "InputPublisherAndConsumerNoResampling_test.cpp", + "InputPublisherAndConsumer_test.cpp", "InputVerifier_test.cpp", - "MotionPredictor_test.cpp", "MotionPredictorMetricsManager_test.cpp", + "MotionPredictor_test.cpp", "OneEuroFilter_test.cpp", "Resampler_test.cpp", "RingBuffer_test.cpp", @@ -53,8 +53,8 @@ cc_test { ], cflags: [ "-Wall", - "-Wextra", "-Werror", + "-Wextra", "-Wno-unused-parameter", ], sanitize: { @@ -68,26 +68,26 @@ cc_test { memtag_heap: true, undefined: true, misc_undefined: [ - "bounds", "all", + "bounds", ], }, }, shared_libs: [ + "libPlatformProperties", "libaconfig_storage_read_api_cc", "libbase", "libbinder", "libcutils", "liblog", - "libPlatformProperties", "libstatslog", "libtinyxml2", "libutils", "server_configurable_flags", ], data: [ - "data/*", ":motion_predictor_model", + "data/*", ], test_options: { unit_test: true, @@ -117,10 +117,10 @@ cc_library_static { "-Wextra", ], shared_libs: [ - "libinput", + "libbase", + "libbinder", "libcutils", + "libinput", "libutils", - "libbinder", - "libbase", ], } diff --git a/libs/input/tests/InputVerifier_test.cpp b/libs/input/tests/InputVerifier_test.cpp index 5bb1d56040..8e0d9068c1 100644 --- a/libs/input/tests/InputVerifier_test.cpp +++ b/libs/input/tests/InputVerifier_test.cpp @@ -49,9 +49,9 @@ TEST(InputVerifierTest, ProcessSourceClassPointer) { const Result<void> result = verifier.processMovement(/*deviceId=*/0, AINPUT_SOURCE_CLASS_POINTER, - AMOTION_EVENT_ACTION_DOWN, + AMOTION_EVENT_ACTION_DOWN, /*actionButton=*/0, /*pointerCount=*/properties.size(), properties.data(), - coords.data(), /*flags=*/0); + coords.data(), /*flags=*/0, /*buttonState=*/0); ASSERT_RESULT_OK(result); } diff --git a/libs/renderengine/skia/filters/KawaseBlurDualFilter.cpp b/libs/renderengine/skia/filters/KawaseBlurDualFilter.cpp index 897f5cfc2a..ff96b08283 100644 --- a/libs/renderengine/skia/filters/KawaseBlurDualFilter.cpp +++ b/libs/renderengine/skia/filters/KawaseBlurDualFilter.cpp @@ -39,12 +39,36 @@ namespace renderengine { namespace skia { KawaseBlurDualFilter::KawaseBlurDualFilter() : BlurFilter() { - // A shader to sample each vertex of a unit regular heptagon - // plus the original fragment coordinate. - SkString blurString(R"( + // A shader to sample each vertex of a square, plus the original fragment coordinate, + // using a total of 5 samples. + SkString lowSampleBlurString(R"( uniform shader child; uniform float in_blurOffset; uniform float in_crossFade; + uniform float in_weightedCrossFade; + + const float2 STEP_0 = float2( 0.707106781, 0.707106781); + const float2 STEP_1 = float2( 0.707106781, -0.707106781); + const float2 STEP_2 = float2(-0.707106781, -0.707106781); + const float2 STEP_3 = float2(-0.707106781, 0.707106781); + + half4 main(float2 xy) { + half3 c = child.eval(xy).rgb; + + c += child.eval(xy + STEP_0 * in_blurOffset).rgb; + c += child.eval(xy + STEP_1 * in_blurOffset).rgb; + c += child.eval(xy + STEP_2 * in_blurOffset).rgb; + c += child.eval(xy + STEP_3 * in_blurOffset).rgb; + + return half4(c * in_weightedCrossFade, in_crossFade); + } + )"); + + // A shader to sample each vertex of a unit regular heptagon, plus the original fragment + // coordinate, using a total of 8 samples. + SkString highSampleBlurString(R"( + uniform shader child; + uniform float in_blurOffset; const float2 STEP_0 = float2( 1.0, 0.0); const float2 STEP_1 = float2( 0.623489802, 0.781831482); @@ -65,39 +89,46 @@ KawaseBlurDualFilter::KawaseBlurDualFilter() : BlurFilter() { c += child.eval(xy + STEP_5 * in_blurOffset).rgb; c += child.eval(xy + STEP_6 * in_blurOffset).rgb; - return half4(c * 0.125 * in_crossFade, in_crossFade); + return half4(c * 0.125, 1.0); } )"); - auto [blurEffect, error] = SkRuntimeEffect::MakeForShader(blurString); - LOG_ALWAYS_FATAL_IF(!blurEffect, "RuntimeShader error: %s", error.c_str()); - mBlurEffect = std::move(blurEffect); + auto [lowSampleBlurEffect, error] = SkRuntimeEffect::MakeForShader(lowSampleBlurString); + auto [highSampleBlurEffect, error2] = SkRuntimeEffect::MakeForShader(highSampleBlurString); + LOG_ALWAYS_FATAL_IF(!lowSampleBlurEffect, "RuntimeShader error: %s", error.c_str()); + LOG_ALWAYS_FATAL_IF(!highSampleBlurEffect, "RuntimeShader error: %s", error2.c_str()); + mLowSampleBlurEffect = std::move(lowSampleBlurEffect); + mHighSampleBlurEffect = std::move(highSampleBlurEffect); } void KawaseBlurDualFilter::blurInto(const sk_sp<SkSurface>& drawSurface, const sk_sp<SkImage>& readImage, const float radius, - const float alpha) const { + const float alpha, + const sk_sp<SkRuntimeEffect>& blurEffect) const { const float scale = static_cast<float>(drawSurface->width()) / readImage->width(); SkMatrix blurMatrix = SkMatrix::Scale(scale, scale); blurInto(drawSurface, readImage->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kNone), blurMatrix), - readImage->width() / static_cast<float>(drawSurface->width()), radius, alpha); + radius, alpha, blurEffect); } void KawaseBlurDualFilter::blurInto(const sk_sp<SkSurface>& drawSurface, sk_sp<SkShader> input, - const float inverseScale, const float radius, - const float alpha) const { + const float radius, const float alpha, + const sk_sp<SkRuntimeEffect>& blurEffect) const { SkPaint paint; if (radius == 0) { paint.setShader(std::move(input)); paint.setAlphaf(alpha); } else { - SkRuntimeShaderBuilder blurBuilder(mBlurEffect); + SkRuntimeShaderBuilder blurBuilder(blurEffect); blurBuilder.child("child") = std::move(input); + if (blurEffect == mLowSampleBlurEffect) { + blurBuilder.uniform("in_crossFade") = alpha; + blurBuilder.uniform("in_weightedCrossFade") = alpha * 0.2f; + } blurBuilder.uniform("in_blurOffset") = radius; - blurBuilder.uniform("in_crossFade") = alpha; paint.setShader(blurBuilder.makeShader(nullptr)); } paint.setBlendMode(alpha == 1.0f ? SkBlendMode::kSrc : SkBlendMode::kSrcOver); @@ -163,16 +194,19 @@ sk_sp<SkImage> KawaseBlurDualFilter::generate(SkiaGpuContext* context, const uin input->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kNone), blurMatrix); - blurInto(surfaces[0], std::move(sourceShader), kInputScale, kWeights[0] * step, 1.0f); + blurInto(surfaces[0], std::move(sourceShader), kWeights[0] * step, 1.0f, + mLowSampleBlurEffect); } // Next the remaining downscale blur passes. for (int i = 0; i < filterPasses; i++) { - blurInto(surfaces[i + 1], surfaces[i]->makeTemporaryImage(), kWeights[1 + i] * step, 1.0f); + // Blur with the higher sample effect into the smaller buffers, for better visual quality. + blurInto(surfaces[i + 1], surfaces[i]->makeTemporaryImage(), kWeights[1 + i] * step, 1.0f, + i == 0 ? mLowSampleBlurEffect : mHighSampleBlurEffect); } // Finally blur+upscale back to our original size. for (int i = filterPasses - 1; i >= 0; i--) { blurInto(surfaces[i], surfaces[i + 1]->makeTemporaryImage(), kWeights[4 - i] * step, - std::min(1.0f, filterDepth - i)); + std::min(1.0f, filterDepth - i), mLowSampleBlurEffect); } return surfaces[0]->makeTemporaryImage(); } diff --git a/libs/renderengine/skia/filters/KawaseBlurDualFilter.h b/libs/renderengine/skia/filters/KawaseBlurDualFilter.h index 6f4adbf34c..5efda35376 100644 --- a/libs/renderengine/skia/filters/KawaseBlurDualFilter.h +++ b/libs/renderengine/skia/filters/KawaseBlurDualFilter.h @@ -41,13 +41,14 @@ public: const sk_sp<SkImage> blurInput, const SkRect& blurRect) const override; private: - sk_sp<SkRuntimeEffect> mBlurEffect; + sk_sp<SkRuntimeEffect> mLowSampleBlurEffect; + sk_sp<SkRuntimeEffect> mHighSampleBlurEffect; void blurInto(const sk_sp<SkSurface>& drawSurface, const sk_sp<SkImage>& readImage, - const float radius, const float alpha) const; + const float radius, const float alpha, const sk_sp<SkRuntimeEffect>&) const; void blurInto(const sk_sp<SkSurface>& drawSurface, const sk_sp<SkShader> input, - const float inverseScale, const float radius, const float alpha) const; + const float radius, const float alpha, const sk_sp<SkRuntimeEffect>&) const; }; } // namespace skia diff --git a/libs/tracing_perfetto/tracing_perfetto_internal.cpp b/libs/tracing_perfetto/tracing_perfetto_internal.cpp index f92f6df990..447873290c 100644 --- a/libs/tracing_perfetto/tracing_perfetto_internal.cpp +++ b/libs/tracing_perfetto/tracing_perfetto_internal.cpp @@ -14,15 +14,16 @@ * limitations under the License. */ +// Should match the definitions in: frameworks/native/cmds/atrace/atrace.cpp #define FRAMEWORK_CATEGORIES(C) \ C(always, "always", "Always category") \ - C(graphics, "graphics", "Graphics category") \ + C(graphics, "gfx", "Graphics category") \ C(input, "input", "Input category") \ C(view, "view", "View category") \ C(webview, "webview", "WebView category") \ C(windowmanager, "wm", "WindowManager category") \ C(activitymanager, "am", "ActivityManager category") \ - C(syncmanager, "syncmanager", "SyncManager category") \ + C(syncmanager, "sm", "SyncManager category") \ C(audio, "audio", "Audio category") \ C(video, "video", "Video category") \ C(camera, "camera", "Camera category") \ @@ -33,7 +34,7 @@ C(rs, "rs", "RS category") \ C(bionic, "bionic", "Bionic category") \ C(power, "power", "Power category") \ - C(packagemanager, "packagemanager", "PackageManager category") \ + C(packagemanager, "pm", "PackageManager category") \ C(systemserver, "ss", "System Server category") \ C(database, "database", "Database category") \ C(network, "network", "Network category") \ diff --git a/libs/ui/DisplayIdentification.cpp b/libs/ui/DisplayIdentification.cpp index b7ef9b3738..78e84fc4dc 100644 --- a/libs/ui/DisplayIdentification.cpp +++ b/libs/ui/DisplayIdentification.cpp @@ -444,7 +444,7 @@ PhysicalDisplayId generateEdidDisplayId(const Edid& edid) { (edid.hashedBlockZeroSerialNumberOpt.value_or(0) >> 11) ^ (edid.hashedDescriptorBlockSerialNumberOpt.value_or(0) << 23); - return PhysicalDisplayId::fromEdidHash(id); + return PhysicalDisplayId::fromValue(id); } } // namespace android diff --git a/libs/ui/include/ui/DisplayId.h b/libs/ui/include/ui/DisplayId.h index 13ed754534..937e3f1486 100644 --- a/libs/ui/include/ui/DisplayId.h +++ b/libs/ui/include/ui/DisplayId.h @@ -30,27 +30,16 @@ struct DisplayId { // Flag indicating that the display is virtual. static constexpr uint64_t FLAG_VIRTUAL = 1ULL << 63; - // TODO(b/162612135) Remove default constructor + // TODO: b/162612135 - Remove default constructor. DisplayId() = default; constexpr DisplayId(const DisplayId&) = default; DisplayId& operator=(const DisplayId&) = default; + static constexpr DisplayId fromValue(uint64_t value) { return DisplayId(value); } constexpr bool isVirtual() const { return value & FLAG_VIRTUAL; } uint64_t value; - // For deserialization. - static constexpr std::optional<DisplayId> fromValue(uint64_t); - - // As above, but also upcast to Id. - template <typename Id> - static constexpr std::optional<Id> fromValue(uint64_t value) { - if (const auto id = Id::tryCast(DisplayId(value))) { - return id; - } - return {}; - } - protected: explicit constexpr DisplayId(uint64_t id) : value(id) {} }; @@ -74,6 +63,9 @@ inline std::ostream& operator<<(std::ostream& stream, DisplayId displayId) { // DisplayId of a physical display, such as the internal display or externally connected display. struct PhysicalDisplayId : DisplayId { + // TODO: b/162612135 - Remove default constructor. + PhysicalDisplayId() = default; + static constexpr ftl::Optional<PhysicalDisplayId> tryCast(DisplayId id) { if (id.isVirtual()) { return std::nullopt; @@ -87,11 +79,6 @@ struct PhysicalDisplayId : DisplayId { return PhysicalDisplayId(FLAG_STABLE, port, manufacturerId, modelHash); } - // Returns a stable and consistent ID based exclusively on EDID information. - static constexpr PhysicalDisplayId fromEdidHash(uint64_t hashedEdid) { - return PhysicalDisplayId(hashedEdid); - } - // Returns an unstable ID. If EDID is available using "fromEdid" is preferred. static constexpr PhysicalDisplayId fromPort(uint8_t port) { constexpr uint16_t kManufacturerId = 0; @@ -99,8 +86,9 @@ struct PhysicalDisplayId : DisplayId { return PhysicalDisplayId(0, port, kManufacturerId, kModelHash); } - // TODO(b/162612135) Remove default constructor - PhysicalDisplayId() = default; + static constexpr PhysicalDisplayId fromValue(uint64_t value) { + return PhysicalDisplayId(value); + } constexpr uint8_t getPort() const { return static_cast<uint8_t>(value); } @@ -131,8 +119,15 @@ struct VirtualDisplayId : DisplayId { return std::nullopt; } + static constexpr VirtualDisplayId fromValue(uint64_t value) { + return VirtualDisplayId(SkipVirtualFlag{}, value); + } + protected: + struct SkipVirtualFlag {}; + constexpr VirtualDisplayId(SkipVirtualFlag, uint64_t value) : DisplayId(value) {} explicit constexpr VirtualDisplayId(uint64_t value) : DisplayId(FLAG_VIRTUAL | value) {} + explicit constexpr VirtualDisplayId(DisplayId other) : DisplayId(other) {} }; @@ -146,8 +141,12 @@ struct HalVirtualDisplayId : VirtualDisplayId { return std::nullopt; } + static constexpr HalVirtualDisplayId fromValue(uint64_t value) { + return HalVirtualDisplayId(SkipVirtualFlag{}, value); + } + private: - explicit constexpr HalVirtualDisplayId(DisplayId other) : VirtualDisplayId(other) {} + using VirtualDisplayId::VirtualDisplayId; }; struct GpuVirtualDisplayId : VirtualDisplayId { @@ -160,8 +159,12 @@ struct GpuVirtualDisplayId : VirtualDisplayId { return std::nullopt; } + static constexpr GpuVirtualDisplayId fromValue(uint64_t value) { + return GpuVirtualDisplayId(SkipVirtualFlag{}, value); + } + private: - explicit constexpr GpuVirtualDisplayId(DisplayId other) : VirtualDisplayId(other) {} + using VirtualDisplayId::VirtualDisplayId; }; // HalDisplayId is the ID of a display which is managed by HWC. @@ -177,20 +180,13 @@ struct HalDisplayId : DisplayId { return HalDisplayId(id); } + static constexpr HalDisplayId fromValue(uint64_t value) { return HalDisplayId(value); } + private: + using DisplayId::DisplayId; explicit constexpr HalDisplayId(DisplayId other) : DisplayId(other) {} }; -constexpr std::optional<DisplayId> DisplayId::fromValue(uint64_t value) { - if (const auto id = fromValue<PhysicalDisplayId>(value)) { - return id; - } - if (const auto id = fromValue<VirtualDisplayId>(value)) { - return id; - } - return {}; -} - static_assert(sizeof(DisplayId) == sizeof(uint64_t)); static_assert(sizeof(HalDisplayId) == sizeof(uint64_t)); static_assert(sizeof(VirtualDisplayId) == sizeof(uint64_t)); diff --git a/libs/ui/include/ui/ShadowSettings.h b/libs/ui/include/ui/ShadowSettings.h index 06be6dbbf5..c0b83b8691 100644 --- a/libs/ui/include/ui/ShadowSettings.h +++ b/libs/ui/include/ui/ShadowSettings.h @@ -46,9 +46,6 @@ struct ShadowSettings { // Length of the cast shadow. If length is <= 0.f no shadows will be drawn. float length = 0.f; - // Length of the cast shadow that is drawn by the client. - float clientDrawnLength = 0.f; - // If true fill in the casting layer is translucent and the shadow needs to fill the bounds. // Otherwise the shadow will only be drawn around the edges of the casting layer. bool casterIsTranslucent = false; @@ -58,7 +55,6 @@ static inline bool operator==(const ShadowSettings& lhs, const ShadowSettings& r return lhs.boundaries == rhs.boundaries && lhs.ambientColor == rhs.ambientColor && lhs.spotColor == rhs.spotColor && lhs.lightPos == rhs.lightPos && lhs.lightRadius == rhs.lightRadius && lhs.length == rhs.length && - lhs.clientDrawnLength == rhs.clientDrawnLength && lhs.casterIsTranslucent == rhs.casterIsTranslucent; } diff --git a/libs/ui/tests/DisplayId_test.cpp b/libs/ui/tests/DisplayId_test.cpp index 090d2eefc3..209acba672 100644 --- a/libs/ui/tests/DisplayId_test.cpp +++ b/libs/ui/tests/DisplayId_test.cpp @@ -33,7 +33,7 @@ TEST(DisplayIdTest, createPhysicalIdFromEdid) { EXPECT_TRUE(HalDisplayId::tryCast(id)); EXPECT_EQ(id, DisplayId::fromValue(id.value)); - EXPECT_EQ(id, DisplayId::fromValue<PhysicalDisplayId>(id.value)); + EXPECT_EQ(id, PhysicalDisplayId::fromValue(id.value)); } TEST(DisplayIdTest, createPhysicalIdFromPort) { @@ -47,7 +47,7 @@ TEST(DisplayIdTest, createPhysicalIdFromPort) { EXPECT_TRUE(HalDisplayId::tryCast(id)); EXPECT_EQ(id, DisplayId::fromValue(id.value)); - EXPECT_EQ(id, DisplayId::fromValue<PhysicalDisplayId>(id.value)); + EXPECT_EQ(id, PhysicalDisplayId::fromValue(id.value)); } TEST(DisplayIdTest, createGpuVirtualId) { @@ -59,7 +59,7 @@ TEST(DisplayIdTest, createGpuVirtualId) { EXPECT_FALSE(HalDisplayId::tryCast(id)); EXPECT_EQ(id, DisplayId::fromValue(id.value)); - EXPECT_EQ(id, DisplayId::fromValue<GpuVirtualDisplayId>(id.value)); + EXPECT_EQ(id, GpuVirtualDisplayId::fromValue(id.value)); } TEST(DisplayIdTest, createVirtualIdFromGpuVirtualId) { @@ -83,7 +83,7 @@ TEST(DisplayIdTest, createHalVirtualId) { EXPECT_TRUE(HalDisplayId::tryCast(id)); EXPECT_EQ(id, DisplayId::fromValue(id.value)); - EXPECT_EQ(id, DisplayId::fromValue<HalVirtualDisplayId>(id.value)); + EXPECT_EQ(id, HalVirtualDisplayId::fromValue(id.value)); } TEST(DisplayIdTest, createVirtualIdFromHalVirtualId) { diff --git a/opengl/tools/glgen/stubs/egl/eglCreateWindowSurface.cpp b/opengl/tools/glgen/stubs/egl/eglCreateWindowSurface.cpp index 7c255ed106..5ba72affc0 100644 --- a/opengl/tools/glgen/stubs/egl/eglCreateWindowSurface.cpp +++ b/opengl/tools/glgen/stubs/egl/eglCreateWindowSurface.cpp @@ -113,7 +113,7 @@ not_valid_surface: if (producer == NULL) goto not_valid_surface; - window = new android::Surface(producer, true); + window = android::sp<android::Surface>::make(producer, true); if (window == NULL) goto not_valid_surface; diff --git a/services/automotive/display/AutomotiveDisplayProxyService.cpp b/services/automotive/display/AutomotiveDisplayProxyService.cpp index d205231033..afa623352b 100644 --- a/services/automotive/display/AutomotiveDisplayProxyService.cpp +++ b/services/automotive/display/AutomotiveDisplayProxyService.cpp @@ -34,10 +34,8 @@ AutomotiveDisplayProxyService::getIGraphicBufferProducer(uint64_t id) { sp<IBinder> displayToken = nullptr; sp<SurfaceControl> surfaceControl = nullptr; if (it == mDisplays.end()) { - if (const auto displayId = DisplayId::fromValue<PhysicalDisplayId>(id)) { - displayToken = SurfaceComposerClient::getPhysicalDisplayToken(*displayId); - } - + displayToken = + SurfaceComposerClient::getPhysicalDisplayToken(PhysicalDisplayId::fromValue(id)); if (displayToken == nullptr) { ALOGE("Given display id, 0x%lX, is invalid.", (unsigned long)id); return nullptr; @@ -160,11 +158,8 @@ Return<void> AutomotiveDisplayProxyService::getDisplayInfo(uint64_t id, getDispl HwDisplayConfig activeConfig; HwDisplayState activeState; - sp<IBinder> displayToken; - if (const auto displayId = DisplayId::fromValue<PhysicalDisplayId>(id)) { - displayToken = SurfaceComposerClient::getPhysicalDisplayToken(*displayId); - } - + sp<IBinder> displayToken = + SurfaceComposerClient::getPhysicalDisplayToken(PhysicalDisplayId::fromValue(id)); if (displayToken == nullptr) { ALOGE("Given display id, 0x%lX, is invalid.", (unsigned long)id); } else { @@ -197,4 +192,3 @@ Return<void> AutomotiveDisplayProxyService::getDisplayInfo(uint64_t id, getDispl } // namespace automotive } // namespace frameworks } // namespace android - diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp index ca92ab5aca..107fd207be 100644 --- a/services/inputflinger/Android.bp +++ b/services/inputflinger/Android.bp @@ -32,15 +32,15 @@ cc_defaults { host_supported: true, cpp_std: "c++20", cflags: [ + "-DANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION", "-Wall", - "-Wextra", "-Werror", + "-Wextra", "-Wno-unused-parameter", - "-Wthread-safety", "-Wshadow", "-Wshadow-field-in-constructor-modified", "-Wshadow-uncaptured-local", - "-DANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION", + "-Wthread-safety", ], sanitize: { misc_undefined: [ @@ -62,8 +62,8 @@ cc_defaults { memtag_heap: true, undefined: true, misc_undefined: [ - "bounds", "all", + "bounds", ], }, }, @@ -114,16 +114,16 @@ cc_defaults { "liblog", "libprotobuf-cpp-lite", "libstatslog", - "libutils", "libstatspull", "libstatssocket", + "libutils", "packagemanager_aidl-cpp", "server_configurable_flags", ], static_libs: [ "libattestation", - "libperfetto_client_experimental", "libpalmrejection", + "libperfetto_client_experimental", "libui-types", ], generated_headers: [ @@ -161,10 +161,10 @@ cc_library_shared { shared_libs: [ // This should consist only of dependencies from inputflinger. Other dependencies should be // in cc_defaults so that they are included in the tests. + "libPlatformProperties", "libinputflinger_base", "libinputreader", "libinputreporter", - "libPlatformProperties", ], static_libs: [ "libinputdispatcher", @@ -185,8 +185,8 @@ cc_library_headers { name: "libinputflinger_headers", host_supported: true, export_include_dirs: [ - "include", ".", + "include", ], header_libs: [ "libchrome-gestures_headers", @@ -247,49 +247,40 @@ cc_library_shared { phony { name: "checkinput", required: [ - // native targets - "libgui_test", - "libinput", - "libinputreader_static", - "libinputflinger", - "inputflinger_tests", - "inputflinger_benchmarks", - "libinput_tests", - "libpalmrejection_test", - "libandroid_runtime", - "libinputservice_test", "Bug-115739809", - "StructLayout_test", - - // jni - "libservices.core", - - // rust targets - "libinput_rust_test", - - // native fuzzers - "inputflinger_latencytracker_fuzzer", - "inputflinger_cursor_input_fuzzer", - "inputflinger_keyboard_input_fuzzer", - "inputflinger_multitouch_input_fuzzer", - "inputflinger_switch_input_fuzzer", - "inputflinger_touchpad_input_fuzzer", - "inputflinger_input_reader_fuzzer", - "inputflinger_blocking_queue_fuzzer", - "inputflinger_input_classifier_fuzzer", - "inputflinger_input_dispatcher_fuzzer", - - // Java/Kotlin targets - "CtsWindowManagerDeviceWindow", - "InputTests", "CtsHardwareTestCases", "CtsInputTestCases", + "CtsSecurityBulletinHostTestCases", + "CtsSecurityTestCases", "CtsViewTestCases", "CtsWidgetTestCases", + "CtsWindowManagerDeviceWindow", "FrameworksCoreTests", "FrameworksServicesTests", - "CtsSecurityTestCases", - "CtsSecurityBulletinHostTestCases", + "InputTests", + "StructLayout_test", + "inputflinger_benchmarks", + "inputflinger_blocking_queue_fuzzer", + "inputflinger_cursor_input_fuzzer", + "inputflinger_input_classifier_fuzzer", + "inputflinger_input_dispatcher_fuzzer", + "inputflinger_input_reader_fuzzer", + "inputflinger_keyboard_input_fuzzer", + "inputflinger_latencytracker_fuzzer", + "inputflinger_multitouch_input_fuzzer", + "inputflinger_switch_input_fuzzer", + "inputflinger_tests", + "inputflinger_touchpad_input_fuzzer", + "libandroid_runtime", + "libgui_test", + "libinput", + "libinput_rust_test", + "libinput_tests", + "libinputflinger", + "libinputreader_static", + "libinputservice_test", + "libpalmrejection_test", + "libservices.core", "monkey_test", ], } diff --git a/services/inputflinger/InputFilter.cpp b/services/inputflinger/InputFilter.cpp index 2ef94fbb07..bb4e617bde 100644 --- a/services/inputflinger/InputFilter.cpp +++ b/services/inputflinger/InputFilter.cpp @@ -56,7 +56,7 @@ InputFilter::InputFilter(InputListenerInterface& listener, IInputFlingerRust& ru void InputFilter::notifyInputDevicesChanged(const NotifyInputDevicesChangedArgs& args) { mDeviceInfos.clear(); mDeviceInfos.reserve(args.inputDeviceInfos.size()); - for (auto info : args.inputDeviceInfos) { + for (const auto& info : args.inputDeviceInfos) { AidlDeviceInfo& aidlInfo = mDeviceInfos.emplace_back(); aidlInfo.deviceId = info.getId(); aidlInfo.external = info.isExternal(); diff --git a/services/inputflinger/PointerChoreographer.cpp b/services/inputflinger/PointerChoreographer.cpp index 9f9128529d..3140dc86e9 100644 --- a/services/inputflinger/PointerChoreographer.cpp +++ b/services/inputflinger/PointerChoreographer.cpp @@ -17,6 +17,7 @@ #define LOG_TAG "PointerChoreographer" #include <android-base/logging.h> +#include <android/configuration.h> #include <com_android_input_flags.h> #if defined(__ANDROID__) #include <gui/SurfaceComposerClient.h> @@ -114,6 +115,17 @@ vec2 calculatePositionOnDestinationViewport(const DisplayViewport& destinationVi } } +// The standardised medium display density for which 1 px = 1 dp +constexpr int32_t DENSITY_MEDIUM = ACONFIGURATION_DENSITY_MEDIUM; + +inline float pxToDp(int px, int dpi) { + return static_cast<float>(px * DENSITY_MEDIUM) / static_cast<float>(dpi); +} + +inline int dpToPx(float dp, int dpi) { + return static_cast<int>((dp * dpi) / DENSITY_MEDIUM); +} + } // namespace // --- PointerChoreographer --- @@ -385,8 +397,7 @@ void PointerChoreographer::handleUnconsumedDeltaLocked(PointerControllerInterfac pc.fade(PointerControllerInterface::Transition::IMMEDIATE); pc.setDisplayViewport(destinationViewport); vec2 destinationPosition = - calculatePositionOnDestinationViewport(destinationViewport, - cursorOffset - destinationOffset, + calculatePositionOnDestinationViewport(destinationViewport, destinationOffset, sourceBoundary); // Transform position back to un-rotated coordinate space before sending it to controller @@ -990,10 +1001,10 @@ PointerChoreographer::ControllerConstructor PointerChoreographer::getStylusContr return ConstructorDelegate(std::move(ctor)); } -std::optional<std::pair<const DisplayViewport*, float /*offset*/>> +std::optional<std::pair<const DisplayViewport*, float /*offsetPx*/>> PointerChoreographer::findDestinationDisplayLocked(const ui::LogicalDisplayId sourceDisplayId, const DisplayTopologyPosition sourceBoundary, - float cursorOffset) const { + int32_t sourceCursorOffsetPx) const { const auto& sourceNode = mTopology.graph.find(sourceDisplayId); if (sourceNode == mTopology.graph.end()) { // Topology is likely out of sync with viewport info, wait for it to be updated @@ -1004,22 +1015,32 @@ PointerChoreographer::findDestinationDisplayLocked(const ui::LogicalDisplayId so if (adjacentDisplay.position != sourceBoundary) { continue; } - const DisplayViewport* destinationViewport = - findViewportByIdLocked(adjacentDisplay.displayId); - if (destinationViewport == nullptr) { + const DisplayViewport* adjacentViewport = findViewportByIdLocked(adjacentDisplay.displayId); + if (adjacentViewport == nullptr) { // Topology is likely out of sync with viewport info, wait for them to be updated LOG(WARNING) << "Cannot find viewport for adjacent display " << adjacentDisplay.displayId << "of source display " << sourceDisplayId; continue; } - // target position must be within target display boundary - const int32_t edgeSize = sourceBoundary == DisplayTopologyPosition::TOP || + // As displays can have different densities we need to do all calculations in + // density-independent-pixels a.k.a. dp values. + const int sourceDensity = mTopology.displaysDensity.at(sourceDisplayId); + const int adjacentDisplayDensity = mTopology.displaysDensity.at(adjacentDisplay.displayId); + const float sourceCursorOffsetDp = pxToDp(sourceCursorOffsetPx, sourceDensity); + const int32_t edgeSizePx = sourceBoundary == DisplayTopologyPosition::TOP || sourceBoundary == DisplayTopologyPosition::BOTTOM - ? (destinationViewport->logicalRight - destinationViewport->logicalLeft) - : (destinationViewport->logicalBottom - destinationViewport->logicalTop); - if (cursorOffset >= adjacentDisplay.offsetDp && - cursorOffset <= adjacentDisplay.offsetDp + edgeSize) { - return std::make_pair(destinationViewport, adjacentDisplay.offsetDp); + ? (adjacentViewport->logicalRight - adjacentViewport->logicalLeft) + : (adjacentViewport->logicalBottom - adjacentViewport->logicalTop); + const float adjacentEdgeSizeDp = pxToDp(edgeSizePx, adjacentDisplayDensity); + // Target position must be within target display boundary. + // Cursor should also be able to cross displays when only display corners are touching and + // there may be zero overlapping pixels. To accommodate this we have margin of one pixel + // around the end of the overlapping edge. + if (sourceCursorOffsetDp >= adjacentDisplay.offsetDp && + sourceCursorOffsetDp <= adjacentDisplay.offsetDp + adjacentEdgeSizeDp) { + const int destinationOffsetPx = + dpToPx(sourceCursorOffsetDp - adjacentDisplay.offsetDp, adjacentDisplayDensity); + return std::make_pair(adjacentViewport, destinationOffsetPx); } } return std::nullopt; diff --git a/services/inputflinger/PointerChoreographer.h b/services/inputflinger/PointerChoreographer.h index c2f5ec0e87..a9d971abb4 100644 --- a/services/inputflinger/PointerChoreographer.h +++ b/services/inputflinger/PointerChoreographer.h @@ -163,10 +163,10 @@ private: void handleUnconsumedDeltaLocked(PointerControllerInterface& pc, const vec2& unconsumedDelta) REQUIRES(getLock()); - std::optional<std::pair<const DisplayViewport*, float /*offset*/>> findDestinationDisplayLocked( - const ui::LogicalDisplayId sourceDisplayId, - const DisplayTopologyPosition sourceBoundary, float cursorOffset) const - REQUIRES(getLock()); + std::optional<std::pair<const DisplayViewport*, float /*offsetPx*/>> + findDestinationDisplayLocked(const ui::LogicalDisplayId sourceDisplayId, + const DisplayTopologyPosition sourceBoundary, + int32_t sourceCursorOffsetPx) const REQUIRES(getLock()); /* Topology is initialized with default-constructed value, which is an empty topology. Till we * receive setDisplayTopology call. diff --git a/services/inputflinger/dispatcher/Android.bp b/services/inputflinger/dispatcher/Android.bp index 8b2b8432c3..1aa8b2b69b 100644 --- a/services/inputflinger/dispatcher/Android.bp +++ b/services/inputflinger/dispatcher/Android.bp @@ -49,8 +49,8 @@ filegroup { "LatencyAggregatorWithHistograms.cpp", "LatencyTracker.cpp", "Monitor.cpp", - "TouchedWindow.cpp", "TouchState.cpp", + "TouchedWindow.cpp", "trace/*.cpp", ], } @@ -71,9 +71,9 @@ cc_defaults { "liblog", "libprotobuf-cpp-lite", "libstatslog", - "libutils", "libstatspull", "libstatssocket", + "libutils", "packagemanager_aidl-cpp", "server_configurable_flags", ], diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 098019fc80..05602efd55 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -1267,13 +1267,9 @@ void InputDispatcher::dispatchOnceInnerLocked(nsecs_t& nextWakeupTime) { if (dropReason == DropReason::NOT_DROPPED && isStaleEvent(currentTime, *motionEntry)) { // The event is stale. However, only drop stale events if there isn't an ongoing // gesture. That would allow us to complete the processing of the current stroke. - const auto touchStateIt = mTouchStatesByDisplay.find(motionEntry->displayId); - if (touchStateIt != mTouchStatesByDisplay.end()) { - const TouchState& touchState = touchStateIt->second; - if (!touchState.hasTouchingPointers(motionEntry->deviceId) && - !touchState.hasHoveringPointers(motionEntry->deviceId)) { - dropReason = DropReason::STALE; - } + if (!mTouchStates.hasTouchingOrHoveringPointers(motionEntry->displayId, + motionEntry->deviceId)) { + dropReason = DropReason::STALE; } } if (dropReason == DropReason::NOT_DROPPED && mNextUnblockedEvent) { @@ -1355,7 +1351,8 @@ bool InputDispatcher::shouldPruneInboundQueueLocked(const MotionEntry& motionEnt // Alternatively, maybe there's a spy window that could handle this event. const std::vector<sp<WindowInfoHandle>> touchedSpies = mWindowInfos.findTouchedSpyWindowsAt(displayId, x, y, isStylus, - motionEntry.deviceId, mTouchStatesByDisplay); + motionEntry.deviceId, + mTouchStates.mTouchStatesByDisplay); for (const auto& windowHandle : touchedSpies) { const std::shared_ptr<Connection> connection = mConnectionManager.getConnection(windowHandle->getToken()); @@ -1480,15 +1477,16 @@ sp<WindowInfoHandle> InputDispatcher::DispatcherWindowInfo::findTouchedWindowAt( return nullptr; } -std::vector<InputTarget> InputDispatcher::findOutsideTargetsLocked( - ui::LogicalDisplayId displayId, const sp<WindowInfoHandle>& touchedWindow, - int32_t pointerId) const { +std::vector<InputTarget> InputDispatcher::DispatcherTouchState::findOutsideTargets( + ui::LogicalDisplayId displayId, const sp<gui::WindowInfoHandle>& touchedWindow, + int32_t pointerId, const ConnectionManager& connections, + const DispatcherWindowInfo& windowInfos, std::function<void()> dump) { if (touchedWindow == nullptr) { return {}; } // Traverse windows from front to back until we encounter the touched window. std::vector<InputTarget> outsideTargets; - const auto& windowHandles = mWindowInfos.getWindowHandlesForDisplay(displayId); + const auto& windowHandles = windowInfos.getWindowHandlesForDisplay(displayId); for (const sp<WindowInfoHandle>& windowHandle : windowHandles) { if (windowHandle == touchedWindow) { // Stop iterating once we found a touched window. Any WATCH_OUTSIDE_TOUCH window @@ -1500,9 +1498,13 @@ std::vector<InputTarget> InputDispatcher::findOutsideTargetsLocked( if (info.inputConfig.test(WindowInfo::InputConfig::WATCH_OUTSIDE_TOUCH)) { std::bitset<MAX_POINTER_ID + 1> pointerIds; pointerIds.set(pointerId); - addPointerWindowTargetLocked(windowHandle, InputTarget::DispatchMode::OUTSIDE, - ftl::Flags<InputTarget::Flags>(), pointerIds, - /*firstDownTimeInTarget=*/std::nullopt, outsideTargets); + DispatcherTouchState::addPointerWindowTarget(windowHandle, + InputTarget::DispatchMode::OUTSIDE, + ftl::Flags<InputTarget::Flags>(), + pointerIds, + /*firstDownTimeInTarget=*/std::nullopt, + connections, windowInfos, dump, + outsideTargets); } } return outsideTargets; @@ -1709,9 +1711,7 @@ bool InputDispatcher::dispatchDeviceResetLocked(nsecs_t currentTime, synthesizeCancelationEventsForAllConnectionsLocked(options); // Remove all active pointers from this device - for (auto& [_, touchState] : mTouchStatesByDisplay) { - touchState.removeAllPointersForDevice(entry.deviceId); - } + mTouchStates.removeAllPointersForDevice(entry.deviceId); return true; } @@ -2073,7 +2073,16 @@ bool InputDispatcher::dispatchMotionLocked(nsecs_t currentTime, } Result<std::vector<InputTarget>, InputEventInjectionResult> result = - findTouchedWindowTargetsLocked(currentTime, *entry); + mTouchStates + .findTouchedWindowTargets(currentTime, *entry, mConnectionManager, + mWindowInfos, + mDragState ? mDragState->dragWindow : nullptr, + std::bind_front(&InputDispatcher:: + addDragEventLocked, + this), + std::bind_front(&InputDispatcher:: + logDispatchStateLocked, + this)); if (result.ok()) { inputTargets = std::move(*result); @@ -2318,7 +2327,8 @@ InputDispatcher::findFocusedWindowTargetLocked(nsecs_t currentTime, const EventE } // Drop key events if requested by input feature - if (focusedWindowHandle != nullptr && shouldDropInput(entry, focusedWindowHandle)) { + if (focusedWindowHandle != nullptr && + shouldDropInput(entry, focusedWindowHandle, mWindowInfos)) { return injectionError(InputEventInjectionResult::FAILED); } @@ -2387,8 +2397,12 @@ InputDispatcher::findFocusedWindowTargetLocked(nsecs_t currentTime, const EventE return focusedWindowHandle; } -base::Result<std::vector<InputTarget>, android::os::InputEventInjectionResult> -InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, const MotionEntry& entry) { +base::Result<std::vector<InputTarget>, os::InputEventInjectionResult> +InputDispatcher::DispatcherTouchState::findTouchedWindowTargets( + nsecs_t currentTime, const MotionEntry& entry, const ConnectionManager& connections, + const DispatcherWindowInfo& windowInfos, + const sp<android::gui::WindowInfoHandle> dragWindow, + std::function<void(const MotionEntry&)> addDragEvent, std::function<void()> dump) { ATRACE_CALL(); std::vector<InputTarget> targets; @@ -2448,10 +2462,12 @@ InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, const Motio // be a pointer that would generate ACTION_DOWN, *and* touch should not already be down. const bool isStylus = isPointerFromStylus(entry, pointerIndex); sp<WindowInfoHandle> newTouchedWindowHandle = - mWindowInfos.findTouchedWindowAt(displayId, x, y, isStylus); + windowInfos.findTouchedWindowAt(displayId, x, y, isStylus); if (isDown) { - targets += findOutsideTargetsLocked(displayId, newTouchedWindowHandle, pointer.id); + targets += DispatcherTouchState::findOutsideTargets(displayId, newTouchedWindowHandle, + pointer.id, connections, + windowInfos, dump); } LOG_IF(INFO, newTouchedWindowHandle == nullptr) << "No new touched window at (" << std::format("{:.1f}, {:.1f}", x, y) @@ -2464,8 +2480,8 @@ InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, const Motio } std::vector<sp<WindowInfoHandle>> newTouchedWindows = - mWindowInfos.findTouchedSpyWindowsAt(displayId, x, y, isStylus, entry.deviceId, - mTouchStatesByDisplay); + windowInfos.findTouchedSpyWindowsAt(displayId, x, y, isStylus, entry.deviceId, + mTouchStatesByDisplay); if (newTouchedWindowHandle != nullptr) { // Process the foreground window first so that it is the first to receive the event. newTouchedWindows.insert(newTouchedWindows.begin(), newTouchedWindowHandle); @@ -2478,7 +2494,8 @@ InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, const Motio } for (const sp<WindowInfoHandle>& windowHandle : newTouchedWindows) { - if (!canWindowReceiveMotionLocked(windowHandle, entry)) { + if (!canWindowReceiveMotion(windowHandle, entry, connections, windowInfos, + mTouchStatesByDisplay)) { continue; } @@ -2489,21 +2506,9 @@ InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, const Motio } // Set target flags. - ftl::Flags<InputTarget::Flags> targetFlags; - - if (canReceiveForegroundTouches(*windowHandle->getInfo())) { - // There should only be one touched window that can be "foreground" for the pointer. - targetFlags |= InputTarget::Flags::FOREGROUND; - } - - if (isSplit) { - targetFlags |= InputTarget::Flags::SPLIT; - } - if (mWindowInfos.isWindowObscuredAtPoint(windowHandle, x, y)) { - targetFlags |= InputTarget::Flags::WINDOW_IS_OBSCURED; - } else if (mWindowInfos.isWindowObscured(windowHandle)) { - targetFlags |= InputTarget::Flags::WINDOW_IS_PARTIALLY_OBSCURED; - } + ftl::Flags<InputTarget::Flags> targetFlags = + DispatcherTouchState::getTargetFlags(windowHandle, {x, y}, isSplit, + windowInfos); // Update the temporary touch state. @@ -2521,7 +2526,7 @@ InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, const Motio if (!addResult.ok()) { LOG(ERROR) << "Error while processing " << entry << " for " << windowHandle->getName(); - logDispatchStateLocked(); + dump(); } // If this is the pointer going down and the touched window has a wallpaper // then also add the touched wallpaper windows so they are locked in for the @@ -2533,7 +2538,7 @@ InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, const Motio windowHandle->getInfo()->inputConfig.test( gui::WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER)) { sp<WindowInfoHandle> wallpaper = - mWindowInfos.findWallpaperWindowBelow(windowHandle); + windowInfos.findWallpaperWindowBelow(windowHandle); if (wallpaper != nullptr) { ftl::Flags<InputTarget::Flags> wallpaperFlags = InputTarget::Flags::WINDOW_IS_OBSCURED | @@ -2592,7 +2597,7 @@ InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, const Motio tempTouchState.removeHoveringPointer(entry.deviceId, pointerId); } - addDragEventLocked(entry); + addDragEvent(entry); // Check whether touches should slip outside of the current foreground window. if (maskedAction == AMOTION_EVENT_ACTION_MOVE && entry.getPointerCount() == 1 && @@ -2603,7 +2608,7 @@ InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, const Motio tempTouchState.getFirstForegroundWindowHandle(entry.deviceId); LOG_ALWAYS_FATAL_IF(oldTouchedWindowHandle == nullptr); sp<WindowInfoHandle> newTouchedWindowHandle = - mWindowInfos.findTouchedWindowAt(displayId, x, y, isStylus); + windowInfos.findTouchedWindowAt(displayId, x, y, isStylus); // Verify targeted injection. if (const auto err = verifyTargetedInjection(newTouchedWindowHandle, entry); err) { @@ -2613,7 +2618,8 @@ InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, const Motio // Do not slide events to the window which can not receive motion event if (newTouchedWindowHandle != nullptr && - !canWindowReceiveMotionLocked(newTouchedWindowHandle, entry)) { + !canWindowReceiveMotion(newTouchedWindowHandle, entry, connections, windowInfos, + mTouchStatesByDisplay)) { newTouchedWindowHandle = nullptr; } @@ -2630,26 +2636,18 @@ InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, const Motio const TouchedWindow& touchedWindow = tempTouchState.getTouchedWindow(oldTouchedWindowHandle); - addPointerWindowTargetLocked(oldTouchedWindowHandle, - InputTarget::DispatchMode::SLIPPERY_EXIT, - ftl::Flags<InputTarget::Flags>(), pointerIds, - touchedWindow.getDownTimeInTarget(entry.deviceId), - targets); + DispatcherTouchState:: + addPointerWindowTarget(oldTouchedWindowHandle, + InputTarget::DispatchMode::SLIPPERY_EXIT, + ftl::Flags<InputTarget::Flags>(), pointerIds, + touchedWindow.getDownTimeInTarget(entry.deviceId), + connections, windowInfos, dump, targets); // Make a slippery entrance into the new window. - ftl::Flags<InputTarget::Flags> targetFlags; - if (canReceiveForegroundTouches(*newTouchedWindowHandle->getInfo())) { - targetFlags |= InputTarget::Flags::FOREGROUND; - } - if (isSplit) { - targetFlags |= InputTarget::Flags::SPLIT; - } - if (mWindowInfos.isWindowObscuredAtPoint(newTouchedWindowHandle, x, y)) { - targetFlags |= InputTarget::Flags::WINDOW_IS_OBSCURED; - } else if (mWindowInfos.isWindowObscured(newTouchedWindowHandle)) { - targetFlags |= InputTarget::Flags::WINDOW_IS_PARTIALLY_OBSCURED; - } + ftl::Flags<InputTarget::Flags> targetFlags = + DispatcherTouchState::getTargetFlags(newTouchedWindowHandle, {x, y}, + isSplit, windowInfos); tempTouchState.addOrUpdateWindow(newTouchedWindowHandle, InputTarget::DispatchMode::SLIPPERY_ENTER, @@ -2657,8 +2655,10 @@ InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, const Motio entry.eventTime); // Check if the wallpaper window should deliver the corresponding event. - slipWallpaperTouch(targetFlags, oldTouchedWindowHandle, newTouchedWindowHandle, - tempTouchState, entry, targets); + DispatcherTouchState::slipWallpaperTouch(targetFlags, oldTouchedWindowHandle, + newTouchedWindowHandle, tempTouchState, + entry, targets, connections, windowInfos, + dump); tempTouchState.removeTouchingPointerFromWindow(entry.deviceId, pointer.id, oldTouchedWindowHandle); } @@ -2671,7 +2671,7 @@ InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, const Motio std::vector<PointerProperties> touchingPointers{entry.pointerProperties[pointerIndex]}; for (TouchedWindow& touchedWindow : tempTouchState.windows) { // Ignore drag window for it should just track one pointer. - if (mDragState && mDragState->dragWindow == touchedWindow.windowHandle) { + if (dragWindow == touchedWindow.windowHandle) { continue; } if (!touchedWindow.hasTouchingPointers(entry.deviceId)) { @@ -2685,17 +2685,17 @@ InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, const Motio // Update dispatching for hover enter and exit. { std::vector<TouchedWindow> hoveringWindows = - getHoveringWindowsLocked(oldState, tempTouchState, entry, - std::bind_front(&InputDispatcher::logDispatchStateLocked, - this)); + getHoveringWindowsLocked(oldState, tempTouchState, entry, dump); // Hardcode to single hovering pointer for now. std::bitset<MAX_POINTER_ID + 1> pointerIds; pointerIds.set(entry.pointerProperties[0].id); for (const TouchedWindow& touchedWindow : hoveringWindows) { - addPointerWindowTargetLocked(touchedWindow.windowHandle, touchedWindow.dispatchMode, - touchedWindow.targetFlags, pointerIds, - touchedWindow.getDownTimeInTarget(entry.deviceId), - targets); + DispatcherTouchState::addPointerWindowTarget(touchedWindow.windowHandle, + touchedWindow.dispatchMode, + touchedWindow.targetFlags, pointerIds, + touchedWindow.getDownTimeInTarget( + entry.deviceId), + connections, windowInfos, dump, targets); } } @@ -2724,7 +2724,7 @@ InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, const Motio for (InputTarget& target : targets) { if (target.dispatchMode == InputTarget::DispatchMode::OUTSIDE) { sp<WindowInfoHandle> targetWindow = - mWindowInfos.findWindowHandle(target.connection->getToken()); + windowInfos.findWindowHandle(target.connection->getToken()); if (targetWindow->getInfo()->ownerUid != foregroundWindowUid) { target.flags |= InputTarget::Flags::ZERO_COORDS; } @@ -2748,9 +2748,13 @@ InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, const Motio if (touchingPointers.empty()) { continue; } - addPointerWindowTargetLocked(touchedWindow.windowHandle, touchedWindow.dispatchMode, - touchedWindow.targetFlags, getPointerIds(touchingPointers), - touchedWindow.getDownTimeInTarget(entry.deviceId), targets); + DispatcherTouchState::addPointerWindowTarget(touchedWindow.windowHandle, + touchedWindow.dispatchMode, + touchedWindow.targetFlags, + getPointerIds(touchingPointers), + touchedWindow.getDownTimeInTarget( + entry.deviceId), + connections, windowInfos, dump, targets); } // During targeted injection, only allow owned targets to receive events @@ -2953,11 +2957,12 @@ void InputDispatcher::addWindowTargetLocked(const sp<WindowInfoHandle>& windowHa } } -void InputDispatcher::addPointerWindowTargetLocked( +void InputDispatcher::DispatcherTouchState::addPointerWindowTarget( const sp<android::gui::WindowInfoHandle>& windowHandle, InputTarget::DispatchMode dispatchMode, ftl::Flags<InputTarget::Flags> targetFlags, std::bitset<MAX_POINTER_ID + 1> pointerIds, std::optional<nsecs_t> firstDownTimeInTarget, - std::vector<InputTarget>& inputTargets) const REQUIRES(mLock) { + const ConnectionManager& connections, const DispatcherWindowInfo& windowInfos, + std::function<void()> dump, std::vector<InputTarget>& inputTargets) { if (pointerIds.none()) { for (const auto& target : inputTargets) { LOG(INFO) << "Target: " << target; @@ -2982,19 +2987,17 @@ void InputDispatcher::addPointerWindowTargetLocked( it = inputTargets.end(); } - const WindowInfo* windowInfo = windowHandle->getInfo(); + const WindowInfo& windowInfo = *windowHandle->getInfo(); if (it == inputTargets.end()) { - std::shared_ptr<Connection> connection = - mConnectionManager.getConnection(windowHandle->getToken()); + std::shared_ptr<Connection> connection = connections.getConnection(windowInfo.token); if (connection == nullptr) { - ALOGW("Not creating InputTarget for %s, no input channel", - windowHandle->getName().c_str()); + ALOGW("Not creating InputTarget for %s, no input channel", windowInfo.name.c_str()); return; } inputTargets.push_back( createInputTarget(connection, windowHandle, dispatchMode, targetFlags, - mWindowInfos.getRawTransform(*windowHandle->getInfo()), + windowInfos.getRawTransform(*windowHandle->getInfo()), firstDownTimeInTarget)); it = inputTargets.end() - 1; } @@ -3007,14 +3010,14 @@ void InputDispatcher::addPointerWindowTargetLocked( LOG(ERROR) << __func__ << ": Flags don't match! new targetFlags=" << targetFlags.string() << ", it=" << *it; } - if (it->globalScaleFactor != windowInfo->globalScaleFactor) { + if (it->globalScaleFactor != windowInfo.globalScaleFactor) { LOG(ERROR) << __func__ << ": Mismatch! it->globalScaleFactor=" << it->globalScaleFactor - << ", windowInfo->globalScaleFactor=" << windowInfo->globalScaleFactor; + << ", windowInfo->globalScaleFactor=" << windowInfo.globalScaleFactor; } - Result<void> result = it->addPointers(pointerIds, windowInfo->transform); + Result<void> result = it->addPointers(pointerIds, windowInfo.transform); if (!result.ok()) { - logDispatchStateLocked(); + dump(); LOG(FATAL) << result.error().message(); } } @@ -4069,13 +4072,17 @@ void InputDispatcher::synthesizeCancelationEventsForAllConnectionsLocked( // Generate cancellations for touched windows first. This is to avoid generating cancellations // through a non-touched window if there are more than one window for an input channel. if (cancelPointers) { - for (const auto& [displayId, touchState] : mTouchStatesByDisplay) { - if (options.displayId.has_value() && options.displayId != displayId) { - continue; - } - for (const auto& touchedWindow : touchState.windows) { - synthesizeCancelationEventsForWindowLocked(touchedWindow.windowHandle, options); - } + if (options.displayId.has_value()) { + mTouchStates.forAllTouchedWindowsOnDisplay( + options.displayId.value(), [&](const sp<gui::WindowInfoHandle>& windowHandle) { + base::ScopedLockAssertion assumeLocked(mLock); + synthesizeCancelationEventsForWindowLocked(windowHandle, options); + }); + } else { + mTouchStates.forAllTouchedWindows([&](const sp<gui::WindowInfoHandle>& windowHandle) { + base::ScopedLockAssertion assumeLocked(mLock); + synthesizeCancelationEventsForWindowLocked(windowHandle, options); + }); } } // Follow up by generating cancellations for all windows, because we don't explicitly track @@ -4204,9 +4211,15 @@ void InputDispatcher::synthesizeCancelationEventsForConnectionLocked( sendDropWindowCommandLocked(nullptr, /*x=*/0, /*y=*/0); mDragState.reset(); } - addPointerWindowTargetLocked(window, InputTarget::DispatchMode::AS_IS, - ftl::Flags<InputTarget::Flags>(), pointerIds, - motionEntry.downTime, targets); + DispatcherTouchState:: + addPointerWindowTarget(window, InputTarget::DispatchMode::AS_IS, + ftl::Flags<InputTarget::Flags>(), pointerIds, + motionEntry.downTime, mConnectionManager, + mWindowInfos, + std::bind_front(&InputDispatcher:: + logDispatchStateLocked, + this), + targets); } else { targets.emplace_back(fallbackTarget); // Since we don't have a window, use the display transform as the raw transform. @@ -4267,12 +4280,13 @@ void InputDispatcher::synthesizePointerDownEventsForConnectionLocked( connection->getInputChannelName().c_str(), downEvents.size()); } - const auto [_, touchedWindowState, displayId] = - findTouchStateWindowAndDisplay(connection->getToken(), mTouchStatesByDisplay); - if (touchedWindowState == nullptr) { + auto touchedWindowHandleAndDisplay = + mTouchStates.findTouchedWindowHandleAndDisplay(connection->getToken()); + if (!touchedWindowHandleAndDisplay.has_value()) { LOG(FATAL) << __func__ << ": Touch state is out of sync: No touched window for token"; } - const auto& windowHandle = touchedWindowState->windowHandle; + + const auto [windowHandle, displayId] = touchedWindowHandleAndDisplay.value(); const bool wasEmpty = connection->outboundQueue.empty(); for (std::unique_ptr<EventEntry>& downEventEntry : downEvents) { @@ -4290,9 +4304,14 @@ void InputDispatcher::synthesizePointerDownEventsForConnectionLocked( pointerIndex++) { pointerIds.set(motionEntry.pointerProperties[pointerIndex].id); } - addPointerWindowTargetLocked(windowHandle, InputTarget::DispatchMode::AS_IS, - targetFlags, pointerIds, motionEntry.downTime, - targets); + DispatcherTouchState:: + addPointerWindowTarget(windowHandle, InputTarget::DispatchMode::AS_IS, + targetFlags, pointerIds, motionEntry.downTime, + mConnectionManager, mWindowInfos, + std::bind_front(&InputDispatcher:: + logDispatchStateLocked, + this), + targets); } else { targets.emplace_back(connection, targetFlags); // Since we don't have a window, use the display transform as the raw transform. @@ -4535,8 +4554,9 @@ void InputDispatcher::notifyMotion(const NotifyMotionArgs& args) { args.displayId.toString().c_str())); Result<void> result = it->second.processMovement(args.deviceId, args.source, args.action, - args.getPointerCount(), args.pointerProperties.data(), - args.pointerCoords.data(), args.flags); + args.actionButton, args.getPointerCount(), + args.pointerProperties.data(), args.pointerCoords.data(), + args.flags, args.buttonState); if (!result.ok()) { LOG(FATAL) << "Bad stream: " << result.error() << " caused by " << args.dump(); } @@ -4559,13 +4579,8 @@ void InputDispatcher::notifyMotion(const NotifyMotionArgs& args) { if (!(policyFlags & POLICY_FLAG_PASS_TO_USER)) { // Set the flag anyway if we already have an ongoing gesture. That would allow us to // complete the processing of the current stroke. - const auto touchStateIt = mTouchStatesByDisplay.find(args.displayId); - if (touchStateIt != mTouchStatesByDisplay.end()) { - const TouchState& touchState = touchStateIt->second; - if (touchState.hasTouchingPointers(args.deviceId) || - touchState.hasHoveringPointers(args.deviceId)) { - policyFlags |= POLICY_FLAG_PASS_TO_USER; - } + if (mTouchStates.hasTouchingOrHoveringPointers(args.displayId, args.deviceId)) { + policyFlags |= POLICY_FLAG_PASS_TO_USER; } } @@ -4737,9 +4752,10 @@ bool InputDispatcher::shouldRejectInjectedMotionLocked(const MotionEvent& motion Result<void> result = verifier.processMovement(deviceId, motionEvent.getSource(), motionEvent.getAction(), - motionEvent.getPointerCount(), + motionEvent.getActionButton(), motionEvent.getPointerCount(), motionEvent.getPointerProperties(), - motionEvent.getSamplePointerCoords(), flags); + motionEvent.getSamplePointerCoords(), flags, + motionEvent.getButtonState()); if (!result.ok()) { logDispatchStateLocked(); LOG(ERROR) << "Inconsistent event: " << motionEvent << ", reason: " << result.error(); @@ -4871,13 +4887,8 @@ InputEventInjectionResult InputDispatcher::injectInputEvent(const InputEvent* ev if (!(policyFlags & POLICY_FLAG_PASS_TO_USER)) { // Set the flag anyway if we already have an ongoing motion gesture. That // would allow us to complete the processing of the current stroke. - const auto touchStateIt = mTouchStatesByDisplay.find(displayId); - if (touchStateIt != mTouchStatesByDisplay.end()) { - const TouchState& touchState = touchStateIt->second; - if (touchState.hasTouchingPointers(resolvedDeviceId) || - touchState.hasHoveringPointers(resolvedDeviceId)) { - policyFlags |= POLICY_FLAG_PASS_TO_USER; - } + if (mTouchStates.hasTouchingOrHoveringPointers(displayId, resolvedDeviceId)) { + policyFlags |= POLICY_FLAG_PASS_TO_USER; } } @@ -5266,9 +5277,11 @@ std::string InputDispatcher::DispatcherWindowInfo::dumpDisplayAndWindowInfo() co return dump; } -bool InputDispatcher::canWindowReceiveMotionLocked( +bool InputDispatcher::canWindowReceiveMotion( const sp<android::gui::WindowInfoHandle>& window, - const android::inputdispatcher::MotionEntry& motionEntry) const { + const android::inputdispatcher::MotionEntry& motionEntry, + const ConnectionManager& connections, const DispatcherWindowInfo& windowInfos, + const std::unordered_map<ui::LogicalDisplayId, TouchState>& touchStates) { const WindowInfo& info = *window->getInfo(); // Skip spy window targets that are not valid for targeted injection. @@ -5287,7 +5300,7 @@ bool InputDispatcher::canWindowReceiveMotionLocked( return false; } - std::shared_ptr<Connection> connection = mConnectionManager.getConnection(window->getToken()); + std::shared_ptr<Connection> connection = connections.getConnection(window->getToken()); if (connection == nullptr) { ALOGW("Not sending touch to %s because there's no corresponding connection", window->getName().c_str()); @@ -5302,8 +5315,8 @@ bool InputDispatcher::canWindowReceiveMotionLocked( // Drop events that can't be trusted due to occlusion const auto [x, y] = resolveTouchedPosition(motionEntry); DispatcherWindowInfo::TouchOcclusionInfo occlusionInfo = - mWindowInfos.computeTouchOcclusionInfo(window, x, y); - if (!mWindowInfos.isTouchTrusted(occlusionInfo)) { + windowInfos.computeTouchOcclusionInfo(window, x, y); + if (!windowInfos.isTouchTrusted(occlusionInfo)) { if (DEBUG_TOUCH_OCCLUSION) { ALOGD("Stack of obscuring windows during untrusted touch (%.1f, %.1f):", x, y); for (const auto& log : occlusionInfo.debugInfo) { @@ -5316,13 +5329,13 @@ bool InputDispatcher::canWindowReceiveMotionLocked( } // Drop touch events if requested by input feature - if (shouldDropInput(motionEntry, window)) { + if (shouldDropInput(motionEntry, window, windowInfos)) { return false; } // Ignore touches if stylus is down anywhere on screen if (info.inputConfig.test(WindowInfo::InputConfig::GLOBAL_STYLUS_BLOCKS_TOUCH) && - isStylusActiveInDisplay(info.displayId, mTouchStatesByDisplay)) { + isStylusActiveInDisplay(info.displayId, touchStates)) { LOG(INFO) << "Dropping touch from " << window->getName() << " because stylus is active"; return false; } @@ -5446,70 +5459,38 @@ void InputDispatcher::setInputWindowsLocked( onFocusChangedLocked(*changes, traceContext.getTracker(), removedFocusedWindowHandle); } - if (const auto& it = mTouchStatesByDisplay.find(displayId); it != mTouchStatesByDisplay.end()) { - TouchState& state = it->second; - for (size_t i = 0; i < state.windows.size();) { - TouchedWindow& touchedWindow = state.windows[i]; - if (mWindowInfos.isWindowPresent(touchedWindow.windowHandle)) { - i++; - continue; - } - LOG(INFO) << "Touched window was removed: " << touchedWindow.windowHandle->getName() - << " in display %" << displayId; - CancelationOptions options(CancelationOptions::Mode::CANCEL_POINTER_EVENTS, - "touched window was removed", traceContext.getTracker()); - synthesizeCancelationEventsForWindowLocked(touchedWindow.windowHandle, options); - // Since we are about to drop the touch, cancel the events for the wallpaper as - // well. - if (touchedWindow.targetFlags.test(InputTarget::Flags::FOREGROUND) && - touchedWindow.windowHandle->getInfo()->inputConfig.test( - gui::WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER)) { - for (const DeviceId deviceId : touchedWindow.getTouchingDeviceIds()) { - if (const auto& ww = state.getWallpaperWindow(deviceId); ww != nullptr) { - options.deviceId = deviceId; - synthesizeCancelationEventsForWindowLocked(ww, options); - } - } - } - state.windows.erase(state.windows.begin() + i); - } - - // If drag window is gone, it would receive a cancel event and broadcast the DRAG_END. We - // could just clear the state here. - if (mDragState && mDragState->dragWindow->getInfo()->displayId == displayId && - std::find(windowHandles.begin(), windowHandles.end(), mDragState->dragWindow) == - windowHandles.end()) { - ALOGI("Drag window went away: %s", mDragState->dragWindow->getName().c_str()); - sendDropWindowCommandLocked(nullptr, 0, 0); - mDragState.reset(); + CancelationOptions pointerCancellationOptions(CancelationOptions::Mode::CANCEL_POINTER_EVENTS, + "touched window was removed", + traceContext.getTracker()); + CancelationOptions hoverCancellationOptions(CancelationOptions::Mode::CANCEL_HOVER_EVENTS, + "WindowInfo changed", traceContext.getTracker()); + const std::list<DispatcherTouchState::CancellationArgs> cancellations = + mTouchStates.updateFromWindowInfo(displayId, mWindowInfos); + for (const auto& cancellationArgs : cancellations) { + switch (cancellationArgs.mode) { + case CancelationOptions::Mode::CANCEL_POINTER_EVENTS: + pointerCancellationOptions.deviceId = cancellationArgs.deviceId; + synthesizeCancelationEventsForWindowLocked(cancellationArgs.windowHandle, + pointerCancellationOptions); + break; + case CancelationOptions::Mode::CANCEL_HOVER_EVENTS: + hoverCancellationOptions.deviceId = cancellationArgs.deviceId; + synthesizeCancelationEventsForWindowLocked(cancellationArgs.windowHandle, + hoverCancellationOptions); + break; + default: + LOG_ALWAYS_FATAL("Unexpected cancellation Mode"); } } - // Check if the hovering should stop because the window is no longer eligible to receive it - // (for example, if the touchable region changed) - if (const auto& it = mTouchStatesByDisplay.find(displayId); it != mTouchStatesByDisplay.end()) { - TouchState& state = it->second; - for (TouchedWindow& touchedWindow : state.windows) { - std::vector<DeviceId> erasedDevices = touchedWindow.eraseHoveringPointersIf( - [this, displayId, &touchedWindow](const PointerProperties& properties, float x, - float y) REQUIRES(mLock) { - const bool isStylus = properties.toolType == ToolType::STYLUS; - const ui::Transform displayTransform = - mWindowInfos.getDisplayTransform(displayId); - const bool stillAcceptsTouch = - windowAcceptsTouchAt(*touchedWindow.windowHandle->getInfo(), - displayId, x, y, isStylus, displayTransform); - return !stillAcceptsTouch; - }); - - for (DeviceId deviceId : erasedDevices) { - CancelationOptions options(CancelationOptions::Mode::CANCEL_HOVER_EVENTS, - "WindowInfo changed", - traceContext.getTracker()); - options.deviceId = deviceId; - synthesizeCancelationEventsForWindowLocked(touchedWindow.windowHandle, options); - } - } + // If drag window is gone, it would receive a cancel event and broadcast the DRAG_END. We + // could just clear the state here. + if (mDragState && mDragState->dragWindow->getInfo()->displayId == displayId && + std::find(windowHandles.begin(), windowHandles.end(), mDragState->dragWindow) == + windowHandles.end()) { + ALOGI("Drag window went away: %s", mDragState->dragWindow->getName().c_str()); + sendDropWindowCommandLocked(nullptr, 0, 0); + mDragState.reset(); } // Release information for windows that are no longer present. @@ -5526,6 +5507,76 @@ void InputDispatcher::setInputWindowsLocked( } } +std::list<InputDispatcher::DispatcherTouchState::CancellationArgs> +InputDispatcher::DispatcherTouchState::updateFromWindowInfo( + ui::LogicalDisplayId displayId, const DispatcherWindowInfo& windowInfos) { + std::list<CancellationArgs> cancellations; + if (const auto& it = mTouchStatesByDisplay.find(displayId); it != mTouchStatesByDisplay.end()) { + TouchState& state = it->second; + cancellations = eraseRemovedWindowsFromWindowInfo(state, displayId, windowInfos); + cancellations.splice(cancellations.end(), + updateHoveringStateFromWindowInfo(state, displayId, windowInfos)); + } + return cancellations; +} + +std::list<InputDispatcher::DispatcherTouchState::CancellationArgs> +InputDispatcher::DispatcherTouchState::eraseRemovedWindowsFromWindowInfo( + TouchState& state, ui::LogicalDisplayId displayId, + const DispatcherWindowInfo& windowInfos) { + std::list<CancellationArgs> cancellations; + for (auto it = state.windows.begin(); it != state.windows.end();) { + TouchedWindow& touchedWindow = *it; + if (windowInfos.isWindowPresent(touchedWindow.windowHandle)) { + it++; + continue; + } + LOG(INFO) << "Touched window was removed: " << touchedWindow.windowHandle->getName() + << " in display %" << displayId; + cancellations.emplace_back(touchedWindow.windowHandle, + CancelationOptions::Mode::CANCEL_POINTER_EVENTS); + // Since we are about to drop the touch, cancel the events for the wallpaper as well. + if (touchedWindow.targetFlags.test(InputTarget::Flags::FOREGROUND) && + touchedWindow.windowHandle->getInfo()->inputConfig.test( + gui::WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER)) { + for (const DeviceId deviceId : touchedWindow.getTouchingDeviceIds()) { + if (const auto& ww = state.getWallpaperWindow(deviceId); ww != nullptr) { + cancellations.emplace_back(ww, CancelationOptions::Mode::CANCEL_POINTER_EVENTS, + deviceId); + } + } + } + it = state.windows.erase(it); + } + return cancellations; +} + +std::list<InputDispatcher::DispatcherTouchState::CancellationArgs> +InputDispatcher::DispatcherTouchState::updateHoveringStateFromWindowInfo( + TouchState& state, ui::LogicalDisplayId displayId, + const DispatcherWindowInfo& windowInfos) { + std::list<CancellationArgs> cancellations; + // Check if the hovering should stop because the window is no longer eligible to receive it + // (for example, if the touchable region changed) + ui::Transform displayTransform = windowInfos.getDisplayTransform(displayId); + for (TouchedWindow& touchedWindow : state.windows) { + std::vector<DeviceId> erasedDevices = touchedWindow.eraseHoveringPointersIf( + [&](const PointerProperties& properties, float x, float y) { + const bool isStylus = properties.toolType == ToolType::STYLUS; + const bool stillAcceptsTouch = + windowAcceptsTouchAt(*touchedWindow.windowHandle->getInfo(), displayId, + x, y, isStylus, displayTransform); + return !stillAcceptsTouch; + }); + + for (DeviceId deviceId : erasedDevices) { + cancellations.emplace_back(touchedWindow.windowHandle, + CancelationOptions::Mode::CANCEL_HOVER_EVENTS, deviceId); + } + } + return cancellations; +} + void InputDispatcher::setFocusedApplication( ui::LogicalDisplayId displayId, const std::shared_ptr<InputApplicationHandle>& inputApplicationHandle) { @@ -5751,34 +5802,6 @@ void InputDispatcher::setMaximumObscuringOpacityForTouch(float opacity) { mWindowInfos.setMaximumObscuringOpacityForTouch(opacity); } -std::tuple<const TouchState*, const TouchedWindow*, ui::LogicalDisplayId> -InputDispatcher::findTouchStateWindowAndDisplay( - const sp<IBinder>& token, - const std::unordered_map<ui::LogicalDisplayId, TouchState>& touchStatesByDisplay) { - for (auto& [displayId, state] : touchStatesByDisplay) { - for (const TouchedWindow& w : state.windows) { - if (w.windowHandle->getToken() == token) { - return std::make_tuple(&state, &w, displayId); - } - } - } - return std::make_tuple(nullptr, nullptr, ui::LogicalDisplayId::DEFAULT); -} - -std::tuple<TouchState*, TouchedWindow*, ui::LogicalDisplayId> -InputDispatcher::findTouchStateWindowAndDisplay( - const sp<IBinder>& token, - std::unordered_map<ui::LogicalDisplayId, TouchState>& touchStatesByDisplay) { - auto [constTouchState, constTouchedWindow, displayId] = InputDispatcher:: - findTouchStateWindowAndDisplay(token, - const_cast<const std::unordered_map<ui::LogicalDisplayId, - TouchState>&>( - touchStatesByDisplay)); - - return std::make_tuple(const_cast<TouchState*>(constTouchState), - const_cast<TouchedWindow*>(constTouchedWindow), displayId); -} - bool InputDispatcher::transferTouchGesture(const sp<IBinder>& fromToken, const sp<IBinder>& toToken, bool isDragDrop) { if (fromToken == toToken) { @@ -5791,52 +5814,33 @@ bool InputDispatcher::transferTouchGesture(const sp<IBinder>& fromToken, const s { // acquire lock std::scoped_lock _l(mLock); - // Find the target touch state and touched window by fromToken. - auto [state, touchedWindow, displayId] = - findTouchStateWindowAndDisplay(fromToken, mTouchStatesByDisplay); + ScopedSyntheticEventTracer traceContext(mTracer); + CancelationOptions options(CancelationOptions::Mode::CANCEL_POINTER_EVENTS, + "transferring touch from this window to another window", + traceContext.getTracker()); - if (state == nullptr || touchedWindow == nullptr) { - ALOGD("Touch transfer failed because from window is not being touched."); + auto result = mTouchStates.transferTouchGesture(fromToken, toToken, mWindowInfos, + mConnectionManager); + if (!result.has_value()) { return false; } - std::set<DeviceId> deviceIds = touchedWindow->getTouchingDeviceIds(); - if (deviceIds.size() != 1) { - LOG(INFO) << "Can't transfer touch. Currently touching devices: " - << dumpContainer(deviceIds) << " for window: " << touchedWindow->dump(); - return false; - } - const DeviceId deviceId = *deviceIds.begin(); - const sp<WindowInfoHandle> fromWindowHandle = touchedWindow->windowHandle; - const sp<WindowInfoHandle> toWindowHandle = - mWindowInfos.findWindowHandle(toToken, displayId); - if (!toWindowHandle) { - ALOGW("Cannot transfer touch because the transfer target window was not found."); - return false; - } + const auto [toWindowHandle, deviceId, pointers, cancellations, pointerDowns] = + result.value(); - if (DEBUG_FOCUS) { - ALOGD("%s: fromWindowHandle=%s, toWindowHandle=%s", __func__, - touchedWindow->windowHandle->getName().c_str(), - toWindowHandle->getName().c_str()); + for (const auto& cancellationArgs : cancellations) { + LOG_ALWAYS_FATAL_IF(cancellationArgs.mode != + CancelationOptions::Mode::CANCEL_POINTER_EVENTS); + LOG_ALWAYS_FATAL_IF(cancellationArgs.deviceId.has_value()); + synthesizeCancelationEventsForWindowLocked(cancellationArgs.windowHandle, options); } - // Erase old window. - ftl::Flags<InputTarget::Flags> oldTargetFlags = touchedWindow->targetFlags; - std::vector<PointerProperties> pointers = touchedWindow->getTouchingPointers(deviceId); - state->removeWindowByToken(fromToken); - - // Add new window. - nsecs_t downTimeInTarget = now(); - ftl::Flags<InputTarget::Flags> newTargetFlags = - oldTargetFlags & (InputTarget::Flags::SPLIT); - if (canReceiveForegroundTouches(*toWindowHandle->getInfo())) { - newTargetFlags |= InputTarget::Flags::FOREGROUND; + for (const auto& pointerDownArgs : pointerDowns) { + synthesizePointerDownEventsForConnectionLocked(pointerDownArgs.downTimeInTarget, + pointerDownArgs.connection, + pointerDownArgs.targetFlags, + traceContext.getTracker()); } - // Transferring touch focus using this API should not effect the focused window. - newTargetFlags |= InputTarget::Flags::NO_FOCUS_CHANGE; - state->addOrUpdateWindow(toWindowHandle, InputTarget::DispatchMode::AS_IS, newTargetFlags, - deviceId, pointers, downTimeInTarget); // Store the dragging window. if (isDragDrop) { @@ -5849,30 +5853,6 @@ bool InputDispatcher::transferTouchGesture(const sp<IBinder>& fromToken, const s const size_t id = pointers.begin()->id; mDragState = std::make_unique<DragState>(toWindowHandle, deviceId, id); } - - // Synthesize cancel for old window and down for new window. - ScopedSyntheticEventTracer traceContext(mTracer); - std::shared_ptr<Connection> fromConnection = mConnectionManager.getConnection(fromToken); - std::shared_ptr<Connection> toConnection = mConnectionManager.getConnection(toToken); - if (fromConnection != nullptr && toConnection != nullptr) { - fromConnection->inputState.mergePointerStateTo(toConnection->inputState); - CancelationOptions options(CancelationOptions::Mode::CANCEL_POINTER_EVENTS, - "transferring touch from this window to another window", - traceContext.getTracker()); - synthesizeCancelationEventsForWindowLocked(fromWindowHandle, options, fromConnection); - - // Check if the wallpaper window should deliver the corresponding event. - transferWallpaperTouch(oldTargetFlags, newTargetFlags, fromWindowHandle, toWindowHandle, - *state, deviceId, pointers, traceContext.getTracker()); - - // Because new window may have a wallpaper window, it will merge input state from it - // parent window, after this the firstNewPointerIdx in input state will be reset, then - // it will cause new move event be thought inconsistent, so we should synthesize the - // down event after it reset. - synthesizePointerDownEventsForConnectionLocked(downTimeInTarget, toConnection, - newTargetFlags, - traceContext.getTracker()); - } } // release lock // Wake up poll loop since it may need to make new input dispatching choices. @@ -5880,16 +5860,94 @@ bool InputDispatcher::transferTouchGesture(const sp<IBinder>& fromToken, const s return true; } +std::optional<std::tuple<sp<gui::WindowInfoHandle>, DeviceId, std::vector<PointerProperties>, + std::list<InputDispatcher::DispatcherTouchState::CancellationArgs>, + std::list<InputDispatcher::DispatcherTouchState::PointerDownArgs>>> +InputDispatcher::DispatcherTouchState::transferTouchGesture(const sp<android::IBinder>& fromToken, + const sp<android::IBinder>& toToken, + const DispatcherWindowInfo& windowInfos, + const ConnectionManager& connections) { + // Find the target touch state and touched window by fromToken. + auto touchStateWindowAndDisplay = findTouchStateWindowAndDisplay(fromToken); + if (!touchStateWindowAndDisplay.has_value()) { + ALOGD("Touch transfer failed because from window is not being touched."); + return std::nullopt; + } + + auto [state, touchedWindow, displayId] = touchStateWindowAndDisplay.value(); + std::set<DeviceId> deviceIds = touchedWindow.getTouchingDeviceIds(); + if (deviceIds.size() != 1) { + LOG(INFO) << "Can't transfer touch. Currently touching devices: " + << dumpContainer(deviceIds) << " for window: " << touchedWindow.dump(); + return std::nullopt; + } + const DeviceId deviceId = *deviceIds.begin(); + + const sp<WindowInfoHandle> fromWindowHandle = touchedWindow.windowHandle; + const sp<WindowInfoHandle> toWindowHandle = windowInfos.findWindowHandle(toToken, displayId); + if (!toWindowHandle) { + ALOGW("Cannot transfer touch because the transfer target window was not found."); + return std::nullopt; + } + + if (DEBUG_FOCUS) { + ALOGD("%s: fromWindowHandle=%s, toWindowHandle=%s", __func__, + fromWindowHandle->getName().c_str(), toWindowHandle->getName().c_str()); + } + + // Erase old window. + ftl::Flags<InputTarget::Flags> oldTargetFlags = touchedWindow.targetFlags; + std::vector<PointerProperties> pointers = touchedWindow.getTouchingPointers(deviceId); + state.removeWindowByToken(fromToken); + + // Add new window. + nsecs_t downTimeInTarget = now(); + ftl::Flags<InputTarget::Flags> newTargetFlags = oldTargetFlags & (InputTarget::Flags::SPLIT); + if (canReceiveForegroundTouches(*toWindowHandle->getInfo())) { + newTargetFlags |= InputTarget::Flags::FOREGROUND; + } + // Transferring touch focus using this API should not effect the focused window. + newTargetFlags |= InputTarget::Flags::NO_FOCUS_CHANGE; + state.addOrUpdateWindow(toWindowHandle, InputTarget::DispatchMode::AS_IS, newTargetFlags, + deviceId, pointers, downTimeInTarget); + + // Synthesize cancel for old window and down for new window. + std::shared_ptr<Connection> fromConnection = connections.getConnection(fromToken); + std::shared_ptr<Connection> toConnection = connections.getConnection(toToken); + std::list<CancellationArgs> cancellations; + std::list<PointerDownArgs> pointerDowns; + if (fromConnection != nullptr && toConnection != nullptr) { + fromConnection->inputState.mergePointerStateTo(toConnection->inputState); + cancellations.emplace_back(fromWindowHandle, + CancelationOptions::Mode::CANCEL_POINTER_EVENTS); + + // Check if the wallpaper window should deliver the corresponding event. + auto [wallpaperCancellations, wallpaperPointerDowns] = + transferWallpaperTouch(fromWindowHandle, toWindowHandle, state, deviceId, pointers, + oldTargetFlags, newTargetFlags, windowInfos, connections); + + cancellations.splice(cancellations.end(), wallpaperCancellations); + pointerDowns.splice(pointerDowns.end(), wallpaperPointerDowns); + + // Because new window may have a wallpaper window, it will merge input state from it + // parent window, after this the firstNewPointerIdx in input state will be reset, then + // it will cause new move event be thought inconsistent, so we should synthesize the + // down event after it reset. + pointerDowns.emplace_back(downTimeInTarget, toConnection, newTargetFlags); + } + + return std::make_tuple(toWindowHandle, deviceId, pointers, cancellations, pointerDowns); +} + /** * Get the touched foreground window on the given display. * Return null if there are no windows touched on that display, or if more than one foreground * window is being touched. */ -sp<WindowInfoHandle> InputDispatcher::findTouchedForegroundWindow( - const std::unordered_map<ui::LogicalDisplayId, TouchState>& touchStatesByDisplay, - ui::LogicalDisplayId displayId) { - const auto stateIt = touchStatesByDisplay.find(displayId); - if (stateIt == touchStatesByDisplay.end()) { +sp<WindowInfoHandle> InputDispatcher::DispatcherTouchState::findTouchedForegroundWindow( + ui::LogicalDisplayId displayId) const { + const auto stateIt = mTouchStatesByDisplay.find(displayId); + if (stateIt == mTouchStatesByDisplay.end()) { ALOGI("No touch state on display %s", displayId.toString().c_str()); return nullptr; } @@ -5925,7 +5983,7 @@ bool InputDispatcher::transferTouchOnDisplay(const sp<IBinder>& destChannelToken return false; } - sp<WindowInfoHandle> from = findTouchedForegroundWindow(mTouchStatesByDisplay, displayId); + sp<WindowInfoHandle> from = mTouchStates.findTouchedForegroundWindow(displayId); if (from == nullptr) { ALOGE("Could not find a source window in %s for %p", __func__, destChannelToken.get()); return false; @@ -5953,7 +6011,7 @@ void InputDispatcher::resetAndDropEverythingLocked(const char* reason) { resetNoFocusedWindowTimeoutLocked(); mAnrTracker.clear(); - mTouchStatesByDisplay.clear(); + mTouchStates.clear(); } void InputDispatcher::logDispatchStateLocked() const { @@ -6011,15 +6069,7 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) const { dump += mFocusResolver.dump(); dump += dumpPointerCaptureStateLocked(); - if (!mTouchStatesByDisplay.empty()) { - dump += StringPrintf(INDENT "TouchStatesByDisplay:\n"); - for (const auto& [displayId, state] : mTouchStatesByDisplay) { - std::string touchStateDump = addLinePrefix(state.dump(), INDENT2); - dump += INDENT2 + displayId.toString() + " : " + touchStateDump; - } - } else { - dump += INDENT "TouchStates: <no displays touched>\n"; - } + dump += addLinePrefix(mTouchStates.dump(), INDENT); if (mDragState) { dump += StringPrintf(INDENT "DragState:\n"); @@ -6221,43 +6271,62 @@ status_t InputDispatcher::pilferPointersLocked(const sp<IBinder>& token) { return BAD_VALUE; } - auto [statePtr, windowPtr, displayId] = - findTouchStateWindowAndDisplay(token, mTouchStatesByDisplay); - if (statePtr == nullptr || windowPtr == nullptr) { + ScopedSyntheticEventTracer traceContext(mTracer); + CancelationOptions options(CancelationOptions::Mode::CANCEL_POINTER_EVENTS, + "input channel stole pointer stream", traceContext.getTracker()); + const auto result = mTouchStates.pilferPointers(token, *requestingConnection); + if (!result.ok()) { + return result.error().code(); + } + + const auto cancellations = *result; + for (const auto& cancellationArgs : cancellations) { + LOG_ALWAYS_FATAL_IF(cancellationArgs.mode != + CancelationOptions::Mode::CANCEL_POINTER_EVENTS); + options.displayId = cancellationArgs.displayId; + options.deviceId = cancellationArgs.deviceId; + options.pointerIds = cancellationArgs.pointerIds; + synthesizeCancelationEventsForWindowLocked(cancellationArgs.windowHandle, options); + } + return OK; +} + +base::Result<std::list<InputDispatcher::DispatcherTouchState::CancellationArgs>, status_t> +InputDispatcher::DispatcherTouchState::pilferPointers(const sp<IBinder>& token, + const Connection& requestingConnection) { + auto touchStateWindowAndDisplay = findTouchStateWindowAndDisplay(token); + if (!touchStateWindowAndDisplay.has_value()) { LOG(WARNING) << "Attempted to pilfer points from a channel without any on-going pointer streams." " Ignoring."; - return BAD_VALUE; + return Error(BAD_VALUE); } - std::set<int32_t> deviceIds = windowPtr->getTouchingDeviceIds(); + + auto [state, window, displayId] = touchStateWindowAndDisplay.value(); + + std::set<int32_t> deviceIds = window.getTouchingDeviceIds(); if (deviceIds.empty()) { - LOG(WARNING) << "Can't pilfer: no touching devices in window: " << windowPtr->dump(); - return BAD_VALUE; + LOG(WARNING) << "Can't pilfer: no touching devices in window: " << window.dump(); + return Error(BAD_VALUE); } - ScopedSyntheticEventTracer traceContext(mTracer); + std::list<CancellationArgs> cancellations; for (const DeviceId deviceId : deviceIds) { - TouchState& state = *statePtr; - TouchedWindow& window = *windowPtr; // Send cancel events to all the input channels we're stealing from. - CancelationOptions options(CancelationOptions::Mode::CANCEL_POINTER_EVENTS, - "input channel stole pointer stream", traceContext.getTracker()); - options.deviceId = deviceId; - options.displayId = displayId; std::vector<PointerProperties> pointers = window.getTouchingPointers(deviceId); std::bitset<MAX_POINTER_ID + 1> pointerIds = getPointerIds(pointers); - options.pointerIds = pointerIds; - std::string canceledWindows; for (const TouchedWindow& w : state.windows) { if (w.windowHandle->getToken() != token) { - synthesizeCancelationEventsForWindowLocked(w.windowHandle, options); + cancellations.emplace_back(w.windowHandle, + CancelationOptions::Mode::CANCEL_POINTER_EVENTS, + deviceId, displayId, pointerIds); canceledWindows += canceledWindows.empty() ? "[" : ", "; canceledWindows += w.windowHandle->getName(); } } canceledWindows += canceledWindows.empty() ? "[]" : "]"; - LOG(INFO) << "Channel " << requestingConnection->getInputChannelName() + LOG(INFO) << "Channel " << requestingConnection.getInputChannelName() << " is stealing input gesture for device " << deviceId << " from " << canceledWindows; @@ -6267,7 +6336,7 @@ status_t InputDispatcher::pilferPointersLocked(const sp<IBinder>& token) { state.cancelPointersForWindowsExcept(deviceId, pointerIds, token); } - return OK; + return cancellations; } void InputDispatcher::requestPointerCapture(const sp<IBinder>& windowToken, bool enabled) { @@ -7037,12 +7106,13 @@ void InputDispatcher::onWindowInfosChanged(const gui::WindowInfosUpdate& update) mLooper->wake(); } -bool InputDispatcher::shouldDropInput( - const EventEntry& entry, const sp<android::gui::WindowInfoHandle>& windowHandle) const { +bool InputDispatcher::shouldDropInput(const EventEntry& entry, + const sp<WindowInfoHandle>& windowHandle, + const DispatcherWindowInfo& windowInfos) { if (windowHandle->getInfo()->inputConfig.test(WindowInfo::InputConfig::DROP_INPUT) || (windowHandle->getInfo()->inputConfig.test( WindowInfo::InputConfig::DROP_INPUT_IF_OBSCURED) && - mWindowInfos.isWindowObscured(windowHandle))) { + windowInfos.isWindowObscured(windowHandle))) { ALOGW("Dropping %s event targeting %s as requested by the input configuration {%s} on " "display %s.", ftl::enum_string(entry.type).c_str(), windowHandle->getName().c_str(), @@ -7067,7 +7137,7 @@ void InputDispatcher::cancelCurrentTouch() { "cancel current touch", traceContext.getTracker()); synthesizeCancelationEventsForAllConnectionsLocked(options); - mTouchStatesByDisplay.clear(); + mTouchStates.clear(); } // Wake up poll loop since there might be work to do. mLooper->wake(); @@ -7078,11 +7148,11 @@ void InputDispatcher::setMonitorDispatchingTimeoutForTest(std::chrono::nanosecon mMonitorDispatchingTimeout = timeout; } -void InputDispatcher::slipWallpaperTouch(ftl::Flags<InputTarget::Flags> targetFlags, - const sp<WindowInfoHandle>& oldWindowHandle, - const sp<WindowInfoHandle>& newWindowHandle, - TouchState& state, const MotionEntry& entry, - std::vector<InputTarget>& targets) const { +void InputDispatcher::DispatcherTouchState::slipWallpaperTouch( + ftl::Flags<InputTarget::Flags> targetFlags, const sp<WindowInfoHandle>& oldWindowHandle, + const sp<WindowInfoHandle>& newWindowHandle, TouchState& state, const MotionEntry& entry, + std::vector<InputTarget>& targets, const ConnectionManager& connections, + const DispatcherWindowInfo& windowInfos, std::function<void()> dump) { LOG_IF(FATAL, entry.getPointerCount() != 1) << "Entry not eligible for slip: " << entry; const DeviceId deviceId = entry.deviceId; const PointerProperties& pointerProperties = entry.pointerProperties[0]; @@ -7095,16 +7165,19 @@ void InputDispatcher::slipWallpaperTouch(ftl::Flags<InputTarget::Flags> targetFl const sp<WindowInfoHandle> oldWallpaper = oldHasWallpaper ? state.getWallpaperWindow(deviceId) : nullptr; const sp<WindowInfoHandle> newWallpaper = - newHasWallpaper ? mWindowInfos.findWallpaperWindowBelow(newWindowHandle) : nullptr; + newHasWallpaper ? windowInfos.findWallpaperWindowBelow(newWindowHandle) : nullptr; if (oldWallpaper == newWallpaper) { return; } if (oldWallpaper != nullptr) { const TouchedWindow& oldTouchedWindow = state.getTouchedWindow(oldWallpaper); - addPointerWindowTargetLocked(oldWallpaper, InputTarget::DispatchMode::SLIPPERY_EXIT, - oldTouchedWindow.targetFlags, getPointerIds(pointers), - oldTouchedWindow.getDownTimeInTarget(deviceId), targets); + DispatcherTouchState::addPointerWindowTarget(oldWallpaper, + InputTarget::DispatchMode::SLIPPERY_EXIT, + oldTouchedWindow.targetFlags, + getPointerIds(pointers), + oldTouchedWindow.getDownTimeInTarget(deviceId), + connections, windowInfos, dump, targets); state.removeTouchingPointerFromWindow(deviceId, pointerProperties.id, oldWallpaper); } @@ -7116,12 +7189,15 @@ void InputDispatcher::slipWallpaperTouch(ftl::Flags<InputTarget::Flags> targetFl } } -void InputDispatcher::transferWallpaperTouch( +std::pair<std::list<InputDispatcher::DispatcherTouchState::CancellationArgs>, + std::list<InputDispatcher::DispatcherTouchState::PointerDownArgs>> +InputDispatcher::DispatcherTouchState::transferWallpaperTouch( + const sp<gui::WindowInfoHandle> fromWindowHandle, + const sp<gui::WindowInfoHandle> toWindowHandle, TouchState& state, + android::DeviceId deviceId, const std::vector<PointerProperties>& pointers, ftl::Flags<InputTarget::Flags> oldTargetFlags, - ftl::Flags<InputTarget::Flags> newTargetFlags, const sp<WindowInfoHandle> fromWindowHandle, - const sp<WindowInfoHandle> toWindowHandle, TouchState& state, DeviceId deviceId, - const std::vector<PointerProperties>& pointers, - const std::unique_ptr<trace::EventTrackerInterface>& traceTracker) { + ftl::Flags<InputTarget::Flags> newTargetFlags, const DispatcherWindowInfo& windowInfos, + const ConnectionManager& connections) { const bool oldHasWallpaper = oldTargetFlags.test(InputTarget::Flags::FOREGROUND) && fromWindowHandle->getInfo()->inputConfig.test( gui::WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER); @@ -7132,16 +7208,16 @@ void InputDispatcher::transferWallpaperTouch( const sp<WindowInfoHandle> oldWallpaper = oldHasWallpaper ? state.getWallpaperWindow(deviceId) : nullptr; const sp<WindowInfoHandle> newWallpaper = - newHasWallpaper ? mWindowInfos.findWallpaperWindowBelow(toWindowHandle) : nullptr; + newHasWallpaper ? windowInfos.findWallpaperWindowBelow(toWindowHandle) : nullptr; if (oldWallpaper == newWallpaper) { - return; + return {}; } + std::list<CancellationArgs> cancellations; + std::list<PointerDownArgs> pointerDowns; if (oldWallpaper != nullptr) { - CancelationOptions options(CancelationOptions::Mode::CANCEL_POINTER_EVENTS, - "transferring touch focus to another window", traceTracker); state.removeWindowByToken(oldWallpaper->getToken()); - synthesizeCancelationEventsForWindowLocked(oldWallpaper, options); + cancellations.emplace_back(oldWallpaper, CancelationOptions::Mode::CANCEL_POINTER_EVENTS); } if (newWallpaper != nullptr) { @@ -7153,15 +7229,16 @@ void InputDispatcher::transferWallpaperTouch( state.addOrUpdateWindow(newWallpaper, InputTarget::DispatchMode::AS_IS, wallpaperFlags, deviceId, pointers, downTimeInTarget); std::shared_ptr<Connection> wallpaperConnection = - mConnectionManager.getConnection(newWallpaper->getToken()); + connections.getConnection(newWallpaper->getToken()); if (wallpaperConnection != nullptr) { std::shared_ptr<Connection> toConnection = - mConnectionManager.getConnection(toWindowHandle->getToken()); + connections.getConnection(toWindowHandle->getToken()); toConnection->inputState.mergePointerStateTo(wallpaperConnection->inputState); - synthesizePointerDownEventsForConnectionLocked(downTimeInTarget, wallpaperConnection, - wallpaperFlags, traceTracker); + pointerDowns.emplace_back(downTimeInTarget, wallpaperConnection, wallpaperFlags); } + pointerDowns.emplace_back(downTimeInTarget, wallpaperConnection, wallpaperFlags); } + return {cancellations, pointerDowns}; } sp<WindowInfoHandle> InputDispatcher::DispatcherWindowInfo::findWallpaperWindowBelow( @@ -7199,18 +7276,7 @@ bool InputDispatcher::isPointerInWindow(const sp<android::IBinder>& token, ui::LogicalDisplayId displayId, DeviceId deviceId, int32_t pointerId) { std::scoped_lock _l(mLock); - auto touchStateIt = mTouchStatesByDisplay.find(displayId); - if (touchStateIt == mTouchStatesByDisplay.end()) { - return false; - } - for (const TouchedWindow& window : touchStateIt->second.windows) { - if (window.windowHandle->getToken() == token && - (window.hasTouchingPointer(deviceId, pointerId) || - window.hasHoveringPointer(deviceId, pointerId))) { - return true; - } - } - return false; + return mTouchStates.isPointerInWindow(token, displayId, deviceId, pointerId); } void InputDispatcher::setInputMethodConnectionIsActive(bool isActive) { @@ -7355,4 +7421,122 @@ void InputDispatcher::DispatcherWindowInfo::setMaximumObscuringOpacityForTouch(f mMaximumObscuringOpacityForTouch = opacity; } +ftl::Flags<InputTarget::Flags> InputDispatcher::DispatcherTouchState::getTargetFlags( + const sp<WindowInfoHandle>& targetWindow, vec2 targetPosition, bool isSplit, + const DispatcherWindowInfo& windowInfos) { + ftl::Flags<InputTarget::Flags> targetFlags; + if (canReceiveForegroundTouches(*targetWindow->getInfo())) { + // There should only be one touched window that can be "foreground" for the pointer. + targetFlags |= InputTarget::Flags::FOREGROUND; + } + if (isSplit) { + targetFlags |= InputTarget::Flags::SPLIT; + } + if (windowInfos.isWindowObscuredAtPoint(targetWindow, targetPosition.x, targetPosition.y)) { + targetFlags |= InputTarget::Flags::WINDOW_IS_OBSCURED; + } else if (windowInfos.isWindowObscured(targetWindow)) { + targetFlags |= InputTarget::Flags::WINDOW_IS_PARTIALLY_OBSCURED; + } + return targetFlags; +} + +bool InputDispatcher::DispatcherTouchState::hasTouchingOrHoveringPointers( + ui::LogicalDisplayId displayId, int32_t deviceId) const { + const auto touchStateIt = mTouchStatesByDisplay.find(displayId); + if (touchStateIt == mTouchStatesByDisplay.end()) { + return false; + } + return touchStateIt->second.hasTouchingPointers(deviceId) || + touchStateIt->second.hasHoveringPointers(deviceId); +} + +bool InputDispatcher::DispatcherTouchState::isPointerInWindow(const sp<android::IBinder>& token, + ui::LogicalDisplayId displayId, + android::DeviceId deviceId, + int32_t pointerId) const { + const auto touchStateIt = mTouchStatesByDisplay.find(displayId); + if (touchStateIt == mTouchStatesByDisplay.end()) { + return false; + } + for (const TouchedWindow& window : touchStateIt->second.windows) { + if (window.windowHandle->getToken() == token && + (window.hasTouchingPointer(deviceId, pointerId) || + window.hasHoveringPointer(deviceId, pointerId))) { + return true; + } + } + return false; +} + +std::optional<std::tuple<const sp<gui::WindowInfoHandle>&, ui::LogicalDisplayId>> +InputDispatcher::DispatcherTouchState::findTouchedWindowHandleAndDisplay( + const sp<android::IBinder>& token) const { + for (const auto& [displayId, state] : mTouchStatesByDisplay) { + for (const TouchedWindow& w : state.windows) { + if (w.windowHandle->getToken() == token) { + return std::make_tuple(std::ref(w.windowHandle), displayId); + } + } + } + return std::nullopt; +} + +void InputDispatcher::DispatcherTouchState::forAllTouchedWindows( + std::function<void(const sp<gui::WindowInfoHandle>&)> f) const { + for (const auto& [_, state] : mTouchStatesByDisplay) { + for (const TouchedWindow& window : state.windows) { + f(window.windowHandle); + } + } +} + +void InputDispatcher::DispatcherTouchState::forAllTouchedWindowsOnDisplay( + ui::LogicalDisplayId displayId, + std::function<void(const sp<gui::WindowInfoHandle>&)> f) const { + const auto touchStateIt = mTouchStatesByDisplay.find(displayId); + if (touchStateIt == mTouchStatesByDisplay.end()) { + return; + } + for (const TouchedWindow& window : touchStateIt->second.windows) { + f(window.windowHandle); + } +} + +std::string InputDispatcher::DispatcherTouchState::dump() const { + std::string dump; + if (!mTouchStatesByDisplay.empty()) { + dump += StringPrintf("TouchStatesByDisplay:\n"); + for (const auto& [displayId, state] : mTouchStatesByDisplay) { + std::string touchStateDump = addLinePrefix(state.dump(), INDENT); + dump += INDENT + displayId.toString() + " : " + touchStateDump; + } + } else { + dump += "TouchStates: <no displays touched>\n"; + } + return dump; +} + +void InputDispatcher::DispatcherTouchState::removeAllPointersForDevice(android::DeviceId deviceId) { + for (auto& [_, touchState] : mTouchStatesByDisplay) { + touchState.removeAllPointersForDevice(deviceId); + } +} + +void InputDispatcher::DispatcherTouchState::clear() { + mTouchStatesByDisplay.clear(); +} + +std::optional<std::tuple<TouchState&, TouchedWindow&, ui::LogicalDisplayId>> +InputDispatcher::DispatcherTouchState::findTouchStateWindowAndDisplay( + const sp<android::IBinder>& token) { + for (auto& [displayId, state] : mTouchStatesByDisplay) { + for (TouchedWindow& w : state.windows) { + if (w.windowHandle->getToken() == token) { + return std::make_tuple(std::ref(state), std::ref(w), displayId); + } + } + } + return std::nullopt; +} + } // namespace android::inputdispatcher diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h index 415f4c8031..f468be8a3d 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.h +++ b/services/inputflinger/dispatcher/InputDispatcher.h @@ -350,6 +350,137 @@ private: DispatcherWindowInfo mWindowInfos GUARDED_BY(mLock); + class DispatcherTouchState { + public: + struct CancellationArgs { + const sp<gui::WindowInfoHandle> windowHandle; + CancelationOptions::Mode mode; + std::optional<DeviceId> deviceId{std::nullopt}; + ui::LogicalDisplayId displayId{ui::LogicalDisplayId::INVALID}; + std::bitset<MAX_POINTER_ID + 1> pointerIds{}; + }; + + struct PointerDownArgs { + const nsecs_t downTimeInTarget; + const std::shared_ptr<Connection> connection; + const ftl::Flags<InputTarget::Flags> targetFlags; + }; + + static void addPointerWindowTarget(const sp<android::gui::WindowInfoHandle>& windowHandle, + InputTarget::DispatchMode dispatchMode, + ftl::Flags<InputTarget::Flags> targetFlags, + std::bitset<MAX_POINTER_ID + 1> pointerIds, + std::optional<nsecs_t> firstDownTimeInTarget, + const ConnectionManager& connections, + const DispatcherWindowInfo& windowInfos, + std::function<void()> dump, + std::vector<InputTarget>& inputTargets); + + base::Result<std::vector<InputTarget>, android::os::InputEventInjectionResult> + findTouchedWindowTargets(nsecs_t currentTime, const MotionEntry& entry, + const ConnectionManager& connections, + const DispatcherWindowInfo& windowInfos, + const sp<android::gui::WindowInfoHandle> dragWindow, + std::function<void(const MotionEntry&)> addDragEvent, + std::function<void()> dump); + + sp<android::gui::WindowInfoHandle> findTouchedForegroundWindow( + ui::LogicalDisplayId displayId) const; + + bool hasTouchingOrHoveringPointers(ui::LogicalDisplayId displayId, int32_t deviceId) const; + + bool isPointerInWindow(const sp<android::IBinder>& token, ui::LogicalDisplayId displayId, + DeviceId deviceId, int32_t pointerId) const; + + // Find touched windowHandle and display by token. + std::optional<std::tuple<const sp<gui::WindowInfoHandle>&, ui::LogicalDisplayId>> + findTouchedWindowHandleAndDisplay(const sp<IBinder>& token) const; + + void forAllTouchedWindows(std::function<void(const sp<gui::WindowInfoHandle>&)> f) const; + + void forAllTouchedWindowsOnDisplay( + ui::LogicalDisplayId displayId, + std::function<void(const sp<gui::WindowInfoHandle>&)> f) const; + + std::string dump() const; + + // Updates the touchState for display from WindowInfo, + // returns list of CancellationArgs for every cancelled touch + std::list<CancellationArgs> updateFromWindowInfo(ui::LogicalDisplayId displayId, + const DispatcherWindowInfo& windowInfos); + + void removeAllPointersForDevice(DeviceId deviceId); + + // transfer touch between provided tokens, returns destination WindowHandle, deviceId, + // pointers, list of cancelled windows and pointers on successful transfer. + std::optional< + std::tuple<sp<gui::WindowInfoHandle>, DeviceId, std::vector<PointerProperties>, + std::list<CancellationArgs>, std::list<PointerDownArgs>>> + transferTouchGesture(const sp<IBinder>& fromToken, const sp<IBinder>& toToken, + const DispatcherWindowInfo& windowInfos, + const ConnectionManager& connections); + + base::Result<std::list<CancellationArgs>, status_t> pilferPointers( + const sp<IBinder>& token, const Connection& requestingConnection); + + void clear(); + + std::unordered_map<ui::LogicalDisplayId, TouchState> mTouchStatesByDisplay; + + private: + std::optional<std::tuple<TouchState&, TouchedWindow&, ui::LogicalDisplayId>> + findTouchStateWindowAndDisplay(const sp<IBinder>& token); + + std::pair<std::list<CancellationArgs>, std::list<PointerDownArgs>> transferWallpaperTouch( + const sp<gui::WindowInfoHandle> fromWindowHandle, + const sp<gui::WindowInfoHandle> toWindowHandle, TouchState& state, + DeviceId deviceId, const std::vector<PointerProperties>& pointers, + ftl::Flags<InputTarget::Flags> oldTargetFlags, + ftl::Flags<InputTarget::Flags> newTargetFlags, + const DispatcherWindowInfo& windowInfos, const ConnectionManager& connections); + + static std::list<CancellationArgs> eraseRemovedWindowsFromWindowInfo( + TouchState& state, ui::LogicalDisplayId displayId, + const DispatcherWindowInfo& windowInfos); + + static std::list<CancellationArgs> updateHoveringStateFromWindowInfo( + TouchState& state, ui::LogicalDisplayId displayId, + const DispatcherWindowInfo& windowInfos); + + static std::vector<InputTarget> findOutsideTargets( + ui::LogicalDisplayId displayId, const sp<gui::WindowInfoHandle>& touchedWindow, + int32_t pointerId, const ConnectionManager& connections, + const DispatcherWindowInfo& windowInfos, std::function<void()> dump); + + /** + * Slip the wallpaper touch if necessary. + * + * @param targetFlags the target flags + * @param oldWindowHandle the old window that the touch slipped out of + * @param newWindowHandle the new window that the touch is slipping into + * @param state the current touch state. This will be updated if necessary to reflect the + * new windows that are receiving touch. + * @param deviceId the device id of the current motion being processed + * @param pointerProperties the pointer properties of the current motion being processed + * @param targets the current targets to add the walpaper ones to + * @param eventTime the new downTime for the wallpaper target + */ + static void slipWallpaperTouch(ftl::Flags<InputTarget::Flags> targetFlags, + const sp<android::gui::WindowInfoHandle>& oldWindowHandle, + const sp<android::gui::WindowInfoHandle>& newWindowHandle, + TouchState& state, const MotionEntry& entry, + std::vector<InputTarget>& targets, + const ConnectionManager& connections, + const DispatcherWindowInfo& windowInfos, + std::function<void()> dump); + + static ftl::Flags<InputTarget::Flags> getTargetFlags( + const sp<android::gui::WindowInfoHandle>& targetWindow, vec2 targetPosition, + bool isSplit, const DispatcherWindowInfo& windowInfos); + }; + + DispatcherTouchState mTouchStates GUARDED_BY(mLock); + // With each iteration, InputDispatcher nominally processes one queued event, // a timeout, or a response from an input consumer. // This method should only be called on the input dispatcher's own thread. @@ -378,14 +509,6 @@ private: // to transfer focus to a new application. std::shared_ptr<const EventEntry> mNextUnblockedEvent GUARDED_BY(mLock); - std::vector<InputTarget> findOutsideTargetsLocked( - ui::LogicalDisplayId displayId, const sp<android::gui::WindowInfoHandle>& touchedWindow, - int32_t pointerId) const REQUIRES(mLock); - - static sp<android::gui::WindowInfoHandle> findTouchedForegroundWindow( - const std::unordered_map<ui::LogicalDisplayId, TouchState>& touchStatesByDisplay, - ui::LogicalDisplayId displayId); - status_t pilferPointersLocked(const sp<IBinder>& token) REQUIRES(mLock); const HmacKeyManager mHmacKeyManager; @@ -470,8 +593,11 @@ private: sp<android::gui::WindowInfoHandle> getFocusedWindowHandleLocked( ui::LogicalDisplayId displayId) const REQUIRES(mLock); - bool canWindowReceiveMotionLocked(const sp<android::gui::WindowInfoHandle>& window, - const MotionEntry& motionEntry) const REQUIRES(mLock); + + static bool canWindowReceiveMotion( + const sp<android::gui::WindowInfoHandle>& window, const MotionEntry& motionEntry, + const ConnectionManager& connections, const DispatcherWindowInfo& windowInfos, + const std::unordered_map<ui::LogicalDisplayId, TouchState>& touchStates); // Returns all the input targets (with their respective input channels) from the window handles // passed as argument. @@ -486,8 +612,6 @@ private: const std::vector<sp<android::gui::WindowInfoHandle>>& inputWindowHandles, ui::LogicalDisplayId displayId) REQUIRES(mLock); - std::unordered_map<ui::LogicalDisplayId /*displayId*/, TouchState> mTouchStatesByDisplay - GUARDED_BY(mLock); std::unique_ptr<DragState> mDragState GUARDED_BY(mLock); void setFocusedApplicationLocked( @@ -627,20 +751,12 @@ private: base::Result<sp<android::gui::WindowInfoHandle>, android::os::InputEventInjectionResult> findFocusedWindowTargetLocked(nsecs_t currentTime, const EventEntry& entry, nsecs_t& nextWakeupTime) REQUIRES(mLock); - base::Result<std::vector<InputTarget>, android::os::InputEventInjectionResult> - findTouchedWindowTargetsLocked(nsecs_t currentTime, const MotionEntry& entry) REQUIRES(mLock); void addWindowTargetLocked(const sp<android::gui::WindowInfoHandle>& windowHandle, InputTarget::DispatchMode dispatchMode, ftl::Flags<InputTarget::Flags> targetFlags, std::optional<nsecs_t> firstDownTimeInTarget, std::vector<InputTarget>& inputTargets) const REQUIRES(mLock); - void addPointerWindowTargetLocked(const sp<android::gui::WindowInfoHandle>& windowHandle, - InputTarget::DispatchMode dispatchMode, - ftl::Flags<InputTarget::Flags> targetFlags, - std::bitset<MAX_POINTER_ID + 1> pointerIds, - std::optional<nsecs_t> firstDownTimeInTarget, - std::vector<InputTarget>& inputTargets) const REQUIRES(mLock); void addGlobalMonitoringTargetsLocked(std::vector<InputTarget>& inputTargets, ui::LogicalDisplayId displayId) REQUIRES(mLock); void pokeUserActivityLocked(const EventEntry& eventEntry) REQUIRES(mLock); @@ -652,9 +768,9 @@ private: std::string getApplicationWindowLabel(const InputApplicationHandle* applicationHandle, const sp<android::gui::WindowInfoHandle>& windowHandle); - bool shouldDropInput(const EventEntry& entry, - const sp<android::gui::WindowInfoHandle>& windowHandle) const - REQUIRES(mLock); + static bool shouldDropInput(const EventEntry& entry, + const sp<android::gui::WindowInfoHandle>& windowHandle, + const DispatcherWindowInfo& windowInfo); // Manage the dispatch cycle for a single connection. // These methods are deliberately not Interruptible because doing all of the work @@ -749,17 +865,6 @@ private: const std::shared_ptr<Connection>& connection, DispatchEntry* dispatchEntry, bool handled) REQUIRES(mLock); - // Find touched state and touched window by token. - static std::tuple<TouchState*, TouchedWindow*, ui::LogicalDisplayId> - findTouchStateWindowAndDisplay( - const sp<IBinder>& token, - std::unordered_map<ui::LogicalDisplayId, TouchState>& touchStatesByDisplay); - - static std::tuple<const TouchState*, const TouchedWindow*, ui::LogicalDisplayId> - findTouchStateWindowAndDisplay( - const sp<IBinder>& token, - const std::unordered_map<ui::LogicalDisplayId, TouchState>& touchStatesByDisplay); - // Statistics gathering. nsecs_t mLastStatisticPushTime = 0; std::unique_ptr<InputEventTimelineProcessor> mInputEventTimelineProcessor GUARDED_BY(mLock); @@ -774,33 +879,6 @@ private: sp<InputReporterInterface> mReporter; - /** - * Slip the wallpaper touch if necessary. - * - * @param targetFlags the target flags - * @param oldWindowHandle the old window that the touch slipped out of - * @param newWindowHandle the new window that the touch is slipping into - * @param state the current touch state. This will be updated if necessary to reflect the new - * windows that are receiving touch. - * @param deviceId the device id of the current motion being processed - * @param pointerProperties the pointer properties of the current motion being processed - * @param targets the current targets to add the walpaper ones to - * @param eventTime the new downTime for the wallpaper target - */ - void slipWallpaperTouch(ftl::Flags<InputTarget::Flags> targetFlags, - const sp<android::gui::WindowInfoHandle>& oldWindowHandle, - const sp<android::gui::WindowInfoHandle>& newWindowHandle, - TouchState& state, const MotionEntry& entry, - std::vector<InputTarget>& targets) const REQUIRES(mLock); - void transferWallpaperTouch(ftl::Flags<InputTarget::Flags> oldTargetFlags, - ftl::Flags<InputTarget::Flags> newTargetFlags, - const sp<android::gui::WindowInfoHandle> fromWindowHandle, - const sp<android::gui::WindowInfoHandle> toWindowHandle, - TouchState& state, DeviceId deviceId, - const std::vector<PointerProperties>& pointers, - const std::unique_ptr<trace::EventTrackerInterface>& traceTracker) - REQUIRES(mLock); - /** Stores the value of the input flag for per device input latency metrics. */ const bool mPerDeviceInputLatencyMetricsFlag = com::android::input::flags::enable_per_device_input_latency_metrics(); diff --git a/services/inputflinger/reader/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp index 013ef862ad..3c8b6f54c1 100644 --- a/services/inputflinger/reader/EventHub.cpp +++ b/services/inputflinger/reader/EventHub.cpp @@ -1620,41 +1620,43 @@ std::shared_ptr<const EventHub::AssociatedDevice> EventHub::obtainAssociatedDevi const auto& path = *sysfsRootPathOpt; - std::shared_ptr<const AssociatedDevice> associatedDevice = std::make_shared<AssociatedDevice>( - AssociatedDevice{.sysfsRootPath = path, - .batteryInfos = readBatteryConfiguration(path), - .lightInfos = readLightsConfiguration(path), - .layoutInfo = readLayoutConfiguration(path)}); - - bool associatedDeviceChanged = false; + std::shared_ptr<const AssociatedDevice> associatedDevice; for (const auto& [id, dev] : mDevices) { - if (dev->associatedDevice && dev->associatedDevice->sysfsRootPath == path) { - if (*associatedDevice != *dev->associatedDevice) { - associatedDeviceChanged = true; - dev->associatedDevice = associatedDevice; - } + if (!dev->associatedDevice || dev->associatedDevice->sysfsRootPath != path) { + continue; + } + if (!associatedDevice) { + // Found matching associated device for the first time. associatedDevice = dev->associatedDevice; + // Reload this associated device if needed. + const auto reloadedDevice = AssociatedDevice(path); + if (reloadedDevice != *dev->associatedDevice) { + ALOGI("The AssociatedDevice changed for path '%s'. Using new AssociatedDevice: %s", + path.c_str(), associatedDevice->dump().c_str()); + associatedDevice = std::make_shared<AssociatedDevice>(std::move(reloadedDevice)); + } } + // Update the associatedDevice. + dev->associatedDevice = associatedDevice; + } + + if (!associatedDevice) { + // No existing associated device found for this path, so create a new one. + associatedDevice = std::make_shared<AssociatedDevice>(path); } - ALOGI_IF(associatedDeviceChanged, - "The AssociatedDevice changed for path '%s'. Using new AssociatedDevice: %s", - path.c_str(), associatedDevice->dump().c_str()); return associatedDevice; } -bool EventHub::AssociatedDevice::isChanged() const { - std::unordered_map<int32_t, RawBatteryInfo> newBatteryInfos = - readBatteryConfiguration(sysfsRootPath); - std::unordered_map<int32_t, RawLightInfo> newLightInfos = - readLightsConfiguration(sysfsRootPath); - std::optional<RawLayoutInfo> newLayoutInfo = readLayoutConfiguration(sysfsRootPath); +EventHub::AssociatedDevice::AssociatedDevice(const std::filesystem::path& sysfsRootPath) + : sysfsRootPath(sysfsRootPath), + batteryInfos(readBatteryConfiguration(sysfsRootPath)), + lightInfos(readLightsConfiguration(sysfsRootPath)), + layoutInfo(readLayoutConfiguration(sysfsRootPath)) {} - if (newBatteryInfos == batteryInfos && newLightInfos == lightInfos && - newLayoutInfo == layoutInfo) { - return false; - } - return true; +std::string EventHub::AssociatedDevice::dump() const { + return StringPrintf("path=%s, numBatteries=%zu, numLight=%zu", sysfsRootPath.c_str(), + batteryInfos.size(), lightInfos.size()); } void EventHub::vibrate(int32_t deviceId, const VibrationElement& element) { @@ -2646,33 +2648,56 @@ status_t EventHub::disableDevice(int32_t deviceId) { void EventHub::sysfsNodeChanged(const std::string& sysfsNodePath) { std::scoped_lock _l(mLock); - // Check in opening devices - for (auto it = mOpeningDevices.begin(); it != mOpeningDevices.end(); it++) { - std::unique_ptr<Device>& device = *it; - if (device->associatedDevice && - sysfsNodePath.find(device->associatedDevice->sysfsRootPath.string()) != - std::string::npos && - device->associatedDevice->isChanged()) { - it = mOpeningDevices.erase(it); - openDeviceLocked(device->path); + // Testing whether a sysfs node changed involves several syscalls, so use a cache to avoid + // testing the same node multiple times. + std::map<std::shared_ptr<const AssociatedDevice>, bool /*changed*/> testedDevices; + auto isAssociatedDeviceChanged = [&testedDevices, &sysfsNodePath](const Device& dev) { + if (!dev.associatedDevice) { + return false; } - } + if (auto testedIt = testedDevices.find(dev.associatedDevice); + testedIt != testedDevices.end()) { + return testedIt->second; + } + // Cache miss + if (sysfsNodePath.find(dev.associatedDevice->sysfsRootPath.string()) == std::string::npos) { + testedDevices.emplace(dev.associatedDevice, false); + return false; + } + auto reloadedDevice = AssociatedDevice(dev.associatedDevice->sysfsRootPath); + const bool changed = *dev.associatedDevice != reloadedDevice; + testedDevices.emplace(dev.associatedDevice, changed); + return changed; + }; - // Check in already added device - std::vector<Device*> devicesToReopen; - for (const auto& [id, device] : mDevices) { - if (device->associatedDevice && - sysfsNodePath.find(device->associatedDevice->sysfsRootPath.string()) != - std::string::npos && - device->associatedDevice->isChanged()) { - devicesToReopen.push_back(device.get()); + std::set<Device*> devicesToClose; + std::set<std::string /*path*/> devicesToOpen; + + // Check in opening devices. If its associated device changed, + // the device should be removed from mOpeningDevices and needs to be opened again. + std::erase_if(mOpeningDevices, [&](const auto& dev) { + if (isAssociatedDeviceChanged(*dev)) { + devicesToOpen.emplace(dev->path); + return true; + } + return false; + }); + + // Check in already added device. If its associated device changed, + // the device needs to be re-opened. + for (const auto& [id, dev] : mDevices) { + if (isAssociatedDeviceChanged(*dev)) { + devicesToOpen.emplace(dev->path); + devicesToClose.emplace(dev.get()); } } - for (const auto& device : devicesToReopen) { + + for (auto* device : devicesToClose) { closeDeviceLocked(*device); - openDeviceLocked(device->path); } - devicesToReopen.clear(); + for (const auto& path : devicesToOpen) { + openDeviceLocked(path); + } } void EventHub::createVirtualKeyboardLocked() { @@ -2972,9 +2997,4 @@ void EventHub::monitor() const { std::unique_lock<std::mutex> lock(mLock); } -std::string EventHub::AssociatedDevice::dump() const { - return StringPrintf("path=%s, numBatteries=%zu, numLight=%zu", sysfsRootPath.c_str(), - batteryInfos.size(), lightInfos.size()); -} - } // namespace android diff --git a/services/inputflinger/reader/include/EventHub.h b/services/inputflinger/reader/include/EventHub.h index 5839b4c41c..31ac63f31e 100644 --- a/services/inputflinger/reader/include/EventHub.h +++ b/services/inputflinger/reader/include/EventHub.h @@ -619,13 +619,13 @@ public: private: // Holds information about the sysfs device associated with the Device. struct AssociatedDevice { + AssociatedDevice(const std::filesystem::path& sysfsRootPath); // The sysfs root path of the misc device. std::filesystem::path sysfsRootPath; std::unordered_map<int32_t /*batteryId*/, RawBatteryInfo> batteryInfos; std::unordered_map<int32_t /*lightId*/, RawLightInfo> lightInfos; std::optional<RawLayoutInfo> layoutInfo; - bool isChanged() const; bool operator==(const AssociatedDevice&) const = default; bool operator!=(const AssociatedDevice&) const = default; std::string dump() const; diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.h b/services/inputflinger/reader/mapper/CursorInputMapper.h index 301632ff7a..f2b2b6f2a8 100644 --- a/services/inputflinger/reader/mapper/CursorInputMapper.h +++ b/services/inputflinger/reader/mapper/CursorInputMapper.h @@ -115,6 +115,7 @@ private: ui::Rotation mOrientation{ui::ROTATION_0}; FloatRect mBoundsInLogicalDisplay{}; + // The button state as of the last sync. int32_t mButtonState; nsecs_t mDownTime; nsecs_t mLastEventTime; diff --git a/services/inputflinger/rust/Android.bp b/services/inputflinger/rust/Android.bp index 5b7cc2d432..78674e5a0c 100644 --- a/services/inputflinger/rust/Android.bp +++ b/services/inputflinger/rust/Android.bp @@ -40,14 +40,14 @@ rust_defaults { crate_name: "inputflinger", srcs: ["lib.rs"], rustlibs: [ - "libcxx", - "com.android.server.inputflinger-rust", "android.hardware.input.common-V1-rust", + "com.android.server.inputflinger-rust", "libbinder_rs", + "libcxx", + "libinput_rust", "liblog_rust", "liblogger", "libnix", - "libinput_rust", ], host_supported: true, } diff --git a/services/inputflinger/tests/GestureConverter_test.cpp b/services/inputflinger/tests/GestureConverter_test.cpp index fd9884b234..914f5abdbd 100644 --- a/services/inputflinger/tests/GestureConverter_test.cpp +++ b/services/inputflinger/tests/GestureConverter_test.cpp @@ -1721,15 +1721,16 @@ protected: mParamContinueGesture(std::get<1>(GetParam())), mParamEndGesture(std::get<2>(GetParam())), mDeviceContext(*mDevice, EVENTHUB_ID), - mConverter(*mReader->getContext(), mDeviceContext, DEVICE_ID), - mVerifier("Test verifier") { + mConverter(*mReader->getContext(), mDeviceContext, DEVICE_ID) { mConverter.setDisplayId(ui::LogicalDisplayId::DEFAULT); + input_flags::enable_button_state_verification(true); + mVerifier = std::make_unique<InputVerifier>("Test verifier"); } base::Result<void> processMotionArgs(NotifyMotionArgs arg) { - return mVerifier.processMovement(arg.deviceId, arg.source, arg.action, - arg.getPointerCount(), arg.pointerProperties.data(), - arg.pointerCoords.data(), arg.flags); + return mVerifier->processMovement(arg.deviceId, arg.source, arg.action, arg.actionButton, + arg.getPointerCount(), arg.pointerProperties.data(), + arg.pointerCoords.data(), arg.flags, arg.buttonState); } void verifyArgsFromGesture(const Gesture& gesture, size_t gestureIndex) { @@ -1755,7 +1756,7 @@ protected: InputDeviceContext mDeviceContext; GestureConverter mConverter; - InputVerifier mVerifier; + std::unique_ptr<InputVerifier> mVerifier; }; TEST_P(GestureConverterConsistencyTest, ButtonChangesDuringGesture) { diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index 368db1b5c4..7cc4ff76b8 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -9959,57 +9959,63 @@ TEST_F_WITH_FLAGS( InputDispatcherUserActivityPokeTests, MinPokeTimeObserved, REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(com::android::input::flags, rate_limit_user_activity_poke_in_dispatcher))) { + // Use current time otherwise events may be dropped due to being stale. + const nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC); + mDispatcher->setMinTimeBetweenUserActivityPokes(50ms); // First event of type TOUCH. Should poke. notifyAndConsumeMotion(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ui::LogicalDisplayId::DEFAULT, - milliseconds_to_nanoseconds(50)); + currentTime + milliseconds_to_nanoseconds(50)); mFakePolicy->assertUserActivityPoked( - {{milliseconds_to_nanoseconds(50), USER_ACTIVITY_EVENT_TOUCH, + {{currentTime + milliseconds_to_nanoseconds(50), USER_ACTIVITY_EVENT_TOUCH, ui::LogicalDisplayId::DEFAULT}}); // 80ns > 50ns has passed since previous TOUCH event. Should poke. notifyAndConsumeMotion(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, ui::LogicalDisplayId::DEFAULT, - milliseconds_to_nanoseconds(130)); + currentTime + milliseconds_to_nanoseconds(130)); mFakePolicy->assertUserActivityPoked( - {{milliseconds_to_nanoseconds(130), USER_ACTIVITY_EVENT_TOUCH, + {{currentTime + milliseconds_to_nanoseconds(130), USER_ACTIVITY_EVENT_TOUCH, ui::LogicalDisplayId::DEFAULT}}); // First event of type OTHER. Should poke (despite being within 50ns of previous TOUCH event). notifyAndConsumeMotion(ACTION_SCROLL, AINPUT_SOURCE_ROTARY_ENCODER, - ui::LogicalDisplayId::DEFAULT, milliseconds_to_nanoseconds(135)); + ui::LogicalDisplayId::DEFAULT, + currentTime + milliseconds_to_nanoseconds(135)); mFakePolicy->assertUserActivityPoked( - {{milliseconds_to_nanoseconds(135), USER_ACTIVITY_EVENT_OTHER, + {{currentTime + milliseconds_to_nanoseconds(135), USER_ACTIVITY_EVENT_OTHER, ui::LogicalDisplayId::DEFAULT}}); // Within 50ns of previous TOUCH event. Should NOT poke. notifyAndConsumeMotion(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, ui::LogicalDisplayId::DEFAULT, - milliseconds_to_nanoseconds(140)); + currentTime + milliseconds_to_nanoseconds(140)); mFakePolicy->assertUserActivityNotPoked(); // Within 50ns of previous OTHER event. Should NOT poke. notifyAndConsumeMotion(ACTION_SCROLL, AINPUT_SOURCE_ROTARY_ENCODER, - ui::LogicalDisplayId::DEFAULT, milliseconds_to_nanoseconds(150)); + ui::LogicalDisplayId::DEFAULT, + currentTime + milliseconds_to_nanoseconds(150)); mFakePolicy->assertUserActivityNotPoked(); // Within 50ns of previous TOUCH event (which was at time 130). Should NOT poke. // Note that STYLUS is mapped to TOUCH user activity, since it's a pointer-type source. notifyAndConsumeMotion(ACTION_DOWN, AINPUT_SOURCE_STYLUS, ui::LogicalDisplayId::DEFAULT, - milliseconds_to_nanoseconds(160)); + currentTime + milliseconds_to_nanoseconds(160)); mFakePolicy->assertUserActivityNotPoked(); // 65ns > 50ns has passed since previous OTHER event. Should poke. notifyAndConsumeMotion(ACTION_SCROLL, AINPUT_SOURCE_ROTARY_ENCODER, - ui::LogicalDisplayId::DEFAULT, milliseconds_to_nanoseconds(200)); + ui::LogicalDisplayId::DEFAULT, + currentTime + milliseconds_to_nanoseconds(200)); mFakePolicy->assertUserActivityPoked( - {{milliseconds_to_nanoseconds(200), USER_ACTIVITY_EVENT_OTHER, + {{currentTime + milliseconds_to_nanoseconds(200), USER_ACTIVITY_EVENT_OTHER, ui::LogicalDisplayId::DEFAULT}}); // 170ns > 50ns has passed since previous TOUCH event. Should poke. notifyAndConsumeMotion(ACTION_UP, AINPUT_SOURCE_STYLUS, ui::LogicalDisplayId::DEFAULT, - milliseconds_to_nanoseconds(300)); + currentTime + milliseconds_to_nanoseconds(300)); mFakePolicy->assertUserActivityPoked( - {{milliseconds_to_nanoseconds(300), USER_ACTIVITY_EVENT_TOUCH, + {{currentTime + milliseconds_to_nanoseconds(300), USER_ACTIVITY_EVENT_TOUCH, ui::LogicalDisplayId::DEFAULT}}); // Assert that there's no more user activity poke event. @@ -10020,20 +10026,22 @@ TEST_F_WITH_FLAGS( InputDispatcherUserActivityPokeTests, DefaultMinPokeTimeOf100MsUsed, REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(com::android::input::flags, rate_limit_user_activity_poke_in_dispatcher))) { + // Use current time otherwise events may be dropped due to being stale. + const nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC); notifyAndConsumeMotion(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ui::LogicalDisplayId::DEFAULT, - milliseconds_to_nanoseconds(200)); + currentTime + milliseconds_to_nanoseconds(200)); mFakePolicy->assertUserActivityPoked( - {{milliseconds_to_nanoseconds(200), USER_ACTIVITY_EVENT_TOUCH, + {{currentTime + milliseconds_to_nanoseconds(200), USER_ACTIVITY_EVENT_TOUCH, ui::LogicalDisplayId::DEFAULT}}); notifyAndConsumeMotion(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, ui::LogicalDisplayId::DEFAULT, - milliseconds_to_nanoseconds(280)); + currentTime + milliseconds_to_nanoseconds(280)); mFakePolicy->assertUserActivityNotPoked(); notifyAndConsumeMotion(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, ui::LogicalDisplayId::DEFAULT, - milliseconds_to_nanoseconds(340)); + currentTime + milliseconds_to_nanoseconds(340)); mFakePolicy->assertUserActivityPoked( - {{milliseconds_to_nanoseconds(340), USER_ACTIVITY_EVENT_TOUCH, + {{currentTime + milliseconds_to_nanoseconds(340), USER_ACTIVITY_EVENT_TOUCH, ui::LogicalDisplayId::DEFAULT}}); } @@ -10041,14 +10049,16 @@ TEST_F_WITH_FLAGS( InputDispatcherUserActivityPokeTests, ZeroMinPokeTimeDisablesRateLimiting, REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(com::android::input::flags, rate_limit_user_activity_poke_in_dispatcher))) { + // Use current time otherwise events may be dropped due to being stale. + const nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC); mDispatcher->setMinTimeBetweenUserActivityPokes(0ms); notifyAndConsumeMotion(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ui::LogicalDisplayId::DEFAULT, - 20); + currentTime + 20); mFakePolicy->assertUserActivityPoked(); notifyAndConsumeMotion(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, ui::LogicalDisplayId::DEFAULT, - 30); + currentTime + 30); mFakePolicy->assertUserActivityPoked(); } @@ -12395,43 +12405,69 @@ protected: } void injectDown(int fromSource = AINPUT_SOURCE_TOUCHSCREEN) { + bool consumeButtonPress = false; switch (fromSource) { - case AINPUT_SOURCE_TOUCHSCREEN: + case AINPUT_SOURCE_TOUCHSCREEN: { ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ui::LogicalDisplayId::DEFAULT, {50, 50})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; break; - case AINPUT_SOURCE_STYLUS: + } + case AINPUT_SOURCE_STYLUS: { + PointerBuilder pointer = PointerBuilder(0, ToolType::STYLUS).x(50).y(50); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_STYLUS) .buttonState( AMOTION_EVENT_BUTTON_STYLUS_PRIMARY) - .pointer(PointerBuilder(0, ToolType::STYLUS) - .x(50) - .y(50)) + .pointer(pointer) + .build())); + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionEvent(*mDispatcher, + MotionEventBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, + AINPUT_SOURCE_STYLUS) + .actionButton( + AMOTION_EVENT_BUTTON_STYLUS_PRIMARY) + .buttonState( + AMOTION_EVENT_BUTTON_STYLUS_PRIMARY) + .pointer(pointer) .build())); + consumeButtonPress = true; break; - case AINPUT_SOURCE_MOUSE: + } + case AINPUT_SOURCE_MOUSE: { + PointerBuilder pointer = + PointerBuilder(MOUSE_POINTER_ID, ToolType::MOUSE).x(50).y(50); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_MOUSE) .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) - .pointer(PointerBuilder(MOUSE_POINTER_ID, - ToolType::MOUSE) - .x(50) - .y(50)) + .pointer(pointer) .build())); + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionEvent(*mDispatcher, + MotionEventBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, + AINPUT_SOURCE_MOUSE) + .actionButton(AMOTION_EVENT_BUTTON_PRIMARY) + .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) + .pointer(pointer) + .build())); + consumeButtonPress = true; break; - default: + } + default: { FAIL() << "Source " << fromSource << " doesn't support drag and drop"; + } } // Window should receive motion event. mWindow->consumeMotionDown(ui::LogicalDisplayId::DEFAULT); + if (consumeButtonPress) { + mWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS)); + } // Spy window should also receive motion event mSpyWindow->consumeMotionDown(ui::LogicalDisplayId::DEFAULT); } @@ -12631,6 +12667,16 @@ TEST_F(InputDispatcherDragTests, StylusDragAndDrop) { // Move to another window and release button, expect to drop item. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionEvent(*mDispatcher, + MotionEventBuilder(AMOTION_EVENT_ACTION_BUTTON_RELEASE, + AINPUT_SOURCE_STYLUS) + .actionButton(AMOTION_EVENT_BUTTON_STYLUS_PRIMARY) + .buttonState(0) + .pointer(PointerBuilder(0, ToolType::STYLUS).x(150).y(50)) + .build())) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + mDragWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE)); + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_STYLUS) .buttonState(0) .pointer(PointerBuilder(0, ToolType::STYLUS).x(150).y(50)) @@ -12872,6 +12918,18 @@ TEST_F(InputDispatcherDragTests, MouseDragAndDrop) { // drop to another window. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionEvent(*mDispatcher, + MotionEventBuilder(AMOTION_EVENT_ACTION_BUTTON_RELEASE, + AINPUT_SOURCE_MOUSE) + .actionButton(AMOTION_EVENT_BUTTON_PRIMARY) + .buttonState(0) + .pointer(PointerBuilder(MOUSE_POINTER_ID, ToolType::MOUSE) + .x(150) + .y(50)) + .build())) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + mDragWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE)); + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_MOUSE) .buttonState(0) .pointer(PointerBuilder(MOUSE_POINTER_ID, ToolType::MOUSE) diff --git a/services/inputflinger/tests/PointerChoreographer_test.cpp b/services/inputflinger/tests/PointerChoreographer_test.cpp index 1ca2998f6b..1286a3675c 100644 --- a/services/inputflinger/tests/PointerChoreographer_test.cpp +++ b/services/inputflinger/tests/PointerChoreographer_test.cpp @@ -2617,12 +2617,17 @@ public: static constexpr ui::LogicalDisplayId DISPLAY_BOTTOM_ID = ui::LogicalDisplayId{40}; static constexpr ui::LogicalDisplayId DISPLAY_LEFT_ID = ui::LogicalDisplayId{50}; static constexpr ui::LogicalDisplayId DISPLAY_TOP_RIGHT_CORNER_ID = ui::LogicalDisplayId{60}; + static constexpr ui::LogicalDisplayId DISPLAY_HIGH_DENSITY_ID = ui::LogicalDisplayId{70}; + + static constexpr int DENSITY_MEDIUM = 160; + static constexpr int DENSITY_HIGH = 320; PointerChoreographerDisplayTopologyTestFixture() { com::android::input::flags::connected_displays_cursor(true); } protected: + // Note: viewport size is in pixels and offsets in topology are in dp std::vector<DisplayViewport> mViewports{ createViewport(DISPLAY_CENTER_ID, /*width*/ 100, /*height*/ 100, ui::ROTATION_0), createViewport(DISPLAY_TOP_ID, /*width*/ 90, /*height*/ 90, ui::ROTATION_0), @@ -2631,16 +2636,28 @@ protected: createViewport(DISPLAY_LEFT_ID, /*width*/ 90, /*height*/ 90, ui::ROTATION_270), createViewport(DISPLAY_TOP_RIGHT_CORNER_ID, /*width*/ 90, /*height*/ 90, ui::ROTATION_0), + // Create a high density display size 100x100 dp i.e. 200x200 px + createViewport(DISPLAY_HIGH_DENSITY_ID, /*width*/ 200, /*height*/ 200, ui::ROTATION_0), }; - DisplayTopologyGraph mTopology{DISPLAY_CENTER_ID, - {{DISPLAY_CENTER_ID, - {{DISPLAY_TOP_ID, DisplayTopologyPosition::TOP, 10.0f}, - {DISPLAY_RIGHT_ID, DisplayTopologyPosition::RIGHT, 10.0f}, - {DISPLAY_BOTTOM_ID, DisplayTopologyPosition::BOTTOM, 10.0f}, - {DISPLAY_LEFT_ID, DisplayTopologyPosition::LEFT, 10.0f}, - {DISPLAY_TOP_RIGHT_CORNER_ID, DisplayTopologyPosition::RIGHT, - -90.0f}}}}}; + DisplayTopologyGraph + mTopology{DISPLAY_CENTER_ID, + {{DISPLAY_CENTER_ID, + {{DISPLAY_TOP_ID, DisplayTopologyPosition::TOP, 50.0f}, + // Place a high density display on the left of DISPLAY_TOP_ID with 25 dp + // gap + {DISPLAY_HIGH_DENSITY_ID, DisplayTopologyPosition::TOP, -75.0f}, + {DISPLAY_RIGHT_ID, DisplayTopologyPosition::RIGHT, 10.0f}, + {DISPLAY_BOTTOM_ID, DisplayTopologyPosition::BOTTOM, 10.0f}, + {DISPLAY_LEFT_ID, DisplayTopologyPosition::LEFT, 10.0f}, + {DISPLAY_TOP_RIGHT_CORNER_ID, DisplayTopologyPosition::RIGHT, -90.0f}}}}, + {{DISPLAY_CENTER_ID, DENSITY_MEDIUM}, + {DISPLAY_TOP_ID, DENSITY_MEDIUM}, + {DISPLAY_RIGHT_ID, DENSITY_MEDIUM}, + {DISPLAY_BOTTOM_ID, DENSITY_MEDIUM}, + {DISPLAY_LEFT_ID, DENSITY_MEDIUM}, + {DISPLAY_TOP_RIGHT_CORNER_ID, DENSITY_MEDIUM}, + {DISPLAY_HIGH_DENSITY_ID, DENSITY_HIGH}}}; private: DisplayViewport createViewport(ui::LogicalDisplayId displayId, int32_t width, int32_t height, @@ -2731,7 +2748,7 @@ INSTANTIATE_TEST_SUITE_P( ToolType::FINGER, vec2(50, 50) /* initial x/y */, vec2(25, -100) /* delta x/y */, PointerChoreographerDisplayTopologyTestFixture::DISPLAY_TOP_ID, - vec2(50 + 25 - 10, + vec2(50 + 25 - 50, 90) /* Bottom edge: (source + delta - offset, height) */), std::make_tuple("TransitionToBottomDisplay", AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD, ControllerType::MOUSE, @@ -2739,11 +2756,12 @@ INSTANTIATE_TEST_SUITE_P( vec2(25, 100) /* delta x/y */, PointerChoreographerDisplayTopologyTestFixture::DISPLAY_BOTTOM_ID, vec2(50 + 25 - 10, 0) /* Top edge: (source + delta - offset, 0) */), + // move towards 25 dp gap between DISPLAY_HIGH_DENSITY_ID and DISPLAY_TOP_ID std::make_tuple("NoTransitionAtTopOffset", AINPUT_SOURCE_MOUSE, ControllerType::MOUSE, ToolType::MOUSE, - vec2(5, 50) /* initial x/y */, vec2(0, -100) /* Move Up */, + vec2(35, 50) /* initial x/y */, vec2(0, -100) /* Move Up */, PointerChoreographerDisplayTopologyTestFixture::DISPLAY_CENTER_ID, - vec2(5, 0) /* Top edge */), + vec2(35, 0) /* Top edge */), std::make_tuple("NoTransitionAtRightOffset", AINPUT_SOURCE_MOUSE, ControllerType::MOUSE, ToolType::MOUSE, vec2(95, 5) /* initial x/y */, vec2(100, 0) /* Move Right */, @@ -2764,9 +2782,16 @@ INSTANTIATE_TEST_SUITE_P( std::make_tuple( "TransitionAtTopRightCorner", AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD, ControllerType::MOUSE, ToolType::FINGER, vec2(95, 5) /* initial x/y */, - vec2(10, -10) /* Move dignally to top right corner */, + vec2(10, -10) /* Move diagonally to top right corner */, PointerChoreographerDisplayTopologyTestFixture::DISPLAY_TOP_RIGHT_CORNER_ID, - vec2(0, 90) /* bottom left corner */)), + vec2(0, 90) /* bottom left corner */), + std::make_tuple( + "TransitionToHighDpDisplay", AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD, + ControllerType::MOUSE, ToolType::MOUSE, vec2(20, 20) /* initial x/y */, + vec2(0, -50) /* delta x/y */, + PointerChoreographerDisplayTopologyTestFixture::DISPLAY_HIGH_DENSITY_ID, + /* Bottom edge: ((source + delta - offset) * density, height) */ + vec2((20 + 0 + 75) * 2, 200))), [](const testing::TestParamInfo<PointerChoreographerDisplayTopologyTestFixtureParam>& p) { return std::string{std::get<0>(p.param)}; }); diff --git a/services/inputflinger/tests/fuzzers/Android.bp b/services/inputflinger/tests/fuzzers/Android.bp index 48e19546c5..5000db7d9a 100644 --- a/services/inputflinger/tests/fuzzers/Android.bp +++ b/services/inputflinger/tests/fuzzers/Android.bp @@ -33,8 +33,8 @@ cc_defaults { "frameworks/native/services/inputflinger", ], shared_libs: [ - "libinputreader", "libinputflinger_base", + "libinputreader", ], sanitize: { hwaddress: true, diff --git a/services/inputflinger/tests/fuzzers/InputDispatcherFuzzer.cpp b/services/inputflinger/tests/fuzzers/InputDispatcherFuzzer.cpp index 31db2fedc7..abce931eff 100644 --- a/services/inputflinger/tests/fuzzers/InputDispatcherFuzzer.cpp +++ b/services/inputflinger/tests/fuzzers/InputDispatcherFuzzer.cpp @@ -48,9 +48,9 @@ public: auto [it, _] = mVerifiers.emplace(args.displayId, "Fuzz Verifier"); InputVerifier& verifier = it->second; const Result<void> result = - verifier.processMovement(args.deviceId, args.source, args.action, + verifier.processMovement(args.deviceId, args.source, args.action, args.actionButton, args.getPointerCount(), args.pointerProperties.data(), - args.pointerCoords.data(), args.flags); + args.pointerCoords.data(), args.flags, args.buttonState); if (result.ok()) { return args; } diff --git a/services/powermanager/benchmarks/PowerHalAidlBenchmarks.cpp b/services/powermanager/benchmarks/PowerHalAidlBenchmarks.cpp index 61ab47a75a..3a1b426520 100644 --- a/services/powermanager/benchmarks/PowerHalAidlBenchmarks.cpp +++ b/services/powermanager/benchmarks/PowerHalAidlBenchmarks.cpp @@ -40,10 +40,10 @@ using namespace android; using namespace std::chrono_literals; // Values from Boost.aidl and Mode.aidl. -static constexpr int64_t FIRST_BOOST = static_cast<int64_t>(Boost::INTERACTION); -static constexpr int64_t LAST_BOOST = static_cast<int64_t>(Boost::CAMERA_SHOT); -static constexpr int64_t FIRST_MODE = static_cast<int64_t>(Mode::DOUBLE_TAP_TO_WAKE); -static constexpr int64_t LAST_MODE = static_cast<int64_t>(Mode::CAMERA_STREAMING_HIGH); +static constexpr int64_t FIRST_BOOST = static_cast<int64_t>(*ndk::enum_range<Boost>().begin()); +static constexpr int64_t LAST_BOOST = static_cast<int64_t>(*(ndk::enum_range<Boost>().end()-1)); +static constexpr int64_t FIRST_MODE = static_cast<int64_t>(*ndk::enum_range<Mode>().begin()); +static constexpr int64_t LAST_MODE = static_cast<int64_t>(*(ndk::enum_range<Mode>().end()-1)); class DurationWrapper : public WorkDuration { public: @@ -81,14 +81,17 @@ static void runBenchmark(benchmark::State& state, microseconds delay, R (IPower: return; } - while (state.KeepRunning()) { + for (auto _ : state) { ret = (*hal.*fn)(std::forward<Args1>(args1)...); - state.PauseTiming(); - if (!ret.isOk()) state.SkipWithError(ret.getDescription().c_str()); + if (!ret.isOk()) { + state.SkipWithError(ret.getDescription().c_str()); + break; + } if (delay > 0us) { + state.PauseTiming(); testDelaySpin(std::chrono::duration_cast<std::chrono::duration<float>>(delay).count()); + state.ResumeTiming(); } - state.ResumeTiming(); } } @@ -123,14 +126,15 @@ static void runSessionBenchmark(benchmark::State& state, R (IPowerHintSession::* return; } - while (state.KeepRunning()) { + for (auto _ : state) { ret = (*session.*fn)(std::forward<Args1>(args1)...); - state.PauseTiming(); - if (!ret.isOk()) state.SkipWithError(ret.getDescription().c_str()); - if (ONEWAY_API_DELAY > 0us) { - testDelaySpin(std::chrono::duration_cast<std::chrono::duration<float>>(ONEWAY_API_DELAY) - .count()); + if (!ret.isOk()) { + state.SkipWithError(ret.getDescription().c_str()); + break; } + state.PauseTiming(); + testDelaySpin(std::chrono::duration_cast<std::chrono::duration<float>>(ONEWAY_API_DELAY) + .count()); state.ResumeTiming(); } session->close(); @@ -150,11 +154,41 @@ static void BM_PowerHalAidlBenchmarks_isModeSupported(benchmark::State& state) { static void BM_PowerHalAidlBenchmarks_setBoost(benchmark::State& state) { Boost boost = static_cast<Boost>(state.range(0)); + bool isSupported; + std::shared_ptr<IPower> hal = PowerHalLoader::loadAidl(); + + if (hal == nullptr) { + ALOGV("Power HAL not available, skipping test..."); + state.SkipWithMessage("Power HAL unavailable"); + return; + } + + ndk::ScopedAStatus ret = hal->isBoostSupported(boost, &isSupported); + if (!ret.isOk() || !isSupported) { + state.SkipWithMessage("operation unsupported"); + return; + } + runBenchmark(state, ONEWAY_API_DELAY, &IPower::setBoost, boost, 1); } static void BM_PowerHalAidlBenchmarks_setMode(benchmark::State& state) { Mode mode = static_cast<Mode>(state.range(0)); + bool isSupported; + std::shared_ptr<IPower> hal = PowerHalLoader::loadAidl(); + + if (hal == nullptr) { + ALOGV("Power HAL not available, skipping test..."); + state.SkipWithMessage("Power HAL unavailable"); + return; + } + + ndk::ScopedAStatus ret = hal->isModeSupported(mode, &isSupported); + if (!ret.isOk() || !isSupported) { + state.SkipWithMessage("operation unsupported"); + return; + } + runBenchmark(state, ONEWAY_API_DELAY, &IPower::setMode, mode, false); } @@ -178,12 +212,20 @@ static void BM_PowerHalAidlBenchmarks_createHintSession(benchmark::State& state) ALOGV("Power HAL does not support this operation, skipping test..."); state.SkipWithMessage("operation unsupported"); return; + } else if (!ret.isOk()) { + state.SkipWithError(ret.getDescription().c_str()); + return; + } else { + appSession->close(); } - while (state.KeepRunning()) { + for (auto _ : state) { ret = hal->createHintSession(tgid, uid, threadIds, durationNanos, &appSession); + if (!ret.isOk()) { + state.SkipWithError(ret.getDescription().c_str()); + break; + } state.PauseTiming(); - if (!ret.isOk()) state.SkipWithError(ret.getDescription().c_str()); appSession->close(); state.ResumeTiming(); } diff --git a/services/powermanager/benchmarks/PowerHalControllerBenchmarks.cpp b/services/powermanager/benchmarks/PowerHalControllerBenchmarks.cpp index effddda6a4..0fda686231 100644 --- a/services/powermanager/benchmarks/PowerHalControllerBenchmarks.cpp +++ b/services/powermanager/benchmarks/PowerHalControllerBenchmarks.cpp @@ -19,9 +19,9 @@ #include <aidl/android/hardware/power/Boost.h> #include <aidl/android/hardware/power/Mode.h> #include <benchmark/benchmark.h> +#include <chrono> #include <powermanager/PowerHalController.h> #include <testUtil.h> -#include <chrono> using aidl::android::hardware::power::Boost; using aidl::android::hardware::power::Mode; @@ -32,10 +32,10 @@ using namespace android; using namespace std::chrono_literals; // Values from Boost.aidl and Mode.aidl. -static constexpr int64_t FIRST_BOOST = static_cast<int64_t>(Boost::INTERACTION); -static constexpr int64_t LAST_BOOST = static_cast<int64_t>(Boost::CAMERA_SHOT); -static constexpr int64_t FIRST_MODE = static_cast<int64_t>(Mode::DOUBLE_TAP_TO_WAKE); -static constexpr int64_t LAST_MODE = static_cast<int64_t>(Mode::CAMERA_STREAMING_HIGH); +static constexpr int64_t FIRST_BOOST = static_cast<int64_t>(*ndk::enum_range<Boost>().begin()); +static constexpr int64_t LAST_BOOST = static_cast<int64_t>(*(ndk::enum_range<Boost>().end()-1)); +static constexpr int64_t FIRST_MODE = static_cast<int64_t>(*ndk::enum_range<Mode>().begin()); +static constexpr int64_t LAST_MODE = static_cast<int64_t>(*(ndk::enum_range<Mode>().end()-1)); // Delay between oneway method calls to avoid overflowing the binder buffers. static constexpr std::chrono::microseconds ONEWAY_API_DELAY = 100us; @@ -43,11 +43,27 @@ static constexpr std::chrono::microseconds ONEWAY_API_DELAY = 100us; template <typename T, class... Args0, class... Args1> static void runBenchmark(benchmark::State& state, HalResult<T> (PowerHalController::*fn)(Args0...), Args1&&... args1) { - while (state.KeepRunning()) { - PowerHalController controller; + PowerHalController initController; + HalResult<T> result = (initController.*fn)(std::forward<Args1>(args1)...); + if (result.isFailed()) { + state.SkipWithError(result.errorMessage()); + return; + } else if (result.isUnsupported()) { + ALOGV("Power HAL does not support this operation, skipping test..."); + state.SkipWithMessage("operation unsupported"); + return; + } + + for (auto _ : state) { + PowerHalController controller; // new controller to avoid caching HalResult<T> ret = (controller.*fn)(std::forward<Args1>(args1)...); + if (ret.isFailed()) { + state.SkipWithError(ret.errorMessage()); + break; + } state.PauseTiming(); - if (ret.isFailed()) state.SkipWithError("Power HAL request failed"); + testDelaySpin( + std::chrono::duration_cast<std::chrono::duration<float>>(ONEWAY_API_DELAY).count()); state.ResumeTiming(); } } @@ -57,22 +73,27 @@ static void runCachedBenchmark(benchmark::State& state, HalResult<T> (PowerHalController::*fn)(Args0...), Args1&&... args1) { PowerHalController controller; // First call out of test, to cache HAL service and isSupported result. - (controller.*fn)(std::forward<Args1>(args1)...); + HalResult<T> result = (controller.*fn)(std::forward<Args1>(args1)...); + if (result.isFailed()) { + state.SkipWithError(result.errorMessage()); + return; + } else if (result.isUnsupported()) { + ALOGV("Power HAL does not support this operation, skipping test..."); + state.SkipWithMessage("operation unsupported"); + return; + } - while (state.KeepRunning()) { + for (auto _ : state) { HalResult<T> ret = (controller.*fn)(std::forward<Args1>(args1)...); - state.PauseTiming(); if (ret.isFailed()) { - state.SkipWithError("Power HAL request failed"); + state.SkipWithError(ret.errorMessage()); + break; } - testDelaySpin( - std::chrono::duration_cast<std::chrono::duration<float>>(ONEWAY_API_DELAY).count()); - state.ResumeTiming(); } } static void BM_PowerHalControllerBenchmarks_init(benchmark::State& state) { - while (state.KeepRunning()) { + for (auto _ : state) { PowerHalController controller; controller.init(); } @@ -90,12 +111,12 @@ static void BM_PowerHalControllerBenchmarks_initCached(benchmark::State& state) static void BM_PowerHalControllerBenchmarks_setBoost(benchmark::State& state) { Boost boost = static_cast<Boost>(state.range(0)); - runBenchmark(state, &PowerHalController::setBoost, boost, 0); + runBenchmark(state, &PowerHalController::setBoost, boost, 1); } static void BM_PowerHalControllerBenchmarks_setBoostCached(benchmark::State& state) { Boost boost = static_cast<Boost>(state.range(0)); - runCachedBenchmark(state, &PowerHalController::setBoost, boost, 0); + runCachedBenchmark(state, &PowerHalController::setBoost, boost, 1); } static void BM_PowerHalControllerBenchmarks_setMode(benchmark::State& state) { diff --git a/services/powermanager/benchmarks/PowerHalHidlBenchmarks.cpp b/services/powermanager/benchmarks/PowerHalHidlBenchmarks.cpp index bcb376b799..95fd0c2a4d 100644 --- a/services/powermanager/benchmarks/PowerHalHidlBenchmarks.cpp +++ b/services/powermanager/benchmarks/PowerHalHidlBenchmarks.cpp @@ -54,14 +54,17 @@ static void runBenchmark(benchmark::State& state, microseconds delay, Return<R> return; } - while (state.KeepRunning()) { + for (auto _ : state) { Return<R> ret = (*hal.*fn)(std::forward<Args1>(args1)...); - state.PauseTiming(); - if (!ret.isOk()) state.SkipWithError(ret.description().c_str()); + if (!ret.isOk()) { + state.SkipWithError(ret.description().c_str()); + break; + } if (delay > 0us) { + state.PauseTiming(); testDelaySpin(std::chrono::duration_cast<std::chrono::duration<float>>(delay).count()); + state.ResumeTiming(); } - state.ResumeTiming(); } } diff --git a/services/sensorservice/Android.bp b/services/sensorservice/Android.bp index 8c80dd8ac8..9ecd101326 100644 --- a/services/sensorservice/Android.bp +++ b/services/sensorservice/Android.bp @@ -11,7 +11,7 @@ aconfig_declarations { name: "sensorservice_flags", package: "com.android.frameworks.sensorservice.flags", container: "system", - srcs: ["senserservice_flags.aconfig"], + srcs: ["sensorservice_flags.aconfig"], } cc_aconfig_library { @@ -61,38 +61,38 @@ cc_library { ], shared_libs: [ + "android.hardware.common-V2-ndk", + "android.hardware.common.fmq-V1-ndk", + "android.hardware.sensors@1.0", + "android.hardware.sensors@2.0", + "android.hardware.sensors@2.1", + "libaconfig_storage_read_api_cc", + "libactivitymanager_aidl", + "libbase", + "libbatterystats_aidl", + "libbinder", + "libbinder_ndk", + "libcrypto", "libcutils", + "libfmq", "libhardware", "libhardware_legacy", - "libutils", + "libhidlbase", "liblog", - "libactivitymanager_aidl", - "libbatterystats_aidl", - "libbinder", - "libsensor", - "libsensorprivacy", "libpermission", "libprotoutil", - "libcrypto", - "libbase", - "libhidlbase", - "libfmq", - "libbinder_ndk", + "libsensor", + "libsensorprivacy", + "libutils", "packagemanager_aidl-cpp", - "android.hardware.sensors@1.0", - "android.hardware.sensors@2.0", - "android.hardware.sensors@2.1", - "android.hardware.common-V2-ndk", - "android.hardware.common.fmq-V1-ndk", "server_configurable_flags", - "libaconfig_storage_read_api_cc", ], static_libs: [ - "libaidlcommonsupport", - "android.hardware.sensors@1.0-convert", "android.hardware.sensors-V1-convert", "android.hardware.sensors-V3-ndk", + "android.hardware.sensors@1.0-convert", + "libaidlcommonsupport", "sensorservice_flags_c_lib", ], @@ -100,9 +100,9 @@ cc_library { export_shared_lib_headers: [ "libactivitymanager_aidl", + "libpermission", "libsensor", "libsensorprivacy", - "libpermission", ], afdo: true, @@ -120,9 +120,9 @@ cc_binary { srcs: ["main_sensorservice.cpp"], shared_libs: [ - "libsensorservice", - "libsensorprivacy", "libbinder", + "libsensorprivacy", + "libsensorservice", "libutils", ], diff --git a/services/sensorservice/senserservice_flags.aconfig b/services/sensorservice/sensorservice_flags.aconfig index 7abfbaab07..452b42826c 100644 --- a/services/sensorservice/senserservice_flags.aconfig +++ b/services/sensorservice/sensorservice_flags.aconfig @@ -28,3 +28,13 @@ flag { description: "When this flag is enabled, sensor service will only erase dynamic sensor data at the end of the threadLoop to prevent race condition." bug: "329020894" } + +flag { + name: "enforce_permissions_for_all_target_sdk" + namespace: "sensors" + description: "When this flag is enabled, sensor service will enforce permissions for all target sdks." + bug: "389176817" + metadata { + purpose: PURPOSE_BUGFIX + } +}
\ No newline at end of file diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp index ea7d6d7602..88ff370188 100644 --- a/services/surfaceflinger/Android.bp +++ b/services/surfaceflinger/Android.bp @@ -206,7 +206,6 @@ filegroup { "Display/DisplayModeController.cpp", "Display/DisplaySnapshot.cpp", "DisplayDevice.cpp", - "DisplayRenderArea.cpp", "Effects/Daltonizer.cpp", "FpsReporter.cpp", "FrameTracer/FrameTracer.cpp", @@ -225,12 +224,10 @@ filegroup { "Layer.cpp", "LayerFE.cpp", "LayerProtoHelper.cpp", - "LayerRenderArea.cpp", "LayerVector.cpp", "NativeWindowSurface.cpp", "RefreshRateOverlay.cpp", "RegionSamplingThread.cpp", - "RenderArea.cpp", "Scheduler/EventThread.cpp", "Scheduler/FrameRateOverrideMappings.cpp", "Scheduler/LayerHistory.cpp", diff --git a/services/surfaceflinger/Client.cpp b/services/surfaceflinger/Client.cpp index 77bf1457c3..6088e255df 100644 --- a/services/surfaceflinger/Client.cpp +++ b/services/surfaceflinger/Client.cpp @@ -110,8 +110,8 @@ binder::Status Client::mirrorDisplay(int64_t displayId, gui::CreateSurfaceResult LayerCreationArgs args(mFlinger.get(), sp<Client>::fromExisting(this), "MirrorRoot-" + std::to_string(displayId), 0 /* flags */, gui::LayerMetadata()); - std::optional<DisplayId> id = DisplayId::fromValue(static_cast<uint64_t>(displayId)); - status_t status = mFlinger->mirrorDisplay(*id, args, *outResult); + const DisplayId id = DisplayId::fromValue(static_cast<uint64_t>(displayId)); + status_t status = mFlinger->mirrorDisplay(id, args, *outResult); return binderStatusFromStatusT(status); } diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h index e876693498..780758e2a3 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h @@ -19,6 +19,7 @@ #include <optional> #include <ostream> #include <unordered_set> +#include "aidl/android/hardware/graphics/composer3/Composition.h" #include "ui/LayerStack.h" // TODO(b/129481165): remove the #pragma below and fix conversion issues @@ -36,10 +37,6 @@ #include <utils/RefBase.h> #include <utils/Timers.h> -namespace aidl::android::hardware::graphics::composer3 { -enum class Composition; -} - namespace android { class Fence; @@ -182,10 +179,27 @@ public: // Whether the layer should be rendered with rounded corners. virtual bool hasRoundedCorners() const = 0; virtual void setWasClientComposed(const sp<Fence>&) {} - virtual void setHwcCompositionType( - aidl::android::hardware::graphics::composer3::Composition) = 0; - virtual aidl::android::hardware::graphics::composer3::Composition getHwcCompositionType() - const = 0; + + // These fields are all copied from the last written HWC state. + // This state is only used for debugging purposes. + struct HwcLayerDebugState { + aidl::android::hardware::graphics::composer3::Composition lastCompositionType = + aidl::android::hardware::graphics::composer3::Composition::INVALID; + // Corresponds to passing an alpha of 0 to HWC2::Layer::setPlaneAlpha. + bool wasSkipped = false; + + // Indicates whether the compositionengine::OutputLayer had properties overwritten. + // Not directly passed to HWC. + bool wasOverridden = false; + + // Corresponds to the GraphicBuffer ID of the buffer passed to HWC2::Layer::setBuffer. + // This buffer corresponds to a CachedSet that the LayerFE was flattened to. + uint64_t overrideBufferId = 0; + }; + + // Used for debugging purposes, e.g. perfetto tracing, dumpsys. + virtual void setLastHwcState(const LayerFE::HwcLayerDebugState &hwcState) = 0; + virtual const HwcLayerDebugState &getLastHwcState() const = 0; virtual const gui::LayerMetadata* getMetadata() const = 0; virtual const gui::LayerMetadata* getRelativeMetadata() const = 0; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h index 7744b8bb99..d2a5a2066c 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h @@ -59,9 +59,9 @@ public: MOCK_CONST_METHOD0(getMetadata, gui::LayerMetadata*()); MOCK_CONST_METHOD0(getRelativeMetadata, gui::LayerMetadata*()); MOCK_METHOD0(onPictureProfileCommitted, void()); - MOCK_METHOD(void, setHwcCompositionType, - (aidl::android::hardware::graphics::composer3::Composition), (override)); - MOCK_METHOD(aidl::android::hardware::graphics::composer3::Composition, getHwcCompositionType, + MOCK_METHOD(void, setLastHwcState, + (const HwcLayerDebugState&), (override)); + MOCK_METHOD(const HwcLayerDebugState&, getLastHwcState, (), (const, override)); }; diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp index 9b66f01789..9d67122f2e 100644 --- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp +++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp @@ -502,6 +502,15 @@ void OutputLayer::writeStateToHWC(bool includeGeometry, bool skipLayer, uint32_t editState().hwc->stateOverridden = isOverridden; editState().hwc->layerSkipped = skipLayer; + + + // Save the final HWC state for debugging purposes, e.g. perfetto tracing, dumpsys. + getLayerFE().setLastHwcState({.lastCompositionType = editState().hwc->hwcCompositionType, + .wasSkipped = skipLayer, + .wasOverridden = isOverridden, + .overrideBufferId = editState().overrideInfo.buffer + ? editState().overrideInfo.buffer.get()->getId() + : 0}); } void OutputLayer::writeOutputDependentGeometryStateToHWC(HWC2::Layer* hwcLayer, @@ -867,7 +876,6 @@ void OutputLayer::writeCompositionTypeToHWC(HWC2::Layer* hwcLayer, if (outputDependentState.hwc->hwcCompositionType != requestedCompositionType || (outputDependentState.hwc->layerSkipped && !skipLayer)) { outputDependentState.hwc->hwcCompositionType = requestedCompositionType; - getLayerFE().setHwcCompositionType(requestedCompositionType); if (auto error = hwcLayer->setCompositionType(requestedCompositionType); error != hal::Error::NONE) { @@ -965,7 +973,13 @@ void OutputLayer::applyDeviceCompositionTypeChange(Composition compositionType) } hwcState.hwcCompositionType = compositionType; - getLayerFE().setHwcCompositionType(compositionType); + + getLayerFE().setLastHwcState({.lastCompositionType = hwcState.hwcCompositionType, + .wasSkipped = hwcState.layerSkipped, + .wasOverridden = hwcState.stateOverridden, + .overrideBufferId = state.overrideInfo.buffer + ? state.overrideInfo.buffer.get()->getId() + : 0}); } void OutputLayer::prepareForDeviceLayerRequests() { diff --git a/services/surfaceflinger/DisplayRenderArea.cpp b/services/surfaceflinger/DisplayRenderArea.cpp deleted file mode 100644 index c63c738d34..0000000000 --- a/services/surfaceflinger/DisplayRenderArea.cpp +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2020 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 "DisplayRenderArea.h" -#include "DisplayDevice.h" - -namespace android { - -std::unique_ptr<RenderArea> DisplayRenderArea::create(wp<const DisplayDevice> displayWeak, - const Rect& sourceCrop, ui::Size reqSize, - ui::Dataspace reqDataSpace, - ftl::Flags<Options> options) { - if (auto display = displayWeak.promote()) { - // Using new to access a private constructor. - return std::unique_ptr<DisplayRenderArea>(new DisplayRenderArea(std::move(display), - sourceCrop, reqSize, - reqDataSpace, options)); - } - return nullptr; -} - -DisplayRenderArea::DisplayRenderArea(sp<const DisplayDevice> display, const Rect& sourceCrop, - ui::Size reqSize, ui::Dataspace reqDataSpace, - ftl::Flags<Options> options) - : RenderArea(reqSize, CaptureFill::OPAQUE, reqDataSpace, options), - mDisplay(std::move(display)), - mSourceCrop(sourceCrop) {} - -const ui::Transform& DisplayRenderArea::getTransform() const { - return mTransform; -} - -bool DisplayRenderArea::isSecure() const { - return mOptions.test(Options::CAPTURE_SECURE_LAYERS) && mDisplay->isSecure(); -} - -sp<const DisplayDevice> DisplayRenderArea::getDisplayDevice() const { - return mDisplay; -} - -Rect DisplayRenderArea::getSourceCrop() const { - // use the projected display viewport by default. - if (mSourceCrop.isEmpty()) { - return mDisplay->getLayerStackSpaceRect(); - } - return mSourceCrop; -} - -} // namespace android diff --git a/services/surfaceflinger/DisplayRenderArea.h b/services/surfaceflinger/DisplayRenderArea.h deleted file mode 100644 index 677d01975a..0000000000 --- a/services/surfaceflinger/DisplayRenderArea.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2020 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 <ui/GraphicTypes.h> -#include <ui/Transform.h> - -#include "RenderArea.h" - -namespace android { - -class DisplayDevice; - -class DisplayRenderArea : public RenderArea { -public: - static std::unique_ptr<RenderArea> create(wp<const DisplayDevice>, const Rect& sourceCrop, - ui::Size reqSize, ui::Dataspace, - ftl::Flags<Options> options); - - const ui::Transform& getTransform() const override; - bool isSecure() const override; - sp<const DisplayDevice> getDisplayDevice() const override; - Rect getSourceCrop() const override; - -private: - DisplayRenderArea(sp<const DisplayDevice>, const Rect& sourceCrop, ui::Size reqSize, - ui::Dataspace, ftl::Flags<Options> options); - - const sp<const DisplayDevice> mDisplay; - const Rect mSourceCrop; - const ui::Transform mTransform; -}; - -} // namespace android diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp index 523ef7bfbe..839bd79dac 100644 --- a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp +++ b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp @@ -403,11 +403,8 @@ void LayerSnapshot::merge(const RequestedLayerState& requested, bool forceUpdate if (forceUpdate || requested.what & layer_state_t::eSidebandStreamChanged) { sidebandStream = requested.sidebandStream; } - if (forceUpdate || requested.what & layer_state_t::eShadowRadiusChanged || - requested.what & layer_state_t::eClientDrawnShadowsChanged) { - shadowSettings.length = - requested.clientDrawnShadowRadius > 0 ? 0.f : requested.shadowRadius; - shadowSettings.clientDrawnLength = requested.clientDrawnShadowRadius; + if (forceUpdate || requested.what & layer_state_t::eShadowRadiusChanged) { + shadowSettings.length = requested.shadowRadius; } if (forceUpdate || requested.what & layer_state_t::eFrameRateSelectionPriority) { @@ -537,12 +534,13 @@ void LayerSnapshot::merge(const RequestedLayerState& requested, bool forceUpdate } } -char LayerSnapshot::classifyCompositionForDebug(Composition compositionType) const { +char LayerSnapshot::classifyCompositionForDebug( + const compositionengine::LayerFE::HwcLayerDebugState& hwcState) const { if (!isVisible) { return '.'; } - switch (compositionType) { + switch (hwcState.lastCompositionType) { case Composition::INVALID: return 'i'; case Composition::SOLID_COLOR: @@ -561,21 +559,21 @@ char LayerSnapshot::classifyCompositionForDebug(Composition compositionType) con } char code = '.'; // Default to invisible - if (hasBufferOrSidebandStream()) { - code = 'b'; - } else if (fillsColor()) { - code = 'c'; // Solid color - } else if (hasBlur()) { + if (hasBlur()) { code = 'l'; // Blur } else if (hasProtectedContent) { code = 'p'; // Protected content - } else if (drawShadows()) { - code = 's'; // Shadow } else if (roundedCorner.hasRoundedCorners()) { code = 'r'; // Rounded corners + } else if (drawShadows()) { + code = 's'; // Shadow + } else if (fillsColor()) { + code = 'c'; // Solid color + } else if (hasBufferOrSidebandStream()) { + code = 'b'; } - if (compositionType == Composition::CLIENT) { + if (hwcState.lastCompositionType == Composition::CLIENT) { return static_cast<char>(std::toupper(code)); } else { return code; diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshot.h b/services/surfaceflinger/FrontEnd/LayerSnapshot.h index 04b9f3b448..69120bdcff 100644 --- a/services/surfaceflinger/FrontEnd/LayerSnapshot.h +++ b/services/surfaceflinger/FrontEnd/LayerSnapshot.h @@ -24,6 +24,7 @@ #include "RequestedLayerState.h" #include "Scheduler/LayerInfo.h" #include "android-base/stringprintf.h" +#include "compositionengine/LayerFE.h" namespace android::surfaceflinger::frontend { @@ -163,7 +164,7 @@ struct LayerSnapshot : public compositionengine::LayerFECompositionState { // Returns a char summarizing the composition request // This function tries to maintain parity with planner::Plan chars. char classifyCompositionForDebug( - aidl::android::hardware::graphics::composer3::Composition compositionType) const; + const compositionengine::LayerFE::HwcLayerDebugState& hwcState) const; }; } // namespace android::surfaceflinger::frontend diff --git a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp index 1d53e719ab..58c235ed91 100644 --- a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp +++ b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp @@ -108,7 +108,6 @@ RequestedLayerState::RequestedLayerState(const LayerCreationArgs& args) surfaceDamageRegion = Region::INVALID_REGION; cornerRadius = 0.0f; clientDrawnCornerRadius = 0.0f; - clientDrawnShadowRadius = 0.0f; backgroundBlurRadius = 0; api = -1; hasColorTransform = false; @@ -355,11 +354,6 @@ void RequestedLayerState::merge(const ResolvedComposerState& resolvedComposerSta clientDrawnCornerRadius = clientState.clientDrawnCornerRadius; changes |= RequestedLayerState::Changes::Geometry; } - - if (clientState.what & layer_state_t::eClientDrawnShadowsChanged) { - clientDrawnShadowRadius = clientState.clientDrawnShadowRadius; - changes |= RequestedLayerState::Changes::Geometry; - } } ui::Size RequestedLayerState::getUnrotatedBufferSize(uint32_t displayRotationFlags) const { @@ -646,7 +640,6 @@ bool RequestedLayerState::isSimpleBufferUpdate(const layer_state_t& s) const { layer_state_t::eColorTransformChanged | layer_state_t::eBackgroundColorChanged | layer_state_t::eMatrixChanged | layer_state_t::eCornerRadiusChanged | layer_state_t::eClientDrawnCornerRadiusChanged | - layer_state_t::eClientDrawnShadowsChanged | layer_state_t::eBackgroundBlurRadiusChanged | layer_state_t::eBufferTransformChanged | layer_state_t::eTransformToDisplayInverseChanged | layer_state_t::eCropChanged | layer_state_t::eDataspaceChanged | layer_state_t::eHdrMetadataChanged | diff --git a/services/surfaceflinger/LayerFE.cpp b/services/surfaceflinger/LayerFE.cpp index 725a782177..b6192685ae 100644 --- a/services/surfaceflinger/LayerFE.cpp +++ b/services/surfaceflinger/LayerFE.cpp @@ -428,13 +428,12 @@ LayerFE::ReleaseFencePromiseStatus LayerFE::getReleaseFencePromiseStatus() { return mReleaseFencePromiseStatus; } -void LayerFE::setHwcCompositionType( - aidl::android::hardware::graphics::composer3::Composition type) { - mLastHwcCompositionType = type; +void LayerFE::setLastHwcState(const LayerFE::HwcLayerDebugState &state) { + mLastHwcState = state; } -aidl::android::hardware::graphics::composer3::Composition LayerFE::getHwcCompositionType() const { - return mLastHwcCompositionType; -} +const LayerFE::HwcLayerDebugState& LayerFE::getLastHwcState() const { + return mLastHwcState; +}; } // namespace android diff --git a/services/surfaceflinger/LayerFE.h b/services/surfaceflinger/LayerFE.h index 64ec27862d..a537456beb 100644 --- a/services/surfaceflinger/LayerFE.h +++ b/services/surfaceflinger/LayerFE.h @@ -59,9 +59,10 @@ public: void setReleaseFence(const FenceResult& releaseFence) override; LayerFE::ReleaseFencePromiseStatus getReleaseFencePromiseStatus() override; void onPictureProfileCommitted() override; - void setHwcCompositionType(aidl::android::hardware::graphics::composer3::Composition) override; - aidl::android::hardware::graphics::composer3::Composition getHwcCompositionType() - const override; + + // Used for debugging purposes, e.g. perfetto tracing, dumpsys. + void setLastHwcState(const HwcLayerDebugState &state) override; + const HwcLayerDebugState &getLastHwcState() const override; std::unique_ptr<surfaceflinger::frontend::LayerSnapshot> mSnapshot; @@ -93,8 +94,7 @@ private: std::string mName; std::promise<FenceResult> mReleaseFence; ReleaseFencePromiseStatus mReleaseFencePromiseStatus = ReleaseFencePromiseStatus::UNINITIALIZED; - aidl::android::hardware::graphics::composer3::Composition mLastHwcCompositionType = - aidl::android::hardware::graphics::composer3::Composition::INVALID; + HwcLayerDebugState mLastHwcState; }; } // namespace android diff --git a/services/surfaceflinger/LayerRenderArea.cpp b/services/surfaceflinger/LayerRenderArea.cpp deleted file mode 100644 index bfe6d2a956..0000000000 --- a/services/surfaceflinger/LayerRenderArea.cpp +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2020 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 <ui/GraphicTypes.h> -#include <ui/Transform.h> - -#include "DisplayDevice.h" -#include "FrontEnd/LayerCreationArgs.h" -#include "Layer.h" -#include "LayerRenderArea.h" -#include "SurfaceFlinger.h" - -namespace android { - -LayerRenderArea::LayerRenderArea(sp<Layer> layer, frontend::LayerSnapshot layerSnapshot, - const Rect& crop, ui::Size reqSize, ui::Dataspace reqDataSpace, - const ui::Transform& layerTransform, const Rect& layerBufferSize, - ftl::Flags<RenderArea::Options> options) - : RenderArea(reqSize, CaptureFill::CLEAR, reqDataSpace, options), - mLayer(std::move(layer)), - mLayerSnapshot(std::move(layerSnapshot)), - mLayerBufferSize(layerBufferSize), - mCrop(crop), - mTransform(layerTransform) {} - -const ui::Transform& LayerRenderArea::getTransform() const { - return mTransform; -} - -bool LayerRenderArea::isSecure() const { - return mOptions.test(Options::CAPTURE_SECURE_LAYERS); -} - -sp<const DisplayDevice> LayerRenderArea::getDisplayDevice() const { - return nullptr; -} - -Rect LayerRenderArea::getSourceCrop() const { - if (mCrop.isEmpty()) { - // TODO this should probably be mBounds instead of just buffer bounds - return mLayerBufferSize; - } else { - return mCrop; - } -} - -} // namespace android diff --git a/services/surfaceflinger/LayerRenderArea.h b/services/surfaceflinger/LayerRenderArea.h deleted file mode 100644 index f72c7c7715..0000000000 --- a/services/surfaceflinger/LayerRenderArea.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2020 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 <string> - -#include <ui/GraphicTypes.h> -#include <ui/Transform.h> -#include <utils/StrongPointer.h> - -#include "RenderArea.h" - -namespace android { - -class DisplayDevice; -class Layer; -class SurfaceFlinger; - -class LayerRenderArea : public RenderArea { -public: - LayerRenderArea(sp<Layer> layer, frontend::LayerSnapshot layerSnapshot, const Rect& crop, - ui::Size reqSize, ui::Dataspace reqDataSpace, - const ui::Transform& layerTransform, const Rect& layerBufferSize, - ftl::Flags<RenderArea::Options> options); - - const ui::Transform& getTransform() const override; - bool isSecure() const override; - sp<const DisplayDevice> getDisplayDevice() const override; - Rect getSourceCrop() const override; - - sp<Layer> getParentLayer() const override { return mLayer; } - const frontend::LayerSnapshot* getLayerSnapshot() const override { return &mLayerSnapshot; } - -private: - const sp<Layer> mLayer; - const frontend::LayerSnapshot mLayerSnapshot; - const Rect mLayerBufferSize; - const Rect mCrop; - - ui::Transform mTransform; -}; - -} // namespace android diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp index d3483b0cb0..1c4a11a9fa 100644 --- a/services/surfaceflinger/RegionSamplingThread.cpp +++ b/services/surfaceflinger/RegionSamplingThread.cpp @@ -39,11 +39,8 @@ #include <string> #include "DisplayDevice.h" -#include "DisplayRenderArea.h" #include "FrontEnd/LayerCreationArgs.h" #include "Layer.h" -#include "RenderAreaBuilder.h" -#include "Scheduler/VsyncController.h" #include "SurfaceFlinger.h" namespace android { @@ -259,6 +256,7 @@ void RegionSamplingThread::captureSample() { ui::LayerStack layerStack; ui::Transform::RotationFlags orientation; ui::Size displaySize; + Rect layerStackSpaceRect; { // TODO(b/159112860): Don't keep sp<DisplayDevice> outside of SF main thread @@ -267,6 +265,7 @@ void RegionSamplingThread::captureSample() { layerStack = display->getLayerStack(); orientation = ui::Transform::toRotationFlags(display->getOrientation()); displaySize = display->getSize(); + layerStackSpaceRect = display->getLayerStackSpaceRect(); } std::vector<RegionSamplingThread::Descriptor> descriptors; @@ -347,16 +346,20 @@ void RegionSamplingThread::captureSample() { constexpr bool kGrayscale = false; constexpr bool kIsProtected = false; - SurfaceFlinger::RenderAreaBuilderVariant - renderAreaBuilder(std::in_place_type<DisplayRenderAreaBuilder>, sampledBounds, - sampledBounds.getSize(), ui::Dataspace::V0_SRGB, displayWeak, - RenderArea::Options::CAPTURE_SECURE_LAYERS); + SurfaceFlinger::ScreenshotArgs screenshotArgs; + screenshotArgs.captureTypeVariant = displayWeak; + screenshotArgs.displayId = std::nullopt; + screenshotArgs.sourceCrop = sampledBounds.isEmpty() ? layerStackSpaceRect : sampledBounds; + screenshotArgs.reqSize = sampledBounds.getSize(); + screenshotArgs.dataspace = ui::Dataspace::V0_SRGB; + screenshotArgs.isSecure = true; + screenshotArgs.seamlessTransition = false; std::vector<std::pair<Layer*, sp<LayerFE>>> layers; auto displayState = - mFlinger.getSnapshotsFromMainThread(renderAreaBuilder, getLayerSnapshotsFn, layers); + mFlinger.getSnapshotsFromMainThread(screenshotArgs, getLayerSnapshotsFn, layers); FenceResult fenceResult = - mFlinger.captureScreenshot(renderAreaBuilder, buffer, kRegionSampling, kGrayscale, + mFlinger.captureScreenshot(screenshotArgs, buffer, kRegionSampling, kGrayscale, kIsProtected, nullptr, displayState, layers) .get(); if (fenceResult.ok()) { diff --git a/services/surfaceflinger/RenderArea.cpp b/services/surfaceflinger/RenderArea.cpp deleted file mode 100644 index 5fea521f18..0000000000 --- a/services/surfaceflinger/RenderArea.cpp +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2017 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 "RenderArea.h" - -namespace android { - -float RenderArea::getCaptureFillValue(CaptureFill captureFill) { - switch(captureFill) { - case CaptureFill::CLEAR: - return 0.0f; - case CaptureFill::OPAQUE: - default: - return 1.0f; - } -} - -} // namespace android diff --git a/services/surfaceflinger/RenderArea.h b/services/surfaceflinger/RenderArea.h deleted file mode 100644 index aa66ccf172..0000000000 --- a/services/surfaceflinger/RenderArea.h +++ /dev/null @@ -1,98 +0,0 @@ -#pragma once - -#include <ui/GraphicTypes.h> -#include <ui/Transform.h> - -#include <functional> - -#include "FrontEnd/LayerSnapshot.h" -#include "Layer.h" - -namespace android { - -class DisplayDevice; - -// RenderArea describes a rectangular area that layers can be rendered to. -// -// There is a logical render area and a physical render area. When a layer is -// rendered to the render area, it is first transformed and clipped to the logical -// render area. The transformed and clipped layer is then projected onto the -// physical render area. -class RenderArea { -public: - enum class CaptureFill {CLEAR, OPAQUE}; - enum class Options { - // If not set, the secure layer would be blacked out or skipped - // when rendered to an insecure render area - CAPTURE_SECURE_LAYERS = 1 << 0, - - // If set, the render result may be used for system animations - // that must preserve the exact colors of the display - HINT_FOR_SEAMLESS_TRANSITION = 1 << 1, - }; - static float getCaptureFillValue(CaptureFill captureFill); - - RenderArea(ui::Size reqSize, CaptureFill captureFill, ui::Dataspace reqDataSpace, - ftl::Flags<Options> options) - : mOptions(options), - mReqSize(reqSize), - mReqDataSpace(reqDataSpace), - mCaptureFill(captureFill) {} - - virtual ~RenderArea() = default; - - // Returns true if the render area is secure. A secure layer should be - // blacked out / skipped when rendered to an insecure render area. - virtual bool isSecure() const = 0; - - // Returns the transform to be applied on layers to transform them into - // the logical render area. - virtual const ui::Transform& getTransform() const = 0; - - // Returns the source crop of the render area. The source crop defines - // how layers are projected from the logical render area onto the physical - // render area. It can be larger than the logical render area. It can - // also be optionally rotated. - // - // The source crop is specified in layer space (when rendering a layer and - // its children), or in layer-stack space (when rendering all layers visible - // on the display). - virtual Rect getSourceCrop() const = 0; - - // Returns the size of the physical render area. - int getReqWidth() const { return mReqSize.width; } - int getReqHeight() const { return mReqSize.height; } - - // Returns the composition data space of the render area. - ui::Dataspace getReqDataSpace() const { return mReqDataSpace; } - - // Returns the fill color of the physical render area. Regions not - // covered by any rendered layer should be filled with this color. - CaptureFill getCaptureFill() const { return mCaptureFill; } - - virtual sp<const DisplayDevice> getDisplayDevice() const = 0; - - // If this is a LayerRenderArea, return the root layer of the - // capture operation. - virtual sp<Layer> getParentLayer() const { return nullptr; } - - // If this is a LayerRenderArea, return the layer snapshot - // of the root layer of the capture operation - virtual const frontend::LayerSnapshot* getLayerSnapshot() const { return nullptr; } - - // Returns whether the render result may be used for system animations that - // must preserve the exact colors of the display. - bool getHintForSeamlessTransition() const { - return mOptions.test(Options::HINT_FOR_SEAMLESS_TRANSITION); - } - -protected: - ftl::Flags<Options> mOptions; - -private: - const ui::Size mReqSize; - const ui::Dataspace mReqDataSpace; - const CaptureFill mCaptureFill; -}; - -} // namespace android diff --git a/services/surfaceflinger/RenderAreaBuilder.h b/services/surfaceflinger/RenderAreaBuilder.h deleted file mode 100644 index 599fa7e102..0000000000 --- a/services/surfaceflinger/RenderAreaBuilder.h +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright 2024 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include "DisplayDevice.h" -#include "DisplayRenderArea.h" -#include "LayerRenderArea.h" -#include "ui/Size.h" -#include "ui/Transform.h" - -namespace android { -/** - * A parameter object for creating a render area - */ -struct RenderAreaBuilder { - // Source crop of the render area - Rect crop; - - // Size of the physical render area - ui::Size reqSize; - - // Composition data space of the render area - ui::Dataspace reqDataSpace; - - ftl::Flags<RenderArea::Options> options; - virtual std::unique_ptr<RenderArea> build() const = 0; - - RenderAreaBuilder(Rect crop, ui::Size reqSize, ui::Dataspace reqDataSpace, - ftl::Flags<RenderArea::Options> options) - : crop(crop), reqSize(reqSize), reqDataSpace(reqDataSpace), options(options) {} - - virtual ~RenderAreaBuilder() = default; -}; - -struct DisplayRenderAreaBuilder : RenderAreaBuilder { - DisplayRenderAreaBuilder(Rect crop, ui::Size reqSize, ui::Dataspace reqDataSpace, - wp<const DisplayDevice> displayWeak, - ftl::Flags<RenderArea::Options> options) - : RenderAreaBuilder(crop, reqSize, reqDataSpace, options), displayWeak(displayWeak) {} - - // Display that render area will be on - wp<const DisplayDevice> displayWeak; - - std::unique_ptr<RenderArea> build() const override { - return DisplayRenderArea::create(displayWeak, crop, reqSize, reqDataSpace, options); - } -}; - -struct LayerRenderAreaBuilder : RenderAreaBuilder { - LayerRenderAreaBuilder(Rect crop, ui::Size reqSize, ui::Dataspace reqDataSpace, sp<Layer> layer, - bool childrenOnly, ftl::Flags<RenderArea::Options> options) - : RenderAreaBuilder(crop, reqSize, reqDataSpace, options), - layer(layer), - childrenOnly(childrenOnly) {} - - // Root layer of the render area - sp<Layer> layer; - - // Layer snapshot of the root layer - frontend::LayerSnapshot layerSnapshot; - - // Transform to be applied on the layers to transform them - // into the logical render area - ui::Transform layerTransform{ui::Transform()}; - - // Buffer bounds - Rect layerBufferSize{Rect()}; - - // If false, transform is inverted from the parent snapshot - bool childrenOnly; - - // Uses parent snapshot to determine layer transform and buffer size - void setLayerSnapshot(const frontend::LayerSnapshot& parentSnapshot) { - layerSnapshot = parentSnapshot; - if (!childrenOnly) { - layerTransform = parentSnapshot.localTransform.inverse(); - } - layerBufferSize = parentSnapshot.bufferSize; - } - - std::unique_ptr<RenderArea> build() const override { - return std::make_unique<LayerRenderArea>(layer, std::move(layerSnapshot), crop, reqSize, - reqDataSpace, layerTransform, layerBufferSize, - options); - } -}; - -} // namespace android
\ No newline at end of file diff --git a/services/surfaceflinger/ScreenCaptureOutput.cpp b/services/surfaceflinger/ScreenCaptureOutput.cpp index 5f71b88d01..712390574f 100644 --- a/services/surfaceflinger/ScreenCaptureOutput.cpp +++ b/services/surfaceflinger/ScreenCaptureOutput.cpp @@ -29,11 +29,15 @@ namespace android { std::shared_ptr<ScreenCaptureOutput> createScreenCaptureOutput(ScreenCaptureOutputArgs args) { std::shared_ptr<ScreenCaptureOutput> output = compositionengine::impl::createOutputTemplated< - ScreenCaptureOutput, compositionengine::CompositionEngine, const RenderArea&, + ScreenCaptureOutput, compositionengine::CompositionEngine, + /* sourceCrop */ const Rect, std::optional<DisplayId>, const compositionengine::Output::ColorProfile&, - bool>(args.compositionEngine, args.renderArea, args.colorProfile, args.regionSampling, - args.dimInGammaSpaceForEnhancedScreenshots, args.enableLocalTonemapping); - output->editState().isSecure = args.renderArea.isSecure(); + /* layerAlpha */ float, + /* regionSampling */ bool>(args.compositionEngine, args.sourceCrop, args.displayId, + args.colorProfile, args.layerAlpha, args.regionSampling, + args.dimInGammaSpaceForEnhancedScreenshots, + args.enableLocalTonemapping); + output->editState().isSecure = args.isSecure; output->editState().isProtected = args.isProtected; output->setCompositionEnabled(true); output->setLayerFilter({args.layerStack}); @@ -47,16 +51,16 @@ std::shared_ptr<ScreenCaptureOutput> createScreenCaptureOutput(ScreenCaptureOutp .setHasWideColorGamut(true) .Build())); - const Rect& sourceCrop = args.renderArea.getSourceCrop(); + const Rect& sourceCrop = args.sourceCrop; const ui::Rotation orientation = ui::ROTATION_0; output->setDisplaySize({sourceCrop.getWidth(), sourceCrop.getHeight()}); output->setProjection(orientation, sourceCrop, - {args.renderArea.getReqWidth(), args.renderArea.getReqHeight()}); + {args.reqBufferSize.width, args.reqBufferSize.height}); { std::string name = args.regionSampling ? "RegionSampling" : "ScreenCaptureOutput"; - if (auto displayDevice = args.renderArea.getDisplayDevice()) { - base::StringAppendF(&name, " for %" PRIu64, displayDevice->getId().value); + if (args.displayId) { + base::StringAppendF(&name, " for %" PRIu64, args.displayId.value().value); } output->setName(name); } @@ -64,11 +68,14 @@ std::shared_ptr<ScreenCaptureOutput> createScreenCaptureOutput(ScreenCaptureOutp } ScreenCaptureOutput::ScreenCaptureOutput( - const RenderArea& renderArea, const compositionengine::Output::ColorProfile& colorProfile, + const Rect sourceCrop, std::optional<DisplayId> displayId, + const compositionengine::Output::ColorProfile& colorProfile, float layerAlpha, bool regionSampling, bool dimInGammaSpaceForEnhancedScreenshots, bool enableLocalTonemapping) - : mRenderArea(renderArea), + : mSourceCrop(sourceCrop), + mDisplayId(displayId), mColorProfile(colorProfile), + mLayerAlpha(layerAlpha), mRegionSampling(regionSampling), mDimInGammaSpaceForEnhancedScreenshots(dimInGammaSpaceForEnhancedScreenshots), mEnableLocalTonemapping(enableLocalTonemapping) {} @@ -83,7 +90,7 @@ renderengine::DisplaySettings ScreenCaptureOutput::generateClientCompositionDisp const std::shared_ptr<renderengine::ExternalTexture>& buffer) const { auto clientCompositionDisplay = compositionengine::impl::Output::generateClientCompositionDisplaySettings(buffer); - clientCompositionDisplay.clip = mRenderArea.getSourceCrop(); + clientCompositionDisplay.clip = mSourceCrop; auto renderIntent = static_cast<ui::RenderIntent>(clientCompositionDisplay.renderIntent); if (mDimInGammaSpaceForEnhancedScreenshots && renderIntent != ui::RenderIntent::COLORIMETRIC && @@ -130,8 +137,8 @@ ScreenCaptureOutput::generateLuts() { } std::vector<aidl::android::hardware::graphics::composer3::Luts> luts; - if (auto displayDevice = mRenderArea.getDisplayDevice()) { - const auto id = PhysicalDisplayId::tryCast(displayDevice->getId()); + if (mDisplayId) { + const auto id = PhysicalDisplayId::tryCast(mDisplayId.value()); if (id) { auto& hwc = getCompositionEngine().getHwComposer(); hwc.getLuts(*id, buffers, &luts); @@ -201,14 +208,15 @@ ScreenCaptureOutput::generateClientCompositionRequests( } } - Rect sourceCrop = mRenderArea.getSourceCrop(); compositionengine::LayerFE::LayerSettings fillLayer; fillLayer.source.buffer.buffer = nullptr; fillLayer.source.solidColor = half3(0.0f, 0.0f, 0.0f); fillLayer.geometry.boundaries = - FloatRect(static_cast<float>(sourceCrop.left), static_cast<float>(sourceCrop.top), - static_cast<float>(sourceCrop.right), static_cast<float>(sourceCrop.bottom)); - fillLayer.alpha = half(RenderArea::getCaptureFillValue(mRenderArea.getCaptureFill())); + FloatRect(static_cast<float>(mSourceCrop.left), static_cast<float>(mSourceCrop.top), + static_cast<float>(mSourceCrop.right), + static_cast<float>(mSourceCrop.bottom)); + + fillLayer.alpha = half(mLayerAlpha); clientCompositionLayers.insert(clientCompositionLayers.begin(), fillLayer); return clientCompositionLayers; diff --git a/services/surfaceflinger/ScreenCaptureOutput.h b/services/surfaceflinger/ScreenCaptureOutput.h index 444a28fbf0..b3e98b1a32 100644 --- a/services/surfaceflinger/ScreenCaptureOutput.h +++ b/services/surfaceflinger/ScreenCaptureOutput.h @@ -22,23 +22,25 @@ #include <ui/Rect.h> #include <unordered_map> -#include "RenderArea.h" - namespace android { struct ScreenCaptureOutputArgs { const compositionengine::CompositionEngine& compositionEngine; const compositionengine::Output::ColorProfile& colorProfile; - const RenderArea& renderArea; ui::LayerStack layerStack; + Rect sourceCrop; std::shared_ptr<renderengine::ExternalTexture> buffer; + std::optional<DisplayId> displayId; + ui::Size reqBufferSize; float sdrWhitePointNits; float displayBrightnessNits; // Counterintuitively, when targetBrightness > 1.0 then dim the scene. float targetBrightness; + float layerAlpha; bool regionSampling; bool treat170mAsSrgb; bool dimInGammaSpaceForEnhancedScreenshots; + bool isSecure = false; bool isProtected = false; bool enableLocalTonemapping = false; }; @@ -49,10 +51,10 @@ struct ScreenCaptureOutputArgs { // SurfaceFlinger::captureLayers and SurfaceFlinger::captureDisplay. class ScreenCaptureOutput : public compositionengine::impl::Output { public: - ScreenCaptureOutput(const RenderArea& renderArea, + ScreenCaptureOutput(const Rect sourceCrop, std::optional<DisplayId> displayId, const compositionengine::Output::ColorProfile& colorProfile, - bool regionSampling, bool dimInGammaSpaceForEnhancedScreenshots, - bool enableLocalTonemapping); + float layerAlpha, bool regionSampling, + bool dimInGammaSpaceForEnhancedScreenshots, bool enableLocalTonemapping); void updateColorProfile(const compositionengine::CompositionRefreshArgs&) override; @@ -67,8 +69,10 @@ protected: private: std::unordered_map<int32_t, aidl::android::hardware::graphics::composer3::Luts> generateLuts(); - const RenderArea& mRenderArea; + const Rect mSourceCrop; + const std::optional<DisplayId> mDisplayId; const compositionengine::Output::ColorProfile& mColorProfile; + const float mLayerAlpha; const bool mRegionSampling; const bool mDimInGammaSpaceForEnhancedScreenshots; const bool mEnableLocalTonemapping; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index eecdd72727..11633908c9 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -137,7 +137,6 @@ #include "DisplayHardware/FramebufferSurface.h" #include "DisplayHardware/Hal.h" #include "DisplayHardware/VirtualDisplaySurface.h" -#include "DisplayRenderArea.h" #include "Effects/Daltonizer.h" #include "FpsReporter.h" #include "FrameTimeline/FrameTimeline.h" @@ -151,14 +150,12 @@ #include "Jank/JankTracker.h" #include "Layer.h" #include "LayerProtoHelper.h" -#include "LayerRenderArea.h" #include "LayerVector.h" #include "MutexUtils.h" #include "NativeWindowSurface.h" #include "PowerAdvisor/PowerAdvisor.h" #include "PowerAdvisor/Workload.h" #include "RegionSamplingThread.h" -#include "RenderAreaBuilder.h" #include "Scheduler/EventThread.h" #include "Scheduler/LayerHistory.h" #include "Scheduler/Scheduler.h" @@ -1166,8 +1163,8 @@ status_t SurfaceFlinger::getStaticDisplayInfo(int64_t displayId, ui::StaticDispl } Mutex::Autolock lock(mStateLock); - const auto id = DisplayId::fromValue<PhysicalDisplayId>(static_cast<uint64_t>(displayId)); - const auto displayOpt = mPhysicalDisplays.get(*id).and_then(getDisplayDeviceAndSnapshot()); + const PhysicalDisplayId id = PhysicalDisplayId::fromValue(static_cast<uint64_t>(displayId)); + const auto displayOpt = mPhysicalDisplays.get(id).and_then(getDisplayDeviceAndSnapshot()); if (!displayOpt) { return NAME_NOT_FOUND; @@ -1289,9 +1286,9 @@ status_t SurfaceFlinger::getDynamicDisplayInfoFromId(int64_t physicalDisplayId, Mutex::Autolock lock(mStateLock); - const auto id_ = - DisplayId::fromValue<PhysicalDisplayId>(static_cast<uint64_t>(physicalDisplayId)); - const auto displayOpt = mPhysicalDisplays.get(*id_).and_then(getDisplayDeviceAndSnapshot()); + const PhysicalDisplayId id = + PhysicalDisplayId::fromValue(static_cast<uint64_t>(physicalDisplayId)); + const auto displayOpt = mPhysicalDisplays.get(id).and_then(getDisplayDeviceAndSnapshot()); if (!displayOpt) { return NAME_NOT_FOUND; @@ -2980,6 +2977,8 @@ CompositeResultsPerDisplay SurfaceFlinger::composite( int index = 0; ftl::StaticVector<char, WorkloadTracer::COMPOSITION_SUMMARY_SIZE> compositionSummary; auto lastLayerStack = ui::INVALID_LAYER_STACK; + + uint64_t prevOverrideBufferId = 0; for (auto& [layer, layerFE] : layers) { CompositionResult compositionResult{layerFE->stealCompositionResult()}; if (lastLayerStack != layerFE->mSnapshot->outputFilter.layerStack) { @@ -2989,8 +2988,37 @@ CompositeResultsPerDisplay SurfaceFlinger::composite( } lastLayerStack = layerFE->mSnapshot->outputFilter.layerStack; } + + // If there are N layers in a cached set they should all share the same buffer id. + // The first layer in the cached set will be not skipped and layers 1..N-1 will be skipped. + // We expect all layers in the cached set to be marked as composited by HWC. + // Here is a made up example of how it is visualized + // + // [b:rrc][s:cc] + // + // This should be interpreted to mean that there are 2 cached sets. + // So there are only 2 non skipped layers -- b and s. + // The layers rrc and cc are flattened into layers b and s respectively. + const LayerFE::HwcLayerDebugState &hwcState = layerFE->getLastHwcState(); + if (hwcState.overrideBufferId != prevOverrideBufferId) { + // End the existing run. + if (prevOverrideBufferId) { + compositionSummary.push_back(']'); + } + // Start a new run. + if (hwcState.overrideBufferId) { + compositionSummary.push_back('['); + } + } + compositionSummary.push_back( - layerFE->mSnapshot->classifyCompositionForDebug(layerFE->getHwcCompositionType())); + layerFE->mSnapshot->classifyCompositionForDebug(hwcState)); + + if (hwcState.overrideBufferId && !hwcState.wasSkipped) { + compositionSummary.push_back(':'); + } + prevOverrideBufferId = hwcState.overrideBufferId; + if (layerFE->mSnapshot->hasEffect()) { compositedWorkload |= adpf::Workload::EFFECTS; } @@ -3002,6 +3030,10 @@ CompositeResultsPerDisplay SurfaceFlinger::composite( mActivePictureTracker.onLayerComposed(*layer, *layerFE, compositionResult); } } + // End the last run. + if (prevOverrideBufferId) { + compositionSummary.push_back(']'); + } // Concisely describe the layers composited this frame using single chars. GPU composited layers // are uppercase, DPU composited are lowercase. Special chars denote effects (blur, shadow, @@ -6734,8 +6766,9 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r return getDefaultDisplayDevice()->getDisplayToken().promote(); } - if (const auto id = DisplayId::fromValue<PhysicalDisplayId>(value)) { - return getPhysicalDisplayToken(*id); + if (const auto token = + getPhysicalDisplayToken(PhysicalDisplayId::fromValue(value))) { + return token; } ALOGE("Invalid physical display ID"); @@ -6833,10 +6866,10 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r case 1040: { auto future = mScheduler->schedule([&] { n = data.readInt32(); - std::optional<PhysicalDisplayId> inputId = std::nullopt; + PhysicalDisplayId inputId; if (uint64_t inputDisplayId; data.readUint64(&inputDisplayId) == NO_ERROR) { - inputId = DisplayId::fromValue<PhysicalDisplayId>(inputDisplayId); - if (!inputId || getPhysicalDisplayToken(*inputId)) { + inputId = PhysicalDisplayId::fromValue(inputDisplayId); + if (!getPhysicalDisplayToken(inputId)) { ALOGE("No display with id: %" PRIu64, inputDisplayId); return NAME_NOT_FOUND; } @@ -6845,7 +6878,7 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r Mutex::Autolock lock(mStateLock); mLayerCachingEnabled = n != 0; for (const auto& [_, display] : mDisplays) { - if (!inputId || *inputId == display->getPhysicalId()) { + if (inputId == display->getPhysicalId()) { display->enableLayerCaching(mLayerCachingEnabled); } } @@ -6928,11 +6961,10 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r int64_t arg1 = data.readInt64(); int64_t arg2 = data.readInt64(); // Enable mirroring for one display - const auto display1id = DisplayId::fromValue(arg1); auto mirrorRoot = SurfaceComposerClient::getDefault()->mirrorDisplay( - display1id.value()); - auto id2 = DisplayId::fromValue<PhysicalDisplayId>(arg2); - const auto token2 = getPhysicalDisplayToken(*id2); + DisplayId::fromValue(arg1)); + const auto token2 = + getPhysicalDisplayToken(PhysicalDisplayId::fromValue(arg2)); ui::LayerStack layerStack; { Mutex::Autolock lock(mStateLock); @@ -7220,9 +7252,13 @@ void SurfaceFlinger::captureDisplay(const DisplayCaptureArgs& args, } wp<const DisplayDevice> displayWeak; + DisplayId displayId; ui::LayerStack layerStack; ui::Size reqSize(args.width, args.height); std::unordered_set<uint32_t> excludeLayerIds; + Rect layerStackSpaceRect; + bool displayIsSecure; + { Mutex::Autolock lock(mStateLock); sp<DisplayDevice> display = getDisplayDeviceLocked(args.displayToken); @@ -7232,11 +7268,14 @@ void SurfaceFlinger::captureDisplay(const DisplayCaptureArgs& args, return; } displayWeak = display; + displayId = display->getId(); layerStack = display->getLayerStack(); + displayIsSecure = display->isSecure(); + layerStackSpaceRect = display->getLayerStackSpaceRect(); // set the requested width/height to the logical display layer stack rect size by default if (args.width == 0 || args.height == 0) { - reqSize = display->getLayerStackSpaceRect().getSize(); + reqSize = layerStackSpaceRect.getSize(); } for (const auto& handle : captureArgs.excludeHandles) { @@ -7255,16 +7294,19 @@ void SurfaceFlinger::captureDisplay(const DisplayCaptureArgs& args, getLayerSnapshotsForScreenshots(layerStack, captureArgs.uid, std::move(excludeLayerIds)); - ftl::Flags<RenderArea::Options> options; - if (captureArgs.captureSecureLayers) options |= RenderArea::Options::CAPTURE_SECURE_LAYERS; - if (captureArgs.hintForSeamlessTransition) - options |= RenderArea::Options::HINT_FOR_SEAMLESS_TRANSITION; - captureScreenCommon(RenderAreaBuilderVariant(std::in_place_type<DisplayRenderAreaBuilder>, - gui::aidl_utils::fromARect(captureArgs.sourceCrop), - reqSize, - static_cast<ui::Dataspace>(captureArgs.dataspace), - displayWeak, options), - getLayerSnapshotsFn, reqSize, + ScreenshotArgs screenshotArgs; + screenshotArgs.captureTypeVariant = displayWeak; + screenshotArgs.displayId = displayId; + screenshotArgs.sourceCrop = gui::aidl_utils::fromARect(captureArgs.sourceCrop); + if (screenshotArgs.sourceCrop.isEmpty()) { + screenshotArgs.sourceCrop = layerStackSpaceRect; + } + screenshotArgs.reqSize = reqSize; + screenshotArgs.dataspace = static_cast<ui::Dataspace>(captureArgs.dataspace); + screenshotArgs.isSecure = captureArgs.captureSecureLayers && displayIsSecure; + screenshotArgs.seamlessTransition = captureArgs.hintForSeamlessTransition; + + captureScreenCommon(screenshotArgs, getLayerSnapshotsFn, reqSize, static_cast<ui::PixelFormat>(captureArgs.pixelFormat), captureArgs.allowProtected, captureArgs.grayscale, captureListener); } @@ -7274,6 +7316,9 @@ void SurfaceFlinger::captureDisplay(DisplayId displayId, const CaptureArgs& args ui::LayerStack layerStack; wp<const DisplayDevice> displayWeak; ui::Size size; + Rect layerStackSpaceRect; + bool displayIsSecure; + { Mutex::Autolock lock(mStateLock); @@ -7286,7 +7331,9 @@ void SurfaceFlinger::captureDisplay(DisplayId displayId, const CaptureArgs& args displayWeak = display; layerStack = display->getLayerStack(); + layerStackSpaceRect = display->getLayerStackSpaceRect(); size = display->getLayerStackSpaceRect().getSize(); + displayIsSecure = display->isSecure(); } size.width *= args.frameScaleX; @@ -7315,15 +7362,18 @@ void SurfaceFlinger::captureDisplay(DisplayId displayId, const CaptureArgs& args constexpr bool kAllowProtected = false; constexpr bool kGrayscale = false; - ftl::Flags<RenderArea::Options> options; - if (args.hintForSeamlessTransition) - options |= RenderArea::Options::HINT_FOR_SEAMLESS_TRANSITION; - captureScreenCommon(RenderAreaBuilderVariant(std::in_place_type<DisplayRenderAreaBuilder>, - Rect(), size, - static_cast<ui::Dataspace>(args.dataspace), - displayWeak, options), - getLayerSnapshotsFn, size, static_cast<ui::PixelFormat>(args.pixelFormat), - kAllowProtected, kGrayscale, captureListener); + ScreenshotArgs screenshotArgs; + screenshotArgs.captureTypeVariant = displayWeak; + screenshotArgs.displayId = displayId; + screenshotArgs.sourceCrop = layerStackSpaceRect; + screenshotArgs.reqSize = size; + screenshotArgs.dataspace = static_cast<ui::Dataspace>(args.dataspace); + screenshotArgs.isSecure = args.captureSecureLayers && displayIsSecure; + screenshotArgs.seamlessTransition = args.hintForSeamlessTransition; + + captureScreenCommon(screenshotArgs, getLayerSnapshotsFn, size, + static_cast<ui::PixelFormat>(args.pixelFormat), kAllowProtected, kGrayscale, + captureListener); } ScreenCaptureResults SurfaceFlinger::captureLayersSync(const LayerCaptureArgs& args) { @@ -7425,14 +7475,16 @@ void SurfaceFlinger::captureLayers(const LayerCaptureArgs& args, return; } - ftl::Flags<RenderArea::Options> options; - if (captureArgs.captureSecureLayers) options |= RenderArea::Options::CAPTURE_SECURE_LAYERS; - if (captureArgs.hintForSeamlessTransition) - options |= RenderArea::Options::HINT_FOR_SEAMLESS_TRANSITION; - captureScreenCommon(RenderAreaBuilderVariant(std::in_place_type<LayerRenderAreaBuilder>, crop, - reqSize, dataspace, parent, args.childrenOnly, - options), - getLayerSnapshotsFn, reqSize, + ScreenshotArgs screenshotArgs; + screenshotArgs.captureTypeVariant = parent->getSequence(); + screenshotArgs.childrenOnly = args.childrenOnly; + screenshotArgs.sourceCrop = crop; + screenshotArgs.reqSize = reqSize; + screenshotArgs.dataspace = static_cast<ui::Dataspace>(captureArgs.dataspace); + screenshotArgs.isSecure = captureArgs.captureSecureLayers; + screenshotArgs.seamlessTransition = captureArgs.hintForSeamlessTransition; + + captureScreenCommon(screenshotArgs, getLayerSnapshotsFn, reqSize, static_cast<ui::PixelFormat>(captureArgs.pixelFormat), captureArgs.allowProtected, captureArgs.grayscale, captureListener); } @@ -7468,10 +7520,10 @@ bool SurfaceFlinger::layersHasProtectedLayer( // is reduced when grabbed from the main thread, thus also reducing // risk of deadlocks. std::optional<SurfaceFlinger::OutputCompositionState> SurfaceFlinger::getSnapshotsFromMainThread( - RenderAreaBuilderVariant& renderAreaBuilder, GetLayerSnapshotsFunction getLayerSnapshotsFn, + ScreenshotArgs& args, GetLayerSnapshotsFunction getLayerSnapshotsFn, std::vector<std::pair<Layer*, sp<LayerFE>>>& layers) { return mScheduler - ->schedule([=, this, &renderAreaBuilder, &layers]() REQUIRES(kMainThreadContext) { + ->schedule([=, this, &args, &layers]() REQUIRES(kMainThreadContext) { SFTRACE_NAME_FOR_TRACK(WorkloadTracer::TRACK_NAME, "Screenshot"); mPowerAdvisor->setScreenshotWorkload(); SFTRACE_NAME("getSnapshotsFromMainThread"); @@ -7486,12 +7538,12 @@ std::optional<SurfaceFlinger::OutputCompositionState> SurfaceFlinger::getSnapsho ui::INVALID_LAYER_STACK); } } - return getDisplayStateFromRenderAreaBuilder(renderAreaBuilder); + return getDisplayStateOnMainThread(args); }) .get(); } -void SurfaceFlinger::captureScreenCommon(RenderAreaBuilderVariant renderAreaBuilder, +void SurfaceFlinger::captureScreenCommon(ScreenshotArgs& args, GetLayerSnapshotsFunction getLayerSnapshotsFn, ui::Size bufferSize, ui::PixelFormat reqPixelFormat, bool allowProtected, bool grayscale, @@ -7507,7 +7559,11 @@ void SurfaceFlinger::captureScreenCommon(RenderAreaBuilderVariant renderAreaBuil } std::vector<std::pair<Layer*, sp<LayerFE>>> layers; - auto displayState = getSnapshotsFromMainThread(renderAreaBuilder, getLayerSnapshotsFn, layers); + auto displayState = getSnapshotsFromMainThread(args, getLayerSnapshotsFn, layers); + if (!displayState) { + ALOGD("Display state not found"); + invokeScreenCaptureError(NO_MEMORY, captureListener); + } const bool hasHdrLayer = std::any_of(layers.cbegin(), layers.cend(), [this](const auto& layer) { return isHdrLayer(*(layer.second->mSnapshot.get())); @@ -7545,12 +7601,8 @@ void SurfaceFlinger::captureScreenCommon(RenderAreaBuilderVariant renderAreaBuil std::shared_ptr<renderengine::impl::ExternalTexture> hdrTexture; std::shared_ptr<renderengine::impl::ExternalTexture> gainmapTexture; - bool hintForSeamless = std::visit( - [](auto&& arg) { - return arg.options.test(RenderArea::Options::HINT_FOR_SEAMLESS_TRANSITION); - }, - renderAreaBuilder); - if (hasHdrLayer && !hintForSeamless && FlagManager::getInstance().true_hdr_screenshots()) { + if (hasHdrLayer && !args.seamlessTransition && + FlagManager::getInstance().true_hdr_screenshots()) { const auto hdrBuffer = getFactory().createGraphicBuffer(buffer->getWidth(), buffer->getHeight(), HAL_PIXEL_FORMAT_RGBA_FP16, 1 /* layerCount */, @@ -7583,35 +7635,41 @@ void SurfaceFlinger::captureScreenCommon(RenderAreaBuilderVariant renderAreaBuil } } - auto futureFence = captureScreenshot(renderAreaBuilder, texture, false /* regionSampling */, - grayscale, isProtected, captureListener, displayState, - layers, hdrTexture, gainmapTexture); + auto futureFence = + captureScreenshot(args, texture, false /* regionSampling */, grayscale, isProtected, + captureListener, displayState, layers, hdrTexture, gainmapTexture); futureFence.get(); } -std::optional<SurfaceFlinger::OutputCompositionState> -SurfaceFlinger::getDisplayStateFromRenderAreaBuilder(RenderAreaBuilderVariant& renderAreaBuilder) { +std::optional<SurfaceFlinger::OutputCompositionState> SurfaceFlinger::getDisplayStateOnMainThread( + ScreenshotArgs& args) { sp<const DisplayDevice> display = nullptr; { Mutex::Autolock lock(mStateLock); - if (auto* layerRenderAreaBuilder = - std::get_if<LayerRenderAreaBuilder>(&renderAreaBuilder)) { + // Screenshot initiated through captureLayers + if (auto* layerSequence = std::get_if<int32_t>(&args.captureTypeVariant)) { // LayerSnapshotBuilder should only be accessed from the main thread. const frontend::LayerSnapshot* snapshot = - mLayerSnapshotBuilder.getSnapshot(layerRenderAreaBuilder->layer->getSequence()); + mLayerSnapshotBuilder.getSnapshot(*layerSequence); if (!snapshot) { - ALOGW("Couldn't find layer snapshot for %d", - layerRenderAreaBuilder->layer->getSequence()); + ALOGW("Couldn't find layer snapshot for %d", *layerSequence); } else { - layerRenderAreaBuilder->setLayerSnapshot(*snapshot); + if (!args.childrenOnly) { + args.transform = snapshot->localTransform.inverse(); + } + if (args.sourceCrop.isEmpty()) { + args.sourceCrop = snapshot->bufferSize; + } display = findDisplay( [layerStack = snapshot->outputFilter.layerStack](const auto& display) { return display.getLayerStack() == layerStack; }); } - } else if (auto* displayRenderAreaBuilder = - std::get_if<DisplayRenderAreaBuilder>(&renderAreaBuilder)) { - display = displayRenderAreaBuilder->displayWeak.promote(); + + // Screenshot initiated through captureDisplay + } else if (auto* displayWeak = + std::get_if<wp<const DisplayDevice>>(&args.captureTypeVariant)) { + display = displayWeak->promote(); } if (display == nullptr) { @@ -7626,9 +7684,9 @@ SurfaceFlinger::getDisplayStateFromRenderAreaBuilder(RenderAreaBuilderVariant& r } ftl::SharedFuture<FenceResult> SurfaceFlinger::captureScreenshot( - const RenderAreaBuilderVariant& renderAreaBuilder, - const std::shared_ptr<renderengine::ExternalTexture>& buffer, bool regionSampling, - bool grayscale, bool isProtected, const sp<IScreenCaptureListener>& captureListener, + const ScreenshotArgs& args, const std::shared_ptr<renderengine::ExternalTexture>& buffer, + bool regionSampling, bool grayscale, bool isProtected, + const sp<IScreenCaptureListener>& captureListener, const std::optional<OutputCompositionState>& displayState, const std::vector<std::pair<Layer*, sp<LayerFE>>>& layers, const std::shared_ptr<renderengine::ExternalTexture>& hdrBuffer, @@ -7636,18 +7694,6 @@ ftl::SharedFuture<FenceResult> SurfaceFlinger::captureScreenshot( SFTRACE_CALL(); ScreenCaptureResults captureResults; - std::unique_ptr<const RenderArea> renderArea = - std::visit([](auto&& arg) -> std::unique_ptr<RenderArea> { return arg.build(); }, - renderAreaBuilder); - - if (!renderArea) { - ALOGW("Skipping screen capture because of invalid render area."); - if (captureListener) { - captureResults.fenceResult = base::unexpected(NO_MEMORY); - captureListener->onScreenCaptureCompleted(captureResults); - } - return ftl::yield<FenceResult>(base::unexpected(NO_ERROR)).share(); - } float displayBrightnessNits = displayState.value().displayBrightnessNits; float sdrWhitePointNits = displayState.value().sdrWhitePointNits; @@ -7656,8 +7702,8 @@ ftl::SharedFuture<FenceResult> SurfaceFlinger::captureScreenshot( if (hdrBuffer && gainmapBuffer) { ftl::SharedFuture<FenceResult> hdrRenderFuture = - renderScreenImpl(std::move(renderArea), hdrBuffer, regionSampling, grayscale, - isProtected, captureResults, displayState, layers); + renderScreenImpl(args, hdrBuffer, regionSampling, grayscale, isProtected, + captureResults, displayState, layers); captureResults.buffer = buffer->getBuffer(); captureResults.optionalGainMap = gainmapBuffer->getBuffer(); @@ -7680,8 +7726,8 @@ ftl::SharedFuture<FenceResult> SurfaceFlinger::captureScreenshot( }) .share(); } else { - renderFuture = renderScreenImpl(std::move(renderArea), buffer, regionSampling, grayscale, - isProtected, captureResults, displayState, layers); + renderFuture = renderScreenImpl(args, buffer, regionSampling, grayscale, isProtected, + captureResults, displayState, layers); } if (captureListener) { @@ -7701,8 +7747,7 @@ ftl::SharedFuture<FenceResult> SurfaceFlinger::captureScreenshot( } ftl::SharedFuture<FenceResult> SurfaceFlinger::renderScreenImpl( - std::unique_ptr<const RenderArea> renderArea, - const std::shared_ptr<renderengine::ExternalTexture>& buffer, + const ScreenshotArgs& args, const std::shared_ptr<renderengine::ExternalTexture>& buffer, bool regionSampling, bool grayscale, bool isProtected, ScreenCaptureResults& captureResults, const std::optional<OutputCompositionState>& displayState, const std::vector<std::pair<Layer*, sp<LayerFE>>>& layers) { @@ -7713,29 +7758,27 @@ ftl::SharedFuture<FenceResult> SurfaceFlinger::renderScreenImpl( captureResults.capturedSecureLayers |= (snapshot->isVisible && snapshot->isSecure); captureResults.capturedHdrLayers |= isHdrLayer(*snapshot); layerFE->mSnapshot->geomLayerTransform = - renderArea->getTransform() * layerFE->mSnapshot->geomLayerTransform; + args.transform * layerFE->mSnapshot->geomLayerTransform; layerFE->mSnapshot->geomInverseLayerTransform = layerFE->mSnapshot->geomLayerTransform.inverse(); } auto capturedBuffer = buffer; - auto requestedDataspace = renderArea->getReqDataSpace(); - auto parent = renderArea->getParentLayer(); auto renderIntent = RenderIntent::TONE_MAP_COLORIMETRIC; auto sdrWhitePointNits = DisplayDevice::sDefaultMaxLumiance; auto displayBrightnessNits = DisplayDevice::sDefaultMaxLumiance; - captureResults.capturedDataspace = requestedDataspace; + captureResults.capturedDataspace = args.dataspace; - const bool enableLocalTonemapping = FlagManager::getInstance().local_tonemap_screenshots() && - !renderArea->getHintForSeamlessTransition(); + const bool enableLocalTonemapping = + FlagManager::getInstance().local_tonemap_screenshots() && !args.seamlessTransition; if (displayState) { const auto& state = displayState.value(); captureResults.capturedDataspace = - pickBestDataspace(requestedDataspace, state, captureResults.capturedHdrLayers, - renderArea->getHintForSeamlessTransition()); + pickBestDataspace(args.dataspace, state, captureResults.capturedHdrLayers, + args.seamlessTransition); sdrWhitePointNits = state.sdrWhitePointNits; if (!captureResults.capturedHdrLayers) { @@ -7747,7 +7790,7 @@ ftl::SharedFuture<FenceResult> SurfaceFlinger::renderScreenImpl( // Otherwise for seamless transitions it's important to match the current // display state as the buffer will be shown under these same conditions, and we // want to avoid any flickers - if (sdrWhitePointNits > 1.0f && !renderArea->getHintForSeamlessTransition()) { + if (sdrWhitePointNits > 1.0f && !args.seamlessTransition) { // Restrict the amount of HDR "headroom" in the screenshot to avoid // over-dimming the SDR portion. 2.0 chosen by experimentation constexpr float kMaxScreenshotHeadroom = 2.0f; @@ -7758,8 +7801,7 @@ ftl::SharedFuture<FenceResult> SurfaceFlinger::renderScreenImpl( } // Screenshots leaving the device should be colorimetric - if (requestedDataspace == ui::Dataspace::UNKNOWN && - renderArea->getHintForSeamlessTransition()) { + if (args.dataspace == ui::Dataspace::UNKNOWN && args.seamlessTransition) { renderIntent = state.renderIntent; } } @@ -7774,7 +7816,7 @@ ftl::SharedFuture<FenceResult> SurfaceFlinger::renderScreenImpl( auto present = [this, buffer = capturedBuffer, dataspace = captureResults.capturedDataspace, sdrWhitePointNits, displayBrightnessNits, grayscale, isProtected, layers, - layerStack, regionSampling, renderArea = std::move(renderArea), renderIntent, + layerStack, regionSampling, args, renderIntent, enableLocalTonemapping]() -> FenceResult { std::unique_ptr<compositionengine::CompositionEngine> compositionEngine = mFactory.createCompositionEngine(); @@ -7810,23 +7852,33 @@ ftl::SharedFuture<FenceResult> SurfaceFlinger::renderScreenImpl( } } + // Capturing screenshots using layers have a clear capture fill (0 alpha). + // Capturing via display or displayId, which do not use args.layerSequence, + // has an opaque capture fill (1 alpha). + const float layerAlpha = + std::holds_alternative<int32_t>(args.captureTypeVariant) ? 0.0f : 1.0f; + // Screenshots leaving the device must not dim in gamma space. - const bool dimInGammaSpaceForEnhancedScreenshots = mDimInGammaSpaceForEnhancedScreenshots && - renderArea->getHintForSeamlessTransition(); + const bool dimInGammaSpaceForEnhancedScreenshots = + mDimInGammaSpaceForEnhancedScreenshots && args.seamlessTransition; std::shared_ptr<ScreenCaptureOutput> output = createScreenCaptureOutput( ScreenCaptureOutputArgs{.compositionEngine = *compositionEngine, .colorProfile = colorProfile, - .renderArea = *renderArea, .layerStack = layerStack, + .sourceCrop = args.sourceCrop, .buffer = std::move(buffer), + .displayId = args.displayId, + .reqBufferSize = args.reqSize, .sdrWhitePointNits = sdrWhitePointNits, .displayBrightnessNits = displayBrightnessNits, .targetBrightness = targetBrightness, + .layerAlpha = layerAlpha, .regionSampling = regionSampling, .treat170mAsSrgb = mTreat170mAsSrgb, .dimInGammaSpaceForEnhancedScreenshots = dimInGammaSpaceForEnhancedScreenshots, + .isSecure = args.isSecure, .isProtected = isProtected, .enableLocalTonemapping = enableLocalTonemapping}); @@ -8697,8 +8749,8 @@ binder::Status SurfaceComposerAIDL::getPhysicalDisplayToken(int64_t displayId, if (status != OK) { return binderStatusFromStatusT(status); } - const auto id = DisplayId::fromValue<PhysicalDisplayId>(static_cast<uint64_t>(displayId)); - *outDisplay = mFlinger->getPhysicalDisplayToken(*id); + const PhysicalDisplayId id = PhysicalDisplayId::fromValue(static_cast<uint64_t>(displayId)); + *outDisplay = mFlinger->getPhysicalDisplayToken(id); return binder::Status::ok(); } diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index b3a3aaddc1..935a2da672 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -132,7 +132,6 @@ class Layer; class MessageBase; class RefreshRateOverlay; class RegionSamplingThread; -class RenderArea; class TimeStats; class FrameTracer; class ScreenCapturer; @@ -197,9 +196,6 @@ enum class LatchUnsignaledConfig { Always, }; -struct DisplayRenderAreaBuilder; -struct LayerRenderAreaBuilder; - using DisplayColorSetting = compositionengine::OutputColorSetting; class SurfaceFlinger : public BnSurfaceComposer, @@ -371,9 +367,7 @@ private: friend class Layer; friend class RefreshRateOverlay; friend class RegionSamplingThread; - friend class LayerRenderArea; friend class SurfaceComposerAIDL; - friend class DisplayRenderArea; // For unit tests friend class TestableSurfaceFlinger; @@ -382,7 +376,6 @@ private: using TransactionSchedule = scheduler::TransactionSchedule; using GetLayerSnapshotsFunction = std::function<std::vector<std::pair<Layer*, sp<LayerFE>>>()>; - using RenderAreaBuilderVariant = std::variant<DisplayRenderAreaBuilder, LayerRenderAreaBuilder>; using DumpArgs = Vector<String16>; using Dumper = std::function<void(const DumpArgs&, bool asProto, std::string&)>; @@ -868,20 +861,56 @@ private: using OutputCompositionState = compositionengine::impl::OutputCompositionState; + /* + * Parameters used across screenshot methods. + */ + struct ScreenshotArgs { + // Contains the sequence ID of the parent layer if the screenshot is + // initiated though captureLayers(), or the display that the render + // result will be on if initiated through captureDisplay() + std::variant<int32_t, wp<const DisplayDevice>> captureTypeVariant; + + // Display ID of the display the result will be on + std::optional<DisplayId> displayId{std::nullopt}; + + // If true, transform is inverted from the parent layer snapshot + bool childrenOnly{false}; + + // Source crop of the render area + Rect sourceCrop; + + // Transform to be applied on the layers to transform them + // into the logical render area + ui::Transform transform; + + // Size of the physical render area + ui::Size reqSize; + + // Composition dataspace of the render area + ui::Dataspace dataspace; + + // If false, the secure layer is blacked out or skipped + // when rendered to an insecure render area + bool isSecure{false}; + + // If true, the render result may be used for system animations + // that must preserve the exact colors of the display + bool seamlessTransition{false}; + }; + std::optional<OutputCompositionState> getSnapshotsFromMainThread( - RenderAreaBuilderVariant& renderAreaBuilder, - GetLayerSnapshotsFunction getLayerSnapshotsFn, + ScreenshotArgs& args, GetLayerSnapshotsFunction getLayerSnapshotsFn, std::vector<std::pair<Layer*, sp<LayerFE>>>& layers); - void captureScreenCommon(RenderAreaBuilderVariant, GetLayerSnapshotsFunction, - ui::Size bufferSize, ui::PixelFormat, bool allowProtected, - bool grayscale, const sp<IScreenCaptureListener>&); + void captureScreenCommon(ScreenshotArgs& args, GetLayerSnapshotsFunction, ui::Size bufferSize, + ui::PixelFormat, bool allowProtected, bool grayscale, + const sp<IScreenCaptureListener>&); - std::optional<OutputCompositionState> getDisplayStateFromRenderAreaBuilder( - RenderAreaBuilderVariant& renderAreaBuilder) REQUIRES(kMainThreadContext); + std::optional<OutputCompositionState> getDisplayStateOnMainThread(ScreenshotArgs& args) + REQUIRES(kMainThreadContext); ftl::SharedFuture<FenceResult> captureScreenshot( - const RenderAreaBuilderVariant& renderAreaBuilder, + const ScreenshotArgs& args, const std::shared_ptr<renderengine::ExternalTexture>& buffer, bool regionSampling, bool grayscale, bool isProtected, const sp<IScreenCaptureListener>& captureListener, const std::optional<OutputCompositionState>& displayState, @@ -890,8 +919,7 @@ private: const std::shared_ptr<renderengine::ExternalTexture>& gainmapBuffer = nullptr); ftl::SharedFuture<FenceResult> renderScreenImpl( - std::unique_ptr<const RenderArea> renderArea, - const std::shared_ptr<renderengine::ExternalTexture>&, + const ScreenshotArgs& args, const std::shared_ptr<renderengine::ExternalTexture>&, bool regionSampling, bool grayscale, bool isProtected, ScreenCaptureResults&, const std::optional<OutputCompositionState>& displayState, const std::vector<std::pair<Layer*, sp<LayerFE>>>& layers); diff --git a/services/surfaceflinger/common/include/common/WorkloadTracer.h b/services/surfaceflinger/common/include/common/WorkloadTracer.h index 39b6fa1bf4..c4074f72ff 100644 --- a/services/surfaceflinger/common/include/common/WorkloadTracer.h +++ b/services/surfaceflinger/common/include/common/WorkloadTracer.h @@ -23,7 +23,7 @@ namespace android::WorkloadTracer { static constexpr int32_t COMPOSITION_TRACE_COOKIE = 1; static constexpr int32_t POST_COMPOSITION_TRACE_COOKIE = 2; -static constexpr size_t COMPOSITION_SUMMARY_SIZE = 20; +static constexpr size_t COMPOSITION_SUMMARY_SIZE = 64; static constexpr const char* TRACK_NAME = "CriticalWorkload"; } // namespace android::WorkloadTracer
\ No newline at end of file diff --git a/services/surfaceflinger/tests/common/LayerLifecycleManagerHelper.h b/services/surfaceflinger/tests/common/LayerLifecycleManagerHelper.h index ee5d9193ea..7910e775f6 100644 --- a/services/surfaceflinger/tests/common/LayerLifecycleManagerHelper.h +++ b/services/surfaceflinger/tests/common/LayerLifecycleManagerHelper.h @@ -497,17 +497,6 @@ public: mLifecycleManager.applyTransactions(transactions); } - void setClientDrawnShadowRadius(uint32_t id, float clientDrawnShadowRadius) { - std::vector<QueuedTransactionState> transactions; - transactions.emplace_back(); - transactions.back().states.push_back({}); - - transactions.back().states.front().state.what = layer_state_t::eClientDrawnShadowsChanged; - transactions.back().states.front().layerId = id; - transactions.back().states.front().state.clientDrawnShadowRadius = clientDrawnShadowRadius; - mLifecycleManager.applyTransactions(transactions); - } - void setShadowRadius(uint32_t id, float shadowRadius) { std::vector<QueuedTransactionState> transactions; transactions.emplace_back(); diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp index 71cafbfd64..9ece312850 100644 --- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp +++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp @@ -36,7 +36,6 @@ #include <system/window.h> #include <utils/String8.h> -#include "DisplayRenderArea.h" #include "Layer.h" #include "TestableSurfaceFlinger.h" #include "mock/DisplayHardware/MockComposer.h" @@ -199,25 +198,21 @@ void CompositionTest::captureScreenComposition() { const Rect sourceCrop(0, 0, DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT); constexpr bool regionSampling = false; - auto renderArea = - DisplayRenderArea::create(mDisplay, sourceCrop, sourceCrop.getSize(), - ui::Dataspace::V0_SRGB, - RenderArea::Options::CAPTURE_SECURE_LAYERS | - RenderArea::Options::HINT_FOR_SEAMLESS_TRANSITION); - auto getLayerSnapshotsFn = mFlinger.getLayerSnapshotsForScreenshotsFn(mDisplay->getLayerStack(), CaptureArgs::UNSET_UID); const uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE; mCaptureScreenBuffer = - std::make_shared<renderengine::mock::FakeExternalTexture>(renderArea->getReqWidth(), - renderArea->getReqHeight(), + std::make_shared<renderengine::mock::FakeExternalTexture>(sourceCrop.getSize().width, + sourceCrop.getSize().height, HAL_PIXEL_FORMAT_RGBA_8888, 1, usage); - auto future = mFlinger.renderScreenImpl(mDisplay, std::move(renderArea), getLayerSnapshotsFn, - mCaptureScreenBuffer, regionSampling); + auto future = mFlinger.renderScreenImpl(mDisplay, sourceCrop, ui::Dataspace::V0_SRGB, + getLayerSnapshotsFn, mCaptureScreenBuffer, + regionSampling, mDisplay->isSecure(), + /* seamlessTransition */ true); ASSERT_TRUE(future.valid()); const auto fenceResult = future.get(); diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h index 3fead930cc..81bfc977db 100644 --- a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h +++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h @@ -193,7 +193,7 @@ struct DisplayIdGetter<PhysicalDisplayIdType<PhysicalDisplay>> { } }; -template <uint64_t displayId> +template <VirtualDisplayId::BaseId displayId> struct DisplayIdGetter<HalVirtualDisplayIdType<displayId>> { static HalVirtualDisplayId get() { return HalVirtualDisplayId(displayId); } }; diff --git a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp index 453c053eb5..7aad84b545 100644 --- a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp +++ b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp @@ -1505,14 +1505,6 @@ TEST_F(LayerSnapshotTest, childIgnoreCornerRadiusOverridesParent) { EXPECT_EQ(getSnapshot({.id = 111})->roundedCorner.radius.x, RADIUS); } -TEST_F(LayerSnapshotTest, ignoreShadows) { - static constexpr float SHADOW_RADIUS = 123.f; - setClientDrawnShadowRadius(1, SHADOW_RADIUS); - setShadowRadius(1, SHADOW_RADIUS); - UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER); - EXPECT_EQ(getSnapshot({.id = 1})->shadowSettings.length, 0.f); -} - TEST_F(LayerSnapshotTest, setShadowRadius) { static constexpr float SHADOW_RADIUS = 123.f; setShadowRadius(1, SHADOW_RADIUS); diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_CreateDisplayTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_CreateDisplayTest.cpp index 2d3ebb47bd..aadff760fe 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_CreateDisplayTest.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_CreateDisplayTest.cpp @@ -27,7 +27,8 @@ namespace { class CreateDisplayTest : public DisplayTransactionTest { public: - void createDisplayWithRequestedRefreshRate(const std::string& name, uint64_t displayId, + void createDisplayWithRequestedRefreshRate(const std::string& name, + VirtualDisplayId::BaseId baseId, float pacesetterDisplayRefreshRate, float requestedRefreshRate, float expectedAdjustedRefreshRate) { @@ -49,12 +50,10 @@ public: EXPECT_EQ(display.requestedRefreshRate, Fps::fromValue(requestedRefreshRate)); EXPECT_EQ(name.c_str(), display.displayName); - std::optional<VirtualDisplayId> vid = - DisplayId::fromValue<VirtualDisplayId>(displayId | DisplayId::FLAG_VIRTUAL); - ASSERT_TRUE(vid.has_value()); - + const VirtualDisplayId vid = GpuVirtualDisplayId(baseId); sp<DisplayDevice> device = - mFlinger.createVirtualDisplayDevice(displayToken, *vid, requestedRefreshRate); + mFlinger.createVirtualDisplayDevice(displayToken, vid, requestedRefreshRate); + EXPECT_TRUE(device->isVirtual()); device->adjustRefreshRate(Fps::fromValue(pacesetterDisplayRefreshRate)); // verifying desired value diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index 2353ef8db6..9a2e254ad9 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -42,7 +42,6 @@ #include "FrontEnd/RequestedLayerState.h" #include "Layer.h" #include "NativeWindowSurface.h" -#include "RenderArea.h" #include "Scheduler/RefreshRateSelector.h" #include "Scheduler/VSyncTracker.h" #include "Scheduler/VsyncController.h" @@ -461,11 +460,11 @@ public: return mFlinger->setPowerModeInternal(display, mode); } - auto renderScreenImpl(const sp<DisplayDevice> display, - std::unique_ptr<const RenderArea> renderArea, + auto renderScreenImpl(const sp<DisplayDevice> display, const Rect sourceCrop, + ui::Dataspace dataspace, SurfaceFlinger::GetLayerSnapshotsFunction getLayerSnapshotsFn, const std::shared_ptr<renderengine::ExternalTexture>& buffer, - bool regionSampling) { + bool regionSampling, bool isSecure, bool seamlessTransition) { Mutex::Autolock lock(mFlinger->mStateLock); ftl::FakeGuard guard(kMainThreadContext); @@ -473,7 +472,16 @@ public: auto displayState = std::optional{display->getCompositionDisplay()->getState()}; auto layers = getLayerSnapshotsFn(); - return mFlinger->renderScreenImpl(std::move(renderArea), buffer, regionSampling, + SurfaceFlinger::ScreenshotArgs screenshotArgs; + screenshotArgs.captureTypeVariant = display; + screenshotArgs.displayId = std::nullopt; + screenshotArgs.sourceCrop = sourceCrop; + screenshotArgs.reqSize = sourceCrop.getSize(); + screenshotArgs.dataspace = dataspace; + screenshotArgs.isSecure = isSecure; + screenshotArgs.seamlessTransition = seamlessTransition; + + return mFlinger->renderScreenImpl(screenshotArgs, buffer, regionSampling, false /* grayscale */, false /* isProtected */, captureResults, displayState, layers); } |