summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorScott Lobdell <slobdell@google.com>2021-04-25 19:53:06 +0000
committerRob Seymour <rseymour@google.com>2021-05-06 22:32:25 +0000
commitafbe732519a96ff0a42a1c98bd59fd04080b4a96 (patch)
tree9ca836d438ca47756e4761ee4b844b85bd7e8857
parent7a303d6e8135bbd0a32075986c9f7083e0fbef23 (diff)
parent7132116dfd8bdb9c5b505db8d8a27526a4e889d8 (diff)
Merge SP1A.210425.001
Change-Id: I219cc0af128876534b77a72c36979fa1fe08ba13
-rw-r--r--.clang-format1
-rw-r--r--cmds/atrace/atrace.cpp4
-rw-r--r--cmds/dumpstate/Android.bp1
-rw-r--r--cmds/dumpstate/dumpstate.cpp3
-rw-r--r--cmds/dumpstate/tests/dumpstate_test.cpp10
-rw-r--r--cmds/dumpsys/Android.bp1
-rw-r--r--cmds/dumpsys/OWNERS3
-rw-r--r--cmds/dumpsys/dumpsys.cpp30
-rw-r--r--cmds/dumpsys/dumpsys.h7
-rw-r--r--cmds/dumpsys/tests/Android.bp3
-rw-r--r--cmds/dumpsys/tests/AndroidTest.xml2
-rw-r--r--cmds/dumpsys/tests/dumpsys_test.cpp42
-rw-r--r--cmds/installd/otapreopt_chroot.cpp5
-rw-r--r--cmds/lshal/ListCommand.cpp2
-rw-r--r--cmds/lshal/test.cpp14
-rw-r--r--cmds/servicemanager/ServiceManager.cpp79
-rw-r--r--cmds/servicemanager/ServiceManager.h2
-rw-r--r--cmds/surfacereplayer/proto/src/trace.proto6
-rw-r--r--cmds/surfacereplayer/replayer/Replayer.cpp25
-rw-r--r--cmds/surfacereplayer/replayer/Replayer.h4
-rw-r--r--data/etc/android.software.translation.xml19
-rw-r--r--data/etc/handheld_core_hardware.xml1
-rw-r--r--data/etc/tablet_core_hardware.xml1
-rw-r--r--include/android/bitmap.h1
-rw-r--r--include/android/choreographer.h5
-rw-r--r--include/android/font.h6
-rw-r--r--include/android/font_matcher.h14
-rw-r--r--include/android/imagedecoder.h47
-rw-r--r--include/android/sensor.h47
-rw-r--r--include/android/sharedmem.h10
-rw-r--r--include/android/surface_control.h72
-rw-r--r--include/android/surface_texture.h8
-rw-r--r--include/android/thermal.h8
-rw-r--r--include/android/trace.h2
-rw-r--r--include/android/window.h5
-rw-r--r--libs/binder/Android.bp19
-rw-r--r--libs/binder/BpBinder.cpp15
-rw-r--r--libs/binder/BufferedTextOutput.cpp2
-rw-r--r--libs/binder/IInterface.cpp4
-rw-r--r--libs/binder/IMemory.cpp4
-rw-r--r--libs/binder/IPCThreadState.cpp7
-rw-r--r--libs/binder/IServiceManager.cpp13
-rw-r--r--libs/binder/LazyServiceRegistrar.cpp4
-rw-r--r--libs/binder/MemoryDealer.cpp8
-rw-r--r--libs/binder/Parcel.cpp3
-rw-r--r--libs/binder/ProcessState.cpp23
-rw-r--r--libs/binder/RpcConnection.cpp240
-rw-r--r--libs/binder/RpcServer.cpp4
-rw-r--r--libs/binder/RpcState.cpp21
-rw-r--r--libs/binder/aidl/android/os/IServiceManager.aidl5
-rw-r--r--libs/binder/include/binder/Binder.h4
-rw-r--r--libs/binder/include/binder/BpBinder.h5
-rw-r--r--libs/binder/include/binder/IInterface.h7
-rw-r--r--libs/binder/include/binder/IServiceManager.h8
-rw-r--r--libs/binder/include/binder/Parcel.h8
-rw-r--r--libs/binder/include/binder/ProcessState.h4
-rw-r--r--libs/binder/include/binder/RpcConnection.h30
-rw-r--r--libs/binder/include/binder/RpcServer.h1
-rw-r--r--libs/binder/include/binder/Status.h3
-rw-r--r--libs/binder/include/private/binder/binder_module.h20
-rw-r--r--libs/binder/ndk/include_ndk/android/binder_ibinder.h12
-rw-r--r--libs/binder/ndk/include_platform/android/binder_manager.h9
-rw-r--r--libs/binder/ndk/libbinder_ndk.map.txt9
-rw-r--r--libs/binder/ndk/service_manager.cpp8
-rw-r--r--libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp5
-rw-r--r--libs/binder/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h7
-rw-r--r--libs/binder/parcel_fuzzer/main.cpp16
-rw-r--r--libs/binder/parcel_fuzzer/random_parcel.cpp5
-rw-r--r--libs/binder/rust/Android.bp18
-rw-r--r--libs/binder/rust/src/binder.rs27
-rw-r--r--libs/binder/rust/src/lib.rs11
-rw-r--r--libs/binder/rust/tests/Android.bp4
-rw-r--r--libs/binder/rust/tests/integration.rs63
-rw-r--r--libs/binder/rust/tests/ndk_rust_interop.rs35
-rw-r--r--libs/binder/rust/tests/serialization.rs14
-rw-r--r--libs/binder/tests/Android.bp21
-rw-r--r--libs/binder/tests/IBinderRpcBenchmark.aidl20
-rw-r--r--libs/binder/tests/binderLibTest.cpp12
-rw-r--r--libs/binder/tests/binderRpcBenchmark.cpp141
-rw-r--r--libs/binder/tests/binderRpcTest.cpp54
-rw-r--r--libs/binder/tests/binderSafeInterfaceTest.cpp28
-rw-r--r--libs/binder/tests/binderStabilityTest.cpp2
-rw-r--r--libs/fakeservicemanager/ServiceManager.cpp5
-rw-r--r--libs/fakeservicemanager/ServiceManager.h3
-rw-r--r--libs/gui/Android.bp61
-rw-r--r--libs/gui/BLASTBufferQueue.cpp105
-rw-r--r--libs/gui/DisplayEventDispatcher.cpp1
-rw-r--r--libs/gui/ISurfaceComposer.cpp39
-rw-r--r--libs/gui/ITransactionCompletedListener.cpp33
-rw-r--r--libs/gui/LayerState.cpp18
-rw-r--r--libs/gui/SurfaceComposerClient.cpp114
-rw-r--r--libs/gui/SurfaceControl.cpp81
-rw-r--r--libs/gui/include/gui/BLASTBufferQueue.h42
-rw-r--r--libs/gui/include/gui/DisplayEventDispatcher.h3
-rw-r--r--libs/gui/include/gui/DisplayEventReceiver.h1
-rw-r--r--libs/gui/include/gui/FrameTimelineInfo.h7
-rw-r--r--libs/gui/include/gui/ISurfaceComposer.h7
-rw-r--r--libs/gui/include/gui/ITransactionCompletedListener.h34
-rw-r--r--libs/gui/include/gui/LayerState.h7
-rw-r--r--libs/gui/include/gui/SurfaceComposerClient.h35
-rw-r--r--libs/gui/include/gui/SurfaceControl.h22
-rw-r--r--libs/gui/tests/BLASTBufferQueue_test.cpp278
-rw-r--r--libs/gui/tests/DisplayEventStructLayout_test.cpp3
-rw-r--r--libs/gui/tests/Surface_test.cpp9
-rw-r--r--libs/input/InputTransport.cpp3
-rw-r--r--libs/nativedisplay/AChoreographer.cpp10
-rw-r--r--libs/nativedisplay/include-private/private/android/choreographer.h5
-rw-r--r--libs/nativedisplay/libnativedisplay.map.txt1
-rw-r--r--libs/nativewindow/include/android/hardware_buffer.h73
-rw-r--r--libs/nativewindow/include/android/native_window.h5
-rw-r--r--libs/permission/Android.bp23
-rw-r--r--libs/permission/AppOpsManager.cpp (renamed from libs/binder/AppOpsManager.cpp)2
-rw-r--r--libs/permission/IAppOpsCallback.cpp (renamed from libs/binder/IAppOpsCallback.cpp)0
-rw-r--r--libs/permission/IAppOpsService.cpp (renamed from libs/binder/IAppOpsService.cpp)0
-rw-r--r--libs/permission/include/binder/AppOpsManager.h (renamed from libs/binder/include/binder/AppOpsManager.h)0
-rw-r--r--libs/permission/include/binder/IAppOpsCallback.h (renamed from libs/binder/include/binder/IAppOpsCallback.h)0
-rw-r--r--libs/permission/include/binder/IAppOpsService.h (renamed from libs/binder/include/binder/IAppOpsService.h)0
-rw-r--r--libs/renderengine/Android.bp2
-rw-r--r--libs/renderengine/ExternalTexture.cpp43
-rw-r--r--libs/renderengine/gl/GLESRenderEngine.cpp30
-rw-r--r--libs/renderengine/gl/GLESRenderEngine.h11
-rw-r--r--libs/renderengine/include/renderengine/ExternalTexture.h61
-rw-r--r--libs/renderengine/include/renderengine/LayerSettings.h8
-rw-r--r--libs/renderengine/include/renderengine/RenderEngine.h68
-rw-r--r--libs/renderengine/include/renderengine/mock/RenderEngine.h9
-rw-r--r--libs/renderengine/skia/AutoBackendTexture.cpp20
-rw-r--r--libs/renderengine/skia/AutoBackendTexture.h40
-rw-r--r--libs/renderengine/skia/Cache.cpp96
-rw-r--r--libs/renderengine/skia/SkiaGLRenderEngine.cpp210
-rw-r--r--libs/renderengine/skia/SkiaGLRenderEngine.h16
-rw-r--r--libs/renderengine/skia/SkiaRenderEngine.h10
-rw-r--r--libs/renderengine/skia/debug/SkiaMemoryReporter.cpp205
-rw-r--r--libs/renderengine/skia/debug/SkiaMemoryReporter.h107
-rw-r--r--libs/renderengine/tests/RenderEngineTest.cpp237
-rw-r--r--libs/renderengine/tests/RenderEngineThreadedTest.cpp12
-rw-r--r--libs/renderengine/threaded/RenderEngineThreaded.cpp126
-rw-r--r--libs/renderengine/threaded/RenderEngineThreaded.h18
-rw-r--r--libs/sensor/Android.bp5
-rw-r--r--libs/sensorprivacy/SensorPrivacyManager.cpp16
-rw-r--r--libs/sensorprivacy/aidl/android/hardware/ISensorPrivacyManager.aidl2
-rw-r--r--libs/sensorprivacy/include/sensorprivacy/SensorPrivacyManager.h5
-rw-r--r--services/inputflinger/dispatcher/InputDispatcher.cpp22
-rw-r--r--services/inputflinger/include/InputReaderBase.h4
-rw-r--r--services/inputflinger/reader/InputDevice.cpp25
-rw-r--r--services/inputflinger/reader/include/InputDevice.h1
-rw-r--r--services/inputflinger/reader/mapper/KeyboardInputMapper.cpp4
-rw-r--r--services/inputflinger/tests/InputDispatcher_test.cpp40
-rw-r--r--services/inputflinger/tests/InputReader_test.cpp42
-rw-r--r--services/sensorservice/Android.bp2
-rw-r--r--services/surfaceflinger/BufferLayer.cpp115
-rw-r--r--services/surfaceflinger/BufferLayer.h9
-rw-r--r--services/surfaceflinger/BufferLayerConsumer.cpp56
-rw-r--r--services/surfaceflinger/BufferLayerConsumer.h12
-rw-r--r--services/surfaceflinger/BufferStateLayer.cpp181
-rw-r--r--services/surfaceflinger/BufferStateLayer.h29
-rw-r--r--services/surfaceflinger/ClientCache.cpp13
-rw-r--r--services/surfaceflinger/ClientCache.h10
-rw-r--r--services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h3
-rw-r--r--services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h3
-rw-r--r--services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h10
-rw-r--r--services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h10
-rw-r--r--services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurfaceCreationArgs.h7
-rw-r--r--services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h3
-rw-r--r--services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h10
-rw-r--r--services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h20
-rw-r--r--services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h20
-rw-r--r--services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h53
-rw-r--r--services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h7
-rw-r--r--services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h48
-rw-r--r--services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Planner.h2
-rw-r--r--services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h1
-rw-r--r--services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h5
-rw-r--r--services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h2
-rw-r--r--services/surfaceflinger/CompositionEngine/src/Display.cpp5
-rw-r--r--services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp14
-rw-r--r--services/surfaceflinger/CompositionEngine/src/Output.cpp75
-rw-r--r--services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp50
-rw-r--r--services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp1
-rw-r--r--services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp59
-rw-r--r--services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp86
-rw-r--r--services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp84
-rw-r--r--services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp8
-rw-r--r--services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp12
-rw-r--r--services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp82
-rw-r--r--services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp74
-rw-r--r--services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp46
-rw-r--r--services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp6
-rw-r--r--services/surfaceflinger/CompositionEngine/tests/planner/LayerStateTest.cpp84
-rw-r--r--services/surfaceflinger/CompositionEngine/tests/planner/PredictorTest.cpp36
-rw-r--r--services/surfaceflinger/DisplayDevice.cpp12
-rw-r--r--services/surfaceflinger/DisplayHardware/ComposerHal.cpp26
-rw-r--r--services/surfaceflinger/FrameTimeline/FrameTimeline.cpp60
-rw-r--r--services/surfaceflinger/FrameTimeline/FrameTimeline.h26
-rw-r--r--services/surfaceflinger/Layer.cpp233
-rw-r--r--services/surfaceflinger/Layer.h117
-rw-r--r--services/surfaceflinger/RefreshRateOverlay.cpp23
-rw-r--r--services/surfaceflinger/RefreshRateOverlay.h11
-rw-r--r--services/surfaceflinger/RegionSamplingThread.cpp30
-rw-r--r--services/surfaceflinger/RegionSamplingThread.h15
-rw-r--r--services/surfaceflinger/Scheduler/EventThread.cpp14
-rw-r--r--services/surfaceflinger/Scheduler/EventThread.h4
-rw-r--r--services/surfaceflinger/Scheduler/OneShotTimer.cpp21
-rw-r--r--services/surfaceflinger/Scheduler/OneShotTimer.h14
-rw-r--r--services/surfaceflinger/Scheduler/Scheduler.cpp31
-rw-r--r--services/surfaceflinger/Scheduler/Scheduler.h3
-rw-r--r--services/surfaceflinger/SurfaceFlinger.cpp418
-rw-r--r--services/surfaceflinger/SurfaceFlinger.h54
-rw-r--r--services/surfaceflinger/SurfaceInterceptor.cpp28
-rw-r--r--services/surfaceflinger/SurfaceInterceptor.h2
-rw-r--r--services/surfaceflinger/TimeStats/Android.bp9
-rw-r--r--services/surfaceflinger/TimeStats/TimeStats.cpp312
-rw-r--r--services/surfaceflinger/TimeStats/TimeStats.h67
-rw-r--r--services/surfaceflinger/TimeStats/timestatsatomsproto/Android.bp36
-rw-r--r--services/surfaceflinger/TimeStats/timestatsatomsproto/include/timestatsatomsproto/TimeStatsAtomsProtoHeader.h23
-rw-r--r--services/surfaceflinger/TimeStats/timestatsatomsproto/timestats_atoms.proto289
-rw-r--r--services/surfaceflinger/TransactionCallbackInvoker.cpp91
-rw-r--r--services/surfaceflinger/TransactionCallbackInvoker.h5
-rw-r--r--services/surfaceflinger/main_surfaceflinger.cpp34
-rw-r--r--services/surfaceflinger/tests/BufferGenerator.cpp14
-rw-r--r--services/surfaceflinger/tests/BufferGenerator.h2
-rw-r--r--services/surfaceflinger/tests/Credentials_test.cpp19
-rw-r--r--services/surfaceflinger/tests/EffectLayer_test.cpp1
-rw-r--r--services/surfaceflinger/tests/IPC_test.cpp1
-rw-r--r--services/surfaceflinger/tests/InvalidHandles_test.cpp15
-rw-r--r--services/surfaceflinger/tests/LayerCallback_test.cpp131
-rw-r--r--services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp305
-rw-r--r--services/surfaceflinger/tests/LayerTransactionTest.h5
-rw-r--r--services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp66
-rw-r--r--services/surfaceflinger/tests/LayerUpdate_test.cpp278
-rw-r--r--services/surfaceflinger/tests/MirrorLayer_test.cpp2
-rw-r--r--services/surfaceflinger/tests/ScreenCapture_test.cpp41
-rw-r--r--services/surfaceflinger/tests/SurfaceInterceptor_test.cpp54
-rw-r--r--services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp270
-rw-r--r--services/surfaceflinger/tests/unittests/Android.bp7
-rw-r--r--services/surfaceflinger/tests/unittests/CompositionTest.cpp33
-rw-r--r--services/surfaceflinger/tests/unittests/EventThreadTest.cpp7
-rw-r--r--services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp167
-rw-r--r--services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp195
-rw-r--r--services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp5
-rw-r--r--services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp5
-rw-r--r--services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h4
-rw-r--r--services/surfaceflinger/tests/unittests/TimeStatsTest.cpp497
-rw-r--r--services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp17
-rw-r--r--services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp149
-rw-r--r--services/surfaceflinger/tests/unittests/mock/MockFrameTimeline.h4
-rw-r--r--services/surfaceflinger/tests/unittests/mock/MockTimeStats.h2
-rw-r--r--services/surfaceflinger/tests/utils/TransactionUtils.h18
-rw-r--r--services/vibratorservice/VibratorManagerHalWrapper.cpp2
-rw-r--r--services/vibratorservice/include/vibratorservice/VibratorHalController.h9
-rw-r--r--services/vibratorservice/test/VibratorHalControllerTest.cpp10
-rw-r--r--services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp1
-rw-r--r--services/vibratorservice/test/VibratorManagerHalWrapperAidlTest.cpp2
-rw-r--r--vulkan/libvulkan/swapchain.cpp3
253 files changed, 5374 insertions, 4326 deletions
diff --git a/.clang-format b/.clang-format
index 03af56d640..6725a1fde8 100644
--- a/.clang-format
+++ b/.clang-format
@@ -11,3 +11,4 @@ ContinuationIndentWidth: 8
IndentWidth: 4
PenaltyBreakBeforeFirstCallParameter: 100000
SpacesBeforeTrailingComments: 1
+IncludeBlocks: Preserve
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index cedff0ba8a..79419d3ae6 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -323,9 +323,6 @@ static const char* k_funcgraphCpuPath =
static const char* k_funcgraphProcPath =
"options/funcgraph-proc";
-static const char* k_funcgraphFlatPath =
- "options/funcgraph-flat";
-
static const char* k_ftraceFilterPath =
"set_ftrace_filter";
@@ -703,7 +700,6 @@ static bool setKernelTraceFuncs(const char* funcs)
ok &= setKernelOptionEnable(k_funcgraphAbsTimePath, true);
ok &= setKernelOptionEnable(k_funcgraphCpuPath, true);
ok &= setKernelOptionEnable(k_funcgraphProcPath, true);
- ok &= setKernelOptionEnable(k_funcgraphFlatPath, true);
// Set the requested filter functions.
ok &= truncateFile(k_ftraceFilterPath);
diff --git a/cmds/dumpstate/Android.bp b/cmds/dumpstate/Android.bp
index f48f1fb6f8..aff32c38c2 100644
--- a/cmds/dumpstate/Android.bp
+++ b/cmds/dumpstate/Android.bp
@@ -99,6 +99,7 @@ cc_defaults {
"libhidlbase",
"liblog",
"libutils",
+ "libbinderdebug",
],
srcs: [
"DumpstateService.cpp",
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index c0010c0ced..336c5a2b3d 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -793,6 +793,9 @@ void Dumpstate::PrintHeader() const {
if (module_metadata_version != 0) {
printf("Module Metadata version: %" PRId64 "\n", module_metadata_version);
}
+ printf("SDK extension versions [r=%s s=%s]\n",
+ android::base::GetProperty("build.version.extensions.r", "-").c_str(),
+ android::base::GetProperty("build.version.extensions.s", "-").c_str());
printf("Kernel: ");
DumpFileToFd(STDOUT_FILENO, "", "/proc/version");
diff --git a/cmds/dumpstate/tests/dumpstate_test.cpp b/cmds/dumpstate/tests/dumpstate_test.cpp
index 2c573e4f4a..db508b52bd 100644
--- a/cmds/dumpstate/tests/dumpstate_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_test.cpp
@@ -1032,12 +1032,12 @@ class ZippedBugReportStreamTest : public DumpstateBaseTest {
ZipArchiveHandle handle_;
};
-// Generate a quick wifi report redirected to a file, open it and verify entry exist.
-TEST_F(ZippedBugReportStreamTest, StreamWifiReport) {
- std::string out_path = kTestDataPath + "out.zip";
+// Generate a quick LimitedOnly report redirected to a file, open it and verify entry exist.
+TEST_F(ZippedBugReportStreamTest, StreamLimitedOnlyReport) {
+ std::string out_path = kTestDataPath + "StreamLimitedOnlyReportOut.zip";
android::base::unique_fd out_fd;
CreateFd(out_path, &out_fd);
- ds_.options_->wifi_only = true;
+ ds_.options_->limited_only = true;
ds_.options_->stream_to_socket = true;
RedirectOutputToFd(out_fd);
@@ -1051,7 +1051,7 @@ TEST_F(ZippedBugReportStreamTest, StreamWifiReport) {
ExtractToMemory(handle_, &entry, reinterpret_cast<uint8_t*>(bugreport_txt_name.data()),
entry.uncompressed_length);
EXPECT_THAT(bugreport_txt_name,
- testing::ContainsRegex("(bugreport-.+-wifi(-[[:digit:]]+){6}\\.txt)"));
+ testing::ContainsRegex("(bugreport-.+(-[[:digit:]]+){6}\\.txt)"));
VerifyEntry(handle_, bugreport_txt_name, &entry);
}
diff --git a/cmds/dumpsys/Android.bp b/cmds/dumpsys/Android.bp
index 91aa018451..6ab6b7f951 100644
--- a/cmds/dumpsys/Android.bp
+++ b/cmds/dumpsys/Android.bp
@@ -32,6 +32,7 @@ cc_defaults {
"libutils",
"liblog",
"libbinder",
+ "libbinderdebug",
],
static_libs: [
diff --git a/cmds/dumpsys/OWNERS b/cmds/dumpsys/OWNERS
index 2a9b681318..4f6a89ebe5 100644
--- a/cmds/dumpsys/OWNERS
+++ b/cmds/dumpsys/OWNERS
@@ -2,3 +2,6 @@ set noparent
nandana@google.com
jsharkey@android.com
+
+# for ServiceManager mock
+per-file dumpsys_test.cpp=smoreland@google.com
diff --git a/cmds/dumpsys/dumpsys.cpp b/cmds/dumpsys/dumpsys.cpp
index a017246184..ba1c449dbf 100644
--- a/cmds/dumpsys/dumpsys.cpp
+++ b/cmds/dumpsys/dumpsys.cpp
@@ -25,6 +25,7 @@
#include <binder/Parcel.h>
#include <binder/ProcessState.h>
#include <binder/TextOutput.h>
+#include <binderdebug/BinderDebug.h>
#include <serviceutils/PriorityDumper.h>
#include <utils/Log.h>
#include <utils/Vector.h>
@@ -60,13 +61,15 @@ static void usage() {
"usage: dumpsys\n"
" To dump all services.\n"
"or:\n"
- " dumpsys [-t TIMEOUT] [--priority LEVEL] [--pid] [--help | -l | --skip SERVICES "
+ " dumpsys [-t TIMEOUT] [--priority LEVEL] [--pid] [--thread] [--help | -l | "
+ "--skip SERVICES "
"| SERVICE [ARGS]]\n"
" --help: shows this help\n"
" -l: only list services, do not dump them\n"
" -t TIMEOUT_SEC: TIMEOUT to use in seconds instead of default 10 seconds\n"
" -T TIMEOUT_MS: TIMEOUT to use in milliseconds instead of default 10 seconds\n"
" --pid: dump PID instead of usual dump\n"
+ " --thread: dump thread usage instead of usual dump\n"
" --proto: filter services that support dumping data in proto format. Dumps\n"
" will be in proto format.\n"
" --priority LEVEL: filter services based on specified priority\n"
@@ -125,7 +128,8 @@ int Dumpsys::main(int argc, char* const argv[]) {
Type type = Type::DUMP;
int timeoutArgMs = 10000;
int priorityFlags = IServiceManager::DUMP_FLAG_PRIORITY_ALL;
- static struct option longOptions[] = {{"pid", no_argument, 0, 0},
+ static struct option longOptions[] = {{"thread", no_argument, 0, 0},
+ {"pid", no_argument, 0, 0},
{"priority", required_argument, 0, 0},
{"proto", no_argument, 0, 0},
{"skip", no_argument, 0, 0},
@@ -163,6 +167,8 @@ int Dumpsys::main(int argc, char* const argv[]) {
}
} else if (!strcmp(longOptions[optionIndex].name, "pid")) {
type = Type::PID;
+ } else if (!strcmp(longOptions[optionIndex].name, "thread")) {
+ type = Type::THREAD;
}
break;
@@ -329,6 +335,23 @@ static status_t dumpPidToFd(const sp<IBinder>& service, const unique_fd& fd) {
return OK;
}
+static status_t dumpThreadsToFd(const sp<IBinder>& service, const unique_fd& fd) {
+ pid_t pid;
+ status_t status = service->getDebugPid(&pid);
+ if (status != OK) {
+ return status;
+ }
+ BinderPidInfo pidInfo;
+ status = getBinderPidInfo(BinderDebugContext::BINDER, pid, &pidInfo);
+ if (status != OK) {
+ return status;
+ }
+ WriteStringToFd("Threads in use: " + std::to_string(pidInfo.threadUsage) + "/" +
+ std::to_string(pidInfo.threadCount) + "\n",
+ fd.get());
+ return OK;
+}
+
status_t Dumpsys::startDumpThread(Type type, const String16& serviceName,
const Vector<String16>& args) {
sp<IBinder> service = sm_->checkService(serviceName);
@@ -359,6 +382,9 @@ status_t Dumpsys::startDumpThread(Type type, const String16& serviceName,
case Type::PID:
err = dumpPidToFd(service, remote_end);
break;
+ case Type::THREAD:
+ err = dumpThreadsToFd(service, remote_end);
+ break;
default:
std::cerr << "Unknown dump type" << static_cast<int>(type) << std::endl;
return;
diff --git a/cmds/dumpsys/dumpsys.h b/cmds/dumpsys/dumpsys.h
index 929c55c364..349947ce12 100644
--- a/cmds/dumpsys/dumpsys.h
+++ b/cmds/dumpsys/dumpsys.h
@@ -52,13 +52,14 @@ class Dumpsys {
static void setServiceArgs(Vector<String16>& args, bool asProto, int priorityFlags);
enum class Type {
- DUMP, // dump using `dump` function
- PID, // dump pid of server only
+ DUMP, // dump using `dump` function
+ PID, // dump pid of server only
+ THREAD, // dump thread usage of server only
};
/**
* Starts a thread to connect to a service and get its dump output. The thread redirects
- * the output to a pipe. Thread must be stopped by a subsequent callto {@code
+ * the output to a pipe. Thread must be stopped by a subsequent call to {@code
* stopDumpThread}.
* @param serviceName
* @param args list of arguments to pass to service dump method.
diff --git a/cmds/dumpsys/tests/Android.bp b/cmds/dumpsys/tests/Android.bp
index 6854c7550e..58fec30c9b 100644
--- a/cmds/dumpsys/tests/Android.bp
+++ b/cmds/dumpsys/tests/Android.bp
@@ -19,6 +19,7 @@ cc_test {
"libbase",
"libbinder",
"libutils",
+ "libbinderdebug",
],
static_libs: [
@@ -26,6 +27,4 @@ cc_test {
"libgmock",
"libserviceutils",
],
-
- clang: true,
}
diff --git a/cmds/dumpsys/tests/AndroidTest.xml b/cmds/dumpsys/tests/AndroidTest.xml
index 1a8c67f7aa..c2351d9aff 100644
--- a/cmds/dumpsys/tests/AndroidTest.xml
+++ b/cmds/dumpsys/tests/AndroidTest.xml
@@ -23,4 +23,4 @@
<option name="native-test-device-path" value="/data/local/tmp" />
<option name="module-name" value="dumpsys_test" />
</test>
-</configuration> \ No newline at end of file
+</configuration>
diff --git a/cmds/dumpsys/tests/dumpsys_test.cpp b/cmds/dumpsys/tests/dumpsys_test.cpp
index 67a77f6015..c9d2dbb883 100644
--- a/cmds/dumpsys/tests/dumpsys_test.cpp
+++ b/cmds/dumpsys/tests/dumpsys_test.cpp
@@ -16,12 +16,15 @@
#include "../dumpsys.h"
+#include <regex>
#include <vector>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <android-base/file.h>
+#include <binder/Binder.h>
+#include <binder/ProcessState.h>
#include <serviceutils/PriorityDumper.h>
#include <utils/String16.h>
#include <utils/String8.h>
@@ -56,6 +59,7 @@ class ServiceManagerMock : public IServiceManager {
MOCK_METHOD1(waitForService, sp<IBinder>(const String16&));
MOCK_METHOD1(isDeclared, bool(const String16&));
MOCK_METHOD1(getDeclaredInstances, Vector<String16>(const String16&));
+ MOCK_METHOD1(updatableViaApex, std::optional<String16>(const String16&));
protected:
MOCK_METHOD0(onAsBinder, IBinder*());
};
@@ -222,6 +226,10 @@ class DumpsysTest : public Test {
EXPECT_THAT(stdout_, HasSubstr(expected));
}
+ void AssertOutputFormat(const std::string format) {
+ EXPECT_THAT(stdout_, testing::MatchesRegex(format));
+ }
+
void AssertDumped(const std::string& service, const std::string& dump) {
EXPECT_THAT(stdout_, HasSubstr("DUMP OF SERVICE " + service + ":\n" + dump));
EXPECT_THAT(stdout_, HasSubstr("was the duration of dumpsys " + service + ", ending at: "));
@@ -574,6 +582,30 @@ TEST_F(DumpsysTest, ListServiceWithPid) {
AssertOutput(std::to_string(getpid()) + "\n");
}
+// Tests 'dumpsys --thread'
+TEST_F(DumpsysTest, ListAllServicesWithThread) {
+ ExpectListServices({"Locksmith", "Valet"});
+ ExpectCheckService("Locksmith");
+ ExpectCheckService("Valet");
+
+ CallMain({"--thread"});
+
+ AssertRunningServices({"Locksmith", "Valet"});
+
+ const std::string format("(.|\n)*((Threads in use: [0-9]+/[0-9]+)?\n-(.|\n)*){2}");
+ AssertOutputFormat(format);
+}
+
+// Tests 'dumpsys --thread service_name'
+TEST_F(DumpsysTest, ListServiceWithThread) {
+ ExpectCheckService("Locksmith");
+
+ CallMain({"--thread", "Locksmith"});
+ // returns an empty string without root enabled
+ const std::string format("(^$|Threads in use: [0-9]/[0-9]+\n)");
+ AssertOutputFormat(format);
+}
+
TEST_F(DumpsysTest, GetBytesWritten) {
const char* serviceName = "service2";
const char* dumpContents = "dump1";
@@ -599,3 +631,13 @@ TEST_F(DumpsysTest, WriteDumpWithoutThreadStart) {
/* as_proto = */ false, elapsedDuration, bytesWritten);
EXPECT_THAT(status, Eq(INVALID_OPERATION));
}
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+
+ // start a binder thread pool for testing --thread option
+ android::ProcessState::self()->setThreadPoolMaxThreadCount(8);
+ ProcessState::self()->startThreadPool();
+
+ return RUN_ALL_TESTS();
+}
diff --git a/cmds/installd/otapreopt_chroot.cpp b/cmds/installd/otapreopt_chroot.cpp
index 3a87776162..83f01de01e 100644
--- a/cmds/installd/otapreopt_chroot.cpp
+++ b/cmds/installd/otapreopt_chroot.cpp
@@ -179,6 +179,11 @@ static int otapreopt_chroot(const int argc, char **arg) {
// want it for product APKs. Same notes as vendor above.
TryExtraMount("product", arg[2], "/postinstall/product");
+ // Try to mount the system_ext partition. update_engine doesn't do this for
+ // us, but we want it for system_ext APKs. Same notes as vendor and product
+ // above.
+ TryExtraMount("system_ext", arg[2], "/postinstall/system_ext");
+
constexpr const char* kPostInstallLinkerconfig = "/postinstall/linkerconfig";
// Try to mount /postinstall/linkerconfig. we will set it up after performing the chroot
if (mount("tmpfs", kPostInstallLinkerconfig, "tmpfs", 0, nullptr) != 0) {
diff --git a/cmds/lshal/ListCommand.cpp b/cmds/lshal/ListCommand.cpp
index d5110f6203..2722e214e8 100644
--- a/cmds/lshal/ListCommand.cpp
+++ b/cmds/lshal/ListCommand.cpp
@@ -417,7 +417,7 @@ void ListCommand::dumpVintf(const NullableOStream<std::ostream>& out) const {
}
}
out << "-->" << std::endl;
- out << vintf::gHalManifestConverter(manifest, vintf::SerializeFlags::HALS_ONLY);
+ out << vintf::toXml(manifest, vintf::SerializeFlags::HALS_ONLY);
}
std::string ListCommand::INIT_VINTF_NOTES{
diff --git a/cmds/lshal/test.cpp b/cmds/lshal/test.cpp
index 7c1ca91528..6f08f74690 100644
--- a/cmds/lshal/test.cpp
+++ b/cmds/lshal/test.cpp
@@ -47,8 +47,6 @@ using ::android::hardware::hidl_vec;
using ::android::hardware::Void;
using android::vintf::Arch;
using android::vintf::CompatibilityMatrix;
-using android::vintf::gCompatibilityMatrixConverter;
-using android::vintf::gHalManifestConverter;
using android::vintf::HalManifest;
using android::vintf::Transport;
using android::vintf::VintfObject;
@@ -510,7 +508,7 @@ TEST_F(ListTest, DumpVintf) {
std::string error;
vintf::HalManifest m;
- EXPECT_EQ(true, vintf::gHalManifestConverter(&m, out.str(), &error))
+ EXPECT_EQ(true, vintf::fromXml(&m, out.str(), &error))
<< "--init-vintf does not emit valid HAL manifest: " << error;
}
@@ -775,10 +773,10 @@ TEST_F(ListTest, Vintf) {
auto deviceMatrix = std::make_shared<CompatibilityMatrix>();
auto frameworkMatrix = std::make_shared<CompatibilityMatrix>();
- ASSERT_TRUE(gHalManifestConverter(deviceManifest.get(), deviceManifestXml));
- ASSERT_TRUE(gHalManifestConverter(frameworkManifest.get(), frameworkManifestXml));
- ASSERT_TRUE(gCompatibilityMatrixConverter(deviceMatrix.get(), deviceMatrixXml));
- ASSERT_TRUE(gCompatibilityMatrixConverter(frameworkMatrix.get(), frameworkMatrixXml));
+ ASSERT_TRUE(fromXml(deviceManifest.get(), deviceManifestXml));
+ ASSERT_TRUE(fromXml(frameworkManifest.get(), frameworkManifestXml));
+ ASSERT_TRUE(fromXml(deviceMatrix.get(), deviceMatrixXml));
+ ASSERT_TRUE(fromXml(frameworkMatrix.get(), frameworkMatrixXml));
ON_CALL(*mockList, getDeviceManifest()).WillByDefault(Return(deviceManifest));
ON_CALL(*mockList, getDeviceMatrix()).WillByDefault(Return(deviceMatrix));
@@ -964,7 +962,7 @@ public:
" </hal>\n"
"</manifest>";
auto manifest = std::make_shared<HalManifest>();
- EXPECT_TRUE(gHalManifestConverter(manifest.get(), mockManifestXml));
+ EXPECT_TRUE(fromXml(manifest.get(), mockManifestXml));
EXPECT_CALL(*mockList, getDeviceManifest())
.Times(AnyNumber())
.WillRepeatedly(Return(manifest));
diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp
index 2f5524940e..b429fb3440 100644
--- a/cmds/servicemanager/ServiceManager.cpp
+++ b/cmds/servicemanager/ServiceManager.cpp
@@ -58,22 +58,34 @@ static bool forEachManifest(const std::function<bool(const ManifestWithDescripti
return false;
}
-static bool isVintfDeclared(const std::string& name) {
- size_t firstSlash = name.find('/');
- size_t lastDot = name.rfind('.', firstSlash);
- if (firstSlash == std::string::npos || lastDot == std::string::npos) {
- LOG(ERROR) << "VINTF HALs require names in the format type/instance (e.g. "
- << "some.package.foo.IFoo/default) but got: " << name;
- return false;
+struct AidlName {
+ std::string package;
+ std::string iface;
+ std::string instance;
+
+ static bool fill(const std::string& name, AidlName* aname) {
+ size_t firstSlash = name.find('/');
+ size_t lastDot = name.rfind('.', firstSlash);
+ if (firstSlash == std::string::npos || lastDot == std::string::npos) {
+ LOG(ERROR) << "VINTF HALs require names in the format type/instance (e.g. "
+ << "some.package.foo.IFoo/default) but got: " << name;
+ return false;
+ }
+ aname->package = name.substr(0, lastDot);
+ aname->iface = name.substr(lastDot + 1, firstSlash - lastDot - 1);
+ aname->instance = name.substr(firstSlash + 1);
+ return true;
}
- const std::string package = name.substr(0, lastDot);
- const std::string iface = name.substr(lastDot+1, firstSlash-lastDot-1);
- const std::string instance = name.substr(firstSlash+1);
+};
+
+static bool isVintfDeclared(const std::string& name) {
+ AidlName aname;
+ if (!AidlName::fill(name, &aname)) return false;
- bool found = forEachManifest([&] (const ManifestWithDescription& mwd) {
- if (mwd.manifest->hasAidlInstance(package, iface, instance)) {
+ bool found = forEachManifest([&](const ManifestWithDescription& mwd) {
+ if (mwd.manifest->hasAidlInstance(aname.package, aname.iface, aname.instance)) {
LOG(INFO) << "Found " << name << " in " << mwd.description << " VINTF manifest.";
- return true;
+ return true; // break
}
return false; // continue
});
@@ -81,13 +93,34 @@ static bool isVintfDeclared(const std::string& name) {
if (!found) {
// Although it is tested, explicitly rebuilding qualified name, in case it
// becomes something unexpected.
- LOG(ERROR) << "Could not find " << package << "." << iface << "/" << instance
- << " in the VINTF manifest.";
+ LOG(ERROR) << "Could not find " << aname.package << "." << aname.iface << "/"
+ << aname.instance << " in the VINTF manifest.";
}
return found;
}
+static std::optional<std::string> getVintfUpdatableApex(const std::string& name) {
+ AidlName aname;
+ if (!AidlName::fill(name, &aname)) return std::nullopt;
+
+ std::optional<std::string> updatableViaApex;
+
+ forEachManifest([&](const ManifestWithDescription& mwd) {
+ mwd.manifest->forEachInstance([&](const auto& manifestInstance) {
+ if (manifestInstance.format() != vintf::HalFormat::AIDL) return true;
+ if (manifestInstance.package() != aname.package) return true;
+ if (manifestInstance.interface() != aname.iface) return true;
+ if (manifestInstance.instance() != aname.instance) return true;
+ updatableViaApex = manifestInstance.updatableViaApex();
+ return false; // break (libvintf uses opposite convention)
+ });
+ return false; // continue
+ });
+
+ return updatableViaApex;
+}
+
static std::vector<std::string> getVintfInstances(const std::string& interface) {
size_t lastDot = interface.rfind('.');
if (lastDot == std::string::npos) {
@@ -388,6 +421,22 @@ binder::Status ServiceManager::getDeclaredInstances(const std::string& interface
return Status::ok();
}
+Status ServiceManager::updatableViaApex(const std::string& name,
+ std::optional<std::string>* outReturn) {
+ auto ctx = mAccess->getCallingContext();
+
+ if (!mAccess->canFind(ctx, name)) {
+ return Status::fromExceptionCode(Status::EX_SECURITY);
+ }
+
+ *outReturn = std::nullopt;
+
+#ifndef VENDORSERVICEMANAGER
+ *outReturn = getVintfUpdatableApex(name);
+#endif
+ return Status::ok();
+}
+
void ServiceManager::removeRegistrationCallback(const wp<IBinder>& who,
ServiceCallbackMap::iterator* it,
bool* found) {
diff --git a/cmds/servicemanager/ServiceManager.h b/cmds/servicemanager/ServiceManager.h
index c0891152e6..4f23c21078 100644
--- a/cmds/servicemanager/ServiceManager.h
+++ b/cmds/servicemanager/ServiceManager.h
@@ -46,6 +46,8 @@ public:
binder::Status isDeclared(const std::string& name, bool* outReturn) override;
binder::Status getDeclaredInstances(const std::string& interface, std::vector<std::string>* outReturn) override;
+ binder::Status updatableViaApex(const std::string& name,
+ std::optional<std::string>* outReturn) override;
binder::Status registerClientCallback(const std::string& name, const sp<IBinder>& service,
const sp<IClientCallback>& cb) override;
binder::Status tryUnregisterService(const std::string& name, const sp<IBinder>& binder) override;
diff --git a/cmds/surfacereplayer/proto/src/trace.proto b/cmds/surfacereplayer/proto/src/trace.proto
index 06afefd3c8..3798ba73a4 100644
--- a/cmds/surfacereplayer/proto/src/trace.proto
+++ b/cmds/surfacereplayer/proto/src/trace.proto
@@ -46,7 +46,6 @@ message SurfaceChange {
HiddenFlagChange hidden_flag = 12;
OpaqueFlagChange opaque_flag = 13;
SecureFlagChange secure_flag = 14;
- DeferredTransactionChange deferred_transaction = 15;
CornerRadiusChange corner_radius = 16;
ReparentChange reparent = 17;
RelativeParentChange relative_parent = 18;
@@ -113,11 +112,6 @@ message SecureFlagChange {
required bool secure_flag = 1;
}
-message DeferredTransactionChange {
- required int32 layer_id = 1;
- required uint64 frame_number = 2;
-}
-
message DisplayChange {
required int32 id = 1;
diff --git a/cmds/surfacereplayer/replayer/Replayer.cpp b/cmds/surfacereplayer/replayer/Replayer.cpp
index a6d9a3feb6..cfd42fec30 100644
--- a/cmds/surfacereplayer/replayer/Replayer.cpp
+++ b/cmds/surfacereplayer/replayer/Replayer.cpp
@@ -402,11 +402,6 @@ status_t Replayer::doSurfaceTransaction(
case SurfaceChange::SurfaceChangeCase::kSecureFlag:
setSecureFlag(transaction, change.id(), change.secure_flag());
break;
- case SurfaceChange::SurfaceChangeCase::kDeferredTransaction:
- waitUntilDeferredTransactionLayerExists(change.deferred_transaction(), lock);
- setDeferredTransaction(transaction, change.id(),
- change.deferred_transaction());
- break;
case SurfaceChange::SurfaceChangeCase::kReparent:
setReparentChange(transaction, change.id(), change.reparent());
break;
@@ -560,19 +555,6 @@ void Replayer::setSecureFlag(SurfaceComposerClient::Transaction& t,
t.setFlags(mLayers[id], flag, layer_state_t::eLayerSecure);
}
-void Replayer::setDeferredTransaction(SurfaceComposerClient::Transaction& t,
- layer_id id, const DeferredTransactionChange& dtc) {
- ALOGV("Layer %d: Setting Deferred Transaction -- layer_id=%d, "
- "frame_number=%llu",
- id, dtc.layer_id(), dtc.frame_number());
- if (mLayers.count(dtc.layer_id()) == 0 || mLayers[dtc.layer_id()] == nullptr) {
- ALOGE("Layer %d not found in Deferred Transaction", dtc.layer_id());
- return;
- }
-
- t.deferTransactionUntil_legacy(mLayers[id], mLayers[dtc.layer_id()], dtc.frame_number());
-}
-
void Replayer::setDisplaySurface(SurfaceComposerClient::Transaction& t,
display_id id, const DispSurfaceChange& /*dsc*/) {
sp<IGraphicBufferProducer> outProducer;
@@ -676,13 +658,6 @@ void Replayer::waitUntilTimestamp(int64_t timestamp) {
std::this_thread::sleep_for(std::chrono::nanoseconds(timestamp - mCurrentTime));
}
-void Replayer::waitUntilDeferredTransactionLayerExists(
- const DeferredTransactionChange& dtc, std::unique_lock<std::mutex>& lock) {
- if (mLayers.count(dtc.layer_id()) == 0 || mLayers[dtc.layer_id()] == nullptr) {
- mLayerCond.wait(lock, [&] { return (mLayers[dtc.layer_id()] != nullptr); });
- }
-}
-
status_t Replayer::loadSurfaceComposerClient() {
mComposerClient = new SurfaceComposerClient;
return mComposerClient->initCheck();
diff --git a/cmds/surfacereplayer/replayer/Replayer.h b/cmds/surfacereplayer/replayer/Replayer.h
index 252db2bfbb..d62522a497 100644
--- a/cmds/surfacereplayer/replayer/Replayer.h
+++ b/cmds/surfacereplayer/replayer/Replayer.h
@@ -110,8 +110,6 @@ class Replayer {
layer_id id, const OpaqueFlagChange& ofc);
void setSecureFlag(SurfaceComposerClient::Transaction& t,
layer_id id, const SecureFlagChange& sfc);
- void setDeferredTransaction(SurfaceComposerClient::Transaction& t,
- layer_id id, const DeferredTransactionChange& dtc);
void setReparentChange(SurfaceComposerClient::Transaction& t,
layer_id id, const ReparentChange& c);
void setRelativeParentChange(SurfaceComposerClient::Transaction& t,
@@ -131,8 +129,6 @@ class Replayer {
display_id id, const ProjectionChange& pc);
void waitUntilTimestamp(int64_t timestamp);
- void waitUntilDeferredTransactionLayerExists(
- const DeferredTransactionChange& dtc, std::unique_lock<std::mutex>& lock);
status_t loadSurfaceComposerClient();
Trace mTrace;
diff --git a/data/etc/android.software.translation.xml b/data/etc/android.software.translation.xml
deleted file mode 100644
index 3b361e5cb8..0000000000
--- a/data/etc/android.software.translation.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2020 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.
--->
-
-<permissions>
- <feature name="android.software.translation" />
-</permissions>
diff --git a/data/etc/handheld_core_hardware.xml b/data/etc/handheld_core_hardware.xml
index c3c3a7f247..41f15144d4 100644
--- a/data/etc/handheld_core_hardware.xml
+++ b/data/etc/handheld_core_hardware.xml
@@ -54,7 +54,6 @@
<feature name="android.software.autofill" />
<feature name="android.software.cant_save_state" />
<feature name="android.software.secure_lock_screen" />
- <feature name="android.software.translation" />
<!-- Feature to specify if the device supports adding device admins. -->
<feature name="android.software.device_admin" />
diff --git a/data/etc/tablet_core_hardware.xml b/data/etc/tablet_core_hardware.xml
index 4b565fda97..8c369dea99 100644
--- a/data/etc/tablet_core_hardware.xml
+++ b/data/etc/tablet_core_hardware.xml
@@ -54,7 +54,6 @@
<feature name="android.software.autofill" />
<feature name="android.software.cant_save_state" />
<feature name="android.software.secure_lock_screen" />
- <feature name="android.software.translation" />
<!-- Feature to specify if the device supports adding device admins. -->
<feature name="android.software.device_admin" />
diff --git a/include/android/bitmap.h b/include/android/bitmap.h
index a70dffd756..6704a1ddf2 100644
--- a/include/android/bitmap.h
+++ b/include/android/bitmap.h
@@ -241,6 +241,7 @@ typedef struct AHardwareBuffer AHardwareBuffer;
*
* Available since API level 30.
*
+ * @param env Handle to the JNI environment pointer.
* @param bitmap Handle to an android.graphics.Bitmap.
* @param outBuffer On success, is set to a pointer to the
* {@link AHardwareBuffer} associated with bitmap. This acquires
diff --git a/include/android/choreographer.h b/include/android/choreographer.h
index cc5420e239..b743f491e4 100644
--- a/include/android/choreographer.h
+++ b/include/android/choreographer.h
@@ -32,6 +32,11 @@
__BEGIN_DECLS
struct AChoreographer;
+/**
+ * Opaque type that provides access to an AChoreographer object.
+ *
+ * A pointer can be obtained using {@link AChoreographer_getInstance()}.
+ */
typedef struct AChoreographer AChoreographer;
/**
diff --git a/include/android/font.h b/include/android/font.h
index a172618829..8a3a474f25 100644
--- a/include/android/font.h
+++ b/include/android/font.h
@@ -189,7 +189,7 @@ const char* _Nonnull AFont_getFontFilePath(const AFont* _Nonnull font) __INTRODU
* Available since API level 29.
*
* \param font a font object. Passing NULL is not allowed.
- * \return a positive integer less than or equal to {@link ASYSTEM_FONT_MAX_WEIGHT} is returned.
+ * \return a positive integer less than or equal to {@link AFONT_WEIGHT_MAX} is returned.
*/
uint16_t AFont_getWeight(const AFont* _Nonnull font) __INTRODUCED_IN(29);
@@ -241,7 +241,7 @@ size_t AFont_getCollectionIndex(const AFont* _Nonnull font) __INTRODUCED_IN(29);
* In this case, AFont_getAxisCount returns 2 and AFont_getAxisTag
* and AFont_getAxisValue will return following values.
* \code{.cpp}
- * AFont* font = AFontIterator_next(ite);
+ * AFont* font = ASystemFontIterator_next(ite);
*
* // Returns the number of axes
* AFont_getAxisCount(font); // Returns 2
@@ -289,7 +289,7 @@ uint32_t AFont_getAxisTag(const AFont* _Nonnull font, uint32_t axisIndex)
*
* \param font a font object. Passing NULL is not allowed.
* \param axisIndex an index to the font variation settings. Passing value larger than or
- * equal to {@link ASYstemFont_getAxisCount} is not allwed.
+ * equal to {@link AFont_getAxisCount} is not allowed.
* \return a float value for the given font variation setting.
*/
float AFont_getAxisValue(const AFont* _Nonnull font, uint32_t axisIndex)
diff --git a/include/android/font_matcher.h b/include/android/font_matcher.h
index 49e478c2f3..4417422687 100644
--- a/include/android/font_matcher.h
+++ b/include/android/font_matcher.h
@@ -36,7 +36,7 @@
* // Simple font query for the ASCII character.
* std::vector<uint16_t> text = { 'A' };
* AFontMatcher* matcher = AFontMatcher_create("sans-serif");
- * ASystemFont* font = AFontMatcher_match(text.data(), text.length(), &runLength);
+ * AFont* font = AFontMatcher_match(text.data(), text.length(), &runLength);
* // runLength will be 1 and the font will points a valid font file.
* AFontMatcher_destroy(matcher);
*
@@ -44,17 +44,17 @@
* std::vector<uint16_t> text = { 0x9AA8 };
* AFontMatcher* matcher = AFontMatcher_create("sans-serif");
* AFontMatcher_setLocales(matcher, "zh-CN,ja-JP");
- * ASystemFont* font = AFontMatcher_match(text.data(), text.length(), &runLength);
+ * AFont* font = AFontMatcher_match(text.data(), text.length(), &runLength);
* // runLength will be 1 and the font will points a Simplified Chinese font.
* AFontMatcher_setLocales(matcher, "ja-JP,zh-CN");
- * ASystemFont* font = AFontMatcher_match(text.data(), text.length(), &runLength);
+ * AFont* font = AFontMatcher_match(text.data(), text.length(), &runLength);
* // runLength will be 1 and the font will points a Japanese font.
* AFontMatcher_destroy(matcher);
*
* // Querying font for text/color emoji
* std::vector<uint16_t> text = { 0xD83D, 0xDC68, 0x200D, 0x2764, 0xFE0F, 0x200D, 0xD83D, 0xDC68 };
* AFontMatcher* matcher = AFontMatcher_create("sans-serif");
- * ASystemFont* font = AFontMatcher_match(text.data(), text.length(), &runLength);
+ * AFont* font = AFontMatcher_match(text.data(), text.length(), &runLength);
* // runLength will be 8 and the font will points a color emoji font.
* AFontMatcher_destroy(matcher);
*
@@ -62,7 +62,7 @@
* // 0x05D0 is a Hebrew character and 0x0E01 is a Thai character.
* std::vector<uint16_t> text = { 0x05D0, 0x0E01 };
* AFontMatcher* matcher = AFontMatcher_create("sans-serif");
- * ASystemFont* font = AFontMatcher_match(text.data(), text.length(), &runLength);
+ * AFont* font = AFontMatcher_match(text.data(), text.length(), &runLength);
* // runLength will be 1 and the font will points a Hebrew font.
* AFontMatcher_destroy(matcher);
* \endcode
@@ -146,7 +146,7 @@ void AFontMatcher_destroy(AFontMatcher* _Nonnull matcher) __INTRODUCED_IN(29);
/**
* Set font style to matcher.
*
- * If this function is not called, the matcher performs with {@link ASYSTEM_FONT_WEIGHT_NORMAL}
+ * If this function is not called, the matcher performs with {@link AFONT_WEIGHT_NORMAL}
* with non-italic style.
*
* Available since API level 29.
@@ -206,7 +206,7 @@ void AFontMatcher_setFamilyVariant(
* \param textLength a length of the given text buffer. This must not be zero.
* \param runLengthOut if not null, the font run length will be filled.
* \return a font to be used for given text and params. You need to release the returned font by
- * ASystemFont_close when it is no longer needed.
+ * AFont_close when it is no longer needed.
*/
AFont* _Nonnull AFontMatcher_match(
const AFontMatcher* _Nonnull matcher,
diff --git a/include/android/imagedecoder.h b/include/android/imagedecoder.h
index ee1eee2be6..8d1bf99fe7 100644
--- a/include/android/imagedecoder.h
+++ b/include/android/imagedecoder.h
@@ -15,7 +15,7 @@
*/
/**
- * @defgroup ImageDecoder
+ * @defgroup ImageDecoder Android Image Decoder
*
* Functions for converting encoded images into RGBA pixels.
*
@@ -261,7 +261,8 @@ int AImageDecoder_createFromBuffer(const void* _Nonnull buffer, size_t length,
/**
* Delete the AImageDecoder.
- *
+ * @param decoder {@link AImageDecoder} object created with one of AImageDecoder_createFrom...
+ * functions.
* Available since API level 30.
*/
void AImageDecoder_delete(AImageDecoder* _Nullable decoder) __INTRODUCED_IN(30);
@@ -276,6 +277,7 @@ void AImageDecoder_delete(AImageDecoder* _Nullable decoder) __INTRODUCED_IN(30);
* Available since API level 30.
*
* @param format {@link AndroidBitmapFormat} to use for the output.
+ * @param decoder an {@link AImageDecoder} object.
* @return {@link ANDROID_IMAGE_DECODER_SUCCESS} on success or a value
* indicating the reason for the failure. On failure, the
* {@link AImageDecoder} uses the format it was already planning
@@ -307,6 +309,7 @@ int AImageDecoder_setAndroidBitmapFormat(AImageDecoder* _Nonnull decoder,
*
* Available since API level 30.
*
+ * @param decoder an {@link AImageDecoder} object.
* @param unpremultipliedRequired Pass true to leave the pixels unpremultiplied.
* @return {@link ANDROID_IMAGE_DECODER_SUCCESS} on success or a value
* indicating the reason for the failure.
@@ -335,6 +338,7 @@ int AImageDecoder_setUnpremultipliedRequired(AImageDecoder* _Nonnull decoder,
*
* Available since API level 30.
*
+ * @param decoder an {@link AImageDecoder} object.
* @param dataspace The {@link ADataSpace} to decode into. An ADataSpace
* specifies how to interpret the colors. By default,
* AImageDecoder will decode into the ADataSpace specified by
@@ -373,6 +377,7 @@ int AImageDecoder_setDataSpace(AImageDecoder* _Nonnull decoder, int32_t dataspac
*
* Available since API level 30.
*
+ * @param decoder an {@link AImageDecoder} object.
* @param width Width of the output (prior to cropping).
* This will affect future calls to
* {@link AImageDecoder_getMinimumStride}, which will now return
@@ -404,6 +409,7 @@ int AImageDecoder_setTargetSize(AImageDecoder* _Nonnull decoder, int32_t width,
*
* Available since API level 30.
*
+ * @param decoder an {@link AImageDecoder} object.
* @param sampleSize A subsampling rate of the original image. Must be greater
* than or equal to 1. A sampleSize of 2 means to skip every
* other pixel/line, resulting in a width and height that are
@@ -437,6 +443,7 @@ int AImageDecoder_computeSampledSize(const AImageDecoder* _Nonnull decoder, int
*
* Available since API level 30.
*
+ * @param decoder an {@link AImageDecoder} object.
* @param crop Rectangle describing a crop of the decode. It must be contained inside of
* the (possibly scaled, by {@link AImageDecoder_setTargetSize})
* image dimensions. This will affect future calls to
@@ -475,6 +482,8 @@ typedef struct AImageDecoderHeaderInfo AImageDecoderHeaderInfo;
* This is owned by the {@link AImageDecoder} and will be destroyed when the
* AImageDecoder is destroyed via {@link AImageDecoder_delete}.
*
+ * @param decoder an {@link AImageDecoder} object.
+ *
* Available since API level 30.
*/
const AImageDecoderHeaderInfo* _Nonnull AImageDecoder_getHeaderInfo(
@@ -562,7 +571,7 @@ int32_t AImageDecoderHeaderInfo_getDataSpace(
/**
* Return the minimum stride that can be used in
- * {@link AImageDecoder_decodeImage).
+ * {@link AImageDecoder_decodeImage}.
*
* This stride provides no padding, meaning it will be exactly equal to the
* width times the number of bytes per pixel for the {@link AndroidBitmapFormat}
@@ -571,6 +580,8 @@ int32_t AImageDecoderHeaderInfo_getDataSpace(
* If the output is scaled (via {@link AImageDecoder_setTargetSize}) and/or
* cropped (via {@link AImageDecoder_setCrop}), this takes those into account.
*
+ * @param decoder an {@link AImageDecoder} object.
+ *
* Available since API level 30.
*/
size_t AImageDecoder_getMinimumStride(AImageDecoder* _Nonnull decoder) __INTRODUCED_IN(30);
@@ -664,6 +675,8 @@ int AImageDecoder_decodeImage(AImageDecoder* _Nonnull decoder,
* A single frame GIF is considered to *not* be animated. This may require
* seeking past the first frame to verify whether there is a following frame.
*
+ * @param decoder an {@link AImageDecoder} object.
+ *
* Errors:
* - returns false if |decoder| is null.
*/
@@ -671,7 +684,7 @@ bool AImageDecoder_isAnimated(AImageDecoder* _Nonnull decoder)
__INTRODUCED_IN(31);
enum {
- /*
+ /**
* Reported by {@link AImageDecoder_getRepeatCount} if the
* animation should repeat forever.
*
@@ -696,6 +709,7 @@ enum {
* an image with only one frame (i.e. {@link AImageDecoder_isAnimated} returns
* false) if the encoded image contains a repeat count.
*
+ * @param decoder an {@link AImageDecoder} object.
* @return Number of times to repeat on success or a value
* indicating the reason for the failure.
*
@@ -725,6 +739,7 @@ int32_t AImageDecoder_getRepeatCount(AImageDecoder* _Nonnull decoder)
* skipping frames in an image with such frames may not produce the correct
* results.
*
+ * @param decoder an {@link AImageDecoder} object.
* @return {@link ANDROID_IMAGE_DECODER_SUCCESS} on success or a value
* indicating the reason for the failure.
*
@@ -755,6 +770,7 @@ int AImageDecoder_advanceFrame(AImageDecoder* _Nonnull decoder)
* the end of the animation or an error or in the middle of the
* animation.
*
+ * @param decoder an {@link AImageDecoder} object.
* @return {@link ANDROID_IMAGE_DECODER_SUCCESS} on success or a value
* indicating the reason for the failure.
*
@@ -847,7 +863,7 @@ int64_t AImageDecoderFrameInfo_getDuration(
/**
* The rectangle of the image (within 0, 0,
- * {@link AImageDecoder_getWidth}, {@link AImageDecoder_getHeight})
+ * {@link AImageDecoderHeaderInfo_getWidth}, {@link AImageDecoderHeaderInfo_getHeight})
* updated by this frame.
*
* Introduced in API 31.
@@ -905,15 +921,15 @@ bool AImageDecoderFrameInfo_hasAlphaWithinBounds(
* sequential client does not need this.
*/
enum {
- // No disposal. The following frame will be drawn directly
- // on top of this one.
+ /// No disposal. The following frame will be drawn directly
+ /// on top of this one.
ANDROID_IMAGE_DECODER_DISPOSE_OP_NONE = 1,
- // The frame’s rectangle is cleared to transparent (by AImageDecoder)
- // before decoding the next frame.
+ /// The frame’s rectangle is cleared to transparent (by AImageDecoder)
+ /// before decoding the next frame.
ANDROID_IMAGE_DECODER_DISPOSE_OP_BACKGROUND = 2,
- // The frame’s rectangle is reverted to the prior frame before decoding
- // the next frame. This is handled by AImageDecoder, unless
- // {@link AImageDecoder_setInternallyHandleDisposePrevious} is set to false.
+ /// The frame’s rectangle is reverted to the prior frame before decoding
+ /// the next frame. This is handled by AImageDecoder, unless
+ /// {@link AImageDecoder_setInternallyHandleDisposePrevious} is set to false.
ANDROID_IMAGE_DECODER_DISPOSE_OP_PREVIOUS = 3,
};
@@ -948,10 +964,10 @@ int32_t AImageDecoderFrameInfo_getDisposeOp(
* sequential client does not need this.
*/
enum {
- // This frame replaces existing content. This corresponds
- // to webp’s “do not blend”.
+ /// This frame replaces existing content. This corresponds
+ /// to webp’s “do not blend”.
ANDROID_IMAGE_DECODER_BLEND_OP_SRC = 1,
- // This frame blends with the previous frame.
+ /// This frame blends with the previous frame.
ANDROID_IMAGE_DECODER_BLEND_OP_SRC_OVER = 2,
};
@@ -1002,6 +1018,7 @@ int32_t AImageDecoderFrameInfo_getBlendOp(
* When asked to decode frame i+1, AImageDecoder will now assume that
* the client provided i-1 in |pixels|.
*
+ * @param decoder an {@link AImageDecoder} object.
* @param handleInternally Whether AImageDecoder will internally
* handle ANDROID_IMAGE_DECODER_DISPOSE_OP_PREVIOUS
* frames.
diff --git a/include/android/sensor.h b/include/android/sensor.h
index 92b79c75ff..9dc6983e50 100644
--- a/include/android/sensor.h
+++ b/include/android/sensor.h
@@ -228,8 +228,8 @@ enum {
*
* If a device supports the sensor additional information feature, it will
* report additional information events via {@link ASensorEvent} and will
- * have {@link ASensorEvent#type} set to
- * {@link ASENSOR_TYPE_ADDITIONAL_INFO} and {@link ASensorEvent#sensor} set
+ * have the type of {@link ASensorEvent} set to
+ * {@link ASENSOR_TYPE_ADDITIONAL_INFO} and the sensor of {@link ASensorEvent} set
* to the handle of the reporting sensor.
*
* Additional information reports consist of multiple frames ordered by
@@ -428,6 +428,10 @@ typedef struct ADynamicSensorEvent {
} ADynamicSensorEvent;
typedef struct AAdditionalInfoEvent {
+ /**
+ * Event type, such as ASENSOR_ADDITIONAL_INFO_BEGIN, ASENSOR_ADDITIONAL_INFO_END and others.
+ * Refer to {@link ASENSOR_TYPE_ADDITIONAL_INFO} for the expected reporting behavior.
+ */
int32_t type;
int32_t serial;
union {
@@ -436,12 +440,22 @@ typedef struct AAdditionalInfoEvent {
};
} AAdditionalInfoEvent;
+/**
+ * Information that describes a sensor event, refer to
+ * <a href="/reference/android/hardware/SensorEvent">SensorEvent</a> for additional
+ * documentation.
+ */
/* NOTE: changes to this struct has to be backward compatible */
typedef struct ASensorEvent {
int32_t version; /* sizeof(struct ASensorEvent) */
- int32_t sensor;
- int32_t type;
- int32_t reserved0;
+ int32_t sensor; /** The sensor that generates this event */
+ int32_t type; /** Sensor type for the event, such as {@link ASENSOR_TYPE_ACCELEROMETER} */
+ int32_t reserved0; /** do not use */
+ /**
+ * The time in nanoseconds at which the event happened, and its behavior
+ * is identical to <a href="/reference/android/hardware/SensorEvent#timestamp">
+ * SensorEvent::timestamp</a> in Java API.
+ */
int64_t timestamp;
union {
union {
@@ -653,9 +667,10 @@ int ASensorManager_createHardwareBufferDirectChannel(
/**
* Destroy a direct channel
*
- * Destroy a direct channel previously created using {@link ASensorManager_createDirectChannel}.
- * The buffer used for creating direct channel does not get destroyed with
- * {@link ASensorManager_destroy} and has to be close or released separately.
+ * Destroy a direct channel previously created by using one of
+ * ASensorManager_create*DirectChannel() derivative functions.
+ * Note that the buffer used for creating the direct channel does not get destroyed with
+ * ASensorManager_destroyDirectChannel and has to be closed or released separately.
*
* Available since API level 26.
*
@@ -701,7 +716,7 @@ void ASensorManager_destroyDirectChannel(ASensorManager* manager, int channelId)
* \param channelId channel id (a positive integer) returned from
* {@link ASensorManager_createSharedMemoryDirectChannel} or
* {@link ASensorManager_createHardwareBufferDirectChannel}.
- *
+ * \param rate one of predefined ASENSOR_DIRECT_RATE_... that is supported by the sensor.
* \return positive token for success or negative error code.
*/
int ASensorManager_configureDirectReport(ASensorManager* manager,
@@ -718,7 +733,7 @@ int ASensorManager_configureDirectReport(ASensorManager* manager,
* \param queue {@link ASensorEventQueue} for sensor event to be report to.
* \param sensor {@link ASensor} to be enabled.
* \param samplingPeriodUs sampling period of sensor in microseconds.
- * \param maxBatchReportLatencyus maximum time interval between two batch of sensor events are
+ * \param maxBatchReportLatencyUs maximum time interval between two batches of sensor events are
* delievered in microseconds. For sensor streaming, set to 0.
* \return 0 on success or a negative error code on failure.
*/
@@ -778,7 +793,7 @@ int ASensorEventQueue_hasEvents(ASensorEventQueue* queue);
* Retrieve next available events from the queue to a specified event array.
*
* \param queue {@link ASensorEventQueue} to get events from
- * \param events pointer to an array of {@link ASensorEvents}.
+ * \param events pointer to an array of {@link ASensorEvent}.
* \param count max number of event that can be filled into array event.
* \return number of events returned on success; negative error code when
* no events are pending or an error has occurred.
@@ -798,7 +813,7 @@ ssize_t ASensorEventQueue_getEvents(ASensorEventQueue* queue, ASensorEvent* even
* Request that {@link ASENSOR_TYPE_ADDITIONAL_INFO} events to be delivered on
* the given {@link ASensorEventQueue}.
*
- * Sensor data events are always delivered to the {@ASensorEventQueue}.
+ * Sensor data events are always delivered to the {@link ASensorEventQueue}.
*
* The {@link ASENSOR_TYPE_ADDITIONAL_INFO} events will be returned through
* {@link ASensorEventQueue_getEvents}. The client is responsible for checking
@@ -890,7 +905,7 @@ bool ASensor_isWakeUpSensor(ASensor const* sensor) __INTRODUCED_IN(21);
*
* \param sensor a {@link ASensor} to denote the sensor to be checked.
* \param channelType Channel type constant, either
- * {@ASENSOR_DIRECT_CHANNEL_TYPE_SHARED_MEMORY}
+ * {@link ASENSOR_DIRECT_CHANNEL_TYPE_SHARED_MEMORY}
* or {@link ASENSOR_DIRECT_CHANNEL_TYPE_HARDWARE_BUFFER}.
* \returns true if sensor supports the specified direct channel type.
*/
@@ -913,15 +928,15 @@ int ASensor_getHighestDirectReportRateLevel(ASensor const* sensor) __INTRODUCED_
* Returns the sensor's handle.
*
* The handle identifies the sensor within the system and is included in the
- * {@link ASensorEvent#sensor} field of sensor events, including those sent with type
+ * sensor field of {@link ASensorEvent}, including those sent with type
* {@link ASENSOR_TYPE_ADDITIONAL_INFO}.
*
* A sensor's handle is able to be used to map {@link ASENSOR_TYPE_ADDITIONAL_INFO} events to the
* sensor that generated the event.
*
* It is important to note that the value returned by {@link ASensor_getHandle} is not the same as
- * the value returned by the Java API {@link android.hardware.Sensor#getId} and no mapping exists
- * between the values.
+ * the value returned by the Java API <a href="/reference/android/hardware/Sensor#getId()">
+ * android.hardware.Sensor's getId()</a> and no mapping exists between the values.
*
* Available since API level 29.
*/
diff --git a/include/android/sharedmem.h b/include/android/sharedmem.h
index 7994aa9914..e0a8045d41 100644
--- a/include/android/sharedmem.h
+++ b/include/android/sharedmem.h
@@ -59,9 +59,10 @@ extern "C" {
*
* Use close() to release the shared memory region.
*
- * Use {@link android.os.ParcelFileDescriptor} to pass the file descriptor to
- * another process. File descriptors may also be sent to other processes over a Unix domain
- * socket with sendmsg and SCM_RIGHTS. See sendmsg(3) and cmsg(3) man pages for more information.
+ * Use <a href="/reference/android/os/ParcelFileDescriptor">android.os.ParcelFileDescriptor</a>
+ * to pass the file descriptor to another process. File descriptors may also be sent to other
+ * processes over a Unix domain socket with sendmsg and SCM_RIGHTS. See sendmsg(3) and
+ * cmsg(3) man pages for more information.
*
* If you intend to share this file descriptor with a child process after
* calling exec(3), note that you will need to use fcntl(2) with FD_SETFD
@@ -71,7 +72,8 @@ extern "C" {
*
* \param name an optional name.
* \param size size of the shared memory region
- * \return file descriptor that denotes the shared memory; -1 and sets errno on failure, or -EINVAL if the error is that size was 0.
+ * \return file descriptor that denotes the shared memory;
+ * -1 and sets errno on failure, or -EINVAL if the error is that size was 0.
*/
int ASharedMemory_create(const char *name, size_t size) __INTRODUCED_IN(26);
diff --git a/include/android/surface_control.h b/include/android/surface_control.h
index c5e3587517..b7eafcd6cd 100644
--- a/include/android/surface_control.h
+++ b/include/android/surface_control.h
@@ -147,6 +147,28 @@ typedef struct ASurfaceTransactionStats ASurfaceTransactionStats;
typedef void (*ASurfaceTransaction_OnComplete)(void* context, ASurfaceTransactionStats* stats)
__INTRODUCED_IN(29);
+
+/**
+ * The ASurfaceTransaction_OnCommit callback is invoked when transaction is applied and the updates
+ * are ready to be presented. This callback will be invoked before the
+ * ASurfaceTransaction_OnComplete callback.
+ *
+ * \param context Optional context provided by the client that is passed into the callback.
+ *
+ * \param stats Opaque handle that can be passed to ASurfaceTransactionStats functions to query
+ * information about the transaction. The handle is only valid during the callback.
+ * Present and release fences are not available for this callback. Querying them using
+ * ASurfaceTransactionStats_getPresentFenceFd and ASurfaceTransactionStats_getPreviousReleaseFenceFd
+ * will result in failure.
+ *
+ * THREADING
+ * The transaction committed callback can be invoked on any thread.
+ *
+ * Available since API level 31.
+ */
+typedef void (*ASurfaceTransaction_OnCommit)(void* context, ASurfaceTransactionStats* stats)
+ __INTRODUCED_IN(31);
+
/**
* Returns the timestamp of when the frame was latched by the framework. Once a frame is
* latched by the framework, it is presented at the following hardware vsync.
@@ -161,6 +183,8 @@ int64_t ASurfaceTransactionStats_getLatchTime(ASurfaceTransactionStats* surface_
* The recipient of the callback takes ownership of the fence and is responsible for closing
* it. If a device does not support present fences, a -1 will be returned.
*
+ * This query is not valid for ASurfaceTransaction_OnCommit callback.
+ *
* Available since API level 29.
*/
int ASurfaceTransactionStats_getPresentFenceFd(ASurfaceTransactionStats* surface_transaction_stats)
@@ -218,6 +242,8 @@ int64_t ASurfaceTransactionStats_getAcquireTime(ASurfaceTransactionStats* surfac
* The client must ensure that all pending refs on a buffer are released before attempting to reuse
* this buffer, otherwise synchronization errors may occur.
*
+ * This query is not valid for ASurfaceTransaction_OnCommit callback.
+ *
* Available since API level 29.
*/
int ASurfaceTransactionStats_getPreviousReleaseFenceFd(
@@ -236,6 +262,16 @@ void ASurfaceTransaction_setOnComplete(ASurfaceTransaction* transaction, void* c
ASurfaceTransaction_OnComplete func) __INTRODUCED_IN(29);
/**
+ * Sets the callback that will be invoked when the updates from this transaction are applied and are
+ * ready to be presented. This callback will be invoked before the ASurfaceTransaction_OnComplete
+ * callback.
+ *
+ * Available since API level 31.
+ */
+void ASurfaceTransaction_setOnCommit(ASurfaceTransaction* transaction, void* context,
+ ASurfaceTransaction_OnCommit func) __INTRODUCED_IN(31);
+
+/**
* Reparents the \a surface_control from its old parent to the \a new_parent surface control.
* Any children of the reparented \a surface_control will remain children of the \a surface_control.
*
@@ -329,39 +365,53 @@ void ASurfaceTransaction_setGeometry(ASurfaceTransaction* transaction,
__INTRODUCED_IN(29);
/**
- * \param source The sub-rect within the buffer's content to be rendered inside the surface's area
- * The surface's source rect is clipped by the bounds of its current buffer. The source rect's width
- * and height must be > 0.
+ * Bounds the surface and its children to the bounds specified. The crop and buffer size will be
+ * used to determine the bounds of the surface. If no crop is specified and the surface has no
+ * buffer, the surface bounds is only constrained by the size of its parent bounds.
+ *
+ * \param crop The bounds of the crop to apply.
*
* Available since API level 31.
*/
-void ASurfaceTransaction_setSourceRect(ASurfaceTransaction* transaction,
- ASurfaceControl* surface_control, const ARect& source)
+void ASurfaceTransaction_setCrop(ASurfaceTransaction* transaction,
+ ASurfaceControl* surface_control, const ARect& crop)
__INTRODUCED_IN(31);
/**
- * \param destination Specifies the rect in the parent's space where this surface will be drawn. The
- * post source rect bounds are scaled to fit the destination rect. The surface's destination rect is
- * clipped by the bounds of its parent. The destination rect's width and height must be > 0.
+ * Specifies the position in the parent's space where the surface will be drawn.
+ *
+ * \param x The x position to render the surface.
+ * \param y The y position to render the surface.
*
* Available since API level 31.
*/
void ASurfaceTransaction_setPosition(ASurfaceTransaction* transaction,
- ASurfaceControl* surface_control, const ARect& destination)
+ ASurfaceControl* surface_control, int32_t x, int32_t y)
__INTRODUCED_IN(31);
/**
* \param transform The transform applied after the source rect is applied to the buffer. This
- * parameter should be set to 0 for no transform. To specify a transfrom use the
+ * parameter should be set to 0 for no transform. To specify a transform use the
* NATIVE_WINDOW_TRANSFORM_* enum.
*
* Available since API level 31.
*/
-void ASurfaceTransaction_setTransform(ASurfaceTransaction* transaction,
+void ASurfaceTransaction_setBufferTransform(ASurfaceTransaction* transaction,
ASurfaceControl* surface_control, int32_t transform)
__INTRODUCED_IN(31);
/**
+ * Sets an x and y scale of a surface with (0, 0) as the centerpoint of the scale.
+ *
+ * \param xScale The scale in the x direction. Must be greater than 0.
+ * \param yScale The scale in the y direction. Must be greater than 0.
+ *
+ * Available since API level 31.
+ */
+void ASurfaceTransaction_setScale(ASurfaceTransaction* transaction,
+ ASurfaceControl* surface_control, float xScale, float yScale)
+ __INTRODUCED_IN(31);
+/**
* Parameter for ASurfaceTransaction_setBufferTransparency().
*/
enum {
diff --git a/include/android/surface_texture.h b/include/android/surface_texture.h
index 4757254cc0..9ae211ea14 100644
--- a/include/android/surface_texture.h
+++ b/include/android/surface_texture.h
@@ -86,8 +86,8 @@ ANativeWindow* ASurfaceTexture_acquireANativeWindow(ASurfaceTexture* st) __INTRO
/**
* Attach the SurfaceTexture to the OpenGL ES context that is current on the calling thread. A
* new OpenGL ES texture object is created and populated with the SurfaceTexture image frame
- * that was current at the time of the last call to {@link #detachFromGLContext}. This new
- * texture is bound to the GL_TEXTURE_EXTERNAL_OES texture target.
+ * that was current at the time of the last call to {@link ASurfaceTexture_detachFromGLContext}.
+ * This new texture is bound to the GL_TEXTURE_EXTERNAL_OES texture target.
*
* This can be used to access the SurfaceTexture image contents from multiple OpenGL ES
* contexts. Note, however, that the image contents are only accessible from one OpenGL ES
@@ -106,8 +106,8 @@ int ASurfaceTexture_attachToGLContext(ASurfaceTexture* st, uint32_t texName) __I
* Detach the SurfaceTexture from the OpenGL ES context that owns the OpenGL ES texture object.
* This call must be made with the OpenGL ES context current on the calling thread. The OpenGL
* ES texture object will be deleted as a result of this call. After calling this method all
- * calls to {@link #updateTexImage} will fail until a successful call to {@link #attachToGLContext}
- * is made.
+ * calls to {@link ASurfaceTexture_updateTexImage} will fail until a successful call to
+ * {@link ASurfaceTexture_attachToGLContext} is made.
*
* This can be used to access the SurfaceTexture image contents from multiple OpenGL ES
* contexts. Note, however, that the image contents are only accessible from one OpenGL ES
diff --git a/include/android/thermal.h b/include/android/thermal.h
index 0ea13d3a8d..32580badc0 100644
--- a/include/android/thermal.h
+++ b/include/android/thermal.h
@@ -60,6 +60,10 @@
extern "C" {
#endif
+/**
+ * Thermal status used in function {@link AThermal_getCurrentThermalStatus} and
+ * {@link AThermal_StatusCallback}.
+ */
enum AThermalStatus {
/** Error in thermal status. */
ATHERMAL_STATUS_ERROR = -1,
@@ -194,10 +198,10 @@ int AThermal_unregisterThermalStatusListener(AThermalManager *manager,
*
* The value returned is a non-negative float that represents how much of the thermal envelope
* is in use (or is forecasted to be in use). A value of 1.0 indicates that the device is
- * (or will be) throttled at {@link #THERMAL_STATUS_SEVERE}. Such throttling can affect the
+ * (or will be) throttled at {@link #ATHERMAL_STATUS_SEVERE}. Such throttling can affect the
* CPU, GPU, and other subsystems. Values may exceed 1.0, but there is no implied mapping
* to specific thermal levels beyond that point. This means that values greater than 1.0
- * may correspond to {@link #THERMAL_STATUS_SEVERE}, but may also represent heavier throttling.
+ * may correspond to {@link #ATHERMAL_STATUS_SEVERE}, but may also represent heavier throttling.
*
* A value of 0.0 corresponds to a fixed distance from 1.0, but does not correspond to any
* particular thermal status or temperature. Values on (0.0, 1.0] may be expected to scale
diff --git a/include/android/trace.h b/include/android/trace.h
index dcefffb20d..d11158bb74 100644
--- a/include/android/trace.h
+++ b/include/android/trace.h
@@ -91,7 +91,7 @@ void ATrace_beginAsyncSection(const char* sectionName, int32_t cookie) __INTRODU
*
* Available since API level 29.
*
- * \param methodName The method name to appear in the trace.
+ * \param sectionName The method name to appear in the trace.
* \param cookie Unique identifier for distinguishing simultaneous events
*/
void ATrace_endAsyncSection(const char* sectionName, int32_t cookie) __INTRODUCED_IN(29);
diff --git a/include/android/window.h b/include/android/window.h
index 436bf3a830..c1448646b6 100644
--- a/include/android/window.h
+++ b/include/android/window.h
@@ -103,8 +103,9 @@ enum {
* bar) while this window is displayed. This allows the window to
* use the entire display space for itself -- the status bar will
* be hidden when an app window with this flag set is on the top
- * layer. A fullscreen window will ignore a value of {@link
- * AWINDOW_SOFT_INPUT_ADJUST_RESIZE}; the window will stay
+ * layer. A fullscreen window will ignore a value of
+ * <a href="/reference/android/view/WindowManager.LayoutParams#SOFT_INPUT_ADJUST_RESIZE">
+ * SOFT_INPUT_ADJUST_RESIZE</a>; the window will stay
* fullscreen and will not resize.
*/
AWINDOW_FLAG_FULLSCREEN = 0x00000400,
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index e980dd04ec..a97cf87de3 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -60,10 +60,6 @@ cc_library_headers {
// Currently, these are only on system android (not vendor, not host)
// TODO(b/183654927) - move these into separate libraries
libbinder_device_interface_sources = [
- "AppOpsManager.cpp",
- "IAppOpsCallback.cpp",
- "IAppOpsService.cpp",
-
"IPermissionController.cpp",
"PermissionCache.cpp",
"PermissionController.cpp",
@@ -160,6 +156,7 @@ cc_library {
"-Werror",
"-Wzero-as-null-pointer-constant",
"-DANDROID_BASE_UNIQUE_FD_DISABLE_IMPLICIT_CONVERSION",
+ "-DANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION",
],
product_variables: {
binder32bit: {
@@ -192,6 +189,9 @@ cc_library {
// Only check our headers
"--header-filter=^.*frameworks/native/libs/binder/.*.h$",
],
+ tidy_checks: [
+ "-performance-no-int-to-ptr",
+ ],
tidy_checks_as_errors: [
// Explicitly list the checks that should not occur in this module.
"abseil-*",
@@ -199,20 +199,9 @@ cc_library {
"bugprone-*",
"cert-*",
"clang-analyzer-*",
- "-clang-analyzer-core.CallAndMessage",
- "-clang-analyzer-core.uninitialized.Assign",
- "-clang-analyzer-unix.Malloc",
- "-clang-analyzer-deadcode.DeadStores",
- "-clang-analyzer-optin.cplusplus.UninitializedObject",
"google-*",
- "-google-readability-*",
- "-google-runtime-references",
"misc-*",
- "-misc-no-recursion",
- "-misc-redundant-expression",
- "-misc-unused-using-decls",
"performance*",
- "-performance-no-int-to-ptr",
"portability*",
],
diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp
index 53b36fffdc..fdcf94acfa 100644
--- a/libs/binder/BpBinder.cpp
+++ b/libs/binder/BpBinder.cpp
@@ -107,8 +107,7 @@ void BpBinder::ObjectManager::kill()
// ---------------------------------------------------------------------------
-
-BpBinder* BpBinder::create(int32_t handle) {
+sp<BpBinder> BpBinder::create(int32_t handle) {
int32_t trackedUid = -1;
if (sCountByUidEnabled) {
trackedUid = IPCThreadState::self()->getCallingUid();
@@ -134,10 +133,10 @@ BpBinder* BpBinder::create(int32_t handle) {
}
sTrackingMap[trackedUid]++;
}
- return new BpBinder(BinderHandle{handle}, trackedUid);
+ return sp<BpBinder>::make(BinderHandle{handle}, trackedUid);
}
-BpBinder* BpBinder::create(const sp<RpcConnection>& connection, const RpcAddress& address) {
+sp<BpBinder> BpBinder::create(const sp<RpcConnection>& connection, const RpcAddress& address) {
LOG_ALWAYS_FATAL_IF(connection == nullptr, "BpBinder::create null connection");
// These are not currently tracked, since there is no UID or other
@@ -145,7 +144,7 @@ BpBinder* BpBinder::create(const sp<RpcConnection>& connection, const RpcAddress
// needed, connection objects keep track of all BpBinder objects on a
// per-connection basis.
- return new BpBinder(SocketHandle{connection, address});
+ return sp<BpBinder>::make(SocketHandle{connection, address});
}
BpBinder::BpBinder(Handle&& handle)
@@ -194,7 +193,7 @@ bool BpBinder::isDescriptorCached() const {
const String16& BpBinder::getInterfaceDescriptor() const
{
if (isDescriptorCached() == false) {
- sp<BpBinder> thiz = const_cast<BpBinder*>(this);
+ sp<BpBinder> thiz = sp<BpBinder>::fromExisting(const_cast<BpBinder*>(this));
Parcel data;
data.markForBinder(thiz);
@@ -226,7 +225,7 @@ bool BpBinder::isBinderAlive() const
status_t BpBinder::pingBinder()
{
Parcel data;
- data.markForBinder(this);
+ data.markForBinder(sp<BpBinder>::fromExisting(this));
Parcel reply;
return transact(PING_TRANSACTION, data, &reply);
}
@@ -403,7 +402,7 @@ void BpBinder::reportOneDeath(const Obituary& obit)
ALOGV("Reporting death to recipient: %p\n", recipient.get());
if (recipient == nullptr) return;
- recipient->binderDied(this);
+ recipient->binderDied(wp<BpBinder>::fromExisting(this));
}
diff --git a/libs/binder/BufferedTextOutput.cpp b/libs/binder/BufferedTextOutput.cpp
index 349658ecfa..a90bfd29ba 100644
--- a/libs/binder/BufferedTextOutput.cpp
+++ b/libs/binder/BufferedTextOutput.cpp
@@ -254,7 +254,7 @@ BufferedTextOutput::BufferState* BufferedTextOutput::getBuffer() const
BufferState* bs = ts.states[mIndex].get();
if (bs != nullptr && bs->seq == mSeq) return bs;
- ts.states.editItemAt(mIndex) = new BufferState(mIndex);
+ ts.states.editItemAt(mIndex) = sp<BufferState>::make(mIndex);
bs = ts.states[mIndex].get();
if (bs != nullptr) return bs;
}
diff --git a/libs/binder/IInterface.cpp b/libs/binder/IInterface.cpp
index b19004d454..2780bd4cd9 100644
--- a/libs/binder/IInterface.cpp
+++ b/libs/binder/IInterface.cpp
@@ -33,14 +33,14 @@ IInterface::~IInterface() {
sp<IBinder> IInterface::asBinder(const IInterface* iface)
{
if (iface == nullptr) return nullptr;
- return const_cast<IInterface*>(iface)->onAsBinder();
+ return sp<IBinder>::fromExisting(const_cast<IInterface*>(iface)->onAsBinder());
}
// static
sp<IBinder> IInterface::asBinder(const sp<IInterface>& iface)
{
if (iface == nullptr) return nullptr;
- return iface->onAsBinder();
+ return sp<IBinder>::fromExisting(iface->onAsBinder());
}
diff --git a/libs/binder/IMemory.cpp b/libs/binder/IMemory.cpp
index cca8f81e45..bd974b02b1 100644
--- a/libs/binder/IMemory.cpp
+++ b/libs/binder/IMemory.cpp
@@ -68,7 +68,7 @@ private:
// TODO: Reimplemement based on standard C++ container?
};
-static sp<HeapCache> gHeapCache = new HeapCache();
+static sp<HeapCache> gHeapCache = sp<HeapCache>::make();
/******************************************************************************/
@@ -288,7 +288,7 @@ void BpMemoryHeap::assertMapped() const
int32_t heapId = mHeapId.load(memory_order_acquire);
if (heapId == -1) {
sp<IBinder> binder(IInterface::asBinder(const_cast<BpMemoryHeap*>(this)));
- sp<BpMemoryHeap> heap(static_cast<BpMemoryHeap*>(find_heap(binder).get()));
+ sp<BpMemoryHeap> heap = sp<BpMemoryHeap>::cast(find_heap(binder));
heap->assertReallyMapped();
if (heap->mBase != MAP_FAILED) {
Mutex::Autolock _l(mLock);
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index 406bd54e6f..6fb1227f63 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -90,6 +90,8 @@ static const char *kReturnStrings[] = {
"BR_DEAD_BINDER",
"BR_CLEAR_DEATH_NOTIFICATION_DONE",
"BR_FAILED_REPLY",
+ "BR_FROZEN_REPLY",
+ "BR_ONEWAY_SPAM_SUSPECT",
"BR_TRANSACTION_SEC_CTX",
};
@@ -894,6 +896,11 @@ status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
}
switch (cmd) {
+ case BR_ONEWAY_SPAM_SUSPECT:
+ ALOGE("Process seems to be sending too many oneway calls.");
+ CallStack::logStack("oneway spamming", CallStack::getCurrent().get(),
+ ANDROID_LOG_ERROR);
+ [[fallthrough]];
case BR_TRANSACTION_COMPLETE:
if (!reply && !acquireResult) goto finish;
break;
diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp
index ca067e2d7f..f684cf672f 100644
--- a/libs/binder/IServiceManager.cpp
+++ b/libs/binder/IServiceManager.cpp
@@ -75,6 +75,7 @@ public:
sp<IBinder> waitForService(const String16& name16) override;
bool isDeclared(const String16& name) override;
Vector<String16> getDeclaredInstances(const String16& interface) override;
+ std::optional<String16> updatableViaApex(const String16& name) override;
// for legacy ABI
const String16& getInterfaceDescriptor() const override {
@@ -102,7 +103,7 @@ sp<IServiceManager> defaultServiceManager()
}
}
- gDefaultServiceManager = new ServiceManagerShim(sm);
+ gDefaultServiceManager = sp<ServiceManagerShim>::make(sm);
});
return gDefaultServiceManager;
@@ -324,7 +325,7 @@ sp<IBinder> ServiceManagerShim::waitForService(const String16& name16)
}
if (out != nullptr) return out;
- sp<Waiter> waiter = new Waiter;
+ sp<Waiter> waiter = sp<Waiter>::make();
if (!mTheRealServiceManager->registerForNotifications(
name, waiter).isOk()) {
return nullptr;
@@ -388,4 +389,12 @@ Vector<String16> ServiceManagerShim::getDeclaredInstances(const String16& interf
return res;
}
+std::optional<String16> ServiceManagerShim::updatableViaApex(const String16& name) {
+ std::optional<std::string> declared;
+ if (!mTheRealServiceManager->updatableViaApex(String8(name).c_str(), &declared).isOk()) {
+ return std::nullopt;
+ }
+ return declared ? std::optional<String16>(String16(declared.value().c_str())) : std::nullopt;
+}
+
} // namespace android
diff --git a/libs/binder/LazyServiceRegistrar.cpp b/libs/binder/LazyServiceRegistrar.cpp
index f96b6bb4eb..b503bebc5e 100644
--- a/libs/binder/LazyServiceRegistrar.cpp
+++ b/libs/binder/LazyServiceRegistrar.cpp
@@ -129,7 +129,9 @@ bool ClientCounterCallbackImpl::registerService(const sp<IBinder>& service, cons
}
if (!reRegister) {
- if(!manager->registerClientCallback(name, service, this).isOk()) {
+ if (!manager->registerClientCallback(name, service,
+ sp<android::os::IClientCallback>::fromExisting(this))
+ .isOk()) {
ALOGE("Failed to add client callback for service %s", name.c_str());
return false;
}
diff --git a/libs/binder/MemoryDealer.cpp b/libs/binder/MemoryDealer.cpp
index b46b3e88fc..c4475c7780 100644
--- a/libs/binder/MemoryDealer.cpp
+++ b/libs/binder/MemoryDealer.cpp
@@ -228,10 +228,8 @@ Allocation::~Allocation()
// ----------------------------------------------------------------------------
MemoryDealer::MemoryDealer(size_t size, const char* name, uint32_t flags)
- : mHeap(new MemoryHeapBase(size, flags, name)),
- mAllocator(new SimpleBestFitAllocator(size))
-{
-}
+ : mHeap(sp<MemoryHeapBase>::make(size, flags, name)),
+ mAllocator(new SimpleBestFitAllocator(size)) {}
MemoryDealer::~MemoryDealer()
{
@@ -243,7 +241,7 @@ sp<IMemory> MemoryDealer::allocate(size_t size)
sp<IMemory> memory;
const ssize_t offset = allocator()->allocate(size);
if (offset >= 0) {
- memory = new Allocation(this, heap(), offset, size);
+ memory = sp<Allocation>::make(sp<MemoryDealer>::fromExisting(this), heap(), offset, size);
}
return memory;
}
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 0425159f63..a73530938c 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -293,7 +293,8 @@ status_t Parcel::unflattenBinder(sp<IBinder>* out) const
if (flat) {
switch (flat->hdr.type) {
case BINDER_TYPE_BINDER: {
- sp<IBinder> binder = reinterpret_cast<IBinder*>(flat->cookie);
+ sp<IBinder> binder =
+ sp<IBinder>::fromExisting(reinterpret_cast<IBinder*>(flat->cookie));
return finishUnflattenBinder(binder, out);
}
case BINDER_TYPE_HANDLE: {
diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
index abb792eda0..1d3beb4736 100644
--- a/libs/binder/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -43,6 +43,7 @@
#define BINDER_VM_SIZE ((1 * 1024 * 1024) - sysconf(_SC_PAGE_SIZE) * 2)
#define DEFAULT_MAX_BINDER_THREADS 15
+#define DEFAULT_ENABLE_ONEWAY_SPAM_DETECTION 1
#ifdef __ANDROID_VNDK__
const char* kDefaultDriver = "/dev/vndbinder";
@@ -105,7 +106,7 @@ sp<ProcessState> ProcessState::init(const char *driver, bool requireDefault)
}
std::lock_guard<std::mutex> l(gProcessMutex);
- gProcess = new ProcessState(driver);
+ gProcess = sp<ProcessState>::make(driver);
});
if (requireDefault) {
@@ -299,8 +300,8 @@ sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
return nullptr;
}
- b = BpBinder::create(handle);
- e->binder = b;
+ sp<BpBinder> b = BpBinder::create(handle);
+ e->binder = b.get();
if (b) e->refs = b->getWeakRefs();
result = b;
} else {
@@ -340,7 +341,7 @@ void ProcessState::spawnPooledThread(bool isMain)
if (mThreadPoolStarted) {
String8 name = makeBinderThreadName();
ALOGV("Spawning new pooled thread, name=%s\n", name.string());
- sp<Thread> t = new PoolThread(isMain);
+ sp<Thread> t = sp<PoolThread>::make(isMain);
t->run(name.string());
}
}
@@ -358,6 +359,15 @@ status_t ProcessState::setThreadPoolMaxThreadCount(size_t maxThreads) {
return result;
}
+status_t ProcessState::enableOnewaySpamDetection(bool enable) {
+ uint32_t enableDetection = enable ? 1 : 0;
+ if (ioctl(mDriverFD, BINDER_ENABLE_ONEWAY_SPAM_DETECTION, &enableDetection) == -1) {
+ ALOGI("Binder ioctl to enable oneway spam detection failed: %s", strerror(errno));
+ return -errno;
+ }
+ return NO_ERROR;
+}
+
void ProcessState::giveThreadPoolName() {
androidSetThreadName( makeBinderThreadName().string() );
}
@@ -388,6 +398,11 @@ static int open_driver(const char *driver)
if (result == -1) {
ALOGE("Binder ioctl to set max threads failed: %s", strerror(errno));
}
+ uint32_t enable = DEFAULT_ENABLE_ONEWAY_SPAM_DETECTION;
+ result = ioctl(fd, BINDER_ENABLE_ONEWAY_SPAM_DETECTION, &enable);
+ if (result == -1) {
+ ALOGI("Binder ioctl to enable oneway spam detection failed: %s", strerror(errno));
+ }
} else {
ALOGW("Opening '%s' failed: %s\n", driver, strerror(errno));
}
diff --git a/libs/binder/RpcConnection.cpp b/libs/binder/RpcConnection.cpp
index dab3246fc5..1388a801e4 100644
--- a/libs/binder/RpcConnection.cpp
+++ b/libs/binder/RpcConnection.cpp
@@ -18,6 +18,16 @@
#include <binder/RpcConnection.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#include <string_view>
+
#include <binder/Parcel.h>
#include <binder/Stability.h>
#include <utils/String8.h>
@@ -25,11 +35,6 @@
#include "RpcState.h"
#include "RpcWireFormat.h"
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <sys/un.h>
-#include <unistd.h>
-
#ifdef __GLIBC__
extern "C" pid_t gettid();
#endif
@@ -41,6 +46,7 @@ extern "C" pid_t gettid();
namespace android {
using base::unique_fd;
+using AddrInfo = std::unique_ptr<addrinfo, decltype(&freeaddrinfo)>;
RpcConnection::SocketAddress::~SocketAddress() {}
@@ -51,17 +57,22 @@ RpcConnection::RpcConnection() {
}
RpcConnection::~RpcConnection() {
LOG_RPC_DETAIL("RpcConnection destroyed %p", this);
+
+ std::lock_guard<std::mutex> _l(mSocketMutex);
+ LOG_ALWAYS_FATAL_IF(mServers.size() != 0,
+ "Should not be able to destroy a connection with servers in use.");
}
sp<RpcConnection> RpcConnection::make() {
- return new RpcConnection;
+ return sp<RpcConnection>::make();
}
class UnixSocketAddress : public RpcConnection::SocketAddress {
public:
explicit UnixSocketAddress(const char* path) : mAddr({.sun_family = AF_UNIX}) {
unsigned int pathLen = strlen(path) + 1;
- LOG_ALWAYS_FATAL_IF(pathLen > sizeof(mAddr.sun_path), "%u %s", pathLen, path);
+ LOG_ALWAYS_FATAL_IF(pathLen > sizeof(mAddr.sun_path), "Socket path is too long: %u %s",
+ pathLen, path);
memcpy(mAddr.sun_path, path, pathLen);
}
virtual ~UnixSocketAddress() {}
@@ -78,11 +89,11 @@ private:
};
bool RpcConnection::setupUnixDomainServer(const char* path) {
- return addServer(UnixSocketAddress(path));
+ return setupSocketServer(UnixSocketAddress(path));
}
bool RpcConnection::addUnixDomainClient(const char* path) {
- return addClient(UnixSocketAddress(path));
+ return addSocketClient(UnixSocketAddress(path));
}
#ifdef __BIONIC__
@@ -97,7 +108,7 @@ public:
}) {}
virtual ~VsockSocketAddress() {}
std::string toString() const override {
- return String8::format("cid %du port %du", mAddr.svm_cid, mAddr.svm_port).c_str();
+ return String8::format("cid %u port %u", mAddr.svm_cid, mAddr.svm_port).c_str();
}
const sockaddr* addr() const override { return reinterpret_cast<const sockaddr*>(&mAddr); }
size_t addrSize() const override { return sizeof(mAddr); }
@@ -110,63 +121,140 @@ bool RpcConnection::setupVsockServer(unsigned int port) {
// realizing value w/ this type at compile time to avoid ubsan abort
constexpr unsigned int kAnyCid = VMADDR_CID_ANY;
- return addServer(VsockSocketAddress(kAnyCid, port));
+ return setupSocketServer(VsockSocketAddress(kAnyCid, port));
}
bool RpcConnection::addVsockClient(unsigned int cid, unsigned int port) {
- return addClient(VsockSocketAddress(cid, port));
+ return addSocketClient(VsockSocketAddress(cid, port));
}
#endif // __BIONIC__
+class SocketAddressImpl : public RpcConnection::SocketAddress {
+public:
+ SocketAddressImpl(const sockaddr* addr, size_t size, const String8& desc)
+ : mAddr(addr), mSize(size), mDesc(desc) {}
+ [[nodiscard]] std::string toString() const override {
+ return std::string(mDesc.c_str(), mDesc.size());
+ }
+ [[nodiscard]] const sockaddr* addr() const override { return mAddr; }
+ [[nodiscard]] size_t addrSize() const override { return mSize; }
+ void set(const sockaddr* addr, size_t size) {
+ mAddr = addr;
+ mSize = size;
+ }
+
+private:
+ const sockaddr* mAddr = nullptr;
+ size_t mSize = 0;
+ String8 mDesc;
+};
+
+AddrInfo GetAddrInfo(const char* addr, unsigned int port) {
+ addrinfo hint{
+ .ai_flags = 0,
+ .ai_family = AF_UNSPEC,
+ .ai_socktype = SOCK_STREAM,
+ .ai_protocol = 0,
+ };
+ addrinfo* aiStart = nullptr;
+ if (int rc = getaddrinfo(addr, std::to_string(port).data(), &hint, &aiStart); 0 != rc) {
+ ALOGE("Unable to resolve %s:%u: %s", addr, port, gai_strerror(rc));
+ return AddrInfo(nullptr, nullptr);
+ }
+ if (aiStart == nullptr) {
+ ALOGE("Unable to resolve %s:%u: getaddrinfo returns null", addr, port);
+ return AddrInfo(nullptr, nullptr);
+ }
+ return AddrInfo(aiStart, &freeaddrinfo);
+}
+
+bool RpcConnection::setupInetServer(unsigned int port) {
+ auto aiStart = GetAddrInfo("127.0.0.1", port);
+ if (aiStart == nullptr) return false;
+ SocketAddressImpl socketAddress(nullptr, 0, String8::format("127.0.0.1:%u", port));
+ for (auto ai = aiStart.get(); ai != nullptr; ai = ai->ai_next) {
+ socketAddress.set(ai->ai_addr, ai->ai_addrlen);
+ if (setupSocketServer(socketAddress)) return true;
+ }
+ ALOGE("None of the socket address resolved for 127.0.0.1:%u can be set up as inet server.",
+ port);
+ return false;
+}
+
+bool RpcConnection::addInetClient(const char* addr, unsigned int port) {
+ auto aiStart = GetAddrInfo(addr, port);
+ if (aiStart == nullptr) return false;
+ SocketAddressImpl socketAddress(nullptr, 0, String8::format("%s:%u", addr, port));
+ for (auto ai = aiStart.get(); ai != nullptr; ai = ai->ai_next) {
+ socketAddress.set(ai->ai_addr, ai->ai_addrlen);
+ if (addSocketClient(socketAddress)) return true;
+ }
+ ALOGE("None of the socket address resolved for %s:%u can be added as inet client.", addr, port);
+ return false;
+}
+
+bool RpcConnection::addNullDebuggingClient() {
+ unique_fd serverFd(TEMP_FAILURE_RETRY(open("/dev/null", O_WRONLY | O_CLOEXEC)));
+
+ if (serverFd == -1) {
+ ALOGE("Could not connect to /dev/null: %s", strerror(errno));
+ return false;
+ }
+
+ addClient(std::move(serverFd));
+ return true;
+}
+
sp<IBinder> RpcConnection::getRootObject() {
- ExclusiveSocket socket(this, SocketUse::CLIENT);
- return state()->getRootObject(socket.fd(), this);
+ ExclusiveSocket socket(sp<RpcConnection>::fromExisting(this), SocketUse::CLIENT);
+ return state()->getRootObject(socket.fd(), sp<RpcConnection>::fromExisting(this));
}
status_t RpcConnection::transact(const RpcAddress& address, uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags) {
- ExclusiveSocket socket(this,
+ ExclusiveSocket socket(sp<RpcConnection>::fromExisting(this),
(flags & IBinder::FLAG_ONEWAY) ? SocketUse::CLIENT_ASYNC
: SocketUse::CLIENT);
- return state()->transact(socket.fd(), address, code, data, this, reply, flags);
+ return state()->transact(socket.fd(), address, code, data,
+ sp<RpcConnection>::fromExisting(this), reply, flags);
}
status_t RpcConnection::sendDecStrong(const RpcAddress& address) {
- ExclusiveSocket socket(this, SocketUse::CLIENT_REFCOUNT);
+ ExclusiveSocket socket(sp<RpcConnection>::fromExisting(this), SocketUse::CLIENT_REFCOUNT);
return state()->sendDecStrong(socket.fd(), address);
}
void RpcConnection::join() {
- // establish a connection
- {
- unique_fd clientFd(
- TEMP_FAILURE_RETRY(accept4(mServer.get(), nullptr, 0 /*length*/, SOCK_CLOEXEC)));
- if (clientFd < 0) {
- // If this log becomes confusing, should save more state from setupUnixDomainServer
- // in order to output here.
- ALOGE("Could not accept4 socket: %s", strerror(errno));
- return;
- }
-
- LOG_RPC_DETAIL("accept4 on fd %d yields fd %d", mServer.get(), clientFd.get());
-
- assignServerToThisThread(std::move(clientFd));
+ // TODO(b/185167543): do this dynamically, instead of from a static number
+ // of threads
+ unique_fd clientFd(
+ TEMP_FAILURE_RETRY(accept4(mServer.get(), nullptr, 0 /*length*/, SOCK_CLOEXEC)));
+ if (clientFd < 0) {
+ // If this log becomes confusing, should save more state from setupUnixDomainServer
+ // in order to output here.
+ ALOGE("Could not accept4 socket: %s", strerror(errno));
+ return;
}
- // We may not use the connection we just established (two threads might
- // establish connections for each other), but for now, just use one
- // server/socket connection.
- ExclusiveSocket socket(this, SocketUse::SERVER);
+ LOG_RPC_DETAIL("accept4 on fd %d yields fd %d", mServer.get(), clientFd.get());
+
+ // must be registered to allow arbitrary client code executing commands to
+ // be able to do nested calls (we can't only read from it)
+ sp<ConnectionSocket> socket = assignServerToThisThread(std::move(clientFd));
while (true) {
- status_t error = state()->getAndExecuteCommand(socket.fd(), this);
+ status_t error =
+ state()->getAndExecuteCommand(socket->fd, sp<RpcConnection>::fromExisting(this));
if (error != OK) {
ALOGI("Binder socket thread closing w/ status %s", statusToString(error).c_str());
- return;
+ break;
}
}
+
+ LOG_ALWAYS_FATAL_IF(!removeServerSocket(socket),
+ "bad state: socket object guaranteed to be in list");
}
void RpcConnection::setForServer(const wp<RpcServer>& server) {
@@ -177,7 +265,7 @@ wp<RpcServer> RpcConnection::server() {
return mForServer;
}
-bool RpcConnection::addServer(const SocketAddress& addr) {
+bool RpcConnection::setupSocketServer(const SocketAddress& addr) {
LOG_ALWAYS_FATAL_IF(mServer.get() != -1, "Each RpcConnection can only have one server.");
unique_fd serverFd(
@@ -203,7 +291,7 @@ bool RpcConnection::addServer(const SocketAddress& addr) {
return true;
}
-bool RpcConnection::addClient(const SocketAddress& addr) {
+bool RpcConnection::addSocketClient(const SocketAddress& addr) {
unique_fd serverFd(
TEMP_FAILURE_RETRY(socket(addr.addr()->sa_family, SOCK_STREAM | SOCK_CLOEXEC, 0)));
if (serverFd == -1) {
@@ -220,18 +308,34 @@ bool RpcConnection::addClient(const SocketAddress& addr) {
LOG_RPC_DETAIL("Socket at %s client with fd %d", addr.toString().c_str(), serverFd.get());
+ addClient(std::move(serverFd));
+ return true;
+}
+
+void RpcConnection::addClient(unique_fd&& fd) {
std::lock_guard<std::mutex> _l(mSocketMutex);
- sp<ConnectionSocket> connection = new ConnectionSocket();
- connection->fd = std::move(serverFd);
+ sp<ConnectionSocket> connection = sp<ConnectionSocket>::make();
+ connection->fd = std::move(fd);
mClients.push_back(connection);
- return true;
}
-void RpcConnection::assignServerToThisThread(base::unique_fd&& fd) {
+sp<RpcConnection::ConnectionSocket> RpcConnection::assignServerToThisThread(unique_fd&& fd) {
std::lock_guard<std::mutex> _l(mSocketMutex);
- sp<ConnectionSocket> connection = new ConnectionSocket();
+ sp<ConnectionSocket> connection = sp<ConnectionSocket>::make();
connection->fd = std::move(fd);
+ connection->exclusiveTid = gettid();
mServers.push_back(connection);
+
+ return connection;
+}
+
+bool RpcConnection::removeServerSocket(const sp<ConnectionSocket>& socket) {
+ std::lock_guard<std::mutex> _l(mSocketMutex);
+ if (auto it = std::find(mServers.begin(), mServers.end(), socket); it != mServers.end()) {
+ mServers.erase(it);
+ return true;
+ }
+ return false;
}
RpcConnection::ExclusiveSocket::ExclusiveSocket(const sp<RpcConnection>& connection, SocketUse use)
@@ -246,37 +350,31 @@ RpcConnection::ExclusiveSocket::ExclusiveSocket(const sp<RpcConnection>& connect
// CHECK FOR DEDICATED CLIENT SOCKET
//
- // A server/looper should always use a dedicated connection.
- if (use != SocketUse::SERVER) {
- findSocket(tid, &exclusive, &available, mConnection->mClients,
- mConnection->mClientsOffset);
-
- // WARNING: this assumes a server cannot request its client to send
- // a transaction, as mServers is excluded below.
- //
- // Imagine we have more than one thread in play, and a single thread
- // sends a synchronous, then an asynchronous command. Imagine the
- // asynchronous command is sent on the first client socket. Then, if
- // we naively send a synchronous command to that same socket, the
- // thread on the far side might be busy processing the asynchronous
- // command. So, we move to considering the second available thread
- // for subsequent calls.
- if (use == SocketUse::CLIENT_ASYNC && (exclusive != nullptr || available != nullptr)) {
- mConnection->mClientsOffset =
- (mConnection->mClientsOffset + 1) % mConnection->mClients.size();
- }
+ // A server/looper should always use a dedicated connection if available
+ findSocket(tid, &exclusive, &available, mConnection->mClients, mConnection->mClientsOffset);
+
+ // WARNING: this assumes a server cannot request its client to send
+ // a transaction, as mServers is excluded below.
+ //
+ // Imagine we have more than one thread in play, and a single thread
+ // sends a synchronous, then an asynchronous command. Imagine the
+ // asynchronous command is sent on the first client socket. Then, if
+ // we naively send a synchronous command to that same socket, the
+ // thread on the far side might be busy processing the asynchronous
+ // command. So, we move to considering the second available thread
+ // for subsequent calls.
+ if (use == SocketUse::CLIENT_ASYNC && (exclusive != nullptr || available != nullptr)) {
+ mConnection->mClientsOffset =
+ (mConnection->mClientsOffset + 1) % mConnection->mClients.size();
}
- // USE SERVING SOCKET (to start serving or for nested transaction)
+ // USE SERVING SOCKET (for nested transaction)
//
// asynchronous calls cannot be nested
if (use != SocketUse::CLIENT_ASYNC) {
- // servers should start serving on an available thread only
- // otherwise, this should only be a nested call
- bool useAvailable = use == SocketUse::SERVER;
-
- findSocket(tid, &exclusive, (useAvailable ? &available : nullptr),
- mConnection->mServers, 0 /* index hint */);
+ // server sockets are always assigned to a thread
+ findSocket(tid, &exclusive, nullptr /*available*/, mConnection->mServers,
+ 0 /* index hint */);
}
// if our thread is already using a connection, prioritize using that
@@ -290,8 +388,6 @@ RpcConnection::ExclusiveSocket::ExclusiveSocket(const sp<RpcConnection>& connect
break;
}
- LOG_ALWAYS_FATAL_IF(use == SocketUse::SERVER, "Must create connection to join one.");
-
// in regular binder, this would usually be a deadlock :)
LOG_ALWAYS_FATAL_IF(mConnection->mClients.size() == 0,
"Not a client of any connection. You must create a connection to an "
diff --git a/libs/binder/RpcServer.cpp b/libs/binder/RpcServer.cpp
index df07916f7a..1fa37bacb3 100644
--- a/libs/binder/RpcServer.cpp
+++ b/libs/binder/RpcServer.cpp
@@ -36,7 +36,7 @@ RpcServer::RpcServer() {}
RpcServer::~RpcServer() {}
sp<RpcServer> RpcServer::make() {
- return new RpcServer;
+ return sp<RpcServer>::make();
}
void RpcServer::iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction() {
@@ -47,7 +47,7 @@ sp<RpcConnection> RpcServer::addClientConnection() {
LOG_ALWAYS_FATAL_IF(!mAgreedExperimental, "no!");
auto connection = RpcConnection::make();
- connection->setForServer(this);
+ connection->setForServer(sp<RpcServer>::fromExisting(this));
mConnections.push_back(connection);
return connection;
}
diff --git a/libs/binder/RpcState.cpp b/libs/binder/RpcState.cpp
index 755ff35781..d9341369fa 100644
--- a/libs/binder/RpcState.cpp
+++ b/libs/binder/RpcState.cpp
@@ -40,7 +40,7 @@ status_t RpcState::onBinderLeaving(const sp<RpcConnection>& connection, const sp
// We need to be able to send instructions over the socket for how to
// connect to a different server, and we also need to let the host
// process know that this is happening.
- ALOGE("Canot send binder from unrelated binder RPC connection.");
+ ALOGE("Cannot send binder from unrelated binder RPC connection.");
return INVALID_OPERATION;
}
@@ -498,19 +498,20 @@ status_t RpcState::processTransactInternal(const base::unique_fd& fd,
}
}
- Parcel data;
- // transaction->data is owned by this function. Parcel borrows this data and
- // only holds onto it for the duration of this function call. Parcel will be
- // deleted before the 'transactionData' object.
- data.ipcSetDataReference(transaction->data,
- transactionData.size() - offsetof(RpcWireTransaction, data),
- nullptr /*object*/, 0 /*objectCount*/, do_nothing_to_transact_data);
- data.markForRpc(connection);
-
Parcel reply;
reply.markForRpc(connection);
if (replyStatus == OK) {
+ Parcel data;
+ // transaction->data is owned by this function. Parcel borrows this data and
+ // only holds onto it for the duration of this function call. Parcel will be
+ // deleted before the 'transactionData' object.
+ data.ipcSetDataReference(transaction->data,
+ transactionData.size() - offsetof(RpcWireTransaction, data),
+ nullptr /*object*/, 0 /*objectCount*/,
+ do_nothing_to_transact_data);
+ data.markForRpc(connection);
+
if (target) {
replyStatus = target->transact(transaction->code, data, &reply, transaction->flags);
} else {
diff --git a/libs/binder/aidl/android/os/IServiceManager.aidl b/libs/binder/aidl/android/os/IServiceManager.aidl
index 2fabf947cd..75c4092559 100644
--- a/libs/binder/aidl/android/os/IServiceManager.aidl
+++ b/libs/binder/aidl/android/os/IServiceManager.aidl
@@ -108,6 +108,11 @@ interface IServiceManager {
@utf8InCpp String[] getDeclaredInstances(@utf8InCpp String iface);
/**
+ * If updatable-via-apex, returns the APEX via which this is updated.
+ */
+ @nullable @utf8InCpp String updatableViaApex(@utf8InCpp String name);
+
+ /**
* Request a callback when the number of clients of the service changes.
* Used by LazyServiceRegistrar to dynamically stop services that have no clients.
*/
diff --git a/libs/binder/include/binder/Binder.h b/libs/binder/include/binder/Binder.h
index 7079544080..7e9be417e1 100644
--- a/libs/binder/include/binder/Binder.h
+++ b/libs/binder/include/binder/Binder.h
@@ -131,8 +131,8 @@ protected:
virtual void onLastStrongRef(const void* id);
virtual bool onIncStrongAttempted(uint32_t flags, const void* id);
- inline IBinder* remote() { return mRemote; }
- inline IBinder* remote() const { return mRemote; }
+ inline IBinder* remote() const { return mRemote; }
+ inline sp<IBinder> remoteStrong() const { return sp<IBinder>::fromExisting(mRemote); }
private:
BpRefBase(const BpRefBase& o);
diff --git a/libs/binder/include/binder/BpBinder.h b/libs/binder/include/binder/BpBinder.h
index 8ab789318d..ad618f9de4 100644
--- a/libs/binder/include/binder/BpBinder.h
+++ b/libs/binder/include/binder/BpBinder.h
@@ -40,8 +40,8 @@ using binder_proxy_limit_callback = void(*)(int);
class BpBinder : public IBinder
{
public:
- static BpBinder* create(int32_t handle);
- static BpBinder* create(const sp<RpcConnection>& connection, const RpcAddress& address);
+ static sp<BpBinder> create(int32_t handle);
+ static sp<BpBinder> create(const sp<RpcConnection>& connection, const RpcAddress& address);
/**
* Return value:
@@ -143,6 +143,7 @@ public:
private:
friend PrivateAccessorForId;
+ friend class sp<BpBinder>;
struct BinderHandle {
int32_t handle;
diff --git a/libs/binder/include/binder/IInterface.h b/libs/binder/include/binder/IInterface.h
index b86fc0b629..ff90b30380 100644
--- a/libs/binder/include/binder/IInterface.h
+++ b/libs/binder/include/binder/IInterface.h
@@ -143,11 +143,10 @@ public: \
{ \
::android::sp<I##INTERFACE> intr; \
if (obj != nullptr) { \
- intr = static_cast<I##INTERFACE*>( \
- obj->queryLocalInterface( \
- I##INTERFACE::descriptor).get()); \
+ intr = ::android::sp<I##INTERFACE>::cast( \
+ obj->queryLocalInterface(I##INTERFACE::descriptor)); \
if (intr == nullptr) { \
- intr = new Bp##INTERFACE(obj); \
+ intr = ::android::sp<Bp##INTERFACE>::make(obj); \
} \
} \
return intr; \
diff --git a/libs/binder/include/binder/IServiceManager.h b/libs/binder/include/binder/IServiceManager.h
index 5f0d056c5d..3dbe2c49f4 100644
--- a/libs/binder/include/binder/IServiceManager.h
+++ b/libs/binder/include/binder/IServiceManager.h
@@ -20,6 +20,8 @@
#include <utils/Vector.h>
#include <utils/String16.h>
+#include <optional>
+
namespace android {
// ----------------------------------------------------------------------
@@ -99,6 +101,12 @@ public:
* Get all instances of a service as declared in the VINTF manifest
*/
virtual Vector<String16> getDeclaredInstances(const String16& interface) = 0;
+
+ /**
+ * If this instance is updatable via an APEX, returns the APEX with which
+ * this can be updated.
+ */
+ virtual std::optional<String16> updatableViaApex(const String16& name) = 0;
};
sp<IServiceManager> defaultServiceManager();
diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h
index 211790d14c..957837233b 100644
--- a/libs/binder/include/binder/Parcel.h
+++ b/libs/binder/include/binder/Parcel.h
@@ -101,6 +101,10 @@ public:
// is for an RPC transaction).
void markForBinder(const sp<IBinder>& binder);
+ // Whenever possible, markForBinder should be preferred. This method is
+ // called automatically on reply Parcels for RPC transactions.
+ void markForRpc(const sp<RpcConnection>& connection);
+
// Whether this Parcel is written for RPC transactions (after calls to
// markForBinder or markForRpc).
bool isForRpc() const;
@@ -536,10 +540,6 @@ private:
const binder_size_t* objects, size_t objectsCount,
release_func relFunc);
- // Whenever possible, markForBinder should be preferred. This method is
- // called automatically on reply Parcels for RPC transactions.
- void markForRpc(const sp<RpcConnection>& connection);
-
status_t finishWrite(size_t len);
void releaseObjects();
void acquireObjects();
diff --git a/libs/binder/include/binder/ProcessState.h b/libs/binder/include/binder/ProcessState.h
index ca29440e7c..b9db5d726c 100644
--- a/libs/binder/include/binder/ProcessState.h
+++ b/libs/binder/include/binder/ProcessState.h
@@ -58,6 +58,7 @@ public:
void spawnPooledThread(bool isMain);
status_t setThreadPoolMaxThreadCount(size_t maxThreads);
+ status_t enableOnewaySpamDetection(bool enable);
void giveThreadPoolName();
String8 getDriverName();
@@ -88,7 +89,8 @@ private:
static sp<ProcessState> init(const char *defaultDriver, bool requireDefault);
friend class IPCThreadState;
-
+ friend class sp<ProcessState>;
+
explicit ProcessState(const char* driver);
~ProcessState();
diff --git a/libs/binder/include/binder/RpcConnection.h b/libs/binder/include/binder/RpcConnection.h
index efa922dbda..2395e78de2 100644
--- a/libs/binder/include/binder/RpcConnection.h
+++ b/libs/binder/include/binder/RpcConnection.h
@@ -74,6 +74,25 @@ public:
#endif // __BIONIC__
/**
+ * Creates an RPC server at the current port.
+ */
+ [[nodiscard]] bool setupInetServer(unsigned int port);
+
+ /**
+ * Connects to an RPC server at the given address and port.
+ */
+ [[nodiscard]] bool addInetClient(const char* addr, unsigned int port);
+
+ /**
+ * For debugging!
+ *
+ * Sets up an empty socket. All queries to this socket which require a
+ * response will never be satisfied. All data sent here will be
+ * unceremoniously cast down the bottomless pit, /dev/null.
+ */
+ [[nodiscard]] bool addNullDebuggingClient();
+
+ /**
* Query the other side of the connection for the root object hosted by that
* process's RpcServer (if one exists)
*/
@@ -109,10 +128,6 @@ private:
friend sp<RpcConnection>;
RpcConnection();
- bool addServer(const SocketAddress& address);
- bool addClient(const SocketAddress& address);
- void assignServerToThisThread(base::unique_fd&& fd);
-
struct ConnectionSocket : public RefBase {
base::unique_fd fd;
@@ -121,11 +136,16 @@ private:
std::optional<pid_t> exclusiveTid;
};
+ bool setupSocketServer(const SocketAddress& address);
+ bool addSocketClient(const SocketAddress& address);
+ void addClient(base::unique_fd&& fd);
+ sp<ConnectionSocket> assignServerToThisThread(base::unique_fd&& fd);
+ bool removeServerSocket(const sp<ConnectionSocket>& socket);
+
enum class SocketUse {
CLIENT,
CLIENT_ASYNC,
CLIENT_REFCOUNT,
- SERVER,
};
// RAII object for connection socket
diff --git a/libs/binder/include/binder/RpcServer.h b/libs/binder/include/binder/RpcServer.h
index a2c2aee7b8..d29b651f0b 100644
--- a/libs/binder/include/binder/RpcServer.h
+++ b/libs/binder/include/binder/RpcServer.h
@@ -72,6 +72,7 @@ public:
~RpcServer();
private:
+ friend sp<RpcServer>;
RpcServer();
bool mAgreedExperimental = false;
diff --git a/libs/binder/include/binder/Status.h b/libs/binder/include/binder/Status.h
index c30ae01d60..aaafa36d40 100644
--- a/libs/binder/include/binder/Status.h
+++ b/libs/binder/include/binder/Status.h
@@ -91,6 +91,9 @@ public:
static Status fromExceptionCode(int32_t exceptionCode,
const char* message);
+ // warning: this is still considered an error if it is constructed with a
+ // zero value error code. Please use Status::ok() instead and avoid zero
+ // error codes
static Status fromServiceSpecificError(int32_t serviceSpecificErrorCode);
static Status fromServiceSpecificError(int32_t serviceSpecificErrorCode,
const String8& message);
diff --git a/libs/binder/include/private/binder/binder_module.h b/libs/binder/include/private/binder/binder_module.h
index 157919903f..151235c16b 100644
--- a/libs/binder/include/private/binder/binder_module.h
+++ b/libs/binder/include/private/binder/binder_module.h
@@ -32,10 +32,6 @@
#include <sys/ioctl.h>
#include <linux/android/binder.h>
-#ifdef __cplusplus
-namespace android {
-#endif
-
#ifndef BR_FROZEN_REPLY
// Temporary definition of BR_FROZEN_REPLY. For production
// this will come from UAPI binder.h
@@ -88,8 +84,18 @@ struct binder_frozen_status_info {
};
#endif //BINDER_GET_FROZEN_INFO
-#ifdef __cplusplus
-} // namespace android
-#endif
+#ifndef BR_ONEWAY_SPAM_SUSPECT
+// Temporary definition of BR_ONEWAY_SPAM_SUSPECT. For production
+// this will come from UAPI binder.h
+#define BR_ONEWAY_SPAM_SUSPECT _IO('r', 19)
+#endif //BR_ONEWAY_SPAM_SUSPECT
+
+#ifndef BINDER_ENABLE_ONEWAY_SPAM_DETECTION
+/*
+ * Temporary definitions for oneway spam detection support. For the final version
+ * these will be defined in the UAPI binder.h file from upstream kernel.
+ */
+#define BINDER_ENABLE_ONEWAY_SPAM_DETECTION _IOW('b', 16, __u32)
+#endif //BINDER_ENABLE_ONEWAY_SPAM_DETECTION
#endif // _BINDER_MODULE_H_
diff --git a/libs/binder/ndk/include_ndk/android/binder_ibinder.h b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
index b9adc9a025..9e2050b411 100644
--- a/libs/binder/ndk/include_ndk/android/binder_ibinder.h
+++ b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
@@ -173,7 +173,7 @@ typedef binder_status_t (*AIBinder_Class_onTransact)(AIBinder* binder, transacti
* Available since API level 29.
*
* \param interfaceDescriptor this is a unique identifier for the class. This is used internally for
- * sanity checks on transactions.
+ * validity checks on transactions. This should be utf-8.
* \param onCreate see AIBinder_Class_onCreate.
* \param onDestroy see AIBinder_Class_onDestroy.
* \param onTransact see AIBinder_Class_onTransact.
@@ -645,7 +645,9 @@ binder_status_t AIBinder_setExtension(AIBinder* binder, AIBinder* ext) __INTRODU
*
* \return the class descriptor string. This pointer will never be null; a
* descriptor is required to define a class. The pointer is owned by the class
- * and will remain valid as long as the class does.
+ * and will remain valid as long as the class does. For a local class, this will
+ * be the same value (not necessarily pointer equal) as is passed into
+ * AIBinder_Class_define. Format is utf-8.
*/
const char* AIBinder_Class_getDescriptor(const AIBinder_Class* clazz) __INTRODUCED_IN(31);
@@ -669,7 +671,7 @@ const char* AIBinder_Class_getDescriptor(const AIBinder_Class* clazz) __INTRODUC
*
* \return whether "lhs < rhs" is true
*/
-bool AIBinder_lt(const AIBinder* lhs, const AIBinder* rhs);
+bool AIBinder_lt(const AIBinder* lhs, const AIBinder* rhs) __INTRODUCED_IN(31);
/**
* Clone an AIBinder_Weak. Useful because even if a weak binder promotes to a
@@ -683,7 +685,7 @@ bool AIBinder_lt(const AIBinder* lhs, const AIBinder* rhs);
* \return clone of the input parameter. This must be deleted with
* AIBinder_Weak_delete. Null if weak input parameter is also null.
*/
-AIBinder_Weak* AIBinder_Weak_clone(const AIBinder_Weak* weak);
+AIBinder_Weak* AIBinder_Weak_clone(const AIBinder_Weak* weak) __INTRODUCED_IN(31);
/**
* Whether AIBinder_Weak is less than another.
@@ -718,7 +720,7 @@ AIBinder_Weak* AIBinder_Weak_clone(const AIBinder_Weak* weak);
*
* \return whether "lhs < rhs" is true
*/
-bool AIBinder_Weak_lt(const AIBinder_Weak* lhs, const AIBinder_Weak* rhs);
+bool AIBinder_Weak_lt(const AIBinder_Weak* lhs, const AIBinder_Weak* rhs) __INTRODUCED_IN(31);
__END_DECLS
diff --git a/libs/binder/ndk/include_platform/android/binder_manager.h b/libs/binder/ndk/include_platform/android/binder_manager.h
index 55169140df..a90b4aabca 100644
--- a/libs/binder/ndk/include_platform/android/binder_manager.h
+++ b/libs/binder/ndk/include_platform/android/binder_manager.h
@@ -124,6 +124,15 @@ void AServiceManager_forEachDeclaredInstance(const char* interface, void* contex
__INTRODUCED_IN(31);
/**
+ * Check if a service is updatable via an APEX module.
+ *
+ * \param instance identifier of the service
+ *
+ * \return whether the interface is updatable via APEX
+ */
+bool AServiceManager_isUpdatableViaApex(const char* instance) __INTRODUCED_IN(31);
+
+/**
* Prevent lazy services without client from shutting down their process
*
* \param persist 'true' if the process should not exit.
diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt
index 67c85b66d4..7d4b82e4b6 100644
--- a/libs/binder/ndk/libbinder_ndk.map.txt
+++ b/libs/binder/ndk/libbinder_ndk.map.txt
@@ -118,14 +118,15 @@ LIBBINDER_NDK31 { # introduced=31
AIBinder_getCallingSid; # apex
AIBinder_setRequestingSid; # apex
AParcel_markSensitive; # llndk
- AServiceManager_isDeclared; # apex llndk
AServiceManager_forEachDeclaredInstance; # apex llndk
- AServiceManager_registerLazyService; # llndk
- AServiceManager_waitForService; # apex llndk
AServiceManager_forceLazyServicesPersist; # llndk
+ AServiceManager_isDeclared; # apex llndk
+ AServiceManager_isUpdatableViaApex; # apex
+ AServiceManager_reRegister; # llndk
+ AServiceManager_registerLazyService; # llndk
AServiceManager_setActiveServicesCallback; # llndk
AServiceManager_tryUnregister; # llndk
- AServiceManager_reRegister; # llndk
+ AServiceManager_waitForService; # apex llndk
AIBinder_forceDowngradeToSystemStability; # apex
AIBinder_forceDowngradeToVendorStability; # llndk
diff --git a/libs/binder/ndk/service_manager.cpp b/libs/binder/ndk/service_manager.cpp
index 1ccd0d2a2b..7649a26ff6 100644
--- a/libs/binder/ndk/service_manager.cpp
+++ b/libs/binder/ndk/service_manager.cpp
@@ -105,6 +105,14 @@ void AServiceManager_forEachDeclaredInstance(const char* interface, void* contex
callback(String8(instance).c_str(), context);
}
}
+bool AServiceManager_isUpdatableViaApex(const char* instance) {
+ if (instance == nullptr) {
+ return false;
+ }
+
+ sp<IServiceManager> sm = defaultServiceManager();
+ return sm->updatableViaApex(String16(instance)) != std::nullopt;
+}
void AServiceManager_forceLazyServicesPersist(bool persist) {
auto serviceRegistrar = android::binder::LazyServiceRegistrar::getInstance();
serviceRegistrar.forcePersist(persist);
diff --git a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
index 6a88401962..62db3cfbd2 100644
--- a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
+++ b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
@@ -300,6 +300,11 @@ TEST(NdkBinder, GetLazyService) {
EXPECT_EQ(STATUS_OK, AIBinder_ping(binder.get()));
}
+TEST(NdkBinder, IsUpdatable) {
+ bool isUpdatable = AServiceManager_isUpdatableViaApex("android.hardware.light.ILights/default");
+ EXPECT_EQ(isUpdatable, false);
+}
+
// This is too slow
TEST(NdkBinder, CheckLazyServiceShutDown) {
ndk::SpAIBinder binder(AServiceManager_waitForService(kLazyBinderNdkUnitTestService));
diff --git a/libs/binder/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h b/libs/binder/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h
index b92a6a9f8e..749bf212e6 100644
--- a/libs/binder/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h
+++ b/libs/binder/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h
@@ -20,5 +20,12 @@
#include <fuzzer/FuzzedDataProvider.h>
namespace android {
+/**
+ * Fill parcel data, including some random binder objects and FDs
+ */
void fillRandomParcel(Parcel* p, FuzzedDataProvider&& provider);
+/**
+ * Fill parcel data, but don't fill any objects.
+ */
+void fillRandomParcelData(Parcel* p, FuzzedDataProvider&& provider);
} // namespace android
diff --git a/libs/binder/parcel_fuzzer/main.cpp b/libs/binder/parcel_fuzzer/main.cpp
index 78606ccd91..332e2ada52 100644
--- a/libs/binder/parcel_fuzzer/main.cpp
+++ b/libs/binder/parcel_fuzzer/main.cpp
@@ -23,6 +23,7 @@
#include <iostream>
#include <android-base/logging.h>
+#include <binder/RpcConnection.h>
#include <fuzzbinder/random_parcel.h>
#include <fuzzer/FuzzedDataProvider.h>
@@ -32,6 +33,8 @@
#include <sys/time.h>
using android::fillRandomParcel;
+using android::RpcConnection;
+using android::sp;
void fillRandomParcel(::android::hardware::Parcel* p, FuzzedDataProvider&& provider) {
// TODO: functionality to create random parcels for libhwbinder parcels
@@ -56,7 +59,18 @@ void doFuzz(const char* backend, const std::vector<ParcelRead<P>>& reads,
provider.ConsumeIntegralInRange<size_t>(0, maxInstructions));
P p;
- fillRandomParcel(&p, std::move(provider));
+ if constexpr (std::is_same_v<P, android::Parcel>) {
+ if (provider.ConsumeBool()) {
+ auto connection = sp<RpcConnection>::make();
+ CHECK(connection->addNullDebuggingClient());
+ p.markForRpc(connection);
+ fillRandomParcelData(&p, std::move(provider));
+ } else {
+ fillRandomParcel(&p, std::move(provider));
+ }
+ } else {
+ fillRandomParcel(&p, std::move(provider));
+ }
// since we are only using a byte to index
CHECK(reads.size() <= 255) << reads.size();
diff --git a/libs/binder/parcel_fuzzer/random_parcel.cpp b/libs/binder/parcel_fuzzer/random_parcel.cpp
index 9ca4c8aca4..b045a22eff 100644
--- a/libs/binder/parcel_fuzzer/random_parcel.cpp
+++ b/libs/binder/parcel_fuzzer/random_parcel.cpp
@@ -75,4 +75,9 @@ void fillRandomParcel(Parcel* p, FuzzedDataProvider&& provider) {
}
}
+void fillRandomParcelData(Parcel* p, FuzzedDataProvider&& provider) {
+ std::vector<uint8_t> data = provider.ConsumeBytes<uint8_t>(provider.remaining_bytes());
+ CHECK(OK == p->write(data.data(), data.size()));
+}
+
} // namespace android
diff --git a/libs/binder/rust/Android.bp b/libs/binder/rust/Android.bp
index e12a429cf9..57c9013f60 100644
--- a/libs/binder/rust/Android.bp
+++ b/libs/binder/rust/Android.bp
@@ -65,15 +65,15 @@ rust_bindgen {
// rustified
"--constified-enum", "android::c_interface::consts::.*",
- "--whitelist-type", "android::c_interface::.*",
- "--whitelist-type", "AStatus",
- "--whitelist-type", "AIBinder_Class",
- "--whitelist-type", "AIBinder",
- "--whitelist-type", "AIBinder_Weak",
- "--whitelist-type", "AIBinder_DeathRecipient",
- "--whitelist-type", "AParcel",
- "--whitelist-type", "binder_status_t",
- "--whitelist-function", ".*",
+ "--allowlist-type", "android::c_interface::.*",
+ "--allowlist-type", "AStatus",
+ "--allowlist-type", "AIBinder_Class",
+ "--allowlist-type", "AIBinder",
+ "--allowlist-type", "AIBinder_Weak",
+ "--allowlist-type", "AIBinder_DeathRecipient",
+ "--allowlist-type", "AParcel",
+ "--allowlist-type", "binder_status_t",
+ "--allowlist-function", ".*",
],
shared_libs: [
"libbinder_ndk",
diff --git a/libs/binder/rust/src/binder.rs b/libs/binder/rust/src/binder.rs
index 321b422185..695a83e414 100644
--- a/libs/binder/rust/src/binder.rs
+++ b/libs/binder/rust/src/binder.rs
@@ -548,6 +548,28 @@ unsafe impl<T, V: AsNative<T>> AsNative<T> for Option<V> {
}
}
+/// The features to enable when creating a native Binder.
+///
+/// This should always be initialised with a default value, e.g.:
+/// ```
+/// # use binder::BinderFeatures;
+/// BinderFeatures {
+/// set_requesting_sid: true,
+/// ..BinderFeatures::default(),
+/// }
+/// ```
+#[derive(Clone, Debug, Default, Eq, PartialEq)]
+pub struct BinderFeatures {
+ /// Indicates that the service intends to receive caller security contexts. This must be true
+ /// for `ThreadState::with_calling_sid` to work.
+ pub set_requesting_sid: bool,
+ // Ensure that clients include a ..BinderFeatures::default() to preserve backwards compatibility
+ // when new fields are added. #[non_exhaustive] doesn't work because it prevents struct
+ // expressions entirely.
+ #[doc(hidden)]
+ pub _non_exhaustive: (),
+}
+
/// Declare typed interfaces for a binder object.
///
/// Given an interface trait and descriptor string, create a native and remote
@@ -730,8 +752,9 @@ macro_rules! declare_binder_interface {
impl $native {
/// Create a new binder service.
- pub fn new_binder<T: $interface + Sync + Send + 'static>(inner: T) -> $crate::Strong<dyn $interface> {
- let binder = $crate::Binder::new_with_stability($native(Box::new(inner)), $stability);
+ pub fn new_binder<T: $interface + Sync + Send + 'static>(inner: T, features: $crate::BinderFeatures) -> $crate::Strong<dyn $interface> {
+ let mut binder = $crate::Binder::new_with_stability($native(Box::new(inner)), $stability);
+ $crate::IBinderInternal::set_requesting_sid(&mut binder, features.set_requesting_sid);
$crate::Strong::new(Box::new(binder))
}
}
diff --git a/libs/binder/rust/src/lib.rs b/libs/binder/rust/src/lib.rs
index 30928a5cff..2694cba870 100644
--- a/libs/binder/rust/src/lib.rs
+++ b/libs/binder/rust/src/lib.rs
@@ -107,10 +107,9 @@ use binder_ndk_sys as sys;
pub mod parcel;
pub use crate::binder::{
- FromIBinder, IBinder, IBinderInternal, Interface, InterfaceClass, Remotable,
- Stability, Strong, TransactionCode, TransactionFlags, Weak,
- FIRST_CALL_TRANSACTION, FLAG_CLEAR_BUF, FLAG_ONEWAY, FLAG_PRIVATE_LOCAL,
- LAST_CALL_TRANSACTION,
+ BinderFeatures, FromIBinder, IBinder, IBinderInternal, Interface, InterfaceClass, Remotable,
+ Stability, Strong, TransactionCode, TransactionFlags, Weak, FIRST_CALL_TRANSACTION,
+ FLAG_CLEAR_BUF, FLAG_ONEWAY, FLAG_PRIVATE_LOCAL, LAST_CALL_TRANSACTION,
};
pub use error::{status_t, ExceptionCode, Result, Status, StatusCode};
pub use native::add_service;
@@ -125,8 +124,8 @@ pub mod public_api {
pub use super::parcel::ParcelFileDescriptor;
pub use super::{add_service, get_interface};
pub use super::{
- DeathRecipient, ExceptionCode, IBinder, Interface, ProcessState, SpIBinder, Status,
- StatusCode, Strong, ThreadState, Weak, WpIBinder,
+ BinderFeatures, DeathRecipient, ExceptionCode, IBinder, Interface, ProcessState, SpIBinder,
+ Status, StatusCode, Strong, ThreadState, Weak, WpIBinder,
};
/// Binder result containing a [`Status`] on error.
diff --git a/libs/binder/rust/tests/Android.bp b/libs/binder/rust/tests/Android.bp
index 0bf76c696a..607860f462 100644
--- a/libs/binder/rust/tests/Android.bp
+++ b/libs/binder/rust/tests/Android.bp
@@ -114,8 +114,8 @@ rust_bindgen {
source_stem: "bindings",
cpp_std: "gnu++17",
bindgen_flags: [
- "--whitelist-type", "Transaction",
- "--whitelist-var", "TESTDATA_.*",
+ "--allowlist-type", "Transaction",
+ "--allowlist-var", "TESTDATA_.*",
],
shared_libs: [
diff --git a/libs/binder/rust/tests/integration.rs b/libs/binder/rust/tests/integration.rs
index 60e3502759..03320076cb 100644
--- a/libs/binder/rust/tests/integration.rs
+++ b/libs/binder/rust/tests/integration.rs
@@ -19,7 +19,7 @@
use binder::declare_binder_interface;
use binder::parcel::Parcel;
use binder::{
- Binder, IBinderInternal, Interface, StatusCode, ThreadState, TransactionCode,
+ Binder, BinderFeatures, IBinderInternal, Interface, StatusCode, ThreadState, TransactionCode,
FIRST_CALL_TRANSACTION,
};
use std::convert::{TryFrom, TryInto};
@@ -55,7 +55,8 @@ fn main() -> Result<(), &'static str> {
})));
service.set_requesting_sid(true);
if let Some(extension_name) = extension_name {
- let extension = BnTest::new_binder(TestService { s: extension_name });
+ let extension =
+ BnTest::new_binder(TestService { s: extension_name }, BinderFeatures::default());
service
.set_extension(&mut extension.as_binder())
.expect("Could not add extension");
@@ -212,8 +213,8 @@ mod tests {
use std::time::Duration;
use binder::{
- Binder, DeathRecipient, FromIBinder, IBinder, IBinderInternal, Interface, SpIBinder,
- StatusCode, Strong,
+ Binder, BinderFeatures, DeathRecipient, FromIBinder, IBinder, IBinderInternal, Interface,
+ SpIBinder, StatusCode, Strong,
};
use super::{BnTest, ITest, ITestSameDescriptor, TestService, RUST_SERVICE_BINARY};
@@ -495,9 +496,12 @@ mod tests {
#[test]
fn reassociate_rust_binder() {
let service_name = "testing_service";
- let service_ibinder = BnTest::new_binder(TestService {
- s: service_name.to_string(),
- })
+ let service_ibinder = BnTest::new_binder(
+ TestService {
+ s: service_name.to_string(),
+ },
+ BinderFeatures::default(),
+ )
.as_binder();
let service: Strong<dyn ITest> = service_ibinder
@@ -510,9 +514,12 @@ mod tests {
#[test]
fn weak_binder_upgrade() {
let service_name = "testing_service";
- let service = BnTest::new_binder(TestService {
- s: service_name.to_string(),
- });
+ let service = BnTest::new_binder(
+ TestService {
+ s: service_name.to_string(),
+ },
+ BinderFeatures::default(),
+ );
let weak = Strong::downgrade(&service);
@@ -525,9 +532,12 @@ mod tests {
fn weak_binder_upgrade_dead() {
let service_name = "testing_service";
let weak = {
- let service = BnTest::new_binder(TestService {
- s: service_name.to_string(),
- });
+ let service = BnTest::new_binder(
+ TestService {
+ s: service_name.to_string(),
+ },
+ BinderFeatures::default(),
+ );
Strong::downgrade(&service)
};
@@ -538,9 +548,12 @@ mod tests {
#[test]
fn weak_binder_clone() {
let service_name = "testing_service";
- let service = BnTest::new_binder(TestService {
- s: service_name.to_string(),
- });
+ let service = BnTest::new_binder(
+ TestService {
+ s: service_name.to_string(),
+ },
+ BinderFeatures::default(),
+ );
let weak = Strong::downgrade(&service);
let cloned = weak.clone();
@@ -556,12 +569,18 @@ mod tests {
#[test]
#[allow(clippy::eq_op)]
fn binder_ord() {
- let service1 = BnTest::new_binder(TestService {
- s: "testing_service1".to_string(),
- });
- let service2 = BnTest::new_binder(TestService {
- s: "testing_service2".to_string(),
- });
+ let service1 = BnTest::new_binder(
+ TestService {
+ s: "testing_service1".to_string(),
+ },
+ BinderFeatures::default(),
+ );
+ let service2 = BnTest::new_binder(
+ TestService {
+ s: "testing_service2".to_string(),
+ },
+ BinderFeatures::default(),
+ );
assert!(!(service1 < service1));
assert!(!(service1 > service1));
diff --git a/libs/binder/rust/tests/ndk_rust_interop.rs b/libs/binder/rust/tests/ndk_rust_interop.rs
index ce75ab7125..4702e45f1f 100644
--- a/libs/binder/rust/tests/ndk_rust_interop.rs
+++ b/libs/binder/rust/tests/ndk_rust_interop.rs
@@ -16,15 +16,13 @@
//! Rust Binder NDK interop tests
-use std::ffi::CStr;
-use std::os::raw::{c_char, c_int};
-use ::IBinderRustNdkInteropTest::binder::{self, Interface, StatusCode};
use ::IBinderRustNdkInteropTest::aidl::IBinderRustNdkInteropTest::{
BnBinderRustNdkInteropTest, IBinderRustNdkInteropTest,
};
-use ::IBinderRustNdkInteropTest::aidl::IBinderRustNdkInteropTestOther::{
- IBinderRustNdkInteropTestOther,
-};
+use ::IBinderRustNdkInteropTest::aidl::IBinderRustNdkInteropTestOther::IBinderRustNdkInteropTestOther;
+use ::IBinderRustNdkInteropTest::binder::{self, BinderFeatures, Interface, StatusCode};
+use std::ffi::CStr;
+use std::os::raw::{c_char, c_int};
/// Look up the provided AIDL service and call its echo method.
///
@@ -37,18 +35,21 @@ pub unsafe extern "C" fn rust_call_ndk(service_name: *const c_char) -> c_int {
// The Rust class descriptor pointer will not match the NDK one, but the
// descriptor strings match so this needs to still associate.
- let service: binder::Strong<dyn IBinderRustNdkInteropTest> = match binder::get_interface(service_name) {
- Err(e) => {
- eprintln!("Could not find Ndk service {}: {:?}", service_name, e);
- return StatusCode::NAME_NOT_FOUND as c_int;
- }
- Ok(service) => service,
- };
+ let service: binder::Strong<dyn IBinderRustNdkInteropTest> =
+ match binder::get_interface(service_name) {
+ Err(e) => {
+ eprintln!("Could not find Ndk service {}: {:?}", service_name, e);
+ return StatusCode::NAME_NOT_FOUND as c_int;
+ }
+ Ok(service) => service,
+ };
match service.echo("testing") {
- Ok(s) => if s != "testing" {
- return StatusCode::BAD_VALUE as c_int;
- },
+ Ok(s) => {
+ if s != "testing" {
+ return StatusCode::BAD_VALUE as c_int;
+ }
+ }
Err(e) => return e.into(),
}
@@ -88,7 +89,7 @@ impl IBinderRustNdkInteropTest for Service {
#[no_mangle]
pub unsafe extern "C" fn rust_start_service(service_name: *const c_char) -> c_int {
let service_name = CStr::from_ptr(service_name).to_str().unwrap();
- let service = BnBinderRustNdkInteropTest::new_binder(Service);
+ let service = BnBinderRustNdkInteropTest::new_binder(Service, BinderFeatures::default());
match binder::add_service(&service_name, service.as_binder()) {
Ok(_) => StatusCode::OK as c_int,
Err(e) => e as c_int,
diff --git a/libs/binder/rust/tests/serialization.rs b/libs/binder/rust/tests/serialization.rs
index f1b068ee43..66ba846c2d 100644
--- a/libs/binder/rust/tests/serialization.rs
+++ b/libs/binder/rust/tests/serialization.rs
@@ -18,11 +18,11 @@
//! access.
use binder::declare_binder_interface;
+use binder::parcel::ParcelFileDescriptor;
use binder::{
- Binder, ExceptionCode, Interface, Parcel, Result, SpIBinder, Status,
+ Binder, BinderFeatures, ExceptionCode, Interface, Parcel, Result, SpIBinder, Status,
StatusCode, TransactionCode,
};
-use binder::parcel::ParcelFileDescriptor;
use std::ffi::{c_void, CStr, CString};
use std::sync::Once;
@@ -85,7 +85,7 @@ static mut SERVICE: Option<SpIBinder> = None;
pub extern "C" fn rust_service() -> *mut c_void {
unsafe {
SERVICE_ONCE.call_once(|| {
- SERVICE = Some(BnReadParcelTest::new_binder(()).as_binder());
+ SERVICE = Some(BnReadParcelTest::new_binder((), BinderFeatures::default()).as_binder());
});
SERVICE.as_ref().unwrap().as_raw().cast()
}
@@ -108,8 +108,12 @@ impl ReadParcelTest for BpReadParcelTest {}
impl ReadParcelTest for () {}
#[allow(clippy::float_cmp)]
-fn on_transact(_service: &dyn ReadParcelTest, code: TransactionCode,
- parcel: &Parcel, reply: &mut Parcel) -> Result<()> {
+fn on_transact(
+ _service: &dyn ReadParcelTest,
+ code: TransactionCode,
+ parcel: &Parcel,
+ reply: &mut Parcel,
+) -> Result<()> {
match code {
bindings::Transaction_TEST_BOOL => {
assert_eq!(parcel.read::<bool>()?, true);
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index afc4b1b72c..f303b7c1e3 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -151,6 +151,27 @@ cc_test {
require_root: true,
}
+cc_benchmark {
+ name: "binderRpcBenchmark",
+ defaults: ["binder_test_defaults"],
+ host_supported: true,
+ target: {
+ darwin: {
+ enabled: false,
+ },
+ },
+ srcs: [
+ "binderRpcBenchmark.cpp",
+ "IBinderRpcBenchmark.aidl",
+ ],
+ shared_libs: [
+ "libbase",
+ "libbinder",
+ "liblog",
+ "libutils",
+ ],
+}
+
cc_test {
name: "binderThroughputTest",
defaults: ["binder_test_defaults"],
diff --git a/libs/binder/tests/IBinderRpcBenchmark.aidl b/libs/binder/tests/IBinderRpcBenchmark.aidl
new file mode 100644
index 0000000000..1457422d30
--- /dev/null
+++ b/libs/binder/tests/IBinderRpcBenchmark.aidl
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+interface IBinderRpcBenchmark {
+ @utf8InCpp String repeatString(@utf8InCpp String str);
+ IBinder repeatBinder(IBinder binder);
+}
diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp
index e2193fadab..dc8c0f157e 100644
--- a/libs/binder/tests/binderLibTest.cpp
+++ b/libs/binder/tests/binderLibTest.cpp
@@ -88,6 +88,7 @@ enum BinderLibTestTranscationCode {
BINDER_LIB_TEST_GETPID,
BINDER_LIB_TEST_ECHO_VECTOR,
BINDER_LIB_TEST_REJECT_BUF,
+ BINDER_LIB_TEST_CAN_GET_SID,
};
pid_t start_server_process(int arg2, bool usePoll = false)
@@ -1192,6 +1193,14 @@ TEST_F(BinderLibTest, BufRejected) {
EXPECT_NE(NO_ERROR, ret);
}
+TEST_F(BinderLibTest, GotSid) {
+ sp<IBinder> server = addServer();
+
+ Parcel data;
+ status_t ret = server->transact(BINDER_LIB_TEST_CAN_GET_SID, data, nullptr);
+ EXPECT_EQ(OK, ret);
+}
+
class BinderLibTestService : public BBinder
{
public:
@@ -1494,6 +1503,9 @@ class BinderLibTestService : public BBinder
case BINDER_LIB_TEST_REJECT_BUF: {
return data.objectsCount() == 0 ? BAD_VALUE : NO_ERROR;
}
+ case BINDER_LIB_TEST_CAN_GET_SID: {
+ return IPCThreadState::self()->getCallingSid() == nullptr ? BAD_VALUE : NO_ERROR;
+ }
default:
return UNKNOWN_TRANSACTION;
};
diff --git a/libs/binder/tests/binderRpcBenchmark.cpp b/libs/binder/tests/binderRpcBenchmark.cpp
new file mode 100644
index 0000000000..7c82226aef
--- /dev/null
+++ b/libs/binder/tests/binderRpcBenchmark.cpp
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2021 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 <BnBinderRpcBenchmark.h>
+#include <android-base/logging.h>
+#include <benchmark/benchmark.h>
+#include <binder/Binder.h>
+#include <binder/RpcConnection.h>
+#include <binder/RpcServer.h>
+
+#include <thread>
+
+#include <sys/types.h>
+#include <unistd.h>
+
+using android::BBinder;
+using android::IBinder;
+using android::interface_cast;
+using android::OK;
+using android::RpcConnection;
+using android::RpcServer;
+using android::sp;
+using android::binder::Status;
+
+class MyBinderRpcBenchmark : public BnBinderRpcBenchmark {
+ Status repeatString(const std::string& str, std::string* out) override {
+ *out = str;
+ return Status::ok();
+ }
+ Status repeatBinder(const sp<IBinder>& str, sp<IBinder>* out) override {
+ *out = str;
+ return Status::ok();
+ }
+};
+
+static sp<RpcConnection> gConnection = RpcConnection::make();
+
+void BM_getRootObject(benchmark::State& state) {
+ while (state.KeepRunning()) {
+ CHECK(gConnection->getRootObject() != nullptr);
+ }
+}
+BENCHMARK(BM_getRootObject);
+
+void BM_pingTransaction(benchmark::State& state) {
+ sp<IBinder> binder = gConnection->getRootObject();
+ CHECK(binder != nullptr);
+
+ while (state.KeepRunning()) {
+ CHECK_EQ(OK, binder->pingBinder());
+ }
+}
+BENCHMARK(BM_pingTransaction);
+
+void BM_repeatString(benchmark::State& state) {
+ sp<IBinder> binder = gConnection->getRootObject();
+ CHECK(binder != nullptr);
+ sp<IBinderRpcBenchmark> iface = interface_cast<IBinderRpcBenchmark>(binder);
+ CHECK(iface != nullptr);
+
+ // Googlers might see go/another-look-at-aidl-hidl-perf
+ //
+ // When I checked in July 2019, 99.5% of AIDL transactions and 99.99% of HIDL
+ // transactions were less than one page in size (system wide during a test
+ // involving media and camera). This is why this diverges from
+ // binderThroughputTest and hwbinderThroughputTest. Future consideration - get
+ // this data on continuous integration. Here we are testing sending a
+ // transaction of twice this size. In other cases, we should focus on
+ // benchmarks of particular usecases. If individual binder transactions like
+ // the ones tested here are fast, then Android performance will be dominated
+ // by how many binder calls work together (and by factors like the scheduler,
+ // thermal throttling, core choice, etc..).
+ std::string str = std::string(getpagesize() * 2, 'a');
+ CHECK_EQ(str.size(), getpagesize() * 2);
+
+ while (state.KeepRunning()) {
+ std::string out;
+ Status ret = iface->repeatString(str, &out);
+ CHECK(ret.isOk()) << ret;
+ }
+}
+BENCHMARK(BM_repeatString);
+
+void BM_repeatBinder(benchmark::State& state) {
+ sp<IBinder> binder = gConnection->getRootObject();
+ CHECK(binder != nullptr);
+ sp<IBinderRpcBenchmark> iface = interface_cast<IBinderRpcBenchmark>(binder);
+ CHECK(iface != nullptr);
+
+ while (state.KeepRunning()) {
+ // force creation of a new address
+ sp<IBinder> binder = sp<BBinder>::make();
+
+ sp<IBinder> out;
+ Status ret = iface->repeatBinder(binder, &out);
+ CHECK(ret.isOk()) << ret;
+ }
+}
+BENCHMARK(BM_repeatBinder);
+
+int main(int argc, char** argv) {
+ ::benchmark::Initialize(&argc, argv);
+ if (::benchmark::ReportUnrecognizedArguments(argc, argv)) return 1;
+
+ std::string addr = std::string(getenv("TMPDIR") ?: "/tmp") + "/binderRpcBenchmark";
+ (void)unlink(addr.c_str());
+
+ std::thread([addr]() {
+ sp<RpcServer> server = RpcServer::make();
+ server->setRootObject(sp<MyBinderRpcBenchmark>::make());
+
+ server->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
+
+ sp<RpcConnection> connection = server->addClientConnection();
+ CHECK(connection->setupUnixDomainServer(addr.c_str()));
+
+ connection->join();
+ }).detach();
+
+ for (size_t tries = 0; tries < 5; tries++) {
+ usleep(10000);
+ if (gConnection->addUnixDomainClient(addr.c_str())) goto success;
+ }
+ LOG(FATAL) << "Could not connect.";
+success:
+
+ ::benchmark::RunSpecifiedBenchmarks();
+}
diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp
index a51c98774e..dd68fdbc6d 100644
--- a/libs/binder/tests/binderRpcTest.cpp
+++ b/libs/binder/tests/binderRpcTest.cpp
@@ -80,11 +80,10 @@ public:
sp<RpcConnection> connection;
Status sendString(const std::string& str) override {
- std::cout << "Child received string: " << str << std::endl;
+ (void)str;
return Status::ok();
}
Status doubleString(const std::string& str, std::string* strstr) override {
- std::cout << "Child received string to double: " << str << std::endl;
*strstr = str + str;
return Status::ok();
}
@@ -199,13 +198,8 @@ private:
static std::string allocateSocketAddress() {
static size_t id = 0;
- static bool gUseTmp = access("/tmp/", F_OK) != -1;
-
- if (gUseTmp) {
- return "/tmp/binderRpcTest_" + std::to_string(id++);
- } else {
- return "/dev/binderRpcTest_" + std::to_string(id++);
- }
+ std::string temp = getenv("TMPDIR") ?: "/tmp";
+ return temp + "/binderRpcTest_" + std::to_string(id++);
};
struct ProcessConnection {
@@ -262,6 +256,7 @@ enum class SocketType {
#ifdef __BIONIC__
VSOCK,
#endif // __BIONIC__
+ INET,
};
static inline std::string PrintSocketType(const testing::TestParamInfo<SocketType>& info) {
switch (info.param) {
@@ -271,6 +266,8 @@ static inline std::string PrintSocketType(const testing::TestParamInfo<SocketTyp
case SocketType::VSOCK:
return "vm_socket";
#endif // __BIONIC__
+ case SocketType::INET:
+ return "inet_socket";
default:
LOG_ALWAYS_FATAL("Unknown socket type");
return "";
@@ -310,6 +307,9 @@ public:
CHECK(connection->setupVsockServer(port));
break;
#endif // __BIONIC__
+ case SocketType::INET:
+ CHECK(connection->setupInetServer(port));
+ break;
default:
LOG_ALWAYS_FATAL("Unknown socket type");
}
@@ -340,6 +340,9 @@ public:
if (ret.connection->addVsockClient(VMADDR_CID_LOCAL, port)) goto success;
break;
#endif // __BIONIC__
+ case SocketType::INET:
+ if (ret.connection->addInetClient("127.0.0.1", port)) goto success;
+ break;
default:
LOG_ALWAYS_FATAL("Unknown socket type");
}
@@ -745,7 +748,7 @@ TEST_P(BinderRpc, ThreadingStressTest) {
threads.push_back(std::thread([&] {
for (size_t j = 0; j < kNumCalls; j++) {
sp<IBinder> out;
- proc.rootIface->repeatBinder(proc.rootBinder, &out);
+ EXPECT_OK(proc.rootIface->repeatBinder(proc.rootBinder, &out));
EXPECT_EQ(proc.rootBinder, out);
}
}));
@@ -754,6 +757,28 @@ TEST_P(BinderRpc, ThreadingStressTest) {
for (auto& t : threads) t.join();
}
+TEST_P(BinderRpc, OnewayStressTest) {
+ constexpr size_t kNumClientThreads = 10;
+ constexpr size_t kNumServerThreads = 10;
+ constexpr size_t kNumCalls = 100;
+
+ auto proc = createRpcTestSocketServerProcess(kNumServerThreads);
+
+ std::vector<std::thread> threads;
+ for (size_t i = 0; i < kNumClientThreads; i++) {
+ threads.push_back(std::thread([&] {
+ for (size_t j = 0; j < kNumCalls; j++) {
+ EXPECT_OK(proc.rootIface->sendString("a"));
+ }
+
+ // check threads are not stuck
+ EXPECT_OK(proc.rootIface->sleepMs(250));
+ }));
+ }
+
+ for (auto& t : threads) t.join();
+}
+
TEST_P(BinderRpc, OnewayCallDoesNotWait) {
constexpr size_t kReallyLongTimeMs = 100;
constexpr size_t kSleepMs = kReallyLongTimeMs * 5;
@@ -857,12 +882,13 @@ TEST_P(BinderRpc, Fds) {
}
INSTANTIATE_TEST_CASE_P(PerSocket, BinderRpc,
- ::testing::Values(SocketType::UNIX
+ ::testing::ValuesIn({
+ SocketType::UNIX,
#ifdef __BIONIC__
- ,
- SocketType::VSOCK
+ SocketType::VSOCK,
#endif // __BIONIC__
- ),
+ SocketType::INET,
+ }),
PrintSocketType);
} // namespace android
diff --git a/libs/binder/tests/binderSafeInterfaceTest.cpp b/libs/binder/tests/binderSafeInterfaceTest.cpp
index ffb3ef2c70..c857d62cb2 100644
--- a/libs/binder/tests/binderSafeInterfaceTest.cpp
+++ b/libs/binder/tests/binderSafeInterfaceTest.cpp
@@ -226,7 +226,7 @@ public:
IncrementNativeHandle,
IncrementNoCopyNoMove,
IncrementParcelableVector,
- ToUpper,
+ DoubleString,
CallMeBack,
IncrementInt32,
IncrementUint32,
@@ -256,7 +256,7 @@ public:
virtual status_t increment(const NoCopyNoMove& a, NoCopyNoMove* aPlusOne) const = 0;
virtual status_t increment(const std::vector<TestParcelable>& a,
std::vector<TestParcelable>* aPlusOne) const = 0;
- virtual status_t toUpper(const String8& str, String8* upperStr) const = 0;
+ virtual status_t doubleString(const String8& str, String8* doubleStr) const = 0;
// As mentioned above, sp<IBinder> is already tested by setDeathToken
virtual void callMeBack(const sp<ICallback>& callback, int32_t a) const = 0;
virtual status_t increment(int32_t a, int32_t* aPlusOne) const = 0;
@@ -329,9 +329,10 @@ public:
std::vector<TestParcelable>*);
return callRemote<Signature>(Tag::IncrementParcelableVector, a, aPlusOne);
}
- status_t toUpper(const String8& str, String8* upperStr) const override {
+ status_t doubleString(const String8& str, String8* doubleStr) const override {
ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
- return callRemote<decltype(&ISafeInterfaceTest::toUpper)>(Tag::ToUpper, str, upperStr);
+ return callRemote<decltype(&ISafeInterfaceTest::doubleString)>(Tag::DoubleString, str,
+ doubleStr);
}
void callMeBack(const sp<ICallback>& callback, int32_t a) const override {
ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
@@ -454,10 +455,9 @@ public:
}
return NO_ERROR;
}
- status_t toUpper(const String8& str, String8* upperStr) const override {
+ status_t doubleString(const String8& str, String8* doubleStr) const override {
ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
- *upperStr = str;
- upperStr->toUpper();
+ *doubleStr = str + str;
return NO_ERROR;
}
void callMeBack(const sp<ICallback>& callback, int32_t a) const override {
@@ -548,8 +548,8 @@ public:
std::vector<TestParcelable>*) const;
return callLocal<Signature>(data, reply, &ISafeInterfaceTest::increment);
}
- case ISafeInterfaceTest::Tag::ToUpper: {
- return callLocal(data, reply, &ISafeInterfaceTest::toUpper);
+ case ISafeInterfaceTest::Tag::DoubleString: {
+ return callLocal(data, reply, &ISafeInterfaceTest::doubleString);
}
case ISafeInterfaceTest::Tag::CallMeBack: {
return callLocalAsync(data, reply, &ISafeInterfaceTest::callMeBack);
@@ -726,12 +726,12 @@ TEST_F(SafeInterfaceTest, TestIncremementParcelableVector) {
}
}
-TEST_F(SafeInterfaceTest, TestToUpper) {
- const String8 str{"Hello, world!"};
- String8 upperStr;
- status_t result = mSafeInterfaceTest->toUpper(str, &upperStr);
+TEST_F(SafeInterfaceTest, TestDoubleString) {
+ const String8 str{"asdf"};
+ String8 doubleStr;
+ status_t result = mSafeInterfaceTest->doubleString(str, &doubleStr);
ASSERT_EQ(NO_ERROR, result);
- ASSERT_TRUE(upperStr == String8{"HELLO, WORLD!"});
+ ASSERT_TRUE(doubleStr == String8{"asdfasdf"});
}
TEST_F(SafeInterfaceTest, TestCallMeBack) {
diff --git a/libs/binder/tests/binderStabilityTest.cpp b/libs/binder/tests/binderStabilityTest.cpp
index cb309bdd81..2ce13df4b3 100644
--- a/libs/binder/tests/binderStabilityTest.cpp
+++ b/libs/binder/tests/binderStabilityTest.cpp
@@ -192,6 +192,8 @@ TEST(BinderStability, VintfStabilityServerMustBeDeclaredInManifest) {
EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT,
android::defaultServiceManager()->addService(String16("."), vintfServer)) << instance8;
EXPECT_FALSE(android::defaultServiceManager()->isDeclared(instance)) << instance8;
+ EXPECT_EQ(std::nullopt, android::defaultServiceManager()->updatableViaApex(instance))
+ << instance8;
}
}
diff --git a/libs/fakeservicemanager/ServiceManager.cpp b/libs/fakeservicemanager/ServiceManager.cpp
index 4ecbe531c2..761e45c967 100644
--- a/libs/fakeservicemanager/ServiceManager.cpp
+++ b/libs/fakeservicemanager/ServiceManager.cpp
@@ -73,4 +73,9 @@ Vector<String16> ServiceManager::getDeclaredInstances(const String16& name) {
return out;
}
+std::optional<String16> ServiceManager::updatableViaApex(const String16& name) {
+ (void)name;
+ return std::nullopt;
+}
+
} // namespace android
diff --git a/libs/fakeservicemanager/ServiceManager.h b/libs/fakeservicemanager/ServiceManager.h
index 4ef47fb043..e26c21b9e9 100644
--- a/libs/fakeservicemanager/ServiceManager.h
+++ b/libs/fakeservicemanager/ServiceManager.h
@@ -19,6 +19,7 @@
#include <binder/IServiceManager.h>
#include <map>
+#include <optional>
namespace android {
@@ -48,6 +49,8 @@ public:
Vector<String16> getDeclaredInstances(const String16& iface) override;
+ std::optional<String16> updatableViaApex(const String16& name) override;
+
private:
std::map<String16, sp<IBinder>> mNameToService;
};
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index 7c11b03034..f734582377 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -39,22 +39,66 @@ cc_library_headers {
min_sdk_version: "29",
}
+cc_library_headers {
+ name: "libgui_aidl_headers",
+ vendor_available: true,
+ static_libs: [
+ "libgui_aidl_static",
+ ],
+
+ export_static_lib_headers: [
+ "libgui_aidl_static",
+ ],
+}
+
filegroup {
name: "libgui_aidl",
srcs: ["aidl/**/*.aidl"],
path: "aidl/",
}
+cc_library_static {
+ name: "libgui_aidl_static",
+ vendor_available: true,
+ srcs: [
+ ":libgui_aidl",
+ ],
+
+ shared_libs: [
+ "libbinder",
+ "libui",
+ ],
+
+ local_include_dirs: [
+ "include",
+ ],
+
+ export_shared_lib_headers: [
+ "libbinder",
+ ],
+
+ aidl: {
+ export_aidl_headers: true
+ }
+}
+
+
cc_defaults {
name: "libgui_defaults",
double_loadable: true,
defaults: ["libgui_bufferqueue-defaults"],
+ static_libs: [
+ "libgui_aidl_static",
+ ],
+ export_static_lib_headers: [
+ "libgui_aidl_static",
+ ],
+
srcs: [
":framework_native_aidl",
":inputconstants_aidl",
- ":libgui_aidl",
":libgui_bufferqueue_sources",
"BitTube.cpp",
@@ -110,6 +154,10 @@ cc_defaults {
"libinput",
],
+ export_header_lib_headers: [
+ "libgui_aidl_headers",
+ ],
+
// bufferhub is not used when building libgui for vendors
target: {
vendor: {
@@ -131,15 +179,16 @@ cc_defaults {
},
},
+ aidl: {
+ export_aidl_headers: true,
+ },
+
header_libs: [
"libdvr_headers",
+ "libgui_aidl_headers",
"libpdx_headers",
],
- aidl: {
- export_aidl_headers: true,
- },
-
pgo: {
sampling: true,
profile_file: "libgui/libgui.profdata",
@@ -170,8 +219,8 @@ cc_library_static {
srcs: [
":inputconstants_aidl",
- ":libgui_aidl",
":libgui_bufferqueue_sources",
+ ":libgui_aidl",
],
}
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index bcdd06b6c8..3d854c2b92 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -161,9 +161,9 @@ BLASTBufferQueue::BLASTBufferQueue(const std::string& name, const sp<SurfaceCont
mTransformHint = mSurfaceControl->getTransformHint();
mBufferItemConsumer->setTransformHint(mTransformHint);
SurfaceComposerClient::Transaction()
- .setFlags(surface, layer_state_t::eEnableBackpressure,
- layer_state_t::eEnableBackpressure)
- .apply();
+ .setFlags(surface, layer_state_t::eEnableBackpressure,
+ layer_state_t::eEnableBackpressure)
+ .apply();
mNumAcquired = 0;
mNumFrameAvailable = 0;
@@ -186,6 +186,7 @@ BLASTBufferQueue::~BLASTBufferQueue() {
void BLASTBufferQueue::update(const sp<SurfaceControl>& surface, uint32_t width, uint32_t height,
int32_t format) {
std::unique_lock _lock{mMutex};
+ BQA_LOGV("update width=%d height=%d format=%d", width, height, format);
if (mFormat != format) {
mFormat = format;
mBufferItemConsumer->setDefaultBufferFormat(convertBufferFormat(format));
@@ -204,13 +205,16 @@ void BLASTBufferQueue::update(const sp<SurfaceControl>& surface, uint32_t width,
if (mRequestedSize != newSize) {
mRequestedSize.set(newSize);
mBufferItemConsumer->setDefaultBufferSize(mRequestedSize.width, mRequestedSize.height);
- if (mLastBufferScalingMode != NATIVE_WINDOW_SCALING_MODE_FREEZE) {
+ if (mLastBufferInfo.scalingMode != NATIVE_WINDOW_SCALING_MODE_FREEZE) {
// If the buffer supports scaling, update the frame immediately since the client may
// want to scale the existing buffer to the new size.
mSize = mRequestedSize;
- t.setFrame(mSurfaceControl,
- {0, 0, static_cast<int32_t>(mSize.width),
- static_cast<int32_t>(mSize.height)});
+ // We only need to update the scale if we've received at least one buffer. The reason
+ // for this is the scale is calculated based on the requested size and buffer size.
+ // If there's no buffer, the scale will always be 1.
+ if (mLastBufferInfo.hasBuffer) {
+ setMatrix(&t, mLastBufferInfo);
+ }
applyTransaction = true;
}
}
@@ -239,29 +243,49 @@ void BLASTBufferQueue::transactionCallback(nsecs_t /*latchTime*/, const sp<Fence
ATRACE_CALL();
BQA_LOGV("transactionCallback");
- if (!stats.empty()) {
- mTransformHint = stats[0].transformHint;
- mBufferItemConsumer->setTransformHint(mTransformHint);
- mBufferItemConsumer
- ->updateFrameTimestamps(stats[0].frameEventStats.frameNumber,
- stats[0].frameEventStats.refreshStartTime,
- stats[0].frameEventStats.gpuCompositionDoneFence,
- stats[0].presentFence, stats[0].previousReleaseFence,
- stats[0].frameEventStats.compositorTiming,
- stats[0].latchTime,
- stats[0].frameEventStats.dequeueReadyTime);
- currFrameNumber = stats[0].frameEventStats.frameNumber;
-
- if (mTransactionCompleteCallback &&
- currFrameNumber >= mTransactionCompleteFrameNumber) {
- if (currFrameNumber > mTransactionCompleteFrameNumber) {
- BQA_LOGE("transactionCallback received for a newer framenumber=%" PRIu64
- " than expected=%" PRIu64,
- currFrameNumber, mTransactionCompleteFrameNumber);
+ if (!mSurfaceControlsWithPendingCallback.empty()) {
+ sp<SurfaceControl> pendingSC = mSurfaceControlsWithPendingCallback.front();
+ mSurfaceControlsWithPendingCallback.pop();
+ bool found = false;
+ for (auto stat : stats) {
+ if (!SurfaceControl::isSameSurface(pendingSC, stat.surfaceControl)) {
+ continue;
+ }
+
+ mTransformHint = stat.transformHint;
+ mBufferItemConsumer->setTransformHint(mTransformHint);
+ mBufferItemConsumer
+ ->updateFrameTimestamps(stat.frameEventStats.frameNumber,
+ stat.frameEventStats.refreshStartTime,
+ stat.frameEventStats.gpuCompositionDoneFence,
+ stat.presentFence, stat.previousReleaseFence,
+ stat.frameEventStats.compositorTiming,
+ stat.latchTime,
+ stat.frameEventStats.dequeueReadyTime);
+
+ currFrameNumber = stat.frameEventStats.frameNumber;
+
+ if (mTransactionCompleteCallback &&
+ currFrameNumber >= mTransactionCompleteFrameNumber) {
+ if (currFrameNumber > mTransactionCompleteFrameNumber) {
+ BQA_LOGE("transactionCallback received for a newer framenumber=%" PRIu64
+ " than expected=%" PRIu64,
+ currFrameNumber, mTransactionCompleteFrameNumber);
+ }
+ transactionCompleteCallback = std::move(mTransactionCompleteCallback);
+ mTransactionCompleteFrameNumber = 0;
}
- transactionCompleteCallback = std::move(mTransactionCompleteCallback);
- mTransactionCompleteFrameNumber = 0;
+
+ found = true;
+ break;
+ }
+
+ if (!found) {
+ BQA_LOGE("Failed to find matching SurfaceControl in transaction callback");
}
+ } else {
+ BQA_LOGE("No matching SurfaceControls found: mSurfaceControlsWithPendingCallback was "
+ "empty.");
}
decStrong((void*)transactionCallbackThunk);
@@ -374,8 +398,11 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) {
// Ensure BLASTBufferQueue stays alive until we receive the transaction complete callback.
incStrong((void*)transactionCallbackThunk);
- mLastBufferScalingMode = bufferItem.mScalingMode;
+ Rect crop = computeCrop(bufferItem);
mLastAcquiredFrameNumber = bufferItem.mFrameNumber;
+ mLastBufferInfo.update(true /* hasBuffer */, bufferItem.mGraphicBuffer->getWidth(),
+ bufferItem.mGraphicBuffer->getHeight(), bufferItem.mTransform,
+ bufferItem.mScalingMode, crop);
auto releaseBufferCallback =
std::bind(releaseBufferCallbackThunk, wp<BLASTBufferQueue>(this) /* callbackContext */,
@@ -387,10 +414,10 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) {
t->setAcquireFence(mSurfaceControl,
bufferItem.mFence ? new Fence(bufferItem.mFence->dup()) : Fence::NO_FENCE);
t->addTransactionCompletedCallback(transactionCallbackThunk, static_cast<void*>(this));
+ mSurfaceControlsWithPendingCallback.push(mSurfaceControl);
- t->setFrame(mSurfaceControl,
- {0, 0, static_cast<int32_t>(mSize.width), static_cast<int32_t>(mSize.height)});
- t->setCrop(mSurfaceControl, computeCrop(bufferItem));
+ setMatrix(t, mLastBufferInfo);
+ t->setCrop(mSurfaceControl, crop);
t->setTransform(mSurfaceControl, bufferItem.mTransform);
t->setTransformToDisplayInverse(mSurfaceControl, bufferItem.mTransformToDisplayInverse);
if (!bufferItem.mIsAutoTimestamp) {
@@ -494,6 +521,7 @@ void BLASTBufferQueue::setNextTransaction(SurfaceComposerClient::Transaction* t)
bool BLASTBufferQueue::rejectBuffer(const BufferItem& item) {
if (item.mScalingMode != NATIVE_WINDOW_SCALING_MODE_FREEZE) {
+ mSize = mRequestedSize;
// Only reject buffers if scaling mode is freeze.
return false;
}
@@ -515,6 +543,19 @@ bool BLASTBufferQueue::rejectBuffer(const BufferItem& item) {
return mSize != bufferSize;
}
+void BLASTBufferQueue::setMatrix(SurfaceComposerClient::Transaction* t,
+ const BufferInfo& bufferInfo) {
+ uint32_t bufWidth = bufferInfo.crop.getWidth();
+ uint32_t bufHeight = bufferInfo.crop.getHeight();
+
+ float sx = mSize.width / static_cast<float>(bufWidth);
+ float sy = mSize.height / static_cast<float>(bufHeight);
+
+ t->setMatrix(mSurfaceControl, sx, 0, 0, sy);
+ // Update position based on crop.
+ t->setPosition(mSurfaceControl, bufferInfo.crop.left * sx * -1, bufferInfo.crop.top * sy * -1);
+}
+
void BLASTBufferQueue::setTransactionCompleteCallback(
uint64_t frameNumber, std::function<void(int64_t)>&& transactionCompleteCallback) {
std::lock_guard _lock{mMutex};
diff --git a/libs/gui/DisplayEventDispatcher.cpp b/libs/gui/DisplayEventDispatcher.cpp
index 9cd3f631c8..e1b1efc0ed 100644
--- a/libs/gui/DisplayEventDispatcher.cpp
+++ b/libs/gui/DisplayEventDispatcher.cpp
@@ -152,6 +152,7 @@ bool DisplayEventDispatcher::processPendingEvents(nsecs_t* outTimestamp,
*outCount = ev.vsync.count;
outVsyncEventData->id = ev.vsync.vsyncId;
outVsyncEventData->deadlineTimestamp = ev.vsync.deadlineTimestamp;
+ outVsyncEventData->frameInterval = ev.vsync.frameInterval;
break;
case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG:
dispatchHotplug(ev.header.timestamp, ev.header.displayId, ev.hotplug.connected);
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 454aa9eb7b..53721cf6f7 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -99,7 +99,7 @@ public:
SAFE_PARCEL(data.writeVectorSize, listenerCallbacks);
for (const auto& [listener, callbackIds] : listenerCallbacks) {
SAFE_PARCEL(data.writeStrongBinder, listener);
- SAFE_PARCEL(data.writeInt64Vector, callbackIds);
+ SAFE_PARCEL(data.writeParcelableVector, callbackIds);
}
SAFE_PARCEL(data.writeUint64, transactionId);
@@ -497,6 +497,28 @@ public:
return result;
}
+ status_t onPullAtom(const int32_t atomId, std::string* pulledData, bool* success) {
+ Parcel data, reply;
+ SAFE_PARCEL(data.writeInterfaceToken, ISurfaceComposer::getInterfaceDescriptor());
+ SAFE_PARCEL(data.writeInt32, atomId);
+
+ status_t err = remote()->transact(BnSurfaceComposer::ON_PULL_ATOM, data, &reply);
+ if (err != NO_ERROR) {
+ ALOGE("onPullAtom failed to transact: %d", err);
+ return err;
+ }
+
+ int32_t size = 0;
+ SAFE_PARCEL(reply.readInt32, &size);
+ const void* dataPtr = reply.readInplace(size);
+ if (dataPtr == nullptr) {
+ return UNEXPECTED_NULL;
+ }
+ pulledData->assign((const char*)dataPtr, size);
+ SAFE_PARCEL(reply.readBool, success);
+ return NO_ERROR;
+ }
+
status_t enableVSyncInjections(bool enable) override {
Parcel data, reply;
status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
@@ -1246,7 +1268,7 @@ status_t BnSurfaceComposer::onTransact(
for (int32_t i = 0; i < listenersSize; i++) {
SAFE_PARCEL(data.readStrongBinder, &tmpBinder);
std::vector<CallbackId> callbackIds;
- SAFE_PARCEL(data.readInt64Vector, &callbackIds);
+ SAFE_PARCEL(data.readParcelableVector, &callbackIds);
listenerCallbacks.emplace_back(tmpBinder, callbackIds);
}
@@ -2021,6 +2043,19 @@ status_t BnSurfaceComposer::onTransact(
}
return overrideHdrTypes(display, hdrTypesVector);
}
+ case ON_PULL_ATOM: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ int32_t atomId = 0;
+ SAFE_PARCEL(data.readInt32, &atomId);
+
+ std::string pulledData;
+ bool success;
+ status_t err = onPullAtom(atomId, &pulledData, &success);
+ SAFE_PARCEL(reply->writeByteArray, pulledData.size(),
+ reinterpret_cast<const uint8_t*>(pulledData.data()));
+ SAFE_PARCEL(reply->writeBool, success);
+ return err;
+ }
default: {
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/libs/gui/ITransactionCompletedListener.cpp b/libs/gui/ITransactionCompletedListener.cpp
index b42793b8ac..f74f91e034 100644
--- a/libs/gui/ITransactionCompletedListener.cpp
+++ b/libs/gui/ITransactionCompletedListener.cpp
@@ -152,7 +152,7 @@ status_t SurfaceStats::readFromParcel(const Parcel* input) {
}
status_t TransactionStats::writeToParcel(Parcel* output) const {
- status_t err = output->writeInt64Vector(callbackIds);
+ status_t err = output->writeParcelableVector(callbackIds);
if (err != NO_ERROR) {
return err;
}
@@ -176,7 +176,7 @@ status_t TransactionStats::writeToParcel(Parcel* output) const {
}
status_t TransactionStats::readFromParcel(const Parcel* input) {
- status_t err = input->readInt64Vector(&callbackIds);
+ status_t err = input->readParcelableVector(&callbackIds);
if (err != NO_ERROR) {
return err;
}
@@ -227,8 +227,9 @@ status_t ListenerStats::readFromParcel(const Parcel* input) {
return NO_ERROR;
}
-ListenerStats ListenerStats::createEmpty(const sp<IBinder>& listener,
- const std::unordered_set<CallbackId>& callbackIds) {
+ListenerStats ListenerStats::createEmpty(
+ const sp<IBinder>& listener,
+ const std::unordered_set<CallbackId, CallbackIdHash>& callbackIds) {
ListenerStats listenerStats;
listenerStats.listener = listener;
listenerStats.transactionStats.emplace_back(callbackIds);
@@ -278,4 +279,28 @@ status_t BnTransactionCompletedListener::onTransact(uint32_t code, const Parcel&
}
}
+ListenerCallbacks ListenerCallbacks::filter(CallbackId::Type type) const {
+ std::vector<CallbackId> filteredCallbackIds;
+ for (const auto& callbackId : callbackIds) {
+ if (callbackId.type == type) {
+ filteredCallbackIds.push_back(callbackId);
+ }
+ }
+ return ListenerCallbacks(transactionCompletedListener, filteredCallbackIds);
+}
+
+status_t CallbackId::writeToParcel(Parcel* output) const {
+ SAFE_PARCEL(output->writeInt64, id);
+ SAFE_PARCEL(output->writeInt32, static_cast<int32_t>(type));
+ return NO_ERROR;
+}
+
+status_t CallbackId::readFromParcel(const Parcel* input) {
+ SAFE_PARCEL(input->readInt64, &id);
+ int32_t typeAsInt;
+ SAFE_PARCEL(input->readInt32, &typeAsInt);
+ type = static_cast<CallbackId::Type>(typeAsInt);
+ return NO_ERROR;
+}
+
}; // namespace android
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 5b213ad5c3..517b49e6b5 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -45,7 +45,6 @@ layer_state_t::layer_state_t()
reserved(0),
cornerRadius(0.0f),
backgroundBlurRadius(0),
- barrierFrameNumber(0),
transform(0),
transformToDisplayInverse(false),
crop(Rect::INVALID_RECT),
@@ -87,9 +86,7 @@ status_t layer_state_t::write(Parcel& output) const
SAFE_PARCEL(output.writeUint32, mask);
SAFE_PARCEL(matrix.write, output);
SAFE_PARCEL(output.write, crop);
- SAFE_PARCEL(SurfaceControl::writeNullableToParcel, output, barrierSurfaceControl_legacy);
SAFE_PARCEL(SurfaceControl::writeNullableToParcel, output, reparentSurfaceControl);
- SAFE_PARCEL(output.writeUint64, barrierFrameNumber);
SAFE_PARCEL(SurfaceControl::writeNullableToParcel, output, relativeLayerSurfaceControl);
SAFE_PARCEL(SurfaceControl::writeNullableToParcel, output, parentSurfaceControlForChild);
SAFE_PARCEL(output.writeFloat, color.r);
@@ -143,7 +140,7 @@ status_t layer_state_t::write(Parcel& output) const
for (auto listener : listeners) {
SAFE_PARCEL(output.writeStrongBinder, listener.transactionCompletedListener);
- SAFE_PARCEL(output.writeInt64Vector, listener.callbackIds);
+ SAFE_PARCEL(output.writeParcelableVector, listener.callbackIds);
}
SAFE_PARCEL(output.writeFloat, shadowRadius);
SAFE_PARCEL(output.writeInt32, frameRateSelectionPriority);
@@ -193,9 +190,7 @@ status_t layer_state_t::read(const Parcel& input)
SAFE_PARCEL(matrix.read, input);
SAFE_PARCEL(input.read, crop);
- SAFE_PARCEL(SurfaceControl::readNullableFromParcel, input, &barrierSurfaceControl_legacy);
SAFE_PARCEL(SurfaceControl::readNullableFromParcel, input, &reparentSurfaceControl);
- SAFE_PARCEL(input.readUint64, &barrierFrameNumber);
SAFE_PARCEL(SurfaceControl::readNullableFromParcel, input, &relativeLayerSurfaceControl);
SAFE_PARCEL(SurfaceControl::readNullableFromParcel, input, &parentSurfaceControlForChild);
@@ -263,7 +258,7 @@ status_t layer_state_t::read(const Parcel& input)
sp<IBinder> listener;
std::vector<CallbackId> callbackIds;
SAFE_PARCEL(input.readNullableStrongBinder, &listener);
- SAFE_PARCEL(input.readInt64Vector, &callbackIds);
+ SAFE_PARCEL(input.readParcelableVector, &callbackIds);
listeners.emplace_back(listener, callbackIds);
}
SAFE_PARCEL(input.readFloat, &shadowRadius);
@@ -425,11 +420,6 @@ void layer_state_t::merge(const layer_state_t& other) {
what |= eBlurRegionsChanged;
blurRegions = other.blurRegions;
}
- if (other.what & eDeferTransaction_legacy) {
- what |= eDeferTransaction_legacy;
- barrierSurfaceControl_legacy = other.barrierSurfaceControl_legacy;
- barrierFrameNumber = other.barrierFrameNumber;
- }
if (other.what & eRelativeLayerChanged) {
what |= eRelativeLayerChanged;
what &= ~eLayerChanged;
@@ -455,10 +445,6 @@ void layer_state_t::merge(const layer_state_t& other) {
what |= eCropChanged;
crop = other.crop;
}
- if (other.what & eFrameChanged) {
- what |= eFrameChanged;
- orientedDisplaySpaceRect = other.orientedDisplaySpaceRect;
- }
if (other.what & eBufferChanged) {
what |= eBufferChanged;
buffer = other.buffer;
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index e01a5aee32..5db0eae416 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -139,7 +139,7 @@ JankDataListener::~JankDataListener() {
// 0 is an invalid callback id
TransactionCompletedListener::TransactionCompletedListener() : mCallbackIdCounter(1) {}
-CallbackId TransactionCompletedListener::getNextIdLocked() {
+int64_t TransactionCompletedListener::getNextIdLocked() {
return mCallbackIdCounter++;
}
@@ -163,13 +163,13 @@ void TransactionCompletedListener::startListeningLocked() {
CallbackId TransactionCompletedListener::addCallbackFunction(
const TransactionCompletedCallback& callbackFunction,
const std::unordered_set<sp<SurfaceControl>, SurfaceComposerClient::SCHash>&
- surfaceControls) {
+ surfaceControls,
+ CallbackId::Type callbackType) {
std::lock_guard<std::mutex> lock(mMutex);
startListeningLocked();
- CallbackId callbackId = getNextIdLocked();
+ CallbackId callbackId(getNextIdLocked(), callbackType);
mCallbacks[callbackId].callbackFunction = callbackFunction;
-
auto& callbackSurfaceControls = mCallbacks[callbackId].surfaceControls;
for (const auto& surfaceControl : surfaceControls) {
@@ -228,7 +228,7 @@ void TransactionCompletedListener::removeSurfaceStatsListener(void* context, voi
void TransactionCompletedListener::addSurfaceControlToCallbacks(
const sp<SurfaceControl>& surfaceControl,
- const std::unordered_set<CallbackId>& callbackIds) {
+ const std::unordered_set<CallbackId, CallbackIdHash>& callbackIds) {
std::lock_guard<std::mutex> lock(mMutex);
for (auto callbackId : callbackIds) {
@@ -240,7 +240,7 @@ void TransactionCompletedListener::addSurfaceControlToCallbacks(
}
void TransactionCompletedListener::onTransactionCompleted(ListenerStats listenerStats) {
- std::unordered_map<CallbackId, CallbackTranslation> callbacksMap;
+ std::unordered_map<CallbackId, CallbackTranslation, CallbackIdHash> callbacksMap;
std::multimap<sp<IBinder>, sp<JankDataListener>> jankListenersMap;
std::multimap<sp<IBinder>, SurfaceStatsCallbackEntry> surfaceListeners;
{
@@ -267,7 +267,36 @@ void TransactionCompletedListener::onTransactionCompleted(ListenerStats listener
}
}
for (const auto& transactionStats : listenerStats.transactionStats) {
+ // handle on commit callbacks
+ for (auto callbackId : transactionStats.callbackIds) {
+ if (callbackId.type != CallbackId::Type::ON_COMMIT) {
+ continue;
+ }
+ auto& [callbackFunction, callbackSurfaceControls] = callbacksMap[callbackId];
+ if (!callbackFunction) {
+ ALOGE("cannot call null callback function, skipping");
+ continue;
+ }
+ std::vector<SurfaceControlStats> surfaceControlStats;
+ for (const auto& surfaceStats : transactionStats.surfaceStats) {
+ surfaceControlStats
+ .emplace_back(callbacksMap[callbackId]
+ .surfaceControls[surfaceStats.surfaceControl],
+ transactionStats.latchTime, surfaceStats.acquireTime,
+ transactionStats.presentFence,
+ surfaceStats.previousReleaseFence, surfaceStats.transformHint,
+ surfaceStats.eventStats);
+ }
+
+ callbackFunction(transactionStats.latchTime, transactionStats.presentFence,
+ surfaceControlStats);
+ }
+
+ // handle on complete callbacks
for (auto callbackId : transactionStats.callbackIds) {
+ if (callbackId.type != CallbackId::Type::ON_COMPLETE) {
+ continue;
+ }
auto& [callbackFunction, callbackSurfaceControls] = callbacksMap[callbackId];
if (!callbackFunction) {
ALOGE("cannot call null callback function, skipping");
@@ -542,7 +571,9 @@ status_t SurfaceComposerClient::Transaction::readFromParcel(const Parcel* parcel
return BAD_VALUE;
}
for (size_t j = 0; j < numCallbackIds; j++) {
- listenerCallbacks[listener].callbackIds.insert(parcel->readInt64());
+ CallbackId id;
+ parcel->readParcelable(&id);
+ listenerCallbacks[listener].callbackIds.insert(id);
}
size_t numSurfaces = parcel->readUint32();
if (numSurfaces > parcel->dataSize()) {
@@ -628,7 +659,7 @@ status_t SurfaceComposerClient::Transaction::writeToParcel(Parcel* parcel) const
parcel->writeStrongBinder(ITransactionCompletedListener::asBinder(listener));
parcel->writeUint32(static_cast<uint32_t>(callbackInfo.callbackIds.size()));
for (auto callbackId : callbackInfo.callbackIds) {
- parcel->writeInt64(callbackId);
+ parcel->writeParcelable(callbackId);
}
parcel->writeUint32(static_cast<uint32_t>(callbackInfo.surfaceControls.size()));
for (auto surfaceControl : callbackInfo.surfaceControls) {
@@ -896,7 +927,7 @@ void SurfaceComposerClient::Transaction::setEarlyWakeupEnd() {
}
layer_state_t* SurfaceComposerClient::Transaction::getLayerState(const sp<SurfaceControl>& sc) {
- auto handle = sc->getHandle();
+ auto handle = sc->getLayerStateHandle();
if (mComposerStates.count(handle) == 0) {
// we don't have it, add an initialized layer_state to our list
@@ -1140,23 +1171,6 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setBlurR
return *this;
}
-SurfaceComposerClient::Transaction&
-SurfaceComposerClient::Transaction::deferTransactionUntil_legacy(
- const sp<SurfaceControl>& sc, const sp<SurfaceControl>& barrierSurfaceControl,
- uint64_t frameNumber) {
- layer_state_t* s = getLayerState(sc);
- if (!s) {
- mStatus = BAD_INDEX;
- return *this;
- }
- s->what |= layer_state_t::eDeferTransaction_legacy;
- s->barrierSurfaceControl_legacy = barrierSurfaceControl;
- s->barrierFrameNumber = frameNumber;
-
- registerSurfaceControlForCallback(sc);
- return *this;
-}
-
SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::reparent(
const sp<SurfaceControl>& sc, const sp<SurfaceControl>& newParent) {
layer_state_t* s = getLayerState(sc);
@@ -1164,8 +1178,11 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::reparent
mStatus = BAD_INDEX;
return *this;
}
+ if (SurfaceControl::isSameSurface(sc, newParent)) {
+ return *this;
+ }
s->what |= layer_state_t::eReparent;
- s->parentSurfaceControlForChild = newParent;
+ s->parentSurfaceControlForChild = newParent ? newParent->getParentingLayer() : nullptr;
registerSurfaceControlForCallback(sc);
return *this;
@@ -1232,20 +1249,6 @@ SurfaceComposerClient::Transaction::setTransformToDisplayInverse(const sp<Surfac
return *this;
}
-SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrame(
- const sp<SurfaceControl>& sc, const Rect& frame) {
- layer_state_t* s = getLayerState(sc);
- if (!s) {
- mStatus = BAD_INDEX;
- return *this;
- }
- s->what |= layer_state_t::eFrameChanged;
- s->orientedDisplaySpaceRect = frame;
-
- registerSurfaceControlForCallback(sc);
- return *this;
-}
-
SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setBuffer(
const sp<SurfaceControl>& sc, const sp<GraphicBuffer>& buffer,
ReleaseBufferCallback callback) {
@@ -1417,9 +1420,9 @@ SurfaceComposerClient::Transaction::setFrameRateSelectionPriority(const sp<Surfa
return *this;
}
-SurfaceComposerClient::Transaction&
-SurfaceComposerClient::Transaction::addTransactionCompletedCallback(
- TransactionCompletedCallbackTakesContext callback, void* callbackContext) {
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::addTransactionCallback(
+ TransactionCompletedCallbackTakesContext callback, void* callbackContext,
+ CallbackId::Type callbackType) {
auto listener = TransactionCompletedListener::getInstance();
auto callbackWithContext = std::bind(callback, callbackContext, std::placeholders::_1,
@@ -1427,13 +1430,26 @@ SurfaceComposerClient::Transaction::addTransactionCompletedCallback(
const auto& surfaceControls =
mListenerCallbacks[TransactionCompletedListener::getIInstance()].surfaceControls;
- CallbackId callbackId = listener->addCallbackFunction(callbackWithContext, surfaceControls);
+ CallbackId callbackId =
+ listener->addCallbackFunction(callbackWithContext, surfaceControls, callbackType);
mListenerCallbacks[TransactionCompletedListener::getIInstance()].callbackIds.emplace(
callbackId);
return *this;
}
+SurfaceComposerClient::Transaction&
+SurfaceComposerClient::Transaction::addTransactionCompletedCallback(
+ TransactionCompletedCallbackTakesContext callback, void* callbackContext) {
+ return addTransactionCallback(callback, callbackContext, CallbackId::Type::ON_COMPLETE);
+}
+
+SurfaceComposerClient::Transaction&
+SurfaceComposerClient::Transaction::addTransactionCommittedCallback(
+ TransactionCompletedCallbackTakesContext callback, void* callbackContext) {
+ return addTransactionCallback(callback, callbackContext, CallbackId::Type::ON_COMMIT);
+}
+
SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::notifyProducerDisconnect(
const sp<SurfaceControl>& sc) {
layer_state_t* s = getLayerState(sc);
@@ -1824,7 +1840,8 @@ status_t SurfaceComposerClient::createSurfaceChecked(const String8& name, uint32
}
ALOGE_IF(err, "SurfaceComposerClient::createSurface error %s", strerror(-err));
if (err == NO_ERROR) {
- *outSurface = new SurfaceControl(this, handle, gbp, id, transformHint);
+ *outSurface =
+ new SurfaceControl(this, handle, gbp, id, w, h, format, transformHint, flags);
}
}
return err;
@@ -1977,6 +1994,11 @@ status_t SurfaceComposerClient::overrideHdrTypes(const sp<IBinder>& display,
return ComposerService::getComposerService()->overrideHdrTypes(display, hdrTypes);
}
+status_t SurfaceComposerClient::onPullAtom(const int32_t atomId, std::string* outData,
+ bool* success) {
+ return ComposerService::getComposerService()->onPullAtom(atomId, outData, success);
+}
+
status_t SurfaceComposerClient::getDisplayedContentSamplingAttributes(const sp<IBinder>& display,
ui::PixelFormat* outFormat,
ui::Dataspace* outDataspace,
diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp
index 4be6d2b539..9871447552 100644
--- a/libs/gui/SurfaceControl.cpp
+++ b/libs/gui/SurfaceControl.cpp
@@ -35,6 +35,7 @@
#include <ui/StaticDisplayInfo.h>
#include <gui/BufferQueueCore.h>
+#include <gui/BLASTBufferQueue.h>
#include <gui/ISurfaceComposer.h>
#include <gui/Surface.h>
#include <gui/SurfaceComposerClient.h>
@@ -51,12 +52,17 @@ namespace android {
SurfaceControl::SurfaceControl(const sp<SurfaceComposerClient>& client, const sp<IBinder>& handle,
const sp<IGraphicBufferProducer>& gbp, int32_t layerId,
- uint32_t transform)
+ uint32_t w, uint32_t h, PixelFormat format, uint32_t transform,
+ uint32_t flags)
: mClient(client),
mHandle(handle),
mGraphicBufferProducer(gbp),
mLayerId(layerId),
mTransformHint(transform),
+ mWidth(w),
+ mHeight(h),
+ mFormat(format),
+ mCreateFlags(flags),
mExtension(mHandle, &mGraphicBufferProducer) {}
SurfaceControl::SurfaceControl(const sp<SurfaceControl>& other) {
@@ -65,6 +71,9 @@ SurfaceControl::SurfaceControl(const sp<SurfaceControl>& other) {
mGraphicBufferProducer = other->mGraphicBufferProducer;
mTransformHint = other->mTransformHint;
mLayerId = other->mLayerId;
+ mWidth = other->mWidth;
+ mHeight = other->mHeight;
+ mCreateFlags = other->mCreateFlags;
}
SurfaceControl::~SurfaceControl()
@@ -73,13 +82,13 @@ SurfaceControl::~SurfaceControl()
// happen without delay, since these resources are quite heavy.
mClient.clear();
mHandle.clear();
- mGraphicBufferProducer.clear();
+ mBbq.clear();
IPCThreadState::self()->flushCommands();
}
void SurfaceControl::disconnect() {
- if (mGraphicBufferProducer != nullptr) {
- mGraphicBufferProducer->disconnect(
+ if (getIGraphicBufferProducer() != nullptr) {
+ getIGraphicBufferProducer()->disconnect(
BufferQueueCore::CURRENTLY_CONNECTED_API);
}
}
@@ -121,22 +130,29 @@ status_t SurfaceControl::writeSurfaceToParcel(
{
sp<IGraphicBufferProducer> bp;
if (control != nullptr) {
- bp = control->mGraphicBufferProducer;
+ bp = control->getIGraphicBufferProducer();
}
return parcel->writeStrongBinder(IInterface::asBinder(bp));
}
-sp<Surface> SurfaceControl::generateSurfaceLocked() const
+sp<Surface> SurfaceControl::generateSurfaceLocked()
{
+ uint32_t ignore;
+ auto flags = mCreateFlags & (ISurfaceComposerClient::eCursorWindow |
+ ISurfaceComposerClient::eOpaque);
+ mBbqChild = mClient->createSurface(String8("bbq-wrapper"), 0, 0, mFormat,
+ flags, mHandle, {}, &ignore);
+ mBbq = new BLASTBufferQueue("bbq-adapter", mBbqChild, mWidth, mHeight, mFormat);
+
// This surface is always consumed by SurfaceFlinger, so the
// producerControlledByApp value doesn't matter; using false.
mExtension.init();
- mSurfaceData = new Surface(mGraphicBufferProducer, false);
+ mSurfaceData = mBbq->getSurface(true);
return mSurfaceData;
}
-sp<Surface> SurfaceControl::getSurface() const
+sp<Surface> SurfaceControl::getSurface()
{
Mutex::Autolock _l(mLock);
if (mSurfaceData == nullptr) {
@@ -145,25 +161,42 @@ sp<Surface> SurfaceControl::getSurface() const
return mSurfaceData;
}
-sp<Surface> SurfaceControl::createSurface() const
+sp<Surface> SurfaceControl::createSurface()
{
+ return getSurface();
+}
+
+void SurfaceControl::updateDefaultBufferSize(uint32_t width, uint32_t height) {
Mutex::Autolock _l(mLock);
- return generateSurfaceLocked();
+ mWidth = width; mHeight = height;
+ if (mBbq) {
+ mBbq->update(this, width, height, mFormat);
+ }
+
}
-sp<IBinder> SurfaceControl::getHandle() const
+sp<IBinder> SurfaceControl::getLayerStateHandle() const
{
return mHandle;
}
+sp<IBinder> SurfaceControl::getHandle() const {
+ if (mBbqChild != nullptr) {
+ return mBbqChild->getHandle();
+ }
+ return getLayerStateHandle();
+}
+
int32_t SurfaceControl::getLayerId() const {
return mLayerId;
}
-sp<IGraphicBufferProducer> SurfaceControl::getIGraphicBufferProducer() const
+sp<IGraphicBufferProducer> SurfaceControl::getIGraphicBufferProducer()
{
+ getSurface();
Mutex::Autolock _l(mLock);
- return mGraphicBufferProducer;
+
+ return mBbq->getIGraphicBufferProducer();
}
sp<SurfaceComposerClient> SurfaceControl::getClient() const
@@ -184,9 +217,11 @@ void SurfaceControl::setTransformHint(uint32_t hint) {
status_t SurfaceControl::writeToParcel(Parcel& parcel) {
SAFE_PARCEL(parcel.writeStrongBinder, ISurfaceComposerClient::asBinder(mClient->getClient()));
SAFE_PARCEL(parcel.writeStrongBinder, mHandle);
- SAFE_PARCEL(parcel.writeStrongBinder, IGraphicBufferProducer::asBinder(mGraphicBufferProducer));
SAFE_PARCEL(parcel.writeInt32, mLayerId);
SAFE_PARCEL(parcel.writeUint32, mTransformHint);
+ SAFE_PARCEL(parcel.writeUint32, mWidth);
+ SAFE_PARCEL(parcel.writeUint32, mHeight);
+ SAFE_PARCEL(parcel.writeUint32, mFormat);
return NO_ERROR;
}
@@ -195,21 +230,26 @@ status_t SurfaceControl::readFromParcel(const Parcel& parcel,
sp<SurfaceControl>* outSurfaceControl) {
sp<IBinder> client;
sp<IBinder> handle;
- sp<IBinder> gbp;
int32_t layerId;
uint32_t transformHint;
+ uint32_t width;
+ uint32_t height;
+ uint32_t format;
SAFE_PARCEL(parcel.readStrongBinder, &client);
SAFE_PARCEL(parcel.readStrongBinder, &handle);
- SAFE_PARCEL(parcel.readNullableStrongBinder, &gbp);
SAFE_PARCEL(parcel.readInt32, &layerId);
SAFE_PARCEL(parcel.readUint32, &transformHint);
+ SAFE_PARCEL(parcel.readUint32, &width);
+ SAFE_PARCEL(parcel.readUint32, &height);
+ SAFE_PARCEL(parcel.readUint32, &format);
// We aren't the original owner of the surface.
*outSurfaceControl =
new SurfaceControl(new SurfaceComposerClient(
interface_cast<ISurfaceComposerClient>(client)),
- handle.get(), interface_cast<IGraphicBufferProducer>(gbp), layerId,
+ handle.get(), nullptr, layerId,
+ width, height, format,
transformHint);
return NO_ERROR;
@@ -237,6 +277,13 @@ status_t SurfaceControl::writeNullableToParcel(Parcel& parcel,
return NO_ERROR;
}
+sp<SurfaceControl> SurfaceControl::getParentingLayer() {
+ if (mBbqChild != nullptr) {
+ return mBbqChild;
+ }
+ return this;
+}
+
typedef bool (*InitFunc_t)(sp<IGraphicBufferProducer>*, const sp<IBinder>&);
typedef void (*DeinitFunc_t)(const sp<IBinder>&);
SurfaceControl::VpsExtension::VpsExtension()
diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h
index fbd16f4ea2..139dbb7f6b 100644
--- a/libs/gui/include/gui/BLASTBufferQueue.h
+++ b/libs/gui/include/gui/BLASTBufferQueue.h
@@ -142,6 +142,39 @@ private:
ui::Size mRequestedSize GUARDED_BY(mMutex);
int32_t mFormat GUARDED_BY(mMutex);
+ struct BufferInfo {
+ bool hasBuffer = false;
+ uint32_t width;
+ uint32_t height;
+ uint32_t transform;
+ // This is used to check if we should update the blast layer size immediately or wait until
+ // we get the next buffer. This will support scenarios where the layer can change sizes
+ // and the buffer will scale to fit the new size.
+ uint32_t scalingMode = NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW;
+ Rect crop;
+
+ void update(bool hasBuffer, uint32_t width, uint32_t height, uint32_t transform,
+ uint32_t scalingMode, const Rect& crop) {
+ this->hasBuffer = hasBuffer;
+ this->width = width;
+ this->height = height;
+ this->transform = transform;
+ this->scalingMode = scalingMode;
+ if (!crop.isEmpty()) {
+ this->crop = crop;
+ } else {
+ this->crop = Rect(width, height);
+ }
+ }
+ };
+
+ // Last acquired buffer's info. This is used to calculate the correct scale when size change is
+ // requested. We need to use the old buffer's info to determine what scale we need to apply to
+ // ensure the correct size.
+ BufferInfo mLastBufferInfo GUARDED_BY(mMutex);
+ void setMatrix(SurfaceComposerClient::Transaction* t, const BufferInfo& bufferInfo)
+ REQUIRES(mMutex);
+
uint32_t mTransformHint GUARDED_BY(mMutex);
sp<IGraphicBufferConsumer> mConsumer;
@@ -159,11 +192,6 @@ private:
std::queue<FrameTimelineInfo> mNextFrameTimelineInfoQueue GUARDED_BY(mMutex);
- // Last acquired buffer's scaling mode. This is used to check if we should update the blast
- // layer size immediately or wait until we get the next buffer. This will support scenarios
- // where the layer can change sizes and the buffer will scale to fit the new size.
- uint32_t mLastBufferScalingMode = NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW;
-
// Tracks the last acquired frame number
uint64_t mLastAcquiredFrameNumber GUARDED_BY(mMutex) = 0;
@@ -181,6 +209,10 @@ private:
// it for debugging purposes.
std::unordered_map<uint64_t /* bufferId */, nsecs_t> mDequeueTimestamps
GUARDED_BY(mTimestampMutex);
+
+ // Keep track of SurfaceControls that have submitted a transaction and BBQ is waiting on a
+ // callback for them.
+ std::queue<sp<SurfaceControl>> mSurfaceControlsWithPendingCallback GUARDED_BY(mMutex);
};
} // namespace android
diff --git a/libs/gui/include/gui/DisplayEventDispatcher.h b/libs/gui/include/gui/DisplayEventDispatcher.h
index d74c2ba72b..4ade240dcf 100644
--- a/libs/gui/include/gui/DisplayEventDispatcher.h
+++ b/libs/gui/include/gui/DisplayEventDispatcher.h
@@ -30,6 +30,9 @@ struct VsyncEventData {
// The deadline in CLOCK_MONOTONIC that the app needs to complete its
// frame by (both on the CPU and the GPU)
int64_t deadlineTimestamp = std::numeric_limits<int64_t>::max();
+
+ // The current frame interval in ns when this frame was scheduled.
+ int64_t frameInterval = 0;
};
class DisplayEventDispatcher : public LooperCallback {
diff --git a/libs/gui/include/gui/DisplayEventReceiver.h b/libs/gui/include/gui/DisplayEventReceiver.h
index 7179a20d22..0dffbde88a 100644
--- a/libs/gui/include/gui/DisplayEventReceiver.h
+++ b/libs/gui/include/gui/DisplayEventReceiver.h
@@ -75,6 +75,7 @@ public:
uint32_t count;
nsecs_t expectedVSyncTimestamp __attribute__((aligned(8)));
nsecs_t deadlineTimestamp __attribute__((aligned(8)));
+ nsecs_t frameInterval __attribute__((aligned(8)));
int64_t vsyncId;
};
diff --git a/libs/gui/include/gui/FrameTimelineInfo.h b/libs/gui/include/gui/FrameTimelineInfo.h
index 3b4c009609..a23c20248c 100644
--- a/libs/gui/include/gui/FrameTimelineInfo.h
+++ b/libs/gui/include/gui/FrameTimelineInfo.h
@@ -18,7 +18,6 @@
#include <stdint.h>
-#include <android/os/IInputConstants.h>
#include <binder/Parcel.h>
namespace android {
@@ -31,7 +30,11 @@ struct FrameTimelineInfo {
int64_t vsyncId = INVALID_VSYNC_ID;
// The id of the input event that caused this buffer
- int32_t inputEventId = android::os::IInputConstants::INVALID_INPUT_EVENT_ID;
+ // Default is android::os::IInputConstants::INVALID_INPUT_EVENT_ID = 0
+ // We copy the value of the input event ID instead of including the header, because libgui
+ // header libraries containing FrameTimelineInfo must be available to vendors, but libinput is
+ // not directly vendor available.
+ int32_t inputEventId = 0;
status_t write(Parcel& output) const;
status_t read(const Parcel& input);
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index ccd6d4e754..cb0468901a 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -275,6 +275,12 @@ public:
virtual status_t overrideHdrTypes(const sp<IBinder>& display,
const std::vector<ui::Hdr>& hdrTypes) = 0;
+ /* Pulls surfaceflinger atoms global stats and layer stats to pipe to statsd.
+ *
+ * Requires the calling uid be from system server.
+ */
+ virtual status_t onPullAtom(const int32_t atomId, std::string* outData, bool* success) = 0;
+
virtual status_t enableVSyncInjections(bool enable) = 0;
virtual status_t injectVSync(nsecs_t when) = 0;
@@ -600,6 +606,7 @@ public:
OVERRIDE_HDR_TYPES,
ADD_HDR_LAYER_INFO_LISTENER,
REMOVE_HDR_LAYER_INFO_LISTENER,
+ ON_PULL_ATOM,
// Always append new enum to the end.
};
diff --git a/libs/gui/include/gui/ITransactionCompletedListener.h b/libs/gui/include/gui/ITransactionCompletedListener.h
index 098760e89d..2d71194f70 100644
--- a/libs/gui/include/gui/ITransactionCompletedListener.h
+++ b/libs/gui/include/gui/ITransactionCompletedListener.h
@@ -36,7 +36,22 @@ namespace android {
class ITransactionCompletedListener;
class ListenerCallbacks;
-using CallbackId = int64_t;
+class CallbackId : public Parcelable {
+public:
+ int64_t id;
+ enum class Type : int32_t { ON_COMPLETE, ON_COMMIT } type;
+
+ CallbackId() {}
+ CallbackId(int64_t id, Type type) : id(id), type(type) {}
+ status_t writeToParcel(Parcel* output) const override;
+ status_t readFromParcel(const Parcel* input) override;
+
+ bool operator==(const CallbackId& rhs) const { return id == rhs.id && type == rhs.type; }
+};
+
+struct CallbackIdHash {
+ std::size_t operator()(const CallbackId& key) const { return std::hash<int64_t>()(key.id); }
+};
class FrameEventHistoryStats : public Parcelable {
public:
@@ -112,7 +127,7 @@ public:
TransactionStats() = default;
TransactionStats(const std::vector<CallbackId>& ids) : callbackIds(ids) {}
- TransactionStats(const std::unordered_set<CallbackId>& ids)
+ TransactionStats(const std::unordered_set<CallbackId, CallbackIdHash>& ids)
: callbackIds(ids.begin(), ids.end()) {}
TransactionStats(const std::vector<CallbackId>& ids, nsecs_t latch, const sp<Fence>& present,
const std::vector<SurfaceStats>& surfaces)
@@ -129,8 +144,9 @@ public:
status_t writeToParcel(Parcel* output) const override;
status_t readFromParcel(const Parcel* input) override;
- static ListenerStats createEmpty(const sp<IBinder>& listener,
- const std::unordered_set<CallbackId>& callbackIds);
+ static ListenerStats createEmpty(
+ const sp<IBinder>& listener,
+ const std::unordered_set<CallbackId, CallbackIdHash>& callbackIds);
sp<IBinder> listener;
std::vector<TransactionStats> transactionStats;
@@ -156,7 +172,8 @@ public:
class ListenerCallbacks {
public:
- ListenerCallbacks(const sp<IBinder>& listener, const std::unordered_set<CallbackId>& callbacks)
+ ListenerCallbacks(const sp<IBinder>& listener,
+ const std::unordered_set<CallbackId, CallbackIdHash>& callbacks)
: transactionCompletedListener(listener),
callbackIds(callbacks.begin(), callbacks.end()) {}
@@ -170,9 +187,12 @@ public:
if (callbackIds.empty()) {
return rhs.callbackIds.empty();
}
- return callbackIds.front() == rhs.callbackIds.front();
+ return callbackIds.front().id == rhs.callbackIds.front().id;
}
+ // Returns a new ListenerCallbacks filtered by type
+ ListenerCallbacks filter(CallbackId::Type type) const;
+
sp<IBinder> transactionCompletedListener;
std::vector<CallbackId> callbackIds;
};
@@ -191,7 +211,7 @@ struct CallbackIdsHash {
// same members. It is sufficient to just check the first CallbackId in the vectors. If
// they match, they are the same. If they do not match, they are not the same.
std::size_t operator()(const std::vector<CallbackId>& callbackIds) const {
- return std::hash<CallbackId>{}((callbackIds.empty()) ? 0 : callbackIds.front());
+ return std::hash<int64_t>{}((callbackIds.empty()) ? 0 : callbackIds.front().id);
}
};
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index 65d771053b..b4f62f2206 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -82,10 +82,9 @@ struct layer_state_t {
eTransparentRegionChanged = 0x00000020,
eFlagsChanged = 0x00000040,
eLayerStackChanged = 0x00000080,
- /* was eCropChanged_legacy, now available 0x00000100, */
- eDeferTransaction_legacy = 0x00000200,
eReleaseBufferListenerChanged = 0x00000400,
eShadowRadiusChanged = 0x00000800,
+ eLayerCreated = 0x00001000,
/* was eDetachChildren, now available 0x00002000, */
eRelativeLayerChanged = 0x00004000,
eReparent = 0x00008000,
@@ -105,7 +104,7 @@ struct layer_state_t {
eHasListenerCallbacksChanged = 0x20000000,
eInputInfoChanged = 0x40000000,
eCornerRadiusChanged = 0x80000000,
- eFrameChanged = 0x1'00000000,
+ /* was eFrameChanged, now available 0x1'00000000, */
eCachedBufferChanged = 0x2'00000000,
eBackgroundColorChanged = 0x4'00000000,
eMetadataChanged = 0x8'00000000,
@@ -152,9 +151,7 @@ struct layer_state_t {
matrix22_t matrix;
float cornerRadius;
uint32_t backgroundBlurRadius;
- sp<SurfaceControl> barrierSurfaceControl_legacy;
sp<SurfaceControl> reparentSurfaceControl;
- uint64_t barrierFrameNumber;
sp<SurfaceControl> relativeLayerSurfaceControl;
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 2487961426..5bbd8e3d85 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -336,7 +336,7 @@ public:
struct CallbackInfo {
// All the callbacks that have been requested for a TransactionCompletedListener in the
// Transaction
- std::unordered_set<CallbackId> callbackIds;
+ std::unordered_set<CallbackId, CallbackIdHash> callbackIds;
// All the SurfaceControls that have been modified in this TransactionCompletedListener's
// process that require a callback if there is one or more callbackIds set.
std::unordered_set<sp<SurfaceControl>, SCHash> surfaceControls;
@@ -454,13 +454,7 @@ public:
const std::vector<BlurRegion>& regions);
Transaction& setLayerStack(const sp<SurfaceControl>& sc, uint32_t layerStack);
Transaction& setMetadata(const sp<SurfaceControl>& sc, uint32_t key, const Parcel& p);
- // Defers applying any changes made in this transaction until the Layer
- // identified by handle reaches the given frameNumber. If the Layer identified
- // by handle is removed, then we will apply this transaction regardless of
- // what frame number has been reached.
- Transaction& deferTransactionUntil_legacy(const sp<SurfaceControl>& sc,
- const sp<SurfaceControl>& barrierSurfaceControl,
- uint64_t frameNumber);
+
/// Reparents the current layer to the new parent handle. The new parent must not be null.
Transaction& reparent(const sp<SurfaceControl>& sc, const sp<SurfaceControl>& newParent);
@@ -473,7 +467,6 @@ public:
Transaction& setTransform(const sp<SurfaceControl>& sc, uint32_t transform);
Transaction& setTransformToDisplayInverse(const sp<SurfaceControl>& sc,
bool transformToDisplayInverse);
- Transaction& setFrame(const sp<SurfaceControl>& sc, const Rect& frame);
Transaction& setBuffer(const sp<SurfaceControl>& sc, const sp<GraphicBuffer>& buffer,
ReleaseBufferCallback callback = nullptr);
Transaction& setCachedBuffer(const sp<SurfaceControl>& sc, int32_t bufferId);
@@ -491,9 +484,15 @@ public:
// Sets information about the priority of the frame.
Transaction& setFrameRateSelectionPriority(const sp<SurfaceControl>& sc, int32_t priority);
+ Transaction& addTransactionCallback(TransactionCompletedCallbackTakesContext callback,
+ void* callbackContext, CallbackId::Type callbackType);
+
Transaction& addTransactionCompletedCallback(
TransactionCompletedCallbackTakesContext callback, void* callbackContext);
+ Transaction& addTransactionCommittedCallback(
+ TransactionCompletedCallbackTakesContext callback, void* callbackContext);
+
// ONLY FOR BLAST ADAPTER
Transaction& notifyProducerDisconnect(const sp<SurfaceControl>& sc);
// Set the framenumber generated by the graphics producer to mimic BufferQueue behaviour.
@@ -574,6 +573,8 @@ public:
static status_t overrideHdrTypes(const sp<IBinder>& display,
const std::vector<ui::Hdr>& hdrTypes);
+ static status_t onPullAtom(const int32_t atomId, std::string* outData, bool* success);
+
static void setDisplayProjection(const sp<IBinder>& token, ui::Rotation orientation,
const Rect& layerStackRect, const Rect& displayRect);
@@ -626,14 +627,13 @@ public:
class TransactionCompletedListener : public BnTransactionCompletedListener {
TransactionCompletedListener();
- CallbackId getNextIdLocked() REQUIRES(mMutex);
+ int64_t getNextIdLocked() REQUIRES(mMutex);
std::mutex mMutex;
bool mListening GUARDED_BY(mMutex) = false;
- CallbackId mCallbackIdCounter GUARDED_BY(mMutex) = 1;
-
+ int64_t mCallbackIdCounter GUARDED_BY(mMutex) = 1;
struct CallbackTranslation {
TransactionCompletedCallback callbackFunction;
std::unordered_map<sp<IBinder>, sp<SurfaceControl>, SurfaceComposerClient::IBinderHash>
@@ -651,7 +651,8 @@ class TransactionCompletedListener : public BnTransactionCompletedListener {
SurfaceStatsCallback callback;
};
- std::unordered_map<CallbackId, CallbackTranslation> mCallbacks GUARDED_BY(mMutex);
+ std::unordered_map<CallbackId, CallbackTranslation, CallbackIdHash> mCallbacks
+ GUARDED_BY(mMutex);
std::multimap<sp<IBinder>, sp<JankDataListener>> mJankListeners GUARDED_BY(mMutex);
std::unordered_map<uint64_t /* graphicsBufferId */, ReleaseBufferCallback>
mReleaseBufferCallbacks GUARDED_BY(mMutex);
@@ -667,10 +668,12 @@ public:
CallbackId addCallbackFunction(
const TransactionCompletedCallback& callbackFunction,
const std::unordered_set<sp<SurfaceControl>, SurfaceComposerClient::SCHash>&
- surfaceControls);
+ surfaceControls,
+ CallbackId::Type callbackType);
- void addSurfaceControlToCallbacks(const sp<SurfaceControl>& surfaceControl,
- const std::unordered_set<CallbackId>& callbackIds);
+ void addSurfaceControlToCallbacks(
+ const sp<SurfaceControl>& surfaceControl,
+ const std::unordered_set<CallbackId, CallbackIdHash>& callbackIds);
/*
* Adds a jank listener to be informed about SurfaceFlinger's jank classification for a specific
diff --git a/libs/gui/include/gui/SurfaceControl.h b/libs/gui/include/gui/SurfaceControl.h
index 87dbbcc52f..12d1a344da 100644
--- a/libs/gui/include/gui/SurfaceControl.h
+++ b/libs/gui/include/gui/SurfaceControl.h
@@ -37,6 +37,7 @@ namespace android {
class IGraphicBufferProducer;
class Surface;
class SurfaceComposerClient;
+class BLASTBufferQueue;
// ---------------------------------------------------------------------------
@@ -70,12 +71,13 @@ public:
static status_t writeSurfaceToParcel(
const sp<SurfaceControl>& control, Parcel* parcel);
- sp<Surface> getSurface() const;
- sp<Surface> createSurface() const;
+ sp<Surface> getSurface();
+ sp<Surface> createSurface();
sp<IBinder> getHandle() const;
+ sp<IBinder> getLayerStateHandle() const;
int32_t getLayerId() const;
- sp<IGraphicBufferProducer> getIGraphicBufferProducer() const;
+ sp<IGraphicBufferProducer> getIGraphicBufferProducer();
status_t clearLayerFrameStats() const;
status_t getLayerFrameStats(FrameStats* outStats) const;
@@ -85,12 +87,16 @@ public:
uint32_t getTransformHint() const;
void setTransformHint(uint32_t hint);
+ void updateDefaultBufferSize(uint32_t width, uint32_t height);
explicit SurfaceControl(const sp<SurfaceControl>& other);
SurfaceControl(const sp<SurfaceComposerClient>& client, const sp<IBinder>& handle,
const sp<IGraphicBufferProducer>& gbp, int32_t layerId,
- uint32_t transformHint = 0);
+ uint32_t width = 0, uint32_t height = 0, PixelFormat format = 0,
+ uint32_t transformHint = 0, uint32_t flags = 0);
+
+ sp<SurfaceControl> getParentingLayer();
private:
// can't be copied
@@ -102,7 +108,7 @@ private:
~SurfaceControl();
- sp<Surface> generateSurfaceLocked() const;
+ sp<Surface> generateSurfaceLocked();
status_t validate() const;
sp<SurfaceComposerClient> mClient;
@@ -110,8 +116,14 @@ private:
sp<IGraphicBufferProducer> mGraphicBufferProducer;
mutable Mutex mLock;
mutable sp<Surface> mSurfaceData;
+ mutable sp<BLASTBufferQueue> mBbq;
+ mutable sp<SurfaceControl> mBbqChild;
int32_t mLayerId;
uint32_t mTransformHint;
+ uint32_t mWidth;
+ uint32_t mHeight;
+ PixelFormat mFormat;
+ uint32_t mCreateFlags;
// VpsExtension
class VpsExtension {
diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp
index fe48d88376..5a5da97599 100644
--- a/libs/gui/tests/BLASTBufferQueue_test.cpp
+++ b/libs/gui/tests/BLASTBufferQueue_test.cpp
@@ -140,7 +140,6 @@ protected:
/*parent*/ nullptr);
t.setLayerStack(mSurfaceControl, 0)
.setLayer(mSurfaceControl, std::numeric_limits<int32_t>::max())
- .setFrame(mSurfaceControl, Rect(resolution))
.show(mSurfaceControl)
.setDataspace(mSurfaceControl, ui::Dataspace::V0_SRGB)
.apply();
@@ -218,13 +217,13 @@ protected:
col >= region.left - border && col < region.right + border;
}
if (!outsideRegion && inRegion) {
- EXPECT_GE(epsilon, abs(r - *(pixel)));
- EXPECT_GE(epsilon, abs(g - *(pixel + 1)));
- EXPECT_GE(epsilon, abs(b - *(pixel + 2)));
+ ASSERT_GE(epsilon, abs(r - *(pixel)));
+ ASSERT_GE(epsilon, abs(g - *(pixel + 1)));
+ ASSERT_GE(epsilon, abs(b - *(pixel + 2)));
} else if (outsideRegion && !inRegion) {
- EXPECT_GE(epsilon, abs(r - *(pixel)));
- EXPECT_GE(epsilon, abs(g - *(pixel + 1)));
- EXPECT_GE(epsilon, abs(b - *(pixel + 2)));
+ ASSERT_GE(epsilon, abs(r - *(pixel)));
+ ASSERT_GE(epsilon, abs(g - *(pixel + 1)));
+ ASSERT_GE(epsilon, abs(b - *(pixel + 2)));
}
ASSERT_EQ(false, ::testing::Test::HasFailure());
}
@@ -466,7 +465,8 @@ TEST_F(BLASTBufferQueueTest, SetCrop_Item) {
ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults));
ASSERT_NO_FATAL_FAILURE(
- checkScreenCapture(r, g, b, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight}));
+ checkScreenCapture(r, g, b,
+ {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight / 2}));
}
TEST_F(BLASTBufferQueueTest, SetCrop_ScalingModeScaleCrop) {
@@ -522,16 +522,148 @@ TEST_F(BLASTBufferQueueTest, SetCrop_ScalingModeScaleCrop) {
adapter.waitForCallbacks();
// capture screen and verify that it is red
ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults));
-
- ASSERT_NO_FATAL_FAILURE(
- checkScreenCapture(r, g, b,
- {0, 0, (int32_t)bufferSideLength, (int32_t)bufferSideLength}));
+ ASSERT_NO_FATAL_FAILURE(checkScreenCapture(r, g, b,
+ {10, 10, (int32_t)bufferSideLength - 10,
+ (int32_t)bufferSideLength - 10}));
ASSERT_NO_FATAL_FAILURE(
checkScreenCapture(0, 0, 0,
{0, 0, (int32_t)bufferSideLength, (int32_t)bufferSideLength},
/*border*/ 0, /*outsideRegion*/ true));
}
+TEST_F(BLASTBufferQueueTest, ScaleCroppedBufferToBufferSize) {
+ // add black background
+ auto bg = mClient->createSurface(String8("BGTest"), 0, 0, PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eFXSurfaceEffect);
+ ASSERT_NE(nullptr, bg.get());
+ Transaction t;
+ t.setLayerStack(bg, 0)
+ .setCrop(bg, Rect(0, 0, mDisplayWidth, mDisplayHeight))
+ .setColor(bg, half3{0, 0, 0})
+ .setLayer(bg, 0)
+ .apply();
+
+ Rect windowSize(1000, 1000);
+ Rect bufferSize(windowSize);
+ Rect bufferCrop(200, 200, 700, 700);
+
+ BLASTBufferQueueHelper adapter(mSurfaceControl, windowSize.getWidth(), windowSize.getHeight());
+ sp<IGraphicBufferProducer> igbProducer;
+ setUpProducer(adapter, igbProducer);
+ int slot;
+ sp<Fence> fence;
+ sp<GraphicBuffer> buf;
+ auto ret = igbProducer->dequeueBuffer(&slot, &fence, bufferSize.getWidth(),
+ bufferSize.getHeight(), PIXEL_FORMAT_RGBA_8888,
+ GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr, nullptr);
+ ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, ret);
+ ASSERT_EQ(OK, igbProducer->requestBuffer(slot, &buf));
+
+ uint32_t* bufData;
+ buf->lock(static_cast<uint32_t>(GraphicBuffer::USAGE_SW_WRITE_OFTEN),
+ reinterpret_cast<void**>(&bufData));
+ // fill buffer with grey
+ fillBuffer(bufData, bufferSize, buf->getStride(), 127, 127, 127);
+
+ // fill crop area with different colors so we can verify the cropped region has been scaled
+ // correctly.
+ fillBuffer(bufData, Rect(200, 200, 450, 450), buf->getStride(), /* rgb */ 255, 0, 0);
+ fillBuffer(bufData, Rect(200, 451, 450, 700), buf->getStride(), /* rgb */ 0, 255, 0);
+ fillBuffer(bufData, Rect(451, 200, 700, 450), buf->getStride(), /* rgb */ 0, 0, 255);
+ fillBuffer(bufData, Rect(451, 451, 700, 700), buf->getStride(), /* rgb */ 255, 0, 0);
+ buf->unlock();
+
+ IGraphicBufferProducer::QueueBufferOutput qbOutput;
+ IGraphicBufferProducer::QueueBufferInput input(systemTime(), true /* autotimestamp */,
+ HAL_DATASPACE_UNKNOWN,
+ bufferCrop /* Rect::INVALID_RECT */,
+ NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW, 0,
+ Fence::NO_FENCE);
+ igbProducer->queueBuffer(slot, input, &qbOutput);
+ ASSERT_NE(ui::Transform::ROT_INVALID, qbOutput.transformHint);
+
+ adapter.waitForCallbacks();
+
+ ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults));
+
+ // Verify cropped region is scaled correctly.
+ ASSERT_NO_FATAL_FAILURE(checkScreenCapture(255, 0, 0, {10, 10, 490, 490}));
+ ASSERT_NO_FATAL_FAILURE(checkScreenCapture(0, 255, 0, {10, 510, 490, 990}));
+ ASSERT_NO_FATAL_FAILURE(checkScreenCapture(0, 0, 255, {510, 10, 990, 490}));
+ ASSERT_NO_FATAL_FAILURE(checkScreenCapture(255, 0, 0, {510, 510, 990, 990}));
+ // Verify outside region is black.
+ ASSERT_NO_FATAL_FAILURE(checkScreenCapture(0, 0, 0,
+ {0, 0, (int32_t)windowSize.getWidth(),
+ (int32_t)windowSize.getHeight()},
+ /*border*/ 0, /*outsideRegion*/ true));
+}
+
+TEST_F(BLASTBufferQueueTest, ScaleCroppedBufferToWindowSize) {
+ // add black background
+ auto bg = mClient->createSurface(String8("BGTest"), 0, 0, PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eFXSurfaceEffect);
+ ASSERT_NE(nullptr, bg.get());
+ Transaction t;
+ t.setLayerStack(bg, 0)
+ .setCrop(bg, Rect(0, 0, mDisplayWidth, mDisplayHeight))
+ .setColor(bg, half3{0, 0, 0})
+ .setLayer(bg, 0)
+ .apply();
+
+ Rect windowSize(1000, 1000);
+ Rect bufferSize(500, 500);
+ Rect bufferCrop(100, 100, 350, 350);
+
+ BLASTBufferQueueHelper adapter(mSurfaceControl, windowSize.getWidth(), windowSize.getHeight());
+ sp<IGraphicBufferProducer> igbProducer;
+ setUpProducer(adapter, igbProducer);
+ int slot;
+ sp<Fence> fence;
+ sp<GraphicBuffer> buf;
+ auto ret = igbProducer->dequeueBuffer(&slot, &fence, bufferSize.getWidth(),
+ bufferSize.getHeight(), PIXEL_FORMAT_RGBA_8888,
+ GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr, nullptr);
+ ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, ret);
+ ASSERT_EQ(OK, igbProducer->requestBuffer(slot, &buf));
+
+ uint32_t* bufData;
+ buf->lock(static_cast<uint32_t>(GraphicBuffer::USAGE_SW_WRITE_OFTEN),
+ reinterpret_cast<void**>(&bufData));
+ // fill buffer with grey
+ fillBuffer(bufData, bufferSize, buf->getStride(), 127, 127, 127);
+
+ // fill crop area with different colors so we can verify the cropped region has been scaled
+ // correctly.
+ fillBuffer(bufData, Rect(100, 100, 225, 225), buf->getStride(), /* rgb */ 255, 0, 0);
+ fillBuffer(bufData, Rect(100, 226, 225, 350), buf->getStride(), /* rgb */ 0, 255, 0);
+ fillBuffer(bufData, Rect(226, 100, 350, 225), buf->getStride(), /* rgb */ 0, 0, 255);
+ fillBuffer(bufData, Rect(226, 226, 350, 350), buf->getStride(), /* rgb */ 255, 0, 0);
+ buf->unlock();
+
+ IGraphicBufferProducer::QueueBufferOutput qbOutput;
+ IGraphicBufferProducer::QueueBufferInput input(systemTime(), true /* autotimestamp */,
+ HAL_DATASPACE_UNKNOWN,
+ bufferCrop /* Rect::INVALID_RECT */,
+ NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW, 0,
+ Fence::NO_FENCE);
+ igbProducer->queueBuffer(slot, input, &qbOutput);
+ ASSERT_NE(ui::Transform::ROT_INVALID, qbOutput.transformHint);
+
+ adapter.waitForCallbacks();
+
+ ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults));
+ // Verify cropped region is scaled correctly.
+ ASSERT_NO_FATAL_FAILURE(checkScreenCapture(255, 0, 0, {10, 10, 490, 490}));
+ ASSERT_NO_FATAL_FAILURE(checkScreenCapture(0, 255, 0, {10, 510, 490, 990}));
+ ASSERT_NO_FATAL_FAILURE(checkScreenCapture(0, 0, 255, {510, 10, 990, 490}));
+ ASSERT_NO_FATAL_FAILURE(checkScreenCapture(255, 0, 0, {510, 510, 990, 990}));
+ // Verify outside region is black.
+ ASSERT_NO_FATAL_FAILURE(checkScreenCapture(0, 0, 0,
+ {0, 0, (int32_t)windowSize.getWidth(),
+ (int32_t)windowSize.getHeight()},
+ /*border*/ 0, /*outsideRegion*/ true));
+}
+
class TestProducerListener : public BnProducerListener {
public:
sp<IGraphicBufferProducer> mIgbp;
@@ -596,7 +728,6 @@ TEST_F(BLASTBufferQueueTest, OutOfOrderTransactionTest) {
t.setLayerStack(bgSurface, 0)
.show(bgSurface)
.setDataspace(bgSurface, ui::Dataspace::V0_SRGB)
- .setFrame(bgSurface, Rect(0, 0, mDisplayWidth, mDisplayHeight))
.setLayer(bgSurface, std::numeric_limits<int32_t>::max() - 1)
.apply();
@@ -619,7 +750,8 @@ TEST_F(BLASTBufferQueueTest, OutOfOrderTransactionTest) {
ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults));
ASSERT_NO_FATAL_FAILURE(
- checkScreenCapture(r, g, b, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight}));
+ checkScreenCapture(r, g, b,
+ {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight / 2}));
}
class BLASTBufferQueueTransformTest : public BLASTBufferQueueTest {
@@ -834,26 +966,6 @@ public:
if (postedTime) *postedTime = systemTime();
igbProducer->queueBuffer(slot, input, qbOutput);
}
-
- void createBufferQueueProducer(sp<IGraphicBufferProducer>* bqIgbp) {
- mBufferQueueSurfaceControl =
- mClient->createSurface(String8("BqSurface"), 0, 0, PIXEL_FORMAT_RGBA_8888,
- ISurfaceComposerClient::eFXSurfaceBufferQueue);
- ASSERT_NE(nullptr, mBufferQueueSurfaceControl.get());
- Transaction()
- .setLayerStack(mBufferQueueSurfaceControl, 0)
- .show(mBufferQueueSurfaceControl)
- .setDataspace(mBufferQueueSurfaceControl, ui::Dataspace::V0_SRGB)
- .setSize(mBufferQueueSurfaceControl, mDisplayWidth, mDisplayHeight)
- .setLayer(mBufferQueueSurfaceControl, std::numeric_limits<int32_t>::max())
- .apply();
-
- sp<Surface> bqSurface = mBufferQueueSurfaceControl->getSurface();
- ASSERT_NE(nullptr, bqSurface.get());
-
- *bqIgbp = bqSurface->getIGraphicBufferProducer();
- setUpProducer(*bqIgbp);
- }
sp<SurfaceControl> mBufferQueueSurfaceControl;
};
@@ -909,55 +1021,6 @@ TEST_F(BLASTFrameEventHistoryTest, FrameEventHistory_Basic) {
adapter.waitForCallbacks();
}
-// Runs the same Frame Event History test
-TEST_F(BLASTFrameEventHistoryTest, FrameEventHistory_Basic_BufferQueue) {
- sp<IGraphicBufferProducer> bqIgbp;
- createBufferQueueProducer(&bqIgbp);
-
- ProducerFrameEventHistory history;
- IGraphicBufferProducer::QueueBufferOutput qbOutput;
- nsecs_t requestedPresentTimeA = 0;
- nsecs_t postedTimeA = 0;
- setUpAndQueueBuffer(bqIgbp, &requestedPresentTimeA, &postedTimeA, &qbOutput, true);
- history.applyDelta(qbOutput.frameTimestamps);
-
- FrameEvents* events = nullptr;
- events = history.getFrame(1);
- ASSERT_NE(nullptr, events);
- ASSERT_EQ(1, events->frameNumber);
- ASSERT_EQ(requestedPresentTimeA, events->requestedPresentTime);
- ASSERT_GE(events->postedTime, postedTimeA);
-
- // wait for buffer to be presented
- std::this_thread::sleep_for(200ms);
-
- nsecs_t requestedPresentTimeB = 0;
- nsecs_t postedTimeB = 0;
- setUpAndQueueBuffer(bqIgbp, &requestedPresentTimeB, &postedTimeB, &qbOutput, true);
- history.applyDelta(qbOutput.frameTimestamps);
- events = history.getFrame(1);
- ASSERT_NE(nullptr, events);
-
- // frame number, requestedPresentTime, and postTime should not have changed
- ASSERT_EQ(1, events->frameNumber);
- ASSERT_EQ(requestedPresentTimeA, events->requestedPresentTime);
- ASSERT_GE(events->postedTime, postedTimeA);
-
- ASSERT_GE(events->latchTime, postedTimeA);
- ASSERT_FALSE(events->hasDequeueReadyInfo());
-
- ASSERT_NE(nullptr, events->gpuCompositionDoneFence);
- ASSERT_NE(nullptr, events->displayPresentFence);
- ASSERT_NE(nullptr, events->releaseFence);
-
- // we should also have gotten the initial values for the next frame
- events = history.getFrame(2);
- ASSERT_NE(nullptr, events);
- ASSERT_EQ(2, events->frameNumber);
- ASSERT_EQ(requestedPresentTimeB, events->requestedPresentTime);
- ASSERT_GE(events->postedTime, postedTimeB);
-}
-
TEST_F(BLASTFrameEventHistoryTest, FrameEventHistory_DroppedFrame) {
BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight);
sp<IGraphicBufferProducer> igbProducer;
@@ -1008,53 +1071,4 @@ TEST_F(BLASTFrameEventHistoryTest, FrameEventHistory_DroppedFrame) {
ASSERT_GE(events->postedTime, postedTimeB);
}
-TEST_F(BLASTFrameEventHistoryTest, FrameEventHistory_DroppedFrame_BufferQueue) {
- sp<IGraphicBufferProducer> bqIgbp;
- createBufferQueueProducer(&bqIgbp);
-
- ProducerFrameEventHistory history;
- IGraphicBufferProducer::QueueBufferOutput qbOutput;
- nsecs_t requestedPresentTimeA = 0;
- nsecs_t postedTimeA = 0;
- nsecs_t presentTimeDelay = std::chrono::nanoseconds(500ms).count();
- setUpAndQueueBuffer(bqIgbp, &requestedPresentTimeA, &postedTimeA, &qbOutput, true,
- presentTimeDelay);
- history.applyDelta(qbOutput.frameTimestamps);
-
- FrameEvents* events = nullptr;
- events = history.getFrame(1);
- ASSERT_NE(nullptr, events);
- ASSERT_EQ(1, events->frameNumber);
- ASSERT_EQ(requestedPresentTimeA, events->requestedPresentTime);
- ASSERT_GE(events->postedTime, postedTimeA);
-
- // queue another buffer so the first can be dropped
- nsecs_t requestedPresentTimeB = 0;
- nsecs_t postedTimeB = 0;
- setUpAndQueueBuffer(bqIgbp, &requestedPresentTimeB, &postedTimeB, &qbOutput, true);
- history.applyDelta(qbOutput.frameTimestamps);
- events = history.getFrame(1);
- ASSERT_NE(nullptr, events);
-
- // frame number, requestedPresentTime, and postTime should not have changed
- ASSERT_EQ(1, events->frameNumber);
- ASSERT_EQ(requestedPresentTimeA, events->requestedPresentTime);
- ASSERT_GE(events->postedTime, postedTimeA);
-
- // a valid latchtime should not be set
- ASSERT_FALSE(events->hasLatchInfo());
- ASSERT_FALSE(events->hasDequeueReadyInfo());
-
- ASSERT_NE(nullptr, events->gpuCompositionDoneFence);
- ASSERT_NE(nullptr, events->displayPresentFence);
- ASSERT_NE(nullptr, events->releaseFence);
-
- // we should also have gotten the initial values for the next frame
- events = history.getFrame(2);
- ASSERT_NE(nullptr, events);
- ASSERT_EQ(2, events->frameNumber);
- ASSERT_EQ(requestedPresentTimeB, events->requestedPresentTime);
- ASSERT_GE(events->postedTime, postedTimeB);
-}
-
} // namespace android
diff --git a/libs/gui/tests/DisplayEventStructLayout_test.cpp b/libs/gui/tests/DisplayEventStructLayout_test.cpp
index 7dbba31ba8..bcd39dbbf4 100644
--- a/libs/gui/tests/DisplayEventStructLayout_test.cpp
+++ b/libs/gui/tests/DisplayEventStructLayout_test.cpp
@@ -34,7 +34,8 @@ TEST(DisplayEventStructLayoutTest, TestEventAlignment) {
CHECK_OFFSET(DisplayEventReceiver::Event::VSync, count, 0);
CHECK_OFFSET(DisplayEventReceiver::Event::VSync, expectedVSyncTimestamp, 8);
CHECK_OFFSET(DisplayEventReceiver::Event::VSync, deadlineTimestamp, 16);
- CHECK_OFFSET(DisplayEventReceiver::Event::VSync, vsyncId, 24);
+ CHECK_OFFSET(DisplayEventReceiver::Event::VSync, frameInterval, 24);
+ CHECK_OFFSET(DisplayEventReceiver::Event::VSync, vsyncId, 32);
CHECK_OFFSET(DisplayEventReceiver::Event::Hotplug, connected, 0);
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 751b95af66..ea8c2957a1 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -102,14 +102,13 @@ protected:
// test flakiness.
mSurfaceControl = mComposerClient->createSurface(
String8("Test Surface"), 32, 32, PIXEL_FORMAT_RGBA_8888, 0);
+ SurfaceComposerClient::Transaction().apply(true);
ASSERT_TRUE(mSurfaceControl != nullptr);
ASSERT_TRUE(mSurfaceControl->isValid());
Transaction t;
- ASSERT_EQ(NO_ERROR, t.setLayer(mSurfaceControl, 0x7fffffff)
- .show(mSurfaceControl)
- .apply());
+ ASSERT_EQ(NO_ERROR, t.setLayer(mSurfaceControl, 0x7fffffff).show(mSurfaceControl).apply());
mSurface = mSurfaceControl->getSurface();
ASSERT_TRUE(mSurface != nullptr);
@@ -776,6 +775,10 @@ public:
const std::vector<ui::Hdr>& /*hdrTypes*/) override {
return NO_ERROR;
}
+ status_t onPullAtom(const int32_t /*atomId*/, std::string* /*outData*/,
+ bool* /*success*/) override {
+ return NO_ERROR;
+ }
status_t enableVSyncInjections(bool /*enable*/) override {
return NO_ERROR;
}
diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp
index bf8ec34627..3657fcfdfe 100644
--- a/libs/input/InputTransport.cpp
+++ b/libs/input/InputTransport.cpp
@@ -309,7 +309,8 @@ status_t InputChannel::openInputChannelPair(const std::string& name,
int sockets[2];
if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets)) {
status_t result = -errno;
- ALOGE("channel '%s' ~ Could not create socket pair. errno=%d", name.c_str(), errno);
+ ALOGE("channel '%s' ~ Could not create socket pair. errno=%s(%d)", name.c_str(),
+ strerror(errno), errno);
outServerChannel.reset();
outClientChannel.reset();
return result;
diff --git a/libs/nativedisplay/AChoreographer.cpp b/libs/nativedisplay/AChoreographer.cpp
index dc2dd297c5..0edb213089 100644
--- a/libs/nativedisplay/AChoreographer.cpp
+++ b/libs/nativedisplay/AChoreographer.cpp
@@ -130,7 +130,7 @@ public:
virtual ~Choreographer() override EXCLUDES(gChoreographers.lock);
int64_t getVsyncId() const;
int64_t getFrameDeadline() const;
-
+ int64_t getFrameInterval() const;
private:
Choreographer(const Choreographer&) = delete;
@@ -418,6 +418,10 @@ int64_t Choreographer::getFrameDeadline() const {
return mLastVsyncEventData.deadlineTimestamp;
}
+int64_t Choreographer::getFrameInterval() const {
+ return mLastVsyncEventData.frameInterval;
+}
+
} // namespace android
using namespace android;
@@ -501,6 +505,10 @@ int64_t AChoreographer_getFrameDeadline(const AChoreographer* choreographer) {
return AChoreographer_to_Choreographer(choreographer)->getFrameDeadline();
}
+int64_t AChoreographer_getFrameInterval(const AChoreographer* choreographer) {
+ return AChoreographer_to_Choreographer(choreographer)->getFrameInterval();
+}
+
} // namespace android
/* Glue for the NDK interface */
diff --git a/libs/nativedisplay/include-private/private/android/choreographer.h b/libs/nativedisplay/include-private/private/android/choreographer.h
index 0f4fd4521f..7d25ce8253 100644
--- a/libs/nativedisplay/include-private/private/android/choreographer.h
+++ b/libs/nativedisplay/include-private/private/android/choreographer.h
@@ -42,6 +42,11 @@ int64_t AChoreographer_getVsyncId(const AChoreographer* choreographer);
// value.
int64_t AChoreographer_getFrameDeadline(const AChoreographer* choreographer);
+// Returns the current interval in ns between frames.
+// Client are expected to call this function from their frame callback function.
+// Calling this function from anywhere else will return an undefined value.
+int64_t AChoreographer_getFrameInterval(const AChoreographer* choreographer);
+
// Trampoline functions allowing libandroid.so to define the NDK symbols without including
// the entirety of libnativedisplay as a whole static lib. As libnativedisplay
// maintains global state, libnativedisplay can never be directly statically
diff --git a/libs/nativedisplay/libnativedisplay.map.txt b/libs/nativedisplay/libnativedisplay.map.txt
index fda6a20a0b..9ed4915481 100644
--- a/libs/nativedisplay/libnativedisplay.map.txt
+++ b/libs/nativedisplay/libnativedisplay.map.txt
@@ -31,6 +31,7 @@ LIBNATIVEDISPLAY_PLATFORM {
android::AChoreographer_signalRefreshRateCallbacks*;
android::AChoreographer_getVsyncId*;
android::AChoreographer_getFrameDeadline*;
+ android::AChoreographer_getFrameInterval*;
android::ADisplay_acquirePhysicalDisplays*;
android::ADisplay_release*;
android::ADisplay_getMaxSupportedFps*;
diff --git a/libs/nativewindow/include/android/hardware_buffer.h b/libs/nativewindow/include/android/hardware_buffer.h
index 20a1f74792..d93a84cd25 100644
--- a/libs/nativewindow/include/android/hardware_buffer.h
+++ b/libs/nativewindow/include/android/hardware_buffer.h
@@ -164,45 +164,56 @@ enum AHardwareBuffer_Format {
* Buffer usage flags, specifying how the buffer will be accessed.
*/
enum AHardwareBuffer_UsageFlags {
- /// The buffer will never be locked for direct CPU reads using the
- /// AHardwareBuffer_lock() function. Note that reading the buffer
- /// using OpenGL or Vulkan functions or memory mappings is still
- /// allowed.
+ /**
+ * The buffer will never be locked for direct CPU reads using the
+ * AHardwareBuffer_lock() function. Note that reading the buffer
+ * using OpenGL or Vulkan functions or memory mappings is still
+ * allowed.
+ */
AHARDWAREBUFFER_USAGE_CPU_READ_NEVER = 0UL,
- /// The buffer will sometimes be locked for direct CPU reads using
- /// the AHardwareBuffer_lock() function. Note that reading the
- /// buffer using OpenGL or Vulkan functions or memory mappings
- /// does not require the presence of this flag.
+ /**
+ * The buffer will sometimes be locked for direct CPU reads using
+ * the AHardwareBuffer_lock() function. Note that reading the
+ * buffer using OpenGL or Vulkan functions or memory mappings
+ * does not require the presence of this flag.
+ */
AHARDWAREBUFFER_USAGE_CPU_READ_RARELY = 2UL,
- /// The buffer will often be locked for direct CPU reads using
- /// the AHardwareBuffer_lock() function. Note that reading the
- /// buffer using OpenGL or Vulkan functions or memory mappings
- /// does not require the presence of this flag.
+ /**
+ * The buffer will often be locked for direct CPU reads using
+ * the AHardwareBuffer_lock() function. Note that reading the
+ * buffer using OpenGL or Vulkan functions or memory mappings
+ * does not require the presence of this flag.
+ */
AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN = 3UL,
- /// CPU read value mask.
- AHARDWAREBUFFER_USAGE_CPU_READ_MASK = 0xFUL,
- /// The buffer will never be locked for direct CPU writes using the
- /// AHardwareBuffer_lock() function. Note that writing the buffer
- /// using OpenGL or Vulkan functions or memory mappings is still
- /// allowed.
+ /** CPU read value mask. */
+ AHARDWAREBUFFER_USAGE_CPU_READ_MASK = 0xFUL,
+ /**
+ * The buffer will never be locked for direct CPU writes using the
+ * AHardwareBuffer_lock() function. Note that writing the buffer
+ * using OpenGL or Vulkan functions or memory mappings is still
+ * allowed.
+ */
AHARDWAREBUFFER_USAGE_CPU_WRITE_NEVER = 0UL << 4,
- /// The buffer will sometimes be locked for direct CPU writes using
- /// the AHardwareBuffer_lock() function. Note that writing the
- /// buffer using OpenGL or Vulkan functions or memory mappings
- /// does not require the presence of this flag.
+ /**
+ * The buffer will sometimes be locked for direct CPU writes using
+ * the AHardwareBuffer_lock() function. Note that writing the
+ * buffer using OpenGL or Vulkan functions or memory mappings
+ * does not require the presence of this flag.
+ */
AHARDWAREBUFFER_USAGE_CPU_WRITE_RARELY = 2UL << 4,
- /// The buffer will often be locked for direct CPU writes using
- /// the AHardwareBuffer_lock() function. Note that writing the
- /// buffer using OpenGL or Vulkan functions or memory mappings
- /// does not require the presence of this flag.
+ /**
+ * The buffer will often be locked for direct CPU writes using
+ * the AHardwareBuffer_lock() function. Note that writing the
+ * buffer using OpenGL or Vulkan functions or memory mappings
+ * does not require the presence of this flag.
+ */
AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN = 3UL << 4,
- /// CPU write value mask.
+ /** CPU write value mask. */
AHARDWAREBUFFER_USAGE_CPU_WRITE_MASK = 0xFUL << 4,
-
- /// The buffer will be read from by the GPU as a texture.
+ /** The buffer will be read from by the GPU as a texture. */
AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE = 1UL << 8,
- /// The buffer will be written to by the GPU as a framebuffer attachment.
+ /** The buffer will be written to by the GPU as a framebuffer attachment.*/
AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER = 1UL << 9,
/**
* The buffer will be written to by the GPU as a framebuffer
@@ -237,7 +248,7 @@ enum AHardwareBuffer_UsageFlags {
* buffers are expected to behave.
*/
AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT = 1UL << 14,
- /// The buffer will be read by a hardware video encoder.
+ /** The buffer will be read by a hardware video encoder. */
AHARDWAREBUFFER_USAGE_VIDEO_ENCODE = 1UL << 16,
/**
* The buffer will be used for direct writes from sensors.
diff --git a/libs/nativewindow/include/android/native_window.h b/libs/nativewindow/include/android/native_window.h
index 50e9d53604..61b3f94aab 100644
--- a/libs/nativewindow/include/android/native_window.h
+++ b/libs/nativewindow/include/android/native_window.h
@@ -157,6 +157,7 @@ int32_t ANativeWindow_getFormat(ANativeWindow* window);
* For all of these parameters, if 0 is supplied then the window's base
* value will come back in force.
*
+ * \param window pointer to an ANativeWindow object.
* \param width width of the buffers in pixels.
* \param height height of the buffers in pixels.
* \param format one of the AHardwareBuffer_Format constants.
@@ -191,6 +192,7 @@ int32_t ANativeWindow_unlockAndPost(ANativeWindow* window);
*
* Available since API level 26.
*
+ * \param window pointer to an ANativeWindow object.
* \param transform combination of {@link ANativeWindowTransform} flags
* \return 0 for success, or -EINVAL if \p transform is invalid
*/
@@ -208,6 +210,7 @@ int32_t ANativeWindow_setBuffersTransform(ANativeWindow* window, int32_t transfo
*
* Available since API level 28.
*
+ * \param window pointer to an ANativeWindow object.
* \param dataSpace data space of all buffers queued after this call.
* \return 0 for success, -EINVAL if window is invalid or the dataspace is not
* supported.
@@ -306,6 +309,8 @@ enum ANativeWindow_ChangeFrameRateStrategy {
* valid refresh rate for this device's display - e.g., it's fine to pass 30fps
* to a device that can only run the display at 60fps.
*
+ * \param window pointer to an ANativeWindow object.
+ *
* \param compatibility The frame rate compatibility of this window. The
* compatibility value may influence the system's choice of display refresh
* rate. See the ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_* values for more info.
diff --git a/libs/permission/Android.bp b/libs/permission/Android.bp
new file mode 100644
index 0000000000..a5712b319f
--- /dev/null
+++ b/libs/permission/Android.bp
@@ -0,0 +1,23 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
+cc_library_shared {
+ name: "libpermission",
+ srcs: [
+ "AppOpsManager.cpp",
+ "IAppOpsCallback.cpp",
+ "IAppOpsService.cpp",
+ ],
+ export_include_dirs: ["include"],
+ shared_libs: [
+ "libbinder",
+ "liblog",
+ "libutils",
+ ],
+}
diff --git a/libs/binder/AppOpsManager.cpp b/libs/permission/AppOpsManager.cpp
index de42f36d74..baa9d75116 100644
--- a/libs/binder/AppOpsManager.cpp
+++ b/libs/permission/AppOpsManager.cpp
@@ -37,7 +37,7 @@ static const sp<IBinder>& getClientId() {
pthread_mutex_lock(&gClientIdMutex);
if (gClientId == nullptr) {
- gClientId = new BBinder();
+ gClientId = sp<BBinder>::make();
}
pthread_mutex_unlock(&gClientIdMutex);
return gClientId;
diff --git a/libs/binder/IAppOpsCallback.cpp b/libs/permission/IAppOpsCallback.cpp
index 2b3f462ab8..2b3f462ab8 100644
--- a/libs/binder/IAppOpsCallback.cpp
+++ b/libs/permission/IAppOpsCallback.cpp
diff --git a/libs/binder/IAppOpsService.cpp b/libs/permission/IAppOpsService.cpp
index d59f44562e..d59f44562e 100644
--- a/libs/binder/IAppOpsService.cpp
+++ b/libs/permission/IAppOpsService.cpp
diff --git a/libs/binder/include/binder/AppOpsManager.h b/libs/permission/include/binder/AppOpsManager.h
index c048cbed37..c048cbed37 100644
--- a/libs/binder/include/binder/AppOpsManager.h
+++ b/libs/permission/include/binder/AppOpsManager.h
diff --git a/libs/binder/include/binder/IAppOpsCallback.h b/libs/permission/include/binder/IAppOpsCallback.h
index eb76f57bf8..eb76f57bf8 100644
--- a/libs/binder/include/binder/IAppOpsCallback.h
+++ b/libs/permission/include/binder/IAppOpsCallback.h
diff --git a/libs/binder/include/binder/IAppOpsService.h b/libs/permission/include/binder/IAppOpsService.h
index 22f056b235..22f056b235 100644
--- a/libs/binder/include/binder/IAppOpsService.h
+++ b/libs/permission/include/binder/IAppOpsService.h
diff --git a/libs/renderengine/Android.bp b/libs/renderengine/Android.bp
index 026b19a75a..f395ab43d8 100644
--- a/libs/renderengine/Android.bp
+++ b/libs/renderengine/Android.bp
@@ -48,6 +48,7 @@ filegroup {
name: "librenderengine_sources",
srcs: [
"Description.cpp",
+ "ExternalTexture.cpp",
"Mesh.cpp",
"RenderEngine.cpp",
"Texture.cpp",
@@ -91,6 +92,7 @@ filegroup {
"skia/debug/CaptureTimer.cpp",
"skia/debug/CommonPool.cpp",
"skia/debug/SkiaCapture.cpp",
+ "skia/debug/SkiaMemoryReporter.cpp",
"skia/filters/BlurFilter.cpp",
"skia/filters/LinearEffect.cpp",
],
diff --git a/libs/renderengine/ExternalTexture.cpp b/libs/renderengine/ExternalTexture.cpp
new file mode 100644
index 0000000000..eabff58eba
--- /dev/null
+++ b/libs/renderengine/ExternalTexture.cpp
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2021 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 <renderengine/ExternalTexture.h>
+#include <renderengine/RenderEngine.h>
+#include <ui/GraphicBuffer.h>
+
+#include "log/log_main.h"
+
+namespace android::renderengine {
+
+ExternalTexture::ExternalTexture(const sp<GraphicBuffer>& buffer, RenderEngine& renderEngine,
+ uint32_t usage)
+ : mBuffer(buffer), mRenderEngine(renderEngine) {
+ LOG_ALWAYS_FATAL_IF(buffer == nullptr,
+ "Attempted to bind a null buffer to an external texture!");
+ // GLESRenderEngine has a separate texture cache for output buffers,
+ if (usage == Usage::WRITEABLE &&
+ (mRenderEngine.getRenderEngineType() == RenderEngine::RenderEngineType::GLES ||
+ mRenderEngine.getRenderEngineType() == RenderEngine::RenderEngineType::THREADED)) {
+ return;
+ }
+ mRenderEngine.mapExternalTextureBuffer(mBuffer, usage & Usage::WRITEABLE);
+}
+
+ExternalTexture::~ExternalTexture() {
+ mRenderEngine.unmapExternalTextureBuffer(mBuffer);
+}
+
+} // namespace android::renderengine
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp
index a2963a7c33..d87315fdc2 100644
--- a/libs/renderengine/gl/GLESRenderEngine.cpp
+++ b/libs/renderengine/gl/GLESRenderEngine.cpp
@@ -746,7 +746,8 @@ void GLESRenderEngine::bindExternalTextureBuffer(uint32_t texName, const sp<Grap
return;
}
-void GLESRenderEngine::cacheExternalTextureBuffer(const sp<GraphicBuffer>& buffer) {
+void GLESRenderEngine::mapExternalTextureBuffer(const sp<GraphicBuffer>& buffer,
+ bool /*isRenderable*/) {
ATRACE_CALL();
mImageManager->cacheAsync(buffer, nullptr);
}
@@ -797,8 +798,8 @@ status_t GLESRenderEngine::cacheExternalTextureBufferInternal(const sp<GraphicBu
return NO_ERROR;
}
-void GLESRenderEngine::unbindExternalTextureBuffer(uint64_t bufferId) {
- mImageManager->releaseAsync(bufferId, nullptr);
+void GLESRenderEngine::unmapExternalTextureBuffer(const sp<GraphicBuffer>& buffer) {
+ mImageManager->releaseAsync(buffer->getId(), nullptr);
}
std::shared_ptr<ImageManager::Barrier> GLESRenderEngine::unbindExternalTextureBufferForTesting(
@@ -1102,7 +1103,7 @@ EGLImageKHR GLESRenderEngine::createFramebufferImageIfNeeded(ANativeWindowBuffer
status_t GLESRenderEngine::drawLayers(const DisplaySettings& display,
const std::vector<const LayerSettings*>& layers,
- const sp<GraphicBuffer>& buffer,
+ const std::shared_ptr<ExternalTexture>& buffer,
const bool useFramebufferCache, base::unique_fd&& bufferFence,
base::unique_fd* drawFence) {
ATRACE_CALL();
@@ -1125,7 +1126,7 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display,
return BAD_VALUE;
}
- validateOutputBufferUsage(buffer);
+ validateOutputBufferUsage(buffer->getBuffer());
std::unique_ptr<BindNativeBufferAsFramebuffer> fbo;
// Gathering layers that requested blur, we'll need them to decide when to render to an
@@ -1142,11 +1143,13 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display,
if (blurLayersSize == 0) {
fbo = std::make_unique<BindNativeBufferAsFramebuffer>(*this,
- buffer.get()->getNativeBuffer(),
+ buffer->getBuffer()
+ .get()
+ ->getNativeBuffer(),
useFramebufferCache);
if (fbo->getStatus() != NO_ERROR) {
ALOGE("Failed to bind framebuffer! Aborting GPU composition for buffer (%p).",
- buffer->handle);
+ buffer->getBuffer()->handle);
checkErrors();
return fbo->getStatus();
}
@@ -1157,7 +1160,7 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display,
mBlurFilter->setAsDrawTarget(display, blurLayers.front()->backgroundBlurRadius);
if (status != NO_ERROR) {
ALOGE("Failed to prepare blur filter! Aborting GPU composition for buffer (%p).",
- buffer->handle);
+ buffer->getBuffer()->handle);
checkErrors();
return status;
}
@@ -1194,7 +1197,7 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display,
auto status = mBlurFilter->prepare();
if (status != NO_ERROR) {
ALOGE("Failed to render blur effect! Aborting GPU composition for buffer (%p).",
- buffer->handle);
+ buffer->getBuffer()->handle);
checkErrors("Can't render first blur pass");
return status;
}
@@ -1203,6 +1206,7 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display,
// Done blurring, time to bind the native FBO and render our blur onto it.
fbo = std::make_unique<BindNativeBufferAsFramebuffer>(*this,
buffer.get()
+ ->getBuffer()
->getNativeBuffer(),
useFramebufferCache);
status = fbo->getStatus();
@@ -1215,7 +1219,7 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display,
}
if (status != NO_ERROR) {
ALOGE("Failed to bind framebuffer! Aborting GPU composition for buffer (%p).",
- buffer->handle);
+ buffer->getBuffer()->handle);
checkErrors("Can't bind native framebuffer");
return status;
}
@@ -1223,7 +1227,7 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display,
status = mBlurFilter->render(blurLayersSize > 1);
if (status != NO_ERROR) {
ALOGE("Failed to render blur effect! Aborting GPU composition for buffer (%p).",
- buffer->handle);
+ buffer->getBuffer()->handle);
checkErrors("Can't render blur filter");
return status;
}
@@ -1250,7 +1254,7 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display,
disableTexture = false;
isOpaque = layer->source.buffer.isOpaque;
- sp<GraphicBuffer> gBuf = layer->source.buffer.buffer;
+ sp<GraphicBuffer> gBuf = layer->source.buffer.buffer->getBuffer();
validateInputBufferUsage(gBuf);
bindExternalTextureBuffer(layer->source.buffer.textureName, gBuf,
layer->source.buffer.fence);
@@ -1274,7 +1278,7 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display,
// Do not cache protected EGLImage, protected memory is limited.
if (gBuf->getUsage() & GRALLOC_USAGE_PROTECTED) {
- unbindExternalTextureBuffer(gBuf->getId());
+ unmapExternalTextureBuffer(gBuf);
}
}
diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h
index cd7a86bb0e..e7ed9c01fa 100644
--- a/libs/renderengine/gl/GLESRenderEngine.h
+++ b/libs/renderengine/gl/GLESRenderEngine.h
@@ -60,16 +60,14 @@ public:
void primeCache() override;
void genTextures(size_t count, uint32_t* names) override;
void deleteTextures(size_t count, uint32_t const* names) override;
- void cacheExternalTextureBuffer(const sp<GraphicBuffer>& buffer) EXCLUDES(mRenderingMutex);
- void unbindExternalTextureBuffer(uint64_t bufferId) EXCLUDES(mRenderingMutex);
-
bool isProtected() const override { return mInProtectedContext; }
bool supportsProtectedContent() const override;
bool useProtectedContext(bool useProtectedContext) override;
status_t drawLayers(const DisplaySettings& display,
const std::vector<const LayerSettings*>& layers,
- const sp<GraphicBuffer>& buffer, const bool useFramebufferCache,
- base::unique_fd&& bufferFence, base::unique_fd* drawFence) override;
+ const std::shared_ptr<ExternalTexture>& buffer,
+ const bool useFramebufferCache, base::unique_fd&& bufferFence,
+ base::unique_fd* drawFence) override;
bool cleanupPostRender(CleanupMode mode) override;
int getContextPriority() override;
bool supportsBackgroundBlur() override { return mBlurFilter != nullptr; }
@@ -105,6 +103,9 @@ protected:
EXCLUDES(mFramebufferImageCacheMutex);
size_t getMaxTextureSize() const override;
size_t getMaxViewportDims() const override;
+ void mapExternalTextureBuffer(const sp<GraphicBuffer>& buffer, bool isRenderable)
+ EXCLUDES(mRenderingMutex);
+ void unmapExternalTextureBuffer(const sp<GraphicBuffer>& buffer) EXCLUDES(mRenderingMutex);
private:
friend class BindNativeBufferAsFramebuffer;
diff --git a/libs/renderengine/include/renderengine/ExternalTexture.h b/libs/renderengine/include/renderengine/ExternalTexture.h
new file mode 100644
index 0000000000..07f0833d4a
--- /dev/null
+++ b/libs/renderengine/include/renderengine/ExternalTexture.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2021 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 <android-base/macros.h>
+#include <ui/GraphicBuffer.h>
+
+namespace android::renderengine {
+
+class RenderEngine;
+
+/**
+ * Manages GPU image resources on behalf of clients using RenderEngine.
+ *
+ * Clients of RenderEngine are required to wrap their GraphicBuffer objects as an ExternalTexture,
+ * which is then mapped into GPU resources required by RenderEngine. When a client no longer needs
+ * to use the GraphicBuffer as input into RenderEngine::drawLayers, then the client should delete
+ * their ExternalTexture so that resources may be freed.
+ */
+class ExternalTexture {
+public:
+ // Usage specifies the rendering intent for the buffer.
+ enum Usage : uint32_t {
+ // When a buffer is not READABLE but is WRITEABLE, then GLESRenderEngine will use that as a
+ // hint to load the buffer into a separate cache
+ READABLE = 1 << 0,
+
+ // The buffer needs to be mapped as a 2D texture if set, otherwise must be mapped as an
+ // external texture
+ WRITEABLE = 1 << 1,
+ };
+ // Creates an ExternalTexture for the provided buffer and RenderEngine instance, with the given
+ // usage hint of type Usage.
+ ExternalTexture(const sp<GraphicBuffer>& buffer, RenderEngine& renderEngine, uint32_t usage);
+
+ ~ExternalTexture();
+
+ // Retrieves the buffer that is bound to this texture.
+ const sp<GraphicBuffer>& getBuffer() const { return mBuffer; }
+
+private:
+ sp<GraphicBuffer> mBuffer;
+ RenderEngine& mRenderEngine;
+ DISALLOW_COPY_AND_ASSIGN(ExternalTexture);
+};
+
+} // namespace android::renderengine
diff --git a/libs/renderengine/include/renderengine/LayerSettings.h b/libs/renderengine/include/renderengine/LayerSettings.h
index 7661233967..c54c5ba047 100644
--- a/libs/renderengine/include/renderengine/LayerSettings.h
+++ b/libs/renderengine/include/renderengine/LayerSettings.h
@@ -16,11 +16,9 @@
#pragma once
-#include <iosfwd>
-
#include <math/mat4.h>
#include <math/vec3.h>
-#include <renderengine/Texture.h>
+#include <renderengine/ExternalTexture.h>
#include <ui/BlurRegion.h>
#include <ui/Fence.h>
#include <ui/FloatRect.h>
@@ -31,6 +29,8 @@
#include <ui/StretchEffect.h>
#include <ui/Transform.h>
+#include <iosfwd>
+
namespace android {
namespace renderengine {
@@ -39,7 +39,7 @@ struct Buffer {
// Buffer containing the image that we will render.
// If buffer == nullptr, then the rest of the fields in this struct will be
// ignored.
- sp<GraphicBuffer> buffer = nullptr;
+ std::shared_ptr<ExternalTexture> buffer = nullptr;
// Fence that will fire when the buffer is ready to be bound.
sp<Fence> fence = nullptr;
diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h
index 4639a684a5..a9223ef28c 100644
--- a/libs/renderengine/include/renderengine/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/RenderEngine.h
@@ -17,19 +17,20 @@
#ifndef SF_RENDERENGINE_H_
#define SF_RENDERENGINE_H_
-#include <stdint.h>
-#include <sys/types.h>
-#include <memory>
-
#include <android-base/unique_fd.h>
#include <math/mat4.h>
#include <renderengine/DisplaySettings.h>
+#include <renderengine/ExternalTexture.h>
#include <renderengine/Framebuffer.h>
#include <renderengine/Image.h>
#include <renderengine/LayerSettings.h>
+#include <stdint.h>
+#include <sys/types.h>
#include <ui/GraphicTypes.h>
#include <ui/Transform.h>
+#include <memory>
+
/**
* Allows to set RenderEngine backend to GLES (default) or SkiaGL (NOT yet supported).
*/
@@ -51,6 +52,7 @@ class Region;
namespace renderengine {
+class ExternalTexture;
class Image;
class Mesh;
class Texture;
@@ -104,23 +106,6 @@ public:
virtual void genTextures(size_t count, uint32_t* names) = 0;
virtual void deleteTextures(size_t count, uint32_t const* names) = 0;
- // Caches Image resources for this buffer, but does not bind the buffer to
- // a particular texture.
- // Note that work is deferred to an additional thread, i.e. this call
- // is made asynchronously, but the caller can expect that cache/unbind calls
- // are performed in a manner that's conflict serializable, i.e. unbinding
- // a buffer should never occur before binding the buffer if the caller
- // called {bind, cache}ExternalTextureBuffer before calling unbind.
- virtual void cacheExternalTextureBuffer(const sp<GraphicBuffer>& buffer) = 0;
- // Removes internal resources referenced by the bufferId. This method should be
- // invoked when the caller will no longer hold a reference to a GraphicBuffer
- // and needs to clean up its resources.
- // Note that work is deferred to an additional thread, i.e. this call
- // is made asynchronously, but the caller can expect that cache/unbind calls
- // are performed in a manner that's conflict serializable, i.e. unbinding
- // a buffer should never occur before binding the buffer if the caller
- // called {bind, cache}ExternalTextureBuffer before calling unbind.
- virtual void unbindExternalTextureBuffer(uint64_t bufferId) = 0;
enum class CleanupMode {
CLEAN_OUTPUT_RESOURCES,
@@ -141,7 +126,7 @@ public:
// do any work.
virtual bool cleanupPostRender(CleanupMode mode = CleanupMode::CLEAN_OUTPUT_RESOURCES) = 0;
- // queries
+ // queries that are required to be thread safe
virtual size_t getMaxTextureSize() const = 0;
virtual size_t getMaxViewportDims() const = 0;
@@ -149,8 +134,11 @@ public:
// ----- BEGIN NEW INTERFACE -----
+ // queries that are required to be thread safe
virtual bool isProtected() const = 0;
virtual bool supportsProtectedContent() const = 0;
+
+ // Attempt to switch RenderEngine into and out of protectedContext mode
virtual bool useProtectedContext(bool useProtectedContext) = 0;
// Notify RenderEngine of changes to the dimensions of the primary display
@@ -190,8 +178,9 @@ public:
// now, this always returns NO_ERROR.
virtual status_t drawLayers(const DisplaySettings& display,
const std::vector<const LayerSettings*>& layers,
- const sp<GraphicBuffer>& buffer, const bool useFramebufferCache,
- base::unique_fd&& bufferFence, base::unique_fd* drawFence) = 0;
+ const std::shared_ptr<ExternalTexture>& buffer,
+ const bool useFramebufferCache, base::unique_fd&& bufferFence,
+ base::unique_fd* drawFence) = 0;
virtual void cleanFramebufferCache() = 0;
// Returns the priority this context was actually created with. Note: this may not be
// the same as specified at context creation time, due to implementation limits on the
@@ -199,7 +188,8 @@ public:
virtual int getContextPriority() = 0;
// Returns true if blur was requested in the RenderEngineCreationArgs and the implementation
- // also supports background blur. If false, no blur will be applied when drawing layers.
+ // also supports background blur. If false, no blur will be applied when drawing layers. This
+ // query is required to be thread safe.
virtual bool supportsBackgroundBlur() = 0;
// Returns the current type of RenderEngine instance that was created.
@@ -211,6 +201,31 @@ public:
static void validateOutputBufferUsage(const sp<GraphicBuffer>&);
protected:
+ // Maps GPU resources for this buffer.
+ // Note that work may be deferred to an additional thread, i.e. this call
+ // is made asynchronously, but the caller can expect that map/unmap calls
+ // are performed in a manner that's conflict serializable, i.e. unmapping
+ // a buffer should never occur before binding the buffer if the caller
+ // called mapExternalTextureBuffer before calling unmap.
+ // Note also that if the buffer contains protected content, then mapping those GPU resources may
+ // be deferred until the buffer is really used for drawing. This is because typical SoCs that
+ // support protected memory only support a limited amount, so optimisitically mapping protected
+ // memory may be too burdensome. If a buffer contains protected content and the RenderEngine
+ // implementation supports protected context, then GPU resources may be mapped into both the
+ // protected and unprotected contexts.
+ // If the buffer may ever be written to by RenderEngine, then isRenderable must be true.
+ virtual void mapExternalTextureBuffer(const sp<GraphicBuffer>& buffer, bool isRenderable) = 0;
+ // Unmaps GPU resources used by this buffer. This method should be
+ // invoked when the caller will no longer hold a reference to a GraphicBuffer
+ // and needs to clean up its resources.
+ // Note that if there are multiple callers holding onto the same buffer, then the buffer's
+ // resources may be internally ref-counted to guard against use-after-free errors. Note that
+ // work may be deferred to an additional thread, i.e. this call is expected to be made
+ // asynchronously, but the caller can expect that map/unmap calls are performed in a manner
+ // that's conflict serializable, i.e. unmap a buffer should never occur before binding the
+ // buffer if the caller called mapExternalTextureBuffer before calling unmap.
+ virtual void unmapExternalTextureBuffer(const sp<GraphicBuffer>& buffer) = 0;
+ friend class ExternalTexture;
friend class threaded::RenderEngineThreaded;
const RenderEngineType mRenderEngineType;
};
@@ -295,7 +310,8 @@ private:
bool precacheToneMapperShaderOnly = false;
bool supportsBackgroundBlur = false;
RenderEngine::ContextPriority contextPriority = RenderEngine::ContextPriority::MEDIUM;
- RenderEngine::RenderEngineType renderEngineType = RenderEngine::RenderEngineType::GLES;
+ RenderEngine::RenderEngineType renderEngineType =
+ RenderEngine::RenderEngineType::SKIA_GL_THREADED;
};
} // namespace renderengine
diff --git a/libs/renderengine/include/renderengine/mock/RenderEngine.h b/libs/renderengine/include/renderengine/mock/RenderEngine.h
index a27d28e371..f7d64544b4 100644
--- a/libs/renderengine/include/renderengine/mock/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/mock/RenderEngine.h
@@ -39,8 +39,6 @@ public:
MOCK_METHOD1(dump, void(std::string&));
MOCK_METHOD2(genTextures, void(size_t, uint32_t*));
MOCK_METHOD2(deleteTextures, void(size_t, uint32_t const*));
- MOCK_METHOD1(cacheExternalTextureBuffer, void(const sp<GraphicBuffer>&));
- MOCK_METHOD1(unbindExternalTextureBuffer, void(uint64_t));
MOCK_METHOD1(drawMesh, void(const renderengine::Mesh&));
MOCK_CONST_METHOD0(getMaxTextureSize, size_t());
MOCK_CONST_METHOD0(getMaxViewportDims, size_t());
@@ -52,12 +50,17 @@ public:
void(Rect, Rect));
MOCK_METHOD6(drawLayers,
status_t(const DisplaySettings&, const std::vector<const LayerSettings*>&,
- const sp<GraphicBuffer>&, const bool, base::unique_fd&&,
+ const std::shared_ptr<ExternalTexture>&, const bool, base::unique_fd&&,
base::unique_fd*));
MOCK_METHOD0(cleanFramebufferCache, void());
MOCK_METHOD0(getContextPriority, int());
MOCK_METHOD0(supportsBackgroundBlur, bool());
MOCK_METHOD1(onPrimaryDisplaySizeChanged, void(ui::Size));
+
+protected:
+ // mock renderengine still needs to implement these, but callers should never need to call them.
+ void mapExternalTextureBuffer(const sp<GraphicBuffer>&, bool) {}
+ void unmapExternalTextureBuffer(const sp<GraphicBuffer>&) {}
};
} // namespace mock
diff --git a/libs/renderengine/skia/AutoBackendTexture.cpp b/libs/renderengine/skia/AutoBackendTexture.cpp
index c535597aea..8ae69de7f3 100644
--- a/libs/renderengine/skia/AutoBackendTexture.cpp
+++ b/libs/renderengine/skia/AutoBackendTexture.cpp
@@ -29,7 +29,8 @@ namespace renderengine {
namespace skia {
AutoBackendTexture::AutoBackendTexture(GrDirectContext* context, AHardwareBuffer* buffer,
- bool isRender) {
+ bool isOutputBuffer)
+ : mIsOutputBuffer(isOutputBuffer) {
ATRACE_CALL();
AHardwareBuffer_Desc desc;
AHardwareBuffer_describe(buffer, &desc);
@@ -40,8 +41,12 @@ AutoBackendTexture::AutoBackendTexture(GrDirectContext* context, AHardwareBuffer
GrAHardwareBufferUtils::MakeBackendTexture(context, buffer, desc.width, desc.height,
&mDeleteProc, &mUpdateProc, &mImageCtx,
createProtectedImage, backendFormat,
- isRender);
+ isOutputBuffer);
mColorType = GrAHardwareBufferUtils::GetSkColorTypeFromBufferFormat(desc.format);
+ ALOGE_IF(!mBackendTexture.isValid(),
+ "Failed to create a valid texture. [%p]:[%d,%d] isProtected:%d isWriteable:%d "
+ "format:%d",
+ this, desc.width, desc.height, createProtectedImage, isOutputBuffer, desc.format);
}
void AutoBackendTexture::unref(bool releaseLocalResources) {
@@ -92,13 +97,16 @@ sk_sp<SkImage> AutoBackendTexture::makeImage(ui::Dataspace dataspace, SkAlphaTyp
mImage = image;
mDataspace = dataspace;
- LOG_ALWAYS_FATAL_IF(mImage == nullptr, "Unable to generate SkImage from buffer");
+ LOG_ALWAYS_FATAL_IF(mImage == nullptr,
+ "Unable to generate SkImage. isTextureValid:%d dataspace:%d",
+ mBackendTexture.isValid(), dataspace);
return mImage;
}
sk_sp<SkSurface> AutoBackendTexture::getOrCreateSurface(ui::Dataspace dataspace,
GrDirectContext* context) {
ATRACE_CALL();
+ LOG_ALWAYS_FATAL_IF(!mIsOutputBuffer, "You can't generate a SkSurface for a read-only texture");
if (!mSurface.get() || mDataspace != dataspace) {
sk_sp<SkSurface> surface =
SkSurface::MakeFromBackendTexture(context, mBackendTexture,
@@ -113,10 +121,12 @@ sk_sp<SkSurface> AutoBackendTexture::getOrCreateSurface(ui::Dataspace dataspace,
}
mDataspace = dataspace;
- LOG_ALWAYS_FATAL_IF(mSurface == nullptr, "Unable to generate SkSurface");
+ LOG_ALWAYS_FATAL_IF(mSurface == nullptr,
+ "Unable to generate SkSurface. isTextureValid:%d dataspace:%d",
+ mBackendTexture.isValid(), dataspace);
return mSurface;
}
} // namespace skia
} // namespace renderengine
-} // namespace android \ No newline at end of file
+} // namespace android
diff --git a/libs/renderengine/skia/AutoBackendTexture.h b/libs/renderengine/skia/AutoBackendTexture.h
index bb758780e1..3133de60b5 100644
--- a/libs/renderengine/skia/AutoBackendTexture.h
+++ b/libs/renderengine/skia/AutoBackendTexture.h
@@ -21,9 +21,9 @@
#include <SkImage.h>
#include <SkSurface.h>
#include <sys/types.h>
+#include <ui/GraphicTypes.h>
#include "android-base/macros.h"
-#include "ui/GraphicTypes.h"
namespace android {
namespace renderengine {
@@ -41,26 +41,29 @@ public:
// of shared ownership with Skia objects, so we wrap it here instead.
class LocalRef {
public:
- LocalRef() {}
-
- ~LocalRef() {
- // Destroying the texture is the same as setting it to null
- setTexture(nullptr);
+ LocalRef(GrDirectContext* context, AHardwareBuffer* buffer, bool isOutputBuffer) {
+ mTexture = new AutoBackendTexture(context, buffer, isOutputBuffer);
+ mTexture->ref();
}
- // Sets the texture to locally ref-track.
- void setTexture(AutoBackendTexture* texture) {
+ ~LocalRef() {
if (mTexture != nullptr) {
mTexture->unref(true);
}
+ }
- mTexture = texture;
- if (mTexture != nullptr) {
- mTexture->ref();
- }
+ // Makes a new SkImage from the texture content.
+ // As SkImages are immutable but buffer content is not, we create
+ // a new SkImage every time.
+ sk_sp<SkImage> makeImage(ui::Dataspace dataspace, SkAlphaType alphaType,
+ GrDirectContext* context) {
+ return mTexture->makeImage(dataspace, alphaType, context);
}
- AutoBackendTexture* getTexture() const { return mTexture; }
+ // Makes a new SkSurface from the texture content, if needed.
+ sk_sp<SkSurface> getOrCreateSurface(ui::Dataspace dataspace, GrDirectContext* context) {
+ return mTexture->getOrCreateSurface(dataspace, context);
+ }
DISALLOW_COPY_AND_ASSIGN(LocalRef);
@@ -68,8 +71,12 @@ public:
AutoBackendTexture* mTexture = nullptr;
};
+private:
// Creates a GrBackendTexture whose contents come from the provided buffer.
- AutoBackendTexture(GrDirectContext* context, AHardwareBuffer* buffer, bool isRender);
+ AutoBackendTexture(GrDirectContext* context, AHardwareBuffer* buffer, bool isOutputBuffer);
+
+ // The only way to invoke dtor is with unref, when mUsageCount is 0.
+ ~AutoBackendTexture() {}
void ref() { mUsageCount++; }
@@ -86,10 +93,6 @@ public:
// Makes a new SkSurface from the texture content, if needed.
sk_sp<SkSurface> getOrCreateSurface(ui::Dataspace dataspace, GrDirectContext* context);
-private:
- // The only way to invoke dtor is with unref, when mUsageCount is 0.
- ~AutoBackendTexture() {}
-
GrBackendTexture mBackendTexture;
GrAHardwareBufferUtils::DeleteImageProc mDeleteProc;
GrAHardwareBufferUtils::UpdateImageProc mUpdateProc;
@@ -100,6 +103,7 @@ private:
int mUsageCount = 0;
+ const bool mIsOutputBuffer;
sk_sp<SkImage> mImage = nullptr;
sk_sp<SkSurface> mSurface = nullptr;
ui::Dataspace mDataspace = ui::Dataspace::UNKNOWN;
diff --git a/libs/renderengine/skia/Cache.cpp b/libs/renderengine/skia/Cache.cpp
index 0cd3b622fa..1c2b2fc3ca 100644
--- a/libs/renderengine/skia/Cache.cpp
+++ b/libs/renderengine/skia/Cache.cpp
@@ -25,8 +25,6 @@
#include "ui/Rect.h"
#include "utils/Timers.h"
-#include <android/hardware_buffer.h>
-
namespace android::renderengine::skia {
namespace {
@@ -48,7 +46,7 @@ constexpr auto kDestDataSpace = ui::Dataspace::SRGB;
} // namespace
static void drawShadowLayers(SkiaRenderEngine* renderengine, const DisplaySettings& display,
- sp<GraphicBuffer> dstBuffer) {
+ const std::shared_ptr<ExternalTexture>& dstTexture) {
// Somewhat arbitrary dimensions, but on screen and slightly shorter, based
// on actual use.
FloatRect rect(0, 0, display.physicalDisplay.width(), display.physicalDisplay.height() - 30);
@@ -75,7 +73,7 @@ static void drawShadowLayers(SkiaRenderEngine* renderengine, const DisplaySettin
auto layers = std::vector<const LayerSettings*>{&layer};
// The identity matrix will generate the fast shader
- renderengine->drawLayers(display, layers, dstBuffer, kUseFrameBufferCache, base::unique_fd(),
+ renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache, base::unique_fd(),
nullptr);
// This matrix, which has different scales for x and y, will
// generate the slower (more general case) version, which has variants for translucent
@@ -88,13 +86,14 @@ static void drawShadowLayers(SkiaRenderEngine* renderengine, const DisplaySettin
// clang-format on
for (auto translucent : {false, true}) {
layer.shadow.casterIsTranslucent = translucent;
- renderengine->drawLayers(display, layers, dstBuffer, kUseFrameBufferCache,
+ renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache,
base::unique_fd(), nullptr);
}
}
static void drawImageLayers(SkiaRenderEngine* renderengine, const DisplaySettings& display,
- sp<GraphicBuffer> dstBuffer, sp<GraphicBuffer> srcBuffer) {
+ const std::shared_ptr<ExternalTexture>& dstTexture,
+ const std::shared_ptr<ExternalTexture>& srcTexture) {
const Rect& displayRect = display.physicalDisplay;
FloatRect rect(0, 0, displayRect.width(), displayRect.height());
LayerSettings layer{
@@ -105,7 +104,7 @@ static void drawImageLayers(SkiaRenderEngine* renderengine, const DisplaySetting
},
.source = PixelSource{.buffer =
Buffer{
- .buffer = srcBuffer,
+ .buffer = srcTexture,
.maxMasteringLuminance = 1000.f,
.maxContentLuminance = 1000.f,
}},
@@ -128,7 +127,7 @@ static void drawImageLayers(SkiaRenderEngine* renderengine, const DisplaySetting
layer.source.buffer.isOpaque = isOpaque;
for (auto alpha : {half(.23999f), half(1.0f)}) {
layer.alpha = alpha;
- renderengine->drawLayers(display, layers, dstBuffer, kUseFrameBufferCache,
+ renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache,
base::unique_fd(), nullptr);
}
}
@@ -137,7 +136,7 @@ static void drawImageLayers(SkiaRenderEngine* renderengine, const DisplaySetting
}
static void drawSolidLayers(SkiaRenderEngine* renderengine, const DisplaySettings& display,
- sp<GraphicBuffer> dstBuffer) {
+ const std::shared_ptr<ExternalTexture>& dstTexture) {
const Rect& displayRect = display.physicalDisplay;
FloatRect rect(0, 0, displayRect.width(), displayRect.height());
LayerSettings layer{
@@ -145,11 +144,11 @@ static void drawSolidLayers(SkiaRenderEngine* renderengine, const DisplaySetting
Geometry{
.boundaries = rect,
},
- .alpha = 1,
.source =
PixelSource{
.solidColor = half3(0.1f, 0.2f, 0.3f),
},
+ .alpha = 1,
};
auto layers = std::vector<const LayerSettings*>{&layer};
@@ -157,14 +156,14 @@ static void drawSolidLayers(SkiaRenderEngine* renderengine, const DisplaySetting
layer.geometry.positionTransform = transform;
for (float roundedCornersRadius : {0.0f, 0.05f, 50.f}) {
layer.geometry.roundedCornersRadius = roundedCornersRadius;
- renderengine->drawLayers(display, layers, dstBuffer, kUseFrameBufferCache,
+ renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache,
base::unique_fd(), nullptr);
}
}
}
static void drawBlurLayers(SkiaRenderEngine* renderengine, const DisplaySettings& display,
- sp<GraphicBuffer> dstBuffer) {
+ const std::shared_ptr<ExternalTexture>& dstTexture) {
const Rect& displayRect = display.physicalDisplay;
FloatRect rect(0, 0, displayRect.width(), displayRect.height());
LayerSettings layer{
@@ -178,46 +177,11 @@ static void drawBlurLayers(SkiaRenderEngine* renderengine, const DisplaySettings
auto layers = std::vector<const LayerSettings*>{&layer};
for (int radius : {9, 60}) {
layer.backgroundBlurRadius = radius;
- renderengine->drawLayers(display, layers, dstBuffer, kUseFrameBufferCache,
+ renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache,
base::unique_fd(), nullptr);
}
}
-namespace {
-
-struct AHardwareBuffer_deleter {
- void operator()(AHardwareBuffer* ahb) const { AHardwareBuffer_release(ahb); }
-};
-
-std::unique_ptr<AHardwareBuffer, AHardwareBuffer_deleter> makeAHardwareBuffer() {
- AHardwareBuffer* buffer = nullptr;
-
- int w = 32;
- int h = 32;
-
- AHardwareBuffer_Desc hwbDesc;
- hwbDesc.width = w;
- hwbDesc.height = h;
- hwbDesc.layers = 1;
- hwbDesc.usage = AHARDWAREBUFFER_USAGE_CPU_READ_NEVER | AHARDWAREBUFFER_USAGE_CPU_WRITE_NEVER |
- AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE;
- hwbDesc.format = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
- // The following three are not used in the allocate
- hwbDesc.stride = 0;
- hwbDesc.rfu0 = 0;
- hwbDesc.rfu1 = 0;
-
- if (int error = AHardwareBuffer_allocate(&hwbDesc, &buffer)) {
- ALOGE("Failed to allocated hardware buffer, error: %d", error);
- if (buffer) {
- AHardwareBuffer_release(buffer);
- }
- return nullptr;
- }
- return std::unique_ptr<AHardwareBuffer, AHardwareBuffer_deleter>(buffer);
-}
-} // namespace
-
//
// The collection of shaders cached here were found by using perfetto to record shader compiles
// during actions that involve RenderEngine, logging the layer settings, and the shader code
@@ -251,6 +215,9 @@ void Cache::primeShaderCache(SkiaRenderEngine* renderengine) {
sp<GraphicBuffer> dstBuffer =
new GraphicBuffer(displayRect.width(), displayRect.height(), PIXEL_FORMAT_RGBA_8888, 1,
usage, "primeShaderCache_dst");
+
+ const auto dstTexture = std::make_shared<ExternalTexture>(dstBuffer, *renderengine,
+ ExternalTexture::Usage::WRITEABLE);
// This buffer will be the source for the call to drawImageLayers. Draw
// something to it as a placeholder for what an app draws. We should draw
// something, but the details are not important. Make use of the shadow layer drawing step
@@ -259,22 +226,29 @@ void Cache::primeShaderCache(SkiaRenderEngine* renderengine) {
new GraphicBuffer(displayRect.width(), displayRect.height(), PIXEL_FORMAT_RGBA_8888, 1,
usage, "drawImageLayer_src");
- drawSolidLayers(renderengine, display, dstBuffer);
- drawShadowLayers(renderengine, display, srcBuffer);
- drawBlurLayers(renderengine, display, dstBuffer);
+ const auto srcTexture =
+ std::make_shared<ExternalTexture>(srcBuffer, *renderengine,
+ ExternalTexture::Usage::READABLE |
+ ExternalTexture::Usage::WRITEABLE);
+
+ drawSolidLayers(renderengine, display, dstTexture);
+ drawShadowLayers(renderengine, display, srcTexture);
+ drawBlurLayers(renderengine, display, dstTexture);
// The majority of shaders are related to sampling images.
- drawImageLayers(renderengine, display, dstBuffer, srcBuffer);
+ drawImageLayers(renderengine, display, dstTexture, srcTexture);
- // Draw image layers again sampling from an AHardwareBuffer if it is possible to create one.
- if (auto ahb = makeAHardwareBuffer()) {
- sp<GraphicBuffer> externalBuffer = GraphicBuffer::fromAHardwareBuffer(ahb.get());
- // TODO(b/184665179) doubles number of image shader compilations, but only somewhere
- // between 6 and 8 will occur in real uses.
- drawImageLayers(renderengine, display, dstBuffer, externalBuffer);
- renderengine->unbindExternalTextureBuffer(externalBuffer->getId());
- }
+ // should be the same as AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE;
+ const int64_t usageExternal = GRALLOC_USAGE_HW_TEXTURE;
- renderengine->unbindExternalTextureBuffer(srcBuffer->getId());
+ sp<GraphicBuffer> externalBuffer =
+ new GraphicBuffer(displayRect.width(), displayRect.height(), PIXEL_FORMAT_RGBA_8888, 1,
+ usageExternal, "primeShaderCache_external");
+ const auto externalTexture =
+ std::make_shared<ExternalTexture>(externalBuffer, *renderengine,
+ ExternalTexture::Usage::READABLE);
+ // TODO(b/184665179) doubles number of image shader compilations, but only somewhere
+ // between 6 and 8 will occur in real uses.
+ drawImageLayers(renderengine, display, dstTexture, externalTexture);
const nsecs_t timeAfter = systemTime();
const float compileTimeMs = static_cast<float>(timeAfter - timeBefore) / 1.0E6;
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
index fb7e2856e4..377b6f89ad 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
@@ -28,6 +28,7 @@
#include <SkColorFilter.h>
#include <SkColorMatrix.h>
#include <SkColorSpace.h>
+#include <SkGraphics.h>
#include <SkImage.h>
#include <SkImageFilters.h>
#include <SkRegion.h>
@@ -40,13 +41,13 @@
#include <ui/DebugUtils.h>
#include <ui/GraphicBuffer.h>
#include <utils/Trace.h>
-#include "Cache.h"
#include <cmath>
#include <cstdint>
#include <memory>
#include "../gl/GLExtensions.h"
+#include "Cache.h"
#include "ColorSpaces.h"
#include "SkBlendMode.h"
#include "SkImageInfo.h"
@@ -54,6 +55,7 @@
#include "filters/LinearEffect.h"
#include "log/log_main.h"
#include "skia/debug/SkiaCapture.h"
+#include "skia/debug/SkiaMemoryReporter.h"
#include "system/graphics-base-v1.0.h"
namespace {
@@ -327,8 +329,6 @@ SkiaGLRenderEngine::SkiaGLRenderEngine(const RenderEngineCreationArgs& args, EGL
}
SkiaGLRenderEngine::~SkiaGLRenderEngine() {
- cleanFramebufferCache();
-
std::lock_guard<std::mutex> lock(mRenderingMutex);
if (mBlurFilter) {
delete mBlurFilter;
@@ -482,7 +482,8 @@ static bool needsToneMapping(ui::Dataspace sourceDataspace, ui::Dataspace destin
sourceTransfer != destTransfer;
}
-void SkiaGLRenderEngine::cacheExternalTextureBuffer(const sp<GraphicBuffer>& buffer) {
+void SkiaGLRenderEngine::mapExternalTextureBuffer(const sp<GraphicBuffer>& buffer,
+ bool isRenderable) {
// Only run this if RE is running on its own thread. This way the access to GL
// operations is guaranteed to be happening on the same thread.
if (mRenderEngineType != RenderEngineType::SKIA_GL_THREADED) {
@@ -503,25 +504,41 @@ void SkiaGLRenderEngine::cacheExternalTextureBuffer(const sp<GraphicBuffer>& buf
auto& cache = mInProtectedContext ? mProtectedTextureCache : mTextureCache;
std::lock_guard<std::mutex> lock(mRenderingMutex);
- auto iter = cache.find(buffer->getId());
- if (iter != cache.end()) {
- ALOGV("Texture already exists in cache.");
- } else {
+ mGraphicBufferExternalRefs[buffer->getId()]++;
+
+ if (const auto& iter = cache.find(buffer->getId()); iter == cache.end()) {
std::shared_ptr<AutoBackendTexture::LocalRef> imageTextureRef =
- std::make_shared<AutoBackendTexture::LocalRef>();
- imageTextureRef->setTexture(
- new AutoBackendTexture(grContext.get(), buffer->toAHardwareBuffer(), false));
+ std::make_shared<AutoBackendTexture::LocalRef>(grContext.get(),
+ buffer->toAHardwareBuffer(),
+ isRenderable);
cache.insert({buffer->getId(), imageTextureRef});
}
// restore the original state of the protected context if necessary
useProtectedContext(protectedContextState);
}
-void SkiaGLRenderEngine::unbindExternalTextureBuffer(uint64_t bufferId) {
+void SkiaGLRenderEngine::unmapExternalTextureBuffer(const sp<GraphicBuffer>& buffer) {
ATRACE_CALL();
std::lock_guard<std::mutex> lock(mRenderingMutex);
- mTextureCache.erase(bufferId);
- mProtectedTextureCache.erase(bufferId);
+ if (const auto& iter = mGraphicBufferExternalRefs.find(buffer->getId());
+ iter != mGraphicBufferExternalRefs.end()) {
+ if (iter->second == 0) {
+ ALOGW("Attempted to unmap GraphicBuffer <id: %" PRId64
+ "> from RenderEngine texture, but the "
+ "ref count was already zero!",
+ buffer->getId());
+ mGraphicBufferExternalRefs.erase(buffer->getId());
+ return;
+ }
+
+ iter->second--;
+
+ if (iter->second == 0) {
+ mTextureCache.erase(buffer->getId());
+ mProtectedTextureCache.erase(buffer->getId());
+ mGraphicBufferExternalRefs.erase(buffer->getId());
+ }
+ }
}
sk_sp<SkShader> SkiaGLRenderEngine::createRuntimeEffectShader(sk_sp<SkShader> shader,
@@ -619,8 +636,8 @@ private:
status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display,
const std::vector<const LayerSettings*>& layers,
- const sp<GraphicBuffer>& buffer,
- const bool useFramebufferCache,
+ const std::shared_ptr<ExternalTexture>& buffer,
+ const bool /*useFramebufferCache*/,
base::unique_fd&& bufferFence, base::unique_fd* drawFence) {
ATRACE_NAME("SkiaGL::drawLayers");
@@ -643,38 +660,26 @@ status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display,
return BAD_VALUE;
}
- validateOutputBufferUsage(buffer);
+ validateOutputBufferUsage(buffer->getBuffer());
auto grContext = mInProtectedContext ? mProtectedGrContext : mGrContext;
auto& cache = mInProtectedContext ? mProtectedTextureCache : mTextureCache;
- AHardwareBuffer_Desc bufferDesc;
- AHardwareBuffer_describe(buffer->toAHardwareBuffer(), &bufferDesc);
-
- std::shared_ptr<AutoBackendTexture::LocalRef> surfaceTextureRef = nullptr;
- if (useFramebufferCache) {
- auto iter = cache.find(buffer->getId());
- if (iter != cache.end()) {
- ALOGV("Cache hit!");
- ATRACE_NAME("Cache hit");
- surfaceTextureRef = iter->second;
- }
- }
- if (surfaceTextureRef == nullptr || surfaceTextureRef->getTexture() == nullptr) {
- ATRACE_NAME("Cache miss");
- surfaceTextureRef = std::make_shared<AutoBackendTexture::LocalRef>();
- surfaceTextureRef->setTexture(
- new AutoBackendTexture(grContext.get(), buffer->toAHardwareBuffer(), true));
- if (useFramebufferCache) {
- ALOGD("Adding to cache");
- cache.insert({buffer->getId(), surfaceTextureRef});
- }
+ std::shared_ptr<AutoBackendTexture::LocalRef> surfaceTextureRef;
+ if (const auto& it = cache.find(buffer->getBuffer()->getId()); it != cache.end()) {
+ surfaceTextureRef = it->second;
+ } else {
+ surfaceTextureRef =
+ std::make_shared<AutoBackendTexture::LocalRef>(grContext.get(),
+ buffer->getBuffer()
+ ->toAHardwareBuffer(),
+ true);
}
const ui::Dataspace dstDataspace =
mUseColorManagement ? display.outputDataspace : ui::Dataspace::UNKNOWN;
sk_sp<SkSurface> dstSurface =
- surfaceTextureRef->getTexture()->getOrCreateSurface(dstDataspace, grContext.get());
+ surfaceTextureRef->getOrCreateSurface(dstDataspace, grContext.get());
SkCanvas* dstCanvas = mCapture->tryCapture(dstSurface.get());
if (dstCanvas == nullptr) {
@@ -816,27 +821,30 @@ status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display,
// rect to be blurred in the coordinate space of blurInput
const auto blurRect = canvas->getTotalMatrix().mapRect(bounds);
- if (layer->backgroundBlurRadius > 0) {
- ATRACE_NAME("BackgroundBlur");
- auto blurredImage =
- mBlurFilter->generate(grContext.get(), layer->backgroundBlurRadius,
- blurInput, blurRect);
+ // TODO(b/182216890): Filter out empty layers earlier
+ if (blurRect.width() > 0 && blurRect.height() > 0) {
+ if (layer->backgroundBlurRadius > 0) {
+ ATRACE_NAME("BackgroundBlur");
+ auto blurredImage =
+ mBlurFilter->generate(grContext.get(), layer->backgroundBlurRadius,
+ blurInput, blurRect);
- cachedBlurs[layer->backgroundBlurRadius] = blurredImage;
+ cachedBlurs[layer->backgroundBlurRadius] = blurredImage;
- mBlurFilter->drawBlurRegion(canvas, getBlurRegion(layer), blurRect, blurredImage,
- blurInput);
- }
- for (auto region : layer->blurRegions) {
- if (cachedBlurs[region.blurRadius] == nullptr) {
- ATRACE_NAME("BlurRegion");
- cachedBlurs[region.blurRadius] =
- mBlurFilter->generate(grContext.get(), region.blurRadius, blurInput,
- blurRect);
+ mBlurFilter->drawBlurRegion(canvas, getBlurRegion(layer), blurRect,
+ blurredImage, blurInput);
+ }
+ for (auto region : layer->blurRegions) {
+ if (cachedBlurs[region.blurRadius] == nullptr) {
+ ATRACE_NAME("BlurRegion");
+ cachedBlurs[region.blurRadius] =
+ mBlurFilter->generate(grContext.get(), region.blurRadius, blurInput,
+ blurRect);
+ }
+
+ mBlurFilter->drawBlurRegion(canvas, region, blurRect,
+ cachedBlurs[region.blurRadius], blurInput);
}
-
- mBlurFilter->drawBlurRegion(canvas, region, blurRect,
- cachedBlurs[region.blurRadius], blurInput);
}
}
@@ -874,26 +882,29 @@ status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display,
SkPaint paint;
if (layer->source.buffer.buffer) {
ATRACE_NAME("DrawImage");
- validateInputBufferUsage(layer->source.buffer.buffer);
+ validateInputBufferUsage(layer->source.buffer.buffer->getBuffer());
const auto& item = layer->source.buffer;
std::shared_ptr<AutoBackendTexture::LocalRef> imageTextureRef = nullptr;
- auto iter = cache.find(item.buffer->getId());
- if (iter != cache.end()) {
+
+ if (const auto& iter = cache.find(item.buffer->getBuffer()->getId());
+ iter != cache.end()) {
imageTextureRef = iter->second;
} else {
- imageTextureRef = std::make_shared<AutoBackendTexture::LocalRef>();
- imageTextureRef->setTexture(new AutoBackendTexture(grContext.get(),
- item.buffer->toAHardwareBuffer(),
- false));
- cache.insert({item.buffer->getId(), imageTextureRef});
+ // If we didn't find the image in the cache, then create a local ref but don't cache
+ // it. If we're using skia, we're guaranteed to run on a dedicated GPU thread so if
+ // we didn't find anything in the cache then we intentionally did not cache this
+ // buffer's resources.
+ imageTextureRef = std::make_shared<
+ AutoBackendTexture::LocalRef>(grContext.get(),
+ item.buffer->getBuffer()->toAHardwareBuffer(),
+ false);
}
sk_sp<SkImage> image =
- imageTextureRef->getTexture()->makeImage(layerDataspace,
- item.usePremultipliedAlpha
- ? kPremul_SkAlphaType
- : kUnpremul_SkAlphaType,
- grContext.get());
+ imageTextureRef->makeImage(layerDataspace,
+ item.usePremultipliedAlpha ? kPremul_SkAlphaType
+ : kUnpremul_SkAlphaType,
+ grContext.get());
auto texMatrix = getSkM44(item.textureTransform).asM33();
// textureTansform was intended to be passed directly into a shader, so when
@@ -1198,15 +1209,6 @@ EGLSurface SkiaGLRenderEngine::createPlaceholderEglPbufferSurface(EGLDisplay dis
return eglCreatePbufferSurface(display, placeholderConfig, attributes.data());
}
-void SkiaGLRenderEngine::cleanFramebufferCache() {
- // TODO(b/180767535) Remove this method and use b/180767535 instead, which would allow
- // SF to control texture lifecycle more tightly rather than through custom hooks into RE.
- std::lock_guard<std::mutex> lock(mRenderingMutex);
- mRuntimeEffects.clear();
- mProtectedTextureCache.clear();
- mTextureCache.clear();
-}
-
int SkiaGLRenderEngine::getContextPriority() {
int value;
eglQueryContext(mEGLDisplay, mEGLContext, EGL_CONTEXT_PRIORITY_LEVEL_IMG, &value);
@@ -1249,9 +1251,44 @@ void SkiaGLRenderEngine::dump(std::string& result) {
StringAppendF(&result, "RenderEngine shaders cached since last dump/primeCache: %d\n",
mSkSLCacheMonitor.shadersCachedSinceLastCall());
+ std::vector<ResourcePair> cpuResourceMap = {
+ {"skia/sk_resource_cache/bitmap_", "Bitmaps"},
+ {"skia/sk_resource_cache/rrect-blur_", "Masks"},
+ {"skia/sk_resource_cache/rects-blur_", "Masks"},
+ {"skia/sk_resource_cache/tessellated", "Shadows"},
+ {"skia", "Other"},
+ };
+ SkiaMemoryReporter cpuReporter(cpuResourceMap, false);
+ SkGraphics::DumpMemoryStatistics(&cpuReporter);
+ StringAppendF(&result, "Skia CPU Caches: ");
+ cpuReporter.logTotals(result);
+ cpuReporter.logOutput(result);
+
{
std::lock_guard<std::mutex> lock(mRenderingMutex);
- StringAppendF(&result, "RenderEngine texture cache size: %zu\n", mTextureCache.size());
+
+ std::vector<ResourcePair> gpuResourceMap = {
+ {"texture_renderbuffer", "Texture/RenderBuffer"},
+ {"texture", "Texture"},
+ {"gr_text_blob_cache", "Text"},
+ {"skia", "Other"},
+ };
+ SkiaMemoryReporter gpuReporter(gpuResourceMap, true);
+ mGrContext->dumpMemoryStatistics(&gpuReporter);
+ StringAppendF(&result, "Skia's GPU Caches: ");
+ gpuReporter.logTotals(result);
+ gpuReporter.logOutput(result);
+ StringAppendF(&result, "Skia's Wrapped Objects:\n");
+ gpuReporter.logOutput(result, true);
+
+ StringAppendF(&result, "RenderEngine tracked buffers: %zu\n",
+ mGraphicBufferExternalRefs.size());
+ StringAppendF(&result, "Dumping buffer ids...\n");
+ for (const auto& [id, refCounts] : mGraphicBufferExternalRefs) {
+ StringAppendF(&result, "- 0x%" PRIx64 " - %d refs \n", id, refCounts);
+ }
+ StringAppendF(&result, "RenderEngine AHB/BackendTexture cache size: %zu\n",
+ mTextureCache.size());
StringAppendF(&result, "Dumping buffer ids...\n");
// TODO(178539829): It would be nice to know which layer these are coming from and what
// the texture sizes are.
@@ -1259,7 +1296,18 @@ void SkiaGLRenderEngine::dump(std::string& result) {
StringAppendF(&result, "- 0x%" PRIx64 "\n", id);
}
StringAppendF(&result, "\n");
- StringAppendF(&result, "RenderEngine protected texture cache size: %zu\n",
+
+ SkiaMemoryReporter gpuProtectedReporter(gpuResourceMap, true);
+ if (mProtectedGrContext) {
+ mProtectedGrContext->dumpMemoryStatistics(&gpuProtectedReporter);
+ }
+ StringAppendF(&result, "Skia's GPU Protected Caches: ");
+ gpuProtectedReporter.logTotals(result);
+ gpuProtectedReporter.logOutput(result);
+ StringAppendF(&result, "Skia's Protected Wrapped Objects:\n");
+ gpuProtectedReporter.logOutput(result, true);
+
+ StringAppendF(&result, "RenderEngine protected AHB/BackendTexture cache size: %zu\n",
mProtectedTextureCache.size());
StringAppendF(&result, "Dumping buffer ids...\n");
for (const auto& [id, unused] : mProtectedTextureCache) {
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.h b/libs/renderengine/skia/SkiaGLRenderEngine.h
index 8e77c16b40..e71c560a1f 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.h
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.h
@@ -23,6 +23,7 @@
#include <GrDirectContext.h>
#include <SkSurface.h>
#include <android-base/thread_annotations.h>
+#include <renderengine/ExternalTexture.h>
#include <renderengine/RenderEngine.h>
#include <sys/types.h>
@@ -52,13 +53,12 @@ public:
~SkiaGLRenderEngine() override EXCLUDES(mRenderingMutex);
void primeCache() override;
- void cacheExternalTextureBuffer(const sp<GraphicBuffer>& buffer) override;
- void unbindExternalTextureBuffer(uint64_t bufferId) override;
status_t drawLayers(const DisplaySettings& display,
const std::vector<const LayerSettings*>& layers,
- const sp<GraphicBuffer>& buffer, const bool useFramebufferCache,
- base::unique_fd&& bufferFence, base::unique_fd* drawFence) override;
- void cleanFramebufferCache() override;
+ const std::shared_ptr<ExternalTexture>& buffer,
+ const bool useFramebufferCache, base::unique_fd&& bufferFence,
+ base::unique_fd* drawFence) override;
+ void cleanFramebufferCache() override {}
int getContextPriority() override;
bool isProtected() const override { return mInProtectedContext; }
bool supportsProtectedContent() const override;
@@ -72,6 +72,8 @@ protected:
void dump(std::string& result) override;
size_t getMaxTextureSize() const override;
size_t getMaxViewportDims() const override;
+ void mapExternalTextureBuffer(const sp<GraphicBuffer>& buffer, bool isRenderable) override;
+ void unmapExternalTextureBuffer(const sp<GraphicBuffer>& buffer) override;
private:
static EGLConfig chooseEglConfig(EGLDisplay display, int format, bool logConfig);
@@ -114,7 +116,9 @@ private:
const PixelFormat mDefaultPixelFormat;
const bool mUseColorManagement;
- // Cache of GL textures that we'll store per GraphicBuffer ID
+ // Number of external holders of ExternalTexture references, per GraphicBuffer ID.
+ std::unordered_map<uint64_t, int32_t> mGraphicBufferExternalRefs GUARDED_BY(mRenderingMutex);
+ // Cache of GL textures that we'll store per GraphicBuffer ID, sliced by GPU context.
std::unordered_map<uint64_t, std::shared_ptr<AutoBackendTexture::LocalRef>> mTextureCache
GUARDED_BY(mRenderingMutex);
std::unordered_map<uint64_t, std::shared_ptr<AutoBackendTexture::LocalRef>>
diff --git a/libs/renderengine/skia/SkiaRenderEngine.h b/libs/renderengine/skia/SkiaRenderEngine.h
index d9821b62e0..9f6461a56e 100644
--- a/libs/renderengine/skia/SkiaRenderEngine.h
+++ b/libs/renderengine/skia/SkiaRenderEngine.h
@@ -42,15 +42,12 @@ public:
virtual void primeCache() override{};
virtual void genTextures(size_t /*count*/, uint32_t* /*names*/) override{};
virtual void deleteTextures(size_t /*count*/, uint32_t const* /*names*/) override{};
- virtual void cacheExternalTextureBuffer(const sp<GraphicBuffer>& /*buffer*/){};
- virtual void unbindExternalTextureBuffer(uint64_t /*bufferId*/){};
-
virtual bool isProtected() const override { return false; } // mInProtectedContext; }
virtual bool supportsProtectedContent() const override { return false; };
virtual bool useProtectedContext(bool /*useProtectedContext*/) override { return false; };
virtual status_t drawLayers(const DisplaySettings& /*display*/,
const std::vector<const LayerSettings*>& /*layers*/,
- const sp<GraphicBuffer>& /*buffer*/,
+ const std::shared_ptr<ExternalTexture>& /*buffer*/,
const bool /*useFramebufferCache*/,
base::unique_fd&& /*bufferFence*/,
base::unique_fd* /*drawFence*/) override {
@@ -61,6 +58,11 @@ public:
virtual void assertShadersCompiled(int numShaders) {}
virtual int reportShadersCompiled() { return 0; }
void setViewportAndProjection(Rect /*viewPort*/, Rect /*sourceCrop*/) override { }
+
+protected:
+ virtual void mapExternalTextureBuffer(const sp<GraphicBuffer>& /*buffer*/,
+ bool /*isRenderable*/) override;
+ virtual void unmapExternalTextureBuffer(const sp<GraphicBuffer>& /*buffer*/) override;
};
} // namespace skia
diff --git a/libs/renderengine/skia/debug/SkiaMemoryReporter.cpp b/libs/renderengine/skia/debug/SkiaMemoryReporter.cpp
new file mode 100644
index 0000000000..f24a4f1c05
--- /dev/null
+++ b/libs/renderengine/skia/debug/SkiaMemoryReporter.cpp
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2021 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 "RenderEngine"
+
+#include "SkiaMemoryReporter.h"
+
+#include <SkString.h>
+#include <android-base/stringprintf.h>
+#include <log/log_main.h>
+
+namespace android {
+namespace renderengine {
+namespace skia {
+
+using base::StringAppendF;
+
+SkiaMemoryReporter::SkiaMemoryReporter(const std::vector<ResourcePair>& resourceMap, bool itemize)
+ : mResourceMap(resourceMap),
+ mItemize(itemize),
+ mTotalSize("bytes", 0),
+ mPurgeableSize("bytes", 0) {}
+
+const char* SkiaMemoryReporter::mapName(const char* resourceName) {
+ for (auto& resource : mResourceMap) {
+ if (SkStrContains(resourceName, resource.first)) {
+ return resource.second;
+ }
+ }
+ return nullptr;
+}
+
+void SkiaMemoryReporter::resetCurrentElement() {
+ mCurrentElement.clear();
+ mCurrentValues.clear();
+ mIsCurrentValueWrapped = false;
+}
+
+void SkiaMemoryReporter::processCurrentElement() {
+ // compute the top level element name using the map
+ const char* resourceName = mCurrentElement.empty() ? nullptr : mapName(mCurrentElement.c_str());
+
+ // if we don't have a resource name then we don't know how to label the
+ // data and should abort.
+ if (resourceName == nullptr) {
+ resetCurrentElement();
+ return;
+ }
+
+ // Only count elements that contain "size"; other values just provide metadata.
+ auto sizeResult = mCurrentValues.find("size");
+ if (sizeResult != mCurrentValues.end() && sizeResult->second.value > 0) {
+ if (!mIsCurrentValueWrapped) {
+ mTotalSize.value += sizeResult->second.value;
+ mTotalSize.count++;
+ }
+ } else {
+ resetCurrentElement();
+ return;
+ }
+
+ // find the purgeable size if one exists
+ auto purgeableResult = mCurrentValues.find("purgeable_size");
+ if (!mIsCurrentValueWrapped && purgeableResult != mCurrentValues.end()) {
+ mPurgeableSize.value += purgeableResult->second.value;
+ mPurgeableSize.count++;
+ }
+
+ // do we store this element in the wrapped list or the skia managed list
+ auto& results = mIsCurrentValueWrapped ? mWrappedResults : mResults;
+
+ // insert a copy of the element and all of its keys. We must make a copy here instead of
+ // std::move() as we will continue to use these values later in the function and again
+ // when we move on to process the next element.
+ results.insert({mCurrentElement, mCurrentValues});
+
+ // insert the item into its mapped category
+ auto result = results.find(resourceName);
+ if (result != results.end()) {
+ auto& resourceValues = result->second;
+ auto totalResult = resourceValues.find(sizeResult->first);
+ if (totalResult != resourceValues.end()) {
+ ALOGE_IF(sizeResult->second.units != totalResult->second.units,
+ "resource units do not match so the sum of resource type (%s) will be invalid",
+ resourceName);
+ totalResult->second.value += sizeResult->second.value;
+ totalResult->second.count++;
+ } else {
+ ALOGE("an entry (%s) should not exist in the results without a size", resourceName);
+ }
+ } else {
+ // only store the size for the top level resource
+ results.insert({resourceName, {{sizeResult->first, sizeResult->second}}});
+ }
+
+ resetCurrentElement();
+}
+
+void SkiaMemoryReporter::dumpNumericValue(const char* dumpName, const char* valueName,
+ const char* units, uint64_t value) {
+ if (mCurrentElement != dumpName) {
+ processCurrentElement();
+ mCurrentElement = dumpName;
+ }
+ mCurrentValues.insert({valueName, {units, value}});
+}
+
+void SkiaMemoryReporter::dumpWrappedState(const char* dumpName, bool isWrappedObject) {
+ if (mCurrentElement != dumpName) {
+ processCurrentElement();
+ mCurrentElement = dumpName;
+ }
+ mIsCurrentValueWrapped = isWrappedObject;
+}
+
+void SkiaMemoryReporter::logOutput(std::string& log, bool wrappedResources) {
+ // process the current element before logging
+ processCurrentElement();
+
+ const auto& resultsMap = wrappedResources ? mWrappedResults : mResults;
+
+ // log each individual element based on the resource map
+ for (const auto& resourceCategory : mResourceMap) {
+ // find the named item and print the totals
+ const auto categoryItem = resultsMap.find(resourceCategory.second);
+ if (categoryItem != resultsMap.end()) {
+ auto result = categoryItem->second.find("size");
+ if (result != categoryItem->second.end()) {
+ TraceValue traceValue = convertUnits(result->second);
+ const char* entry = (traceValue.count > 1) ? "entries" : "entry";
+ StringAppendF(&log, " %s: %.2f %s (%d %s)\n", categoryItem->first.c_str(),
+ traceValue.value, traceValue.units, traceValue.count, entry);
+ }
+ if (mItemize) {
+ for (const auto& individualItem : resultsMap) {
+ // if the individual item matches the category then print all its details or
+ // in the case of wrapped resources just print the wrapped size
+ const char* categoryMatch = mapName(individualItem.first.c_str());
+ if (categoryMatch && strcmp(categoryMatch, resourceCategory.second) == 0) {
+ auto result = individualItem.second.find("size");
+ TraceValue size = convertUnits(result->second);
+ StringAppendF(&log, " %s: size[%.2f %s]", individualItem.first.c_str(),
+ size.value, size.units);
+ if (!wrappedResources) {
+ for (const auto& itemValues : individualItem.second) {
+ if (strcmp("size", itemValues.first) == 0) {
+ continue;
+ }
+ TraceValue traceValue = convertUnits(itemValues.second);
+ if (traceValue.value == 0.0f) {
+ StringAppendF(&log, " %s[%s]", itemValues.first,
+ traceValue.units);
+ } else {
+ StringAppendF(&log, " %s[%.2f %s]", itemValues.first,
+ traceValue.value, traceValue.units);
+ }
+ }
+ }
+ StringAppendF(&log, "\n");
+ }
+ }
+ }
+ }
+ }
+}
+
+void SkiaMemoryReporter::logTotals(std::string& log) {
+ // process the current element before logging
+ processCurrentElement();
+
+ TraceValue total = convertUnits(mTotalSize);
+ TraceValue purgeable = convertUnits(mPurgeableSize);
+ StringAppendF(&log, " %.0f bytes, %.2f %s (%.2f %s is purgeable)\n", mTotalSize.value,
+ total.value, total.units, purgeable.value, purgeable.units);
+}
+
+SkiaMemoryReporter::TraceValue SkiaMemoryReporter::convertUnits(const TraceValue& value) {
+ TraceValue output(value);
+ if (SkString("bytes") == SkString(output.units) && output.value >= 1024) {
+ output.value = output.value / 1024.0f;
+ output.units = "KB";
+ }
+ if (SkString("KB") == SkString(output.units) && output.value >= 1024) {
+ output.value = output.value / 1024.0f;
+ output.units = "MB";
+ }
+ return output;
+}
+
+} /* namespace skia */
+} /* namespace renderengine */
+} /* namespace android */
diff --git a/libs/renderengine/skia/debug/SkiaMemoryReporter.h b/libs/renderengine/skia/debug/SkiaMemoryReporter.h
new file mode 100644
index 0000000000..dbbd65b3da
--- /dev/null
+++ b/libs/renderengine/skia/debug/SkiaMemoryReporter.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2021 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 <SkTraceMemoryDump.h>
+
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+namespace android {
+namespace renderengine {
+namespace skia {
+
+// Mapping of resource substrings (1st element) that if found within a trace "dumpName"
+// should be mapped to the category name (2nd element). All char* used in a resourcePair
+// are expected to have a lifetime longer than the SkiaMemoryReporter in which they are used.
+typedef std::pair<const char*, const char*> ResourcePair;
+
+/*
+ * Utility class for logging the CPU/GPU usage of Skia caches in a format that is specific
+ * to RenderEngine. HWUI has a similar logging class, but the data collected and the way
+ * it is formatted and reported on are intended to be unique to each use case.
+ */
+class SkiaMemoryReporter : public SkTraceMemoryDump {
+public:
+ /**
+ * Creates the reporter class that can be populated by various Skia entry points, like
+ * SkGraphics and GrContext, as well as format and log the results.
+ * @param resourceMap An array of values that maps a Skia dumpName into a user defined category.
+ * The first vector entry that matches the dumpName is used for the mapping.
+ * @param itemize if true when logging the categories the individual elements will be printed
+ * directly after the category details are printed. Otherwise, only the category
+ * totals will be printed.
+ */
+ SkiaMemoryReporter(const std::vector<ResourcePair>& resourceMap, bool itemize);
+ ~SkiaMemoryReporter() override {}
+
+ void logOutput(std::string& log, bool wrappedResources = false);
+ void logTotals(std::string& log);
+
+ void dumpNumericValue(const char* dumpName, const char* valueName, const char* units,
+ uint64_t value) override;
+
+ void dumpStringValue(const char* dumpName, const char* valueName, const char* value) override {
+ // for convenience we just store this in the same format as numerical values
+ dumpNumericValue(dumpName, valueName, value, 0);
+ }
+ void dumpWrappedState(const char* dumpName, bool isWrappedObject) override;
+
+ LevelOfDetail getRequestedDetails() const override {
+ return SkTraceMemoryDump::kLight_LevelOfDetail;
+ }
+
+ bool shouldDumpWrappedObjects() const override { return true; }
+ void setMemoryBacking(const char*, const char*, const char*) override {}
+ void setDiscardableMemoryBacking(const char*, const SkDiscardableMemory&) override {}
+
+private:
+ struct TraceValue {
+ TraceValue(const char* units, uint64_t value) : units(units), value(value), count(1) {}
+ TraceValue(const TraceValue& v) : units(v.units), value(v.value), count(v.count) {}
+
+ const char* units;
+ float value;
+ int count;
+ };
+
+ const char* mapName(const char* resourceName);
+ void processCurrentElement();
+ void resetCurrentElement();
+ TraceValue convertUnits(const TraceValue& value);
+
+ const std::vector<ResourcePair>& mResourceMap;
+ const bool mItemize;
+
+ // variables storing the size of all non-wrapped elements being dumped
+ TraceValue mTotalSize;
+ TraceValue mPurgeableSize;
+
+ // variables storing information on the current node being dumped
+ std::string mCurrentElement;
+ std::unordered_map<const char*, TraceValue> mCurrentValues;
+ bool mIsCurrentValueWrapped = false;
+
+ // variable that stores the final format of the data after the individual elements are processed
+ std::unordered_map<std::string, std::unordered_map<const char*, TraceValue>> mResults;
+ std::unordered_map<std::string, std::unordered_map<const char*, TraceValue>> mWrappedResults;
+};
+
+} /* namespace skia */
+} /* namespace renderengine */
+} /* namespace android */ \ No newline at end of file
diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp
index 7846156383..34ef0a4f08 100644
--- a/libs/renderengine/tests/RenderEngineTest.cpp
+++ b/libs/renderengine/tests/RenderEngineTest.cpp
@@ -24,6 +24,7 @@
#include <cutils/properties.h>
#include <gtest/gtest.h>
+#include <renderengine/ExternalTexture.h>
#include <renderengine/RenderEngine.h>
#include <sync/sync.h>
#include <ui/PixelFormat.h>
@@ -160,27 +161,42 @@ public:
class RenderEngineTest : public ::testing::TestWithParam<std::shared_ptr<RenderEngineFactory>> {
public:
- static sp<GraphicBuffer> allocateDefaultBuffer() {
- return new GraphicBuffer(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT,
- HAL_PIXEL_FORMAT_RGBA_8888, 1,
- GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN |
- GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE,
- "output");
+ std::shared_ptr<renderengine::ExternalTexture> allocateDefaultBuffer() {
+ return std::make_shared<
+ renderengine::
+ ExternalTexture>(new GraphicBuffer(DEFAULT_DISPLAY_WIDTH,
+ DEFAULT_DISPLAY_HEIGHT,
+ HAL_PIXEL_FORMAT_RGBA_8888, 1,
+ GRALLOC_USAGE_SW_READ_OFTEN |
+ GRALLOC_USAGE_SW_WRITE_OFTEN |
+ GRALLOC_USAGE_HW_RENDER |
+ GRALLOC_USAGE_HW_TEXTURE,
+ "output"),
+ *mRE,
+ renderengine::ExternalTexture::Usage::READABLE |
+ renderengine::ExternalTexture::Usage::WRITEABLE);
}
// Allocates a 1x1 buffer to fill with a solid color
- static sp<GraphicBuffer> allocateSourceBuffer(uint32_t width, uint32_t height) {
- return new GraphicBuffer(width, height, HAL_PIXEL_FORMAT_RGBA_8888, 1,
- GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN |
- GRALLOC_USAGE_HW_TEXTURE,
- "input");
+ std::shared_ptr<renderengine::ExternalTexture> allocateSourceBuffer(uint32_t width,
+ uint32_t height) {
+ return std::make_shared<
+ renderengine::
+ ExternalTexture>(new GraphicBuffer(width, height,
+ HAL_PIXEL_FORMAT_RGBA_8888, 1,
+ GRALLOC_USAGE_SW_READ_OFTEN |
+ GRALLOC_USAGE_SW_WRITE_OFTEN |
+ GRALLOC_USAGE_HW_TEXTURE,
+ "input"),
+ *mRE,
+ renderengine::ExternalTexture::Usage::READABLE |
+ renderengine::ExternalTexture::Usage::WRITEABLE);
}
RenderEngineTest() {
const ::testing::TestInfo* const test_info =
::testing::UnitTest::GetInstance()->current_test_info();
ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
- mBuffer = allocateDefaultBuffer();
}
~RenderEngineTest() {
@@ -211,20 +227,21 @@ public:
}
uint8_t* pixels;
- mBuffer->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
- reinterpret_cast<void**>(&pixels));
+ mBuffer->getBuffer()->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
+ reinterpret_cast<void**>(&pixels));
file << "P6\n";
- file << mBuffer->getWidth() << "\n";
- file << mBuffer->getHeight() << "\n";
+ file << mBuffer->getBuffer()->getWidth() << "\n";
+ file << mBuffer->getBuffer()->getHeight() << "\n";
file << 255 << "\n";
- std::vector<uint8_t> outBuffer(mBuffer->getWidth() * mBuffer->getHeight() * 3);
+ std::vector<uint8_t> outBuffer(mBuffer->getBuffer()->getWidth() *
+ mBuffer->getBuffer()->getHeight() * 3);
auto outPtr = reinterpret_cast<uint8_t*>(outBuffer.data());
- for (int32_t j = 0; j < mBuffer->getHeight(); j++) {
- const uint8_t* src = pixels + (mBuffer->getStride() * j) * 4;
- for (int32_t i = 0; i < mBuffer->getWidth(); i++) {
+ for (int32_t j = 0; j < mBuffer->getBuffer()->getHeight(); j++) {
+ const uint8_t* src = pixels + (mBuffer->getBuffer()->getStride() * j) * 4;
+ for (int32_t i = 0; i < mBuffer->getBuffer()->getWidth(); i++) {
// Only copy R, G and B components
outPtr[0] = src[0];
outPtr[1] = src[1];
@@ -235,7 +252,7 @@ public:
}
}
file.write(reinterpret_cast<char*>(outBuffer.data()), outBuffer.size());
- mBuffer->unlock();
+ mBuffer->getBuffer()->unlock();
}
void expectBufferColor(const Region& region, uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
@@ -262,13 +279,13 @@ public:
void expectBufferColor(const Rect& region, uint8_t r, uint8_t g, uint8_t b, uint8_t a,
std::function<bool(const uint8_t* a, const uint8_t* b)> colorCompare) {
uint8_t* pixels;
- mBuffer->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
- reinterpret_cast<void**>(&pixels));
+ mBuffer->getBuffer()->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
+ reinterpret_cast<void**>(&pixels));
int32_t maxFails = 10;
int32_t fails = 0;
for (int32_t j = 0; j < region.getHeight(); j++) {
- const uint8_t* src =
- pixels + (mBuffer->getStride() * (region.top + j) + region.left) * 4;
+ const uint8_t* src = pixels +
+ (mBuffer->getBuffer()->getStride() * (region.top + j) + region.left) * 4;
for (int32_t i = 0; i < region.getWidth(); i++) {
const uint8_t expected[4] = {r, g, b, a};
bool equal = colorCompare(src, expected);
@@ -289,7 +306,7 @@ public:
break;
}
}
- mBuffer->unlock();
+ mBuffer->getBuffer()->unlock();
}
void expectAlpha(const Rect& rect, uint8_t a) {
@@ -387,7 +404,6 @@ public:
base::unique_fd fence;
status_t status =
mRE->drawLayers(settings, layers, mBuffer, true, base::unique_fd(), &fence);
- mCurrentBuffer = mBuffer;
int fd = fence.release();
if (fd >= 0) {
@@ -397,7 +413,7 @@ public:
ASSERT_EQ(NO_ERROR, status);
if (layers.size() > 0 && mGLESRE != nullptr) {
- ASSERT_TRUE(mGLESRE->isFramebufferImageCachedForTesting(mBuffer->getId()));
+ ASSERT_TRUE(mGLESRE->isFramebufferImageCachedForTesting(mBuffer->getBuffer()->getId()));
}
}
@@ -503,17 +519,11 @@ public:
void initializeRenderEngine();
std::unique_ptr<renderengine::RenderEngine> mRE;
+ std::shared_ptr<renderengine::ExternalTexture> mBuffer;
// GLESRenderEngine for testing GLES-specific behavior.
// Owened by mRE, but this is downcasted.
renderengine::gl::GLESRenderEngine* mGLESRE = nullptr;
- // Dumb hack to avoid NPE in the EGL driver: the GraphicBuffer needs to
- // be freed *after* RenderEngine is destroyed, so that the EGL image is
- // destroyed first.
- sp<GraphicBuffer> mCurrentBuffer;
-
- sp<GraphicBuffer> mBuffer;
-
std::vector<uint32_t> mTexNames;
};
@@ -530,6 +540,7 @@ void RenderEngineTest::initializeRenderEngine() {
} else {
mRE = renderEngineFactory->createRenderEngine();
}
+ mBuffer = allocateDefaultBuffer();
}
struct ColorSourceVariant {
@@ -566,18 +577,18 @@ template <typename OpaquenessVariant>
struct BufferSourceVariant {
static void fillColor(renderengine::LayerSettings& layer, half r, half g, half b,
RenderEngineTest* fixture) {
- sp<GraphicBuffer> buf = RenderEngineTest::allocateSourceBuffer(1, 1);
+ const auto buf = fixture->allocateSourceBuffer(1, 1);
uint32_t texName;
fixture->mRE->genTextures(1, &texName);
fixture->mTexNames.push_back(texName);
uint8_t* pixels;
- buf->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
- reinterpret_cast<void**>(&pixels));
+ buf->getBuffer()->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
+ reinterpret_cast<void**>(&pixels));
- for (int32_t j = 0; j < buf->getHeight(); j++) {
- uint8_t* iter = pixels + (buf->getStride() * j) * 4;
- for (int32_t i = 0; i < buf->getWidth(); i++) {
+ for (int32_t j = 0; j < buf->getBuffer()->getHeight(); j++) {
+ uint8_t* iter = pixels + (buf->getBuffer()->getStride() * j) * 4;
+ for (int32_t i = 0; i < buf->getBuffer()->getWidth(); i++) {
iter[0] = uint8_t(r * 255);
iter[1] = uint8_t(g * 255);
iter[2] = uint8_t(b * 255);
@@ -586,7 +597,7 @@ struct BufferSourceVariant {
}
}
- buf->unlock();
+ buf->getBuffer()->unlock();
layer.source.buffer.buffer = buf;
layer.source.buffer.textureName = texName;
@@ -1012,14 +1023,14 @@ void RenderEngineTest::fillRedBufferTextureTransform() {
layer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR;
// Here will allocate a checker board texture, but transform texture
// coordinates so that only the upper left is applied.
- sp<GraphicBuffer> buf = allocateSourceBuffer(2, 2);
+ const auto buf = allocateSourceBuffer(2, 2);
uint32_t texName;
RenderEngineTest::mRE->genTextures(1, &texName);
this->mTexNames.push_back(texName);
uint8_t* pixels;
- buf->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
- reinterpret_cast<void**>(&pixels));
+ buf->getBuffer()->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
+ reinterpret_cast<void**>(&pixels));
// Red top left, Green top right, Blue bottom left, Black bottom right
pixels[0] = 255;
pixels[1] = 0;
@@ -1033,7 +1044,7 @@ void RenderEngineTest::fillRedBufferTextureTransform() {
pixels[9] = 0;
pixels[10] = 255;
pixels[11] = 255;
- buf->unlock();
+ buf->getBuffer()->unlock();
layer.source.buffer.buffer = buf;
layer.source.buffer.textureName = texName;
@@ -1061,19 +1072,19 @@ void RenderEngineTest::fillRedBufferWithPremultiplyAlpha() {
std::vector<const renderengine::LayerSettings*> layers;
renderengine::LayerSettings layer;
- sp<GraphicBuffer> buf = allocateSourceBuffer(1, 1);
+ const auto buf = allocateSourceBuffer(1, 1);
uint32_t texName;
RenderEngineTest::mRE->genTextures(1, &texName);
this->mTexNames.push_back(texName);
uint8_t* pixels;
- buf->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
- reinterpret_cast<void**>(&pixels));
+ buf->getBuffer()->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
+ reinterpret_cast<void**>(&pixels));
pixels[0] = 255;
pixels[1] = 0;
pixels[2] = 0;
pixels[3] = 255;
- buf->unlock();
+ buf->getBuffer()->unlock();
layer.source.buffer.buffer = buf;
layer.source.buffer.textureName = texName;
@@ -1100,19 +1111,19 @@ void RenderEngineTest::fillRedBufferWithoutPremultiplyAlpha() {
std::vector<const renderengine::LayerSettings*> layers;
renderengine::LayerSettings layer;
- sp<GraphicBuffer> buf = allocateSourceBuffer(1, 1);
+ const auto buf = allocateSourceBuffer(1, 1);
uint32_t texName;
RenderEngineTest::mRE->genTextures(1, &texName);
this->mTexNames.push_back(texName);
uint8_t* pixels;
- buf->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
- reinterpret_cast<void**>(&pixels));
+ buf->getBuffer()->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
+ reinterpret_cast<void**>(&pixels));
pixels[0] = 255;
pixels[1] = 0;
pixels[2] = 0;
pixels[3] = 255;
- buf->unlock();
+ buf->getBuffer()->unlock();
layer.source.buffer.buffer = buf;
layer.source.buffer.textureName = texName;
@@ -1233,8 +1244,7 @@ TEST_P(RenderEngineTest, drawLayers_noLayersToDraw) {
}
TEST_P(RenderEngineTest, drawLayers_withoutBuffers_withColorTransform) {
- const auto& renderEngineFactory = GetParam();
- mRE = renderEngineFactory->createRenderEngine();
+ initializeRenderEngine();
renderengine::DisplaySettings settings;
settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR;
@@ -1295,7 +1305,6 @@ TEST_P(RenderEngineTest, drawLayers_nullOutputFence) {
layers.push_back(&layer);
status_t status = mRE->drawLayers(settings, layers, mBuffer, true, base::unique_fd(), nullptr);
- mCurrentBuffer = mBuffer;
ASSERT_EQ(NO_ERROR, status);
expectBufferColor(fullscreenRect(), 255, 0, 0, 255);
}
@@ -1323,9 +1332,8 @@ TEST_P(RenderEngineTest, drawLayers_doesNotCacheFramebuffer) {
layers.push_back(&layer);
status_t status = mRE->drawLayers(settings, layers, mBuffer, false, base::unique_fd(), nullptr);
- mCurrentBuffer = mBuffer;
ASSERT_EQ(NO_ERROR, status);
- ASSERT_FALSE(mGLESRE->isFramebufferImageCachedForTesting(mBuffer->getId()));
+ ASSERT_FALSE(mGLESRE->isFramebufferImageCachedForTesting(mBuffer->getBuffer()->getId()));
expectBufferColor(fullscreenRect(), 255, 0, 0, 255);
}
@@ -1394,7 +1402,8 @@ TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransformZeroLayerAlpha_color
fillBufferColorTransformZeroLayerAlpha<ColorSourceVariant>();
}
-TEST_P(RenderEngineTest, drawLayers_fillBufferAndBlurBackground_colorSource) {
+// TODO(b/186010146): reenable once swiftshader is happy with this test
+TEST_P(RenderEngineTest, DISABLED_drawLayers_fillBufferAndBlurBackground_colorSource) {
initializeRenderEngine();
fillBufferAndBlurBackground<ColorSourceVariant>();
}
@@ -1469,7 +1478,8 @@ TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransformZeroLayerAlpha_opaqu
fillBufferColorTransformZeroLayerAlpha<BufferSourceVariant<ForceOpaqueBufferVariant>>();
}
-TEST_P(RenderEngineTest, drawLayers_fillBufferAndBlurBackground_opaqueBufferSource) {
+// TODO(b/186010146): reenable once swiftshader is happy with this test
+TEST_P(RenderEngineTest, DISABLED_drawLayers_fillBufferAndBlurBackground_opaqueBufferSource) {
initializeRenderEngine();
fillBufferAndBlurBackground<BufferSourceVariant<ForceOpaqueBufferVariant>>();
}
@@ -1544,7 +1554,8 @@ TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransformZeroLayerAlpha_buffe
fillBufferColorTransformZeroLayerAlpha<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
}
-TEST_P(RenderEngineTest, drawLayers_fillBufferAndBlurBackground_bufferSource) {
+// TODO(b/186010146): reenable once swiftshader is happy with this test
+TEST_P(RenderEngineTest, DISABLED_drawLayers_fillBufferAndBlurBackground_bufferSource) {
initializeRenderEngine();
fillBufferAndBlurBackground<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
}
@@ -1574,98 +1585,6 @@ TEST_P(RenderEngineTest, drawLayers_clearRegion) {
clearRegion();
}
-TEST_P(RenderEngineTest, drawLayers_fillsBufferAndCachesImages) {
- const auto& renderEngineFactory = GetParam();
-
- if (renderEngineFactory->type() != renderengine::RenderEngine::RenderEngineType::GLES) {
- // GLES-specific test
- return;
- }
-
- initializeRenderEngine();
-
- renderengine::DisplaySettings settings;
- settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR;
- settings.physicalDisplay = fullscreenRect();
- settings.clip = fullscreenRect();
-
- std::vector<const renderengine::LayerSettings*> layers;
-
- renderengine::LayerSettings layer;
- layer.geometry.boundaries = fullscreenRect().toFloatRect();
- BufferSourceVariant<ForceOpaqueBufferVariant>::fillColor(layer, 1.0f, 0.0f, 0.0f, this);
-
- layers.push_back(&layer);
- invokeDraw(settings, layers);
- uint64_t bufferId = layer.source.buffer.buffer->getId();
- EXPECT_TRUE(mGLESRE->isImageCachedForTesting(bufferId));
- std::shared_ptr<renderengine::gl::ImageManager::Barrier> barrier =
- mGLESRE->unbindExternalTextureBufferForTesting(bufferId);
- std::lock_guard<std::mutex> lock(barrier->mutex);
- ASSERT_TRUE(barrier->condition.wait_for(barrier->mutex, std::chrono::seconds(5),
- [&]() REQUIRES(barrier->mutex) {
- return barrier->isOpen;
- }));
- EXPECT_FALSE(mGLESRE->isImageCachedForTesting(bufferId));
- EXPECT_EQ(NO_ERROR, barrier->result);
-}
-
-TEST_P(RenderEngineTest, cacheExternalBuffer_withNullBuffer) {
- const auto& renderEngineFactory = GetParam();
-
- if (renderEngineFactory->type() != renderengine::RenderEngine::RenderEngineType::GLES) {
- // GLES-specific test
- return;
- }
-
- initializeRenderEngine();
-
- std::shared_ptr<renderengine::gl::ImageManager::Barrier> barrier =
- mGLESRE->cacheExternalTextureBufferForTesting(nullptr);
- std::lock_guard<std::mutex> lock(barrier->mutex);
- ASSERT_TRUE(barrier->condition.wait_for(barrier->mutex, std::chrono::seconds(5),
- [&]() REQUIRES(barrier->mutex) {
- return barrier->isOpen;
- }));
- EXPECT_TRUE(barrier->isOpen);
- EXPECT_EQ(BAD_VALUE, barrier->result);
-}
-
-TEST_P(RenderEngineTest, cacheExternalBuffer_cachesImages) {
- const auto& renderEngineFactory = GetParam();
-
- if (renderEngineFactory->type() != renderengine::RenderEngine::RenderEngineType::GLES) {
- // GLES-specific test
- return;
- }
-
- initializeRenderEngine();
-
- sp<GraphicBuffer> buf = allocateSourceBuffer(1, 1);
- uint64_t bufferId = buf->getId();
- std::shared_ptr<renderengine::gl::ImageManager::Barrier> barrier =
- mGLESRE->cacheExternalTextureBufferForTesting(buf);
- {
- std::lock_guard<std::mutex> lock(barrier->mutex);
- ASSERT_TRUE(barrier->condition.wait_for(barrier->mutex, std::chrono::seconds(5),
- [&]() REQUIRES(barrier->mutex) {
- return barrier->isOpen;
- }));
- EXPECT_EQ(NO_ERROR, barrier->result);
- }
- EXPECT_TRUE(mGLESRE->isImageCachedForTesting(bufferId));
- barrier = mGLESRE->unbindExternalTextureBufferForTesting(bufferId);
- {
- std::lock_guard<std::mutex> lock(barrier->mutex);
- ASSERT_TRUE(barrier->condition.wait_for(barrier->mutex, std::chrono::seconds(5),
- [&]() REQUIRES(barrier->mutex) {
- return barrier->isOpen;
- }));
- EXPECT_EQ(NO_ERROR, barrier->result);
- }
- EXPECT_FALSE(mGLESRE->isImageCachedForTesting(bufferId));
-}
-
TEST_P(RenderEngineTest, drawLayers_fillShadow_castsWithoutCasterLayer) {
initializeRenderEngine();
@@ -1858,7 +1777,7 @@ TEST_P(RenderEngineTest, cleanupPostRender_whenCleaningAll_replacesTextureMemory
sync_wait(fd, -1);
}
- uint64_t bufferId = layer.source.buffer.buffer->getId();
+ uint64_t bufferId = layer.source.buffer.buffer->getBuffer()->getId();
uint32_t texName = layer.source.buffer.textureName;
EXPECT_TRUE(mGLESRE->isImageCachedForTesting(bufferId));
EXPECT_EQ(bufferId, mGLESRE->getBufferIdForTextureNameForTesting(texName));
@@ -1966,16 +1885,16 @@ TEST_P(RenderEngineTest, testDisableBlendingBuffer) {
// The next layer will overwrite redLayer with a GraphicBuffer that is green
// applied with a translucent alpha.
- auto buf = allocateSourceBuffer(1, 1);
+ const auto buf = allocateSourceBuffer(1, 1);
{
uint8_t* pixels;
- buf->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
- reinterpret_cast<void**>(&pixels));
+ buf->getBuffer()->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
+ reinterpret_cast<void**>(&pixels));
pixels[0] = 0;
pixels[1] = 255;
pixels[2] = 0;
pixels[3] = 255;
- buf->unlock();
+ buf->getBuffer()->unlock();
}
const renderengine::LayerSettings greenLayer{
diff --git a/libs/renderengine/tests/RenderEngineThreadedTest.cpp b/libs/renderengine/tests/RenderEngineThreadedTest.cpp
index 63aa4c891c..e3917cce09 100644
--- a/libs/renderengine/tests/RenderEngineThreadedTest.cpp
+++ b/libs/renderengine/tests/RenderEngineThreadedTest.cpp
@@ -49,6 +49,9 @@ TEST_F(RenderEngineThreadedTest, dump) {
TEST_F(RenderEngineThreadedTest, primeCache) {
EXPECT_CALL(*mRenderEngine, primeCache());
mThreadedRE->primeCache();
+ // need to call ANY synchronous function after primeCache to ensure that primeCache has
+ // completed asynchronously before the test completes execution.
+ mThreadedRE->getContextPriority();
}
TEST_F(RenderEngineThreadedTest, genTextures) {
@@ -159,15 +162,18 @@ TEST_F(RenderEngineThreadedTest, supportsBackgroundBlur_returnsTrue) {
TEST_F(RenderEngineThreadedTest, drawLayers) {
renderengine::DisplaySettings settings;
std::vector<const renderengine::LayerSettings*> layers;
- sp<GraphicBuffer> buffer = new GraphicBuffer();
+ std::shared_ptr<renderengine::ExternalTexture> buffer = std::make_shared<
+ renderengine::ExternalTexture>(new GraphicBuffer(), *mRenderEngine,
+ renderengine::ExternalTexture::Usage::READABLE |
+ renderengine::ExternalTexture::Usage::WRITEABLE);
base::unique_fd bufferFence;
base::unique_fd drawFence;
EXPECT_CALL(*mRenderEngine, drawLayers)
.WillOnce([](const renderengine::DisplaySettings&,
const std::vector<const renderengine::LayerSettings*>&,
- const sp<GraphicBuffer>&, const bool, base::unique_fd&&,
- base::unique_fd*) -> status_t { return NO_ERROR; });
+ const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
+ base::unique_fd&&, base::unique_fd*) -> status_t { return NO_ERROR; });
status_t result = mThreadedRE->drawLayers(settings, layers, buffer, false,
std::move(bufferFence), &drawFence);
diff --git a/libs/renderengine/threaded/RenderEngineThreaded.cpp b/libs/renderengine/threaded/RenderEngineThreaded.cpp
index 9c0b3e508b..d02a58fd9e 100644
--- a/libs/renderengine/threaded/RenderEngineThreaded.cpp
+++ b/libs/renderengine/threaded/RenderEngineThreaded.cpp
@@ -74,6 +74,12 @@ void RenderEngineThreaded::threadMain(CreateInstanceFactory factory) NO_THREAD_S
std::unique_lock<std::mutex> lock(mThreadMutex);
pthread_setname_np(pthread_self(), mThreadName);
+ {
+ std::unique_lock<std::mutex> lock(mInitializedMutex);
+ mIsInitialized = true;
+ }
+ mInitializedCondition.notify_all();
+
while (mRunning) {
if (!mFunctionCalls.empty()) {
auto task = mFunctionCalls.front();
@@ -84,21 +90,27 @@ void RenderEngineThreaded::threadMain(CreateInstanceFactory factory) NO_THREAD_S
return !mRunning || !mFunctionCalls.empty();
});
}
+
+ // we must release the RenderEngine on the thread that created it
+ mRenderEngine.reset();
+}
+
+void RenderEngineThreaded::waitUntilInitialized() const {
+ std::unique_lock<std::mutex> lock(mInitializedMutex);
+ mInitializedCondition.wait(lock, [=] { return mIsInitialized; });
}
void RenderEngineThreaded::primeCache() {
- std::promise<void> resultPromise;
- std::future<void> resultFuture = resultPromise.get_future();
+ // This function is designed so it can run asynchronously, so we do not need to wait
+ // for the futures.
{
std::lock_guard lock(mThreadMutex);
- mFunctionCalls.push([&resultPromise](renderengine::RenderEngine& instance) {
+ mFunctionCalls.push([](renderengine::RenderEngine& instance) {
ATRACE_NAME("REThreaded::primeCache");
instance.primeCache();
- resultPromise.set_value();
});
}
mCondition.notify_one();
- resultFuture.wait();
}
void RenderEngineThreaded::dump(std::string& result) {
@@ -148,90 +160,54 @@ void RenderEngineThreaded::deleteTextures(size_t count, uint32_t const* names) {
resultFuture.wait();
}
-void RenderEngineThreaded::cacheExternalTextureBuffer(const sp<GraphicBuffer>& buffer) {
+void RenderEngineThreaded::mapExternalTextureBuffer(const sp<GraphicBuffer>& buffer,
+ bool isRenderable) {
// This function is designed so it can run asynchronously, so we do not need to wait
// for the futures.
{
std::lock_guard lock(mThreadMutex);
mFunctionCalls.push([=](renderengine::RenderEngine& instance) {
- ATRACE_NAME("REThreaded::cacheExternalTextureBuffer");
- instance.cacheExternalTextureBuffer(buffer);
+ ATRACE_NAME("REThreaded::mapExternalTextureBuffer");
+ instance.mapExternalTextureBuffer(buffer, isRenderable);
});
}
mCondition.notify_one();
}
-void RenderEngineThreaded::unbindExternalTextureBuffer(uint64_t bufferId) {
+void RenderEngineThreaded::unmapExternalTextureBuffer(const sp<GraphicBuffer>& buffer) {
// This function is designed so it can run asynchronously, so we do not need to wait
// for the futures.
{
std::lock_guard lock(mThreadMutex);
mFunctionCalls.push([=](renderengine::RenderEngine& instance) {
- ATRACE_NAME("REThreaded::unbindExternalTextureBuffer");
- instance.unbindExternalTextureBuffer(bufferId);
+ ATRACE_NAME("REThreaded::unmapExternalTextureBuffer");
+ instance.unmapExternalTextureBuffer(buffer);
});
}
mCondition.notify_one();
}
size_t RenderEngineThreaded::getMaxTextureSize() const {
- std::promise<size_t> resultPromise;
- std::future<size_t> resultFuture = resultPromise.get_future();
- {
- std::lock_guard lock(mThreadMutex);
- mFunctionCalls.push([&resultPromise](renderengine::RenderEngine& instance) {
- ATRACE_NAME("REThreaded::getMaxTextureSize");
- size_t size = instance.getMaxTextureSize();
- resultPromise.set_value(size);
- });
- }
- mCondition.notify_one();
- return resultFuture.get();
+ waitUntilInitialized();
+ return mRenderEngine->getMaxTextureSize();
}
size_t RenderEngineThreaded::getMaxViewportDims() const {
- std::promise<size_t> resultPromise;
- std::future<size_t> resultFuture = resultPromise.get_future();
- {
- std::lock_guard lock(mThreadMutex);
- mFunctionCalls.push([&resultPromise](renderengine::RenderEngine& instance) {
- ATRACE_NAME("REThreaded::getMaxViewportDims");
- size_t size = instance.getMaxViewportDims();
- resultPromise.set_value(size);
- });
- }
- mCondition.notify_one();
- return resultFuture.get();
+ waitUntilInitialized();
+ return mRenderEngine->getMaxViewportDims();
}
bool RenderEngineThreaded::isProtected() const {
- std::promise<bool> resultPromise;
- std::future<bool> resultFuture = resultPromise.get_future();
- {
- std::lock_guard lock(mThreadMutex);
- mFunctionCalls.push([&resultPromise](renderengine::RenderEngine& instance) {
- ATRACE_NAME("REThreaded::isProtected");
- bool returnValue = instance.isProtected();
- resultPromise.set_value(returnValue);
- });
- }
- mCondition.notify_one();
- return resultFuture.get();
+ waitUntilInitialized();
+ // ensure that useProtectedContext is not currently being changed by some
+ // other thread.
+ std::lock_guard lock(mThreadMutex);
+ return mRenderEngine->isProtected();
}
bool RenderEngineThreaded::supportsProtectedContent() const {
- std::promise<bool> resultPromise;
- std::future<bool> resultFuture = resultPromise.get_future();
- {
- std::lock_guard lock(mThreadMutex);
- mFunctionCalls.push([&resultPromise](renderengine::RenderEngine& instance) {
- ATRACE_NAME("REThreaded::supportsProtectedContent");
- bool returnValue = instance.supportsProtectedContent();
- resultPromise.set_value(returnValue);
- });
- }
- mCondition.notify_one();
- return resultFuture.get();
+ waitUntilInitialized();
+ return mRenderEngine->supportsProtectedContent();
}
bool RenderEngineThreaded::useProtectedContext(bool useProtectedContext) {
@@ -282,7 +258,7 @@ void RenderEngineThreaded::setViewportAndProjection(Rect viewPort, Rect sourceCr
status_t RenderEngineThreaded::drawLayers(const DisplaySettings& display,
const std::vector<const LayerSettings*>& layers,
- const sp<GraphicBuffer>& buffer,
+ const std::shared_ptr<ExternalTexture>& buffer,
const bool useFramebufferCache,
base::unique_fd&& bufferFence,
base::unique_fd* drawFence) {
@@ -303,18 +279,16 @@ status_t RenderEngineThreaded::drawLayers(const DisplaySettings& display,
}
void RenderEngineThreaded::cleanFramebufferCache() {
- std::promise<void> resultPromise;
- std::future<void> resultFuture = resultPromise.get_future();
+ // This function is designed so it can run asynchronously, so we do not need to wait
+ // for the futures.
{
std::lock_guard lock(mThreadMutex);
- mFunctionCalls.push([&resultPromise](renderengine::RenderEngine& instance) {
+ mFunctionCalls.push([](renderengine::RenderEngine& instance) {
ATRACE_NAME("REThreaded::cleanFramebufferCache");
instance.cleanFramebufferCache();
- resultPromise.set_value();
});
}
mCondition.notify_one();
- resultFuture.wait();
}
int RenderEngineThreaded::getContextPriority() {
@@ -333,33 +307,21 @@ int RenderEngineThreaded::getContextPriority() {
}
bool RenderEngineThreaded::supportsBackgroundBlur() {
- std::promise<bool> resultPromise;
- std::future<bool> resultFuture = resultPromise.get_future();
- {
- std::lock_guard lock(mThreadMutex);
- mFunctionCalls.push([&resultPromise](renderengine::RenderEngine& instance) {
- ATRACE_NAME("REThreaded::supportsBackgroundBlur");
- bool returnValue = instance.supportsBackgroundBlur();
- resultPromise.set_value(returnValue);
- });
- }
- mCondition.notify_one();
- return resultFuture.get();
+ waitUntilInitialized();
+ return mRenderEngine->supportsBackgroundBlur();
}
void RenderEngineThreaded::onPrimaryDisplaySizeChanged(ui::Size size) {
- std::promise<void> resultPromise;
- std::future<void> resultFuture = resultPromise.get_future();
+ // This function is designed so it can run asynchronously, so we do not need to wait
+ // for the futures.
{
std::lock_guard lock(mThreadMutex);
- mFunctionCalls.push([&resultPromise, size](renderengine::RenderEngine& instance) {
+ mFunctionCalls.push([size](renderengine::RenderEngine& instance) {
ATRACE_NAME("REThreaded::onPrimaryDisplaySizeChanged");
instance.onPrimaryDisplaySizeChanged(size);
- resultPromise.set_value();
});
}
mCondition.notify_one();
- resultFuture.wait();
}
} // namespace threaded
diff --git a/libs/renderengine/threaded/RenderEngineThreaded.h b/libs/renderengine/threaded/RenderEngineThreaded.h
index 352c1e0694..285627e8be 100644
--- a/libs/renderengine/threaded/RenderEngineThreaded.h
+++ b/libs/renderengine/threaded/RenderEngineThreaded.h
@@ -48,8 +48,6 @@ public:
void genTextures(size_t count, uint32_t* names) override;
void deleteTextures(size_t count, uint32_t const* names) override;
- void cacheExternalTextureBuffer(const sp<GraphicBuffer>& buffer) override;
- void unbindExternalTextureBuffer(uint64_t bufferId) override;
size_t getMaxTextureSize() const override;
size_t getMaxViewportDims() const override;
@@ -61,16 +59,22 @@ public:
status_t drawLayers(const DisplaySettings& display,
const std::vector<const LayerSettings*>& layers,
- const sp<GraphicBuffer>& buffer, const bool useFramebufferCache,
- base::unique_fd&& bufferFence, base::unique_fd* drawFence) override;
+ const std::shared_ptr<ExternalTexture>& buffer,
+ const bool useFramebufferCache, base::unique_fd&& bufferFence,
+ base::unique_fd* drawFence) override;
void cleanFramebufferCache() override;
int getContextPriority() override;
bool supportsBackgroundBlur() override;
void onPrimaryDisplaySizeChanged(ui::Size size) override;
+protected:
+ void mapExternalTextureBuffer(const sp<GraphicBuffer>& buffer, bool isRenderable) override;
+ void unmapExternalTextureBuffer(const sp<GraphicBuffer>& buffer) override;
+
private:
void threadMain(CreateInstanceFactory factory);
+ void waitUntilInitialized() const;
/* ------------------------------------------------------------------------
* Threading
@@ -84,6 +88,12 @@ private:
GUARDED_BY(mThreadMutex);
mutable std::condition_variable mCondition;
+ // Used to allow select thread safe methods to be accessed without requiring the
+ // method to be invoked on the RenderEngine thread
+ bool mIsInitialized = false;
+ mutable std::mutex mInitializedMutex;
+ mutable std::condition_variable mInitializedCondition;
+
/* ------------------------------------------------------------------------
* Render Engine
*/
diff --git a/libs/sensor/Android.bp b/libs/sensor/Android.bp
index 497c33c386..edd453a936 100644
--- a/libs/sensor/Android.bp
+++ b/libs/sensor/Android.bp
@@ -48,11 +48,10 @@ cc_library_shared {
"libutils",
"liblog",
"libhardware",
+ "libpermission",
],
export_include_dirs: ["include"],
- export_shared_lib_headers: ["libbinder", "libhardware"],
+ export_shared_lib_headers: ["libbinder", "libpermission", "libhardware"],
}
-
-subdirs = ["tests"]
diff --git a/libs/sensorprivacy/SensorPrivacyManager.cpp b/libs/sensorprivacy/SensorPrivacyManager.cpp
index 47144696f2..b3537ce444 100644
--- a/libs/sensorprivacy/SensorPrivacyManager.cpp
+++ b/libs/sensorprivacy/SensorPrivacyManager.cpp
@@ -55,6 +55,22 @@ sp<hardware::ISensorPrivacyManager> SensorPrivacyManager::getService()
return service;
}
+bool SensorPrivacyManager::supportsSensorToggle(int sensor) {
+ if (mSupportedCache.find(sensor) == mSupportedCache.end()) {
+ sp<hardware::ISensorPrivacyManager> service = getService();
+ if (service != nullptr) {
+ bool result;
+ service->supportsSensorToggle(sensor, &result);
+ mSupportedCache[sensor] = result;
+ return result;
+ }
+ // if the SensorPrivacyManager is not available then assume sensor privacy feature isn't
+ // supported
+ return false;
+ }
+ return mSupportedCache[sensor];
+}
+
void SensorPrivacyManager::addSensorPrivacyListener(
const sp<hardware::ISensorPrivacyListener>& listener)
{
diff --git a/libs/sensorprivacy/aidl/android/hardware/ISensorPrivacyManager.aidl b/libs/sensorprivacy/aidl/android/hardware/ISensorPrivacyManager.aidl
index 629b8c2093..c8ceeb89af 100644
--- a/libs/sensorprivacy/aidl/android/hardware/ISensorPrivacyManager.aidl
+++ b/libs/sensorprivacy/aidl/android/hardware/ISensorPrivacyManager.aidl
@@ -20,6 +20,8 @@ import android.hardware.ISensorPrivacyListener;
/** @hide */
interface ISensorPrivacyManager {
+ boolean supportsSensorToggle(int sensor);
+
void addSensorPrivacyListener(in ISensorPrivacyListener listener);
void addIndividualSensorPrivacyListener(int userId, int sensor, in ISensorPrivacyListener listener);
diff --git a/libs/sensorprivacy/include/sensorprivacy/SensorPrivacyManager.h b/libs/sensorprivacy/include/sensorprivacy/SensorPrivacyManager.h
index 12778e16b6..fb4cbe9d55 100644
--- a/libs/sensorprivacy/include/sensorprivacy/SensorPrivacyManager.h
+++ b/libs/sensorprivacy/include/sensorprivacy/SensorPrivacyManager.h
@@ -22,6 +22,8 @@
#include <utils/threads.h>
+#include <unordered_map>
+
// ---------------------------------------------------------------------------
namespace android {
@@ -35,6 +37,7 @@ public:
SensorPrivacyManager();
+ bool supportsSensorToggle(int sensor);
void addSensorPrivacyListener(const sp<hardware::ISensorPrivacyListener>& listener);
status_t addIndividualSensorPrivacyListener(int userId, int sensor,
const sp<hardware::ISensorPrivacyListener>& listener);
@@ -50,6 +53,8 @@ private:
Mutex mLock;
sp<hardware::ISensorPrivacyManager> mService;
sp<hardware::ISensorPrivacyManager> getService();
+
+ std::unordered_map<int, bool> mSupportedCache;
};
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 073455a7ff..edbf21aef4 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -2326,6 +2326,8 @@ void InputDispatcher::finishDragAndDrop(int32_t displayId, float x, float y) {
if (dropWindow) {
vec2 local = dropWindow->getInfo()->transform.transform(x, y);
notifyDropWindowLocked(dropWindow->getToken(), local.x, local.y);
+ } else {
+ notifyDropWindowLocked(nullptr, 0, 0);
}
mDragState.reset();
}
@@ -2372,6 +2374,7 @@ void InputDispatcher::addDragEventLocked(const MotionEntry& entry) {
} else if (maskedAction == AMOTION_EVENT_ACTION_UP) {
finishDragAndDrop(entry.displayId, x, y);
} else if (maskedAction == AMOTION_EVENT_ACTION_CANCEL) {
+ notifyDropWindowLocked(nullptr, 0, 0);
mDragState.reset();
}
}
@@ -3154,8 +3157,9 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
ALOGE("channel '%s' ~ Could not publish event because the pipe is full. "
"This is unexpected because the wait queue is empty, so the pipe "
"should be empty and we shouldn't have any problems writing an "
- "event to it, status=%d",
- connection->getInputChannelName().c_str(), status);
+ "event to it, status=%s(%d)",
+ connection->getInputChannelName().c_str(), statusToString(status).c_str(),
+ status);
abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/);
} else {
// Pipe is full and we are waiting for the app to finish process some events
@@ -3168,8 +3172,9 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
}
} else {
ALOGE("channel '%s' ~ Could not publish event due to an unexpected error, "
- "status=%d",
- connection->getInputChannelName().c_str(), status);
+ "status=%s(%d)",
+ connection->getInputChannelName().c_str(), statusToString(status).c_str(),
+ status);
abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/);
}
return;
@@ -3338,8 +3343,9 @@ int InputDispatcher::handleReceiveCallback(int fd, int events, void* data) {
notify = status != DEAD_OBJECT || !connection->monitor;
if (notify) {
- ALOGE("channel '%s' ~ Failed to receive finished signal. status=%d",
- connection->getInputChannelName().c_str(), status);
+ ALOGE("channel '%s' ~ Failed to receive finished signal. status=%s(%d)",
+ connection->getInputChannelName().c_str(), statusToString(status).c_str(),
+ status);
}
} else {
// Monitor channels are never explicitly unregistered.
@@ -5094,6 +5100,8 @@ Result<std::unique_ptr<InputChannel>> InputDispatcher::createInputMonitor(int32_
monitorsByDisplay[displayId].emplace_back(serverChannel, pid);
mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
+ ALOGI("Created monitor %s for display %" PRId32 ", gesture=%s, pid=%" PRId32, name.c_str(),
+ displayId, toString(isGestureMonitor), pid);
}
// Wake the looper because some connections have changed.
@@ -5154,6 +5162,8 @@ void InputDispatcher::removeMonitorChannelLocked(
const size_t numMonitors = monitors.size();
for (size_t i = 0; i < numMonitors; i++) {
if (monitors[i].inputChannel->getConnectionToken() == connectionToken) {
+ ALOGI("Erasing monitor %s on display %" PRId32 ", pid=%" PRId32,
+ monitors[i].inputChannel->getName().c_str(), it->first, monitors[i].pid);
monitors.erase(monitors.begin() + i);
break;
}
diff --git a/services/inputflinger/include/InputReaderBase.h b/services/inputflinger/include/InputReaderBase.h
index 3bf212a51b..19abfd9adf 100644
--- a/services/inputflinger/include/InputReaderBase.h
+++ b/services/inputflinger/include/InputReaderBase.h
@@ -198,6 +198,10 @@ struct InputReaderConfiguration {
// Used to determine which DisplayViewport should be tied to which InputDevice.
std::unordered_map<std::string, uint8_t> portAssociations;
+ // The associations between input device names and display unique ids.
+ // Used to determine which DisplayViewport should be tied to which InputDevice.
+ std::unordered_map<std::string, std::string> uniqueIdAssociations;
+
// The suggested display ID to show the cursor.
int32_t defaultPointerDisplayId;
diff --git a/services/inputflinger/reader/InputDevice.cpp b/services/inputflinger/reader/InputDevice.cpp
index 8f75d22d87..ad503fde99 100644
--- a/services/inputflinger/reader/InputDevice.cpp
+++ b/services/inputflinger/reader/InputDevice.cpp
@@ -103,6 +103,12 @@ void InputDevice::dump(std::string& dump, const std::string& eventHubDevStr) {
} else {
dump += "<none>\n";
}
+ dump += StringPrintf(INDENT2 "AssociatedDisplayUniqueId: ");
+ if (mAssociatedDisplayUniqueId) {
+ dump += StringPrintf("%s\n", mAssociatedDisplayUniqueId->c_str());
+ } else {
+ dump += "<none>\n";
+ }
dump += StringPrintf(INDENT2 "HasMic: %s\n", toString(mHasMic));
dump += StringPrintf(INDENT2 "Sources: 0x%08x\n", deviceInfo.getSources());
dump += StringPrintf(INDENT2 "KeyboardType: %d\n", deviceInfo.getKeyboardType());
@@ -293,8 +299,9 @@ void InputDevice::configure(nsecs_t when, const InputReaderConfiguration* config
}
if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) {
- // In most situations, no port will be specified.
+ // In most situations, no port or name will be specified.
mAssociatedDisplayPort = std::nullopt;
+ mAssociatedDisplayUniqueId = std::nullopt;
mAssociatedViewport = std::nullopt;
// Find the display port that corresponds to the current input port.
const std::string& inputPort = mIdentifier.location;
@@ -305,6 +312,13 @@ void InputDevice::configure(nsecs_t when, const InputReaderConfiguration* config
mAssociatedDisplayPort = std::make_optional(displayPort->second);
}
}
+ const std::string& inputDeviceName = mIdentifier.name;
+ const std::unordered_map<std::string, std::string>& names =
+ config->uniqueIdAssociations;
+ const auto& displayUniqueId = names.find(inputDeviceName);
+ if (displayUniqueId != names.end()) {
+ mAssociatedDisplayUniqueId = displayUniqueId->second;
+ }
// If the device was explicitly disabled by the user, it would be present in the
// "disabledDevices" list. If it is associated with a specific display, and it was not
@@ -319,6 +333,15 @@ void InputDevice::configure(nsecs_t when, const InputReaderConfiguration* config
getName().c_str(), *mAssociatedDisplayPort);
enabled = false;
}
+ } else if (mAssociatedDisplayUniqueId != std::nullopt) {
+ mAssociatedViewport =
+ config->getDisplayViewportByUniqueId(*mAssociatedDisplayUniqueId);
+ if (!mAssociatedViewport) {
+ ALOGW("Input device %s should be associated with display %s but the "
+ "corresponding viewport cannot be found",
+ inputDeviceName.c_str(), mAssociatedDisplayUniqueId->c_str());
+ enabled = false;
+ }
}
if (changes) {
diff --git a/services/inputflinger/reader/include/InputDevice.h b/services/inputflinger/reader/include/InputDevice.h
index b2b23e5977..291f1059c5 100644
--- a/services/inputflinger/reader/include/InputDevice.h
+++ b/services/inputflinger/reader/include/InputDevice.h
@@ -169,6 +169,7 @@ private:
uint32_t mSources;
bool mIsExternal;
std::optional<uint8_t> mAssociatedDisplayPort;
+ std::optional<std::string> mAssociatedDisplayUniqueId;
std::optional<DisplayViewport> mAssociatedViewport;
bool mHasMic;
bool mDropUntilNextSync;
diff --git a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
index 2c5a576160..104d087387 100644
--- a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
@@ -132,9 +132,7 @@ void KeyboardInputMapper::dump(std::string& dump) {
std::optional<DisplayViewport> KeyboardInputMapper::findViewport(
nsecs_t when, const InputReaderConfiguration* config) {
- const std::optional<uint8_t> displayPort = getDeviceContext().getAssociatedDisplayPort();
- if (displayPort) {
- // Find the viewport that contains the same port
+ if (getDeviceContext().getAssociatedViewport()) {
return getDeviceContext().getAssociatedViewport();
}
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index f5198077f3..ea7a162a1a 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -268,7 +268,9 @@ public:
void assertDropTargetEquals(const sp<IBinder>& targetToken) {
std::scoped_lock lock(mLock);
+ ASSERT_TRUE(mNotifyDropWindowWasCalled);
ASSERT_EQ(targetToken, mDropTargetWindowToken);
+ mNotifyDropWindowWasCalled = false;
}
private:
@@ -290,6 +292,7 @@ private:
std::condition_variable mNotifyAnr;
sp<IBinder> mDropTargetWindowToken GUARDED_BY(mLock);
+ bool mNotifyDropWindowWasCalled GUARDED_BY(mLock) = false;
void notifyConfigurationChanged(nsecs_t when) override {
std::scoped_lock lock(mLock);
@@ -403,6 +406,7 @@ private:
void notifyDropWindow(const sp<IBinder>& token, float x, float y) override {
std::scoped_lock lock(mLock);
+ mNotifyDropWindowWasCalled = true;
mDropTargetWindowToken = token;
}
@@ -4954,4 +4958,40 @@ TEST_F(InputDispatcherDragTests, StylusDragAndDrop) {
mSecondWindow->assertNoEvents();
}
+TEST_F(InputDispatcherDragTests, DragAndDrop_InvalidWindow) {
+ performDrag();
+
+ // Set second window invisible.
+ mSecondWindow->setVisible(false);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mDragWindow, mWindow, mSecondWindow}}});
+
+ // Move on window.
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
+ ADISPLAY_ID_DEFAULT, {50, 50}))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+ mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT);
+ mWindow->consumeDragEvent(false, 50, 50);
+ mSecondWindow->assertNoEvents();
+
+ // Move to another window.
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
+ ADISPLAY_ID_DEFAULT, {150, 50}))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+ mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT);
+ mWindow->consumeDragEvent(true, 150, 50);
+ mSecondWindow->assertNoEvents();
+
+ // drop to another window.
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionUp(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
+ {150, 50}))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+ mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT);
+ mFakePolicy->assertDropTargetEquals(nullptr);
+ mWindow->assertNoEvents();
+ mSecondWindow->assertNoEvents();
+}
+
} // namespace android::inputdispatcher
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 0e721e909d..5eaca71c6a 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -269,6 +269,11 @@ public:
mConfig.portAssociations.insert({inputPort, displayPort});
}
+ void addInputUniqueIdAssociation(const std::string& inputUniqueId,
+ const std::string& displayUniqueId) {
+ mConfig.uniqueIdAssociations.insert({inputUniqueId, displayUniqueId});
+ }
+
void addDisabledDevice(int32_t deviceId) { mConfig.disabledDevices.insert(deviceId); }
void removeDisabledDevice(int32_t deviceId) { mConfig.disabledDevices.erase(deviceId); }
@@ -2621,6 +2626,41 @@ TEST_F(InputDeviceTest, Configure_AssignsDisplayPort) {
ASSERT_FALSE(mDevice->isEnabled());
}
+TEST_F(InputDeviceTest, Configure_AssignsDisplayUniqueId) {
+ // Device should be enabled by default.
+ mFakePolicy->clearViewports();
+ mDevice->addMapper<FakeInputMapper>(EVENTHUB_ID, AINPUT_SOURCE_KEYBOARD);
+ mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), 0);
+ ASSERT_TRUE(mDevice->isEnabled());
+
+ // Device should be disabled because it is associated with a specific display, but the
+ // corresponding display is not found.
+ const std::string DISPLAY_UNIQUE_ID = "displayUniqueId";
+ mFakePolicy->addInputUniqueIdAssociation(DEVICE_NAME, DISPLAY_UNIQUE_ID);
+ mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
+ InputReaderConfiguration::CHANGE_DISPLAY_INFO);
+ ASSERT_FALSE(mDevice->isEnabled());
+
+ // Device should be enabled when a display is found.
+ mFakePolicy->addDisplayViewport(SECONDARY_DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT,
+ DISPLAY_ORIENTATION_0, /* isActive= */ true, DISPLAY_UNIQUE_ID,
+ NO_PORT, ViewportType::INTERNAL);
+ mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
+ InputReaderConfiguration::CHANGE_DISPLAY_INFO);
+ ASSERT_TRUE(mDevice->isEnabled());
+
+ // Device should be disabled after set disable.
+ mFakePolicy->addDisabledDevice(mDevice->getId());
+ mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
+ InputReaderConfiguration::CHANGE_ENABLED_STATE);
+ ASSERT_FALSE(mDevice->isEnabled());
+
+ // Device should still be disabled even found the associated display.
+ mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
+ InputReaderConfiguration::CHANGE_DISPLAY_INFO);
+ ASSERT_FALSE(mDevice->isEnabled());
+}
+
// --- InputMapperTest ---
class InputMapperTest : public testing::Test {
@@ -7853,8 +7893,6 @@ TEST_F(MultiTouchInputMapperTest, Configure_EnabledForAssociatedDisplay) {
ASSERT_EQ(SECONDARY_DISPLAY_ID, args.displayId);
}
-
-
TEST_F(MultiTouchInputMapperTest, Process_ShouldHandleSingleTouch) {
addConfigurationProperty("touch.deviceType", "touchScreen");
prepareDisplay(DISPLAY_ORIENTATION_0);
diff --git a/services/sensorservice/Android.bp b/services/sensorservice/Android.bp
index 9aecaff409..4151b4512f 100644
--- a/services/sensorservice/Android.bp
+++ b/services/sensorservice/Android.bp
@@ -54,6 +54,7 @@ cc_library_shared {
"libbinder",
"libsensor",
"libsensorprivacy",
+ "libpermission",
"libprotoutil",
"libcrypto",
"libbase",
@@ -74,6 +75,7 @@ cc_library_shared {
"libactivitymanager_aidl",
"libsensor",
"libsensorprivacy",
+ "libpermission",
],
}
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index a6d606f8ff..b8a8f15ff8 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -192,9 +192,9 @@ std::optional<compositionengine::LayerFE::LayerSettings> BufferLayer::prepareCli
}
}
const bool blackOutLayer = (isProtected() && !targetSettings.supportsProtectedContent) ||
- (isSecure() && !targetSettings.isSecure);
+ ((isSecure() || isProtected()) && !targetSettings.isSecure);
const bool bufferCanBeUsedAsHwTexture =
- mBufferInfo.mBuffer->getUsage() & GraphicBuffer::USAGE_HW_TEXTURE;
+ mBufferInfo.mBuffer->getBuffer()->getUsage() & GraphicBuffer::USAGE_HW_TEXTURE;
compositionengine::LayerFE::LayerSettings& layer = *result;
if (blackOutLayer || !bufferCanBeUsedAsHwTexture) {
ALOGE_IF(!bufferCanBeUsedAsHwTexture, "%s is blacked out as buffer is not gpu readable",
@@ -219,7 +219,7 @@ std::optional<compositionengine::LayerFE::LayerSettings> BufferLayer::prepareCli
? mBufferInfo.mHdrMetadata.cta8613.maxContentLightLevel
: defaultMaxContentLuminance;
layer.frameNumber = mCurrentFrameNumber;
- layer.bufferId = mBufferInfo.mBuffer ? mBufferInfo.mBuffer->getId() : 0;
+ layer.bufferId = mBufferInfo.mBuffer ? mBufferInfo.mBuffer->getBuffer()->getId() : 0;
const bool useFiltering =
targetSettings.needsFiltering || mNeedsFiltering || bufferNeedsFiltering();
@@ -320,7 +320,7 @@ void BufferLayer::preparePerFrameCompositionState() {
: Hwc2::IComposerClient::Composition::DEVICE;
}
- compositionState->buffer = mBufferInfo.mBuffer;
+ compositionState->buffer = mBufferInfo.mBuffer->getBuffer();
compositionState->bufferSlot = (mBufferInfo.mBufferSlot == BufferQueue::INVALID_BUFFER_SLOT)
? 0
: mBufferInfo.mBufferSlot;
@@ -448,7 +448,7 @@ bool BufferLayer::onPostComposition(const DisplayDevice* display,
void BufferLayer::gatherBufferInfo() {
mBufferInfo.mPixelFormat =
- !mBufferInfo.mBuffer ? PIXEL_FORMAT_NONE : mBufferInfo.mBuffer->format;
+ !mBufferInfo.mBuffer ? PIXEL_FORMAT_NONE : mBufferInfo.mBuffer->getBuffer()->format;
mBufferInfo.mFrameLatencyNeeded = true;
}
@@ -513,11 +513,6 @@ bool BufferLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime,
BufferInfo oldBufferInfo = mBufferInfo;
- if (!allTransactionsSignaled(expectedPresentTime)) {
- mFlinger->setTransactionFlags(eTraversalNeeded);
- return false;
- }
-
status_t err = updateTexImage(recomputeVisibleRegions, latchTime, expectedPresentTime);
if (err != NO_ERROR) {
return false;
@@ -550,10 +545,10 @@ bool BufferLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime,
}
if (oldBufferInfo.mBuffer != nullptr) {
- uint32_t bufWidth = mBufferInfo.mBuffer->getWidth();
- uint32_t bufHeight = mBufferInfo.mBuffer->getHeight();
- if (bufWidth != uint32_t(oldBufferInfo.mBuffer->width) ||
- bufHeight != uint32_t(oldBufferInfo.mBuffer->height)) {
+ uint32_t bufWidth = mBufferInfo.mBuffer->getBuffer()->getWidth();
+ uint32_t bufHeight = mBufferInfo.mBuffer->getBuffer()->getHeight();
+ if (bufWidth != uint32_t(oldBufferInfo.mBuffer->getBuffer()->width) ||
+ bufHeight != uint32_t(oldBufferInfo.mBuffer->getBuffer()->height)) {
recomputeVisibleRegions = true;
}
}
@@ -562,53 +557,9 @@ bool BufferLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime,
recomputeVisibleRegions = true;
}
- // Remove any sync points corresponding to the buffer which was just
- // latched
- {
- Mutex::Autolock lock(mLocalSyncPointMutex);
- auto point = mLocalSyncPoints.begin();
- while (point != mLocalSyncPoints.end()) {
- if (!(*point)->frameIsAvailable() || !(*point)->transactionIsApplied()) {
- // This sync point must have been added since we started
- // latching. Don't drop it yet.
- ++point;
- continue;
- }
-
- if ((*point)->getFrameNumber() <= mCurrentFrameNumber) {
- std::stringstream ss;
- ss << "Dropping sync point " << (*point)->getFrameNumber();
- ATRACE_NAME(ss.str().c_str());
- point = mLocalSyncPoints.erase(point);
- } else {
- ++point;
- }
- }
- }
-
return true;
}
-// transaction
-void BufferLayer::notifyAvailableFrames(nsecs_t expectedPresentTime) {
- const auto headFrameNumber = getHeadFrameNumber(expectedPresentTime);
- const bool headFenceSignaled = fenceHasSignaled();
- const bool presentTimeIsCurrent = framePresentTimeIsCurrent(expectedPresentTime);
- Mutex::Autolock lock(mLocalSyncPointMutex);
- for (auto& point : mLocalSyncPoints) {
- if (headFrameNumber >= point->getFrameNumber() && headFenceSignaled &&
- presentTimeIsCurrent) {
- point->setFrameAvailable();
- sp<Layer> requestedSyncLayer = point->getRequestedSyncLayer();
- if (requestedSyncLayer) {
- // Need to update the transaction flag to ensure the layer's pending transaction
- // gets applied.
- requestedSyncLayer->setTransactionFlags(eTransactionNeeded);
- }
- }
- }
-}
-
bool BufferLayer::hasReadyFrame() const {
return hasFrameUpdate() || getSidebandStreamChanged() || getAutoRefresh();
}
@@ -618,8 +569,8 @@ uint32_t BufferLayer::getEffectiveScalingMode() const {
}
bool BufferLayer::isProtected() const {
- const sp<GraphicBuffer>& buffer(mBufferInfo.mBuffer);
- return (buffer != 0) && (buffer->getUsage() & GRALLOC_USAGE_PROTECTED);
+ return (mBufferInfo.mBuffer != nullptr) &&
+ (mBufferInfo.mBuffer->getBuffer()->getUsage() & GRALLOC_USAGE_PROTECTED);
}
bool BufferLayer::latchUnsignaledBuffers() {
@@ -636,32 +587,6 @@ bool BufferLayer::latchUnsignaledBuffers() {
return latch;
}
-// h/w composer set-up
-bool BufferLayer::allTransactionsSignaled(nsecs_t expectedPresentTime) {
- const auto headFrameNumber = getHeadFrameNumber(expectedPresentTime);
- bool matchingFramesFound = false;
- bool allTransactionsApplied = true;
- Mutex::Autolock lock(mLocalSyncPointMutex);
-
- for (auto& point : mLocalSyncPoints) {
- if (point->getFrameNumber() > headFrameNumber) {
- break;
- }
- matchingFramesFound = true;
-
- if (!point->frameIsAvailable()) {
- // We haven't notified the remote layer that the frame for
- // this point is available yet. Notify it now, and then
- // abort this attempt to latch.
- point->setFrameAvailable();
- allTransactionsApplied = false;
- break;
- }
-
- allTransactionsApplied = allTransactionsApplied && point->transactionIsApplied();
- }
- return !matchingFramesFound || allTransactionsApplied;
-}
// As documented in libhardware header, formats in the range
// 0x100 - 0x1FF are specific to the HAL implementation, and
@@ -747,8 +672,8 @@ Rect BufferLayer::getBufferSize(const State& s) const {
return Rect::INVALID_RECT;
}
- uint32_t bufWidth = mBufferInfo.mBuffer->getWidth();
- uint32_t bufHeight = mBufferInfo.mBuffer->getHeight();
+ uint32_t bufWidth = mBufferInfo.mBuffer->getBuffer()->getWidth();
+ uint32_t bufHeight = mBufferInfo.mBuffer->getBuffer()->getHeight();
// Undo any transformations on the buffer and return the result.
if (mBufferInfo.mTransform & ui::Transform::ROT_90) {
@@ -779,8 +704,8 @@ FloatRect BufferLayer::computeSourceBounds(const FloatRect& parentBounds) const
return parentBounds;
}
- uint32_t bufWidth = mBufferInfo.mBuffer->getWidth();
- uint32_t bufHeight = mBufferInfo.mBuffer->getHeight();
+ uint32_t bufWidth = mBufferInfo.mBuffer->getBuffer()->getWidth();
+ uint32_t bufHeight = mBufferInfo.mBuffer->getBuffer()->getHeight();
// Undo any transformations on the buffer and return the result.
if (mBufferInfo.mTransform & ui::Transform::ROT_90) {
@@ -822,7 +747,7 @@ Rect BufferLayer::getBufferCrop() const {
return mBufferInfo.mCrop;
} else if (mBufferInfo.mBuffer != nullptr) {
// otherwise we use the whole buffer
- return mBufferInfo.mBuffer->getBounds();
+ return mBufferInfo.mBuffer->getBuffer()->getBounds();
} else {
// if we don't have a buffer yet, we use an empty/invalid crop
return Rect();
@@ -867,12 +792,14 @@ ui::Dataspace BufferLayer::translateDataspace(ui::Dataspace dataspace) {
}
sp<GraphicBuffer> BufferLayer::getBuffer() const {
- return mBufferInfo.mBuffer;
+ return mBufferInfo.mBuffer ? mBufferInfo.mBuffer->getBuffer() : nullptr;
}
void BufferLayer::getDrawingTransformMatrix(bool filteringEnabled, float outMatrix[16]) {
- GLConsumer::computeTransformMatrix(outMatrix, mBufferInfo.mBuffer, mBufferInfo.mCrop,
- mBufferInfo.mTransform, filteringEnabled);
+ GLConsumer::computeTransformMatrix(outMatrix,
+ mBufferInfo.mBuffer ? mBufferInfo.mBuffer->getBuffer()
+ : nullptr,
+ mBufferInfo.mCrop, mBufferInfo.mTransform, filteringEnabled);
}
void BufferLayer::setInitialValuesForClone(const sp<Layer>& clonedFrom) {
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index 284132cad6..1d6b63ced1 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -90,8 +90,6 @@ public:
bool isBufferLatched() const override { return mRefreshPending; }
- void notifyAvailableFrames(nsecs_t expectedPresentTime) override;
-
bool hasReadyFrame() const override;
// Returns the current scaling mode
@@ -134,7 +132,7 @@ protected:
PixelFormat mPixelFormat{PIXEL_FORMAT_NONE};
bool mTransformToDisplayInverse{false};
- sp<GraphicBuffer> mBuffer;
+ std::shared_ptr<renderengine::ExternalTexture> mBuffer;
int mBufferSlot{BufferQueue::INVALID_BUFFER_SLOT};
bool mFrameLatencyNeeded{false};
@@ -156,11 +154,6 @@ protected:
// Loads the corresponding system property once per process
static bool latchUnsignaledBuffers();
- // Check all of the local sync points to ensure that all transactions
- // which need to have been applied prior to the frame which is about to
- // be latched have signaled
- bool allTransactionsSignaled(nsecs_t expectedPresentTime);
-
static bool getOpacityForFormat(uint32_t format);
// from graphics API
diff --git a/services/surfaceflinger/BufferLayerConsumer.cpp b/services/surfaceflinger/BufferLayerConsumer.cpp
index 69d2d11a4d..96b22478ab 100644
--- a/services/surfaceflinger/BufferLayerConsumer.cpp
+++ b/services/surfaceflinger/BufferLayerConsumer.cpp
@@ -40,7 +40,6 @@
#include <gui/ISurfaceComposer.h>
#include <gui/SurfaceComposerClient.h>
#include <private/gui/ComposerService.h>
-#include <renderengine/Image.h>
#include <renderengine/RenderEngine.h>
#include <utils/Log.h>
#include <utils/String8.h>
@@ -167,7 +166,7 @@ void BufferLayerConsumer::setReleaseFence(const sp<Fence>& fence) {
}
auto buffer = mPendingRelease.isPending ? mPendingRelease.graphicBuffer
- : mCurrentTextureBuffer->graphicBuffer();
+ : mCurrentTextureBuffer->getBuffer();
auto err = addReleaseFence(slot, buffer, fence);
if (err != OK) {
BLC_LOGE("setReleaseFence: failed to add the fence: %s (%d)", strerror(-err), err);
@@ -206,9 +205,11 @@ status_t BufferLayerConsumer::acquireBufferLocked(BufferItem* item, nsecs_t pres
// before, so we need to clean up old references.
if (item->mGraphicBuffer != nullptr) {
std::lock_guard<std::mutex> lock(mImagesMutex);
- if (mImages[item->mSlot] == nullptr || mImages[item->mSlot]->graphicBuffer() == nullptr ||
- mImages[item->mSlot]->graphicBuffer()->getId() != item->mGraphicBuffer->getId()) {
- mImages[item->mSlot] = std::make_shared<Image>(item->mGraphicBuffer, mRE);
+ if (mImages[item->mSlot] == nullptr || mImages[item->mSlot]->getBuffer() == nullptr ||
+ mImages[item->mSlot]->getBuffer()->getId() != item->mGraphicBuffer->getId()) {
+ mImages[item->mSlot] = std::make_shared<
+ renderengine::ExternalTexture>(item->mGraphicBuffer, mRE,
+ renderengine::ExternalTexture::Usage::READABLE);
}
}
@@ -222,8 +223,8 @@ status_t BufferLayerConsumer::updateAndReleaseLocked(const BufferItem& item,
int slot = item.mSlot;
BLC_LOGV("updateAndRelease: (slot=%d buf=%p) -> (slot=%d buf=%p)", mCurrentTexture,
- (mCurrentTextureBuffer != nullptr && mCurrentTextureBuffer->graphicBuffer() != nullptr)
- ? mCurrentTextureBuffer->graphicBuffer()->handle
+ (mCurrentTextureBuffer != nullptr && mCurrentTextureBuffer->getBuffer() != nullptr)
+ ? mCurrentTextureBuffer->getBuffer()->handle
: 0,
slot, mSlots[slot].mGraphicBuffer->handle);
@@ -231,7 +232,7 @@ status_t BufferLayerConsumer::updateAndReleaseLocked(const BufferItem& item,
// releaseBufferLocked() if we're in shared buffer mode and both buffers are
// the same.
- std::shared_ptr<Image> nextTextureBuffer;
+ std::shared_ptr<renderengine::ExternalTexture> nextTextureBuffer;
{
std::lock_guard<std::mutex> lock(mImagesMutex);
nextTextureBuffer = mImages[slot];
@@ -241,7 +242,7 @@ status_t BufferLayerConsumer::updateAndReleaseLocked(const BufferItem& item,
if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
if (pendingRelease == nullptr) {
status_t status =
- releaseBufferLocked(mCurrentTexture, mCurrentTextureBuffer->graphicBuffer());
+ releaseBufferLocked(mCurrentTexture, mCurrentTextureBuffer->getBuffer());
if (status < NO_ERROR) {
BLC_LOGE("updateAndRelease: failed to release buffer: %s (%d)", strerror(-status),
status);
@@ -250,7 +251,7 @@ status_t BufferLayerConsumer::updateAndReleaseLocked(const BufferItem& item,
}
} else {
pendingRelease->currentTexture = mCurrentTexture;
- pendingRelease->graphicBuffer = mCurrentTextureBuffer->graphicBuffer();
+ pendingRelease->graphicBuffer = mCurrentTextureBuffer->getBuffer();
pendingRelease->isPending = true;
}
}
@@ -301,14 +302,14 @@ void BufferLayerConsumer::setFilteringEnabled(bool enabled) {
void BufferLayerConsumer::computeCurrentTransformMatrixLocked() {
BLC_LOGV("computeCurrentTransformMatrixLocked");
- if (mCurrentTextureBuffer == nullptr || mCurrentTextureBuffer->graphicBuffer() == nullptr) {
+ if (mCurrentTextureBuffer == nullptr || mCurrentTextureBuffer->getBuffer() == nullptr) {
BLC_LOGD("computeCurrentTransformMatrixLocked: "
"mCurrentTextureBuffer is nullptr");
}
GLConsumer::computeTransformMatrix(mCurrentTransformMatrix,
mCurrentTextureBuffer == nullptr
? nullptr
- : mCurrentTextureBuffer->graphicBuffer(),
+ : mCurrentTextureBuffer->getBuffer(),
getCurrentCropLocked(), mCurrentTransform,
mFilteringEnabled);
}
@@ -360,7 +361,8 @@ int BufferLayerConsumer::getCurrentApi() const {
return mCurrentApi;
}
-sp<GraphicBuffer> BufferLayerConsumer::getCurrentBuffer(int* outSlot, sp<Fence>* outFence) const {
+std::shared_ptr<renderengine::ExternalTexture> BufferLayerConsumer::getCurrentBuffer(
+ int* outSlot, sp<Fence>* outFence) const {
Mutex::Autolock lock(mMutex);
if (outSlot != nullptr) {
@@ -371,7 +373,7 @@ sp<GraphicBuffer> BufferLayerConsumer::getCurrentBuffer(int* outSlot, sp<Fence>*
*outFence = mCurrentFence;
}
- return mCurrentTextureBuffer == nullptr ? nullptr : mCurrentTextureBuffer->graphicBuffer();
+ return mCurrentTextureBuffer == nullptr ? nullptr : mCurrentTextureBuffer;
}
Rect BufferLayerConsumer::getCurrentCrop() const {
@@ -456,10 +458,12 @@ void BufferLayerConsumer::onSidebandStreamChanged() {
void BufferLayerConsumer::onBufferAvailable(const BufferItem& item) {
if (item.mGraphicBuffer != nullptr && item.mSlot != BufferQueue::INVALID_BUFFER_SLOT) {
std::lock_guard<std::mutex> lock(mImagesMutex);
- const std::shared_ptr<Image>& oldImage = mImages[item.mSlot];
- if (oldImage == nullptr || oldImage->graphicBuffer() == nullptr ||
- oldImage->graphicBuffer()->getId() != item.mGraphicBuffer->getId()) {
- mImages[item.mSlot] = std::make_shared<Image>(item.mGraphicBuffer, mRE);
+ const std::shared_ptr<renderengine::ExternalTexture>& oldImage = mImages[item.mSlot];
+ if (oldImage == nullptr || oldImage->getBuffer() == nullptr ||
+ oldImage->getBuffer()->getId() != item.mGraphicBuffer->getId()) {
+ mImages[item.mSlot] = std::make_shared<
+ renderengine::ExternalTexture>(item.mGraphicBuffer, mRE,
+ renderengine::ExternalTexture::Usage::READABLE);
}
}
}
@@ -499,22 +503,6 @@ void BufferLayerConsumer::dumpLocked(String8& result, const char* prefix) const
ConsumerBase::dumpLocked(result, prefix);
}
-
-BufferLayerConsumer::Image::Image(const sp<GraphicBuffer>& graphicBuffer,
- renderengine::RenderEngine& engine)
- : mGraphicBuffer(graphicBuffer), mRE(engine) {
- if (graphicBuffer != nullptr && (graphicBuffer->getUsage() & GRALLOC_USAGE_PROTECTED)) {
- return;
- }
- mRE.cacheExternalTextureBuffer(mGraphicBuffer);
-}
-
-BufferLayerConsumer::Image::~Image() {
- if (mGraphicBuffer != nullptr) {
- ALOGV("Destroying buffer: %" PRId64, mGraphicBuffer->getId());
- mRE.unbindExternalTextureBuffer(mGraphicBuffer->getId());
- }
-}
}; // namespace android
// TODO(b/129481165): remove the #pragma below and fix conversion issues
diff --git a/services/surfaceflinger/BufferLayerConsumer.h b/services/surfaceflinger/BufferLayerConsumer.h
index dd39214aff..9ed80b46bd 100644
--- a/services/surfaceflinger/BufferLayerConsumer.h
+++ b/services/surfaceflinger/BufferLayerConsumer.h
@@ -21,12 +21,11 @@
#include <gui/BufferQueueDefs.h>
#include <gui/ConsumerBase.h>
#include <gui/HdrMetadata.h>
-
+#include <renderengine/ExternalTexture.h>
#include <ui/FenceTime.h>
#include <ui/GraphicBuffer.h>
#include <ui/GraphicTypes.h>
#include <ui/Region.h>
-
#include <utils/String8.h>
#include <utils/Vector.h>
#include <utils/threads.h>
@@ -39,7 +38,6 @@ class String8;
namespace renderengine {
class RenderEngine;
-class Image;
} // namespace renderengine
/*
@@ -153,7 +151,8 @@ public:
// When outSlot is not nullptr, the current buffer slot index is also
// returned. Simiarly, when outFence is not nullptr, the current output
// fence is returned.
- sp<GraphicBuffer> getCurrentBuffer(int* outSlot = nullptr, sp<Fence>* outFence = nullptr) const;
+ std::shared_ptr<renderengine::ExternalTexture> getCurrentBuffer(
+ int* outSlot = nullptr, sp<Fence>* outFence = nullptr) const;
// getCurrentCrop returns the cropping rectangle of the current buffer.
Rect getCurrentCrop() const;
@@ -258,7 +257,7 @@ private:
// mCurrentTextureBuffer is the buffer containing the current texture. It's
// possible that this buffer is not associated with any buffer slot, so we
// must track it separately in order to support the getCurrentBuffer method.
- std::shared_ptr<Image> mCurrentTextureBuffer;
+ std::shared_ptr<renderengine::ExternalTexture> mCurrentTextureBuffer;
// mCurrentCrop is the crop rectangle that applies to the current texture.
// It gets set each time updateTexImage is called.
@@ -337,7 +336,8 @@ private:
int mCurrentTexture;
// Shadow buffer cache for cleaning up renderengine references.
- std::shared_ptr<Image> mImages[BufferQueueDefs::NUM_BUFFER_SLOTS] GUARDED_BY(mImagesMutex);
+ std::shared_ptr<renderengine::ExternalTexture>
+ mImages[BufferQueueDefs::NUM_BUFFER_SLOTS] GUARDED_BY(mImagesMutex);
// Separate mutex guarding the shadow buffer cache.
// mImagesMutex can be manipulated with binder threads (e.g. onBuffersAllocated)
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 700c19689d..471a551432 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -74,14 +74,8 @@ BufferStateLayer::~BufferStateLayer() {
// original layer and the clone should be removed at the same time so there shouldn't be any
// issue with the clone layer trying to use the texture.
if (mBufferInfo.mBuffer != nullptr && !isClone()) {
- // Ensure that mBuffer is uncached from RenderEngine here, as
- // RenderEngine may have been using the buffer as an external texture
- // after the client uncached the buffer.
- auto& engine(mFlinger->getRenderEngine());
- const uint64_t bufferId = mBufferInfo.mBuffer->getId();
- engine.unbindExternalTextureBuffer(bufferId);
- callReleaseBufferCallback(mDrawingState.releaseBufferListener, mBufferInfo.mBuffer,
- mBufferInfo.mFence);
+ callReleaseBufferCallback(mDrawingState.releaseBufferListener,
+ mBufferInfo.mBuffer->getBuffer(), mBufferInfo.mFence);
}
}
@@ -289,17 +283,8 @@ bool BufferStateLayer::isBufferDue(nsecs_t expectedPresentTime) const {
return isDue;
}
-bool BufferStateLayer::applyPendingStates(Layer::State* stateToCommit) {
- mCurrentStateModified = mCurrentState.modified;
- bool stateUpdateAvailable = Layer::applyPendingStates(stateToCommit);
- mCurrentStateModified = stateUpdateAvailable && mCurrentStateModified;
- mCurrentState.modified = false;
- return stateUpdateAvailable;
-}
-
-// Crop that applies to the window
-Rect BufferStateLayer::getCrop(const Layer::State& /*s*/) const {
- return Rect::INVALID_RECT;
+Rect BufferStateLayer::getCrop(const Layer::State& s) const {
+ return s.crop;
}
bool BufferStateLayer::setTransform(uint32_t transform) {
@@ -320,57 +305,53 @@ bool BufferStateLayer::setTransformToDisplayInverse(bool transformToDisplayInver
}
bool BufferStateLayer::setCrop(const Rect& crop) {
- Rect c = crop;
- if (c.left < 0) {
- c.left = 0;
- }
- if (c.top < 0) {
- c.top = 0;
- }
- // If the width and/or height are < 0, make it [0, 0, -1, -1] so the equality comparision below
- // treats all invalid rectangles the same.
- if (!c.isValid()) {
- c.makeInvalid();
- }
+ if (mCurrentState.crop == crop) return false;
+ mCurrentState.sequence++;
+ mCurrentState.crop = crop;
- if (mCurrentState.crop == c) return false;
- mCurrentState.crop = c;
mCurrentState.modified = true;
setTransactionFlags(eTransactionNeeded);
return true;
}
-bool BufferStateLayer::setFrame(const Rect& frame) {
- int x = frame.left;
- int y = frame.top;
- int w = frame.getWidth();
- int h = frame.getHeight();
-
- if (x < 0) {
- x = 0;
- w = frame.right;
+bool BufferStateLayer::setMatrix(const layer_state_t::matrix22_t& matrix,
+ bool allowNonRectPreservingTransforms) {
+ if (mCurrentState.transform.dsdx() == matrix.dsdx &&
+ mCurrentState.transform.dtdy() == matrix.dtdy &&
+ mCurrentState.transform.dtdx() == matrix.dtdx &&
+ mCurrentState.transform.dsdy() == matrix.dsdy) {
+ return false;
}
- if (y < 0) {
- y = 0;
- h = frame.bottom;
- }
+ ui::Transform t;
+ t.set(matrix.dsdx, matrix.dtdy, matrix.dtdx, matrix.dsdy);
- if (mCurrentState.transform.tx() == x && mCurrentState.transform.ty() == y &&
- mCurrentState.width == w && mCurrentState.height == h) {
+ if (!allowNonRectPreservingTransforms && !t.preserveRects()) {
+ ALOGW("Attempt to set rotation matrix without permission ACCESS_SURFACE_FLINGER nor "
+ "ROTATE_SURFACE_FLINGER ignored");
return false;
}
- if (!frame.isValid()) {
- x = y = w = h = 0;
+ mCurrentState.transform.set(matrix.dsdx, matrix.dtdy, matrix.dtdx, matrix.dsdy);
+
+ mCurrentState.sequence++;
+ mCurrentState.modified = true;
+ setTransactionFlags(eTransactionNeeded);
+
+ return true;
+}
+
+bool BufferStateLayer::setPosition(float x, float y) {
+ if (mCurrentState.transform.tx() == x && mCurrentState.transform.ty() == y) {
+ return false;
}
+
mCurrentState.transform.set(x, y);
- mCurrentState.width = w;
- mCurrentState.height = h;
mCurrentState.sequence++;
mCurrentState.modified = true;
setTransactionFlags(eTransactionNeeded);
+
return true;
}
@@ -387,8 +368,9 @@ bool BufferStateLayer::addFrameEvent(const sp<Fence>& acquireFence, nsecs_t post
return true;
}
-bool BufferStateLayer::setBuffer(const sp<GraphicBuffer>& buffer, const sp<Fence>& acquireFence,
- nsecs_t postTime, nsecs_t desiredPresentTime, bool isAutoTimestamp,
+bool BufferStateLayer::setBuffer(const std::shared_ptr<renderengine::ExternalTexture>& buffer,
+ const sp<Fence>& acquireFence, nsecs_t postTime,
+ nsecs_t desiredPresentTime, bool isAutoTimestamp,
const client_cache_t& clientCacheId, uint64_t frameNumber,
std::optional<nsecs_t> dequeueTime, const FrameTimelineInfo& info,
const sp<ITransactionCompletedListener>& releaseBufferListener) {
@@ -396,12 +378,14 @@ bool BufferStateLayer::setBuffer(const sp<GraphicBuffer>& buffer, const sp<Fence
if (mCurrentState.buffer) {
mReleasePreviousBuffer = true;
- if (mCurrentState.buffer != mDrawingState.buffer) {
+ if (!mDrawingState.buffer ||
+ mCurrentState.buffer->getBuffer() != mDrawingState.buffer->getBuffer()) {
// If mCurrentState has a buffer, and we are about to update again
// before swapping to drawing state, then the first buffer will be
// dropped and we should decrement the pending buffer count and
// call any release buffer callbacks if set.
- callReleaseBufferCallback(mCurrentState.releaseBufferListener, mCurrentState.buffer,
+ callReleaseBufferCallback(mCurrentState.releaseBufferListener,
+ mCurrentState.buffer->getBuffer(),
mCurrentState.acquireFence);
decrementPendingBufferCount();
if (mCurrentState.bufferSurfaceFrameTX != nullptr) {
@@ -439,8 +423,8 @@ bool BufferStateLayer::setBuffer(const sp<GraphicBuffer>& buffer, const sp<Fence
setFrameTimelineVsyncForBufferTransaction(info, postTime);
- if (dequeueTime && *dequeueTime != 0) {
- const uint64_t bufferId = buffer->getId();
+ if (buffer && dequeueTime && *dequeueTime != 0) {
+ const uint64_t bufferId = buffer->getBuffer()->getId();
mFlinger->mFrameTracer->traceNewLayer(layerId, getName().c_str());
mFlinger->mFrameTracer->traceTimestamp(layerId, bufferId, frameNumber, *dequeueTime,
FrameTracer::FrameEvent::DEQUEUE);
@@ -448,6 +432,9 @@ bool BufferStateLayer::setBuffer(const sp<GraphicBuffer>& buffer, const sp<Fence
FrameTracer::FrameEvent::QUEUE);
}
+ mCurrentState.width = mCurrentState.buffer->getBuffer()->getWidth();
+ mCurrentState.height = mCurrentState.buffer->getBuffer()->getHeight();
+
if (mFlinger->mSmoMo) {
smomo::SmomoBufferStats bufferStats;
bufferStats.id = getSequence();
@@ -709,7 +696,7 @@ status_t BufferStateLayer::updateTexImage(bool& /*recomputeVisibleRegions*/, nse
}
const int32_t layerId = getSequence();
- const uint64_t bufferId = mDrawingState.buffer->getId();
+ const uint64_t bufferId = mDrawingState.buffer->getBuffer()->getId();
const uint64_t frameNumber = mDrawingState.frameNumber;
const auto acquireFence = std::make_shared<FenceTime>(mDrawingState.acquireFence);
mFlinger->mTimeStats->setAcquireFence(layerId, frameNumber, acquireFence);
@@ -731,6 +718,11 @@ status_t BufferStateLayer::updateTexImage(bool& /*recomputeVisibleRegions*/, nse
latchTime);
}
+ std::deque<sp<CallbackHandle>> remainingHandles;
+ mFlinger->getTransactionCallbackInvoker()
+ .finalizeOnCommitCallbackHandles(mDrawingState.callbackHandles, remainingHandles);
+ mDrawingState.callbackHandles = remainingHandles;
+
mCurrentStateModified = false;
return NO_ERROR;
@@ -743,7 +735,7 @@ status_t BufferStateLayer::updateActiveBuffer() {
return BAD_VALUE;
}
- if (s.buffer != mBufferInfo.mBuffer) {
+ if (!mBufferInfo.mBuffer || s.buffer->getBuffer() != mBufferInfo.mBuffer->getBuffer()) {
decrementPendingBufferCount();
}
@@ -847,7 +839,7 @@ void BufferStateLayer::gatherBufferInfo() {
mBufferInfo.mFence = s.acquireFence;
mBufferInfo.mTransform = s.bufferTransform;
mBufferInfo.mDataspace = translateDataspace(s.dataspace);
- mBufferInfo.mCrop = computeCrop(s);
+ mBufferInfo.mCrop = computeBufferCrop(s);
mBufferInfo.mScaleMode = NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW;
mBufferInfo.mSurfaceDamage = s.surfaceDamageRegion;
mBufferInfo.mHdrMetadata = s.hdrMetadata;
@@ -860,27 +852,11 @@ uint32_t BufferStateLayer::getEffectiveScalingMode() const {
return NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW;
}
-Rect BufferStateLayer::computeCrop(const State& s) {
- if (s.crop.isEmpty() && s.buffer) {
- return s.buffer->getBounds();
- } else if (s.buffer) {
- Rect crop = s.crop;
- crop.left = std::max(crop.left, 0);
- crop.top = std::max(crop.top, 0);
- uint32_t bufferWidth = s.buffer->getWidth();
- uint32_t bufferHeight = s.buffer->getHeight();
- if (bufferHeight <= std::numeric_limits<int32_t>::max() &&
- bufferWidth <= std::numeric_limits<int32_t>::max()) {
- crop.right = std::min(crop.right, static_cast<int32_t>(bufferWidth));
- crop.bottom = std::min(crop.bottom, static_cast<int32_t>(bufferHeight));
- }
- if (!crop.isValid()) {
- // Crop rect is out of bounds, return whole buffer
- return s.buffer->getBounds();
- }
- return crop;
+Rect BufferStateLayer::computeBufferCrop(const State& s) {
+ if (s.buffer) {
+ return s.buffer->getBuffer()->getBounds();
}
- return s.crop;
+ return Rect::INVALID_RECT;
}
sp<Layer> BufferStateLayer::createClone() {
@@ -892,41 +868,14 @@ sp<Layer> BufferStateLayer::createClone() {
return layer;
}
-Layer::RoundedCornerState BufferStateLayer::getRoundedCornerState() const {
- const auto& p = mDrawingParent.promote();
- if (p != nullptr) {
- RoundedCornerState parentState = p->getRoundedCornerState();
- if (parentState.radius > 0) {
- ui::Transform t = getActiveTransform(getDrawingState());
- t = t.inverse();
- parentState.cropRect = t.transform(parentState.cropRect);
- // The rounded corners shader only accepts 1 corner radius for performance reasons,
- // but a transform matrix can define horizontal and vertical scales.
- // Let's take the average between both of them and pass into the shader, practically we
- // never do this type of transformation on windows anyway.
- parentState.radius *= (t[0][0] + t[1][1]) / 2.0f;
- return parentState;
- }
- }
- const float radius = getDrawingState().cornerRadius;
- const State& s(getDrawingState());
- if (radius <= 0 || (getActiveWidth(s) == UINT32_MAX && getActiveHeight(s) == UINT32_MAX))
- return RoundedCornerState();
- return RoundedCornerState(FloatRect(static_cast<float>(s.transform.tx()),
- static_cast<float>(s.transform.ty()),
- static_cast<float>(s.transform.tx() + s.width),
- static_cast<float>(s.transform.ty() + s.height)),
- radius);
-}
-
bool BufferStateLayer::bufferNeedsFiltering() const {
const State& s(getDrawingState());
if (!s.buffer) {
return false;
}
- uint32_t bufferWidth = s.buffer->width;
- uint32_t bufferHeight = s.buffer->height;
+ uint32_t bufferWidth = s.buffer->getBuffer()->width;
+ uint32_t bufferHeight = s.buffer->getBuffer()->height;
// Undo any transformations on the buffer and return the result.
if (s.bufferTransform & ui::Transform::ROT_90) {
@@ -953,14 +902,16 @@ void BufferStateLayer::tracePendingBufferCount(int32_t pendingBuffers) {
ATRACE_INT(mBlastTransactionName.c_str(), pendingBuffers);
}
-void BufferStateLayer::bufferMayChange(sp<GraphicBuffer>& newBuffer) {
- if (mDrawingState.buffer != nullptr && mDrawingState.buffer != mBufferInfo.mBuffer &&
- newBuffer != mDrawingState.buffer) {
+void BufferStateLayer::bufferMayChange(const sp<GraphicBuffer>& newBuffer) {
+ if (mDrawingState.buffer != nullptr &&
+ (!mBufferInfo.mBuffer ||
+ mDrawingState.buffer->getBuffer() != mBufferInfo.mBuffer->getBuffer()) &&
+ newBuffer != mDrawingState.buffer->getBuffer()) {
// If we are about to update mDrawingState.buffer but it has not yet latched
// then we will drop a buffer and should decrement the pending buffer count and
// call any release buffer callbacks if set.
- callReleaseBufferCallback(mDrawingState.releaseBufferListener, mDrawingState.buffer,
- mDrawingState.acquireFence);
+ callReleaseBufferCallback(mDrawingState.releaseBufferListener,
+ mDrawingState.buffer->getBuffer(), mDrawingState.acquireFence);
decrementPendingBufferCount();
}
}
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index 3ae8597c73..46dfd7f6f6 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -50,10 +50,6 @@ public:
uint32_t doTransactionResize(uint32_t flags, Layer::State* /*stateToCommit*/) override {
return flags;
}
- /*TODO:vhau return to using BufferStateLayer override once WM
- * has removed deferred transactions!
- void pushPendingState() override;*/
- bool applyPendingStates(Layer::State* stateToCommit) override;
uint32_t getActiveWidth(const Layer::State& s) const override { return s.width; }
uint32_t getActiveHeight(const Layer::State& s) const override { return s.height; }
@@ -66,10 +62,9 @@ public:
bool setTransform(uint32_t transform) override;
bool setTransformToDisplayInverse(bool transformToDisplayInverse) override;
bool setCrop(const Rect& crop) override;
- bool setFrame(const Rect& frame) override;
- bool setBuffer(const sp<GraphicBuffer>& buffer, const sp<Fence>& acquireFence, nsecs_t postTime,
- nsecs_t desiredPresentTime, bool isAutoTimestamp,
- const client_cache_t& clientCacheId, uint64_t frameNumber,
+ bool setBuffer(const std::shared_ptr<renderengine::ExternalTexture>& buffer,
+ const sp<Fence>& acquireFence, nsecs_t postTime, nsecs_t desiredPresentTime,
+ bool isAutoTimestamp, const client_cache_t& clientCacheId, uint64_t frameNumber,
std::optional<nsecs_t> dequeueTime, const FrameTimelineInfo& info,
const sp<ITransactionCompletedListener>& transactionListener) override;
bool setAcquireFence(const sp<Fence>& fence) override;
@@ -81,23 +76,16 @@ public:
bool setTransactionCompletedListeners(const std::vector<sp<CallbackHandle>>& handles) override;
bool addFrameEvent(const sp<Fence>& acquireFence, nsecs_t postedTime,
nsecs_t requestedPresentTime) override;
+ bool setPosition(float /*x*/, float /*y*/) override;
+ bool setMatrix(const layer_state_t::matrix22_t& /*matrix*/,
+ bool /*allowNonRectPreservingTransforms*/);
// Override to ignore legacy layer state properties that are not used by BufferStateLayer
bool setSize(uint32_t /*w*/, uint32_t /*h*/) override { return false; }
- bool setPosition(float /*x*/, float /*y*/) override { return false; }
bool setTransparentRegionHint(const Region& transparent) override;
- bool setMatrix(const layer_state_t::matrix22_t& /*matrix*/,
- bool /*allowNonRectPreservingTransforms*/) override {
- return false;
- }
- void deferTransactionUntil_legacy(const sp<IBinder>& /*barrierHandle*/,
- uint64_t /*frameNumber*/) override {}
- void deferTransactionUntil_legacy(const sp<Layer>& /*barrierLayer*/,
- uint64_t /*frameNumber*/) override {}
Rect getBufferSize(const State& s) const override;
FloatRect computeSourceBounds(const FloatRect& parentBounds) const override;
- Layer::RoundedCornerState getRoundedCornerState() const override;
void setAutoRefresh(bool autoRefresh) override;
// -----------------------------------------------------------------------
@@ -112,7 +100,7 @@ public:
// See mPendingBufferTransactions
void decrementPendingBufferCount();
- void bufferMayChange(sp<GraphicBuffer>& newBuffer) override;
+ void bufferMayChange(const sp<GraphicBuffer>& newBuffer) override;
std::atomic<int32_t>* getPendingBufferCounter() override { return &mPendingBufferTransactions; }
std::string getPendingBufferCounterName() override { return mBlastTransactionName; }
@@ -152,7 +140,7 @@ private:
sp<Layer> createClone() override;
// Crop that applies to the buffer
- Rect computeCrop(const State& s);
+ Rect computeBufferCrop(const State& s);
bool willPresentCurrentTransaction() const;
@@ -169,7 +157,6 @@ private:
uint64_t mPreviousBufferId = 0;
uint64_t mPreviousReleasedFrameNumber = 0;
- mutable bool mCurrentStateModified = false;
bool mReleasePreviousBuffer = false;
// Stores the last set acquire fence signal time used to populate the callback handle's acquire
diff --git a/services/surfaceflinger/ClientCache.cpp b/services/surfaceflinger/ClientCache.cpp
index 44b33ef43d..f310738423 100644
--- a/services/surfaceflinger/ClientCache.cpp
+++ b/services/surfaceflinger/ClientCache.cpp
@@ -102,7 +102,12 @@ bool ClientCache::add(const client_cache_t& cacheId, const sp<GraphicBuffer>& bu
return false;
}
- processBuffers[id].buffer = buffer;
+ LOG_ALWAYS_FATAL_IF(mRenderEngine == nullptr,
+ "Attempted to build the ClientCache before a RenderEngine instance was "
+ "ready!");
+ processBuffers[id].buffer = std::make_shared<
+ renderengine::ExternalTexture>(buffer, *mRenderEngine,
+ renderengine::ExternalTexture::Usage::READABLE);
return true;
}
@@ -132,7 +137,7 @@ void ClientCache::erase(const client_cache_t& cacheId) {
}
}
-sp<GraphicBuffer> ClientCache::get(const client_cache_t& cacheId) {
+std::shared_ptr<renderengine::ExternalTexture> ClientCache::get(const client_cache_t& cacheId) {
std::lock_guard lock(mMutex);
ClientCacheBuffer* buf = nullptr;
@@ -213,8 +218,8 @@ void ClientCache::dump(std::string& result) {
auto &buffers = i.second.second;
for (auto& [id, clientCacheBuffer] : buffers) {
StringAppendF(&result, "\t ID: %d, Width/Height: %d,%d\n", (int)id,
- (int)clientCacheBuffer.buffer->getWidth(),
- (int)clientCacheBuffer.buffer->getHeight());
+ (int)clientCacheBuffer.buffer->getBuffer()->getWidth(),
+ (int)clientCacheBuffer.buffer->getBuffer()->getHeight());
}
}
}
diff --git a/services/surfaceflinger/ClientCache.h b/services/surfaceflinger/ClientCache.h
index 0d597c8e05..a9b8177d70 100644
--- a/services/surfaceflinger/ClientCache.h
+++ b/services/surfaceflinger/ClientCache.h
@@ -19,6 +19,7 @@
#include <android-base/thread_annotations.h>
#include <binder/IBinder.h>
#include <gui/LayerState.h>
+#include <renderengine/RenderEngine.h>
#include <ui/GraphicBuffer.h>
#include <utils/RefBase.h>
#include <utils/Singleton.h>
@@ -39,7 +40,11 @@ public:
bool add(const client_cache_t& cacheId, const sp<GraphicBuffer>& buffer);
void erase(const client_cache_t& cacheId);
- sp<GraphicBuffer> get(const client_cache_t& cacheId);
+ std::shared_ptr<renderengine::ExternalTexture> get(const client_cache_t& cacheId);
+
+ // Always called immediately after setup. Will be set to non-null, and then should never be
+ // called again.
+ void setRenderEngine(renderengine::RenderEngine* renderEngine) { mRenderEngine = renderEngine; }
void removeProcess(const wp<IBinder>& processToken);
@@ -59,7 +64,7 @@ private:
std::mutex mMutex;
struct ClientCacheBuffer {
- sp<GraphicBuffer> buffer;
+ std::shared_ptr<renderengine::ExternalTexture> buffer;
std::set<wp<ErasedRecipient>> recipients;
};
std::map<wp<IBinder> /*caching process*/,
@@ -73,6 +78,7 @@ private:
};
sp<CacheDeathRecipient> mDeathRecipient;
+ renderengine::RenderEngine* mRenderEngine = nullptr;
bool getBuffer(const client_cache_t& cacheId, ClientCacheBuffer** outClientCacheBuffer)
REQUIRES(mMutex);
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h
index a0606b48f0..289cb119ca 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h
@@ -79,6 +79,9 @@ struct CompositionRefreshArgs {
// If set, causes the dirty regions to flash with the delay
std::optional<std::chrono::microseconds> devOptFlashDirtyRegionsDelay;
+
+ // The earliest time to send the present command to the HAL
+ std::chrono::steady_clock::time_point earliestPresentTime;
};
} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
index 1fd07b01f4..791e7db75c 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
@@ -138,6 +138,9 @@ public:
// Gets the sequence number: a serial number that uniquely identifies a Layer
virtual int32_t getSequence() const = 0;
+
+ // Whether the layer should be rendered with rounded corners.
+ virtual bool hasRoundedCorners() const = 0;
};
// TODO(b/121291683): Specialize std::hash<> for sp<T> so these and others can
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h
index 27d0291caf..d0f7238a6a 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h
@@ -16,6 +16,7 @@
#pragma once
+#include <cstdint>
#include <optional>
#include <string>
@@ -95,8 +96,13 @@ public:
// Writes the geometry state to the HWC, or does nothing if this layer does
// not use the HWC. If includeGeometry is false, the geometry state can be
// skipped. If skipLayer is true, then the alpha of the layer is forced to
- // 0 so that HWC will ignore it.
- virtual void writeStateToHWC(bool includeGeometry, bool skipLayer) = 0;
+ // 0 so that HWC will ignore it. z specifies the order to draw the layer in
+ // (starting with 0 for the back layer, and increasing for each following
+ // layer). zIsOverridden specifies whether the layer has been reordered.
+ // isPeekingThrough specifies whether this layer will be shown through a
+ // hole punch in a layer above it.
+ virtual void writeStateToHWC(bool includeGeometry, bool skipLayer, uint32_t z,
+ bool zIsOverridden, bool isPeekingThrough) = 0;
// Updates the cursor position with the HWC
virtual void writeCursorPositionToHWC() const = 0;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h
index 4ef3973973..7d345907d9 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h
@@ -16,15 +16,16 @@
#pragma once
-#include <cstdint>
-#include <vector>
-
+#include <renderengine/ExternalTexture.h>
#include <ui/Fence.h>
#include <ui/GraphicTypes.h>
#include <ui/Size.h>
#include <utils/Errors.h>
#include <utils/StrongPointer.h>
+#include <cstdint>
+#include <vector>
+
namespace android {
class GraphicBuffer;
@@ -82,7 +83,8 @@ public:
virtual void prepareFrame(bool usesClientComposition, bool usesDeviceComposition) = 0;
// Allocates a buffer as scratch space for GPU composition
- virtual sp<GraphicBuffer> dequeueBuffer(base::unique_fd* bufferFence) = 0;
+ virtual std::shared_ptr<renderengine::ExternalTexture> dequeueBuffer(
+ base::unique_fd* bufferFence) = 0;
// Queues the drawn buffer for consumption by HWC. readyFence is the fence
// which will fire when the buffer is ready for consumption.
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurfaceCreationArgs.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurfaceCreationArgs.h
index a1230b3c4d..a8d372c562 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurfaceCreationArgs.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurfaceCreationArgs.h
@@ -45,6 +45,8 @@ struct RenderSurfaceCreationArgs {
// The DisplaySurface for this surface
sp<DisplaySurface> displaySurface;
+
+ size_t maxTextureCacheSize;
};
/**
@@ -81,6 +83,11 @@ public:
return *this;
}
+ RenderSurfaceCreationArgsBuilder& setMaxTextureCacheSize(size_t maxTextureCacheSize) {
+ mArgs.maxTextureCacheSize = maxTextureCacheSize;
+ return *this;
+ }
+
private:
RenderSurfaceCreationArgs mArgs;
};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
index 8f767d37f6..f0ef6d6e7d 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
@@ -115,6 +115,9 @@ struct OutputCompositionState {
// Current target dataspace
ui::Dataspace targetDataspace{ui::Dataspace::UNKNOWN};
+ // The earliest time to send the present command to the HAL
+ std::chrono::steady_clock::time_point earliestPresentTime;
+
// Debugging
void dump(std::string& result) const;
};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
index 83bca2d058..4dc7a3afe9 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
@@ -16,6 +16,7 @@
#pragma once
+#include <cstdint>
#include <memory>
#include <string>
@@ -47,7 +48,8 @@ public:
void updateCompositionState(bool includeGeometry, bool forceClientComposition,
ui::Transform::RotationFlags) override;
- void writeStateToHWC(bool includeGeometry, bool skipLayer) override;
+ void writeStateToHWC(bool includeGeometry, bool skipLayer, uint32_t z, bool zIsOverridden,
+ bool isPeekingThrough) override;
void writeCursorPositionToHWC() const override;
#ifdef QTI_UNIFIED_DRAW
void writeLayerFlagToHWC(IQtiComposerClient::LayerFlag) override;
@@ -73,7 +75,8 @@ protected:
private:
Rect calculateInitialCrop() const;
- void writeOutputDependentGeometryStateToHWC(HWC2::Layer*, Hwc2::IComposerClient::Composition);
+ void writeOutputDependentGeometryStateToHWC(HWC2::Layer*, Hwc2::IComposerClient::Composition,
+ uint32_t z);
void writeOutputIndependentGeometryStateToHWC(HWC2::Layer*, const LayerFECompositionState&,
bool skipLayer);
void writeOutputDependentPerFrameStateToHWC(HWC2::Layer*);
@@ -81,7 +84,8 @@ private:
void writeSolidColorStateToHWC(HWC2::Layer*, const LayerFECompositionState&);
void writeSidebandStateToHWC(HWC2::Layer*, const LayerFECompositionState&);
void writeBufferStateToHWC(HWC2::Layer*, const LayerFECompositionState&);
- void writeCompositionTypeToHWC(HWC2::Layer*, Hwc2::IComposerClient::Composition);
+ void writeCompositionTypeToHWC(HWC2::Layer*, Hwc2::IComposerClient::Composition,
+ bool isPeekingThrough);
void detectDisallowedCompositionTypeChange(Hwc2::IComposerClient::Composition from,
Hwc2::IComposerClient::Composition to) const;
};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h
index 4c065ec112..356965cf48 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h
@@ -18,7 +18,7 @@
#include <compositionengine/ProjectionSpace.h>
#include <compositionengine/impl/HwcBufferCache.h>
-#include <renderengine/Mesh.h>
+#include <renderengine/ExternalTexture.h>
#include <ui/FloatRect.h>
#include <ui/GraphicTypes.h>
#include <ui/Rect.h>
@@ -46,6 +46,10 @@ class Layer;
class HWComposer;
+namespace compositionengine {
+class OutputLayer;
+} // namespace compositionengine
+
namespace compositionengine::impl {
// Note that fields that affect HW composer state may need to be mirrored into
@@ -84,18 +88,21 @@ struct OutputLayerCompositionState {
// The dataspace for this layer
ui::Dataspace dataspace{ui::Dataspace::UNKNOWN};
- // The Z order index of this layer on this output
- uint32_t z{0};
-
// Overrides the buffer, acquire fence, and display frame stored in LayerFECompositionState
struct {
- sp<GraphicBuffer> buffer = nullptr;
+ std::shared_ptr<renderengine::ExternalTexture> buffer = nullptr;
sp<Fence> acquireFence = nullptr;
Rect displayFrame = {};
ui::Dataspace dataspace{ui::Dataspace::UNKNOWN};
ProjectionSpace displaySpace;
Region damageRegion = Region::INVALID_REGION;
Region visibleRegion;
+
+ // The OutputLayer pointed to by this field will be rearranged to draw
+ // behind the OutputLayer represented by this CompositionState and will
+ // be visible through it. Unowned - the OutputLayer's lifetime will
+ // outlast this.)
+ OutputLayer* peekThroughLayer = nullptr;
} overrideInfo;
/*
@@ -115,6 +122,9 @@ struct OutputLayerCompositionState {
// The buffer cache for this layer. This is used to lower the
// cost of sending reused buffers to the HWC.
HwcBufferCache hwcBufferCache;
+
+ // Set to true when overridden info has been sent to HW composer
+ bool stateOverridden = false;
};
// The HWC state is optional, and is only set up if there is any potential
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h
index ba5edc7fb9..6de7886180 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h
@@ -16,12 +16,16 @@
#pragma once
-#include <memory>
-
#include <android-base/unique_fd.h>
#include <compositionengine/RenderSurface.h>
#include <utils/StrongPointer.h>
+#include <memory>
+#include <vector>
+
+#include "renderengine/ExternalTexture.h"
+#include "renderengine/RenderEngine.h"
+
struct ANativeWindow;
namespace android {
@@ -56,7 +60,8 @@ public:
void setProtected(bool useProtected) override;
status_t beginFrame(bool mustRecompose) override;
void prepareFrame(bool usesClientComposition, bool usesDeviceComposition) override;
- sp<GraphicBuffer> dequeueBuffer(base::unique_fd* bufferFence) override;
+ std::shared_ptr<renderengine::ExternalTexture> dequeueBuffer(
+ base::unique_fd* bufferFence) override;
void queueBuffer(base::unique_fd readyFence) override;
void onPresentDisplayCompleted() override;
void flip() override;
@@ -68,7 +73,7 @@ public:
// Testing
void setPageFlipCountForTest(std::uint32_t);
void setSizeForTest(const ui::Size&);
- sp<GraphicBuffer>& mutableGraphicBufferForTest();
+ std::shared_ptr<renderengine::ExternalTexture>& mutableTextureForTest();
base::unique_fd& mutableBufferReadyForTest();
void flipClientTarget(bool flip) override;
void setViewportAndProjection() override;
@@ -79,10 +84,13 @@ private:
// ANativeWindow being rendered into
const sp<ANativeWindow> mNativeWindow;
- // Current buffer being rendered into
- sp<GraphicBuffer> mGraphicBuffer;
+
+ std::vector<std::shared_ptr<renderengine::ExternalTexture>> mTextureCache;
+ // Current texture being rendered into
+ std::shared_ptr<renderengine::ExternalTexture> mTexture;
const sp<DisplaySurface> mDisplaySurface;
ui::Size mSize;
+ const size_t mMaxTextureCacheSize;
bool mProtected{false};
bool mFlipClientTarget{false};
std::uint32_t mPageFlipCount{0};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h
index afa02cd0c2..a6c4eafbab 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h
@@ -66,10 +66,11 @@ public:
const Rect& getBounds() const { return mBounds; }
const Region& getVisibleRegion() const { return mVisibleRegion; }
size_t getAge() const { return mAge; }
- const sp<GraphicBuffer>& getBuffer() const { return mTexture.getBuffer(); }
+ const std::shared_ptr<renderengine::ExternalTexture>& getBuffer() const { return mTexture; }
const sp<Fence>& getDrawFence() const { return mDrawFence; }
const ProjectionSpace& getOutputSpace() const { return mOutputSpace; }
ui::Dataspace getOutputDataspace() const { return mOutputDataspace; }
+ const std::vector<Layer>& getConstituentLayers() const { return mLayers; }
NonBufferHash getNonBufferHash() const;
@@ -87,7 +88,7 @@ public:
void setLastUpdate(std::chrono::steady_clock::time_point now) { mLastUpdate = now; }
void append(const CachedSet& other) {
- mTexture.setBuffer(nullptr, nullptr);
+ mTexture = nullptr;
mOutputDataspace = ui::Dataspace::UNKNOWN;
mDrawFence = nullptr;
@@ -105,41 +106,37 @@ public:
void dump(std::string& result) const;
+ // Whether this represents a single layer with a buffer and rounded corners.
+ // If it is, we may be able to draw it by placing it behind another
+ // CachedSet and punching a hole.
+ bool requiresHolePunch() const;
+
+ // Add a layer that will be drawn behind this one. ::render() will render a
+ // hole in this CachedSet's buffer, allowing the supplied layer to peek
+ // through. Must be called before ::render().
+ // Will do nothing if this CachedSet is not opaque where the hole punch
+ // layer is displayed.
+ // If isFirstLayer is true, this CachedSet can be considered opaque because
+ // nothing (besides the hole punch layer) will be drawn behind it.
+ void addHolePunchLayerIfFeasible(const CachedSet&, bool isFirstLayer);
+
+ // Retrieve the layer that will be drawn behind this one.
+ OutputLayer* getHolePunchLayer() const;
+
private:
CachedSet() = default;
- NonBufferHash mFingerprint = 0;
+ const NonBufferHash mFingerprint;
std::chrono::steady_clock::time_point mLastUpdate = std::chrono::steady_clock::now();
std::vector<Layer> mLayers;
+
+ // Unowned.
+ const LayerState* mHolePunchLayer = nullptr;
Rect mBounds = Rect::EMPTY_RECT;
Region mVisibleRegion;
size_t mAge = 0;
- class Texture {
- public:
- ~Texture() { setBuffer(nullptr, nullptr); }
-
- void setBuffer(const sp<GraphicBuffer>& buffer, renderengine::RenderEngine* re) {
- if (mRE && mBuffer) {
- mRE->unbindExternalTextureBuffer(mBuffer->getId());
- }
-
- mBuffer = buffer;
- mRE = re;
-
- if (mRE && mBuffer) {
- mRE->cacheExternalTextureBuffer(mBuffer);
- }
- }
-
- const sp<GraphicBuffer>& getBuffer() const { return mBuffer; }
-
- private:
- sp<GraphicBuffer> mBuffer = nullptr;
- renderengine::RenderEngine* mRE = nullptr;
- };
-
- Texture mTexture;
+ std::shared_ptr<renderengine::ExternalTexture> mTexture;
sp<Fence> mDrawFence;
ProjectionSpace mOutputSpace;
ui::Dataspace mOutputDataspace;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h
index 313a180f4f..942592a9eb 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h
@@ -36,7 +36,8 @@ class Predictor;
class Flattener {
public:
- Flattener(Predictor& predictor) : mPredictor(predictor) {}
+ Flattener(Predictor& predictor, bool enableHolePunch = false)
+ : mEnableHolePunch(enableHolePunch), mPredictor(predictor) {}
void setDisplaySize(ui::Size size) { mDisplaySize = size; }
@@ -54,13 +55,14 @@ private:
void resetActivities(NonBufferHash, std::chrono::steady_clock::time_point now);
- void updateLayersHash();
+ NonBufferHash computeLayersHash() const;
bool mergeWithCachedSets(const std::vector<const LayerState*>& layers,
std::chrono::steady_clock::time_point now);
void buildCachedSets(std::chrono::steady_clock::time_point now);
+ const bool mEnableHolePunch;
Predictor& mPredictor;
ui::Size mDisplaySize;
@@ -69,7 +71,6 @@ private:
std::chrono::steady_clock::time_point mLastGeometryUpdate;
std::vector<CachedSet> mLayers;
- NonBufferHash mLayersHash = 0;
std::optional<CachedSet> mNewCachedSet;
// Statistics
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h
index 050e2643e5..3391273679 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h
@@ -53,20 +53,19 @@ enum class LayerStateField : uint32_t {
Name = 1u << 1,
DisplayFrame = 1u << 2,
SourceCrop = 1u << 3,
- ZOrder = 1u << 4,
- BufferTransform = 1u << 5,
- BlendMode = 1u << 6,
- Alpha = 1u << 7,
- LayerMetadata = 1u << 8,
- VisibleRegion = 1u << 9,
- Dataspace = 1u << 10,
- PixelFormat = 1u << 11,
- ColorTransform = 1u << 12,
- SurfaceDamage = 1u << 13,
- CompositionType = 1u << 14,
- SidebandStream = 1u << 15,
- Buffer = 1u << 16,
- SolidColor = 1u << 17,
+ BufferTransform = 1u << 4,
+ BlendMode = 1u << 5,
+ Alpha = 1u << 6,
+ LayerMetadata = 1u << 7,
+ VisibleRegion = 1u << 8,
+ Dataspace = 1u << 9,
+ PixelFormat = 1u << 10,
+ ColorTransform = 1u << 11,
+ SurfaceDamage = 1u << 12,
+ CompositionType = 1u << 13,
+ SidebandStream = 1u << 14,
+ Buffer = 1u << 15,
+ SolidColor = 1u << 16,
};
// clang-format on
@@ -271,9 +270,6 @@ private:
rect.top, rect.right, rect.bottom)};
}};
- OutputLayerState<uint32_t, LayerStateField::ZOrder> mZOrder{
- [](auto layer) { return layer->getState().z; }};
-
using BufferTransformState = OutputLayerState<hardware::graphics::composer::hal::Transform,
LayerStateField::BufferTransform>;
BufferTransformState mBufferTransform{[](auto layer) {
@@ -360,14 +356,6 @@ private:
OutputLayerState<mat4, LayerStateField::ColorTransform> mColorTransform;
- using SurfaceDamageState = OutputLayerState<Region, LayerStateField::SurfaceDamage>;
- SurfaceDamageState
- mSurfaceDamage{[](auto layer) {
- return layer->getLayerFE().getCompositionState()->surfaceDamage;
- },
- SurfaceDamageState::getRegionToStrings(),
- SurfaceDamageState::getRegionEquals()};
-
using CompositionTypeState = OutputLayerState<hardware::graphics::composer::hal::Composition,
LayerStateField::CompositionType>;
CompositionTypeState
@@ -410,7 +398,7 @@ private:
return std::vector<std::string>{stream.str()};
}};
- static const constexpr size_t kNumNonUniqueFields = 16;
+ static const constexpr size_t kNumNonUniqueFields = 14;
std::array<StateInterface*, kNumNonUniqueFields> getNonUniqueFields() {
std::array<const StateInterface*, kNumNonUniqueFields> constFields =
@@ -425,10 +413,10 @@ private:
std::array<const StateInterface*, kNumNonUniqueFields> getNonUniqueFields() const {
return {
- &mDisplayFrame, &mSourceCrop, &mZOrder, &mBufferTransform,
- &mBlendMode, &mAlpha, &mLayerMetadata, &mVisibleRegion,
- &mOutputDataspace, &mPixelFormat, &mColorTransform, &mSurfaceDamage,
- &mCompositionType, &mSidebandStream, &mBuffer, &mSolidColor,
+ &mDisplayFrame, &mSourceCrop, &mBufferTransform, &mBlendMode,
+ &mAlpha, &mLayerMetadata, &mVisibleRegion, &mOutputDataspace,
+ &mPixelFormat, &mColorTransform, &mCompositionType, &mSidebandStream,
+ &mBuffer, &mSolidColor,
};
}
};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Planner.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Planner.h
index e6d2b636a3..c2037a899e 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Planner.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Planner.h
@@ -41,7 +41,7 @@ namespace compositionengine::impl::planner {
// as a more efficient representation of parts of the layer stack.
class Planner {
public:
- Planner() : mFlattener(mPredictor) {}
+ Planner();
void setDisplaySize(ui::Size);
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
index dde8999524..d215bda891 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
@@ -43,6 +43,7 @@ public:
MOCK_CONST_METHOD0(getDebugName, const char*());
MOCK_CONST_METHOD0(getSequence, int32_t());
+ MOCK_CONST_METHOD0(hasRoundedCorners, bool());
};
} // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h
index 04c316e7dc..2942200d45 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h
@@ -22,9 +22,11 @@
#include <compositionengine/OutputLayer.h>
#include <compositionengine/impl/OutputLayerCompositionState.h>
#include <gmock/gmock.h>
+#include <cstdint>
#ifdef QTI_UNIFIED_DRAW
#include <vendor/qti/hardware/display/composer/3.1/IQtiComposerClient.h>
#endif
+
namespace android::compositionengine::mock {
#ifdef QTI_UNIFIED_DRAW
using vendor::qti::hardware::display::composer::V3_1::IQtiComposerClient;
@@ -43,7 +45,8 @@ public:
MOCK_METHOD0(editState, impl::OutputLayerCompositionState&());
MOCK_METHOD3(updateCompositionState, void(bool, bool, ui::Transform::RotationFlags));
- MOCK_METHOD2(writeStateToHWC, void(bool, bool));
+
+ MOCK_METHOD5(writeStateToHWC, void(bool, bool, uint32_t, bool, bool));
#ifdef QTI_UNIFIED_DRAW
MOCK_METHOD1(writeLayerFlagToHWC, void(IQtiComposerClient::LayerFlag));
#endif
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
index 2f9c0875f0..29ebb44564 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
@@ -41,7 +41,7 @@ public:
MOCK_METHOD1(setBufferPixelFormat, void(ui::PixelFormat));
MOCK_METHOD1(beginFrame, status_t(bool mustRecompose));
MOCK_METHOD2(prepareFrame, void(bool, bool));
- MOCK_METHOD1(dequeueBuffer, sp<GraphicBuffer>(base::unique_fd*));
+ MOCK_METHOD1(dequeueBuffer, std::shared_ptr<renderengine::ExternalTexture>(base::unique_fd*));
MOCK_METHOD1(queueBuffer, void(base::unique_fd));
MOCK_METHOD1(flipClientTarget, void(bool flip));
MOCK_METHOD0(onPresentDisplayCompleted, void());
diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp
index be8f3214fe..82dfc9fbb6 100644
--- a/services/surfaceflinger/CompositionEngine/src/Display.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp
@@ -411,6 +411,11 @@ compositionengine::Output::FrameFences Display::presentAndGetFrameFences() {
return fences;
}
+ {
+ ATRACE_NAME("wait for earliest present time");
+ std::this_thread::sleep_until(getState().earliestPresentTime);
+ }
+
auto& hwc = getCompositionEngine().getHwComposer();
hwc.presentAndGetReleaseFences(*halDisplayIdOpt);
diff --git a/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp
index 430945ab4c..ff7d430531 100644
--- a/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp
@@ -78,6 +78,20 @@ void LayerFECompositionState::dump(std::string& out) const {
dumpVal(out, "stretchEffect", stretchEffect);
}
+ if (!blurRegions.empty()) {
+ out.append("\n blurRegions {");
+ for (const auto& region : blurRegions) {
+ out.append("\n ");
+ base::StringAppendF(&out,
+ "{radius=%du, cornerRadii=[%f, %f, %f, %f], alpha=%f, rect=[%d, "
+ "%d, %d, %d]",
+ region.blurRadius, region.cornerRadiusTL, region.cornerRadiusTR,
+ region.cornerRadiusBL, region.cornerRadiusBR, region.alpha,
+ region.left, region.top, region.right, region.bottom);
+ }
+ out.append("\n }\n ");
+ }
+
if (!metadata.empty()) {
out.append("\n metadata {");
for (const auto& [key, entry] : metadata) {
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index 708956d4e9..23b3ec4b49 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#include <thread>
-
+#include <SurfaceFlingerProperties.sysprop.h>
#include <android-base/stringprintf.h>
#include <compositionengine/CompositionEngine.h>
#include <compositionengine/CompositionRefreshArgs.h>
@@ -29,7 +28,9 @@
#include <compositionengine/impl/OutputLayerCompositionState.h>
#include <compositionengine/impl/planner/Planner.h>
-#include <SurfaceFlingerProperties.sysprop.h>
+#include <thread>
+
+#include "renderengine/ExternalTexture.h"
// TODO(b/129481165): remove the #pragma below and fix conversion issues
#pragma clang diagnostic push
@@ -458,12 +459,6 @@ void Output::collectVisibleLayers(const compositionengine::CompositionRefreshArg
setReleasedLayers(refreshArgs);
finalizePendingOutputLayers();
-
- // Generate a simple Z-order values to each visible output layer
- uint32_t zOrder = 0;
- for (auto* outputLayer : getOutputLayersOrderedByZ()) {
- outputLayer->editState().z = zOrder++;
- }
}
void Output::ensureOutputLayerIfVisible(sp<compositionengine::LayerFE>& layerFE,
@@ -728,6 +723,9 @@ void Output::writeCompositionState(const compositionengine::CompositionRefreshAr
return;
}
+ editState().earliestPresentTime = refreshArgs.earliestPresentTime;
+
+ OutputLayer* peekThroughLayer = nullptr;
bool hasSecureCamera = false;
bool hasSecureDisplay = false;
bool needsProtected = false;
@@ -744,22 +742,43 @@ void Output::writeCompositionState(const compositionengine::CompositionRefreshAr
}
sp<GraphicBuffer> previousOverride = nullptr;
+ bool includeGeometry = refreshArgs.updatingGeometryThisFrame;
+ uint32_t z = 0;
+ bool overrideZ = false;
for (auto* layer : getOutputLayersOrderedByZ()) {
+ if (layer == peekThroughLayer) {
+ // No longer needed, although it should not show up again, so
+ // resetting it is not truly needed either.
+ peekThroughLayer = nullptr;
+
+ // peekThroughLayer was already drawn ahead of its z order.
+ continue;
+ }
bool skipLayer = false;
- if (layer->getState().overrideInfo.buffer != nullptr) {
- if (previousOverride != nullptr &&
- layer->getState().overrideInfo.buffer == previousOverride) {
+ const auto& overrideInfo = layer->getState().overrideInfo;
+ if (overrideInfo.buffer != nullptr) {
+ if (previousOverride && overrideInfo.buffer->getBuffer() == previousOverride) {
ALOGV("Skipping redundant buffer");
skipLayer = true;
+ } else {
+ // First layer with the override buffer.
+ if (overrideInfo.peekThroughLayer) {
+ peekThroughLayer = overrideInfo.peekThroughLayer;
+
+ // Draw peekThroughLayer first.
+ overrideZ = true;
+ includeGeometry = true;
+ constexpr bool isPeekingThrough = true;
+ peekThroughLayer->writeStateToHWC(includeGeometry, false, z++, overrideZ,
+ isPeekingThrough);
+ }
+
+ previousOverride = overrideInfo.buffer->getBuffer();
}
- previousOverride = layer->getState().overrideInfo.buffer;
}
- // TODO(b/181172795): We now update geometry for all flattened layers. We should update it
- // only when the geometry actually changes
- const bool includeGeometry = refreshArgs.updatingGeometryThisFrame ||
- layer->getState().overrideInfo.buffer != nullptr || skipLayer;
- layer->writeStateToHWC(includeGeometry, skipLayer);
+ constexpr bool isPeekingThrough = false;
+ layer->writeStateToHWC(includeGeometry, skipLayer, z++, overrideZ, isPeekingThrough);
#ifdef QTI_UNIFIED_DRAW
if (hasSecureCamera || hasSecureDisplay || needsProtected) {
layer->writeLayerFlagToHWC(IQtiComposerClient::LayerFlag::DEFAULT);
@@ -1041,14 +1060,15 @@ std::optional<base::unique_fd> Output::composeSurfaces(
}
base::unique_fd fd;
- sp<GraphicBuffer> buf;
+
+ std::shared_ptr<renderengine::ExternalTexture> tex;
// If we aren't doing client composition on this output, but do have a
// flipClientTarget request for this frame on this output, we still need to
// dequeue a buffer.
if (hasClientComposition || outputState.flipClientTarget) {
- buf = mRenderSurface->dequeueBuffer(&fd);
- if (buf == nullptr) {
+ tex = mRenderSurface->dequeueBuffer(&fd);
+ if (tex == nullptr) {
ALOGW("Dequeuing buffer for display [%s] failed, bailing out of "
"client composition for this frame",
mName.c_str());
@@ -1093,13 +1113,14 @@ std::optional<base::unique_fd> Output::composeSurfaces(
// Check if the client composition requests were rendered into the provided graphic buffer. If
// so, we can reuse the buffer and avoid client composition.
if (mClientCompositionRequestCache) {
- if (mClientCompositionRequestCache->exists(buf->getId(), clientCompositionDisplay,
+ if (mClientCompositionRequestCache->exists(tex->getBuffer()->getId(),
+ clientCompositionDisplay,
clientCompositionLayers)) {
outputCompositionState.reusedClientComposition = true;
setExpensiveRenderingExpected(false);
return readyFence;
}
- mClientCompositionRequestCache->add(buf->getId(), clientCompositionDisplay,
+ mClientCompositionRequestCache->add(tex->getBuffer()->getId(), clientCompositionDisplay,
clientCompositionLayers);
}
@@ -1132,12 +1153,12 @@ std::optional<base::unique_fd> Output::composeSurfaces(
// over to RenderEngine, in which case this flag can be removed from the drawLayers interface.
const bool useFramebufferCache = outputState.layerStackInternal;
status_t status =
- renderEngine.drawLayers(clientCompositionDisplay, clientCompositionLayerPointers, buf,
+ renderEngine.drawLayers(clientCompositionDisplay, clientCompositionLayerPointers, tex,
useFramebufferCache, std::move(fd), &readyFence);
if (status != NO_ERROR && mClientCompositionRequestCache) {
// If rendering was not successful, remove the request from the cache.
- mClientCompositionRequestCache->remove(buf->getId());
+ mClientCompositionRequestCache->remove(tex->getBuffer()->getId());
}
auto& timeStats = getCompositionEngine().getTimeStats();
@@ -1214,9 +1235,9 @@ std::vector<LayerFE::LayerSettings> Output::generateClientCompositionRequests(
std::vector<LayerFE::LayerSettings> results;
if (layer->getState().overrideInfo.buffer != nullptr) {
- if (layer->getState().overrideInfo.buffer != previousOverrideBuffer) {
+ if (layer->getState().overrideInfo.buffer->getBuffer() != previousOverrideBuffer) {
results = layer->getOverrideCompositionList();
- previousOverrideBuffer = layer->getState().overrideInfo.buffer;
+ previousOverrideBuffer = layer->getState().overrideInfo.buffer->getBuffer();
ALOGV("Replacing [%s] with override in RE", layer->getLayerFE().getDebugName());
} else {
ALOGV("Skipping redundant override buffer for [%s] in RE",
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
index 0df25401c3..7b1376c0b7 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -21,6 +21,7 @@
#include <compositionengine/impl/OutputCompositionState.h>
#include <compositionengine/impl/OutputLayer.h>
#include <compositionengine/impl/OutputLayerCompositionState.h>
+#include <cstdint>
// TODO(b/129481165): remove the #pragma below and fix conversion issues
#pragma clang diagnostic push
@@ -317,7 +318,8 @@ void OutputLayer::updateCompositionState(
}
}
-void OutputLayer::writeStateToHWC(bool includeGeometry, bool skipLayer) {
+void OutputLayer::writeStateToHWC(bool includeGeometry, bool skipLayer, uint32_t z,
+ bool zIsOverridden, bool isPeekingThrough) {
const auto& state = getState();
// Skip doing this if there is no HWC interface
if (!state.hwc) {
@@ -338,8 +340,13 @@ void OutputLayer::writeStateToHWC(bool includeGeometry, bool skipLayer) {
auto requestedCompositionType = outputIndependentState->compositionType;
- if (includeGeometry) {
- writeOutputDependentGeometryStateToHWC(hwcLayer.get(), requestedCompositionType);
+ // TODO(b/181172795): We now update geometry for all flattened layers. We should update it
+ // only when the geometry actually changes
+ const bool isOverridden =
+ state.overrideInfo.buffer != nullptr || isPeekingThrough || zIsOverridden;
+ const bool prevOverridden = state.hwc->stateOverridden;
+ if (isOverridden || prevOverridden || skipLayer || includeGeometry) {
+ writeOutputDependentGeometryStateToHWC(hwcLayer.get(), requestedCompositionType, z);
writeOutputIndependentGeometryStateToHWC(hwcLayer.get(), *outputIndependentState,
skipLayer);
}
@@ -347,14 +354,17 @@ void OutputLayer::writeStateToHWC(bool includeGeometry, bool skipLayer) {
writeOutputDependentPerFrameStateToHWC(hwcLayer.get());
writeOutputIndependentPerFrameStateToHWC(hwcLayer.get(), *outputIndependentState);
- writeCompositionTypeToHWC(hwcLayer.get(), requestedCompositionType);
+ writeCompositionTypeToHWC(hwcLayer.get(), requestedCompositionType, isPeekingThrough);
// Always set the layer color after setting the composition type.
writeSolidColorStateToHWC(hwcLayer.get(), *outputIndependentState);
+
+ editState().hwc->stateOverridden = isOverridden;
}
-void OutputLayer::writeOutputDependentGeometryStateToHWC(
- HWC2::Layer* hwcLayer, hal::Composition requestedCompositionType) {
+void OutputLayer::writeOutputDependentGeometryStateToHWC(HWC2::Layer* hwcLayer,
+ hal::Composition requestedCompositionType,
+ uint32_t z) {
const auto& outputDependentState = getState();
Rect displayFrame = outputDependentState.displayFrame;
@@ -362,7 +372,12 @@ void OutputLayer::writeOutputDependentGeometryStateToHWC(
if (outputDependentState.overrideInfo.buffer != nullptr) {
displayFrame = outputDependentState.overrideInfo.displayFrame;
- sourceCrop = displayFrame.toFloatRect();
+ sourceCrop =
+ FloatRect(0.f, 0.f,
+ static_cast<float>(outputDependentState.overrideInfo.buffer->getBuffer()
+ ->getWidth()),
+ static_cast<float>(outputDependentState.overrideInfo.buffer->getBuffer()
+ ->getHeight()));
}
ALOGV("Writing display frame [%d, %d, %d, %d]", displayFrame.left, displayFrame.top,
@@ -381,9 +396,9 @@ void OutputLayer::writeOutputDependentGeometryStateToHWC(
sourceCrop.bottom, to_string(error).c_str(), static_cast<int32_t>(error));
}
- if (auto error = hwcLayer->setZOrder(outputDependentState.z); error != hal::Error::NONE) {
- ALOGE("[%s] Failed to set Z %u: %s (%d)", getLayerFE().getDebugName(),
- outputDependentState.z, to_string(error).c_str(), static_cast<int32_t>(error));
+ if (auto error = hwcLayer->setZOrder(z); error != hal::Error::NONE) {
+ ALOGE("[%s] Failed to set Z %u: %s (%d)", getLayerFE().getDebugName(), z,
+ to_string(error).c_str(), static_cast<int32_t>(error));
}
// Solid-color layers and overridden buffers should always use an identity transform.
@@ -402,7 +417,10 @@ void OutputLayer::writeOutputDependentGeometryStateToHWC(
void OutputLayer::writeOutputIndependentGeometryStateToHWC(
HWC2::Layer* hwcLayer, const LayerFECompositionState& outputIndependentState,
bool skipLayer) {
- const auto blendMode = getState().overrideInfo.buffer
+ // If there is a peekThroughLayer, then this layer has a hole in it. We need to use
+ // PREMULTIPLIED so it will peek through.
+ const auto& overrideInfo = getState().overrideInfo;
+ const auto blendMode = overrideInfo.buffer || overrideInfo.peekThroughLayer
? hardware::graphics::composer::hal::BlendMode::PREMULTIPLIED
: outputIndependentState.blendMode;
if (auto error = hwcLayer->setBlendMode(blendMode); error != hal::Error::NONE) {
@@ -542,7 +560,7 @@ void OutputLayer::writeBufferStateToHWC(HWC2::Layer* hwcLayer,
sp<GraphicBuffer> buffer = outputIndependentState.buffer;
sp<Fence> acquireFence = outputIndependentState.acquireFence;
if (getState().overrideInfo.buffer != nullptr) {
- buffer = getState().overrideInfo.buffer;
+ buffer = getState().overrideInfo.buffer->getBuffer();
acquireFence = getState().overrideInfo.acquireFence;
}
@@ -563,11 +581,13 @@ void OutputLayer::writeBufferStateToHWC(HWC2::Layer* hwcLayer,
}
void OutputLayer::writeCompositionTypeToHWC(HWC2::Layer* hwcLayer,
- hal::Composition requestedCompositionType) {
+ hal::Composition requestedCompositionType,
+ bool isPeekingThrough) {
auto& outputDependentState = editState();
// If we are forcing client composition, we need to tell the HWC
- if (outputDependentState.forceClientComposition) {
+ if (outputDependentState.forceClientComposition ||
+ (!isPeekingThrough && getLayerFE().hasRoundedCorners())) {
requestedCompositionType = hal::Composition::CLIENT;
}
@@ -720,7 +740,7 @@ std::vector<LayerFE::LayerSettings> OutputLayer::getOverrideCompositionList() co
settings.geometry = renderengine::Geometry{
.boundaries = boundaries.toFloatRect(),
};
- settings.bufferId = getState().overrideInfo.buffer->getId();
+ settings.bufferId = getState().overrideInfo.buffer->getBuffer()->getId();
settings.source = renderengine::PixelSource{
.buffer = renderengine::Buffer{
.buffer = getState().overrideInfo.buffer,
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp
index efd23dce98..b4c314c8d4 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp
@@ -67,7 +67,6 @@ void OutputLayerCompositionState::dump(std::string& out) const {
dumpVal(out, "sourceCrop", sourceCrop);
dumpVal(out, "bufferTransform", toString(bufferTransform), bufferTransform);
dumpVal(out, "dataspace", toString(dataspace), dataspace);
- dumpVal(out, "z-index", z);
dumpVal(out, "override buffer", overrideInfo.buffer.get());
dumpVal(out, "override acquire fence", overrideInfo.acquireFence.get());
dumpVal(out, "override display frame", overrideInfo.displayFrame);
diff --git a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
index eca34729ae..ead245d85d 100644
--- a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
@@ -25,8 +25,8 @@
#include <compositionengine/impl/DumpHelpers.h>
#include <compositionengine/impl/OutputCompositionState.h>
#include <compositionengine/impl/RenderSurface.h>
-
#include <log/log.h>
+#include <renderengine/ExternalTexture.h>
#include <renderengine/RenderEngine.h>
#include <system/window.h>
#include <ui/GraphicBuffer.h>
@@ -63,7 +63,8 @@ RenderSurface::RenderSurface(const CompositionEngine& compositionEngine, Display
mDisplay(display),
mNativeWindow(args.nativeWindow),
mDisplaySurface(args.displaySurface),
- mSize(args.displayWidth, args.displayHeight) {
+ mSize(args.displayWidth, args.displayHeight),
+ mMaxTextureCacheSize(args.maxTextureCacheSize) {
LOG_ALWAYS_FATAL_IF(!mNativeWindow);
}
@@ -154,7 +155,8 @@ void RenderSurface::prepareFrame(bool usesClientComposition, bool usesDeviceComp
}
}
-sp<GraphicBuffer> RenderSurface::dequeueBuffer(base::unique_fd* bufferFence) {
+std::shared_ptr<renderengine::ExternalTexture> RenderSurface::dequeueBuffer(
+ base::unique_fd* bufferFence) {
ATRACE_CALL();
int fd = -1;
ANativeWindowBuffer* buffer = nullptr;
@@ -166,16 +168,41 @@ sp<GraphicBuffer> RenderSurface::dequeueBuffer(base::unique_fd* bufferFence) {
mDisplay.getName().c_str(), result);
// Return fast here as we can't do much more - any rendering we do
// now will just be wrong.
- return mGraphicBuffer;
+ return mTexture;
+ }
+
+ ALOGW_IF(mTexture != nullptr, "Clobbering a non-null pointer to a buffer [%p].",
+ mTexture->getBuffer()->getNativeBuffer()->handle);
+
+ sp<GraphicBuffer> newBuffer = GraphicBuffer::from(buffer);
+
+ std::shared_ptr<renderengine::ExternalTexture> texture;
+
+ for (auto it = mTextureCache.begin(); it != mTextureCache.end(); it++) {
+ const auto& cachedTexture = *it;
+ if (cachedTexture->getBuffer()->getId() == newBuffer->getId()) {
+ texture = cachedTexture;
+ mTextureCache.erase(it);
+ break;
+ }
}
- ALOGW_IF(mGraphicBuffer != nullptr, "Clobbering a non-null pointer to a buffer [%p].",
- mGraphicBuffer->getNativeBuffer()->handle);
- mGraphicBuffer = GraphicBuffer::from(buffer);
+ if (texture) {
+ mTexture = texture;
+ } else {
+ mTexture = std::make_shared<
+ renderengine::ExternalTexture>(GraphicBuffer::from(buffer),
+ mCompositionEngine.getRenderEngine(),
+ renderengine::ExternalTexture::Usage::WRITEABLE);
+ }
+ mTextureCache.push_back(mTexture);
+ if (mTextureCache.size() > mMaxTextureCacheSize) {
+ mTextureCache.erase(mTextureCache.begin());
+ }
*bufferFence = base::unique_fd(fd);
- return mGraphicBuffer;
+ return mTexture;
}
void RenderSurface::queueBuffer(base::unique_fd readyFence) {
@@ -186,24 +213,24 @@ void RenderSurface::queueBuffer(base::unique_fd readyFence) {
// hasFlipClientTargetRequest could return true even if we haven't
// dequeued a buffer before. Try dequeueing one if we don't have a
// buffer ready.
- if (mGraphicBuffer == nullptr) {
+ if (mTexture == nullptr) {
ALOGI("Attempting to queue a client composited buffer without one "
"previously dequeued for display [%s]. Attempting to dequeue "
"a scratch buffer now",
mDisplay.getName().c_str());
- // We shouldn't deadlock here, since mGraphicBuffer == nullptr only
+ // We shouldn't deadlock here, since mTexture == nullptr only
// after a successful call to queueBuffer, or if dequeueBuffer has
// never been called.
base::unique_fd unused;
dequeueBuffer(&unused);
}
- if (mGraphicBuffer == nullptr) {
+ if (mTexture == nullptr) {
ALOGE("No buffer is ready for display [%s]", mDisplay.getName().c_str());
} else {
status_t result =
mNativeWindow->queueBuffer(mNativeWindow.get(),
- mGraphicBuffer->getNativeBuffer(),
+ mTexture->getBuffer()->getNativeBuffer(),
mFlipClientTarget ? -1 : dup(readyFence));
if (result != NO_ERROR) {
ALOGE("Error when queueing buffer for display [%s]: %d", mDisplay.getName().c_str(),
@@ -214,12 +241,12 @@ void RenderSurface::queueBuffer(base::unique_fd readyFence) {
LOG_ALWAYS_FATAL("ANativeWindow::queueBuffer failed with error: %d", result);
} else {
mNativeWindow->cancelBuffer(mNativeWindow.get(),
- mGraphicBuffer->getNativeBuffer(),
+ mTexture->getBuffer()->getNativeBuffer(),
mFlipClientTarget ? -1 : dup(readyFence));
}
}
- mGraphicBuffer = nullptr;
+ mTexture = nullptr;
}
}
@@ -273,8 +300,8 @@ void RenderSurface::setSizeForTest(const ui::Size& size) {
mSize = size;
}
-sp<GraphicBuffer>& RenderSurface::mutableGraphicBufferForTest() {
- return mGraphicBuffer;
+std::shared_ptr<renderengine::ExternalTexture>& RenderSurface::mutableTextureForTest() {
+ return mTexture;
}
void RenderSurface::flipClientTarget(bool flip) {
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
index dcb75556e3..b31e89e247 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
@@ -130,7 +130,7 @@ bool CachedSet::hasBufferUpdate() const {
}
bool CachedSet::hasReadyBuffer() const {
- return mTexture.getBuffer() != nullptr && mDrawFence->getStatus() == Fence::Status::Signaled;
+ return mTexture != nullptr && mDrawFence->getStatus() == Fence::Status::Signaled;
}
std::vector<CachedSet> CachedSet::decompose() const {
@@ -193,6 +193,23 @@ void CachedSet::render(renderengine::RenderEngine& renderEngine,
std::transform(layerSettings.cbegin(), layerSettings.cend(),
std::back_inserter(layerSettingsPointers),
[](const renderengine::LayerSettings& settings) { return &settings; });
+ renderengine::LayerSettings holePunchSettings;
+ if (mHolePunchLayer) {
+ auto clientCompositionList =
+ mHolePunchLayer->getOutputLayer()->getLayerFE().prepareClientCompositionList(
+ targetSettings);
+ // Assume that the final layer contains the buffer that we want to
+ // replace with a hole punch.
+ holePunchSettings = clientCompositionList.back();
+ LOG_ALWAYS_FATAL_IF(!holePunchSettings.source.buffer.buffer, "Expected to have a buffer!");
+ // This mimics Layer::prepareClearClientComposition
+ holePunchSettings.source.buffer.buffer = nullptr;
+ holePunchSettings.source.solidColor = half3(0.0f, 0.0f, 0.0f);
+ holePunchSettings.disableBlending = true;
+ holePunchSettings.alpha = 0.0f;
+ holePunchSettings.name = std::string("hole punch layer");
+ layerSettingsPointers.push_back(&holePunchSettings);
+ }
if (sDebugHighlighLayers) {
highlight = {
@@ -217,22 +234,78 @@ void CachedSet::render(renderengine::RenderEngine& renderEngine,
sp<GraphicBuffer> buffer = new GraphicBuffer(static_cast<uint32_t>(mBounds.getWidth()),
static_cast<uint32_t>(mBounds.getHeight()),
HAL_PIXEL_FORMAT_RGBA_8888, 1, usageFlags);
+ const auto texture = std::make_shared<
+ renderengine::ExternalTexture>(buffer, renderEngine,
+ renderengine::ExternalTexture::Usage::READABLE |
+ renderengine::ExternalTexture::Usage::WRITEABLE);
LOG_ALWAYS_FATAL_IF(buffer->initCheck() != OK);
base::unique_fd drawFence;
- status_t result = renderEngine.drawLayers(displaySettings, layerSettingsPointers, buffer, false,
- base::unique_fd(), &drawFence);
+ status_t result = renderEngine.drawLayers(displaySettings, layerSettingsPointers, texture,
+ false, base::unique_fd(), &drawFence);
if (result == NO_ERROR) {
- mTexture.setBuffer(buffer, &renderEngine);
mDrawFence = new Fence(drawFence.release());
mOutputSpace = ProjectionSpace(ui::Size(outputState.framebufferSpace.bounds.getWidth(),
outputState.framebufferSpace.bounds.getHeight()),
mBounds);
+ mTexture = std::move(texture);
mOutputSpace.orientation = outputState.framebufferSpace.orientation;
mOutputDataspace = outputDataspace;
mOrientation = orientation;
+ } else {
+ mTexture = nullptr;
+ }
+}
+
+bool CachedSet::requiresHolePunch() const {
+ // In order for the hole punch to be beneficial, the layer must be updating
+ // regularly, meaning it should not have been merged with other layers.
+ if (getLayerCount() != 1) {
+ return false;
}
+
+ // There is no benefit to a hole punch unless the layer has a buffer.
+ if (!mLayers[0].getBuffer()) {
+ return false;
+ }
+
+ const auto& layerFE = mLayers[0].getState()->getOutputLayer()->getLayerFE();
+ if (layerFE.getCompositionState()->forceClientComposition) {
+ return false;
+ }
+
+ return layerFE.hasRoundedCorners();
+}
+
+namespace {
+bool contains(const Rect& outer, const Rect& inner) {
+ return outer.left <= inner.left && outer.right >= inner.right && outer.top <= inner.top &&
+ outer.bottom >= inner.bottom;
+}
+}; // namespace
+
+void CachedSet::addHolePunchLayerIfFeasible(const CachedSet& holePunchLayer, bool isFirstLayer) {
+ // Verify that this CachedSet is opaque where the hole punch layer
+ // will draw.
+ const Rect& holePunchBounds = holePunchLayer.getBounds();
+ for (const auto& layer : mLayers) {
+ // The first layer is considered opaque because nothing is behind it.
+ // Note that isOpaque is always false for a layer with rounded
+ // corners, even if the interior is opaque. In theory, such a layer
+ // could be used for a hole punch, but this is unlikely to happen in
+ // practice.
+ const auto* outputLayer = layer.getState()->getOutputLayer();
+ if (contains(outputLayer->getState().displayFrame, holePunchBounds) &&
+ (isFirstLayer || outputLayer->getLayerFE().getCompositionState()->isOpaque)) {
+ mHolePunchLayer = holePunchLayer.getFirstLayer().getState();
+ return;
+ }
+ }
+}
+
+OutputLayer* CachedSet::getHolePunchLayer() const {
+ return mHolePunchLayer ? mHolePunchLayer->getOutputLayer() : nullptr;
}
void CachedSet::dump(std::string& result) const {
@@ -242,6 +315,11 @@ void CachedSet::dump(std::string& result) const {
std::chrono::duration_cast<std::chrono::milliseconds>(now - mLastUpdate);
base::StringAppendF(&result, " + Fingerprint %016zx, last update %sago, age %zd\n",
mFingerprint, durationString(lastUpdate).c_str(), mAge);
+ {
+ const auto b = mTexture ? mTexture->getBuffer().get() : nullptr;
+ base::StringAppendF(&result, " Override buffer: %p\n", b);
+ }
+ base::StringAppendF(&result, " HolePunchLayer: %p\n", mHolePunchLayer);
if (mLayers.size() == 1) {
base::StringAppendF(&result, " Layer [%s]\n", mLayers[0].getName().c_str());
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
index ffca5baab7..b4e761004f 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
@@ -27,12 +27,44 @@ using namespace std::chrono_literals;
namespace android::compositionengine::impl::planner {
+namespace {
+
+// True if the underlying layer stack is the same modulo state that would be expected to be
+// different like specific buffers, false otherwise.
+bool isSameStack(const std::vector<const LayerState*>& incomingLayers,
+ const std::vector<CachedSet>& cachedSets) {
+ std::vector<const LayerState*> existingLayers;
+ for (auto& cachedSet : cachedSets) {
+ for (auto& layer : cachedSet.getConstituentLayers()) {
+ existingLayers.push_back(layer.getState());
+ }
+ }
+
+ if (incomingLayers.size() != existingLayers.size()) {
+ return false;
+ }
+
+ for (size_t i = 0; i < incomingLayers.size(); i++) {
+ if (incomingLayers[i]->getDifferingFields(*(existingLayers[i])) != LayerStateField::None) {
+ return false;
+ }
+ }
+ return true;
+}
+
+} // namespace
+
NonBufferHash Flattener::flattenLayers(const std::vector<const LayerState*>& layers,
NonBufferHash hash, time_point now) {
const size_t unflattenedDisplayCost = calculateDisplayCost(layers);
mUnflattenedDisplayCost += unflattenedDisplayCost;
- if (mCurrentGeometry != hash) {
+ // We invalidate the layer cache if:
+ // 1. We're not tracking any layers, or
+ // 2. The last seen hashed geometry changed between frames, or
+ // 3. A stricter equality check demonstrates that the layer stack really did change, since the
+ // hashed geometry does not guarantee uniqueness.
+ if (mCurrentGeometry != hash || (!mLayers.empty() && !isSameStack(layers, mLayers))) {
resetActivities(hash, now);
mFlattenedDisplayCost += unflattenedDisplayCost;
return hash;
@@ -40,13 +72,17 @@ NonBufferHash Flattener::flattenLayers(const std::vector<const LayerState*>& lay
++mInitialLayerCounts[layers.size()];
- if (mergeWithCachedSets(layers, now)) {
- hash = mLayersHash;
- }
+ // Only buildCachedSets if these layers are already stored in mLayers.
+ // Otherwise (i.e. mergeWithCachedSets returns false), the time has not
+ // changed, so buildCachedSets will never find any runs.
+ const bool alreadyHadCachedSets = mergeWithCachedSets(layers, now);
++mFinalLayerCounts[mLayers.size()];
- buildCachedSets(now);
+ if (alreadyHadCachedSets) {
+ buildCachedSets(now);
+ hash = computeLayersHash();
+ }
return hash;
}
@@ -157,14 +193,17 @@ void Flattener::resetActivities(NonBufferHash hash, time_point now) {
}
}
-void Flattener::updateLayersHash() {
+NonBufferHash Flattener::computeLayersHash() const{
size_t hash = 0;
for (const auto& layer : mLayers) {
android::hashCombineSingleHashed(hash, layer.getNonBufferHash());
}
- mLayersHash = hash;
+ return hash;
}
+// Only called if the geometry matches the last frame. Return true if mLayers
+// was already populated with these layers, i.e. on the second and following
+// calls with the same geometry.
bool Flattener::mergeWithCachedSets(const std::vector<const LayerState*>& layers, time_point now) {
std::vector<CachedSet> merged;
@@ -202,6 +241,7 @@ bool Flattener::mergeWithCachedSets(const std::vector<const LayerState*>& layers
ALOGV("[%s] Found ready buffer", __func__);
size_t skipCount = mNewCachedSet->getLayerCount();
while (skipCount != 0) {
+ auto* peekThroughLayer = mNewCachedSet->getHolePunchLayer();
const size_t layerCount = currentLayerIter->getLayerCount();
for (size_t i = 0; i < layerCount; ++i) {
OutputLayer::CompositionState& state =
@@ -214,6 +254,7 @@ bool Flattener::mergeWithCachedSets(const std::vector<const LayerState*>& layers
.displaySpace = mNewCachedSet->getOutputSpace(),
.damageRegion = Region::INVALID_REGION,
.visibleRegion = mNewCachedSet->getVisibleRegion(),
+ .peekThroughLayer = peekThroughLayer,
};
++incomingLayerIter;
}
@@ -237,6 +278,7 @@ bool Flattener::mergeWithCachedSets(const std::vector<const LayerState*>& layers
// Skip the incoming layers corresponding to this valid current layer
const size_t layerCount = currentLayerIter->getLayerCount();
+ auto* peekThroughLayer = currentLayerIter->getHolePunchLayer();
for (size_t i = 0; i < layerCount; ++i) {
OutputLayer::CompositionState& state =
(*incomingLayerIter)->getOutputLayer()->editState();
@@ -248,6 +290,7 @@ bool Flattener::mergeWithCachedSets(const std::vector<const LayerState*>& layers
.displaySpace = currentLayerIter->getOutputSpace(),
.damageRegion = Region(),
.visibleRegion = currentLayerIter->getVisibleRegion(),
+ .peekThroughLayer = peekThroughLayer,
};
++incomingLayerIter;
}
@@ -272,7 +315,6 @@ bool Flattener::mergeWithCachedSets(const std::vector<const LayerState*>& layers
}
mLayers = std::move(merged);
- updateLayersHash();
return true;
}
@@ -292,6 +334,11 @@ void Flattener::buildCachedSets(time_point now) {
std::vector<Run> runs;
bool isPartOfRun = false;
+
+ // Keep track of the layer that follows a run. It's possible that we will
+ // render it with a hole-punch.
+ const CachedSet* holePunchLayer = nullptr;
+
for (auto currentSet = mLayers.cbegin(); currentSet != mLayers.cend(); ++currentSet) {
if (now - currentSet->getLastUpdate() > kActiveLayerTimeout) {
// Layer is inactive
@@ -306,10 +353,20 @@ void Flattener::buildCachedSets(time_point now) {
isPartOfRun = true;
}
}
- } else {
+ } else if (isPartOfRun) {
// Runs must be at least 2 sets long or there's nothing to combine
- if (isPartOfRun && runs.back().start->getLayerCount() == runs.back().length) {
+ if (runs.back().start->getLayerCount() == runs.back().length) {
runs.pop_back();
+ } else {
+ // The prior run contained at least two sets. Currently, we'll
+ // only possibly merge a single run, so only keep track of a
+ // holePunchLayer if this is the first run.
+ if (runs.size() == 1) {
+ holePunchLayer = &(*currentSet);
+ }
+
+ // TODO(b/185114532: Break out of the loop? We may find more runs, but we
+ // won't do anything with them.
}
isPartOfRun = false;
@@ -335,6 +392,13 @@ void Flattener::buildCachedSets(time_point now) {
mNewCachedSet->append(*currentSet);
}
+ if (mEnableHolePunch && holePunchLayer && holePunchLayer->requiresHolePunch()) {
+ // Add the pip layer to mNewCachedSet, but in a special way - it should
+ // replace the buffer with a clear round rect.
+ mNewCachedSet->addHolePunchLayerIfFeasible(*holePunchLayer,
+ runs[0].start == mLayers.cbegin());
+ }
+
// TODO(b/181192467): Actually compute new LayerState vector and corresponding hash for each run
mPredictor.getPredictedPlan({}, 0);
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp b/services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp
index 7c32e944fc..8423a124cf 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp
@@ -155,13 +155,11 @@ std::optional<std::string> LayerState::compare(const LayerState& other) const {
bool operator==(const LayerState& lhs, const LayerState& rhs) {
return lhs.mId == rhs.mId && lhs.mName == rhs.mName && lhs.mDisplayFrame == rhs.mDisplayFrame &&
- lhs.mSourceCrop == rhs.mSourceCrop && lhs.mZOrder == rhs.mZOrder &&
- lhs.mBufferTransform == rhs.mBufferTransform && lhs.mBlendMode == rhs.mBlendMode &&
- lhs.mAlpha == rhs.mAlpha && lhs.mLayerMetadata == rhs.mLayerMetadata &&
- lhs.mVisibleRegion == rhs.mVisibleRegion &&
+ lhs.mSourceCrop == rhs.mSourceCrop && lhs.mBufferTransform == rhs.mBufferTransform &&
+ lhs.mBlendMode == rhs.mBlendMode && lhs.mAlpha == rhs.mAlpha &&
+ lhs.mLayerMetadata == rhs.mLayerMetadata && lhs.mVisibleRegion == rhs.mVisibleRegion &&
lhs.mOutputDataspace == rhs.mOutputDataspace && lhs.mPixelFormat == rhs.mPixelFormat &&
lhs.mColorTransform == rhs.mColorTransform &&
- lhs.mSurfaceDamage == rhs.mSurfaceDamage &&
lhs.mCompositionType == rhs.mCompositionType &&
lhs.mSidebandStream == rhs.mSidebandStream && lhs.mBuffer == rhs.mBuffer &&
(lhs.mCompositionType.get() != hal::Composition::SOLID_COLOR ||
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp b/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp
index ad7555730d..7d2bf06133 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp
@@ -19,12 +19,17 @@
#undef LOG_TAG
#define LOG_TAG "Planner"
+#include <android-base/properties.h>
#include <compositionengine/LayerFECompositionState.h>
#include <compositionengine/impl/OutputLayerCompositionState.h>
#include <compositionengine/impl/planner/Planner.h>
namespace android::compositionengine::impl::planner {
+Planner::Planner()
+ : mFlattener(mPredictor,
+ base::GetBoolProperty(std::string("debug.sf.enable_hole_punch_pip"), false)) {}
+
void Planner::setDisplaySize(ui::Size size) {
mFlattener.setDisplaySize(size);
}
@@ -111,7 +116,12 @@ void Planner::reportFinalPlan(
const GraphicBuffer* currentOverrideBuffer = nullptr;
bool hasSkippedLayers = false;
for (auto layer : layers) {
- const GraphicBuffer* overrideBuffer = layer->getState().overrideInfo.buffer.get();
+ if (!layer->getState().overrideInfo.buffer) {
+ continue;
+ }
+
+ const GraphicBuffer* overrideBuffer =
+ layer->getState().overrideInfo.buffer->getBuffer().get();
if (overrideBuffer != nullptr && overrideBuffer == currentOverrideBuffer) {
// Skip this layer since it is part of a previous cached set
hasSkippedLayers = true;
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
index 8a4d161289..fb8ffcedf3 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
@@ -23,6 +23,8 @@
#include <gtest/gtest.h>
#include <log/log.h>
+#include <renderengine/mock/RenderEngine.h>
+#include <ui/PixelFormat.h>
#include "MockHWC2.h"
#include "MockHWComposer.h"
#include "RegionMatcher.h"
@@ -688,7 +690,6 @@ TEST_F(OutputLayerUpdateCompositionStateTest, clientCompositionForcedFromArgumen
struct OutputLayerWriteStateToHWCTest : public OutputLayerTest {
static constexpr hal::Error kError = hal::Error::UNSUPPORTED;
static constexpr FloatRect kSourceCrop{11.f, 12.f, 13.f, 14.f};
- static constexpr uint32_t kZOrder = 21u;
static constexpr Hwc2::Transform kBufferTransform = static_cast<Hwc2::Transform>(31);
static constexpr Hwc2::Transform kOverrideBufferTransform = static_cast<Hwc2::Transform>(0);
static constexpr Hwc2::IComposerClient::BlendMode kBlendMode =
@@ -707,6 +708,7 @@ struct OutputLayerWriteStateToHWCTest : public OutputLayerTest {
static const half4 kColor;
static const Rect kDisplayFrame;
static const Rect kOverrideDisplayFrame;
+ static const FloatRect kOverrideSourceCrop;
static const Region kOutputSpaceVisibleRegion;
static const Region kOverrideVisibleRegion;
static const mat4 kColorTransform;
@@ -729,7 +731,6 @@ struct OutputLayerWriteStateToHWCTest : public OutputLayerTest {
outputLayerState.displayFrame = kDisplayFrame;
outputLayerState.sourceCrop = kSourceCrop;
- outputLayerState.z = kZOrder;
outputLayerState.bufferTransform = static_cast<Hwc2::Transform>(kBufferTransform);
outputLayerState.outputSpaceVisibleRegion = kOutputSpaceVisibleRegion;
outputLayerState.dataspace = kDataspace;
@@ -764,7 +765,11 @@ struct OutputLayerWriteStateToHWCTest : public OutputLayerTest {
void includeOverrideInfo() {
auto& overrideInfo = mOutputLayer.editState().overrideInfo;
- overrideInfo.buffer = kOverrideBuffer;
+ overrideInfo.buffer = std::make_shared<
+ renderengine::ExternalTexture>(kOverrideBuffer, mRenderEngine,
+ renderengine::ExternalTexture::Usage::READABLE |
+ renderengine::ExternalTexture::Usage::
+ WRITEABLE);
overrideInfo.acquireFence = kOverrideFence;
overrideInfo.displayFrame = kOverrideDisplayFrame;
overrideInfo.dataspace = kOverrideDataspace;
@@ -779,7 +784,7 @@ struct OutputLayerWriteStateToHWCTest : public OutputLayerTest {
float alpha = kAlpha) {
EXPECT_CALL(*mHwcLayer, setDisplayFrame(displayFrame)).WillOnce(Return(kError));
EXPECT_CALL(*mHwcLayer, setSourceCrop(sourceCrop)).WillOnce(Return(kError));
- EXPECT_CALL(*mHwcLayer, setZOrder(kZOrder)).WillOnce(Return(kError));
+ EXPECT_CALL(*mHwcLayer, setZOrder(_)).WillOnce(Return(kError));
EXPECT_CALL(*mHwcLayer, setTransform(bufferTransform)).WillOnce(Return(kError));
EXPECT_CALL(*mHwcLayer, setBlendMode(blendMode)).WillOnce(Return(kError));
@@ -839,12 +844,14 @@ struct OutputLayerWriteStateToHWCTest : public OutputLayerTest {
std::shared_ptr<HWC2::mock::Layer> mHwcLayer{std::make_shared<StrictMock<HWC2::mock::Layer>>()};
StrictMock<mock::DisplayColorProfile> mDisplayColorProfile;
+ renderengine::mock::RenderEngine mRenderEngine;
};
const half4 OutputLayerWriteStateToHWCTest::kColor{81.f / 255.f, 82.f / 255.f, 83.f / 255.f,
84.f / 255.f};
const Rect OutputLayerWriteStateToHWCTest::kDisplayFrame{1001, 1002, 1003, 10044};
const Rect OutputLayerWriteStateToHWCTest::kOverrideDisplayFrame{1002, 1003, 1004, 20044};
+const FloatRect OutputLayerWriteStateToHWCTest::kOverrideSourceCrop{0.f, 0.f, 4.f, 5.f};
const Region OutputLayerWriteStateToHWCTest::kOutputSpaceVisibleRegion{
Rect{1005, 1006, 1007, 1008}};
const Region OutputLayerWriteStateToHWCTest::kOverrideVisibleRegion{Rect{1006, 1007, 1008, 1009}};
@@ -858,7 +865,10 @@ const HdrMetadata OutputLayerWriteStateToHWCTest::kHdrMetadata{{/* LightFlattena
native_handle_t* OutputLayerWriteStateToHWCTest::kSidebandStreamHandle =
reinterpret_cast<native_handle_t*>(1031);
const sp<GraphicBuffer> OutputLayerWriteStateToHWCTest::kBuffer;
-const sp<GraphicBuffer> OutputLayerWriteStateToHWCTest::kOverrideBuffer = new GraphicBuffer();
+const sp<GraphicBuffer> OutputLayerWriteStateToHWCTest::kOverrideBuffer =
+ new GraphicBuffer(4, 5, PIXEL_FORMAT_RGBA_8888,
+ AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN |
+ AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN);
const sp<Fence> OutputLayerWriteStateToHWCTest::kFence;
const sp<Fence> OutputLayerWriteStateToHWCTest::kOverrideFence = new Fence();
const std::string OutputLayerWriteStateToHWCTest::kLayerGenericMetadata1Key =
@@ -872,19 +882,22 @@ const std::vector<uint8_t> OutputLayerWriteStateToHWCTest::kLayerGenericMetadata
TEST_F(OutputLayerWriteStateToHWCTest, doesNothingIfNoFECompositionState) {
EXPECT_CALL(*mLayerFE, getCompositionState()).WillOnce(Return(nullptr));
- mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false);
+ mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0,
+ /*zIsOverridden*/ false, /*isPeekingThrough*/ false);
}
TEST_F(OutputLayerWriteStateToHWCTest, doesNothingIfNoHWCState) {
mOutputLayer.editState().hwc.reset();
- mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false);
+ mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0,
+ /*zIsOverridden*/ false, /*isPeekingThrough*/ false);
}
TEST_F(OutputLayerWriteStateToHWCTest, doesNothingIfNoHWCLayer) {
mOutputLayer.editState().hwc = impl::OutputLayerCompositionState::Hwc(nullptr);
- mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false);
+ mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0,
+ /*zIsOverridden*/ false, /*isPeekingThrough*/ false);
}
TEST_F(OutputLayerWriteStateToHWCTest, canSetAllState) {
@@ -892,8 +905,10 @@ TEST_F(OutputLayerWriteStateToHWCTest, canSetAllState) {
expectPerFrameCommonCalls();
expectNoSetCompositionTypeCall();
+ EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillOnce(Return(false));
- mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false);
+ mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0,
+ /*zIsOverridden*/ false, /*isPeekingThrough*/ false);
}
TEST_F(OutputLayerTest, displayInstallOrientationBufferTransformSetTo90) {
@@ -915,6 +930,7 @@ TEST_F(OutputLayerWriteStateToHWCTest, canSetPerFrameStateForSolidColor) {
mLayerFEState.compositionType = Hwc2::IComposerClient::Composition::SOLID_COLOR;
expectPerFrameCommonCalls();
+ EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillOnce(Return(false));
// Setting the composition type should happen before setting the color. We
// check this in this test only by setting up an testing::InSeqeuence
@@ -923,7 +939,8 @@ TEST_F(OutputLayerWriteStateToHWCTest, canSetPerFrameStateForSolidColor) {
expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::SOLID_COLOR);
expectSetColorCall();
- mOutputLayer.writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false);
+ mOutputLayer.writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, 0,
+ /*zIsOverridden*/ false, /*isPeekingThrough*/ false);
}
TEST_F(OutputLayerWriteStateToHWCTest, canSetPerFrameStateForSideband) {
@@ -933,7 +950,10 @@ TEST_F(OutputLayerWriteStateToHWCTest, canSetPerFrameStateForSideband) {
expectSetSidebandHandleCall();
expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::SIDEBAND);
- mOutputLayer.writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false);
+ EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillOnce(Return(false));
+
+ mOutputLayer.writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, 0,
+ /*zIsOverridden*/ false, /*isPeekingThrough*/ false);
}
TEST_F(OutputLayerWriteStateToHWCTest, canSetPerFrameStateForCursor) {
@@ -943,7 +963,10 @@ TEST_F(OutputLayerWriteStateToHWCTest, canSetPerFrameStateForCursor) {
expectSetHdrMetadataAndBufferCalls();
expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::CURSOR);
- mOutputLayer.writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false);
+ EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillOnce(Return(false));
+
+ mOutputLayer.writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, 0,
+ /*zIsOverridden*/ false, /*isPeekingThrough*/ false);
}
TEST_F(OutputLayerWriteStateToHWCTest, canSetPerFrameStateForDevice) {
@@ -953,7 +976,10 @@ TEST_F(OutputLayerWriteStateToHWCTest, canSetPerFrameStateForDevice) {
expectSetHdrMetadataAndBufferCalls();
expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::DEVICE);
- mOutputLayer.writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false);
+ EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillOnce(Return(false));
+
+ mOutputLayer.writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, 0,
+ /*zIsOverridden*/ false, /*isPeekingThrough*/ false);
}
TEST_F(OutputLayerWriteStateToHWCTest, compositionTypeIsNotSetIfUnchanged) {
@@ -966,7 +992,10 @@ TEST_F(OutputLayerWriteStateToHWCTest, compositionTypeIsNotSetIfUnchanged) {
expectSetColorCall();
expectNoSetCompositionTypeCall();
- mOutputLayer.writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false);
+ EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillOnce(Return(false));
+
+ mOutputLayer.writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, 0,
+ /*zIsOverridden*/ false, /*isPeekingThrough*/ false);
}
TEST_F(OutputLayerWriteStateToHWCTest, compositionTypeIsSetToClientIfColorTransformNotSupported) {
@@ -976,7 +1005,8 @@ TEST_F(OutputLayerWriteStateToHWCTest, compositionTypeIsSetToClientIfColorTransf
expectSetColorCall();
expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::CLIENT);
- mOutputLayer.writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false);
+ mOutputLayer.writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, 0,
+ /*zIsOverridden*/ false, /*isPeekingThrough*/ false);
}
TEST_F(OutputLayerWriteStateToHWCTest, compositionTypeIsSetToClientIfClientCompositionForced) {
@@ -988,7 +1018,8 @@ TEST_F(OutputLayerWriteStateToHWCTest, compositionTypeIsSetToClientIfClientCompo
expectSetColorCall();
expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::CLIENT);
- mOutputLayer.writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false);
+ mOutputLayer.writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, 0,
+ /*zIsOverridden*/ false, /*isPeekingThrough*/ false);
}
TEST_F(OutputLayerWriteStateToHWCTest, allStateIncludesMetadataIfPresent) {
@@ -1001,7 +1032,10 @@ TEST_F(OutputLayerWriteStateToHWCTest, allStateIncludesMetadataIfPresent) {
expectGenericLayerMetadataCalls();
expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::DEVICE);
- mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false);
+ EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillOnce(Return(false));
+
+ mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0,
+ /*zIsOverridden*/ false, /*isPeekingThrough*/ false);
}
TEST_F(OutputLayerWriteStateToHWCTest, perFrameStateDoesNotIncludeMetadataIfPresent) {
@@ -1012,21 +1046,27 @@ TEST_F(OutputLayerWriteStateToHWCTest, perFrameStateDoesNotIncludeMetadataIfPres
expectSetHdrMetadataAndBufferCalls();
expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::DEVICE);
- mOutputLayer.writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false);
+ EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillOnce(Return(false));
+
+ mOutputLayer.writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, 0,
+ /*zIsOverridden*/ false, /*isPeekingThrough*/ false);
}
TEST_F(OutputLayerWriteStateToHWCTest, includesOverrideInfoIfPresent) {
mLayerFEState.compositionType = Hwc2::IComposerClient::Composition::DEVICE;
includeOverrideInfo();
- expectGeometryCommonCalls(kOverrideDisplayFrame, kOverrideDisplayFrame.toFloatRect(),
- kOverrideBufferTransform, kOverrideBlendMode, kOverrideAlpha);
+ expectGeometryCommonCalls(kOverrideDisplayFrame, kOverrideSourceCrop, kOverrideBufferTransform,
+ kOverrideBlendMode, kOverrideAlpha);
expectPerFrameCommonCalls(SimulateUnsupported::None, kOverrideDataspace, kOverrideVisibleRegion,
kOverrideSurfaceDamage);
expectSetHdrMetadataAndBufferCalls(kOverrideBuffer, kOverrideFence);
expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::DEVICE);
- mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false);
+ EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillOnce(Return(false));
+
+ mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0,
+ /*zIsOverridden*/ false, /*isPeekingThrough*/ false);
}
/*
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index 5f0b0eea15..7b71957021 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -14,8 +14,6 @@
* limitations under the License.
*/
-#include <cmath>
-
#include <android-base/stringprintf.h>
#include <compositionengine/LayerFECompositionState.h>
#include <compositionengine/impl/Output.h>
@@ -31,9 +29,13 @@
#include <ui/Rect.h>
#include <ui/Region.h>
+#include <cmath>
+#include <cstdint>
+
#include "CallOrderStateMachineHelper.h"
#include "MockHWC2.h"
#include "RegionMatcher.h"
+#include "renderengine/ExternalTexture.h"
namespace android::compositionengine {
namespace {
@@ -782,15 +784,19 @@ TEST_F(OutputUpdateAndWriteCompositionStateTest, updatesLayerContentForAllLayers
InjectedLayer layer2;
InjectedLayer layer3;
+ uint32_t z = 0;
EXPECT_CALL(*layer1.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_180));
EXPECT_CALL(*layer1.outputLayer,
- writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false));
+ writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++,
+ /*zIsOverridden*/ false, /*isPeekingThrough*/ false));
EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_180));
EXPECT_CALL(*layer2.outputLayer,
- writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false));
+ writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++,
+ /*zIsOverridden*/ false, /*isPeekingThrough*/ false));
EXPECT_CALL(*layer3.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_180));
EXPECT_CALL(*layer3.outputLayer,
- writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false));
+ writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++,
+ /*zIsOverridden*/ false, /*isPeekingThrough*/ false));
injectOutputLayer(layer1);
injectOutputLayer(layer2);
@@ -812,15 +818,19 @@ TEST_F(OutputUpdateAndWriteCompositionStateTest, updatesLayerGeometryAndContentF
InjectedLayer layer2;
InjectedLayer layer3;
+ uint32_t z = 0;
EXPECT_CALL(*layer1.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0));
EXPECT_CALL(*layer1.outputLayer,
- writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false));
+ writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, z++,
+ /*zIsOverridden*/ false, /*isPeekingThrough*/ false));
EXPECT_CALL(*layer2.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0));
EXPECT_CALL(*layer2.outputLayer,
- writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false));
+ writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, z++,
+ /*zIsOverridden*/ false, /*isPeekingThrough*/ false));
EXPECT_CALL(*layer3.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0));
EXPECT_CALL(*layer3.outputLayer,
- writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false));
+ writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, z++,
+ /*zIsOverridden*/ false, /*isPeekingThrough*/ false));
injectOutputLayer(layer1);
injectOutputLayer(layer2);
@@ -841,15 +851,19 @@ TEST_F(OutputUpdateAndWriteCompositionStateTest, forcesClientCompositionForAllLa
InjectedLayer layer2;
InjectedLayer layer3;
+ uint32_t z = 0;
EXPECT_CALL(*layer1.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0));
EXPECT_CALL(*layer1.outputLayer,
- writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false));
+ writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++,
+ /*zIsOverridden*/ false, /*isPeekingThrough*/ false));
EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0));
EXPECT_CALL(*layer2.outputLayer,
- writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false));
+ writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++,
+ /*zIsOverridden*/ false, /*isPeekingThrough*/ false));
EXPECT_CALL(*layer3.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0));
EXPECT_CALL(*layer3.outputLayer,
- writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false));
+ writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++,
+ /*zIsOverridden*/ false, /*isPeekingThrough*/ false));
injectOutputLayer(layer1);
injectOutputLayer(layer2);
@@ -1143,11 +1157,6 @@ TEST_F(OutputCollectVisibleLayersTest, processesCandidateLayersReversedAndSetsOu
EXPECT_CALL(mOutput, finalizePendingOutputLayers());
mOutput.collectVisibleLayers(mRefreshArgs, mCoverageState);
-
- // Ensure all output layers have been assigned a simple/flattened z-order.
- EXPECT_EQ(0u, mLayer1.outputLayerState.z);
- EXPECT_EQ(1u, mLayer2.outputLayerState.z);
- EXPECT_EQ(2u, mLayer3.outputLayerState.z);
}
/*
@@ -2960,7 +2969,10 @@ struct OutputComposeSurfacesTest : public testing::Test {
mock::DisplayColorProfile* mDisplayColorProfile = new StrictMock<mock::DisplayColorProfile>();
mock::RenderSurface* mRenderSurface = new StrictMock<mock::RenderSurface>();
StrictMock<OutputPartialMock> mOutput;
- sp<GraphicBuffer> mOutputBuffer = new GraphicBuffer();
+ std::shared_ptr<renderengine::ExternalTexture> mOutputBuffer = std::make_shared<
+ renderengine::ExternalTexture>(new GraphicBuffer(), mRenderEngine,
+ renderengine::ExternalTexture::Usage::READABLE |
+ renderengine::ExternalTexture::Usage::WRITEABLE);
std::optional<base::unique_fd> mReadyFence;
};
@@ -3173,7 +3185,10 @@ TEST_F(OutputComposeSurfacesTest, clientCompositionIfBufferChanges) {
EXPECT_CALL(mOutput, appendRegionFlashRequests(RegionEq(kDebugRegion), _))
.WillRepeatedly(Return());
- sp<GraphicBuffer> otherOutputBuffer = new GraphicBuffer();
+ const auto otherOutputBuffer = std::make_shared<
+ renderengine::ExternalTexture>(new GraphicBuffer(), mRenderEngine,
+ renderengine::ExternalTexture::Usage::READABLE |
+ renderengine::ExternalTexture::Usage::WRITEABLE);
EXPECT_CALL(*mRenderSurface, dequeueBuffer(_))
.WillOnce(Return(mOutputBuffer))
.WillOnce(Return(otherOutputBuffer));
@@ -3494,7 +3509,8 @@ struct OutputComposeSurfacesTest_SetsExpensiveRendering_ForBlur
EXPECT_CALL(mLayer.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0));
EXPECT_CALL(mLayer.outputLayer,
- writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false));
+ writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, 0,
+ /*zIsOverridden*/ false, /*isPeekingThrough*/ false));
EXPECT_CALL(mOutput, generateClientCompositionRequests(_, _, kDefaultOutputDataspace))
.WillOnce(Return(std::vector<LayerFE::LayerSettings>{}));
EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, false, _, _)).WillOnce(Return(NO_ERROR));
@@ -4073,16 +4089,20 @@ TEST_F(OutputUpdateAndWriteCompositionStateTest, handlesBackgroundBlurRequests)
InjectedLayer layer2;
InjectedLayer layer3;
+ uint32_t z = 0;
// Layer requesting blur, or below, should request client composition.
EXPECT_CALL(*layer1.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0));
EXPECT_CALL(*layer1.outputLayer,
- writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false));
+ writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++,
+ /*zIsOverridden*/ false, /*isPeekingThrough*/ false));
EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0));
EXPECT_CALL(*layer2.outputLayer,
- writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false));
+ writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++,
+ /*zIsOverridden*/ false, /*isPeekingThrough*/ false));
EXPECT_CALL(*layer3.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_0));
EXPECT_CALL(*layer3.outputLayer,
- writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false));
+ writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++,
+ /*zIsOverridden*/ false, /*isPeekingThrough*/ false));
layer2.layerFEState.backgroundBlurRadius = 10;
@@ -4105,16 +4125,20 @@ TEST_F(OutputUpdateAndWriteCompositionStateTest, handlesBlurRegionRequests) {
InjectedLayer layer2;
InjectedLayer layer3;
+ uint32_t z = 0;
// Layer requesting blur, or below, should request client composition.
EXPECT_CALL(*layer1.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0));
EXPECT_CALL(*layer1.outputLayer,
- writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false));
+ writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++,
+ /*zIsOverridden*/ false, /*isPeekingThrough*/ false));
EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0));
EXPECT_CALL(*layer2.outputLayer,
- writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false));
+ writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++,
+ /*zIsOverridden*/ false, /*isPeekingThrough*/ false));
EXPECT_CALL(*layer3.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_0));
EXPECT_CALL(*layer3.outputLayer,
- writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false));
+ writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++,
+ /*zIsOverridden*/ false, /*isPeekingThrough*/ false));
BlurRegion region;
layer2.layerFEState.blurRegions.push_back(region);
diff --git a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
index 5ef5d7b5cb..9aeb290eb5 100644
--- a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
@@ -15,6 +15,8 @@
*/
// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#include "renderengine/ExternalTexture.h"
+#include "ui/GraphicBuffer.h"
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wextra"
@@ -239,9 +241,9 @@ TEST_F(RenderSurfaceTest, dequeueBufferObtainsABuffer) {
DoAll(SetArgPointee<0>(buffer.get()), SetArgPointee<1>(-1), Return(NO_ERROR)));
base::unique_fd fence;
- EXPECT_EQ(buffer.get(), mSurface.dequeueBuffer(&fence).get());
+ EXPECT_EQ(buffer.get(), mSurface.dequeueBuffer(&fence)->getBuffer().get());
- EXPECT_EQ(buffer.get(), mSurface.mutableGraphicBufferForTest().get());
+ EXPECT_EQ(buffer.get(), mSurface.mutableTextureForTest()->getBuffer().get());
}
/*
@@ -249,8 +251,11 @@ TEST_F(RenderSurfaceTest, dequeueBufferObtainsABuffer) {
*/
TEST_F(RenderSurfaceTest, queueBufferHandlesNoClientComposition) {
- sp<GraphicBuffer> buffer = new GraphicBuffer();
- mSurface.mutableGraphicBufferForTest() = buffer;
+ const auto buffer = std::make_shared<
+ renderengine::ExternalTexture>(new GraphicBuffer(), mRenderEngine,
+ renderengine::ExternalTexture::Usage::READABLE |
+ renderengine::ExternalTexture::Usage::WRITEABLE);
+ mSurface.mutableTextureForTest() = buffer;
impl::OutputCompositionState state;
state.usesClientComposition = false;
@@ -261,43 +266,45 @@ TEST_F(RenderSurfaceTest, queueBufferHandlesNoClientComposition) {
mSurface.queueBuffer(base::unique_fd());
- EXPECT_EQ(buffer.get(), mSurface.mutableGraphicBufferForTest().get());
+ EXPECT_EQ(buffer.get(), mSurface.mutableTextureForTest().get());
}
TEST_F(RenderSurfaceTest, queueBufferHandlesClientComposition) {
- sp<GraphicBuffer> buffer = new GraphicBuffer();
- mSurface.mutableGraphicBufferForTest() = buffer;
+ const auto buffer = std::make_shared<renderengine::ExternalTexture>(new GraphicBuffer(),
+ mRenderEngine, false);
+ mSurface.mutableTextureForTest() = buffer;
impl::OutputCompositionState state;
state.usesClientComposition = true;
state.flipClientTarget = false;
EXPECT_CALL(mDisplay, getState()).WillOnce(ReturnRef(state));
- EXPECT_CALL(*mNativeWindow, queueBuffer(buffer->getNativeBuffer(), -1))
+ EXPECT_CALL(*mNativeWindow, queueBuffer(buffer->getBuffer()->getNativeBuffer(), -1))
.WillOnce(Return(NO_ERROR));
EXPECT_CALL(*mDisplaySurface, advanceFrame()).Times(1);
mSurface.queueBuffer(base::unique_fd());
- EXPECT_EQ(nullptr, mSurface.mutableGraphicBufferForTest().get());
+ EXPECT_EQ(nullptr, mSurface.mutableTextureForTest().get());
}
TEST_F(RenderSurfaceTest, queueBufferHandlesFlipClientTargetRequest) {
- sp<GraphicBuffer> buffer = new GraphicBuffer();
- mSurface.mutableGraphicBufferForTest() = buffer;
+ const auto buffer = std::make_shared<renderengine::ExternalTexture>(new GraphicBuffer(),
+ mRenderEngine, false);
+ mSurface.mutableTextureForTest() = buffer;
impl::OutputCompositionState state;
state.usesClientComposition = false;
state.flipClientTarget = true;
EXPECT_CALL(mDisplay, getState()).WillOnce(ReturnRef(state));
- EXPECT_CALL(*mNativeWindow, queueBuffer(buffer->getNativeBuffer(), -1))
+ EXPECT_CALL(*mNativeWindow, queueBuffer(buffer->getBuffer()->getNativeBuffer(), -1))
.WillOnce(Return(NO_ERROR));
EXPECT_CALL(*mDisplaySurface, advanceFrame()).Times(1);
mSurface.queueBuffer(base::unique_fd());
- EXPECT_EQ(nullptr, mSurface.mutableGraphicBufferForTest().get());
+ EXPECT_EQ(nullptr, mSurface.mutableTextureForTest().get());
}
TEST_F(RenderSurfaceTest, queueBufferHandlesFlipClientTargetRequestWithNoBufferYetDequeued) {
@@ -317,27 +324,28 @@ TEST_F(RenderSurfaceTest, queueBufferHandlesFlipClientTargetRequestWithNoBufferY
mSurface.queueBuffer(base::unique_fd());
- EXPECT_EQ(nullptr, mSurface.mutableGraphicBufferForTest().get());
+ EXPECT_EQ(nullptr, mSurface.mutableTextureForTest().get());
}
TEST_F(RenderSurfaceTest, queueBufferHandlesNativeWindowQueueBufferFailureOnVirtualDisplay) {
- sp<GraphicBuffer> buffer = new GraphicBuffer();
- mSurface.mutableGraphicBufferForTest() = buffer;
+ const auto buffer = std::make_shared<renderengine::ExternalTexture>(new GraphicBuffer(),
+ mRenderEngine, false);
+ mSurface.mutableTextureForTest() = buffer;
impl::OutputCompositionState state;
state.usesClientComposition = true;
EXPECT_CALL(mDisplay, getState()).WillOnce(ReturnRef(state));
- EXPECT_CALL(*mNativeWindow, queueBuffer(buffer->getNativeBuffer(), -1))
+ EXPECT_CALL(*mNativeWindow, queueBuffer(buffer->getBuffer()->getNativeBuffer(), -1))
.WillOnce(Return(INVALID_OPERATION));
EXPECT_CALL(mDisplay, isVirtual()).WillOnce(Return(true));
- EXPECT_CALL(*mNativeWindow, cancelBuffer(buffer->getNativeBuffer(), -1))
+ EXPECT_CALL(*mNativeWindow, cancelBuffer(buffer->getBuffer()->getNativeBuffer(), -1))
.WillOnce(Return(NO_ERROR));
EXPECT_CALL(*mDisplaySurface, advanceFrame()).Times(1);
mSurface.queueBuffer(base::unique_fd());
- EXPECT_EQ(nullptr, mSurface.mutableGraphicBufferForTest().get());
+ EXPECT_EQ(nullptr, mSurface.mutableTextureForTest().get());
}
/*
diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp
index f01fe27b38..283c69270f 100644
--- a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp
@@ -305,8 +305,8 @@ TEST_F(CachedSetTest, render) {
const auto drawLayers = [&](const renderengine::DisplaySettings& displaySettings,
const std::vector<const renderengine::LayerSettings*>& layers,
- const sp<GraphicBuffer>&, const bool, base::unique_fd&&,
- base::unique_fd*) -> size_t {
+ const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
+ base::unique_fd&&, base::unique_fd*) -> size_t {
EXPECT_EQ(Rect(0, 0, 2, 2), displaySettings.physicalDisplay);
EXPECT_EQ(mOutputState.layerStackSpace.content, displaySettings.clip);
EXPECT_EQ(ui::Transform::toRotationFlags(mOutputState.framebufferSpace.orientation),
@@ -321,7 +321,6 @@ TEST_F(CachedSetTest, render) {
EXPECT_CALL(*layerFE1, prepareClientCompositionList(_)).WillOnce(Return(clientCompList1));
EXPECT_CALL(*layerFE2, prepareClientCompositionList(_)).WillOnce(Return(clientCompList2));
EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Invoke(drawLayers));
- EXPECT_CALL(mRenderEngine, cacheExternalTextureBuffer(_));
cachedSet.render(mRenderEngine, mOutputState);
expectReadyBuffer(cachedSet);
@@ -331,7 +330,6 @@ TEST_F(CachedSetTest, render) {
cachedSet.getOutputSpace().bounds);
// Now check that appending a new cached set properly cleans up RenderEngine resources.
- EXPECT_CALL(mRenderEngine, unbindExternalTextureBuffer(_));
CachedSet::Layer& layer3 = *mTestLayers[2]->cachedSetLayer.get();
cachedSet.append(CachedSet(layer3));
}
diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/LayerStateTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/LayerStateTest.cpp
index 47b1ae8959..948c850735 100644
--- a/services/surfaceflinger/CompositionEngine/tests/planner/LayerStateTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/planner/LayerStateTest.cpp
@@ -41,8 +41,6 @@ const Rect sRectOne = Rect(10, 20, 30, 40);
const Rect sRectTwo = Rect(40, 30, 20, 10);
const FloatRect sFloatRectOne = FloatRect(100.f, 200.f, 300.f, 400.f);
const FloatRect sFloatRectTwo = FloatRect(400.f, 300.f, 200.f, 100.f);
-const constexpr int32_t sZOne = 100;
-const constexpr int32_t sZTwo = 101;
const constexpr float sAlphaOne = 0.25f;
const constexpr float sAlphaTwo = 0.5f;
const Region sRegionOne = Region(sRectOne);
@@ -408,45 +406,6 @@ TEST_F(LayerStateTest, compareSourceCrop) {
EXPECT_TRUE(otherLayerState->compare(*mLayerState));
}
-TEST_F(LayerStateTest, updateZOrder) {
- OutputLayerCompositionState outputLayerCompositionState;
- outputLayerCompositionState.z = sZOne;
- LayerFECompositionState layerFECompositionState;
- setupMocksForLayer(mOutputLayer, mLayerFE, outputLayerCompositionState,
- layerFECompositionState);
- mLayerState = std::make_unique<LayerState>(&mOutputLayer);
-
- mock::OutputLayer newOutputLayer;
- mock::LayerFE newLayerFE;
- OutputLayerCompositionState outputLayerCompositionStateTwo;
- outputLayerCompositionStateTwo.z = sZTwo;
- setupMocksForLayer(newOutputLayer, newLayerFE, outputLayerCompositionStateTwo,
- layerFECompositionState);
- Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
- EXPECT_EQ(Flags<LayerStateField>(LayerStateField::ZOrder), updates);
-}
-
-TEST_F(LayerStateTest, compareZOrder) {
- OutputLayerCompositionState outputLayerCompositionState;
- outputLayerCompositionState.z = sZOne;
- LayerFECompositionState layerFECompositionState;
- setupMocksForLayer(mOutputLayer, mLayerFE, outputLayerCompositionState,
- layerFECompositionState);
- mLayerState = std::make_unique<LayerState>(&mOutputLayer);
- mock::OutputLayer newOutputLayer;
- mock::LayerFE newLayerFE;
- OutputLayerCompositionState outputLayerCompositionStateTwo;
- outputLayerCompositionStateTwo.z = sZTwo;
- setupMocksForLayer(newOutputLayer, newLayerFE, outputLayerCompositionStateTwo,
- layerFECompositionState);
- auto otherLayerState = std::make_unique<LayerState>(&newOutputLayer);
-
- verifyNonUniqueDifferingFields(*mLayerState, *otherLayerState, LayerStateField::ZOrder);
-
- EXPECT_TRUE(mLayerState->compare(*otherLayerState));
- EXPECT_TRUE(otherLayerState->compare(*mLayerState));
-}
-
TEST_F(LayerStateTest, updateBufferTransform) {
OutputLayerCompositionState outputLayerCompositionState;
outputLayerCompositionState.bufferTransform = Hwc2::Transform::FLIP_H;
@@ -793,47 +752,6 @@ TEST_F(LayerStateTest, compareColorTransform) {
EXPECT_TRUE(otherLayerState->compare(*mLayerState));
}
-TEST_F(LayerStateTest, updateSurfaceDamage) {
- OutputLayerCompositionState outputLayerCompositionState;
- LayerFECompositionState layerFECompositionState;
- layerFECompositionState.surfaceDamage = sRegionOne;
- setupMocksForLayer(mOutputLayer, mLayerFE, outputLayerCompositionState,
- layerFECompositionState);
- mLayerState = std::make_unique<LayerState>(&mOutputLayer);
-
- mock::OutputLayer newOutputLayer;
- mock::LayerFE newLayerFE;
- OutputLayerCompositionState outputLayerCompositionStateTwo;
- LayerFECompositionState layerFECompositionStateTwo;
- layerFECompositionStateTwo.surfaceDamage = sRegionTwo;
- setupMocksForLayer(newOutputLayer, newLayerFE, outputLayerCompositionStateTwo,
- layerFECompositionStateTwo);
- Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
- EXPECT_EQ(Flags<LayerStateField>(LayerStateField::SurfaceDamage), updates);
-}
-
-TEST_F(LayerStateTest, compareSurfaceDamage) {
- OutputLayerCompositionState outputLayerCompositionState;
- LayerFECompositionState layerFECompositionState;
- layerFECompositionState.surfaceDamage = sRegionOne;
- setupMocksForLayer(mOutputLayer, mLayerFE, outputLayerCompositionState,
- layerFECompositionState);
- mLayerState = std::make_unique<LayerState>(&mOutputLayer);
- mock::OutputLayer newOutputLayer;
- mock::LayerFE newLayerFE;
- OutputLayerCompositionState outputLayerCompositionStateTwo;
- LayerFECompositionState layerFECompositionStateTwo;
- layerFECompositionStateTwo.surfaceDamage = sRegionTwo;
- setupMocksForLayer(newOutputLayer, newLayerFE, outputLayerCompositionStateTwo,
- layerFECompositionStateTwo);
- auto otherLayerState = std::make_unique<LayerState>(&newOutputLayer);
-
- verifyNonUniqueDifferingFields(*mLayerState, *otherLayerState, LayerStateField::SurfaceDamage);
-
- EXPECT_TRUE(mLayerState->compare(*otherLayerState));
- EXPECT_TRUE(otherLayerState->compare(*mLayerState));
-}
-
TEST_F(LayerStateTest, updateSidebandStream) {
OutputLayerCompositionState outputLayerCompositionState;
LayerFECompositionState layerFECompositionState;
@@ -995,4 +913,4 @@ TEST_F(LayerStateTest, getNonBufferHash_filtersOutBuffers) {
}
} // namespace
-} // namespace android::compositionengine::impl::planner \ No newline at end of file
+} // namespace android::compositionengine::impl::planner
diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/PredictorTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/PredictorTest.cpp
index 43e119fc11..1492707ad2 100644
--- a/services/surfaceflinger/CompositionEngine/tests/planner/PredictorTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/planner/PredictorTest.cpp
@@ -31,8 +31,6 @@ const FloatRect sFloatRectOne = FloatRect(100.f, 200.f, 300.f, 400.f);
const FloatRect sFloatRectTwo = FloatRect(400.f, 300.f, 200.f, 100.f);
const Rect sRectOne = Rect(1, 2, 3, 4);
const Rect sRectTwo = Rect(4, 3, 2, 1);
-const constexpr int32_t sZOne = 100;
-const constexpr int32_t sZTwo = 101;
const constexpr float sAlphaOne = 0.25f;
const constexpr float sAlphaTwo = 0.5f;
const Region sRegionOne = Region(sRectOne);
@@ -194,11 +192,11 @@ TEST_F(LayerStackTest, getApproximateMatch_doesNotMatchManyDifferences) {
.displayFrame = sRectOne,
.sourceCrop = sFloatRectOne,
.dataspace = ui::Dataspace::SRGB,
- .z = sZOne,
};
LayerFECompositionState layerFECompositionStateOne;
layerFECompositionStateOne.alpha = sAlphaOne;
layerFECompositionStateOne.colorTransformIsIdentity = true;
+ layerFECompositionStateOne.blendMode = hal::BlendMode::NONE;
setupMocksForLayer(outputLayerOne, layerFEOne, outputLayerCompositionStateOne,
layerFECompositionStateOne);
LayerState layerStateOne(&outputLayerOne);
@@ -210,12 +208,12 @@ TEST_F(LayerStackTest, getApproximateMatch_doesNotMatchManyDifferences) {
.displayFrame = sRectTwo,
.sourceCrop = sFloatRectTwo,
.dataspace = ui::Dataspace::DISPLAY_P3,
- .z = sZTwo,
};
LayerFECompositionState layerFECompositionStateTwo;
layerFECompositionStateTwo.alpha = sAlphaTwo;
layerFECompositionStateTwo.colorTransformIsIdentity = false;
layerFECompositionStateTwo.colorTransform = sMat4One;
+ layerFECompositionStateTwo.blendMode = hal::BlendMode::PREMULTIPLIED;
setupMocksForLayer(outputLayerTwo, layerFETwo, outputLayerCompositionStateTwo,
layerFECompositionStateTwo);
LayerState layerStateTwo(&outputLayerTwo);
@@ -264,7 +262,6 @@ TEST_F(LayerStackTest, getApproximateMatch_alwaysMatchesClientComposition) {
.displayFrame = sRectOne,
.sourceCrop = sFloatRectOne,
.dataspace = ui::Dataspace::SRGB,
- .z = sZOne,
};
LayerFECompositionState layerFECompositionStateOne;
layerFECompositionStateOne.buffer = new GraphicBuffer();
@@ -282,7 +279,6 @@ TEST_F(LayerStackTest, getApproximateMatch_alwaysMatchesClientComposition) {
.displayFrame = sRectTwo,
.sourceCrop = sFloatRectTwo,
.dataspace = ui::Dataspace::DISPLAY_P3,
- .z = sZTwo,
};
LayerFECompositionState layerFECompositionStateTwo;
layerFECompositionStateTwo.buffer = new GraphicBuffer();
@@ -346,6 +342,32 @@ struct PredictionTest : public testing::Test {
}
};
+TEST_F(LayerStackTest, reorderingChangesNonBufferHash) {
+ mock::OutputLayer outputLayerOne;
+ mock::LayerFE layerFEOne;
+ OutputLayerCompositionState outputLayerCompositionStateOne{
+ .sourceCrop = sFloatRectOne,
+ };
+ LayerFECompositionState layerFECompositionStateOne;
+ setupMocksForLayer(outputLayerOne, layerFEOne, outputLayerCompositionStateOne,
+ layerFECompositionStateOne);
+ LayerState layerStateOne(&outputLayerOne);
+
+ mock::OutputLayer outputLayerTwo;
+ mock::LayerFE layerFETwo;
+ OutputLayerCompositionState outputLayerCompositionStateTwo{
+ .sourceCrop = sFloatRectTwo,
+ };
+ LayerFECompositionState layerFECompositionStateTwo;
+ setupMocksForLayer(outputLayerTwo, layerFETwo, outputLayerCompositionStateTwo,
+ layerFECompositionStateTwo);
+ LayerState layerStateTwo(&outputLayerTwo);
+
+ NonBufferHash hash = getNonBufferHash({&layerStateOne, &layerStateTwo});
+ NonBufferHash hashReverse = getNonBufferHash({&layerStateTwo, &layerStateOne});
+ EXPECT_NE(hash, hashReverse);
+}
+
TEST_F(PredictionTest, constructPrediction) {
Plan plan;
plan.addLayerType(hal::Composition::DEVICE);
@@ -525,4 +547,4 @@ TEST_F(PredictorTest, recordMissedPlan_skipsApproximateMatch) {
}
} // namespace
-} // namespace android::compositionengine::impl::planner \ No newline at end of file
+} // namespace android::compositionengine::impl::planner
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index fd0371787f..2c09ebdead 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -71,11 +71,13 @@ DisplayDevice::DisplayDevice(DisplayDeviceCreationArgs& args)
mIsPowerModeOverride(false){
mCompositionDisplay->editState().isSecure = args.isSecure;
mCompositionDisplay->createRenderSurface(
- compositionengine::RenderSurfaceCreationArgs{ANativeWindow_getWidth(
- args.nativeWindow.get()),
- ANativeWindow_getHeight(
- args.nativeWindow.get()),
- args.nativeWindow, args.displaySurface});
+ compositionengine::
+ RenderSurfaceCreationArgs{ANativeWindow_getWidth(args.nativeWindow.get()),
+ ANativeWindow_getHeight(args.nativeWindow.get()),
+ args.nativeWindow, args.displaySurface,
+ static_cast<size_t>(
+ SurfaceFlinger::
+ maxFrameBufferAcquiredBuffers)});
if (!mFlinger->mDisableClientCompositionCache &&
SurfaceFlinger::maxFrameBufferAcquiredBuffers > 0) {
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
index bf81b74a75..0f4d0dd119 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
@@ -20,11 +20,7 @@
#undef LOG_TAG
#define LOG_TAG "HwcComposer"
-
-#include <log/log.h>
-
-#include <algorithm>
-#include <cinttypes>
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
#include "ComposerHal.h"
@@ -32,6 +28,11 @@
#include <gui/BufferQueue.h>
#include <hidl/HidlTransportSupport.h>
#include <hidl/HidlTransportUtils.h>
+#include <log/log.h>
+#include <utils/Trace.h>
+
+#include <algorithm>
+#include <cinttypes>
#ifdef QTI_UNIFIED_DRAW
#include <vendor/qti/hardware/display/composer/3.1/IQtiComposerClient.h>
@@ -604,6 +605,7 @@ Error Composer::getReleaseFences(Display display,
Error Composer::presentDisplay(Display display, int* outPresentFence)
{
+ ATRACE_NAME("HwcPresentDisplay");
mWriter.selectDisplay(display);
mWriter.presentDisplay();
@@ -727,6 +729,7 @@ Error Composer::setClientTargetSlotCount(Display display)
Error Composer::validateDisplay(Display display, uint32_t* outNumTypes,
uint32_t* outNumRequests)
{
+ ATRACE_NAME("HwcValidateDisplay");
mWriter.selectDisplay(display);
mWriter.validateDisplay();
@@ -742,13 +745,14 @@ Error Composer::validateDisplay(Display display, uint32_t* outNumTypes,
Error Composer::presentOrValidateDisplay(Display display, uint32_t* outNumTypes,
uint32_t* outNumRequests, int* outPresentFence, uint32_t* state) {
- mWriter.selectDisplay(display);
- mWriter.presentOrvalidateDisplay();
+ ATRACE_NAME("HwcPresentOrValidateDisplay");
+ mWriter.selectDisplay(display);
+ mWriter.presentOrvalidateDisplay();
- Error error = execute();
- if (error != Error::NONE) {
- return error;
- }
+ Error error = execute();
+ if (error != Error::NONE) {
+ return error;
+ }
mReader.takePresentOrValidateStage(display, state);
diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
index 6485265c17..be552c6435 100644
--- a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
+++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
@@ -653,8 +653,10 @@ void SurfaceFrame::traceActuals(int64_t displayFrameToken) const {
// If prediction is expired, we can't use the predicted start time. Instead, just use a
// start time a little earlier than the end time so that we have some info about this
// frame in the trace.
+ nsecs_t endTime =
+ (mPresentState == PresentState::Dropped ? mDropTime : mActuals.endTime);
packet->set_timestamp(
- static_cast<uint64_t>(mActuals.endTime - kPredictionExpiredStartTimeDelta));
+ static_cast<uint64_t>(endTime - kPredictionExpiredStartTimeDelta));
} else {
packet->set_timestamp(static_cast<uint64_t>(mPredictions.startTime));
}
@@ -752,14 +754,13 @@ void TokenManager::flushTokens(nsecs_t flushTime) {
}
FrameTimeline::FrameTimeline(std::shared_ptr<TimeStats> timeStats, pid_t surfaceFlingerPid,
- JankClassificationThresholds thresholds, nsecs_t hwcDuration)
+ JankClassificationThresholds thresholds)
: mMaxDisplayFrames(kDefaultMaxDisplayFrames),
mTimeStats(std::move(timeStats)),
mSurfaceFlingerPid(surfaceFlingerPid),
- mJankClassificationThresholds(thresholds),
- mHwcDuration(hwcDuration) {
- mCurrentDisplayFrame = std::make_shared<DisplayFrame>(mTimeStats, thresholds, hwcDuration,
- &mTraceCookieCounter);
+ mJankClassificationThresholds(thresholds) {
+ mCurrentDisplayFrame =
+ std::make_shared<DisplayFrame>(mTimeStats, thresholds, &mTraceCookieCounter);
}
void FrameTimeline::onBootFinished() {
@@ -804,13 +805,11 @@ std::shared_ptr<SurfaceFrame> FrameTimeline::createSurfaceFrameForToken(
FrameTimeline::DisplayFrame::DisplayFrame(std::shared_ptr<TimeStats> timeStats,
JankClassificationThresholds thresholds,
- nsecs_t hwcDuration,
TraceCookieCounter* traceCookieCounter)
: mSurfaceFlingerPredictions(TimelineItem()),
mSurfaceFlingerActuals(TimelineItem()),
mTimeStats(timeStats),
mJankClassificationThresholds(thresholds),
- mHwcDuration(hwcDuration),
mTraceCookieCounter(*traceCookieCounter) {
mSurfaceFrames.reserve(kNumSurfaceFramesInitial);
}
@@ -830,13 +829,11 @@ void FrameTimeline::setSfWakeUp(int64_t token, nsecs_t wakeUpTime, Fps refreshRa
void FrameTimeline::setSfPresent(nsecs_t sfPresentTime,
const std::shared_ptr<FenceTime>& presentFence,
- bool gpuComposition) {
+ const std::shared_ptr<FenceTime>& gpuFence) {
ATRACE_CALL();
std::scoped_lock lock(mMutex);
mCurrentDisplayFrame->setActualEndTime(sfPresentTime);
- if (gpuComposition) {
- mCurrentDisplayFrame->setGpuComposition();
- }
+ mCurrentDisplayFrame->setGpuFence(gpuFence);
mPendingPresentFences.emplace_back(std::make_pair(presentFence, mCurrentDisplayFrame));
flushPendingPresentFences();
finalizeCurrentDisplayFrame();
@@ -874,25 +871,32 @@ void FrameTimeline::DisplayFrame::setActualEndTime(nsecs_t actualEndTime) {
mSurfaceFlingerActuals.endTime = actualEndTime;
}
-void FrameTimeline::DisplayFrame::setGpuComposition() {
- mGpuComposition = true;
+void FrameTimeline::DisplayFrame::setGpuFence(const std::shared_ptr<FenceTime>& gpuFence) {
+ mGpuFence = gpuFence;
}
void FrameTimeline::DisplayFrame::classifyJank(nsecs_t& deadlineDelta, nsecs_t& deltaToVsync) {
if (mPredictionState == PredictionState::Expired ||
mSurfaceFlingerActuals.presentTime == Fence::SIGNAL_TIME_INVALID) {
- // Cannot do jank classification with expired predictions or invalid signal times.
+ // Cannot do jank classification with expired predictions or invalid signal times. Set the
+ // deltas to 0 as both negative and positive deltas are used as real values.
mJankType = JankType::Unknown;
- deadlineDelta = -1;
- deltaToVsync = -1;
+ deadlineDelta = 0;
+ deltaToVsync = 0;
return;
}
// Delta between the expected present and the actual present
const nsecs_t presentDelta =
mSurfaceFlingerActuals.presentTime - mSurfaceFlingerPredictions.presentTime;
- deadlineDelta =
- mSurfaceFlingerActuals.endTime - (mSurfaceFlingerPredictions.endTime - mHwcDuration);
+ // Sf actual end time represents the CPU end time. In case of HWC, SF's end time would have
+ // included the time for composition. However, for GPU composition, the final end time is max(sf
+ // end time, gpu fence time).
+ nsecs_t combinedEndTime = mSurfaceFlingerActuals.endTime;
+ if (mGpuFence != FenceTime::NO_FENCE) {
+ combinedEndTime = std::max(combinedEndTime, mGpuFence->getSignalTime());
+ }
+ deadlineDelta = combinedEndTime - mSurfaceFlingerPredictions.endTime;
// How far off was the presentDelta when compared to the vsyncPeriod. Used in checking if there
// was a prediction error or not.
@@ -907,9 +911,7 @@ void FrameTimeline::DisplayFrame::classifyJank(nsecs_t& deadlineDelta, nsecs_t&
mFramePresentMetadata = FramePresentMetadata::OnTimePresent;
}
- if (mSurfaceFlingerActuals.endTime > mSurfaceFlingerPredictions.endTime - mHwcDuration) {
- // SF needs to have finished at least mHwcDuration ahead of the deadline for it to be
- // on time.
+ if (combinedEndTime > mSurfaceFlingerPredictions.endTime) {
mFrameReadyMetadata = FrameReadyMetadata::LateFinish;
} else {
mFrameReadyMetadata = FrameReadyMetadata::OnTimeFinish;
@@ -966,7 +968,15 @@ void FrameTimeline::DisplayFrame::classifyJank(nsecs_t& deadlineDelta, nsecs_t&
mJankType = JankType::SurfaceFlingerScheduling;
} else {
// OnTime start, Finish late, Present late
- mJankType = JankType::SurfaceFlingerCpuDeadlineMissed;
+ if (mGpuFence != FenceTime::NO_FENCE &&
+ mSurfaceFlingerActuals.endTime - mSurfaceFlingerActuals.startTime <
+ mRefreshRate.getPeriodNsecs()) {
+ // If SF was in GPU composition and the CPU work finished before the vsync
+ // period, classify it as GPU deadline missed.
+ mJankType = JankType::SurfaceFlingerGpuDeadlineMissed;
+ } else {
+ mJankType = JankType::SurfaceFlingerCpuDeadlineMissed;
+ }
}
} else {
// Finish time unknown
@@ -1041,7 +1051,7 @@ void FrameTimeline::DisplayFrame::traceActuals(pid_t surfaceFlingerPid) const {
actualDisplayFrameStartEvent->set_present_type(toProto(mFramePresentMetadata));
actualDisplayFrameStartEvent->set_on_time_finish(mFrameReadyMetadata ==
FrameReadyMetadata::OnTimeFinish);
- actualDisplayFrameStartEvent->set_gpu_composition(mGpuComposition);
+ actualDisplayFrameStartEvent->set_gpu_composition(mGpuFence != FenceTime::NO_FENCE);
actualDisplayFrameStartEvent->set_jank_type(jankTypeBitmaskToProto(mJankType));
actualDisplayFrameStartEvent->set_prediction_type(toProto(mPredictionState));
});
@@ -1164,7 +1174,7 @@ void FrameTimeline::finalizeCurrentDisplayFrame() {
mDisplayFrames.push_back(mCurrentDisplayFrame);
mCurrentDisplayFrame.reset();
mCurrentDisplayFrame = std::make_shared<DisplayFrame>(mTimeStats, mJankClassificationThresholds,
- mHwcDuration, &mTraceCookieCounter);
+ &mTraceCookieCounter);
}
nsecs_t FrameTimeline::DisplayFrame::getBaseTime() const {
diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.h b/services/surfaceflinger/FrameTimeline/FrameTimeline.h
index 3f04592b6e..41f4978543 100644
--- a/services/surfaceflinger/FrameTimeline/FrameTimeline.h
+++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.h
@@ -293,11 +293,12 @@ public:
// the token and sets the actualSfWakeTime for the current DisplayFrame.
virtual void setSfWakeUp(int64_t token, nsecs_t wakeupTime, Fps refreshRate) = 0;
- // Sets the sfPresentTime, gpuComposition and finalizes the current DisplayFrame. Tracks the
+ // Sets the sfPresentTime and finalizes the current DisplayFrame. Tracks the
// given present fence until it's signaled, and updates the present timestamps of all presented
- // SurfaceFrames in that vsync.
+ // SurfaceFrames in that vsync. If a gpuFence was also provided, its tracked in the
+ // corresponding DisplayFrame.
virtual void setSfPresent(nsecs_t sfPresentTime, const std::shared_ptr<FenceTime>& presentFence,
- bool gpuComposition) = 0;
+ const std::shared_ptr<FenceTime>& gpuFence) = 0;
// Args:
// -jank : Dumps only the Display Frames that are either janky themselves
@@ -355,7 +356,7 @@ public:
class DisplayFrame {
public:
DisplayFrame(std::shared_ptr<TimeStats> timeStats, JankClassificationThresholds thresholds,
- nsecs_t hwcDuration, TraceCookieCounter* traceCookieCounter);
+ TraceCookieCounter* traceCookieCounter);
virtual ~DisplayFrame() = default;
// Dumpsys interface - dumps only if the DisplayFrame itself is janky or is at least one
// SurfaceFrame is janky.
@@ -376,7 +377,7 @@ public:
void setPredictions(PredictionState predictionState, TimelineItem predictions);
void setActualStartTime(nsecs_t actualStartTime);
void setActualEndTime(nsecs_t actualEndTime);
- void setGpuComposition();
+ void setGpuFence(const std::shared_ptr<FenceTime>& gpuFence);
// BaseTime is the smallest timestamp in a DisplayFrame.
// Used for dumping all timestamps relative to the oldest, making it easy to read.
@@ -410,7 +411,6 @@ public:
TimelineItem mSurfaceFlingerActuals;
std::shared_ptr<TimeStats> mTimeStats;
const JankClassificationThresholds mJankClassificationThresholds;
- const nsecs_t mHwcDuration;
// Collection of predictions and actual values sent over by Layers
std::vector<std::shared_ptr<SurfaceFrame>> mSurfaceFrames;
@@ -418,8 +418,8 @@ public:
PredictionState mPredictionState = PredictionState::None;
// Bitmask for the type of jank
int32_t mJankType = JankType::None;
- // Indicates if this frame was composited by the GPU or not
- bool mGpuComposition = false;
+ // A valid gpu fence indicates that the DisplayFrame was composited by the GPU
+ std::shared_ptr<FenceTime> mGpuFence = FenceTime::NO_FENCE;
// Enum for the type of present
FramePresentMetadata mFramePresentMetadata = FramePresentMetadata::UnknownPresent;
// Enum for the type of finish
@@ -436,8 +436,7 @@ public:
};
FrameTimeline(std::shared_ptr<TimeStats> timeStats, pid_t surfaceFlingerPid,
- JankClassificationThresholds thresholds = {},
- nsecs_t hwcDuration = kDefaultHwcDuration);
+ JankClassificationThresholds thresholds = {});
~FrameTimeline() = default;
frametimeline::TokenManager* getTokenManager() override { return &mTokenManager; }
@@ -447,7 +446,7 @@ public:
void addSurfaceFrame(std::shared_ptr<frametimeline::SurfaceFrame> surfaceFrame) override;
void setSfWakeUp(int64_t token, nsecs_t wakeupTime, Fps refreshRate) override;
void setSfPresent(nsecs_t sfPresentTime, const std::shared_ptr<FenceTime>& presentFence,
- bool gpuComposition = false) override;
+ const std::shared_ptr<FenceTime>& gpuFence = FenceTime::NO_FENCE) override;
void parseArgs(const Vector<String16>& args, std::string& result) override;
void setMaxDisplayFrames(uint32_t size) override;
float computeFps(const std::unordered_set<int32_t>& layerIds) override;
@@ -482,11 +481,6 @@ private:
std::shared_ptr<TimeStats> mTimeStats;
const pid_t mSurfaceFlingerPid;
const JankClassificationThresholds mJankClassificationThresholds;
- // In SF Predictions, both end & present are the same. The predictions consider the time used by
- // composer as well, but we have no way to estimate how much time the composer needs. We are
- // assuming an arbitrary time for the composer work.
- const nsecs_t mHwcDuration;
- static constexpr nsecs_t kDefaultHwcDuration = std::chrono::nanoseconds(3ms).count();
static constexpr uint32_t kDefaultMaxDisplayFrames = 64;
// The initial container size for the vector<SurfaceFrames> inside display frame. Although
// this number doesn't represent any bounds on the number of surface frames that can go in a
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index cb152e42b9..41b7ecc740 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -204,19 +204,6 @@ LayerCreationArgs::LayerCreationArgs(SurfaceFlinger* flinger, sp<Client> client,
*/
void Layer::onLayerDisplayed(const sp<Fence>& /*releaseFence*/) {}
-void Layer::removeRemoteSyncPoints() {
- for (auto& point : mRemoteSyncPoints) {
- point->setTransactionApplied();
- }
- mRemoteSyncPoints.clear();
-
- {
- for (State pendingState : mPendingStates) {
- pendingState.barrierLayer_legacy = nullptr;
- }
- }
-}
-
void Layer::removeRelativeZ(const std::vector<Layer*>& layersInTree) {
if (mCurrentState.zOrderRelativeOf == nullptr) {
return;
@@ -238,21 +225,6 @@ void Layer::removeRelativeZ(const std::vector<Layer*>& layersInTree) {
void Layer::removeFromCurrentState() {
mRemovedFromCurrentState = true;
- // Since we are no longer reachable from CurrentState SurfaceFlinger
- // will no longer invoke doTransaction for us, and so we will
- // never finish applying transactions. We signal the sync point
- // now so that another layer will not become indefinitely
- // blocked.
- removeRemoteSyncPoints();
-
- {
- Mutex::Autolock syncLock(mLocalSyncPointMutex);
- for (auto& point : mLocalSyncPoints) {
- point->setFrameAvailable();
- }
- mLocalSyncPoints.clear();
- }
-
mFlinger->markLayerPendingRemovalLocked(this);
}
@@ -566,7 +538,9 @@ void Layer::preparePerFrameCompositionState() {
isOpaque(drawingState) && !usesRoundedCorners && getAlpha() == 1.0_hf;
// Force client composition for special cases known only to the front-end.
- if (isHdrY410() || usesRoundedCorners || drawShadows() || drawingState.blurRegions.size() > 0 ||
+ // Rounded corners no longer force client composition, since we may use a
+ // hole punch so that the layer will appear to have rounded corners.
+ if (isHdrY410() || drawShadows() || drawingState.blurRegions.size() > 0 ||
compositionState->stretchEffect.hasEffect()) {
compositionState->forceClientComposition = true;
}
@@ -782,21 +756,6 @@ Hwc2::IComposerClient::Composition Layer::getCompositionType(const DisplayDevice
}
}
-bool Layer::addSyncPoint(const std::shared_ptr<SyncPoint>& point) {
- if (point->getFrameNumber() <= mCurrentFrameNumber) {
- // Don't bother with a SyncPoint, since we've already latched the
- // relevant frame
- return false;
- }
- if (isRemovedFromCurrentState()) {
- return false;
- }
-
- Mutex::Autolock lock(mLocalSyncPointMutex);
- mLocalSyncPoints.push_back(point);
- return true;
-}
-
// ----------------------------------------------------------------------------
// local state
// ----------------------------------------------------------------------------
@@ -832,132 +791,6 @@ bool Layer::isScreenshot() const {
// transaction
// ----------------------------------------------------------------------------
-void Layer::pushPendingState() {
- if (!mCurrentState.modified) {
- return;
- }
- ATRACE_CALL();
-
- // If this transaction is waiting on the receipt of a frame, generate a sync
- // point and send it to the remote layer.
- // We don't allow installing sync points after we are removed from the current state
- // as we won't be able to signal our end.
- if (mCurrentState.barrierLayer_legacy != nullptr && !isRemovedFromCurrentState()) {
- sp<Layer> barrierLayer = mCurrentState.barrierLayer_legacy.promote();
- if (barrierLayer == nullptr) {
- ALOGE("[%s] Unable to promote barrier Layer.", getDebugName());
- // If we can't promote the layer we are intended to wait on,
- // then it is expired or otherwise invalid. Allow this transaction
- // to be applied as per normal (no synchronization).
- mCurrentState.barrierLayer_legacy = nullptr;
- } else {
- auto syncPoint = std::make_shared<SyncPoint>(mCurrentState.barrierFrameNumber, this,
- barrierLayer);
- if (barrierLayer->addSyncPoint(syncPoint)) {
- std::stringstream ss;
- ss << "Adding sync point " << mCurrentState.barrierFrameNumber;
- ATRACE_NAME(ss.str().c_str());
- mRemoteSyncPoints.push_back(std::move(syncPoint));
- } else {
- // We already missed the frame we're supposed to synchronize
- // on, so go ahead and apply the state update
- mCurrentState.barrierLayer_legacy = nullptr;
- }
- }
-
- // Wake us up to check if the frame has been received
- setTransactionFlags(eTransactionNeeded);
- mFlinger->setTransactionFlags(eTraversalNeeded);
- }
- if (mCurrentState.bufferlessSurfaceFramesTX.size() >= State::kStateSurfaceFramesThreshold) {
- // Ideally, the currentState would only contain one SurfaceFrame per transaction (assuming
- // each Tx uses a different token). We don't expect the current state to hold a huge amount
- // of SurfaceFrames. However, in the event it happens, this debug statement will leave a
- // trail that can help in debugging.
- ALOGW("Bufferless SurfaceFrames size on current state of layer %s is %" PRIu32 "",
- mName.c_str(), static_cast<uint32_t>(mCurrentState.bufferlessSurfaceFramesTX.size()));
- }
- mPendingStates.push_back(mCurrentState);
- // Since the current state along with the SurfaceFrames has been pushed into the pendingState,
- // we no longer need to retain them. If multiple states are pushed and applied together, we have
- // a merging logic to address the SurfaceFrames at mergeSurfaceFrames().
- mCurrentState.bufferlessSurfaceFramesTX.clear();
- ATRACE_INT(mTransactionName.c_str(), mPendingStates.size());
-}
-
-void Layer::mergeSurfaceFrames(State& source, State& target) {
- // No need to merge BufferSurfaceFrame as the target's surfaceFrame, if it exists, will be used
- // directly. Dropping of source's SurfaceFrame is taken care of at setBuffer().
- target.bufferlessSurfaceFramesTX.merge(source.bufferlessSurfaceFramesTX);
- source.bufferlessSurfaceFramesTX.clear();
-}
-
-void Layer::popPendingState(State* stateToCommit) {
- ATRACE_CALL();
-
- mergeSurfaceFrames(*stateToCommit, mPendingStates[0]);
- *stateToCommit = mPendingStates[0];
- mPendingStates.pop_front();
- ATRACE_INT(mTransactionName.c_str(), mPendingStates.size());
-}
-
-bool Layer::applyPendingStates(State* stateToCommit) {
- bool stateUpdateAvailable = false;
- while (!mPendingStates.empty()) {
- if (mPendingStates[0].barrierLayer_legacy != nullptr) {
- if (mRemoteSyncPoints.empty()) {
- // If we don't have a sync point for this, apply it anyway. It
- // will be visually wrong, but it should keep us from getting
- // into too much trouble.
- ALOGV("[%s] No local sync point found", getDebugName());
- popPendingState(stateToCommit);
- stateUpdateAvailable = true;
- continue;
- }
-
- if (mRemoteSyncPoints.front()->getFrameNumber() !=
- mPendingStates[0].barrierFrameNumber) {
- ALOGE("[%s] Unexpected sync point frame number found", getDebugName());
-
- // Signal our end of the sync point and then dispose of it
- mRemoteSyncPoints.front()->setTransactionApplied();
- mRemoteSyncPoints.pop_front();
- continue;
- }
-
- if (mRemoteSyncPoints.front()->frameIsAvailable()) {
- ATRACE_NAME("frameIsAvailable");
- // Apply the state update
- popPendingState(stateToCommit);
- stateUpdateAvailable = true;
-
- // Signal our end of the sync point and then dispose of it
- mRemoteSyncPoints.front()->setTransactionApplied();
- mRemoteSyncPoints.pop_front();
- } else {
- ATRACE_NAME("!frameIsAvailable");
- mRemoteSyncPoints.front()->checkTimeoutAndLog();
- break;
- }
- } else {
- popPendingState(stateToCommit);
- stateUpdateAvailable = true;
- }
- }
-
- // If we still have pending updates, we need to ensure SurfaceFlinger
- // will keep calling doTransaction, and so we force a traversal.
- // However, our pending states won't clear until a frame is available,
- // and so there is no need to specifically trigger a wakeup.
- if (!mPendingStates.empty()) {
- setTransactionFlags(eTransactionNeeded);
- mFlinger->setTraversalNeeded();
- }
-
- mCurrentState.modified = false;
- return stateUpdateAvailable;
-}
-
uint32_t Layer::doTransactionResize(uint32_t flags, State* stateToCommit) {
const State& s(getDrawingState());
@@ -1038,15 +871,14 @@ uint32_t Layer::doTransaction(uint32_t flags) {
mChildrenChanged = false;
}
- pushPendingState();
- State c = getCurrentState();
- if (!applyPendingStates(&c)) {
- return flags;
- }
+ // TODO: This is unfortunate.
+ mCurrentStateModified = mCurrentState.modified;
+ mCurrentState.modified = false;
- flags = doTransactionResize(flags, &c);
+ flags = doTransactionResize(flags, &mCurrentState);
const State& s(getDrawingState());
+ State& c(getCurrentState());
if (getActiveGeometry(c) != getActiveGeometry(s)) {
// invalidate and recompute the visible regions if needed
@@ -1074,11 +906,10 @@ uint32_t Layer::doTransaction(uint32_t flags) {
}
// Allow BufferStateLayer to release any unlatched buffers in drawing state.
- bufferMayChange(c.buffer);
+ bufferMayChange(c.buffer->getBuffer());
// Commit the transaction
commitTransaction(c);
- mPendingStatesSnapshot = mPendingStates;
mCurrentState.callbackHandles = {};
return flags;
@@ -1086,7 +917,11 @@ uint32_t Layer::doTransaction(uint32_t flags) {
void Layer::commitTransaction(State& stateToCommit) {
if (auto& bufferSurfaceFrame = mDrawingState.bufferSurfaceFrameTX;
- mDrawingState.buffer != stateToCommit.buffer && bufferSurfaceFrame != nullptr &&
+ ((mDrawingState.buffer && stateToCommit.buffer &&
+ mDrawingState.buffer->getBuffer() != stateToCommit.buffer->getBuffer()) ||
+ (mDrawingState.buffer && !stateToCommit.buffer) ||
+ (!mDrawingState.buffer && stateToCommit.buffer)) &&
+ bufferSurfaceFrame != nullptr &&
bufferSurfaceFrame->getPresentState() != PresentState::Presented) {
// If the previous buffer was committed but not latched (refreshPending - happens during
// back to back invalidates), it gets silently dropped here. Mark the corresponding
@@ -1692,25 +1527,6 @@ Layer::FrameRate Layer::getFrameRateForLayerTree() const {
return frameRate;
}
-void Layer::deferTransactionUntil_legacy(const sp<Layer>& barrierLayer, uint64_t frameNumber) {
- ATRACE_CALL();
-
- mCurrentState.barrierLayer_legacy = barrierLayer;
- mCurrentState.barrierFrameNumber = frameNumber;
- // We don't set eTransactionNeeded, because just receiving a deferral
- // request without any other state updates shouldn't actually induce a delay
- mCurrentState.modified = true;
- pushPendingState();
- mCurrentState.barrierLayer_legacy = nullptr;
- mCurrentState.barrierFrameNumber = 0;
- mCurrentState.modified = false;
-}
-
-void Layer::deferTransactionUntil_legacy(const sp<IBinder>& barrierHandle, uint64_t frameNumber) {
- sp<Handle> handle = static_cast<Handle*>(barrierHandle.get());
- deferTransactionUntil_legacy(handle->owner.promote(), frameNumber);
-}
-
// ----------------------------------------------------------------------------
// pageflip handling...
// ----------------------------------------------------------------------------
@@ -2296,8 +2112,13 @@ int32_t Layer::getBackgroundBlurRadius() const {
return parentAlpha * getDrawingState().backgroundBlurRadius;
}
-const std::vector<BlurRegion>& Layer::getBlurRegions() const {
- return getDrawingState().blurRegions;
+const std::vector<BlurRegion> Layer::getBlurRegions() const {
+ auto regionsCopy(getDrawingState().blurRegions);
+ int layerAlpha = getAlpha();
+ for (auto& region : regionsCopy) {
+ region.alpha = region.alpha * layerAlpha;
+ }
+ return regionsCopy;
}
Layer::RoundedCornerState Layer::getRoundedCornerState() const {
@@ -2319,8 +2140,8 @@ Layer::RoundedCornerState Layer::getRoundedCornerState() const {
}
}
const float radius = getDrawingState().cornerRadius;
- return radius > 0 && getCrop(getDrawingState()).isValid()
- ? RoundedCornerState(getCrop(getDrawingState()).toFloatRect(), radius)
+ return radius > 0 && getCroppedBufferSize(getDrawingState()).isValid()
+ ? RoundedCornerState(getCroppedBufferSize(getDrawingState()).toFloatRect(), radius)
: RoundedCornerState();
}
@@ -2394,14 +2215,6 @@ void Layer::writeToProtoDrawingState(LayerProto* layerInfo, uint32_t traceFlags,
const ui::Transform transform = getTransform();
if (traceFlags & SurfaceTracing::TRACE_CRITICAL) {
- for (const auto& pendingState : mPendingStatesSnapshot) {
- auto barrierLayer = pendingState.barrierLayer_legacy.promote();
- if (barrierLayer != nullptr) {
- BarrierLayerProto* barrierLayerProto = layerInfo->add_barrier_layer();
- barrierLayerProto->set_id(barrierLayer->sequence);
- barrierLayerProto->set_frame_number(pendingState.barrierFrameNumber);
- }
- }
auto buffer = getBuffer();
if (buffer != nullptr) {
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 4d3fb550d0..7118513717 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -166,11 +166,6 @@ public:
Rect crop;
Rect requestedCrop;
- // If set, defers this state update until the identified Layer
- // receives a frame with the given frameNumber
- wp<Layer> barrierLayer_legacy;
- uint64_t barrierFrameNumber;
-
// the transparentRegion hint is a bit special, it's latched only
// when we receive a buffer -- this is because it's "content"
// dependent.
@@ -208,7 +203,7 @@ public:
Region transparentRegionHint;
- sp<GraphicBuffer> buffer;
+ std::shared_ptr<renderengine::ExternalTexture> buffer;
client_cache_t clientCacheId;
sp<Fence> acquireFence;
std::shared_ptr<FenceTime> acquireFenceTime;
@@ -398,9 +393,6 @@ public:
virtual bool setFlags(uint32_t flags, uint32_t mask);
virtual bool setLayerStack(uint32_t layerStack);
virtual uint32_t getLayerStack() const;
- virtual void deferTransactionUntil_legacy(const sp<IBinder>& barrierHandle,
- uint64_t frameNumber);
- virtual void deferTransactionUntil_legacy(const sp<Layer>& barrierLayer, uint64_t frameNumber);
virtual bool setMetadata(const LayerMetadata& data);
virtual void setChildrenDrawingParent(const sp<Layer>&);
virtual bool reparent(const sp<IBinder>& newParentHandle);
@@ -412,11 +404,11 @@ public:
// Used only to set BufferStateLayer state
virtual bool setTransform(uint32_t /*transform*/) { return false; };
virtual bool setTransformToDisplayInverse(bool /*transformToDisplayInverse*/) { return false; };
- virtual bool setFrame(const Rect& /*frame*/) { return false; };
- virtual bool setBuffer(const sp<GraphicBuffer>& /*buffer*/, const sp<Fence>& /*acquireFence*/,
- nsecs_t /*postTime*/, nsecs_t /*desiredPresentTime*/,
- bool /*isAutoTimestamp*/, const client_cache_t& /*clientCacheId*/,
- uint64_t /* frameNumber */, std::optional<nsecs_t> /* dequeueTime */,
+ virtual bool setBuffer(const std::shared_ptr<renderengine::ExternalTexture>& /*buffer*/,
+ const sp<Fence>& /*acquireFence*/, nsecs_t /*postTime*/,
+ nsecs_t /*desiredPresentTime*/, bool /*isAutoTimestamp*/,
+ const client_cache_t& /*clientCacheId*/, uint64_t /* frameNumber */,
+ std::optional<nsecs_t> /* dequeueTime */,
const FrameTimelineInfo& /*info*/,
const sp<ITransactionCompletedListener>& /* releaseBufferListener */) {
return false;
@@ -580,14 +572,6 @@ public:
virtual int32_t getQueuedFrameCount() const { return 0; }
- virtual void pushPendingState();
-
- /*
- * Merges the BufferlessSurfaceFrames from source with the target. If the same token exists in
- * both source and target, target's SurfaceFrame will be retained.
- */
- void mergeSurfaceFrames(State& source, State& target);
-
/**
* Returns active buffer size in the correct orientation. Buffer size is determined by undoing
* any buffer transformations. If the layer has no buffer then return INVALID_RECT.
@@ -617,7 +601,8 @@ public:
// ignored.
virtual RoundedCornerState getRoundedCornerState() const;
- virtual void notifyAvailableFrames(nsecs_t /*expectedPresentTime*/) {}
+ bool hasRoundedCorners() const override { return getRoundedCornerState().radius > .0f; }
+
virtual PixelFormat getPixelFormat() const { return PIXEL_FORMAT_NONE; }
/**
* Return whether this layer needs an input info. For most layer types
@@ -732,7 +717,7 @@ public:
* Called before updating the drawing state buffer. Used by BufferStateLayer to release any
* unlatched buffers in the drawing state.
*/
- virtual void bufferMayChange(sp<GraphicBuffer>& /* newBuffer */){};
+ virtual void bufferMayChange(const sp<GraphicBuffer>& /* newBuffer */){};
/*
* Remove relative z for the layer if its relative parent is not part of the
@@ -909,65 +894,6 @@ public:
virtual std::string getPendingBufferCounterName() { return ""; }
protected:
- class SyncPoint {
- public:
- explicit SyncPoint(uint64_t frameNumber, wp<Layer> requestedSyncLayer,
- wp<Layer> barrierLayer_legacy)
- : mFrameNumber(frameNumber),
- mFrameIsAvailable(false),
- mTransactionIsApplied(false),
- mRequestedSyncLayer(requestedSyncLayer),
- mBarrierLayer_legacy(barrierLayer_legacy) {}
- uint64_t getFrameNumber() const { return mFrameNumber; }
-
- bool frameIsAvailable() const { return mFrameIsAvailable; }
-
- void setFrameAvailable() { mFrameIsAvailable = true; }
-
- bool transactionIsApplied() const { return mTransactionIsApplied; }
-
- void setTransactionApplied() { mTransactionIsApplied = true; }
-
- sp<Layer> getRequestedSyncLayer() { return mRequestedSyncLayer.promote(); }
-
- sp<Layer> getBarrierLayer() const { return mBarrierLayer_legacy.promote(); }
-
- bool isTimeout() const {
- using namespace std::chrono_literals;
- static constexpr std::chrono::nanoseconds TIMEOUT_THRESHOLD = 1s;
-
- return std::chrono::steady_clock::now() - mCreateTimeStamp > TIMEOUT_THRESHOLD;
- }
-
- void checkTimeoutAndLog() {
- using namespace std::chrono_literals;
- static constexpr std::chrono::nanoseconds LOG_PERIOD = 1s;
-
- if (!frameIsAvailable() && isTimeout()) {
- const auto now = std::chrono::steady_clock::now();
- if (now - mLastLogTime > LOG_PERIOD) {
- mLastLogTime = now;
- sp<Layer> requestedSyncLayer = getRequestedSyncLayer();
- sp<Layer> barrierLayer = getBarrierLayer();
- ALOGW("[%s] sync point %" PRIu64 " wait timeout %lld for %s",
- requestedSyncLayer ? requestedSyncLayer->getDebugName() : "Removed",
- mFrameNumber, (now - mCreateTimeStamp).count(),
- barrierLayer ? barrierLayer->getDebugName() : "Removed");
- }
- }
- }
-
- private:
- const uint64_t mFrameNumber;
- std::atomic<bool> mFrameIsAvailable;
- std::atomic<bool> mTransactionIsApplied;
- wp<Layer> mRequestedSyncLayer;
- wp<Layer> mBarrierLayer_legacy;
- const std::chrono::time_point<std::chrono::steady_clock> mCreateTimeStamp =
- std::chrono::steady_clock::now();
- std::chrono::time_point<std::chrono::steady_clock> mLastLogTime;
- };
-
friend class impl::SurfaceInterceptor;
// For unit tests
@@ -986,7 +912,6 @@ protected:
ui::Dataspace outputDataspace);
virtual void preparePerFrameCompositionState();
virtual void commitTransaction(State& stateToCommit);
- virtual bool applyPendingStates(State* stateToCommit);
virtual uint32_t doTransactionResize(uint32_t flags, Layer::State* stateToCommit);
virtual void onSurfaceFrameCreated(const std::shared_ptr<frametimeline::SurfaceFrame>&) {}
@@ -1035,21 +960,6 @@ protected:
virtual ui::Transform getInputTransform() const;
virtual Rect getInputBounds() const;
- // SyncPoints which will be signaled when the correct frame is at the head
- // of the queue and dropped after the frame has been latched. Protected by
- // mLocalSyncPointMutex.
- Mutex mLocalSyncPointMutex;
- std::list<std::shared_ptr<SyncPoint>> mLocalSyncPoints;
-
- // SyncPoints which will be signaled and then dropped when the transaction
- // is applied
- std::list<std::shared_ptr<SyncPoint>> mRemoteSyncPoints;
-
- // Returns false if the relevant frame has already been latched
- bool addSyncPoint(const std::shared_ptr<SyncPoint>& point);
-
- void popPendingState(State* stateToCommit);
-
// constant
sp<SurfaceFlinger> mFlinger;
@@ -1059,14 +969,10 @@ protected:
// These are only accessed by the main thread or the tracing thread.
State mDrawingState;
- // Store a copy of the pending state so that the drawing thread can access the
- // states without a lock.
- std::deque<State> mPendingStatesSnapshot;
// these are protected by an external lock (mStateLock)
State mCurrentState;
std::atomic<uint32_t> mTransactionFlags{0};
- std::deque<State> mPendingStates;
// Timestamp history for UIAutomation. Thread safe.
FrameTracker mFrameTracker;
@@ -1130,6 +1036,8 @@ protected:
// Used in buffer stuffing analysis in FrameTimeline.
nsecs_t mLastLatchTime = 0;
+ mutable bool mCurrentStateModified = false;
+
private:
virtual void setTransformHint(ui::Transform::RotationFlags) {}
@@ -1154,7 +1062,6 @@ private:
void updateTreeHasFrameRateVote();
void setZOrderRelativeOf(const wp<Layer>& relativeOf);
- void removeRemoteSyncPoints();
// Find the root of the cloned hierarchy, this means the first non cloned parent.
// This will return null if first non cloned parent is not found.
@@ -1204,7 +1111,7 @@ private:
mutable int32_t mPriority = Layer::PRIORITY_UNSET;
// A list of regions on this layer that should have blurs.
- const std::vector<BlurRegion>& getBlurRegions() const;
+ const std::vector<BlurRegion> getBlurRegions() const;
};
std::ostream& operator<<(std::ostream& stream, const Layer::FrameRate& rate);
diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp
index 1d00cc38f2..a9fd16cb75 100644
--- a/services/surfaceflinger/RefreshRateOverlay.cpp
+++ b/services/surfaceflinger/RefreshRateOverlay.cpp
@@ -208,7 +208,8 @@ bool RefreshRateOverlay::createLayer() {
return true;
}
-const std::vector<sp<GraphicBuffer>>& RefreshRateOverlay::getOrCreateBuffers(uint32_t fps) {
+const std::vector<std::shared_ptr<renderengine::ExternalTexture>>&
+RefreshRateOverlay::getOrCreateBuffers(uint32_t fps) {
if (mBufferCache.find(fps) == mBufferCache.end()) {
// Ensure the range is > 0, so we don't divide by 0.
const auto rangeLength = std::max(1u, mHighFps - mLowFps);
@@ -222,7 +223,17 @@ const std::vector<sp<GraphicBuffer>>& RefreshRateOverlay::getOrCreateBuffers(uin
color.g = HIGH_FPS_COLOR.g * fpsScale + LOW_FPS_COLOR.g * (1 - fpsScale);
color.b = HIGH_FPS_COLOR.b * fpsScale + LOW_FPS_COLOR.b * (1 - fpsScale);
color.a = ALPHA;
- mBufferCache.emplace(fps, SevenSegmentDrawer::drawNumber(fps, color, mShowSpinner));
+ auto buffers = SevenSegmentDrawer::drawNumber(fps, color, mShowSpinner);
+ std::vector<std::shared_ptr<renderengine::ExternalTexture>> textures;
+ std::transform(buffers.begin(), buffers.end(), std::back_inserter(textures),
+ [&](const auto& buffer) -> std::shared_ptr<renderengine::ExternalTexture> {
+ return std::make_shared<
+ renderengine::ExternalTexture>(buffer,
+ mFlinger.getRenderEngine(),
+ renderengine::ExternalTexture::
+ Usage::READABLE);
+ });
+ mBufferCache.emplace(fps, textures);
}
return mBufferCache[fps];
@@ -231,8 +242,14 @@ const std::vector<sp<GraphicBuffer>>& RefreshRateOverlay::getOrCreateBuffers(uin
void RefreshRateOverlay::setViewport(ui::Size viewport) {
Rect frame((3 * viewport.width) >> 4, viewport.height >> 5);
frame.offsetBy(viewport.width >> 5, viewport.height >> 4);
- mLayer->setFrame(frame);
+ layer_state_t::matrix22_t matrix;
+ matrix.dsdx = frame.getWidth() / static_cast<float>(SevenSegmentDrawer::getWidth());
+ matrix.dtdx = 0;
+ matrix.dtdy = 0;
+ matrix.dsdy = frame.getHeight() / static_cast<float>(SevenSegmentDrawer::getHeight());
+ mLayer->setMatrix(matrix, true);
+ mLayer->setPosition(frame.left, frame.top);
mFlinger.mTransactionFlags.fetch_or(eTransactionMask);
}
diff --git a/services/surfaceflinger/RefreshRateOverlay.h b/services/surfaceflinger/RefreshRateOverlay.h
index c16cfa07a4..aa8329c46a 100644
--- a/services/surfaceflinger/RefreshRateOverlay.h
+++ b/services/surfaceflinger/RefreshRateOverlay.h
@@ -16,13 +16,14 @@
#pragma once
-#include <unordered_map>
-
#include <math/vec4.h>
+#include <renderengine/RenderEngine.h>
#include <ui/Rect.h>
#include <ui/Size.h>
#include <utils/StrongPointer.h>
+#include <unordered_map>
+
#include "Fps.h"
namespace android {
@@ -70,7 +71,8 @@ private:
};
bool createLayer();
- const std::vector<sp<GraphicBuffer>>& getOrCreateBuffers(uint32_t fps);
+ const std::vector<std::shared_ptr<renderengine::ExternalTexture>>& getOrCreateBuffers(
+ uint32_t fps);
SurfaceFlinger& mFlinger;
const sp<Client> mClient;
@@ -78,7 +80,8 @@ private:
sp<IBinder> mIBinder;
sp<IGraphicBufferProducer> mGbp;
- std::unordered_map<int, std::vector<sp<GraphicBuffer>>> mBufferCache;
+ std::unordered_map<int, std::vector<std::shared_ptr<renderengine::ExternalTexture>>>
+ mBufferCache;
std::optional<int> mCurrentFps;
int mFrame = 0;
static constexpr float ALPHA = 0.8f;
diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp
index d0032ac7fd..00090d948a 100644
--- a/services/surfaceflinger/RegionSamplingThread.cpp
+++ b/services/surfaceflinger/RegionSamplingThread.cpp
@@ -438,18 +438,22 @@ void RegionSamplingThread::captureSample() {
mFlinger.traverseLayersInLayerStack(layerStack, CaptureArgs::UNSET_UID, filterVisitor);
};
- sp<GraphicBuffer> buffer = nullptr;
- if (mCachedBuffer && mCachedBuffer->getWidth() == sampledBounds.getWidth() &&
- mCachedBuffer->getHeight() == sampledBounds.getHeight()) {
+ std::shared_ptr<renderengine::ExternalTexture> buffer = nullptr;
+ if (mCachedBuffer && mCachedBuffer->getBuffer()->getWidth() == sampledBounds.getWidth() &&
+ mCachedBuffer->getBuffer()->getHeight() == sampledBounds.getHeight()) {
buffer = mCachedBuffer;
} else {
const uint32_t usage =
GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE;
- buffer = new GraphicBuffer(sampledBounds.getWidth(), sampledBounds.getHeight(),
- PIXEL_FORMAT_RGBA_8888, 1, usage, "RegionSamplingThread");
- const status_t bufferStatus = buffer->initCheck();
+ sp<GraphicBuffer> graphicBuffer =
+ new GraphicBuffer(sampledBounds.getWidth(), sampledBounds.getHeight(),
+ PIXEL_FORMAT_RGBA_8888, 1, usage, "RegionSamplingThread");
+ const status_t bufferStatus = graphicBuffer->initCheck();
LOG_ALWAYS_FATAL_IF(bufferStatus != OK, "captureSample: Buffer failed to allocate: %d",
bufferStatus);
+ buffer = std::make_shared<
+ renderengine::ExternalTexture>(graphicBuffer, mFlinger.getRenderEngine(),
+ renderengine::ExternalTexture::Usage::WRITEABLE);
}
const sp<SyncScreenCaptureListener> captureListener = new SyncScreenCaptureListener();
@@ -465,8 +469,8 @@ void RegionSamplingThread::captureSample() {
}
ALOGV("Sampling %zu descriptors", activeDescriptors.size());
- std::vector<float> lumas =
- sampleBuffer(buffer, sampledBounds.leftTop(), activeDescriptors, orientation);
+ std::vector<float> lumas = sampleBuffer(buffer->getBuffer(), sampledBounds.leftTop(),
+ activeDescriptors, orientation);
if (lumas.size() != activeDescriptors.size()) {
ALOGW("collected %zu median luma values for %zu descriptors", lumas.size(),
activeDescriptors.size());
@@ -477,16 +481,6 @@ void RegionSamplingThread::captureSample() {
activeDescriptors[d].listener->onSampleCollected(lumas[d]);
}
- // Extend the lifetime of mCachedBuffer from the previous frame to here to ensure that:
- // 1) The region sampling thread is the last owner of the buffer, and the freeing of the buffer
- // happens in this thread, as opposed to the main thread.
- // 2) The listener(s) receive their notifications prior to freeing the buffer.
- if (mCachedBuffer != nullptr && mCachedBuffer != buffer) {
- if (mFlinger.getRenderEngine().getRenderEngineType() ==
- renderengine::RenderEngine::RenderEngineType::SKIA_GL_THREADED) {
- mFlinger.getRenderEngine().unbindExternalTextureBuffer(mCachedBuffer->getId());
- }
- }
mCachedBuffer = buffer;
ATRACE_INT(lumaSamplingStepTag, static_cast<int>(samplingStep::noWorkNeeded));
}
diff --git a/services/surfaceflinger/RegionSamplingThread.h b/services/surfaceflinger/RegionSamplingThread.h
index 0defdb3fcb..86632db490 100644
--- a/services/surfaceflinger/RegionSamplingThread.h
+++ b/services/surfaceflinger/RegionSamplingThread.h
@@ -16,17 +16,19 @@
#pragma once
+#include <android-base/thread_annotations.h>
+#include <binder/IBinder.h>
+#include <renderengine/ExternalTexture.h>
+#include <ui/GraphicBuffer.h>
+#include <ui/Rect.h>
+#include <utils/StrongPointer.h>
+
#include <chrono>
#include <condition_variable>
#include <mutex>
#include <thread>
#include <unordered_map>
-#include <android-base/thread_annotations.h>
-#include <binder/IBinder.h>
-#include <ui/GraphicBuffer.h>
-#include <ui/Rect.h>
-#include <utils/StrongPointer.h>
#include "Scheduler/OneShotTimer.h"
namespace android {
@@ -122,7 +124,8 @@ private:
std::mutex mSamplingMutex;
std::unordered_map<wp<IBinder>, Descriptor, WpHash> mDescriptors GUARDED_BY(mSamplingMutex);
- sp<GraphicBuffer> mCachedBuffer GUARDED_BY(mSamplingMutex) = nullptr;
+ std::shared_ptr<renderengine::ExternalTexture> mCachedBuffer GUARDED_BY(mSamplingMutex) =
+ nullptr;
};
} // namespace android
diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp
index 716bd59dfc..f4b87dd9f5 100644
--- a/services/surfaceflinger/Scheduler/EventThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventThread.cpp
@@ -218,12 +218,18 @@ namespace impl {
EventThread::EventThread(std::unique_ptr<VSyncSource> vsyncSource,
android::frametimeline::TokenManager* tokenManager,
InterceptVSyncsCallback interceptVSyncsCallback,
- ThrottleVsyncCallback throttleVsyncCallback)
+ ThrottleVsyncCallback throttleVsyncCallback,
+ GetVsyncPeriodFunction getVsyncPeriodFunction)
: mVSyncSource(std::move(vsyncSource)),
mTokenManager(tokenManager),
mInterceptVSyncsCallback(std::move(interceptVSyncsCallback)),
mThrottleVsyncCallback(std::move(throttleVsyncCallback)),
+ mGetVsyncPeriodFunction(std::move(getVsyncPeriodFunction)),
mThreadName(mVSyncSource->getName()) {
+
+ LOG_ALWAYS_FATAL_IF(getVsyncPeriodFunction == nullptr,
+ "getVsyncPeriodFunction must not be null");
+
mVSyncSource->setCallback(this);
mThread = std::thread([this]() NO_THREAD_SAFETY_ANALYSIS {
@@ -595,9 +601,13 @@ void EventThread::dispatchEvent(const DisplayEventReceiver::Event& event,
const DisplayEventConsumers& consumers) {
const uint8_t num_attempts = 3;
for (const auto& consumer : consumers) {
+ DisplayEventReceiver::Event copy = event;
+ if (event.header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) {
+ copy.vsync.frameInterval = mGetVsyncPeriodFunction(consumer->mOwnerUid);
+ }
bool needs_retry = true;
for (uint8_t attempt = 0; needs_retry && (attempt < num_attempts); attempt++) {
- switch (consumer->postEvent(event)) {
+ switch (consumer->postEvent(copy)) {
case NO_ERROR:
needs_retry = false;
break;
diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h
index 2b85a43d8d..07fa805d6c 100644
--- a/services/surfaceflinger/Scheduler/EventThread.h
+++ b/services/surfaceflinger/Scheduler/EventThread.h
@@ -152,9 +152,10 @@ class EventThread : public android::EventThread, private VSyncSource::Callback {
public:
using InterceptVSyncsCallback = std::function<void(nsecs_t)>;
using ThrottleVsyncCallback = std::function<bool(nsecs_t, uid_t)>;
+ using GetVsyncPeriodFunction = std::function<nsecs_t(uid_t)>;
EventThread(std::unique_ptr<VSyncSource>, frametimeline::TokenManager*, InterceptVSyncsCallback,
- ThrottleVsyncCallback);
+ ThrottleVsyncCallback, GetVsyncPeriodFunction);
~EventThread();
sp<EventThreadConnection> createEventConnection(
@@ -210,6 +211,7 @@ private:
const InterceptVSyncsCallback mInterceptVSyncsCallback;
const ThrottleVsyncCallback mThrottleVsyncCallback;
+ const GetVsyncPeriodFunction mGetVsyncPeriodFunction;
const char* const mThreadName;
std::thread mThread;
diff --git a/services/surfaceflinger/Scheduler/OneShotTimer.cpp b/services/surfaceflinger/Scheduler/OneShotTimer.cpp
index ce3b0c6cfa..d659398394 100644
--- a/services/surfaceflinger/Scheduler/OneShotTimer.cpp
+++ b/services/surfaceflinger/Scheduler/OneShotTimer.cpp
@@ -40,13 +40,21 @@ void calculateTimeoutTime(std::chrono::nanoseconds timestamp, timespec* spec) {
namespace android {
namespace scheduler {
+std::chrono::steady_clock::time_point OneShotTimer::Clock::now() const {
+ return std::chrono::steady_clock::now();
+}
+
OneShotTimer::OneShotTimer(std::string name, const Interval& interval,
const ResetCallback& resetCallback,
- const TimeoutCallback& timeoutCallback)
- : mName(std::move(name)),
+ const TimeoutCallback& timeoutCallback,
+ std::unique_ptr<OneShotTimer::Clock> clock)
+ : mClock(std::move(clock)),
+ mName(std::move(name)),
mInterval(interval),
mResetCallback(resetCallback),
- mTimeoutCallback(timeoutCallback) {}
+ mTimeoutCallback(timeoutCallback) {
+ LOG_ALWAYS_FATAL_IF(!mClock, "Clock must not be provided");
+}
OneShotTimer::~OneShotTimer() {
stop();
@@ -112,7 +120,7 @@ void OneShotTimer::loop() {
break;
}
- auto triggerTime = std::chrono::steady_clock::now() + mInterval;
+ auto triggerTime = mClock->now() + mInterval;
state = TimerState::WAITING;
while (state == TimerState::WAITING) {
constexpr auto zero = std::chrono::steady_clock::duration::zero();
@@ -128,10 +136,9 @@ void OneShotTimer::loop() {
state = checkForResetAndStop(state);
if (state == TimerState::RESET) {
- triggerTime = std::chrono::steady_clock::now() + mInterval;
+ triggerTime = mClock->now() + mInterval;
state = TimerState::WAITING;
- } else if (state == TimerState::WAITING &&
- (triggerTime - std::chrono::steady_clock::now()) <= zero) {
+ } else if (state == TimerState::WAITING && (triggerTime - mClock->now()) <= zero) {
triggerTimeout = true;
state = TimerState::IDLE;
}
diff --git a/services/surfaceflinger/Scheduler/OneShotTimer.h b/services/surfaceflinger/Scheduler/OneShotTimer.h
index 3690ce7542..7285427abb 100644
--- a/services/surfaceflinger/Scheduler/OneShotTimer.h
+++ b/services/surfaceflinger/Scheduler/OneShotTimer.h
@@ -36,8 +36,17 @@ public:
using ResetCallback = std::function<void()>;
using TimeoutCallback = std::function<void()>;
+ class Clock {
+ public:
+ Clock() = default;
+ virtual ~Clock() = default;
+
+ virtual std::chrono::steady_clock::time_point now() const;
+ };
+
OneShotTimer(std::string name, const Interval& interval, const ResetCallback& resetCallback,
- const TimeoutCallback& timeoutCallback);
+ const TimeoutCallback& timeoutCallback,
+ std::unique_ptr<OneShotTimer::Clock> = std::make_unique<OneShotTimer::Clock>());
~OneShotTimer();
// Initializes and turns on the idle timer.
@@ -78,6 +87,9 @@ private:
// Thread waiting for timer to expire.
std::thread mThread;
+ // Clock object for the timer. Mocked in unit tests.
+ std::unique_ptr<Clock> mClock;
+
// Semaphore to keep mThread synchronized.
sem_t mSemaphore;
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 43c7666031..8d25898f9e 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -248,15 +248,34 @@ impl::EventThread::ThrottleVsyncCallback Scheduler::makeThrottleVsyncCallback()
};
}
+impl::EventThread::GetVsyncPeriodFunction Scheduler::makeGetVsyncPeriodFunction() const {
+ return [this](uid_t uid) {
+ nsecs_t basePeriod = mRefreshRateConfigs.getCurrentRefreshRate().getVsyncPeriod();
+ const auto frameRate = getFrameRateOverride(uid);
+ if (!frameRate.has_value()) {
+ return basePeriod;
+ }
+
+ const auto divider = scheduler::RefreshRateConfigs::getFrameRateDivider(
+ mRefreshRateConfigs.getCurrentRefreshRate().getFps(), *frameRate);
+ if (divider <= 1) {
+ return basePeriod;
+ }
+ return basePeriod * divider;
+ };
+}
+
Scheduler::ConnectionHandle Scheduler::createConnection(
const char* connectionName, frametimeline::TokenManager* tokenManager,
std::chrono::nanoseconds workDuration, std::chrono::nanoseconds readyDuration,
impl::EventThread::InterceptVSyncsCallback interceptCallback) {
auto vsyncSource = makePrimaryDispSyncSource(connectionName, workDuration, readyDuration);
auto throttleVsync = makeThrottleVsyncCallback();
+ auto getVsyncPeriod = makeGetVsyncPeriodFunction();
auto eventThread = std::make_unique<impl::EventThread>(std::move(vsyncSource), tokenManager,
std::move(interceptCallback),
- std::move(throttleVsync));
+ std::move(throttleVsync),
+ std::move(getVsyncPeriod));
bool triggerRefresh = !strcmp(connectionName, "app");
return createConnection(std::move(eventThread), triggerRefresh);
}
@@ -453,7 +472,8 @@ Scheduler::ConnectionHandle Scheduler::enableVSyncInjection(bool enable) {
std::make_unique<impl::EventThread>(std::move(vsyncSource),
/*tokenManager=*/nullptr,
impl::EventThread::InterceptVSyncsCallback(),
- impl::EventThread::ThrottleVsyncCallback());
+ impl::EventThread::ThrottleVsyncCallback(),
+ impl::EventThread::GetVsyncPeriodFunction());
// EventThread does not dispatch VSYNC unless the display is connected and powered on.
eventThread->onHotplugReceived(PhysicalDisplayId::fromPort(0), true);
@@ -930,6 +950,13 @@ void Scheduler::setPreferredRefreshRateForUid(FrameRateOverride frameRateOverrid
}
}
+std::chrono::steady_clock::time_point Scheduler::getPreviousVsyncFrom(
+ nsecs_t expectedPresentTime) const {
+ const auto presentTime = std::chrono::nanoseconds(expectedPresentTime);
+ const auto vsyncPeriod = std::chrono::nanoseconds(mVsyncSchedule.tracker->currentPeriod());
+ return std::chrono::steady_clock::time_point(presentTime - vsyncPeriod);
+}
+
void Scheduler::setIdleState() {
mDisplayIdle = true;
}
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 95235725e8..29cbd86e47 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -150,6 +150,8 @@ public:
bool isVsyncValid(nsecs_t expectedVsyncTimestamp, uid_t uid) const
EXCLUDES(mFrameRateOverridesMutex);
+ std::chrono::steady_clock::time_point getPreviousVsyncFrom(nsecs_t expectedPresentTime) const;
+
void dump(std::string&) const;
void dump(ConnectionHandle, std::string&) const;
void dumpVsync(std::string&) const;
@@ -242,6 +244,7 @@ private:
EXCLUDES(mFrameRateOverridesMutex);
impl::EventThread::ThrottleVsyncCallback makeThrottleVsyncCallback() const;
+ impl::EventThread::GetVsyncPeriodFunction makeGetVsyncPeriodFunction() const;
// Stores EventThread associated with a given VSyncSource, and an initial EventThreadConnection.
struct Connection {
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index f01e99cbeb..4c512590fc 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -64,7 +64,6 @@
#include <private/android_filesystem_config.h>
#include <private/gui/SyncFeatures.h>
#include <renderengine/RenderEngine.h>
-#include <statslog.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fstream>
@@ -346,19 +345,6 @@ bool SurfaceFlinger::sDirectStreaming;
::DisplayConfig::ClientInterface *mDisplayConfigIntf = nullptr;
DisplayConfigCallbackHandler *mDisplayConfigCallbackhandler = nullptr;
#endif
-std::string getHwcServiceName() {
- char value[PROPERTY_VALUE_MAX] = {};
- property_get("debug.sf.hwc_service_name", value, "default");
- ALOGI("Using HWComposer service: '%s'", value);
- return std::string(value);
-}
-
-bool useTrebleTestingOverride() {
- char value[PROPERTY_VALUE_MAX] = {};
- property_get("debug.sf.treble_testing_override", value, "false");
- ALOGI("Treble testing override: '%s'", value);
- return std::string(value) == "true";
-}
std::string decodeDisplayColorSetting(DisplayColorSetting displayColorSetting) {
switch(displayColorSetting) {
@@ -382,8 +368,6 @@ bool callingThreadHasRotateSurfaceFlingerAccess() {
PermissionCache::checkPermission(sRotateSurfaceFlinger, pid, uid);
}
-SurfaceFlingerBE::SurfaceFlingerBE() : mHwcServiceName(getHwcServiceName()) {}
-
bool SmomoWrapper::init() {
mSmoMoLibHandle = dlopen(SMOMO_LIBRARY_NAME, RTLD_NOW);
if (!mSmoMoLibHandle) {
@@ -470,8 +454,11 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory, SkipInitializationTag)
mFrameTimeline(mFactory.createFrameTimeline(mTimeStats, getpid())),
mEventQueue(mFactory.createMessageQueue()),
mCompositionEngine(mFactory.createCompositionEngine()),
+ mHwcServiceName(base::GetProperty("debug.sf.hwc_service_name"s, "default"s)),
mInternalDisplayDensity(getDensityFromProperty("ro.sf.lcd_density", true)),
mEmulatedDisplayDensity(getDensityFromProperty("qemu.sf.lcd_density", false)) {
+ ALOGI("Using HWComposer service: %s", mHwcServiceName.c_str());
+
mSetInputWindowsListener = new SetInputWindowsListener([&]() { setInputWindowsFinished(); });
}
@@ -603,12 +590,13 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipI
// comes online to attempt to read the property. The property is
// instead read after the boot animation
- if (useTrebleTestingOverride()) {
+ if (base::GetBoolProperty("debug.sf.treble_testing_override"s, false)) {
// Without the override SurfaceFlinger cannot connect to HIDL
// services that are not listed in the manifests. Considered
// deriving the setting from the set service name, but it
// would be brittle if the name that's not 'default' is used
// for production purposes later on.
+ ALOGI("Enabling Treble testing override");
android::hardware::details::setTrebleTestingOverride(true);
}
@@ -843,7 +831,6 @@ void SurfaceFlinger::bootFinished() {
ALOGI("Boot is finished (%ld ms)", long(ns2ms(duration)) );
mFrameTracer->initialize();
- mTimeStats->onBootFinished();
mFrameTimeline->onBootFinished();
// wait patiently for the window manager death
@@ -910,12 +897,16 @@ uint32_t SurfaceFlinger::getNewTexture() {
// The pool was empty, so we need to get a new texture name directly using a
// blocking call to the main thread
- return schedule([this] {
+ auto genTextures = [this] {
uint32_t name = 0;
getRenderEngine().genTextures(1, &name);
return name;
- })
- .get();
+ };
+ if (std::this_thread::get_id() == mMainThreadId) {
+ return genTextures();
+ } else {
+ return schedule(genTextures).get();
+ }
}
void SurfaceFlinger::deleteTextureAsync(uint32_t texture) {
@@ -950,8 +941,9 @@ void SurfaceFlinger::init() {
: renderengine::RenderEngine::ContextPriority::MEDIUM)
.build()));
mCompositionEngine->setTimeStats(mTimeStats);
- mCompositionEngine->setHwComposer(getFactory().createHWComposer(getBE().mHwcServiceName));
+ mCompositionEngine->setHwComposer(getFactory().createHWComposer(mHwcServiceName));
mCompositionEngine->getHwComposer().setConfiguration(this, getBE().mComposerSequenceId);
+ ClientCache::getInstance().setRenderEngine(&getRenderEngine());
// Process any initial hotplug and resulting display changes.
processDisplayHotplugEventsLocked();
const auto display = getDefaultDisplayDeviceLocked();
@@ -1599,6 +1591,11 @@ status_t SurfaceFlinger::overrideHdrTypes(const sp<IBinder>& displayToken,
return NO_ERROR;
}
+status_t SurfaceFlinger::onPullAtom(const int32_t atomId, std::string* pulledData, bool* success) {
+ *success = mTimeStats->onPullAtom(atomId, pulledData);
+ return NO_ERROR;
+}
+
status_t SurfaceFlinger::getDisplayedContentSamplingAttributes(const sp<IBinder>& displayToken,
ui::PixelFormat* outFormat,
ui::Dataspace* outDataspace,
@@ -2472,6 +2469,8 @@ void SurfaceFlinger::onMessageRefresh() {
std::chrono::milliseconds(mDebugRegion > 1 ? mDebugRegion : 0);
}
+ refreshArgs.earliestPresentTime = mScheduler->getPreviousVsyncFrom(mExpectedPresentTime);
+
mGeometryInvalid = false;
// Store the present time just before calling to the composition engine so we could notify
@@ -2549,6 +2548,9 @@ bool SurfaceFlinger::handleMessageInvalidate() {
ATRACE_CALL();
bool refreshNeeded = handlePageFlip();
+ // Send on commit callbacks
+ mTransactionCallbackInvoker.sendCallbacks();
+
if (mVisibleRegionsDirty) {
computeLayerBounds();
}
@@ -2651,7 +2653,7 @@ void SurfaceFlinger::postComposition() {
// information from previous' frame classification is already available when sending jank info
// to clients, so they get jank classification as early as possible.
mFrameTimeline->setSfPresent(systemTime(), mPreviousPresentFences[0].fenceTime,
- glCompositionDoneFenceTime != FenceTime::NO_FENCE);
+ glCompositionDoneFenceTime);
nsecs_t dequeueReadyTime = systemTime();
for (const auto& layer : mLayersWithQueuedFrames) {
@@ -3461,6 +3463,7 @@ void SurfaceFlinger::processDisplayChanged(const wp<IBinder>& displayToken,
display->setProjection(currentState.orientation, currentState.layerStackSpaceRect,
currentState.orientedDisplaySpaceRect);
}
+ mDefaultDisplayTransformHint = display->getTransformHint();
}
if (currentState.width != drawingState.width ||
currentState.height != drawingState.height) {
@@ -3547,13 +3550,6 @@ void SurfaceFlinger::processDisplayChangesLocked() {
}
void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) {
- const nsecs_t expectedPresentTime = mExpectedPresentTime.load();
-
- // Notify all layers of available frames
- mCurrentState.traverse([expectedPresentTime](Layer* layer) {
- layer->notifyAvailableFrames(expectedPresentTime);
- });
-
/*
* Traversal of the children
* (perform the transaction for each of them if needed)
@@ -4011,76 +4007,44 @@ status_t SurfaceFlinger::addClientLayer(const sp<Client>& client, const sp<IBind
const sp<IBinder>& parentHandle,
const sp<Layer>& parentLayer, bool addToCurrentState,
uint32_t* outTransformHint) {
- // add this layer to the current state list
- {
- Mutex::Autolock _l(mStateLock);
- sp<Layer> parent;
- if (parentHandle != nullptr) {
- parent = fromHandleLocked(parentHandle).promote();
- if (parent == nullptr) {
- return NAME_NOT_FOUND;
- }
- } else {
- parent = parentLayer;
- }
-
- if (mNumLayers >= ISurfaceComposer::MAX_LAYERS) {
- ALOGE("AddClientLayer failed, mNumLayers (%zu) >= MAX_LAYERS (%zu)", mNumLayers.load(),
- ISurfaceComposer::MAX_LAYERS);
- mCurrentState.traverseInZOrder([&](Layer* layer) {
- const auto& p = layer->getParent();
- ALOGE("layer (%s) :: parent (%s).",
- layer->getName().c_str(),
- (p != nullptr) ? p->getName().c_str() : "no-parent");
- });
- return NO_MEMORY;
- }
+ if (mNumLayers >= ISurfaceComposer::MAX_LAYERS) {
+ ALOGE("AddClientLayer failed, mNumLayers (%zu) >= MAX_LAYERS (%zu)", mNumLayers.load(),
+ ISurfaceComposer::MAX_LAYERS);
+ mCurrentState.traverseInZOrder([&](Layer* layer) {
+ const auto& p = layer->getParent();
+ ALOGE("layer (%s) :: parent (%s).",
+ layer->getName().c_str(),
+ (p != nullptr) ? p->getName().c_str() : "no-parent");
+ });
+ return NO_MEMORY;
+ }
- mLayersByLocalBinderToken.emplace(handle->localBinder(), lbc);
+ wp<IBinder> initialProducer;
+ if (gbc != nullptr) {
+ initialProducer = IInterface::asBinder(gbc);
+ }
+ setLayerCreatedState(handle, lbc, parentHandle, parentLayer, initialProducer);
- if (parent == nullptr && addToCurrentState) {
- mCurrentState.layersSortedByZ.add(lbc);
- } else if (parent == nullptr) {
- lbc->onRemovedFromCurrentState();
- } else if (parent->isRemovedFromCurrentState()) {
- parent->addChild(lbc);
- lbc->onRemovedFromCurrentState();
- } else {
- parent->addChild(lbc);
- }
-
- if (gbc != nullptr) {
- mGraphicBufferProducerList.insert(IInterface::asBinder(gbc).get());
- LOG_ALWAYS_FATAL_IF(mGraphicBufferProducerList.size() >
- mMaxGraphicBufferProducerListSize,
- "Suspected IGBP leak: %zu IGBPs (%zu max), %zu Layers",
- mGraphicBufferProducerList.size(),
- mMaxGraphicBufferProducerListSize, mNumLayers.load());
- if (mGraphicBufferProducerList.size() > mGraphicBufferProducerListSizeLogThreshold) {
- ALOGW("Suspected IGBP leak: %zu IGBPs (%zu max), %zu Layers",
- mGraphicBufferProducerList.size(), mMaxGraphicBufferProducerListSize,
- mNumLayers.load());
- }
- }
+ // Create a transaction includes the initial parent and producer.
+ Vector<ComposerState> states;
+ Vector<DisplayState> displays;
- if (const auto token = getInternalDisplayTokenLocked()) {
- const ssize_t index = mCurrentState.displays.indexOfKey(token);
- if (index >= 0) {
- const DisplayDeviceState& state = mCurrentState.displays.valueAt(index);
- lbc->updateTransformHint(ui::Transform::toRotationFlags(state.orientation));
- }
- }
- if (outTransformHint) {
- *outTransformHint = lbc->getTransformHint();
- }
+ ComposerState composerState;
+ composerState.state.what = layer_state_t::eLayerCreated;
+ composerState.state.surface = handle;
+ states.add(composerState);
- mLayersAdded = true;
+ lbc->updateTransformHint(mDefaultDisplayTransformHint);
+ if (outTransformHint) {
+ *outTransformHint = mDefaultDisplayTransformHint;
}
-
// attach this layer to the client
client->attachLayer(handle, lbc);
- return NO_ERROR;
+ return setTransactionState(FrameTimelineInfo{}, states, displays, 0 /* flags */, nullptr,
+ InputWindowCommands{}, -1 /* desiredPresentTime */,
+ true /* isAutoTimestamp */, {}, false /* hasListenerCallbacks */, {},
+ 0 /* Undefined transactionId */);
}
void SurfaceFlinger::removeGraphicBufferProducerAsync(const wp<IBinder>& binder) {
@@ -4457,7 +4421,6 @@ void SurfaceFlinger::applyTransactionState(const FrameTimelineInfo& frameTimelin
if (uncacheBuffer.isValid()) {
ClientCache::getInstance().erase(uncacheBuffer);
- getRenderEngine().unbindExternalTextureBuffer(uncacheBuffer.id);
}
// If a synchronous transaction is explicitly requested without any changes, force a transaction
@@ -4595,19 +4558,47 @@ bool SurfaceFlinger::callingThreadHasUnscopedSurfaceFlingerAccess(bool usePermis
uint32_t SurfaceFlinger::setClientStateLocked(
const FrameTimelineInfo& frameTimelineInfo, const ComposerState& composerState,
int64_t desiredPresentTime, bool isAutoTimestamp, int64_t postTime, uint32_t permissions,
- std::unordered_set<ListenerCallbacks, ListenerCallbacksHash>& listenerCallbacks) {
+ std::unordered_set<ListenerCallbacks, ListenerCallbacksHash>& outListenerCallbacks) {
const layer_state_t& s = composerState.state;
const bool privileged = permissions & Permission::ACCESS_SURFACE_FLINGER;
+
+ std::vector<ListenerCallbacks> filteredListeners;
for (auto& listener : s.listeners) {
+ // Starts a registration but separates the callback ids according to callback type. This
+ // allows the callback invoker to send on latch callbacks earlier.
// note that startRegistration will not re-register if the listener has
// already be registered for a prior surface control
- mTransactionCallbackInvoker.startRegistration(listener);
- listenerCallbacks.insert(listener);
+
+ ListenerCallbacks onCommitCallbacks = listener.filter(CallbackId::Type::ON_COMMIT);
+ if (!onCommitCallbacks.callbackIds.empty()) {
+ mTransactionCallbackInvoker.startRegistration(onCommitCallbacks);
+ filteredListeners.push_back(onCommitCallbacks);
+ outListenerCallbacks.insert(onCommitCallbacks);
+ }
+
+ ListenerCallbacks onCompleteCallbacks = listener.filter(CallbackId::Type::ON_COMPLETE);
+ if (!onCompleteCallbacks.callbackIds.empty()) {
+ mTransactionCallbackInvoker.startRegistration(onCompleteCallbacks);
+ filteredListeners.push_back(onCompleteCallbacks);
+ outListenerCallbacks.insert(onCompleteCallbacks);
+ }
}
+ const uint64_t what = s.what;
+ uint32_t flags = 0;
sp<Layer> layer = nullptr;
if (s.surface) {
- layer = fromHandleLocked(s.surface).promote();
+ if (what & layer_state_t::eLayerCreated) {
+ layer = handleLayerCreatedLocked(s.surface, privileged);
+ if (layer) {
+ // put the created layer into mLayersByLocalBinderToken.
+ mLayersByLocalBinderToken.emplace(s.surface->localBinder(), layer);
+ flags |= eTransactionNeeded | eTraversalNeeded;
+ mLayersAdded = true;
+ }
+ } else {
+ layer = fromHandleLocked(s.surface).promote();
+ }
} else {
// The client may provide us a null handle. Treat it as if the layer was removed.
ALOGW("Attempt to set client state with a null layer handle");
@@ -4620,16 +4611,6 @@ uint32_t SurfaceFlinger::setClientStateLocked(
return 0;
}
- uint32_t flags = 0;
-
- const uint64_t what = s.what;
-
- // If we are deferring transaction, make sure to push the pending state, as otherwise the
- // pending state will also be deferred.
- if (what & layer_state_t::eDeferTransaction_legacy) {
- layer->pushPendingState();
- }
-
// Only set by BLAST adapter layers
if (what & layer_state_t::eProducerDisconnect) {
layer->onDisconnect();
@@ -4764,12 +4745,6 @@ uint32_t SurfaceFlinger::setClientStateLocked(
flags |= eTransactionNeeded | eTraversalNeeded | eTransformHintUpdateNeeded;
}
}
- if (what & layer_state_t::eDeferTransaction_legacy) {
- layer->deferTransactionUntil_legacy(s.barrierSurfaceControl_legacy->getHandle(),
- s.barrierFrameNumber);
- // We don't trigger a traversal here because if no other state is
- // changed, we don't want this to cause any more work
- }
if (what & layer_state_t::eTransformChanged) {
if (layer->setTransform(s.transform)) flags |= eTraversalNeeded;
}
@@ -4780,9 +4755,6 @@ uint32_t SurfaceFlinger::setClientStateLocked(
if (what & layer_state_t::eCropChanged) {
if (layer->setCrop(s.crop)) flags |= eTraversalNeeded;
}
- if (what & layer_state_t::eFrameChanged) {
- if (layer->setFrame(s.orientedDisplaySpaceRect)) flags |= eTraversalNeeded;
- }
if (what & layer_state_t::eAcquireFenceChanged) {
if (layer->setAcquireFence(s.acquireFence)) flags |= eTraversalNeeded;
}
@@ -4870,30 +4842,23 @@ uint32_t SurfaceFlinger::setClientStateLocked(
}
}
std::vector<sp<CallbackHandle>> callbackHandles;
- if ((what & layer_state_t::eHasListenerCallbacksChanged) && (!s.listeners.empty())) {
- for (auto& [listener, callbackIds] : s.listeners) {
+ if ((what & layer_state_t::eHasListenerCallbacksChanged) && (!filteredListeners.empty())) {
+ for (auto& [listener, callbackIds] : filteredListeners) {
callbackHandles.emplace_back(new CallbackHandle(listener, callbackIds, s.surface));
}
}
bool bufferChanged = what & layer_state_t::eBufferChanged;
bool cacheIdChanged = what & layer_state_t::eCachedBufferChanged;
- sp<GraphicBuffer> buffer;
+ std::shared_ptr<renderengine::ExternalTexture> buffer;
if (bufferChanged && cacheIdChanged && s.buffer != nullptr) {
- buffer = s.buffer;
- bool success = ClientCache::getInstance().add(s.cachedBuffer, s.buffer);
- if (success) {
- getRenderEngine().cacheExternalTextureBuffer(s.buffer);
- success = ClientCache::getInstance()
- .registerErasedRecipient(s.cachedBuffer,
- wp<ClientCache::ErasedRecipient>(this));
- if (!success) {
- getRenderEngine().unbindExternalTextureBuffer(s.buffer->getId());
- }
- }
+ ClientCache::getInstance().add(s.cachedBuffer, s.buffer);
+ buffer = ClientCache::getInstance().get(s.cachedBuffer);
} else if (cacheIdChanged) {
buffer = ClientCache::getInstance().get(s.cachedBuffer);
- } else if (bufferChanged) {
- buffer = s.buffer;
+ } else if (bufferChanged && s.buffer != nullptr) {
+ buffer = std::make_shared<
+ renderengine::ExternalTexture>(s.buffer, getRenderEngine(),
+ renderengine::ExternalTexture::Usage::READABLE);
}
if (buffer) {
const bool frameNumberChanged = what & layer_state_t::eFrameNumberChanged;
@@ -4976,10 +4941,6 @@ status_t SurfaceFlinger::createLayer(const String8& name, const sp<Client>& clie
switch (flags & ISurfaceComposerClient::eFXSurfaceMask) {
case ISurfaceComposerClient::eFXSurfaceBufferQueue:
- result = createBufferQueueLayer(client, std::move(uniqueName), w, h, flags,
- std::move(metadata), format, handle, gbp, &layer);
-
- break;
case ISurfaceComposerClient::eFXSurfaceBufferState: {
result = createBufferStateLayer(client, std::move(uniqueName), w, h, flags,
std::move(metadata), handle, &layer);
@@ -5103,14 +5064,7 @@ status_t SurfaceFlinger::createBufferStateLayer(const sp<Client>& client, std::s
sp<Layer>* outLayer) {
LayerCreationArgs args(this, client, std::move(name), w, h, flags, std::move(metadata));
args.textureName = getNewTexture();
- sp<BufferStateLayer> layer;
- {
- // TODO (b/173538294): Investigate why we need mStateLock here and above in
- // createBufferQueue layer. Is it the renderengine::Image?
- Mutex::Autolock lock(mStateLock);
- layer = getFactory().createBufferStateLayer(args);
-
- }
+ sp<BufferStateLayer> layer = getFactory().createBufferStateLayer(args);
*handle = layer->getHandle();
*outLayer = layer;
@@ -5198,7 +5152,7 @@ void SurfaceFlinger::onInitializeDisplays() {
setPowerModeInternal(display, hal::PowerMode::ON);
const nsecs_t vsyncPeriod = mRefreshRateConfigs->getCurrentRefreshRate().getVsyncPeriod();
mAnimFrameTracker.setDisplayRefreshPeriod(vsyncPeriod);
-
+ mDefaultDisplayTransformHint = display->getTransformHint();
// Use phase of 0 since phase is not known.
// Use latency of 0, which will snap to the ideal latency.
DisplayStatInfo stats{0 /* vsyncTime */, vsyncPeriod};
@@ -6156,13 +6110,16 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) {
#pragma clang diagnostic push
#pragma clang diagnostic error "-Wswitch-enum"
switch (static_cast<ISurfaceComposerTag>(code)) {
+ case ENABLE_VSYNC_INJECTIONS:
+ case INJECT_VSYNC:
+ if (!hasMockHwc()) return PERMISSION_DENIED;
+ [[fallthrough]];
// These methods should at minimum make sure that the client requested
// access to SF.
case BOOT_FINISHED:
case CLEAR_ANIMATION_FRAME_STATS:
case CREATE_DISPLAY:
case DESTROY_DISPLAY:
- case ENABLE_VSYNC_INJECTIONS:
case GET_ANIMATION_FRAME_STATS:
case OVERRIDE_HDR_TYPES:
case GET_HDR_CAPABILITIES:
@@ -6173,7 +6130,6 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) {
case SET_AUTO_LOW_LATENCY_MODE:
case GET_GAME_CONTENT_TYPE_SUPPORT:
case SET_GAME_CONTENT_TYPE:
- case INJECT_VSYNC:
case SET_POWER_MODE:
case GET_DISPLAYED_CONTENT_SAMPLING_ATTRIBUTES:
case SET_DISPLAY_CONTENT_SAMPLING_ENABLED:
@@ -6237,17 +6193,15 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) {
// captureLayers and captureDisplay will handle the permission check in the function
case CAPTURE_LAYERS:
case CAPTURE_DISPLAY:
- case SET_DISPLAY_BRIGHTNESS:
case SET_FRAME_TIMELINE_INFO:
case GET_GPU_CONTEXT_PRIORITY:
case GET_EXTRA_BUFFER_COUNT: {
// This is not sensitive information, so should not require permission control.
return OK;
}
+ case SET_DISPLAY_BRIGHTNESS:
case ADD_HDR_LAYER_INFO_LISTENER:
case REMOVE_HDR_LAYER_INFO_LISTENER: {
- // TODO (b/183985553): Should getting & setting brightness be part of this...?
- // codes that require permission check
IPCThreadState* ipc = IPCThreadState::self();
const int pid = ipc->getCallingPid();
const int uid = ipc->getCallingUid();
@@ -6282,6 +6236,13 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) {
}
return PERMISSION_DENIED;
}
+ case ON_PULL_ATOM: {
+ const int uid = IPCThreadState::self()->getCallingUid();
+ if (uid == AID_SYSTEM) {
+ return OK;
+ }
+ return PERMISSION_DENIED;
+ }
}
// These codes are used for the IBinder protocol to either interrogate the recipient
@@ -6611,9 +6572,24 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r
const int modeId = data.readInt32();
mDebugDisplayModeSetByBackdoor = false;
- const auto displayId = getInternalDisplayId();
+ const auto displayId = [&]() -> std::optional<PhysicalDisplayId> {
+ uint64_t inputDisplayId = 0;
+ if (data.readUint64(&inputDisplayId) == NO_ERROR) {
+ const auto token = getPhysicalDisplayToken(
+ static_cast<PhysicalDisplayId>(inputDisplayId));
+ if (!token) {
+ ALOGE("No display with id: %" PRIu64, inputDisplayId);
+ return std::nullopt;
+ }
+
+ return std::make_optional<PhysicalDisplayId>(inputDisplayId);
+ }
+
+ return getInternalDisplayId();
+ }();
+
if (!displayId) {
- ALOGE("No internal display found.");
+ ALOGE("No display found");
return NO_ERROR;
}
@@ -7248,15 +7224,17 @@ status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture,
const status_t bufferStatus = buffer->initCheck();
LOG_ALWAYS_FATAL_IF(bufferStatus != OK, "captureScreenCommon: Buffer failed to allocate: %d",
bufferStatus);
- return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, buffer,
+ const auto texture = std::make_shared<
+ renderengine::ExternalTexture>(buffer, getRenderEngine(),
+ renderengine::ExternalTexture::Usage::WRITEABLE);
+ return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, texture,
false /* regionSampling */, grayscale, captureListener);
}
-status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture,
- TraverseLayersFunction traverseLayers,
- sp<GraphicBuffer>& buffer, bool regionSampling,
- bool grayscale,
- const sp<IScreenCaptureListener>& captureListener) {
+status_t SurfaceFlinger::captureScreenCommon(
+ RenderAreaFuture renderAreaFuture, TraverseLayersFunction traverseLayers,
+ const std::shared_ptr<renderengine::ExternalTexture>& buffer, bool regionSampling,
+ bool grayscale, const sp<IScreenCaptureListener>& captureListener) {
ATRACE_CALL();
if (captureListener == nullptr) {
@@ -7289,15 +7267,6 @@ status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture,
regionSampling, grayscale, captureResults);
});
- // TODO(b/180767535): Remove this once we optimize buffer lifecycle for RenderEngine
- // Only do this when we're not doing region sampling, to allow the region sampling thread to
- // manage buffer lifecycle itself.
- if (!regionSampling &&
- getRenderEngine().getRenderEngineType() ==
- renderengine::RenderEngine::RenderEngineType::SKIA_GL_THREADED) {
- getRenderEngine().unbindExternalTextureBuffer(buffer->getId());
- }
-
captureResults.result = result;
captureListener->onScreenCaptureCompleted(captureResults);
}));
@@ -7305,11 +7274,10 @@ status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture,
return NO_ERROR;
}
-status_t SurfaceFlinger::renderScreenImplLocked(const RenderArea& renderArea,
- TraverseLayersFunction traverseLayers,
- const sp<GraphicBuffer>& buffer, bool forSystem,
- bool regionSampling, bool grayscale,
- ScreenCaptureResults& captureResults) {
+status_t SurfaceFlinger::renderScreenImplLocked(
+ const RenderArea& renderArea, TraverseLayersFunction traverseLayers,
+ const std::shared_ptr<renderengine::ExternalTexture>& buffer, bool forSystem,
+ bool regionSampling, bool grayscale, ScreenCaptureResults& captureResults) {
ATRACE_CALL();
traverseLayers([&](Layer* layer) {
@@ -7317,7 +7285,7 @@ status_t SurfaceFlinger::renderScreenImplLocked(const RenderArea& renderArea,
captureResults.capturedSecureLayers || (layer->isVisible() && layer->isSecure());
});
- const bool useProtected = buffer->getUsage() & GRALLOC_USAGE_PROTECTED;
+ const bool useProtected = buffer->getBuffer()->getUsage() & GRALLOC_USAGE_PROTECTED;
// We allow the system server to take screenshots of secure layers for
// use in situations like the Screen-rotation animation and place
@@ -7327,7 +7295,7 @@ status_t SurfaceFlinger::renderScreenImplLocked(const RenderArea& renderArea,
return PERMISSION_DENIED;
}
- captureResults.buffer = buffer;
+ captureResults.buffer = buffer->getBuffer();
captureResults.capturedDataspace = renderArea.getReqDataSpace();
const auto reqWidth = renderArea.getReqWidth();
@@ -7421,11 +7389,9 @@ status_t SurfaceFlinger::renderScreenImplLocked(const RenderArea& renderArea,
base::unique_fd drawFence;
getRenderEngine().useProtectedContext(useProtected);
- // TODO(b/180767535): Remove this once we optimize buffer lifecycle for RenderEngine
- const bool useFramebufferCache = getRenderEngine().getRenderEngineType() ==
- renderengine::RenderEngine::RenderEngineType::SKIA_GL_THREADED;
+ const constexpr bool kUseFramebufferCache = false;
getRenderEngine().drawLayers(clientCompositionDisplay, clientCompositionLayerPointers, buffer,
- useFramebufferCache, std::move(bufferFence), &drawFence);
+ kUseFramebufferCache, std::move(bufferFence), &drawFence);
if (drawFence >= 0) {
sp<Fence> releaseFence = new Fence(dup(drawFence));
@@ -7493,6 +7459,11 @@ status_t SurfaceFlinger::setDesiredDisplayModeSpecsInternal(
"Can only set override policy on the primary display");
LOG_ALWAYS_FATAL_IF(!policy && !overridePolicy, "Can only clear the override policy");
+ if (mDebugDisplayModeSetByBackdoor) {
+ // ignore this request as mode is overridden by backdoor
+ return NO_ERROR;
+ }
+
if (!display->isPrimary()) {
if (!isInternalDisplay(display)) {
return NO_ERROR;
@@ -7529,11 +7500,6 @@ status_t SurfaceFlinger::setDesiredDisplayModeSpecsInternal(
return NO_ERROR;
}
- if (mDebugDisplayModeSetByBackdoor) {
- // ignore this request as mode is overridden by backdoor
- return NO_ERROR;
- }
-
status_t setPolicyResult = overridePolicy
? mRefreshRateConfigs->setOverridePolicy(policy)
: mRefreshRateConfigs->setDisplayManagerPolicy(*policy);
@@ -7725,10 +7691,6 @@ void SurfaceFlinger::removeFromOffscreenLayers(Layer* layer) {
mOffscreenLayers.erase(layer);
}
-void SurfaceFlinger::bufferErased(const client_cache_t& clientCacheId) {
- getRenderEngine().unbindExternalTextureBuffer(clientCacheId.id);
-}
-
status_t SurfaceFlinger::setGlobalShadowSettings(const half4& ambientColor, const half4& spotColor,
float lightPosY, float lightPosZ,
float lightRadius) {
@@ -7940,6 +7902,88 @@ void SurfaceFlinger::TransactionState::traverseStatesWithBuffers(
}
}
+void SurfaceFlinger::setLayerCreatedState(const sp<IBinder>& handle, const wp<Layer>& layer,
+ const wp<IBinder>& parent, const wp<Layer> parentLayer,
+ const wp<IBinder>& producer) {
+ Mutex::Autolock lock(mCreatedLayersLock);
+ mCreatedLayers[handle->localBinder()] =
+ std::make_unique<LayerCreatedState>(layer, parent, parentLayer, producer);
+}
+
+auto SurfaceFlinger::getLayerCreatedState(const sp<IBinder>& handle) {
+ Mutex::Autolock lock(mCreatedLayersLock);
+ BBinder* b = nullptr;
+ if (handle) {
+ b = handle->localBinder();
+ }
+
+ if (b == nullptr) {
+ return std::unique_ptr<LayerCreatedState>(nullptr);
+ }
+
+ auto it = mCreatedLayers.find(b);
+ if (it == mCreatedLayers.end()) {
+ ALOGE("Can't find layer from handle %p", handle.get());
+ return std::unique_ptr<LayerCreatedState>(nullptr);
+ }
+
+ auto state = std::move(it->second);
+ mCreatedLayers.erase(it);
+ return state;
+}
+
+sp<Layer> SurfaceFlinger::handleLayerCreatedLocked(const sp<IBinder>& handle, bool privileged) {
+ const auto& state = getLayerCreatedState(handle);
+ if (!state) {
+ return nullptr;
+ }
+
+ sp<Layer> layer = state->layer.promote();
+ if (!layer) {
+ ALOGE("Invalid layer %p", state->layer.unsafe_get());
+ return nullptr;
+ }
+
+ sp<Layer> parent;
+ bool allowAddRoot = privileged;
+ if (state->initialParent != nullptr) {
+ parent = fromHandleLocked(state->initialParent.promote()).promote();
+ if (parent == nullptr) {
+ ALOGE("Invalid parent %p", state->initialParent.unsafe_get());
+ allowAddRoot = false;
+ }
+ } else if (state->initialParentLayer != nullptr) {
+ parent = state->initialParentLayer.promote();
+ allowAddRoot = false;
+ }
+
+ if (parent == nullptr && allowAddRoot) {
+ mCurrentState.layersSortedByZ.add(layer);
+ } else if (parent == nullptr) {
+ layer->onRemovedFromCurrentState();
+ } else if (parent->isRemovedFromCurrentState()) {
+ parent->addChild(layer);
+ layer->onRemovedFromCurrentState();
+ } else {
+ parent->addChild(layer);
+ }
+
+ if (state->initialProducer != nullptr) {
+ mGraphicBufferProducerList.insert(state->initialProducer);
+ LOG_ALWAYS_FATAL_IF(mGraphicBufferProducerList.size() > mMaxGraphicBufferProducerListSize,
+ "Suspected IGBP leak: %zu IGBPs (%zu max), %zu Layers",
+ mGraphicBufferProducerList.size(), mMaxGraphicBufferProducerListSize,
+ mNumLayers.load());
+ if (mGraphicBufferProducerList.size() > mGraphicBufferProducerListSizeLogThreshold) {
+ ALOGW("Suspected IGBP leak: %zu IGBPs (%zu max), %zu Layers",
+ mGraphicBufferProducerList.size(), mMaxGraphicBufferProducerListSize,
+ mNumLayers.load());
+ }
+ }
+
+ return layer;
+}
+
void SurfaceFlinger::setContentFps(uint32_t contentFps) {
if (mBootFinished && !mSetActiveModePending) {
if (mDisplayExtnIntf) {
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index ec5dfc4054..3e0fba0855 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -159,13 +159,7 @@ enum {
using DisplayColorSetting = compositionengine::OutputColorSetting;
-class SurfaceFlingerBE
-{
-public:
- SurfaceFlingerBE();
-
- const std::string mHwcServiceName; // "default" for real use, something else for testing.
-
+struct SurfaceFlingerBE {
FenceTimeline mGlCompositionDoneTimeline;
FenceTimeline mDisplayTimeline;
@@ -255,7 +249,6 @@ private:
class SurfaceFlinger : public BnSurfaceComposer,
public PriorityDumper,
- public ClientCache::ErasedRecipient,
private IBinder::DeathRecipient,
private HWC2::ComposerCallback,
private ISchedulerCallback {
@@ -405,9 +398,6 @@ public:
wp<Layer> fromHandle(const sp<IBinder>& handle);
wp<Layer> fromHandleLocked(const sp<IBinder>& handle) const REQUIRES(mStateLock);
- // Inherit from ClientCache::ErasedRecipient
- void bufferErased(const client_cache_t& clientCacheId) override;
-
// If set, disables reusing client composition buffers. This can be set by
// debug.sf.disable_client_composition_cache
bool mDisableClientCompositionCache = false;
@@ -723,6 +713,7 @@ private:
status_t getAnimationFrameStats(FrameStats* outStats) const override;
status_t overrideHdrTypes(const sp<IBinder>& displayToken,
const std::vector<ui::Hdr>& hdrTypes) override;
+ status_t onPullAtom(const int32_t atomId, std::string* pulledData, bool* success) override;
status_t enableVSyncInjections(bool enable) override;
status_t injectVSync(nsecs_t when) override;
status_t getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) override;
@@ -990,12 +981,14 @@ private:
status_t captureScreenCommon(RenderAreaFuture, TraverseLayersFunction, ui::Size bufferSize,
ui::PixelFormat, bool allowProtected, bool grayscale,
const sp<IScreenCaptureListener>&);
- status_t captureScreenCommon(RenderAreaFuture, TraverseLayersFunction, sp<GraphicBuffer>&,
+ status_t captureScreenCommon(RenderAreaFuture, TraverseLayersFunction,
+ const std::shared_ptr<renderengine::ExternalTexture>&,
bool regionSampling, bool grayscale,
const sp<IScreenCaptureListener>&);
status_t renderScreenImplLocked(const RenderArea&, TraverseLayersFunction,
- const sp<GraphicBuffer>&, bool forSystem, bool regionSampling,
- bool grayscale, ScreenCaptureResults&);
+ const std::shared_ptr<renderengine::ExternalTexture>&,
+ bool forSystem, bool regionSampling, bool grayscale,
+ ScreenCaptureResults&);
sp<DisplayDevice> getDisplayByIdOrLayerStack(uint64_t displayOrLayerStack) REQUIRES(mStateLock);
sp<DisplayDevice> getDisplayById(DisplayId displayId) const REQUIRES(mStateLock);
@@ -1462,6 +1455,10 @@ private:
SurfaceFlingerBE mBE;
std::unique_ptr<compositionengine::CompositionEngine> mCompositionEngine;
+ const std::string mHwcServiceName;
+
+ bool hasMockHwc() const { return mHwcServiceName == "mock"; }
+
/*
* Scheduler
*/
@@ -1534,6 +1531,35 @@ private:
std::unordered_map<DisplayId, sp<HdrLayerInfoReporter>> mHdrLayerInfoListeners
GUARDED_BY(mStateLock);
+ mutable Mutex mCreatedLayersLock;
+ struct LayerCreatedState {
+ LayerCreatedState(const wp<Layer>& layer, const wp<IBinder>& parent,
+ const wp<Layer> parentLayer, const wp<IBinder>& producer)
+ : layer(layer),
+ initialParent(parent),
+ initialParentLayer(parentLayer),
+ initialProducer(producer) {}
+ 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<IBinder> initialParent;
+ wp<Layer> initialParentLayer;
+ // Indicates the initial graphic buffer producer of the created layer, only used for
+ // creating layer in SurfaceFlinger.
+ wp<IBinder> initialProducer;
+ };
+
+ // A temporay pool that store the created layers and will be added to current state in main
+ // thread.
+ std::unordered_map<BBinder*, std::unique_ptr<LayerCreatedState>> mCreatedLayers;
+ void setLayerCreatedState(const sp<IBinder>& handle, const wp<Layer>& layer,
+ const wp<IBinder>& parent, const wp<Layer> parentLayer,
+ const wp<IBinder>& producer);
+ auto getLayerCreatedState(const sp<IBinder>& handle);
+ sp<Layer> handleLayerCreatedLocked(const sp<IBinder>& handle, bool privileged)
+ REQUIRES(mStateLock);
+
+ std::atomic<ui::Transform::RotationFlags> mDefaultDisplayTransformHint;
SmomoWrapper mSmoMo;
LayerExtWrapper mLayerExt;
diff --git a/services/surfaceflinger/SurfaceInterceptor.cpp b/services/surfaceflinger/SurfaceInterceptor.cpp
index b49562a0a5..113f463c39 100644
--- a/services/surfaceflinger/SurfaceInterceptor.cpp
+++ b/services/surfaceflinger/SurfaceInterceptor.cpp
@@ -141,11 +141,6 @@ void SurfaceInterceptor::addInitialSurfaceStateLocked(Increment* increment,
addCornerRadiusLocked(transaction, layerId, layer->mCurrentState.cornerRadius);
addBackgroundBlurRadiusLocked(transaction, layerId, layer->mCurrentState.backgroundBlurRadius);
addBlurRegionsLocked(transaction, layerId, layer->mCurrentState.blurRegions);
- if (layer->mCurrentState.barrierLayer_legacy != nullptr) {
- addDeferTransactionLocked(transaction, layerId,
- layer->mCurrentState.barrierLayer_legacy.promote(),
- layer->mCurrentState.barrierFrameNumber);
- }
addFlagsLocked(transaction, layerId, layer->mCurrentState.flags,
layer_state_t::eLayerHidden | layer_state_t::eLayerOpaque |
layer_state_t::eLayerSecure);
@@ -380,20 +375,6 @@ void SurfaceInterceptor::addBlurRegionsLocked(Transaction* transaction, int32_t
}
}
-void SurfaceInterceptor::addDeferTransactionLocked(Transaction* transaction, int32_t layerId,
- const sp<const Layer>& layer, uint64_t frameNumber)
-{
- SurfaceChange* change(createSurfaceChangeLocked(transaction, layerId));
- if (layer == nullptr) {
- ALOGE("An existing layer could not be retrieved with the handle"
- " for the deferred transaction");
- return;
- }
- DeferredTransactionChange* deferTransaction(change->mutable_deferred_transaction());
- deferTransaction->set_layer_id(getLayerId(layer));
- deferTransaction->set_frame_number(frameNumber);
-}
-
void SurfaceInterceptor::addReparentLocked(Transaction* transaction, int32_t layerId,
int32_t parentId) {
SurfaceChange* change(createSurfaceChangeLocked(transaction, layerId));
@@ -464,15 +445,6 @@ void SurfaceInterceptor::addSurfaceChangesLocked(Transaction* transaction,
if (state.what & layer_state_t::eBlurRegionsChanged) {
addBlurRegionsLocked(transaction, layerId, state.blurRegions);
}
- if (state.what & layer_state_t::eDeferTransaction_legacy) {
- sp<Layer> otherLayer = nullptr;
- if (state.barrierSurfaceControl_legacy != nullptr) {
- otherLayer = static_cast<Layer::Handle*>(
- state.barrierSurfaceControl_legacy->getHandle().get())
- ->owner.promote();
- }
- addDeferTransactionLocked(transaction, layerId, otherLayer, state.barrierFrameNumber);
- }
if (state.what & layer_state_t::eReparent) {
auto parentHandle = (state.parentSurfaceControlForChild)
? state.parentSurfaceControlForChild->getHandle()
diff --git a/services/surfaceflinger/SurfaceInterceptor.h b/services/surfaceflinger/SurfaceInterceptor.h
index d2cbf40426..30aca8340e 100644
--- a/services/surfaceflinger/SurfaceInterceptor.h
+++ b/services/surfaceflinger/SurfaceInterceptor.h
@@ -167,8 +167,6 @@ private:
int32_t backgroundBlurRadius);
void addBlurRegionsLocked(Transaction* transaction, int32_t layerId,
const std::vector<BlurRegion>& effectRegions);
- void addDeferTransactionLocked(Transaction* transaction, int32_t layerId,
- const sp<const Layer>& layer, uint64_t frameNumber);
void addSurfaceChangesLocked(Transaction* transaction, const layer_state_t& state);
void addTransactionLocked(Increment* increment, const Vector<ComposerState>& stateUpdates,
const DefaultKeyedVector<wp<IBinder>, DisplayDeviceState>& displays,
diff --git a/services/surfaceflinger/TimeStats/Android.bp b/services/surfaceflinger/TimeStats/Android.bp
index 62fddb4f47..bcc3e4e52a 100644
--- a/services/surfaceflinger/TimeStats/Android.bp
+++ b/services/surfaceflinger/TimeStats/Android.bp
@@ -18,20 +18,13 @@ cc_library {
"libcutils",
"liblog",
"libprotobuf-cpp-lite",
- "libprotoutil",
- "libstatslog",
- "libstatspull",
- "libstatssocket",
+ "libtimestats_atoms_proto",
"libtimestats_proto",
"libui",
"libutils",
],
export_include_dirs: ["."],
export_shared_lib_headers: [
- "libprotoutil",
- "libstatslog",
- "libstatspull",
- "libstatssocket",
"libtimestats_proto",
],
cppflags: [
diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp
index 2094972ed0..3d82afa43a 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.cpp
+++ b/services/surfaceflinger/TimeStats/TimeStats.cpp
@@ -19,11 +19,9 @@
#define LOG_TAG "TimeStats"
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-#include "TimeStats.h"
-
#include <android-base/stringprintf.h>
-#include <android/util/ProtoOutputStream.h>
#include <log/log.h>
+#include <timestatsatomsproto/TimeStatsAtomsProtoHeader.h>
#include <utils/String8.h>
#include <utils/Timers.h>
#include <utils/Trace.h>
@@ -31,147 +29,102 @@
#include <algorithm>
#include <chrono>
+#include "TimeStats.h"
#include "timestatsproto/TimeStatsHelper.h"
namespace android {
namespace impl {
-AStatsManager_PullAtomCallbackReturn TimeStats::pullAtomCallback(int32_t atom_tag,
- AStatsEventList* data,
- void* cookie) {
- impl::TimeStats* timeStats = reinterpret_cast<impl::TimeStats*>(cookie);
- AStatsManager_PullAtomCallbackReturn result = AStatsManager_PULL_SKIP;
- if (atom_tag == android::util::SURFACEFLINGER_STATS_GLOBAL_INFO) {
- result = timeStats->populateGlobalAtom(data);
- } else if (atom_tag == android::util::SURFACEFLINGER_STATS_LAYER_INFO) {
- result = timeStats->populateLayerAtom(data);
- }
-
- // Enable timestats now. The first full pull for a given build is expected to
- // have empty or very little stats, as stats are first enabled after the
- // first pull is completed for either the global or layer stats.
- timeStats->enable();
- return result;
-}
-
namespace {
-// Histograms align with the order of fields in SurfaceflingerStatsLayerInfo.
-const std::array<std::string, 6> kHistogramNames = {
- "present2present", "post2present", "acquire2present",
- "latch2present", "desired2present", "post2acquire",
-};
-
-std::string histogramToProtoByteString(const std::unordered_map<int32_t, int32_t>& histogram,
- size_t maxPulledHistogramBuckets) {
+
+FrameTimingHistogram histogramToProto(const std::unordered_map<int32_t, int32_t>& histogram,
+ size_t maxPulledHistogramBuckets) {
auto buckets = std::vector<std::pair<int32_t, int32_t>>(histogram.begin(), histogram.end());
std::sort(buckets.begin(), buckets.end(),
[](std::pair<int32_t, int32_t>& left, std::pair<int32_t, int32_t>& right) {
return left.second > right.second;
});
- util::ProtoOutputStream proto;
+ FrameTimingHistogram histogramProto;
int histogramSize = 0;
for (const auto& bucket : buckets) {
if (++histogramSize > maxPulledHistogramBuckets) {
break;
}
- proto.write(android::util::FIELD_TYPE_INT32 | android::util::FIELD_COUNT_REPEATED |
- 1 /* field id */,
- (int32_t)bucket.first);
- proto.write(android::util::FIELD_TYPE_INT64 | android::util::FIELD_COUNT_REPEATED |
- 2 /* field id */,
- (int64_t)bucket.second);
+ histogramProto.add_time_millis_buckets((int32_t)bucket.first);
+ histogramProto.add_frame_counts((int64_t)bucket.second);
}
-
- std::string byteString;
- proto.serializeToString(&byteString);
- return byteString;
+ return histogramProto;
}
-std::string frameRateVoteToProtoByteString(
- float refreshRate,
- TimeStats::SetFrameRateVote::FrameRateCompatibility frameRateCompatibility,
- TimeStats::SetFrameRateVote::Seamlessness seamlessness) {
- util::ProtoOutputStream proto;
- proto.write(android::util::FIELD_TYPE_FLOAT | 1 /* field id */, refreshRate);
- proto.write(android::util::FIELD_TYPE_ENUM | 2 /* field id */,
- static_cast<int>(frameRateCompatibility));
- proto.write(android::util::FIELD_TYPE_ENUM | 3 /* field id */, static_cast<int>(seamlessness));
-
- std::string byteString;
- proto.serializeToString(&byteString);
- return byteString;
+SurfaceflingerStatsLayerInfo_SetFrameRateVote frameRateVoteToProto(
+ const TimeStats::SetFrameRateVote& setFrameRateVote) {
+ using FrameRateCompatibilityEnum =
+ SurfaceflingerStatsLayerInfo::SetFrameRateVote::FrameRateCompatibility;
+ using SeamlessnessEnum = SurfaceflingerStatsLayerInfo::SetFrameRateVote::Seamlessness;
+
+ SurfaceflingerStatsLayerInfo_SetFrameRateVote proto;
+ proto.set_frame_rate(setFrameRateVote.frameRate);
+ proto.set_frame_rate_compatibility(
+ static_cast<FrameRateCompatibilityEnum>(setFrameRateVote.frameRateCompatibility));
+ proto.set_seamlessness(static_cast<SeamlessnessEnum>(setFrameRateVote.seamlessness));
+ return proto;
}
} // namespace
-AStatsManager_PullAtomCallbackReturn TimeStats::populateGlobalAtom(AStatsEventList* data) {
+bool TimeStats::populateGlobalAtom(std::string* pulledData) {
std::lock_guard<std::mutex> lock(mMutex);
if (mTimeStats.statsStartLegacy == 0) {
- return AStatsManager_PULL_SKIP;
+ return false;
}
flushPowerTimeLocked();
-
+ SurfaceflingerStatsGlobalInfoWrapper atomList;
for (const auto& globalSlice : mTimeStats.stats) {
- AStatsEvent* event = mStatsDelegate->addStatsEventToPullData(data);
- mStatsDelegate->statsEventSetAtomId(event, android::util::SURFACEFLINGER_STATS_GLOBAL_INFO);
- mStatsDelegate->statsEventWriteInt64(event, mTimeStats.totalFramesLegacy);
- mStatsDelegate->statsEventWriteInt64(event, mTimeStats.missedFramesLegacy);
- mStatsDelegate->statsEventWriteInt64(event, mTimeStats.clientCompositionFramesLegacy);
- mStatsDelegate->statsEventWriteInt64(event, mTimeStats.displayOnTimeLegacy);
- mStatsDelegate->statsEventWriteInt64(event, mTimeStats.presentToPresentLegacy.totalTime());
- mStatsDelegate->statsEventWriteInt32(event, mTimeStats.displayEventConnectionsCountLegacy);
- std::string frameDurationBytes =
- histogramToProtoByteString(mTimeStats.frameDurationLegacy.hist,
- mMaxPulledHistogramBuckets);
- mStatsDelegate->statsEventWriteByteArray(event, (const uint8_t*)frameDurationBytes.c_str(),
- frameDurationBytes.size());
- std::string renderEngineTimingBytes =
- histogramToProtoByteString(mTimeStats.renderEngineTimingLegacy.hist,
- mMaxPulledHistogramBuckets);
- mStatsDelegate->statsEventWriteByteArray(event,
- (const uint8_t*)renderEngineTimingBytes.c_str(),
- renderEngineTimingBytes.size());
-
- mStatsDelegate->statsEventWriteInt32(event, globalSlice.second.jankPayload.totalFrames);
- mStatsDelegate->statsEventWriteInt32(event,
- globalSlice.second.jankPayload.totalJankyFrames);
- mStatsDelegate->statsEventWriteInt32(event, globalSlice.second.jankPayload.totalSFLongCpu);
- mStatsDelegate->statsEventWriteInt32(event, globalSlice.second.jankPayload.totalSFLongGpu);
- mStatsDelegate->statsEventWriteInt32(event,
- globalSlice.second.jankPayload.totalSFUnattributed);
- mStatsDelegate->statsEventWriteInt32(event,
- globalSlice.second.jankPayload.totalAppUnattributed);
- mStatsDelegate->statsEventWriteInt32(event,
- globalSlice.second.jankPayload.totalSFScheduling);
- mStatsDelegate->statsEventWriteInt32(event,
- globalSlice.second.jankPayload.totalSFPredictionError);
- mStatsDelegate->statsEventWriteInt32(event,
- globalSlice.second.jankPayload.totalAppBufferStuffing);
- mStatsDelegate->statsEventWriteInt32(event, globalSlice.first.displayRefreshRateBucket);
- std::string sfDeadlineMissedBytes =
- histogramToProtoByteString(globalSlice.second.displayDeadlineDeltas.hist,
- mMaxPulledHistogramBuckets);
- mStatsDelegate->statsEventWriteByteArray(event,
- (const uint8_t*)sfDeadlineMissedBytes.c_str(),
- sfDeadlineMissedBytes.size());
- std::string sfPredictionErrorBytes =
- histogramToProtoByteString(globalSlice.second.displayPresentDeltas.hist,
- mMaxPulledHistogramBuckets);
- mStatsDelegate->statsEventWriteByteArray(event,
- (const uint8_t*)sfPredictionErrorBytes.c_str(),
- sfPredictionErrorBytes.size());
- mStatsDelegate->statsEventWriteInt32(event, globalSlice.first.renderRateBucket);
- mStatsDelegate->statsEventBuild(event);
+ SurfaceflingerStatsGlobalInfo* atom = atomList.add_atom();
+ atom->set_total_frames(mTimeStats.totalFramesLegacy);
+ atom->set_missed_frames(mTimeStats.missedFramesLegacy);
+ atom->set_client_composition_frames(mTimeStats.clientCompositionFramesLegacy);
+ atom->set_display_on_millis(mTimeStats.displayOnTimeLegacy);
+ atom->set_animation_millis(mTimeStats.presentToPresentLegacy.totalTime());
+ atom->set_event_connection_count(mTimeStats.displayEventConnectionsCountLegacy);
+ *atom->mutable_frame_duration() =
+ histogramToProto(mTimeStats.frameDurationLegacy.hist, mMaxPulledHistogramBuckets);
+ *atom->mutable_render_engine_timing() =
+ histogramToProto(mTimeStats.renderEngineTimingLegacy.hist,
+ mMaxPulledHistogramBuckets);
+ atom->set_total_timeline_frames(globalSlice.second.jankPayload.totalFrames);
+ atom->set_total_janky_frames(globalSlice.second.jankPayload.totalJankyFrames);
+ atom->set_total_janky_frames_with_long_cpu(globalSlice.second.jankPayload.totalSFLongCpu);
+ atom->set_total_janky_frames_with_long_gpu(globalSlice.second.jankPayload.totalSFLongGpu);
+ atom->set_total_janky_frames_sf_unattributed(
+ globalSlice.second.jankPayload.totalSFUnattributed);
+ atom->set_total_janky_frames_app_unattributed(
+ globalSlice.second.jankPayload.totalAppUnattributed);
+ atom->set_total_janky_frames_sf_scheduling(
+ globalSlice.second.jankPayload.totalSFScheduling);
+ atom->set_total_jank_frames_sf_prediction_error(
+ globalSlice.second.jankPayload.totalSFPredictionError);
+ atom->set_total_jank_frames_app_buffer_stuffing(
+ globalSlice.second.jankPayload.totalAppBufferStuffing);
+ atom->set_display_refresh_rate_bucket(globalSlice.first.displayRefreshRateBucket);
+ *atom->mutable_sf_deadline_misses() =
+ histogramToProto(globalSlice.second.displayDeadlineDeltas.hist,
+ mMaxPulledHistogramBuckets);
+ *atom->mutable_sf_prediction_errors() =
+ histogramToProto(globalSlice.second.displayPresentDeltas.hist,
+ mMaxPulledHistogramBuckets);
+ atom->set_render_rate_bucket(globalSlice.first.renderRateBucket);
}
+ // Always clear data.
clearGlobalLocked();
- return AStatsManager_PULL_SUCCESS;
+ return atomList.SerializeToString(pulledData);
}
-AStatsManager_PullAtomCallbackReturn TimeStats::populateLayerAtom(AStatsEventList* data) {
+bool TimeStats::populateLayerAtom(std::string* pulledData) {
std::lock_guard<std::mutex> lock(mMutex);
std::vector<TimeStatsHelper::TimeStatsLayer*> dumpStats;
@@ -198,69 +151,73 @@ AStatsManager_PullAtomCallbackReturn TimeStats::populateLayerAtom(AStatsEventLis
dumpStats.resize(mMaxPulledLayers);
}
+ SurfaceflingerStatsLayerInfoWrapper atomList;
for (auto& layer : dumpStats) {
- AStatsEvent* event = mStatsDelegate->addStatsEventToPullData(data);
- mStatsDelegate->statsEventSetAtomId(event, android::util::SURFACEFLINGER_STATS_LAYER_INFO);
- mStatsDelegate->statsEventWriteString8(event, layer->layerName.c_str());
- mStatsDelegate->statsEventWriteInt64(event, layer->totalFrames);
- mStatsDelegate->statsEventWriteInt64(event, layer->droppedFrames);
-
- for (const auto& name : kHistogramNames) {
- const auto& histogram = layer->deltas.find(name);
- if (histogram == layer->deltas.cend()) {
- mStatsDelegate->statsEventWriteByteArray(event, nullptr, 0);
- } else {
- std::string bytes = histogramToProtoByteString(histogram->second.hist,
- mMaxPulledHistogramBuckets);
- mStatsDelegate->statsEventWriteByteArray(event, (const uint8_t*)bytes.c_str(),
- bytes.size());
- }
+ SurfaceflingerStatsLayerInfo* atom = atomList.add_atom();
+ atom->set_layer_name(layer->layerName);
+ atom->set_total_frames(layer->totalFrames);
+ atom->set_dropped_frames(layer->droppedFrames);
+ const auto& present2PresentHist = layer->deltas.find("present2present");
+ if (present2PresentHist != layer->deltas.cend()) {
+ *atom->mutable_present_to_present() =
+ histogramToProto(present2PresentHist->second.hist, mMaxPulledHistogramBuckets);
+ }
+ const auto& post2presentHist = layer->deltas.find("post2present");
+ if (post2presentHist != layer->deltas.cend()) {
+ *atom->mutable_post_to_present() =
+ histogramToProto(post2presentHist->second.hist, mMaxPulledHistogramBuckets);
+ }
+ const auto& acquire2presentHist = layer->deltas.find("acquire2present");
+ if (acquire2presentHist != layer->deltas.cend()) {
+ *atom->mutable_acquire_to_present() =
+ histogramToProto(acquire2presentHist->second.hist, mMaxPulledHistogramBuckets);
+ }
+ const auto& latch2presentHist = layer->deltas.find("latch2present");
+ if (latch2presentHist != layer->deltas.cend()) {
+ *atom->mutable_latch_to_present() =
+ histogramToProto(latch2presentHist->second.hist, mMaxPulledHistogramBuckets);
+ }
+ const auto& desired2presentHist = layer->deltas.find("desired2present");
+ if (desired2presentHist != layer->deltas.cend()) {
+ *atom->mutable_desired_to_present() =
+ histogramToProto(desired2presentHist->second.hist, mMaxPulledHistogramBuckets);
+ }
+ const auto& post2acquireHist = layer->deltas.find("post2acquire");
+ if (post2acquireHist != layer->deltas.cend()) {
+ *atom->mutable_post_to_acquire() =
+ histogramToProto(post2acquireHist->second.hist, mMaxPulledHistogramBuckets);
}
- mStatsDelegate->statsEventWriteInt64(event, layer->lateAcquireFrames);
- mStatsDelegate->statsEventWriteInt64(event, layer->badDesiredPresentFrames);
- mStatsDelegate->statsEventWriteInt32(event, layer->uid);
- mStatsDelegate->statsEventWriteInt32(event, layer->jankPayload.totalFrames);
- mStatsDelegate->statsEventWriteInt32(event, layer->jankPayload.totalJankyFrames);
- mStatsDelegate->statsEventWriteInt32(event, layer->jankPayload.totalSFLongCpu);
- mStatsDelegate->statsEventWriteInt32(event, layer->jankPayload.totalSFLongGpu);
- mStatsDelegate->statsEventWriteInt32(event, layer->jankPayload.totalSFUnattributed);
- mStatsDelegate->statsEventWriteInt32(event, layer->jankPayload.totalAppUnattributed);
- mStatsDelegate->statsEventWriteInt32(event, layer->jankPayload.totalSFScheduling);
- mStatsDelegate->statsEventWriteInt32(event, layer->jankPayload.totalSFPredictionError);
- mStatsDelegate->statsEventWriteInt32(event, layer->jankPayload.totalAppBufferStuffing);
- mStatsDelegate->statsEventWriteInt32(
- event, layer->displayRefreshRateBucket); // display_refresh_rate_bucket
- mStatsDelegate->statsEventWriteInt32(event, layer->renderRateBucket); // render_rate_bucket
- std::string frameRateVoteBytes =
- frameRateVoteToProtoByteString(layer->setFrameRateVote.frameRate,
- layer->setFrameRateVote.frameRateCompatibility,
- layer->setFrameRateVote.seamlessness);
- mStatsDelegate->statsEventWriteByteArray(event, (const uint8_t*)frameRateVoteBytes.c_str(),
- frameRateVoteBytes.size()); // set_frame_rate_vote
- std::string appDeadlineMissedBytes =
- histogramToProtoByteString(layer->deltas["appDeadlineDeltas"].hist,
- mMaxPulledHistogramBuckets);
- mStatsDelegate->statsEventWriteByteArray(event,
- (const uint8_t*)appDeadlineMissedBytes.c_str(),
- appDeadlineMissedBytes.size());
-
- mStatsDelegate->statsEventBuild(event);
+ atom->set_late_acquire_frames(layer->lateAcquireFrames);
+ atom->set_bad_desired_present_frames(layer->badDesiredPresentFrames);
+ atom->set_uid(layer->uid);
+ atom->set_total_timeline_frames(layer->jankPayload.totalFrames);
+ atom->set_total_janky_frames(layer->jankPayload.totalJankyFrames);
+ atom->set_total_janky_frames_with_long_cpu(layer->jankPayload.totalSFLongCpu);
+ atom->set_total_janky_frames_with_long_gpu(layer->jankPayload.totalSFLongGpu);
+ atom->set_total_janky_frames_sf_unattributed(layer->jankPayload.totalSFUnattributed);
+ atom->set_total_janky_frames_app_unattributed(layer->jankPayload.totalAppUnattributed);
+ atom->set_total_janky_frames_sf_scheduling(layer->jankPayload.totalSFScheduling);
+ atom->set_total_jank_frames_sf_prediction_error(layer->jankPayload.totalSFPredictionError);
+ atom->set_total_jank_frames_app_buffer_stuffing(layer->jankPayload.totalAppBufferStuffing);
+ atom->set_display_refresh_rate_bucket(layer->displayRefreshRateBucket);
+ atom->set_render_rate_bucket(layer->renderRateBucket);
+ *atom->mutable_set_frame_rate_vote() = frameRateVoteToProto(layer->setFrameRateVote);
+ *atom->mutable_app_deadline_misses() =
+ histogramToProto(layer->deltas["appDeadlineDeltas"].hist,
+ mMaxPulledHistogramBuckets);
}
+
+ // Always clear data.
clearLayersLocked();
- return AStatsManager_PULL_SUCCESS;
+ return atomList.SerializeToString(pulledData);
}
-TimeStats::TimeStats() : TimeStats(nullptr, std::nullopt, std::nullopt) {}
+TimeStats::TimeStats() : TimeStats(std::nullopt, std::nullopt) {}
-TimeStats::TimeStats(std::unique_ptr<StatsEventDelegate> statsDelegate,
- std::optional<size_t> maxPulledLayers,
+TimeStats::TimeStats(std::optional<size_t> maxPulledLayers,
std::optional<size_t> maxPulledHistogramBuckets) {
- if (statsDelegate != nullptr) {
- mStatsDelegate = std::move(statsDelegate);
- }
-
if (maxPulledLayers) {
mMaxPulledLayers = *maxPulledLayers;
}
@@ -270,18 +227,19 @@ TimeStats::TimeStats(std::unique_ptr<StatsEventDelegate> statsDelegate,
}
}
-TimeStats::~TimeStats() {
- std::lock_guard<std::mutex> lock(mMutex);
- mStatsDelegate->clearStatsPullAtomCallback(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO);
- mStatsDelegate->clearStatsPullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO);
-}
+bool TimeStats::onPullAtom(const int atomId, std::string* pulledData) {
+ bool success = false;
+ if (atomId == 10062) { // SURFACEFLINGER_STATS_GLOBAL_INFO
+ success = populateGlobalAtom(pulledData);
+ } else if (atomId == 10063) { // SURFACEFLINGER_STATS_LAYER_INFO
+ success = populateLayerAtom(pulledData);
+ }
-void TimeStats::onBootFinished() {
- std::lock_guard<std::mutex> lock(mMutex);
- mStatsDelegate->setStatsPullAtomCallback(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
- nullptr, TimeStats::pullAtomCallback, this);
- mStatsDelegate->setStatsPullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO,
- nullptr, TimeStats::pullAtomCallback, this);
+ // Enable timestats now. The first full pull for a given build is expected to
+ // have empty or very little stats, as stats are first enabled after the
+ // first pull is completed for either the global or layer stats.
+ enable();
+ return success;
}
void TimeStats::parseArgs(bool asProto, const Vector<String16>& args, std::string& result) {
@@ -787,7 +745,7 @@ void TimeStats::setPresentFence(int32_t layerId, uint64_t frameNumber,
static const constexpr int32_t kValidJankyReason = JankType::DisplayHAL |
JankType::SurfaceFlingerCpuDeadlineMissed | JankType::SurfaceFlingerGpuDeadlineMissed |
JankType::AppDeadlineMissed | JankType::PredictionError |
- JankType::SurfaceFlingerScheduling | JankType::BufferStuffing;
+ JankType::SurfaceFlingerScheduling;
template <class T>
static void updateJankPayload(T& t, int32_t reasons) {
@@ -813,9 +771,11 @@ static void updateJankPayload(T& t, int32_t reasons) {
if ((reasons & JankType::SurfaceFlingerScheduling) != 0) {
t.jankPayload.totalSFScheduling++;
}
- if ((reasons & JankType::BufferStuffing) != 0) {
- t.jankPayload.totalAppBufferStuffing++;
- }
+ }
+
+ // We want to track BufferStuffing separately as it can provide info on latency issues
+ if (reasons & JankType::BufferStuffing) {
+ t.jankPayload.totalAppBufferStuffing++;
}
}
diff --git a/services/surfaceflinger/TimeStats/TimeStats.h b/services/surfaceflinger/TimeStats/TimeStats.h
index a87b7cb4a6..5b0f5bd13d 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.h
+++ b/services/surfaceflinger/TimeStats/TimeStats.h
@@ -29,9 +29,6 @@
#include <../Fps.h>
#include <gui/JankInfo.h>
-#include <stats_event.h>
-#include <stats_pull_atom_callback.h>
-#include <statslog.h>
#include <timestatsproto/TimeStatsHelper.h>
#include <timestatsproto/TimeStatsProtoHeader.h>
#include <ui/FenceTime.h>
@@ -54,9 +51,8 @@ public:
virtual ~TimeStats() = default;
- // Called once boot has been finished to perform additional capabilities,
- // e.g. registration to statsd.
- virtual void onBootFinished() = 0;
+ // Process a pull request from statsd.
+ virtual bool onPullAtom(const int atomId, std::string* pulledData);
virtual void parseArgs(bool asProto, const Vector<String16>& args, std::string& result) = 0;
virtual bool isEnabled() = 0;
@@ -232,58 +228,11 @@ class TimeStats : public android::TimeStats {
public:
TimeStats();
-
- // Delegate to the statsd service and associated APIs.
- // Production code may use this class directly, whereas unit test may define
- // a subclass for ease of testing.
- class StatsEventDelegate {
- public:
- virtual ~StatsEventDelegate() = default;
- virtual AStatsEvent* addStatsEventToPullData(AStatsEventList* data) {
- return AStatsEventList_addStatsEvent(data);
- }
- virtual void setStatsPullAtomCallback(int32_t atom_tag,
- AStatsManager_PullAtomMetadata* metadata,
- AStatsManager_PullAtomCallback callback,
- void* cookie) {
- return AStatsManager_setPullAtomCallback(atom_tag, metadata, callback, cookie);
- }
-
- virtual void clearStatsPullAtomCallback(int32_t atom_tag) {
- return AStatsManager_clearPullAtomCallback(atom_tag);
- }
-
- virtual void statsEventSetAtomId(AStatsEvent* event, uint32_t atom_id) {
- return AStatsEvent_setAtomId(event, atom_id);
- }
-
- virtual void statsEventWriteInt32(AStatsEvent* event, int32_t field) {
- return AStatsEvent_writeInt32(event, field);
- }
-
- virtual void statsEventWriteInt64(AStatsEvent* event, int64_t field) {
- return AStatsEvent_writeInt64(event, field);
- }
-
- virtual void statsEventWriteString8(AStatsEvent* event, const char* field) {
- return AStatsEvent_writeString(event, field);
- }
-
- virtual void statsEventWriteByteArray(AStatsEvent* event, const uint8_t* buf,
- size_t numBytes) {
- return AStatsEvent_writeByteArray(event, buf, numBytes);
- }
-
- virtual void statsEventBuild(AStatsEvent* event) { return AStatsEvent_build(event); }
- };
// For testing only for injecting custom dependencies.
- TimeStats(std::unique_ptr<StatsEventDelegate> statsDelegate,
- std::optional<size_t> maxPulledLayers,
+ TimeStats(std::optional<size_t> maxPulledLayers,
std::optional<size_t> maxPulledHistogramBuckets);
- ~TimeStats() override;
-
- void onBootFinished() override;
+ bool onPullAtom(const int atomId, std::string* pulledData) override;
void parseArgs(bool asProto, const Vector<String16>& args, std::string& result) override;
bool isEnabled() override;
std::string miniDump() override;
@@ -332,11 +281,8 @@ public:
static const size_t MAX_NUM_TIME_RECORDS = 64;
private:
- static AStatsManager_PullAtomCallbackReturn pullAtomCallback(int32_t atom_tag,
- AStatsEventList* data,
- void* cookie);
- AStatsManager_PullAtomCallbackReturn populateGlobalAtom(AStatsEventList* data);
- AStatsManager_PullAtomCallbackReturn populateLayerAtom(AStatsEventList* data);
+ bool populateGlobalAtom(std::string* pulledData);
+ bool populateLayerAtom(std::string* pulledData);
bool recordReadyLocked(int32_t layerId, TimeRecord* timeRecord);
void flushAvailableRecordsToStatsLocked(int32_t layerId, Fps displayRefreshRate,
std::optional<Fps> renderRate,
@@ -366,7 +312,6 @@ private:
static const size_t RENDER_RATE_BUCKET_WIDTH = REFRESH_RATE_BUCKET_WIDTH;
static const size_t MAX_NUM_LAYER_STATS = 200;
static const size_t MAX_NUM_PULLED_LAYERS = MAX_NUM_LAYER_STATS;
- std::unique_ptr<StatsEventDelegate> mStatsDelegate = std::make_unique<StatsEventDelegate>();
size_t mMaxPulledLayers = MAX_NUM_PULLED_LAYERS;
size_t mMaxPulledHistogramBuckets = 6;
};
diff --git a/services/surfaceflinger/TimeStats/timestatsatomsproto/Android.bp b/services/surfaceflinger/TimeStats/timestatsatomsproto/Android.bp
new file mode 100644
index 0000000000..0cf086fe01
--- /dev/null
+++ b/services/surfaceflinger/TimeStats/timestatsatomsproto/Android.bp
@@ -0,0 +1,36 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
+cc_library {
+ name: "libtimestats_atoms_proto",
+ export_include_dirs: ["include"],
+
+ srcs: [
+ "timestats_atoms.proto",
+ ],
+
+ proto: {
+ type: "lite",
+ export_proto_headers: true,
+ },
+
+ cppflags: [
+ "-Werror",
+ "-Wno-c++98-compat-pedantic",
+ "-Wno-disabled-macro-expansion",
+ "-Wno-float-conversion",
+ "-Wno-float-equal",
+ "-Wno-format",
+ "-Wno-old-style-cast",
+ "-Wno-padded",
+ "-Wno-sign-conversion",
+ "-Wno-undef",
+ "-Wno-unused-parameter",
+ ],
+} \ No newline at end of file
diff --git a/services/surfaceflinger/TimeStats/timestatsatomsproto/include/timestatsatomsproto/TimeStatsAtomsProtoHeader.h b/services/surfaceflinger/TimeStats/timestatsatomsproto/include/timestatsatomsproto/TimeStatsAtomsProtoHeader.h
new file mode 100644
index 0000000000..d305cb403c
--- /dev/null
+++ b/services/surfaceflinger/TimeStats/timestatsatomsproto/include/timestatsatomsproto/TimeStatsAtomsProtoHeader.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2021 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 is used here to disable the warnings emitted from the protobuf
+// headers. By adding #pragma before including layer.pb.h, it suppresses
+// protobuf warnings, but allows the rest of the files to continuing using
+// the current flags.
+// This file should be included instead of directly including timestats_atoms.b.h
+#pragma GCC system_header
+#include <timestats_atoms.pb.h>
diff --git a/services/surfaceflinger/TimeStats/timestatsatomsproto/timestats_atoms.proto b/services/surfaceflinger/TimeStats/timestatsatomsproto/timestats_atoms.proto
new file mode 100644
index 0000000000..133a5419b5
--- /dev/null
+++ b/services/surfaceflinger/TimeStats/timestatsatomsproto/timestats_atoms.proto
@@ -0,0 +1,289 @@
+/*
+ * Copyright 2021 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.
+ */
+syntax = "proto2";
+option optimize_for = LITE_RUNTIME;
+package android.surfaceflinger;
+
+// This is a copy of surfaceflinger's atoms from frameworks/proto_logging/stats/atoms.proto.
+// Pulled atoms for surfaceflinger must be routed through system server since surfaceflinger is
+// in the bootstrap namespace. This copy is used to pass the atoms as protos to system server using
+// proto lite to serialize/deserialize the atoms.
+
+// These wrappers are so that we can pass a List<Atom> as a single byte string.
+// They are not in atoms.proto
+message SurfaceflingerStatsGlobalInfoWrapper {
+ repeated SurfaceflingerStatsGlobalInfo atom = 1;
+}
+
+message SurfaceflingerStatsLayerInfoWrapper {
+ repeated SurfaceflingerStatsLayerInfo atom = 1;
+}
+
+/**
+ * Global display pipeline metrics reported by SurfaceFlinger.
+ * Metrics exist beginning in Android 11.
+ * Pulled from:
+ * frameworks/native/services/surfaceflinger/TimeStats/TimeStats.cpp
+ */
+message SurfaceflingerStatsGlobalInfo {
+ // Aggregated refresh rate buckets that layers were presenting at. Buckets
+ // are defined in SurfaceFlinger and are tracked per device.
+ // Introduced in Android 12.
+ // This is intended to be used as a dimenstion in collecting per-refresh rate
+ // jank statistics.
+ optional int32 display_refresh_rate_bucket = 18;
+ // Aggregated render rate buckets that layers were overridden to run at.
+ // Buckets are defined in SurfaceFlinger and are tracked per device.
+ // Introduced in Android 12.
+ // This is intended to be used as a dimension in collecting per-render rate
+ // jank statistics.
+ optional int32 render_rate_bucket = 21;
+ // Total number of frames presented during the tracing period
+ // Note: This stat is not sliced by dimension. It will be duplicated for metrics
+ // using render_rate_bucket as a dimension.
+ optional int64 total_frames = 1;
+ // Total number of frames missed
+ // Note: This stat is not sliced by dimension. It will be duplicated for metrics
+ // using render_rate_bucket as a dimension.
+ optional int64 missed_frames = 2;
+ // Total number of frames that fell back to client composition
+ // Note: This stat is not sliced by dimension. It will be duplicated for metrics
+ // using render_rate_bucket as a dimension.
+ optional int64 client_composition_frames = 3;
+ // Total time the display was turned on
+ // Note: This stat is not sliced by dimension. It will be duplicated for metrics
+ // using render_rate_bucket as a dimension.
+ optional int64 display_on_millis = 4;
+ // Total time that was spent performing animations.
+ // This is derived from the present-to-present layer histogram.
+ // Note: This stat is not sliced by dimension. It will be duplicated for metrics
+ // using render_rate_bucket as a dimension.
+ optional int64 animation_millis = 5;
+ // Total number of event connections tracked by SurfaceFlinger at the time
+ // of this pull. If this number grows prohibitively large, then this can
+ // cause jank due to resource contention.
+ // Note: This stat is not sliced by dimension. It will be duplicated for metrics
+ // using render_rate_bucket as a dimension.
+ optional int32 event_connection_count = 6;
+ // Set of timings measured from when SurfaceFlinger began compositing a
+ // frame, until the frame was requested to be presented to the display. This
+ // measures SurfaceFlinger's total CPU walltime on the critical path per
+ // frame.
+ // Note: This stat is not sliced by dimension. It will be duplicated for metrics
+ // using render_rate_bucket as a dimension.
+ optional FrameTimingHistogram frame_duration = 7;
+ // Set of timings measured from when SurfaceFlinger first began using the
+ // GPU to composite a frame, until the GPU has finished compositing that
+ // frame. This measures the total additional time SurfaceFlinger needed to
+ // perform due to falling back into GPU composition.
+ // Note: This stat is not sliced by dimension. It will be duplicated for metrics
+ // using render_rate_bucket as a dimension.
+ optional FrameTimingHistogram render_engine_timing = 8;
+ // Number of frames where SF saw a frame, based on its frame timeline.
+ // Frame timelines may include transactions without updating buffer contents.
+ // Introduced in Android 12.
+ optional int32 total_timeline_frames = 9;
+ // Number of frames where SF saw a janky frame.
+ // Introduced in Android 12.
+ optional int32 total_janky_frames = 10;
+ // Number of janky frames where SF spent a long time on the CPU.
+ // Introduced in Android 12.
+ optional int32 total_janky_frames_with_long_cpu = 11;
+ // Number of janky frames where SF spent a long time on the GPU.
+ // Introduced in Android 12.
+ optional int32 total_janky_frames_with_long_gpu = 12;
+ // Number of janky frames where SF missed the frame deadline, but there
+ // was not an attributed reason (e.g., maybe HWC missed?)
+ // Introduced in Android 12.
+ optional int32 total_janky_frames_sf_unattributed = 13;
+ // Number of janky frames where the app missed the frame deadline, but
+ // there was not an attributed reason
+ // Introduced in Android 12.
+ optional int32 total_janky_frames_app_unattributed = 14;
+ // Number of janky frames that were caused because of scheduling errors in
+ // SF that resulted in early present (e.g., SF sending a buffer to the
+ // composition engine earlier than expected, resulting in a present that is
+ // one vsync early)
+ // Introduced in Android 12.
+ optional int32 total_janky_frames_sf_scheduling = 15;
+ // Number of frames that were classified as jank because of possible drift in
+ // vsync predictions.
+ // Introduced in Android 12.
+ optional int32 total_jank_frames_sf_prediction_error = 16;
+ // Number of janky frames where the app was in a buffer stuffed state (more
+ // than one buffer ready to be presented at the same vsync). Usually caused
+ // when the first frame is unusually long, the following frames enter into a
+ // stuffed state.
+ // Introduced in Android 12.
+ optional int32 total_jank_frames_app_buffer_stuffing = 17;
+ // Buckets of timings in ms by which SurfaceFlinger's deadline was missed
+ // while latching and presenting frames.
+ // Introduced in Android 12.
+ optional FrameTimingHistogram sf_deadline_misses = 19;
+ // Buckets of timings in ms by which the Vsync prediction drifted, when
+ // compared to the actual hardware vsync.
+ // Introduced in Android 12.
+ optional FrameTimingHistogram sf_prediction_errors = 20;
+
+ // Next ID: 22
+}
+
+/**
+ * Per-layer display pipeline metrics reported by SurfaceFlinger.
+ * Metrics exist beginning in Android 11.
+ * The number of layers uploaded may be restricted due to size limitations.
+ * Pulled from:
+ * frameworks/native/services/surfaceflinger/TimeStats/TimeStats.cpp
+ */
+message SurfaceflingerStatsLayerInfo {
+ // UID of the application who submitted this layer for presentation
+ // This is intended to be used as a dimension for surfacing rendering
+ // statistics to applications.
+ // Introduced in Android 12.
+ optional int32 uid = 12;
+ // Refresh rate bucket that the layer was presenting at. Buckets are
+ // defined in SurfaceFlinger and are tracked per device.
+ // Introduced in Android 12.
+ // This is intended to be used as a dimension in collecting per-refresh rate
+ // jank statistics
+ optional int32 display_refresh_rate_bucket = 22;
+ // Render rate bucket that the layer was submitting frames at. Buckets are
+ // defined in SurfaceFlinger and are tracked per device.
+ // Introduced in Android 12.
+ // This is intended to be used as a dimension in collecting per-render rate
+ // jank statistics.
+ optional int32 render_rate_bucket = 23;
+ // The layer for this set of metrics
+ // In many scenarios the package name is included in the layer name, e.g.,
+ // layers created by Window Manager. But this is not a guarantee - in the
+ // general case layer names are arbitrary debug names.
+ optional string layer_name = 1;
+ // Total number of frames presented
+ optional int64 total_frames = 2;
+ // Total number of dropped frames while latching a buffer for this layer.
+ optional int64 dropped_frames = 3;
+ // Set of timings measured between successive presentation timestamps.
+ optional FrameTimingHistogram present_to_present = 4;
+ // Set of timings measured from when an app queued a buffer for
+ // presentation, until the buffer was actually presented to the
+ // display.
+ optional FrameTimingHistogram post_to_present = 5;
+ // Set of timings measured from when a buffer is ready to be presented,
+ // until the buffer was actually presented to the display.
+ optional FrameTimingHistogram acquire_to_present = 6;
+ // Set of timings measured from when a buffer was latched by
+ // SurfaceFlinger, until the buffer was presented to the display
+ optional FrameTimingHistogram latch_to_present = 7;
+ // Set of timings measured from the desired presentation to the actual
+ // presentation time
+ optional FrameTimingHistogram desired_to_present = 8;
+ // Set of timings measured from when an app queued a buffer for
+ // presentation, until the buffer was ready to be presented.
+ optional FrameTimingHistogram post_to_acquire = 9;
+ // Frames missed latch because the acquire fence didn't fire
+ optional int64 late_acquire_frames = 10;
+ // Frames latched early because the desired present time was bad
+ optional int64 bad_desired_present_frames = 11;
+ // Number of frames where SF saw a frame, based on its frame timeline.
+ // Frame timelines may include transactions without updating buffer contents.
+ // Introduced in Android 12.
+ optional int32 total_timeline_frames = 13;
+ // Number of frames where SF saw a janky frame.
+ // Introduced in Android 12.
+ optional int32 total_janky_frames = 14;
+ // Number of janky frames where SF spent a long time on the CPU.
+ // Introduced in Android 12.
+ optional int32 total_janky_frames_with_long_cpu = 15;
+ // Number of janky frames where SF spent a long time on the GPU.
+ // Introduced in Android 12.
+ optional int32 total_janky_frames_with_long_gpu = 16;
+ // Number of janky frames where SF missed the frame deadline, but there
+ // was not an attributed reason (e.g., maybe HWC missed?)
+ // Introduced in Android 12.
+ optional int32 total_janky_frames_sf_unattributed = 17;
+ // Number of janky frames where the app missed the frame deadline, but
+ // there was not an attributed reason
+ // Introduced in Android 12.
+ optional int32 total_janky_frames_app_unattributed = 18;
+ // Number of janky frames that were caused because of scheduling errors in
+ // SF that resulted in early present (e.g., SF sending a buffer to the
+ // composition engine earlier than expected, resulting in a present that is
+ // one vsync early)
+ // Introduced in Android 12.
+ optional int32 total_janky_frames_sf_scheduling = 19;
+ // Number of frames that were classified as jank because of possible drift in
+ // vsync predictions.
+ // Introduced in Android 12.
+ optional int32 total_jank_frames_sf_prediction_error = 20;
+ // Number of janky frames where the app was in a buffer stuffed state (more
+ // than one buffer ready to be presented at the same vsync). Usually caused
+ // when the first frame is unusually long, the following frames enter into a
+ // stuffed state.
+ // Introduced in Android 12.
+ optional int32 total_jank_frames_app_buffer_stuffing = 21;
+
+ /**
+ * Encapsulates the FrameRateVote information sent by the application while
+ * calling setFrameRate.
+ * Metrics exist beginning in Android 12.
+ */
+ message SetFrameRateVote {
+ // The desired frame rate the application wishes to run on.
+ optional float frame_rate = 1;
+
+ enum FrameRateCompatibility {
+ FRAME_RATE_UNDEFINED = 0;
+ FRAME_RATE_DEFAULT = 1;
+ FRAME_RATE_EXACT_OR_MULTIPLE = 2;
+ }
+
+ // Specifies how to interpret the frame rate associated with the layer.
+ // Defined in Layer.h
+ optional FrameRateCompatibility frame_rate_compatibility = 2;
+
+ enum Seamlessness {
+ SEAMLESS_UNDEFINED = 0;
+ SEAMLESS_SHOULD_BE_SEAMLESS = 1;
+ SEAMLESS_NOT_REQUIRED = 2;
+ }
+ // Indicates whether seamless refresh rate switch is required or not.
+ optional Seamlessness seamlessness = 3;
+ }
+
+ // The last frame rate vote set by the application.
+ // Introduced in Android 12.
+ optional SetFrameRateVote set_frame_rate_vote = 24;
+ // Buckets of timings in ms by which the app deadline was missed while
+ // submitting work for a frame.
+ // Introduced in Android 12.
+ optional FrameTimingHistogram app_deadline_misses = 25;
+
+ // Next ID: 26
+}
+
+/**
+ * Histogram of frame counts bucketed by time in milliseconds.
+ * Because of size limitations, we hard-cap the number of buckets, with
+ * buckets for corresponding to larger milliseconds being less precise.
+ */
+message FrameTimingHistogram {
+ // Timings in milliseconds that describes a set of histogram buckets
+ repeated int32 time_millis_buckets = 1;
+ // Number of frames that match to each time_millis, i.e. the bucket
+ // contents
+ // It's required that len(time_millis) == len(frame_count)
+ repeated int64 frame_counts = 2;
+}
diff --git a/services/surfaceflinger/TransactionCallbackInvoker.cpp b/services/surfaceflinger/TransactionCallbackInvoker.cpp
index 3590e76cb9..4f4c02be6c 100644
--- a/services/surfaceflinger/TransactionCallbackInvoker.cpp
+++ b/services/surfaceflinger/TransactionCallbackInvoker.cpp
@@ -36,13 +36,17 @@ namespace android {
// <0 if the first id that doesn't match is lower in c2 or all ids match but c2 is shorter
// >0 if the first id that doesn't match is greater in c2 or all ids match but c2 is longer
//
-// See CallbackIdsHash for a explaniation of why this works
+// See CallbackIdsHash for a explanation of why this works
static int compareCallbackIds(const std::vector<CallbackId>& c1,
const std::vector<CallbackId>& c2) {
if (c1.empty()) {
return !c2.empty();
}
- return c1.front() - c2.front();
+ return c1.front().id - c2.front().id;
+}
+
+static bool containsOnCommitCallbacks(const std::vector<CallbackId>& callbacks) {
+ return !callbacks.empty() && callbacks.front().type == CallbackId::Type::ON_COMMIT;
}
TransactionCallbackInvoker::~TransactionCallbackInvoker() {
@@ -114,39 +118,69 @@ status_t TransactionCallbackInvoker::registerPendingCallbackHandle(
return NO_ERROR;
}
-status_t TransactionCallbackInvoker::finalizePendingCallbackHandles(
- const std::deque<sp<CallbackHandle>>& handles, const std::vector<JankData>& jankData) {
+status_t TransactionCallbackInvoker::finalizeCallbackHandle(const sp<CallbackHandle>& handle,
+ const std::vector<JankData>& jankData) {
+ auto listener = mPendingTransactions.find(handle->listener);
+ if (listener != mPendingTransactions.end()) {
+ auto& pendingCallbacks = listener->second;
+ auto pendingCallback = pendingCallbacks.find(handle->callbackIds);
+
+ if (pendingCallback != pendingCallbacks.end()) {
+ auto& pendingCount = pendingCallback->second;
+
+ // Decrease the pending count for this listener
+ if (--pendingCount == 0) {
+ pendingCallbacks.erase(pendingCallback);
+ }
+ } else {
+ ALOGW("there are more latched callbacks than there were registered callbacks");
+ }
+ if (listener->second.size() == 0) {
+ mPendingTransactions.erase(listener);
+ }
+ } else {
+ ALOGW("cannot find listener in mPendingTransactions");
+ }
+
+ status_t err = addCallbackHandle(handle, jankData);
+ if (err != NO_ERROR) {
+ ALOGE("could not add callback handle");
+ return err;
+ }
+ return NO_ERROR;
+}
+
+status_t TransactionCallbackInvoker::finalizeOnCommitCallbackHandles(
+ const std::deque<sp<CallbackHandle>>& handles,
+ std::deque<sp<CallbackHandle>>& outRemainingHandles) {
if (handles.empty()) {
return NO_ERROR;
}
std::lock_guard lock(mMutex);
-
+ const std::vector<JankData>& jankData = std::vector<JankData>();
for (const auto& handle : handles) {
- auto listener = mPendingTransactions.find(handle->listener);
- if (listener != mPendingTransactions.end()) {
- auto& pendingCallbacks = listener->second;
- auto pendingCallback = pendingCallbacks.find(handle->callbackIds);
-
- if (pendingCallback != pendingCallbacks.end()) {
- auto& pendingCount = pendingCallback->second;
-
- // Decrease the pending count for this listener
- if (--pendingCount == 0) {
- pendingCallbacks.erase(pendingCallback);
- }
- } else {
- ALOGW("there are more latched callbacks than there were registered callbacks");
- }
- if (listener->second.size() == 0) {
- mPendingTransactions.erase(listener);
- }
- } else {
- ALOGW("cannot find listener in mPendingTransactions");
+ if (!containsOnCommitCallbacks(handle->callbackIds)) {
+ outRemainingHandles.push_back(handle);
+ continue;
}
+ status_t err = finalizeCallbackHandle(handle, jankData);
+ if (err != NO_ERROR) {
+ return err;
+ }
+ }
- status_t err = addCallbackHandle(handle, jankData);
+ return NO_ERROR;
+}
+
+status_t TransactionCallbackInvoker::finalizePendingCallbackHandles(
+ const std::deque<sp<CallbackHandle>>& handles, const std::vector<JankData>& jankData) {
+ if (handles.empty()) {
+ return NO_ERROR;
+ }
+ std::lock_guard lock(mMutex);
+ for (const auto& handle : handles) {
+ status_t err = finalizeCallbackHandle(handle, jankData);
if (err != NO_ERROR) {
- ALOGE("could not add callback handle");
return err;
}
}
@@ -243,7 +277,8 @@ void TransactionCallbackInvoker::sendCallbacks() {
}
// If the transaction has been latched
- if (transactionStats.latchTime >= 0) {
+ if (transactionStats.latchTime >= 0 &&
+ !containsOnCommitCallbacks(transactionStats.callbackIds)) {
if (!mPresentFence) {
break;
}
diff --git a/services/surfaceflinger/TransactionCallbackInvoker.h b/services/surfaceflinger/TransactionCallbackInvoker.h
index caa8a4fb45..184b15103e 100644
--- a/services/surfaceflinger/TransactionCallbackInvoker.h
+++ b/services/surfaceflinger/TransactionCallbackInvoker.h
@@ -74,6 +74,8 @@ public:
// Notifies the TransactionCallbackInvoker that a pending CallbackHandle has been presented.
status_t finalizePendingCallbackHandles(const std::deque<sp<CallbackHandle>>& handles,
const std::vector<JankData>& jankData);
+ status_t finalizeOnCommitCallbackHandles(const std::deque<sp<CallbackHandle>>& handles,
+ std::deque<sp<CallbackHandle>>& outRemainingHandles);
// Adds the Transaction CallbackHandle from a layer that does not need to be relatched and
// presented this frame.
@@ -95,6 +97,9 @@ private:
status_t addCallbackHandle(const sp<CallbackHandle>& handle,
const std::vector<JankData>& jankData) REQUIRES(mMutex);
+ status_t finalizeCallbackHandle(const sp<CallbackHandle>& handle,
+ const std::vector<JankData>& jankData) REQUIRES(mMutex);
+
class CallbackDeathRecipient : public IBinder::DeathRecipient {
public:
// This function is a no-op. isBinderAlive needs a linked DeathRecipient to work.
diff --git a/services/surfaceflinger/main_surfaceflinger.cpp b/services/surfaceflinger/main_surfaceflinger.cpp
index 2b8424c987..9686523525 100644
--- a/services/surfaceflinger/main_surfaceflinger.cpp
+++ b/services/surfaceflinger/main_surfaceflinger.cpp
@@ -89,13 +89,47 @@ int main(int, char**) {
// binder threads to 4.
ProcessState::self()->setThreadPoolMaxThreadCount(4);
+ // The binder threadpool we start will inherit sched policy and priority
+ // of (this) creating thread. We want the binder thread pool to have
+ // SCHED_FIFO policy and priority 1 (lowest RT priority)
+ // Once the pool is created we reset this thread's priority back to
+ // original.
+ int newPriority = 0;
+ int origPolicy = sched_getscheduler(0);
+ struct sched_param origSchedParam;
+
+ int errorInPriorityModification = sched_getparam(0, &origSchedParam);
+ if (errorInPriorityModification == 0) {
+ int policy = SCHED_FIFO;
+ newPriority = sched_get_priority_min(policy);
+
+ struct sched_param param;
+ param.sched_priority = newPriority;
+
+ errorInPriorityModification = sched_setscheduler(0, policy, &param);
+ }
+
// start the thread pool
sp<ProcessState> ps(ProcessState::self());
ps->startThreadPool();
+ // Reset current thread's policy and priority
+ if (errorInPriorityModification == 0) {
+ errorInPriorityModification = sched_setscheduler(0, origPolicy, &origSchedParam);
+ } else {
+ ALOGE("Failed to set SurfaceFlinger binder threadpool priority to SCHED_FIFO");
+ }
+
// instantiate surfaceflinger
sp<SurfaceFlinger> flinger = surfaceflinger::createSurfaceFlinger();
+ // Set the minimum policy of surfaceflinger node to be SCHED_FIFO.
+ // So any thread with policy/priority lower than {SCHED_FIFO, 1}, will run
+ // at least with SCHED_FIFO policy and priority 1.
+ if (errorInPriorityModification == 0) {
+ flinger->setMinSchedulerPolicy(SCHED_FIFO, newPriority);
+ }
+
setpriority(PRIO_PROCESS, 0, PRIORITY_URGENT_DISPLAY);
set_sched_policy(0, SP_FOREGROUND);
diff --git a/services/surfaceflinger/tests/BufferGenerator.cpp b/services/surfaceflinger/tests/BufferGenerator.cpp
index 03f8e1afba..47a150dd35 100644
--- a/services/surfaceflinger/tests/BufferGenerator.cpp
+++ b/services/surfaceflinger/tests/BufferGenerator.cpp
@@ -296,12 +296,12 @@ private:
BufferGenerator::BufferGenerator()
: mSurfaceManager(new SurfaceManager), mEglManager(new EglManager), mProgram(new Program) {
- const float width = 1000.0;
- const float height = 1000.0;
+ mBufferSize.set(1000.0, 1000.0);
auto setBufferWithContext =
std::bind(setBuffer, std::placeholders::_1, std::placeholders::_2, this);
- mSurfaceManager->initialize(width, height, HAL_PIXEL_FORMAT_RGBA_8888, setBufferWithContext);
+ mSurfaceManager->initialize(mBufferSize.width, mBufferSize.height, HAL_PIXEL_FORMAT_RGBA_8888,
+ setBufferWithContext);
if (!mEglManager->initialize(mSurfaceManager->getSurface())) return;
@@ -309,7 +309,9 @@ BufferGenerator::BufferGenerator()
if (!mProgram->initialize(VERTEX_SHADER, FRAGMENT_SHADER)) return;
mProgram->use();
- mProgram->bindVec4(0, vec4{width, height, 1.0f / width, 1.0f / height});
+ mProgram->bindVec4(0,
+ vec4{mBufferSize.width, mBufferSize.height, 1.0f / mBufferSize.width,
+ 1.0f / mBufferSize.height});
mProgram->bindVec3(2, &SPHERICAL_HARMONICS[0], 4);
glEnableVertexAttribArray(0);
@@ -372,6 +374,10 @@ status_t BufferGenerator::get(sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence)
return NO_ERROR;
}
+ui::Size BufferGenerator::getSize() {
+ return mBufferSize;
+}
+
// static
void BufferGenerator::setBuffer(const sp<GraphicBuffer>& buffer, int32_t fence,
void* bufferGenerator) {
diff --git a/services/surfaceflinger/tests/BufferGenerator.h b/services/surfaceflinger/tests/BufferGenerator.h
index a3ffe86572..f7d548b6bf 100644
--- a/services/surfaceflinger/tests/BufferGenerator.h
+++ b/services/surfaceflinger/tests/BufferGenerator.h
@@ -37,6 +37,7 @@ public:
/* Static callback that sets the fence on a particular instance */
static void setBuffer(const sp<GraphicBuffer>& buffer, int32_t fence, void* fenceGenerator);
+ ui::Size getSize();
private:
bool mInitialized = false;
@@ -53,6 +54,7 @@ private:
using Epoch = std::chrono::time_point<std::chrono::steady_clock>;
Epoch mEpoch = std::chrono::steady_clock::now();
+ ui::Size mBufferSize;
};
} // namespace android
diff --git a/services/surfaceflinger/tests/Credentials_test.cpp b/services/surfaceflinger/tests/Credentials_test.cpp
index 6246321fab..fa3f0e7239 100644
--- a/services/surfaceflinger/tests/Credentials_test.cpp
+++ b/services/surfaceflinger/tests/Credentials_test.cpp
@@ -305,25 +305,6 @@ TEST_F(CredentialsTest, CaptureLayersTest) {
/**
* The following tests are for methods accessible directly through SurfaceFlinger.
*/
-
-/**
- * An app can pass a buffer queue to the media server and ask the media server to decode a DRM video
- * to that buffer queue. The media server is the buffer producer in this case. Because the app may create
- * its own buffer queue and act as the buffer consumer, the media server wants to be careful to avoid
- * sending decoded video frames to the app. This is where authenticateSurfaceTexture call comes in, to check
- * the consumer of a buffer queue is SurfaceFlinger.
- */
-TEST_F(CredentialsTest, AuthenticateSurfaceTextureTest) {
- setupBackgroundSurface();
- sp<IGraphicBufferProducer> producer =
- mBGSurfaceControl->getSurface()->getIGraphicBufferProducer();
- sp<ISurfaceComposer> sf(ComposerService::getComposerService());
-
- std::function<bool()> condition = [=]() { return sf->authenticateSurfaceTexture(producer); };
- // Anyone should be able to check if the consumer of the buffer queue is SF.
- ASSERT_NO_FATAL_FAILURE(checkWithPrivileges(condition, true, true));
-}
-
TEST_F(CredentialsTest, GetLayerDebugInfo) {
setupBackgroundSurface();
sp<ISurfaceComposer> sf(ComposerService::getComposerService());
diff --git a/services/surfaceflinger/tests/EffectLayer_test.cpp b/services/surfaceflinger/tests/EffectLayer_test.cpp
index f470eda7d3..af00ec7fc9 100644
--- a/services/surfaceflinger/tests/EffectLayer_test.cpp
+++ b/services/surfaceflinger/tests/EffectLayer_test.cpp
@@ -149,7 +149,6 @@ TEST_F(EffectLayerTest, BlurEffectLayerIsVisible) {
t.reparent(blurLayer, mParentLayer);
t.setBackgroundBlurRadius(blurLayer, blurRadius);
t.setCrop(blurLayer, blurRect);
- t.setFrame(blurLayer, blurRect);
t.setAlpha(blurLayer, 0.0f);
t.show(blurLayer);
});
diff --git a/services/surfaceflinger/tests/IPC_test.cpp b/services/surfaceflinger/tests/IPC_test.cpp
index a8647c3e50..9fa3d4c417 100644
--- a/services/surfaceflinger/tests/IPC_test.cpp
+++ b/services/surfaceflinger/tests/IPC_test.cpp
@@ -161,7 +161,6 @@ public:
Color::RED);
transaction->setLayerStack(mSurfaceControl, 0)
.setLayer(mSurfaceControl, std::numeric_limits<int32_t>::max())
- .setFrame(mSurfaceControl, Rect(0, 0, width, height))
.setBuffer(mSurfaceControl, gb)
.setAcquireFence(mSurfaceControl, fence)
.show(mSurfaceControl)
diff --git a/services/surfaceflinger/tests/InvalidHandles_test.cpp b/services/surfaceflinger/tests/InvalidHandles_test.cpp
index 58b039e5d5..9cf7c0909b 100644
--- a/services/surfaceflinger/tests/InvalidHandles_test.cpp
+++ b/services/surfaceflinger/tests/InvalidHandles_test.cpp
@@ -52,12 +52,15 @@ protected:
}
};
-TEST_F(InvalidHandleTest, createSurfaceInvalidHandle) {
- auto notSc = makeNotSurfaceControl();
- ASSERT_EQ(nullptr,
- mScc->createSurface(String8("lolcats"), 19, 47, PIXEL_FORMAT_RGBA_8888, 0,
- notSc->getHandle())
- .get());
+TEST_F(InvalidHandleTest, createSurfaceInvalidParentHandle) {
+ // The createSurface is scheduled now, we could still get a created surface from createSurface.
+ // Should verify if it actually added into current state by checking the screenshot.
+ auto notSc = mScc->createSurface(String8("lolcats"), 19, 47, PIXEL_FORMAT_RGBA_8888, 0,
+ mNotSc->getHandle());
+ LayerCaptureArgs args;
+ args.layerHandle = notSc->getHandle();
+ ScreenCaptureResults captureResults;
+ ASSERT_EQ(NAME_NOT_FOUND, ScreenCapture::captureLayers(args, captureResults));
}
TEST_F(InvalidHandleTest, captureLayersInvalidHandle) {
diff --git a/services/surfaceflinger/tests/LayerCallback_test.cpp b/services/surfaceflinger/tests/LayerCallback_test.cpp
index 158801a705..011ff70409 100644
--- a/services/surfaceflinger/tests/LayerCallback_test.cpp
+++ b/services/surfaceflinger/tests/LayerCallback_test.cpp
@@ -164,7 +164,10 @@ TEST_F(LayerCallbackTest, NoBufferNoColor) {
return;
}
- transaction.setFrame(layer, Rect(0, 0, 32, 32)).apply();
+ ui::Size bufferSize = getBufferSize();
+ TransactionUtils::setFrame(transaction, layer, Rect(0, 0, bufferSize.width, bufferSize.height),
+ Rect(0, 0, 32, 32));
+ transaction.apply();
ExpectedResult expected;
expected.addSurface(ExpectedResult::Transaction::NOT_PRESENTED, layer,
@@ -184,7 +187,10 @@ TEST_F(LayerCallbackTest, BufferNoColor) {
return;
}
- transaction.setFrame(layer, Rect(0, 0, 32, 32)).apply();
+ ui::Size bufferSize = getBufferSize();
+ TransactionUtils::setFrame(transaction, layer, Rect(0, 0, bufferSize.width, bufferSize.height),
+ Rect(0, 0, 32, 32));
+ transaction.apply();
ExpectedResult expected;
expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
@@ -203,7 +209,10 @@ TEST_F(LayerCallbackTest, NoBufferColor) {
return;
}
- transaction.setFrame(layer, Rect(0, 0, 32, 32)).apply();
+ ui::Size bufferSize = getBufferSize();
+ TransactionUtils::setFrame(transaction, layer, Rect(0, 0, bufferSize.width, bufferSize.height),
+ Rect(0, 0, 32, 32));
+ transaction.apply();
ExpectedResult expected;
expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer,
@@ -238,7 +247,10 @@ TEST_F(LayerCallbackTest, OffScreen) {
return;
}
- transaction.setFrame(layer, Rect(-100, -100, 100, 100)).apply();
+ ui::Size bufferSize = getBufferSize();
+ TransactionUtils::setFrame(transaction, layer, Rect(0, 0, bufferSize.width, bufferSize.height),
+ Rect(-100, -100, 100, 100));
+ transaction.apply();
ExpectedResult expected;
expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
@@ -263,8 +275,15 @@ TEST_F(LayerCallbackTest, MergeBufferNoColor) {
return;
}
- transaction1.setFrame(layer1, Rect(0, 0, 32, 32));
- transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply();
+ ui::Size bufferSize = getBufferSize();
+
+ TransactionUtils::setFrame(transaction1, layer1,
+ Rect(0, 0, bufferSize.width, bufferSize.height), Rect(0, 0, 32, 32));
+ TransactionUtils::setFrame(transaction2, layer2,
+ Rect(0, 0, bufferSize.width, bufferSize.height),
+ Rect(32, 32, 64, 64));
+
+ transaction2.merge(std::move(transaction1)).apply();
ExpectedResult expected;
expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2});
@@ -290,8 +309,15 @@ TEST_F(LayerCallbackTest, MergeNoBufferColor) {
return;
}
- transaction1.setFrame(layer1, Rect(0, 0, 32, 32));
- transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply();
+ ui::Size bufferSize = getBufferSize();
+
+ TransactionUtils::setFrame(transaction1, layer1,
+ Rect(0, 0, bufferSize.width, bufferSize.height), Rect(0, 0, 32, 32));
+ TransactionUtils::setFrame(transaction2, layer2,
+ Rect(0, 0, bufferSize.width, bufferSize.height),
+ Rect(32, 32, 64, 64));
+
+ transaction2.merge(std::move(transaction1)).apply();
ExpectedResult expected;
expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2},
@@ -318,8 +344,15 @@ TEST_F(LayerCallbackTest, MergeOneBufferOneColor) {
return;
}
- transaction1.setFrame(layer1, Rect(0, 0, 32, 32));
- transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply();
+ ui::Size bufferSize = getBufferSize();
+
+ TransactionUtils::setFrame(transaction1, layer1,
+ Rect(0, 0, bufferSize.width, bufferSize.height), Rect(0, 0, 32, 32));
+ TransactionUtils::setFrame(transaction2, layer2,
+ Rect(0, 0, bufferSize.width, bufferSize.height),
+ Rect(32, 32, 64, 64));
+
+ transaction2.merge(std::move(transaction1)).apply();
ExpectedResult expected;
expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer1);
@@ -405,8 +438,15 @@ TEST_F(LayerCallbackTest, Merge_DifferentClients) {
return;
}
- transaction1.setFrame(layer1, Rect(0, 0, 32, 32));
- transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply();
+ ui::Size bufferSize = getBufferSize();
+
+ TransactionUtils::setFrame(transaction1, layer1,
+ Rect(0, 0, bufferSize.width, bufferSize.height), Rect(0, 0, 32, 32));
+ TransactionUtils::setFrame(transaction2, layer2,
+ Rect(0, 0, bufferSize.width, bufferSize.height),
+ Rect(32, 32, 64, 64));
+
+ transaction2.merge(std::move(transaction1)).apply();
ExpectedResult expected;
expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2});
@@ -491,7 +531,11 @@ TEST_F(LayerCallbackTest, MultipleTransactions_SameStateChange) {
}
}
- transaction.setFrame(layer, Rect(0, 0, 32, 32)).apply();
+ ui::Size bufferSize = getBufferSize();
+ TransactionUtils::setFrame(transaction, layer,
+ Rect(0, 0, bufferSize.width, bufferSize.height),
+ Rect(0, 0, 32, 32));
+ transaction.apply();
ExpectedResult expected;
expected.addSurface((i == 0) ? ExpectedResult::Transaction::PRESENTED
@@ -523,8 +567,16 @@ TEST_F(LayerCallbackTest, MultipleTransactions_Merge) {
return;
}
- transaction1.setFrame(layer1, Rect(0, 0, 32, 32));
- transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply();
+ ui::Size bufferSize = getBufferSize();
+
+ TransactionUtils::setFrame(transaction1, layer1,
+ Rect(0, 0, bufferSize.width, bufferSize.height),
+ Rect(0, 0, 32, 32));
+ TransactionUtils::setFrame(transaction2, layer2,
+ Rect(0, 0, bufferSize.width, bufferSize.height),
+ Rect(32, 32, 64, 64));
+
+ transaction2.merge(std::move(transaction1)).apply();
ExpectedResult expected;
expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2},
@@ -564,8 +616,16 @@ TEST_F(LayerCallbackTest, MultipleTransactions_Merge_DifferentClients) {
return;
}
- transaction1.setFrame(layer1, Rect(0, 0, 32, 32));
- transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply();
+ ui::Size bufferSize = getBufferSize();
+
+ TransactionUtils::setFrame(transaction1, layer1,
+ Rect(0, 0, bufferSize.width, bufferSize.height),
+ Rect(0, 0, 32, 32));
+ TransactionUtils::setFrame(transaction2, layer2,
+ Rect(0, 0, bufferSize.width, bufferSize.height),
+ Rect(32, 32, 64, 64));
+
+ transaction2.merge(std::move(transaction1)).apply();
ExpectedResult expected;
expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2},
@@ -606,8 +666,15 @@ TEST_F(LayerCallbackTest, MultipleTransactions_Merge_DifferentClients_NoStateCha
return;
}
- transaction1.setFrame(layer1, Rect(0, 0, 32, 32));
- transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply();
+ ui::Size bufferSize = getBufferSize();
+
+ TransactionUtils::setFrame(transaction1, layer1,
+ Rect(0, 0, bufferSize.width, bufferSize.height), Rect(0, 0, 32, 32));
+ TransactionUtils::setFrame(transaction2, layer2,
+ Rect(0, 0, bufferSize.width, bufferSize.height),
+ Rect(32, 32, 64, 64));
+
+ transaction2.merge(std::move(transaction1)).apply();
ExpectedResult expected;
expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2});
@@ -661,8 +728,15 @@ TEST_F(LayerCallbackTest, MultipleTransactions_Merge_DifferentClients_SameStateC
return;
}
- transaction1.setFrame(layer1, Rect(0, 0, 32, 32));
- transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply();
+ ui::Size bufferSize = getBufferSize();
+
+ TransactionUtils::setFrame(transaction1, layer1,
+ Rect(0, 0, bufferSize.width, bufferSize.height), Rect(0, 0, 32, 32));
+ TransactionUtils::setFrame(transaction2, layer2,
+ Rect(0, 0, bufferSize.width, bufferSize.height),
+ Rect(32, 32, 64, 64));
+
+ transaction2.merge(std::move(transaction1)).apply();
ExpectedResult expected;
expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2});
@@ -682,7 +756,10 @@ TEST_F(LayerCallbackTest, MultipleTransactions_Merge_DifferentClients_SameStateC
return;
}
- transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply();
+ TransactionUtils::setFrame(transaction2, layer2,
+ Rect(0, 0, bufferSize.width, bufferSize.height),
+ Rect(32, 32, 64, 64));
+ transaction2.merge(std::move(transaction1)).apply();
expected.addSurface(ExpectedResult::Transaction::NOT_PRESENTED, layer2,
ExpectedResult::Buffer::NOT_ACQUIRED);
@@ -762,7 +839,10 @@ TEST_F(LayerCallbackTest, MultipleTransactions_SingleFrame_SameStateChange) {
return;
}
- transaction.setFrame(layer, Rect(0, 0, 32, 32)).apply();
+ ui::Size bufferSize = getBufferSize();
+ TransactionUtils::setFrame(transaction, layer, Rect(0, 0, bufferSize.width, bufferSize.height),
+ Rect(0, 0, 32, 32));
+ transaction.apply();
ExpectedResult expectedResult;
expectedResult.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
@@ -781,7 +861,10 @@ TEST_F(LayerCallbackTest, MultipleTransactions_SingleFrame_SameStateChange) {
return;
}
- transaction.setFrame(layer, Rect(0, 0, 32, 32)).apply();
+ TransactionUtils::setFrame(transaction, layer,
+ Rect(0, 0, bufferSize.width, bufferSize.height),
+ Rect(0, 0, 32, 32));
+ transaction.apply();
}
EXPECT_NO_FATAL_FAILURE(waitForCallbacks(callback, expectedResults, true));
}
diff --git a/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp
index 7505e6ea9b..7581cd3af4 100644
--- a/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp
+++ b/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp
@@ -135,53 +135,6 @@ TEST_P(LayerRenderTypeTransactionTest, SetPositionPartiallyOutOfBounds_BufferQue
}
}
-TEST_P(LayerRenderTypeTransactionTest, SetPositionWithResize_BufferQueue) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
-
- // setPosition is applied immediately by default, with or without resize
- // pending
- Transaction().setPosition(layer, 5, 10).setSize(layer, 64, 64).apply();
- {
- SCOPED_TRACE("resize pending");
- auto shot = getScreenCapture();
- const Rect rect(5, 10, 37, 42);
- shot->expectColor(rect, Color::RED);
- shot->expectBorder(rect, Color::BLACK);
- }
-
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 64, 64));
- {
- SCOPED_TRACE("resize applied");
- getScreenCapture()->expectColor(Rect(5, 10, 69, 74), Color::RED);
- }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetSizeBasic_BufferQueue) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
-
- Transaction().setSize(layer, 64, 64).apply();
- {
- SCOPED_TRACE("resize pending");
- auto shot = getScreenCapture();
- const Rect rect(0, 0, 32, 32);
- shot->expectColor(rect, Color::RED);
- shot->expectBorder(rect, Color::BLACK);
- }
-
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 64, 64));
- {
- SCOPED_TRACE("resize applied");
- auto shot = getScreenCapture();
- const Rect rect(0, 0, 64, 64);
- shot->expectColor(rect, Color::RED);
- shot->expectBorder(rect, Color::BLACK);
- }
-}
-
TEST_P(LayerRenderTypeTransactionTest, CreateLayer_BufferState) {
uint32_t transformHint = ui::Transform::ROT_INVALID;
sp<SurfaceControl> layer;
@@ -204,11 +157,7 @@ void LayerRenderTypeTransactionTest::setRelativeZBasicHelper(uint32_t layerType)
Transaction().setPosition(layerG, 16, 16).setRelativeLayer(layerG, layerR, 1).apply();
break;
case ISurfaceComposerClient::eFXSurfaceBufferState:
- Transaction()
- .setFrame(layerR, Rect(0, 0, 32, 32))
- .setFrame(layerG, Rect(16, 16, 48, 48))
- .setRelativeLayer(layerG, layerR, 1)
- .apply();
+ Transaction().setPosition(layerG, 16, 16).setRelativeLayer(layerG, layerR, 1).apply();
break;
default:
ASSERT_FALSE(true) << "Unsupported layer type";
@@ -260,10 +209,9 @@ void LayerRenderTypeTransactionTest::setRelativeZGroupHelper(uint32_t layerType)
break;
case ISurfaceComposerClient::eFXSurfaceBufferState:
Transaction()
- .setFrame(layerR, Rect(0, 0, 32, 32))
- .setFrame(layerG, Rect(8, 8, 40, 40))
+ .setPosition(layerG, 8, 8)
.setRelativeLayer(layerG, layerR, 3)
- .setFrame(layerB, Rect(16, 16, 48, 48))
+ .setPosition(layerB, 16, 16)
.setLayer(layerB, mLayerZBase + 2)
.apply();
break;
@@ -388,7 +336,6 @@ TEST_P(LayerRenderTypeTransactionTest, SetTransparentRegionHintBasic_BufferState
Transaction()
.setTransparentRegionHint(layer, Region(top))
.setBuffer(layer, buffer)
- .setFrame(layer, Rect(0, 0, 32, 32))
.apply();
{
SCOPED_TRACE("top transparent");
@@ -447,7 +394,7 @@ TEST_P(LayerRenderTypeTransactionTest, SetTransparentRegionHintOutOfBounds_Buffe
// check that transparent region hint is bound by the layer size
Transaction()
.setTransparentRegionHint(layerTransparent, Region(mDisplayRect))
- .setFrame(layerR, Rect(16, 16, 48, 48))
+ .setPosition(layerR, 16, 16)
.setLayer(layerR, mLayerZBase + 1)
.apply();
ASSERT_NO_FATAL_FAILURE(
@@ -477,8 +424,7 @@ void LayerRenderTypeTransactionTest::setAlphaBasicHelper(uint32_t layerType) {
Transaction()
.setAlpha(layer1, 0.25f)
.setAlpha(layer2, 0.75f)
- .setFrame(layer1, Rect(0, 0, 32, 32))
- .setFrame(layer2, Rect(16, 0, 48, 32))
+ .setPosition(layer2, 16, 0)
.setLayer(layer2, mLayerZBase + 1)
.apply();
break;
@@ -573,7 +519,7 @@ void LayerRenderTypeTransactionTest::setBackgroundColorHelper(uint32_t layerType
ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, fillColor, width, height));
expectedColor = fillColor;
}
- Transaction().setFrame(layer, Rect(0, 0, width, height)).apply();
+ Transaction().setCrop(layer, Rect(0, 0, width, height)).apply();
break;
default:
GTEST_FAIL() << "Unknown layer type in setBackgroundColorHelper";
@@ -614,44 +560,6 @@ TEST_P(LayerRenderTypeTransactionTest, SetBackgroundColor_Color_NoEffect) {
}
TEST_P(LayerRenderTypeTransactionTest,
- SetBackgroundColor_BufferQueue_BufferFill_NoPriorColor_Basic) {
- bool priorColor = false;
- bool bufferFill = true;
- float alpha = 1.0f;
- Color finalColor = Color::RED;
- ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue,
- priorColor, bufferFill, alpha, finalColor));
-}
-
-TEST_P(LayerRenderTypeTransactionTest,
- SetBackgroundColor_BufferQueue_NoBufferFill_NoPriorColor_Basic) {
- bool priorColor = false;
- bool bufferFill = false;
- float alpha = 1.0f;
- Color finalColor = Color::GREEN;
- ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue,
- priorColor, bufferFill, alpha, finalColor));
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetBackgroundColor_BufferQueue_BufferFill_PriorColor_Basic) {
- bool priorColor = true;
- bool bufferFill = true;
- float alpha = 1.0f;
- Color finalColor = Color::RED;
- ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue,
- priorColor, bufferFill, alpha, finalColor));
-}
-
-TEST_P(LayerRenderTypeTransactionTest,
- SetBackgroundColor_BufferQueue_NoBufferFill_PriorColor_Basic) {
- bool priorColor = true;
- bool bufferFill = false;
- float alpha = 1.0f;
- Color finalColor = Color::GREEN;
- ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue,
- priorColor, bufferFill, alpha, finalColor));
-}
-TEST_P(LayerRenderTypeTransactionTest,
SetBackgroundColor_BufferQueue_NoPriorColor_ZeroAlpha_NoEffect) {
bool priorColor = false;
bool bufferFill = false;
@@ -849,42 +757,39 @@ TEST_P(LayerRenderTypeTransactionTest, SetMatrixBasic_BufferState) {
ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerQuadrant(layer, 32, 32, Color::RED, Color::GREEN,
Color::BLUE, Color::WHITE));
- Transaction()
- .setMatrix(layer, 1.0f, 0.0f, 0.0f, 1.0f)
- .setFrame(layer, Rect(0, 0, 32, 32))
- .apply();
+ Transaction().setPosition(layer, 32, 32).setMatrix(layer, 1.0f, 0.0f, 0.0f, 1.0f).apply();
{
SCOPED_TRACE("IDENTITY");
- getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN,
+ getScreenCapture()->expectQuadrant(Rect(32, 32, 64, 64), Color::RED, Color::GREEN,
Color::BLUE, Color::WHITE);
}
Transaction().setMatrix(layer, -1.0f, 0.0f, 0.0f, 1.0f).apply();
{
SCOPED_TRACE("FLIP_H");
- getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN,
- Color::BLUE, Color::WHITE);
+ getScreenCapture()->expectQuadrant(Rect(0, 32, 32, 64), Color::GREEN, Color::RED,
+ Color::WHITE, Color::BLUE);
}
Transaction().setMatrix(layer, 1.0f, 0.0f, 0.0f, -1.0f).apply();
{
SCOPED_TRACE("FLIP_V");
- getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN,
- Color::BLUE, Color::WHITE);
+ getScreenCapture()->expectQuadrant(Rect(32, 0, 64, 32), Color::BLUE, Color::WHITE,
+ Color::RED, Color::GREEN);
}
Transaction().setMatrix(layer, 0.0f, 1.0f, -1.0f, 0.0f).apply();
{
SCOPED_TRACE("ROT_90");
- getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN,
- Color::BLUE, Color::WHITE);
+ getScreenCapture()->expectQuadrant(Rect(0, 32, 32, 64), Color::BLUE, Color::RED,
+ Color::WHITE, Color::GREEN);
}
Transaction().setMatrix(layer, 2.0f, 0.0f, 0.0f, 2.0f).apply();
{
SCOPED_TRACE("SCALE");
- getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN,
- Color::BLUE, Color::WHITE);
+ getScreenCapture()->expectQuadrant(Rect(32, 32, 96, 96), Color::RED, Color::GREEN,
+ Color::BLUE, Color::WHITE, 1 /* tolerance */);
}
}
@@ -911,29 +816,6 @@ TEST_P(LayerRenderTypeTransactionTest, SetMatrixRot45_BufferQueue) {
shot->expectColor(get8x8Rect(2 * unit, 3 * unit), Color::WHITE);
}
-TEST_P(LayerRenderTypeTransactionTest, SetMatrixWithResize_BufferQueue) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
-
- // setMatrix is applied after any pending resize, unlike setPosition
- Transaction().setMatrix(layer, 2.0f, 0.0f, 0.0f, 2.0f).setSize(layer, 64, 64).apply();
- {
- SCOPED_TRACE("resize pending");
- auto shot = getScreenCapture();
- const Rect rect(0, 0, 32, 32);
- shot->expectColor(rect, Color::RED);
- shot->expectBorder(rect, Color::BLACK);
- }
-
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 64, 64));
- {
- SCOPED_TRACE("resize applied");
- const Rect rect(0, 0, 128, 128);
- getScreenCapture()->expectColor(rect, Color::RED);
- }
-}
-
TEST_P(LayerRenderTypeTransactionTest, SetCropBasic_BufferQueue) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
@@ -955,8 +837,8 @@ TEST_P(LayerRenderTypeTransactionTest, SetCropBasic_BufferState) {
Transaction().setCrop(layer, crop).apply();
auto shot = getScreenCapture();
- shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
- shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
+ shot->expectColor(crop, Color::RED);
+ shot->expectBorder(crop, Color::BLACK);
}
TEST_P(LayerRenderTypeTransactionTest, SetCropEmpty_BufferQueue) {
@@ -986,13 +868,13 @@ TEST_P(LayerRenderTypeTransactionTest, SetCropEmpty_BufferState) {
{
SCOPED_TRACE("empty rect");
Transaction().setCrop(layer, Rect(8, 8, 8, 8)).apply();
- getScreenCapture()->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
}
{
SCOPED_TRACE("negative rect");
Transaction().setCrop(layer, Rect(8, 8, 0, 0)).apply();
- getScreenCapture()->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
}
}
@@ -1016,8 +898,6 @@ TEST_P(LayerRenderTypeTransactionTest, SetCropOutOfBounds_BufferState) {
TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, 32, 16), Color::BLUE);
TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 16, 32, 64), Color::RED);
- Transaction().setFrame(layer, Rect(0, 0, 64, 64)).apply();
-
Transaction().setBuffer(layer, buffer).apply();
// Partially out of bounds in the negative (upper left) direction
@@ -1025,8 +905,8 @@ TEST_P(LayerRenderTypeTransactionTest, SetCropOutOfBounds_BufferState) {
{
SCOPED_TRACE("out of bounds, negative (upper left) direction");
auto shot = getScreenCapture();
- shot->expectColor(Rect(0, 0, 64, 64), Color::BLUE);
- shot->expectBorder(Rect(0, 0, 64, 64), Color::BLACK);
+ shot->expectColor(Rect(0, 0, 32, 16), Color::BLUE);
+ shot->expectBorder(Rect(0, 0, 32, 16), Color::BLACK);
}
// Partially out of bounds in the positive (lower right) direction
@@ -1034,8 +914,8 @@ TEST_P(LayerRenderTypeTransactionTest, SetCropOutOfBounds_BufferState) {
{
SCOPED_TRACE("out of bounds, positive (lower right) direction");
auto shot = getScreenCapture();
- shot->expectColor(Rect(0, 0, 64, 64), Color::RED);
- shot->expectBorder(Rect(0, 0, 64, 64), Color::BLACK);
+ shot->expectColor(Rect(0, 16, 32, 64), Color::RED);
+ shot->expectBorder(Rect(0, 16, 32, 64), Color::BLACK);
}
// Fully out of buffer space bounds
@@ -1043,9 +923,7 @@ TEST_P(LayerRenderTypeTransactionTest, SetCropOutOfBounds_BufferState) {
{
SCOPED_TRACE("Fully out of bounds");
auto shot = getScreenCapture();
- shot->expectColor(Rect(0, 0, 64, 16), Color::BLUE);
- shot->expectColor(Rect(0, 16, 64, 64), Color::RED);
- shot->expectBorder(Rect(0, 0, 64, 64), Color::BLACK);
+ shot->expectColor(Rect(0, 0, 64, 64), Color::BLACK);
}
}
@@ -1068,12 +946,11 @@ TEST_P(LayerRenderTypeTransactionTest, SetCropWithTranslation_BufferState) {
layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32));
- const Rect frame(32, 32, 64, 64);
const Rect crop(8, 8, 24, 24);
- Transaction().setFrame(layer, frame).setCrop(layer, crop).apply();
+ Transaction().setPosition(layer, 32, 32).setCrop(layer, crop).apply();
auto shot = getScreenCapture();
- shot->expectColor(frame, Color::RED);
- shot->expectBorder(frame, Color::BLACK);
+ shot->expectColor(Rect(40, 40, 56, 56), Color::RED);
+ shot->expectBorder(Rect(40, 40, 56, 56), Color::BLACK);
}
TEST_P(LayerRenderTypeTransactionTest, SetCropWithScale_BufferQueue) {
@@ -1091,29 +968,6 @@ TEST_P(LayerRenderTypeTransactionTest, SetCropWithScale_BufferQueue) {
shot->expectBorder(Rect(16, 16, 48, 48), Color::BLACK);
}
-TEST_P(LayerRenderTypeTransactionTest, SetCropWithResize_BufferQueue) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
-
- // setCrop is applied immediately by default, with or without resize pending
- Transaction().setCrop(layer, Rect(8, 8, 24, 24)).setSize(layer, 16, 16).apply();
- {
- SCOPED_TRACE("resize pending");
- auto shot = getScreenCapture();
- shot->expectColor(Rect(8, 8, 24, 24), Color::RED);
- shot->expectBorder(Rect(8, 8, 24, 24), Color::BLACK);
- }
-
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 16, 16));
- {
- SCOPED_TRACE("resize applied");
- auto shot = getScreenCapture();
- shot->expectColor(Rect(8, 8, 16, 16), Color::RED);
- shot->expectBorder(Rect(8, 8, 16, 16), Color::BLACK);
- }
-}
-
TEST_P(LayerRenderTypeTransactionTest, SetFrameBasic_BufferState) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(
@@ -1121,7 +975,10 @@ TEST_P(LayerRenderTypeTransactionTest, SetFrameBasic_BufferState) {
ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32));
const Rect frame(8, 8, 24, 24);
- Transaction().setFrame(layer, frame).apply();
+ Transaction t;
+ TransactionUtils::setFrame(t, layer, Rect(0, 0, 32, 32), frame);
+ t.apply();
+
auto shot = getScreenCapture();
shot->expectColor(frame, Color::RED);
shot->expectBorder(frame, Color::BLACK);
@@ -1133,16 +990,23 @@ TEST_P(LayerRenderTypeTransactionTest, SetFrameEmpty_BufferState) {
layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32));
+ Transaction t;
{
SCOPED_TRACE("empty rect");
- Transaction().setFrame(layer, Rect(8, 8, 8, 8)).apply();
+ TransactionUtils::setFrame(t, layer, Rect(0, 0, 32, 32), Rect(8, 8, 8, 8));
+ t.apply();
+
getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
}
{
SCOPED_TRACE("negative rect");
- Transaction().setFrame(layer, Rect(8, 8, 0, 0)).apply();
- getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
+ TransactionUtils::setFrame(t, layer, Rect(0, 0, 32, 32), Rect(8, 8, 0, 0));
+ t.apply();
+
+ auto shot = getScreenCapture();
+ shot->expectColor(Rect(0, 0, 8, 8), Color::RED);
+ shot->expectBorder(Rect(0, 0, 8, 8), Color::BLACK);
}
}
@@ -1152,10 +1016,10 @@ TEST_P(LayerRenderTypeTransactionTest, SetFrameDefaultParentless_BufferState) {
layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 10, 10));
- // A parentless layer will default to a frame with the same size as the buffer
+ // A layer with a buffer will have a computed size that matches the buffer size.
auto shot = getScreenCapture();
- shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
- shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
+ shot->expectColor(Rect(0, 0, 10, 10), Color::RED);
+ shot->expectBorder(Rect(0, 0, 10, 10), Color::BLACK);
}
TEST_P(LayerRenderTypeTransactionTest, SetFrameDefaultBSParent_BufferState) {
@@ -1163,17 +1027,16 @@ TEST_P(LayerRenderTypeTransactionTest, SetFrameDefaultBSParent_BufferState) {
ASSERT_NO_FATAL_FAILURE(
parent = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(parent, Color::RED, 32, 32));
- Transaction().setFrame(parent, Rect(0, 0, 32, 32)).apply();
ASSERT_NO_FATAL_FAILURE(
- child = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+ child = createLayer("test", 10, 10, ISurfaceComposerClient::eFXSurfaceBufferState));
ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(child, Color::BLUE, 10, 10));
Transaction().reparent(child, parent).apply();
- // A layer will default to the frame of its parent
+ // A layer with a buffer will have a computed size that matches the buffer size.
auto shot = getScreenCapture();
- shot->expectColor(Rect(0, 0, 32, 32), Color::BLUE);
+ shot->expectColor(Rect(0, 0, 10, 10), Color::BLUE);
shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
}
@@ -1183,14 +1046,14 @@ TEST_P(LayerRenderTypeTransactionTest, SetFrameDefaultBQParent_BufferState) {
ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(parent, Color::RED, 32, 32));
ASSERT_NO_FATAL_FAILURE(
- child = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+ child = createLayer("test", 10, 10, ISurfaceComposerClient::eFXSurfaceBufferState));
ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(child, Color::BLUE, 10, 10));
Transaction().reparent(child, parent).apply();
- // A layer will default to the frame of its parent
+ // A layer with a buffer will have a computed size that matches the buffer size.
auto shot = getScreenCapture();
- shot->expectColor(Rect(0, 0, 32, 32), Color::BLUE);
+ shot->expectColor(Rect(0, 0, 10, 10), Color::BLUE);
shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
}
@@ -1199,11 +1062,10 @@ TEST_P(LayerRenderTypeTransactionTest, SetFrameUpdate_BufferState) {
ASSERT_NO_FATAL_FAILURE(
layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32));
- Transaction().setFrame(layer, Rect(0, 0, 32, 32)).apply();
std::this_thread::sleep_for(500ms);
- Transaction().setFrame(layer, Rect(16, 16, 48, 48)).apply();
+ Transaction().setPosition(layer, 16, 16).apply();
auto shot = getScreenCapture();
shot->expectColor(Rect(16, 16, 48, 48), Color::RED);
@@ -1215,18 +1077,20 @@ TEST_P(LayerRenderTypeTransactionTest, SetFrameOutsideBounds_BufferState) {
ASSERT_NO_FATAL_FAILURE(
parent = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
ASSERT_NO_FATAL_FAILURE(
- child = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+ child = createLayer("test", 10, 10, ISurfaceComposerClient::eFXSurfaceBufferState));
Transaction().reparent(child, parent).apply();
ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(parent, Color::RED, 32, 32));
- Transaction().setFrame(parent, Rect(0, 0, 32, 32)).apply();
ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(child, Color::BLUE, 10, 10));
- Transaction().setFrame(child, Rect(0, 16, 32, 32)).apply();
+ Rect childDst(0, 16, 32, 32);
+ Transaction t;
+ TransactionUtils::setFrame(t, child, Rect(0, 0, 10, 10), childDst);
+ t.apply();
auto shot = getScreenCapture();
shot->expectColor(Rect(0, 0, 32, 16), Color::RED);
- shot->expectColor(Rect(0, 16, 32, 32), Color::BLUE);
+ shot->expectColor(childDst, Color::BLUE);
shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
}
@@ -1238,8 +1102,8 @@ TEST_P(LayerRenderTypeTransactionTest, SetBufferBasic_BufferState) {
ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32));
auto shot = getScreenCapture();
- shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
- shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
+ shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
}
TEST_P(LayerRenderTypeTransactionTest, SetBufferMultipleBuffers_BufferState) {
@@ -1252,8 +1116,8 @@ TEST_P(LayerRenderTypeTransactionTest, SetBufferMultipleBuffers_BufferState) {
{
SCOPED_TRACE("set buffer 1");
auto shot = getScreenCapture();
- shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
- shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
+ shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
}
ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::BLUE, 32, 32));
@@ -1261,8 +1125,8 @@ TEST_P(LayerRenderTypeTransactionTest, SetBufferMultipleBuffers_BufferState) {
{
SCOPED_TRACE("set buffer 2");
auto shot = getScreenCapture();
- shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLUE);
- shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
+ shot->expectColor(Rect(0, 0, 32, 32), Color::BLUE);
+ shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
}
ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32));
@@ -1270,8 +1134,8 @@ TEST_P(LayerRenderTypeTransactionTest, SetBufferMultipleBuffers_BufferState) {
{
SCOPED_TRACE("set buffer 3");
auto shot = getScreenCapture();
- shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
- shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
+ shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
}
}
@@ -1286,7 +1150,6 @@ TEST_P(LayerRenderTypeTransactionTest, SetBufferMultipleLayers_BufferState) {
ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer1, Color::RED, 64, 64));
- Transaction().setFrame(layer1, Rect(0, 0, 64, 64)).apply();
{
SCOPED_TRACE("set layer 1 buffer red");
auto shot = getScreenCapture();
@@ -1295,7 +1158,6 @@ TEST_P(LayerRenderTypeTransactionTest, SetBufferMultipleLayers_BufferState) {
ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer2, Color::BLUE, 32, 32));
- Transaction().setFrame(layer2, Rect(0, 0, 32, 32)).apply();
{
SCOPED_TRACE("set layer 2 buffer blue");
auto shot = getScreenCapture();
@@ -1350,8 +1212,8 @@ TEST_P(LayerRenderTypeTransactionTest, SetBufferCaching_BufferState) {
Color color = colors[idx % colors.size()];
auto shot = screenshot();
- shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), color);
- shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
+ shot->expectColor(Rect(0, 0, 32, 32), color);
+ shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
}
idx++;
}
@@ -1383,8 +1245,8 @@ TEST_P(LayerRenderTypeTransactionTest, SetBufferCaching_LeastRecentlyUsed_Buffer
Color color = colors[idx % colors.size()];
auto shot = screenshot();
- shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), color);
- shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
+ shot->expectColor(Rect(0, 0, 32, 32), color);
+ shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
}
idx++;
}
@@ -1416,8 +1278,8 @@ TEST_P(LayerRenderTypeTransactionTest, SetBufferCaching_DestroyedBuffer_BufferSt
Color color = colors[idx % colors.size()];
auto shot = screenshot();
- shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), color);
- shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
+ shot->expectColor(Rect(0, 0, 32, 32), color);
+ shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
}
if (idx == 0) {
buffers[0].clear();
@@ -1435,7 +1297,6 @@ TEST_P(LayerRenderTypeTransactionTest, SetTransformRotate90_BufferState) {
Color::BLUE, Color::WHITE));
Transaction()
- .setFrame(layer, Rect(0, 0, 32, 32))
.setTransform(layer, NATIVE_WINDOW_TRANSFORM_ROT_90)
.apply();
@@ -1452,7 +1313,6 @@ TEST_P(LayerRenderTypeTransactionTest, SetTransformFlipH_BufferState) {
Color::BLUE, Color::WHITE));
Transaction()
- .setFrame(layer, Rect(0, 0, 32, 32))
.setTransform(layer, NATIVE_WINDOW_TRANSFORM_FLIP_H)
.apply();
@@ -1469,7 +1329,6 @@ TEST_P(LayerRenderTypeTransactionTest, SetTransformFlipV_BufferState) {
Color::BLUE, Color::WHITE));
Transaction()
- .setFrame(layer, Rect(0, 0, 32, 32))
.setTransform(layer, NATIVE_WINDOW_TRANSFORM_FLIP_V)
.apply();
@@ -1518,8 +1377,8 @@ TEST_P(LayerRenderTypeTransactionTest, SetFenceNull_BufferState) {
Transaction().setBuffer(layer, buffer).setAcquireFence(layer, fence).apply();
auto shot = getScreenCapture();
- shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
- shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
+ shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
}
TEST_P(LayerRenderTypeTransactionTest, SetDataspaceBasic_BufferState) {
@@ -1534,8 +1393,8 @@ TEST_P(LayerRenderTypeTransactionTest, SetDataspaceBasic_BufferState) {
Transaction().setBuffer(layer, buffer).setDataspace(layer, ui::Dataspace::UNKNOWN).apply();
auto shot = getScreenCapture();
- shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
- shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
+ shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
}
TEST_P(LayerRenderTypeTransactionTest, SetHdrMetadataBasic_BufferState) {
@@ -1552,8 +1411,8 @@ TEST_P(LayerRenderTypeTransactionTest, SetHdrMetadataBasic_BufferState) {
Transaction().setBuffer(layer, buffer).setHdrMetadata(layer, hdrMetadata).apply();
auto shot = getScreenCapture();
- shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
- shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
+ shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
}
TEST_P(LayerRenderTypeTransactionTest, SetSurfaceDamageRegionBasic_BufferState) {
@@ -1570,8 +1429,8 @@ TEST_P(LayerRenderTypeTransactionTest, SetSurfaceDamageRegionBasic_BufferState)
Transaction().setBuffer(layer, buffer).setSurfaceDamageRegion(layer, region).apply();
auto shot = getScreenCapture();
- shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
- shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
+ shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
}
TEST_P(LayerRenderTypeTransactionTest, SetApiBasic_BufferState) {
@@ -1586,8 +1445,8 @@ TEST_P(LayerRenderTypeTransactionTest, SetApiBasic_BufferState) {
Transaction().setBuffer(layer, buffer).setApi(layer, NATIVE_WINDOW_API_CPU).apply();
auto shot = getScreenCapture();
- shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
- shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
+ shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
}
TEST_P(LayerRenderTypeTransactionTest, SetColorTransformBasic) {
diff --git a/services/surfaceflinger/tests/LayerTransactionTest.h b/services/surfaceflinger/tests/LayerTransactionTest.h
index 87c7b7d829..0bc8fe7aa0 100644
--- a/services/surfaceflinger/tests/LayerTransactionTest.h
+++ b/services/surfaceflinger/tests/LayerTransactionTest.h
@@ -244,6 +244,11 @@ protected:
return bufferGenerator.get(outBuffer, outFence);
}
+ static ui::Size getBufferSize() {
+ static BufferGenerator bufferGenerator;
+ return bufferGenerator.getSize();
+ }
+
sp<SurfaceComposerClient> mClient;
bool deviceSupportsBlurs() {
diff --git a/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp
index ac5e297e43..2828d61a76 100644
--- a/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp
+++ b/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp
@@ -51,14 +51,9 @@ INSTANTIATE_TEST_CASE_P(
LayerTypeAndRenderTypeTransactionTests, LayerTypeAndRenderTypeTransactionTest,
::testing::Combine(
::testing::Values(
- static_cast<uint32_t>(ISurfaceComposerClient::eFXSurfaceBufferQueue),
static_cast<uint32_t>(ISurfaceComposerClient::eFXSurfaceBufferState)),
::testing::Values(RenderPath::VIRTUAL_DISPLAY, RenderPath::SCREENSHOT)));
-TEST_P(LayerTypeAndRenderTypeTransactionTest, SetSizeInvalid) {
- // cannot test robustness against invalid sizes (zero or really huge)
-}
-
TEST_P(LayerTypeAndRenderTypeTransactionTest, SetZBasic) {
sp<SurfaceControl> layerR;
sp<SurfaceControl> layerG;
@@ -196,17 +191,7 @@ TEST_P(LayerTypeAndRenderTypeTransactionTest, SetCornerRadius) {
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", size, size));
ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED, size, size));
- if (mLayerType == ISurfaceComposerClient::eFXSurfaceBufferQueue) {
- Transaction()
- .setCornerRadius(layer, cornerRadius)
- .setCrop(layer, Rect(0, 0, size, size))
- .apply();
- } else {
- Transaction()
- .setCornerRadius(layer, cornerRadius)
- .setFrame(layer, Rect(0, 0, size, size))
- .apply();
- }
+ Transaction().setCornerRadius(layer, cornerRadius).apply();
{
const uint8_t bottom = size - 1;
const uint8_t right = size - 1;
@@ -234,19 +219,13 @@ TEST_P(LayerTypeAndRenderTypeTransactionTest, SetCornerRadiusRotated) {
ASSERT_NO_FATAL_FAILURE(child = createLayer("child", size, size));
ASSERT_NO_FATAL_FAILURE(fillLayerColor(child, Color::GREEN, size, size));
- auto transaction = Transaction()
- .setCornerRadius(parent, cornerRadius)
- .setCrop(parent, Rect(0, 0, size, size))
- .reparent(child, parent)
- .setPosition(child, 0, size)
- // Rotate by half PI
- .setMatrix(child, 0.0f, -1.0f, 1.0f, 0.0f);
- if (mLayerType == ISurfaceComposerClient::eFXSurfaceBufferQueue) {
- transaction.setCrop(parent, Rect(0, 0, size, size));
- } else {
- transaction.setFrame(parent, Rect(0, 0, size, size));
- }
- transaction.apply();
+ Transaction()
+ .setCornerRadius(parent, cornerRadius)
+ .reparent(child, parent)
+ .setPosition(child, 0, size)
+ // Rotate by half PI
+ .setMatrix(child, 0.0f, -1.0f, 1.0f, 0.0f)
+ .apply();
{
const uint8_t bottom = size - 1;
@@ -275,21 +254,12 @@ TEST_P(LayerTypeAndRenderTypeTransactionTest, SetCornerRadiusChildCrop) {
ASSERT_NO_FATAL_FAILURE(child = createLayer("child", size, size / 2));
ASSERT_NO_FATAL_FAILURE(fillLayerColor(child, Color::GREEN, size, size / 2));
- if (mLayerType == ISurfaceComposerClient::eFXSurfaceBufferQueue) {
- Transaction()
- .setCornerRadius(parent, cornerRadius)
- .setCrop(parent, Rect(0, 0, size, size))
- .reparent(child, parent)
- .setPosition(child, 0, size / 2)
- .apply();
- } else {
- Transaction()
- .setCornerRadius(parent, cornerRadius)
- .setFrame(parent, Rect(0, 0, size, size))
- .reparent(child, parent)
- .setFrame(child, Rect(0, size / 2, size, size))
- .apply();
- }
+ Transaction()
+ .setCornerRadius(parent, cornerRadius)
+ .reparent(child, parent)
+ .setPosition(child, 0, size / 2)
+ .apply();
+
{
const uint8_t bottom = size - 1;
const uint8_t right = size - 1;
@@ -331,12 +301,9 @@ TEST_P(LayerTypeAndRenderTypeTransactionTest, SetBackgroundBlurRadiusSimple) {
Transaction()
.setLayer(greenLayer, mLayerZBase)
- .setFrame(leftLayer, {0, 0, canvasSize * 2, canvasSize * 2})
.setLayer(leftLayer, mLayerZBase + 1)
- .setFrame(leftLayer, leftRect)
.setLayer(rightLayer, mLayerZBase + 2)
.setPosition(rightLayer, rightRect.left, rightRect.top)
- .setFrame(rightLayer, rightRect)
.apply();
{
@@ -352,8 +319,6 @@ TEST_P(LayerTypeAndRenderTypeTransactionTest, SetBackgroundBlurRadiusSimple) {
.setLayer(blurLayer, mLayerZBase + 3)
.setBackgroundBlurRadius(blurLayer, blurRadius)
.setCrop(blurLayer, blurRect)
- .setFrame(blurLayer, blurRect)
- .setSize(blurLayer, blurRect.getWidth(), blurRect.getHeight())
.setAlpha(blurLayer, 0.0f)
.apply();
@@ -435,10 +400,8 @@ TEST_P(LayerTypeAndRenderTypeTransactionTest, SetBackgroundBlurAffectedByParentA
Transaction()
.setLayer(left, mLayerZBase + 1)
- .setFrame(left, {0, 0, size, size})
.setLayer(right, mLayerZBase + 2)
.setPosition(right, size, 0)
- .setFrame(right, {size, 0, size * 2, size})
.apply();
{
@@ -457,7 +420,6 @@ TEST_P(LayerTypeAndRenderTypeTransactionTest, SetBackgroundBlurAffectedByParentA
.setAlpha(blurParent, 0.5)
.setLayer(blur, mLayerZBase + 4)
.setBackgroundBlurRadius(blur, size) // set the blur radius to the size of one rect
- .setFrame(blur, {0, 0, size * 2, size})
.reparent(blur, blurParent)
.apply();
diff --git a/services/surfaceflinger/tests/LayerUpdate_test.cpp b/services/surfaceflinger/tests/LayerUpdate_test.cpp
index 39d9206e1a..ee4d367f3d 100644
--- a/services/surfaceflinger/tests/LayerUpdate_test.cpp
+++ b/services/surfaceflinger/tests/LayerUpdate_test.cpp
@@ -127,15 +127,7 @@ protected:
TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63);
waitForPostedBuffers();
}
- void restoreInitialState() {
- asTransaction([&](Transaction& t) {
- t.setSize(mFGSurfaceControl, 64, 64);
- t.setPosition(mFGSurfaceControl, 64, 64);
- t.setCrop(mFGSurfaceControl, Rect(0, 0, 64, 64));
- });
- EXPECT_INITIAL_STATE("After restoring initial state");
- }
std::unique_ptr<ScreenCapture> sc;
};
@@ -160,61 +152,6 @@ protected:
}
};
-TEST_F(LayerUpdateTest, DeferredTransactionTest) {
- std::unique_ptr<ScreenCapture> sc;
- {
- SCOPED_TRACE("before anything");
- ScreenCapture::captureScreen(&sc);
- sc->expectBGColor(32, 32);
- sc->expectFGColor(96, 96);
- sc->expectBGColor(160, 160);
- }
-
- // set up two deferred transactions on different frames
- asTransaction([&](Transaction& t) {
- t.setAlpha(mFGSurfaceControl, 0.75);
- t.deferTransactionUntil_legacy(mFGSurfaceControl, mSyncSurfaceControl,
- mSyncSurfaceControl->getSurface()->getNextFrameNumber());
- });
-
- asTransaction([&](Transaction& t) {
- t.setPosition(mFGSurfaceControl, 128, 128);
- t.deferTransactionUntil_legacy(mFGSurfaceControl, mSyncSurfaceControl,
- mSyncSurfaceControl->getSurface()->getNextFrameNumber() + 1);
- });
-
- {
- SCOPED_TRACE("before any trigger");
- ScreenCapture::captureScreen(&sc);
- sc->expectBGColor(32, 32);
- sc->expectFGColor(96, 96);
- sc->expectBGColor(160, 160);
- }
-
- // should trigger the first deferred transaction, but not the second one
- TransactionUtils::fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31);
- {
- SCOPED_TRACE("after first trigger");
- ScreenCapture::captureScreen(&sc);
- sc->expectBGColor(32, 32);
- sc->checkPixel(96, 96, 162, 63, 96);
- sc->expectBGColor(160, 160);
- }
-
- // should show up immediately since it's not deferred
- asTransaction([&](Transaction& t) { t.setAlpha(mFGSurfaceControl, 1.0); });
-
- // trigger the second deferred transaction
- TransactionUtils::fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31);
- {
- SCOPED_TRACE("after second trigger");
- ScreenCapture::captureScreen(&sc);
- sc->expectBGColor(32, 32);
- sc->expectBGColor(96, 96);
- sc->expectFGColor(160, 160);
- }
-}
-
TEST_F(LayerUpdateTest, LayerWithNoBuffersResizesImmediately) {
std::unique_ptr<ScreenCapture> sc;
@@ -517,221 +454,6 @@ TEST_F(ChildLayerTest, ChildrenRelativeZSurvivesParentDestruction) {
}
}
-TEST_F(ChildLayerTest, ChildrenInheritNonTransformScalingFromParent) {
- asTransaction([&](Transaction& t) {
- t.show(mChild);
- t.setPosition(mChild, 0, 0);
- t.setPosition(mFGSurfaceControl, 0, 0);
- });
-
- {
- mCapture = screenshot();
- // We've positioned the child in the top left.
- mCapture->expectChildColor(0, 0);
- // But it's only 10x15.
- mCapture->expectFGColor(10, 15);
- }
-
- asTransaction([&](Transaction& t) {
- mFGSurfaceControl->getSurface()->setScalingMode(
- NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
- // Resubmit buffer with new scaling mode
- TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63);
- // We cause scaling by 2.
- t.setSize(mFGSurfaceControl, 128, 128);
- });
-
- {
- mCapture = screenshot();
- // We've positioned the child in the top left.
- mCapture->expectChildColor(0, 0);
- mCapture->expectChildColor(10, 10);
- mCapture->expectChildColor(19, 29);
- // And now it should be scaled all the way to 20x30
- mCapture->expectFGColor(20, 30);
- }
-}
-
-// Regression test for b/37673612
-TEST_F(ChildLayerTest, ChildrenWithParentBufferTransform) {
- asTransaction([&](Transaction& t) {
- t.show(mChild);
- t.setPosition(mChild, 0, 0);
- t.setPosition(mFGSurfaceControl, 0, 0);
- });
-
- {
- mCapture = screenshot();
- // We've positioned the child in the top left.
- mCapture->expectChildColor(0, 0);
- mCapture->expectChildColor(9, 14);
- // But it's only 10x15.
- mCapture->expectFGColor(10, 15);
- }
- // We set things up as in b/37673612 so that there is a mismatch between the buffer size and
- // the WM specified state size.
- asTransaction([&](Transaction& t) { t.setSize(mFGSurfaceControl, 128, 64); });
- sp<Surface> s = mFGSurfaceControl->getSurface();
- auto anw = static_cast<ANativeWindow*>(s.get());
- native_window_set_buffers_transform(anw, NATIVE_WINDOW_TRANSFORM_ROT_90);
- native_window_set_buffers_dimensions(anw, 64, 128);
- TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63);
- waitForPostedBuffers();
-
- {
- // The child should still be in the same place and not have any strange scaling as in
- // b/37673612.
- mCapture = screenshot();
- mCapture->expectChildColor(0, 0);
- mCapture->expectFGColor(10, 10);
- }
-}
-
-// A child with a buffer transform from its parents should be cropped by its parent bounds.
-TEST_F(ChildLayerTest, ChildCroppedByParentWithBufferTransform) {
- asTransaction([&](Transaction& t) {
- t.show(mChild);
- t.setPosition(mChild, 0, 0);
- t.setPosition(mFGSurfaceControl, 0, 0);
- t.setSize(mChild, 100, 100);
- });
- TransactionUtils::fillSurfaceRGBA8(mChild, 200, 200, 200);
-
- {
- mCapture = screenshot();
-
- mCapture->expectChildColor(0, 0);
- mCapture->expectChildColor(63, 63);
- mCapture->expectBGColor(64, 64);
- }
-
- asTransaction([&](Transaction& t) { t.setSize(mFGSurfaceControl, 128, 64); });
- sp<Surface> s = mFGSurfaceControl->getSurface();
- auto anw = static_cast<ANativeWindow*>(s.get());
- // Apply a 90 transform on the buffer.
- native_window_set_buffers_transform(anw, NATIVE_WINDOW_TRANSFORM_ROT_90);
- native_window_set_buffers_dimensions(anw, 64, 128);
- TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63);
- waitForPostedBuffers();
-
- // The child should be cropped by the new parent bounds.
- {
- mCapture = screenshot();
- mCapture->expectChildColor(0, 0);
- mCapture->expectChildColor(99, 63);
- mCapture->expectFGColor(100, 63);
- mCapture->expectBGColor(128, 64);
- }
-}
-
-// A child with a scale transform from its parents should be cropped by its parent bounds.
-TEST_F(ChildLayerTest, ChildCroppedByParentWithBufferScale) {
- asTransaction([&](Transaction& t) {
- t.show(mChild);
- t.setPosition(mChild, 0, 0);
- t.setPosition(mFGSurfaceControl, 0, 0);
- t.setSize(mChild, 200, 200);
- });
- TransactionUtils::fillSurfaceRGBA8(mChild, 200, 200, 200);
-
- {
- mCapture = screenshot();
-
- mCapture->expectChildColor(0, 0);
- mCapture->expectChildColor(63, 63);
- mCapture->expectBGColor(64, 64);
- }
-
- asTransaction([&](Transaction& t) {
- mFGSurfaceControl->getSurface()->setScalingMode(
- NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
- // Resubmit buffer with new scaling mode
- TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63);
- // Set a scaling by 2.
- t.setSize(mFGSurfaceControl, 128, 128);
- });
-
- // Child should inherit its parents scale but should be cropped by its parent bounds.
- {
- mCapture = screenshot();
- mCapture->expectChildColor(0, 0);
- mCapture->expectChildColor(127, 127);
- mCapture->expectBGColor(128, 128);
- }
-}
-
-// Regression test for b/127368943
-// Child should ignore the buffer transform but apply parent scale transform.
-TEST_F(ChildLayerTest, ChildrenWithParentBufferTransformAndScale) {
- asTransaction([&](Transaction& t) {
- t.show(mChild);
- t.setPosition(mChild, 0, 0);
- t.setPosition(mFGSurfaceControl, 0, 0);
- });
-
- {
- mCapture = screenshot();
- mCapture->expectChildColor(0, 0);
- mCapture->expectChildColor(9, 14);
- mCapture->expectFGColor(10, 15);
- }
-
- // Change the size of the foreground to 128 * 64 so we can test rotation as well.
- asTransaction([&](Transaction& t) {
- mFGSurfaceControl->getSurface()->setScalingMode(
- NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
- // Resubmit buffer with new scaling mode
- TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63);
- t.setSize(mFGSurfaceControl, 128, 64);
- });
- sp<Surface> s = mFGSurfaceControl->getSurface();
- auto anw = static_cast<ANativeWindow*>(s.get());
- // Apply a 90 transform on the buffer and submit a buffer half the expected size so that we
- // have an effective scale of 2.0 applied to the buffer along with a rotation transform.
- native_window_set_buffers_transform(anw, NATIVE_WINDOW_TRANSFORM_ROT_90);
- native_window_set_buffers_dimensions(anw, 32, 64);
- TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63);
- waitForPostedBuffers();
-
- // The child should ignore the buffer transform but apply the 2.0 scale from parent.
- {
- mCapture = screenshot();
- mCapture->expectChildColor(0, 0);
- mCapture->expectChildColor(19, 29);
- mCapture->expectFGColor(20, 30);
- }
-}
-
-TEST_F(ChildLayerTest, Bug36858924) {
- // Destroy the child layer
- mChild.clear();
-
- // Now recreate it as hidden
- mChild = createSurface(mClient, "Child surface", 10, 10, PIXEL_FORMAT_RGBA_8888,
- ISurfaceComposerClient::eHidden, mFGSurfaceControl.get());
-
- // Show the child layer in a deferred transaction
- asTransaction([&](Transaction& t) {
- t.deferTransactionUntil_legacy(mChild, mFGSurfaceControl,
- mFGSurfaceControl->getSurface()->getNextFrameNumber());
- t.show(mChild);
- });
-
- // Render the foreground surface a few times
- //
- // Prior to the bugfix for b/36858924, this would usually hang while trying to fill the third
- // frame because SurfaceFlinger would never process the deferred transaction and would therefore
- // never acquire/release the first buffer
- ALOGI("Filling 1");
- TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 0, 255, 0);
- ALOGI("Filling 2");
- TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 0, 0, 255);
- ALOGI("Filling 3");
- TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 255, 0, 0);
- ALOGI("Filling 4");
- TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 0, 255, 0);
-}
-
TEST_F(ChildLayerTest, Reparent) {
asTransaction([&](Transaction& t) {
t.show(mChild);
diff --git a/services/surfaceflinger/tests/MirrorLayer_test.cpp b/services/surfaceflinger/tests/MirrorLayer_test.cpp
index 613b21ef04..ccf434d63a 100644
--- a/services/surfaceflinger/tests/MirrorLayer_test.cpp
+++ b/services/surfaceflinger/tests/MirrorLayer_test.cpp
@@ -195,7 +195,7 @@ TEST_F(MirrorLayerTest, MirrorBufferLayer) {
createLayer("BufferStateLayer", 200, 200, ISurfaceComposerClient::eFXSurfaceBufferState,
mChildLayer.get());
fillBufferStateLayerColor(bufferStateLayer, Color::BLUE, 200, 200);
- Transaction().setFrame(bufferStateLayer, Rect(0, 0, 200, 200)).show(bufferStateLayer).apply();
+ Transaction().show(bufferStateLayer).apply();
{
SCOPED_TRACE("Initial Mirror BufferStateLayer");
diff --git a/services/surfaceflinger/tests/ScreenCapture_test.cpp b/services/surfaceflinger/tests/ScreenCapture_test.cpp
index b0753c842e..2e9c10ce5c 100644
--- a/services/surfaceflinger/tests/ScreenCapture_test.cpp
+++ b/services/surfaceflinger/tests/ScreenCapture_test.cpp
@@ -350,7 +350,10 @@ TEST_F(ScreenCaptureTest, CaptureBoundlessLayerWithoutSourceCropFails) {
TEST_F(ScreenCaptureTest, CaptureBufferLayerWithoutBufferFails) {
sp<SurfaceControl> child = createSurface(mClient, "Child surface", 10, 10,
- PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
+ PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eFXSurfaceBufferState,
+ mFGSurfaceControl.get());
+
SurfaceComposerClient::Transaction().show(child).apply(true);
sp<GraphicBuffer> outBuffer;
@@ -361,7 +364,7 @@ TEST_F(ScreenCaptureTest, CaptureBufferLayerWithoutBufferFails) {
ScreenCaptureResults captureResults;
ASSERT_EQ(BAD_VALUE, ScreenCapture::captureLayers(args, captureResults));
- TransactionUtils::fillSurfaceRGBA8(child, Color::RED);
+ ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(child, Color::RED, 32, 32));
SurfaceComposerClient::Transaction().apply(true);
ASSERT_EQ(NO_ERROR, ScreenCapture::captureLayers(args, captureResults));
ScreenCapture sc(captureResults.buffer);
@@ -432,12 +435,15 @@ TEST_F(ScreenCaptureTest, CaptureGrandchildOnly) {
}
TEST_F(ScreenCaptureTest, CaptureCrop) {
- sp<SurfaceControl> redLayer = createLayer(String8("Red surface"), 60, 60, 0);
+ sp<SurfaceControl> redLayer = createLayer(String8("Red surface"), 60, 60,
+ ISurfaceComposerClient::eFXSurfaceBufferState);
sp<SurfaceControl> blueLayer = createSurface(mClient, "Blue surface", 30, 30,
- PIXEL_FORMAT_RGBA_8888, 0, redLayer.get());
+ PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eFXSurfaceBufferState,
+ redLayer.get());
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(redLayer, Color::RED, 60, 60));
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(blueLayer, Color::BLUE, 30, 30));
+ ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(redLayer, Color::RED, 60, 60));
+ ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(blueLayer, Color::BLUE, 30, 30));
SurfaceComposerClient::Transaction()
.setLayer(redLayer, INT32_MAX - 1)
@@ -464,12 +470,15 @@ TEST_F(ScreenCaptureTest, CaptureCrop) {
}
TEST_F(ScreenCaptureTest, CaptureSize) {
- sp<SurfaceControl> redLayer = createLayer(String8("Red surface"), 60, 60, 0);
+ sp<SurfaceControl> redLayer =
+ createLayer(String8("Red surface"), 60, 60, ISurfaceComposerClient::eFXSurfaceBufferState);
sp<SurfaceControl> blueLayer = createSurface(mClient, "Blue surface", 30, 30,
- PIXEL_FORMAT_RGBA_8888, 0, redLayer.get());
+ PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eFXSurfaceBufferState,
+ redLayer.get());
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(redLayer, Color::RED, 60, 60));
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(blueLayer, Color::BLUE, 30, 30));
+ ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(redLayer, Color::RED, 60, 60));
+ ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(blueLayer, Color::BLUE, 30, 30));
SurfaceComposerClient::Transaction()
.setLayer(redLayer, INT32_MAX - 1)
@@ -489,6 +498,7 @@ TEST_F(ScreenCaptureTest, CaptureSize) {
captureArgs.frameScaleX = 0.5f;
captureArgs.frameScaleY = 0.5f;
+ sleep(1);
ScreenCapture::captureLayers(&mCapture, captureArgs);
// Capturing the downsized area (30x30) should leave both red and blue but in a smaller area.
@@ -519,14 +529,15 @@ TEST_F(ScreenCaptureTest, CaptureInvalidLayer) {
}
TEST_F(ScreenCaptureTest, CaputureSecureLayer) {
- sp<SurfaceControl> redLayer = createLayer(String8("Red surface"), 60, 60, 0);
+ sp<SurfaceControl> redLayer = createLayer(String8("Red surface"), 60, 60,
+ ISurfaceComposerClient::eFXSurfaceBufferState);
sp<SurfaceControl> secureLayer =
createLayer(String8("Secure surface"), 30, 30,
ISurfaceComposerClient::eSecure |
- ISurfaceComposerClient::eFXSurfaceBufferQueue,
+ ISurfaceComposerClient::eFXSurfaceBufferState,
redLayer.get());
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(redLayer, Color::RED, 60, 60));
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(secureLayer, Color::BLUE, 30, 30));
+ ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(redLayer, Color::RED, 60, 60));
+ ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(secureLayer, Color::BLUE, 30, 30));
auto redLayerHandle = redLayer->getHandle();
Transaction()
@@ -874,4 +885,4 @@ TEST_F(ScreenCaptureChildOnlyTest, CaptureLayerIgnoresTransform) {
} // namespace android
// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion" \ No newline at end of file
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
index 09bd775872..ee4e863474 100644
--- a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
+++ b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
@@ -44,7 +44,6 @@ constexpr uint32_t BUFFER_UPDATES = 18;
constexpr uint32_t LAYER_UPDATE = INT_MAX - 2;
constexpr uint32_t SIZE_UPDATE = 134;
constexpr uint32_t STACK_UPDATE = 1;
-constexpr uint64_t DEFERRED_UPDATE = 0;
constexpr int32_t RELATIVE_Z = 42;
constexpr float ALPHA_UPDATE = 0.29f;
constexpr float CORNER_RADIUS_UPDATE = 0.2f;
@@ -191,7 +190,6 @@ public:
bool hiddenFlagUpdateFound(const SurfaceChange& change, bool foundHiddenFlag);
bool opaqueFlagUpdateFound(const SurfaceChange& change, bool foundOpaqueFlag);
bool secureFlagUpdateFound(const SurfaceChange& change, bool foundSecureFlag);
- bool deferredTransactionUpdateFound(const SurfaceChange& change, bool foundDeferred);
bool reparentUpdateFound(const SurfaceChange& change, bool found);
bool relativeParentUpdateFound(const SurfaceChange& change, bool found);
bool shadowRadiusUpdateFound(const SurfaceChange& change, bool found);
@@ -227,7 +225,6 @@ public:
void hiddenFlagUpdate(Transaction&);
void opaqueFlagUpdate(Transaction&);
void secureFlagUpdate(Transaction&);
- void deferredTransactionUpdate(Transaction&);
void reparentUpdate(Transaction&);
void relativeParentUpdate(Transaction&);
void shadowRadiusUpdate(Transaction&);
@@ -396,10 +393,6 @@ void SurfaceInterceptorTest::secureFlagUpdate(Transaction& t) {
t.setFlags(mBGSurfaceControl, layer_state_t::eLayerSecure, layer_state_t::eLayerSecure);
}
-void SurfaceInterceptorTest::deferredTransactionUpdate(Transaction& t) {
- t.deferTransactionUntil_legacy(mBGSurfaceControl, mBGSurfaceControl, DEFERRED_UPDATE);
-}
-
void SurfaceInterceptorTest::reparentUpdate(Transaction& t) {
t.reparent(mBGSurfaceControl, mFGSurfaceControl);
}
@@ -437,7 +430,6 @@ void SurfaceInterceptorTest::runAllUpdates() {
runInTransaction(&SurfaceInterceptorTest::hiddenFlagUpdate);
runInTransaction(&SurfaceInterceptorTest::opaqueFlagUpdate);
runInTransaction(&SurfaceInterceptorTest::secureFlagUpdate);
- runInTransaction(&SurfaceInterceptorTest::deferredTransactionUpdate);
runInTransaction(&SurfaceInterceptorTest::reparentUpdate);
runInTransaction(&SurfaceInterceptorTest::relativeParentUpdate);
runInTransaction(&SurfaceInterceptorTest::shadowRadiusUpdate);
@@ -621,18 +613,6 @@ bool SurfaceInterceptorTest::secureFlagUpdateFound(const SurfaceChange& change,
return foundSecureFlag;
}
-bool SurfaceInterceptorTest::deferredTransactionUpdateFound(const SurfaceChange& change,
- bool foundDeferred) {
- bool hasId(change.deferred_transaction().layer_id() == mBGLayerId);
- bool hasFrameNumber(change.deferred_transaction().frame_number() == DEFERRED_UPDATE);
- if (hasId && hasFrameNumber && !foundDeferred) {
- foundDeferred = true;
- } else if (hasId && hasFrameNumber && foundDeferred) {
- [] () { FAIL(); }();
- }
- return foundDeferred;
-}
-
bool SurfaceInterceptorTest::reparentUpdateFound(const SurfaceChange& change, bool found) {
bool hasId(change.reparent().parent_id() == mFGLayerId);
if (hasId && !found) {
@@ -715,9 +695,6 @@ bool SurfaceInterceptorTest::surfaceUpdateFound(const Trace& trace,
case SurfaceChange::SurfaceChangeCase::kSecureFlag:
foundUpdate = secureFlagUpdateFound(change, foundUpdate);
break;
- case SurfaceChange::SurfaceChangeCase::kDeferredTransaction:
- foundUpdate = deferredTransactionUpdateFound(change, foundUpdate);
- break;
case SurfaceChange::SurfaceChangeCase::kReparent:
foundUpdate = reparentUpdateFound(change, foundUpdate);
break;
@@ -749,7 +726,6 @@ void SurfaceInterceptorTest::assertAllUpdatesFound(const Trace& trace) {
ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kHiddenFlag));
ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kOpaqueFlag));
ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kSecureFlag));
- ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kDeferredTransaction));
ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kReparent));
ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kRelativeParent));
}
@@ -906,11 +882,6 @@ TEST_F(SurfaceInterceptorTest, InterceptSecureFlagUpdateWorks) {
SurfaceChange::SurfaceChangeCase::kSecureFlag);
}
-TEST_F(SurfaceInterceptorTest, InterceptDeferredTransactionUpdateWorks) {
- captureTest(&SurfaceInterceptorTest::deferredTransactionUpdate,
- SurfaceChange::SurfaceChangeCase::kDeferredTransaction);
-}
-
TEST_F(SurfaceInterceptorTest, InterceptReparentUpdateWorks) {
captureTest(&SurfaceInterceptorTest::reparentUpdate,
SurfaceChange::SurfaceChangeCase::kReparent);
@@ -950,11 +921,6 @@ TEST_F(SurfaceInterceptorTest, InterceptDisplayDeletionWorks) {
ASSERT_TRUE(singleIncrementFound(capturedTrace, Increment::IncrementCase::kDisplayDeletion));
}
-TEST_F(SurfaceInterceptorTest, InterceptBufferUpdateWorks) {
- captureTest(&SurfaceInterceptorTest::nBufferUpdates,
- &SurfaceInterceptorTest::bufferUpdatesFound);
-}
-
// If the interceptor is enabled while buffer updates are being pushed, the interceptor should
// first create a snapshot of the existing displays and surfaces and then start capturing
// the buffer updates
@@ -970,26 +936,6 @@ TEST_F(SurfaceInterceptorTest, InterceptWhileBufferUpdatesWorks) {
const auto& firstIncrement = capturedTrace.mutable_increment(0);
ASSERT_EQ(firstIncrement->increment_case(), Increment::IncrementCase::kDisplayCreation);
}
-
-TEST_F(SurfaceInterceptorTest, InterceptSimultaneousUpdatesWorks) {
- enableInterceptor();
- setupBackgroundSurface();
- std::thread bufferUpdates(&SurfaceInterceptorTest::nBufferUpdates, this);
- std::thread surfaceUpdates(&SurfaceInterceptorTest::runAllUpdates, this);
- runInTransaction(&SurfaceInterceptorTest::surfaceCreation);
- bufferUpdates.join();
- surfaceUpdates.join();
- disableInterceptor();
-
- Trace capturedTrace;
- ASSERT_EQ(NO_ERROR, readProtoFile(&capturedTrace));
- preProcessTrace(capturedTrace);
-
- assertAllUpdatesFound(capturedTrace);
- ASSERT_TRUE(bufferUpdatesFound(capturedTrace));
- ASSERT_TRUE(singleIncrementFound(capturedTrace, Increment::IncrementCase::kSurfaceCreation));
}
-}
-
// TODO(b/129481165): remove the #pragma below and fix conversion issues
#pragma clang diagnostic pop // ignored "-Wconversion -Wextra"
diff --git a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
index c081f9b642..162711d6f5 100644
--- a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
+++ b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
@@ -91,7 +91,6 @@ constexpr static TestColor RED = {195, 63, 63, 255};
constexpr static TestColor LIGHT_RED = {255, 177, 177, 255};
constexpr static TestColor GREEN = {63, 195, 63, 255};
constexpr static TestColor BLUE = {63, 63, 195, 255};
-constexpr static TestColor DARK_GRAY = {63, 63, 63, 255};
constexpr static TestColor LIGHT_GRAY = {200, 200, 200, 255};
// Fill an RGBA_8888 formatted surface with a single color.
@@ -1294,31 +1293,6 @@ protected:
EXPECT_TRUE(framesAreSame(frame2Ref, sFakeComposer->getFrameRects(2)));
}
- void Test_LayerResize() {
- ALOGD("TransactionTest::LayerResize");
- {
- TransactionScope ts(*sFakeComposer);
- ts.setSize(mFGSurfaceControl, 128, 128);
- }
-
- fillSurfaceRGBA8(mFGSurfaceControl, GREEN);
- sFakeComposer->runVSyncAndWait();
-
- ASSERT_EQ(3, sFakeComposer->getFrameCount()); // Make sure the waits didn't time out and
- // there's no extra frames.
-
- auto frame1Ref = mBaseFrame;
- // NOTE: The resize should not be visible for frame 1 as there's no buffer with new size
- // posted.
- EXPECT_TRUE(framesAreSame(frame1Ref, sFakeComposer->getFrameRects(1)));
-
- auto frame2Ref = frame1Ref;
- frame2Ref[FG_LAYER].mSwapCount++;
- frame2Ref[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 128, 64 + 128};
- frame2Ref[FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 128.f, 128.f};
- EXPECT_TRUE(framesAreSame(frame2Ref, sFakeComposer->getFrameRects(2)));
- }
-
void Test_LayerCrop() {
// TODO: Add scaling to confirm that crop happens in buffer space?
{
@@ -1469,77 +1443,6 @@ protected:
}
}
- void Test_DeferredTransaction() {
- // Synchronization surface
- constexpr static int SYNC_LAYER = 2;
- auto syncSurfaceControl = mComposerClient->createSurface(String8("Sync Test Surface"), 1, 1,
- PIXEL_FORMAT_RGBA_8888, 0);
- ASSERT_TRUE(syncSurfaceControl != nullptr);
- ASSERT_TRUE(syncSurfaceControl->isValid());
-
- fillSurfaceRGBA8(syncSurfaceControl, DARK_GRAY);
-
- {
- TransactionScope ts(*sFakeComposer);
- ts.setLayer(syncSurfaceControl, INT32_MAX - 1);
- ts.setPosition(syncSurfaceControl, mDisplayWidth - 2, mDisplayHeight - 2);
- ts.show(syncSurfaceControl);
- }
- auto referenceFrame = mBaseFrame;
- referenceFrame.push_back(makeSimpleRect(mDisplayWidth - 2, mDisplayHeight - 2,
- mDisplayWidth - 1, mDisplayHeight - 1));
- referenceFrame[SYNC_LAYER].mSwapCount = 1;
- EXPECT_EQ(2, sFakeComposer->getFrameCount());
- EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
-
- // set up two deferred transactions on different frames - these should not yield composited
- // frames
- {
- TransactionScope ts(*sFakeComposer);
- ts.setAlpha(mFGSurfaceControl, 0.75);
- ts.deferTransactionUntil_legacy(mFGSurfaceControl, syncSurfaceControl,
- syncSurfaceControl->getSurface()->getNextFrameNumber());
- }
- EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
-
- {
- TransactionScope ts(*sFakeComposer);
- ts.setPosition(mFGSurfaceControl, 128, 128);
- ts.deferTransactionUntil_legacy(mFGSurfaceControl, syncSurfaceControl,
- syncSurfaceControl->getSurface()->getNextFrameNumber() +
- 1);
- }
- EXPECT_EQ(4, sFakeComposer->getFrameCount());
- EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
-
- // should trigger the first deferred transaction, but not the second one
- fillSurfaceRGBA8(syncSurfaceControl, DARK_GRAY);
- sFakeComposer->runVSyncAndWait();
- EXPECT_EQ(5, sFakeComposer->getFrameCount());
-
- referenceFrame[FG_LAYER].mPlaneAlpha = 0.75f;
- referenceFrame[SYNC_LAYER].mSwapCount++;
- EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
-
- // should show up immediately since it's not deferred
- {
- TransactionScope ts(*sFakeComposer);
- ts.setAlpha(mFGSurfaceControl, 1.0);
- }
- referenceFrame[FG_LAYER].mPlaneAlpha = 1.f;
- EXPECT_EQ(6, sFakeComposer->getFrameCount());
- EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
-
- // trigger the second deferred transaction
- fillSurfaceRGBA8(syncSurfaceControl, DARK_GRAY);
- sFakeComposer->runVSyncAndWait();
- // TODO: Compute from layer size?
- referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{128, 128, 128 + 64, 128 + 64};
- referenceFrame[SYNC_LAYER].mSwapCount++;
- EXPECT_EQ(7, sFakeComposer->getFrameCount());
- EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
- }
-
void Test_SetRelativeLayer() {
constexpr int RELATIVE_LAYER = 2;
auto relativeSurfaceControl = mComposerClient->createSurface(String8("Test Surface"), 64,
@@ -1589,10 +1492,6 @@ TEST_F(TransactionTest_2_1, DISABLED_LayerMove) {
Test_LayerMove();
}
-TEST_F(TransactionTest_2_1, DISABLED_LayerResize) {
- Test_LayerResize();
-}
-
TEST_F(TransactionTest_2_1, DISABLED_LayerCrop) {
Test_LayerCrop();
}
@@ -1625,10 +1524,6 @@ TEST_F(TransactionTest_2_1, DISABLED_LayerSetMatrix) {
Test_LayerSetMatrix();
}
-TEST_F(TransactionTest_2_1, DISABLED_DeferredTransaction) {
- Test_DeferredTransaction();
-}
-
TEST_F(TransactionTest_2_1, DISABLED_SetRelativeLayer) {
Test_SetRelativeLayer();
}
@@ -1766,77 +1661,6 @@ protected:
EXPECT_TRUE(framesAreSame(referenceFrame2, Base::sFakeComposer->getLatestFrame()));
}
- // Regression test for b/37673612
- void Test_ChildrenWithParentBufferTransform() {
- {
- TransactionScope ts(*Base::sFakeComposer);
- ts.show(mChild);
- ts.setPosition(mChild, 0, 0);
- ts.setPosition(Base::mFGSurfaceControl, 0, 0);
- }
-
- // We set things up as in b/37673612 so that there is a mismatch between the buffer size and
- // the WM specified state size.
- {
- TransactionScope ts(*Base::sFakeComposer);
- ts.setSize(Base::mFGSurfaceControl, 128, 64);
- }
-
- sp<Surface> s = Base::mFGSurfaceControl->getSurface();
- auto anw = static_cast<ANativeWindow*>(s.get());
- native_window_set_buffers_transform(anw, NATIVE_WINDOW_TRANSFORM_ROT_90);
- native_window_set_buffers_dimensions(anw, 64, 128);
- fillSurfaceRGBA8(Base::mFGSurfaceControl, RED);
- Base::sFakeComposer->runVSyncAndWait();
-
- // The child should still be in the same place and not have any strange scaling as in
- // b/37673612.
- auto referenceFrame = Base::mBaseFrame;
- referenceFrame[Base::FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 128, 64};
- referenceFrame[Base::FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 64.f, 128.f};
- referenceFrame[Base::FG_LAYER].mSwapCount++;
- referenceFrame[CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 10, 10};
- EXPECT_TRUE(framesAreSame(referenceFrame, Base::sFakeComposer->getLatestFrame()));
- }
-
- void Test_Bug36858924() {
- // Destroy the child layer
- mChild.clear();
-
- // Now recreate it as hidden
- mChild = Base::mComposerClient->createSurface(String8("Child surface"), 10, 10,
- PIXEL_FORMAT_RGBA_8888,
- ISurfaceComposerClient::eHidden,
- Base::mFGSurfaceControl->getHandle());
-
- // Show the child layer in a deferred transaction
- {
- TransactionScope ts(*Base::sFakeComposer);
- ts.deferTransactionUntil_legacy(mChild, Base::mFGSurfaceControl,
- Base::mFGSurfaceControl->getSurface()
- ->getNextFrameNumber());
- ts.show(mChild);
- }
-
- // Render the foreground surface a few times
- //
- // Prior to the bugfix for b/36858924, this would usually hang while trying to fill the
- // third frame because SurfaceFlinger would never process the deferred transaction and would
- // therefore never acquire/release the first buffer
- ALOGI("Filling 1");
- fillSurfaceRGBA8(Base::mFGSurfaceControl, GREEN);
- Base::sFakeComposer->runVSyncAndWait();
- ALOGI("Filling 2");
- fillSurfaceRGBA8(Base::mFGSurfaceControl, BLUE);
- Base::sFakeComposer->runVSyncAndWait();
- ALOGI("Filling 3");
- fillSurfaceRGBA8(Base::mFGSurfaceControl, RED);
- Base::sFakeComposer->runVSyncAndWait();
- ALOGI("Filling 4");
- fillSurfaceRGBA8(Base::mFGSurfaceControl, GREEN);
- Base::sFakeComposer->runVSyncAndWait();
- }
-
sp<SurfaceControl> mChild;
};
@@ -1862,15 +1686,6 @@ TEST_F(ChildLayerTest_2_1, DISABLED_LayerAlpha) {
Test_LayerAlpha();
}
-// Regression test for b/37673612
-TEST_F(ChildLayerTest_2_1, DISABLED_ChildrenWithParentBufferTransform) {
- Test_ChildrenWithParentBufferTransform();
-}
-
-TEST_F(ChildLayerTest_2_1, DISABLED_Bug36858924) {
- Test_Bug36858924();
-}
-
template <typename FakeComposerService>
class ChildColorLayerTest : public ChildLayerTest<FakeComposerService> {
using Base = ChildLayerTest<FakeComposerService>;
@@ -1960,91 +1775,6 @@ TEST_F(ChildColorLayerTest_2_1, DISABLED_LayerAlpha) {
TEST_F(ChildColorLayerTest_2_1, DISABLED_LayerZeroAlpha) {
Test_LayerZeroAlpha();
}
-
-template <typename FakeComposerService>
-class LatchingTest : public TransactionTest<FakeComposerService> {
- using Base = TransactionTest<FakeComposerService>;
-
-protected:
- void lockAndFillFGBuffer() { fillSurfaceRGBA8(Base::mFGSurfaceControl, RED, false); }
-
- void unlockFGBuffer() {
- sp<Surface> s = Base::mFGSurfaceControl->getSurface();
- ASSERT_EQ(NO_ERROR, s->unlockAndPost());
- Base::sFakeComposer->runVSyncAndWait();
- }
-
- void completeFGResize() {
- fillSurfaceRGBA8(Base::mFGSurfaceControl, RED);
- Base::sFakeComposer->runVSyncAndWait();
- }
- void restoreInitialState() {
- TransactionScope ts(*Base::sFakeComposer);
- ts.setSize(Base::mFGSurfaceControl, 64, 64);
- ts.setPosition(Base::mFGSurfaceControl, 64, 64);
- ts.setCrop(Base::mFGSurfaceControl, Rect(0, 0, 64, 64));
- }
-
- void Test_SurfacePositionLatching() {
- // By default position can be updated even while
- // a resize is pending.
- {
- TransactionScope ts(*Base::sFakeComposer);
- ts.setSize(Base::mFGSurfaceControl, 32, 32);
- ts.setPosition(Base::mFGSurfaceControl, 100, 100);
- }
-
- // The size should not have updated as we have not provided a new buffer.
- auto referenceFrame1 = Base::mBaseFrame;
- referenceFrame1[Base::FG_LAYER].mDisplayFrame = hwc_rect_t{100, 100, 100 + 64, 100 + 64};
- EXPECT_TRUE(framesAreSame(referenceFrame1, Base::sFakeComposer->getLatestFrame()));
-
- restoreInitialState();
-
- completeFGResize();
-
- auto referenceFrame2 = Base::mBaseFrame;
- referenceFrame2[Base::FG_LAYER].mDisplayFrame = hwc_rect_t{100, 100, 100 + 32, 100 + 32};
- referenceFrame2[Base::FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 32.f, 32.f};
- referenceFrame2[Base::FG_LAYER].mSwapCount++;
- EXPECT_TRUE(framesAreSame(referenceFrame2, Base::sFakeComposer->getLatestFrame()));
- }
-
- void Test_CropLatching() {
- // Normally the crop applies immediately even while a resize is pending.
- {
- TransactionScope ts(*Base::sFakeComposer);
- ts.setSize(Base::mFGSurfaceControl, 128, 128);
- ts.setCrop(Base::mFGSurfaceControl, Rect(0, 0, 63, 63));
- }
-
- auto referenceFrame1 = Base::mBaseFrame;
- referenceFrame1[Base::FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 63, 64 + 63};
- referenceFrame1[Base::FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 63.f, 63.f};
- EXPECT_TRUE(framesAreSame(referenceFrame1, Base::sFakeComposer->getLatestFrame()));
-
- restoreInitialState();
-
- completeFGResize();
-
- auto referenceFrame2 = Base::mBaseFrame;
- referenceFrame2[Base::FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 63, 64 + 63};
- referenceFrame2[Base::FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 63.f, 63.f};
- referenceFrame2[Base::FG_LAYER].mSwapCount++;
- EXPECT_TRUE(framesAreSame(referenceFrame2, Base::sFakeComposer->getLatestFrame()));
- }
-};
-
-using LatchingTest_2_1 = LatchingTest<FakeComposerService_2_1>;
-
-TEST_F(LatchingTest_2_1, DISABLED_SurfacePositionLatching) {
- Test_SurfacePositionLatching();
-}
-
-TEST_F(LatchingTest_2_1, DISABLED_CropLatching) {
- Test_CropLatching();
-}
-
} // namespace
int main(int argc, char** argv) {
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index af7d4da478..89ffee6952 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -119,6 +119,7 @@ cc_test {
"android.hardware.power@1.1",
"android.hardware.power@1.2",
"android.hardware.power@1.3",
+ "android.hardware.power-V1-cpp",
"libcompositionengine_mocks",
"libcompositionengine",
"libframetimeline",
@@ -130,6 +131,7 @@ cc_test {
"librenderengine",
"libserviceutils",
"libtimestats",
+ "libtimestats_atoms_proto",
"libtimestats_proto",
"libtrace_proto",
"perfetto_trace_protos",
@@ -142,7 +144,6 @@ cc_test {
"android.hardware.graphics.allocator@2.0",
"android.hardware.graphics.allocator@3.0",
"android.hardware.graphics.common@1.2",
- "android.hardware.power-V1-cpp",
"libbase",
"libbinder",
"libcutils",
@@ -157,14 +158,10 @@ cc_test {
"libnativewindow",
"libprocessgroup",
"libprotobuf-cpp-lite",
- "libprotoutil",
- "libstatslog",
- "libstatssocket",
"libSurfaceFlingerProp",
"libsync",
"libui",
"libutils",
- "libstatspull",
],
header_libs: [
"android.hardware.graphics.composer@2.1-command-buffer",
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index 4e1c0c77ea..3042450f29 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -15,6 +15,7 @@
*/
// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#include "renderengine/ExternalTexture.h"
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
#pragma clang diagnostic ignored "-Wextra"
@@ -194,7 +195,7 @@ public:
sp<Fence> mClientTargetAcquireFence = Fence::NO_FENCE;
- sp<GraphicBuffer> mCaptureScreenBuffer;
+ std::shared_ptr<renderengine::ExternalTexture> mCaptureScreenBuffer;
};
template <typename LayerCase>
@@ -243,11 +244,15 @@ void CompositionTest::captureScreenComposition() {
// TODO: Eliminate expensive/real allocation if possible.
const uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN |
GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE;
- mCaptureScreenBuffer = new GraphicBuffer(renderArea->getReqWidth(), renderArea->getReqHeight(),
- HAL_PIXEL_FORMAT_RGBA_8888, 1, usage, "screenshot");
+ mCaptureScreenBuffer = std::make_shared<
+ renderengine::ExternalTexture>(new GraphicBuffer(renderArea->getReqWidth(),
+ renderArea->getReqHeight(),
+ HAL_PIXEL_FORMAT_RGBA_8888, 1, usage,
+ "screenshot"),
+ *mRenderEngine, true);
status_t result =
- mFlinger.renderScreenImplLocked(*renderArea, traverseLayers, mCaptureScreenBuffer.get(),
+ mFlinger.renderScreenImplLocked(*renderArea, traverseLayers, mCaptureScreenBuffer,
forSystem, regionSampling);
EXPECT_EQ(NO_ERROR, result);
@@ -340,8 +345,8 @@ struct BaseDisplayVariant {
EXPECT_CALL(*test->mRenderEngine, drawLayers)
.WillRepeatedly([](const renderengine::DisplaySettings& displaySettings,
const std::vector<const renderengine::LayerSettings*>&,
- const sp<GraphicBuffer>&, const bool, base::unique_fd&&,
- base::unique_fd*) -> status_t {
+ const std::shared_ptr<renderengine::ExternalTexture>&,
+ const bool, base::unique_fd&&, base::unique_fd*) -> status_t {
EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
displaySettings.physicalDisplay);
@@ -389,8 +394,8 @@ struct BaseDisplayVariant {
EXPECT_CALL(*test->mRenderEngine, drawLayers)
.WillRepeatedly([](const renderengine::DisplaySettings& displaySettings,
const std::vector<const renderengine::LayerSettings*>&,
- const sp<GraphicBuffer>&, const bool, base::unique_fd&&,
- base::unique_fd*) -> status_t {
+ const std::shared_ptr<renderengine::ExternalTexture>&,
+ const bool, base::unique_fd&&, base::unique_fd*) -> status_t {
EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
displaySettings.physicalDisplay);
@@ -625,8 +630,8 @@ struct BaseLayerProperties {
EXPECT_CALL(*test->mRenderEngine, drawLayers)
.WillOnce([](const renderengine::DisplaySettings& displaySettings,
const std::vector<const renderengine::LayerSettings*>& layerSettings,
- const sp<GraphicBuffer>&, const bool, base::unique_fd&&,
- base::unique_fd*) -> status_t {
+ const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
+ base::unique_fd&&, base::unique_fd*) -> status_t {
EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
displaySettings.physicalDisplay);
@@ -674,8 +679,8 @@ struct BaseLayerProperties {
EXPECT_CALL(*test->mRenderEngine, drawLayers)
.WillOnce([](const renderengine::DisplaySettings& displaySettings,
const std::vector<const renderengine::LayerSettings*>& layerSettings,
- const sp<GraphicBuffer>&, const bool, base::unique_fd&&,
- base::unique_fd*) -> status_t {
+ const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
+ base::unique_fd&&, base::unique_fd*) -> status_t {
EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
displaySettings.physicalDisplay);
@@ -751,8 +756,8 @@ struct CommonSecureLayerProperties : public BaseLayerProperties<LayerProperties>
EXPECT_CALL(*test->mRenderEngine, drawLayers)
.WillOnce([](const renderengine::DisplaySettings& displaySettings,
const std::vector<const renderengine::LayerSettings*>& layerSettings,
- const sp<GraphicBuffer>&, const bool, base::unique_fd&&,
- base::unique_fd*) -> status_t {
+ const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
+ base::unique_fd&&, base::unique_fd*) -> status_t {
EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
displaySettings.physicalDisplay);
diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
index 7cc0032bc8..b4a1481e9c 100644
--- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
+++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
@@ -44,7 +44,7 @@ namespace {
constexpr PhysicalDisplayId INTERNAL_DISPLAY_ID(111);
constexpr PhysicalDisplayId EXTERNAL_DISPLAY_ID(222);
constexpr PhysicalDisplayId DISPLAY_ID_64BIT(0xabcd12349876fedcULL);
-
+constexpr std::chrono::duration VSYNC_PERIOD(16ms);
class MockVSyncSource : public VSyncSource {
public:
const char* getName() const override { return "test"; }
@@ -166,11 +166,14 @@ void EventThreadTest::createThread(std::unique_ptr<VSyncSource> source) {
mThrottleVsyncCallRecorder.getInvocable()(expectedVsyncTimestamp, uid);
return (uid == mThrottledConnectionUid);
};
+ const auto getVsyncPeriod = [](uid_t uid) {
+ return VSYNC_PERIOD.count();
+ };
mThread = std::make_unique<impl::EventThread>(std::move(source),
/*tokenManager=*/nullptr,
mInterceptVSyncCallRecorder.getInvocable(),
- throttleVsync);
+ throttleVsync, getVsyncPeriod);
// EventThread should register itself as VSyncSource callback.
mCallback = expectVSyncSetCallbackCallReceived();
diff --git a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
index 982252f0be..8a3f561487 100644
--- a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
+++ b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
@@ -68,7 +68,7 @@ public:
void SetUp() override {
mTimeStats = std::make_shared<mock::TimeStats>();
mFrameTimeline = std::make_unique<impl::FrameTimeline>(mTimeStats, kSurfaceFlingerPid,
- kTestThresholds, kHwcDuration);
+ kTestThresholds);
mFrameTimeline->registerDataSource();
mTokenManager = &mFrameTimeline->mTokenManager;
mTraceCookieCounter = &mFrameTimeline->mTraceCookieCounter;
@@ -163,7 +163,6 @@ public:
static constexpr JankClassificationThresholds kTestThresholds{kPresentThreshold,
kDeadlineThreshold,
kStartThreshold};
- static constexpr nsecs_t kHwcDuration = std::chrono::nanoseconds(3ns).count();
};
static const std::string sLayerNameOne = "layer1";
@@ -483,7 +482,6 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_doesNotReportForInvalidTokens) {
TEST_F(FrameTimelineTest, presentFenceSignaled_reportsLongSfCpu) {
Fps refreshRate = Fps::fromPeriodNsecs(11);
- // Deadline delta is 2ms because, sf's adjusted deadline is 60 - composerTime(3) = 57ms.
EXPECT_CALL(*mTimeStats,
incrementJankyFrames(
TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne,
@@ -504,7 +502,34 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsLongSfCpu) {
mFrameTimeline->addSurfaceFrame(surfaceFrame1);
presentFence1->signalForTest(70);
- mFrameTimeline->setSfPresent(59, presentFence1);
+ mFrameTimeline->setSfPresent(62, presentFence1);
+}
+
+TEST_F(FrameTimelineTest, presentFenceSignaled_reportsLongSfGpu) {
+ Fps refreshRate = Fps::fromPeriodNsecs(11);
+ EXPECT_CALL(*mTimeStats,
+ incrementJankyFrames(
+ TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne,
+ sLayerNameOne,
+ JankType::SurfaceFlingerGpuDeadlineMissed, 4, 10,
+ 0}));
+ auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+ auto gpuFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+ int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({10, 20, 60});
+ int64_t sfToken1 = mTokenManager->generateTokenForPredictions({52, 60, 60});
+
+ auto surfaceFrame1 =
+ mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
+ sUidOne, sLayerIdOne, sLayerNameOne,
+ sLayerNameOne, /*isBuffer*/ true);
+ mFrameTimeline->setSfWakeUp(sfToken1, 52, refreshRate);
+ surfaceFrame1->setAcquireFenceTime(20);
+ surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
+ mFrameTimeline->addSurfaceFrame(surfaceFrame1);
+ gpuFence1->signalForTest(64);
+ presentFence1->signalForTest(70);
+
+ mFrameTimeline->setSfPresent(59, presentFence1, gpuFence1);
}
TEST_F(FrameTimelineTest, presentFenceSignaled_reportsDisplayMiss) {
@@ -512,7 +537,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsDisplayMiss) {
EXPECT_CALL(*mTimeStats,
incrementJankyFrames(TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne,
sLayerNameOne, JankType::DisplayHAL,
- -1, 0, 0}));
+ -4, 0, 0}));
auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({10, 20, 60});
@@ -536,7 +561,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsAppMiss) {
EXPECT_CALL(*mTimeStats,
incrementJankyFrames(TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne,
sLayerNameOne,
- JankType::AppDeadlineMissed, -1, 0,
+ JankType::AppDeadlineMissed, -4, 0,
25}));
auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({10, 20, 60});
@@ -563,7 +588,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsSfScheduling) {
incrementJankyFrames(TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne,
sLayerNameOne,
JankType::SurfaceFlingerScheduling,
- -1, 0, -10}));
+ -4, 0, -10}));
auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({40, 60, 92});
int64_t sfToken1 = mTokenManager->generateTokenForPredictions({52, 60, 60});
@@ -588,7 +613,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsSfPredictionError) {
EXPECT_CALL(*mTimeStats,
incrementJankyFrames(TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne,
sLayerNameOne,
- JankType::PredictionError, -1, 5,
+ JankType::PredictionError, -4, 5,
0}));
auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({30, 40, 60});
@@ -614,7 +639,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsAppBufferStuffing) {
EXPECT_CALL(*mTimeStats,
incrementJankyFrames(TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne,
sLayerNameOne,
- JankType::BufferStuffing, -1, 0,
+ JankType::BufferStuffing, -4, 0,
0}));
auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({30, 40, 58});
@@ -642,7 +667,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsAppMissWithRenderRate) {
EXPECT_CALL(*mTimeStats,
incrementJankyFrames(
TimeStats::JankyFramesInfo{refreshRate, renderRate, sUidOne, sLayerNameOne,
- JankType::AppDeadlineMissed, -1, 0, 25}));
+ JankType::AppDeadlineMissed, -4, 0, 25}));
auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({10, 20, 60});
int64_t sfToken1 = mTokenManager->generateTokenForPredictions({82, 90, 90});
@@ -671,7 +696,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_displayFramePredictionExpiredPres
incrementJankyFrames(
TimeStats::JankyFramesInfo{refreshRate, renderRate, sUidOne, sLayerNameOne,
JankType::Unknown | JankType::AppDeadlineMissed,
- -1, -1, 25}));
+ 0, 0, 25}));
auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({10, 20, 60});
int64_t sfToken1 = mTokenManager->generateTokenForPredictions({82, 90, 90});
@@ -1322,6 +1347,81 @@ TEST_F(FrameTimelineTest, traceSurfaceFrame_predictionExpiredDoesNotTraceExpecte
validateTraceEvent(actualSurfaceFrameEnd, protoActualSurfaceFrameEnd);
}
+TEST_F(FrameTimelineTest, traceSurfaceFrame_predictionExpiredDroppedFramesTracedProperly) {
+ auto tracingSession = getTracingSessionForTest();
+ auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+
+ tracingSession->StartBlocking();
+ constexpr nsecs_t appStartTime = std::chrono::nanoseconds(10ms).count();
+ constexpr nsecs_t appEndTime = std::chrono::nanoseconds(20ms).count();
+ constexpr nsecs_t appPresentTime = std::chrono::nanoseconds(30ms).count();
+ int64_t surfaceFrameToken =
+ mTokenManager->generateTokenForPredictions({appStartTime, appEndTime, appPresentTime});
+
+ // Flush the token so that it would expire
+ flushTokens(systemTime() + maxTokenRetentionTime);
+ auto surfaceFrame1 =
+ mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, /*inputEventId*/ 0},
+ sPidOne, sUidOne, sLayerIdOne, sLayerNameOne,
+ sLayerNameOne, /*isBuffer*/ true);
+
+ constexpr nsecs_t sfStartTime = std::chrono::nanoseconds(22ms).count();
+ constexpr nsecs_t sfEndTime = std::chrono::nanoseconds(30ms).count();
+ constexpr nsecs_t sfPresentTime = std::chrono::nanoseconds(30ms).count();
+ int64_t displayFrameToken =
+ mTokenManager->generateTokenForPredictions({sfStartTime, sfEndTime, sfPresentTime});
+
+ // First 2 cookies will be used by the DisplayFrame
+ int64_t traceCookie = snoopCurrentTraceCookie() + 2;
+
+ auto protoActualSurfaceFrameStart =
+ createProtoActualSurfaceFrameStart(traceCookie + 1, surfaceFrameToken,
+ displayFrameToken, sPidOne, sLayerNameOne,
+ FrameTimelineEvent::PRESENT_DROPPED, false, false,
+ FrameTimelineEvent::JANK_NONE,
+ FrameTimelineEvent::PREDICTION_EXPIRED);
+ auto protoActualSurfaceFrameEnd = createProtoFrameEnd(traceCookie + 1);
+
+ // Set up the display frame
+ mFrameTimeline->setSfWakeUp(displayFrameToken, sfStartTime, Fps::fromPeriodNsecs(11));
+ surfaceFrame1->setDropTime(sfStartTime);
+ surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Dropped);
+ mFrameTimeline->addSurfaceFrame(surfaceFrame1);
+ mFrameTimeline->setSfPresent(sfEndTime, presentFence1);
+ presentFence1->signalForTest(sfPresentTime);
+
+ addEmptyDisplayFrame();
+ flushTrace();
+ tracingSession->StopBlocking();
+
+ auto packets = readFrameTimelinePacketsBlocking(tracingSession.get());
+ // Display Frame 4 packets + SurfaceFrame 2 packets
+ ASSERT_EQ(packets.size(), 6u);
+
+ // Packet - 4 : ActualSurfaceFrameStart
+ const auto& packet4 = packets[4];
+ ASSERT_TRUE(packet4.has_timestamp());
+ EXPECT_EQ(packet4.timestamp(),
+ static_cast<uint64_t>(sfStartTime - SurfaceFrame::kPredictionExpiredStartTimeDelta));
+ ASSERT_TRUE(packet4.has_frame_timeline_event());
+
+ const auto& event4 = packet4.frame_timeline_event();
+ ASSERT_TRUE(event4.has_actual_surface_frame_start());
+ const auto& actualSurfaceFrameStart = event4.actual_surface_frame_start();
+ validateTraceEvent(actualSurfaceFrameStart, protoActualSurfaceFrameStart);
+
+ // Packet - 5 : FrameEnd (ActualSurfaceFrame)
+ const auto& packet5 = packets[5];
+ ASSERT_TRUE(packet5.has_timestamp());
+ EXPECT_EQ(packet5.timestamp(), static_cast<uint64_t>(sfStartTime));
+ ASSERT_TRUE(packet5.has_frame_timeline_event());
+
+ const auto& event5 = packet5.frame_timeline_event();
+ ASSERT_TRUE(event5.has_frame_end());
+ const auto& actualSurfaceFrameEnd = event5.frame_end();
+ validateTraceEvent(actualSurfaceFrameEnd, protoActualSurfaceFrameEnd);
+}
+
// Tests for Jank classification
TEST_F(FrameTimelineTest, jankClassification_presentOnTimeDoesNotClassify) {
// Layer specific increment
@@ -1458,24 +1558,47 @@ TEST_F(FrameTimelineTest, jankClassification_displayFrameLateFinishEarlyPresent)
}
TEST_F(FrameTimelineTest, jankClassification_displayFrameLateFinishLatePresent) {
+ /*
+ * Case 1 - cpu time > vsync period but combined time > deadline > deadline -> cpudeadlinemissed
+ * Case 2 - cpu time < vsync period but combined time > deadline -> gpudeadlinemissed
+ */
auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+ auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+ auto gpuFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+ auto gpuFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
int64_t sfToken1 = mTokenManager->generateTokenForPredictions({22, 26, 40});
+ int64_t sfToken2 = mTokenManager->generateTokenForPredictions({52, 60, 60});
+ // case 1 - cpu time = 33 - 12 = 21, vsync period = 11
mFrameTimeline->setSfWakeUp(sfToken1, 12, Fps::fromPeriodNsecs(11));
- mFrameTimeline->setSfPresent(36, presentFence1);
- auto displayFrame = getDisplayFrame(0);
+ mFrameTimeline->setSfPresent(33, presentFence1, gpuFence1);
+ auto displayFrame0 = getDisplayFrame(0);
+ gpuFence1->signalForTest(36);
presentFence1->signalForTest(52);
// Fences haven't been flushed yet, so it should be 0
- EXPECT_EQ(displayFrame->getActuals().presentTime, 0);
+ EXPECT_EQ(displayFrame0->getActuals().presentTime, 0);
+
+ // case 2 - cpu time = 56 - 52 = 4, vsync period = 11
+ mFrameTimeline->setSfWakeUp(sfToken2, 52, Fps::fromPeriodNsecs(11));
+ mFrameTimeline->setSfPresent(56, presentFence2, gpuFence2);
+ auto displayFrame1 = getDisplayFrame(1);
+ gpuFence2->signalForTest(66);
+ presentFence2->signalForTest(71);
+
+ EXPECT_EQ(displayFrame1->getActuals().presentTime, 0);
+ // Fences have flushed for first displayFrame, so the present timestamps should be updated
+ EXPECT_EQ(displayFrame0->getActuals().presentTime, 52);
+ EXPECT_EQ(displayFrame0->getFramePresentMetadata(), FramePresentMetadata::LatePresent);
+ EXPECT_EQ(displayFrame0->getFrameReadyMetadata(), FrameReadyMetadata::LateFinish);
+ EXPECT_EQ(displayFrame0->getJankType(), JankType::SurfaceFlingerCpuDeadlineMissed);
addEmptyDisplayFrame();
- displayFrame = getDisplayFrame(0);
- // Fences have flushed, so the present timestamps should be updated
- EXPECT_EQ(displayFrame->getActuals().presentTime, 52);
- EXPECT_EQ(displayFrame->getFramePresentMetadata(), FramePresentMetadata::LatePresent);
- EXPECT_EQ(displayFrame->getFrameReadyMetadata(), FrameReadyMetadata::LateFinish);
- EXPECT_EQ(displayFrame->getJankType(), JankType::SurfaceFlingerCpuDeadlineMissed);
+ // Fences have flushed for second displayFrame, so the present timestamps should be updated
+ EXPECT_EQ(displayFrame1->getActuals().presentTime, 71);
+ EXPECT_EQ(displayFrame1->getFramePresentMetadata(), FramePresentMetadata::LatePresent);
+ EXPECT_EQ(displayFrame1->getFrameReadyMetadata(), FrameReadyMetadata::LateFinish);
+ EXPECT_EQ(displayFrame1->getJankType(), JankType::SurfaceFlingerGpuDeadlineMissed);
}
TEST_F(FrameTimelineTest, jankClassification_displayFrameLateStartLateFinishLatePresent) {
@@ -1562,7 +1685,7 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameOnTimeFinishEarlyPresen
EXPECT_CALL(*mTimeStats,
incrementJankyFrames(
TimeStats::JankyFramesInfo{Fps::fromPeriodNsecs(11), std::nullopt, sUidOne,
- sLayerNameOne, JankType::PredictionError, 0, 5,
+ sLayerNameOne, JankType::PredictionError, -3, 5,
0}));
addEmptyDisplayFrame();
@@ -1642,7 +1765,7 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameOnTimeFinishLatePresent
EXPECT_CALL(*mTimeStats,
incrementJankyFrames(
TimeStats::JankyFramesInfo{Fps::fromPeriodNsecs(11), std::nullopt, sUidOne,
- sLayerNameOne, JankType::PredictionError, 0, 5,
+ sLayerNameOne, JankType::PredictionError, -3, 5,
0}));
addEmptyDisplayFrame();
diff --git a/services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp b/services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp
index cfbb3f5e9f..a1f0588fc7 100644
--- a/services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp
@@ -19,6 +19,7 @@
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <utils/Log.h>
+#include <utils/Timers.h>
#include "AsyncCallRecorder.h"
#include "Scheduler/OneShotTimer.h"
@@ -28,21 +29,22 @@ using namespace std::chrono_literals;
namespace android {
namespace scheduler {
+class FakeClock : public OneShotTimer::Clock {
+public:
+ virtual ~FakeClock() = default;
+ std::chrono::steady_clock::time_point now() const override { return mNow; }
+
+ void advanceTime(std::chrono::nanoseconds delta) { mNow += delta; }
+
+private:
+ std::chrono::steady_clock::time_point mNow;
+};
+
class OneShotTimerTest : public testing::Test {
protected:
OneShotTimerTest() = default;
~OneShotTimerTest() override = default;
- // This timeout should be used when a 3ms callback is expected.
- // While the tests typically request a callback after 3ms, the scheduler
- // does not always cooperate, at it can take significantly longer (observed
- // 30ms).
- static constexpr auto waitTimeForExpected3msCallback = 100ms;
-
- // This timeout should be used when an 3ms callback is not expected.
- // Note that there can be false-negatives if the callback happens later.
- static constexpr auto waitTimeForUnexpected3msCallback = 6ms;
-
AsyncCallRecorder<void (*)()> mResetTimerCallback;
AsyncCallRecorder<void (*)()> mExpiredTimerCallback;
@@ -56,162 +58,179 @@ protected:
namespace {
TEST_F(OneShotTimerTest, createAndDestroyTest) {
+ FakeClock* clock = new FakeClock();
mIdleTimer = std::make_unique<scheduler::OneShotTimer>(
- "TestTimer", 3ms, [] {}, [] {});
+ "TestTimer", 3ms, [] {}, [] {}, std::unique_ptr<FakeClock>(clock));
}
TEST_F(OneShotTimerTest, startStopTest) {
- mIdleTimer = std::make_unique<scheduler::OneShotTimer>("TestTimer", 30ms,
+ FakeClock* clock = new FakeClock();
+ mIdleTimer = std::make_unique<scheduler::OneShotTimer>("TestTimer", 1ms,
mResetTimerCallback.getInvocable(),
- mExpiredTimerCallback.getInvocable());
- auto startTime = std::chrono::steady_clock::now();
+ mExpiredTimerCallback.getInvocable(),
+ std::unique_ptr<FakeClock>(clock));
mIdleTimer->start();
EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
- // The idle timer fires after 30ms, so there should be no callback within
- // 25ms (waiting for a callback for the full 30ms would be problematic).
- bool callbackCalled = mExpiredTimerCallback.waitForCall(25ms).has_value();
- // Under ideal conditions there should be no event. But occasionally
- // it is possible that the wait just prior takes more than 30ms, and
- // a callback is observed. We check the elapsed time since before the OneShotTimer
- // thread was started as a sanity check to not have a flakey test.
- EXPECT_FALSE(callbackCalled && std::chrono::steady_clock::now() - startTime < 30ms);
-
- std::this_thread::sleep_for(std::chrono::milliseconds(25));
- EXPECT_FALSE(mResetTimerCallback.waitForCall().has_value());
+ EXPECT_FALSE(mExpiredTimerCallback.waitForUnexpectedCall().has_value());
+
+ clock->advanceTime(2ms);
+ EXPECT_TRUE(mExpiredTimerCallback.waitForCall().has_value());
+
+ clock->advanceTime(2ms);
+ EXPECT_FALSE(mExpiredTimerCallback.waitForUnexpectedCall().has_value());
+ EXPECT_FALSE(mResetTimerCallback.waitForUnexpectedCall().has_value());
mIdleTimer->stop();
}
TEST_F(OneShotTimerTest, resetTest) {
- mIdleTimer = std::make_unique<scheduler::OneShotTimer>("TestTimer", 20ms,
+ FakeClock* clock = new FakeClock();
+ mIdleTimer = std::make_unique<scheduler::OneShotTimer>("TestTimer", 1ms,
mResetTimerCallback.getInvocable(),
- mExpiredTimerCallback.getInvocable());
+ mExpiredTimerCallback.getInvocable(),
+ std::unique_ptr<FakeClock>(clock));
+
mIdleTimer->start();
EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
- // Observe any event that happens in about 25ms. We don't care if one was
- // observed or not.
- mExpiredTimerCallback.waitForCall(25ms).has_value();
+ EXPECT_FALSE(mExpiredTimerCallback.waitForUnexpectedCall().has_value());
+ clock->advanceTime(2ms);
+ EXPECT_TRUE(mExpiredTimerCallback.waitForCall().has_value());
mIdleTimer->reset();
EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
- // There may have been a race with the reset. Clear any callbacks we
- // received right afterwards.
- clearPendingCallbacks();
- // A single callback should be generated after 30ms
- EXPECT_TRUE(
- mExpiredTimerCallback.waitForCall(waitTimeForExpected3msCallback + 30ms).has_value());
- // After one event, it should be idle, and not generate another.
- EXPECT_FALSE(
- mExpiredTimerCallback.waitForCall(waitTimeForUnexpected3msCallback * 10).has_value());
- mIdleTimer->stop();
- // Final quick check that no more callback were observed.
- EXPECT_FALSE(mExpiredTimerCallback.waitForCall(0ms).has_value());
- EXPECT_FALSE(mResetTimerCallback.waitForCall(0ms).has_value());
+ clock->advanceTime(2ms);
+ EXPECT_TRUE(mExpiredTimerCallback.waitForCall().has_value());
+
+ clock->advanceTime(2ms);
+ EXPECT_FALSE(mExpiredTimerCallback.waitForUnexpectedCall().has_value());
+ EXPECT_FALSE(mResetTimerCallback.waitForUnexpectedCall().has_value());
}
TEST_F(OneShotTimerTest, resetBackToBackTest) {
- mIdleTimer = std::make_unique<scheduler::OneShotTimer>("TestTimer", 20ms,
+ FakeClock* clock = new FakeClock();
+ mIdleTimer = std::make_unique<scheduler::OneShotTimer>("TestTimer", 1ms,
mResetTimerCallback.getInvocable(),
- mExpiredTimerCallback.getInvocable());
+ mExpiredTimerCallback.getInvocable(),
+ std::unique_ptr<FakeClock>(clock));
mIdleTimer->start();
EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
mIdleTimer->reset();
- EXPECT_FALSE(mResetTimerCallback.waitForCall(1ms).has_value());
- EXPECT_FALSE(mExpiredTimerCallback.waitForCall(waitTimeForUnexpected3msCallback).has_value());
+ EXPECT_FALSE(mResetTimerCallback.waitForUnexpectedCall().has_value());
+ EXPECT_FALSE(mExpiredTimerCallback.waitForUnexpectedCall().has_value());
mIdleTimer->reset();
- EXPECT_FALSE(mResetTimerCallback.waitForCall(1ms).has_value());
- EXPECT_FALSE(mExpiredTimerCallback.waitForCall(waitTimeForUnexpected3msCallback).has_value());
+ EXPECT_FALSE(mResetTimerCallback.waitForUnexpectedCall().has_value());
+ EXPECT_FALSE(mExpiredTimerCallback.waitForUnexpectedCall().has_value());
mIdleTimer->reset();
- EXPECT_FALSE(mResetTimerCallback.waitForCall(1ms).has_value());
- EXPECT_FALSE(mExpiredTimerCallback.waitForCall(waitTimeForUnexpected3msCallback).has_value());
+ EXPECT_FALSE(mResetTimerCallback.waitForUnexpectedCall().has_value());
+ EXPECT_FALSE(mExpiredTimerCallback.waitForUnexpectedCall().has_value());
mIdleTimer->reset();
- EXPECT_FALSE(mResetTimerCallback.waitForCall(1ms).has_value());
- EXPECT_FALSE(mExpiredTimerCallback.waitForCall(waitTimeForUnexpected3msCallback).has_value());
+ EXPECT_FALSE(mResetTimerCallback.waitForUnexpectedCall().has_value());
+
+ clock->advanceTime(2ms);
+ EXPECT_TRUE(mExpiredTimerCallback.waitForCall().has_value());
- // A single callback should be generated after 30ms
- EXPECT_TRUE(
- mExpiredTimerCallback.waitForCall(waitTimeForExpected3msCallback + 30ms).has_value());
mIdleTimer->stop();
+ clock->advanceTime(2ms);
// Final quick check that no more callback were observed.
- EXPECT_FALSE(mExpiredTimerCallback.waitForCall(0ms).has_value());
- EXPECT_FALSE(mResetTimerCallback.waitForCall(0ms).has_value());
+ EXPECT_FALSE(mExpiredTimerCallback.waitForUnexpectedCall().has_value());
+ EXPECT_FALSE(mResetTimerCallback.waitForUnexpectedCall().has_value());
}
TEST_F(OneShotTimerTest, startNotCalledTest) {
- mIdleTimer = std::make_unique<scheduler::OneShotTimer>("TestTimer", 3ms,
+ FakeClock* clock = new FakeClock();
+ mIdleTimer = std::make_unique<scheduler::OneShotTimer>("TestTimer", 1ms,
mResetTimerCallback.getInvocable(),
- mExpiredTimerCallback.getInvocable());
+ mExpiredTimerCallback.getInvocable(),
+ std::unique_ptr<FakeClock>(clock));
// The start hasn't happened, so the callback does not happen.
- EXPECT_FALSE(mExpiredTimerCallback.waitForCall(waitTimeForUnexpected3msCallback).has_value());
- EXPECT_FALSE(mResetTimerCallback.waitForCall().has_value());
+ EXPECT_FALSE(mExpiredTimerCallback.waitForUnexpectedCall().has_value());
+ EXPECT_FALSE(mResetTimerCallback.waitForUnexpectedCall().has_value());
mIdleTimer->stop();
+ clock->advanceTime(2ms);
// Final quick check that no more callback were observed.
- EXPECT_FALSE(mExpiredTimerCallback.waitForCall(0ms).has_value());
- EXPECT_FALSE(mResetTimerCallback.waitForCall(0ms).has_value());
+ EXPECT_FALSE(mExpiredTimerCallback.waitForUnexpectedCall().has_value());
+ EXPECT_FALSE(mResetTimerCallback.waitForUnexpectedCall().has_value());
}
TEST_F(OneShotTimerTest, idleTimerIdlesTest) {
- mIdleTimer = std::make_unique<scheduler::OneShotTimer>("TestTimer", 3ms,
+ FakeClock* clock = new FakeClock();
+ mIdleTimer = std::make_unique<scheduler::OneShotTimer>("TestTimer", 1ms,
mResetTimerCallback.getInvocable(),
- mExpiredTimerCallback.getInvocable());
+ mExpiredTimerCallback.getInvocable(),
+ std::unique_ptr<FakeClock>(clock));
mIdleTimer->start();
EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
+ clock->advanceTime(2ms);
+ EXPECT_TRUE(mExpiredTimerCallback.waitForCall().has_value());
+
+ EXPECT_FALSE(mExpiredTimerCallback.waitForUnexpectedCall().has_value());
+ EXPECT_FALSE(mResetTimerCallback.waitForUnexpectedCall().has_value());
- // A callback should be generated after 3ms
- EXPECT_TRUE(mExpiredTimerCallback.waitForCall(waitTimeForExpected3msCallback).has_value());
- // After one event, it should be idle, and not generate another.
- EXPECT_FALSE(mExpiredTimerCallback.waitForCall(waitTimeForUnexpected3msCallback).has_value());
- // Once reset, it should generate another
mIdleTimer->reset();
EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
- EXPECT_TRUE(mExpiredTimerCallback.waitForCall(waitTimeForExpected3msCallback).has_value());
+ clock->advanceTime(2ms);
+ EXPECT_TRUE(mExpiredTimerCallback.waitForCall().has_value());
mIdleTimer->stop();
+ clock->advanceTime(2ms);
// Final quick check that no more callback were observed.
- EXPECT_FALSE(mExpiredTimerCallback.waitForCall(0ms).has_value());
- EXPECT_FALSE(mResetTimerCallback.waitForCall(0ms).has_value());
+ EXPECT_FALSE(mExpiredTimerCallback.waitForUnexpectedCall().has_value());
+ EXPECT_FALSE(mResetTimerCallback.waitForUnexpectedCall().has_value());
}
TEST_F(OneShotTimerTest, timeoutCallbackExecutionTest) {
- mIdleTimer = std::make_unique<scheduler::OneShotTimer>("TestTimer", 3ms,
+ FakeClock* clock = new FakeClock();
+ mIdleTimer = std::make_unique<scheduler::OneShotTimer>("TestTimer", 1ms,
mResetTimerCallback.getInvocable(),
- mExpiredTimerCallback.getInvocable());
+ mExpiredTimerCallback.getInvocable(),
+ std::unique_ptr<FakeClock>(clock));
mIdleTimer->start();
EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
- EXPECT_TRUE(mExpiredTimerCallback.waitForCall(waitTimeForExpected3msCallback).has_value());
+
+ clock->advanceTime(2ms);
+ EXPECT_TRUE(mExpiredTimerCallback.waitForCall().has_value());
mIdleTimer->stop();
+ clock->advanceTime(2ms);
+ EXPECT_FALSE(mExpiredTimerCallback.waitForUnexpectedCall().has_value());
+ EXPECT_FALSE(mResetTimerCallback.waitForUnexpectedCall().has_value());
}
TEST_F(OneShotTimerTest, noCallbacksAfterStopAndResetTest) {
- mIdleTimer = std::make_unique<scheduler::OneShotTimer>("TestTimer", 3ms,
+ FakeClock* clock = new FakeClock();
+ mIdleTimer = std::make_unique<scheduler::OneShotTimer>("TestTimer", 1ms,
mResetTimerCallback.getInvocable(),
- mExpiredTimerCallback.getInvocable());
+ mExpiredTimerCallback.getInvocable(),
+ std::unique_ptr<FakeClock>(clock));
mIdleTimer->start();
EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
- EXPECT_TRUE(mExpiredTimerCallback.waitForCall(waitTimeForExpected3msCallback).has_value());
+ clock->advanceTime(2ms);
+ EXPECT_TRUE(mExpiredTimerCallback.waitForCall().has_value());
mIdleTimer->stop();
- clearPendingCallbacks();
mIdleTimer->reset();
- EXPECT_FALSE(mExpiredTimerCallback.waitForCall(waitTimeForUnexpected3msCallback).has_value());
- EXPECT_FALSE(mResetTimerCallback.waitForCall().has_value());
+ clock->advanceTime(2ms);
+ EXPECT_FALSE(mExpiredTimerCallback.waitForUnexpectedCall().has_value());
+ EXPECT_FALSE(mResetTimerCallback.waitForUnexpectedCall().has_value());
}
TEST_F(OneShotTimerTest, noCallbacksAfterStopTest) {
- mIdleTimer = std::make_unique<scheduler::OneShotTimer>("TestTimer", 3ms,
+ FakeClock* clock = new FakeClock();
+ mIdleTimer = std::make_unique<scheduler::OneShotTimer>("TestTimer", 1ms,
mResetTimerCallback.getInvocable(),
- mExpiredTimerCallback.getInvocable());
+ mExpiredTimerCallback.getInvocable(),
+ std::unique_ptr<FakeClock>(clock));
mIdleTimer->start();
EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
+ EXPECT_FALSE(mExpiredTimerCallback.waitForUnexpectedCall().has_value());
mIdleTimer->stop();
- clearPendingCallbacks();
mIdleTimer->reset();
+ clock->advanceTime(2ms);
// No more idle events should be observed
- EXPECT_FALSE(mExpiredTimerCallback.waitForCall(waitTimeForUnexpected3msCallback).has_value());
- EXPECT_FALSE(mResetTimerCallback.waitForCall().has_value());
+ EXPECT_FALSE(mExpiredTimerCallback.waitForUnexpectedCall().has_value());
+ EXPECT_FALSE(mResetTimerCallback.waitForUnexpectedCall().has_value());
}
} // namespace
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp
index abecd4b45b..9c6ad06e1d 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp
@@ -118,11 +118,8 @@ void RefreshRateSelectionTest::setParent(Layer* child, Layer* parent) {
}
void RefreshRateSelectionTest::commitTransaction(Layer* layer) {
- layer->pushPendingState();
auto c = layer->getCurrentState();
- if (layer->applyPendingStates(&c)) {
- layer->commitTransaction(c);
- }
+ layer->commitTransaction(c);
}
void RefreshRateSelectionTest::setupScheduler() {
diff --git a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
index 0bb7e31194..c088ddc971 100644
--- a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
@@ -153,11 +153,8 @@ void SetFrameRateTest::removeChild(sp<Layer> layer, sp<Layer> child) {
void SetFrameRateTest::commitTransaction() {
for (auto layer : mLayers) {
- layer->pushPendingState();
auto c = layer->getCurrentState();
- if (layer->applyPendingStates(&c)) {
- layer->commitTransaction(c);
- }
+ layer->commitTransaction(c);
}
}
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 63baf7dee2..d004b9d9eb 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -352,8 +352,8 @@ public:
auto renderScreenImplLocked(const RenderArea& renderArea,
SurfaceFlinger::TraverseLayersFunction traverseLayers,
- const sp<GraphicBuffer>& buffer, bool forSystem,
- bool regionSampling) {
+ const std::shared_ptr<renderengine::ExternalTexture>& buffer,
+ bool forSystem, bool regionSampling) {
ScreenCaptureResults captureResults;
return mFlinger->renderScreenImplLocked(renderArea, traverseLayers, buffer, forSystem,
regionSampling, false /* grayscale */,
diff --git a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
index c1f0c4ef03..188ea758d4 100644
--- a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
@@ -23,10 +23,10 @@
#define LOG_TAG "LibSurfaceFlingerUnittests"
#include <TimeStats/TimeStats.h>
-#include <android/util/ProtoOutputStream.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <log/log.h>
+#include <timestatsatomsproto/TimeStatsAtomsProtoHeader.h>
#include <utils/String16.h>
#include <utils/Vector.h>
@@ -156,44 +156,8 @@ public:
}
std::mt19937 mRandomEngine = std::mt19937(std::random_device()());
-
- class FakeStatsEventDelegate : public impl::TimeStats::StatsEventDelegate {
- public:
- FakeStatsEventDelegate() = default;
- ~FakeStatsEventDelegate() override = default;
-
- struct AStatsEvent* addStatsEventToPullData(AStatsEventList*) override {
- return mEvent;
- }
- void setStatsPullAtomCallback(int32_t atom_tag, AStatsManager_PullAtomMetadata*,
- AStatsManager_PullAtomCallback callback,
- void* cookie) override {
- mAtomTags.push_back(atom_tag);
- mCallback = callback;
- mCookie = cookie;
- }
-
- AStatsManager_PullAtomCallbackReturn makePullAtomCallback(int32_t atom_tag, void* cookie) {
- return (*mCallback)(atom_tag, nullptr, cookie);
- }
-
- MOCK_METHOD1(clearStatsPullAtomCallback, void(int32_t));
- MOCK_METHOD2(statsEventSetAtomId, void(AStatsEvent*, uint32_t));
- MOCK_METHOD2(statsEventWriteInt32, void(AStatsEvent*, int32_t));
- MOCK_METHOD2(statsEventWriteInt64, void(AStatsEvent*, int64_t));
- MOCK_METHOD2(statsEventWriteString8, void(AStatsEvent*, const char*));
- MOCK_METHOD3(statsEventWriteByteArray, void(AStatsEvent*, const uint8_t*, size_t));
- MOCK_METHOD1(statsEventBuild, void(AStatsEvent*));
-
- AStatsEvent* mEvent = AStatsEvent_obtain();
- std::vector<int32_t> mAtomTags;
- AStatsManager_PullAtomCallback mCallback = nullptr;
- void* mCookie = nullptr;
- };
- FakeStatsEventDelegate* mDelegate = new FakeStatsEventDelegate;
std::unique_ptr<TimeStats> mTimeStats =
- std::make_unique<impl::TimeStats>(std::unique_ptr<FakeStatsEventDelegate>(mDelegate),
- std::nullopt, std::nullopt);
+ std::make_unique<impl::TimeStats>(std::nullopt, std::nullopt);
};
std::string TimeStatsTest::inputCommand(InputCommand cmd, bool useProto) {
@@ -278,21 +242,6 @@ TEST_F(TimeStatsTest, disabledByDefault) {
ASSERT_FALSE(mTimeStats->isEnabled());
}
-TEST_F(TimeStatsTest, setsCallbacksAfterBoot) {
- mTimeStats->onBootFinished();
- EXPECT_THAT(mDelegate->mAtomTags,
- UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
- android::util::SURFACEFLINGER_STATS_LAYER_INFO));
-}
-
-TEST_F(TimeStatsTest, clearsCallbacksOnDestruction) {
- EXPECT_CALL(*mDelegate,
- clearStatsPullAtomCallback(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO));
- EXPECT_CALL(*mDelegate,
- clearStatsPullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO));
- mTimeStats.reset();
-}
-
TEST_F(TimeStatsTest, canEnableAndDisableTimeStats) {
EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
ASSERT_TRUE(mTimeStats->isEnabled());
@@ -1012,61 +961,49 @@ TEST_F(TimeStatsTest, noInfInAverageFPS) {
}
namespace {
-std::string buildExpectedHistogramBytestring(const std::vector<int32_t>& times,
- const std::vector<int32_t>& frameCounts) {
- util::ProtoOutputStream proto;
+FrameTimingHistogram buildExpectedHistogram(const std::vector<int32_t>& times,
+ const std::vector<int32_t>& frameCounts) {
+ FrameTimingHistogram histogram;
for (int i = 0; i < times.size(); i++) {
ALOGE("Writing time: %d", times[i]);
- proto.write(util::FIELD_TYPE_INT32 | util::FIELD_COUNT_REPEATED | 1 /* field id */,
- (int32_t)times[i]);
+ histogram.add_time_millis_buckets(times[i]);
ALOGE("Writing count: %d", frameCounts[i]);
- proto.write(util::FIELD_TYPE_INT64 | util::FIELD_COUNT_REPEATED | 2 /* field id */,
- (int64_t)frameCounts[i]);
- }
- std::string byteString;
- proto.serializeToString(&byteString);
- return byteString;
-}
-
-std::string frameRateVoteToProtoByteString(
- float refreshRate,
- TimeStats::SetFrameRateVote::FrameRateCompatibility frameRateCompatibility,
- TimeStats::SetFrameRateVote::Seamlessness seamlessness) {
- util::ProtoOutputStream proto;
- proto.write(android::util::FIELD_TYPE_FLOAT | 1 /* field id */, refreshRate);
- proto.write(android::util::FIELD_TYPE_ENUM | 2 /* field id */,
- static_cast<int>(frameRateCompatibility));
- proto.write(android::util::FIELD_TYPE_ENUM | 3 /* field id */, static_cast<int>(seamlessness));
-
- std::string byteString;
- proto.serializeToString(&byteString);
- return byteString;
-}
-
-std::string dumpByteStringHex(const std::string& str) {
- std::stringstream ss;
- ss << std::hex;
- for (const char& c : str) {
- ss << (int)c << " ";
+ histogram.add_frame_counts((int64_t)frameCounts[i]);
}
-
- return ss.str();
+ return histogram;
}
-
} // namespace
-MATCHER_P2(BytesEq, bytes, size, "") {
- std::string expected;
- expected.append((const char*)bytes, size);
- std::string actual;
- actual.append((const char*)arg, size);
+MATCHER_P(HistogramEq, expected, "") {
+ *result_listener << "Histograms are not equal! \n";
- *result_listener << "Bytes are not equal! \n";
- *result_listener << "size: " << size << "\n";
- *result_listener << "expected: " << dumpByteStringHex(expected).c_str() << "\n";
- *result_listener << "actual: " << dumpByteStringHex(actual).c_str() << "\n";
+ if (arg.time_millis_buckets_size() != expected.time_millis_buckets_size()) {
+ *result_listener << "Time millis bucket are different sizes. Expected: "
+ << expected.time_millis_buckets_size() << ". Actual "
+ << arg.time_millis_buckets_size();
+ return false;
+ }
+ if (arg.frame_counts_size() != expected.frame_counts_size()) {
+ *result_listener << "Frame counts are different sizes. Expected: "
+ << expected.frame_counts_size() << ". Actual " << arg.frame_counts_size();
+ return false;
+ }
- return expected == actual;
+ for (int i = 0; i < expected.time_millis_buckets_size(); i++) {
+ if (arg.time_millis_buckets(i) != expected.time_millis_buckets(i)) {
+ *result_listener << "time_millis_bucket[" << i
+ << "] is different. Expected: " << expected.time_millis_buckets(i)
+ << ". Actual: " << arg.time_millis_buckets(i);
+ return false;
+ }
+ if (arg.frame_counts(i) != expected.frame_counts(i)) {
+ *result_listener << "frame_counts[" << i
+ << "] is different. Expected: " << expected.frame_counts(i)
+ << ". Actual: " << arg.frame_counts(i);
+ return false;
+ }
+ }
+ return true;
}
TEST_F(TimeStatsTest, globalStatsCallback) {
@@ -1075,7 +1012,6 @@ TEST_F(TimeStatsTest, globalStatsCallback) {
constexpr size_t CLIENT_COMPOSITION_FRAMES = 3;
constexpr size_t DISPLAY_EVENT_CONNECTIONS = 14;
- mTimeStats->onBootFinished();
EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
for (size_t i = 0; i < TOTAL_FRAMES; i++) {
@@ -1115,71 +1051,39 @@ TEST_F(TimeStatsTest, globalStatsCallback) {
JankType::AppDeadlineMissed | JankType::BufferStuffing, 1, 2,
3});
mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+ JankType::BufferStuffing, 1, 2, 3});
+ mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
JankType::None, 1, 2, 3});
- EXPECT_THAT(mDelegate->mAtomTags,
- UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
- android::util::SURFACEFLINGER_STATS_LAYER_INFO));
- EXPECT_NE(nullptr, mDelegate->mCallback);
- EXPECT_EQ(mTimeStats.get(), mDelegate->mCookie);
-
- std::string expectedFrameDuration = buildExpectedHistogramBytestring({2}, {1});
- std::string expectedRenderEngineTiming = buildExpectedHistogramBytestring({1, 2}, {1, 1});
- std::string expectedEmptyHistogram = buildExpectedHistogramBytestring({}, {});
- std::string expectedSfDeadlineMissed = buildExpectedHistogramBytestring({1}, {7});
- std::string expectedSfPredictionErrors = buildExpectedHistogramBytestring({2}, {7});
-
- {
- InSequence seq;
- EXPECT_CALL(*mDelegate,
- statsEventSetAtomId(mDelegate->mEvent,
- android::util::SURFACEFLINGER_STATS_GLOBAL_INFO));
- EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, TOTAL_FRAMES));
- EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, MISSED_FRAMES));
- EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, CLIENT_COMPOSITION_FRAMES));
- EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, _));
- EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, 2));
- EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, DISPLAY_EVENT_CONNECTIONS));
- EXPECT_CALL(*mDelegate,
- statsEventWriteByteArray(mDelegate->mEvent,
- BytesEq((const uint8_t*)expectedFrameDuration.c_str(),
- expectedFrameDuration.size()),
- expectedFrameDuration.size()));
- EXPECT_CALL(*mDelegate,
- statsEventWriteByteArray(mDelegate->mEvent,
- BytesEq((const uint8_t*)
- expectedRenderEngineTiming.c_str(),
- expectedRenderEngineTiming.size()),
- expectedRenderEngineTiming.size()));
- EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 8));
- EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 7));
- EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 1));
- EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 1));
- EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 1));
- EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 2));
- EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 1));
- EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 1));
- EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 1));
- EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, REFRESH_RATE_BUCKET_0));
- EXPECT_CALL(*mDelegate,
- statsEventWriteByteArray(mDelegate->mEvent,
- BytesEq((const uint8_t*)
- expectedSfDeadlineMissed.c_str(),
- expectedSfDeadlineMissed.size()),
- expectedSfDeadlineMissed.size()));
- EXPECT_CALL(*mDelegate,
- statsEventWriteByteArray(mDelegate->mEvent,
- BytesEq((const uint8_t*)
- expectedSfPredictionErrors.c_str(),
- expectedSfPredictionErrors.size()),
- expectedSfPredictionErrors.size()));
- EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, RENDER_RATE_BUCKET_0));
-
- EXPECT_CALL(*mDelegate, statsEventBuild(mDelegate->mEvent));
- }
- EXPECT_EQ(AStatsManager_PULL_SUCCESS,
- mDelegate->makePullAtomCallback(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
- mDelegate->mCookie));
+ std::string pulledData;
+ EXPECT_TRUE(mTimeStats->onPullAtom(10062 /*SURFACEFLINGER_STATS_GLOBAL_INFO*/, &pulledData));
+
+ android::surfaceflinger::SurfaceflingerStatsGlobalInfoWrapper atomList;
+ ASSERT_TRUE(atomList.ParseFromString(pulledData));
+ ASSERT_EQ(atomList.atom_size(), 1);
+ const android::surfaceflinger::SurfaceflingerStatsGlobalInfo& atom = atomList.atom(0);
+
+ EXPECT_EQ(atom.total_frames(), TOTAL_FRAMES);
+ EXPECT_EQ(atom.missed_frames(), MISSED_FRAMES);
+ EXPECT_EQ(atom.client_composition_frames(), CLIENT_COMPOSITION_FRAMES);
+ // Display on millis is not checked.
+ EXPECT_EQ(atom.animation_millis(), 2);
+ EXPECT_EQ(atom.event_connection_count(), DISPLAY_EVENT_CONNECTIONS);
+ EXPECT_THAT(atom.frame_duration(), HistogramEq(buildExpectedHistogram({2}, {1})));
+ EXPECT_THAT(atom.render_engine_timing(), HistogramEq(buildExpectedHistogram({1, 2}, {1, 1})));
+ EXPECT_EQ(atom.total_timeline_frames(), 9);
+ EXPECT_EQ(atom.total_janky_frames(), 7);
+ EXPECT_EQ(atom.total_janky_frames_with_long_cpu(), 1);
+ EXPECT_EQ(atom.total_janky_frames_with_long_gpu(), 1);
+ EXPECT_EQ(atom.total_janky_frames_sf_unattributed(), 1);
+ EXPECT_EQ(atom.total_janky_frames_app_unattributed(), 2);
+ EXPECT_EQ(atom.total_janky_frames_sf_scheduling(), 1);
+ EXPECT_EQ(atom.total_jank_frames_sf_prediction_error(), 1);
+ EXPECT_EQ(atom.total_jank_frames_app_buffer_stuffing(), 2);
+ EXPECT_EQ(atom.display_refresh_rate_bucket(), REFRESH_RATE_BUCKET_0);
+ EXPECT_THAT(atom.sf_deadline_misses(), HistogramEq(buildExpectedHistogram({1}, {7})));
+ EXPECT_THAT(atom.sf_prediction_errors(), HistogramEq(buildExpectedHistogram({2}, {7})));
+ EXPECT_EQ(atom.render_rate_bucket(), RENDER_RATE_BUCKET_0);
SFTimeStatsGlobalProto globalProto;
ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
@@ -1194,7 +1098,7 @@ TEST_F(TimeStatsTest, globalStatsCallback) {
const std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING));
std::string expectedResult = "totalTimelineFrames = " + std::to_string(0);
EXPECT_THAT(result, HasSubstr(expectedResult));
- expectedResult = "totalTimelineFrames = " + std::to_string(8);
+ expectedResult = "totalTimelineFrames = " + std::to_string(9);
EXPECT_THAT(result, HasSubstr(expectedResult));
expectedResult = "jankyFrames = " + std::to_string(0);
EXPECT_THAT(result, HasSubstr(expectedResult));
@@ -1226,7 +1130,7 @@ TEST_F(TimeStatsTest, globalStatsCallback) {
EXPECT_THAT(result, HasSubstr(expectedResult));
expectedResult = "appBufferStuffingJankyFrames = " + std::to_string(0);
EXPECT_THAT(result, HasSubstr(expectedResult));
- expectedResult = "appBufferStuffingJankyFrames = " + std::to_string(1);
+ expectedResult = "appBufferStuffingJankyFrames = " + std::to_string(2);
EXPECT_THAT(result, HasSubstr(expectedResult));
}
@@ -1235,8 +1139,6 @@ TEST_F(TimeStatsTest, layerStatsCallback_pullsAllAndClears) {
constexpr size_t BAD_DESIRED_PRESENT_FRAMES = 3;
EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
- mTimeStats->onBootFinished();
-
insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
for (size_t i = 0; i < LATE_ACQUIRE_FRAMES; i++) {
mTimeStats->incrementLatchSkipped(LAYER_ID_0, TimeStats::LatchSkipReason::LateAcquire);
@@ -1270,99 +1172,42 @@ TEST_F(TimeStatsTest, layerStatsCallback_pullsAllAndClears) {
mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
JankType::None, 1, 2, 3});
- EXPECT_THAT(mDelegate->mAtomTags,
- UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
- android::util::SURFACEFLINGER_STATS_LAYER_INFO));
- EXPECT_NE(nullptr, mDelegate->mCallback);
- EXPECT_EQ(mTimeStats.get(), mDelegate->mCookie);
-
- std::string expectedPresentToPresent = buildExpectedHistogramBytestring({1}, {1});
- std::string expectedPostToPresent = buildExpectedHistogramBytestring({4}, {1});
- std::string expectedAcquireToPresent = buildExpectedHistogramBytestring({3}, {1});
- std::string expectedLatchToPresent = buildExpectedHistogramBytestring({2}, {1});
- std::string expectedDesiredToPresent = buildExpectedHistogramBytestring({1}, {1});
- std::string expectedPostToAcquire = buildExpectedHistogramBytestring({1}, {1});
- std::string expectedFrameRateOverride =
- frameRateVoteToProtoByteString(frameRate60.frameRate,
- frameRate60.frameRateCompatibility,
- frameRate60.seamlessness);
- std::string expectedAppDeadlineMissed = buildExpectedHistogramBytestring({3, 2}, {4, 3});
- {
- InSequence seq;
- EXPECT_CALL(*mDelegate,
- statsEventSetAtomId(mDelegate->mEvent,
- android::util::SURFACEFLINGER_STATS_LAYER_INFO));
- EXPECT_CALL(*mDelegate,
- statsEventWriteString8(mDelegate->mEvent,
- StrEq(genLayerName(LAYER_ID_0).c_str())));
- EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, 1));
- EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, 0));
- EXPECT_CALL(*mDelegate,
- statsEventWriteByteArray(mDelegate->mEvent,
- BytesEq((const uint8_t*)
- expectedPresentToPresent.c_str(),
- expectedPresentToPresent.size()),
- expectedPresentToPresent.size()));
- EXPECT_CALL(*mDelegate,
- statsEventWriteByteArray(mDelegate->mEvent,
- BytesEq((const uint8_t*)expectedPostToPresent.c_str(),
- expectedPostToPresent.size()),
- expectedPostToPresent.size()));
- EXPECT_CALL(*mDelegate,
- statsEventWriteByteArray(mDelegate->mEvent,
- BytesEq((const uint8_t*)
- expectedAcquireToPresent.c_str(),
- expectedAcquireToPresent.size()),
- expectedAcquireToPresent.size()));
- EXPECT_CALL(*mDelegate,
- statsEventWriteByteArray(mDelegate->mEvent,
- BytesEq((const uint8_t*)expectedLatchToPresent.c_str(),
- expectedLatchToPresent.size()),
- expectedLatchToPresent.size()));
- EXPECT_CALL(*mDelegate,
- statsEventWriteByteArray(mDelegate->mEvent,
- BytesEq((const uint8_t*)
- expectedDesiredToPresent.c_str(),
- expectedDesiredToPresent.size()),
- expectedDesiredToPresent.size()));
- EXPECT_CALL(*mDelegate,
- statsEventWriteByteArray(mDelegate->mEvent,
- BytesEq((const uint8_t*)expectedPostToAcquire.c_str(),
- expectedPostToAcquire.size()),
- expectedPostToAcquire.size()));
- EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, LATE_ACQUIRE_FRAMES));
- EXPECT_CALL(*mDelegate,
- statsEventWriteInt64(mDelegate->mEvent, BAD_DESIRED_PRESENT_FRAMES));
- EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, UID_0));
- EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 8));
- EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 7));
- EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 1));
- EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 1));
- EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 1));
- EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 2));
- EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 1));
- EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 1));
- EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 1));
- EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, REFRESH_RATE_BUCKET_0));
- EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, RENDER_RATE_BUCKET_0));
- EXPECT_CALL(*mDelegate,
- statsEventWriteByteArray(mDelegate->mEvent,
- BytesEq((const uint8_t*)
- expectedFrameRateOverride.c_str(),
- expectedFrameRateOverride.size()),
- expectedFrameRateOverride.size()));
- EXPECT_CALL(*mDelegate,
- statsEventWriteByteArray(mDelegate->mEvent,
- BytesEq((const uint8_t*)
- expectedAppDeadlineMissed.c_str(),
- expectedAppDeadlineMissed.size()),
- expectedAppDeadlineMissed.size()));
-
- EXPECT_CALL(*mDelegate, statsEventBuild(mDelegate->mEvent));
- }
- EXPECT_EQ(AStatsManager_PULL_SUCCESS,
- mDelegate->makePullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO,
- mDelegate->mCookie));
+ std::string pulledData;
+ EXPECT_TRUE(mTimeStats->onPullAtom(10063 /*SURFACEFLINGER_STATS_LAYER_INFO*/, &pulledData));
+
+ android::surfaceflinger::SurfaceflingerStatsLayerInfoWrapper atomList;
+ ASSERT_TRUE(atomList.ParseFromString(pulledData));
+ ASSERT_EQ(atomList.atom_size(), 1);
+ const android::surfaceflinger::SurfaceflingerStatsLayerInfo& atom = atomList.atom(0);
+
+ EXPECT_EQ(atom.layer_name(), genLayerName(LAYER_ID_0));
+ EXPECT_EQ(atom.total_frames(), 1);
+ EXPECT_EQ(atom.dropped_frames(), 0);
+ EXPECT_THAT(atom.present_to_present(), HistogramEq(buildExpectedHistogram({1}, {1})));
+ EXPECT_THAT(atom.post_to_present(), HistogramEq(buildExpectedHistogram({4}, {1})));
+ EXPECT_THAT(atom.acquire_to_present(), HistogramEq(buildExpectedHistogram({3}, {1})));
+ EXPECT_THAT(atom.latch_to_present(), HistogramEq(buildExpectedHistogram({2}, {1})));
+ EXPECT_THAT(atom.desired_to_present(), HistogramEq(buildExpectedHistogram({1}, {1})));
+ EXPECT_THAT(atom.post_to_acquire(), HistogramEq(buildExpectedHistogram({1}, {1})));
+ EXPECT_EQ(atom.late_acquire_frames(), LATE_ACQUIRE_FRAMES);
+ EXPECT_EQ(atom.bad_desired_present_frames(), BAD_DESIRED_PRESENT_FRAMES);
+ EXPECT_EQ(atom.uid(), UID_0);
+ EXPECT_EQ(atom.total_timeline_frames(), 8);
+ EXPECT_EQ(atom.total_janky_frames(), 7);
+ EXPECT_EQ(atom.total_janky_frames_with_long_cpu(), 1);
+ EXPECT_EQ(atom.total_janky_frames_with_long_gpu(), 1);
+ EXPECT_EQ(atom.total_janky_frames_sf_unattributed(), 1);
+ EXPECT_EQ(atom.total_janky_frames_app_unattributed(), 2);
+ EXPECT_EQ(atom.total_janky_frames_sf_scheduling(), 1);
+ EXPECT_EQ(atom.total_jank_frames_sf_prediction_error(), 1);
+ EXPECT_EQ(atom.total_jank_frames_app_buffer_stuffing(), 1);
+ EXPECT_EQ(atom.display_refresh_rate_bucket(), REFRESH_RATE_BUCKET_0);
+ EXPECT_EQ(atom.render_rate_bucket(), RENDER_RATE_BUCKET_0);
+ EXPECT_THAT(atom.set_frame_rate_vote().frame_rate(), testing::FloatEq(frameRate60.frameRate));
+ EXPECT_EQ((int)atom.set_frame_rate_vote().frame_rate_compatibility(),
+ (int)frameRate60.frameRateCompatibility);
+ EXPECT_EQ((int)atom.set_frame_rate_vote().seamlessness(), (int)frameRate60.seamlessness);
+ EXPECT_THAT(atom.app_deadline_misses(), HistogramEq(buildExpectedHistogram({3, 2}, {4, 3})));
SFTimeStatsGlobalProto globalProto;
ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
@@ -1398,37 +1243,26 @@ TEST_F(TimeStatsTest, layerStatsCallback_pullsAllAndClears) {
TEST_F(TimeStatsTest, layerStatsCallback_pullsMultipleLayers) {
EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
- mTimeStats->onBootFinished();
-
insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000);
insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_1, 1, 2000000);
insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_1, 2, 3000000);
- EXPECT_THAT(mDelegate->mAtomTags,
- UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
- android::util::SURFACEFLINGER_STATS_LAYER_INFO));
- EXPECT_NE(nullptr, mDelegate->mCallback);
- EXPECT_EQ(mTimeStats.get(), mDelegate->mCookie);
-
- EXPECT_CALL(*mDelegate,
- statsEventSetAtomId(mDelegate->mEvent,
- android::util::SURFACEFLINGER_STATS_LAYER_INFO))
- .Times(2);
- EXPECT_CALL(*mDelegate,
- statsEventWriteString8(mDelegate->mEvent, StrEq(genLayerName(LAYER_ID_0).c_str())));
- EXPECT_CALL(*mDelegate,
- statsEventWriteString8(mDelegate->mEvent, StrEq(genLayerName(LAYER_ID_1).c_str())));
- EXPECT_EQ(AStatsManager_PULL_SUCCESS,
- mDelegate->makePullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO,
- mDelegate->mCookie));
+ std::string pulledData;
+ EXPECT_TRUE(mTimeStats->onPullAtom(10063 /*SURFACEFLINGER_STATS_LAYER_INFO*/, &pulledData));
+
+ android::surfaceflinger::SurfaceflingerStatsLayerInfoWrapper atomList;
+ ASSERT_TRUE(atomList.ParseFromString(pulledData));
+ ASSERT_EQ(atomList.atom_size(), 2);
+ std::vector<std::string> actualLayerNames = {atomList.atom(0).layer_name(),
+ atomList.atom(1).layer_name()};
+ EXPECT_THAT(actualLayerNames,
+ UnorderedElementsAre(genLayerName(LAYER_ID_0), genLayerName(LAYER_ID_1)));
}
TEST_F(TimeStatsTest, layerStatsCallback_pullsMultipleBuckets) {
EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
- mTimeStats->onBootFinished();
-
insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000);
insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 3, 4000000);
@@ -1438,102 +1272,53 @@ TEST_F(TimeStatsTest, layerStatsCallback_pullsMultipleBuckets) {
mTimeStats->setPowerMode(PowerMode::ON);
mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(3000000));
mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(5000000));
- EXPECT_THAT(mDelegate->mAtomTags,
- UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
- android::util::SURFACEFLINGER_STATS_LAYER_INFO));
- EXPECT_NE(nullptr, mDelegate->mCallback);
- EXPECT_EQ(mTimeStats.get(), mDelegate->mCookie);
-
- EXPECT_THAT(mDelegate->mAtomTags,
- UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
- android::util::SURFACEFLINGER_STATS_LAYER_INFO));
- std::string expectedPresentToPresent = buildExpectedHistogramBytestring({1, 2}, {2, 1});
- {
- InSequence seq;
- EXPECT_CALL(*mDelegate,
- statsEventWriteByteArray(mDelegate->mEvent,
- BytesEq((const uint8_t*)
- expectedPresentToPresent.c_str(),
- expectedPresentToPresent.size()),
- expectedPresentToPresent.size()));
- EXPECT_CALL(*mDelegate, statsEventWriteByteArray(mDelegate->mEvent, _, _))
- .Times(AnyNumber());
- }
- EXPECT_EQ(AStatsManager_PULL_SUCCESS,
- mDelegate->makePullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO,
- mDelegate->mCookie));
+
+ std::string pulledData;
+ EXPECT_TRUE(mTimeStats->onPullAtom(10063 /*SURFACEFLINGER_STATS_LAYER_INFO*/, &pulledData));
+
+ android::surfaceflinger::SurfaceflingerStatsLayerInfoWrapper atomList;
+ ASSERT_TRUE(atomList.ParseFromString(pulledData));
+ ASSERT_EQ(atomList.atom_size(), 1);
+ const android::surfaceflinger::SurfaceflingerStatsLayerInfo& atom = atomList.atom(0);
+ EXPECT_THAT(atom.present_to_present(), HistogramEq(buildExpectedHistogram({1, 2}, {2, 1})));
}
TEST_F(TimeStatsTest, layerStatsCallback_limitsHistogramBuckets) {
- mDelegate = new FakeStatsEventDelegate;
- mTimeStats =
- std::make_unique<impl::TimeStats>(std::unique_ptr<FakeStatsEventDelegate>(mDelegate),
- std::nullopt, 1);
+ mTimeStats = std::make_unique<impl::TimeStats>(std::nullopt, 1);
EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
- mTimeStats->onBootFinished();
-
insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000);
insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 3, 4000000);
insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 4, 5000000);
- EXPECT_THAT(mDelegate->mAtomTags,
- UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
- android::util::SURFACEFLINGER_STATS_LAYER_INFO));
- EXPECT_NE(nullptr, mDelegate->mCallback);
- EXPECT_EQ(mTimeStats.get(), mDelegate->mCookie);
-
- EXPECT_THAT(mDelegate->mAtomTags,
- UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
- android::util::SURFACEFLINGER_STATS_LAYER_INFO));
- std::string expectedPresentToPresent = buildExpectedHistogramBytestring({1}, {2});
- {
- InSequence seq;
- EXPECT_CALL(*mDelegate,
- statsEventWriteByteArray(mDelegate->mEvent,
- BytesEq((const uint8_t*)
- expectedPresentToPresent.c_str(),
- expectedPresentToPresent.size()),
- expectedPresentToPresent.size()));
- EXPECT_CALL(*mDelegate, statsEventWriteByteArray(mDelegate->mEvent, _, _))
- .Times(AnyNumber());
- }
- EXPECT_EQ(AStatsManager_PULL_SUCCESS,
- mDelegate->makePullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO,
- mDelegate->mCookie));
+ std::string pulledData;
+ EXPECT_TRUE(mTimeStats->onPullAtom(10063 /*SURFACEFLINGER_STATS_LAYER_INFO*/, &pulledData));
+
+ android::surfaceflinger::SurfaceflingerStatsLayerInfoWrapper atomList;
+ ASSERT_TRUE(atomList.ParseFromString(pulledData));
+ ASSERT_EQ(atomList.atom_size(), 1);
+ const android::surfaceflinger::SurfaceflingerStatsLayerInfo& atom = atomList.atom(0);
+ EXPECT_THAT(atom.present_to_present(), HistogramEq(buildExpectedHistogram({1}, {2})));
}
TEST_F(TimeStatsTest, layerStatsCallback_limitsLayers) {
- mDelegate = new FakeStatsEventDelegate;
- mTimeStats =
- std::make_unique<impl::TimeStats>(std::unique_ptr<FakeStatsEventDelegate>(mDelegate), 1,
- std::nullopt);
+ mTimeStats = std::make_unique<impl::TimeStats>(1, std::nullopt);
EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
- mTimeStats->onBootFinished();
-
insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000);
insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_1, 1, 2000000);
insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_1, 2, 3000000);
insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_1, 4, 5000000);
- EXPECT_THAT(mDelegate->mAtomTags,
- UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
- android::util::SURFACEFLINGER_STATS_LAYER_INFO));
- EXPECT_NE(nullptr, mDelegate->mCallback);
- EXPECT_EQ(mTimeStats.get(), mDelegate->mCookie);
-
- EXPECT_CALL(*mDelegate,
- statsEventSetAtomId(mDelegate->mEvent,
- android::util::SURFACEFLINGER_STATS_LAYER_INFO))
- .Times(1);
- EXPECT_CALL(*mDelegate,
- statsEventWriteString8(mDelegate->mEvent, StrEq(genLayerName(LAYER_ID_1).c_str())));
- EXPECT_EQ(AStatsManager_PULL_SUCCESS,
- mDelegate->makePullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO,
- mDelegate->mCookie));
+ std::string pulledData;
+ EXPECT_TRUE(mTimeStats->onPullAtom(10063 /*SURFACEFLINGER_STATS_LAYER_INFO*/, &pulledData));
+
+ android::surfaceflinger::SurfaceflingerStatsLayerInfoWrapper atomList;
+ ASSERT_TRUE(atomList.ParseFromString(pulledData));
+ ASSERT_EQ(atomList.atom_size(), 1);
+ EXPECT_EQ(atomList.atom(0).layer_name(), genLayerName(LAYER_ID_1));
}
TEST_F(TimeStatsTest, canSurviveMonkey) {
diff --git a/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp b/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp
index b5ef0a1334..25001d3890 100644
--- a/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp
@@ -21,6 +21,8 @@
#include <gtest/gtest.h>
#include <gui/SurfaceComposerClient.h>
#include <log/log.h>
+#include <renderengine/ExternalTexture.h>
+#include <renderengine/mock/RenderEngine.h>
#include <utils/String8.h>
#include "TestableSurfaceFlinger.h"
@@ -60,11 +62,8 @@ public:
}
void commitTransaction(Layer* layer) {
- layer->pushPendingState();
auto c = layer->getCurrentState();
- if (layer->applyPendingStates(&c)) {
- layer->commitTransaction(c);
- }
+ layer->commitTransaction(c);
}
void setupScheduler() {
@@ -102,6 +101,7 @@ public:
TestableSurfaceFlinger mFlinger;
Hwc2::mock::Composer* mComposer = nullptr;
+ renderengine::mock::RenderEngine mRenderEngine;
FenceToFenceTimeMap fenceFactory;
client_cache_t mClientCache;
@@ -109,9 +109,12 @@ public:
sp<BufferStateLayer> layer = createBufferStateLayer();
sp<Fence> fence(new Fence());
- sp<GraphicBuffer> buffer{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)};
+ const auto buffer = std::make_shared<
+ renderengine::ExternalTexture>(new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888,
+ 1, 0),
+ mRenderEngine, false);
int32_t layerId = layer->getSequence();
- uint64_t bufferId = buffer->getId();
+ uint64_t bufferId = buffer->getBuffer()->getId();
uint64_t frameNumber = 5;
nsecs_t dequeueTime = 10;
nsecs_t postTime = 20;
@@ -151,4 +154,4 @@ TEST_F(TransactionFrameTracerTest, BLASTTransactionSendsFrameTracerEvents) {
BLASTTransactionSendsFrameTracerEvents();
}
-} // namespace android \ No newline at end of file
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp b/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp
index c75538f476..b7917aa00e 100644
--- a/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp
@@ -21,6 +21,8 @@
#include <gtest/gtest.h>
#include <gui/SurfaceComposerClient.h>
#include <log/log.h>
+#include <renderengine/ExternalTexture.h>
+#include <renderengine/mock/RenderEngine.h>
#include <utils/String8.h>
#include "TestableSurfaceFlinger.h"
@@ -60,13 +62,8 @@ public:
}
void commitTransaction(Layer* layer) {
- layer->pushPendingState();
- // After pushing the state, the currentState should not store any BufferlessSurfaceFrames
- EXPECT_EQ(0u, layer->mCurrentState.bufferlessSurfaceFramesTX.size());
auto c = layer->getCurrentState();
- if (layer->applyPendingStates(&c)) {
- layer->commitTransaction(c);
- }
+ layer->commitTransaction(c);
}
void setupScheduler() {
@@ -104,6 +101,7 @@ public:
TestableSurfaceFlinger mFlinger;
Hwc2::mock::Composer* mComposer = nullptr;
+ renderengine::mock::RenderEngine mRenderEngine;
FenceToFenceTimeMap fenceFactory;
client_cache_t mClientCache;
@@ -124,7 +122,10 @@ public:
sp<BufferStateLayer> layer = createBufferStateLayer();
sp<Fence> fence(new Fence());
auto acquireFence = fenceFactory.createFenceTimeForTest(fence);
- sp<GraphicBuffer> buffer{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)};
+ const auto buffer = std::make_shared<
+ renderengine::ExternalTexture>(new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888,
+ 1, 0),
+ mRenderEngine, false);
layer->setBuffer(buffer, fence, 10, 20, false, mClientCache, 1, std::nullopt,
{/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */);
acquireFence->signalForTest(12);
@@ -149,7 +150,10 @@ public:
sp<Fence> fence1(new Fence());
auto acquireFence1 = fenceFactory.createFenceTimeForTest(fence1);
- sp<GraphicBuffer> buffer1{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)};
+ const auto buffer1 = std::make_shared<
+ renderengine::ExternalTexture>(new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888,
+ 1, 0),
+ mRenderEngine, false);
layer->setBuffer(buffer1, fence1, 10, 20, false, mClientCache, 1, std::nullopt,
{/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */);
EXPECT_EQ(0u, layer->mCurrentState.bufferlessSurfaceFramesTX.size());
@@ -158,7 +162,10 @@ public:
sp<Fence> fence2(new Fence());
auto acquireFence2 = fenceFactory.createFenceTimeForTest(fence2);
- sp<GraphicBuffer> buffer2{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)};
+ const auto buffer2 = std::make_shared<
+ renderengine::ExternalTexture>(new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888,
+ 1, 0),
+ mRenderEngine, false);
nsecs_t start = systemTime();
layer->setBuffer(buffer2, fence2, 10, 20, false, mClientCache, 1, std::nullopt,
{/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */);
@@ -196,8 +203,10 @@ public:
sp<Fence> fence(new Fence());
auto acquireFence = fenceFactory.createFenceTimeForTest(fence);
- sp<GraphicBuffer> buffer{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)};
-
+ const auto buffer = std::make_shared<
+ renderengine::ExternalTexture>(new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888,
+ 1, 0),
+ mRenderEngine, false);
layer->setBuffer(buffer, fence, 10, 20, false, mClientCache, 1, std::nullopt,
{/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */);
acquireFence->signalForTest(12);
@@ -222,8 +231,10 @@ public:
sp<BufferStateLayer> layer = createBufferStateLayer();
sp<Fence> fence(new Fence());
auto acquireFence = fenceFactory.createFenceTimeForTest(fence);
- sp<GraphicBuffer> buffer{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)};
-
+ const auto buffer = std::make_shared<
+ renderengine::ExternalTexture>(new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888,
+ 1, 0),
+ mRenderEngine, false);
layer->setBuffer(buffer, fence, 10, 20, false, mClientCache, 1, std::nullopt,
{/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */);
EXPECT_EQ(0u, layer->mCurrentState.bufferlessSurfaceFramesTX.size());
@@ -252,8 +263,10 @@ public:
sp<Fence> fence(new Fence());
auto acquireFence = fenceFactory.createFenceTimeForTest(fence);
- sp<GraphicBuffer> buffer{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)};
-
+ const auto buffer = std::make_shared<
+ renderengine::ExternalTexture>(new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888,
+ 1, 0),
+ mRenderEngine, false);
layer->setBuffer(buffer, fence, 10, 20, false, mClientCache, 1, std::nullopt,
{/*vsyncId*/ 3, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */);
EXPECT_EQ(2u, layer->mCurrentState.bufferlessSurfaceFramesTX.size());
@@ -283,75 +296,15 @@ public:
EXPECT_EQ(PresentState::Presented, bufferSurfaceFrameTX->getPresentState());
}
- void MergePendingStates_BufferlessSurfaceFramesWithoutOverlappingToken() {
- sp<BufferStateLayer> layer = createBufferStateLayer();
- layer->setFrameTimelineVsyncForBufferlessTransaction({/*vsyncId*/ 1, /*inputEventId*/ 0},
- 10);
- EXPECT_EQ(1u, layer->mCurrentState.bufferlessSurfaceFramesTX.size());
- ASSERT_EQ(nullptr, layer->mCurrentState.bufferSurfaceFrameTX);
- const auto bufferlessSurfaceFrame1 =
- layer->mCurrentState.bufferlessSurfaceFramesTX.at(/*token*/ 1);
-
- layer->pushPendingState();
- EXPECT_EQ(0u, layer->mCurrentState.bufferlessSurfaceFramesTX.size());
-
- layer->setFrameTimelineVsyncForBufferlessTransaction({/*vsyncId*/ 2, /*inputEventId*/ 0},
- 12);
- EXPECT_EQ(1u, layer->mCurrentState.bufferlessSurfaceFramesTX.size());
- ASSERT_EQ(nullptr, layer->mCurrentState.bufferSurfaceFrameTX);
- const auto bufferlessSurfaceFrame2 =
- layer->mCurrentState.bufferlessSurfaceFramesTX.at(/*token*/ 2);
-
- commitTransaction(layer.get());
-
- EXPECT_EQ(1, bufferlessSurfaceFrame1->getToken());
- EXPECT_EQ(false, bufferlessSurfaceFrame1->getIsBuffer());
- EXPECT_EQ(PresentState::Presented, bufferlessSurfaceFrame1->getPresentState());
- EXPECT_EQ(10, bufferlessSurfaceFrame1->getActuals().endTime);
-
- EXPECT_EQ(2, bufferlessSurfaceFrame2->getToken());
- EXPECT_EQ(false, bufferlessSurfaceFrame2->getIsBuffer());
- EXPECT_EQ(PresentState::Presented, bufferlessSurfaceFrame2->getPresentState());
- EXPECT_EQ(12, bufferlessSurfaceFrame2->getActuals().endTime);
- }
-
- void MergePendingStates_BufferlessSurfaceFramesWithOverlappingToken() {
- sp<BufferStateLayer> layer = createBufferStateLayer();
- layer->setFrameTimelineVsyncForBufferlessTransaction({/*vsyncId*/ 1, /*inputEventId*/ 0},
- 10);
- EXPECT_EQ(1u, layer->mCurrentState.bufferlessSurfaceFramesTX.size());
- ASSERT_EQ(nullptr, layer->mCurrentState.bufferSurfaceFrameTX);
- const auto bufferlessSurfaceFrame1 =
- layer->mCurrentState.bufferlessSurfaceFramesTX.at(/*token*/ 1);
-
- layer->pushPendingState();
- EXPECT_EQ(0u, layer->mCurrentState.bufferlessSurfaceFramesTX.size());
-
- layer->setFrameTimelineVsyncForBufferlessTransaction({/*vsyncId*/ 1, /*inputEventId*/ 0},
- 12);
- EXPECT_EQ(1u, layer->mCurrentState.bufferlessSurfaceFramesTX.size());
- ASSERT_EQ(nullptr, layer->mCurrentState.bufferSurfaceFrameTX);
- const auto bufferlessSurfaceFrame2 =
- layer->mCurrentState.bufferlessSurfaceFramesTX.at(/*token*/ 1);
-
- commitTransaction(layer.get());
-
- EXPECT_EQ(1, bufferlessSurfaceFrame1->getToken());
- EXPECT_EQ(false, bufferlessSurfaceFrame1->getIsBuffer());
- EXPECT_EQ(PresentState::Unknown, bufferlessSurfaceFrame1->getPresentState());
-
- EXPECT_EQ(1, bufferlessSurfaceFrame2->getToken());
- EXPECT_EQ(false, bufferlessSurfaceFrame2->getIsBuffer());
- EXPECT_EQ(PresentState::Presented, bufferlessSurfaceFrame2->getPresentState());
- EXPECT_EQ(12, bufferlessSurfaceFrame2->getActuals().endTime);
- }
-
void PendingSurfaceFramesRemovedAfterClassification() {
sp<BufferStateLayer> layer = createBufferStateLayer();
sp<Fence> fence1(new Fence());
auto acquireFence1 = fenceFactory.createFenceTimeForTest(fence1);
- sp<GraphicBuffer> buffer1{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)};
+ const auto buffer1 = std::make_shared<
+ renderengine::ExternalTexture>(new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888,
+ 1, 0),
+ mRenderEngine, false);
layer->setBuffer(buffer1, fence1, 10, 20, false, mClientCache, 1, std::nullopt,
{/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */);
ASSERT_NE(nullptr, layer->mCurrentState.bufferSurfaceFrameTX);
@@ -359,7 +312,10 @@ public:
sp<Fence> fence2(new Fence());
auto acquireFence2 = fenceFactory.createFenceTimeForTest(fence2);
- sp<GraphicBuffer> buffer2{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)};
+ const auto buffer2 = std::make_shared<
+ renderengine::ExternalTexture>(new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888,
+ 1, 0),
+ mRenderEngine, false);
layer->setBuffer(buffer2, fence2, 10, 20, false, mClientCache, 1, std::nullopt,
{/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */);
acquireFence2->signalForTest(12);
@@ -386,7 +342,10 @@ public:
sp<Fence> fence1(new Fence());
auto acquireFence1 = fenceFactory.createFenceTimeForTest(fence1);
- sp<GraphicBuffer> buffer1{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)};
+ const auto buffer1 = std::make_shared<
+ renderengine::ExternalTexture>(new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888,
+ 1, 0),
+ mRenderEngine, false);
layer->setBuffer(buffer1, fence1, 10, 20, false, mClientCache, 1, std::nullopt,
{/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */);
EXPECT_EQ(0u, layer->mCurrentState.bufferlessSurfaceFramesTX.size());
@@ -395,7 +354,10 @@ public:
sp<Fence> fence2(new Fence());
auto acquireFence2 = fenceFactory.createFenceTimeForTest(fence2);
- sp<GraphicBuffer> buffer2{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)};
+ const auto buffer2 = std::make_shared<
+ renderengine::ExternalTexture>(new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888,
+ 1, 0),
+ mRenderEngine, false);
auto dropStartTime1 = systemTime();
layer->setBuffer(buffer2, fence2, 10, 20, false, mClientCache, 1, std::nullopt,
{/*vsyncId*/ FrameTimelineInfo::INVALID_VSYNC_ID, /*inputEventId*/ 0},
@@ -407,7 +369,10 @@ public:
sp<Fence> fence3(new Fence());
auto acquireFence3 = fenceFactory.createFenceTimeForTest(fence3);
- sp<GraphicBuffer> buffer3{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)};
+ const auto buffer3 = std::make_shared<
+ renderengine::ExternalTexture>(new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888,
+ 1, 0),
+ mRenderEngine, false);
auto dropStartTime2 = systemTime();
layer->setBuffer(buffer3, fence3, 10, 20, false, mClientCache, 1, std::nullopt,
{/*vsyncId*/ 2, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */);
@@ -447,7 +412,11 @@ public:
std::vector<std::shared_ptr<frametimeline::SurfaceFrame>> bufferlessSurfaceFrames;
for (int i = 0; i < 10; i += 2) {
sp<Fence> fence1(new Fence());
- sp<GraphicBuffer> buffer1{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)};
+ const auto buffer1 = std::make_shared<
+ renderengine::ExternalTexture>(new GraphicBuffer(1, 1,
+ HAL_PIXEL_FORMAT_RGBA_8888, 1,
+ 0),
+ mRenderEngine, false);
layer->setBuffer(buffer1, fence1, 10, 20, false, mClientCache, 1, std::nullopt,
{/*vsyncId*/ 1, /*inputEventId*/ 0},
nullptr /* releaseBufferCallback */);
@@ -529,16 +498,6 @@ TEST_F(TransactionSurfaceFrameTest, MultipleSurfaceFramesPresentedTogether) {
MultipleSurfaceFramesPresentedTogether();
}
-TEST_F(TransactionSurfaceFrameTest,
- MergePendingStates_BufferlessSurfaceFramesWithoutOverlappingToken) {
- MergePendingStates_BufferlessSurfaceFramesWithoutOverlappingToken();
-}
-
-TEST_F(TransactionSurfaceFrameTest,
- MergePendingStates_BufferlessSurfaceFramesWithOverlappingToken) {
- MergePendingStates_BufferlessSurfaceFramesWithOverlappingToken();
-}
-
TEST_F(TransactionSurfaceFrameTest, PendingSurfaceFramesRemovedAfterClassification) {
PendingSurfaceFramesRemovedAfterClassification();
}
@@ -552,4 +511,4 @@ TEST_F(TransactionSurfaceFrameTest, MultipleCommitsBeforeLatch) {
MultipleCommitsBeforeLatch();
}
-} // namespace android \ No newline at end of file
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/mock/MockFrameTimeline.h b/services/surfaceflinger/tests/unittests/mock/MockFrameTimeline.h
index 570797861d..5dc48c3703 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockFrameTimeline.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockFrameTimeline.h
@@ -32,7 +32,9 @@ public:
MOCK_METHOD0(onBootFinished, void());
MOCK_METHOD1(addSurfaceFrame, void(std::shared_ptr<frametimeline::SurfaceFrame>));
MOCK_METHOD3(setSfWakeUp, void(int64_t, nsecs_t, Fps));
- MOCK_METHOD3(setSfPresent, void(nsecs_t, const std::shared_ptr<FenceTime>&, bool));
+ MOCK_METHOD3(setSfPresent,
+ void(nsecs_t, const std::shared_ptr<FenceTime>&,
+ const std::shared_ptr<FenceTime>&));
MOCK_METHOD1(computeFps, float(const std::unordered_set<int32_t>&));
};
diff --git a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
index 37b74ed3a7..526a847614 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
@@ -27,7 +27,7 @@ public:
TimeStats();
~TimeStats() override;
- MOCK_METHOD0(onBootFinished, void());
+ MOCK_METHOD2(onPullAtom, bool(const int, std::string*));
MOCK_METHOD3(parseArgs, void(bool, const Vector<String16>&, std::string&));
MOCK_METHOD0(isEnabled, bool());
MOCK_METHOD0(miniDump, std::string());
diff --git a/services/surfaceflinger/tests/utils/TransactionUtils.h b/services/surfaceflinger/tests/utils/TransactionUtils.h
index 3cbfed98f5..8c448e2f96 100644
--- a/services/surfaceflinger/tests/utils/TransactionUtils.h
+++ b/services/surfaceflinger/tests/utils/TransactionUtils.h
@@ -126,7 +126,7 @@ public:
const uint8_t* src = pixels + (outBuffer->getStride() * (y + j) + x) * 4;
for (int32_t i = 0; i < width; i++) {
const uint8_t expected[4] = {color.r, color.g, color.b, color.a};
- EXPECT_TRUE(std::equal(src, src + 4, expected, colorCompare))
+ ASSERT_TRUE(std::equal(src, src + 4, expected, colorCompare))
<< "pixel @ (" << x + i << ", " << y + j << "): "
<< "expected (" << color << "), "
<< "got (" << Color{src[0], src[1], src[2], src[3]} << ")";
@@ -161,6 +161,22 @@ public:
ASSERT_EQ(NO_ERROR, s->unlockAndPost());
}
}
+
+ static void setFrame(Transaction& t, const sp<SurfaceControl>& sc, Rect source, Rect dest,
+ int32_t transform = 0) {
+ uint32_t sourceWidth = source.getWidth();
+ uint32_t sourceHeight = source.getHeight();
+
+ if (transform & ui::Transform::ROT_90) {
+ std::swap(sourceWidth, sourceHeight);
+ }
+
+ float dsdx = dest.getWidth() / static_cast<float>(sourceWidth);
+ float dsdy = dest.getHeight() / static_cast<float>(sourceHeight);
+
+ t.setMatrix(sc, dsdx, 0, 0, dsdy);
+ t.setPosition(sc, dest.left, dest.top);
+ }
};
enum class RenderPath { SCREENSHOT, VIRTUAL_DISPLAY };
diff --git a/services/vibratorservice/VibratorManagerHalWrapper.cpp b/services/vibratorservice/VibratorManagerHalWrapper.cpp
index a9d499de1d..6e660e7e41 100644
--- a/services/vibratorservice/VibratorManagerHalWrapper.cpp
+++ b/services/vibratorservice/VibratorManagerHalWrapper.cpp
@@ -30,7 +30,7 @@ constexpr int32_t SINGLE_VIBRATOR_ID = 0;
const constexpr char* MISSING_VIBRATOR_MESSAGE_PREFIX = "No vibrator with id=";
HalResult<void> LegacyManagerHalWrapper::ping() {
- auto pingFn = [](std::shared_ptr<HalWrapper> hal) { return hal->ping(); };
+ auto pingFn = [](HalWrapper* hal) { return hal->ping(); };
return mController->doWithRetry<void>(pingFn, "ping");
}
diff --git a/services/vibratorservice/include/vibratorservice/VibratorHalController.h b/services/vibratorservice/include/vibratorservice/VibratorHalController.h
index 354e56ca68..6c31e2b882 100644
--- a/services/vibratorservice/include/vibratorservice/VibratorHalController.h
+++ b/services/vibratorservice/include/vibratorservice/VibratorHalController.h
@@ -30,7 +30,7 @@ namespace vibrator {
std::shared_ptr<HalWrapper> connectHal(std::shared_ptr<CallbackScheduler> scheduler);
template <typename T>
-using HalFunction = std::function<T(std::shared_ptr<HalWrapper>)>;
+using HalFunction = std::function<T(HalWrapper*)>;
// Controller for Vibrator HAL handle.
// This relies on a given Connector to connect to the underlying Vibrator HAL service and reconnects
@@ -64,8 +64,7 @@ public:
*/
Info getInfo() {
static Info sDefaultInfo = InfoCache().get();
- return apply<Info>([](std::shared_ptr<HalWrapper> hal) { return hal->getInfo(); },
- sDefaultInfo, "getInfo");
+ return apply<Info>([](HalWrapper* hal) { return hal->getInfo(); }, sDefaultInfo, "getInfo");
}
/* Calls given HAL function, applying automatic retries to reconnect with the HAL when the
@@ -103,7 +102,7 @@ private:
}
for (int i = 0; i < MAX_RETRIES; i++) {
- T result = halFn(hal);
+ T result = halFn(hal.get());
if (result.checkAndLogFailure(functionName)) {
tryReconnect();
} else {
@@ -111,7 +110,7 @@ private:
}
}
- return halFn(hal);
+ return halFn(hal.get());
}
};
diff --git a/services/vibratorservice/test/VibratorHalControllerTest.cpp b/services/vibratorservice/test/VibratorHalControllerTest.cpp
index 279496a8b8..8e77bc57f3 100644
--- a/services/vibratorservice/test/VibratorHalControllerTest.cpp
+++ b/services/vibratorservice/test/VibratorHalControllerTest.cpp
@@ -40,11 +40,9 @@ using namespace android;
using namespace std::chrono_literals;
using namespace testing;
-static const auto ON_FN = [](std::shared_ptr<vibrator::HalWrapper> hal) {
- return hal->on(10ms, []() {});
-};
-static const auto OFF_FN = [](std::shared_ptr<vibrator::HalWrapper> hal) { return hal->off(); };
-static const auto PING_FN = [](std::shared_ptr<vibrator::HalWrapper> hal) { return hal->ping(); };
+static const auto ON_FN = [](vibrator::HalWrapper* hal) { return hal->on(10ms, []() {}); };
+static const auto OFF_FN = [](vibrator::HalWrapper* hal) { return hal->off(); };
+static const auto PING_FN = [](vibrator::HalWrapper* hal) { return hal->ping(); };
// -------------------------------------------------------------------------------------------------
@@ -233,7 +231,7 @@ TEST_F(VibratorHalControllerTest, TestScheduledCallbackSurvivesReconnection) {
std::unique_ptr<int32_t> callbackCounter = std::make_unique<int32_t>();
auto callback = vibrator::TestFactory::createCountingCallback(callbackCounter.get());
- auto onFn = [&](std::shared_ptr<vibrator::HalWrapper> hal) { return hal->on(10ms, callback); };
+ auto onFn = [&](vibrator::HalWrapper* hal) { return hal->on(10ms, callback); };
ASSERT_TRUE(mController->doWithRetry<void>(onFn, "on").isOk());
ASSERT_TRUE(mController->doWithRetry<void>(PING_FN, "ping").isFailed());
mMockHal.reset();
diff --git a/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp b/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp
index d1db82b4ca..af0cdb85b1 100644
--- a/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp
+++ b/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp
@@ -644,7 +644,6 @@ TEST_F(VibratorHalWrapperAidlTest, TestPerformPwleEffect) {
.Times(Exactly(2))
.WillOnce(Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY)))
.WillRepeatedly(DoAll(TriggerCallbackInArg1(), Return(Status())));
- ;
}
std::unique_ptr<int32_t> callbackCounter = std::make_unique<int32_t>();
diff --git a/services/vibratorservice/test/VibratorManagerHalWrapperAidlTest.cpp b/services/vibratorservice/test/VibratorManagerHalWrapperAidlTest.cpp
index 3de157667c..548d02817a 100644
--- a/services/vibratorservice/test/VibratorManagerHalWrapperAidlTest.cpp
+++ b/services/vibratorservice/test/VibratorManagerHalWrapperAidlTest.cpp
@@ -40,7 +40,7 @@ using android::hardware::vibrator::PrimitivePwle;
using namespace android;
using namespace testing;
-static const auto OFF_FN = [](std::shared_ptr<vibrator::HalWrapper> hal) { return hal->off(); };
+static const auto OFF_FN = [](vibrator::HalWrapper* hal) { return hal->off(); };
class MockBinder : public BBinder {
public:
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index 020b520a7c..8d6681c9f4 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -1086,7 +1086,8 @@ VkResult CreateSwapchainKHR(VkDevice device,
ALOGW_IF(err != android::OK, "native_window_api_connect failed: %s (%d)",
strerror(-err), err);
- err = window->perform(window, NATIVE_WINDOW_SET_DEQUEUE_TIMEOUT, -1);
+ err =
+ window->perform(window, NATIVE_WINDOW_SET_DEQUEUE_TIMEOUT, nsecs_t{-1});
if (err != android::OK) {
ALOGE("window->perform(SET_DEQUEUE_TIMEOUT) failed: %s (%d)",
strerror(-err), err);