summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2022-05-08 04:55:01 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2022-05-08 04:55:01 +0000
commit5cea12c8508aa438f67066490cb26101bb169b27 (patch)
tree10524a8c46844f072d95c56cadc67b5ecedfa42f
parentf3f4033673fc34e371d02f02fd506c881a605994 (diff)
parent23fa3fb806fb8392708c3fa139dd4ef24cedfaaf (diff)
downloadnative-5cea12c8508aa438f67066490cb26101bb169b27.tar.gz
Merge "Snap for 8554636 from 864034bf750090c0522ba6a3cd1abb379999ba6e to sdk-release" into sdk-releaseplatform-tools-33.0.2
-rw-r--r--TEST_MAPPING61
-rw-r--r--cmds/atrace/atrace.cpp11
-rw-r--r--cmds/dumpstate/dumpstate.cpp6
-rw-r--r--cmds/installd/Android.bp5
-rw-r--r--cmds/installd/InstalldNativeService.cpp600
-rw-r--r--cmds/installd/InstalldNativeService.h46
-rw-r--r--cmds/installd/TEST_MAPPING8
-rw-r--r--cmds/installd/binder/android/os/IInstalld.aidl5
-rw-r--r--cmds/installd/binder/android/os/ReconcileSdkDataArgs.aidl29
-rw-r--r--cmds/installd/tests/Android.bp2
-rw-r--r--cmds/installd/tests/installd_service_test.cpp781
-rw-r--r--cmds/installd/tests/installd_utils_test.cpp56
-rw-r--r--cmds/installd/utils.cpp115
-rw-r--r--cmds/installd/utils.h13
-rw-r--r--cmds/servicemanager/ServiceManager.cpp13
-rw-r--r--cmds/surfacereplayer/proto/src/trace.proto7
-rw-r--r--data/etc/Android.bp20
-rw-r--r--data/etc/android.software.app_compat_overrides.xml21
-rw-r--r--include/android/multinetwork.h24
-rw-r--r--include/android/storage_manager.h6
-rw-r--r--include/ftl/Flags.h (renamed from include/input/Flags.h)7
-rw-r--r--include/ftl/NamedEnum.h (renamed from include/input/NamedEnum.h)5
-rw-r--r--include/input/DisplayViewport.h3
-rw-r--r--include/input/Input.h22
-rw-r--r--include/input/InputTransport.h7
-rw-r--r--include/input/KeyCharacterMap.h18
-rw-r--r--libs/binder/Android.bp1
-rw-r--r--libs/binder/Binder.cpp8
-rw-r--r--libs/binder/BpBinder.cpp26
-rw-r--r--libs/binder/BufferedTextOutput.h2
-rw-r--r--libs/binder/IMemory.cpp45
-rw-r--r--libs/binder/IPCThreadState.cpp6
-rw-r--r--libs/binder/MemoryDealer.cpp1
-rw-r--r--libs/binder/MemoryHeapBase.cpp64
-rw-r--r--libs/binder/Parcel.cpp51
-rw-r--r--libs/binder/ParcelableHolder.cpp5
-rw-r--r--libs/binder/ProcessState.cpp29
-rw-r--r--libs/binder/RpcSession.cpp23
-rw-r--r--libs/binder/RpcState.cpp18
-rw-r--r--libs/binder/RpcTransportRaw.cpp17
-rw-r--r--libs/binder/RpcTransportTls.cpp43
-rw-r--r--libs/binder/Static.h2
-rw-r--r--libs/binder/include/binder/BpBinder.h5
-rw-r--r--libs/binder/include/binder/IServiceManager.h12
-rw-r--r--libs/binder/include/binder/MemoryHeapBase.h16
-rw-r--r--libs/binder/include/binder/Parcel.h6
-rw-r--r--libs/binder/include/binder/ParcelableHolder.h4
-rw-r--r--libs/binder/include/binder/PermissionController.h3
-rw-r--r--libs/binder/include/binder/ProcessState.h9
-rw-r--r--libs/binder/include/binder/RpcServer.h2
-rw-r--r--libs/binder/include/binder/RpcTransport.h3
-rw-r--r--libs/binder/include_activitymanager/binder/ActivityManager.h5
-rw-r--r--libs/binder/ndk/include_cpp/android/binder_auto_utils.h4
-rw-r--r--libs/binder/ndk/include_cpp/android/binder_interface_utils.h4
-rw-r--r--libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h39
-rw-r--r--libs/binder/ndk/include_ndk/android/binder_ibinder_jni.h6
-rw-r--r--libs/binder/ndk/include_platform/android/binder_manager.h10
-rw-r--r--libs/binder/ndk/include_platform/android/binder_stability.h4
-rw-r--r--libs/binder/rust/src/binder.rs4
-rw-r--r--libs/binder/rust/src/parcel/parcelable_holder.rs4
-rw-r--r--libs/binder/rust/src/proxy.rs14
-rw-r--r--libs/binder/rust/tests/serialization.cpp2
-rw-r--r--libs/binder/rust/tests/serialization.rs4
-rw-r--r--libs/binder/tests/Android.bp1
-rw-r--r--libs/binder/tests/binderBinderUnitTest.cpp7
-rw-r--r--libs/binder/tests/binderLibTest.cpp6
-rw-r--r--libs/binder/tests/binderMemoryHeapBaseUnitTest.cpp97
-rw-r--r--libs/binder/tests/binderParcelUnitTest.cpp37
-rw-r--r--libs/binder/tests/include_tls_test_utils/binder/RpcTlsTestUtils.h1
-rw-r--r--libs/binder/tests/parcel_fuzzer/Android.bp6
-rw-r--r--libs/binder/tests/parcel_fuzzer/binder.cpp2
-rw-r--r--libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/libbinder_driver.h37
-rw-r--r--libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/libbinder_ndk_driver.h37
-rw-r--r--libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_fd.h5
-rw-r--r--libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h21
-rw-r--r--libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp65
-rw-r--r--libs/binder/tests/parcel_fuzzer/libbinder_ndk_driver.cpp31
-rw-r--r--libs/binder/tests/parcel_fuzzer/random_fd.cpp4
-rw-r--r--libs/binder/tests/parcel_fuzzer/random_parcel.cpp44
-rw-r--r--libs/binder/tests/unit_fuzzers/BpBinderFuzzFunctions.h1
-rw-r--r--libs/binder/tests/unit_fuzzers/IBinderFuzzFunctions.h1
-rw-r--r--libs/cputimeinstate/cputimeinstate.cpp13
-rw-r--r--libs/cputimeinstate/testtimeinstate.cpp52
-rw-r--r--libs/ftl/Android.bp10
-rw-r--r--libs/ftl/Flags_test.cpp (renamed from libs/input/tests/Flags_test.cpp)2
-rw-r--r--libs/ftl/NamedEnum_test.cpp (renamed from libs/input/tests/NamedEnum_test.cpp)2
-rw-r--r--libs/graphicsenv/OWNERS8
-rw-r--r--libs/gui/Android.bp65
-rw-r--r--libs/gui/BLASTBufferQueue.cpp252
-rw-r--r--libs/gui/BufferQueueCore.cpp1
-rw-r--r--libs/gui/ISurfaceComposer.cpp31
-rw-r--r--libs/gui/LayerState.cpp54
-rw-r--r--libs/gui/SurfaceComposerClient.cpp103
-rw-r--r--libs/gui/WindowInfo.cpp (renamed from libs/input/InputWindow.cpp)73
-rw-r--r--libs/gui/WindowInfosListenerReporter.cpp98
-rw-r--r--libs/gui/android/gui/DropInputMode.aidl45
-rw-r--r--libs/gui/android/gui/FocusRequest.aidl (renamed from libs/input/android/FocusRequest.aidl)2
-rw-r--r--libs/gui/android/gui/IWindowInfosListener.aidl26
-rw-r--r--libs/gui/android/gui/IWindowInfosReportedListener.aidl (renamed from libs/input/android/os/ISetInputWindowsListener.aidl)6
-rw-r--r--libs/gui/android/gui/InputApplicationInfo.aidl (renamed from libs/input/android/InputApplicationInfo.aidl)2
-rw-r--r--libs/gui/android/gui/TouchOcclusionMode.aidl (renamed from libs/input/android/os/TouchOcclusionMode.aidl)2
-rw-r--r--libs/gui/android/gui/WindowInfo.aidl (renamed from libs/input/android/InputWindowInfo.aidl)7
-rw-r--r--libs/gui/include/gui/BLASTBufferQueue.h25
-rw-r--r--libs/gui/include/gui/ISurfaceComposer.h10
-rw-r--r--libs/gui/include/gui/InputApplication.h (renamed from include/input/InputApplication.h)18
-rw-r--r--libs/gui/include/gui/LayerState.h28
-rw-r--r--libs/gui/include/gui/SurfaceComposerClient.h29
-rw-r--r--libs/gui/include/gui/WindowInfo.h (renamed from include/input/InputWindow.h)73
-rw-r--r--libs/gui/include/gui/WindowInfosListener.h28
-rw-r--r--libs/gui/include/gui/WindowInfosListenerReporter.h48
-rw-r--r--libs/gui/include/gui/constants.h37
-rw-r--r--libs/gui/include/gui/test/CallbackUtils.h (renamed from services/surfaceflinger/tests/utils/CallbackUtils.h)14
-rw-r--r--libs/gui/tests/Android.bp1
-rw-r--r--libs/gui/tests/BLASTBufferQueue_test.cpp349
-rw-r--r--libs/gui/tests/EndToEndNativeInputTest.cpp214
-rw-r--r--libs/gui/tests/Surface_test.cpp10
-rw-r--r--libs/gui/tests/WindowInfo_test.cpp (renamed from libs/input/tests/InputWindow_test.cpp)27
-rw-r--r--libs/input/Android.bp29
-rw-r--r--libs/input/Input.cpp89
-rw-r--r--libs/input/InputDevice.cpp2
-rw-r--r--libs/input/InputTransport.cpp22
-rw-r--r--libs/input/KeyCharacterMap.cpp141
-rw-r--r--libs/input/KeyLayoutMap.cpp2
-rw-r--r--libs/input/android/os/IInputFlinger.aidl11
-rw-r--r--libs/input/tests/Android.bp13
-rw-r--r--libs/input/tests/InputDevice_test.cpp50
-rw-r--r--libs/input/tests/InputEvent_test.cpp99
-rw-r--r--libs/input/tests/InputPublisherAndConsumer_test.cpp24
-rw-r--r--libs/input/tests/StructLayout_test.cpp8
-rw-r--r--libs/input/tests/VelocityTracker_test.cpp5
-rw-r--r--libs/input/tests/VerifiedInputEvent_test.cpp8
-rw-r--r--libs/input/tests/data/english_us.kcm311
-rw-r--r--libs/input/tests/data/french.kcm336
-rw-r--r--libs/input/tests/data/german.kcm336
-rw-r--r--libs/nativedisplay/AChoreographer.cpp1
-rw-r--r--libs/nativewindow/AHardwareBuffer.cpp6
-rw-r--r--libs/renderengine/gl/GLESRenderEngine.h2
-rw-r--r--libs/renderengine/include/renderengine/RenderEngine.h4
-rw-r--r--libs/renderengine/include/renderengine/mock/RenderEngine.h2
-rw-r--r--libs/renderengine/skia/SkiaGLRenderEngine.cpp2
-rw-r--r--libs/renderengine/skia/SkiaGLRenderEngine.h2
-rw-r--r--libs/renderengine/threaded/RenderEngineThreaded.cpp6
-rw-r--r--libs/renderengine/threaded/RenderEngineThreaded.h2
-rw-r--r--libs/ui/Gralloc4.cpp20
-rw-r--r--libs/ui/tests/Android.bp1
-rw-r--r--libs/ui/tests/GraphicBufferOverBinder_test.cpp3
-rw-r--r--libs/vibrator/ExternalVibrationUtils.cpp48
-rw-r--r--libs/vibrator/include/vibrator/ExternalVibrationUtils.h6
-rw-r--r--libs/vr/libbroadcastring/Android.bp2
-rw-r--r--libs/vr/libvrflinger/vr_flinger.cpp1
-rw-r--r--opengl/OWNERS7
-rw-r--r--services/inputflinger/Android.bp2
-rw-r--r--services/inputflinger/InputManager.cpp31
-rw-r--r--services/inputflinger/InputManager.h8
-rw-r--r--services/inputflinger/InputReaderBase.cpp2
-rw-r--r--services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp16
-rw-r--r--services/inputflinger/dispatcher/Android.bp2
-rw-r--r--services/inputflinger/dispatcher/DragState.cpp2
-rw-r--r--services/inputflinger/dispatcher/DragState.h10
-rw-r--r--services/inputflinger/dispatcher/Entry.cpp4
-rw-r--r--services/inputflinger/dispatcher/Entry.h6
-rw-r--r--services/inputflinger/dispatcher/FocusResolver.cpp15
-rw-r--r--services/inputflinger/dispatcher/FocusResolver.h18
-rw-r--r--services/inputflinger/dispatcher/InputDispatcher.cpp439
-rw-r--r--services/inputflinger/dispatcher/InputDispatcher.h110
-rw-r--r--services/inputflinger/dispatcher/InputTarget.h6
-rw-r--r--services/inputflinger/dispatcher/TouchState.cpp13
-rw-r--r--services/inputflinger/dispatcher/TouchState.h14
-rw-r--r--services/inputflinger/dispatcher/TouchedWindow.h6
-rw-r--r--services/inputflinger/dispatcher/include/InputDispatcherInterface.h12
-rw-r--r--services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h2
-rw-r--r--services/inputflinger/host/InputFlinger.h7
-rw-r--r--services/inputflinger/reader/Android.bp1
-rw-r--r--services/inputflinger/reader/EventHub.cpp9
-rw-r--r--services/inputflinger/reader/InputDevice.cpp2
-rw-r--r--services/inputflinger/reader/controller/PeripheralController.cpp2
-rw-r--r--services/inputflinger/reader/include/EventHub.h2
-rw-r--r--services/inputflinger/reader/include/InputDevice.h2
-rw-r--r--services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h6
-rw-r--r--services/inputflinger/reader/mapper/TouchInputMapper.cpp32
-rw-r--r--services/inputflinger/reader/mapper/TouchInputMapper.h9
-rw-r--r--services/inputflinger/sysprop/Android.bp15
-rw-r--r--services/inputflinger/sysprop/InputFlingerProperties.sysprop27
-rw-r--r--services/inputflinger/tests/Android.bp1
-rw-r--r--services/inputflinger/tests/FocusResolver_test.cpp20
-rw-r--r--services/inputflinger/tests/IInputFlingerQuery.aidl7
-rw-r--r--services/inputflinger/tests/InputClassifierConverter_test.cpp2
-rw-r--r--services/inputflinger/tests/InputClassifier_test.cpp1
-rw-r--r--services/inputflinger/tests/InputDispatcher_test.cpp552
-rw-r--r--services/inputflinger/tests/InputFlingerService_test.cpp223
-rw-r--r--services/inputflinger/tests/InputReader_test.cpp379
-rw-r--r--services/inputflinger/tests/fuzzers/Android.bp3
-rw-r--r--services/sensorservice/SensorDevice.cpp18
-rw-r--r--services/sensorservice/SensorDevice.h8
-rw-r--r--services/sensorservice/SensorInterface.cpp20
-rw-r--r--services/sensorservice/SensorInterface.h7
-rw-r--r--services/sensorservice/SensorService.cpp54
-rw-r--r--services/sensorservice/SensorService.h12
-rw-r--r--services/surfaceflinger/Android.bp2
-rw-r--r--services/surfaceflinger/BufferLayer.cpp60
-rw-r--r--services/surfaceflinger/BufferQueueLayer.cpp7
-rw-r--r--services/surfaceflinger/BufferStateLayer.cpp18
-rw-r--r--services/surfaceflinger/BufferStateLayer.h3
-rw-r--r--services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h3
-rw-r--r--services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h1
-rw-r--r--services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h85
-rw-r--r--services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h2
-rw-r--r--services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Planner.h5
-rw-r--r--services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/TexturePool.h11
-rw-r--r--services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h1
-rw-r--r--services/surfaceflinger/CompositionEngine/src/Output.cpp9
-rw-r--r--services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp30
-rw-r--r--services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp34
-rw-r--r--services/surfaceflinger/CompositionEngine/src/planner/TexturePool.cpp32
-rw-r--r--services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h4
-rw-r--r--services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp34
-rw-r--r--services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp27
-rw-r--r--services/surfaceflinger/CompositionEngine/tests/planner/TexturePoolTest.cpp40
-rw-r--r--services/surfaceflinger/DisplayDevice.cpp126
-rw-r--r--services/surfaceflinger/DisplayDevice.h69
-rw-r--r--services/surfaceflinger/DisplayHardware/ComposerHal.cpp2
-rw-r--r--services/surfaceflinger/DisplayHardware/ComposerHal.h4
-rw-r--r--services/surfaceflinger/DisplayHardware/DisplayMode.h8
-rw-r--r--services/surfaceflinger/DisplayHardware/HWComposer.cpp10
-rw-r--r--services/surfaceflinger/DisplayHardware/HWComposer.h9
-rw-r--r--services/surfaceflinger/DisplayHardware/Hal.h11
-rw-r--r--services/surfaceflinger/Layer.cpp239
-rw-r--r--services/surfaceflinger/Layer.h37
-rw-r--r--services/surfaceflinger/LayerProtoHelper.cpp29
-rw-r--r--services/surfaceflinger/LayerProtoHelper.h11
-rw-r--r--services/surfaceflinger/LayerRenderArea.cpp14
-rw-r--r--services/surfaceflinger/MainThreadGuard.h35
-rw-r--r--services/surfaceflinger/OWNERS3
-rw-r--r--services/surfaceflinger/RefreshRateOverlay.cpp34
-rw-r--r--services/surfaceflinger/RefreshRateOverlay.h8
-rw-r--r--services/surfaceflinger/Scheduler/EventThread.cpp15
-rw-r--r--services/surfaceflinger/Scheduler/EventThread.h6
-rw-r--r--services/surfaceflinger/Scheduler/LayerHistory.cpp8
-rw-r--r--services/surfaceflinger/Scheduler/LayerHistory.h4
-rw-r--r--services/surfaceflinger/Scheduler/LayerInfo.cpp13
-rw-r--r--services/surfaceflinger/Scheduler/LayerInfo.h9
-rw-r--r--services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp36
-rw-r--r--services/surfaceflinger/Scheduler/RefreshRateConfigs.h95
-rw-r--r--services/surfaceflinger/Scheduler/Scheduler.cpp217
-rw-r--r--services/surfaceflinger/Scheduler/Scheduler.h114
-rw-r--r--services/surfaceflinger/Scheduler/VSyncReactor.cpp1
-rw-r--r--services/surfaceflinger/SurfaceFlinger.cpp922
-rw-r--r--services/surfaceflinger/SurfaceFlinger.h138
-rw-r--r--services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp5
-rw-r--r--services/surfaceflinger/SurfaceFlingerDefaultFactory.h4
-rw-r--r--services/surfaceflinger/SurfaceFlingerFactory.h4
-rw-r--r--services/surfaceflinger/SurfaceInterceptor.cpp11
-rw-r--r--services/surfaceflinger/SurfaceInterceptor.h3
-rw-r--r--services/surfaceflinger/SurfaceTracing.cpp13
-rw-r--r--services/surfaceflinger/SurfaceTracing.h3
-rw-r--r--services/surfaceflinger/WindowInfosListenerInvoker.cpp96
-rw-r--r--services/surfaceflinger/WindowInfosListenerInvoker.h57
-rw-r--r--services/surfaceflinger/layerproto/Android.bp3
-rw-r--r--services/surfaceflinger/layerproto/common.proto39
-rw-r--r--services/surfaceflinger/layerproto/display.proto36
-rw-r--r--services/surfaceflinger/layerproto/layers.proto28
-rw-r--r--services/surfaceflinger/layerproto/layerstrace.proto3
-rw-r--r--services/surfaceflinger/tests/Android.bp1
-rw-r--r--services/surfaceflinger/tests/EffectLayer_test.cpp9
-rw-r--r--services/surfaceflinger/tests/IPC_test.cpp2
-rw-r--r--services/surfaceflinger/tests/InvalidHandles_test.cpp11
-rw-r--r--services/surfaceflinger/tests/LayerCallback_test.cpp2
-rw-r--r--services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp120
-rw-r--r--services/surfaceflinger/tests/MirrorLayer_test.cpp55
-rw-r--r--services/surfaceflinger/tests/RefreshRateOverlay_test.cpp4
-rw-r--r--services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp64
-rw-r--r--services/surfaceflinger/tests/ScreenCapture_test.cpp54
-rw-r--r--services/surfaceflinger/tests/SurfaceInterceptor_test.cpp2
-rw-r--r--services/surfaceflinger/tests/WindowInfosListener_test.cpp137
-rw-r--r--services/surfaceflinger/tests/unittests/Android.bp1
-rw-r--r--services/surfaceflinger/tests/unittests/CompositionTest.cpp4
-rw-r--r--services/surfaceflinger/tests/unittests/DisplayDevice_InitiateModeChange.cpp173
-rw-r--r--services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h4
-rw-r--r--services/surfaceflinger/tests/unittests/EventThreadTest.cpp31
-rw-r--r--services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp170
-rw-r--r--services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp51
-rw-r--r--services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp1
-rw-r--r--services/surfaceflinger/tests/unittests/SchedulerTest.cpp32
-rw-r--r--services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp4
-rw-r--r--services/surfaceflinger/tests/unittests/SurfaceFlinger_SetDisplayStateTest.cpp68
-rw-r--r--services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp5
-rw-r--r--services/surfaceflinger/tests/unittests/TestableScheduler.h22
-rw-r--r--services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h27
-rw-r--r--services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp1
-rw-r--r--services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp2
-rw-r--r--services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp35
-rw-r--r--services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h3
-rw-r--r--services/surfaceflinger/tests/unittests/mock/MockEventThread.h2
-rw-r--r--services/surfaceflinger/tests/utils/ScreenshotUtils.h5
-rw-r--r--vulkan/libvulkan/driver.cpp9
-rw-r--r--vulkan/libvulkan/driver_gen.cpp2
-rw-r--r--vulkan/libvulkan/driver_gen.h2
-rw-r--r--vulkan/libvulkan/swapchain.cpp204
-rw-r--r--vulkan/scripts/driver_generator.py2
299 files changed, 9649 insertions, 2912 deletions
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 4b64203387..260ee8dd4f 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -67,5 +67,66 @@
}
]
}
+ ],
+ "hwasan-postsubmit": [
+ {
+ "name": "SurfaceFlinger_test",
+ "options": [
+ {
+ "include-filter": "*CredentialsTest.*"
+ },
+ {
+ "include-filter": "*SurfaceFlingerStress.*"
+ },
+ {
+ "include-filter": "*SurfaceInterceptorTest.*"
+ },
+ {
+ "include-filter": "*LayerTransactionTest.*"
+ },
+ {
+ "include-filter": "*LayerTypeTransactionTest.*"
+ },
+ {
+ "include-filter": "*LayerUpdateTest.*"
+ },
+ {
+ "include-filter": "*GeometryLatchingTest.*"
+ },
+ {
+ "include-filter": "*CropLatchingTest.*"
+ },
+ {
+ "include-filter": "*ChildLayerTest.*"
+ },
+ {
+ "include-filter": "*ScreenCaptureTest.*"
+ },
+ {
+ "include-filter": "*ScreenCaptureChildOnlyTest.*"
+ },
+ {
+ "include-filter": "*DereferenceSurfaceControlTest.*"
+ },
+ {
+ "include-filter": "*BoundlessLayerTest.*"
+ },
+ {
+ "include-filter": "*MultiDisplayLayerBoundsTest.*"
+ },
+ {
+ "include-filter": "*InvalidHandleTest.*"
+ },
+ {
+ "include-filter": "*VirtualDisplayTest.*"
+ },
+ {
+ "include-filter": "*RelativeZTest.*"
+ },
+ {
+ "include-filter": "*RefreshRateOverlayTest.*"
+ }
+ ]
+ }
]
}
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index 7aee795fc4..9bd733d04c 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -1224,10 +1224,7 @@ int main(int argc, char **argv)
if (ret < 0) {
for (int i = optind; i < argc; i++) {
- if (!setCategoryEnable(argv[i])) {
- fprintf(stderr, "error enabling tracing category \"%s\"\n", argv[i]);
- exit(1);
- }
+ setCategoryEnable(argv[i]);
}
break;
}
@@ -1343,10 +1340,10 @@ int main(int argc, char **argv)
// contain entries from only one CPU can cause "begin" entries without a
// matching "end" entry to show up if a task gets migrated from one CPU to
// another.
- if (!onlyUserspace)
+ if (!onlyUserspace) {
ok = clearTrace();
-
- writeClockSyncMarker();
+ writeClockSyncMarker();
+ }
if (ok && !async && !traceStream) {
// Sleep to allow the trace to be captured.
struct timespec timeLeft;
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 0e9ce897bc..890c15f895 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -2418,7 +2418,7 @@ void Dumpstate::DumpstateBoard(int out_fd) {
// Given that bugreport is required to diagnose failures, it's better to set an arbitrary amount
// of timeout for IDumpstateDevice than to block the rest of bugreport. In the timeout case, we
// will kill the HAL and grab whatever it dumped in time.
- constexpr size_t timeout_sec = 30;
+ constexpr size_t timeout_sec = 45;
if (dumpstate_hal_handle_aidl != nullptr) {
DoDumpstateBoardAidl(dumpstate_hal_handle_aidl, dumpstate_fds, options_->bugreport_mode,
@@ -2733,8 +2733,8 @@ void Dumpstate::DumpOptions::Initialize(BugreportMode bugreport_mode,
const android::base::unique_fd& screenshot_fd_in,
bool is_screenshot_requested) {
// Duplicate the fds because the passed in fds don't outlive the binder transaction.
- bugreport_fd.reset(dup(bugreport_fd_in.get()));
- screenshot_fd.reset(dup(screenshot_fd_in.get()));
+ bugreport_fd.reset(fcntl(bugreport_fd_in.get(), F_DUPFD_CLOEXEC, 0));
+ screenshot_fd.reset(fcntl(screenshot_fd_in.get(), F_DUPFD_CLOEXEC, 0));
SetOptionsFromMode(bugreport_mode, this, is_screenshot_requested);
}
diff --git a/cmds/installd/Android.bp b/cmds/installd/Android.bp
index c9f680b266..bf5e893a99 100644
--- a/cmds/installd/Android.bp
+++ b/cmds/installd/Android.bp
@@ -81,8 +81,9 @@ cc_defaults {
"cert-*",
"-cert-err58-cpp",
],
- tidy_flags: [
- "-warnings-as-errors=clang-analyzer-security*,cert-*",
+ tidy_checks_as_errors: [
+ "clang-analyzer-security*",
+ "cert-*",
],
}
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 4e3aae4312..95335e90ae 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -18,13 +18,9 @@
#define ATRACE_TAG ATRACE_TAG_PACKAGE_MANAGER
-#include <algorithm>
#include <errno.h>
-#include <fstream>
#include <fts.h>
-#include <functional>
#include <inttypes.h>
-#include <regex>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -40,6 +36,12 @@
#include <sys/wait.h>
#include <sys/xattr.h>
#include <unistd.h>
+#include <algorithm>
+#include <filesystem>
+#include <fstream>
+#include <functional>
+#include <regex>
+#include <unordered_set>
#include <android-base/file.h>
#include <android-base/logging.h>
@@ -53,7 +55,8 @@
#include <cutils/fs.h>
#include <cutils/properties.h>
#include <cutils/sched_policy.h>
-#include <log/log.h> // TODO: Move everything to base/logging.
+#include <linux/quota.h>
+#include <log/log.h> // TODO: Move everything to base/logging.
#include <logwrap/logwrap.h>
#include <private/android_filesystem_config.h>
#include <private/android_projectid_config.h>
@@ -80,6 +83,7 @@
// #define GRANULAR_LOCKS
using android::base::ParseUint;
+using android::base::Split;
using android::base::StringPrintf;
using std::endl;
@@ -114,6 +118,12 @@ static constexpr const char* kMntFuse = "/mnt/pass_through/0/";
static std::atomic<bool> sAppDataIsolationEnabled(false);
+/**
+ * Flag to control if project ids are supported for internal storage
+ */
+static std::atomic<bool> sUsingProjectIdsFlag(false);
+static std::once_flag flag;
+
namespace {
constexpr const char* kDump = "android.permission.DUMP";
@@ -455,14 +465,41 @@ done:
return res;
}
-static int prepare_app_dir(const std::string& path, mode_t target_mode, uid_t uid) {
- if (fs_prepare_dir_strict(path.c_str(), target_mode, uid, uid) != 0) {
+static bool internal_storage_has_project_id() {
+ // The following path is populated in setFirstBoot, so if this file is present
+ // then project ids can be used. Using call once to cache the result of this check
+ // to avoid having to check the file presence again and again.
+ std::call_once(flag, []() {
+ auto using_project_ids =
+ StringPrintf("%smisc/installd/using_project_ids", android_data_dir.c_str());
+ sUsingProjectIdsFlag = access(using_project_ids.c_str(), F_OK) == 0;
+ });
+ // return sUsingProjectIdsFlag;
+ return false;
+}
+
+static int prepare_app_dir(const std::string& path, mode_t target_mode, uid_t uid, gid_t gid,
+ long project_id) {
+ if (fs_prepare_dir_strict(path.c_str(), target_mode, uid, gid) != 0) {
PLOG(ERROR) << "Failed to prepare " << path;
return -1;
}
+ if (internal_storage_has_project_id()) {
+ return set_quota_project_id(path, project_id, true);
+ }
return 0;
}
+static int prepare_app_cache_dir(const std::string& parent, const char* name, mode_t target_mode,
+ uid_t uid, gid_t gid, long project_id) {
+ auto path = StringPrintf("%s/%s", parent.c_str(), name);
+ int ret = prepare_app_cache_dir(parent, name, target_mode, uid, gid);
+ if (ret == 0 && internal_storage_has_project_id()) {
+ return set_quota_project_id(path, project_id, true);
+ }
+ return ret;
+}
+
static bool prepare_app_profile_dir(const std::string& packageName, int32_t appId, int32_t userId) {
if (!property_get_bool("dalvik.vm.usejitprofiles", false)) {
return true;
@@ -596,9 +633,10 @@ static void chown_app_profile_dir(const std::string &packageName, int32_t appId,
}
}
-static binder::Status createAppDataDirs(const std::string& path,
- int32_t uid, int32_t* previousUid, int32_t cacheGid,
- const std::string& seInfo, mode_t targetMode) {
+static binder::Status createAppDataDirs(const std::string& path, int32_t uid, int32_t gid,
+ int32_t previousUid, int32_t cacheGid,
+ const std::string& seInfo, mode_t targetMode,
+ long projectIdApp, long projectIdCache) {
struct stat st{};
bool parent_dir_exists = (stat(path.c_str(), &st) == 0);
@@ -608,23 +646,17 @@ static binder::Status createAppDataDirs(const std::string& path,
bool code_cache_exists = (access(code_cache_path.c_str(), F_OK) == 0);
if (parent_dir_exists) {
- if (*previousUid < 0) {
- // If previousAppId is -1 in CreateAppDataArgs, we will assume the current owner
- // of the directory as previousUid. This is required because it is not always possible
- // to chown app data during app upgrade (e.g. secondary users' CE storage not unlocked)
- *previousUid = st.st_uid;
- }
- if (*previousUid != uid) {
- if (!chown_app_dir(path, uid, *previousUid, cacheGid)) {
+ if (previousUid > 0 && previousUid != uid) {
+ if (!chown_app_dir(path, uid, previousUid, cacheGid)) {
return error("Failed to chown " + path);
}
}
}
// Prepare only the parent app directory
- if (prepare_app_dir(path, targetMode, uid) ||
- prepare_app_cache_dir(path, "cache", 02771, uid, cacheGid) ||
- prepare_app_cache_dir(path, "code_cache", 02771, uid, cacheGid)) {
+ if (prepare_app_dir(path, targetMode, uid, gid, projectIdApp) ||
+ prepare_app_cache_dir(path, "cache", 02771, uid, cacheGid, projectIdCache) ||
+ prepare_app_cache_dir(path, "code_cache", 02771, uid, cacheGid, projectIdCache)) {
return error("Failed to prepare " + path);
}
@@ -665,12 +697,9 @@ binder::Status InstalldNativeService::createAppDataLocked(
int32_t uid = multiuser_get_uid(userId, appId);
- // If previousAppId < 0, we will use the existing app data owner as previousAppUid
- // If previousAppId == 0, we use uid as previousUid (no data migration will happen)
- // if previousAppId > 0, an app is upgrading and changing its app ID
- int32_t previousUid = previousAppId > 0
- ? (int32_t) multiuser_get_uid(userId, previousAppId)
- : (previousAppId == 0 ? uid : -1);
+ // If previousAppId > 0, an app is changing its app ID
+ int32_t previousUid =
+ previousAppId > 0 ? (int32_t)multiuser_get_uid(userId, previousAppId) : -1;
int32_t cacheGid = multiuser_get_cache_gid(userId, appId);
mode_t targetMode = targetSdkVersion >= MIN_RESTRICTED_HOME_SDK_VERSION ? 0700 : 0751;
@@ -680,10 +709,14 @@ binder::Status InstalldNativeService::createAppDataLocked(
cacheGid = uid;
}
+ long projectIdApp = get_project_id(uid, PROJECT_ID_APP_START);
+ long projectIdCache = get_project_id(uid, PROJECT_ID_APP_CACHE_START);
+
if (flags & FLAG_STORAGE_CE) {
auto path = create_data_user_ce_package_path(uuid_, userId, pkgname);
- auto status = createAppDataDirs(path, uid, &previousUid, cacheGid, seInfo, targetMode);
+ auto status = createAppDataDirs(path, uid, uid, previousUid, cacheGid, seInfo, targetMode,
+ projectIdApp, projectIdCache);
if (!status.isOk()) {
return status;
}
@@ -708,11 +741,12 @@ binder::Status InstalldNativeService::createAppDataLocked(
if (flags & FLAG_STORAGE_DE) {
auto path = create_data_user_de_package_path(uuid_, userId, pkgname);
- auto status = createAppDataDirs(path, uid, &previousUid, cacheGid, seInfo, targetMode);
+ auto status = createAppDataDirs(path, uid, uid, previousUid, cacheGid, seInfo, targetMode,
+ projectIdApp, projectIdCache);
if (!status.isOk()) {
return status;
}
- if (previousUid != uid) {
+ if (previousUid > 0 && previousUid != uid) {
chown_app_profile_dir(packageName, appId, userId);
}
@@ -720,6 +754,59 @@ binder::Status InstalldNativeService::createAppDataLocked(
return error("Failed to prepare profiles for " + packageName);
}
}
+
+ if (flags & FLAG_STORAGE_SDK) {
+ // Safe to ignore status since we can retry creating this by calling reconcileSdkData
+ auto ignore = createSdkSandboxDataPackageDirectory(uuid, packageName, userId, appId, flags);
+ if (!ignore.isOk()) {
+ PLOG(WARNING) << "Failed to create sdk data package directory for " << packageName;
+ }
+
+ } else {
+ // Package does not need sdk storage. Remove it.
+ destroySdkSandboxDataPackageDirectory(uuid, packageName, userId, flags);
+ }
+
+ return ok();
+}
+
+/**
+ * Responsible for creating /data/misc_{ce|de}/user/0/sdksandbox/<package-name> directory and other
+ * app level sub directories, such as ./shared
+ */
+binder::Status InstalldNativeService::createSdkSandboxDataPackageDirectory(
+ const std::optional<std::string>& uuid, const std::string& packageName, int32_t userId,
+ int32_t appId, int32_t flags) {
+ int32_t sdkSandboxUid = multiuser_get_sdk_sandbox_uid(userId, appId);
+ if (sdkSandboxUid == -1) {
+ // There no valid sdk sandbox process for this app. Skip creation of data directory
+ return ok();
+ }
+
+ const char* uuid_ = uuid ? uuid->c_str() : nullptr;
+
+ constexpr int storageFlags[2] = {FLAG_STORAGE_CE, FLAG_STORAGE_DE};
+ for (int currentFlag : storageFlags) {
+ if ((flags & currentFlag) == 0) {
+ continue;
+ }
+ bool isCeData = (currentFlag == FLAG_STORAGE_CE);
+
+ // /data/misc_{ce,de}/<user-id>/sdksandbox directory gets created by vold
+ // during user creation
+
+ // Prepare the package directory
+ auto packagePath = create_data_misc_sdk_sandbox_package_path(uuid_, isCeData, userId,
+ packageName.c_str());
+#if SDK_DEBUG
+ LOG(DEBUG) << "Creating app-level sdk data directory: " << packagePath;
+#endif
+
+ if (prepare_app_dir(packagePath, 0751, AID_SYSTEM, AID_SYSTEM, 0)) {
+ return error("Failed to prepare " + packagePath);
+ }
+ }
+
return ok();
}
@@ -766,6 +853,111 @@ binder::Status InstalldNativeService::createAppDataBatched(
return ok();
}
+binder::Status InstalldNativeService::reconcileSdkData(
+ const android::os::ReconcileSdkDataArgs& args) {
+ // Locking is performed depeer in the callstack.
+
+ return reconcileSdkData(args.uuid, args.packageName, args.subDirNames, args.userId, args.appId,
+ args.previousAppId, args.seInfo, args.flags);
+}
+
+/**
+ * Reconciles per-sdk directory under app-level sdk data directory.
+
+ * E.g. `/data/misc_ce/0/sdksandbox/<package-name>/<sdkPackageName>-<randomSuffix>
+ *
+ * - If the sdk data package directory is missing, we create it first.
+ * - If sdkPackageNames is empty, we delete sdk package directory since it's not needed anymore.
+ * - If a sdk level directory we need to prepare already exist, we skip creating it again. This
+ * is to avoid having same per-sdk directory with different suffix.
+ * - If a sdk level directory exist which is absent from sdkPackageNames, we remove it.
+ */
+binder::Status InstalldNativeService::reconcileSdkData(const std::optional<std::string>& uuid,
+ const std::string& packageName,
+ const std::vector<std::string>& subDirNames,
+ int userId, int appId, int previousAppId,
+ const std::string& seInfo, int flags) {
+ ENFORCE_UID(AID_SYSTEM);
+ CHECK_ARGUMENT_UUID(uuid);
+ CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+ LOCK_PACKAGE_USER();
+
+#if SDK_DEBUG
+ LOG(DEBUG) << "Creating per sdk data directory for: " << packageName;
+#endif
+
+ const char* uuid_ = uuid ? uuid->c_str() : nullptr;
+
+ // Prepare the sdk package directory in case it's missing
+ const auto status =
+ createSdkSandboxDataPackageDirectory(uuid, packageName, userId, appId, flags);
+ if (!status.isOk()) {
+ return status;
+ }
+
+ auto res = ok();
+ // We have to create sdk data for CE and DE storage
+ const int storageFlags[2] = {FLAG_STORAGE_CE, FLAG_STORAGE_DE};
+ for (int currentFlag : storageFlags) {
+ if ((flags & currentFlag) == 0) {
+ continue;
+ }
+ const bool isCeData = (currentFlag == FLAG_STORAGE_CE);
+
+ const auto packagePath = create_data_misc_sdk_sandbox_package_path(uuid_, isCeData, userId,
+ packageName.c_str());
+
+ // Remove existing sub-directories not referred in subDirNames
+ const std::unordered_set<std::string> expectedSubDirNames(subDirNames.begin(),
+ subDirNames.end());
+ const auto subDirHandler = [&packagePath, &expectedSubDirNames,
+ &res](const std::string& subDirName) {
+ // Remove the per-sdk directory if it is not referred in
+ // expectedSubDirNames
+ if (expectedSubDirNames.find(subDirName) == expectedSubDirNames.end()) {
+ auto path = packagePath + "/" + subDirName;
+ if (delete_dir_contents_and_dir(path) != 0) {
+ res = error("Failed to delete " + path);
+ return;
+ }
+ }
+ };
+ const int ec = foreach_subdir(packagePath, subDirHandler);
+ if (ec != 0) {
+ res = error("Failed to process subdirs for " + packagePath);
+ continue;
+ }
+
+ // Now create the subDirNames
+ for (const auto& subDirName : subDirNames) {
+ const std::string path =
+ create_data_misc_sdk_sandbox_sdk_path(uuid_, isCeData, userId,
+ packageName.c_str(), subDirName.c_str());
+
+ // Create the directory along with cache and code_cache
+ const int32_t cacheGid = multiuser_get_cache_gid(userId, appId);
+ if (cacheGid == -1) {
+ return exception(binder::Status::EX_ILLEGAL_STATE,
+ StringPrintf("cacheGid cannot be -1 for sdk data"));
+ }
+ const int32_t sandboxUid = multiuser_get_sdk_sandbox_uid(userId, appId);
+ int32_t previousSandboxUid = multiuser_get_sdk_sandbox_uid(userId, previousAppId);
+ int32_t appUid = multiuser_get_uid(userId, appId);
+ long projectIdApp = get_project_id(appUid, PROJECT_ID_APP_START);
+ long projectIdCache = get_project_id(appUid, PROJECT_ID_APP_CACHE_START);
+ auto status =
+ createAppDataDirs(path, sandboxUid, AID_NOBODY, previousSandboxUid, cacheGid,
+ seInfo, 0700 | S_ISGID, projectIdApp, projectIdCache);
+ if (!status.isOk()) {
+ res = status;
+ continue;
+ }
+ }
+ }
+
+ return res;
+}
+
binder::Status InstalldNativeService::migrateAppData(const std::optional<std::string>& uuid,
const std::string& packageName, int32_t userId, int32_t flags) {
ENFORCE_UID(AID_SYSTEM);
@@ -911,6 +1103,47 @@ binder::Status InstalldNativeService::clearAppData(const std::optional<std::stri
}
}
}
+ auto status = clearSdkSandboxDataPackageDirectory(uuid, packageName, userId, flags);
+ if (!status.isOk()) {
+ res = status;
+ }
+ return res;
+}
+
+binder::Status InstalldNativeService::clearSdkSandboxDataPackageDirectory(
+ const std::optional<std::string>& uuid, const std::string& packageName, int32_t userId,
+ int32_t flags) {
+ const char* uuid_ = uuid ? uuid->c_str() : nullptr;
+ const char* pkgname = packageName.c_str();
+
+ binder::Status res = ok();
+ constexpr int storageFlags[2] = {FLAG_STORAGE_CE, FLAG_STORAGE_DE};
+ for (int i = 0; i < 2; i++) {
+ int currentFlag = storageFlags[i];
+ if ((flags & currentFlag) == 0) {
+ continue;
+ }
+ bool isCeData = (currentFlag == FLAG_STORAGE_CE);
+ std::string suffix;
+ if (flags & FLAG_CLEAR_CACHE_ONLY) {
+ suffix = CACHE_DIR_POSTFIX;
+ } else if (flags & FLAG_CLEAR_CODE_CACHE_ONLY) {
+ suffix = CODE_CACHE_DIR_POSTFIX;
+ }
+
+ auto appPath = create_data_misc_sdk_sandbox_package_path(uuid_, isCeData, userId, pkgname);
+ if (access(appPath.c_str(), F_OK) != 0) continue;
+ const auto subDirHandler = [&appPath, &res, &suffix](const std::string& filename) {
+ auto filepath = appPath + "/" + filename + suffix;
+ if (delete_dir_contents(filepath, true) != 0) {
+ res = error("Failed to clear contents of " + filepath);
+ }
+ };
+ const int ec = foreach_subdir(appPath, subDirHandler);
+ if (ec != 0) {
+ res = error("Failed to process subdirs for " + appPath);
+ }
+ }
return res;
}
@@ -1007,6 +1240,32 @@ binder::Status InstalldNativeService::destroyAppData(const std::optional<std::st
}
}
}
+ auto status = destroySdkSandboxDataPackageDirectory(uuid, packageName, userId, flags);
+ if (!status.isOk()) {
+ res = status;
+ }
+ return res;
+}
+
+binder::Status InstalldNativeService::destroySdkSandboxDataPackageDirectory(
+ const std::optional<std::string>& uuid, const std::string& packageName, int32_t userId,
+ int32_t flags) {
+ const char* uuid_ = uuid ? uuid->c_str() : nullptr;
+ const char* pkgname = packageName.c_str();
+
+ binder::Status res = ok();
+ constexpr int storageFlags[2] = {FLAG_STORAGE_CE, FLAG_STORAGE_DE};
+ for (int i = 0; i < 2; i++) {
+ int currentFlag = storageFlags[i];
+ if ((flags & currentFlag) == 0) {
+ continue;
+ }
+ bool isCeData = (currentFlag == FLAG_STORAGE_CE);
+ auto appPath = create_data_misc_sdk_sandbox_package_path(uuid_, isCeData, userId, pkgname);
+ if (rename_delete_dir_contents_and_dir(appPath) != 0) {
+ res = error("Failed to delete " + appPath);
+ }
+ }
return res;
}
@@ -1492,6 +1751,36 @@ binder::Status InstalldNativeService::moveCompleteApp(const std::optional<std::s
}
}
+ // Copy sdk data for all known users
+ for (auto userId : users) {
+ LOCK_USER();
+
+ constexpr int storageFlags[2] = {FLAG_STORAGE_CE, FLAG_STORAGE_DE};
+ for (int currentFlag : storageFlags) {
+ const bool isCeData = currentFlag == FLAG_STORAGE_CE;
+
+ const auto from = create_data_misc_sdk_sandbox_package_path(from_uuid, isCeData, userId,
+ package_name);
+ if (access(from.c_str(), F_OK) != 0) {
+ LOG(INFO) << "Missing source " << from;
+ continue;
+ }
+ const auto to = create_data_misc_sdk_sandbox_path(to_uuid, isCeData, userId);
+
+ const int rc = copy_directory_recursive(from.c_str(), to.c_str());
+ if (rc != 0) {
+ res = error(rc, "Failed copying " + from + " to " + to);
+ goto fail;
+ }
+ }
+
+ if (!restoreconSdkDataLocked(toUuid, packageName, userId, FLAG_STORAGE_CE | FLAG_STORAGE_DE,
+ appId, seInfo)
+ .isOk()) {
+ res = error("Failed to restorecon");
+ goto fail;
+ }
+ }
// We let the framework scan the new location and persist that before
// deleting the data in the old location; this ordering ensures that
// we can recover from things like battery pulls.
@@ -1519,6 +1808,18 @@ fail:
}
}
}
+ for (auto userId : users) {
+ LOCK_USER();
+ constexpr int storageFlags[2] = {FLAG_STORAGE_CE, FLAG_STORAGE_DE};
+ for (int currentFlag : storageFlags) {
+ const bool isCeData = currentFlag == FLAG_STORAGE_CE;
+ const auto to = create_data_misc_sdk_sandbox_package_path(to_uuid, isCeData, userId,
+ package_name);
+ if (delete_dir_contents(to.c_str(), 1, nullptr) != 0) {
+ LOG(WARNING) << "Failed to rollback " << to;
+ }
+ }
+ }
return res;
}
@@ -1550,8 +1851,14 @@ binder::Status InstalldNativeService::destroyUserData(const std::optional<std::s
binder::Status res = ok();
if (flags & FLAG_STORAGE_DE) {
auto path = create_data_user_de_path(uuid_, userId);
- if (delete_dir_contents_and_dir(path, true) != 0) {
- res = error("Failed to delete " + path);
+ // Contents only, as vold is responsible for the user_de dir itself.
+ if (delete_dir_contents(path, true) != 0) {
+ res = error("Failed to delete contents of " + path);
+ }
+ auto sdk_sandbox_de_path =
+ create_data_misc_sdk_sandbox_path(uuid_, /*isCeData=*/false, userId);
+ if (delete_dir_contents_and_dir(sdk_sandbox_de_path, true) != 0) {
+ res = error("Failed to delete " + sdk_sandbox_de_path);
}
if (uuid_ == nullptr) {
path = create_data_misc_legacy_path(userId);
@@ -1566,12 +1873,19 @@ binder::Status InstalldNativeService::destroyUserData(const std::optional<std::s
}
if (flags & FLAG_STORAGE_CE) {
auto path = create_data_user_ce_path(uuid_, userId);
- if (delete_dir_contents_and_dir(path, true) != 0) {
- res = error("Failed to delete " + path);
+ // Contents only, as vold is responsible for the user_ce dir itself.
+ if (delete_dir_contents(path, true) != 0) {
+ res = error("Failed to delete contents of " + path);
+ }
+ auto sdk_sandbox_ce_path =
+ create_data_misc_sdk_sandbox_path(uuid_, /*isCeData=*/true, userId);
+ if (delete_dir_contents_and_dir(sdk_sandbox_ce_path, true) != 0) {
+ res = error("Failed to delete " + sdk_sandbox_ce_path);
}
path = findDataMediaPath(uuid, userId);
- if (delete_dir_contents_and_dir(path, true) != 0) {
- res = error("Failed to delete " + path);
+ // Contents only, as vold is responsible for the media dir itself.
+ if (delete_dir_contents(path, true) != 0) {
+ res = error("Failed to delete contents of " + path);
}
}
return res;
@@ -1808,69 +2122,78 @@ static std::string toString(std::vector<int64_t> values) {
return res.str();
}
#endif
+// On devices without sdcardfs, if internal and external are on
+// the same volume, a uid such as u0_a123 is used for both
+// internal and external storage; therefore, subtract that
+// amount from internal to make sure we don't count it double.
+// This needs to happen for data, cache and OBB
+static void deductDoubleSpaceIfNeeded(stats* stats, int64_t doubleSpaceToBeDeleted, uid_t uid,
+ const std::string& uuid) {
+ if (!supports_sdcardfs()) {
+ stats->dataSize -= doubleSpaceToBeDeleted;
+ long obbProjectId = get_project_id(uid, PROJECT_ID_EXT_OBB_START);
+ int64_t appObbSize = GetOccupiedSpaceForProjectId(uuid, obbProjectId);
+ stats->dataSize -= appObbSize;
+ }
+}
static void collectQuotaStats(const std::string& uuid, int32_t userId,
int32_t appId, struct stats* stats, struct stats* extStats) {
- int64_t space;
+ int64_t space, doubleSpaceToBeDeleted = 0;
uid_t uid = multiuser_get_uid(userId, appId);
- if (stats != nullptr) {
- if ((space = GetOccupiedSpaceForUid(uuid, uid)) != -1) {
- stats->dataSize += space;
- }
-
- int cacheGid = multiuser_get_cache_gid(userId, appId);
- if (cacheGid != -1) {
- if ((space = GetOccupiedSpaceForGid(uuid, cacheGid)) != -1) {
- stats->cacheSize += space;
- }
- }
-
- int sharedGid = multiuser_get_shared_gid(0, appId);
- if (sharedGid != -1) {
- if ((space = GetOccupiedSpaceForGid(uuid, sharedGid)) != -1) {
- stats->codeSize += space;
- }
- }
- }
+ static const bool supportsProjectId = internal_storage_has_project_id();
if (extStats != nullptr) {
- static const bool supportsSdCardFs = supports_sdcardfs();
space = get_occupied_app_space_external(uuid, userId, appId);
if (space != -1) {
extStats->dataSize += space;
- if (!supportsSdCardFs && stats != nullptr) {
- // On devices without sdcardfs, if internal and external are on
- // the same volume, a uid such as u0_a123 is used for
- // application dirs on both internal and external storage;
- // therefore, substract that amount from internal to make sure
- // we don't count it double.
- stats->dataSize -= space;
- }
+ doubleSpaceToBeDeleted += space;
}
space = get_occupied_app_cache_space_external(uuid, userId, appId);
if (space != -1) {
extStats->dataSize += space; // cache counts for "data"
extStats->cacheSize += space;
- if (!supportsSdCardFs && stats != nullptr) {
- // On devices without sdcardfs, if internal and external are on
- // the same volume, a uid such as u0_a123 is used for both
- // internal and external storage; therefore, substract that
- // amount from internal to make sure we don't count it double.
- stats->dataSize -= space;
+ doubleSpaceToBeDeleted += space;
+ }
+ }
+
+ if (stats != nullptr) {
+ if (!supportsProjectId) {
+ if ((space = GetOccupiedSpaceForUid(uuid, uid)) != -1) {
+ stats->dataSize += space;
+ }
+ deductDoubleSpaceIfNeeded(stats, doubleSpaceToBeDeleted, uid, uuid);
+ int sdkSandboxUid = multiuser_get_sdk_sandbox_uid(userId, appId);
+ if (sdkSandboxUid != -1) {
+ if ((space = GetOccupiedSpaceForUid(uuid, sdkSandboxUid)) != -1) {
+ stats->dataSize += space;
+ }
+ }
+ int cacheGid = multiuser_get_cache_gid(userId, appId);
+ if (cacheGid != -1) {
+ if ((space = GetOccupiedSpaceForGid(uuid, cacheGid)) != -1) {
+ stats->cacheSize += space;
+ }
+ }
+ } else {
+ long projectId = get_project_id(uid, PROJECT_ID_APP_START);
+ if ((space = GetOccupiedSpaceForProjectId(uuid, projectId)) != -1) {
+ stats->dataSize += space;
+ }
+ projectId = get_project_id(uid, PROJECT_ID_APP_CACHE_START);
+ if ((space = GetOccupiedSpaceForProjectId(uuid, projectId)) != -1) {
+ stats->cacheSize += space;
+ stats->dataSize += space;
}
}
- if (!supportsSdCardFs && stats != nullptr) {
- // On devices without sdcardfs, the UID of OBBs on external storage
- // matches the regular app UID (eg u0_a123); therefore, to avoid
- // OBBs being include in stats->dataSize, compute the OBB size for
- // this app, and substract it from the size reported on internal
- // storage
- long obbProjectId = uid - AID_APP_START + PROJECT_ID_EXT_OBB_START;
- int64_t appObbSize = GetOccupiedSpaceForProjectId(uuid, obbProjectId);
- stats->dataSize -= appObbSize;
+ int sharedGid = multiuser_get_shared_gid(0, appId);
+ if (sharedGid != -1) {
+ if ((space = GetOccupiedSpaceForGid(uuid, sharedGid)) != -1) {
+ stats->codeSize += space;
+ }
}
}
}
@@ -1925,8 +2248,17 @@ static void collectManualStats(const std::string& path, struct stats* stats) {
closedir(d);
}
+void collectManualStatsForSubDirectories(const std::string& path, struct stats* stats) {
+ const auto subDirHandler = [&path, &stats](const std::string& subDir) {
+ auto fullpath = path + "/" + subDir;
+ collectManualStats(fullpath, stats);
+ };
+ foreach_subdir(path, subDirHandler);
+}
+
static void collectManualStatsForUser(const std::string& path, struct stats* stats,
- bool exclude_apps = false) {
+ bool exclude_apps = false,
+ bool is_sdk_sandbox_storage = false) {
DIR *d;
int dfd;
struct dirent *de;
@@ -1951,6 +2283,11 @@ static void collectManualStatsForUser(const std::string& path, struct stats* sta
continue;
} else if (exclude_apps && (user_uid >= AID_APP_START && user_uid <= AID_APP_END)) {
continue;
+ } else if (is_sdk_sandbox_storage) {
+ // In case of sdk sandbox storage (e.g. /data/misc_ce/0/sdksandbox/<package-name>),
+ // collect individual stats of each subdirectory (shared, storage of each sdk etc.)
+ collectManualStatsForSubDirectories(StringPrintf("%s/%s", path.c_str(), name),
+ stats);
} else {
collectManualStats(StringPrintf("%s/%s", path.c_str(), name), stats);
}
@@ -1993,6 +2330,11 @@ static void collectManualExternalStatsForUser(const std::string& path, struct st
fts_close(fts);
}
static bool ownsExternalStorage(int32_t appId) {
+ // if project id calculation is supported then, there is no need to
+ // calculate in a different way and project_id based calculation can work
+ if (internal_storage_has_project_id()) {
+ return false;
+ }
// Fetch external storage owner appid and check if it is the same as the
// current appId whose size is calculated
struct stat s;
@@ -2093,6 +2435,19 @@ binder::Status InstalldNativeService::getAppSize(const std::optional<std::string
collectManualStats(dePath, &stats);
ATRACE_END();
+ // In case of sdk sandbox storage (e.g. /data/misc_ce/0/sdksandbox/<package-name>),
+ // collect individual stats of each subdirectory (shared, storage of each sdk etc.)
+ if (appId >= AID_APP_START && appId <= AID_APP_END) {
+ ATRACE_BEGIN("sdksandbox");
+ auto sdkSandboxCePath =
+ create_data_misc_sdk_sandbox_package_path(uuid_, true, userId, pkgname);
+ collectManualStatsForSubDirectories(sdkSandboxCePath, &stats);
+ auto sdkSandboxDePath =
+ create_data_misc_sdk_sandbox_package_path(uuid_, false, userId, pkgname);
+ collectManualStatsForSubDirectories(sdkSandboxDePath, &stats);
+ ATRACE_END();
+ }
+
if (!uuid) {
ATRACE_BEGIN("profiles");
calculate_tree_size(
@@ -2329,6 +2684,13 @@ binder::Status InstalldNativeService::getUserSize(const std::optional<std::strin
collectManualStatsForUser(dePath, &stats);
ATRACE_END();
+ ATRACE_BEGIN("sdksandbox");
+ auto sdkSandboxCePath = create_data_misc_sdk_sandbox_path(uuid_, true, userId);
+ collectManualStatsForUser(sdkSandboxCePath, &stats, false, true);
+ auto sdkSandboxDePath = create_data_misc_sdk_sandbox_path(uuid_, false, userId);
+ collectManualStatsForUser(sdkSandboxDePath, &stats, false, true);
+ ATRACE_END();
+
if (!uuid) {
ATRACE_BEGIN("profile");
auto userProfilePath = create_primary_cur_profile_dir_path(userId);
@@ -2850,6 +3212,49 @@ binder::Status InstalldNativeService::restoreconAppDataLocked(
return res;
}
+binder::Status InstalldNativeService::restoreconSdkDataLocked(
+ const std::optional<std::string>& uuid, const std::string& packageName, int32_t userId,
+ int32_t flags, int32_t appId, const std::string& seInfo) {
+ ENFORCE_UID(AID_SYSTEM);
+ CHECK_ARGUMENT_UUID(uuid);
+ CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+
+ binder::Status res = ok();
+
+ // SELINUX_ANDROID_RESTORECON_DATADATA flag is set by libselinux. Not needed here.
+ unsigned int seflags = SELINUX_ANDROID_RESTORECON_RECURSE;
+ const char* uuid_ = uuid ? uuid->c_str() : nullptr;
+ const char* pkgName = packageName.c_str();
+ const char* seinfo = seInfo.c_str();
+
+ uid_t uid = multiuser_get_sdk_sandbox_uid(userId, appId);
+ constexpr int storageFlags[2] = {FLAG_STORAGE_CE, FLAG_STORAGE_DE};
+ for (int currentFlag : storageFlags) {
+ if ((flags & currentFlag) == 0) {
+ continue;
+ }
+ const bool isCeData = (currentFlag == FLAG_STORAGE_CE);
+ const auto packagePath =
+ create_data_misc_sdk_sandbox_package_path(uuid_, isCeData, userId, pkgName);
+ if (access(packagePath.c_str(), F_OK) != 0) {
+ LOG(INFO) << "Missing source " << packagePath;
+ continue;
+ }
+ const auto subDirHandler = [&packagePath, &seinfo, &uid, &seflags,
+ &res](const std::string& subDir) {
+ const auto& fullpath = packagePath + "/" + subDir;
+ if (selinux_android_restorecon_pkgdir(fullpath.c_str(), seinfo, uid, seflags) < 0) {
+ res = error("restorecon failed for " + fullpath);
+ }
+ };
+ const auto ec = foreach_subdir(packagePath, subDirHandler);
+ if (ec != 0) {
+ res = error("Failed to restorecon for subdirs of " + packagePath);
+ }
+ }
+ return res;
+}
+
binder::Status InstalldNativeService::createOatDir(const std::string& oatDir,
const std::string& instructionSet) {
ENFORCE_UID(AID_SYSTEM);
@@ -2984,6 +3389,33 @@ binder::Status InstalldNativeService::hashSecondaryDexFile(
return result ? ok() : error();
}
+bool check_if_ioctl_feature_is_supported() {
+ bool result = false;
+ auto temp_path = StringPrintf("%smisc/installd/ioctl_check", android_data_dir.c_str());
+ if (access(temp_path.c_str(), F_OK) != 0) {
+ open(temp_path.c_str(), O_CREAT | O_TRUNC | O_RDWR | O_CLOEXEC, 0644);
+ result = set_quota_project_id(temp_path, 0, false) == 0;
+ // delete the temp file
+ // remove the external file
+ remove(temp_path.c_str());
+ }
+ return result;
+}
+
+binder::Status InstalldNativeService::setFirstBoot() {
+ ENFORCE_UID(AID_SYSTEM);
+ std::lock_guard<std::recursive_mutex> lock(mMountsLock);
+ std::string uuid;
+ if (GetOccupiedSpaceForProjectId(uuid, 0) != -1 && check_if_ioctl_feature_is_supported()) {
+ auto first_boot_path =
+ StringPrintf("%smisc/installd/using_project_ids", android_data_dir.c_str());
+ if (access(first_boot_path.c_str(), F_OK) != 0) {
+ open(first_boot_path.c_str(), O_CREAT | O_TRUNC | O_RDWR | O_CLOEXEC, 0644);
+ }
+ }
+ return ok();
+}
+
binder::Status InstalldNativeService::invalidateMounts() {
ENFORCE_UID(AID_SYSTEM);
std::lock_guard<std::recursive_mutex> lock(mMountsLock);
@@ -3187,11 +3619,17 @@ binder::Status InstalldNativeService::cleanupInvalidPackageDirs(
if (flags & FLAG_STORAGE_CE) {
auto ce_path = create_data_user_ce_path(uuid_cstr, userId);
cleanup_invalid_package_dirs_under_path(ce_path);
+ auto sdksandbox_ce_path =
+ create_data_misc_sdk_sandbox_path(uuid_cstr, /*isCeData=*/true, userId);
+ cleanup_invalid_package_dirs_under_path(sdksandbox_ce_path);
}
if (flags & FLAG_STORAGE_DE) {
auto de_path = create_data_user_de_path(uuid_cstr, userId);
cleanup_invalid_package_dirs_under_path(de_path);
+ auto sdksandbox_de_path =
+ create_data_misc_sdk_sandbox_path(uuid_cstr, /*isCeData=*/false, userId);
+ cleanup_invalid_package_dirs_under_path(sdksandbox_de_path);
}
return ok();
diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h
index 96783c3dbb..95ac51692d 100644
--- a/cmds/installd/InstalldNativeService.h
+++ b/cmds/installd/InstalldNativeService.h
@@ -47,14 +47,9 @@ public:
int32_t flags);
binder::Status createAppData(const std::optional<std::string>& uuid,
- const std::string& packageName, int32_t userId, int32_t flags, int32_t appId,
- int32_t previousAppId, const std::string& seInfo, int32_t targetSdkVersion,
- int64_t* _aidl_return);
- binder::Status createAppDataLocked(const std::optional<std::string>& uuid,
- const std::string& packageName, int32_t userId,
- int32_t flags, int32_t appId, int32_t previousAppId,
- const std::string& seInfo, int32_t targetSdkVersion,
- int64_t* _aidl_return);
+ const std::string& packageName, int32_t userId, int32_t flags,
+ int32_t appId, int32_t previousAppId, const std::string& seInfo,
+ int32_t targetSdkVersion, int64_t* _aidl_return);
binder::Status createAppData(
const android::os::CreateAppDataArgs& args,
@@ -63,12 +58,12 @@ public:
const std::vector<android::os::CreateAppDataArgs>& args,
std::vector<android::os::CreateAppDataResult>* _aidl_return);
+ binder::Status reconcileSdkData(const android::os::ReconcileSdkDataArgs& args);
+
binder::Status restoreconAppData(const std::optional<std::string>& uuid,
const std::string& packageName, int32_t userId, int32_t flags, int32_t appId,
const std::string& seInfo);
- binder::Status restoreconAppDataLocked(const std::optional<std::string>& uuid,
- const std::string& packageName, int32_t userId,
- int32_t flags, int32_t appId, const std::string& seInfo);
+
binder::Status migrateAppData(const std::optional<std::string>& uuid,
const std::string& packageName, int32_t userId, int32_t flags);
binder::Status clearAppData(const std::optional<std::string>& uuid,
@@ -172,6 +167,7 @@ public:
int32_t storageFlag, std::vector<uint8_t>* _aidl_return);
binder::Status invalidateMounts();
+ binder::Status setFirstBoot();
binder::Status isQuotaSupported(const std::optional<std::string>& volumeUuid,
bool* _aidl_return);
binder::Status tryMountDataMirror(const std::optional<std::string>& volumeUuid);
@@ -202,6 +198,34 @@ private:
std::unordered_map<uid_t, int64_t> mCacheQuotas;
std::string findDataMediaPath(const std::optional<std::string>& uuid, userid_t userid);
+
+ binder::Status createAppDataLocked(const std::optional<std::string>& uuid,
+ const std::string& packageName, int32_t userId,
+ int32_t flags, int32_t appId, int32_t previousAppId,
+ const std::string& seInfo, int32_t targetSdkVersion,
+ int64_t* _aidl_return);
+ binder::Status restoreconAppDataLocked(const std::optional<std::string>& uuid,
+ const std::string& packageName, int32_t userId,
+ int32_t flags, int32_t appId, const std::string& seInfo);
+
+ binder::Status createSdkSandboxDataPackageDirectory(const std::optional<std::string>& uuid,
+ const std::string& packageName,
+ int32_t userId, int32_t appId,
+ int32_t flags);
+ binder::Status clearSdkSandboxDataPackageDirectory(const std::optional<std::string>& uuid,
+ const std::string& packageName,
+ int32_t userId, int32_t flags);
+ binder::Status destroySdkSandboxDataPackageDirectory(const std::optional<std::string>& uuid,
+ const std::string& packageName,
+ int32_t userId, int32_t flags);
+ binder::Status reconcileSdkData(const std::optional<std::string>& uuid,
+ const std::string& packageName,
+ const std::vector<std::string>& subDirNames, int32_t userId,
+ int32_t appId, int32_t previousAppId, const std::string& seInfo,
+ int flags);
+ binder::Status restoreconSdkDataLocked(const std::optional<std::string>& uuid,
+ const std::string& packageName, int32_t userId,
+ int32_t flags, int32_t appId, const std::string& seInfo);
};
} // namespace installd
diff --git a/cmds/installd/TEST_MAPPING b/cmds/installd/TEST_MAPPING
index 3f0fb6d2ba..fc4cfc98dc 100644
--- a/cmds/installd/TEST_MAPPING
+++ b/cmds/installd/TEST_MAPPING
@@ -30,6 +30,14 @@
},
{
"name": "CtsCompilationTestCases"
+ },
+ {
+ "name": "SdkSandboxStorageHostTest",
+ "options": [
+ {
+ "exclude-annotation": "android.platform.test.annotations.LargeTest"
+ }
+ ]
}
]
}
diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl
index f4fd9a94de..c17c6bfce3 100644
--- a/cmds/installd/binder/android/os/IInstalld.aidl
+++ b/cmds/installd/binder/android/os/IInstalld.aidl
@@ -20,10 +20,12 @@ package android.os;
interface IInstalld {
void createUserData(@nullable @utf8InCpp String uuid, int userId, int userSerial, int flags);
void destroyUserData(@nullable @utf8InCpp String uuid, int userId, int flags);
-
+ void setFirstBoot();
android.os.CreateAppDataResult createAppData(in android.os.CreateAppDataArgs args);
android.os.CreateAppDataResult[] createAppDataBatched(in android.os.CreateAppDataArgs[] args);
+ void reconcileSdkData(in android.os.ReconcileSdkDataArgs args);
+
void restoreconAppData(@nullable @utf8InCpp String uuid, @utf8InCpp String packageName,
int userId, int flags, int appId, @utf8InCpp String seInfo);
void migrateAppData(@nullable @utf8InCpp String uuid, @utf8InCpp String packageName,
@@ -131,6 +133,7 @@ interface IInstalld {
const int FLAG_STORAGE_DE = 0x1;
const int FLAG_STORAGE_CE = 0x2;
const int FLAG_STORAGE_EXTERNAL = 0x4;
+ const int FLAG_STORAGE_SDK = 0x8;
const int FLAG_CLEAR_CACHE_ONLY = 0x10;
const int FLAG_CLEAR_CODE_CACHE_ONLY = 0x20;
diff --git a/cmds/installd/binder/android/os/ReconcileSdkDataArgs.aidl b/cmds/installd/binder/android/os/ReconcileSdkDataArgs.aidl
new file mode 100644
index 0000000000..583a36d580
--- /dev/null
+++ b/cmds/installd/binder/android/os/ReconcileSdkDataArgs.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+/** {@hide} */
+parcelable ReconcileSdkDataArgs {
+ @nullable @utf8InCpp String uuid;
+ @utf8InCpp String packageName;
+ @utf8InCpp List<String> subDirNames;
+ int userId;
+ int appId;
+ int previousAppId;
+ @utf8InCpp String seInfo;
+ int flags;
+}
diff --git a/cmds/installd/tests/Android.bp b/cmds/installd/tests/Android.bp
index e390babb57..b3baca5c41 100644
--- a/cmds/installd/tests/Android.bp
+++ b/cmds/installd/tests/Android.bp
@@ -26,6 +26,7 @@ cc_test {
"libasync_safe",
"libdiskusage",
"libext2_uuid",
+ "libgmock",
"libinstalld",
"liblog",
],
@@ -106,6 +107,7 @@ cc_test {
"libziparchive",
"liblog",
"liblogwrap",
+ "libc++fs",
],
test_config: "installd_service_test.xml",
diff --git a/cmds/installd/tests/installd_service_test.cpp b/cmds/installd/tests/installd_service_test.cpp
index 9702d42b14..effb4013f1 100644
--- a/cmds/installd/tests/installd_service_test.cpp
+++ b/cmds/installd/tests/installd_service_test.cpp
@@ -32,16 +32,20 @@
#include <android-base/stringprintf.h>
#include <cutils/properties.h>
#include <gtest/gtest.h>
+#include <filesystem>
+#include <fstream>
#include <android/content/pm/IPackageManagerNative.h>
#include <binder/IServiceManager.h>
#include "InstalldNativeService.h"
+#include "binder/Status.h"
#include "binder_test_utils.h"
#include "dexopt.h"
#include "globals.h"
#include "utils.h"
using android::base::StringPrintf;
+using std::filesystem::is_empty;
namespace android {
std::string get_package_name(uid_t uid) {
@@ -74,8 +78,20 @@ std::string get_package_name(uid_t uid) {
}
namespace installd {
-constexpr const char* kTestUuid = "TEST";
-constexpr const char* kTestPath = "/data/local/tmp/user/0";
+static constexpr const char* kTestUuid = "TEST";
+static const std::string kTestPath = "/data/local/tmp";
+static constexpr const uid_t kNobodyUid = 9999;
+static constexpr const uid_t kSystemUid = 1000;
+static constexpr const int32_t kTestUserId = 0;
+static constexpr const uid_t kTestAppId = 19999;
+static constexpr const int FLAG_STORAGE_SDK = InstalldNativeService::FLAG_STORAGE_SDK;
+static constexpr const int FLAG_CLEAR_CACHE_ONLY = InstalldNativeService::FLAG_CLEAR_CACHE_ONLY;
+static constexpr const int FLAG_CLEAR_CODE_CACHE_ONLY =
+ InstalldNativeService::FLAG_CLEAR_CODE_CACHE_ONLY;
+
+const gid_t kTestAppUid = multiuser_get_uid(kTestUserId, kTestAppId);
+const gid_t kTestCacheGid = multiuser_get_cache_gid(kTestUserId, kTestAppId);
+const uid_t kTestSdkSandboxUid = multiuser_get_sdk_sandbox_uid(kTestUserId, kTestAppId);
#define FLAG_FORCE InstalldNativeService::FLAG_FORCE
@@ -97,18 +113,18 @@ bool create_cache_path(char path[PKG_PATH_MAX], const char *src, const char *ins
return create_cache_path_default(path, src, instruction_set);
}
-static std::string get_full_path(const char* path) {
- return StringPrintf("%s/%s", kTestPath, path);
+static std::string get_full_path(const std::string& path) {
+ return StringPrintf("%s/%s", kTestPath.c_str(), path.c_str());
}
-static void mkdir(const char* path, uid_t owner, gid_t group, mode_t mode) {
+static void mkdir(const std::string& path, uid_t owner, gid_t group, mode_t mode) {
const std::string fullPath = get_full_path(path);
EXPECT_EQ(::mkdir(fullPath.c_str(), mode), 0);
EXPECT_EQ(::chown(fullPath.c_str(), owner, group), 0);
EXPECT_EQ(::chmod(fullPath.c_str(), mode), 0);
}
-static int create(const char* path, uid_t owner, gid_t group, mode_t mode) {
+static int create(const std::string& path, uid_t owner, gid_t group, mode_t mode) {
int fd = ::open(get_full_path(path).c_str(), O_RDWR | O_CREAT, mode);
EXPECT_NE(fd, -1);
EXPECT_EQ(::fchown(fd, owner, group), 0);
@@ -116,8 +132,8 @@ static int create(const char* path, uid_t owner, gid_t group, mode_t mode) {
return fd;
}
-static void touch(const char* path, uid_t owner, gid_t group, mode_t mode) {
- EXPECT_EQ(::close(create(path, owner, group, mode)), 0);
+static void touch(const std::string& path, uid_t owner, gid_t group, mode_t mode) {
+ EXPECT_EQ(::close(create(path.c_str(), owner, group, mode)), 0);
}
static int stat_gid(const char* path) {
@@ -132,7 +148,7 @@ static int stat_mode(const char* path) {
return buf.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO | S_ISGID);
}
-static bool exists(const char* path) {
+static bool exists(const std::string& path) {
return ::access(get_full_path(path).c_str(), F_OK) == 0;
}
@@ -155,8 +171,8 @@ static bool find_file(const char* path, Pred&& pred) {
return result;
}
-static bool exists_renamed_deleted_dir() {
- return find_file(kTestPath, [](const std::string& name, bool is_dir) {
+static bool exists_renamed_deleted_dir(const std::string& rootDirectory) {
+ return find_file((kTestPath + rootDirectory).c_str(), [](const std::string& name, bool is_dir) {
return is_dir && is_renamed_deleted_dir(name);
});
}
@@ -173,197 +189,205 @@ protected:
service = new InstalldNativeService();
testUuid = kTestUuid;
system("rm -rf /data/local/tmp/user");
+ system("rm -rf /data/local/tmp/misc_ce");
+ system("rm -rf /data/local/tmp/misc_de");
system("mkdir -p /data/local/tmp/user/0");
-
+ system("mkdir -p /data/local/tmp/misc_ce/0/sdksandbox");
+ system("mkdir -p /data/local/tmp/misc_de/0/sdksandbox");
init_globals_from_data_and_root();
}
virtual void TearDown() {
delete service;
system("rm -rf /data/local/tmp/user");
+ system("rm -rf /data/local/tmp/misc_ce");
+ system("rm -rf /data/local/tmp/misc_de");
}
};
TEST_F(ServiceTest, FixupAppData_Upgrade) {
LOG(INFO) << "FixupAppData_Upgrade";
- mkdir("com.example", 10000, 10000, 0700);
- mkdir("com.example/normal", 10000, 10000, 0700);
- mkdir("com.example/cache", 10000, 10000, 0700);
- touch("com.example/cache/file", 10000, 10000, 0700);
+ mkdir("user/0/com.example", 10000, 10000, 0700);
+ mkdir("user/0/com.example/normal", 10000, 10000, 0700);
+ mkdir("user/0/com.example/cache", 10000, 10000, 0700);
+ touch("user/0/com.example/cache/file", 10000, 10000, 0700);
service->fixupAppData(testUuid, 0);
- EXPECT_EQ(10000, stat_gid("com.example/normal"));
- EXPECT_EQ(20000, stat_gid("com.example/cache"));
- EXPECT_EQ(20000, stat_gid("com.example/cache/file"));
+ EXPECT_EQ(10000, stat_gid("user/0/com.example/normal"));
+ EXPECT_EQ(20000, stat_gid("user/0/com.example/cache"));
+ EXPECT_EQ(20000, stat_gid("user/0/com.example/cache/file"));
- EXPECT_EQ(0700, stat_mode("com.example/normal"));
- EXPECT_EQ(02771, stat_mode("com.example/cache"));
- EXPECT_EQ(0700, stat_mode("com.example/cache/file"));
+ EXPECT_EQ(0700, stat_mode("user/0/com.example/normal"));
+ EXPECT_EQ(02771, stat_mode("user/0/com.example/cache"));
+ EXPECT_EQ(0700, stat_mode("user/0/com.example/cache/file"));
}
TEST_F(ServiceTest, FixupAppData_Moved) {
LOG(INFO) << "FixupAppData_Moved";
- mkdir("com.example", 10000, 10000, 0700);
- mkdir("com.example/foo", 10000, 10000, 0700);
- touch("com.example/foo/file", 10000, 20000, 0700);
- mkdir("com.example/bar", 10000, 20000, 0700);
- touch("com.example/bar/file", 10000, 20000, 0700);
+ mkdir("user/0/com.example", 10000, 10000, 0700);
+ mkdir("user/0/com.example/foo", 10000, 10000, 0700);
+ touch("user/0/com.example/foo/file", 10000, 20000, 0700);
+ mkdir("user/0/com.example/bar", 10000, 20000, 0700);
+ touch("user/0/com.example/bar/file", 10000, 20000, 0700);
service->fixupAppData(testUuid, 0);
- EXPECT_EQ(10000, stat_gid("com.example/foo"));
- EXPECT_EQ(20000, stat_gid("com.example/foo/file"));
- EXPECT_EQ(10000, stat_gid("com.example/bar"));
- EXPECT_EQ(10000, stat_gid("com.example/bar/file"));
+ EXPECT_EQ(10000, stat_gid("user/0/com.example/foo"));
+ EXPECT_EQ(20000, stat_gid("user/0/com.example/foo/file"));
+ EXPECT_EQ(10000, stat_gid("user/0/com.example/bar"));
+ EXPECT_EQ(10000, stat_gid("user/0/com.example/bar/file"));
service->fixupAppData(testUuid, FLAG_FORCE);
- EXPECT_EQ(10000, stat_gid("com.example/foo"));
- EXPECT_EQ(10000, stat_gid("com.example/foo/file"));
- EXPECT_EQ(10000, stat_gid("com.example/bar"));
- EXPECT_EQ(10000, stat_gid("com.example/bar/file"));
+ EXPECT_EQ(10000, stat_gid("user/0/com.example/foo"));
+ EXPECT_EQ(10000, stat_gid("user/0/com.example/foo/file"));
+ EXPECT_EQ(10000, stat_gid("user/0/com.example/bar"));
+ EXPECT_EQ(10000, stat_gid("user/0/com.example/bar/file"));
}
TEST_F(ServiceTest, DestroyUserData) {
LOG(INFO) << "DestroyUserData";
- mkdir("com.example", 10000, 10000, 0700);
- mkdir("com.example/foo", 10000, 10000, 0700);
- touch("com.example/foo/file", 10000, 20000, 0700);
- mkdir("com.example/bar", 10000, 20000, 0700);
- touch("com.example/bar/file", 10000, 20000, 0700);
+ mkdir("user/0/com.example", 10000, 10000, 0700);
+ mkdir("user/0/com.example/foo", 10000, 10000, 0700);
+ touch("user/0/com.example/foo/file", 10000, 20000, 0700);
+ mkdir("user/0/com.example/bar", 10000, 20000, 0700);
+ touch("user/0/com.example/bar/file", 10000, 20000, 0700);
- EXPECT_TRUE(exists("com.example/foo"));
- EXPECT_TRUE(exists("com.example/foo/file"));
- EXPECT_TRUE(exists("com.example/bar"));
- EXPECT_TRUE(exists("com.example/bar/file"));
+ EXPECT_TRUE(exists("user/0/com.example/foo"));
+ EXPECT_TRUE(exists("user/0/com.example/foo/file"));
+ EXPECT_TRUE(exists("user/0/com.example/bar"));
+ EXPECT_TRUE(exists("user/0/com.example/bar/file"));
service->destroyUserData(testUuid, 0, FLAG_STORAGE_DE | FLAG_STORAGE_CE);
- EXPECT_FALSE(exists("com.example/foo"));
- EXPECT_FALSE(exists("com.example/foo/file"));
- EXPECT_FALSE(exists("com.example/bar"));
- EXPECT_FALSE(exists("com.example/bar/file"));
+ EXPECT_FALSE(exists("user/0/com.example/foo"));
+ EXPECT_FALSE(exists("user/0/com.example/foo/file"));
+ EXPECT_FALSE(exists("user/0/com.example/bar"));
+ EXPECT_FALSE(exists("user/0/com.example/bar/file"));
- EXPECT_FALSE(exists_renamed_deleted_dir());
+ EXPECT_FALSE(exists_renamed_deleted_dir("/user/0"));
}
TEST_F(ServiceTest, DestroyAppData) {
LOG(INFO) << "DestroyAppData";
- mkdir("com.example", 10000, 10000, 0700);
- mkdir("com.example/foo", 10000, 10000, 0700);
- touch("com.example/foo/file", 10000, 20000, 0700);
- mkdir("com.example/bar", 10000, 20000, 0700);
- touch("com.example/bar/file", 10000, 20000, 0700);
+ mkdir("user/0/com.example", 10000, 10000, 0700);
+ mkdir("user/0/com.example/foo", 10000, 10000, 0700);
+ touch("user/0/com.example/foo/file", 10000, 20000, 0700);
+ mkdir("user/0/com.example/bar", 10000, 20000, 0700);
+ touch("user/0/com.example/bar/file", 10000, 20000, 0700);
- EXPECT_TRUE(exists("com.example/foo"));
- EXPECT_TRUE(exists("com.example/foo/file"));
- EXPECT_TRUE(exists("com.example/bar"));
- EXPECT_TRUE(exists("com.example/bar/file"));
+ EXPECT_TRUE(exists("user/0/com.example/foo"));
+ EXPECT_TRUE(exists("user/0/com.example/foo/file"));
+ EXPECT_TRUE(exists("user/0/com.example/bar"));
+ EXPECT_TRUE(exists("user/0/com.example/bar/file"));
service->destroyAppData(testUuid, "com.example", 0, FLAG_STORAGE_DE | FLAG_STORAGE_CE, 0);
- EXPECT_FALSE(exists("com.example/foo"));
- EXPECT_FALSE(exists("com.example/foo/file"));
- EXPECT_FALSE(exists("com.example/bar"));
- EXPECT_FALSE(exists("com.example/bar/file"));
+ EXPECT_FALSE(exists("user/0/com.example/foo"));
+ EXPECT_FALSE(exists("user/0/com.example/foo/file"));
+ EXPECT_FALSE(exists("user/0/com.example/bar"));
+ EXPECT_FALSE(exists("user/0/com.example/bar/file"));
- EXPECT_FALSE(exists_renamed_deleted_dir());
+ EXPECT_FALSE(exists_renamed_deleted_dir("/user/0"));
}
TEST_F(ServiceTest, CleanupInvalidPackageDirs) {
LOG(INFO) << "CleanupInvalidPackageDirs";
- mkdir("5b14b6458a44==deleted==", 10000, 10000, 0700);
- mkdir("5b14b6458a44==deleted==/foo", 10000, 10000, 0700);
- touch("5b14b6458a44==deleted==/foo/file", 10000, 20000, 0700);
- mkdir("5b14b6458a44==deleted==/bar", 10000, 20000, 0700);
- touch("5b14b6458a44==deleted==/bar/file", 10000, 20000, 0700);
-
- auto fd = create("5b14b6458a44==deleted==/bar/opened_file", 10000, 20000, 0700);
-
- mkdir("b14b6458a44NOTdeleted", 10000, 10000, 0700);
- mkdir("b14b6458a44NOTdeleted/foo", 10000, 10000, 0700);
- touch("b14b6458a44NOTdeleted/foo/file", 10000, 20000, 0700);
- mkdir("b14b6458a44NOTdeleted/bar", 10000, 20000, 0700);
- touch("b14b6458a44NOTdeleted/bar/file", 10000, 20000, 0700);
-
- mkdir("com.example", 10000, 10000, 0700);
- mkdir("com.example/foo", 10000, 10000, 0700);
- touch("com.example/foo/file", 10000, 20000, 0700);
- mkdir("com.example/bar", 10000, 20000, 0700);
- touch("com.example/bar/file", 10000, 20000, 0700);
-
- mkdir("==deleted==", 10000, 10000, 0700);
- mkdir("==deleted==/foo", 10000, 10000, 0700);
- touch("==deleted==/foo/file", 10000, 20000, 0700);
- mkdir("==deleted==/bar", 10000, 20000, 0700);
- touch("==deleted==/bar/file", 10000, 20000, 0700);
-
- EXPECT_TRUE(exists("5b14b6458a44==deleted==/foo"));
- EXPECT_TRUE(exists("5b14b6458a44==deleted==/foo/file"));
- EXPECT_TRUE(exists("5b14b6458a44==deleted==/bar"));
- EXPECT_TRUE(exists("5b14b6458a44==deleted==/bar/file"));
- EXPECT_TRUE(exists("5b14b6458a44==deleted==/bar/opened_file"));
-
- EXPECT_TRUE(exists("b14b6458a44NOTdeleted/foo"));
- EXPECT_TRUE(exists("b14b6458a44NOTdeleted/foo/file"));
- EXPECT_TRUE(exists("b14b6458a44NOTdeleted/bar"));
- EXPECT_TRUE(exists("b14b6458a44NOTdeleted/bar/file"));
-
- EXPECT_TRUE(exists("com.example/foo"));
- EXPECT_TRUE(exists("com.example/foo/file"));
- EXPECT_TRUE(exists("com.example/bar"));
- EXPECT_TRUE(exists("com.example/bar/file"));
-
- EXPECT_TRUE(exists("==deleted==/foo"));
- EXPECT_TRUE(exists("==deleted==/foo/file"));
- EXPECT_TRUE(exists("==deleted==/bar"));
- EXPECT_TRUE(exists("==deleted==/bar/file"));
-
- EXPECT_TRUE(exists_renamed_deleted_dir());
-
- service->cleanupInvalidPackageDirs(testUuid, 0, FLAG_STORAGE_CE | FLAG_STORAGE_DE);
-
- EXPECT_EQ(::close(fd), 0);
-
- EXPECT_FALSE(exists("5b14b6458a44==deleted==/foo"));
- EXPECT_FALSE(exists("5b14b6458a44==deleted==/foo/file"));
- EXPECT_FALSE(exists("5b14b6458a44==deleted==/bar"));
- EXPECT_FALSE(exists("5b14b6458a44==deleted==/bar/file"));
- EXPECT_FALSE(exists("5b14b6458a44==deleted==/bar/opened_file"));
-
- EXPECT_TRUE(exists("b14b6458a44NOTdeleted/foo"));
- EXPECT_TRUE(exists("b14b6458a44NOTdeleted/foo/file"));
- EXPECT_TRUE(exists("b14b6458a44NOTdeleted/bar"));
- EXPECT_TRUE(exists("b14b6458a44NOTdeleted/bar/file"));
-
- EXPECT_TRUE(exists("com.example/foo"));
- EXPECT_TRUE(exists("com.example/foo/file"));
- EXPECT_TRUE(exists("com.example/bar"));
- EXPECT_TRUE(exists("com.example/bar/file"));
-
- EXPECT_FALSE(exists("==deleted==/foo"));
- EXPECT_FALSE(exists("==deleted==/foo/file"));
- EXPECT_FALSE(exists("==deleted==/bar"));
- EXPECT_FALSE(exists("==deleted==/bar/file"));
-
- EXPECT_FALSE(exists_renamed_deleted_dir());
+ std::string rootDirectoryPrefix[] = {"user/0", "misc_ce/0/sdksandbox", "misc_de/0/sdksandbox"};
+ for (auto& prefix : rootDirectoryPrefix) {
+ mkdir(prefix + "/5b14b6458a44==deleted==", 10000, 10000, 0700);
+ mkdir(prefix + "/5b14b6458a44==deleted==/foo", 10000, 10000, 0700);
+ touch(prefix + "/5b14b6458a44==deleted==/foo/file", 10000, 20000, 0700);
+ mkdir(prefix + "/5b14b6458a44==deleted==/bar", 10000, 20000, 0700);
+ touch(prefix + "/5b14b6458a44==deleted==/bar/file", 10000, 20000, 0700);
+
+ auto fd = create(prefix + "/5b14b6458a44==deleted==/bar/opened_file", 10000, 20000, 0700);
+
+ mkdir(prefix + "/b14b6458a44NOTdeleted", 10000, 10000, 0700);
+ mkdir(prefix + "/b14b6458a44NOTdeleted/foo", 10000, 10000, 0700);
+ touch(prefix + "/b14b6458a44NOTdeleted/foo/file", 10000, 20000, 0700);
+ mkdir(prefix + "/b14b6458a44NOTdeleted/bar", 10000, 20000, 0700);
+ touch(prefix + "/b14b6458a44NOTdeleted/bar/file", 10000, 20000, 0700);
+
+ mkdir(prefix + "/com.example", 10000, 10000, 0700);
+ mkdir(prefix + "/com.example/foo", 10000, 10000, 0700);
+ touch(prefix + "/com.example/foo/file", 10000, 20000, 0700);
+ mkdir(prefix + "/com.example/bar", 10000, 20000, 0700);
+ touch(prefix + "/com.example/bar/file", 10000, 20000, 0700);
+
+ mkdir(prefix + "/==deleted==", 10000, 10000, 0700);
+ mkdir(prefix + "/==deleted==/foo", 10000, 10000, 0700);
+ touch(prefix + "/==deleted==/foo/file", 10000, 20000, 0700);
+ mkdir(prefix + "/==deleted==/bar", 10000, 20000, 0700);
+ touch(prefix + "/==deleted==/bar/file", 10000, 20000, 0700);
+
+ EXPECT_TRUE(exists(prefix + "/5b14b6458a44==deleted==/foo"));
+ EXPECT_TRUE(exists(prefix + "/5b14b6458a44==deleted==/foo/file"));
+ EXPECT_TRUE(exists(prefix + "/5b14b6458a44==deleted==/bar"));
+ EXPECT_TRUE(exists(prefix + "/5b14b6458a44==deleted==/bar/file"));
+ EXPECT_TRUE(exists(prefix + "/5b14b6458a44==deleted==/bar/opened_file"));
+
+ EXPECT_TRUE(exists(prefix + "/b14b6458a44NOTdeleted/foo"));
+ EXPECT_TRUE(exists(prefix + "/b14b6458a44NOTdeleted/foo/file"));
+ EXPECT_TRUE(exists(prefix + "/b14b6458a44NOTdeleted/bar"));
+ EXPECT_TRUE(exists(prefix + "/b14b6458a44NOTdeleted/bar/file"));
+
+ EXPECT_TRUE(exists(prefix + "/com.example/foo"));
+ EXPECT_TRUE(exists(prefix + "/com.example/foo/file"));
+ EXPECT_TRUE(exists(prefix + "/com.example/bar"));
+ EXPECT_TRUE(exists(prefix + "/com.example/bar/file"));
+
+ EXPECT_TRUE(exists(prefix + "/==deleted==/foo"));
+ EXPECT_TRUE(exists(prefix + "/==deleted==/foo/file"));
+ EXPECT_TRUE(exists(prefix + "/==deleted==/bar"));
+ EXPECT_TRUE(exists(prefix + "/==deleted==/bar/file"));
+
+ EXPECT_TRUE(exists_renamed_deleted_dir("/" + prefix));
+
+ service->cleanupInvalidPackageDirs(testUuid, 0, FLAG_STORAGE_CE | FLAG_STORAGE_DE);
+
+ EXPECT_EQ(::close(fd), 0);
+
+ EXPECT_FALSE(exists(prefix + "/5b14b6458a44==deleted==/foo"));
+ EXPECT_FALSE(exists(prefix + "/5b14b6458a44==deleted==/foo/file"));
+ EXPECT_FALSE(exists(prefix + "/5b14b6458a44==deleted==/bar"));
+ EXPECT_FALSE(exists(prefix + "/5b14b6458a44==deleted==/bar/file"));
+ EXPECT_FALSE(exists(prefix + "/5b14b6458a44==deleted==/bar/opened_file"));
+
+ EXPECT_TRUE(exists(prefix + "/b14b6458a44NOTdeleted/foo"));
+ EXPECT_TRUE(exists(prefix + "/b14b6458a44NOTdeleted/foo/file"));
+ EXPECT_TRUE(exists(prefix + "/b14b6458a44NOTdeleted/bar"));
+ EXPECT_TRUE(exists(prefix + "/b14b6458a44NOTdeleted/bar/file"));
+
+ EXPECT_TRUE(exists(prefix + "/com.example/foo"));
+ EXPECT_TRUE(exists(prefix + "/com.example/foo/file"));
+ EXPECT_TRUE(exists(prefix + "/com.example/bar"));
+ EXPECT_TRUE(exists(prefix + "/com.example/bar/file"));
+
+ EXPECT_FALSE(exists(prefix + "/==deleted==/foo"));
+ EXPECT_FALSE(exists(prefix + "/==deleted==/foo/file"));
+ EXPECT_FALSE(exists(prefix + "/==deleted==/bar"));
+ EXPECT_FALSE(exists(prefix + "/==deleted==/bar/file"));
+
+ EXPECT_FALSE(exists_renamed_deleted_dir(prefix));
+ }
}
TEST_F(ServiceTest, HashSecondaryDex) {
LOG(INFO) << "HashSecondaryDex";
- mkdir("com.example", 10000, 10000, 0700);
- mkdir("com.example/foo", 10000, 10000, 0700);
- touch("com.example/foo/file", 10000, 20000, 0700);
+ mkdir("user/0/com.example", 10000, 10000, 0700);
+ mkdir("user/0/com.example/foo", 10000, 10000, 0700);
+ touch("user/0/com.example/foo/file", 10000, 20000, 0700);
std::vector<uint8_t> result;
- std::string dexPath = get_full_path("com.example/foo/file");
+ std::string dexPath = get_full_path("user/0/com.example/foo/file");
EXPECT_BINDER_SUCCESS(service->hashSecondaryDexFile(
dexPath, "com.example", 10000, testUuid, FLAG_STORAGE_CE, &result));
@@ -383,7 +407,7 @@ TEST_F(ServiceTest, HashSecondaryDex_NoSuch) {
LOG(INFO) << "HashSecondaryDex_NoSuch";
std::vector<uint8_t> result;
- std::string dexPath = get_full_path("com.example/foo/file");
+ std::string dexPath = get_full_path("user/0/com.example/foo/file");
EXPECT_BINDER_SUCCESS(service->hashSecondaryDexFile(
dexPath, "com.example", 10000, testUuid, FLAG_STORAGE_CE, &result));
@@ -393,12 +417,12 @@ TEST_F(ServiceTest, HashSecondaryDex_NoSuch) {
TEST_F(ServiceTest, HashSecondaryDex_Unreadable) {
LOG(INFO) << "HashSecondaryDex_Unreadable";
- mkdir("com.example", 10000, 10000, 0700);
- mkdir("com.example/foo", 10000, 10000, 0700);
- touch("com.example/foo/file", 10000, 20000, 0300);
+ mkdir("user/0/com.example", 10000, 10000, 0700);
+ mkdir("user/0/com.example/foo", 10000, 10000, 0700);
+ touch("user/0/com.example/foo/file", 10000, 20000, 0300);
std::vector<uint8_t> result;
- std::string dexPath = get_full_path("com.example/foo/file");
+ std::string dexPath = get_full_path("user/0/com.example/foo/file");
EXPECT_BINDER_SUCCESS(service->hashSecondaryDexFile(
dexPath, "com.example", 10000, testUuid, FLAG_STORAGE_CE, &result));
@@ -408,12 +432,12 @@ TEST_F(ServiceTest, HashSecondaryDex_Unreadable) {
TEST_F(ServiceTest, HashSecondaryDex_WrongApp) {
LOG(INFO) << "HashSecondaryDex_WrongApp";
- mkdir("com.example", 10000, 10000, 0700);
- mkdir("com.example/foo", 10000, 10000, 0700);
- touch("com.example/foo/file", 10000, 20000, 0700);
+ mkdir("user/0/com.example", 10000, 10000, 0700);
+ mkdir("user/0/com.example/foo", 10000, 10000, 0700);
+ touch("user/0/com.example/foo/file", 10000, 20000, 0700);
std::vector<uint8_t> result;
- std::string dexPath = get_full_path("com.example/foo/file");
+ std::string dexPath = get_full_path("user/0/com.example/foo/file");
EXPECT_BINDER_FAIL(service->hashSecondaryDexFile(
dexPath, "com.wrong", 10000, testUuid, FLAG_STORAGE_CE, &result));
}
@@ -441,7 +465,7 @@ TEST_F(ServiceTest, CalculateCache) {
EXPECT_TRUE(create_cache_path(buf, "/path/to/file.apk", "isa"));
EXPECT_EQ("/data/dalvik-cache/isa/path@to@file.apk@classes.dex", std::string(buf));
}
-TEST_F(ServiceTest, GetAppSize) {
+TEST_F(ServiceTest, GetAppSizeManualForMedia) {
struct stat s;
std::string externalPicDir =
@@ -485,6 +509,100 @@ TEST_F(ServiceTest, GetAppSize) {
system(removeCommand.c_str());
}
}
+// TEST_F(ServiceTest, GetAppSizeProjectID_UID) {
+// struct stat s;
+// std::string externalPicDir =
+// StringPrintf("%s/Pictures", create_data_media_path(nullptr, 0).c_str());
+// if (stat(externalPicDir.c_str(), &s) == 0) {
+// // fetch the appId from the uid of the external storage owning app
+// int32_t externalStorageAppId = multiuser_get_app_id(s.st_uid);
+// // Fetch Package Name for the external storage owning app uid
+// std::string pkg = get_package_name(s.st_uid);
+//
+// std::vector<int64_t> externalStorageSize, externalStorageSizeAfterAddingCacheFile;
+// std::vector<int64_t> ceDataInodes;
+//
+// std::vector<std::string> codePaths;
+// std::vector<std::string> packageNames;
+// // set up parameters
+// packageNames.push_back(pkg);
+// ceDataInodes.push_back(0);
+// // initialise the mounts
+// service->invalidateMounts();
+// auto using_project_ids =
+// StringPrintf("%smisc/installd/using_project_ids", android_data_dir.c_str());
+// bool usingProjectIds = access(using_project_ids.c_str(), F_OK) == 0;
+// if (!usingProjectIds) {
+// service->setFirstBoot();
+// }
+//
+// if (access(using_project_ids.c_str(), F_OK) != 0) {
+// // projectids is not used, so check that ioctl features should be absent
+// auto temp_path = StringPrintf("%smisc/installd/ioctl_check",
+// android_data_dir.c_str());
+//
+// if (access(temp_path.c_str(), F_OK) != 0) {
+// open(temp_path.c_str(), O_CREAT | O_TRUNC | O_RDWR | O_CLOEXEC, 0644);
+// bool result = set_quota_project_id(temp_path, 0, false) == 0;
+// // delete the temp file
+// // remove the external file
+// remove(temp_path.c_str());
+// // since using_project_ids file is not present, so ioctl settings should be
+// absent
+// // that is denoted by the result of setting project id flag as false
+// ASSERT_FALSE(result);
+// }
+// }
+// // call the getAppSize to get the current size of the external storage owning app
+// service->getAppSize(std::nullopt, packageNames, 0, InstalldNativeService::FLAG_USE_QUOTA,
+// externalStorageAppId, ceDataInodes, codePaths, &externalStorageSize);
+// // add a file with 20MB size to the external storage
+// std::string externalStorageCacheDir =
+// StringPrintf("%s/%s/cache", create_data_user_ce_path(nullptr, 0).c_str(),
+// pkg.c_str());
+// std::string cacheFileLocation =
+// StringPrintf("%s/%s", externalStorageCacheDir.c_str(), "External.jpg");
+// std::string externalFileContentCommand =
+// StringPrintf("dd if=/dev/zero of=%s bs=1M count=20", cacheFileLocation.c_str());
+// system(externalFileContentCommand.c_str());
+// // call the getAppSize again to get the new size of the external storage owning app
+// service->getAppSize(std::nullopt, packageNames, 0, InstalldNativeService::FLAG_USE_QUOTA,
+// externalStorageAppId, ceDataInodes, codePaths,
+// &externalStorageSizeAfterAddingCacheFile);
+// // check that the size of cache and data increases when cache file is added
+// int64_t sizeDiffData = externalStorageSizeAfterAddingCacheFile[1] -
+// externalStorageSize[1]; int64_t sizeDiffCache =
+// externalStorageSizeAfterAddingCacheFile[2] - externalStorageSize[2];
+// ASSERT_TRUE(sizeDiffData == sizeDiffCache);
+// // remove the external file
+// std::string removeCommand = StringPrintf("rm -f %s", cacheFileLocation.c_str());
+// system(removeCommand.c_str());
+// // remove the setFirstBoot setting
+// std::string removeCommand2 = "rm -f /data/misc/installd/using_project_ids";
+// system(removeCommand2.c_str());
+// // Do now without project id
+// std::vector<int64_t> sizeWithUID, sizeWithUIDAfterAddingCacheFile;
+// // call the getAppSize to get the current size of the external storage owning app
+// service->getAppSize(std::nullopt, packageNames, 0, InstalldNativeService::FLAG_USE_QUOTA,
+// externalStorageAppId, ceDataInodes, codePaths, &sizeWithUID);
+// // add a file with 20MB size to the external storage
+// system(externalFileContentCommand.c_str());
+// // call the getAppSize again to get the new size of the external storage owning app
+// service->getAppSize(std::nullopt, packageNames, 0, InstalldNativeService::FLAG_USE_QUOTA,
+// externalStorageAppId, ceDataInodes, codePaths,
+// &sizeWithUIDAfterAddingCacheFile);
+// // check that the size of cache and data increases when cache file is added
+// sizeDiffData = sizeWithUIDAfterAddingCacheFile[1] - sizeWithUID[1];
+// sizeDiffCache = sizeWithUIDAfterAddingCacheFile[2] - sizeWithUID[2];
+// ASSERT_TRUE(sizeDiffData == sizeDiffCache);
+// // remove the external file
+// system(removeCommand.c_str());
+// // reset the using_project_id if it was initially set
+// if (usingProjectIds) {
+// service->setFirstBoot();
+// }
+// }
+// }
TEST_F(ServiceTest, GetAppSizeWrongSizes) {
int32_t externalStorageAppId = -1;
std::vector<int64_t> externalStorageSize;
@@ -943,5 +1061,364 @@ TEST_F(AppDataSnapshotTest, RestoreAppDataSnapshot_WrongVolumeUuid) {
"com.foo", 10000, "", 0, 41, FLAG_STORAGE_DE));
}
+class SdkSandboxDataTest : public testing::Test {
+public:
+ void CheckFileAccess(const std::string& path, uid_t uid, gid_t gid, mode_t mode) {
+ const auto fullPath = "/data/local/tmp/" + path;
+ ASSERT_TRUE(exists(fullPath.c_str())) << "For path: " << fullPath;
+ struct stat st;
+ ASSERT_EQ(0, stat(fullPath.c_str(), &st));
+ ASSERT_EQ(uid, st.st_uid) << "For path: " << fullPath;
+ ASSERT_EQ(gid, st.st_gid) << "For path: " << fullPath;
+ ASSERT_EQ(mode, st.st_mode) << "For path: " << fullPath;
+ }
+
+ bool exists(const char* path) { return ::access(path, F_OK) == 0; }
+
+ // Creates a default CreateAppDataArgs object
+ android::os::CreateAppDataArgs createAppDataArgs(const std::string& packageName) {
+ android::os::CreateAppDataArgs args;
+ args.uuid = kTestUuid;
+ args.packageName = packageName;
+ args.userId = kTestUserId;
+ args.appId = kTestAppId;
+ args.seInfo = "default";
+ args.flags = FLAG_STORAGE_CE | FLAG_STORAGE_DE | FLAG_STORAGE_SDK;
+ return args;
+ }
+
+ android::os::ReconcileSdkDataArgs reconcileSdkDataArgs(
+ const std::string& packageName, const std::vector<std::string>& subDirNames) {
+ android::os::ReconcileSdkDataArgs args;
+ args.uuid = kTestUuid;
+ args.packageName = packageName;
+ for (const auto& subDirName : subDirNames) {
+ args.subDirNames.push_back(subDirName);
+ }
+ args.userId = kTestUserId;
+ args.appId = kTestAppId;
+ args.previousAppId = -1;
+ args.seInfo = "default";
+ args.flags = FLAG_STORAGE_CE | FLAG_STORAGE_DE;
+ return args;
+ }
+
+protected:
+ InstalldNativeService* service;
+
+ virtual void SetUp() {
+ setenv("ANDROID_LOG_TAGS", "*:v", 1);
+ android::base::InitLogging(nullptr);
+
+ service = new InstalldNativeService();
+ clearAppData();
+ ASSERT_TRUE(mkdirs("/data/local/tmp/user/0", 0700));
+ ASSERT_TRUE(mkdirs("/data/local/tmp/user_de/0", 0700));
+ ASSERT_TRUE(mkdirs("/data/local/tmp/misc_ce/0/sdksandbox", 0700));
+ ASSERT_TRUE(mkdirs("/data/local/tmp/misc_de/0/sdksandbox", 0700));
+
+ init_globals_from_data_and_root();
+ }
+
+ virtual void TearDown() {
+ delete service;
+ clearAppData();
+ }
+
+private:
+ void clearAppData() {
+ ASSERT_EQ(0, delete_dir_contents_and_dir("/data/local/tmp/user", true));
+ ASSERT_EQ(0, delete_dir_contents_and_dir("/data/local/tmp/user_de", true));
+ ASSERT_EQ(0, delete_dir_contents_and_dir("/data/local/tmp/misc_ce", true));
+ ASSERT_EQ(0, delete_dir_contents_and_dir("/data/local/tmp/misc_de", true));
+ }
+};
+
+TEST_F(SdkSandboxDataTest, CreateAppData_CreatesSdkPackageData) {
+ android::os::CreateAppDataResult result;
+ android::os::CreateAppDataArgs args = createAppDataArgs("com.foo");
+
+ // Create the app user data.
+ ASSERT_BINDER_SUCCESS(service->createAppData(args, &result));
+
+ const std::string fooCePath = "misc_ce/0/sdksandbox/com.foo";
+ CheckFileAccess(fooCePath, kSystemUid, kSystemUid, S_IFDIR | 0751);
+
+ const std::string fooDePath = "misc_de/0/sdksandbox/com.foo";
+ CheckFileAccess(fooDePath, kSystemUid, kSystemUid, S_IFDIR | 0751);
+}
+
+TEST_F(SdkSandboxDataTest, CreateAppData_CreatesSdkPackageData_WithoutSdkFlag) {
+ android::os::CreateAppDataResult result;
+ android::os::CreateAppDataArgs args = createAppDataArgs("com.foo");
+ args.flags = FLAG_STORAGE_CE | FLAG_STORAGE_DE;
+
+ // Create the app user data.
+ ASSERT_BINDER_SUCCESS(service->createAppData(args, &result));
+
+ ASSERT_FALSE(exists("/data/local/tmp/misc_ce/0/sdksandbox/com.foo"));
+ ASSERT_FALSE(exists("/data/local/tmp/misc_de/0/sdksandbox/com.foo"));
+}
+
+TEST_F(SdkSandboxDataTest, CreateAppData_CreatesSdkPackageData_WithoutSdkFlagDeletesExisting) {
+ android::os::CreateAppDataResult result;
+ android::os::CreateAppDataArgs args = createAppDataArgs("com.foo");
+ // Create the app user data.
+ ASSERT_BINDER_SUCCESS(service->createAppData(args, &result));
+ ASSERT_TRUE(exists("/data/local/tmp/misc_ce/0/sdksandbox/com.foo"));
+ ASSERT_TRUE(exists("/data/local/tmp/misc_de/0/sdksandbox/com.foo"));
+
+ args.flags = FLAG_STORAGE_CE | FLAG_STORAGE_DE;
+ ASSERT_BINDER_SUCCESS(service->createAppData(args, &result));
+ ASSERT_FALSE(exists("/data/local/tmp/misc_ce/0/sdksandbox/com.foo"));
+ ASSERT_FALSE(exists("/data/local/tmp/misc_de/0/sdksandbox/com.foo"));
+}
+
+TEST_F(SdkSandboxDataTest, CreateAppData_CreatesSdkPackageData_WithoutDeFlag) {
+ android::os::CreateAppDataResult result;
+ android::os::CreateAppDataArgs args = createAppDataArgs("com.foo");
+ args.flags = FLAG_STORAGE_CE | FLAG_STORAGE_SDK;
+
+ // Create the app user data.
+ ASSERT_BINDER_SUCCESS(service->createAppData(args, &result));
+
+ // Only CE paths should exist
+ CheckFileAccess("misc_ce/0/sdksandbox/com.foo", kSystemUid, kSystemUid, S_IFDIR | 0751);
+
+ // DE paths should not exist
+ ASSERT_FALSE(exists("/data/local/tmp/misc_de/0/sdksandbox/com.foo"));
+}
+
+TEST_F(SdkSandboxDataTest, CreateAppData_CreatesSdkPackageData_WithoutCeFlag) {
+ android::os::CreateAppDataResult result;
+ android::os::CreateAppDataArgs args = createAppDataArgs("com.foo");
+ args.flags = FLAG_STORAGE_DE | FLAG_STORAGE_SDK;
+
+ // Create the app user data.
+ ASSERT_BINDER_SUCCESS(service->createAppData(args, &result));
+
+ // CE paths should not exist
+ ASSERT_FALSE(exists("/data/local/tmp/misc_ce/0/sdksandbox/com.foo"));
+
+ // Only DE paths should exist
+ CheckFileAccess("misc_de/0/sdksandbox/com.foo", kSystemUid, kSystemUid, S_IFDIR | 0751);
+}
+
+TEST_F(SdkSandboxDataTest, ReconcileSdkData) {
+ android::os::ReconcileSdkDataArgs args =
+ reconcileSdkDataArgs("com.foo", {"bar@random1", "baz@random2"});
+
+ // Create the sdk data.
+ ASSERT_BINDER_SUCCESS(service->reconcileSdkData(args));
+
+ const std::string barCePath = "misc_ce/0/sdksandbox/com.foo/bar@random1";
+ CheckFileAccess(barCePath, kTestSdkSandboxUid, kNobodyUid, S_IFDIR | S_ISGID | 0700);
+ CheckFileAccess(barCePath + "/cache", kTestSdkSandboxUid, kTestCacheGid,
+ S_IFDIR | S_ISGID | 0771);
+ CheckFileAccess(barCePath + "/code_cache", kTestSdkSandboxUid, kTestCacheGid,
+ S_IFDIR | S_ISGID | 0771);
+
+ const std::string bazCePath = "misc_ce/0/sdksandbox/com.foo/baz@random2";
+ CheckFileAccess(bazCePath, kTestSdkSandboxUid, kNobodyUid, S_IFDIR | S_ISGID | 0700);
+ CheckFileAccess(bazCePath + "/cache", kTestSdkSandboxUid, kTestCacheGid,
+ S_IFDIR | S_ISGID | 0771);
+ CheckFileAccess(bazCePath + "/code_cache", kTestSdkSandboxUid, kTestCacheGid,
+ S_IFDIR | S_ISGID | 0771);
+
+ const std::string barDePath = "misc_de/0/sdksandbox/com.foo/bar@random1";
+ CheckFileAccess(barDePath, kTestSdkSandboxUid, kNobodyUid, S_IFDIR | S_ISGID | 0700);
+ CheckFileAccess(barDePath + "/cache", kTestSdkSandboxUid, kTestCacheGid,
+ S_IFDIR | S_ISGID | 0771);
+ CheckFileAccess(barDePath + "/code_cache", kTestSdkSandboxUid, kTestCacheGid,
+ S_IFDIR | S_ISGID | 0771);
+
+ const std::string bazDePath = "misc_de/0/sdksandbox/com.foo/baz@random2";
+ CheckFileAccess(bazDePath, kTestSdkSandboxUid, kNobodyUid, S_IFDIR | S_ISGID | 0700);
+ CheckFileAccess(bazDePath + "/cache", kTestSdkSandboxUid, kTestCacheGid,
+ S_IFDIR | S_ISGID | 0771);
+ CheckFileAccess(bazDePath + "/code_cache", kTestSdkSandboxUid, kTestCacheGid,
+ S_IFDIR | S_ISGID | 0771);
+}
+
+TEST_F(SdkSandboxDataTest, ReconcileSdkData_ExtraCodeDirectoriesAreDeleted) {
+ android::os::ReconcileSdkDataArgs args =
+ reconcileSdkDataArgs("com.foo", {"bar@random1", "baz@random2"});
+
+ // Create the sdksandbox data.
+ ASSERT_BINDER_SUCCESS(service->reconcileSdkData(args));
+
+ // Retry with different package name
+ args.subDirNames[0] = "bar.diff@random1";
+
+ // Create the sdksandbox data again
+ ASSERT_BINDER_SUCCESS(service->reconcileSdkData(args));
+
+ // New directoris should exist
+ CheckFileAccess("misc_ce/0/sdksandbox/com.foo/bar.diff@random1", kTestSdkSandboxUid, kNobodyUid,
+ S_IFDIR | S_ISGID | 0700);
+ CheckFileAccess("misc_ce/0/sdksandbox/com.foo/baz@random2", kTestSdkSandboxUid, kNobodyUid,
+ S_IFDIR | S_ISGID | 0700);
+ // Directory for old unreferred sdksandbox package name should be removed
+ ASSERT_FALSE(exists("/data/local/tmp/misc_ce/0/sdksandbox/com.foo/bar@random1"));
+}
+
+class DestroyAppDataTest : public SdkSandboxDataTest {};
+
+TEST_F(DestroyAppDataTest, DestroySdkSandboxDataDirectories_WithCeAndDeFlag) {
+ android::os::CreateAppDataResult result;
+ android::os::CreateAppDataArgs args = createAppDataArgs("com.foo");
+ args.packageName = "com.foo";
+ // Create the app user data.
+ ASSERT_BINDER_SUCCESS(service->createAppData(args, &result));
+ // Destroy the app user data.
+ ASSERT_BINDER_SUCCESS(service->destroyAppData(args.uuid, args.packageName, args.userId,
+ args.flags, result.ceDataInode));
+ ASSERT_FALSE(exists("/data/local/tmp/misc_ce/0/sdksandbox/com.foo"));
+ ASSERT_FALSE(exists("/data/local/tmp/misc_de/0/sdksandbox/com.foo"));
+}
+
+TEST_F(DestroyAppDataTest, DestroySdkSandboxDataDirectories_WithoutDeFlag) {
+ android::os::CreateAppDataResult result;
+ android::os::CreateAppDataArgs args = createAppDataArgs("com.foo");
+ args.packageName = "com.foo";
+ // Create the app user data.
+ ASSERT_BINDER_SUCCESS(service->createAppData(args, &result));
+ // Destroy the app user data.
+ ASSERT_BINDER_SUCCESS(service->destroyAppData(args.uuid, args.packageName, args.userId,
+ FLAG_STORAGE_CE, result.ceDataInode));
+ ASSERT_TRUE(exists("/data/local/tmp/misc_de/0/sdksandbox/com.foo"));
+ ASSERT_FALSE(exists("/data/local/tmp/misc_ce/0/sdksandbox/com.foo"));
+}
+
+TEST_F(DestroyAppDataTest, DestroySdkSandboxDataDirectories_WithoutCeFlag) {
+ android::os::CreateAppDataResult result;
+ android::os::CreateAppDataArgs args = createAppDataArgs("com.foo");
+ args.packageName = "com.foo";
+ // Create the app user data.
+ ASSERT_BINDER_SUCCESS(service->createAppData(args, &result));
+ // Destroy the app user data.
+ ASSERT_BINDER_SUCCESS(service->destroyAppData(args.uuid, args.packageName, args.userId,
+ FLAG_STORAGE_DE, result.ceDataInode));
+ ASSERT_TRUE(exists("/data/local/tmp/misc_ce/0/sdksandbox/com.foo"));
+ ASSERT_FALSE(exists("/data/local/tmp/misc_de/0/sdksandbox/com.foo"));
+}
+
+class ClearAppDataTest : public SdkSandboxDataTest {
+public:
+ void createTestSdkData(const std::string& packageName, std::vector<std::string> sdkNames) {
+ const auto& cePackagePath = "/data/local/tmp/misc_ce/0/sdksandbox/" + packageName;
+ const auto& dePackagePath = "/data/local/tmp/misc_de/0/sdksandbox/" + packageName;
+ ASSERT_TRUE(mkdirs(cePackagePath, 0700));
+ ASSERT_TRUE(mkdirs(dePackagePath, 0700));
+ const std::vector<std::string> packagePaths = {cePackagePath, dePackagePath};
+ for (const auto& packagePath : packagePaths) {
+ for (auto sdkName : sdkNames) {
+ ASSERT_TRUE(mkdirs(packagePath + "/" + sdkName + "/cache", 0700));
+ ASSERT_TRUE(mkdirs(packagePath + "/" + sdkName + "/code_cache", 0700));
+ std::ofstream{packagePath + "/" + sdkName + "/cache/cachedTestData.txt"};
+ std::ofstream{packagePath + "/" + sdkName + "/code_cache/cachedTestData.txt"};
+ }
+ }
+ }
+};
+
+TEST_F(ClearAppDataTest, ClearSdkSandboxDataDirectories_WithCeAndClearCacheFlag) {
+ createTestSdkData("com.foo", {"shared", "sdk1", "sdk2"});
+ // Clear the app user data.
+ ASSERT_BINDER_SUCCESS(service->clearAppData(kTestUuid, "com.foo", 0,
+ FLAG_STORAGE_CE | FLAG_CLEAR_CACHE_ONLY, -1));
+
+ const std::string packagePath = kTestPath + "/misc_ce/0/sdksandbox/com.foo";
+ ASSERT_TRUE(is_empty(packagePath + "/shared/cache"));
+ ASSERT_TRUE(is_empty(packagePath + "/sdk1/cache"));
+ ASSERT_TRUE(is_empty(packagePath + "/sdk2/cache"));
+}
+
+TEST_F(ClearAppDataTest, ClearSdkSandboxDataDirectories_WithCeAndClearCodeCacheFlag) {
+ createTestSdkData("com.foo", {"shared", "sdk1", "sdk2"});
+ // Clear the app user data.
+ ASSERT_BINDER_SUCCESS(service->clearAppData(kTestUuid, "com.foo", 0,
+ FLAG_STORAGE_CE | FLAG_CLEAR_CODE_CACHE_ONLY, -1));
+
+ const std::string packagePath = kTestPath + "/misc_ce/0/sdksandbox/com.foo";
+ ASSERT_TRUE(is_empty(packagePath + "/shared/code_cache"));
+ ASSERT_TRUE(is_empty(packagePath + "/sdk1/code_cache"));
+ ASSERT_TRUE(is_empty(packagePath + "/sdk2/code_cache"));
+}
+
+TEST_F(ClearAppDataTest, ClearSdkSandboxDataDirectories_WithDeAndClearCacheFlag) {
+ createTestSdkData("com.foo", {"shared", "sdk1", "sdk2"});
+ // Clear the app user data
+ ASSERT_BINDER_SUCCESS(
+ service->clearAppData(kTestUuid, "com.foo", 0,
+ FLAG_STORAGE_DE | (InstalldNativeService::FLAG_CLEAR_CACHE_ONLY),
+ -1));
+
+ const std::string packagePath = kTestPath + "/misc_de/0/sdksandbox/com.foo";
+ ASSERT_TRUE(is_empty(packagePath + "/shared/cache"));
+ ASSERT_TRUE(is_empty(packagePath + "/sdk1/cache"));
+ ASSERT_TRUE(is_empty(packagePath + "/sdk2/cache"));
+}
+
+TEST_F(ClearAppDataTest, ClearSdkSandboxDataDirectories_WithDeAndClearCodeCacheFlag) {
+ createTestSdkData("com.foo", {"shared", "sdk1", "sdk2"});
+ // Clear the app user data.
+ ASSERT_BINDER_SUCCESS(service->clearAppData(kTestUuid, "com.foo", 0,
+ FLAG_STORAGE_DE | FLAG_CLEAR_CODE_CACHE_ONLY, -1));
+
+ const std::string packagePath = kTestPath + "/misc_de/0/sdksandbox/com.foo";
+ ASSERT_TRUE(is_empty(packagePath + "/shared/code_cache"));
+ ASSERT_TRUE(is_empty(packagePath + "/sdk1/code_cache"));
+ ASSERT_TRUE(is_empty(packagePath + "/sdk2/code_cache"));
+}
+
+TEST_F(ClearAppDataTest, ClearSdkSandboxDataDirectories_WithCeAndWithoutAnyCacheFlag) {
+ createTestSdkData("com.foo", {"shared", "sdk1", "sdk2"});
+ // Clear the app user data.
+ ASSERT_BINDER_SUCCESS(service->clearAppData(kTestUuid, "com.foo", 0, FLAG_STORAGE_CE, -1));
+
+ const std::string packagePath = kTestPath + "/misc_ce/0/sdksandbox/com.foo";
+ ASSERT_TRUE(is_empty(packagePath + "/shared"));
+ ASSERT_TRUE(is_empty(packagePath + "/sdk1"));
+ ASSERT_TRUE(is_empty(packagePath + "/sdk2"));
+}
+
+TEST_F(ClearAppDataTest, ClearSdkSandboxDataDirectories_WithDeAndWithoutAnyCacheFlag) {
+ createTestSdkData("com.foo", {"shared", "sdk1", "sdk2"});
+ // Clear the app user data.
+ ASSERT_BINDER_SUCCESS(service->clearAppData(kTestUuid, "com.foo", 0, FLAG_STORAGE_DE, -1));
+
+ const std::string packagePath = kTestPath + "/misc_de/0/sdksandbox/com.foo";
+ ASSERT_TRUE(is_empty(packagePath + "/shared"));
+ ASSERT_TRUE(is_empty(packagePath + "/sdk1"));
+ ASSERT_TRUE(is_empty(packagePath + "/sdk2"));
+}
+
+class DestroyUserDataTest : public SdkSandboxDataTest {};
+
+TEST_F(DestroyUserDataTest, DestroySdkData_WithCeFlag) {
+ android::os::CreateAppDataResult result;
+ android::os::CreateAppDataArgs args = createAppDataArgs("com.foo");
+ args.packageName = "com.foo";
+ // Create the app user data.
+ ASSERT_BINDER_SUCCESS(service->createAppData(args, &result));
+ // Destroy user data
+ ASSERT_BINDER_SUCCESS(service->destroyUserData(args.uuid, args.userId, FLAG_STORAGE_CE));
+ ASSERT_FALSE(exists("/data/local/tmp/misc_ce/0/sdksandbox"));
+ ASSERT_TRUE(exists("/data/local/tmp/misc_de/0/sdksandbox"));
+}
+
+TEST_F(DestroyUserDataTest, DestroySdkData_WithDeFlag) {
+ android::os::CreateAppDataResult result;
+ android::os::CreateAppDataArgs args = createAppDataArgs("com.foo");
+ args.packageName = "com.foo";
+ // Create the app user data.
+ ASSERT_BINDER_SUCCESS(service->createAppData(args, &result));
+ // Destroy user data
+ ASSERT_BINDER_SUCCESS(service->destroyUserData(args.uuid, args.userId, FLAG_STORAGE_DE));
+ ASSERT_TRUE(exists("/data/local/tmp/misc_ce/0/sdksandbox"));
+ ASSERT_FALSE(exists("/data/local/tmp/misc_de/0/sdksandbox"));
+}
+
} // namespace installd
} // namespace android
diff --git a/cmds/installd/tests/installd_utils_test.cpp b/cmds/installd/tests/installd_utils_test.cpp
index 514b88135a..910cd630f3 100644
--- a/cmds/installd/tests/installd_utils_test.cpp
+++ b/cmds/installd/tests/installd_utils_test.cpp
@@ -21,6 +21,7 @@
#include <android-base/logging.h>
#include <android-base/scopeguard.h>
+#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "InstalldNativeService.h"
@@ -47,6 +48,8 @@
namespace android {
namespace installd {
+using ::testing::UnorderedElementsAre;
+
class UtilsTest : public testing::Test {
protected:
virtual void SetUp() {
@@ -658,6 +661,59 @@ TEST_F(UtilsTest, TestCreateDirIfNeeded) {
ASSERT_NE(0, create_dir_if_needed("/data/local/tmp/user/0/bar/baz", 0700));
}
+TEST_F(UtilsTest, TestForEachSubdir) {
+ auto deleter = [&]() {
+ delete_dir_contents_and_dir("/data/local/tmp/user/0", true /* ignore_if_missing */);
+ };
+ auto scope_guard = android::base::make_scope_guard(deleter);
+
+ system("mkdir -p /data/local/tmp/user/0/com.foo");
+ system("mkdir -p /data/local/tmp/user/0/com.bar");
+ system("touch /data/local/tmp/user/0/some-file");
+
+ std::vector<std::string> result;
+ foreach_subdir("/data/local/tmp/user/0",
+ [&](const std::string &filename) { result.push_back(filename); });
+
+ EXPECT_THAT(result, UnorderedElementsAre("com.foo", "com.bar"));
+}
+
+TEST_F(UtilsTest, TestSdkSandboxDataPaths) {
+ // Ce data paths
+ EXPECT_EQ("/data/misc_ce/0/sdksandbox",
+ create_data_misc_sdk_sandbox_path(nullptr, /*isCeData=*/true, 0));
+ EXPECT_EQ("/data/misc_ce/10/sdksandbox", create_data_misc_sdk_sandbox_path(nullptr, true, 10));
+
+ EXPECT_EQ("/data/misc_ce/0/sdksandbox/com.foo",
+ create_data_misc_sdk_sandbox_package_path(nullptr, true, 0, "com.foo"));
+ EXPECT_EQ("/data/misc_ce/10/sdksandbox/com.foo",
+ create_data_misc_sdk_sandbox_package_path(nullptr, true, 10, "com.foo"));
+
+ EXPECT_EQ("/data/misc_ce/0/sdksandbox/com.foo/shared",
+ create_data_misc_sdk_sandbox_sdk_path(nullptr, true, 0, "com.foo", "shared"));
+ EXPECT_EQ("/data/misc_ce/10/sdksandbox/com.foo/shared",
+ create_data_misc_sdk_sandbox_sdk_path(nullptr, true, 10, "com.foo", "shared"));
+ EXPECT_EQ("/data/misc_ce/10/sdksandbox/com.foo/bar@random",
+ create_data_misc_sdk_sandbox_sdk_path(nullptr, true, 10, "com.foo", "bar@random"));
+
+ // De data paths
+ EXPECT_EQ("/data/misc_de/0/sdksandbox",
+ create_data_misc_sdk_sandbox_path(nullptr, /*isCeData=*/false, 0));
+ EXPECT_EQ("/data/misc_de/10/sdksandbox", create_data_misc_sdk_sandbox_path(nullptr, false, 10));
+
+ EXPECT_EQ("/data/misc_de/0/sdksandbox/com.foo",
+ create_data_misc_sdk_sandbox_package_path(nullptr, false, 0, "com.foo"));
+ EXPECT_EQ("/data/misc_de/10/sdksandbox/com.foo",
+ create_data_misc_sdk_sandbox_package_path(nullptr, false, 10, "com.foo"));
+
+ EXPECT_EQ("/data/misc_de/0/sdksandbox/com.foo/shared",
+ create_data_misc_sdk_sandbox_sdk_path(nullptr, false, 0, "com.foo", "shared"));
+ EXPECT_EQ("/data/misc_de/10/sdksandbox/com.foo/shared",
+ create_data_misc_sdk_sandbox_sdk_path(nullptr, false, 10, "com.foo", "shared"));
+ EXPECT_EQ("/data/misc_de/10/sdksandbox/com.foo/bar@random",
+ create_data_misc_sdk_sandbox_sdk_path(nullptr, false, 10, "com.foo", "bar@random"));
+}
+
TEST_F(UtilsTest, WaitChild) {
pid_t pid = fork();
if (pid == 0) {
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index f04ee337d9..c7bea3f4a9 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -37,6 +37,7 @@
#include <android-base/unique_fd.h>
#include <cutils/fs.h>
#include <cutils/properties.h>
+#include <linux/fs.h>
#include <log/log.h>
#include <private/android_filesystem_config.h>
#include <private/android_projectid_config.h>
@@ -197,6 +198,45 @@ std::string create_data_user_de_path(const char* volume_uuid, userid_t userid) {
return StringPrintf("%s/user_de/%u", data.c_str(), userid);
}
+/**
+ * Create the path name where sdk_sandbox data for all apps will be stored.
+ * E.g. /data/misc_ce/0/sdksandbox
+ */
+std::string create_data_misc_sdk_sandbox_path(const char* uuid, bool isCeData, userid_t user) {
+ std::string data(create_data_path(uuid));
+ if (isCeData) {
+ return StringPrintf("%s/misc_ce/%d/sdksandbox", data.c_str(), user);
+ } else {
+ return StringPrintf("%s/misc_de/%d/sdksandbox", data.c_str(), user);
+ }
+}
+
+/**
+ * Create the path name where code data for all codes in a particular app will be stored.
+ * E.g. /data/misc_ce/0/sdksandbox/<package-name>
+ */
+std::string create_data_misc_sdk_sandbox_package_path(const char* volume_uuid, bool isCeData,
+ userid_t user, const char* package_name) {
+ check_package_name(package_name);
+ return StringPrintf("%s/%s",
+ create_data_misc_sdk_sandbox_path(volume_uuid, isCeData, user).c_str(),
+ package_name);
+}
+
+/**
+ * Create the path name where sdk data for a particular sdk will be stored.
+ * E.g. /data/misc_ce/0/sdksandbox/<package-name>/com.foo@randomstrings
+ */
+std::string create_data_misc_sdk_sandbox_sdk_path(const char* volume_uuid, bool isCeData,
+ userid_t user, const char* package_name,
+ const char* sub_dir_name) {
+ return StringPrintf("%s/%s",
+ create_data_misc_sdk_sandbox_package_path(volume_uuid, isCeData, user,
+ package_name)
+ .c_str(),
+ sub_dir_name);
+}
+
std::string create_data_misc_ce_rollback_base_path(const char* volume_uuid, userid_t user) {
return StringPrintf("%s/misc_ce/%u/rollback", create_data_path(volume_uuid).c_str(), user);
}
@@ -384,7 +424,44 @@ std::vector<userid_t> get_known_users(const char* volume_uuid) {
return users;
}
+long get_project_id(uid_t uid, long start_project_id_range) {
+ return uid - AID_APP_START + start_project_id_range;
+}
+
+int set_quota_project_id(const std::string& path, long project_id, bool set_inherit) {
+ struct fsxattr fsx;
+ android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_CLOEXEC)));
+ if (fd == -1) {
+ PLOG(ERROR) << "Failed to open " << path << " to set project id.";
+ return -1;
+ }
+
+ if (ioctl(fd, FS_IOC_FSGETXATTR, &fsx) == -1) {
+ PLOG(ERROR) << "Failed to get extended attributes for " << path << " to get project id.";
+ return -1;
+ }
+
+ fsx.fsx_projid = project_id;
+ if (ioctl(fd, FS_IOC_FSSETXATTR, &fsx) == -1) {
+ PLOG(ERROR) << "Failed to set project id on " << path;
+ return -1;
+ }
+ if (set_inherit) {
+ unsigned int flags;
+ if (ioctl(fd, FS_IOC_GETFLAGS, &flags) == -1) {
+ PLOG(ERROR) << "Failed to get flags for " << path << " to set project id inheritance.";
+ return -1;
+ }
+
+ flags |= FS_PROJINHERIT_FL;
+ if (ioctl(fd, FS_IOC_SETFLAGS, &flags) == -1) {
+ PLOG(ERROR) << "Failed to set flags for " << path << " to set project id inheritance.";
+ return -1;
+ }
+ }
+ return 0;
+}
int calculate_tree_size(const std::string& path, int64_t* size,
int32_t include_gid, int32_t exclude_gid, bool exclude_apps) {
FTS *fts;
@@ -628,16 +705,16 @@ static int rename_delete_dir_contents(const std::string& pathname,
auto temp_dir_path =
base::StringPrintf("%s/%s", Dirname(pathname).c_str(), temp_dir_name.c_str());
- if (::rename(pathname.c_str(), temp_dir_path.c_str())) {
+ auto dir_to_delete = temp_dir_path.c_str();
+ if (::rename(pathname.c_str(), dir_to_delete)) {
if (ignore_if_missing && (errno == ENOENT)) {
return 0;
}
- ALOGE("Couldn't rename %s -> %s: %s \n", pathname.c_str(), temp_dir_path.c_str(),
- strerror(errno));
- return -errno;
+ ALOGE("Couldn't rename %s -> %s: %s \n", pathname.c_str(), dir_to_delete, strerror(errno));
+ dir_to_delete = pathname.c_str();
}
- return delete_dir_contents(temp_dir_path.c_str(), 1, exclusion_predicate, ignore_if_missing);
+ return delete_dir_contents(dir_to_delete, 1, exclusion_predicate, ignore_if_missing);
}
bool is_renamed_deleted_dir(const std::string& path) {
@@ -659,6 +736,34 @@ static auto open_dir(const char* dir) {
return std::unique_ptr<DIR, DirCloser>(::opendir(dir));
}
+// Collects filename of subdirectories of given directory and passes it to the function
+int foreach_subdir(const std::string& pathname, const std::function<void(const std::string&)> fn) {
+ auto dir = open_dir(pathname.c_str());
+ if (!dir) return -1;
+
+ int dfd = dirfd(dir.get());
+ if (dfd < 0) {
+ ALOGE("Couldn't dirfd %s: %s\n", pathname.c_str(), strerror(errno));
+ return -1;
+ }
+
+ struct dirent* de;
+ while ((de = readdir(dir.get()))) {
+ if (de->d_type != DT_DIR) {
+ continue;
+ }
+
+ std::string name{de->d_name};
+ // always skip "." and ".."
+ if (name == "." || name == "..") {
+ continue;
+ }
+ fn(name);
+ }
+
+ return 0;
+}
+
void cleanup_invalid_package_dirs_under_path(const std::string& pathname) {
auto dir = open_dir(pathname.c_str());
if (!dir) {
diff --git a/cmds/installd/utils.h b/cmds/installd/utils.h
index 39738945e4..ecea1d2b1c 100644
--- a/cmds/installd/utils.h
+++ b/cmds/installd/utils.h
@@ -32,6 +32,7 @@
#define MEASURE_DEBUG 0
#define FIXUP_DEBUG 0
+#define SDK_DEBUG 1
#define BYPASS_QUOTA 0
#define BYPASS_SDCARDFS 0
@@ -60,6 +61,14 @@ std::string create_data_user_de_package_path(const char* volume_uuid,
std::string create_data_user_ce_package_path_as_user_link(
const char* volume_uuid, userid_t userid, const char* package_name);
+std::string create_data_misc_sdk_sandbox_path(const char* volume_uuid, bool isCeData,
+ userid_t userid);
+std::string create_data_misc_sdk_sandbox_package_path(const char* volume_uuid, bool isCeData,
+ userid_t userid, const char* package_name);
+std::string create_data_misc_sdk_sandbox_sdk_path(const char* volume_uuid, bool isCeData,
+ userid_t userid, const char* package_name,
+ const char* sub_dir_name);
+
std::string create_data_misc_ce_rollback_base_path(const char* volume_uuid, userid_t user);
std::string create_data_misc_de_rollback_base_path(const char* volume_uuid, userid_t user);
std::string create_data_misc_ce_rollback_path(const char* volume_uuid, userid_t user,
@@ -123,6 +132,8 @@ int delete_dir_contents_and_dir(const std::string& pathname, bool ignore_if_miss
bool is_renamed_deleted_dir(const std::string& path);
int rename_delete_dir_contents_and_dir(const std::string& pathname, bool ignore_if_missing = true);
+int foreach_subdir(const std::string& pathname, std::function<void(const std::string&)> fn);
+
void cleanup_invalid_package_dirs_under_path(const std::string& pathname);
int delete_dir_contents(const char *pathname,
@@ -160,6 +171,8 @@ int prepare_app_cache_dir(const std::string& parent, const char* name, mode_t ta
uid_t uid, gid_t gid);
bool supports_sdcardfs();
+long get_project_id(uid_t uid, long start_project_id_range);
+int set_quota_project_id(const std::string& path, long project_id, bool set_inherit);
int64_t get_occupied_app_space_external(const std::string& uuid, int32_t userId, int32_t appId);
int64_t get_occupied_app_cache_space_external(const std::string& uuid, int32_t userId, int32_t appId);
diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp
index 555be1ed7e..3cfe5297ca 100644
--- a/cmds/servicemanager/ServiceManager.cpp
+++ b/cmds/servicemanager/ServiceManager.cpp
@@ -295,28 +295,27 @@ bool isValidServiceName(const std::string& name) {
Status ServiceManager::addService(const std::string& name, const sp<IBinder>& binder, bool allowIsolated, int32_t dumpPriority) {
auto ctx = mAccess->getCallingContext();
- // apps cannot add services
if (multiuser_get_app_id(ctx.uid) >= AID_APP) {
- return Status::fromExceptionCode(Status::EX_SECURITY);
+ return Status::fromExceptionCode(Status::EX_SECURITY, "App UIDs cannot add services");
}
if (!mAccess->canAdd(ctx, name)) {
- return Status::fromExceptionCode(Status::EX_SECURITY);
+ return Status::fromExceptionCode(Status::EX_SECURITY, "SELinux denial");
}
if (binder == nullptr) {
- return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT);
+ return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT, "Null binder");
}
if (!isValidServiceName(name)) {
LOG(ERROR) << "Invalid service name: " << name;
- return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT);
+ return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT, "Invalid service name");
}
#ifndef VENDORSERVICEMANAGER
if (!meetsDeclarationRequirements(binder, name)) {
// already logged
- return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT);
+ return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT, "VINTF declaration error");
}
#endif // !VENDORSERVICEMANAGER
@@ -324,7 +323,7 @@ Status ServiceManager::addService(const std::string& name, const sp<IBinder>& bi
if (binder->remoteBinder() != nullptr &&
binder->linkToDeath(sp<ServiceManager>::fromExisting(this)) != OK) {
LOG(ERROR) << "Could not linkToDeath when adding " << name;
- return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE);
+ return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE, "linkToDeath failure");
}
// Overwrite the old service if it exists
diff --git a/cmds/surfacereplayer/proto/src/trace.proto b/cmds/surfacereplayer/proto/src/trace.proto
index 03a2709075..a177027e5c 100644
--- a/cmds/surfacereplayer/proto/src/trace.proto
+++ b/cmds/surfacereplayer/proto/src/trace.proto
@@ -101,6 +101,10 @@ message LayerStackChange {
required uint32 layer_stack = 1;
}
+message DisplayFlagsChange {
+ required uint32 flags = 1;
+}
+
message HiddenFlagChange {
required bool hidden_flag = 1;
}
@@ -121,6 +125,7 @@ message DisplayChange {
LayerStackChange layer_stack = 3;
SizeChange size = 4;
ProjectionChange projection = 5;
+ DisplayFlagsChange flags = 6;
}
}
@@ -217,4 +222,4 @@ message BlurRegionChange {
message Origin {
required int32 pid = 1;
required int32 uid = 2;
-} \ No newline at end of file
+}
diff --git a/data/etc/Android.bp b/data/etc/Android.bp
index 31dee235e8..34d53a52a0 100644
--- a/data/etc/Android.bp
+++ b/data/etc/Android.bp
@@ -221,6 +221,12 @@ prebuilt_etc {
}
prebuilt_etc {
+ name: "android.software.opengles.deqp.level-2022-03-01.prebuilt.xml",
+ src: "android.software.opengles.deqp.level-2022-03-01.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
name: "android.software.sip.voip.prebuilt.xml",
src: "android.software.sip.voip.xml",
defaults: ["frameworks_native_data_etc_defaults"],
@@ -239,6 +245,12 @@ prebuilt_etc {
}
prebuilt_etc {
+ name: "android.software.vulkan.deqp.level-2022-03-01.prebuilt.xml",
+ src: "android.software.vulkan.deqp.level-2022-03-01.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
name: "aosp_excluded_hardware.prebuilt.xml",
src: "aosp_excluded_hardware.xml",
defaults: ["frameworks_native_data_etc_defaults"],
@@ -255,3 +267,11 @@ prebuilt_etc {
src: "handheld_core_hardware.xml",
defaults: ["frameworks_native_data_etc_defaults"],
}
+
+prebuilt_etc {
+ name: "android.software.app_compat_overrides.xml",
+ product_specific: true,
+ sub_dir: "permissions",
+ src: "android.software.app_compat_overrides.xml",
+ filename_from_src: true,
+}
diff --git a/data/etc/android.software.app_compat_overrides.xml b/data/etc/android.software.app_compat_overrides.xml
new file mode 100644
index 0000000000..2f9726a3f0
--- /dev/null
+++ b/data/etc/android.software.app_compat_overrides.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<!-- Feature for devices that are opted-in to receive per-app compatibility
+ overrides. -->
+<permissions>
+ <feature name="android.software.app_compat_overrides" />
+</permissions>
diff --git a/include/android/multinetwork.h b/include/android/multinetwork.h
index 4c83a14728..ee392fc401 100644
--- a/include/android/multinetwork.h
+++ b/include/android/multinetwork.h
@@ -235,7 +235,7 @@ void android_res_cancel(int nsend_fd) __INTRODUCED_IN(29);
*
* Available since API level 33.
*/
-int android_tag_socket_with_uid(int sockfd, int tag, uid_t uid) __INTRODUCED_IN(33);
+int android_tag_socket_with_uid(int sockfd, uint32_t tag, uid_t uid) __INTRODUCED_IN(33);
/*
* Set the socket tag for traffic statistics on the specified socket.
@@ -245,14 +245,26 @@ int android_tag_socket_with_uid(int sockfd, int tag, uid_t uid) __INTRODUCED_IN(
* opened by another UID or was previously tagged by another UID. Subsequent
* calls always replace any existing parameters. The socket tag is kept when the
* socket is sent to another process using binder IPCs or other mechanisms such
- * as UNIX socket fd passing.
+ * as UNIX socket fd passing. The tag is a value defined by the caller and used
+ * together with uid for data traffic accounting, so that the function callers
+ * can account different types of data usage for a uid.
*
* Returns 0 on success, or a negative POSIX error code (see errno.h) on
* failure.
*
+ * Some possible error codes:
+ * -EBADF Bad socketfd.
+ * -EPERM No permission.
+ * -EAFNOSUPPORT Socket family is neither AF_INET nor AF_INET6.
+ * -EPROTONOSUPPORT Socket protocol is neither IPPROTO_UDP nor IPPROTO_TCP.
+ * -EMFILE Too many stats entries.
+ * There are still other error codes that may provided by -errno of
+ * [getsockopt()](https://man7.org/linux/man-pages/man2/getsockopt.2.html) or by
+ * BPF maps read/write sys calls, which are set appropriately.
+ *
* Available since API level 33.
*/
-int android_tag_socket(int sockfd, int tag) __INTRODUCED_IN(33);
+int android_tag_socket(int sockfd, uint32_t tag) __INTRODUCED_IN(33);
/*
* Untag a network socket.
@@ -267,6 +279,12 @@ int android_tag_socket(int sockfd, int tag) __INTRODUCED_IN(33);
* Returns 0 on success, or a negative POSIX error code (see errno.h) on
* failure.
*
+ * One of possible error code:
+ * -EBADF Bad socketfd.
+ * Other error codes are either provided by -errno of
+ * [getsockopt()](https://man7.org/linux/man-pages/man2/getsockopt.2.html) or by
+ * BPF map element deletion sys call, which are set appropriately.
+ *
* Available since API level 33.
*/
int android_untag_socket(int sockfd) __INTRODUCED_IN(33);
diff --git a/include/android/storage_manager.h b/include/android/storage_manager.h
index 7f2ee08d62..270570e0df 100644
--- a/include/android/storage_manager.h
+++ b/include/android/storage_manager.h
@@ -124,6 +124,12 @@ typedef void (*AStorageManager_obbCallbackFunc)(const char* filename, const int3
/**
* Attempts to mount an OBB file. This is an asynchronous operation.
+ *
+ * Since API level 33, this function can only be used to mount unencrypted OBBs,
+ * i.e. the {@code key} parameter must be {@code null} or an empty string. Note
+ * that even before API level 33, mounting encrypted OBBs didn't work on many
+ * Android device implementations. Applications should not assume any particular
+ * behavior when {@code key} is nonempty.
*/
void AStorageManager_mountObb(AStorageManager* mgr, const char* filename, const char* key,
AStorageManager_obbCallbackFunc cb, void* data);
diff --git a/include/input/Flags.h b/include/ftl/Flags.h
index b12a9ed2c5..27c84769cb 100644
--- a/include/input/Flags.h
+++ b/include/ftl/Flags.h
@@ -22,11 +22,10 @@
#include <string>
#include <type_traits>
-#include "NamedEnum.h"
+#include <ftl/NamedEnum.h>
#include "utils/BitSet.h"
-#ifndef __UI_INPUT_FLAGS_H
-#define __UI_INPUT_FLAGS_H
+#pragma once
namespace android {
@@ -279,5 +278,3 @@ Flags<F> operator|(F lhs, F rhs) {
} // namespace flag_operators
} // namespace android
-
-#endif // __UI_INPUT_FLAGS_H
diff --git a/include/input/NamedEnum.h b/include/ftl/NamedEnum.h
index 8d3f6b7946..6e98feeb87 100644
--- a/include/input/NamedEnum.h
+++ b/include/ftl/NamedEnum.h
@@ -21,8 +21,7 @@
#include <optional>
#include <string>
-#ifndef __UI_INPUT_NAMEDENUM_H
-#define __UI_INPUT_NAMEDENUM_H
+#pragma once
namespace android {
@@ -128,5 +127,3 @@ public:
};
} // namespace android
-
-#endif // __UI_INPUT_NAMEDENUM_H \ No newline at end of file
diff --git a/include/input/DisplayViewport.h b/include/input/DisplayViewport.h
index 5e40ca7ece..a6213f3ddd 100644
--- a/include/input/DisplayViewport.h
+++ b/include/input/DisplayViewport.h
@@ -18,8 +18,9 @@
#define _LIBINPUT_DISPLAY_VIEWPORT_H
#include <android-base/stringprintf.h>
+#include <ftl/NamedEnum.h>
+#include <gui/constants.h>
#include <input/Input.h>
-#include <input/NamedEnum.h>
#include <cinttypes>
#include <optional>
diff --git a/include/input/Input.h b/include/input/Input.h
index dce6ccb3d5..4adaa5b1c5 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -124,15 +124,6 @@ constexpr int32_t VERIFIED_MOTION_EVENT_FLAGS = AMOTION_EVENT_FLAG_WINDOW_IS_OBS
constexpr int32_t AMOTION_EVENT_FLAG_CANCELED = 0x20;
enum {
- /* Used when a motion event is not associated with any display.
- * Typically used for non-pointer events. */
- ADISPLAY_ID_NONE = -1,
-
- /* The default display id. */
- ADISPLAY_ID_DEFAULT = 0,
-};
-
-enum {
/*
* Indicates that an input device has switches.
* This input source flag is hidden from the API because switches are only used by the system
@@ -354,12 +345,6 @@ private:
*/
constexpr float AMOTION_EVENT_INVALID_CURSOR_POSITION = std::numeric_limits<float>::quiet_NaN();
-/**
- * Invalid value for display size. Used when display size isn't available for an event or doesn't
- * matter. This is just a constant 0 so that it has no effect if unused.
- */
-constexpr int32_t AMOTION_EVENT_INVALID_DISPLAY_SIZE = 0;
-
/*
* Pointer coordinate data.
*/
@@ -592,6 +577,8 @@ public:
void setCursorPosition(float x, float y);
+ uint32_t getDisplayOrientation() const { return mDisplayOrientation; }
+
int2 getDisplaySize() const { return {mDisplayWidth, mDisplayHeight}; }
static inline bool isValidCursorPosition(float x, float y) { return !isnan(x) && !isnan(y); }
@@ -768,8 +755,8 @@ public:
int32_t flags, int32_t edgeFlags, int32_t metaState, int32_t buttonState,
MotionClassification classification, const ui::Transform& transform,
float xPrecision, float yPrecision, float rawXCursorPosition,
- float rawYCursorPosition, int32_t displayWidth, int32_t displayHeight,
- nsecs_t downTime, nsecs_t eventTime, size_t pointerCount,
+ float rawYCursorPosition, uint32_t displayOrientation, int32_t displayWidth,
+ int32_t displayHeight, nsecs_t downTime, nsecs_t eventTime, size_t pointerCount,
const PointerProperties* pointerProperties, const PointerCoords* pointerCoords);
void copyFrom(const MotionEvent* other, bool keepHistory);
@@ -827,6 +814,7 @@ protected:
float mYPrecision;
float mRawXCursorPosition;
float mRawYCursorPosition;
+ uint32_t mDisplayOrientation;
int32_t mDisplayWidth;
int32_t mDisplayHeight;
nsecs_t mDownTime;
diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h
index 360dfbfd73..a790b5637f 100644
--- a/include/input/InputTransport.h
+++ b/include/input/InputTransport.h
@@ -136,10 +136,10 @@ struct InputMessage {
float yPrecision;
float xCursorPosition;
float yCursorPosition;
+ uint32_t displayOrientation;
int32_t displayWidth;
int32_t displayHeight;
uint32_t pointerCount;
- uint32_t empty3;
/**
* The "pointers" field must be the last field of the struct InputMessage.
* When we send the struct InputMessage across the socket, we are not
@@ -355,8 +355,9 @@ public:
int32_t metaState, int32_t buttonState,
MotionClassification classification, const ui::Transform& transform,
float xPrecision, float yPrecision, float xCursorPosition,
- float yCursorPosition, int32_t displayWidth, int32_t displayHeight,
- nsecs_t downTime, nsecs_t eventTime, uint32_t pointerCount,
+ float yCursorPosition, uint32_t displayOrientation,
+ int32_t displayWidth, int32_t displayHeight, nsecs_t downTime,
+ nsecs_t eventTime, uint32_t pointerCount,
const PointerProperties* pointerProperties,
const PointerCoords* pointerCoords);
diff --git a/include/input/KeyCharacterMap.h b/include/input/KeyCharacterMap.h
index 451ca3c6cd..f6f8939b7a 100644
--- a/include/input/KeyCharacterMap.h
+++ b/include/input/KeyCharacterMap.h
@@ -84,7 +84,7 @@ public:
const std::string getLoadFileName() const;
- /* Combines this key character map with an overlay. */
+ /* Combines this key character map with the provided overlay. */
void combine(const KeyCharacterMap& overlay);
/* Gets the keyboard type. */
@@ -144,6 +144,8 @@ public:
bool operator==(const KeyCharacterMap& other) const;
+ bool operator!=(const KeyCharacterMap& other) const;
+
KeyCharacterMap(const KeyCharacterMap& other);
virtual ~KeyCharacterMap();
@@ -230,11 +232,12 @@ private:
KeyedVector<int32_t, Key*> mKeys;
KeyboardType mType;
std::string mLoadFileName;
+ bool mLayoutOverlayApplied;
KeyedVector<int32_t, int32_t> mKeysByScanCode;
KeyedVector<int32_t, int32_t> mKeysByUsageCode;
- KeyCharacterMap();
+ KeyCharacterMap(const std::string& filename);
bool getKey(int32_t keyCode, const Key** outKey) const;
bool getKeyBehavior(int32_t keyCode, int32_t metaState,
@@ -243,8 +246,6 @@ private:
bool findKey(char16_t ch, int32_t* outKeyCode, int32_t* outMetaState) const;
- static base::Result<std::shared_ptr<KeyCharacterMap>> load(Tokenizer* tokenizer, Format format);
-
static void addKey(Vector<KeyEvent>& outEvents,
int32_t deviceId, int32_t keyCode, int32_t metaState, bool down, nsecs_t time);
static void addMetaKeys(Vector<KeyEvent>& outEvents,
@@ -264,6 +265,15 @@ private:
int32_t deviceId, int32_t metaState, nsecs_t time,
int32_t keyCode, int32_t keyMetaState,
int32_t* currentMetaState);
+
+ /* Clears all data stored in this key character map */
+ void clear();
+
+ /* Loads the KeyCharacterMap provided by the tokenizer into this instance. */
+ status_t load(Tokenizer* tokenizer, Format format);
+
+ /* Reloads the data from mLoadFileName and unapplies any overlay. */
+ status_t reloadBaseFromFile();
};
} // namespace android
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index 7448308ec9..63d87dae5a 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -166,6 +166,7 @@ cc_library {
"-Wextra-semi",
"-Werror",
"-Wzero-as-null-pointer-constant",
+ "-Wreorder-init-list",
"-DANDROID_BASE_UNIQUE_FD_DISABLE_IMPLICIT_CONVERSION",
"-DANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION",
],
diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp
index 0970ca5aa5..39befbe8e0 100644
--- a/libs/binder/Binder.cpp
+++ b/libs/binder/Binder.cpp
@@ -19,6 +19,7 @@
#include <atomic>
#include <set>
+#include <android-base/logging.h>
#include <android-base/unique_fd.h>
#include <binder/BpBinder.h>
#include <binder/IInterface.h>
@@ -281,9 +282,11 @@ status_t BBinder::transact(
err = pingBinder();
break;
case EXTENSION_TRANSACTION:
+ CHECK(reply != nullptr);
err = reply->writeStrongBinder(getExtension());
break;
case DEBUG_PID_TRANSACTION:
+ CHECK(reply != nullptr);
err = reply->writeInt32(getDebugPid());
break;
case SET_RPC_CLIENT_TRANSACTION: {
@@ -579,6 +582,10 @@ void BBinder::removeRpcServerLink(const sp<RpcServerLink>& link) {
BBinder::~BBinder()
{
+ if (!wasParceled() && getExtension()) {
+ ALOGW("Binder %p destroyed with extension attached before being parceled.", this);
+ }
+
Extras* e = mExtras.load(std::memory_order_relaxed);
if (e) delete e;
}
@@ -590,6 +597,7 @@ status_t BBinder::onTransact(
{
switch (code) {
case INTERFACE_TRANSACTION:
+ CHECK(reply != nullptr);
reply->writeString16(getInterfaceDescriptor());
return NO_ERROR;
diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp
index 056ef0ab74..921e57c7bf 100644
--- a/libs/binder/BpBinder.cpp
+++ b/libs/binder/BpBinder.cpp
@@ -72,29 +72,29 @@ void* BpBinder::ObjectManager::attach(const void* objectID, void* object, void*
e.cleanupCookie = cleanupCookie;
e.func = func;
- if (ssize_t idx = mObjects.indexOfKey(objectID); idx >= 0) {
+ if (mObjects.find(objectID) != mObjects.end()) {
ALOGI("Trying to attach object ID %p to binder ObjectManager %p with object %p, but object "
"ID already in use",
objectID, this, object);
- return mObjects[idx].object;
+ return mObjects[objectID].object;
}
- mObjects.add(objectID, e);
+ mObjects.insert({objectID, e});
return nullptr;
}
void* BpBinder::ObjectManager::find(const void* objectID) const
{
- const ssize_t i = mObjects.indexOfKey(objectID);
- if (i < 0) return nullptr;
- return mObjects.valueAt(i).object;
+ auto i = mObjects.find(objectID);
+ if (i == mObjects.end()) return nullptr;
+ return i->second.object;
}
void* BpBinder::ObjectManager::detach(const void* objectID) {
- ssize_t idx = mObjects.indexOfKey(objectID);
- if (idx < 0) return nullptr;
- void* value = mObjects[idx].object;
- mObjects.removeItemsAt(idx, 1);
+ auto i = mObjects.find(objectID);
+ if (i == mObjects.end()) return nullptr;
+ void* value = i->second.object;
+ mObjects.erase(i);
return value;
}
@@ -102,10 +102,10 @@ void BpBinder::ObjectManager::kill()
{
const size_t N = mObjects.size();
ALOGV("Killing %zu objects in manager %p", N, this);
- for (size_t i=0; i<N; i++) {
- const entry_t& e = mObjects.valueAt(i);
+ for (auto i : mObjects) {
+ const entry_t& e = i.second;
if (e.func != nullptr) {
- e.func(mObjects.keyAt(i), e.object, e.cleanupCookie);
+ e.func(i.first, e.object, e.cleanupCookie);
}
}
diff --git a/libs/binder/BufferedTextOutput.h b/libs/binder/BufferedTextOutput.h
index fdd532aec6..57e03cb3a6 100644
--- a/libs/binder/BufferedTextOutput.h
+++ b/libs/binder/BufferedTextOutput.h
@@ -18,8 +18,8 @@
#define ANDROID_BUFFEREDTEXTOUTPUT_H
#include <binder/TextOutput.h>
-#include <utils/threads.h>
#include <sys/uio.h>
+#include <utils/Mutex.h>
// ---------------------------------------------------------------------------
namespace android {
diff --git a/libs/binder/IMemory.cpp b/libs/binder/IMemory.cpp
index bd974b02b1..c6b0cb7b01 100644
--- a/libs/binder/IMemory.cpp
+++ b/libs/binder/IMemory.cpp
@@ -31,8 +31,9 @@
#include <binder/Parcel.h>
#include <log/log.h>
-#include <utils/KeyedVector.h>
-#include <utils/threads.h>
+#include <utils/Mutex.h>
+
+#include <map>
#define VERBOSE 0
@@ -63,7 +64,7 @@ private:
void free_heap(const wp<IBinder>& binder);
Mutex mHeapCacheLock; // Protects entire vector below.
- KeyedVector< wp<IBinder>, heap_info_t > mHeapCache;
+ std::map<wp<IBinder>, heap_info_t> mHeapCache;
// We do not use the copy-on-write capabilities of KeyedVector.
// TODO: Reimplemement based on standard C++ container?
};
@@ -434,9 +435,9 @@ void HeapCache::binderDied(const wp<IBinder>& binder)
sp<IMemoryHeap> HeapCache::find_heap(const sp<IBinder>& binder)
{
Mutex::Autolock _l(mHeapCacheLock);
- ssize_t i = mHeapCache.indexOfKey(binder);
- if (i>=0) {
- heap_info_t& info = mHeapCache.editValueAt(i);
+ auto i = mHeapCache.find(binder);
+ if (i != mHeapCache.end()) {
+ heap_info_t& info = i->second;
ALOGD_IF(VERBOSE,
"found binder=%p, heap=%p, size=%zu, fd=%d, count=%d",
binder.get(), info.heap.get(),
@@ -452,7 +453,7 @@ sp<IMemoryHeap> HeapCache::find_heap(const sp<IBinder>& binder)
info.count = 1;
//ALOGD("adding binder=%p, heap=%p, count=%d",
// binder.get(), info.heap.get(), info.count);
- mHeapCache.add(binder, info);
+ mHeapCache.insert({binder, info});
return info.heap;
}
}
@@ -466,9 +467,9 @@ void HeapCache::free_heap(const wp<IBinder>& binder)
sp<IMemoryHeap> rel;
{
Mutex::Autolock _l(mHeapCacheLock);
- ssize_t i = mHeapCache.indexOfKey(binder);
- if (i>=0) {
- heap_info_t& info(mHeapCache.editValueAt(i));
+ auto i = mHeapCache.find(binder);
+ if (i != mHeapCache.end()) {
+ heap_info_t& info = i->second;
if (--info.count == 0) {
ALOGD_IF(VERBOSE,
"removing binder=%p, heap=%p, size=%zu, fd=%d, count=%d",
@@ -477,8 +478,8 @@ void HeapCache::free_heap(const wp<IBinder>& binder)
static_cast<BpMemoryHeap*>(info.heap.get())
->mHeapId.load(memory_order_relaxed),
info.count);
- rel = mHeapCache.valueAt(i).heap;
- mHeapCache.removeItemsAt(i);
+ rel = i->second.heap;
+ mHeapCache.erase(i);
}
} else {
ALOGE("free_heap binder=%p not found!!!", binder.unsafe_get());
@@ -490,23 +491,23 @@ sp<IMemoryHeap> HeapCache::get_heap(const sp<IBinder>& binder)
{
sp<IMemoryHeap> realHeap;
Mutex::Autolock _l(mHeapCacheLock);
- ssize_t i = mHeapCache.indexOfKey(binder);
- if (i>=0) realHeap = mHeapCache.valueAt(i).heap;
- else realHeap = interface_cast<IMemoryHeap>(binder);
+ auto i = mHeapCache.find(binder);
+ if (i != mHeapCache.end())
+ realHeap = i->second.heap;
+ else
+ realHeap = interface_cast<IMemoryHeap>(binder);
return realHeap;
}
void HeapCache::dump_heaps()
{
Mutex::Autolock _l(mHeapCacheLock);
- int c = mHeapCache.size();
- for (int i=0 ; i<c ; i++) {
- const heap_info_t& info = mHeapCache.valueAt(i);
+ for (const auto& i : mHeapCache) {
+ const heap_info_t& info = i.second;
BpMemoryHeap const* h(static_cast<BpMemoryHeap const *>(info.heap.get()));
- ALOGD("hey=%p, heap=%p, count=%d, (fd=%d, base=%p, size=%zu)",
- mHeapCache.keyAt(i).unsafe_get(),
- info.heap.get(), info.count,
- h->mHeapId.load(memory_order_relaxed), h->mBase, h->mSize);
+ ALOGD("hey=%p, heap=%p, count=%d, (fd=%d, base=%p, size=%zu)", i.first.unsafe_get(),
+ info.heap.get(), info.count, h->mHeapId.load(memory_order_relaxed), h->mBase,
+ h->mSize);
}
}
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index 13f0a4c4a5..3c97dcab93 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -27,7 +27,6 @@
#include <utils/CallStack.h>
#include <utils/Log.h>
#include <utils/SystemClock.h>
-#include <utils/threads.h>
#include <atomic>
#include <errno.h>
@@ -1199,7 +1198,8 @@ status_t IPCThreadState::executeCommand(int32_t cmd)
case BR_DECREFS:
refs = (RefBase::weakref_type*)mIn.readPointer();
- obj = (BBinder*)mIn.readPointer();
+ // NOLINTNEXTLINE(clang-analyzer-deadcode.DeadStores)
+ obj = (BBinder*)mIn.readPointer(); // consume
// NOTE: This assertion is not valid, because the object may no
// longer exist (thus the (BBinder*)cast above resulting in a different
// memory address).
@@ -1409,7 +1409,7 @@ status_t IPCThreadState::getProcessFreezeInfo(pid_t pid, uint32_t *sync_received
uint32_t *async_received)
{
int ret = 0;
- binder_frozen_status_info info;
+ binder_frozen_status_info info = {};
info.pid = pid;
#if defined(__ANDROID__)
diff --git a/libs/binder/MemoryDealer.cpp b/libs/binder/MemoryDealer.cpp
index c4475c7780..03553f36e9 100644
--- a/libs/binder/MemoryDealer.cpp
+++ b/libs/binder/MemoryDealer.cpp
@@ -23,7 +23,6 @@
#include <utils/Log.h>
#include <utils/SortedVector.h>
#include <utils/String8.h>
-#include <utils/threads.h>
#include <stdint.h>
#include <stdio.h>
diff --git a/libs/binder/MemoryHeapBase.cpp b/libs/binder/MemoryHeapBase.cpp
index e1cbc1996d..8132d46940 100644
--- a/libs/binder/MemoryHeapBase.cpp
+++ b/libs/binder/MemoryHeapBase.cpp
@@ -18,10 +18,13 @@
#include <errno.h>
#include <fcntl.h>
+#include <linux/memfd.h>
#include <stdint.h>
#include <stdlib.h>
#include <sys/ioctl.h>
+#include <sys/mman.h>
#include <sys/stat.h>
+#include <sys/syscall.h>
#include <sys/types.h>
#include <unistd.h>
@@ -34,6 +37,24 @@ namespace android {
// ---------------------------------------------------------------------------
+#ifdef __BIONIC__
+static int memfd_create_region(const char* name, size_t size) {
+ int fd = memfd_create(name, MFD_CLOEXEC | MFD_ALLOW_SEALING);
+ if (fd == -1) {
+ ALOGE("%s: memfd_create(%s, %zd) failed: %s\n", __func__, name, size, strerror(errno));
+ return -1;
+ }
+
+ if (ftruncate(fd, size) == -1) {
+ ALOGE("%s, ftruncate(%s, %zd) failed for memfd creation: %s\n", __func__, name, size,
+ strerror(errno));
+ close(fd);
+ return -1;
+ }
+ return fd;
+}
+#endif
+
MemoryHeapBase::MemoryHeapBase()
: mFD(-1), mSize(0), mBase(MAP_FAILED),
mDevice(nullptr), mNeedUnmap(false), mOffset(0)
@@ -45,15 +66,36 @@ MemoryHeapBase::MemoryHeapBase(size_t size, uint32_t flags, char const * name)
mDevice(nullptr), mNeedUnmap(false), mOffset(0)
{
const size_t pagesize = getpagesize();
- size = ((size + pagesize-1) & ~(pagesize-1));
- int fd = ashmem_create_region(name == nullptr ? "MemoryHeapBase" : name, size);
- ALOGE_IF(fd<0, "error creating ashmem region: %s", strerror(errno));
- if (fd >= 0) {
- if (mapfd(fd, true, size) == NO_ERROR) {
- if (flags & READ_ONLY) {
- ashmem_set_prot_region(fd, PROT_READ);
- }
+ size = ((size + pagesize - 1) & ~(pagesize - 1));
+ int fd = -1;
+ if (mFlags & FORCE_MEMFD) {
+#ifdef __BIONIC__
+ ALOGV("MemoryHeapBase: Attempting to force MemFD");
+ fd = memfd_create_region(name ? name : "MemoryHeapBase", size);
+ if (fd < 0 || (mapfd(fd, true, size) != NO_ERROR)) return;
+ const int SEAL_FLAGS = ((mFlags & READ_ONLY) ? F_SEAL_FUTURE_WRITE : 0) |
+ ((mFlags & MEMFD_ALLOW_SEALING) ? 0 : F_SEAL_SEAL);
+ if (SEAL_FLAGS && (fcntl(fd, F_ADD_SEALS, SEAL_FLAGS) == -1)) {
+ ALOGE("MemoryHeapBase: MemFD %s sealing with flags %x failed with error %s", name,
+ SEAL_FLAGS, strerror(errno));
+ munmap(mBase, mSize);
+ mBase = nullptr;
+ mSize = 0;
+ close(fd);
}
+ return;
+#else
+ mFlags &= ~(FORCE_MEMFD | MEMFD_ALLOW_SEALING);
+#endif
+ }
+ if (mFlags & MEMFD_ALLOW_SEALING) {
+ LOG_ALWAYS_FATAL("Invalid Flags. MEMFD_ALLOW_SEALING only valid with FORCE_MEMFD.");
+ }
+ fd = ashmem_create_region(name ? name : "MemoryHeapBase", size);
+ ALOGE_IF(fd < 0, "MemoryHeapBase: error creating ashmem region: %s", strerror(errno));
+ if (fd < 0 || (mapfd(fd, true, size) != NO_ERROR)) return;
+ if (mFlags & READ_ONLY) {
+ ashmem_set_prot_region(fd, PROT_READ);
}
}
@@ -61,6 +103,9 @@ MemoryHeapBase::MemoryHeapBase(const char* device, size_t size, uint32_t flags)
: mFD(-1), mSize(0), mBase(MAP_FAILED), mFlags(flags),
mDevice(nullptr), mNeedUnmap(false), mOffset(0)
{
+ if (flags & (FORCE_MEMFD | MEMFD_ALLOW_SEALING)) {
+ LOG_ALWAYS_FATAL("FORCE_MEMFD, MEMFD_ALLOW_SEALING only valid with creating constructor");
+ }
int open_flags = O_RDWR;
if (flags & NO_CACHING)
open_flags |= O_SYNC;
@@ -80,6 +125,9 @@ MemoryHeapBase::MemoryHeapBase(int fd, size_t size, uint32_t flags, off_t offset
: mFD(-1), mSize(0), mBase(MAP_FAILED), mFlags(flags),
mDevice(nullptr), mNeedUnmap(false), mOffset(0)
{
+ if (flags & (FORCE_MEMFD | MEMFD_ALLOW_SEALING)) {
+ LOG_ALWAYS_FATAL("FORCE_MEMFD, MEMFD_ALLOW_SEALING only valid with creating constructor");
+ }
const size_t pagesize = getpagesize();
size = ((size + pagesize-1) & ~(pagesize-1));
mapfd(fcntl(fd, F_DUPFD_CLOEXEC, 0), false, size, offset);
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 6a138e340f..58b0b35323 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -63,7 +63,7 @@
// This macro should never be used at runtime, as a too large value
// of s could cause an integer overflow. Instead, you should always
// use the wrapper function pad_size()
-#define PAD_SIZE_UNSAFE(s) (((s)+3)&~3)
+#define PAD_SIZE_UNSAFE(s) (((s) + 3) & ~3UL)
static size_t pad_size(size_t s) {
if (s > (std::numeric_limits<size_t>::max() - 3)) {
@@ -569,6 +569,47 @@ bool Parcel::hasFileDescriptors() const
return mHasFds;
}
+std::vector<sp<IBinder>> Parcel::debugReadAllStrongBinders() const {
+ std::vector<sp<IBinder>> ret;
+
+ size_t initPosition = dataPosition();
+ for (size_t i = 0; i < mObjectsSize; i++) {
+ binder_size_t offset = mObjects[i];
+ const flat_binder_object* flat =
+ reinterpret_cast<const flat_binder_object*>(mData + offset);
+ if (flat->hdr.type != BINDER_TYPE_BINDER) continue;
+
+ setDataPosition(offset);
+
+ sp<IBinder> binder = readStrongBinder();
+ if (binder != nullptr) ret.push_back(binder);
+ }
+
+ setDataPosition(initPosition);
+ return ret;
+}
+
+std::vector<int> Parcel::debugReadAllFileDescriptors() const {
+ std::vector<int> ret;
+
+ size_t initPosition = dataPosition();
+ for (size_t i = 0; i < mObjectsSize; i++) {
+ binder_size_t offset = mObjects[i];
+ const flat_binder_object* flat =
+ reinterpret_cast<const flat_binder_object*>(mData + offset);
+ if (flat->hdr.type != BINDER_TYPE_FD) continue;
+
+ setDataPosition(offset);
+
+ int fd = readFileDescriptor();
+ LOG_ALWAYS_FATAL_IF(fd == -1);
+ ret.push_back(fd);
+ }
+
+ setDataPosition(initPosition);
+ return ret;
+}
+
status_t Parcel::hasFileDescriptorsInRange(size_t offset, size_t len, bool* result) const {
if (len > INT32_MAX || offset > INT32_MAX) {
// Don't accept size_t values which may have come from an inadvertent conversion from a
@@ -1543,6 +1584,7 @@ status_t Parcel::readOutVectorSizeWithCheck(size_t elmSize, int32_t* size) const
template<class T>
status_t Parcel::readAligned(T *pArg) const {
static_assert(PAD_SIZE_UNSAFE(sizeof(T)) == sizeof(T));
+ static_assert(std::is_trivially_copyable_v<T>);
if ((mDataPos+sizeof(T)) <= mDataSize) {
if (mObjectsSize > 0) {
@@ -1554,9 +1596,8 @@ status_t Parcel::readAligned(T *pArg) const {
}
}
- const void* data = mData+mDataPos;
+ memcpy(pArg, mData + mDataPos, sizeof(T));
mDataPos += sizeof(T);
- *pArg = *reinterpret_cast<const T*>(data);
return NO_ERROR;
} else {
return NOT_ENOUGH_DATA;
@@ -1576,10 +1617,11 @@ T Parcel::readAligned() const {
template<class T>
status_t Parcel::writeAligned(T val) {
static_assert(PAD_SIZE_UNSAFE(sizeof(T)) == sizeof(T));
+ static_assert(std::is_trivially_copyable_v<T>);
if ((mDataPos+sizeof(val)) <= mDataCapacity) {
restart_write:
- *reinterpret_cast<T*>(mData+mDataPos) = val;
+ memcpy(mData + mDataPos, &val, sizeof(val));
return finishWrite(sizeof(val));
}
@@ -1862,6 +1904,7 @@ status_t Parcel::readStrongBinder(sp<IBinder>* val) const
{
status_t status = readNullableStrongBinder(val);
if (status == OK && !val->get()) {
+ ALOGW("Expecting binder but got null!");
status = UNEXPECTED_NULL;
}
return status;
diff --git a/libs/binder/ParcelableHolder.cpp b/libs/binder/ParcelableHolder.cpp
index 2e86b7415a..3cf94e3047 100644
--- a/libs/binder/ParcelableHolder.cpp
+++ b/libs/binder/ParcelableHolder.cpp
@@ -52,7 +52,10 @@ status_t ParcelableHolder::writeToParcel(Parcel* p) const {
}
status_t ParcelableHolder::readFromParcel(const Parcel* p) {
- this->mStability = static_cast<Stability>(p->readInt32());
+ int32_t wireStability;
+ if (status_t status = p->readInt32(&wireStability); status != OK) return status;
+ if (static_cast<int32_t>(this->mStability) != wireStability) return BAD_VALUE;
+
this->mParcelable = nullptr;
this->mParcelableName = std::nullopt;
int32_t rawDataSize;
diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
index baa817c6b9..4a01d8176d 100644
--- a/libs/binder/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -25,9 +25,10 @@
#include <binder/IServiceManager.h>
#include <binder/Stability.h>
#include <cutils/atomic.h>
+#include <utils/AndroidThreads.h>
#include <utils/Log.h>
#include <utils/String8.h>
-#include <utils/threads.h>
+#include <utils/Thread.h>
#include "Static.h"
#include "binder_module.h"
@@ -409,6 +410,28 @@ size_t ProcessState::getThreadPoolMaxThreadCount() const {
return 0;
}
+#define DRIVER_FEATURES_PATH "/dev/binderfs/features/"
+bool ProcessState::isDriverFeatureEnabled(const DriverFeature feature) {
+ static const char* const names[] = {
+ [static_cast<int>(DriverFeature::ONEWAY_SPAM_DETECTION)] =
+ DRIVER_FEATURES_PATH "oneway_spam_detection",
+ };
+ int fd = open(names[static_cast<int>(feature)], O_RDONLY | O_CLOEXEC);
+ char on;
+ if (fd == -1) {
+ ALOGE_IF(errno != ENOENT, "%s: cannot open %s: %s", __func__,
+ names[static_cast<int>(feature)], strerror(errno));
+ return false;
+ }
+ if (read(fd, &on, sizeof(on)) == -1) {
+ ALOGE("%s: error reading to %s: %s", __func__,
+ names[static_cast<int>(feature)], strerror(errno));
+ return false;
+ }
+ close(fd);
+ return on == '1';
+}
+
status_t ProcessState::enableOnewaySpamDetection(bool enable) {
uint32_t enableDetection = enable ? 1 : 0;
if (ioctl(mDriverFD, BINDER_ENABLE_ONEWAY_SPAM_DETECTION, &enableDetection) == -1) {
@@ -452,7 +475,9 @@ static base::Result<int> open_driver(const char* driver) {
uint32_t enable = DEFAULT_ENABLE_ONEWAY_SPAM_DETECTION;
result = ioctl(fd, BINDER_ENABLE_ONEWAY_SPAM_DETECTION, &enable);
if (result == -1) {
- ALOGV("Binder ioctl to enable oneway spam detection failed: %s", strerror(errno));
+ ALOGE_IF(ProcessState::isDriverFeatureEnabled(
+ ProcessState::DriverFeature::ONEWAY_SPAM_DETECTION),
+ "Binder ioctl to enable oneway spam detection failed: %s", strerror(errno));
}
return fd;
}
diff --git a/libs/binder/RpcSession.cpp b/libs/binder/RpcSession.cpp
index b84395e7cb..d40778a3d8 100644
--- a/libs/binder/RpcSession.cpp
+++ b/libs/binder/RpcSession.cpp
@@ -152,8 +152,13 @@ status_t RpcSession::setupInetClient(const char* addr, unsigned int port) {
}
status_t RpcSession::setupPreconnectedClient(unique_fd fd, std::function<unique_fd()>&& request) {
- return setupClient([&](const std::vector<uint8_t>& sessionId, bool incoming) -> status_t {
- // std::move'd from fd becomes -1 (!ok())
+ // Why passing raw fd? When fd is passed as reference, Clang analyzer sees that the variable
+ // `fd` is a moved-from object. To work-around the issue, unwrap the raw fd from the outer `fd`,
+ // pass the raw fd by value to the lambda, and then finally wrap it in unique_fd inside the
+ // lambda.
+ return setupClient([&, raw = fd.release()](const std::vector<uint8_t>& sessionId,
+ bool incoming) -> status_t {
+ unique_fd fd(raw);
if (!fd.ok()) {
fd = request();
if (!fd.ok()) return BAD_VALUE;
@@ -848,10 +853,16 @@ status_t RpcSession::ExclusiveConnection::find(const sp<RpcSession>& session, Co
}
if (session->mConnections.mOutgoing.size() == 0) {
- ALOGE("Session has no client connections. This is required for an RPC server to make "
- "any non-nested (e.g. oneway or on another thread) calls. Use: %d. Server "
- "connections: %zu",
- static_cast<int>(use), session->mConnections.mIncoming.size());
+ ALOGE("Session has no outgoing connections. This is required for an RPC server to make "
+ "any non-nested (e.g. oneway or on another thread) calls. Use code request "
+ "reason: %d. Incoming connections: %zu. %s.",
+ static_cast<int>(use), session->mConnections.mIncoming.size(),
+ (session->server()
+ ? "This is a server session, so see RpcSession::setMaxIncomingThreads "
+ "for the corresponding client"
+ : "This is a client session, so see RpcSession::setMaxOutgoingThreads "
+ "for this client or RpcServer::setMaxThreads for the corresponding "
+ "server"));
return WOULD_BLOCK;
}
diff --git a/libs/binder/RpcState.cpp b/libs/binder/RpcState.cpp
index 4ddbce71a8..6d89064a5d 100644
--- a/libs/binder/RpcState.cpp
+++ b/libs/binder/RpcState.cpp
@@ -125,8 +125,8 @@ status_t RpcState::onBinderLeaving(const sp<RpcSession>& session, const sp<IBind
auto&& [it, inserted] = mNodeForAddress.insert({RpcWireAddress::toRaw(address),
BinderNode{
.binder = binder,
- .timesSent = 1,
.sentRef = binder,
+ .timesSent = 1,
}});
if (inserted) {
*outAddress = it->first;
@@ -313,7 +313,8 @@ status_t RpcState::rpcSend(const sp<RpcSession::RpcConnection>& connection,
const sp<RpcSession>& session, const char* what, iovec* iovs, int niovs,
const std::function<status_t()>& altPoll) {
for (int i = 0; i < niovs; i++) {
- LOG_RPC_DETAIL("Sending %s on RpcTransport %p: %s", what, connection->rpcTransport.get(),
+ LOG_RPC_DETAIL("Sending %s (part %d of %d) on RpcTransport %p: %s",
+ what, i + 1, niovs, connection->rpcTransport.get(),
android::base::HexString(iovs[i].iov_base, iovs[i].iov_len).c_str());
}
@@ -343,7 +344,8 @@ status_t RpcState::rpcRec(const sp<RpcSession::RpcConnection>& connection,
}
for (int i = 0; i < niovs; i++) {
- LOG_RPC_DETAIL("Received %s on RpcTransport %p: %s", what, connection->rpcTransport.get(),
+ LOG_RPC_DETAIL("Received %s (part %d of %d) on RpcTransport %p: %s",
+ what, i + 1, niovs, connection->rpcTransport.get(),
android::base::HexString(iovs[i].iov_base, iovs[i].iov_len).c_str());
}
return OK;
@@ -660,8 +662,14 @@ status_t RpcState::getAndExecuteCommand(const sp<RpcSession::RpcConnection>& con
status_t RpcState::drainCommands(const sp<RpcSession::RpcConnection>& connection,
const sp<RpcSession>& session, CommandType type) {
uint8_t buf;
- while (connection->rpcTransport->peek(&buf, sizeof(buf)).value_or(0) > 0) {
- status_t status = getAndExecuteCommand(connection, session, type);
+ while (true) {
+ size_t num_bytes;
+ status_t status = connection->rpcTransport->peek(&buf, sizeof(buf), &num_bytes);
+ if (status == WOULD_BLOCK) break;
+ if (status != OK) return status;
+ if (!num_bytes) break;
+
+ status = getAndExecuteCommand(connection, session, type);
if (status != OK) return status;
}
return OK;
diff --git a/libs/binder/RpcTransportRaw.cpp b/libs/binder/RpcTransportRaw.cpp
index 636e5d06e5..7cfc78082e 100644
--- a/libs/binder/RpcTransportRaw.cpp
+++ b/libs/binder/RpcTransportRaw.cpp
@@ -24,9 +24,6 @@
#include "FdTrigger.h"
#include "RpcState.h"
-using android::base::ErrnoError;
-using android::base::Result;
-
namespace android {
namespace {
@@ -35,12 +32,20 @@ namespace {
class RpcTransportRaw : public RpcTransport {
public:
explicit RpcTransportRaw(android::base::unique_fd socket) : mSocket(std::move(socket)) {}
- Result<size_t> peek(void *buf, size_t size) override {
+ status_t peek(void* buf, size_t size, size_t* out_size) override {
ssize_t ret = TEMP_FAILURE_RETRY(::recv(mSocket.get(), buf, size, MSG_PEEK));
if (ret < 0) {
- return ErrnoError() << "recv(MSG_PEEK)";
+ int savedErrno = errno;
+ if (savedErrno == EAGAIN || savedErrno == EWOULDBLOCK) {
+ return WOULD_BLOCK;
+ }
+
+ LOG_RPC_DETAIL("RpcTransport peek(): %s", strerror(savedErrno));
+ return -savedErrno;
}
- return ret;
+
+ *out_size = static_cast<size_t>(ret);
+ return OK;
}
template <typename SendOrReceive>
diff --git a/libs/binder/RpcTransportTls.cpp b/libs/binder/RpcTransportTls.cpp
index 3936204bdf..bc68c379ce 100644
--- a/libs/binder/RpcTransportTls.cpp
+++ b/libs/binder/RpcTransportTls.cpp
@@ -37,10 +37,6 @@
#define LOG_TLS_DETAIL(...) ALOGV(__VA_ARGS__) // for type checking
#endif
-using android::base::ErrnoError;
-using android::base::Error;
-using android::base::Result;
-
namespace android {
namespace {
@@ -165,17 +161,8 @@ public:
return ret;
}
- // |sslError| should be from Ssl::getError().
- // If |sslError| is WANT_READ / WANT_WRITE, poll for POLLIN / POLLOUT respectively. Otherwise
- // return error. Also return error if |fdTrigger| is triggered before or during poll().
- status_t pollForSslError(android::base::borrowed_fd fd, int sslError, FdTrigger* fdTrigger,
- const char* fnString, int additionalEvent,
- const std::function<status_t()>& altPoll) {
+ status_t toStatus(int sslError, const char* fnString) {
switch (sslError) {
- case SSL_ERROR_WANT_READ:
- return handlePoll(POLLIN | additionalEvent, fd, fdTrigger, fnString, altPoll);
- case SSL_ERROR_WANT_WRITE:
- return handlePoll(POLLOUT | additionalEvent, fd, fdTrigger, fnString, altPoll);
case SSL_ERROR_SYSCALL: {
auto queue = toString();
LOG_TLS_DETAIL("%s(): %s. Treating as DEAD_OBJECT. Error queue: %s", fnString,
@@ -191,6 +178,22 @@ public:
}
}
+ // |sslError| should be from Ssl::getError().
+ // If |sslError| is WANT_READ / WANT_WRITE, poll for POLLIN / POLLOUT respectively. Otherwise
+ // return error. Also return error if |fdTrigger| is triggered before or during poll().
+ status_t pollForSslError(android::base::borrowed_fd fd, int sslError, FdTrigger* fdTrigger,
+ const char* fnString, int additionalEvent,
+ const std::function<status_t()>& altPoll) {
+ switch (sslError) {
+ case SSL_ERROR_WANT_READ:
+ return handlePoll(POLLIN | additionalEvent, fd, fdTrigger, fnString, altPoll);
+ case SSL_ERROR_WANT_WRITE:
+ return handlePoll(POLLOUT | additionalEvent, fd, fdTrigger, fnString, altPoll);
+ default:
+ return toStatus(sslError, fnString);
+ }
+ }
+
private:
bool mHandled = false;
@@ -274,7 +277,7 @@ class RpcTransportTls : public RpcTransport {
public:
RpcTransportTls(android::base::unique_fd socket, Ssl ssl)
: mSocket(std::move(socket)), mSsl(std::move(ssl)) {}
- Result<size_t> peek(void* buf, size_t size) override;
+ status_t peek(void* buf, size_t size, size_t* out_size) override;
status_t interruptableWriteFully(FdTrigger* fdTrigger, iovec* iovs, int niovs,
const std::function<status_t()>& altPoll) override;
status_t interruptableReadFully(FdTrigger* fdTrigger, iovec* iovs, int niovs,
@@ -286,7 +289,7 @@ private:
};
// Error code is errno.
-Result<size_t> RpcTransportTls::peek(void* buf, size_t size) {
+status_t RpcTransportTls::peek(void* buf, size_t size, size_t* out_size) {
size_t todo = std::min<size_t>(size, std::numeric_limits<int>::max());
auto [ret, errorQueue] = mSsl.call(SSL_peek, buf, static_cast<int>(todo));
if (ret < 0) {
@@ -294,13 +297,15 @@ Result<size_t> RpcTransportTls::peek(void* buf, size_t size) {
if (err == SSL_ERROR_WANT_WRITE || err == SSL_ERROR_WANT_READ) {
// Seen EAGAIN / EWOULDBLOCK on recv(2) / send(2).
// Like RpcTransportRaw::peek(), don't handle it here.
- return Error(EWOULDBLOCK) << "SSL_peek(): " << errorQueue.toString();
+ errorQueue.clear();
+ return WOULD_BLOCK;
}
- return Error() << "SSL_peek(): " << errorQueue.toString();
+ return errorQueue.toStatus(err, "SSL_peek");
}
errorQueue.clear();
LOG_TLS_DETAIL("TLS: Peeked %d bytes!", ret);
- return ret;
+ *out_size = static_cast<size_t>(ret);
+ return OK;
}
status_t RpcTransportTls::interruptableWriteFully(FdTrigger* fdTrigger, iovec* iovs, int niovs,
diff --git a/libs/binder/Static.h b/libs/binder/Static.h
index 83524e8575..8444fe780c 100644
--- a/libs/binder/Static.h
+++ b/libs/binder/Static.h
@@ -17,8 +17,6 @@
// All static variables go here, to control initialization and
// destruction order in the library.
-#include <utils/threads.h>
-
#include <binder/IBinder.h>
#include <binder/ProcessState.h>
diff --git a/libs/binder/include/binder/BpBinder.h b/libs/binder/include/binder/BpBinder.h
index c0454b6fbd..19ad5e6efe 100644
--- a/libs/binder/include/binder/BpBinder.h
+++ b/libs/binder/include/binder/BpBinder.h
@@ -17,10 +17,9 @@
#pragma once
#include <binder/IBinder.h>
-#include <utils/KeyedVector.h>
#include <utils/Mutex.h>
-#include <utils/threads.h>
+#include <map>
#include <unordered_map>
#include <variant>
@@ -110,7 +109,7 @@ public:
IBinder::object_cleanup_func func;
};
- KeyedVector<const void*, entry_t> mObjects;
+ std::map<const void*, entry_t> mObjects;
};
class PrivateAccessor {
diff --git a/libs/binder/include/binder/IServiceManager.h b/libs/binder/include/binder/IServiceManager.h
index ea40db8ffa..bb55831ec2 100644
--- a/libs/binder/include/binder/IServiceManager.h
+++ b/libs/binder/include/binder/IServiceManager.h
@@ -56,8 +56,16 @@ public:
static const int DUMP_FLAG_PROTO = 1 << 4;
/**
- * Retrieve an existing service, blocking for a few seconds
- * if it doesn't yet exist.
+ * Retrieve an existing service, blocking for a few seconds if it doesn't yet exist. This
+ * does polling. A more efficient way to make sure you unblock as soon as the service is
+ * available is to use waitForService or to use service notifications.
+ *
+ * Warning: when using this API, typically, you should call it in a loop. It's dangerous to
+ * assume that nullptr could mean that the service is not available. The service could just
+ * be starting. Generally, whether a service exists, this information should be declared
+ * externally (for instance, an Android feature might imply the existence of a service,
+ * a system property, or in the case of services in the VINTF manifest, it can be checked
+ * with isDeclared).
*/
virtual sp<IBinder> getService( const String16& name) const = 0;
diff --git a/libs/binder/include/binder/MemoryHeapBase.h b/libs/binder/include/binder/MemoryHeapBase.h
index dd76943ac7..15dd28f08e 100644
--- a/libs/binder/include/binder/MemoryHeapBase.h
+++ b/libs/binder/include/binder/MemoryHeapBase.h
@@ -34,7 +34,21 @@ public:
// memory won't be mapped locally, but will be mapped in the remote
// process.
DONT_MAP_LOCALLY = 0x00000100,
- NO_CACHING = 0x00000200
+ NO_CACHING = 0x00000200,
+ // Bypass ashmem-libcutils to create a memfd shared region.
+ // Ashmem-libcutils will eventually migrate to memfd.
+ // Memfd has security benefits and supports file sealing.
+ // Calling process will need to modify selinux permissions to
+ // open access to tmpfs files. See audioserver for examples.
+ // This is only valid for size constructor.
+ // For host compilation targets, memfd is stubbed in favor of /tmp
+ // files so sealing is not enforced.
+ FORCE_MEMFD = 0x00000400,
+ // Default opt-out of sealing behavior in memfd to avoid potential DOS.
+ // Clients of shared files can seal at anytime via syscall, leading to
+ // TOC/TOU issues if additional seals prevent access from the creating
+ // process. Alternatively, seccomp fcntl().
+ MEMFD_ALLOW_SEALING = 0x00000800
};
/*
diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h
index 450e3888f1..e2b2c5128d 100644
--- a/libs/binder/include/binder/Parcel.h
+++ b/libs/binder/include/binder/Parcel.h
@@ -95,6 +95,12 @@ public:
bool hasFileDescriptors() const;
status_t hasFileDescriptorsInRange(size_t offset, size_t length, bool* result) const;
+ // returns all binder objects in the Parcel
+ std::vector<sp<IBinder>> debugReadAllStrongBinders() const;
+ // returns all file descriptors in the Parcel
+ // does not dup
+ std::vector<int> debugReadAllFileDescriptors() const;
+
// Zeros data when reallocating. Other mitigations may be added
// in the future.
//
diff --git a/libs/binder/include/binder/ParcelableHolder.h b/libs/binder/include/binder/ParcelableHolder.h
index 42c85f9121..88790a803b 100644
--- a/libs/binder/include/binder/ParcelableHolder.h
+++ b/libs/binder/include/binder/ParcelableHolder.h
@@ -86,7 +86,7 @@ public:
*ret = nullptr;
return android::BAD_VALUE;
}
- *ret = std::shared_ptr<T>(mParcelable, reinterpret_cast<T*>(mParcelable.get()));
+ *ret = std::static_pointer_cast<T>(mParcelable);
return android::OK;
}
this->mParcelPtr->setDataPosition(0);
@@ -105,7 +105,7 @@ public:
return status;
}
this->mParcelPtr = nullptr;
- *ret = std::shared_ptr<T>(mParcelable, reinterpret_cast<T*>(mParcelable.get()));
+ *ret = std::static_pointer_cast<T>(mParcelable);
return android::OK;
}
diff --git a/libs/binder/include/binder/PermissionController.h b/libs/binder/include/binder/PermissionController.h
index e65857417b..6f9eb5e4b9 100644
--- a/libs/binder/include/binder/PermissionController.h
+++ b/libs/binder/include/binder/PermissionController.h
@@ -19,8 +19,7 @@
#ifndef __ANDROID_VNDK__
#include <binder/IPermissionController.h>
-
-#include <utils/threads.h>
+#include <utils/Mutex.h>
// ---------------------------------------------------------------------------
namespace android {
diff --git a/libs/binder/include/binder/ProcessState.h b/libs/binder/include/binder/ProcessState.h
index cf8d8e433c..675585ecef 100644
--- a/libs/binder/include/binder/ProcessState.h
+++ b/libs/binder/include/binder/ProcessState.h
@@ -18,11 +18,10 @@
#include <binder/IBinder.h>
#include <utils/KeyedVector.h>
+#include <utils/Mutex.h>
#include <utils/String16.h>
#include <utils/String8.h>
-#include <utils/threads.h>
-
#include <pthread.h>
// ---------------------------------------------------------------------------
@@ -91,6 +90,12 @@ public:
*/
size_t getThreadPoolMaxThreadCount() const;
+ enum class DriverFeature {
+ ONEWAY_SPAM_DETECTION,
+ };
+ // Determine whether a feature is supported by the binder driver.
+ static bool isDriverFeatureEnabled(const DriverFeature feature);
+
private:
static sp<ProcessState> init(const char* defaultDriver, bool requireDefault);
diff --git a/libs/binder/include/binder/RpcServer.h b/libs/binder/include/binder/RpcServer.h
index aaa812b067..6b31812d17 100644
--- a/libs/binder/include/binder/RpcServer.h
+++ b/libs/binder/include/binder/RpcServer.h
@@ -77,7 +77,7 @@ public:
* have
*/
[[nodiscard]] status_t setupInetServer(const char* address, unsigned int port,
- unsigned int* assignedPort);
+ unsigned int* assignedPort = nullptr);
/**
* If setup*Server has been successful, return true. Otherwise return false.
diff --git a/libs/binder/include/binder/RpcTransport.h b/libs/binder/include/binder/RpcTransport.h
index ade2d94609..751c4f905d 100644
--- a/libs/binder/include/binder/RpcTransport.h
+++ b/libs/binder/include/binder/RpcTransport.h
@@ -22,7 +22,6 @@
#include <memory>
#include <string>
-#include <android-base/result.h>
#include <android-base/unique_fd.h>
#include <utils/Errors.h>
@@ -41,7 +40,7 @@ public:
virtual ~RpcTransport() = default;
// replacement of ::recv(MSG_PEEK). Error code may not be set if TLS is enabled.
- [[nodiscard]] virtual android::base::Result<size_t> peek(void *buf, size_t size) = 0;
+ [[nodiscard]] virtual status_t peek(void *buf, size_t size, size_t *out_size) = 0;
/**
* Read (or write), but allow to be interrupted by a trigger.
diff --git a/libs/binder/include_activitymanager/binder/ActivityManager.h b/libs/binder/include_activitymanager/binder/ActivityManager.h
index b772b80227..abc7f1d374 100644
--- a/libs/binder/include_activitymanager/binder/ActivityManager.h
+++ b/libs/binder/include_activitymanager/binder/ActivityManager.h
@@ -18,10 +18,9 @@
#ifndef __ANDROID_VNDK__
-#include <binder/IActivityManager.h>
#include <android/app/ProcessStateEnum.h>
-
-#include <utils/threads.h>
+#include <binder/IActivityManager.h>
+#include <utils/Mutex.h>
// ---------------------------------------------------------------------------
namespace android {
diff --git a/libs/binder/ndk/include_cpp/android/binder_auto_utils.h b/libs/binder/ndk/include_cpp/android/binder_auto_utils.h
index 2c471c6e8f..7ea9be797b 100644
--- a/libs/binder/ndk/include_cpp/android/binder_auto_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_auto_utils.h
@@ -268,7 +268,11 @@ class ScopedAStatus : public impl::ScopedAResource<AStatus*, AStatus_delete, nul
const char* getMessage() const { return AStatus_getMessage(get()); }
std::string getDescription() const {
+#ifdef __ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__
if (__builtin_available(android 30, *)) {
+#else
+ if (__ANDROID_API__ >= 30) {
+#endif
const char* cStr = AStatus_getDescription(get());
std::string ret = cStr;
AStatus_deleteDescription(cStr);
diff --git a/libs/binder/ndk/include_cpp/android/binder_interface_utils.h b/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
index 09411e76a3..b3bc7f449e 100644
--- a/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
@@ -256,7 +256,11 @@ AIBinder_Class* ICInterface::defineClass(const char* interfaceDescriptor,
// ourselves. The defaults are harmless.
AIBinder_Class_setOnDump(clazz, ICInterfaceData::onDump);
#ifdef HAS_BINDER_SHELL_COMMAND
+#ifdef __ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__
if (__builtin_available(android 30, *)) {
+#else
+ if (__ANDROID_API__ >= 30) {
+#endif
AIBinder_Class_setHandleShellCommand(clazz, ICInterfaceData::handleShellCommand);
}
#endif
diff --git a/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h b/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h
index 972eca79ff..f45aa7631b 100644
--- a/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h
@@ -51,7 +51,11 @@ class AParcelableHolder {
AParcelableHolder(const AParcelableHolder& other)
: mParcel(AParcel_create()), mStability(other.mStability) {
// AParcelableHolder has been introduced in 31.
+#ifdef __ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__
if (__builtin_available(android 31, *)) {
+#else
+ if (__ANDROID_API__ >= 31) {
+#endif
AParcel_appendFrom(other.mParcel.get(), this->mParcel.get(), 0,
AParcel_getDataSize(other.mParcel.get()));
}
@@ -63,13 +67,21 @@ class AParcelableHolder {
binder_status_t writeToParcel(AParcel* parcel) const {
RETURN_ON_FAILURE(AParcel_writeInt32(parcel, static_cast<int32_t>(this->mStability)));
+#ifdef __ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__
if (__builtin_available(android 31, *)) {
+#else
+ if (__ANDROID_API__ >= 31) {
+#endif
int32_t size = AParcel_getDataSize(this->mParcel.get());
RETURN_ON_FAILURE(AParcel_writeInt32(parcel, size));
} else {
return STATUS_INVALID_OPERATION;
}
+#ifdef __ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__
if (__builtin_available(android 31, *)) {
+#else
+ if (__ANDROID_API__ >= 31) {
+#endif
int32_t size = AParcel_getDataSize(this->mParcel.get());
RETURN_ON_FAILURE(AParcel_appendFrom(this->mParcel.get(), parcel, 0, size));
} else {
@@ -79,13 +91,22 @@ class AParcelableHolder {
}
binder_status_t readFromParcel(const AParcel* parcel) {
+#ifdef __ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__
if (__builtin_available(android 31, *)) {
+#else
+ if (__ANDROID_API__ >= 31) {
+#endif
AParcel_reset(mParcel.get());
} else {
return STATUS_INVALID_OPERATION;
}
- RETURN_ON_FAILURE(AParcel_readInt32(parcel, &this->mStability));
+ parcelable_stability_t wireStability;
+ RETURN_ON_FAILURE(AParcel_readInt32(parcel, &wireStability));
+ if (this->mStability != wireStability) {
+ return STATUS_BAD_VALUE;
+ }
+
int32_t dataSize;
binder_status_t status = AParcel_readInt32(parcel, &dataSize);
@@ -99,7 +120,11 @@ class AParcelableHolder {
return STATUS_BAD_VALUE;
}
+#ifdef __ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__
if (__builtin_available(android 31, *)) {
+#else
+ if (__ANDROID_API__ >= 31) {
+#endif
status = AParcel_appendFrom(parcel, mParcel.get(), dataStartPos, dataSize);
} else {
status = STATUS_INVALID_OPERATION;
@@ -115,7 +140,11 @@ class AParcelableHolder {
if (this->mStability > T::_aidl_stability) {
return STATUS_BAD_VALUE;
}
+#ifdef __ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__
if (__builtin_available(android 31, *)) {
+#else
+ if (__ANDROID_API__ >= 31) {
+#endif
AParcel_reset(mParcel.get());
} else {
return STATUS_INVALID_OPERATION;
@@ -129,7 +158,11 @@ class AParcelableHolder {
binder_status_t getParcelable(std::optional<T>* ret) const {
const std::string parcelableDesc(T::descriptor);
AParcel_setDataPosition(mParcel.get(), 0);
+#ifdef __ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__
if (__builtin_available(android 31, *)) {
+#else
+ if (__ANDROID_API__ >= 31) {
+#endif
if (AParcel_getDataSize(mParcel.get()) == 0) {
*ret = std::nullopt;
return STATUS_OK;
@@ -153,7 +186,11 @@ class AParcelableHolder {
}
void reset() {
+#ifdef __ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__
if (__builtin_available(android 31, *)) {
+#else
+ if (__ANDROID_API__ >= 31) {
+#endif
AParcel_reset(mParcel.get());
}
}
diff --git a/libs/binder/ndk/include_ndk/android/binder_ibinder_jni.h b/libs/binder/ndk/include_ndk/android/binder_ibinder_jni.h
index 6880d86e1a..8e288b307e 100644
--- a/libs/binder/ndk/include_ndk/android/binder_ibinder_jni.h
+++ b/libs/binder/ndk/include_ndk/android/binder_ibinder_jni.h
@@ -56,6 +56,12 @@ __attribute__((warn_unused_result)) AIBinder* AIBinder_fromJavaBinder(JNIEnv* en
* If the binder is null, null is returned. If this binder object was originally an IBinder object,
* the original java object will be returned.
*
+ * WARNING: this function returns global and local references. This can be
+ * figured out using GetObjectRefType. Though, when this function is called
+ * from within a Java context, the local ref will automatically be cleaned
+ * up. If this is called outside of a Java frame,
+ * PushObjectFrame/PopObjectFrame can simulate this automatic cleanup.
+ *
* Available since API level 29.
*
* \param env Java environment. Must not be null.
diff --git a/libs/binder/ndk/include_platform/android/binder_manager.h b/libs/binder/ndk/include_platform/android/binder_manager.h
index 2a66941cef..dfa8ea28e7 100644
--- a/libs/binder/ndk/include_platform/android/binder_manager.h
+++ b/libs/binder/ndk/include_platform/android/binder_manager.h
@@ -53,11 +53,19 @@ __attribute__((warn_unused_result)) AIBinder* AServiceManager_checkService(const
/**
* Gets a binder object with this specific instance name. Blocks for a couple of seconds waiting on
* it. This also implicitly calls AIBinder_incStrong (so the caller of this function is responsible
- * for calling AIBinder_decStrong).
+ * for calling AIBinder_decStrong). This does polling. A more efficient way to make sure you
+ * unblock as soon as the service is available is to use AIBinder_waitForService.
*
* WARNING: when using this API across an APEX boundary, do not use with unstable
* AIDL services. TODO(b/139325195)
*
+ * WARNING: when using this API, typically, you should call it in a loop. It's dangerous to
+ * assume that nullptr could mean that the service is not available. The service could just
+ * be starting. Generally, whether a service exists, this information should be declared
+ * externally (for instance, an Android feature might imply the existence of a service,
+ * a system property, or in the case of services in the VINTF manifest, it can be checked
+ * with AServiceManager_isDeclared).
+ *
* \param instance identifier of the service used to lookup the service.
*/
__attribute__((warn_unused_result)) AIBinder* AServiceManager_getService(const char* instance)
diff --git a/libs/binder/ndk/include_platform/android/binder_stability.h b/libs/binder/ndk/include_platform/android/binder_stability.h
index f113ba8f21..d0cd11f6fc 100644
--- a/libs/binder/ndk/include_platform/android/binder_stability.h
+++ b/libs/binder/ndk/include_platform/android/binder_stability.h
@@ -97,6 +97,10 @@ static inline void AIBinder_forceDowngradeToLocalStability(AIBinder* binder) {
*
* This interface has system<->vendor stability
*/
+// b/227835797 - can't use __INTRODUCED_IN(30) because old targets load this code
+#if __ANDROID_MIN_SDK_VERSION__ < 30
+__attribute__((weak))
+#endif // __ANDROID_MIN_SDK_VERSION__ < 30
void AIBinder_markVintfStability(AIBinder* binder);
__END_DECLS
diff --git a/libs/binder/rust/src/binder.rs b/libs/binder/rust/src/binder.rs
index 467e51e276..5d6206de0b 100644
--- a/libs/binder/rust/src/binder.rs
+++ b/libs/binder/rust/src/binder.rs
@@ -1086,7 +1086,7 @@ macro_rules! declare_binder_enum {
{
$( #[$attr:meta] )*
$enum:ident : [$backing:ty; $size:expr] {
- $( $name:ident = $value:expr, )*
+ $( $( #[$value_attr:meta] )* $name:ident = $value:expr, )*
}
} => {
$( #[$attr] )*
@@ -1094,7 +1094,7 @@ macro_rules! declare_binder_enum {
#[allow(missing_docs)]
pub struct $enum(pub $backing);
impl $enum {
- $( #[allow(missing_docs)] pub const $name: Self = Self($value); )*
+ $( $( #[$value_attr] )* #[allow(missing_docs)] pub const $name: Self = Self($value); )*
#[inline(always)]
#[allow(missing_docs)]
diff --git a/libs/binder/rust/src/parcel/parcelable_holder.rs b/libs/binder/rust/src/parcel/parcelable_holder.rs
index d58e839ad4..432da5dfd7 100644
--- a/libs/binder/rust/src/parcel/parcelable_holder.rs
+++ b/libs/binder/rust/src/parcel/parcelable_holder.rs
@@ -233,7 +233,9 @@ impl Parcelable for ParcelableHolder {
}
fn read_from_parcel(&mut self, parcel: &BorrowedParcel<'_>) -> Result<(), StatusCode> {
- self.stability = parcel.read()?;
+ if self.stability != parcel.read()? {
+ return Err(StatusCode::BAD_VALUE);
+ }
let data_size: i32 = parcel.read()?;
if data_size < 0 {
diff --git a/libs/binder/rust/src/proxy.rs b/libs/binder/rust/src/proxy.rs
index e3e47305d4..4df557bee0 100644
--- a/libs/binder/rust/src/proxy.rs
+++ b/libs/binder/rust/src/proxy.rs
@@ -575,6 +575,20 @@ struct DeathRecipientVtable {
cookie_decr_refcount: unsafe extern "C" fn(*mut c_void),
}
+/// # Safety
+///
+/// A `DeathRecipient` is a wrapper around `AIBinder_DeathRecipient` and a pointer
+/// to a `Fn` which is `Sync` and `Send` (the cookie field). As
+/// `AIBinder_DeathRecipient` is threadsafe, this structure is too.
+unsafe impl Send for DeathRecipient {}
+
+/// # Safety
+///
+/// A `DeathRecipient` is a wrapper around `AIBinder_DeathRecipient` and a pointer
+/// to a `Fn` which is `Sync` and `Send` (the cookie field). As
+/// `AIBinder_DeathRecipient` is threadsafe, this structure is too.
+unsafe impl Sync for DeathRecipient {}
+
impl DeathRecipient {
/// Create a new death recipient that will call the given callback when its
/// associated object dies.
diff --git a/libs/binder/rust/tests/serialization.cpp b/libs/binder/rust/tests/serialization.cpp
index ec780f28a1..3f59dab3a9 100644
--- a/libs/binder/rust/tests/serialization.cpp
+++ b/libs/binder/rust/tests/serialization.cpp
@@ -381,7 +381,7 @@ TEST_F(SerializationTest, SerializeFileDescriptor) {
string expected = "TestingFileDescriptors";
vector<char> buf(expected.length());
base::ReadFully(file_descriptors[0].release(), buf.data(), buf.size());
- ASSERT_EQ(expected, string(buf.data()));
+ ASSERT_EQ(expected, string(buf.data(), expected.length()));
}
TEST_F(SerializationTest, SerializeIBinder) {
diff --git a/libs/binder/rust/tests/serialization.rs b/libs/binder/rust/tests/serialization.rs
index b62da7be03..f6bdf5c9ed 100644
--- a/libs/binder/rust/tests/serialization.rs
+++ b/libs/binder/rust/tests/serialization.rs
@@ -117,8 +117,8 @@ fn on_transact(
) -> Result<(), StatusCode> {
match code {
bindings::Transaction_TEST_BOOL => {
- assert_eq!(parcel.read::<bool>()?, true);
- assert_eq!(parcel.read::<bool>()?, false);
+ assert!(parcel.read::<bool>()?);
+ assert!(!parcel.read::<bool>()?);
assert_eq!(parcel.read::<Vec<bool>>()?, unsafe {
bindings::TESTDATA_BOOL
});
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index ff55d6ebdc..a3533d831b 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -99,6 +99,7 @@ cc_test {
"binderParcelUnitTest.cpp",
"binderBinderUnitTest.cpp",
"binderStatusUnitTest.cpp",
+ "binderMemoryHeapBaseUnitTest.cpp",
],
shared_libs: [
"libbinder",
diff --git a/libs/binder/tests/binderBinderUnitTest.cpp b/libs/binder/tests/binderBinderUnitTest.cpp
index 1be0c59c78..ce2770f943 100644
--- a/libs/binder/tests/binderBinderUnitTest.cpp
+++ b/libs/binder/tests/binderBinderUnitTest.cpp
@@ -41,3 +41,10 @@ TEST(Binder, DetachObject) {
EXPECT_EQ(kObject1, binder->detachObject(kObjectId1));
EXPECT_EQ(nullptr, binder->attachObject(kObjectId1, kObject2, nullptr, nullptr));
}
+
+TEST(Binder, AttachExtension) {
+ auto binder = sp<BBinder>::make();
+ auto ext = sp<BBinder>::make();
+ binder->setExtension(ext);
+ EXPECT_EQ(ext, binder->getExtension());
+}
diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp
index b1e17b7892..57a1fda95f 100644
--- a/libs/binder/tests/binderLibTest.cpp
+++ b/libs/binder/tests/binderLibTest.cpp
@@ -247,13 +247,11 @@ class BinderLibTest : public ::testing::Test {
{
int32_t id;
Parcel data, reply;
- sp<IBinder> binder;
EXPECT_THAT(m_server->transact(code, data, &reply), StatusEq(NO_ERROR));
- EXPECT_FALSE(binder != nullptr);
- binder = reply.readStrongBinder();
- EXPECT_TRUE(binder != nullptr);
+ sp<IBinder> binder = reply.readStrongBinder();
+ EXPECT_NE(nullptr, binder);
EXPECT_THAT(reply.readInt32(&id), StatusEq(NO_ERROR));
if (idPtr)
*idPtr = id;
diff --git a/libs/binder/tests/binderMemoryHeapBaseUnitTest.cpp b/libs/binder/tests/binderMemoryHeapBaseUnitTest.cpp
new file mode 100644
index 0000000000..21cb70be17
--- /dev/null
+++ b/libs/binder/tests/binderMemoryHeapBaseUnitTest.cpp
@@ -0,0 +1,97 @@
+/*
+ * 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 <binder/MemoryHeapBase.h>
+#include <cutils/ashmem.h>
+#include <fcntl.h>
+
+#include <gtest/gtest.h>
+using namespace android;
+#ifdef __BIONIC__
+TEST(MemoryHeapBase, ForceMemfdRespected) {
+ auto mHeap = sp<MemoryHeapBase>::make(10, MemoryHeapBase::FORCE_MEMFD, "Test mapping");
+ int fd = mHeap->getHeapID();
+ EXPECT_NE(fd, -1);
+ EXPECT_FALSE(ashmem_valid(fd));
+ EXPECT_NE(fcntl(fd, F_GET_SEALS), -1);
+}
+
+TEST(MemoryHeapBase, MemfdSealed) {
+ auto mHeap = sp<MemoryHeapBase>::make(8192,
+ MemoryHeapBase::FORCE_MEMFD,
+ "Test mapping");
+ int fd = mHeap->getHeapID();
+ EXPECT_NE(fd, -1);
+ EXPECT_EQ(fcntl(fd, F_GET_SEALS), F_SEAL_SEAL);
+}
+
+TEST(MemoryHeapBase, MemfdUnsealed) {
+ auto mHeap = sp<MemoryHeapBase>::make(8192,
+ MemoryHeapBase::FORCE_MEMFD |
+ MemoryHeapBase::MEMFD_ALLOW_SEALING,
+ "Test mapping");
+ int fd = mHeap->getHeapID();
+ EXPECT_NE(fd, -1);
+ EXPECT_EQ(fcntl(fd, F_GET_SEALS), 0);
+}
+
+TEST(MemoryHeapBase, MemfdSealedProtected) {
+ auto mHeap = sp<MemoryHeapBase>::make(8192,
+ MemoryHeapBase::FORCE_MEMFD |
+ MemoryHeapBase::READ_ONLY,
+ "Test mapping");
+ int fd = mHeap->getHeapID();
+ EXPECT_NE(fd, -1);
+ EXPECT_EQ(fcntl(fd, F_GET_SEALS), F_SEAL_SEAL | F_SEAL_FUTURE_WRITE);
+}
+
+TEST(MemoryHeapBase, MemfdUnsealedProtected) {
+ auto mHeap = sp<MemoryHeapBase>::make(8192,
+ MemoryHeapBase::FORCE_MEMFD |
+ MemoryHeapBase::READ_ONLY |
+ MemoryHeapBase::MEMFD_ALLOW_SEALING,
+ "Test mapping");
+ int fd = mHeap->getHeapID();
+ EXPECT_NE(fd, -1);
+ EXPECT_EQ(fcntl(fd, F_GET_SEALS), F_SEAL_FUTURE_WRITE);
+}
+
+#else
+TEST(MemoryHeapBase, HostMemfdExpected) {
+ auto mHeap = sp<MemoryHeapBase>::make(8192,
+ MemoryHeapBase::READ_ONLY,
+ "Test mapping");
+ int fd = mHeap->getHeapID();
+ void* ptr = mHeap->getBase();
+ EXPECT_NE(ptr, MAP_FAILED);
+ EXPECT_TRUE(ashmem_valid(fd));
+ EXPECT_EQ(mHeap->getFlags(), MemoryHeapBase::READ_ONLY);
+}
+
+TEST(MemoryHeapBase,HostMemfdException) {
+ auto mHeap = sp<MemoryHeapBase>::make(8192,
+ MemoryHeapBase::FORCE_MEMFD |
+ MemoryHeapBase::READ_ONLY |
+ MemoryHeapBase::MEMFD_ALLOW_SEALING,
+ "Test mapping");
+ int fd = mHeap->getHeapID();
+ void* ptr = mHeap->getBase();
+ EXPECT_EQ(mHeap->getFlags(), MemoryHeapBase::READ_ONLY);
+ EXPECT_TRUE(ashmem_valid(fd));
+ EXPECT_NE(ptr, MAP_FAILED);
+}
+
+#endif
diff --git a/libs/binder/tests/binderParcelUnitTest.cpp b/libs/binder/tests/binderParcelUnitTest.cpp
index aee15d8bd9..359c783de5 100644
--- a/libs/binder/tests/binderParcelUnitTest.cpp
+++ b/libs/binder/tests/binderParcelUnitTest.cpp
@@ -20,9 +20,12 @@
#include <cutils/ashmem.h>
#include <gtest/gtest.h>
+using android::BBinder;
+using android::IBinder;
using android::IPCThreadState;
using android::OK;
using android::Parcel;
+using android::sp;
using android::status_t;
using android::String16;
using android::String8;
@@ -75,6 +78,40 @@ TEST(Parcel, EnforceNoDataAvail) {
EXPECT_EQ(p.enforceNoDataAvail().exceptionCode(), Status::Exception::EX_NONE);
}
+TEST(Parcel, DebugReadAllBinders) {
+ sp<IBinder> binder1 = sp<BBinder>::make();
+ sp<IBinder> binder2 = sp<BBinder>::make();
+
+ Parcel p;
+ p.writeInt32(4);
+ p.writeStrongBinder(binder1);
+ p.writeStrongBinder(nullptr);
+ p.writeInt32(4);
+ p.writeStrongBinder(binder2);
+ p.writeInt32(4);
+
+ auto ret = p.debugReadAllStrongBinders();
+
+ ASSERT_EQ(ret.size(), 2);
+ EXPECT_EQ(ret[0], binder1);
+ EXPECT_EQ(ret[1], binder2);
+}
+
+TEST(Parcel, DebugReadAllFds) {
+ Parcel p;
+ p.writeInt32(4);
+ p.writeFileDescriptor(STDOUT_FILENO, false /*takeOwnership*/);
+ p.writeInt32(4);
+ p.writeFileDescriptor(STDIN_FILENO, false /*takeOwnership*/);
+ p.writeInt32(4);
+
+ auto ret = p.debugReadAllFileDescriptors();
+
+ ASSERT_EQ(ret.size(), 2);
+ EXPECT_EQ(ret[0], STDOUT_FILENO);
+ EXPECT_EQ(ret[1], STDIN_FILENO);
+}
+
// Tests a second operation results in a parcel at the same location as it
// started.
void parcelOpSameLength(const std::function<void(Parcel*)>& a, const std::function<void(Parcel*)>& b) {
diff --git a/libs/binder/tests/include_tls_test_utils/binder/RpcTlsTestUtils.h b/libs/binder/tests/include_tls_test_utils/binder/RpcTlsTestUtils.h
index 094addd690..50d12c408f 100644
--- a/libs/binder/tests/include_tls_test_utils/binder/RpcTlsTestUtils.h
+++ b/libs/binder/tests/include_tls_test_utils/binder/RpcTlsTestUtils.h
@@ -18,6 +18,7 @@
#include <memory>
#include <mutex>
+#include <vector>
#include <binder/RpcAuth.h>
#include <binder/RpcCertificateFormat.h>
diff --git a/libs/binder/tests/parcel_fuzzer/Android.bp b/libs/binder/tests/parcel_fuzzer/Android.bp
index 38bde3a011..e5d32da4cc 100644
--- a/libs/binder/tests/parcel_fuzzer/Android.bp
+++ b/libs/binder/tests/parcel_fuzzer/Android.bp
@@ -29,7 +29,6 @@ cc_fuzz {
"libcutils",
"libhidlbase",
"liblog",
- "libutils",
],
target: {
@@ -37,12 +36,14 @@ cc_fuzz {
shared_libs: [
"libbinder_ndk",
"libbinder",
+ "libutils",
],
},
host: {
static_libs: [
"libbinder_ndk",
"libbinder",
+ "libutils",
],
},
darwin: {
@@ -66,10 +67,13 @@ cc_library_static {
srcs: [
"random_fd.cpp",
"random_parcel.cpp",
+ "libbinder_driver.cpp",
+ "libbinder_ndk_driver.cpp",
],
shared_libs: [
"libbase",
"libbinder",
+ "libbinder_ndk",
"libcutils",
"libutils",
],
diff --git a/libs/binder/tests/parcel_fuzzer/binder.cpp b/libs/binder/tests/parcel_fuzzer/binder.cpp
index 13f7195eb7..47ec776990 100644
--- a/libs/binder/tests/parcel_fuzzer/binder.cpp
+++ b/libs/binder/tests/parcel_fuzzer/binder.cpp
@@ -109,6 +109,8 @@ std::vector<ParcelRead<::android::Parcel>> BINDER_PARCEL_READ_FUNCTIONS {
},
PARCEL_READ_NO_STATUS(size_t, allowFds),
PARCEL_READ_NO_STATUS(size_t, hasFileDescriptors),
+ PARCEL_READ_NO_STATUS(std::vector<android::sp<android::IBinder>>, debugReadAllStrongBinders),
+ PARCEL_READ_NO_STATUS(std::vector<int>, debugReadAllFileDescriptors),
[] (const ::android::Parcel& p, uint8_t len) {
std::string interface(len, 'a');
FUZZ_LOG() << "about to enforceInterface: " << interface;
diff --git a/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/libbinder_driver.h b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/libbinder_driver.h
new file mode 100644
index 0000000000..a9a6197439
--- /dev/null
+++ b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/libbinder_driver.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <binder/IBinder.h>
+#include <fuzzer/FuzzedDataProvider.h>
+
+namespace android {
+/**
+ * Based on the random data in provider, construct an arbitrary number of
+ * Parcel objects and send them to the service in serial.
+ *
+ * Usage:
+ *
+ * extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ * FuzzedDataProvider provider = FuzzedDataProvider(data, size);
+ * // can use provider here to create a service with different options
+ * sp<IFoo> myService = sp<IFoo>::make(...);
+ * fuzzService(myService, std::move(provider));
+ * }
+ */
+void fuzzService(const sp<IBinder>& binder, FuzzedDataProvider&& provider);
+} // namespace android
diff --git a/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/libbinder_ndk_driver.h b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/libbinder_ndk_driver.h
new file mode 100644
index 0000000000..f2b782337c
--- /dev/null
+++ b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/libbinder_ndk_driver.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/binder_parcel.h>
+#include <fuzzer/FuzzedDataProvider.h>
+
+namespace android {
+/**
+ * Based on the random data in provider, construct an arbitrary number of
+ * Parcel objects and send them to the service in serial.
+ *
+ * Usage:
+ *
+ * extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ * FuzzedDataProvider provider = FuzzedDataProvider(data, size);
+ * // can use provider here to create a service with different options
+ * std::shared_ptr<IFoo> myService = ndk::SharedRefBase<IFoo>::make(...);
+ * fuzzService(myService->asBinder().get(), std::move(provider));
+ * }
+ */
+void fuzzService(AIBinder* binder, FuzzedDataProvider&& provider);
+} // namespace android
diff --git a/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_fd.h b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_fd.h
index 0a083d7665..843b6e3011 100644
--- a/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_fd.h
+++ b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_fd.h
@@ -16,12 +16,13 @@
#pragma once
+#include <android-base/unique_fd.h>
#include <fuzzer/FuzzedDataProvider.h>
namespace android {
-// ownership to callee, always valid or aborts
+// always valid or aborts
// get a random FD for use in fuzzing, of a few different specific types
-int getRandomFd(FuzzedDataProvider* provider);
+base::unique_fd getRandomFd(FuzzedDataProvider* provider);
} // namespace android
diff --git a/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h
index 749bf212e6..459fb127c2 100644
--- a/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h
+++ b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h
@@ -19,13 +19,24 @@
#include <binder/Parcel.h>
#include <fuzzer/FuzzedDataProvider.h>
+#include <functional>
+#include <vector>
+
namespace android {
+
+struct RandomParcelOptions {
+ std::function<void(Parcel* p, FuzzedDataProvider& provider)> writeHeader;
+ std::vector<sp<IBinder>> extraBinders;
+ std::vector<base::unique_fd> extraFds;
+};
+
/**
* Fill parcel data, including some random binder objects and FDs
+ *
+ * p - the Parcel to fill
+ * provider - takes ownership and completely consumes provider
+ * writeHeader - optional function to write a specific header once the format of the parcel is
+ * picked (for instance, to write an interface header)
*/
-void fillRandomParcel(Parcel* p, FuzzedDataProvider&& provider);
-/**
- * Fill parcel data, but don't fill any objects.
- */
-void fillRandomParcelData(Parcel* p, FuzzedDataProvider&& provider);
+void fillRandomParcel(Parcel* p, FuzzedDataProvider&& provider, const RandomParcelOptions& = {});
} // namespace android
diff --git a/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp b/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp
new file mode 100644
index 0000000000..d5aa353af0
--- /dev/null
+++ b/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <fuzzbinder/libbinder_driver.h>
+
+#include <fuzzbinder/random_parcel.h>
+
+namespace android {
+
+void fuzzService(const sp<IBinder>& binder, FuzzedDataProvider&& provider) {
+ sp<IBinder> target;
+
+ RandomParcelOptions options{
+ .extraBinders = {binder},
+ .extraFds = {},
+ };
+
+ while (provider.remaining_bytes() > 0) {
+ uint32_t code = provider.ConsumeIntegral<uint32_t>();
+ uint32_t flags = provider.ConsumeIntegral<uint32_t>();
+ Parcel data;
+
+ sp<IBinder> target = options.extraBinders.at(
+ provider.ConsumeIntegralInRange<size_t>(0, options.extraBinders.size() - 1));
+ options.writeHeader = [&target](Parcel* p, FuzzedDataProvider& provider) {
+ // most code will be behind checks that the head of the Parcel
+ // is exactly this, so make it easier for fuzzers to reach this
+ if (provider.ConsumeBool()) {
+ p->writeInterfaceToken(target->getInterfaceDescriptor());
+ }
+ };
+
+ std::vector<uint8_t> subData = provider.ConsumeBytes<uint8_t>(
+ provider.ConsumeIntegralInRange<size_t>(0, provider.remaining_bytes()));
+ fillRandomParcel(&data, FuzzedDataProvider(subData.data(), subData.size()), options);
+
+ Parcel reply;
+ (void)target->transact(code, data, &reply, flags);
+
+ // feed back in binders and fds that are returned from the service, so that
+ // we can fuzz those binders, and use the fds and binders to feed back into
+ // the binders
+ auto retBinders = reply.debugReadAllStrongBinders();
+ options.extraBinders.insert(options.extraBinders.end(), retBinders.begin(),
+ retBinders.end());
+ auto retFds = reply.debugReadAllFileDescriptors();
+ for (size_t i = 0; i < retFds.size(); i++) {
+ options.extraFds.push_back(base::unique_fd(dup(retFds[i])));
+ }
+ }
+}
+
+} // namespace android
diff --git a/libs/binder/tests/parcel_fuzzer/libbinder_ndk_driver.cpp b/libs/binder/tests/parcel_fuzzer/libbinder_ndk_driver.cpp
new file mode 100644
index 0000000000..462ef9a5e9
--- /dev/null
+++ b/libs/binder/tests/parcel_fuzzer/libbinder_ndk_driver.cpp
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <fuzzbinder/libbinder_ndk_driver.h>
+
+#include <fuzzbinder/libbinder_driver.h>
+#include <fuzzbinder/random_parcel.h>
+
+// libbinder_ndk doesn't export this header which breaks down its API for NDK
+// and APEX users, but we need access to it to fuzz.
+#include "../../ndk/ibinder_internal.h"
+
+namespace android {
+
+void fuzzService(AIBinder* binder, FuzzedDataProvider&& provider) {
+ fuzzService(binder->getBinder(), std::move(provider));
+}
+
+} // namespace android
diff --git a/libs/binder/tests/parcel_fuzzer/random_fd.cpp b/libs/binder/tests/parcel_fuzzer/random_fd.cpp
index cef6adb82d..ab0b7e306f 100644
--- a/libs/binder/tests/parcel_fuzzer/random_fd.cpp
+++ b/libs/binder/tests/parcel_fuzzer/random_fd.cpp
@@ -23,13 +23,13 @@
namespace android {
-int getRandomFd(FuzzedDataProvider* provider) {
+base::unique_fd getRandomFd(FuzzedDataProvider* provider) {
int fd = provider->PickValueInArray<std::function<int()>>({
[]() { return ashmem_create_region("binder test region", 1024); },
[]() { return open("/dev/null", O_RDWR); },
})();
CHECK(fd >= 0);
- return fd;
+ return base::unique_fd(fd);
}
} // namespace android
diff --git a/libs/binder/tests/parcel_fuzzer/random_parcel.cpp b/libs/binder/tests/parcel_fuzzer/random_parcel.cpp
index 8bf04ccae0..0204f5ed61 100644
--- a/libs/binder/tests/parcel_fuzzer/random_parcel.cpp
+++ b/libs/binder/tests/parcel_fuzzer/random_parcel.cpp
@@ -34,15 +34,30 @@ private:
String16 mDescriptor;
};
-void fillRandomParcel(Parcel* p, FuzzedDataProvider&& provider) {
+static 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()));
+}
+
+void fillRandomParcel(Parcel* p, FuzzedDataProvider&& provider,
+ const RandomParcelOptions& options) {
if (provider.ConsumeBool()) {
auto session = RpcSession::make(RpcTransportCtxFactoryRaw::make());
CHECK_EQ(OK, session->addNullDebuggingClient());
p->markForRpc(session);
+
+ if (options.writeHeader) {
+ options.writeHeader(p, provider);
+ }
+
fillRandomParcelData(p, std::move(provider));
return;
}
+ if (options.writeHeader) {
+ options.writeHeader(p, provider);
+ }
+
while (provider.remaining_bytes() > 0) {
auto fillFunc = provider.PickValueInArray<const std::function<void()>>({
// write data
@@ -54,8 +69,16 @@ void fillRandomParcel(Parcel* p, FuzzedDataProvider&& provider) {
},
// write FD
[&]() {
- int fd = getRandomFd(&provider);
- CHECK(OK == p->writeFileDescriptor(fd, true /*takeOwnership*/));
+ if (options.extraFds.size() > 0 && provider.ConsumeBool()) {
+ const base::unique_fd& fd = options.extraFds.at(
+ provider.ConsumeIntegralInRange<size_t>(0,
+ options.extraFds.size() -
+ 1));
+ CHECK(OK == p->writeFileDescriptor(fd.get(), false /*takeOwnership*/));
+ } else {
+ base::unique_fd fd = getRandomFd(&provider);
+ CHECK(OK == p->writeFileDescriptor(fd.release(), true /*takeOwnership*/));
+ }
},
// write binder
[&]() {
@@ -74,7 +97,15 @@ void fillRandomParcel(Parcel* p, FuzzedDataProvider&& provider) {
// candidate for checking usage of an actual BpBinder
return IInterface::asBinder(defaultServiceManager());
},
- []() { return nullptr; },
+ [&]() -> sp<IBinder> {
+ if (options.extraBinders.size() > 0 && provider.ConsumeBool()) {
+ return options.extraBinders.at(
+ provider.ConsumeIntegralInRange<
+ size_t>(0, options.extraBinders.size() - 1));
+ } else {
+ return nullptr;
+ }
+ },
});
sp<IBinder> binder = makeFunc();
CHECK(OK == p->writeStrongBinder(binder));
@@ -85,9 +116,4 @@ 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/tests/unit_fuzzers/BpBinderFuzzFunctions.h b/libs/binder/tests/unit_fuzzers/BpBinderFuzzFunctions.h
index 741987f754..5079431058 100644
--- a/libs/binder/tests/unit_fuzzers/BpBinderFuzzFunctions.h
+++ b/libs/binder/tests/unit_fuzzers/BpBinderFuzzFunctions.h
@@ -30,7 +30,6 @@
#include <utils/KeyedVector.h>
#include <utils/Log.h>
#include <utils/Mutex.h>
-#include <utils/threads.h>
#include <stdio.h>
diff --git a/libs/binder/tests/unit_fuzzers/IBinderFuzzFunctions.h b/libs/binder/tests/unit_fuzzers/IBinderFuzzFunctions.h
index 4a0aebac43..bf7c61347f 100644
--- a/libs/binder/tests/unit_fuzzers/IBinderFuzzFunctions.h
+++ b/libs/binder/tests/unit_fuzzers/IBinderFuzzFunctions.h
@@ -27,7 +27,6 @@
#include <utils/KeyedVector.h>
#include <utils/Log.h>
#include <utils/Mutex.h>
-#include <utils/threads.h>
namespace android {
diff --git a/libs/cputimeinstate/cputimeinstate.cpp b/libs/cputimeinstate/cputimeinstate.cpp
index 7e9bb7d468..d1690437ef 100644
--- a/libs/cputimeinstate/cputimeinstate.cpp
+++ b/libs/cputimeinstate/cputimeinstate.cpp
@@ -300,11 +300,11 @@ std::optional<std::vector<std::vector<uint64_t>>> getUidCpuFreqTimes(uint32_t ui
}
std::vector<tis_val_t> vals(gNCpus);
- time_key_t key = {.uid = uid};
for (uint32_t i = 0; i <= (maxFreqCount - 1) / FREQS_PER_ENTRY; ++i) {
- key.bucket = i;
+ const time_key_t key = {.uid = uid, .bucket = i};
if (findMapEntry(gTisMapFd, &key, vals.data())) {
- if (errno != ENOENT || getFirstMapKey(gTisMapFd, &key)) return {};
+ time_key_t tmpKey;
+ if (errno != ENOENT || getFirstMapKey(gTisMapFd, &tmpKey)) return {};
continue;
}
@@ -412,10 +412,11 @@ std::optional<concurrent_time_t> getUidConcurrentTimes(uint32_t uid, bool retry)
concurrent_time_t ret = {.active = std::vector<uint64_t>(gNCpus, 0)};
for (const auto &cpuList : gPolicyCpus) ret.policy.emplace_back(cpuList.size(), 0);
std::vector<concurrent_val_t> vals(gNCpus);
- time_key_t key = {.uid = uid};
- for (key.bucket = 0; key.bucket <= (gNCpus - 1) / CPUS_PER_ENTRY; ++key.bucket) {
+ for (uint32_t i = 0; i <= (gNCpus - 1) / CPUS_PER_ENTRY; ++i) {
+ const time_key_t key = {.uid = uid, .bucket = i};
if (findMapEntry(gConcurrentMapFd, &key, vals.data())) {
- if (errno != ENOENT || getFirstMapKey(gConcurrentMapFd, &key)) return {};
+ time_key_t tmpKey;
+ if (errno != ENOENT || getFirstMapKey(gConcurrentMapFd, &tmpKey)) return {};
continue;
}
auto offset = key.bucket * CPUS_PER_ENTRY;
diff --git a/libs/cputimeinstate/testtimeinstate.cpp b/libs/cputimeinstate/testtimeinstate.cpp
index 1513ecafc8..45a6d47bb4 100644
--- a/libs/cputimeinstate/testtimeinstate.cpp
+++ b/libs/cputimeinstate/testtimeinstate.cpp
@@ -31,6 +31,7 @@
#include <android-base/unique_fd.h>
#include <bpf/BpfMap.h>
#include <cputimeinstate.h>
+#include <cutils/android_filesystem_config.h>
#include <libbpf.h>
namespace android {
@@ -219,6 +220,7 @@ TEST_F(TimeInStateTest, TotalAndAllUidTimeInStateConsistent) {
uint32_t totalFreqsCount = totalTimes.size();
std::vector<uint64_t> allUidTimes(totalFreqsCount, 0);
for (auto const &[uid, uidTimes]: *allUid) {
+ if (uid == AID_SDK_SANDBOX) continue;
for (uint32_t freqIdx = 0; freqIdx < uidTimes[policyIdx].size(); ++freqIdx) {
allUidTimes[std::min(freqIdx, totalFreqsCount - 1)] += uidTimes[policyIdx][freqIdx];
}
@@ -646,5 +648,55 @@ TEST_F(TimeInStateTest, GetAggregatedTaskCpuFreqTimes) {
}
}
+void *forceSwitchWithUid(void *uidPtr) {
+ if (!uidPtr) return nullptr;
+ setuid(*(uint32_t *)uidPtr);
+
+ // Sleep briefly to trigger a context switch, ensuring we see at least one update.
+ struct timespec ts;
+ ts.tv_sec = 0;
+ ts.tv_nsec = 1000000;
+ nanosleep(&ts, NULL);
+ return nullptr;
+}
+
+TEST_F(TimeInStateTest, SdkSandboxUid) {
+ // Find an unused app UID and its corresponding SDK sandbox uid.
+ uint32_t appUid = AID_APP_START, sandboxUid;
+ {
+ auto times = getUidsCpuFreqTimes();
+ ASSERT_TRUE(times.has_value());
+ ASSERT_FALSE(times->empty());
+ for (const auto &kv : *times) {
+ if (kv.first > AID_APP_END) break;
+ appUid = std::max(appUid, kv.first);
+ }
+ appUid++;
+ sandboxUid = appUid + (AID_SDK_SANDBOX_PROCESS_START - AID_APP_START);
+ }
+
+ // Create a thread to run with the fake sandbox uid.
+ pthread_t thread;
+ ASSERT_EQ(pthread_create(&thread, NULL, &forceSwitchWithUid, &sandboxUid), 0);
+ pthread_join(thread, NULL);
+
+ // Confirm we recorded stats for appUid and AID_SDK_SANDBOX but not sandboxUid
+ auto allTimes = getUidsCpuFreqTimes();
+ ASSERT_TRUE(allTimes.has_value());
+ ASSERT_FALSE(allTimes->empty());
+ ASSERT_NE(allTimes->find(appUid), allTimes->end());
+ ASSERT_NE(allTimes->find(AID_SDK_SANDBOX), allTimes->end());
+ ASSERT_EQ(allTimes->find(sandboxUid), allTimes->end());
+
+ auto allConcurrentTimes = getUidsConcurrentTimes();
+ ASSERT_TRUE(allConcurrentTimes.has_value());
+ ASSERT_FALSE(allConcurrentTimes->empty());
+ ASSERT_NE(allConcurrentTimes->find(appUid), allConcurrentTimes->end());
+ ASSERT_NE(allConcurrentTimes->find(AID_SDK_SANDBOX), allConcurrentTimes->end());
+ ASSERT_EQ(allConcurrentTimes->find(sandboxUid), allConcurrentTimes->end());
+
+ ASSERT_TRUE(clearUidTimes(appUid));
+}
+
} // namespace bpf
} // namespace android
diff --git a/libs/ftl/Android.bp b/libs/ftl/Android.bp
index 97626bec7d..2524c5f6d2 100644
--- a/libs/ftl/Android.bp
+++ b/libs/ftl/Android.bp
@@ -14,7 +14,9 @@ cc_test {
address: true,
},
srcs: [
+ "Flags_test.cpp",
"future_test.cpp",
+ "NamedEnum_test.cpp",
"small_map_test.cpp",
"small_vector_test.cpp",
"static_vector_test.cpp",
@@ -25,4 +27,12 @@ cc_test {
"-Wextra",
"-Wpedantic",
],
+
+ header_libs: [
+ "libbase_headers",
+ ],
+
+ shared_libs: [
+ "libbase",
+ ],
}
diff --git a/libs/input/tests/Flags_test.cpp b/libs/ftl/Flags_test.cpp
index 6de030f7cf..8c00b5299b 100644
--- a/libs/input/tests/Flags_test.cpp
+++ b/libs/ftl/Flags_test.cpp
@@ -15,7 +15,7 @@
*/
#include <gtest/gtest.h>
-#include <input/Flags.h>
+#include <ftl/Flags.h>
#include <type_traits>
diff --git a/libs/input/tests/NamedEnum_test.cpp b/libs/ftl/NamedEnum_test.cpp
index 74a0044387..dff2b8aaa1 100644
--- a/libs/input/tests/NamedEnum_test.cpp
+++ b/libs/ftl/NamedEnum_test.cpp
@@ -15,7 +15,7 @@
*/
#include <gtest/gtest.h>
-#include <input/NamedEnum.h>
+#include <ftl/NamedEnum.h>
namespace android {
diff --git a/libs/graphicsenv/OWNERS b/libs/graphicsenv/OWNERS
index 8c284647f2..347c4e0db1 100644
--- a/libs/graphicsenv/OWNERS
+++ b/libs/graphicsenv/OWNERS
@@ -1,4 +1,10 @@
+abdolrashidi@google.com
+cclao@google.com
chrisforbes@google.com
cnorthrop@google.com
+ianelliott@google.com
+lfy@google.com
lpy@google.com
-timvp@google.com
+romanl@google.com
+vantablack@google.com
+yuxinhu@google.com
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index fa853cb106..bd9abc1996 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -51,6 +51,60 @@ cc_library_headers {
],
}
+// AIDL files that should be exposed to java
+filegroup {
+ name: "guiconstants_aidl",
+ srcs: [
+ "android/**/DropInputMode.aidl",
+ "android/**/TouchOcclusionMode.aidl",
+ ],
+}
+
+cc_library_static {
+ name: "libgui_window_info_static",
+ vendor_available: true,
+ host_supported: true,
+ srcs: [
+ ":guiconstants_aidl",
+ "android/gui/FocusRequest.aidl",
+ "android/gui/InputApplicationInfo.aidl",
+ "android/gui/IWindowInfosListener.aidl",
+ "android/gui/IWindowInfosReportedListener.aidl",
+ "android/gui/WindowInfo.aidl",
+ "WindowInfo.cpp",
+ ],
+
+ shared_libs: [
+ "libbinder",
+ ],
+
+ local_include_dirs: [
+ "include",
+ ],
+
+ export_shared_lib_headers: [
+ "libbinder",
+ ],
+
+ static_libs: [
+ "libui-types",
+ ],
+
+ aidl: {
+ export_aidl_headers: true
+ },
+
+ include_dirs: [
+ "frameworks/native/include",
+ ],
+
+ target: {
+ darwin: {
+ enabled: false,
+ },
+ },
+}
+
filegroup {
name: "libgui_aidl",
srcs: ["aidl/**/*.aidl"],
@@ -77,6 +131,10 @@ cc_library_static {
"libbinder",
],
+ static_libs: [
+ "libui-types",
+ ],
+
aidl: {
export_aidl_headers: true,
},
@@ -95,9 +153,11 @@ cc_library_shared {
static_libs: [
"libgui_aidl_static",
+ "libgui_window_info_static",
],
export_static_lib_headers: [
"libgui_aidl_static",
+ "libgui_window_info_static",
],
srcs: [
@@ -138,6 +198,7 @@ cc_library_shared {
"SyncFeatures.cpp",
"TransactionTracing.cpp",
"view/Surface.cpp",
+ "WindowInfosListenerReporter.cpp",
"bufferqueue/1.0/B2HProducerListener.cpp",
"bufferqueue/1.0/H2BGraphicBufferProducer.cpp",
"bufferqueue/2.0/B2HProducerListener.cpp",
@@ -148,13 +209,11 @@ cc_library_shared {
"libbinder",
"libbufferhub",
"libbufferhubqueue", // TODO(b/70046255): Remove this once BufferHub is integrated into libgui.
- "libinput",
"libpdx_default_transport",
],
export_shared_lib_headers: [
"libbinder",
- "libinput",
],
export_header_lib_headers: [
@@ -166,7 +225,6 @@ cc_library_shared {
vendor: {
cflags: [
"-DNO_BUFFERHUB",
- "-DNO_INPUT",
],
exclude_srcs: [
"BufferHubConsumer.cpp",
@@ -175,7 +233,6 @@ cc_library_shared {
exclude_shared_libs: [
"libbufferhub",
"libbufferhubqueue",
- "libinput",
"libpdx_default_transport",
],
},
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index 9baf79b443..f034642681 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -38,7 +38,7 @@
using namespace std::chrono_literals;
namespace {
-inline const char* toString(bool b) {
+inline const char* boolToString(bool b) {
return b ? "true" : "false";
}
} // namespace
@@ -46,6 +46,8 @@ inline const char* toString(bool b) {
namespace android {
// Macros to include adapter info in log messages
+#define BQA_LOGD(x, ...) \
+ ALOGD("[%s](f:%u,a:%u) " x, mName.c_str(), mNumFrameAvailable, mNumAcquired, ##__VA_ARGS__)
#define BQA_LOGV(x, ...) \
ALOGV("[%s](f:%u,a:%u) " x, mName.c_str(), mNumFrameAvailable, mNumAcquired, ##__VA_ARGS__)
// enable logs for a single layer
@@ -125,12 +127,11 @@ void BLASTBufferItemConsumer::onSidebandStreamChanged() {
}
}
-BLASTBufferQueue::BLASTBufferQueue(const std::string& name, const sp<SurfaceControl>& surface,
- int width, int height, int32_t format)
- : mSurfaceControl(surface),
- mSize(width, height),
+BLASTBufferQueue::BLASTBufferQueue(const std::string& name)
+ : mSurfaceControl(nullptr),
+ mSize(1, 1),
mRequestedSize(mSize),
- mFormat(format),
+ mFormat(PIXEL_FORMAT_RGBA_8888),
mNextTransaction(nullptr) {
createBufferQueue(&mProducer, &mConsumer);
// since the adapter is in the client process, set dequeue timeout
@@ -151,23 +152,18 @@ BLASTBufferQueue::BLASTBufferQueue(const std::string& name, const sp<SurfaceCont
mBufferItemConsumer->setName(String8(consumerName.c_str()));
mBufferItemConsumer->setFrameAvailableListener(this);
mBufferItemConsumer->setBufferFreedListener(this);
- mBufferItemConsumer->setDefaultBufferSize(mSize.width, mSize.height);
- mBufferItemConsumer->setDefaultBufferFormat(convertBufferFormat(format));
ComposerService::getComposerService()->getMaxAcquiredBufferCount(&mMaxAcquiredBuffers);
mBufferItemConsumer->setMaxAcquiredBufferCount(mMaxAcquiredBuffers);
-
- mTransformHint = mSurfaceControl->getTransformHint();
- mBufferItemConsumer->setTransformHint(mTransformHint);
- SurfaceComposerClient::Transaction()
- .setFlags(surface, layer_state_t::eEnableBackpressure,
- layer_state_t::eEnableBackpressure)
- .setApplyToken(mApplyToken)
- .apply();
mNumAcquired = 0;
mNumFrameAvailable = 0;
- BQA_LOGV("BLASTBufferQueue created width=%d height=%d format=%d mTransformHint=%d", width,
- height, format, mTransformHint);
+ BQA_LOGV("BLASTBufferQueue created");
+}
+
+BLASTBufferQueue::BLASTBufferQueue(const std::string& name, const sp<SurfaceControl>& surface,
+ int width, int height, int32_t format)
+ : BLASTBufferQueue(name) {
+ update(surface, width, height, format);
}
BLASTBufferQueue::~BLASTBufferQueue() {
@@ -218,12 +214,9 @@ void BLASTBufferQueue::update(const sp<SurfaceControl>& surface, uint32_t width,
// 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;
- // 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.
SurfaceComposerClient::Transaction* destFrameTransaction =
(outTransaction) ? outTransaction : &t;
- if (mSurfaceControl != nullptr && mLastBufferInfo.hasBuffer) {
+ if (mSurfaceControl != nullptr) {
destFrameTransaction->setDestinationFrame(mSurfaceControl,
Rect(0, 0, newSize.getWidth(),
newSize.getHeight()));
@@ -236,6 +229,67 @@ void BLASTBufferQueue::update(const sp<SurfaceControl>& surface, uint32_t width,
}
}
+static std::optional<SurfaceControlStats> findMatchingStat(
+ const std::vector<SurfaceControlStats>& stats, const sp<SurfaceControl>& sc) {
+ for (auto stat : stats) {
+ if (SurfaceControl::isSameSurface(sc, stat.surfaceControl)) {
+ return stat;
+ }
+ }
+ return std::nullopt;
+}
+
+static void transactionCommittedCallbackThunk(void* context, nsecs_t latchTime,
+ const sp<Fence>& presentFence,
+ const std::vector<SurfaceControlStats>& stats) {
+ if (context == nullptr) {
+ return;
+ }
+ sp<BLASTBufferQueue> bq = static_cast<BLASTBufferQueue*>(context);
+ bq->transactionCommittedCallback(latchTime, presentFence, stats);
+}
+
+void BLASTBufferQueue::transactionCommittedCallback(nsecs_t /*latchTime*/,
+ const sp<Fence>& /*presentFence*/,
+ const std::vector<SurfaceControlStats>& stats) {
+ {
+ std::unique_lock _lock{mMutex};
+ ATRACE_CALL();
+ BQA_LOGV("transactionCommittedCallback");
+ if (!mSurfaceControlsWithPendingCallback.empty()) {
+ sp<SurfaceControl> pendingSC = mSurfaceControlsWithPendingCallback.front();
+ std::optional<SurfaceControlStats> stat = findMatchingStat(stats, pendingSC);
+ if (stat) {
+ uint64_t currFrameNumber = stat->frameEventStats.frameNumber;
+
+ // We need to check if we were waiting for a transaction callback in order to
+ // process any pending buffers and unblock. It's possible to get transaction
+ // callbacks for previous requests so we need to ensure the frame from this
+ // transaction callback matches the last acquired buffer. Since acquireNextBuffer
+ // will stop processing buffers when mWaitForTransactionCallback is set, we know
+ // that mLastAcquiredFrameNumber is the frame we're waiting on.
+ // We also want to check if mNextTransaction is null because it's possible another
+ // sync request came in while waiting, but it hasn't started processing yet. In that
+ // case, we don't actually want to flush the frames in between since they will get
+ // processed and merged with the sync transaction and released earlier than if they
+ // were sent to SF
+ if (mWaitForTransactionCallback && mNextTransaction == nullptr &&
+ currFrameNumber >= mLastAcquiredFrameNumber) {
+ mWaitForTransactionCallback = false;
+ flushShadowQueueLocked();
+ }
+ } else {
+ BQA_LOGE("Failed to find matching SurfaceControl in transactionCommittedCallback");
+ }
+ } else {
+ BQA_LOGE("No matching SurfaceControls found: mSurfaceControlsWithPendingCallback was "
+ "empty.");
+ }
+
+ decStrong((void*)transactionCommittedCallbackThunk);
+ }
+}
+
static void transactionCallbackThunk(void* context, nsecs_t latchTime,
const sp<Fence>& presentFence,
const std::vector<SurfaceControlStats>& stats) {
@@ -259,12 +313,9 @@ void BLASTBufferQueue::transactionCallback(nsecs_t /*latchTime*/, const sp<Fence
if (!mSurfaceControlsWithPendingCallback.empty()) {
sp<SurfaceControl> pendingSC = mSurfaceControlsWithPendingCallback.front();
mSurfaceControlsWithPendingCallback.pop();
- bool found = false;
- for (auto stat : stats) {
- if (!SurfaceControl::isSameSurface(pendingSC, stat.surfaceControl)) {
- continue;
- }
-
+ std::optional<SurfaceControlStats> statsOptional = findMatchingStat(stats, pendingSC);
+ if (statsOptional) {
+ SurfaceControlStats stat = *statsOptional;
mTransformHint = stat.transformHint;
mBufferItemConsumer->setTransformHint(mTransformHint);
BQA_LOGV("updated mTransformHint=%d", mTransformHint);
@@ -292,19 +343,25 @@ void BLASTBufferQueue::transactionCallback(nsecs_t /*latchTime*/, const sp<Fence
transactionCompleteCallback = std::move(mTransactionCompleteCallback);
mTransactionCompleteFrameNumber = 0;
}
-
- found = true;
- break;
- }
-
- if (!found) {
- BQA_LOGE("Failed to find matching SurfaceControl in transaction callback");
+ std::vector<ReleaseCallbackId> staleReleases;
+ for (const auto& [key, value]: mSubmitted) {
+ if (currFrameNumber > key.framenumber) {
+ staleReleases.push_back(key);
+ }
+ }
+ for (const auto& staleRelease : staleReleases) {
+ releaseBufferCallbackLocked(staleRelease, stat.previousReleaseFence ? stat.previousReleaseFence : Fence::NO_FENCE,
+ stat.transformHint, stat.currentMaxAcquiredBufferCount);
+ }
+ } else {
+ BQA_LOGE("Failed to find matching SurfaceControl in transactionCallback");
}
} else {
BQA_LOGE("No matching SurfaceControls found: mSurfaceControlsWithPendingCallback was "
"empty.");
}
+
decStrong((void*)transactionCallbackThunk);
}
@@ -329,11 +386,31 @@ static void releaseBufferCallbackThunk(wp<BLASTBufferQueue> context, const Relea
}
}
+void BLASTBufferQueue::flushShadowQueueLocked() {
+ BQA_LOGV("flushShadowQueueLocked");
+ int numFramesToFlush = mNumFrameAvailable;
+ while (numFramesToFlush > 0) {
+ acquireNextBufferLocked(std::nullopt);
+ numFramesToFlush--;
+ }
+}
+
+void BLASTBufferQueue::flushShadowQueue() {
+ std::unique_lock _lock{mMutex};
+ flushShadowQueueLocked();
+}
+
void BLASTBufferQueue::releaseBufferCallback(const ReleaseCallbackId& id,
const sp<Fence>& releaseFence, uint32_t transformHint,
uint32_t currentMaxAcquiredBufferCount) {
- ATRACE_CALL();
std::unique_lock _lock{mMutex};
+ releaseBufferCallbackLocked(id, releaseFence, transformHint, currentMaxAcquiredBufferCount);
+}
+
+void BLASTBufferQueue::releaseBufferCallbackLocked(const ReleaseCallbackId& id,
+ const sp<Fence>& releaseFence, uint32_t transformHint,
+ uint32_t currentMaxAcquiredBufferCount) {
+ ATRACE_CALL();
BQA_LOGV("releaseBufferCallback %s", id.to_string().c_str());
if (mSurfaceControl != nullptr) {
@@ -354,7 +431,10 @@ void BLASTBufferQueue::releaseBufferCallback(const ReleaseCallbackId& id,
const auto numPendingBuffersToHold =
isEGL ? std::max(0u, mMaxAcquiredBuffers - currentMaxAcquiredBufferCount) : 0;
- mPendingRelease.emplace_back(ReleasedBuffer{id, releaseFence});
+ auto rb = ReleasedBuffer{id, releaseFence};
+ if (std::find(mPendingRelease.begin(), mPendingRelease.end(), rb) == mPendingRelease.end()) {
+ mPendingRelease.emplace_back(rb);
+ }
// Release all buffers that are beyond the ones that we need to hold
while (mPendingRelease.size() > numPendingBuffersToHold) {
@@ -370,7 +450,11 @@ void BLASTBufferQueue::releaseBufferCallback(const ReleaseCallbackId& id,
BQA_LOGV("released %s", id.to_string().c_str());
mBufferItemConsumer->releaseBuffer(it->second, releaseBuffer.releaseFence);
mSubmitted.erase(it);
- processNextBufferLocked(false /* useNextTransaction */);
+ // Don't process the transactions here if mWaitForTransactionCallback is set. Instead, let
+ // onFrameAvailable handle processing them since it will merge with the nextTransaction.
+ if (!mWaitForTransactionCallback) {
+ acquireNextBufferLocked(std::nullopt);
+ }
}
ATRACE_INT("PendingRelease", mPendingRelease.size());
@@ -379,13 +463,15 @@ void BLASTBufferQueue::releaseBufferCallback(const ReleaseCallbackId& id,
mCallbackCV.notify_all();
}
-void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) {
+void BLASTBufferQueue::acquireNextBufferLocked(
+ const std::optional<SurfaceComposerClient::Transaction*> transaction) {
ATRACE_CALL();
// If the next transaction is set, we want to guarantee the our acquire will not fail, so don't
// include the extra buffer when checking if we can acquire the next buffer.
- const bool includeExtraAcquire = !useNextTransaction;
- if (mNumFrameAvailable == 0 || maxBuffersAcquired(includeExtraAcquire)) {
- mCallbackCV.notify_all();
+ const bool includeExtraAcquire = !transaction;
+ const bool maxAcquired = maxBuffersAcquired(includeExtraAcquire);
+ if (mNumFrameAvailable == 0 || maxAcquired) {
+ BQA_LOGV("Can't process next buffer maxBuffersAcquired=%s", boolToString(maxAcquired));
return;
}
@@ -397,9 +483,8 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) {
SurfaceComposerClient::Transaction localTransaction;
bool applyTransaction = true;
SurfaceComposerClient::Transaction* t = &localTransaction;
- if (mNextTransaction != nullptr && useNextTransaction) {
- t = mNextTransaction;
- mNextTransaction = nullptr;
+ if (transaction) {
+ t = *transaction;
applyTransaction = false;
}
@@ -429,7 +514,7 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) {
mSize.width, mSize.height, mRequestedSize.width, mRequestedSize.height,
buffer->getWidth(), buffer->getHeight(), bufferItem.mTransform);
mBufferItemConsumer->releaseBuffer(bufferItem, Fence::NO_FENCE);
- processNextBufferLocked(useNextTransaction);
+ acquireNextBufferLocked(transaction);
return;
}
@@ -449,10 +534,9 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) {
// Ensure BLASTBufferQueue stays alive until we receive the transaction complete callback.
incStrong((void*)transactionCallbackThunk);
+ const bool updateDestinationFrame = mRequestedSize != mSize;
+ mSize = mRequestedSize;
Rect crop = computeCrop(bufferItem);
- const bool updateDestinationFrame =
- bufferItem.mScalingMode == NATIVE_WINDOW_SCALING_MODE_FREEZE ||
- !mLastBufferInfo.hasBuffer;
mLastBufferInfo.update(true /* hasBuffer */, bufferItem.mGraphicBuffer->getWidth(),
bufferItem.mGraphicBuffer->getHeight(), bufferItem.mTransform,
bufferItem.mScalingMode, crop);
@@ -468,6 +552,7 @@ 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);
if (updateDestinationFrame) {
@@ -520,10 +605,10 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) {
t->setApplyToken(mApplyToken).apply();
}
- BQA_LOGV("processNextBufferLocked size=%dx%d mFrameNumber=%" PRIu64
+ BQA_LOGV("acquireNextBufferLocked size=%dx%d mFrameNumber=%" PRIu64
" applyTransaction=%s mTimestamp=%" PRId64 "%s mPendingTransactions.size=%d"
" graphicBufferId=%" PRIu64 "%s transform=%d",
- mSize.width, mSize.height, bufferItem.mFrameNumber, toString(applyTransaction),
+ mSize.width, mSize.height, bufferItem.mFrameNumber, boolToString(applyTransaction),
bufferItem.mTimestamp, bufferItem.mIsAutoTimestamp ? "(auto)" : "",
static_cast<uint32_t>(mPendingTransactions.size()), bufferItem.mGraphicBuffer->getId(),
bufferItem.mAutoRefresh ? " mAutoRefresh" : "", bufferItem.mTransform);
@@ -536,25 +621,75 @@ Rect BLASTBufferQueue::computeCrop(const BufferItem& item) {
return item.mCrop;
}
+void BLASTBufferQueue::acquireAndReleaseBuffer() {
+ BufferItem bufferItem;
+ status_t status =
+ mBufferItemConsumer->acquireBuffer(&bufferItem, 0 /* expectedPresent */, false);
+ if (status != OK) {
+ BQA_LOGE("Failed to acquire a buffer in acquireAndReleaseBuffer, err=%s",
+ statusToString(status).c_str());
+ return;
+ }
+ mNumFrameAvailable--;
+ mBufferItemConsumer->releaseBuffer(bufferItem, bufferItem.mFence);
+}
+
void BLASTBufferQueue::onFrameAvailable(const BufferItem& item) {
ATRACE_CALL();
std::unique_lock _lock{mMutex};
const bool nextTransactionSet = mNextTransaction != nullptr;
+ BQA_LOGV("onFrameAvailable-start nextTransactionSet=%s", boolToString(nextTransactionSet));
if (nextTransactionSet) {
- while (mNumFrameAvailable > 0 || maxBuffersAcquired(false /* includeExtraAcquire */)) {
- BQA_LOGV("waiting in onFrameAvailable...");
+ if (mWaitForTransactionCallback) {
+ // We are waiting on a previous sync's transaction callback so allow another sync
+ // transaction to proceed.
+ //
+ // We need to first flush out the transactions that were in between the two syncs.
+ // We do this by merging them into mNextTransaction so any buffer merging will get
+ // a release callback invoked. The release callback will be async so we need to wait
+ // on max acquired to make sure we have the capacity to acquire another buffer.
+ if (maxBuffersAcquired(false /* includeExtraAcquire */)) {
+ BQA_LOGD("waiting to flush shadow queue...");
+ mCallbackCV.wait(_lock);
+ }
+ while (mNumFrameAvailable > 0) {
+ // flush out the shadow queue
+ acquireAndReleaseBuffer();
+ }
+ }
+
+ while (maxBuffersAcquired(false /* includeExtraAcquire */)) {
+ BQA_LOGD("waiting for free buffer.");
mCallbackCV.wait(_lock);
}
}
+
// add to shadow queue
mNumFrameAvailable++;
+ if (mWaitForTransactionCallback && mNumFrameAvailable == 2) {
+ acquireAndReleaseBuffer();
+ }
ATRACE_INT(mQueuedBufferTrace.c_str(),
mNumFrameAvailable + mNumAcquired - mPendingRelease.size());
BQA_LOGV("onFrameAvailable framenumber=%" PRIu64 " nextTransactionSet=%s", item.mFrameNumber,
- toString(nextTransactionSet));
- processNextBufferLocked(nextTransactionSet /* useNextTransaction */);
+ boolToString(nextTransactionSet));
+
+ if (nextTransactionSet) {
+ acquireNextBufferLocked(std::move(mNextTransaction));
+
+ // Only need a commit callback when syncing to ensure the buffer that's synced has been sent
+ // to SF
+ incStrong((void*)transactionCommittedCallbackThunk);
+ mNextTransaction->addTransactionCommittedCallback(transactionCommittedCallbackThunk,
+ static_cast<void*>(this));
+
+ mNextTransaction = nullptr;
+ mWaitForTransactionCallback = true;
+ } else if (!mWaitForTransactionCallback) {
+ acquireNextBufferLocked(std::nullopt);
+ }
}
void BLASTBufferQueue::onFrameReplaced(const BufferItem& item) {
@@ -579,7 +714,6 @@ 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;
}
@@ -593,7 +727,6 @@ bool BLASTBufferQueue::rejectBuffer(const BufferItem& item) {
}
ui::Size bufferSize(bufWidth, bufHeight);
if (mRequestedSize != mSize && mRequestedSize == bufferSize) {
- mSize = mRequestedSize;
return false;
}
@@ -861,4 +994,9 @@ uint32_t BLASTBufferQueue::getLastTransformHint() const {
}
}
+uint64_t BLASTBufferQueue::getLastAcquiredFrameNum() {
+ std::unique_lock _lock{mMutex};
+ return mLastAcquiredFrameNumber;
+}
+
} // namespace android
diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp
index 5023b6bb81..2930154ad4 100644
--- a/libs/gui/BufferQueueCore.cpp
+++ b/libs/gui/BufferQueueCore.cpp
@@ -34,7 +34,6 @@
#include <gui/BufferQueueCore.h>
#include <gui/IConsumerListener.h>
#include <gui/IProducerListener.h>
-#include <gui/ISurfaceComposer.h>
#include <private/gui/ComposerService.h>
#include <system/window.h>
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index a82fc6fa81..1726761785 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -44,6 +44,7 @@
namespace android {
+using gui::IWindowInfosListener;
using ui::ColorMode;
class BpSurfaceComposer : public BpInterface<ISurfaceComposer>
@@ -1238,6 +1239,22 @@ public:
return reply.readInt32(buffers);
}
+
+ status_t addWindowInfosListener(
+ const sp<IWindowInfosListener>& windowInfosListener) const override {
+ Parcel data, reply;
+ SAFE_PARCEL(data.writeInterfaceToken, ISurfaceComposer::getInterfaceDescriptor());
+ SAFE_PARCEL(data.writeStrongBinder, IInterface::asBinder(windowInfosListener));
+ return remote()->transact(BnSurfaceComposer::ADD_WINDOW_INFOS_LISTENER, data, &reply);
+ }
+
+ status_t removeWindowInfosListener(
+ const sp<IWindowInfosListener>& windowInfosListener) const override {
+ Parcel data, reply;
+ SAFE_PARCEL(data.writeInterfaceToken, ISurfaceComposer::getInterfaceDescriptor());
+ SAFE_PARCEL(data.writeStrongBinder, IInterface::asBinder(windowInfosListener));
+ return remote()->transact(BnSurfaceComposer::REMOVE_WINDOW_INFOS_LISTENER, data, &reply);
+ }
};
// Out-of-line virtual method definition to trigger vtable emission in this
@@ -2128,6 +2145,20 @@ status_t BnSurfaceComposer::onTransact(
SAFE_PARCEL(reply->writeBool, success);
return err;
}
+ case ADD_WINDOW_INFOS_LISTENER: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ sp<IWindowInfosListener> listener;
+ SAFE_PARCEL(data.readStrongBinder, &listener);
+
+ return addWindowInfosListener(listener);
+ }
+ case REMOVE_WINDOW_INFOS_LISTENER: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ sp<IWindowInfosListener> listener;
+ SAFE_PARCEL(data.readStrongBinder, &listener);
+
+ return removeWindowInfosListener(listener);
+ }
default: {
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 076c90dd23..77a883b332 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -31,6 +31,9 @@
namespace android {
+using gui::FocusRequest;
+using gui::WindowInfoHandle;
+
layer_state_t::layer_state_t()
: what(0),
x(0),
@@ -67,7 +70,8 @@ layer_state_t::layer_state_t()
isTrustedOverlay(false),
bufferCrop(Rect::INVALID_RECT),
destinationFrame(Rect::INVALID_RECT),
- releaseBufferListener(nullptr) {
+ releaseBufferListener(nullptr),
+ dropInputMode(gui::DropInputMode::NONE) {
matrix.dsdx = matrix.dtdy = 1.0f;
matrix.dsdy = matrix.dtdx = 0.0f;
hdrMetadata.validTypes = 0;
@@ -95,9 +99,7 @@ status_t layer_state_t::write(Parcel& output) const
SAFE_PARCEL(output.writeFloat, color.r);
SAFE_PARCEL(output.writeFloat, color.g);
SAFE_PARCEL(output.writeFloat, color.b);
-#ifndef NO_INPUT
- SAFE_PARCEL(inputHandle->writeToParcel, &output);
-#endif
+ SAFE_PARCEL(windowInfoHandle->writeToParcel, &output);
SAFE_PARCEL(output.write, transparentRegion);
SAFE_PARCEL(output.writeUint32, transform);
SAFE_PARCEL(output.writeBool, transformToDisplayInverse);
@@ -173,6 +175,8 @@ status_t layer_state_t::write(Parcel& output) const
SAFE_PARCEL(output.write, destinationFrame);
SAFE_PARCEL(output.writeBool, isTrustedOverlay);
+ SAFE_PARCEL(output.writeStrongBinder, releaseBufferEndpoint);
+ SAFE_PARCEL(output.writeUint32, static_cast<uint32_t>(dropInputMode));
return NO_ERROR;
}
@@ -207,9 +211,7 @@ status_t layer_state_t::read(const Parcel& input)
color.g = tmpFloat;
SAFE_PARCEL(input.readFloat, &tmpFloat);
color.b = tmpFloat;
-#ifndef NO_INPUT
- SAFE_PARCEL(inputHandle->readFromParcel, &input);
-#endif
+ SAFE_PARCEL(windowInfoHandle->readFromParcel, &input);
SAFE_PARCEL(input.read, transparentRegion);
SAFE_PARCEL(input.readUint32, &transform);
@@ -304,6 +306,11 @@ status_t layer_state_t::read(const Parcel& input)
SAFE_PARCEL(input.read, destinationFrame);
SAFE_PARCEL(input.readBool, &isTrustedOverlay);
+ SAFE_PARCEL(input.readNullableStrongBinder, &releaseBufferEndpoint);
+
+ uint32_t mode;
+ SAFE_PARCEL(input.readUint32, &mode);
+ dropInputMode = static_cast<gui::DropInputMode>(mode);
return NO_ERROR;
}
@@ -318,6 +325,7 @@ status_t ComposerState::read(const Parcel& input) {
DisplayState::DisplayState()
: what(0),
layerStack(0),
+ flags(0),
layerStackSpaceRect(Rect::EMPTY_RECT),
orientedDisplaySpaceRect(Rect::EMPTY_RECT),
width(0),
@@ -328,6 +336,7 @@ status_t DisplayState::write(Parcel& output) const {
SAFE_PARCEL(output.writeStrongBinder, IInterface::asBinder(surface));
SAFE_PARCEL(output.writeUint32, what);
SAFE_PARCEL(output.writeUint32, layerStack);
+ SAFE_PARCEL(output.writeUint32, flags);
SAFE_PARCEL(output.writeUint32, toRotationInt(orientation));
SAFE_PARCEL(output.write, layerStackSpaceRect);
SAFE_PARCEL(output.write, orientedDisplaySpaceRect);
@@ -344,6 +353,7 @@ status_t DisplayState::read(const Parcel& input) {
SAFE_PARCEL(input.readUint32, &what);
SAFE_PARCEL(input.readUint32, &layerStack);
+ SAFE_PARCEL(input.readUint32, &flags);
uint32_t tmpUint = 0;
SAFE_PARCEL(input.readUint32, &tmpUint);
orientation = ui::toRotation(tmpUint);
@@ -364,6 +374,10 @@ void DisplayState::merge(const DisplayState& other) {
what |= eLayerStackChanged;
layerStack = other.layerStack;
}
+ if (other.what & eFlagsChanged) {
+ what |= eFlagsChanged;
+ flags = other.flags;
+ }
if (other.what & eDisplayProjectionChanged) {
what |= eDisplayProjectionChanged;
orientation = other.orientation;
@@ -455,6 +469,7 @@ void layer_state_t::merge(const layer_state_t& other) {
if (other.what & eBufferChanged) {
what |= eBufferChanged;
buffer = other.buffer;
+ releaseBufferEndpoint = other.releaseBufferEndpoint;
}
if (other.what & eAcquireFenceChanged) {
what |= eAcquireFenceChanged;
@@ -487,17 +502,14 @@ void layer_state_t::merge(const layer_state_t& other) {
if (other.what & eHasListenerCallbacksChanged) {
what |= eHasListenerCallbacksChanged;
}
-
-#ifndef NO_INPUT
if (other.what & eInputInfoChanged) {
what |= eInputInfoChanged;
- inputHandle = new InputWindowHandle(*other.inputHandle);
+ windowInfoHandle = new WindowInfoHandle(*other.windowInfoHandle);
}
-#endif
-
if (other.what & eCachedBufferChanged) {
what |= eCachedBufferChanged;
cachedBuffer = other.cachedBuffer;
+ releaseBufferEndpoint = other.releaseBufferEndpoint;
}
if (other.what & eBackgroundColorChanged) {
what |= eBackgroundColorChanged;
@@ -558,6 +570,14 @@ void layer_state_t::merge(const layer_state_t& other) {
what |= eDestinationFrameChanged;
destinationFrame = other.destinationFrame;
}
+ if (other.what & eDropInputModeChanged) {
+ what |= eDropInputModeChanged;
+ dropInputMode = other.dropInputMode;
+ }
+ if (other.what & eColorChanged) {
+ what |= eColorChanged;
+ color = other.color;
+ }
if ((other.what & what) != other.what) {
ALOGE("Unmerged SurfaceComposer Transaction properties. LayerState::merge needs updating? "
"other.what=0x%" PRIu64 " what=0x%" PRIu64,
@@ -593,11 +613,9 @@ status_t layer_state_t::matrix22_t::read(const Parcel& input) {
bool InputWindowCommands::merge(const InputWindowCommands& other) {
bool changes = false;
-#ifndef NO_INPUT
changes |= !other.focusRequests.empty();
focusRequests.insert(focusRequests.end(), std::make_move_iterator(other.focusRequests.begin()),
std::make_move_iterator(other.focusRequests.end()));
-#endif
changes |= other.syncInputWindows && !syncInputWindows;
syncInputWindows |= other.syncInputWindows;
return changes;
@@ -605,31 +623,23 @@ bool InputWindowCommands::merge(const InputWindowCommands& other) {
bool InputWindowCommands::empty() const {
bool empty = true;
-#ifndef NO_INPUT
empty = focusRequests.empty() && !syncInputWindows;
-#endif
return empty;
}
void InputWindowCommands::clear() {
-#ifndef NO_INPUT
focusRequests.clear();
-#endif
syncInputWindows = false;
}
status_t InputWindowCommands::write(Parcel& output) const {
-#ifndef NO_INPUT
SAFE_PARCEL(output.writeParcelableVector, focusRequests);
-#endif
SAFE_PARCEL(output.writeBool, syncInputWindows);
return NO_ERROR;
}
status_t InputWindowCommands::read(const Parcel& input) {
-#ifndef NO_INPUT
SAFE_PARCEL(input.readParcelableVector, &focusRequests);
-#endif
SAFE_PARCEL(input.readBool, &syncInputWindows);
return NO_ERROR;
}
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 1377284f92..725ea6571d 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -19,6 +19,7 @@
#include <stdint.h>
#include <sys/types.h>
+#include <android/gui/IWindowInfosListener.h>
#include <utils/Errors.h>
#include <utils/Log.h>
#include <utils/SortedVector.h>
@@ -39,14 +40,11 @@
#include <gui/LayerState.h>
#include <gui/Surface.h>
#include <gui/SurfaceComposerClient.h>
+#include <gui/WindowInfo.h>
#include <private/gui/ParcelUtils.h>
#include <ui/DisplayMode.h>
#include <ui/DynamicDisplayInfo.h>
-#ifndef NO_INPUT
-#include <input/InputWindow.h>
-#endif
-
#include <private/gui/ComposerService.h>
// This server size should always be smaller than the server cache size
@@ -54,6 +52,10 @@
namespace android {
+using gui::FocusRequest;
+using gui::WindowInfo;
+using gui::WindowInfoHandle;
+using gui::WindowInfosListener;
using ui::ColorMode;
// ---------------------------------------------------------------------------
@@ -95,6 +97,7 @@ bool ComposerService::connectLocked() {
if (instance.mComposerService == nullptr) {
if (ComposerService::getInstance().connectLocked()) {
ALOGD("ComposerService reconnected");
+ WindowInfosListenerReporter::getInstance()->reconnect(instance.mComposerService);
}
}
return instance.mComposerService;
@@ -144,8 +147,16 @@ int64_t TransactionCompletedListener::getNextIdLocked() {
return mCallbackIdCounter++;
}
+sp<TransactionCompletedListener> TransactionCompletedListener::sInstance = nullptr;
+
+void TransactionCompletedListener::setInstance(const sp<TransactionCompletedListener>& listener) {
+ sInstance = listener;
+}
+
sp<TransactionCompletedListener> TransactionCompletedListener::getInstance() {
- static sp<TransactionCompletedListener> sInstance = new TransactionCompletedListener;
+ if (sInstance == nullptr) {
+ sInstance = new TransactionCompletedListener;
+ }
return sInstance;
}
@@ -183,7 +194,7 @@ CallbackId TransactionCompletedListener::addCallbackFunction(
void TransactionCompletedListener::addJankListener(const sp<JankDataListener>& listener,
sp<SurfaceControl> surfaceControl) {
std::lock_guard<std::mutex> lock(mMutex);
- mJankListeners.insert({surfaceControl->getHandle(), listener});
+ mJankListeners.insert({surfaceControl->getLayerId(), listener});
}
void TransactionCompletedListener::removeJankListener(const sp<JankDataListener>& listener) {
@@ -212,8 +223,8 @@ void TransactionCompletedListener::removeReleaseBufferCallback(
void TransactionCompletedListener::addSurfaceStatsListener(void* context, void* cookie,
sp<SurfaceControl> surfaceControl, SurfaceStatsCallback listener) {
std::scoped_lock<std::recursive_mutex> lock(mSurfaceStatsListenerMutex);
- mSurfaceStatsListeners.insert({surfaceControl->getHandle(),
- SurfaceStatsCallbackEntry(context, cookie, listener)});
+ mSurfaceStatsListeners.insert(
+ {surfaceControl->getLayerId(), SurfaceStatsCallbackEntry(context, cookie, listener)});
}
void TransactionCompletedListener::removeSurfaceStatsListener(void* context, void* cookie) {
@@ -243,7 +254,7 @@ void TransactionCompletedListener::addSurfaceControlToCallbacks(
void TransactionCompletedListener::onTransactionCompleted(ListenerStats listenerStats) {
std::unordered_map<CallbackId, CallbackTranslation, CallbackIdHash> callbacksMap;
- std::multimap<sp<IBinder>, sp<JankDataListener>> jankListenersMap;
+ std::multimap<int32_t, sp<JankDataListener>> jankListenersMap;
{
std::lock_guard<std::mutex> lock(mMutex);
@@ -285,7 +296,7 @@ void TransactionCompletedListener::onTransactionCompleted(ListenerStats listener
transactionStats.latchTime, surfaceStats.acquireTime,
transactionStats.presentFence,
surfaceStats.previousReleaseFence, surfaceStats.transformHint,
- surfaceStats.eventStats);
+ surfaceStats.eventStats, surfaceStats.currentMaxAcquiredBufferCount);
}
callbackFunction(transactionStats.latchTime, transactionStats.presentFence,
@@ -310,7 +321,7 @@ void TransactionCompletedListener::onTransactionCompleted(ListenerStats listener
transactionStats.latchTime, surfaceStats.acquireTime,
transactionStats.presentFence,
surfaceStats.previousReleaseFence, surfaceStats.transformHint,
- surfaceStats.eventStats);
+ surfaceStats.eventStats, surfaceStats.currentMaxAcquiredBufferCount);
if (callbacksMap[callbackId].surfaceControls[surfaceStats.surfaceControl]) {
callbacksMap[callbackId]
.surfaceControls[surfaceStats.surfaceControl]
@@ -341,13 +352,26 @@ void TransactionCompletedListener::onTransactionCompleted(ListenerStats listener
callbackFunction(transactionStats.latchTime, transactionStats.presentFence,
surfaceControlStats);
}
+
for (const auto& surfaceStats : transactionStats.surfaceStats) {
+ // The callbackMap contains the SurfaceControl object, which we need to look up the
+ // layerId. Since we don't know which callback contains the SurfaceControl, iterate
+ // through all until the SC is found.
+ int32_t layerId = -1;
+ for (auto callbackId : transactionStats.callbackIds) {
+ sp<SurfaceControl> sc =
+ callbacksMap[callbackId].surfaceControls[surfaceStats.surfaceControl];
+ if (sc != nullptr) {
+ layerId = sc->getLayerId();
+ break;
+ }
+ }
+
{
// Acquire surface stats listener lock such that we guarantee that after calling
// unregister, there won't be any further callback.
std::scoped_lock<std::recursive_mutex> lock(mSurfaceStatsListenerMutex);
- auto listenerRange = mSurfaceStatsListeners.equal_range(
- surfaceStats.surfaceControl);
+ auto listenerRange = mSurfaceStatsListeners.equal_range(layerId);
for (auto it = listenerRange.first; it != listenerRange.second; it++) {
auto entry = it->second;
entry.callback(entry.context, transactionStats.latchTime,
@@ -356,7 +380,7 @@ void TransactionCompletedListener::onTransactionCompleted(ListenerStats listener
}
if (surfaceStats.jankData.empty()) continue;
- auto jankRange = jankListenersMap.equal_range(surfaceStats.surfaceControl);
+ auto jankRange = jankListenersMap.equal_range(layerId);
for (auto it = jankRange.first; it != jankRange.second; it++) {
it->second->onJankDataAvailable(surfaceStats.jankData);
}
@@ -1275,6 +1299,7 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setBuffe
removeReleaseBufferCallback(s);
s->what |= layer_state_t::eBufferChanged;
s->buffer = buffer;
+ s->releaseBufferEndpoint = IInterface::asBinder(TransactionCompletedListener::getIInstance());
if (mIsAutoTimestamp) {
mDesiredPresentTime = systemTime();
}
@@ -1495,16 +1520,14 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrame
return *this;
}
-#ifndef NO_INPUT
SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setInputWindowInfo(
- const sp<SurfaceControl>& sc,
- const InputWindowInfo& info) {
+ const sp<SurfaceControl>& sc, const WindowInfo& info) {
layer_state_t* s = getLayerState(sc);
if (!s) {
mStatus = BAD_INDEX;
return *this;
}
- s->inputHandle = new InputWindowHandle(info);
+ s->windowInfoHandle = new WindowInfoHandle(info);
s->what |= layer_state_t::eInputInfoChanged;
return *this;
}
@@ -1520,8 +1543,6 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::syncInpu
return *this;
}
-#endif
-
SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setColorTransform(
const sp<SurfaceControl>& sc, const mat3& matrix, const vec3& translation) {
layer_state_t* s = getLayerState(sc);
@@ -1722,6 +1743,21 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setDesti
return *this;
}
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setDropInputMode(
+ const sp<SurfaceControl>& sc, gui::DropInputMode mode) {
+ layer_state_t* s = getLayerState(sc);
+ if (!s) {
+ mStatus = BAD_INDEX;
+ return *this;
+ }
+
+ s->what |= layer_state_t::eDropInputModeChanged;
+ s->dropInputMode = mode;
+
+ registerSurfaceControlForCallback(sc);
+ return *this;
+}
+
// ---------------------------------------------------------------------------
DisplayState& SurfaceComposerClient::Transaction::getDisplayState(const sp<IBinder>& token) {
@@ -1762,6 +1798,12 @@ void SurfaceComposerClient::Transaction::setDisplayLayerStack(const sp<IBinder>&
s.what |= DisplayState::eLayerStackChanged;
}
+void SurfaceComposerClient::Transaction::setDisplayFlags(const sp<IBinder>& token, uint32_t flags) {
+ DisplayState& s(getDisplayState(token));
+ s.flags = flags;
+ s.what |= DisplayState::eFlagsChanged;
+}
+
void SurfaceComposerClient::Transaction::setDisplayProjection(const sp<IBinder>& token,
ui::Rotation orientation,
const Rect& layerStackRect,
@@ -1783,15 +1825,10 @@ void SurfaceComposerClient::Transaction::setDisplaySize(const sp<IBinder>& token
// ---------------------------------------------------------------------------
-SurfaceComposerClient::SurfaceComposerClient()
- : mStatus(NO_INIT)
-{
-}
+SurfaceComposerClient::SurfaceComposerClient() : mStatus(NO_INIT) {}
SurfaceComposerClient::SurfaceComposerClient(const sp<ISurfaceComposerClient>& client)
- : mStatus(NO_ERROR), mClient(client)
-{
-}
+ : mStatus(NO_ERROR), mClient(client) {}
void SurfaceComposerClient::onFirstRef() {
sp<ISurfaceComposer> sf(ComposerService::getComposerService());
@@ -2157,6 +2194,18 @@ int SurfaceComposerClient::getGPUContextPriority() {
return ComposerService::getComposerService()->getGPUContextPriority();
}
+status_t SurfaceComposerClient::addWindowInfosListener(
+ const sp<WindowInfosListener>& windowInfosListener) {
+ return WindowInfosListenerReporter::getInstance()
+ ->addWindowInfosListener(windowInfosListener, ComposerService::getComposerService());
+}
+
+status_t SurfaceComposerClient::removeWindowInfosListener(
+ const sp<WindowInfosListener>& windowInfosListener) {
+ return WindowInfosListenerReporter::getInstance()
+ ->removeWindowInfosListener(windowInfosListener, ComposerService::getComposerService());
+}
+
// ----------------------------------------------------------------------------
status_t ScreenshotClient::captureDisplay(const DisplayCaptureArgs& captureArgs,
diff --git a/libs/input/InputWindow.cpp b/libs/gui/WindowInfo.cpp
index 99477200db..b2ef7aabc9 100644
--- a/libs/input/InputWindow.cpp
+++ b/libs/gui/WindowInfo.cpp
@@ -15,50 +15,47 @@
*/
#include <type_traits>
-#define LOG_TAG "InputWindow"
+#define LOG_TAG "WindowInfo"
#define LOG_NDEBUG 0
#include <android-base/stringprintf.h>
#include <binder/Parcel.h>
-#include <input/InputTransport.h>
-#include <input/InputWindow.h>
+#include <gui/WindowInfo.h>
#include <log/log.h>
-namespace android {
+namespace android::gui {
-
-// --- InputWindowInfo ---
-void InputWindowInfo::addTouchableRegion(const Rect& region) {
+// --- WindowInfo ---
+void WindowInfo::addTouchableRegion(const Rect& region) {
touchableRegion.orSelf(region);
}
-bool InputWindowInfo::touchableRegionContainsPoint(int32_t x, int32_t y) const {
- return touchableRegion.contains(x,y);
+bool WindowInfo::touchableRegionContainsPoint(int32_t x, int32_t y) const {
+ return touchableRegion.contains(x, y);
}
-bool InputWindowInfo::frameContainsPoint(int32_t x, int32_t y) const {
- return x >= frameLeft && x < frameRight
- && y >= frameTop && y < frameBottom;
+bool WindowInfo::frameContainsPoint(int32_t x, int32_t y) const {
+ return x >= frameLeft && x < frameRight && y >= frameTop && y < frameBottom;
}
-bool InputWindowInfo::supportsSplitTouch() const {
+bool WindowInfo::supportsSplitTouch() const {
return flags.test(Flag::SPLIT_TOUCH);
}
-bool InputWindowInfo::overlaps(const InputWindowInfo* other) const {
- return frameLeft < other->frameRight && frameRight > other->frameLeft
- && frameTop < other->frameBottom && frameBottom > other->frameTop;
+bool WindowInfo::overlaps(const WindowInfo* other) const {
+ return frameLeft < other->frameRight && frameRight > other->frameLeft &&
+ frameTop < other->frameBottom && frameBottom > other->frameTop;
}
-bool InputWindowInfo::operator==(const InputWindowInfo& info) const {
+bool WindowInfo::operator==(const WindowInfo& info) const {
return info.token == token && info.id == id && info.name == name && info.flags == flags &&
info.type == type && info.dispatchingTimeout == dispatchingTimeout &&
info.frameLeft == frameLeft && info.frameTop == frameTop &&
info.frameRight == frameRight && info.frameBottom == frameBottom &&
info.surfaceInset == surfaceInset && info.globalScaleFactor == globalScaleFactor &&
- info.transform == transform && info.displayWidth == displayWidth &&
- info.displayHeight == displayHeight &&
+ info.transform == transform && info.displayOrientation == displayOrientation &&
+ info.displayWidth == displayWidth && info.displayHeight == displayHeight &&
info.touchableRegion.hasSameRects(touchableRegion) && info.visible == visible &&
info.trustedOverlay == trustedOverlay && info.focusable == focusable &&
info.touchOcclusionMode == touchOcclusionMode && info.hasWallpaper == hasWallpaper &&
@@ -69,7 +66,7 @@ bool InputWindowInfo::operator==(const InputWindowInfo& info) const {
info.applicationInfo == applicationInfo;
}
-status_t InputWindowInfo::writeToParcel(android::Parcel* parcel) const {
+status_t WindowInfo::writeToParcel(android::Parcel* parcel) const {
if (parcel == nullptr) {
ALOGE("%s: Null parcel", __func__);
return BAD_VALUE;
@@ -86,7 +83,7 @@ status_t InputWindowInfo::writeToParcel(android::Parcel* parcel) const {
parcel->writeInt32(id) ?:
parcel->writeUtf8AsUtf16(name) ?:
parcel->writeInt32(flags.get()) ?:
- parcel->writeInt32(static_cast<std::underlying_type_t<InputWindowInfo::Type>>(type)) ?:
+ parcel->writeInt32(static_cast<std::underlying_type_t<WindowInfo::Type>>(type)) ?:
parcel->writeInt32(frameLeft) ?:
parcel->writeInt32(frameTop) ?:
parcel->writeInt32(frameRight) ?:
@@ -100,6 +97,7 @@ status_t InputWindowInfo::writeToParcel(android::Parcel* parcel) const {
parcel->writeFloat(transform.dtdy()) ?:
parcel->writeFloat(transform.dsdy()) ?:
parcel->writeFloat(transform.ty()) ?:
+ parcel->writeUint32(displayOrientation) ?:
parcel->writeInt32(displayWidth) ?:
parcel->writeInt32(displayHeight) ?:
parcel->writeBool(visible) ?:
@@ -117,12 +115,13 @@ status_t InputWindowInfo::writeToParcel(android::Parcel* parcel) const {
applicationInfo.writeToParcel(parcel) ?:
parcel->write(touchableRegion) ?:
parcel->writeBool(replaceTouchableRegionWithCrop) ?:
- parcel->writeStrongBinder(touchableRegionCropHandle.promote());
+ parcel->writeStrongBinder(touchableRegionCropHandle.promote()) ?:
+ parcel->writeStrongBinder(windowToken);
// clang-format on
return status;
}
-status_t InputWindowInfo::readFromParcel(const android::Parcel* parcel) {
+status_t WindowInfo::readFromParcel(const android::Parcel* parcel) {
if (parcel == nullptr) {
ALOGE("%s: Null parcel", __func__);
return BAD_VALUE;
@@ -156,6 +155,7 @@ status_t InputWindowInfo::readFromParcel(const android::Parcel* parcel) {
parcel->readFloat(&dtdy) ?:
parcel->readFloat(&dsdy) ?:
parcel->readFloat(&ty) ?:
+ parcel->readUint32(&displayOrientation) ?:
parcel->readInt32(&displayWidth) ?:
parcel->readInt32(&displayHeight) ?:
parcel->readBool(&visible) ?:
@@ -176,11 +176,13 @@ status_t InputWindowInfo::readFromParcel(const android::Parcel* parcel) {
touchOcclusionMode = static_cast<TouchOcclusionMode>(touchOcclusionModeInt);
inputFeatures = Flags<Feature>(parcel->readInt32());
+ // clang-format off
status = parcel->readInt32(&displayId) ?:
parcel->readInt32(&portalToDisplayId) ?:
applicationInfo.readFromParcel(parcel) ?:
parcel->read(touchableRegion) ?:
parcel->readBool(&replaceTouchableRegionWithCrop);
+ // clang-format on
if (status != OK) {
return status;
@@ -189,36 +191,37 @@ status_t InputWindowInfo::readFromParcel(const android::Parcel* parcel) {
touchableRegionCropHandle = parcel->readStrongBinder();
transform.set({dsdx, dtdx, tx, dtdy, dsdy, ty, 0, 0, 1});
- return OK;
+ status = parcel->readNullableStrongBinder(&windowToken);
+ return status;
}
-// --- InputWindowHandle ---
+// --- WindowInfoHandle ---
-InputWindowHandle::InputWindowHandle() {}
+WindowInfoHandle::WindowInfoHandle() {}
-InputWindowHandle::~InputWindowHandle() {}
+WindowInfoHandle::~WindowInfoHandle() {}
-InputWindowHandle::InputWindowHandle(const InputWindowHandle& other) : mInfo(other.mInfo) {}
+WindowInfoHandle::WindowInfoHandle(const WindowInfoHandle& other) : mInfo(other.mInfo) {}
-InputWindowHandle::InputWindowHandle(const InputWindowInfo& other) : mInfo(other) {}
+WindowInfoHandle::WindowInfoHandle(const WindowInfo& other) : mInfo(other) {}
-status_t InputWindowHandle::writeToParcel(android::Parcel* parcel) const {
+status_t WindowInfoHandle::writeToParcel(android::Parcel* parcel) const {
return mInfo.writeToParcel(parcel);
}
-status_t InputWindowHandle::readFromParcel(const android::Parcel* parcel) {
+status_t WindowInfoHandle::readFromParcel(const android::Parcel* parcel) {
return mInfo.readFromParcel(parcel);
}
-void InputWindowHandle::releaseChannel() {
+void WindowInfoHandle::releaseChannel() {
mInfo.token.clear();
}
-sp<IBinder> InputWindowHandle::getToken() const {
+sp<IBinder> WindowInfoHandle::getToken() const {
return mInfo.token;
}
-void InputWindowHandle::updateFrom(sp<InputWindowHandle> handle) {
+void WindowInfoHandle::updateFrom(sp<WindowInfoHandle> handle) {
mInfo = handle->mInfo;
}
-} // namespace android
+} // namespace android::gui
diff --git a/libs/gui/WindowInfosListenerReporter.cpp b/libs/gui/WindowInfosListenerReporter.cpp
new file mode 100644
index 0000000000..c00a4389ad
--- /dev/null
+++ b/libs/gui/WindowInfosListenerReporter.cpp
@@ -0,0 +1,98 @@
+/*
+ * 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 <gui/ISurfaceComposer.h>
+#include <gui/WindowInfosListenerReporter.h>
+
+namespace android {
+
+using gui::IWindowInfosReportedListener;
+using gui::WindowInfo;
+using gui::WindowInfosListener;
+
+sp<WindowInfosListenerReporter> WindowInfosListenerReporter::getInstance() {
+ static sp<WindowInfosListenerReporter> sInstance = new WindowInfosListenerReporter;
+ return sInstance;
+}
+
+status_t WindowInfosListenerReporter::addWindowInfosListener(
+ const sp<WindowInfosListener>& windowInfosListener,
+ const sp<ISurfaceComposer>& surfaceComposer) {
+ status_t status = OK;
+ {
+ std::scoped_lock lock(mListenersMutex);
+ if (mWindowInfosListeners.empty()) {
+ status = surfaceComposer->addWindowInfosListener(this);
+ }
+
+ if (status == OK) {
+ mWindowInfosListeners.insert(windowInfosListener);
+ }
+ }
+
+ return status;
+}
+
+status_t WindowInfosListenerReporter::removeWindowInfosListener(
+ const sp<WindowInfosListener>& windowInfosListener,
+ const sp<ISurfaceComposer>& surfaceComposer) {
+ status_t status = OK;
+ {
+ std::scoped_lock lock(mListenersMutex);
+ if (mWindowInfosListeners.size() == 1) {
+ status = surfaceComposer->removeWindowInfosListener(this);
+ }
+
+ if (status == OK) {
+ mWindowInfosListeners.erase(windowInfosListener);
+ }
+ }
+
+ return status;
+}
+
+binder::Status WindowInfosListenerReporter::onWindowInfosChanged(
+ const std::vector<WindowInfo>& windowInfos,
+ const sp<IWindowInfosReportedListener>& windowInfosReportedListener) {
+ std::unordered_set<sp<WindowInfosListener>, ISurfaceComposer::SpHash<WindowInfosListener>>
+ windowInfosListeners;
+
+ {
+ std::scoped_lock lock(mListenersMutex);
+ for (auto listener : mWindowInfosListeners) {
+ windowInfosListeners.insert(listener);
+ }
+ }
+
+ for (auto listener : windowInfosListeners) {
+ listener->onWindowInfosChanged(windowInfos);
+ }
+
+ if (windowInfosReportedListener) {
+ windowInfosReportedListener->onWindowInfosReported();
+ }
+
+ return binder::Status::ok();
+}
+
+void WindowInfosListenerReporter::reconnect(const sp<ISurfaceComposer>& composerService) {
+ std::scoped_lock lock(mListenersMutex);
+ if (!mWindowInfosListeners.empty()) {
+ composerService->addWindowInfosListener(this);
+ }
+}
+
+} // namespace android \ No newline at end of file
diff --git a/libs/gui/android/gui/DropInputMode.aidl b/libs/gui/android/gui/DropInputMode.aidl
new file mode 100644
index 0000000000..2b31744ca2
--- /dev/null
+++ b/libs/gui/android/gui/DropInputMode.aidl
@@ -0,0 +1,45 @@
+/**
+ * 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.
+ */
+
+package android.gui;
+
+
+/**
+ * Input event drop modes: Input event drop options for windows and its children.
+ *
+ * @hide
+ */
+@Backing(type="int")
+enum DropInputMode {
+ /**
+ * Default mode, input events are sent to the target as usual.
+ */
+ NONE,
+
+ /**
+ * Window and its children will not receive any input even if it has a valid input channel.
+ * Touches and keys will be dropped. If a window is focused, it will remain focused but will
+ * not receive any keys. If the window has a touchable region and is the target of an input
+ * event, the event will be dropped and will not go to the window behind. ref: b/197296414
+ */
+ ALL,
+
+ /**
+ * Similar to DROP but input events are only dropped if the window is considered to be
+ * obscured. ref: b/197364677
+ */
+ OBSCURED
+}
diff --git a/libs/input/android/FocusRequest.aidl b/libs/gui/android/gui/FocusRequest.aidl
index 8812d34a72..90186351c5 100644
--- a/libs/input/android/FocusRequest.aidl
+++ b/libs/gui/android/gui/FocusRequest.aidl
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android;
+package android.gui;
/** @hide */
parcelable FocusRequest {
diff --git a/libs/gui/android/gui/IWindowInfosListener.aidl b/libs/gui/android/gui/IWindowInfosListener.aidl
new file mode 100644
index 0000000000..d4553ca82d
--- /dev/null
+++ b/libs/gui/android/gui/IWindowInfosListener.aidl
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+package android.gui;
+
+import android.gui.IWindowInfosReportedListener;
+import android.gui.WindowInfo;
+
+/** @hide */
+oneway interface IWindowInfosListener
+{
+ void onWindowInfosChanged(in WindowInfo[] windowInfos, in @nullable IWindowInfosReportedListener windowInfosReportedListener);
+}
diff --git a/libs/input/android/os/ISetInputWindowsListener.aidl b/libs/gui/android/gui/IWindowInfosReportedListener.aidl
index bb58fb671b..0e4cce61a2 100644
--- a/libs/input/android/os/ISetInputWindowsListener.aidl
+++ b/libs/gui/android/gui/IWindowInfosReportedListener.aidl
@@ -14,10 +14,10 @@
* limitations under the License.
*/
-package android.os;
+package android.gui;
/** @hide */
-oneway interface ISetInputWindowsListener
+oneway interface IWindowInfosReportedListener
{
- void onSetInputWindowsFinished();
+ void onWindowInfosReported();
}
diff --git a/libs/input/android/InputApplicationInfo.aidl b/libs/gui/android/gui/InputApplicationInfo.aidl
index 933603916d..c0fd666543 100644
--- a/libs/input/android/InputApplicationInfo.aidl
+++ b/libs/gui/android/gui/InputApplicationInfo.aidl
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android;
+package android.gui;
parcelable InputApplicationInfo {
@nullable IBinder token;
diff --git a/libs/input/android/os/TouchOcclusionMode.aidl b/libs/gui/android/gui/TouchOcclusionMode.aidl
index 106f159a50..d91d052135 100644
--- a/libs/input/android/os/TouchOcclusionMode.aidl
+++ b/libs/gui/android/gui/TouchOcclusionMode.aidl
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.os;
+package android.gui;
/**
diff --git a/libs/input/android/InputWindowInfo.aidl b/libs/gui/android/gui/WindowInfo.aidl
index eeaf400227..2c85d155a8 100644
--- a/libs/input/android/InputWindowInfo.aidl
+++ b/libs/gui/android/gui/WindowInfo.aidl
@@ -1,5 +1,4 @@
-/* //device/java/android/android/view/InputChannel.aidl
-**
+/*
** Copyright 2020, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,6 +14,6 @@
** limitations under the License.
*/
-package android;
+package android.gui;
-parcelable InputWindowInfo cpp_header "input/InputWindow.h";
+parcelable WindowInfo cpp_header "gui/WindowInfo.h";
diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h
index bc35792bef..f9e40ecb5b 100644
--- a/libs/gui/include/gui/BLASTBufferQueue.h
+++ b/libs/gui/include/gui/BLASTBufferQueue.h
@@ -53,7 +53,6 @@ public:
CompositorTiming compositorTiming, nsecs_t latchTime,
nsecs_t dequeueReadyTime) REQUIRES(mMutex);
void getConnectionEvents(uint64_t frameNumber, bool* needsDisconnect);
- void setBlastBufferQueue(BLASTBufferQueue* blastbufferqueue) REQUIRES(mMutex);
protected:
void onSidebandStreamChanged() override REQUIRES(mMutex);
@@ -74,6 +73,7 @@ class BLASTBufferQueue
: public ConsumerBase::FrameAvailableListener, public BufferItemConsumer::BufferFreedListener
{
public:
+ BLASTBufferQueue(const std::string& name);
BLASTBufferQueue(const std::string& name, const sp<SurfaceControl>& surface, int width,
int height, int32_t format);
@@ -88,10 +88,14 @@ public:
void onFrameDequeued(const uint64_t) override;
void onFrameCancelled(const uint64_t) override;
+ void transactionCommittedCallback(nsecs_t latchTime, const sp<Fence>& presentFence,
+ const std::vector<SurfaceControlStats>& stats);
void transactionCallback(nsecs_t latchTime, const sp<Fence>& presentFence,
const std::vector<SurfaceControlStats>& stats);
void releaseBufferCallback(const ReleaseCallbackId& id, const sp<Fence>& releaseFence,
uint32_t transformHint, uint32_t currentMaxAcquiredBufferCount);
+ void releaseBufferCallbackLocked(const ReleaseCallbackId& id, const sp<Fence>& releaseFence,
+ uint32_t transformHint, uint32_t currentMaxAcquiredBufferCount);
void setNextTransaction(SurfaceComposerClient::Transaction *t);
void mergeWithNextTransaction(SurfaceComposerClient::Transaction* t, uint64_t frameNumber);
void setTransactionCompleteCallback(uint64_t frameNumber,
@@ -99,7 +103,6 @@ public:
void update(const sp<SurfaceControl>& surface, uint32_t width, uint32_t height, int32_t format,
SurfaceComposerClient::Transaction* outTransaction = nullptr);
- void flushShadowQueue() {}
status_t setFrameRate(float frameRate, int8_t compatibility, bool shouldBeSeamless);
status_t setFrameTimelineInfo(const FrameTimelineInfo& info);
@@ -107,6 +110,9 @@ public:
void setSidebandStream(const sp<NativeHandle>& stream);
uint32_t getLastTransformHint() const;
+ void flushShadowQueue();
+
+ uint64_t getLastAcquiredFrameNum();
virtual ~BLASTBufferQueue();
@@ -119,13 +125,17 @@ private:
void createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
sp<IGraphicBufferConsumer>* outConsumer);
- void processNextBufferLocked(bool useNextTransaction) REQUIRES(mMutex);
+ void acquireNextBufferLocked(
+ const std::optional<SurfaceComposerClient::Transaction*> transaction) REQUIRES(mMutex);
Rect computeCrop(const BufferItem& item) REQUIRES(mMutex);
// Return true if we need to reject the buffer based on the scaling mode and the buffer size.
bool rejectBuffer(const BufferItem& item) REQUIRES(mMutex);
bool maxBuffersAcquired(bool includeExtraAcquire) const REQUIRES(mMutex);
static PixelFormat convertBufferFormat(PixelFormat& format);
+ void flushShadowQueueLocked() REQUIRES(mMutex);
+ void acquireAndReleaseBuffer() REQUIRES(mMutex);
+
std::string mName;
// Represents the queued buffer count from buffer queue,
// pre-BLAST. This is mNumFrameAvailable (buffers that queued to blast) +
@@ -155,6 +165,12 @@ private:
struct ReleasedBuffer {
ReleaseCallbackId callbackId;
sp<Fence> releaseFence;
+ bool operator==(const ReleasedBuffer& rhs) const {
+ // Only compare Id so if we somehow got two callbacks
+ // with different fences we don't decrement mNumAcquired
+ // too far.
+ return rhs.callbackId == callbackId;
+ }
};
std::deque<ReleasedBuffer> mPendingRelease GUARDED_BY(mMutex);
@@ -233,6 +249,9 @@ private:
// 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);
+
+ uint32_t mCurrentMaxAcquiredBufferCount;
+ bool mWaitForTransactionCallback = false;
};
} // namespace android
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index ef5353f594..cd289cb401 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -22,11 +22,12 @@
#include <android/gui/IScreenCaptureListener.h>
#include <android/gui/ITransactionTraceListener.h>
#include <android/gui/ITunnelModeEnabledListener.h>
+#include <android/gui/IWindowInfosListener.h>
#include <binder/IBinder.h>
#include <binder/IInterface.h>
+#include <ftl/Flags.h>
#include <gui/FrameTimelineInfo.h>
#include <gui/ITransactionCompletedListener.h>
-#include <input/Flags.h>
#include <math/vec4.h>
#include <stdint.h>
#include <sys/types.h>
@@ -554,6 +555,11 @@ public:
* in MIN_UNDEQUEUED_BUFFERS.
*/
virtual status_t getMaxAcquiredBufferCount(int* buffers) const = 0;
+
+ virtual status_t addWindowInfosListener(
+ const sp<gui::IWindowInfosListener>& windowInfosListener) const = 0;
+ virtual status_t removeWindowInfosListener(
+ const sp<gui::IWindowInfosListener>& windowInfosListener) const = 0;
};
// ----------------------------------------------------------------------------
@@ -626,6 +632,8 @@ public:
ON_PULL_ATOM,
ADD_TUNNEL_MODE_ENABLED_LISTENER,
REMOVE_TUNNEL_MODE_ENABLED_LISTENER,
+ ADD_WINDOW_INFOS_LISTENER,
+ REMOVE_WINDOW_INFOS_LISTENER,
GET_PRIMARY_PHYSICAL_DISPLAY_ID,
// Always append new enum to the end.
};
diff --git a/include/input/InputApplication.h b/libs/gui/include/gui/InputApplication.h
index 8e4fe796a5..679c2a1754 100644
--- a/include/input/InputApplication.h
+++ b/libs/gui/include/gui/InputApplication.h
@@ -19,17 +19,17 @@
#include <string>
-#include <android/InputApplicationInfo.h>
+#include <android/gui/InputApplicationInfo.h>
#include <binder/IBinder.h>
#include <binder/Parcel.h>
#include <binder/Parcelable.h>
-#include <input/Input.h>
#include <utils/RefBase.h>
#include <utils/Timers.h>
namespace android {
+
/*
* Handle for an application that can receive input.
*
@@ -38,13 +38,9 @@ namespace android {
*/
class InputApplicationHandle {
public:
- inline const InputApplicationInfo* getInfo() const {
- return &mInfo;
- }
+ inline const gui::InputApplicationInfo* getInfo() const { return &mInfo; }
- inline std::string getName() const {
- return !mInfo.name.empty() ? mInfo.name : "<invalid>";
- }
+ inline std::string getName() const { return !mInfo.name.empty() ? mInfo.name : "<invalid>"; }
inline std::chrono::nanoseconds getDispatchingTimeout(
std::chrono::nanoseconds defaultValue) const {
@@ -52,9 +48,7 @@ public:
: defaultValue;
}
- inline sp<IBinder> getApplicationToken() const {
- return mInfo.token;
- }
+ inline sp<IBinder> getApplicationToken() const { return mInfo.token; }
bool operator==(const InputApplicationHandle& other) const {
return getName() == other.getName() && getApplicationToken() == other.getApplicationToken();
@@ -77,7 +71,7 @@ protected:
InputApplicationHandle() = default;
virtual ~InputApplicationHandle() = default;
- InputApplicationInfo mInfo;
+ gui::InputApplicationInfo mInfo;
};
} // namespace android
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index 3e57ff611e..03e4aacdbe 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -26,14 +26,13 @@
#include <gui/ITransactionCompletedListener.h>
#include <math/mat4.h>
-#ifndef NO_INPUT
-#include <android/FocusRequest.h>
-#include <input/InputWindow.h>
-#endif
+#include <android/gui/DropInputMode.h>
+#include <android/gui/FocusRequest.h>
#include <gui/ISurfaceComposer.h>
#include <gui/LayerMetadata.h>
#include <gui/SurfaceControl.h>
+#include <gui/WindowInfo.h>
#include <math/vec3.h>
#include <ui/BlurRegion.h>
#include <ui/GraphicTypes.h>
@@ -119,6 +118,7 @@ struct layer_state_t {
eAutoRefreshChanged = 0x1000'00000000,
eStretchChanged = 0x2000'00000000,
eTrustedOverlayChanged = 0x4000'00000000,
+ eDropInputModeChanged = 0x8000'00000000,
};
layer_state_t();
@@ -178,9 +178,7 @@ struct layer_state_t {
mat4 colorTransform;
std::vector<BlurRegion> blurRegions;
-#ifndef NO_INPUT
- sp<InputWindowHandle> inputHandle = new InputWindowHandle();
-#endif
+ sp<gui::WindowInfoHandle> windowInfoHandle = new gui::WindowInfoHandle();
client_cache_t cachedBuffer;
@@ -246,6 +244,14 @@ struct layer_state_t {
// is used to remove the old callback from the client process map if it is
// overwritten by another setBuffer call.
ReleaseCallbackId releaseCallbackId;
+
+ // Stores which endpoint the release information should be sent to. We don't want to send the
+ // releaseCallbackId and release fence to all listeners so we store which listener the setBuffer
+ // was called with.
+ sp<IBinder> releaseBufferEndpoint;
+
+ // Force inputflinger to drop all input events for the layer and its children.
+ gui::DropInputMode dropInputMode;
};
struct ComposerState {
@@ -259,7 +265,8 @@ struct DisplayState {
eSurfaceChanged = 0x01,
eLayerStackChanged = 0x02,
eDisplayProjectionChanged = 0x04,
- eDisplaySizeChanged = 0x08
+ eDisplaySizeChanged = 0x08,
+ eFlagsChanged = 0x10
};
DisplayState();
@@ -269,6 +276,7 @@ struct DisplayState {
sp<IBinder> token;
sp<IGraphicBufferProducer> surface;
uint32_t layerStack;
+ uint32_t flags;
// These states define how layers are projected onto the physical display.
//
@@ -292,9 +300,7 @@ struct DisplayState {
};
struct InputWindowCommands {
-#ifndef NO_INPUT
- std::vector<FocusRequest> focusRequests;
-#endif
+ std::vector<gui::FocusRequest> focusRequests;
bool syncInputWindows{false};
// Merges the passed in commands and returns true if there were any changes.
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 4164ca36ba..0d1d1a37bd 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -42,6 +42,7 @@
#include <gui/ITransactionCompletedListener.h>
#include <gui/LayerState.h>
#include <gui/SurfaceControl.h>
+#include <gui/WindowInfosListenerReporter.h>
#include <math/vec3.h>
namespace android {
@@ -56,14 +57,15 @@ class Region;
struct SurfaceControlStats {
SurfaceControlStats(const sp<SurfaceControl>& sc, nsecs_t latchTime, nsecs_t acquireTime,
const sp<Fence>& presentFence, const sp<Fence>& prevReleaseFence,
- uint32_t hint, FrameEventHistoryStats eventStats)
+ uint32_t hint, FrameEventHistoryStats eventStats, uint32_t currentMaxAcquiredBufferCount)
: surfaceControl(sc),
latchTime(latchTime),
acquireTime(acquireTime),
presentFence(presentFence),
previousReleaseFence(prevReleaseFence),
transformHint(hint),
- frameEventStats(eventStats) {}
+ frameEventStats(eventStats),
+ currentMaxAcquiredBufferCount(currentMaxAcquiredBufferCount) {}
sp<SurfaceControl> surfaceControl;
nsecs_t latchTime = -1;
@@ -72,6 +74,7 @@ struct SurfaceControlStats {
sp<Fence> previousReleaseFence;
uint32_t transformHint = 0;
FrameEventHistoryStats frameEventStats;
+ uint32_t currentMaxAcquiredBufferCount = 0;
};
using TransactionCompletedCallbackTakesContext =
@@ -503,11 +506,9 @@ public:
// Set the framenumber generated by the graphics producer to mimic BufferQueue behaviour.
Transaction& setFrameNumber(const sp<SurfaceControl>& sc, uint64_t frameNumber);
-#ifndef NO_INPUT
- Transaction& setInputWindowInfo(const sp<SurfaceControl>& sc, const InputWindowInfo& info);
- Transaction& setFocusedWindow(const FocusRequest& request);
+ Transaction& setInputWindowInfo(const sp<SurfaceControl>& sc, const gui::WindowInfo& info);
+ Transaction& setFocusedWindow(const gui::FocusRequest& request);
Transaction& syncInputWindows();
-#endif
// Set a color transform matrix on the given layer on the built-in display.
Transaction& setColorTransform(const sp<SurfaceControl>& sc, const mat3& matrix,
@@ -564,12 +565,15 @@ public:
Transaction& setBufferCrop(const sp<SurfaceControl>& sc, const Rect& bufferCrop);
Transaction& setDestinationFrame(const sp<SurfaceControl>& sc,
const Rect& destinationFrame);
+ Transaction& setDropInputMode(const sp<SurfaceControl>& sc, gui::DropInputMode mode);
status_t setDisplaySurface(const sp<IBinder>& token,
const sp<IGraphicBufferProducer>& bufferProducer);
void setDisplayLayerStack(const sp<IBinder>& token, uint32_t layerStack);
+ void setDisplayFlags(const sp<IBinder>& token, uint32_t flags);
+
/* setDisplayProjection() defines the projection of layer stacks
* to a given display.
*
@@ -623,6 +627,9 @@ public:
static status_t removeTunnelModeEnabledListener(
const sp<gui::ITunnelModeEnabledListener>& listener);
+ status_t addWindowInfosListener(const sp<gui::WindowInfosListener>& windowInfosListener);
+ status_t removeWindowInfosListener(const sp<gui::WindowInfosListener>& windowInfosListener);
+
private:
virtual void onFirstRef();
@@ -652,8 +659,10 @@ public:
};
class TransactionCompletedListener : public BnTransactionCompletedListener {
+public:
TransactionCompletedListener();
+protected:
int64_t getNextIdLocked() REQUIRES(mMutex);
std::mutex mMutex;
@@ -683,13 +692,13 @@ class TransactionCompletedListener : public BnTransactionCompletedListener {
std::unordered_map<CallbackId, CallbackTranslation, CallbackIdHash> mCallbacks
GUARDED_BY(mMutex);
- std::multimap<sp<IBinder>, sp<JankDataListener>> mJankListeners GUARDED_BY(mMutex);
+ std::multimap<int32_t, sp<JankDataListener>> mJankListeners GUARDED_BY(mMutex);
std::unordered_map<ReleaseCallbackId, ReleaseBufferCallback, ReleaseBufferCallbackIdHash>
mReleaseBufferCallbacks GUARDED_BY(mMutex);
// This is protected by mSurfaceStatsListenerMutex, but GUARDED_BY isn't supported for
// std::recursive_mutex
- std::multimap<sp<IBinder>, SurfaceStatsCallbackEntry> mSurfaceStatsListeners;
+ std::multimap<int32_t, SurfaceStatsCallbackEntry> mSurfaceStatsListeners;
public:
static sp<TransactionCompletedListener> getInstance();
@@ -731,8 +740,12 @@ public:
void onReleaseBuffer(ReleaseCallbackId, sp<Fence> releaseFence, uint32_t transformHint,
uint32_t currentMaxAcquiredBufferCount) override;
+ // For Testing Only
+ static void setInstance(const sp<TransactionCompletedListener>&);
+
private:
ReleaseBufferCallback popReleaseBufferCallbackLocked(const ReleaseCallbackId&);
+ static sp<TransactionCompletedListener> sInstance;
};
} // namespace android
diff --git a/include/input/InputWindow.h b/libs/gui/include/gui/WindowInfo.h
index 121be6d963..4727740ab5 100644
--- a/include/input/InputWindow.h
+++ b/libs/gui/include/gui/WindowInfo.h
@@ -14,15 +14,13 @@
* limitations under the License.
*/
-#ifndef _UI_INPUT_WINDOW_H
-#define _UI_INPUT_WINDOW_H
+#pragma once
-#include <android/os/TouchOcclusionMode.h>
+#include <android/gui/TouchOcclusionMode.h>
#include <binder/Parcel.h>
#include <binder/Parcelable.h>
-#include <input/Flags.h>
-#include <input/Input.h>
-#include <input/InputTransport.h>
+#include <ftl/Flags.h>
+#include <gui/constants.h>
#include <ui/Rect.h>
#include <ui/Region.h>
#include <ui/Transform.h>
@@ -31,15 +29,13 @@
#include "InputApplication.h"
-using android::os::TouchOcclusionMode;
-
-namespace android {
+namespace android::gui {
/*
* Describes the properties of a window that can receive input.
*/
-struct InputWindowInfo : public Parcelable {
- InputWindowInfo() = default;
+struct WindowInfo : public Parcelable {
+ WindowInfo() = default;
// Window flags from WindowManager.LayoutParams
enum class Flag : uint32_t {
@@ -125,9 +121,11 @@ struct InputWindowInfo : public Parcelable {
};
enum class Feature {
- DISABLE_TOUCH_PAD_GESTURES = 0x00000001,
- NO_INPUT_CHANNEL = 0x00000002,
- DISABLE_USER_ACTIVITY = 0x00000004,
+ DISABLE_TOUCH_PAD_GESTURES = 1u << 0,
+ NO_INPUT_CHANNEL = 1u << 1,
+ DISABLE_USER_ACTIVITY = 1u << 2,
+ DROP_INPUT = 1u << 3,
+ DROP_INPUT_IF_OBSCURED = 1u << 4,
};
/* These values are filled in by the WM and passed through SurfaceFlinger
@@ -136,6 +134,10 @@ struct InputWindowInfo : public Parcelable {
// This value should NOT be used to uniquely identify the window. There may be different
// input windows that have the same token.
sp<IBinder> token;
+
+ // The token that identifies which client window this WindowInfo was created for.
+ sp<IBinder> windowToken;
+
// This uniquely identifies the input window.
int32_t id = -1;
std::string name;
@@ -168,9 +170,12 @@ struct InputWindowInfo : public Parcelable {
// Transform applied to individual windows.
ui::Transform transform;
+ // Display orientation as ui::Transform::RotationFlags. Used for compatibility raw coordinates.
+ uint32_t displayOrientation = ui::Transform::ROT_0;
+
// Display size in its natural rotation. Used to rotate raw coordinates for compatibility.
- int32_t displayWidth = AMOTION_EVENT_INVALID_DISPLAY_SIZE;
- int32_t displayHeight = AMOTION_EVENT_INVALID_DISPLAY_SIZE;
+ int32_t displayWidth = 0;
+ int32_t displayHeight = 0;
/*
* This is filled in by the WM relative to the frame and then translated
@@ -206,9 +211,9 @@ struct InputWindowInfo : public Parcelable {
bool supportsSplitTouch() const;
- bool overlaps(const InputWindowInfo* other) const;
+ bool overlaps(const WindowInfo* other) const;
- bool operator==(const InputWindowInfo& inputChannel) const;
+ bool operator==(const WindowInfo& inputChannel) const;
status_t writeToParcel(android::Parcel* parcel) const override;
@@ -221,13 +226,13 @@ struct InputWindowInfo : public Parcelable {
* Used by the native input dispatcher to indirectly refer to the window manager objects
* that describe a window.
*/
-class InputWindowHandle : public RefBase {
+class WindowInfoHandle : public RefBase {
public:
- explicit InputWindowHandle();
- InputWindowHandle(const InputWindowHandle& other);
- InputWindowHandle(const InputWindowInfo& other);
+ explicit WindowInfoHandle();
+ WindowInfoHandle(const WindowInfoHandle& other);
+ WindowInfoHandle(const WindowInfo& other);
- inline const InputWindowInfo* getInfo() const { return &mInfo; }
+ inline const WindowInfo* getInfo() const { return &mInfo; }
sp<IBinder> getToken() const;
@@ -243,21 +248,9 @@ public:
}
/**
- * Requests that the state of this object be updated to reflect
- * the most current available information about the application.
- * As this class is created as RefBase object, no pure virtual function is allowed.
- *
- * This method should only be called from within the input dispatcher's
- * critical section.
- *
- * Returns true on success, or false if the handle is no longer valid.
- */
- virtual bool updateInfo() { return false; }
-
- /**
* Updates from another input window handle.
*/
- void updateFrom(const sp<InputWindowHandle> handle);
+ void updateFrom(const sp<WindowInfoHandle> handle);
/**
* Releases the channel used by the associated information when it is
@@ -270,10 +263,8 @@ public:
status_t writeToParcel(android::Parcel* parcel) const;
protected:
- virtual ~InputWindowHandle();
+ virtual ~WindowInfoHandle();
- InputWindowInfo mInfo;
+ WindowInfo mInfo;
};
-} // namespace android
-
-#endif // _UI_INPUT_WINDOW_H
+} // namespace android::gui \ No newline at end of file
diff --git a/libs/gui/include/gui/WindowInfosListener.h b/libs/gui/include/gui/WindowInfosListener.h
new file mode 100644
index 0000000000..8a70b9bb57
--- /dev/null
+++ b/libs/gui/include/gui/WindowInfosListener.h
@@ -0,0 +1,28 @@
+/*
+ * 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 <gui/WindowInfo.h>
+#include <utils/RefBase.h>
+
+namespace android::gui {
+
+class WindowInfosListener : public virtual RefBase {
+public:
+ virtual void onWindowInfosChanged(const std::vector<WindowInfo>& /*windowInfos*/) = 0;
+};
+} // namespace android::gui \ No newline at end of file
diff --git a/libs/gui/include/gui/WindowInfosListenerReporter.h b/libs/gui/include/gui/WindowInfosListenerReporter.h
new file mode 100644
index 0000000000..7cb96e0a30
--- /dev/null
+++ b/libs/gui/include/gui/WindowInfosListenerReporter.h
@@ -0,0 +1,48 @@
+/*
+ * 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/gui/BnWindowInfosListener.h>
+#include <android/gui/IWindowInfosReportedListener.h>
+#include <binder/IBinder.h>
+#include <gui/ISurfaceComposer.h>
+#include <gui/WindowInfosListener.h>
+#include <utils/Mutex.h>
+#include <unordered_set>
+
+namespace android {
+class ISurfaceComposer;
+
+class WindowInfosListenerReporter : public gui::BnWindowInfosListener {
+public:
+ static sp<WindowInfosListenerReporter> getInstance();
+ binder::Status onWindowInfosChanged(const std::vector<gui::WindowInfo>& windowInfos,
+ const sp<gui::IWindowInfosReportedListener>&) override;
+
+ status_t addWindowInfosListener(const sp<gui::WindowInfosListener>& windowInfosListener,
+ const sp<ISurfaceComposer>&);
+ status_t removeWindowInfosListener(const sp<gui::WindowInfosListener>& windowInfosListener,
+ const sp<ISurfaceComposer>&);
+ void reconnect(const sp<ISurfaceComposer>&);
+
+private:
+ std::mutex mListenersMutex;
+ std::unordered_set<sp<gui::WindowInfosListener>,
+ ISurfaceComposer::SpHash<gui::WindowInfosListener>>
+ mWindowInfosListeners GUARDED_BY(mListenersMutex);
+};
+} // namespace android \ No newline at end of file
diff --git a/libs/gui/include/gui/constants.h b/libs/gui/include/gui/constants.h
new file mode 100644
index 0000000000..8eab3783e9
--- /dev/null
+++ b/libs/gui/include/gui/constants.h
@@ -0,0 +1,37 @@
+/*
+ * 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 <stdint.h>
+
+namespace android {
+
+/**
+ * Invalid value for display size. Used when display size isn't available.
+ */
+constexpr int32_t INVALID_DISPLAY_SIZE = 0;
+
+enum {
+ /* Used when an event is not associated with any display.
+ * Typically used for non-pointer events. */
+ ADISPLAY_ID_NONE = -1,
+
+ /* The default display id. */
+ ADISPLAY_ID_DEFAULT = 0,
+};
+
+} // namespace android \ No newline at end of file
diff --git a/services/surfaceflinger/tests/utils/CallbackUtils.h b/libs/gui/include/gui/test/CallbackUtils.h
index 459b35c544..d2e04268dc 100644
--- a/services/surfaceflinger/tests/utils/CallbackUtils.h
+++ b/libs/gui/include/gui/test/CallbackUtils.h
@@ -20,8 +20,12 @@
#include <gui/SurfaceControl.h>
#include <ui/Fence.h>
#include <utils/Timers.h>
+#include <chrono>
#include <thread>
+using ::std::literals::chrono_literals::operator""ms;
+using ::std::literals::chrono_literals::operator""s;
+
namespace android {
namespace {
@@ -130,10 +134,8 @@ private:
void verifySurfaceControlStats(const SurfaceControlStats& surfaceControlStats,
nsecs_t latchTime) const {
- const auto&
- [surfaceControl, latch, acquireTime, presentFence, previousReleaseFence,
- transformHint,
- frameEvents] = surfaceControlStats;
+ const auto& [surfaceControl, latch, acquireTime, presentFence, previousReleaseFence,
+ transformHint, frameEvents, ignore] = surfaceControlStats;
ASSERT_EQ(acquireTime > 0, mBufferResult == ExpectedResult::Buffer::ACQUIRED)
<< "bad acquire time";
@@ -195,7 +197,7 @@ public:
std::this_thread::sleep_for(500ms);
std::lock_guard lock(mMutex);
- EXPECT_EQ(mCallbackDataQueue.size(), 0) << "extra callbacks received";
+ EXPECT_EQ(mCallbackDataQueue.size(), 0U) << "extra callbacks received";
mCallbackDataQueue = {};
}
@@ -205,5 +207,5 @@ public:
std::condition_variable mConditionVariable;
std::queue<CallbackData> mCallbackDataQueue;
};
-}
+} // namespace
} // namespace android
diff --git a/libs/gui/tests/Android.bp b/libs/gui/tests/Android.bp
index c801c6243a..3d26c3d858 100644
--- a/libs/gui/tests/Android.bp
+++ b/libs/gui/tests/Android.bp
@@ -43,6 +43,7 @@ cc_test {
"SurfaceTextureMultiContextGL_test.cpp",
"Surface_test.cpp",
"TextureRenderer.cpp",
+ "WindowInfo_test.cpp",
],
shared_libs: [
diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp
index 9082d275a2..fc7548511d 100644
--- a/libs/gui/tests/BLASTBufferQueue_test.cpp
+++ b/libs/gui/tests/BLASTBufferQueue_test.cpp
@@ -27,6 +27,7 @@
#include <gui/Surface.h>
#include <gui/SurfaceComposerClient.h>
#include <gui/SyncScreenCaptureListener.h>
+#include <gui/test/CallbackUtils.h>
#include <private/gui/ComposerService.h>
#include <ui/DisplayMode.h>
#include <ui/GraphicBuffer.h>
@@ -42,6 +43,29 @@ namespace android {
using Transaction = SurfaceComposerClient::Transaction;
using android::hardware::graphics::common::V1_2::BufferUsage;
+class CountProducerListener : public BnProducerListener {
+public:
+ void onBufferReleased() override {
+ std::scoped_lock<std::mutex> lock(mMutex);
+ mNumReleased++;
+ mReleaseCallback.notify_one();
+ }
+
+ void waitOnNumberReleased(int32_t expectedNumReleased) {
+ std::unique_lock<std::mutex> lock(mMutex);
+ while (mNumReleased < expectedNumReleased) {
+ ASSERT_NE(mReleaseCallback.wait_for(lock, std::chrono::seconds(3)),
+ std::cv_status::timeout)
+ << "did not receive release";
+ }
+ }
+
+private:
+ std::mutex mMutex;
+ std::condition_variable mReleaseCallback;
+ int32_t mNumReleased GUARDED_BY(mMutex) = 0;
+};
+
class BLASTBufferQueueHelper {
public:
BLASTBufferQueueHelper(const sp<SurfaceControl>& sc, int width, int height) {
@@ -152,18 +176,19 @@ protected:
mCaptureArgs.dataspace = ui::Dataspace::V0_SRGB;
}
- void setUpProducer(BLASTBufferQueueHelper& adapter, sp<IGraphicBufferProducer>& producer) {
+ void setUpProducer(BLASTBufferQueueHelper& adapter, sp<IGraphicBufferProducer>& producer,
+ int32_t maxBufferCount = 2) {
producer = adapter.getIGraphicBufferProducer();
- setUpProducer(producer);
+ setUpProducer(producer, maxBufferCount);
}
- void setUpProducer(sp<IGraphicBufferProducer>& igbProducer) {
+ void setUpProducer(sp<IGraphicBufferProducer>& igbProducer, int32_t maxBufferCount) {
ASSERT_NE(nullptr, igbProducer.get());
- ASSERT_EQ(NO_ERROR, igbProducer->setMaxDequeuedBufferCount(2));
+ ASSERT_EQ(NO_ERROR, igbProducer->setMaxDequeuedBufferCount(maxBufferCount));
IGraphicBufferProducer::QueueBufferOutput qbOutput;
+ mProducerListener = new CountProducerListener();
ASSERT_EQ(NO_ERROR,
- igbProducer->connect(new StubProducerListener, NATIVE_WINDOW_API_CPU, false,
- &qbOutput));
+ igbProducer->connect(mProducerListener, NATIVE_WINDOW_API_CPU, false, &qbOutput));
ASSERT_NE(ui::Transform::ROT_INVALID, qbOutput.transformHint);
}
@@ -287,6 +312,7 @@ protected:
DisplayCaptureArgs mCaptureArgs;
ScreenCaptureResults mCaptureResults;
+ sp<CountProducerListener> mProducerListener;
};
TEST_F(BLASTBufferQueueTest, CreateBLASTBufferQueue) {
@@ -672,6 +698,317 @@ TEST_F(BLASTBufferQueueTest, ScaleCroppedBufferToWindowSize) {
/*border*/ 0, /*outsideRegion*/ true));
}
+// b/196339769 verify we can can update the requested size while the in FREEZE scaling mode and
+// scale the buffer properly when the mode changes to SCALE_TO_WINDOW
+TEST_F(BLASTBufferQueueTest, ScalingModeChanges) {
+ uint8_t r = 255;
+ uint8_t g = 0;
+ uint8_t b = 0;
+
+ BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight / 4);
+ sp<IGraphicBufferProducer> igbProducer;
+ setUpProducer(adapter, igbProducer);
+ {
+ int slot;
+ sp<Fence> fence;
+ sp<GraphicBuffer> buf;
+ auto ret = igbProducer->dequeueBuffer(&slot, &fence, mDisplayWidth, mDisplayHeight / 4,
+ 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));
+ fillBuffer(bufData, Rect(buf->getWidth(), buf->getHeight()), buf->getStride(), r, g, b);
+ buf->unlock();
+
+ IGraphicBufferProducer::QueueBufferOutput qbOutput;
+ IGraphicBufferProducer::QueueBufferInput input(systemTime(), true /* autotimestamp */,
+ HAL_DATASPACE_UNKNOWN, {},
+ NATIVE_WINDOW_SCALING_MODE_FREEZE, 0,
+ Fence::NO_FENCE);
+ igbProducer->queueBuffer(slot, input, &qbOutput);
+ 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)mDisplayWidth, (int32_t)mDisplayHeight / 4}));
+
+ // update the size to half the display and dequeue a buffer quarter of the display.
+ adapter.update(mSurfaceControl, mDisplayWidth, mDisplayHeight / 2);
+
+ {
+ int slot;
+ sp<Fence> fence;
+ sp<GraphicBuffer> buf;
+ auto ret = igbProducer->dequeueBuffer(&slot, &fence, mDisplayWidth, mDisplayHeight / 8,
+ 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));
+ g = 255;
+ fillBuffer(bufData, Rect(buf->getWidth(), buf->getHeight()), buf->getStride(), r, g, b);
+ buf->unlock();
+
+ IGraphicBufferProducer::QueueBufferOutput qbOutput;
+ IGraphicBufferProducer::QueueBufferInput input(systemTime(), true /* autotimestamp */,
+ HAL_DATASPACE_UNKNOWN, {},
+ NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW,
+ 0, Fence::NO_FENCE);
+ igbProducer->queueBuffer(slot, input, &qbOutput);
+ adapter.waitForCallbacks();
+ }
+ // capture screen and verify that it is red
+ ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults));
+ // verify we still scale the buffer to the new size (half the screen height)
+ ASSERT_NO_FATAL_FAILURE(
+ checkScreenCapture(r, g, b,
+ {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight / 2}));
+}
+
+TEST_F(BLASTBufferQueueTest, SyncThenNoSync) {
+ uint8_t r = 255;
+ uint8_t g = 0;
+ uint8_t b = 0;
+
+ BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight);
+
+ sp<IGraphicBufferProducer> igbProducer;
+ setUpProducer(adapter, igbProducer);
+
+ Transaction next;
+ adapter.setNextTransaction(&next);
+ queueBuffer(igbProducer, 0, 255, 0, 0);
+
+ // queue non sync buffer, so this one should get blocked
+ // Add a present delay to allow the first screenshot to get taken.
+ nsecs_t presentTimeDelay = std::chrono::nanoseconds(500ms).count();
+ queueBuffer(igbProducer, r, g, b, presentTimeDelay);
+
+ CallbackHelper transactionCallback;
+ next.addTransactionCompletedCallback(transactionCallback.function,
+ transactionCallback.getContext())
+ .apply();
+
+ CallbackData callbackData;
+ transactionCallback.getCallbackData(&callbackData);
+
+ // capture screen and verify that it is red
+ ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults));
+ ASSERT_NO_FATAL_FAILURE(
+ checkScreenCapture(0, 255, 0, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight}));
+
+ mProducerListener->waitOnNumberReleased(1);
+ ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults));
+ ASSERT_NO_FATAL_FAILURE(
+ checkScreenCapture(r, g, b, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight}));
+}
+
+TEST_F(BLASTBufferQueueTest, MultipleSyncTransactions) {
+ uint8_t r = 255;
+ uint8_t g = 0;
+ uint8_t b = 0;
+
+ BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight);
+
+ sp<IGraphicBufferProducer> igbProducer;
+ setUpProducer(adapter, igbProducer);
+
+ Transaction mainTransaction;
+
+ Transaction next;
+ adapter.setNextTransaction(&next);
+ queueBuffer(igbProducer, 0, 255, 0, 0);
+
+ mainTransaction.merge(std::move(next));
+
+ adapter.setNextTransaction(&next);
+ queueBuffer(igbProducer, r, g, b, 0);
+
+ mainTransaction.merge(std::move(next));
+ // Expect 1 buffer to be released even before sending to SurfaceFlinger
+ mProducerListener->waitOnNumberReleased(1);
+
+ CallbackHelper transactionCallback;
+ mainTransaction
+ .addTransactionCompletedCallback(transactionCallback.function,
+ transactionCallback.getContext())
+ .apply();
+
+ CallbackData callbackData;
+ transactionCallback.getCallbackData(&callbackData);
+
+ // 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)mDisplayWidth, (int32_t)mDisplayHeight}));
+}
+
+TEST_F(BLASTBufferQueueTest, MultipleSyncTransactionWithNonSync) {
+ uint8_t r = 255;
+ uint8_t g = 0;
+ uint8_t b = 0;
+
+ BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight);
+
+ sp<IGraphicBufferProducer> igbProducer;
+ setUpProducer(adapter, igbProducer);
+
+ Transaction mainTransaction;
+
+ Transaction next;
+ // queue a sync transaction
+ adapter.setNextTransaction(&next);
+ queueBuffer(igbProducer, 0, 255, 0, 0);
+
+ mainTransaction.merge(std::move(next));
+
+ // queue another buffer without setting next transaction
+ queueBuffer(igbProducer, 0, 0, 255, 0);
+
+ // queue another sync transaction
+ adapter.setNextTransaction(&next);
+ queueBuffer(igbProducer, r, g, b, 0);
+ // Expect 1 buffer to be released because the non sync transaction should merge
+ // with the sync
+ mProducerListener->waitOnNumberReleased(1);
+
+ mainTransaction.merge(std::move(next));
+ // Expect 2 buffers to be released due to merging the two syncs.
+ mProducerListener->waitOnNumberReleased(2);
+
+ CallbackHelper transactionCallback;
+ mainTransaction
+ .addTransactionCompletedCallback(transactionCallback.function,
+ transactionCallback.getContext())
+ .apply();
+
+ CallbackData callbackData;
+ transactionCallback.getCallbackData(&callbackData);
+
+ // 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)mDisplayWidth, (int32_t)mDisplayHeight}));
+}
+
+TEST_F(BLASTBufferQueueTest, MultipleSyncRunOutOfBuffers) {
+ uint8_t r = 255;
+ uint8_t g = 0;
+ uint8_t b = 0;
+
+ BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight);
+
+ sp<IGraphicBufferProducer> igbProducer;
+ setUpProducer(adapter, igbProducer, 3);
+
+ Transaction mainTransaction;
+
+ Transaction next;
+ // queue a sync transaction
+ adapter.setNextTransaction(&next);
+ queueBuffer(igbProducer, 0, 255, 0, 0);
+
+ mainTransaction.merge(std::move(next));
+
+ // queue a few buffers without setting next transaction
+ queueBuffer(igbProducer, 0, 0, 255, 0);
+ queueBuffer(igbProducer, 0, 0, 255, 0);
+ queueBuffer(igbProducer, 0, 0, 255, 0);
+
+ // queue another sync transaction
+ adapter.setNextTransaction(&next);
+ queueBuffer(igbProducer, r, g, b, 0);
+ // Expect 3 buffers to be released because the non sync transactions should merge
+ // with the sync
+ mProducerListener->waitOnNumberReleased(3);
+
+ mainTransaction.merge(std::move(next));
+ // Expect 4 buffers to be released due to merging the two syncs.
+ mProducerListener->waitOnNumberReleased(4);
+
+ CallbackHelper transactionCallback;
+ mainTransaction
+ .addTransactionCompletedCallback(transactionCallback.function,
+ transactionCallback.getContext())
+ .apply();
+
+ CallbackData callbackData;
+ transactionCallback.getCallbackData(&callbackData);
+
+ // 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)mDisplayWidth, (int32_t)mDisplayHeight}));
+}
+
+// Tests BBQ with a sync transaction when the buffers acquired reaches max and the only way to
+// continue processing is for a release callback from SurfaceFlinger.
+// This is done by sending a buffer to SF so it can release the previous one and allow BBQ to
+// continue acquiring buffers.
+TEST_F(BLASTBufferQueueTest, RunOutOfBuffersWaitingOnSF) {
+ uint8_t r = 255;
+ uint8_t g = 0;
+ uint8_t b = 0;
+
+ BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight);
+
+ sp<IGraphicBufferProducer> igbProducer;
+ setUpProducer(adapter, igbProducer, 4);
+
+ Transaction mainTransaction;
+
+ // Send a buffer to SF
+ queueBuffer(igbProducer, 0, 255, 0, 0);
+
+ Transaction next;
+ // queue a sync transaction
+ adapter.setNextTransaction(&next);
+ queueBuffer(igbProducer, 0, 255, 0, 0);
+
+ mainTransaction.merge(std::move(next));
+
+ // queue a few buffers without setting next transaction
+ queueBuffer(igbProducer, 0, 0, 255, 0);
+ queueBuffer(igbProducer, 0, 0, 255, 0);
+ queueBuffer(igbProducer, 0, 0, 255, 0);
+
+ // apply the first synced buffer to ensure we have to wait on SF
+ mainTransaction.apply();
+
+ // queue another sync transaction
+ adapter.setNextTransaction(&next);
+ queueBuffer(igbProducer, r, g, b, 0);
+ // Expect 2 buffers to be released because the non sync transactions should merge
+ // with the sync
+ mProducerListener->waitOnNumberReleased(3);
+
+ mainTransaction.merge(std::move(next));
+
+ CallbackHelper transactionCallback;
+ mainTransaction
+ .addTransactionCompletedCallback(transactionCallback.function,
+ transactionCallback.getContext())
+ .apply();
+
+ CallbackData callbackData;
+ transactionCallback.getCallbackData(&callbackData);
+
+ // 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)mDisplayWidth, (int32_t)mDisplayHeight}));
+}
+
class TestProducerListener : public BnProducerListener {
public:
sp<IGraphicBufferProducer> mIgbp;
diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp
index 49c44a78d1..5daef0df28 100644
--- a/libs/gui/tests/EndToEndNativeInputTest.cpp
+++ b/libs/gui/tests/EndToEndNativeInputTest.cpp
@@ -24,6 +24,7 @@
#include <memory>
+#include <android/keycodes.h>
#include <android/native_window.h>
#include <binder/Binder.h>
@@ -37,9 +38,9 @@
#include <gui/SurfaceControl.h>
#include <android/os/IInputFlinger.h>
+#include <gui/WindowInfo.h>
#include <input/Input.h>
#include <input/InputTransport.h>
-#include <input/InputWindow.h>
#include <ui/DisplayMode.h>
#include <ui/Rect.h>
@@ -49,6 +50,11 @@ using android::os::IInputFlinger;
using android::hardware::graphics::common::V1_1::BufferUsage;
+using android::gui::FocusRequest;
+using android::gui::InputApplicationInfo;
+using android::gui::TouchOcclusionMode;
+using android::gui::WindowInfo;
+
namespace android::test {
using Transaction = SurfaceComposerClient::Transaction;
@@ -115,8 +121,8 @@ public:
return std::make_unique<InputSurface>(surfaceControl, width, height);
}
- InputEvent* consumeEvent() {
- waitForEventAvailable();
+ InputEvent *consumeEvent(int timeoutMs = 3000) {
+ waitForEventAvailable(timeoutMs);
InputEvent *ev;
uint32_t seqId;
@@ -173,6 +179,24 @@ public:
EXPECT_EQ(flags, mev->getFlags() & flags);
}
+ void expectKey(uint32_t keycode) {
+ InputEvent *ev = consumeEvent();
+ ASSERT_NE(ev, nullptr);
+ ASSERT_EQ(AINPUT_EVENT_TYPE_KEY, ev->getType());
+ KeyEvent *keyEvent = static_cast<KeyEvent *>(ev);
+ EXPECT_EQ(AMOTION_EVENT_ACTION_DOWN, keyEvent->getAction());
+ EXPECT_EQ(keycode, keyEvent->getKeyCode());
+ EXPECT_EQ(0, keyEvent->getFlags() & VERIFIED_KEY_EVENT_FLAGS);
+
+ ev = consumeEvent();
+ ASSERT_NE(ev, nullptr);
+ ASSERT_EQ(AINPUT_EVENT_TYPE_KEY, ev->getType());
+ keyEvent = static_cast<KeyEvent *>(ev);
+ EXPECT_EQ(AMOTION_EVENT_ACTION_UP, keyEvent->getAction());
+ EXPECT_EQ(keycode, keyEvent->getKeyCode());
+ EXPECT_EQ(0, keyEvent->getFlags() & VERIFIED_KEY_EVENT_FLAGS);
+ }
+
virtual ~InputSurface() {
mInputFlinger->removeInputChannel(mClientChannel->getConnectionToken());
}
@@ -210,19 +234,19 @@ public:
}
private:
- void waitForEventAvailable() {
+ void waitForEventAvailable(int timeoutMs) {
struct pollfd fd;
fd.fd = mClientChannel->getFd();
fd.events = POLLIN;
- poll(&fd, 1, 3000);
+ poll(&fd, 1, timeoutMs);
}
void populateInputInfo(int width, int height) {
mInputInfo.token = mClientChannel->getConnectionToken();
mInputInfo.name = "Test info";
- mInputInfo.flags = InputWindowInfo::Flag::NOT_TOUCH_MODAL;
- mInputInfo.type = InputWindowInfo::Type::BASE_APPLICATION;
+ mInputInfo.flags = WindowInfo::Flag::NOT_TOUCH_MODAL;
+ mInputInfo.type = WindowInfo::Type::BASE_APPLICATION;
mInputInfo.dispatchingTimeout = 5s;
mInputInfo.globalScaleFactor = 1.0;
mInputInfo.focusable = true;
@@ -249,7 +273,7 @@ public:
std::shared_ptr<InputChannel> mClientChannel;
sp<IInputFlinger> mInputFlinger;
- InputWindowInfo mInputInfo;
+ WindowInfo mInputInfo;
PreallocatedInputEventFactory mInputEventFactory;
InputConsumer* mInputConsumer;
@@ -358,6 +382,14 @@ void injectTap(int x, int y) {
}
}
+void injectKey(uint32_t keycode) {
+ char *buf1;
+ asprintf(&buf1, "%d", keycode);
+ if (fork() == 0) {
+ execlp("input", "input", "keyevent", buf1, NULL);
+ }
+}
+
TEST_F(InputSurfacesTest, can_receive_input) {
std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
surface->showAt(100, 100);
@@ -609,6 +641,9 @@ TEST_F(InputSurfacesTest, can_be_focused) {
surface->requestFocus();
surface->assertFocusChange(true);
+
+ injectKey(AKEYCODE_V);
+ surface->expectKey(AKEYCODE_V);
}
TEST_F(InputSurfacesTest, rotate_surface) {
@@ -686,7 +721,7 @@ TEST_F(InputSurfacesTest, touch_flag_obscured) {
// Add non touchable window to fully cover touchable window. Window behind gets touch, but
// with flag AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED
std::unique_ptr<InputSurface> nonTouchableSurface = makeSurface(100, 100);
- nonTouchableSurface->mInputInfo.flags = InputWindowInfo::Flag::NOT_TOUCHABLE;
+ nonTouchableSurface->mInputInfo.flags = WindowInfo::Flag::NOT_TOUCHABLE;
nonTouchableSurface->mInputInfo.ownerUid = 22222;
// Overriding occlusion mode otherwise the touch would be discarded at InputDispatcher by
// the default obscured/untrusted touch filter introduced in S.
@@ -706,8 +741,8 @@ TEST_F(InputSurfacesTest, touch_flag_partially_obscured_with_crop) {
// AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED
std::unique_ptr<InputSurface> parentSurface = makeSurface(100, 100);
std::unique_ptr<InputSurface> nonTouchableSurface = makeSurface(100, 100);
- nonTouchableSurface->mInputInfo.flags = InputWindowInfo::Flag::NOT_TOUCHABLE;
- parentSurface->mInputInfo.flags = InputWindowInfo::Flag::NOT_TOUCHABLE;
+ nonTouchableSurface->mInputInfo.flags = WindowInfo::Flag::NOT_TOUCHABLE;
+ parentSurface->mInputInfo.flags = WindowInfo::Flag::NOT_TOUCHABLE;
nonTouchableSurface->mInputInfo.ownerUid = 22222;
parentSurface->mInputInfo.ownerUid = 22222;
nonTouchableSurface->showAt(0, 0);
@@ -730,8 +765,8 @@ TEST_F(InputSurfacesTest, touch_not_obscured_with_crop) {
// the touchable window. Window behind gets touch with no obscured flags.
std::unique_ptr<InputSurface> parentSurface = makeSurface(100, 100);
std::unique_ptr<InputSurface> nonTouchableSurface = makeSurface(100, 100);
- nonTouchableSurface->mInputInfo.flags = InputWindowInfo::Flag::NOT_TOUCHABLE;
- parentSurface->mInputInfo.flags = InputWindowInfo::Flag::NOT_TOUCHABLE;
+ nonTouchableSurface->mInputInfo.flags = WindowInfo::Flag::NOT_TOUCHABLE;
+ parentSurface->mInputInfo.flags = WindowInfo::Flag::NOT_TOUCHABLE;
nonTouchableSurface->mInputInfo.ownerUid = 22222;
parentSurface->mInputInfo.ownerUid = 22222;
nonTouchableSurface->showAt(0, 0);
@@ -751,7 +786,7 @@ TEST_F(InputSurfacesTest, touch_not_obscured_with_zero_sized_bql) {
std::unique_ptr<InputSurface> bufferSurface =
InputSurface::makeBufferInputSurface(mComposerClient, 0, 0);
- bufferSurface->mInputInfo.flags = InputWindowInfo::Flag::NOT_TOUCHABLE;
+ bufferSurface->mInputInfo.flags = WindowInfo::Flag::NOT_TOUCHABLE;
bufferSurface->mInputInfo.ownerUid = 22222;
surface->showAt(10, 10);
@@ -766,7 +801,7 @@ TEST_F(InputSurfacesTest, touch_not_obscured_with_zero_sized_blast) {
std::unique_ptr<BlastInputSurface> bufferSurface =
BlastInputSurface::makeBlastInputSurface(mComposerClient, 0, 0);
- bufferSurface->mInputInfo.flags = InputWindowInfo::Flag::NOT_TOUCHABLE;
+ bufferSurface->mInputInfo.flags = WindowInfo::Flag::NOT_TOUCHABLE;
bufferSurface->mInputInfo.ownerUid = 22222;
surface->showAt(10, 10);
@@ -776,4 +811,153 @@ TEST_F(InputSurfacesTest, touch_not_obscured_with_zero_sized_blast) {
surface->expectTap(1, 1);
}
+TEST_F(InputSurfacesTest, strict_unobscured_input_unobscured_window) {
+ std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
+ surface->doTransaction(
+ [&](auto &t, auto &sc) { t.setDropInputMode(sc, gui::DropInputMode::OBSCURED); });
+ surface->showAt(100, 100);
+
+ injectTap(101, 101);
+
+ EXPECT_NE(surface->consumeEvent(), nullptr);
+ EXPECT_NE(surface->consumeEvent(), nullptr);
+
+ surface->requestFocus();
+ surface->assertFocusChange(true);
+ injectKey(AKEYCODE_V);
+ surface->expectKey(AKEYCODE_V);
+}
+
+TEST_F(InputSurfacesTest, strict_unobscured_input_scaled_without_crop_window) {
+ std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
+ surface->doTransaction([&](auto &t, auto &sc) {
+ t.setDropInputMode(sc, gui::DropInputMode::OBSCURED);
+ t.setMatrix(sc, 2.0, 0, 0, 2.0);
+ });
+ surface->showAt(100, 100);
+
+ injectTap(101, 101);
+
+ EXPECT_NE(surface->consumeEvent(), nullptr);
+ EXPECT_NE(surface->consumeEvent(), nullptr);
+
+ surface->requestFocus();
+ surface->assertFocusChange(true);
+ injectKey(AKEYCODE_V);
+ surface->expectKey(AKEYCODE_V);
+}
+
+TEST_F(InputSurfacesTest, strict_unobscured_input_obscured_window) {
+ std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
+ surface->mInputInfo.ownerUid = 11111;
+ surface->doTransaction(
+ [&](auto &t, auto &sc) { t.setDropInputMode(sc, gui::DropInputMode::OBSCURED); });
+ surface->showAt(100, 100);
+ std::unique_ptr<InputSurface> obscuringSurface = makeSurface(100, 100);
+ obscuringSurface->mInputInfo.flags = WindowInfo::Flag::NOT_TOUCHABLE;
+ obscuringSurface->mInputInfo.ownerUid = 22222;
+ obscuringSurface->showAt(100, 100);
+ injectTap(101, 101);
+ EXPECT_EQ(surface->consumeEvent(100), nullptr);
+
+ surface->requestFocus();
+ surface->assertFocusChange(true);
+ injectKey(AKEYCODE_V);
+ EXPECT_EQ(surface->consumeEvent(100), nullptr);
+}
+
+TEST_F(InputSurfacesTest, strict_unobscured_input_partially_obscured_window) {
+ std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
+ surface->mInputInfo.ownerUid = 11111;
+ surface->doTransaction(
+ [&](auto &t, auto &sc) { t.setDropInputMode(sc, gui::DropInputMode::OBSCURED); });
+ surface->showAt(100, 100);
+ std::unique_ptr<InputSurface> obscuringSurface = makeSurface(100, 100);
+ obscuringSurface->mInputInfo.flags = WindowInfo::Flag::NOT_TOUCHABLE;
+ obscuringSurface->mInputInfo.ownerUid = 22222;
+ obscuringSurface->showAt(190, 190);
+
+ injectTap(101, 101);
+
+ EXPECT_EQ(surface->consumeEvent(100), nullptr);
+
+ surface->requestFocus();
+ surface->assertFocusChange(true);
+ injectKey(AKEYCODE_V);
+ EXPECT_EQ(surface->consumeEvent(100), nullptr);
+}
+
+TEST_F(InputSurfacesTest, strict_unobscured_input_alpha_window) {
+ std::unique_ptr<InputSurface> parentSurface = makeSurface(300, 300);
+ parentSurface->showAt(0, 0, Rect(0, 0, 300, 300));
+
+ std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
+ surface->showAt(100, 100);
+ surface->doTransaction([&](auto &t, auto &sc) {
+ t.setDropInputMode(sc, gui::DropInputMode::OBSCURED);
+ t.reparent(sc, parentSurface->mSurfaceControl);
+ t.setAlpha(parentSurface->mSurfaceControl, 0.9f);
+ });
+
+ injectTap(101, 101);
+
+ EXPECT_EQ(surface->consumeEvent(100), nullptr);
+
+ surface->requestFocus();
+ surface->assertFocusChange(true);
+ injectKey(AKEYCODE_V);
+ EXPECT_EQ(surface->consumeEvent(100), nullptr);
+}
+
+TEST_F(InputSurfacesTest, strict_unobscured_input_cropped_window) {
+ std::unique_ptr<InputSurface> parentSurface = makeSurface(300, 300);
+ parentSurface->showAt(0, 0, Rect(0, 0, 300, 300));
+
+ std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
+ surface->doTransaction([&](auto &t, auto &sc) {
+ t.setDropInputMode(sc, gui::DropInputMode::OBSCURED);
+ t.reparent(sc, parentSurface->mSurfaceControl);
+ t.setCrop(parentSurface->mSurfaceControl, Rect(10, 10, 100, 100));
+ });
+ surface->showAt(100, 100);
+
+ injectTap(111, 111);
+
+ EXPECT_EQ(surface->consumeEvent(100), nullptr);
+
+ surface->requestFocus();
+ surface->assertFocusChange(true);
+ injectKey(AKEYCODE_V);
+ EXPECT_EQ(surface->consumeEvent(100), nullptr);
+}
+
+TEST_F(InputSurfacesTest, ignore_touch_region_with_zero_sized_blast) {
+ std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
+
+ std::unique_ptr<BlastInputSurface> bufferSurface =
+ BlastInputSurface::makeBlastInputSurface(mComposerClient, 0, 0);
+
+ surface->showAt(100, 100);
+ bufferSurface->mInputInfo.touchableRegion.orSelf(Rect(0, 0, 200, 200));
+ bufferSurface->showAt(100, 100, Rect::EMPTY_RECT);
+
+ injectTap(101, 101);
+ surface->expectTap(1, 1);
+}
+
+TEST_F(InputSurfacesTest, drop_input_policy) {
+ std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
+ surface->doTransaction(
+ [&](auto &t, auto &sc) { t.setDropInputMode(sc, gui::DropInputMode::ALL); });
+ surface->showAt(100, 100);
+
+ injectTap(101, 101);
+
+ EXPECT_EQ(surface->consumeEvent(100), nullptr);
+
+ surface->requestFocus();
+ surface->assertFocusChange(true);
+ injectKey(AKEYCODE_V);
+ EXPECT_EQ(surface->consumeEvent(100), nullptr);
+}
} // namespace android::test
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 630dd17daa..c745505038 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -905,6 +905,16 @@ public:
status_t getMaxAcquiredBufferCount(int* /*buffers*/) const override { return NO_ERROR; }
+ status_t addWindowInfosListener(
+ const sp<gui::IWindowInfosListener>& /*windowInfosListener*/) const override {
+ return NO_ERROR;
+ }
+
+ status_t removeWindowInfosListener(
+ const sp<gui::IWindowInfosListener>& /*windowInfosListener*/) const override {
+ return NO_ERROR;
+ }
+
protected:
IBinder* onAsBinder() override { return nullptr; }
diff --git a/libs/input/tests/InputWindow_test.cpp b/libs/gui/tests/WindowInfo_test.cpp
index 493f2f4495..a4f436cdba 100644
--- a/libs/input/tests/InputWindow_test.cpp
+++ b/libs/gui/tests/WindowInfo_test.cpp
@@ -19,16 +19,20 @@
#include <binder/Binder.h>
#include <binder/Parcel.h>
-#include <input/InputWindow.h>
-#include <input/InputTransport.h>
+#include <gui/WindowInfo.h>
using std::chrono_literals::operator""s;
namespace android {
+
+using gui::InputApplicationInfo;
+using gui::TouchOcclusionMode;
+using gui::WindowInfo;
+
namespace test {
-TEST(InputWindowInfo, ParcellingWithoutToken) {
- InputWindowInfo i, i2;
+TEST(WindowInfo, ParcellingWithoutToken) {
+ WindowInfo i, i2;
i.token = nullptr;
Parcel p;
@@ -38,14 +42,15 @@ TEST(InputWindowInfo, ParcellingWithoutToken) {
ASSERT_TRUE(i2.token == nullptr);
}
-TEST(InputWindowInfo, Parcelling) {
+TEST(WindowInfo, Parcelling) {
sp<IBinder> touchableRegionCropHandle = new BBinder();
- InputWindowInfo i;
+ WindowInfo i;
i.token = new BBinder();
+ i.windowToken = new BBinder();
i.id = 1;
i.name = "Foobar";
- i.flags = InputWindowInfo::Flag::SLIPPERY;
- i.type = InputWindowInfo::Type::INPUT_METHOD;
+ i.flags = WindowInfo::Flag::SLIPPERY;
+ i.type = WindowInfo::Type::INPUT_METHOD;
i.dispatchingTimeout = 12s;
i.frameLeft = 93;
i.frameTop = 34;
@@ -55,6 +60,7 @@ TEST(InputWindowInfo, Parcelling) {
i.globalScaleFactor = 0.3;
i.alpha = 0.7;
i.transform.set({0.4, -1, 100, 0.5, 0, 40, 0, 0, 1});
+ i.displayOrientation = ui::Transform::ROT_0;
i.displayWidth = 1000;
i.displayHeight = 2000;
i.visible = false;
@@ -65,7 +71,7 @@ TEST(InputWindowInfo, Parcelling) {
i.ownerPid = 19;
i.ownerUid = 24;
i.packageName = "com.example.package";
- i.inputFeatures = InputWindowInfo::Feature::DISABLE_USER_ACTIVITY;
+ i.inputFeatures = WindowInfo::Feature::DISABLE_USER_ACTIVITY;
i.displayId = 34;
i.portalToDisplayId = 2;
i.replaceTouchableRegionWithCrop = true;
@@ -77,9 +83,10 @@ TEST(InputWindowInfo, Parcelling) {
Parcel p;
i.writeToParcel(&p);
p.setDataPosition(0);
- InputWindowInfo i2;
+ WindowInfo i2;
i2.readFromParcel(&p);
ASSERT_EQ(i.token, i2.token);
+ ASSERT_EQ(i.windowToken, i2.windowToken);
ASSERT_EQ(i.id, i2.id);
ASSERT_EQ(i.name, i2.name);
ASSERT_EQ(i.flags, i2.flags);
diff --git a/libs/input/Android.bp b/libs/input/Android.bp
index a63ec8fb2a..71a129141d 100644
--- a/libs/input/Android.bp
+++ b/libs/input/Android.bp
@@ -30,7 +30,6 @@ filegroup {
"android/os/IInputConstants.aidl",
"android/os/InputEventInjectionResult.aidl",
"android/os/InputEventInjectionSync.aidl",
- "android/os/TouchOcclusionMode.aidl",
],
}
@@ -79,16 +78,11 @@ cc_library {
android: {
srcs: [
"InputTransport.cpp",
- "InputWindow.cpp",
- "android/FocusRequest.aidl",
- "android/InputApplicationInfo.aidl",
"android/os/BlockUntrustedTouchesMode.aidl",
"android/os/IInputConstants.aidl",
"android/os/IInputFlinger.aidl",
"android/os/InputEventInjectionResult.aidl",
"android/os/InputEventInjectionSync.aidl",
- "android/os/ISetInputWindowsListener.aidl",
- "android/os/TouchOcclusionMode.aidl",
],
export_shared_lib_headers: ["libbinder"],
@@ -99,6 +93,14 @@ cc_library {
"libui",
],
+ static_libs: [
+ "libgui_window_info_static",
+ ],
+
+ export_static_lib_headers: [
+ "libgui_window_info_static",
+ ],
+
sanitize: {
misc_undefined: ["integer"],
},
@@ -111,29 +113,32 @@ cc_library {
"frameworks/native/libs/arect/include",
],
},
- linux_glibc: {
+ host_linux: {
srcs: [
"InputTransport.cpp",
- "InputWindow.cpp",
- "android/FocusRequest.aidl",
- "android/InputApplicationInfo.aidl",
"android/os/IInputConstants.aidl",
"android/os/IInputFlinger.aidl",
- "android/os/ISetInputWindowsListener.aidl",
- "android/os/TouchOcclusionMode.aidl",
],
static_libs: [
"libhostgraphics",
+ "libgui_window_info_static",
],
shared_libs: [
"libbinder",
],
+
+ export_static_lib_headers: [
+ "libgui_window_info_static",
+ ],
},
},
aidl: {
local_include_dirs: ["."],
export_aidl_headers: true,
+ include_dirs: [
+ "frameworks/native/libs/gui",
+ ],
},
}
diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp
index d954d23507..5f440b77e2 100644
--- a/libs/input/Input.cpp
+++ b/libs/input/Input.cpp
@@ -25,6 +25,7 @@
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
+#include <gui/constants.h>
#include <input/Input.h>
#include <input/InputDevice.h>
#include <input/InputEventLabels.h>
@@ -66,23 +67,15 @@ float transformAngle(const ui::Transform& transform, float angleRadians) {
transformedPoint.y -= origin.y;
// Derive the transformed vector's clockwise angle from vertical.
- float result = atan2f(transformedPoint.x, -transformedPoint.y);
- if (result < -M_PI_2) {
- result += M_PI;
- } else if (result > M_PI_2) {
- result -= M_PI;
- }
- return result;
+ // The return value of atan2f is in range [-pi, pi] which conforms to the orientation API.
+ return atan2f(transformedPoint.x, -transformedPoint.y);
}
-// Rotates the given point to the transform's orientation. If the display width and height are
+// Rotates the given point to the specified orientation. If the display width and height are
// provided, the point is rotated in the screen space. Otherwise, the point is rotated about the
// origin. This helper is used to avoid the extra overhead of creating new Transforms.
-vec2 rotatePoint(const ui::Transform& transform, float x, float y, int32_t displayWidth = 0,
+vec2 rotatePoint(uint32_t orientation, float x, float y, int32_t displayWidth = 0,
int32_t displayHeight = 0) {
- // 0x7 encapsulates all 3 rotations (see ui::Transform::RotationFlags)
- static const int ALL_ROTATIONS_MASK = 0x7;
- const uint32_t orientation = (transform.getOrientation() & ALL_ROTATIONS_MASK);
if (orientation == ui::Transform::ROT_0) {
return {x, y};
}
@@ -101,6 +94,19 @@ vec2 rotatePoint(const ui::Transform& transform, float x, float y, int32_t displ
return xy;
}
+vec2 applyTransformWithoutTranslation(const ui::Transform& transform, float x, float y) {
+ const vec2 transformedXy = transform.transform(x, y);
+ const vec2 transformedOrigin = transform.transform(0, 0);
+ return transformedXy - transformedOrigin;
+}
+
+bool shouldDisregardWindowTranslation(uint32_t source) {
+ // Pointer events are the only type of events that refer to absolute coordinates on the display,
+ // so we should apply the entire window transform. For other types of events, we should make
+ // sure to not apply the window translation/offset.
+ return (source & AINPUT_SOURCE_CLASS_POINTER) == 0;
+}
+
} // namespace
const char* motionClassificationToString(MotionClassification classification) {
@@ -315,6 +321,8 @@ void PointerCoords::scale(float globalScaleFactor, float windowXScale, float win
scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOUCH_MINOR, globalScaleFactor);
scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOOL_MAJOR, globalScaleFactor);
scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOOL_MINOR, globalScaleFactor);
+ scaleAxisValue(*this, AMOTION_EVENT_AXIS_RELATIVE_X, windowXScale);
+ scaleAxisValue(*this, AMOTION_EVENT_AXIS_RELATIVE_Y, windowYScale);
}
void PointerCoords::scale(float globalScaleFactor) {
@@ -383,6 +391,15 @@ void PointerCoords::transform(const ui::Transform& transform) {
setAxisValue(AMOTION_EVENT_AXIS_X, xy.x);
setAxisValue(AMOTION_EVENT_AXIS_Y, xy.y);
+ if (BitSet64::hasBit(bits, AMOTION_EVENT_AXIS_RELATIVE_X) ||
+ BitSet64::hasBit(bits, AMOTION_EVENT_AXIS_RELATIVE_Y)) {
+ const ui::Transform rotation(transform.getOrientation());
+ const vec2 relativeXy = rotation.transform(getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X),
+ getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y));
+ setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, relativeXy.x);
+ setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, relativeXy.y);
+ }
+
if (BitSet64::hasBit(bits, AMOTION_EVENT_AXIS_ORIENTATION)) {
const float val = getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION);
setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, transformAngle(transform, val));
@@ -410,9 +427,9 @@ void MotionEvent::initialize(int32_t id, int32_t deviceId, uint32_t source, int3
int32_t buttonState, MotionClassification classification,
const ui::Transform& transform, float xPrecision, float yPrecision,
float rawXCursorPosition, float rawYCursorPosition,
- int32_t displayWidth, int32_t displayHeight, nsecs_t downTime,
- nsecs_t eventTime, size_t pointerCount,
- const PointerProperties* pointerProperties,
+ uint32_t displayOrientation, int32_t displayWidth,
+ int32_t displayHeight, nsecs_t downTime, nsecs_t eventTime,
+ size_t pointerCount, const PointerProperties* pointerProperties,
const PointerCoords* pointerCoords) {
InputEvent::initialize(id, deviceId, source, displayId, hmac);
mAction = action;
@@ -427,6 +444,7 @@ void MotionEvent::initialize(int32_t id, int32_t deviceId, uint32_t source, int3
mYPrecision = yPrecision;
mRawXCursorPosition = rawXCursorPosition;
mRawYCursorPosition = rawYCursorPosition;
+ mDisplayOrientation = displayOrientation;
mDisplayWidth = displayWidth;
mDisplayHeight = displayHeight;
mDownTime = downTime;
@@ -452,6 +470,7 @@ void MotionEvent::copyFrom(const MotionEvent* other, bool keepHistory) {
mYPrecision = other->mYPrecision;
mRawXCursorPosition = other->mRawXCursorPosition;
mRawYCursorPosition = other->mRawYCursorPosition;
+ mDisplayOrientation = other->mDisplayOrientation;
mDisplayWidth = other->mDisplayWidth;
mDisplayHeight = other->mDisplayHeight;
mDownTime = other->mDownTime;
@@ -521,25 +540,48 @@ float MotionEvent::getHistoricalRawAxisValue(int32_t axis, size_t pointerIndex,
if (axis == AMOTION_EVENT_AXIS_X || axis == AMOTION_EVENT_AXIS_Y) {
// For compatibility, convert raw coordinates into "oriented screen space". Once app
// developers are educated about getRaw, we can consider removing this.
- const vec2 xy = rotatePoint(mTransform, coords->getX(), coords->getY(), mDisplayWidth,
- mDisplayHeight);
+ const vec2 xy = shouldDisregardWindowTranslation(mSource)
+ ? rotatePoint(mDisplayOrientation, coords->getX(), coords->getY())
+ : rotatePoint(mDisplayOrientation, coords->getX(), coords->getY(), mDisplayWidth,
+ mDisplayHeight);
static_assert(AMOTION_EVENT_AXIS_X == 0 && AMOTION_EVENT_AXIS_Y == 1);
return xy[axis];
}
+ if (axis == AMOTION_EVENT_AXIS_RELATIVE_X || axis == AMOTION_EVENT_AXIS_RELATIVE_Y) {
+ // For compatibility, since we convert raw coordinates into "oriented screen space", we
+ // need to convert the relative axes into the same orientation for consistency.
+ const vec2 relativeXy = rotatePoint(mDisplayOrientation,
+ coords->getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X),
+ coords->getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y));
+ return axis == AMOTION_EVENT_AXIS_RELATIVE_X ? relativeXy.x : relativeXy.y;
+ }
+
return coords->getAxisValue(axis);
}
float MotionEvent::getHistoricalAxisValue(int32_t axis, size_t pointerIndex,
- size_t historicalIndex) const {
+ size_t historicalIndex) const {
const PointerCoords* coords = getHistoricalRawPointerCoords(pointerIndex, historicalIndex);
if (axis == AMOTION_EVENT_AXIS_X || axis == AMOTION_EVENT_AXIS_Y) {
- const vec2 xy = mTransform.transform(coords->getXYValue());
+ const vec2 xy = shouldDisregardWindowTranslation(mSource)
+ ? applyTransformWithoutTranslation(mTransform, coords->getX(), coords->getY())
+ : mTransform.transform(coords->getXYValue());
static_assert(AMOTION_EVENT_AXIS_X == 0 && AMOTION_EVENT_AXIS_Y == 1);
return xy[axis];
}
+ if (axis == AMOTION_EVENT_AXIS_RELATIVE_X || axis == AMOTION_EVENT_AXIS_RELATIVE_Y) {
+ const vec2 relativeXy =
+ applyTransformWithoutTranslation(mTransform,
+ coords->getAxisValue(
+ AMOTION_EVENT_AXIS_RELATIVE_X),
+ coords->getAxisValue(
+ AMOTION_EVENT_AXIS_RELATIVE_Y));
+ return axis == AMOTION_EVENT_AXIS_RELATIVE_X ? relativeXy.x : relativeXy.y;
+ }
+
return coords->getAxisValue(axis);
}
@@ -595,6 +637,13 @@ void MotionEvent::applyTransform(const std::array<float, 9>& matrix) {
// Apply the transformation to all samples.
std::for_each(mSamplePointerCoords.begin(), mSamplePointerCoords.end(),
[&transform](PointerCoords& c) { c.transform(transform); });
+
+ if (mRawXCursorPosition != AMOTION_EVENT_INVALID_CURSOR_POSITION &&
+ mRawYCursorPosition != AMOTION_EVENT_INVALID_CURSOR_POSITION) {
+ const vec2 cursor = transform.transform(mRawXCursorPosition, mRawYCursorPosition);
+ mRawXCursorPosition = cursor.x;
+ mRawYCursorPosition = cursor.y;
+ }
}
#ifdef __linux__
@@ -655,6 +704,7 @@ status_t MotionEvent::readFromParcel(Parcel* parcel) {
mYPrecision = parcel->readFloat();
mRawXCursorPosition = parcel->readFloat();
mRawYCursorPosition = parcel->readFloat();
+ mDisplayOrientation = parcel->readUint32();
mDisplayWidth = parcel->readInt32();
mDisplayHeight = parcel->readInt32();
mDownTime = parcel->readInt64();
@@ -716,6 +766,7 @@ status_t MotionEvent::writeToParcel(Parcel* parcel) const {
parcel->writeFloat(mYPrecision);
parcel->writeFloat(mRawXCursorPosition);
parcel->writeFloat(mRawYCursorPosition);
+ parcel->writeUint32(mDisplayOrientation);
parcel->writeInt32(mDisplayWidth);
parcel->writeInt32(mDisplayHeight);
parcel->writeInt64(mDownTime);
diff --git a/libs/input/InputDevice.cpp b/libs/input/InputDevice.cpp
index fcbc16f9c7..1aec477081 100644
--- a/libs/input/InputDevice.cpp
+++ b/libs/input/InputDevice.cpp
@@ -21,9 +21,9 @@
#include <ctype.h>
#include <android-base/stringprintf.h>
+#include <ftl/NamedEnum.h>
#include <input/InputDevice.h>
#include <input/InputEventLabels.h>
-#include <input/NamedEnum.h>
using android::base::StringPrintf;
diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp
index dd1c46265c..ea8b9a7ec8 100644
--- a/libs/input/InputTransport.cpp
+++ b/libs/input/InputTransport.cpp
@@ -33,8 +33,8 @@ static constexpr bool DEBUG_TRANSPORT_ACTIONS = false;
#include <log/log.h>
#include <utils/Trace.h>
+#include <ftl/NamedEnum.h>
#include <input/InputTransport.h>
-#include <input/NamedEnum.h>
using android::base::StringPrintf;
@@ -242,9 +242,11 @@ void InputMessage::getSanitizedCopy(InputMessage* msg) const {
msg->body.motion.xCursorPosition = body.motion.xCursorPosition;
// float yCursorPosition
msg->body.motion.yCursorPosition = body.motion.yCursorPosition;
- // int32_t displayW
+ // uint32_t displayOrientation
+ msg->body.motion.displayOrientation = body.motion.displayOrientation;
+ // int32_t displayWidth
msg->body.motion.displayWidth = body.motion.displayWidth;
- // int32_t displayH
+ // int32_t displayHeight
msg->body.motion.displayHeight = body.motion.displayHeight;
// uint32_t pointerCount
msg->body.motion.pointerCount = body.motion.pointerCount;
@@ -533,9 +535,10 @@ status_t InputPublisher::publishMotionEvent(
std::array<uint8_t, 32> hmac, int32_t action, int32_t actionButton, int32_t flags,
int32_t edgeFlags, int32_t metaState, int32_t buttonState,
MotionClassification classification, const ui::Transform& transform, float xPrecision,
- float yPrecision, float xCursorPosition, float yCursorPosition, int32_t displayWidth,
- int32_t displayHeight, nsecs_t downTime, nsecs_t eventTime, uint32_t pointerCount,
- const PointerProperties* pointerProperties, const PointerCoords* pointerCoords) {
+ float yPrecision, float xCursorPosition, float yCursorPosition, uint32_t displayOrientation,
+ int32_t displayWidth, int32_t displayHeight, nsecs_t downTime, nsecs_t eventTime,
+ uint32_t pointerCount, const PointerProperties* pointerProperties,
+ const PointerCoords* pointerCoords) {
if (ATRACE_ENABLED()) {
std::string message = StringPrintf(
"publishMotionEvent(inputChannel=%s, action=%" PRId32 ")",
@@ -593,6 +596,7 @@ status_t InputPublisher::publishMotionEvent(
msg.body.motion.yPrecision = yPrecision;
msg.body.motion.xCursorPosition = xCursorPosition;
msg.body.motion.yCursorPosition = yCursorPosition;
+ msg.body.motion.displayOrientation = displayOrientation;
msg.body.motion.displayWidth = displayWidth;
msg.body.motion.displayHeight = displayHeight;
msg.body.motion.downTime = downTime;
@@ -1361,9 +1365,9 @@ void InputConsumer::initializeMotionEvent(MotionEvent* event, const InputMessage
msg->body.motion.buttonState, msg->body.motion.classification, transform,
msg->body.motion.xPrecision, msg->body.motion.yPrecision,
msg->body.motion.xCursorPosition, msg->body.motion.yCursorPosition,
- msg->body.motion.displayWidth, msg->body.motion.displayHeight,
- msg->body.motion.downTime, msg->body.motion.eventTime, pointerCount,
- pointerProperties, pointerCoords);
+ msg->body.motion.displayOrientation, msg->body.motion.displayWidth,
+ msg->body.motion.displayHeight, msg->body.motion.downTime,
+ msg->body.motion.eventTime, pointerCount, pointerProperties, pointerCoords);
}
void InputConsumer::addSample(MotionEvent* event, const InputMessage* msg) {
diff --git a/libs/input/KeyCharacterMap.cpp b/libs/input/KeyCharacterMap.cpp
index 44f3f34994..2039fa6553 100644
--- a/libs/input/KeyCharacterMap.cpp
+++ b/libs/input/KeyCharacterMap.cpp
@@ -28,10 +28,11 @@
#include <input/KeyCharacterMap.h>
#include <input/Keyboard.h>
-#include <utils/Log.h>
+#include <gui/constants.h>
#include <utils/Errors.h>
-#include <utils/Tokenizer.h>
+#include <utils/Log.h>
#include <utils/Timers.h>
+#include <utils/Tokenizer.h>
// Enables debug output for the parser.
#define DEBUG_PARSER 0
@@ -85,10 +86,13 @@ static String8 toString(const char16_t* chars, size_t numChars) {
// --- KeyCharacterMap ---
-KeyCharacterMap::KeyCharacterMap() : mType(KeyboardType::UNKNOWN) {}
+KeyCharacterMap::KeyCharacterMap(const std::string& filename)
+ : mType(KeyboardType::UNKNOWN), mLoadFileName(filename) {}
KeyCharacterMap::KeyCharacterMap(const KeyCharacterMap& other)
: mType(other.mType),
+ mLoadFileName(other.mLoadFileName),
+ mLayoutOverlayApplied(other.mLayoutOverlayApplied),
mKeysByScanCode(other.mKeysByScanCode),
mKeysByUsageCode(other.mKeysByUsageCode) {
for (size_t i = 0; i < other.mKeys.size(); i++) {
@@ -97,16 +101,19 @@ KeyCharacterMap::KeyCharacterMap(const KeyCharacterMap& other)
}
KeyCharacterMap::~KeyCharacterMap() {
- for (size_t i = 0; i < mKeys.size(); i++) {
- Key* key = mKeys.editValueAt(i);
- delete key;
- }
+ clear();
}
bool KeyCharacterMap::operator==(const KeyCharacterMap& other) const {
if (mType != other.mType) {
return false;
}
+ if (mLoadFileName != other.mLoadFileName) {
+ return false;
+ }
+ if (mLayoutOverlayApplied != other.mLayoutOverlayApplied) {
+ return false;
+ }
if (mKeys.size() != other.mKeys.size() ||
mKeysByScanCode.size() != other.mKeysByScanCode.size() ||
mKeysByUsageCode.size() != other.mKeysByUsageCode.size()) {
@@ -145,6 +152,10 @@ bool KeyCharacterMap::operator==(const KeyCharacterMap& other) const {
return true;
}
+bool KeyCharacterMap::operator!=(const KeyCharacterMap& other) const {
+ return !(*this == other);
+}
+
base::Result<std::shared_ptr<KeyCharacterMap>> KeyCharacterMap::load(const std::string& filename,
Format format) {
Tokenizer* tokenizer;
@@ -152,12 +163,18 @@ base::Result<std::shared_ptr<KeyCharacterMap>> KeyCharacterMap::load(const std::
if (status) {
return Errorf("Error {} opening key character map file {}.", status, filename.c_str());
}
+ std::shared_ptr<KeyCharacterMap> map =
+ std::shared_ptr<KeyCharacterMap>(new KeyCharacterMap(filename));
+ if (!map.get()) {
+ ALOGE("Error allocating key character map.");
+ return Errorf("Error allocating key character map.");
+ }
std::unique_ptr<Tokenizer> t(tokenizer);
- auto ret = load(t.get(), format);
- if (ret.ok()) {
- (*ret)->mLoadFileName = filename;
+ status = map->load(t.get(), format);
+ if (status == OK) {
+ return map;
}
- return ret;
+ return Errorf("Load KeyCharacterMap failed {}.", status);
}
base::Result<std::shared_ptr<KeyCharacterMap>> KeyCharacterMap::loadContents(
@@ -168,40 +185,67 @@ base::Result<std::shared_ptr<KeyCharacterMap>> KeyCharacterMap::loadContents(
ALOGE("Error %d opening key character map.", status);
return Errorf("Error {} opening key character map.", status);
}
+ std::shared_ptr<KeyCharacterMap> map =
+ std::shared_ptr<KeyCharacterMap>(new KeyCharacterMap(filename));
+ if (!map.get()) {
+ ALOGE("Error allocating key character map.");
+ return Errorf("Error allocating key character map.");
+ }
std::unique_ptr<Tokenizer> t(tokenizer);
- auto ret = load(t.get(), format);
- if (ret.ok()) {
- (*ret)->mLoadFileName = filename;
+ status = map->load(t.get(), format);
+ if (status == OK) {
+ return map;
}
- return ret;
+ return Errorf("Load KeyCharacterMap failed {}.", status);
}
-base::Result<std::shared_ptr<KeyCharacterMap>> KeyCharacterMap::load(Tokenizer* tokenizer,
- Format format) {
+status_t KeyCharacterMap::load(Tokenizer* tokenizer, Format format) {
status_t status = OK;
- std::shared_ptr<KeyCharacterMap> map = std::shared_ptr<KeyCharacterMap>(new KeyCharacterMap());
- if (!map.get()) {
- ALOGE("Error allocating key character map.");
- return Errorf("Error allocating key character map.");
- }
#if DEBUG_PARSER_PERFORMANCE
nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC);
#endif
- Parser parser(map.get(), tokenizer, format);
+ Parser parser(this, tokenizer, format);
status = parser.parse();
#if DEBUG_PARSER_PERFORMANCE
nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime;
ALOGD("Parsed key character map file '%s' %d lines in %0.3fms.",
tokenizer->getFilename().string(), tokenizer->getLineNumber(), elapsedTime / 1000000.0);
#endif
- if (status == OK) {
- return map;
+ if (status != OK) {
+ ALOGE("Loading KeyCharacterMap failed with status %s", statusToString(status).c_str());
}
+ return status;
+}
- return Errorf("Load KeyCharacterMap failed {}.", status);
+void KeyCharacterMap::clear() {
+ mKeysByScanCode.clear();
+ mKeysByUsageCode.clear();
+ for (size_t i = 0; i < mKeys.size(); i++) {
+ Key* key = mKeys.editValueAt(i);
+ delete key;
+ }
+ mKeys.clear();
+ mLayoutOverlayApplied = false;
+ mType = KeyboardType::UNKNOWN;
+}
+
+status_t KeyCharacterMap::reloadBaseFromFile() {
+ clear();
+ Tokenizer* tokenizer;
+ status_t status = Tokenizer::open(String8(mLoadFileName.c_str()), &tokenizer);
+ if (status) {
+ ALOGE("Error %s opening key character map file %s.", statusToString(status).c_str(),
+ mLoadFileName.c_str());
+ return status;
+ }
+ std::unique_ptr<Tokenizer> t(tokenizer);
+ return load(t.get(), KeyCharacterMap::Format::BASE);
}
void KeyCharacterMap::combine(const KeyCharacterMap& overlay) {
+ if (mLayoutOverlayApplied) {
+ reloadBaseFromFile();
+ }
for (size_t i = 0; i < overlay.mKeys.size(); i++) {
int32_t keyCode = overlay.mKeys.keyAt(i);
Key* key = overlay.mKeys.valueAt(i);
@@ -223,7 +267,7 @@ void KeyCharacterMap::combine(const KeyCharacterMap& overlay) {
mKeysByUsageCode.replaceValueFor(overlay.mKeysByUsageCode.keyAt(i),
overlay.mKeysByUsageCode.valueAt(i));
}
- mLoadFileName = overlay.mLoadFileName;
+ mLayoutOverlayApplied = true;
}
KeyCharacterMap::KeyboardType KeyCharacterMap::getKeyboardType() const {
@@ -635,8 +679,11 @@ std::shared_ptr<KeyCharacterMap> KeyCharacterMap::readFromParcel(Parcel* parcel)
ALOGE("%s: Null parcel", __func__);
return nullptr;
}
- std::shared_ptr<KeyCharacterMap> map = std::shared_ptr<KeyCharacterMap>(new KeyCharacterMap());
+ std::string loadFileName = parcel->readCString();
+ std::shared_ptr<KeyCharacterMap> map =
+ std::shared_ptr<KeyCharacterMap>(new KeyCharacterMap(loadFileName));
map->mType = static_cast<KeyCharacterMap::KeyboardType>(parcel->readInt32());
+ map->mLayoutOverlayApplied = parcel->readBool();
size_t numKeys = parcel->readInt32();
if (parcel->errorCheck()) {
return nullptr;
@@ -686,6 +733,30 @@ std::shared_ptr<KeyCharacterMap> KeyCharacterMap::readFromParcel(Parcel* parcel)
return nullptr;
}
}
+ size_t numKeysByScanCode = parcel->readInt32();
+ if (parcel->errorCheck()) {
+ return nullptr;
+ }
+ for (size_t i = 0; i < numKeysByScanCode; i++) {
+ int32_t key = parcel->readInt32();
+ int32_t value = parcel->readInt32();
+ map->mKeysByScanCode.add(key, value);
+ if (parcel->errorCheck()) {
+ return nullptr;
+ }
+ }
+ size_t numKeysByUsageCode = parcel->readInt32();
+ if (parcel->errorCheck()) {
+ return nullptr;
+ }
+ for (size_t i = 0; i < numKeysByUsageCode; i++) {
+ int32_t key = parcel->readInt32();
+ int32_t value = parcel->readInt32();
+ map->mKeysByUsageCode.add(key, value);
+ if (parcel->errorCheck()) {
+ return nullptr;
+ }
+ }
return map;
}
@@ -694,7 +765,9 @@ void KeyCharacterMap::writeToParcel(Parcel* parcel) const {
ALOGE("%s: Null parcel", __func__);
return;
}
+ parcel->writeCString(mLoadFileName.c_str());
parcel->writeInt32(static_cast<int32_t>(mType));
+ parcel->writeBool(mLayoutOverlayApplied);
size_t numKeys = mKeys.size();
parcel->writeInt32(numKeys);
@@ -714,6 +787,18 @@ void KeyCharacterMap::writeToParcel(Parcel* parcel) const {
}
parcel->writeInt32(0);
}
+ size_t numKeysByScanCode = mKeysByScanCode.size();
+ parcel->writeInt32(numKeysByScanCode);
+ for (size_t i = 0; i < numKeysByScanCode; i++) {
+ parcel->writeInt32(mKeysByScanCode.keyAt(i));
+ parcel->writeInt32(mKeysByScanCode.valueAt(i));
+ }
+ size_t numKeysByUsageCode = mKeysByUsageCode.size();
+ parcel->writeInt32(numKeysByUsageCode);
+ for (size_t i = 0; i < numKeysByUsageCode; i++) {
+ parcel->writeInt32(mKeysByUsageCode.keyAt(i));
+ parcel->writeInt32(mKeysByUsageCode.valueAt(i));
+ }
}
#endif // __linux__
diff --git a/libs/input/KeyLayoutMap.cpp b/libs/input/KeyLayoutMap.cpp
index fa5a5412e6..c365ab070e 100644
--- a/libs/input/KeyLayoutMap.cpp
+++ b/libs/input/KeyLayoutMap.cpp
@@ -19,10 +19,10 @@
#include <stdlib.h>
#include <android/keycodes.h>
+#include <ftl/NamedEnum.h>
#include <input/InputEventLabels.h>
#include <input/KeyLayoutMap.h>
#include <input/Keyboard.h>
-#include <input/NamedEnum.h>
#include <utils/Errors.h>
#include <utils/Log.h>
#include <utils/Timers.h>
diff --git a/libs/input/android/os/IInputFlinger.aidl b/libs/input/android/os/IInputFlinger.aidl
index 1771d192af..00ebd4d34f 100644
--- a/libs/input/android/os/IInputFlinger.aidl
+++ b/libs/input/android/os/IInputFlinger.aidl
@@ -16,20 +16,13 @@
package android.os;
-import android.FocusRequest;
import android.InputChannel;
-import android.InputWindowInfo;
-import android.os.ISetInputWindowsListener;
+import android.gui.FocusRequest;
+import android.gui.WindowInfo;
/** @hide */
interface IInputFlinger
{
- // SurfaceFlinger is the caller of this method, it uses the listener callback to ensure the
- // ordering when needed.
- // SurfaceFlinger calls this only every VSync, so overflow of binder's oneway buffer
- // shouldn't be a concern.
- oneway void setInputWindows(in InputWindowInfo[] inputHandles,
- in @nullable ISetInputWindowsListener setInputWindowsListener);
InputChannel createInputChannel(in @utf8InCpp String name);
void removeInputChannel(in IBinder connectionToken);
/**
diff --git a/libs/input/tests/Android.bp b/libs/input/tests/Android.bp
index 6ffc6a8926..6ffe8518b6 100644
--- a/libs/input/tests/Android.bp
+++ b/libs/input/tests/Android.bp
@@ -11,26 +11,24 @@ package {
cc_test {
name: "libinput_tests",
srcs: [
- "NamedEnum_test.cpp",
- "Flags_test.cpp",
"IdGenerator_test.cpp",
"InputChannel_test.cpp",
"InputDevice_test.cpp",
"InputEvent_test.cpp",
"InputPublisherAndConsumer_test.cpp",
- "InputWindow_test.cpp",
"TouchVideoFrame_test.cpp",
"VelocityTracker_test.cpp",
"VerifiedInputEvent_test.cpp",
],
+ static_libs: [
+ "libgui_window_info_static",
+ "libinput",
+ ],
cflags: [
"-Wall",
"-Wextra",
"-Werror",
],
- static_libs: [
- "libinput",
- ],
shared_libs: [
"libbase",
"libbinder",
@@ -39,6 +37,7 @@ cc_test {
"libui",
"libutils",
],
+ data: ["data/*.kcm"],
test_suites: ["device-tests"],
}
@@ -61,5 +60,5 @@ cc_library_static {
"libbinder",
"libui",
"libbase",
- ]
+ ],
}
diff --git a/libs/input/tests/InputDevice_test.cpp b/libs/input/tests/InputDevice_test.cpp
index f8f2f4e931..61e88df11d 100644
--- a/libs/input/tests/InputDevice_test.cpp
+++ b/libs/input/tests/InputDevice_test.cpp
@@ -20,6 +20,7 @@
#include <input/InputDevice.h>
#include <input/KeyLayoutMap.h>
#include <input/Keyboard.h>
+#include "android-base/file.h"
namespace android {
@@ -82,4 +83,53 @@ TEST_F(InputDeviceKeyMapTest, keyCharacterMapParcelingTest) {
ASSERT_EQ(*map, *mKeyMap.keyCharacterMap);
}
+TEST_F(InputDeviceKeyMapTest, keyCharacterMapWithOverlayParcelingTest) {
+ Parcel parcel;
+ std::string overlayPath = base::GetExecutableDirectory() + "/data/german.kcm";
+ base::Result<std::shared_ptr<KeyCharacterMap>> overlay =
+ KeyCharacterMap::load(overlayPath, KeyCharacterMap::Format::OVERLAY);
+ ASSERT_TRUE(overlay.ok()) << "Cannot load KeyCharacterMap at " << overlayPath;
+ mKeyMap.keyCharacterMap->combine(*overlay->get());
+ mKeyMap.keyCharacterMap->writeToParcel(&parcel);
+ parcel.setDataPosition(0);
+ std::shared_ptr<KeyCharacterMap> map = KeyCharacterMap::readFromParcel(&parcel);
+ ASSERT_EQ(*map, *mKeyMap.keyCharacterMap);
+}
+
+TEST_F(InputDeviceKeyMapTest, keyCharacteMapApplyMultipleOverlaysTest) {
+ std::string frenchOverlayPath = base::GetExecutableDirectory() + "/data/french.kcm";
+ std::string englishOverlayPath = base::GetExecutableDirectory() + "/data/english_us.kcm";
+ std::string germanOverlayPath = base::GetExecutableDirectory() + "/data/german.kcm";
+ base::Result<std::shared_ptr<KeyCharacterMap>> frenchOverlay =
+ KeyCharacterMap::load(frenchOverlayPath, KeyCharacterMap::Format::OVERLAY);
+ ASSERT_TRUE(frenchOverlay.ok()) << "Cannot load KeyCharacterMap at " << frenchOverlayPath;
+ base::Result<std::shared_ptr<KeyCharacterMap>> englishOverlay =
+ KeyCharacterMap::load(englishOverlayPath, KeyCharacterMap::Format::OVERLAY);
+ ASSERT_TRUE(englishOverlay.ok()) << "Cannot load KeyCharacterMap at " << englishOverlayPath;
+ base::Result<std::shared_ptr<KeyCharacterMap>> germanOverlay =
+ KeyCharacterMap::load(germanOverlayPath, KeyCharacterMap::Format::OVERLAY);
+ ASSERT_TRUE(germanOverlay.ok()) << "Cannot load KeyCharacterMap at " << germanOverlayPath;
+
+ // Apply the French overlay
+ mKeyMap.keyCharacterMap->combine(*frenchOverlay->get());
+ // Copy the result for later
+ std::shared_ptr<KeyCharacterMap> frenchOverlaidKeyCharacterMap =
+ std::make_shared<KeyCharacterMap>(*mKeyMap.keyCharacterMap);
+
+ // Apply the English overlay
+ mKeyMap.keyCharacterMap->combine(*englishOverlay->get());
+ // Verify that the result is different from the French overlay result
+ ASSERT_NE(*mKeyMap.keyCharacterMap, *frenchOverlaidKeyCharacterMap);
+
+ // Apply the German overlay
+ mKeyMap.keyCharacterMap->combine(*germanOverlay->get());
+ // Verify that the result is different from the French overlay result
+ ASSERT_NE(*mKeyMap.keyCharacterMap, *frenchOverlaidKeyCharacterMap);
+
+ // Apply the French overlay
+ mKeyMap.keyCharacterMap->combine(*frenchOverlay->get());
+ // Verify that the result is the same like after applying it initially
+ ASSERT_EQ(*mKeyMap.keyCharacterMap, *frenchOverlaidKeyCharacterMap);
+}
+
} // namespace android
diff --git a/libs/input/tests/InputEvent_test.cpp b/libs/input/tests/InputEvent_test.cpp
index 3b76ddbb7c..b1ef7534e4 100644
--- a/libs/input/tests/InputEvent_test.cpp
+++ b/libs/input/tests/InputEvent_test.cpp
@@ -21,6 +21,7 @@
#include <attestation/HmacKeyManager.h>
#include <binder/Parcel.h>
#include <gtest/gtest.h>
+#include <gui/constants.h>
#include <input/Input.h>
namespace android {
@@ -293,7 +294,7 @@ void MotionEventTest::initializeEventWithHistory(MotionEvent* event) {
AMOTION_EVENT_EDGE_FLAG_TOP, AMETA_ALT_ON, AMOTION_EVENT_BUTTON_PRIMARY,
MotionClassification::NONE, mTransform, 2.0f, 2.1f,
AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION,
- AMOTION_EVENT_INVALID_DISPLAY_SIZE, AMOTION_EVENT_INVALID_DISPLAY_SIZE,
+ ui::Transform::ROT_0, INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE,
ARBITRARY_DOWN_TIME, ARBITRARY_EVENT_TIME, 2, pointerProperties,
pointerCoords);
@@ -610,12 +611,12 @@ TEST_F(MotionEventTest, Transform) {
}
MotionEvent event;
ui::Transform identityTransform;
- event.initialize(InputEvent::nextId(), 0 /*deviceId*/, AINPUT_SOURCE_UNKNOWN, DISPLAY_ID,
+ event.initialize(InputEvent::nextId(), 0 /*deviceId*/, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID,
INVALID_HMAC, AMOTION_EVENT_ACTION_MOVE, 0 /*actionButton*/, 0 /*flags*/,
AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0 /*buttonState*/,
MotionClassification::NONE, identityTransform, 0 /*xPrecision*/,
0 /*yPrecision*/, 3 + RADIUS /*xCursorPosition*/, 2 /*yCursorPosition*/,
- AMOTION_EVENT_INVALID_DISPLAY_SIZE, AMOTION_EVENT_INVALID_DISPLAY_SIZE,
+ ui::Transform::ROT_0, INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE,
0 /*downTime*/, 0 /*eventTime*/, pointerCount, pointerProperties,
pointerCoords);
float originalRawX = 0 + 3;
@@ -658,13 +659,17 @@ TEST_F(MotionEventTest, Transform) {
ASSERT_NEAR(originalRawY, event.getRawY(0), 0.001);
}
-MotionEvent createTouchDownEvent(int x, int y, ui::Transform transform) {
+MotionEvent createTouchDownEvent(float x, float y, float dx, float dy,
+ const ui::Transform& transform,
+ uint32_t displayOrientation = ui::Transform::ROT_0) {
std::vector<PointerProperties> pointerProperties;
pointerProperties.push_back(PointerProperties{/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER});
std::vector<PointerCoords> pointerCoords;
pointerCoords.emplace_back().clear();
pointerCoords.back().setAxisValue(AMOTION_EVENT_AXIS_X, x);
pointerCoords.back().setAxisValue(AMOTION_EVENT_AXIS_Y, y);
+ pointerCoords.back().setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, dx);
+ pointerCoords.back().setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, dy);
nsecs_t eventTime = systemTime(SYSTEM_TIME_MONOTONIC);
MotionEvent event;
event.initialize(InputEvent::nextId(), /* deviceId */ 1, AINPUT_SOURCE_TOUCHSCREEN,
@@ -672,7 +677,8 @@ MotionEvent createTouchDownEvent(int x, int y, ui::Transform transform) {
/* actionButton */ 0, /* flags */ 0, /* edgeFlags */ 0, AMETA_NONE,
/* buttonState */ 0, MotionClassification::NONE, transform,
/* xPrecision */ 0, /* yPrecision */ 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
- AMOTION_EVENT_INVALID_CURSOR_POSITION, /* displayWidth */ 400,
+ AMOTION_EVENT_INVALID_CURSOR_POSITION, displayOrientation,
+ /* displayWidth */ 400,
/* displayHeight */ 800, eventTime, eventTime, pointerCoords.size(),
pointerProperties.data(), pointerCoords.data());
return event;
@@ -683,26 +689,56 @@ TEST_F(MotionEventTest, ApplyTransform) {
ui::Transform identity;
ui::Transform xform(ui::Transform::ROT_90, 800, 400);
xform.set(xform.tx() + 20, xform.ty() + 40);
- MotionEvent event = createTouchDownEvent(60, 100, xform);
+ MotionEvent event = createTouchDownEvent(60, 100, 42, 96, xform, ui::Transform::ROT_90);
ASSERT_EQ(700, event.getRawX(0));
ASSERT_EQ(60, event.getRawY(0));
ASSERT_NE(event.getRawX(0), event.getX(0));
ASSERT_NE(event.getRawY(0), event.getY(0));
+ // Relative values should be rotated but not translated.
+ ASSERT_EQ(-96, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0));
+ ASSERT_EQ(42, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0));
- MotionEvent changedEvent = createTouchDownEvent(60, 100, identity);
+ MotionEvent changedEvent = createTouchDownEvent(60, 100, 42, 96, identity);
const std::array<float, 9> rowMajor{xform[0][0], xform[1][0], xform[2][0],
xform[0][1], xform[1][1], xform[2][1],
xform[0][2], xform[1][2], xform[2][2]};
changedEvent.applyTransform(rowMajor);
// transformContent effectively rotates the raw coordinates, so those should now include
- // both rotation AND offset
+ // both rotation AND offset.
ASSERT_EQ(720, changedEvent.getRawX(0));
ASSERT_EQ(100, changedEvent.getRawY(0));
+ // Relative values should be rotated but not translated.
+ ASSERT_EQ(-96, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0));
+ ASSERT_EQ(42, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0));
- // The transformed output should be the same then
+ // The transformed output should be the same then.
ASSERT_NEAR(event.getX(0), changedEvent.getX(0), 0.001);
ASSERT_NEAR(event.getY(0), changedEvent.getY(0), 0.001);
+ ASSERT_NEAR(event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0),
+ changedEvent.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0), 0.001);
+ ASSERT_NEAR(event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0),
+ changedEvent.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0), 0.001);
+}
+
+TEST_F(MotionEventTest, NonPointerSourcesAreNotTranslated) {
+ constexpr static auto NON_POINTER_SOURCES = {AINPUT_SOURCE_TRACKBALL,
+ AINPUT_SOURCE_MOUSE_RELATIVE,
+ AINPUT_SOURCE_JOYSTICK};
+ for (uint32_t source : NON_POINTER_SOURCES) {
+ // Create a rotate-90 transform with an offset (like a window which isn't fullscreen).
+ ui::Transform xform(ui::Transform::ROT_90, 800, 400);
+ xform.set(xform.tx() + 20, xform.ty() + 40);
+ MotionEvent event = createTouchDownEvent(60, 100, 42, 96, xform, ui::Transform::ROT_90);
+ event.setSource(source);
+
+ // Since this event comes from a non-pointer source, it should include rotation but not
+ // translation/offset.
+ ASSERT_EQ(-100, event.getX(0));
+ ASSERT_EQ(60, event.getY(0));
+ ASSERT_EQ(event.getRawX(0), event.getX(0));
+ ASSERT_EQ(event.getRawY(0), event.getY(0));
+ }
}
TEST_F(MotionEventTest, RawCompatTransform) {
@@ -710,11 +746,14 @@ TEST_F(MotionEventTest, RawCompatTransform) {
// Make sure raw is raw regardless of transform translation.
ui::Transform xform;
xform.set(20, 40);
- MotionEvent event = createTouchDownEvent(60, 100, xform);
+ MotionEvent event = createTouchDownEvent(60, 100, 42, 96, xform);
ASSERT_EQ(60, event.getRawX(0));
ASSERT_EQ(100, event.getRawY(0));
ASSERT_NE(event.getRawX(0), event.getX(0));
ASSERT_NE(event.getRawY(0), event.getY(0));
+ // Relative values should not be modified.
+ ASSERT_EQ(42, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0));
+ ASSERT_EQ(96, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0));
}
// Next check that getRaw contains rotation (for compatibility) but otherwise is still
@@ -723,29 +762,50 @@ TEST_F(MotionEventTest, RawCompatTransform) {
// Create a rotate-90 transform with an offset (like a window which isn't fullscreen).
ui::Transform xform(ui::Transform::ROT_90, 800, 400);
xform.set(xform.tx() + 20, xform.ty() + 40);
- MotionEvent event = createTouchDownEvent(60, 100, xform);
+ MotionEvent event = createTouchDownEvent(60, 100, 42, 96, xform, ui::Transform::ROT_90);
ASSERT_EQ(700, event.getRawX(0));
ASSERT_EQ(60, event.getRawY(0));
ASSERT_NE(event.getRawX(0), event.getX(0));
ASSERT_NE(event.getRawY(0), event.getY(0));
+ // Relative values should be rotated but not translated.
+ ASSERT_EQ(-96, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0));
+ ASSERT_EQ(42, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0));
}
{
// Same as above, but check rotate-180.
ui::Transform xform(ui::Transform::ROT_180, 400, 800);
xform.set(xform.tx() + 20, xform.ty() + 40);
- MotionEvent event = createTouchDownEvent(60, 100, xform);
+ MotionEvent event = createTouchDownEvent(60, 100, 42, 96, xform, ui::Transform::ROT_180);
ASSERT_EQ(340, event.getRawX(0));
ASSERT_EQ(700, event.getRawY(0));
+ // Relative values should be rotated but not translated.
+ ASSERT_EQ(-42, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0));
+ ASSERT_EQ(-96, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0));
}
{
// Same as above, but check rotate-270.
ui::Transform xform(ui::Transform::ROT_270, 800, 400);
xform.set(xform.tx() + 20, xform.ty() + 40);
- MotionEvent event = createTouchDownEvent(60, 100, xform);
+ MotionEvent event = createTouchDownEvent(60, 100, 42, 96, xform, ui::Transform::ROT_270);
ASSERT_EQ(100, event.getRawX(0));
ASSERT_EQ(340, event.getRawY(0));
+ // Relative values should be rotated but not translated.
+ ASSERT_EQ(96, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0));
+ ASSERT_EQ(-42, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0));
+ }
+
+ {
+ // Finally, check that raw isn't effected by transform
+ ui::Transform xform(ui::Transform::ROT_270, 800, 400);
+ xform.set(xform.tx() + 20, xform.ty() + 40);
+ MotionEvent event = createTouchDownEvent(60, 100, 42, 96, xform, ui::Transform::ROT_90);
+ ASSERT_EQ(700, event.getRawX(0));
+ ASSERT_EQ(60, event.getRawY(0));
+ // Relative values should be rotated but not translated.
+ ASSERT_EQ(96, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0));
+ ASSERT_EQ(-42, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0));
}
}
@@ -772,9 +832,9 @@ TEST_F(MotionEventTest, Initialize_SetsClassification) {
DISPLAY_ID, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0, 0,
AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0, classification,
identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
- AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_DISPLAY_SIZE,
- AMOTION_EVENT_INVALID_DISPLAY_SIZE, 0 /*downTime*/, 0 /*eventTime*/,
- pointerCount, pointerProperties, pointerCoords);
+ AMOTION_EVENT_INVALID_CURSOR_POSITION, ui::Transform::ROT_0,
+ INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, 0 /*downTime*/,
+ 0 /*eventTime*/, pointerCount, pointerProperties, pointerCoords);
ASSERT_EQ(classification, event.getClassification());
}
}
@@ -794,10 +854,9 @@ TEST_F(MotionEventTest, Initialize_SetsCursorPosition) {
event.initialize(InputEvent::nextId(), 0 /*deviceId*/, AINPUT_SOURCE_MOUSE, DISPLAY_ID,
INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0, 0, AMOTION_EVENT_EDGE_FLAG_NONE,
AMETA_NONE, 0, MotionClassification::NONE, identityTransform, 0, 0,
- 280 /*xCursorPosition*/, 540 /*yCursorPosition*/,
- AMOTION_EVENT_INVALID_DISPLAY_SIZE, AMOTION_EVENT_INVALID_DISPLAY_SIZE,
- 0 /*downTime*/, 0 /*eventTime*/, pointerCount, pointerProperties,
- pointerCoords);
+ 280 /*xCursorPosition*/, 540 /*yCursorPosition*/, ui::Transform::ROT_0,
+ INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, 0 /*downTime*/, 0 /*eventTime*/,
+ pointerCount, pointerProperties, pointerCoords);
event.offsetLocation(20, 60);
ASSERT_EQ(280, event.getRawXCursorPosition());
ASSERT_EQ(540, event.getRawYCursorPosition());
diff --git a/libs/input/tests/InputPublisherAndConsumer_test.cpp b/libs/input/tests/InputPublisherAndConsumer_test.cpp
index a2cfaa1cc0..5d1f2c3bfc 100644
--- a/libs/input/tests/InputPublisherAndConsumer_test.cpp
+++ b/libs/input/tests/InputPublisherAndConsumer_test.cpp
@@ -23,6 +23,7 @@
#include <attestation/HmacKeyManager.h>
#include <cutils/ashmem.h>
#include <gtest/gtest.h>
+#include <gui/constants.h>
#include <input/InputTransport.h>
#include <utils/StopWatch.h>
#include <utils/Timers.h>
@@ -162,6 +163,7 @@ void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent() {
constexpr float yPrecision = 0.5;
constexpr float xCursorPosition = 1.3;
constexpr float yCursorPosition = 50.6;
+ constexpr uint32_t displayOrientation = ui::Transform::ROT_0;
constexpr int32_t displayWidth = 1000;
constexpr int32_t displayHeight = 2000;
constexpr nsecs_t downTime = 3;
@@ -192,9 +194,9 @@ void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent() {
status = mPublisher->publishMotionEvent(seq, eventId, deviceId, source, displayId, hmac, action,
actionButton, flags, edgeFlags, metaState, buttonState,
classification, transform, xPrecision, yPrecision,
- xCursorPosition, yCursorPosition, displayWidth,
- displayHeight, downTime, eventTime, pointerCount,
- pointerProperties, pointerCoords);
+ xCursorPosition, yCursorPosition, displayOrientation,
+ displayWidth, displayHeight, downTime, eventTime,
+ pointerCount, pointerProperties, pointerCoords);
ASSERT_EQ(OK, status)
<< "publisher publishMotionEvent should return OK";
@@ -231,6 +233,7 @@ void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent() {
EXPECT_EQ(yCursorPosition, motionEvent->getRawYCursorPosition());
EXPECT_EQ(xCursorPosition * xScale + xOffset, motionEvent->getXCursorPosition());
EXPECT_EQ(yCursorPosition * yScale + yOffset, motionEvent->getYCursorPosition());
+ EXPECT_EQ(displayOrientation, motionEvent->getDisplayOrientation());
EXPECT_EQ(displayWidth, motionEvent->getDisplaySize().x);
EXPECT_EQ(displayHeight, motionEvent->getDisplaySize().y);
EXPECT_EQ(downTime, motionEvent->getDownTime());
@@ -460,8 +463,9 @@ TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenSequenceNumberIsZer
status = mPublisher->publishMotionEvent(0, InputEvent::nextId(), 0, 0, 0, INVALID_HMAC, 0, 0, 0,
0, 0, 0, MotionClassification::NONE, identityTransform,
0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
- AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, 0, 0, 0,
- pointerCount, pointerProperties, pointerCoords);
+ AMOTION_EVENT_INVALID_CURSOR_POSITION,
+ ui::Transform::ROT_0, 0, 0, 0, 0, pointerCount,
+ pointerProperties, pointerCoords);
ASSERT_EQ(BAD_VALUE, status)
<< "publisher publishMotionEvent should return BAD_VALUE";
}
@@ -476,8 +480,9 @@ TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenPointerCountLessTha
status = mPublisher->publishMotionEvent(1, InputEvent::nextId(), 0, 0, 0, INVALID_HMAC, 0, 0, 0,
0, 0, 0, MotionClassification::NONE, identityTransform,
0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
- AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, 0, 0, 0,
- pointerCount, pointerProperties, pointerCoords);
+ AMOTION_EVENT_INVALID_CURSOR_POSITION,
+ ui::Transform::ROT_0, 0, 0, 0, 0, pointerCount,
+ pointerProperties, pointerCoords);
ASSERT_EQ(BAD_VALUE, status)
<< "publisher publishMotionEvent should return BAD_VALUE";
}
@@ -497,8 +502,9 @@ TEST_F(InputPublisherAndConsumerTest,
status = mPublisher->publishMotionEvent(1, InputEvent::nextId(), 0, 0, 0, INVALID_HMAC, 0, 0, 0,
0, 0, 0, MotionClassification::NONE, identityTransform,
0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
- AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, 0, 0, 0,
- pointerCount, pointerProperties, pointerCoords);
+ AMOTION_EVENT_INVALID_CURSOR_POSITION,
+ ui::Transform::ROT_0, 0, 0, 0, 0, pointerCount,
+ pointerProperties, pointerCoords);
ASSERT_EQ(BAD_VALUE, status)
<< "publisher publishMotionEvent should return BAD_VALUE";
}
diff --git a/libs/input/tests/StructLayout_test.cpp b/libs/input/tests/StructLayout_test.cpp
index 5861d55156..59fed1fb41 100644
--- a/libs/input/tests/StructLayout_test.cpp
+++ b/libs/input/tests/StructLayout_test.cpp
@@ -74,10 +74,10 @@ void TestInputMessageAlignment() {
CHECK_OFFSET(InputMessage::Body::Motion, yPrecision, 124);
CHECK_OFFSET(InputMessage::Body::Motion, xCursorPosition, 128);
CHECK_OFFSET(InputMessage::Body::Motion, yCursorPosition, 132);
- CHECK_OFFSET(InputMessage::Body::Motion, displayWidth, 136);
- CHECK_OFFSET(InputMessage::Body::Motion, displayHeight, 140);
- CHECK_OFFSET(InputMessage::Body::Motion, pointerCount, 144);
- CHECK_OFFSET(InputMessage::Body::Motion, empty3, 148);
+ CHECK_OFFSET(InputMessage::Body::Motion, displayOrientation, 136);
+ CHECK_OFFSET(InputMessage::Body::Motion, displayWidth, 140);
+ CHECK_OFFSET(InputMessage::Body::Motion, displayHeight, 144);
+ CHECK_OFFSET(InputMessage::Body::Motion, pointerCount, 148);
CHECK_OFFSET(InputMessage::Body::Motion, pointers, 152);
CHECK_OFFSET(InputMessage::Body::Focus, eventId, 0);
diff --git a/libs/input/tests/VelocityTracker_test.cpp b/libs/input/tests/VelocityTracker_test.cpp
index aefc2ec47d..13e2b02ca4 100644
--- a/libs/input/tests/VelocityTracker_test.cpp
+++ b/libs/input/tests/VelocityTracker_test.cpp
@@ -23,6 +23,7 @@
#include <android-base/stringprintf.h>
#include <attestation/HmacKeyManager.h>
#include <gtest/gtest.h>
+#include <gui/constants.h>
#include <input/VelocityTracker.h>
using namespace std::chrono_literals;
@@ -183,8 +184,8 @@ static std::vector<MotionEvent> createMotionEventStream(
AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0 /*buttonState*/,
MotionClassification::NONE, identityTransform, 0 /*xPrecision*/,
0 /*yPrecision*/, AMOTION_EVENT_INVALID_CURSOR_POSITION,
- AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_DISPLAY_SIZE,
- AMOTION_EVENT_INVALID_DISPLAY_SIZE, 0 /*downTime*/,
+ AMOTION_EVENT_INVALID_CURSOR_POSITION, ui::Transform::ROT_0,
+ INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, 0 /*downTime*/,
entry.eventTime.count(), pointerCount, properties, coords);
events.emplace_back(event);
diff --git a/libs/input/tests/VerifiedInputEvent_test.cpp b/libs/input/tests/VerifiedInputEvent_test.cpp
index f79098c63c..b29c9a4877 100644
--- a/libs/input/tests/VerifiedInputEvent_test.cpp
+++ b/libs/input/tests/VerifiedInputEvent_test.cpp
@@ -16,6 +16,7 @@
#include <attestation/HmacKeyManager.h>
#include <gtest/gtest.h>
+#include <gui/constants.h>
#include <input/Input.h>
namespace android {
@@ -46,10 +47,9 @@ static MotionEvent getMotionEventWithFlags(int32_t flags) {
INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0 /*actionButton*/, flags,
AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0 /*buttonState*/,
MotionClassification::NONE, transform, 0.1 /*xPrecision*/, 0.2 /*yPrecision*/,
- 280 /*xCursorPosition*/, 540 /*yCursorPosition*/,
- AMOTION_EVENT_INVALID_DISPLAY_SIZE, AMOTION_EVENT_INVALID_DISPLAY_SIZE,
- 100 /*downTime*/, 200 /*eventTime*/, pointerCount, pointerProperties,
- pointerCoords);
+ 280 /*xCursorPosition*/, 540 /*yCursorPosition*/, ui::Transform::ROT_0,
+ INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, 100 /*downTime*/,
+ 200 /*eventTime*/, pointerCount, pointerProperties, pointerCoords);
return event;
}
diff --git a/libs/input/tests/data/english_us.kcm b/libs/input/tests/data/english_us.kcm
new file mode 100644
index 0000000000..d0ef027f85
--- /dev/null
+++ b/libs/input/tests/data/english_us.kcm
@@ -0,0 +1,311 @@
+# 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.
+
+#
+# English (US) keyboard layout.
+# Unlike the default (generic) keyboard layout, English (US) does not contain any
+# special ALT characters.
+#
+
+type OVERLAY
+
+### ROW 1
+
+key GRAVE {
+ label: '`'
+ base: '`'
+ shift: '~'
+}
+
+key 1 {
+ label: '1'
+ base: '1'
+ shift: '!'
+}
+
+key 2 {
+ label: '2'
+ base: '2'
+ shift: '@'
+}
+
+key 3 {
+ label: '3'
+ base: '3'
+ shift: '#'
+}
+
+key 4 {
+ label: '4'
+ base: '4'
+ shift: '$'
+}
+
+key 5 {
+ label: '5'
+ base: '5'
+ shift: '%'
+}
+
+key 6 {
+ label: '6'
+ base: '6'
+ shift: '^'
+}
+
+key 7 {
+ label: '7'
+ base: '7'
+ shift: '&'
+}
+
+key 8 {
+ label: '8'
+ base: '8'
+ shift: '*'
+}
+
+key 9 {
+ label: '9'
+ base: '9'
+ shift: '('
+}
+
+key 0 {
+ label: '0'
+ base: '0'
+ shift: ')'
+}
+
+key MINUS {
+ label: '-'
+ base: '-'
+ shift: '_'
+}
+
+key EQUALS {
+ label: '='
+ base: '='
+ shift: '+'
+}
+
+### ROW 2
+
+key Q {
+ label: 'Q'
+ base: 'q'
+ shift, capslock: 'Q'
+}
+
+key W {
+ label: 'W'
+ base: 'w'
+ shift, capslock: 'W'
+}
+
+key E {
+ label: 'E'
+ base: 'e'
+ shift, capslock: 'E'
+}
+
+key R {
+ label: 'R'
+ base: 'r'
+ shift, capslock: 'R'
+}
+
+key T {
+ label: 'T'
+ base: 't'
+ shift, capslock: 'T'
+}
+
+key Y {
+ label: 'Y'
+ base: 'y'
+ shift, capslock: 'Y'
+}
+
+key U {
+ label: 'U'
+ base: 'u'
+ shift, capslock: 'U'
+}
+
+key I {
+ label: 'I'
+ base: 'i'
+ shift, capslock: 'I'
+}
+
+key O {
+ label: 'O'
+ base: 'o'
+ shift, capslock: 'O'
+}
+
+key P {
+ label: 'P'
+ base: 'p'
+ shift, capslock: 'P'
+}
+
+key LEFT_BRACKET {
+ label: '['
+ base: '['
+ shift: '{'
+}
+
+key RIGHT_BRACKET {
+ label: ']'
+ base: ']'
+ shift: '}'
+}
+
+key BACKSLASH {
+ label: '\\'
+ base: '\\'
+ shift: '|'
+}
+
+### ROW 3
+
+key A {
+ label: 'A'
+ base: 'a'
+ shift, capslock: 'A'
+}
+
+key S {
+ label: 'S'
+ base: 's'
+ shift, capslock: 'S'
+}
+
+key D {
+ label: 'D'
+ base: 'd'
+ shift, capslock: 'D'
+}
+
+key F {
+ label: 'F'
+ base: 'f'
+ shift, capslock: 'F'
+}
+
+key G {
+ label: 'G'
+ base: 'g'
+ shift, capslock: 'G'
+}
+
+key H {
+ label: 'H'
+ base: 'h'
+ shift, capslock: 'H'
+}
+
+key J {
+ label: 'J'
+ base: 'j'
+ shift, capslock: 'J'
+}
+
+key K {
+ label: 'K'
+ base: 'k'
+ shift, capslock: 'K'
+}
+
+key L {
+ label: 'L'
+ base: 'l'
+ shift, capslock: 'L'
+}
+
+key SEMICOLON {
+ label: ';'
+ base: ';'
+ shift: ':'
+}
+
+key APOSTROPHE {
+ label: '\''
+ base: '\''
+ shift: '"'
+}
+
+### ROW 4
+
+key Z {
+ label: 'Z'
+ base: 'z'
+ shift, capslock: 'Z'
+}
+
+key X {
+ label: 'X'
+ base: 'x'
+ shift, capslock: 'X'
+}
+
+key C {
+ label: 'C'
+ base: 'c'
+ shift, capslock: 'C'
+}
+
+key V {
+ label: 'V'
+ base: 'v'
+ shift, capslock: 'V'
+}
+
+key B {
+ label: 'B'
+ base: 'b'
+ shift, capslock: 'B'
+}
+
+key N {
+ label: 'N'
+ base: 'n'
+ shift, capslock: 'N'
+}
+
+key M {
+ label: 'M'
+ base: 'm'
+ shift, capslock: 'M'
+}
+
+key COMMA {
+ label: ','
+ base: ','
+ shift: '<'
+}
+
+key PERIOD {
+ label: '.'
+ base: '.'
+ shift: '>'
+}
+
+key SLASH {
+ label: '/'
+ base: '/'
+ shift: '?'
+} \ No newline at end of file
diff --git a/libs/input/tests/data/french.kcm b/libs/input/tests/data/french.kcm
new file mode 100644
index 0000000000..db69ea0430
--- /dev/null
+++ b/libs/input/tests/data/french.kcm
@@ -0,0 +1,336 @@
+# 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.
+
+#
+# French keyboard layout, AZERTY style.
+#
+
+type OVERLAY
+
+map key 16 A
+map key 17 Z
+map key 30 Q
+map key 39 M
+map key 44 W
+map key 50 COMMA
+map key 51 SEMICOLON
+map key 86 PLUS
+
+### ROW 1
+
+key GRAVE {
+ label: '\u00b2'
+ base: '\u00b2'
+}
+
+key 1 {
+ label: '1'
+ base: '&'
+ shift: '1'
+}
+
+key 2 {
+ label: '2'
+ base: '\u00e9'
+ shift: '2'
+ ralt: '~'
+}
+
+key 3 {
+ label: '3'
+ base: '"'
+ shift: '3'
+ ralt: '#'
+}
+
+key 4 {
+ label: '4'
+ base: '\''
+ shift: '4'
+ ralt: '{'
+}
+
+key 5 {
+ label: '5'
+ base: '('
+ shift: '5'
+ ralt: '['
+}
+
+key 6 {
+ label: '6'
+ base: '-'
+ shift: '6'
+ ralt: '|'
+}
+
+key 7 {
+ label: '7'
+ base: '\u00e8'
+ shift: '7'
+ ralt: '`'
+}
+
+key 8 {
+ label: '8'
+ base: '_'
+ shift: '8'
+ ralt: '\\'
+}
+
+key 9 {
+ label: '9'
+ base: '\u00e7'
+ shift: '9'
+ ralt: '^'
+}
+
+key 0 {
+ label: '0'
+ base: '\u00e0'
+ shift: '0'
+ ralt: '@'
+}
+
+key MINUS {
+ label: ')'
+ base: ')'
+ shift: '\u00b0'
+ ralt: ']'
+}
+
+key EQUALS {
+ label: '='
+ base: '='
+ shift: '+'
+ ralt: '}'
+}
+
+### ROW 2
+
+key A {
+ label: 'A'
+ base: 'a'
+ shift, capslock: 'A'
+}
+
+key Z {
+ label: 'Z'
+ base: 'z'
+ shift, capslock: 'Z'
+}
+
+key E {
+ label: 'E'
+ base: 'e'
+ shift, capslock: 'E'
+ ralt: '\u20ac'
+}
+
+key R {
+ label: 'R'
+ base: 'r'
+ shift, capslock: 'R'
+}
+
+key T {
+ label: 'T'
+ base: 't'
+ shift, capslock: 'T'
+}
+
+key Y {
+ label: 'Y'
+ base: 'y'
+ shift, capslock: 'Y'
+}
+
+key U {
+ label: 'U'
+ base: 'u'
+ shift, capslock: 'U'
+}
+
+key I {
+ label: 'I'
+ base: 'i'
+ shift, capslock: 'I'
+}
+
+key O {
+ label: 'O'
+ base: 'o'
+ shift, capslock: 'O'
+}
+
+key P {
+ label: 'P'
+ base: 'p'
+ shift, capslock: 'P'
+}
+
+key LEFT_BRACKET {
+ label: '\u02c6'
+ base: '\u0302'
+ shift: '\u0308'
+}
+
+key RIGHT_BRACKET {
+ label: '$'
+ base: '$'
+ shift: '\u00a3'
+ ralt: '\u00a4'
+}
+
+### ROW 3
+
+key Q {
+ label: 'Q'
+ base: 'q'
+ shift, capslock: 'Q'
+}
+
+key S {
+ label: 'S'
+ base: 's'
+ shift, capslock: 'S'
+}
+
+key D {
+ label: 'D'
+ base: 'd'
+ shift, capslock: 'D'
+}
+
+key F {
+ label: 'F'
+ base: 'f'
+ shift, capslock: 'F'
+}
+
+key G {
+ label: 'G'
+ base: 'g'
+ shift, capslock: 'G'
+}
+
+key H {
+ label: 'H'
+ base: 'h'
+ shift, capslock: 'H'
+}
+
+key J {
+ label: 'J'
+ base: 'j'
+ shift, capslock: 'J'
+}
+
+key K {
+ label: 'K'
+ base: 'k'
+ shift, capslock: 'K'
+}
+
+key L {
+ label: 'L'
+ base: 'l'
+ shift, capslock: 'L'
+}
+
+key M {
+ label: 'M'
+ base: 'm'
+ shift, capslock: 'M'
+}
+
+key APOSTROPHE {
+ label: '\u00f9'
+ base: '\u00f9'
+ shift: '%'
+}
+
+key BACKSLASH {
+ label: '*'
+ base: '*'
+ shift: '\u00b5'
+}
+
+### ROW 4
+
+key PLUS {
+ label: '<'
+ base: '<'
+ shift: '>'
+}
+
+key W {
+ label: 'W'
+ base: 'w'
+ shift, capslock: 'W'
+}
+
+key X {
+ label: 'X'
+ base: 'x'
+ shift, capslock: 'X'
+}
+
+key C {
+ label: 'C'
+ base: 'c'
+ shift, capslock: 'C'
+}
+
+key V {
+ label: 'V'
+ base: 'v'
+ shift, capslock: 'V'
+}
+
+key B {
+ label: 'B'
+ base: 'b'
+ shift, capslock: 'B'
+}
+
+key N {
+ label: 'N'
+ base: 'n'
+ shift, capslock: 'N'
+}
+
+key COMMA {
+ label: ','
+ base: ','
+ shift: '?'
+}
+
+key SEMICOLON {
+ label: ';'
+ base: ';'
+ shift: '.'
+}
+
+key PERIOD {
+ label: ':'
+ base: ':'
+ shift: '/'
+}
+
+key SLASH {
+ label: '!'
+ base: '!'
+ shift: '\u00a7'
+} \ No newline at end of file
diff --git a/libs/input/tests/data/german.kcm b/libs/input/tests/data/german.kcm
new file mode 100644
index 0000000000..2fbc5e54e3
--- /dev/null
+++ b/libs/input/tests/data/german.kcm
@@ -0,0 +1,336 @@
+# 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.
+
+#
+# German keyboard layout, QWERTZ style.
+#
+
+type OVERLAY
+
+map key 12 SLASH # � ? \
+map key 21 Z
+map key 44 Y
+map key 53 MINUS # - _
+map key 86 PLUS # < > |
+
+map key usage 32 A # for testing purposes only
+map key usage 67 B # for testing purposes only
+
+### ROW 1
+
+key GRAVE {
+ label: '^'
+ base: '^'
+ shift: '\u00b0'
+}
+
+key 1 {
+ label: '1'
+ base: '1'
+ shift: '!'
+}
+
+key 2 {
+ label: '2'
+ base: '2'
+ shift: '"'
+ ralt: '\u00b2'
+}
+
+key 3 {
+ label: '3'
+ base: '3'
+ shift: '\u00a7'
+ ralt: '\u00b3'
+}
+
+key 4 {
+ label: '4'
+ base: '4'
+ shift: '$'
+}
+
+key 5 {
+ label: '5'
+ base: '5'
+ shift: '%'
+}
+
+key 6 {
+ label: '6'
+ base: '6'
+ shift: '&'
+}
+
+key 7 {
+ label: '7'
+ base: '7'
+ shift: '/'
+ ralt: '{'
+}
+
+key 8 {
+ label: '8'
+ base: '8'
+ shift: '('
+ ralt: '['
+}
+
+key 9 {
+ label: '9'
+ base: '9'
+ shift: ')'
+ ralt: ']'
+}
+
+key 0 {
+ label: '0'
+ base: '0'
+ shift: '='
+ ralt: '}'
+}
+
+key SLASH {
+ label: '\u00df'
+ base: '\u00df'
+ shift: '?'
+ ralt: '\\'
+}
+
+key EQUALS {
+ label: '\u00b4'
+ base: '\u0301'
+ shift: '\u0300'
+}
+
+### ROW 2
+
+key Q {
+ label: 'Q'
+ base: 'q'
+ shift, capslock: 'Q'
+ ralt: '@'
+}
+
+key W {
+ label: 'W'
+ base: 'w'
+ shift, capslock: 'W'
+}
+
+key E {
+ label: 'E'
+ base: 'e'
+ shift, capslock: 'E'
+ ralt: '\u20ac'
+}
+
+key R {
+ label: 'R'
+ base: 'r'
+ shift, capslock: 'R'
+}
+
+key T {
+ label: 'T'
+ base: 't'
+ shift, capslock: 'T'
+}
+
+key Z {
+ label: 'Z'
+ base: 'z'
+ shift, capslock: 'Z'
+}
+
+key U {
+ label: 'U'
+ base: 'u'
+ shift, capslock: 'U'
+}
+
+key I {
+ label: 'I'
+ base: 'i'
+ shift, capslock: 'I'
+}
+
+key O {
+ label: 'O'
+ base: 'o'
+ shift, capslock: 'O'
+}
+
+key P {
+ label: 'P'
+ base: 'p'
+ shift, capslock: 'P'
+}
+
+key LEFT_BRACKET {
+ label: '\u00dc'
+ base: '\u00fc'
+ shift, capslock: '\u00dc'
+}
+
+key RIGHT_BRACKET {
+ label: '+'
+ base: '+'
+ shift: '*'
+ ralt: '~'
+}
+
+### ROW 3
+
+key A {
+ label: 'A'
+ base: 'a'
+ shift, capslock: 'A'
+}
+
+key S {
+ label: 'S'
+ base: 's'
+ shift, capslock: 'S'
+}
+
+key D {
+ label: 'D'
+ base: 'd'
+ shift, capslock: 'D'
+}
+
+key F {
+ label: 'F'
+ base: 'f'
+ shift, capslock: 'F'
+}
+
+key G {
+ label: 'G'
+ base: 'g'
+ shift, capslock: 'G'
+}
+
+key H {
+ label: 'H'
+ base: 'h'
+ shift, capslock: 'H'
+}
+
+key J {
+ label: 'J'
+ base: 'j'
+ shift, capslock: 'J'
+}
+
+key K {
+ label: 'K'
+ base: 'k'
+ shift, capslock: 'K'
+}
+
+key L {
+ label: 'L'
+ base: 'l'
+ shift, capslock: 'L'
+}
+
+key SEMICOLON {
+ label: '\u00d6'
+ base: '\u00f6'
+ shift, capslock: '\u00d6'
+}
+
+key APOSTROPHE {
+ label: '\u00c4'
+ base: '\u00e4'
+ shift, capslock: '\u00c4'
+}
+
+key BACKSLASH {
+ label: '#'
+ base: '#'
+ shift: '\''
+}
+
+### ROW 4
+
+key PLUS {
+ label: '<'
+ base: '<'
+ shift: '>'
+ ralt: '|'
+}
+
+key Y {
+ label: 'Y'
+ base: 'y'
+ shift, capslock: 'Y'
+}
+
+key X {
+ label: 'X'
+ base: 'x'
+ shift, capslock: 'X'
+}
+
+key C {
+ label: 'C'
+ base: 'c'
+ shift, capslock: 'C'
+}
+
+key V {
+ label: 'V'
+ base: 'v'
+ shift, capslock: 'V'
+}
+
+key B {
+ label: 'B'
+ base: 'b'
+ shift, capslock: 'B'
+}
+
+key N {
+ label: 'N'
+ base: 'n'
+ shift, capslock: 'N'
+}
+
+key M {
+ label: 'M'
+ base: 'm'
+ shift, capslock: 'M'
+ ralt: '\u00b5'
+}
+
+key COMMA {
+ label: ','
+ base: ','
+ shift: ';'
+}
+
+key PERIOD {
+ label: '.'
+ base: '.'
+ shift: ':'
+}
+
+key MINUS {
+ label: '-'
+ base: '-'
+ shift: '_'
+}
diff --git a/libs/nativedisplay/AChoreographer.cpp b/libs/nativedisplay/AChoreographer.cpp
index 0edb213089..2dd6c4fcaa 100644
--- a/libs/nativedisplay/AChoreographer.cpp
+++ b/libs/nativedisplay/AChoreographer.cpp
@@ -20,7 +20,6 @@
#include <android-base/thread_annotations.h>
#include <gui/DisplayEventDispatcher.h>
#include <gui/ISurfaceComposer.h>
-#include <gui/SurfaceComposerClient.h>
#include <jni.h>
#include <private/android/choreographer.h>
#include <utils/Looper.h>
diff --git a/libs/nativewindow/AHardwareBuffer.cpp b/libs/nativewindow/AHardwareBuffer.cpp
index ef7602f24e..af55623ac5 100644
--- a/libs/nativewindow/AHardwareBuffer.cpp
+++ b/libs/nativewindow/AHardwareBuffer.cpp
@@ -207,7 +207,11 @@ int AHardwareBuffer_lockPlanes(AHardwareBuffer* buffer, uint64_t usage,
if (result == 0) {
outPlanes->planeCount = 3;
outPlanes->planes[0].data = yuvData.y;
- outPlanes->planes[0].pixelStride = 1;
+ if (format == AHARDWAREBUFFER_FORMAT_YCbCr_P010) {
+ outPlanes->planes[0].pixelStride = 2;
+ } else {
+ outPlanes->planes[0].pixelStride = 1;
+ }
outPlanes->planes[0].rowStride = yuvData.ystride;
outPlanes->planes[1].data = yuvData.cb;
outPlanes->planes[1].pixelStride = yuvData.chroma_step;
diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h
index 4cb1b4259b..14627ce0ce 100644
--- a/libs/renderengine/gl/GLESRenderEngine.h
+++ b/libs/renderengine/gl/GLESRenderEngine.h
@@ -71,7 +71,7 @@ public:
void cleanupPostRender() override;
int getContextPriority() override;
bool supportsBackgroundBlur() override { return mBlurFilter != nullptr; }
- void onPrimaryDisplaySizeChanged(ui::Size size) override {}
+ void onActiveDisplaySizeChanged(ui::Size size) override {}
EGLDisplay getEGLDisplay() const { return mEGLDisplay; }
// Creates an output image for rendering to
diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h
index 46a7d1eea6..f555cdbc0d 100644
--- a/libs/renderengine/include/renderengine/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/RenderEngine.h
@@ -129,9 +129,9 @@ public:
// Attempt to switch RenderEngine into and out of protectedContext mode
virtual void useProtectedContext(bool useProtectedContext) = 0;
- // Notify RenderEngine of changes to the dimensions of the primary display
+ // Notify RenderEngine of changes to the dimensions of the active display
// so that it can configure its internal caches accordingly.
- virtual void onPrimaryDisplaySizeChanged(ui::Size size) = 0;
+ virtual void onActiveDisplaySizeChanged(ui::Size size) = 0;
// Renders layers for a particular display via GPU composition. This method
// should be called for every display that needs to be rendered via the GPU.
diff --git a/libs/renderengine/include/renderengine/mock/RenderEngine.h b/libs/renderengine/include/renderengine/mock/RenderEngine.h
index a4aa9ea488..0be3ba6b11 100644
--- a/libs/renderengine/include/renderengine/mock/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/mock/RenderEngine.h
@@ -54,7 +54,7 @@ public:
MOCK_METHOD0(cleanFramebufferCache, void());
MOCK_METHOD0(getContextPriority, int());
MOCK_METHOD0(supportsBackgroundBlur, bool());
- MOCK_METHOD1(onPrimaryDisplaySizeChanged, void(ui::Size));
+ MOCK_METHOD1(onActiveDisplaySizeChanged, void(ui::Size));
protected:
// mock renderengine still needs to implement these, but callers should never need to call them.
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
index 94023e6247..e42b5b9e79 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
@@ -1413,7 +1413,7 @@ int SkiaGLRenderEngine::getContextPriority() {
return value;
}
-void SkiaGLRenderEngine::onPrimaryDisplaySizeChanged(ui::Size size) {
+void SkiaGLRenderEngine::onActiveDisplaySizeChanged(ui::Size size) {
// This cache multiplier was selected based on review of cache sizes relative
// to the screen resolution. Looking at the worst case memory needed by blur (~1.5x),
// shadows (~1x), and general data structures (e.g. vertex buffers) we selected this as a
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.h b/libs/renderengine/skia/SkiaGLRenderEngine.h
index 238ad8f452..e1162f5574 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.h
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.h
@@ -67,7 +67,7 @@ public:
void useProtectedContext(bool useProtectedContext) override;
bool supportsBackgroundBlur() override { return mBlurFilter != nullptr; }
void assertShadersCompiled(int numShaders) override;
- void onPrimaryDisplaySizeChanged(ui::Size size) override;
+ void onActiveDisplaySizeChanged(ui::Size size) override;
int reportShadersCompiled() override;
protected:
diff --git a/libs/renderengine/threaded/RenderEngineThreaded.cpp b/libs/renderengine/threaded/RenderEngineThreaded.cpp
index b9dabc1d05..8e666d5733 100644
--- a/libs/renderengine/threaded/RenderEngineThreaded.cpp
+++ b/libs/renderengine/threaded/RenderEngineThreaded.cpp
@@ -361,14 +361,14 @@ bool RenderEngineThreaded::supportsBackgroundBlur() {
return mRenderEngine->supportsBackgroundBlur();
}
-void RenderEngineThreaded::onPrimaryDisplaySizeChanged(ui::Size size) {
+void RenderEngineThreaded::onActiveDisplaySizeChanged(ui::Size size) {
// 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([size](renderengine::RenderEngine& instance) {
- ATRACE_NAME("REThreaded::onPrimaryDisplaySizeChanged");
- instance.onPrimaryDisplaySizeChanged(size);
+ ATRACE_NAME("REThreaded::onActiveDisplaySizeChanged");
+ instance.onActiveDisplaySizeChanged(size);
});
}
mCondition.notify_one();
diff --git a/libs/renderengine/threaded/RenderEngineThreaded.h b/libs/renderengine/threaded/RenderEngineThreaded.h
index f2f5c0f7cd..b197df7e0f 100644
--- a/libs/renderengine/threaded/RenderEngineThreaded.h
+++ b/libs/renderengine/threaded/RenderEngineThreaded.h
@@ -65,7 +65,7 @@ public:
void cleanFramebufferCache() override;
int getContextPriority() override;
bool supportsBackgroundBlur() override;
- void onPrimaryDisplaySizeChanged(ui::Size size) override;
+ void onActiveDisplaySizeChanged(ui::Size size) override;
protected:
void mapExternalTextureBuffer(const sp<GraphicBuffer>& buffer, bool isRenderable) override;
diff --git a/libs/ui/Gralloc4.cpp b/libs/ui/Gralloc4.cpp
index 9dc9beb8e7..162fd95945 100644
--- a/libs/ui/Gralloc4.cpp
+++ b/libs/ui/Gralloc4.cpp
@@ -300,20 +300,19 @@ status_t Gralloc4Mapper::lock(buffer_handle_t bufferHandle, uint64_t usage, cons
if (!gralloc4::isStandardPlaneLayoutComponentType(planeLayoutComponent.type)) {
continue;
}
- if (0 != planeLayoutComponent.offsetInBits % 8) {
- unlock(bufferHandle);
- return BAD_VALUE;
- }
- uint8_t* tmpData = static_cast<uint8_t*>(data) + planeLayout.offsetInBytes +
- (planeLayoutComponent.offsetInBits / 8);
+ uint8_t* tmpData = static_cast<uint8_t*>(data) + planeLayout.offsetInBytes;
+
+ // Note that `offsetInBits` may not be a multiple of 8 for packed formats (e.g. P010)
+ // but we still want to point to the start of the first byte.
+ tmpData += (planeLayoutComponent.offsetInBits / 8);
+
uint64_t sampleIncrementInBytes;
auto type = static_cast<PlaneLayoutComponentType>(planeLayoutComponent.type.value);
switch (type) {
case PlaneLayoutComponentType::Y:
- if ((ycbcr.y != nullptr) || (planeLayoutComponent.sizeInBits != 8) ||
- (planeLayout.sampleIncrementInBits != 8)) {
+ if ((ycbcr.y != nullptr) || (planeLayout.sampleIncrementInBits % 8 != 0)) {
unlock(bufferHandle);
return BAD_VALUE;
}
@@ -329,7 +328,8 @@ status_t Gralloc4Mapper::lock(buffer_handle_t bufferHandle, uint64_t usage, cons
}
sampleIncrementInBytes = planeLayout.sampleIncrementInBits / 8;
- if ((sampleIncrementInBytes != 1) && (sampleIncrementInBytes != 2)) {
+ if ((sampleIncrementInBytes != 1) && (sampleIncrementInBytes != 2) &&
+ (sampleIncrementInBytes != 4)) {
unlock(bufferHandle);
return BAD_VALUE;
}
@@ -939,7 +939,7 @@ status_t Gralloc4Mapper::bufferDumpHelper(const BufferDump& bufferDump, std::ost
<< "KiB, w/h:" << width << "x" << height << ", usage: 0x" << std::hex << usage
<< std::dec << ", req fmt:" << static_cast<int32_t>(pixelFormatRequested)
<< ", fourcc/mod:" << pixelFormatFourCC << "/" << pixelFormatModifier
- << ", dataspace: 0x" << std::hex << static_cast<uint32_t>(dataspace)
+ << ", dataspace: 0x" << std::hex << static_cast<uint32_t>(dataspace) << std::dec
<< ", compressed: ";
if (less) {
diff --git a/libs/ui/tests/Android.bp b/libs/ui/tests/Android.bp
index 516aad824e..b780770b86 100644
--- a/libs/ui/tests/Android.bp
+++ b/libs/ui/tests/Android.bp
@@ -93,7 +93,6 @@ cc_test {
cflags: ["-Wall", "-Werror"],
shared_libs: [
"libbinder",
- "libgui",
"liblog",
"libui",
"libutils",
diff --git a/libs/ui/tests/GraphicBufferOverBinder_test.cpp b/libs/ui/tests/GraphicBufferOverBinder_test.cpp
index 126a945a0a..4c9d574ef8 100644
--- a/libs/ui/tests/GraphicBufferOverBinder_test.cpp
+++ b/libs/ui/tests/GraphicBufferOverBinder_test.cpp
@@ -20,9 +20,6 @@
#include <binder/Parcel.h>
#include <binder/ProcessState.h>
#include <gtest/gtest.h>
-#include <gui/BufferQueue.h>
-#include <gui/IGraphicBufferConsumer.h>
-#include <gui/IGraphicBufferProducer.h>
#include <ui/GraphicBuffer.h>
#include <utils/Log.h>
diff --git a/libs/vibrator/ExternalVibrationUtils.cpp b/libs/vibrator/ExternalVibrationUtils.cpp
index 749c568457..980b08ba36 100644
--- a/libs/vibrator/ExternalVibrationUtils.cpp
+++ b/libs/vibrator/ExternalVibrationUtils.cpp
@@ -56,6 +56,36 @@ float getHapticMaxAmplitudeRatio(HapticScale scale) {
}
}
+void applyHapticScale(float* buffer, size_t length, HapticScale scale) {
+ if (scale == HapticScale::MUTE) {
+ memset(buffer, 0, length * sizeof(float));
+ return;
+ }
+ if (scale == HapticScale::NONE) {
+ return;
+ }
+ float gamma = getHapticScaleGamma(scale);
+ float maxAmplitudeRatio = getHapticMaxAmplitudeRatio(scale);
+ for (size_t i = 0; i < length; i++) {
+ float sign = buffer[i] >= 0 ? 1.0 : -1.0;
+ buffer[i] = powf(fabsf(buffer[i] / HAPTIC_MAX_AMPLITUDE_FLOAT), gamma)
+ * maxAmplitudeRatio * HAPTIC_MAX_AMPLITUDE_FLOAT * sign;
+ }
+}
+
+void clipHapticData(float* buffer, size_t length, float limit) {
+ if (isnan(limit) || limit == 0) {
+ return;
+ }
+ limit = fabsf(limit);
+ for (size_t i = 0; i < length; i++) {
+ float sign = buffer[i] >= 0 ? 1.0 : -1.0;
+ if (fabsf(buffer[i]) > limit) {
+ buffer[i] = limit * sign;
+ }
+ }
+}
+
} // namespace
bool isValidHapticScale(HapticScale scale) {
@@ -71,21 +101,11 @@ bool isValidHapticScale(HapticScale scale) {
return false;
}
-void scaleHapticData(float* buffer, size_t length, HapticScale scale) {
- if (!isValidHapticScale(scale) || scale == HapticScale::NONE) {
- return;
- }
- if (scale == HapticScale::MUTE) {
- memset(buffer, 0, length * sizeof(float));
- return;
- }
- float gamma = getHapticScaleGamma(scale);
- float maxAmplitudeRatio = getHapticMaxAmplitudeRatio(scale);
- for (size_t i = 0; i < length; i++) {
- float sign = buffer[i] >= 0 ? 1.0 : -1.0;
- buffer[i] = powf(fabsf(buffer[i] / HAPTIC_MAX_AMPLITUDE_FLOAT), gamma)
- * maxAmplitudeRatio * HAPTIC_MAX_AMPLITUDE_FLOAT * sign;
+void scaleHapticData(float* buffer, size_t length, HapticScale scale, float limit) {
+ if (isValidHapticScale(scale)) {
+ applyHapticScale(buffer, length, scale);
}
+ clipHapticData(buffer, length, limit);
}
} // namespace android::os
diff --git a/libs/vibrator/include/vibrator/ExternalVibrationUtils.h b/libs/vibrator/include/vibrator/ExternalVibrationUtils.h
index 20045d0769..84357fcb35 100644
--- a/libs/vibrator/include/vibrator/ExternalVibrationUtils.h
+++ b/libs/vibrator/include/vibrator/ExternalVibrationUtils.h
@@ -32,7 +32,11 @@ enum class HapticScale {
bool isValidHapticScale(HapticScale scale);
-void scaleHapticData(float* buffer, size_t length, HapticScale scale);
+/* Scales the haptic data in given buffer using the selected HapticScale and ensuring no absolute
+ * value will be larger than the absolute of given limit.
+ * The limit will be ignored if it is NaN or zero.
+ */
+void scaleHapticData(float* buffer, size_t length, HapticScale scale, float limit);
} // namespace android::os
diff --git a/libs/vr/libbroadcastring/Android.bp b/libs/vr/libbroadcastring/Android.bp
index d4538f12a2..fa449aeb55 100644
--- a/libs/vr/libbroadcastring/Android.bp
+++ b/libs/vr/libbroadcastring/Android.bp
@@ -9,7 +9,7 @@ package {
cc_library_static {
name: "libbroadcastring",
- clang: true,
+
cflags: [
"-Wall",
"-Wextra",
diff --git a/libs/vr/libvrflinger/vr_flinger.cpp b/libs/vr/libvrflinger/vr_flinger.cpp
index a8a847664f..de7d8f879b 100644
--- a/libs/vr/libvrflinger/vr_flinger.cpp
+++ b/libs/vr/libvrflinger/vr_flinger.cpp
@@ -17,6 +17,7 @@
#include <processgroup/sched_policy.h>
#include <sys/prctl.h>
#include <sys/resource.h>
+#include <utils/ThreadDefs.h>
#include <functional>
diff --git a/opengl/OWNERS b/opengl/OWNERS
index a9bd4bb2e2..379f7638f0 100644
--- a/opengl/OWNERS
+++ b/opengl/OWNERS
@@ -1,6 +1,11 @@
+abdolrashidi@google.com
+cclao@google.com
chrisforbes@google.com
cnorthrop@google.com
ianelliott@google.com
jessehall@google.com
+lfy@google.com
lpy@google.com
-timvp@google.com
+romanl@google.com
+vantablack@google.com
+yuxinhu@google.com
diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp
index 6612a932a0..73e57495e6 100644
--- a/services/inputflinger/Android.bp
+++ b/services/inputflinger/Android.bp
@@ -73,6 +73,7 @@ cc_defaults {
"libui",
"lib-platform-compat-native-api",
"server_configurable_flags",
+ "InputFlingerProperties",
],
static_libs: [
"libattestation",
@@ -95,6 +96,7 @@ cc_library_shared {
"libinputflinger_base",
"libinputreporter",
"libinputreader",
+ "libgui",
],
static_libs: [
"libinputdispatcher",
diff --git a/services/inputflinger/InputManager.cpp b/services/inputflinger/InputManager.cpp
index a50e5c70f7..7b3658dfde 100644
--- a/services/inputflinger/InputManager.cpp
+++ b/services/inputflinger/InputManager.cpp
@@ -31,6 +31,10 @@
namespace android {
+using gui::FocusRequest;
+using gui::WindowInfo;
+using gui::WindowInfoHandle;
+
static int32_t exceptionCodeFromStatusT(status_t status) {
switch (status) {
case OK:
@@ -110,33 +114,6 @@ sp<InputDispatcherInterface> InputManager::getDispatcher() {
return mDispatcher;
}
-class BinderWindowHandle : public InputWindowHandle {
-public:
- BinderWindowHandle(const InputWindowInfo& info) { mInfo = info; }
-
- bool updateInfo() override {
- return true;
- }
-};
-
-binder::Status InputManager::setInputWindows(
- const std::vector<InputWindowInfo>& infos,
- const sp<ISetInputWindowsListener>& setInputWindowsListener) {
- std::unordered_map<int32_t, std::vector<sp<InputWindowHandle>>> handlesPerDisplay;
-
- std::vector<sp<InputWindowHandle>> handles;
- for (const auto& info : infos) {
- handlesPerDisplay.emplace(info.displayId, std::vector<sp<InputWindowHandle>>());
- handlesPerDisplay[info.displayId].push_back(new BinderWindowHandle(info));
- }
- mDispatcher->setInputWindows(handlesPerDisplay);
-
- if (setInputWindowsListener) {
- setInputWindowsListener->onSetInputWindowsFinished();
- }
- return binder::Status::ok();
-}
-
// Used by tests only.
binder::Status InputManager::createInputChannel(const std::string& name, InputChannel* outChannel) {
IPCThreadState* ipc = IPCThreadState::self();
diff --git a/services/inputflinger/InputManager.h b/services/inputflinger/InputManager.h
index 49bea132c8..4c07c22154 100644
--- a/services/inputflinger/InputManager.h
+++ b/services/inputflinger/InputManager.h
@@ -26,7 +26,6 @@
#include <InputDispatcherInterface.h>
#include <InputDispatcherPolicyInterface.h>
-#include <android/os/ISetInputWindowsListener.h>
#include <input/Input.h>
#include <input/InputTransport.h>
@@ -38,7 +37,6 @@
#include <utils/Vector.h>
using android::os::BnInputFlinger;
-using android::os::ISetInputWindowsListener;
namespace android {
class InputChannel;
@@ -104,13 +102,9 @@ public:
sp<InputDispatcherInterface> getDispatcher() override;
status_t dump(int fd, const Vector<String16>& args) override;
- binder::Status setInputWindows(
- const std::vector<InputWindowInfo>& handles,
- const sp<ISetInputWindowsListener>& setInputWindowsListener) override;
-
binder::Status createInputChannel(const std::string& name, InputChannel* outChannel) override;
binder::Status removeInputChannel(const sp<IBinder>& connectionToken) override;
- binder::Status setFocusedWindow(const FocusRequest&) override;
+ binder::Status setFocusedWindow(const gui::FocusRequest&) override;
private:
sp<InputReaderInterface> mReader;
diff --git a/services/inputflinger/InputReaderBase.cpp b/services/inputflinger/InputReaderBase.cpp
index d34482f506..05ef489133 100644
--- a/services/inputflinger/InputReaderBase.cpp
+++ b/services/inputflinger/InputReaderBase.cpp
@@ -19,9 +19,9 @@
//#define LOG_NDEBUG 0
#include "InputReaderBase.h"
+#include <ftl/NamedEnum.h>
#include "input/DisplayViewport.h"
#include "input/Input.h"
-#include "input/NamedEnum.h"
#include <android/log.h>
#include <android-base/stringprintf.h>
diff --git a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
index aa8cc302c7..6ce0313929 100644
--- a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
+++ b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
@@ -18,8 +18,11 @@
#include <android/os/IInputConstants.h>
#include <binder/Binder.h>
+#include <gui/constants.h>
#include "../dispatcher/InputDispatcher.h"
+using android::gui::WindowInfo;
+using android::gui::WindowInfoHandle;
using android::os::IInputConstants;
using android::os::InputEventInjectionResult;
using android::os::InputEventInjectionSync;
@@ -173,7 +176,7 @@ protected:
PreallocatedInputEventFactory mEventFactory;
};
-class FakeWindowHandle : public InputWindowHandle, public FakeInputReceiver {
+class FakeWindowHandle : public WindowInfoHandle, public FakeInputReceiver {
public:
static const int32_t WIDTH = 200;
static const int32_t HEIGHT = 200;
@@ -182,13 +185,14 @@ public:
const sp<InputDispatcher>& dispatcher, const std::string name)
: FakeInputReceiver(dispatcher, name), mFrame(Rect(0, 0, WIDTH, HEIGHT)) {
inputApplicationHandle->updateInfo();
+ updateInfo();
mInfo.applicationInfo = *inputApplicationHandle->getInfo();
}
- virtual bool updateInfo() override {
+ void updateInfo() {
mInfo.token = mClientChannel->getConnectionToken();
mInfo.name = "FakeWindowHandle";
- mInfo.type = InputWindowInfo::Type::APPLICATION;
+ mInfo.type = WindowInfo::Type::APPLICATION;
mInfo.dispatchingTimeout = DISPATCHING_TIMEOUT;
mInfo.frameLeft = mFrame.left;
mInfo.frameTop = mFrame.top;
@@ -204,8 +208,6 @@ public:
mInfo.ownerPid = INJECTOR_PID;
mInfo.ownerUid = INJECTOR_UID;
mInfo.displayId = ADISPLAY_ID_DEFAULT;
-
- return true;
}
protected:
@@ -234,8 +236,8 @@ static MotionEvent generateMotionEvent() {
/* edgeFlags */ 0, AMETA_NONE, /* buttonState */ 0, MotionClassification::NONE,
identityTransform, /* xPrecision */ 0,
/* yPrecision */ 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
- AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_DISPLAY_SIZE,
- AMOTION_EVENT_INVALID_DISPLAY_SIZE, currentTime, currentTime,
+ AMOTION_EVENT_INVALID_CURSOR_POSITION, ui::Transform::ROT_0,
+ INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, currentTime, currentTime,
/*pointerCount*/ 1, pointerProperties, pointerCoords);
return event;
}
diff --git a/services/inputflinger/dispatcher/Android.bp b/services/inputflinger/dispatcher/Android.bp
index 1b3888b340..171f2b5ce8 100644
--- a/services/inputflinger/dispatcher/Android.bp
+++ b/services/inputflinger/dispatcher/Android.bp
@@ -64,9 +64,11 @@ cc_defaults {
"libstatspull",
"libstatssocket",
"libui",
+ "libgui",
"libutils",
"lib-platform-compat-native-api",
"server_configurable_flags",
+ "InputFlingerProperties",
],
static_libs: [
"libattestation",
diff --git a/services/inputflinger/dispatcher/DragState.cpp b/services/inputflinger/dispatcher/DragState.cpp
index 2e2df43009..e1844a4a3a 100644
--- a/services/inputflinger/dispatcher/DragState.cpp
+++ b/services/inputflinger/dispatcher/DragState.cpp
@@ -16,9 +16,7 @@
#include "DragState.h"
#include <android-base/stringprintf.h>
-#include <input/InputWindow.h>
-using android::InputWindowHandle;
using android::base::StringPrintf;
namespace android::inputdispatcher {
diff --git a/services/inputflinger/dispatcher/DragState.h b/services/inputflinger/dispatcher/DragState.h
index 06453d8eee..b3c5709cbc 100644
--- a/services/inputflinger/dispatcher/DragState.h
+++ b/services/inputflinger/dispatcher/DragState.h
@@ -17,22 +17,22 @@
#ifndef _UI_INPUT_INPUTDISPATCHER_DRAGSTATE_H
#define _UI_INPUT_INPUTDISPATCHER_DRAGSTATE_H
+#include <gui/WindowInfo.h>
#include <utils/RefBase.h>
#include <string>
namespace android {
-class InputWindowHandle;
-
namespace inputdispatcher {
+
struct DragState {
- DragState(const sp<android::InputWindowHandle>& windowHandle) : dragWindow(windowHandle) {}
+ DragState(const sp<android::gui::WindowInfoHandle>& windowHandle) : dragWindow(windowHandle) {}
void dump(std::string& dump, const char* prefix = "");
// The window being dragged.
- const sp<InputWindowHandle> dragWindow;
+ const sp<android::gui::WindowInfoHandle> dragWindow;
// The last drag hover window which could receive the drag event.
- sp<InputWindowHandle> dragHoverWindowHandle;
+ sp<android::gui::WindowInfoHandle> dragHoverWindowHandle;
// Indicates the if received first event to check for button state.
bool isStartDrag = false;
// Indicate if the stylus button is down at the start of the drag.
diff --git a/services/inputflinger/dispatcher/Entry.cpp b/services/inputflinger/dispatcher/Entry.cpp
index 5c3747e2ec..82b4fe476e 100644
--- a/services/inputflinger/dispatcher/Entry.cpp
+++ b/services/inputflinger/dispatcher/Entry.cpp
@@ -296,12 +296,14 @@ std::string SensorEntry::getDescription() const {
volatile int32_t DispatchEntry::sNextSeqAtomic;
DispatchEntry::DispatchEntry(std::shared_ptr<EventEntry> eventEntry, int32_t targetFlags,
- ui::Transform transform, float globalScaleFactor, int2 displaySize)
+ ui::Transform transform, float globalScaleFactor,
+ uint32_t displayOrientation, int2 displaySize)
: seq(nextSeq()),
eventEntry(std::move(eventEntry)),
targetFlags(targetFlags),
transform(transform),
globalScaleFactor(globalScaleFactor),
+ displayOrientation(displayOrientation),
displaySize(displaySize),
deliveryTime(0),
resolvedAction(0),
diff --git a/services/inputflinger/dispatcher/Entry.h b/services/inputflinger/dispatcher/Entry.h
index 6f1dfadf59..ffe3bb691c 100644
--- a/services/inputflinger/dispatcher/Entry.h
+++ b/services/inputflinger/dispatcher/Entry.h
@@ -20,8 +20,8 @@
#include "InjectionState.h"
#include "InputTarget.h"
+#include <gui/InputApplication.h>
#include <input/Input.h>
-#include <input/InputApplication.h>
#include <stdint.h>
#include <utils/Timers.h>
#include <functional>
@@ -215,6 +215,7 @@ struct DispatchEntry {
int32_t targetFlags;
ui::Transform transform;
float globalScaleFactor;
+ uint32_t displayOrientation;
int2 displaySize;
// Both deliveryTime and timeoutTime are only populated when the entry is sent to the app,
// and will be undefined before that.
@@ -228,7 +229,8 @@ struct DispatchEntry {
int32_t resolvedFlags;
DispatchEntry(std::shared_ptr<EventEntry> eventEntry, int32_t targetFlags,
- ui::Transform transform, float globalScaleFactor, int2 displaySize);
+ ui::Transform transform, float globalScaleFactor, uint32_t displayOrientation,
+ int2 displaySize);
inline bool hasForegroundTarget() const { return targetFlags & InputTarget::FLAG_FOREGROUND; }
diff --git a/services/inputflinger/dispatcher/FocusResolver.cpp b/services/inputflinger/dispatcher/FocusResolver.cpp
index fb194355ba..4a75773201 100644
--- a/services/inputflinger/dispatcher/FocusResolver.cpp
+++ b/services/inputflinger/dispatcher/FocusResolver.cpp
@@ -27,12 +27,15 @@ static constexpr bool DEBUG_FOCUS = false;
#include <android-base/stringprintf.h>
#include <binder/Binder.h>
-#include <input/InputWindow.h>
-#include <input/NamedEnum.h>
+#include <ftl/NamedEnum.h>
+#include <gui/WindowInfo.h>
#include <log/log.h>
#include "FocusResolver.h"
+using android::gui::FocusRequest;
+using android::gui::WindowInfoHandle;
+
namespace android::inputdispatcher {
sp<IBinder> FocusResolver::getFocusedWindowToken(int32_t displayId) const {
@@ -52,7 +55,7 @@ std::optional<FocusRequest> FocusResolver::getFocusRequest(int32_t displayId) {
* we will check if the previous focus request is eligible to receive focus.
*/
std::optional<FocusResolver::FocusChanges> FocusResolver::setInputWindows(
- int32_t displayId, const std::vector<sp<InputWindowHandle>>& windows) {
+ int32_t displayId, const std::vector<sp<WindowInfoHandle>>& windows) {
std::string removeFocusReason;
// Check if the currently focused window is still focusable.
@@ -87,7 +90,7 @@ std::optional<FocusResolver::FocusChanges> FocusResolver::setInputWindows(
}
std::optional<FocusResolver::FocusChanges> FocusResolver::setFocusedWindow(
- const FocusRequest& request, const std::vector<sp<InputWindowHandle>>& windows) {
+ const FocusRequest& request, const std::vector<sp<WindowInfoHandle>>& windows) {
const int32_t displayId = request.displayId;
const sp<IBinder> currentFocus = getFocusedWindowToken(displayId);
if (currentFocus == request.token) {
@@ -136,11 +139,11 @@ std::optional<FocusResolver::FocusChanges> FocusResolver::setFocusedWindow(
}
FocusResolver::Focusability FocusResolver::isTokenFocusable(
- const sp<IBinder>& token, const std::vector<sp<InputWindowHandle>>& windows) {
+ const sp<IBinder>& token, const std::vector<sp<WindowInfoHandle>>& windows) {
bool allWindowsAreFocusable = true;
bool visibleWindowFound = false;
bool windowFound = false;
- for (const sp<InputWindowHandle>& window : windows) {
+ for (const sp<WindowInfoHandle>& window : windows) {
if (window->getToken() != token) {
continue;
}
diff --git a/services/inputflinger/dispatcher/FocusResolver.h b/services/inputflinger/dispatcher/FocusResolver.h
index afe16b3b45..1d6cd9a5fa 100644
--- a/services/inputflinger/dispatcher/FocusResolver.h
+++ b/services/inputflinger/dispatcher/FocusResolver.h
@@ -20,9 +20,9 @@
#include <optional>
#include <unordered_map>
-#include <android/FocusRequest.h>
+#include <android/gui/FocusRequest.h>
#include <binder/Binder.h>
-#include <input/InputWindow.h>
+#include <gui/WindowInfo.h>
namespace android::inputdispatcher {
@@ -58,9 +58,10 @@ public:
std::string reason;
};
std::optional<FocusResolver::FocusChanges> setInputWindows(
- int32_t displayId, const std::vector<sp<InputWindowHandle>>& windows);
+ int32_t displayId, const std::vector<sp<android::gui::WindowInfoHandle>>& windows);
std::optional<FocusResolver::FocusChanges> setFocusedWindow(
- const FocusRequest& request, const std::vector<sp<InputWindowHandle>>& windows);
+ const android::gui::FocusRequest& request,
+ const std::vector<sp<android::gui::WindowInfoHandle>>& windows);
// Display has been removed from the system, clean up old references.
void displayRemoved(int32_t displayId);
@@ -87,8 +88,9 @@ private:
// we expect the focusability of the windows to match since its hard to reason why one window
// can receive focus events and the other cannot when both are backed by the same input channel.
//
- static Focusability isTokenFocusable(const sp<IBinder>& token,
- const std::vector<sp<InputWindowHandle>>& windows);
+ static Focusability isTokenFocusable(
+ const sp<IBinder>& token,
+ const std::vector<sp<android::gui::WindowInfoHandle>>& windows);
// Focus tracking for keys, trackball, etc. A window token can be associated with one or
// more InputWindowHandles. If a window is mirrored, the window and its mirror will share
@@ -99,7 +101,7 @@ private:
// This map will store the focus request per display. When the input window handles are updated,
// the current request will be checked to see if it can be processed at that time.
- std::unordered_map<int32_t /* displayId */, FocusRequest> mFocusRequestByDisplay;
+ std::unordered_map<int32_t /* displayId */, android::gui::FocusRequest> mFocusRequestByDisplay;
// Last reason for not granting a focus request. This is used to add more debug information
// in the event logs.
@@ -108,7 +110,7 @@ private:
std::optional<FocusResolver::FocusChanges> updateFocusedWindow(
int32_t displayId, const std::string& reason, const sp<IBinder>& token,
const std::string& tokenName = "");
- std::optional<FocusRequest> getFocusRequest(int32_t displayId);
+ std::optional<android::gui::FocusRequest> getFocusRequest(int32_t displayId);
};
} // namespace android::inputdispatcher \ No newline at end of file
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 6e9430a975..d53495f9c8 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -47,6 +47,7 @@ static constexpr bool DEBUG_TOUCH_OCCLUSION = true;
// Log debug messages about hover events.
#define DEBUG_HOVER 0
+#include <InputFlingerProperties.sysprop.h>
#include <android-base/chrono_utils.h>
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
@@ -54,8 +55,8 @@ static constexpr bool DEBUG_TOUCH_OCCLUSION = true;
#include <binder/Binder.h>
#include <binder/IServiceManager.h>
#include <com/android/internal/compat/IPlatformCompatNative.h>
+#include <gui/SurfaceComposerClient.h>
#include <input/InputDevice.h>
-#include <input/InputWindow.h>
#include <log/log.h>
#include <log/log_event_list.h>
#include <powermanager/PowerManager.h>
@@ -81,6 +82,10 @@ static constexpr bool DEBUG_TOUCH_OCCLUSION = true;
using android::base::HwTimeoutMultiplier;
using android::base::Result;
using android::base::StringPrintf;
+using android::gui::FocusRequest;
+using android::gui::TouchOcclusionMode;
+using android::gui::WindowInfo;
+using android::gui::WindowInfoHandle;
using android::os::BlockUntrustedTouchesMode;
using android::os::IInputConstants;
using android::os::InputEventInjectionResult;
@@ -93,7 +98,8 @@ namespace android::inputdispatcher {
// coordinates and SurfaceFlinger includes the display rotation in the input window transforms.
static bool isPerWindowInputRotationEnabled() {
static const bool PER_WINDOW_INPUT_ROTATION =
- base::GetBoolProperty("persist.debug.per_window_input_rotation", false);
+ sysprop::InputFlingerProperties::per_window_input_rotation().value_or(false);
+
return PER_WINDOW_INPUT_ROTATION;
}
@@ -290,7 +296,7 @@ static V getValueByKey(const std::unordered_map<K, V>& map, K key) {
return it != map.end() ? it->second : V{};
}
-static bool haveSameToken(const sp<InputWindowHandle>& first, const sp<InputWindowHandle>& second) {
+static bool haveSameToken(const sp<WindowInfoHandle>& first, const sp<WindowInfoHandle>& second) {
if (first == second) {
return true;
}
@@ -302,7 +308,7 @@ static bool haveSameToken(const sp<InputWindowHandle>& first, const sp<InputWind
return first->getToken() == second->getToken();
}
-static bool haveSameApplicationToken(const InputWindowInfo* first, const InputWindowInfo* second) {
+static bool haveSameApplicationToken(const WindowInfo* first, const WindowInfo* second) {
if (first == nullptr || second == nullptr) {
return false;
}
@@ -319,13 +325,14 @@ static std::unique_ptr<DispatchEntry> createDispatchEntry(const InputTarget& inp
int32_t inputTargetFlags) {
if (eventEntry->type == EventEntry::Type::MOTION) {
const MotionEntry& motionEntry = static_cast<const MotionEntry&>(*eventEntry);
- if ((motionEntry.source & AINPUT_SOURCE_CLASS_POINTER) == 0) {
+ if ((motionEntry.source & AINPUT_SOURCE_CLASS_JOYSTICK) ||
+ (motionEntry.source & AINPUT_SOURCE_CLASS_POSITION)) {
const ui::Transform identityTransform;
- // Use identity transform for events that are not pointer events because their axes
- // values do not represent on-screen coordinates, so they should not have any window
- // transformations applied to them.
+ // Use identity transform for joystick and position-based (touchpad) events because they
+ // don't depend on the window transform.
return std::make_unique<DispatchEntry>(eventEntry, inputTargetFlags, identityTransform,
1.0f /*globalScaleFactor*/,
+ inputTarget.displayOrientation,
inputTarget.displaySize);
}
}
@@ -334,6 +341,7 @@ static std::unique_ptr<DispatchEntry> createDispatchEntry(const InputTarget& inp
const ui::Transform& transform = inputTarget.getDefaultPointerTransform();
return std::make_unique<DispatchEntry>(eventEntry, inputTargetFlags, transform,
inputTarget.globalScaleFactor,
+ inputTarget.displayOrientation,
inputTarget.displaySize);
}
@@ -386,6 +394,7 @@ static std::unique_ptr<DispatchEntry> createDispatchEntry(const InputTarget& inp
std::unique_ptr<DispatchEntry> dispatchEntry =
std::make_unique<DispatchEntry>(std::move(combinedMotionEntry), inputTargetFlags,
firstPointerTransform, inputTarget.globalScaleFactor,
+ inputTarget.displayOrientation,
inputTarget.displaySize);
return dispatchEntry;
}
@@ -550,6 +559,10 @@ InputDispatcher::~InputDispatcher() {
}
}
+void InputDispatcher::onFirstRef() {
+ SurfaceComposerClient::getDefault()->addWindowInfosListener(this);
+}
+
status_t InputDispatcher::start() {
if (mThread) {
return ALREADY_EXISTS;
@@ -623,7 +636,7 @@ void InputDispatcher::processNoFocusedWindowAnrLocked() {
return; // The focused application has changed.
}
- const sp<InputWindowHandle>& focusedWindowHandle =
+ const sp<WindowInfoHandle>& focusedWindowHandle =
getFocusedWindowHandleLocked(mAwaitedApplicationDisplayId);
if (focusedWindowHandle != nullptr) {
return; // We now have a focused window. No need for ANR.
@@ -672,7 +685,7 @@ nsecs_t InputDispatcher::processAnrsLocked() {
}
std::chrono::nanoseconds InputDispatcher::getDispatchingTimeoutLocked(const sp<IBinder>& token) {
- sp<InputWindowHandle> window = getWindowHandleLocked(token);
+ sp<WindowInfoHandle> window = getWindowHandleLocked(token);
if (window != nullptr) {
return window->getDispatchingTimeout(DEFAULT_INPUT_DISPATCHING_TIMEOUT);
}
@@ -884,7 +897,7 @@ bool InputDispatcher::shouldPruneInboundQueueLocked(const MotionEntry& motionEnt
motionEntry.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X));
int32_t y = static_cast<int32_t>(
motionEntry.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y));
- sp<InputWindowHandle> touchedWindowHandle =
+ sp<WindowInfoHandle> touchedWindowHandle =
findTouchedWindowAtLocked(displayId, x, y, nullptr);
if (touchedWindowHandle != nullptr &&
touchedWindowHandle->getApplicationToken() !=
@@ -989,29 +1002,29 @@ void InputDispatcher::addRecentEventLocked(std::shared_ptr<EventEntry> entry) {
}
}
-sp<InputWindowHandle> InputDispatcher::findTouchedWindowAtLocked(int32_t displayId, int32_t x,
- int32_t y, TouchState* touchState,
- bool addOutsideTargets,
- bool addPortalWindows,
- bool ignoreDragWindow) {
+sp<WindowInfoHandle> InputDispatcher::findTouchedWindowAtLocked(int32_t displayId, int32_t x,
+ int32_t y, TouchState* touchState,
+ bool addOutsideTargets,
+ bool addPortalWindows,
+ bool ignoreDragWindow) {
if ((addPortalWindows || addOutsideTargets) && touchState == nullptr) {
LOG_ALWAYS_FATAL(
"Must provide a valid touch state if adding portal windows or outside targets");
}
// Traverse windows from front to back to find touched window.
- const std::vector<sp<InputWindowHandle>>& windowHandles = getWindowHandlesLocked(displayId);
- for (const sp<InputWindowHandle>& windowHandle : windowHandles) {
+ const std::vector<sp<WindowInfoHandle>>& windowHandles = getWindowHandlesLocked(displayId);
+ for (const sp<WindowInfoHandle>& windowHandle : windowHandles) {
if (ignoreDragWindow && haveSameToken(windowHandle, mDragState->dragWindow)) {
continue;
}
- const InputWindowInfo* windowInfo = windowHandle->getInfo();
+ const WindowInfo* windowInfo = windowHandle->getInfo();
if (windowInfo->displayId == displayId) {
auto flags = windowInfo->flags;
if (windowInfo->visible) {
- if (!flags.test(InputWindowInfo::Flag::NOT_TOUCHABLE)) {
- bool isTouchModal = !flags.test(InputWindowInfo::Flag::NOT_FOCUSABLE) &&
- !flags.test(InputWindowInfo::Flag::NOT_TOUCH_MODAL);
+ if (!flags.test(WindowInfo::Flag::NOT_TOUCHABLE)) {
+ bool isTouchModal = !flags.test(WindowInfo::Flag::NOT_FOCUSABLE) &&
+ !flags.test(WindowInfo::Flag::NOT_TOUCH_MODAL);
if (isTouchModal || windowInfo->touchableRegionContainsPoint(x, y)) {
int32_t portalToDisplayId = windowInfo->portalToDisplayId;
if (portalToDisplayId != ADISPLAY_ID_NONE &&
@@ -1028,7 +1041,7 @@ sp<InputWindowHandle> InputDispatcher::findTouchedWindowAtLocked(int32_t display
}
}
- if (addOutsideTargets && flags.test(InputWindowInfo::Flag::WATCH_OUTSIDE_TOUCH)) {
+ if (addOutsideTargets && flags.test(WindowInfo::Flag::WATCH_OUTSIDE_TOUCH)) {
touchState->addOrUpdateWindow(windowHandle,
InputTarget::FLAG_DISPATCH_AS_OUTSIDE,
BitSet32(0));
@@ -1040,13 +1053,13 @@ sp<InputWindowHandle> InputDispatcher::findTouchedWindowAtLocked(int32_t display
}
std::vector<TouchedMonitor> InputDispatcher::findTouchedGestureMonitorsLocked(
- int32_t displayId, const std::vector<sp<InputWindowHandle>>& portalWindows) const {
+ int32_t displayId, const std::vector<sp<WindowInfoHandle>>& portalWindows) const {
std::vector<TouchedMonitor> touchedMonitors;
std::vector<Monitor> monitors = getValueByKey(mGestureMonitorsByDisplay, displayId);
addGestureMonitors(monitors, touchedMonitors);
- for (const sp<InputWindowHandle>& portalWindow : portalWindows) {
- const InputWindowInfo* windowInfo = portalWindow->getInfo();
+ for (const sp<WindowInfoHandle>& portalWindow : portalWindows) {
+ const WindowInfo* windowInfo = portalWindow->getInfo();
monitors = getValueByKey(mGestureMonitorsByDisplay, windowInfo->portalToDisplayId);
addGestureMonitors(monitors, touchedMonitors, -windowInfo->frameLeft,
-windowInfo->frameTop);
@@ -1609,7 +1622,7 @@ bool InputDispatcher::dispatchMotionLocked(nsecs_t currentTime, std::shared_ptr<
// The event has gone through these portal windows, so we add monitoring targets of
// the corresponding displays as well.
for (size_t i = 0; i < state.portalWindows.size(); i++) {
- const InputWindowInfo* windowInfo = state.portalWindows[i]->getInfo();
+ const WindowInfo* windowInfo = state.portalWindows[i]->getInfo();
addGlobalMonitoringTargetsLocked(inputTargets, windowInfo->portalToDisplayId,
-windowInfo->frameLeft, -windowInfo->frameTop);
}
@@ -1627,7 +1640,7 @@ bool InputDispatcher::dispatchMotionLocked(nsecs_t currentTime, std::shared_ptr<
return true;
}
-void InputDispatcher::enqueueDragEventLocked(const sp<InputWindowHandle>& windowHandle,
+void InputDispatcher::enqueueDragEventLocked(const sp<WindowInfoHandle>& windowHandle,
bool isExiting, const MotionEntry& motionEntry) {
// If the window needs enqueue a drag event, the pointerCount should be 1 and the action should
// be AMOTION_EVENT_ACTION_MOVE, that could guarantee the first pointer is always valid.
@@ -1807,7 +1820,7 @@ InputEventInjectionResult InputDispatcher::findFocusedWindowTargetsLocked(
std::string reason;
int32_t displayId = getTargetDisplayId(entry);
- sp<InputWindowHandle> focusedWindowHandle = getFocusedWindowHandleLocked(displayId);
+ sp<WindowInfoHandle> focusedWindowHandle = getFocusedWindowHandleLocked(displayId);
std::shared_ptr<InputApplicationHandle> focusedApplicationHandle =
getValueByKey(mFocusedApplicationHandlesByDisplay, displayId);
@@ -1820,6 +1833,11 @@ InputEventInjectionResult InputDispatcher::findFocusedWindowTargetsLocked(
return InputEventInjectionResult::FAILED;
}
+ // Drop key events if requested by input feature
+ if (focusedWindowHandle != nullptr && shouldDropInput(entry, focusedWindowHandle)) {
+ return InputEventInjectionResult::FAILED;
+ }
+
// Compatibility behavior: raise ANR if there is a focused application, but no focused window.
// Only start counting when we have a focused event to dispatch. The ANR is canceled if we
// start interacting with another application via touch (app switch). This code can be removed
@@ -1934,8 +1952,8 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked(
// Update the touch state as needed based on the properties of the touch event.
InputEventInjectionResult injectionResult = InputEventInjectionResult::PENDING;
InjectionPermission injectionPermission = INJECTION_PERMISSION_UNKNOWN;
- sp<InputWindowHandle> newHoverWindowHandle(mLastHoverWindowHandle);
- sp<InputWindowHandle> newTouchedWindowHandle;
+ sp<WindowInfoHandle> newHoverWindowHandle(mLastHoverWindowHandle);
+ sp<WindowInfoHandle> newTouchedWindowHandle;
// Copy current touch state into tempTouchState.
// This state will be used to update mTouchStatesByDisplay at the end of this function.
@@ -2008,10 +2026,6 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked(
findTouchedWindowAtLocked(displayId, x, y, &tempTouchState,
isDown /*addOutsideTargets*/, true /*addPortalWindows*/);
- std::vector<TouchedMonitor> newGestureMonitors = isDown
- ? findTouchedGestureMonitorsLocked(displayId, tempTouchState.portalWindows)
- : std::vector<TouchedMonitor>{};
-
// Figure out whether splitting will be allowed for this window.
if (newTouchedWindowHandle != nullptr &&
newTouchedWindowHandle->getInfo()->supportsSplitTouch()) {
@@ -2066,8 +2080,15 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked(
}
}
- // Also don't send the new touch event to unresponsive gesture monitors
- newGestureMonitors = selectResponsiveMonitorsLocked(newGestureMonitors);
+ // Drop touch events if requested by input feature
+ if (newTouchedWindowHandle != nullptr && shouldDropInput(entry, newTouchedWindowHandle)) {
+ newTouchedWindowHandle = nullptr;
+ }
+
+ const std::vector<TouchedMonitor> newGestureMonitors = isDown
+ ? selectResponsiveMonitorsLocked(
+ findTouchedGestureMonitorsLocked(displayId, tempTouchState.portalWindows))
+ : tempTouchState.gestureMonitors;
if (newTouchedWindowHandle == nullptr && newGestureMonitors.empty()) {
ALOGI("Dropping event because there is no touchable window or gesture monitor at "
@@ -2103,9 +2124,14 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked(
pointerIds.markBit(pointerId);
}
tempTouchState.addOrUpdateWindow(newTouchedWindowHandle, targetFlags, pointerIds);
+ } else if (tempTouchState.windows.empty()) {
+ // If no window is touched, set split to true. This will allow the next pointer down to
+ // be delivered to a new window which supports split touch.
+ tempTouchState.split = true;
+ }
+ if (isDown) {
+ tempTouchState.addGestureMonitors(newGestureMonitors);
}
-
- tempTouchState.addGestureMonitors(newGestureMonitors);
} else {
/* Case 2: Pointer move, up, cancel or non-splittable pointer down. */
@@ -2128,9 +2154,16 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked(
int32_t x = int32_t(entry.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X));
int32_t y = int32_t(entry.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y));
- sp<InputWindowHandle> oldTouchedWindowHandle =
+ sp<WindowInfoHandle> oldTouchedWindowHandle =
tempTouchState.getFirstForegroundWindowHandle();
newTouchedWindowHandle = findTouchedWindowAtLocked(displayId, x, y, &tempTouchState);
+
+ // Drop touch events if requested by input feature
+ if (newTouchedWindowHandle != nullptr &&
+ shouldDropInput(entry, newTouchedWindowHandle)) {
+ newTouchedWindowHandle = nullptr;
+ }
+
if (oldTouchedWindowHandle != newTouchedWindowHandle &&
oldTouchedWindowHandle != nullptr && newTouchedWindowHandle != nullptr) {
if (DEBUG_FOCUS) {
@@ -2227,15 +2260,15 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked(
// Check whether windows listening for outside touches are owned by the same UID. If it is
// set the policy flag that we will not reveal coordinate information to this window.
if (maskedAction == AMOTION_EVENT_ACTION_DOWN) {
- sp<InputWindowHandle> foregroundWindowHandle =
+ sp<WindowInfoHandle> foregroundWindowHandle =
tempTouchState.getFirstForegroundWindowHandle();
if (foregroundWindowHandle) {
const int32_t foregroundWindowUid = foregroundWindowHandle->getInfo()->ownerUid;
for (const TouchedWindow& touchedWindow : tempTouchState.windows) {
if (touchedWindow.targetFlags & InputTarget::FLAG_DISPATCH_AS_OUTSIDE) {
- sp<InputWindowHandle> inputWindowHandle = touchedWindow.windowHandle;
- if (inputWindowHandle->getInfo()->ownerUid != foregroundWindowUid) {
- tempTouchState.addOrUpdateWindow(inputWindowHandle,
+ sp<WindowInfoHandle> windowInfoHandle = touchedWindow.windowHandle;
+ if (windowInfoHandle->getInfo()->ownerUid != foregroundWindowUid) {
+ tempTouchState.addOrUpdateWindow(windowInfoHandle,
InputTarget::FLAG_ZERO_COORDS,
BitSet32(0));
}
@@ -2251,15 +2284,15 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked(
// engine only supports touch events. We would need to add a mechanism similar
// to View.onGenericMotionEvent to enable wallpapers to handle these events.
if (maskedAction == AMOTION_EVENT_ACTION_DOWN) {
- sp<InputWindowHandle> foregroundWindowHandle =
+ sp<WindowInfoHandle> foregroundWindowHandle =
tempTouchState.getFirstForegroundWindowHandle();
if (foregroundWindowHandle && foregroundWindowHandle->getInfo()->hasWallpaper) {
- const std::vector<sp<InputWindowHandle>>& windowHandles =
+ const std::vector<sp<WindowInfoHandle>>& windowHandles =
getWindowHandlesLocked(displayId);
- for (const sp<InputWindowHandle>& windowHandle : windowHandles) {
- const InputWindowInfo* info = windowHandle->getInfo();
+ for (const sp<WindowInfoHandle>& windowHandle : windowHandles) {
+ const WindowInfo* info = windowHandle->getInfo();
if (info->displayId == displayId &&
- windowHandle->getInfo()->type == InputWindowInfo::Type::WALLPAPER) {
+ windowHandle->getInfo()->type == WindowInfo::Type::WALLPAPER) {
tempTouchState
.addOrUpdateWindow(windowHandle,
InputTarget::FLAG_WINDOW_IS_OBSCURED |
@@ -2378,7 +2411,7 @@ Failed:
}
void InputDispatcher::finishDragAndDrop(int32_t displayId, float x, float y) {
- const sp<InputWindowHandle> dropWindow =
+ const sp<WindowInfoHandle> dropWindow =
findTouchedWindowAtLocked(displayId, x, y, nullptr /*touchState*/,
false /*addOutsideTargets*/, false /*addPortalWindows*/,
true /*ignoreDragWindow*/);
@@ -2413,7 +2446,7 @@ void InputDispatcher::addDragEventLocked(const MotionEntry& entry) {
return;
}
- const sp<InputWindowHandle> hoverWindowHandle =
+ const sp<WindowInfoHandle> hoverWindowHandle =
findTouchedWindowAtLocked(entry.displayId, x, y, nullptr /*touchState*/,
false /*addOutsideTargets*/, false /*addPortalWindows*/,
true /*ignoreDragWindow*/);
@@ -2438,7 +2471,7 @@ void InputDispatcher::addDragEventLocked(const MotionEntry& entry) {
}
}
-void InputDispatcher::addWindowTargetLocked(const sp<InputWindowHandle>& windowHandle,
+void InputDispatcher::addWindowTargetLocked(const sp<WindowInfoHandle>& windowHandle,
int32_t targetFlags, BitSet32 pointerIds,
std::vector<InputTarget>& inputTargets) {
std::vector<InputTarget>::iterator it =
@@ -2448,7 +2481,7 @@ void InputDispatcher::addWindowTargetLocked(const sp<InputWindowHandle>& windowH
windowHandle->getToken();
});
- const InputWindowInfo* windowInfo = windowHandle->getInfo();
+ const WindowInfo* windowInfo = windowHandle->getInfo();
if (it == inputTargets.end()) {
InputTarget inputTarget;
@@ -2461,6 +2494,7 @@ void InputDispatcher::addWindowTargetLocked(const sp<InputWindowHandle>& windowH
inputTarget.inputChannel = inputChannel;
inputTarget.flags = targetFlags;
inputTarget.globalScaleFactor = windowInfo->globalScaleFactor;
+ inputTarget.displayOrientation = windowInfo->displayOrientation;
inputTarget.displaySize =
int2(windowHandle->getInfo()->displayWidth, windowHandle->getInfo()->displayHeight);
inputTargets.push_back(inputTarget);
@@ -2499,7 +2533,7 @@ void InputDispatcher::addMonitoringTargetLocked(const Monitor& monitor, float xO
inputTargets.push_back(target);
}
-bool InputDispatcher::checkInjectionPermission(const sp<InputWindowHandle>& windowHandle,
+bool InputDispatcher::checkInjectionPermission(const sp<WindowInfoHandle>& windowHandle,
const InjectionState* injectionState) {
if (injectionState &&
(windowHandle == nullptr ||
@@ -2524,8 +2558,8 @@ bool InputDispatcher::checkInjectionPermission(const sp<InputWindowHandle>& wind
* another window handle. We only check a few preconditions. Actually
* checking the bounds is left to the caller.
*/
-static bool canBeObscuredBy(const sp<InputWindowHandle>& windowHandle,
- const sp<InputWindowHandle>& otherHandle) {
+static bool canBeObscuredBy(const sp<WindowInfoHandle>& windowHandle,
+ const sp<WindowInfoHandle>& otherHandle) {
// Compare by token so cloned layers aren't counted
if (haveSameToken(windowHandle, otherHandle)) {
return false;
@@ -2534,8 +2568,7 @@ static bool canBeObscuredBy(const sp<InputWindowHandle>& windowHandle,
auto otherInfo = otherHandle->getInfo();
if (!otherInfo->visible) {
return false;
- } else if (otherInfo->alpha == 0 &&
- otherInfo->flags.test(InputWindowInfo::Flag::NOT_TOUCHABLE)) {
+ } else if (otherInfo->alpha == 0 && otherInfo->flags.test(WindowInfo::Flag::NOT_TOUCHABLE)) {
// Those act as if they were invisible, so we don't need to flag them.
// We do want to potentially flag touchable windows even if they have 0
// opacity, since they can consume touches and alter the effects of the
@@ -2573,20 +2606,20 @@ static bool canBeObscuredBy(const sp<InputWindowHandle>& windowHandle,
* If neither of those is true, then it means the touch can be allowed.
*/
InputDispatcher::TouchOcclusionInfo InputDispatcher::computeTouchOcclusionInfoLocked(
- const sp<InputWindowHandle>& windowHandle, int32_t x, int32_t y) const {
- const InputWindowInfo* windowInfo = windowHandle->getInfo();
+ const sp<WindowInfoHandle>& windowHandle, int32_t x, int32_t y) const {
+ const WindowInfo* windowInfo = windowHandle->getInfo();
int32_t displayId = windowInfo->displayId;
- const std::vector<sp<InputWindowHandle>>& windowHandles = getWindowHandlesLocked(displayId);
+ const std::vector<sp<WindowInfoHandle>>& windowHandles = getWindowHandlesLocked(displayId);
TouchOcclusionInfo info;
info.hasBlockingOcclusion = false;
info.obscuringOpacity = 0;
info.obscuringUid = -1;
std::map<int32_t, float> opacityByUid;
- for (const sp<InputWindowHandle>& otherHandle : windowHandles) {
+ for (const sp<WindowInfoHandle>& otherHandle : windowHandles) {
if (windowHandle == otherHandle) {
break; // All future windows are below us. Exit early.
}
- const InputWindowInfo* otherInfo = otherHandle->getInfo();
+ const WindowInfo* otherInfo = otherHandle->getInfo();
if (canBeObscuredBy(windowHandle, otherHandle) && otherInfo->frameContainsPoint(x, y) &&
!haveSameApplicationToken(windowInfo, otherInfo)) {
if (DEBUG_TOUCH_OCCLUSION) {
@@ -2625,7 +2658,7 @@ InputDispatcher::TouchOcclusionInfo InputDispatcher::computeTouchOcclusionInfoLo
return info;
}
-std::string InputDispatcher::dumpWindowForTouchOcclusion(const InputWindowInfo* info,
+std::string InputDispatcher::dumpWindowForTouchOcclusion(const WindowInfo* info,
bool isTouchedWindow) const {
return StringPrintf(INDENT2
"* %stype=%s, package=%s/%" PRId32 ", id=%" PRId32 ", mode=%s, alpha=%.2f, "
@@ -2659,15 +2692,15 @@ bool InputDispatcher::isTouchTrustedLocked(const TouchOcclusionInfo& occlusionIn
return true;
}
-bool InputDispatcher::isWindowObscuredAtPointLocked(const sp<InputWindowHandle>& windowHandle,
+bool InputDispatcher::isWindowObscuredAtPointLocked(const sp<WindowInfoHandle>& windowHandle,
int32_t x, int32_t y) const {
int32_t displayId = windowHandle->getInfo()->displayId;
- const std::vector<sp<InputWindowHandle>>& windowHandles = getWindowHandlesLocked(displayId);
- for (const sp<InputWindowHandle>& otherHandle : windowHandles) {
+ const std::vector<sp<WindowInfoHandle>>& windowHandles = getWindowHandlesLocked(displayId);
+ for (const sp<WindowInfoHandle>& otherHandle : windowHandles) {
if (windowHandle == otherHandle) {
break; // All future windows are below us. Exit early.
}
- const InputWindowInfo* otherInfo = otherHandle->getInfo();
+ const WindowInfo* otherInfo = otherHandle->getInfo();
if (canBeObscuredBy(windowHandle, otherHandle) &&
otherInfo->frameContainsPoint(x, y)) {
return true;
@@ -2676,15 +2709,15 @@ bool InputDispatcher::isWindowObscuredAtPointLocked(const sp<InputWindowHandle>&
return false;
}
-bool InputDispatcher::isWindowObscuredLocked(const sp<InputWindowHandle>& windowHandle) const {
+bool InputDispatcher::isWindowObscuredLocked(const sp<WindowInfoHandle>& windowHandle) const {
int32_t displayId = windowHandle->getInfo()->displayId;
- const std::vector<sp<InputWindowHandle>>& windowHandles = getWindowHandlesLocked(displayId);
- const InputWindowInfo* windowInfo = windowHandle->getInfo();
- for (const sp<InputWindowHandle>& otherHandle : windowHandles) {
+ const std::vector<sp<WindowInfoHandle>>& windowHandles = getWindowHandlesLocked(displayId);
+ const WindowInfo* windowInfo = windowHandle->getInfo();
+ for (const sp<WindowInfoHandle>& otherHandle : windowHandles) {
if (windowHandle == otherHandle) {
break; // All future windows are below us. Exit early.
}
- const InputWindowInfo* otherInfo = otherHandle->getInfo();
+ const WindowInfo* otherInfo = otherHandle->getInfo();
if (canBeObscuredBy(windowHandle, otherHandle) &&
otherInfo->overlaps(windowInfo)) {
return true;
@@ -2694,8 +2727,7 @@ bool InputDispatcher::isWindowObscuredLocked(const sp<InputWindowHandle>& window
}
std::string InputDispatcher::getApplicationWindowLabel(
- const InputApplicationHandle* applicationHandle,
- const sp<InputWindowHandle>& windowHandle) {
+ const InputApplicationHandle* applicationHandle, const sp<WindowInfoHandle>& windowHandle) {
if (applicationHandle != nullptr) {
if (windowHandle != nullptr) {
return applicationHandle->getName() + " - " + windowHandle->getName();
@@ -2718,10 +2750,10 @@ void InputDispatcher::pokeUserActivityLocked(const EventEntry& eventEntry) {
return;
}
int32_t displayId = getTargetDisplayId(eventEntry);
- sp<InputWindowHandle> focusedWindowHandle = getFocusedWindowHandleLocked(displayId);
+ sp<WindowInfoHandle> focusedWindowHandle = getFocusedWindowHandleLocked(displayId);
if (focusedWindowHandle != nullptr) {
- const InputWindowInfo* info = focusedWindowHandle->getInfo();
- if (info->inputFeatures.test(InputWindowInfo::Feature::DISABLE_USER_ACTIVITY)) {
+ const WindowInfo* info = focusedWindowHandle->getInfo();
+ if (info->inputFeatures.test(WindowInfo::Feature::DISABLE_USER_ACTIVITY)) {
#if DEBUG_DISPATCH_CYCLE
ALOGD("Not poking user activity: disabled by window '%s'.", info->name.c_str());
#endif
@@ -3176,6 +3208,7 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
motionEntry.xPrecision, motionEntry.yPrecision,
motionEntry.xCursorPosition,
motionEntry.yCursorPosition,
+ dispatchEntry->displayOrientation,
dispatchEntry->displaySize.x,
dispatchEntry->displaySize.y,
motionEntry.downTime, motionEntry.eventTime,
@@ -3492,10 +3525,10 @@ void InputDispatcher::synthesizeCancelationEventsForConnectionLocked(
#endif
InputTarget target;
- sp<InputWindowHandle> windowHandle =
+ sp<WindowInfoHandle> windowHandle =
getWindowHandleLocked(connection->inputChannel->getConnectionToken());
if (windowHandle != nullptr) {
- const InputWindowInfo* windowInfo = windowHandle->getInfo();
+ const WindowInfo* windowInfo = windowHandle->getInfo();
target.setDefaultPointerTransform(windowInfo->transform);
target.globalScaleFactor = windowInfo->globalScaleFactor;
}
@@ -3559,10 +3592,10 @@ void InputDispatcher::synthesizePointerDownEventsForConnectionLocked(
#endif
InputTarget target;
- sp<InputWindowHandle> windowHandle =
+ sp<WindowInfoHandle> windowHandle =
getWindowHandleLocked(connection->inputChannel->getConnectionToken());
if (windowHandle != nullptr) {
- const InputWindowInfo* windowInfo = windowHandle->getInfo();
+ const WindowInfo* windowInfo = windowHandle->getInfo();
target.setDefaultPointerTransform(windowInfo->transform);
target.globalScaleFactor = windowInfo->globalScaleFactor;
}
@@ -3888,8 +3921,8 @@ void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) {
args->action, args->actionButton, args->flags, args->edgeFlags,
args->metaState, args->buttonState, args->classification, transform,
args->xPrecision, args->yPrecision, args->xCursorPosition,
- args->yCursorPosition, AMOTION_EVENT_INVALID_DISPLAY_SIZE,
- AMOTION_EVENT_INVALID_DISPLAY_SIZE, args->downTime, args->eventTime,
+ args->yCursorPosition, ui::Transform::ROT_0, INVALID_DISPLAY_SIZE,
+ INVALID_DISPLAY_SIZE, args->downTime, args->eventTime,
args->pointerCount, args->pointerProperties, args->pointerCoords);
policyFlags |= POLICY_FLAG_FILTERED;
@@ -4340,22 +4373,22 @@ void InputDispatcher::decrementPendingForegroundDispatches(EventEntry& entry) {
}
}
-const std::vector<sp<InputWindowHandle>>& InputDispatcher::getWindowHandlesLocked(
+const std::vector<sp<WindowInfoHandle>>& InputDispatcher::getWindowHandlesLocked(
int32_t displayId) const {
- static const std::vector<sp<InputWindowHandle>> EMPTY_WINDOW_HANDLES;
+ static const std::vector<sp<WindowInfoHandle>> EMPTY_WINDOW_HANDLES;
auto it = mWindowHandlesByDisplay.find(displayId);
return it != mWindowHandlesByDisplay.end() ? it->second : EMPTY_WINDOW_HANDLES;
}
-sp<InputWindowHandle> InputDispatcher::getWindowHandleLocked(
+sp<WindowInfoHandle> InputDispatcher::getWindowHandleLocked(
const sp<IBinder>& windowHandleToken) const {
if (windowHandleToken == nullptr) {
return nullptr;
}
for (auto& it : mWindowHandlesByDisplay) {
- const std::vector<sp<InputWindowHandle>>& windowHandles = it.second;
- for (const sp<InputWindowHandle>& windowHandle : windowHandles) {
+ const std::vector<sp<WindowInfoHandle>>& windowHandles = it.second;
+ for (const sp<WindowInfoHandle>& windowHandle : windowHandles) {
if (windowHandle->getToken() == windowHandleToken) {
return windowHandle;
}
@@ -4364,13 +4397,13 @@ sp<InputWindowHandle> InputDispatcher::getWindowHandleLocked(
return nullptr;
}
-sp<InputWindowHandle> InputDispatcher::getWindowHandleLocked(const sp<IBinder>& windowHandleToken,
- int displayId) const {
+sp<WindowInfoHandle> InputDispatcher::getWindowHandleLocked(const sp<IBinder>& windowHandleToken,
+ int displayId) const {
if (windowHandleToken == nullptr) {
return nullptr;
}
- for (const sp<InputWindowHandle>& windowHandle : getWindowHandlesLocked(displayId)) {
+ for (const sp<WindowInfoHandle>& windowHandle : getWindowHandlesLocked(displayId)) {
if (windowHandle->getToken() == windowHandleToken) {
return windowHandle;
}
@@ -4378,11 +4411,11 @@ sp<InputWindowHandle> InputDispatcher::getWindowHandleLocked(const sp<IBinder>&
return nullptr;
}
-sp<InputWindowHandle> InputDispatcher::getWindowHandleLocked(
- const sp<InputWindowHandle>& windowHandle) const {
+sp<WindowInfoHandle> InputDispatcher::getWindowHandleLocked(
+ const sp<WindowInfoHandle>& windowHandle) const {
for (auto& it : mWindowHandlesByDisplay) {
- const std::vector<sp<InputWindowHandle>>& windowHandles = it.second;
- for (const sp<InputWindowHandle>& handle : windowHandles) {
+ const std::vector<sp<WindowInfoHandle>>& windowHandles = it.second;
+ for (const sp<WindowInfoHandle>& handle : windowHandles) {
if (handle->getId() == windowHandle->getId() &&
handle->getToken() == windowHandle->getToken()) {
if (windowHandle->getInfo()->displayId != it.first) {
@@ -4398,15 +4431,15 @@ sp<InputWindowHandle> InputDispatcher::getWindowHandleLocked(
return nullptr;
}
-sp<InputWindowHandle> InputDispatcher::getFocusedWindowHandleLocked(int displayId) const {
+sp<WindowInfoHandle> InputDispatcher::getFocusedWindowHandleLocked(int displayId) const {
sp<IBinder> focusedToken = mFocusResolver.getFocusedWindowToken(displayId);
return getWindowHandleLocked(focusedToken, displayId);
}
-bool InputDispatcher::hasResponsiveConnectionLocked(InputWindowHandle& windowHandle) const {
+bool InputDispatcher::hasResponsiveConnectionLocked(WindowInfoHandle& windowHandle) const {
sp<Connection> connection = getConnectionLocked(windowHandle.getToken());
const bool noInputChannel =
- windowHandle.getInfo()->inputFeatures.test(InputWindowInfo::Feature::NO_INPUT_CHANNEL);
+ windowHandle.getInfo()->inputFeatures.test(WindowInfo::Feature::NO_INPUT_CHANNEL);
if (connection != nullptr && noInputChannel) {
ALOGW("%s has feature NO_INPUT_CHANNEL, but it matched to connection %s",
windowHandle.getName().c_str(), connection->inputChannel->getName().c_str());
@@ -4436,8 +4469,8 @@ std::shared_ptr<InputChannel> InputDispatcher::getInputChannelLocked(
}
void InputDispatcher::updateWindowHandlesForDisplayLocked(
- const std::vector<sp<InputWindowHandle>>& inputWindowHandles, int32_t displayId) {
- if (inputWindowHandles.empty()) {
+ const std::vector<sp<WindowInfoHandle>>& windowInfoHandles, int32_t displayId) {
+ if (windowInfoHandles.empty()) {
// Remove all handles on a display if there are no windows left.
mWindowHandlesByDisplay.erase(displayId);
return;
@@ -4445,26 +4478,21 @@ void InputDispatcher::updateWindowHandlesForDisplayLocked(
// Since we compare the pointer of input window handles across window updates, we need
// to make sure the handle object for the same window stays unchanged across updates.
- const std::vector<sp<InputWindowHandle>>& oldHandles = getWindowHandlesLocked(displayId);
- std::unordered_map<int32_t /*id*/, sp<InputWindowHandle>> oldHandlesById;
- for (const sp<InputWindowHandle>& handle : oldHandles) {
+ const std::vector<sp<WindowInfoHandle>>& oldHandles = getWindowHandlesLocked(displayId);
+ std::unordered_map<int32_t /*id*/, sp<WindowInfoHandle>> oldHandlesById;
+ for (const sp<WindowInfoHandle>& handle : oldHandles) {
oldHandlesById[handle->getId()] = handle;
}
- std::vector<sp<InputWindowHandle>> newHandles;
- for (const sp<InputWindowHandle>& handle : inputWindowHandles) {
- if (!handle->updateInfo()) {
- // handle no longer valid
- continue;
- }
-
- const InputWindowInfo* info = handle->getInfo();
+ std::vector<sp<WindowInfoHandle>> newHandles;
+ for (const sp<WindowInfoHandle>& handle : windowInfoHandles) {
+ const WindowInfo* info = handle->getInfo();
if ((getInputChannelLocked(handle->getToken()) == nullptr &&
info->portalToDisplayId == ADISPLAY_ID_NONE)) {
const bool noInputChannel =
- info->inputFeatures.test(InputWindowInfo::Feature::NO_INPUT_CHANNEL);
- const bool canReceiveInput = !info->flags.test(InputWindowInfo::Flag::NOT_TOUCHABLE) ||
- !info->flags.test(InputWindowInfo::Flag::NOT_FOCUSABLE);
+ info->inputFeatures.test(WindowInfo::Feature::NO_INPUT_CHANNEL);
+ const bool canReceiveInput = !info->flags.test(WindowInfo::Flag::NOT_TOUCHABLE) ||
+ !info->flags.test(WindowInfo::Flag::NOT_FOCUSABLE);
if (canReceiveInput && !noInputChannel) {
ALOGV("Window handle %s has no registered input channel",
handle->getName().c_str());
@@ -4480,7 +4508,7 @@ void InputDispatcher::updateWindowHandlesForDisplayLocked(
if ((oldHandlesById.find(handle->getId()) != oldHandlesById.end()) &&
(oldHandlesById.at(handle->getId())->getToken() == handle->getToken())) {
- const sp<InputWindowHandle>& oldHandle = oldHandlesById.at(handle->getId());
+ const sp<WindowInfoHandle>& oldHandle = oldHandlesById.at(handle->getId());
oldHandle->updateFrom(handle);
newHandles.push_back(oldHandle);
} else {
@@ -4493,7 +4521,7 @@ void InputDispatcher::updateWindowHandlesForDisplayLocked(
}
void InputDispatcher::setInputWindows(
- const std::unordered_map<int32_t, std::vector<sp<InputWindowHandle>>>& handlesPerDisplay) {
+ const std::unordered_map<int32_t, std::vector<sp<WindowInfoHandle>>>& handlesPerDisplay) {
{ // acquire lock
std::scoped_lock _l(mLock);
for (const auto& [displayId, handles] : handlesPerDisplay) {
@@ -4512,19 +4540,19 @@ void InputDispatcher::setInputWindows(
* For removed handle, check if need to send a cancel event if already in touch.
*/
void InputDispatcher::setInputWindowsLocked(
- const std::vector<sp<InputWindowHandle>>& inputWindowHandles, int32_t displayId) {
+ const std::vector<sp<WindowInfoHandle>>& windowInfoHandles, int32_t displayId) {
if (DEBUG_FOCUS) {
std::string windowList;
- for (const sp<InputWindowHandle>& iwh : inputWindowHandles) {
+ for (const sp<WindowInfoHandle>& iwh : windowInfoHandles) {
windowList += iwh->getName() + " ";
}
ALOGD("setInputWindows displayId=%" PRId32 " %s", displayId, windowList.c_str());
}
// Ensure all tokens are null if the window has feature NO_INPUT_CHANNEL
- for (const sp<InputWindowHandle>& window : inputWindowHandles) {
+ for (const sp<WindowInfoHandle>& window : windowInfoHandles) {
const bool noInputWindow =
- window->getInfo()->inputFeatures.test(InputWindowInfo::Feature::NO_INPUT_CHANNEL);
+ window->getInfo()->inputFeatures.test(WindowInfo::Feature::NO_INPUT_CHANNEL);
if (noInputWindow && window->getToken() != nullptr) {
ALOGE("%s has feature NO_INPUT_WINDOW, but a non-null token. Clearing",
window->getName().c_str());
@@ -4533,18 +4561,18 @@ void InputDispatcher::setInputWindowsLocked(
}
// Copy old handles for release if they are no longer present.
- const std::vector<sp<InputWindowHandle>> oldWindowHandles = getWindowHandlesLocked(displayId);
+ const std::vector<sp<WindowInfoHandle>> oldWindowHandles = getWindowHandlesLocked(displayId);
// Save the old windows' orientation by ID before it gets updated.
std::unordered_map<int32_t, uint32_t> oldWindowOrientations;
- for (const sp<InputWindowHandle>& handle : oldWindowHandles) {
+ for (const sp<WindowInfoHandle>& handle : oldWindowHandles) {
oldWindowOrientations.emplace(handle->getId(),
handle->getInfo()->transform.getOrientation());
}
- updateWindowHandlesForDisplayLocked(inputWindowHandles, displayId);
+ updateWindowHandlesForDisplayLocked(windowInfoHandles, displayId);
- const std::vector<sp<InputWindowHandle>>& windowHandles = getWindowHandlesLocked(displayId);
+ const std::vector<sp<WindowInfoHandle>>& windowHandles = getWindowHandlesLocked(displayId);
if (mLastHoverWindowHandle &&
std::find(windowHandles.begin(), windowHandles.end(), mLastHoverWindowHandle) ==
windowHandles.end()) {
@@ -4593,8 +4621,8 @@ void InputDispatcher::setInputWindowsLocked(
if (isPerWindowInputRotationEnabled()) {
// Determine if the orientation of any of the input windows have changed, and cancel all
// pointer events if necessary.
- for (const sp<InputWindowHandle>& oldWindowHandle : oldWindowHandles) {
- const sp<InputWindowHandle> newWindowHandle = getWindowHandleLocked(oldWindowHandle);
+ for (const sp<WindowInfoHandle>& oldWindowHandle : oldWindowHandles) {
+ const sp<WindowInfoHandle> newWindowHandle = getWindowHandleLocked(oldWindowHandle);
if (newWindowHandle != nullptr &&
newWindowHandle->getInfo()->transform.getOrientation() !=
oldWindowOrientations[oldWindowHandle->getId()]) {
@@ -4613,7 +4641,7 @@ void InputDispatcher::setInputWindowsLocked(
// This ensures that unused input channels are released promptly.
// Otherwise, they might stick around until the window handle is destroyed
// which might not happen until the next GC.
- for (const sp<InputWindowHandle>& oldWindowHandle : oldWindowHandles) {
+ for (const sp<WindowInfoHandle>& oldWindowHandle : oldWindowHandles) {
if (getWindowHandleLocked(oldWindowHandle) == nullptr) {
if (DEBUG_FOCUS) {
ALOGD("Window went away: %s", oldWindowHandle->getName().c_str());
@@ -4623,7 +4651,7 @@ void InputDispatcher::setInputWindowsLocked(
// check for window flags when windows are going away.
// TODO(b/157929241) : delete this. This is only needed temporarily
// in order to gather some data about the flag usage
- if (oldWindowHandle->getInfo()->flags.test(InputWindowInfo::Flag::SLIPPERY)) {
+ if (oldWindowHandle->getInfo()->flags.test(WindowInfo::Flag::SLIPPERY)) {
ALOGW("%s has FLAG_SLIPPERY. Please report this in b/157929241",
oldWindowHandle->getName().c_str());
if (mCompatService != nullptr) {
@@ -4801,6 +4829,18 @@ void InputDispatcher::setBlockUntrustedTouchesMode(BlockUntrustedTouchesMode mod
mBlockUntrustedTouchesMode = mode;
}
+std::pair<TouchState*, TouchedWindow*> InputDispatcher::findTouchStateAndWindowLocked(
+ const sp<IBinder>& token) {
+ for (auto& [displayId, state] : mTouchStatesByDisplay) {
+ for (TouchedWindow& w : state.windows) {
+ if (w.windowHandle->getToken() == token) {
+ return std::make_pair(&state, &w);
+ }
+ }
+ }
+ return std::make_pair(nullptr, nullptr);
+}
+
bool InputDispatcher::transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken,
bool isDragDrop) {
if (fromToken == toToken) {
@@ -4813,58 +4853,43 @@ bool InputDispatcher::transferTouchFocus(const sp<IBinder>& fromToken, const sp<
{ // acquire lock
std::scoped_lock _l(mLock);
- sp<InputWindowHandle> fromWindowHandle = getWindowHandleLocked(fromToken);
- sp<InputWindowHandle> toWindowHandle = getWindowHandleLocked(toToken);
- if (fromWindowHandle == nullptr || toWindowHandle == nullptr) {
- ALOGW("Cannot transfer focus because from or to window not found.");
+ // Find the target touch state and touched window by fromToken.
+ auto [state, touchedWindow] = findTouchStateAndWindowLocked(fromToken);
+ if (state == nullptr || touchedWindow == nullptr) {
+ ALOGD("Focus transfer failed because from window is not being touched.");
return false;
}
- if (DEBUG_FOCUS) {
- ALOGD("transferTouchFocus: fromWindowHandle=%s, toWindowHandle=%s",
- fromWindowHandle->getName().c_str(), toWindowHandle->getName().c_str());
- }
- if (fromWindowHandle->getInfo()->displayId != toWindowHandle->getInfo()->displayId) {
- if (DEBUG_FOCUS) {
- ALOGD("Cannot transfer focus because windows are on different displays.");
- }
+
+ const int32_t displayId = state->displayId;
+ sp<WindowInfoHandle> toWindowHandle = getWindowHandleLocked(toToken, displayId);
+ if (toWindowHandle == nullptr) {
+ ALOGW("Cannot transfer focus because to window not found.");
return false;
}
- bool found = false;
- for (std::pair<const int32_t, TouchState>& pair : mTouchStatesByDisplay) {
- TouchState& state = pair.second;
- for (size_t i = 0; i < state.windows.size(); i++) {
- const TouchedWindow& touchedWindow = state.windows[i];
- if (touchedWindow.windowHandle == fromWindowHandle) {
- int32_t oldTargetFlags = touchedWindow.targetFlags;
- BitSet32 pointerIds = touchedWindow.pointerIds;
-
- state.windows.erase(state.windows.begin() + i);
-
- int32_t newTargetFlags = oldTargetFlags &
- (InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_SPLIT |
- InputTarget::FLAG_DISPATCH_AS_IS);
- state.addOrUpdateWindow(toWindowHandle, newTargetFlags, pointerIds);
+ if (DEBUG_FOCUS) {
+ ALOGD("transferTouchFocus: fromWindowHandle=%s, toWindowHandle=%s",
+ touchedWindow->windowHandle->getName().c_str(),
+ toWindowHandle->getName().c_str());
+ }
- // Store the dragging window.
- if (isDragDrop) {
- mDragState = std::make_unique<DragState>(toWindowHandle);
- }
+ // Erase old window.
+ int32_t oldTargetFlags = touchedWindow->targetFlags;
+ BitSet32 pointerIds = touchedWindow->pointerIds;
+ state->removeWindowByToken(fromToken);
- found = true;
- goto Found;
- }
- }
- }
- Found:
+ // Add new window.
+ int32_t newTargetFlags = oldTargetFlags &
+ (InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_SPLIT |
+ InputTarget::FLAG_DISPATCH_AS_IS);
+ state->addOrUpdateWindow(toWindowHandle, newTargetFlags, pointerIds);
- if (!found) {
- if (DEBUG_FOCUS) {
- ALOGD("Focus transfer failed because from window did not have focus.");
- }
- return false;
+ // Store the dragging window.
+ if (isDragDrop) {
+ mDragState = std::make_unique<DragState>(toWindowHandle);
}
+ // Synthesize cancel for old window and down for new window.
sp<Connection> fromConnection = getConnectionLocked(fromToken);
sp<Connection> toConnection = getConnectionLocked(toToken);
if (fromConnection != nullptr && toConnection != nullptr) {
@@ -4892,27 +4917,20 @@ bool InputDispatcher::transferTouch(const sp<IBinder>& destChannelToken) {
{ // acquire lock
std::scoped_lock _l(mLock);
- sp<InputWindowHandle> toWindowHandle = getWindowHandleLocked(destChannelToken);
- if (toWindowHandle == nullptr) {
- ALOGW("Could not find window associated with token=%p", destChannelToken.get());
+ auto it = std::find_if(mTouchStatesByDisplay.begin(), mTouchStatesByDisplay.end(),
+ [](const auto& pair) { return pair.second.windows.size() == 1; });
+ if (it == mTouchStatesByDisplay.end()) {
+ ALOGW("Cannot transfer touch state because there is no exact window being touched");
return false;
}
-
- const int32_t displayId = toWindowHandle->getInfo()->displayId;
-
- auto touchStateIt = mTouchStatesByDisplay.find(displayId);
- if (touchStateIt == mTouchStatesByDisplay.end()) {
- ALOGD("Could not transfer touch because the display %" PRId32 " is not being touched",
- displayId);
+ const int32_t displayId = it->first;
+ sp<WindowInfoHandle> toWindowHandle = getWindowHandleLocked(destChannelToken, displayId);
+ if (toWindowHandle == nullptr) {
+ ALOGW("Could not find window associated with token=%p", destChannelToken.get());
return false;
}
- TouchState& state = touchStateIt->second;
- if (state.windows.size() != 1) {
- ALOGW("Cannot transfer touch state because there are %zu windows being touched",
- state.windows.size());
- return false;
- }
+ TouchState& state = it->second;
const TouchedWindow& touchedWindow = state.windows[0];
fromToken = touchedWindow.windowHandle->getToken();
} // release lock
@@ -4959,7 +4977,7 @@ std::string InputDispatcher::dumpPointerCaptureStateLocked() {
std::string windowName = "None";
if (mWindowTokenWithPointerCapture) {
- const sp<InputWindowHandle> captureWindowHandle =
+ const sp<WindowInfoHandle> captureWindowHandle =
getWindowHandleLocked(mWindowTokenWithPointerCapture);
windowName = captureWindowHandle ? captureWindowHandle->getName().c_str()
: "token has capture without window";
@@ -5015,7 +5033,7 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) {
if (!state.portalWindows.empty()) {
dump += INDENT3 "Portal windows:\n";
for (size_t i = 0; i < state.portalWindows.size(); i++) {
- const sp<InputWindowHandle> portalWindowHandle = state.portalWindows[i];
+ const sp<WindowInfoHandle> portalWindowHandle = state.portalWindows[i];
dump += StringPrintf(INDENT4 "%zu: name='%s'\n", i,
portalWindowHandle->getName().c_str());
}
@@ -5032,13 +5050,13 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) {
if (!mWindowHandlesByDisplay.empty()) {
for (auto& it : mWindowHandlesByDisplay) {
- const std::vector<sp<InputWindowHandle>> windowHandles = it.second;
+ const std::vector<sp<WindowInfoHandle>> windowHandles = it.second;
dump += StringPrintf(INDENT "Display: %" PRId32 "\n", it.first);
if (!windowHandles.empty()) {
dump += INDENT2 "Windows:\n";
for (size_t i = 0; i < windowHandles.size(); i++) {
- const sp<InputWindowHandle>& windowHandle = windowHandles[i];
- const InputWindowInfo* windowInfo = windowHandle->getInfo();
+ const sp<WindowInfoHandle>& windowHandle = windowHandles[i];
+ const WindowInfo* windowInfo = windowHandle->getInfo();
dump += StringPrintf(INDENT3 "%zu: name='%s', id=%" PRId32 ", displayId=%d, "
"portalToDisplayId=%d, paused=%s, focusable=%s, "
@@ -5066,12 +5084,13 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) {
windowInfo->inputFeatures.string().c_str());
dump += StringPrintf(", ownerPid=%d, ownerUid=%d, dispatchingTimeout=%" PRId64
"ms, trustedOverlay=%s, hasToken=%s, "
- "touchOcclusionMode=%s\n",
+ "touchOcclusionMode=%s, displayOrientation=%d\n",
windowInfo->ownerPid, windowInfo->ownerUid,
millis(windowInfo->dispatchingTimeout),
toString(windowInfo->trustedOverlay),
toString(windowInfo->token != nullptr),
- toString(windowInfo->touchOcclusionMode).c_str());
+ toString(windowInfo->touchOcclusionMode).c_str(),
+ windowInfo->displayOrientation);
windowInfo->transform.dump(dump, "transform", INDENT4);
}
} else {
@@ -5410,6 +5429,7 @@ status_t InputDispatcher::pilferPointers(const sp<IBinder>& token) {
canceledWindows.c_str());
// Then clear the current touch state so we stop dispatching to them as well.
+ state.split = false;
state.filterNonMonitors();
}
return OK;
@@ -5419,7 +5439,7 @@ void InputDispatcher::requestPointerCapture(const sp<IBinder>& windowToken, bool
{ // acquire lock
std::scoped_lock _l(mLock);
if (DEBUG_FOCUS) {
- const sp<InputWindowHandle> windowHandle = getWindowHandleLocked(windowToken);
+ const sp<WindowInfoHandle> windowHandle = getWindowHandleLocked(windowToken);
ALOGI("Request to %s Pointer Capture from: %s.", enabled ? "enable" : "disable",
windowHandle != nullptr ? windowHandle->getName().c_str()
: "token without window");
@@ -5589,7 +5609,7 @@ void InputDispatcher::onUntrustedTouchLocked(const std::string& obscuringPackage
postCommandLocked(std::move(commandEntry));
}
-void InputDispatcher::updateLastAnrStateLocked(const sp<InputWindowHandle>& window,
+void InputDispatcher::updateLastAnrStateLocked(const sp<WindowInfoHandle>& window,
const std::string& reason) {
const std::string windowLabel = getApplicationWindowLabel(nullptr, window);
updateLastAnrStateLocked(windowLabel, reason);
@@ -6257,4 +6277,31 @@ void InputDispatcher::displayRemoved(int32_t displayId) {
mLooper->wake();
}
+void InputDispatcher::onWindowInfosChanged(const std::vector<gui::WindowInfo>& windowInfos) {
+ // The listener sends the windows as a flattened array. Separate the windows by display for
+ // more convenient parsing.
+ std::unordered_map<int32_t, std::vector<sp<WindowInfoHandle>>> handlesPerDisplay;
+
+ for (const auto& info : windowInfos) {
+ handlesPerDisplay.emplace(info.displayId, std::vector<sp<WindowInfoHandle>>());
+ handlesPerDisplay[info.displayId].push_back(new WindowInfoHandle(info));
+ }
+ setInputWindows(handlesPerDisplay);
+}
+
+bool InputDispatcher::shouldDropInput(
+ const EventEntry& entry, const sp<android::gui::WindowInfoHandle>& windowHandle) const {
+ if (windowHandle->getInfo()->inputFeatures.test(WindowInfo::Feature::DROP_INPUT) ||
+ (windowHandle->getInfo()->inputFeatures.test(WindowInfo::Feature::DROP_INPUT_IF_OBSCURED) &&
+ isWindowObscuredLocked(windowHandle))) {
+ ALOGW("Dropping %s event targeting %s as requested by input feature %s on display "
+ "%" PRId32 ".",
+ NamedEnum::string(entry.type).c_str(), windowHandle->getName().c_str(),
+ windowHandle->getInfo()->inputFeatures.string().c_str(),
+ windowHandle->getInfo()->displayId);
+ return true;
+ }
+ return false;
+}
+
} // namespace android::inputdispatcher
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index 30652c65ee..04913d479a 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -37,10 +37,10 @@
#include <attestation/HmacKeyManager.h>
#include <com/android/internal/compat/IPlatformCompatNative.h>
+#include <gui/InputApplication.h>
+#include <gui/WindowInfo.h>
#include <input/Input.h>
-#include <input/InputApplication.h>
#include <input/InputTransport.h>
-#include <input/InputWindow.h>
#include <limits.h>
#include <stddef.h>
#include <ui/Region.h>
@@ -58,6 +58,7 @@
#include <InputListener.h>
#include <InputReporterInterface.h>
+#include <gui/WindowInfosListener.h>
namespace android::inputdispatcher {
@@ -80,7 +81,7 @@ class Connection;
*
* A 'LockedInterruptible' method may called a 'Locked' method, but NOT vice-versa.
*/
-class InputDispatcher : public android::InputDispatcherInterface {
+class InputDispatcher : public android::InputDispatcherInterface, public gui::WindowInfosListener {
protected:
~InputDispatcher() override;
@@ -109,8 +110,9 @@ public:
std::unique_ptr<VerifiedInputEvent> verifyInputEvent(const InputEvent& event) override;
- void setInputWindows(const std::unordered_map<int32_t, std::vector<sp<InputWindowHandle>>>&
- handlesPerDisplay) override;
+ void setInputWindows(
+ const std::unordered_map<int32_t, std::vector<sp<android::gui::WindowInfoHandle>>>&
+ handlesPerDisplay) override;
void setFocusedApplication(
int32_t displayId,
const std::shared_ptr<InputApplicationHandle>& inputApplicationHandle) override;
@@ -127,7 +129,7 @@ public:
base::Result<std::unique_ptr<InputChannel>> createInputChannel(
const std::string& name) override;
- void setFocusedWindow(const FocusRequest&) override;
+ void setFocusedWindow(const android::gui::FocusRequest&) override;
base::Result<std::unique_ptr<InputChannel>> createInputMonitor(int32_t displayId,
bool isGestureMonitor,
const std::string& name,
@@ -141,6 +143,8 @@ public:
void displayRemoved(int32_t displayId) override;
+ void onWindowInfosChanged(const std::vector<gui::WindowInfo>& windowInfos) override;
+
private:
enum class DropReason {
NOT_DROPPED,
@@ -190,8 +194,8 @@ private:
void enqueueFocusEventLocked(const sp<IBinder>& windowToken, bool hasFocus,
const std::string& reason) REQUIRES(mLock);
// Enqueues a drag event.
- void enqueueDragEventLocked(const sp<InputWindowHandle>& windowToken, bool isExiting,
- const MotionEntry& motionEntry) REQUIRES(mLock);
+ void enqueueDragEventLocked(const sp<android::gui::WindowInfoHandle>& windowToken,
+ bool isExiting, const MotionEntry& motionEntry) REQUIRES(mLock);
// Adds an event to a queue of recent events for debugging purposes.
void addRecentEventLocked(std::shared_ptr<EventEntry> entry) REQUIRES(mLock);
@@ -208,11 +212,12 @@ private:
// to transfer focus to a new application.
std::shared_ptr<EventEntry> mNextUnblockedEvent GUARDED_BY(mLock);
- sp<InputWindowHandle> findTouchedWindowAtLocked(int32_t displayId, int32_t x, int32_t y,
- TouchState* touchState,
- bool addOutsideTargets = false,
- bool addPortalWindows = false,
- bool ignoreDragWindow = false) REQUIRES(mLock);
+ sp<android::gui::WindowInfoHandle> findTouchedWindowAtLocked(int32_t displayId, int32_t x,
+ int32_t y, TouchState* touchState,
+ bool addOutsideTargets = false,
+ bool addPortalWindows = false,
+ bool ignoreDragWindow = false)
+ REQUIRES(mLock);
sp<Connection> getConnectionLocked(const sp<IBinder>& inputConnectionToken) const
REQUIRES(mLock);
@@ -314,33 +319,36 @@ private:
float mMaximumObscuringOpacityForTouch GUARDED_BY(mLock);
android::os::BlockUntrustedTouchesMode mBlockUntrustedTouchesMode GUARDED_BY(mLock);
- std::unordered_map<int32_t, std::vector<sp<InputWindowHandle>>> mWindowHandlesByDisplay
- GUARDED_BY(mLock);
- void setInputWindowsLocked(const std::vector<sp<InputWindowHandle>>& inputWindowHandles,
- int32_t displayId) REQUIRES(mLock);
+ std::unordered_map<int32_t, std::vector<sp<android::gui::WindowInfoHandle>>>
+ mWindowHandlesByDisplay GUARDED_BY(mLock);
+ void setInputWindowsLocked(
+ const std::vector<sp<android::gui::WindowInfoHandle>>& inputWindowHandles,
+ int32_t displayId) REQUIRES(mLock);
// Get a reference to window handles by display, return an empty vector if not found.
- const std::vector<sp<InputWindowHandle>>& getWindowHandlesLocked(int32_t displayId) const
- REQUIRES(mLock);
- sp<InputWindowHandle> getWindowHandleLocked(const sp<IBinder>& windowHandleToken) const
- REQUIRES(mLock);
+ const std::vector<sp<android::gui::WindowInfoHandle>>& getWindowHandlesLocked(
+ int32_t displayId) const REQUIRES(mLock);
+ sp<android::gui::WindowInfoHandle> getWindowHandleLocked(
+ const sp<IBinder>& windowHandleToken) const REQUIRES(mLock);
// Same function as above, but faster. Since displayId is provided, this avoids the need
// to loop through all displays.
- sp<InputWindowHandle> getWindowHandleLocked(const sp<IBinder>& windowHandleToken,
- int displayId) const REQUIRES(mLock);
- sp<InputWindowHandle> getWindowHandleLocked(const sp<InputWindowHandle>& windowHandle) const
- REQUIRES(mLock);
+ sp<android::gui::WindowInfoHandle> getWindowHandleLocked(const sp<IBinder>& windowHandleToken,
+ int displayId) const REQUIRES(mLock);
+ sp<android::gui::WindowInfoHandle> getWindowHandleLocked(
+ const sp<android::gui::WindowInfoHandle>& windowHandle) const REQUIRES(mLock);
std::shared_ptr<InputChannel> getInputChannelLocked(const sp<IBinder>& windowToken) const
REQUIRES(mLock);
- sp<InputWindowHandle> getFocusedWindowHandleLocked(int displayId) const REQUIRES(mLock);
- bool hasResponsiveConnectionLocked(InputWindowHandle& windowHandle) const REQUIRES(mLock);
+ sp<android::gui::WindowInfoHandle> getFocusedWindowHandleLocked(int displayId) const
+ REQUIRES(mLock);
+ bool hasResponsiveConnectionLocked(android::gui::WindowInfoHandle& windowHandle) const
+ REQUIRES(mLock);
/*
* Validate and update InputWindowHandles for a given display.
*/
void updateWindowHandlesForDisplayLocked(
- const std::vector<sp<InputWindowHandle>>& inputWindowHandles, int32_t displayId)
- REQUIRES(mLock);
+ const std::vector<sp<android::gui::WindowInfoHandle>>& inputWindowHandles,
+ int32_t displayId) REQUIRES(mLock);
std::unordered_map<int32_t, TouchState> mTouchStatesByDisplay GUARDED_BY(mLock);
std::unique_ptr<DragState> mDragState GUARDED_BY(mLock);
@@ -473,7 +481,7 @@ private:
AnrTracker mAnrTracker GUARDED_BY(mLock);
// Contains the last window which received a hover event.
- sp<InputWindowHandle> mLastHoverWindowHandle GUARDED_BY(mLock);
+ sp<android::gui::WindowInfoHandle> mLastHoverWindowHandle GUARDED_BY(mLock);
void cancelEventsForAnrLocked(const sp<Connection>& connection) REQUIRES(mLock);
nsecs_t getTimeSpentWaitingForApplicationLocked(nsecs_t currentTime) REQUIRES(mLock);
@@ -492,20 +500,21 @@ private:
nsecs_t currentTime, const MotionEntry& entry, std::vector<InputTarget>& inputTargets,
nsecs_t* nextWakeupTime, bool* outConflictingPointerActions) REQUIRES(mLock);
std::vector<TouchedMonitor> findTouchedGestureMonitorsLocked(
- int32_t displayId, const std::vector<sp<InputWindowHandle>>& portalWindows) const
+ int32_t displayId,
+ const std::vector<sp<android::gui::WindowInfoHandle>>& portalWindows) const
REQUIRES(mLock);
std::vector<TouchedMonitor> selectResponsiveMonitorsLocked(
const std::vector<TouchedMonitor>& gestureMonitors) const REQUIRES(mLock);
- void addWindowTargetLocked(const sp<InputWindowHandle>& windowHandle, int32_t targetFlags,
- BitSet32 pointerIds, std::vector<InputTarget>& inputTargets)
- REQUIRES(mLock);
+ void addWindowTargetLocked(const sp<android::gui::WindowInfoHandle>& windowHandle,
+ int32_t targetFlags, BitSet32 pointerIds,
+ std::vector<InputTarget>& inputTargets) REQUIRES(mLock);
void addMonitoringTargetLocked(const Monitor& monitor, float xOffset, float yOffset,
std::vector<InputTarget>& inputTargets) REQUIRES(mLock);
void addGlobalMonitoringTargetsLocked(std::vector<InputTarget>& inputTargets, int32_t displayId,
float xOffset = 0, float yOffset = 0) REQUIRES(mLock);
void pokeUserActivityLocked(const EventEntry& eventEntry) REQUIRES(mLock);
- bool checkInjectionPermission(const sp<InputWindowHandle>& windowHandle,
+ bool checkInjectionPermission(const sp<android::gui::WindowInfoHandle>& windowHandle,
const InjectionState* injectionState);
// Enqueue a drag event if needed, and update the touch state.
// Uses findTouchedWindowTargetsLocked to make the decision
@@ -520,15 +529,22 @@ private:
std::vector<std::string> debugInfo;
};
- TouchOcclusionInfo computeTouchOcclusionInfoLocked(const sp<InputWindowHandle>& windowHandle,
- int32_t x, int32_t y) const REQUIRES(mLock);
+ TouchOcclusionInfo computeTouchOcclusionInfoLocked(
+ const sp<android::gui::WindowInfoHandle>& windowHandle, int32_t x, int32_t y) const
+ REQUIRES(mLock);
bool isTouchTrustedLocked(const TouchOcclusionInfo& occlusionInfo) const REQUIRES(mLock);
- bool isWindowObscuredAtPointLocked(const sp<InputWindowHandle>& windowHandle, int32_t x,
- int32_t y) const REQUIRES(mLock);
- bool isWindowObscuredLocked(const sp<InputWindowHandle>& windowHandle) const REQUIRES(mLock);
- std::string dumpWindowForTouchOcclusion(const InputWindowInfo* info, bool isTouchWindow) const;
+ bool isWindowObscuredAtPointLocked(const sp<android::gui::WindowInfoHandle>& windowHandle,
+ int32_t x, int32_t y) const REQUIRES(mLock);
+ bool isWindowObscuredLocked(const sp<android::gui::WindowInfoHandle>& windowHandle) const
+ REQUIRES(mLock);
+ std::string dumpWindowForTouchOcclusion(const android::gui::WindowInfo* info,
+ bool isTouchWindow) const;
std::string getApplicationWindowLabel(const InputApplicationHandle* applicationHandle,
- const sp<InputWindowHandle>& windowHandle);
+ const sp<android::gui::WindowInfoHandle>& windowHandle);
+
+ bool shouldDropInput(const EventEntry& entry,
+ const sp<android::gui::WindowInfoHandle>& windowHandle) const
+ REQUIRES(mLock);
// Manage the dispatch cycle for a single connection.
// These methods are deliberately not Interruptible because doing all of the work
@@ -607,8 +623,8 @@ private:
void onAnrLocked(const sp<Connection>& connection) REQUIRES(mLock);
void onAnrLocked(std::shared_ptr<InputApplicationHandle> application) REQUIRES(mLock);
void onUntrustedTouchLocked(const std::string& obscuringPackage) REQUIRES(mLock);
- void updateLastAnrStateLocked(const sp<InputWindowHandle>& window, const std::string& reason)
- REQUIRES(mLock);
+ void updateLastAnrStateLocked(const sp<android::gui::WindowInfoHandle>& window,
+ const std::string& reason) REQUIRES(mLock);
void updateLastAnrStateLocked(const InputApplicationHandle& application,
const std::string& reason) REQUIRES(mLock);
void updateLastAnrStateLocked(const std::string& windowLabel, const std::string& reason)
@@ -643,6 +659,10 @@ private:
void doPokeUserActivityLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock);
void doOnPointerDownOutsideFocusLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock);
+ // Find touched state and touched window by token.
+ std::pair<TouchState*, TouchedWindow*> findTouchStateAndWindowLocked(const sp<IBinder>& token)
+ REQUIRES(mLock);
+
// Statistics gathering.
LatencyAggregator mLatencyAggregator GUARDED_BY(mLock);
LatencyTracker mLatencyTracker GUARDED_BY(mLock);
@@ -652,6 +672,8 @@ private:
sp<InputReporterInterface> mReporter;
sp<com::android::internal::compat::IPlatformCompatNative> mCompatService;
+
+ void onFirstRef() override;
};
} // namespace android::inputdispatcher
diff --git a/services/inputflinger/dispatcher/InputTarget.h b/services/inputflinger/dispatcher/InputTarget.h
index 1c4980b302..7c463c8697 100644
--- a/services/inputflinger/dispatcher/InputTarget.h
+++ b/services/inputflinger/dispatcher/InputTarget.h
@@ -17,6 +17,7 @@
#ifndef _UI_INPUT_INPUTDISPATCHER_INPUTTARGET_H
#define _UI_INPUT_INPUTDISPATCHER_INPUTTARGET_H
+#include <gui/constants.h>
#include <input/InputTransport.h>
#include <ui/Transform.h>
#include <utils/BitSet.h>
@@ -100,8 +101,11 @@ struct InputTarget {
// (ignored for KeyEvents)
float globalScaleFactor = 1.0f;
+ // Current display orientation
+ uint32_t displayOrientation = ui::Transform::ROT_0;
+
// Display-size in its natural rotation. Used for compatibility transform of raw coordinates.
- int2 displaySize = {AMOTION_EVENT_INVALID_DISPLAY_SIZE, AMOTION_EVENT_INVALID_DISPLAY_SIZE};
+ int2 displaySize = {INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE};
// The subset of pointer ids to include in motion events dispatched to this input target
// if FLAG_SPLIT is set.
diff --git a/services/inputflinger/dispatcher/TouchState.cpp b/services/inputflinger/dispatcher/TouchState.cpp
index 81b3cf025b..20b6eadf5b 100644
--- a/services/inputflinger/dispatcher/TouchState.cpp
+++ b/services/inputflinger/dispatcher/TouchState.cpp
@@ -14,13 +14,14 @@
* limitations under the License.
*/
-#include <input/InputWindow.h>
+#include <gui/WindowInfo.h>
#include "InputTarget.h"
#include "TouchState.h"
-using android::InputWindowHandle;
+using android::gui::WindowInfo;
+using android::gui::WindowInfoHandle;
namespace android::inputdispatcher {
@@ -51,7 +52,7 @@ void TouchState::copyFrom(const TouchState& other) {
gestureMonitors = other.gestureMonitors;
}
-void TouchState::addOrUpdateWindow(const sp<InputWindowHandle>& windowHandle, int32_t targetFlags,
+void TouchState::addOrUpdateWindow(const sp<WindowInfoHandle>& windowHandle, int32_t targetFlags,
BitSet32 pointerIds) {
if (targetFlags & InputTarget::FLAG_SPLIT) {
split = true;
@@ -76,7 +77,7 @@ void TouchState::addOrUpdateWindow(const sp<InputWindowHandle>& windowHandle, in
windows.push_back(touchedWindow);
}
-void TouchState::addPortalWindow(const sp<InputWindowHandle>& windowHandle) {
+void TouchState::addPortalWindow(const sp<android::gui::WindowInfoHandle>& windowHandle) {
size_t numWindows = portalWindows.size();
for (size_t i = 0; i < numWindows; i++) {
if (portalWindows[i] == windowHandle) {
@@ -121,7 +122,7 @@ void TouchState::filterNonMonitors() {
portalWindows.clear();
}
-sp<InputWindowHandle> TouchState::getFirstForegroundWindowHandle() const {
+sp<WindowInfoHandle> TouchState::getFirstForegroundWindowHandle() const {
for (size_t i = 0; i < windows.size(); i++) {
const TouchedWindow& window = windows[i];
if (window.targetFlags & InputTarget::FLAG_FOREGROUND) {
@@ -137,7 +138,7 @@ bool TouchState::isSlippery() const {
for (const TouchedWindow& window : windows) {
if (window.targetFlags & InputTarget::FLAG_FOREGROUND) {
if (haveSlipperyForegroundWindow ||
- !window.windowHandle->getInfo()->flags.test(InputWindowInfo::Flag::SLIPPERY)) {
+ !window.windowHandle->getInfo()->flags.test(WindowInfo::Flag::SLIPPERY)) {
return false;
}
haveSlipperyForegroundWindow = true;
diff --git a/services/inputflinger/dispatcher/TouchState.h b/services/inputflinger/dispatcher/TouchState.h
index 623c6a824f..a4e52b0d83 100644
--- a/services/inputflinger/dispatcher/TouchState.h
+++ b/services/inputflinger/dispatcher/TouchState.h
@@ -22,7 +22,9 @@
namespace android {
-class InputWindowHandle;
+namespace gui {
+class WindowInfoHandle;
+}
namespace inputdispatcher {
@@ -37,7 +39,7 @@ struct TouchState {
// This collects the portal windows that the touch has gone through. Each portal window
// targets a display (embedded display for most cases). With this info, we can add the
// monitoring channels of the displays touched.
- std::vector<sp<android::InputWindowHandle>> portalWindows;
+ std::vector<sp<android::gui::WindowInfoHandle>> portalWindows;
std::vector<TouchedMonitor> gestureMonitors;
@@ -45,14 +47,14 @@ struct TouchState {
~TouchState();
void reset();
void copyFrom(const TouchState& other);
- void addOrUpdateWindow(const sp<android::InputWindowHandle>& windowHandle, int32_t targetFlags,
- BitSet32 pointerIds);
- void addPortalWindow(const sp<android::InputWindowHandle>& windowHandle);
+ void addOrUpdateWindow(const sp<android::gui::WindowInfoHandle>& windowHandle,
+ int32_t targetFlags, BitSet32 pointerIds);
+ void addPortalWindow(const sp<android::gui::WindowInfoHandle>& windowHandle);
void addGestureMonitors(const std::vector<TouchedMonitor>& monitors);
void removeWindowByToken(const sp<IBinder>& token);
void filterNonAsIsTouchWindows();
void filterNonMonitors();
- sp<InputWindowHandle> getFirstForegroundWindowHandle() const;
+ sp<android::gui::WindowInfoHandle> getFirstForegroundWindowHandle() const;
bool isSlippery() const;
};
diff --git a/services/inputflinger/dispatcher/TouchedWindow.h b/services/inputflinger/dispatcher/TouchedWindow.h
index 8713aa3f56..4c31ec3acd 100644
--- a/services/inputflinger/dispatcher/TouchedWindow.h
+++ b/services/inputflinger/dispatcher/TouchedWindow.h
@@ -19,13 +19,15 @@
namespace android {
-class InputWindowHandle;
+namespace gui {
+class WindowInfoHandle;
+}
namespace inputdispatcher {
// Focus tracking for touch.
struct TouchedWindow {
- sp<android::InputWindowHandle> windowHandle;
+ sp<gui::WindowInfoHandle> windowHandle;
int32_t targetFlags;
BitSet32 pointerIds; // zero unless target flag FLAG_SPLIT is set
};
diff --git a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
index 43428a0130..a7dccf0d19 100644
--- a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
+++ b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
@@ -19,18 +19,16 @@
#include <InputListener.h>
#include <android-base/result.h>
-#include <android/FocusRequest.h>
+#include <android/gui/FocusRequest.h>
#include <android/os/BlockUntrustedTouchesMode.h>
-#include <android/os/ISetInputWindowsListener.h>
#include <android/os/InputEventInjectionResult.h>
#include <android/os/InputEventInjectionSync.h>
-#include <input/InputApplication.h>
+#include <gui/InputApplication.h>
+#include <gui/WindowInfo.h>
#include <input/InputDevice.h>
#include <input/InputTransport.h>
-#include <input/InputWindow.h>
#include <unordered_map>
-
namespace android {
/* Notifies the system about input events generated by the input reader.
@@ -91,7 +89,7 @@ public:
* This method may be called on any thread (usually by the input manager).
*/
virtual void setInputWindows(
- const std::unordered_map<int32_t, std::vector<sp<InputWindowHandle>>>&
+ const std::unordered_map<int32_t, std::vector<sp<gui::WindowInfoHandle>>>&
handlesPerDisplay) = 0;
/* Sets the focused application on the given display.
@@ -162,7 +160,7 @@ public:
/**
* Sets focus on the specified window.
*/
- virtual void setFocusedWindow(const FocusRequest&) = 0;
+ virtual void setFocusedWindow(const gui::FocusRequest&) = 0;
/**
* Creates an input channel that may be used as targets for input events.
diff --git a/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h
index fd591e0e1c..3c1e6370b7 100644
--- a/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h
+++ b/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h
@@ -20,8 +20,8 @@
#include "InputDispatcherConfiguration.h"
#include <binder/IBinder.h>
+#include <gui/InputApplication.h>
#include <input/Input.h>
-#include <input/InputApplication.h>
#include <utils/RefBase.h>
namespace android {
diff --git a/services/inputflinger/host/InputFlinger.h b/services/inputflinger/host/InputFlinger.h
index 8112038b16..3cf1b2b797 100644
--- a/services/inputflinger/host/InputFlinger.h
+++ b/services/inputflinger/host/InputFlinger.h
@@ -23,15 +23,14 @@
#include "InputHost.h"
#include <android/os/BnInputFlinger.h>
-#include <android/os/ISetInputWindowsListener.h>
#include <binder/Binder.h>
#include <cutils/compiler.h>
#include <utils/String16.h>
#include <utils/String8.h>
#include <utils/StrongPointer.h>
+using android::gui::FocusRequest;
using android::os::BnInputFlinger;
-using android::os::ISetInputWindowsListener;
namespace android {
@@ -44,10 +43,6 @@ public:
InputFlinger() ANDROID_API;
status_t dump(int fd, const Vector<String16>& args) override;
- binder::Status setInputWindows(const std::vector<InputWindowInfo>&,
- const sp<ISetInputWindowsListener>&) override {
- return binder::Status::ok();
- }
binder::Status createInputChannel(const std::string&, InputChannel*) override {
return binder::Status::ok();
}
diff --git a/services/inputflinger/reader/Android.bp b/services/inputflinger/reader/Android.bp
index 7db32e3071..ee7b392bcd 100644
--- a/services/inputflinger/reader/Android.bp
+++ b/services/inputflinger/reader/Android.bp
@@ -71,6 +71,7 @@ cc_defaults {
"libstatslog",
"libui",
"libutils",
+ "InputFlingerProperties",
],
static_libs: [
"libc++fs",
diff --git a/services/inputflinger/reader/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp
index 68d5e7c300..166f358598 100644
--- a/services/inputflinger/reader/EventHub.cpp
+++ b/services/inputflinger/reader/EventHub.cpp
@@ -1252,12 +1252,11 @@ const std::shared_ptr<KeyCharacterMap> EventHub::getKeyCharacterMap(int32_t devi
bool EventHub::setKeyboardLayoutOverlay(int32_t deviceId, std::shared_ptr<KeyCharacterMap> map) {
std::scoped_lock _l(mLock);
Device* device = getDeviceLocked(deviceId);
- if (device != nullptr && map != nullptr && device->keyMap.keyCharacterMap != nullptr) {
- device->keyMap.keyCharacterMap->combine(*map);
- device->keyMap.keyCharacterMapFile = device->keyMap.keyCharacterMap->getLoadFileName();
- return true;
+ if (device == nullptr || map == nullptr || device->keyMap.keyCharacterMap == nullptr) {
+ return false;
}
- return false;
+ device->keyMap.keyCharacterMap->combine(*map);
+ return true;
}
static std::string generateDescriptor(InputDeviceIdentifier& identifier) {
diff --git a/services/inputflinger/reader/InputDevice.cpp b/services/inputflinger/reader/InputDevice.cpp
index 7af014cb34..1e9ec54d5d 100644
--- a/services/inputflinger/reader/InputDevice.cpp
+++ b/services/inputflinger/reader/InputDevice.cpp
@@ -18,7 +18,7 @@
#include "InputDevice.h"
-#include <input/Flags.h>
+#include <ftl/Flags.h>
#include <algorithm>
#include "CursorInputMapper.h"
diff --git a/services/inputflinger/reader/controller/PeripheralController.cpp b/services/inputflinger/reader/controller/PeripheralController.cpp
index 16251ee0ca..9c8a29a059 100644
--- a/services/inputflinger/reader/controller/PeripheralController.cpp
+++ b/services/inputflinger/reader/controller/PeripheralController.cpp
@@ -19,8 +19,8 @@
#include "../Macros.h"
+#include <ftl/NamedEnum.h>
#include "PeripheralController.h"
-#include "input/NamedEnum.h"
// Log detailed debug messages about input device lights.
static constexpr bool DEBUG_LIGHT_DETAILS = false;
diff --git a/services/inputflinger/reader/include/EventHub.h b/services/inputflinger/reader/include/EventHub.h
index d88b1bd704..3c3f88e36e 100644
--- a/services/inputflinger/reader/include/EventHub.h
+++ b/services/inputflinger/reader/include/EventHub.h
@@ -22,7 +22,7 @@
#include <unordered_map>
#include <vector>
-#include <input/Flags.h>
+#include <ftl/Flags.h>
#include <filesystem>
#include <batteryservice/BatteryService.h>
diff --git a/services/inputflinger/reader/include/InputDevice.h b/services/inputflinger/reader/include/InputDevice.h
index 2f2eba78b1..f32472d37b 100644
--- a/services/inputflinger/reader/include/InputDevice.h
+++ b/services/inputflinger/reader/include/InputDevice.h
@@ -17,8 +17,8 @@
#ifndef _UI_INPUTREADER_INPUT_DEVICE_H
#define _UI_INPUTREADER_INPUT_DEVICE_H
+#include <ftl/Flags.h>
#include <input/DisplayViewport.h>
-#include <input/Flags.h>
#include <input/InputDevice.h>
#include <input/PropertyMap.h>
#include <stdint.h>
diff --git a/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h b/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h
index da0fea4616..7347b2cec4 100644
--- a/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h
+++ b/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h
@@ -17,7 +17,7 @@
#ifndef _UI_INPUTREADER_TOUCH_CURSOR_INPUT_MAPPER_COMMON_H
#define _UI_INPUTREADER_TOUCH_CURSOR_INPUT_MAPPER_COMMON_H
-#include <android-base/properties.h>
+#include <InputFlingerProperties.sysprop.h>
#include <input/DisplayViewport.h>
#include <stdint.h>
@@ -33,9 +33,7 @@ namespace android {
// projection are part of the input window's transform. This means InputReader should work in the
// un-rotated coordinate space.
static bool isPerWindowInputRotationEnabled() {
- static const bool PER_WINDOW_INPUT_ROTATION =
- base::GetBoolProperty("persist.debug.per_window_input_rotation", false);
- return PER_WINDOW_INPUT_ROTATION;
+ return sysprop::InputFlingerProperties::per_window_input_rotation().value_or(false);
}
static int32_t getInverseRotation(int32_t orientation) {
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
index ae89ca1ca9..ac5f6b652b 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
@@ -18,7 +18,7 @@
#include "../Macros.h"
// clang-format on
-#include <input/NamedEnum.h>
+#include <ftl/NamedEnum.h>
#include "TouchInputMapper.h"
#include "CursorButtonAccumulator.h"
@@ -470,6 +470,23 @@ void TouchInputMapper::configureParameters() {
getDeviceContext().getConfiguration().tryGetProperty(String8("touch.orientationAware"),
mParameters.orientationAware);
+ mParameters.orientation = Parameters::Orientation::ORIENTATION_0;
+ String8 orientationString;
+ if (getDeviceContext().getConfiguration().tryGetProperty(String8("touch.orientation"),
+ orientationString)) {
+ if (mParameters.deviceType != Parameters::DeviceType::TOUCH_SCREEN) {
+ ALOGW("The configuration 'touch.orientation' is only supported for touchscreens.");
+ } else if (orientationString == "ORIENTATION_90") {
+ mParameters.orientation = Parameters::Orientation::ORIENTATION_90;
+ } else if (orientationString == "ORIENTATION_180") {
+ mParameters.orientation = Parameters::Orientation::ORIENTATION_180;
+ } else if (orientationString == "ORIENTATION_270") {
+ mParameters.orientation = Parameters::Orientation::ORIENTATION_270;
+ } else if (orientationString != "ORIENTATION_0") {
+ ALOGW("Invalid value for touch.orientation: '%s'", orientationString.string());
+ }
+ }
+
mParameters.hasAssociatedDisplay = false;
mParameters.associatedDisplayIsExternal = false;
if (mParameters.orientationAware ||
@@ -508,6 +525,7 @@ void TouchInputMapper::dumpParameters(std::string& dump) {
toString(mParameters.associatedDisplayIsExternal),
mParameters.uniqueDisplayId.c_str());
dump += StringPrintf(INDENT4 "OrientationAware: %s\n", toString(mParameters.orientationAware));
+ dump += INDENT4 "Orientation: " + NamedEnum::string(mParameters.orientation) + "\n";
}
void TouchInputMapper::configureRawPointerAxes() {
@@ -669,7 +687,13 @@ void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) {
int32_t naturalPhysicalWidth, naturalPhysicalHeight;
int32_t naturalPhysicalLeft, naturalPhysicalTop;
int32_t naturalDeviceWidth, naturalDeviceHeight;
- switch (mViewport.orientation) {
+
+ // Apply the inverse of the input device orientation so that the surface is configured
+ // in the same orientation as the device. The input device orientation will be
+ // re-applied to mSurfaceOrientation.
+ const int32_t naturalSurfaceOrientation =
+ (mViewport.orientation - static_cast<int32_t>(mParameters.orientation) + 4) % 4;
+ switch (naturalSurfaceOrientation) {
case DISPLAY_ORIENTATION_90:
naturalLogicalWidth = mViewport.logicalBottom - mViewport.logicalTop;
naturalLogicalHeight = mViewport.logicalRight - mViewport.logicalLeft;
@@ -752,6 +776,10 @@ void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) {
mSurfaceOrientation = mParameters.orientationAware ? mViewport.orientation
: DISPLAY_ORIENTATION_0;
}
+
+ // Apply the input device orientation for the device.
+ mSurfaceOrientation =
+ (mSurfaceOrientation + static_cast<int32_t>(mParameters.orientation)) % 4;
} else {
mPhysicalWidth = rawWidth;
mPhysicalHeight = rawHeight;
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.h b/services/inputflinger/reader/mapper/TouchInputMapper.h
index 920f8428f3..e104220e47 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.h
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.h
@@ -204,6 +204,15 @@ protected:
bool hasAssociatedDisplay;
bool associatedDisplayIsExternal;
bool orientationAware;
+
+ enum class Orientation : int32_t {
+ ORIENTATION_0 = DISPLAY_ORIENTATION_0,
+ ORIENTATION_90 = DISPLAY_ORIENTATION_90,
+ ORIENTATION_180 = DISPLAY_ORIENTATION_180,
+ ORIENTATION_270 = DISPLAY_ORIENTATION_270,
+ };
+ Orientation orientation;
+
bool hasButtonUnderPad;
std::string uniqueDisplayId;
diff --git a/services/inputflinger/sysprop/Android.bp b/services/inputflinger/sysprop/Android.bp
new file mode 100644
index 0000000000..b9d65ee246
--- /dev/null
+++ b/services/inputflinger/sysprop/Android.bp
@@ -0,0 +1,15 @@
+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"],
+}
+
+sysprop_library {
+ name: "InputFlingerProperties",
+ srcs: ["*.sysprop"],
+ api_packages: ["android.sysprop"],
+ property_owner: "Platform",
+}
diff --git a/services/inputflinger/sysprop/InputFlingerProperties.sysprop b/services/inputflinger/sysprop/InputFlingerProperties.sysprop
new file mode 100644
index 0000000000..1c7e724332
--- /dev/null
+++ b/services/inputflinger/sysprop/InputFlingerProperties.sysprop
@@ -0,0 +1,27 @@
+# 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.
+
+module: "android.sysprop.InputFlingerProperties"
+owner: Platform
+
+# When per-window-input-rotation is enabled, InputReader works in the un-rotated
+# display coordinate space, and the display rotation is encoded as part of the
+# input window transform that is sent from SurfaceFlinger to InputDispatcher.
+prop {
+ api_name: "per_window_input_rotation"
+ type: Boolean
+ scope: Internal
+ access: ReadWrite
+ prop_name: "persist.debug.per_window_input_rotation"
+}
diff --git a/services/inputflinger/tests/Android.bp b/services/inputflinger/tests/Android.bp
index 918e1bef7a..e68692474d 100644
--- a/services/inputflinger/tests/Android.bp
+++ b/services/inputflinger/tests/Android.bp
@@ -52,6 +52,7 @@ cc_test {
],
aidl: {
include_dirs: [
+ "frameworks/native/libs/gui",
"frameworks/native/libs/input",
],
},
diff --git a/services/inputflinger/tests/FocusResolver_test.cpp b/services/inputflinger/tests/FocusResolver_test.cpp
index 9051ff12c2..662be8063e 100644
--- a/services/inputflinger/tests/FocusResolver_test.cpp
+++ b/services/inputflinger/tests/FocusResolver_test.cpp
@@ -26,9 +26,12 @@
// atest inputflinger_tests:FocusResolverTest
+using android::gui::FocusRequest;
+using android::gui::WindowInfoHandle;
+
namespace android::inputdispatcher {
-class FakeWindowHandle : public InputWindowHandle {
+class FakeWindowHandle : public WindowInfoHandle {
public:
FakeWindowHandle(const std::string& name, const sp<IBinder>& token, bool focusable,
bool visible) {
@@ -38,7 +41,6 @@ public:
mInfo.focusable = focusable;
}
- bool updateInfo() { return true; }
void setFocusable(bool focusable) { mInfo.focusable = focusable; }
void setVisible(bool visible) { mInfo.visible = visible; }
};
@@ -47,7 +49,7 @@ TEST(FocusResolverTest, SetFocusedWindow) {
sp<IBinder> focusableWindowToken = new BBinder();
sp<IBinder> invisibleWindowToken = new BBinder();
sp<IBinder> unfocusableWindowToken = new BBinder();
- std::vector<sp<InputWindowHandle>> windows;
+ std::vector<sp<WindowInfoHandle>> windows;
windows.push_back(new FakeWindowHandle("Focusable", focusableWindowToken, true /* focusable */,
true /* visible */));
windows.push_back(new FakeWindowHandle("Invisible", invisibleWindowToken, true /* focusable */,
@@ -82,7 +84,7 @@ TEST(FocusResolverTest, SetFocusedMirroredWindow) {
sp<IBinder> focusableWindowToken = new BBinder();
sp<IBinder> invisibleWindowToken = new BBinder();
sp<IBinder> unfocusableWindowToken = new BBinder();
- std::vector<sp<InputWindowHandle>> windows;
+ std::vector<sp<WindowInfoHandle>> windows;
windows.push_back(new FakeWindowHandle("Mirror1", focusableWindowToken, true /* focusable */,
true /* visible */));
windows.push_back(new FakeWindowHandle("Mirror1", focusableWindowToken, true /* focusable */,
@@ -120,7 +122,7 @@ TEST(FocusResolverTest, SetFocusedMirroredWindow) {
TEST(FocusResolverTest, SetInputWindows) {
sp<IBinder> focusableWindowToken = new BBinder();
- std::vector<sp<InputWindowHandle>> windows;
+ std::vector<sp<WindowInfoHandle>> windows;
sp<FakeWindowHandle> window = new FakeWindowHandle("Focusable", focusableWindowToken,
true /* focusable */, true /* visible */);
windows.push_back(window);
@@ -142,7 +144,7 @@ TEST(FocusResolverTest, SetInputWindows) {
TEST(FocusResolverTest, FocusRequestsCanBePending) {
sp<IBinder> invisibleWindowToken = new BBinder();
- std::vector<sp<InputWindowHandle>> windows;
+ std::vector<sp<WindowInfoHandle>> windows;
sp<FakeWindowHandle> invisibleWindow =
new FakeWindowHandle("Invisible", invisibleWindowToken, true /* focusable */,
@@ -166,7 +168,7 @@ TEST(FocusResolverTest, FocusRequestsCanBePending) {
TEST(FocusResolverTest, FocusRequestsArePersistent) {
sp<IBinder> windowToken = new BBinder();
- std::vector<sp<InputWindowHandle>> windows;
+ std::vector<sp<WindowInfoHandle>> windows;
sp<FakeWindowHandle> window = new FakeWindowHandle("Test Window", windowToken,
false /* focusable */, true /* visible */);
@@ -207,7 +209,7 @@ TEST(FocusResolverTest, FocusRequestsArePersistent) {
TEST(FocusResolverTest, ConditionalFocusRequestsAreNotPersistent) {
sp<IBinder> hostWindowToken = new BBinder();
- std::vector<sp<InputWindowHandle>> windows;
+ std::vector<sp<WindowInfoHandle>> windows;
sp<FakeWindowHandle> hostWindow =
new FakeWindowHandle("Host Window", hostWindowToken, true /* focusable */,
@@ -258,7 +260,7 @@ TEST(FocusResolverTest, ConditionalFocusRequestsAreNotPersistent) {
}
TEST(FocusResolverTest, FocusRequestsAreClearedWhenWindowIsRemoved) {
sp<IBinder> windowToken = new BBinder();
- std::vector<sp<InputWindowHandle>> windows;
+ std::vector<sp<WindowInfoHandle>> windows;
sp<FakeWindowHandle> window = new FakeWindowHandle("Test Window", windowToken,
true /* focusable */, true /* visible */);
diff --git a/services/inputflinger/tests/IInputFlingerQuery.aidl b/services/inputflinger/tests/IInputFlingerQuery.aidl
index 5c8a8da612..5aeb21f6b4 100644
--- a/services/inputflinger/tests/IInputFlingerQuery.aidl
+++ b/services/inputflinger/tests/IInputFlingerQuery.aidl
@@ -14,17 +14,14 @@
* limitations under the License.
*/
-import android.FocusRequest;
import android.InputChannel;
-import android.InputWindowInfo;
-import android.os.ISetInputWindowsListener;
+import android.gui.FocusRequest;
+import android.gui.WindowInfo;
/** @hide */
interface IInputFlingerQuery
{
/* Test interfaces */
- void getInputWindows(out InputWindowInfo[] inputHandles);
void getInputChannels(out InputChannel[] channels);
- void getLastFocusRequest(out FocusRequest request);
void resetInputManager();
}
diff --git a/services/inputflinger/tests/InputClassifierConverter_test.cpp b/services/inputflinger/tests/InputClassifierConverter_test.cpp
index c0ada9d517..f626d56b8c 100644
--- a/services/inputflinger/tests/InputClassifierConverter_test.cpp
+++ b/services/inputflinger/tests/InputClassifierConverter_test.cpp
@@ -17,9 +17,9 @@
#include "../InputClassifierConverter.h"
#include <gtest/gtest.h>
+#include <gui/constants.h>
#include <utils/BitSet.h>
-
using namespace android::hardware::input;
namespace android {
diff --git a/services/inputflinger/tests/InputClassifier_test.cpp b/services/inputflinger/tests/InputClassifier_test.cpp
index a72df01ce6..3a9994eed9 100644
--- a/services/inputflinger/tests/InputClassifier_test.cpp
+++ b/services/inputflinger/tests/InputClassifier_test.cpp
@@ -16,6 +16,7 @@
#include "../InputClassifier.h"
#include <gtest/gtest.h>
+#include <gui/constants.h>
#include "TestInputListener.h"
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 7d4c6386f8..ee4d3b8e79 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -29,9 +29,12 @@
#include <vector>
using android::base::StringPrintf;
+using android::gui::FocusRequest;
+using android::gui::TouchOcclusionMode;
+using android::gui::WindowInfo;
+using android::gui::WindowInfoHandle;
using android::os::InputEventInjectionResult;
using android::os::InputEventInjectionSync;
-using android::os::TouchOcclusionMode;
using namespace android::flag_operators;
namespace android::inputdispatcher {
@@ -43,7 +46,8 @@ static const nsecs_t ARBITRARY_TIME = 1234;
static const int32_t DEVICE_ID = 1;
// An arbitrary display id.
-static const int32_t DISPLAY_ID = ADISPLAY_ID_DEFAULT;
+static constexpr int32_t DISPLAY_ID = ADISPLAY_ID_DEFAULT;
+static constexpr int32_t SECOND_DISPLAY_ID = 1;
// An arbitrary injector pid / uid pair that has permission to inject events.
static const int32_t INJECTOR_PID = 999;
@@ -473,8 +477,8 @@ protected:
}
}
- void setFocusedWindow(const sp<InputWindowHandle>& window,
- const sp<InputWindowHandle>& focusedWindow = nullptr) {
+ void setFocusedWindow(const sp<WindowInfoHandle>& window,
+ const sp<WindowInfoHandle>& focusedWindow = nullptr) {
FocusRequest request;
request.token = window->getToken();
request.windowName = window->getName();
@@ -531,8 +535,8 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) {
event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
/*action*/ -1, 0, 0, edgeFlags, metaState, 0, classification,
identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
- AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_DISPLAY_SIZE,
- AMOTION_EVENT_INVALID_DISPLAY_SIZE, ARBITRARY_TIME, ARBITRARY_TIME,
+ AMOTION_EVENT_INVALID_CURSOR_POSITION, ui::Transform::ROT_0,
+ INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, ARBITRARY_TIME, ARBITRARY_TIME,
/*pointerCount*/ 1, pointerProperties, pointerCoords);
ASSERT_EQ(InputEventInjectionResult::FAILED,
mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
@@ -545,9 +549,9 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) {
(1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
0, 0, edgeFlags, metaState, 0, classification, identityTransform, 0, 0,
AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION,
- AMOTION_EVENT_INVALID_DISPLAY_SIZE, AMOTION_EVENT_INVALID_DISPLAY_SIZE,
- ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties,
- pointerCoords);
+ ui::Transform::ROT_0, INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE,
+ ARBITRARY_TIME, ARBITRARY_TIME,
+ /*pointerCount*/ 1, pointerProperties, pointerCoords);
ASSERT_EQ(InputEventInjectionResult::FAILED,
mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
InputEventInjectionSync::NONE, 0ms, 0))
@@ -558,9 +562,9 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) {
(~0U << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
0, 0, edgeFlags, metaState, 0, classification, identityTransform, 0, 0,
AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION,
- AMOTION_EVENT_INVALID_DISPLAY_SIZE, AMOTION_EVENT_INVALID_DISPLAY_SIZE,
- ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties,
- pointerCoords);
+ ui::Transform::ROT_0, INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE,
+ ARBITRARY_TIME, ARBITRARY_TIME,
+ /*pointerCount*/ 1, pointerProperties, pointerCoords);
ASSERT_EQ(InputEventInjectionResult::FAILED,
mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
InputEventInjectionSync::NONE, 0ms, 0))
@@ -572,9 +576,9 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) {
(1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
0, 0, edgeFlags, metaState, 0, classification, identityTransform, 0, 0,
AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION,
- AMOTION_EVENT_INVALID_DISPLAY_SIZE, AMOTION_EVENT_INVALID_DISPLAY_SIZE,
- ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties,
- pointerCoords);
+ ui::Transform::ROT_0, INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE,
+ ARBITRARY_TIME, ARBITRARY_TIME,
+ /*pointerCount*/ 1, pointerProperties, pointerCoords);
ASSERT_EQ(InputEventInjectionResult::FAILED,
mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
InputEventInjectionSync::NONE, 0ms, 0))
@@ -585,9 +589,9 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) {
(~0U << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
0, 0, edgeFlags, metaState, 0, classification, identityTransform, 0, 0,
AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION,
- AMOTION_EVENT_INVALID_DISPLAY_SIZE, AMOTION_EVENT_INVALID_DISPLAY_SIZE,
- ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties,
- pointerCoords);
+ ui::Transform::ROT_0, INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE,
+ ARBITRARY_TIME, ARBITRARY_TIME,
+ /*pointerCount*/ 1, pointerProperties, pointerCoords);
ASSERT_EQ(InputEventInjectionResult::FAILED,
mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
InputEventInjectionSync::NONE, 0ms, 0))
@@ -597,8 +601,8 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) {
event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification,
identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
- AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_DISPLAY_SIZE,
- AMOTION_EVENT_INVALID_DISPLAY_SIZE, ARBITRARY_TIME, ARBITRARY_TIME,
+ AMOTION_EVENT_INVALID_CURSOR_POSITION, ui::Transform::ROT_0,
+ INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, ARBITRARY_TIME, ARBITRARY_TIME,
/*pointerCount*/ 0, pointerProperties, pointerCoords);
ASSERT_EQ(InputEventInjectionResult::FAILED,
mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
@@ -608,8 +612,8 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) {
event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification,
identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
- AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_DISPLAY_SIZE,
- AMOTION_EVENT_INVALID_DISPLAY_SIZE, ARBITRARY_TIME, ARBITRARY_TIME,
+ AMOTION_EVENT_INVALID_CURSOR_POSITION, ui::Transform::ROT_0,
+ INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, ARBITRARY_TIME, ARBITRARY_TIME,
/*pointerCount*/ MAX_POINTERS + 1, pointerProperties, pointerCoords);
ASSERT_EQ(InputEventInjectionResult::FAILED,
mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
@@ -621,8 +625,8 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) {
event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification,
identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
- AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_DISPLAY_SIZE,
- AMOTION_EVENT_INVALID_DISPLAY_SIZE, ARBITRARY_TIME, ARBITRARY_TIME,
+ AMOTION_EVENT_INVALID_CURSOR_POSITION, ui::Transform::ROT_0,
+ INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, ARBITRARY_TIME, ARBITRARY_TIME,
/*pointerCount*/ 1, pointerProperties, pointerCoords);
ASSERT_EQ(InputEventInjectionResult::FAILED,
mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
@@ -633,8 +637,8 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) {
event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification,
identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
- AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_DISPLAY_SIZE,
- AMOTION_EVENT_INVALID_DISPLAY_SIZE, ARBITRARY_TIME, ARBITRARY_TIME,
+ AMOTION_EVENT_INVALID_CURSOR_POSITION, ui::Transform::ROT_0,
+ INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, ARBITRARY_TIME, ARBITRARY_TIME,
/*pointerCount*/ 1, pointerProperties, pointerCoords);
ASSERT_EQ(InputEventInjectionResult::FAILED,
mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
@@ -647,8 +651,8 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) {
event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification,
identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
- AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_DISPLAY_SIZE,
- AMOTION_EVENT_INVALID_DISPLAY_SIZE, ARBITRARY_TIME, ARBITRARY_TIME,
+ AMOTION_EVENT_INVALID_CURSOR_POSITION, ui::Transform::ROT_0,
+ INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, ARBITRARY_TIME, ARBITRARY_TIME,
/*pointerCount*/ 2, pointerProperties, pointerCoords);
ASSERT_EQ(InputEventInjectionResult::FAILED,
mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
@@ -896,7 +900,7 @@ protected:
std::string mName;
};
-class FakeWindowHandle : public InputWindowHandle {
+class FakeWindowHandle : public WindowInfoHandle {
public:
static const int32_t WIDTH = 600;
static const int32_t HEIGHT = 800;
@@ -918,7 +922,7 @@ public:
mInfo.token = *token;
mInfo.id = sId++;
mInfo.name = name;
- mInfo.type = InputWindowInfo::Type::APPLICATION;
+ mInfo.type = WindowInfo::Type::APPLICATION;
mInfo.dispatchingTimeout = DISPATCHING_TIMEOUT;
mInfo.alpha = 1.0;
mInfo.frameLeft = 0;
@@ -938,7 +942,14 @@ public:
mInfo.displayId = displayId;
}
- virtual bool updateInfo() { return true; }
+ sp<FakeWindowHandle> clone(
+ const std::shared_ptr<InputApplicationHandle>& inputApplicationHandle,
+ const sp<InputDispatcher>& dispatcher, int32_t displayId) {
+ sp<FakeWindowHandle> handle =
+ new FakeWindowHandle(inputApplicationHandle, dispatcher, mInfo.name + "(Mirror)",
+ displayId, mInfo.token);
+ return handle;
+ }
void setFocusable(bool focusable) { mInfo.focusable = focusable; }
@@ -952,9 +963,7 @@ public:
void setAlpha(float alpha) { mInfo.alpha = alpha; }
- void setTouchOcclusionMode(android::os::TouchOcclusionMode mode) {
- mInfo.touchOcclusionMode = mode;
- }
+ void setTouchOcclusionMode(TouchOcclusionMode mode) { mInfo.touchOcclusionMode = mode; }
void setApplicationToken(sp<IBinder> token) { mInfo.applicationInfo.token = token; }
@@ -968,11 +977,11 @@ public:
mInfo.addTouchableRegion(frame);
}
- void addFlags(Flags<InputWindowInfo::Flag> flags) { mInfo.flags |= flags; }
+ void addFlags(Flags<WindowInfo::Flag> flags) { mInfo.flags |= flags; }
- void setFlags(Flags<InputWindowInfo::Flag> flags) { mInfo.flags = flags; }
+ void setFlags(Flags<WindowInfo::Flag> flags) { mInfo.flags = flags; }
- void setInputFeatures(InputWindowInfo::Feature features) { mInfo.inputFeatures = features; }
+ void setInputFeatures(WindowInfo::Feature features) { mInfo.inputFeatures = features; }
void setWindowTransform(float dsdx, float dtdx, float dtdy, float dsdy) {
mInfo.transform.set(dsdx, dtdx, dtdy, dsdy);
@@ -1106,7 +1115,7 @@ public:
void assertNoEvents() {
if (mInputReceiver == nullptr &&
- mInfo.inputFeatures.test(InputWindowInfo::Feature::NO_INPUT_CHANNEL)) {
+ mInfo.inputFeatures.test(WindowInfo::Feature::NO_INPUT_CHANNEL)) {
return; // Can't receive events if the window does not have input channel
}
ASSERT_NE(nullptr, mInputReceiver)
@@ -1271,8 +1280,9 @@ public:
mAction, mActionButton, mFlags, /* edgeFlags */ 0, AMETA_NONE,
mButtonState, MotionClassification::NONE, identityTransform,
/* xPrecision */ 0, /* yPrecision */ 0, mRawXCursorPosition,
- mRawYCursorPosition, mDisplayWidth, mDisplayHeight, mEventTime, mEventTime,
- mPointers.size(), pointerProperties.data(), pointerCoords.data());
+ mRawYCursorPosition, mDisplayOrientation, mDisplayWidth, mDisplayHeight,
+ mEventTime, mEventTime, mPointers.size(), pointerProperties.data(),
+ pointerCoords.data());
return event;
}
@@ -1287,8 +1297,9 @@ private:
int32_t mFlags{0};
float mRawXCursorPosition{AMOTION_EVENT_INVALID_CURSOR_POSITION};
float mRawYCursorPosition{AMOTION_EVENT_INVALID_CURSOR_POSITION};
- int32_t mDisplayWidth{AMOTION_EVENT_INVALID_DISPLAY_SIZE};
- int32_t mDisplayHeight{AMOTION_EVENT_INVALID_DISPLAY_SIZE};
+ uint32_t mDisplayOrientation{ui::Transform::ROT_0};
+ int32_t mDisplayWidth{INVALID_DISPLAY_SIZE};
+ int32_t mDisplayHeight{INVALID_DISPLAY_SIZE};
std::vector<PointerBuilder> mPointers;
};
@@ -1415,7 +1426,7 @@ TEST_F(InputDispatcherTest, SetInputWindowOnce_SingleWindowTouch) {
sp<FakeWindowHandle> window =
new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
window->setFrame(Rect(0, 0, 100, 100));
- window->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL);
+ window->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
@@ -1438,7 +1449,7 @@ TEST_F(InputDispatcherTest, SetInputWindowTwice_SingleWindowTouch) {
sp<FakeWindowHandle> window =
new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
window->setFrame(Rect(0, 0, 100, 100));
- window->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL);
+ window->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
@@ -1474,11 +1485,11 @@ TEST_F(InputDispatcherTest, HoverMoveEnterMouseClickAndHoverMoveExit) {
sp<FakeWindowHandle> windowLeft =
new FakeWindowHandle(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
windowLeft->setFrame(Rect(0, 0, 600, 800));
- windowLeft->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL);
+ windowLeft->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
sp<FakeWindowHandle> windowRight =
new FakeWindowHandle(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
windowRight->setFrame(Rect(600, 0, 1200, 800));
- windowRight->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL);
+ windowRight->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
@@ -1585,7 +1596,7 @@ TEST_F(InputDispatcherTest, HoverEnterMouseClickAndHoverExit) {
sp<FakeWindowHandle> window =
new FakeWindowHandle(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
window->setFrame(Rect(0, 0, 1200, 800));
- window->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL);
+ window->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
@@ -1667,11 +1678,11 @@ TEST_F(InputDispatcherTest, DispatchMouseEventsUnderCursor) {
sp<FakeWindowHandle> windowLeft =
new FakeWindowHandle(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
windowLeft->setFrame(Rect(0, 0, 600, 800));
- windowLeft->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL);
+ windowLeft->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
sp<FakeWindowHandle> windowRight =
new FakeWindowHandle(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
windowRight->setFrame(Rect(600, 0, 1200, 800));
- windowRight->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL);
+ windowRight->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
@@ -1865,15 +1876,13 @@ TEST_F(InputDispatcherTest, TransferTouchFocus_TwoPointersSplitTouch) {
sp<FakeWindowHandle> firstWindow =
new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT);
firstWindow->setFrame(Rect(0, 0, 600, 400));
- firstWindow->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL |
- InputWindowInfo::Flag::SPLIT_TOUCH);
+ firstWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH);
// Create a non touch modal window that supports split touch
sp<FakeWindowHandle> secondWindow =
new FakeWindowHandle(application, mDispatcher, "Second Window", ADISPLAY_ID_DEFAULT);
secondWindow->setFrame(Rect(0, 400, 600, 800));
- secondWindow->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL |
- InputWindowInfo::Flag::SPLIT_TOUCH);
+ secondWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH);
// Add the windows to the dispatcher
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {firstWindow, secondWindow}}});
@@ -1939,15 +1948,13 @@ TEST_F(InputDispatcherTest, TransferTouch_TwoPointersSplitTouch) {
sp<FakeWindowHandle> firstWindow =
new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT);
firstWindow->setFrame(Rect(0, 0, 600, 400));
- firstWindow->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL |
- InputWindowInfo::Flag::SPLIT_TOUCH);
+ firstWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH);
// Create a non touch modal window that supports split touch
sp<FakeWindowHandle> secondWindow =
new FakeWindowHandle(application, mDispatcher, "Second Window", ADISPLAY_ID_DEFAULT);
secondWindow->setFrame(Rect(0, 400, 600, 800));
- secondWindow->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL |
- InputWindowInfo::Flag::SPLIT_TOUCH);
+ secondWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH);
// Add the windows to the dispatcher
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {firstWindow, secondWindow}}});
@@ -2004,6 +2011,134 @@ TEST_F(InputDispatcherTest, TransferTouch_TwoPointersSplitTouch) {
secondWindow->assertNoEvents();
}
+// This case will create two windows and one mirrored window on the default display and mirror
+// two windows on the second display. It will test if 'transferTouchFocus' works fine if we put
+// the windows info of second display before default display.
+TEST_F(InputDispatcherTest, TransferTouchFocus_CloneSurface) {
+ std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
+ sp<FakeWindowHandle> firstWindowInPrimary =
+ new FakeWindowHandle(application, mDispatcher, "D_1_W1", ADISPLAY_ID_DEFAULT);
+ firstWindowInPrimary->setFrame(Rect(0, 0, 100, 100));
+ firstWindowInPrimary->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
+ sp<FakeWindowHandle> secondWindowInPrimary =
+ new FakeWindowHandle(application, mDispatcher, "D_1_W2", ADISPLAY_ID_DEFAULT);
+ secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100));
+ secondWindowInPrimary->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
+
+ sp<FakeWindowHandle> mirrorWindowInPrimary =
+ firstWindowInPrimary->clone(application, mDispatcher, ADISPLAY_ID_DEFAULT);
+ mirrorWindowInPrimary->setFrame(Rect(0, 100, 100, 200));
+ mirrorWindowInPrimary->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
+
+ sp<FakeWindowHandle> firstWindowInSecondary =
+ firstWindowInPrimary->clone(application, mDispatcher, SECOND_DISPLAY_ID);
+ firstWindowInSecondary->setFrame(Rect(0, 0, 100, 100));
+ firstWindowInSecondary->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
+
+ sp<FakeWindowHandle> secondWindowInSecondary =
+ secondWindowInPrimary->clone(application, mDispatcher, SECOND_DISPLAY_ID);
+ secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100));
+ secondWindowInPrimary->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
+
+ // Update window info, let it find window handle of second display first.
+ mDispatcher->setInputWindows(
+ {{SECOND_DISPLAY_ID, {firstWindowInSecondary, secondWindowInSecondary}},
+ {ADISPLAY_ID_DEFAULT,
+ {mirrorWindowInPrimary, firstWindowInPrimary, secondWindowInPrimary}}});
+
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
+ {50, 50}))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+
+ // Window should receive motion event.
+ firstWindowInPrimary->consumeMotionDown(ADISPLAY_ID_DEFAULT);
+
+ // Transfer touch focus
+ ASSERT_TRUE(mDispatcher->transferTouchFocus(firstWindowInPrimary->getToken(),
+ secondWindowInPrimary->getToken()));
+ // The first window gets cancel.
+ firstWindowInPrimary->consumeMotionCancel();
+ secondWindowInPrimary->consumeMotionDown();
+
+ 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";
+ firstWindowInPrimary->assertNoEvents();
+ secondWindowInPrimary->consumeMotionMove();
+
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionUp(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
+ {150, 50}))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+ firstWindowInPrimary->assertNoEvents();
+ secondWindowInPrimary->consumeMotionUp();
+}
+
+// Same as TransferTouchFocus_CloneSurface, but this touch on the secondary display and use
+// 'transferTouch' api.
+TEST_F(InputDispatcherTest, TransferTouch_CloneSurface) {
+ std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
+ sp<FakeWindowHandle> firstWindowInPrimary =
+ new FakeWindowHandle(application, mDispatcher, "D_1_W1", ADISPLAY_ID_DEFAULT);
+ firstWindowInPrimary->setFrame(Rect(0, 0, 100, 100));
+ firstWindowInPrimary->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
+ sp<FakeWindowHandle> secondWindowInPrimary =
+ new FakeWindowHandle(application, mDispatcher, "D_1_W2", ADISPLAY_ID_DEFAULT);
+ secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100));
+ secondWindowInPrimary->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
+
+ sp<FakeWindowHandle> mirrorWindowInPrimary =
+ firstWindowInPrimary->clone(application, mDispatcher, ADISPLAY_ID_DEFAULT);
+ mirrorWindowInPrimary->setFrame(Rect(0, 100, 100, 200));
+ mirrorWindowInPrimary->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
+
+ sp<FakeWindowHandle> firstWindowInSecondary =
+ firstWindowInPrimary->clone(application, mDispatcher, SECOND_DISPLAY_ID);
+ firstWindowInSecondary->setFrame(Rect(0, 0, 100, 100));
+ firstWindowInSecondary->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
+
+ sp<FakeWindowHandle> secondWindowInSecondary =
+ secondWindowInPrimary->clone(application, mDispatcher, SECOND_DISPLAY_ID);
+ secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100));
+ secondWindowInPrimary->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
+
+ // Update window info, let it find window handle of second display first.
+ mDispatcher->setInputWindows(
+ {{SECOND_DISPLAY_ID, {firstWindowInSecondary, secondWindowInSecondary}},
+ {ADISPLAY_ID_DEFAULT,
+ {mirrorWindowInPrimary, firstWindowInPrimary, secondWindowInPrimary}}});
+
+ // Touch on second display.
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID, {50, 50}))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+
+ // Window should receive motion event.
+ firstWindowInPrimary->consumeMotionDown(SECOND_DISPLAY_ID);
+
+ // Transfer touch focus
+ ASSERT_TRUE(mDispatcher->transferTouch(secondWindowInSecondary->getToken()));
+
+ // The first window gets cancel.
+ firstWindowInPrimary->consumeMotionCancel(SECOND_DISPLAY_ID);
+ secondWindowInPrimary->consumeMotionDown(SECOND_DISPLAY_ID);
+
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
+ SECOND_DISPLAY_ID, {150, 50}))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+ firstWindowInPrimary->assertNoEvents();
+ secondWindowInPrimary->consumeMotionMove(SECOND_DISPLAY_ID);
+
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionUp(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID, {150, 50}))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+ firstWindowInPrimary->assertNoEvents();
+ secondWindowInPrimary->consumeMotionUp(SECOND_DISPLAY_ID);
+}
+
TEST_F(InputDispatcherTest, FocusedWindow_ReceivesFocusEventAndKeyEvent) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
sp<FakeWindowHandle> window =
@@ -2065,15 +2200,13 @@ TEST_F(InputDispatcherTest, PointerCancel_SendCancelWhenSplitTouch) {
sp<FakeWindowHandle> firstWindow =
new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT);
firstWindow->setFrame(Rect(0, 0, 600, 400));
- firstWindow->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL |
- InputWindowInfo::Flag::SPLIT_TOUCH);
+ firstWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH);
// Create second non touch modal window that supports split touch
sp<FakeWindowHandle> secondWindow =
new FakeWindowHandle(application, mDispatcher, "Second Window", ADISPLAY_ID_DEFAULT);
secondWindow->setFrame(Rect(0, 400, 600, 800));
- secondWindow->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL |
- InputWindowInfo::Flag::SPLIT_TOUCH);
+ secondWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH);
// Add the windows to the dispatcher
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {firstWindow, secondWindow}}});
@@ -2168,6 +2301,18 @@ public:
expectedDisplayId, expectedFlags);
}
+ void consumeMotionCancel(int32_t expectedDisplayId, int32_t expectedFlags = 0) {
+ mInputReceiver->consumeEvent(AINPUT_EVENT_TYPE_MOTION, AMOTION_EVENT_ACTION_CANCEL,
+ expectedDisplayId, expectedFlags);
+ }
+
+ void consumeMotionPointerDown(int32_t pointerIdx) {
+ int32_t action = AMOTION_EVENT_ACTION_POINTER_DOWN |
+ (pointerIdx << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
+ mInputReceiver->consumeEvent(AINPUT_EVENT_TYPE_MOTION, action, ADISPLAY_ID_DEFAULT,
+ 0 /*expectedFlags*/);
+ }
+
MotionEvent* consumeMotion() {
InputEvent* event = mInputReceiver->consume();
if (!event) {
@@ -2314,6 +2459,91 @@ TEST_F(InputDispatcherTest, TestMoveEvent) {
0 /*expectedFlags*/);
}
+TEST_F(InputDispatcherTest, GestureMonitor_SplitIfNoWindowTouched) {
+ FakeMonitorReceiver monitor = FakeMonitorReceiver(mDispatcher, "GM_1", ADISPLAY_ID_DEFAULT,
+ true /*isGestureMonitor*/);
+
+ std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
+ // Create a non touch modal window that supports split touch
+ sp<FakeWindowHandle> window =
+ new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
+ window->setFrame(Rect(0, 0, 100, 100));
+ window->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
+
+ // First finger down, no window touched.
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
+ {100, 200}))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+ monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT);
+ window->assertNoEvents();
+
+ // Second finger down on window, the window should receive touch down.
+ const MotionEvent secondFingerDownEvent =
+ MotionEventBuilder(AMOTION_EVENT_ACTION_POINTER_DOWN |
+ (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
+ AINPUT_SOURCE_TOUCHSCREEN)
+ .displayId(ADISPLAY_ID_DEFAULT)
+ .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
+ .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER)
+ .x(100)
+ .y(200))
+ .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50))
+ .build();
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
+ InputEventInjectionSync::WAIT_FOR_RESULT))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+
+ window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
+ monitor.consumeMotionPointerDown(1 /* pointerIndex */);
+}
+
+TEST_F(InputDispatcherTest, GestureMonitor_NoSplitAfterPilfer) {
+ FakeMonitorReceiver monitor = FakeMonitorReceiver(mDispatcher, "GM_1", ADISPLAY_ID_DEFAULT,
+ true /*isGestureMonitor*/);
+
+ std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
+ // Create a non touch modal window that supports split touch
+ sp<FakeWindowHandle> window =
+ new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
+ window->setFrame(Rect(0, 0, 100, 100));
+ window->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
+
+ // First finger down, no window touched.
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
+ {100, 200}))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+ monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT);
+ window->assertNoEvents();
+
+ // Gesture monitor pilfer the pointers.
+ mDispatcher->pilferPointers(monitor.getToken());
+
+ // Second finger down on window, the window should not receive touch down.
+ const MotionEvent secondFingerDownEvent =
+ MotionEventBuilder(AMOTION_EVENT_ACTION_POINTER_DOWN |
+ (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
+ AINPUT_SOURCE_TOUCHSCREEN)
+ .displayId(ADISPLAY_ID_DEFAULT)
+ .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
+ .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER)
+ .x(100)
+ .y(200))
+ .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50))
+ .build();
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
+ InputEventInjectionSync::WAIT_FOR_RESULT))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+
+ window->assertNoEvents();
+ monitor.consumeMotionPointerDown(1 /* pointerIndex */);
+}
+
/**
* Dispatcher has touch mode enabled by default. Typically, the policy overrides that value to
* the device default right away. In the test scenario, we check both the default value,
@@ -2437,7 +2667,7 @@ TEST_F(InputDispatcherTest, VerifyInputEvent_MotionEvent) {
EXPECT_EQ(motionArgs.buttonState, verifiedMotion.buttonState);
}
-TEST_F(InputDispatcherTest, NonPointerMotionEvent_NotTransformed) {
+TEST_F(InputDispatcherTest, NonPointerMotionEvent_JoystickAndTouchpadNotTransformed) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
sp<FakeWindowHandle> window =
new FakeWindowHandle(application, mDispatcher, "Test window", ADISPLAY_ID_DEFAULT);
@@ -2457,20 +2687,19 @@ TEST_F(InputDispatcherTest, NonPointerMotionEvent_NotTransformed) {
// Second, we consume focus event if it is right or wrong according to onFocusChangedLocked.
window->consumeFocusEvent(true);
- constexpr const std::array nonPointerSources = {AINPUT_SOURCE_TRACKBALL,
- AINPUT_SOURCE_MOUSE_RELATIVE,
- AINPUT_SOURCE_JOYSTICK};
- for (const int source : nonPointerSources) {
- // Notify motion with a non-pointer source.
- NotifyMotionArgs motionArgs =
- generateMotionArgs(AMOTION_EVENT_ACTION_MOVE, source, ADISPLAY_ID_DEFAULT);
+ constexpr const std::array nonTransformedSources = {std::pair(AINPUT_SOURCE_TOUCHPAD,
+ AMOTION_EVENT_ACTION_DOWN),
+ std::pair(AINPUT_SOURCE_JOYSTICK,
+ AMOTION_EVENT_ACTION_MOVE)};
+ for (const auto& [source, action] : nonTransformedSources) {
+ const NotifyMotionArgs motionArgs = generateMotionArgs(action, source, ADISPLAY_ID_DEFAULT);
mDispatcher->notifyMotion(&motionArgs);
MotionEvent* event = window->consumeMotion();
ASSERT_NE(event, nullptr);
const MotionEvent& motionEvent = *event;
- EXPECT_EQ(AMOTION_EVENT_ACTION_MOVE, motionEvent.getAction());
+ EXPECT_EQ(action, motionEvent.getAction());
EXPECT_EQ(motionArgs.pointerCount, motionEvent.getPointerCount());
float expectedX = motionArgs.pointerCoords[0].getX();
@@ -2742,8 +2971,7 @@ TEST_F(InputDispatcherTest, SlipperyWindow_SetsFlagPartiallyObscured) {
sp<FakeWindowHandle> slipperyExitWindow =
new FakeWindowHandle(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
- slipperyExitWindow->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL |
- InputWindowInfo::Flag::SLIPPERY);
+ slipperyExitWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SLIPPERY);
// Make sure this one overlaps the bottom window
slipperyExitWindow->setFrame(Rect(25, 25, 75, 75));
// Change the owner uid/pid of the window so that it is considered to be occluding the bottom
@@ -2928,7 +3156,6 @@ TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_RepeatKeyEventsUseUniqueEvent
/* Test InputDispatcher for MultiDisplay */
class InputDispatcherFocusOnTwoDisplaysTest : public InputDispatcherTest {
public:
- static constexpr int32_t SECOND_DISPLAY_ID = 1;
virtual void SetUp() override {
InputDispatcherTest::SetUp();
@@ -3091,8 +3318,6 @@ TEST_F(InputDispatcherFocusOnTwoDisplaysTest, CanFocusWindowOnUnfocusedDisplay)
class InputFilterTest : public InputDispatcherTest {
protected:
- static constexpr int32_t SECOND_DISPLAY_ID = 1;
-
void testNotifyMotion(int32_t displayId, bool expectToBeFiltered) {
NotifyMotionArgs motionArgs;
@@ -3226,9 +3451,9 @@ protected:
DISPLAY_ID, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0, 0,
AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0, MotionClassification::NONE,
identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
- AMOTION_EVENT_INVALID_CURSOR_POSITION,
- 0 /*AMOTION_EVENT_INVALID_DISPLAY_SIZE*/,
- 0 /*AMOTION_EVENT_INVALID_DISPLAY_SIZE*/, eventTime, eventTime,
+ AMOTION_EVENT_INVALID_CURSOR_POSITION, ui::Transform::ROT_0,
+ 0 /*INVALID_DISPLAY_SIZE*/, 0 /*INVALID_DISPLAY_SIZE*/, eventTime,
+ eventTime,
/*pointerCount*/ 1, pointerProperties, pointerCoords);
const int32_t additionalPolicyFlags = POLICY_FLAG_PASS_TO_USER;
@@ -3286,12 +3511,12 @@ class InputDispatcherOnPointerDownOutsideFocus : public InputDispatcherTest {
mUnfocusedWindow->setFrame(Rect(0, 0, 30, 30));
// Adding FLAG_NOT_TOUCH_MODAL to ensure taps outside this window are not sent to this
// window.
- mUnfocusedWindow->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL);
+ mUnfocusedWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
mFocusedWindow =
new FakeWindowHandle(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
mFocusedWindow->setFrame(Rect(50, 50, 100, 100));
- mFocusedWindow->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL);
+ mFocusedWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
// Set focused application.
mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
@@ -3400,14 +3625,12 @@ class InputDispatcherMultiWindowSameTokenTests : public InputDispatcherTest {
ADISPLAY_ID_DEFAULT);
// Adding FLAG_NOT_TOUCH_MODAL otherwise all taps will go to the top most window.
// We also need FLAG_SPLIT_TOUCH or we won't be able to get touches for both windows.
- mWindow1->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL |
- InputWindowInfo::Flag::SPLIT_TOUCH);
+ mWindow1->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH);
mWindow1->setFrame(Rect(0, 0, 100, 100));
mWindow2 = new FakeWindowHandle(application, mDispatcher, "Fake Window 2",
ADISPLAY_ID_DEFAULT, mWindow1->getToken());
- mWindow2->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL |
- InputWindowInfo::Flag::SPLIT_TOUCH);
+ mWindow2->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH);
mWindow2->setFrame(Rect(100, 100, 200, 200));
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow1, mWindow2}}});
@@ -3418,7 +3641,7 @@ protected:
sp<FakeWindowHandle> mWindow2;
// Helper function to convert the point from screen coordinates into the window's space
- static PointF getPointInWindow(const InputWindowInfo* windowInfo, const PointF& point) {
+ static PointF getPointInWindow(const WindowInfo* windowInfo, const PointF& point) {
vec2 vals = windowInfo->transform.transform(point.x, point.y);
return {vals.x, vals.y};
}
@@ -3606,7 +3829,7 @@ class InputDispatcherSingleWindowAnr : public InputDispatcherTest {
mWindow->setFocusable(true);
// Adding FLAG_NOT_TOUCH_MODAL to ensure taps outside this window are not sent to this
// window.
- mWindow->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL);
+ mWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
// Set focused application.
mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApplication);
@@ -4007,16 +4230,15 @@ class InputDispatcherMultiWindowAnr : public InputDispatcherTest {
// Adding FLAG_NOT_TOUCH_MODAL to ensure taps outside this window are not sent to this
// window.
// Adding FLAG_WATCH_OUTSIDE_TOUCH to receive ACTION_OUTSIDE when another window is tapped
- mUnfocusedWindow->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL |
- InputWindowInfo::Flag::WATCH_OUTSIDE_TOUCH |
- InputWindowInfo::Flag::SPLIT_TOUCH);
+ mUnfocusedWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL |
+ WindowInfo::Flag::WATCH_OUTSIDE_TOUCH |
+ WindowInfo::Flag::SPLIT_TOUCH);
mFocusedWindow =
new FakeWindowHandle(mApplication, mDispatcher, "Focused", ADISPLAY_ID_DEFAULT);
mFocusedWindow->setDispatchingTimeout(30ms);
mFocusedWindow->setFrame(Rect(50, 50, 100, 100));
- mFocusedWindow->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL |
- InputWindowInfo::Flag::SPLIT_TOUCH);
+ mFocusedWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH);
// Set focused application.
mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApplication);
@@ -4384,7 +4606,7 @@ class InputDispatcherMultiWindowOcclusionTests : public InputDispatcherTest {
"Window without input channel", ADISPLAY_ID_DEFAULT,
std::make_optional<sp<IBinder>>(nullptr) /*token*/);
- mNoInputWindow->setInputFeatures(InputWindowInfo::Feature::NO_INPUT_CHANNEL);
+ mNoInputWindow->setInputFeatures(WindowInfo::Feature::NO_INPUT_CHANNEL);
mNoInputWindow->setFrame(Rect(0, 0, 100, 100));
// It's perfectly valid for this window to not have an associated input channel
@@ -4426,7 +4648,7 @@ TEST_F(InputDispatcherMultiWindowOcclusionTests,
"Window with input channel and NO_INPUT_CHANNEL",
ADISPLAY_ID_DEFAULT);
- mNoInputWindow->setInputFeatures(InputWindowInfo::Feature::NO_INPUT_CHANNEL);
+ mNoInputWindow->setInputFeatures(WindowInfo::Feature::NO_INPUT_CHANNEL);
mNoInputWindow->setFrame(Rect(0, 0, 100, 100));
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mNoInputWindow, mBottomWindow}}});
@@ -4747,10 +4969,10 @@ protected:
mTouchWindow.clear();
}
- sp<FakeWindowHandle> getOccludingWindow(int32_t uid, std::string name,
- os::TouchOcclusionMode mode, float alpha = 1.0f) {
+ sp<FakeWindowHandle> getOccludingWindow(int32_t uid, std::string name, TouchOcclusionMode mode,
+ float alpha = 1.0f) {
sp<FakeWindowHandle> window = getWindow(uid, name);
- window->setFlags(InputWindowInfo::Flag::NOT_TOUCHABLE);
+ window->setFlags(WindowInfo::Flag::NOT_TOUCHABLE);
window->setTouchOcclusionMode(mode);
window->setAlpha(alpha);
return window;
@@ -4864,7 +5086,7 @@ TEST_F(InputDispatcherUntrustedTouchesTest,
WindowWithZeroOpacityAndWatchOutside_ReceivesOutsideEvent) {
const sp<FakeWindowHandle>& w =
getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, 0.0f);
- w->addFlags(InputWindowInfo::Flag::WATCH_OUTSIDE_TOUCH);
+ w->addFlags(WindowInfo::Flag::WATCH_OUTSIDE_TOUCH);
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w, mTouchWindow}}});
touch();
@@ -4875,7 +5097,7 @@ TEST_F(InputDispatcherUntrustedTouchesTest,
TEST_F(InputDispatcherUntrustedTouchesTest, OutsideEvent_HasZeroCoordinates) {
const sp<FakeWindowHandle>& w =
getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, 0.0f);
- w->addFlags(InputWindowInfo::Flag::WATCH_OUTSIDE_TOUCH);
+ w->addFlags(WindowInfo::Flag::WATCH_OUTSIDE_TOUCH);
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w, mTouchWindow}}});
touch();
@@ -5129,11 +5351,11 @@ protected:
mApp = std::make_shared<FakeApplicationHandle>();
mWindow = new FakeWindowHandle(mApp, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
mWindow->setFrame(Rect(0, 0, 100, 100));
- mWindow->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL);
+ mWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
mSecondWindow = new FakeWindowHandle(mApp, mDispatcher, "TestWindow2", ADISPLAY_ID_DEFAULT);
mSecondWindow->setFrame(Rect(100, 0, 200, 100));
- mSecondWindow->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL);
+ mSecondWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApp);
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow, mSecondWindow}}});
@@ -5341,4 +5563,134 @@ TEST_F(InputDispatcherDragTests, DragAndDrop_InvalidWindow) {
mSecondWindow->assertNoEvents();
}
+class InputDispatcherDropInputFeatureTest : public InputDispatcherTest {};
+
+TEST_F(InputDispatcherDropInputFeatureTest, WindowDropsInput) {
+ std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
+ sp<FakeWindowHandle> window =
+ new FakeWindowHandle(application, mDispatcher, "Test window", ADISPLAY_ID_DEFAULT);
+ window->setInputFeatures(WindowInfo::Feature::DROP_INPUT);
+ mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
+ window->setFocusable(true);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
+ setFocusedWindow(window);
+ window->consumeFocusEvent(true /*hasFocus*/, true /*inTouchMode*/);
+
+ // With the flag set, window should not get any input
+ NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT);
+ mDispatcher->notifyKey(&keyArgs);
+ window->assertNoEvents();
+
+ NotifyMotionArgs motionArgs =
+ generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
+ ADISPLAY_ID_DEFAULT);
+ mDispatcher->notifyMotion(&motionArgs);
+ window->assertNoEvents();
+
+ // With the flag cleared, the window should get input
+ window->setInputFeatures({});
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
+
+ keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT);
+ mDispatcher->notifyKey(&keyArgs);
+ window->consumeKeyUp(ADISPLAY_ID_DEFAULT);
+
+ motionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
+ ADISPLAY_ID_DEFAULT);
+ mDispatcher->notifyMotion(&motionArgs);
+ window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
+ window->assertNoEvents();
+}
+
+TEST_F(InputDispatcherDropInputFeatureTest, ObscuredWindowDropsInput) {
+ std::shared_ptr<FakeApplicationHandle> obscuringApplication =
+ std::make_shared<FakeApplicationHandle>();
+ sp<FakeWindowHandle> obscuringWindow =
+ new FakeWindowHandle(obscuringApplication, mDispatcher, "obscuringWindow",
+ ADISPLAY_ID_DEFAULT);
+ obscuringWindow->setFrame(Rect(0, 0, 50, 50));
+ obscuringWindow->setOwnerInfo(111, 111);
+ obscuringWindow->setFlags(WindowInfo::Flag::NOT_TOUCHABLE);
+ std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
+ sp<FakeWindowHandle> window =
+ new FakeWindowHandle(application, mDispatcher, "Test window", ADISPLAY_ID_DEFAULT);
+ window->setInputFeatures(WindowInfo::Feature::DROP_INPUT_IF_OBSCURED);
+ window->setOwnerInfo(222, 222);
+ mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
+ window->setFocusable(true);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {obscuringWindow, window}}});
+ setFocusedWindow(window);
+ window->consumeFocusEvent(true /*hasFocus*/, true /*inTouchMode*/);
+
+ // With the flag set, window should not get any input
+ NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT);
+ mDispatcher->notifyKey(&keyArgs);
+ window->assertNoEvents();
+
+ NotifyMotionArgs motionArgs =
+ generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
+ ADISPLAY_ID_DEFAULT);
+ mDispatcher->notifyMotion(&motionArgs);
+ window->assertNoEvents();
+
+ // With the flag cleared, the window should get input
+ window->setInputFeatures({});
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {obscuringWindow, window}}});
+
+ keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT);
+ mDispatcher->notifyKey(&keyArgs);
+ window->consumeKeyUp(ADISPLAY_ID_DEFAULT);
+
+ motionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
+ ADISPLAY_ID_DEFAULT);
+ mDispatcher->notifyMotion(&motionArgs);
+ window->consumeMotionDown(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED);
+ window->assertNoEvents();
+}
+
+TEST_F(InputDispatcherDropInputFeatureTest, UnobscuredWindowGetsInput) {
+ std::shared_ptr<FakeApplicationHandle> obscuringApplication =
+ std::make_shared<FakeApplicationHandle>();
+ sp<FakeWindowHandle> obscuringWindow =
+ new FakeWindowHandle(obscuringApplication, mDispatcher, "obscuringWindow",
+ ADISPLAY_ID_DEFAULT);
+ obscuringWindow->setFrame(Rect(0, 0, 50, 50));
+ obscuringWindow->setOwnerInfo(111, 111);
+ obscuringWindow->setFlags(WindowInfo::Flag::NOT_TOUCHABLE);
+ std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
+ sp<FakeWindowHandle> window =
+ new FakeWindowHandle(application, mDispatcher, "Test window", ADISPLAY_ID_DEFAULT);
+ window->setInputFeatures(WindowInfo::Feature::DROP_INPUT_IF_OBSCURED);
+ window->setOwnerInfo(222, 222);
+ mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
+ window->setFocusable(true);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {obscuringWindow, window}}});
+ setFocusedWindow(window);
+ window->consumeFocusEvent(true /*hasFocus*/, true /*inTouchMode*/);
+
+ // With the flag set, window should not get any input
+ NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT);
+ mDispatcher->notifyKey(&keyArgs);
+ window->assertNoEvents();
+
+ NotifyMotionArgs motionArgs =
+ generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
+ ADISPLAY_ID_DEFAULT);
+ mDispatcher->notifyMotion(&motionArgs);
+ window->assertNoEvents();
+
+ // When the window is no longer obscured because it went on top, it should get input
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window, obscuringWindow}}});
+
+ keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT);
+ mDispatcher->notifyKey(&keyArgs);
+ window->consumeKeyUp(ADISPLAY_ID_DEFAULT);
+
+ motionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
+ ADISPLAY_ID_DEFAULT);
+ mDispatcher->notifyMotion(&motionArgs);
+ window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
+ window->assertNoEvents();
+}
+
} // namespace android::inputdispatcher
diff --git a/services/inputflinger/tests/InputFlingerService_test.cpp b/services/inputflinger/tests/InputFlingerService_test.cpp
index c368e79f41..454e531af6 100644
--- a/services/inputflinger/tests/InputFlingerService_test.cpp
+++ b/services/inputflinger/tests/InputFlingerService_test.cpp
@@ -18,9 +18,7 @@
#include <IInputFlingerQuery.h>
#include <android/os/BnInputFlinger.h>
-#include <android/os/BnSetInputWindowsListener.h>
#include <android/os/IInputFlinger.h>
-#include <android/os/ISetInputWindowsListener.h>
#include <binder/Binder.h>
#include <binder/IPCThreadState.h>
@@ -30,7 +28,6 @@
#include <input/Input.h>
#include <input/InputTransport.h>
-#include <input/InputWindow.h>
#include <gtest/gtest.h>
#include <inttypes.h>
@@ -44,56 +41,18 @@
#define TAG "InputFlingerServiceTest"
+using android::gui::FocusRequest;
using android::os::BnInputFlinger;
-using android::os::BnSetInputWindowsListener;
using android::os::IInputFlinger;
-using android::os::ISetInputWindowsListener;
using std::chrono_literals::operator""ms;
using std::chrono_literals::operator""s;
namespace android {
-static const sp<IBinder> TestInfoToken = new BBinder();
-static const sp<IBinder> FocusedTestInfoToken = new BBinder();
-static constexpr int32_t TestInfoId = 1;
-static const std::string TestInfoName = "InputFlingerServiceTestInputWindowInfo";
-static constexpr Flags<InputWindowInfo::Flag> TestInfoFlags = InputWindowInfo::Flag::NOT_FOCUSABLE;
-static constexpr InputWindowInfo::Type TestInfoType = InputWindowInfo::Type::INPUT_METHOD;
-static constexpr std::chrono::duration TestInfoDispatchingTimeout = 2532ms;
-static constexpr int32_t TestInfoFrameLeft = 93;
-static constexpr int32_t TestInfoFrameTop = 34;
-static constexpr int32_t TestInfoFrameRight = 16;
-static constexpr int32_t TestInfoFrameBottom = 19;
-static constexpr int32_t TestInfoSurfaceInset = 17;
-static constexpr float TestInfoGlobalScaleFactor = 0.3;
-static constexpr float TestInfoWindowXScale = 0.4;
-static constexpr float TestInfoWindowYScale = 0.5;
-static const Rect TestInfoTouchableRegionRect = {100 /* left */, 150 /* top */, 400 /* right */,
- 450 /* bottom */};
-static const Region TestInfoTouchableRegion(TestInfoTouchableRegionRect);
-static constexpr bool TestInfoVisible = false;
-static constexpr bool TestInfoTrustedOverlay = true;
-static constexpr bool TestInfoFocusable = false;
-static constexpr bool TestInfoHasWallpaper = false;
-static constexpr bool TestInfoPaused = false;
-static constexpr int32_t TestInfoOwnerPid = 19;
-static constexpr int32_t TestInfoOwnerUid = 24;
-static constexpr InputWindowInfo::Feature TestInfoInputFeatures =
- InputWindowInfo::Feature::NO_INPUT_CHANNEL;
-static constexpr int32_t TestInfoDisplayId = 34;
-static constexpr int32_t TestInfoPortalToDisplayId = 2;
-static constexpr bool TestInfoReplaceTouchableRegionWithCrop = true;
-static const sp<IBinder> TestInfoTouchableRegionCropHandle = new BBinder();
-
-static const std::string TestAppInfoName = "InputFlingerServiceTestInputApplicationInfo";
-static const sp<IBinder> TestAppInfoToken = new BBinder();
-static constexpr std::chrono::duration TestAppInfoDispatchingTimeout = 12345678ms;
-
static const String16 kTestServiceName = String16("InputFlingerService");
static const String16 kQueryServiceName = String16("InputFlingerQueryService");
-struct SetInputWindowsListener;
// --- InputFlingerServiceTest ---
class InputFlingerServiceTest : public testing::Test {
public:
@@ -102,32 +61,15 @@ public:
protected:
void InitializeInputFlinger();
- void setInputWindowsByInfos(const std::vector<InputWindowInfo>& infos);
- void setFocusedWindow(const sp<IBinder> token, const sp<IBinder> focusedToken,
- nsecs_t timestampNanos);
-
- void setInputWindowsFinished();
- void verifyInputWindowInfo(const InputWindowInfo& info) const;
- InputWindowInfo& getInfo() const { return const_cast<InputWindowInfo&>(mInfo); }
sp<IInputFlinger> mService;
sp<IInputFlingerQuery> mQuery;
private:
- sp<SetInputWindowsListener> mSetInputWindowsListener;
std::unique_ptr<InputChannel> mServerChannel, mClientChannel;
- InputWindowInfo mInfo;
std::mutex mLock;
- std::condition_variable mSetInputWindowsFinishedCondition;
};
-struct SetInputWindowsListener : BnSetInputWindowsListener {
- explicit SetInputWindowsListener(std::function<void()> cbFunc) : mCbFunc(cbFunc) {}
-
- binder::Status onSetInputWindowsFinished() override;
-
- std::function<void()> mCbFunc;
-};
class TestInputManager : public BnInputFlinger {
protected:
@@ -136,16 +78,10 @@ protected:
public:
TestInputManager(){};
- binder::Status getInputWindows(std::vector<::android::InputWindowInfo>* inputHandles);
binder::Status getInputChannels(std::vector<::android::InputChannel>* channels);
- binder::Status getLastFocusRequest(FocusRequest*);
status_t dump(int fd, const Vector<String16>& args) override;
- binder::Status setInputWindows(
- const std::vector<InputWindowInfo>& handles,
- const sp<ISetInputWindowsListener>& setInputWindowsListener) override;
-
binder::Status createInputChannel(const std::string& name, InputChannel* outChannel) override;
binder::Status removeInputChannel(const sp<IBinder>& connectionToken) override;
binder::Status setFocusedWindow(const FocusRequest&) override;
@@ -154,63 +90,28 @@ public:
private:
mutable Mutex mLock;
- std::unordered_map<int32_t, std::vector<sp<InputWindowHandle>>> mHandlesPerDisplay;
std::vector<std::shared_ptr<InputChannel>> mInputChannels;
- FocusRequest mFocusRequest;
};
class TestInputQuery : public BnInputFlingerQuery {
public:
TestInputQuery(sp<android::TestInputManager> manager) : mManager(manager){};
- binder::Status getInputWindows(std::vector<::android::InputWindowInfo>* inputHandles) override;
binder::Status getInputChannels(std::vector<::android::InputChannel>* channels) override;
- binder::Status getLastFocusRequest(FocusRequest*) override;
binder::Status resetInputManager() override;
private:
sp<android::TestInputManager> mManager;
};
-binder::Status TestInputQuery::getInputWindows(
- std::vector<::android::InputWindowInfo>* inputHandles) {
- return mManager->getInputWindows(inputHandles);
-}
-
binder::Status TestInputQuery::getInputChannels(std::vector<::android::InputChannel>* channels) {
return mManager->getInputChannels(channels);
}
-binder::Status TestInputQuery::getLastFocusRequest(FocusRequest* request) {
- return mManager->getLastFocusRequest(request);
-}
-
binder::Status TestInputQuery::resetInputManager() {
mManager->reset();
return binder::Status::ok();
}
-binder::Status SetInputWindowsListener::onSetInputWindowsFinished() {
- if (mCbFunc != nullptr) {
- mCbFunc();
- }
- return binder::Status::ok();
-}
-
-binder::Status TestInputManager::setInputWindows(
- const std::vector<InputWindowInfo>& infos,
- const sp<ISetInputWindowsListener>& setInputWindowsListener) {
- AutoMutex _l(mLock);
-
- for (const auto& info : infos) {
- mHandlesPerDisplay.emplace(info.displayId, std::vector<sp<InputWindowHandle>>());
- mHandlesPerDisplay[info.displayId].push_back(new InputWindowHandle(info));
- }
- if (setInputWindowsListener) {
- setInputWindowsListener->onSetInputWindowsFinished();
- }
- return binder::Status::ok();
-}
-
binder::Status TestInputManager::createInputChannel(const std::string& name,
InputChannel* outChannel) {
AutoMutex _l(mLock);
@@ -248,16 +149,6 @@ status_t TestInputManager::dump(int fd, const Vector<String16>& args) {
return NO_ERROR;
}
-binder::Status TestInputManager::getInputWindows(
- std::vector<::android::InputWindowInfo>* inputInfos) {
- for (auto& [displayId, inputHandles] : mHandlesPerDisplay) {
- for (auto& inputHandle : inputHandles) {
- inputInfos->push_back(*inputHandle->getInfo());
- }
- }
- return binder::Status::ok();
-}
-
binder::Status TestInputManager::getInputChannels(std::vector<::android::InputChannel>* channels) {
channels->clear();
for (std::shared_ptr<InputChannel>& channel : mInputChannels) {
@@ -266,64 +157,16 @@ binder::Status TestInputManager::getInputChannels(std::vector<::android::InputCh
return binder::Status::ok();
}
-binder::Status TestInputManager::getLastFocusRequest(FocusRequest* request) {
- *request = mFocusRequest;
- return binder::Status::ok();
-}
-
binder::Status TestInputManager::setFocusedWindow(const FocusRequest& request) {
- mFocusRequest = request;
return binder::Status::ok();
}
void TestInputManager::reset() {
- mHandlesPerDisplay.clear();
mInputChannels.clear();
- mFocusRequest = FocusRequest();
}
void InputFlingerServiceTest::SetUp() {
- mSetInputWindowsListener = new SetInputWindowsListener([&]() {
- std::unique_lock<std::mutex> lock(mLock);
- mSetInputWindowsFinishedCondition.notify_all();
- });
InputChannel::openInputChannelPair("testchannels", mServerChannel, mClientChannel);
-
- mInfo.token = TestInfoToken;
- mInfo.id = TestInfoId;
- mInfo.name = TestInfoName;
- mInfo.flags = TestInfoFlags;
- mInfo.type = TestInfoType;
- mInfo.dispatchingTimeout = TestInfoDispatchingTimeout;
- mInfo.frameLeft = TestInfoFrameLeft;
- mInfo.frameTop = TestInfoFrameTop;
- mInfo.frameRight = TestInfoFrameRight;
- mInfo.frameBottom = TestInfoFrameBottom;
- mInfo.surfaceInset = TestInfoSurfaceInset;
- mInfo.globalScaleFactor = TestInfoGlobalScaleFactor;
- mInfo.transform.set({TestInfoWindowXScale, 0, TestInfoFrameLeft, 0, TestInfoWindowYScale,
- TestInfoFrameTop, 0, 0, 1});
- mInfo.touchableRegion = TestInfoTouchableRegion;
- mInfo.visible = TestInfoVisible;
- mInfo.trustedOverlay = TestInfoTrustedOverlay;
- mInfo.focusable = TestInfoFocusable;
-
- mInfo.hasWallpaper = TestInfoHasWallpaper;
- mInfo.paused = TestInfoPaused;
- mInfo.ownerPid = TestInfoOwnerPid;
- mInfo.ownerUid = TestInfoOwnerUid;
- mInfo.inputFeatures = TestInfoInputFeatures;
- mInfo.displayId = TestInfoDisplayId;
- mInfo.portalToDisplayId = TestInfoPortalToDisplayId;
- mInfo.replaceTouchableRegionWithCrop = TestInfoReplaceTouchableRegionWithCrop;
- mInfo.touchableRegionCropHandle = TestInfoTouchableRegionCropHandle;
-
- mInfo.applicationInfo.name = TestAppInfoName;
- mInfo.applicationInfo.token = TestAppInfoToken;
- mInfo.applicationInfo.dispatchingTimeoutMillis =
- std::chrono::duration_cast<std::chrono::milliseconds>(TestAppInfoDispatchingTimeout)
- .count();
-
InitializeInputFlinger();
}
@@ -331,10 +174,6 @@ void InputFlingerServiceTest::TearDown() {
mQuery->resetInputManager();
}
-void InputFlingerServiceTest::verifyInputWindowInfo(const InputWindowInfo& info) const {
- EXPECT_EQ(mInfo, info);
-}
-
void InputFlingerServiceTest::InitializeInputFlinger() {
sp<IBinder> input(defaultServiceManager()->waitForService(kTestServiceName));
ASSERT_TRUE(input != nullptr);
@@ -345,40 +184,6 @@ void InputFlingerServiceTest::InitializeInputFlinger() {
mQuery = interface_cast<IInputFlingerQuery>(input);
}
-void InputFlingerServiceTest::setInputWindowsByInfos(const std::vector<InputWindowInfo>& infos) {
- std::unique_lock<std::mutex> lock(mLock);
- mService->setInputWindows(infos, mSetInputWindowsListener);
- // Verify listener call
- EXPECT_NE(mSetInputWindowsFinishedCondition.wait_for(lock, 1s), std::cv_status::timeout);
-}
-
-void InputFlingerServiceTest::setFocusedWindow(const sp<IBinder> token,
- const sp<IBinder> focusedToken,
- nsecs_t timestampNanos) {
- FocusRequest request;
- request.token = TestInfoToken;
- request.focusedToken = focusedToken;
- request.timestamp = timestampNanos;
- mService->setFocusedWindow(request);
- // call set input windows and wait for the callback to drain the queue.
- setInputWindowsByInfos(std::vector<InputWindowInfo>());
-}
-
-/**
- * Test InputFlinger service interface SetInputWindows
- */
-TEST_F(InputFlingerServiceTest, InputWindow_SetInputWindows) {
- std::vector<InputWindowInfo> infos = {getInfo()};
- setInputWindowsByInfos(infos);
-
- // Verify input windows from service
- std::vector<::android::InputWindowInfo> windowInfos;
- mQuery->getInputWindows(&windowInfos);
- for (const ::android::InputWindowInfo& windowInfo : windowInfos) {
- verifyInputWindowInfo(windowInfo);
- }
-}
-
/**
* Test InputFlinger service interface createInputChannel
*/
@@ -397,7 +202,7 @@ TEST_F(InputFlingerServiceTest, CreateInputChannelReturnsUnblockedFd) {
EXPECT_EQ(result & O_NONBLOCK, O_NONBLOCK);
}
-TEST_F(InputFlingerServiceTest, InputWindow_CreateInputChannel) {
+TEST_F(InputFlingerServiceTest, CreateInputChannel) {
InputChannel channel;
ASSERT_TRUE(mService->createInputChannel("testchannels", &channel).isOk());
@@ -411,30 +216,6 @@ TEST_F(InputFlingerServiceTest, InputWindow_CreateInputChannel) {
EXPECT_EQ(channels.size(), 0UL);
}
-TEST_F(InputFlingerServiceTest, InputWindow_setFocusedWindow) {
- nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
- setFocusedWindow(TestInfoToken, nullptr /* focusedToken */, now);
-
- FocusRequest request;
- mQuery->getLastFocusRequest(&request);
-
- EXPECT_EQ(request.token, TestInfoToken);
- EXPECT_EQ(request.focusedToken, nullptr);
- EXPECT_EQ(request.timestamp, now);
-}
-
-TEST_F(InputFlingerServiceTest, InputWindow_setFocusedWindowWithFocusedToken) {
- nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
- setFocusedWindow(TestInfoToken, FocusedTestInfoToken, now);
-
- FocusRequest request;
- mQuery->getLastFocusRequest(&request);
-
- EXPECT_EQ(request.token, TestInfoToken);
- EXPECT_EQ(request.focusedToken, FocusedTestInfoToken);
- EXPECT_EQ(request.timestamp, now);
-}
-
} // namespace android
int main(int argc, char** argv) {
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 38dfe4041f..b419d9ab3d 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -16,6 +16,7 @@
#include <CursorInputMapper.h>
#include <InputDevice.h>
+#include <InputFlingerProperties.sysprop.h>
#include <InputMapper.h>
#include <InputReader.h>
#include <InputReaderBase.h>
@@ -32,6 +33,7 @@
#include <VibratorInputMapper.h>
#include <android-base/thread_annotations.h>
#include <gtest/gtest.h>
+#include <gui/constants.h>
#include <inttypes.h>
#include <math.h>
@@ -94,6 +96,17 @@ const std::unordered_map<std::string, LightColor> LIGHT_COLORS = {{"red", LightC
{"green", LightColor::GREEN},
{"blue", LightColor::BLUE}};
+static int32_t getInverseRotation(int32_t orientation) {
+ switch (orientation) {
+ case DISPLAY_ORIENTATION_90:
+ return DISPLAY_ORIENTATION_270;
+ case DISPLAY_ORIENTATION_270:
+ return DISPLAY_ORIENTATION_90;
+ default:
+ return orientation;
+ }
+}
+
// --- FakePointerController ---
class FakePointerController : public PointerControllerInterface {
@@ -2662,6 +2675,7 @@ protected:
static const int32_t DEVICE_CONTROLLER_NUMBER;
static const Flags<InputDeviceClass> DEVICE_CLASSES;
static const int32_t EVENTHUB_ID;
+ static const std::optional<bool> INITIAL_PER_WINDOW_INPUT_ROTATION_FLAG_VALUE;
std::shared_ptr<FakeEventHub> mFakeEventHub;
sp<FakeInputReaderPolicy> mFakePolicy;
@@ -2678,11 +2692,19 @@ protected:
mDevice = newDevice(DEVICE_ID, DEVICE_NAME, DEVICE_LOCATION, EVENTHUB_ID, classes);
}
- void SetUp() override { SetUp(DEVICE_CLASSES); }
+ void SetUp() override {
+ // Ensure per_window_input_rotation is enabled.
+ sysprop::InputFlingerProperties::per_window_input_rotation(true);
+
+ SetUp(DEVICE_CLASSES);
+ }
void TearDown() override {
mFakeListener.clear();
mFakePolicy.clear();
+
+ sysprop::InputFlingerProperties::per_window_input_rotation(
+ INITIAL_PER_WINDOW_INPUT_ROTATION_FLAG_VALUE);
}
void addConfigurationProperty(const char* key, const char* value) {
@@ -2794,6 +2816,8 @@ const int32_t InputMapperTest::DEVICE_CONTROLLER_NUMBER = 0;
const Flags<InputDeviceClass> InputMapperTest::DEVICE_CLASSES =
Flags<InputDeviceClass>(0); // not needed for current tests
const int32_t InputMapperTest::EVENTHUB_ID = 1;
+const std::optional<bool> InputMapperTest::INITIAL_PER_WINDOW_INPUT_ROTATION_FLAG_VALUE =
+ sysprop::InputFlingerProperties::per_window_input_rotation();
// --- SwitchInputMapperTest ---
@@ -4090,8 +4114,11 @@ TEST_F(CursorInputMapperTest, Process_ShouldHandleCombinedXYAndButtonUpdates) {
ASSERT_NO_FATAL_FAILURE(assertCursorPointerCoords(args.pointerCoords[0], 0.0f, 0.0f, 0.0f));
}
-TEST_F(CursorInputMapperTest, Process_WhenNotOrientationAware_ShouldNotRotateMotions) {
+TEST_F(CursorInputMapperTest, Process_WhenOrientationAware_ShouldNotRotateMotions) {
addConfigurationProperty("cursor.mode", "navigation");
+ // InputReader works in the un-rotated coordinate space, so orientation-aware devices do not
+ // need to be rotated.
+ addConfigurationProperty("cursor.orientationAware", "1");
CursorInputMapper& mapper = addMapperAndConfigure<CursorInputMapper>();
prepareDisplay(DISPLAY_ORIENTATION_90);
@@ -4105,9 +4132,10 @@ TEST_F(CursorInputMapperTest, Process_WhenNotOrientationAware_ShouldNotRotateMot
ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 1, -1, 1));
}
-TEST_F(CursorInputMapperTest, Process_WhenOrientationAware_ShouldRotateMotions) {
+TEST_F(CursorInputMapperTest, Process_WhenNotOrientationAware_ShouldRotateMotions) {
addConfigurationProperty("cursor.mode", "navigation");
- addConfigurationProperty("cursor.orientationAware", "1");
+ // Since InputReader works in the un-rotated coordinate space, only devices that are not
+ // orientation-aware are affected by display rotation.
CursorInputMapper& mapper = addMapperAndConfigure<CursorInputMapper>();
prepareDisplay(DISPLAY_ORIENTATION_0);
@@ -4121,14 +4149,14 @@ TEST_F(CursorInputMapperTest, Process_WhenOrientationAware_ShouldRotateMotions)
ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 1, -1, 1));
prepareDisplay(DISPLAY_ORIENTATION_90);
- ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, 1, 1, 0));
- ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 1, 1, -1));
- ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 0, 0, -1));
- ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, -1, -1, -1));
- ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, -1, -1, 0));
- ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, -1, -1, 1));
- ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 0, 0, 1));
- ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 1, 1, 1));
+ ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, 1, -1, 0));
+ ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 1, -1, 1));
+ ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 0, 0, 1));
+ ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, -1, 1, 1));
+ ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, -1, 1, 0));
+ ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, -1, 1, -1));
+ ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 0, 0, -1));
+ ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 1, -1, -1));
prepareDisplay(DISPLAY_ORIENTATION_180);
ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, 1, 0, -1));
@@ -4141,14 +4169,14 @@ TEST_F(CursorInputMapperTest, Process_WhenOrientationAware_ShouldRotateMotions)
ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 1, 1, -1));
prepareDisplay(DISPLAY_ORIENTATION_270);
- ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, 1, -1, 0));
- ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 1, -1, 1));
- ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 0, 0, 1));
- ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, -1, 1, 1));
- ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, -1, 1, 0));
- ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, -1, 1, -1));
- ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 0, 0, -1));
- ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 1, -1, -1));
+ ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, 1, 1, 0));
+ ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 1, 1, -1));
+ ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 0, 0, -1));
+ ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, -1, -1, -1));
+ ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, -1, -1, 0));
+ ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, -1, -1, 1));
+ ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 0, 0, 1));
+ ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 1, 1, 1));
}
TEST_F(CursorInputMapperTest, Process_ShouldHandleAllButtons) {
@@ -4634,6 +4662,8 @@ protected:
void prepareLocationCalibration();
int32_t toRawX(float displayX);
int32_t toRawY(float displayY);
+ int32_t toRotatedRawX(float displayX);
+ int32_t toRotatedRawY(float displayY);
float toCookedX(float rawX, float rawY);
float toCookedY(float rawX, float rawY);
float toDisplayX(int32_t rawX);
@@ -4716,6 +4746,14 @@ int32_t TouchInputMapperTest::toRawY(float displayY) {
return int32_t(displayY * (RAW_Y_MAX - RAW_Y_MIN + 1) / DISPLAY_HEIGHT + RAW_Y_MIN);
}
+int32_t TouchInputMapperTest::toRotatedRawX(float displayX) {
+ return int32_t(displayX * (RAW_X_MAX - RAW_X_MIN + 1) / DISPLAY_HEIGHT + RAW_X_MIN);
+}
+
+int32_t TouchInputMapperTest::toRotatedRawY(float displayY) {
+ return int32_t(displayY * (RAW_Y_MAX - RAW_Y_MIN + 1) / DISPLAY_WIDTH + RAW_Y_MIN);
+}
+
float TouchInputMapperTest::toCookedX(float rawX, float rawY) {
AFFINE_TRANSFORM.applyTo(rawX, rawY);
return rawX;
@@ -5370,11 +5408,12 @@ TEST_F(SingleTouchInputMapperTest, Process_NormalSingleTouchGesture) {
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled());
}
-TEST_F(SingleTouchInputMapperTest, Process_WhenNotOrientationAware_DoesNotRotateMotions) {
+TEST_F(SingleTouchInputMapperTest, Process_WhenOrientationAware_DoesNotRotateMotions) {
addConfigurationProperty("touch.deviceType", "touchScreen");
prepareButtons();
prepareAxes(POSITION);
- addConfigurationProperty("touch.orientationAware", "0");
+ // InputReader works in the un-rotated coordinate space, so orientation-aware devices do not
+ // need to be rotated. Touchscreens are orientation-aware by default.
SingleTouchInputMapper& mapper = addMapperAndConfigure<SingleTouchInputMapper>();
NotifyMotionArgs args;
@@ -5393,10 +5432,13 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenNotOrientationAware_DoesNotRotate
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled());
}
-TEST_F(SingleTouchInputMapperTest, Process_WhenOrientationAware_RotatesMotions) {
+TEST_F(SingleTouchInputMapperTest, Process_WhenNotOrientationAware_RotatesMotions) {
addConfigurationProperty("touch.deviceType", "touchScreen");
prepareButtons();
prepareAxes(POSITION);
+ // Since InputReader works in the un-rotated coordinate space, only devices that are not
+ // orientation-aware are affected by display rotation.
+ addConfigurationProperty("touch.orientationAware", "0");
SingleTouchInputMapper& mapper = addMapperAndConfigure<SingleTouchInputMapper>();
NotifyMotionArgs args;
@@ -5418,7 +5460,7 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenOrientationAware_RotatesMotions)
// Rotation 90.
clearViewports();
prepareDisplay(DISPLAY_ORIENTATION_90);
- processDown(mapper, RAW_X_MAX - toRawX(75) + RAW_X_MIN, toRawY(50));
+ processDown(mapper, toRawX(75), RAW_Y_MAX - toRawY(50) + RAW_Y_MIN);
processSync(mapper);
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
@@ -5446,7 +5488,7 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenOrientationAware_RotatesMotions)
// Rotation 270.
clearViewports();
prepareDisplay(DISPLAY_ORIENTATION_270);
- processDown(mapper, toRawX(75), RAW_Y_MAX - toRawY(50) + RAW_Y_MIN);
+ processDown(mapper, RAW_X_MAX - toRawX(75) + RAW_X_MIN, toRawY(50));
processSync(mapper);
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
@@ -5458,6 +5500,172 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenOrientationAware_RotatesMotions)
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled());
}
+TEST_F(SingleTouchInputMapperTest, Process_WhenOrientation0_RotatesMotions) {
+ addConfigurationProperty("touch.deviceType", "touchScreen");
+ prepareButtons();
+ prepareAxes(POSITION);
+ addConfigurationProperty("touch.orientationAware", "1");
+ addConfigurationProperty("touch.orientation", "ORIENTATION_0");
+ clearViewports();
+ prepareDisplay(DISPLAY_ORIENTATION_0);
+ auto& mapper = addMapperAndConfigure<SingleTouchInputMapper>();
+ NotifyMotionArgs args;
+
+ // Orientation 0.
+ processDown(mapper, toRawX(50), toRawY(75));
+ processSync(mapper);
+
+ EXPECT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
+ EXPECT_NEAR(50, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X), 1);
+ EXPECT_NEAR(75, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y), 1);
+
+ processUp(mapper);
+ processSync(mapper);
+ EXPECT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled());
+}
+
+TEST_F(SingleTouchInputMapperTest, Process_WhenOrientation90_RotatesMotions) {
+ addConfigurationProperty("touch.deviceType", "touchScreen");
+ prepareButtons();
+ prepareAxes(POSITION);
+ addConfigurationProperty("touch.orientationAware", "1");
+ addConfigurationProperty("touch.orientation", "ORIENTATION_90");
+ clearViewports();
+ prepareDisplay(DISPLAY_ORIENTATION_0);
+ auto& mapper = addMapperAndConfigure<SingleTouchInputMapper>();
+ NotifyMotionArgs args;
+
+ // Orientation 90.
+ processDown(mapper, RAW_X_MAX - toRotatedRawX(75) + RAW_X_MIN, toRotatedRawY(50));
+ processSync(mapper);
+
+ EXPECT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
+ EXPECT_NEAR(50, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X), 1);
+ EXPECT_NEAR(75, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y), 1);
+
+ processUp(mapper);
+ processSync(mapper);
+ EXPECT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled());
+}
+
+TEST_F(SingleTouchInputMapperTest, Process_WhenOrientation180_RotatesMotions) {
+ addConfigurationProperty("touch.deviceType", "touchScreen");
+ prepareButtons();
+ prepareAxes(POSITION);
+ addConfigurationProperty("touch.orientationAware", "1");
+ addConfigurationProperty("touch.orientation", "ORIENTATION_180");
+ clearViewports();
+ prepareDisplay(DISPLAY_ORIENTATION_0);
+ auto& mapper = addMapperAndConfigure<SingleTouchInputMapper>();
+ NotifyMotionArgs args;
+
+ // Orientation 180.
+ processDown(mapper, RAW_X_MAX - toRawX(50) + RAW_X_MIN, RAW_Y_MAX - toRawY(75) + RAW_Y_MIN);
+ processSync(mapper);
+
+ EXPECT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
+ EXPECT_NEAR(50, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X), 1);
+ EXPECT_NEAR(75, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y), 1);
+
+ processUp(mapper);
+ processSync(mapper);
+ EXPECT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled());
+}
+
+TEST_F(SingleTouchInputMapperTest, Process_WhenOrientation270_RotatesMotions) {
+ addConfigurationProperty("touch.deviceType", "touchScreen");
+ prepareButtons();
+ prepareAxes(POSITION);
+ addConfigurationProperty("touch.orientationAware", "1");
+ addConfigurationProperty("touch.orientation", "ORIENTATION_270");
+ clearViewports();
+ prepareDisplay(DISPLAY_ORIENTATION_0);
+ auto& mapper = addMapperAndConfigure<SingleTouchInputMapper>();
+ NotifyMotionArgs args;
+
+ // Orientation 270.
+ processDown(mapper, toRotatedRawX(75), RAW_Y_MAX - toRotatedRawY(50) + RAW_Y_MIN);
+ processSync(mapper);
+
+ EXPECT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
+ EXPECT_NEAR(50, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X), 1);
+ EXPECT_NEAR(75, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y), 1);
+
+ processUp(mapper);
+ processSync(mapper);
+ EXPECT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled());
+}
+
+TEST_F(SingleTouchInputMapperTest, Process_WhenOrientationSpecified_RotatesMotionWithDisplay) {
+ addConfigurationProperty("touch.deviceType", "touchScreen");
+ prepareButtons();
+ prepareAxes(POSITION);
+ // Since InputReader works in the un-rotated coordinate space, only devices that are not
+ // orientation-aware are affected by display rotation.
+ addConfigurationProperty("touch.orientationAware", "0");
+ addConfigurationProperty("touch.orientation", "ORIENTATION_90");
+ auto& mapper = addMapperAndConfigure<SingleTouchInputMapper>();
+
+ NotifyMotionArgs args;
+
+ // Orientation 90, Rotation 0.
+ clearViewports();
+ prepareDisplay(DISPLAY_ORIENTATION_0);
+ processDown(mapper, RAW_X_MAX - toRotatedRawX(75) + RAW_X_MIN, toRotatedRawY(50));
+ processSync(mapper);
+
+ EXPECT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
+ EXPECT_NEAR(50, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X), 1);
+ EXPECT_NEAR(75, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y), 1);
+
+ processUp(mapper);
+ processSync(mapper);
+ EXPECT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled());
+
+ // Orientation 90, Rotation 90.
+ clearViewports();
+ prepareDisplay(DISPLAY_ORIENTATION_90);
+ processDown(mapper, toRotatedRawX(50), toRotatedRawY(75));
+ processSync(mapper);
+
+ EXPECT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
+ EXPECT_NEAR(50, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X), 1);
+ EXPECT_NEAR(75, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y), 1);
+
+ processUp(mapper);
+ processSync(mapper);
+ EXPECT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled());
+
+ // Orientation 90, Rotation 180.
+ clearViewports();
+ prepareDisplay(DISPLAY_ORIENTATION_180);
+ processDown(mapper, toRotatedRawX(75), RAW_Y_MAX - toRotatedRawY(50) + RAW_Y_MIN);
+ processSync(mapper);
+
+ EXPECT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
+ EXPECT_NEAR(50, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X), 1);
+ EXPECT_NEAR(75, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y), 1);
+
+ processUp(mapper);
+ processSync(mapper);
+ EXPECT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled());
+
+ // Orientation 90, Rotation 270.
+ clearViewports();
+ prepareDisplay(DISPLAY_ORIENTATION_270);
+ processDown(mapper, RAW_X_MAX - toRotatedRawX(50) + RAW_X_MIN,
+ RAW_Y_MAX - toRotatedRawY(75) + RAW_Y_MIN);
+ processSync(mapper);
+
+ EXPECT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
+ EXPECT_NEAR(50, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X), 1);
+ EXPECT_NEAR(75, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y), 1);
+
+ processUp(mapper);
+ processSync(mapper);
+ EXPECT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled());
+}
+
TEST_F(SingleTouchInputMapperTest, Process_AllAxes_DefaultCalibration) {
addConfigurationProperty("touch.deviceType", "touchScreen");
prepareDisplay(DISPLAY_ORIENTATION_0);
@@ -7808,7 +8016,7 @@ TEST_F(MultiTouchInputMapperTest, VideoFrames_ReceivedByListener) {
ASSERT_EQ(std::vector<TouchVideoFrame>(), motionArgs.videoFrames);
}
-TEST_F(MultiTouchInputMapperTest, VideoFrames_AreRotated) {
+TEST_F(MultiTouchInputMapperTest, VideoFrames_AreNotRotated) {
prepareAxes(POSITION);
addConfigurationProperty("touch.deviceType", "touchScreen");
MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
@@ -7818,6 +8026,32 @@ TEST_F(MultiTouchInputMapperTest, VideoFrames_AreRotated) {
// Test all 4 orientations
for (int32_t orientation : {DISPLAY_ORIENTATION_0, DISPLAY_ORIENTATION_90,
+ DISPLAY_ORIENTATION_180, DISPLAY_ORIENTATION_270}) {
+ SCOPED_TRACE("Orientation " + StringPrintf("%i", orientation));
+ clearViewports();
+ prepareDisplay(orientation);
+ std::vector<TouchVideoFrame> frames{frame};
+ mFakeEventHub->setVideoFrames({{EVENTHUB_ID, frames}});
+ processPosition(mapper, 100, 200);
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+ ASSERT_EQ(frames, motionArgs.videoFrames);
+ }
+}
+
+TEST_F(MultiTouchInputMapperTest, VideoFrames_WhenNotOrientationAware_AreRotated) {
+ prepareAxes(POSITION);
+ addConfigurationProperty("touch.deviceType", "touchScreen");
+ // Since InputReader works in the un-rotated coordinate space, only devices that are not
+ // orientation-aware are affected by display rotation.
+ addConfigurationProperty("touch.orientationAware", "0");
+ MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
+ // Unrotated video frame
+ TouchVideoFrame frame(3, 2, {1, 2, 3, 4, 5, 6}, {1, 2});
+ NotifyMotionArgs motionArgs;
+
+ // Test all 4 orientations
+ for (int32_t orientation : {DISPLAY_ORIENTATION_0, DISPLAY_ORIENTATION_90,
DISPLAY_ORIENTATION_180, DISPLAY_ORIENTATION_270}) {
SCOPED_TRACE("Orientation " + StringPrintf("%i", orientation));
clearViewports();
@@ -7827,12 +8061,16 @@ TEST_F(MultiTouchInputMapperTest, VideoFrames_AreRotated) {
processPosition(mapper, 100, 200);
processSync(mapper);
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
- frames[0].rotate(orientation);
+ // We expect the raw coordinates of the MotionEvent to be rotated in the inverse direction
+ // compared to the display. This is so that when the window transform (which contains the
+ // display rotation) is applied later by InputDispatcher, the coordinates end up in the
+ // window's coordinate space.
+ frames[0].rotate(getInverseRotation(orientation));
ASSERT_EQ(frames, motionArgs.videoFrames);
}
}
-TEST_F(MultiTouchInputMapperTest, VideoFrames_MultipleFramesAreRotated) {
+TEST_F(MultiTouchInputMapperTest, VideoFrames_MultipleFramesAreNotRotated) {
prepareAxes(POSITION);
addConfigurationProperty("touch.deviceType", "touchScreen");
MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
@@ -7849,8 +8087,36 @@ TEST_F(MultiTouchInputMapperTest, VideoFrames_MultipleFramesAreRotated) {
processPosition(mapper, 100, 200);
processSync(mapper);
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
- std::for_each(frames.begin(), frames.end(),
- [](TouchVideoFrame& frame) { frame.rotate(DISPLAY_ORIENTATION_90); });
+ ASSERT_EQ(frames, motionArgs.videoFrames);
+}
+
+TEST_F(MultiTouchInputMapperTest, VideoFrames_WhenNotOrientationAware_MultipleFramesAreRotated) {
+ prepareAxes(POSITION);
+ addConfigurationProperty("touch.deviceType", "touchScreen");
+ // Since InputReader works in the un-rotated coordinate space, only devices that are not
+ // orientation-aware are affected by display rotation.
+ addConfigurationProperty("touch.orientationAware", "0");
+ MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
+ // Unrotated video frames. There's no rule that they must all have the same dimensions,
+ // so mix these.
+ TouchVideoFrame frame1(3, 2, {1, 2, 3, 4, 5, 6}, {1, 2});
+ TouchVideoFrame frame2(3, 3, {0, 1, 2, 3, 4, 5, 6, 7, 8}, {1, 3});
+ TouchVideoFrame frame3(2, 2, {10, 20, 10, 0}, {1, 4});
+ std::vector<TouchVideoFrame> frames{frame1, frame2, frame3};
+ NotifyMotionArgs motionArgs;
+
+ prepareDisplay(DISPLAY_ORIENTATION_90);
+ mFakeEventHub->setVideoFrames({{EVENTHUB_ID, frames}});
+ processPosition(mapper, 100, 200);
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+ std::for_each(frames.begin(), frames.end(), [](TouchVideoFrame& frame) {
+ // We expect the raw coordinates of the MotionEvent to be rotated in the inverse direction
+ // compared to the display. This is so that when the window transform (which contains the
+ // display rotation) is applied later by InputDispatcher, the coordinates end up in the
+ // window's coordinate space.
+ frame.rotate(getInverseRotation(DISPLAY_ORIENTATION_90));
+ });
ASSERT_EQ(frames, motionArgs.videoFrames);
}
@@ -8404,18 +8670,25 @@ TEST_F(MultiTouchInputMapperTest_SurfaceRange, Viewports_SurfaceRange) {
// Reset.
mapper.reset(ARBITRARY_TIME);
- // Let physical display be different to device, and make surface and physical could be 1:1.
- halfDisplayToCenterHorizontal(DISPLAY_ORIENTATION_0);
+ // Let physical display be different to device, and make surface and physical could be 1:1 in
+ // all four orientations.
+ for (int orientation : {DISPLAY_ORIENTATION_0, DISPLAY_ORIENTATION_90, DISPLAY_ORIENTATION_180,
+ DISPLAY_ORIENTATION_270}) {
+ halfDisplayToCenterHorizontal(orientation);
- const int32_t xExpected = (x + 1) - (DISPLAY_WIDTH / 4);
- const int32_t yExpected = y;
- processPositionAndVerify(mapper, x - 1, y, x + 1, y, xExpected, yExpected);
+ const int32_t xExpected = (x + 1) - (DISPLAY_WIDTH / 4);
+ const int32_t yExpected = y;
+ processPositionAndVerify(mapper, x - 1, y, x + 1, y, xExpected, yExpected);
+ }
}
-TEST_F(MultiTouchInputMapperTest_SurfaceRange, Viewports_SurfaceRange_90) {
+TEST_F(MultiTouchInputMapperTest_SurfaceRange, Viewports_SurfaceRange_90_NotOrientationAware) {
addConfigurationProperty("touch.deviceType", "touchScreen");
prepareDisplay(DISPLAY_ORIENTATION_0);
prepareAxes(POSITION);
+ // Since InputReader works in the un-rotated coordinate space, only devices that are not
+ // orientation-aware are affected by display rotation.
+ addConfigurationProperty("touch.orientationAware", "0");
MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
// Half display to (width/4, 0, width * 3/4, height) and rotate 90-degrees.
@@ -8424,16 +8697,19 @@ TEST_F(MultiTouchInputMapperTest_SurfaceRange, Viewports_SurfaceRange_90) {
const int32_t x = DISPLAY_WIDTH / 4;
const int32_t y = DISPLAY_HEIGHT / 2;
- // expect x/y = swap x/y then reverse y.
- const int32_t xExpected = y;
- const int32_t yExpected = (DISPLAY_WIDTH * 3 / 4) - (x + 1);
+ // expect x/y = swap x/y then reverse x.
+ constexpr int32_t xExpected = DISPLAY_HEIGHT - y;
+ constexpr int32_t yExpected = (x + 1) - DISPLAY_WIDTH / 4;
processPositionAndVerify(mapper, x - 1, y, x + 1, y, xExpected, yExpected);
}
-TEST_F(MultiTouchInputMapperTest_SurfaceRange, Viewports_SurfaceRange_270) {
+TEST_F(MultiTouchInputMapperTest_SurfaceRange, Viewports_SurfaceRange_270_NotOrientationAware) {
addConfigurationProperty("touch.deviceType", "touchScreen");
prepareDisplay(DISPLAY_ORIENTATION_0);
prepareAxes(POSITION);
+ // Since InputReader works in the un-rotated coordinate space, only devices that are not
+ // orientation-aware are affected by display rotation.
+ addConfigurationProperty("touch.orientationAware", "0");
MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
// Half display to (width/4, 0, width * 3/4, height) and rotate 270-degrees.
@@ -8442,16 +8718,19 @@ TEST_F(MultiTouchInputMapperTest_SurfaceRange, Viewports_SurfaceRange_270) {
const int32_t x = DISPLAY_WIDTH / 4;
const int32_t y = DISPLAY_HEIGHT / 2;
- // expect x/y = swap x/y then reverse x.
- constexpr int32_t xExpected = DISPLAY_HEIGHT - y;
- constexpr int32_t yExpected = (x + 1) - DISPLAY_WIDTH / 4;
+ // expect x/y = swap x/y then reverse y.
+ const int32_t xExpected = y;
+ const int32_t yExpected = (DISPLAY_WIDTH * 3 / 4) - (x + 1);
processPositionAndVerify(mapper, x - 1, y, x + 1, y, xExpected, yExpected);
}
-TEST_F(MultiTouchInputMapperTest_SurfaceRange, Viewports_SurfaceRange_Corner) {
+TEST_F(MultiTouchInputMapperTest_SurfaceRange, Viewports_SurfaceRange_Corner_NotOrientationAware) {
addConfigurationProperty("touch.deviceType", "touchScreen");
prepareDisplay(DISPLAY_ORIENTATION_0);
prepareAxes(POSITION);
+ // Since InputReader works in the un-rotated coordinate space, only devices that are not
+ // orientation-aware are affected by display rotation.
+ addConfigurationProperty("touch.orientationAware", "0");
MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
const int32_t x = 0;
@@ -8463,16 +8742,16 @@ TEST_F(MultiTouchInputMapperTest_SurfaceRange, Viewports_SurfaceRange_Corner) {
clearViewports();
prepareDisplay(DISPLAY_ORIENTATION_90);
- // expect x/y = swap x/y then reverse y.
- const int32_t xExpected90 = y;
- const int32_t yExpected90 = DISPLAY_WIDTH - 1;
+ // expect x/y = swap x/y then reverse x.
+ const int32_t xExpected90 = DISPLAY_HEIGHT - 1;
+ const int32_t yExpected90 = x;
processPositionAndVerify(mapper, x - 1, y, x, y, xExpected90, yExpected90);
clearViewports();
prepareDisplay(DISPLAY_ORIENTATION_270);
- // expect x/y = swap x/y then reverse x.
- const int32_t xExpected270 = DISPLAY_HEIGHT - 1;
- const int32_t yExpected270 = x;
+ // expect x/y = swap x/y then reverse y.
+ const int32_t xExpected270 = y;
+ const int32_t yExpected270 = DISPLAY_WIDTH - 1;
processPositionAndVerify(mapper, x - 1, y, x, y, xExpected270, yExpected270);
}
diff --git a/services/inputflinger/tests/fuzzers/Android.bp b/services/inputflinger/tests/fuzzers/Android.bp
index df4db199f8..455a1e2133 100644
--- a/services/inputflinger/tests/fuzzers/Android.bp
+++ b/services/inputflinger/tests/fuzzers/Android.bp
@@ -42,4 +42,7 @@ cc_fuzz {
srcs: [
"LatencyTrackerFuzzer.cpp",
],
+ fuzz_config: {
+ cc: ["android-framework-input@google.com"],
+ },
}
diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp
index ec31afe367..e4efde2448 100644
--- a/services/sensorservice/SensorDevice.cpp
+++ b/services/sensorservice/SensorDevice.cpp
@@ -614,6 +614,8 @@ ssize_t SensorDevice::pollFmq(sensors_event_t* buffer, size_t maxNumEventsToRead
Return<void> SensorDevice::onDynamicSensorsConnected(
const hidl_vec<SensorInfo> &dynamicSensorsAdded) {
+ std::unique_lock<std::mutex> lock(mDynamicSensorsMutex);
+
// Allocate a sensor_t structure for each dynamic sensor added and insert
// it into the dictionary of connected dynamic sensors keyed by handle.
for (size_t i = 0; i < dynamicSensorsAdded.size(); ++i) {
@@ -629,6 +631,8 @@ Return<void> SensorDevice::onDynamicSensorsConnected(
std::make_pair(sensor->handle, sensor));
}
+ mDynamicSensorsCv.notify_all();
+
return Return<void>();
}
@@ -1174,8 +1178,20 @@ void SensorDevice::convertToSensorEvent(
dst->dynamic_sensor_meta.connected = dyn.connected;
dst->dynamic_sensor_meta.handle = dyn.sensorHandle;
if (dyn.connected) {
+ std::unique_lock<std::mutex> lock(mDynamicSensorsMutex);
+ // Give MAX_DYN_SENSOR_WAIT_SEC for onDynamicSensorsConnected to be invoked since it
+ // can be received out of order from this event due to a bug in the HIDL spec that
+ // marks it as oneway.
auto it = mConnectedDynamicSensors.find(dyn.sensorHandle);
- CHECK(it != mConnectedDynamicSensors.end());
+ if (it == mConnectedDynamicSensors.end()) {
+ mDynamicSensorsCv.wait_for(lock, MAX_DYN_SENSOR_WAIT,
+ [&, dyn]{
+ return mConnectedDynamicSensors.find(dyn.sensorHandle)
+ != mConnectedDynamicSensors.end();
+ });
+ it = mConnectedDynamicSensors.find(dyn.sensorHandle);
+ CHECK(it != mConnectedDynamicSensors.end());
+ }
dst->dynamic_sensor_meta.sensor = it->second;
diff --git a/services/sensorservice/SensorDevice.h b/services/sensorservice/SensorDevice.h
index 75da7bb0a1..bc8d20fbf6 100644
--- a/services/sensorservice/SensorDevice.h
+++ b/services/sensorservice/SensorDevice.h
@@ -139,6 +139,14 @@ private:
Vector<sensor_t> mSensorList;
std::unordered_map<int32_t, sensor_t*> mConnectedDynamicSensors;
+ // A bug in the Sensors HIDL spec which marks onDynamicSensorsConnected as oneway causes dynamic
+ // meta events and onDynamicSensorsConnected to be received out of order. This mutex + CV are
+ // used to block meta event processing until onDynamicSensorsConnected is received to simplify
+ // HAL implementations.
+ std::mutex mDynamicSensorsMutex;
+ std::condition_variable mDynamicSensorsCv;
+ static constexpr std::chrono::seconds MAX_DYN_SENSOR_WAIT{5};
+
static const nsecs_t MINIMUM_EVENTS_PERIOD = 1000000; // 1000 Hz
mutable Mutex mLock; // protect mActivationCount[].batchParams
// fixed-size array after construction
diff --git a/services/sensorservice/SensorInterface.cpp b/services/sensorservice/SensorInterface.cpp
index c285c00623..46f00e8329 100644
--- a/services/sensorservice/SensorInterface.cpp
+++ b/services/sensorservice/SensorInterface.cpp
@@ -92,31 +92,13 @@ ProximitySensor::ProximitySensor(const sensor_t& sensor, SensorService& service)
}
status_t ProximitySensor::activate(void* ident, bool enabled) {
- bool lastState = mSensorDevice.isSensorActive(mSensor.getHandle());
-
status_t status = HardwareSensor::activate(ident, enabled);
if (status != NO_ERROR) {
return status;
}
-
- bool currentState = mSensorDevice.isSensorActive(mSensor.getHandle());
- if (currentState != lastState) {
- mSensorService.onProximityActiveLocked(currentState);
- }
+ mSensorService.checkAndReportProxStateChangeLocked();
return NO_ERROR;
}
-void ProximitySensor::willDisableAllSensors() {
- if (mSensorDevice.isSensorActive(mSensor.getHandle())) {
- mSensorService.onProximityActiveLocked(false);
- }
-}
-
-void ProximitySensor::didEnableAllSensors() {
- if (mSensorDevice.isSensorActive(mSensor.getHandle())) {
- mSensorService.onProximityActiveLocked(true);
- }
-}
-
// ---------------------------------------------------------------------------
}; // namespace android
diff --git a/services/sensorservice/SensorInterface.h b/services/sensorservice/SensorInterface.h
index 4e9f7bf9c8..57043592c5 100644
--- a/services/sensorservice/SensorInterface.h
+++ b/services/sensorservice/SensorInterface.h
@@ -44,9 +44,6 @@ public:
virtual const Sensor& getSensor() const = 0;
virtual bool isVirtual() const = 0;
virtual void autoDisable(void* /*ident*/, int /*handle*/) = 0;
-
- virtual void willDisableAllSensors() = 0;
- virtual void didEnableAllSensors() = 0;
};
class BaseSensor : public SensorInterface {
@@ -70,8 +67,6 @@ public:
virtual const Sensor& getSensor() const override { return mSensor; }
virtual void autoDisable(void* /*ident*/, int /*handle*/) override { }
- virtual void willDisableAllSensors() override { }
- virtual void didEnableAllSensors() override { }
protected:
SensorDevice& mSensorDevice;
Sensor mSensor;
@@ -115,8 +110,6 @@ public:
status_t activate(void* ident, bool enabled) override;
- void willDisableAllSensors() override;
- void didEnableAllSensors() override;
private:
SensorService& mSensorService;
};
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index 726fe8ea84..bdbae7b1ec 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -103,7 +103,7 @@ static const String16 sManageSensorsPermission("android.permission.MANAGE_SENSOR
SensorService::SensorService()
: mInitCheck(NO_INIT), mSocketBufferSize(SOCKET_BUFFER_SIZE_NON_BATCHED),
- mWakeLockAcquired(false), mProximityActiveCount(0) {
+ mWakeLockAcquired(false), mLastReportedProxIsActive(false) {
mUidPolicy = new UidPolicy(this);
mSensorPrivacyPolicy = new SensorPrivacyPolicy(this);
}
@@ -204,9 +204,11 @@ void SensorService::onFirstRef() {
}
if (useThisSensor) {
if (list[i].type == SENSOR_TYPE_PROXIMITY) {
- registerSensor(new ProximitySensor(list[i], *this));
+ SensorInterface* s = new ProximitySensor(list[i], *this);
+ registerSensor(s);
+ mProxSensorHandles.push_back(s->getSensor().getHandle());
} else {
- registerSensor( new HardwareSensor(list[i]) );
+ registerSensor(new HardwareSensor(list[i]));
}
}
}
@@ -331,6 +333,7 @@ void SensorService::onUidStateChanged(uid_t uid, UidState state) {
conn->onSensorAccessChanged(hasAccess);
}
}
+ checkAndReportProxStateChangeLocked();
}
bool SensorService::hasSensorAccess(uid_t uid, const String16& opPackageName) {
@@ -680,11 +683,8 @@ void SensorService::disableAllSensorsLocked(ConnectionSafeAutolock* connLock) {
bool hasAccess = hasSensorAccessLocked(conn->getUid(), conn->getOpPackageName());
conn->onSensorAccessChanged(hasAccess);
}
- mSensors.forEachEntry([](const SensorServiceUtil::SensorList::Entry& e) {
- e.si->willDisableAllSensors();
- return true;
- });
dev.disableAllSensors();
+ checkAndReportProxStateChangeLocked();
// Clear all pending flush connections for all active sensors. If one of the active
// connections has called flush() and the underlying sensor has been disabled before a
// flush complete event is returned, we need to remove the connection from this queue.
@@ -709,14 +709,11 @@ void SensorService::enableAllSensorsLocked(ConnectionSafeAutolock* connLock) {
}
SensorDevice& dev(SensorDevice::getInstance());
dev.enableAllSensors();
- mSensors.forEachEntry([](const SensorServiceUtil::SensorList::Entry& e) {
- e.si->didEnableAllSensors();
- return true;
- });
for (const sp<SensorDirectConnection>& conn : connLock->getDirectConnections()) {
bool hasAccess = hasSensorAccessLocked(conn->getUid(), conn->getOpPackageName());
conn->onSensorAccessChanged(hasAccess);
}
+ checkAndReportProxStateChangeLocked();
}
void SensorService::capRates(userid_t userId) {
@@ -1538,10 +1535,7 @@ status_t SensorService::resetToNormalModeLocked() {
if (err == NO_ERROR) {
mCurrentOperatingMode = NORMAL;
dev.enableAllSensors();
- mSensors.forEachEntry([](const SensorServiceUtil::SensorList::Entry& e) {
- e.si->didEnableAllSensors();
- return true;
- });
+ checkAndReportProxStateChangeLocked();
}
return err;
}
@@ -1606,28 +1600,26 @@ void SensorService::cleanupConnection(SensorDirectConnection* c) {
mConnectionHolder.removeDirectConnection(c);
}
-void SensorService::onProximityActiveLocked(bool isActive) {
- int prevCount = mProximityActiveCount;
- bool activeStateChanged = false;
- if (isActive) {
- mProximityActiveCount++;
- activeStateChanged = prevCount == 0;
- } else {
- mProximityActiveCount--;
- if (mProximityActiveCount < 0) {
- ALOGE("Proximity active count is negative (%d)!", mProximityActiveCount);
+void SensorService::checkAndReportProxStateChangeLocked() {
+ if (mProxSensorHandles.empty()) return;
+
+ SensorDevice& dev(SensorDevice::getInstance());
+ bool isActive = false;
+ for (auto& sensor : mProxSensorHandles) {
+ if (dev.isSensorActive(sensor)) {
+ isActive = true;
+ break;
}
- activeStateChanged = prevCount > 0 && mProximityActiveCount <= 0;
}
-
- if (activeStateChanged) {
- notifyProximityStateLocked(mProximityActiveListeners);
+ if (isActive != mLastReportedProxIsActive) {
+ notifyProximityStateLocked(isActive, mProximityActiveListeners);
+ mLastReportedProxIsActive = isActive;
}
}
void SensorService::notifyProximityStateLocked(
+ const bool isActive,
const std::vector<sp<ProximityActiveListener>>& listeners) {
- const bool isActive = mProximityActiveCount > 0;
const uint64_t mySeq = ++curProxCallbackSeq;
std::thread t([isActive, mySeq, listenersCopy = listeners]() {
while (completedCallbackSeq.load() != mySeq - 1)
@@ -1655,7 +1647,7 @@ status_t SensorService::addProximityActiveListener(const sp<ProximityActiveListe
mProximityActiveListeners.push_back(callback);
std::vector<sp<ProximityActiveListener>> listener(1, callback);
- notifyProximityStateLocked(listener);
+ notifyProximityStateLocked(mLastReportedProxIsActive, listener);
return OK;
}
diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h
index def661177c..b059e61130 100644
--- a/services/sensorservice/SensorService.h
+++ b/services/sensorservice/SensorService.h
@@ -103,8 +103,9 @@ public:
void cleanupConnection(SensorDirectConnection* c);
// Call with mLock held.
- void onProximityActiveLocked(bool isActive);
- void notifyProximityStateLocked(const std::vector<sp<ProximityActiveListener>>& listeners);
+ void checkAndReportProxStateChangeLocked();
+ void notifyProximityStateLocked(const bool isActive,
+ const std::vector<sp<ProximityActiveListener>>& listeners);
status_t enable(const sp<SensorEventConnection>& connection, int handle,
nsecs_t samplingPeriodNs, nsecs_t maxBatchReportLatencyNs, int reservedFlags,
@@ -496,8 +497,11 @@ private:
// Checks if the mic sensor privacy is enabled for the uid
bool isMicSensorPrivacyEnabledForUid(uid_t uid);
- // Counts how many proximity sensors are currently active.
- int mProximityActiveCount;
+ // Keeps track of the handles of all proximity sensors in the system.
+ std::vector<int32_t> mProxSensorHandles;
+ // The last proximity sensor active state reported to listeners.
+ bool mLastReportedProxIsActive;
+ // Listeners subscribed to receive updates on the proximity sensor active state.
std::vector<sp<ProximityActiveListener>> mProximityActiveListeners;
};
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index 40b1fd08ce..9e69283244 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -155,6 +155,7 @@ filegroup {
"FrameTracer/FrameTracer.cpp",
"FrameTracker.cpp",
"HdrLayerInfoReporter.cpp",
+ "WindowInfosListenerInvoker.cpp",
"Layer.cpp",
"LayerProtoHelper.cpp",
"LayerRejecter.cpp",
@@ -209,7 +210,6 @@ cc_defaults {
"libcutils",
"libdisplayservicehidl",
"libhidlbase",
- "libinput",
"liblayers_proto",
"liblog",
"libprocessgroup",
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index f2a69940af..636555e685 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -58,6 +58,8 @@
namespace android {
+using gui::WindowInfo;
+
static constexpr float defaultMaxLuminance = 1000.0;
BufferLayer::BufferLayer(const LayerCreationArgs& args)
@@ -419,33 +421,35 @@ bool BufferLayer::onPostComposition(const DisplayDevice* display,
mFrameTracker.setFrameReadyTime(desiredPresentTime);
}
- const Fps refreshRate = mFlinger->mRefreshRateConfigs->getCurrentRefreshRate().getFps();
- const std::optional<Fps> renderRate = mFlinger->mScheduler->getFrameRateOverride(getOwnerUid());
- if (presentFence->isValid()) {
- mFlinger->mTimeStats->setPresentFence(layerId, mCurrentFrameNumber, presentFence,
- refreshRate, renderRate,
- frameRateToSetFrameRateVotePayload(
- mDrawingState.frameRate),
- getGameMode());
- mFlinger->mFrameTracer->traceFence(layerId, getCurrentBufferId(), mCurrentFrameNumber,
- presentFence, FrameTracer::FrameEvent::PRESENT_FENCE);
- mFrameTracker.setActualPresentFence(std::shared_ptr<FenceTime>(presentFence));
- } else if (!display) {
- // Do nothing.
- } else if (const auto displayId = PhysicalDisplayId::tryCast(display->getId());
- displayId && mFlinger->getHwComposer().isConnected(*displayId)) {
- // The HWC doesn't support present fences, so use the refresh
- // timestamp instead.
- const nsecs_t actualPresentTime = display->getRefreshTimestamp();
- mFlinger->mTimeStats->setPresentTime(layerId, mCurrentFrameNumber, actualPresentTime,
- refreshRate, renderRate,
- frameRateToSetFrameRateVotePayload(
- mDrawingState.frameRate),
- getGameMode());
- mFlinger->mFrameTracer->traceTimestamp(layerId, getCurrentBufferId(), mCurrentFrameNumber,
- actualPresentTime,
+ if (display) {
+ const Fps refreshRate = display->refreshRateConfigs().getCurrentRefreshRate().getFps();
+ const std::optional<Fps> renderRate =
+ mFlinger->mScheduler->getFrameRateOverride(getOwnerUid());
+ if (presentFence->isValid()) {
+ mFlinger->mTimeStats->setPresentFence(layerId, mCurrentFrameNumber, presentFence,
+ refreshRate, renderRate,
+ frameRateToSetFrameRateVotePayload(
+ mDrawingState.frameRate),
+ getGameMode());
+ mFlinger->mFrameTracer->traceFence(layerId, getCurrentBufferId(), mCurrentFrameNumber,
+ presentFence,
FrameTracer::FrameEvent::PRESENT_FENCE);
- mFrameTracker.setActualPresentTime(actualPresentTime);
+ mFrameTracker.setActualPresentFence(std::shared_ptr<FenceTime>(presentFence));
+ } else if (const auto displayId = PhysicalDisplayId::tryCast(display->getId());
+ displayId && mFlinger->getHwComposer().isConnected(*displayId)) {
+ // The HWC doesn't support present fences, so use the refresh
+ // timestamp instead.
+ const nsecs_t actualPresentTime = display->getRefreshTimestamp();
+ mFlinger->mTimeStats->setPresentTime(layerId, mCurrentFrameNumber, actualPresentTime,
+ refreshRate, renderRate,
+ frameRateToSetFrameRateVotePayload(
+ mDrawingState.frameRate),
+ getGameMode());
+ mFlinger->mFrameTracer->traceTimestamp(layerId, getCurrentBufferId(),
+ mCurrentFrameNumber, actualPresentTime,
+ FrameTracer::FrameEvent::PRESENT_FENCE);
+ mFrameTracker.setActualPresentTime(actualPresentTime);
+ }
}
mFrameTracker.advanceFrame();
@@ -825,9 +829,9 @@ void BufferLayer::updateCloneBufferInfo() {
wp<Layer> tmpZOrderRelativeOf = mDrawingState.zOrderRelativeOf;
SortedVector<wp<Layer>> tmpZOrderRelatives = mDrawingState.zOrderRelatives;
wp<Layer> tmpTouchableRegionCrop = mDrawingState.touchableRegionCrop;
- InputWindowInfo tmpInputInfo = mDrawingState.inputInfo;
+ WindowInfo tmpInputInfo = mDrawingState.inputInfo;
- mDrawingState = clonedFrom->mDrawingState;
+ cloneDrawingState(clonedFrom.get());
mDrawingState.touchableRegionCrop = tmpTouchableRegionCrop;
mDrawingState.zOrderRelativeOf = tmpZOrderRelativeOf;
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index 6b6d43425d..99e470dfe6 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -515,13 +515,10 @@ void BufferQueueLayer::onFirstRef() {
}
status_t BufferQueueLayer::setDefaultBufferProperties(uint32_t w, uint32_t h, PixelFormat format) {
- uint32_t const maxSurfaceDims =
- std::min(mFlinger->getMaxTextureSize(), mFlinger->getMaxViewportDims());
-
// never allow a surface larger than what our underlying GL implementation
// can handle.
- if ((uint32_t(w) > maxSurfaceDims) || (uint32_t(h) > maxSurfaceDims)) {
- ALOGE("dimensions too large %u x %u", uint32_t(w), uint32_t(h));
+ if (mFlinger->exceedsMaxRenderTargetSize(w, h)) {
+ ALOGE("dimensions too large %" PRIu32 " x %" PRIu32, w, h);
return BAD_VALUE;
}
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 8bc51dfa5d..df91904ac8 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -66,7 +66,7 @@ BufferStateLayer::~BufferStateLayer() {
// one of the layers, in this case the original layer, needs to handle the deletion. The
// 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()) {
+ if (mBufferInfo.mBuffer != nullptr) {
callReleaseBufferCallback(mDrawingState.releaseBufferListener,
mBufferInfo.mBuffer->getBuffer(), mBufferInfo.mFrameNumber,
mBufferInfo.mFence, mTransformHint,
@@ -158,7 +158,8 @@ void BufferStateLayer::onLayerDisplayed(const sp<Fence>& releaseFence) {
// transaction doesn't need a previous release fence.
sp<CallbackHandle> ch;
for (auto& handle : mDrawingState.callbackHandles) {
- if (handle->releasePreviousBuffer) {
+ if (handle->releasePreviousBuffer &&
+ mDrawingState.releaseBufferEndpoint == handle->listener) {
ch = handle;
break;
}
@@ -199,14 +200,9 @@ void BufferStateLayer::releasePendingBuffer(nsecs_t dequeueReadyTime) {
mFlinger->getMaxAcquiredBufferCountForCurrentRefreshRate(mOwnerUid);
}
- // If there are multiple transactions in this frame, set the previous id on the earliest
- // transacton. We don't need to pass in the released buffer id to multiple transactions.
- // The buffer id does not have to correspond to any particular transaction as long as the
- // listening end point is the same but the client expects the first transaction callback that
- // replaces the presented buffer to contain the release fence. This follows the same logic.
- // see BufferStateLayer::onLayerDisplayed.
for (auto& handle : mDrawingState.callbackHandles) {
- if (handle->releasePreviousBuffer) {
+ if (handle->releasePreviousBuffer &&
+ mDrawingState.releaseBufferEndpoint == handle->listener) {
handle->previousReleaseCallbackId = mPreviousReleaseCallbackId;
break;
}
@@ -420,7 +416,8 @@ bool BufferStateLayer::setBuffer(const std::shared_ptr<renderengine::ExternalTex
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) {
+ const sp<ITransactionCompletedListener>& releaseBufferListener,
+ const sp<IBinder>& releaseBufferEndpoint) {
ATRACE_CALL();
if (mDrawingState.buffer) {
@@ -485,6 +482,7 @@ bool BufferStateLayer::setBuffer(const std::shared_ptr<renderengine::ExternalTex
mDrawingState.width = mDrawingState.buffer->getBuffer()->getWidth();
mDrawingState.height = mDrawingState.buffer->getBuffer()->getHeight();
+ mDrawingState.releaseBufferEndpoint = releaseBufferEndpoint;
return true;
}
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index cab48994b3..0a0527c1a9 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -59,7 +59,8 @@ public:
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;
+ const sp<ITransactionCompletedListener>& transactionListener,
+ const sp<IBinder>& releaseBufferEndpoint) override;
bool setAcquireFence(const sp<Fence>& fence) override;
bool setDataspace(ui::Dataspace dataspace) override;
bool setHdrMetadata(const HdrMetadata& hdrMetadata) override;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
index 1416b1e3c0..0ef0b995c3 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
@@ -166,6 +166,9 @@ public:
// Enables (or disables) layer caching on this output
virtual void setLayerCachingEnabled(bool) = 0;
+ // Enables (or disables) layer caching texture pool on this output
+ virtual void setLayerCachingTexturePoolEnabled(bool) = 0;
+
// Sets the projection state to use
virtual void setProjection(ui::Rotation orientation, const Rect& layerStackSpaceRect,
const Rect& orientedDisplaySpaceRect) = 0;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
index f832084f39..ddcc907a91 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
@@ -41,6 +41,7 @@ public:
std::optional<DisplayId> getDisplayId() const override;
void setCompositionEnabled(bool) override;
void setLayerCachingEnabled(bool) override;
+ void setLayerCachingTexturePoolEnabled(bool) override;
void setProjection(ui::Rotation orientation, const Rect& layerStackSpaceRect,
const Rect& orientedDisplaySpaceRect) override;
void setDisplaySize(const ui::Size&) override;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h
index 7534548d4a..a040fa93de 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h
@@ -38,35 +38,56 @@ class Predictor;
class Flattener {
public:
- struct CachedSetRenderSchedulingTunables {
- // This default assumes that rendering a cached set takes about 3ms. That time is then cut
- // in half - the next frame using the cached set would have the same workload, meaning that
- // composition cost is the same. This is best illustrated with the following example:
- //
- // Suppose we're at a 120hz cadence so SurfaceFlinger is budgeted 8.3ms per-frame. If
- // renderCachedSets costs 3ms, then two consecutive frames have timings:
- //
- // First frame: Start at 0ms, end at 6.8ms.
- // renderCachedSets: Start at 6.8ms, end at 9.8ms.
- // Second frame: Start at 9.8ms, end at 16.6ms.
- //
- // Now the second frame won't render a cached set afterwards, but the first frame didn't
- // really steal time from the second frame.
- static const constexpr std::chrono::nanoseconds kDefaultCachedSetRenderDuration = 1500us;
-
- static const constexpr size_t kDefaultMaxDeferRenderAttempts = 240;
-
- // Duration allocated for rendering a cached set. If we don't have enough time for rendering
- // a cached set, then rendering is deferred to another frame.
- const std::chrono::nanoseconds cachedSetRenderDuration;
- // Maximum of times that we defer rendering a cached set. If we defer rendering a cached set
- // too many times, then render it anyways so that future frames would benefit from the
- // flattened cached set.
- const size_t maxDeferRenderAttempts;
+ // Collection of tunables which are backed by sysprops
+ struct Tunables {
+ // Tunables that are specific to scheduling when a cached set should be rendered
+ struct RenderScheduling {
+ // This default assumes that rendering a cached set takes about 3ms. That time is then
+ // cut in half - the next frame using the cached set would have the same workload,
+ // meaning that composition cost is the same. This is best illustrated with the
+ // following example:
+ //
+ // Suppose we're at a 120hz cadence so SurfaceFlinger is budgeted 8.3ms per-frame. If
+ // renderCachedSets costs 3ms, then two consecutive frames have timings:
+ //
+ // First frame: Start at 0ms, end at 6.8ms.
+ // renderCachedSets: Start at 6.8ms, end at 9.8ms.
+ // Second frame: Start at 9.8ms, end at 16.6ms.
+ //
+ // Now the second frame won't render a cached set afterwards, but the first frame didn't
+ // really steal time from the second frame.
+ static const constexpr std::chrono::nanoseconds kDefaultCachedSetRenderDuration =
+ 1500us;
+
+ static const constexpr size_t kDefaultMaxDeferRenderAttempts = 240;
+
+ // Duration allocated for rendering a cached set. If we don't have enough time for
+ // rendering a cached set, then rendering is deferred to another frame.
+ const std::chrono::nanoseconds cachedSetRenderDuration;
+ // Maximum of times that we defer rendering a cached set. If we defer rendering a cached
+ // set too many times, then render it anyways so that future frames would benefit from
+ // the flattened cached set.
+ const size_t maxDeferRenderAttempts;
+ };
+
+ static const constexpr std::chrono::milliseconds kDefaultActiveLayerTimeout = 150ms;
+
+ static const constexpr bool kDefaultEnableHolePunch = true;
+
+ // Threshold for determing whether a layer is active. A layer whose properties, including
+ // the buffer, have not changed in at least this time is considered inactive and is
+ // therefore a candidate for flattening.
+ const std::chrono::milliseconds mActiveLayerTimeout;
+
+ // Toggles for scheduling when it's safe to render a cached set.
+ // See: RenderScheduling
+ const std::optional<RenderScheduling> mRenderScheduling;
+
+ // True if the hole punching feature should be enabled.
+ const bool mEnableHolePunch;
};
- Flattener(renderengine::RenderEngine& renderEngine, bool enableHolePunch = false,
- std::optional<CachedSetRenderSchedulingTunables> cachedSetRenderSchedulingTunables =
- std::nullopt);
+
+ Flattener(renderengine::RenderEngine& renderEngine, const Tunables& tunables);
void setDisplaySize(ui::Size size) {
mDisplaySize = size;
@@ -80,6 +101,8 @@ public:
void renderCachedSets(const OutputCompositionState& outputState,
std::optional<std::chrono::steady_clock::time_point> renderDeadline);
+ void setTexturePoolEnabled(bool enabled) { mTexturePool.setEnabled(enabled); }
+
void dump(std::string& result) const;
void dumpLayers(std::string& result) const;
@@ -175,8 +198,7 @@ private:
void buildCachedSets(std::chrono::steady_clock::time_point now);
renderengine::RenderEngine& mRenderEngine;
- const bool mEnableHolePunch;
- const std::optional<CachedSetRenderSchedulingTunables> mCachedSetRenderSchedulingTunables;
+ const Tunables mTunables;
TexturePool mTexturePool;
@@ -200,9 +222,6 @@ private:
size_t mCachedSetCreationCount = 0;
size_t mCachedSetCreationCost = 0;
std::unordered_map<size_t, size_t> mInvalidatedCachedSetAges;
- std::chrono::nanoseconds mActiveLayerTimeout = kActiveLayerTimeout;
-
- static constexpr auto kActiveLayerTimeout = std::chrono::nanoseconds(150ms);
};
} // namespace compositionengine::impl::planner
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h
index bce438fa13..523752719d 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h
@@ -21,7 +21,7 @@
#include <compositionengine/LayerFECompositionState.h>
#include <compositionengine/OutputLayer.h>
#include <compositionengine/impl/OutputLayerCompositionState.h>
-#include <input/Flags.h>
+#include <ftl/Flags.h>
#include <string>
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Planner.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Planner.h
index be34153d31..b7ebca60fd 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Planner.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Planner.h
@@ -39,6 +39,9 @@ namespace compositionengine::impl::planner {
// heuristically determining the composition strategy of the current layer stack,
// and flattens inactive layers into an override buffer so it can be used
// as a more efficient representation of parts of the layer stack.
+// Implicitly, layer caching must also be enabled for the Planner to have any effect
+// E.g., setprop debug.sf.enable_layer_caching 1, or
+// adb shell service call SurfaceFlinger 1040 i32 1 [i64 <display ID>]
class Planner {
public:
Planner(renderengine::RenderEngine& renderengine);
@@ -64,6 +67,8 @@ public:
void renderCachedSets(const OutputCompositionState& outputState,
std::optional<std::chrono::steady_clock::time_point> renderDeadline);
+ void setTexturePoolEnabled(bool enabled) { mFlattener.setTexturePoolEnabled(enabled); }
+
void dump(const Vector<String16>& args, std::string&);
private:
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/TexturePool.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/TexturePool.h
index fb53ee04cd..d607c75325 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/TexturePool.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/TexturePool.h
@@ -63,7 +63,8 @@ public:
sp<Fence> mFence;
};
- TexturePool(renderengine::RenderEngine& renderEngine) : mRenderEngine(renderEngine) {}
+ TexturePool(renderengine::RenderEngine& renderEngine)
+ : mRenderEngine(renderEngine), mEnabled(false) {}
virtual ~TexturePool() = default;
@@ -78,6 +79,12 @@ public:
// to the pool.
std::shared_ptr<AutoTexture> borrowTexture();
+ // Enables or disables the pool. When the pool is disabled, no buffers will
+ // be held by the pool. This is useful when the active display changes.
+ void setEnabled(bool enable);
+
+ void dump(std::string& out) const;
+
protected:
// Proteted visibility so that they can be used for testing
const static constexpr size_t kMinPoolSize = 3;
@@ -95,8 +102,10 @@ private:
// Returns a previously borrowed texture to the pool.
void returnTexture(std::shared_ptr<renderengine::ExternalTexture>&& texture,
const sp<Fence>& fence);
+ void allocatePool();
renderengine::RenderEngine& mRenderEngine;
ui::Size mSize;
+ bool mEnabled;
};
} // namespace android::compositionengine::impl::planner
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
index 8e777e3c9f..8fdf3ae887 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
@@ -37,6 +37,7 @@ public:
MOCK_METHOD1(setCompositionEnabled, void(bool));
MOCK_METHOD1(setLayerCachingEnabled, void(bool));
+ MOCK_METHOD1(setLayerCachingTexturePoolEnabled, void(bool));
MOCK_METHOD3(setProjection, void(ui::Rotation, const Rect&, const Rect&));
MOCK_METHOD1(setDisplaySize, void(const ui::Size&));
MOCK_METHOD2(setLayerStackFilter, void(uint32_t, bool));
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index cafcb40e80..95ae5e514e 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -146,6 +146,12 @@ void Output::setLayerCachingEnabled(bool enabled) {
}
}
+void Output::setLayerCachingTexturePoolEnabled(bool enabled) {
+ if (mPlanner) {
+ mPlanner->setTexturePoolEnabled(enabled);
+ }
+}
+
void Output::setProjection(ui::Rotation orientation, const Rect& layerStackSpaceRect,
const Rect& orientedDisplaySpaceRect) {
auto& outputState = editState();
@@ -783,6 +789,9 @@ compositionengine::OutputLayer* Output::findLayerRequestingBackgroundComposition
if (compState->sidebandStream != nullptr) {
return nullptr;
}
+ if (compState->isOpaque) {
+ continue;
+ }
if (compState->backgroundBlurRadius > 0 || compState->blurRegions.size() > 0) {
layerRequestingBgComposition = layer;
}
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
index f033279caa..ad5e93168d 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
@@ -60,19 +60,8 @@ bool isSameStack(const std::vector<const LayerState*>& incomingLayers,
} // namespace
-Flattener::Flattener(
- renderengine::RenderEngine& renderEngine, bool enableHolePunch,
- std::optional<CachedSetRenderSchedulingTunables> cachedSetRenderSchedulingTunables)
- : mRenderEngine(renderEngine),
- mEnableHolePunch(enableHolePunch),
- mCachedSetRenderSchedulingTunables(cachedSetRenderSchedulingTunables),
- mTexturePool(mRenderEngine) {
- const int timeoutInMs =
- base::GetIntProperty(std::string("debug.sf.layer_caching_active_layer_timeout_ms"), 0);
- if (timeoutInMs != 0) {
- mActiveLayerTimeout = std::chrono::milliseconds(timeoutInMs);
- }
-}
+Flattener::Flattener(renderengine::RenderEngine& renderEngine, const Tunables& tunables)
+ : mRenderEngine(renderEngine), mTunables(tunables), mTexturePool(mRenderEngine) {}
NonBufferHash Flattener::flattenLayers(const std::vector<const LayerState*>& layers,
NonBufferHash hash, time_point now) {
@@ -128,14 +117,14 @@ void Flattener::renderCachedSets(
// If we have a render deadline, and the flattener is configured to skip rendering if we don't
// have enough time, then we skip rendering the cached set if we think that we'll steal too much
// time from the next frame.
- if (renderDeadline && mCachedSetRenderSchedulingTunables) {
+ if (renderDeadline && mTunables.mRenderScheduling) {
if (const auto estimatedRenderFinish =
- now + mCachedSetRenderSchedulingTunables->cachedSetRenderDuration;
+ now + mTunables.mRenderScheduling->cachedSetRenderDuration;
estimatedRenderFinish > *renderDeadline) {
mNewCachedSet->incrementSkipCount();
if (mNewCachedSet->getSkipCount() <=
- mCachedSetRenderSchedulingTunables->maxDeferRenderAttempts) {
+ mTunables.mRenderScheduling->maxDeferRenderAttempts) {
ATRACE_FORMAT("DeadlinePassed: exceeded deadline by: %d us",
std::chrono::duration_cast<std::chrono::microseconds>(
estimatedRenderFinish - *renderDeadline)
@@ -205,6 +194,9 @@ void Flattener::dump(std::string& result) const {
durationString(lastUpdate).c_str());
dumpLayers(result);
+
+ base::StringAppendF(&result, "\n");
+ mTexturePool.dump(result);
}
size_t Flattener::calculateDisplayCost(const std::vector<const LayerState*>& layers) const {
@@ -417,8 +409,10 @@ std::vector<Flattener::Run> Flattener::findCandidateRuns(time_point now) const {
bool runHasFirstLayer = false;
for (auto currentSet = mLayers.cbegin(); currentSet != mLayers.cend(); ++currentSet) {
- const bool layerIsInactive = now - currentSet->getLastUpdate() > mActiveLayerTimeout;
+ const bool layerIsInactive =
+ now - currentSet->getLastUpdate() > mTunables.mActiveLayerTimeout;
const bool layerHasBlur = currentSet->hasBlurBehind();
+
if (layerIsInactive && (firstLayer || runHasFirstLayer || !layerHasBlur) &&
!currentSet->hasUnsupportedDataspace()) {
if (isPartOfRun) {
@@ -519,7 +513,7 @@ void Flattener::buildCachedSets(time_point now) {
mNewCachedSet->addBackgroundBlurLayer(*bestRun->getBlurringLayer());
}
- if (mEnableHolePunch && bestRun->getHolePunchCandidate() &&
+ if (mTunables.mEnableHolePunch && bestRun->getHolePunchCandidate() &&
bestRun->getHolePunchCandidate()->requiresHolePunch()) {
// Add the pip layer to mNewCachedSet, but in a special way - it should
// replace the buffer with a clear round rect.
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp b/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp
index f077470c80..f5b1cee469 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp
@@ -32,36 +32,46 @@ namespace android::compositionengine::impl::planner {
namespace {
-std::optional<Flattener::CachedSetRenderSchedulingTunables> buildFlattenerTuneables() {
+std::optional<Flattener::Tunables::RenderScheduling> buildRenderSchedulingTunables() {
if (!base::GetBoolProperty(std::string("debug.sf.enable_cached_set_render_scheduling"), true)) {
return std::nullopt;
}
- auto renderDuration = std::chrono::nanoseconds(
+ const auto renderDuration = std::chrono::nanoseconds(
base::GetUintProperty<uint64_t>(std::string("debug.sf.cached_set_render_duration_ns"),
- Flattener::CachedSetRenderSchedulingTunables::
+ Flattener::Tunables::RenderScheduling::
kDefaultCachedSetRenderDuration.count()));
- auto maxDeferRenderAttempts = base::GetUintProperty<
+ const auto maxDeferRenderAttempts = base::GetUintProperty<
size_t>(std::string("debug.sf.cached_set_max_defer_render_attmpts"),
- Flattener::CachedSetRenderSchedulingTunables::kDefaultMaxDeferRenderAttempts);
+ Flattener::Tunables::RenderScheduling::kDefaultMaxDeferRenderAttempts);
- return std::make_optional<Flattener::CachedSetRenderSchedulingTunables>(
- Flattener::CachedSetRenderSchedulingTunables{
+ return std::make_optional<Flattener::Tunables::RenderScheduling>(
+ Flattener::Tunables::RenderScheduling{
.cachedSetRenderDuration = renderDuration,
.maxDeferRenderAttempts = maxDeferRenderAttempts,
});
}
+Flattener::Tunables buildFlattenerTuneables() {
+ const auto activeLayerTimeout = std::chrono::milliseconds(
+ base::GetIntProperty<int32_t>(std::string(
+ "debug.sf.layer_caching_active_layer_timeout_ms"),
+ Flattener::Tunables::kDefaultActiveLayerTimeout.count()));
+ const auto enableHolePunch =
+ base::GetBoolProperty(std::string("debug.sf.enable_hole_punch_pip"),
+ Flattener::Tunables::kDefaultEnableHolePunch);
+ return Flattener::Tunables{
+ .mActiveLayerTimeout = activeLayerTimeout,
+ .mRenderScheduling = buildRenderSchedulingTunables(),
+ .mEnableHolePunch = enableHolePunch,
+ };
+}
+
} // namespace
Planner::Planner(renderengine::RenderEngine& renderEngine)
- // Implicitly, layer caching must also be enabled for the hole punch or
- // predictor to have any effect.
- // E.g., setprop debug.sf.enable_layer_caching 1, or
- // adb shell service call SurfaceFlinger 1040 i32 1 [i64 <display ID>]
: mFlattener(renderEngine,
- base::GetBoolProperty(std::string("debug.sf.enable_hole_punch_pip"), true),
buildFlattenerTuneables()) {
mPredictorEnabled =
base::GetBoolProperty(std::string("debug.sf.enable_planner_prediction"), false);
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/TexturePool.cpp b/services/surfaceflinger/CompositionEngine/src/planner/TexturePool.cpp
index e3772a22d2..497c433c76 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/TexturePool.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/TexturePool.cpp
@@ -24,14 +24,22 @@
namespace android::compositionengine::impl::planner {
+void TexturePool::allocatePool() {
+ mPool.clear();
+ if (mEnabled && mSize.isValid()) {
+ mPool.resize(kMinPoolSize);
+ std::generate_n(mPool.begin(), kMinPoolSize, [&]() {
+ return Entry{genTexture(), nullptr};
+ });
+ }
+}
+
void TexturePool::setDisplaySize(ui::Size size) {
if (mSize == size) {
return;
}
mSize = size;
- mPool.clear();
- mPool.resize(kMinPoolSize);
- std::generate_n(mPool.begin(), kMinPoolSize, [&]() { return Entry{genTexture(), nullptr}; });
+ allocatePool();
}
std::shared_ptr<TexturePool::AutoTexture> TexturePool::borrowTexture() {
@@ -46,7 +54,12 @@ std::shared_ptr<TexturePool::AutoTexture> TexturePool::borrowTexture() {
void TexturePool::returnTexture(std::shared_ptr<renderengine::ExternalTexture>&& texture,
const sp<Fence>& fence) {
- // Drop the texture on the floor if the pool is no longer tracking textures of the same size.
+ // Drop the texture on the floor if the pool is not enabled
+ if (!mEnabled) {
+ return;
+ }
+
+ // Or the texture on the floor if the pool is no longer tracking textures of the same size.
if (static_cast<int32_t>(texture->getBuffer()->getWidth()) != mSize.getWidth() ||
static_cast<int32_t>(texture->getBuffer()->getHeight()) != mSize.getHeight()) {
ALOGV("Deallocating texture from Planner's pool - display size changed (previous: (%dx%d), "
@@ -81,4 +94,15 @@ std::shared_ptr<renderengine::ExternalTexture> TexturePool::genTexture() {
renderengine::ExternalTexture::Usage::WRITEABLE);
}
+void TexturePool::setEnabled(bool enabled) {
+ mEnabled = enabled;
+ allocatePool();
+}
+
+void TexturePool::dump(std::string& out) const {
+ base::StringAppendF(&out,
+ "TexturePool (%s) has %zu buffers of size [%" PRId32 ", %" PRId32 "]\n",
+ mEnabled ? "enabled" : "disabled", mPool.size(), mSize.width, mSize.height);
+}
+
} // namespace android::compositionengine::impl::planner \ No newline at end of file
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
index a195e5808a..ada5adfa12 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
@@ -47,9 +47,7 @@ public:
MOCK_CONST_METHOD0(getMaxVirtualDisplayCount, size_t());
MOCK_CONST_METHOD0(getMaxVirtualDisplayDimension, size_t());
- MOCK_METHOD4(allocateVirtualDisplay,
- bool(HalVirtualDisplayId, ui::Size, ui::PixelFormat*,
- std::optional<PhysicalDisplayId>));
+ MOCK_METHOD3(allocateVirtualDisplay, bool(HalVirtualDisplayId, ui::Size, ui::PixelFormat*));
MOCK_METHOD2(allocatePhysicalDisplay, void(hal::HWDisplayId, PhysicalDisplayId));
MOCK_METHOD1(createLayer, std::shared_ptr<HWC2::Layer>(HalDisplayId));
MOCK_METHOD5(getDeviceCompositionChanges,
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index ee73cfc0c1..09f5a5e51d 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -3606,6 +3606,7 @@ struct OutputComposeSurfacesTest_SetsExpensiveRendering_ForBlur
: public OutputComposeSurfacesTest_SetsExpensiveRendering {
OutputComposeSurfacesTest_SetsExpensiveRendering_ForBlur() {
mLayer.layerFEState.backgroundBlurRadius = 10;
+ mLayer.layerFEState.isOpaque = false;
mOutput.editState().isEnabled = true;
EXPECT_CALL(mLayer.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0));
@@ -4225,6 +4226,37 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers,
kDisplayDataspace));
}
+TEST_F(OutputUpdateAndWriteCompositionStateTest, noBackgroundBlurWhenOpaque) {
+ InjectedLayer layer1;
+ InjectedLayer layer2;
+
+ uint32_t z = 0;
+ // Layer requesting blur, or below, should request client composition, unless opaque.
+ EXPECT_CALL(*layer1.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_0));
+ EXPECT_CALL(*layer1.outputLayer,
+ writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++,
+ /*zIsOverridden*/ false, /*isPeekingThrough*/ false));
+ EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_0));
+ EXPECT_CALL(*layer2.outputLayer,
+ writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++,
+ /*zIsOverridden*/ false, /*isPeekingThrough*/ false));
+
+ layer2.layerFEState.backgroundBlurRadius = 10;
+ layer2.layerFEState.isOpaque = true;
+
+ injectOutputLayer(layer1);
+ injectOutputLayer(layer2);
+
+ mOutput->editState().isEnabled = true;
+
+ CompositionRefreshArgs args;
+ args.updatingGeometryThisFrame = false;
+ args.devOptForceClientComposition = false;
+ mOutput->updateCompositionState(args);
+ mOutput->planComposition();
+ mOutput->writeCompositionState(args);
+}
+
TEST_F(OutputUpdateAndWriteCompositionStateTest, handlesBackgroundBlurRequests) {
InjectedLayer layer1;
InjectedLayer layer2;
@@ -4246,6 +4278,7 @@ TEST_F(OutputUpdateAndWriteCompositionStateTest, handlesBackgroundBlurRequests)
/*zIsOverridden*/ false, /*isPeekingThrough*/ false));
layer2.layerFEState.backgroundBlurRadius = 10;
+ layer2.layerFEState.isOpaque = false;
injectOutputLayer(layer1);
injectOutputLayer(layer2);
@@ -4283,6 +4316,7 @@ TEST_F(OutputUpdateAndWriteCompositionStateTest, handlesBlurRegionRequests) {
BlurRegion region;
layer2.layerFEState.blurRegions.push_back(region);
+ layer2.layerFEState.isOpaque = false;
injectOutputLayer(layer1);
injectOutputLayer(layer2);
diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp
index f5cfd2f115..a28fb2c652 100644
--- a/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp
@@ -47,23 +47,24 @@ namespace {
class TestableFlattener : public Flattener {
public:
- TestableFlattener(renderengine::RenderEngine& renderEngine, bool enableHolePunch,
- std::optional<Flattener::CachedSetRenderSchedulingTunables>
- cachedSetRenderSchedulingTunables = std::nullopt)
- : Flattener(renderEngine, enableHolePunch, cachedSetRenderSchedulingTunables) {}
+ TestableFlattener(renderengine::RenderEngine& renderEngine, const Tunables& tunables)
+ : Flattener(renderEngine, tunables) {}
const std::optional<CachedSet>& getNewCachedSetForTesting() const { return mNewCachedSet; }
};
class FlattenerTest : public testing::Test {
public:
- FlattenerTest() : FlattenerTest(std::nullopt) {}
+ FlattenerTest()
+ : FlattenerTest(Flattener::Tunables{
+ .mActiveLayerTimeout = 100ms,
+ .mRenderScheduling = std::nullopt,
+ .mEnableHolePunch = true,
+ }) {}
void SetUp() override;
protected:
- FlattenerTest(std::optional<Flattener::CachedSetRenderSchedulingTunables>
- cachedSetRenderSchedulingTunables)
- : mFlattener(std::make_unique<TestableFlattener>(mRenderEngine, true,
- cachedSetRenderSchedulingTunables)) {}
+ FlattenerTest(const Flattener::Tunables& tunables)
+ : mFlattener(std::make_unique<TestableFlattener>(mRenderEngine, tunables)) {}
void initializeOverrideBuffer(const std::vector<const LayerState*>& layers);
void initializeFlattener(const std::vector<const LayerState*>& layers);
void expectAllLayersFlattened(const std::vector<const LayerState*>& layers);
@@ -899,11 +900,13 @@ class FlattenerRenderSchedulingTest : public FlattenerTest {
public:
FlattenerRenderSchedulingTest()
: FlattenerTest(
- Flattener::CachedSetRenderSchedulingTunables{.cachedSetRenderDuration =
+ Flattener::Tunables{.mActiveLayerTimeout = 100ms,
+ .mRenderScheduling = Flattener::Tunables::
+ RenderScheduling{.cachedSetRenderDuration =
kCachedSetRenderDuration,
.maxDeferRenderAttempts =
- kMaxDeferRenderAttempts}) {
- }
+ kMaxDeferRenderAttempts},
+ .mEnableHolePunch = true}) {}
};
TEST_F(FlattenerRenderSchedulingTest, flattenLayers_renderCachedSets_defersUpToMaxAttempts) {
diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/TexturePoolTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/TexturePoolTest.cpp
index b802e51234..6fc90fe5e5 100644
--- a/services/surfaceflinger/CompositionEngine/tests/planner/TexturePoolTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/planner/TexturePoolTest.cpp
@@ -42,6 +42,7 @@ struct TexturePoolTest : public testing::Test {
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());
+ mTexturePool.setEnabled(true);
mTexturePool.setDisplaySize(kDisplaySize);
}
@@ -130,5 +131,44 @@ TEST_F(TexturePoolTest, reallocatesWhenDisplaySizeChanges) {
static_cast<int32_t>(texture->get()->getBuffer()->getHeight()));
}
+TEST_F(TexturePoolTest, freesBuffersWhenDisabled) {
+ EXPECT_EQ(mTexturePool.getPoolSize(), mTexturePool.getMinPoolSize());
+
+ std::deque<std::shared_ptr<TexturePool::AutoTexture>> textures;
+ for (size_t i = 0; i < mTexturePool.getMinPoolSize() - 1; i++) {
+ textures.emplace_back(mTexturePool.borrowTexture());
+ }
+
+ EXPECT_EQ(mTexturePool.getPoolSize(), 1u);
+ mTexturePool.setEnabled(false);
+ EXPECT_EQ(mTexturePool.getPoolSize(), 0u);
+
+ textures.clear();
+ EXPECT_EQ(mTexturePool.getPoolSize(), 0u);
+}
+
+TEST_F(TexturePoolTest, doesNotHoldBuffersWhenDisabled) {
+ EXPECT_EQ(mTexturePool.getPoolSize(), mTexturePool.getMinPoolSize());
+ mTexturePool.setEnabled(false);
+ EXPECT_EQ(mTexturePool.getPoolSize(), 0u);
+
+ std::deque<std::shared_ptr<TexturePool::AutoTexture>> textures;
+ for (size_t i = 0; i < mTexturePool.getMinPoolSize() - 1; i++) {
+ textures.emplace_back(mTexturePool.borrowTexture());
+ }
+
+ EXPECT_EQ(mTexturePool.getPoolSize(), 0u);
+ textures.clear();
+ EXPECT_EQ(mTexturePool.getPoolSize(), 0u);
+}
+
+TEST_F(TexturePoolTest, reallocatesWhenReEnabled) {
+ EXPECT_EQ(mTexturePool.getPoolSize(), mTexturePool.getMinPoolSize());
+ mTexturePool.setEnabled(false);
+ EXPECT_EQ(mTexturePool.getPoolSize(), 0u);
+ mTexturePool.setEnabled(true);
+ EXPECT_EQ(mTexturePool.getPoolSize(), mTexturePool.getMinPoolSize());
+}
+
} // namespace
} // namespace android::compositionengine::impl::planner
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index ca4b6abc03..4445eea604 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -22,6 +22,8 @@
#undef LOG_TAG
#define LOG_TAG "DisplayDevice"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
#include <android-base/stringprintf.h>
#include <compositionengine/CompositionEngine.h>
#include <compositionengine/Display.h>
@@ -40,6 +42,7 @@
#include "DisplayDevice.h"
#include "Layer.h"
+#include "RefreshRateOverlay.h"
#include "SurfaceFlinger.h"
namespace android {
@@ -65,9 +68,12 @@ DisplayDevice::DisplayDevice(DisplayDeviceCreationArgs& args)
mSequenceId(args.sequenceId),
mConnectionType(args.connectionType),
mCompositionDisplay{args.compositionDisplay},
+ mActiveModeFPSTrace("ActiveModeFPS -" + to_string(getId())),
+ mActiveModeFPSHwcTrace("ActiveModeFPS_HWC -" + to_string(getId())),
mPhysicalOrientation(args.physicalOrientation),
mSupportedModes(std::move(args.supportedModes)),
- mIsPrimary(args.isPrimary) {
+ mIsPrimary(args.isPrimary),
+ mRefreshRateConfigs(std::move(args.refreshRateConfigs)) {
mCompositionDisplay->editState().isSecure = args.isSecure;
mCompositionDisplay->createRenderSurface(
compositionengine::RenderSurfaceCreationArgsBuilder()
@@ -154,20 +160,29 @@ bool DisplayDevice::isPoweredOn() const {
void DisplayDevice::setActiveMode(DisplayModeId id) {
const auto mode = getMode(id);
LOG_FATAL_IF(!mode, "Cannot set active mode which is not supported.");
+ ATRACE_INT(mActiveModeFPSTrace.c_str(), mode->getFps().getIntValue());
mActiveMode = mode;
+ if (mRefreshRateConfigs) {
+ mRefreshRateConfigs->setCurrentModeId(mActiveMode->getId());
+ }
+ if (mRefreshRateOverlay) {
+ mRefreshRateOverlay->changeRefreshRate(mActiveMode->getFps());
+ }
}
-status_t DisplayDevice::initiateModeChange(DisplayModeId modeId,
+status_t DisplayDevice::initiateModeChange(const ActiveModeInfo& info,
const hal::VsyncPeriodChangeConstraints& constraints,
- hal::VsyncPeriodChangeTimeline* outTimeline) const {
- const auto mode = getMode(modeId);
- if (!mode) {
+ hal::VsyncPeriodChangeTimeline* outTimeline) {
+ if (!info.mode || info.mode->getPhysicalDisplayId() != getPhysicalId()) {
ALOGE("Trying to initiate a mode change to invalid mode %s on display %s",
- std::to_string(modeId.value()).c_str(), to_string(getId()).c_str());
+ info.mode ? std::to_string(info.mode->getId().value()).c_str() : "null",
+ to_string(getId()).c_str());
return BAD_VALUE;
}
- return mHwComposer.setActiveModeWithConstraints(getPhysicalId(), mode->getHwcId(), constraints,
- outTimeline);
+ mUpcomingActiveMode = info;
+ ATRACE_INT(mActiveModeFPSHwcTrace.c_str(), info.mode->getFps().getIntValue());
+ return mHwComposer.setActiveModeWithConstraints(getPhysicalId(), info.mode->getHwcId(),
+ constraints, outTimeline);
}
const DisplayModePtr& DisplayDevice::getActiveMode() const {
@@ -217,12 +232,23 @@ ui::Dataspace DisplayDevice::getCompositionDataSpace() const {
}
void DisplayDevice::setLayerStack(ui::LayerStack stack) {
- mCompositionDisplay->setLayerStackFilter(stack, isPrimary());
+ mCompositionDisplay->setLayerStackFilter(stack, isInternal());
+ if (mRefreshRateOverlay) {
+ mRefreshRateOverlay->setLayerStack(stack);
+ }
+}
+
+void DisplayDevice::setFlags(uint32_t flags) {
+ mFlags = flags;
}
void DisplayDevice::setDisplaySize(int width, int height) {
LOG_FATAL_IF(!isVirtual(), "Changing the display size is supported only for virtual displays.");
- mCompositionDisplay->setDisplaySize(ui::Size(width, height));
+ const auto size = ui::Size(width, height);
+ mCompositionDisplay->setDisplaySize(size);
+ if (mRefreshRateOverlay) {
+ mRefreshRateOverlay->setViewport(size);
+ }
}
void DisplayDevice::setProjection(ui::Rotation orientation, Rect layerStackSpaceRect,
@@ -262,7 +288,7 @@ ui::Transform::RotationFlags DisplayDevice::getPrimaryDisplayRotationFlags() {
std::string DisplayDevice::getDebugName() const {
const char* type = "virtual";
if (mConnectionType) {
- type = *mConnectionType == ui::DisplayConnectionType::Internal ? "internal" : "external";
+ type = isInternal() ? "internal" : "external";
}
return base::StringPrintf("DisplayDevice{%s, %s%s, \"%s\"}", to_string(getId()).c_str(), type,
@@ -292,6 +318,10 @@ void DisplayDevice::dump(std::string& result) const {
}
result.append("\n");
getCompositionDisplay()->dump(result);
+
+ if (mRefreshRateConfigs) {
+ mRefreshRateConfigs->dump(result);
+ }
}
bool DisplayDevice::hasRenderIntent(ui::RenderIntent intent) const {
@@ -378,6 +408,80 @@ HdrCapabilities DisplayDevice::getHdrCapabilities() const {
capabilities.getDesiredMinLuminance());
}
+void DisplayDevice::enableRefreshRateOverlay(bool enable, bool showSpinnner) {
+ if (!enable) {
+ mRefreshRateOverlay.reset();
+ return;
+ }
+
+ const auto [lowFps, highFps] = mRefreshRateConfigs->getSupportedRefreshRateRange();
+ mRefreshRateOverlay = std::make_unique<RefreshRateOverlay>(*mFlinger, lowFps.getIntValue(),
+ highFps.getIntValue(), showSpinnner);
+ mRefreshRateOverlay->setLayerStack(getLayerStack());
+ mRefreshRateOverlay->setViewport(getSize());
+ mRefreshRateOverlay->changeRefreshRate(getActiveMode()->getFps());
+}
+
+bool DisplayDevice::onKernelTimerChanged(std::optional<DisplayModeId> desiredModeId,
+ bool timerExpired) {
+ if (mRefreshRateConfigs && mRefreshRateOverlay) {
+ const auto newRefreshRate =
+ mRefreshRateConfigs->onKernelTimerChanged(desiredModeId, timerExpired);
+ if (newRefreshRate) {
+ mRefreshRateOverlay->changeRefreshRate(*newRefreshRate);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void DisplayDevice::onInvalidate() {
+ if (mRefreshRateOverlay) {
+ mRefreshRateOverlay->onInvalidate();
+ }
+}
+
+bool DisplayDevice::setDesiredActiveMode(const ActiveModeInfo& info) {
+ ATRACE_CALL();
+
+ LOG_ALWAYS_FATAL_IF(!info.mode, "desired mode not provided");
+ LOG_ALWAYS_FATAL_IF(getPhysicalId() != info.mode->getPhysicalDisplayId(), "DisplayId mismatch");
+
+ ALOGV("%s(%s)", __func__, to_string(*info.mode).c_str());
+
+ std::scoped_lock lock(mActiveModeLock);
+ if (mDesiredActiveModeChanged) {
+ // If a mode change is pending, just cache the latest request in mDesiredActiveMode
+ const Scheduler::ModeEvent prevConfig = mDesiredActiveMode.event;
+ mDesiredActiveMode = info;
+ mDesiredActiveMode.event = mDesiredActiveMode.event | prevConfig;
+ return false;
+ }
+
+ // Check if we are already at the desired mode
+ if (getActiveMode()->getId() == info.mode->getId()) {
+ return false;
+ }
+
+ // Initiate a mode change.
+ mDesiredActiveModeChanged = true;
+ mDesiredActiveMode = info;
+ return true;
+}
+
+std::optional<DisplayDevice::ActiveModeInfo> DisplayDevice::getDesiredActiveMode() const {
+ std::scoped_lock lock(mActiveModeLock);
+ if (mDesiredActiveModeChanged) return mDesiredActiveMode;
+ return std::nullopt;
+}
+
+void DisplayDevice::clearDesiredActiveModeState() {
+ std::scoped_lock lock(mActiveModeLock);
+ mDesiredActiveMode.event = Scheduler::ModeEvent::None;
+ mDesiredActiveModeChanged = false;
+}
+
std::atomic<int32_t> DisplayDeviceState::sNextSequenceId(1);
} // namespace android
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index 7e4d92308c..4d435c7e47 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -39,17 +39,24 @@
#include <utils/RefBase.h>
#include <utils/Timers.h>
+#include "MainThreadGuard.h"
+
#include "DisplayHardware/DisplayIdentification.h"
#include "DisplayHardware/DisplayMode.h"
#include "DisplayHardware/Hal.h"
#include "DisplayHardware/PowerAdvisor.h"
+#include "Scheduler/RefreshRateConfigs.h"
+
+#include "TracedOrdinal.h"
+
namespace android {
class Fence;
class HWComposer;
class IGraphicBufferProducer;
class Layer;
+class RefreshRateOverlay;
class SurfaceFlinger;
struct CompositionInfo;
@@ -64,6 +71,7 @@ class DisplayDevice : public RefBase {
public:
constexpr static float sDefaultMinLumiance = 0.0;
constexpr static float sDefaultMaxLumiance = 500.0;
+ enum { eReceivesInput = 0x01 };
explicit DisplayDevice(DisplayDeviceCreationArgs& args);
@@ -78,6 +86,9 @@ public:
bool isVirtual() const { return !mConnectionType; }
bool isPrimary() const { return mIsPrimary; }
+ bool isInternal() const {
+ return !isVirtual() && mConnectionType == ui::DisplayConnectionType::Internal;
+ }
// isSecure indicates whether this display can be trusted to display
// secure surfaces.
@@ -90,6 +101,7 @@ public:
void setLayerStack(ui::LayerStack);
void setDisplaySize(int width, int height);
void setProjection(ui::Rotation orientation, Rect viewport, Rect frame);
+ void setFlags(uint32_t flags);
ui::Rotation getPhysicalOrientation() const { return mPhysicalOrientation; }
ui::Rotation getOrientation() const { return mOrientation; }
@@ -102,6 +114,7 @@ public:
const Rect& getOrientedDisplaySpaceRect() const;
bool needsFiltering() const;
ui::LayerStack getLayerStack() const;
+ bool receivesInput() const { return mFlags & eReceivesInput; }
DisplayId getId() const;
@@ -172,10 +185,28 @@ public:
* Display mode management.
*/
const DisplayModePtr& getActiveMode() const;
- void setActiveMode(DisplayModeId);
- status_t initiateModeChange(DisplayModeId modeId,
+
+ struct ActiveModeInfo {
+ DisplayModePtr mode;
+ scheduler::RefreshRateConfigEvent event = scheduler::RefreshRateConfigEvent::None;
+
+ bool operator!=(const ActiveModeInfo& other) const {
+ return mode != other.mode || event != other.event;
+ }
+ };
+
+ bool setDesiredActiveMode(const ActiveModeInfo&) EXCLUDES(mActiveModeLock);
+ std::optional<ActiveModeInfo> getDesiredActiveMode() const EXCLUDES(mActiveModeLock);
+ void clearDesiredActiveModeState() EXCLUDES(mActiveModeLock);
+ ActiveModeInfo getUpcomingActiveMode() const REQUIRES(SF_MAIN_THREAD) {
+ return mUpcomingActiveMode;
+ }
+
+ void setActiveMode(DisplayModeId) REQUIRES(SF_MAIN_THREAD);
+ status_t initiateModeChange(const ActiveModeInfo&,
const hal::VsyncPeriodChangeConstraints& constraints,
- hal::VsyncPeriodChangeTimeline* outTimeline) const;
+ hal::VsyncPeriodChangeTimeline* outTimeline)
+ REQUIRES(SF_MAIN_THREAD);
// Return the immutable list of supported display modes. The HWC may report different modes
// after a hotplug reconnect event, in which case the DisplayDevice object will be recreated.
@@ -187,6 +218,22 @@ public:
// set-top boxes after a hotplug reconnect.
DisplayModePtr getMode(DisplayModeId) const;
+ // Returns the refresh rate configs for this display.
+ scheduler::RefreshRateConfigs& refreshRateConfigs() const { return *mRefreshRateConfigs; }
+
+ // Returns a shared pointer to the refresh rate configs for this display.
+ // Clients can store this refresh rate configs and use it even if the DisplayDevice
+ // is destroyed.
+ std::shared_ptr<scheduler::RefreshRateConfigs> holdRefreshRateConfigs() const {
+ return mRefreshRateConfigs;
+ }
+
+ // Enables an overlay to be displayed with the current refresh rate
+ void enableRefreshRateOverlay(bool enable, bool showSpinner);
+ bool isRefreshRateOverlayEnabled() const { return mRefreshRateOverlay != nullptr; }
+ bool onKernelTimerChanged(std::optional<DisplayModeId>, bool timerExpired);
+ void onInvalidate();
+
void onVsync(nsecs_t timestamp);
nsecs_t getVsyncPeriodFromHWC() const;
nsecs_t getRefreshTimestamp() const;
@@ -211,6 +258,8 @@ private:
const std::shared_ptr<compositionengine::Display> mCompositionDisplay;
std::string mDisplayName;
+ std::string mActiveModeFPSTrace;
+ std::string mActiveModeFPSHwcTrace;
const ui::Rotation mPhysicalOrientation;
ui::Rotation mOrientation = ui::ROTATION_0;
@@ -227,9 +276,20 @@ private:
// TODO(b/74619554): Remove special cases for primary display.
const bool mIsPrimary;
+ uint32_t mFlags = 0;
+
std::optional<DeviceProductInfo> mDeviceProductInfo;
std::vector<ui::Hdr> mOverrideHdrTypes;
+
+ std::shared_ptr<scheduler::RefreshRateConfigs> mRefreshRateConfigs;
+ std::unique_ptr<RefreshRateOverlay> mRefreshRateOverlay;
+
+ mutable std::mutex mActiveModeLock;
+ ActiveModeInfo mDesiredActiveMode GUARDED_BY(mActiveModeLock);
+ TracedOrdinal<bool> mDesiredActiveModeChanged
+ GUARDED_BY(mActiveModeLock) = {"DesiredActiveModeChanged", false};
+ ActiveModeInfo mUpcomingActiveMode GUARDED_BY(SF_MAIN_THREAD);
};
struct DisplayDeviceState {
@@ -252,6 +312,7 @@ struct DisplayDeviceState {
std::optional<Physical> physical;
sp<IGraphicBufferProducer> surface;
ui::LayerStack layerStack = ui::NO_LAYER_STACK;
+ uint32_t flags = 0;
Rect layerStackSpaceRect;
Rect orientedDisplaySpaceRect;
ui::Rotation orientation = ui::ROTATION_0;
@@ -274,6 +335,7 @@ struct DisplayDeviceCreationArgs {
HWComposer& hwComposer;
const wp<IBinder> displayToken;
const std::shared_ptr<compositionengine::Display> compositionDisplay;
+ std::shared_ptr<scheduler::RefreshRateConfigs> refreshRateConfigs;
int32_t sequenceId{0};
std::optional<ui::DisplayConnectionType> connectionType;
@@ -289,6 +351,7 @@ struct DisplayDeviceCreationArgs {
hardware::graphics::composer::hal::PowerMode::ON};
bool isPrimary{false};
DisplayModes supportedModes;
+ DisplayModeId activeModeId;
};
// Predicates for display lookup.
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
index caf0294a56..09734c275f 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
@@ -212,7 +212,7 @@ uint32_t Composer::getMaxVirtualDisplayCount()
}
Error Composer::createVirtualDisplay(uint32_t width, uint32_t height, PixelFormat* format,
- std::optional<Display>, Display* outDisplay) {
+ Display* outDisplay) {
const uint32_t bufferSlotCount = 1;
Error error = kDefaultError;
if (mClient_2_2) {
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h
index b525e63c66..fe114b9512 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h
@@ -96,7 +96,7 @@ public:
virtual uint32_t getMaxVirtualDisplayCount() = 0;
virtual Error createVirtualDisplay(uint32_t width, uint32_t height, PixelFormat*,
- std::optional<Display> mirror, Display* outDisplay) = 0;
+ Display* outDisplay) = 0;
virtual Error destroyVirtualDisplay(Display display) = 0;
virtual Error acceptDisplayChanges(Display display) = 0;
@@ -342,7 +342,7 @@ public:
uint32_t getMaxVirtualDisplayCount() override;
Error createVirtualDisplay(uint32_t width, uint32_t height, PixelFormat* format,
- std::optional<Display> mirror, Display* outDisplay) override;
+ Display* outDisplay) override;
Error destroyVirtualDisplay(Display display) override;
Error acceptDisplayChanges(Display display) override;
diff --git a/services/surfaceflinger/DisplayHardware/DisplayMode.h b/services/surfaceflinger/DisplayHardware/DisplayMode.h
index 85cc993c67..5de622b318 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayMode.h
+++ b/services/surfaceflinger/DisplayHardware/DisplayMode.h
@@ -22,6 +22,7 @@
#include <android-base/stringprintf.h>
#include <android/configuration.h>
+#include <ui/DisplayId.h>
#include <ui/DisplayMode.h>
#include <ui/Size.h>
#include <utils/Timers.h>
@@ -54,6 +55,11 @@ public:
return *this;
}
+ Builder& setPhysicalDisplayId(PhysicalDisplayId id) {
+ mDisplayMode->mPhysicalDisplayId = id;
+ return *this;
+ }
+
Builder& setWidth(int32_t width) {
mDisplayMode->mWidth = width;
return *this;
@@ -112,6 +118,7 @@ public:
DisplayModeId getId() const { return mId; }
hal::HWConfigId getHwcId() const { return mHwcId; }
+ PhysicalDisplayId getPhysicalDisplayId() const { return mPhysicalDisplayId; }
int32_t getWidth() const { return mWidth; }
int32_t getHeight() const { return mHeight; }
@@ -136,6 +143,7 @@ private:
hal::HWConfigId mHwcId;
DisplayModeId mId;
+ PhysicalDisplayId mPhysicalDisplayId;
int32_t mWidth = -1;
int32_t mHeight = -1;
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 7e45dabdea..a790b4c11e 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -245,8 +245,7 @@ size_t HWComposer::getMaxVirtualDisplayDimension() const {
}
bool HWComposer::allocateVirtualDisplay(HalVirtualDisplayId displayId, ui::Size resolution,
- ui::PixelFormat* format,
- std::optional<PhysicalDisplayId> mirror) {
+ ui::PixelFormat* format) {
if (!resolution.isValid()) {
ALOGE("%s: Invalid resolution %dx%d", __func__, resolution.width, resolution.height);
return false;
@@ -262,14 +261,9 @@ bool HWComposer::allocateVirtualDisplay(HalVirtualDisplayId displayId, ui::Size
return false;
}
- std::optional<hal::HWDisplayId> hwcMirrorId;
- if (mirror) {
- hwcMirrorId = fromPhysicalDisplayId(*mirror);
- }
-
hal::HWDisplayId hwcDisplayId;
const auto error = static_cast<hal::Error>(
- mComposer->createVirtualDisplay(width, height, format, hwcMirrorId, &hwcDisplayId));
+ mComposer->createVirtualDisplay(width, height, format, &hwcDisplayId));
RETURN_IF_HWC_ERROR_FOR("createVirtualDisplay", error, displayId, false);
auto display = std::make_unique<HWC2::impl::Display>(*mComposer.get(), mCapabilities,
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index b1849e8c11..49f96d9614 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -113,11 +113,7 @@ public:
// Attempts to allocate a virtual display on the HWC. The maximum number of virtual displays
// supported by the HWC can be queried in advance, but allocation may fail for other reasons.
- // For virtualized compositors, the PhysicalDisplayId is a hint that this virtual display is
- // a mirror of a physical display, and that the screen should be captured by the host rather
- // than guest compositor.
- virtual bool allocateVirtualDisplay(HalVirtualDisplayId, ui::Size, ui::PixelFormat*,
- std::optional<PhysicalDisplayId> mirror) = 0;
+ virtual bool allocateVirtualDisplay(HalVirtualDisplayId, ui::Size, ui::PixelFormat*) = 0;
virtual void allocatePhysicalDisplay(hal::HWDisplayId, PhysicalDisplayId) = 0;
@@ -265,8 +261,7 @@ public:
size_t getMaxVirtualDisplayCount() const override;
size_t getMaxVirtualDisplayDimension() const override;
- bool allocateVirtualDisplay(HalVirtualDisplayId, ui::Size, ui::PixelFormat*,
- std::optional<PhysicalDisplayId>) override;
+ bool allocateVirtualDisplay(HalVirtualDisplayId, ui::Size, ui::PixelFormat*) override;
// Called from SurfaceFlinger, when the state for a new physical display needs to be recreated.
void allocatePhysicalDisplay(hal::HWDisplayId, PhysicalDisplayId) override;
diff --git a/services/surfaceflinger/DisplayHardware/Hal.h b/services/surfaceflinger/DisplayHardware/Hal.h
index bb2888e0fb..02d065881b 100644
--- a/services/surfaceflinger/DisplayHardware/Hal.h
+++ b/services/surfaceflinger/DisplayHardware/Hal.h
@@ -166,4 +166,15 @@ inline std::string to_string(hardware::graphics::composer::hal::PowerMode mode)
}
}
+inline std::string to_string(hardware::graphics::composer::hal::Vsync vsync) {
+ switch (vsync) {
+ case hardware::graphics::composer::hal::Vsync::ENABLE:
+ return "Enable";
+ case hardware::graphics::composer::hal::Vsync::DISABLE:
+ return "Disable";
+ default:
+ return "Unknown";
+ }
+}
+
} // namespace android
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index d8cead5e50..da7ff71510 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -71,7 +71,6 @@
#include "SurfaceFlinger.h"
#include "TimeStats/TimeStats.h"
#include "TunnelModeEnabledReporter.h"
-#include "input/InputWindow.h"
#define DEBUG_RESIZE 0
@@ -83,6 +82,7 @@ constexpr int kDumpTableRowLength = 159;
using base::StringAppendF;
using namespace android::flag_operators;
using PresentState = frametimeline::SurfaceFrame::PresentState;
+using gui::WindowInfo;
std::atomic<int32_t> Layer::sSequence{1};
@@ -90,8 +90,8 @@ Layer::Layer(const LayerCreationArgs& args)
: mFlinger(args.flinger),
mName(args.name),
mClientRef(args.client),
- mWindowType(static_cast<InputWindowInfo::Type>(
- args.metadata.getInt32(METADATA_WINDOW_TYPE, 0))) {
+ mWindowType(
+ static_cast<WindowInfo::Type>(args.metadata.getInt32(METADATA_WINDOW_TYPE, 0))) {
uint32_t layerFlags = 0;
if (args.flags & ISurfaceComposerClient::eHidden) layerFlags |= layer_state_t::eLayerHidden;
if (args.flags & ISurfaceComposerClient::eOpaque) layerFlags |= layer_state_t::eLayerOpaque;
@@ -135,6 +135,7 @@ Layer::Layer(const LayerCreationArgs& args)
mDrawingState.postTime = -1;
mDrawingState.destinationFrame.makeInvalid();
mDrawingState.isTrustedOverlay = false;
+ mDrawingState.dropInputMode = gui::DropInputMode::NONE;
if (args.flags & ISurfaceComposerClient::eNoColorFill) {
// Set an invalid color so there is no color fill.
@@ -421,8 +422,6 @@ void Layer::prepareBasicGeometryCompositionState() {
compositionState->blendMode = static_cast<Hwc2::IComposerClient::BlendMode>(blendMode);
compositionState->alpha = alpha;
- compositionState->backgroundBlurRadius = drawingState.backgroundBlurRadius;
- compositionState->blurRegions = drawingState.blurRegions;
compositionState->stretchEffect = getStretchEffect();
}
@@ -498,6 +497,9 @@ void Layer::preparePerFrameCompositionState() {
compositionState->stretchEffect.hasEffect()) {
compositionState->forceClientComposition = true;
}
+ // If there are no visible region changes, we still need to update blur parameters.
+ compositionState->blurRegions = drawingState.blurRegions;
+ compositionState->backgroundBlurRadius = drawingState.backgroundBlurRadius;
}
void Layer::prepareCursorCompositionState() {
@@ -938,8 +940,11 @@ bool Layer::setCornerRadius(float cornerRadius) {
bool Layer::setBackgroundBlurRadius(int backgroundBlurRadius) {
if (mDrawingState.backgroundBlurRadius == backgroundBlurRadius) return false;
-
- mDrawingState.sequence++;
+ // If we start or stop drawing blur then the layer's visibility state may change so increment
+ // the magic sequence number.
+ if (mDrawingState.backgroundBlurRadius == 0 || backgroundBlurRadius == 0) {
+ mDrawingState.sequence++;
+ }
mDrawingState.backgroundBlurRadius = backgroundBlurRadius;
mDrawingState.modified = true;
setTransactionFlags(eTransactionNeeded);
@@ -972,6 +977,11 @@ bool Layer::setTransparentRegionHint(const Region& transparent) {
}
bool Layer::setBlurRegions(const std::vector<BlurRegion>& blurRegions) {
+ // If we start or stop drawing blur then the layer's visibility state may change so increment
+ // the magic sequence number.
+ if (mDrawingState.blurRegions.size() == 0 || blurRegions.size() == 0) {
+ mDrawingState.sequence++;
+ }
mDrawingState.blurRegions = blurRegions;
mDrawingState.modified = true;
setTransactionFlags(eTransactionNeeded);
@@ -1916,27 +1926,49 @@ const std::vector<BlurRegion> Layer::getBlurRegions() const {
}
Layer::RoundedCornerState Layer::getRoundedCornerState() const {
- const auto& p = mDrawingParent.promote();
- if (p != nullptr) {
- RoundedCornerState parentState = p->getRoundedCornerState();
- if (parentState.radius > 0) {
+ // Get parent settings
+ RoundedCornerState parentSettings;
+ const auto& parent = mDrawingParent.promote();
+ if (parent != nullptr) {
+ parentSettings = parent->getRoundedCornerState();
+ if (parentSettings.radius > 0) {
ui::Transform t = getActiveTransform(getDrawingState());
t = t.inverse();
- parentState.cropRect = t.transform(parentState.cropRect);
+ parentSettings.cropRect = t.transform(parentSettings.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.
auto scaleX = sqrtf(t[0][0] * t[0][0] + t[0][1] * t[0][1]);
auto scaleY = sqrtf(t[1][0] * t[1][0] + t[1][1] * t[1][1]);
- parentState.radius *= (scaleX + scaleY) / 2.0f;
- return parentState;
+ parentSettings.radius *= (scaleX + scaleY) / 2.0f;
}
}
+
+ // Get layer settings
+ Rect layerCropRect = getCroppedBufferSize(getDrawingState());
const float radius = getDrawingState().cornerRadius;
- return radius > 0 && getCroppedBufferSize(getDrawingState()).isValid()
- ? RoundedCornerState(getCroppedBufferSize(getDrawingState()).toFloatRect(), radius)
- : RoundedCornerState();
+ RoundedCornerState layerSettings(layerCropRect.toFloatRect(), radius);
+ const bool layerSettingsValid = layerSettings.radius > 0 && layerCropRect.isValid();
+
+ if (layerSettingsValid && parentSettings.radius > 0) {
+ // If the parent and the layer have rounded corner settings, use the parent settings if the
+ // parent crop is entirely inside the layer crop.
+ // This has limitations and cause rendering artifacts. See b/200300845 for correct fix.
+ if (parentSettings.cropRect.left > layerCropRect.left &&
+ parentSettings.cropRect.top > layerCropRect.top &&
+ parentSettings.cropRect.right < layerCropRect.right &&
+ parentSettings.cropRect.bottom < layerCropRect.bottom) {
+ return parentSettings;
+ } else {
+ return layerSettings;
+ }
+ } else if (layerSettingsValid) {
+ return layerSettings;
+ } else if (parentSettings.radius > 0) {
+ return parentSettings;
+ }
+ return {};
}
void Layer::prepareShadowClientComposition(LayerFE::LayerSettings& caster,
@@ -1982,7 +2014,7 @@ void Layer::commitChildList() {
}
-void Layer::setInputInfo(const InputWindowInfo& info) {
+void Layer::setInputInfo(const WindowInfo& info) {
mDrawingState.inputInfo = info;
mDrawingState.touchableRegionCrop = fromHandle(info.touchableRegionCropHandle.promote());
mDrawingState.modified = true;
@@ -2021,8 +2053,8 @@ void Layer::writeToProtoDrawingState(LayerProto* layerInfo, uint32_t traceFlags,
if (buffer != nullptr) {
LayerProtoHelper::writeToProto(buffer,
[&]() { return layerInfo->mutable_active_buffer(); });
- LayerProtoHelper::writeToProto(ui::Transform(getBufferTransform()),
- layerInfo->mutable_buffer_transform());
+ LayerProtoHelper::writeToProtoDeprecated(ui::Transform(getBufferTransform()),
+ layerInfo->mutable_buffer_transform());
}
layerInfo->set_invalidate(contentDirty);
layerInfo->set_is_protected(isProtected());
@@ -2032,10 +2064,11 @@ void Layer::writeToProtoDrawingState(LayerProto* layerInfo, uint32_t traceFlags,
layerInfo->set_curr_frame(mCurrentFrameNumber);
layerInfo->set_effective_scaling_mode(getEffectiveScalingMode());
+ layerInfo->set_requested_corner_radius(getDrawingState().cornerRadius);
layerInfo->set_corner_radius(getRoundedCornerState().radius);
layerInfo->set_background_blur_radius(getBackgroundBlurRadius());
layerInfo->set_is_trusted_overlay(isTrustedOverlay());
- LayerProtoHelper::writeToProto(transform, layerInfo->mutable_transform());
+ LayerProtoHelper::writeToProtoDeprecated(transform, layerInfo->mutable_transform());
LayerProtoHelper::writePositionToProto(transform.tx(), transform.ty(),
[&]() { return layerInfo->mutable_position(); });
LayerProtoHelper::writeToProto(mBounds, [&]() { return layerInfo->mutable_bounds(); });
@@ -2110,8 +2143,8 @@ void Layer::writeToProtoCommonState(LayerProto* layerInfo, LayerVector::StateSet
[&]() { return layerInfo->mutable_requested_color(); });
layerInfo->set_flags(state.flags);
- LayerProtoHelper::writeToProto(requestedTransform,
- layerInfo->mutable_requested_transform());
+ LayerProtoHelper::writeToProtoDeprecated(requestedTransform,
+ layerInfo->mutable_requested_transform());
auto parent = useDrawing ? mDrawingParent.promote() : mCurrentParent.promote();
if (parent != nullptr) {
@@ -2133,7 +2166,7 @@ void Layer::writeToProtoCommonState(LayerProto* layerInfo, LayerVector::StateSet
}
if (traceFlags & SurfaceTracing::TRACE_INPUT) {
- InputWindowInfo info;
+ WindowInfo info;
if (useDrawing) {
info = fillInputInfo({nullptr});
} else {
@@ -2164,7 +2197,7 @@ Rect Layer::getInputBounds() const {
return getCroppedBufferSize(getDrawingState());
}
-void Layer::fillInputFrameInfo(InputWindowInfo& info, const ui::Transform& toPhysicalDisplay) {
+void Layer::fillInputFrameInfo(WindowInfo& info, const ui::Transform& toNonRotatedDisplay) {
// Transform layer size to screen space and inset it by surface insets.
// If this is a portal window, set the touchableRegion to the layerBounds.
Rect layerBounds = info.portalToDisplayId == ADISPLAY_ID_NONE
@@ -2181,16 +2214,18 @@ void Layer::fillInputFrameInfo(InputWindowInfo& info, const ui::Transform& toPhy
info.frameRight = 0;
info.frameBottom = 0;
info.transform.reset();
+ info.touchableRegion = Region();
+ info.flags = WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::NOT_FOCUSABLE;
return;
}
ui::Transform layerToDisplay = getInputTransform();
- // Transform that takes window coordinates to unrotated display coordinates
- ui::Transform t = toPhysicalDisplay * layerToDisplay;
+ // Transform that takes window coordinates to non-rotated display coordinates
+ ui::Transform t = toNonRotatedDisplay * layerToDisplay;
int32_t xSurfaceInset = info.surfaceInset;
int32_t ySurfaceInset = info.surfaceInset;
- // Bring screenBounds into unrotated space
- Rect screenBounds = toPhysicalDisplay.transform(Rect{mScreenBounds});
+ // Bring screenBounds into non-rotated space
+ Rect screenBounds = toNonRotatedDisplay.transform(Rect{mScreenBounds});
const float xScale = t.getScaleX();
const float yScale = t.getScaleY();
@@ -2259,7 +2294,7 @@ void Layer::fillInputFrameInfo(InputWindowInfo& info, const ui::Transform& toPhy
info.touchableRegion = inputTransform.transform(info.touchableRegion);
}
-void Layer::fillTouchOcclusionMode(InputWindowInfo& info) {
+void Layer::fillTouchOcclusionMode(WindowInfo& info) {
sp<Layer> p = this;
while (p != nullptr && !p->hasInputInfo()) {
p = p->mDrawingParent.promote();
@@ -2269,32 +2304,115 @@ void Layer::fillTouchOcclusionMode(InputWindowInfo& info) {
}
}
-InputWindowInfo Layer::fillInputInfo(const sp<DisplayDevice>& display) {
+gui::DropInputMode Layer::getDropInputMode() const {
+ gui::DropInputMode mode = mDrawingState.dropInputMode;
+ if (mode == gui::DropInputMode::ALL) {
+ return mode;
+ }
+ sp<Layer> parent = mDrawingParent.promote();
+ if (parent) {
+ gui::DropInputMode parentMode = parent->getDropInputMode();
+ if (parentMode != gui::DropInputMode::NONE) {
+ return parentMode;
+ }
+ }
+ return mode;
+}
+
+void Layer::handleDropInputMode(gui::WindowInfo& info) const {
+ if (mDrawingState.inputInfo.inputFeatures.test(WindowInfo::Feature::NO_INPUT_CHANNEL)) {
+ return;
+ }
+
+ // Check if we need to drop input unconditionally
+ gui::DropInputMode dropInputMode = getDropInputMode();
+ if (dropInputMode == gui::DropInputMode::ALL) {
+ info.inputFeatures |= WindowInfo::Feature::DROP_INPUT;
+ ALOGV("Dropping input for %s as requested by policy.", getDebugName());
+ return;
+ }
+
+ // Check if we need to check if the window is obscured by parent
+ if (dropInputMode != gui::DropInputMode::OBSCURED) {
+ return;
+ }
+
+ // Check if the parent has set an alpha on the layer
+ sp<Layer> parent = mDrawingParent.promote();
+ if (parent && parent->getAlpha() != 1.0_hf) {
+ info.inputFeatures |= WindowInfo::Feature::DROP_INPUT;
+ ALOGV("Dropping input for %s as requested by policy because alpha=%f", getDebugName(),
+ static_cast<float>(getAlpha()));
+ }
+
+ // Check if the parent has cropped the buffer
+ Rect bufferSize = getCroppedBufferSize(getDrawingState());
+ if (!bufferSize.isValid()) {
+ info.inputFeatures |= WindowInfo::Feature::DROP_INPUT_IF_OBSCURED;
+ return;
+ }
+
+ // Screenbounds are the layer bounds cropped by parents, transformed to screenspace.
+ // To check if the layer has been cropped, we take the buffer bounds, apply the local
+ // layer crop and apply the same set of transforms to move to screenspace. If the bounds
+ // match then the layer has not been cropped by its parents.
+ Rect bufferInScreenSpace(getTransform().transform(bufferSize));
+ bool croppedByParent = bufferInScreenSpace != Rect{mScreenBounds};
+
+ if (croppedByParent) {
+ info.inputFeatures |= WindowInfo::Feature::DROP_INPUT;
+ ALOGV("Dropping input for %s as requested by policy because buffer is cropped by parent",
+ getDebugName());
+ } else {
+ // If the layer is not obscured by its parents (by setting an alpha or crop), then only drop
+ // input if the window is obscured. This check should be done in surfaceflinger but the
+ // logic currently resides in inputflinger. So pass the if_obscured check to input to only
+ // drop input events if the window is obscured.
+ info.inputFeatures |= WindowInfo::Feature::DROP_INPUT_IF_OBSCURED;
+ }
+}
+
+WindowInfo Layer::fillInputInfo(const sp<DisplayDevice>& display) {
if (!hasInputInfo()) {
mDrawingState.inputInfo.name = getName();
mDrawingState.inputInfo.ownerUid = mOwnerUid;
mDrawingState.inputInfo.ownerPid = mOwnerPid;
- mDrawingState.inputInfo.inputFeatures = InputWindowInfo::Feature::NO_INPUT_CHANNEL;
- mDrawingState.inputInfo.flags = InputWindowInfo::Flag::NOT_TOUCH_MODAL;
+ mDrawingState.inputInfo.inputFeatures = WindowInfo::Feature::NO_INPUT_CHANNEL;
+ mDrawingState.inputInfo.flags = WindowInfo::Flag::NOT_TOUCH_MODAL;
mDrawingState.inputInfo.displayId = getLayerStack();
}
- InputWindowInfo info = mDrawingState.inputInfo;
+ WindowInfo info = mDrawingState.inputInfo;
info.id = sequence;
+ info.displayId = getLayerStack();
- if (info.displayId == ADISPLAY_ID_NONE) {
- info.displayId = getLayerStack();
- }
-
- // Transform that goes from "logical(rotated)" display to physical/unrotated display.
- // This is for when inputflinger operates in physical display-space.
- ui::Transform toPhysicalDisplay;
+ // Transform that goes from "logical(rotated)" display to the non-rotated display.
+ ui::Transform toNonRotatedDisplay;
if (display) {
- toPhysicalDisplay = display->getTransform();
- info.displayWidth = display->getWidth();
- info.displayHeight = display->getHeight();
+ // The physical orientation is set when the orientation of the display panel is different
+ // than the default orientation of the device. We do not need to expose the physical
+ // orientation of the panel outside of SurfaceFlinger.
+ const ui::Rotation inversePhysicalOrientation =
+ ui::ROTATION_0 - display->getPhysicalOrientation();
+ auto width = display->getWidth();
+ auto height = display->getHeight();
+ if (inversePhysicalOrientation == ui::ROTATION_90 ||
+ inversePhysicalOrientation == ui::ROTATION_270) {
+ std::swap(width, height);
+ }
+ const auto rotationFlags = ui::Transform::toRotationFlags(inversePhysicalOrientation);
+ const ui::Transform undoPhysicalOrientation(rotationFlags, width, height);
+ toNonRotatedDisplay = undoPhysicalOrientation * display->getTransform();
+
+ // Send the inverse of the display orientation so that input can transform points back to
+ // the rotated display space.
+ const ui::Rotation inverseOrientation = ui::ROTATION_0 - display->getOrientation();
+ info.displayOrientation = ui::Transform::toRotationFlags(inverseOrientation);
+
+ info.displayWidth = width;
+ info.displayHeight = height;
}
- fillInputFrameInfo(info, toPhysicalDisplay);
+ fillInputFrameInfo(info, toNonRotatedDisplay);
// For compatibility reasons we let layers which can receive input
// receive input before they have actually submitted a buffer. Because
@@ -2307,18 +2425,19 @@ InputWindowInfo Layer::fillInputInfo(const sp<DisplayDevice>& display) {
info.visible = hasInputInfo() ? canReceiveInput() : isVisible();
info.alpha = getAlpha();
fillTouchOcclusionMode(info);
+ handleDropInputMode(info);
auto cropLayer = mDrawingState.touchableRegionCrop.promote();
if (info.replaceTouchableRegionWithCrop) {
if (cropLayer == nullptr) {
- info.touchableRegion = Region(toPhysicalDisplay.transform(Rect{mScreenBounds}));
+ info.touchableRegion = Region(toNonRotatedDisplay.transform(Rect{mScreenBounds}));
} else {
info.touchableRegion =
- Region(toPhysicalDisplay.transform(Rect{cropLayer->mScreenBounds}));
+ Region(toNonRotatedDisplay.transform(Rect{cropLayer->mScreenBounds}));
}
} else if (cropLayer != nullptr) {
info.touchableRegion = info.touchableRegion.intersect(
- toPhysicalDisplay.transform(Rect{cropLayer->mScreenBounds}));
+ toNonRotatedDisplay.transform(Rect{cropLayer->mScreenBounds}));
}
// Inherit the trusted state from the parent hierarchy, but don't clobber the trusted state
@@ -2331,7 +2450,7 @@ InputWindowInfo Layer::fillInputInfo(const sp<DisplayDevice>& display) {
if (isClone()) {
sp<Layer> clonedRoot = getClonedRoot();
if (clonedRoot != nullptr) {
- Rect rect = toPhysicalDisplay.transform(Rect{clonedRoot->mScreenBounds});
+ Rect rect = toNonRotatedDisplay.transform(Rect{clonedRoot->mScreenBounds});
info.touchableRegion = info.touchableRegion.intersect(rect);
}
}
@@ -2369,8 +2488,7 @@ Region Layer::getVisibleRegion(const DisplayDevice* display) const {
}
void Layer::setInitialValuesForClone(const sp<Layer>& clonedFrom) {
- // copy drawing state from cloned layer
- mDrawingState = clonedFrom->mDrawingState;
+ cloneDrawingState(clonedFrom.get());
mClonedFrom = clonedFrom;
}
@@ -2405,7 +2523,7 @@ void Layer::updateClonedDrawingState(std::map<sp<Layer>, sp<Layer>>& clonedLayer
// since we may be able to pull out other children that are still alive.
if (isClonedFromAlive()) {
sp<Layer> clonedFrom = getClonedFrom();
- mDrawingState = clonedFrom->mDrawingState;
+ cloneDrawingState(clonedFrom.get());
clonedLayersMap.emplace(clonedFrom, this);
}
@@ -2458,7 +2576,7 @@ void Layer::updateClonedInputInfo(const std::map<sp<Layer>, sp<Layer>>& clonedLa
}
// Cloned layers shouldn't handle watch outside since their z order is not determined by
// WM or the client.
- mDrawingState.inputInfo.flags &= ~InputWindowInfo::Flag::WATCH_OUTSIDE_TOUCH;
+ mDrawingState.inputInfo.flags &= ~WindowInfo::Flag::WATCH_OUTSIDE_TOUCH;
}
void Layer::updateClonedRelatives(const std::map<sp<Layer>, sp<Layer>>& clonedLayersMap) {
@@ -2560,6 +2678,21 @@ wp<Layer> Layer::fromHandle(const sp<IBinder>& handleBinder) {
return handle->owner;
}
+bool Layer::setDropInputMode(gui::DropInputMode mode) {
+ if (mDrawingState.dropInputMode == mode) {
+ return false;
+ }
+ mDrawingState.dropInputMode = mode;
+ return true;
+}
+
+void Layer::cloneDrawingState(const Layer* from) {
+ mDrawingState = from->mDrawingState;
+ // Skip callback info since they are not applicable for cloned layers.
+ mDrawingState.releaseBufferListener = nullptr;
+ mDrawingState.callbackHandles = {};
+}
+
// ---------------------------------------------------------------------------
std::ostream& operator<<(std::ostream& stream, const Layer::FrameRate& rate) {
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 8905548b64..c1af4685f0 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -17,11 +17,12 @@
#pragma once
+#include <android/gui/DropInputMode.h>
#include <compositionengine/LayerFE.h>
#include <gui/BufferQueue.h>
#include <gui/ISurfaceComposerClient.h>
#include <gui/LayerState.h>
-#include <input/InputWindow.h>
+#include <gui/WindowInfo.h>
#include <layerproto/LayerProtoHeader.h>
#include <math/vec4.h>
#include <renderengine/Mesh.h>
@@ -186,7 +187,7 @@ public:
float cornerRadius;
int backgroundBlurRadius;
- InputWindowInfo inputInfo;
+ gui::WindowInfo inputInfo;
wp<Layer> touchableRegionCrop;
// dataspace is only used by BufferStateLayer and EffectLayer
@@ -280,6 +281,10 @@ public:
Rect bufferCrop;
Rect destinationFrame;
+
+ sp<IBinder> releaseBufferEndpoint;
+
+ gui::DropInputMode dropInputMode;
};
/*
@@ -422,7 +427,8 @@ public:
const client_cache_t& /*clientCacheId*/, uint64_t /* frameNumber */,
std::optional<nsecs_t> /* dequeueTime */,
const FrameTimelineInfo& /*info*/,
- const sp<ITransactionCompletedListener>& /* releaseBufferListener */) {
+ const sp<ITransactionCompletedListener>& /* releaseBufferListener */,
+ const sp<IBinder>& /* releaseBufferEndpoint */) {
return false;
};
virtual bool setAcquireFence(const sp<Fence>& /*fence*/) { return false; };
@@ -444,6 +450,8 @@ public:
virtual bool setFrameRateSelectionPriority(int32_t priority);
virtual bool setFixedTransformHint(ui::Transform::RotationFlags fixedTransformHint);
virtual void setAutoRefresh(bool /* autoRefresh */) {}
+ bool setDropInputMode(gui::DropInputMode);
+
// If the variable is not set on the layer, it traverses up the tree to inherit the frame
// rate priority from its parent.
virtual int32_t getFrameRateSelectionPriority() const;
@@ -603,10 +611,8 @@ public:
virtual bool getTransformToDisplayInverse() const { return false; }
// Returns how rounded corners should be drawn for this layer.
- // This will traverse the hierarchy until it reaches its root, finding topmost rounded
- // corner definition and converting it into current layer's coordinates.
- // As of now, only 1 corner radius per display list is supported. Subsequent ones will be
- // ignored.
+ // A layer can override its parent's rounded corner settings if the parent's rounded
+ // corner crop does not intersect with its own rounded corner crop.
virtual RoundedCornerState getRoundedCornerState() const;
bool hasRoundedCorners() const override { return getRoundedCornerState().radius > .0f; }
@@ -695,7 +701,7 @@ public:
void writeToProtoCommonState(LayerProto* layerInfo, LayerVector::StateSet,
uint32_t traceFlags = SurfaceTracing::TRACE_ALL);
- InputWindowInfo::Type getWindowType() const { return mWindowType; }
+ gui::WindowInfo::Type getWindowType() const { return mWindowType; }
bool getPrimaryDisplayOnly() const;
@@ -846,9 +852,9 @@ public:
sp<IBinder> getHandle();
const std::string& getName() const { return mName; }
bool getPremultipledAlpha() const;
- void setInputInfo(const InputWindowInfo& info);
+ void setInputInfo(const gui::WindowInfo& info);
- InputWindowInfo fillInputInfo(const sp<DisplayDevice>& display);
+ gui::WindowInfo fillInputInfo(const sp<DisplayDevice>& display);
/**
* Returns whether this layer has an explicitly set input-info.
*/
@@ -923,6 +929,7 @@ protected:
bool isClone() { return mClonedFrom != nullptr; }
bool isClonedFromAlive() { return getClonedFrom() != nullptr; }
+ void cloneDrawingState(const Layer* from);
void updateClonedDrawingState(std::map<sp<Layer>, sp<Layer>>& clonedLayersMap);
void updateClonedChildren(const sp<Layer>& mirrorRoot,
std::map<sp<Layer>, sp<Layer>>& clonedLayersMap);
@@ -1013,7 +1020,7 @@ protected:
wp<Layer> mDrawingParent;
// Window types from WindowManager.LayoutParams
- const InputWindowInfo::Type mWindowType;
+ const gui::WindowInfo::Type mWindowType;
// The owner of the layer. If created from a non system process, it will be the calling uid.
// If created from a system process, the value can be passed in.
@@ -1056,6 +1063,8 @@ private:
bool setFrameRateForLayerTree(FrameRate);
void setZOrderRelativeOf(const wp<Layer>& relativeOf);
bool isTrustedOverlay() const;
+ gui::DropInputMode getDropInputMode() const;
+ void handleDropInputMode(gui::WindowInfo& info) const;
// 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.
@@ -1067,10 +1076,10 @@ private:
// Fills in the touch occlusion mode of the first parent (including this layer) that
// hasInputInfo() or no-op if no such parent is found.
- void fillTouchOcclusionMode(InputWindowInfo& info);
+ void fillTouchOcclusionMode(gui::WindowInfo& info);
- // Fills in the frame and transform info for the InputWindowInfo
- void fillInputFrameInfo(InputWindowInfo& info, const ui::Transform& toPhysicalDisplay);
+ // Fills in the frame and transform info for the gui::WindowInfo
+ void fillInputFrameInfo(gui::WindowInfo& info, const ui::Transform& toNonRotatedDisplay);
// Cached properties computed from drawing state
// Effective transform taking into account parent transforms and any parent scaling, which is
diff --git a/services/surfaceflinger/LayerProtoHelper.cpp b/services/surfaceflinger/LayerProtoHelper.cpp
index b1db6d34a3..1062126b58 100644
--- a/services/surfaceflinger/LayerProtoHelper.cpp
+++ b/services/surfaceflinger/LayerProtoHelper.cpp
@@ -22,6 +22,9 @@
#include "LayerProtoHelper.h"
namespace android {
+
+using gui::WindowInfo;
+
namespace surfaceflinger {
void LayerProtoHelper::writePositionToProto(const float x, const float y,
@@ -95,8 +98,8 @@ void LayerProtoHelper::writeToProto(const half4 color, std::function<ColorProto*
}
}
-void LayerProtoHelper::writeToProto(const ui::Transform& transform,
- TransformProto* transformProto) {
+void LayerProtoHelper::writeToProtoDeprecated(const ui::Transform& transform,
+ TransformProto* transformProto) {
const uint32_t type = transform.getType() | (transform.getOrientation() << 8);
transformProto->set_type(type);
@@ -111,6 +114,22 @@ void LayerProtoHelper::writeToProto(const ui::Transform& transform,
}
}
+void LayerProtoHelper::writeTransformToProto(const ui::Transform& transform,
+ TransformProto* transformProto) {
+ const uint32_t type = transform.getType() | (transform.getOrientation() << 8);
+ transformProto->set_type(type);
+
+ // Rotations that are 90/180/270 have their own type so the transform matrix can be
+ // reconstructed later. All other rotation have the type UNKNOWN so we need to save the
+ // transform values in that case.
+ if (type & (ui::Transform::SCALE | ui::Transform::UNKNOWN)) {
+ transformProto->set_dsdx(transform.dsdx());
+ transformProto->set_dtdx(transform.dtdx());
+ transformProto->set_dtdy(transform.dtdy());
+ transformProto->set_dsdy(transform.dsdy());
+ }
+}
+
void LayerProtoHelper::writeToProto(const sp<GraphicBuffer>& buffer,
std::function<ActiveBufferProto*()> getActiveBufferProto) {
if (buffer->getWidth() != 0 || buffer->getHeight() != 0 || buffer->getStride() != 0 ||
@@ -125,7 +144,7 @@ void LayerProtoHelper::writeToProto(const sp<GraphicBuffer>& buffer,
}
void LayerProtoHelper::writeToProto(
- const InputWindowInfo& inputInfo, const wp<Layer>& touchableRegionBounds,
+ const WindowInfo& inputInfo, const wp<Layer>& touchableRegionBounds,
std::function<InputWindowInfoProto*()> getInputWindowInfoProto) {
if (inputInfo.token == nullptr) {
return;
@@ -133,7 +152,7 @@ void LayerProtoHelper::writeToProto(
InputWindowInfoProto* proto = getInputWindowInfoProto();
proto->set_layout_params_flags(inputInfo.flags.get());
- using U = std::underlying_type_t<InputWindowInfo::Type>;
+ using U = std::underlying_type_t<WindowInfo::Type>;
// TODO(b/129481165): This static assert can be safely removed once conversion warnings
// are re-enabled.
static_assert(std::is_same_v<U, int32_t>);
@@ -151,7 +170,7 @@ void LayerProtoHelper::writeToProto(
proto->set_has_wallpaper(inputInfo.hasWallpaper);
proto->set_global_scale_factor(inputInfo.globalScaleFactor);
- LayerProtoHelper::writeToProto(inputInfo.transform, proto->mutable_transform());
+ LayerProtoHelper::writeToProtoDeprecated(inputInfo.transform, proto->mutable_transform());
proto->set_replace_touchable_region_with_crop(inputInfo.replaceTouchableRegionWithCrop);
auto cropLayer = touchableRegionBounds.promote();
if (cropLayer != nullptr) {
diff --git a/services/surfaceflinger/LayerProtoHelper.h b/services/surfaceflinger/LayerProtoHelper.h
index 502238d389..36e06471ee 100644
--- a/services/surfaceflinger/LayerProtoHelper.h
+++ b/services/surfaceflinger/LayerProtoHelper.h
@@ -17,7 +17,7 @@
#include <layerproto/LayerProtoHeader.h>
#include <Layer.h>
-#include <input/InputWindow.h>
+#include <gui/WindowInfo.h>
#include <math/vec4.h>
#include <ui/GraphicBuffer.h>
#include <ui/Rect.h>
@@ -37,10 +37,15 @@ public:
std::function<FloatRectProto*()> getFloatRectProto);
static void writeToProto(const Region& region, std::function<RegionProto*()> getRegionProto);
static void writeToProto(const half4 color, std::function<ColorProto*()> getColorProto);
- static void writeToProto(const ui::Transform& transform, TransformProto* transformProto);
+ // This writeToProto for transform is incorrect, but due to backwards compatibility, we can't
+ // update Layers to use it. Use writeTransformToProto for any new transform proto data.
+ static void writeToProtoDeprecated(const ui::Transform& transform,
+ TransformProto* transformProto);
+ static void writeTransformToProto(const ui::Transform& transform,
+ TransformProto* transformProto);
static void writeToProto(const sp<GraphicBuffer>& buffer,
std::function<ActiveBufferProto*()> getActiveBufferProto);
- static void writeToProto(const InputWindowInfo& inputInfo,
+ static void writeToProto(const gui::WindowInfo& inputInfo,
const wp<Layer>& touchableRegionBounds,
std::function<InputWindowInfoProto*()> getInputWindowInfoProto);
static void writeToProto(const mat4 matrix, ColorTransformProto* colorTransformProto);
diff --git a/services/surfaceflinger/LayerRenderArea.cpp b/services/surfaceflinger/LayerRenderArea.cpp
index e84508febc..11fe6d0755 100644
--- a/services/surfaceflinger/LayerRenderArea.cpp
+++ b/services/surfaceflinger/LayerRenderArea.cpp
@@ -94,8 +94,22 @@ void LayerRenderArea::render(std::function<void()> drawLayers) {
// no need to check rotation because there is none
mNeedsFiltering = sourceCrop.width() != getReqWidth() || sourceCrop.height() != getReqHeight();
+ // If layer is offscreen, update mirroring info if it exists
+ if (mLayer->isRemovedFromCurrentState()) {
+ mLayer->traverse(LayerVector::StateSet::Drawing,
+ [&](Layer* layer) { layer->updateMirrorInfo(); });
+ mLayer->traverse(LayerVector::StateSet::Drawing,
+ [&](Layer* layer) { layer->updateCloneBufferInfo(); });
+ }
+
if (!mChildrenOnly) {
mTransform = mLayer->getTransform().inverse();
+ // If the layer is offscreen, compute bounds since we don't compute bounds for offscreen
+ // layers in a regular cycles.
+ if (mLayer->isRemovedFromCurrentState()) {
+ FloatRect maxBounds = mFlinger.getMaxDisplayBounds();
+ mLayer->computeBounds(maxBounds, ui::Transform(), 0.f /* shadowRadius */);
+ }
drawLayers();
} else {
uint32_t w = static_cast<uint32_t>(getWidth());
diff --git a/services/surfaceflinger/MainThreadGuard.h b/services/surfaceflinger/MainThreadGuard.h
new file mode 100644
index 0000000000..c1aa118492
--- /dev/null
+++ b/services/surfaceflinger/MainThreadGuard.h
@@ -0,0 +1,35 @@
+/*
+ * 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 <utils/Mutex.h>
+
+namespace android {
+namespace {
+
+// Helps to ensure that some functions runs on SF's main thread by using the
+// clang thread safety annotations.
+class CAPABILITY("mutex") MainThreadGuard {
+} SF_MAIN_THREAD;
+
+struct SCOPED_CAPABILITY MainThreadScopedGuard {
+public:
+ explicit MainThreadScopedGuard(MainThreadGuard& mutex) ACQUIRE(mutex) {}
+ ~MainThreadScopedGuard() RELEASE() {}
+};
+} // namespace
+} // namespace android
diff --git a/services/surfaceflinger/OWNERS b/services/surfaceflinger/OWNERS
index 43a6e55a09..2ece51c3dc 100644
--- a/services/surfaceflinger/OWNERS
+++ b/services/surfaceflinger/OWNERS
@@ -3,4 +3,5 @@ alecmouri@google.com
chaviw@google.com
lpy@google.com
racarr@google.com
-vishnun@google.com
+scroggo@google.com
+vishnun@google.com \ No newline at end of file
diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp
index 27a1c280fb..bc32a1d66c 100644
--- a/services/surfaceflinger/RefreshRateOverlay.cpp
+++ b/services/surfaceflinger/RefreshRateOverlay.cpp
@@ -175,10 +175,14 @@ std::vector<sp<GraphicBuffer>> RefreshRateOverlay::SevenSegmentDrawer::drawNumbe
return buffers;
}
-RefreshRateOverlay::RefreshRateOverlay(SurfaceFlinger& flinger, bool showSpinner)
- : mFlinger(flinger), mClient(new Client(&mFlinger)), mShowSpinner(showSpinner) {
+RefreshRateOverlay::RefreshRateOverlay(SurfaceFlinger& flinger, uint32_t lowFps, uint32_t highFps,
+ bool showSpinner)
+ : mFlinger(flinger),
+ mClient(new Client(&mFlinger)),
+ mShowSpinner(showSpinner),
+ mLowFps(lowFps),
+ mHighFps(highFps) {
createLayer();
- reset();
}
bool RefreshRateOverlay::createLayer() {
@@ -194,7 +198,6 @@ bool RefreshRateOverlay::createLayer() {
return false;
}
- Mutex::Autolock _l(mFlinger.mStateLock);
mLayer = mClient->getLayerUser(mIBinder);
mLayer->setFrameRate(Layer::FrameRate(Fps(0.0f), Layer::FrameRateCompatibility::NoVote));
mLayer->setIsAtRoot(true);
@@ -241,8 +244,11 @@ RefreshRateOverlay::getOrCreateBuffers(uint32_t fps) {
}
void RefreshRateOverlay::setViewport(ui::Size viewport) {
- Rect frame((3 * viewport.width) >> 4, viewport.height >> 5);
- frame.offsetBy(viewport.width >> 5, viewport.height >> 4);
+ constexpr int32_t kMaxWidth = 1000;
+ const auto width = std::min(kMaxWidth, std::min(viewport.width, viewport.height));
+ const auto height = 2 * width;
+ Rect frame((3 * width) >> 4, height >> 5);
+ frame.offsetBy(width >> 5, height >> 4);
layer_state_t::matrix22_t matrix;
matrix.dsdx = frame.getWidth() / static_cast<float>(SevenSegmentDrawer::getWidth());
@@ -254,13 +260,18 @@ void RefreshRateOverlay::setViewport(ui::Size viewport) {
mFlinger.mTransactionFlags.fetch_or(eTransactionMask);
}
+void RefreshRateOverlay::setLayerStack(uint32_t stack) {
+ mLayer->setLayerStack(stack);
+ mFlinger.mTransactionFlags.fetch_or(eTransactionMask);
+}
+
void RefreshRateOverlay::changeRefreshRate(const Fps& fps) {
mCurrentFps = fps.getIntValue();
auto buffer = getOrCreateBuffers(*mCurrentFps)[mFrame];
mLayer->setBuffer(buffer, Fence::NO_FENCE, 0, 0, true, {},
mLayer->getHeadFrameNumber(-1 /* expectedPresentTime */),
std::nullopt /* dequeueTime */, FrameTimelineInfo{},
- nullptr /* releaseBufferListener */);
+ nullptr /* releaseBufferListener */, nullptr /* releaseBufferEndpoint */);
mFlinger.mTransactionFlags.fetch_or(eTransactionMask);
}
@@ -274,18 +285,11 @@ void RefreshRateOverlay::onInvalidate() {
mLayer->setBuffer(buffer, Fence::NO_FENCE, 0, 0, true, {},
mLayer->getHeadFrameNumber(-1 /* expectedPresentTime */),
std::nullopt /* dequeueTime */, FrameTimelineInfo{},
- nullptr /* releaseBufferListener */);
+ nullptr /* releaseBufferListener */, nullptr /* releaseBufferEndpoint */);
mFlinger.mTransactionFlags.fetch_or(eTransactionMask);
}
-void RefreshRateOverlay::reset() {
- mBufferCache.clear();
- const auto range = mFlinger.mRefreshRateConfigs->getSupportedRefreshRateRange();
- mLowFps = range.min.getIntValue();
- mHighFps = range.max.getIntValue();
-}
-
} // namespace android
// TODO(b/129481165): remove the #pragma below and fix conversion issues
diff --git a/services/surfaceflinger/RefreshRateOverlay.h b/services/surfaceflinger/RefreshRateOverlay.h
index aa8329c46a..f9baa898dc 100644
--- a/services/surfaceflinger/RefreshRateOverlay.h
+++ b/services/surfaceflinger/RefreshRateOverlay.h
@@ -37,12 +37,12 @@ class SurfaceFlinger;
class RefreshRateOverlay {
public:
- RefreshRateOverlay(SurfaceFlinger&, bool showSpinner);
+ RefreshRateOverlay(SurfaceFlinger&, uint32_t lowFps, uint32_t highFps, bool showSpinner);
+ void setLayerStack(uint32_t stack);
void setViewport(ui::Size);
void changeRefreshRate(const Fps&);
void onInvalidate();
- void reset();
private:
class SevenSegmentDrawer {
@@ -91,8 +91,8 @@ private:
const bool mShowSpinner;
// Interpolate the colors between these values.
- uint32_t mLowFps;
- uint32_t mHighFps;
+ const uint32_t mLowFps;
+ const uint32_t mHighFps;
};
} // namespace android
diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp
index 2321e2d082..2bdcaf6ad0 100644
--- a/services/surfaceflinger/Scheduler/EventThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventThread.cpp
@@ -118,12 +118,12 @@ DisplayEventReceiver::Event makeVSync(PhysicalDisplayId displayId, nsecs_t times
return event;
}
-DisplayEventReceiver::Event makeModeChanged(PhysicalDisplayId displayId, DisplayModeId modeId,
- nsecs_t vsyncPeriod) {
+DisplayEventReceiver::Event makeModeChanged(DisplayModePtr mode) {
DisplayEventReceiver::Event event;
- event.header = {DisplayEventReceiver::DISPLAY_EVENT_MODE_CHANGE, displayId, systemTime()};
- event.modeChange.modeId = modeId.value();
- event.modeChange.vsyncPeriod = vsyncPeriod;
+ event.header = {DisplayEventReceiver::DISPLAY_EVENT_MODE_CHANGE, mode->getPhysicalDisplayId(),
+ systemTime()};
+ event.modeChange.modeId = mode->getId().value();
+ event.modeChange.vsyncPeriod = mode->getVsyncPeriod();
return event;
}
@@ -375,11 +375,10 @@ void EventThread::onHotplugReceived(PhysicalDisplayId displayId, bool connected)
mCondition.notify_all();
}
-void EventThread::onModeChanged(PhysicalDisplayId displayId, DisplayModeId modeId,
- nsecs_t vsyncPeriod) {
+void EventThread::onModeChanged(DisplayModePtr mode) {
std::lock_guard<std::mutex> lock(mMutex);
- mPendingEvents.push_back(makeModeChanged(displayId, modeId, vsyncPeriod));
+ mPendingEvents.push_back(makeModeChanged(mode));
mCondition.notify_all();
}
diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h
index 1e6793f77c..9265a25b86 100644
--- a/services/surfaceflinger/Scheduler/EventThread.h
+++ b/services/surfaceflinger/Scheduler/EventThread.h
@@ -124,8 +124,7 @@ public:
virtual void onHotplugReceived(PhysicalDisplayId displayId, bool connected) = 0;
// called when SF changes the active mode and apps needs to be notified about the change
- virtual void onModeChanged(PhysicalDisplayId displayId, DisplayModeId modeId,
- nsecs_t vsyncPeriod) = 0;
+ virtual void onModeChanged(DisplayModePtr) = 0;
// called when SF updates the Frame Rate Override list
virtual void onFrameRateOverridesChanged(PhysicalDisplayId displayId,
@@ -174,8 +173,7 @@ public:
void onHotplugReceived(PhysicalDisplayId displayId, bool connected) override;
- void onModeChanged(PhysicalDisplayId displayId, DisplayModeId modeId,
- nsecs_t vsyncPeriod) override;
+ void onModeChanged(DisplayModePtr) override;
void onFrameRateOverridesChanged(PhysicalDisplayId displayId,
std::vector<FrameRateOverride> overrides) override;
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp
index 0563795c79..84e3548b6e 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.cpp
+++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp
@@ -75,10 +75,9 @@ void trace(const LayerInfo& info, LayerHistory::LayerVoteType type, int fps) {
}
} // namespace
-LayerHistory::LayerHistory(const RefreshRateConfigs& refreshRateConfigs)
+LayerHistory::LayerHistory()
: mTraceEnabled(traceEnabled()), mUseFrameRatePriority(useFrameRatePriority()) {
LayerInfo::setTraceEnabled(mTraceEnabled);
- LayerInfo::setRefreshRateConfigs(refreshRateConfigs);
}
LayerHistory::~LayerHistory() = default;
@@ -138,7 +137,8 @@ void LayerHistory::record(Layer* layer, nsecs_t presentTime, nsecs_t now,
}
}
-LayerHistory::Summary LayerHistory::summarize(nsecs_t now) {
+LayerHistory::Summary LayerHistory::summarize(const RefreshRateConfigs& refreshRateConfigs,
+ nsecs_t now) {
LayerHistory::Summary summary;
std::lock_guard lock(mLock);
@@ -151,7 +151,7 @@ LayerHistory::Summary LayerHistory::summarize(nsecs_t now) {
ALOGV("%s has priority: %d %s focused", info->getName().c_str(), frameRateSelectionPriority,
layerFocused ? "" : "not");
- const auto vote = info->getRefreshRateVote(now);
+ const auto vote = info->getRefreshRateVote(refreshRateConfigs, now);
// Skip NoVote layer as those don't have any requirements
if (vote.type == LayerHistory::LayerVoteType::NoVote) {
continue;
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.h b/services/surfaceflinger/Scheduler/LayerHistory.h
index 82f6c3907b..92236f560a 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.h
+++ b/services/surfaceflinger/Scheduler/LayerHistory.h
@@ -42,7 +42,7 @@ class LayerHistory {
public:
using LayerVoteType = RefreshRateConfigs::LayerVoteType;
- LayerHistory(const RefreshRateConfigs&);
+ LayerHistory();
~LayerHistory();
// Layers are unregistered when the weak reference expires.
@@ -67,7 +67,7 @@ public:
using Summary = std::vector<RefreshRateConfigs::LayerRequirement>;
// Rebuilds sets of active/inactive layers, and accumulates stats for active layers.
- Summary summarize(nsecs_t now);
+ Summary summarize(const RefreshRateConfigs&, nsecs_t now);
void clear();
diff --git a/services/surfaceflinger/Scheduler/LayerInfo.cpp b/services/surfaceflinger/Scheduler/LayerInfo.cpp
index 989bf4ef19..8a45b66b60 100644
--- a/services/surfaceflinger/Scheduler/LayerInfo.cpp
+++ b/services/surfaceflinger/Scheduler/LayerInfo.cpp
@@ -34,7 +34,6 @@
namespace android::scheduler {
-const RefreshRateConfigs* LayerInfo::sRefreshRateConfigs = nullptr;
bool LayerInfo::sTraceEnabled = false;
LayerInfo::LayerInfo(const std::string& name, uid_t ownerUid,
@@ -184,7 +183,8 @@ std::optional<nsecs_t> LayerInfo::calculateAverageFrameTime() const {
return static_cast<nsecs_t>(averageFrameTime);
}
-std::optional<Fps> LayerInfo::calculateRefreshRateIfPossible(nsecs_t now) {
+std::optional<Fps> LayerInfo::calculateRefreshRateIfPossible(
+ const RefreshRateConfigs& refreshRateConfigs, nsecs_t now) {
static constexpr float MARGIN = 1.0f; // 1Hz
if (!hasEnoughDataForHeuristic()) {
ALOGV("Not enough data");
@@ -196,9 +196,7 @@ std::optional<Fps> LayerInfo::calculateRefreshRateIfPossible(nsecs_t now) {
const auto refreshRate = Fps::fromPeriodNsecs(*averageFrameTime);
const bool refreshRateConsistent = mRefreshRateHistory.add(refreshRate, now);
if (refreshRateConsistent) {
- const auto knownRefreshRate =
- sRefreshRateConfigs->findClosestKnownFrameRate(refreshRate);
-
+ const auto knownRefreshRate = refreshRateConfigs.findClosestKnownFrameRate(refreshRate);
// To avoid oscillation, use the last calculated refresh rate if it is
// close enough
if (std::abs(mLastRefreshRate.calculated.getValue() - refreshRate.getValue()) >
@@ -220,7 +218,8 @@ std::optional<Fps> LayerInfo::calculateRefreshRateIfPossible(nsecs_t now) {
: std::nullopt;
}
-LayerInfo::LayerVote LayerInfo::getRefreshRateVote(nsecs_t now) {
+LayerInfo::LayerVote LayerInfo::getRefreshRateVote(const RefreshRateConfigs& refreshRateConfigs,
+ nsecs_t now) {
if (mLayerVote.type != LayerHistory::LayerVoteType::Heuristic) {
ALOGV("%s voted %d ", mName.c_str(), static_cast<int>(mLayerVote.type));
return mLayerVote;
@@ -247,7 +246,7 @@ LayerInfo::LayerVote LayerInfo::getRefreshRateVote(nsecs_t now) {
clearHistory(now);
}
- auto refreshRate = calculateRefreshRateIfPossible(now);
+ auto refreshRate = calculateRefreshRateIfPossible(refreshRateConfigs, now);
if (refreshRate.has_value()) {
ALOGV("%s calculated refresh rate: %s", mName.c_str(), to_string(*refreshRate).c_str());
return {LayerHistory::LayerVoteType::Heuristic, refreshRate.value()};
diff --git a/services/surfaceflinger/Scheduler/LayerInfo.h b/services/surfaceflinger/Scheduler/LayerInfo.h
index 34cc3890d3..ce9783c5a9 100644
--- a/services/surfaceflinger/Scheduler/LayerInfo.h
+++ b/services/surfaceflinger/Scheduler/LayerInfo.h
@@ -122,10 +122,6 @@ public:
static void setTraceEnabled(bool enabled) { sTraceEnabled = enabled; }
- static void setRefreshRateConfigs(const RefreshRateConfigs& refreshRateConfigs) {
- sRefreshRateConfigs = &refreshRateConfigs;
- }
-
LayerInfo(const std::string& name, uid_t ownerUid, LayerHistory::LayerVoteType defaultVote);
LayerInfo(const LayerInfo&) = delete;
@@ -161,7 +157,7 @@ public:
uid_t getOwnerUid() const { return mOwnerUid; }
- LayerVote getRefreshRateVote(nsecs_t now);
+ LayerVote getRefreshRateVote(const RefreshRateConfigs&, nsecs_t now);
// Return the last updated time. If the present time is farther in the future than the
// updated time, the updated time is the present time.
@@ -263,7 +259,7 @@ private:
bool isFrequent(nsecs_t now) const;
bool isAnimating(nsecs_t now) const;
bool hasEnoughDataForHeuristic() const;
- std::optional<Fps> calculateRefreshRateIfPossible(nsecs_t now);
+ std::optional<Fps> calculateRefreshRateIfPossible(const RefreshRateConfigs&, nsecs_t now);
std::optional<nsecs_t> calculateAverageFrameTime() const;
bool isFrameTimeValid(const FrameTimeData&) const;
@@ -300,7 +296,6 @@ private:
mutable std::unordered_map<LayerHistory::LayerVoteType, std::string> mTraceTags;
// Shared for all LayerInfo instances
- static const RefreshRateConfigs* sRefreshRateConfigs;
static bool sTraceEnabled;
};
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
index 71cd52d0db..a56827e8f1 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
@@ -22,6 +22,7 @@
#pragma clang diagnostic ignored "-Wextra"
#include "RefreshRateConfigs.h"
+#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <utils/Trace.h>
#include <chrono>
@@ -113,7 +114,7 @@ bool RefreshRateConfigs::isVoteAllowed(const LayerRequirement& layer,
case LayerVoteType::ExplicitExactOrMultiple:
case LayerVoteType::Heuristic:
if (mConfig.frameRateMultipleThreshold != 0 &&
- refreshRate.fps.greaterThanOrEqualWithMargin(
+ refreshRate.getFps().greaterThanOrEqualWithMargin(
Fps(mConfig.frameRateMultipleThreshold)) &&
layer.desiredRefreshRate.lessThanWithMargin(
Fps(mConfig.frameRateMultipleThreshold / 2))) {
@@ -491,7 +492,7 @@ RefreshRate RefreshRateConfigs::getBestRefreshRateLocked(
}
}();
if (globalSignals.touch && explicitDefaultVoteLayers == 0 && touchBoostForExplicitExact &&
- bestRefreshRate->fps.lessThanWithMargin(touchRefreshRate.fps)) {
+ bestRefreshRate->getFps().lessThanWithMargin(touchRefreshRate.getFps())) {
setTouchConsidered();
ALOGV("TouchBoost - choose %s", touchRefreshRate.getName().c_str());
return touchRefreshRate;
@@ -707,9 +708,30 @@ void RefreshRateConfigs::setCurrentModeId(DisplayModeId modeId) {
RefreshRateConfigs::RefreshRateConfigs(const DisplayModes& modes, DisplayModeId currentModeId,
Config config)
: mKnownFrameRates(constructKnownFrameRates(modes)), mConfig(config) {
+ initializeIdleTimer();
updateDisplayModes(modes, currentModeId);
}
+void RefreshRateConfigs::initializeIdleTimer() {
+ if (mConfig.idleTimerTimeoutMs > 0) {
+ const auto getCallback = [this]() -> std::optional<IdleTimerCallbacks::Callbacks> {
+ std::scoped_lock lock(mIdleTimerCallbacksMutex);
+ if (!mIdleTimerCallbacks.has_value()) return {};
+ return mConfig.supportKernelIdleTimer ? mIdleTimerCallbacks->kernel
+ : mIdleTimerCallbacks->platform;
+ };
+
+ mIdleTimer.emplace(
+ "IdleTimer", std::chrono::milliseconds(mConfig.idleTimerTimeoutMs),
+ [getCallback] {
+ if (const auto callback = getCallback()) callback->onReset();
+ },
+ [getCallback] {
+ if (const auto callback = getCallback()) callback->onExpired();
+ });
+ }
+}
+
void RefreshRateConfigs::updateDisplayModes(const DisplayModes& modes,
DisplayModeId currentModeId) {
std::lock_guard lock(mLock);
@@ -727,8 +749,7 @@ void RefreshRateConfigs::updateDisplayModes(const DisplayModes& modes,
for (const auto& mode : modes) {
const auto modeId = mode->getId();
mRefreshRates.emplace(modeId,
- std::make_unique<RefreshRate>(modeId, mode, mode->getFps(),
- RefreshRate::ConstructorTag(0)));
+ std::make_unique<RefreshRate>(mode, RefreshRate::ConstructorTag(0)));
if (modeId == currentModeId) {
mCurrentRefreshRate = mRefreshRates.at(modeId).get();
}
@@ -821,7 +842,7 @@ RefreshRateConfigs::Policy RefreshRateConfigs::getDisplayManagerPolicy() const {
bool RefreshRateConfigs::isModeAllowed(DisplayModeId modeId) const {
std::lock_guard lock(mLock);
for (const RefreshRate* refreshRate : mAppRequestRefreshRates) {
- if (refreshRate->modeId == modeId) {
+ if (refreshRate->getModeId() == modeId) {
return true;
}
}
@@ -836,7 +857,7 @@ void RefreshRateConfigs::getSortedRefreshRateListLocked(
for (const auto& [type, refreshRate] : mRefreshRates) {
if (shouldAddRefreshRate(*refreshRate)) {
ALOGV("getSortedRefreshRateListLocked: mode %d added to list policy",
- refreshRate->modeId.value());
+ refreshRate->getModeId().value());
outRefreshRates->push_back(refreshRate.get());
}
}
@@ -984,6 +1005,9 @@ void RefreshRateConfigs::dump(std::string& result) const {
base::StringAppendF(&result, "Supports Frame Rate Override: %s\n",
mSupportsFrameRateOverride ? "yes" : "no");
+ base::StringAppendF(&result, "Idle timer: (%s) %s\n",
+ mConfig.supportKernelIdleTimer ? "kernel" : "platform",
+ mIdleTimer ? mIdleTimer->dump().c_str() : "off");
result.append("\n");
}
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
index 913e5ee2dc..99f217c2e2 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -27,6 +27,7 @@
#include "DisplayHardware/DisplayMode.h"
#include "DisplayHardware/HWComposer.h"
#include "Fps.h"
+#include "Scheduler/OneShotTimer.h"
#include "Scheduler/SchedulerUtils.h"
#include "Scheduler/Seamlessness.h"
#include "Scheduler/StrongTyping.h"
@@ -64,25 +65,23 @@ public:
};
public:
- RefreshRate(DisplayModeId modeId, DisplayModePtr mode, Fps fps, ConstructorTag)
- : modeId(modeId), mode(mode), fps(std::move(fps)) {}
+ RefreshRate(DisplayModePtr mode, ConstructorTag) : mode(mode) {}
- DisplayModeId getModeId() const { return modeId; }
+ DisplayModeId getModeId() const { return mode->getId(); }
nsecs_t getVsyncPeriod() const { return mode->getVsyncPeriod(); }
int32_t getModeGroup() const { return mode->getGroup(); }
- std::string getName() const { return to_string(fps); }
- Fps getFps() const { return fps; }
+ std::string getName() const { return to_string(getFps()); }
+ Fps getFps() const { return mode->getFps(); }
+ DisplayModePtr getMode() const { return mode; }
// Checks whether the fps of this RefreshRate struct is within a given min and max refresh
// rate passed in. Margin of error is applied to the boundaries for approximation.
bool inPolicy(Fps minRefreshRate, Fps maxRefreshRate) const {
- return minRefreshRate.lessThanOrEqualWithMargin(fps) &&
- fps.lessThanOrEqualWithMargin(maxRefreshRate);
+ return minRefreshRate.lessThanOrEqualWithMargin(getFps()) &&
+ getFps().lessThanOrEqualWithMargin(maxRefreshRate);
}
- bool operator!=(const RefreshRate& other) const {
- return modeId != other.modeId || mode != other.mode;
- }
+ bool operator!=(const RefreshRate& other) const { return mode != other.mode; }
bool operator<(const RefreshRate& other) const {
return getFps().getValue() < other.getFps().getValue();
@@ -99,10 +98,7 @@ public:
friend RefreshRateConfigs;
friend class RefreshRateConfigsTest;
- const DisplayModeId modeId;
DisplayModePtr mode;
- // Refresh rate in frames per second
- const Fps fps{0.0f};
};
using AllRefreshRatesMapType =
@@ -310,13 +306,19 @@ public:
// or heuristic, such that refresh rates higher than this value will not be voted for. 0 if
// no threshold is set.
int frameRateMultipleThreshold = 0;
+
+ // The Idle Timer timeout. 0 timeout means no idle timer.
+ int32_t idleTimerTimeoutMs = 0;
+
+ // Whether to use idle timer callbacks that support the kernel timer.
+ bool supportKernelIdleTimer = false;
};
- RefreshRateConfigs(const DisplayModes& modes, DisplayModeId currentModeId,
+ RefreshRateConfigs(const DisplayModes&, DisplayModeId,
Config config = {.enableFrameRateOverride = false,
- .frameRateMultipleThreshold = 0});
-
- void updateDisplayModes(const DisplayModes& mode, DisplayModeId currentModeId) EXCLUDES(mLock);
+ .frameRateMultipleThreshold = 0,
+ .idleTimerTimeoutMs = 0,
+ .supportKernelIdleTimer = false});
// Returns whether switching modes (refresh rate or resolution) is possible.
// TODO(b/158780872): Consider HAL support, and skip frame rate detection if the modes only
@@ -356,8 +358,47 @@ public:
Fps displayFrameRate, bool touch) const
EXCLUDES(mLock);
+ bool supportsKernelIdleTimer() const { return mConfig.supportKernelIdleTimer; }
+
+ void setIdleTimerCallbacks(std::function<void()> platformTimerReset,
+ std::function<void()> platformTimerExpired,
+ std::function<void()> kernelTimerReset,
+ std::function<void()> kernelTimerExpired) {
+ std::scoped_lock lock(mIdleTimerCallbacksMutex);
+ mIdleTimerCallbacks.emplace();
+ mIdleTimerCallbacks->platform.onReset = std::move(platformTimerReset);
+ mIdleTimerCallbacks->platform.onExpired = std::move(platformTimerExpired);
+ mIdleTimerCallbacks->kernel.onReset = std::move(kernelTimerReset);
+ mIdleTimerCallbacks->kernel.onExpired = std::move(kernelTimerExpired);
+ }
+
+ void startIdleTimer() {
+ if (mIdleTimer) {
+ mIdleTimer->start();
+ }
+ }
+
+ void stopIdleTimer() {
+ if (mIdleTimer) {
+ mIdleTimer->stop();
+ }
+ }
+
+ void resetIdleTimer(bool kernelOnly) {
+ if (!mIdleTimer) {
+ return;
+ }
+ if (kernelOnly && !mConfig.supportKernelIdleTimer) {
+ return;
+ }
+ mIdleTimer->reset();
+ };
+
void dump(std::string& result) const EXCLUDES(mLock);
+ RefreshRateConfigs(const RefreshRateConfigs&) = delete;
+ void operator=(const RefreshRateConfigs&) = delete;
+
private:
friend class RefreshRateConfigsTest;
@@ -412,6 +453,10 @@ private:
float calculateNonExactMatchingLayerScoreLocked(const LayerRequirement&,
const RefreshRate&) const REQUIRES(mLock);
+ void updateDisplayModes(const DisplayModes& mode, DisplayModeId currentModeId) EXCLUDES(mLock);
+
+ void initializeIdleTimer();
+
// The list of refresh rates, indexed by display modes ID. This may change after this
// object is initialized.
AllRefreshRatesMapType mRefreshRates GUARDED_BY(mLock);
@@ -455,6 +500,22 @@ private:
};
mutable std::optional<GetBestRefreshRateInvocation> lastBestRefreshRateInvocation
GUARDED_BY(mLock);
+
+ // Timer that records time between requests for next vsync.
+ std::optional<scheduler::OneShotTimer> mIdleTimer;
+
+ struct IdleTimerCallbacks {
+ struct Callbacks {
+ std::function<void()> onReset;
+ std::function<void()> onExpired;
+ };
+
+ Callbacks platform;
+ Callbacks kernel;
+ };
+
+ std::mutex mIdleTimerCallbacksMutex;
+ std::optional<IdleTimerCallbacks> mIdleTimerCallbacks GUARDED_BY(mIdleTimerCallbacksMutex);
};
} // namespace android::scheduler
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 64ad178b26..1989d57cd7 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -25,7 +25,7 @@
#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
#include <android/hardware/configstore/1.1/ISurfaceFlingerConfigs.h>
#include <configstore/Utils.h>
-#include <input/InputWindow.h>
+#include <gui/WindowInfo.h>
#include <system/window.h>
#include <ui/DisplayStatInfo.h>
#include <utils/Timers.h>
@@ -64,6 +64,8 @@ using namespace std::string_literals;
namespace android {
+using gui::WindowInfo;
+
namespace {
std::unique_ptr<scheduler::VSyncTracker> createVSyncTracker() {
@@ -115,30 +117,18 @@ private:
}
};
-Scheduler::Scheduler(const scheduler::RefreshRateConfigs& configs, ISchedulerCallback& callback)
+Scheduler::Scheduler(const std::shared_ptr<scheduler::RefreshRateConfigs>& configs,
+ ISchedulerCallback& callback)
: Scheduler(configs, callback,
- {.supportKernelTimer = sysprop::support_kernel_idle_timer(false),
- .useContentDetection = sysprop::use_content_detection_for_refresh_rate(false)}) {
+ {.useContentDetection = sysprop::use_content_detection_for_refresh_rate(false)}) {
}
-Scheduler::Scheduler(const scheduler::RefreshRateConfigs& configs, ISchedulerCallback& callback,
- Options options)
- : Scheduler(createVsyncSchedule(options.supportKernelTimer), configs, callback,
- createLayerHistory(configs), options) {
+Scheduler::Scheduler(const std::shared_ptr<scheduler::RefreshRateConfigs>& configs,
+ ISchedulerCallback& callback, Options options)
+ : Scheduler(createVsyncSchedule(configs->supportsKernelIdleTimer()), configs, callback,
+ createLayerHistory(), options) {
using namespace sysprop;
- const int setIdleTimerMs = base::GetIntProperty("debug.sf.set_idle_timer_ms"s, 0);
-
- if (const auto millis = setIdleTimerMs ? setIdleTimerMs : set_idle_timer_ms(0); millis > 0) {
- const auto callback = mOptions.supportKernelTimer ? &Scheduler::kernelIdleTimerCallback
- : &Scheduler::idleTimerCallback;
- mIdleTimer.emplace(
- "IdleTimer", std::chrono::milliseconds(millis),
- [this, callback] { std::invoke(callback, this, TimerState::Reset); },
- [this, callback] { std::invoke(callback, this, TimerState::Expired); });
- mIdleTimer->start();
- }
-
if (const int64_t millis = set_touch_timer_ms(0); millis > 0) {
// Touch events are coming to SF every 100ms, so the timer needs to be higher than that
mTouchTimer.emplace(
@@ -157,18 +147,19 @@ Scheduler::Scheduler(const scheduler::RefreshRateConfigs& configs, ISchedulerCal
}
}
-Scheduler::Scheduler(VsyncSchedule schedule, const scheduler::RefreshRateConfigs& configs,
+Scheduler::Scheduler(VsyncSchedule schedule,
+ const std::shared_ptr<scheduler::RefreshRateConfigs>& configs,
ISchedulerCallback& schedulerCallback,
std::unique_ptr<LayerHistory> layerHistory, Options options)
: mOptions(options),
mVsyncSchedule(std::move(schedule)),
mLayerHistory(std::move(layerHistory)),
mSchedulerCallback(schedulerCallback),
- mRefreshRateConfigs(configs),
mPredictedVsyncTracer(
base::GetBoolProperty("debug.sf.show_predicted_vsync", false)
? std::make_unique<PredictedVsyncTracer>(*mVsyncSchedule.dispatch)
: nullptr) {
+ setRefreshRateConfigs(configs);
mSchedulerCallback.setVsyncEnabled(false);
}
@@ -176,7 +167,7 @@ Scheduler::~Scheduler() {
// Ensure the OneShotTimer threads are joined before we start destroying state.
mDisplayPowerTimer.reset();
mTouchTimer.reset();
- mIdleTimer.reset();
+ mRefreshRateConfigs.reset();
}
Scheduler::VsyncSchedule Scheduler::createVsyncSchedule(bool supportKernelTimer) {
@@ -192,9 +183,8 @@ Scheduler::VsyncSchedule Scheduler::createVsyncSchedule(bool supportKernelTimer)
return {std::move(controller), std::move(tracker), std::move(dispatch)};
}
-std::unique_ptr<LayerHistory> Scheduler::createLayerHistory(
- const scheduler::RefreshRateConfigs& configs) {
- return std::make_unique<scheduler::LayerHistory>(configs);
+std::unique_ptr<LayerHistory> Scheduler::createLayerHistory() {
+ return std::make_unique<scheduler::LayerHistory>();
}
std::unique_ptr<VSyncSource> Scheduler::makePrimaryDispSyncSource(
@@ -205,11 +195,14 @@ std::unique_ptr<VSyncSource> Scheduler::makePrimaryDispSyncSource(
}
std::optional<Fps> Scheduler::getFrameRateOverride(uid_t uid) const {
- if (!mRefreshRateConfigs.supportsFrameRateOverride()) {
- return std::nullopt;
+ {
+ std::scoped_lock lock(mRefreshRateConfigsLock);
+ if (!mRefreshRateConfigs->supportsFrameRateOverride()) {
+ return std::nullopt;
+ }
}
- std::lock_guard lock(mFrameRateOverridesMutex);
+ std::lock_guard lock(mFrameRateOverridesLock);
{
const auto iter = mFrameRateOverridesFromBackdoor.find(uid);
if (iter != mFrameRateOverridesFromBackdoor.end()) {
@@ -237,7 +230,8 @@ bool Scheduler::isVsyncValid(nsecs_t expectedVsyncTimestamp, uid_t uid) const {
}
impl::EventThread::ThrottleVsyncCallback Scheduler::makeThrottleVsyncCallback() const {
- if (!mRefreshRateConfigs.supportsFrameRateOverride()) {
+ std::scoped_lock lock(mRefreshRateConfigsLock);
+ if (!mRefreshRateConfigs->supportsFrameRateOverride()) {
return {};
}
@@ -248,14 +242,18 @@ impl::EventThread::ThrottleVsyncCallback Scheduler::makeThrottleVsyncCallback()
impl::EventThread::GetVsyncPeriodFunction Scheduler::makeGetVsyncPeriodFunction() const {
return [this](uid_t uid) {
- nsecs_t basePeriod = mRefreshRateConfigs.getCurrentRefreshRate().getVsyncPeriod();
+ const auto refreshRateConfigs = holdRefreshRateConfigs();
+ nsecs_t basePeriod = refreshRateConfigs->getCurrentRefreshRate().getVsyncPeriod();
const auto frameRate = getFrameRateOverride(uid);
if (!frameRate.has_value()) {
return basePeriod;
}
- const auto divider = scheduler::RefreshRateConfigs::getFrameRateDivider(
- mRefreshRateConfigs.getCurrentRefreshRate().getFps(), *frameRate);
+ const auto divider =
+ scheduler::RefreshRateConfigs::getFrameRateDivider(refreshRateConfigs
+ ->getCurrentRefreshRate()
+ .getFps(),
+ *frameRate);
if (divider <= 1) {
return basePeriod;
}
@@ -326,6 +324,7 @@ void Scheduler::onScreenAcquired(ConnectionHandle handle) {
thread = mConnections[handle].thread.get();
}
thread->onScreenAcquired();
+ mScreenAcquired = true;
}
void Scheduler::onScreenReleased(ConnectionHandle handle) {
@@ -336,12 +335,13 @@ void Scheduler::onScreenReleased(ConnectionHandle handle) {
thread = mConnections[handle].thread.get();
}
thread->onScreenReleased();
+ mScreenAcquired = false;
}
void Scheduler::onFrameRateOverridesChanged(ConnectionHandle handle, PhysicalDisplayId displayId) {
std::vector<FrameRateOverride> overrides;
{
- std::lock_guard lock(mFrameRateOverridesMutex);
+ std::lock_guard lock(mFrameRateOverridesLock);
for (const auto& [uid, frameRate] : mFrameRateOverridesFromBackdoor) {
overrides.emplace_back(FrameRateOverride{uid, frameRate.getValue()});
}
@@ -360,23 +360,22 @@ void Scheduler::onFrameRateOverridesChanged(ConnectionHandle handle, PhysicalDis
thread->onFrameRateOverridesChanged(displayId, std::move(overrides));
}
-void Scheduler::onPrimaryDisplayModeChanged(ConnectionHandle handle, PhysicalDisplayId displayId,
- DisplayModeId modeId, nsecs_t vsyncPeriod) {
+void Scheduler::onPrimaryDisplayModeChanged(ConnectionHandle handle, DisplayModePtr mode) {
{
std::lock_guard<std::mutex> lock(mFeatureStateLock);
// Cache the last reported modes for primary display.
- mFeatures.cachedModeChangedParams = {handle, displayId, modeId, vsyncPeriod};
+ mFeatures.cachedModeChangedParams = {handle, mode};
// Invalidate content based refresh rate selection so it could be calculated
// again for the new refresh rate.
mFeatures.contentRequirements.clear();
}
- onNonPrimaryDisplayModeChanged(handle, displayId, modeId, vsyncPeriod);
+ onNonPrimaryDisplayModeChanged(handle, mode);
}
void Scheduler::dispatchCachedReportedMode() {
// Check optional fields first.
- if (!mFeatures.modeId.has_value()) {
+ if (!mFeatures.mode) {
ALOGW("No mode ID found, not dispatching cached mode.");
return;
}
@@ -385,39 +384,32 @@ void Scheduler::dispatchCachedReportedMode() {
return;
}
- const auto modeId = *mFeatures.modeId;
- // If the modeId is not the current mode, this means that a
+ // If the mode is not the current mode, this means that a
// mode change is in progress. In that case we shouldn't dispatch an event
// as it will be dispatched when the current mode changes.
- if (mRefreshRateConfigs.getCurrentRefreshRate().getModeId() != modeId) {
+ if (std::scoped_lock lock(mRefreshRateConfigsLock);
+ mRefreshRateConfigs->getCurrentRefreshRate().getMode() != mFeatures.mode) {
return;
}
- const auto vsyncPeriod = mRefreshRateConfigs.getRefreshRateFromModeId(modeId).getVsyncPeriod();
-
// If there is no change from cached mode, there is no need to dispatch an event
- if (modeId == mFeatures.cachedModeChangedParams->modeId &&
- vsyncPeriod == mFeatures.cachedModeChangedParams->vsyncPeriod) {
+ if (mFeatures.mode == mFeatures.cachedModeChangedParams->mode) {
return;
}
- mFeatures.cachedModeChangedParams->modeId = modeId;
- mFeatures.cachedModeChangedParams->vsyncPeriod = vsyncPeriod;
+ mFeatures.cachedModeChangedParams->mode = mFeatures.mode;
onNonPrimaryDisplayModeChanged(mFeatures.cachedModeChangedParams->handle,
- mFeatures.cachedModeChangedParams->displayId,
- mFeatures.cachedModeChangedParams->modeId,
- mFeatures.cachedModeChangedParams->vsyncPeriod);
+ mFeatures.cachedModeChangedParams->mode);
}
-void Scheduler::onNonPrimaryDisplayModeChanged(ConnectionHandle handle, PhysicalDisplayId displayId,
- DisplayModeId modeId, nsecs_t vsyncPeriod) {
+void Scheduler::onNonPrimaryDisplayModeChanged(ConnectionHandle handle, DisplayModePtr mode) {
android::EventThread* thread;
{
std::lock_guard<std::mutex> lock(mConnectionsLock);
RETURN_IF_INVALID_HANDLE(handle);
thread = mConnections[handle].thread.get();
}
- thread->onModeChanged(displayId, modeId, vsyncPeriod);
+ thread->onModeChanged(mode);
}
size_t Scheduler::getEventThreadConnectionCount(ConnectionHandle handle) {
@@ -537,7 +529,11 @@ void Scheduler::resync() {
const nsecs_t last = mLastResyncTime.exchange(now);
if (now - last > kIgnoreDelay) {
- resyncToHardwareVsync(false, mRefreshRateConfigs.getCurrentRefreshRate().getVsyncPeriod());
+ const auto vsyncPeriod = [&] {
+ std::scoped_lock lock(mRefreshRateConfigsLock);
+ return mRefreshRateConfigs->getCurrentRefreshRate().getVsyncPeriod();
+ }();
+ resyncToHardwareVsync(false, vsyncPeriod);
}
}
@@ -586,10 +582,9 @@ void Scheduler::setIgnorePresentFences(bool ignore) {
void Scheduler::registerLayer(Layer* layer) {
scheduler::LayerHistory::LayerVoteType voteType;
- if (!mOptions.useContentDetection ||
- layer->getWindowType() == InputWindowInfo::Type::STATUS_BAR) {
+ if (!mOptions.useContentDetection || layer->getWindowType() == WindowInfo::Type::STATUS_BAR) {
voteType = scheduler::LayerHistory::LayerVoteType::NoVote;
- } else if (layer->getWindowType() == InputWindowInfo::Type::WALLPAPER) {
+ } else if (layer->getWindowType() == WindowInfo::Type::WALLPAPER) {
// Running Wallpaper at Min is considered as part of content detection.
voteType = scheduler::LayerHistory::LayerVoteType::Min;
} else {
@@ -608,9 +603,12 @@ void Scheduler::deregisterLayer(Layer* layer) {
void Scheduler::recordLayerHistory(Layer* layer, nsecs_t presentTime,
LayerHistory::LayerUpdateType updateType) {
- if (mRefreshRateConfigs.canSwitch()) {
- mLayerHistory->record(layer, presentTime, systemTime(), updateType);
+ {
+ std::scoped_lock lock(mRefreshRateConfigsLock);
+ if (!mRefreshRateConfigs->canSwitch()) return;
}
+
+ mLayerHistory->record(layer, presentTime, systemTime(), updateType);
}
void Scheduler::setModeChangePending(bool pending) {
@@ -618,25 +616,28 @@ void Scheduler::setModeChangePending(bool pending) {
}
void Scheduler::chooseRefreshRateForContent() {
- if (!mRefreshRateConfigs.canSwitch()) return;
+ {
+ std::scoped_lock lock(mRefreshRateConfigsLock);
+ if (!mRefreshRateConfigs->canSwitch()) return;
+ }
ATRACE_CALL();
- scheduler::LayerHistory::Summary summary = mLayerHistory->summarize(systemTime());
+ const auto refreshRateConfigs = holdRefreshRateConfigs();
+ scheduler::LayerHistory::Summary summary =
+ mLayerHistory->summarize(*refreshRateConfigs, systemTime());
scheduler::RefreshRateConfigs::GlobalSignals consideredSignals;
- DisplayModeId newModeId;
+ DisplayModePtr newMode;
bool frameRateChanged;
bool frameRateOverridesChanged;
{
std::lock_guard<std::mutex> lock(mFeatureStateLock);
mFeatures.contentRequirements = summary;
- newModeId = calculateRefreshRateModeId(&consideredSignals);
- auto newRefreshRate = mRefreshRateConfigs.getRefreshRateFromModeId(newModeId);
- frameRateOverridesChanged =
- updateFrameRateOverrides(consideredSignals, newRefreshRate.getFps());
+ newMode = calculateRefreshRateModeId(&consideredSignals);
+ frameRateOverridesChanged = updateFrameRateOverrides(consideredSignals, newMode->getFps());
- if (mFeatures.modeId == newModeId) {
+ if (mFeatures.mode == newMode) {
// We don't need to change the display mode, but we might need to send an event
// about a mode change, since it was suppressed due to a previous idleConsidered
if (!consideredSignals.idle) {
@@ -644,12 +645,12 @@ void Scheduler::chooseRefreshRateForContent() {
}
frameRateChanged = false;
} else {
- mFeatures.modeId = newModeId;
+ mFeatures.mode = newMode;
frameRateChanged = true;
}
}
if (frameRateChanged) {
- auto newRefreshRate = mRefreshRateConfigs.getRefreshRateFromModeId(newModeId);
+ auto newRefreshRate = refreshRateConfigs->getRefreshRateFromModeId(newMode->getId());
mSchedulerCallback.changeRefreshRate(newRefreshRate,
consideredSignals.idle ? ModeEvent::None
: ModeEvent::Changed);
@@ -660,18 +661,16 @@ void Scheduler::chooseRefreshRateForContent() {
}
void Scheduler::resetIdleTimer() {
- if (mIdleTimer) {
- mIdleTimer->reset();
- }
+ std::scoped_lock lock(mRefreshRateConfigsLock);
+ mRefreshRateConfigs->resetIdleTimer(/*kernelOnly*/ false);
}
void Scheduler::notifyTouchEvent() {
if (mTouchTimer) {
mTouchTimer->reset();
- if (mOptions.supportKernelTimer && mIdleTimer) {
- mIdleTimer->reset();
- }
+ std::scoped_lock lock(mRefreshRateConfigsLock);
+ mRefreshRateConfigs->resetIdleTimer(/*kernelOnly*/ true);
}
}
@@ -695,7 +694,11 @@ void Scheduler::kernelIdleTimerCallback(TimerState state) {
// TODO(145561154): cleanup the kernel idle timer implementation and the refresh rate
// magic number
- const auto& refreshRate = mRefreshRateConfigs.getCurrentRefreshRate();
+ const auto refreshRate = [&] {
+ std::scoped_lock lock(mRefreshRateConfigsLock);
+ return mRefreshRateConfigs->getCurrentRefreshRate();
+ }();
+
constexpr Fps FPS_THRESHOLD_FOR_KERNEL_TIMER{65.0f};
if (state == TimerState::Reset &&
refreshRate.getFps().greaterThanWithMargin(FPS_THRESHOLD_FOR_KERNEL_TIMER)) {
@@ -739,7 +742,6 @@ void Scheduler::displayPowerTimerCallback(TimerState state) {
void Scheduler::dump(std::string& result) const {
using base::StringAppendF;
- StringAppendF(&result, "+ Idle timer: %s\n", mIdleTimer ? mIdleTimer->dump().c_str() : "off");
StringAppendF(&result, "+ Touch timer: %s\n",
mTouchTimer ? mTouchTimer->dump().c_str() : "off");
StringAppendF(&result, "+ Content detection: %s %s\n\n",
@@ -747,7 +749,7 @@ void Scheduler::dump(std::string& result) const {
mLayerHistory ? mLayerHistory->dump().c_str() : "(no layer history)");
{
- std::lock_guard lock(mFrameRateOverridesMutex);
+ std::lock_guard lock(mFrameRateOverridesLock);
StringAppendF(&result, "Frame Rate Overrides (backdoor): {");
for (const auto& [uid, frameRate] : mFrameRateOverridesFromBackdoor) {
StringAppendF(&result, "[uid: %d frameRate: %s], ", uid, to_string(frameRate).c_str());
@@ -760,6 +762,13 @@ void Scheduler::dump(std::string& result) const {
}
StringAppendF(&result, "}\n");
}
+
+ {
+ std::lock_guard lock(mHWVsyncLock);
+ StringAppendF(&result,
+ "mScreenAcquired=%d mPrimaryHWVsyncEnabled=%d mHWVsyncAvailable=%d\n",
+ mScreenAcquired.load(), mPrimaryHWVsyncEnabled, mHWVsyncAvailable);
+ }
}
void Scheduler::dumpVsync(std::string& s) const {
@@ -773,16 +782,17 @@ void Scheduler::dumpVsync(std::string& s) const {
bool Scheduler::updateFrameRateOverrides(
scheduler::RefreshRateConfigs::GlobalSignals consideredSignals, Fps displayRefreshRate) {
- if (!mRefreshRateConfigs.supportsFrameRateOverride()) {
+ const auto refreshRateConfigs = holdRefreshRateConfigs();
+ if (!refreshRateConfigs->supportsFrameRateOverride()) {
return false;
}
if (!consideredSignals.idle) {
const auto frameRateOverrides =
- mRefreshRateConfigs.getFrameRateOverrides(mFeatures.contentRequirements,
+ refreshRateConfigs->getFrameRateOverrides(mFeatures.contentRequirements,
displayRefreshRate,
consideredSignals.touch);
- std::lock_guard lock(mFrameRateOverridesMutex);
+ std::lock_guard lock(mFrameRateOverridesLock);
if (!std::equal(mFrameRateOverridesByContent.begin(), mFrameRateOverridesByContent.end(),
frameRateOverrides.begin(), frameRateOverrides.end(),
[](const std::pair<uid_t, Fps>& a, const std::pair<uid_t, Fps>& b) {
@@ -797,33 +807,33 @@ bool Scheduler::updateFrameRateOverrides(
template <class T>
bool Scheduler::handleTimerStateChanged(T* currentState, T newState) {
- DisplayModeId newModeId;
+ DisplayModePtr newMode;
bool refreshRateChanged = false;
bool frameRateOverridesChanged;
scheduler::RefreshRateConfigs::GlobalSignals consideredSignals;
+ const auto refreshRateConfigs = holdRefreshRateConfigs();
{
std::lock_guard<std::mutex> lock(mFeatureStateLock);
if (*currentState == newState) {
return false;
}
*currentState = newState;
- newModeId = calculateRefreshRateModeId(&consideredSignals);
- const RefreshRate& newRefreshRate = mRefreshRateConfigs.getRefreshRateFromModeId(newModeId);
- frameRateOverridesChanged =
- updateFrameRateOverrides(consideredSignals, newRefreshRate.getFps());
- if (mFeatures.modeId == newModeId) {
+ newMode = calculateRefreshRateModeId(&consideredSignals);
+ frameRateOverridesChanged = updateFrameRateOverrides(consideredSignals, newMode->getFps());
+ if (mFeatures.mode == newMode) {
// We don't need to change the display mode, but we might need to send an event
// about a mode change, since it was suppressed due to a previous idleConsidered
if (!consideredSignals.idle) {
dispatchCachedReportedMode();
}
} else {
- mFeatures.modeId = newModeId;
+ mFeatures.mode = newMode;
refreshRateChanged = true;
}
}
if (refreshRateChanged) {
- const RefreshRate& newRefreshRate = mRefreshRateConfigs.getRefreshRateFromModeId(newModeId);
+ const RefreshRate& newRefreshRate =
+ refreshRateConfigs->getRefreshRateFromModeId(newMode->getId());
mSchedulerCallback.changeRefreshRate(newRefreshRate,
consideredSignals.idle ? ModeEvent::None
@@ -835,35 +845,36 @@ bool Scheduler::handleTimerStateChanged(T* currentState, T newState) {
return consideredSignals.touch;
}
-DisplayModeId Scheduler::calculateRefreshRateModeId(
+DisplayModePtr Scheduler::calculateRefreshRateModeId(
scheduler::RefreshRateConfigs::GlobalSignals* consideredSignals) {
ATRACE_CALL();
if (consideredSignals) *consideredSignals = {};
+ const auto refreshRateConfigs = holdRefreshRateConfigs();
// If Display Power is not in normal operation we want to be in performance mode. When coming
// back to normal mode, a grace period is given with DisplayPowerTimer.
if (mDisplayPowerTimer &&
(!mFeatures.isDisplayPowerStateNormal ||
mFeatures.displayPowerTimer == TimerState::Reset)) {
- return mRefreshRateConfigs.getMaxRefreshRateByPolicy().getModeId();
+ return refreshRateConfigs->getMaxRefreshRateByPolicy().getMode();
}
const bool touchActive = mTouchTimer && mFeatures.touch == TouchState::Active;
- const bool idle = mIdleTimer && mFeatures.idleTimer == TimerState::Expired;
+ const bool idle = mFeatures.idleTimer == TimerState::Expired;
- return mRefreshRateConfigs
- .getBestRefreshRate(mFeatures.contentRequirements, {.touch = touchActive, .idle = idle},
- consideredSignals)
- .getModeId();
+ return refreshRateConfigs
+ ->getBestRefreshRate(mFeatures.contentRequirements,
+ {.touch = touchActive, .idle = idle}, consideredSignals)
+ .getMode();
}
-std::optional<DisplayModeId> Scheduler::getPreferredModeId() {
+DisplayModePtr Scheduler::getPreferredDisplayMode() {
std::lock_guard<std::mutex> lock(mFeatureStateLock);
// Make sure that the default mode ID is first updated, before returned.
- if (mFeatures.modeId.has_value()) {
- mFeatures.modeId = calculateRefreshRateModeId();
+ if (mFeatures.mode) {
+ mFeatures.mode = calculateRefreshRateModeId();
}
- return mFeatures.modeId;
+ return mFeatures.mode;
}
void Scheduler::onNewVsyncPeriodChangeTimeline(const hal::VsyncPeriodChangeTimeline& timeline) {
@@ -899,7 +910,7 @@ void Scheduler::onDisplayRefreshed(nsecs_t timestamp) {
}
}
-void Scheduler::onPrimaryDisplayAreaChanged(uint32_t displayArea) {
+void Scheduler::onActiveDisplayAreaChanged(uint32_t displayArea) {
mLayerHistory->setDisplayArea(displayArea);
}
@@ -908,7 +919,7 @@ void Scheduler::setPreferredRefreshRateForUid(FrameRateOverride frameRateOverrid
return;
}
- std::lock_guard lock(mFrameRateOverridesMutex);
+ std::lock_guard lock(mFrameRateOverridesLock);
if (frameRateOverride.frameRateHz != 0.f) {
mFrameRateOverridesFromBackdoor[frameRateOverride.uid] = Fps(frameRateOverride.frameRateHz);
} else {
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 30a32537ad..bbbbca5b2f 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -72,7 +72,7 @@ public:
using RefreshRate = scheduler::RefreshRateConfigs::RefreshRate;
using ModeEvent = scheduler::RefreshRateConfigEvent;
- Scheduler(const scheduler::RefreshRateConfigs&, ISchedulerCallback&);
+ Scheduler(const std::shared_ptr<scheduler::RefreshRateConfigs>&, ISchedulerCallback&);
~Scheduler();
using ConnectionHandle = scheduler::ConnectionHandle;
@@ -87,15 +87,13 @@ public:
sp<EventThreadConnection> getEventConnection(ConnectionHandle);
void onHotplugReceived(ConnectionHandle, PhysicalDisplayId, bool connected);
- void onPrimaryDisplayModeChanged(ConnectionHandle, PhysicalDisplayId, DisplayModeId,
- nsecs_t vsyncPeriod) EXCLUDES(mFeatureStateLock);
- void onNonPrimaryDisplayModeChanged(ConnectionHandle, PhysicalDisplayId, DisplayModeId,
- nsecs_t vsyncPeriod);
+ void onPrimaryDisplayModeChanged(ConnectionHandle, DisplayModePtr) EXCLUDES(mFeatureStateLock);
+ void onNonPrimaryDisplayModeChanged(ConnectionHandle, DisplayModePtr);
void onScreenAcquired(ConnectionHandle);
void onScreenReleased(ConnectionHandle);
void onFrameRateOverridesChanged(ConnectionHandle, PhysicalDisplayId)
- EXCLUDES(mFrameRateOverridesMutex) EXCLUDES(mConnectionsLock);
+ EXCLUDES(mFrameRateOverridesLock) EXCLUDES(mConnectionsLock);
// Modifies work duration in the event thread.
void setDuration(ConnectionHandle, std::chrono::nanoseconds workDuration,
@@ -116,7 +114,7 @@ public:
// no-op.
// The period is the vsync period from the current display configuration.
void resyncToHardwareVsync(bool makeAvailable, nsecs_t period);
- void resync();
+ void resync() EXCLUDES(mRefreshRateConfigsLock);
// Passes a vsync sample to VsyncController. periodFlushed will be true if
// VsyncController detected that the vsync period changed, and false otherwise.
@@ -127,14 +125,14 @@ public:
// Layers are registered on creation, and unregistered when the weak reference expires.
void registerLayer(Layer*);
- void recordLayerHistory(Layer*, nsecs_t presentTime, LayerHistory::LayerUpdateType updateType);
+ void recordLayerHistory(Layer*, nsecs_t presentTime, LayerHistory::LayerUpdateType updateType)
+ EXCLUDES(mRefreshRateConfigsLock);
void setModeChangePending(bool pending);
void deregisterLayer(Layer*);
// Detects content using layer history, and selects a matching refresh rate.
- void chooseRefreshRateForContent();
+ void chooseRefreshRateForContent() EXCLUDES(mRefreshRateConfigsLock);
- bool isIdleTimerEnabled() const { return mIdleTimer.has_value(); }
void resetIdleTimer();
// Function that resets the touch timer.
@@ -147,7 +145,7 @@ public:
// Returns true if a given vsync timestamp is considered valid vsync
// for a given uid
bool isVsyncValid(nsecs_t expectedVsyncTimestamp, uid_t uid) const
- EXCLUDES(mFrameRateOverridesMutex);
+ EXCLUDES(mFrameRateOverridesLock);
std::chrono::steady_clock::time_point getPreviousVsyncFrom(nsecs_t expectedPresentTime) const;
@@ -156,7 +154,7 @@ public:
void dumpVsync(std::string&) const;
// Get the appropriate refresh for current conditions.
- std::optional<DisplayModeId> getPreferredModeId();
+ DisplayModePtr getPreferredDisplayMode();
// Notifies the scheduler about a refresh rate timeline change.
void onNewVsyncPeriodChangeTimeline(const hal::VsyncPeriodChangeTimeline& timeline);
@@ -165,7 +163,7 @@ public:
void onDisplayRefreshed(nsecs_t timestamp);
// Notifies the scheduler when the display size has changed. Called from SF's main thread
- void onPrimaryDisplayAreaChanged(uint32_t displayArea);
+ void onActiveDisplayAreaChanged(uint32_t displayArea);
size_t getEventThreadConnectionCount(ConnectionHandle handle);
@@ -176,9 +174,45 @@ public:
// Stores the preferred refresh rate that an app should run at.
// FrameRateOverride.refreshRateHz == 0 means no preference.
- void setPreferredRefreshRateForUid(FrameRateOverride) EXCLUDES(mFrameRateOverridesMutex);
+ void setPreferredRefreshRateForUid(FrameRateOverride) EXCLUDES(mFrameRateOverridesLock);
// Retrieves the overridden refresh rate for a given uid.
- std::optional<Fps> getFrameRateOverride(uid_t uid) const EXCLUDES(mFrameRateOverridesMutex);
+ std::optional<Fps> getFrameRateOverride(uid_t uid) const
+ EXCLUDES(mRefreshRateConfigsLock, mFrameRateOverridesLock);
+
+ void setRefreshRateConfigs(std::shared_ptr<scheduler::RefreshRateConfigs> refreshRateConfigs)
+ EXCLUDES(mRefreshRateConfigsLock) {
+ // We need to stop the idle timer on the previous RefreshRateConfigs instance
+ // and cleanup the scheduler's state before we switch to the other RefreshRateConfigs.
+ {
+ std::scoped_lock lock(mRefreshRateConfigsLock);
+ if (mRefreshRateConfigs) mRefreshRateConfigs->stopIdleTimer();
+ }
+ {
+ std::scoped_lock lock(mFeatureStateLock);
+ mFeatures = {};
+ }
+ {
+ std::scoped_lock lock(mRefreshRateConfigsLock);
+ mRefreshRateConfigs = std::move(refreshRateConfigs);
+ mRefreshRateConfigs->setIdleTimerCallbacks(
+ [this] { std::invoke(&Scheduler::idleTimerCallback, this, TimerState::Reset); },
+ [this] {
+ std::invoke(&Scheduler::idleTimerCallback, this, TimerState::Expired);
+ },
+ [this] {
+ std::invoke(&Scheduler::kernelIdleTimerCallback, this, TimerState::Reset);
+ },
+ [this] {
+ std::invoke(&Scheduler::kernelIdleTimerCallback, this, TimerState::Expired);
+ });
+ mRefreshRateConfigs->startIdleTimer();
+ }
+ }
+
+ nsecs_t getVsyncPeriodFromRefreshRateConfigs() const EXCLUDES(mRefreshRateConfigsLock) {
+ std::scoped_lock lock(mRefreshRateConfigsLock);
+ return mRefreshRateConfigs->getCurrentRefreshRate().getVsyncPeriod();
+ }
private:
friend class TestableScheduler;
@@ -190,8 +224,6 @@ private:
enum class TouchState { Inactive, Active };
struct Options {
- // Whether to use idle timer callbacks that support the kernel timer.
- bool supportKernelTimer;
// Whether to use content detection at all.
bool useContentDetection;
};
@@ -203,14 +235,14 @@ private:
};
// Unlike the testing constructor, this creates the VsyncSchedule, LayerHistory, and timers.
- Scheduler(const scheduler::RefreshRateConfigs&, ISchedulerCallback&, Options);
+ Scheduler(const std::shared_ptr<scheduler::RefreshRateConfigs>&, ISchedulerCallback&, Options);
// Used by tests to inject mocks.
- Scheduler(VsyncSchedule, const scheduler::RefreshRateConfigs&, ISchedulerCallback&,
- std::unique_ptr<LayerHistory>, Options);
+ Scheduler(VsyncSchedule, const std::shared_ptr<scheduler::RefreshRateConfigs>&,
+ ISchedulerCallback&, std::unique_ptr<LayerHistory>, Options);
static VsyncSchedule createVsyncSchedule(bool supportKernelIdleTimer);
- static std::unique_ptr<LayerHistory> createLayerHistory(const scheduler::RefreshRateConfigs&);
+ static std::unique_ptr<LayerHistory> createLayerHistory();
// Create a connection on the given EventThread.
ConnectionHandle createConnection(std::unique_ptr<EventThread>);
@@ -218,7 +250,7 @@ private:
EventThread*, ISurfaceComposer::EventRegistrationFlags eventRegistration = {});
// Update feature state machine to given state when corresponding timer resets or expires.
- void kernelIdleTimerCallback(TimerState);
+ void kernelIdleTimerCallback(TimerState) EXCLUDES(mRefreshRateConfigsLock);
void idleTimerCallback(TimerState);
void touchTimerCallback(TimerState);
void displayPowerTimerCallback(TimerState);
@@ -232,18 +264,25 @@ private:
// This function checks whether individual features that are affecting the refresh rate
// selection were initialized, prioritizes them, and calculates the DisplayModeId
// for the suggested refresh rate.
- DisplayModeId calculateRefreshRateModeId(
+ DisplayModePtr calculateRefreshRateModeId(
scheduler::RefreshRateConfigs::GlobalSignals* consideredSignals = nullptr)
REQUIRES(mFeatureStateLock);
- void dispatchCachedReportedMode() REQUIRES(mFeatureStateLock);
+ void dispatchCachedReportedMode() REQUIRES(mFeatureStateLock) EXCLUDES(mRefreshRateConfigsLock);
bool updateFrameRateOverrides(scheduler::RefreshRateConfigs::GlobalSignals consideredSignals,
Fps displayRefreshRate) REQUIRES(mFeatureStateLock)
- EXCLUDES(mFrameRateOverridesMutex);
+ EXCLUDES(mFrameRateOverridesLock);
- impl::EventThread::ThrottleVsyncCallback makeThrottleVsyncCallback() const;
+ impl::EventThread::ThrottleVsyncCallback makeThrottleVsyncCallback() const
+ EXCLUDES(mRefreshRateConfigsLock);
impl::EventThread::GetVsyncPeriodFunction makeGetVsyncPeriodFunction() const;
+ std::shared_ptr<scheduler::RefreshRateConfigs> holdRefreshRateConfigs() const
+ EXCLUDES(mRefreshRateConfigsLock) {
+ std::scoped_lock lock(mRefreshRateConfigsLock);
+ return mRefreshRateConfigs;
+ }
+
// Stores EventThread associated with a given VSyncSource, and an initial EventThreadConnection.
struct Connection {
sp<EventThreadConnection> connection;
@@ -258,7 +297,7 @@ private:
InjectVSyncSource* mVSyncInjector = nullptr;
ConnectionHandle mInjectorConnectionHandle;
- std::mutex mHWVsyncLock;
+ mutable std::mutex mHWVsyncLock;
bool mPrimaryHWVsyncEnabled GUARDED_BY(mHWVsyncLock) = false;
bool mHWVsyncAvailable GUARDED_BY(mHWVsyncLock) = false;
@@ -270,8 +309,6 @@ private:
// Used to choose refresh rate if content detection is enabled.
std::unique_ptr<LayerHistory> mLayerHistory;
- // Timer that records time between requests for next vsync.
- std::optional<scheduler::OneShotTimer> mIdleTimer;
// Timer used to monitor touch events.
std::optional<scheduler::OneShotTimer> mTouchTimer;
// Timer used to monitor display power mode.
@@ -288,7 +325,7 @@ private:
TouchState touch = TouchState::Inactive;
TimerState displayPowerTimer = TimerState::Expired;
- std::optional<DisplayModeId> modeId;
+ DisplayModePtr mode;
LayerHistory::Summary contentRequirements;
bool isDisplayPowerStateNormal = true;
@@ -296,15 +333,15 @@ private:
// Used to cache the last parameters of onPrimaryDisplayModeChanged
struct ModeChangedParams {
ConnectionHandle handle;
- PhysicalDisplayId displayId;
- DisplayModeId modeId;
- nsecs_t vsyncPeriod;
+ DisplayModePtr mode;
};
std::optional<ModeChangedParams> cachedModeChangedParams;
} mFeatures GUARDED_BY(mFeatureStateLock);
- const scheduler::RefreshRateConfigs& mRefreshRateConfigs;
+ mutable std::mutex mRefreshRateConfigsLock;
+ std::shared_ptr<scheduler::RefreshRateConfigs> mRefreshRateConfigs
+ GUARDED_BY(mRefreshRateConfigsLock);
std::mutex mVsyncTimelineLock;
std::optional<hal::VsyncPeriodChangeTimeline> mLastVsyncPeriodChangeTimeline
@@ -315,14 +352,17 @@ private:
// The frame rate override lists need their own mutex as they are being read
// by SurfaceFlinger, Scheduler and EventThread (as a callback) to prevent deadlocks
- mutable std::mutex mFrameRateOverridesMutex;
+ mutable std::mutex mFrameRateOverridesLock;
// mappings between a UID and a preferred refresh rate that this app would
// run at.
scheduler::RefreshRateConfigs::UidToFrameRateOverride mFrameRateOverridesByContent
- GUARDED_BY(mFrameRateOverridesMutex);
+ GUARDED_BY(mFrameRateOverridesLock);
scheduler::RefreshRateConfigs::UidToFrameRateOverride mFrameRateOverridesFromBackdoor
- GUARDED_BY(mFrameRateOverridesMutex);
+ GUARDED_BY(mFrameRateOverridesLock);
+
+ // Keeps track of whether the screen is acquired for debug
+ std::atomic<bool> mScreenAcquired = false;
};
} // namespace android
diff --git a/services/surfaceflinger/Scheduler/VSyncReactor.cpp b/services/surfaceflinger/Scheduler/VSyncReactor.cpp
index 7b5d4626dc..ee973f718a 100644
--- a/services/surfaceflinger/Scheduler/VSyncReactor.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncReactor.cpp
@@ -42,6 +42,7 @@ VSyncReactor::VSyncReactor(std::unique_ptr<Clock> clock, VSyncTracker& tracker,
: mClock(std::move(clock)),
mTracker(tracker),
mPendingLimit(pendingFenceLimit),
+ // TODO(adyabr): change mSupportKernelIdleTimer when the active display changes
mSupportKernelIdleTimer(supportKernelIdleTimer) {}
VSyncReactor::~VSyncReactor() = default;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 893dc2a5d2..ce793ad9c5 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -31,7 +31,6 @@
#include <android/hardware/configstore/1.1/types.h>
#include <android/hardware/power/Boost.h>
#include <android/native_window.h>
-#include <android/os/BnSetInputWindowsListener.h>
#include <android/os/IInputFlinger.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
@@ -115,6 +114,7 @@
#include "FrameTracer/FrameTracer.h"
#include "HdrLayerInfoReporter.h"
#include "Layer.h"
+#include "LayerProtoHelper.h"
#include "LayerRenderArea.h"
#include "LayerVector.h"
#include "MonitoredProducer.h"
@@ -133,6 +133,7 @@
#include "SurfaceInterceptor.h"
#include "TimeStats/TimeStats.h"
#include "TunnelModeEnabledReporter.h"
+#include "WindowInfosListenerInvoker.h"
#include "android-base/parseint.h"
#include "android-base/stringprintf.h"
#include "android-base/strings.h"
@@ -146,6 +147,13 @@
return (expr); \
}()
+#define MAIN_THREAD_GUARD(expr) \
+ [&] { \
+ LOG_FATAL_IF(std::this_thread::get_id() != mMainThreadId); \
+ MainThreadScopedGuard lock(SF_MAIN_THREAD); \
+ return (expr); \
+ }()
+
#undef NO_THREAD_SAFETY_ANALYSIS
#define NO_THREAD_SAFETY_ANALYSIS \
_Pragma("GCC error \"Prefer MAIN_THREAD macros or {Conditional,Timed,Unnecessary}Lock.\"")
@@ -160,6 +168,8 @@ using namespace android::sysprop;
using android::hardware::power::Boost;
using base::StringAppendF;
+using gui::IWindowInfosListener;
+using gui::WindowInfo;
using ui::ColorMode;
using ui::Dataspace;
using ui::DisplayPrimaries;
@@ -265,23 +275,42 @@ enum Permission {
ROTATE_SURFACE_FLINGER = 0x2,
};
-} // namespace anonymous
+struct IdleTimerConfig {
+ int32_t timeoutMs;
+ bool supportKernelIdleTimer;
+};
+
+IdleTimerConfig getIdleTimerConfiguration(DisplayId displayId) {
+ // TODO(adyabr): use ro.surface_flinger.* namespace
-struct SetInputWindowsListener : os::BnSetInputWindowsListener {
- explicit SetInputWindowsListener(std::function<void()> listenerCb) : mListenerCb(listenerCb) {}
+ const auto displayIdleTimerMsKey = [displayId] {
+ std::stringstream ss;
+ ss << "debug.sf.set_idle_timer_ms_" << displayId.value;
+ return ss.str();
+ }();
- binder::Status onSetInputWindowsFinished() override;
+ const auto displaySupportKernelIdleTimerKey = [displayId] {
+ std::stringstream ss;
+ ss << "debug.sf.support_kernel_idle_timer_" << displayId.value;
+ return ss.str();
+ }();
- std::function<void()> mListenerCb;
-};
+ const int32_t displayIdleTimerMs = base::GetIntProperty(displayIdleTimerMsKey, 0);
+ const auto displaySupportKernelIdleTimer =
+ base::GetBoolProperty(displaySupportKernelIdleTimerKey, false);
-binder::Status SetInputWindowsListener::onSetInputWindowsFinished() {
- if (mListenerCb != nullptr) {
- mListenerCb();
+ if (displayIdleTimerMs > 0) {
+ return {displayIdleTimerMs, displaySupportKernelIdleTimer};
}
- return binder::Status::ok();
+
+ const int32_t setIdleTimerMs = base::GetIntProperty("debug.sf.set_idle_timer_ms", 0);
+ const int32_t millis = setIdleTimerMs ? setIdleTimerMs : sysprop::set_idle_timer_ms(0);
+
+ return {millis, sysprop::support_kernel_idle_timer(false)};
}
+} // namespace anonymous
+
// ---------------------------------------------------------------------------
const String16 sHardwareTest("android.permission.HARDWARE_TEST");
@@ -347,10 +376,9 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory, SkipInitializationTag)
mTunnelModeEnabledReporter(new TunnelModeEnabledReporter()),
mInternalDisplayDensity(getDensityFromProperty("ro.sf.lcd_density", true)),
mEmulatedDisplayDensity(getDensityFromProperty("qemu.sf.lcd_density", false)),
- mPowerAdvisor(*this) {
+ mPowerAdvisor(*this),
+ mWindowInfosListenerInvoker(new WindowInfosListenerInvoker(this)) {
ALOGI("Using HWComposer service: %s", mHwcServiceName.c_str());
-
- mSetInputWindowsListener = new SetInputWindowsListener([&]() { setInputWindowsFinished(); });
}
SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipInitialization) {
@@ -475,9 +503,6 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipI
useFrameRateApi = use_frame_rate_api(true);
- mKernelIdleTimerEnabled = mSupportKernelIdleTimer = sysprop::support_kernel_idle_timer(false);
- base::SetProperty(KERNEL_IDLE_TIMER_PROP, mKernelIdleTimerEnabled ? "true" : "false");
-
mRefreshRateOverlaySpinner = property_get_bool("sf.debug.show_refresh_rate_overlay_spinner", 0);
// Debug property overrides ro. property
@@ -590,19 +615,11 @@ void SurfaceFlinger::enableHalVirtualDisplays(bool enable) {
}
}
-VirtualDisplayId SurfaceFlinger::acquireVirtualDisplay(ui::Size resolution, ui::PixelFormat format,
- ui::LayerStack layerStack) {
+VirtualDisplayId SurfaceFlinger::acquireVirtualDisplay(ui::Size resolution,
+ ui::PixelFormat format) {
if (auto& generator = mVirtualDisplayIdGenerators.hal) {
if (const auto id = generator->generateId()) {
- std::optional<PhysicalDisplayId> mirror;
-
- if (const auto display = findDisplay([layerStack](const auto& display) {
- return !display.isVirtual() && display.getLayerStack() == layerStack;
- })) {
- mirror = display->getPhysicalId();
- }
-
- if (getHwComposer().allocateVirtualDisplay(*id, resolution, &format, mirror)) {
+ if (getHwComposer().allocateVirtualDisplay(*id, resolution, &format)) {
return *id;
}
@@ -632,20 +649,18 @@ void SurfaceFlinger::releaseVirtualDisplay(VirtualDisplayId displayId) {
mVirtualDisplayIdGenerators.gpu.releaseId(*id);
}
-std::vector<PhysicalDisplayId> SurfaceFlinger::getPhysicalDisplayIds() const {
- Mutex::Autolock lock(mStateLock);
-
- const auto internalDisplayId = getInternalDisplayIdLocked();
- if (!internalDisplayId) {
+std::vector<PhysicalDisplayId> SurfaceFlinger::getPhysicalDisplayIdsLocked() const {
+ const auto display = getDefaultDisplayDeviceLocked();
+ if (!display) {
return {};
}
std::vector<PhysicalDisplayId> displayIds;
displayIds.reserve(mPhysicalDisplayTokens.size());
- displayIds.push_back(*internalDisplayId);
+ displayIds.push_back(display->getPhysicalId());
for (const auto& [id, token] : mPhysicalDisplayTokens) {
- if (id != *internalDisplayId) {
+ if (id != display->getPhysicalId()) {
displayIds.push_back(id);
}
}
@@ -739,7 +754,7 @@ void SurfaceFlinger::bootFinished() {
mBootStage = BootStage::FINISHED;
if (property_get_bool("sf.debug.show_refresh_rate_overlay", false)) {
- enableRefreshRateOverlay(true);
+ ON_MAIN_THREAD(enableRefreshRateOverlay(true));
}
}));
}
@@ -803,6 +818,8 @@ void SurfaceFlinger::init() {
? renderengine::RenderEngine::ContextPriority::REALTIME
: renderengine::RenderEngine::ContextPriority::MEDIUM)
.build()));
+ mMaxRenderTargetSize =
+ std::min(getRenderEngine().getMaxTextureSize(), getRenderEngine().getMaxViewportDims());
// Set SF main policy after initializing RenderEngine which has its own policy.
if (!SetTaskProfiles(0, {"SFMainPolicy"})) {
@@ -848,7 +865,7 @@ void SurfaceFlinger::init() {
}
}
- getRenderEngine().onPrimaryDisplaySizeChanged(display->getSize());
+ onActiveDisplaySizeChanged(display);
// Inform native graphics APIs whether the present timestamp is supported:
@@ -890,14 +907,6 @@ void SurfaceFlinger::startBootAnim() {
}
}
-size_t SurfaceFlinger::getMaxTextureSize() const {
- return getRenderEngine().getMaxTextureSize();
-}
-
-size_t SurfaceFlinger::getMaxViewportDims() const {
- return getRenderEngine().getMaxViewportDims();
-}
-
// ----------------------------------------------------------------------------
bool SurfaceFlinger::authenticateSurfaceTexture(
@@ -1086,36 +1095,28 @@ status_t SurfaceFlinger::getDisplayStats(const sp<IBinder>&, DisplayStatInfo* st
void SurfaceFlinger::setDesiredActiveMode(const ActiveModeInfo& info) {
ATRACE_CALL();
- auto refreshRate = mRefreshRateConfigs->getRefreshRateFromModeId(info.modeId);
- ALOGV("%s(%s)", __func__, refreshRate.getName().c_str());
-
- std::lock_guard<std::mutex> lock(mActiveModeLock);
- if (mDesiredActiveModeChanged) {
- // If a mode change is pending, just cache the latest request in mDesiredActiveMode
- const Scheduler::ModeEvent prevConfig = mDesiredActiveMode.event;
- mDesiredActiveMode = info;
- mDesiredActiveMode.event = mDesiredActiveMode.event | prevConfig;
- } else {
- // Check if we are already at the desired mode
- const auto display = getDefaultDisplayDeviceLocked();
- if (!display || display->getActiveMode()->getId() == refreshRate.getModeId()) {
- return;
- }
- // Initiate a mode change.
- mDesiredActiveModeChanged = true;
- mDesiredActiveMode = info;
+ if (!info.mode) {
+ ALOGW("requested display mode is null");
+ return;
+ }
+ auto display = getDisplayDeviceLocked(info.mode->getPhysicalDisplayId());
+ if (!display) {
+ ALOGW("%s: display is no longer valid", __func__);
+ return;
+ }
+ if (display->setDesiredActiveMode(info)) {
// This will trigger HWC refresh without resetting the idle timer.
repaintEverythingForHWC();
// Start receiving vsync samples now, so that we can detect a period
// switch.
- mScheduler->resyncToHardwareVsync(true, refreshRate.getVsyncPeriod());
+ mScheduler->resyncToHardwareVsync(true, info.mode->getVsyncPeriod());
// As we called to set period, we will call to onRefreshRateChangeCompleted once
// VsyncController model is locked.
modulateVsync(&VsyncModulator::onRefreshRateChangeInitiated);
- updatePhaseConfiguration(refreshRate.getFps());
+ updatePhaseConfiguration(info.mode->getFps());
mScheduler->setModeChangePending(true);
}
}
@@ -1149,7 +1150,7 @@ status_t SurfaceFlinger::setActiveMode(const sp<IBinder>& displayToken, int mode
const auto fps = mode->getFps();
// Keep the old switching type.
const auto allowGroupSwitching =
- mRefreshRateConfigs->getCurrentPolicy().allowGroupSwitching;
+ display->refreshRateConfigs().getCurrentPolicy().allowGroupSwitching;
const scheduler::RefreshRateConfigs::Policy policy{mode->getId(),
allowGroupSwitching,
{fps, fps}};
@@ -1169,63 +1170,49 @@ void SurfaceFlinger::setActiveModeInternal() {
return;
}
- const auto upcomingMode = display->getMode(mUpcomingActiveMode.modeId);
- if (!upcomingMode) {
- ALOGW("Upcoming active mode is no longer supported. Mode ID = %d",
- mUpcomingActiveMode.modeId.value());
- // TODO(b/159590486) Handle the error better. Some parts of SurfaceFlinger may
- // have been already updated with the upcoming active mode.
+ const auto upcomingModeInfo = MAIN_THREAD_GUARD(display->getUpcomingActiveMode());
+ if (!upcomingModeInfo.mode) {
+ // There is no pending mode change. This can happen if the active
+ // display changed and the mode change happened on a different display.
return;
}
- if (display->getActiveMode()->getSize() != upcomingMode->getSize()) {
+ if (display->getActiveMode()->getSize() != upcomingModeInfo.mode->getSize()) {
auto& state = mCurrentState.displays.editValueFor(display->getDisplayToken());
// We need to generate new sequenceId in order to recreate the display (and this
// way the framebuffer).
state.sequenceId = DisplayDeviceState{}.sequenceId;
- state.physical->activeMode = upcomingMode;
+ state.physical->activeMode = upcomingModeInfo.mode;
processDisplayChangesLocked();
// processDisplayChangesLocked will update all necessary components so we're done here.
return;
}
- std::lock_guard<std::mutex> lock(mActiveModeLock);
- mRefreshRateConfigs->setCurrentModeId(mUpcomingActiveMode.modeId);
- display->setActiveMode(mUpcomingActiveMode.modeId);
-
- const Fps refreshRate = upcomingMode->getFps();
+ // We just created this display so we can call even if we are not on
+ // the main thread
+ MainThreadScopedGuard fakeMainThreadGuard(SF_MAIN_THREAD);
+ display->setActiveMode(upcomingModeInfo.mode->getId());
+ const Fps refreshRate = upcomingModeInfo.mode->getFps();
mRefreshRateStats->setRefreshRate(refreshRate);
-
updatePhaseConfiguration(refreshRate);
- ATRACE_INT("ActiveConfigFPS", refreshRate.getValue());
- if (mRefreshRateOverlay) {
- mRefreshRateOverlay->changeRefreshRate(upcomingMode->getFps());
- }
-
- if (mUpcomingActiveMode.event != Scheduler::ModeEvent::None) {
- const nsecs_t vsyncPeriod = refreshRate.getPeriodNsecs();
- const auto physicalId = display->getPhysicalId();
- mScheduler->onPrimaryDisplayModeChanged(mAppConnectionHandle, physicalId,
- mUpcomingActiveMode.modeId, vsyncPeriod);
+ if (upcomingModeInfo.event != Scheduler::ModeEvent::None) {
+ mScheduler->onPrimaryDisplayModeChanged(mAppConnectionHandle, upcomingModeInfo.mode);
}
}
-void SurfaceFlinger::clearDesiredActiveModeState() {
- std::lock_guard<std::mutex> lock(mActiveModeLock);
- mDesiredActiveMode.event = Scheduler::ModeEvent::None;
- mDesiredActiveModeChanged = false;
- mScheduler->setModeChangePending(false);
+void SurfaceFlinger::clearDesiredActiveModeState(const sp<DisplayDevice>& display) {
+ display->clearDesiredActiveModeState();
+ if (isDisplayActiveLocked(display)) {
+ mScheduler->setModeChangePending(false);
+ }
}
-void SurfaceFlinger::desiredActiveModeChangeDone() {
- const auto modeId = getDesiredActiveMode()->modeId;
-
- clearDesiredActiveModeState();
-
- const auto refreshRate = getDefaultDisplayDeviceLocked()->getMode(modeId)->getFps();
+void SurfaceFlinger::desiredActiveModeChangeDone(const sp<DisplayDevice>& display) {
+ const auto refreshRate = display->getDesiredActiveMode()->mode->getFps();
+ clearDesiredActiveModeState(display);
mScheduler->resyncToHardwareVsync(true, refreshRate.getPeriodNsecs());
updatePhaseConfiguration(refreshRate);
}
@@ -1233,63 +1220,75 @@ void SurfaceFlinger::desiredActiveModeChangeDone() {
void SurfaceFlinger::performSetActiveMode() {
ATRACE_CALL();
ALOGV("%s", __FUNCTION__);
- // Store the local variable to release the lock.
- const auto desiredActiveMode = getDesiredActiveMode();
- if (!desiredActiveMode) {
- // No desired active mode pending to be applied
- return;
- }
- const auto display = getDefaultDisplayDeviceLocked();
- const auto desiredMode = display->getMode(desiredActiveMode->modeId);
- if (!desiredMode) {
- ALOGW("Desired display mode is no longer supported. Mode ID = %d",
- desiredActiveMode->modeId.value());
- clearDesiredActiveModeState();
- return;
- }
- const auto refreshRate = desiredMode->getFps();
- ALOGV("%s changing active mode to %d(%s)", __FUNCTION__, desiredMode->getId().value(),
- to_string(refreshRate).c_str());
+ for (const auto& iter : mDisplays) {
+ const auto& display = iter.second;
+ if (!display || !display->isInternal()) {
+ continue;
+ }
- if (!display || display->getActiveMode()->getId() == desiredActiveMode->modeId) {
- // display is not valid or we are already in the requested mode
- // on both cases there is nothing left to do
- desiredActiveModeChangeDone();
- return;
- }
+ // Store the local variable to release the lock.
+ const auto desiredActiveMode = display->getDesiredActiveMode();
+ if (!desiredActiveMode) {
+ // No desired active mode pending to be applied
+ continue;
+ }
- // Desired active mode was set, it is different than the mode currently in use, however
- // allowed modes might have changed by the time we process the refresh.
- // Make sure the desired mode is still allowed
- if (!isDisplayModeAllowed(desiredActiveMode->modeId)) {
- desiredActiveModeChangeDone();
- return;
- }
+ if (!isDisplayActiveLocked(display)) {
+ // display is no longer the active display, so abort the mode change
+ clearDesiredActiveModeState(display);
+ continue;
+ }
- mUpcomingActiveMode = *desiredActiveMode;
+ const auto desiredMode = display->getMode(desiredActiveMode->mode->getId());
+ if (!desiredMode) {
+ ALOGW("Desired display mode is no longer supported. Mode ID = %d",
+ desiredActiveMode->mode->getId().value());
+ clearDesiredActiveModeState(display);
+ continue;
+ }
- ATRACE_INT("ActiveModeFPS_HWC", refreshRate.getValue());
+ const auto refreshRate = desiredMode->getFps();
+ ALOGV("%s changing active mode to %d(%s) for display %s", __func__,
+ desiredMode->getId().value(), to_string(refreshRate).c_str(),
+ to_string(display->getId()).c_str());
- // TODO(b/142753666) use constrains
- hal::VsyncPeriodChangeConstraints constraints;
- constraints.desiredTimeNanos = systemTime();
- constraints.seamlessRequired = false;
+ if (display->getActiveMode()->getId() == desiredActiveMode->mode->getId()) {
+ // display is not valid or we are already in the requested mode
+ // on both cases there is nothing left to do
+ desiredActiveModeChangeDone(display);
+ continue;
+ }
- hal::VsyncPeriodChangeTimeline outTimeline;
- const auto status =
- display->initiateModeChange(mUpcomingActiveMode.modeId, constraints, &outTimeline);
- if (status != NO_ERROR) {
- // initiateModeChange may fail if a hotplug event is just about
- // to be sent. We just log the error in this case.
- ALOGW("initiateModeChange failed: %d", status);
- return;
- }
+ // Desired active mode was set, it is different than the mode currently in use, however
+ // allowed modes might have changed by the time we process the refresh.
+ // Make sure the desired mode is still allowed
+ const auto displayModeAllowed =
+ display->refreshRateConfigs().isModeAllowed(desiredActiveMode->mode->getId());
+ if (!displayModeAllowed) {
+ desiredActiveModeChangeDone(display);
+ continue;
+ }
- mScheduler->onNewVsyncPeriodChangeTimeline(outTimeline);
+ // TODO(b/142753666) use constrains
+ hal::VsyncPeriodChangeConstraints constraints;
+ constraints.desiredTimeNanos = systemTime();
+ constraints.seamlessRequired = false;
+ hal::VsyncPeriodChangeTimeline outTimeline;
+
+ const auto status = MAIN_THREAD_GUARD(
+ display->initiateModeChange(*desiredActiveMode, constraints, &outTimeline));
+ if (status != NO_ERROR) {
+ // initiateModeChange may fail if a hotplug event is just about
+ // to be sent. We just log the error in this case.
+ ALOGW("initiateModeChange failed: %d", status);
+ continue;
+ }
+ mScheduler->onNewVsyncPeriodChangeTimeline(outTimeline);
- // Scheduler will submit an empty frame to HWC if needed.
- mSetActiveModePending = true;
+ // Scheduler will submit an empty frame to HWC if needed.
+ mSetActiveModePending = true;
+ }
}
void SurfaceFlinger::disableExpensiveRendering() {
@@ -1731,10 +1730,10 @@ void SurfaceFlinger::onComposerHalVsync(hal::HWDisplayId hwcDisplayId, int64_t t
ATRACE_CALL();
Mutex::Autolock lock(mStateLock);
-
- if (const auto displayId = getHwComposer().toPhysicalDisplayId(hwcDisplayId)) {
- auto token = getPhysicalDisplayTokenLocked(*displayId);
- auto display = getDisplayDeviceLocked(token);
+ const auto displayId = getHwComposer().toPhysicalDisplayId(hwcDisplayId);
+ if (displayId) {
+ const auto token = getPhysicalDisplayTokenLocked(*displayId);
+ const auto display = getDisplayDeviceLocked(token);
display->onVsync(timestamp);
}
@@ -1742,8 +1741,10 @@ void SurfaceFlinger::onComposerHalVsync(hal::HWDisplayId hwcDisplayId, int64_t t
return;
}
- if (hwcDisplayId != getHwComposer().getInternalHwcDisplayId()) {
- // For now, we don't do anything with external display vsyncs.
+ const bool isActiveDisplay =
+ displayId && getPhysicalDisplayTokenLocked(*displayId) == mActiveDisplayToken;
+ if (!isActiveDisplay) {
+ // For now, we don't do anything with non active display vsyncs.
return;
}
@@ -1759,10 +1760,6 @@ void SurfaceFlinger::getCompositorTiming(CompositorTiming* compositorTiming) {
*compositorTiming = getBE().mCompositorTiming;
}
-bool SurfaceFlinger::isDisplayModeAllowed(DisplayModeId modeId) const {
- return mRefreshRateConfigs->isModeAllowed(modeId);
-}
-
void SurfaceFlinger::changeRefreshRateLocked(const RefreshRate& refreshRate,
Scheduler::ModeEvent event) {
const auto display = getDefaultDisplayDeviceLocked();
@@ -1772,13 +1769,13 @@ void SurfaceFlinger::changeRefreshRateLocked(const RefreshRate& refreshRate,
ATRACE_CALL();
// Don't do any updating if the current fps is the same as the new one.
- if (!isDisplayModeAllowed(refreshRate.getModeId())) {
+ if (!display->refreshRateConfigs().isModeAllowed(refreshRate.getModeId())) {
ALOGV("Skipping mode %d as it is not part of allowed modes",
refreshRate.getModeId().value());
return;
}
- setDesiredActiveMode({refreshRate.getModeId(), event});
+ setDesiredActiveMode({refreshRate.getMode(), event});
}
void SurfaceFlinger::onComposerHalHotplug(hal::HWDisplayId hwcDisplayId,
@@ -1827,7 +1824,7 @@ void SurfaceFlinger::setVsyncEnabled(bool enabled) {
if (const auto display = getDefaultDisplayDeviceLocked();
display && display->isPoweredOn()) {
- getHwComposer().setVsyncEnabled(display->getPhysicalId(), mHWCVsyncPendingState);
+ setHWCVsyncEnabled(display->getPhysicalId(), mHWCVsyncPendingState);
}
}));
}
@@ -1979,8 +1976,13 @@ void SurfaceFlinger::onMessageInvalidate(int64_t vsyncId, nsecs_t expectedVSyncT
}
if (mRefreshRateOverlaySpinner) {
- if (Mutex::Autolock lock(mStateLock); mRefreshRateOverlay) {
- mRefreshRateOverlay->onInvalidate();
+ if (Mutex::Autolock lock(mStateLock);
+ const auto display = getDefaultDisplayDeviceLocked()) {
+ if (display) {
+ display->onInvalidate();
+ } else {
+ ALOGW("%s: default display is null", __func__);
+ }
}
}
@@ -2366,7 +2368,7 @@ void SurfaceFlinger::postComposition() {
mTransactionCallbackInvoker.addPresentFence(mPreviousPresentFences[0].fence);
mTransactionCallbackInvoker.sendCallbacks();
- if (display && display->isPrimary() && display->getPowerMode() == hal::PowerMode::ON &&
+ if (display && display->isInternal() && display->getPowerMode() == hal::PowerMode::ON &&
mPreviousPresentFences[0].fenceTime->isValid()) {
mScheduler->addPresentFence(mPreviousPresentFences[0].fenceTime);
}
@@ -2457,24 +2459,34 @@ void SurfaceFlinger::postComposition() {
}
}
-FloatRect SurfaceFlinger::getLayerClipBoundsForDisplay(const DisplayDevice& displayDevice) const {
- return displayDevice.getLayerStackSpaceRect().toFloatRect();
-}
-
-void SurfaceFlinger::computeLayerBounds() {
+FloatRect SurfaceFlinger::getMaxDisplayBounds() {
+ // Find the largest width and height among all the displays.
+ int32_t maxDisplayWidth = 0;
+ int32_t maxDisplayHeight = 0;
for (const auto& pair : ON_MAIN_THREAD(mDisplays)) {
const auto& displayDevice = pair.second;
- const auto display = displayDevice->getCompositionDisplay();
- for (const auto& layer : mDrawingState.layersSortedByZ) {
- // only consider the layers on the given layer stack
- if (!display->belongsInOutput(layer->getLayerStack(), layer->getPrimaryDisplayOnly())) {
- continue;
- }
-
- layer->computeBounds(getLayerClipBoundsForDisplay(*displayDevice), ui::Transform(),
- 0.f /* shadowRadius */);
+ int32_t width = displayDevice->getWidth();
+ int32_t height = displayDevice->getHeight();
+ if (width > maxDisplayWidth) {
+ maxDisplayWidth = width;
+ }
+ if (height > maxDisplayHeight) {
+ maxDisplayHeight = height;
}
}
+
+ // Ignore display bounds for now since they will be computed later. Use a large Rect bound
+ // to ensure it's bigger than an actual display will be.
+ FloatRect maxBounds = FloatRect(-maxDisplayWidth * 10, -maxDisplayHeight * 10,
+ maxDisplayWidth * 10, maxDisplayHeight * 10);
+ return maxBounds;
+}
+
+void SurfaceFlinger::computeLayerBounds() {
+ FloatRect maxBounds = getMaxDisplayBounds();
+ for (const auto& layer : mDrawingState.layersSortedByZ) {
+ layer->computeBounds(maxBounds, ui::Transform(), 0.f /* shadowRadius */);
+ }
}
void SurfaceFlinger::postFrame() {
@@ -2504,7 +2516,6 @@ void SurfaceFlinger::handleTransaction(uint32_t transactionFlags) {
// We call getTransactionFlags(), which will also clear the flags,
// with mStateLock held to guarantee that mCurrentState won't change
// until the transaction is committed.
-
modulateVsync(&VsyncModulator::onTransactionCommit);
transactionFlags = getTransactionFlags(eTransactionMask);
handleTransactionLocked(transactionFlags);
@@ -2555,6 +2566,7 @@ void SurfaceFlinger::loadDisplayModes(PhysicalDisplayId displayId, DisplayModes&
for (const auto& hwcMode : hwcModes) {
newModes.push_back(DisplayMode::Builder(hwcMode.hwcId)
.setId(DisplayModeId{nextModeId++})
+ .setPhysicalDisplayId(displayId)
.setWidth(hwcMode.width)
.setHeight(hwcMode.height)
.setVsyncPeriod(hwcMode.vsyncPeriod)
@@ -2616,11 +2628,6 @@ void SurfaceFlinger::processDisplayHotplugEventsLocked() {
sp<IBinder> token = new BBinder();
mCurrentState.displays.add(token, state);
mPhysicalDisplayTokens.emplace(displayId, std::move(token));
-
- if (event.hwcDisplayId == getHwComposer().getInternalHwcDisplayId()) {
- initScheduler(state);
- }
-
mInterceptor->saveDisplayCreation(state);
} else {
ALOGV("Recreating display %s", to_string(displayId).c_str());
@@ -2675,6 +2682,18 @@ sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal(
if (const auto& physical = state.physical) {
creationArgs.connectionType = physical->type;
creationArgs.supportedModes = physical->supportedModes;
+ creationArgs.activeModeId = physical->activeMode->getId();
+ const auto [idleTimerTimeoutMs, supportKernelIdleTimer] =
+ getIdleTimerConfiguration(compositionDisplay->getId());
+ scheduler::RefreshRateConfigs::Config config =
+ {.enableFrameRateOverride = android::sysprop::enable_frame_rate_override(false),
+ .frameRateMultipleThreshold =
+ base::GetIntProperty("debug.sf.frame_rate_multiple_threshold", 0),
+ .idleTimerTimeoutMs = idleTimerTimeoutMs,
+ .supportKernelIdleTimer = supportKernelIdleTimer};
+ creationArgs.refreshRateConfigs =
+ std::make_shared<scheduler::RefreshRateConfigs>(creationArgs.supportedModes,
+ creationArgs.activeModeId, config);
}
if (const auto id = PhysicalDisplayId::tryCast(compositionDisplay->getId())) {
@@ -2731,7 +2750,7 @@ sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal(
RenderIntent::COLORIMETRIC,
Dataspace::UNKNOWN});
if (!state.isVirtual()) {
- display->setActiveMode(state.physical->activeMode->getId());
+ MAIN_THREAD_GUARD(display->setActiveMode(state.physical->activeMode->getId()));
display->setDeviceProductInfo(state.physical->deviceProductInfo);
}
@@ -2771,7 +2790,7 @@ void SurfaceFlinger::processDisplayAdded(const wp<IBinder>& displayToken,
builder.setId(physical->id);
builder.setConnectionType(physical->type);
} else {
- builder.setId(acquireVirtualDisplay(resolution, pixelFormat, state.layerStack));
+ builder.setId(acquireVirtualDisplay(resolution, pixelFormat));
}
builder.setPixels(resolution);
@@ -2813,14 +2832,12 @@ void SurfaceFlinger::processDisplayAdded(const wp<IBinder>& displayToken,
const auto display = setupNewDisplayDeviceInternal(displayToken, std::move(compositionDisplay),
state, displaySurface, producer);
mDisplays.emplace(displayToken, display);
+ if (display->isPrimary()) {
+ initScheduler(display);
+ }
if (!state.isVirtual()) {
dispatchDisplayHotplugEvent(display->getPhysicalId(), true);
}
-
- if (display->isPrimary()) {
- mScheduler->onPrimaryDisplayAreaChanged(display->getWidth() * display->getHeight());
- getRenderEngine().onPrimaryDisplaySizeChanged(display->getSize());
- }
}
void SurfaceFlinger::processDisplayRemoved(const wp<IBinder>& displayToken) {
@@ -2885,16 +2902,7 @@ void SurfaceFlinger::processDisplayChanged(const wp<IBinder>& displayToken,
// TODO(b/175678251) Call a listener instead.
if (currentState.physical->hwcDisplayId == getHwComposer().getInternalHwcDisplayId()) {
- mRefreshRateConfigs->updateDisplayModes(currentState.physical->supportedModes,
- currentState.physical->activeMode->getId());
- mVsyncConfiguration->reset();
- const Fps refreshRate = currentState.physical->activeMode->getFps();
- updatePhaseConfiguration(refreshRate);
- mRefreshRateStats->setRefreshRate(refreshRate);
-
- if (mRefreshRateOverlay) {
- mRefreshRateOverlay->reset();
- }
+ updateInternalDisplayVsyncLocked(display);
}
}
return;
@@ -2904,29 +2912,34 @@ void SurfaceFlinger::processDisplayChanged(const wp<IBinder>& displayToken,
if (currentState.layerStack != drawingState.layerStack) {
display->setLayerStack(currentState.layerStack);
}
+ if (currentState.flags != drawingState.flags) {
+ display->setFlags(currentState.flags);
+ }
if ((currentState.orientation != drawingState.orientation) ||
(currentState.layerStackSpaceRect != drawingState.layerStackSpaceRect) ||
(currentState.orientedDisplaySpaceRect != drawingState.orientedDisplaySpaceRect)) {
display->setProjection(currentState.orientation, currentState.layerStackSpaceRect,
currentState.orientedDisplaySpaceRect);
- if (display->isPrimary()) {
- mDefaultDisplayTransformHint = display->getTransformHint();
+ if (isDisplayActiveLocked(display)) {
+ mActiveDisplayTransformHint = display->getTransformHint();
}
}
if (currentState.width != drawingState.width ||
currentState.height != drawingState.height) {
display->setDisplaySize(currentState.width, currentState.height);
- if (display->isPrimary()) {
- mScheduler->onPrimaryDisplayAreaChanged(currentState.width * currentState.height);
- }
-
- if (mRefreshRateOverlay) {
- mRefreshRateOverlay->setViewport(display->getSize());
+ if (isDisplayActiveLocked(display)) {
+ onActiveDisplaySizeChanged(display);
}
}
}
}
+void SurfaceFlinger::updateInternalDisplayVsyncLocked(const sp<DisplayDevice>& activeDisplay) {
+ mVsyncConfiguration->reset();
+ const Fps refreshRate = activeDisplay->refreshRateConfigs().getCurrentRefreshRate().getFps();
+ updatePhaseConfiguration(refreshRate);
+ mRefreshRateStats->setRefreshRate(refreshRate);
+}
void SurfaceFlinger::processDisplayChangesLocked() {
// here we take advantage of Vector's copy-on-write semantics to
@@ -3088,11 +3101,11 @@ void SurfaceFlinger::updateInputFlinger() {
if (mVisibleRegionsDirty || mInputInfoChanged) {
mInputInfoChanged = false;
- updateInputWindowInfo();
+ notifyWindowInfos();
} else if (mInputWindowCommands.syncInputWindows) {
// If the caller requested to sync input windows, but there are no
// changes to input windows, notify immediately.
- setInputWindowsFinished();
+ windowInfosReported();
}
for (const auto& focusRequest : mInputWindowCommands.focusRequests) {
@@ -3107,31 +3120,20 @@ bool enablePerWindowInputRotation() {
return value;
}
-void SurfaceFlinger::updateInputWindowInfo() {
- std::vector<InputWindowInfo> inputInfos;
+void SurfaceFlinger::notifyWindowInfos() {
+ std::vector<WindowInfo> windowInfos;
mDrawingState.traverseInReverseZOrder([&](Layer* layer) {
if (!layer->needsInputInfo()) return;
- sp<DisplayDevice> display;
- if (enablePerWindowInputRotation()) {
- for (const auto& pair : ON_MAIN_THREAD(mDisplays)) {
- const auto& displayDevice = pair.second;
- if (!displayDevice->getCompositionDisplay()
- ->belongsInOutput(layer->getLayerStack(),
- layer->getPrimaryDisplayOnly())) {
- continue;
- }
- display = displayDevice;
- }
- }
+ sp<DisplayDevice> display = enablePerWindowInputRotation()
+ ? ON_MAIN_THREAD(getDisplayWithInputByLayer(layer))
+ : nullptr;
// When calculating the screen bounds we ignore the transparent region since it may
// result in an unwanted offset.
- inputInfos.push_back(layer->fillInputInfo(display));
+ windowInfos.push_back(layer->fillInputInfo(display));
});
-
- mInputFlinger->setInputWindows(inputInfos,
- mInputWindowCommands.syncInputWindows ? mSetInputWindowsListener
- : nullptr);
+ mWindowInfosListenerInvoker->windowInfosChanged(windowInfos,
+ mInputWindowCommands.syncInputWindows);
}
void SurfaceFlinger::updateCursorAsync() {
@@ -3163,24 +3165,16 @@ void SurfaceFlinger::triggerOnFrameRateOverridesChanged() {
mScheduler->onFrameRateOverridesChanged(mAppConnectionHandle, displayId);
}
-void SurfaceFlinger::initScheduler(const DisplayDeviceState& displayState) {
+void SurfaceFlinger::initScheduler(const sp<DisplayDevice>& display) {
if (mScheduler) {
- // In practice it's not allowed to hotplug in/out the primary display once it's been
- // connected during startup, but some tests do it, so just warn and return.
- ALOGW("Can't re-init scheduler");
+ // If the scheduler is already initialized, this means that we received
+ // a hotplug(connected) on the primary display. In that case we should
+ // update the scheduler with the most recent display information.
+ ALOGW("Scheduler already initialized, updating instead");
+ mScheduler->setRefreshRateConfigs(display->holdRefreshRateConfigs());
return;
}
- const auto displayId = displayState.physical->id;
- scheduler::RefreshRateConfigs::Config config =
- {.enableFrameRateOverride = android::sysprop::enable_frame_rate_override(false),
- .frameRateMultipleThreshold =
- base::GetIntProperty("debug.sf.frame_rate_multiple_threshold", 0)};
- mRefreshRateConfigs =
- std::make_unique<scheduler::RefreshRateConfigs>(displayState.physical->supportedModes,
- displayState.physical->activeMode
- ->getId(),
- config);
- const auto currRefreshRate = displayState.physical->activeMode->getFps();
+ const auto currRefreshRate = display->getActiveMode()->getFps();
mRefreshRateStats = std::make_unique<scheduler::RefreshRateStats>(*mTimeStats, currRefreshRate,
hal::PowerMode::OFF);
@@ -3188,7 +3182,7 @@ void SurfaceFlinger::initScheduler(const DisplayDeviceState& displayState) {
mVsyncModulator = sp<VsyncModulator>::make(mVsyncConfiguration->getCurrentConfigs());
// start the EventThread
- mScheduler = getFactory().createScheduler(*mRefreshRateConfigs, *this);
+ mScheduler = getFactory().createScheduler(display->holdRefreshRateConfigs(), *this);
const auto configs = mVsyncConfiguration->getCurrentConfigs();
const nsecs_t vsyncPeriod = currRefreshRate.getPeriodNsecs();
mAppConnectionHandle =
@@ -3217,9 +3211,7 @@ void SurfaceFlinger::initScheduler(const DisplayDeviceState& displayState) {
// This is a bit hacky, but this avoids a back-pointer into the main SF
// classes from EventThread, and there should be no run-time binder cost
// anyway since there are no connected apps at this point.
- mScheduler->onPrimaryDisplayModeChanged(mAppConnectionHandle, displayId,
- displayState.physical->activeMode->getId(),
- vsyncPeriod);
+ mScheduler->onPrimaryDisplayModeChanged(mAppConnectionHandle, display->getActiveMode());
static auto ignorePresentFences =
base::GetBoolProperty("debug.sf.vsync_reactor_ignore_present_fences"s, false);
mScheduler->setIgnorePresentFences(
@@ -3433,9 +3425,9 @@ status_t SurfaceFlinger::addClientLayer(const sp<Client>& client, const sp<IBind
composerState.state.surface = handle;
states.add(composerState);
- lbc->updateTransformHint(mDefaultDisplayTransformHint);
+ lbc->updateTransformHint(mActiveDisplayTransformHint);
if (outTransformHint) {
- *outTransformHint = mDefaultDisplayTransformHint;
+ *outTransformHint = mActiveDisplayTransformHint;
}
// attach this layer to the client
client->attachLayer(handle, lbc);
@@ -3872,6 +3864,12 @@ uint32_t SurfaceFlinger::setDisplayStateLocked(const DisplayState& s) {
flags |= eDisplayTransactionNeeded;
}
}
+ if (what & DisplayState::eFlagsChanged) {
+ if (state.flags != s.flags) {
+ state.flags = s.flags;
+ flags |= eDisplayTransactionNeeded;
+ }
+ }
if (what & DisplayState::eDisplayProjectionChanged) {
if (state.orientation != s.orientation) {
state.orientation = s.orientation;
@@ -4130,10 +4128,10 @@ uint32_t SurfaceFlinger::setClientStateLocked(
}
if (what & layer_state_t::eInputInfoChanged) {
if (privileged) {
- layer->setInputInfo(*s.inputHandle->getInfo());
+ layer->setInputInfo(*s.windowInfoHandle->getInfo());
flags |= eTraversalNeeded;
} else {
- ALOGE("Attempt to update InputWindowInfo without permission ACCESS_SURFACE_FLINGER");
+ ALOGE("Attempt to update WindowInfo without permission ACCESS_SURFACE_FLINGER");
}
}
std::optional<nsecs_t> dequeueBufferTimestamp;
@@ -4206,6 +4204,16 @@ uint32_t SurfaceFlinger::setClientStateLocked(
flags |= eTraversalNeeded;
}
}
+ if (what & layer_state_t::eDropInputModeChanged) {
+ if (privileged) {
+ if (layer->setDropInputMode(s.dropInputMode)) {
+ flags |= eTraversalNeeded;
+ mInputInfoChanged = true;
+ }
+ } else {
+ ALOGE("Attempt to update InputPolicyFlags without permission ACCESS_SURFACE_FLINGER");
+ }
+ }
// This has to happen after we reparent children because when we reparent to null we remove
// child layers from current state and remove its relative z. If the children are reparented in
// the same transaction, then we have to make sure we reparent the children first so we do not
@@ -4231,17 +4239,30 @@ uint32_t SurfaceFlinger::setClientStateLocked(
}
bool bufferChanged = what & layer_state_t::eBufferChanged;
bool cacheIdChanged = what & layer_state_t::eCachedBufferChanged;
+ bool bufferSizeExceedsLimit = false;
std::shared_ptr<renderengine::ExternalTexture> buffer;
if (bufferChanged && cacheIdChanged && s.buffer != nullptr) {
- ClientCache::getInstance().add(s.cachedBuffer, s.buffer);
- buffer = ClientCache::getInstance().get(s.cachedBuffer);
+ bufferSizeExceedsLimit =
+ exceedsMaxRenderTargetSize(s.buffer->getWidth(), s.buffer->getHeight());
+ if (!bufferSizeExceedsLimit) {
+ 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 && s.buffer != nullptr) {
- buffer = std::make_shared<
- renderengine::ExternalTexture>(s.buffer, getRenderEngine(),
- renderengine::ExternalTexture::Usage::READABLE);
- }
+ bufferSizeExceedsLimit =
+ exceedsMaxRenderTargetSize(s.buffer->getWidth(), s.buffer->getHeight());
+ if (!bufferSizeExceedsLimit) {
+ buffer = std::make_shared<
+ renderengine::ExternalTexture>(s.buffer, getRenderEngine(),
+ renderengine::ExternalTexture::Usage::READABLE);
+ }
+ }
+ ALOGE_IF(bufferSizeExceedsLimit,
+ "Attempted to create an ExternalTexture for layer %s that exceeds render target size "
+ "limit.",
+ layer->getDebugName());
if (buffer) {
const bool frameNumberChanged = what & layer_state_t::eFrameNumberChanged;
const uint64_t frameNumber = frameNumberChanged
@@ -4250,7 +4271,7 @@ uint32_t SurfaceFlinger::setClientStateLocked(
if (layer->setBuffer(buffer, s.acquireFence, postTime, desiredPresentTime, isAutoTimestamp,
s.cachedBuffer, frameNumber, dequeueBufferTimestamp, frameTimelineInfo,
- s.releaseBufferListener)) {
+ s.releaseBufferListener, s.releaseBufferEndpoint)) {
flags |= eTraversalNeeded;
}
} else if (frameTimelineInfo.vsyncId != FrameTimelineInfo::INVALID_VSYNC_ID) {
@@ -4524,9 +4545,10 @@ void SurfaceFlinger::onInitializeDisplays() {
{}, getpid(), getuid(), 0 /* Undefined transactionId */);
setPowerModeInternal(display, hal::PowerMode::ON);
- const nsecs_t vsyncPeriod = mRefreshRateConfigs->getCurrentRefreshRate().getVsyncPeriod();
+ const nsecs_t vsyncPeriod =
+ display->refreshRateConfigs().getCurrentRefreshRate().getVsyncPeriod();
mAnimFrameTracker.setDisplayRefreshPeriod(vsyncPeriod);
- mDefaultDisplayTransformHint = display->getTransformHint();
+ mActiveDisplayTransformHint = 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};
@@ -4538,6 +4560,26 @@ void SurfaceFlinger::initializeDisplays() {
static_cast<void>(schedule([this]() MAIN_THREAD { onInitializeDisplays(); }));
}
+sp<DisplayDevice> SurfaceFlinger::getDisplayWithInputByLayer(Layer* layer) const {
+ sp<DisplayDevice> display;
+ for (const auto& pair : mDisplays) {
+ const auto& displayDevice = pair.second;
+ if (!displayDevice->receivesInput() ||
+ !displayDevice->getCompositionDisplay()
+ ->belongsInOutput(layer->getLayerStack(), layer->getPrimaryDisplayOnly())) {
+ continue;
+ }
+ // Don't return immediately so that we can log duplicates.
+ if (display) {
+ ALOGE("Multiple display devices claim to accept input for the same layerstack: %d",
+ layer->getLayerStack());
+ continue;
+ }
+ display = displayDevice;
+ }
+ return display;
+}
+
void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, hal::PowerMode mode) {
if (display->isVirtual()) {
ALOGE("%s: Invalid operation on virtual display", __FUNCTION__);
@@ -4552,13 +4594,23 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, hal:
return;
}
+ const auto activeDisplay = getDisplayDeviceLocked(mActiveDisplayToken);
+ if (activeDisplay != display && display->isInternal() && activeDisplay &&
+ activeDisplay->isPoweredOn()) {
+ ALOGW("Trying to change power mode on non active display while the active display is ON");
+ }
+
display->setPowerMode(mode);
if (mInterceptor->isEnabled()) {
mInterceptor->savePowerModeUpdate(display->getSequenceId(), static_cast<int32_t>(mode));
}
- const auto vsyncPeriod = mRefreshRateConfigs->getCurrentRefreshRate().getVsyncPeriod();
+ const auto vsyncPeriod = display->refreshRateConfigs().getCurrentRefreshRate().getVsyncPeriod();
if (currentMode == hal::PowerMode::OFF) {
+ // Turn on the display
+ if (display->isInternal() && (!activeDisplay || !activeDisplay->isPoweredOn())) {
+ onActiveDisplayChangedLocked(display);
+ }
// Keep uclamp in a separate syscall and set it before changing to RT due to b/190237315.
// We can merge the syscall later.
if (SurfaceFlinger::setSchedAttr(true) != NO_ERROR) {
@@ -4568,8 +4620,8 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, hal:
ALOGW("Couldn't set SCHED_FIFO on display on: %s\n", strerror(errno));
}
getHwComposer().setPowerMode(displayId, mode);
- if (display->isPrimary() && mode != hal::PowerMode::DOZE_SUSPEND) {
- getHwComposer().setVsyncEnabled(displayId, mHWCVsyncPendingState);
+ if (isDisplayActiveLocked(display) && mode != hal::PowerMode::DOZE_SUSPEND) {
+ setHWCVsyncEnabled(displayId, mHWCVsyncPendingState);
mScheduler->onScreenAcquired(mAppConnectionHandle);
mScheduler->resyncToHardwareVsync(true, vsyncPeriod);
}
@@ -4585,13 +4637,13 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, hal:
if (SurfaceFlinger::setSchedAttr(false) != NO_ERROR) {
ALOGW("Couldn't set uclamp.min on display off: %s\n", strerror(errno));
}
- if (display->isPrimary() && currentMode != hal::PowerMode::DOZE_SUSPEND) {
+ if (isDisplayActiveLocked(display) && currentMode != hal::PowerMode::DOZE_SUSPEND) {
mScheduler->disableHardwareVsync(true);
mScheduler->onScreenReleased(mAppConnectionHandle);
}
// Make sure HWVsync is disabled before turning off the display
- getHwComposer().setVsyncEnabled(displayId, hal::Vsync::DISABLE);
+ setHWCVsyncEnabled(displayId, hal::Vsync::DISABLE);
getHwComposer().setPowerMode(displayId, mode);
mVisibleRegionsDirty = true;
@@ -4599,13 +4651,13 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, hal:
} else if (mode == hal::PowerMode::DOZE || mode == hal::PowerMode::ON) {
// Update display while dozing
getHwComposer().setPowerMode(displayId, mode);
- if (display->isPrimary() && currentMode == hal::PowerMode::DOZE_SUSPEND) {
+ if (isDisplayActiveLocked(display) && currentMode == hal::PowerMode::DOZE_SUSPEND) {
mScheduler->onScreenAcquired(mAppConnectionHandle);
mScheduler->resyncToHardwareVsync(true, vsyncPeriod);
}
} else if (mode == hal::PowerMode::DOZE_SUSPEND) {
// Leave display going to doze
- if (display->isPrimary()) {
+ if (isDisplayActiveLocked(display)) {
mScheduler->disableHardwareVsync(true);
mScheduler->onScreenReleased(mAppConnectionHandle);
}
@@ -4615,7 +4667,7 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, hal:
getHwComposer().setPowerMode(displayId, mode);
}
- if (display->isPrimary()) {
+ if (isDisplayActiveLocked(display)) {
mTimeStats->setPowerMode(mode);
mRefreshRateStats->setPowerMode(mode);
mScheduler->setDisplayPowerState(mode == hal::PowerMode::ON);
@@ -4685,12 +4737,17 @@ status_t SurfaceFlinger::doDump(int fd, const DumpArgs& args, bool asProto) {
}
if (dumpLayers) {
- const LayersProto layersProto = dumpProtoFromMainThread();
+ LayersTraceFileProto traceFileProto = SurfaceTracing::createLayersTraceFileProto();
+ LayersTraceProto* layersTrace = traceFileProto.add_entry();
+ LayersProto layersProto = dumpProtoFromMainThread();
+ layersTrace->mutable_layers()->Swap(&layersProto);
+ dumpDisplayProto(*layersTrace);
+
if (asProto) {
- result.append(layersProto.SerializeAsString());
+ result.append(traceFileProto.SerializeAsString());
} else {
// Dump info that we need to access from the main thread
- const auto layerTree = LayerProtoParser::generateLayerTree(layersProto);
+ const auto layerTree = LayerProtoParser::generateLayerTree(layersTrace->layers());
result.append(LayerProtoParser::layerTreeToString(layerTree));
result.append("\n");
dumpOffscreenLayers(result);
@@ -4784,13 +4841,13 @@ void SurfaceFlinger::dumpVSync(std::string& result) const {
" present offset: %9" PRId64 " ns\t VSYNC period: %9" PRId64 " ns\n\n",
dispSyncPresentTimeOffset, getVsyncPeriodFromHWC());
- mRefreshRateConfigs->dump(result);
-
StringAppendF(&result, "(mode override by backdoor: %s)\n\n",
mDebugDisplayModeSetByBackdoor ? "yes" : "no");
mScheduler->dump(mAppConnectionHandle, result);
mScheduler->dumpVsync(result);
+ StringAppendF(&result, "mHWCVsyncPendingState=%s mLastHWCVsyncState=%s\n",
+ to_string(mHWCVsyncPendingState).c_str(), to_string(mLastHWCVsyncState).c_str());
}
void SurfaceFlinger::dumpPlannerInfo(const DumpArgs& args, std::string& result) const {
@@ -4961,6 +5018,22 @@ LayersProto SurfaceFlinger::dumpDrawingStateProto(uint32_t traceFlags) const {
return layersProto;
}
+void SurfaceFlinger::dumpDisplayProto(LayersTraceProto& layersTraceProto) const {
+ for (const auto& [_, display] : ON_MAIN_THREAD(mDisplays)) {
+ DisplayProto* displayProto = layersTraceProto.add_displays();
+ displayProto->set_id(display->getId().value);
+ displayProto->set_name(display->getDisplayName());
+ displayProto->set_layer_stack(display->getLayerStack());
+ LayerProtoHelper::writeSizeToProto(display->getWidth(), display->getHeight(),
+ [&]() { return displayProto->mutable_size(); });
+ LayerProtoHelper::writeToProto(display->getLayerStackSpaceRect(), [&]() {
+ return displayProto->mutable_layer_stack_space_rect();
+ });
+ LayerProtoHelper::writeTransformToProto(display->getTransform(),
+ displayProto->mutable_transform());
+ }
+}
+
void SurfaceFlinger::dumpHwc(std::string& result) const {
getHwComposer().dump(result);
}
@@ -5149,7 +5222,8 @@ void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, std::string& result) co
continue;
}
- StringAppendF(&result, "Display %s HWC layers:\n", to_string(*displayId).c_str());
+ StringAppendF(&result, "Display %s (%s) HWC layers:\n", to_string(*displayId).c_str(),
+ (isDisplayActiveLocked(display) ? "active" : "inactive"));
Layer::miniDumpHeader(result);
const DisplayDevice& ref = *display;
@@ -5349,6 +5423,14 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) {
}
return PERMISSION_DENIED;
}
+ case ADD_WINDOW_INFOS_LISTENER:
+ case REMOVE_WINDOW_INFOS_LISTENER: {
+ const int uid = IPCThreadState::self()->getCallingUid();
+ if (uid == AID_SYSTEM || uid == AID_GRAPHICS) {
+ return OK;
+ }
+ return PERMISSION_DENIED;
+ }
}
// These codes are used for the IBinder protocol to either interrogate the recipient
@@ -5662,16 +5744,17 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r
return NO_ERROR;
}
case 1034: {
- switch (n = data.readInt32()) {
- case 0:
- case 1:
- enableRefreshRateOverlay(static_cast<bool>(n));
- break;
- default: {
- Mutex::Autolock lock(mStateLock);
- reply->writeBool(mRefreshRateOverlay != nullptr);
+ schedule([&] {
+ switch (n = data.readInt32()) {
+ case 0:
+ case 1:
+ ON_MAIN_THREAD(enableRefreshRateOverlay(static_cast<bool>(n)));
+ break;
+ default: {
+ reply->writeBool(ON_MAIN_THREAD(isRefreshRateOverlayEnabled()));
+ }
}
- }
+ }).get();
return NO_ERROR;
}
case 1035: {
@@ -5691,7 +5774,7 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r
return std::make_optional<PhysicalDisplayId>(inputDisplayId);
}
- return getInternalDisplayId();
+ return getDefaultDisplayDevice()->getPhysicalId();
}();
if (!displayId) {
@@ -5817,22 +5900,25 @@ void SurfaceFlinger::kernelTimerChanged(bool expired) {
static bool updateOverlay =
property_get_bool("debug.sf.kernel_idle_timer_update_overlay", true);
if (!updateOverlay) return;
- if (Mutex::Autolock lock(mStateLock); !mRefreshRateOverlay) return;
+ if (Mutex::Autolock lock(mStateLock); !isRefreshRateOverlayEnabled()) return;
// Update the overlay on the main thread to avoid race conditions with
// mRefreshRateConfigs->getCurrentRefreshRate()
static_cast<void>(schedule([=] {
- const auto desiredActiveMode = getDesiredActiveMode();
- const std::optional<DisplayModeId> desiredModeId =
- desiredActiveMode ? std::make_optional(desiredActiveMode->modeId) : std::nullopt;
+ const auto display = ON_MAIN_THREAD(getDefaultDisplayDeviceLocked());
+ if (!display) {
+ ALOGW("%s: default display is null", __func__);
+ return;
+ }
+
+ const auto desiredActiveMode = display->getDesiredActiveMode();
+ const std::optional<DisplayModeId> desiredModeId = desiredActiveMode
+ ? std::make_optional(desiredActiveMode->mode->getId())
+ : std::nullopt;
const bool timerExpired = mKernelIdleTimerEnabled && expired;
- const auto newRefreshRate =
- mRefreshRateConfigs->onKernelTimerChanged(desiredModeId, timerExpired);
- if (newRefreshRate) {
- if (Mutex::Autolock lock(mStateLock); mRefreshRateOverlay) {
- mRefreshRateOverlay->changeRefreshRate(*newRefreshRate);
- }
+
+ if (display->onKernelTimerChanged(desiredModeId, timerExpired)) {
mEventQueue->invalidate();
}
}));
@@ -5841,12 +5927,19 @@ void SurfaceFlinger::kernelTimerChanged(bool expired) {
void SurfaceFlinger::toggleKernelIdleTimer() {
using KernelIdleTimerAction = scheduler::RefreshRateConfigs::KernelIdleTimerAction;
- // If the support for kernel idle timer is disabled in SF code, don't do anything.
- if (!mSupportKernelIdleTimer) {
+ const auto display = getDefaultDisplayDeviceLocked();
+ if (!display) {
+ ALOGW("%s: default display is null", __func__);
return;
}
- const KernelIdleTimerAction action = mRefreshRateConfigs->getIdleTimerAction();
+ // If the support for kernel idle timer is disabled for the active display,
+ // don't do anything.
+ if (!display->refreshRateConfigs().supportsKernelIdleTimer()) {
+ return;
+ }
+
+ const KernelIdleTimerAction action = display->refreshRateConfigs().getIdleTimerAction();
switch (action) {
case KernelIdleTimerAction::TurnOff:
if (mKernelIdleTimerEnabled) {
@@ -6083,9 +6176,7 @@ status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args,
sp<Layer> parent;
Rect crop(args.sourceCrop);
std::unordered_set<sp<Layer>, ISurfaceComposer::SpHash<Layer>> excludeLayers;
- Rect layerStackSpaceRect;
ui::Dataspace dataspace;
- bool captureSecureLayers;
// Call this before holding mStateLock to avoid any deadlocking.
bool canCaptureBlackoutContent = hasCaptureBlackoutContentPermission();
@@ -6094,7 +6185,7 @@ status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args,
Mutex::Autolock lock(mStateLock);
parent = fromHandle(args.layerHandle).promote();
- if (parent == nullptr || parent->isRemovedFromCurrentState()) {
+ if (parent == nullptr) {
ALOGE("captureLayers called with an invalid or removed parent");
return NAME_NOT_FOUND;
}
@@ -6133,39 +6224,36 @@ status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args,
}
}
- const auto display = findDisplay(WithLayerStack(parent->getLayerStack()));
- if (!display) {
- return NAME_NOT_FOUND;
- }
-
- layerStackSpaceRect = display->getLayerStackSpaceRect();
-
// The dataspace is depended on the color mode of display, that could use non-native mode
// (ex. displayP3) to enhance the content, but some cases are checking native RGB in bytes,
// and failed if display is not in native mode. This provide a way to force using native
// colors when capture.
dataspace = args.dataspace;
if (dataspace == ui::Dataspace::UNKNOWN) {
+ auto display = findDisplay(WithLayerStack(parent->getLayerStack()));
+ if (!display) {
+ // If the layer is not on a display, use the dataspace for the default display.
+ display = getDefaultDisplayDeviceLocked();
+ }
+
const ui::ColorMode colorMode = display->getCompositionDisplay()->getState().colorMode;
dataspace = pickDataspaceFromColorMode(colorMode);
}
- captureSecureLayers = args.captureSecureLayers && display->isSecure();
} // mStateLock
// really small crop or frameScale
- if (reqSize.width <= 0) {
- reqSize.width = 1;
- }
- if (reqSize.height <= 0) {
- reqSize.height = 1;
+ if (reqSize.width <= 0 || reqSize.height <= 0) {
+ ALOGW("Failed to captureLayes: crop or scale too small");
+ return BAD_VALUE;
}
+ Rect layerStackSpaceRect(0, 0, reqSize.width, reqSize.height);
bool childrenOnly = args.childrenOnly;
RenderAreaFuture renderAreaFuture = ftl::defer([=]() -> std::unique_ptr<RenderArea> {
return std::make_unique<LayerRenderArea>(*this, parent, crop, reqSize, dataspace,
childrenOnly, layerStackSpaceRect,
- captureSecureLayers);
+ args.captureSecureLayers);
});
auto traverseLayers = [parent, args, excludeLayers](const LayerVector::Visitor& visitor) {
@@ -6202,6 +6290,13 @@ status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture,
const sp<IScreenCaptureListener>& captureListener) {
ATRACE_CALL();
+ if (exceedsMaxRenderTargetSize(bufferSize.getWidth(), bufferSize.getHeight())) {
+ ALOGE("Attempted to capture screen with size (%" PRId32 ", %" PRId32
+ ") that exceeds render target size limit.",
+ bufferSize.getWidth(), bufferSize.getHeight());
+ return BAD_VALUE;
+ }
+
// Loop over all visible layers to see whether there's any protected layer. A protected layer is
// typically a layer with DRM contents, or have the GRALLOC_USAGE_PROTECTED set on the buffer.
// A protected layer has no implication on whether it's secure, which is explicitly set by
@@ -6416,7 +6511,7 @@ status_t SurfaceFlinger::renderScreenImplLocked(
return NO_ERROR;
}
-void SurfaceFlinger::setInputWindowsFinished() {
+void SurfaceFlinger::windowInfosReported() {
Mutex::Autolock _l(mStateLock);
signalSynchronousTransactions(CountDownLatch::eSyncInputWindows);
}
@@ -6464,78 +6559,55 @@ status_t SurfaceFlinger::setDesiredDisplayModeSpecsInternal(
const std::optional<scheduler::RefreshRateConfigs::Policy>& policy, bool overridePolicy) {
Mutex::Autolock lock(mStateLock);
- LOG_ALWAYS_FATAL_IF(!display->isPrimary() && overridePolicy,
- "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()) {
- // TODO(b/144711714): For non-primary displays we should be able to set an active mode
- // as well. For now, just call directly to initiateModeChange but ideally
- // it should go thru setDesiredActiveMode, similar to primary display.
- ALOGV("%s for non-primary display", __func__);
- const auto displayId = display->getPhysicalId();
-
- hal::VsyncPeriodChangeConstraints constraints;
- constraints.desiredTimeNanos = systemTime();
- constraints.seamlessRequired = false;
-
- hal::VsyncPeriodChangeTimeline timeline = {0, 0, 0};
- if (display->initiateModeChange(policy->defaultMode, constraints, &timeline) != NO_ERROR) {
- return BAD_VALUE;
- }
- if (timeline.refreshRequired) {
- repaintEverythingForHWC();
- }
-
- display->setActiveMode(policy->defaultMode);
- const nsecs_t vsyncPeriod = display->getMode(policy->defaultMode)->getVsyncPeriod();
- mScheduler->onNonPrimaryDisplayModeChanged(mAppConnectionHandle, displayId,
- policy->defaultMode, vsyncPeriod);
- return NO_ERROR;
- }
-
status_t setPolicyResult = overridePolicy
- ? mRefreshRateConfigs->setOverridePolicy(policy)
- : mRefreshRateConfigs->setDisplayManagerPolicy(*policy);
+ ? display->refreshRateConfigs().setOverridePolicy(policy)
+ : display->refreshRateConfigs().setDisplayManagerPolicy(*policy);
if (setPolicyResult < 0) {
return BAD_VALUE;
}
if (setPolicyResult == scheduler::RefreshRateConfigs::CURRENT_POLICY_UNCHANGED) {
return NO_ERROR;
}
- scheduler::RefreshRateConfigs::Policy currentPolicy = mRefreshRateConfigs->getCurrentPolicy();
+
+ scheduler::RefreshRateConfigs::Policy currentPolicy =
+ display->refreshRateConfigs().getCurrentPolicy();
ALOGV("Setting desired display mode specs: %s", currentPolicy.toString().c_str());
// TODO(b/140204874): Leave the event in until we do proper testing with all apps that might
// be depending in this callback.
const auto activeMode = display->getActiveMode();
- const nsecs_t vsyncPeriod = activeMode->getVsyncPeriod();
- const auto physicalId = display->getPhysicalId();
- mScheduler->onPrimaryDisplayModeChanged(mAppConnectionHandle, physicalId, activeMode->getId(),
- vsyncPeriod);
- toggleKernelIdleTimer();
+ if (isDisplayActiveLocked(display)) {
+ mScheduler->onPrimaryDisplayModeChanged(mAppConnectionHandle, activeMode);
+ toggleKernelIdleTimer();
+ } else {
+ mScheduler->onNonPrimaryDisplayModeChanged(mAppConnectionHandle, activeMode);
+ }
+
+ const DisplayModePtr preferredDisplayMode = [&] {
+ const auto schedulerMode = mScheduler->getPreferredDisplayMode();
+ if (schedulerMode && schedulerMode->getPhysicalDisplayId() == display->getPhysicalId()) {
+ return schedulerMode;
+ }
+
+ return display->getMode(currentPolicy.defaultMode);
+ }();
- auto modeId = mScheduler->getPreferredModeId();
- auto preferredRefreshRate = modeId
- ? mRefreshRateConfigs->getRefreshRateFromModeId(*modeId)
- // NOTE: Choose the default mode ID, if Scheduler doesn't have one in mind.
- : mRefreshRateConfigs->getRefreshRateFromModeId(currentPolicy.defaultMode);
ALOGV("trying to switch to Scheduler preferred mode %d (%s)",
- preferredRefreshRate.getModeId().value(), preferredRefreshRate.getName().c_str());
+ preferredDisplayMode->getId().value(), to_string(preferredDisplayMode->getFps()).c_str());
- if (isDisplayModeAllowed(preferredRefreshRate.getModeId())) {
+ if (display->refreshRateConfigs().isModeAllowed(preferredDisplayMode->getId())) {
ALOGV("switching to Scheduler preferred display mode %d",
- preferredRefreshRate.getModeId().value());
- setDesiredActiveMode({preferredRefreshRate.getModeId(), Scheduler::ModeEvent::Changed});
+ preferredDisplayMode->getId().value());
+ setDesiredActiveMode({preferredDisplayMode, Scheduler::ModeEvent::Changed});
} else {
LOG_ALWAYS_FATAL("Desired display mode not allowed: %d",
- preferredRefreshRate.getModeId().value());
+ preferredDisplayMode->getId().value());
}
return NO_ERROR;
@@ -6595,29 +6667,19 @@ status_t SurfaceFlinger::getDesiredDisplayModeSpecs(const sp<IBinder>& displayTo
return NAME_NOT_FOUND;
}
- if (display->isPrimary()) {
- scheduler::RefreshRateConfigs::Policy policy =
- mRefreshRateConfigs->getDisplayManagerPolicy();
- *outDefaultMode = policy.defaultMode.value();
- *outAllowGroupSwitching = policy.allowGroupSwitching;
- *outPrimaryRefreshRateMin = policy.primaryRange.min.getValue();
- *outPrimaryRefreshRateMax = policy.primaryRange.max.getValue();
- *outAppRequestRefreshRateMin = policy.appRequestRange.min.getValue();
- *outAppRequestRefreshRateMax = policy.appRequestRange.max.getValue();
- return NO_ERROR;
- } else if (display->isVirtual()) {
+ if (display->isVirtual()) {
return INVALID_OPERATION;
- } else {
- const auto activeMode = display->getActiveMode();
- *outDefaultMode = activeMode->getId().value();
- *outAllowGroupSwitching = false;
- auto vsyncPeriod = activeMode->getVsyncPeriod();
- *outPrimaryRefreshRateMin = Fps::fromPeriodNsecs(vsyncPeriod).getValue();
- *outPrimaryRefreshRateMax = Fps::fromPeriodNsecs(vsyncPeriod).getValue();
- *outAppRequestRefreshRateMin = Fps::fromPeriodNsecs(vsyncPeriod).getValue();
- *outAppRequestRefreshRateMax = Fps::fromPeriodNsecs(vsyncPeriod).getValue();
- return NO_ERROR;
}
+
+ scheduler::RefreshRateConfigs::Policy policy =
+ display->refreshRateConfigs().getDisplayManagerPolicy();
+ *outDefaultMode = policy.defaultMode.value();
+ *outAllowGroupSwitching = policy.allowGroupSwitching;
+ *outPrimaryRefreshRateMin = policy.primaryRange.min.getValue();
+ *outPrimaryRefreshRateMax = policy.primaryRange.max.getValue();
+ *outAppRequestRefreshRateMin = policy.appRequestRange.min.getValue();
+ *outAppRequestRefreshRateMax = policy.appRequestRange.max.getValue();
+ return NO_ERROR;
}
wp<Layer> SurfaceFlinger::fromHandle(const sp<IBinder>& handle) const {
@@ -6736,7 +6798,8 @@ status_t SurfaceFlinger::acquireFrameRateFlexibilityToken(sp<IBinder>* outToken)
// matter for the override policy though, since we set allowGroupSwitching to
// true, so it's not a problem.
scheduler::RefreshRateConfigs::Policy overridePolicy;
- overridePolicy.defaultMode = mRefreshRateConfigs->getDisplayManagerPolicy().defaultMode;
+ overridePolicy.defaultMode =
+ display->refreshRateConfigs().getDisplayManagerPolicy().defaultMode;
overridePolicy.allowGroupSwitching = true;
constexpr bool kOverridePolicy = true;
result = setDesiredDisplayModeSpecsInternal(display, overridePolicy, kOverridePolicy);
@@ -6804,25 +6867,11 @@ status_t SurfaceFlinger::setFrameTimelineInfo(const sp<IGraphicBufferProducer>&
}
void SurfaceFlinger::enableRefreshRateOverlay(bool enable) {
- static_cast<void>(schedule([=] {
- std::unique_ptr<RefreshRateOverlay> overlay;
- if (enable) {
- overlay = std::make_unique<RefreshRateOverlay>(*this, mRefreshRateOverlaySpinner);
- }
-
- {
- Mutex::Autolock lock(mStateLock);
-
- // Destroy the layer of the current overlay, if any, outside the lock.
- mRefreshRateOverlay.swap(overlay);
- if (!mRefreshRateOverlay) return;
-
- if (const auto display = getDefaultDisplayDeviceLocked()) {
- mRefreshRateOverlay->setViewport(display->getSize());
- mRefreshRateOverlay->changeRefreshRate(display->getActiveMode()->getFps());
- }
+ for (const auto& [ignored, display] : mDisplays) {
+ if (display->isInternal()) {
+ display->enableRefreshRateOverlay(enable, mRefreshRateOverlaySpinner);
}
- }));
+ }
}
status_t SurfaceFlinger::addTransactionTraceListener(
@@ -6850,7 +6899,14 @@ int SurfaceFlinger::calculateMaxAcquiredBufferCount(Fps refreshRate,
}
status_t SurfaceFlinger::getMaxAcquiredBufferCount(int* buffers) const {
- const auto maxSupportedRefreshRate = mRefreshRateConfigs->getSupportedRefreshRateRange().max;
+ const auto maxSupportedRefreshRate = [&] {
+ const auto display = getDefaultDisplayDevice();
+ if (display) {
+ return display->refreshRateConfigs().getSupportedRefreshRateRange().max;
+ }
+ ALOGW("%s: default display is null", __func__);
+ return Fps(60);
+ }();
*buffers = getMaxAcquiredBufferCountForRefreshRate(maxSupportedRefreshRate);
return NO_ERROR;
}
@@ -6861,7 +6917,14 @@ int SurfaceFlinger::getMaxAcquiredBufferCountForCurrentRefreshRate(uid_t uid) co
if (frameRateOverride.has_value()) {
return frameRateOverride.value();
}
- return mRefreshRateConfigs->getCurrentRefreshRate().getFps();
+
+ const auto display = ON_MAIN_THREAD(getDefaultDisplayDeviceLocked());
+ if (display) {
+ return display->refreshRateConfigs().getCurrentRefreshRate().getFps();
+ }
+
+ ALOGW("%s: default display is null", __func__);
+ return Fps(60);
}();
return getMaxAcquiredBufferCountForRefreshRate(refreshRate);
}
@@ -6948,7 +7011,7 @@ sp<Layer> SurfaceFlinger::handleLayerCreatedLocked(const sp<IBinder>& handle) {
parent->addChild(layer);
}
- layer->updateTransformHint(mDefaultDisplayTransformHint);
+ layer->updateTransformHint(mActiveDisplayTransformHint);
if (state->initialProducer != nullptr) {
mGraphicBufferProducerList.insert(state->initialProducer);
@@ -6978,6 +7041,47 @@ void SurfaceFlinger::notifyRegionSamplingThread() {
mRegionSamplingThread->onCompositionComplete(mEventQueue->nextExpectedInvalidate());
}
+void SurfaceFlinger::onActiveDisplaySizeChanged(const sp<DisplayDevice>& activeDisplay) {
+ mScheduler->onActiveDisplayAreaChanged(activeDisplay->getWidth() * activeDisplay->getHeight());
+ getRenderEngine().onActiveDisplaySizeChanged(activeDisplay->getSize());
+}
+
+void SurfaceFlinger::onActiveDisplayChangedLocked(const sp<DisplayDevice>& activeDisplay) {
+ ATRACE_CALL();
+
+ if (const auto display = getDisplayDeviceLocked(mActiveDisplayToken)) {
+ display->getCompositionDisplay()->setLayerCachingTexturePoolEnabled(false);
+ }
+
+ if (!activeDisplay) {
+ ALOGE("%s: activeDisplay is null", __func__);
+ return;
+ }
+ mActiveDisplayToken = activeDisplay->getDisplayToken();
+ activeDisplay->getCompositionDisplay()->setLayerCachingTexturePoolEnabled(true);
+ updateInternalDisplayVsyncLocked(activeDisplay);
+ mScheduler->setModeChangePending(false);
+ mScheduler->setRefreshRateConfigs(activeDisplay->holdRefreshRateConfigs());
+ onActiveDisplaySizeChanged(activeDisplay);
+ mActiveDisplayTransformHint = activeDisplay->getTransformHint();
+
+ // Update the kernel timer for the current active display, since the policy
+ // for this display might have changed when it was not the active display.
+ toggleKernelIdleTimer();
+}
+
+status_t SurfaceFlinger::addWindowInfosListener(
+ const sp<IWindowInfosListener>& windowInfosListener) const {
+ mWindowInfosListenerInvoker->addWindowInfosListener(windowInfosListener);
+ return NO_ERROR;
+}
+
+status_t SurfaceFlinger::removeWindowInfosListener(
+ const sp<IWindowInfosListener>& windowInfosListener) const {
+ mWindowInfosListenerInvoker->removeWindowInfosListener(windowInfosListener);
+ return NO_ERROR;
+}
+
} // namespace android
#if defined(__gl_h_)
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 4e8e614cbd..74fe7d97d0 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -93,7 +93,6 @@ class FpsReporter;
class TunnelModeEnabledReporter;
class HdrLayerInfoReporter;
class HWComposer;
-struct SetInputWindowsListener;
class IGraphicBufferProducer;
class Layer;
class MessageBase;
@@ -102,6 +101,7 @@ class RegionSamplingThread;
class RenderArea;
class TimeStats;
class FrameTracer;
+class WindowInfosListenerInvoker;
using gui::ScreenCaptureResults;
@@ -332,11 +332,12 @@ public:
// If set, disables reusing client composition buffers. This can be set by
// debug.sf.disable_client_composition_cache
bool mDisableClientCompositionCache = false;
- void setInputWindowsFinished();
+ void windowInfosReported();
// Disables expensive rendering for all displays
// This is scheduled on the main thread
void disableExpensiveRendering();
+ FloatRect getMaxDisplayBounds();
protected:
// We're reference counted, never destroy SurfaceFlinger directly
@@ -350,12 +351,14 @@ protected:
REQUIRES(mStateLock);
virtual void commitTransactionLocked();
- // Used internally by computeLayerBounds() to gets the clip rectangle to use for the
- // root layers on a particular display in layer-coordinate space. The
- // layers (and effectively their children) will be clipped against this
- // rectangle. The base behavior is to clip to the visible region of the
- // display.
- virtual FloatRect getLayerClipBoundsForDisplay(const DisplayDevice&) const;
+ virtual void processDisplayAdded(const wp<IBinder>& displayToken, const DisplayDeviceState&)
+ REQUIRES(mStateLock);
+
+ // Returns true if any display matches a `bool(const DisplayDevice&)` predicate.
+ template <typename Predicate>
+ bool hasDisplay(Predicate p) const REQUIRES(mStateLock) {
+ return static_cast<bool>(findDisplay(p));
+ }
private:
friend class BufferLayer;
@@ -455,14 +458,7 @@ private:
mCounterByLayerHandle GUARDED_BY(mLock);
};
- struct ActiveModeInfo {
- DisplayModeId modeId;
- Scheduler::ModeEvent event = Scheduler::ModeEvent::None;
-
- bool operator!=(const ActiveModeInfo& other) const {
- return modeId != other.modeId || event != other.event;
- }
- };
+ using ActiveModeInfo = DisplayDevice::ActiveModeInfo;
enum class BootStage {
BOOTLOADER,
@@ -593,7 +589,7 @@ private:
typename Handler = VsyncModulator::VsyncConfigOpt (VsyncModulator::*)(Args...)>
void modulateVsync(Handler handler, Args... args) {
if (const auto config = (*mVsyncModulator.*handler)(args...)) {
- const auto vsyncPeriod = mRefreshRateConfigs->getCurrentRefreshRate().getVsyncPeriod();
+ const auto vsyncPeriod = mScheduler->getVsyncPeriodFromRefreshRateConfigs();
setVsyncConfig(*config, vsyncPeriod);
}
}
@@ -612,8 +608,12 @@ private:
sp<ISurfaceComposerClient> createConnection() override;
sp<IBinder> createDisplay(const String8& displayName, bool secure) override;
void destroyDisplay(const sp<IBinder>& displayToken) override;
- std::vector<PhysicalDisplayId> getPhysicalDisplayIds() const override;
+ std::vector<PhysicalDisplayId> getPhysicalDisplayIds() const override EXCLUDES(mStateLock) {
+ Mutex::Autolock lock(mStateLock);
+ return getPhysicalDisplayIdsLocked();
+ }
status_t getPrimaryPhysicalDisplayId(PhysicalDisplayId*) const override EXCLUDES(mStateLock);
+
sp<IBinder> getPhysicalDisplayToken(PhysicalDisplayId displayId) const override;
status_t setTransactionState(const FrameTimelineInfo& frameTimelineInfo,
const Vector<ComposerState>& state,
@@ -721,6 +721,11 @@ private:
status_t getMaxAcquiredBufferCount(int* buffers) const override;
+ status_t addWindowInfosListener(
+ const sp<gui::IWindowInfosListener>& windowInfosListener) const override;
+ status_t removeWindowInfosListener(
+ const sp<gui::IWindowInfosListener>& windowInfosListener) const override;
+
// Implements IBinder::DeathRecipient.
void binderDied(const wp<IBinder>& who) override;
@@ -751,12 +756,10 @@ private:
// Called when the frame rate override list changed to trigger an event.
void triggerOnFrameRateOverridesChanged() override;
// Toggles the kernel idle timer on or off depending the policy decisions around refresh rates.
- void toggleKernelIdleTimer();
+ void toggleKernelIdleTimer() REQUIRES(mStateLock);
// Keeps track of whether the kernel idle timer is currently enabled, so we don't have to
// make calls to sys prop each time.
bool mKernelIdleTimerEnabled = false;
- // Keeps track of whether the kernel timer is supported on the SF side.
- bool mSupportKernelIdleTimer = false;
// Show spinner with refresh rate overlay
bool mRefreshRateOverlaySpinner = false;
@@ -780,9 +783,9 @@ private:
// Calls to setActiveMode on the main thread if there is a pending mode change
// that needs to be applied.
void performSetActiveMode() REQUIRES(mStateLock);
- void clearDesiredActiveModeState() REQUIRES(mStateLock) EXCLUDES(mActiveModeLock);
+ void clearDesiredActiveModeState(const sp<DisplayDevice>&) REQUIRES(mStateLock);
// Called when active mode is no longer is progress
- void desiredActiveModeChangeDone() REQUIRES(mStateLock);
+ void desiredActiveModeChangeDone(const sp<DisplayDevice>&) REQUIRES(mStateLock);
// Called on the main thread in response to setPowerMode()
void setPowerModeInternal(const sp<DisplayDevice>& display, hal::PowerMode mode)
REQUIRES(mStateLock);
@@ -811,11 +814,11 @@ private:
void handleTransactionLocked(uint32_t transactionFlags) REQUIRES(mStateLock);
void updateInputFlinger();
- void updateInputWindowInfo();
+ void notifyWindowInfos();
void commitInputWindowCommands() REQUIRES(mStateLock);
void updateCursorAsync();
- void initScheduler(const DisplayDeviceState&) REQUIRES(mStateLock);
+ void initScheduler(const sp<DisplayDevice>& display) REQUIRES(mStateLock);
void updatePhaseConfiguration(const Fps&) REQUIRES(mStateLock);
void setVsyncConfig(const VsyncModulator::VsyncConfig&, nsecs_t vsyncPeriod);
@@ -931,8 +934,9 @@ private:
void readPersistentProperties();
- size_t getMaxTextureSize() const;
- size_t getMaxViewportDims() const;
+ bool exceedsMaxRenderTargetSize(uint32_t width, uint32_t height) const {
+ return width > mMaxRenderTargetSize || height > mMaxRenderTargetSize;
+ }
int getMaxAcquiredBufferCountForCurrentRefreshRate(uid_t uid) const;
@@ -954,6 +958,10 @@ private:
sp<const DisplayDevice> getDisplayDeviceLocked(PhysicalDisplayId id) const
REQUIRES(mStateLock) {
+ return const_cast<SurfaceFlinger*>(this)->getDisplayDeviceLocked(id);
+ }
+
+ sp<DisplayDevice> getDisplayDeviceLocked(PhysicalDisplayId id) REQUIRES(mStateLock) {
if (const auto token = getPhysicalDisplayTokenLocked(id)) {
return getDisplayDeviceLocked(token);
}
@@ -965,13 +973,18 @@ private:
}
sp<DisplayDevice> getDefaultDisplayDeviceLocked() REQUIRES(mStateLock) {
+ if (const auto display = getDisplayDeviceLocked(mActiveDisplayToken)) {
+ return display;
+ }
+ // The active display is outdated, fall back to the internal display
+ mActiveDisplayToken.clear();
if (const auto token = getInternalDisplayTokenLocked()) {
return getDisplayDeviceLocked(token);
}
return nullptr;
}
- sp<const DisplayDevice> getDefaultDisplayDevice() EXCLUDES(mStateLock) {
+ sp<const DisplayDevice> getDefaultDisplayDevice() const EXCLUDES(mStateLock) {
Mutex::Autolock lock(mStateLock);
return getDefaultDisplayDeviceLocked();
}
@@ -990,10 +1003,18 @@ private:
return findDisplay([id](const auto& display) { return display.getId() == id; });
}
+ std::vector<PhysicalDisplayId> getPhysicalDisplayIdsLocked() const REQUIRES(mStateLock);
+
// mark a region of a layer stack dirty. this updates the dirty
// region of all screens presenting this layer stack.
void invalidateLayerStack(const sp<const Layer>& layer, const Region& dirty);
+ sp<DisplayDevice> getDisplayWithInputByLayer(Layer* layer) const REQUIRES(mStateLock);
+
+ bool isDisplayActiveLocked(const sp<const DisplayDevice>& display) const REQUIRES(mStateLock) {
+ return display->getDisplayToken() == mActiveDisplayToken;
+ }
+
/*
* H/W composer
*/
@@ -1031,8 +1052,6 @@ private:
const sp<compositionengine::DisplaySurface>& displaySurface,
const sp<IGraphicBufferProducer>& producer) REQUIRES(mStateLock);
void processDisplayChangesLocked() REQUIRES(mStateLock);
- void processDisplayAdded(const wp<IBinder>& displayToken, const DisplayDeviceState&)
- REQUIRES(mStateLock);
void processDisplayRemoved(const wp<IBinder>& displayToken) REQUIRES(mStateLock);
void processDisplayChanged(const wp<IBinder>& displayToken,
const DisplayDeviceState& currentState,
@@ -1046,12 +1065,15 @@ private:
*/
nsecs_t getVsyncPeriodFromHWC() const REQUIRES(mStateLock);
+ void setHWCVsyncEnabled(PhysicalDisplayId id, hal::Vsync enabled) {
+ mLastHWCVsyncState = enabled;
+ getHwComposer().setVsyncEnabled(id, enabled);
+ }
+
// Sets the refresh rate by switching active configs, if they are available for
// the desired refresh rate.
void changeRefreshRateLocked(const RefreshRate&, Scheduler::ModeEvent) REQUIRES(mStateLock);
- bool isDisplayModeAllowed(DisplayModeId) const REQUIRES(mStateLock);
-
struct FenceWithFenceTime {
sp<Fence> fence = Fence::NO_FENCE;
std::shared_ptr<FenceTime> fenceTime = FenceTime::NO_FENCE;
@@ -1112,10 +1134,13 @@ private:
void enableHalVirtualDisplays(bool);
// Virtual display lifecycle for ID generation and HAL allocation.
- VirtualDisplayId acquireVirtualDisplay(ui::Size, ui::PixelFormat, ui::LayerStack)
- REQUIRES(mStateLock);
+ VirtualDisplayId acquireVirtualDisplay(ui::Size, ui::PixelFormat) REQUIRES(mStateLock);
void releaseVirtualDisplay(VirtualDisplayId);
+ void onActiveDisplayChangedLocked(const sp<DisplayDevice>& activeDisplay) REQUIRES(mStateLock);
+
+ void onActiveDisplaySizeChanged(const sp<DisplayDevice>& activeDisplay);
+
/*
* Debugging & dumpsys
*/
@@ -1143,6 +1168,8 @@ private:
LayersProto dumpDrawingStateProto(uint32_t traceFlags) const;
void dumpOffscreenLayersProto(LayersProto& layersProto,
uint32_t traceFlags = SurfaceTracing::TRACE_ALL) const;
+ void dumpDisplayProto(LayersTraceProto& layersTraceProto) const;
+
// Dumps state from HW Composer
void dumpHwc(std::string& result) const;
LayersProto dumpProtoFromMainThread(uint32_t traceFlags = SurfaceTracing::TRACE_ALL)
@@ -1181,13 +1208,6 @@ private:
/*
* Misc
*/
-
- std::optional<ActiveModeInfo> getDesiredActiveMode() EXCLUDES(mActiveModeLock) {
- std::lock_guard<std::mutex> lock(mActiveModeLock);
- if (mDesiredActiveModeChanged) return mDesiredActiveMode;
- return std::nullopt;
- }
-
std::vector<ui::ColorMode> getDisplayColorModes(PhysicalDisplayId displayId)
REQUIRES(mStateLock);
@@ -1195,6 +1215,9 @@ private:
std::chrono::nanoseconds presentLatency);
int getMaxAcquiredBufferCountForRefreshRate(Fps refreshRate) const;
+ void updateInternalDisplayVsyncLocked(const sp<DisplayDevice>& activeDisplay)
+ REQUIRES(mStateLock);
+
sp<StartPropertySetThread> mStartPropertySetThread;
surfaceflinger::Factory& mFactory;
@@ -1379,6 +1402,9 @@ private:
SurfaceFlingerBE mBE;
std::unique_ptr<compositionengine::CompositionEngine> mCompositionEngine;
+ // mMaxRenderTargetSize is only set once in init() so it doesn't need to be protected by
+ // any mutex.
+ size_t mMaxRenderTargetSize{1};
const std::string mHwcServiceName;
@@ -1397,24 +1423,14 @@ private:
// Optional to defer construction until PhaseConfiguration is created.
sp<VsyncModulator> mVsyncModulator;
- std::unique_ptr<scheduler::RefreshRateConfigs> mRefreshRateConfigs;
std::unique_ptr<scheduler::RefreshRateStats> mRefreshRateStats;
std::atomic<nsecs_t> mExpectedPresentTime = 0;
nsecs_t mScheduledPresentTime = 0;
hal::Vsync mHWCVsyncPendingState = hal::Vsync::DISABLE;
-
- std::mutex mActiveModeLock;
- // This bit is set once we start setting the mode. We read from this bit during the
- // process. If at the end, this bit is different than mDesiredActiveMode, we restart
- // the process.
- ActiveModeInfo mUpcomingActiveMode; // Always read and written on the main thread.
- // This bit can be set at any point in time when the system wants the new mode.
- ActiveModeInfo mDesiredActiveMode GUARDED_BY(mActiveModeLock);
+ hal::Vsync mLastHWCVsyncState = hal::Vsync::DISABLE;
// below flags are set by main thread only
- TracedOrdinal<bool> mDesiredActiveModeChanged
- GUARDED_BY(mActiveModeLock) = {"DesiredActiveModeChanged", false};
bool mSetActiveModePending = false;
bool mLumaSampling = true;
@@ -1430,15 +1446,12 @@ private:
// Should only be accessed by the main thread.
InputWindowCommands mInputWindowCommands;
- sp<SetInputWindowsListener> mSetInputWindowsListener;
-
Hwc2::impl::PowerAdvisor mPowerAdvisor;
// This should only be accessed on the main thread.
nsecs_t mFrameStartTime = 0;
- void enableRefreshRateOverlay(bool enable);
- std::unique_ptr<RefreshRateOverlay> mRefreshRateOverlay GUARDED_BY(mStateLock);
+ void enableRefreshRateOverlay(bool enable) REQUIRES(mStateLock);
// Flag used to set override desired display mode from backdoor
bool mDebugDisplayModeSetByBackdoor = false;
@@ -1489,10 +1502,21 @@ private:
auto getLayerCreatedState(const sp<IBinder>& handle);
sp<Layer> handleLayerCreatedLocked(const sp<IBinder>& handle) REQUIRES(mStateLock);
- std::atomic<ui::Transform::RotationFlags> mDefaultDisplayTransformHint;
+ std::atomic<ui::Transform::RotationFlags> mActiveDisplayTransformHint;
void scheduleRegionSamplingThread();
void notifyRegionSamplingThread();
+
+ bool isRefreshRateOverlayEnabled() const REQUIRES(mStateLock) {
+ return std::any_of(mDisplays.begin(), mDisplays.end(),
+ [](std::pair<wp<IBinder>, sp<DisplayDevice>> display) {
+ return display.second->isRefreshRateOverlayEnabled();
+ });
+ }
+
+ wp<IBinder> mActiveDisplayToken GUARDED_BY(mStateLock);
+
+ const sp<WindowInfosListenerInvoker> mWindowInfosListenerInvoker;
};
} // namespace android
diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
index 4a7518066f..89d1c4d327 100644
--- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
+++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
@@ -65,8 +65,9 @@ std::unique_ptr<scheduler::VsyncConfiguration> DefaultFactory::createVsyncConfig
}
std::unique_ptr<Scheduler> DefaultFactory::createScheduler(
- const scheduler::RefreshRateConfigs& configs, ISchedulerCallback& callback) {
- return std::make_unique<Scheduler>(configs, callback);
+ const std::shared_ptr<scheduler::RefreshRateConfigs>& refreshRateConfigs,
+ ISchedulerCallback& callback) {
+ return std::make_unique<Scheduler>(std::move(refreshRateConfigs), callback);
}
sp<SurfaceInterceptor> DefaultFactory::createSurfaceInterceptor() {
diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.h b/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
index 24148ddf9d..b8bf2baa33 100644
--- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
+++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
@@ -30,8 +30,8 @@ public:
std::unique_ptr<MessageQueue> createMessageQueue() override;
std::unique_ptr<scheduler::VsyncConfiguration> createVsyncConfiguration(
Fps currentRefreshRate) override;
- std::unique_ptr<Scheduler> createScheduler(const scheduler::RefreshRateConfigs&,
- ISchedulerCallback&) override;
+ std::unique_ptr<Scheduler> createScheduler(
+ const std::shared_ptr<scheduler::RefreshRateConfigs>&, ISchedulerCallback&) override;
sp<SurfaceInterceptor> createSurfaceInterceptor() override;
sp<StartPropertySetThread> createStartPropertySetThread(bool timestampPropertyValue) override;
sp<DisplayDevice> createDisplayDevice(DisplayDeviceCreationArgs&) override;
diff --git a/services/surfaceflinger/SurfaceFlingerFactory.h b/services/surfaceflinger/SurfaceFlingerFactory.h
index 885297fc30..13c95ddd15 100644
--- a/services/surfaceflinger/SurfaceFlingerFactory.h
+++ b/services/surfaceflinger/SurfaceFlingerFactory.h
@@ -79,8 +79,8 @@ public:
virtual std::unique_ptr<MessageQueue> createMessageQueue() = 0;
virtual std::unique_ptr<scheduler::VsyncConfiguration> createVsyncConfiguration(
Fps currentRefreshRate) = 0;
- virtual std::unique_ptr<Scheduler> createScheduler(const scheduler::RefreshRateConfigs&,
- ISchedulerCallback&) = 0;
+ virtual std::unique_ptr<Scheduler> createScheduler(
+ const std::shared_ptr<scheduler::RefreshRateConfigs>&, ISchedulerCallback&) = 0;
virtual sp<SurfaceInterceptor> createSurfaceInterceptor() = 0;
virtual sp<StartPropertySetThread> createStartPropertySetThread(
diff --git a/services/surfaceflinger/SurfaceInterceptor.cpp b/services/surfaceflinger/SurfaceInterceptor.cpp
index 837b2e8924..9be3abefab 100644
--- a/services/surfaceflinger/SurfaceInterceptor.cpp
+++ b/services/surfaceflinger/SurfaceInterceptor.cpp
@@ -161,6 +161,7 @@ void SurfaceInterceptor::addInitialDisplayStateLocked(Increment* increment,
addDisplaySurfaceLocked(transaction, display.sequenceId, display.surface);
addDisplayLayerStackLocked(transaction, display.sequenceId, display.layerStack);
+ addDisplayFlagsLocked(transaction, display.sequenceId, display.flags);
addDisplaySizeLocked(transaction, display.sequenceId, display.width, display.height);
addDisplayProjectionLocked(transaction, display.sequenceId, toRotationInt(display.orientation),
display.layerStackSpaceRect, display.orientedDisplaySpaceRect);
@@ -481,6 +482,9 @@ void SurfaceInterceptor::addDisplayChangesLocked(Transaction* transaction,
if (state.what & DisplayState::eLayerStackChanged) {
addDisplayLayerStackLocked(transaction, sequenceId, state.layerStack);
}
+ if (state.what & DisplayState::eFlagsChanged) {
+ addDisplayFlagsLocked(transaction, sequenceId, state.flags);
+ }
if (state.what & DisplayState::eDisplaySizeChanged) {
addDisplaySizeLocked(transaction, sequenceId, state.width, state.height);
}
@@ -572,6 +576,13 @@ void SurfaceInterceptor::addDisplayLayerStackLocked(Transaction* transaction,
layerStackChange->set_layer_stack(layerStack);
}
+void SurfaceInterceptor::addDisplayFlagsLocked(Transaction* transaction, int32_t sequenceId,
+ uint32_t flags) {
+ DisplayChange* dispChange(createDisplayChangeLocked(transaction, sequenceId));
+ DisplayFlagsChange* flagsChange(dispChange->mutable_flags());
+ flagsChange->set_flags(flags);
+}
+
void SurfaceInterceptor::addDisplaySizeLocked(Transaction* transaction, int32_t sequenceId,
uint32_t w, uint32_t h)
{
diff --git a/services/surfaceflinger/SurfaceInterceptor.h b/services/surfaceflinger/SurfaceInterceptor.h
index c9555969dc..7b331b9f5f 100644
--- a/services/surfaceflinger/SurfaceInterceptor.h
+++ b/services/surfaceflinger/SurfaceInterceptor.h
@@ -48,7 +48,7 @@ using SurfaceChange = surfaceflinger::SurfaceChange;
using Increment = surfaceflinger::Increment;
using DisplayChange = surfaceflinger::DisplayChange;
-constexpr auto DEFAULT_FILENAME = "/data/misc/wmtrace/transaction_trace.pb";
+constexpr auto DEFAULT_FILENAME = "/data/misc/wmtrace/transaction_trace.winscope";
class SurfaceInterceptor : public IBinder::DeathRecipient {
public:
@@ -185,6 +185,7 @@ private:
const sp<const IGraphicBufferProducer>& surface);
void addDisplayLayerStackLocked(Transaction* transaction, int32_t sequenceId,
uint32_t layerStack);
+ void addDisplayFlagsLocked(Transaction* transaction, int32_t sequenceId, uint32_t flags);
void addDisplaySizeLocked(Transaction* transaction, int32_t sequenceId, uint32_t w,
uint32_t h);
void addDisplayProjectionLocked(Transaction* transaction, int32_t sequenceId,
diff --git a/services/surfaceflinger/SurfaceTracing.cpp b/services/surfaceflinger/SurfaceTracing.cpp
index b4d8a9adce..596373732f 100644
--- a/services/surfaceflinger/SurfaceTracing.cpp
+++ b/services/surfaceflinger/SurfaceTracing.cpp
@@ -137,14 +137,19 @@ status_t SurfaceTracing::Runner::stop() {
return writeToFile();
}
+LayersTraceFileProto SurfaceTracing::createLayersTraceFileProto() {
+ LayersTraceFileProto fileProto;
+ fileProto.set_magic_number(uint64_t(LayersTraceFileProto_MagicNumber_MAGIC_NUMBER_H) << 32 |
+ LayersTraceFileProto_MagicNumber_MAGIC_NUMBER_L);
+ return fileProto;
+}
+
status_t SurfaceTracing::Runner::writeToFile() {
ATRACE_CALL();
- LayersTraceFileProto fileProto;
+ LayersTraceFileProto fileProto = createLayersTraceFileProto();
std::string output;
- fileProto.set_magic_number(uint64_t(LayersTraceFileProto_MagicNumber_MAGIC_NUMBER_H) << 32 |
- LayersTraceFileProto_MagicNumber_MAGIC_NUMBER_L);
mBuffer.flush(&fileProto);
mBuffer.reset(mConfig.bufferSize);
@@ -186,7 +191,7 @@ LayersTraceProto SurfaceTracing::Runner::traceLayers(const char* where) {
entry.set_excludes_composition_state(true);
}
entry.set_missed_entries(mMissedTraceEntries);
-
+ mFlinger.dumpDisplayProto(entry);
return entry;
}
diff --git a/services/surfaceflinger/SurfaceTracing.h b/services/surfaceflinger/SurfaceTracing.h
index 15a503d834..cea1a3324e 100644
--- a/services/surfaceflinger/SurfaceTracing.h
+++ b/services/surfaceflinger/SurfaceTracing.h
@@ -73,11 +73,12 @@ public:
};
void setTraceFlags(uint32_t flags) { mConfig.flags = flags; }
bool flagIsSet(uint32_t flags) { return (mConfig.flags & flags) == flags; }
+ static LayersTraceFileProto createLayersTraceFileProto();
private:
class Runner;
static constexpr auto DEFAULT_BUFFER_SIZE = 5_MB;
- static constexpr auto DEFAULT_FILE_NAME = "/data/misc/wmtrace/layers_trace.pb";
+ static constexpr auto DEFAULT_FILE_NAME = "/data/misc/wmtrace/layers_trace.winscope";
SurfaceFlinger& mFlinger;
mutable std::mutex mTraceLock;
diff --git a/services/surfaceflinger/WindowInfosListenerInvoker.cpp b/services/surfaceflinger/WindowInfosListenerInvoker.cpp
new file mode 100644
index 0000000000..dc2aa58c9a
--- /dev/null
+++ b/services/surfaceflinger/WindowInfosListenerInvoker.cpp
@@ -0,0 +1,96 @@
+/*
+ * 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 "WindowInfosListenerInvoker.h"
+#include <gui/ISurfaceComposer.h>
+#include <unordered_set>
+#include "SurfaceFlinger.h"
+
+namespace android {
+
+using gui::IWindowInfosListener;
+using gui::WindowInfo;
+
+struct WindowInfosReportedListener : gui::BnWindowInfosReportedListener {
+ explicit WindowInfosReportedListener(std::function<void()> listenerCb)
+ : mListenerCb(listenerCb) {}
+
+ binder::Status onWindowInfosReported() override {
+ if (mListenerCb != nullptr) {
+ mListenerCb();
+ }
+ return binder::Status::ok();
+ }
+
+ std::function<void()> mListenerCb;
+};
+
+WindowInfosListenerInvoker::WindowInfosListenerInvoker(const sp<SurfaceFlinger>& sf) : mSf(sf) {
+ mWindowInfosReportedListener =
+ new WindowInfosReportedListener([&]() { windowInfosReported(); });
+}
+
+void WindowInfosListenerInvoker::addWindowInfosListener(
+ const sp<IWindowInfosListener>& windowInfosListener) {
+ sp<IBinder> asBinder = IInterface::asBinder(windowInfosListener);
+
+ asBinder->linkToDeath(this);
+ std::scoped_lock lock(mListenersMutex);
+ mWindowInfosListeners.emplace(asBinder, windowInfosListener);
+}
+
+void WindowInfosListenerInvoker::removeWindowInfosListener(
+ const sp<IWindowInfosListener>& windowInfosListener) {
+ sp<IBinder> asBinder = IInterface::asBinder(windowInfosListener);
+
+ std::scoped_lock lock(mListenersMutex);
+ asBinder->unlinkToDeath(this);
+ mWindowInfosListeners.erase(asBinder);
+}
+
+void WindowInfosListenerInvoker::binderDied(const wp<IBinder>& who) {
+ std::scoped_lock lock(mListenersMutex);
+ mWindowInfosListeners.erase(who);
+}
+
+void WindowInfosListenerInvoker::windowInfosChanged(const std::vector<WindowInfo>& windowInfos,
+ bool shouldSync) {
+ std::unordered_set<sp<IWindowInfosListener>, ISurfaceComposer::SpHash<IWindowInfosListener>>
+ windowInfosListeners;
+
+ {
+ std::scoped_lock lock(mListenersMutex);
+ for (const auto& [_, listener] : mWindowInfosListeners) {
+ windowInfosListeners.insert(listener);
+ }
+ }
+
+ mCallbacksPending = windowInfosListeners.size();
+
+ for (const auto& listener : windowInfosListeners) {
+ listener->onWindowInfosChanged(windowInfos,
+ shouldSync ? mWindowInfosReportedListener : nullptr);
+ }
+}
+
+void WindowInfosListenerInvoker::windowInfosReported() {
+ mCallbacksPending--;
+ if (mCallbacksPending == 0) {
+ mSf->windowInfosReported();
+ }
+}
+
+} // namespace android \ No newline at end of file
diff --git a/services/surfaceflinger/WindowInfosListenerInvoker.h b/services/surfaceflinger/WindowInfosListenerInvoker.h
new file mode 100644
index 0000000000..5e5796fe2d
--- /dev/null
+++ b/services/surfaceflinger/WindowInfosListenerInvoker.h
@@ -0,0 +1,57 @@
+/*
+ * 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/gui/BnWindowInfosReportedListener.h>
+#include <android/gui/IWindowInfosListener.h>
+#include <android/gui/IWindowInfosReportedListener.h>
+#include <binder/IBinder.h>
+#include <utils/Mutex.h>
+#include <unordered_map>
+
+namespace android {
+
+class SurfaceFlinger;
+
+class WindowInfosListenerInvoker : public IBinder::DeathRecipient {
+public:
+ WindowInfosListenerInvoker(const sp<SurfaceFlinger>& sf);
+ void addWindowInfosListener(const sp<gui::IWindowInfosListener>& windowInfosListener);
+ void removeWindowInfosListener(const sp<gui::IWindowInfosListener>& windowInfosListener);
+
+ void windowInfosChanged(const std::vector<gui::WindowInfo>& windowInfos, bool shouldSync);
+
+protected:
+ void binderDied(const wp<IBinder>& who) override;
+
+private:
+ void windowInfosReported();
+
+ struct WpHash {
+ size_t operator()(const wp<IBinder>& p) const {
+ return std::hash<IBinder*>()(p.unsafe_get());
+ }
+ };
+
+ const sp<SurfaceFlinger> mSf;
+ std::mutex mListenersMutex;
+ std::unordered_map<wp<IBinder>, const sp<gui::IWindowInfosListener>, WpHash>
+ mWindowInfosListeners GUARDED_BY(mListenersMutex);
+ sp<gui::IWindowInfosReportedListener> mWindowInfosReportedListener;
+ std::atomic<size_t> mCallbacksPending{0};
+};
+} // namespace android \ No newline at end of file
diff --git a/services/surfaceflinger/layerproto/Android.bp b/services/surfaceflinger/layerproto/Android.bp
index c8a2b5eed6..973a4392a2 100644
--- a/services/surfaceflinger/layerproto/Android.bp
+++ b/services/surfaceflinger/layerproto/Android.bp
@@ -13,8 +13,7 @@ cc_library {
srcs: [
"LayerProtoParser.cpp",
- "layers.proto",
- "layerstrace.proto",
+ "*.proto",
],
shared_libs: [
diff --git a/services/surfaceflinger/layerproto/common.proto b/services/surfaceflinger/layerproto/common.proto
new file mode 100644
index 0000000000..1c73a9f4a8
--- /dev/null
+++ b/services/surfaceflinger/layerproto/common.proto
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+
+syntax = "proto3";
+option optimize_for = LITE_RUNTIME;
+package android.surfaceflinger;
+
+message RectProto {
+ int32 left = 1;
+ int32 top = 2;
+ int32 right = 3;
+ int32 bottom = 4;
+}
+
+message SizeProto {
+ int32 w = 1;
+ int32 h = 2;
+}
+
+message TransformProto {
+ float dsdx = 1;
+ float dtdx = 2;
+ float dsdy = 3;
+ float dtdy = 4;
+ int32 type = 5;
+} \ No newline at end of file
diff --git a/services/surfaceflinger/layerproto/display.proto b/services/surfaceflinger/layerproto/display.proto
new file mode 100644
index 0000000000..ee8830e7f2
--- /dev/null
+++ b/services/surfaceflinger/layerproto/display.proto
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+syntax = "proto3";
+option optimize_for = LITE_RUNTIME;
+
+import "frameworks/native/services/surfaceflinger/layerproto/common.proto";
+
+package android.surfaceflinger;
+
+message DisplayProto {
+ uint64 id = 1;
+
+ string name = 2;
+
+ uint32 layer_stack = 3;
+
+ SizeProto size = 4;
+
+ RectProto layer_stack_space_rect = 5;
+
+ TransformProto transform = 6;
+}
diff --git a/services/surfaceflinger/layerproto/layers.proto b/services/surfaceflinger/layerproto/layers.proto
index dddc677715..057eabb8cc 100644
--- a/services/surfaceflinger/layerproto/layers.proto
+++ b/services/surfaceflinger/layerproto/layers.proto
@@ -2,6 +2,9 @@
syntax = "proto3";
option optimize_for = LITE_RUNTIME;
+
+import "frameworks/native/services/surfaceflinger/layerproto/common.proto";
+
package android.surfaceflinger;
// Contains a list of all layers.
@@ -130,6 +133,9 @@ message LayerProto {
repeated BlurRegion blur_regions = 54;
bool is_trusted_overlay = 55;
+
+ // Corner radius explicitly set on layer rather than inherited
+ float requested_corner_radius = 56;
}
message PositionProto {
@@ -137,31 +143,11 @@ message PositionProto {
float y = 2;
}
-message SizeProto {
- int32 w = 1;
- int32 h = 2;
-}
-
-message TransformProto {
- float dsdx = 1;
- float dtdx = 2;
- float dsdy = 3;
- float dtdy = 4;
- int32 type = 5;
-}
-
message RegionProto {
reserved 1; // Previously: uint64 id
repeated RectProto rect = 2;
}
-message RectProto {
- int32 left = 1;
- int32 top = 2;
- int32 right = 3;
- int32 bottom = 4;
-}
-
message FloatRectProto {
float left = 1;
float top = 2;
@@ -228,4 +214,4 @@ message BlurRegion {
int32 top = 8;
int32 right = 9;
int32 bottom = 10;
-} \ No newline at end of file
+}
diff --git a/services/surfaceflinger/layerproto/layerstrace.proto b/services/surfaceflinger/layerproto/layerstrace.proto
index 990f3cffda..13647b669e 100644
--- a/services/surfaceflinger/layerproto/layerstrace.proto
+++ b/services/surfaceflinger/layerproto/layerstrace.proto
@@ -18,6 +18,7 @@ syntax = "proto2";
option optimize_for = LITE_RUNTIME;
import "frameworks/native/services/surfaceflinger/layerproto/layers.proto";
+import "frameworks/native/services/surfaceflinger/layerproto/display.proto";
package android.surfaceflinger;
@@ -57,4 +58,6 @@ message LayersTraceProto {
/* Number of missed entries since the last entry was recorded. */
optional uint32 missed_entries = 6;
+
+ repeated DisplayProto displays = 7;
}
diff --git a/services/surfaceflinger/tests/Android.bp b/services/surfaceflinger/tests/Android.bp
index a36c6ed521..32ad8732ad 100644
--- a/services/surfaceflinger/tests/Android.bp
+++ b/services/surfaceflinger/tests/Android.bp
@@ -51,6 +51,7 @@ cc_test {
"Stress_test.cpp",
"SurfaceInterceptor_test.cpp",
"VirtualDisplay_test.cpp",
+ "WindowInfosListener_test.cpp",
],
data: ["SurfaceFlinger_test.filter"],
static_libs: [
diff --git a/services/surfaceflinger/tests/EffectLayer_test.cpp b/services/surfaceflinger/tests/EffectLayer_test.cpp
index af00ec7fc9..93656f3fd2 100644
--- a/services/surfaceflinger/tests/EffectLayer_test.cpp
+++ b/services/surfaceflinger/tests/EffectLayer_test.cpp
@@ -176,6 +176,15 @@ TEST_F(EffectLayerTest, BlurEffectLayerIsVisible) {
}
}
+TEST_F(EffectLayerTest, EffectLayerWithColorNoCrop) {
+ const auto display = SurfaceComposerClient::getInternalDisplayToken();
+ ui::DisplayMode mode;
+ ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayMode(display, &mode));
+ const ui::Size& resolution = mode.resolution;
+ auto shot = screenshot();
+ shot->expectColor(Rect(0, 0, resolution.getWidth(), resolution.getHeight()), Color::RED);
+}
+
} // namespace android
// TODO(b/129481165): remove the #pragma below and fix conversion issues
diff --git a/services/surfaceflinger/tests/IPC_test.cpp b/services/surfaceflinger/tests/IPC_test.cpp
index 9fa3d4c417..84fea6c751 100644
--- a/services/surfaceflinger/tests/IPC_test.cpp
+++ b/services/surfaceflinger/tests/IPC_test.cpp
@@ -28,8 +28,8 @@
#include <limits>
+#include <gui/test/CallbackUtils.h>
#include "BufferGenerator.h"
-#include "utils/CallbackUtils.h"
#include "utils/ColorUtils.h"
#include "utils/TransactionUtils.h"
diff --git a/services/surfaceflinger/tests/InvalidHandles_test.cpp b/services/surfaceflinger/tests/InvalidHandles_test.cpp
index 9cf7c0909b..d192a2d83d 100644
--- a/services/surfaceflinger/tests/InvalidHandles_test.cpp
+++ b/services/surfaceflinger/tests/InvalidHandles_test.cpp
@@ -52,17 +52,6 @@ protected:
}
};
-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) {
LayerCaptureArgs args;
args.layerHandle = mNotSc->getHandle();
diff --git a/services/surfaceflinger/tests/LayerCallback_test.cpp b/services/surfaceflinger/tests/LayerCallback_test.cpp
index 965aac301d..7ff041ea57 100644
--- a/services/surfaceflinger/tests/LayerCallback_test.cpp
+++ b/services/surfaceflinger/tests/LayerCallback_test.cpp
@@ -18,8 +18,8 @@
#include <gui/DisplayEventReceiver.h>
+#include <gui/test/CallbackUtils.h>
#include "LayerTransactionTest.h"
-#include "utils/CallbackUtils.h"
using namespace std::chrono_literals;
diff --git a/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp
index 43d957cf7a..25f3bb91ae 100644
--- a/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp
+++ b/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp
@@ -208,6 +208,37 @@ TEST_P(LayerTypeAndRenderTypeTransactionTest, SetCornerRadius) {
}
}
+// b/200781179 - don't round a layer without a valid crop
+// This behaviour should be fixed since we treat buffer layers differently than
+// effect or container layers.
+TEST_P(LayerTypeAndRenderTypeTransactionTest, SetCornerRadiusInvalidCrop) {
+ sp<SurfaceControl> parent;
+ sp<SurfaceControl> child;
+ const uint8_t size = 64;
+ const uint8_t testArea = 4;
+ const float cornerRadius = 20.0f;
+ ASSERT_NO_FATAL_FAILURE(parent = createLayer("parent", size, size));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(parent, Color::GREEN, size, size));
+ ASSERT_NO_FATAL_FAILURE(child = createColorLayer("child", Color::RED));
+
+ Transaction().setCornerRadius(child, cornerRadius).reparent(child, parent).show(child).apply();
+ {
+ const uint8_t bottom = size - 1;
+ const uint8_t right = size - 1;
+ auto shot = getScreenCapture();
+ std::this_thread::sleep_for(std::chrono::seconds(5));
+ // Solid corners since we don't round a layer without a valid crop
+ shot->expectColor(Rect(0, 0, testArea, testArea), Color::RED);
+ shot->expectColor(Rect(size - testArea, 0, right, testArea), Color::RED);
+ shot->expectColor(Rect(0, bottom - testArea, testArea, bottom), Color::RED);
+ shot->expectColor(Rect(size - testArea, bottom - testArea, right, bottom), Color::RED);
+ // Solid center
+ shot->expectColor(Rect(size / 2 - testArea / 2, size / 2 - testArea / 2,
+ size / 2 + testArea / 2, size / 2 + testArea / 2),
+ Color::RED);
+ }
+}
+
TEST_P(LayerTypeAndRenderTypeTransactionTest, SetCornerRadiusRotated) {
sp<SurfaceControl> parent;
sp<SurfaceControl> child;
@@ -465,6 +496,95 @@ TEST_P(LayerTypeAndRenderTypeTransactionTest, SetCornerRadiusChildBufferRotation
}
}
+TEST_P(LayerTypeAndRenderTypeTransactionTest, ChildCornerRadiusTakesPrecedence) {
+ sp<SurfaceControl> parent;
+ sp<SurfaceControl> child;
+ const uint32_t size = 64;
+ const uint32_t parentSize = size * 3;
+ const uint32_t testLength = 4;
+ const float cornerRadius = 20.0f;
+ ASSERT_NO_FATAL_FAILURE(parent = createLayer("parent", parentSize, parentSize));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(parent, Color::RED, parentSize, parentSize));
+ ASSERT_NO_FATAL_FAILURE(child = createLayer("child", size, size));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(child, Color::GREEN, size, size));
+
+ Transaction()
+ .setCornerRadius(parent, cornerRadius)
+ .setCornerRadius(child, cornerRadius)
+ .reparent(child, parent)
+ .setPosition(child, size, size)
+ .apply();
+
+ {
+ const uint32_t top = size - 1;
+ const uint32_t left = size - 1;
+ const uint32_t bottom = size * 2 - 1;
+ const uint32_t right = size * 2 - 1;
+ auto shot = getScreenCapture();
+ // Edges are transparent
+ // TL
+ shot->expectColor(Rect(left, top, testLength, testLength), Color::RED);
+ // TR
+ shot->expectColor(Rect(right - testLength, top, right, testLength), Color::RED);
+ // BL
+ shot->expectColor(Rect(left, bottom - testLength, testLength, bottom - testLength),
+ Color::RED);
+ // BR
+ shot->expectColor(Rect(right - testLength, bottom - testLength, right, bottom), Color::RED);
+ // Solid center
+ shot->expectColor(Rect(parentSize / 2 - testLength / 2, parentSize / 2 - testLength / 2,
+ parentSize / 2 + testLength / 2, parentSize / 2 + testLength / 2),
+ Color::GREEN);
+ }
+}
+
+// Test if ParentCornerRadiusTakesPrecedence if the parent corner radius crop is fully contained by
+// the child corner radius crop.
+TEST_P(LayerTypeAndRenderTypeTransactionTest, ParentCornerRadiusTakesPrecedence) {
+ sp<SurfaceControl> parent;
+ sp<SurfaceControl> child;
+ const uint32_t size = 64;
+ const uint32_t parentSize = size * 3;
+ const Rect parentCrop(size + 1, size + 1, size * 2 - 1, size * 2 - 1);
+ const uint32_t testLength = 4;
+ const float cornerRadius = 20.0f;
+ ASSERT_NO_FATAL_FAILURE(parent = createLayer("parent", parentSize, parentSize));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(parent, Color::RED, parentSize, parentSize));
+ ASSERT_NO_FATAL_FAILURE(child = createLayer("child", size, size));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(child, Color::GREEN, size, size));
+
+ Transaction()
+ .setCornerRadius(parent, cornerRadius)
+ .setCrop(parent, parentCrop)
+ .setCornerRadius(child, cornerRadius)
+ .reparent(child, parent)
+ .setPosition(child, size, size)
+ .apply();
+
+ {
+ const uint32_t top = size - 1;
+ const uint32_t left = size - 1;
+ const uint32_t bottom = size * 2 - 1;
+ const uint32_t right = size * 2 - 1;
+ auto shot = getScreenCapture();
+ // Edges are transparent
+ // TL
+ shot->expectColor(Rect(left, top, testLength, testLength), Color::BLACK);
+ // TR
+ shot->expectColor(Rect(right - testLength, top, right, testLength), Color::BLACK);
+ // BL
+ shot->expectColor(Rect(left, bottom - testLength, testLength, bottom - testLength),
+ Color::BLACK);
+ // BR
+ shot->expectColor(Rect(right - testLength, bottom - testLength, right, bottom),
+ Color::BLACK);
+ // Solid center
+ shot->expectColor(Rect(parentSize / 2 - testLength / 2, parentSize / 2 - testLength / 2,
+ parentSize / 2 + testLength / 2, parentSize / 2 + testLength / 2),
+ Color::GREEN);
+ }
+}
+
TEST_P(LayerTypeAndRenderTypeTransactionTest, SetBackgroundBlurRadiusSimple) {
if (!deviceSupportsBlurs()) GTEST_SKIP();
if (!deviceUsesSkiaRenderEngine()) GTEST_SKIP();
diff --git a/services/surfaceflinger/tests/MirrorLayer_test.cpp b/services/surfaceflinger/tests/MirrorLayer_test.cpp
index d02786504e..b7a927129d 100644
--- a/services/surfaceflinger/tests/MirrorLayer_test.cpp
+++ b/services/surfaceflinger/tests/MirrorLayer_test.cpp
@@ -273,6 +273,61 @@ TEST_F(MirrorLayerTest, InitialMirrorState) {
}
}
+// Test that a mirror layer can be screenshot when offscreen
+TEST_F(MirrorLayerTest, OffscreenMirrorScreenshot) {
+ const auto display = SurfaceComposerClient::getInternalDisplayToken();
+ ui::DisplayMode mode;
+ SurfaceComposerClient::getActiveDisplayMode(display, &mode);
+ const ui::Size& size = mode.resolution;
+
+ sp<SurfaceControl> grandchild =
+ createLayer("Grandchild layer", 50, 50, ISurfaceComposerClient::eFXSurfaceBufferState,
+ mChildLayer.get());
+ ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(grandchild, Color::BLUE, 50, 50));
+ Rect childBounds = Rect(50, 50, 450, 450);
+
+ asTransaction([&](Transaction& t) {
+ t.setCrop(grandchild, Rect(0, 0, 50, 50)).show(grandchild);
+ t.setFlags(grandchild, layer_state_t::eLayerOpaque, layer_state_t::eLayerOpaque);
+ });
+
+ sp<SurfaceControl> mirrorLayer = nullptr;
+ {
+ // Run as system to get the ACCESS_SURFACE_FLINGER permission when mirroring
+ UIDFaker f(AID_SYSTEM);
+ // Mirror mChildLayer
+ mirrorLayer = mClient->mirrorSurface(mChildLayer.get());
+ ASSERT_NE(mirrorLayer, nullptr);
+ }
+
+ // Show the mirror layer, but don't reparent to a layer on screen.
+ Transaction().show(mirrorLayer).apply();
+
+ {
+ SCOPED_TRACE("Offscreen Mirror");
+ auto shot = screenshot();
+ shot->expectColor(Rect(0, 0, size.getWidth(), 50), Color::RED);
+ shot->expectColor(Rect(0, 0, 50, size.getHeight()), Color::RED);
+ shot->expectColor(Rect(450, 0, size.getWidth(), size.getHeight()), Color::RED);
+ shot->expectColor(Rect(0, 450, size.getWidth(), size.getHeight()), Color::RED);
+ shot->expectColor(Rect(100, 100, 450, 450), Color::GREEN);
+ shot->expectColor(Rect(50, 50, 100, 100), Color::BLUE);
+ }
+
+ {
+ SCOPED_TRACE("Capture Mirror");
+ // Capture just the mirror layer and child.
+ LayerCaptureArgs captureArgs;
+ captureArgs.layerHandle = mirrorLayer->getHandle();
+ captureArgs.sourceCrop = childBounds;
+ std::unique_ptr<ScreenCapture> shot;
+ ScreenCapture::captureLayers(&shot, captureArgs);
+ shot->expectSize(childBounds.width(), childBounds.height());
+ shot->expectColor(Rect(0, 0, 50, 50), Color::BLUE);
+ shot->expectColor(Rect(50, 50, 400, 400), Color::GREEN);
+ }
+}
+
} // namespace android
// TODO(b/129481165): remove the #pragma below and fix conversion issues
diff --git a/services/surfaceflinger/tests/RefreshRateOverlay_test.cpp b/services/surfaceflinger/tests/RefreshRateOverlay_test.cpp
index 05858bf839..fb4458a27e 100644
--- a/services/surfaceflinger/tests/RefreshRateOverlay_test.cpp
+++ b/services/surfaceflinger/tests/RefreshRateOverlay_test.cpp
@@ -20,6 +20,10 @@
#include <gui/SurfaceComposerClient.h>
#include <private/gui/ComposerService.h>
+#include <chrono>
+
+using ::std::literals::chrono_literals::operator""ms;
+using ::std::literals::chrono_literals::operator""s;
static constexpr int kRefreshRateOverlayCode = 1034;
static constexpr int kRefreshRateOverlayEnable = 1;
diff --git a/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp b/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp
index 579a26ebf4..309ab2f0db 100644
--- a/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp
+++ b/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp
@@ -14,8 +14,8 @@
* limitations under the License.
*/
+#include <gui/test/CallbackUtils.h>
#include "LayerTransactionTest.h"
-#include "utils/CallbackUtils.h"
using namespace std::chrono_literals;
@@ -61,7 +61,7 @@ public:
std::this_thread::sleep_for(300ms);
std::lock_guard lock(mMutex);
- EXPECT_EQ(mCallbackDataQueue.size(), 0) << "extra callbacks received";
+ EXPECT_EQ(mCallbackDataQueue.size(), 0U) << "extra callbacks received";
mCallbackDataQueue = {};
}
@@ -99,10 +99,10 @@ public:
}
static void waitForReleaseBufferCallback(ReleaseBufferCallbackHelper& releaseCallback,
- const ReleaseCallbackId& expectedCallbackId) {
+ const ReleaseCallbackId& expectedReleaseBufferId) {
ReleaseCallbackId actualReleaseBufferId;
releaseCallback.getCallbackData(&actualReleaseBufferId);
- EXPECT_EQ(expectedCallbackId, actualReleaseBufferId);
+ EXPECT_EQ(expectedReleaseBufferId, actualReleaseBufferId);
releaseCallback.verifyNoCallbacks();
}
static ReleaseBufferCallbackHelper* getReleaseBufferCallbackHelper() {
@@ -333,4 +333,60 @@ TEST_F(ReleaseBufferCallbackTest, DISABLED_FrameDropping) {
ASSERT_NO_FATAL_FAILURE(waitForReleaseBufferCallback(*releaseCallback, firstBufferCallbackId));
}
+TEST_F(ReleaseBufferCallbackTest, DISABLED_Merge_Different_Processes) {
+ sp<TransactionCompletedListener> firstCompletedListener = new TransactionCompletedListener();
+ sp<TransactionCompletedListener> secondCompletedListener = new TransactionCompletedListener();
+
+ CallbackHelper callback1, callback2;
+
+ TransactionCompletedListener::setInstance(firstCompletedListener);
+
+ sp<SurfaceControl> layer = createBufferStateLayer();
+ ReleaseBufferCallbackHelper* releaseCallback = getReleaseBufferCallbackHelper();
+
+ sp<GraphicBuffer> firstBuffer = getBuffer();
+ ReleaseCallbackId firstBufferCallbackId(firstBuffer->getId(), generateFrameNumber());
+
+ // Send initial buffer for the layer
+ submitBuffer(layer, firstBuffer, Fence::NO_FENCE, callback1, firstBufferCallbackId,
+ *releaseCallback);
+
+ ExpectedResult expected;
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer,
+ ExpectedResult::Buffer::NOT_ACQUIRED);
+ ASSERT_NO_FATAL_FAILURE(waitForCallback(callback1, expected));
+
+ // Sent a second buffer to allow the first buffer to get released.
+ sp<GraphicBuffer> secondBuffer = getBuffer();
+ ReleaseCallbackId secondBufferCallbackId(secondBuffer->getId(), generateFrameNumber());
+
+ Transaction transaction1;
+ transaction1.setFrameNumber(layer, secondBufferCallbackId.framenumber);
+ transaction1.setBuffer(layer, secondBuffer, secondBufferCallbackId,
+ releaseCallback->getCallback());
+ transaction1.setAcquireFence(layer, Fence::NO_FENCE);
+ transaction1.addTransactionCompletedCallback(callback1.function, callback1.getContext());
+
+ // Set a different TransactionCompletedListener to mimic a second process
+ TransactionCompletedListener::setInstance(secondCompletedListener);
+
+ // Make sure the second "process" has a callback set up.
+ Transaction transaction2;
+ transaction2.addTransactionCompletedCallback(callback2.function, callback2.getContext());
+
+ // This merging order, merge transaction1 first then transaction2, seems to ensure the listener
+ // for transaction2 is ordered first. This makes sure the wrong process is added first to the
+ // layer's vector of listeners. With the bug, only the secondCompletedListener will get the
+ // release callback id, since it's ordered first. Then firstCompletedListener would fail to get
+ // the release callback id and not invoke the release callback.
+ Transaction().merge(std::move(transaction1)).merge(std::move(transaction2)).apply();
+
+ expected = ExpectedResult();
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer,
+ ExpectedResult::Buffer::NOT_ACQUIRED,
+ ExpectedResult::PreviousBuffer::RELEASED);
+ ASSERT_NO_FATAL_FAILURE(waitForCallback(callback1, expected));
+ ASSERT_NO_FATAL_FAILURE(waitForReleaseBufferCallback(*releaseCallback, firstBufferCallbackId));
+}
+
} // namespace android
diff --git a/services/surfaceflinger/tests/ScreenCapture_test.cpp b/services/surfaceflinger/tests/ScreenCapture_test.cpp
index 6912fcf219..2d5b50238c 100644
--- a/services/surfaceflinger/tests/ScreenCapture_test.cpp
+++ b/services/surfaceflinger/tests/ScreenCapture_test.cpp
@@ -37,6 +37,8 @@ protected:
ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayMode(display, &mode));
const ui::Size& resolution = mode.resolution;
+ mDisplaySize = resolution;
+
// Background surface
mBGSurfaceControl = createLayer(String8("BG Test Surface"), resolution.getWidth(),
resolution.getHeight(), 0);
@@ -72,6 +74,7 @@ protected:
sp<SurfaceControl> mBGSurfaceControl;
sp<SurfaceControl> mFGSurfaceControl;
std::unique_ptr<ScreenCapture> mCapture;
+ ui::Size mDisplaySize;
};
TEST_F(ScreenCaptureTest, SetFlagsSecureEUidSystem) {
@@ -515,21 +518,27 @@ TEST_F(ScreenCaptureTest, CaptureSize) {
}
TEST_F(ScreenCaptureTest, CaptureInvalidLayer) {
- sp<SurfaceControl> redLayer = createLayer(String8("Red surface"), 60, 60, 0);
+ LayerCaptureArgs args;
+ args.layerHandle = new BBinder();
+ ScreenCaptureResults captureResults;
+ // Layer was deleted so captureLayers should fail with NAME_NOT_FOUND
+ ASSERT_EQ(NAME_NOT_FOUND, ScreenCapture::captureLayers(args, captureResults));
+}
+
+TEST_F(ScreenCaptureTest, CaptureTooLargeLayer) {
+ sp<SurfaceControl> redLayer = createLayer(String8("Red surface"), 60, 60);
ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(redLayer, Color::RED, 60, 60));
- auto redLayerHandle = redLayer->getHandle();
- Transaction().reparent(redLayer, nullptr).apply();
- redLayer.clear();
- SurfaceComposerClient::Transaction().apply(true);
+ Transaction().show(redLayer).setLayer(redLayer, INT32_MAX).apply(true);
- LayerCaptureArgs args;
- args.layerHandle = redLayerHandle;
+ LayerCaptureArgs captureArgs;
+ captureArgs.layerHandle = redLayer->getHandle();
+ captureArgs.frameScaleX = INT32_MAX / 60;
+ captureArgs.frameScaleY = INT32_MAX / 60;
ScreenCaptureResults captureResults;
- // Layer was deleted so captureLayers should fail with NAME_NOT_FOUND
- ASSERT_EQ(NAME_NOT_FOUND, ScreenCapture::captureLayers(args, captureResults));
+ ASSERT_EQ(BAD_VALUE, ScreenCapture::captureLayers(captureArgs, captureResults));
}
TEST_F(ScreenCaptureTest, CaptureSecureLayer) {
@@ -824,6 +833,33 @@ TEST_F(ScreenCaptureTest, CaptureWithGrayscale) {
Color{expectedColor, expectedColor, expectedColor, 255}, tolerance);
}
+TEST_F(ScreenCaptureTest, CaptureOffscreen) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test layer", 32, 32,
+ ISurfaceComposerClient::eFXSurfaceBufferState,
+ mBGSurfaceControl.get()));
+ ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32));
+
+ Transaction().show(layer).hide(mFGSurfaceControl).reparent(layer, nullptr).apply();
+
+ DisplayCaptureArgs displayCaptureArgs;
+ displayCaptureArgs.displayToken = mDisplay;
+
+ {
+ // Validate that the red layer is not on screen
+ ScreenCapture::captureDisplay(&mCapture, displayCaptureArgs);
+ mCapture->expectColor(Rect(0, 0, mDisplaySize.width, mDisplaySize.height),
+ {63, 63, 195, 255});
+ }
+
+ LayerCaptureArgs captureArgs;
+ captureArgs.layerHandle = layer->getHandle();
+
+ ScreenCapture::captureLayers(&mCapture, captureArgs);
+ mCapture->expectSize(32, 32);
+ mCapture->expectColor(Rect(0, 0, 32, 32), Color::RED);
+}
+
// In the following tests we verify successful skipping of a parent layer,
// so we use the same verification logic and only change how we mutate
// the parent layer to verify that various properties are ignored.
diff --git a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
index d5890ffa79..a42405989f 100644
--- a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
+++ b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
@@ -61,7 +61,7 @@ constexpr auto UNIQUE_TEST_FG_SURFACE_NAME = "FG Interceptor Test Surface#0";
constexpr auto LAYER_NAME = "Layer Create and Delete Test";
constexpr auto UNIQUE_LAYER_NAME = "Layer Create and Delete Test#0";
-constexpr auto DEFAULT_FILENAME = "/data/misc/wmtrace/transaction_trace.pb";
+constexpr auto DEFAULT_FILENAME = "/data/misc/wmtrace/transaction_trace.winscope";
// Fill an RGBA_8888 formatted surface with a single color.
static void fillSurfaceRGBA8(const sp<SurfaceControl>& sc, uint8_t r, uint8_t g, uint8_t b) {
diff --git a/services/surfaceflinger/tests/WindowInfosListener_test.cpp b/services/surfaceflinger/tests/WindowInfosListener_test.cpp
new file mode 100644
index 0000000000..15b79be06c
--- /dev/null
+++ b/services/surfaceflinger/tests/WindowInfosListener_test.cpp
@@ -0,0 +1,137 @@
+/*
+ * 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 <gtest/gtest.h>
+#include <gui/SurfaceComposerClient.h>
+#include <private/android_filesystem_config.h>
+#include <future>
+#include "utils/TransactionUtils.h"
+
+namespace android {
+using Transaction = SurfaceComposerClient::Transaction;
+using gui::WindowInfo;
+
+class WindowInfosListenerTest : public ::testing::Test {
+protected:
+ void SetUp() override {
+ seteuid(AID_SYSTEM);
+ mClient = new SurfaceComposerClient;
+ mWindowInfosListener = new SyncWindowInfosListener();
+ mClient->addWindowInfosListener(mWindowInfosListener);
+ }
+
+ void TearDown() override {
+ mClient->removeWindowInfosListener(mWindowInfosListener);
+ seteuid(AID_ROOT);
+ }
+
+ struct SyncWindowInfosListener : public gui::WindowInfosListener {
+ public:
+ void onWindowInfosChanged(const std::vector<WindowInfo>& windowInfos) override {
+ windowInfosPromise.set_value(windowInfos);
+ }
+
+ std::vector<WindowInfo> waitForWindowInfos() {
+ std::future<std::vector<WindowInfo>> windowInfosFuture =
+ windowInfosPromise.get_future();
+ std::vector<WindowInfo> windowInfos = windowInfosFuture.get();
+ windowInfosPromise = std::promise<std::vector<WindowInfo>>();
+ return windowInfos;
+ }
+
+ private:
+ std::promise<std::vector<WindowInfo>> windowInfosPromise;
+ };
+
+ sp<SurfaceComposerClient> mClient;
+ sp<SyncWindowInfosListener> mWindowInfosListener;
+};
+
+std::optional<WindowInfo> findMatchingWindowInfo(WindowInfo targetWindowInfo,
+ std::vector<WindowInfo> windowInfos) {
+ std::optional<WindowInfo> foundWindowInfo = std::nullopt;
+ for (WindowInfo windowInfo : windowInfos) {
+ if (windowInfo.token == targetWindowInfo.token) {
+ foundWindowInfo = std::make_optional<>(windowInfo);
+ break;
+ }
+ }
+
+ return foundWindowInfo;
+}
+
+TEST_F(WindowInfosListenerTest, WindowInfoAddedAndRemoved) {
+ std::string name = "Test Layer";
+ sp<IBinder> token = new BBinder();
+ WindowInfo windowInfo;
+ windowInfo.name = name;
+ windowInfo.token = token;
+ sp<SurfaceControl> surfaceControl =
+ mClient->createSurface(String8(name.c_str()), 100, 100, PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eFXSurfaceBufferState);
+
+ Transaction()
+ .setLayerStack(surfaceControl, 0)
+ .show(surfaceControl)
+ .setLayer(surfaceControl, INT32_MAX - 1)
+ .setInputWindowInfo(surfaceControl, windowInfo)
+ .apply();
+
+ std::vector<WindowInfo> windowInfos = mWindowInfosListener->waitForWindowInfos();
+ std::optional<WindowInfo> foundWindowInfo = findMatchingWindowInfo(windowInfo, windowInfos);
+ ASSERT_NE(std::nullopt, foundWindowInfo);
+
+ Transaction().reparent(surfaceControl, nullptr).apply();
+
+ windowInfos = mWindowInfosListener->waitForWindowInfos();
+ foundWindowInfo = findMatchingWindowInfo(windowInfo, windowInfos);
+ ASSERT_EQ(std::nullopt, foundWindowInfo);
+}
+
+TEST_F(WindowInfosListenerTest, WindowInfoChanged) {
+ std::string name = "Test Layer";
+ sp<IBinder> token = new BBinder();
+ WindowInfo windowInfo;
+ windowInfo.name = name;
+ windowInfo.token = token;
+ sp<SurfaceControl> surfaceControl =
+ mClient->createSurface(String8(name.c_str()), 100, 100, PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eFXSurfaceBufferState);
+ const Rect crop(0, 0, 100, 100);
+ Transaction()
+ .setLayerStack(surfaceControl, 0)
+ .show(surfaceControl)
+ .setLayer(surfaceControl, INT32_MAX - 1)
+ .setCrop(surfaceControl, crop)
+ .setInputWindowInfo(surfaceControl, windowInfo)
+ .apply();
+
+ std::vector<WindowInfo> windowInfos = mWindowInfosListener->waitForWindowInfos();
+ std::optional<WindowInfo> foundWindowInfo = findMatchingWindowInfo(windowInfo, windowInfos);
+ ASSERT_NE(std::nullopt, foundWindowInfo);
+ ASSERT_TRUE(foundWindowInfo->touchableRegion.isEmpty());
+
+ Rect touchableRegions(0, 0, 50, 50);
+ windowInfo.addTouchableRegion(Rect(0, 0, 50, 50));
+ Transaction().setInputWindowInfo(surfaceControl, windowInfo).apply();
+
+ windowInfos = mWindowInfosListener->waitForWindowInfos();
+ foundWindowInfo = findMatchingWindowInfo(windowInfo, windowInfos);
+ ASSERT_NE(std::nullopt, foundWindowInfo);
+ ASSERT_TRUE(foundWindowInfo->touchableRegion.hasSameRects(windowInfo.touchableRegion));
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index b5086fafb7..9e704c32fc 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -51,6 +51,7 @@ cc_test {
"DisplayIdGeneratorTest.cpp",
"DisplayTransactionTest.cpp",
"DisplayDevice_GetBestColorModeTest.cpp",
+ "DisplayDevice_InitiateModeChange.cpp",
"DisplayDevice_SetProjectionTest.cpp",
"EventThreadTest.cpp",
"FpsReporterTest.cpp",
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index 560f139719..52a36a2719 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -108,6 +108,8 @@ public:
mComposer = new Hwc2::mock::Composer();
mFlinger.setupComposer(std::unique_ptr<Hwc2::Composer>(mComposer));
+
+ mFlinger.mutableMaxRenderTargetSize() = 16384;
}
~CompositionTest() {
@@ -519,8 +521,6 @@ struct BaseLayerProperties {
static void setupLatchedBuffer(CompositionTest* test, sp<BufferQueueLayer> layer) {
// TODO: Eliminate the complexity of actually creating a buffer
- EXPECT_CALL(*test->mRenderEngine, getMaxTextureSize()).WillOnce(Return(16384));
- EXPECT_CALL(*test->mRenderEngine, getMaxViewportDims()).WillOnce(Return(16384));
status_t err =
layer->setDefaultBufferProperties(LayerProperties::WIDTH, LayerProperties::HEIGHT,
LayerProperties::FORMAT);
diff --git a/services/surfaceflinger/tests/unittests/DisplayDevice_InitiateModeChange.cpp b/services/surfaceflinger/tests/unittests/DisplayDevice_InitiateModeChange.cpp
new file mode 100644
index 0000000000..d4cfbbbe0c
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/DisplayDevice_InitiateModeChange.cpp
@@ -0,0 +1,173 @@
+/*
+ * 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.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "LibSurfaceFlingerUnittests"
+
+#include "DisplayTransactionTestHelpers.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+namespace android {
+namespace {
+
+using FakeDisplayDeviceInjector = TestableSurfaceFlinger::FakeDisplayDeviceInjector;
+
+class InitiateModeChangeTest : public DisplayTransactionTest {
+public:
+ using Event = scheduler::RefreshRateConfigEvent;
+
+ void SetUp() override {
+ injectFakeBufferQueueFactory();
+ injectFakeNativeWindowSurfaceFactory();
+
+ PrimaryDisplayVariant::setupHwcHotplugCallExpectations(this);
+ PrimaryDisplayVariant::setupFramebufferConsumerBufferQueueCallExpectations(this);
+ PrimaryDisplayVariant::setupFramebufferProducerBufferQueueCallExpectations(this);
+ PrimaryDisplayVariant::setupNativeWindowSurfaceCreationCallExpectations(this);
+ PrimaryDisplayVariant::setupHwcGetActiveConfigCallExpectations(this);
+
+ mFlinger.onComposerHalHotplug(PrimaryDisplayVariant::HWC_DISPLAY_ID, Connection::CONNECTED);
+
+ mDisplay = PrimaryDisplayVariant::makeFakeExistingDisplayInjector(this)
+ .setSupportedModes({kDisplayMode60, kDisplayMode90, kDisplayMode120})
+ .setActiveMode(kDisplayModeId60)
+ .inject();
+ }
+
+protected:
+ sp<DisplayDevice> mDisplay;
+
+ const DisplayModeId kDisplayModeId60 = DisplayModeId(0);
+ const DisplayModePtr kDisplayMode60 =
+ DisplayMode::Builder(hal::HWConfigId(kDisplayModeId60.value()))
+ .setId(kDisplayModeId60)
+ .setPhysicalDisplayId(PrimaryDisplayVariant::DISPLAY_ID::get())
+ .setVsyncPeriod(int32_t(16'666'667))
+ .setGroup(0)
+ .setHeight(1000)
+ .setWidth(1000)
+ .build();
+
+ const DisplayModeId kDisplayModeId90 = DisplayModeId(1);
+ const DisplayModePtr kDisplayMode90 =
+ DisplayMode::Builder(hal::HWConfigId(kDisplayModeId90.value()))
+ .setId(kDisplayModeId90)
+ .setPhysicalDisplayId(PrimaryDisplayVariant::DISPLAY_ID::get())
+ .setVsyncPeriod(int32_t(11'111'111))
+ .setGroup(0)
+ .setHeight(1000)
+ .setWidth(1000)
+ .build();
+
+ const DisplayModeId kDisplayModeId120 = DisplayModeId(2);
+ const DisplayModePtr kDisplayMode120 =
+ DisplayMode::Builder(hal::HWConfigId(kDisplayModeId120.value()))
+ .setId(kDisplayModeId120)
+ .setPhysicalDisplayId(PrimaryDisplayVariant::DISPLAY_ID::get())
+ .setVsyncPeriod(int32_t(8'333'333))
+ .setGroup(0)
+ .setHeight(1000)
+ .setWidth(1000)
+ .build();
+};
+
+TEST_F(InitiateModeChangeTest, setDesiredActiveMode_setCurrentMode) {
+ EXPECT_FALSE(mDisplay->setDesiredActiveMode({kDisplayMode60, Event::None}));
+ EXPECT_EQ(std::nullopt, mDisplay->getDesiredActiveMode());
+}
+
+TEST_F(InitiateModeChangeTest, setDesiredActiveMode_setNewMode) {
+ EXPECT_TRUE(mDisplay->setDesiredActiveMode({kDisplayMode90, Event::None}));
+ ASSERT_NE(std::nullopt, mDisplay->getDesiredActiveMode());
+ EXPECT_EQ(kDisplayMode90, mDisplay->getDesiredActiveMode()->mode);
+ EXPECT_EQ(Event::None, mDisplay->getDesiredActiveMode()->event);
+
+ // Setting another mode should be cached but return false
+ EXPECT_FALSE(mDisplay->setDesiredActiveMode({kDisplayMode120, Event::None}));
+ ASSERT_NE(std::nullopt, mDisplay->getDesiredActiveMode());
+ EXPECT_EQ(kDisplayMode120, mDisplay->getDesiredActiveMode()->mode);
+ EXPECT_EQ(Event::None, mDisplay->getDesiredActiveMode()->event);
+}
+
+TEST_F(InitiateModeChangeTest, clearDesiredActiveModeState) {
+ EXPECT_TRUE(mDisplay->setDesiredActiveMode({kDisplayMode90, Event::None}));
+ ASSERT_NE(std::nullopt, mDisplay->getDesiredActiveMode());
+
+ mDisplay->clearDesiredActiveModeState();
+ ASSERT_EQ(std::nullopt, mDisplay->getDesiredActiveMode());
+}
+
+TEST_F(InitiateModeChangeTest, initiateModeChange) NO_THREAD_SAFETY_ANALYSIS {
+ EXPECT_TRUE(mDisplay->setDesiredActiveMode({kDisplayMode90, Event::None}));
+ ASSERT_NE(std::nullopt, mDisplay->getDesiredActiveMode());
+ EXPECT_EQ(kDisplayMode90, mDisplay->getDesiredActiveMode()->mode);
+ EXPECT_EQ(Event::None, mDisplay->getDesiredActiveMode()->event);
+
+ hal::VsyncPeriodChangeConstraints constraints{
+ .desiredTimeNanos = systemTime(),
+ .seamlessRequired = false,
+ };
+ hal::VsyncPeriodChangeTimeline timeline;
+ EXPECT_EQ(OK,
+ mDisplay->initiateModeChange(*mDisplay->getDesiredActiveMode(), constraints,
+ &timeline));
+ EXPECT_EQ(kDisplayMode90, mDisplay->getUpcomingActiveMode().mode);
+ EXPECT_EQ(Event::None, mDisplay->getUpcomingActiveMode().event);
+
+ mDisplay->clearDesiredActiveModeState();
+ ASSERT_EQ(std::nullopt, mDisplay->getDesiredActiveMode());
+}
+
+TEST_F(InitiateModeChangeTest, getUpcomingActiveMode_desiredActiveModeChanged)
+NO_THREAD_SAFETY_ANALYSIS {
+ EXPECT_TRUE(mDisplay->setDesiredActiveMode({kDisplayMode90, Event::None}));
+ ASSERT_NE(std::nullopt, mDisplay->getDesiredActiveMode());
+ EXPECT_EQ(kDisplayMode90, mDisplay->getDesiredActiveMode()->mode);
+ EXPECT_EQ(Event::None, mDisplay->getDesiredActiveMode()->event);
+
+ hal::VsyncPeriodChangeConstraints constraints{
+ .desiredTimeNanos = systemTime(),
+ .seamlessRequired = false,
+ };
+ hal::VsyncPeriodChangeTimeline timeline;
+ EXPECT_EQ(OK,
+ mDisplay->initiateModeChange(*mDisplay->getDesiredActiveMode(), constraints,
+ &timeline));
+ EXPECT_EQ(kDisplayMode90, mDisplay->getUpcomingActiveMode().mode);
+ EXPECT_EQ(Event::None, mDisplay->getUpcomingActiveMode().event);
+
+ EXPECT_FALSE(mDisplay->setDesiredActiveMode({kDisplayMode120, Event::None}));
+ ASSERT_NE(std::nullopt, mDisplay->getDesiredActiveMode());
+ EXPECT_EQ(kDisplayMode120, mDisplay->getDesiredActiveMode()->mode);
+ EXPECT_EQ(Event::None, mDisplay->getDesiredActiveMode()->event);
+
+ EXPECT_EQ(kDisplayMode90, mDisplay->getUpcomingActiveMode().mode);
+ EXPECT_EQ(Event::None, mDisplay->getUpcomingActiveMode().event);
+
+ EXPECT_EQ(OK,
+ mDisplay->initiateModeChange(*mDisplay->getDesiredActiveMode(), constraints,
+ &timeline));
+ EXPECT_EQ(kDisplayMode120, mDisplay->getUpcomingActiveMode().mode);
+ EXPECT_EQ(Event::None, mDisplay->getUpcomingActiveMode().event);
+
+ mDisplay->clearDesiredActiveModeState();
+ ASSERT_EQ(std::nullopt, mDisplay->getDesiredActiveMode());
+}
+
+} // namespace
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
index 6ce281d403..de058a4f68 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
@@ -615,8 +615,8 @@ struct HwcVirtualDisplayVariant
}
static void setupHwcVirtualDisplayCreationCallExpectations(DisplayTransactionTest* test) {
- EXPECT_CALL(*test->mComposer, createVirtualDisplay(Base::WIDTH, Base::HEIGHT, _, _, _))
- .WillOnce(DoAll(SetArgPointee<4>(Self::HWC_DISPLAY_ID), Return(Error::NONE)));
+ EXPECT_CALL(*test->mComposer, createVirtualDisplay(Base::WIDTH, Base::HEIGHT, _, _))
+ .WillOnce(DoAll(SetArgPointee<3>(Self::HWC_DISPLAY_ID), Return(Error::NONE)));
EXPECT_CALL(*test->mComposer, setClientTargetSlotCount(_)).WillOnce(Return(Error::NONE));
}
};
diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
index b4a1481e9c..4ff7592b71 100644
--- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
+++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
@@ -543,17 +543,34 @@ TEST_F(EventThreadTest, postHotplugExternalConnect) {
}
TEST_F(EventThreadTest, postConfigChangedPrimary) {
- mThread->onModeChanged(INTERNAL_DISPLAY_ID, DisplayModeId(7), 16666666);
+ const auto mode = DisplayMode::Builder(hal::HWConfigId(0))
+ .setPhysicalDisplayId(INTERNAL_DISPLAY_ID)
+ .setId(DisplayModeId(7))
+ .setVsyncPeriod(16666666)
+ .build();
+
+ mThread->onModeChanged(mode);
expectConfigChangedEventReceivedByConnection(INTERNAL_DISPLAY_ID, 7, 16666666);
}
TEST_F(EventThreadTest, postConfigChangedExternal) {
- mThread->onModeChanged(EXTERNAL_DISPLAY_ID, DisplayModeId(5), 16666666);
+ const auto mode = DisplayMode::Builder(hal::HWConfigId(0))
+ .setPhysicalDisplayId(EXTERNAL_DISPLAY_ID)
+ .setId(DisplayModeId(5))
+ .setVsyncPeriod(16666666)
+ .build();
+
+ mThread->onModeChanged(mode);
expectConfigChangedEventReceivedByConnection(EXTERNAL_DISPLAY_ID, 5, 16666666);
}
TEST_F(EventThreadTest, postConfigChangedPrimary64bit) {
- mThread->onModeChanged(DISPLAY_ID_64BIT, DisplayModeId(7), 16666666);
+ const auto mode = DisplayMode::Builder(hal::HWConfigId(0))
+ .setPhysicalDisplayId(DISPLAY_ID_64BIT)
+ .setId(DisplayModeId(7))
+ .setVsyncPeriod(16666666)
+ .build();
+ mThread->onModeChanged(mode);
expectConfigChangedEventReceivedByConnection(DISPLAY_ID_64BIT, 7, 16666666);
}
@@ -562,7 +579,13 @@ TEST_F(EventThreadTest, suppressConfigChanged) {
sp<MockEventThreadConnection> suppressConnection =
createConnection(suppressConnectionEventRecorder);
- mThread->onModeChanged(INTERNAL_DISPLAY_ID, DisplayModeId(9), 16666666);
+ const auto mode = DisplayMode::Builder(hal::HWConfigId(0))
+ .setPhysicalDisplayId(INTERNAL_DISPLAY_ID)
+ .setId(DisplayModeId(9))
+ .setVsyncPeriod(16666666)
+ .build();
+
+ mThread->onModeChanged(mode);
expectConfigChangedEventReceivedByConnection(INTERNAL_DISPLAY_ID, 9, 16666666);
auto args = suppressConnectionEventRecorder.waitForCall();
diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
index b67ebcaa49..02ec7fc493 100644
--- a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
@@ -35,6 +35,7 @@
using testing::_;
using testing::Return;
+using testing::ReturnRef;
namespace android {
@@ -62,6 +63,10 @@ protected:
LayerHistory& history() { return *mScheduler->mutableLayerHistory(); }
const LayerHistory& history() const { return *mScheduler->mutableLayerHistory(); }
+ LayerHistory::Summary summarizeLayerHistory(nsecs_t now) {
+ return history().summarize(*mScheduler->refreshRateConfigs(), now);
+ }
+
size_t layerCount() const { return mScheduler->layerHistorySize(); }
size_t activeLayerCount() const NO_THREAD_SAFETY_ANALYSIS { return history().mActiveLayersEnd; }
@@ -101,7 +106,7 @@ protected:
history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
time += frameRate.getPeriodNsecs();
- summary = history().summarize(time);
+ summary = summarizeLayerHistory(time);
}
ASSERT_EQ(1, summary.size());
@@ -110,21 +115,24 @@ protected:
<< "Frame rate is " << frameRate;
}
- RefreshRateConfigs mConfigs{{DisplayMode::Builder(0)
- .setId(DisplayModeId(0))
- .setVsyncPeriod(int32_t(LO_FPS_PERIOD))
- .setGroup(0)
- .build(),
- DisplayMode::Builder(1)
- .setId(DisplayModeId(1))
- .setVsyncPeriod(int32_t(HI_FPS_PERIOD))
- .setGroup(0)
- .build()},
- DisplayModeId(0)};
-
- mock::NoOpSchedulerCallback mSchedulerCallback;
-
- TestableScheduler* const mScheduler = new TestableScheduler(mConfigs, mSchedulerCallback);
+ std::shared_ptr<RefreshRateConfigs> mConfigs = std::make_shared<
+ RefreshRateConfigs>(DisplayModes{DisplayMode::Builder(0)
+ .setId(DisplayModeId(0))
+ .setPhysicalDisplayId(PhysicalDisplayId(0))
+ .setVsyncPeriod(int32_t(LO_FPS_PERIOD))
+ .setGroup(0)
+ .build(),
+ DisplayMode::Builder(1)
+ .setId(DisplayModeId(1))
+ .setPhysicalDisplayId(PhysicalDisplayId(0))
+ .setVsyncPeriod(int32_t(HI_FPS_PERIOD))
+ .setGroup(0)
+ .build()},
+ DisplayModeId(0));
+
+ mock::SchedulerCallback mSchedulerCallback;
+
+ TestableScheduler* mScheduler = new TestableScheduler(mConfigs, mSchedulerCallback);
TestableSurfaceFlinger mFlinger;
};
@@ -142,22 +150,22 @@ TEST_F(LayerHistoryTest, oneLayer) {
const nsecs_t time = systemTime();
// No layers returned if no layers are active.
- EXPECT_TRUE(history().summarize(time).empty());
+ EXPECT_TRUE(summarizeLayerHistory(time).empty());
EXPECT_EQ(0, activeLayerCount());
// Max returned if active layers have insufficient history.
for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE - 1; i++) {
history().record(layer.get(), 0, time, LayerHistory::LayerUpdateType::Buffer);
- ASSERT_EQ(1, history().summarize(time).size());
- EXPECT_EQ(LayerHistory::LayerVoteType::Max, history().summarize(time)[0].vote);
+ ASSERT_EQ(1, summarizeLayerHistory(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote);
EXPECT_EQ(1, activeLayerCount());
}
// Max is returned since we have enough history but there is no timestamp votes.
for (int i = 0; i < 10; i++) {
history().record(layer.get(), 0, time, LayerHistory::LayerUpdateType::Buffer);
- ASSERT_EQ(1, history().summarize(time).size());
- EXPECT_EQ(LayerHistory::LayerVoteType::Max, history().summarize(time)[0].vote);
+ ASSERT_EQ(1, summarizeLayerHistory(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote);
EXPECT_EQ(1, activeLayerCount());
}
}
@@ -173,17 +181,17 @@ TEST_F(LayerHistoryTest, oneInvisibleLayer) {
nsecs_t time = systemTime();
history().record(layer.get(), 0, time, LayerHistory::LayerUpdateType::Buffer);
- auto summary = history().summarize(time);
- ASSERT_EQ(1, history().summarize(time).size());
+ auto summary = summarizeLayerHistory(time);
+ ASSERT_EQ(1, summarizeLayerHistory(time).size());
// Layer is still considered inactive so we expect to get Min
- EXPECT_EQ(LayerHistory::LayerVoteType::Max, history().summarize(time)[0].vote);
+ EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote);
EXPECT_EQ(1, activeLayerCount());
EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(false));
history().record(layer.get(), 0, time, LayerHistory::LayerUpdateType::Buffer);
- summary = history().summarize(time);
- EXPECT_TRUE(history().summarize(time).empty());
+ summary = summarizeLayerHistory(time);
+ EXPECT_TRUE(summarizeLayerHistory(time).empty());
EXPECT_EQ(0, activeLayerCount());
}
@@ -201,9 +209,9 @@ TEST_F(LayerHistoryTest, explicitTimestamp) {
time += LO_FPS_PERIOD;
}
- ASSERT_EQ(1, history().summarize(time).size());
- EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, history().summarize(time)[0].vote);
- EXPECT_TRUE(LO_FPS.equalsWithMargin(history().summarize(time)[0].desiredRefreshRate));
+ ASSERT_EQ(1, summarizeLayerHistory(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summarizeLayerHistory(time)[0].vote);
+ EXPECT_TRUE(LO_FPS.equalsWithMargin(summarizeLayerHistory(time)[0].desiredRefreshRate));
EXPECT_EQ(1, activeLayerCount());
EXPECT_EQ(1, frequentLayerCount(time));
}
@@ -224,13 +232,13 @@ TEST_F(LayerHistoryTest, oneLayerNoVote) {
time += HI_FPS_PERIOD;
}
- ASSERT_TRUE(history().summarize(time).empty());
+ ASSERT_TRUE(summarizeLayerHistory(time).empty());
EXPECT_EQ(1, activeLayerCount());
EXPECT_EQ(1, frequentLayerCount(time));
// layer became inactive
time += MAX_ACTIVE_LAYER_PERIOD_NS.count();
- ASSERT_TRUE(history().summarize(time).empty());
+ ASSERT_TRUE(summarizeLayerHistory(time).empty());
EXPECT_EQ(0, activeLayerCount());
EXPECT_EQ(0, frequentLayerCount(time));
}
@@ -251,14 +259,14 @@ TEST_F(LayerHistoryTest, oneLayerMinVote) {
time += HI_FPS_PERIOD;
}
- ASSERT_EQ(1, history().summarize(time).size());
- EXPECT_EQ(LayerHistory::LayerVoteType::Min, history().summarize(time)[0].vote);
+ ASSERT_EQ(1, summarizeLayerHistory(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Min, summarizeLayerHistory(time)[0].vote);
EXPECT_EQ(1, activeLayerCount());
EXPECT_EQ(1, frequentLayerCount(time));
// layer became inactive
time += MAX_ACTIVE_LAYER_PERIOD_NS.count();
- ASSERT_TRUE(history().summarize(time).empty());
+ ASSERT_TRUE(summarizeLayerHistory(time).empty());
EXPECT_EQ(0, activeLayerCount());
EXPECT_EQ(0, frequentLayerCount(time));
}
@@ -279,14 +287,14 @@ TEST_F(LayerHistoryTest, oneLayerMaxVote) {
time += LO_FPS_PERIOD;
}
- ASSERT_EQ(1, history().summarize(time).size());
- EXPECT_EQ(LayerHistory::LayerVoteType::Max, history().summarize(time)[0].vote);
+ ASSERT_EQ(1, summarizeLayerHistory(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote);
EXPECT_EQ(1, activeLayerCount());
EXPECT_EQ(1, frequentLayerCount(time));
// layer became inactive
time += MAX_ACTIVE_LAYER_PERIOD_NS.count();
- ASSERT_TRUE(history().summarize(time).empty());
+ ASSERT_TRUE(summarizeLayerHistory(time).empty());
EXPECT_EQ(0, activeLayerCount());
EXPECT_EQ(0, frequentLayerCount(time));
}
@@ -307,18 +315,18 @@ TEST_F(LayerHistoryTest, oneLayerExplicitVote) {
time += HI_FPS_PERIOD;
}
- ASSERT_EQ(1, history().summarize(time).size());
- EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitDefault, history().summarize(time)[0].vote);
- EXPECT_TRUE(Fps(73.4f).equalsWithMargin(history().summarize(time)[0].desiredRefreshRate));
+ ASSERT_EQ(1, summarizeLayerHistory(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitDefault, summarizeLayerHistory(time)[0].vote);
+ EXPECT_TRUE(Fps(73.4f).equalsWithMargin(summarizeLayerHistory(time)[0].desiredRefreshRate));
EXPECT_EQ(1, activeLayerCount());
EXPECT_EQ(1, frequentLayerCount(time));
// layer became inactive, but the vote stays
setDefaultLayerVote(layer.get(), LayerHistory::LayerVoteType::Heuristic);
time += MAX_ACTIVE_LAYER_PERIOD_NS.count();
- ASSERT_EQ(1, history().summarize(time).size());
- EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitDefault, history().summarize(time)[0].vote);
- EXPECT_TRUE(Fps(73.4f).equalsWithMargin(history().summarize(time)[0].desiredRefreshRate));
+ ASSERT_EQ(1, summarizeLayerHistory(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitDefault, summarizeLayerHistory(time)[0].vote);
+ EXPECT_TRUE(Fps(73.4f).equalsWithMargin(summarizeLayerHistory(time)[0].desiredRefreshRate));
EXPECT_EQ(1, activeLayerCount());
EXPECT_EQ(0, frequentLayerCount(time));
}
@@ -339,20 +347,20 @@ TEST_F(LayerHistoryTest, oneLayerExplicitExactVote) {
time += HI_FPS_PERIOD;
}
- ASSERT_EQ(1, history().summarize(time).size());
+ ASSERT_EQ(1, summarizeLayerHistory(time).size());
EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitExactOrMultiple,
- history().summarize(time)[0].vote);
- EXPECT_TRUE(Fps(73.4f).equalsWithMargin(history().summarize(time)[0].desiredRefreshRate));
+ summarizeLayerHistory(time)[0].vote);
+ EXPECT_TRUE(Fps(73.4f).equalsWithMargin(summarizeLayerHistory(time)[0].desiredRefreshRate));
EXPECT_EQ(1, activeLayerCount());
EXPECT_EQ(1, frequentLayerCount(time));
// layer became inactive, but the vote stays
setDefaultLayerVote(layer.get(), LayerHistory::LayerVoteType::Heuristic);
time += MAX_ACTIVE_LAYER_PERIOD_NS.count();
- ASSERT_EQ(1, history().summarize(time).size());
+ ASSERT_EQ(1, summarizeLayerHistory(time).size());
EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitExactOrMultiple,
- history().summarize(time)[0].vote);
- EXPECT_TRUE(Fps(73.4f).equalsWithMargin(history().summarize(time)[0].desiredRefreshRate));
+ summarizeLayerHistory(time)[0].vote);
+ EXPECT_TRUE(Fps(73.4f).equalsWithMargin(summarizeLayerHistory(time)[0].desiredRefreshRate));
EXPECT_EQ(1, activeLayerCount());
EXPECT_EQ(0, frequentLayerCount(time));
}
@@ -383,7 +391,7 @@ TEST_F(LayerHistoryTest, multipleLayers) {
for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
history().record(layer1.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
time += MAX_FREQUENT_LAYER_PERIOD_NS.count();
- summary = history().summarize(time);
+ summary = summarizeLayerHistory(time);
}
ASSERT_EQ(1, summary.size());
@@ -395,7 +403,7 @@ TEST_F(LayerHistoryTest, multipleLayers) {
for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
history().record(layer2.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
time += HI_FPS_PERIOD;
- summary = history().summarize(time);
+ summary = summarizeLayerHistory(time);
}
// layer1 is still active but infrequent.
@@ -404,7 +412,7 @@ TEST_F(LayerHistoryTest, multipleLayers) {
ASSERT_EQ(2, summary.size());
EXPECT_EQ(LayerHistory::LayerVoteType::Min, summary[0].vote);
ASSERT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[1].vote);
- EXPECT_TRUE(HI_FPS.equalsWithMargin(history().summarize(time)[1].desiredRefreshRate));
+ EXPECT_TRUE(HI_FPS.equalsWithMargin(summarizeLayerHistory(time)[1].desiredRefreshRate));
EXPECT_EQ(2, activeLayerCount());
EXPECT_EQ(1, frequentLayerCount(time));
@@ -414,7 +422,7 @@ TEST_F(LayerHistoryTest, multipleLayers) {
for (int i = 0; i < 2 * PRESENT_TIME_HISTORY_SIZE; i++) {
history().record(layer2.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
time += LO_FPS_PERIOD;
- summary = history().summarize(time);
+ summary = summarizeLayerHistory(time);
}
ASSERT_EQ(1, summary.size());
@@ -433,7 +441,7 @@ TEST_F(LayerHistoryTest, multipleLayers) {
history().record(layer3.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
time += HI_FPS_PERIOD;
- summary = history().summarize(time);
+ summary = summarizeLayerHistory(time);
}
ASSERT_EQ(2, summary.size());
@@ -445,7 +453,7 @@ TEST_F(LayerHistoryTest, multipleLayers) {
// layer3 becomes recently active.
history().record(layer3.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
- summary = history().summarize(time);
+ summary = summarizeLayerHistory(time);
ASSERT_EQ(2, summary.size());
EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote);
EXPECT_TRUE(LO_FPS.equalsWithMargin(summary[0].desiredRefreshRate));
@@ -456,7 +464,7 @@ TEST_F(LayerHistoryTest, multipleLayers) {
// layer1 expires.
layer1.clear();
- summary = history().summarize(time);
+ summary = summarizeLayerHistory(time);
ASSERT_EQ(2, summary.size());
EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote);
EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote);
@@ -472,7 +480,7 @@ TEST_F(LayerHistoryTest, multipleLayers) {
for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
history().record(layer2.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
time += LO_FPS_PERIOD;
- summary = history().summarize(time);
+ summary = summarizeLayerHistory(time);
}
ASSERT_EQ(1, summary.size());
@@ -483,7 +491,7 @@ TEST_F(LayerHistoryTest, multipleLayers) {
// layer2 expires.
layer2.clear();
- summary = history().summarize(time);
+ summary = summarizeLayerHistory(time);
EXPECT_TRUE(summary.empty());
EXPECT_EQ(1, layerCount());
EXPECT_EQ(0, activeLayerCount());
@@ -493,7 +501,7 @@ TEST_F(LayerHistoryTest, multipleLayers) {
for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE + FREQUENT_LAYER_WINDOW_SIZE + 1; i++) {
history().record(layer3.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
time += HI_FPS_PERIOD;
- summary = history().summarize(time);
+ summary = summarizeLayerHistory(time);
}
ASSERT_EQ(1, summary.size());
@@ -505,7 +513,7 @@ TEST_F(LayerHistoryTest, multipleLayers) {
// layer3 expires.
layer3.clear();
- summary = history().summarize(time);
+ summary = summarizeLayerHistory(time);
EXPECT_TRUE(summary.empty());
EXPECT_EQ(0, layerCount());
EXPECT_EQ(0, activeLayerCount());
@@ -526,8 +534,8 @@ TEST_F(LayerHistoryTest, inactiveLayers) {
time += MAX_FREQUENT_LAYER_PERIOD_NS.count();
EXPECT_EQ(1, layerCount());
- ASSERT_EQ(1, history().summarize(time).size());
- EXPECT_EQ(LayerHistory::LayerVoteType::Max, history().summarize(time)[0].vote);
+ ASSERT_EQ(1, summarizeLayerHistory(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote);
EXPECT_EQ(1, activeLayerCount());
EXPECT_EQ(1, frequentLayerCount(time));
}
@@ -537,8 +545,8 @@ TEST_F(LayerHistoryTest, inactiveLayers) {
time += MAX_FREQUENT_LAYER_PERIOD_NS.count();
EXPECT_EQ(1, layerCount());
- ASSERT_EQ(1, history().summarize(time).size());
- EXPECT_EQ(LayerHistory::LayerVoteType::Min, history().summarize(time)[0].vote);
+ ASSERT_EQ(1, summarizeLayerHistory(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Min, summarizeLayerHistory(time)[0].vote);
EXPECT_EQ(1, activeLayerCount());
EXPECT_EQ(0, frequentLayerCount(time));
@@ -551,8 +559,8 @@ TEST_F(LayerHistoryTest, inactiveLayers) {
time += HI_FPS_PERIOD;
EXPECT_EQ(1, layerCount());
- ASSERT_EQ(1, history().summarize(time).size());
- EXPECT_EQ(LayerHistory::LayerVoteType::Min, history().summarize(time)[0].vote);
+ ASSERT_EQ(1, summarizeLayerHistory(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Min, summarizeLayerHistory(time)[0].vote);
EXPECT_EQ(1, activeLayerCount());
EXPECT_EQ(0, frequentLayerCount(time));
}
@@ -562,8 +570,8 @@ TEST_F(LayerHistoryTest, inactiveLayers) {
time += HI_FPS_PERIOD;
EXPECT_EQ(1, layerCount());
- ASSERT_EQ(1, history().summarize(time).size());
- EXPECT_EQ(LayerHistory::LayerVoteType::Max, history().summarize(time)[0].vote);
+ ASSERT_EQ(1, summarizeLayerHistory(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote);
EXPECT_EQ(1, activeLayerCount());
EXPECT_EQ(1, frequentLayerCount(time));
}
@@ -590,10 +598,10 @@ TEST_F(LayerHistoryTest, invisibleExplicitLayer) {
LayerHistory::LayerUpdateType::Buffer);
EXPECT_EQ(2, layerCount());
- ASSERT_EQ(1, history().summarize(time).size());
+ ASSERT_EQ(1, summarizeLayerHistory(time).size());
EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitExactOrMultiple,
- history().summarize(time)[0].vote);
- EXPECT_TRUE(Fps(60.0f).equalsWithMargin(history().summarize(time)[0].desiredRefreshRate));
+ summarizeLayerHistory(time)[0].vote);
+ EXPECT_TRUE(Fps(60.0f).equalsWithMargin(summarizeLayerHistory(time)[0].desiredRefreshRate));
EXPECT_EQ(2, activeLayerCount());
EXPECT_EQ(2, frequentLayerCount(time));
}
@@ -617,8 +625,8 @@ TEST_F(LayerHistoryTest, infrequentAnimatingLayer) {
time += MAX_FREQUENT_LAYER_PERIOD_NS.count();
}
- ASSERT_EQ(1, history().summarize(time).size());
- EXPECT_EQ(LayerHistory::LayerVoteType::Min, history().summarize(time)[0].vote);
+ ASSERT_EQ(1, summarizeLayerHistory(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Min, summarizeLayerHistory(time)[0].vote);
EXPECT_EQ(1, activeLayerCount());
EXPECT_EQ(0, frequentLayerCount(time));
EXPECT_EQ(0, animatingLayerCount(time));
@@ -627,8 +635,8 @@ TEST_F(LayerHistoryTest, infrequentAnimatingLayer) {
history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
time += MAX_FREQUENT_LAYER_PERIOD_NS.count();
- ASSERT_EQ(1, history().summarize(time).size());
- EXPECT_EQ(LayerHistory::LayerVoteType::Min, history().summarize(time)[0].vote);
+ ASSERT_EQ(1, summarizeLayerHistory(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Min, summarizeLayerHistory(time)[0].vote);
EXPECT_EQ(1, activeLayerCount());
EXPECT_EQ(0, frequentLayerCount(time));
EXPECT_EQ(0, animatingLayerCount(time));
@@ -637,8 +645,8 @@ TEST_F(LayerHistoryTest, infrequentAnimatingLayer) {
history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::AnimationTX);
time += MAX_FREQUENT_LAYER_PERIOD_NS.count();
- ASSERT_EQ(1, history().summarize(time).size());
- EXPECT_EQ(LayerHistory::LayerVoteType::Max, history().summarize(time)[0].vote);
+ ASSERT_EQ(1, summarizeLayerHistory(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote);
EXPECT_EQ(1, activeLayerCount());
EXPECT_EQ(0, frequentLayerCount(time));
EXPECT_EQ(1, animatingLayerCount(time));
@@ -727,13 +735,13 @@ TEST_P(LayerHistoryTestParameterized, HeuristicLayerWithInfrequentLayer) {
}
if (time - startTime > PRESENT_TIME_HISTORY_DURATION.count()) {
- ASSERT_NE(0, history().summarize(time).size());
- ASSERT_GE(2, history().summarize(time).size());
+ ASSERT_NE(0, summarizeLayerHistory(time).size());
+ ASSERT_GE(2, summarizeLayerHistory(time).size());
bool max = false;
bool min = false;
Fps heuristic{0.0};
- for (const auto& layer : history().summarize(time)) {
+ for (const auto& layer : summarizeLayerHistory(time)) {
if (layer.vote == LayerHistory::LayerVoteType::Heuristic) {
heuristic = layer.desiredRefreshRate;
} else if (layer.vote == LayerHistory::LayerVoteType::Max) {
@@ -746,7 +754,7 @@ TEST_P(LayerHistoryTestParameterized, HeuristicLayerWithInfrequentLayer) {
if (infrequentLayerUpdates > FREQUENT_LAYER_WINDOW_SIZE) {
EXPECT_TRUE(Fps(24.0f).equalsWithMargin(heuristic));
EXPECT_FALSE(max);
- if (history().summarize(time).size() == 2) {
+ if (summarizeLayerHistory(time).size() == 2) {
EXPECT_TRUE(min);
}
}
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
index 112fabdefe..77b75ab767 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
@@ -51,8 +51,7 @@ protected:
~RefreshRateConfigsTest();
RefreshRate createRefreshRate(DisplayModePtr displayMode) {
- return {displayMode->getId(), displayMode, displayMode->getFps(),
- RefreshRate::ConstructorTag(0)};
+ return {displayMode, RefreshRate::ConstructorTag(0)};
}
Fps findClosestKnownFrameRate(const RefreshRateConfigs& refreshRateConfigs, Fps frameRate) {
@@ -164,24 +163,17 @@ protected:
mConfig60, mConfig60Frac};
// Expected RefreshRate objects
- RefreshRate mExpected60Config = {HWC_CONFIG_ID_60, mConfig60, Fps(60),
- RefreshRate::ConstructorTag(0)};
- RefreshRate mExpectedAlmost60Config = {HWC_CONFIG_ID_60,
- createDisplayMode(HWC_CONFIG_ID_60, 0, 16666665),
- Fps(60), RefreshRate::ConstructorTag(0)};
- RefreshRate mExpected90Config = {HWC_CONFIG_ID_90, mConfig90, Fps(90),
- RefreshRate::ConstructorTag(0)};
- RefreshRate mExpected90DifferentGroupConfig = {HWC_CONFIG_ID_90, mConfig90DifferentGroup,
- Fps(90), RefreshRate::ConstructorTag(0)};
- RefreshRate mExpected90DifferentResolutionConfig = {HWC_CONFIG_ID_90,
- mConfig90DifferentResolution, Fps(90),
+ RefreshRate mExpected60Config = {mConfig60, RefreshRate::ConstructorTag(0)};
+ RefreshRate mExpectedAlmost60Config = {createDisplayMode(HWC_CONFIG_ID_60, 0, 16666665),
+ RefreshRate::ConstructorTag(0)};
+ RefreshRate mExpected90Config = {mConfig90, RefreshRate::ConstructorTag(0)};
+ RefreshRate mExpected90DifferentGroupConfig = {mConfig90DifferentGroup,
+ RefreshRate::ConstructorTag(0)};
+ RefreshRate mExpected90DifferentResolutionConfig = {mConfig90DifferentResolution,
RefreshRate::ConstructorTag(0)};
- RefreshRate mExpected72Config = {HWC_CONFIG_ID_72, mConfig72, Fps(72.0f),
- RefreshRate::ConstructorTag(0)};
- RefreshRate mExpected30Config = {HWC_CONFIG_ID_30, mConfig30, Fps(30),
- RefreshRate::ConstructorTag(0)};
- RefreshRate mExpected120Config = {HWC_CONFIG_ID_120, mConfig120, Fps(120),
- RefreshRate::ConstructorTag(0)};
+ RefreshRate mExpected72Config = {mConfig72, RefreshRate::ConstructorTag(0)};
+ RefreshRate mExpected30Config = {mConfig30, RefreshRate::ConstructorTag(0)};
+ RefreshRate mExpected120Config = {mConfig120, RefreshRate::ConstructorTag(0)};
DisplayModePtr createDisplayMode(DisplayModeId modeId, int32_t group, int64_t vsyncPeriod,
ui::Size resolution = ui::Size());
@@ -205,6 +197,7 @@ DisplayModePtr RefreshRateConfigsTest::createDisplayMode(DisplayModeId modeId, i
int64_t vsyncPeriod, ui::Size resolution) {
return DisplayMode::Builder(hal::HWConfigId(modeId.value()))
.setId(modeId)
+ .setPhysicalDisplayId(PhysicalDisplayId(0))
.setVsyncPeriod(int32_t(vsyncPeriod))
.setGroup(group)
.setHeight(resolution.height)
@@ -2515,26 +2508,6 @@ TEST_F(RefreshRateConfigsTest, getFrameRateOverrides_touch) {
ASSERT_TRUE(frameRateOverrides.empty());
}
-TEST_F(RefreshRateConfigsTest, updateDisplayModes) {
- auto refreshRateConfigs =
- std::make_unique<RefreshRateConfigs>(m30_60_72_90_120Device,
- /*currentConfigId=*/HWC_CONFIG_ID_30);
- refreshRateConfigs->setDisplayManagerPolicy({DisplayModeId(HWC_CONFIG_ID_30),
- /* allowGroupSwitching */ false,
- /* range */ {Fps(30.0f), Fps(30.0f)}});
-
- refreshRateConfigs->updateDisplayModes(m60_90Device, HWC_CONFIG_ID_60);
-
- const auto currentRefreshRate = refreshRateConfigs->getCurrentRefreshRate();
- EXPECT_TRUE(currentRefreshRate.getFps().equalsWithMargin(Fps(60.0)));
- EXPECT_EQ(currentRefreshRate.getModeId(), HWC_CONFIG_ID_60);
-
- EXPECT_TRUE(
- getMaxSupportedRefreshRate(*refreshRateConfigs).getFps().equalsWithMargin(Fps(90.0)));
- EXPECT_TRUE(
- getMinSupportedRefreshRate(*refreshRateConfigs).getFps().equalsWithMargin(Fps(60.0)));
-}
-
} // namespace
} // namespace scheduler
} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
index bf07106afd..12b155bd2c 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
@@ -81,6 +81,7 @@ DisplayModePtr RefreshRateStatsTest::createDisplayMode(DisplayModeId modeId, int
int64_t vsyncPeriod) {
return DisplayMode::Builder(static_cast<hal::HWConfigId>(modeId.value()))
.setId(modeId)
+ .setPhysicalDisplayId(PhysicalDisplayId(0))
.setVsyncPeriod(static_cast<int32_t>(vsyncPeriod))
.setGroup(group)
.build();
diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
index f680d802e6..5713c2f64a 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -53,16 +53,19 @@ protected:
const DisplayModePtr mode60 = DisplayMode::Builder(0)
.setId(DisplayModeId(0))
+ .setPhysicalDisplayId(PhysicalDisplayId(0))
.setVsyncPeriod(Fps(60.f).getPeriodNsecs())
.setGroup(0)
.build();
const DisplayModePtr mode120 = DisplayMode::Builder(1)
.setId(DisplayModeId(1))
+ .setPhysicalDisplayId(PhysicalDisplayId(0))
.setVsyncPeriod(Fps(120.f).getPeriodNsecs())
.setGroup(0)
.build();
- scheduler::RefreshRateConfigs mConfigs{{mode60}, mode60->getId()};
+ std::shared_ptr<scheduler::RefreshRateConfigs> mConfigs =
+ std::make_shared<scheduler::RefreshRateConfigs>(DisplayModes{mode60}, mode60->getId());
mock::SchedulerCallback mSchedulerCallback;
@@ -171,7 +174,7 @@ TEST_F(SchedulerTest, chooseRefreshRateForContentIsNoopWhenModeSwitchingIsNotSup
mScheduler->setDisplayPowerState(kPowerStateNormal);
constexpr uint32_t kDisplayArea = 999'999;
- mScheduler->onPrimaryDisplayAreaChanged(kDisplayArea);
+ mScheduler->onActiveDisplayAreaChanged(kDisplayArea);
EXPECT_CALL(mSchedulerCallback, changeRefreshRate(_, _)).Times(0);
mScheduler->chooseRefreshRateForContent();
@@ -182,7 +185,9 @@ TEST_F(SchedulerTest, updateDisplayModes) {
sp<mock::MockLayer> layer = sp<mock::MockLayer>::make(mFlinger.flinger());
ASSERT_EQ(static_cast<size_t>(1), mScheduler->layerHistorySize());
- mConfigs.updateDisplayModes({mode60, mode120}, /* activeMode */ mode60->getId());
+ mScheduler->setRefreshRateConfigs(
+ std::make_shared<scheduler::RefreshRateConfigs>(DisplayModes{mode60, mode120},
+ mode60->getId()));
ASSERT_EQ(static_cast<size_t>(0), mScheduler->getNumActiveLayers());
mScheduler->recordLayerHistory(layer.get(), 0, LayerHistory::LayerUpdateType::Buffer);
@@ -194,20 +199,21 @@ TEST_F(SchedulerTest, testDispatchCachedReportedMode) {
// onModeChange is called.
mScheduler->clearOptionalFieldsInFeatures();
EXPECT_NO_FATAL_FAILURE(mScheduler->dispatchCachedReportedMode());
- EXPECT_CALL(*mEventThread, onModeChanged(_, _, _)).Times(0);
+ EXPECT_CALL(*mEventThread, onModeChanged(_)).Times(0);
}
TEST_F(SchedulerTest, onNonPrimaryDisplayModeChanged_invalidParameters) {
- DisplayModeId modeId = DisplayModeId(111);
- nsecs_t vsyncPeriod = 111111;
+ const auto mode = DisplayMode::Builder(hal::HWConfigId(0))
+ .setId(DisplayModeId(111))
+ .setPhysicalDisplayId(PHYSICAL_DISPLAY_ID)
+ .setVsyncPeriod(111111)
+ .build();
// If the handle is incorrect, the function should return before
// onModeChange is called.
Scheduler::ConnectionHandle invalidHandle = {.id = 123};
- EXPECT_NO_FATAL_FAILURE(mScheduler->onNonPrimaryDisplayModeChanged(invalidHandle,
- PHYSICAL_DISPLAY_ID, modeId,
- vsyncPeriod));
- EXPECT_CALL(*mEventThread, onModeChanged(_, _, _)).Times(0);
+ EXPECT_NO_FATAL_FAILURE(mScheduler->onNonPrimaryDisplayModeChanged(invalidHandle, mode));
+ EXPECT_CALL(*mEventThread, onModeChanged(_)).Times(0);
}
TEST_F(SchedulerTest, calculateMaxAcquiredBufferCount) {
@@ -225,7 +231,9 @@ MATCHER(Is120Hz, "") {
}
TEST_F(SchedulerTest, chooseRefreshRateForContentSelectsMaxRefreshRate) {
- mConfigs.updateDisplayModes({mode60, mode120}, /* activeMode */ mode60->getId());
+ mScheduler->setRefreshRateConfigs(
+ std::make_shared<scheduler::RefreshRateConfigs>(DisplayModes{mode60, mode120},
+ mode60->getId()));
sp<mock::MockLayer> layer = sp<mock::MockLayer>::make(mFlinger.flinger());
@@ -235,7 +243,7 @@ TEST_F(SchedulerTest, chooseRefreshRateForContentSelectsMaxRefreshRate) {
mScheduler->setDisplayPowerState(kPowerStateNormal);
constexpr uint32_t kDisplayArea = 999'999;
- mScheduler->onPrimaryDisplayAreaChanged(kDisplayArea);
+ mScheduler->onActiveDisplayAreaChanged(kDisplayArea);
EXPECT_CALL(mSchedulerCallback, changeRefreshRate(Is120Hz(), _)).Times(1);
mScheduler->chooseRefreshRateForContent();
diff --git a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
index 2761470c31..a4e9d20b75 100644
--- a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
@@ -479,7 +479,9 @@ TEST_P(SetFrameRateTest, SetOnParentActivatesTree) {
->record(child.get(), 0, 0, LayerHistory::LayerUpdateType::Buffer);
const auto layerHistorySummary =
- mFlinger.mutableScheduler().mutableLayerHistory()->summarize(0);
+ mFlinger.mutableScheduler()
+ .mutableLayerHistory()
+ ->summarize(*mFlinger.mutableScheduler().refreshRateConfigs(), 0);
ASSERT_EQ(2u, layerHistorySummary.size());
EXPECT_TRUE(FRAME_RATE_VOTE1.rate.equalsWithMargin(layerHistorySummary[0].desiredRefreshRate));
EXPECT_TRUE(FRAME_RATE_VOTE1.rate.equalsWithMargin(layerHistorySummary[1].desiredRefreshRate));
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetDisplayStateTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetDisplayStateTest.cpp
index be019848fb..fc40818ad1 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetDisplayStateTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetDisplayStateTest.cpp
@@ -224,6 +224,74 @@ TEST_F(SetDisplayStateLockedTest, setDisplayStateLockedRequestsUpdateIfLayerStac
EXPECT_EQ(456u, display.getCurrentDisplayState().layerStack);
}
+TEST_F(SetDisplayStateLockedTest, setDisplayStateLockedDoesNothingIfFlagsNotChanged) {
+ using Case = SimplePrimaryDisplayCase;
+
+ // --------------------------------------------------------------------
+ // Preconditions
+
+ // A display is set up
+ auto display = Case::Display::makeFakeExistingDisplayInjector(this);
+ display.inject();
+
+ // The display has flags set
+ display.mutableCurrentDisplayState().flags = 1u;
+
+ // The incoming request sets a different layer stack
+ DisplayState state;
+ state.what = DisplayState::eFlagsChanged;
+ state.token = display.token();
+ state.flags = 1u;
+
+ // --------------------------------------------------------------------
+ // Invocation
+
+ uint32_t flags = mFlinger.setDisplayStateLocked(state);
+
+ // --------------------------------------------------------------------
+ // Postconditions
+
+ // The returned flags are empty
+ EXPECT_EQ(0u, flags);
+
+ // The desired display state has been set to the new value.
+ EXPECT_EQ(1u, display.getCurrentDisplayState().flags);
+}
+
+TEST_F(SetDisplayStateLockedTest, setDisplayStateLockedRequestsUpdateIfFlagsChanged) {
+ using Case = SimplePrimaryDisplayCase;
+
+ // --------------------------------------------------------------------
+ // Preconditions
+
+ // A display is set up
+ auto display = Case::Display::makeFakeExistingDisplayInjector(this);
+ display.inject();
+
+ // The display has a layer stack set
+ display.mutableCurrentDisplayState().flags = 0u;
+
+ // The incoming request sets a different layer stack
+ DisplayState state;
+ state.what = DisplayState::eFlagsChanged;
+ state.token = display.token();
+ state.flags = 1u;
+
+ // --------------------------------------------------------------------
+ // Invocation
+
+ uint32_t flags = mFlinger.setDisplayStateLocked(state);
+
+ // --------------------------------------------------------------------
+ // Postconditions
+
+ // The returned flags indicate a transaction is needed
+ EXPECT_EQ(eDisplayTransactionNeeded, flags);
+
+ // The desired display state has been set to the new value.
+ EXPECT_EQ(1u, display.getCurrentDisplayState().flags);
+}
+
TEST_F(SetDisplayStateLockedTest, setDisplayStateLockedDoesNothingIfProjectionDidNotChange) {
using Case = SimplePrimaryDisplayCase;
constexpr ui::Rotation initialOrientation = ui::ROTATION_180;
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp
index 65024202b8..eea1002236 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp
@@ -260,6 +260,11 @@ struct DisplayPowerCase {
auto display = Display::makeFakeExistingDisplayInjector(test);
display.inject();
display.mutableDisplayDevice()->setPowerMode(mode);
+ if (display.mutableDisplayDevice()->isInternal()) {
+ test->mFlinger.mutableActiveDisplayToken() =
+ display.mutableDisplayDevice()->getDisplayToken();
+ }
+
return display;
}
diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h
index 41fd6e316f..1d21bd43e3 100644
--- a/services/surfaceflinger/tests/unittests/TestableScheduler.h
+++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h
@@ -32,16 +32,19 @@ namespace android {
class TestableScheduler : public Scheduler {
public:
- TestableScheduler(const scheduler::RefreshRateConfigs& configs, ISchedulerCallback& callback)
+ TestableScheduler(const std::shared_ptr<scheduler::RefreshRateConfigs>& refreshRateConfigs,
+ ISchedulerCallback& callback)
: TestableScheduler(std::make_unique<mock::VsyncController>(),
- std::make_unique<mock::VSyncTracker>(), configs, callback) {}
+ std::make_unique<mock::VSyncTracker>(), refreshRateConfigs,
+ callback) {}
TestableScheduler(std::unique_ptr<scheduler::VsyncController> vsyncController,
std::unique_ptr<scheduler::VSyncTracker> vsyncTracker,
- const scheduler::RefreshRateConfigs& configs, ISchedulerCallback& callback)
- : Scheduler({std::move(vsyncController), std::move(vsyncTracker), nullptr}, configs,
- callback, createLayerHistory(configs),
- {.supportKernelTimer = false, .useContentDetection = true}) {}
+ const std::shared_ptr<scheduler::RefreshRateConfigs>& refreshRateConfigs,
+ ISchedulerCallback& callback)
+ : Scheduler({std::move(vsyncController), std::move(vsyncTracker), nullptr},
+ refreshRateConfigs, callback, createLayerHistory(),
+ {.useContentDetection = true}) {}
// Used to inject mock event thread.
ConnectionHandle createConnection(std::unique_ptr<EventThread> eventThread) {
@@ -64,6 +67,8 @@ public:
return mutableLayerHistory()->mLayerInfos.size();
}
+ auto refreshRateConfigs() { return holdRefreshRateConfigs(); }
+
size_t getNumActiveLayers() NO_THREAD_SAFETY_ANALYSIS {
if (!mLayerHistory) return 0;
return mutableLayerHistory()->mActiveLayersEnd;
@@ -95,9 +100,8 @@ public:
mFeatures.cachedModeChangedParams.reset();
}
- void onNonPrimaryDisplayModeChanged(ConnectionHandle handle, PhysicalDisplayId displayId,
- DisplayModeId modeId, nsecs_t vsyncPeriod) {
- return Scheduler::onNonPrimaryDisplayModeChanged(handle, displayId, modeId, vsyncPeriod);
+ void onNonPrimaryDisplayModeChanged(ConnectionHandle handle, DisplayModePtr mode) {
+ return Scheduler::onNonPrimaryDisplayModeChanged(handle, mode);
}
~TestableScheduler() {
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index cf67593174..a23361e856 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -82,8 +82,8 @@ public:
return std::make_unique<scheduler::FakePhaseOffsets>();
}
- std::unique_ptr<Scheduler> createScheduler(const scheduler::RefreshRateConfigs&,
- ISchedulerCallback&) override {
+ std::unique_ptr<Scheduler> createScheduler(
+ const std::shared_ptr<scheduler::RefreshRateConfigs>&, ISchedulerCallback&) override {
return nullptr;
}
@@ -209,6 +209,7 @@ public:
ISchedulerCallback* callback = nullptr, bool hasMultipleModes = false) {
DisplayModes modes{DisplayMode::Builder(0)
.setId(DisplayModeId(0))
+ .setPhysicalDisplayId(PhysicalDisplayId(0))
.setVsyncPeriod(16'666'667)
.setGroup(0)
.build()};
@@ -216,25 +217,24 @@ public:
if (hasMultipleModes) {
modes.emplace_back(DisplayMode::Builder(1)
.setId(DisplayModeId(1))
+ .setPhysicalDisplayId(PhysicalDisplayId(0))
.setVsyncPeriod(11'111'111)
.setGroup(0)
.build());
}
const auto currMode = DisplayModeId(0);
- mFlinger->mRefreshRateConfigs =
- std::make_unique<scheduler::RefreshRateConfigs>(modes, currMode);
- const auto currFps =
- mFlinger->mRefreshRateConfigs->getRefreshRateFromModeId(currMode).getFps();
- mFlinger->mRefreshRateStats =
- std::make_unique<scheduler::RefreshRateStats>(*mFlinger->mTimeStats, currFps,
- /*powerMode=*/hal::PowerMode::OFF);
+ mRefreshRateConfigs = std::make_shared<scheduler::RefreshRateConfigs>(modes, currMode);
+ const auto currFps = mRefreshRateConfigs->getCurrentRefreshRate().getFps();
mFlinger->mVsyncConfiguration = mFactory.createVsyncConfiguration(currFps);
mFlinger->mVsyncModulator = sp<scheduler::VsyncModulator>::make(
mFlinger->mVsyncConfiguration->getCurrentConfigs());
+ mFlinger->mRefreshRateStats =
+ std::make_unique<scheduler::RefreshRateStats>(*mFlinger->mTimeStats, currFps,
+ /*powerMode=*/hal::PowerMode::OFF);
mScheduler = new TestableScheduler(std::move(vsyncController), std::move(vsyncTracker),
- *mFlinger->mRefreshRateConfigs, *(callback ?: this));
+ mRefreshRateConfigs, *(callback ?: this));
mFlinger->mAppConnectionHandle = mScheduler->createConnection(std::move(appEventThread));
mFlinger->mSfConnectionHandle = mScheduler->createConnection(std::move(sfEventThread));
@@ -435,12 +435,14 @@ public:
auto& mutableTransactionFlags() { return mFlinger->mTransactionFlags; }
auto& mutablePowerAdvisor() { return mFlinger->mPowerAdvisor; }
auto& mutableDebugDisableHWC() { return mFlinger->mDebugDisableHWC; }
+ auto& mutableMaxRenderTargetSize() { return mFlinger->mMaxRenderTargetSize; }
auto& mutableHwcDisplayData() { return getHwComposer().mDisplayData; }
auto& mutableHwcPhysicalDisplayIdMap() { return getHwComposer().mPhysicalDisplayIdMap; }
auto& mutableInternalHwcDisplayId() { return getHwComposer().mInternalHwcDisplayId; }
auto& mutableExternalHwcDisplayId() { return getHwComposer().mExternalHwcDisplayId; }
auto& mutableUseFrameRateApi() { return mFlinger->useFrameRateApi; }
+ auto& mutableActiveDisplayToken() { return mFlinger->mActiveDisplayToken; }
auto fromHandle(const sp<IBinder>& handle) {
return mFlinger->fromHandle(handle);
@@ -644,6 +646,7 @@ public:
DisplayModePtr activeMode =
DisplayMode::Builder(FakeHwcDisplayInjector::DEFAULT_ACTIVE_CONFIG)
.setId(mActiveModeId)
+ .setPhysicalDisplayId(PhysicalDisplayId(0))
.setWidth(FakeHwcDisplayInjector::DEFAULT_WIDTH)
.setHeight(FakeHwcDisplayInjector::DEFAULT_HEIGHT)
.setVsyncPeriod(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD)
@@ -654,6 +657,7 @@ public:
DisplayModes modes{activeMode};
mCreationArgs.supportedModes = modes;
+ mCreationArgs.refreshRateConfigs = flinger.mRefreshRateConfigs;
}
sp<IBinder> token() const { return mDisplayToken; }
@@ -723,7 +727,7 @@ public:
return *this;
}
- sp<DisplayDevice> inject() {
+ sp<DisplayDevice> inject() NO_THREAD_SAFETY_ANALYSIS {
const auto displayId = mCreationArgs.compositionDisplay->getDisplayId();
DisplayDeviceState state;
@@ -770,6 +774,7 @@ private:
surfaceflinger::test::Factory mFactory;
sp<SurfaceFlinger> mFlinger = new SurfaceFlinger(mFactory, SurfaceFlinger::SkipInitialization);
TestableScheduler* mScheduler = nullptr;
+ std::shared_ptr<scheduler::RefreshRateConfigs> mRefreshRateConfigs;
};
} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
index 7c431a077b..1a50427b93 100644
--- a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
@@ -74,6 +74,7 @@ public:
EXPECT_CALL(*mVSyncTracker, currentPeriod())
.WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD));
+ mFlinger.setupComposer(std::make_unique<Hwc2::mock::Composer>());
mFlinger.setupScheduler(std::unique_ptr<mock::VsyncController>(mVsyncController),
std::unique_ptr<mock::VSyncTracker>(mVSyncTracker),
std::move(eventThread), std::move(sfEventThread));
diff --git a/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp b/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp
index 2845d0ab14..a749ece835 100644
--- a/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp
@@ -119,7 +119,7 @@ public:
FrameTracer::FrameEvent::QUEUE, /*duration*/ 0));
layer->setBuffer(buffer, fence, postTime, /*desiredPresentTime*/ 30, false, mClientCache,
frameNumber, dequeueTime, FrameTimelineInfo{},
- nullptr /* releaseBufferCallback */);
+ nullptr /* releaseBufferCallback */, nullptr /* releaseBufferEndpoint*/);
commitTransaction(layer.get());
bool computeVisisbleRegions;
diff --git a/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp b/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp
index 7bf224d557..2a7921f661 100644
--- a/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp
@@ -119,7 +119,8 @@ public:
1, 0),
mRenderEngine, false);
layer->setBuffer(buffer, fence, 10, 20, false, mClientCache, 1, std::nullopt,
- {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */);
+ {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */,
+ nullptr /* releaseBufferEndpoint */);
acquireFence->signalForTest(12);
commitTransaction(layer.get());
@@ -147,7 +148,8 @@ public:
1, 0),
mRenderEngine, false);
layer->setBuffer(buffer1, fence1, 10, 20, false, mClientCache, 1, std::nullopt,
- {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */);
+ {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */,
+ nullptr /* releaseBufferEndpoint */);
EXPECT_EQ(0u, layer->mDrawingState.bufferlessSurfaceFramesTX.size());
ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX);
const auto droppedSurfaceFrame = layer->mDrawingState.bufferSurfaceFrameTX;
@@ -160,7 +162,8 @@ public:
mRenderEngine, false);
nsecs_t start = systemTime();
layer->setBuffer(buffer2, fence2, 10, 20, false, mClientCache, 1, std::nullopt,
- {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */);
+ {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */,
+ nullptr /* releaseBufferEndpoint */);
nsecs_t end = systemTime();
acquireFence2->signalForTest(12);
@@ -200,7 +203,8 @@ public:
1, 0),
mRenderEngine, false);
layer->setBuffer(buffer, fence, 10, 20, false, mClientCache, 1, std::nullopt,
- {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */);
+ {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */,
+ nullptr /* releaseBufferEndpoint */);
acquireFence->signalForTest(12);
EXPECT_EQ(0u, layer->mDrawingState.bufferlessSurfaceFramesTX.size());
@@ -228,7 +232,8 @@ public:
1, 0),
mRenderEngine, false);
layer->setBuffer(buffer, fence, 10, 20, false, mClientCache, 1, std::nullopt,
- {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */);
+ {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */,
+ nullptr /* releaseBufferEndpoint */);
EXPECT_EQ(0u, layer->mDrawingState.bufferlessSurfaceFramesTX.size());
ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX);
@@ -260,7 +265,8 @@ public:
1, 0),
mRenderEngine, false);
layer->setBuffer(buffer, fence, 10, 20, false, mClientCache, 1, std::nullopt,
- {/*vsyncId*/ 3, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */);
+ {/*vsyncId*/ 3, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */,
+ nullptr /* releaseBufferEndpoint */);
EXPECT_EQ(2u, layer->mDrawingState.bufferlessSurfaceFramesTX.size());
ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX);
const auto bufferSurfaceFrameTX = layer->mDrawingState.bufferSurfaceFrameTX;
@@ -298,7 +304,8 @@ public:
1, 0),
mRenderEngine, false);
layer->setBuffer(buffer1, fence1, 10, 20, false, mClientCache, 1, std::nullopt,
- {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */);
+ {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */,
+ nullptr /* releaseBufferEndpoint */);
ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX);
const auto droppedSurfaceFrame = layer->mDrawingState.bufferSurfaceFrameTX;
@@ -309,7 +316,8 @@ public:
1, 0),
mRenderEngine, false);
layer->setBuffer(buffer2, fence2, 10, 20, false, mClientCache, 1, std::nullopt,
- {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */);
+ {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */,
+ nullptr /* releaseBufferEndpoint */);
acquireFence2->signalForTest(12);
ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX);
@@ -339,7 +347,8 @@ public:
1, 0),
mRenderEngine, false);
layer->setBuffer(buffer1, fence1, 10, 20, false, mClientCache, 1, std::nullopt,
- {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */);
+ {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */,
+ nullptr /* releaseBufferEndpoint */);
EXPECT_EQ(0u, layer->mDrawingState.bufferlessSurfaceFramesTX.size());
ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX);
const auto droppedSurfaceFrame1 = layer->mDrawingState.bufferSurfaceFrameTX;
@@ -353,7 +362,7 @@ public:
auto dropStartTime1 = systemTime();
layer->setBuffer(buffer2, fence2, 10, 20, false, mClientCache, 1, std::nullopt,
{/*vsyncId*/ FrameTimelineInfo::INVALID_VSYNC_ID, /*inputEventId*/ 0},
- nullptr /* releaseBufferCallback */);
+ nullptr /* releaseBufferCallback */, nullptr /* releaseBufferEndpoint */);
auto dropEndTime1 = systemTime();
EXPECT_EQ(0u, layer->mDrawingState.bufferlessSurfaceFramesTX.size());
ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX);
@@ -367,7 +376,8 @@ public:
mRenderEngine, false);
auto dropStartTime2 = systemTime();
layer->setBuffer(buffer3, fence3, 10, 20, false, mClientCache, 1, std::nullopt,
- {/*vsyncId*/ 2, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */);
+ {/*vsyncId*/ 2, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */,
+ nullptr /* releaseBufferEndpoint */);
auto dropEndTime2 = systemTime();
acquireFence3->signalForTest(12);
@@ -411,7 +421,8 @@ public:
mRenderEngine, false);
layer->setBuffer(buffer1, fence1, 10, 20, false, mClientCache, 1, std::nullopt,
{/*vsyncId*/ 1, /*inputEventId*/ 0},
- nullptr /* releaseBufferCallback */);
+ nullptr /* releaseBufferCallback */,
+ nullptr /* releaseBufferEndpoint */);
layer->setFrameTimelineVsyncForBufferlessTransaction({/*vsyncId*/ 2,
/*inputEventId*/ 0},
10);
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
index cb3bd73920..1ba3c0f56e 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
@@ -54,8 +54,7 @@ public:
MOCK_METHOD0(resetCommands, void());
MOCK_METHOD0(executeCommands, Error());
MOCK_METHOD0(getMaxVirtualDisplayCount, uint32_t());
- MOCK_METHOD5(createVirtualDisplay,
- Error(uint32_t, uint32_t, PixelFormat*, std::optional<Display>, Display*));
+ MOCK_METHOD4(createVirtualDisplay, Error(uint32_t, uint32_t, PixelFormat*, Display*));
MOCK_METHOD1(destroyVirtualDisplay, Error(Display));
MOCK_METHOD1(acceptDisplayChanges, Error(Display));
MOCK_METHOD2(createLayer, Error(Display, Layer* outLayer));
diff --git a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
index 485b4acdce..d25973e1ce 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
@@ -33,7 +33,7 @@ public:
MOCK_METHOD0(onScreenReleased, void());
MOCK_METHOD0(onScreenAcquired, void());
MOCK_METHOD2(onHotplugReceived, void(PhysicalDisplayId, bool));
- MOCK_METHOD3(onModeChanged, void(PhysicalDisplayId, DisplayModeId, nsecs_t));
+ MOCK_METHOD1(onModeChanged, void(DisplayModePtr));
MOCK_METHOD2(onFrameRateOverridesChanged,
void(PhysicalDisplayId, std::vector<FrameRateOverride>));
MOCK_CONST_METHOD1(dump, void(std::string&));
diff --git a/services/surfaceflinger/tests/utils/ScreenshotUtils.h b/services/surfaceflinger/tests/utils/ScreenshotUtils.h
index ddaa5a166e..cae76849bf 100644
--- a/services/surfaceflinger/tests/utils/ScreenshotUtils.h
+++ b/services/surfaceflinger/tests/utils/ScreenshotUtils.h
@@ -175,6 +175,11 @@ public:
void expectChildColor(uint32_t x, uint32_t y) { checkPixel(x, y, 200, 200, 200); }
+ void expectSize(uint32_t width, uint32_t height) {
+ EXPECT_EQ(width, mOutBuffer->getWidth());
+ EXPECT_EQ(height, mOutBuffer->getHeight());
+ }
+
explicit ScreenCapture(const sp<GraphicBuffer>& outBuffer) : mOutBuffer(outBuffer) {
if (mOutBuffer) {
mOutBuffer->lock(GRALLOC_USAGE_SW_READ_OFTEN, reinterpret_cast<void**>(&mPixels));
diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp
index cf774fd9b8..0c5d61b8d5 100644
--- a/vulkan/libvulkan/driver.cpp
+++ b/vulkan/libvulkan/driver.cpp
@@ -624,8 +624,10 @@ void CreateInfoWrapper::FilterExtension(const char* name) {
switch (ext_bit) {
case ProcHook::KHR_android_surface:
case ProcHook::KHR_surface:
+ case ProcHook::KHR_surface_protected_capabilities:
case ProcHook::EXT_swapchain_colorspace:
case ProcHook::KHR_get_surface_capabilities2:
+ case ProcHook::GOOGLE_surfaceless_query:
hook_extensions_.set(ext_bit);
// return now as these extensions do not require HAL support
return;
@@ -701,8 +703,10 @@ void CreateInfoWrapper::FilterExtension(const char* name) {
case ProcHook::KHR_external_fence_capabilities:
case ProcHook::KHR_get_surface_capabilities2:
case ProcHook::KHR_surface:
+ case ProcHook::KHR_surface_protected_capabilities:
case ProcHook::EXT_debug_report:
case ProcHook::EXT_swapchain_colorspace:
+ case ProcHook::GOOGLE_surfaceless_query:
case ProcHook::ANDROID_native_buffer:
case ProcHook::EXTENSION_CORE_1_0:
case ProcHook::EXTENSION_CORE_1_1:
@@ -913,6 +917,9 @@ VkResult EnumerateInstanceExtensionProperties(
loader_extensions.push_back({
VK_KHR_SURFACE_EXTENSION_NAME,
VK_KHR_SURFACE_SPEC_VERSION});
+ loader_extensions.push_back(
+ {VK_KHR_SURFACE_PROTECTED_CAPABILITIES_EXTENSION_NAME,
+ VK_KHR_SURFACE_PROTECTED_CAPABILITIES_SPEC_VERSION});
loader_extensions.push_back({
VK_KHR_ANDROID_SURFACE_EXTENSION_NAME,
VK_KHR_ANDROID_SURFACE_SPEC_VERSION});
@@ -922,6 +929,8 @@ VkResult EnumerateInstanceExtensionProperties(
loader_extensions.push_back({
VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME,
VK_KHR_GET_SURFACE_CAPABILITIES_2_SPEC_VERSION});
+ loader_extensions.push_back({VK_GOOGLE_SURFACELESS_QUERY_EXTENSION_NAME,
+ VK_GOOGLE_SURFACELESS_QUERY_SPEC_VERSION});
static const VkExtensionProperties loader_debug_report_extension = {
VK_EXT_DEBUG_REPORT_EXTENSION_NAME, VK_EXT_DEBUG_REPORT_SPEC_VERSION,
diff --git a/vulkan/libvulkan/driver_gen.cpp b/vulkan/libvulkan/driver_gen.cpp
index 5f37a50a03..b436db1de7 100644
--- a/vulkan/libvulkan/driver_gen.cpp
+++ b/vulkan/libvulkan/driver_gen.cpp
@@ -565,11 +565,13 @@ ProcHook::Extension GetProcHookExtension(const char* name) {
if (strcmp(name, "VK_EXT_hdr_metadata") == 0) return ProcHook::EXT_hdr_metadata;
if (strcmp(name, "VK_EXT_swapchain_colorspace") == 0) return ProcHook::EXT_swapchain_colorspace;
if (strcmp(name, "VK_GOOGLE_display_timing") == 0) return ProcHook::GOOGLE_display_timing;
+ if (strcmp(name, "VK_GOOGLE_surfaceless_query") == 0) return ProcHook::GOOGLE_surfaceless_query;
if (strcmp(name, "VK_KHR_android_surface") == 0) return ProcHook::KHR_android_surface;
if (strcmp(name, "VK_KHR_get_surface_capabilities2") == 0) return ProcHook::KHR_get_surface_capabilities2;
if (strcmp(name, "VK_KHR_incremental_present") == 0) return ProcHook::KHR_incremental_present;
if (strcmp(name, "VK_KHR_shared_presentable_image") == 0) return ProcHook::KHR_shared_presentable_image;
if (strcmp(name, "VK_KHR_surface") == 0) return ProcHook::KHR_surface;
+ if (strcmp(name, "VK_KHR_surface_protected_capabilities") == 0) return ProcHook::KHR_surface_protected_capabilities;
if (strcmp(name, "VK_KHR_swapchain") == 0) return ProcHook::KHR_swapchain;
if (strcmp(name, "VK_ANDROID_external_memory_android_hardware_buffer") == 0) return ProcHook::ANDROID_external_memory_android_hardware_buffer;
if (strcmp(name, "VK_KHR_bind_memory2") == 0) return ProcHook::KHR_bind_memory2;
diff --git a/vulkan/libvulkan/driver_gen.h b/vulkan/libvulkan/driver_gen.h
index 047e774004..688630c0a5 100644
--- a/vulkan/libvulkan/driver_gen.h
+++ b/vulkan/libvulkan/driver_gen.h
@@ -41,11 +41,13 @@ struct ProcHook {
EXT_hdr_metadata,
EXT_swapchain_colorspace,
GOOGLE_display_timing,
+ GOOGLE_surfaceless_query,
KHR_android_surface,
KHR_get_surface_capabilities2,
KHR_incremental_present,
KHR_shared_presentable_image,
KHR_surface,
+ KHR_surface_protected_capabilities,
KHR_swapchain,
ANDROID_external_memory_android_hardware_buffer,
KHR_bind_memory2,
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index 6191063894..0b9ba05be8 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -614,42 +614,65 @@ VkResult GetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice /*pdev*/,
VKAPI_ATTR
VkResult GetPhysicalDeviceSurfaceCapabilitiesKHR(
- VkPhysicalDevice /*pdev*/,
+ VkPhysicalDevice pdev,
VkSurfaceKHR surface,
VkSurfaceCapabilitiesKHR* capabilities) {
ATRACE_CALL();
int err;
- ANativeWindow* window = SurfaceFromHandle(surface)->window.get();
-
int width, height;
- err = window->query(window, NATIVE_WINDOW_DEFAULT_WIDTH, &width);
- if (err != android::OK) {
- ALOGE("NATIVE_WINDOW_DEFAULT_WIDTH query failed: %s (%d)",
- strerror(-err), err);
- return VK_ERROR_SURFACE_LOST_KHR;
- }
- err = window->query(window, NATIVE_WINDOW_DEFAULT_HEIGHT, &height);
- if (err != android::OK) {
- ALOGE("NATIVE_WINDOW_DEFAULT_WIDTH query failed: %s (%d)",
- strerror(-err), err);
- return VK_ERROR_SURFACE_LOST_KHR;
- }
-
int transform_hint;
- err = window->query(window, NATIVE_WINDOW_TRANSFORM_HINT, &transform_hint);
- if (err != android::OK) {
- ALOGE("NATIVE_WINDOW_TRANSFORM_HINT query failed: %s (%d)",
- strerror(-err), err);
- return VK_ERROR_SURFACE_LOST_KHR;
- }
-
int max_buffer_count;
- err = window->query(window, NATIVE_WINDOW_MAX_BUFFER_COUNT, &max_buffer_count);
- if (err != android::OK) {
- ALOGE("NATIVE_WINDOW_MAX_BUFFER_COUNT query failed: %s (%d)",
- strerror(-err), err);
- return VK_ERROR_SURFACE_LOST_KHR;
+ if (surface == VK_NULL_HANDLE) {
+ const InstanceData& instance_data = GetData(pdev);
+ ProcHook::Extension surfaceless = ProcHook::GOOGLE_surfaceless_query;
+ bool surfaceless_enabled =
+ instance_data.hook_extensions.test(surfaceless);
+ if (!surfaceless_enabled) {
+ // It is an error to pass a surface==VK_NULL_HANDLE unless the
+ // VK_GOOGLE_surfaceless_query extension is enabled
+ return VK_ERROR_SURFACE_LOST_KHR;
+ }
+ // Support for VK_GOOGLE_surfaceless_query. The primary purpose of this
+ // extension for this function is for
+ // VkSurfaceProtectedCapabilitiesKHR::supportsProtected. The following
+ // four values cannot be known without a surface. Default values will
+ // be supplied anyway, but cannot be relied upon.
+ width = 1000;
+ height = 1000;
+ transform_hint = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
+ max_buffer_count = 10;
+ } else {
+ ANativeWindow* window = SurfaceFromHandle(surface)->window.get();
+
+ err = window->query(window, NATIVE_WINDOW_DEFAULT_WIDTH, &width);
+ if (err != android::OK) {
+ ALOGE("NATIVE_WINDOW_DEFAULT_WIDTH query failed: %s (%d)",
+ strerror(-err), err);
+ return VK_ERROR_SURFACE_LOST_KHR;
+ }
+ err = window->query(window, NATIVE_WINDOW_DEFAULT_HEIGHT, &height);
+ if (err != android::OK) {
+ ALOGE("NATIVE_WINDOW_DEFAULT_WIDTH query failed: %s (%d)",
+ strerror(-err), err);
+ return VK_ERROR_SURFACE_LOST_KHR;
+ }
+
+ err = window->query(window, NATIVE_WINDOW_TRANSFORM_HINT,
+ &transform_hint);
+ if (err != android::OK) {
+ ALOGE("NATIVE_WINDOW_TRANSFORM_HINT query failed: %s (%d)",
+ strerror(-err), err);
+ return VK_ERROR_SURFACE_LOST_KHR;
+ }
+
+ err = window->query(window, NATIVE_WINDOW_MAX_BUFFER_COUNT,
+ &max_buffer_count);
+ if (err != android::OK) {
+ ALOGE("NATIVE_WINDOW_MAX_BUFFER_COUNT query failed: %s (%d)",
+ strerror(-err), err);
+ return VK_ERROR_SURFACE_LOST_KHR;
+ }
}
capabilities->minImageCount = std::min(max_buffer_count, 3);
capabilities->maxImageCount = static_cast<uint32_t>(max_buffer_count);
@@ -690,23 +713,43 @@ VkResult GetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice pdev,
const InstanceData& instance_data = GetData(pdev);
bool wide_color_support = false;
- Surface& surface = *SurfaceFromHandle(surface_handle);
- int err = native_window_get_wide_color_support(surface.window.get(),
- &wide_color_support);
- if (err) {
- return VK_ERROR_SURFACE_LOST_KHR;
- }
- ALOGV("wide_color_support is: %d", wide_color_support);
- wide_color_support =
- wide_color_support &&
+ uint64_t consumer_usage = 0;
+ bool colorspace_ext =
instance_data.hook_extensions.test(ProcHook::EXT_swapchain_colorspace);
+ if (surface_handle == VK_NULL_HANDLE) {
+ ProcHook::Extension surfaceless = ProcHook::GOOGLE_surfaceless_query;
+ bool surfaceless_enabled =
+ instance_data.hook_extensions.test(surfaceless);
+ if (!surfaceless_enabled) {
+ return VK_ERROR_SURFACE_LOST_KHR;
+ }
+ // Support for VK_GOOGLE_surfaceless_query. The EGL loader
+ // unconditionally supports wide color formats, even if they will cause
+ // a SurfaceFlinger fallback. Based on that, wide_color_support will be
+ // set to true in this case.
+ wide_color_support = true;
+
+ // TODO(b/203826952): research proper value; temporarily use the
+ // values seen on Pixel
+ consumer_usage = AHARDWAREBUFFER_USAGE_COMPOSER_OVERLAY;
+ } else {
+ Surface& surface = *SurfaceFromHandle(surface_handle);
+ int err = native_window_get_wide_color_support(surface.window.get(),
+ &wide_color_support);
+ if (err) {
+ return VK_ERROR_SURFACE_LOST_KHR;
+ }
+ ALOGV("wide_color_support is: %d", wide_color_support);
+
+ consumer_usage = surface.consumer_usage;
+ }
+ wide_color_support = wide_color_support && colorspace_ext;
AHardwareBuffer_Desc desc = {};
desc.width = 1;
desc.height = 1;
desc.layers = 1;
- desc.usage = surface.consumer_usage |
- AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE |
+ desc.usage = consumer_usage | AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE |
AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER;
// We must support R8G8B8A8
@@ -714,6 +757,11 @@ VkResult GetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice pdev,
{VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR},
{VK_FORMAT_R8G8B8A8_SRGB, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR}};
+ if (colorspace_ext) {
+ all_formats.emplace_back(VkSurfaceFormatKHR{
+ VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_BT709_LINEAR_EXT});
+ }
+
if (wide_color_support) {
all_formats.emplace_back(VkSurfaceFormatKHR{
VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT});
@@ -721,6 +769,10 @@ VkResult GetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice pdev,
VK_FORMAT_R8G8B8A8_SRGB, VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT});
}
+ // NOTE: Any new formats that are added must be coordinated across different
+ // Android users. This includes the ANGLE team (a layered implementation of
+ // OpenGL-ES).
+
desc.format = AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM;
if (AHardwareBuffer_isSupported(&desc)) {
all_formats.emplace_back(VkSurfaceFormatKHR{
@@ -753,6 +805,10 @@ VkResult GetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice pdev,
}
}
+ // NOTE: Any new formats that are added must be coordinated across different
+ // Android users. This includes the ANGLE team (a layered implementation of
+ // OpenGL-ES).
+
VkResult result = VK_SUCCESS;
if (formats) {
uint32_t transfer_count = all_formats.size();
@@ -797,6 +853,12 @@ VkResult GetPhysicalDeviceSurfaceCapabilities2KHR(
.supportedUsageFlags;
} break;
+ case VK_STRUCTURE_TYPE_SURFACE_PROTECTED_CAPABILITIES_KHR: {
+ VkSurfaceProtectedCapabilitiesKHR* protected_caps =
+ reinterpret_cast<VkSurfaceProtectedCapabilitiesKHR*>(caps);
+ protected_caps->supportsProtected = VK_TRUE;
+ } break;
+
default:
// Ignore all other extension structs
break;
@@ -848,31 +910,51 @@ VkResult GetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice pdev,
int err;
int query_value;
- ANativeWindow* window = SurfaceFromHandle(surface)->window.get();
+ std::vector<VkPresentModeKHR> present_modes;
+ if (surface == VK_NULL_HANDLE) {
+ const InstanceData& instance_data = GetData(pdev);
+ ProcHook::Extension surfaceless = ProcHook::GOOGLE_surfaceless_query;
+ bool surfaceless_enabled =
+ instance_data.hook_extensions.test(surfaceless);
+ if (!surfaceless_enabled) {
+ return VK_ERROR_SURFACE_LOST_KHR;
+ }
+ // Support for VK_GOOGLE_surfaceless_query. The primary purpose of this
+ // extension for this function is for
+ // VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR and
+ // VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR. We technically cannot
+ // know if VK_PRESENT_MODE_SHARED_MAILBOX_KHR is supported without a
+ // surface, and that cannot be relied upon.
+ present_modes.push_back(VK_PRESENT_MODE_MAILBOX_KHR);
+ present_modes.push_back(VK_PRESENT_MODE_FIFO_KHR);
+ } else {
+ ANativeWindow* window = SurfaceFromHandle(surface)->window.get();
- err = window->query(window, NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
- &query_value);
- if (err != android::OK || query_value < 0) {
- ALOGE(
- "NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS query failed: %s (%d) "
- "value=%d",
- strerror(-err), err, query_value);
- return VK_ERROR_SURFACE_LOST_KHR;
- }
- uint32_t min_undequeued_buffers = static_cast<uint32_t>(query_value);
+ err = window->query(window, NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
+ &query_value);
+ if (err != android::OK || query_value < 0) {
+ ALOGE(
+ "NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS query failed: %s (%d) "
+ "value=%d",
+ strerror(-err), err, query_value);
+ return VK_ERROR_SURFACE_LOST_KHR;
+ }
+ uint32_t min_undequeued_buffers = static_cast<uint32_t>(query_value);
+
+ err =
+ window->query(window, NATIVE_WINDOW_MAX_BUFFER_COUNT, &query_value);
+ if (err != android::OK || query_value < 0) {
+ ALOGE(
+ "NATIVE_WINDOW_MAX_BUFFER_COUNT query failed: %s (%d) value=%d",
+ strerror(-err), err, query_value);
+ return VK_ERROR_SURFACE_LOST_KHR;
+ }
+ uint32_t max_buffer_count = static_cast<uint32_t>(query_value);
- err = window->query(window, NATIVE_WINDOW_MAX_BUFFER_COUNT, &query_value);
- if (err != android::OK || query_value < 0) {
- ALOGE("NATIVE_WINDOW_MAX_BUFFER_COUNT query failed: %s (%d) value=%d",
- strerror(-err), err, query_value);
- return VK_ERROR_SURFACE_LOST_KHR;
+ if (min_undequeued_buffers + 1 < max_buffer_count)
+ present_modes.push_back(VK_PRESENT_MODE_MAILBOX_KHR);
+ present_modes.push_back(VK_PRESENT_MODE_FIFO_KHR);
}
- uint32_t max_buffer_count = static_cast<uint32_t>(query_value);
-
- std::vector<VkPresentModeKHR> present_modes;
- if (min_undequeued_buffers + 1 < max_buffer_count)
- present_modes.push_back(VK_PRESENT_MODE_MAILBOX_KHR);
- present_modes.push_back(VK_PRESENT_MODE_FIFO_KHR);
VkPhysicalDevicePresentationPropertiesANDROID present_properties;
QueryPresentationProperties(pdev, &present_properties);
diff --git a/vulkan/scripts/driver_generator.py b/vulkan/scripts/driver_generator.py
index 6a73023193..af56764a21 100644
--- a/vulkan/scripts/driver_generator.py
+++ b/vulkan/scripts/driver_generator.py
@@ -27,11 +27,13 @@ _INTERCEPTED_EXTENSIONS = [
'VK_EXT_hdr_metadata',
'VK_EXT_swapchain_colorspace',
'VK_GOOGLE_display_timing',
+ 'VK_GOOGLE_surfaceless_query',
'VK_KHR_android_surface',
'VK_KHR_get_surface_capabilities2',
'VK_KHR_incremental_present',
'VK_KHR_shared_presentable_image',
'VK_KHR_surface',
+ 'VK_KHR_surface_protected_capabilities',
'VK_KHR_swapchain',
]