diff options
8 files changed, 485 insertions, 8 deletions
diff --git a/services/surfaceflinger/Tracing/tools/Android.bp b/services/surfaceflinger/Tracing/tools/Android.bp new file mode 100644 index 0000000000..114f1ebb2d --- /dev/null +++ b/services/surfaceflinger/Tracing/tools/Android.bp @@ -0,0 +1,46 @@ +// Copyright (C) 2022 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. + +cc_binary { + name: "layertracegenerator", + defaults: [ + "libsurfaceflinger_mocks_defaults", + "surfaceflinger_defaults", + "skia_renderengine_deps", + ], + srcs: [ + ":libsurfaceflinger_sources", + ":libsurfaceflinger_mock_sources", + ":layertracegenerator_sources", + "main.cpp", + ], + static_libs: [ + "libgtest", + ], + header_libs: [ + "libsurfaceflinger_mocks_headers", + ], +} + +filegroup { + name: "layertracegenerator_sources", + srcs: [ + "LayerTraceGenerator.cpp", + ], +} + +cc_library_headers { + name: "layertracegenerator_headers", + export_include_dirs: ["."], +} diff --git a/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp b/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp new file mode 100644 index 0000000000..947fdcee4e --- /dev/null +++ b/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp @@ -0,0 +1,284 @@ +/* + * Copyright (C) 2022 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 "LayerTraceGenerator" + +#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/FakeExternalTexture.h> +#include <renderengine/mock/RenderEngine.h> +#include <utils/String16.h> +#include <string> + +#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<SurfaceInterceptor> createSurfaceInterceptor() override { + return new android::impl::SurfaceInterceptor(); + } + + sp<StartPropertySetThread> createStartPropertySetThread( + bool /* timestampPropertyValue */) override { + return nullptr; + } + + sp<DisplayDevice> createDisplayDevice(DisplayDeviceCreationArgs& /* creationArgs */) override { + return nullptr; + } + + sp<GraphicBuffer> createGraphicBuffer(uint32_t /* width */, uint32_t /* height */, + PixelFormat /* format */, uint32_t /* layerCount */, + uint64_t /* usage */, + std::string /* requestorName */) override { + return nullptr; + } + + void createBufferQueue(sp<IGraphicBufferProducer>* /* outProducer */, + sp<IGraphicBufferConsumer>* /* outConsumer */, + bool /* consumerIsSurfaceFlinger */) override {} + + sp<IGraphicBufferProducer> createMonitoredProducer( + const sp<IGraphicBufferProducer>& /* producer */, + const sp<SurfaceFlinger>& /* flinger */, const wp<Layer>& /* layer */) override { + return nullptr; + } + + sp<BufferLayerConsumer> createBufferLayerConsumer( + const sp<IGraphicBufferConsumer>& /* consumer */, + renderengine::RenderEngine& /* renderEngine */, uint32_t /* textureName */, + Layer* /* layer */) override { + return nullptr; + } + + 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<ContainerLayer> createContainerLayer(const LayerCreationArgs& args) { + return sp<ContainerLayer>::make(args); + } + + sp<BufferStateLayer> createBufferStateLayer(const LayerCreationArgs& args) { + return new BufferStateLayer(args); + } + + sp<EffectLayer> createEffectLayer(const LayerCreationArgs& args) { + return new EffectLayer(args); + } + + sp<BufferQueueLayer> createBufferQueueLayer(const LayerCreationArgs&) override { + return nullptr; + } + + 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 MockSurfaceFlinger : public SurfaceFlinger { +public: + MockSurfaceFlinger(Factory& factory) + : SurfaceFlinger(factory, SurfaceFlinger::SkipInitialization) {} + std::shared_ptr<renderengine::ExternalTexture> getExternalTextureFromBufferData( + const BufferData& bufferData, const char* /* layerName */) const override { + return std::make_shared<renderengine::mock::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 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; + } +}; + +bool LayerTraceGenerator::generate(const proto::TransactionTraceFile& traceFile, + const char* outputLayersTracePath) { + if (traceFile.entry_size() == 0) { + return false; + } + + Factory mFactory; + sp<MockSurfaceFlinger> flinger = new MockSurfaceFlinger(mFactory); + TestableSurfaceFlinger mFlinger(flinger); + mFlinger.setupRenderEngine( + std::make_unique<testing::NiceMock<renderengine::mock::RenderEngine>>()); + mock::VsyncController* mVsyncController = new testing::NiceMock<mock::VsyncController>(); + mock::VSyncTracker* mVSyncTracker = new testing::NiceMock<mock::VSyncTracker>(); + mock::EventThread* mEventThread = new testing::NiceMock<mock::EventThread>(); + mock::EventThread* mSFEventThread = new testing::NiceMock<mock::EventThread>(); + mFlinger.setupScheduler(std::unique_ptr<scheduler::VsyncController>(mVsyncController), + std::unique_ptr<scheduler::VSyncTracker>(mVSyncTracker), + std::unique_ptr<EventThread>(mEventThread), + std::unique_ptr<EventThread>(mSFEventThread), + TestableSurfaceFlinger::SchedulerCallbackImpl::kNoOp, + TestableSurfaceFlinger::kOneDisplayMode, true /* useNiceMock */); + + Hwc2::mock::Composer* mComposer = new testing::NiceMock<Hwc2::mock::Composer>(); + mFlinger.setupComposer(std::unique_ptr<Hwc2::Composer>(mComposer)); + mFlinger.mutableMaxRenderTargetSize() = 16384; + + flinger->setLayerTracingFlags(LayerTracing::TRACE_BUFFERS | LayerTracing::TRACE_INPUT | + LayerTracing::TRACE_BUFFERS); + flinger->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)); + + nsecs_t frameTime; + int64_t vsyncId; + ALOGD("Generating %d transactions...", traceFile.entry_size()); + for (int i = 0; i < traceFile.entry_size(); i++) { + proto::TransactionTraceEntry entry = traceFile.entry(i); + ALOGV(" Entry %04d/%04d for time=%" PRId64 " vsyncid=%" PRId64 + " layers +%d -%d transactions=%d", + i, traceFile.entry_size(), entry.elapsed_realtime_nanos(), entry.vsync_id(), + entry.added_layers_size(), entry.removed_layers_size(), entry.transactions_size()); + + for (int j = 0; j < entry.added_layers_size(); j++) { + // create layers + TracingLayerCreationArgs tracingArgs; + parser.fromProto(entry.added_layers(j), tracingArgs); + + sp<IBinder> outHandle; + int32_t outLayerId; + LayerCreationArgs args(mFlinger.flinger(), nullptr /* client */, tracingArgs.name, + tracingArgs.flags, LayerMetadata()); + args.sequence = 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 { + parentHandle = dataMapper->getLayerHandle(tracingArgs.parentId); + } + mFlinger.createLayer(args, &outHandle, parentHandle, &outLayerId, + nullptr /* parentLayer */, nullptr /* outTransformHint */); + } else { + sp<IBinder> mirrorFromHandle = dataMapper->getLayerHandle(tracingArgs.mirrorFromId); + mFlinger.mirrorLayer(args, mirrorFromHandle, &outHandle, &outLayerId); + } + LOG_ALWAYS_FATAL_IF(outLayerId != tracingArgs.layerId, + "Could not create layer expected:%d actual:%d", tracingArgs.layerId, + outLayerId); + dataMapper->mLayerHandles[tracingArgs.layerId] = outHandle; + } + + for (int j = 0; j < entry.transactions_size(); j++) { + // apply transactions + TransactionState transaction = parser.fromProto(entry.transactions(j)); + mFlinger.setTransactionState(transaction.frameTimelineInfo, transaction.states, + transaction.displays, transaction.flags, + transaction.applyToken, transaction.inputWindowCommands, + transaction.desiredPresentTime, + transaction.isAutoTimestamp, {}, + transaction.hasListenerCallbacks, + transaction.listenerCallbacks, transaction.id); + } + + for (int j = 0; j < entry.removed_layer_handles_size(); j++) { + dataMapper->mLayerHandles.erase(entry.removed_layer_handles(j)); + } + + frameTime = entry.elapsed_realtime_nanos(); + vsyncId = entry.vsync_id(); + mFlinger.commit(frameTime, vsyncId); + } + + flinger->stopLayerTracing(outputLayersTracePath); + ALOGD("End of generating trace file. File written to %s", outputLayersTracePath); + dataMapper->mLayerHandles.clear(); + return true; +} + +} // namespace android
\ No newline at end of file diff --git a/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.h b/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.h new file mode 100644 index 0000000000..ee1ea6ce8b --- /dev/null +++ b/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2022 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 <Tracing/TransactionTracing.h> + +namespace android { +class LayerTraceGenerator { +public: + bool generate(const proto::TransactionTraceFile&, const char* outputLayersTracePath); +}; +} // namespace android
\ No newline at end of file diff --git a/services/surfaceflinger/Tracing/tools/main.cpp b/services/surfaceflinger/Tracing/tools/main.cpp new file mode 100644 index 0000000000..f3cf42d7ab --- /dev/null +++ b/services/surfaceflinger/Tracing/tools/main.cpp @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2022 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 "LayerTraceGenerator" + +#include <fstream> +#include <iostream> +#include <string> + +#include "LayerTraceGenerator.h" + +using namespace android; + +int main(int argc, char** argv) { + if (argc > 3) { + std::cout << "Usage: " << argv[0] + << " [transaction-trace-path] [output-layers-trace-path]\n"; + return -1; + } + + const char* transactionTracePath = + (argc > 1) ? argv[1] : "/data/misc/wmtrace/transactions_trace.winscope"; + std::cout << "Parsing " << transactionTracePath << "\n"; + std::fstream input(transactionTracePath, std::ios::in | std::ios::binary); + if (!input) { + std::cout << "Error: Could not open " << transactionTracePath; + return -1; + } + + proto::TransactionTraceFile transactionTraceFile; + if (!transactionTraceFile.ParseFromIstream(&input)) { + std::cout << "Error: Failed to parse " << transactionTracePath; + return -1; + } + + const char* outputLayersTracePath = + (argc == 3) ? argv[2] : "/data/misc/wmtrace/layers_trace.winscope"; + ; + ALOGD("Generating %s...", outputLayersTracePath); + std::cout << "Generating " << outputLayersTracePath << "\n"; + if (!LayerTraceGenerator().generate(transactionTraceFile, outputLayersTracePath)) { + std::cout << "Error: Failed to generate layers trace " << outputLayersTracePath; + return -1; + } + return 0; +}
\ No newline at end of file diff --git a/services/surfaceflinger/Tracing/tools/readme.md b/services/surfaceflinger/Tracing/tools/readme.md new file mode 100644 index 0000000000..143c14fe20 --- /dev/null +++ b/services/surfaceflinger/Tracing/tools/readme.md @@ -0,0 +1,13 @@ +### LayerTraceGenerator ### + +Generates layer traces from transaction traces. The tool is a custom +surface flinger build that mocks out everything else apart from the +front end logic. Transaction traces are written when the transaction +is applied, along wth a timestamp and vsync id. The transactions +are parsed from proto and applied to recreate the layer state. The +result is then written as a layer trace. + +Usage: +1. build and push to device +2. run ./layertracegenerator [transaction-trace-path] [output-layers-trace-path] + diff --git a/services/surfaceflinger/Tracing/tools/run.sh b/services/surfaceflinger/Tracing/tools/run.sh new file mode 100644 index 0000000000..baa93f1a1c --- /dev/null +++ b/services/surfaceflinger/Tracing/tools/run.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash + +set -ex + +# Build, push and run layertracegenerator +$ANDROID_BUILD_TOP/build/soong/soong_ui.bash --make-mode layertracegenerator +adb wait-for-device && adb push $OUT/system/bin/layertracegenerator /data/layertracegenerator +echo "Writing transaction trace to file" +adb shell service call SurfaceFlinger 1041 i32 0 +adb shell /data/layertracegenerator +adb pull /data/misc/wmtrace/layers_trace.winscope
\ No newline at end of file diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp index 1db5e613f8..58cd7ba96a 100644 --- a/services/surfaceflinger/tests/unittests/Android.bp +++ b/services/surfaceflinger/tests/unittests/Android.bp @@ -42,6 +42,7 @@ filegroup { cc_test { name: "libsurfaceflinger_unittest", defaults: [ + "libsurfaceflinger_mocks_defaults", "skia_renderengine_deps", "surfaceflinger_defaults", ], @@ -122,6 +123,10 @@ cc_test { "VSyncReactorTest.cpp", "VsyncConfigurationTest.cpp", ], +} + +cc_defaults { + name: "libsurfaceflinger_mocks_defaults", static_libs: [ "android.hardware.common-V2-ndk", "android.hardware.common.fmq-V1-ndk", @@ -193,3 +198,8 @@ cc_test { "libsurfaceflinger_headers", ], } + +cc_library_headers { + name: "libsurfaceflinger_mocks_headers", + export_include_dirs: ["."], +} diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index 67e47e7b37..d83b9bbd40 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -177,8 +177,10 @@ class TestableSurfaceFlinger { public: using HotplugEvent = SurfaceFlinger::HotplugEvent; - TestableSurfaceFlinger() - : mFlinger(sp<SurfaceFlinger>::make(mFactory, SurfaceFlinger::SkipInitialization)) { + TestableSurfaceFlinger(sp<SurfaceFlinger> flinger = nullptr) : mFlinger(flinger) { + if (!mFlinger) { + mFlinger = sp<SurfaceFlinger>::make(mFactory, SurfaceFlinger::SkipInitialization); + } mFlinger->mAnimationTransactionTimeout = ms2ns(10); } @@ -219,7 +221,8 @@ public: std::unique_ptr<EventThread> appEventThread, std::unique_ptr<EventThread> sfEventThread, SchedulerCallbackImpl callbackImpl = SchedulerCallbackImpl::kNoOp, - DisplayModesVariant modesVariant = kOneDisplayMode) { + DisplayModesVariant modesVariant = kOneDisplayMode, + bool useNiceMock = false) { RefreshRateConfigsPtr configs; if (std::holds_alternative<RefreshRateConfigsPtr>(modesVariant)) { configs = std::move(std::get<RefreshRateConfigsPtr>(modesVariant)); @@ -256,9 +259,17 @@ public: ? static_cast<Callback&>(mNoOpSchedulerCallback) : static_cast<Callback&>(mSchedulerCallback); - mScheduler = new scheduler::TestableScheduler(std::move(vsyncController), - std::move(vsyncTracker), std::move(configs), - callback); + if (useNiceMock) { + mScheduler = + new testing::NiceMock<scheduler::TestableScheduler>(std::move(vsyncController), + std::move(vsyncTracker), + std::move(configs), + callback); + } else { + mScheduler = new scheduler::TestableScheduler(std::move(vsyncController), + std::move(vsyncTracker), + std::move(configs), callback); + } mFlinger->mAppConnectionHandle = mScheduler->createConnection(std::move(appEventThread)); mFlinger->mSfConnectionHandle = mScheduler->createConnection(std::move(sfEventThread)); @@ -455,6 +466,23 @@ public: mFlinger->onActiveDisplayChangedLocked(activeDisplay); } + auto commit(nsecs_t frameTime, int64_t vsyncId) { + const nsecs_t expectedVsyncTime = frameTime + 10'000'000; + mFlinger->commit(frameTime, vsyncId, expectedVsyncTime); + } + + auto createLayer(LayerCreationArgs& args, sp<IBinder>* outHandle, + const sp<IBinder>& parentHandle, int32_t* outLayerId, + const sp<Layer>& parentLayer, uint32_t* outTransformHint) { + return mFlinger->createLayer(args, outHandle, parentHandle, outLayerId, parentLayer, + outTransformHint); + } + + auto mirrorLayer(const LayerCreationArgs& args, const sp<IBinder>& mirrorFromHandle, + sp<IBinder>* outHandle, int32_t* outLayerId) { + return mFlinger->mirrorLayer(args, mirrorFromHandle, outHandle, outLayerId); + } + /* ------------------------------------------------------------------------ * Read-only access to private data to assert post-conditions. */ @@ -850,8 +878,7 @@ public: private: surfaceflinger::test::Factory mFactory; - sp<SurfaceFlinger> mFlinger = new SurfaceFlinger(mFactory, SurfaceFlinger::SkipInitialization); - + sp<SurfaceFlinger> mFlinger; scheduler::mock::SchedulerCallback mSchedulerCallback; scheduler::mock::NoOpSchedulerCallback mNoOpSchedulerCallback; scheduler::TestableScheduler* mScheduler = nullptr; |