Merge changes from topic "revert-31063667-ZXNTVOTPQF" into main
* changes:
Revert "[8/n InputDispatcher refactor] move input connections to a subclass"
Revert "[9/n Dispatcher refactor] Move computeTouchOcclusionInfo..."
Revert "[10/n Dispatcher refactor] Move obscuring related method..."
Revert "[11/n Dispatcher refactor] Move isTouchTrusted to WindowInfo"
diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp
index 38a125b..59c4d53 100644
--- a/cmds/servicemanager/ServiceManager.cpp
+++ b/cmds/servicemanager/ServiceManager.cpp
@@ -410,7 +410,16 @@
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 964abee..5c4d891 100644
--- a/cmds/servicemanager/ServiceManager.h
+++ b/cmds/servicemanager/ServiceManager.h
@@ -46,7 +46,8 @@
// 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 e620770..7ad84fa 100644
--- a/cmds/servicemanager/test_sm.cpp
+++ b/cmds/servicemanager/test_sm.cpp
@@ -204,6 +204,11 @@
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 6d59706..bdb1413 100644
--- a/include/android/system_health.h
+++ b/include/android/system_health.h
@@ -417,7 +417,6 @@
* @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 @@
* @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 a35a145..b0641b8 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 @@
// 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 0000000..05a5a06
--- /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 ee3d6af..7c0319a 100644
--- a/libs/binder/BackendUnifiedServiceManager.cpp
+++ b/libs/binder/BackendUnifiedServiceManager.cpp
@@ -215,7 +215,9 @@
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 @@
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 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 2496f62..c14f280 100644
--- a/libs/binder/BackendUnifiedServiceManager.h
+++ b/libs/binder/BackendUnifiedServiceManager.h
@@ -122,7 +122,8 @@
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 53bd08d..0a22588 100644
--- a/libs/binder/Binder.cpp
+++ b/libs/binder/Binder.cpp
@@ -288,7 +288,7 @@
// for below objects
RpcMutex mLock;
std::set<sp<RpcServerLink>> mRpcServerLinks;
- BpBinder::ObjectManager mObjects;
+ BpBinder::ObjectManager mObjectMgr;
unique_fd mRecordingFd;
};
@@ -468,7 +468,7 @@
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 @@
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 @@
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 @@
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 3758b65..444f061 100644
--- a/libs/binder/BpBinder.cpp
+++ b/libs/binder/BpBinder.cpp
@@ -78,7 +78,16 @@
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 @@
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::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 @@
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 5c72ed3..719e445 100644
--- a/libs/binder/IServiceManager.cpp
+++ b/libs/binder/IServiceManager.cpp
@@ -624,7 +624,7 @@
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 69edef8..6539238 100644
--- a/libs/binder/aidl/android/os/IServiceManager.aidl
+++ b/libs/binder/aidl/android/os/IServiceManager.aidl
@@ -83,11 +83,20 @@
/**
* 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 7518044..935bd8d 100644
--- a/libs/binder/include/binder/BpBinder.h
+++ b/libs/binder/include/binder/BpBinder.h
@@ -104,6 +104,7 @@
// 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 @@
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 @@
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 be99065..78fe2a8 100644
--- a/libs/binder/servicedispatcher.cpp
+++ b/libs/binder/servicedispatcher.cpp
@@ -127,7 +127,12 @@
// 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 19395c2..121e5ae 100644
--- a/libs/binder/tests/binderCacheUnitTest.cpp
+++ b/libs/binder/tests/binderCacheUnitTest.cpp
@@ -74,7 +74,7 @@
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 @@
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 5bb8f7f..2beeae0 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -829,7 +829,9 @@
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 @@
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 @@
// 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 @@
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 @@
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 @@
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 @@
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 @@
}
}
- // 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 @@
}
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 16425c9..1002614 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -302,6 +302,11 @@
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 10c51a3..d20b346 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -467,7 +467,10 @@
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 6bf38c0..394a5cf 100644
--- a/libs/gui/libgui_flags.aconfig
+++ b/libs/gui/libgui_flags.aconfig
@@ -138,4 +138,7 @@
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 09042c2..bf928f4 100644
--- a/libs/input/input_flags.aconfig
+++ b/libs/input/input_flags.aconfig
@@ -188,6 +188,16 @@
}
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 d11631b..afcdf74 100644
--- a/services/audiomanager/Android.bp
+++ b/services/audiomanager/Android.bp
@@ -15,6 +15,7 @@
],
shared_libs: [
+ "av-types-aidl-cpp",
"libutils",
"libbinder",
"liblog",
diff --git a/services/audiomanager/IAudioManager.cpp b/services/audiomanager/IAudioManager.cpp
index f8a38d1..99360b9 100644
--- a/services/audiomanager/IAudioManager.cpp
+++ b/services/audiomanager/IAudioManager.cpp
@@ -35,6 +35,24 @@
{
}
+ // 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 0b17507..cc04684 100644
--- a/services/inputflinger/dispatcher/trace/AndroidInputEventProtoConverter.cpp
+++ b/services/inputflinger/dispatcher/trace/AndroidInputEventProtoConverter.cpp
@@ -115,13 +115,17 @@
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 @@
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 d9e7054..6efaeca 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 @@
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 @@
}
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 @@
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 @@
pressure = in.pressure * mPressureScale;
break;
default:
- pressure = in.isHovering ? 0 : 1;
+ pressure = isHovering ? 0 : 1;
break;
}
@@ -3697,7 +3720,10 @@
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 ef0e02f..eb4326f 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.h
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.h
@@ -215,7 +215,7 @@
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 @@
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 685645c..b6e27a8 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 @@
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 2daa1e9..470e65b 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 @@
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 @@
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 @@
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 @@
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, Process_Pointer_ShouldHandleDisplayId) {
+ SCOPED_FLAG_OVERRIDE(disable_touch_input_mapper_pointer_usage, true);
prepareSecondaryDisplay(ViewportType::EXTERNAL);
prepareDisplay(ui::ROTATION_0);
@@ -7532,9 +7548,9 @@
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 @@
* 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 @@
* 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 @@
* 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, 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, 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 9a6b266..d15048d 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 @@
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 0000000..883673c
--- /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 abeb2a9..77bf145 100644
--- a/services/surfaceflinger/Client.cpp
+++ b/services/surfaceflinger/Client.cpp
@@ -53,7 +53,6 @@
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::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::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 20aceb1..a982d3e 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;
@@ -176,6 +180,11 @@
// 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 272fa3e..7744b8b 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
@@ -59,6 +59,10 @@
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 96b86d5..9b66f01 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -867,6 +867,7 @@
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 @@
}
hwcState.hwcCompositionType = compositionType;
+ getLayerFE().setHwcCompositionType(compositionType);
}
void OutputLayer::prepareForDeviceLayerRequests() {
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp
index 42f3202..523ef7b 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 @@
}
}
+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 68b1395..04b9f3b 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 @@
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 0be3a11..7289e2f 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
@@ -982,6 +982,8 @@
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 dbb1ed3..617dfbe 100644
--- a/services/surfaceflinger/LayerFE.cpp
+++ b/services/surfaceflinger/LayerFE.cpp
@@ -427,4 +427,14 @@
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 9483aeb..64ec278 100644
--- a/services/surfaceflinger/LayerFE.h
+++ b/services/surfaceflinger/LayerFE.h
@@ -59,6 +59,9 @@
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 @@
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 ff45272..cd7210c 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 @@
}
}
+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 @@
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 43fc210..540a9df 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 @@
// 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 @@
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 @@
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 0000000..7002357
--- /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 af40c02..86683da 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 @@
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 21c1bd7..1f8557c 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 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 @@
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 @@
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 @@
// 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 @@
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 @@
}
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 @@
}
}
+ // 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 @@
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 @@
flags &= ~(eEarlyWakeupStart | eEarlyWakeupEnd);
}
}
+ if (flags & eEarlyWakeupStart) {
+ queuedWorkload |= adpf::Workload::WAKEUP;
+ }
+ mPowerAdvisor->setQueuedWorkload(queuedWorkload);
const int64_t postTime = systemTime();
@@ -4963,6 +5030,7 @@
originUid,
transactionId,
mergedTransactionIds};
+ state.workloadHint = queuedWorkload;
if (mTransactionTracing) {
mTransactionTracing->addQueuedTransaction(state);
@@ -7396,6 +7464,8 @@
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 0000000..39b6fa1
--- /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 dc5716b..9a7e97f 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 @@
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 2deb177..ab8c733 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 @@
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, 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 5c25f34..d7f7bdb 100644
--- a/services/surfaceflinger/tests/unittests/PowerAdvisorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/PowerAdvisorTest.cpp
@@ -39,6 +39,7 @@
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 @@
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 @@
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 @@
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 fd55597..5abee16 100644
--- a/services/surfaceflinger/tests/unittests/mock/PowerAdvisor/MockPowerAdvisor.h
+++ b/services/surfaceflinger/tests/unittests/mock/PowerAdvisor/MockPowerAdvisor.h
@@ -65,6 +65,10 @@
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