diff options
97 files changed, 2467 insertions, 847 deletions
diff --git a/cmds/lshal/libprocpartition/include/procpartition/procpartition.h b/cmds/lshal/libprocpartition/include/procpartition/procpartition.h index ca1e690694..9c0fc18697 100644 --- a/cmds/lshal/libprocpartition/include/procpartition/procpartition.h +++ b/cmds/lshal/libprocpartition/include/procpartition/procpartition.h @@ -27,6 +27,8 @@ namespace procpartition { enum class Partition { UNKNOWN = 0, SYSTEM, + SYSTEM_EXT, + PRODUCT, VENDOR, ODM }; diff --git a/cmds/lshal/libprocpartition/procpartition.cpp b/cmds/lshal/libprocpartition/procpartition.cpp index 9645f3a3f3..35fad577a4 100644 --- a/cmds/lshal/libprocpartition/procpartition.cpp +++ b/cmds/lshal/libprocpartition/procpartition.cpp @@ -24,6 +24,8 @@ namespace procpartition { std::ostream& operator<<(std::ostream& os, Partition p) { switch (p) { case Partition::SYSTEM: return os << "system"; + case Partition::SYSTEM_EXT: return os << "system_ext"; + case Partition::PRODUCT: return os << "product"; case Partition::VENDOR: return os << "vendor"; case Partition::ODM: return os << "odm"; case Partition::UNKNOWN: // fallthrough @@ -57,6 +59,12 @@ Partition parsePartition(const std::string& s) { if (s == "system") { return Partition::SYSTEM; } + if (s == "system_ext") { + return Partition::SYSTEM_EXT; + } + if (s == "product") { + return Partition::PRODUCT; + } if (s == "vendor") { return Partition::VENDOR; } diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp index 38a125bb54..59c4d53bc0 100644 --- a/cmds/servicemanager/ServiceManager.cpp +++ b/cmds/servicemanager/ServiceManager.cpp @@ -410,7 +410,16 @@ Status ServiceManager::getService2(const std::string& name, os::Service* outServ return Status::ok(); } -Status ServiceManager::checkService(const std::string& name, os::Service* outService) { +Status ServiceManager::checkService(const std::string& name, sp<IBinder>* outBinder) { + SM_PERFETTO_TRACE_FUNC(PERFETTO_TE_PROTO_FIELDS( + PERFETTO_TE_PROTO_FIELD_CSTR(kProtoServiceName, name.c_str()))); + + *outBinder = tryGetBinder(name, false).service; + // returns ok regardless of result for legacy reasons + return Status::ok(); +} + +Status ServiceManager::checkService2(const std::string& name, os::Service* outService) { SM_PERFETTO_TRACE_FUNC(PERFETTO_TE_PROTO_FIELDS( PERFETTO_TE_PROTO_FIELD_CSTR(kProtoServiceName, name.c_str()))); diff --git a/cmds/servicemanager/ServiceManager.h b/cmds/servicemanager/ServiceManager.h index 964abee6af..5c4d891218 100644 --- a/cmds/servicemanager/ServiceManager.h +++ b/cmds/servicemanager/ServiceManager.h @@ -46,7 +46,8 @@ public: // getService will try to start any services it cannot find binder::Status getService(const std::string& name, sp<IBinder>* outBinder) override; binder::Status getService2(const std::string& name, os::Service* outService) override; - binder::Status checkService(const std::string& name, os::Service* outService) override; + binder::Status checkService(const std::string& name, sp<IBinder>* outBinder) override; + binder::Status checkService2(const std::string& name, os::Service* outService) override; binder::Status addService(const std::string& name, const sp<IBinder>& binder, bool allowIsolated, int32_t dumpPriority) override; binder::Status listServices(int32_t dumpPriority, std::vector<std::string>* outList) override; diff --git a/cmds/servicemanager/test_sm.cpp b/cmds/servicemanager/test_sm.cpp index e620770e18..7ad84faca0 100644 --- a/cmds/servicemanager/test_sm.cpp +++ b/cmds/servicemanager/test_sm.cpp @@ -204,6 +204,11 @@ TEST(GetService, HappyHappy) { sp<IBinder> outBinder; EXPECT_TRUE(sm->getService("foo", &outBinder).isOk()); EXPECT_EQ(service, outBinder); + + EXPECT_TRUE(sm->checkService2("foo", &out).isOk()); + EXPECT_EQ(service, out.get<Service::Tag::serviceWithMetadata>().service); + EXPECT_TRUE(sm->checkService("foo", &outBinder).isOk()); + EXPECT_EQ(service, outBinder); } TEST(GetService, NonExistant) { diff --git a/include/android/surface_control_input_receiver.h b/include/android/surface_control_input_receiver.h index f0503f6324..59d3a31b30 100644 --- a/include/android/surface_control_input_receiver.h +++ b/include/android/surface_control_input_receiver.h @@ -39,11 +39,11 @@ __BEGIN_DECLS * * \param motionEvent The motion event. This must be released with AInputEvent_release. * + * \return true if the event is handled by the client, false otherwise. * Available since API level 35. */ typedef bool (*AInputReceiver_onMotionEvent)(void *_Null_unspecified context, - AInputEvent *_Nonnull motionEvent) - __INTRODUCED_IN(__ANDROID_API_V__); + AInputEvent *_Nonnull motionEvent); /** * The AInputReceiver_onKeyEvent callback is invoked when the registered input channel receives * a key event. @@ -53,11 +53,12 @@ typedef bool (*AInputReceiver_onMotionEvent)(void *_Null_unspecified context, * * \param keyEvent The key event. This must be released with AInputEvent_release. * + * \return true if the event is handled by the client, false otherwise. System may generate + * a fallback key event if the event is not handled. * Available since API level 35. */ typedef bool (*AInputReceiver_onKeyEvent)(void *_Null_unspecified context, - AInputEvent *_Nonnull keyEvent) - __INTRODUCED_IN(__ANDROID_API_V__); + AInputEvent *_Nonnull keyEvent); typedef struct AInputReceiverCallbacks AInputReceiverCallbacks; diff --git a/include/audiomanager/IAudioManager.h b/include/audiomanager/IAudioManager.h index a35a145084..b0641b826e 100644 --- a/include/audiomanager/IAudioManager.h +++ b/include/audiomanager/IAudioManager.h @@ -17,6 +17,7 @@ #ifndef ANDROID_IAUDIOMANAGER_H #define ANDROID_IAUDIOMANAGER_H +#include <android/media/IAudioManagerNative.h> #include <audiomanager/AudioManager.h> #include <utils/Errors.h> #include <binder/IInterface.h> @@ -34,20 +35,23 @@ public: // These transaction IDs must be kept in sync with the method order from // IAudioService.aidl. enum { - TRACK_PLAYER = IBinder::FIRST_CALL_TRANSACTION, - PLAYER_ATTRIBUTES = IBinder::FIRST_CALL_TRANSACTION + 1, - PLAYER_EVENT = IBinder::FIRST_CALL_TRANSACTION + 2, - RELEASE_PLAYER = IBinder::FIRST_CALL_TRANSACTION + 3, - TRACK_RECORDER = IBinder::FIRST_CALL_TRANSACTION + 4, - RECORDER_EVENT = IBinder::FIRST_CALL_TRANSACTION + 5, - RELEASE_RECORDER = IBinder::FIRST_CALL_TRANSACTION + 6, - PLAYER_SESSION_ID = IBinder::FIRST_CALL_TRANSACTION + 7, - PORT_EVENT = IBinder::FIRST_CALL_TRANSACTION + 8, - PERMISSION_UPDATE_BARRIER = IBinder::FIRST_CALL_TRANSACTION + 9, + GET_NATIVE_INTERFACE = IBinder::FIRST_CALL_TRANSACTION, + TRACK_PLAYER = IBinder::FIRST_CALL_TRANSACTION + 1, + PLAYER_ATTRIBUTES = IBinder::FIRST_CALL_TRANSACTION + 2, + PLAYER_EVENT = IBinder::FIRST_CALL_TRANSACTION + 3, + RELEASE_PLAYER = IBinder::FIRST_CALL_TRANSACTION + 4, + TRACK_RECORDER = IBinder::FIRST_CALL_TRANSACTION + 5, + RECORDER_EVENT = IBinder::FIRST_CALL_TRANSACTION + 6, + RELEASE_RECORDER = IBinder::FIRST_CALL_TRANSACTION + 7, + PLAYER_SESSION_ID = IBinder::FIRST_CALL_TRANSACTION + 8, + PORT_EVENT = IBinder::FIRST_CALL_TRANSACTION + 9, + PERMISSION_UPDATE_BARRIER = IBinder::FIRST_CALL_TRANSACTION + 10, }; DECLARE_META_INTERFACE(AudioManager) + virtual sp<media::IAudioManagerNative> getNativeInterface() = 0; + // The parcels created by these methods must be kept in sync with the // corresponding methods from IAudioService.aidl and objects it imports. virtual audio_unique_id_t trackPlayer(player_type_t playerType, audio_usage_t usage, diff --git a/include/ftl/finalizer.h b/include/ftl/finalizer.h new file mode 100644 index 0000000000..0251957ad0 --- /dev/null +++ b/include/ftl/finalizer.h @@ -0,0 +1,211 @@ +/* + * 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 <cstddef> + +#include <functional> +#include <type_traits> +#include <utility> + +#include <ftl/function.h> + +namespace android::ftl { + +// An RAII wrapper that invokes a function object as a finalizer when destroyed. +// +// The function object must take no arguments, and must return void. If the function object needs +// any context for the call, it must store it itself, for example with a lambda capture. +// +// The stored function object will be called once (unless canceled via the `cancel()` member +// function) at the first of: +// +// - The Finalizer instance is destroyed. +// - `operator()` is used to invoke the contained function. +// - The Finalizer instance is move-assigned a new value. The function being replaced will be +// invoked, and the replacement will be stored to be called later. +// +// The intent with this class is to keep cleanup code next to the code that requires that +// cleanup be performed. +// +// bool read_file(std::string filename) { +// FILE* f = fopen(filename.c_str(), "rb"); +// if (f == nullptr) return false; +// const auto cleanup = ftl::Finalizer([f]() { fclose(f); }); +// // fread(...), etc +// return true; +// } +// +// The `FinalFunction` template argument to Finalizer<FinalFunction> allows a polymorphic function +// type for storing the finalization function, such as `std::function` or `ftl::Function`. +// +// For convenience, this header defines a few useful aliases for using those types. +// +// - `FinalizerStd`, an alias for `Finalizer<std::function<void()>>` +// - `FinalizerFtl`, an alias for `Finalizer<ftl::Function<void()>>` +// - `FinalizerFtl1`, an alias for `Finalizer<ftl::Function<void(), 1>>` +// - `FinalizerFtl2`, an alias for `Finalizer<ftl::Function<void(), 2>>` +// - `FinalizerFtl3`, an alias for `Finalizer<ftl::Function<void(), 3>>` +// +// Clients of this header are free to define other aliases they need. +// +// A Finalizer that uses a polymorphic function type can be returned from a function call and/or +// stored as member data (to be destroyed along with the containing class). +// +// auto register(Observer* observer) -> ftl::FinalizerStd<void()> { +// const auto id = observers.add(observer); +// return ftl::Finalizer([id]() { observers.remove(id); }); +// } +// +// { +// const auto _ = register(observer); +// // do the things that required the registered observer. +// } +// // the observer is removed. +// +// Cautions: +// +// 1. When a Finalizer is stored as member data, you will almost certainly want that cleanup to +// happen first, before the rest of the other member data is destroyed. For safety you should +// assume that the finalization function will access that data directly or indirectly. +// +// This means that Finalizers should be defined last, after all other normal member data in a +// class. +// +// class MyClass { +// public: +// bool initialize() { +// ready_ = true; +// cleanup_ = ftl::Finalizer([this]() { ready_ = false; }); +// return true; +// } +// +// bool ready_ = false; +// +// // Finalizers should be last so other class members can be accessed before being +// // destroyed. +// ftl::FinalizerStd<void()> cleanup_; +// }; +// +// 2. Care must be taken to use `ftl::Finalizer()` when constructing locally from a lambda. If you +// forget to do so, you are just creating a lambda that won't be automatically invoked! +// +// const auto bad = [&counter](){ ++counter; }; // Just a lambda instance +// const auto good = ftl::Finalizer([&counter](){ ++counter; }); +// +template <typename FinalFunction> +class Finalizer final { + // requires(std::is_invocable_r_v<void, FinalFunction>) + static_assert(std::is_invocable_r_v<void, FinalFunction>); + + public: + // A default constructed Finalizer does nothing when destroyed. + // requires(std::is_default_constructible_v<FinalFunction>) + constexpr Finalizer() = default; + + // Constructs a Finalizer from a function object. + // requires(std::is_invocable_v<F>) + template <typename F, typename = std::enable_if_t<std::is_invocable_v<F>>> + [[nodiscard]] explicit constexpr Finalizer(F&& function) + : Finalizer(std::forward<F>(function), false) {} + + constexpr ~Finalizer() { maybe_invoke(); } + + // Disallow copying. + Finalizer(const Finalizer& that) = delete; + auto operator=(const Finalizer& that) = delete; + + // Move construction + // requires(std::is_move_constructible_v<FinalFunction>) + [[nodiscard]] constexpr Finalizer(Finalizer&& that) + : Finalizer(std::move(that.function_), std::exchange(that.canceled_, true)) {} + + // Implicit conversion move construction + // requires(!std::is_same_v<Finalizer, Finalizer<F>>) + template <typename F, typename = std::enable_if_t<!std::is_same_v<Finalizer, Finalizer<F>>>> + // NOLINTNEXTLINE(google-explicit-constructor, cppcoreguidelines-rvalue-reference-param-not-moved) + [[nodiscard]] constexpr Finalizer(Finalizer<F>&& that) + : Finalizer(std::move(that.function_), std::exchange(that.canceled_, true)) {} + + // Move assignment + // requires(std::is_move_assignable_v<FinalFunction>) + constexpr auto operator=(Finalizer&& that) -> Finalizer& { + maybe_invoke(); + + function_ = std::move(that.function_); + canceled_ = std::exchange(that.canceled_, true); + + return *this; + } + + // Implicit conversion move assignment + // requires(!std::is_same_v<Finalizer, Finalizer<F>>) + template <typename F, typename = std::enable_if_t<!std::is_same_v<Finalizer, Finalizer<F>>>> + // NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved) + constexpr auto operator=(Finalizer<F>&& that) -> Finalizer& { + *this = Finalizer(std::move(that.function_), std::exchange(that.canceled_, true)); + return *this; + } + + // Cancels the final function, preventing it from being invoked. + constexpr void cancel() { + canceled_ = true; + maybe_nullify_function(); + } + + // Invokes the final function now, if not already invoked. + constexpr void operator()() { maybe_invoke(); } + + private: + template <typename> + friend class Finalizer; + + template <typename F, typename = std::enable_if_t<std::is_invocable_v<F>>> + [[nodiscard]] explicit constexpr Finalizer(F&& function, bool canceled) + : function_(std::forward<F>(function)), canceled_(canceled) {} + + constexpr void maybe_invoke() { + if (!std::exchange(canceled_, true)) { + std::invoke(function_); + maybe_nullify_function(); + } + } + + constexpr void maybe_nullify_function() { + // Sets function_ to nullptr if that is supported for the backing type. + if constexpr (std::is_assignable_v<FinalFunction, nullptr_t>) { + function_ = nullptr; + } + } + + FinalFunction function_; + bool canceled_ = true; +}; + +template <typename F> +Finalizer(F&&) -> Finalizer<std::decay_t<F>>; + +// A standard alias for using `std::function` as the polymorphic function type. +using FinalizerStd = Finalizer<std::function<void()>>; + +// Helpful aliases for using `ftl::Function` as the polymorphic function type. +using FinalizerFtl = Finalizer<Function<void()>>; +using FinalizerFtl1 = Finalizer<Function<void(), 1>>; +using FinalizerFtl2 = Finalizer<Function<void(), 2>>; +using FinalizerFtl3 = Finalizer<Function<void(), 3>>; + +} // namespace android::ftl
\ No newline at end of file diff --git a/include/private/OWNERS b/include/private/OWNERS index 37da96d488..db3ae48698 100644 --- a/include/private/OWNERS +++ b/include/private/OWNERS @@ -1,3 +1,4 @@ # ADPF per-file thermal_private.h = file:platform/frameworks/base:/ADPF_OWNERS per-file performance_hint_private.h = file:platform/frameworks/base:/ADPF_OWNERS +per-file system_health_private.h = file:platform/frameworks/base:/ADPF_OWNERS diff --git a/libs/binder/BackendUnifiedServiceManager.cpp b/libs/binder/BackendUnifiedServiceManager.cpp index ee3d6af742..7c0319aead 100644 --- a/libs/binder/BackendUnifiedServiceManager.cpp +++ b/libs/binder/BackendUnifiedServiceManager.cpp @@ -215,7 +215,9 @@ Status BackendUnifiedServiceManager::getService(const ::std::string& name, sp<IBinder>* _aidl_return) { os::Service service; Status status = getService2(name, &service); - *_aidl_return = service.get<os::Service::Tag::serviceWithMetadata>().service; + if (status.isOk()) { + *_aidl_return = service.get<os::Service::Tag::serviceWithMetadata>().service; + } return status; } @@ -238,7 +240,17 @@ Status BackendUnifiedServiceManager::getService2(const ::std::string& name, os:: return status; } -Status BackendUnifiedServiceManager::checkService(const ::std::string& name, os::Service* _out) { +Status BackendUnifiedServiceManager::checkService(const ::std::string& name, + sp<IBinder>* _aidl_return) { + os::Service service; + Status status = checkService2(name, &service); + if (status.isOk()) { + *_aidl_return = service.get<os::Service::Tag::serviceWithMetadata>().service; + } + return status; +} + +Status BackendUnifiedServiceManager::checkService2(const ::std::string& name, os::Service* _out) { os::Service service; if (returnIfCached(name, _out)) { return Status::ok(); @@ -246,7 +258,7 @@ Status BackendUnifiedServiceManager::checkService(const ::std::string& name, os: Status status = Status::ok(); if (mTheRealServiceManager) { - status = mTheRealServiceManager->checkService(name, &service); + status = mTheRealServiceManager->checkService2(name, &service); } if (status.isOk()) { status = toBinderService(name, service, _out); diff --git a/libs/binder/BackendUnifiedServiceManager.h b/libs/binder/BackendUnifiedServiceManager.h index 2496f62503..c14f28063f 100644 --- a/libs/binder/BackendUnifiedServiceManager.h +++ b/libs/binder/BackendUnifiedServiceManager.h @@ -122,7 +122,8 @@ public: binder::Status getService(const ::std::string& name, sp<IBinder>* _aidl_return) override; binder::Status getService2(const ::std::string& name, os::Service* out) override; - binder::Status checkService(const ::std::string& name, os::Service* out) override; + binder::Status checkService(const ::std::string& name, sp<IBinder>* _aidl_return) override; + binder::Status checkService2(const ::std::string& name, os::Service* out) override; binder::Status addService(const ::std::string& name, const sp<IBinder>& service, bool allowIsolated, int32_t dumpPriority) override; binder::Status listServices(int32_t dumpPriority, diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp index 53bd08d420..0a22588a90 100644 --- a/libs/binder/Binder.cpp +++ b/libs/binder/Binder.cpp @@ -288,7 +288,7 @@ public: // for below objects RpcMutex mLock; std::set<sp<RpcServerLink>> mRpcServerLinks; - BpBinder::ObjectManager mObjects; + BpBinder::ObjectManager mObjectMgr; unique_fd mRecordingFd; }; @@ -468,7 +468,7 @@ void* BBinder::attachObject(const void* objectID, void* object, void* cleanupCoo LOG_ALWAYS_FATAL_IF(!e, "no memory"); RpcMutexUniqueLock _l(e->mLock); - return e->mObjects.attach(objectID, object, cleanupCookie, func); + return e->mObjectMgr.attach(objectID, object, cleanupCookie, func); } void* BBinder::findObject(const void* objectID) const @@ -477,7 +477,7 @@ void* BBinder::findObject(const void* objectID) const if (!e) return nullptr; RpcMutexUniqueLock _l(e->mLock); - return e->mObjects.find(objectID); + return e->mObjectMgr.find(objectID); } void* BBinder::detachObject(const void* objectID) { @@ -485,7 +485,7 @@ void* BBinder::detachObject(const void* objectID) { if (!e) return nullptr; RpcMutexUniqueLock _l(e->mLock); - return e->mObjects.detach(objectID); + return e->mObjectMgr.detach(objectID); } void BBinder::withLock(const std::function<void()>& doWithLock) { @@ -501,7 +501,7 @@ sp<IBinder> BBinder::lookupOrCreateWeak(const void* objectID, object_make_func m Extras* e = getOrCreateExtras(); LOG_ALWAYS_FATAL_IF(!e, "no memory"); RpcMutexUniqueLock _l(e->mLock); - return e->mObjects.lookupOrCreateWeak(objectID, make, makeArgs); + return e->mObjectMgr.lookupOrCreateWeak(objectID, make, makeArgs); } BBinder* BBinder::localBinder() diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp index 3758b6521c..444f06174e 100644 --- a/libs/binder/BpBinder.cpp +++ b/libs/binder/BpBinder.cpp @@ -78,7 +78,16 @@ BpBinder::ObjectManager::ObjectManager() BpBinder::ObjectManager::~ObjectManager() { - kill(); + const size_t N = mObjects.size(); + ALOGV("Killing %zu objects in manager %p", N, this); + for (auto i : mObjects) { + const entry_t& e = i.second; + if (e.func != nullptr) { + e.func(i.first, e.object, e.cleanupCookie); + } + } + + mObjects.clear(); } void* BpBinder::ObjectManager::attach(const void* objectID, void* object, void* cleanupCookie, @@ -144,20 +153,6 @@ sp<IBinder> BpBinder::ObjectManager::lookupOrCreateWeak(const void* objectID, ob return newObj; } -void BpBinder::ObjectManager::kill() -{ - const size_t N = mObjects.size(); - ALOGV("Killing %zu objects in manager %p", N, this); - for (auto i : mObjects) { - const entry_t& e = i.second; - if (e.func != nullptr) { - e.func(i.first, e.object, e.cleanupCookie); - } - } - - mObjects.clear(); -} - // --------------------------------------------------------------------------- sp<BpBinder> BpBinder::create(int32_t handle, std::function<void()>* postTask) { @@ -697,19 +692,19 @@ void BpBinder::reportOneDeath(const Obituary& obit) void* BpBinder::attachObject(const void* objectID, void* object, void* cleanupCookie, object_cleanup_func func) { RpcMutexUniqueLock _l(mLock); - ALOGV("Attaching object %p to binder %p (manager=%p)", object, this, &mObjects); - return mObjects.attach(objectID, object, cleanupCookie, func); + ALOGV("Attaching object %p to binder %p (manager=%p)", object, this, &mObjectMgr); + return mObjectMgr.attach(objectID, object, cleanupCookie, func); } void* BpBinder::findObject(const void* objectID) const { RpcMutexUniqueLock _l(mLock); - return mObjects.find(objectID); + return mObjectMgr.find(objectID); } void* BpBinder::detachObject(const void* objectID) { RpcMutexUniqueLock _l(mLock); - return mObjects.detach(objectID); + return mObjectMgr.detach(objectID); } void BpBinder::withLock(const std::function<void()>& doWithLock) { @@ -720,7 +715,7 @@ void BpBinder::withLock(const std::function<void()>& doWithLock) { sp<IBinder> BpBinder::lookupOrCreateWeak(const void* objectID, object_make_func make, const void* makeArgs) { RpcMutexUniqueLock _l(mLock); - return mObjects.lookupOrCreateWeak(objectID, make, makeArgs); + return mObjectMgr.lookupOrCreateWeak(objectID, make, makeArgs); } BpBinder* BpBinder::remoteBinder() diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp index 5c72ed3197..719e445794 100644 --- a/libs/binder/IServiceManager.cpp +++ b/libs/binder/IServiceManager.cpp @@ -624,7 +624,7 @@ sp<IBinder> CppBackendShim::getService(const String16& name) const { sp<IBinder> CppBackendShim::checkService(const String16& name) const { Service ret; - if (!mUnifiedServiceManager->checkService(String8(name).c_str(), &ret).isOk()) { + if (!mUnifiedServiceManager->checkService2(String8(name).c_str(), &ret).isOk()) { return nullptr; } return ret.get<Service::Tag::serviceWithMetadata>().service; diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp index 0b7cd8154d..c0ebee006b 100644 --- a/libs/binder/Parcel.cpp +++ b/libs/binder/Parcel.cpp @@ -1293,10 +1293,6 @@ status_t Parcel::writeUniqueFileDescriptorVector(const std::vector<unique_fd>& v status_t Parcel::writeUniqueFileDescriptorVector(const std::optional<std::vector<unique_fd>>& val) { return writeData(val); } -status_t Parcel::writeUniqueFileDescriptorVector( - const std::unique_ptr<std::vector<unique_fd>>& val) { - return writeData(val); -} status_t Parcel::writeStrongBinderVector(const std::vector<sp<IBinder>>& val) { return writeData(val); } status_t Parcel::writeStrongBinderVector(const std::optional<std::vector<sp<IBinder>>>& val) { return writeData(val); } @@ -1352,10 +1348,6 @@ status_t Parcel::readUtf8VectorFromUtf16Vector(std::vector<std::string>* val) co status_t Parcel::readUniqueFileDescriptorVector(std::optional<std::vector<unique_fd>>* val) const { return readData(val); } -status_t Parcel::readUniqueFileDescriptorVector( - std::unique_ptr<std::vector<unique_fd>>* val) const { - return readData(val); -} status_t Parcel::readUniqueFileDescriptorVector(std::vector<unique_fd>* val) const { return readData(val); } @@ -3397,14 +3389,6 @@ void Parcel::scanForFds() const { } #ifdef BINDER_WITH_KERNEL_IPC -size_t Parcel::getBlobAshmemSize() const -{ - // This used to return the size of all blobs that were written to ashmem, now we're returning - // the ashmem currently referenced by this Parcel, which should be equivalent. - // TODO(b/202029388): Remove method once ABI can be changed. - return getOpenAshmemSize(); -} - size_t Parcel::getOpenAshmemSize() const { auto* kernelFields = maybeKernelFields(); diff --git a/libs/binder/TEST_MAPPING b/libs/binder/TEST_MAPPING index 9e5e79f89b..4332f8ae79 100644 --- a/libs/binder/TEST_MAPPING +++ b/libs/binder/TEST_MAPPING @@ -37,6 +37,9 @@ "name": "binderStabilityTest" }, { + "name": "binderStabilityIntegrationTest" + }, + { "name": "binderRpcWireProtocolTest" }, { diff --git a/libs/binder/aidl/android/os/IServiceManager.aidl b/libs/binder/aidl/android/os/IServiceManager.aidl index 69edef86aa..6539238ce7 100644 --- a/libs/binder/aidl/android/os/IServiceManager.aidl +++ b/libs/binder/aidl/android/os/IServiceManager.aidl @@ -83,11 +83,20 @@ interface IServiceManager { /** * Retrieve an existing service called @a name from the service + * manager. Non-blocking. Returns null if the service does not exist. + * + * @deprecated TODO(b/355394904): Use checkService2 instead. This does not + * return metadata that is included in ServiceWithMetadata + */ + @UnsupportedAppUsage + @nullable IBinder checkService(@utf8InCpp String name); + + /** + * Retrieve an existing service called @a name from the service * manager. Non-blocking. Returns null if the service does not * exist. */ - @UnsupportedAppUsage - Service checkService(@utf8InCpp String name); + Service checkService2(@utf8InCpp String name); /** * Place a new @a service called @a name into the service diff --git a/libs/binder/include/binder/BpBinder.h b/libs/binder/include/binder/BpBinder.h index 7518044ce6..935bd8dbc6 100644 --- a/libs/binder/include/binder/BpBinder.h +++ b/libs/binder/include/binder/BpBinder.h @@ -104,6 +104,7 @@ public: // Stop the current recording. LIBBINDER_EXPORTED status_t stopRecordingBinder(); + // Note: This class is not thread safe so protect uses of it when necessary class ObjectManager { public: ObjectManager(); @@ -116,8 +117,6 @@ public: sp<IBinder> lookupOrCreateWeak(const void* objectID, IBinder::object_make_func make, const void* makeArgs); - void kill(); - private: ObjectManager(const ObjectManager&); ObjectManager& operator=(const ObjectManager&); @@ -224,7 +223,7 @@ private: volatile int32_t mObitsSent; Vector<Obituary>* mObituaries; std::unique_ptr<FrozenStateChange> mFrozen; - ObjectManager mObjects; + ObjectManager mObjectMgr; mutable String16 mDescriptorCache; int32_t mTrackedUid; diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h index 69a73d415e..6c4c6fe573 100644 --- a/libs/binder/include/binder/Parcel.h +++ b/libs/binder/include/binder/Parcel.h @@ -383,9 +383,6 @@ public: LIBBINDER_EXPORTED status_t writeUniqueFileDescriptorVector(const std::optional<std::vector<binder::unique_fd>>& val); LIBBINDER_EXPORTED status_t - writeUniqueFileDescriptorVector(const std::unique_ptr<std::vector<binder::unique_fd>>& val) - __attribute__((deprecated("use std::optional version instead"))); - LIBBINDER_EXPORTED status_t writeUniqueFileDescriptorVector(const std::vector<binder::unique_fd>& val); // WARNING: deprecated and incompatible with AIDL. You should use Parcelable @@ -630,9 +627,6 @@ public: LIBBINDER_EXPORTED status_t readUniqueFileDescriptorVector(std::optional<std::vector<binder::unique_fd>>* val) const; LIBBINDER_EXPORTED status_t - readUniqueFileDescriptorVector(std::unique_ptr<std::vector<binder::unique_fd>>* val) const - __attribute__((deprecated("use std::optional version instead"))); - LIBBINDER_EXPORTED status_t readUniqueFileDescriptorVector(std::vector<binder::unique_fd>* val) const; // WARNING: deprecated and incompatible with AIDL. You should use Parcelable @@ -1494,14 +1488,15 @@ public: * Note: for historical reasons, this does not include ashmem memory which * is referenced by this Parcel, but which this parcel doesn't own (e.g. * writeFileDescriptor is called without 'takeOwnership' true). + * + * WARNING: you should not use this, but rather, unparcel, and inspect + * each FD independently. This counts ashmem size, but there may be + * other resources used for non-ashmem FDs, such as other types of + * shared memory, files, etc.. */ LIBBINDER_EXPORTED size_t getOpenAshmemSize() const; private: - // TODO(b/202029388): Remove 'getBlobAshmemSize' once no prebuilts reference - // this - LIBBINDER_EXPORTED size_t getBlobAshmemSize() const; - // Needed so that we can save object metadata to the disk friend class android::binder::debug::RecordedTransaction; }; diff --git a/libs/binder/include/binder/Stability.h b/libs/binder/include/binder/Stability.h index cafb8aa04b..bfe0a5af9c 100644 --- a/libs/binder/include/binder/Stability.h +++ b/libs/binder/include/binder/Stability.h @@ -20,6 +20,8 @@ #include <binder/IBinder.h> #include <string> +class BinderStabilityIntegrationTest_ExpectedStabilityForItsPartition_Test; + namespace android { class BpBinder; @@ -127,6 +129,8 @@ private: // through Parcel) friend ::android::ProcessState; + friend ::BinderStabilityIntegrationTest_ExpectedStabilityForItsPartition_Test; + static void tryMarkCompilationUnit(IBinder* binder); // Currently, we use int16_t for Level so that it can fit in BBinder. @@ -156,11 +160,11 @@ private: uint32_t flags); // get stability information as encoded on the wire - static int16_t getRepr(IBinder* binder); + LIBBINDER_EXPORTED static int16_t getRepr(IBinder* binder); // whether a transaction on binder is allowed, if the transaction // is done from a context with a specific stability level - static bool check(int16_t provided, Level required); + LIBBINDER_EXPORTED static bool check(int16_t provided, Level required); static bool isDeclaredLevel(int32_t level); static std::string levelString(int32_t level); diff --git a/libs/binder/servicedispatcher.cpp b/libs/binder/servicedispatcher.cpp index be990657d5..78fe2a8714 100644 --- a/libs/binder/servicedispatcher.cpp +++ b/libs/binder/servicedispatcher.cpp @@ -127,7 +127,12 @@ public: // We can't send BpBinder for regular binder over RPC. return android::binder::Status::fromStatusT(android::INVALID_OPERATION); } - android::binder::Status checkService(const std::string&, android::os::Service*) override { + android::binder::Status checkService(const std::string&, + android::sp<android::IBinder>*) override { + // We can't send BpBinder for regular binder over RPC. + return android::binder::Status::fromStatusT(android::INVALID_OPERATION); + } + android::binder::Status checkService2(const std::string&, android::os::Service*) override { // We can't send BpBinder for regular binder over RPC. return android::binder::Status::fromStatusT(android::INVALID_OPERATION); } diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp index c21d7c61cd..f412dfb6f4 100644 --- a/libs/binder/tests/Android.bp +++ b/libs/binder/tests/Android.bp @@ -803,6 +803,28 @@ cc_test { } cc_test { + name: "binderStabilityIntegrationTest", + defaults: ["binder_test_defaults"], + srcs: [ + "binderStabilityIntegrationTest.cpp", + ], + + shared_libs: [ + "libbinder", + "libutils", + ], + static_libs: [ + "libprocpartition", + ], + + test_suites: [ + "general-tests", + "vts", + ], + require_root: true, +} + +cc_test { name: "binderAllocationLimits", defaults: ["binder_test_defaults"], srcs: ["binderAllocationLimits.cpp"], diff --git a/libs/binder/tests/binderCacheUnitTest.cpp b/libs/binder/tests/binderCacheUnitTest.cpp index 19395c2dcd..121e5ae5e9 100644 --- a/libs/binder/tests/binderCacheUnitTest.cpp +++ b/libs/binder/tests/binderCacheUnitTest.cpp @@ -74,7 +74,7 @@ class MockAidlServiceManager : public os::IServiceManagerDefault { public: MockAidlServiceManager() : innerSm() {} - binder::Status checkService(const ::std::string& name, os::Service* _out) override { + binder::Status checkService2(const ::std::string& name, os::Service* _out) override { os::ServiceWithMetadata serviceWithMetadata = os::ServiceWithMetadata(); serviceWithMetadata.service = innerSm.getService(String16(name.c_str())); serviceWithMetadata.isLazyService = false; @@ -98,7 +98,7 @@ class MockAidlServiceManager2 : public os::IServiceManagerDefault { public: MockAidlServiceManager2() : innerSm() {} - binder::Status checkService(const ::std::string& name, os::Service* _out) override { + binder::Status checkService2(const ::std::string& name, os::Service* _out) override { os::ServiceWithMetadata serviceWithMetadata = os::ServiceWithMetadata(); serviceWithMetadata.service = innerSm.getService(String16(name.c_str())); serviceWithMetadata.isLazyService = true; diff --git a/libs/binder/tests/binderSafeInterfaceTest.cpp b/libs/binder/tests/binderSafeInterfaceTest.cpp index 7d1556e7d2..45b2103637 100644 --- a/libs/binder/tests/binderSafeInterfaceTest.cpp +++ b/libs/binder/tests/binderSafeInterfaceTest.cpp @@ -858,7 +858,13 @@ TEST_F(SafeInterfaceTest, TestIncrementTwo) { ASSERT_EQ(b + 1, bPlusOne); } -extern "C" int main(int argc, char **argv) { +} // namespace tests +} // namespace android + +int main(int argc, char** argv) { + using namespace android; + using namespace android::tests; + testing::InitGoogleTest(&argc, argv); if (fork() == 0) { @@ -875,6 +881,3 @@ extern "C" int main(int argc, char **argv) { return RUN_ALL_TESTS(); } - -} // namespace tests -} // namespace android diff --git a/libs/binder/tests/binderStabilityIntegrationTest.cpp b/libs/binder/tests/binderStabilityIntegrationTest.cpp new file mode 100644 index 0000000000..a3fc9cc2c8 --- /dev/null +++ b/libs/binder/tests/binderStabilityIntegrationTest.cpp @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2025 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 <binder/Binder.h> +#include <binder/IServiceManager.h> +#include <binder/Stability.h> +#include <gtest/gtest.h> +#include <procpartition/procpartition.h> + +using namespace android; +using android::internal::Stability; // for testing only! +using android::procpartition::getPartition; +using android::procpartition::Partition; + +class BinderStabilityIntegrationTest : public testing::Test, + public ::testing::WithParamInterface<String16> { +public: + virtual ~BinderStabilityIntegrationTest() {} +}; + +TEST_P(BinderStabilityIntegrationTest, ExpectedStabilityForItsPartition) { + const String16& serviceName = GetParam(); + + sp<IBinder> binder = defaultServiceManager()->checkService(serviceName); + if (!binder) GTEST_SKIP() << "Could not get service, may have gone away."; + + pid_t pid; + status_t res = binder->getDebugPid(&pid); + if (res != OK) { + GTEST_SKIP() << "Could not talk to service to get PID, res: " << statusToString(res); + } + + Partition partition = getPartition(pid); + + Stability::Level level = Stability::Level::UNDECLARED; + switch (partition) { + case Partition::SYSTEM: + case Partition::SYSTEM_EXT: + level = Stability::Level::SYSTEM; + break; + case Partition::VENDOR: + case Partition::ODM: + level = Stability::Level::VENDOR; + break; + case Partition::UNKNOWN: + GTEST_SKIP() << "Not sure of partition of process."; + return; + default: + ADD_FAILURE() << "Unrecognized partition for service: " << partition; + return; + } + + ASSERT_TRUE(Stability::check(Stability::getRepr(binder.get()), level)) + << "Binder hosted on partition " << partition + << " should have corresponding stability set."; +} + +std::string PrintTestParam( + const testing::TestParamInfo<BinderStabilityIntegrationTest::ParamType>& info) { + std::string name = String8(info.param).c_str(); + for (size_t i = 0; i < name.size(); i++) { + bool alnum = false; + alnum |= (name[i] >= 'a' && name[i] <= 'z'); + alnum |= (name[i] >= 'A' && name[i] <= 'Z'); + alnum |= (name[i] >= '0' && name[i] <= '9'); + alnum |= (name[i] == '_'); + if (!alnum) name[i] = '_'; + } + + // index for uniqueness + return std::to_string(info.index) + "__" + name; +} + +INSTANTIATE_TEST_CASE_P(RegisteredServices, BinderStabilityIntegrationTest, + ::testing::ValuesIn(defaultServiceManager()->listServices()), + PrintTestParam); diff --git a/libs/binder/tests/parcel_fuzzer/binder.cpp b/libs/binder/tests/parcel_fuzzer/binder.cpp index 401c2749ef..b2ba1ae38d 100644 --- a/libs/binder/tests/parcel_fuzzer/binder.cpp +++ b/libs/binder/tests/parcel_fuzzer/binder.cpp @@ -317,8 +317,6 @@ std::vector<ParcelRead<::android::Parcel>> BINDER_PARCEL_READ_FUNCTIONS { PARCEL_READ_NO_STATUS(int, readParcelFileDescriptor), PARCEL_READ_WITH_STATUS(unique_fd, readUniqueFileDescriptor), - PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<unique_fd>>, - readUniqueFileDescriptorVector), PARCEL_READ_WITH_STATUS(std::optional<std::vector<unique_fd>>, readUniqueFileDescriptorVector), PARCEL_READ_WITH_STATUS(std::vector<unique_fd>, readUniqueFileDescriptorVector), diff --git a/libs/binderdebug/stats.cpp b/libs/binderdebug/stats.cpp index 9c26afaa97..972fbd5295 100644 --- a/libs/binderdebug/stats.cpp +++ b/libs/binderdebug/stats.cpp @@ -22,9 +22,9 @@ #include <inttypes.h> -namespace android { +int main() { + using namespace android; -extern "C" int main() { // ignore args - we only print csv // we should use a csv library here for escaping, because @@ -58,5 +58,3 @@ extern "C" int main() { } return 0; } - -} // namespace android diff --git a/libs/binderdebug/tests/binderdebug_test.cpp b/libs/binderdebug/tests/binderdebug_test.cpp index ea799c06a2..ad2b581abc 100644 --- a/libs/binderdebug/tests/binderdebug_test.cpp +++ b/libs/binderdebug/tests/binderdebug_test.cpp @@ -60,8 +60,15 @@ TEST(BinderDebugTests, BinderThreads) { EXPECT_GE(pidInfo.threadCount, 1); } -extern "C" { +} // namespace test +} // namespace binderdebug +} // namespace android + int main(int argc, char** argv) { + using namespace android; + using namespace android::binderdebug; + using namespace android::binderdebug::test; + ::testing::InitGoogleTest(&argc, argv); // Create a child/client process to call into the main process so we can ensure @@ -84,7 +91,3 @@ int main(int argc, char** argv) { return RUN_ALL_TESTS(); } -} // extern "C" -} // namespace test -} // namespace binderdebug -} // namespace android diff --git a/libs/ftl/Android.bp b/libs/ftl/Android.bp index 368f5e079c..08ce855c2b 100644 --- a/libs/ftl/Android.bp +++ b/libs/ftl/Android.bp @@ -21,6 +21,7 @@ cc_test { "enum_test.cpp", "expected_test.cpp", "fake_guard_test.cpp", + "finalizer_test.cpp", "flags_test.cpp", "function_test.cpp", "future_test.cpp", diff --git a/libs/ftl/finalizer_test.cpp b/libs/ftl/finalizer_test.cpp new file mode 100644 index 0000000000..4f5c2258db --- /dev/null +++ b/libs/ftl/finalizer_test.cpp @@ -0,0 +1,209 @@ +/* + * 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. + */ + +#include <memory> +#include <type_traits> +#include <utility> + +#include <ftl/finalizer.h> +#include <gtest/gtest.h> + +namespace android::test { + +namespace { + +struct Counter { + constexpr auto increment_fn() { + return [this] { ++value_; }; + } + + auto increment_finalizer() { + return ftl::Finalizer([this] { ++value_; }); + } + + [[nodiscard]] constexpr auto value() const -> int { return value_; } + + private: + int value_ = 0; +}; + +struct CounterPair { + constexpr auto increment_first_fn() { return first.increment_fn(); } + constexpr auto increment_second_fn() { return second.increment_fn(); } + [[nodiscard]] constexpr auto values() const -> std::pair<int, int> { + return {first.value(), second.value()}; + } + + private: + Counter first; + Counter second; +}; + +} // namespace + +TEST(Finalizer, DefaultConstructionAndNoOpDestructionWhenPolymorphicType) { + ftl::FinalizerStd finalizer1; + ftl::FinalizerFtl finalizer2; + ftl::FinalizerFtl1 finalizer3; + ftl::FinalizerFtl2 finalizer4; + ftl::FinalizerFtl3 finalizer5; +} + +TEST(Finalizer, InvokesTheFunctionOnDestruction) { + Counter counter; + { + const auto finalizer = counter.increment_finalizer(); + EXPECT_EQ(counter.value(), 0); + } + EXPECT_EQ(counter.value(), 1); +} + +TEST(Finalizer, InvocationCanBeCanceled) { + Counter counter; + { + auto finalizer = counter.increment_finalizer(); + EXPECT_EQ(counter.value(), 0); + finalizer.cancel(); + EXPECT_EQ(counter.value(), 0); + } + EXPECT_EQ(counter.value(), 0); +} + +TEST(Finalizer, InvokesTheFunctionOnce) { + Counter counter; + { + auto finalizer = counter.increment_finalizer(); + EXPECT_EQ(counter.value(), 0); + finalizer(); + EXPECT_EQ(counter.value(), 1); + finalizer(); + EXPECT_EQ(counter.value(), 1); + } + EXPECT_EQ(counter.value(), 1); +} + +TEST(Finalizer, SelfInvocationIsAllowedAndANoOp) { + Counter counter; + ftl::FinalizerStd finalizer; + finalizer = ftl::Finalizer([&]() { + counter.increment_fn()(); + finalizer(); // recursive invocation should do nothing. + }); + EXPECT_EQ(counter.value(), 0); + finalizer(); + EXPECT_EQ(counter.value(), 1); +} + +TEST(Finalizer, MoveConstruction) { + Counter counter; + { + ftl::FinalizerStd outer_finalizer = counter.increment_finalizer(); + EXPECT_EQ(counter.value(), 0); + { + ftl::FinalizerStd inner_finalizer = std::move(outer_finalizer); + static_assert(std::is_same_v<decltype(inner_finalizer), decltype(outer_finalizer)>); + EXPECT_EQ(counter.value(), 0); + } + EXPECT_EQ(counter.value(), 1); + } + EXPECT_EQ(counter.value(), 1); +} + +TEST(Finalizer, MoveConstructionWithImplicitConversion) { + Counter counter; + { + auto outer_finalizer = counter.increment_finalizer(); + EXPECT_EQ(counter.value(), 0); + { + ftl::FinalizerStd inner_finalizer = std::move(outer_finalizer); + static_assert(!std::is_same_v<decltype(inner_finalizer), decltype(outer_finalizer)>); + EXPECT_EQ(counter.value(), 0); + } + EXPECT_EQ(counter.value(), 1); + } + EXPECT_EQ(counter.value(), 1); +} + +TEST(Finalizer, MoveAssignment) { + CounterPair pair; + { + ftl::FinalizerStd outer_finalizer = ftl::Finalizer(pair.increment_first_fn()); + EXPECT_EQ(pair.values(), std::make_pair(0, 0)); + + { + ftl::FinalizerStd inner_finalizer = ftl::Finalizer(pair.increment_second_fn()); + static_assert(std::is_same_v<decltype(inner_finalizer), decltype(outer_finalizer)>); + EXPECT_EQ(pair.values(), std::make_pair(0, 0)); + inner_finalizer = std::move(outer_finalizer); + EXPECT_EQ(pair.values(), std::make_pair(0, 1)); + } + EXPECT_EQ(pair.values(), std::make_pair(1, 1)); + } + EXPECT_EQ(pair.values(), std::make_pair(1, 1)); +} + +TEST(Finalizer, MoveAssignmentWithImplicitConversion) { + CounterPair pair; + { + auto outer_finalizer = ftl::Finalizer(pair.increment_first_fn()); + EXPECT_EQ(pair.values(), std::make_pair(0, 0)); + + { + ftl::FinalizerStd inner_finalizer = ftl::Finalizer(pair.increment_second_fn()); + static_assert(!std::is_same_v<decltype(inner_finalizer), decltype(outer_finalizer)>); + EXPECT_EQ(pair.values(), std::make_pair(0, 0)); + inner_finalizer = std::move(outer_finalizer); + EXPECT_EQ(pair.values(), std::make_pair(0, 1)); + } + EXPECT_EQ(pair.values(), std::make_pair(1, 1)); + } + EXPECT_EQ(pair.values(), std::make_pair(1, 1)); +} + +TEST(Finalizer, NullifiesTheFunctionWhenInvokedIfPossible) { + auto shared = std::make_shared<int>(0); + std::weak_ptr<int> weak = shared; + + int count = 0; + { + auto lambda = [capture = std::move(shared)]() {}; + auto finalizer = ftl::Finalizer(std::move(lambda)); + EXPECT_FALSE(weak.expired()); + + // A lambda is not nullable. Invoking the finalizer cannot destroy it to destroy the lambda's + // capture. + finalizer(); + EXPECT_FALSE(weak.expired()); + } + // The lambda is only destroyed when the finalizer instance is destroyed. + EXPECT_TRUE(weak.expired()); + + shared = std::make_shared<int>(0); + weak = shared; + + { + auto lambda = [capture = std::move(shared)]() {}; + auto finalizer = ftl::FinalizerStd(std::move(lambda)); + EXPECT_FALSE(weak.expired()); + + // Since std::function is used, and is nullable, invoking the finalizer will destroy the + // contained function, which will destroy the lambda's capture. + finalizer(); + EXPECT_TRUE(weak.expired()); + } +} + +} // namespace android::test diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp index a8d5fe7371..4874dbde9c 100644 --- a/libs/graphicsenv/GraphicsEnv.cpp +++ b/libs/graphicsenv/GraphicsEnv.cpp @@ -596,7 +596,7 @@ bool GraphicsEnv::shouldUseAngle() { // If path is set to nonempty and shouldUseNativeDriver is true, ANGLE will be used regardless. void GraphicsEnv::setAngleInfo(const std::string& path, const bool shouldUseNativeDriver, const std::string& packageName, - const std::vector<std::string> eglFeatures) { + const std::vector<std::string>& eglFeatures) { if (mShouldUseAngle) { // ANGLE is already set up for this application process, even if the application // needs to switch from apk to system or vice versa, the application process must @@ -606,11 +606,11 @@ void GraphicsEnv::setAngleInfo(const std::string& path, const bool shouldUseNati return; } - mAngleEglFeatures = std::move(eglFeatures); + mAngleEglFeatures = eglFeatures; ALOGV("setting ANGLE path to '%s'", path.c_str()); - mAnglePath = std::move(path); + mAnglePath = path; ALOGV("setting app package name to '%s'", packageName.c_str()); - mPackageName = std::move(packageName); + mPackageName = packageName; if (mAnglePath == "system") { mShouldUseSystemAngle = true; } diff --git a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h index b0ab0b9d22..452e48bb75 100644 --- a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h +++ b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h @@ -114,7 +114,7 @@ public: // If shouldUseNativeDriver is true, it means native GLES drivers must be used for the process. // If path is set to nonempty and shouldUseNativeDriver is true, ANGLE will be used regardless. void setAngleInfo(const std::string& path, const bool shouldUseNativeDriver, - const std::string& packageName, const std::vector<std::string> eglFeatures); + const std::string& packageName, const std::vector<std::string>& eglFeatures); // Get the ANGLE driver namespace. android_namespace_t* getAngleNamespace(); // Get the app package name. diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index c1a03fcfea..44aac9bfae 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -66,6 +66,8 @@ layer_state_t::layer_state_t() mask(0), reserved(0), cornerRadius(0.0f), + clientDrawnCornerRadius(0.0f), + clientDrawnShadowRadius(0.0f), backgroundBlurRadius(0), color(0), bufferTransform(0), @@ -140,6 +142,8 @@ 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); @@ -274,6 +278,8 @@ 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); @@ -596,6 +602,14 @@ void layer_state_t::merge(const layer_state_t& other) { what |= eCornerRadiusChanged; cornerRadius = other.cornerRadius; } + if (other.what & eClientDrawnCornerRadiusChanged) { + what |= eClientDrawnCornerRadiusChanged; + clientDrawnCornerRadius = other.clientDrawnCornerRadius; + } + if (other.what & eClientDrawnShadowsChanged) { + what |= eClientDrawnShadowsChanged; + clientDrawnShadowRadius = other.clientDrawnShadowRadius; + } if (other.what & eBackgroundBlurRadiusChanged) { what |= eBackgroundBlurRadiusChanged; backgroundBlurRadius = other.backgroundBlurRadius; @@ -809,6 +823,8 @@ 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 cabde22c6d..2beeae0201 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -1695,6 +1695,29 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setCorne return *this; } +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setClientDrawnCornerRadius( + const sp<SurfaceControl>& sc, float clientDrawnCornerRadius) { + layer_state_t* s = getLayerState(sc); + if (!s) { + mStatus = BAD_INDEX; + return *this; + } + s->what |= layer_state_t::eClientDrawnCornerRadiusChanged; + s->clientDrawnCornerRadius = clientDrawnCornerRadius; + 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/WindowInfo.cpp b/libs/gui/WindowInfo.cpp index 82d2554340..3fb66d1f33 100644 --- a/libs/gui/WindowInfo.cpp +++ b/libs/gui/WindowInfo.cpp @@ -59,6 +59,32 @@ std::ostream& operator<<(std::ostream& out, const Region& region) { return out; } +status_t writeTransform(android::Parcel* parcel, const ui::Transform& transform) { + return parcel->writeFloat(transform.dsdx()) ?: + parcel->writeFloat(transform.dtdx()) ?: + parcel->writeFloat(transform.tx()) ?: + parcel->writeFloat(transform.dtdy()) ?: + parcel->writeFloat(transform.dsdy()) ?: + parcel->writeFloat(transform.ty()); +} + +status_t readTransform(const android::Parcel* parcel, ui::Transform& transform) { + float dsdx, dtdx, tx, dtdy, dsdy, ty; + + const status_t status = parcel->readFloat(&dsdx) ?: + parcel->readFloat(&dtdx) ?: + parcel->readFloat(&tx) ?: + parcel->readFloat(&dtdy) ?: + parcel->readFloat(&dsdy) ?: + parcel->readFloat(&ty); + if (status != OK) { + return status; + } + + transform.set({dsdx, dtdx, tx, dtdy, dsdy, ty, 0, 0, 1}); + return OK; +} + } // namespace void WindowInfo::setInputConfig(ftl::Flags<InputConfig> config, bool value) { @@ -73,10 +99,6 @@ void WindowInfo::addTouchableRegion(const Rect& region) { touchableRegion.orSelf(region); } -bool WindowInfo::supportsSplitTouch() const { - return !inputConfig.test(InputConfig::PREVENT_SPLITTING); -} - bool WindowInfo::isSpy() const { return inputConfig.test(InputConfig::SPY); } @@ -135,12 +157,7 @@ status_t WindowInfo::writeToParcel(android::Parcel* parcel) const { parcel->writeInt32(surfaceInset) ?: parcel->writeFloat(globalScaleFactor) ?: parcel->writeFloat(alpha) ?: - parcel->writeFloat(transform.dsdx()) ?: - parcel->writeFloat(transform.dtdx()) ?: - parcel->writeFloat(transform.tx()) ?: - parcel->writeFloat(transform.dtdy()) ?: - parcel->writeFloat(transform.dsdy()) ?: - parcel->writeFloat(transform.ty()) ?: + writeTransform(parcel, transform) ?: parcel->writeInt32(static_cast<int32_t>(touchOcclusionMode)) ?: parcel->writeInt32(ownerPid.val()) ?: parcel->writeInt32(ownerUid.val()) ?: @@ -153,8 +170,12 @@ status_t WindowInfo::writeToParcel(android::Parcel* parcel) const { parcel->writeStrongBinder(touchableRegionCropHandle.promote()) ?: parcel->writeStrongBinder(windowToken) ?: parcel->writeStrongBinder(focusTransferTarget) ?: - parcel->writeBool(canOccludePresentation); + parcel->writeBool(canOccludePresentation) ?: + parcel->writeBool(cloneLayerStackTransform.has_value()); // clang-format on + if (cloneLayerStackTransform) { + status = status ?: writeTransform(parcel, *cloneLayerStackTransform); + } return status; } @@ -174,10 +195,10 @@ status_t WindowInfo::readFromParcel(const android::Parcel* parcel) { return status; } - float dsdx, dtdx, tx, dtdy, dsdy, ty; int32_t lpFlags, lpType, touchOcclusionModeInt, inputConfigInt, ownerPidInt, ownerUidInt, displayIdInt; sp<IBinder> touchableRegionCropHandleSp; + bool hasCloneLayerStackTransform = false; // clang-format off status = parcel->readInt32(&lpFlags) ?: @@ -188,12 +209,7 @@ status_t WindowInfo::readFromParcel(const android::Parcel* parcel) { parcel->readInt32(&surfaceInset) ?: parcel->readFloat(&globalScaleFactor) ?: parcel->readFloat(&alpha) ?: - parcel->readFloat(&dsdx) ?: - parcel->readFloat(&dtdx) ?: - parcel->readFloat(&tx) ?: - parcel->readFloat(&dtdy) ?: - parcel->readFloat(&dsdy) ?: - parcel->readFloat(&ty) ?: + readTransform(parcel, /*byRef*/ transform) ?: parcel->readInt32(&touchOcclusionModeInt) ?: parcel->readInt32(&ownerPidInt) ?: parcel->readInt32(&ownerUidInt) ?: @@ -206,8 +222,8 @@ status_t WindowInfo::readFromParcel(const android::Parcel* parcel) { parcel->readNullableStrongBinder(&touchableRegionCropHandleSp) ?: parcel->readNullableStrongBinder(&windowToken) ?: parcel->readNullableStrongBinder(&focusTransferTarget) ?: - parcel->readBool(&canOccludePresentation); - + parcel->readBool(&canOccludePresentation)?: + parcel->readBool(&hasCloneLayerStackTransform); // clang-format on if (status != OK) { @@ -216,7 +232,6 @@ status_t WindowInfo::readFromParcel(const android::Parcel* parcel) { layoutParamsFlags = ftl::Flags<Flag>(lpFlags); layoutParamsType = static_cast<Type>(lpType); - transform.set({dsdx, dtdx, tx, dtdy, dsdy, ty, 0, 0, 1}); touchOcclusionMode = static_cast<TouchOcclusionMode>(touchOcclusionModeInt); inputConfig = ftl::Flags<InputConfig>(inputConfigInt); ownerPid = Pid{ownerPidInt}; @@ -224,6 +239,15 @@ status_t WindowInfo::readFromParcel(const android::Parcel* parcel) { touchableRegionCropHandle = touchableRegionCropHandleSp; displayId = ui::LogicalDisplayId{displayIdInt}; + cloneLayerStackTransform = + hasCloneLayerStackTransform ? std::make_optional<ui::Transform>() : std::nullopt; + if (cloneLayerStackTransform) { + status = readTransform(parcel, /*byRef*/ *cloneLayerStackTransform); + if (status != OK) { + return status; + } + } + return OK; } diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index 64f191b867..100261423a 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -231,6 +231,8 @@ struct layer_state_t { eBufferReleaseChannelChanged = 0x40000'00000000, ePictureProfileHandleChanged = 0x80000'00000000, eAppContentPriorityChanged = 0x100000'00000000, + eClientDrawnCornerRadiusChanged = 0x200000'00000000, + eClientDrawnShadowsChanged = 0x400000'00000000, }; layer_state_t(); @@ -251,9 +253,9 @@ struct layer_state_t { // Geometry updates. static constexpr uint64_t GEOMETRY_CHANGES = layer_state_t::eBufferCropChanged | layer_state_t::eBufferTransformChanged | layer_state_t::eCornerRadiusChanged | - layer_state_t::eCropChanged | layer_state_t::eDestinationFrameChanged | - layer_state_t::eMatrixChanged | layer_state_t::ePositionChanged | - layer_state_t::eTransformToDisplayInverseChanged | + layer_state_t::eClientDrawnCornerRadiusChanged | layer_state_t::eCropChanged | + layer_state_t::eDestinationFrameChanged | layer_state_t::eMatrixChanged | + layer_state_t::ePositionChanged | layer_state_t::eTransformToDisplayInverseChanged | layer_state_t::eTransparentRegionChanged | layer_state_t::eEdgeExtensionChanged; // Buffer and related updates. @@ -274,8 +276,8 @@ 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::eStretchChanged | layer_state_t::ePictureProfileHandleChanged | - layer_state_t::eAppContentPriorityChanged; + layer_state_t::eClientDrawnShadowsChanged | layer_state_t::eStretchChanged | + layer_state_t::ePictureProfileHandleChanged | layer_state_t::eAppContentPriorityChanged; // Changes which invalidates the layer's visible region in CE. static constexpr uint64_t CONTENT_DIRTY = layer_state_t::CONTENT_CHANGES | @@ -300,6 +302,11 @@ struct layer_state_t { static constexpr uint64_t VISIBLE_REGION_CHANGES = layer_state_t::GEOMETRY_CHANGES | layer_state_t::HIERARCHY_CHANGES | layer_state_t::eAlphaChanged; + // Changes that force GPU composition. + static constexpr uint64_t COMPOSITION_EFFECTS = layer_state_t::eBackgroundBlurRadiusChanged | + layer_state_t::eBlurRegionsChanged | layer_state_t::eCornerRadiusChanged | + layer_state_t::eShadowRadiusChanged | layer_state_t::eStretchChanged; + bool hasValidBuffer() const; void sanitize(int32_t permissions); @@ -328,6 +335,8 @@ struct layer_state_t { uint8_t reserved; 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 0f66c8b492..d20b3460b5 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -567,6 +567,15 @@ public: Transaction& setCrop(const sp<SurfaceControl>& sc, const Rect& crop); Transaction& setCrop(const sp<SurfaceControl>& sc, const FloatRect& crop); Transaction& setCornerRadius(const sp<SurfaceControl>& sc, float cornerRadius); + // Sets the client drawn corner radius for the layer. If both a corner radius and a client + // radius are sent to SF, the client radius will be used. This indicates that the corner + // 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/gui/include/gui/WindowInfo.h b/libs/gui/include/gui/WindowInfo.h index eb3be5588a..420dc2103f 100644 --- a/libs/gui/include/gui/WindowInfo.h +++ b/libs/gui/include/gui/WindowInfo.h @@ -150,8 +150,6 @@ struct WindowInfo : public Parcelable { static_cast<uint32_t>(os::InputConfig::NOT_FOCUSABLE), NOT_TOUCHABLE = static_cast<uint32_t>(os::InputConfig::NOT_TOUCHABLE), - PREVENT_SPLITTING = - static_cast<uint32_t>(os::InputConfig::PREVENT_SPLITTING), DUPLICATE_TOUCH_TO_WALLPAPER = static_cast<uint32_t>(os::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER), IS_WALLPAPER = @@ -220,9 +218,14 @@ struct WindowInfo : public Parcelable { // An alpha of 1.0 means fully opaque and 0.0 means fully transparent. float alpha; - // Transform applied to individual windows. + // Transform applied to individual windows for input. + // Maps display coordinates to the window's input coordinate space. ui::Transform transform; + // Transform applied to get to the layer stack space of the cloned window for input. + // Maps display coordinates of the clone window to the layer stack space of the cloned window. + std::optional<ui::Transform> cloneLayerStackTransform; + /* * This is filled in by the WM relative to the frame and then translated * to absolute coordinates by SurfaceFlinger once the frame is computed. diff --git a/libs/gui/libgui_flags.aconfig b/libs/gui/libgui_flags.aconfig index 6bf38c05f1..394a5cf5c5 100644 --- a/libs/gui/libgui_flags.aconfig +++ b/libs/gui/libgui_flags.aconfig @@ -138,4 +138,7 @@ flag { description: "Remove BufferQueueProducer::dequeue's wait on this fence (or the fence entirely) to prevent deadlocks" bug: "339705065" is_fixed_read_only: true + metadata { + purpose: PURPOSE_BUGFIX + } } # bq_gl_fence_cleanup diff --git a/libs/gui/tests/WindowInfo_test.cpp b/libs/gui/tests/WindowInfo_test.cpp index ce22082a9f..e3f9a07b34 100644 --- a/libs/gui/tests/WindowInfo_test.cpp +++ b/libs/gui/tests/WindowInfo_test.cpp @@ -40,7 +40,18 @@ TEST(WindowInfo, ParcellingWithoutToken) { ASSERT_EQ(OK, i.writeToParcel(&p)); p.setDataPosition(0); i2.readFromParcel(&p); - ASSERT_TRUE(i2.token == nullptr); + ASSERT_EQ(i2.token, nullptr); +} + +TEST(WindowInfo, ParcellingWithoutCloneTransform) { + WindowInfo i, i2; + i.cloneLayerStackTransform.reset(); + + Parcel p; + ASSERT_EQ(OK, i.writeToParcel(&p)); + p.setDataPosition(0); + i2.readFromParcel(&p); + ASSERT_EQ(i2.cloneLayerStackTransform, std::nullopt); } TEST(WindowInfo, Parcelling) { @@ -71,6 +82,8 @@ TEST(WindowInfo, Parcelling) { i.applicationInfo.token = new BBinder(); i.applicationInfo.dispatchingTimeoutMillis = 0x12345678ABCD; i.focusTransferTarget = new BBinder(); + i.cloneLayerStackTransform = ui::Transform(); + i.cloneLayerStackTransform->set({5, -1, 100, 4, 0, 40, 0, 0, 1}); Parcel p; i.writeToParcel(&p); @@ -100,6 +113,7 @@ TEST(WindowInfo, Parcelling) { ASSERT_EQ(i.touchableRegionCropHandle, i2.touchableRegionCropHandle); ASSERT_EQ(i.applicationInfo, i2.applicationInfo); ASSERT_EQ(i.focusTransferTarget, i2.focusTransferTarget); + ASSERT_EQ(i.cloneLayerStackTransform, i2.cloneLayerStackTransform); } TEST(InputApplicationInfo, Parcelling) { diff --git a/libs/input/android/os/InputConfig.aidl b/libs/input/android/os/InputConfig.aidl index da62e03821..e5f7b56561 100644 --- a/libs/input/android/os/InputConfig.aidl +++ b/libs/input/android/os/InputConfig.aidl @@ -57,16 +57,9 @@ enum InputConfig { NOT_TOUCHABLE = 1 << 3, /** - * Indicates that this window will not accept a touch event that is split between - * more than one window. When set: - * - If this window receives a DOWN event with the first pointer, all successive - * pointers that go down, regardless of their location on the screen, will be - * directed to this window; - * - If the DOWN event lands outside the touchable bounds of this window, no - * successive pointers that go down, regardless of their location on the screen, - * will be directed to this window. - */ - PREVENT_SPLITTING = 1 << 4, + * This flag is now deprecated and should not be used. + */ + DEPRECATED_PREVENT_SPLITTING = 1 << 4, /** * Indicates that this window shows the wallpaper behind it, so all touch events diff --git a/libs/input/input_flags.aconfig b/libs/input/input_flags.aconfig index 6cdd249b9e..bf928f4847 100644 --- a/libs/input/input_flags.aconfig +++ b/libs/input/input_flags.aconfig @@ -37,9 +37,9 @@ flag { } flag { - name: "split_all_touches" + name: "deprecate_split_touch_apis" namespace: "input" - description: "Set FLAG_SPLIT_TOUCHES to true for all windows, regardless of what they specify. This is essentially deprecating this flag by forcefully enabling the split functionality" + description: "Deprecate all public APIs related to split touch because now all windows behave as if split touch is permanently enabled and there's no way for a window to disable split touch." bug: "239934827" } @@ -188,6 +188,16 @@ flag { } flag { + name: "disable_touch_input_mapper_pointer_usage" + namespace: "input" + description: "Disable the PointerUsage concept in TouchInputMapper since the old touchpad stack is no longer used." + bug: "281840344" + metadata { + purpose: PURPOSE_BUGFIX + } +} + +flag { name: "keyboard_repeat_keys" namespace: "input" description: "Allow user to enable key repeats or configure timeout before key repeat and key repeat delay rates." @@ -224,3 +234,13 @@ flag { description: "Allow cursor to transition across multiple connected displays" bug: "362719483" } + +flag { + name: "use_cloned_screen_coordinates_as_raw" + namespace: "input" + description: "Use the cloned window's layer stack (screen) space as the raw coordinate space for input going to clones" + bug: "377846505" + metadata { + purpose: PURPOSE_BUGFIX + } +} diff --git a/libs/renderengine/skia/compat/GraphiteGpuContext.cpp b/libs/renderengine/skia/compat/GraphiteGpuContext.cpp index 69f583226b..7a72d09804 100644 --- a/libs/renderengine/skia/compat/GraphiteGpuContext.cpp +++ b/libs/renderengine/skia/compat/GraphiteGpuContext.cpp @@ -110,8 +110,40 @@ bool GraphiteGpuContext::isAbandonedOrDeviceLost() { return mContext->isDeviceLost(); } +void GraphiteGpuContext::setResourceCacheLimit(size_t maxResourceBytes) { + // Graphite has a separate budget for its Context and its Recorder. For now the majority of + // memory that Graphite will allocate will be on the Recorder and minimal amount on the Context. + // The main allocations on the Context are MSAA buffers (not often, if ever used in + // RenderEngine) and stencil buffers. However, both of these should be "memoryless" in Vulkan on + // tiled GPUs, so they don't actually use GPU memory. However, in Vulkan there are scenarios + // where Vulkan could end up using real memory for them. Skia will regularly query the device to + // get the real memory usage and update the budgeted appropriately. Though for all real usage + // patterns we don't expect to ever trigger the device to allocate real memory. + // + // Therefore, we set the full maxResourceBytes budget on the Recorder. However, in the rare + // chance that the devcies does allocate real memory we don't want to immediately kill device + // performance by constantly trashing allocations on the Context. Thus we set the Context's + // budget to be 50% of the total budget to make sure we allow the MSAA or Stencil buffers to be + // allocated in Skia and not immediately discarded. But even with this extra 50% budget, as + // described above, this shouldn't result in actual GPU memory usage. + // + // TODO: We will need to revise this strategy for GLES which does not have the same memoryless + // textures. + // TODO: Work in Graphite has started to move a lot more of its scratch resources to be owned + // by the Context and not on Recorders. This will mean most memory is actually owned by the + // Context and thus the budgeting here will need to be updated. + mContext->setMaxBudgetedBytes(maxResourceBytes / 2); + mRecorder->setMaxBudgetedBytes(maxResourceBytes); +} + +void GraphiteGpuContext::purgeUnlockedScratchResources() { + mContext->freeGpuResources(); + mRecorder->freeGpuResources(); +} + void GraphiteGpuContext::dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const { mContext->dumpMemoryStatistics(traceMemoryDump); + mRecorder->dumpMemoryStatistics(traceMemoryDump); } } // namespace android::renderengine::skia diff --git a/libs/renderengine/skia/compat/GraphiteGpuContext.h b/libs/renderengine/skia/compat/GraphiteGpuContext.h index 413817ffff..57da796af5 100644 --- a/libs/renderengine/skia/compat/GraphiteGpuContext.h +++ b/libs/renderengine/skia/compat/GraphiteGpuContext.h @@ -39,16 +39,10 @@ public: size_t getMaxRenderTargetSize() const override; size_t getMaxTextureSize() const override; bool isAbandonedOrDeviceLost() override; - // No-op (large resources like textures, surfaces, images, etc. created by clients don't count - // towards Graphite's internal caching budgets, so adjusting its limits based on display change - // events should be unnecessary. Additionally, Graphite doesn't expose many cache tweaking - // functions yet, as its design may evolve.) - void setResourceCacheLimit(size_t maxResourceBytes) override{}; - // TODO: b/293371537 - Triple-check and validate that no cleanup is necessary when switching - // contexts. - // No-op (unnecessary during context switch for Graphite's client-budgeted memory model). - void purgeUnlockedScratchResources() override{}; + void setResourceCacheLimit(size_t maxResourceBytes) override; + void purgeUnlockedScratchResources() override; + // No-op (only applicable to GL). void resetContextIfApplicable() override{}; diff --git a/libs/renderengine/skia/filters/KawaseBlurDualFilter.cpp b/libs/renderengine/skia/filters/KawaseBlurDualFilter.cpp index 750e08fa55..ef57c30563 100644 --- a/libs/renderengine/skia/filters/KawaseBlurDualFilter.cpp +++ b/libs/renderengine/skia/filters/KawaseBlurDualFilter.cpp @@ -118,9 +118,12 @@ sk_sp<SkImage> KawaseBlurDualFilter::generate(SkiaGpuContext* context, const uin const int filterPasses = std::min(kMaxSurfaces - 1, static_cast<int>(ceil(filterDepth))); auto makeSurface = [&](float scale) -> sk_sp<SkSurface> { - const auto newW = static_cast<float>(blurRect.width() / scale); - const auto newH = static_cast<float>(blurRect.height() / scale); - return context->createRenderTarget(input->imageInfo().makeWH(newW, newH)); + const auto newW = ceil(static_cast<float>(blurRect.width() / scale)); + const auto newH = ceil(static_cast<float>(blurRect.height() / scale)); + sk_sp<SkSurface> surface = + context->createRenderTarget(input->imageInfo().makeWH(newW, newH)); + LOG_ALWAYS_FATAL_IF(!surface, "%s: Failed to create surface for blurring!", __func__); + return surface; }; // Render into surfaces downscaled by 1x, 2x, and 4x from the initial downscale. diff --git a/libs/ui/include/ui/ShadowSettings.h b/libs/ui/include/ui/ShadowSettings.h index c0b83b8691..06be6dbbf5 100644 --- a/libs/ui/include/ui/ShadowSettings.h +++ b/libs/ui/include/ui/ShadowSettings.h @@ -46,6 +46,9 @@ 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; @@ -55,6 +58,7 @@ 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/services/audiomanager/Android.bp b/services/audiomanager/Android.bp index d11631b783..afcdf742c9 100644 --- a/services/audiomanager/Android.bp +++ b/services/audiomanager/Android.bp @@ -15,6 +15,7 @@ cc_library { ], shared_libs: [ + "av-types-aidl-cpp", "libutils", "libbinder", "liblog", diff --git a/services/audiomanager/IAudioManager.cpp b/services/audiomanager/IAudioManager.cpp index f8a38d1e38..99360b9a14 100644 --- a/services/audiomanager/IAudioManager.cpp +++ b/services/audiomanager/IAudioManager.cpp @@ -35,6 +35,24 @@ public: { } + // This should never fail + virtual sp<media::IAudioManagerNative> getNativeInterface() { + Parcel data, reply; + data.writeInterfaceToken(IAudioManager::getInterfaceDescriptor()); + const status_t res = remote()->transact(GET_NATIVE_INTERFACE, data, &reply, 0); + LOG_ALWAYS_FATAL_IF(res != OK, "%s failed with result %d", __func__, res); + const int ex = reply.readExceptionCode(); + LOG_ALWAYS_FATAL_IF(ex != binder::Status::EX_NONE, "%s failed with exception %d", + __func__, + ex); + sp<IBinder> binder; + const status_t err = reply.readNullableStrongBinder(&binder); + LOG_ALWAYS_FATAL_IF(binder == nullptr, "%s failed unexpected nullptr %d", __func__, err); + const auto iface = checked_interface_cast<media::IAudioManagerNative>(std::move(binder)); + LOG_ALWAYS_FATAL_IF(iface == nullptr, "%s failed unexpected interface", __func__); + return iface; + } + virtual audio_unique_id_t trackPlayer(player_type_t playerType, audio_usage_t usage, audio_content_type_t content, const sp<IBinder>& player, audio_session_t sessionId) { Parcel data, reply; diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 0b1e849bc7..266e691153 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -418,7 +418,7 @@ std::unique_ptr<DispatchEntry> createDispatchEntry(const IdGenerator& idGenerato if (inputTarget.useDefaultPointerTransform() && !zeroCoords) { const ui::Transform& transform = inputTarget.getDefaultPointerTransform(); return std::make_unique<DispatchEntry>(eventEntry, inputTargetFlags, transform, - inputTarget.displayTransform, + inputTarget.rawTransform, inputTarget.globalScaleFactor, uid, vsyncId, windowId); } @@ -439,7 +439,7 @@ std::unique_ptr<DispatchEntry> createDispatchEntry(const IdGenerator& idGenerato transform = &inputTarget.getTransformForPointer(firstMarkedBit(inputTarget.getPointerIds())); const ui::Transform inverseTransform = transform->inverse(); - displayTransform = &inputTarget.displayTransform; + displayTransform = &inputTarget.rawTransform; // Iterate through all pointers in the event to normalize against the first. for (size_t i = 0; i < motionEntry.getPointerCount(); i++) { @@ -788,38 +788,14 @@ void filterUntrustedTargets(TouchState& touchState, std::vector<InputTarget>& ta }); } -/** - * In general, touch should be always split between windows. Some exceptions: - * 1. Don't split touch if all of the below is true: - * (a) we have an active pointer down *and* - * (b) a new pointer is going down that's from the same device *and* - * (c) the window that's receiving the current pointer does not support split touch. - * 2. Don't split mouse events - */ -bool shouldSplitTouch(const TouchState& touchState, const MotionEntry& entry) { - if (isFromSource(entry.source, AINPUT_SOURCE_MOUSE)) { - // We should never split mouse events - return false; - } - for (const TouchedWindow& touchedWindow : touchState.windows) { - if (touchedWindow.windowHandle->getInfo()->isSpy()) { - // Spy windows should not affect whether or not touch is split. - continue; - } - if (touchedWindow.windowHandle->getInfo()->supportsSplitTouch()) { - continue; - } - if (touchedWindow.windowHandle->getInfo()->inputConfig.test( - gui::WindowInfo::InputConfig::IS_WALLPAPER)) { - // Wallpaper window should not affect whether or not touch is split - continue; - } - - if (touchedWindow.hasTouchingPointers(entry.deviceId)) { - return false; - } - } - return true; +bool shouldSplitTouch(int32_t source) { + // We should never split mouse events. This is because the events that are produced by touchpad + // are sent to InputDispatcher as two fingers (for example, pinch zoom), but they need to be + // dispatched to the same window. In those cases, the behaviour is also slightly different from + // default because the events should be sent to the cursor position rather than the x,y values + // of each of the fingers. + // The "normal" (uncaptured) events produced by touchpad and by mouse have SOURCE_MOUSE. + return !isFromSource(source, AINPUT_SOURCE_MOUSE); } /** @@ -929,7 +905,7 @@ InputTarget createInputTarget(const std::shared_ptr<Connection>& connection, const sp<android::gui::WindowInfoHandle>& windowHandle, InputTarget::DispatchMode dispatchMode, ftl::Flags<InputTarget::Flags> targetFlags, - const ui::Transform& displayTransform, + const ui::Transform& rawTransform, std::optional<nsecs_t> firstDownTimeInTarget) { LOG_ALWAYS_FATAL_IF(connection == nullptr); InputTarget inputTarget{connection}; @@ -937,11 +913,26 @@ InputTarget createInputTarget(const std::shared_ptr<Connection>& connection, inputTarget.dispatchMode = dispatchMode; inputTarget.flags = targetFlags; inputTarget.globalScaleFactor = windowHandle->getInfo()->globalScaleFactor; - inputTarget.displayTransform = displayTransform; + inputTarget.rawTransform = rawTransform; inputTarget.firstDownTimeInTarget = firstDownTimeInTarget; return inputTarget; } +std::string dumpWindowForTouchOcclusion(const WindowInfo& info, bool isTouchedWindow) { + return StringPrintf(INDENT2 "* %spackage=%s/%s, id=%" PRId32 ", mode=%s, alpha=%.2f, " + "frame=[%" PRId32 ",%" PRId32 "][%" PRId32 ",%" PRId32 + "], touchableRegion=%s, window={%s}, inputConfig={%s}, " + "hasToken=%s, applicationInfo.name=%s, applicationInfo.token=%s\n", + isTouchedWindow ? "[TOUCHED] " : "", info.packageName.c_str(), + info.ownerUid.toString().c_str(), info.id, + toString(info.touchOcclusionMode).c_str(), info.alpha, info.frame.left, + info.frame.top, info.frame.right, info.frame.bottom, + dumpRegion(info.touchableRegion).c_str(), info.name.c_str(), + info.inputConfig.string().c_str(), toString(info.token != nullptr), + info.applicationInfo.name.c_str(), + binderToString(info.applicationInfo.token).c_str()); +} + } // namespace // --- InputDispatcher --- @@ -952,16 +943,17 @@ InputDispatcher::InputDispatcher(InputDispatcherPolicyInterface& policy) InputDispatcher::InputDispatcher(InputDispatcherPolicyInterface& policy, std::unique_ptr<trace::InputTracingBackendInterface> traceBackend) : mPolicy(policy), + mLooper(sp<Looper>::make(false)), mPendingEvent(nullptr), mLastDropReason(DropReason::NOT_DROPPED), mIdGenerator(IdGenerator::Source::INPUT_DISPATCHER), mMinTimeBetweenUserActivityPokes(DEFAULT_USER_ACTIVITY_POKE_INTERVAL), + mConnectionManager(mLooper), mNextUnblockedEvent(nullptr), mMonitorDispatchingTimeout(DEFAULT_INPUT_DISPATCHING_TIMEOUT), mDispatchEnabled(false), mDispatchFrozen(false), mInputFilterEnabled(false), - mMaximumObscuringOpacityForTouch(1.0f), mFocusedDisplayId(ui::LogicalDisplayId::DEFAULT), mWindowTokenWithPointerCapture(nullptr), mAwaitedApplicationDisplayId(ui::LogicalDisplayId::INVALID), @@ -972,7 +964,6 @@ InputDispatcher::InputDispatcher(InputDispatcherPolicyInterface& policy, : std::move(std::unique_ptr<InputEventTimelineProcessor>( new LatencyAggregator()))), mLatencyTracker(*mInputEventTimelineProcessor) { - mLooper = sp<Looper>::make(false); mReporter = createInputReporter(); mWindowInfoListener = sp<DispatcherWindowListener>::make(*this); @@ -995,11 +986,6 @@ InputDispatcher::~InputDispatcher() { releasePendingEventLocked(); drainInboundQueueLocked(); mCommandQueue.clear(); - - while (!mConnectionsByToken.empty()) { - std::shared_ptr<Connection> connection = mConnectionsByToken.begin()->second; - removeInputChannelLocked(connection->getToken(), /*notify=*/false); - } } status_t InputDispatcher::start() { @@ -1116,7 +1102,8 @@ nsecs_t InputDispatcher::processAnrsLocked() { } // If we reached here, we have an unresponsive connection. - std::shared_ptr<Connection> connection = getConnectionLocked(mAnrTracker.firstToken()); + std::shared_ptr<Connection> connection = + mConnectionManager.getConnection(mAnrTracker.firstToken()); if (connection == nullptr) { ALOGE("Could not find connection for entry %" PRId64, mAnrTracker.firstTimeout()); return nextAnrCheck; @@ -1368,7 +1355,7 @@ bool InputDispatcher::shouldPruneInboundQueueLocked(const MotionEntry& motionEnt motionEntry.deviceId, mTouchStatesByDisplay); for (const auto& windowHandle : touchedSpies) { const std::shared_ptr<Connection> connection = - getConnectionLocked(windowHandle->getToken()); + mConnectionManager.getConnection(windowHandle->getToken()); if (connection != nullptr && connection->responsive) { // This spy window could take more input. Drop all events preceding this // event, so that the spy window can get a chance to receive the stream. @@ -1528,20 +1515,8 @@ std::vector<sp<WindowInfoHandle>> InputDispatcher::DispatcherWindowInfo::findTou const WindowInfo& info = *windowHandle->getInfo(); if (!windowAcceptsTouchAt(info, displayId, x, y, isStylus, getDisplayTransform(displayId))) { - // Generally, we would skip any pointer that's outside of the window. However, if the - // spy prevents splitting, and already has some of the pointers from this device, then - // it should get more pointers from the same device, even if they are outside of that - // window - if (info.supportsSplitTouch()) { - continue; - } - - // We know that split touch is not supported. Skip this window only if it doesn't have - // any touching pointers for this device already. - if (!windowHasTouchingPointers(windowHandle, deviceId, touchStatesByDisplay)) { - continue; - } - // If it already has pointers down for this device, then give it this pointer, too. + // Skip if the pointer is outside of the window. + continue; } if (!info.isSpy()) { // The first touched non-spy window was found, so return the spy windows touched so far. @@ -1763,7 +1738,8 @@ void InputDispatcher::enqueueFocusEventLocked(const sp<IBinder>& windowToken, bo void InputDispatcher::dispatchFocusLocked(nsecs_t currentTime, std::shared_ptr<const FocusEntry> entry) { - std::shared_ptr<Connection> connection = getConnectionLocked(entry->connectionToken); + std::shared_ptr<Connection> connection = + mConnectionManager.getConnection(entry->connectionToken); if (connection == nullptr) { return; // Connection has gone away } @@ -1831,7 +1807,7 @@ void InputDispatcher::dispatchPointerCaptureChangedLocked( } } - auto connection = getConnectionLocked(token); + auto connection = mConnectionManager.getConnection(token); if (connection == nullptr) { // Window has gone away, clean up Pointer Capture state. mWindowTokenWithPointerCapture = nullptr; @@ -1870,7 +1846,7 @@ std::vector<InputTarget> InputDispatcher::getInputTargetsFromWindowHandlesLocked if (token == nullptr) { continue; } - std::shared_ptr<Connection> connection = getConnectionLocked(token); + std::shared_ptr<Connection> connection = mConnectionManager.getConnection(token); if (connection == nullptr) { continue; // Connection has gone away } @@ -1994,7 +1970,8 @@ bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, std::shared_ptr<con InputTarget::Flags::FOREGROUND, getDownTime(*entry), inputTargets); // Add monitor channels from event's or focused display. - addGlobalMonitoringTargetsLocked(inputTargets, getTargetDisplayId(*entry)); + ui::LogicalDisplayId displayId = getTargetDisplayId(*entry); + addGlobalMonitoringTargetsLocked(inputTargets, displayId); if (mTracer) { ensureEventTraced(*entry); @@ -2136,7 +2113,8 @@ bool InputDispatcher::dispatchMotionLocked(nsecs_t currentTime, } // Add monitor channels from event's or focused display. - addGlobalMonitoringTargetsLocked(inputTargets, getTargetDisplayId(*entry)); + ui::LogicalDisplayId displayId = getTargetDisplayId(*entry); + addGlobalMonitoringTargetsLocked(inputTargets, displayId); if (mTracer) { ensureEventTraced(*entry); @@ -2163,7 +2141,8 @@ void InputDispatcher::enqueueDragEventLocked(const sp<WindowInfoHandle>& windowH void InputDispatcher::dispatchDragLocked(nsecs_t currentTime, std::shared_ptr<const DragEntry> entry) { - std::shared_ptr<Connection> connection = getConnectionLocked(entry->connectionToken); + std::shared_ptr<Connection> connection = + mConnectionManager.getConnection(entry->connectionToken); if (connection == nullptr) { return; // Connection has gone away } @@ -2407,26 +2386,6 @@ InputDispatcher::findFocusedWindowTargetLocked(nsecs_t currentTime, const EventE return focusedWindowHandle; } -/** - * Given a list of monitors, remove the ones we cannot find a connection for, and the ones - * that are currently unresponsive. - */ -std::vector<Monitor> InputDispatcher::selectResponsiveMonitorsLocked( - const std::vector<Monitor>& monitors) const { - std::vector<Monitor> responsiveMonitors; - std::copy_if(monitors.begin(), monitors.end(), std::back_inserter(responsiveMonitors), - [](const Monitor& monitor) REQUIRES(mLock) { - std::shared_ptr<Connection> connection = monitor.connection; - if (!connection->responsive) { - ALOGW("Unresponsive monitor %s will not get the new gesture", - connection->getInputChannelName().c_str()); - return false; - } - return true; - }); - return responsiveMonitors; -} - base::Result<std::vector<InputTarget>, android::os::InputEventInjectionResult> InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, const MotionEntry& entry) { ATRACE_CALL(); @@ -2448,7 +2407,7 @@ InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, const Motio tempTouchState = *oldState; } - bool isSplit = shouldSplitTouch(tempTouchState, entry); + bool isSplit = shouldSplitTouch(entry.source); const bool isHoverAction = (maskedAction == AMOTION_EVENT_ACTION_HOVER_MOVE || maskedAction == AMOTION_EVENT_ACTION_HOVER_ENTER || @@ -2501,17 +2460,6 @@ InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, const Motio LOG_IF(INFO, newTouchedWindowHandle == nullptr) << "No new touched window at (" << std::format("{:.1f}, {:.1f}", x, y) << ") in display " << displayId; - // Handle the case where we did not find a window. - if (!input_flags::split_all_touches()) { - // If we are force splitting all touches, then touches outside of the window should - // be dropped, even if this device already has pointers down in another window. - if (newTouchedWindowHandle == nullptr) { - // Try to assign the pointer to the first foreground window we find, if there is - // one. - newTouchedWindowHandle = - tempTouchState.getFirstForegroundWindowHandle(entry.deviceId); - } - } // Verify targeted injection. if (const auto err = verifyTargetedInjection(newTouchedWindowHandle, entry); err) { @@ -2519,24 +2467,7 @@ InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, const Motio return injectionError(InputEventInjectionResult::TARGET_MISMATCH); } - // Figure out whether splitting will be allowed for this window. - if (newTouchedWindowHandle != nullptr) { - if (newTouchedWindowHandle->getInfo()->supportsSplitTouch()) { - // New window supports splitting, but we should never split mouse events. - isSplit = !isFromMouse; - } else if (isSplit) { - // New window does not support splitting but we have already split events. - // Ignore the new window. - LOG(INFO) << "Skipping " << newTouchedWindowHandle->getName() - << " because it doesn't support split touch"; - newTouchedWindowHandle = nullptr; - } - } else { - // No window is touched, so set split to true. This will allow the next pointer down to - // be delivered to a new window which supports split touch. Pointers from a mouse device - // should never be split. - isSplit = !isFromMouse; - } + isSplit = !isFromMouse; std::vector<sp<WindowInfoHandle>> newTouchedWindows = mWindowInfos.findTouchedSpyWindowsAt(displayId, x, y, isStylus, entry.deviceId, @@ -2574,9 +2505,9 @@ InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, const Motio if (isSplit) { targetFlags |= InputTarget::Flags::SPLIT; } - if (isWindowObscuredAtPointLocked(windowHandle, x, y)) { + if (mWindowInfos.isWindowObscuredAtPoint(windowHandle, x, y)) { targetFlags |= InputTarget::Flags::WINDOW_IS_OBSCURED; - } else if (isWindowObscuredLocked(windowHandle)) { + } else if (mWindowInfos.isWindowObscured(windowHandle)) { targetFlags |= InputTarget::Flags::WINDOW_IS_PARTIALLY_OBSCURED; } @@ -2607,7 +2538,8 @@ InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, const Motio if (isDownOrPointerDown && targetFlags.test(InputTarget::Flags::FOREGROUND) && windowHandle->getInfo()->inputConfig.test( gui::WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER)) { - sp<WindowInfoHandle> wallpaper = findWallpaperWindowBelow(windowHandle); + sp<WindowInfoHandle> wallpaper = + mWindowInfos.findWallpaperWindowBelow(windowHandle); if (wallpaper != nullptr) { ftl::Flags<InputTarget::Flags> wallpaperFlags = InputTarget::Flags::WINDOW_IS_OBSCURED | @@ -2711,9 +2643,7 @@ InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, const Motio targets); // Make a slippery entrance into the new window. - if (newTouchedWindowHandle->getInfo()->supportsSplitTouch()) { - isSplit = !isFromMouse; - } + isSplit = !isFromMouse; ftl::Flags<InputTarget::Flags> targetFlags; if (canReceiveForegroundTouches(*newTouchedWindowHandle->getInfo())) { @@ -2722,9 +2652,9 @@ InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, const Motio if (isSplit) { targetFlags |= InputTarget::Flags::SPLIT; } - if (isWindowObscuredAtPointLocked(newTouchedWindowHandle, x, y)) { + if (mWindowInfos.isWindowObscuredAtPoint(newTouchedWindowHandle, x, y)) { targetFlags |= InputTarget::Flags::WINDOW_IS_OBSCURED; - } else if (isWindowObscuredLocked(newTouchedWindowHandle)) { + } else if (mWindowInfos.isWindowObscured(newTouchedWindowHandle)) { targetFlags |= InputTarget::Flags::WINDOW_IS_PARTIALLY_OBSCURED; } @@ -3007,17 +2937,17 @@ void InputDispatcher::addWindowTargetLocked(const sp<WindowInfoHandle>& windowHa const WindowInfo* windowInfo = windowHandle->getInfo(); if (it == inputTargets.end()) { - std::shared_ptr<Connection> connection = getConnectionLocked(windowHandle->getToken()); + std::shared_ptr<Connection> connection = + mConnectionManager.getConnection(windowHandle->getToken()); if (connection == nullptr) { ALOGW("Not creating InputTarget for %s, no input channel", windowHandle->getName().c_str()); return; } - inputTargets.push_back(createInputTarget(connection, windowHandle, dispatchMode, - targetFlags, - mWindowInfos.getDisplayTransform( - windowHandle->getInfo()->displayId), - firstDownTimeInTarget)); + inputTargets.push_back( + createInputTarget(connection, windowHandle, dispatchMode, targetFlags, + mWindowInfos.getRawTransform(*windowHandle->getInfo()), + firstDownTimeInTarget)); it = inputTargets.end() - 1; } @@ -3062,17 +2992,17 @@ void InputDispatcher::addPointerWindowTargetLocked( const WindowInfo* windowInfo = windowHandle->getInfo(); if (it == inputTargets.end()) { - std::shared_ptr<Connection> connection = getConnectionLocked(windowHandle->getToken()); + std::shared_ptr<Connection> connection = + mConnectionManager.getConnection(windowHandle->getToken()); if (connection == nullptr) { ALOGW("Not creating InputTarget for %s, no input channel", windowHandle->getName().c_str()); return; } - inputTargets.push_back(createInputTarget(connection, windowHandle, dispatchMode, - targetFlags, - mWindowInfos.getDisplayTransform( - windowHandle->getInfo()->displayId), - firstDownTimeInTarget)); + inputTargets.push_back( + createInputTarget(connection, windowHandle, dispatchMode, targetFlags, + mWindowInfos.getRawTransform(*windowHandle->getInfo()), + firstDownTimeInTarget)); it = inputTargets.end() - 1; } @@ -3098,17 +3028,31 @@ void InputDispatcher::addPointerWindowTargetLocked( void InputDispatcher::addGlobalMonitoringTargetsLocked(std::vector<InputTarget>& inputTargets, ui::LogicalDisplayId displayId) { - auto monitorsIt = mGlobalMonitorsByDisplay.find(displayId); - if (monitorsIt == mGlobalMonitorsByDisplay.end()) return; - - for (const Monitor& monitor : selectResponsiveMonitorsLocked(monitorsIt->second)) { - InputTarget target{monitor.connection}; - // target.firstDownTimeInTarget is not set for global monitors. It is only required in split - // touch and global monitoring works as intended even without setting firstDownTimeInTarget - target.displayTransform = mWindowInfos.getDisplayTransform(displayId); - target.setDefaultPointerTransform(target.displayTransform); - inputTargets.push_back(target); - } + ui::Transform displayTransform = mWindowInfos.getDisplayTransform(displayId); + mConnectionManager + .forEachGlobalMonitorConnection(displayId, + [&](const std::shared_ptr<Connection>& connection) { + if (!connection->responsive) { + ALOGW("Ignoring unrsponsive monitor: %s", + connection->getInputChannelName() + .c_str()); + return; + } + + InputTarget target{connection}; + // target.firstDownTimeInTarget is not set for + // global monitors. It is only required in split + // touch and global monitoring works as intended + // even without setting firstDownTimeInTarget. Since + // global monitors don't have windows, use the + // display transform as the raw transform. + base::ScopedLockAssertion assumeLocked(mLock); + target.rawTransform = + mWindowInfos.getDisplayTransform(displayId); + target.setDefaultPointerTransform( + target.rawTransform); + inputTargets.push_back(target); + }); } /** @@ -3164,12 +3108,12 @@ static bool canBeObscuredBy(const sp<WindowInfoHandle>& windowHandle, * * If neither of those is true, then it means the touch can be allowed. */ -InputDispatcher::TouchOcclusionInfo InputDispatcher::computeTouchOcclusionInfoLocked( +InputDispatcher::DispatcherWindowInfo::TouchOcclusionInfo +InputDispatcher::DispatcherWindowInfo::computeTouchOcclusionInfo( const sp<WindowInfoHandle>& windowHandle, float x, float y) const { const WindowInfo* windowInfo = windowHandle->getInfo(); ui::LogicalDisplayId displayId = windowInfo->displayId; - const std::vector<sp<WindowInfoHandle>>& windowHandles = - mWindowInfos.getWindowHandlesForDisplay(displayId); + const std::vector<sp<WindowInfoHandle>>& windowHandles = getWindowHandlesForDisplay(displayId); TouchOcclusionInfo info; info.hasBlockingOcclusion = false; info.obscuringOpacity = 0; @@ -3181,12 +3125,11 @@ InputDispatcher::TouchOcclusionInfo InputDispatcher::computeTouchOcclusionInfoLo } const WindowInfo* otherInfo = otherHandle->getInfo(); if (canBeObscuredBy(windowHandle, otherHandle) && - windowOccludesTouchAt(*otherInfo, displayId, x, y, - mWindowInfos.getDisplayTransform(displayId)) && + windowOccludesTouchAt(*otherInfo, displayId, x, y, getDisplayTransform(displayId)) && !haveSameApplicationToken(windowInfo, otherInfo)) { if (DEBUG_TOUCH_OCCLUSION) { info.debugInfo.push_back( - dumpWindowForTouchOcclusion(otherInfo, /*isTouchedWindow=*/false)); + dumpWindowForTouchOcclusion(*otherInfo, /*isTouchedWindow=*/false)); } // canBeObscuredBy() has returned true above, which means this window is untrusted, so // we perform the checks below to see if the touch can be propagated or not based on the @@ -3214,28 +3157,14 @@ InputDispatcher::TouchOcclusionInfo InputDispatcher::computeTouchOcclusionInfoLo } } if (DEBUG_TOUCH_OCCLUSION) { - info.debugInfo.push_back(dumpWindowForTouchOcclusion(windowInfo, /*isTouchedWindow=*/true)); + info.debugInfo.push_back( + dumpWindowForTouchOcclusion(*windowInfo, /*isTouchedWindow=*/true)); } return info; } -std::string InputDispatcher::dumpWindowForTouchOcclusion(const WindowInfo* info, - bool isTouchedWindow) const { - return StringPrintf(INDENT2 "* %spackage=%s/%s, id=%" PRId32 ", mode=%s, alpha=%.2f, " - "frame=[%" PRId32 ",%" PRId32 "][%" PRId32 ",%" PRId32 - "], touchableRegion=%s, window={%s}, inputConfig={%s}, " - "hasToken=%s, applicationInfo.name=%s, applicationInfo.token=%s\n", - isTouchedWindow ? "[TOUCHED] " : "", info->packageName.c_str(), - info->ownerUid.toString().c_str(), info->id, - toString(info->touchOcclusionMode).c_str(), info->alpha, info->frame.left, - info->frame.top, info->frame.right, info->frame.bottom, - dumpRegion(info->touchableRegion).c_str(), info->name.c_str(), - info->inputConfig.string().c_str(), toString(info->token != nullptr), - info->applicationInfo.name.c_str(), - binderToString(info->applicationInfo.token).c_str()); -} - -bool InputDispatcher::isTouchTrustedLocked(const TouchOcclusionInfo& occlusionInfo) const { +bool InputDispatcher::DispatcherWindowInfo::isTouchTrusted( + const TouchOcclusionInfo& occlusionInfo) const { if (occlusionInfo.hasBlockingOcclusion) { ALOGW("Untrusted touch due to occlusion by %s/%s", occlusionInfo.obscuringPackage.c_str(), occlusionInfo.obscuringUid.toString().c_str()); @@ -3251,29 +3180,27 @@ bool InputDispatcher::isTouchTrustedLocked(const TouchOcclusionInfo& occlusionIn return true; } -bool InputDispatcher::isWindowObscuredAtPointLocked(const sp<WindowInfoHandle>& windowHandle, - float x, float y) const { +bool InputDispatcher::DispatcherWindowInfo::isWindowObscuredAtPoint( + const sp<WindowInfoHandle>& windowHandle, float x, float y) const { ui::LogicalDisplayId displayId = windowHandle->getInfo()->displayId; - const std::vector<sp<WindowInfoHandle>>& windowHandles = - mWindowInfos.getWindowHandlesForDisplay(displayId); + const std::vector<sp<WindowInfoHandle>>& windowHandles = getWindowHandlesForDisplay(displayId); for (const sp<WindowInfoHandle>& otherHandle : windowHandles) { if (windowHandle == otherHandle) { break; // All future windows are below us. Exit early. } const WindowInfo* otherInfo = otherHandle->getInfo(); if (canBeObscuredBy(windowHandle, otherHandle) && - windowOccludesTouchAt(*otherInfo, displayId, x, y, - mWindowInfos.getDisplayTransform(displayId))) { + windowOccludesTouchAt(*otherInfo, displayId, x, y, getDisplayTransform(displayId))) { return true; } } return false; } -bool InputDispatcher::isWindowObscuredLocked(const sp<WindowInfoHandle>& windowHandle) const { +bool InputDispatcher::DispatcherWindowInfo::isWindowObscured( + const sp<WindowInfoHandle>& windowHandle) const { ui::LogicalDisplayId displayId = windowHandle->getInfo()->displayId; - const std::vector<sp<WindowInfoHandle>>& windowHandles = - mWindowInfos.getWindowHandlesForDisplay(displayId); + const std::vector<sp<WindowInfoHandle>>& windowHandles = getWindowHandlesForDisplay(displayId); const WindowInfo* windowInfo = windowHandle->getInfo(); for (const sp<WindowInfoHandle>& otherHandle : windowHandles) { if (windowHandle == otherHandle) { @@ -3930,7 +3857,7 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, "event to it, status=%s(%d)", connection->getInputChannelName().c_str(), statusToString(status).c_str(), status); - abortBrokenDispatchCycleLocked(currentTime, connection, /*notify=*/true); + abortBrokenDispatchCycleLocked(connection, /*notify=*/true); } else { // Pipe is full and we are waiting for the app to finish process some events // before sending more events to it. @@ -3945,7 +3872,7 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, "status=%s(%d)", connection->getInputChannelName().c_str(), statusToString(status).c_str(), status); - abortBrokenDispatchCycleLocked(currentTime, connection, /*notify=*/true); + abortBrokenDispatchCycleLocked(connection, /*notify=*/true); } return; } @@ -4020,8 +3947,7 @@ void InputDispatcher::finishDispatchCycleLocked(nsecs_t currentTime, postCommandLocked(std::move(command)); } -void InputDispatcher::abortBrokenDispatchCycleLocked(nsecs_t currentTime, - const std::shared_ptr<Connection>& connection, +void InputDispatcher::abortBrokenDispatchCycleLocked(const std::shared_ptr<Connection>& connection, bool notify) { if (DEBUG_DISPATCH_CYCLE) { LOG(INFO) << "channel '" << connection->getInputChannelName() << "'~ " << __func__ @@ -4068,7 +3994,7 @@ void InputDispatcher::releaseDispatchEntry(std::unique_ptr<DispatchEntry> dispat int InputDispatcher::handleReceiveCallback(int events, sp<IBinder> connectionToken) { std::scoped_lock _l(mLock); - std::shared_ptr<Connection> connection = getConnectionLocked(connectionToken); + std::shared_ptr<Connection> connection = mConnectionManager.getConnection(connectionToken); if (connection == nullptr) { ALOGW("Received looper callback for unknown input channel token %p. events=0x%x", connectionToken.get(), events); @@ -4137,7 +4063,7 @@ int InputDispatcher::handleReceiveCallback(int events, sp<IBinder> connectionTok } // Remove the channel. - removeInputChannelLocked(connection->getToken(), notify); + removeInputChannelLocked(connection, notify); return 0; // remove the callback } @@ -4176,12 +4102,12 @@ void InputDispatcher::synthesizeCancelationEventsForAllConnectionsLocked( void InputDispatcher::synthesizeCancelationEventsForMonitorsLocked( const CancelationOptions& options) { - for (const auto& [_, monitors] : mGlobalMonitorsByDisplay) { - for (const Monitor& monitor : monitors) { - synthesizeCancelationEventsForConnectionLocked(monitor.connection, options, - /*window=*/nullptr); - } - } + mConnectionManager.forEachGlobalMonitorConnection( + [&](const std::shared_ptr<Connection>& connection) { + base::ScopedLockAssertion assumeLocked(mLock); + synthesizeCancelationEventsForConnectionLocked(connection, options, + /*window=*/nullptr); + }); } void InputDispatcher::synthesizeCancelationEventsForWindowLocked( @@ -4199,7 +4125,7 @@ void InputDispatcher::synthesizeCancelationEventsForWindowLocked( } std::shared_ptr<Connection> resolvedConnection = - connection ? connection : getConnectionLocked(windowHandle->getToken()); + connection ? connection : mConnectionManager.getConnection(windowHandle->getToken()); if (!resolvedConnection) { LOG(DEBUG) << __func__ << "No connection found for window: " << windowHandle->getName(); return; @@ -4291,9 +4217,10 @@ void InputDispatcher::synthesizeCancelationEventsForConnectionLocked( motionEntry.downTime, targets); } else { targets.emplace_back(fallbackTarget); + // Since we don't have a window, use the display transform as the raw transform. const ui::Transform displayTransform = mWindowInfos.getDisplayTransform(motionEntry.displayId); - targets.back().displayTransform = displayTransform; + targets.back().rawTransform = displayTransform; targets.back().setDefaultPointerTransform(displayTransform); } logOutboundMotionDetails("cancel - ", motionEntry); @@ -4376,9 +4303,10 @@ void InputDispatcher::synthesizePointerDownEventsForConnectionLocked( targets); } else { targets.emplace_back(connection, targetFlags); + // Since we don't have a window, use the display transform as the raw transform. const ui::Transform displayTransform = mWindowInfos.getDisplayTransform(motionEntry.displayId); - targets.back().displayTransform = displayTransform; + targets.back().rawTransform = displayTransform; targets.back().setDefaultPointerTransform(displayTransform); } logOutboundMotionDetails("down - ", motionEntry); @@ -4944,6 +4872,19 @@ InputEventInjectionResult InputDispatcher::injectInputEvent(const InputEvent* ev return InputEventInjectionResult::FAILED; } + 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; + } + } + } + const nsecs_t* sampleEventTimes = motionEvent.getSampleEventTimes(); const size_t pointerCount = motionEvent.getPointerCount(); const std::vector<PointerProperties> @@ -5289,6 +5230,16 @@ ui::Transform InputDispatcher::DispatcherWindowInfo::getDisplayTransform( : kIdentityTransform; } +ui::Transform InputDispatcher::DispatcherWindowInfo::getRawTransform( + const android::gui::WindowInfo& windowInfo) const { + // If the window has a cloneLayerStackTransform, always use it as the transform for the "getRaw" + // APIs. If not, fall back to using the DisplayInfo transform of the window's display. + return (input_flags::use_cloned_screen_coordinates_as_raw() && + windowInfo.cloneLayerStackTransform) + ? *windowInfo.cloneLayerStackTransform + : getDisplayTransform(windowInfo.displayId); +} + std::string InputDispatcher::DispatcherWindowInfo::dumpDisplayAndWindowInfo() const { std::string dump; if (!mWindowHandlesByDisplay.empty()) { @@ -5319,8 +5270,9 @@ std::string InputDispatcher::DispatcherWindowInfo::dumpDisplayAndWindowInfo() co return dump; } -bool InputDispatcher::canWindowReceiveMotionLocked(const sp<WindowInfoHandle>& window, - const MotionEntry& motionEntry) const { +bool InputDispatcher::canWindowReceiveMotionLocked( + const sp<android::gui::WindowInfoHandle>& window, + const android::inputdispatcher::MotionEntry& motionEntry) const { const WindowInfo& info = *window->getInfo(); // Skip spy window targets that are not valid for targeted injection. @@ -5339,7 +5291,7 @@ bool InputDispatcher::canWindowReceiveMotionLocked(const sp<WindowInfoHandle>& w return false; } - std::shared_ptr<Connection> connection = getConnectionLocked(window->getToken()); + std::shared_ptr<Connection> connection = mConnectionManager.getConnection(window->getToken()); if (connection == nullptr) { ALOGW("Not sending touch to %s because there's no corresponding connection", window->getName().c_str()); @@ -5353,8 +5305,9 @@ bool InputDispatcher::canWindowReceiveMotionLocked(const sp<WindowInfoHandle>& w // Drop events that can't be trusted due to occlusion const auto [x, y] = resolveTouchedPosition(motionEntry); - TouchOcclusionInfo occlusionInfo = computeTouchOcclusionInfoLocked(window, x, y); - if (!isTouchTrustedLocked(occlusionInfo)) { + DispatcherWindowInfo::TouchOcclusionInfo occlusionInfo = + mWindowInfos.computeTouchOcclusionInfo(window, x, y); + if (!mWindowInfos.isTouchTrusted(occlusionInfo)) { if (DEBUG_TOUCH_OCCLUSION) { ALOGD("Stack of obscuring windows during untrusted touch (%.1f, %.1f):", x, y); for (const auto& log : occlusionInfo.debugInfo) { @@ -5402,7 +5355,7 @@ void InputDispatcher::updateWindowHandlesForDisplayLocked( std::vector<sp<WindowInfoHandle>> newHandles; for (const sp<WindowInfoHandle>& handle : windowInfoHandles) { const WindowInfo* info = handle->getInfo(); - if (getConnectionLocked(handle->getToken()) == nullptr) { + if (mConnectionManager.getConnection(handle->getToken()) == nullptr) { const bool noInputChannel = info->inputConfig.test(WindowInfo::InputConfig::NO_INPUT_CHANNEL); const bool canReceiveInput = @@ -5798,13 +5751,8 @@ bool InputDispatcher::recentWindowsAreOwnedByLocked(gui::Pid pid, gui::Uid uid) } void InputDispatcher::setMaximumObscuringOpacityForTouch(float opacity) { - if (opacity < 0 || opacity > 1) { - LOG_ALWAYS_FATAL("Maximum obscuring opacity for touch should be >= 0 and <= 1"); - return; - } - std::scoped_lock lock(mLock); - mMaximumObscuringOpacityForTouch = opacity; + mWindowInfos.setMaximumObscuringOpacityForTouch(opacity); } std::tuple<const TouchState*, const TouchedWindow*, ui::LogicalDisplayId> @@ -5835,18 +5783,6 @@ InputDispatcher::findTouchStateWindowAndDisplay( const_cast<TouchedWindow*>(constTouchedWindow), displayId); } -bool InputDispatcher::windowHasTouchingPointers( - const sp<WindowInfoHandle>& windowHandle, DeviceId deviceId, - const std::unordered_map<ui::LogicalDisplayId, TouchState>& touchStatesByDisplay) { - const auto& [touchState, touchedWindow, _] = - findTouchStateWindowAndDisplay(windowHandle->getToken(), touchStatesByDisplay); - if (touchState == nullptr) { - // No touching pointers at all - return false; - } - return touchState->hasTouchingPointers(deviceId); -} - bool InputDispatcher::transferTouchGesture(const sp<IBinder>& fromToken, const sp<IBinder>& toToken, bool isDragDrop) { if (fromToken == toToken) { @@ -5920,8 +5856,8 @@ bool InputDispatcher::transferTouchGesture(const sp<IBinder>& fromToken, const s // Synthesize cancel for old window and down for new window. ScopedSyntheticEventTracer traceContext(mTracer); - std::shared_ptr<Connection> fromConnection = getConnectionLocked(fromToken); - std::shared_ptr<Connection> toConnection = getConnectionLocked(toToken); + 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, @@ -6096,18 +6032,10 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) const { dump += addLinePrefix(mWindowInfos.dumpDisplayAndWindowInfo(), INDENT); - if (!mGlobalMonitorsByDisplay.empty()) { - for (const auto& [displayId, monitors] : mGlobalMonitorsByDisplay) { - dump += StringPrintf(INDENT "Global monitors on display %s:\n", - displayId.toString().c_str()); - dumpMonitors(dump, monitors); - } - } else { - dump += INDENT "Global Monitors: <none>\n"; - } - const nsecs_t currentTime = now(); + dump += addLinePrefix(mConnectionManager.dump(currentTime), INDENT); + // Dump recently dispatched or dropped events from oldest to newest. if (!mRecentQueue.empty()) { dump += StringPrintf(INDENT "RecentQueue: length=%zu\n", mRecentQueue.size()); @@ -6149,37 +6077,6 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) const { dump += INDENT "CommandQueue: <empty>\n"; } - if (!mConnectionsByToken.empty()) { - dump += INDENT "Connections:\n"; - for (const auto& [token, connection] : mConnectionsByToken) { - dump += StringPrintf(INDENT2 "%i: channelName='%s', " - "status=%s, monitor=%s, responsive=%s\n", - connection->inputPublisher.getChannel().getFd(), - connection->getInputChannelName().c_str(), - ftl::enum_string(connection->status).c_str(), - toString(connection->monitor), toString(connection->responsive)); - - if (!connection->outboundQueue.empty()) { - dump += StringPrintf(INDENT3 "OutboundQueue: length=%zu\n", - connection->outboundQueue.size()); - dump += dumpQueue(connection->outboundQueue, currentTime); - } - - if (!connection->waitQueue.empty()) { - dump += StringPrintf(INDENT3 "WaitQueue: length=%zu\n", - connection->waitQueue.size()); - dump += dumpQueue(connection->waitQueue, currentTime); - } - std::string inputStateDump = streamableToString(connection->inputState); - if (!inputStateDump.empty()) { - dump += INDENT3 "InputState: "; - dump += inputStateDump + "\n"; - } - } - } else { - dump += INDENT "Connections: <none>\n"; - } - if (!mTouchModePerDisplay.empty()) { dump += INDENT "TouchModePerDisplay:\n"; for (const auto& [displayId, touchMode] : mTouchModePerDisplay) { @@ -6200,16 +6097,6 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) const { dump += mTracer == nullptr ? "Disabled" : "Enabled"; } -void InputDispatcher::dumpMonitors(std::string& dump, const std::vector<Monitor>& monitors) const { - const size_t numMonitors = monitors.size(); - for (size_t i = 0; i < numMonitors; i++) { - const Monitor& monitor = monitors[i]; - const std::shared_ptr<Connection>& connection = monitor.connection; - dump += StringPrintf(INDENT2 "%zu: '%s', ", i, connection->getInputChannelName().c_str()); - dump += "\n"; - } -} - class LooperEventCallback : public LooperCallback { public: LooperEventCallback(std::function<int(int events)> callback) : mCallback(callback) {} @@ -6236,14 +6123,8 @@ Result<std::unique_ptr<InputChannel>> InputDispatcher::createInputChannel(const std::scoped_lock _l(mLock); const sp<IBinder>& token = serverChannel->getConnectionToken(); const int fd = serverChannel->getFd(); - std::shared_ptr<Connection> connection = - std::make_shared<Connection>(std::move(serverChannel), /*monitor=*/false, - mIdGenerator); - auto [_, inserted] = mConnectionsByToken.try_emplace(token, connection); - if (!inserted) { - ALOGE("Created a new connection, but the token %p is already known", token.get()); - } + mConnectionManager.createConnection(std::move(serverChannel), mIdGenerator); std::function<int(int events)> callback = std::bind(&InputDispatcher::handleReceiveCallback, this, std::placeholders::_1, token); @@ -6276,19 +6157,11 @@ Result<std::unique_ptr<InputChannel>> InputDispatcher::createInputMonitor( const sp<IBinder>& token = serverChannel->getConnectionToken(); const int fd = serverChannel->getFd(); - std::shared_ptr<Connection> connection = - std::make_shared<Connection>(std::move(serverChannel), /*monitor=*/true, - mIdGenerator); - - auto [_, inserted] = mConnectionsByToken.emplace(token, connection); - if (!inserted) { - ALOGE("Created a new connection, but the token %p is already known", token.get()); - } - std::function<int(int events)> callback = std::bind(&InputDispatcher::handleReceiveCallback, this, std::placeholders::_1, token); - mGlobalMonitorsByDisplay[displayId].emplace_back(connection, pid); + mConnectionManager.createGlobalInputMonitor(displayId, std::move(serverChannel), + mIdGenerator, pid); mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, sp<LooperEventCallback>::make(callback), nullptr); @@ -6302,8 +6175,14 @@ Result<std::unique_ptr<InputChannel>> InputDispatcher::createInputMonitor( status_t InputDispatcher::removeInputChannel(const sp<IBinder>& connectionToken) { { // acquire lock std::scoped_lock _l(mLock); + std::shared_ptr<Connection> connection = mConnectionManager.getConnection(connectionToken); + if (connection == nullptr) { + // Connection can be removed via socket hang up or an explicit call to + // 'removeInputChannel' + return BAD_VALUE; + } - status_t status = removeInputChannelLocked(connectionToken, /*notify=*/false); + status_t status = mConnectionManager.removeInputChannel(connection); if (status) { return status; } @@ -6315,30 +6194,18 @@ status_t InputDispatcher::removeInputChannel(const sp<IBinder>& connectionToken) return OK; } -status_t InputDispatcher::removeInputChannelLocked(const sp<IBinder>& connectionToken, +status_t InputDispatcher::removeInputChannelLocked(const std::shared_ptr<Connection>& connection, bool notify) { - std::shared_ptr<Connection> connection = getConnectionLocked(connectionToken); - if (connection == nullptr) { - // Connection can be removed via socket hang up or an explicit call to 'removeInputChannel' - return BAD_VALUE; - } - - removeConnectionLocked(connection); - - if (connection->monitor) { - removeMonitorChannelLocked(connectionToken); - } - - mLooper->removeFd(connection->inputPublisher.getChannel().getFd()); + LOG_ALWAYS_FATAL_IF(connection == nullptr); + abortBrokenDispatchCycleLocked(connection, notify); - nsecs_t currentTime = now(); - abortBrokenDispatchCycleLocked(currentTime, connection, notify); + mAnrTracker.eraseToken(connection->getToken()); + mConnectionManager.removeInputChannel(connection); - connection->status = Connection::Status::ZOMBIE; return OK; } -void InputDispatcher::removeMonitorChannelLocked(const sp<IBinder>& connectionToken) { +void InputDispatcher::ConnectionManager::removeMonitorChannel(const sp<IBinder>& connectionToken) { for (auto it = mGlobalMonitorsByDisplay.begin(); it != mGlobalMonitorsByDisplay.end();) { auto& [displayId, monitors] = *it; std::erase_if(monitors, [connectionToken](const Monitor& monitor) { @@ -6359,7 +6226,8 @@ status_t InputDispatcher::pilferPointers(const sp<IBinder>& token) { } status_t InputDispatcher::pilferPointersLocked(const sp<IBinder>& token) { - const std::shared_ptr<Connection> requestingConnection = getConnectionLocked(token); + const std::shared_ptr<Connection> requestingConnection = + mConnectionManager.getConnection(token); if (!requestingConnection) { LOG(WARNING) << "Attempted to pilfer pointers from an un-registered channel or invalid token"; @@ -6466,7 +6334,8 @@ void InputDispatcher::setDisplayEligibilityForPointerCapture(ui::LogicalDisplayI } // release lock } -std::optional<gui::Pid> InputDispatcher::findMonitorPidByTokenLocked(const sp<IBinder>& token) { +std::optional<gui::Pid> InputDispatcher::ConnectionManager::findMonitorPidByToken( + const sp<IBinder>& token) const { for (const auto& [_, monitors] : mGlobalMonitorsByDisplay) { for (const Monitor& monitor : monitors) { if (monitor.connection->getToken() == token) { @@ -6477,7 +6346,7 @@ std::optional<gui::Pid> InputDispatcher::findMonitorPidByTokenLocked(const sp<IB return std::nullopt; } -std::shared_ptr<Connection> InputDispatcher::getConnectionLocked( +std::shared_ptr<Connection> InputDispatcher::ConnectionManager::getConnection( const sp<IBinder>& inputConnectionToken) const { if (inputConnectionToken == nullptr) { return nullptr; @@ -6492,16 +6361,8 @@ std::shared_ptr<Connection> InputDispatcher::getConnectionLocked( return nullptr; } -std::string InputDispatcher::getConnectionNameLocked(const sp<IBinder>& connectionToken) const { - std::shared_ptr<Connection> connection = getConnectionLocked(connectionToken); - if (connection == nullptr) { - return "<nullptr>"; - } - return connection->getInputChannelName(); -} - -void InputDispatcher::removeConnectionLocked(const std::shared_ptr<Connection>& connection) { - mAnrTracker.eraseToken(connection->getToken()); +void InputDispatcher::ConnectionManager::removeConnection( + const std::shared_ptr<Connection>& connection) { mConnectionsByToken.erase(connection->getToken()); } @@ -6567,9 +6428,8 @@ void InputDispatcher::doDispatchCycleFinishedCommand(nsecs_t finishTime, createInputTarget(connection, windowHandle, InputTarget::DispatchMode::AS_IS, dispatchEntry->targetFlags, - mWindowInfos.getDisplayTransform( - windowHandle->getInfo() - ->displayId), + mWindowInfos.getRawTransform( + *windowHandle->getInfo()), downTime)); } } @@ -6730,7 +6590,7 @@ void InputDispatcher::processConnectionUnresponsiveLocked(const Connection& conn if (connection.monitor) { ALOGW("Monitor %s is unresponsive: %s", connection.getInputChannelName().c_str(), reason.c_str()); - pid = findMonitorPidByTokenLocked(connectionToken); + pid = mConnectionManager.findMonitorPidByToken(connectionToken); } else { // The connection is a window ALOGW("Window %s is unresponsive: %s", connection.getInputChannelName().c_str(), @@ -6750,7 +6610,7 @@ void InputDispatcher::processConnectionResponsiveLocked(const Connection& connec const sp<IBinder>& connectionToken = connection.getToken(); std::optional<gui::Pid> pid; if (connection.monitor) { - pid = findMonitorPidByTokenLocked(connectionToken); + pid = mConnectionManager.findMonitorPidByToken(connectionToken); } else { // The connection is a window const sp<WindowInfoHandle> handle = mWindowInfos.findWindowHandle(connectionToken); @@ -7168,13 +7028,6 @@ void InputDispatcher::onWindowInfosChanged(const gui::WindowInfosUpdate& update) for (const auto& info : update.windowInfos) { handlesPerDisplay.emplace(info.displayId, std::vector<sp<WindowInfoHandle>>()); handlesPerDisplay[info.displayId].push_back(sp<WindowInfoHandle>::make(info)); - if (input_flags::split_all_touches()) { - handlesPerDisplay[info.displayId] - .back() - ->editInfo() - ->setInputConfig(android::gui::WindowInfo::InputConfig::PREVENT_SPLITTING, - false); - } } { // acquire lock @@ -7207,7 +7060,7 @@ bool InputDispatcher::shouldDropInput( if (windowHandle->getInfo()->inputConfig.test(WindowInfo::InputConfig::DROP_INPUT) || (windowHandle->getInfo()->inputConfig.test( WindowInfo::InputConfig::DROP_INPUT_IF_OBSCURED) && - isWindowObscuredLocked(windowHandle))) { + mWindowInfos.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(), @@ -7260,7 +7113,7 @@ void InputDispatcher::slipWallpaperTouch(ftl::Flags<InputTarget::Flags> targetFl const sp<WindowInfoHandle> oldWallpaper = oldHasWallpaper ? state.getWallpaperWindow(deviceId) : nullptr; const sp<WindowInfoHandle> newWallpaper = - newHasWallpaper ? findWallpaperWindowBelow(newWindowHandle) : nullptr; + newHasWallpaper ? mWindowInfos.findWallpaperWindowBelow(newWindowHandle) : nullptr; if (oldWallpaper == newWallpaper) { return; } @@ -7297,7 +7150,7 @@ void InputDispatcher::transferWallpaperTouch( const sp<WindowInfoHandle> oldWallpaper = oldHasWallpaper ? state.getWallpaperWindow(deviceId) : nullptr; const sp<WindowInfoHandle> newWallpaper = - newHasWallpaper ? findWallpaperWindowBelow(toWindowHandle) : nullptr; + newHasWallpaper ? mWindowInfos.findWallpaperWindowBelow(toWindowHandle) : nullptr; if (oldWallpaper == newWallpaper) { return; } @@ -7318,10 +7171,10 @@ void InputDispatcher::transferWallpaperTouch( state.addOrUpdateWindow(newWallpaper, InputTarget::DispatchMode::AS_IS, wallpaperFlags, deviceId, pointers, downTimeInTarget); std::shared_ptr<Connection> wallpaperConnection = - getConnectionLocked(newWallpaper->getToken()); + mConnectionManager.getConnection(newWallpaper->getToken()); if (wallpaperConnection != nullptr) { std::shared_ptr<Connection> toConnection = - getConnectionLocked(toWindowHandle->getToken()); + mConnectionManager.getConnection(toWindowHandle->getToken()); toConnection->inputState.mergePointerStateTo(wallpaperConnection->inputState); synthesizePointerDownEventsForConnectionLocked(downTimeInTarget, wallpaperConnection, wallpaperFlags, traceTracker); @@ -7329,10 +7182,10 @@ void InputDispatcher::transferWallpaperTouch( } } -sp<WindowInfoHandle> InputDispatcher::findWallpaperWindowBelow( +sp<WindowInfoHandle> InputDispatcher::DispatcherWindowInfo::findWallpaperWindowBelow( const sp<WindowInfoHandle>& windowHandle) const { const std::vector<sp<WindowInfoHandle>>& windowHandles = - mWindowInfos.getWindowHandlesForDisplay(windowHandle->getInfo()->displayId); + getWindowHandlesForDisplay(windowHandle->getInfo()->displayId); bool foundWindow = false; for (const sp<WindowInfoHandle>& otherHandle : windowHandles) { if (!foundWindow && otherHandle != windowHandle) { @@ -7385,4 +7238,130 @@ void InputDispatcher::setInputMethodConnectionIsActive(bool isActive) { } } +InputDispatcher::ConnectionManager::ConnectionManager(sp<android::Looper> looper) + : mLooper(looper) {} + +InputDispatcher::ConnectionManager::~ConnectionManager() { + while (!mConnectionsByToken.empty()) { + std::shared_ptr<Connection> connection = mConnectionsByToken.begin()->second; + removeInputChannel(connection); + } +} + +void InputDispatcher::ConnectionManager::forEachGlobalMonitorConnection( + std::function<void(const std::shared_ptr<Connection>&)> f) const { + for (const auto& [_, monitors] : mGlobalMonitorsByDisplay) { + for (const Monitor& monitor : monitors) { + f(monitor.connection); + } + } +} + +void InputDispatcher::ConnectionManager::forEachGlobalMonitorConnection( + ui::LogicalDisplayId displayId, + std::function<void(const std::shared_ptr<Connection>&)> f) const { + auto monitorsIt = mGlobalMonitorsByDisplay.find(displayId); + if (monitorsIt == mGlobalMonitorsByDisplay.end()) return; + + for (const Monitor& monitor : monitorsIt->second) { + f(monitor.connection); + } +} + +void InputDispatcher::ConnectionManager::createGlobalInputMonitor( + ui::LogicalDisplayId displayId, std::unique_ptr<InputChannel>&& inputChannel, + const android::IdGenerator& idGenerator, gui::Pid pid) { + std::shared_ptr<Connection> connection = + std::make_shared<Connection>(std::move(inputChannel), /*monitor=*/true, idGenerator); + sp<IBinder> token = connection->getToken(); + auto [_, inserted] = mConnectionsByToken.emplace(token, connection); + if (!inserted) { + ALOGE("Created a new connection, but the token %p is already known", token.get()); + } + mGlobalMonitorsByDisplay[displayId].emplace_back(connection, pid); +} + +void InputDispatcher::ConnectionManager::createConnection( + std::unique_ptr<InputChannel>&& inputChannel, const android::IdGenerator& idGenerator) { + std::shared_ptr<Connection> connection = + std::make_shared<Connection>(std::move(inputChannel), /*monitor=*/false, idGenerator); + sp<IBinder> token = connection->getToken(); + auto [_, inserted] = mConnectionsByToken.try_emplace(token, connection); + if (!inserted) { + ALOGE("Created a new connection, but the token %p is already known", token.get()); + } +} + +status_t InputDispatcher::ConnectionManager::removeInputChannel( + const std::shared_ptr<Connection>& connection) { + removeConnection(connection); + + if (connection->monitor) { + removeMonitorChannel(connection->getToken()); + } + + mLooper->removeFd(connection->inputPublisher.getChannel().getFd()); + + connection->status = Connection::Status::ZOMBIE; + return OK; +} + +std::string InputDispatcher::ConnectionManager::dump(nsecs_t currentTime) const { + std::string dump; + if (!mGlobalMonitorsByDisplay.empty()) { + for (const auto& [displayId, monitors] : mGlobalMonitorsByDisplay) { + dump += StringPrintf("Global monitors on display %s:\n", displayId.toString().c_str()); + const size_t numMonitors = monitors.size(); + for (size_t i = 0; i < numMonitors; i++) { + const Monitor& monitor = monitors[i]; + const std::shared_ptr<Connection>& connection = monitor.connection; + dump += StringPrintf(INDENT "%zu: '%s', ", i, + connection->getInputChannelName().c_str()); + dump += "\n"; + } + } + } else { + dump += "Global Monitors: <none>\n"; + } + + if (!mConnectionsByToken.empty()) { + dump += "Connections:\n"; + for (const auto& [token, connection] : mConnectionsByToken) { + dump += StringPrintf(INDENT "%i: channelName='%s', " + "status=%s, monitor=%s, responsive=%s\n", + connection->inputPublisher.getChannel().getFd(), + connection->getInputChannelName().c_str(), + ftl::enum_string(connection->status).c_str(), + toString(connection->monitor), toString(connection->responsive)); + + if (!connection->outboundQueue.empty()) { + dump += StringPrintf(INDENT2 "OutboundQueue: length=%zu\n", + connection->outboundQueue.size()); + dump += dumpQueue(connection->outboundQueue, currentTime); + } + + if (!connection->waitQueue.empty()) { + dump += StringPrintf(INDENT2 "WaitQueue: length=%zu\n", + connection->waitQueue.size()); + dump += dumpQueue(connection->waitQueue, currentTime); + } + std::string inputStateDump = streamableToString(connection->inputState); + if (!inputStateDump.empty()) { + dump += INDENT2 "InputState: "; + dump += inputStateDump + "\n"; + } + } + } else { + dump += "Connections: <none>\n"; + } + return dump; +} + +void InputDispatcher::DispatcherWindowInfo::setMaximumObscuringOpacityForTouch(float opacity) { + if (opacity < 0 || opacity > 1) { + LOG_ALWAYS_FATAL("Maximum obscuring opacity for touch should be >= 0 and <= 1"); + } + mMaximumObscuringOpacityForTouch = opacity; +} + } // namespace android::inputdispatcher diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h index fd550dd396..13fec2ae54 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.h +++ b/services/inputflinger/dispatcher/InputDispatcher.h @@ -224,6 +224,133 @@ private: /** Stores the latest user-activity poke event times per user activity types. */ std::array<nsecs_t, USER_ACTIVITY_EVENT_LAST + 1> mLastUserActivityTimes GUARDED_BY(mLock); + template <typename T> + struct StrongPointerHash { + std::size_t operator()(const sp<T>& b) const { return std::hash<T*>{}(b.get()); } + }; + + class ConnectionManager { + public: + ConnectionManager(sp<Looper> lopper); + ~ConnectionManager(); + + std::shared_ptr<Connection> getConnection(const sp<IBinder>& inputConnectionToken) const; + std::string getConnectionName(const sp<IBinder>& connectionToken) const; + + // Find a monitor pid by the provided token. + std::optional<gui::Pid> findMonitorPidByToken(const sp<IBinder>& token) const; + void forEachGlobalMonitorConnection( + std::function<void(const std::shared_ptr<Connection>&)> f) const; + void forEachGlobalMonitorConnection( + ui::LogicalDisplayId displayId, + std::function<void(const std::shared_ptr<Connection>&)> f) const; + + void createGlobalInputMonitor(ui::LogicalDisplayId displayId, + std::unique_ptr<InputChannel>&& inputChannel, + const IdGenerator& idGenerator, gui::Pid pid); + + status_t removeInputChannel(const std::shared_ptr<Connection>& connection); + void removeConnection(const std::shared_ptr<Connection>& connection); + + void createConnection(std::unique_ptr<InputChannel>&& inputChannel, + const IdGenerator& idGenerator); + + std::string dump(nsecs_t currentTime) const; + + private: + sp<Looper> mLooper; + + // All registered connections mapped by input channel token. + std::unordered_map<sp<IBinder>, std::shared_ptr<Connection>, StrongPointerHash<IBinder>> + mConnectionsByToken; + + // Input channels that will receive a copy of all input events sent to the provided display. + std::unordered_map<ui::LogicalDisplayId, std::vector<Monitor>> mGlobalMonitorsByDisplay; + + void removeMonitorChannel(const sp<IBinder>& connectionToken); + }; + + ConnectionManager mConnectionManager GUARDED_BY(mLock); + + class DispatcherWindowInfo { + public: + struct TouchOcclusionInfo { + bool hasBlockingOcclusion; + float obscuringOpacity; + std::string obscuringPackage; + gui::Uid obscuringUid = gui::Uid::INVALID; + std::vector<std::string> debugInfo; + }; + + void setWindowHandlesForDisplay( + ui::LogicalDisplayId displayId, + std::vector<sp<android::gui::WindowInfoHandle>>&& windowHandles); + + void setDisplayInfos(const std::vector<android::gui::DisplayInfo>& displayInfos); + + void removeDisplay(ui::LogicalDisplayId displayId); + + void setMaximumObscuringOpacityForTouch(float opacity); + + // Get a reference to window handles by display, return an empty vector if not found. + const std::vector<sp<android::gui::WindowInfoHandle>>& getWindowHandlesForDisplay( + ui::LogicalDisplayId displayId) const; + + void forEachWindowHandle( + std::function<void(const sp<android::gui::WindowInfoHandle>&)> f) const; + + void forEachDisplayId(std::function<void(ui::LogicalDisplayId)> f) const; + + // Get the transform for display, returns Identity-transform if display is missing. + ui::Transform getDisplayTransform(ui::LogicalDisplayId displayId) const; + + // Get the raw transform to use for motion events going to the given window. + ui::Transform getRawTransform(const android::gui::WindowInfo&) const; + + // Lookup for WindowInfoHandle from token and optionally a display-id. In cases where + // display-id is not provided lookup is done for all displays. + sp<android::gui::WindowInfoHandle> findWindowHandle( + const sp<IBinder>& windowHandleToken, + std::optional<ui::LogicalDisplayId> displayId = {}) const; + + bool isWindowPresent(const sp<android::gui::WindowInfoHandle>& windowHandle) const; + + // Returns the touched window at the given location, excluding the ignoreWindow if provided. + sp<android::gui::WindowInfoHandle> findTouchedWindowAt( + ui::LogicalDisplayId displayId, float x, float y, bool isStylus = false, + const sp<android::gui::WindowInfoHandle> ignoreWindow = nullptr) const; + + std::vector<sp<android::gui::WindowInfoHandle>> findTouchedSpyWindowsAt( + ui::LogicalDisplayId displayId, float x, float y, bool isStylus, DeviceId deviceId, + const std::unordered_map<ui::LogicalDisplayId, TouchState>& touchStatesByDisplay) + const; + + TouchOcclusionInfo computeTouchOcclusionInfo( + const sp<android::gui::WindowInfoHandle>& windowHandle, float x, float y) const; + + bool isWindowObscured(const sp<android::gui::WindowInfoHandle>& windowHandle) const; + + bool isWindowObscuredAtPoint(const sp<android::gui::WindowInfoHandle>& windowHandle, + float x, float y) const; + + sp<android::gui::WindowInfoHandle> findWallpaperWindowBelow( + const sp<android::gui::WindowInfoHandle>& windowHandle) const; + + bool isTouchTrusted(const TouchOcclusionInfo& occlusionInfo) const; + + std::string dumpDisplayAndWindowInfo() const; + + private: + std::unordered_map<ui::LogicalDisplayId /*displayId*/, + std::vector<sp<android::gui::WindowInfoHandle>>> + mWindowHandlesByDisplay; + std::unordered_map<ui::LogicalDisplayId /*displayId*/, android::gui::DisplayInfo> + mDisplayInfos; + float mMaximumObscuringOpacityForTouch{1.0f}; + }; + + DispatcherWindowInfo mWindowInfos 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. @@ -260,31 +387,8 @@ private: const std::unordered_map<ui::LogicalDisplayId, TouchState>& touchStatesByDisplay, ui::LogicalDisplayId displayId); - std::shared_ptr<Connection> getConnectionLocked(const sp<IBinder>& inputConnectionToken) const - REQUIRES(mLock); - - std::string getConnectionNameLocked(const sp<IBinder>& connectionToken) const REQUIRES(mLock); - - void removeConnectionLocked(const std::shared_ptr<Connection>& connection) REQUIRES(mLock); - status_t pilferPointersLocked(const sp<IBinder>& token) REQUIRES(mLock); - template <typename T> - struct StrongPointerHash { - std::size_t operator()(const sp<T>& b) const { return std::hash<T*>{}(b.get()); } - }; - - // All registered connections mapped by input channel token. - std::unordered_map<sp<IBinder>, std::shared_ptr<Connection>, StrongPointerHash<IBinder>> - mConnectionsByToken GUARDED_BY(mLock); - - // Find a monitor pid by the provided token. - std::optional<gui::Pid> findMonitorPidByTokenLocked(const sp<IBinder>& token) REQUIRES(mLock); - - // Input channels that will receive a copy of all input events sent to the provided display. - std::unordered_map<ui::LogicalDisplayId, std::vector<Monitor>> mGlobalMonitorsByDisplay - GUARDED_BY(mLock); - const HmacKeyManager mHmacKeyManager; const std::array<uint8_t, 32> getSignature(const MotionEntry& motionEntry, const DispatchEntry& dispatchEntry) const; @@ -344,7 +448,6 @@ private: bool mDispatchEnabled GUARDED_BY(mLock); bool mDispatchFrozen GUARDED_BY(mLock); bool mInputFilterEnabled GUARDED_BY(mLock); - float mMaximumObscuringOpacityForTouch GUARDED_BY(mLock); // This map is not really needed, but it helps a lot with debugging (dumpsys input). // In the java layer, touch mode states are spread across multiple DisplayContent objects, @@ -362,58 +465,6 @@ private: }; sp<gui::WindowInfosListener> mWindowInfoListener; - class DispatcherWindowInfo { - public: - void setWindowHandlesForDisplay( - ui::LogicalDisplayId displayId, - std::vector<sp<android::gui::WindowInfoHandle>>&& windowHandles); - - void setDisplayInfos(const std::vector<android::gui::DisplayInfo>& displayInfos); - - void removeDisplay(ui::LogicalDisplayId displayId); - - // Get a reference to window handles by display, return an empty vector if not found. - const std::vector<sp<android::gui::WindowInfoHandle>>& getWindowHandlesForDisplay( - ui::LogicalDisplayId displayId) const; - - void forEachWindowHandle( - std::function<void(const sp<android::gui::WindowInfoHandle>&)> f) const; - - void forEachDisplayId(std::function<void(ui::LogicalDisplayId)> f) const; - - // Get the transform for display, returns Identity-transform if display is missing. - ui::Transform getDisplayTransform(ui::LogicalDisplayId displayId) const; - - // Lookup for WindowInfoHandle from token and optionally a display-id. In cases where - // display-id is not provided lookup is done for all displays. - sp<android::gui::WindowInfoHandle> findWindowHandle( - const sp<IBinder>& windowHandleToken, - std::optional<ui::LogicalDisplayId> displayId = {}) const; - - bool isWindowPresent(const sp<android::gui::WindowInfoHandle>& windowHandle) const; - - // Returns the touched window at the given location, excluding the ignoreWindow if provided. - sp<android::gui::WindowInfoHandle> findTouchedWindowAt( - ui::LogicalDisplayId displayId, float x, float y, bool isStylus = false, - const sp<android::gui::WindowInfoHandle> ignoreWindow = nullptr) const; - - std::vector<sp<android::gui::WindowInfoHandle>> findTouchedSpyWindowsAt( - ui::LogicalDisplayId displayId, float x, float y, bool isStylus, DeviceId deviceId, - const std::unordered_map<ui::LogicalDisplayId, TouchState>& touchStatesByDisplay) - const; - - std::string dumpDisplayAndWindowInfo() const; - - private: - std::unordered_map<ui::LogicalDisplayId /*displayId*/, - std::vector<sp<android::gui::WindowInfoHandle>>> - mWindowHandlesByDisplay; - std::unordered_map<ui::LogicalDisplayId /*displayId*/, android::gui::DisplayInfo> - mDisplayInfos; - }; - - DispatcherWindowInfo mWindowInfos GUARDED_BY(mLock); - void setInputWindowsLocked( const std::vector<sp<android::gui::WindowInfoHandle>>& inputWindowHandles, ui::LogicalDisplayId displayId) REQUIRES(mLock); @@ -579,8 +630,6 @@ private: nsecs_t& nextWakeupTime) REQUIRES(mLock); base::Result<std::vector<InputTarget>, android::os::InputEventInjectionResult> findTouchedWindowTargetsLocked(nsecs_t currentTime, const MotionEntry& entry) REQUIRES(mLock); - std::vector<Monitor> selectResponsiveMonitorsLocked( - const std::vector<Monitor>& gestureMonitors) const REQUIRES(mLock); void addWindowTargetLocked(const sp<android::gui::WindowInfoHandle>& windowHandle, InputTarget::DispatchMode dispatchMode, @@ -601,24 +650,6 @@ private: void addDragEventLocked(const MotionEntry& entry) REQUIRES(mLock); void finishDragAndDrop(ui::LogicalDisplayId displayId, float x, float y) REQUIRES(mLock); - struct TouchOcclusionInfo { - bool hasBlockingOcclusion; - float obscuringOpacity; - std::string obscuringPackage; - gui::Uid obscuringUid = gui::Uid::INVALID; - std::vector<std::string> debugInfo; - }; - - TouchOcclusionInfo computeTouchOcclusionInfoLocked( - const sp<android::gui::WindowInfoHandle>& windowHandle, float x, float y) const - REQUIRES(mLock); - bool isTouchTrustedLocked(const TouchOcclusionInfo& occlusionInfo) const REQUIRES(mLock); - bool isWindowObscuredAtPointLocked(const sp<android::gui::WindowInfoHandle>& windowHandle, - float x, float y) const REQUIRES(mLock); - bool isWindowObscuredLocked(const sp<android::gui::WindowInfoHandle>& windowHandle) const - REQUIRES(mLock); - std::string dumpWindowForTouchOcclusion(const android::gui::WindowInfo* info, - bool isTouchWindow) const; std::string getApplicationWindowLabel(const InputApplicationHandle* applicationHandle, const sp<android::gui::WindowInfoHandle>& windowHandle); @@ -646,8 +677,7 @@ private: void finishDispatchCycleLocked(nsecs_t currentTime, const std::shared_ptr<Connection>& connection, uint32_t seq, bool handled, nsecs_t consumeTime) REQUIRES(mLock); - void abortBrokenDispatchCycleLocked(nsecs_t currentTime, - const std::shared_ptr<Connection>& connection, bool notify) + void abortBrokenDispatchCycleLocked(const std::shared_ptr<Connection>& connection, bool notify) REQUIRES(mLock); void drainDispatchQueue(std::deque<std::unique_ptr<DispatchEntry>>& queue); void releaseDispatchEntry(std::unique_ptr<DispatchEntry> dispatchEntry); @@ -687,13 +717,10 @@ private: // Dump state. void dumpDispatchStateLocked(std::string& dump) const REQUIRES(mLock); - void dumpMonitors(std::string& dump, const std::vector<Monitor>& monitors) const; void logDispatchStateLocked() const REQUIRES(mLock); std::string dumpPointerCaptureStateLocked() const REQUIRES(mLock); - // Registration. - void removeMonitorChannelLocked(const sp<IBinder>& connectionToken) REQUIRES(mLock); - status_t removeInputChannelLocked(const sp<IBinder>& connectionToken, bool notify) + status_t removeInputChannelLocked(const std::shared_ptr<Connection>& connection, bool notify) REQUIRES(mLock); // Interesting events that we might like to log or tell the framework about. @@ -734,10 +761,6 @@ private: const sp<IBinder>& token, const std::unordered_map<ui::LogicalDisplayId, TouchState>& touchStatesByDisplay); - static bool windowHasTouchingPointers( - const sp<android::gui::WindowInfoHandle>& windowHandle, DeviceId deviceId, - const std::unordered_map<ui::LogicalDisplayId, TouchState>& touchStatesByDisplay); - // Statistics gathering. nsecs_t mLastStatisticPushTime = 0; std::unique_ptr<InputEventTimelineProcessor> mInputEventTimelineProcessor GUARDED_BY(mLock); @@ -779,9 +802,6 @@ private: const std::unique_ptr<trace::EventTrackerInterface>& traceTracker) REQUIRES(mLock); - sp<android::gui::WindowInfoHandle> findWallpaperWindowBelow( - const sp<android::gui::WindowInfoHandle>& windowHandle) const 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/dispatcher/InputTarget.h b/services/inputflinger/dispatcher/InputTarget.h index 90374f1481..76f3fe0d0c 100644 --- a/services/inputflinger/dispatcher/InputTarget.h +++ b/services/inputflinger/dispatcher/InputTarget.h @@ -77,8 +77,8 @@ public: // (ignored for KeyEvents) float globalScaleFactor = 1.0f; - // Current display transform. Used for compatibility for raw coordinates. - ui::Transform displayTransform; + // The raw coordinate transform that's used for compatibility for MotionEvent's getRaw APIs. + ui::Transform rawTransform; // Event time for the first motion event (ACTION_DOWN) dispatched to this input target if // FLAG_SPLIT is set. diff --git a/services/inputflinger/dispatcher/trace/AndroidInputEventProtoConverter.cpp b/services/inputflinger/dispatcher/trace/AndroidInputEventProtoConverter.cpp index 0b17507c2c..cc0468464e 100644 --- a/services/inputflinger/dispatcher/trace/AndroidInputEventProtoConverter.cpp +++ b/services/inputflinger/dispatcher/trace/AndroidInputEventProtoConverter.cpp @@ -115,13 +115,17 @@ void AndroidInputEventProtoConverter::toProtoWindowDispatchEvent( for (size_t i = 0; i < motion->pointerProperties.size(); i++) { auto* pointerProto = outProto.add_dispatched_pointer(); pointerProto->set_pointer_id(motion->pointerProperties[i].id); + const auto& coords = motion->pointerCoords[i]; const auto rawXY = MotionEvent::calculateTransformedXY(motion->source, args.rawTransform, - motion->pointerCoords[i].getXYValue()); - pointerProto->set_x_in_display(rawXY.x); - pointerProto->set_y_in_display(rawXY.y); + coords.getXYValue()); + if (coords.getXYValue() != rawXY) { + // These values are only traced if they were modified by the raw transform + // to save space. Trace consumers should be aware of this optimization. + pointerProto->set_x_in_display(rawXY.x); + pointerProto->set_y_in_display(rawXY.y); + } - const auto& coords = motion->pointerCoords[i]; const auto coordsInWindow = MotionEvent::calculateTransformedCoords(motion->source, motion->flags, args.transform, coords); @@ -129,6 +133,7 @@ void AndroidInputEventProtoConverter::toProtoWindowDispatchEvent( for (int32_t axisIndex = 0; !bits.isEmpty(); axisIndex++) { const uint32_t axis = bits.clearFirstMarkedBit(); const float axisValueInWindow = coordsInWindow.values[axisIndex]; + // Only values that are modified by the window transform are traced. if (coords.values[axisIndex] != axisValueInWindow) { auto* axisEntry = pointerProto->add_axis_value_in_window(); axisEntry->set_axis(axis); diff --git a/services/inputflinger/include/InputReaderBase.h b/services/inputflinger/include/InputReaderBase.h index 404a509247..f54b76b3bf 100644 --- a/services/inputflinger/include/InputReaderBase.h +++ b/services/inputflinger/include/InputReaderBase.h @@ -143,7 +143,7 @@ struct InputReaderConfiguration { // user's pointer speed setting, should be disabled for mice. This differs from // disabling acceleration via the 'mousePointerAccelerationEnabled' setting, where // the pointer speed setting still influences the scaling factor. - std::set<ui::LogicalDisplayId> displaysWithMousePointerAccelerationDisabled; + std::set<ui::LogicalDisplayId> displaysWithMouseScalingDisabled; // True if the connected mouse should exhibit pointer acceleration. If false, // a flat acceleration curve (linear scaling) is used, but the user's pointer @@ -282,7 +282,7 @@ struct InputReaderConfiguration { : virtualKeyQuietTime(0), defaultPointerDisplayId(ui::LogicalDisplayId::DEFAULT), mousePointerSpeed(0), - displaysWithMousePointerAccelerationDisabled(), + displaysWithMouseScalingDisabled(), mousePointerAccelerationEnabled(true), pointerVelocityControlParameters(1.0f, 500.0f, 3000.0f, static_cast<float>( diff --git a/services/inputflinger/reader/Android.bp b/services/inputflinger/reader/Android.bp index b3cd35c936..3934e783d1 100644 --- a/services/inputflinger/reader/Android.bp +++ b/services/inputflinger/reader/Android.bp @@ -79,25 +79,25 @@ cc_defaults { srcs: [":libinputreader_sources"], shared_libs: [ "android.companion.virtualdevice.flags-aconfig-cc", + "libPlatformProperties", "libbase", "libcap", "libcrypto", "libcutils", - "libjsoncpp", "libinput", + "libjsoncpp", "liblog", - "libPlatformProperties", "libstatslog", "libstatspull", - "libutils", "libstatssocket", + "libutils", ], static_libs: [ "libchrome-gestures", - "libui-types", "libexpresslog", - "libtextclassifier_hash_static", "libstatslog_express", + "libtextclassifier_hash_static", + "libui-types", ], header_libs: [ "libbatteryservice_headers", diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.cpp b/services/inputflinger/reader/mapper/CursorInputMapper.cpp index e9f17e796f..9f584a0251 100644 --- a/services/inputflinger/reader/mapper/CursorInputMapper.cpp +++ b/services/inputflinger/reader/mapper/CursorInputMapper.cpp @@ -484,7 +484,7 @@ void CursorInputMapper::configureOnChangePointerSpeed(const InputReaderConfigura return; } - bool disableAllScaling = config.displaysWithMousePointerAccelerationDisabled.count( + bool disableAllScaling = config.displaysWithMouseScalingDisabled.count( mDisplayId.value_or(ui::LogicalDisplayId::INVALID)) != 0; mPointerVelocityControl.setAccelerationEnabled(!disableAllScaling); diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp index 5c90cbb6ce..6efaecaaa8 100644 --- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp +++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp @@ -30,6 +30,7 @@ #include <android-base/stringprintf.h> #include <android/input.h> +#include <com_android_input_flags.h> #include <ftl/enum.h> #include <input/PrintTools.h> #include <input/PropertyMap.h> @@ -47,6 +48,8 @@ namespace android { +namespace input_flags = com::android::input::flags; + // --- Constants --- // Artificial latency on synthetic events created from stylus data without corresponding touch @@ -1575,7 +1578,8 @@ std::list<NotifyArgs> TouchInputMapper::cookAndDispatch(nsecs_t when, nsecs_t re mLastCookedState.buttonState, mCurrentCookedState.buttonState); // Dispatch the touches either directly or by translation through a pointer on screen. - if (mDeviceMode == DeviceMode::POINTER) { + if (!input_flags::disable_touch_input_mapper_pointer_usage() && + mDeviceMode == DeviceMode::POINTER) { for (BitSet32 idBits(mCurrentRawState.rawPointerData.touchingIdBits); !idBits.isEmpty();) { uint32_t id = idBits.clearFirstMarkedBit(); const RawPointerData::Pointer& pointer = @@ -1613,7 +1617,9 @@ std::list<NotifyArgs> TouchInputMapper::cookAndDispatch(nsecs_t when, nsecs_t re } out += dispatchPointerUsage(when, readTime, policyFlags, pointerUsage); - } else { + } + if (input_flags::disable_touch_input_mapper_pointer_usage() || + mDeviceMode != DeviceMode::POINTER) { if (!mCurrentMotionAborted) { out += dispatchButtonRelease(when, readTime, policyFlags); out += dispatchHoverExit(when, readTime, policyFlags); @@ -2251,6 +2257,23 @@ void TouchInputMapper::cookPointerData() { for (uint32_t i = 0; i < currentPointerCount; i++) { const RawPointerData::Pointer& in = mCurrentRawState.rawPointerData.pointers[i]; + bool isHovering = in.isHovering; + + // A tool MOUSE pointer is only down/touching when a mouse button is pressed. + if (input_flags::disable_touch_input_mapper_pointer_usage() && + in.toolType == ToolType::MOUSE && + !mCurrentRawState.rawPointerData.canceledIdBits.hasBit(in.id)) { + if (isPointerDown(mCurrentRawState.buttonState)) { + isHovering = false; + mCurrentCookedState.cookedPointerData.touchingIdBits.markBit(in.id); + mCurrentCookedState.cookedPointerData.hoveringIdBits.clearBit(in.id); + } else { + isHovering = true; + mCurrentCookedState.cookedPointerData.touchingIdBits.clearBit(in.id); + mCurrentCookedState.cookedPointerData.hoveringIdBits.markBit(in.id); + } + } + // Size float touchMajor, touchMinor, toolMajor, toolMinor, size; switch (mCalibration.sizeCalibration) { @@ -2340,7 +2363,7 @@ void TouchInputMapper::cookPointerData() { pressure = in.pressure * mPressureScale; break; default: - pressure = in.isHovering ? 0 : 1; + pressure = isHovering ? 0 : 1; break; } @@ -3476,7 +3499,7 @@ std::list<NotifyArgs> TouchInputMapper::dispatchPointerMouse(nsecs_t when, nsecs } return dispatchPointerSimple(when, readTime, policyFlags, down, hovering, - ui::LogicalDisplayId::INVALID); + getAssociatedDisplayId().value_or(ui::LogicalDisplayId::INVALID)); } std::list<NotifyArgs> TouchInputMapper::abortPointerMouse(nsecs_t when, nsecs_t readTime, @@ -3697,7 +3720,10 @@ NotifyMotionArgs TouchInputMapper::dispatchMotion( float xCursorPosition = AMOTION_EVENT_INVALID_CURSOR_POSITION; float yCursorPosition = AMOTION_EVENT_INVALID_CURSOR_POSITION; if (mDeviceMode == DeviceMode::POINTER) { - xCursorPosition = yCursorPosition = 0.f; + ALOGW_IF(pointerCount != 1, + "Only single pointer events are fully supported in POINTER mode"); + xCursorPosition = pointerCoords[0].getX(); + yCursorPosition = pointerCoords[0].getY(); } const DeviceId deviceId = getDeviceId(); std::vector<TouchVideoFrame> frames = getDeviceContext().getVideoFrames(); @@ -3967,14 +3993,8 @@ bool TouchInputMapper::markSupportedKeyCodes(uint32_t sourceMask, } std::optional<ui::LogicalDisplayId> TouchInputMapper::getAssociatedDisplayId() { - if (mParameters.hasAssociatedDisplay) { - if (mDeviceMode == DeviceMode::POINTER) { - return ui::LogicalDisplayId::INVALID; - } else { - return std::make_optional(mViewport.displayId); - } - } - return std::nullopt; + return mParameters.hasAssociatedDisplay ? std::make_optional(mViewport.displayId) + : std::nullopt; } } // namespace android diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.h b/services/inputflinger/reader/mapper/TouchInputMapper.h index ef0e02f40c..eb4326fa56 100644 --- a/services/inputflinger/reader/mapper/TouchInputMapper.h +++ b/services/inputflinger/reader/mapper/TouchInputMapper.h @@ -215,7 +215,7 @@ protected: DISABLED, // input is disabled DIRECT, // direct mapping (touchscreen) NAVIGATION, // unscaled mapping with assist gesture (touch navigation) - POINTER, // pointer mapping (e.g. uncaptured touchpad, drawing tablet) + POINTER, // pointer mapping (e.g. absolute mouse, drawing tablet) ftl_last = POINTER }; @@ -234,6 +234,9 @@ protected: ftl_last = POINTER }; + // TouchInputMapper will configure devices with INPUT_PROP_DIRECT as + // DeviceType::TOUCH_SCREEN, and will otherwise use DeviceType::POINTER by default. + // This can be overridden by IDC files, using the `touch.deviceType` config. DeviceType deviceType; bool hasAssociatedDisplay; bool associatedDisplayIsExternal; diff --git a/services/inputflinger/tests/CursorInputMapper_test.cpp b/services/inputflinger/tests/CursorInputMapper_test.cpp index a31c4e96d7..18e0b309ba 100644 --- a/services/inputflinger/tests/CursorInputMapper_test.cpp +++ b/services/inputflinger/tests/CursorInputMapper_test.cpp @@ -1078,7 +1078,7 @@ TEST_F(CursorInputMapperUnitTest, ConfigureAccelerationWithAssociatedViewport) { ASSERT_GT(coords.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y), 20.f); // Disable acceleration for the display, and verify that acceleration is no longer applied. - mReaderConfiguration.displaysWithMousePointerAccelerationDisabled.emplace(DISPLAY_ID); + mReaderConfiguration.displaysWithMouseScalingDisabled.emplace(DISPLAY_ID); args += mMapper->reconfigure(ARBITRARY_TIME, mReaderConfiguration, InputReaderConfiguration::Change::POINTER_SPEED); args.clear(); @@ -1097,7 +1097,7 @@ TEST_F(CursorInputMapperUnitTest, ConfigureAccelerationOnDisplayChange) { DisplayViewport primaryViewport = createPrimaryViewport(ui::Rotation::Rotation0); mReaderConfiguration.setDisplayViewports({primaryViewport}); // Disable acceleration for the display. - mReaderConfiguration.displaysWithMousePointerAccelerationDisabled.emplace(DISPLAY_ID); + mReaderConfiguration.displaysWithMouseScalingDisabled.emplace(DISPLAY_ID); // Don't associate the device with the display yet. EXPECT_CALL((*mDevice), getAssociatedViewport).WillRepeatedly(Return(std::nullopt)); diff --git a/services/inputflinger/tests/FakeWindows.h b/services/inputflinger/tests/FakeWindows.h index 3a3238a6ad..54dc25aaa0 100644 --- a/services/inputflinger/tests/FakeWindows.h +++ b/services/inputflinger/tests/FakeWindows.h @@ -144,10 +144,6 @@ public: mInfo.setInputConfig(InputConfig::PAUSE_DISPATCHING, paused); } - inline void setPreventSplitting(bool preventSplitting) { - mInfo.setInputConfig(InputConfig::PREVENT_SPLITTING, preventSplitting); - } - inline void setSlippery(bool slippery) { mInfo.setInputConfig(InputConfig::SLIPPERY, slippery); } diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index fb67cebf29..b6e27a87f8 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -19,6 +19,7 @@ #include "FakeInputDispatcherPolicy.h" #include "FakeInputTracingBackend.h" #include "FakeWindows.h" +#include "ScopedFlagOverride.h" #include "TestEventMatchers.h" #include <NotifyArgsBuilders.h> @@ -138,40 +139,6 @@ static KeyEvent getTestKeyEvent() { return event; } -/** - * Provide a local override for a flag value. The value is restored when the object of this class - * goes out of scope. - * This class is not intended to be used directly, because its usage is cumbersome. - * Instead, a wrapper macro SCOPED_FLAG_OVERRIDE is provided. - */ -class ScopedFlagOverride { -public: - ScopedFlagOverride(std::function<bool()> read, std::function<void(bool)> write, bool value) - : mInitialValue(read()), mWriteValue(write) { - mWriteValue(value); - } - ~ScopedFlagOverride() { mWriteValue(mInitialValue); } - -private: - const bool mInitialValue; - std::function<void(bool)> mWriteValue; -}; - -typedef bool (*readFlagValueFunction)(); -typedef void (*writeFlagValueFunction)(bool); - -/** - * Use this macro to locally override a flag value. - * Example usage: - * SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false); - * Note: this works by creating a local variable in your current scope. Don't call this twice for - * the same flag, because the variable names will clash! - */ -#define SCOPED_FLAG_OVERRIDE(NAME, VALUE) \ - readFlagValueFunction read##NAME = com::android::input::flags::NAME; \ - writeFlagValueFunction write##NAME = com::android::input::flags::NAME; \ - ScopedFlagOverride override##NAME(read##NAME, write##NAME, (VALUE)) - } // namespace // --- InputDispatcherTest --- @@ -1215,22 +1182,17 @@ TEST_F(InputDispatcherTest, MultiDeviceTouchTransferWithWallpaperWindows) { WithFlags(EXPECTED_WALLPAPER_FLAGS | AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE))); } -class ShouldSplitTouchFixture : public InputDispatcherTest, - public ::testing::WithParamInterface<bool> {}; -INSTANTIATE_TEST_SUITE_P(InputDispatcherTest, ShouldSplitTouchFixture, - ::testing::Values(true, false)); /** * A single window that receives touch (on top), and a wallpaper window underneath it. * The top window gets a multitouch gesture. * Ensure that wallpaper gets the same gesture. */ -TEST_P(ShouldSplitTouchFixture, WallpaperWindowReceivesMultiTouch) { +TEST_F(InputDispatcherTest, WallpaperWindowReceivesMultiTouch) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); sp<FakeWindowHandle> foregroundWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Foreground", ui::LogicalDisplayId::DEFAULT); foregroundWindow->setDupTouchToWallpaper(true); - foregroundWindow->setPreventSplitting(GetParam()); sp<FakeWindowHandle> wallpaperWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper", @@ -1575,6 +1537,60 @@ TEST_F(InputDispatcherTest, HoverEventInconsistentPolicy) { window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT)); } +// Still send inject motion events to window which already be touched. +TEST_F(InputDispatcherTest, AlwaysDispatchInjectMotionEventWhenAlreadyDownForWindow) { + std::shared_ptr<FakeApplicationHandle> application1 = std::make_shared<FakeApplicationHandle>(); + sp<FakeWindowHandle> window1 = + sp<FakeWindowHandle>::make(application1, mDispatcher, "window1", + ui::LogicalDisplayId::DEFAULT); + window1->setFrame(Rect(0, 0, 100, 100)); + window1->setWatchOutsideTouch(false); + + std::shared_ptr<FakeApplicationHandle> application2 = std::make_shared<FakeApplicationHandle>(); + sp<FakeWindowHandle> window2 = + sp<FakeWindowHandle>::make(application2, mDispatcher, "window2", + ui::LogicalDisplayId::DEFAULT); + window2->setFrame(Rect(50, 50, 100, 100)); + window2->setWatchOutsideTouch(true); + mDispatcher->onWindowInfosChanged({{*window2->getInfo(), *window1->getInfo()}, {}, 0, 0}); + + std::chrono::milliseconds injectionTimeout = INJECT_EVENT_TIMEOUT; + InputEventInjectionSync injectionMode = InputEventInjectionSync::WAIT_FOR_RESULT; + std::optional<gui::Uid> targetUid = {}; + uint32_t policyFlags = DEFAULT_POLICY_FLAGS; + + const MotionEvent eventDown1 = MotionEventBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .pointer(PointerBuilder(0, ToolType::FINGER).x(60).y(60)).deviceId(-1) + .build(); + injectMotionEvent(*mDispatcher, eventDown1, injectionTimeout, injectionMode, targetUid, + policyFlags); + window2->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); + + const MotionEvent eventUp1 = MotionEventBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN) + .pointer(PointerBuilder(0, ToolType::FINGER).x(60).y(60)).deviceId(-1) + .downTime(eventDown1.getDownTime()).build(); + // Inject UP event, without the POLICY_FLAG_PASS_TO_USER (to simulate policy behaviour + // when screen is off). + injectMotionEvent(*mDispatcher, eventUp1, injectionTimeout, injectionMode, targetUid, + /*policyFlags=*/0); + window2->consumeMotionEvent(WithMotionAction(ACTION_UP)); + const MotionEvent eventDown2 = MotionEventBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .pointer(PointerBuilder(0, ToolType::FINGER).x(40).y(40)).deviceId(-1) + .build(); + injectMotionEvent(*mDispatcher, eventDown2, injectionTimeout, injectionMode, targetUid, + policyFlags); + window1->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); + window2->consumeMotionEvent(WithMotionAction(ACTION_OUTSIDE)); + + const MotionEvent eventUp2 = MotionEventBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN) + .pointer(PointerBuilder(0, ToolType::FINGER).x(60).y(60)).deviceId(-1) + .downTime(eventDown2.getDownTime()).build(); + injectMotionEvent(*mDispatcher, eventUp2, injectionTimeout, injectionMode, targetUid, + /*policyFlags=*/0); + window1->consumeMotionEvent(WithMotionAction(ACTION_UP)); + window2->assertNoEvents(); +} + /** * Two windows: a window on the left and a window on the right. * Mouse is hovered from the right window into the left window. @@ -4260,17 +4276,15 @@ TEST_F(InputDispatcherTest, SplitTouchesSendCorrectActionDownTime) { } /** - * When events are not split, the downTime should be adjusted such that the downTime corresponds + * When events are split, the downTime should be adjusted such that the downTime corresponds * to the event time of the first ACTION_DOWN. If a new window appears, it should not affect - * the event routing because the first window prevents splitting. + * the event routing unless pointers are delivered to the new window. */ TEST_F(InputDispatcherTest, SplitTouchesSendCorrectActionDownTimeForNewWindow) { - SCOPED_FLAG_OVERRIDE(split_all_touches, false); std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); sp<FakeWindowHandle> window1 = sp<FakeWindowHandle>::make(application, mDispatcher, "Window1", DISPLAY_ID); window1->setTouchableRegion(Region{{0, 0, 100, 100}}); - window1->setPreventSplitting(true); sp<FakeWindowHandle> window2 = sp<FakeWindowHandle>::make(application, mDispatcher, "Window2", DISPLAY_ID); @@ -4290,13 +4304,18 @@ TEST_F(InputDispatcherTest, SplitTouchesSendCorrectActionDownTimeForNewWindow) { // Second window is added mDispatcher->onWindowInfosChanged({{*window1->getInfo(), *window2->getInfo()}, {}, 0, 0}); - // Now touch down on the window with another pointer - mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) - .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50)) - .pointer(PointerBuilder(1, ToolType::FINGER).x(150).y(50)) - .downTime(downArgs.downTime) - .build()); - window1->consumeMotionPointerDown(1, AllOf(WithDownTime(downArgs.downTime))); + // Now touch down on the new window with another pointer + NotifyMotionArgs pointerDownArgs = + MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50)) + .pointer(PointerBuilder(1, ToolType::FINGER).x(150).y(50)) + .downTime(downArgs.downTime) + .build(); + mDispatcher->notifyMotion(pointerDownArgs); + window1->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithPointerCount(1), + WithDownTime(downArgs.downTime))); + window2->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_DOWN), WithDownTime(pointerDownArgs.eventTime))); // Finish the gesture mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN) @@ -4304,11 +4323,16 @@ TEST_F(InputDispatcherTest, SplitTouchesSendCorrectActionDownTimeForNewWindow) { .pointer(PointerBuilder(1, ToolType::FINGER).x(150).y(50)) .downTime(downArgs.downTime) .build()); + window1->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_MOVE), WithDownTime(downArgs.downTime))); + window2->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_UP), WithDownTime(pointerDownArgs.eventTime))); + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN) .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50)) .downTime(downArgs.downTime) .build()); - window1->consumeMotionPointerUp(1, AllOf(WithDownTime(downArgs.downTime))); + window1->consumeMotionEvent( AllOf(WithMotionAction(ACTION_UP), WithDownTime(downArgs.downTime))); window2->assertNoEvents(); @@ -4317,13 +4341,12 @@ TEST_F(InputDispatcherTest, SplitTouchesSendCorrectActionDownTimeForNewWindow) { /** * When splitting touch events, the downTime should be adjusted such that the downTime corresponds * to the event time of the first ACTION_DOWN sent to the new window. - * If a new window that does not support split appears on the screen and gets touched with the - * second finger, it should not get any events because it doesn't want split touches. At the same - * time, the first window should not get the pointer_down event because it supports split touches - * (and the touch occurred outside of the bounds of window1). + * If a new window appears on the screen and gets touched with the + * second finger, it should get the new event. At the same + * time, the first window should not get the pointer_down event because + * the touch occurred outside of its bounds. */ -TEST_F(InputDispatcherTest, SplitTouchesDropsEventForNonSplittableSecondWindow) { - SCOPED_FLAG_OVERRIDE(split_all_touches, false); +TEST_F(InputDispatcherTest, SplitTouchesWhenWindowIsAdded) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); sp<FakeWindowHandle> window1 = sp<FakeWindowHandle>::make(application, mDispatcher, "Window1", DISPLAY_ID); @@ -4345,16 +4368,16 @@ TEST_F(InputDispatcherTest, SplitTouchesDropsEventForNonSplittableSecondWindow) AllOf(WithMotionAction(ACTION_DOWN), WithDownTime(downArgs.downTime))); // Second window is added - window2->setPreventSplitting(true); mDispatcher->onWindowInfosChanged({{*window1->getInfo(), *window2->getInfo()}, {}, 0, 0}); - // Now touch down on the window with another pointer + // Now touch down on the new window with another pointer mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50)) .pointer(PointerBuilder(1, ToolType::FINGER).x(150).y(50)) .downTime(downArgs.downTime) .build()); - // Event is dropped because window2 doesn't support split touch, and window1 does. + window1->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithPointerCount(1))); + window2->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); // Complete the gesture mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN) @@ -4365,6 +4388,8 @@ TEST_F(InputDispatcherTest, SplitTouchesDropsEventForNonSplittableSecondWindow) // A redundant MOVE event is generated that doesn't carry any new information window1->consumeMotionEvent( AllOf(WithMotionAction(ACTION_MOVE), WithDownTime(downArgs.downTime))); + window2->consumeMotionEvent(WithMotionAction(ACTION_UP)); + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN) .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50)) .downTime(downArgs.downTime) @@ -4584,22 +4609,20 @@ TEST_F(InputDispatcherTest, TwoPointersDownMouseClick) { * A spy window sits above a window with NO_INPUT_CHANNEL. Ensure that the spy receives events even * though the window underneath should not get any events. */ -TEST_F(InputDispatcherTest, NonSplittableSpyAboveNoInputChannelWindowSinglePointer) { +TEST_F(InputDispatcherTest, SpyAboveNoInputChannelWindowSinglePointer) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); sp<FakeWindowHandle> spyWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ui::LogicalDisplayId::DEFAULT); spyWindow->setFrame(Rect(0, 0, 100, 100)); spyWindow->setTrustedOverlay(true); - spyWindow->setPreventSplitting(true); spyWindow->setSpy(true); - // Another window below spy that has both NO_INPUT_CHANNEL and PREVENT_SPLITTING + // Another window below spy that has NO_INPUT_CHANNEL sp<FakeWindowHandle> inputSinkWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Input sink below spy", ui::LogicalDisplayId::DEFAULT); inputSinkWindow->setFrame(Rect(0, 0, 100, 100)); inputSinkWindow->setTrustedOverlay(true); - inputSinkWindow->setPreventSplitting(true); inputSinkWindow->setNoInputChannel(true); mDispatcher->onWindowInfosChanged( @@ -4624,22 +4647,20 @@ TEST_F(InputDispatcherTest, NonSplittableSpyAboveNoInputChannelWindowSinglePoint * though the window underneath should not get any events. * Same test as above, but with two pointers touching instead of one. */ -TEST_F(InputDispatcherTest, NonSplittableSpyAboveNoInputChannelWindowTwoPointers) { +TEST_F(InputDispatcherTest, SpyAboveNoInputChannelWindowTwoPointers) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); sp<FakeWindowHandle> spyWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ui::LogicalDisplayId::DEFAULT); spyWindow->setFrame(Rect(0, 0, 100, 100)); spyWindow->setTrustedOverlay(true); - spyWindow->setPreventSplitting(true); spyWindow->setSpy(true); - // Another window below spy that would have both NO_INPUT_CHANNEL and PREVENT_SPLITTING + // Another window below spy that would have NO_INPUT_CHANNEL sp<FakeWindowHandle> inputSinkWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Input sink below spy", ui::LogicalDisplayId::DEFAULT); inputSinkWindow->setFrame(Rect(0, 0, 100, 100)); inputSinkWindow->setTrustedOverlay(true); - inputSinkWindow->setPreventSplitting(true); inputSinkWindow->setNoInputChannel(true); mDispatcher->onWindowInfosChanged( @@ -4671,15 +4692,10 @@ TEST_F(InputDispatcherTest, NonSplittableSpyAboveNoInputChannelWindowTwoPointers inputSinkWindow->assertNoEvents(); } -/** Check the behaviour for cases where input sink prevents or doesn't prevent splitting. */ -class SpyThatPreventsSplittingWithApplicationFixture : public InputDispatcherTest, - public ::testing::WithParamInterface<bool> { -}; - /** * Three windows: * - An application window (app window) - * - A spy window that does not overlap the app window. Has PREVENT_SPLITTING flag + * - A spy window that does not overlap the app window. * - A window below the spy that has NO_INPUT_CHANNEL (call it 'inputSink') * * The spy window is side-by-side with the app window. The inputSink is below the spy. @@ -4687,34 +4703,31 @@ class SpyThatPreventsSplittingWithApplicationFixture : public InputDispatcherTes * Only the SPY window should get the DOWN event. * The spy pilfers after receiving the first DOWN event. * Next, we touch the app window. - * The spy should receive POINTER_DOWN(1) (since spy is preventing splits). - * Also, since the spy is already pilfering the first pointer, it will be sent the remaining new - * pointers automatically, as well. + * The spy should not receive POINTER_DOWN(1) (since the pointer is outside of the spy). * Next, the first pointer (from the spy) is lifted. - * Spy should get POINTER_UP(0). + * Spy should get ACTION_UP. * This event should not go to the app because the app never received this pointer to begin with. - * Now, lift the remaining pointer and check that the spy receives UP event. + * However, due to the current implementation, this would still cause an ACTION_MOVE event in the + * app. + * Now, lift the remaining pointer and check that the app receives UP event. * - * Finally, send a new ACTION_DOWN event to the spy and check that it's received. + * Finally, send a new ACTION_DOWN event to the spy and check that it gets received. * This test attempts to reproduce a crash in the dispatcher. */ -TEST_P(SpyThatPreventsSplittingWithApplicationFixture, SpyThatPreventsSplittingWithApplication) { - SCOPED_FLAG_OVERRIDE(split_all_touches, false); +TEST_F(InputDispatcherTest, SpyThatPilfersAfterFirstPointerWithTwoOtherWindows) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); sp<FakeWindowHandle> spyWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ui::LogicalDisplayId::DEFAULT); spyWindow->setFrame(Rect(100, 100, 200, 200)); spyWindow->setTrustedOverlay(true); - spyWindow->setPreventSplitting(true); spyWindow->setSpy(true); - // Another window below spy that has both NO_INPUT_CHANNEL and PREVENT_SPLITTING + // Another window below spy that has NO_INPUT_CHANNEL sp<FakeWindowHandle> inputSinkWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Input sink below spy", ui::LogicalDisplayId::DEFAULT); inputSinkWindow->setFrame(Rect(100, 100, 200, 200)); // directly below the spy inputSinkWindow->setTrustedOverlay(true); - inputSinkWindow->setPreventSplitting(GetParam()); inputSinkWindow->setNoInputChannel(true); sp<FakeWindowHandle> appWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "App", @@ -4736,16 +4749,15 @@ TEST_P(SpyThatPreventsSplittingWithApplicationFixture, SpyThatPreventsSplittingW mDispatcher->pilferPointers(spyWindow->getToken()); - // Second finger lands in the app, and goes to the spy window. It doesn't go to the app because - // the spy is already pilfering the first pointer, and this automatically grants the remaining - // new pointers to the spy, as well. + // Second finger lands in the app. It goes to the app as ACTION_DOWN. mDispatcher->notifyMotion( MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(150).y(150)) .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50)) .build()); - spyWindow->consumeMotionPointerDown(1, WithPointerCount(2)); + spyWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithPointerCount(1))); + appWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); // Now lift up the first pointer mDispatcher->notifyMotion( @@ -4753,14 +4765,15 @@ TEST_P(SpyThatPreventsSplittingWithApplicationFixture, SpyThatPreventsSplittingW .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(150).y(150)) .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50)) .build()); - spyWindow->consumeMotionPointerUp(0, WithPointerCount(2)); + spyWindow->consumeMotionEvent(WithMotionAction(ACTION_UP)); + appWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithPointerCount(1))); // And lift the remaining pointer! mDispatcher->notifyMotion( MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN) .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50)) .build()); - spyWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_UP), WithPointerCount(1))); + appWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_UP), WithPointerCount(1))); // Now send a new DOWN, which should again go to spy. mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) @@ -4772,10 +4785,6 @@ TEST_P(SpyThatPreventsSplittingWithApplicationFixture, SpyThatPreventsSplittingW appWindow->assertNoEvents(); } -// Behaviour should be the same regardless of whether inputSink supports splitting. -INSTANTIATE_TEST_SUITE_P(SpyThatPreventsSplittingWithApplication, - SpyThatPreventsSplittingWithApplicationFixture, testing::Bool()); - TEST_F(InputDispatcherTest, HoverWithSpyWindows) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); @@ -5729,14 +5738,12 @@ TEST_F(InputDispatcherTest, OnWindowInfosChanged_RemoveAllWindowsOnDisplay) { window->assertNoEvents(); } -TEST_F(InputDispatcherTest, NonSplitTouchableWindowReceivesMultiTouch) { - SCOPED_FLAG_OVERRIDE(split_all_touches, false); +TEST_F(InputDispatcherTest, WindowDoesNotReceiveSecondPointerOutsideOfItsBounds) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Fake Window", ui::LogicalDisplayId::DEFAULT); - // Ensure window is non-split and have some transform. - window->setPreventSplitting(true); + // Ensure window has a non-trivial transform. window->setWindowOffset(20, 40); mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); @@ -5744,7 +5751,10 @@ TEST_F(InputDispatcherTest, NonSplitTouchableWindowReceivesMultiTouch) { injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ui::LogicalDisplayId::DEFAULT, {50, 50})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; - window->consumeMotionDown(ui::LogicalDisplayId::DEFAULT); + window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), + WithCoords(70, // 50 + 20 + 90 // 50 + 40 + ))); const MotionEvent secondFingerDownEvent = MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) @@ -5753,45 +5763,32 @@ TEST_F(InputDispatcherTest, NonSplitTouchableWindowReceivesMultiTouch) { .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50)) .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(-30).y(-50)) .build(); - ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + ASSERT_EQ(InputEventInjectionResult::FAILED, injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, InputEventInjectionSync::WAIT_FOR_RESULT)) - << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; - - std::unique_ptr<MotionEvent> event = window->consumeMotionEvent(); - ASSERT_NE(nullptr, event); - EXPECT_EQ(POINTER_1_DOWN, event->getAction()); - EXPECT_EQ(70, event->getX(0)); // 50 + 20 - EXPECT_EQ(90, event->getY(0)); // 50 + 40 - EXPECT_EQ(-10, event->getX(1)); // -30 + 20 - EXPECT_EQ(-10, event->getY(1)); // -50 + 40 + << "Injection should fail because the second finger is outside of any window on the " + "screen."; } /** - * Two windows: a splittable and a non-splittable. - * The non-splittable window shouldn't receive any "incomplete" gestures. - * Send the first pointer to the splittable window, and then touch the non-splittable window. - * The second pointer should be dropped because the initial window is splittable, so it won't get - * any pointers outside of it, and the second window is non-splittable, so it shouldn't get any - * "incomplete" gestures. + * Two windows. + * Send the first pointer to the left window, and then touch the right window. + * The second pointer should generate an ACTION_DOWN in the right window. */ -TEST_F(InputDispatcherTest, SplittableAndNonSplittableWindows) { - SCOPED_FLAG_OVERRIDE(split_all_touches, false); +TEST_F(InputDispatcherTest, TwoWindowsTwoPointers) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); sp<FakeWindowHandle> leftWindow = - sp<FakeWindowHandle>::make(application, mDispatcher, "Left splittable Window", + sp<FakeWindowHandle>::make(application, mDispatcher, "Left Window", ui::LogicalDisplayId::DEFAULT); - leftWindow->setPreventSplitting(false); leftWindow->setFrame(Rect(0, 0, 100, 100)); sp<FakeWindowHandle> rightWindow = - sp<FakeWindowHandle>::make(application, mDispatcher, "Right non-splittable Window", + sp<FakeWindowHandle>::make(application, mDispatcher, "Right Window", ui::LogicalDisplayId::DEFAULT); - rightWindow->setPreventSplitting(true); rightWindow->setFrame(Rect(100, 100, 200, 200)); mDispatcher->onWindowInfosChanged( {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0}); - // Touch down on left, splittable window + // Touch down on left window mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50)) .build()); @@ -5802,8 +5799,8 @@ TEST_F(InputDispatcherTest, SplittableAndNonSplittableWindows) { .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50)) .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(150)) .build()); - leftWindow->assertNoEvents(); - rightWindow->assertNoEvents(); + leftWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE)); + rightWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); } /** @@ -5826,7 +5823,6 @@ TEST_F(InputDispatcherTest, WallpaperWindowWhenSlipperyAndMultiWindowMultiTouch) sp<FakeWindowHandle>::make(application1, mDispatcher, "wallpaper", ui::LogicalDisplayId::DEFAULT); wallpaper->setIsWallpaper(true); - wallpaper->setPreventSplitting(true); wallpaper->setTouchable(false); sp<FakeWindowHandle> leftWindow = sp<FakeWindowHandle>::make(application2, mDispatcher, "Left", @@ -5960,7 +5956,6 @@ TEST_F(InputDispatcherTest, WallpaperWindowWhenSlipperyAndMultiWindowMultiTouch_ sp<FakeWindowHandle>::make(application1, mDispatcher, "wallpaper", ui::LogicalDisplayId::DEFAULT); wallpaper->setIsWallpaper(true); - wallpaper->setPreventSplitting(true); wallpaper->setTouchable(false); sp<FakeWindowHandle> leftWindow = sp<FakeWindowHandle>::make(application2, mDispatcher, "Left", @@ -6074,20 +6069,18 @@ TEST_F(InputDispatcherTest, WallpaperWindowWhenSlipperyAndMultiWindowMultiTouch_ } /** - * Two windows: left and right. The left window has PREVENT_SPLITTING input config. Device A sends a - * down event to the right window. Device B sends a down event to the left window, and then a - * POINTER_DOWN event to the right window. However, since the left window prevents splitting, the - * POINTER_DOWN event should only go to the left window, and not to the right window. + * Two windows: left and right. Device A sends a DOWN event to the right window. Device B sends a + * DOWN event to the left window, and then a POINTER_DOWN event outside of all windows. + * The POINTER_DOWN event should be dropped. * This test attempts to reproduce a crash. */ -TEST_F(InputDispatcherTest, MultiDeviceTwoWindowsPreventSplitting) { - SCOPED_FLAG_OVERRIDE(split_all_touches, false); +TEST_F(InputDispatcherTest, MultiDeviceTwoWindowsTwoPointers) { + SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true); std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); sp<FakeWindowHandle> leftWindow = - sp<FakeWindowHandle>::make(application, mDispatcher, "Left window (prevent splitting)", + sp<FakeWindowHandle>::make(application, mDispatcher, "Left window", ui::LogicalDisplayId::DEFAULT); leftWindow->setFrame(Rect(0, 0, 100, 100)); - leftWindow->setPreventSplitting(true); sp<FakeWindowHandle> rightWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Right window", @@ -6111,14 +6104,14 @@ TEST_F(InputDispatcherTest, MultiDeviceTwoWindowsPreventSplitting) { .deviceId(deviceB) .build()); leftWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceB))); - // Send a second pointer from device B to the right window. It shouldn't go to the right window - // because the left window prevents splitting. + + // Send a second pointer from device B to an area outside of all windows. mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .deviceId(deviceB) .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50)) .pointer(PointerBuilder(1, ToolType::FINGER).x(120).y(120)) .build()); - leftWindow->consumeMotionPointerDown(1, WithDeviceId(deviceB)); + // This is dropped because there's no touchable window at the location (120, 120) // Finish the gesture for both devices mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN) @@ -6126,7 +6119,8 @@ TEST_F(InputDispatcherTest, MultiDeviceTwoWindowsPreventSplitting) { .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50)) .pointer(PointerBuilder(1, ToolType::FINGER).x(120).y(120)) .build()); - leftWindow->consumeMotionPointerUp(1, WithDeviceId(deviceB)); + leftWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithPointerId(0, 0))); + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN) .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50)) .deviceId(deviceB) @@ -6505,19 +6499,47 @@ TEST_F(InputDispatcherDisplayProjectionTest, WindowGetsEventsInCorrectCoordinate ui::LogicalDisplayId::DEFAULT, {PointF{150, 220}})); firstWindow->assertNoEvents(); - std::unique_ptr<MotionEvent> event = secondWindow->consumeMotionEvent(); - ASSERT_NE(nullptr, event); - EXPECT_EQ(AMOTION_EVENT_ACTION_DOWN, event->getAction()); + secondWindow->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_DOWN), + // Ensure that the events from the "getRaw" API are in logical display + // coordinates, which has an x-scale of 2 and y-scale of 4. + WithRawCoords(300, 880), + // Ensure that the x and y values are in the window's coordinate space. + // The left-top of the second window is at (100, 200) in display space, which is + // (200, 800) in the logical display space. This will be the origin of the window + // space. + WithCoords(100, 80))); +} - // Ensure that the events from the "getRaw" API are in logical display coordinates. - EXPECT_EQ(300, event->getRawX(0)); - EXPECT_EQ(880, event->getRawY(0)); +TEST_F(InputDispatcherDisplayProjectionTest, UseCloneLayerStackTransformForRawCoordinates) { + SCOPED_FLAG_OVERRIDE(use_cloned_screen_coordinates_as_raw, true); - // Ensure that the x and y values are in the window's coordinate space. - // The left-top of the second window is at (100, 200) in display space, which is (200, 800) in - // the logical display space. This will be the origin of the window space. - EXPECT_EQ(100, event->getX(0)); - EXPECT_EQ(80, event->getY(0)); + auto [firstWindow, secondWindow] = setupScaledDisplayScenario(); + + const std::array<float, 9> matrix = {1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 0.0, 0.0, 1.0}; + ui::Transform secondDisplayTransform; + secondDisplayTransform.set(matrix); + addDisplayInfo(SECOND_DISPLAY_ID, secondDisplayTransform); + + // When a clone layer stack transform is provided for a window, we should use that as the + // "display transform" for input going to that window. + sp<FakeWindowHandle> secondWindowClone = secondWindow->clone(SECOND_DISPLAY_ID); + secondWindowClone->editInfo()->cloneLayerStackTransform = ui::Transform(); + secondWindowClone->editInfo()->cloneLayerStackTransform->set(0.5, 0, 0, 0.25); + addWindow(secondWindowClone); + + // Touch down on the clone window, and ensure its raw coordinates use + // the clone layer stack transform. + mDispatcher->notifyMotion(generateMotionArgs(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, + SECOND_DISPLAY_ID, {PointF{150, 220}})); + secondWindowClone->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_DOWN), + // Ensure the x and y coordinates are in the window's coordinate space. + // See previous test case for calculation. + WithCoords(100, 80), + // Ensure the "getRaw" API uses the clone layer stack transform when it is + // provided for the window. It has an x-scale of 0.5 and y-scale of 0.25. + WithRawCoords(75, 55))); } TEST_F(InputDispatcherDisplayProjectionTest, CancelMotionWithCorrectCoordinates) { @@ -6953,7 +6975,7 @@ TEST_P(TransferTouchFixture, TransferTouch_MultipleWindowsWithSpy) { AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE); } -TEST_P(TransferTouchFixture, TransferTouch_TwoPointersNonSplitTouch) { +TEST_P(TransferTouchFixture, TransferTouch_TwoPointers) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); PointF touchPoint = {10, 10}; @@ -6962,11 +6984,9 @@ TEST_P(TransferTouchFixture, TransferTouch_TwoPointersNonSplitTouch) { sp<FakeWindowHandle> firstWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "First Window", ui::LogicalDisplayId::DEFAULT); - firstWindow->setPreventSplitting(true); sp<FakeWindowHandle> secondWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window", ui::LogicalDisplayId::DEFAULT); - secondWindow->setPreventSplitting(true); // Add the windows to the dispatcher mDispatcher->onWindowInfosChanged( @@ -8823,12 +8843,10 @@ TEST_F(InputDispatcherTest, HoverEnterExitSynthesisUsesNewEventId) { } /** - * When a device reports a DOWN event, which lands in a window that supports splits, and then the - * device then reports a POINTER_DOWN, which lands in the location of a non-existing window, then - * the previous window should receive this event and not be dropped. + * First finger lands into a window, and then the second finger lands in the location of a + * non-existent window. The second finger should be dropped. */ TEST_F(InputDispatcherMultiDeviceTest, SingleDevicePointerDownEventRetentionWithoutWindowTarget) { - SCOPED_FLAG_OVERRIDE(split_all_touches, false); std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ui::LogicalDisplayId::DEFAULT); @@ -8846,13 +8864,13 @@ TEST_F(InputDispatcherMultiDeviceTest, SingleDevicePointerDownEventRetentionWith .pointer(PointerBuilder(1, ToolType::FINGER).x(200).y(200)) .build()); - window->consumeMotionEvent(AllOf(WithMotionAction(POINTER_1_DOWN))); + window->assertNoEvents(); } /** * When deviceA reports a DOWN event, which lands in a window that supports splits, and then deviceB * also reports a DOWN event, which lands in the location of a non-existing window, then the - * previous window should receive deviceB's event and it should be dropped. + * previous window should not receive deviceB's event and it should be dropped. */ TEST_F(InputDispatcherMultiDeviceTest, SecondDeviceDownEventDroppedWithoutWindowTarget) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); @@ -12653,9 +12671,6 @@ TEST_F(InputDispatcherDragTests, DragAndDropOnInvalidWindow) { } TEST_F(InputDispatcherDragTests, NoDragAndDropWhenMultiFingers) { - // Ensure window could track pointerIds if it didn't support split touch. - mWindow->setPreventSplitting(true); - ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ui::LogicalDisplayId::DEFAULT, {50, 50})) @@ -13555,14 +13570,10 @@ TEST_F(InputDispatcherSpyWindowTest, ReceivesSecondPointerAsDown) { } /** - * The spy window should not be able to affect whether or not touches are split. Only the foreground - * windows should be allowed to control split touch. + * The spy window should not be able to affect whether or not touches are split. */ TEST_F(InputDispatcherSpyWindowTest, SplitIfNoForegroundWindowTouched) { - // This spy window prevents touch splitting. However, we still expect to split touches - // because a foreground window has not disabled splitting. auto spy = createSpy(); - spy->setPreventSplitting(true); auto window = createForeground(); window->setFrame(Rect(0, 0, 100, 100)); diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp index 0906536e32..470e65b8b5 100644 --- a/services/inputflinger/tests/InputReader_test.cpp +++ b/services/inputflinger/tests/InputReader_test.cpp @@ -28,6 +28,7 @@ #include <MultiTouchInputMapper.h> #include <NotifyArgsBuilders.h> #include <PeripheralController.h> +#include <ScopedFlagOverride.h> #include <SingleTouchInputMapper.h> #include <TestEventMatchers.h> #include <TestInputListener.h> @@ -4526,6 +4527,10 @@ TEST_F(SingleTouchInputMapperTest, Process_ShouldHandleAllToolTypes) { NotifyMotionArgs motionArgs; + // Hold down the mouse button for the duration of the test, since the mouse tools require + // the button to be pressed to make sure they are not hovering. + processKey(mapper, BTN_MOUSE, 1); + // default tool type is finger processDown(mapper, 100, 200); processSync(mapper); @@ -4533,6 +4538,9 @@ TEST_F(SingleTouchInputMapperTest, Process_ShouldHandleAllToolTypes) { ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled( + WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS))); + // eraser processKey(mapper, BTN_TOOL_RUBBER, 1); processSync(mapper); @@ -7175,6 +7183,10 @@ TEST_F(MultiTouchInputMapperTest, Process_ShouldHandleAllToolTypes) { NotifyMotionArgs motionArgs; + // Hold down the mouse button for the duration of the test, since the mouse tools require + // the button to be pressed to make sure they are not hovering. + processKey(mapper, BTN_MOUSE, 1); + // default tool type is finger processId(mapper, 1); processPosition(mapper, 100, 200); @@ -7183,6 +7195,9 @@ TEST_F(MultiTouchInputMapperTest, Process_ShouldHandleAllToolTypes) { ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled( + WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS))); + // eraser processKey(mapper, BTN_TOOL_RUBBER, 1); processSync(mapper); @@ -7520,6 +7535,7 @@ TEST_F(MultiTouchInputMapperTest, Configure_AssignsDisplayUniqueId) { } TEST_F(MultiTouchInputMapperTest, Process_Pointer_ShouldHandleDisplayId) { + SCOPED_FLAG_OVERRIDE(disable_touch_input_mapper_pointer_usage, true); prepareSecondaryDisplay(ViewportType::EXTERNAL); prepareDisplay(ui::ROTATION_0); @@ -7532,9 +7548,9 @@ TEST_F(MultiTouchInputMapperTest, Process_Pointer_ShouldHandleDisplayId) { processPosition(mapper, 100, 100); processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action); - ASSERT_EQ(ui::LogicalDisplayId::INVALID, motionArgs.displayId); + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithDisplayId(DISPLAY_ID), + WithSource(AINPUT_SOURCE_MOUSE), WithToolType(ToolType::FINGER)))); } /** @@ -8604,6 +8620,8 @@ protected: * fingers start to move downwards, the gesture should be swipe. */ TEST_F(MultiTouchPointerModeTest, PointerGestureMaxSwipeWidthSwipe) { + SCOPED_FLAG_OVERRIDE(disable_touch_input_mapper_pointer_usage, false); + // The min freeform gesture width is 25units/mm x 30mm = 750 // which is greater than fraction of the diagnal length of the touchpad (349). // Thus, MaxSwipWidth is 750. @@ -8664,6 +8682,8 @@ TEST_F(MultiTouchPointerModeTest, PointerGestureMaxSwipeWidthSwipe) { * the gesture should be swipe. */ TEST_F(MultiTouchPointerModeTest, PointerGestureMaxSwipeWidthLowResolutionSwipe) { + SCOPED_FLAG_OVERRIDE(disable_touch_input_mapper_pointer_usage, false); + // The min freeform gesture width is 5units/mm x 30mm = 150 // which is greater than fraction of the diagnal length of the touchpad (349). // Thus, MaxSwipWidth is the fraction of the diagnal length, 349. @@ -8723,6 +8743,8 @@ TEST_F(MultiTouchPointerModeTest, PointerGestureMaxSwipeWidthLowResolutionSwipe) * freeform gestures after two fingers start to move downwards. */ TEST_F(MultiTouchPointerModeTest, PointerGestureMaxSwipeWidthFreeform) { + SCOPED_FLAG_OVERRIDE(disable_touch_input_mapper_pointer_usage, false); + preparePointerMode(/*xResolution=*/25, /*yResolution=*/25); MultiTouchInputMapper& mapper = constructAndAddMapper<MultiTouchInputMapper>(); @@ -8818,6 +8840,8 @@ TEST_F(MultiTouchPointerModeTest, PointerGestureMaxSwipeWidthFreeform) { } TEST_F(MultiTouchPointerModeTest, TwoFingerSwipeOffsets) { + SCOPED_FLAG_OVERRIDE(disable_touch_input_mapper_pointer_usage, false); + preparePointerMode(/*xResolution=*/25, /*yResolution=*/25); MultiTouchInputMapper& mapper = constructAndAddMapper<MultiTouchInputMapper>(); NotifyMotionArgs motionArgs; @@ -8864,6 +8888,8 @@ TEST_F(MultiTouchPointerModeTest, TwoFingerSwipeOffsets) { } TEST_F(MultiTouchPointerModeTest, WhenViewportActiveStatusChanged_PointerGestureIsReset) { + SCOPED_FLAG_OVERRIDE(disable_touch_input_mapper_pointer_usage, false); + preparePointerMode(/*xResolution=*/25, /*yResolution=*/25); mFakeEventHub->addKey(EVENTHUB_ID, BTN_TOOL_PEN, 0, AKEYCODE_UNKNOWN, 0); MultiTouchInputMapper& mapper = constructAndAddMapper<MultiTouchInputMapper>(); diff --git a/services/inputflinger/tests/MultiTouchInputMapper_test.cpp b/services/inputflinger/tests/MultiTouchInputMapper_test.cpp index 9a6b266b21..d15048dddf 100644 --- a/services/inputflinger/tests/MultiTouchInputMapper_test.cpp +++ b/services/inputflinger/tests/MultiTouchInputMapper_test.cpp @@ -23,6 +23,7 @@ #include "InputMapperTest.h" #include "InterfaceMocks.h" +#include "ScopedFlagOverride.h" #include "TestEventMatchers.h" #define TAG "MultiTouchpadInputMapperUnit_test" @@ -30,6 +31,7 @@ namespace android { using testing::_; +using testing::AllOf; using testing::IsEmpty; using testing::Return; using testing::SetArgPointee; @@ -266,4 +268,94 @@ TEST_F(MultiTouchInputMapperUnitTest, MultiFingerGestureWithUnexpectedReset) { VariantWith<NotifyMotionArgs>(WithMotionAction(AMOTION_EVENT_ACTION_UP)))); } +class MultiTouchInputMapperPointerModeUnitTest : public MultiTouchInputMapperUnitTest { +protected: + void SetUp() override { + MultiTouchInputMapperUnitTest::SetUp(); + + // TouchInputMapper goes into POINTER mode whenever INPUT_PROP_DIRECT is not set. + EXPECT_CALL(mMockEventHub, hasInputProperty(EVENTHUB_ID, INPUT_PROP_DIRECT)) + .WillRepeatedly(Return(false)); + + mMapper = createInputMapper<MultiTouchInputMapper>(*mDeviceContext, + mFakePolicy->getReaderConfiguration()); + } +}; + +TEST_F(MultiTouchInputMapperPointerModeUnitTest, MouseToolOnlyDownWhenMouseButtonsAreDown) { + SCOPED_FLAG_OVERRIDE(disable_touch_input_mapper_pointer_usage, true); + + std::list<NotifyArgs> args; + + // Set the tool type to mouse. + args += processKey(BTN_TOOL_MOUSE, 1); + + args += processPosition(100, 100); + args += processId(1); + ASSERT_THAT(args, IsEmpty()); + + args = processSync(); + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER), + WithToolType(ToolType::MOUSE))), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), + WithToolType(ToolType::MOUSE))))); + + // Setting BTN_TOUCH does not make a mouse pointer go down. + args = processKey(BTN_TOUCH, 1); + args += processSync(); + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE)))); + + // The mouse button is pressed, so the mouse goes down. + args = processKey(BTN_MOUSE, 1); + args += processSync(); + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT), + WithToolType(ToolType::MOUSE))), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), + WithToolType(ToolType::MOUSE), + WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY))), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS), + WithToolType(ToolType::MOUSE), + WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY), + WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY))))); + + // The mouse button is released, so the mouse starts hovering. + args = processKey(BTN_MOUSE, 0); + args += processSync(); + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE), + WithButtonState(0), WithToolType(ToolType::MOUSE), + WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY))), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), + WithToolType(ToolType::MOUSE), WithButtonState(0))), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER), + WithToolType(ToolType::MOUSE))), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), + WithToolType(ToolType::MOUSE))))); + + // Change the tool type so that it is no longer a mouse. + // The default tool type is finger, and the finger is already down. + args = processKey(BTN_TOOL_MOUSE, 0); + args += processSync(); + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT), + WithToolType(ToolType::MOUSE))), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), + WithToolType(ToolType::FINGER))))); +} + } // namespace android diff --git a/services/inputflinger/tests/ScopedFlagOverride.h b/services/inputflinger/tests/ScopedFlagOverride.h new file mode 100644 index 0000000000..883673c2f5 --- /dev/null +++ b/services/inputflinger/tests/ScopedFlagOverride.h @@ -0,0 +1,58 @@ +/* + * Copyright 2025 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 <com_android_input_flags.h> +#include <functional> + +namespace android { + +/** + * Provide a local override for a flag value. The value is restored when the object of this class + * goes out of scope. + * This class is not intended to be used directly, because its usage is cumbersome. + * Instead, a wrapper macro SCOPED_FLAG_OVERRIDE is provided. + */ +class ScopedFlagOverride { +public: + ScopedFlagOverride(std::function<bool()> read, std::function<void(bool)> write, bool value) + : mInitialValue(read()), mWriteValue(write) { + mWriteValue(value); + } + ~ScopedFlagOverride() { mWriteValue(mInitialValue); } + +private: + const bool mInitialValue; + std::function<void(bool)> mWriteValue; +}; + +typedef bool (*ReadFlagValueFunction)(); +typedef void (*WriteFlagValueFunction)(bool); + +/** + * Use this macro to locally override a flag value. + * Example usage: + * SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false); + * Note: this works by creating a local variable in your current scope. Don't call this twice for + * the same flag, because the variable names will clash! + */ +#define SCOPED_FLAG_OVERRIDE(NAME, VALUE) \ + ReadFlagValueFunction read##NAME = com::android::input::flags::NAME; \ + WriteFlagValueFunction write##NAME = com::android::input::flags::NAME; \ + ScopedFlagOverride override##NAME(read##NAME, write##NAME, (VALUE)) + +} // namespace android diff --git a/services/inputflinger/tests/fuzzers/InputDispatcherFuzzer.cpp b/services/inputflinger/tests/fuzzers/InputDispatcherFuzzer.cpp index 79a5ff6e5f..31db2fedc7 100644 --- a/services/inputflinger/tests/fuzzers/InputDispatcherFuzzer.cpp +++ b/services/inputflinger/tests/fuzzers/InputDispatcherFuzzer.cpp @@ -76,7 +76,6 @@ void scrambleWindow(FuzzedDataProvider& fdp, FakeWindowHandle& window) { window.setDupTouchToWallpaper(fdp.ConsumeBool()); window.setIsWallpaper(fdp.ConsumeBool()); window.setVisible(fdp.ConsumeBool()); - window.setPreventSplitting(fdp.ConsumeBool()); const bool isTrustedOverlay = fdp.ConsumeBool(); window.setTrustedOverlay(isTrustedOverlay); if (isTrustedOverlay) { diff --git a/services/surfaceflinger/Client.cpp b/services/surfaceflinger/Client.cpp index abeb2a92eb..77bf1457c3 100644 --- a/services/surfaceflinger/Client.cpp +++ b/services/surfaceflinger/Client.cpp @@ -53,7 +53,6 @@ binder::Status Client::createSurface(const std::string& name, int32_t flags, const sp<IBinder>& parent, const gui::LayerMetadata& metadata, gui::CreateSurfaceResult* outResult) { // We rely on createLayer to check permissions. - sp<IBinder> handle; LayerCreationArgs args(mFlinger.get(), sp<Client>::fromExisting(this), name.c_str(), static_cast<uint32_t>(flags), std::move(metadata)); args.parentHandle = parent; @@ -101,7 +100,6 @@ binder::Status Client::getLayerFrameStats(const sp<IBinder>& handle, gui::FrameS binder::Status Client::mirrorSurface(const sp<IBinder>& mirrorFromHandle, gui::CreateSurfaceResult* outResult) { - sp<IBinder> handle; LayerCreationArgs args(mFlinger.get(), sp<Client>::fromExisting(this), "MirrorRoot", 0 /* flags */, gui::LayerMetadata()); status_t status = mFlinger->mirrorLayer(args, mirrorFromHandle, *outResult); @@ -109,7 +107,6 @@ binder::Status Client::mirrorSurface(const sp<IBinder>& mirrorFromHandle, } binder::Status Client::mirrorDisplay(int64_t displayId, gui::CreateSurfaceResult* outResult) { - sp<IBinder> handle; LayerCreationArgs args(mFlinger.get(), sp<Client>::fromExisting(this), "MirrorRoot-" + std::to_string(displayId), 0 /* flags */, gui::LayerMetadata()); diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionEngine.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionEngine.h index e32cc02974..fd58191ed2 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionEngine.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionEngine.h @@ -53,7 +53,7 @@ public: createLayerFECompositionState() = 0; virtual HWComposer& getHwComposer() const = 0; - virtual void setHwComposer(std::unique_ptr<HWComposer>) = 0; + virtual void setHwComposer(HWComposer*) = 0; virtual renderengine::RenderEngine& getRenderEngine() const = 0; virtual void setRenderEngine(renderengine::RenderEngine*) = 0; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h index cda4edc216..a982d3e868 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h @@ -36,6 +36,10 @@ #include <utils/RefBase.h> #include <utils/Timers.h> +namespace aidl::android::hardware::graphics::composer3 { +enum class Composition; +} + namespace android { class Fence; @@ -131,6 +135,9 @@ public: // Currently latched frame number, 0 if invalid. uint64_t frameNumber = 0; + + // layer serial number, -1 if invalid. + int32_t sequence = -1; }; // Describes the states of the release fence. Checking the states allows checks @@ -173,6 +180,11 @@ 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; + virtual const gui::LayerMetadata* getMetadata() const = 0; virtual const gui::LayerMetadata* getRelativeMetadata() const = 0; }; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h index 45208dd3c7..2992b6d843 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h @@ -31,7 +31,7 @@ public: override; HWComposer& getHwComposer() const override; - void setHwComposer(std::unique_ptr<HWComposer>) override; + void setHwComposer(HWComposer*) override; renderengine::RenderEngine& getRenderEngine() const override; void setRenderEngine(renderengine::RenderEngine*) override; @@ -59,7 +59,7 @@ public: void setNeedsAnotherUpdateForTest(bool); private: - std::unique_ptr<HWComposer> mHwComposer; + HWComposer* mHwComposer; renderengine::RenderEngine* mRenderEngine; std::shared_ptr<TimeStats> mTimeStats; bool mNeedsAnotherUpdate = false; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/CompositionEngine.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/CompositionEngine.h index a1b728232c..bb1a2227be 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/CompositionEngine.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/CompositionEngine.h @@ -37,7 +37,7 @@ public: std::unique_ptr<compositionengine::LayerFECompositionState>()); MOCK_CONST_METHOD0(getHwComposer, HWComposer&()); - MOCK_METHOD1(setHwComposer, void(std::unique_ptr<HWComposer>)); + MOCK_METHOD1(setHwComposer, void(HWComposer*)); MOCK_CONST_METHOD0(getRenderEngine, renderengine::RenderEngine&()); MOCK_METHOD1(setRenderEngine, void(renderengine::RenderEngine*)); diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h index 272fa3eef7..7744b8bb99 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h @@ -59,6 +59,10 @@ 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, + (), (const, override)); }; } // namespace android::compositionengine::mock diff --git a/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp b/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp index cfcce473a2..989f8e3c5e 100644 --- a/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp +++ b/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp @@ -58,11 +58,11 @@ CompositionEngine::createLayerFECompositionState() { } HWComposer& CompositionEngine::getHwComposer() const { - return *mHwComposer.get(); + return *mHwComposer; } -void CompositionEngine::setHwComposer(std::unique_ptr<HWComposer> hwComposer) { - mHwComposer = std::move(hwComposer); +void CompositionEngine::setHwComposer(HWComposer* hwComposer) { + mHwComposer = hwComposer; } renderengine::RenderEngine& CompositionEngine::getRenderEngine() const { diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp index 96b86d5a31..9b66f01789 100644 --- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp +++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp @@ -867,6 +867,7 @@ 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) { @@ -964,6 +965,7 @@ void OutputLayer::applyDeviceCompositionTypeChange(Composition compositionType) } hwcState.hwcCompositionType = compositionType; + getLayerFE().setHwcCompositionType(compositionType); } void OutputLayer::prepareForDeviceLayerRequests() { diff --git a/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp b/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp index 3e0c390a5d..ad65c4422e 100644 --- a/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp @@ -61,7 +61,7 @@ TEST_F(CompositionEngineTest, canInstantiateCompositionEngine) { TEST_F(CompositionEngineTest, canSetHWComposer) { android::mock::HWComposer* hwc = new StrictMock<android::mock::HWComposer>(); - mEngine.setHwComposer(std::unique_ptr<android::HWComposer>(hwc)); + mEngine.setHwComposer(static_cast<android::HWComposer*>(hwc)); EXPECT_EQ(hwc, &mEngine.getHwComposer()); } diff --git a/services/surfaceflinger/FrontEnd/LayerHierarchy.h b/services/surfaceflinger/FrontEnd/LayerHierarchy.h index 47d0041a8b..4fdbae1831 100644 --- a/services/surfaceflinger/FrontEnd/LayerHierarchy.h +++ b/services/surfaceflinger/FrontEnd/LayerHierarchy.h @@ -102,6 +102,8 @@ public: // Returns true if the node is a clone. bool isClone() const { return !mirrorRootIds.empty(); } + TraversalPath getClonedFrom() const { return {.id = id, .variant = variant}; } + bool operator==(const TraversalPath& other) const { return id == other.id && mirrorRootIds == other.mirrorRootIds; } diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp index 367132c113..523ef7bfbe 100644 --- a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp +++ b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp @@ -18,12 +18,17 @@ #undef LOG_TAG #define LOG_TAG "SurfaceFlinger" -#include "LayerSnapshot.h" +#include <PowerAdvisor/Workload.h> +#include <aidl/android/hardware/graphics/composer3/Composition.h> +#include <gui/LayerState.h> + #include "Layer.h" +#include "LayerSnapshot.h" namespace android::surfaceflinger::frontend { using namespace ftl::flag_operators; +using namespace aidl::android::hardware::graphics::composer3; namespace { @@ -398,9 +403,13 @@ 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) { - shadowSettings.length = requested.shadowRadius; + 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::eFrameRateSelectionPriority) { frameRateSelectionPriority = requested.frameRateSelectionPriority; } @@ -528,4 +537,49 @@ void LayerSnapshot::merge(const RequestedLayerState& requested, bool forceUpdate } } +char LayerSnapshot::classifyCompositionForDebug(Composition compositionType) const { + if (!isVisible) { + return '.'; + } + + switch (compositionType) { + case Composition::INVALID: + return 'i'; + case Composition::SOLID_COLOR: + return 'c'; + case Composition::CURSOR: + return 'u'; + case Composition::SIDEBAND: + return 'd'; + case Composition::DISPLAY_DECORATION: + return 'a'; + case Composition::REFRESH_RATE_INDICATOR: + return 'r'; + case Composition::CLIENT: + case Composition::DEVICE: + break; + } + + char code = '.'; // Default to invisible + if (hasBufferOrSidebandStream()) { + code = 'b'; + } else if (fillsColor()) { + code = 'c'; // Solid color + } else 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 + } + + if (compositionType == Composition::CLIENT) { + return static_cast<char>(std::toupper(code)); + } else { + return code; + } +} + } // namespace android::surfaceflinger::frontend diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshot.h b/services/surfaceflinger/FrontEnd/LayerSnapshot.h index b8df3ed748..04b9f3b448 100644 --- a/services/surfaceflinger/FrontEnd/LayerSnapshot.h +++ b/services/surfaceflinger/FrontEnd/LayerSnapshot.h @@ -16,6 +16,7 @@ #pragma once +#include <PowerAdvisor/Workload.h> #include <compositionengine/LayerFECompositionState.h> #include <renderengine/LayerSettings.h> #include "DisplayHardware/ComposerHal.h" @@ -28,16 +29,23 @@ namespace android::surfaceflinger::frontend { struct RoundedCornerState { RoundedCornerState() = default; - RoundedCornerState(const FloatRect& cropRect, const vec2& radius) - : cropRect(cropRect), radius(radius) {} // Rounded rectangle in local layer coordinate space. FloatRect cropRect = FloatRect(); - // Radius of the rounded rectangle. + // Radius of the rounded rectangle for composition vec2 radius; + // Requested radius of the rounded rectangle + vec2 requestedRadius; + // Radius drawn by client for the rounded rectangle + vec2 clientDrawnRadius; + bool hasClientDrawnRadius() const { + return clientDrawnRadius.x > 0.0f && clientDrawnRadius.y > 0.0f; + } + bool hasRequestedRadius() const { return requestedRadius.x > 0.0f && requestedRadius.y > 0.0f; } bool hasRoundedCorners() const { return radius.x > 0.0f && radius.y > 0.0f; } bool operator==(RoundedCornerState const& rhs) const { - return cropRect == rhs.cropRect && radius == rhs.radius; + return cropRect == rhs.cropRect && radius == rhs.radius && + clientDrawnRadius == rhs.clientDrawnRadius; } }; @@ -152,6 +160,10 @@ struct LayerSnapshot : public compositionengine::LayerFECompositionState { friend std::ostream& operator<<(std::ostream& os, const LayerSnapshot& obj); void merge(const RequestedLayerState& requested, bool forceUpdate, bool displayChanges, bool forceFullDamage, uint32_t displayRotationFlags); + // 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; }; } // namespace android::surfaceflinger::frontend diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp index 022588deef..0be3a1153d 100644 --- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp +++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp @@ -16,6 +16,8 @@ // #define LOG_NDEBUG 0 #define ATRACE_TAG ATRACE_TAG_GRAPHICS +#include "FrontEnd/LayerSnapshot.h" +#include "ui/Transform.h" #undef LOG_TAG #define LOG_TAG "SurfaceFlinger" @@ -25,6 +27,7 @@ #include <common/FlagManager.h> #include <common/trace.h> #include <ftl/small_map.h> +#include <math/vec2.h> #include <ui/DisplayMap.h> #include <ui/FloatRect.h> @@ -932,7 +935,8 @@ void LayerSnapshotBuilder::updateSnapshot(LayerSnapshot& snapshot, const Args& a if (forceUpdate || snapshot.clientChanges & layer_state_t::eCornerRadiusChanged || snapshot.changes.any(RequestedLayerState::Changes::Geometry | - RequestedLayerState::Changes::BufferUsageFlags)) { + RequestedLayerState::Changes::BufferUsageFlags) || + snapshot.clientChanges & layer_state_t::eClientDrawnCornerRadiusChanged) { updateRoundedCorner(snapshot, requested, parentSnapshot, args); } @@ -972,7 +976,7 @@ void LayerSnapshotBuilder::updateRoundedCorner(LayerSnapshot& snapshot, } snapshot.roundedCorner = RoundedCornerState(); RoundedCornerState parentRoundedCorner; - if (parentSnapshot.roundedCorner.hasRoundedCorners()) { + if (parentSnapshot.roundedCorner.hasRequestedRadius()) { parentRoundedCorner = parentSnapshot.roundedCorner; ui::Transform t = snapshot.localTransform.inverse(); parentRoundedCorner.cropRect = t.transform(parentRoundedCorner.cropRect); @@ -981,10 +985,16 @@ void LayerSnapshotBuilder::updateRoundedCorner(LayerSnapshot& snapshot, } FloatRect layerCropRect = snapshot.croppedBufferSize; - const vec2 radius(requested.cornerRadius, requested.cornerRadius); - RoundedCornerState layerSettings(layerCropRect, radius); - const bool layerSettingsValid = layerSettings.hasRoundedCorners() && !layerCropRect.isEmpty(); - const bool parentRoundedCornerValid = parentRoundedCorner.hasRoundedCorners(); + const vec2 requestedRadius(requested.cornerRadius, requested.cornerRadius); + const vec2 clientDrawnRadius(requested.clientDrawnCornerRadius, + requested.clientDrawnCornerRadius); + RoundedCornerState layerSettings; + layerSettings.cropRect = layerCropRect; + layerSettings.requestedRadius = requestedRadius; + layerSettings.clientDrawnRadius = clientDrawnRadius; + + const bool layerSettingsValid = layerSettings.hasRequestedRadius() && !layerCropRect.isEmpty(); + const bool parentRoundedCornerValid = parentRoundedCorner.hasRequestedRadius(); if (layerSettingsValid && parentRoundedCornerValid) { // If the parent and the layer have rounded corner settings, use the parent settings if // the parent crop is entirely inside the layer crop. This has limitations and cause @@ -1002,6 +1012,14 @@ void LayerSnapshotBuilder::updateRoundedCorner(LayerSnapshot& snapshot, } else if (parentRoundedCornerValid) { snapshot.roundedCorner = parentRoundedCorner; } + + if (snapshot.roundedCorner.requestedRadius.x == requested.clientDrawnCornerRadius) { + // If the client drawn radius matches the requested radius, then surfaceflinger + // does not need to draw rounded corners for this layer + snapshot.roundedCorner.radius = vec2(0.f, 0.f); + } else { + snapshot.roundedCorner.radius = snapshot.roundedCorner.requestedRadius; + } } /** @@ -1205,13 +1223,27 @@ void LayerSnapshotBuilder::updateInput(LayerSnapshot& snapshot, snapshot.inputInfo.contentSize = {snapshot.croppedBufferSize.getHeight(), snapshot.croppedBufferSize.getWidth()}; - // If the layer is a clone, we need to crop the input region to cloned root to prevent - // touches from going outside the cloned area. + snapshot.inputInfo.cloneLayerStackTransform.reset(); + if (path.isClone()) { snapshot.inputInfo.inputConfig |= InputConfig::CLONE; // Cloned layers shouldn't handle watch outside since their z order is not determined by // WM or the client. snapshot.inputInfo.inputConfig.clear(InputConfig::WATCH_OUTSIDE_TOUCH); + + // Compute the transform that maps the clone's display to the layer stack space of the + // cloned window. + const LayerSnapshot* clonedSnapshot = getSnapshot(path.getClonedFrom()); + if (clonedSnapshot != nullptr) { + const auto& [clonedInputBounds, s] = + getInputBounds(*clonedSnapshot, /*fillParentBounds=*/false); + ui::Transform inputToLayer; + inputToLayer.set(clonedInputBounds.left, clonedInputBounds.top); + const ui::Transform& layerToLayerStack = getInputTransform(*clonedSnapshot); + const auto& displayToInput = snapshot.inputInfo.transform; + snapshot.inputInfo.cloneLayerStackTransform = + layerToLayerStack * inputToLayer * displayToInput; + } } } diff --git a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp index ee9302b937..591ebb2043 100644 --- a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp +++ b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp @@ -107,6 +107,8 @@ RequestedLayerState::RequestedLayerState(const LayerCreationArgs& args) hdrMetadata.validTypes = 0; surfaceDamageRegion = Region::INVALID_REGION; cornerRadius = 0.0f; + clientDrawnCornerRadius = 0.0f; + clientDrawnShadowRadius = 0.0f; backgroundBlurRadius = 0; api = -1; hasColorTransform = false; @@ -348,6 +350,16 @@ void RequestedLayerState::merge(const ResolvedComposerState& resolvedComposerSta requestedFrameRate.category = category; changes |= RequestedLayerState::Changes::FrameRate; } + + if (clientState.what & layer_state_t::eClientDrawnCornerRadiusChanged) { + 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 { @@ -624,6 +636,8 @@ bool RequestedLayerState::isSimpleBufferUpdate(const layer_state_t& s) const { const uint64_t deniedChanges = layer_state_t::ePositionChanged | layer_state_t::eAlphaChanged | 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/Layer.h b/services/surfaceflinger/Layer.h index c234a75693..6af0f59d51 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -516,11 +516,6 @@ private: bool mGetHandleCalled = false; - // The inherited shadow radius after taking into account the layer hierarchy. This is the - // final shadow radius for this layer. If a shadow is specified for a layer, then effective - // shadow radius is the set shadow radius, otherwise its the parent's shadow radius. - float mEffectiveShadowRadius = 0.f; - // Game mode for the layer. Set by WindowManagerShell and recorded by SurfaceFlingerStats. gui::GameMode mGameMode = gui::GameMode::Unsupported; diff --git a/services/surfaceflinger/LayerFE.cpp b/services/surfaceflinger/LayerFE.cpp index fea7671af2..617dfbe9c0 100644 --- a/services/surfaceflinger/LayerFE.cpp +++ b/services/surfaceflinger/LayerFE.cpp @@ -191,6 +191,7 @@ void LayerFE::prepareClearClientComposition(LayerFE::LayerSettings& layerSetting layerSettings.disableBlending = true; layerSettings.bufferId = 0; layerSettings.frameNumber = 0; + layerSettings.sequence = -1; // If layer is blacked out, force alpha to 1 so that we draw a black color layer. layerSettings.alpha = blackout ? 1.0f : 0.0f; @@ -262,6 +263,7 @@ void LayerFE::prepareBufferStateClientComposition( layerSettings.source.buffer.maxLuminanceNits = maxLuminance; layerSettings.frameNumber = mSnapshot->frameNumber; layerSettings.bufferId = mSnapshot->externalTexture->getId(); + layerSettings.sequence = mSnapshot->sequence; const bool useFiltering = targetSettings.needsFiltering || mSnapshot->geomLayerTransform.needsBilinearFiltering(); @@ -425,4 +427,14 @@ ftl::Future<FenceResult> LayerFE::createReleaseFenceFuture() { LayerFE::ReleaseFencePromiseStatus LayerFE::getReleaseFencePromiseStatus() { return mReleaseFencePromiseStatus; } + +void LayerFE::setHwcCompositionType( + aidl::android::hardware::graphics::composer3::Composition type) { + mLastHwcCompositionType = type; +} + +aidl::android::hardware::graphics::composer3::Composition LayerFE::getHwcCompositionType() const { + return mLastHwcCompositionType; +} + } // namespace android diff --git a/services/surfaceflinger/LayerFE.h b/services/surfaceflinger/LayerFE.h index 9483aebafa..64ec27862d 100644 --- a/services/surfaceflinger/LayerFE.h +++ b/services/surfaceflinger/LayerFE.h @@ -59,6 +59,9 @@ 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; std::unique_ptr<surfaceflinger::frontend::LayerSnapshot> mSnapshot; @@ -90,6 +93,8 @@ 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; }; } // namespace android diff --git a/services/surfaceflinger/PowerAdvisor/PowerAdvisor.cpp b/services/surfaceflinger/PowerAdvisor/PowerAdvisor.cpp index ff452723d5..cd7210c627 100644 --- a/services/surfaceflinger/PowerAdvisor/PowerAdvisor.cpp +++ b/services/surfaceflinger/PowerAdvisor/PowerAdvisor.cpp @@ -29,7 +29,9 @@ #include <android-base/properties.h> #include <android/binder_libbinder.h> +#include <common/WorkloadTracer.h> #include <common/trace.h> +#include <ftl/concat.h> #include <utils/Log.h> #include <utils/Mutex.h> @@ -44,6 +46,7 @@ namespace android::adpf::impl { +using namespace android::ftl::flag_operators; using aidl::android::hardware::common::fmq::SynchronizedReadWrite; using android::hardware::EventFlag; @@ -62,6 +65,8 @@ void traceExpensiveRendering(bool enabled) { } } +static constexpr ftl::Flags<Workload> TRIGGER_LOAD_CHANGE_HINTS = Workload::EFFECTS | + Workload::VISIBLE_REGION | Workload::DISPLAY_CHANGES | Workload::SCREENSHOT; } // namespace PowerAdvisor::PowerAdvisor(std::function<void()>&& sfDisableExpensiveFn, @@ -756,4 +761,58 @@ power::PowerHalController& PowerAdvisor::getPowerHal() { return *mPowerHal; } +void PowerAdvisor::setQueuedWorkload(ftl::Flags<Workload> queued) { + queued &= TRIGGER_LOAD_CHANGE_HINTS; + if (!(queued).get()) return; + uint32_t previousQueuedWorkload = mQueuedWorkload.fetch_or(queued.get()); + + uint32_t newHints = (previousQueuedWorkload ^ queued.get()) & queued.get(); + if (newHints) { + SFTRACE_INSTANT_FOR_TRACK(WorkloadTracer::TRACK_NAME, + ftl::Concat("QueuedWorkload: ", + ftl::truncated<20>(ftl::Flags<Workload>(newHints) + .string() + .c_str())) + .c_str()); + } + if (!previousQueuedWorkload) { + // TODO(b/385028458) maybe load up hint if close to wake up + } +} + +void PowerAdvisor::setScreenshotWorkload() { + mCommittedWorkload |= Workload::SCREENSHOT; +} + +void PowerAdvisor::setCommittedWorkload(ftl::Flags<Workload> workload) { + workload &= TRIGGER_LOAD_CHANGE_HINTS; + uint32_t queued = mQueuedWorkload.exchange(0); + mCommittedWorkload |= workload; + + bool cancelLoadupHint = queued && !mCommittedWorkload.get(); + if (cancelLoadupHint) { + SFTRACE_INSTANT_FOR_TRACK(WorkloadTracer::TRACK_NAME, + ftl::Concat("UncommittedQueuedWorkload: ", + ftl::truncated<20>(ftl::Flags<Workload>(queued) + .string() + .c_str())) + .c_str()); + // TODO(b/385028458) cancel load up hint + } + + bool increasedWorkload = queued == 0 && mCommittedWorkload.get() != 0; + if (increasedWorkload) { + SFTRACE_INSTANT_FOR_TRACK(WorkloadTracer::TRACK_NAME, + ftl::Concat("CommittedWorkload: ", + ftl::truncated<20>(mCommittedWorkload.string())) + .c_str()); + + // TODO(b/385028458) load up hint + } +} + +void PowerAdvisor::setCompositedWorkload(ftl::Flags<Workload> composited) { + composited &= TRIGGER_LOAD_CHANGE_HINTS; + mCommittedWorkload = composited; +} } // namespace android::adpf::impl diff --git a/services/surfaceflinger/PowerAdvisor/PowerAdvisor.h b/services/surfaceflinger/PowerAdvisor/PowerAdvisor.h index 43fc21093f..540a9df2ca 100644 --- a/services/surfaceflinger/PowerAdvisor/PowerAdvisor.h +++ b/services/surfaceflinger/PowerAdvisor/PowerAdvisor.h @@ -32,9 +32,12 @@ #include <fmq/AidlMessageQueue.h> #pragma clang diagnostic pop +#include <common/trace.h> +#include <ftl/flags.h> #include <scheduler/Time.h> #include <ui/DisplayIdentification.h> #include "../Scheduler/OneShotTimer.h" +#include "Workload.h" #include "SessionManager.h" @@ -109,6 +112,26 @@ public: // Get the session manager, if it exists virtual std::shared_ptr<SessionManager> getSessionManager() = 0; + // --- Track per frame workloads to use for load up hint heuristics + // Track queued workload from transactions as they are queued from the binder thread. + // The workload is accumulated and reset on frame commit. The queued workload may be + // relevant for the next frame so can be used as an early load up hint. Note this is + // only a hint because the transaction can remain in the queue and not be applied on + // the next frame. + virtual void setQueuedWorkload(ftl::Flags<Workload> workload) = 0; + // Track additional workload dur to a screenshot request for load up hint heuristics. This + // would indicate an immediate increase in GPU workload. + virtual void setScreenshotWorkload() = 0; + // Track committed workload from transactions that are applied on the main thread. + // This workload is determined from the applied transactions. This can provide a high + // confidence that the CPU and or GPU workload will increase immediately. + virtual void setCommittedWorkload(ftl::Flags<Workload> workload) = 0; + // Update committed workload with the actual workload from post composition. This is + // used to update the baseline workload so we can detect increases in workloads on the + // next commit. We use composite instead of commit to update the baseline to account + // for optimizations like caching which may reduce the workload. + virtual void setCompositedWorkload(ftl::Flags<Workload> workload) = 0; + // --- The following methods may run on threads besides SF main --- // Send a hint about an upcoming increase in the CPU workload virtual void notifyCpuLoadUp() = 0; @@ -158,6 +181,11 @@ public: void setTotalFrameTargetWorkDuration(Duration targetDuration) override; std::shared_ptr<SessionManager> getSessionManager() override; + void setQueuedWorkload(ftl::Flags<Workload> workload) override; + void setScreenshotWorkload() override; + void setCommittedWorkload(ftl::Flags<Workload> workload) override; + void setCompositedWorkload(ftl::Flags<Workload> workload) override; + // --- The following methods may run on threads besides SF main --- void notifyCpuLoadUp() override; void notifyDisplayUpdateImminentAndCpuReset() override; @@ -332,6 +360,11 @@ private: static constexpr const Duration kFenceWaitStartDelayValidated{150us}; static constexpr const Duration kFenceWaitStartDelaySkippedValidate{250us}; + // Track queued and committed workloads per frame. Queued workload is atomic because it's + // updated on both binder and the main thread. + std::atomic<uint32_t> mQueuedWorkload; + ftl::Flags<Workload> mCommittedWorkload; + void sendHintSessionHint(aidl::android::hardware::power::SessionHint hint); template <aidl::android::hardware::power::ChannelMessage::ChannelMessageContents::Tag T, diff --git a/services/surfaceflinger/PowerAdvisor/Workload.h b/services/surfaceflinger/PowerAdvisor/Workload.h new file mode 100644 index 0000000000..70023579f8 --- /dev/null +++ b/services/surfaceflinger/PowerAdvisor/Workload.h @@ -0,0 +1,44 @@ +/* + * 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 <ftl/flags.h> +#include <stdint.h> + +namespace android::adpf { +// Additional composition workload that can increase cpu load. +enum class Workload : uint32_t { + NONE = 0, + // Layer effects like blur and shadows which forces client composition + EFFECTS = 1 << 0, + + // Geometry changes which requires HWC to validate and share composition strategy + VISIBLE_REGION = 1 << 1, + + // Diplay changes which can cause geometry changes + DISPLAY_CHANGES = 1 << 2, + + // Changes in sf duration which can shorten the deadline for sf to composite the frame + WAKEUP = 1 << 3, + + // Increases in refresh rates can cause the deadline for sf to composite to be shorter + REFRESH_RATE_INCREASE = 1 << 4, + + // Screenshot requests increase both the cpu and gpu workload + SCREENSHOT = 1 << 5 +}; +} // namespace android::adpf diff --git a/services/surfaceflinger/QueuedTransactionState.h b/services/surfaceflinger/QueuedTransactionState.h index af40c026a0..86683da26c 100644 --- a/services/surfaceflinger/QueuedTransactionState.h +++ b/services/surfaceflinger/QueuedTransactionState.h @@ -21,7 +21,9 @@ #include "FrontEnd/LayerCreationArgs.h" #include "renderengine/ExternalTexture.h" +#include <PowerAdvisor/Workload.h> #include <common/FlagManager.h> +#include <ftl/flags.h> #include <gui/LayerState.h> #include <system/window.h> @@ -148,6 +150,7 @@ struct QueuedTransactionState { uint64_t id; bool sentFenceTimeoutWarning = false; std::vector<uint64_t> mergedTransactionIds; + ftl::Flags<adpf::Workload> workloadHint; }; } // namespace android diff --git a/services/surfaceflinger/ScreenCaptureOutput.cpp b/services/surfaceflinger/ScreenCaptureOutput.cpp index 41a9a1bb22..5f71b88d01 100644 --- a/services/surfaceflinger/ScreenCaptureOutput.cpp +++ b/services/surfaceflinger/ScreenCaptureOutput.cpp @@ -16,11 +16,13 @@ #include "ScreenCaptureOutput.h" #include "ScreenCaptureRenderSurface.h" +#include "common/include/common/FlagManager.h" #include "ui/Rotation.h" #include <compositionengine/CompositionEngine.h> #include <compositionengine/DisplayColorProfileCreationArgs.h> #include <compositionengine/impl/DisplayColorProfile.h> +#include <ui/HdrRenderTypeUtils.h> #include <ui/Rotation.h> namespace android { @@ -104,14 +106,84 @@ renderengine::DisplaySettings ScreenCaptureOutput::generateClientCompositionDisp return clientCompositionDisplay; } +std::unordered_map<int32_t, aidl::android::hardware::graphics::composer3::Luts> +ScreenCaptureOutput::generateLuts() { + std::unordered_map<int32_t, aidl::android::hardware::graphics::composer3::Luts> lutsMapper; + if (FlagManager::getInstance().luts_api()) { + std::vector<sp<GraphicBuffer>> buffers; + std::vector<int32_t> layerIds; + + for (const auto* layer : getOutputLayersOrderedByZ()) { + const auto& layerState = layer->getState(); + const auto* layerFEState = layer->getLayerFE().getCompositionState(); + auto pixelFormat = layerFEState->buffer + ? std::make_optional( + static_cast<ui::PixelFormat>(layerFEState->buffer->getPixelFormat())) + : std::nullopt; + const auto hdrType = getHdrRenderType(layerState.dataspace, pixelFormat, + layerFEState->desiredHdrSdrRatio); + if (layerFEState->buffer && !layerFEState->luts && + hdrType == HdrRenderType::GENERIC_HDR) { + buffers.push_back(layerFEState->buffer); + layerIds.push_back(layer->getLayerFE().getSequence()); + } + } + + std::vector<aidl::android::hardware::graphics::composer3::Luts> luts; + if (auto displayDevice = mRenderArea.getDisplayDevice()) { + const auto id = PhysicalDisplayId::tryCast(displayDevice->getId()); + if (id) { + auto& hwc = getCompositionEngine().getHwComposer(); + hwc.getLuts(*id, buffers, &luts); + } + } + + if (buffers.size() == luts.size()) { + for (size_t i = 0; i < luts.size(); i++) { + lutsMapper[layerIds[i]] = std::move(luts[i]); + } + } + } + return lutsMapper; +} + std::vector<compositionengine::LayerFE::LayerSettings> ScreenCaptureOutput::generateClientCompositionRequests( bool supportsProtectedContent, ui::Dataspace outputDataspace, std::vector<compositionengine::LayerFE*>& outLayerFEs) { + // This map maps the layer unique id to a Lut + std::unordered_map<int32_t, aidl::android::hardware::graphics::composer3::Luts> lutsMapper = + generateLuts(); + auto clientCompositionLayers = compositionengine::impl::Output:: generateClientCompositionRequests(supportsProtectedContent, outputDataspace, outLayerFEs); + for (auto& layer : clientCompositionLayers) { + if (lutsMapper.find(layer.sequence) != lutsMapper.end()) { + auto& aidlLuts = lutsMapper[layer.sequence]; + if (aidlLuts.pfd.get() >= 0 && aidlLuts.offsets) { + std::vector<int32_t> offsets = *aidlLuts.offsets; + std::vector<int32_t> dimensions; + dimensions.reserve(offsets.size()); + std::vector<int32_t> sizes; + sizes.reserve(offsets.size()); + std::vector<int32_t> keys; + keys.reserve(offsets.size()); + for (size_t j = 0; j < offsets.size(); j++) { + dimensions.emplace_back( + static_cast<int32_t>(aidlLuts.lutProperties[j].dimension)); + sizes.emplace_back(aidlLuts.lutProperties[j].size); + keys.emplace_back( + static_cast<int32_t>(aidlLuts.lutProperties[j].samplingKeys[0])); + } + layer.luts = std::make_shared<gui::DisplayLuts>(base::unique_fd( + aidlLuts.pfd.dup().get()), + offsets, dimensions, sizes, keys); + } + } + } + if (mRegionSampling) { for (auto& layer : clientCompositionLayers) { layer.backgroundBlurRadius = 0; diff --git a/services/surfaceflinger/ScreenCaptureOutput.h b/services/surfaceflinger/ScreenCaptureOutput.h index c233ead575..444a28fbf0 100644 --- a/services/surfaceflinger/ScreenCaptureOutput.h +++ b/services/surfaceflinger/ScreenCaptureOutput.h @@ -20,6 +20,7 @@ #include <compositionengine/RenderSurface.h> #include <compositionengine/impl/Output.h> #include <ui/Rect.h> +#include <unordered_map> #include "RenderArea.h" @@ -65,6 +66,7 @@ protected: const std::shared_ptr<renderengine::ExternalTexture>& buffer) const override; private: + std::unordered_map<int32_t, aidl::android::hardware::graphics::composer3::Luts> generateLuts(); const RenderArea& mRenderArea; const compositionengine::Output::ColorProfile& mColorProfile; const bool mRegionSampling; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index dd1119a5d1..1f8557c675 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -44,6 +44,7 @@ #include <com_android_graphics_libgui_flags.h> #include <com_android_graphics_surfaceflinger_flags.h> #include <common/FlagManager.h> +#include <common/WorkloadTracer.h> #include <common/trace.h> #include <compositionengine/CompositionEngine.h> #include <compositionengine/CompositionRefreshArgs.h> @@ -156,6 +157,7 @@ #include "MutexUtils.h" #include "NativeWindowSurface.h" #include "PowerAdvisor/PowerAdvisor.h" +#include "PowerAdvisor/Workload.h" #include "RegionSamplingThread.h" #include "RenderAreaBuilder.h" #include "Scheduler/EventThread.h" @@ -879,6 +881,8 @@ renderengine::RenderEngine::BlurAlgorithm chooseBlurAlgorithm(bool supportsBlur) return renderengine::RenderEngine::BlurAlgorithm::GAUSSIAN; } else if (algorithm == "kawase2") { return renderengine::RenderEngine::BlurAlgorithm::KAWASE_DUAL_FILTER; + } else if (algorithm == "kawase") { + return renderengine::RenderEngine::BlurAlgorithm::KAWASE; } else { if (FlagManager::getInstance().window_blur_kawase2()) { return renderengine::RenderEngine::BlurAlgorithm::KAWASE_DUAL_FILTER; @@ -920,7 +924,8 @@ void SurfaceFlinger::init() FTL_FAKE_GUARD(kMainThreadContext) { mCompositionEngine->setTimeStats(mTimeStats); - mCompositionEngine->setHwComposer(getFactory().createHWComposer(mHwcServiceName)); + mHWComposer = getFactory().createHWComposer(mHwcServiceName); + mCompositionEngine->setHwComposer(mHWComposer.get()); auto& composer = mCompositionEngine->getHwComposer(); composer.setCallback(*this); mDisplayModeController.setHwComposer(&composer); @@ -2457,6 +2462,7 @@ bool SurfaceFlinger::updateLayerSnapshots(VsyncId vsyncId, nsecs_t frameTimeNs, bool flushTransactions, bool& outTransactionsAreEmpty) { using Changes = frontend::RequestedLayerState::Changes; SFTRACE_CALL(); + SFTRACE_NAME_FOR_TRACK(WorkloadTracer::TRACK_NAME, "Transaction Handling"); frontend::Update update; if (flushTransactions) { SFTRACE_NAME("TransactionHandler:flushTransactions"); @@ -2483,8 +2489,20 @@ bool SurfaceFlinger::updateLayerSnapshots(VsyncId vsyncId, nsecs_t frameTimeNs, mDestroyedHandles.clear(); } + size_t addedLayers = update.newLayers.size(); mLayerLifecycleManager.addLayers(std::move(update.newLayers)); update.transactions = mTransactionHandler.flushTransactions(); + ftl::Flags<adpf::Workload> committedWorkload; + for (auto& transaction : update.transactions) { + committedWorkload |= transaction.workloadHint; + } + SFTRACE_INSTANT_FOR_TRACK(WorkloadTracer::TRACK_NAME, + ftl::Concat("Layers: +", addedLayers, " -", + update.destroyedHandles.size(), + " txns:", update.transactions.size()) + .c_str()); + + mPowerAdvisor->setCommittedWorkload(committedWorkload); if (mTransactionTracing) { mTransactionTracing->addCommittedTransactions(ftl::to_underlying(vsyncId), frameTimeNs, update, mFrontEndDisplayInfos, @@ -2685,7 +2703,7 @@ bool SurfaceFlinger::commit(PhysicalDisplayId pacesetterId, return false; } } - + SFTRACE_NAME_FOR_TRACK(WorkloadTracer::TRACK_NAME, "Commit"); const Period vsyncPeriod = mScheduler->getVsyncSchedule()->period(); // Save this once per commit + composite to ensure consistency @@ -2759,6 +2777,7 @@ bool SurfaceFlinger::commit(PhysicalDisplayId pacesetterId, // Hold mStateLock as chooseRefreshRateForContent promotes wp<Layer> to sp<Layer> // and may eventually call to ~Layer() if it holds the last reference { + SFTRACE_NAME_FOR_TRACK(WorkloadTracer::TRACK_NAME, "Refresh Rate Selection"); bool updateAttachedChoreographer = mUpdateAttachedChoreographer; mUpdateAttachedChoreographer = false; @@ -2785,6 +2804,8 @@ bool SurfaceFlinger::commit(PhysicalDisplayId pacesetterId, CompositeResultsPerDisplay SurfaceFlinger::composite( PhysicalDisplayId pacesetterId, const scheduler::FrameTargeters& frameTargeters) { + SFTRACE_ASYNC_FOR_TRACK_BEGIN(WorkloadTracer::TRACK_NAME, "Composition", + WorkloadTracer::COMPOSITION_TRACE_COOKIE); const scheduler::FrameTarget& pacesetterTarget = frameTargeters.get(pacesetterId)->get()->target(); @@ -2947,10 +2968,34 @@ CompositeResultsPerDisplay SurfaceFlinger::composite( } mCompositionEngine->present(refreshArgs); - moveSnapshotsFromCompositionArgs(refreshArgs, layers); + ftl::Flags<adpf::Workload> compositedWorkload; + if (refreshArgs.updatingGeometryThisFrame || refreshArgs.updatingOutputGeometryThisFrame) { + compositedWorkload |= adpf::Workload::VISIBLE_REGION; + } + if (mFrontEndDisplayInfosChanged) { + compositedWorkload |= adpf::Workload::DISPLAY_CHANGES; + SFTRACE_INSTANT_FOR_TRACK(WorkloadTracer::TRACK_NAME, "Display Changes"); + } + int index = 0; + std::array<char, WorkloadTracer::COMPOSITION_SUMMARY_SIZE> compositionSummary = {0}; + auto lastLayerStack = ui::INVALID_LAYER_STACK; for (auto& [layer, layerFE] : layers) { CompositionResult compositionResult{layerFE->stealCompositionResult()}; + if (index < compositionSummary.size()) { + if (lastLayerStack != ui::INVALID_LAYER_STACK && + lastLayerStack != layerFE->mSnapshot->outputFilter.layerStack) { + // add a space to separate displays + compositionSummary[index++] = ' '; + } + lastLayerStack = layerFE->mSnapshot->outputFilter.layerStack; + compositionSummary[index++] = layerFE->mSnapshot->classifyCompositionForDebug( + layerFE->getHwcCompositionType()); + if (layerFE->mSnapshot->hasEffect()) { + compositedWorkload |= adpf::Workload::EFFECTS; + } + } + if (compositionResult.lastClientCompositionFence) { layer->setWasClientComposed(compositionResult.lastClientCompositionFence); } @@ -2959,6 +3004,20 @@ CompositeResultsPerDisplay SurfaceFlinger::composite( } } + // 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, + // etc.). This provides a snapshot of the compositing workload. + SFTRACE_INSTANT_FOR_TRACK(WorkloadTracer::TRACK_NAME, + ftl::Concat("Layers: ", layers.size(), " ", + ftl::truncated<WorkloadTracer::COMPOSITION_SUMMARY_SIZE>( + compositionSummary.data())) + .c_str()); + + mPowerAdvisor->setCompositedWorkload(compositedWorkload); + moveSnapshotsFromCompositionArgs(refreshArgs, layers); + SFTRACE_ASYNC_FOR_TRACK_END(WorkloadTracer::TRACK_NAME, + WorkloadTracer::COMPOSITION_TRACE_COOKIE); + SFTRACE_NAME_FOR_TRACK(WorkloadTracer::TRACK_NAME, "Post Composition"); SFTRACE_NAME("postComposition"); mTimeStats->recordFrameDuration(pacesetterTarget.frameBeginTime().ns(), systemTime()); @@ -4873,8 +4932,15 @@ status_t SurfaceFlinger::setTransactionState( const int originPid = ipc->getCallingPid(); const int originUid = ipc->getCallingUid(); uint32_t permissions = LayerStatePermissions::getTransactionPermissions(originPid, originUid); + ftl::Flags<adpf::Workload> queuedWorkload; for (auto& composerState : states) { composerState.state.sanitize(permissions); + if (composerState.state.what & layer_state_t::COMPOSITION_EFFECTS) { + queuedWorkload |= adpf::Workload::EFFECTS; + } + if (composerState.state.what & layer_state_t::VISIBLE_REGION_CHANGES) { + queuedWorkload |= adpf::Workload::VISIBLE_REGION; + } } for (DisplayState& display : displays) { @@ -4897,6 +4963,10 @@ status_t SurfaceFlinger::setTransactionState( flags &= ~(eEarlyWakeupStart | eEarlyWakeupEnd); } } + if (flags & eEarlyWakeupStart) { + queuedWorkload |= adpf::Workload::WAKEUP; + } + mPowerAdvisor->setQueuedWorkload(queuedWorkload); const int64_t postTime = systemTime(); @@ -4960,6 +5030,7 @@ status_t SurfaceFlinger::setTransactionState( originUid, transactionId, mergedTransactionIds}; + state.workloadHint = queuedWorkload; if (mTransactionTracing) { mTransactionTracing->addQueuedTransaction(state); @@ -7393,6 +7464,8 @@ std::optional<SurfaceFlinger::OutputCompositionState> SurfaceFlinger::getSnapsho std::vector<std::pair<Layer*, sp<LayerFE>>>& layers) { return mScheduler ->schedule([=, this, &renderAreaBuilder, &layers]() REQUIRES(kMainThreadContext) { + SFTRACE_NAME_FOR_TRACK(WorkloadTracer::TRACK_NAME, "Screenshot"); + mPowerAdvisor->setScreenshotWorkload(); SFTRACE_NAME("getSnapshotsFromMainThread"); layers = getLayerSnapshotsFn(); // Non-threaded RenderEngine eventually returns to the main thread a 2nd time @@ -7697,6 +7770,7 @@ ftl::SharedFuture<FenceResult> SurfaceFlinger::renderScreenImpl( std::unique_ptr<compositionengine::CompositionEngine> compositionEngine = mFactory.createCompositionEngine(); compositionEngine->setRenderEngine(mRenderEngine.get()); + compositionEngine->setHwComposer(mHWComposer.get()); std::vector<sp<compositionengine::LayerFE>> layerFEs; layerFEs.reserve(layers.size()); diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index c2e687f385..824a55a652 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -1368,6 +1368,7 @@ private: std::atomic<int> mNumTrustedPresentationListeners = 0; std::unique_ptr<compositionengine::CompositionEngine> mCompositionEngine; + std::unique_ptr<HWComposer> mHWComposer; CompositionCoveragePerDisplay mCompositionCoverage; diff --git a/services/surfaceflinger/common/include/common/WorkloadTracer.h b/services/surfaceflinger/common/include/common/WorkloadTracer.h new file mode 100644 index 0000000000..39b6fa1bf4 --- /dev/null +++ b/services/surfaceflinger/common/include/common/WorkloadTracer.h @@ -0,0 +1,29 @@ + +/* + * 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 <ftl/flags.h> +#include <stdint.h> +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 const char* TRACK_NAME = "CriticalWorkload"; + +} // namespace android::WorkloadTracer
\ No newline at end of file diff --git a/services/surfaceflinger/common/include/common/trace.h b/services/surfaceflinger/common/include/common/trace.h index dc5716ba05..9a7e97feba 100644 --- a/services/surfaceflinger/common/include/common/trace.h +++ b/services/surfaceflinger/common/include/common/trace.h @@ -65,6 +65,8 @@ #define SFTRACE_NAME(name) ::android::ScopedTrace PASTE(___tracer, __LINE__)(name) // SFTRACE_CALL is an SFTRACE_NAME that uses the current function name. #define SFTRACE_CALL() SFTRACE_NAME(__FUNCTION__) +#define SFTRACE_NAME_FOR_TRACK(trackName, name) \ + ::android::ScopedTraceForTrack PASTE(___tracer, __LINE__)(trackName, name) #define SFTRACE_FORMAT(fmt, ...) \ ::android::ScopedTrace PASTE(___tracer, __LINE__)(fmt, ##__VA_ARGS__) @@ -87,4 +89,21 @@ public: inline ~ScopedTrace() { SFTRACE_END(); } }; +class ScopedTraceForTrack { +public: + inline ScopedTraceForTrack(const char* trackName, const char* name) + : mCookie(getUniqueCookie()), mTrackName(trackName) { + SFTRACE_ASYNC_FOR_TRACK_BEGIN(mTrackName, name, mCookie); + } + inline ~ScopedTraceForTrack() { SFTRACE_ASYNC_FOR_TRACK_END(mTrackName, mCookie); } + +private: + static int32_t getUniqueCookie() { + static std::atomic<int32_t> sUniqueCookie = 1000; + return sUniqueCookie++; + } + int32_t mCookie; + const char* mTrackName; +}; + } // namespace android diff --git a/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp index f247c9f088..151611cad2 100644 --- a/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp +++ b/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp @@ -585,6 +585,83 @@ TEST_P(LayerTypeAndRenderTypeTransactionTest, ParentCornerRadiusTakesPrecedence) } } +TEST_P(LayerTypeAndRenderTypeTransactionTest, SetClientDrawnCornerRadius) { + sp<SurfaceControl> layer; + const uint8_t size = 64; + const uint8_t testArea = 4; + const float cornerRadius = 20.0f; + ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", size, size)); + ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED, size, size)); + + Transaction() + .setClientDrawnCornerRadius(layer, cornerRadius) + .setCornerRadius(layer, cornerRadius) + .setCrop(layer, Rect(size, size)) + .apply(); + + { + const uint8_t bottom = size - 1; + const uint8_t right = size - 1; + auto shot = getScreenCapture(); + // Solid corners + shot->expectColor(Rect(0, 0, testArea, testArea), Color::RED); + shot->expectColor(Rect(size - testArea, 0, right, testArea), Color::RED); + shot->expectColor(Rect(0, bottom - testArea, testArea, bottom), Color::RED); + shot->expectColor(Rect(size - testArea, bottom - testArea, right, bottom), Color::RED); + // Solid center + shot->expectColor(Rect(size / 2 - testArea / 2, size / 2 - testArea / 2, + size / 2 + testArea / 2, size / 2 + testArea / 2), + Color::RED); + } +} + +// Test if ParentCornerRadiusTakesPrecedence if the parent's client drawn corner radius crop +// is fully contained by the child corner radius crop. +TEST_P(LayerTypeAndRenderTypeTransactionTest, ParentCornerRadiusPrecedenceClientDrawnCornerRadius) { + sp<SurfaceControl> parent; + sp<SurfaceControl> child; + const uint32_t size = 64; + const uint32_t parentSize = size * 3; + const Rect parentCrop(size, size, size, size); + const uint32_t testLength = 4; + const float cornerRadius = 20.0f; + ASSERT_NO_FATAL_FAILURE(parent = createLayer("parent", parentSize, parentSize)); + ASSERT_NO_FATAL_FAILURE(fillLayerColor(parent, Color::RED, parentSize, parentSize)); + ASSERT_NO_FATAL_FAILURE(child = createLayer("child", size, size)); + ASSERT_NO_FATAL_FAILURE(fillLayerColor(child, Color::GREEN, size, size)); + + Transaction() + .setCornerRadius(parent, cornerRadius) + .setCrop(parent, parentCrop) + .setClientDrawnCornerRadius(parent, cornerRadius) + .reparent(child, parent) + .setPosition(child, size, size) + .apply(true); + + { + const uint32_t top = size; + const uint32_t left = size; + const uint32_t bottom = size * 2; + const uint32_t right = size * 2; + auto shot = getScreenCapture(); + // Corners are RED because parent's client drawn corner radius is actually 0 + // and the child is fully within the parent's crop + // TL + shot->expectColor(Rect(left, top, testLength, testLength), Color::RED); + // TR + shot->expectColor(Rect(right - testLength, top, testLength, testLength), Color::RED); + // BL + shot->expectColor(Rect(left, bottom - testLength, testLength, testLength), Color::RED); + // BR + shot->expectColor(Rect(right - testLength, bottom - testLength, testLength, testLength), + Color::RED); + // Solid center + shot->expectColor(Rect(parentSize / 2 - testLength, parentSize / 2 - testLength, testLength, + testLength), + Color::GREEN); + } +} + TEST_P(LayerTypeAndRenderTypeTransactionTest, SetBackgroundBlurRadiusSimple) { if (!deviceSupportsBlurs()) GTEST_SKIP(); if (!deviceUsesSkiaRenderEngine()) GTEST_SKIP(); diff --git a/services/surfaceflinger/tests/common/LayerLifecycleManagerHelper.h b/services/surfaceflinger/tests/common/LayerLifecycleManagerHelper.h index a894c418f6..ee5d9193ea 100644 --- a/services/surfaceflinger/tests/common/LayerLifecycleManagerHelper.h +++ b/services/surfaceflinger/tests/common/LayerLifecycleManagerHelper.h @@ -485,6 +485,29 @@ public: mLifecycleManager.applyTransactions(transactions); } + void setClientDrawnCornerRadius(uint32_t id, float clientDrawnCornerRadius) { + std::vector<QueuedTransactionState> transactions; + transactions.emplace_back(); + transactions.back().states.push_back({}); + + transactions.back().states.front().state.what = + layer_state_t::eClientDrawnCornerRadiusChanged; + transactions.back().states.front().layerId = id; + transactions.back().states.front().state.clientDrawnCornerRadius = clientDrawnCornerRadius; + 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/LayerSnapshotTest.cpp b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp index 1177d1601e..2deb177496 100644 --- a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp +++ b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp @@ -1425,6 +1425,59 @@ TEST_F(LayerSnapshotTest, setBufferCrop) { EXPECT_EQ(getSnapshot(1)->geomContentCrop, Rect(0, 0, 100, 100)); } +TEST_F(LayerSnapshotTest, setCornerRadius) { + static constexpr float RADIUS = 123.f; + setRoundedCorners(1, RADIUS); + setCrop(1, Rect{1000, 1000}); + UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER); + EXPECT_EQ(getSnapshot({.id = 1})->roundedCorner.radius.x, RADIUS); +} + +TEST_F(LayerSnapshotTest, ignoreCornerRadius) { + static constexpr float RADIUS = 123.f; + setClientDrawnCornerRadius(1, RADIUS); + setRoundedCorners(1, RADIUS); + setCrop(1, Rect{1000, 1000}); + UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER); + EXPECT_TRUE(getSnapshot({.id = 1})->roundedCorner.hasClientDrawnRadius()); + EXPECT_EQ(getSnapshot({.id = 1})->roundedCorner.radius.x, 0.f); +} + +TEST_F(LayerSnapshotTest, childInheritsParentIntendedCornerRadius) { + static constexpr float RADIUS = 123.f; + + setClientDrawnCornerRadius(1, RADIUS); + setRoundedCorners(1, RADIUS); + setCrop(1, Rect(1, 1, 999, 999)); + + UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER); + EXPECT_TRUE(getSnapshot({.id = 1})->roundedCorner.hasClientDrawnRadius()); + EXPECT_TRUE(getSnapshot({.id = 11})->roundedCorner.hasRoundedCorners()); + EXPECT_EQ(getSnapshot({.id = 11})->roundedCorner.radius.x, RADIUS); +} + +TEST_F(LayerSnapshotTest, childIgnoreCornerRadiusOverridesParent) { + static constexpr float RADIUS = 123.f; + + setRoundedCorners(1, RADIUS); + setCrop(1, Rect(1, 1, 999, 999)); + + setClientDrawnCornerRadius(11, RADIUS); + + UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER); + EXPECT_EQ(getSnapshot({.id = 1})->roundedCorner.radius.x, RADIUS); + EXPECT_EQ(getSnapshot({.id = 11})->roundedCorner.radius.x, 0.f); + 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/PowerAdvisorTest.cpp b/services/surfaceflinger/tests/unittests/PowerAdvisorTest.cpp index 5c25f34ae7..d7f7bdb9db 100644 --- a/services/surfaceflinger/tests/unittests/PowerAdvisorTest.cpp +++ b/services/surfaceflinger/tests/unittests/PowerAdvisorTest.cpp @@ -39,6 +39,7 @@ using namespace android::hardware::power; using namespace std::chrono_literals; using namespace testing; using namespace android::power; +using namespace ftl::flag_operators; namespace android::adpf::impl { @@ -54,6 +55,8 @@ public: void setTimingTestingMode(bool testinMode); void allowReportActualToAcquireMutex(); bool sessionExists(); + ftl::Flags<Workload> getCommittedWorkload() const; + ftl::Flags<Workload> getQueuedWorkload() const; int64_t toNanos(Duration d); struct GpuTestConfig { @@ -315,6 +318,14 @@ Duration PowerAdvisorTest::getErrorMargin() { return mPowerAdvisor->sTargetSafetyMargin; } +ftl::Flags<Workload> PowerAdvisorTest::getCommittedWorkload() const { + return mPowerAdvisor->mCommittedWorkload; +} + +ftl::Flags<Workload> PowerAdvisorTest::getQueuedWorkload() const { + return ftl::Flags<Workload>{mPowerAdvisor->mQueuedWorkload.load()}; +} + namespace { TEST_F(PowerAdvisorTest, hintSessionUseHwcDisplay) { @@ -842,5 +853,32 @@ TEST_F(PowerAdvisorTest, fmq_sendHint_queueFull) { ASSERT_EQ(hint, SessionHint::CPU_LOAD_UP); } +TEST_F(PowerAdvisorTest, trackQueuedWorkloads) { + mPowerAdvisor->setQueuedWorkload(ftl::Flags<Workload>()); + ASSERT_EQ(getQueuedWorkload(), ftl::Flags<Workload>()); + + // verify workloads are queued + mPowerAdvisor->setQueuedWorkload(ftl::Flags<Workload>(Workload::VISIBLE_REGION)); + ASSERT_EQ(getQueuedWorkload(), ftl::Flags<Workload>(Workload::VISIBLE_REGION)); + + mPowerAdvisor->setQueuedWorkload(ftl::Flags<Workload>(Workload::EFFECTS)); + ASSERT_EQ(getQueuedWorkload(), Workload::VISIBLE_REGION | Workload::EFFECTS); + + // verify queued workloads are cleared after commit + mPowerAdvisor->setCommittedWorkload(ftl::Flags<Workload>()); + ASSERT_EQ(getQueuedWorkload(), ftl::Flags<Workload>()); +} + +TEST_F(PowerAdvisorTest, trackCommittedWorkloads) { + // verify queued workloads are cleared after commit + mPowerAdvisor->setCommittedWorkload(Workload::SCREENSHOT | Workload::VISIBLE_REGION); + ASSERT_EQ(getCommittedWorkload(), Workload::SCREENSHOT | Workload::VISIBLE_REGION); + + // on composite, verify we update the committed workload so we track workload increases for the + // next frame accurately + mPowerAdvisor->setCompositedWorkload(Workload::VISIBLE_REGION | Workload::DISPLAY_CHANGES); + ASSERT_EQ(getCommittedWorkload(), Workload::VISIBLE_REGION | Workload::DISPLAY_CHANGES); +} + } // namespace } // namespace android::adpf::impl diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index 3455c13bb7..c2e88688e0 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -184,8 +184,8 @@ public: } void setupComposer(std::unique_ptr<Hwc2::Composer> composer) { - mFlinger->mCompositionEngine->setHwComposer( - std::make_unique<impl::HWComposer>(std::move(composer))); + mFlinger->mHWComposer = std::make_unique<impl::HWComposer>(std::move(composer)); + mFlinger->mCompositionEngine->setHwComposer(mFlinger->mHWComposer.get()); mFlinger->mDisplayModeController.setHwComposer( &mFlinger->mCompositionEngine->getHwComposer()); } @@ -771,7 +771,8 @@ public: mutableCurrentState().displays.clear(); mutableDrawingState().displays.clear(); mFlinger->mScheduler.reset(); - mFlinger->mCompositionEngine->setHwComposer(std::unique_ptr<HWComposer>()); + mFlinger->mHWComposer = std::unique_ptr<HWComposer>(); + mFlinger->mCompositionEngine->setHwComposer(mFlinger->mHWComposer.get()); mFlinger->mRenderEngine = std::unique_ptr<renderengine::RenderEngine>(); mFlinger->mCompositionEngine->setRenderEngine(mFlinger->mRenderEngine.get()); mFlinger->mTransactionTracing.reset(); diff --git a/services/surfaceflinger/tests/unittests/mock/PowerAdvisor/MockPowerAdvisor.h b/services/surfaceflinger/tests/unittests/mock/PowerAdvisor/MockPowerAdvisor.h index fd55597d7a..5abee16bd0 100644 --- a/services/surfaceflinger/tests/unittests/mock/PowerAdvisor/MockPowerAdvisor.h +++ b/services/surfaceflinger/tests/unittests/mock/PowerAdvisor/MockPowerAdvisor.h @@ -65,6 +65,10 @@ public: MOCK_METHOD(void, setTotalFrameTargetWorkDuration, (Duration targetDuration), (override)); MOCK_METHOD(std::shared_ptr<SessionManager>, getSessionManager, (), (override)); MOCK_METHOD(sp<IBinder>, getOrCreateSessionManagerForBinder, (uid_t uid), (override)); + MOCK_METHOD(void, setQueuedWorkload, (ftl::Flags<Workload> workload), (override)); + MOCK_METHOD(void, setScreenshotWorkload, (), (override)); + MOCK_METHOD(void, setCommittedWorkload, (ftl::Flags<Workload> workload), (override)); + MOCK_METHOD(void, setCompositedWorkload, (ftl::Flags<Workload> workload), (override)); }; } // namespace android::adpf::mock |