SF: Introduce LayerTraceGenerator
Generates layer traces from transaction traces. The tool is a custom
surface flinger build that mocks out most everything else apart from
the front end logic. Transaction traces are written when the
transaction is applied, along with a timestamp and vsync id. The
transactions are parsed from proto, and applied to recreate the
layer state and output the result into a layer trace.
Test: presubmit
Bug: 200284593
Change-Id: If90a23b9310dbafbdca597b7f5178e40c8b86022
diff --git a/services/surfaceflinger/Tracing/tools/Android.bp b/services/surfaceflinger/Tracing/tools/Android.bp
new file mode 100644
index 0000000..114f1eb
--- /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 0000000..947fdce
--- /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 0000000..ee1ea6c
--- /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 0000000..f3cf42d
--- /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 0000000..143c14f
--- /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 0000000..baa93f1
--- /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 1db5e61..58cd7ba 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -42,6 +42,7 @@
cc_test {
name: "libsurfaceflinger_unittest",
defaults: [
+ "libsurfaceflinger_mocks_defaults",
"skia_renderengine_deps",
"surfaceflinger_defaults",
],
@@ -122,6 +123,10 @@
"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 @@
"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 67e47e7..d83b9bb 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -177,8 +177,10 @@
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 @@
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 @@
? 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 @@
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 @@
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;