Add getStalledTransactionInfo method to SurfaceComposer
Bug: 287577707
Test: presubmits
Change-Id: I9c464ee302e7bafe8d45021063368fcd984e27ec
Merged-In: I9c464ee302e7bafe8d45021063368fcd984e27ec
diff --git a/services/surfaceflinger/FrontEnd/TransactionHandler.cpp b/services/surfaceflinger/FrontEnd/TransactionHandler.cpp
index fa8eb3c..6e78e93 100644
--- a/services/surfaceflinger/FrontEnd/TransactionHandler.cpp
+++ b/services/surfaceflinger/FrontEnd/TransactionHandler.cpp
@@ -186,21 +186,36 @@
}
void TransactionHandler::onTransactionQueueStalled(uint64_t transactionId,
- sp<ITransactionCompletedListener>& listener,
- const std::string& reason) {
- if (std::find(mStalledTransactions.begin(), mStalledTransactions.end(), transactionId) !=
- mStalledTransactions.end()) {
- return;
- }
-
- mStalledTransactions.push_back(transactionId);
- listener->onTransactionQueueStalled(String8(reason.c_str()));
+ StalledTransactionInfo stalledTransactionInfo) {
+ std::lock_guard lock{mStalledMutex};
+ mStalledTransactions.emplace(transactionId, std::move(stalledTransactionInfo));
}
-void TransactionHandler::removeFromStalledTransactions(uint64_t id) {
- auto it = std::find(mStalledTransactions.begin(), mStalledTransactions.end(), id);
- if (it != mStalledTransactions.end()) {
- mStalledTransactions.erase(it);
+void TransactionHandler::removeFromStalledTransactions(uint64_t transactionId) {
+ std::lock_guard lock{mStalledMutex};
+ mStalledTransactions.erase(transactionId);
+}
+
+std::optional<TransactionHandler::StalledTransactionInfo>
+TransactionHandler::getStalledTransactionInfo(pid_t pid) {
+ std::lock_guard lock{mStalledMutex};
+ for (auto [_, stalledTransactionInfo] : mStalledTransactions) {
+ if (pid == stalledTransactionInfo.pid) {
+ return stalledTransactionInfo;
+ }
+ }
+ return std::nullopt;
+}
+
+void TransactionHandler::onLayerDestroyed(uint32_t layerId) {
+ std::lock_guard lock{mStalledMutex};
+ for (auto it = mStalledTransactions.begin(); it != mStalledTransactions.end();) {
+ if (it->second.layerId == layerId) {
+ it = mStalledTransactions.erase(it);
+ } else {
+ it++;
+ }
}
}
+
} // namespace android::surfaceflinger::frontend
diff --git a/services/surfaceflinger/FrontEnd/TransactionHandler.h b/services/surfaceflinger/FrontEnd/TransactionHandler.h
index 865835f..ff54dc5 100644
--- a/services/surfaceflinger/FrontEnd/TransactionHandler.h
+++ b/services/surfaceflinger/FrontEnd/TransactionHandler.h
@@ -18,6 +18,7 @@
#include <semaphore.h>
#include <cstdint>
+#include <optional>
#include <vector>
#include <LocklessQueue.h>
@@ -61,9 +62,18 @@
std::vector<TransactionState> flushTransactions();
void addTransactionReadyFilter(TransactionFilter&&);
void queueTransaction(TransactionState&&);
- void onTransactionQueueStalled(uint64_t transactionId, sp<ITransactionCompletedListener>&,
- const std::string& reason);
+
+ struct StalledTransactionInfo {
+ pid_t pid;
+ uint32_t layerId;
+ std::string layerName;
+ uint64_t bufferId;
+ uint64_t frameNumber;
+ };
+ void onTransactionQueueStalled(uint64_t transactionId, StalledTransactionInfo);
void removeFromStalledTransactions(uint64_t transactionId);
+ std::optional<StalledTransactionInfo> getStalledTransactionInfo(pid_t pid);
+ void onLayerDestroyed(uint32_t layerId);
private:
// For unit tests
@@ -79,7 +89,10 @@
LocklessQueue<TransactionState> mLocklessTransactionQueue;
std::atomic<size_t> mPendingTransactionCount = 0;
ftl::SmallVector<TransactionFilter, 2> mTransactionReadyFilters;
- std::vector<uint64_t> mStalledTransactions;
+
+ std::mutex mStalledMutex;
+ std::unordered_map<uint64_t /* transactionId */, StalledTransactionInfo> mStalledTransactions
+ GUARDED_BY(mStalledMutex);
};
} // namespace surfaceflinger::frontend
} // namespace android
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 9f8af90..d41318e 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -4355,9 +4355,13 @@
(flushState.queueProcessTime - transaction.postTime) >
std::chrono::nanoseconds(4s).count()) {
mTransactionHandler
- .onTransactionQueueStalled(transaction.id, listener,
- "Buffer processing hung up due to stuck "
- "fence. Indicates GPU hang");
+ .onTransactionQueueStalled(transaction.id,
+ {.pid = layer->getOwnerPid(),
+ .layerId = static_cast<uint32_t>(
+ layer->getSequence()),
+ .layerName = layer->getDebugName(),
+ .bufferId = s.bufferData->getId(),
+ .frameNumber = s.bufferData->frameNumber});
}
ATRACE_FORMAT("fence unsignaled %s", layer->getDebugName());
return TraverseBuffersReturnValues::STOP_TRAVERSAL;
@@ -5381,6 +5385,8 @@
mDestroyedHandles.emplace_back(layerId);
}
+ mTransactionHandler.onLayerDestroyed(layerId);
+
Mutex::Autolock lock(mStateLock);
markLayerPendingRemovalLocked(layer);
layer->onHandleDestroyed();
@@ -7981,6 +7987,12 @@
return NO_ERROR;
}
+status_t SurfaceFlinger::getStalledTransactionInfo(
+ int pid, std::optional<TransactionHandler::StalledTransactionInfo>& result) {
+ result = mTransactionHandler.getStalledTransactionInfo(pid);
+ return NO_ERROR;
+}
+
std::shared_ptr<renderengine::ExternalTexture> SurfaceFlinger::getExternalTextureFromBufferData(
BufferData& bufferData, const char* layerName, uint64_t transactionId) {
if (bufferData.buffer &&
@@ -9085,6 +9097,28 @@
return binderStatusFromStatusT(status);
}
+binder::Status SurfaceComposerAIDL::getStalledTransactionInfo(
+ int pid, std::optional<gui::StalledTransactionInfo>* outInfo) {
+ const int callingPid = IPCThreadState::self()->getCallingPid();
+ const int callingUid = IPCThreadState::self()->getCallingUid();
+ if (!checkPermission(sAccessSurfaceFlinger, callingPid, callingUid)) {
+ return binderStatusFromStatusT(PERMISSION_DENIED);
+ }
+
+ std::optional<TransactionHandler::StalledTransactionInfo> stalledTransactionInfo;
+ status_t status = mFlinger->getStalledTransactionInfo(pid, stalledTransactionInfo);
+ if (stalledTransactionInfo) {
+ gui::StalledTransactionInfo result;
+ result.layerName = String16{stalledTransactionInfo->layerName.c_str()},
+ result.bufferId = stalledTransactionInfo->bufferId,
+ result.frameNumber = stalledTransactionInfo->frameNumber,
+ outInfo->emplace(std::move(result));
+ } else {
+ outInfo->reset();
+ }
+ return binderStatusFromStatusT(status);
+}
+
status_t SurfaceComposerAIDL::checkAccessPermission(bool usePermissionCache) {
if (!mFlinger->callingThreadHasUnscopedSurfaceFlingerAccess(usePermissionCache)) {
IPCThreadState* ipc = IPCThreadState::self();
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index f1759a5..34f4d34 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -618,6 +618,9 @@
status_t removeWindowInfosListener(
const sp<gui::IWindowInfosListener>& windowInfosListener) const;
+ status_t getStalledTransactionInfo(
+ int pid, std::optional<TransactionHandler::StalledTransactionInfo>& result);
+
// Implements IBinder::DeathRecipient.
void binderDied(const wp<IBinder>& who) override;
@@ -1542,6 +1545,8 @@
gui::WindowInfosListenerInfo* outInfo) override;
binder::Status removeWindowInfosListener(
const sp<gui::IWindowInfosListener>& windowInfosListener) override;
+ binder::Status getStalledTransactionInfo(int pid,
+ std::optional<gui::StalledTransactionInfo>* outInfo);
private:
static const constexpr bool kUsePermissionCache = true;