diff options
48 files changed, 841 insertions, 119 deletions
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/system_health.h b/include/android/system_health.h index 6d59706490..bdb1413555 100644 --- a/include/android/system_health.h +++ b/include/android/system_health.h @@ -417,7 +417,6 @@ __INTRODUCED_IN(36); * @param outMinIntervalMillis Non-null output pointer to a int64_t, which * will be set to the minimum polling interval in milliseconds. * @return 0 on success. - * EPIPE if failed to get the minimum polling interval. * ENOTSUP if API is unsupported. */ int ASystemHealth_getCpuHeadroomMinIntervalMillis(int64_t* _Nonnull outMinIntervalMillis) @@ -434,7 +433,6 @@ __INTRODUCED_IN(36); * @param outMinIntervalMillis Non-null output pointer to a int64_t, which * will be set to the minimum polling interval in milliseconds. * @return 0 on success. - * EPIPE if failed to get the minimum polling interval. * ENOTSUP if API is unsupported. */ int ASystemHealth_getGpuHeadroomMinIntervalMillis(int64_t* _Nonnull outMinIntervalMillis) 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/private/system_health_private.h b/include/private/system_health_private.h new file mode 100644 index 0000000000..05a5a06c9c --- /dev/null +++ b/include/private/system_health_private.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 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. + */ + +#ifndef ANDROID_PRIVATE_NATIVE_SYSTEM_HEALTH_H +#define ANDROID_PRIVATE_NATIVE_SYSTEM_HEALTH_H + +#include <stdint.h> + +__BEGIN_DECLS + +/** + * For testing only. + */ +void ASystemHealth_setIHintManagerForTesting(void* iManager); + +__END_DECLS + +#endif // ANDROID_PRIVATE_NATIVE_SYSTEM_HEALTH_H + 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/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/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/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/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 5bb8f7f8f7..2beeae0201 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -829,7 +829,9 @@ SurfaceComposerClient::Transaction::Transaction() { SurfaceComposerClient::Transaction::Transaction(const Transaction& other) : mId(other.mId), - mFlags(other.mFlags), + mAnimation(other.mAnimation), + mEarlyWakeupStart(other.mEarlyWakeupStart), + mEarlyWakeupEnd(other.mEarlyWakeupEnd), mMayContainBuffer(other.mMayContainBuffer), mDesiredPresentTime(other.mDesiredPresentTime), mIsAutoTimestamp(other.mIsAutoTimestamp), @@ -866,7 +868,9 @@ SurfaceComposerClient::Transaction::createFromParcel(const Parcel* parcel) { status_t SurfaceComposerClient::Transaction::readFromParcel(const Parcel* parcel) { const uint64_t transactionId = parcel->readUint64(); - const uint32_t flags = parcel->readUint32(); + const bool animation = parcel->readBool(); + const bool earlyWakeupStart = parcel->readBool(); + const bool earlyWakeupEnd = parcel->readBool(); const int64_t desiredPresentTime = parcel->readInt64(); const bool isAutoTimestamp = parcel->readBool(); const bool logCallPoints = parcel->readBool(); @@ -961,7 +965,9 @@ status_t SurfaceComposerClient::Transaction::readFromParcel(const Parcel* parcel // Parsing was successful. Update the object. mId = transactionId; - mFlags = flags; + mAnimation = animation; + mEarlyWakeupStart = earlyWakeupStart; + mEarlyWakeupEnd = earlyWakeupEnd; mDesiredPresentTime = desiredPresentTime; mIsAutoTimestamp = isAutoTimestamp; mFrameTimelineInfo = frameTimelineInfo; @@ -990,7 +996,9 @@ status_t SurfaceComposerClient::Transaction::writeToParcel(Parcel* parcel) const const_cast<SurfaceComposerClient::Transaction*>(this)->cacheBuffers(); parcel->writeUint64(mId); - parcel->writeUint32(mFlags); + parcel->writeBool(mAnimation); + parcel->writeBool(mEarlyWakeupStart); + parcel->writeBool(mEarlyWakeupEnd); parcel->writeInt64(mDesiredPresentTime); parcel->writeBool(mIsAutoTimestamp); parcel->writeBool(mLogCallPoints); @@ -1123,7 +1131,8 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::merge(Tr mInputWindowCommands.merge(other.mInputWindowCommands); mMayContainBuffer |= other.mMayContainBuffer; - mFlags |= other.mFlags; + mEarlyWakeupStart = mEarlyWakeupStart || other.mEarlyWakeupStart; + mEarlyWakeupEnd = mEarlyWakeupEnd || other.mEarlyWakeupEnd; mApplyToken = other.mApplyToken; mergeFrameTimelineInfo(mFrameTimelineInfo, other.mFrameTimelineInfo); @@ -1145,13 +1154,15 @@ void SurfaceComposerClient::Transaction::clear() { mInputWindowCommands.clear(); mUncacheBuffers.clear(); mMayContainBuffer = false; + mAnimation = false; + mEarlyWakeupStart = false; + mEarlyWakeupEnd = false; mDesiredPresentTime = 0; mIsAutoTimestamp = true; mFrameTimelineInfo = {}; mApplyToken = nullptr; mMergedTransactionIds.clear(); mLogCallPoints = false; - mFlags = 0; } uint64_t SurfaceComposerClient::Transaction::getId() { @@ -1322,6 +1333,9 @@ status_t SurfaceComposerClient::Transaction::apply(bool synchronous, bool oneWay displayStates = std::move(mDisplayStates); + if (mAnimation) { + flags |= ISurfaceComposer::eAnimation; + } if (oneWay) { if (synchronous) { ALOGE("Transaction attempted to set synchronous and one way at the same time" @@ -1331,12 +1345,15 @@ status_t SurfaceComposerClient::Transaction::apply(bool synchronous, bool oneWay } } - // If both ISurfaceComposer::eEarlyWakeupStart and ISurfaceComposer::eEarlyWakeupEnd are set + // If both mEarlyWakeupStart and mEarlyWakeupEnd are set // it is equivalent for none - uint32_t wakeupFlags = ISurfaceComposer::eEarlyWakeupStart | ISurfaceComposer::eEarlyWakeupEnd; - if ((flags & wakeupFlags) == wakeupFlags) { - flags &= ~(wakeupFlags); + if (mEarlyWakeupStart && !mEarlyWakeupEnd) { + flags |= ISurfaceComposer::eEarlyWakeupStart; + } + if (mEarlyWakeupEnd && !mEarlyWakeupStart) { + flags |= ISurfaceComposer::eEarlyWakeupEnd; } + sp<IBinder> applyToken = mApplyToken ? mApplyToken : getDefaultApplyToken(); sp<ISurfaceComposer> sf(ComposerService::getComposerService()); @@ -1444,15 +1461,15 @@ std::optional<gui::StalledTransactionInfo> SurfaceComposerClient::getStalledTran } void SurfaceComposerClient::Transaction::setAnimationTransaction() { - mFlags |= ISurfaceComposer::eAnimation; + mAnimation = true; } void SurfaceComposerClient::Transaction::setEarlyWakeupStart() { - mFlags |= ISurfaceComposer::eEarlyWakeupStart; + mEarlyWakeupStart = true; } void SurfaceComposerClient::Transaction::setEarlyWakeupEnd() { - mFlags |= ISurfaceComposer::eEarlyWakeupEnd; + mEarlyWakeupEnd = true; } layer_state_t* SurfaceComposerClient::Transaction::getLayerState(const sp<SurfaceControl>& sc) { diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index 16425c9872..100261423a 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -302,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); diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 10c51a3e20..d20b3460b5 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -467,7 +467,10 @@ public: std::vector<uint64_t> mMergedTransactionIds; uint64_t mId; - uint32_t mFlags; + + bool mAnimation = false; + bool mEarlyWakeupStart = false; + bool mEarlyWakeupEnd = false; // Indicates that the Transaction may contain buffers that should be cached. The reason this // is only a guess is that buffers can be removed before cache is called. This is only a 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/input/input_flags.aconfig b/libs/input/input_flags.aconfig index 09042c2099..bf928f4847 100644 --- a/libs/input/input_flags.aconfig +++ b/libs/input/input_flags.aconfig @@ -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." 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/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/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp index d9e7054322..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; } @@ -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(); 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/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index 685645cfbb..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 --- diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp index 2daa1e9f49..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(DISPLAY_ID, 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/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/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h index 42e1a1922d..e876693498 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; @@ -178,6 +182,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/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/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/FrontEnd/LayerSnapshot.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp index 42f3202f20..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 { @@ -532,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 68b13959a8..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" @@ -159,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 0be3a1153d..7289e2f201 100644 --- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp +++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp @@ -982,6 +982,8 @@ void LayerSnapshotBuilder::updateRoundedCorner(LayerSnapshot& snapshot, parentRoundedCorner.cropRect = t.transform(parentRoundedCorner.cropRect); parentRoundedCorner.radius.x *= t.getScaleX(); parentRoundedCorner.radius.y *= t.getScaleY(); + parentRoundedCorner.requestedRadius.x *= t.getScaleX(); + parentRoundedCorner.requestedRadius.y *= t.getScaleY(); } FloatRect layerCropRect = snapshot.croppedBufferSize; diff --git a/services/surfaceflinger/LayerFE.cpp b/services/surfaceflinger/LayerFE.cpp index e331e68c35..725a782177 100644 --- a/services/surfaceflinger/LayerFE.cpp +++ b/services/surfaceflinger/LayerFE.cpp @@ -427,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/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 21c1bd7eda..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" @@ -2460,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"); @@ -2486,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, @@ -2688,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 @@ -2762,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; @@ -2788,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(); @@ -2950,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); } @@ -2962,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()); @@ -4876,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) { @@ -4900,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(); @@ -4963,6 +5030,7 @@ status_t SurfaceFlinger::setTransactionState( originUid, transactionId, mergedTransactionIds}; + state.workloadHint = queuedWorkload; if (mTransactionTracing) { mTransactionTracing->addQueuedTransaction(state); @@ -7396,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 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/unittests/LayerSnapshotTest.cpp b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp index 2deb177496..ab8c733cc8 100644 --- a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp +++ b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp @@ -28,6 +28,7 @@ #include "ui/GraphicTypes.h" #include <com_android_graphics_libgui_flags.h> +#include <cmath> #define UPDATE_AND_VERIFY(BUILDER, ...) \ ({ \ @@ -1443,7 +1444,36 @@ TEST_F(LayerSnapshotTest, ignoreCornerRadius) { EXPECT_EQ(getSnapshot({.id = 1})->roundedCorner.radius.x, 0.f); } -TEST_F(LayerSnapshotTest, childInheritsParentIntendedCornerRadius) { +TEST_F(LayerSnapshotTest, childInheritsParentScaledSettings) { + // ROOT + // ├── 1 (crop rect set to contain child layer) + // │ ├── 11 + static constexpr float RADIUS = 123.f; + + setRoundedCorners(1, RADIUS); + FloatRect parentCropRect(1, 1, 999, 999); + setCrop(1, parentCropRect); + // Rotate surface by 90 + setMatrix(11, 0.f, -1.f, 1.f, 0.f); + + UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER); + + ui::Transform t = getSnapshot({.id = 11})->localTransform.inverse(); + + UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER); + EXPECT_EQ(getSnapshot({.id = 11})->roundedCorner.cropRect, t.transform(parentCropRect)); + EXPECT_EQ(getSnapshot({.id = 11})->roundedCorner.radius.x, RADIUS * t.getScaleX()); + EXPECT_EQ(getSnapshot({.id = 11})->roundedCorner.radius.y, RADIUS * t.getScaleY()); + EXPECT_EQ(getSnapshot({.id = 11})->roundedCorner.requestedRadius.x, RADIUS * t.getScaleX()); + EXPECT_EQ(getSnapshot({.id = 11})->roundedCorner.requestedRadius.y, RADIUS * t.getScaleY()); +} + +TEST_F(LayerSnapshotTest, childInheritsParentClientDrawnCornerRadius) { + // ROOT + // ├── 1 (crop rect set to contain child layers ) + // │ ├── 11 + // │ │ └── 111 + static constexpr float RADIUS = 123.f; setClientDrawnCornerRadius(1, RADIUS); @@ -1457,6 +1487,11 @@ TEST_F(LayerSnapshotTest, childInheritsParentIntendedCornerRadius) { } TEST_F(LayerSnapshotTest, childIgnoreCornerRadiusOverridesParent) { + // ROOT + // ├── 1 (crop rect set to contain child layers ) + // │ ├── 11 + // │ │ └── 111 + static constexpr float RADIUS = 123.f; setRoundedCorners(1, 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/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 |