diff options
65 files changed, 1299 insertions, 945 deletions
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg index c71c4a0251..39eb4abb39 100644 --- a/PREUPLOAD.cfg +++ b/PREUPLOAD.cfg @@ -14,6 +14,7 @@ clang_format = --commit ${PREUPLOAD_COMMIT} --style file --extensions c,h,cc,cpp include/powermanager/ libs/binder/fuzzer/ libs/binder/ + libs/binderdebug/ libs/binderthreadstate/ libs/graphicsenv/ libs/gui/ diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc index 95f5c03a37..e66cc412f0 100644 --- a/cmds/atrace/atrace.rc +++ b/cmds/atrace/atrace.rc @@ -501,6 +501,33 @@ on late-init && property:ro.boot.hypervisor.vm.supported=1 chmod 0440 /sys/kernel/debug/tracing/hyp/events/hyp/hyp_exit/id chmod 0440 /sys/kernel/tracing/hyp/events/hyp/hyp_exit/id +# host_hcall event + chmod 0660 /sys/kernel/debug/tracing/hyp/events/hyp/host_hcall/enable + chmod 0660 /sys/kernel/tracing/hyp/events/hyp/host_hcall/enable +# TODO(b/249050813): should this be handled in kernel? + chmod 0440 /sys/kernel/debug/tracing/hyp/events/hyp/host_hcall/format + chmod 0440 /sys/kernel/tracing/hyp/events/hyp/host_hcall/format + chmod 0440 /sys/kernel/debug/tracing/hyp/events/hyp/host_hcall/id + chmod 0440 /sys/kernel/tracing/hyp/events/hyp/host_hcall/id + +# host_smc event + chmod 0660 /sys/kernel/debug/tracing/hyp/events/hyp/host_smc/enable + chmod 0660 /sys/kernel/tracing/hyp/events/hyp/host_smc/enable +# TODO(b/249050813): should this be handled in kernel? + chmod 0440 /sys/kernel/debug/tracing/hyp/events/hyp/host_smc/format + chmod 0440 /sys/kernel/tracing/hyp/events/hyp/host_smc/format + chmod 0440 /sys/kernel/debug/tracing/hyp/events/hyp/host_smc/id + chmod 0440 /sys/kernel/tracing/hyp/events/hyp/host_smc/id + +# host_mem_abort event + chmod 0660 /sys/kernel/debug/tracing/hyp/events/hyp/host_mem_abort/enable + chmod 0660 /sys/kernel/tracing/hyp/events/hyp/host_mem_abort/enable +# TODO(b/249050813): should this be handled in kernel? + chmod 0440 /sys/kernel/debug/tracing/hyp/events/hyp/host_mem_abort/format + chmod 0440 /sys/kernel/tracing/hyp/events/hyp/host_mem_abort/format + chmod 0440 /sys/kernel/debug/tracing/hyp/events/hyp/host_mem_abort/id + chmod 0440 /sys/kernel/tracing/hyp/events/hyp/host_mem_abort/id + on property:persist.debug.atrace.boottrace=1 start boottrace diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp index 23cdd10a25..6f84e7c0ac 100644 --- a/cmds/dumpstate/dumpstate.cpp +++ b/cmds/dumpstate/dumpstate.cpp @@ -1254,8 +1254,9 @@ static Dumpstate::RunStatus RunDumpsysTextByPriority(const std::string& title, i dumpsys.writeDumpHeader(STDOUT_FILENO, service, priority); dumpsys.writeDumpFooter(STDOUT_FILENO, service, std::chrono::milliseconds(1)); } else { - status_t status = dumpsys.startDumpThread(Dumpsys::TYPE_DUMP, service, args); - if (status == OK) { + status_t status = dumpsys.startDumpThread(Dumpsys::TYPE_DUMP | Dumpsys::TYPE_PID, + service, args); + if (status == OK) { dumpsys.writeDumpHeader(STDOUT_FILENO, service, priority); std::chrono::duration<double> elapsed_seconds; if (priority == IServiceManager::DUMP_FLAG_PRIORITY_HIGH && @@ -1902,6 +1903,9 @@ Dumpstate::RunStatus Dumpstate::DumpstateDefaultAfterCritical() { } ds.AddDir(PREREBOOT_DATA_DIR, false); add_mountinfo(); + for (const char* path : {"/proc/cpuinfo", "/proc/meminfo"}) { + ds.AddZipEntry(ZIP_ROOT_DIR + path, path); + } DumpIpTablesAsRoot(); DumpDynamicPartitionInfo(); ds.AddDir(OTA_METADATA_DIR, true); diff --git a/include/input/PropertyMap.h b/include/input/PropertyMap.h index 28e4816afe..18ce16df36 100644 --- a/include/input/PropertyMap.h +++ b/include/input/PropertyMap.h @@ -18,7 +18,10 @@ #include <android-base/result.h> #include <utils/Tokenizer.h> + +#include <string> #include <unordered_map> +#include <unordered_set> namespace android { @@ -57,6 +60,9 @@ public: */ void addProperty(const std::string& key, const std::string& value); + /* Returns a set of all property keys starting with the given prefix. */ + std::unordered_set<std::string> getKeysWithPrefix(const std::string& prefix) const; + /* Gets the value of a property and parses it. * Returns true and sets outValue if the key was found and its value was parsed successfully. * Otherwise returns false and does not modify outValue. (Also logs a warning.) @@ -65,6 +71,7 @@ public: bool tryGetProperty(const std::string& key, bool& outValue) const; bool tryGetProperty(const std::string& key, int32_t& outValue) const; bool tryGetProperty(const std::string& key, float& outValue) const; + bool tryGetProperty(const std::string& key, double& outValue) const; /* Adds all values from the specified property map. */ void addAll(const PropertyMap* map); diff --git a/libs/binder/RecordedTransaction.cpp b/libs/binder/RecordedTransaction.cpp index 51b971651d..ef58ed365f 100644 --- a/libs/binder/RecordedTransaction.cpp +++ b/libs/binder/RecordedTransaction.cpp @@ -127,8 +127,7 @@ std::optional<RecordedTransaction> RecordedTransaction::fromDetails( t.mData.mInterfaceName = std::string(String8(interfaceName).string()); if (interfaceName.size() != t.mData.mInterfaceName.size()) { LOG(ERROR) << "Interface Name is not valid. Contains characters that aren't single byte " - "utf-8: " - << interfaceName; + "utf-8."; return std::nullopt; } diff --git a/libs/binder/RpcState.cpp b/libs/binder/RpcState.cpp index 38bd081b8b..ed3ce24e46 100644 --- a/libs/binder/RpcState.cpp +++ b/libs/binder/RpcState.cpp @@ -262,8 +262,10 @@ void RpcState::dump() { } void RpcState::clear() { - RpcMutexUniqueLock _l(mNodeMutex); + return clear(RpcMutexUniqueLock(mNodeMutex)); +} +void RpcState::clear(RpcMutexUniqueLock nodeLock) { if (mTerminated) { LOG_ALWAYS_FATAL_IF(!mNodeForAddress.empty(), "New state should be impossible after terminating!"); @@ -292,7 +294,7 @@ void RpcState::clear() { auto temp = std::move(mNodeForAddress); mNodeForAddress.clear(); // RpcState isn't reusable, but for future/explicit - _l.unlock(); + nodeLock.unlock(); temp.clear(); // explicit } @@ -704,7 +706,7 @@ status_t RpcState::sendDecStrongToTarget(const sp<RpcSession::RpcConnection>& co }; { - RpcMutexLockGuard _l(mNodeMutex); + RpcMutexUniqueLock _l(mNodeMutex); if (mTerminated) return DEAD_OBJECT; // avoid fatal only, otherwise races auto it = mNodeForAddress.find(addr); LOG_ALWAYS_FATAL_IF(it == mNodeForAddress.end(), @@ -720,8 +722,9 @@ status_t RpcState::sendDecStrongToTarget(const sp<RpcSession::RpcConnection>& co body.amount = it->second.timesRecd - target; it->second.timesRecd = target; - LOG_ALWAYS_FATAL_IF(nullptr != tryEraseNode(it), + LOG_ALWAYS_FATAL_IF(nullptr != tryEraseNode(session, std::move(_l), it), "Bad state. RpcState shouldn't own received binder"); + // LOCK ALREADY RELEASED } RpcWireHeader cmd = { @@ -1164,8 +1167,8 @@ status_t RpcState::processDecStrong(const sp<RpcSession::RpcConnection>& connect it->second.timesSent); it->second.timesSent -= body.amount; - sp<IBinder> tempHold = tryEraseNode(it); - _l.unlock(); + sp<IBinder> tempHold = tryEraseNode(session, std::move(_l), it); + // LOCK ALREADY RELEASED tempHold = nullptr; // destructor may make binder calls on this session return OK; @@ -1229,7 +1232,10 @@ status_t RpcState::validateParcel(const sp<RpcSession>& session, const Parcel& p return OK; } -sp<IBinder> RpcState::tryEraseNode(std::map<uint64_t, BinderNode>::iterator& it) { +sp<IBinder> RpcState::tryEraseNode(const sp<RpcSession>& session, RpcMutexUniqueLock nodeLock, + std::map<uint64_t, BinderNode>::iterator& it) { + bool shouldShutdown = false; + sp<IBinder> ref; if (it->second.timesSent == 0) { @@ -1239,9 +1245,27 @@ sp<IBinder> RpcState::tryEraseNode(std::map<uint64_t, BinderNode>::iterator& it) LOG_ALWAYS_FATAL_IF(!it->second.asyncTodo.empty(), "Can't delete binder w/ pending async transactions"); mNodeForAddress.erase(it); + + if (mNodeForAddress.size() == 0) { + shouldShutdown = true; + } } } + // If we shutdown, prevent RpcState from being re-used. This prevents another + // thread from getting the root object again. + if (shouldShutdown) { + clear(std::move(nodeLock)); + } else { + nodeLock.unlock(); // explicit + } + // LOCK IS RELEASED + + if (shouldShutdown) { + ALOGI("RpcState has no binders left, so triggering shutdown..."); + (void)session->shutdownAndWait(false); + } + return ref; } diff --git a/libs/binder/RpcState.h b/libs/binder/RpcState.h index ac8658540e..0e23ea7515 100644 --- a/libs/binder/RpcState.h +++ b/libs/binder/RpcState.h @@ -168,6 +168,7 @@ public: void clear(); private: + void clear(RpcMutexUniqueLock nodeLock); void dumpLocked(); // Alternative to std::vector<uint8_t> that doesn't abort on allocation failure and caps @@ -268,11 +269,20 @@ private: std::string toString() const; }; - // checks if there is any reference left to a node and erases it. If erase - // happens, and there is a strong reference to the binder kept by - // binderNode, this returns that strong reference, so that it can be - // dropped after any locks are removed. - sp<IBinder> tryEraseNode(std::map<uint64_t, BinderNode>::iterator& it); + // Checks if there is any reference left to a node and erases it. If this + // is the last node, shuts down the session. + // + // Node lock is passed here for convenience, so that we can release it + // and terminate the session, but we could leave it up to the caller + // by returning a continuation if we needed to erase multiple specific + // nodes. It may be tempting to allow the client to keep on holding the + // lock and instead just return whether or not we should shutdown, but + // this introduces the posssibility that another thread calls + // getRootBinder and thinks it is valid, rather than immediately getting + // an error. + sp<IBinder> tryEraseNode(const sp<RpcSession>& session, RpcMutexUniqueLock nodeLock, + std::map<uint64_t, BinderNode>::iterator& it); + // true - success // false - session shutdown, halt [[nodiscard]] bool nodeProgressAsyncNumber(BinderNode* node); diff --git a/libs/binder/TEST_MAPPING b/libs/binder/TEST_MAPPING index 1488400007..07b38d7368 100644 --- a/libs/binder/TEST_MAPPING +++ b/libs/binder/TEST_MAPPING @@ -119,5 +119,10 @@ { "name": "memunreachable_binder_test" } + ], + "imports": [ + { + "path": "packages/modules/Virtualization" + } ] } diff --git a/libs/binder/include/binder/RpcSession.h b/libs/binder/include/binder/RpcSession.h index 0750ccfc3f..a323febbc7 100644 --- a/libs/binder/include/binder/RpcSession.h +++ b/libs/binder/include/binder/RpcSession.h @@ -51,6 +51,9 @@ constexpr uint32_t RPC_WIRE_PROTOCOL_VERSION_RPC_HEADER_FEATURE_EXPLICIT_PARCEL_ * This represents a session (group of connections) between a client * and a server. Multiple connections are needed for multiple parallel "binder" * calls which may also have nested calls. + * + * Once a binder exists in the session, if all references to all binders are dropped, + * the session shuts down. */ class RpcSession final : public virtual RefBase { public: diff --git a/libs/binder/rust/src/binder.rs b/libs/binder/rust/src/binder.rs index 976f54d36f..d0e35de3f7 100644 --- a/libs/binder/rust/src/binder.rs +++ b/libs/binder/rust/src/binder.rs @@ -100,22 +100,17 @@ where /// An interface can promise to be a stable vendor interface ([`Vintf`]), or /// makes no stability guarantees ([`Local`]). [`Local`] is /// currently the default stability. -#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Default)] pub enum Stability { /// Default stability, visible to other modules in the same compilation /// context (e.g. modules on system.img) + #[default] Local, /// A Vendor Interface Object, which promises to be stable Vintf, } -impl Default for Stability { - fn default() -> Self { - Stability::Local - } -} - impl From<Stability> for i32 { fn from(stability: Stability) -> i32 { use Stability::*; diff --git a/libs/binder/tests/IBinderRpcTest.aidl b/libs/binder/tests/IBinderRpcTest.aidl index a3ed571462..116476765a 100644 --- a/libs/binder/tests/IBinderRpcTest.aidl +++ b/libs/binder/tests/IBinderRpcTest.aidl @@ -80,4 +80,8 @@ interface IBinderRpcTest { // get queued. oneway void blockingSendFdOneway(in ParcelFileDescriptor fd); ParcelFileDescriptor blockingRecvFd(); + + // Same as blockingSendFdOneway, but with integers. + oneway void blockingSendIntOneway(int n); + int blockingRecvInt(); } diff --git a/libs/binder/tests/binderRpcBenchmark.cpp b/libs/binder/tests/binderRpcBenchmark.cpp index 52ba9b00fd..593927306e 100644 --- a/libs/binder/tests/binderRpcBenchmark.cpp +++ b/libs/binder/tests/binderRpcBenchmark.cpp @@ -102,9 +102,11 @@ std::unique_ptr<RpcTransportCtxFactory> makeFactoryTls() { } static sp<RpcSession> gSession = RpcSession::make(); +static sp<IBinder> gRpcBinder; // Certificate validation happens during handshake and does not affect the result of benchmarks. // Skip certificate validation to simplify the setup process. static sp<RpcSession> gSessionTls = RpcSession::make(makeFactoryTls()); +static sp<IBinder> gRpcTlsBinder; #ifdef __BIONIC__ static const String16 kKernelBinderInstance = String16(u"binderRpcBenchmark-control"); static sp<IBinder> gKernelBinder; @@ -118,9 +120,9 @@ static sp<IBinder> getBinderForOptions(benchmark::State& state) { return gKernelBinder; #endif case RPC: - return gSession->getRootObject(); + return gRpcBinder; case RPC_TLS: - return gSessionTls->getRootObject(); + return gRpcTlsBinder; default: LOG(FATAL) << "Unknown transport value: " << transport; return nullptr; @@ -254,11 +256,13 @@ int main(int argc, char** argv) { (void)unlink(addr.c_str()); forkRpcServer(addr.c_str(), RpcServer::make(RpcTransportCtxFactoryRaw::make())); setupClient(gSession, addr.c_str()); + gRpcBinder = gSession->getRootObject(); std::string tlsAddr = tmp + "/binderRpcTlsBenchmark"; (void)unlink(tlsAddr.c_str()); forkRpcServer(tlsAddr.c_str(), RpcServer::make(makeFactoryTls())); setupClient(gSessionTls, tlsAddr.c_str()); + gRpcTlsBinder = gSessionTls->getRootObject(); ::benchmark::RunSpecifiedBenchmarks(); return 0; diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp index 5952c4172e..efc314bdec 100644 --- a/libs/binder/tests/binderRpcTest.cpp +++ b/libs/binder/tests/binderRpcTest.cpp @@ -163,7 +163,8 @@ public: session.root = nullptr; } - for (auto& info : sessions) { + for (size_t sessionNum = 0; sessionNum < sessions.size(); sessionNum++) { + auto& info = sessions.at(sessionNum); sp<RpcSession>& session = info.session; EXPECT_NE(nullptr, session); @@ -179,6 +180,7 @@ public: for (size_t i = 0; i < 3; i++) { sp<RpcSession> strongSession = weakSession.promote(); EXPECT_EQ(nullptr, strongSession) + << "For session " << sessionNum << ". " << (debugBacktrace(host.getPid()), debugBacktrace(getpid()), "Leaked sess: ") << strongSession->getStrongCount() << " checked time " << i; @@ -254,6 +256,10 @@ std::unique_ptr<ProcessSession> BinderRpc::createRpcTestSocketServerProcessEtc( const BinderRpcOptions& options) { CHECK_GE(options.numSessions, 1) << "Must have at least one session to a server"; + if (options.numIncomingConnectionsBySession.size() != 0) { + CHECK_EQ(options.numIncomingConnectionsBySession.size(), options.numSessions); + } + SocketType socketType = std::get<0>(GetParam()); RpcSecurity rpcSecurity = std::get<1>(GetParam()); uint32_t clientVersion = std::get<2>(GetParam()); @@ -351,9 +357,15 @@ std::unique_ptr<ProcessSession> BinderRpc::createRpcTestSocketServerProcessEtc( status_t status; - for (const auto& session : sessions) { + for (size_t i = 0; i < sessions.size(); i++) { + const auto& session = sessions.at(i); + + size_t numIncoming = options.numIncomingConnectionsBySession.size() > 0 + ? options.numIncomingConnectionsBySession.at(i) + : 0; + CHECK(session->setProtocolVersion(clientVersion)); - session->setMaxIncomingThreads(options.numIncomingConnections); + session->setMaxIncomingThreads(numIncoming); session->setMaxOutgoingConnections(options.numOutgoingConnections); session->setFileDescriptorTransportMode(options.clientFileDescriptorTransportMode); @@ -587,30 +599,22 @@ TEST_P(BinderRpc, OnewayCallQueueing) { GTEST_SKIP() << "This test requires multiple threads"; } - constexpr size_t kNumSleeps = 10; + constexpr size_t kNumQueued = 10; constexpr size_t kNumExtraServerThreads = 4; - constexpr size_t kSleepMs = 50; // make sure calls to the same object happen on the same thread auto proc = createRpcTestSocketServerProcess({.numThreads = 1 + kNumExtraServerThreads}); - EXPECT_OK(proc.rootIface->lock()); - - size_t epochMsBefore = epochMillis(); - - // all these *Async commands should be queued on the server sequentially, + // all these *Oneway commands should be queued on the server sequentially, // even though there are multiple threads. - for (size_t i = 0; i + 1 < kNumSleeps; i++) { - proc.rootIface->sleepMsAsync(kSleepMs); + for (size_t i = 0; i + 1 < kNumQueued; i++) { + proc.rootIface->blockingSendIntOneway(i); + } + for (size_t i = 0; i + 1 < kNumQueued; i++) { + int n; + proc.rootIface->blockingRecvInt(&n); + EXPECT_EQ(n, i); } - EXPECT_OK(proc.rootIface->unlockInMsAsync(kSleepMs)); - - // this can only return once the final async call has unlocked - EXPECT_OK(proc.rootIface->lockUnlock()); - - size_t epochMsAfter = epochMillis(); - - EXPECT_GE(epochMsAfter, epochMsBefore + kSleepMs * kNumSleeps); saturateThreadPool(1 + kNumExtraServerThreads, proc.rootIface); } @@ -659,6 +663,32 @@ TEST_P(BinderRpc, OnewayCallExhaustion) { proc.proc->sessions.erase(proc.proc->sessions.begin() + 1); } +TEST_P(BinderRpc, SessionWithIncomingThreadpoolDoesntLeak) { + if (clientOrServerSingleThreaded()) { + GTEST_SKIP() << "This test requires multiple threads"; + } + + // session 0 - will check for leaks in destrutor of proc + // session 1 - we want to make sure it gets deleted when we drop all references to it + auto proc = createRpcTestSocketServerProcess( + {.numThreads = 1, .numIncomingConnectionsBySession = {0, 1}, .numSessions = 2}); + + wp<RpcSession> session = proc.proc->sessions.at(1).session; + + // remove all references to the second session + proc.proc->sessions.at(1).root = nullptr; + proc.proc->sessions.erase(proc.proc->sessions.begin() + 1); + + // TODO(b/271830568) more efficient way to wait for other incoming threadpool + // to drain commands. + for (size_t i = 0; i < 100; i++) { + usleep(10 * 1000); + if (session.promote() == nullptr) break; + } + + EXPECT_EQ(nullptr, session.promote()); +} + TEST_P(BinderRpc, SingleDeathRecipient) { if (clientOrServerSingleThreaded()) { GTEST_SKIP() << "This test requires multiple threads"; @@ -676,7 +706,7 @@ TEST_P(BinderRpc, SingleDeathRecipient) { // Death recipient needs to have an incoming connection to be called auto proc = createRpcTestSocketServerProcess( - {.numThreads = 1, .numSessions = 1, .numIncomingConnections = 1}); + {.numThreads = 1, .numSessions = 1, .numIncomingConnectionsBySession = {1}}); auto dr = sp<MyDeathRec>::make(); ASSERT_EQ(OK, proc.rootBinder->linkToDeath(dr, (void*)1, 0)); @@ -689,6 +719,10 @@ TEST_P(BinderRpc, SingleDeathRecipient) { ASSERT_TRUE(dr->mCv.wait_for(lock, 100ms, [&]() { return dr->dead; })); // need to wait for the session to shutdown so we don't "Leak session" + // can't do this before checking the death recipient by calling + // forceShutdown earlier, because shutdownAndWait will also trigger + // a death recipient, but if we had a way to wait for the service + // to gracefully shutdown, we could use that here. EXPECT_TRUE(proc.proc->sessions.at(0).session->shutdownAndWait(true)); proc.expectAlreadyShutdown = true; } @@ -710,7 +744,7 @@ TEST_P(BinderRpc, SingleDeathRecipientOnShutdown) { // Death recipient needs to have an incoming connection to be called auto proc = createRpcTestSocketServerProcess( - {.numThreads = 1, .numSessions = 1, .numIncomingConnections = 1}); + {.numThreads = 1, .numSessions = 1, .numIncomingConnectionsBySession = {1}}); auto dr = sp<MyDeathRec>::make(); EXPECT_EQ(OK, proc.rootBinder->linkToDeath(dr, (void*)1, 0)); @@ -743,8 +777,7 @@ TEST_P(BinderRpc, DeathRecipientFailsWithoutIncoming) { void binderDied(const wp<IBinder>& /* who */) override {} }; - auto proc = createRpcTestSocketServerProcess( - {.numThreads = 1, .numSessions = 1, .numIncomingConnections = 0}); + auto proc = createRpcTestSocketServerProcess({.numThreads = 1, .numSessions = 1}); auto dr = sp<MyDeathRec>::make(); EXPECT_EQ(INVALID_OPERATION, proc.rootBinder->linkToDeath(dr, (void*)1, 0)); @@ -763,19 +796,13 @@ TEST_P(BinderRpc, UnlinkDeathRecipient) { // Death recipient needs to have an incoming connection to be called auto proc = createRpcTestSocketServerProcess( - {.numThreads = 1, .numSessions = 1, .numIncomingConnections = 1}); + {.numThreads = 1, .numSessions = 1, .numIncomingConnectionsBySession = {1}}); auto dr = sp<MyDeathRec>::make(); ASSERT_EQ(OK, proc.rootBinder->linkToDeath(dr, (void*)1, 0)); ASSERT_EQ(OK, proc.rootBinder->unlinkToDeath(dr, (void*)1, 0, nullptr)); - if (auto status = proc.rootIface->scheduleShutdown(); !status.isOk()) { - EXPECT_EQ(DEAD_OBJECT, status.transactionError()) << status; - } - - // need to wait for the session to shutdown so we don't "Leak session" - EXPECT_TRUE(proc.proc->sessions.at(0).session->shutdownAndWait(true)); - proc.expectAlreadyShutdown = true; + proc.forceShutdown(); } TEST_P(BinderRpc, Die) { diff --git a/libs/binder/tests/binderRpcTestCommon.h b/libs/binder/tests/binderRpcTestCommon.h index a467ee389b..a9f0df3c0f 100644 --- a/libs/binder/tests/binderRpcTestCommon.h +++ b/libs/binder/tests/binderRpcTestCommon.h @@ -126,7 +126,11 @@ static inline size_t epochMillis() { struct BinderRpcOptions { size_t numThreads = 1; size_t numSessions = 1; - size_t numIncomingConnections = 0; + // right now, this can be empty, or length numSessions, where each value + // represents the info for the corresponding session, but we should + // probably switch this to be a list of sessions options so that other + // options can all be specified per session + std::vector<size_t> numIncomingConnectionsBySession = {}; size_t numOutgoingConnections = SIZE_MAX; RpcSession::FileDescriptorTransportMode clientFileDescriptorTransportMode = RpcSession::FileDescriptorTransportMode::NONE; @@ -445,6 +449,12 @@ public: Status blockingRecvFd(android::os::ParcelFileDescriptor* /*fd*/) override { return Status::fromStatusT(UNKNOWN_TRANSACTION); } + + Status blockingSendIntOneway(int /*n*/) override { + return Status::fromStatusT(UNKNOWN_TRANSACTION); + } + + Status blockingRecvInt(int* /*n*/) override { return Status::fromStatusT(UNKNOWN_TRANSACTION); } }; } // namespace android diff --git a/libs/binder/tests/binderRpcTestFixture.h b/libs/binder/tests/binderRpcTestFixture.h index c99d68aacf..20fb6bf3ce 100644 --- a/libs/binder/tests/binderRpcTestFixture.h +++ b/libs/binder/tests/binderRpcTestFixture.h @@ -64,6 +64,21 @@ struct BinderRpcTestProcessSession { // whether session should be invalidated by end of run bool expectAlreadyShutdown = false; + // TODO(b/271830568): fix this in binderRpcTest, we always use the first session to cause the + // remote process to shutdown. Normally, when we shutdown, the default in the destructor is to + // check that there are no leaks and shutdown. However, when there are incoming threadpools, + // there will be a few extra binder threads there, so we can't shutdown the server. We should + // consider an alternative way of doing the test so that we don't need this, some ideas, such as + // program in understanding of incoming threadpool into the destructor so that (e.g. + // intelligently wait for sessions to shutdown now that they will do this) + void forceShutdown() { + if (auto status = rootIface->scheduleShutdown(); !status.isOk()) { + EXPECT_EQ(DEAD_OBJECT, status.transactionError()) << status; + } + EXPECT_TRUE(proc->sessions.at(0).session->shutdownAndWait(true)); + expectAlreadyShutdown = true; + } + BinderRpcTestProcessSession(BinderRpcTestProcessSession&&) = default; ~BinderRpcTestProcessSession() { if (!expectAlreadyShutdown) { diff --git a/libs/binder/tests/binderRpcTestService.cpp b/libs/binder/tests/binderRpcTestService.cpp index a27bd2f2e6..ca5a117f00 100644 --- a/libs/binder/tests/binderRpcTestService.cpp +++ b/libs/binder/tests/binderRpcTestService.cpp @@ -83,6 +83,18 @@ public: fd->reset(mFdChannel.read()); return Status::ok(); } + + HandoffChannel<int> mIntChannel; + + Status blockingSendIntOneway(int n) override { + mIntChannel.write(n); + return Status::ok(); + } + + Status blockingRecvInt(int* n) override { + *n = mIntChannel.read(); + return Status::ok(); + } }; int main(int argc, char* argv[]) { diff --git a/libs/binder/tests/binderRpcTestTrusty.cpp b/libs/binder/tests/binderRpcTestTrusty.cpp index 63b56a3a64..85794bdf14 100644 --- a/libs/binder/tests/binderRpcTestTrusty.cpp +++ b/libs/binder/tests/binderRpcTestTrusty.cpp @@ -60,9 +60,9 @@ std::string BinderRpc::PrintParamInfo(const testing::TestParamInfo<ParamType>& i // threads. std::unique_ptr<ProcessSession> BinderRpc::createRpcTestSocketServerProcessEtc( const BinderRpcOptions& options) { - LOG_ALWAYS_FATAL_IF(options.numIncomingConnections != 0, + LOG_ALWAYS_FATAL_IF(options.numIncomingConnectionsBySession.size() != 0, "Non-zero incoming connections %zu on Trusty", - options.numIncomingConnections); + options.numIncomingConnectionsBySession.size()); uint32_t clientVersion = std::get<2>(GetParam()); uint32_t serverVersion = std::get<3>(GetParam()); diff --git a/libs/binder/tests/binderRpcUniversalTests.cpp b/libs/binder/tests/binderRpcUniversalTests.cpp index 11a22b0fb6..1f4601010c 100644 --- a/libs/binder/tests/binderRpcUniversalTests.cpp +++ b/libs/binder/tests/binderRpcUniversalTests.cpp @@ -463,7 +463,7 @@ TEST_P(BinderRpc, Callbacks) { auto proc = createRpcTestSocketServerProcess( {.numThreads = 1, .numSessions = 1, - .numIncomingConnections = numIncomingConnections}); + .numIncomingConnectionsBySession = {numIncomingConnections}}); auto cb = sp<MyBinderRpcCallback>::make(); if (callIsOneway) { @@ -491,16 +491,7 @@ TEST_P(BinderRpc, Callbacks) { << "callIsOneway: " << callIsOneway << " callbackIsOneway: " << callbackIsOneway << " delayed: " << delayed; - // since we are severing the connection, we need to go ahead and - // tell the server to shutdown and exit so that waitpid won't hang - if (auto status = proc.rootIface->scheduleShutdown(); !status.isOk()) { - EXPECT_EQ(DEAD_OBJECT, status.transactionError()) << status; - } - - // since this session has an incoming connection w/ a threadpool, we - // need to manually shut it down - EXPECT_TRUE(proc.proc->sessions.at(0).session->shutdownAndWait(true)); - proc.expectAlreadyShutdown = true; + proc.forceShutdown(); } } } diff --git a/libs/binderdebug/Android.bp b/libs/binderdebug/Android.bp index 3eeaf3e4f1..1454727114 100644 --- a/libs/binderdebug/Android.bp +++ b/libs/binderdebug/Android.bp @@ -21,6 +21,17 @@ package { default_applicable_licenses: ["frameworks_native_license"], } +cc_benchmark { + name: "binder_thread_stats", + shared_libs: [ + "libutils", + "libbinder", + "libbase", + ], + static_libs: ["libbinderdebug"], + srcs: ["stats.cpp"], +} + cc_library { name: "libbinderdebug", vendor_available: true, diff --git a/libs/binderdebug/stats.cpp b/libs/binderdebug/stats.cpp new file mode 100644 index 0000000000..9c26afaa97 --- /dev/null +++ b/libs/binderdebug/stats.cpp @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <android-base/logging.h> +#include <binder/BpBinder.h> +#include <binder/IServiceManager.h> +#include <binderdebug/BinderDebug.h> +#include <utils/Errors.h> + +#include <inttypes.h> + +namespace android { + +extern "C" int main() { + // ignore args - we only print csv + + // we should use a csv library here for escaping, because + // the name is coming from another process + printf("name,binder_threads_in_use,binder_threads_started,client_count\n"); + + for (const String16& name : defaultServiceManager()->listServices()) { + sp<IBinder> binder = defaultServiceManager()->checkService(name); + if (binder == nullptr) { + fprintf(stderr, "%s is null", String8(name).c_str()); + continue; + } + + BpBinder* remote = binder->remoteBinder(); + const auto handle = remote->getDebugBinderHandle(); + CHECK(handle != std::nullopt); + + pid_t pid; + CHECK_EQ(OK, binder->getDebugPid(&pid)); + + BinderPidInfo info; + CHECK_EQ(OK, getBinderPidInfo(BinderDebugContext::BINDER, pid, &info)); + + std::vector<pid_t> clientPids; + CHECK_EQ(OK, + getBinderClientPids(BinderDebugContext::BINDER, getpid(), pid, *handle, + &clientPids)); + + printf("%s,%" PRIu32 ",%" PRIu32 ",%zu\n", String8(name).c_str(), info.threadUsage, + info.threadCount, clientPids.size()); + } + return 0; +} + +} // namespace android diff --git a/libs/ftl/Android.bp b/libs/ftl/Android.bp index 8e57152b49..ea1b5e4998 100644 --- a/libs/ftl/Android.bp +++ b/libs/ftl/Android.bp @@ -10,9 +10,6 @@ package { cc_test { name: "ftl_test", test_suites: ["device-tests"], - sanitize: { - address: true, - }, srcs: [ "algorithm_test.cpp", "cast_test.cpp", diff --git a/libs/ftl/TEST_MAPPING b/libs/ftl/TEST_MAPPING new file mode 100644 index 0000000000..ec0c671213 --- /dev/null +++ b/libs/ftl/TEST_MAPPING @@ -0,0 +1,12 @@ +{ + "presubmit": [ + { + "name": "ftl_test" + } + ], + "hwasan-presubmit": [ + { + "name": "ftl_test" + } + ] +} diff --git a/libs/input/Android.bp b/libs/input/Android.bp index f38dd98428..869458c407 100644 --- a/libs/input/Android.bp +++ b/libs/input/Android.bp @@ -167,6 +167,7 @@ cc_library { cc_defaults { name: "libinput_fuzz_defaults", + cpp_std: "c++20", host_supported: true, shared_libs: [ "libutils", diff --git a/libs/input/PropertyMap.cpp b/libs/input/PropertyMap.cpp index ed9ac9fc72..9a4f10b21d 100644 --- a/libs/input/PropertyMap.cpp +++ b/libs/input/PropertyMap.cpp @@ -16,6 +16,8 @@ #define LOG_TAG "PropertyMap" +#include <cstdlib> + #include <input/PropertyMap.h> #include <log/log.h> @@ -44,6 +46,16 @@ void PropertyMap::addProperty(const std::string& key, const std::string& value) mProperties.emplace(key, value); } +std::unordered_set<std::string> PropertyMap::getKeysWithPrefix(const std::string& prefix) const { + std::unordered_set<std::string> keys; + for (const auto& [key, _] : mProperties) { + if (key.starts_with(prefix)) { + keys.insert(key); + } + } + return keys; +} + bool PropertyMap::hasProperty(const std::string& key) const { return mProperties.find(key) != mProperties.end(); } @@ -102,6 +114,23 @@ bool PropertyMap::tryGetProperty(const std::string& key, float& outValue) const return true; } +bool PropertyMap::tryGetProperty(const std::string& key, double& outValue) const { + std::string stringValue; + if (!tryGetProperty(key, stringValue) || stringValue.length() == 0) { + return false; + } + + char* end; + double value = strtod(stringValue.c_str(), &end); + if (*end != '\0') { + ALOGW("Property key '%s' has invalid value '%s'. Expected a double.", key.c_str(), + stringValue.c_str()); + return false; + } + outValue = value; + return true; +} + void PropertyMap::addAll(const PropertyMap* map) { for (const auto& [key, value] : map->mProperties) { mProperties.emplace(key, value); diff --git a/libs/input/TfLiteMotionPredictor.cpp b/libs/input/TfLiteMotionPredictor.cpp index 691e87c366..3b061d1cf1 100644 --- a/libs/input/TfLiteMotionPredictor.cpp +++ b/libs/input/TfLiteMotionPredictor.cpp @@ -61,8 +61,21 @@ constexpr char OUTPUT_R[] = "r"; constexpr char OUTPUT_PHI[] = "phi"; constexpr char OUTPUT_PRESSURE[] = "pressure"; +// Ideally, we would just use std::filesystem::exists here, but it requires libc++fs, which causes +// build issues in other parts of the system. +#if defined(__ANDROID__) +bool fileExists(const char* filename) { + struct stat buffer; + return stat(filename, &buffer) == 0; +} +#endif + std::string getModelPath() { #if defined(__ANDROID__) + static const char* oemModel = "/vendor/etc/motion_predictor_model.fb"; + if (fileExists(oemModel)) { + return oemModel; + } return "/system/etc/motion_predictor_model.fb"; #else return base::GetExecutableDirectory() + "/motion_predictor_model.fb"; @@ -217,7 +230,7 @@ void TfLiteMotionPredictorBuffers::pushSample(int64_t timestamp, std::unique_ptr<TfLiteMotionPredictorModel> TfLiteMotionPredictorModel::create() { const std::string modelPath = getModelPath(); - const int fd = open(modelPath.c_str(), O_RDONLY); + android::base::unique_fd fd(open(modelPath.c_str(), O_RDONLY)); if (fd == -1) { PLOG(FATAL) << "Could not read model from " << modelPath; } @@ -232,9 +245,6 @@ std::unique_ptr<TfLiteMotionPredictorModel> TfLiteMotionPredictorModel::create() if (!modelBuffer) { PLOG(FATAL) << "Failed to mmap model"; } - if (close(fd) == -1) { - PLOG(FATAL) << "Failed to close model fd"; - } return std::unique_ptr<TfLiteMotionPredictorModel>( new TfLiteMotionPredictorModel(std::move(modelBuffer))); diff --git a/services/gpuservice/tests/unittests/Android.bp b/services/gpuservice/tests/unittests/Android.bp index 86f6c7febb..51642f9472 100644 --- a/services/gpuservice/tests/unittests/Android.bp +++ b/services/gpuservice/tests/unittests/Android.bp @@ -24,9 +24,6 @@ package { cc_test { name: "gpuservice_unittest", test_suites: ["device-tests"], - sanitize: { - address: true, - }, srcs: [ "GpuMemTest.cpp", "GpuMemTracerTest.cpp", diff --git a/services/inputflinger/reader/InputDevice.cpp b/services/inputflinger/reader/InputDevice.cpp index 0d2030e0c4..69363b6e10 100644 --- a/services/inputflinger/reader/InputDevice.cpp +++ b/services/inputflinger/reader/InputDevice.cpp @@ -210,14 +210,13 @@ void InputDevice::addEventHubDevice(int32_t eventHubId, bool populateMappers) { // Touchscreens and touchpad devices. static const bool ENABLE_TOUCHPAD_GESTURES_LIBRARY = sysprop::InputProperties::enable_touchpad_gestures_library().value_or(true); - // TODO(b/246587538): Fix the new touchpad stack for Sony DualShock 4 (5c4, 9cc) and DualSense - // (ce6) touchpads, or at least load this setting from the IDC file. + // TODO(b/272518665): Fix the new touchpad stack for Sony DualShock 4 (5c4, 9cc) touchpads, or + // at least load this setting from the IDC file. const InputDeviceIdentifier identifier = contextPtr->getDeviceIdentifier(); - const bool isSonyGamepadTouchpad = identifier.vendor == 0x054c && - (identifier.product == 0x05c4 || identifier.product == 0x09cc || - identifier.product == 0x0ce6); + const bool isSonyDualShock4Touchpad = identifier.vendor == 0x054c && + (identifier.product == 0x05c4 || identifier.product == 0x09cc); if (ENABLE_TOUCHPAD_GESTURES_LIBRARY && classes.test(InputDeviceClass::TOUCHPAD) && - classes.test(InputDeviceClass::TOUCH_MT) && !isSonyGamepadTouchpad) { + classes.test(InputDeviceClass::TOUCH_MT) && !isSonyDualShock4Touchpad) { mappers.push_back(std::make_unique<TouchpadInputMapper>(*contextPtr)); } else if (classes.test(InputDeviceClass::TOUCH_MT)) { mappers.push_back(std::make_unique<MultiTouchInputMapper>(*contextPtr)); diff --git a/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp b/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp index d3af402153..330976719d 100644 --- a/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp +++ b/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp @@ -20,6 +20,7 @@ #include <optional> #include <android/input.h> +#include <ftl/enum.h> #include <input/PrintTools.h> #include <linux/input-event-codes.h> #include <log/log_main.h> @@ -216,6 +217,11 @@ void TouchpadInputMapper::dump(std::string& dump) { std::list<NotifyArgs> TouchpadInputMapper::configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes) { + if (!changes) { + // First time configuration + mPropertyProvider.loadPropertiesFromIdcFile(getDeviceContext().getConfiguration()); + } + if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) { std::optional<int32_t> displayId = mPointerController->getDisplayId(); ui::Rotation orientation = ui::ROTATION_0; diff --git a/services/inputflinger/reader/mapper/gestures/PropertyProvider.cpp b/services/inputflinger/reader/mapper/gestures/PropertyProvider.cpp index 089f45a4e6..3d883389c9 100644 --- a/services/inputflinger/reader/mapper/gestures/PropertyProvider.cpp +++ b/services/inputflinger/reader/mapper/gestures/PropertyProvider.cpp @@ -84,6 +84,29 @@ std::string PropertyProvider::dump() const { return dump; } +void PropertyProvider::loadPropertiesFromIdcFile(const PropertyMap& idcProperties) { + // For compatibility with the configuration file syntax, gesture property names in IDC files are + // prefixed with "gestureProp." and have spaces replaced by underscores. So, for example, the + // configuration key "gestureProp.Palm_Width" refers to the "Palm Width" property. + const std::string gesturePropPrefix = "gestureProp."; + for (const std::string key : idcProperties.getKeysWithPrefix(gesturePropPrefix)) { + std::string propertyName = key.substr(gesturePropPrefix.length()); + for (size_t i = 0; i < propertyName.length(); i++) { + if (propertyName[i] == '_') { + propertyName[i] = ' '; + } + } + + auto it = mProperties.find(propertyName); + if (it != mProperties.end()) { + it->second.trySetFromIdcProperty(idcProperties, key); + } else { + ALOGE("Gesture property \"%s\" specified in IDC file does not exist for this device.", + propertyName.c_str()); + } + } +} + GesturesProp* PropertyProvider::createIntArrayProperty(const std::string& name, int* loc, size_t count, const int* init) { const auto [it, inserted] = @@ -211,6 +234,59 @@ void GesturesProp::setRealValues(const std::vector<double>& values) { setValues(std::get<double*>(mDataPointer), values); } +namespace { + +// Helper to std::visit with lambdas. +template <typename... V> +struct Visitor : V... {}; +// explicit deduction guide (not needed as of C++20) +template <typename... V> +Visitor(V...) -> Visitor<V...>; + +} // namespace + +void GesturesProp::trySetFromIdcProperty(const android::PropertyMap& idcProperties, + const std::string& propertyName) { + if (mCount != 1) { + ALOGE("Gesture property \"%s\" is an array, and so cannot be set in an IDC file.", + mName.c_str()); + return; + } + bool parsedSuccessfully = false; + Visitor setVisitor{ + [&](int*) { + int32_t value; + parsedSuccessfully = idcProperties.tryGetProperty(propertyName, value); + if (parsedSuccessfully) { + setIntValues({value}); + } + }, + [&](GesturesPropBool*) { + bool value; + parsedSuccessfully = idcProperties.tryGetProperty(propertyName, value); + if (parsedSuccessfully) { + setBoolValues({value}); + } + }, + [&](double*) { + double value; + parsedSuccessfully = idcProperties.tryGetProperty(propertyName, value); + if (parsedSuccessfully) { + setRealValues({value}); + } + }, + [&](const char**) { + ALOGE("Gesture property \"%s\" is a string, and so cannot be set in an IDC file.", + mName.c_str()); + }, + }; + std::visit(setVisitor, mDataPointer); + + ALOGE_IF(!parsedSuccessfully, "Gesture property \"%s\" could set due to a type mismatch.", + mName.c_str()); + return; +} + template <typename T, typename U> const std::vector<T> GesturesProp::getValues(U* dataPointer) const { if (mGetter != nullptr) { diff --git a/services/inputflinger/reader/mapper/gestures/PropertyProvider.h b/services/inputflinger/reader/mapper/gestures/PropertyProvider.h index 50451a3929..c7e0858c6d 100644 --- a/services/inputflinger/reader/mapper/gestures/PropertyProvider.h +++ b/services/inputflinger/reader/mapper/gestures/PropertyProvider.h @@ -22,6 +22,7 @@ #include <vector> #include "include/gestures.h" +#include "input/PropertyMap.h" namespace android { @@ -35,6 +36,8 @@ public: GesturesProp& getProperty(const std::string& name); std::string dump() const; + void loadPropertiesFromIdcFile(const PropertyMap& idcProperties); + // Methods to be called by the gestures library: GesturesProp* createIntArrayProperty(const std::string& name, int* loc, size_t count, const int* init); @@ -83,6 +86,9 @@ public: // Setting string values isn't supported since we don't have a use case yet and the memory // management adds additional complexity. + void trySetFromIdcProperty(const android::PropertyMap& idcProperties, + const std::string& propertyName); + private: // Two type parameters are required for these methods, rather than one, due to the gestures // library using its own bool type. diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp index 711cfbf922..eb58d0bd95 100644 --- a/services/inputflinger/tests/InputReader_test.cpp +++ b/services/inputflinger/tests/InputReader_test.cpp @@ -1830,7 +1830,7 @@ using StylusButtonIntegrationTestTypes = ::testing::Types<UinputTouchScreen, UinputExternalStylus, UinputExternalStylusWithPressure>; TYPED_TEST_SUITE(StylusButtonIntegrationTest, StylusButtonIntegrationTestTypes); -TYPED_TEST(StylusButtonIntegrationTest, StylusButtonsGenerateKeyEvents) { +TYPED_TEST(StylusButtonIntegrationTest, DISABLED_StylusButtonsGenerateKeyEvents) { const auto stylusId = TestFixture::mStylusInfo.getId(); TestFixture::mStylus->pressKey(BTN_STYLUS); @@ -1844,7 +1844,7 @@ TYPED_TEST(StylusButtonIntegrationTest, StylusButtonsGenerateKeyEvents) { WithKeyCode(AKEYCODE_STYLUS_BUTTON_PRIMARY), WithDeviceId(stylusId)))); } -TYPED_TEST(StylusButtonIntegrationTest, StylusButtonsSurroundingTouchGesture) { +TYPED_TEST(StylusButtonIntegrationTest, DISABLED_StylusButtonsSurroundingTouchGesture) { const Point centerPoint = TestFixture::mTouchscreen->getCenterPoint(); const auto touchscreenId = TestFixture::mTouchscreenInfo.getId(); const auto stylusId = TestFixture::mStylusInfo.getId(); @@ -1890,7 +1890,7 @@ TYPED_TEST(StylusButtonIntegrationTest, StylusButtonsSurroundingTouchGesture) { WithKeyCode(AKEYCODE_STYLUS_BUTTON_PRIMARY), WithDeviceId(stylusId)))); } -TYPED_TEST(StylusButtonIntegrationTest, StylusButtonsSurroundingHoveringTouchGesture) { +TYPED_TEST(StylusButtonIntegrationTest, DISABLED_StylusButtonsSurroundingHoveringTouchGesture) { const Point centerPoint = TestFixture::mTouchscreen->getCenterPoint(); const auto touchscreenId = TestFixture::mTouchscreenInfo.getId(); const auto stylusId = TestFixture::mStylusInfo.getId(); @@ -1966,7 +1966,7 @@ TYPED_TEST(StylusButtonIntegrationTest, StylusButtonsSurroundingHoveringTouchGes WithKeyCode(AKEYCODE_STYLUS_BUTTON_PRIMARY), WithDeviceId(stylusId)))); } -TYPED_TEST(StylusButtonIntegrationTest, StylusButtonsWithinTouchGesture) { +TYPED_TEST(StylusButtonIntegrationTest, DISABLED_StylusButtonsWithinTouchGesture) { const Point centerPoint = TestFixture::mTouchscreen->getCenterPoint(); const auto touchscreenId = TestFixture::mTouchscreenInfo.getId(); const auto stylusId = TestFixture::mStylusInfo.getId(); @@ -2020,7 +2020,7 @@ TYPED_TEST(StylusButtonIntegrationTest, StylusButtonsWithinTouchGesture) { WithDeviceId(touchscreenId)))); } -TYPED_TEST(StylusButtonIntegrationTest, StylusButtonMotionEventsDisabled) { +TYPED_TEST(StylusButtonIntegrationTest, DISABLED_StylusButtonMotionEventsDisabled) { TestFixture::mFakePolicy->setStylusButtonMotionEventsEnabled(false); TestFixture::mReader->requestRefreshConfiguration( InputReaderConfiguration::CHANGE_STYLUS_BUTTON_REPORTING); @@ -2077,7 +2077,7 @@ TYPED_TEST(StylusButtonIntegrationTest, StylusButtonMotionEventsDisabled) { // ongoing stylus gesture that is being emitted by the touchscreen. using ExternalStylusIntegrationTest = TouchIntegrationTest; -TEST_F(ExternalStylusIntegrationTest, FusedExternalStylusPressureReported) { +TEST_F(ExternalStylusIntegrationTest, DISABLED_FusedExternalStylusPressureReported) { const Point centerPoint = mDevice->getCenterPoint(); // Create an external stylus capable of reporting pressure data that @@ -2123,7 +2123,7 @@ TEST_F(ExternalStylusIntegrationTest, FusedExternalStylusPressureReported) { ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyKeyWasNotCalled()); } -TEST_F(ExternalStylusIntegrationTest, FusedExternalStylusPressureNotReported) { +TEST_F(ExternalStylusIntegrationTest, DISABLED_FusedExternalStylusPressureNotReported) { const Point centerPoint = mDevice->getCenterPoint(); // Create an external stylus capable of reporting pressure data that @@ -2191,7 +2191,7 @@ TEST_F(ExternalStylusIntegrationTest, FusedExternalStylusPressureNotReported) { ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyKeyWasNotCalled()); } -TEST_F(ExternalStylusIntegrationTest, UnfusedExternalStylus) { +TEST_F(ExternalStylusIntegrationTest, DISABLED_UnfusedExternalStylus) { const Point centerPoint = mDevice->getCenterPoint(); // Create an external stylus device that does not support pressure. It should not affect any diff --git a/services/inputflinger/tests/PropertyProvider_test.cpp b/services/inputflinger/tests/PropertyProvider_test.cpp index 42a6a9f4b9..8a40e78b89 100644 --- a/services/inputflinger/tests/PropertyProvider_test.cpp +++ b/services/inputflinger/tests/PropertyProvider_test.cpp @@ -18,6 +18,7 @@ #include <gmock/gmock.h> #include <gtest/gtest.h> +#include "TestConstants.h" #include "include/gestures.h" namespace android { @@ -283,4 +284,68 @@ TEST_F(PropertyProviderTest, Free) { EXPECT_FALSE(mProvider.hasProperty("Foo")); } +class PropertyProviderIdcLoadingTest : public testing::Test { +protected: + void SetUp() override { + int initialInt = 0; + GesturesPropBool initialBool = false; + double initialReal = 0.0; + gesturePropProvider.create_int_fn(&mProvider, "An Integer", &mIntData, 1, &initialInt); + gesturePropProvider.create_bool_fn(&mProvider, "A Boolean", &mBoolData, 1, &initialBool); + gesturePropProvider.create_real_fn(&mProvider, "A Real", &mRealData, 1, &initialReal); + } + + PropertyProvider mProvider; + + int mIntData; + GesturesPropBool mBoolData; + double mRealData; +}; + +TEST_F(PropertyProviderIdcLoadingTest, AllCorrect) { + PropertyMap idcProps; + idcProps.addProperty("gestureProp.An_Integer", "42"); + idcProps.addProperty("gestureProp.A_Boolean", "1"); + idcProps.addProperty("gestureProp.A_Real", "3.14159"); + + mProvider.loadPropertiesFromIdcFile(idcProps); + EXPECT_THAT(mProvider.getProperty("An Integer").getIntValues(), ElementsAre(42)); + EXPECT_THAT(mProvider.getProperty("A Boolean").getBoolValues(), ElementsAre(true)); + EXPECT_NEAR(mProvider.getProperty("A Real").getRealValues()[0], 3.14159, EPSILON); +} + +TEST_F(PropertyProviderIdcLoadingTest, InvalidPropsIgnored) { + int intArrayData[2]; + int initialInts[2] = {0, 1}; + gesturePropProvider.create_int_fn(&mProvider, "Two Integers", intArrayData, 2, initialInts); + + PropertyMap idcProps; + // Wrong type + idcProps.addProperty("gestureProp.An_Integer", "37.25"); + // Wrong size + idcProps.addProperty("gestureProp.Two_Integers", "42"); + // Doesn't exist + idcProps.addProperty("gestureProp.Some_Nonexistent_Property", "1"); + // A valid assignment that should still be applied despite the others being invalid + idcProps.addProperty("gestureProp.A_Real", "3.14159"); + + mProvider.loadPropertiesFromIdcFile(idcProps); + EXPECT_THAT(mProvider.getProperty("An Integer").getIntValues(), ElementsAre(0)); + EXPECT_THAT(mProvider.getProperty("Two Integers").getIntValues(), ElementsAre(0, 1)); + EXPECT_FALSE(mProvider.hasProperty("Some Nonexistent Property")); + EXPECT_NEAR(mProvider.getProperty("A Real").getRealValues()[0], 3.14159, EPSILON); +} + +TEST_F(PropertyProviderIdcLoadingTest, FunkyName) { + int data; + int initialData = 0; + gesturePropProvider.create_int_fn(&mProvider, " I lOvE sNAKes ", &data, 1, &initialData); + + PropertyMap idcProps; + idcProps.addProperty("gestureProp.__I_lOvE_sNAKes_", "42"); + + mProvider.loadPropertiesFromIdcFile(idcProps); + EXPECT_THAT(mProvider.getProperty(" I lOvE sNAKes ").getIntValues(), ElementsAre(42)); +} + } // namespace android diff --git a/services/inputflinger/tests/TestConstants.h b/services/inputflinger/tests/TestConstants.h index 27881f6f49..ad48b0fbe0 100644 --- a/services/inputflinger/tests/TestConstants.h +++ b/services/inputflinger/tests/TestConstants.h @@ -16,6 +16,10 @@ #pragma once +#include <chrono> + +#include <utils/Timers.h> + namespace android { using std::chrono_literals::operator""ms; diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index 3cdb3d5c76..064bbd246e 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -167,6 +167,7 @@ auto DisplayDevice::getFrontEndInfo() const -> frontend::DisplayInfo { .receivesInput = receivesInput(), .isSecure = isSecure(), .isPrimary = isPrimary(), + .isVirtual = isVirtual(), .rotationFlags = ui::Transform::toRotationFlags(mOrientation), .transformHint = getTransformHint()}; } diff --git a/services/surfaceflinger/FrontEnd/DisplayInfo.h b/services/surfaceflinger/FrontEnd/DisplayInfo.h index 6b9d7a2f5c..76b36fe0f2 100644 --- a/services/surfaceflinger/FrontEnd/DisplayInfo.h +++ b/services/surfaceflinger/FrontEnd/DisplayInfo.h @@ -30,6 +30,7 @@ struct DisplayInfo { bool isSecure; // TODO(b/238781169) can eliminate once sPrimaryDisplayRotationFlags is removed. bool isPrimary; + bool isVirtual; ui::Transform::RotationFlags rotationFlags; ui::Transform::RotationFlags transformHint; std::string getDebugString() const { diff --git a/services/surfaceflinger/FrontEnd/LayerCreationArgs.cpp b/services/surfaceflinger/FrontEnd/LayerCreationArgs.cpp index 5efa3944dd..ce21233424 100644 --- a/services/surfaceflinger/FrontEnd/LayerCreationArgs.cpp +++ b/services/surfaceflinger/FrontEnd/LayerCreationArgs.cpp @@ -69,7 +69,9 @@ LayerCreationArgs::LayerCreationArgs(std::optional<uint32_t> id, bool internalLa : LayerCreationArgs(nullptr, nullptr, /*name=*/"", /*flags=*/0, /*metadata=*/{}, id, internalLayer) {} -LayerCreationArgs::LayerCreationArgs(const LayerCreationArgs& args) - : LayerCreationArgs(args.flinger, args.client, args.name, args.flags, args.metadata) {} +LayerCreationArgs LayerCreationArgs::fromOtherArgs(const LayerCreationArgs& other) { + // returns a new instance of LayerCreationArgs with a unique id. + return LayerCreationArgs(other.flinger, other.client, other.name, other.flags, other.metadata); +} } // namespace android::surfaceflinger diff --git a/services/surfaceflinger/FrontEnd/LayerCreationArgs.h b/services/surfaceflinger/FrontEnd/LayerCreationArgs.h index 8341e1dfc5..011250c52d 100644 --- a/services/surfaceflinger/FrontEnd/LayerCreationArgs.h +++ b/services/surfaceflinger/FrontEnd/LayerCreationArgs.h @@ -37,13 +37,13 @@ namespace android::surfaceflinger { struct LayerCreationArgs { static std::atomic<uint32_t> sSequence; static uint32_t getInternalLayerId(uint32_t id); + static LayerCreationArgs fromOtherArgs(const LayerCreationArgs& other); LayerCreationArgs(android::SurfaceFlinger*, sp<android::Client>, std::string name, uint32_t flags, gui::LayerMetadata, std::optional<uint32_t> id = std::nullopt, bool internalLayer = false); LayerCreationArgs(std::optional<uint32_t> id, bool internalLayer = false); - - LayerCreationArgs(const LayerCreationArgs&); + LayerCreationArgs() = default; // for tracing android::SurfaceFlinger* flinger; sp<android::Client> client; diff --git a/services/surfaceflinger/FrontEnd/LayerHierarchy.h b/services/surfaceflinger/FrontEnd/LayerHierarchy.h index 3dd89badff..b25b731356 100644 --- a/services/surfaceflinger/FrontEnd/LayerHierarchy.h +++ b/services/surfaceflinger/FrontEnd/LayerHierarchy.h @@ -104,6 +104,16 @@ public: static const TraversalPath ROOT; }; + struct TraversalPathHash { + std::size_t operator()(const LayerHierarchy::TraversalPath& key) const { + uint32_t hashCode = key.id * 31; + if (key.mirrorRootId != UNASSIGNED_LAYER_ID) { + hashCode += key.mirrorRootId * 31; + } + return std::hash<size_t>{}(hashCode); + } + }; + // Helper class to add nodes to an existing traversal id and removes the // node when it goes out of scope. class ScopedAddToTraversalPath { diff --git a/services/surfaceflinger/FrontEnd/LayerLifecycleManager.cpp b/services/surfaceflinger/FrontEnd/LayerLifecycleManager.cpp index fe42422f6f..3706225228 100644 --- a/services/surfaceflinger/FrontEnd/LayerLifecycleManager.cpp +++ b/services/surfaceflinger/FrontEnd/LayerLifecycleManager.cpp @@ -71,12 +71,14 @@ void LayerLifecycleManager::addLayers(std::vector<std::unique_ptr<RequestedLayer } } -void LayerLifecycleManager::onHandlesDestroyed(const std::vector<uint32_t>& destroyedHandles) { +void LayerLifecycleManager::onHandlesDestroyed(const std::vector<uint32_t>& destroyedHandles, + bool ignoreUnknownHandles) { std::vector<uint32_t> layersToBeDestroyed; for (const auto& layerId : destroyedHandles) { auto it = mIdToLayer.find(layerId); if (it == mIdToLayer.end()) { - LOG_ALWAYS_FATAL("%s Layerid not found %d", __func__, layerId); + LOG_ALWAYS_FATAL_IF(!ignoreUnknownHandles, "%s Layerid not found %d", __func__, + layerId); continue; } RequestedLayerState& layer = it->second.owner; diff --git a/services/surfaceflinger/FrontEnd/LayerLifecycleManager.h b/services/surfaceflinger/FrontEnd/LayerLifecycleManager.h index 25d27ee373..3d9a74c843 100644 --- a/services/surfaceflinger/FrontEnd/LayerLifecycleManager.h +++ b/services/surfaceflinger/FrontEnd/LayerLifecycleManager.h @@ -40,7 +40,10 @@ public: // External state changes should be updated in the following order: void addLayers(std::vector<std::unique_ptr<RequestedLayerState>>); void applyTransactions(const std::vector<TransactionState>&); - void onHandlesDestroyed(const std::vector<uint32_t>&); + // Ignore unknown handles when iteroping with legacy front end. In the old world, we + // would create child layers which are not necessary with the new front end. This means + // we will get notified for handle changes that don't exist in the new front end. + void onHandlesDestroyed(const std::vector<uint32_t>&, bool ignoreUnknownHandles = false); // Detaches the layer from its relative parent to prevent a loop in the // layer hierarchy. This overrides the RequestedLayerState and leaves diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp index 8a450933f0..5e7c25946b 100644 --- a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp +++ b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp @@ -28,9 +28,14 @@ LayerSnapshot::LayerSnapshot(const RequestedLayerState& state, const LayerHierarchy::TraversalPath& path) : path(path) { static uint32_t sUniqueSequenceId = 0; - // Provide a unique id for clones otherwise keeping using the sequence id. - // The seq id can still be useful for debugging if its available. - uniqueSequence = (path.isClone()) ? sUniqueSequenceId++ : state.id; + // Provide a unique id for all snapshots. + // A front end layer can generate multiple snapshots if its mirrored. + // Additionally, if the layer is not reachable, we may choose to destroy + // and recreate the snapshot in which case the unique sequence id will + // change. The consumer shouldn't tie any lifetimes to this unique id but + // register a LayerLifecycleManager::ILifecycleListener or get a list of + // destroyed layers from LayerLifecycleManager. + uniqueSequence = sUniqueSequenceId++; sequence = static_cast<int32_t>(state.id); name = state.name; textureName = state.textureName; diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h index 3997a0ad83..7b1ff2710b 100644 --- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h +++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h @@ -68,6 +68,7 @@ public: void update(const Args&); std::vector<std::unique_ptr<LayerSnapshot>>& getSnapshots(); LayerSnapshot* getSnapshot(uint32_t layerId) const; + LayerSnapshot* getSnapshot(const LayerHierarchy::TraversalPath& id) const; typedef std::function<void(const LayerSnapshot& snapshot)> ConstVisitor; @@ -86,7 +87,6 @@ public: private: friend class LayerSnapshotTest; - LayerSnapshot* getSnapshot(const LayerHierarchy::TraversalPath& id) const; static LayerSnapshot getRootSnapshot(); // return true if we were able to successfully update the snapshots via @@ -120,16 +120,8 @@ private: void updateChildState(LayerSnapshot& snapshot, const LayerSnapshot& childSnapshot, const Args& args); - struct TraversalPathHash { - std::size_t operator()(const LayerHierarchy::TraversalPath& key) const { - uint32_t hashCode = key.id * 31; - if (key.mirrorRootId != UNASSIGNED_LAYER_ID) { - hashCode += key.mirrorRootId * 31; - } - return std::hash<size_t>{}(hashCode); - } - }; - std::unordered_map<LayerHierarchy::TraversalPath, LayerSnapshot*, TraversalPathHash> + std::unordered_map<LayerHierarchy::TraversalPath, LayerSnapshot*, + LayerHierarchy::TraversalPathHash> mIdToSnapshot; std::vector<std::unique_ptr<LayerSnapshot>> mSnapshots; LayerSnapshot mRootSnapshot; diff --git a/services/surfaceflinger/FrontEnd/Update.h b/services/surfaceflinger/FrontEnd/Update.h new file mode 100644 index 0000000000..e1449b6e1b --- /dev/null +++ b/services/surfaceflinger/FrontEnd/Update.h @@ -0,0 +1,52 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <gui/DisplayInfo.h> + +#include "FrontEnd/LayerCreationArgs.h" +#include "RequestedLayerState.h" +#include "TransactionState.h" + +namespace android { +struct LayerCreatedState { + LayerCreatedState(const wp<Layer>& layer, const wp<Layer>& parent, bool addToRoot) + : layer(layer), initialParent(parent), addToRoot(addToRoot) {} + wp<Layer> layer; + // Indicates the initial parent of the created layer, only used for creating layer in + // SurfaceFlinger. If nullptr, it may add the created layer into the current root layers. + wp<Layer> initialParent; + // Indicates whether the layer getting created should be added at root if there's no parent + // and has permission ACCESS_SURFACE_FLINGER. If set to false and no parent, the layer will + // be added offscreen. + bool addToRoot; +}; +} // namespace android + +namespace android::surfaceflinger::frontend { + +// Atomic set of changes affecting layer state. These changes are queued in binder threads and +// applied every vsync. +struct Update { + std::vector<TransactionState> transactions; + std::vector<LayerCreatedState> layerCreatedStates; + std::vector<std::unique_ptr<frontend::RequestedLayerState>> newLayers; + std::vector<LayerCreationArgs> layerCreationArgs; + std::vector<uint32_t> destroyedHandles; +}; + +} // namespace android::surfaceflinger::frontend diff --git a/services/surfaceflinger/LayerProtoHelper.cpp b/services/surfaceflinger/LayerProtoHelper.cpp index 55281fa962..b5ae1a7f5a 100644 --- a/services/surfaceflinger/LayerProtoHelper.cpp +++ b/services/surfaceflinger/LayerProtoHelper.cpp @@ -15,6 +15,8 @@ */ // TODO(b/129481165): remove the #pragma below and fix conversion issues +#include "FrontEnd/LayerCreationArgs.h" +#include "FrontEnd/LayerSnapshot.h" #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wconversion" #pragma clang diagnostic ignored "-Wextra" @@ -248,47 +250,88 @@ void LayerProtoHelper::readFromProto(const BlurRegion& proto, android::BlurRegio outRegion.bottom = proto.bottom(); } -void LayerProtoHelper::writeHierarchyToProto( - LayersProto& outLayersProto, const frontend::LayerHierarchy& root, - const frontend::LayerSnapshotBuilder& snapshotBuilder, - const std::unordered_map<uint32_t, sp<Layer>>& legacyLayers, uint32_t traceFlags) { - using Variant = frontend::LayerHierarchy::Variant; - frontend::LayerSnapshot defaultSnapshot; - - LayerProto* layerProto = outLayersProto.add_layers(); - const frontend::RequestedLayerState& layer = *root.getLayer(); - frontend::LayerSnapshot* snapshot = snapshotBuilder.getSnapshot(layer.id); +LayersProto LayerProtoFromSnapshotGenerator::generate(const frontend::LayerHierarchy& root) { + mLayersProto.clear_layers(); + std::unordered_set<uint64_t> stackIdsToSkip; + if ((mTraceFlags & LayerTracing::TRACE_VIRTUAL_DISPLAYS) == 0) { + for (const auto& [layerStack, displayInfo] : mDisplayInfos) { + if (displayInfo.isVirtual) { + stackIdsToSkip.insert(layerStack.id); + } + } + } - if (!snapshot) { - defaultSnapshot.uniqueSequence = layer.id; - snapshot = &defaultSnapshot; + frontend::LayerHierarchy::TraversalPath path = frontend::LayerHierarchy::TraversalPath::ROOT; + for (auto& [child, variant] : root.mChildren) { + if (variant != frontend::LayerHierarchy::Variant::Attached || + stackIdsToSkip.find(child->getLayer()->layerStack.id) != stackIdsToSkip.end()) { + continue; + } + frontend::LayerHierarchy::ScopedAddToTraversalPath addChildToPath(path, + child->getLayer()->id, + variant); + LayerProtoFromSnapshotGenerator::writeHierarchyToProto(*child, path); } - writeSnapshotToProto(layerProto, layer, *snapshot, traceFlags); - for (const auto& [child, variant] : root.mChildren) { - if (variant == Variant::Attached || variant == Variant::Detached) { - layerProto->add_children(child->getLayer()->id); - } else if (variant == Variant::Relative) { - layerProto->add_relatives(child->getLayer()->id); + + // fill in relative and parent info + for (int i = 0; i < mLayersProto.layers_size(); i++) { + auto layerProto = mLayersProto.mutable_layers()->Mutable(i); + auto it = mChildToRelativeParent.find(layerProto->id()); + if (it == mChildToRelativeParent.end()) { + layerProto->set_z_order_relative_of(-1); + } else { + layerProto->set_z_order_relative_of(it->second); + } + it = mChildToParent.find(layerProto->id()); + if (it == mChildToParent.end()) { + layerProto->set_parent(-1); + } else { + layerProto->set_parent(it->second); } } - auto parent = root.getParent(); - if (parent && parent->getLayer()) { - layerProto->set_parent(parent->getLayer()->id); + mDefaultSnapshots.clear(); + mChildToRelativeParent.clear(); + return std::move(mLayersProto); +} + +frontend::LayerSnapshot* LayerProtoFromSnapshotGenerator::getSnapshot( + frontend::LayerHierarchy::TraversalPath& path, const frontend::RequestedLayerState& layer) { + frontend::LayerSnapshot* snapshot = mSnapshotBuilder.getSnapshot(path); + if (snapshot) { + return snapshot; } else { - layerProto->set_parent(-1); + mDefaultSnapshots[path] = frontend::LayerSnapshot(layer, path); + return &mDefaultSnapshots[path]; } +} - auto relativeParent = root.getRelativeParent(); - if (relativeParent && relativeParent->getLayer()) { - layerProto->set_z_order_relative_of(relativeParent->getLayer()->id); - } else { - layerProto->set_z_order_relative_of(-1); +void LayerProtoFromSnapshotGenerator::writeHierarchyToProto( + const frontend::LayerHierarchy& root, frontend::LayerHierarchy::TraversalPath& path) { + using Variant = frontend::LayerHierarchy::Variant; + LayerProto* layerProto = mLayersProto.add_layers(); + const frontend::RequestedLayerState& layer = *root.getLayer(); + frontend::LayerSnapshot* snapshot = getSnapshot(path, layer); + LayerProtoHelper::writeSnapshotToProto(layerProto, layer, *snapshot, mTraceFlags); + + for (const auto& [child, variant] : root.mChildren) { + frontend::LayerHierarchy::ScopedAddToTraversalPath addChildToPath(path, + child->getLayer()->id, + variant); + frontend::LayerSnapshot* childSnapshot = getSnapshot(path, layer); + if (variant == Variant::Attached || variant == Variant::Detached || + variant == Variant::Mirror) { + mChildToParent[childSnapshot->uniqueSequence] = snapshot->uniqueSequence; + layerProto->add_children(childSnapshot->uniqueSequence); + } else if (variant == Variant::Relative) { + mChildToRelativeParent[childSnapshot->uniqueSequence] = snapshot->uniqueSequence; + layerProto->add_relatives(childSnapshot->uniqueSequence); + } } - if (traceFlags & LayerTracing::TRACE_COMPOSITION) { - auto it = legacyLayers.find(layer.id); - if (it != legacyLayers.end()) { + if (mTraceFlags & LayerTracing::TRACE_COMPOSITION) { + auto it = mLegacyLayers.find(layer.id); + if (it != mLegacyLayers.end()) { it->second->writeCompositionStateToProto(layerProto); } } @@ -298,7 +341,10 @@ void LayerProtoHelper::writeHierarchyToProto( if (variant == Variant::Detached) { continue; } - writeHierarchyToProto(outLayersProto, *child, snapshotBuilder, legacyLayers, traceFlags); + frontend::LayerHierarchy::ScopedAddToTraversalPath addChildToPath(path, + child->getLayer()->id, + variant); + writeHierarchyToProto(*child, path); } } @@ -345,6 +391,7 @@ void LayerProtoHelper::writeSnapshotToProto(LayerProto* layerInfo, layerInfo->set_shadow_radius(snapshot.shadowRadius); layerInfo->set_id(snapshot.uniqueSequence); + layerInfo->set_original_id(snapshot.sequence); layerInfo->set_name(requestedState.name); layerInfo->set_type("Layer"); @@ -394,6 +441,22 @@ void LayerProtoHelper::writeSnapshotToProto(LayerProto* layerInfo, [&]() { return layerInfo->mutable_destination_frame(); }); } +google::protobuf::RepeatedPtrField<DisplayProto> LayerProtoHelper::writeDisplayInfoToProto( + const display::DisplayMap<ui::LayerStack, frontend::DisplayInfo>& displayInfos) { + google::protobuf::RepeatedPtrField<DisplayProto> displays; + displays.Reserve(displayInfos.size()); + for (const auto& [layerStack, displayInfo] : displayInfos) { + auto displayProto = displays.Add(); + displayProto->set_id(displayInfo.info.displayId); + displayProto->set_layer_stack(layerStack.id); + displayProto->mutable_size()->set_w(displayInfo.info.logicalWidth); + displayProto->mutable_size()->set_h(displayInfo.info.logicalHeight); + writeTransformToProto(displayInfo.transform, displayProto->mutable_transform()); + displayProto->set_is_virtual(displayInfo.isVirtual); + } + return displays; +} + } // namespace surfaceflinger } // namespace android diff --git a/services/surfaceflinger/LayerProtoHelper.h b/services/surfaceflinger/LayerProtoHelper.h index de4bd01f1a..b84a49b27c 100644 --- a/services/surfaceflinger/LayerProtoHelper.h +++ b/services/surfaceflinger/LayerProtoHelper.h @@ -25,6 +25,9 @@ #include <ui/Rect.h> #include <ui/Region.h> #include <ui/Transform.h> +#include <cstdint> +#include "FrontEnd/LayerHierarchy.h" +#include "FrontEnd/LayerSnapshot.h" namespace android { namespace surfaceflinger { @@ -58,15 +61,44 @@ public: static void readFromProto(const ColorTransformProto& colorTransformProto, mat4& matrix); static void writeToProto(const android::BlurRegion region, BlurRegion*); static void readFromProto(const BlurRegion& proto, android::BlurRegion& outRegion); - static void writeHierarchyToProto(LayersProto& layersProto, - const frontend::LayerHierarchy& root, - const frontend::LayerSnapshotBuilder& snapshotBuilder, - const std::unordered_map<uint32_t, sp<Layer>>& mLegacyLayers, - uint32_t traceFlags); - static void writeSnapshotToProto(LayerProto* outProto, const frontend::RequestedLayerState& requestedState, const frontend::LayerSnapshot& snapshot, uint32_t traceFlags); + static google::protobuf::RepeatedPtrField<DisplayProto> writeDisplayInfoToProto( + const display::DisplayMap<ui::LayerStack, frontend::DisplayInfo>& displayInfos); +}; + +class LayerProtoFromSnapshotGenerator { +public: + LayerProtoFromSnapshotGenerator( + const frontend::LayerSnapshotBuilder& snapshotBuilder, + const display::DisplayMap<ui::LayerStack, frontend::DisplayInfo>& displayInfos, + const std::unordered_map<uint32_t, sp<Layer>>& legacyLayers, uint32_t traceFlags) + : mSnapshotBuilder(snapshotBuilder), + mLegacyLayers(legacyLayers), + mDisplayInfos(displayInfos), + mTraceFlags(traceFlags) {} + LayersProto generate(const frontend::LayerHierarchy& root); + +private: + void writeHierarchyToProto(const frontend::LayerHierarchy& root, + frontend::LayerHierarchy::TraversalPath& path); + frontend::LayerSnapshot* getSnapshot(frontend::LayerHierarchy::TraversalPath& path, + const frontend::RequestedLayerState& layer); + + const frontend::LayerSnapshotBuilder& mSnapshotBuilder; + const std::unordered_map<uint32_t, sp<Layer>>& mLegacyLayers; + const display::DisplayMap<ui::LayerStack, frontend::DisplayInfo>& mDisplayInfos; + uint32_t mTraceFlags; + LayersProto mLayersProto; + // winscope expects all the layers, so provide a snapshot even if it not currently drawing + std::unordered_map<frontend::LayerHierarchy::TraversalPath, frontend::LayerSnapshot, + frontend::LayerHierarchy::TraversalPathHash> + mDefaultSnapshots; + std::unordered_map<uint32_t /* child unique seq*/, uint32_t /* relative parent unique seq*/> + mChildToRelativeParent; + std::unordered_map<uint32_t /* child unique seq*/, uint32_t /* parent unique seq*/> + mChildToParent; }; } // namespace surfaceflinger diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 63b7f75c84..8ce479a213 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -105,6 +105,7 @@ #include <memory> #include <mutex> #include <optional> +#include <string> #include <type_traits> #include <unordered_map> #include <vector> @@ -130,6 +131,7 @@ #include "FrameTracer/FrameTracer.h" #include "FrontEnd/LayerCreationArgs.h" #include "FrontEnd/LayerHandle.h" +#include "FrontEnd/LayerLifecycleManager.h" #include "FrontEnd/LayerSnapshot.h" #include "HdrLayerInfoReporter.h" #include "Layer.h" @@ -2183,7 +2185,7 @@ void SurfaceFlinger::configure() FTL_FAKE_GUARD(kMainThreadContext) { } } -bool SurfaceFlinger::updateLayerSnapshotsLegacy(VsyncId vsyncId, LifecycleUpdate& update, +bool SurfaceFlinger::updateLayerSnapshotsLegacy(VsyncId vsyncId, frontend::Update& update, bool transactionsFlushed, bool& outTransactionsAreEmpty) { bool needsTraversal = false; @@ -2235,7 +2237,7 @@ void SurfaceFlinger::updateLayerHistory(const frontend::LayerSnapshot& snapshot) } } -bool SurfaceFlinger::updateLayerSnapshots(VsyncId vsyncId, LifecycleUpdate& update, +bool SurfaceFlinger::updateLayerSnapshots(VsyncId vsyncId, frontend::Update& update, bool transactionsFlushed, bool& outTransactionsAreEmpty) { using Changes = frontend::RequestedLayerState::Changes; ATRACE_NAME("updateLayerSnapshots"); @@ -2485,9 +2487,14 @@ bool SurfaceFlinger::commit(TimePoint frameTime, VsyncId vsyncId, TimePoint expe Fps::fromPeriodNsecs(vsyncPeriod.ns())); const bool flushTransactions = clearTransactionFlags(eTransactionFlushNeeded); - LifecycleUpdate updates; + frontend::Update updates; if (flushTransactions) { updates = flushLifecycleUpdates(); + if (mTransactionTracing) { + mTransactionTracing->addCommittedTransactions(vsyncId.value, frameTime.ns(), + updates, mFrontEndDisplayInfos, + mFrontEndDisplayInfosChanged); + } } bool transactionsAreEmpty; if (mLegacyFrontEndEnabled) { @@ -2529,7 +2536,7 @@ bool SurfaceFlinger::commit(TimePoint frameTime, VsyncId vsyncId, TimePoint expe if (mLayerTracingEnabled && !mLayerTracing.flagIsSet(LayerTracing::TRACE_COMPOSITION)) { // This will block and tracing should only be enabled for debugging. - mLayerTracing.notify(mVisibleRegionsDirty, frameTime.ns(), vsyncId.value); + addToLayerTracing(mVisibleRegionsDirty, frameTime.ns(), vsyncId.value); } mLastCommittedVsyncId = vsyncId; @@ -2700,7 +2707,7 @@ void SurfaceFlinger::composite(TimePoint frameTime, VsyncId vsyncId) mLayersWithQueuedFrames.clear(); if (mLayerTracingEnabled && mLayerTracing.flagIsSet(LayerTracing::TRACE_COMPOSITION)) { // This will block and should only be used for debugging. - mLayerTracing.notify(mVisibleRegionsDirty, frameTime.ns(), vsyncId.value); + addToLayerTracing(mVisibleRegionsDirty, frameTime.ns(), vsyncId.value); } if (mVisibleRegionsDirty) mHdrLayerInfoChanged = true; @@ -4112,6 +4119,9 @@ status_t SurfaceFlinger::addClientLayer(LayerCreationArgs& args, const sp<IBinde std::scoped_lock<std::mutex> lock(mCreatedLayersLock); mCreatedLayers.emplace_back(layer, parent, args.addToRoot); mNewLayers.emplace_back(std::make_unique<frontend::RequestedLayerState>(args)); + args.mirrorLayerHandle.clear(); + args.parentHandle.clear(); + mNewLayerArgs.emplace_back(std::move(args)); } setTransactionFlags(eTransactionNeeded); @@ -4297,10 +4307,6 @@ bool SurfaceFlinger::applyTransactionsLocked(std::vector<TransactionState>& tran transaction.listenerCallbacks, transaction.originPid, transaction.originUid, transaction.id); } - - if (mTransactionTracing) { - mTransactionTracing->addCommittedTransactions(transactions, vsyncId.value); - } return needsTraversal; } @@ -5142,7 +5148,7 @@ status_t SurfaceFlinger::mirrorLayer(const LayerCreationArgs& args, sp<Layer> mirrorLayer; sp<Layer> mirrorFrom; - LayerCreationArgs mirrorArgs(args); + LayerCreationArgs mirrorArgs = LayerCreationArgs::fromOtherArgs(args); { Mutex::Autolock _l(mStateLock); mirrorFrom = LayerHandle::getLayer(mirrorFromHandle); @@ -5162,11 +5168,6 @@ status_t SurfaceFlinger::mirrorLayer(const LayerCreationArgs& args, outResult.layerId = mirrorLayer->sequence; outResult.layerName = String16(mirrorLayer->getDebugName()); - if (mTransactionTracing) { - mTransactionTracing->onMirrorLayerAdded(outResult.handle->localBinder(), - mirrorLayer->sequence, args.name, - mirrorFrom->sequence); - } return addClientLayer(mirrorArgs, outResult.handle, mirrorLayer /* layer */, nullptr /* parent */, nullptr /* outTransformHint */); } @@ -5193,7 +5194,7 @@ status_t SurfaceFlinger::mirrorDisplay(DisplayId displayId, const LayerCreationA } layerStack = display->getLayerStack(); - LayerCreationArgs mirrorArgs(args); + LayerCreationArgs mirrorArgs = LayerCreationArgs::fromOtherArgs(args); mirrorArgs.flags |= ISurfaceComposerClient::eNoColorFill; mirrorArgs.addToRoot = true; mirrorArgs.layerStackToMirror = layerStack; @@ -5208,11 +5209,6 @@ status_t SurfaceFlinger::mirrorDisplay(DisplayId displayId, const LayerCreationA return result; } - if (mTransactionTracing) { - mTransactionTracing->onLayerAdded(outResult.handle->localBinder(), outResult.layerId, - args.name, args.flags, -1 /* parentId */); - } - if (mLegacyFrontEndEnabled) { std::scoped_lock<std::mutex> lock(mMirrorDisplayLock); mMirrorDisplays.emplace_back(layerStack, outResult.handle, args.client); @@ -5260,12 +5256,6 @@ status_t SurfaceFlinger::createLayer(LayerCreationArgs& args, gui::CreateSurface args.addToRoot = false; } - const int parentId = parent ? parent->getSequence() : -1; - if (mTransactionTracing) { - mTransactionTracing->onLayerAdded(outResult.handle->localBinder(), layer->sequence, - args.name, args.flags, parentId); - } - uint32_t outTransformHint; result = addClientLayer(args, outResult.handle, layer, parent, &outTransformHint); if (result != NO_ERROR) { @@ -5309,9 +5299,6 @@ void SurfaceFlinger::onHandleDestroyed(BBinder* handle, sp<Layer>& layer, uint32 markLayerPendingRemovalLocked(layer); mBufferCountTracker.remove(handle); layer.clear(); - if (mTransactionTracing) { - mTransactionTracing->onHandleRemoved(handle); - } setTransactionFlags(eTransactionFlushNeeded); } @@ -5562,7 +5549,8 @@ status_t SurfaceFlinger::doDump(int fd, const DumpArgs& args, bool asProto) { LayersTraceProto* layersTrace = traceFileProto.add_entry(); LayersProto layersProto = dumpProtoFromMainThread(); layersTrace->mutable_layers()->Swap(&layersProto); - dumpDisplayProto(*layersTrace); + auto displayProtos = dumpDisplayProto(); + layersTrace->mutable_displays()->Swap(&displayProtos); if (asProto) { result.append(traceFileProto.SerializeAsString()); @@ -5801,22 +5789,15 @@ LayersProto SurfaceFlinger::dumpDrawingStateProto(uint32_t traceFlags) const { return layersProto; } - const frontend::LayerHierarchy& root = mLayerHierarchyBuilder.getHierarchy(); - LayersProto layersProto; - for (auto& [child, variant] : root.mChildren) { - if (variant != frontend::LayerHierarchy::Variant::Attached || - stackIdsToSkip.find(child->getLayer()->layerStack.id) != stackIdsToSkip.end()) { - continue; - } - LayerProtoHelper::writeHierarchyToProto(layersProto, *child, mLayerSnapshotBuilder, - mLegacyLayers, traceFlags); - } - return layersProto; + return LayerProtoFromSnapshotGenerator(mLayerSnapshotBuilder, mFrontEndDisplayInfos, {}, + traceFlags) + .generate(mLayerHierarchyBuilder.getHierarchy()); } -void SurfaceFlinger::dumpDisplayProto(LayersTraceProto& layersTraceProto) const { +google::protobuf::RepeatedPtrField<DisplayProto> SurfaceFlinger::dumpDisplayProto() const { + google::protobuf::RepeatedPtrField<DisplayProto> displays; for (const auto& [_, display] : FTL_FAKE_GUARD(mStateLock, mDisplays)) { - DisplayProto* displayProto = layersTraceProto.add_displays(); + DisplayProto* displayProto = displays.Add(); displayProto->set_id(display->getId().value); displayProto->set_name(display->getDisplayName()); displayProto->set_layer_stack(display->getLayerStack().id); @@ -5829,6 +5810,7 @@ void SurfaceFlinger::dumpDisplayProto(LayersTraceProto& layersTraceProto) const displayProto->mutable_transform()); displayProto->set_is_virtual(display->isVirtual()); } + return displays; } void SurfaceFlinger::dumpHwc(std::string& result) const { @@ -6359,9 +6341,10 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r int64_t startingTime = (fixedStartingTime) ? fixedStartingTime : systemTime(); mScheduler - ->schedule([&]() FTL_FAKE_GUARD(mStateLock) { - mLayerTracing.notify(true /* visibleRegionDirty */, - startingTime, mLastCommittedVsyncId.value); + ->schedule([&]() FTL_FAKE_GUARD(mStateLock) FTL_FAKE_GUARD( + kMainThreadContext) { + addToLayerTracing(true /* visibleRegionDirty */, startingTime, + mLastCommittedVsyncId.value); }) .wait(); } @@ -7724,10 +7707,6 @@ void SurfaceFlinger::handleLayerCreatedLocked(const LayerCreatedState& state, Vs if (hintDisplay) { layer->updateTransformHint(hintDisplay->getTransformHint()); } - - if (mTransactionTracing) { - mTransactionTracing->onLayerAddedToDrawingState(layer->getSequence(), vsyncId.value); - } } void SurfaceFlinger::sample() { @@ -7868,10 +7847,6 @@ bool SurfaceFlinger::commitMirrorDisplays(VsyncId vsyncId) { sp<Layer> childMirror; createEffectLayer(mirrorArgs, &unused, &childMirror); childMirror->setClonedChild(layer->createClone()); - if (mTransactionTracing) { - mTransactionTracing->onLayerAddedToDrawingState(childMirror->getSequence(), - vsyncId.value); - } childMirror->reparent(mirrorDisplay.rootHandle); } } @@ -8056,8 +8031,8 @@ SurfaceFlinger::getLayerSnapshotsForScreenshots(uint32_t rootLayerId, uint32_t u }; } -SurfaceFlinger::LifecycleUpdate SurfaceFlinger::flushLifecycleUpdates() { - LifecycleUpdate update; +frontend::Update SurfaceFlinger::flushLifecycleUpdates() { + frontend::Update update; ATRACE_NAME("TransactionHandler:flushTransactions"); // Locking: // 1. to prevent onHandleDestroyed from being called while the state lock is held, @@ -8074,12 +8049,28 @@ SurfaceFlinger::LifecycleUpdate SurfaceFlinger::flushLifecycleUpdates() { mCreatedLayers.clear(); update.newLayers = std::move(mNewLayers); mNewLayers.clear(); + update.layerCreationArgs = std::move(mNewLayerArgs); + mNewLayerArgs.clear(); update.destroyedHandles = std::move(mDestroyedHandles); mDestroyedHandles.clear(); } return update; } +void SurfaceFlinger::addToLayerTracing(bool visibleRegionDirty, int64_t time, int64_t vsyncId) { + const uint32_t tracingFlags = mLayerTracing.getFlags(); + LayersProto layers(dumpDrawingStateProto(tracingFlags)); + if (tracingFlags & LayerTracing::TRACE_EXTRA) { + dumpOffscreenLayersProto(layers); + } + std::string hwcDump; + if (tracingFlags & LayerTracing::TRACE_HWC) { + dumpHwc(hwcDump); + } + auto displays = dumpDisplayProto(); + mLayerTracing.notify(visibleRegionDirty, time, vsyncId, &layers, std::move(hwcDump), &displays); +} + // gui::ISurfaceComposer binder::Status SurfaceComposerAIDL::bootFinished() { diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 63d54bc24d..42d5db7cc9 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -455,26 +455,6 @@ private: FINISHED, }; - struct LayerCreatedState { - LayerCreatedState(const wp<Layer>& layer, const wp<Layer>& parent, bool addToRoot) - : layer(layer), initialParent(parent), addToRoot(addToRoot) {} - wp<Layer> layer; - // Indicates the initial parent of the created layer, only used for creating layer in - // SurfaceFlinger. If nullptr, it may add the created layer into the current root layers. - wp<Layer> initialParent; - // Indicates whether the layer getting created should be added at root if there's no parent - // and has permission ACCESS_SURFACE_FLINGER. If set to false and no parent, the layer will - // be added offscreen. - bool addToRoot; - }; - - struct LifecycleUpdate { - std::vector<TransactionState> transactions; - std::vector<LayerCreatedState> layerCreatedStates; - std::vector<std::unique_ptr<frontend::RequestedLayerState>> newLayers; - std::vector<uint32_t> destroyedHandles; - }; - template <typename F, std::enable_if_t<!std::is_member_function_pointer_v<F>>* = nullptr> static Dumper dumper(F&& dump) { using namespace std::placeholders; @@ -721,13 +701,13 @@ private: int64_t vsyncId); void moveSnapshotsFromCompositionArgs(compositionengine::CompositionRefreshArgs& refreshArgs, std::vector<std::pair<Layer*, LayerFE*>>& layers); - bool updateLayerSnapshotsLegacy(VsyncId vsyncId, LifecycleUpdate& update, + bool updateLayerSnapshotsLegacy(VsyncId vsyncId, frontend::Update& update, bool transactionsFlushed, bool& out) REQUIRES(kMainThreadContext); - bool updateLayerSnapshots(VsyncId vsyncId, LifecycleUpdate& update, bool transactionsFlushed, + bool updateLayerSnapshots(VsyncId vsyncId, frontend::Update& update, bool transactionsFlushed, bool& out) REQUIRES(kMainThreadContext); void updateLayerHistory(const frontend::LayerSnapshot& snapshot); - LifecycleUpdate flushLifecycleUpdates() REQUIRES(kMainThreadContext); + frontend::Update flushLifecycleUpdates() REQUIRES(kMainThreadContext); void updateInputFlinger(); void persistDisplayBrightness(bool needsComposite) REQUIRES(kMainThreadContext); @@ -1086,7 +1066,9 @@ private: LayersProto dumpDrawingStateProto(uint32_t traceFlags) const; void dumpOffscreenLayersProto(LayersProto& layersProto, uint32_t traceFlags = LayerTracing::TRACE_ALL) const; - void dumpDisplayProto(LayersTraceProto& layersTraceProto) const; + google::protobuf::RepeatedPtrField<DisplayProto> dumpDisplayProto() const; + void addToLayerTracing(bool visibleRegionDirty, int64_t time, int64_t vsyncId) + REQUIRES(kMainThreadContext); // Dumps state from HW Composer void dumpHwc(std::string& result) const; @@ -1240,7 +1222,7 @@ private: bool mLayerCachingEnabled = false; bool mBackpressureGpuComposition = false; - LayerTracing mLayerTracing{*this}; + LayerTracing mLayerTracing; bool mLayerTracingEnabled = false; std::optional<TransactionTracing> mTransactionTracing; @@ -1422,6 +1404,7 @@ private: std::vector<uint32_t> mDestroyedHandles; std::vector<std::unique_ptr<frontend::RequestedLayerState>> mNewLayers; + std::vector<LayerCreationArgs> mNewLayerArgs; // These classes do not store any client state but help with managing transaction callbacks // and stats. std::unordered_map<uint32_t, sp<Layer>> mLegacyLayers; diff --git a/services/surfaceflinger/Tracing/LayerTracing.cpp b/services/surfaceflinger/Tracing/LayerTracing.cpp index 566d55353f..2918f7cd37 100644 --- a/services/surfaceflinger/Tracing/LayerTracing.cpp +++ b/services/surfaceflinger/Tracing/LayerTracing.cpp @@ -29,9 +29,8 @@ namespace android { -LayerTracing::LayerTracing(SurfaceFlinger& flinger) : mFlinger(flinger) { - mBuffer = std::make_unique<RingBuffer<LayersTraceFileProto, LayersTraceProto>>(); -} +LayerTracing::LayerTracing() + : mBuffer(std::make_unique<RingBuffer<LayersTraceFileProto, LayersTraceProto>>()) {} LayerTracing::~LayerTracing() = default; @@ -84,8 +83,11 @@ void LayerTracing::setBufferSize(size_t bufferSizeInBytes) { bool LayerTracing::flagIsSet(uint32_t flags) const { return (mFlags & flags) == flags; } +uint32_t LayerTracing::getFlags() const { + return mFlags; +} -LayersTraceFileProto LayerTracing::createTraceFileProto() const { +LayersTraceFileProto LayerTracing::createTraceFileProto() { LayersTraceFileProto fileProto; fileProto.set_magic_number(uint64_t(LayersTraceFileProto_MagicNumber_MAGIC_NUMBER_H) << 32 | LayersTraceFileProto_MagicNumber_MAGIC_NUMBER_L); @@ -101,7 +103,9 @@ void LayerTracing::dump(std::string& result) const { mBuffer->dump(result); } -void LayerTracing::notify(bool visibleRegionDirty, int64_t time, int64_t vsyncId) { +void LayerTracing::notify(bool visibleRegionDirty, int64_t time, int64_t vsyncId, + LayersProto* layers, std::string hwcDump, + google::protobuf::RepeatedPtrField<DisplayProto>* displays) { std::scoped_lock lock(mTraceLock); if (!mEnabled) { return; @@ -116,22 +120,15 @@ void LayerTracing::notify(bool visibleRegionDirty, int64_t time, int64_t vsyncId entry.set_elapsed_realtime_nanos(time); const char* where = visibleRegionDirty ? "visibleRegionsDirty" : "bufferLatched"; entry.set_where(where); - LayersProto layers(mFlinger.dumpDrawingStateProto(mFlags)); - - if (flagIsSet(LayerTracing::TRACE_EXTRA)) { - mFlinger.dumpOffscreenLayersProto(layers); - } - entry.mutable_layers()->Swap(&layers); + entry.mutable_layers()->Swap(layers); if (flagIsSet(LayerTracing::TRACE_HWC)) { - std::string hwcDump; - mFlinger.dumpHwc(hwcDump); entry.set_hwc_blob(hwcDump); } if (!flagIsSet(LayerTracing::TRACE_COMPOSITION)) { entry.set_excludes_composition_state(true); } - mFlinger.dumpDisplayProto(entry); + entry.mutable_displays()->Swap(displays); entry.set_vsync_id(vsyncId); mBuffer->emplace(std::move(entry)); } diff --git a/services/surfaceflinger/Tracing/LayerTracing.h b/services/surfaceflinger/Tracing/LayerTracing.h index b32001cc63..11bb9f45df 100644 --- a/services/surfaceflinger/Tracing/LayerTracing.h +++ b/services/surfaceflinger/Tracing/LayerTracing.h @@ -40,14 +40,15 @@ class SurfaceFlinger; */ class LayerTracing { public: - LayerTracing(SurfaceFlinger& flinger); + LayerTracing(); ~LayerTracing(); bool enable(); bool disable(std::string filename = FILE_NAME); bool isEnabled() const; status_t writeToFile(); - LayersTraceFileProto createTraceFileProto() const; - void notify(bool visibleRegionDirty, int64_t time, int64_t vsyncId); + static LayersTraceFileProto createTraceFileProto(); + void notify(bool visibleRegionDirty, int64_t time, int64_t vsyncId, LayersProto* layers, + std::string hwcDump, google::protobuf::RepeatedPtrField<DisplayProto>* displays); enum : uint32_t { TRACE_INPUT = 1 << 1, @@ -60,13 +61,12 @@ public: }; void setTraceFlags(uint32_t flags); bool flagIsSet(uint32_t flags) const; + uint32_t getFlags() const; void setBufferSize(size_t bufferSizeInBytes); void dump(std::string&) const; private: static constexpr auto FILE_NAME = "/data/misc/wmtrace/layers_trace.winscope"; - - SurfaceFlinger& mFlinger; uint32_t mFlags = TRACE_INPUT; mutable std::mutex mTraceLock; bool mEnabled GUARDED_BY(mTraceLock) = false; diff --git a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp index ba08ceebc7..8fd653880c 100644 --- a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp +++ b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp @@ -15,15 +15,43 @@ */ #include <gui/SurfaceComposerClient.h> -#include <renderengine/mock/FakeExternalTexture.h> #include <ui/Fence.h> #include <ui/Rect.h> +#include "FrontEnd/LayerCreationArgs.h" #include "LayerProtoHelper.h" #include "TransactionProtoParser.h" +#include "TransactionState.h" +#include "gui/LayerState.h" namespace android::surfaceflinger { +class FakeExternalTexture : public renderengine::ExternalTexture { + const sp<GraphicBuffer> mEmptyBuffer = + sp<GraphicBuffer>::make(1u, 1u, PIXEL_FORMAT_RGBA_8888, + GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_SW_READ_OFTEN); + uint32_t mWidth; + uint32_t mHeight; + uint64_t mId; + PixelFormat mPixelFormat; + uint64_t mUsage; + +public: + FakeExternalTexture(uint32_t width, uint32_t height, uint64_t id, PixelFormat pixelFormat, + uint64_t usage) + : mWidth(width), mHeight(height), mId(id), mPixelFormat(pixelFormat), mUsage(usage) {} + const sp<GraphicBuffer>& getBuffer() const { return mEmptyBuffer; } + bool hasSameBuffer(const renderengine::ExternalTexture& other) const override { + return getId() == other.getId(); + } + uint32_t getWidth() const override { return mWidth; } + uint32_t getHeight() const override { return mHeight; } + uint64_t getId() const override { return mId; } + PixelFormat getPixelFormat() const override { return mPixelFormat; } + uint64_t getUsage() const override { return mUsage; } + ~FakeExternalTexture() = default; +}; + proto::TransactionState TransactionProtoParser::toProto(const TransactionState& t) { proto::TransactionState proto; proto.set_pid(t.originPid); @@ -35,7 +63,7 @@ proto::TransactionState TransactionProtoParser::toProto(const TransactionState& proto.mutable_layer_changes()->Reserve(static_cast<int32_t>(t.states.size())); for (auto& layerState : t.states) { - proto.mutable_layer_changes()->Add(std::move(toProto(layerState.state))); + proto.mutable_layer_changes()->Add(std::move(toProto(layerState))); } proto.mutable_display_changes()->Reserve(static_cast<int32_t>(t.displays.size())); @@ -46,40 +74,22 @@ proto::TransactionState TransactionProtoParser::toProto(const TransactionState& } proto::TransactionState TransactionProtoParser::toProto( - const std::map<int32_t /* layerId */, TracingLayerState>& states) { + const std::map<uint32_t /* layerId */, TracingLayerState>& states) { proto::TransactionState proto; proto.mutable_layer_changes()->Reserve(static_cast<int32_t>(states.size())); for (auto& [layerId, state] : states) { proto::LayerState layerProto = toProto(state); - if (layerProto.has_buffer_data()) { - proto::LayerState_BufferData* bufferProto = layerProto.mutable_buffer_data(); - bufferProto->set_buffer_id(state.bufferId); - bufferProto->set_width(state.bufferWidth); - bufferProto->set_height(state.bufferHeight); - bufferProto->set_pixel_format( - static_cast<proto::LayerState_BufferData_PixelFormat>(state.pixelFormat)); - bufferProto->set_usage(state.bufferUsage); - } layerProto.set_has_sideband_stream(state.hasSidebandStream); - layerProto.set_layer_id(state.layerId); - layerProto.set_parent_id(state.parentId); - layerProto.set_relative_parent_id(state.relativeParentId); - if (layerProto.has_window_info_handle()) { - layerProto.mutable_window_info_handle()->set_crop_layer_id(state.inputCropId); - } proto.mutable_layer_changes()->Add(std::move(layerProto)); } return proto; } -proto::LayerState TransactionProtoParser::toProto(const layer_state_t& layer) { +proto::LayerState TransactionProtoParser::toProto( + const ResolvedComposerState& resolvedComposerState) { proto::LayerState proto; - if (layer.surface) { - proto.set_layer_id(mMapper->getLayerId(layer.surface)); - } else { - proto.set_layer_id(layer.layerId); - } - + auto& layer = resolvedComposerState.state; + proto.set_layer_id(resolvedComposerState.layerId); proto.set_what(layer.what); if (layer.what & layer_state_t::ePositionChanged) { @@ -135,27 +145,13 @@ proto::LayerState TransactionProtoParser::toProto(const layer_state_t& layer) { } if (layer.what & layer_state_t::eBufferChanged) { proto::LayerState_BufferData* bufferProto = proto.mutable_buffer_data(); - if (layer.bufferData->hasBuffer()) { - bufferProto->set_buffer_id(layer.bufferData->getId()); - bufferProto->set_width(layer.bufferData->getWidth()); - bufferProto->set_height(layer.bufferData->getHeight()); + if (resolvedComposerState.externalTexture) { + bufferProto->set_buffer_id(resolvedComposerState.externalTexture->getId()); + bufferProto->set_width(resolvedComposerState.externalTexture->getWidth()); + bufferProto->set_height(resolvedComposerState.externalTexture->getHeight()); bufferProto->set_pixel_format(static_cast<proto::LayerState_BufferData_PixelFormat>( - layer.bufferData->getPixelFormat())); - bufferProto->set_usage(layer.bufferData->getUsage()); - } else { - uint64_t bufferId; - uint32_t width; - uint32_t height; - int32_t pixelFormat; - uint64_t usage; - mMapper->getGraphicBufferPropertiesFromCache(layer.bufferData->cachedBuffer, &bufferId, - &width, &height, &pixelFormat, &usage); - bufferProto->set_buffer_id(bufferId); - bufferProto->set_width(width); - bufferProto->set_height(height); - bufferProto->set_pixel_format( - static_cast<proto::LayerState_BufferData_PixelFormat>(pixelFormat)); - bufferProto->set_usage(usage); + resolvedComposerState.externalTexture->getPixelFormat())); + bufferProto->set_usage(resolvedComposerState.externalTexture->getUsage()); } bufferProto->set_frame_number(layer.bufferData->frameNumber); bufferProto->set_flags(layer.bufferData->flags.get()); @@ -179,16 +175,10 @@ proto::LayerState TransactionProtoParser::toProto(const layer_state_t& layer) { } if (layer.what & layer_state_t::eReparent) { - int64_t layerId = layer.parentSurfaceControlForChild - ? mMapper->getLayerId(layer.parentSurfaceControlForChild->getHandle()) - : -1; - proto.set_parent_id(layerId); + proto.set_parent_id(resolvedComposerState.parentId); } if (layer.what & layer_state_t::eRelativeLayerChanged) { - int64_t layerId = layer.relativeLayerSurfaceControl - ? mMapper->getLayerId(layer.relativeLayerSurfaceControl->getHandle()) - : -1; - proto.set_relative_parent_id(layerId); + proto.set_relative_parent_id(resolvedComposerState.relativeParentId); proto.set_z(layer.z); } @@ -207,7 +197,7 @@ proto::LayerState TransactionProtoParser::toProto(const layer_state_t& layer) { windowInfoProto->set_has_wallpaper(inputInfo->inputConfig.test( gui::WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER)); windowInfoProto->set_global_scale_factor(inputInfo->globalScaleFactor); - proto::LayerState_Transform* transformProto = windowInfoProto->mutable_transform(); + proto::Transform* transformProto = windowInfoProto->mutable_transform(); transformProto->set_dsdx(inputInfo->transform.dsdx()); transformProto->set_dtdx(inputInfo->transform.dtdx()); transformProto->set_dtdy(inputInfo->transform.dtdy()); @@ -216,8 +206,7 @@ proto::LayerState TransactionProtoParser::toProto(const layer_state_t& layer) { transformProto->set_ty(inputInfo->transform.ty()); windowInfoProto->set_replace_touchable_region_with_crop( inputInfo->replaceTouchableRegionWithCrop); - windowInfoProto->set_crop_layer_id( - mMapper->getLayerId(inputInfo->touchableRegionCropHandle.promote())); + windowInfoProto->set_crop_layer_id(resolvedComposerState.touchCropId); } } if (layer.what & layer_state_t::eBackgroundColorChanged) { @@ -289,13 +278,15 @@ proto::DisplayState TransactionProtoParser::toProto(const DisplayState& display) return proto; } -proto::LayerCreationArgs TransactionProtoParser::toProto(const TracingLayerCreationArgs& args) { +proto::LayerCreationArgs TransactionProtoParser::toProto(const LayerCreationArgs& args) { proto::LayerCreationArgs proto; - proto.set_layer_id(args.layerId); + proto.set_layer_id(args.sequence); proto.set_name(args.name); proto.set_flags(args.flags); proto.set_parent_id(args.parentId); - proto.set_mirror_from_id(args.mirrorFromId); + proto.set_mirror_from_id(args.layerIdToMirror); + proto.set_add_to_root(args.addToRoot); + proto.set_layer_stack_to_mirror(args.layerStackToMirror.id); return proto; } @@ -313,15 +304,7 @@ TransactionState TransactionProtoParser::fromProto(const proto::TransactionState for (int i = 0; i < layerCount; i++) { ResolvedComposerState s; s.state.what = 0; - fromProto(proto.layer_changes(i), s.state); - if (s.state.bufferData) { - s.externalTexture = std::make_shared< - renderengine::mock::FakeExternalTexture>(s.state.bufferData->getWidth(), - s.state.bufferData->getHeight(), - s.state.bufferData->getId(), - s.state.bufferData->getPixelFormat(), - s.state.bufferData->getUsage()); - } + fromProto(proto.layer_changes(i), s); t.states.emplace_back(s); } @@ -334,46 +317,47 @@ TransactionState TransactionProtoParser::fromProto(const proto::TransactionState } void TransactionProtoParser::fromProto(const proto::LayerCreationArgs& proto, - TracingLayerCreationArgs& outArgs) { - outArgs.layerId = proto.layer_id(); + LayerCreationArgs& outArgs) { + outArgs.sequence = proto.layer_id(); + outArgs.name = proto.name(); outArgs.flags = proto.flags(); outArgs.parentId = proto.parent_id(); - outArgs.mirrorFromId = proto.mirror_from_id(); + outArgs.layerIdToMirror = proto.mirror_from_id(); + outArgs.addToRoot = proto.add_to_root(); + outArgs.layerStackToMirror.id = proto.layer_stack_to_mirror(); } void TransactionProtoParser::mergeFromProto(const proto::LayerState& proto, TracingLayerState& outState) { - layer_state_t state; - fromProto(proto, state); - outState.merge(state); + ResolvedComposerState resolvedComposerState; + fromProto(proto, resolvedComposerState); + layer_state_t& state = resolvedComposerState.state; + outState.state.merge(state); + outState.layerId = resolvedComposerState.layerId; if (state.what & layer_state_t::eReparent) { - outState.parentId = static_cast<int32_t>(proto.parent_id()); + outState.parentId = resolvedComposerState.parentId; } if (state.what & layer_state_t::eRelativeLayerChanged) { - outState.relativeParentId = static_cast<int32_t>(proto.relative_parent_id()); + outState.relativeParentId = resolvedComposerState.relativeParentId; } if (state.what & layer_state_t::eInputInfoChanged) { - outState.inputCropId = static_cast<int32_t>(proto.window_info_handle().crop_layer_id()); + outState.touchCropId = resolvedComposerState.touchCropId; } if (state.what & layer_state_t::eBufferChanged) { - const proto::LayerState_BufferData& bufferProto = proto.buffer_data(); - outState.bufferId = bufferProto.buffer_id(); - outState.bufferWidth = bufferProto.width(); - outState.bufferHeight = bufferProto.height(); - outState.pixelFormat = bufferProto.pixel_format(); - outState.bufferUsage = bufferProto.usage(); + outState.externalTexture = resolvedComposerState.externalTexture; } if (state.what & layer_state_t::eSidebandStreamChanged) { outState.hasSidebandStream = proto.has_sideband_stream(); } } -void TransactionProtoParser::fromProto(const proto::LayerState& proto, layer_state_t& layer) { - layer.layerId = (int32_t)proto.layer_id(); +void TransactionProtoParser::fromProto(const proto::LayerState& proto, + ResolvedComposerState& resolvedComposerState) { + auto& layer = resolvedComposerState.state; + resolvedComposerState.layerId = proto.layer_id(); layer.what |= proto.what(); - layer.surface = mMapper->getLayerHandle(layer.layerId); if (proto.what() & layer_state_t::ePositionChanged) { layer.x = proto.x(); @@ -428,9 +412,15 @@ void TransactionProtoParser::fromProto(const proto::LayerState& proto, layer_sta if (proto.what() & layer_state_t::eBufferChanged) { const proto::LayerState_BufferData& bufferProto = proto.buffer_data(); layer.bufferData = - std::move(mMapper->getGraphicData(bufferProto.buffer_id(), bufferProto.width(), - bufferProto.height(), bufferProto.pixel_format(), - bufferProto.usage())); + std::make_shared<fake::BufferData>(bufferProto.buffer_id(), bufferProto.width(), + bufferProto.height(), bufferProto.pixel_format(), + bufferProto.usage()); + resolvedComposerState.externalTexture = + std::make_shared<FakeExternalTexture>(layer.bufferData->getWidth(), + layer.bufferData->getHeight(), + layer.bufferData->getId(), + layer.bufferData->getPixelFormat(), + layer.bufferData->getUsage()); layer.bufferData->frameNumber = bufferProto.frame_number(); layer.bufferData->flags = ftl::Flags<BufferData::BufferDataChange>(bufferProto.flags()); layer.bufferData->cachedBuffer.id = bufferProto.cached_buffer_id(); @@ -454,26 +444,10 @@ void TransactionProtoParser::fromProto(const proto::LayerState& proto, layer_sta } if (proto.what() & layer_state_t::eReparent) { - int64_t layerId = proto.parent_id(); - if (layerId == -1) { - layer.parentSurfaceControlForChild = nullptr; - } else { - layer.parentSurfaceControlForChild = - sp<SurfaceControl>::make(SurfaceComposerClient::getDefault(), - mMapper->getLayerHandle(static_cast<int32_t>(layerId)), - static_cast<int32_t>(layerId), ""); - } + resolvedComposerState.parentId = proto.parent_id(); } if (proto.what() & layer_state_t::eRelativeLayerChanged) { - int64_t layerId = proto.relative_parent_id(); - if (layerId == -1) { - layer.relativeLayerSurfaceControl = nullptr; - } else { - layer.relativeLayerSurfaceControl = - sp<SurfaceControl>::make(SurfaceComposerClient::getDefault(), - mMapper->getLayerHandle(static_cast<int32_t>(layerId)), - static_cast<int32_t>(layerId), ""); - } + resolvedComposerState.relativeParentId = proto.relative_parent_id(); layer.z = proto.z(); } @@ -493,19 +467,13 @@ void TransactionProtoParser::fromProto(const proto::LayerState& proto, layer_sta inputInfo.setInputConfig(gui::WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER, windowInfoProto.has_wallpaper()); inputInfo.globalScaleFactor = windowInfoProto.global_scale_factor(); - const proto::LayerState_Transform& transformProto = windowInfoProto.transform(); + const proto::Transform& transformProto = windowInfoProto.transform(); inputInfo.transform.set(transformProto.dsdx(), transformProto.dtdx(), transformProto.dtdy(), transformProto.dsdy()); inputInfo.transform.set(transformProto.tx(), transformProto.ty()); inputInfo.replaceTouchableRegionWithCrop = windowInfoProto.replace_touchable_region_with_crop(); - int64_t layerId = windowInfoProto.crop_layer_id(); - if (layerId != -1) { - inputInfo.touchableRegionCropHandle = - mMapper->getLayerHandle(static_cast<int32_t>(layerId)); - } else { - inputInfo.touchableRegionCropHandle = wp<IBinder>(); - } + resolvedComposerState.touchCropId = windowInfoProto.crop_layer_id(); layer.windowInfoHandle = sp<gui::WindowInfoHandle>::make(inputInfo); } @@ -577,4 +545,62 @@ DisplayState TransactionProtoParser::fromProto(const proto::DisplayState& proto) return display; } +void asProto(proto::Transform* proto, const ui::Transform& transform) { + proto->set_dsdx(transform.dsdx()); + proto->set_dtdx(transform.dtdx()); + proto->set_dtdy(transform.dtdy()); + proto->set_dsdy(transform.dsdy()); + proto->set_tx(transform.tx()); + proto->set_ty(transform.ty()); +} + +proto::DisplayInfo TransactionProtoParser::toProto(const frontend::DisplayInfo& displayInfo, + uint32_t layerStack) { + proto::DisplayInfo proto; + proto.set_layer_stack(layerStack); + proto.set_display_id(displayInfo.info.displayId); + proto.set_logical_width(displayInfo.info.logicalWidth); + proto.set_logical_height(displayInfo.info.logicalHeight); + asProto(proto.mutable_transform_inverse(), displayInfo.info.transform); + asProto(proto.mutable_transform(), displayInfo.transform); + proto.set_receives_input(displayInfo.receivesInput); + proto.set_is_secure(displayInfo.isSecure); + proto.set_is_primary(displayInfo.isPrimary); + proto.set_is_virtual(displayInfo.isVirtual); + proto.set_rotation_flags((int)displayInfo.rotationFlags); + proto.set_transform_hint((int)displayInfo.transformHint); + return proto; +} + +void fromProto2(ui::Transform& outTransform, const proto::Transform& proto) { + outTransform.set(proto.dsdx(), proto.dtdx(), proto.dtdy(), proto.dsdy()); + outTransform.set(proto.tx(), proto.ty()); +} + +frontend::DisplayInfo TransactionProtoParser::fromProto(const proto::DisplayInfo& proto) { + frontend::DisplayInfo displayInfo; + displayInfo.info.displayId = proto.display_id(); + displayInfo.info.logicalWidth = proto.logical_width(); + displayInfo.info.logicalHeight = proto.logical_height(); + fromProto2(displayInfo.info.transform, proto.transform_inverse()); + fromProto2(displayInfo.transform, proto.transform()); + displayInfo.receivesInput = proto.receives_input(); + displayInfo.isSecure = proto.is_secure(); + displayInfo.isPrimary = proto.is_primary(); + displayInfo.isPrimary = proto.is_virtual(); + displayInfo.rotationFlags = (ui::Transform::RotationFlags)proto.rotation_flags(); + displayInfo.transformHint = (ui::Transform::RotationFlags)proto.transform_hint(); + return displayInfo; +} + +void TransactionProtoParser::fromProto( + const google::protobuf::RepeatedPtrField<proto::DisplayInfo>& proto, + display::DisplayMap<ui::LayerStack, frontend::DisplayInfo> outDisplayInfos) { + outDisplayInfos.clear(); + for (const proto::DisplayInfo& displayInfo : proto) { + outDisplayInfos.emplace_or_replace(ui::LayerStack::fromValue(displayInfo.layer_stack()), + fromProto(displayInfo)); + } +} + } // namespace android::surfaceflinger diff --git a/services/surfaceflinger/Tracing/TransactionProtoParser.h b/services/surfaceflinger/Tracing/TransactionProtoParser.h index 2232bb9cb1..50944fce0f 100644 --- a/services/surfaceflinger/Tracing/TransactionProtoParser.h +++ b/services/surfaceflinger/Tracing/TransactionProtoParser.h @@ -18,30 +18,17 @@ #include <gui/fake/BufferData.h> #include <layerproto/TransactionProto.h> #include <utils/RefBase.h> +#include "Display/DisplayMap.h" +#include "FrontEnd/DisplayInfo.h" +#include "FrontEnd/LayerCreationArgs.h" #include "TransactionState.h" namespace android::surfaceflinger { -struct TracingLayerCreationArgs { - int32_t layerId; - std::string name; - uint32_t flags = 0; - int32_t parentId = -1; - int32_t mirrorFromId = -1; -}; - -struct TracingLayerState : layer_state_t { - uint64_t bufferId; - uint32_t bufferHeight; - uint32_t bufferWidth; - int32_t pixelFormat; - uint64_t bufferUsage; +struct TracingLayerState : ResolvedComposerState { bool hasSidebandStream; - int32_t parentId; - int32_t relativeParentId; - int32_t inputCropId; - TracingLayerCreationArgs args; + LayerCreationArgs args; }; class TransactionProtoParser { @@ -51,40 +38,30 @@ public: class FlingerDataMapper { public: virtual ~FlingerDataMapper() = default; - virtual sp<IBinder> getLayerHandle(int32_t /* layerId */) const { return nullptr; } - virtual int64_t getLayerId(const sp<IBinder>& /* layerHandle */) const { return -1; } - virtual int64_t getLayerId(BBinder* /* layerHandle */) const { return -1; } virtual sp<IBinder> getDisplayHandle(int32_t /* displayId */) const { return nullptr; } virtual int32_t getDisplayId(const sp<IBinder>& /* displayHandle */) const { return -1; } - virtual std::shared_ptr<BufferData> getGraphicData(uint64_t bufferId, uint32_t width, - uint32_t height, int32_t pixelFormat, - uint64_t usage) const { - return std::make_shared<fake::BufferData>(bufferId, width, height, pixelFormat, usage); - } - virtual void getGraphicBufferPropertiesFromCache(client_cache_t /* cachedBuffer */, - uint64_t* /* outBufferId */, - uint32_t* /* outWidth */, - uint32_t* /* outHeight */, - int32_t* /* outPixelFormat */, - uint64_t* /* outUsage */) const {} }; TransactionProtoParser(std::unique_ptr<FlingerDataMapper> provider) : mMapper(std::move(provider)) {} proto::TransactionState toProto(const TransactionState&); - proto::TransactionState toProto(const std::map<int32_t /* layerId */, TracingLayerState>&); - proto::LayerCreationArgs toProto(const TracingLayerCreationArgs& args); + proto::TransactionState toProto(const std::map<uint32_t /* layerId */, TracingLayerState>&); + proto::LayerCreationArgs toProto(const LayerCreationArgs& args); + proto::LayerState toProto(const ResolvedComposerState&); + proto::DisplayInfo toProto(const frontend::DisplayInfo&, uint32_t layerStack); TransactionState fromProto(const proto::TransactionState&); void mergeFromProto(const proto::LayerState&, TracingLayerState& outState); - void fromProto(const proto::LayerCreationArgs&, TracingLayerCreationArgs& outArgs); + void fromProto(const proto::LayerCreationArgs&, LayerCreationArgs& outArgs); std::unique_ptr<FlingerDataMapper> mMapper; + frontend::DisplayInfo fromProto(const proto::DisplayInfo&); + void fromProto(const google::protobuf::RepeatedPtrField<proto::DisplayInfo>&, + display::DisplayMap<ui::LayerStack, frontend::DisplayInfo> outDisplayInfos); private: - proto::LayerState toProto(const layer_state_t&); proto::DisplayState toProto(const DisplayState&); - void fromProto(const proto::LayerState&, layer_state_t& out); + void fromProto(const proto::LayerState&, ResolvedComposerState& out); DisplayState fromProto(const proto::DisplayState&); }; diff --git a/services/surfaceflinger/Tracing/TransactionTracing.cpp b/services/surfaceflinger/Tracing/TransactionTracing.cpp index cb5320b88c..26ed878396 100644 --- a/services/surfaceflinger/Tracing/TransactionTracing.cpp +++ b/services/surfaceflinger/Tracing/TransactionTracing.cpp @@ -23,75 +23,14 @@ #include <utils/SystemClock.h> #include <utils/Trace.h> -#include "ClientCache.h" +#include "Client.h" +#include "FrontEnd/LayerCreationArgs.h" #include "TransactionTracing.h" -#include "renderengine/ExternalTexture.h" namespace android { -// Keeps the binder address as the layer id so we can avoid holding the tracing lock in the -// binder thread. -class FlatDataMapper : public TransactionProtoParser::FlingerDataMapper { -public: - virtual int64_t getLayerId(const sp<IBinder>& layerHandle) const { - if (layerHandle == nullptr) { - return -1; - } - - return reinterpret_cast<int64_t>(layerHandle->localBinder()); - } - - void getGraphicBufferPropertiesFromCache(client_cache_t cachedBuffer, uint64_t* outBufferId, - uint32_t* outWidth, uint32_t* outHeight, - int32_t* outPixelFormat, - uint64_t* outUsage) const override { - std::shared_ptr<renderengine::ExternalTexture> buffer = - ClientCache::getInstance().get(cachedBuffer); - if (!buffer || !buffer->getBuffer()) { - *outBufferId = 0; - *outWidth = 0; - *outHeight = 0; - *outPixelFormat = 0; - *outUsage = 0; - return; - } - - *outBufferId = buffer->getId(); - *outWidth = buffer->getWidth(); - *outHeight = buffer->getHeight(); - *outPixelFormat = buffer->getPixelFormat(); - *outUsage = buffer->getUsage(); - return; - } -}; - -class FlingerDataMapper : public FlatDataMapper { - std::unordered_map<BBinder* /* layerHandle */, int32_t /* layerId */>& mLayerHandles; - -public: - FlingerDataMapper(std::unordered_map<BBinder* /* handle */, int32_t /* id */>& layerHandles) - : mLayerHandles(layerHandles) {} - - int64_t getLayerId(const sp<IBinder>& layerHandle) const override { - if (layerHandle == nullptr) { - return -1; - } - return getLayerId(layerHandle->localBinder()); - } - - int64_t getLayerId(BBinder* localBinder) const { - auto it = mLayerHandles.find(localBinder); - if (it == mLayerHandles.end()) { - ALOGW("Could not find layer handle %p", localBinder); - return -1; - } - return it->second; - } -}; - TransactionTracing::TransactionTracing() - : mProtoParser(std::make_unique<FlingerDataMapper>(mLayerHandles)), - mLockfreeProtoParser(std::make_unique<FlatDataMapper>()) { + : mProtoParser(std::make_unique<TransactionProtoParser::FlingerDataMapper>()) { std::scoped_lock lock(mTraceLock); mBuffer.setSize(mBufferSizeInBytes); @@ -137,84 +76,77 @@ proto::TransactionTraceFile TransactionTracing::createTraceFileProto() const { auto timeOffsetNs = static_cast<std::uint64_t>(systemTime(SYSTEM_TIME_REALTIME) - systemTime(SYSTEM_TIME_MONOTONIC)); proto.set_real_to_elapsed_time_offset_nanos(timeOffsetNs); + proto.set_version(TRACING_VERSION); return proto; } void TransactionTracing::dump(std::string& result) const { std::scoped_lock lock(mTraceLock); - base::StringAppendF(&result, - " queued transactions=%zu created layers=%zu handles=%zu states=%zu\n", - mQueuedTransactions.size(), mCreatedLayers.size(), mLayerHandles.size(), - mStartingStates.size()); + base::StringAppendF(&result, " queued transactions=%zu created layers=%zu states=%zu\n", + mQueuedTransactions.size(), mCreatedLayers.size(), mStartingStates.size()); mBuffer.dump(result); } void TransactionTracing::addQueuedTransaction(const TransactionState& transaction) { - proto::TransactionState* state = - new proto::TransactionState(mLockfreeProtoParser.toProto(transaction)); + proto::TransactionState* state = new proto::TransactionState(mProtoParser.toProto(transaction)); mTransactionQueue.push(state); } -TransactionTracing::CommittedTransactions& -TransactionTracing::findOrCreateCommittedTransactionRecord(int64_t vsyncId) { - for (auto& pendingTransaction : mPendingTransactions) { - if (pendingTransaction.vsyncId == vsyncId) { - return pendingTransaction; - } +void TransactionTracing::addCommittedTransactions( + int64_t vsyncId, nsecs_t commitTime, frontend::Update& newUpdate, + const display::DisplayMap<ui::LayerStack, frontend::DisplayInfo>& displayInfos, + bool displayInfoChanged) { + CommittedUpdates update; + update.vsyncId = vsyncId; + update.timestamp = commitTime; + update.transactionIds.reserve(newUpdate.transactions.size()); + for (const auto& transaction : newUpdate.transactions) { + update.transactionIds.emplace_back(transaction.id); } - - CommittedTransactions committedTransactions; - committedTransactions.vsyncId = vsyncId; - committedTransactions.timestamp = systemTime(); - mPendingTransactions.emplace_back(committedTransactions); - return mPendingTransactions.back(); -} - -void TransactionTracing::onLayerAddedToDrawingState(int layerId, int64_t vsyncId) { - CommittedTransactions& committedTransactions = findOrCreateCommittedTransactionRecord(vsyncId); - committedTransactions.createdLayerIds.emplace_back(layerId); -} - -void TransactionTracing::addCommittedTransactions(std::vector<TransactionState>& transactions, - int64_t vsyncId) { - CommittedTransactions& committedTransactions = findOrCreateCommittedTransactionRecord(vsyncId); - committedTransactions.transactionIds.reserve(transactions.size()); - for (const auto& transaction : transactions) { - committedTransactions.transactionIds.emplace_back(transaction.id); + update.displayInfoChanged = displayInfoChanged; + if (displayInfoChanged) { + update.displayInfos = displayInfos; } + update.createdLayers = std::move(newUpdate.layerCreationArgs); + newUpdate.layerCreationArgs.clear(); + update.destroyedLayerHandles.reserve(newUpdate.destroyedHandles.size()); + for (uint32_t handle : newUpdate.destroyedHandles) { + update.destroyedLayerHandles.push_back(handle); + } + mPendingUpdates.emplace_back(update); tryPushToTracingThread(); } void TransactionTracing::loop() { while (true) { - std::vector<CommittedTransactions> committedTransactions; - std::vector<int32_t> removedLayers; + std::vector<CommittedUpdates> committedUpdates; + std::vector<uint32_t> destroyedLayers; { std::unique_lock<std::mutex> lock(mMainThreadLock); base::ScopedLockAssertion assumeLocked(mMainThreadLock); mTransactionsAvailableCv.wait(lock, [&]() REQUIRES(mMainThreadLock) { - return mDone || !mCommittedTransactions.empty(); + return mDone || !mUpdates.empty(); }); if (mDone) { - mCommittedTransactions.clear(); - mRemovedLayers.clear(); + mUpdates.clear(); + mDestroyedLayers.clear(); break; } - removedLayers = std::move(mRemovedLayers); - mRemovedLayers.clear(); - committedTransactions = std::move(mCommittedTransactions); - mCommittedTransactions.clear(); + destroyedLayers = std::move(mDestroyedLayers); + mDestroyedLayers.clear(); + committedUpdates = std::move(mUpdates); + mUpdates.clear(); } // unlock mMainThreadLock - if (!committedTransactions.empty() || !removedLayers.empty()) { - addEntry(committedTransactions, removedLayers); + if (!committedUpdates.empty() || !destroyedLayers.empty()) { + addEntry(committedUpdates, destroyedLayers); } } } -void TransactionTracing::addEntry(const std::vector<CommittedTransactions>& committedTransactions, - const std::vector<int32_t>& removedLayers) { +void TransactionTracing::addEntry(const std::vector<CommittedUpdates>& committedUpdates, + const std::vector<uint32_t>& destroyedLayers) { ATRACE_CALL(); std::scoped_lock lock(mTraceLock); std::vector<std::string> removedEntries; @@ -222,59 +154,27 @@ void TransactionTracing::addEntry(const std::vector<CommittedTransactions>& comm while (auto incomingTransaction = mTransactionQueue.pop()) { auto transaction = *incomingTransaction; - int32_t layerCount = transaction.layer_changes_size(); - for (int i = 0; i < layerCount; i++) { - auto layer = transaction.mutable_layer_changes(i); - layer->set_layer_id( - mProtoParser.mMapper->getLayerId(reinterpret_cast<BBinder*>(layer->layer_id()))); - if ((layer->what() & layer_state_t::eReparent) && layer->parent_id() != -1) { - layer->set_parent_id( - mProtoParser.mMapper->getLayerId(reinterpret_cast<BBinder*>( - layer->parent_id()))); - } - - if ((layer->what() & layer_state_t::eRelativeLayerChanged) && - layer->relative_parent_id() != -1) { - layer->set_relative_parent_id( - mProtoParser.mMapper->getLayerId(reinterpret_cast<BBinder*>( - layer->relative_parent_id()))); - } - - if (layer->has_window_info_handle() && - layer->window_info_handle().crop_layer_id() != -1) { - auto input = layer->mutable_window_info_handle(); - input->set_crop_layer_id( - mProtoParser.mMapper->getLayerId(reinterpret_cast<BBinder*>( - input->crop_layer_id()))); - } - } mQueuedTransactions[incomingTransaction->transaction_id()] = transaction; delete incomingTransaction; } - for (const CommittedTransactions& entry : committedTransactions) { - entryProto.set_elapsed_realtime_nanos(entry.timestamp); - entryProto.set_vsync_id(entry.vsyncId); + for (const CommittedUpdates& update : committedUpdates) { + entryProto.set_elapsed_realtime_nanos(update.timestamp); + entryProto.set_vsync_id(update.vsyncId); entryProto.mutable_added_layers()->Reserve( - static_cast<int32_t>(entry.createdLayerIds.size())); + static_cast<int32_t>(update.createdLayers.size())); - for (const int32_t& id : entry.createdLayerIds) { - auto it = mCreatedLayers.find(id); - if (it != mCreatedLayers.end()) { - entryProto.mutable_added_layers()->Add(std::move(it->second)); - mCreatedLayers.erase(it); - } else { - ALOGW("Could not created layer with id %d", id); - } + for (const auto& args : update.createdLayers) { + entryProto.mutable_added_layers()->Add(std::move(mProtoParser.toProto(args))); } - entryProto.mutable_removed_layers()->Reserve(static_cast<int32_t>(removedLayers.size())); - for (auto& removedLayer : removedLayers) { - entryProto.mutable_removed_layers()->Add(removedLayer); - mCreatedLayers.erase(removedLayer); + entryProto.mutable_destroyed_layers()->Reserve( + static_cast<int32_t>(destroyedLayers.size())); + for (auto& destroyedLayer : destroyedLayers) { + entryProto.mutable_destroyed_layers()->Add(destroyedLayer); } entryProto.mutable_transactions()->Reserve( - static_cast<int32_t>(entry.transactionIds.size())); - for (const uint64_t& id : entry.transactionIds) { + static_cast<int32_t>(update.transactionIds.size())); + for (const uint64_t& id : update.transactionIds) { auto it = mQueuedTransactions.find(id); if (it != mQueuedTransactions.end()) { entryProto.mutable_transactions()->Add(std::move(it->second)); @@ -284,13 +184,21 @@ void TransactionTracing::addEntry(const std::vector<CommittedTransactions>& comm } } - entryProto.mutable_removed_layer_handles()->Reserve( - static_cast<int32_t>(mRemovedLayerHandles.size())); - for (auto& [handle, layerId] : mRemovedLayerHandles) { - entryProto.mutable_removed_layer_handles()->Add(layerId); - mLayerHandles.erase(handle); + entryProto.mutable_destroyed_layer_handles()->Reserve( + static_cast<int32_t>(update.destroyedLayerHandles.size())); + for (auto layerId : update.destroyedLayerHandles) { + entryProto.mutable_destroyed_layer_handles()->Add(layerId); + } + + entryProto.set_displays_changed(update.displayInfoChanged); + if (update.displayInfoChanged) { + entryProto.mutable_displays()->Reserve( + static_cast<int32_t>(update.displayInfos.size())); + for (auto& [layerStack, displayInfo] : update.displayInfos) { + entryProto.mutable_displays()->Add( + std::move(mProtoParser.toProto(displayInfo, layerStack.id))); + } } - mRemovedLayerHandles.clear(); std::string serializedProto; entryProto.SerializeToString(&serializedProto); @@ -311,7 +219,7 @@ void TransactionTracing::addEntry(const std::vector<CommittedTransactions>& comm } void TransactionTracing::flush(int64_t vsyncId) { - while (!mPendingTransactions.empty() || !mPendingRemovedLayers.empty()) { + while (!mPendingUpdates.empty() || !mPendingDestroyedLayers.empty()) { tryPushToTracingThread(); } std::unique_lock<std::mutex> lock(mTraceLock); @@ -325,54 +233,21 @@ void TransactionTracing::flush(int64_t vsyncId) { }); } -void TransactionTracing::onLayerAdded(BBinder* layerHandle, int layerId, const std::string& name, - uint32_t flags, int parentId) { - std::scoped_lock lock(mTraceLock); - TracingLayerCreationArgs args{layerId, name, flags, parentId, -1 /* mirrorFromId */}; - if (mLayerHandles.find(layerHandle) != mLayerHandles.end()) { - ALOGW("Duplicate handles found. %p", layerHandle); - } - mLayerHandles[layerHandle] = layerId; - mCreatedLayers[layerId] = mProtoParser.toProto(args); -} - -void TransactionTracing::onMirrorLayerAdded(BBinder* layerHandle, int layerId, - const std::string& name, int mirrorFromId) { - std::scoped_lock lock(mTraceLock); - TracingLayerCreationArgs args{layerId, name, 0 /* flags */, -1 /* parentId */, mirrorFromId}; - if (mLayerHandles.find(layerHandle) != mLayerHandles.end()) { - ALOGW("Duplicate handles found. %p", layerHandle); - } - mLayerHandles[layerHandle] = layerId; - mCreatedLayers[layerId] = mProtoParser.toProto(args); -} - void TransactionTracing::onLayerRemoved(int32_t layerId) { - mPendingRemovedLayers.emplace_back(layerId); + mPendingDestroyedLayers.emplace_back(layerId); tryPushToTracingThread(); } -void TransactionTracing::onHandleRemoved(BBinder* layerHandle) { - std::scoped_lock lock(mTraceLock); - auto it = mLayerHandles.find(layerHandle); - if (it == mLayerHandles.end()) { - ALOGW("handle not found. %p", layerHandle); - return; - } - mRemovedLayerHandles.emplace_back(layerHandle, it->second); -} - void TransactionTracing::tryPushToTracingThread() { // Try to acquire the lock from main thread. if (mMainThreadLock.try_lock()) { // We got the lock! Collect any pending transactions and continue. - mCommittedTransactions.insert(mCommittedTransactions.end(), - std::make_move_iterator(mPendingTransactions.begin()), - std::make_move_iterator(mPendingTransactions.end())); - mPendingTransactions.clear(); - mRemovedLayers.insert(mRemovedLayers.end(), mPendingRemovedLayers.begin(), - mPendingRemovedLayers.end()); - mPendingRemovedLayers.clear(); + mUpdates.insert(mUpdates.end(), std::make_move_iterator(mPendingUpdates.begin()), + std::make_move_iterator(mPendingUpdates.end())); + mPendingUpdates.clear(); + mDestroyedLayers.insert(mDestroyedLayers.end(), mPendingDestroyedLayers.begin(), + mPendingDestroyedLayers.end()); + mPendingDestroyedLayers.clear(); mTransactionsAvailableCv.notify_one(); mMainThreadLock.unlock(); } else { @@ -394,24 +269,28 @@ void TransactionTracing::updateStartingStateLocked( // Merge layer states to starting transaction state. for (const proto::TransactionState& transaction : removedEntry.transactions()) { for (const proto::LayerState& layerState : transaction.layer_changes()) { - auto it = mStartingStates.find((int32_t)layerState.layer_id()); + auto it = mStartingStates.find(layerState.layer_id()); if (it == mStartingStates.end()) { - ALOGW("Could not find layer id %d", (int32_t)layerState.layer_id()); + ALOGW("Could not find layer id %d", layerState.layer_id()); continue; } mProtoParser.mergeFromProto(layerState, it->second); } } - for (const int32_t removedLayerHandleId : removedEntry.removed_layer_handles()) { - mRemovedLayerHandlesAtStart.insert(removedLayerHandleId); + for (const uint32_t destroyedLayerHandleId : removedEntry.destroyed_layer_handles()) { + mRemovedLayerHandlesAtStart.insert(destroyedLayerHandleId); } // Clean up stale starting states since the layer has been removed and the buffer does not // contain any references to the layer. - for (const int32_t removedLayerId : removedEntry.removed_layers()) { - mStartingStates.erase(removedLayerId); - mRemovedLayerHandlesAtStart.erase(removedLayerId); + for (const uint32_t destroyedLayerId : removedEntry.destroyed_layers()) { + mStartingStates.erase(destroyedLayerId); + mRemovedLayerHandlesAtStart.erase(destroyedLayerId); + } + + if (removedEntry.displays_changed()) { + mProtoParser.fromProto(removedEntry.displays(), mStartingDisplayInfos); } } @@ -434,10 +313,15 @@ void TransactionTracing::addStartingStateToProtoLocked(proto::TransactionTraceFi transactionProto.set_post_time(mStartingTimestamp); entryProto->mutable_transactions()->Add(std::move(transactionProto)); - entryProto->mutable_removed_layer_handles()->Reserve( + entryProto->mutable_destroyed_layer_handles()->Reserve( static_cast<int32_t>(mRemovedLayerHandlesAtStart.size())); - for (const int32_t removedLayerHandleId : mRemovedLayerHandlesAtStart) { - entryProto->mutable_removed_layer_handles()->Add(removedLayerHandleId); + for (const uint32_t destroyedLayerHandleId : mRemovedLayerHandlesAtStart) { + entryProto->mutable_destroyed_layer_handles()->Add(destroyedLayerHandleId); + } + + entryProto->mutable_displays()->Reserve(static_cast<int32_t>(mStartingDisplayInfos.size())); + for (auto& [layerStack, displayInfo] : mStartingDisplayInfos) { + entryProto->mutable_displays()->Add(mProtoParser.toProto(displayInfo, layerStack.id)); } } diff --git a/services/surfaceflinger/Tracing/TransactionTracing.h b/services/surfaceflinger/Tracing/TransactionTracing.h index ae01d3c0cc..f27e7a9663 100644 --- a/services/surfaceflinger/Tracing/TransactionTracing.h +++ b/services/surfaceflinger/Tracing/TransactionTracing.h @@ -25,8 +25,12 @@ #include <mutex> #include <thread> -#include "RingBuffer.h" +#include "Display/DisplayMap.h" +#include "FrontEnd/DisplayInfo.h" +#include "FrontEnd/LayerCreationArgs.h" +#include "FrontEnd/Update.h" #include "LocklessStack.h" +#include "RingBuffer.h" #include "TransactionProtoParser.h" using namespace android::surfaceflinger; @@ -55,22 +59,22 @@ public: ~TransactionTracing(); void addQueuedTransaction(const TransactionState&); - void addCommittedTransactions(std::vector<TransactionState>& transactions, int64_t vsyncId); + void addCommittedTransactions( + int64_t vsyncId, nsecs_t commitTime, frontend::Update& update, + const display::DisplayMap<ui::LayerStack, frontend::DisplayInfo>& displayInfos, + bool displayInfoChanged); status_t writeToFile(std::string filename = FILE_NAME); void setBufferSize(size_t bufferSizeInBytes); - void onLayerAdded(BBinder* layerHandle, int layerId, const std::string& name, uint32_t flags, - int parentId); - void onMirrorLayerAdded(BBinder* layerHandle, int layerId, const std::string& name, - int mirrorFromId); void onLayerRemoved(int layerId); - void onHandleRemoved(BBinder* layerHandle); - void onLayerAddedToDrawingState(int layerId, int64_t vsyncId); void dump(std::string&) const; static constexpr auto CONTINUOUS_TRACING_BUFFER_SIZE = 512 * 1024; static constexpr auto ACTIVE_TRACING_BUFFER_SIZE = 100 * 1024 * 1024; + // version 1 - switching to support new frontend + static constexpr auto TRACING_VERSION = 1; private: friend class TransactionTracingTest; + friend class SurfaceFlinger; static constexpr auto FILE_NAME = "/data/misc/wmtrace/transactions_trace.winscope"; @@ -83,16 +87,12 @@ private: LocklessStack<proto::TransactionState> mTransactionQueue; nsecs_t mStartingTimestamp GUARDED_BY(mTraceLock); std::unordered_map<int, proto::LayerCreationArgs> mCreatedLayers GUARDED_BY(mTraceLock); - std::unordered_map<BBinder* /* layerHandle */, int32_t /* layerId */> mLayerHandles + std::map<uint32_t /* layerId */, TracingLayerState> mStartingStates GUARDED_BY(mTraceLock); + display::DisplayMap<ui::LayerStack, frontend::DisplayInfo> mStartingDisplayInfos GUARDED_BY(mTraceLock); - std::vector<std::pair<BBinder* /* layerHandle */, int32_t /* layerId */>> mRemovedLayerHandles - GUARDED_BY(mTraceLock); - std::map<int32_t /* layerId */, TracingLayerState> mStartingStates GUARDED_BY(mTraceLock); - std::set<int32_t /* layerId */> mRemovedLayerHandlesAtStart GUARDED_BY(mTraceLock); - TransactionProtoParser mProtoParser GUARDED_BY(mTraceLock); - // Parses the transaction to proto without holding any tracing locks so we can generate proto - // in the binder thread without any contention. - TransactionProtoParser mLockfreeProtoParser; + + std::set<uint32_t /* layerId */> mRemovedLayerHandlesAtStart GUARDED_BY(mTraceLock); + TransactionProtoParser mProtoParser; // We do not want main thread to block so main thread will try to acquire mMainThreadLock, // otherwise will push data to temporary container. @@ -101,27 +101,29 @@ private: bool mDone GUARDED_BY(mMainThreadLock) = false; std::condition_variable mTransactionsAvailableCv; std::condition_variable mTransactionsAddedToBufferCv; - struct CommittedTransactions { + struct CommittedUpdates { std::vector<uint64_t> transactionIds; - std::vector<int32_t> createdLayerIds; + std::vector<LayerCreationArgs> createdLayers; + std::vector<uint32_t> destroyedLayerHandles; + bool displayInfoChanged; + display::DisplayMap<ui::LayerStack, frontend::DisplayInfo> displayInfos; int64_t vsyncId; int64_t timestamp; }; - std::vector<CommittedTransactions> mCommittedTransactions GUARDED_BY(mMainThreadLock); - std::vector<CommittedTransactions> mPendingTransactions; // only accessed by main thread + std::vector<CommittedUpdates> mUpdates GUARDED_BY(mMainThreadLock); + std::vector<CommittedUpdates> mPendingUpdates; // only accessed by main thread - std::vector<int32_t /* layerId */> mRemovedLayers GUARDED_BY(mMainThreadLock); - std::vector<int32_t /* layerId */> mPendingRemovedLayers; // only accessed by main thread + std::vector<uint32_t /* layerId */> mDestroyedLayers GUARDED_BY(mMainThreadLock); + std::vector<uint32_t /* layerId */> mPendingDestroyedLayers; // only accessed by main thread proto::TransactionTraceFile createTraceFileProto() const; void loop(); - void addEntry(const std::vector<CommittedTransactions>& committedTransactions, - const std::vector<int32_t>& removedLayers) EXCLUDES(mTraceLock); + void addEntry(const std::vector<CommittedUpdates>& committedTransactions, + const std::vector<uint32_t>& removedLayers) EXCLUDES(mTraceLock); int32_t getLayerIdLocked(const sp<IBinder>& layerHandle) REQUIRES(mTraceLock); void tryPushToTracingThread() EXCLUDES(mMainThreadLock); void addStartingStateToProtoLocked(proto::TransactionTraceFile& proto) REQUIRES(mTraceLock); void updateStartingStateLocked(const proto::TransactionTraceEntry& entry) REQUIRES(mTraceLock); - CommittedTransactions& findOrCreateCommittedTransactionRecord(int64_t vsyncId); // TEST // Wait until all the committed transactions for the specified vsync id are added to the buffer. void flush(int64_t vsyncId) EXCLUDES(mMainThreadLock); diff --git a/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp b/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp index 31f4723915..2418cf22e5 100644 --- a/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp +++ b/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp @@ -14,175 +14,31 @@ * limitations under the License. */ +#include <memory> +#include <vector> +#include "FrontEnd/LayerCreationArgs.h" +#include "FrontEnd/RequestedLayerState.h" +#include "Tracing/LayerTracing.h" +#include "TransactionState.h" +#include "cutils/properties.h" #undef LOG_TAG #define LOG_TAG "LayerTraceGenerator" //#define LOG_NDEBUG 0 -#include <TestableSurfaceFlinger.h> #include <Tracing/TransactionProtoParser.h> -#include <binder/IPCThreadState.h> -#include <gmock/gmock.h> -#include <gtest/gtest.h> #include <gui/LayerState.h> #include <log/log.h> -#include <mock/MockEventThread.h> #include <renderengine/ExternalTexture.h> -#include <renderengine/mock/RenderEngine.h> #include <utils/String16.h> +#include <filesystem> +#include <fstream> #include <string> +#include "LayerProtoHelper.h" #include "LayerTraceGenerator.h" namespace android { - -class Factory final : public surfaceflinger::Factory { -public: - ~Factory() = default; - - std::unique_ptr<HWComposer> createHWComposer(const std::string&) override { return nullptr; } - - std::unique_ptr<scheduler::VsyncConfiguration> createVsyncConfiguration( - Fps /*currentRefreshRate*/) override { - return std::make_unique<scheduler::FakePhaseOffsets>(); - } - - sp<StartPropertySetThread> createStartPropertySetThread( - bool /* timestampPropertyValue */) override { - return sp<StartPropertySetThread>(); - } - - sp<DisplayDevice> createDisplayDevice(DisplayDeviceCreationArgs& /* creationArgs */) override { - return sp<DisplayDevice>(); - } - - sp<GraphicBuffer> createGraphicBuffer(uint32_t /* width */, uint32_t /* height */, - PixelFormat /* format */, uint32_t /* layerCount */, - uint64_t /* usage */, - std::string /* requestorName */) override { - return sp<GraphicBuffer>(); - } - - void createBufferQueue(sp<IGraphicBufferProducer>* /* outProducer */, - sp<IGraphicBufferConsumer>* /* outConsumer */, - bool /* consumerIsSurfaceFlinger */) override {} - - std::unique_ptr<surfaceflinger::NativeWindowSurface> createNativeWindowSurface( - const sp<IGraphicBufferProducer>& /* producer */) override { - return nullptr; - } - - std::unique_ptr<compositionengine::CompositionEngine> createCompositionEngine() override { - return compositionengine::impl::createCompositionEngine(); - } - - sp<Layer> createBufferStateLayer(const LayerCreationArgs& args) { - return sp<Layer>::make(args); - } - - sp<Layer> createEffectLayer(const LayerCreationArgs& args) { return sp<Layer>::make(args); } - - sp<LayerFE> createLayerFE(const std::string& layerName) { return sp<LayerFE>::make(layerName); } - - std::unique_ptr<FrameTracer> createFrameTracer() override { - return std::make_unique<testing::NiceMock<mock::FrameTracer>>(); - } - - std::unique_ptr<frametimeline::FrameTimeline> createFrameTimeline( - std::shared_ptr<TimeStats> timeStats, pid_t surfaceFlingerPid = 0) override { - return std::make_unique<testing::NiceMock<mock::FrameTimeline>>(timeStats, - surfaceFlingerPid); - } -}; - -class FakeExternalTexture : public renderengine::ExternalTexture { - const sp<GraphicBuffer> mNullBuffer = nullptr; - uint32_t mWidth; - uint32_t mHeight; - uint64_t mId; - PixelFormat mPixelFormat; - uint64_t mUsage; - -public: - FakeExternalTexture(uint32_t width, uint32_t height, uint64_t id, PixelFormat pixelFormat, - uint64_t usage) - : mWidth(width), mHeight(height), mId(id), mPixelFormat(pixelFormat), mUsage(usage) {} - const sp<GraphicBuffer>& getBuffer() const { return mNullBuffer; } - bool hasSameBuffer(const renderengine::ExternalTexture& other) const override { - return getId() == other.getId(); - } - uint32_t getWidth() const override { return mWidth; } - uint32_t getHeight() const override { return mHeight; } - uint64_t getId() const override { return mId; } - PixelFormat getPixelFormat() const override { return mPixelFormat; } - uint64_t getUsage() const override { return mUsage; } - ~FakeExternalTexture() = default; -}; - -class MockSurfaceFlinger : public SurfaceFlinger { -public: - MockSurfaceFlinger(Factory& factory) - : SurfaceFlinger(factory, SurfaceFlinger::SkipInitialization) {} - std::shared_ptr<renderengine::ExternalTexture> getExternalTextureFromBufferData( - BufferData& bufferData, const char* /* layerName */, - uint64_t /* transactionId */) override { - return std::make_shared<FakeExternalTexture>(bufferData.getWidth(), bufferData.getHeight(), - bufferData.getId(), - bufferData.getPixelFormat(), - bufferData.getUsage()); - }; - - // b/220017192 migrate from transact codes to ISurfaceComposer apis - void setLayerTracingFlags(int32_t flags) { - Parcel data; - Parcel reply; - data.writeInterfaceToken(String16("android.ui.ISurfaceComposer")); - data.writeInt32(flags); - transact(1033, data, &reply, 0 /* flags */); - } - - void setLayerTraceSize(int32_t sizeInKb) { - Parcel data; - Parcel reply; - data.writeInterfaceToken(String16("android.ui.ISurfaceComposer")); - data.writeInt32(sizeInKb); - transact(1029, data, &reply, 0 /* flags */); - } - - void startLayerTracing(int64_t traceStartTime) { - Parcel data; - Parcel reply; - data.writeInterfaceToken(String16("android.ui.ISurfaceComposer")); - data.writeInt32(1); - data.writeInt64(traceStartTime); - transact(1025, data, &reply, 0 /* flags */); - } - - void stopLayerTracing(const char* tracePath) { - Parcel data; - Parcel reply; - data.writeInterfaceToken(String16("android.ui.ISurfaceComposer")); - data.writeInt32(2); - data.writeCString(tracePath); - transact(1025, data, &reply, 0 /* flags */); - } -}; - -class TraceGenFlingerDataMapper : public TransactionProtoParser::FlingerDataMapper { -public: - std::unordered_map<int32_t /*layerId*/, sp<IBinder> /* handle */> mLayerHandles; - sp<IBinder> getLayerHandle(int32_t layerId) const override { - if (layerId == -1) { - ALOGE("Error: Called with layer=%d", layerId); - return nullptr; - } - auto it = mLayerHandles.find(layerId); - if (it == mLayerHandles.end()) { - ALOGE("Error: Could not find handle for layer=%d", layerId); - return nullptr; - } - return it->second; - } -}; +using namespace ftl::flag_operators; bool LayerTraceGenerator::generate(const proto::TransactionTraceFile& traceFile, const char* outputLayersTracePath) { @@ -191,82 +47,103 @@ bool LayerTraceGenerator::generate(const proto::TransactionTraceFile& traceFile, return false; } - Factory factory; - sp<MockSurfaceFlinger> flingerPtr = sp<MockSurfaceFlinger>::make(factory); - TestableSurfaceFlinger flinger(flingerPtr); - flinger.setupRenderEngine( - std::make_unique<testing::NiceMock<renderengine::mock::RenderEngine>>()); - flinger.setupMockScheduler({.useNiceMock = true}); + TransactionProtoParser parser(std::make_unique<TransactionProtoParser::FlingerDataMapper>()); - Hwc2::mock::Composer* composerPtr = new testing::NiceMock<Hwc2::mock::Composer>(); - flinger.setupComposer(std::unique_ptr<Hwc2::Composer>(composerPtr)); - flinger.mutableMaxRenderTargetSize() = 16384; + // frontend + frontend::LayerLifecycleManager lifecycleManager; + frontend::LayerHierarchyBuilder hierarchyBuilder{{}}; + frontend::LayerSnapshotBuilder snapshotBuilder; + display::DisplayMap<ui::LayerStack, frontend::DisplayInfo> displayInfos; - flingerPtr->setLayerTracingFlags(LayerTracing::TRACE_INPUT | LayerTracing::TRACE_BUFFERS); - flingerPtr->setLayerTraceSize(512 * 1024); // 512MB buffer size - flingerPtr->startLayerTracing(traceFile.entry(0).elapsed_realtime_nanos()); - std::unique_ptr<TraceGenFlingerDataMapper> mapper = - std::make_unique<TraceGenFlingerDataMapper>(); - TraceGenFlingerDataMapper* dataMapper = mapper.get(); - TransactionProtoParser parser(std::move(mapper)); + renderengine::ShadowSettings globalShadowSettings{.ambientColor = {1, 1, 1, 1}}; + char value[PROPERTY_VALUE_MAX]; + property_get("ro.surface_flinger.supports_background_blur", value, "0"); + bool supportsBlur = atoi(value); + + LayerTracing layerTracing; + layerTracing.setTraceFlags(LayerTracing::TRACE_INPUT | LayerTracing::TRACE_BUFFERS); + layerTracing.setBufferSize(512 * 1024 * 1024); // 512MB buffer size + layerTracing.enable(); ALOGD("Generating %d transactions...", traceFile.entry_size()); for (int i = 0; i < traceFile.entry_size(); i++) { + // parse proto proto::TransactionTraceEntry entry = traceFile.entry(i); ALOGV(" Entry %04d/%04d for time=%" PRId64 " vsyncid=%" PRId64 " layers +%d -%d handles -%d transactions=%d", i, traceFile.entry_size(), entry.elapsed_realtime_nanos(), entry.vsync_id(), - entry.added_layers_size(), entry.removed_layers_size(), - entry.removed_layer_handles_size(), entry.transactions_size()); + entry.added_layers_size(), entry.destroyed_layers_size(), + entry.destroyed_layer_handles_size(), entry.transactions_size()); + std::vector<std::unique_ptr<frontend::RequestedLayerState>> addedLayers; + addedLayers.reserve((size_t)entry.added_layers_size()); for (int j = 0; j < entry.added_layers_size(); j++) { - // create layers - TracingLayerCreationArgs tracingArgs; - parser.fromProto(entry.added_layers(j), tracingArgs); - - gui::CreateSurfaceResult outResult; - LayerCreationArgs args(flinger.flinger(), nullptr /* client */, tracingArgs.name, - tracingArgs.flags, LayerMetadata(), - std::make_optional<int32_t>(tracingArgs.layerId)); - - if (tracingArgs.mirrorFromId == -1) { - sp<IBinder> parentHandle = nullptr; - if ((tracingArgs.parentId != -1) && - (dataMapper->mLayerHandles.find(tracingArgs.parentId) == - dataMapper->mLayerHandles.end())) { - args.addToRoot = false; - } else if (tracingArgs.parentId != -1) { - parentHandle = dataMapper->getLayerHandle(tracingArgs.parentId); - } - flinger.createLayer(args, parentHandle, outResult); - } else { - sp<IBinder> mirrorFromHandle = dataMapper->getLayerHandle(tracingArgs.mirrorFromId); - flinger.mirrorLayer(args, mirrorFromHandle, outResult); - } - LOG_ALWAYS_FATAL_IF(outResult.layerId != tracingArgs.layerId, - "Could not create layer expected:%d actual:%d", tracingArgs.layerId, - outResult.layerId); - dataMapper->mLayerHandles[tracingArgs.layerId] = outResult.handle; + LayerCreationArgs args; + parser.fromProto(entry.added_layers(j), args); + addedLayers.emplace_back(std::make_unique<frontend::RequestedLayerState>(args)); } + std::vector<TransactionState> transactions; + transactions.reserve((size_t)entry.transactions_size()); for (int j = 0; j < entry.transactions_size(); j++) { // apply transactions TransactionState transaction = parser.fromProto(entry.transactions(j)); - flinger.setTransactionStateInternal(transaction); + transactions.emplace_back(std::move(transaction)); } - const auto frameTime = TimePoint::fromNs(entry.elapsed_realtime_nanos()); - const auto vsyncId = VsyncId{entry.vsync_id()}; - flinger.commit(frameTime, vsyncId); + std::vector<uint32_t> destroyedHandles; + destroyedHandles.reserve((size_t)entry.destroyed_layer_handles_size()); + for (int j = 0; j < entry.destroyed_layer_handles_size(); j++) { + destroyedHandles.push_back(entry.destroyed_layer_handles(j)); + } - for (int j = 0; j < entry.removed_layer_handles_size(); j++) { - dataMapper->mLayerHandles.erase(entry.removed_layer_handles(j)); + bool displayChanged = entry.displays_changed(); + if (displayChanged) { + parser.fromProto(entry.displays(), displayInfos); + } + + // apply updates + lifecycleManager.addLayers(std::move(addedLayers)); + lifecycleManager.applyTransactions(transactions); + lifecycleManager.onHandlesDestroyed(destroyedHandles, /*ignoreUnknownHandles=*/true); + + if (lifecycleManager.getGlobalChanges().test( + frontend::RequestedLayerState::Changes::Hierarchy)) { + hierarchyBuilder.update(lifecycleManager.getLayers(), + lifecycleManager.getDestroyedLayers()); } - } - flingerPtr->stopLayerTracing(outputLayersTracePath); + frontend::LayerSnapshotBuilder::Args args{.root = hierarchyBuilder.getHierarchy(), + .layerLifecycleManager = lifecycleManager, + .displays = displayInfos, + .displayChanges = displayChanged, + .globalShadowSettings = globalShadowSettings, + .supportsBlur = supportsBlur, + .forceFullDamage = false, + .supportedLayerGenericMetadata = {}, + .genericLayerMetadataKeyMap = {}}; + snapshotBuilder.update(args); + + bool visibleRegionsDirty = lifecycleManager.getGlobalChanges().any( + frontend::RequestedLayerState::Changes::VisibleRegion | + frontend::RequestedLayerState::Changes::Hierarchy | + frontend::RequestedLayerState::Changes::Visibility); + + ALOGV(" layers:%04zu snapshots:%04zu changes:%s", lifecycleManager.getLayers().size(), + snapshotBuilder.getSnapshots().size(), + lifecycleManager.getGlobalChanges().string().c_str()); + + lifecycleManager.commitChanges(); + + LayersProto layersProto = LayerProtoFromSnapshotGenerator(snapshotBuilder, displayInfos, {}, + layerTracing.getFlags()) + .generate(hierarchyBuilder.getHierarchy()); + auto displayProtos = LayerProtoHelper::writeDisplayInfoToProto(displayInfos); + layerTracing.notify(visibleRegionsDirty, entry.elapsed_realtime_nanos(), entry.vsync_id(), + &layersProto, {}, &displayProtos); + } + layerTracing.disable(outputLayersTracePath); ALOGD("End of generating trace file. File written to %s", outputLayersTracePath); - dataMapper->mLayerHandles.clear(); return true; } diff --git a/services/surfaceflinger/Tracing/tools/main.cpp b/services/surfaceflinger/Tracing/tools/main.cpp index 9f9ae4815b..c440c19ccc 100644 --- a/services/surfaceflinger/Tracing/tools/main.cpp +++ b/services/surfaceflinger/Tracing/tools/main.cpp @@ -53,9 +53,6 @@ int main(int argc, char** argv) { ALOGD("Generating %s...", outputLayersTracePath); std::cout << "Generating " << outputLayersTracePath << "\n"; - // sink any log spam from the stubbed surfaceflinger - __android_log_set_logger([](const struct __android_log_message* /* log_message */) {}); - if (!LayerTraceGenerator().generate(transactionTraceFile, outputLayersTracePath)) { std::cout << "Error: Failed to generate layers trace " << outputLayersTracePath; return -1; diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h index 72cecc9f89..6074bb7a16 100644 --- a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h +++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h @@ -452,8 +452,7 @@ public: LayersProto layersProto = mFlinger->dumpDrawingStateProto(fdp->ConsumeIntegral<uint32_t>()); mFlinger->dumpOffscreenLayersProto(layersProto); - LayersTraceProto layersTraceProto{}; - mFlinger->dumpDisplayProto(layersTraceProto); + mFlinger->dumpDisplayProto(); result = fdp->ConsumeRandomLengthString().c_str(); mFlinger->dumpHwc(result); diff --git a/services/surfaceflinger/layerproto/layers.proto b/services/surfaceflinger/layerproto/layers.proto index 3598308338..e9add2e1a4 100644 --- a/services/surfaceflinger/layerproto/layers.proto +++ b/services/surfaceflinger/layerproto/layers.proto @@ -138,6 +138,8 @@ message LayerProto { float requested_corner_radius = 56; RectProto destination_frame = 57; + + uint32 original_id = 58; } message PositionProto { diff --git a/services/surfaceflinger/layerproto/transactions.proto b/services/surfaceflinger/layerproto/transactions.proto index 4c6a9cf85b..2c4eb101e6 100644 --- a/services/surfaceflinger/layerproto/transactions.proto +++ b/services/surfaceflinger/layerproto/transactions.proto @@ -40,6 +40,7 @@ message TransactionTraceFile { /* offset between real-time clock and elapsed time clock in nanoseconds. Calculated as: systemTime(SYSTEM_TIME_REALTIME) - systemTime(SYSTEM_TIME_MONOTONIC) */ fixed64 real_to_elapsed_time_offset_nanos = 3; + uint32 version = 4; } message TransactionTraceEntry { @@ -47,18 +48,47 @@ message TransactionTraceEntry { int64 vsync_id = 2; repeated TransactionState transactions = 3; repeated LayerCreationArgs added_layers = 4; - repeated int32 removed_layers = 5; + repeated uint32 destroyed_layers = 5; repeated DisplayState added_displays = 6; repeated int32 removed_displays = 7; - repeated int32 removed_layer_handles = 8; + repeated uint32 destroyed_layer_handles = 8; + bool displays_changed = 9; + repeated DisplayInfo displays = 10; +} + +message DisplayInfo { + uint32 layer_stack = 1; + int32 display_id = 2; + int32 logical_width = 3; + int32 logical_height = 4; + Transform transform_inverse = 5; + Transform transform = 6; + bool receives_input = 7; + bool is_secure = 8; + bool is_primary = 9; + bool is_virtual = 10; + int32 rotation_flags = 11; + int32 transform_hint = 12; + } message LayerCreationArgs { - int32 layer_id = 1; + uint32 layer_id = 1; string name = 2; uint32 flags = 3; - int32 parent_id = 4; - int32 mirror_from_id = 5; + uint32 parent_id = 4; + uint32 mirror_from_id = 5; + bool add_to_root = 6; + uint32 layer_stack_to_mirror = 7; +} + +message Transform { + float dsdx = 1; + float dtdx = 2; + float dtdy = 3; + float dsdy = 4; + float tx = 5; + float ty = 6; } message TransactionState { @@ -74,7 +104,7 @@ message TransactionState { // Keep insync with layer_state_t message LayerState { - int64 layer_id = 1; + uint32 layer_id = 1; // Changes are split into ChangesLsb and ChangesMsb. First 32 bits are in ChangesLsb // and the next 32 bits are in ChangesMsb. This is needed because enums have to be // 32 bits and there's no nice way to put 64bit constants into .proto files. @@ -164,8 +194,8 @@ message LayerState { Matrix22 matrix = 11; float corner_radius = 12; uint32 background_blur_radius = 13; - int64 parent_id = 14; - int64 relative_parent_id = 15; + uint32 parent_id = 14; + uint32 relative_parent_id = 15; float alpha = 16; message Color3 { @@ -220,14 +250,6 @@ message LayerState { ColorTransformProto color_transform = 25; repeated BlurRegion blur_regions = 26; - message Transform { - float dsdx = 1; - float dtdx = 2; - float dtdy = 3; - float dsdy = 4; - float tx = 5; - float ty = 6; - } message WindowInfo { uint32 layout_params_flags = 1; int32 layout_params_type = 2; @@ -236,7 +258,7 @@ message LayerState { bool focusable = 5; bool has_wallpaper = 6; float global_scale_factor = 7; - int64 crop_layer_id = 8; + uint32 crop_layer_id = 8; bool replace_touchable_region_with_crop = 9; RectProto touchable_region_crop = 10; Transform transform = 11; diff --git a/services/surfaceflinger/tests/tracing/TransactionTraceTestSuite.cpp b/services/surfaceflinger/tests/tracing/TransactionTraceTestSuite.cpp index 5f9214c548..7355c35131 100644 --- a/services/surfaceflinger/tests/tracing/TransactionTraceTestSuite.cpp +++ b/services/surfaceflinger/tests/tracing/TransactionTraceTestSuite.cpp @@ -20,6 +20,7 @@ #include <fstream> #include <iostream> #include <string> +#include <unordered_map> #include <LayerTraceGenerator.h> #include <Tracing/TransactionProtoParser.h> @@ -84,9 +85,9 @@ protected: std::vector<std::filesystem::path> TransactionTraceTestSuite::sTransactionTraces{}; struct LayerInfo { - int id; + int32_t id; std::string name; - int parent; + int32_t parent; int z; uint64_t curr_frame; float x; @@ -143,16 +144,27 @@ TEST_P(TransactionTraceTestSuite, validateEndState) { expectedLayers.reserve(static_cast<size_t>(expectedLastEntry.layers().layers_size())); for (int i = 0; i < expectedLastEntry.layers().layers_size(); i++) { auto layer = expectedLastEntry.layers().layers(i); - expectedLayers.push_back(getLayerInfoFromProto(layer)); + LayerInfo layerInfo = getLayerInfoFromProto(layer); + expectedLayers.push_back(layerInfo); } std::sort(expectedLayers.begin(), expectedLayers.end(), compareById); + std::unordered_map<int32_t /* snapshotId*/, int32_t /*layerId*/> snapshotIdToLayerId; std::vector<LayerInfo> actualLayers; actualLayers.reserve(static_cast<size_t>(actualLastEntry.layers().layers_size())); for (int i = 0; i < actualLastEntry.layers().layers_size(); i++) { auto layer = actualLastEntry.layers().layers(i); - actualLayers.push_back(getLayerInfoFromProto(layer)); + LayerInfo layerInfo = getLayerInfoFromProto(layer); + snapshotIdToLayerId[layerInfo.id] = static_cast<int32_t>(layer.original_id()); + actualLayers.push_back(layerInfo); + } + + for (auto& layer : actualLayers) { + layer.id = snapshotIdToLayerId[layer.id]; + auto it = snapshotIdToLayerId.find(layer.parent); + layer.parent = it == snapshotIdToLayerId.end() ? -1 : it->second; } + std::sort(actualLayers.begin(), actualLayers.end(), compareById); size_t i = 0; diff --git a/services/surfaceflinger/tests/tracing/testdata/layers_trace_boot.winscope b/services/surfaceflinger/tests/tracing/testdata/layers_trace_boot.winscope Binary files differindex 9e4005c2cf..296d2fdec6 100644 --- a/services/surfaceflinger/tests/tracing/testdata/layers_trace_boot.winscope +++ b/services/surfaceflinger/tests/tracing/testdata/layers_trace_boot.winscope diff --git a/services/surfaceflinger/tests/tracing/testdata/layers_trace_nodisplayfound.winscope b/services/surfaceflinger/tests/tracing/testdata/layers_trace_nodisplayfound.winscope Binary files differindex 16a91ee6ee..ae5441550d 100644 --- a/services/surfaceflinger/tests/tracing/testdata/layers_trace_nodisplayfound.winscope +++ b/services/surfaceflinger/tests/tracing/testdata/layers_trace_nodisplayfound.winscope diff --git a/services/surfaceflinger/tests/tracing/testdata/transactions_trace_boot.winscope b/services/surfaceflinger/tests/tracing/testdata/transactions_trace_boot.winscope Binary files differindex 8356ae7992..8d03df4735 100644 --- a/services/surfaceflinger/tests/tracing/testdata/transactions_trace_boot.winscope +++ b/services/surfaceflinger/tests/tracing/testdata/transactions_trace_boot.winscope diff --git a/services/surfaceflinger/tests/tracing/testdata/transactions_trace_nodisplayfound.winscope b/services/surfaceflinger/tests/tracing/testdata/transactions_trace_nodisplayfound.winscope Binary files differindex cd62ab8ce0..022861c7ea 100644 --- a/services/surfaceflinger/tests/tracing/testdata/transactions_trace_nodisplayfound.winscope +++ b/services/surfaceflinger/tests/tracing/testdata/transactions_trace_nodisplayfound.winscope diff --git a/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp b/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp index b6427c0ffb..3dea189ca0 100644 --- a/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp +++ b/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp @@ -19,6 +19,7 @@ #include <limits> // std::numeric_limits #include <gui/SurfaceComposerClient.h> +#include "LayerProtoHelper.h" #include "Tracing/TransactionProtoParser.h" @@ -27,7 +28,6 @@ using namespace android::surfaceflinger; namespace android { TEST(TransactionProtoParserTest, parse) { - const sp<IBinder> layerHandle = sp<BBinder>::make(); const sp<IBinder> displayHandle = sp<BBinder>::make(); TransactionState t1; t1.originPid = 1; @@ -37,7 +37,6 @@ TEST(TransactionProtoParserTest, parse) { t1.postTime = 5; layer_state_t layer; - layer.layerId = 6; layer.what = std::numeric_limits<uint64_t>::max(); layer.what &= ~static_cast<uint64_t>(layer_state_t::eBufferChanged); layer.x = 7; @@ -48,10 +47,9 @@ TEST(TransactionProtoParserTest, parse) { for (uint32_t i = 0; i < layerCount; i++) { ResolvedComposerState s; if (i == 1) { - layer.parentSurfaceControlForChild = - sp<SurfaceControl>::make(SurfaceComposerClient::getDefault(), layerHandle, 42, - "#42"); + s.parentId = 42; } + s.layerId = 6 + i; s.state = layer; t1.states.emplace_back(s); } @@ -72,18 +70,10 @@ TEST(TransactionProtoParserTest, parse) { class TestMapper : public TransactionProtoParser::FlingerDataMapper { public: - sp<IBinder> layerHandle; sp<IBinder> displayHandle; - TestMapper(sp<IBinder> layerHandle, sp<IBinder> displayHandle) - : layerHandle(layerHandle), displayHandle(displayHandle) {} + TestMapper(sp<IBinder> displayHandle) : displayHandle(displayHandle) {} - sp<IBinder> getLayerHandle(int32_t id) const override { - return (id == 42) ? layerHandle : nullptr; - } - int64_t getLayerId(const sp<IBinder>& handle) const override { - return (handle == layerHandle) ? 42 : -1; - } sp<IBinder> getDisplayHandle(int32_t id) const { return (id == 43) ? displayHandle : nullptr; } @@ -92,7 +82,7 @@ TEST(TransactionProtoParserTest, parse) { } }; - TransactionProtoParser parser(std::make_unique<TestMapper>(layerHandle, displayHandle)); + TransactionProtoParser parser(std::make_unique<TestMapper>(displayHandle)); proto::TransactionState proto = parser.toProto(t1); TransactionState t2 = parser.fromProto(proto); @@ -105,8 +95,8 @@ TEST(TransactionProtoParserTest, parse) { ASSERT_EQ(t1.states.size(), t2.states.size()); ASSERT_EQ(t1.states[0].state.x, t2.states[0].state.x); ASSERT_EQ(t1.states[0].state.matrix.dsdx, t2.states[0].state.matrix.dsdx); - ASSERT_EQ(t1.states[1].state.parentSurfaceControlForChild->getHandle(), - t2.states[1].state.parentSurfaceControlForChild->getHandle()); + ASSERT_EQ(t1.states[1].layerId, t2.states[1].layerId); + ASSERT_EQ(t1.states[1].parentId, t2.states[1].parentId); ASSERT_EQ(t1.displays.size(), t2.displays.size()); ASSERT_EQ(t1.displays[1].width, t2.displays[1].width); diff --git a/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp b/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp index 482c3a8e50..74541ace0b 100644 --- a/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp +++ b/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp @@ -18,7 +18,11 @@ #include <gtest/gtest.h> #include <gui/SurfaceComposerClient.h> +#include <cstdint> +#include "Client.h" +#include "FrontEnd/LayerCreationArgs.h" +#include "FrontEnd/Update.h" #include "Tracing/RingBuffer.h" #include "Tracing/TransactionTracing.h" @@ -42,14 +46,15 @@ protected: } void queueAndCommitTransaction(int64_t vsyncId) { + frontend::Update update; TransactionState transaction; transaction.id = static_cast<uint64_t>(vsyncId * 3); transaction.originUid = 1; transaction.originPid = 2; mTracing.addQueuedTransaction(transaction); std::vector<TransactionState> transactions; - transactions.emplace_back(transaction); - mTracing.addCommittedTransactions(transactions, vsyncId); + update.transactions.emplace_back(transaction); + mTracing.addCommittedTransactions(vsyncId, 0, update, {}, false); flush(vsyncId); } @@ -57,13 +62,25 @@ protected: const std::vector<TransactionState>& expectedTransactions, int64_t expectedVsyncId) { EXPECT_EQ(actualProto.vsync_id(), expectedVsyncId); - EXPECT_EQ(actualProto.transactions().size(), + ASSERT_EQ(actualProto.transactions().size(), static_cast<int32_t>(expectedTransactions.size())); for (uint32_t i = 0; i < expectedTransactions.size(); i++) { EXPECT_EQ(actualProto.transactions(static_cast<int32_t>(i)).pid(), expectedTransactions[i].originPid); } } + + LayerCreationArgs getLayerCreationArgs(uint32_t layerId, uint32_t parentId, + uint32_t layerIdToMirror, uint32_t flags, + bool addToRoot) { + LayerCreationArgs args; + args.sequence = layerId; + args.parentId = parentId; + args.layerIdToMirror = layerIdToMirror; + args.flags = flags; + args.addToRoot = addToRoot; + return args; + } }; TEST_F(TransactionTracingTest, addTransactions) { @@ -79,57 +96,59 @@ TEST_F(TransactionTracingTest, addTransactions) { // Split incoming transactions into two and commit them in reverse order to test out of order // commits. - std::vector<TransactionState> firstTransactionSet = - std::vector<TransactionState>(transactions.begin() + 50, transactions.end()); int64_t firstTransactionSetVsyncId = 42; - mTracing.addCommittedTransactions(firstTransactionSet, firstTransactionSetVsyncId); + frontend::Update firstUpdate; + firstUpdate.transactions = + std::vector<TransactionState>(transactions.begin() + 50, transactions.end()); + mTracing.addCommittedTransactions(firstTransactionSetVsyncId, 0, firstUpdate, {}, false); int64_t secondTransactionSetVsyncId = 43; - std::vector<TransactionState> secondTransactionSet = + frontend::Update secondUpdate; + secondUpdate.transactions = std::vector<TransactionState>(transactions.begin(), transactions.begin() + 50); - mTracing.addCommittedTransactions(secondTransactionSet, secondTransactionSetVsyncId); + mTracing.addCommittedTransactions(secondTransactionSetVsyncId, 0, secondUpdate, {}, false); flush(secondTransactionSetVsyncId); proto::TransactionTraceFile proto = writeToProto(); - EXPECT_EQ(proto.entry().size(), 2); - verifyEntry(proto.entry(0), firstTransactionSet, firstTransactionSetVsyncId); - verifyEntry(proto.entry(1), secondTransactionSet, secondTransactionSetVsyncId); + ASSERT_EQ(proto.entry().size(), 2); + verifyEntry(proto.entry(0), firstUpdate.transactions, firstTransactionSetVsyncId); + verifyEntry(proto.entry(1), secondUpdate.transactions, secondTransactionSetVsyncId); } class TransactionTracingLayerHandlingTest : public TransactionTracingTest { protected: void SetUp() override { - // add layers mTracing.setBufferSize(SMALL_BUFFER_SIZE); - const sp<IBinder> fakeLayerHandle = sp<BBinder>::make(); - mTracing.onLayerAdded(fakeLayerHandle->localBinder(), mParentLayerId, "parent", - 123 /* flags */, -1 /* parentId */); - const sp<IBinder> fakeChildLayerHandle = sp<BBinder>::make(); - mTracing.onLayerAdded(fakeChildLayerHandle->localBinder(), mChildLayerId, "child", - 456 /* flags */, mParentLayerId); - - // add some layer transaction + + // add layers and add some layer transaction { + frontend::Update update; + update.layerCreationArgs.emplace_back(std::move( + getLayerCreationArgs(mParentLayerId, /*parentId=*/UNASSIGNED_LAYER_ID, + /*layerIdToMirror=*/UNASSIGNED_LAYER_ID, /*flags=*/123, + /*addToRoot=*/true))); + update.layerCreationArgs.emplace_back(std::move( + getLayerCreationArgs(mChildLayerId, mParentLayerId, + /*layerIdToMirror=*/UNASSIGNED_LAYER_ID, /*flags=*/456, + /*addToRoot=*/true))); TransactionState transaction; transaction.id = 50; ResolvedComposerState layerState; - layerState.state.surface = fakeLayerHandle; + layerState.layerId = mParentLayerId; layerState.state.what = layer_state_t::eLayerChanged; layerState.state.z = 42; transaction.states.emplace_back(layerState); ResolvedComposerState childState; - childState.state.surface = fakeChildLayerHandle; + childState.layerId = mChildLayerId; childState.state.what = layer_state_t::eLayerChanged; childState.state.z = 43; transaction.states.emplace_back(childState); mTracing.addQueuedTransaction(transaction); - std::vector<TransactionState> transactions; - transactions.emplace_back(transaction); + update.transactions.emplace_back(transaction); VSYNC_ID_FIRST_LAYER_CHANGE = ++mVsyncId; - mTracing.onLayerAddedToDrawingState(mParentLayerId, VSYNC_ID_FIRST_LAYER_CHANGE); - mTracing.onLayerAddedToDrawingState(mChildLayerId, VSYNC_ID_FIRST_LAYER_CHANGE); - mTracing.addCommittedTransactions(transactions, VSYNC_ID_FIRST_LAYER_CHANGE); + mTracing.addCommittedTransactions(VSYNC_ID_FIRST_LAYER_CHANGE, 0, update, {}, false); + flush(VSYNC_ID_FIRST_LAYER_CHANGE); } @@ -139,17 +158,17 @@ protected: TransactionState transaction; transaction.id = 51; ResolvedComposerState layerState; - layerState.state.surface = fakeLayerHandle; + layerState.layerId = mParentLayerId; layerState.state.what = layer_state_t::eLayerChanged | layer_state_t::ePositionChanged; layerState.state.z = 41; layerState.state.x = 22; transaction.states.emplace_back(layerState); mTracing.addQueuedTransaction(transaction); - std::vector<TransactionState> transactions; - transactions.emplace_back(transaction); + frontend::Update update; + update.transactions.emplace_back(transaction); VSYNC_ID_SECOND_LAYER_CHANGE = ++mVsyncId; - mTracing.addCommittedTransactions(transactions, VSYNC_ID_SECOND_LAYER_CHANGE); + mTracing.addCommittedTransactions(VSYNC_ID_SECOND_LAYER_CHANGE, 0, update, {}, false); flush(VSYNC_ID_SECOND_LAYER_CHANGE); } @@ -163,8 +182,8 @@ protected: queueAndCommitTransaction(++mVsyncId); } - int mParentLayerId = 1; - int mChildLayerId = 2; + uint32_t mParentLayerId = 1; + uint32_t mChildLayerId = 2; int64_t mVsyncId = 0; int64_t VSYNC_ID_FIRST_LAYER_CHANGE; int64_t VSYNC_ID_SECOND_LAYER_CHANGE; @@ -232,42 +251,42 @@ TEST_F(TransactionTracingLayerHandlingTest, startingStateSurvivesBufferFlush) { class TransactionTracingMirrorLayerTest : public TransactionTracingTest { protected: void SetUp() override { - // add layers mTracing.setBufferSize(SMALL_BUFFER_SIZE); - const sp<IBinder> fakeLayerHandle = sp<BBinder>::make(); - mTracing.onLayerAdded(fakeLayerHandle->localBinder(), mLayerId, "Test Layer", - 123 /* flags */, -1 /* parentId */); - const sp<IBinder> fakeMirrorLayerHandle = sp<BBinder>::make(); - mTracing.onMirrorLayerAdded(fakeMirrorLayerHandle->localBinder(), mMirrorLayerId, "Mirror", - mLayerId); - mTracing.onLayerAddedToDrawingState(mLayerId, mVsyncId); - mTracing.onLayerAddedToDrawingState(mMirrorLayerId, mVsyncId); - - // add some layer transaction + + // add layers and some layer transaction { + frontend::Update update; + update.layerCreationArgs.emplace_back( + getLayerCreationArgs(mLayerId, /*parentId=*/UNASSIGNED_LAYER_ID, + /*layerIdToMirror=*/UNASSIGNED_LAYER_ID, /*flags=*/123, + /*addToRoot=*/true)); + update.layerCreationArgs.emplace_back( + getLayerCreationArgs(mMirrorLayerId, UNASSIGNED_LAYER_ID, + /*layerIdToMirror=*/mLayerId, /*flags=*/0, + /*addToRoot=*/false)); + TransactionState transaction; transaction.id = 50; ResolvedComposerState layerState; - layerState.state.surface = fakeLayerHandle; + layerState.layerId = mLayerId; layerState.state.what = layer_state_t::eLayerChanged; layerState.state.z = 42; transaction.states.emplace_back(layerState); ResolvedComposerState mirrorState; - mirrorState.state.surface = fakeMirrorLayerHandle; + mirrorState.layerId = mMirrorLayerId; mirrorState.state.what = layer_state_t::eLayerChanged; mirrorState.state.z = 43; transaction.states.emplace_back(mirrorState); mTracing.addQueuedTransaction(transaction); - std::vector<TransactionState> transactions; - transactions.emplace_back(transaction); - mTracing.addCommittedTransactions(transactions, mVsyncId); + update.transactions.emplace_back(transaction); + mTracing.addCommittedTransactions(mVsyncId, 0, update, {}, false); flush(mVsyncId); } } - int mLayerId = 5; - int mMirrorLayerId = 55; + uint32_t mLayerId = 5; + uint32_t mMirrorLayerId = 55; int64_t mVsyncId = 0; int64_t VSYNC_ID_FIRST_LAYER_CHANGE; int64_t VSYNC_ID_SECOND_LAYER_CHANGE; |