[sf] Add TransactionTraceWriterTests
Bug: 238781169, 294989213
Test: presubmit
Change-Id: Ibeb4118b08424ae28f4f48442f977a433aeff18e
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 1ef381c..d8b920e 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -863,30 +863,32 @@
ALOGE("Run StartPropertySetThread failed!");
}
- if (mTransactionTracing) {
- TransactionTraceWriter::getInstance().setWriterFunction([&](const std::string& prefix,
- bool overwrite) {
- auto writeFn = [&]() {
- const std::string filename =
- TransactionTracing::DIR_NAME + prefix + TransactionTracing::FILE_NAME;
- if (!overwrite && access(filename.c_str(), F_OK) == 0) {
- ALOGD("TransactionTraceWriter: file=%s already exists", filename.c_str());
- return;
- }
- mTransactionTracing->flush();
- mTransactionTracing->writeToFile(filename);
- };
- if (std::this_thread::get_id() == mMainThreadId) {
- writeFn();
- } else {
- mScheduler->schedule(writeFn).get();
- }
- });
- }
-
+ initTransactionTraceWriter();
ALOGV("Done initializing");
}
+void SurfaceFlinger::initTransactionTraceWriter() {
+ if (!mTransactionTracing) {
+ return;
+ }
+ TransactionTraceWriter::getInstance().setWriterFunction(
+ [&](const std::string& filename, bool overwrite) {
+ auto writeFn = [&]() {
+ if (!overwrite && access(filename.c_str(), F_OK) == 0) {
+ ALOGD("TransactionTraceWriter: file=%s already exists", filename.c_str());
+ return;
+ }
+ mTransactionTracing->flush();
+ mTransactionTracing->writeToFile(filename);
+ };
+ if (std::this_thread::get_id() == mMainThreadId) {
+ writeFn();
+ } else {
+ mScheduler->schedule(writeFn).get();
+ }
+ });
+}
+
void SurfaceFlinger::readPersistentProperties() {
Mutex::Autolock _l(mStateLock);
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 4d17fa7..175209f 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -1134,7 +1134,7 @@
ui::Rotation getPhysicalDisplayOrientation(DisplayId, bool isPrimary) const
REQUIRES(mStateLock);
void traverseLegacyLayers(const LayerVector::Visitor& visitor) const;
-
+ void initTransactionTraceWriter();
sp<StartPropertySetThread> mStartPropertySetThread;
surfaceflinger::Factory& mFactory;
pid_t mPid;
diff --git a/services/surfaceflinger/Tracing/TransactionTracing.h b/services/surfaceflinger/Tracing/TransactionTracing.h
index 31bca5f..422b5f3 100644
--- a/services/surfaceflinger/Tracing/TransactionTracing.h
+++ b/services/surfaceflinger/Tracing/TransactionTracing.h
@@ -73,12 +73,16 @@
static constexpr auto TRACING_VERSION = 1;
private:
+ friend class TransactionTraceWriter;
friend class TransactionTracingTest;
friend class SurfaceFlinger;
static constexpr auto DIR_NAME = "/data/misc/wmtrace/";
static constexpr auto FILE_NAME = "transactions_trace.winscope";
static constexpr auto FILE_PATH = "/data/misc/wmtrace/transactions_trace.winscope";
+ static std::string getFilePath(const std::string& prefix) {
+ return DIR_NAME + prefix + FILE_NAME;
+ }
mutable std::mutex mTraceLock;
TransactionRingBuffer<proto::TransactionTraceFile, proto::TransactionTraceEntry> mBuffer
@@ -138,10 +142,16 @@
public:
void setWriterFunction(
- std::function<void(const std::string& prefix, bool overwrite)> function) {
+ std::function<void(const std::string& filename, bool overwrite)> function) {
mWriterFunction = std::move(function);
}
- void invoke(const std::string& prefix, bool overwrite) { mWriterFunction(prefix, overwrite); }
+ void invoke(const std::string& prefix, bool overwrite) {
+ mWriterFunction(TransactionTracing::getFilePath(prefix), overwrite);
+ }
+ /* pass in a complete file path for testing */
+ void invokeForTest(const std::string& filename, bool overwrite) {
+ mWriterFunction(filename, overwrite);
+ }
};
} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index 3dd33b9..7d8796f 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -66,6 +66,7 @@
// option to false temporarily.
address: true,
},
+ static_libs: ["libc++fs"],
srcs: [
":libsurfaceflinger_mock_sources",
":libsurfaceflinger_sources",
@@ -128,6 +129,7 @@
"TransactionFrameTracerTest.cpp",
"TransactionProtoParserTest.cpp",
"TransactionSurfaceFrameTest.cpp",
+ "TransactionTraceWriterTest.cpp",
"TransactionTracingTest.cpp",
"TunnelModeEnabledReporterTest.cpp",
"StrongTypingTest.cpp",
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 02fa415..8458aa3 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -651,6 +651,11 @@
auto fromHandle(const sp<IBinder>& handle) { return LayerHandle::getLayer(handle); }
+ auto initTransactionTraceWriter() {
+ mFlinger->mTransactionTracing.emplace();
+ return mFlinger->initTransactionTraceWriter();
+ }
+
~TestableSurfaceFlinger() {
// All these pointer and container clears help ensure that GMock does
// not report a leaked object, since the SurfaceFlinger instance may
@@ -664,6 +669,7 @@
mFlinger->mCompositionEngine->setHwComposer(std::unique_ptr<HWComposer>());
mFlinger->mRenderEngine = std::unique_ptr<renderengine::RenderEngine>();
mFlinger->mCompositionEngine->setRenderEngine(mFlinger->mRenderEngine.get());
+ mFlinger->mTransactionTracing.reset();
}
/* ------------------------------------------------------------------------
diff --git a/services/surfaceflinger/tests/unittests/TransactionTraceWriterTest.cpp b/services/surfaceflinger/tests/unittests/TransactionTraceWriterTest.cpp
new file mode 100644
index 0000000..379135e
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/TransactionTraceWriterTest.cpp
@@ -0,0 +1,79 @@
+/*
+ * 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.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "TransactionTraceWriterTest"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <log/log.h>
+#include <filesystem>
+
+#include "TestableSurfaceFlinger.h"
+
+namespace android {
+
+class TransactionTraceWriterTest : public testing::Test {
+protected:
+ std::string mFilename = "/data/local/tmp/testfile_transaction_trace.winscope";
+
+ void SetUp() { mFlinger.initTransactionTraceWriter(); }
+ void TearDown() { std::filesystem::remove(mFilename); }
+
+ void verifyTraceFile() {
+ std::fstream file(mFilename, std::ios::in);
+ ASSERT_TRUE(file.is_open());
+ std::string line;
+ char magicNumber[8];
+ file.read(magicNumber, 8);
+ EXPECT_EQ("\tTNXTRAC", std::string(magicNumber, magicNumber + 8));
+ }
+
+ TestableSurfaceFlinger mFlinger;
+};
+
+TEST_F(TransactionTraceWriterTest, canWriteToFile) {
+ TransactionTraceWriter::getInstance().invokeForTest(mFilename, /* overwrite */ true);
+ EXPECT_EQ(access(mFilename.c_str(), F_OK), 0);
+ verifyTraceFile();
+}
+
+TEST_F(TransactionTraceWriterTest, canOverwriteFile) {
+ std::string testLine = "test";
+ {
+ std::ofstream file(mFilename, std::ios::out);
+ file << testLine;
+ }
+ TransactionTraceWriter::getInstance().invokeForTest(mFilename, /* overwrite */ true);
+ verifyTraceFile();
+}
+
+TEST_F(TransactionTraceWriterTest, doNotOverwriteFile) {
+ std::string testLine = "test";
+ {
+ std::ofstream file(mFilename, std::ios::out);
+ file << testLine;
+ }
+ TransactionTraceWriter::getInstance().invokeForTest(mFilename, /* overwrite */ false);
+ {
+ std::fstream file(mFilename, std::ios::in);
+ ASSERT_TRUE(file.is_open());
+ std::string line;
+ std::getline(file, line);
+ EXPECT_EQ(line, testLine);
+ }
+}
+} // namespace android
\ No newline at end of file