summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.bp43
-rw-r--r--aidl/gui/android/hardware/display/IDeviceProductInfoConstants.aidl32
-rw-r--r--cmds/atrace/Android.bp17
-rw-r--r--cmds/bugreport/Android.bp9
-rw-r--r--cmds/bugreport/OWNERS2
-rw-r--r--cmds/bugreportz/Android.bp9
-rw-r--r--cmds/bugreportz/OWNERS2
-rw-r--r--cmds/cmd/Android.bp17
-rw-r--r--cmds/dumpstate/Android.bp9
-rw-r--r--cmds/dumpstate/OWNERS2
-rw-r--r--cmds/dumpsys/Android.bp17
-rw-r--r--cmds/dumpsys/OWNERS2
-rw-r--r--cmds/dumpsys/tests/Android.bp9
-rw-r--r--cmds/flatland/Android.mk3
-rw-r--r--cmds/idlcli/Android.bp11
-rw-r--r--cmds/idlcli/vibrator/CommandGetQFactor.cpp69
-rw-r--r--cmds/idlcli/vibrator/CommandGetResonantFrequency.cpp71
-rw-r--r--cmds/installd/Android.bp9
-rw-r--r--cmds/installd/tests/Android.bp10
-rw-r--r--cmds/ip-up-vpn/Android.mk3
-rw-r--r--cmds/lshal/Android.bp9
-rw-r--r--cmds/lshal/libprocpartition/Android.bp9
-rw-r--r--cmds/rawbu/Android.bp17
-rw-r--r--cmds/rss_hwm_reset/Android.bp9
-rw-r--r--cmds/service/Android.bp17
-rw-r--r--cmds/servicemanager/Android.bp9
-rw-r--r--cmds/surfacereplayer/Android.bp11
-rw-r--r--cmds/surfacereplayer/proto/Android.bp11
-rw-r--r--cmds/surfacereplayer/replayer/Android.bp9
-rw-r--r--cmds/surfacereplayer/replayer/Replayer.cpp1
-rw-r--r--data/etc/android.hardware.keystore.app_attest_key.xml20
-rw-r--r--headers/Android.bp10
-rw-r--r--include/android/choreographer.h4
-rw-r--r--include/android/input.h2
-rw-r--r--include/android/permission_manager.h17
-rw-r--r--include/android/surface_control.h18
-rw-r--r--include/input/InputDevice.h28
-rw-r--r--include/input/InputTransport.h17
-rw-r--r--include/input/TouchVideoFrame.h2
-rw-r--r--include/private/surface_control_private.h71
l---------include/ui/DisplayInfo.h1
l---------include/ui/StaticDisplayInfo.h1
-rw-r--r--libs/adbd_auth/Android.bp9
-rw-r--r--libs/android_runtime_lazy/Android.bp9
-rw-r--r--libs/arect/Android.bp17
-rw-r--r--libs/binder/Android.bp9
-rw-r--r--libs/binder/BpBinder.cpp3
-rw-r--r--libs/binder/Parcel.cpp712
-rw-r--r--libs/binder/ProcessState.cpp6
-rw-r--r--libs/binder/Stability.cpp16
-rw-r--r--libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl13
-rw-r--r--libs/binder/aidl/android/os/IServiceManager.aidl6
-rw-r--r--libs/binder/include/binder/Parcel.h1140
-rw-r--r--libs/binder/include/private/binder/binder_module.h4
-rw-r--r--libs/binder/ndk/Android.bp17
-rw-r--r--libs/binder/ndk/include_cpp/android/binder_to_string.h48
-rw-r--r--libs/binder/ndk/include_platform/android/binder_manager.h51
-rw-r--r--libs/binder/ndk/include_platform/android/binder_stability.h2
-rw-r--r--libs/binder/ndk/libbinder_ndk.map.txt4
-rw-r--r--libs/binder/ndk/service_manager.cpp19
-rw-r--r--libs/binder/ndk/tests/Android.bp9
-rw-r--r--libs/binder/ndk/tests/IBinderNdkUnitTest.aidl3
-rw-r--r--libs/binder/ndk/tests/binderVendorDoubleLoadTest.cpp3
-rw-r--r--libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp108
-rw-r--r--libs/binder/parcel_fuzzer/Android.bp9
-rw-r--r--libs/binder/rust/Android.bp25
-rw-r--r--libs/binder/rust/src/binder.rs158
-rw-r--r--libs/binder/rust/src/lib.rs6
-rw-r--r--libs/binder/rust/src/parcel/parcelable.rs10
-rw-r--r--libs/binder/rust/src/proxy.rs97
-rw-r--r--libs/binder/rust/tests/Android.bp9
-rw-r--r--libs/binder/rust/tests/integration.rs63
-rw-r--r--libs/binder/rust/tests/ndk_rust_interop.rs4
-rw-r--r--libs/binder/tests/Android.bp9
-rw-r--r--libs/binder/tests/binderParcelBenchmark.cpp100
-rw-r--r--libs/binder/tests/fuzzers/Android.bp9
-rw-r--r--libs/binderdebug/Android.bp9
-rw-r--r--libs/binderdebug/tests/Android.bp9
-rw-r--r--libs/binderthreadstate/1.0/Android.bp9
-rw-r--r--libs/binderthreadstate/Android.bp9
-rw-r--r--libs/bufferqueueconverter/Android.bp9
-rw-r--r--libs/cputimeinstate/Android.bp10
-rw-r--r--libs/diskusage/Android.bp9
-rw-r--r--libs/dumputils/Android.bp9
-rw-r--r--libs/fakeservicemanager/Android.bp9
-rw-r--r--libs/gralloc/types/Android.bp9
-rw-r--r--libs/gralloc/types/fuzzer/Android.bp9
-rw-r--r--libs/gralloc/types/tests/Android.bp9
-rw-r--r--libs/graphicsenv/Android.bp9
-rw-r--r--libs/gui/Android.bp9
-rw-r--r--libs/gui/BLASTBufferQueue.cpp30
-rw-r--r--libs/gui/ISurfaceComposer.cpp290
-rw-r--r--libs/gui/LayerDebugInfo.cpp8
-rw-r--r--libs/gui/LayerState.cpp10
-rw-r--r--libs/gui/Surface.cpp14
-rw-r--r--libs/gui/SurfaceComposerClient.cpp120
-rw-r--r--libs/gui/SurfaceControl.cpp2
-rw-r--r--libs/gui/include/gui/BLASTBufferQueue.h26
-rw-r--r--libs/gui/include/gui/ISurfaceComposer.h97
-rw-r--r--libs/gui/include/gui/LayerDebugInfo.h2
-rw-r--r--libs/gui/include/gui/LayerState.h5
-rw-r--r--libs/gui/include/gui/SurfaceComposerClient.h66
-rw-r--r--libs/gui/sysprop/Android.bp9
-rw-r--r--libs/gui/tests/Android.bp9
-rw-r--r--libs/gui/tests/BLASTBufferQueue_test.cpp183
-rw-r--r--libs/gui/tests/Surface_test.cpp32
-rw-r--r--libs/incidentcompanion/Android.bp10
-rw-r--r--libs/input/Android.bp9
-rw-r--r--libs/input/InputDevice.cpp27
-rw-r--r--libs/input/InputTransport.cpp48
-rw-r--r--libs/input/tests/Android.bp9
-rw-r--r--libs/input/tests/InputPublisherAndConsumer_test.cpp48
-rw-r--r--libs/input/tests/StructLayout_test.cpp3
-rw-r--r--libs/math/Android.bp17
-rw-r--r--libs/math/tests/Android.bp9
-rw-r--r--libs/nativebase/Android.bp17
-rw-r--r--libs/nativedisplay/ADisplay.cpp41
-rw-r--r--libs/nativedisplay/Android.bp19
-rw-r--r--libs/nativedisplay/include/apex/display.h5
-rw-r--r--libs/nativewindow/Android.bp19
-rw-r--r--libs/nativewindow/tests/Android.bp11
-rw-r--r--libs/renderengine/Android.bp17
-rw-r--r--libs/renderengine/OWNERS2
-rw-r--r--libs/renderengine/gl/GLESRenderEngine.h1
-rw-r--r--libs/renderengine/gl/filters/BlurFilter.cpp6
-rw-r--r--libs/renderengine/include/renderengine/LayerSettings.h3
-rw-r--r--libs/renderengine/include/renderengine/RenderEngine.h4
-rw-r--r--libs/renderengine/include/renderengine/mock/RenderEngine.h1
-rw-r--r--libs/renderengine/skia/SkiaGLRenderEngine.cpp269
-rw-r--r--libs/renderengine/skia/SkiaGLRenderEngine.h6
-rw-r--r--libs/renderengine/skia/debug/SkiaCapture.cpp68
-rw-r--r--libs/renderengine/skia/debug/SkiaCapture.h20
-rw-r--r--libs/renderengine/skia/filters/BlurFilter.cpp132
-rw-r--r--libs/renderengine/skia/filters/BlurFilter.h11
-rw-r--r--libs/renderengine/tests/Android.bp9
-rw-r--r--libs/renderengine/tests/RenderEngineTest.cpp20
-rw-r--r--libs/renderengine/tests/RenderEngineThreadedTest.cpp11
-rw-r--r--libs/renderengine/threaded/RenderEngineThreaded.cpp15
-rw-r--r--libs/renderengine/threaded/RenderEngineThreaded.h1
-rw-r--r--libs/sensor/Android.bp9
-rw-r--r--libs/sensor/ISensorServer.cpp6
-rw-r--r--libs/sensor/Sensor.cpp13
-rw-r--r--libs/sensor/SensorManager.cpp7
-rw-r--r--libs/sensor/include/sensor/ISensorServer.h2
-rw-r--r--libs/sensor/include/sensor/Sensor.h3
-rw-r--r--libs/sensor/include/sensor/SensorManager.h3
-rw-r--r--libs/sensor/tests/Android.bp9
-rw-r--r--libs/sensorprivacy/Android.bp9
-rw-r--r--libs/ui/Android.bp22
-rw-r--r--libs/ui/DisplayMode.cpp69
-rw-r--r--libs/ui/DynamicDisplayInfo.cpp72
-rw-r--r--libs/ui/HdrCapabilities.cpp4
-rw-r--r--libs/ui/StaticDisplayInfo.cpp (renamed from libs/ui/DisplayInfo.cpp)12
-rw-r--r--libs/ui/include/ui/DisplayMode.h17
-rw-r--r--libs/ui/include/ui/DynamicDisplayInfo.h60
-rw-r--r--libs/ui/include/ui/FloatRect.h2
-rw-r--r--libs/ui/include/ui/HdrCapabilities.h6
-rw-r--r--libs/ui/include/ui/StaticDisplayInfo.h (renamed from libs/ui/include/ui/DisplayInfo.h)7
-rw-r--r--libs/ui/include/ui/StretchEffect.h58
-rw-r--r--libs/ui/include_private/ui/FlattenableHelpers.h17
l---------libs/ui/include_vndk/ui/DisplayInfo.h1
l---------libs/ui/include_vndk/ui/StaticDisplayInfo.h1
-rw-r--r--libs/ui/tests/Android.bp9
-rw-r--r--libs/ui/tests/FlattenableHelpers_test.cpp63
-rw-r--r--libs/ui/tools/Android.bp9
-rw-r--r--libs/vibrator/Android.bp9
-rw-r--r--libs/vibrator/fuzzer/Android.bp9
-rw-r--r--libs/vr/Android.bp11
-rw-r--r--libs/vr/libbroadcastring/Android.bp11
-rw-r--r--libs/vr/libbufferhub/Android.bp11
-rw-r--r--libs/vr/libbufferhubqueue/Android.bp11
-rw-r--r--libs/vr/libbufferhubqueue/benchmarks/Android.bp11
-rw-r--r--libs/vr/libbufferhubqueue/tests/Android.bp11
-rw-r--r--libs/vr/libdisplay/Android.bp11
-rw-r--r--libs/vr/libdvr/Android.bp11
-rw-r--r--libs/vr/libdvr/tests/Android.bp11
-rw-r--r--libs/vr/libdvrcommon/Android.bp11
-rw-r--r--libs/vr/libpdx/Android.bp9
-rw-r--r--libs/vr/libpdx/fuzz/Android.bp9
-rw-r--r--libs/vr/libpdx_default_transport/Android.bp12
-rw-r--r--libs/vr/libpdx_uds/Android.bp11
-rw-r--r--libs/vr/libperformance/Android.bp11
-rw-r--r--libs/vr/libvr_manager/Android.bp9
-rw-r--r--libs/vr/libvrflinger/Android.bp11
-rw-r--r--libs/vr/libvrflinger/tests/Android.bp11
-rw-r--r--libs/vr/libvrsensor/Android.bp12
-rw-r--r--opengl/Android.bp12
-rw-r--r--opengl/libs/Android.bp9
-rw-r--r--opengl/tests/Android.bp13
-rw-r--r--opengl/tests/EGLTest/Android.bp9
-rw-r--r--opengl/tests/angeles/Android.bp45
-rw-r--r--opengl/tests/configdump/Android.bp11
-rw-r--r--opengl/tests/fillrate/Android.bp9
-rw-r--r--opengl/tests/filter/Android.bp11
-rw-r--r--opengl/tests/finish/Android.bp9
-rw-r--r--opengl/tests/gl2_basic/Android.bp9
-rw-r--r--opengl/tests/gl2_cameraeye/Android.bp9
-rw-r--r--opengl/tests/gl2_copyTexImage/Android.bp9
-rw-r--r--opengl/tests/gl2_java/Android.bp9
-rw-r--r--opengl/tests/gl2_jni/Android.bp9
-rw-r--r--opengl/tests/gl2_yuvtex/Android.bp9
-rw-r--r--opengl/tests/gl_basic/Android.bp11
-rw-r--r--opengl/tests/gl_jni/Android.bp9
-rw-r--r--opengl/tests/gl_perf/Android.bp9
-rw-r--r--opengl/tests/gl_perfapp/Android.bp9
-rw-r--r--opengl/tests/gl_yuvtex/Android.bp9
-rw-r--r--opengl/tests/gldual/Android.bp9
-rw-r--r--opengl/tests/gralloc/Android.bp9
-rw-r--r--opengl/tests/hwc/Android.bp9
-rw-r--r--opengl/tests/lib/Android.bp9
-rw-r--r--opengl/tests/lighting1709/Android.bp9
-rw-r--r--opengl/tests/linetex/Android.bp9
-rw-r--r--opengl/tests/swapinterval/Android.bp9
-rw-r--r--opengl/tests/testFramerate/Android.bp9
-rw-r--r--opengl/tests/testLatency/Android.bp9
-rw-r--r--opengl/tests/testPauseResume/Android.bp9
-rw-r--r--opengl/tests/testViewport/Android.bp9
-rw-r--r--opengl/tests/textures/Android.bp9
-rw-r--r--opengl/tests/tritex/Android.bp11
-rw-r--r--services/audiomanager/Android.bp9
-rw-r--r--services/automotive/display/Android.bp9
-rw-r--r--services/batteryservice/Android.bp9
-rw-r--r--services/displayservice/Android.bp9
-rw-r--r--services/gpuservice/Android.bp9
-rw-r--r--services/gpuservice/bpfprogs/Android.bp9
-rw-r--r--services/gpuservice/gpumem/Android.bp9
-rw-r--r--services/gpuservice/gpustats/Android.bp9
-rw-r--r--services/gpuservice/tests/unittests/Android.bp9
-rw-r--r--services/gpuservice/tracing/Android.bp9
-rw-r--r--services/inputflinger/Android.bp9
-rw-r--r--services/inputflinger/benchmarks/Android.bp9
-rw-r--r--services/inputflinger/dispatcher/Android.bp9
-rw-r--r--services/inputflinger/dispatcher/Entry.h1
-rw-r--r--services/inputflinger/dispatcher/InputDispatcher.cpp50
-rw-r--r--services/inputflinger/dispatcher/InputDispatcher.h5
-rw-r--r--services/inputflinger/host/Android.bp9
-rw-r--r--services/inputflinger/include/InputReaderBase.h13
-rw-r--r--services/inputflinger/reader/Android.bp10
-rw-r--r--services/inputflinger/reader/EventHub.cpp347
-rw-r--r--services/inputflinger/reader/InputDevice.cpp47
-rw-r--r--services/inputflinger/reader/InputReader.cpp136
-rw-r--r--services/inputflinger/reader/include/EventHub.h78
-rw-r--r--services/inputflinger/reader/include/InputDevice.h29
-rw-r--r--services/inputflinger/reader/include/InputReader.h36
-rw-r--r--services/inputflinger/reader/include/InputReaderContext.h27
-rw-r--r--services/inputflinger/reader/mapper/BatteryInputMapper.cpp2
-rw-r--r--services/inputflinger/reader/mapper/CursorInputMapper.cpp56
-rw-r--r--services/inputflinger/reader/mapper/InputMapper.h7
-rw-r--r--services/inputflinger/reader/mapper/JoystickInputMapper.cpp13
-rw-r--r--services/inputflinger/reader/mapper/KeyboardInputMapper.cpp7
-rw-r--r--services/inputflinger/reader/mapper/LightInputMapper.cpp478
-rw-r--r--services/inputflinger/reader/mapper/LightInputMapper.h135
-rw-r--r--services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp13
-rw-r--r--services/inputflinger/reader/mapper/SensorInputMapper.cpp11
-rw-r--r--services/inputflinger/reader/mapper/SwitchInputMapper.cpp5
-rw-r--r--services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h5
-rw-r--r--services/inputflinger/reader/mapper/TouchInputMapper.cpp142
-rw-r--r--services/inputflinger/reader/mapper/VibratorInputMapper.cpp6
-rw-r--r--services/inputflinger/reporter/Android.bp10
-rw-r--r--services/inputflinger/tests/Android.bp9
-rw-r--r--services/inputflinger/tests/InputDispatcher_test.cpp295
-rw-r--r--services/inputflinger/tests/InputReader_test.cpp239
-rw-r--r--services/powermanager/Android.bp9
-rw-r--r--services/schedulerservice/Android.bp9
-rw-r--r--services/sensorservice/Android.bp9
-rw-r--r--services/sensorservice/SensorDevice.cpp15
-rw-r--r--services/sensorservice/SensorDevice.h4
-rw-r--r--services/sensorservice/SensorDirectConnection.cpp101
-rw-r--r--services/sensorservice/SensorDirectConnection.h10
-rw-r--r--services/sensorservice/SensorEventConnection.cpp149
-rw-r--r--services/sensorservice/SensorEventConnection.h22
-rw-r--r--services/sensorservice/SensorService.cpp169
-rw-r--r--services/sensorservice/SensorService.h38
-rw-r--r--services/sensorservice/hidl/Android.bp9
-rw-r--r--services/sensorservice/tests/Android.bp9
-rw-r--r--services/stats/Android.bp18
-rw-r--r--services/stats/StatsAidl.cpp79
-rw-r--r--services/stats/android.frameworks.stats@1.0-service.xml6
-rw-r--r--services/stats/include/stats/StatsAidl.h38
-rw-r--r--services/surfaceflinger/Android.bp13
-rw-r--r--services/surfaceflinger/BufferLayer.cpp8
-rw-r--r--services/surfaceflinger/BufferStateLayer.cpp39
-rw-r--r--services/surfaceflinger/BufferStateLayer.h1
-rw-r--r--services/surfaceflinger/ClientCache.cpp16
-rw-r--r--services/surfaceflinger/ClientCache.h2
-rw-r--r--services/surfaceflinger/CompositionEngine/Android.bp9
-rw-r--r--services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h4
-rw-r--r--services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h3
-rw-r--r--services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DumpHelpers.h2
-rw-r--r--services/surfaceflinger/CompositionEngine/src/Display.cpp3
-rw-r--r--services/surfaceflinger/CompositionEngine/src/DumpHelpers.cpp6
-rw-r--r--services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp3
-rw-r--r--services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp10
-rw-r--r--services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h2
-rw-r--r--services/surfaceflinger/DisplayDevice.cpp7
-rw-r--r--services/surfaceflinger/DisplayDevice.h10
-rw-r--r--services/surfaceflinger/DisplayHardware/DisplayMode.h5
-rw-r--r--services/surfaceflinger/DisplayHardware/HWC2.cpp7
-rw-r--r--services/surfaceflinger/DisplayHardware/HWC2.h6
-rw-r--r--services/surfaceflinger/DisplayHardware/HWComposer.cpp10
-rw-r--r--services/surfaceflinger/DisplayHardware/HWComposer.h4
-rw-r--r--services/surfaceflinger/Fps.h2
-rw-r--r--services/surfaceflinger/FrameTimeline/FrameTimeline.cpp202
-rw-r--r--services/surfaceflinger/FrameTimeline/FrameTimeline.h41
-rw-r--r--services/surfaceflinger/Layer.cpp96
-rw-r--r--services/surfaceflinger/Layer.h15
-rw-r--r--services/surfaceflinger/RefreshRateOverlay.cpp3
-rw-r--r--services/surfaceflinger/RegionSamplingThread.cpp3
-rw-r--r--services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp8
-rw-r--r--services/surfaceflinger/Scheduler/Scheduler.h3
-rw-r--r--services/surfaceflinger/SurfaceFlinger.cpp288
-rw-r--r--services/surfaceflinger/SurfaceFlinger.h31
-rw-r--r--services/surfaceflinger/SurfaceInterceptor.cpp3
-rw-r--r--services/surfaceflinger/SurfaceTracing.cpp2
-rw-r--r--services/surfaceflinger/SurfaceTracing.h4
-rw-r--r--services/surfaceflinger/TimeStats/Android.bp9
-rw-r--r--services/surfaceflinger/TimeStats/TimeStats.cpp325
-rw-r--r--services/surfaceflinger/TimeStats/TimeStats.h86
-rw-r--r--services/surfaceflinger/TimeStats/timestatsproto/Android.bp9
-rw-r--r--services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp93
-rw-r--r--services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h103
-rw-r--r--services/surfaceflinger/layerproto/Android.bp9
-rw-r--r--services/surfaceflinger/sysprop/Android.bp9
-rw-r--r--services/surfaceflinger/tests/Android.bp9
-rw-r--r--services/surfaceflinger/tests/Credentials_test.cpp26
-rw-r--r--services/surfaceflinger/tests/DisplayConfigs_test.cpp14
-rw-r--r--services/surfaceflinger/tests/fakehwc/Android.bp9
-rw-r--r--services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp26
-rw-r--r--services/surfaceflinger/tests/unittests/Android.bp10
-rw-r--r--services/surfaceflinger/tests/unittests/CompositionTest.cpp4
-rw-r--r--services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp8
-rw-r--r--services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h13
-rw-r--r--services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp818
-rw-r--r--services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp20
-rw-r--r--services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp28
-rw-r--r--services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h8
-rw-r--r--services/surfaceflinger/tests/unittests/TimeStatsTest.cpp307
-rw-r--r--services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp153
-rw-r--r--services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp43
-rw-r--r--services/surfaceflinger/tests/unittests/mock/MockFrameTimeline.h2
-rw-r--r--services/surfaceflinger/tests/unittests/mock/MockTimeStats.h9
-rw-r--r--services/surfaceflinger/tests/vsync/Android.bp9
-rw-r--r--services/surfaceflinger/tests/waitforvsync/Android.bp9
-rw-r--r--services/utils/Android.bp9
-rw-r--r--services/utils/tests/Android.bp9
-rw-r--r--services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp2
-rw-r--r--services/vibratorservice/test/VibratorManagerHalWrapperAidlTest.cpp2
-rw-r--r--services/vr/Android.bp10
-rw-r--r--services/vr/bufferhubd/Android.bp11
-rw-r--r--services/vr/hardware_composer/Android.bp9
-rw-r--r--services/vr/hardware_composer/aidl/Android.bp11
-rw-r--r--services/vr/performanced/Android.bp9
-rw-r--r--services/vr/virtual_touchpad/Android.bp9
-rw-r--r--vulkan/Android.bp10
-rw-r--r--vulkan/libvulkan/Android.bp9
-rw-r--r--vulkan/nulldrv/Android.bp9
-rw-r--r--vulkan/vkjson/Android.bp9
357 files changed, 9174 insertions, 3340 deletions
diff --git a/Android.bp b/Android.bp
index 9829c7fbad..298c01abba 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1,3 +1,41 @@
+package {
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
+// Added automatically by a large-scale-change that took the approach of
+// 'apply every license found to every target'. While this makes sure we respect
+// every license restriction, it may not be entirely correct.
+//
+// e.g. GPL in an MIT project might only apply to the contrib/ directory.
+//
+// Please consider splitting the single license below into multiple licenses,
+// taking care not to lose any license_kind information, and overriding the
+// default license using the 'licenses: [...]' property on targets as needed.
+//
+// For unused files, consider creating a 'fileGroup' with "//visibility:private"
+// to attach the license to, and including a comment whether the files may be
+// used in the current project.
+//
+// large-scale-change filtered out the below license kinds as false-positives:
+// SPDX-license-identifier-LGPL
+// SPDX-license-identifier-LGPL-2.1
+// SPDX-license-identifier-LGPL-3.0
+// See: http://go/android-license-faq
+license {
+ name: "frameworks_native_license",
+ visibility: [":__subpackages__"],
+ license_kinds: [
+ "SPDX-license-identifier-Apache-2.0",
+ "SPDX-license-identifier-BSD",
+ "SPDX-license-identifier-MIT",
+ "SPDX-license-identifier-Unicode-DFS",
+ "legacy_notice",
+ ],
+ license_text: [
+ "NOTICE",
+ ],
+}
+
ndk_headers {
name: "libandroid_headers",
from: "include/android",
@@ -43,3 +81,8 @@ filegroup {
":framework_native_aidl_gui",
],
}
+
+cc_library_headers{
+ name: "libandroid_headers_private",
+ export_include_dirs: ["include/private"],
+} \ No newline at end of file
diff --git a/aidl/gui/android/hardware/display/IDeviceProductInfoConstants.aidl b/aidl/gui/android/hardware/display/IDeviceProductInfoConstants.aidl
new file mode 100644
index 0000000000..7cc272adff
--- /dev/null
+++ b/aidl/gui/android/hardware/display/IDeviceProductInfoConstants.aidl
@@ -0,0 +1,32 @@
+/*
+ * 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.hardware.display;
+
+/** @hide */
+interface IDeviceProductInfoConstants {
+ /** The device connection to the display sink is unknown. */
+ const int CONNECTION_TO_SINK_UNKNOWN = 0;
+
+ /** The device is built-in in the display sink. */
+ const int CONNECTION_TO_SINK_BUILT_IN = 1;
+
+ /** The device is directly connected to the display sink. */
+ const int CONNECTION_TO_SINK_DIRECT = 2;
+
+ /** The device is transitively connected to the display sink. */
+ const int CONNECTION_TO_SINK_TRANSITIVE = 3;
+} \ No newline at end of file
diff --git a/cmds/atrace/Android.bp b/cmds/atrace/Android.bp
index e7d0ad0549..aa0ef253bf 100644
--- a/cmds/atrace/Android.bp
+++ b/cmds/atrace/Android.bp
@@ -1,5 +1,22 @@
// Copyright 2012 The Android Open Source Project
+package {
+ default_applicable_licenses: ["frameworks_native_cmds_atrace_license"],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+ name: "frameworks_native_cmds_atrace_license",
+ visibility: [":__subpackages__"],
+ license_kinds: [
+ "SPDX-license-identifier-Apache-2.0",
+ ],
+ license_text: [
+ "NOTICE",
+ ],
+}
+
cc_binary {
name: "atrace",
srcs: ["atrace.cpp"],
diff --git a/cmds/bugreport/Android.bp b/cmds/bugreport/Android.bp
index 24044a64b0..8262aed97b 100644
--- a/cmds/bugreport/Android.bp
+++ b/cmds/bugreport/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_binary {
name: "bugreport",
srcs: ["bugreport.cpp"],
diff --git a/cmds/bugreport/OWNERS b/cmds/bugreport/OWNERS
index 1ba7cffa0e..2a9b681318 100644
--- a/cmds/bugreport/OWNERS
+++ b/cmds/bugreport/OWNERS
@@ -1,6 +1,4 @@
set noparent
-felipeal@google.com
nandana@google.com
jsharkey@android.com
-enh@google.com
diff --git a/cmds/bugreportz/Android.bp b/cmds/bugreportz/Android.bp
index 924a3a351b..332f858e92 100644
--- a/cmds/bugreportz/Android.bp
+++ b/cmds/bugreportz/Android.bp
@@ -1,5 +1,14 @@
// bugreportz
// ==========
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_binary {
name: "bugreportz",
diff --git a/cmds/bugreportz/OWNERS b/cmds/bugreportz/OWNERS
index 1ba7cffa0e..2a9b681318 100644
--- a/cmds/bugreportz/OWNERS
+++ b/cmds/bugreportz/OWNERS
@@ -1,6 +1,4 @@
set noparent
-felipeal@google.com
nandana@google.com
jsharkey@android.com
-enh@google.com
diff --git a/cmds/cmd/Android.bp b/cmds/cmd/Android.bp
index 8ea71cd048..c900a24e15 100644
--- a/cmds/cmd/Android.bp
+++ b/cmds/cmd/Android.bp
@@ -1,3 +1,20 @@
+package {
+ default_applicable_licenses: ["frameworks_native_cmds_cmd_license"],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+ name: "frameworks_native_cmds_cmd_license",
+ visibility: [":__subpackages__"],
+ license_kinds: [
+ "SPDX-license-identifier-Apache-2.0",
+ ],
+ license_text: [
+ "NOTICE",
+ ],
+}
+
cc_library_static {
name: "libcmd",
diff --git a/cmds/dumpstate/Android.bp b/cmds/dumpstate/Android.bp
index 34e9a85af3..f48f1fb6f8 100644
--- a/cmds/dumpstate/Android.bp
+++ b/cmds/dumpstate/Android.bp
@@ -13,6 +13,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_defaults {
name: "dumpstate_cflag_defaults",
cflags: [
diff --git a/cmds/dumpstate/OWNERS b/cmds/dumpstate/OWNERS
index 1ba7cffa0e..2a9b681318 100644
--- a/cmds/dumpstate/OWNERS
+++ b/cmds/dumpstate/OWNERS
@@ -1,6 +1,4 @@
set noparent
-felipeal@google.com
nandana@google.com
jsharkey@android.com
-enh@google.com
diff --git a/cmds/dumpsys/Android.bp b/cmds/dumpsys/Android.bp
index f99588ffc8..91aa018451 100644
--- a/cmds/dumpsys/Android.bp
+++ b/cmds/dumpsys/Android.bp
@@ -1,3 +1,20 @@
+package {
+ default_applicable_licenses: ["frameworks_native_cmds_dumpsys_license"],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+ name: "frameworks_native_cmds_dumpsys_license",
+ visibility: [":__subpackages__"],
+ license_kinds: [
+ "SPDX-license-identifier-Apache-2.0",
+ ],
+ license_text: [
+ "NOTICE",
+ ],
+}
+
cc_defaults {
name: "dumpsys_defaults",
diff --git a/cmds/dumpsys/OWNERS b/cmds/dumpsys/OWNERS
index 1ba7cffa0e..2a9b681318 100644
--- a/cmds/dumpsys/OWNERS
+++ b/cmds/dumpsys/OWNERS
@@ -1,6 +1,4 @@
set noparent
-felipeal@google.com
nandana@google.com
jsharkey@android.com
-enh@google.com
diff --git a/cmds/dumpsys/tests/Android.bp b/cmds/dumpsys/tests/Android.bp
index e182b9d287..6854c7550e 100644
--- a/cmds/dumpsys/tests/Android.bp
+++ b/cmds/dumpsys/tests/Android.bp
@@ -1,4 +1,13 @@
// Build the unit tests for dumpsys
+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_cmds_dumpsys_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_cmds_dumpsys_license"],
+}
+
cc_test {
name: "dumpsys_test",
test_suites: ["device-tests"],
diff --git a/cmds/flatland/Android.mk b/cmds/flatland/Android.mk
index 7aa111c7ae..754a99caf6 100644
--- a/cmds/flatland/Android.mk
+++ b/cmds/flatland/Android.mk
@@ -11,6 +11,9 @@ LOCAL_SRC_FILES:= \
LOCAL_CFLAGS := -Wall -Werror
LOCAL_MODULE:= flatland
+LOCAL_LICENSE_KINDS:= SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS:= notice
+LOCAL_NOTICE_FILE:= $(LOCAL_PATH)/../../NOTICE
LOCAL_MODULE_TAGS := tests
diff --git a/cmds/idlcli/Android.bp b/cmds/idlcli/Android.bp
index 72ffc94d22..1ebdc47ebc 100644
--- a/cmds/idlcli/Android.bp
+++ b/cmds/idlcli/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_defaults {
name: "idlcli-defaults",
shared_libs: [
@@ -44,6 +53,8 @@ cc_library {
"vibrator/CommandGetCompositionDelayMax.cpp",
"vibrator/CommandGetCompositionSizeMax.cpp",
"vibrator/CommandGetPrimitiveDuration.cpp",
+ "vibrator/CommandGetQFactor.cpp",
+ "vibrator/CommandGetResonantFrequency.cpp",
"vibrator/CommandGetSupportedAlwaysOnEffects.cpp",
"vibrator/CommandGetSupportedEffects.cpp",
"vibrator/CommandGetSupportedPrimitives.cpp",
diff --git a/cmds/idlcli/vibrator/CommandGetQFactor.cpp b/cmds/idlcli/vibrator/CommandGetQFactor.cpp
new file mode 100644
index 0000000000..a2681e905b
--- /dev/null
+++ b/cmds/idlcli/vibrator/CommandGetQFactor.cpp
@@ -0,0 +1,69 @@
+/*
+ * 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 "utils.h"
+#include "vibrator.h"
+
+namespace android {
+namespace idlcli {
+
+class CommandVibrator;
+
+namespace vibrator {
+
+class CommandGetQFactor : public Command {
+ std::string getDescription() const override { return "Retrieves vibrator Q factor."; }
+
+ std::string getUsageSummary() const override { return ""; }
+
+ UsageDetails getUsageDetails() const override {
+ UsageDetails details{};
+ return details;
+ }
+
+ Status doArgs(Args &args) override {
+ if (!args.empty()) {
+ std::cerr << "Unexpected Arguments!" << std::endl;
+ return USAGE;
+ }
+ return OK;
+ }
+
+ Status doMain(Args && /*args*/) override {
+ std::string statusStr;
+ float qFactor;
+ Status ret;
+
+ if (auto hal = getHal<aidl::IVibrator>()) {
+ auto status = hal->call(&aidl::IVibrator::getQFactor, &qFactor);
+ statusStr = status.getDescription();
+ ret = status.isOk() ? OK : ERROR;
+ } else {
+ return UNAVAILABLE;
+ }
+
+ std::cout << "Status: " << statusStr << std::endl;
+ std::cout << "Q Factor: " << qFactor << std::endl;
+
+ return ret;
+ }
+};
+
+static const auto Command =
+ CommandRegistry<CommandVibrator>::Register<CommandGetQFactor>("getQFactor");
+
+} // namespace vibrator
+} // namespace idlcli
+} // namespace android
diff --git a/cmds/idlcli/vibrator/CommandGetResonantFrequency.cpp b/cmds/idlcli/vibrator/CommandGetResonantFrequency.cpp
new file mode 100644
index 0000000000..81a6391de5
--- /dev/null
+++ b/cmds/idlcli/vibrator/CommandGetResonantFrequency.cpp
@@ -0,0 +1,71 @@
+/*
+ * 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 "utils.h"
+#include "vibrator.h"
+
+namespace android {
+namespace idlcli {
+
+class CommandVibrator;
+
+namespace vibrator {
+
+class CommandGetResonantFrequency : public Command {
+ std::string getDescription() const override {
+ return "Retrieves vibrator resonant frequency in Hz.";
+ }
+
+ std::string getUsageSummary() const override { return ""; }
+
+ UsageDetails getUsageDetails() const override {
+ UsageDetails details{};
+ return details;
+ }
+
+ Status doArgs(Args &args) override {
+ if (!args.empty()) {
+ std::cerr << "Unexpected Arguments!" << std::endl;
+ return USAGE;
+ }
+ return OK;
+ }
+
+ Status doMain(Args && /*args*/) override {
+ std::string statusStr;
+ float resonantFrequencyHz;
+ Status ret;
+
+ if (auto hal = getHal<aidl::IVibrator>()) {
+ auto status = hal->call(&aidl::IVibrator::getResonantFrequency, &resonantFrequencyHz);
+ statusStr = status.getDescription();
+ ret = status.isOk() ? OK : ERROR;
+ } else {
+ return UNAVAILABLE;
+ }
+
+ std::cout << "Status: " << statusStr << std::endl;
+ std::cout << "Resonant Frequency: " << resonantFrequencyHz << " Hz" << std::endl;
+
+ return ret;
+ }
+};
+
+static const auto Command = CommandRegistry<CommandVibrator>::Register<CommandGetResonantFrequency>(
+ "getResonantFrequency");
+
+} // namespace vibrator
+} // namespace idlcli
+} // namespace android
diff --git a/cmds/installd/Android.bp b/cmds/installd/Android.bp
index cbe857aacb..5c2211ff9a 100644
--- a/cmds/installd/Android.bp
+++ b/cmds/installd/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_defaults {
name: "installd_defaults",
diff --git a/cmds/installd/tests/Android.bp b/cmds/installd/tests/Android.bp
index 7c9e3b2e38..f67ab812fa 100644
--- a/cmds/installd/tests/Android.bp
+++ b/cmds/installd/tests/Android.bp
@@ -1,4 +1,13 @@
// Build the unit tests for installd
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_test {
name: "installd_utils_test",
test_suites: ["device-tests"],
@@ -157,4 +166,3 @@ cc_test {
"libotapreoptparameters"
],
}
-
diff --git a/cmds/ip-up-vpn/Android.mk b/cmds/ip-up-vpn/Android.mk
index e1e2204233..396ae9db04 100644
--- a/cmds/ip-up-vpn/Android.mk
+++ b/cmds/ip-up-vpn/Android.mk
@@ -21,6 +21,9 @@ LOCAL_SRC_FILES := ip-up-vpn.c
LOCAL_CFLAGS := -Wall -Werror
LOCAL_SHARED_LIBRARIES := libcutils liblog
LOCAL_MODULE := ip-up-vpn
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
+LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../NOTICE
LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/ppp
LOCAL_MODULE_TAGS := optional
diff --git a/cmds/lshal/Android.bp b/cmds/lshal/Android.bp
index 0cbb80feb2..649e53a8aa 100644
--- a/cmds/lshal/Android.bp
+++ b/cmds/lshal/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library_static {
name: "liblshal",
shared_libs: [
diff --git a/cmds/lshal/libprocpartition/Android.bp b/cmds/lshal/libprocpartition/Android.bp
index 9592111796..cbfbdc9223 100644
--- a/cmds/lshal/libprocpartition/Android.bp
+++ b/cmds/lshal/libprocpartition/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library_static {
name: "libprocpartition",
shared_libs: [
diff --git a/cmds/rawbu/Android.bp b/cmds/rawbu/Android.bp
index 363ffc1aaf..e34119d1d1 100644
--- a/cmds/rawbu/Android.bp
+++ b/cmds/rawbu/Android.bp
@@ -1,5 +1,22 @@
// Copyright 2009 The Android Open Source Project
+package {
+ default_applicable_licenses: ["frameworks_native_cmds_rawbu_license"],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+ name: "frameworks_native_cmds_rawbu_license",
+ visibility: [":__subpackages__"],
+ license_kinds: [
+ "SPDX-license-identifier-Apache-2.0",
+ ],
+ license_text: [
+ "NOTICE",
+ ],
+}
+
cc_binary {
name: "rawbu",
diff --git a/cmds/rss_hwm_reset/Android.bp b/cmds/rss_hwm_reset/Android.bp
index 15f10efdee..cd335d44cc 100644
--- a/cmds/rss_hwm_reset/Android.bp
+++ b/cmds/rss_hwm_reset/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_binary {
name: "rss_hwm_reset",
diff --git a/cmds/service/Android.bp b/cmds/service/Android.bp
index a5b1ac5c5f..3e8e3f67f8 100644
--- a/cmds/service/Android.bp
+++ b/cmds/service/Android.bp
@@ -1,3 +1,20 @@
+package {
+ default_applicable_licenses: ["frameworks_native_cmds_service_license"],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+ name: "frameworks_native_cmds_service_license",
+ visibility: [":__subpackages__"],
+ license_kinds: [
+ "SPDX-license-identifier-Apache-2.0",
+ ],
+ license_text: [
+ "NOTICE",
+ ],
+}
+
cc_binary {
name: "service",
diff --git a/cmds/servicemanager/Android.bp b/cmds/servicemanager/Android.bp
index b1392515a2..9de344a820 100644
--- a/cmds/servicemanager/Android.bp
+++ b/cmds/servicemanager/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_defaults {
name: "servicemanager_defaults",
diff --git a/cmds/surfacereplayer/Android.bp b/cmds/surfacereplayer/Android.bp
index d4c037ab7d..34fc8b10ea 100644
--- a/cmds/surfacereplayer/Android.bp
+++ b/cmds/surfacereplayer/Android.bp
@@ -1,4 +1,13 @@
+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"],
+}
+
subdirs = [
"proto",
"replayer",
-] \ No newline at end of file
+]
diff --git a/cmds/surfacereplayer/proto/Android.bp b/cmds/surfacereplayer/proto/Android.bp
index 71a5e23a9e..dae976e3df 100644
--- a/cmds/surfacereplayer/proto/Android.bp
+++ b/cmds/surfacereplayer/proto/Android.bp
@@ -1,3 +1,14 @@
+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
+ // SPDX-license-identifier-MIT
+ // SPDX-license-identifier-Unicode-DFS
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library_static {
name: "libtrace_proto",
srcs: [
diff --git a/cmds/surfacereplayer/replayer/Android.bp b/cmds/surfacereplayer/replayer/Android.bp
index 7632311906..3985230f08 100644
--- a/cmds/surfacereplayer/replayer/Android.bp
+++ b/cmds/surfacereplayer/replayer/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library_shared {
name: "libsurfacereplayer",
srcs: [
diff --git a/cmds/surfacereplayer/replayer/Replayer.cpp b/cmds/surfacereplayer/replayer/Replayer.cpp
index 58d6582e0b..3c53c025ff 100644
--- a/cmds/surfacereplayer/replayer/Replayer.cpp
+++ b/cmds/surfacereplayer/replayer/Replayer.cpp
@@ -28,7 +28,6 @@
#include <gui/Surface.h>
#include <private/gui/ComposerService.h>
-#include <ui/DisplayInfo.h>
#include <utils/Log.h>
#include <utils/String8.h>
#include <utils/Trace.h>
diff --git a/data/etc/android.hardware.keystore.app_attest_key.xml b/data/etc/android.hardware.keystore.app_attest_key.xml
new file mode 100644
index 0000000000..8adc4399d3
--- /dev/null
+++ b/data/etc/android.hardware.keystore.app_attest_key.xml
@@ -0,0 +1,20 @@
+<?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 support app attestation keys (i.e. KeyMint 1.0). -->
+<permissions>
+ <feature name="android.hardware.keystore.app_attest_key" />
+</permissions>
diff --git a/headers/Android.bp b/headers/Android.bp
index 8f41c2b75b..7481a230c3 100644
--- a/headers/Android.bp
+++ b/headers/Android.bp
@@ -1,3 +1,13 @@
+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
+ // SPDX-license-identifier-MIT
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library_headers {
name: "media_plugin_headers",
vendor_available: true,
diff --git a/include/android/choreographer.h b/include/android/choreographer.h
index 8039bb0d79..cc5420e239 100644
--- a/include/android/choreographer.h
+++ b/include/android/choreographer.h
@@ -127,6 +127,10 @@ void AChoreographer_postFrameCallbackDelayed64(AChoreographer* choreographer,
* to listen directly to DisplayManager.DisplayListener#onDisplayChanged events
* instead.
*
+ * As of API level 31, this api is guaranteed to have a consistent view with DisplayManager;
+ * Display#getRefreshRate is guaranteed to not return a stale refresh rate when invoked from this
+ * callback.
+ *
* Available since API level 30.
*/
void AChoreographer_registerRefreshRateCallback(AChoreographer* choreographer,
diff --git a/include/android/input.h b/include/android/input.h
index b70d42427d..797348742d 100644
--- a/include/android/input.h
+++ b/include/android/input.h
@@ -859,7 +859,7 @@ enum {
/** HDMI */
AINPUT_SOURCE_HDMI = 0x02000000 | AINPUT_SOURCE_CLASS_BUTTON,
/** sensor */
- AINPUT_SOURCE_SENSOR = 0x04000000 | AINPUT_SOURCE_UNKNOWN,
+ AINPUT_SOURCE_SENSOR = 0x04000000 | AINPUT_SOURCE_CLASS_NONE,
/** rotary encoder */
AINPUT_SOURCE_ROTARY_ENCODER = 0x00400000 | AINPUT_SOURCE_CLASS_NONE,
diff --git a/include/android/permission_manager.h b/include/android/permission_manager.h
index 2d5d060840..753b6d16de 100644
--- a/include/android/permission_manager.h
+++ b/include/android/permission_manager.h
@@ -14,6 +14,17 @@
* limitations under the License.
*/
+/**
+ * Structures and functions related to permission checks in native code.
+ *
+ * @addtogroup Permission
+ * @{
+ */
+
+/**
+ * @file permission_manager.h
+ */
+
#ifndef ANDROID_PERMISSION_MANAGER_H
#define ANDROID_PERMISSION_MANAGER_H
@@ -48,8 +59,8 @@ enum {
enum {
/**
* This is returned if the permission check completed without errors.
- * The output result is valid and contains one of {PERMISSION_MANAGER_PERMISSION_GRANTED,
- * PERMISSION_MANAGER_PERMISSION_DENIED}.
+ * The output result is valid and contains one of {::PERMISSION_MANAGER_PERMISSION_GRANTED,
+ * ::PERMISSION_MANAGER_PERMISSION_DENIED}.
*/
PERMISSION_MANAGER_STATUS_OK = 0,
/**
@@ -85,3 +96,5 @@ int32_t APermissionManager_checkPermission(const char* permission,
__END_DECLS
#endif // ANDROID_PERMISSION_MANAGER_H
+
+/** @} */
diff --git a/include/android/surface_control.h b/include/android/surface_control.h
index 98fd875968..b836581226 100644
--- a/include/android/surface_control.h
+++ b/include/android/surface_control.h
@@ -67,9 +67,21 @@ ASurfaceControl* ASurfaceControl_create(ASurfaceControl* parent, const char* deb
__INTRODUCED_IN(29);
/**
- * Releases the \a surface_control object. After releasing the ASurfaceControl the caller no longer
- * has ownership of the AsurfaceControl. The surface and it's children may remain on display as long
- * as their parent remains on display.
+ * Acquires a reference on the given ASurfaceControl object. This prevents the object
+ * from being deleted until the reference is removed.
+ *
+ * To release the reference, use the ASurfaceControl_release function.
+ *
+ * Available since API level 31.
+ */
+void ASurfaceControl_acquire(ASurfaceControl* surface_control) __INTRODUCED_IN(31);
+
+/**
+ * Removes a reference that was previously acquired with one of the following functions:
+ * ASurfaceControl_createFromWindow
+ * ASurfaceControl_create
+ * ANativeWindow_acquire
+ * The surface and its children may remain on display as long as their parent remains on display.
*
* Available since API level 29.
*/
diff --git a/include/input/InputDevice.h b/include/input/InputDevice.h
index 2bd7bd2004..2deb99d154 100644
--- a/include/input/InputDevice.h
+++ b/include/input/InputDevice.h
@@ -100,6 +100,13 @@ enum class InputDeviceSensorReportingMode : int32_t {
SPECIAL_TRIGGER = 3,
};
+enum class InputDeviceLightType : int32_t {
+ SINGLE = 0,
+ PLAYER_ID = 1,
+ RGB = 2,
+ MULTI_COLOR = 3,
+};
+
struct InputDeviceSensorInfo {
explicit InputDeviceSensorInfo(std::string name, std::string vendor, int32_t version,
InputDeviceSensorType type, InputDeviceSensorAccuracy accuracy,
@@ -156,6 +163,20 @@ struct InputDeviceSensorInfo {
int32_t id;
};
+struct InputDeviceLightInfo {
+ explicit InputDeviceLightInfo(std::string name, int32_t id, InputDeviceLightType type,
+ int32_t ordinal)
+ : name(name), id(id), type(type), ordinal(ordinal) {}
+ // Name string of the light.
+ std::string name;
+ // Light id
+ int32_t id;
+ // Type of the light.
+ InputDeviceLightType type;
+ // Ordinal of the light
+ int32_t ordinal;
+};
+
/*
* Describes the characteristics and capabilities of an input device.
*/
@@ -198,6 +219,7 @@ public:
float min, float max, float flat, float fuzz, float resolution);
void addMotionRange(const MotionRange& range);
void addSensorInfo(const InputDeviceSensorInfo& info);
+ void addLightInfo(const InputDeviceLightInfo& info);
inline void setKeyboardType(int32_t keyboardType) { mKeyboardType = keyboardType; }
inline int32_t getKeyboardType() const { return mKeyboardType; }
@@ -230,6 +252,10 @@ public:
const std::vector<InputDeviceSensorType> getSensorTypes();
+ const std::vector<int32_t> getLightIds();
+
+ const InputDeviceLightInfo* getLightInfo(int32_t id);
+
private:
int32_t mId;
int32_t mGeneration;
@@ -248,6 +274,8 @@ private:
std::vector<MotionRange> mMotionRanges;
std::unordered_map<InputDeviceSensorType, InputDeviceSensorInfo> mSensors;
+ /* Map from light ID to light info */
+ std::unordered_map<int32_t, InputDeviceLightInfo> mLights;
};
/* Types of input device configuration files. */
diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h
index 8744ef76c1..11b714fbaf 100644
--- a/include/input/InputTransport.h
+++ b/include/input/InputTransport.h
@@ -30,6 +30,7 @@
*/
#include <string>
+#include <unordered_map>
#include <android-base/chrono_utils.h>
@@ -155,6 +156,7 @@ struct InputMessage {
struct Finished {
uint32_t empty1;
uint32_t handled; // actually a bool, but we must maintain 8-byte alignment
+ nsecs_t consumeTime; // The time when the event was consumed by the receiving end
inline size_t size() const { return sizeof(Finished); }
} finished;
@@ -362,7 +364,8 @@ public:
/* Receives the finished signal from the consumer in reply to the original dispatch signal.
* If a signal was received, returns the message sequence number,
- * and whether the consumer handled the message.
+ * whether the consumer handled the message, and the time the event was first read by the
+ * consumer.
*
* The returned sequence number is never 0 unless the operation failed.
*
@@ -371,7 +374,8 @@ public:
* Returns DEAD_OBJECT if the channel's peer has been closed.
* Other errors probably indicate that the channel is broken.
*/
- status_t receiveFinishedSignal(uint32_t* outSeq, bool* outHandled);
+ status_t receiveFinishedSignal(
+ const std::function<void(uint32_t seq, bool handled, nsecs_t consumeTime)>& callback);
private:
std::shared_ptr<InputChannel> mChannel;
@@ -577,6 +581,13 @@ private:
};
std::vector<SeqChain> mSeqChains;
+ // The time at which each event with the sequence number 'seq' was consumed.
+ // This data is provided in 'finishInputEvent' so that the receiving end can measure the latency
+ // This collection is populated when the event is received, and the entries are erased when the
+ // events are finished. It should not grow infinitely because if an event is not ack'd, ANR
+ // will be raised for that connection, and no further events will be posted to that channel.
+ std::unordered_map<uint32_t /*seq*/, nsecs_t /*consumeTime*/> mConsumeTimes;
+
status_t consumeBatch(InputEventFactoryInterface* factory,
nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent);
status_t consumeSamples(InputEventFactoryInterface* factory,
@@ -589,6 +600,8 @@ private:
ssize_t findBatch(int32_t deviceId, int32_t source) const;
ssize_t findTouchState(int32_t deviceId, int32_t source) const;
+ nsecs_t getConsumeTime(uint32_t seq) const;
+ void popConsumeTime(uint32_t seq);
status_t sendUnchainedFinishedSignal(uint32_t seq, bool handled);
static void rewriteMessage(TouchState& state, InputMessage& msg);
diff --git a/include/input/TouchVideoFrame.h b/include/input/TouchVideoFrame.h
index 4fa2f86dc1..eda628e233 100644
--- a/include/input/TouchVideoFrame.h
+++ b/include/input/TouchVideoFrame.h
@@ -57,7 +57,7 @@ public:
/**
* Rotate the video frame.
- * The rotation value is an enum from ui/DisplayInfo.h
+ * The rotation value is an enum from ui/Rotation.h
*/
void rotate(int32_t orientation);
diff --git a/include/private/surface_control_private.h b/include/private/surface_control_private.h
new file mode 100644
index 0000000000..37a476e679
--- /dev/null
+++ b/include/private/surface_control_private.h
@@ -0,0 +1,71 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_PRIVATE_NATIVE_SURFACE_CONTROL_H
+#define ANDROID_PRIVATE_NATIVE_SURFACE_CONTROL_H
+
+#include <stdint.h>
+
+__BEGIN_DECLS
+
+struct ASurfaceControl;
+struct ASurfaceControlStats;
+
+typedef struct ASurfaceControlStats ASurfaceControlStats;
+
+/**
+ * Callback to be notified when surface stats for a specific surface control are available.
+ */
+typedef void (*ASurfaceControl_SurfaceStatsListener)(void* context,
+ ASurfaceControl* control, ASurfaceControlStats* stats);
+
+/**
+ * Registers a callback to be invoked when surface stats from a specific surface are available.
+ *
+ * \param context Optional context provided by the client that is passed into
+ * the callback.
+ *
+ * \param control The surface to retrieve callbacks for.
+ *
+ * \param func The callback to be invoked when surface stats are available.
+ */
+void ASurfaceControl_registerSurfaceStatsListener(ASurfaceControl* control, void* context,
+ ASurfaceControl_SurfaceStatsListener func);
+
+/**
+ * Unregisters a callback to be invoked when surface stats from a specific surface are available.
+ *
+ * \param context The context passed into ASurfaceControl_registerSurfaceStatsListener
+ *
+ * \param func The callback passed into ASurfaceControl_registerSurfaceStatsListener
+ */
+void ASurfaceControl_unregisterSurfaceStatsListener(void* context,
+ ASurfaceControl_SurfaceStatsListener func);
+
+/**
+ * Returns the timestamp of when the buffer was acquired for a specific frame with frame number
+ * obtained from ASurfaceControlStats_getFrameNumber.
+ */
+int64_t ASurfaceControlStats_getAcquireTime(ASurfaceControlStats* stats);
+
+/**
+ * Returns the frame number of the surface stats object passed into the callback.
+ */
+uint64_t ASurfaceControlStats_getFrameNumber(ASurfaceControlStats* stats);
+
+__END_DECLS
+
+#endif //ANDROID_PRIVATE_NATIVE_SURFACE_CONTROL_H
diff --git a/include/ui/DisplayInfo.h b/include/ui/DisplayInfo.h
deleted file mode 120000
index 9a195eaed4..0000000000
--- a/include/ui/DisplayInfo.h
+++ /dev/null
@@ -1 +0,0 @@
-../../libs/ui/include/ui/DisplayInfo.h \ No newline at end of file
diff --git a/include/ui/StaticDisplayInfo.h b/include/ui/StaticDisplayInfo.h
new file mode 120000
index 0000000000..c58aae3020
--- /dev/null
+++ b/include/ui/StaticDisplayInfo.h
@@ -0,0 +1 @@
+../../libs/ui/include/ui/StaticDisplayInfo.h \ No newline at end of file
diff --git a/libs/adbd_auth/Android.bp b/libs/adbd_auth/Android.bp
index 8883c0478a..16cded8141 100644
--- a/libs/adbd_auth/Android.bp
+++ b/libs/adbd_auth/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library {
name: "libadbd_auth",
cflags: [
diff --git a/libs/android_runtime_lazy/Android.bp b/libs/android_runtime_lazy/Android.bp
index cdd776480c..b74923cbfc 100644
--- a/libs/android_runtime_lazy/Android.bp
+++ b/libs/android_runtime_lazy/Android.bp
@@ -30,6 +30,15 @@
// instead of libandroid_runtime. When they are used by a vendor process,
// depending on libandroid_runtime is meaningless. In this case,
// they can depend on libandroid_runtime_lazy.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library {
name: "libandroid_runtime_lazy",
vendor_available: true,
diff --git a/libs/arect/Android.bp b/libs/arect/Android.bp
index 80aa8916da..bb40f5146e 100644
--- a/libs/arect/Android.bp
+++ b/libs/arect/Android.bp
@@ -12,6 +12,23 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ default_applicable_licenses: ["frameworks_native_libs_arect_license"],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+ name: "frameworks_native_libs_arect_license",
+ visibility: [":__subpackages__"],
+ license_kinds: [
+ "SPDX-license-identifier-Apache-2.0",
+ ],
+ license_text: [
+ "NOTICE",
+ ],
+}
+
ndk_headers {
name: "libarect_headers_for_ndk",
from: "include/android",
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index b585ad2c7b..e9d866b448 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library_headers {
name: "libbinder_headers",
export_include_dirs: ["include"],
diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp
index bf4387a0a1..ddda024a40 100644
--- a/libs/binder/BpBinder.cpp
+++ b/libs/binder/BpBinder.cpp
@@ -228,8 +228,9 @@ status_t BpBinder::transact(
: Stability::getLocalLevel();
if (CC_UNLIKELY(!Stability::check(category, required))) {
- ALOGE("Cannot do a user transaction on a %s binder in a %s context.",
+ ALOGE("Cannot do a user transaction on a %s binder (%s) in a %s context.",
category.debugString().c_str(),
+ String8(getInterfaceDescriptor()).c_str(),
Stability::levelString(required).c_str());
return BAD_TYPE;
}
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index b9d00fe7ea..3773760f38 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -520,7 +520,7 @@ void Parcel::updateWorkSourceRequestHeaderPosition() const {
}
}
-#if defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__)
+#if defined(__ANDROID_VNDK__)
constexpr int32_t kHeader = B_PACK_CHARS('V', 'N', 'D', 'R');
#else
constexpr int32_t kHeader = B_PACK_CHARS('S', 'Y', 'S', 'T');
@@ -769,200 +769,116 @@ status_t Parcel::writeUtf8AsUtf16(const std::string& str) {
return NO_ERROR;
}
-status_t Parcel::writeUtf8AsUtf16(const std::optional<std::string>& str) {
- if (!str) {
- return writeInt32(-1);
- }
- return writeUtf8AsUtf16(*str);
-}
-
-status_t Parcel::writeUtf8AsUtf16(const std::unique_ptr<std::string>& str) {
- if (!str) {
- return writeInt32(-1);
- }
- return writeUtf8AsUtf16(*str);
-}
-
-status_t Parcel::writeByteVectorInternal(const int8_t* data, size_t size) {
- if (size > std::numeric_limits<int32_t>::max()) {
- return BAD_VALUE;
- }
-
- status_t status = writeInt32(size);
- if (status != OK) {
- return status;
- }
-
- return write(data, size);
-}
-
-status_t Parcel::writeByteVector(const std::vector<int8_t>& val) {
- return writeByteVectorInternal(val.data(), val.size());
-}
-
-status_t Parcel::writeByteVector(const std::optional<std::vector<int8_t>>& val)
-{
- if (!val) return writeInt32(-1);
- return writeByteVectorInternal(val->data(), val->size());
-}
-
-status_t Parcel::writeByteVector(const std::unique_ptr<std::vector<int8_t>>& val)
-{
- if (!val) return writeInt32(-1);
- return writeByteVectorInternal(val->data(), val->size());
-}
-
-status_t Parcel::writeByteVector(const std::vector<uint8_t>& val) {
- return writeByteVectorInternal(reinterpret_cast<const int8_t*>(val.data()), val.size());
-}
-
-status_t Parcel::writeByteVector(const std::optional<std::vector<uint8_t>>& val)
-{
- if (!val) return writeInt32(-1);
- return writeByteVectorInternal(reinterpret_cast<const int8_t*>(val->data()), val->size());
-}
-
-status_t Parcel::writeByteVector(const std::unique_ptr<std::vector<uint8_t>>& val)
-{
- if (!val) return writeInt32(-1);
- return writeByteVectorInternal(reinterpret_cast<const int8_t*>(val->data()), val->size());
-}
-
-status_t Parcel::writeInt32Vector(const std::vector<int32_t>& val)
-{
- return writeTypedVector(val, &Parcel::writeInt32);
-}
-
-status_t Parcel::writeInt32Vector(const std::optional<std::vector<int32_t>>& val)
-{
- return writeNullableTypedVector(val, &Parcel::writeInt32);
-}
-
-status_t Parcel::writeInt32Vector(const std::unique_ptr<std::vector<int32_t>>& val)
-{
- return writeNullableTypedVector(val, &Parcel::writeInt32);
-}
-
-status_t Parcel::writeInt64Vector(const std::vector<int64_t>& val)
-{
- return writeTypedVector(val, &Parcel::writeInt64);
-}
-
-status_t Parcel::writeInt64Vector(const std::optional<std::vector<int64_t>>& val)
-{
- return writeNullableTypedVector(val, &Parcel::writeInt64);
-}
-
-status_t Parcel::writeInt64Vector(const std::unique_ptr<std::vector<int64_t>>& val)
-{
- return writeNullableTypedVector(val, &Parcel::writeInt64);
-}
-
-status_t Parcel::writeUint64Vector(const std::vector<uint64_t>& val)
-{
- return writeTypedVector(val, &Parcel::writeUint64);
-}
-
-status_t Parcel::writeUint64Vector(const std::optional<std::vector<uint64_t>>& val)
-{
- return writeNullableTypedVector(val, &Parcel::writeUint64);
-}
-
-status_t Parcel::writeUint64Vector(const std::unique_ptr<std::vector<uint64_t>>& val)
-{
- return writeNullableTypedVector(val, &Parcel::writeUint64);
-}
-
-status_t Parcel::writeFloatVector(const std::vector<float>& val)
-{
- return writeTypedVector(val, &Parcel::writeFloat);
-}
-
-status_t Parcel::writeFloatVector(const std::optional<std::vector<float>>& val)
-{
- return writeNullableTypedVector(val, &Parcel::writeFloat);
-}
-
-status_t Parcel::writeFloatVector(const std::unique_ptr<std::vector<float>>& val)
-{
- return writeNullableTypedVector(val, &Parcel::writeFloat);
-}
-
-status_t Parcel::writeDoubleVector(const std::vector<double>& val)
-{
- return writeTypedVector(val, &Parcel::writeDouble);
-}
-
-status_t Parcel::writeDoubleVector(const std::optional<std::vector<double>>& val)
-{
- return writeNullableTypedVector(val, &Parcel::writeDouble);
-}
-
-status_t Parcel::writeDoubleVector(const std::unique_ptr<std::vector<double>>& val)
-{
- return writeNullableTypedVector(val, &Parcel::writeDouble);
-}
-
-status_t Parcel::writeBoolVector(const std::vector<bool>& val)
-{
- return writeTypedVector(val, &Parcel::writeBool);
-}
-
-status_t Parcel::writeBoolVector(const std::optional<std::vector<bool>>& val)
-{
- return writeNullableTypedVector(val, &Parcel::writeBool);
-}
-
-status_t Parcel::writeBoolVector(const std::unique_ptr<std::vector<bool>>& val)
-{
- return writeNullableTypedVector(val, &Parcel::writeBool);
-}
-
-status_t Parcel::writeCharVector(const std::vector<char16_t>& val)
-{
- return writeTypedVector(val, &Parcel::writeChar);
-}
-
-status_t Parcel::writeCharVector(const std::optional<std::vector<char16_t>>& val)
-{
- return writeNullableTypedVector(val, &Parcel::writeChar);
-}
-
-status_t Parcel::writeCharVector(const std::unique_ptr<std::vector<char16_t>>& val)
-{
- return writeNullableTypedVector(val, &Parcel::writeChar);
-}
-
-status_t Parcel::writeString16Vector(const std::vector<String16>& val)
-{
- return writeTypedVector(val, &Parcel::writeString16);
-}
+status_t Parcel::writeUtf8AsUtf16(const std::optional<std::string>& str) { return writeData(str); }
+status_t Parcel::writeUtf8AsUtf16(const std::unique_ptr<std::string>& str) { return writeData(str); }
+
+status_t Parcel::writeString16(const std::optional<String16>& str) { return writeData(str); }
+status_t Parcel::writeString16(const std::unique_ptr<String16>& str) { return writeData(str); }
+
+status_t Parcel::writeByteVector(const std::vector<int8_t>& val) { return writeData(val); }
+status_t Parcel::writeByteVector(const std::optional<std::vector<int8_t>>& val) { return writeData(val); }
+status_t Parcel::writeByteVector(const std::unique_ptr<std::vector<int8_t>>& val) { return writeData(val); }
+status_t Parcel::writeByteVector(const std::vector<uint8_t>& val) { return writeData(val); }
+status_t Parcel::writeByteVector(const std::optional<std::vector<uint8_t>>& val) { return writeData(val); }
+status_t Parcel::writeByteVector(const std::unique_ptr<std::vector<uint8_t>>& val){ return writeData(val); }
+status_t Parcel::writeInt32Vector(const std::vector<int32_t>& val) { return writeData(val); }
+status_t Parcel::writeInt32Vector(const std::optional<std::vector<int32_t>>& val) { return writeData(val); }
+status_t Parcel::writeInt32Vector(const std::unique_ptr<std::vector<int32_t>>& val) { return writeData(val); }
+status_t Parcel::writeInt64Vector(const std::vector<int64_t>& val) { return writeData(val); }
+status_t Parcel::writeInt64Vector(const std::optional<std::vector<int64_t>>& val) { return writeData(val); }
+status_t Parcel::writeInt64Vector(const std::unique_ptr<std::vector<int64_t>>& val) { return writeData(val); }
+status_t Parcel::writeUint64Vector(const std::vector<uint64_t>& val) { return writeData(val); }
+status_t Parcel::writeUint64Vector(const std::optional<std::vector<uint64_t>>& val) { return writeData(val); }
+status_t Parcel::writeUint64Vector(const std::unique_ptr<std::vector<uint64_t>>& val) { return writeData(val); }
+status_t Parcel::writeFloatVector(const std::vector<float>& val) { return writeData(val); }
+status_t Parcel::writeFloatVector(const std::optional<std::vector<float>>& val) { return writeData(val); }
+status_t Parcel::writeFloatVector(const std::unique_ptr<std::vector<float>>& val) { return writeData(val); }
+status_t Parcel::writeDoubleVector(const std::vector<double>& val) { return writeData(val); }
+status_t Parcel::writeDoubleVector(const std::optional<std::vector<double>>& val) { return writeData(val); }
+status_t Parcel::writeDoubleVector(const std::unique_ptr<std::vector<double>>& val) { return writeData(val); }
+status_t Parcel::writeBoolVector(const std::vector<bool>& val) { return writeData(val); }
+status_t Parcel::writeBoolVector(const std::optional<std::vector<bool>>& val) { return writeData(val); }
+status_t Parcel::writeBoolVector(const std::unique_ptr<std::vector<bool>>& val) { return writeData(val); }
+status_t Parcel::writeCharVector(const std::vector<char16_t>& val) { return writeData(val); }
+status_t Parcel::writeCharVector(const std::optional<std::vector<char16_t>>& val) { return writeData(val); }
+status_t Parcel::writeCharVector(const std::unique_ptr<std::vector<char16_t>>& val) { return writeData(val); }
+
+status_t Parcel::writeString16Vector(const std::vector<String16>& val) { return writeData(val); }
status_t Parcel::writeString16Vector(
- const std::optional<std::vector<std::optional<String16>>>& val)
-{
- return writeNullableTypedVector(val, &Parcel::writeString16);
-}
-
+ const std::optional<std::vector<std::optional<String16>>>& val) { return writeData(val); }
status_t Parcel::writeString16Vector(
- const std::unique_ptr<std::vector<std::unique_ptr<String16>>>& val)
-{
- return writeNullableTypedVector(val, &Parcel::writeString16);
-}
-
+ const std::unique_ptr<std::vector<std::unique_ptr<String16>>>& val) { return writeData(val); }
status_t Parcel::writeUtf8VectorAsUtf16Vector(
- const std::optional<std::vector<std::optional<std::string>>>& val) {
- return writeNullableTypedVector(val, &Parcel::writeUtf8AsUtf16);
-}
-
+ const std::optional<std::vector<std::optional<std::string>>>& val) { return writeData(val); }
status_t Parcel::writeUtf8VectorAsUtf16Vector(
- const std::unique_ptr<std::vector<std::unique_ptr<std::string>>>& val) {
- return writeNullableTypedVector(val, &Parcel::writeUtf8AsUtf16);
-}
+ const std::unique_ptr<std::vector<std::unique_ptr<std::string>>>& val) { return writeData(val); }
+status_t Parcel::writeUtf8VectorAsUtf16Vector(const std::vector<std::string>& val) { return writeData(val); }
+
+status_t Parcel::writeUniqueFileDescriptorVector(const std::vector<base::unique_fd>& val) { return writeData(val); }
+status_t Parcel::writeUniqueFileDescriptorVector(const std::optional<std::vector<base::unique_fd>>& val) { return writeData(val); }
+status_t Parcel::writeUniqueFileDescriptorVector(const std::unique_ptr<std::vector<base::unique_fd>>& val) { return writeData(val); }
+
+status_t Parcel::writeStrongBinderVector(const std::vector<sp<IBinder>>& val) { return writeData(val); }
+status_t Parcel::writeStrongBinderVector(const std::optional<std::vector<sp<IBinder>>>& val) { return writeData(val); }
+status_t Parcel::writeStrongBinderVector(const std::unique_ptr<std::vector<sp<IBinder>>>& val) { return writeData(val); }
+
+status_t Parcel::writeParcelable(const Parcelable& parcelable) { return writeData(parcelable); }
+
+status_t Parcel::readUtf8FromUtf16(std::optional<std::string>* str) const { return readData(str); }
+status_t Parcel::readUtf8FromUtf16(std::unique_ptr<std::string>* str) const { return readData(str); }
+
+status_t Parcel::readString16(std::optional<String16>* pArg) const { return readData(pArg); }
+status_t Parcel::readString16(std::unique_ptr<String16>* pArg) const { return readData(pArg); }
+
+status_t Parcel::readByteVector(std::vector<int8_t>* val) const { return readData(val); }
+status_t Parcel::readByteVector(std::vector<uint8_t>* val) const { return readData(val); }
+status_t Parcel::readByteVector(std::optional<std::vector<int8_t>>* val) const { return readData(val); }
+status_t Parcel::readByteVector(std::unique_ptr<std::vector<int8_t>>* val) const { return readData(val); }
+status_t Parcel::readByteVector(std::optional<std::vector<uint8_t>>* val) const { return readData(val); }
+status_t Parcel::readByteVector(std::unique_ptr<std::vector<uint8_t>>* val) const { return readData(val); }
+status_t Parcel::readInt32Vector(std::optional<std::vector<int32_t>>* val) const { return readData(val); }
+status_t Parcel::readInt32Vector(std::unique_ptr<std::vector<int32_t>>* val) const { return readData(val); }
+status_t Parcel::readInt32Vector(std::vector<int32_t>* val) const { return readData(val); }
+status_t Parcel::readInt64Vector(std::optional<std::vector<int64_t>>* val) const { return readData(val); }
+status_t Parcel::readInt64Vector(std::unique_ptr<std::vector<int64_t>>* val) const { return readData(val); }
+status_t Parcel::readInt64Vector(std::vector<int64_t>* val) const { return readData(val); }
+status_t Parcel::readUint64Vector(std::optional<std::vector<uint64_t>>* val) const { return readData(val); }
+status_t Parcel::readUint64Vector(std::unique_ptr<std::vector<uint64_t>>* val) const { return readData(val); }
+status_t Parcel::readUint64Vector(std::vector<uint64_t>* val) const { return readData(val); }
+status_t Parcel::readFloatVector(std::optional<std::vector<float>>* val) const { return readData(val); }
+status_t Parcel::readFloatVector(std::unique_ptr<std::vector<float>>* val) const { return readData(val); }
+status_t Parcel::readFloatVector(std::vector<float>* val) const { return readData(val); }
+status_t Parcel::readDoubleVector(std::optional<std::vector<double>>* val) const { return readData(val); }
+status_t Parcel::readDoubleVector(std::unique_ptr<std::vector<double>>* val) const { return readData(val); }
+status_t Parcel::readDoubleVector(std::vector<double>* val) const { return readData(val); }
+status_t Parcel::readBoolVector(std::optional<std::vector<bool>>* val) const { return readData(val); }
+status_t Parcel::readBoolVector(std::unique_ptr<std::vector<bool>>* val) const { return readData(val); }
+status_t Parcel::readBoolVector(std::vector<bool>* val) const { return readData(val); }
+status_t Parcel::readCharVector(std::optional<std::vector<char16_t>>* val) const { return readData(val); }
+status_t Parcel::readCharVector(std::unique_ptr<std::vector<char16_t>>* val) const { return readData(val); }
+status_t Parcel::readCharVector(std::vector<char16_t>* val) const { return readData(val); }
-status_t Parcel::writeUtf8VectorAsUtf16Vector(const std::vector<std::string>& val) {
- return writeTypedVector(val, &Parcel::writeUtf8AsUtf16);
-}
+status_t Parcel::readString16Vector(
+ std::optional<std::vector<std::optional<String16>>>* val) const { return readData(val); }
+status_t Parcel::readString16Vector(
+ std::unique_ptr<std::vector<std::unique_ptr<String16>>>* val) const { return readData(val); }
+status_t Parcel::readString16Vector(std::vector<String16>* val) const { return readData(val); }
+status_t Parcel::readUtf8VectorFromUtf16Vector(
+ std::optional<std::vector<std::optional<std::string>>>* val) const { return readData(val); }
+status_t Parcel::readUtf8VectorFromUtf16Vector(
+ std::unique_ptr<std::vector<std::unique_ptr<std::string>>>* val) const { return readData(val); }
+status_t Parcel::readUtf8VectorFromUtf16Vector(std::vector<std::string>* val) const { return readData(val); }
+
+status_t Parcel::readUniqueFileDescriptorVector(std::optional<std::vector<base::unique_fd>>* val) const { return readData(val); }
+status_t Parcel::readUniqueFileDescriptorVector(std::unique_ptr<std::vector<base::unique_fd>>* val) const { return readData(val); }
+status_t Parcel::readUniqueFileDescriptorVector(std::vector<base::unique_fd>* val) const { return readData(val); }
+
+status_t Parcel::readStrongBinderVector(std::optional<std::vector<sp<IBinder>>>* val) const { return readData(val); }
+status_t Parcel::readStrongBinderVector(std::unique_ptr<std::vector<sp<IBinder>>>* val) const { return readData(val); }
+status_t Parcel::readStrongBinderVector(std::vector<sp<IBinder>>* val) const { return readData(val); }
+
+status_t Parcel::readParcelable(Parcelable* parcelable) const { return readData(parcelable); }
status_t Parcel::writeInt32(int32_t val)
{
@@ -1091,24 +1007,6 @@ status_t Parcel::writeString8(const char* str, size_t len)
return err;
}
-status_t Parcel::writeString16(const std::optional<String16>& str)
-{
- if (!str) {
- return writeInt32(-1);
- }
-
- return writeString16(*str);
-}
-
-status_t Parcel::writeString16(const std::unique_ptr<String16>& str)
-{
- if (!str) {
- return writeInt32(-1);
- }
-
- return writeString16(*str);
-}
-
status_t Parcel::writeString16(const String16& str)
{
return writeString16(str.string(), str.size());
@@ -1138,32 +1036,6 @@ status_t Parcel::writeStrongBinder(const sp<IBinder>& val)
return flattenBinder(val);
}
-status_t Parcel::writeStrongBinderVector(const std::vector<sp<IBinder>>& val)
-{
- return writeTypedVector(val, &Parcel::writeStrongBinder);
-}
-
-status_t Parcel::writeStrongBinderVector(const std::optional<std::vector<sp<IBinder>>>& val)
-{
- return writeNullableTypedVector(val, &Parcel::writeStrongBinder);
-}
-
-status_t Parcel::writeStrongBinderVector(const std::unique_ptr<std::vector<sp<IBinder>>>& val)
-{
- return writeNullableTypedVector(val, &Parcel::writeStrongBinder);
-}
-
-status_t Parcel::readStrongBinderVector(std::optional<std::vector<sp<IBinder>>>* val) const {
- return readNullableTypedVector(val, &Parcel::readNullableStrongBinder);
-}
-
-status_t Parcel::readStrongBinderVector(std::unique_ptr<std::vector<sp<IBinder>>>* val) const {
- return readNullableTypedVector(val, &Parcel::readNullableStrongBinder);
-}
-
-status_t Parcel::readStrongBinderVector(std::vector<sp<IBinder>>* val) const {
- return readTypedVector(val, &Parcel::readStrongBinder);
-}
status_t Parcel::writeRawNullableParcelable(const Parcelable* parcelable) {
if (!parcelable) {
@@ -1173,14 +1045,6 @@ status_t Parcel::writeRawNullableParcelable(const Parcelable* parcelable) {
return writeParcelable(*parcelable);
}
-status_t Parcel::writeParcelable(const Parcelable& parcelable) {
- status_t status = writeInt32(1); // parcelable is not null.
- if (status != OK) {
- return status;
- }
- return parcelable.writeToParcel(this);
-}
-
status_t Parcel::writeNativeHandle(const native_handle* handle)
{
if (!handle || handle->version != sizeof(native_handle))
@@ -1251,18 +1115,6 @@ status_t Parcel::writeUniqueFileDescriptor(const base::unique_fd& fd) {
return writeDupFileDescriptor(fd.get());
}
-status_t Parcel::writeUniqueFileDescriptorVector(const std::vector<base::unique_fd>& val) {
- return writeTypedVector(val, &Parcel::writeUniqueFileDescriptor);
-}
-
-status_t Parcel::writeUniqueFileDescriptorVector(const std::optional<std::vector<base::unique_fd>>& val) {
- return writeNullableTypedVector(val, &Parcel::writeUniqueFileDescriptor);
-}
-
-status_t Parcel::writeUniqueFileDescriptorVector(const std::unique_ptr<std::vector<base::unique_fd>>& val) {
- return writeNullableTypedVector(val, &Parcel::writeUniqueFileDescriptor);
-}
-
status_t Parcel::writeBlob(size_t len, bool mutableCopy, WritableBlob* outBlob)
{
if (len > INT32_MAX) {
@@ -1477,31 +1329,6 @@ data_unsorted:
goto data_sorted;
}
-status_t Parcel::readVectorSizeWithCoarseBoundCheck(int32_t *size) const {
- int32_t requestedSize;
- const status_t status = readInt32(&requestedSize);
- if (status != NO_ERROR) return status;
-
- // We permit negative sizes, which indicate presence of a nullable vector,
- // i.e. a vector embedded in std::optional, std::unique_ptr, or std::shared_ptr.
- if (requestedSize > 0) {
- // Check if there are fewer bytes than vector elements.
- // A lower bound is 1 byte per element, satisfied by some enum and int8_t and uint8_t.
- const size_t availableBytes = dataAvail();
- if (static_cast<size_t>(requestedSize) > availableBytes) {
- // We have a size that is greater than the number of bytes available.
- // On bounds failure we do not 'rewind' position by 4 bytes of the size already read.
- ALOGW("%s: rejecting out of bounds vector size (requestedSize):%d "
- "Parcel{dataAvail:%zu mDataSize:%zu mDataPos:%zu mDataCapacity:%zu}",
- __func__, requestedSize, availableBytes, mDataSize, mDataPos, mDataCapacity);
- return BAD_VALUE;
- }
- }
-
- *size = requestedSize;
- return NO_ERROR;
-}
-
status_t Parcel::read(void* outData, size_t len) const
{
if (len > INT32_MAX) {
@@ -1605,236 +1432,6 @@ restart_write:
return err;
}
-status_t Parcel::readByteVector(std::vector<int8_t>* val) const {
- size_t size;
- if (status_t status = reserveOutVector(val, &size); status != OK) return status;
- return readByteVectorInternal(val, size);
-}
-
-status_t Parcel::readByteVector(std::vector<uint8_t>* val) const {
- size_t size;
- if (status_t status = reserveOutVector(val, &size); status != OK) return status;
- return readByteVectorInternal(val, size);
-}
-
-status_t Parcel::readByteVector(std::optional<std::vector<int8_t>>* val) const {
- size_t size;
- if (status_t status = reserveOutVector(val, &size); status != OK) return status;
- if (!*val) {
- // reserveOutVector does not create the out vector if size is < 0.
- // This occurs when writing a null byte vector.
- return OK;
- }
- return readByteVectorInternal(&**val, size);
-}
-
-status_t Parcel::readByteVector(std::unique_ptr<std::vector<int8_t>>* val) const {
- size_t size;
- if (status_t status = reserveOutVector(val, &size); status != OK) return status;
- if (val->get() == nullptr) {
- // reserveOutVector does not create the out vector if size is < 0.
- // This occurs when writing a null byte vector.
- return OK;
- }
- return readByteVectorInternal(val->get(), size);
-}
-
-status_t Parcel::readByteVector(std::optional<std::vector<uint8_t>>* val) const {
- size_t size;
- if (status_t status = reserveOutVector(val, &size); status != OK) return status;
- if (!*val) {
- // reserveOutVector does not create the out vector if size is < 0.
- // This occurs when writing a null byte vector.
- return OK;
- }
- return readByteVectorInternal(&**val, size);
-}
-
-status_t Parcel::readByteVector(std::unique_ptr<std::vector<uint8_t>>* val) const {
- size_t size;
- if (status_t status = reserveOutVector(val, &size); status != OK) return status;
- if (val->get() == nullptr) {
- // reserveOutVector does not create the out vector if size is < 0.
- // This occurs when writing a null byte vector.
- return OK;
- }
- return readByteVectorInternal(val->get(), size);
-}
-
-status_t Parcel::readInt32Vector(std::optional<std::vector<int32_t>>* val) const {
- return readNullableTypedVector(val, &Parcel::readInt32);
-}
-
-status_t Parcel::readInt32Vector(std::unique_ptr<std::vector<int32_t>>* val) const {
- return readNullableTypedVector(val, &Parcel::readInt32);
-}
-
-status_t Parcel::readInt32Vector(std::vector<int32_t>* val) const {
- return readTypedVector(val, &Parcel::readInt32);
-}
-
-status_t Parcel::readInt64Vector(std::optional<std::vector<int64_t>>* val) const {
- return readNullableTypedVector(val, &Parcel::readInt64);
-}
-
-status_t Parcel::readInt64Vector(std::unique_ptr<std::vector<int64_t>>* val) const {
- return readNullableTypedVector(val, &Parcel::readInt64);
-}
-
-status_t Parcel::readInt64Vector(std::vector<int64_t>* val) const {
- return readTypedVector(val, &Parcel::readInt64);
-}
-
-status_t Parcel::readUint64Vector(std::optional<std::vector<uint64_t>>* val) const {
- return readNullableTypedVector(val, &Parcel::readUint64);
-}
-
-status_t Parcel::readUint64Vector(std::unique_ptr<std::vector<uint64_t>>* val) const {
- return readNullableTypedVector(val, &Parcel::readUint64);
-}
-
-status_t Parcel::readUint64Vector(std::vector<uint64_t>* val) const {
- return readTypedVector(val, &Parcel::readUint64);
-}
-
-status_t Parcel::readFloatVector(std::optional<std::vector<float>>* val) const {
- return readNullableTypedVector(val, &Parcel::readFloat);
-}
-
-status_t Parcel::readFloatVector(std::unique_ptr<std::vector<float>>* val) const {
- return readNullableTypedVector(val, &Parcel::readFloat);
-}
-
-status_t Parcel::readFloatVector(std::vector<float>* val) const {
- return readTypedVector(val, &Parcel::readFloat);
-}
-
-status_t Parcel::readDoubleVector(std::optional<std::vector<double>>* val) const {
- return readNullableTypedVector(val, &Parcel::readDouble);
-}
-
-status_t Parcel::readDoubleVector(std::unique_ptr<std::vector<double>>* val) const {
- return readNullableTypedVector(val, &Parcel::readDouble);
-}
-
-status_t Parcel::readDoubleVector(std::vector<double>* val) const {
- return readTypedVector(val, &Parcel::readDouble);
-}
-
-status_t Parcel::readBoolVector(std::optional<std::vector<bool>>* val) const {
- const int32_t start = dataPosition();
- int32_t size;
- status_t status = readVectorSizeWithCoarseBoundCheck(&size);
- val->reset();
-
- if (status != OK || size < 0) {
- return status;
- }
-
- setDataPosition(start);
- val->emplace();
-
- status = readBoolVector(&**val);
-
- if (status != OK) {
- val->reset();
- }
-
- return status;
-}
-
-status_t Parcel::readBoolVector(std::unique_ptr<std::vector<bool>>* val) const {
- const int32_t start = dataPosition();
- int32_t size;
- status_t status = readVectorSizeWithCoarseBoundCheck(&size);
- val->reset();
-
- if (status != OK || size < 0) {
- return status;
- }
-
- setDataPosition(start);
- val->reset(new (std::nothrow) std::vector<bool>());
-
- status = readBoolVector(val->get());
-
- if (status != OK) {
- val->reset();
- }
-
- return status;
-}
-
-status_t Parcel::readBoolVector(std::vector<bool>* val) const {
- int32_t size;
- status_t status = readVectorSizeWithCoarseBoundCheck(&size);
-
- if (status != OK) {
- return status;
- }
-
- if (size < 0) {
- return UNEXPECTED_NULL;
- }
-
- val->resize(size);
-
- /* C++ bool handling means a vector of bools isn't necessarily addressable
- * (we might use individual bits)
- */
- bool data;
- for (int32_t i = 0; i < size; ++i) {
- status = readBool(&data);
- (*val)[i] = data;
-
- if (status != OK) {
- return status;
- }
- }
-
- return OK;
-}
-
-status_t Parcel::readCharVector(std::optional<std::vector<char16_t>>* val) const {
- return readNullableTypedVector(val, &Parcel::readChar);
-}
-
-status_t Parcel::readCharVector(std::unique_ptr<std::vector<char16_t>>* val) const {
- return readNullableTypedVector(val, &Parcel::readChar);
-}
-
-status_t Parcel::readCharVector(std::vector<char16_t>* val) const {
- return readTypedVector(val, &Parcel::readChar);
-}
-
-status_t Parcel::readString16Vector(
- std::optional<std::vector<std::optional<String16>>>* val) const {
- return readNullableTypedVector(val, &Parcel::readString16);
-}
-
-status_t Parcel::readString16Vector(
- std::unique_ptr<std::vector<std::unique_ptr<String16>>>* val) const {
- return readNullableTypedVector(val, &Parcel::readString16);
-}
-
-status_t Parcel::readString16Vector(std::vector<String16>* val) const {
- return readTypedVector(val, &Parcel::readString16);
-}
-
-status_t Parcel::readUtf8VectorFromUtf16Vector(
- std::optional<std::vector<std::optional<std::string>>>* val) const {
- return readNullableTypedVector(val, &Parcel::readUtf8FromUtf16);
-}
-
-status_t Parcel::readUtf8VectorFromUtf16Vector(
- std::unique_ptr<std::vector<std::unique_ptr<std::string>>>* val) const {
- return readNullableTypedVector(val, &Parcel::readUtf8FromUtf16);
-}
-
-status_t Parcel::readUtf8VectorFromUtf16Vector(std::vector<std::string>* val) const {
- return readTypedVector(val, &Parcel::readUtf8FromUtf16);
-}
-
status_t Parcel::readInt32(int32_t *pArg) const
{
return readAligned(pArg);
@@ -2007,36 +1604,6 @@ status_t Parcel::readUtf8FromUtf16(std::string* str) const {
return NO_ERROR;
}
-status_t Parcel::readUtf8FromUtf16(std::optional<std::string>* str) const {
- const int32_t start = dataPosition();
- int32_t size;
- status_t status = readInt32(&size);
- str->reset();
-
- if (status != OK || size < 0) {
- return status;
- }
-
- setDataPosition(start);
- str->emplace();
- return readUtf8FromUtf16(&**str);
-}
-
-status_t Parcel::readUtf8FromUtf16(std::unique_ptr<std::string>* str) const {
- const int32_t start = dataPosition();
- int32_t size;
- status_t status = readInt32(&size);
- str->reset();
-
- if (status != OK || size < 0) {
- return status;
- }
-
- setDataPosition(start);
- str->reset(new (std::nothrow) std::string());
- return readUtf8FromUtf16(str->get());
-}
-
const char* Parcel::readCString() const
{
if (mDataPos < mDataSize) {
@@ -2103,51 +1670,6 @@ String16 Parcel::readString16() const
return String16();
}
-status_t Parcel::readString16(std::optional<String16>* pArg) const
-{
- const int32_t start = dataPosition();
- int32_t size;
- status_t status = readInt32(&size);
- pArg->reset();
-
- if (status != OK || size < 0) {
- return status;
- }
-
- setDataPosition(start);
- pArg->emplace();
-
- status = readString16(&**pArg);
-
- if (status != OK) {
- pArg->reset();
- }
-
- return status;
-}
-
-status_t Parcel::readString16(std::unique_ptr<String16>* pArg) const
-{
- const int32_t start = dataPosition();
- int32_t size;
- status_t status = readInt32(&size);
- pArg->reset();
-
- if (status != OK || size < 0) {
- return status;
- }
-
- setDataPosition(start);
- pArg->reset(new (std::nothrow) String16());
-
- status = readString16(pArg->get());
-
- if (status != OK) {
- pArg->reset();
- }
-
- return status;
-}
status_t Parcel::readString16(String16* pArg) const
{
@@ -2204,18 +1726,6 @@ sp<IBinder> Parcel::readStrongBinder() const
return val;
}
-status_t Parcel::readParcelable(Parcelable* parcelable) const {
- int32_t have_parcelable = 0;
- status_t status = readInt32(&have_parcelable);
- if (status != OK) {
- return status;
- }
- if (!have_parcelable) {
- return UNEXPECTED_NULL;
- }
- return parcelable->readFromParcel(this);
-}
-
int32_t Parcel::readExceptionCode() const
{
binder::Status status;
@@ -2334,18 +1844,6 @@ status_t Parcel::readUniqueParcelFileDescriptor(base::unique_fd* val) const
return OK;
}
-status_t Parcel::readUniqueFileDescriptorVector(std::optional<std::vector<base::unique_fd>>* val) const {
- return readNullableTypedVector(val, &Parcel::readUniqueFileDescriptor);
-}
-
-status_t Parcel::readUniqueFileDescriptorVector(std::unique_ptr<std::vector<base::unique_fd>>* val) const {
- return readNullableTypedVector(val, &Parcel::readUniqueFileDescriptor);
-}
-
-status_t Parcel::readUniqueFileDescriptorVector(std::vector<base::unique_fd>* val) const {
- return readTypedVector(val, &Parcel::readUniqueFileDescriptor);
-}
-
status_t Parcel::readBlob(size_t len, ReadableBlob* outBlob) const
{
int32_t blobType;
diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
index c38249ef7c..edadcd5c58 100644
--- a/libs/binder/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -406,12 +406,6 @@ ProcessState::ProcessState(const char *driver)
, mThreadPoolSeq(1)
, mCallRestriction(CallRestriction::NONE)
{
-
-// TODO(b/166468760): enforce in build system
-#if defined(__ANDROID_APEX__)
- LOG_ALWAYS_FATAL("Cannot use libbinder in APEX (only system.img libbinder) since it is not stable.");
-#endif
-
if (mDriverFD >= 0) {
// mmap the binder, providing a chunk of virtual address space to receive transactions.
mVMStart = mmap(nullptr, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);
diff --git a/libs/binder/Stability.cpp b/libs/binder/Stability.cpp
index 339c53833b..b56e09fa6e 100644
--- a/libs/binder/Stability.cpp
+++ b/libs/binder/Stability.cpp
@@ -76,18 +76,12 @@ void Stability::tryMarkCompilationUnit(IBinder* binder) {
}
Stability::Level Stability::getLocalLevel() {
+#ifdef __ANDROID_APEX__
+#error APEX can't use libbinder (must use libbinder_ndk)
+#endif
+
#ifdef __ANDROID_VNDK__
- #ifdef __ANDROID_APEX__
- // TODO(b/142684679) avoid use_vendor on system APEXes
- #if !defined(__ANDROID_APEX_COM_ANDROID_MEDIA_SWCODEC__) \
- && !defined(__ANDROID_APEX_TEST_COM_ANDROID_MEDIA_SWCODEC__)
- #error VNDK + APEX only defined for com.android.media.swcodec
- #endif
- // TODO(b/142684679) avoid use_vendor on system APEXes
- return Level::SYSTEM;
- #else
- return Level::VENDOR;
- #endif
+ return Level::VENDOR;
#else
// TODO(b/139325195): split up stability levels for system/APEX.
return Level::SYSTEM;
diff --git a/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
index dc8d74c052..a7a6563958 100644
--- a/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
+++ b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
@@ -101,4 +101,17 @@ interface IPackageManagerNative {
* This does nothing if this observer was not already registered.
*/
void unregisterPackageChangeObserver(in IPackageChangeObserver observer);
+
+ /**
+ * Returns true if the package has the SHA 256 version of the signing certificate.
+ * @see PackageManager#hasSigningCertificate(String, byte[], int), where type
+ * has been set to {@link PackageManager#CERT_INPUT_SHA256}.
+ */
+ boolean hasSha256SigningCertificate(in @utf8InCpp String packageName, in byte[] certificate);
+
+ /**
+ * Returns the debug flag for the given package.
+ * Unknown packages will cause the call to fail.
+ */
+ boolean isPackageDebuggable(in String packageName);
}
diff --git a/libs/binder/aidl/android/os/IServiceManager.aidl b/libs/binder/aidl/android/os/IServiceManager.aidl
index ce30050a89..2fabf947cd 100644
--- a/libs/binder/aidl/android/os/IServiceManager.aidl
+++ b/libs/binder/aidl/android/os/IServiceManager.aidl
@@ -43,9 +43,9 @@ interface IServiceManager {
*/
const int DUMP_FLAG_PRIORITY_DEFAULT = 1 << 3;
- const int DUMP_FLAG_PRIORITY_ALL = 15;
- // DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_HIGH
- // | DUMP_FLAG_PRIORITY_NORMAL | DUMP_FLAG_PRIORITY_DEFAULT;
+ const int DUMP_FLAG_PRIORITY_ALL =
+ DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_HIGH
+ | DUMP_FLAG_PRIORITY_NORMAL | DUMP_FLAG_PRIORITY_DEFAULT;
/* Allows services to dump sections in protobuf format. */
const int DUMP_FLAG_PROTO = 1 << 4;
diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h
index 54c49e4c0c..7b298f5b39 100644
--- a/libs/binder/include/binder/Parcel.h
+++ b/libs/binder/include/binder/Parcel.h
@@ -190,34 +190,47 @@ public:
// Write an Enum vector with underlying type int8_t.
// Does not use padding; each byte is contiguous.
template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
- status_t writeEnumVector(const std::vector<T>& val);
+ status_t writeEnumVector(const std::vector<T>& val)
+ { return writeData(val); }
template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
- status_t writeEnumVector(const std::optional<std::vector<T>>& val);
+ status_t writeEnumVector(const std::optional<std::vector<T>>& val)
+ { return writeData(val); }
template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
- status_t writeEnumVector(const std::unique_ptr<std::vector<T>>& val) __attribute__((deprecated("use std::optional version instead")));
+ status_t writeEnumVector(const std::unique_ptr<std::vector<T>>& val) __attribute__((deprecated("use std::optional version instead")))
+ { return writeData(val); }
// Write an Enum vector with underlying type != int8_t.
template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
- status_t writeEnumVector(const std::vector<T>& val);
+ status_t writeEnumVector(const std::vector<T>& val)
+ { return writeData(val); }
template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
- status_t writeEnumVector(const std::optional<std::vector<T>>& val);
+ status_t writeEnumVector(const std::optional<std::vector<T>>& val)
+ { return writeData(val); }
template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
- status_t writeEnumVector(const std::unique_ptr<std::vector<T>>& val) __attribute__((deprecated("use std::optional version instead")));
+ status_t writeEnumVector(const std::unique_ptr<std::vector<T>>& val) __attribute__((deprecated("use std::optional version instead")))
+ { return writeData(val); }
template<typename T>
- status_t writeParcelableVector(const std::optional<std::vector<std::optional<T>>>& val);
+ status_t writeParcelableVector(const std::optional<std::vector<std::optional<T>>>& val)
+ { return writeData(val); }
template<typename T>
- status_t writeParcelableVector(const std::unique_ptr<std::vector<std::unique_ptr<T>>>& val) __attribute__((deprecated("use std::optional version instead")));
+ status_t writeParcelableVector(const std::unique_ptr<std::vector<std::unique_ptr<T>>>& val) __attribute__((deprecated("use std::optional version instead")))
+ { return writeData(val); }
template<typename T>
- status_t writeParcelableVector(const std::shared_ptr<std::vector<std::unique_ptr<T>>>& val) __attribute__((deprecated("use std::optional version instead")));
+ status_t writeParcelableVector(const std::shared_ptr<std::vector<std::unique_ptr<T>>>& val) __attribute__((deprecated("use std::optional version instead")))
+ { return writeData(val); }
template<typename T>
- status_t writeParcelableVector(const std::shared_ptr<std::vector<std::optional<T>>>& val);
+ status_t writeParcelableVector(const std::shared_ptr<std::vector<std::optional<T>>>& val)
+ { return writeData(val); }
template<typename T>
- status_t writeParcelableVector(const std::vector<T>& val);
+ status_t writeParcelableVector(const std::vector<T>& val)
+ { return writeData(val); }
template<typename T>
- status_t writeNullableParcelable(const std::optional<T>& parcelable);
+ status_t writeNullableParcelable(const std::optional<T>& parcelable)
+ { return writeData(parcelable); }
template<typename T>
- status_t writeNullableParcelable(const std::unique_ptr<T>& parcelable) __attribute__((deprecated("use std::optional version instead")));
+ status_t writeNullableParcelable(const std::unique_ptr<T>& parcelable) __attribute__((deprecated("use std::optional version instead")))
+ { return writeData(parcelable); }
status_t writeParcelable(const Parcelable& parcelable);
@@ -335,35 +348,48 @@ public:
// Read an Enum vector with underlying type int8_t.
// Does not use padding; each byte is contiguous.
template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
- status_t readEnumVector(std::vector<T>* val) const;
+ status_t readEnumVector(std::vector<T>* val) const
+ { return readData(val); }
template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
- status_t readEnumVector(std::unique_ptr<std::vector<T>>* val) const __attribute__((deprecated("use std::optional version instead")));
+ status_t readEnumVector(std::unique_ptr<std::vector<T>>* val) const __attribute__((deprecated("use std::optional version instead")))
+ { return readData(val); }
template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
- status_t readEnumVector(std::optional<std::vector<T>>* val) const;
+ status_t readEnumVector(std::optional<std::vector<T>>* val) const
+ { return readData(val); }
// Read an Enum vector with underlying type != int8_t.
template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
- status_t readEnumVector(std::vector<T>* val) const;
+ status_t readEnumVector(std::vector<T>* val) const
+ { return readData(val); }
template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
- status_t readEnumVector(std::unique_ptr<std::vector<T>>* val) const __attribute__((deprecated("use std::optional version instead")));
+ status_t readEnumVector(std::unique_ptr<std::vector<T>>* val) const __attribute__((deprecated("use std::optional version instead")))
+ { return readData(val); }
template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
- status_t readEnumVector(std::optional<std::vector<T>>* val) const;
+ status_t readEnumVector(std::optional<std::vector<T>>* val) const
+ { return readData(val); }
template<typename T>
status_t readParcelableVector(
- std::optional<std::vector<std::optional<T>>>* val) const;
+ std::optional<std::vector<std::optional<T>>>* val) const
+ { return readData(val); }
template<typename T>
status_t readParcelableVector(
- std::unique_ptr<std::vector<std::unique_ptr<T>>>* val) const __attribute__((deprecated("use std::optional version instead")));
+ std::unique_ptr<std::vector<std::unique_ptr<T>>>* val) const __attribute__((deprecated("use std::optional version instead")))
+ { return readData(val); }
template<typename T>
- status_t readParcelableVector(std::vector<T>* val) const;
+ status_t readParcelableVector(std::vector<T>* val) const
+ { return readData(val); }
status_t readParcelable(Parcelable* parcelable) const;
template<typename T>
- status_t readParcelable(std::optional<T>* parcelable) const;
+ status_t readParcelable(std::optional<T>* parcelable) const
+ { return readData(parcelable); }
template<typename T>
- status_t readParcelable(std::unique_ptr<T>* parcelable) const __attribute__((deprecated("use std::optional version instead")));
+ status_t readParcelable(std::unique_ptr<T>* parcelable) const __attribute__((deprecated("use std::optional version instead")))
+ { return readData(parcelable); }
+ // If strong binder would be nullptr, readStrongBinder() returns an error.
+ // TODO: T must be derived from IInterface, fix for clarity.
template<typename T>
status_t readStrongBinder(sp<T>* val) const;
@@ -418,20 +444,13 @@ public:
template<typename T>
status_t read(LightFlattenable<T>& val) const;
+ // resizeOutVector is used to resize AIDL out vector parameters.
template<typename T>
status_t resizeOutVector(std::vector<T>* val) const;
template<typename T>
status_t resizeOutVector(std::optional<std::vector<T>>* val) const;
template<typename T>
status_t resizeOutVector(std::unique_ptr<std::vector<T>>* val) const __attribute__((deprecated("use std::optional version instead")));
- template<typename T>
- status_t reserveOutVector(std::vector<T>* val, size_t* size) const;
- template<typename T>
- status_t reserveOutVector(std::optional<std::vector<T>>* val,
- size_t* size) const;
- template<typename T>
- status_t reserveOutVector(std::unique_ptr<std::vector<T>>* val,
- size_t* size) const __attribute__((deprecated("use std::optional version instead")));
// Like Parcel.java's readExceptionCode(). Reads the first int32
// off of a Parcel's header, returning 0 or the negative error
@@ -518,10 +537,6 @@ private:
void scanForFds() const;
status_t validateReadData(size_t len) const;
- // Reads an int32 size and does a coarse bounds check against the number
- // of available bytes in the Parcel.
- status_t readVectorSizeWithCoarseBoundCheck(int32_t *size) const;
-
void updateWorkSourceRequestHeaderPosition() const;
status_t finishFlattenBinder(const sp<IBinder>& binder);
@@ -540,53 +555,544 @@ private:
status_t writeRawNullableParcelable(const Parcelable*
parcelable);
- template<typename T, std::enable_if_t<std::is_same_v<typename std::underlying_type_t<T>,int32_t>, bool> = 0>
- status_t writeEnum(const T& val);
- template<typename T, std::enable_if_t<std::is_same_v<typename std::underlying_type_t<T>,int64_t>, bool> = 0>
- status_t writeEnum(const T& val);
+ //-----------------------------------------------------------------------------
+ // Generic type read and write methods for Parcel:
+ //
+ // readData(T *value) will read a value from the Parcel.
+ // writeData(const T& value) will write a value to the Parcel.
+ //
+ // Our approach to parceling is based on two overloaded functions
+ // readData() and writeData() that generate parceling code for an
+ // object automatically based on its type. The code from templates are generated at
+ // compile time (if constexpr), and decomposes an object through a call graph matching
+ // recursive descent of the template typename.
+ //
+ // This approach unifies handling of complex objects,
+ // resulting in fewer lines of code, greater consistency,
+ // extensibility to nested types, efficiency (decisions made at compile time),
+ // and better code maintainability and optimization.
+ //
+ // Design decision: Incorporate the read and write code into Parcel rather than
+ // as a non-intrusive serializer that emits a byte stream, as we have
+ // active objects, alignment, legacy code, and historical idiosyncrasies.
+ //
+ // --- Overview
+ //
+ // Parceling is a way of serializing objects into a sequence of bytes for communication
+ // between processes, as part of marshaling data for remote procedure calls.
+ //
+ // The Parcel instance contains objects serialized as bytes, such as the following:
+ //
+ // 1) Ordinary primitive data such as int, float.
+ // 2) Established structured data such as String16, std::string.
+ // 3) Parcelables, which are C++ objects that derive from Parcelable (and thus have a
+ // readFromParcel and writeToParcel method). (Similar for Java)
+ // 4) A std::vector<> of such data.
+ // 5) Nullable objects contained in std::optional, std::unique_ptr, or std::shared_ptr.
+ //
+ // And active objects from the Android ecosystem such as:
+ // 6) File descriptors, base::unique_fd (kernel object handles)
+ // 7) Binder objects, sp<IBinder> (active Android RPC handles)
+ //
+ // Objects from (1) through (5) serialize into the mData buffer.
+ // Active objects (6) and (7) serialize into both mData and mObjects buffers.
+ //
+ // --- Data layout details
+ //
+ // Data is read or written to the parcel by recursively decomposing the type of the parameter
+ // type T through readData() and writeData() methods.
+ //
+ // We focus on writeData() here in our explanation of the data layout.
+ //
+ // 1) Alignment
+ // Implementation detail: Regardless of the parameter type, writeData() calls are designed
+ // to finish at a multiple of 4 bytes, the default alignment of the Parcel.
+ //
+ // Writes of single uint8_t, int8_t, enums based on types of size 1, char16_t, etc
+ // will result in 4 bytes being written. The data is widened to int32 and then written;
+ // hence the position of the nonzero bytes depend on the native endianness of the CPU.
+ //
+ // Writes of primitive values with 8 byte size, double, int64_t, uint64_t,
+ // are stored with 4 byte alignment. The ARM and x86/x64 permit unaligned reads
+ // and writes (albeit with potential latency/throughput penalty) which may or may
+ // not be observable unless the process is IO bound.
+ //
+ // 2) Parcelables
+ // Parcelables are detected by the type's base class, and implemented through calling
+ // into the Parcelable type's readFromParcel() or writeToParcel() methods.
+ // Historically, due to null object detection, a (int32_t) 1 is prepended to the data written.
+ // Parcelables must have a default constructor (i.e. one that takes no arguments).
+ //
+ // 3) Arrays
+ // Arrays of uint8_t and int8_t, and enums based on size 1 are written as
+ // a contiguous packed byte stream. Hidden zero padding is applied at the end of the byte
+ // stream to make a multiple of 4 bytes (and prevent info leakage when writing).
+ //
+ // All other array writes can be conceptually thought of as recursively calling
+ // writeData on the individual elements (though may be implemented differently for speed).
+ // As discussed in (1), alignment rules are therefore applied for each element
+ // write (not as an aggregate whole), so the wire representation of data can be
+ // substantially larger.
+ //
+ // Historical Note:
+ // Because of element-wise alignment, CharVector and BoolVector are expanded
+ // element-wise into integers even though they could have been optimized to be packed
+ // just like uint8_t, int8_t (size 1 data).
+ //
+ // 3.1) Arrays accessed by the std::vector type. This is the default for AIDL.
+ //
+ // 4) Nullables
+ // std::optional, std::unique_ptr, std::shared_ptr are all parceled identically
+ // (i.e. result in identical byte layout).
+ // The target of the std::optional, std::unique_ptr, or std::shared_ptr
+ // can either be a std::vector, String16, std::string, or a Parcelable.
+ //
+ // Detection of null relies on peeking the first int32 data and checking if the
+ // the peeked value is considered invalid for the object:
+ // (-1 for vectors, String16, std::string) (0 for Parcelables). If the peeked value
+ // is invalid, then a null is returned.
+ //
+ // Application Note: When to use each nullable type:
+ //
+ // std::optional: Embeds the object T by value rather than creating a new instance
+ // by managed pointer as std::unique_ptr or std::shared_ptr. This will save a malloc
+ // when creating an optional instance.
+ //
+ // Use of std::optionals by value can result in copies of the underlying value stored in it,
+ // so a std::move may be used to move in and move out (for example) a vector value into
+ // the std::optional or for the std::optional itself.
+ //
+ // std::unique_ptr, std::shared_ptr: These are preferred when the lifetime of the object is
+ // already managed by the application. This reduces unnecessary copying of data
+ // especially when the calls are local in-proc (rather than via binder rpc).
+ //
+ // 5) StrongBinder (sp<IBinder>)
+ // StrongBinder objects are written regardless of null. When read, null StrongBinder values
+ // will be interpreted as UNKNOWN_ERROR if the type is a single argument <sp<T>>
+ // or in a vector argument <std::vector<sp<T>>. However, they will be read without an error
+ // if present in a std::optional, std::unique_ptr, or std::shared_ptr vector, e.g.
+ // <std::optional<std::vector<sp<T>>>.
+ //
+ // See AIDL annotation @Nullable, readStrongBinder(), and readNullableStrongBinder().
+ //
+ // Historical Note: writing a vector of StrongBinder objects <std::vector<sp<T>>
+ // containing a null will not cause an error. However reading such a vector will cause
+ // an error _and_ early termination of the read.
- template<typename T, std::enable_if_t<std::is_same_v<typename std::underlying_type_t<T>,int32_t>, bool> = 0>
- status_t readEnum(T* pArg) const;
- template<typename T, std::enable_if_t<std::is_same_v<typename std::underlying_type_t<T>,int64_t>, bool> = 0>
- status_t readEnum(T* pArg) const;
+ // --- Examples
+ //
+ // Using recursive parceling, we can parcel complex data types so long
+ // as they obey the rules described above.
+ //
+ // Example #1
+ // Parceling of a 3D vector
+ //
+ // std::vector<std::vector<std::vector<int32_t>>> v1 {
+ // { {1}, {2, 3}, {4} },
+ // {},
+ // { {10}, {20}, {30, 40} },
+ // };
+ // Parcel p1;
+ // p1.writeData(v1);
+ // decltype(v1) v2;
+ // p1.setDataPosition(0);
+ // p1.readData(&v2);
+ // ASSERT_EQ(v1, v2);
+ //
+ // Example #2
+ // Parceling of mixed shared pointers
+ //
+ // Parcel p1;
+ // auto sp1 = std::make_shared<std::vector<std::shared_ptr<std::vector<int>>>>(3);
+ // (*sp1)[2] = std::make_shared<std::vector<int>>(3);
+ // (*(*sp1)[2])[2] = 2;
+ // p1.writeData(sp1);
+ // decltype(sp1) sp2;
+ // p1.setDataPosition(0);
+ // p1.readData(&sp2);
+ // ASSERT_EQ((*sp1)[0], (*sp2)[0]); // nullptr
+ // ASSERT_EQ((*sp1)[1], (*sp2)[1]); // nullptr
+ // ASSERT_EQ(*(*sp1)[2], *(*sp2)[2]); // { 0, 0, 2}
+
+ // --- Helper Methods
+ // TODO: move this to a utils header.
+ //
+ // Determine if a type is a specialization of a templated type
+ // Example: is_specialization_v<T, std::vector>
- status_t writeByteVectorInternal(const int8_t* data, size_t size);
- template<typename T>
- status_t readByteVectorInternal(std::vector<T>* val, size_t size) const;
+ template <typename Test, template <typename...> class Ref>
+ struct is_specialization : std::false_type {};
- template<typename T, typename U>
- status_t unsafeReadTypedVector(std::vector<T>* val,
- status_t(Parcel::*read_func)(U*) const) const;
- template<typename T>
- status_t readNullableTypedVector(std::optional<std::vector<T>>* val,
- status_t(Parcel::*read_func)(T*) const) const;
- template<typename T>
- status_t readNullableTypedVector(std::unique_ptr<std::vector<T>>* val,
- status_t(Parcel::*read_func)(T*) const) const __attribute__((deprecated("use std::optional version instead")));
- template<typename T>
- status_t readTypedVector(std::vector<T>* val,
- status_t(Parcel::*read_func)(T*) const) const;
- template<typename T, typename U>
- status_t unsafeWriteTypedVector(const std::vector<T>& val,
- status_t(Parcel::*write_func)(U));
- template<typename T>
- status_t writeNullableTypedVector(const std::optional<std::vector<T>>& val,
- status_t(Parcel::*write_func)(const T&));
- template<typename T>
- status_t writeNullableTypedVector(const std::unique_ptr<std::vector<T>>& val,
- status_t(Parcel::*write_func)(const T&)) __attribute__((deprecated("use std::optional version instead")));
- template<typename T>
- status_t writeNullableTypedVector(const std::optional<std::vector<T>>& val,
- status_t(Parcel::*write_func)(T));
- template<typename T>
- status_t writeNullableTypedVector(const std::unique_ptr<std::vector<T>>& val,
- status_t(Parcel::*write_func)(T)) __attribute__((deprecated("use std::optional version instead")));
- template<typename T>
- status_t writeTypedVector(const std::vector<T>& val,
- status_t(Parcel::*write_func)(const T&));
- template<typename T>
- status_t writeTypedVector(const std::vector<T>& val,
- status_t(Parcel::*write_func)(T));
+ template <template <typename...> class Ref, typename... Args>
+ struct is_specialization<Ref<Args...>, Ref>: std::true_type {};
+
+ template <typename Test, template <typename...> class Ref>
+ static inline constexpr bool is_specialization_v = is_specialization<Test, Ref>::value;
+
+ // Get the first template type from a container, the T from MyClass<T, ...>.
+ template<typename T> struct first_template_type;
+
+ template <template <typename ...> class V, typename T, typename... Args>
+ struct first_template_type<V<T, Args...>> {
+ using type_t = T;
+ };
+
+ template <typename T>
+ using first_template_type_t = typename first_template_type<T>::type_t;
+
+ // For static assert(false) we need a template version to avoid early failure.
+ template <typename T>
+ static inline constexpr bool dependent_false_v = false;
+
+ // primitive types that we consider packed and trivially copyable as an array
+ template <typename T>
+ static inline constexpr bool is_pointer_equivalent_array_v =
+ std::is_same_v<T, int8_t>
+ || std::is_same_v<T, uint8_t>
+ // We could support int16_t and uint16_t, but those aren't currently AIDL types.
+ || std::is_same_v<T, int32_t>
+ || std::is_same_v<T, uint32_t>
+ || std::is_same_v<T, float>
+ // are unaligned reads and write support is assumed.
+ || std::is_same_v<T, uint64_t>
+ || std::is_same_v<T, int64_t>
+ || std::is_same_v<T, double>
+ || (std::is_enum_v<T> && (sizeof(T) == 1 || sizeof(T) == 4)); // size check not type
+
+ // allowed "nullable" types
+ // These are nonintrusive containers std::optional, std::unique_ptr, std::shared_ptr.
+ template <typename T>
+ static inline constexpr bool is_parcel_nullable_type_v =
+ is_specialization_v<T, std::optional>
+ || is_specialization_v<T, std::unique_ptr>
+ || is_specialization_v<T, std::shared_ptr>;
+
+ // special int32 value to indicate NonNull or Null parcelables
+ // This is fixed to be only 0 or 1 by contract, do not change.
+ static constexpr int32_t kNonNullParcelableFlag = 1;
+ static constexpr int32_t kNullParcelableFlag = 0;
+
+ // special int32 size representing a null vector, when applicable in Nullable data.
+ // This fixed as -1 by contract, do not change.
+ static constexpr int32_t kNullVectorSize = -1;
+
+ // --- readData and writeData methods.
+ // We choose a mixture of function and template overloads to improve code readability.
+ // TODO: Consider C++20 concepts when they become available.
+
+ // writeData function overloads.
+ // Implementation detail: Function overloading improves code readability over
+ // template overloading, but prevents writeData<T> from being used for those types.
+
+ status_t writeData(bool t) {
+ return writeBool(t); // this writes as int32_t
+ }
+
+ status_t writeData(int8_t t) {
+ return writeByte(t); // this writes as int32_t
+ }
+
+ status_t writeData(uint8_t t) {
+ return writeByte(static_cast<int8_t>(t)); // this writes as int32_t
+ }
+
+ status_t writeData(char16_t t) {
+ return writeChar(t); // this writes as int32_t
+ }
+
+ status_t writeData(int32_t t) {
+ return writeInt32(t);
+ }
+
+ status_t writeData(uint32_t t) {
+ return writeUint32(t);
+ }
+
+ status_t writeData(int64_t t) {
+ return writeInt64(t);
+ }
+
+ status_t writeData(uint64_t t) {
+ return writeUint64(t);
+ }
+
+ status_t writeData(float t) {
+ return writeFloat(t);
+ }
+
+ status_t writeData(double t) {
+ return writeDouble(t);
+ }
+
+ status_t writeData(const String16& t) {
+ return writeString16(t);
+ }
+
+ status_t writeData(const std::string& t) {
+ return writeUtf8AsUtf16(t);
+ }
+
+ status_t writeData(const base::unique_fd& t) {
+ return writeUniqueFileDescriptor(t);
+ }
+
+ status_t writeData(const Parcelable& t) { // std::is_base_of_v<Parcelable, T>
+ // implemented here. writeParcelable() calls this.
+ status_t status = writeData(static_cast<int32_t>(kNonNullParcelableFlag));
+ if (status != OK) return status;
+ return t.writeToParcel(this);
+ }
+
+ // writeData<T> template overloads.
+ // Written such that the first template type parameter is the complete type
+ // of the first function parameter.
+ template <typename T,
+ typename std::enable_if_t<std::is_enum_v<T>, bool> = true>
+ status_t writeData(const T& t) {
+ // implemented here. writeEnum() calls this.
+ using UT = std::underlying_type_t<T>;
+ return writeData(static_cast<UT>(t)); // recurse
+ }
+
+ template <typename T,
+ typename std::enable_if_t<is_specialization_v<T, sp>, bool> = true>
+ status_t writeData(const T& t) {
+ return writeStrongBinder(t);
+ }
+
+ // std::optional, std::unique_ptr, std::shared_ptr special case.
+ template <typename CT,
+ typename std::enable_if_t<is_parcel_nullable_type_v<CT>, bool> = true>
+ status_t writeData(const CT& c) {
+ using T = first_template_type_t<CT>; // The T in CT == C<T, ...>
+ if constexpr (is_specialization_v<T, std::vector>
+ || std::is_same_v<T, String16>
+ || std::is_same_v<T, std::string>) {
+ if (!c) return writeData(static_cast<int32_t>(kNullVectorSize));
+ } else if constexpr (std::is_base_of_v<Parcelable, T>) {
+ if (!c) return writeData(static_cast<int32_t>(kNullParcelableFlag));
+ } else /* constexpr */ { // could define this, but raise as error.
+ static_assert(dependent_false_v<CT>);
+ }
+ return writeData(*c);
+ }
+
+ template <typename CT,
+ typename std::enable_if_t<is_specialization_v<CT, std::vector>, bool> = true>
+ status_t writeData(const CT& c) {
+ using T = first_template_type_t<CT>; // The T in CT == C<T, ...>
+ if (c.size() > std::numeric_limits<int32_t>::max()) return BAD_VALUE;
+ const auto size = static_cast<int32_t>(c.size());
+ writeData(size);
+ if constexpr (is_pointer_equivalent_array_v<T>) {
+ constexpr size_t limit = std::numeric_limits<size_t>::max() / sizeof(T);
+ if (c.size() > limit) return BAD_VALUE;
+ // is_pointer_equivalent types do not have gaps which could leak info,
+ // which is only a concern when writing through binder.
+
+ // TODO: Padding of the write is suboptimal when the length of the
+ // data is not a multiple of 4. Consider improving the write() method.
+ return write(c.data(), c.size() * sizeof(T));
+ } else if constexpr (std::is_same_v<T, bool>
+ || std::is_same_v<T, char16_t>) {
+ // reserve data space to write to
+ auto data = reinterpret_cast<int32_t*>(writeInplace(c.size() * sizeof(int32_t)));
+ if (data == nullptr) return BAD_VALUE;
+ for (const auto t: c) {
+ *data++ = static_cast<int32_t>(t);
+ }
+ } else /* constexpr */ {
+ for (const auto &t : c) {
+ const status_t status = writeData(t);
+ if (status != OK) return status;
+ }
+ }
+ return OK;
+ }
+
+ // readData function overloads.
+ // Implementation detail: Function overloading improves code readability over
+ // template overloading, but prevents readData<T> from being used for those types.
+
+ status_t readData(bool* t) const {
+ return readBool(t); // this reads as int32_t
+ }
+
+ status_t readData(int8_t* t) const {
+ return readByte(t); // this reads as int32_t
+ }
+
+ status_t readData(uint8_t* t) const {
+ return readByte(reinterpret_cast<int8_t*>(t)); // NOTE: this reads as int32_t
+ }
+
+ status_t readData(char16_t* t) const {
+ return readChar(t); // this reads as int32_t
+ }
+
+ status_t readData(int32_t* t) const {
+ return readInt32(t);
+ }
+
+ status_t readData(uint32_t* t) const {
+ return readUint32(t);
+ }
+
+ status_t readData(int64_t* t) const {
+ return readInt64(t);
+ }
+
+ status_t readData(uint64_t* t) const {
+ return readUint64(t);
+ }
+
+ status_t readData(float* t) const {
+ return readFloat(t);
+ }
+
+ status_t readData(double* t) const {
+ return readDouble(t);
+ }
+
+ status_t readData(String16* t) const {
+ return readString16(t);
+ }
+
+ status_t readData(std::string* t) const {
+ return readUtf8FromUtf16(t);
+ }
+
+ status_t readData(base::unique_fd* t) const {
+ return readUniqueFileDescriptor(t);
+ }
+
+ status_t readData(Parcelable* t) const { // std::is_base_of_v<Parcelable, T>
+ // implemented here. readParcelable() calls this.
+ int32_t present;
+ status_t status = readData(&present);
+ if (status != OK) return status;
+ if (present != kNonNullParcelableFlag) return UNEXPECTED_NULL;
+ return t->readFromParcel(this);
+ }
+
+ // readData<T> template overloads.
+ // Written such that the first template type parameter is the complete type
+ // of the first function parameter.
+
+ template <typename T,
+ typename std::enable_if_t<std::is_enum_v<T>, bool> = true>
+ status_t readData(T* t) const {
+ // implemented here. readEnum() calls this.
+ using UT = std::underlying_type_t<T>;
+ return readData(reinterpret_cast<UT*>(t));
+ }
+
+ template <typename T,
+ typename std::enable_if_t<is_specialization_v<T, sp>, bool> = true>
+ status_t readData(T* t) const {
+ return readStrongBinder(t); // Note: on null, returns failure
+ }
+
+
+ template <typename CT,
+ typename std::enable_if_t<is_parcel_nullable_type_v<CT>, bool> = true>
+ status_t readData(CT* c) const {
+ using T = first_template_type_t<CT>; // The T in CT == C<T, ...>
+ const size_t startPos = dataPosition();
+ int32_t peek;
+ status_t status = readData(&peek);
+ if (status != OK) return status;
+ if constexpr (is_specialization_v<T, std::vector>
+ || std::is_same_v<T, String16>
+ || std::is_same_v<T, std::string>) {
+ if (peek == kNullVectorSize) {
+ c->reset();
+ return OK;
+ }
+ } else if constexpr (std::is_base_of_v<Parcelable, T>) {
+ if (peek == kNullParcelableFlag) {
+ c->reset();
+ return OK;
+ }
+ } else /* constexpr */ { // could define this, but raise as error.
+ static_assert(dependent_false_v<CT>);
+ }
+ // create a new object.
+ if constexpr (is_specialization_v<CT, std::optional>) {
+ c->emplace();
+ } else /* constexpr */ {
+ T* const t = new (std::nothrow) T; // contents read from Parcel below.
+ if (t == nullptr) return NO_MEMORY;
+ c->reset(t);
+ }
+ // rewind data ptr to reread (this is pretty quick), otherwise we could
+ // pass an optional argument to readData to indicate a peeked value.
+ setDataPosition(startPos);
+ if constexpr (is_specialization_v<T, std::vector>) {
+ return readData(&**c, READ_FLAG_SP_NULLABLE); // nullable sp<> allowed now
+ } else {
+ return readData(&**c);
+ }
+ }
+
+ // std::vector special case, incorporating flags whether the vector
+ // accepts nullable sp<> to be read.
+ enum ReadFlags {
+ READ_FLAG_NONE = 0,
+ READ_FLAG_SP_NULLABLE = 1 << 0,
+ };
+
+ template <typename CT,
+ typename std::enable_if_t<is_specialization_v<CT, std::vector>, bool> = true>
+ status_t readData(CT* c, ReadFlags readFlags = READ_FLAG_NONE) const {
+ using T = first_template_type_t<CT>; // The T in CT == C<T, ...>
+ int32_t size;
+ status_t status = readInt32(&size);
+ if (status != OK) return status;
+ if (size < 0) return UNEXPECTED_NULL;
+ const size_t availableBytes = dataAvail(); // coarse bound on vector size.
+ if (static_cast<size_t>(size) > availableBytes) return BAD_VALUE;
+ c->clear(); // must clear before resizing/reserving otherwise move ctors may be called.
+ if constexpr (is_pointer_equivalent_array_v<T>) {
+ // could consider POD without gaps and alignment of 4.
+ auto data = reinterpret_cast<const T*>(
+ readInplace(static_cast<size_t>(size) * sizeof(T)));
+ if (data == nullptr) return BAD_VALUE;
+ c->insert(c->begin(), data, data + size); // insert should do a reserve().
+ } else if constexpr (std::is_same_v<T, bool>
+ || std::is_same_v<T, char16_t>) {
+ c->reserve(size); // avoids default initialization
+ auto data = reinterpret_cast<const int32_t*>(
+ readInplace(static_cast<size_t>(size) * sizeof(int32_t)));
+ if (data == nullptr) return BAD_VALUE;
+ for (int32_t i = 0; i < size; ++i) {
+ c->emplace_back(static_cast<T>(*data++));
+ }
+ } else if constexpr (is_specialization_v<T, sp>) {
+ c->resize(size); // calls ctor
+ if (readFlags & READ_FLAG_SP_NULLABLE) {
+ for (auto &t : *c) {
+ status = readNullableStrongBinder(&t); // allow nullable
+ if (status != OK) return status;
+ }
+ } else {
+ for (auto &t : *c) {
+ status = readStrongBinder(&t);
+ if (status != OK) return status;
+ }
+ }
+ } else /* constexpr */ {
+ c->resize(size); // calls ctor
+ for (auto &t : *c) {
+ status = readData(&t);
+ if (status != OK) return status;
+ }
+ }
+ return OK;
+ }
+
+ //-----------------------------------------------------------------------------
+ private:
status_t mError;
uint8_t* mData;
@@ -792,7 +1298,6 @@ status_t Parcel::writeVectorSize(const std::unique_ptr<std::vector<T>>& val) {
template<typename T>
status_t Parcel::resizeOutVector(std::vector<T>* val) const {
int32_t size;
- // used for allocating 'out' vector args, do not use readVectorSizeWithCoarseBoundCheck() here
status_t err = readInt32(&size);
if (err != NO_ERROR) {
return err;
@@ -808,7 +1313,6 @@ status_t Parcel::resizeOutVector(std::vector<T>* val) const {
template<typename T>
status_t Parcel::resizeOutVector(std::optional<std::vector<T>>* val) const {
int32_t size;
- // used for allocating 'out' vector args, do not use readVectorSizeWithCoarseBoundCheck() here
status_t err = readInt32(&size);
if (err != NO_ERROR) {
return err;
@@ -825,7 +1329,6 @@ status_t Parcel::resizeOutVector(std::optional<std::vector<T>>* val) const {
template<typename T>
status_t Parcel::resizeOutVector(std::unique_ptr<std::vector<T>>* val) const {
int32_t size;
- // used for allocating 'out' vector args, do not use readVectorSizeWithCoarseBoundCheck() here
status_t err = readInt32(&size);
if (err != NO_ERROR) {
return err;
@@ -840,61 +1343,6 @@ status_t Parcel::resizeOutVector(std::unique_ptr<std::vector<T>>* val) const {
}
template<typename T>
-status_t Parcel::reserveOutVector(std::vector<T>* val, size_t* size) const {
- int32_t read_size;
- status_t err = readVectorSizeWithCoarseBoundCheck(&read_size);
- if (err != NO_ERROR) {
- return err;
- }
-
- if (read_size < 0) {
- return UNEXPECTED_NULL;
- }
- *size = static_cast<size_t>(read_size);
- val->reserve(*size);
- return OK;
-}
-
-template<typename T>
-status_t Parcel::reserveOutVector(std::optional<std::vector<T>>* val, size_t* size) const {
- int32_t read_size;
- status_t err = readVectorSizeWithCoarseBoundCheck(&read_size);
- if (err != NO_ERROR) {
- return err;
- }
-
- if (read_size >= 0) {
- *size = static_cast<size_t>(read_size);
- val->emplace();
- (*val)->reserve(*size);
- } else {
- val->reset();
- }
-
- return OK;
-}
-
-template<typename T>
-status_t Parcel::reserveOutVector(std::unique_ptr<std::vector<T>>* val,
- size_t* size) const {
- int32_t read_size;
- status_t err = readVectorSizeWithCoarseBoundCheck(&read_size);
- if (err != NO_ERROR) {
- return err;
- }
-
- if (read_size >= 0) {
- *size = static_cast<size_t>(read_size);
- val->reset(new std::vector<T>());
- (*val)->reserve(*size);
- } else {
- val->reset();
- }
-
- return OK;
-}
-
-template<typename T>
status_t Parcel::readStrongBinder(sp<T>* val) const {
sp<IBinder> tmp;
status_t ret = readStrongBinder(&tmp);
@@ -926,422 +1374,6 @@ status_t Parcel::readNullableStrongBinder(sp<T>* val) const {
return ret;
}
-template<typename T, typename U>
-status_t Parcel::unsafeReadTypedVector(
- std::vector<T>* val,
- status_t(Parcel::*read_func)(U*) const) const {
- int32_t size;
- status_t status = this->readVectorSizeWithCoarseBoundCheck(&size);
-
- if (status != OK) {
- return status;
- }
-
- if (size < 0) {
- return UNEXPECTED_NULL;
- }
-
- if (val->max_size() < static_cast<size_t>(size)) {
- return NO_MEMORY;
- }
-
- val->resize(static_cast<size_t>(size));
-
- if (val->size() < static_cast<size_t>(size)) {
- return NO_MEMORY;
- }
-
- for (auto& v: *val) {
- status = (this->*read_func)(&v);
-
- if (status != OK) {
- return status;
- }
- }
-
- return OK;
-}
-
-template<typename T>
-status_t Parcel::readTypedVector(std::vector<T>* val,
- status_t(Parcel::*read_func)(T*) const) const {
- return unsafeReadTypedVector(val, read_func);
-}
-
-template<typename T>
-status_t Parcel::readNullableTypedVector(std::optional<std::vector<T>>* val,
- status_t(Parcel::*read_func)(T*) const) const {
- const size_t start = dataPosition();
- int32_t size;
- status_t status = readVectorSizeWithCoarseBoundCheck(&size);
- val->reset();
-
- if (status != OK || size < 0) {
- return status;
- }
-
- setDataPosition(start);
- val->emplace();
-
- status = unsafeReadTypedVector(&**val, read_func);
-
- if (status != OK) {
- val->reset();
- }
-
- return status;
-}
-
-template<typename T>
-status_t Parcel::readNullableTypedVector(std::unique_ptr<std::vector<T>>* val,
- status_t(Parcel::*read_func)(T*) const) const {
- const size_t start = dataPosition();
- int32_t size;
- status_t status = readVectorSizeWithCoarseBoundCheck(&size);
- val->reset();
-
- if (status != OK || size < 0) {
- return status;
- }
-
- setDataPosition(start);
- val->reset(new std::vector<T>());
-
- status = unsafeReadTypedVector(val->get(), read_func);
-
- if (status != OK) {
- val->reset();
- }
-
- return status;
-}
-
-template<typename T, typename U>
-status_t Parcel::unsafeWriteTypedVector(const std::vector<T>& val,
- status_t(Parcel::*write_func)(U)) {
- if (val.size() > std::numeric_limits<int32_t>::max()) {
- return BAD_VALUE;
- }
-
- status_t status = this->writeInt32(static_cast<int32_t>(val.size()));
-
- if (status != OK) {
- return status;
- }
-
- for (const auto& item : val) {
- status = (this->*write_func)(item);
-
- if (status != OK) {
- return status;
- }
- }
-
- return OK;
-}
-
-template<typename T>
-status_t Parcel::writeTypedVector(const std::vector<T>& val,
- status_t(Parcel::*write_func)(const T&)) {
- return unsafeWriteTypedVector(val, write_func);
-}
-
-template<typename T>
-status_t Parcel::writeTypedVector(const std::vector<T>& val,
- status_t(Parcel::*write_func)(T)) {
- return unsafeWriteTypedVector(val, write_func);
-}
-
-template<typename T>
-status_t Parcel::writeNullableTypedVector(const std::optional<std::vector<T>>& val,
- status_t(Parcel::*write_func)(const T&)) {
- if (!val) {
- return this->writeInt32(-1);
- }
-
- return unsafeWriteTypedVector(*val, write_func);
-}
-
-template<typename T>
-status_t Parcel::writeNullableTypedVector(const std::unique_ptr<std::vector<T>>& val,
- status_t(Parcel::*write_func)(const T&)) {
- if (val.get() == nullptr) {
- return this->writeInt32(-1);
- }
-
- return unsafeWriteTypedVector(*val, write_func);
-}
-
-template<typename T>
-status_t Parcel::writeNullableTypedVector(const std::optional<std::vector<T>>& val,
- status_t(Parcel::*write_func)(T)) {
- if (!val) {
- return this->writeInt32(-1);
- }
-
- return unsafeWriteTypedVector(*val, write_func);
-}
-
-template<typename T>
-status_t Parcel::writeNullableTypedVector(const std::unique_ptr<std::vector<T>>& val,
- status_t(Parcel::*write_func)(T)) {
- if (val.get() == nullptr) {
- return this->writeInt32(-1);
- }
-
- return unsafeWriteTypedVector(*val, write_func);
-}
-
-template<typename T>
-status_t Parcel::readParcelableVector(std::vector<T>* val) const {
- return unsafeReadTypedVector<T, Parcelable>(val, &Parcel::readParcelable);
-}
-
-template<typename T>
-status_t Parcel::readParcelableVector(std::optional<std::vector<std::optional<T>>>* val) const {
- const size_t start = dataPosition();
- int32_t size;
- status_t status = readVectorSizeWithCoarseBoundCheck(&size);
- val->reset();
-
- if (status != OK || size < 0) {
- return status;
- }
-
- setDataPosition(start);
- val->emplace();
-
- using NullableT = std::optional<T>;
- status = unsafeReadTypedVector<NullableT, NullableT>(&**val, &Parcel::readParcelable);
-
- if (status != OK) {
- val->reset();
- }
-
- return status;
-}
-
-template<typename T>
-status_t Parcel::readParcelableVector(std::unique_ptr<std::vector<std::unique_ptr<T>>>* val) const {
- const size_t start = dataPosition();
- int32_t size;
- status_t status = readVectorSizeWithCoarseBoundCheck(&size);
- val->reset();
-
- if (status != OK || size < 0) {
- return status;
- }
-
- setDataPosition(start);
- val->reset(new std::vector<std::unique_ptr<T>>());
-
- using NullableT = std::unique_ptr<T>;
- status = unsafeReadTypedVector<NullableT, NullableT>(val->get(), &Parcel::readParcelable);
-
- if (status != OK) {
- val->reset();
- }
-
- return status;
-}
-
-template<typename T>
-status_t Parcel::readParcelable(std::optional<T>* parcelable) const {
- const size_t start = dataPosition();
- int32_t present;
- status_t status = readInt32(&present);
- parcelable->reset();
-
- if (status != OK || !present) {
- return status;
- }
-
- setDataPosition(start);
- parcelable->emplace();
-
- status = readParcelable(&**parcelable);
-
- if (status != OK) {
- parcelable->reset();
- }
-
- return status;
-}
-
-template<typename T>
-status_t Parcel::readParcelable(std::unique_ptr<T>* parcelable) const {
- const size_t start = dataPosition();
- int32_t present;
- status_t status = readInt32(&present);
- parcelable->reset();
-
- if (status != OK || !present) {
- return status;
- }
-
- setDataPosition(start);
- parcelable->reset(new T());
-
- status = readParcelable(parcelable->get());
-
- if (status != OK) {
- parcelable->reset();
- }
-
- return status;
-}
-
-template<typename T>
-status_t Parcel::writeNullableParcelable(const std::optional<T>& parcelable) {
- return writeRawNullableParcelable(parcelable ? &*parcelable : nullptr);
-}
-
-template<typename T>
-status_t Parcel::writeNullableParcelable(const std::unique_ptr<T>& parcelable) {
- return writeRawNullableParcelable(parcelable.get());
-}
-
-template<typename T>
-status_t Parcel::writeParcelableVector(const std::vector<T>& val) {
- return unsafeWriteTypedVector<T,const Parcelable&>(val, &Parcel::writeParcelable);
-}
-
-template<typename T>
-status_t Parcel::writeParcelableVector(const std::optional<std::vector<std::optional<T>>>& val) {
- if (!val) {
- return this->writeInt32(-1);
- }
-
- using NullableT = std::optional<T>;
- return unsafeWriteTypedVector<NullableT, const NullableT&>(*val, &Parcel::writeNullableParcelable);
-}
-
-template<typename T>
-status_t Parcel::writeParcelableVector(const std::unique_ptr<std::vector<std::unique_ptr<T>>>& val) {
- if (val.get() == nullptr) {
- return this->writeInt32(-1);
- }
-
- return unsafeWriteTypedVector(*val, &Parcel::writeNullableParcelable<T>);
-}
-
-template<typename T>
-status_t Parcel::writeParcelableVector(const std::shared_ptr<std::vector<std::unique_ptr<T>>>& val) {
- if (val.get() == nullptr) {
- return this->writeInt32(-1);
- }
-
- using NullableT = std::unique_ptr<T>;
- return unsafeWriteTypedVector<NullableT, const NullableT&>(*val, &Parcel::writeNullableParcelable);
-}
-
-template<typename T>
-status_t Parcel::writeParcelableVector(const std::shared_ptr<std::vector<std::optional<T>>>& val) {
- if (val.get() == nullptr) {
- return this->writeInt32(-1);
- }
-
- using NullableT = std::optional<T>;
- return unsafeWriteTypedVector<NullableT, const NullableT&>(*val, &Parcel::writeNullableParcelable);
-}
-
-template<typename T, std::enable_if_t<std::is_same_v<typename std::underlying_type_t<T>,int32_t>, bool>>
-status_t Parcel::writeEnum(const T& val) {
- return writeInt32(static_cast<int32_t>(val));
-}
-template<typename T, std::enable_if_t<std::is_same_v<typename std::underlying_type_t<T>,int64_t>, bool>>
-status_t Parcel::writeEnum(const T& val) {
- return writeInt64(static_cast<int64_t>(val));
-}
-
-template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool>>
-status_t Parcel::writeEnumVector(const std::vector<T>& val) {
- return writeByteVectorInternal(reinterpret_cast<const int8_t*>(val.data()), val.size());
-}
-template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool>>
-status_t Parcel::writeEnumVector(const std::optional<std::vector<T>>& val) {
- if (!val) return writeInt32(-1);
- return writeByteVectorInternal(reinterpret_cast<const int8_t*>(val->data()), val->size());
-}
-template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool>>
-status_t Parcel::writeEnumVector(const std::unique_ptr<std::vector<T>>& val) {
- if (!val) return writeInt32(-1);
- return writeByteVectorInternal(reinterpret_cast<const int8_t*>(val->data()), val->size());
-}
-template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool>>
-status_t Parcel::writeEnumVector(const std::vector<T>& val) {
- return writeTypedVector(val, &Parcel::writeEnum);
-}
-template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool>>
-status_t Parcel::writeEnumVector(const std::optional<std::vector<T>>& val) {
- return writeNullableTypedVector(val, &Parcel::writeEnum);
-}
-template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool>>
-status_t Parcel::writeEnumVector(const std::unique_ptr<std::vector<T>>& val) {
- return writeNullableTypedVector(val, &Parcel::writeEnum);
-}
-
-template<typename T, std::enable_if_t<std::is_same_v<typename std::underlying_type_t<T>,int32_t>, bool>>
-status_t Parcel::readEnum(T* pArg) const {
- return readInt32(reinterpret_cast<int32_t *>(pArg));
-}
-template<typename T, std::enable_if_t<std::is_same_v<typename std::underlying_type_t<T>,int64_t>, bool>>
-status_t Parcel::readEnum(T* pArg) const {
- return readInt64(reinterpret_cast<int64_t *>(pArg));
-}
-
-template<typename T>
-inline status_t Parcel::readByteVectorInternal(std::vector<T>* val, size_t size) const {
- // readByteVectorInternal expects a vector that has been reserved (but not
- // resized) to have the provided size.
- const T* data = reinterpret_cast<const T*>(readInplace(size));
- if (!data) return BAD_VALUE;
- val->clear();
- val->insert(val->begin(), data, data+size);
- return NO_ERROR;
-}
-
-template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool>>
-status_t Parcel::readEnumVector(std::vector<T>* val) const {
- size_t size;
- if (status_t status = reserveOutVector(val, &size); status != OK) return status;
- return readByteVectorInternal(val, size);
-}
-template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool>>
-status_t Parcel::readEnumVector(std::optional<std::vector<T>>* val) const {
- size_t size;
- if (status_t status = reserveOutVector(val, &size); status != OK) return status;
- if (!*val) {
- // reserveOutVector does not create the out vector if size is < 0.
- // This occurs when writing a null Enum vector.
- return OK;
- }
- return readByteVectorInternal(&**val, size);
-}
-template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool>>
-status_t Parcel::readEnumVector(std::unique_ptr<std::vector<T>>* val) const {
- size_t size;
- if (status_t status = reserveOutVector(val, &size); status != OK) return status;
- if (val->get() == nullptr) {
- // reserveOutVector does not create the out vector if size is < 0.
- // This occurs when writing a null Enum vector.
- return OK;
- }
- return readByteVectorInternal(val->get(), size);
-}
-template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool>>
-status_t Parcel::readEnumVector(std::vector<T>* val) const {
- return readTypedVector(val, &Parcel::readEnum);
-}
-template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool>>
-status_t Parcel::readEnumVector(std::optional<std::vector<T>>* val) const {
- return readNullableTypedVector(val, &Parcel::readEnum);
-}
-template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool>>
-status_t Parcel::readEnumVector(std::unique_ptr<std::vector<T>>* val) const {
- return readNullableTypedVector(val, &Parcel::readEnum);
-}
-
// ---------------------------------------------------------------------------
inline TextOutput& operator<<(TextOutput& to, const Parcel& parcel)
diff --git a/libs/binder/include/private/binder/binder_module.h b/libs/binder/include/private/binder/binder_module.h
index 5a719b8930..157919903f 100644
--- a/libs/binder/include/private/binder/binder_module.h
+++ b/libs/binder/include/private/binder/binder_module.h
@@ -88,10 +88,6 @@ struct binder_frozen_status_info {
};
#endif //BINDER_GET_FROZEN_INFO
-enum transaction_flags_ext {
- TF_CLEAR_BUF = 0x20, /* clear buffer on txn complete */
-};
-
#ifdef __cplusplus
} // namespace android
#endif
diff --git a/libs/binder/ndk/Android.bp b/libs/binder/ndk/Android.bp
index 897c72a406..eb103d3d77 100644
--- a/libs/binder/ndk/Android.bp
+++ b/libs/binder/ndk/Android.bp
@@ -15,6 +15,23 @@
*/
// TODO(b/31559095): bionic on host should define this
+package {
+ default_applicable_licenses: ["frameworks_native_libs_binder_ndk_license"],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+ name: "frameworks_native_libs_binder_ndk_license",
+ visibility: [":__subpackages__"],
+ license_kinds: [
+ "SPDX-license-identifier-Apache-2.0",
+ ],
+ license_text: [
+ "NOTICE",
+ ],
+}
+
cc_defaults {
name: "libbinder_ndk_host_user",
target: {
diff --git a/libs/binder/ndk/include_cpp/android/binder_to_string.h b/libs/binder/ndk/include_cpp/android/binder_to_string.h
index bd51b1167f..584292551b 100644
--- a/libs/binder/ndk/include_cpp/android/binder_to_string.h
+++ b/libs/binder/ndk/include_cpp/android/binder_to_string.h
@@ -28,10 +28,22 @@
#include <codecvt>
#include <locale>
+#include <memory>
+#include <optional>
#include <sstream>
#include <string>
#include <type_traits>
+#if __has_include(<utils/StrongPointer.h>)
+#include <utils/StrongPointer.h>
+#define HAS_STRONG_POINTER
+#endif
+
+#if __has_include(<utils/String16.h>)
+#include <utils/String16.h>
+#define HAS_STRING16
+#endif
+
#if __has_include(<android/binder_ibinder.h>)
#include <android/binder_auto_utils.h>
#include <android/binder_interface_utils.h>
@@ -42,9 +54,6 @@
#include <binder/IInterface.h>
#include <binder/ParcelFileDescriptor.h>
#include <binder/ParcelableHolder.h>
-#include <utils/String16.h>
-#include <utils/StrongPointer.h>
-#define HAS_CPP_INTERFACE
#endif //_has_include
namespace android {
@@ -80,11 +89,28 @@ class HasToStringFunction {
enum { value = decltype(_test<_T>(0))::value };
};
-// Truthy if _T is like a pointer
+template <typename T, template <typename...> typename U>
+struct IsInstantiationOf : std::false_type {};
+
+template <template <typename...> typename U, typename... Args>
+struct IsInstantiationOf<U<Args...>, U> : std::true_type {};
+
+// Truthy if _T is like a pointer: one of sp/optional/shared_ptr
template <typename _T>
class IsPointerLike {
template <typename _U>
- static auto _test(int) -> decltype(!std::declval<_U>(), *std::declval<_U>(), std::true_type());
+ static std::enable_if_t<
+#ifdef HAS_STRONG_POINTER
+ IsInstantiationOf<_U, sp>::value || // for IBinder and interface types in the C++
+ // backend
+#endif
+ IsInstantiationOf<_U, std::optional>::value || // for @nullable types in the
+ // C++/NDK backends
+ IsInstantiationOf<_U, std::shared_ptr>::value, // for interface types in the
+ // NDK backends
+
+ std::true_type>
+ _test(int);
template <typename _U>
static std::false_type _test(...);
@@ -142,12 +168,17 @@ std::string ToString(const _T& t) {
return std::to_string(t);
} else if constexpr (std::is_same_v<std::string, _T>) {
return t;
-#ifdef HAS_CPP_INTERFACE
+#ifdef HAS_STRING16
} else if constexpr (std::is_same_v<String16, _T>) {
std::stringstream out;
out << t;
return out.str();
#endif
+ } else if constexpr (details::IsPointerLike<_T>::value) {
+ if (!t) return "(null)";
+ std::stringstream out;
+ out << ToString(*t);
+ return out.str();
} else if constexpr (details::HasToStringMethod<_T>::value) {
return t.toString();
} else if constexpr (details::HasToStringFunction<_T>::value) {
@@ -168,11 +199,6 @@ std::string ToString(const _T& t) {
}
out << "]";
return out.str();
- } else if constexpr (details::IsPointerLike<_T>::value) {
- if (!t) return "(null)";
- std::stringstream out;
- out << ToString(*t);
- return out.str();
} else {
return "{no toString() implemented}";
}
diff --git a/libs/binder/ndk/include_platform/android/binder_manager.h b/libs/binder/ndk/include_platform/android/binder_manager.h
index 2784aa823d..45807515e4 100644
--- a/libs/binder/ndk/include_platform/android/binder_manager.h
+++ b/libs/binder/ndk/include_platform/android/binder_manager.h
@@ -31,7 +31,8 @@ __BEGIN_DECLS
*
* \return EX_NONE on success.
*/
-binder_exception_t AServiceManager_addService(AIBinder* binder, const char* instance);
+__attribute__((warn_unused_result)) binder_exception_t AServiceManager_addService(
+ AIBinder* binder, const char* instance);
/**
* Gets a binder object with this specific instance name. Will return nullptr immediately if the
@@ -94,4 +95,52 @@ __attribute__((warn_unused_result)) AIBinder* AServiceManager_waitForService(con
*/
bool AServiceManager_isDeclared(const char* instance) __INTRODUCED_IN(31);
+/**
+ * Prevent lazy services without client from shutting down their process
+ *
+ * \param persist 'true' if the process should not exit.
+ */
+void AServiceManager_forceLazyServicesPersist(bool persist) __INTRODUCED_IN(31);
+
+/**
+ * Set a callback that is invoked when the active service count (i.e. services with clients)
+ * registered with this process drops to zero (or becomes nonzero).
+ * The callback takes a boolean argument, which is 'true' if there is
+ * at least one service with clients.
+ *
+ * \param callback function to call when the number of services
+ * with clients changes.
+ * \param context opaque pointer passed back as second parameter to the
+ * callback.
+ *
+ * The callback takes two arguments. The first is a boolean that represents if there are
+ * services with clients (true) or not (false).
+ * The second is the 'context' pointer passed during the registration.
+ *
+ * Callback return value:
+ * - false: Default behavior for lazy services (shut down the process if there
+ * are no clients).
+ * - true: Don't shut down the process even if there are no clients.
+ *
+ * This callback gives a chance to:
+ * 1 - Perform some additional operations before exiting;
+ * 2 - Prevent the process from exiting by returning "true" from the callback.
+ */
+void AServiceManager_setActiveServicesCallback(bool (*callback)(bool, void*), void* context)
+ __INTRODUCED_IN(31);
+
+/**
+ * Try to unregister all services previously registered with 'registerService'.
+ *
+ * \return true on success.
+ */
+bool AServiceManager_tryUnregister() __INTRODUCED_IN(31);
+
+/**
+ * Re-register services that were unregistered by 'tryUnregister'.
+ * This method should be called in the case 'tryUnregister' fails
+ * (and should be called on the same thread).
+ */
+void AServiceManager_reRegister() __INTRODUCED_IN(31);
+
__END_DECLS
diff --git a/libs/binder/ndk/include_platform/android/binder_stability.h b/libs/binder/ndk/include_platform/android/binder_stability.h
index f5e8bf60ef..44ed48f839 100644
--- a/libs/binder/ndk/include_platform/android/binder_stability.h
+++ b/libs/binder/ndk/include_platform/android/binder_stability.h
@@ -30,6 +30,8 @@ enum {
FLAG_PRIVATE_VENDOR = 0x10000000,
};
+// TODO(b/180646847): __ANDROID_APEX__ here is what allows product partition to
+// talk to system.
#if defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__)
enum {
diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt
index 9a93bf3c4b..cef0bf31d2 100644
--- a/libs/binder/ndk/libbinder_ndk.map.txt
+++ b/libs/binder/ndk/libbinder_ndk.map.txt
@@ -120,6 +120,10 @@ LIBBINDER_NDK31 { # introduced=31
AServiceManager_isDeclared; # apex llndk
AServiceManager_registerLazyService; # llndk
AServiceManager_waitForService; # apex llndk
+ AServiceManager_forceLazyServicesPersist; # llndk
+ AServiceManager_setActiveServicesCallback; # llndk
+ AServiceManager_tryUnregister; # llndk
+ AServiceManager_reRegister; # llndk
AIBinder_Class_getDescriptor;
AIBinder_Weak_clone;
diff --git a/libs/binder/ndk/service_manager.cpp b/libs/binder/ndk/service_manager.cpp
index c782d47c1c..cb0987e3e1 100644
--- a/libs/binder/ndk/service_manager.cpp
+++ b/libs/binder/ndk/service_manager.cpp
@@ -92,3 +92,22 @@ bool AServiceManager_isDeclared(const char* instance) {
sp<IServiceManager> sm = defaultServiceManager();
return sm->isDeclared(String16(instance));
}
+void AServiceManager_forceLazyServicesPersist(bool persist) {
+ auto serviceRegistrar = android::binder::LazyServiceRegistrar::getInstance();
+ serviceRegistrar.forcePersist(persist);
+}
+void AServiceManager_setActiveServicesCallback(bool (*callback)(bool, void*), void* context) {
+ auto serviceRegistrar = android::binder::LazyServiceRegistrar::getInstance();
+ std::function<bool(bool)> fn = [=](bool hasClients) -> bool {
+ return callback(hasClients, context);
+ };
+ serviceRegistrar.setActiveServicesCallback(fn);
+}
+bool AServiceManager_tryUnregister() {
+ auto serviceRegistrar = android::binder::LazyServiceRegistrar::getInstance();
+ return serviceRegistrar.tryUnregister();
+}
+void AServiceManager_reRegister() {
+ auto serviceRegistrar = android::binder::LazyServiceRegistrar::getInstance();
+ serviceRegistrar.reRegister();
+} \ No newline at end of file
diff --git a/libs/binder/ndk/tests/Android.bp b/libs/binder/ndk/tests/Android.bp
index 46e6270eb0..bb51bf0b5d 100644
--- a/libs/binder/ndk/tests/Android.bp
+++ b/libs/binder/ndk/tests/Android.bp
@@ -14,6 +14,15 @@
* limitations under the License.
*/
+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_libs_binder_ndk_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_libs_binder_ndk_license"],
+}
+
cc_defaults {
name: "test_libbinder_ndk_defaults",
shared_libs: [
diff --git a/libs/binder/ndk/tests/IBinderNdkUnitTest.aidl b/libs/binder/ndk/tests/IBinderNdkUnitTest.aidl
index dc77467d8c..ecbd6490e9 100644
--- a/libs/binder/ndk/tests/IBinderNdkUnitTest.aidl
+++ b/libs/binder/ndk/tests/IBinderNdkUnitTest.aidl
@@ -28,4 +28,7 @@ interface IBinderNdkUnitTest {
void forceFlushCommands();
boolean getsRequestedSid();
+
+ void forcePersist(boolean persist);
+ void setCustomActiveServicesCallback();
}
diff --git a/libs/binder/ndk/tests/binderVendorDoubleLoadTest.cpp b/libs/binder/ndk/tests/binderVendorDoubleLoadTest.cpp
index ad78e319a2..f3cd21822d 100644
--- a/libs/binder/ndk/tests/binderVendorDoubleLoadTest.cpp
+++ b/libs/binder/ndk/tests/binderVendorDoubleLoadTest.cpp
@@ -163,7 +163,8 @@ int main(int argc, char** argv) {
// LOCAL SERVERS
std::shared_ptr<NdkServer> ndkServer = SharedRefBase::make<NdkServer>();
- AServiceManager_addService(ndkServer->asBinder().get(), kLocalNdkServerName.c_str());
+ CHECK(STATUS_OK ==
+ AServiceManager_addService(ndkServer->asBinder().get(), kLocalNdkServerName.c_str()));
return RUN_ALL_TESTS();
}
diff --git a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
index 0d1989e4d5..de1a48dfd8 100644
--- a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
+++ b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
@@ -46,6 +46,11 @@ using namespace android;
constexpr char kExistingNonNdkService[] = "SurfaceFlinger";
constexpr char kBinderNdkUnitTestService[] = "BinderNdkUnitTest";
constexpr char kLazyBinderNdkUnitTestService[] = "LazyBinderNdkUnitTest";
+constexpr char kForcePersistNdkUnitTestService[] = "ForcePersistNdkUnitTestService";
+constexpr char kActiveServicesNdkUnitTestService[] = "ActiveServicesNdkUnitTestService";
+
+constexpr unsigned int kShutdownWaitTime = 10;
+constexpr uint64_t kContextTestValue = 0xb4e42fb4d9a1d715;
class MyBinderNdkUnitTest : public aidl::BnBinderNdkUnitTest {
ndk::ScopedAStatus repeatInt(int32_t in, int32_t* out) {
@@ -76,6 +81,46 @@ class MyBinderNdkUnitTest : public aidl::BnBinderNdkUnitTest {
fsync(out);
return STATUS_OK;
}
+ ndk::ScopedAStatus forcePersist(bool persist) {
+ AServiceManager_forceLazyServicesPersist(persist);
+ return ndk::ScopedAStatus::ok();
+ }
+ ndk::ScopedAStatus setCustomActiveServicesCallback() {
+ AServiceManager_setActiveServicesCallback(activeServicesCallback, this);
+ return ndk::ScopedAStatus::ok();
+ }
+ static bool activeServicesCallback(bool hasClients, void* context) {
+ if (hasClients) {
+ return false;
+ }
+
+ // Unregister all services
+ if (!AServiceManager_tryUnregister()) {
+ // Prevent shutdown (test will fail)
+ return false;
+ }
+
+ // Re-register all services
+ AServiceManager_reRegister();
+
+ // Unregister again before shutdown
+ if (!AServiceManager_tryUnregister()) {
+ // Prevent shutdown (test will fail)
+ return false;
+ }
+
+ // Check if the context was passed correctly
+ MyBinderNdkUnitTest* service = static_cast<MyBinderNdkUnitTest*>(context);
+ if (service->contextTestValue != kContextTestValue) {
+ // Prevent shutdown (test will fail)
+ return false;
+ }
+
+ exit(EXIT_SUCCESS);
+ // Unreachable
+ }
+
+ uint64_t contextTestValue = kContextTestValue;
};
int generatedService() {
@@ -168,6 +213,16 @@ int lazyService(const char* instance) {
return 1; // should not return
}
+bool isServiceRunning(const char* serviceName) {
+ AIBinder* binder = AServiceManager_checkService(serviceName);
+ if (binder == nullptr) {
+ return false;
+ }
+ AIBinder_decStrong(binder);
+
+ return true;
+}
+
TEST(NdkBinder, GetServiceThatDoesntExist) {
sp<IFoo> foo = IFoo::getService("asdfghkl;");
EXPECT_EQ(nullptr, foo.get());
@@ -238,10 +293,51 @@ TEST(NdkBinder, CheckLazyServiceShutDown) {
service = nullptr;
IPCThreadState::self()->flushCommands();
// Make sure the service is dead after some time of no use
- sleep(10);
+ sleep(kShutdownWaitTime);
ASSERT_EQ(nullptr, AServiceManager_checkService(kLazyBinderNdkUnitTestService));
}
+TEST(NdkBinder, ForcedPersistenceTest) {
+ for (int i = 0; i < 2; i++) {
+ ndk::SpAIBinder binder(AServiceManager_waitForService(kForcePersistNdkUnitTestService));
+ std::shared_ptr<aidl::IBinderNdkUnitTest> service =
+ aidl::IBinderNdkUnitTest::fromBinder(binder);
+ ASSERT_NE(service, nullptr);
+ ASSERT_TRUE(service->forcePersist(i == 0).isOk());
+
+ binder = nullptr;
+ service = nullptr;
+ IPCThreadState::self()->flushCommands();
+
+ sleep(kShutdownWaitTime);
+
+ bool isRunning = isServiceRunning(kForcePersistNdkUnitTestService);
+
+ if (i == 0) {
+ ASSERT_TRUE(isRunning) << "Service shut down when it shouldn't have.";
+ } else {
+ ASSERT_FALSE(isRunning) << "Service failed to shut down.";
+ }
+ }
+}
+
+TEST(NdkBinder, ActiveServicesCallbackTest) {
+ ndk::SpAIBinder binder(AServiceManager_waitForService(kActiveServicesNdkUnitTestService));
+ std::shared_ptr<aidl::IBinderNdkUnitTest> service =
+ aidl::IBinderNdkUnitTest::fromBinder(binder);
+ ASSERT_NE(service, nullptr);
+ ASSERT_TRUE(service->setCustomActiveServicesCallback().isOk());
+
+ binder = nullptr;
+ service = nullptr;
+ IPCThreadState::self()->flushCommands();
+
+ sleep(kShutdownWaitTime);
+
+ ASSERT_FALSE(isServiceRunning(kActiveServicesNdkUnitTestService))
+ << "Service failed to shut down.";
+}
+
void LambdaOnDeath(void* cookie) {
auto onDeath = static_cast<std::function<void(void)>*>(cookie);
(*onDeath)();
@@ -564,10 +660,18 @@ int main(int argc, char* argv[]) {
}
if (fork() == 0) {
prctl(PR_SET_PDEATHSIG, SIGHUP);
+ return lazyService(kForcePersistNdkUnitTestService);
+ }
+ if (fork() == 0) {
+ prctl(PR_SET_PDEATHSIG, SIGHUP);
+ return lazyService(kActiveServicesNdkUnitTestService);
+ }
+ if (fork() == 0) {
+ prctl(PR_SET_PDEATHSIG, SIGHUP);
return generatedService();
}
- ABinderProcess_setThreadPoolMaxThreadCount(1); // to recieve death notifications/callbacks
+ ABinderProcess_setThreadPoolMaxThreadCount(1); // to receive death notifications/callbacks
ABinderProcess_startThreadPool();
return RUN_ALL_TESTS();
diff --git a/libs/binder/parcel_fuzzer/Android.bp b/libs/binder/parcel_fuzzer/Android.bp
index 3e6fe99541..74b8eb8d93 100644
--- a/libs/binder/parcel_fuzzer/Android.bp
+++ b/libs/binder/parcel_fuzzer/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_fuzz {
name: "binder_parcel_fuzzer",
defaults: ["libbinder_ndk_host_user"],
diff --git a/libs/binder/rust/Android.bp b/libs/binder/rust/Android.bp
index fd5f2f5d9c..e12a429cf9 100644
--- a/libs/binder/rust/Android.bp
+++ b/libs/binder/rust/Android.bp
@@ -1,3 +1,12 @@
+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"],
+}
+
rust_library {
name: "libbinder_rs",
crate_name: "binder",
@@ -14,7 +23,11 @@ rust_library {
darwin: {
enabled: false,
}
- }
+ },
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.virt",
+ ],
}
rust_library {
@@ -32,7 +45,11 @@ rust_library {
darwin: {
enabled: false,
}
- }
+ },
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.virt",
+ ],
}
rust_bindgen {
@@ -78,6 +95,10 @@ rust_bindgen {
enabled: false,
},
},
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.virt",
+ ],
}
rust_test {
diff --git a/libs/binder/rust/src/binder.rs b/libs/binder/rust/src/binder.rs
index 42c1e0ac0e..d53a88f726 100644
--- a/libs/binder/rust/src/binder.rs
+++ b/libs/binder/rust/src/binder.rs
@@ -16,12 +16,17 @@
//! Trait definitions for binder objects
-use crate::error::{status_t, Result};
+use crate::error::{status_t, Result, StatusCode};
use crate::parcel::Parcel;
-use crate::proxy::{DeathRecipient, SpIBinder};
+use crate::proxy::{DeathRecipient, SpIBinder, WpIBinder};
use crate::sys;
+use std::borrow::Borrow;
+use std::cmp::Ordering;
use std::ffi::{c_void, CStr, CString};
+use std::fmt;
+use std::marker::PhantomData;
+use std::ops::Deref;
use std::os::raw::c_char;
use std::os::unix::io::AsRawFd;
use std::ptr;
@@ -44,7 +49,7 @@ pub type TransactionFlags = u32;
/// interfaces) must implement this trait.
///
/// This is equivalent `IInterface` in C++.
-pub trait Interface {
+pub trait Interface: Send {
/// Convert this binder object into a generic [`SpIBinder`] reference.
fn as_binder(&self) -> SpIBinder {
panic!("This object was not a Binder object and cannot be converted into an SpIBinder.")
@@ -230,6 +235,132 @@ impl From<InterfaceClass> for *const sys::AIBinder_Class {
}
}
+/// Strong reference to a binder object
+pub struct Strong<I: FromIBinder + ?Sized>(Box<I>);
+
+impl<I: FromIBinder + ?Sized> Strong<I> {
+ /// Create a new strong reference to the provided binder object
+ pub fn new(binder: Box<I>) -> Self {
+ Self(binder)
+ }
+
+ /// Construct a new weak reference to this binder
+ pub fn downgrade(this: &Strong<I>) -> Weak<I> {
+ Weak::new(this)
+ }
+}
+
+impl<I: FromIBinder + ?Sized> Clone for Strong<I> {
+ fn clone(&self) -> Self {
+ // Since we hold a strong reference, we should always be able to create
+ // a new strong reference to the same interface type, so try_from()
+ // should never fail here.
+ FromIBinder::try_from(self.0.as_binder()).unwrap()
+ }
+}
+
+impl<I: FromIBinder + ?Sized> Borrow<I> for Strong<I> {
+ fn borrow(&self) -> &I {
+ &self.0
+ }
+}
+
+impl<I: FromIBinder + ?Sized> AsRef<I> for Strong<I> {
+ fn as_ref(&self) -> &I {
+ &self.0
+ }
+}
+
+impl<I: FromIBinder + ?Sized> Deref for Strong<I> {
+ type Target = I;
+
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+}
+
+impl<I: FromIBinder + fmt::Debug + ?Sized> fmt::Debug for Strong<I> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Debug::fmt(&**self, f)
+ }
+}
+
+impl<I: FromIBinder + ?Sized> Ord for Strong<I> {
+ fn cmp(&self, other: &Self) -> Ordering {
+ self.0.as_binder().cmp(&other.0.as_binder())
+ }
+}
+
+impl<I: FromIBinder + ?Sized> PartialOrd for Strong<I> {
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ self.0.as_binder().partial_cmp(&other.0.as_binder())
+ }
+}
+
+impl<I: FromIBinder + ?Sized> PartialEq for Strong<I> {
+ fn eq(&self, other: &Self) -> bool {
+ self.0.as_binder().eq(&other.0.as_binder())
+ }
+}
+
+impl<I: FromIBinder + ?Sized> Eq for Strong<I> {}
+
+/// Weak reference to a binder object
+#[derive(Debug)]
+pub struct Weak<I: FromIBinder + ?Sized> {
+ weak_binder: WpIBinder,
+ interface_type: PhantomData<I>,
+}
+
+impl<I: FromIBinder + ?Sized> Weak<I> {
+ /// Construct a new weak reference from a strong reference
+ fn new(binder: &Strong<I>) -> Self {
+ let weak_binder = binder.as_binder().downgrade();
+ Weak {
+ weak_binder,
+ interface_type: PhantomData,
+ }
+ }
+
+ /// Upgrade this weak reference to a strong reference if the binder object
+ /// is still alive
+ pub fn upgrade(&self) -> Result<Strong<I>> {
+ self.weak_binder
+ .promote()
+ .ok_or(StatusCode::DEAD_OBJECT)
+ .and_then(FromIBinder::try_from)
+ }
+}
+
+impl<I: FromIBinder + ?Sized> Clone for Weak<I> {
+ fn clone(&self) -> Self {
+ Self {
+ weak_binder: self.weak_binder.clone(),
+ interface_type: PhantomData,
+ }
+ }
+}
+
+impl<I: FromIBinder + ?Sized> Ord for Weak<I> {
+ fn cmp(&self, other: &Self) -> Ordering {
+ self.weak_binder.cmp(&other.weak_binder)
+ }
+}
+
+impl<I: FromIBinder + ?Sized> PartialOrd for Weak<I> {
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ self.weak_binder.partial_cmp(&other.weak_binder)
+ }
+}
+
+impl<I: FromIBinder + ?Sized> PartialEq for Weak<I> {
+ fn eq(&self, other: &Self) -> bool {
+ self.weak_binder == other.weak_binder
+ }
+}
+
+impl<I: FromIBinder + ?Sized> Eq for Weak<I> {}
+
/// Create a function implementing a static getter for an interface class.
///
/// Each binder interface (i.e. local [`Remotable`] service or remote proxy
@@ -354,12 +485,12 @@ pub trait InterfaceClassMethods {
/// }
/// }
/// ```
-pub trait FromIBinder {
+pub trait FromIBinder: Interface {
/// Try to interpret a generic Binder object as this interface.
///
/// Returns a trait object for the `Self` interface if this object
/// implements that interface.
- fn try_from(ibinder: SpIBinder) -> Result<Box<Self>>;
+ fn try_from(ibinder: SpIBinder) -> Result<Strong<Self>>;
}
/// Trait for transparent Rust wrappers around android C++ native types.
@@ -534,8 +665,9 @@ macro_rules! declare_binder_interface {
impl $native {
/// Create a new binder service.
- pub fn new_binder<T: $interface + Sync + Send + 'static>(inner: T) -> impl $interface {
- $crate::Binder::new($native(Box::new(inner)))
+ pub fn new_binder<T: $interface + Sync + Send + 'static>(inner: T) -> $crate::Strong<dyn $interface> {
+ let binder = $crate::Binder::new($native(Box::new(inner)));
+ $crate::Strong::new(Box::new(binder))
}
}
@@ -577,7 +709,7 @@ macro_rules! declare_binder_interface {
}
impl $crate::FromIBinder for dyn $interface {
- fn try_from(mut ibinder: $crate::SpIBinder) -> $crate::Result<Box<dyn $interface>> {
+ fn try_from(mut ibinder: $crate::SpIBinder) -> $crate::Result<$crate::Strong<dyn $interface>> {
use $crate::AssociateClass;
let existing_class = ibinder.get_class();
@@ -590,7 +722,7 @@ macro_rules! declare_binder_interface {
// associated object as remote, because we can't cast it
// into a Rust service object without a matching class
// pointer.
- return Ok(Box::new(<$proxy as $crate::Proxy>::from_binder(ibinder)?));
+ return Ok($crate::Strong::new(Box::new(<$proxy as $crate::Proxy>::from_binder(ibinder)?)));
}
}
@@ -600,10 +732,10 @@ macro_rules! declare_binder_interface {
if let Ok(service) = service {
// We were able to associate with our expected class and
// the service is local.
- return Ok(Box::new(service));
+ return Ok($crate::Strong::new(Box::new(service)));
} else {
// Service is remote
- return Ok(Box::new(<$proxy as $crate::Proxy>::from_binder(ibinder)?));
+ return Ok($crate::Strong::new(Box::new(<$proxy as $crate::Proxy>::from_binder(ibinder)?)));
}
}
@@ -633,9 +765,9 @@ macro_rules! declare_binder_interface {
}
}
- // Convert a &dyn $interface to Box<dyn $interface>
+ /// Convert a &dyn $interface to Strong<dyn $interface>
impl std::borrow::ToOwned for dyn $interface {
- type Owned = Box<dyn $interface>;
+ type Owned = $crate::Strong<dyn $interface>;
fn to_owned(&self) -> Self::Owned {
self.as_binder().into_interface()
.expect(concat!("Error cloning interface ", stringify!($interface)))
diff --git a/libs/binder/rust/src/lib.rs b/libs/binder/rust/src/lib.rs
index edfb56a26c..43a237abf9 100644
--- a/libs/binder/rust/src/lib.rs
+++ b/libs/binder/rust/src/lib.rs
@@ -107,7 +107,8 @@ use binder_ndk_sys as sys;
pub mod parcel;
pub use crate::binder::{
- FromIBinder, IBinder, Interface, InterfaceClass, Remotable, TransactionCode, TransactionFlags,
+ FromIBinder, IBinder, Interface, InterfaceClass, Remotable, Strong, TransactionCode,
+ TransactionFlags, Weak,
};
pub use error::{status_t, ExceptionCode, Result, Status, StatusCode};
pub use native::add_service;
@@ -122,7 +123,8 @@ pub mod public_api {
pub use super::parcel::ParcelFileDescriptor;
pub use super::{add_service, get_interface};
pub use super::{
- ExceptionCode, Interface, ProcessState, SpIBinder, Status, StatusCode, WpIBinder,
+ ExceptionCode, Interface, ProcessState, SpIBinder, Status, StatusCode, Strong, ThreadState,
+ Weak, WpIBinder,
};
/// Binder result containing a [`Status`] on error.
diff --git a/libs/binder/rust/src/parcel/parcelable.rs b/libs/binder/rust/src/parcel/parcelable.rs
index 8d18fb486d..f57788b87e 100644
--- a/libs/binder/rust/src/parcel/parcelable.rs
+++ b/libs/binder/rust/src/parcel/parcelable.rs
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-use crate::binder::{AsNative, FromIBinder};
+use crate::binder::{AsNative, FromIBinder, Strong};
use crate::error::{status_result, status_t, Result, Status, StatusCode};
use crate::parcel::Parcel;
use crate::proxy::SpIBinder;
@@ -628,26 +628,26 @@ impl Deserialize for Status {
}
}
-impl<T: Serialize + ?Sized> Serialize for Box<T> {
+impl<T: Serialize + FromIBinder + ?Sized> Serialize for Strong<T> {
fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
Serialize::serialize(&**self, parcel)
}
}
-impl<T: SerializeOption + ?Sized> SerializeOption for Box<T> {
+impl<T: SerializeOption + FromIBinder + ?Sized> SerializeOption for Strong<T> {
fn serialize_option(this: Option<&Self>, parcel: &mut Parcel) -> Result<()> {
SerializeOption::serialize_option(this.map(|b| &**b), parcel)
}
}
-impl<T: FromIBinder + ?Sized> Deserialize for Box<T> {
+impl<T: FromIBinder + ?Sized> Deserialize for Strong<T> {
fn deserialize(parcel: &Parcel) -> Result<Self> {
let ibinder: SpIBinder = parcel.read()?;
FromIBinder::try_from(ibinder)
}
}
-impl<T: FromIBinder + ?Sized> DeserializeOption for Box<T> {
+impl<T: FromIBinder + ?Sized> DeserializeOption for Strong<T> {
fn deserialize_option(parcel: &Parcel) -> Result<Option<Self>> {
let ibinder: Option<SpIBinder> = parcel.read()?;
ibinder.map(FromIBinder::try_from).transpose()
diff --git a/libs/binder/rust/src/proxy.rs b/libs/binder/rust/src/proxy.rs
index e9e74c05e8..132e0758e1 100644
--- a/libs/binder/rust/src/proxy.rs
+++ b/libs/binder/rust/src/proxy.rs
@@ -17,7 +17,7 @@
//! Rust API for interacting with a remote binder service.
use crate::binder::{
- AsNative, FromIBinder, IBinder, Interface, InterfaceClass, TransactionCode, TransactionFlags,
+ AsNative, FromIBinder, IBinder, Interface, InterfaceClass, Strong, TransactionCode, TransactionFlags,
};
use crate::error::{status_result, Result, StatusCode};
use crate::parcel::{
@@ -27,6 +27,7 @@ use crate::parcel::{
use crate::sys;
use std::convert::TryInto;
+use std::cmp::Ordering;
use std::ffi::{c_void, CString};
use std::fmt;
use std::os::unix::io::AsRawFd;
@@ -99,7 +100,7 @@ impl SpIBinder {
///
/// If this object does not implement the expected interface, the error
/// `StatusCode::BAD_TYPE` is returned.
- pub fn into_interface<I: FromIBinder + ?Sized>(self) -> Result<Box<I>> {
+ pub fn into_interface<I: FromIBinder + Interface + ?Sized>(self) -> Result<Strong<I>> {
FromIBinder::try_from(self)
}
@@ -148,6 +149,36 @@ impl AssociateClass for SpIBinder {
}
}
+impl Ord for SpIBinder {
+ fn cmp(&self, other: &Self) -> Ordering {
+ let less_than = unsafe {
+ // Safety: SpIBinder always holds a valid `AIBinder` pointer, so
+ // this pointer is always safe to pass to `AIBinder_lt` (null is
+ // also safe to pass to this function, but we should never do that).
+ sys::AIBinder_lt(self.0, other.0)
+ };
+ let greater_than = unsafe {
+ // Safety: SpIBinder always holds a valid `AIBinder` pointer, so
+ // this pointer is always safe to pass to `AIBinder_lt` (null is
+ // also safe to pass to this function, but we should never do that).
+ sys::AIBinder_lt(other.0, self.0)
+ };
+ if !less_than && !greater_than {
+ Ordering::Equal
+ } else if less_than {
+ Ordering::Less
+ } else {
+ Ordering::Greater
+ }
+ }
+}
+
+impl PartialOrd for SpIBinder {
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ Some(self.cmp(other))
+ }
+}
+
impl PartialEq for SpIBinder {
fn eq(&self, other: &Self) -> bool {
ptr::eq(self.0, other.0)
@@ -326,7 +357,7 @@ impl<T: AsNative<sys::AIBinder>> IBinder for T {
// Safety: `SpIBinder` guarantees that `self` always contains a
// valid pointer to an `AIBinder`. `recipient` can always be
// converted into a valid pointer to an
- // `AIBinder_DeatRecipient`. Any value is safe to pass as the
+ // `AIBinder_DeathRecipient`. Any value is safe to pass as the
// cookie, although we depend on this value being set by
// `get_cookie` when the death recipient callback is called.
sys::AIBinder_linkToDeath(
@@ -342,7 +373,7 @@ impl<T: AsNative<sys::AIBinder>> IBinder for T {
// Safety: `SpIBinder` guarantees that `self` always contains a
// valid pointer to an `AIBinder`. `recipient` can always be
// converted into a valid pointer to an
- // `AIBinder_DeatRecipient`. Any value is safe to pass as the
+ // `AIBinder_DeathRecipient`. Any value is safe to pass as the
// cookie, although we depend on this value being set by
// `get_cookie` when the death recipient callback is called.
sys::AIBinder_unlinkToDeath(
@@ -430,6 +461,62 @@ impl WpIBinder {
}
}
+impl Clone for WpIBinder {
+ fn clone(&self) -> Self {
+ let ptr = unsafe {
+ // Safety: WpIBinder always holds a valid `AIBinder_Weak` pointer,
+ // so this pointer is always safe to pass to `AIBinder_Weak_clone`
+ // (although null is also a safe value to pass to this API).
+ //
+ // We get ownership of the returned pointer, so can construct a new
+ // WpIBinder object from it.
+ sys::AIBinder_Weak_clone(self.0)
+ };
+ assert!(!ptr.is_null(), "Unexpected null pointer from AIBinder_Weak_clone");
+ Self(ptr)
+ }
+}
+
+impl Ord for WpIBinder {
+ fn cmp(&self, other: &Self) -> Ordering {
+ let less_than = unsafe {
+ // Safety: WpIBinder always holds a valid `AIBinder_Weak` pointer,
+ // so this pointer is always safe to pass to `AIBinder_Weak_lt`
+ // (null is also safe to pass to this function, but we should never
+ // do that).
+ sys::AIBinder_Weak_lt(self.0, other.0)
+ };
+ let greater_than = unsafe {
+ // Safety: WpIBinder always holds a valid `AIBinder_Weak` pointer,
+ // so this pointer is always safe to pass to `AIBinder_Weak_lt`
+ // (null is also safe to pass to this function, but we should never
+ // do that).
+ sys::AIBinder_Weak_lt(other.0, self.0)
+ };
+ if !less_than && !greater_than {
+ Ordering::Equal
+ } else if less_than {
+ Ordering::Less
+ } else {
+ Ordering::Greater
+ }
+ }
+}
+
+impl PartialOrd for WpIBinder {
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ Some(self.cmp(other))
+ }
+}
+
+impl PartialEq for WpIBinder {
+ fn eq(&self, other: &Self) -> bool {
+ self.cmp(other) == Ordering::Equal
+ }
+}
+
+impl Eq for WpIBinder {}
+
impl Drop for WpIBinder {
fn drop(&mut self) {
unsafe {
@@ -564,7 +651,7 @@ pub fn get_service(name: &str) -> Option<SpIBinder> {
/// Retrieve an existing service for a particular interface, blocking for a few
/// seconds if it doesn't yet exist.
-pub fn get_interface<T: FromIBinder + ?Sized>(name: &str) -> Result<Box<T>> {
+pub fn get_interface<T: FromIBinder + ?Sized>(name: &str) -> Result<Strong<T>> {
let service = get_service(name);
match service {
Some(service) => FromIBinder::try_from(service),
diff --git a/libs/binder/rust/tests/Android.bp b/libs/binder/rust/tests/Android.bp
index 8810b5dd16..0bf76c696a 100644
--- a/libs/binder/rust/tests/Android.bp
+++ b/libs/binder/rust/tests/Android.bp
@@ -1,3 +1,12 @@
+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"],
+}
+
rust_test {
name: "rustBinderTest",
srcs: ["integration.rs"],
diff --git a/libs/binder/rust/tests/integration.rs b/libs/binder/rust/tests/integration.rs
index bb8c492bdb..719229c9b7 100644
--- a/libs/binder/rust/tests/integration.rs
+++ b/libs/binder/rust/tests/integration.rs
@@ -209,7 +209,7 @@ mod tests {
use std::thread;
use std::time::Duration;
- use binder::{Binder, DeathRecipient, FromIBinder, IBinder, Interface, SpIBinder, StatusCode};
+ use binder::{Binder, DeathRecipient, FromIBinder, IBinder, Interface, SpIBinder, StatusCode, Strong};
use super::{BnTest, ITest, ITestSameDescriptor, RUST_SERVICE_BINARY, TestService};
@@ -271,7 +271,7 @@ mod tests {
fn trivial_client() {
let service_name = "trivial_client_test";
let _process = ScopedServiceProcess::new(service_name);
- let test_client: Box<dyn ITest> =
+ let test_client: Strong<dyn ITest> =
binder::get_interface(service_name).expect("Did not get manager binder service");
assert_eq!(test_client.test().unwrap(), "trivial_client_test");
}
@@ -280,7 +280,7 @@ mod tests {
fn get_selinux_context() {
let service_name = "get_selinux_context";
let _process = ScopedServiceProcess::new(service_name);
- let test_client: Box<dyn ITest> =
+ let test_client: Strong<dyn ITest> =
binder::get_interface(service_name).expect("Did not get manager binder service");
let expected_context = unsafe {
let mut out_ptr = ptr::null_mut();
@@ -453,7 +453,7 @@ mod tests {
let extension = maybe_extension.expect("Remote binder did not have an extension");
- let extension: Box<dyn ITest> = FromIBinder::try_from(extension)
+ let extension: Strong<dyn ITest> = FromIBinder::try_from(extension)
.expect("Extension could not be converted to the expected interface");
assert_eq!(extension.test().unwrap(), extension_name);
@@ -479,7 +479,7 @@ mod tests {
// This should succeed although we will have to treat the service as
// remote.
- let _interface: Box<dyn ITestSameDescriptor> = FromIBinder::try_from(service.as_binder())
+ let _interface: Strong<dyn ITestSameDescriptor> = FromIBinder::try_from(service.as_binder())
.expect("Could not re-interpret service as the ITestSameDescriptor interface");
}
@@ -490,9 +490,60 @@ mod tests {
let service_ibinder = BnTest::new_binder(TestService { s: service_name.to_string() })
.as_binder();
- let service: Box<dyn ITest> = service_ibinder.into_interface()
+ let service: Strong<dyn ITest> = service_ibinder.into_interface()
.expect("Could not reassociate the generic ibinder");
assert_eq!(service.test().unwrap(), service_name);
}
+
+ #[test]
+ fn weak_binder_upgrade() {
+ let service_name = "testing_service";
+ let service = BnTest::new_binder(TestService { s: service_name.to_string() });
+
+ let weak = Strong::downgrade(&service);
+
+ let upgraded = weak.upgrade().expect("Could not upgrade weak binder");
+
+ assert_eq!(service, upgraded);
+ }
+
+ #[test]
+ fn weak_binder_upgrade_dead() {
+ let service_name = "testing_service";
+ let weak = {
+ let service = BnTest::new_binder(TestService { s: service_name.to_string() });
+
+ Strong::downgrade(&service)
+ };
+
+ assert_eq!(weak.upgrade(), Err(StatusCode::DEAD_OBJECT));
+ }
+
+ #[test]
+ fn weak_binder_clone() {
+ let service_name = "testing_service";
+ let service = BnTest::new_binder(TestService { s: service_name.to_string() });
+
+ let weak = Strong::downgrade(&service);
+ let cloned = weak.clone();
+ assert_eq!(weak, cloned);
+
+ let upgraded = weak.upgrade().expect("Could not upgrade weak binder");
+ let clone_upgraded = cloned.upgrade().expect("Could not upgrade weak binder");
+
+ assert_eq!(service, upgraded);
+ assert_eq!(service, clone_upgraded);
+ }
+
+ #[test]
+ #[allow(clippy::eq_op)]
+ fn binder_ord() {
+ let service1 = BnTest::new_binder(TestService { s: "testing_service1".to_string() });
+ let service2 = BnTest::new_binder(TestService { s: "testing_service2".to_string() });
+
+ assert!(!(service1 < service1));
+ assert!(!(service1 > service1));
+ assert_eq!(service1 < service2, !(service2 < service1));
+ }
}
diff --git a/libs/binder/rust/tests/ndk_rust_interop.rs b/libs/binder/rust/tests/ndk_rust_interop.rs
index 70a6dc0788..ce75ab7125 100644
--- a/libs/binder/rust/tests/ndk_rust_interop.rs
+++ b/libs/binder/rust/tests/ndk_rust_interop.rs
@@ -37,7 +37,7 @@ pub unsafe extern "C" fn rust_call_ndk(service_name: *const c_char) -> c_int {
// The Rust class descriptor pointer will not match the NDK one, but the
// descriptor strings match so this needs to still associate.
- let service: Box<dyn IBinderRustNdkInteropTest> = match binder::get_interface(service_name) {
+ let service: binder::Strong<dyn IBinderRustNdkInteropTest> = match binder::get_interface(service_name) {
Err(e) => {
eprintln!("Could not find Ndk service {}: {:?}", service_name, e);
return StatusCode::NAME_NOT_FOUND as c_int;
@@ -53,7 +53,7 @@ pub unsafe extern "C" fn rust_call_ndk(service_name: *const c_char) -> c_int {
}
// Try using the binder service through the wrong interface type
- let wrong_service: Result<Box<dyn IBinderRustNdkInteropTestOther>, StatusCode> =
+ let wrong_service: Result<binder::Strong<dyn IBinderRustNdkInteropTestOther>, StatusCode> =
binder::get_interface(service_name);
match wrong_service {
Err(e) if e == StatusCode::BAD_TYPE => {}
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index 259417a655..3bbb0b52bb 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_defaults {
name: "binder_test_defaults",
cflags: [
diff --git a/libs/binder/tests/binderParcelBenchmark.cpp b/libs/binder/tests/binderParcelBenchmark.cpp
index ec69c367ba..26c50ebb57 100644
--- a/libs/binder/tests/binderParcelBenchmark.cpp
+++ b/libs/binder/tests/binderParcelBenchmark.cpp
@@ -91,56 +91,56 @@ static void BM_ParcelVector(benchmark::State& state) {
Results on Crosshatch Pixel 3XL
- #BM_BoolVector/1 40 ns 40 ns 17261011
- #BM_BoolVector/2 46 ns 46 ns 15029619
- #BM_BoolVector/4 65 ns 64 ns 10888021
- #BM_BoolVector/8 114 ns 114 ns 6130937
- #BM_BoolVector/16 179 ns 179 ns 3902462
- #BM_BoolVector/32 328 ns 327 ns 2138812
- #BM_BoolVector/64 600 ns 598 ns 1169414
- #BM_BoolVector/128 1168 ns 1165 ns 601281
- #BM_BoolVector/256 2288 ns 2281 ns 305737
- #BM_BoolVector/512 4535 ns 4521 ns 154668
- #BM_ByteVector/1 53 ns 52 ns 13212196
- #BM_ByteVector/2 53 ns 53 ns 13194050
- #BM_ByteVector/4 50 ns 50 ns 13768037
- #BM_ByteVector/8 50 ns 50 ns 13890210
- #BM_ByteVector/16 50 ns 50 ns 13897305
- #BM_ByteVector/32 51 ns 51 ns 13679862
- #BM_ByteVector/64 54 ns 53 ns 12988544
- #BM_ByteVector/128 64 ns 64 ns 10921227
- #BM_ByteVector/256 82 ns 81 ns 8542549
- #BM_ByteVector/512 118 ns 118 ns 5862931
- #BM_CharVector/1 32 ns 32 ns 21783579
- #BM_CharVector/2 38 ns 38 ns 18200971
- #BM_CharVector/4 53 ns 53 ns 13111785
- #BM_CharVector/8 80 ns 80 ns 8698331
- #BM_CharVector/16 159 ns 159 ns 4390738
- #BM_CharVector/32 263 ns 262 ns 2667310
- #BM_CharVector/64 486 ns 485 ns 1441118
- #BM_CharVector/128 937 ns 934 ns 749006
- #BM_CharVector/256 1848 ns 1843 ns 379537
- #BM_CharVector/512 3650 ns 3639 ns 191713
- #BM_Int32Vector/1 31 ns 31 ns 22104147
- #BM_Int32Vector/2 38 ns 38 ns 18075471
- #BM_Int32Vector/4 53 ns 52 ns 13249969
- #BM_Int32Vector/8 80 ns 80 ns 8719798
- #BM_Int32Vector/16 161 ns 160 ns 4350096
- #BM_Int32Vector/32 271 ns 270 ns 2591896
- #BM_Int32Vector/64 499 ns 498 ns 1406201
- #BM_Int32Vector/128 948 ns 945 ns 740052
- #BM_Int32Vector/256 1855 ns 1849 ns 379127
- #BM_Int32Vector/512 3665 ns 3653 ns 191533
- #BM_Int64Vector/1 31 ns 31 ns 22388370
- #BM_Int64Vector/2 38 ns 38 ns 18300347
- #BM_Int64Vector/4 53 ns 53 ns 13137818
- #BM_Int64Vector/8 81 ns 81 ns 8599613
- #BM_Int64Vector/16 167 ns 166 ns 4195953
- #BM_Int64Vector/32 280 ns 280 ns 2499271
- #BM_Int64Vector/64 523 ns 522 ns 1341380
- #BM_Int64Vector/128 991 ns 988 ns 707437
- #BM_Int64Vector/256 1940 ns 1934 ns 361704
- #BM_Int64Vector/512 3843 ns 3831 ns 183204
+ #BM_BoolVector/1 44 ns 44 ns 15630626
+ #BM_BoolVector/2 54 ns 54 ns 12900340
+ #BM_BoolVector/4 73 ns 72 ns 9749841
+ #BM_BoolVector/8 107 ns 107 ns 6503326
+ #BM_BoolVector/16 186 ns 185 ns 3773627
+ #BM_BoolVector/32 337 ns 336 ns 2083877
+ #BM_BoolVector/64 607 ns 605 ns 1154113
+ #BM_BoolVector/128 1155 ns 1151 ns 608128
+ #BM_BoolVector/256 2259 ns 2253 ns 310973
+ #BM_BoolVector/512 4469 ns 4455 ns 157277
+ #BM_ByteVector/1 41 ns 41 ns 16837425
+ #BM_ByteVector/2 41 ns 41 ns 16820726
+ #BM_ByteVector/4 38 ns 38 ns 18217813
+ #BM_ByteVector/8 38 ns 38 ns 18290298
+ #BM_ByteVector/16 38 ns 38 ns 18117817
+ #BM_ByteVector/32 38 ns 38 ns 18172385
+ #BM_ByteVector/64 41 ns 41 ns 16950055
+ #BM_ByteVector/128 53 ns 53 ns 13170749
+ #BM_ByteVector/256 69 ns 69 ns 10113626
+ #BM_ByteVector/512 106 ns 106 ns 6561936
+ #BM_CharVector/1 38 ns 38 ns 18074831
+ #BM_CharVector/2 40 ns 40 ns 17206266
+ #BM_CharVector/4 50 ns 50 ns 13785944
+ #BM_CharVector/8 67 ns 67 ns 10223316
+ #BM_CharVector/16 96 ns 96 ns 7297285
+ #BM_CharVector/32 156 ns 155 ns 4484845
+ #BM_CharVector/64 277 ns 276 ns 2536003
+ #BM_CharVector/128 520 ns 518 ns 1347070
+ #BM_CharVector/256 1006 ns 1003 ns 695952
+ #BM_CharVector/512 1976 ns 1970 ns 354673
+ #BM_Int32Vector/1 41 ns 41 ns 16951262
+ #BM_Int32Vector/2 41 ns 41 ns 16916883
+ #BM_Int32Vector/4 41 ns 41 ns 16761373
+ #BM_Int32Vector/8 42 ns 42 ns 16553179
+ #BM_Int32Vector/16 43 ns 43 ns 16200362
+ #BM_Int32Vector/32 55 ns 54 ns 12724454
+ #BM_Int32Vector/64 70 ns 69 ns 10049223
+ #BM_Int32Vector/128 107 ns 107 ns 6525796
+ #BM_Int32Vector/256 179 ns 178 ns 3922563
+ #BM_Int32Vector/512 324 ns 323 ns 2160653
+ #BM_Int64Vector/1 41 ns 41 ns 16909470
+ #BM_Int64Vector/2 41 ns 41 ns 16740788
+ #BM_Int64Vector/4 42 ns 42 ns 16564197
+ #BM_Int64Vector/8 43 ns 42 ns 16284082
+ #BM_Int64Vector/16 54 ns 54 ns 12839474
+ #BM_Int64Vector/32 69 ns 69 ns 10011010
+ #BM_Int64Vector/64 107 ns 106 ns 6557956
+ #BM_Int64Vector/128 177 ns 177 ns 3925618
+ #BM_Int64Vector/256 324 ns 323 ns 2163321
+ #BM_Int64Vector/512 613 ns 611 ns 1140418
*/
static void BM_BoolVector(benchmark::State& state) {
diff --git a/libs/binder/tests/fuzzers/Android.bp b/libs/binder/tests/fuzzers/Android.bp
index 5531296edb..b1263e8d8e 100644
--- a/libs/binder/tests/fuzzers/Android.bp
+++ b/libs/binder/tests/fuzzers/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_defaults {
name: "binder_fuzz_defaults",
host_supported: true,
diff --git a/libs/binderdebug/Android.bp b/libs/binderdebug/Android.bp
index 343246a324..3eeaf3e4f1 100644
--- a/libs/binderdebug/Android.bp
+++ b/libs/binderdebug/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library {
name: "libbinderdebug",
vendor_available: true,
diff --git a/libs/binderdebug/tests/Android.bp b/libs/binderdebug/tests/Android.bp
index 4c06b1d0d9..d141a05ca9 100644
--- a/libs/binderdebug/tests/Android.bp
+++ b/libs/binderdebug/tests/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_test {
name: "libbinderdebug_test",
test_suites: ["general-tests"],
diff --git a/libs/binderthreadstate/1.0/Android.bp b/libs/binderthreadstate/1.0/Android.bp
index ebdc932591..99477d8e26 100644
--- a/libs/binderthreadstate/1.0/Android.bp
+++ b/libs/binderthreadstate/1.0/Android.bp
@@ -1,5 +1,14 @@
// This file is autogenerated by hidl-gen -Landroidbp.
+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"],
+}
+
hidl_interface {
name: "binderthreadstateutilstest@1.0",
root: "binderthreadstateutilstest",
diff --git a/libs/binderthreadstate/Android.bp b/libs/binderthreadstate/Android.bp
index 08c62df072..0a82463feb 100644
--- a/libs/binderthreadstate/Android.bp
+++ b/libs/binderthreadstate/Android.bp
@@ -14,6 +14,15 @@
// DO NOT ADD NEW USAGES OF THIS
// See comments in header file.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library_static {
name: "libbinderthreadstateutils",
double_loadable: true,
diff --git a/libs/bufferqueueconverter/Android.bp b/libs/bufferqueueconverter/Android.bp
index bab267466c..c5d3a3207c 100644
--- a/libs/bufferqueueconverter/Android.bp
+++ b/libs/bufferqueueconverter/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library_headers {
name: "libbufferqueueconverter_headers",
vendor_available: true,
diff --git a/libs/cputimeinstate/Android.bp b/libs/cputimeinstate/Android.bp
index e3cd0859cb..570af71d9a 100644
--- a/libs/cputimeinstate/Android.bp
+++ b/libs/cputimeinstate/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library {
name: "libtimeinstate",
srcs: ["cputimeinstate.cpp"],
@@ -35,4 +44,3 @@ cc_test {
],
require_root: true,
}
-
diff --git a/libs/diskusage/Android.bp b/libs/diskusage/Android.bp
index a8263069de..86840613e6 100644
--- a/libs/diskusage/Android.bp
+++ b/libs/diskusage/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library_static {
name: "libdiskusage",
srcs: ["dirsize.c"],
diff --git a/libs/dumputils/Android.bp b/libs/dumputils/Android.bp
index e403d36da1..acda402993 100644
--- a/libs/dumputils/Android.bp
+++ b/libs/dumputils/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library {
name: "libdumputils",
diff --git a/libs/fakeservicemanager/Android.bp b/libs/fakeservicemanager/Android.bp
index 76518c1286..47c0657bbd 100644
--- a/libs/fakeservicemanager/Android.bp
+++ b/libs/fakeservicemanager/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_defaults {
name: "fakeservicemanager_defaults",
host_supported: true,
diff --git a/libs/gralloc/types/Android.bp b/libs/gralloc/types/Android.bp
index dd0ae30703..a0032aecb9 100644
--- a/libs/gralloc/types/Android.bp
+++ b/libs/gralloc/types/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library {
name: "libgralloctypes",
defaults: ["libbinder_ndk_host_user"],
diff --git a/libs/gralloc/types/fuzzer/Android.bp b/libs/gralloc/types/fuzzer/Android.bp
index 8933dc323f..6689771a24 100644
--- a/libs/gralloc/types/fuzzer/Android.bp
+++ b/libs/gralloc/types/fuzzer/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_fuzz {
name: "libgralloctypes_fuzzer",
defaults: ["libbinder_ndk_host_user"],
diff --git a/libs/gralloc/types/tests/Android.bp b/libs/gralloc/types/tests/Android.bp
index b939c1db59..66eb0aa2fe 100644
--- a/libs/gralloc/types/tests/Android.bp
+++ b/libs/gralloc/types/tests/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_test {
name: "GrallocTypes_test",
shared_libs: [
diff --git a/libs/graphicsenv/Android.bp b/libs/graphicsenv/Android.bp
index 642c5f2cc0..a96a07a9b8 100644
--- a/libs/graphicsenv/Android.bp
+++ b/libs/graphicsenv/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library_shared {
name: "libgraphicsenv",
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index fa5044cc16..debd664aba 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -11,6 +11,15 @@
// 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 {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library_headers {
name: "libgui_headers",
vendor_available: true,
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index 1e6fc2b217..82c9268feb 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -55,7 +55,7 @@ namespace android {
ALOGE("[%s](f:%u,a:%u) " x, mName.c_str(), mNumFrameAvailable, mNumAcquired, ##__VA_ARGS__)
void BLASTBufferItemConsumer::onDisconnect() {
- Mutex::Autolock lock(mFrameEventHistoryMutex);
+ Mutex::Autolock lock(mMutex);
mPreviouslyConnected = mCurrentlyConnected;
mCurrentlyConnected = false;
if (mPreviouslyConnected) {
@@ -66,7 +66,7 @@ void BLASTBufferItemConsumer::onDisconnect() {
void BLASTBufferItemConsumer::addAndGetFrameTimestamps(const NewFrameEventsEntry* newTimestamps,
FrameEventHistoryDelta* outDelta) {
- Mutex::Autolock lock(mFrameEventHistoryMutex);
+ Mutex::Autolock lock(mMutex);
if (newTimestamps) {
// BufferQueueProducer only adds a new timestamp on
// queueBuffer
@@ -90,7 +90,7 @@ void BLASTBufferItemConsumer::updateFrameTimestamps(uint64_t frameNumber, nsecs_
const sp<Fence>& prevReleaseFence,
CompositorTiming compositorTiming,
nsecs_t latchTime, nsecs_t dequeueReadyTime) {
- Mutex::Autolock lock(mFrameEventHistoryMutex);
+ Mutex::Autolock lock(mMutex);
// if the producer is not connected, don't bother updating,
// the next producer that connects won't access this frame event
@@ -108,7 +108,7 @@ void BLASTBufferItemConsumer::updateFrameTimestamps(uint64_t frameNumber, nsecs_
void BLASTBufferItemConsumer::getConnectionEvents(uint64_t frameNumber, bool* needsDisconnect) {
bool disconnect = false;
- Mutex::Autolock lock(mFrameEventHistoryMutex);
+ Mutex::Autolock lock(mMutex);
while (!mDisconnectEvents.empty() && mDisconnectEvents.front() <= frameNumber) {
disconnect = true;
mDisconnectEvents.pop();
@@ -116,6 +116,19 @@ void BLASTBufferItemConsumer::getConnectionEvents(uint64_t frameNumber, bool* ne
if (needsDisconnect != nullptr) *needsDisconnect = disconnect;
}
+void BLASTBufferItemConsumer::setBlastBufferQueue(BLASTBufferQueue* blastbufferqueue) {
+ Mutex::Autolock lock(mMutex);
+ mBLASTBufferQueue = blastbufferqueue;
+}
+
+void BLASTBufferItemConsumer::onSidebandStreamChanged() {
+ Mutex::Autolock lock(mMutex);
+ if (mBLASTBufferQueue != nullptr) {
+ sp<NativeHandle> stream = getSidebandStream();
+ mBLASTBufferQueue->setSidebandStream(stream);
+ }
+}
+
BLASTBufferQueue::BLASTBufferQueue(const std::string& name, const sp<SurfaceControl>& surface,
int width, int height, int32_t format,
bool enableTripleBuffering)
@@ -145,6 +158,7 @@ BLASTBufferQueue::BLASTBufferQueue(const std::string& name, const sp<SurfaceCont
mBufferItemConsumer->setBufferFreedListener(this);
mBufferItemConsumer->setDefaultBufferSize(mSize.width, mSize.height);
mBufferItemConsumer->setDefaultBufferFormat(convertBufferFormat(format));
+ mBufferItemConsumer->setBlastBufferQueue(this);
mTransformHint = mSurfaceControl->getTransformHint();
mBufferItemConsumer->setTransformHint(mTransformHint);
@@ -160,6 +174,7 @@ BLASTBufferQueue::BLASTBufferQueue(const std::string& name, const sp<SurfaceCont
}
BLASTBufferQueue::~BLASTBufferQueue() {
+ mBufferItemConsumer->setBlastBufferQueue(nullptr);
if (mPendingTransactions.empty()) {
return;
}
@@ -557,6 +572,13 @@ status_t BLASTBufferQueue::setFrameTimelineInfo(const FrameTimelineInfo& frameTi
return OK;
}
+void BLASTBufferQueue::setSidebandStream(const sp<NativeHandle>& stream) {
+ std::unique_lock _lock{mMutex};
+ SurfaceComposerClient::Transaction t;
+
+ t.setSidebandStream(mSurfaceControl, stream).apply();
+}
+
sp<Surface> BLASTBufferQueue::getSurface(bool includeSurfaceControlHandle) {
std::unique_lock _lock{mMutex};
sp<IBinder> scHandle = nullptr;
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 762746c0ce..eba7b3c9fd 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -36,11 +36,12 @@
#include <system/graphics.h>
-#include <ui/DisplayInfo.h>
#include <ui/DisplayMode.h>
#include <ui/DisplayStatInfo.h>
#include <ui/DisplayState.h>
+#include <ui/DynamicDisplayInfo.h>
#include <ui/HdrCapabilities.h>
+#include <ui/StaticDisplayInfo.h>
#include <utils/Log.h>
@@ -323,32 +324,26 @@ public:
return result;
}
- status_t getDisplayInfo(const sp<IBinder>& display, DisplayInfo* info) override {
+ status_t getStaticDisplayInfo(const sp<IBinder>& display,
+ ui::StaticDisplayInfo* info) override {
Parcel data, reply;
data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
data.writeStrongBinder(display);
- remote()->transact(BnSurfaceComposer::GET_DISPLAY_INFO, data, &reply);
+ remote()->transact(BnSurfaceComposer::GET_STATIC_DISPLAY_INFO, data, &reply);
const status_t result = reply.readInt32();
if (result != NO_ERROR) return result;
return reply.read(*info);
}
- status_t getDisplayModes(const sp<IBinder>& display, Vector<ui::DisplayMode>* modes) override {
+ status_t getDynamicDisplayInfo(const sp<IBinder>& display,
+ ui::DynamicDisplayInfo* info) override {
Parcel data, reply;
data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
data.writeStrongBinder(display);
- remote()->transact(BnSurfaceComposer::GET_DISPLAY_MODES, data, &reply);
+ remote()->transact(BnSurfaceComposer::GET_DYNAMIC_DISPLAY_INFO, data, &reply);
const status_t result = reply.readInt32();
- if (result == NO_ERROR) {
- const size_t numModes = reply.readUint32();
- modes->clear();
- modes->resize(numModes);
- for (size_t i = 0; i < numModes; i++) {
- memcpy(&(modes->editItemAt(i)), reply.readInplace(sizeof(ui::DisplayMode)),
- sizeof(ui::DisplayMode));
- }
- }
- return result;
+ if (result != NO_ERROR) return result;
+ return reply.read(*info);
}
status_t getDisplayStats(const sp<IBinder>& display, DisplayStatInfo* stats) override {
@@ -365,44 +360,6 @@ public:
return result;
}
- int getActiveDisplayModeId(const sp<IBinder>& display) override {
- Parcel data, reply;
- data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- data.writeStrongBinder(display);
- remote()->transact(BnSurfaceComposer::GET_ACTIVE_DISPLAY_MODE, data, &reply);
- return reply.readInt32();
- }
-
- status_t getDisplayColorModes(const sp<IBinder>& display,
- Vector<ColorMode>* outColorModes) override {
- Parcel data, reply;
- status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- if (result != NO_ERROR) {
- ALOGE("getDisplayColorModes failed to writeInterfaceToken: %d", result);
- return result;
- }
- result = data.writeStrongBinder(display);
- if (result != NO_ERROR) {
- ALOGE("getDisplayColorModes failed to writeStrongBinder: %d", result);
- return result;
- }
- result = remote()->transact(BnSurfaceComposer::GET_DISPLAY_COLOR_MODES, data, &reply);
- if (result != NO_ERROR) {
- ALOGE("getDisplayColorModes failed to transact: %d", result);
- return result;
- }
- result = static_cast<status_t>(reply.readInt32());
- if (result == NO_ERROR) {
- size_t numModes = reply.readUint32();
- outColorModes->clear();
- outColorModes->resize(numModes);
- for (size_t i = 0; i < numModes; ++i) {
- outColorModes->replaceAt(static_cast<ColorMode>(reply.readInt32()), i);
- }
- }
- return result;
- }
-
status_t getDisplayNativePrimaries(const sp<IBinder>& display,
ui::DisplayPrimaries& primaries) override {
Parcel data, reply;
@@ -429,26 +386,6 @@ public:
return result;
}
- ColorMode getActiveColorMode(const sp<IBinder>& display) override {
- Parcel data, reply;
- status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- if (result != NO_ERROR) {
- ALOGE("getActiveColorMode failed to writeInterfaceToken: %d", result);
- return static_cast<ColorMode>(result);
- }
- result = data.writeStrongBinder(display);
- if (result != NO_ERROR) {
- ALOGE("getActiveColorMode failed to writeStrongBinder: %d", result);
- return static_cast<ColorMode>(result);
- }
- result = remote()->transact(BnSurfaceComposer::GET_ACTIVE_COLOR_MODE, data, &reply);
- if (result != NO_ERROR) {
- ALOGE("getActiveColorMode failed to transact: %d", result);
- return static_cast<ColorMode>(result);
- }
- return static_cast<ColorMode>(reply.readInt32());
- }
-
status_t setActiveColorMode(const sp<IBinder>& display, ColorMode colorMode) override {
Parcel data, reply;
status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
@@ -474,24 +411,6 @@ public:
return static_cast<status_t>(reply.readInt32());
}
- status_t getAutoLowLatencyModeSupport(const sp<IBinder>& display,
- bool* outSupport) const override {
- Parcel data, reply;
- data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- status_t result = data.writeStrongBinder(display);
- if (result != NO_ERROR) {
- ALOGE("getAutoLowLatencyModeSupport failed to writeStrongBinder: %d", result);
- return result;
- }
- result = remote()->transact(BnSurfaceComposer::GET_AUTO_LOW_LATENCY_MODE_SUPPORT, data,
- &reply);
- if (result != NO_ERROR) {
- ALOGE("getAutoLowLatencyModeSupport failed to transact: %d", result);
- return result;
- }
- return reply.readBool(outSupport);
- }
-
void setAutoLowLatencyMode(const sp<IBinder>& display, bool on) override {
Parcel data, reply;
status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
@@ -517,23 +436,6 @@ public:
}
}
- status_t getGameContentTypeSupport(const sp<IBinder>& display,
- bool* outSupport) const override {
- Parcel data, reply;
- data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- status_t result = data.writeStrongBinder(display);
- if (result != NO_ERROR) {
- ALOGE("getGameContentTypeSupport failed to writeStrongBinder: %d", result);
- return result;
- }
- result = remote()->transact(BnSurfaceComposer::GET_GAME_CONTENT_TYPE_SUPPORT, data, &reply);
- if (result != NO_ERROR) {
- ALOGE("getGameContentTypeSupport failed to transact: %d", result);
- return result;
- }
- return reply.readBool(outSupport);
- }
-
void setGameContentType(const sp<IBinder>& display, bool on) override {
Parcel data, reply;
status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
@@ -580,28 +482,6 @@ public:
return reply.readInt32();
}
- status_t getHdrCapabilities(const sp<IBinder>& display,
- HdrCapabilities* outCapabilities) const override {
- Parcel data, reply;
- data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- status_t result = data.writeStrongBinder(display);
- if (result != NO_ERROR) {
- ALOGE("getHdrCapabilities failed to writeStrongBinder: %d", result);
- return result;
- }
- result = remote()->transact(BnSurfaceComposer::GET_HDR_CAPABILITIES,
- data, &reply);
- if (result != NO_ERROR) {
- ALOGE("getHdrCapabilities failed to transact: %d", result);
- return result;
- }
- result = reply.readInt32();
- if (result == NO_ERROR) {
- result = reply.read(*outCapabilities);
- }
- return result;
- }
-
status_t enableVSyncInjections(bool enable) override {
Parcel data, reply;
status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
@@ -881,9 +761,10 @@ public:
return error;
}
- status_t setDesiredDisplayModeSpecs(const sp<IBinder>& displayToken, size_t defaultMode,
- bool allowGroupSwitching, float primaryRefreshRateMin,
- float primaryRefreshRateMax, float appRequestRefreshRateMin,
+ status_t setDesiredDisplayModeSpecs(const sp<IBinder>& displayToken,
+ ui::DisplayModeId defaultMode, bool allowGroupSwitching,
+ float primaryRefreshRateMin, float primaryRefreshRateMax,
+ float appRequestRefreshRateMin,
float appRequestRefreshRateMax) override {
Parcel data, reply;
status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
@@ -938,7 +819,8 @@ public:
return reply.readInt32();
}
- status_t getDesiredDisplayModeSpecs(const sp<IBinder>& displayToken, size_t* outDefaultMode,
+ status_t getDesiredDisplayModeSpecs(const sp<IBinder>& displayToken,
+ ui::DisplayModeId* outDefaultMode,
bool* outAllowGroupSwitching,
float* outPrimaryRefreshRateMin,
float* outPrimaryRefreshRateMax,
@@ -966,17 +848,16 @@ public:
ALOGE("getDesiredDisplayModeSpecs failed to transact: %d", result);
return result;
}
- int32_t defaultMode;
- result = reply.readInt32(&defaultMode);
+
+ result = reply.readInt32(outDefaultMode);
if (result != NO_ERROR) {
ALOGE("getDesiredDisplayModeSpecs failed to read defaultMode: %d", result);
return result;
}
- if (defaultMode < 0) {
- ALOGE("%s: defaultMode must be non-negative but it was %d", __func__, defaultMode);
+ if (*outDefaultMode < 0) {
+ ALOGE("%s: defaultMode must be non-negative but it was %d", __func__, *outDefaultMode);
return BAD_VALUE;
}
- *outDefaultMode = static_cast<size_t>(defaultMode);
result = reply.readBool(outAllowGroupSwitching);
if (result != NO_ERROR) {
@@ -1436,28 +1317,24 @@ status_t BnSurfaceComposer::onTransact(
}
return NO_ERROR;
}
- case GET_DISPLAY_INFO: {
+ case GET_STATIC_DISPLAY_INFO: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
- DisplayInfo info;
+ ui::StaticDisplayInfo info;
const sp<IBinder> display = data.readStrongBinder();
- const status_t result = getDisplayInfo(display, &info);
- reply->writeInt32(result);
+ const status_t result = getStaticDisplayInfo(display, &info);
+ SAFE_PARCEL(reply->writeInt32, result);
if (result != NO_ERROR) return result;
- return reply->write(info);
+ SAFE_PARCEL(reply->write, info);
+ return NO_ERROR;
}
- case GET_DISPLAY_MODES: {
+ case GET_DYNAMIC_DISPLAY_INFO: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
- Vector<ui::DisplayMode> modes;
+ ui::DynamicDisplayInfo info;
const sp<IBinder> display = data.readStrongBinder();
- const status_t result = getDisplayModes(display, &modes);
- reply->writeInt32(result);
- if (result == NO_ERROR) {
- reply->writeUint32(static_cast<uint32_t>(modes.size()));
- for (size_t i = 0; i < modes.size(); i++) {
- memcpy(reply->writeInplace(sizeof(ui::DisplayMode)), &modes[i],
- sizeof(ui::DisplayMode));
- }
- }
+ const status_t result = getDynamicDisplayInfo(display, &info);
+ SAFE_PARCEL(reply->writeInt32, result);
+ if (result != NO_ERROR) return result;
+ SAFE_PARCEL(reply->write, info);
return NO_ERROR;
}
case GET_DISPLAY_STATS: {
@@ -1472,32 +1349,6 @@ status_t BnSurfaceComposer::onTransact(
}
return NO_ERROR;
}
- case GET_ACTIVE_DISPLAY_MODE: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- sp<IBinder> display = data.readStrongBinder();
- int id = getActiveDisplayModeId(display);
- reply->writeInt32(id);
- return NO_ERROR;
- }
- case GET_DISPLAY_COLOR_MODES: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- Vector<ColorMode> colorModes;
- sp<IBinder> display = nullptr;
- status_t result = data.readStrongBinder(&display);
- if (result != NO_ERROR) {
- ALOGE("getDisplayColorModes failed to readStrongBinder: %d", result);
- return result;
- }
- result = getDisplayColorModes(display, &colorModes);
- reply->writeInt32(result);
- if (result == NO_ERROR) {
- reply->writeUint32(static_cast<uint32_t>(colorModes.size()));
- for (size_t i = 0; i < colorModes.size(); ++i) {
- reply->writeInt32(static_cast<int32_t>(colorModes[i]));
- }
- }
- return NO_ERROR;
- }
case GET_DISPLAY_NATIVE_PRIMARIES: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
ui::DisplayPrimaries primaries;
@@ -1518,18 +1369,6 @@ status_t BnSurfaceComposer::onTransact(
return NO_ERROR;
}
- case GET_ACTIVE_COLOR_MODE: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- sp<IBinder> display = nullptr;
- status_t result = data.readStrongBinder(&display);
- if (result != NO_ERROR) {
- ALOGE("getActiveColorMode failed to readStrongBinder: %d", result);
- return result;
- }
- ColorMode colorMode = getActiveColorMode(display);
- result = reply->writeInt32(static_cast<int32_t>(colorMode));
- return result;
- }
case SET_ACTIVE_COLOR_MODE: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
sp<IBinder> display = nullptr;
@@ -1549,23 +1388,6 @@ status_t BnSurfaceComposer::onTransact(
result = reply->writeInt32(result);
return result;
}
-
- case GET_AUTO_LOW_LATENCY_MODE_SUPPORT: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- sp<IBinder> display = nullptr;
- status_t result = data.readStrongBinder(&display);
- if (result != NO_ERROR) {
- ALOGE("getAutoLowLatencyModeSupport failed to readStrongBinder: %d", result);
- return result;
- }
- bool supported = false;
- result = getAutoLowLatencyModeSupport(display, &supported);
- if (result == NO_ERROR) {
- result = reply->writeBool(supported);
- }
- return result;
- }
-
case SET_AUTO_LOW_LATENCY_MODE: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
sp<IBinder> display = nullptr;
@@ -1583,23 +1405,6 @@ status_t BnSurfaceComposer::onTransact(
setAutoLowLatencyMode(display, setAllm);
return result;
}
-
- case GET_GAME_CONTENT_TYPE_SUPPORT: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- sp<IBinder> display = nullptr;
- status_t result = data.readStrongBinder(&display);
- if (result != NO_ERROR) {
- ALOGE("getGameContentTypeSupport failed to readStrongBinder: %d", result);
- return result;
- }
- bool supported = false;
- result = getGameContentTypeSupport(display, &supported);
- if (result == NO_ERROR) {
- result = reply->writeBool(supported);
- }
- return result;
- }
-
case SET_GAME_CONTENT_TYPE: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
sp<IBinder> display = nullptr;
@@ -1617,7 +1422,6 @@ status_t BnSurfaceComposer::onTransact(
setGameContentType(display, setGameContentTypeOn);
return result;
}
-
case CLEAR_ANIMATION_FRAME_STATS: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
status_t result = clearAnimationFrameStats();
@@ -1639,23 +1443,6 @@ status_t BnSurfaceComposer::onTransact(
setPowerMode(display, mode);
return NO_ERROR;
}
- case GET_HDR_CAPABILITIES: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- sp<IBinder> display = nullptr;
- status_t result = data.readStrongBinder(&display);
- if (result != NO_ERROR) {
- ALOGE("getHdrCapabilities failed to readStrongBinder: %d",
- result);
- return result;
- }
- HdrCapabilities capabilities;
- result = getHdrCapabilities(display, &capabilities);
- reply->writeInt32(result);
- if (result == NO_ERROR) {
- reply->write(capabilities);
- }
- return NO_ERROR;
- }
case ENABLE_VSYNC_INJECTIONS: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
bool enable = false;
@@ -1862,7 +1649,7 @@ status_t BnSurfaceComposer::onTransact(
case SET_DESIRED_DISPLAY_MODE_SPECS: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
sp<IBinder> displayToken = data.readStrongBinder();
- int32_t defaultMode;
+ ui::DisplayModeId defaultMode;
status_t result = data.readInt32(&defaultMode);
if (result != NO_ERROR) {
ALOGE("setDesiredDisplayModeSpecs: failed to read defaultMode: %d", result);
@@ -1906,10 +1693,9 @@ status_t BnSurfaceComposer::onTransact(
result);
return result;
}
- result = setDesiredDisplayModeSpecs(displayToken, static_cast<size_t>(defaultMode),
- allowGroupSwitching, primaryRefreshRateMin,
- primaryRefreshRateMax, appRequestRefreshRateMin,
- appRequestRefreshRateMax);
+ result = setDesiredDisplayModeSpecs(displayToken, defaultMode, allowGroupSwitching,
+ primaryRefreshRateMin, primaryRefreshRateMax,
+ appRequestRefreshRateMin, appRequestRefreshRateMax);
if (result != NO_ERROR) {
ALOGE("setDesiredDisplayModeSpecs: failed to call setDesiredDisplayModeSpecs: "
"%d",
@@ -1922,7 +1708,7 @@ status_t BnSurfaceComposer::onTransact(
case GET_DESIRED_DISPLAY_MODE_SPECS: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
sp<IBinder> displayToken = data.readStrongBinder();
- size_t defaultMode;
+ ui::DisplayModeId defaultMode;
bool allowGroupSwitching;
float primaryRefreshRateMin;
float primaryRefreshRateMax;
@@ -1941,7 +1727,7 @@ status_t BnSurfaceComposer::onTransact(
return result;
}
- result = reply->writeInt32(static_cast<int32_t>(defaultMode));
+ result = reply->writeInt32(defaultMode);
if (result != NO_ERROR) {
ALOGE("getDesiredDisplayModeSpecs: failed to write defaultMode: %d", result);
return result;
diff --git a/libs/gui/LayerDebugInfo.cpp b/libs/gui/LayerDebugInfo.cpp
index cdde9a2308..e707684618 100644
--- a/libs/gui/LayerDebugInfo.cpp
+++ b/libs/gui/LayerDebugInfo.cpp
@@ -61,6 +61,7 @@ status_t LayerDebugInfo::writeToParcel(Parcel* parcel) const {
RETURN_ON_ERROR(parcel->writeBool(mRefreshPending));
RETURN_ON_ERROR(parcel->writeBool(mIsOpaque));
RETURN_ON_ERROR(parcel->writeBool(mContentDirty));
+ RETURN_ON_ERROR(parcel->write(mStretchEffect));
return NO_ERROR;
}
@@ -105,6 +106,7 @@ status_t LayerDebugInfo::readFromParcel(const Parcel* parcel) {
RETURN_ON_ERROR(parcel->readBool(&mRefreshPending));
RETURN_ON_ERROR(parcel->readBool(&mIsOpaque));
RETURN_ON_ERROR(parcel->readBool(&mContentDirty));
+ RETURN_ON_ERROR(parcel->read(mStretchEffect));
return NO_ERROR;
}
@@ -115,6 +117,12 @@ std::string to_string(const LayerDebugInfo& info) {
info.mTransparentRegion.dump(result, "TransparentRegion");
info.mVisibleRegion.dump(result, "VisibleRegion");
info.mSurfaceDamageRegion.dump(result, "SurfaceDamageRegion");
+ if (info.mStretchEffect.hasEffect()) {
+ const auto& se = info.mStretchEffect;
+ StringAppendF(&result, " StretchEffect area=[%f, %f, %f, %f] vec=(%f, %f) maxAmount=%f\n",
+ se.area.left, se.area.top, se.area.right, se.area.bottom, se.vectorX,
+ se.vectorY, se.maxAmount);
+ }
StringAppendF(&result, " layerStack=%4d, z=%9d, pos=(%g,%g), size=(%4d,%4d), ",
info.mLayerStack, info.mZ, static_cast<double>(info.mX),
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index fff33056e1..288bf92c15 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -167,6 +167,9 @@ status_t layer_state_t::write(Parcel& output) const
SAFE_PARCEL(output.writeInt32, region.right);
SAFE_PARCEL(output.writeInt32, region.bottom);
}
+
+ SAFE_PARCEL(output.write, stretchEffect);
+
return NO_ERROR;
}
@@ -290,6 +293,9 @@ status_t layer_state_t::read(const Parcel& input)
SAFE_PARCEL(input.readInt32, &region.bottom);
blurRegions.push_back(region);
}
+
+ SAFE_PARCEL(input.read, stretchEffect);
+
return NO_ERROR;
}
@@ -542,6 +548,10 @@ void layer_state_t::merge(const layer_state_t& other) {
what |= eAutoRefreshChanged;
autoRefresh = other.autoRefresh;
}
+ if (other.what & eStretchChanged) {
+ what |= eStretchChanged;
+ stretchEffect = other.stretchEffect;
+ }
if ((other.what & what) != other.what) {
ALOGE("Unmerged SurfaceComposer Transaction properties. LayerState::merge needs updating? "
"other.what=0x%" PRIu64 " what=0x%" PRIu64,
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 07fc0694d6..6de3e971b2 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -34,9 +34,9 @@
#include <utils/NativeHandle.h>
#include <ui/DisplayStatInfo.h>
+#include <ui/DynamicDisplayInfo.h>
#include <ui/Fence.h>
#include <ui/GraphicBuffer.h>
-#include <ui/HdrCapabilities.h>
#include <ui/Region.h>
#include <gui/BufferItem.h>
@@ -48,7 +48,6 @@
namespace android {
-using ui::ColorMode;
using ui::Dataspace;
namespace {
@@ -361,15 +360,12 @@ status_t Surface::getHdrSupport(bool* supported) {
return NAME_NOT_FOUND;
}
- HdrCapabilities hdrCapabilities;
- status_t err =
- composerService()->getHdrCapabilities(display, &hdrCapabilities);
-
- if (err)
+ ui::DynamicDisplayInfo info;
+ if (status_t err = composerService()->getDynamicDisplayInfo(display, &info); err != NO_ERROR) {
return err;
+ }
- *supported = !hdrCapabilities.getSupportedHdrTypes().empty();
-
+ *supported = !info.hdrCapabilities.getSupportedHdrTypes().empty();
return NO_ERROR;
}
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 4493a21fc3..0317b2bd2b 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -40,6 +40,7 @@
#include <gui/Surface.h>
#include <gui/SurfaceComposerClient.h>
#include <ui/DisplayMode.h>
+#include <ui/DynamicDisplayInfo.h>
#ifndef NO_INPUT
#include <input/InputWindow.h>
@@ -194,6 +195,25 @@ void TransactionCompletedListener::removeJankListener(const sp<JankDataListener>
}
}
+void TransactionCompletedListener::addSurfaceStatsListener(void* context, void* cookie,
+ sp<SurfaceControl> surfaceControl, SurfaceStatsCallback listener) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ mSurfaceStatsListeners.insert({surfaceControl->getHandle(),
+ SurfaceStatsCallbackEntry(context, cookie, listener)});
+}
+
+void TransactionCompletedListener::removeSurfaceStatsListener(void* context, void* cookie) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ for (auto it = mSurfaceStatsListeners.begin(); it != mSurfaceStatsListeners.end();) {
+ auto [itContext, itCookie, itListener] = it->second;
+ if (itContext == context && itCookie == cookie) {
+ it = mSurfaceStatsListeners.erase(it);
+ } else {
+ it++;
+ }
+ }
+}
+
void TransactionCompletedListener::addSurfaceControlToCallbacks(
const sp<SurfaceControl>& surfaceControl,
const std::unordered_set<CallbackId>& callbackIds) {
@@ -210,6 +230,7 @@ void TransactionCompletedListener::addSurfaceControlToCallbacks(
void TransactionCompletedListener::onTransactionCompleted(ListenerStats listenerStats) {
std::unordered_map<CallbackId, CallbackTranslation> callbacksMap;
std::multimap<sp<IBinder>, sp<JankDataListener>> jankListenersMap;
+ std::multimap<sp<IBinder>, SurfaceStatsCallbackEntry> surfaceListeners;
{
std::lock_guard<std::mutex> lock(mMutex);
@@ -226,6 +247,7 @@ void TransactionCompletedListener::onTransactionCompleted(ListenerStats listener
*/
callbacksMap = mCallbacks;
jankListenersMap = mJankListeners;
+ surfaceListeners = mSurfaceStatsListeners;
for (const auto& transactionStats : listenerStats.transactionStats) {
for (auto& callbackId : transactionStats.callbackIds) {
mCallbacks.erase(callbackId);
@@ -259,9 +281,16 @@ void TransactionCompletedListener::onTransactionCompleted(ListenerStats listener
surfaceControlStats);
}
for (const auto& surfaceStats : transactionStats.surfaceStats) {
+ auto listenerRange = surfaceListeners.equal_range(surfaceStats.surfaceControl);
+ for (auto it = listenerRange.first; it != listenerRange.second; it++) {
+ auto entry = it->second;
+ entry.callback(entry.context, transactionStats.latchTime,
+ transactionStats.presentFence, surfaceStats);
+ }
+
if (surfaceStats.jankData.empty()) continue;
- for (auto it = jankListenersMap.find(surfaceStats.surfaceControl);
- it != jankListenersMap.end(); it++) {
+ auto jankRange = jankListenersMap.equal_range(surfaceStats.surfaceControl);
+ for (auto it = jankRange.first; it != jankRange.second; it++) {
it->second->onJankDataAvailable(surfaceStats.jankData);
}
}
@@ -1569,6 +1598,23 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setApply
return *this;
}
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setStretchEffect(
+ const sp<SurfaceControl>& sc, float left, float top, float right, float bottom, float vecX,
+ float vecY, float maxAmount) {
+ layer_state_t* s = getLayerState(sc);
+ if (!s) {
+ mStatus = BAD_INDEX;
+ return *this;
+ }
+
+ s->what |= layer_state_t::eStretchChanged;
+ s->stretchEffect = StretchEffect{.area = {left, top, right, bottom},
+ .vectorX = vecX,
+ .vectorY = vecY,
+ .maxAmount = maxAmount};
+ return *this;
+}
+
// ---------------------------------------------------------------------------
DisplayState& SurfaceComposerClient::Transaction::getDisplayState(const sp<IBinder>& token) {
@@ -1798,39 +1844,35 @@ status_t SurfaceComposerClient::getDisplayState(const sp<IBinder>& display,
return ComposerService::getComposerService()->getDisplayState(display, state);
}
-status_t SurfaceComposerClient::getDisplayInfo(const sp<IBinder>& display, DisplayInfo* info) {
- return ComposerService::getComposerService()->getDisplayInfo(display, info);
+status_t SurfaceComposerClient::getStaticDisplayInfo(const sp<IBinder>& display,
+ ui::StaticDisplayInfo* info) {
+ return ComposerService::getComposerService()->getStaticDisplayInfo(display, info);
}
-status_t SurfaceComposerClient::getDisplayModes(const sp<IBinder>& display,
- Vector<ui::DisplayMode>* modes) {
- return ComposerService::getComposerService()->getDisplayModes(display, modes);
+status_t SurfaceComposerClient::getDynamicDisplayInfo(const sp<IBinder>& display,
+ ui::DynamicDisplayInfo* info) {
+ return ComposerService::getComposerService()->getDynamicDisplayInfo(display, info);
}
status_t SurfaceComposerClient::getActiveDisplayMode(const sp<IBinder>& display,
ui::DisplayMode* mode) {
- Vector<ui::DisplayMode> modes;
- status_t result = getDisplayModes(display, &modes);
+ ui::DynamicDisplayInfo info;
+ status_t result = getDynamicDisplayInfo(display, &info);
if (result != NO_ERROR) {
return result;
}
- int activeId = getActiveDisplayModeId(display);
- if (activeId < 0) {
- ALOGE("No active mode found");
- return NAME_NOT_FOUND;
+ if (const auto activeMode = info.getActiveDisplayMode()) {
+ *mode = *activeMode;
+ return NO_ERROR;
}
- *mode = modes[static_cast<size_t>(activeId)];
- return NO_ERROR;
-}
-
-int SurfaceComposerClient::getActiveDisplayModeId(const sp<IBinder>& display) {
- return ComposerService::getComposerService()->getActiveDisplayModeId(display);
+ ALOGE("Active display mode not found.");
+ return NAME_NOT_FOUND;
}
status_t SurfaceComposerClient::setDesiredDisplayModeSpecs(
- const sp<IBinder>& displayToken, size_t defaultMode, bool allowGroupSwitching,
+ const sp<IBinder>& displayToken, ui::DisplayModeId defaultMode, bool allowGroupSwitching,
float primaryRefreshRateMin, float primaryRefreshRateMax, float appRequestRefreshRateMin,
float appRequestRefreshRateMax) {
return ComposerService::getComposerService()
@@ -1839,51 +1881,33 @@ status_t SurfaceComposerClient::setDesiredDisplayModeSpecs(
appRequestRefreshRateMin, appRequestRefreshRateMax);
}
-status_t SurfaceComposerClient::getDesiredDisplayModeSpecs(
- const sp<IBinder>& displayToken, size_t* outDefaultMode, bool* outAllowGroupSwitching,
- float* outPrimaryRefreshRateMin, float* outPrimaryRefreshRateMax,
- float* outAppRequestRefreshRateMin, float* outAppRequestRefreshRateMax) {
+status_t SurfaceComposerClient::getDesiredDisplayModeSpecs(const sp<IBinder>& displayToken,
+ ui::DisplayModeId* outDefaultMode,
+ bool* outAllowGroupSwitching,
+ float* outPrimaryRefreshRateMin,
+ float* outPrimaryRefreshRateMax,
+ float* outAppRequestRefreshRateMin,
+ float* outAppRequestRefreshRateMax) {
return ComposerService::getComposerService()
->getDesiredDisplayModeSpecs(displayToken, outDefaultMode, outAllowGroupSwitching,
outPrimaryRefreshRateMin, outPrimaryRefreshRateMax,
outAppRequestRefreshRateMin, outAppRequestRefreshRateMax);
}
-status_t SurfaceComposerClient::getDisplayColorModes(const sp<IBinder>& display,
- Vector<ColorMode>* outColorModes) {
- return ComposerService::getComposerService()->getDisplayColorModes(display, outColorModes);
-}
-
status_t SurfaceComposerClient::getDisplayNativePrimaries(const sp<IBinder>& display,
ui::DisplayPrimaries& outPrimaries) {
return ComposerService::getComposerService()->getDisplayNativePrimaries(display, outPrimaries);
}
-ColorMode SurfaceComposerClient::getActiveColorMode(const sp<IBinder>& display) {
- return ComposerService::getComposerService()->getActiveColorMode(display);
-}
-
status_t SurfaceComposerClient::setActiveColorMode(const sp<IBinder>& display,
ColorMode colorMode) {
return ComposerService::getComposerService()->setActiveColorMode(display, colorMode);
}
-bool SurfaceComposerClient::getAutoLowLatencyModeSupport(const sp<IBinder>& display) {
- bool supported = false;
- ComposerService::getComposerService()->getAutoLowLatencyModeSupport(display, &supported);
- return supported;
-}
-
void SurfaceComposerClient::setAutoLowLatencyMode(const sp<IBinder>& display, bool on) {
ComposerService::getComposerService()->setAutoLowLatencyMode(display, on);
}
-bool SurfaceComposerClient::getGameContentTypeSupport(const sp<IBinder>& display) {
- bool supported = false;
- ComposerService::getComposerService()->getGameContentTypeSupport(display, &supported);
- return supported;
-}
-
void SurfaceComposerClient::setGameContentType(const sp<IBinder>& display, bool on) {
ComposerService::getComposerService()->setGameContentType(display, on);
}
@@ -1915,12 +1939,6 @@ status_t SurfaceComposerClient::getAnimationFrameStats(FrameStats* outStats) {
return ComposerService::getComposerService()->getAnimationFrameStats(outStats);
}
-status_t SurfaceComposerClient::getHdrCapabilities(const sp<IBinder>& display,
- HdrCapabilities* outCapabilities) {
- return ComposerService::getComposerService()->getHdrCapabilities(display,
- outCapabilities);
-}
-
status_t SurfaceComposerClient::getDisplayedContentSamplingAttributes(const sp<IBinder>& display,
ui::PixelFormat* outFormat,
ui::Dataspace* outDataspace,
diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp
index e842382ded..1dcfe2e804 100644
--- a/libs/gui/SurfaceControl.cpp
+++ b/libs/gui/SurfaceControl.cpp
@@ -30,9 +30,9 @@
#include <binder/IPCThreadState.h>
-#include <ui/DisplayInfo.h>
#include <ui/GraphicBuffer.h>
#include <ui/Rect.h>
+#include <ui/StaticDisplayInfo.h>
#include <gui/BufferQueueCore.h>
#include <gui/ISurfaceComposer.h>
diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h
index bccb71b362..dd8e714e23 100644
--- a/libs/gui/include/gui/BLASTBufferQueue.h
+++ b/libs/gui/include/gui/BLASTBufferQueue.h
@@ -32,6 +32,7 @@
namespace android {
+class BLASTBufferQueue;
class BufferItemConsumer;
class BLASTBufferItemConsumer : public BufferItemConsumer {
@@ -40,27 +41,32 @@ public:
int bufferCount, bool controlledByApp)
: BufferItemConsumer(consumer, consumerUsage, bufferCount, controlledByApp),
mCurrentlyConnected(false),
- mPreviouslyConnected(false) {}
+ mPreviouslyConnected(false),
+ mBLASTBufferQueue(nullptr) {}
void onDisconnect() override;
void addAndGetFrameTimestamps(const NewFrameEventsEntry* newTimestamps,
- FrameEventHistoryDelta* outDelta) override
- REQUIRES(mFrameEventHistoryMutex);
+ FrameEventHistoryDelta* outDelta) override REQUIRES(mMutex);
void updateFrameTimestamps(uint64_t frameNumber, nsecs_t refreshStartTime,
const sp<Fence>& gpuCompositionDoneFence,
const sp<Fence>& presentFence, const sp<Fence>& prevReleaseFence,
CompositorTiming compositorTiming, nsecs_t latchTime,
- nsecs_t dequeueReadyTime) REQUIRES(mFrameEventHistoryMutex);
+ nsecs_t dequeueReadyTime) REQUIRES(mMutex);
void getConnectionEvents(uint64_t frameNumber, bool* needsDisconnect);
+ void setBlastBufferQueue(BLASTBufferQueue* blastbufferqueue) REQUIRES(mMutex);
+
+protected:
+ void onSidebandStreamChanged() override REQUIRES(mMutex);
private:
uint64_t mCurrentFrameNumber = 0;
- Mutex mFrameEventHistoryMutex;
- ConsumerFrameEventHistory mFrameEventHistory GUARDED_BY(mFrameEventHistoryMutex);
- std::queue<uint64_t> mDisconnectEvents GUARDED_BY(mFrameEventHistoryMutex);
- bool mCurrentlyConnected GUARDED_BY(mFrameEventHistoryMutex);
- bool mPreviouslyConnected GUARDED_BY(mFrameEventHistoryMutex);
+ Mutex mMutex;
+ ConsumerFrameEventHistory mFrameEventHistory GUARDED_BY(mMutex);
+ std::queue<uint64_t> mDisconnectEvents GUARDED_BY(mMutex);
+ bool mCurrentlyConnected GUARDED_BY(mMutex);
+ bool mPreviouslyConnected GUARDED_BY(mMutex);
+ BLASTBufferQueue* mBLASTBufferQueue GUARDED_BY(mMutex);
};
class BLASTBufferQueue
@@ -94,6 +100,8 @@ public:
status_t setFrameRate(float frameRate, int8_t compatibility, bool shouldBeSeamless);
status_t setFrameTimelineInfo(const FrameTimelineInfo& info);
+ void setSidebandStream(const sp<NativeHandle>& stream);
+
virtual ~BLASTBufferQueue();
private:
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index 292838e9ae..6289e5a5d0 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -33,6 +33,7 @@
#include <ui/ConfigStoreTypes.h>
#include <ui/DisplayId.h>
+#include <ui/DisplayMode.h>
#include <ui/DisplayedFrameStats.h>
#include <ui/FrameStats.h>
#include <ui/GraphicBuffer.h>
@@ -54,7 +55,6 @@ namespace android {
struct client_cache_t;
struct ComposerState;
struct DisplayCaptureArgs;
-struct DisplayInfo;
struct DisplayStatInfo;
struct DisplayState;
struct InputWindowCommands;
@@ -74,6 +74,8 @@ namespace ui {
struct DisplayMode;
struct DisplayState;
+struct DynamicDisplayInfo;
+struct StaticDisplayInfo;
} // namespace ui
@@ -202,56 +204,32 @@ public:
virtual status_t getDisplayState(const sp<IBinder>& display, ui::DisplayState*) = 0;
/**
- * Get immutable information about given physical display.
+ * Gets immutable information about given physical display.
*/
- virtual status_t getDisplayInfo(const sp<IBinder>& display, DisplayInfo*) = 0;
+ virtual status_t getStaticDisplayInfo(const sp<IBinder>& display, ui::StaticDisplayInfo*) = 0;
/**
- * Get modes supported by given physical display.
+ * Gets dynamic information about given physical display.
*/
- virtual status_t getDisplayModes(const sp<IBinder>& display, Vector<ui::DisplayMode>*) = 0;
+ virtual status_t getDynamicDisplayInfo(const sp<IBinder>& display, ui::DynamicDisplayInfo*) = 0;
- /**
- * Get the index into modes returned by getDisplayModes,
- * corresponding to the active mode.
- */
- virtual int getActiveDisplayModeId(const sp<IBinder>& display) = 0;
-
- virtual status_t getDisplayColorModes(const sp<IBinder>& display,
- Vector<ui::ColorMode>* outColorModes) = 0;
virtual status_t getDisplayNativePrimaries(const sp<IBinder>& display,
ui::DisplayPrimaries& primaries) = 0;
- virtual ui::ColorMode getActiveColorMode(const sp<IBinder>& display) = 0;
virtual status_t setActiveColorMode(const sp<IBinder>& display,
ui::ColorMode colorMode) = 0;
/**
- * Returns true if the connected display reports support for HDMI 2.1 Auto
- * Low Latency Mode.
- * For more information, see the HDMI 2.1 specification.
- */
- virtual status_t getAutoLowLatencyModeSupport(const sp<IBinder>& display,
- bool* outSupport) const = 0;
-
- /**
* Switches Auto Low Latency Mode on/off on the connected display, if it is
- * available. This should only be called if #getAutoLowLatencyMode returns
- * true.
+ * available. This should only be called if the display supports Auto Low
+ * Latency Mode as reported in #getDynamicDisplayInfo.
* For more information, see the HDMI 2.1 specification.
*/
virtual void setAutoLowLatencyMode(const sp<IBinder>& display, bool on) = 0;
/**
- * Returns true if the connected display reports support for Game Content Type.
- * For more information, see the HDMI 1.4 specification.
- */
- virtual status_t getGameContentTypeSupport(const sp<IBinder>& display,
- bool* outSupport) const = 0;
-
- /**
* This will start sending infoframes to the connected display with
- * ContentType=Game (if on=true). This will switch the disply to Game mode.
- * This should only be called if #getGameContentTypeSupport returns true.
+ * ContentType=Game (if on=true). This should only be called if the display
+ * Game Content Type as reported in #getDynamicDisplayInfo.
* For more information, see the HDMI 1.4 specification.
*/
virtual void setGameContentType(const sp<IBinder>& display, bool on) = 0;
@@ -296,13 +274,6 @@ public:
*/
virtual status_t getAnimationFrameStats(FrameStats* outStats) const = 0;
- /* Gets the supported HDR capabilities of the given display.
- *
- * Requires the ACCESS_SURFACE_FLINGER permission.
- */
- virtual status_t getHdrCapabilities(const sp<IBinder>& display,
- HdrCapabilities* outCapabilities) const = 0;
-
virtual status_t enableVSyncInjections(bool enable) = 0;
virtual status_t injectVSync(nsecs_t when) = 0;
@@ -397,20 +368,21 @@ public:
*
* defaultMode is used to narrow the list of display modes SurfaceFlinger will consider
* switching between. Only modes with a mode group and resolution matching defaultMode
- * will be considered for switching. The defaultMode index corresponds to the list of modes
- * returned from getDisplayModes().
- */
- virtual status_t setDesiredDisplayModeSpecs(const sp<IBinder>& displayToken, size_t defaultMode,
- bool allowGroupSwitching,
- float primaryRefreshRateMin,
- float primaryRefreshRateMax,
- float appRequestRefreshRateMin,
- float appRequestRefreshRateMax) = 0;
-
- virtual status_t getDesiredDisplayModeSpecs(
- const sp<IBinder>& displayToken, size_t* outDefaultMode, bool* outAllowGroupSwitching,
- float* outPrimaryRefreshRateMin, float* outPrimaryRefreshRateMax,
- float* outAppRequestRefreshRateMin, float* outAppRequestRefreshRateMax) = 0;
+ * will be considered for switching. The defaultMode corresponds to an ID of mode in the list
+ * of supported modes returned from getDynamicDisplayInfo().
+ */
+ virtual status_t setDesiredDisplayModeSpecs(
+ const sp<IBinder>& displayToken, ui::DisplayModeId defaultMode,
+ bool allowGroupSwitching, float primaryRefreshRateMin, float primaryRefreshRateMax,
+ float appRequestRefreshRateMin, float appRequestRefreshRateMax) = 0;
+
+ virtual status_t getDesiredDisplayModeSpecs(const sp<IBinder>& displayToken,
+ ui::DisplayModeId* outDefaultMode,
+ bool* outAllowGroupSwitching,
+ float* outPrimaryRefreshRateMin,
+ float* outPrimaryRefreshRateMax,
+ float* outAppRequestRefreshRateMin,
+ float* outAppRequestRefreshRateMax) = 0;
/*
* Gets whether brightness operations are supported on a display.
*
@@ -534,7 +506,7 @@ public:
// Java by ActivityManagerService.
BOOT_FINISHED = IBinder::FIRST_CALL_TRANSACTION,
CREATE_CONNECTION,
- GET_DISPLAY_INFO,
+ GET_STATIC_DISPLAY_INFO,
CREATE_DISPLAY_EVENT_CONNECTION,
CREATE_DISPLAY,
DESTROY_DISPLAY,
@@ -542,8 +514,8 @@ public:
SET_TRANSACTION_STATE,
AUTHENTICATE_SURFACE,
GET_SUPPORTED_FRAME_TIMESTAMPS,
- GET_DISPLAY_MODES,
- GET_ACTIVE_DISPLAY_MODE,
+ GET_DISPLAY_MODES, // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead.
+ GET_ACTIVE_DISPLAY_MODE, // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead.
GET_DISPLAY_STATE,
CAPTURE_DISPLAY,
CAPTURE_LAYERS,
@@ -551,9 +523,9 @@ public:
GET_ANIMATION_FRAME_STATS,
SET_POWER_MODE,
GET_DISPLAY_STATS,
- GET_HDR_CAPABILITIES,
- GET_DISPLAY_COLOR_MODES,
- GET_ACTIVE_COLOR_MODE,
+ GET_HDR_CAPABILITIES, // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead.
+ GET_DISPLAY_COLOR_MODES, // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead.
+ GET_ACTIVE_COLOR_MODE, // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead.
SET_ACTIVE_COLOR_MODE,
ENABLE_VSYNC_INJECTIONS,
INJECT_VSYNC,
@@ -576,9 +548,9 @@ public:
CAPTURE_DISPLAY_BY_ID,
NOTIFY_POWER_BOOST,
SET_GLOBAL_SHADOW_SETTINGS,
- GET_AUTO_LOW_LATENCY_MODE_SUPPORT,
+ GET_AUTO_LOW_LATENCY_MODE_SUPPORT, // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead.
SET_AUTO_LOW_LATENCY_MODE,
- GET_GAME_CONTENT_TYPE_SUPPORT,
+ GET_GAME_CONTENT_TYPE_SUPPORT, // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead.
SET_GAME_CONTENT_TYPE,
SET_FRAME_RATE,
ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN,
@@ -586,6 +558,7 @@ public:
ADD_TRANSACTION_TRACE_LISTENER,
GET_GPU_CONTEXT_PRIORITY,
GET_EXTRA_BUFFER_COUNT,
+ GET_DYNAMIC_DISPLAY_INFO,
// Always append new enum to the end.
};
diff --git a/libs/gui/include/gui/LayerDebugInfo.h b/libs/gui/include/gui/LayerDebugInfo.h
index 66a7b4dc06..8b7d32c0a5 100644
--- a/libs/gui/include/gui/LayerDebugInfo.h
+++ b/libs/gui/include/gui/LayerDebugInfo.h
@@ -20,6 +20,7 @@
#include <ui/PixelFormat.h>
#include <ui/Region.h>
+#include <ui/StretchEffect.h>
#include <string>
#include <math/vec4.h>
@@ -66,6 +67,7 @@ public:
bool mRefreshPending = false;
bool mIsOpaque = false;
bool mContentDirty = false;
+ StretchEffect mStretchEffect = {};
};
std::string to_string(const LayerDebugInfo& info);
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index 2f9a0c01eb..b273805e25 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -56,6 +56,7 @@
#include <ui/Rect.h>
#include <ui/Region.h>
#include <ui/Rotation.h>
+#include <ui/StretchEffect.h>
#include <ui/Transform.h>
#include <utils/Errors.h>
@@ -135,6 +136,7 @@ struct layer_state_t {
eFrameTimelineInfoChanged = 0x800'00000000,
eBlurRegionsChanged = 0x1000'00000000,
eAutoRefreshChanged = 0x2000'00000000,
+ eStretchChanged = 0x4000'00000000,
};
layer_state_t();
@@ -244,6 +246,9 @@ struct layer_state_t {
// can and not wait for a frame to become available. This is only relevant
// in shared buffer mode.
bool autoRefresh;
+
+ // Stretch effect to be applied to this layer
+ StretchEffect stretchEffect;
};
struct ComposerState {
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index bd9f066f96..64c8af50bd 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -80,6 +80,10 @@ using TransactionCompletedCallbackTakesContext =
using TransactionCompletedCallback =
std::function<void(nsecs_t /*latchTime*/, const sp<Fence>& /*presentFence*/,
const std::vector<SurfaceControlStats>& /*stats*/)>;
+using SurfaceStatsCallback =
+ std::function<void(void* /*context*/, nsecs_t /*latchTime*/,
+ const sp<Fence>& /*presentFence*/,
+ const SurfaceStats& /*stats*/)>;
// ---------------------------------------------------------------------------
@@ -108,58 +112,42 @@ public:
static status_t getDisplayState(const sp<IBinder>& display, ui::DisplayState*);
// Get immutable information about given physical display.
- static status_t getDisplayInfo(const sp<IBinder>& display, DisplayInfo*);
+ static status_t getStaticDisplayInfo(const sp<IBinder>& display, ui::StaticDisplayInfo*);
- // Get modes supported by given physical display.
- static status_t getDisplayModes(const sp<IBinder>& display, Vector<ui::DisplayMode>*);
+ // Get dynamic information about given physical display.
+ static status_t getDynamicDisplayInfo(const sp<IBinder>& display, ui::DynamicDisplayInfo*);
- // Get the ID of the active DisplayMode, as getDisplayModes index.
- static int getActiveDisplayModeId(const sp<IBinder>& display);
-
- // Shorthand for getDisplayModes element at getActiveDisplayModeId index.
+ // Shorthand for the active display mode from getDynamicDisplayInfo().
+ // TODO(b/180391891): Update clients to use getDynamicDisplayInfo and remove this function.
static status_t getActiveDisplayMode(const sp<IBinder>& display, ui::DisplayMode*);
// Sets the refresh rate boundaries for the display.
- static status_t setDesiredDisplayModeSpecs(const sp<IBinder>& displayToken, size_t defaultMode,
- bool allowGroupSwitching,
- float primaryRefreshRateMin,
- float primaryRefreshRateMax,
- float appRequestRefreshRateMin,
- float appRequestRefreshRateMax);
+ static status_t setDesiredDisplayModeSpecs(
+ const sp<IBinder>& displayToken, ui::DisplayModeId defaultMode,
+ bool allowGroupSwitching, float primaryRefreshRateMin, float primaryRefreshRateMax,
+ float appRequestRefreshRateMin, float appRequestRefreshRateMax);
// Gets the refresh rate boundaries for the display.
static status_t getDesiredDisplayModeSpecs(const sp<IBinder>& displayToken,
- size_t* outDefaultMode, bool* outAllowGroupSwitching,
+ ui::DisplayModeId* outDefaultMode,
+ bool* outAllowGroupSwitching,
float* outPrimaryRefreshRateMin,
float* outPrimaryRefreshRateMax,
float* outAppRequestRefreshRateMin,
float* outAppRequestRefreshRateMax);
- // Gets the list of supported color modes for the given display
- static status_t getDisplayColorModes(const sp<IBinder>& display,
- Vector<ui::ColorMode>* outColorModes);
-
// Get the coordinates of the display's native color primaries
static status_t getDisplayNativePrimaries(const sp<IBinder>& display,
ui::DisplayPrimaries& outPrimaries);
- // Gets the active color mode for the given display
- static ui::ColorMode getActiveColorMode(const sp<IBinder>& display);
-
// Sets the active color mode for the given display
static status_t setActiveColorMode(const sp<IBinder>& display,
ui::ColorMode colorMode);
- // Reports whether the connected display supports Auto Low Latency Mode
- static bool getAutoLowLatencyModeSupport(const sp<IBinder>& display);
-
// Switches on/off Auto Low Latency Mode on the connected display. This should only be
// called if the connected display supports Auto Low Latency Mode as reported by
// #getAutoLowLatencyModeSupport
static void setAutoLowLatencyMode(const sp<IBinder>& display, bool on);
- // Reports whether the connected display supports Game content type
- static bool getGameContentTypeSupport(const sp<IBinder>& display);
-
// Turns Game mode on/off on the connected display. This should only be called
// if the display supports Game content type, as reported by #getGameContentTypeSupport
static void setGameContentType(const sp<IBinder>& display, bool on);
@@ -550,6 +538,10 @@ public:
// transactions from blocking each other.
Transaction& setApplyToken(const sp<IBinder>& token);
+ Transaction& setStretchEffect(const sp<SurfaceControl>& sc, float left, float top,
+ float right, float bottom, float vecX, float vecY,
+ float maxAmount);
+
status_t setDisplaySurface(const sp<IBinder>& token,
const sp<IGraphicBufferProducer>& bufferProducer);
@@ -579,9 +571,6 @@ public:
static status_t clearAnimationFrameStats();
static status_t getAnimationFrameStats(FrameStats* outStats);
- static status_t getHdrCapabilities(const sp<IBinder>& display,
- HdrCapabilities* outCapabilities);
-
static void setDisplayProjection(const sp<IBinder>& token, ui::Rotation orientation,
const Rect& layerStackRect, const Rect& displayRect);
@@ -646,8 +635,21 @@ class TransactionCompletedListener : public BnTransactionCompletedListener {
surfaceControls;
};
+ struct SurfaceStatsCallbackEntry {
+ SurfaceStatsCallbackEntry(void* context, void* cookie, SurfaceStatsCallback callback)
+ : context(context),
+ cookie(cookie),
+ callback(callback) {}
+
+ void* context;
+ void* cookie;
+ SurfaceStatsCallback callback;
+ };
+
std::unordered_map<CallbackId, CallbackTranslation> mCallbacks GUARDED_BY(mMutex);
std::multimap<sp<IBinder>, sp<JankDataListener>> mJankListeners GUARDED_BY(mMutex);
+ std::multimap<sp<IBinder>, SurfaceStatsCallbackEntry>
+ mSurfaceStatsListeners GUARDED_BY(mMutex);
public:
static sp<TransactionCompletedListener> getInstance();
@@ -675,6 +677,10 @@ public:
*/
void removeJankListener(const sp<JankDataListener>& listener);
+ void addSurfaceStatsListener(void* context, void* cookie, sp<SurfaceControl> surfaceControl,
+ SurfaceStatsCallback listener);
+ void removeSurfaceStatsListener(void* context, void* cookie);
+
// Overrides BnTransactionCompletedListener's onTransactionCompleted
void onTransactionCompleted(ListenerStats stats) override;
};
diff --git a/libs/gui/sysprop/Android.bp b/libs/gui/sysprop/Android.bp
index 64b1eacaa2..bddb0ac5ee 100644
--- a/libs/gui/sysprop/Android.bp
+++ b/libs/gui/sysprop/Android.bp
@@ -1,3 +1,12 @@
+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: "LibGuiProperties",
srcs: ["*.sysprop"],
diff --git a/libs/gui/tests/Android.bp b/libs/gui/tests/Android.bp
index 53c13c8859..c801c6243a 100644
--- a/libs/gui/tests/Android.bp
+++ b/libs/gui/tests/Android.bp
@@ -2,6 +2,15 @@
// Build the binary to $(TARGET_OUT_DATA_NATIVE_TESTS)/$(LOCAL_MODULE)
// to integrate with auto-test framework.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_test {
name: "libgui_test",
test_suites: ["device-tests"],
diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp
index 5447b7659b..fb07a198ec 100644
--- a/libs/gui/tests/BLASTBufferQueue_test.cpp
+++ b/libs/gui/tests/BLASTBufferQueue_test.cpp
@@ -129,7 +129,11 @@ protected:
}
void setUpProducer(BLASTBufferQueueHelper adapter, sp<IGraphicBufferProducer>& producer) {
- auto igbProducer = adapter.getIGraphicBufferProducer();
+ producer = adapter.getIGraphicBufferProducer();
+ setUpProducer(producer);
+ }
+
+ void setUpProducer(sp<IGraphicBufferProducer>& igbProducer) {
ASSERT_NE(nullptr, igbProducer.get());
ASSERT_EQ(NO_ERROR, igbProducer->setMaxDequeuedBufferCount(2));
IGraphicBufferProducer::QueueBufferOutput qbOutput;
@@ -137,7 +141,6 @@ protected:
igbProducer->connect(new StubProducerListener, NATIVE_WINDOW_API_CPU, false,
&qbOutput));
ASSERT_NE(ui::Transform::ROT_INVALID, qbOutput.transformHint);
- producer = igbProducer;
}
void fillBuffer(uint32_t* bufData, Rect rect, uint32_t stride, uint8_t r, uint8_t g,
@@ -555,6 +558,8 @@ TEST_F(BLASTBufferQueueTest, QueryNativeWindowQueuesToWindowComposer) {
ASSERT_EQ(queuesToNativeWindow, 1);
}
+// Test a slow producer doesn't hold up a faster producer from the same client. Essentially tests
+// BBQ uses separate transaction queues.
TEST_F(BLASTBufferQueueTest, OutOfOrderTransactionTest) {
sp<SurfaceControl> bgSurface =
mClient->createSurface(String8("BGTest"), 0, 0, PIXEL_FORMAT_RGBA_8888,
@@ -781,7 +786,7 @@ public:
void setUpAndQueueBuffer(const sp<IGraphicBufferProducer>& igbProducer,
nsecs_t* requestedPresentTime, nsecs_t* postedTime,
IGraphicBufferProducer::QueueBufferOutput* qbOutput,
- bool getFrameTimestamps) {
+ bool getFrameTimestamps, nsecs_t requestedPresentTimeDelay = 0) {
int slot;
sp<Fence> fence;
sp<GraphicBuffer> buf;
@@ -791,7 +796,7 @@ public:
ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, ret);
ASSERT_EQ(OK, igbProducer->requestBuffer(slot, &buf));
- nsecs_t requestedTime = systemTime();
+ nsecs_t requestedTime = systemTime() + requestedPresentTimeDelay;
if (requestedPresentTime) *requestedPresentTime = requestedTime;
IGraphicBufferProducer::QueueBufferInput input(requestedTime, false, HAL_DATASPACE_UNKNOWN,
Rect(mDisplayWidth, mDisplayHeight),
@@ -801,6 +806,27 @@ public:
if (postedTime) *postedTime = systemTime();
igbProducer->queueBuffer(slot, input, qbOutput);
}
+
+ void createBufferQueueProducer(sp<IGraphicBufferProducer>* bqIgbp) {
+ mBufferQueueSurfaceControl =
+ mClient->createSurface(String8("BqSurface"), 0, 0, PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eFXSurfaceBufferQueue);
+ ASSERT_NE(nullptr, mBufferQueueSurfaceControl.get());
+ Transaction()
+ .setLayerStack(mBufferQueueSurfaceControl, 0)
+ .show(mBufferQueueSurfaceControl)
+ .setDataspace(mBufferQueueSurfaceControl, ui::Dataspace::V0_SRGB)
+ .setSize(mBufferQueueSurfaceControl, mDisplayWidth, mDisplayHeight)
+ .setLayer(mBufferQueueSurfaceControl, std::numeric_limits<int32_t>::max())
+ .apply();
+
+ sp<Surface> bqSurface = mBufferQueueSurfaceControl->getSurface();
+ ASSERT_NE(nullptr, bqSurface.get());
+
+ *bqIgbp = bqSurface->getIGraphicBufferProducer();
+ setUpProducer(*bqIgbp);
+ }
+ sp<SurfaceControl> mBufferQueueSurfaceControl;
};
TEST_F(BLASTFrameEventHistoryTest, FrameEventHistory_Basic) {
@@ -853,4 +879,153 @@ TEST_F(BLASTFrameEventHistoryTest, FrameEventHistory_Basic) {
// wait for any callbacks that have not been received
adapter.waitForCallbacks();
}
+
+// Runs the same Frame Event History test
+TEST_F(BLASTFrameEventHistoryTest, FrameEventHistory_Basic_BufferQueue) {
+ sp<IGraphicBufferProducer> bqIgbp;
+ createBufferQueueProducer(&bqIgbp);
+
+ ProducerFrameEventHistory history;
+ IGraphicBufferProducer::QueueBufferOutput qbOutput;
+ nsecs_t requestedPresentTimeA = 0;
+ nsecs_t postedTimeA = 0;
+ setUpAndQueueBuffer(bqIgbp, &requestedPresentTimeA, &postedTimeA, &qbOutput, true);
+ history.applyDelta(qbOutput.frameTimestamps);
+
+ FrameEvents* events = nullptr;
+ events = history.getFrame(1);
+ ASSERT_NE(nullptr, events);
+ ASSERT_EQ(1, events->frameNumber);
+ ASSERT_EQ(requestedPresentTimeA, events->requestedPresentTime);
+ ASSERT_GE(events->postedTime, postedTimeA);
+
+ // wait for buffer to be presented
+ std::this_thread::sleep_for(200ms);
+
+ nsecs_t requestedPresentTimeB = 0;
+ nsecs_t postedTimeB = 0;
+ setUpAndQueueBuffer(bqIgbp, &requestedPresentTimeB, &postedTimeB, &qbOutput, true);
+ history.applyDelta(qbOutput.frameTimestamps);
+ events = history.getFrame(1);
+ ASSERT_NE(nullptr, events);
+
+ // frame number, requestedPresentTime, and postTime should not have changed
+ ASSERT_EQ(1, events->frameNumber);
+ ASSERT_EQ(requestedPresentTimeA, events->requestedPresentTime);
+ ASSERT_GE(events->postedTime, postedTimeA);
+
+ ASSERT_GE(events->latchTime, postedTimeA);
+ ASSERT_FALSE(events->hasDequeueReadyInfo());
+
+ ASSERT_NE(nullptr, events->gpuCompositionDoneFence);
+ ASSERT_NE(nullptr, events->displayPresentFence);
+ ASSERT_NE(nullptr, events->releaseFence);
+
+ // we should also have gotten the initial values for the next frame
+ events = history.getFrame(2);
+ ASSERT_NE(nullptr, events);
+ ASSERT_EQ(2, events->frameNumber);
+ ASSERT_EQ(requestedPresentTimeB, events->requestedPresentTime);
+ ASSERT_GE(events->postedTime, postedTimeB);
+}
+
+TEST_F(BLASTFrameEventHistoryTest, FrameEventHistory_DroppedFrame) {
+ BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight);
+ sp<IGraphicBufferProducer> igbProducer;
+ setUpProducer(adapter, igbProducer);
+
+ ProducerFrameEventHistory history;
+ IGraphicBufferProducer::QueueBufferOutput qbOutput;
+ nsecs_t requestedPresentTimeA = 0;
+ nsecs_t postedTimeA = 0;
+ nsecs_t presentTimeDelay = std::chrono::nanoseconds(500ms).count();
+ setUpAndQueueBuffer(igbProducer, &requestedPresentTimeA, &postedTimeA, &qbOutput, true,
+ presentTimeDelay);
+ history.applyDelta(qbOutput.frameTimestamps);
+
+ FrameEvents* events = nullptr;
+ events = history.getFrame(1);
+ ASSERT_NE(nullptr, events);
+ ASSERT_EQ(1, events->frameNumber);
+ ASSERT_EQ(requestedPresentTimeA, events->requestedPresentTime);
+ ASSERT_GE(events->postedTime, postedTimeA);
+
+ // queue another buffer so the first can be dropped
+ nsecs_t requestedPresentTimeB = 0;
+ nsecs_t postedTimeB = 0;
+ setUpAndQueueBuffer(igbProducer, &requestedPresentTimeB, &postedTimeB, &qbOutput, true);
+ history.applyDelta(qbOutput.frameTimestamps);
+ events = history.getFrame(1);
+ ASSERT_NE(nullptr, events);
+
+ // frame number, requestedPresentTime, and postTime should not have changed
+ ASSERT_EQ(1, events->frameNumber);
+ ASSERT_EQ(requestedPresentTimeA, events->requestedPresentTime);
+ ASSERT_GE(events->postedTime, postedTimeA);
+
+ // a valid latchtime should not be set
+ ASSERT_FALSE(events->hasLatchInfo());
+ ASSERT_FALSE(events->hasDequeueReadyInfo());
+
+ ASSERT_NE(nullptr, events->gpuCompositionDoneFence);
+ ASSERT_NE(nullptr, events->displayPresentFence);
+ ASSERT_NE(nullptr, events->releaseFence);
+
+ // we should also have gotten the initial values for the next frame
+ events = history.getFrame(2);
+ ASSERT_NE(nullptr, events);
+ ASSERT_EQ(2, events->frameNumber);
+ ASSERT_EQ(requestedPresentTimeB, events->requestedPresentTime);
+ ASSERT_GE(events->postedTime, postedTimeB);
+}
+
+TEST_F(BLASTFrameEventHistoryTest, FrameEventHistory_DroppedFrame_BufferQueue) {
+ sp<IGraphicBufferProducer> bqIgbp;
+ createBufferQueueProducer(&bqIgbp);
+
+ ProducerFrameEventHistory history;
+ IGraphicBufferProducer::QueueBufferOutput qbOutput;
+ nsecs_t requestedPresentTimeA = 0;
+ nsecs_t postedTimeA = 0;
+ nsecs_t presentTimeDelay = std::chrono::nanoseconds(500ms).count();
+ setUpAndQueueBuffer(bqIgbp, &requestedPresentTimeA, &postedTimeA, &qbOutput, true,
+ presentTimeDelay);
+ history.applyDelta(qbOutput.frameTimestamps);
+
+ FrameEvents* events = nullptr;
+ events = history.getFrame(1);
+ ASSERT_NE(nullptr, events);
+ ASSERT_EQ(1, events->frameNumber);
+ ASSERT_EQ(requestedPresentTimeA, events->requestedPresentTime);
+ ASSERT_GE(events->postedTime, postedTimeA);
+
+ // queue another buffer so the first can be dropped
+ nsecs_t requestedPresentTimeB = 0;
+ nsecs_t postedTimeB = 0;
+ setUpAndQueueBuffer(bqIgbp, &requestedPresentTimeB, &postedTimeB, &qbOutput, true);
+ history.applyDelta(qbOutput.frameTimestamps);
+ events = history.getFrame(1);
+ ASSERT_NE(nullptr, events);
+
+ // frame number, requestedPresentTime, and postTime should not have changed
+ ASSERT_EQ(1, events->frameNumber);
+ ASSERT_EQ(requestedPresentTimeA, events->requestedPresentTime);
+ ASSERT_GE(events->postedTime, postedTimeA);
+
+ // a valid latchtime should not be set
+ ASSERT_FALSE(events->hasLatchInfo());
+ ASSERT_FALSE(events->hasDequeueReadyInfo());
+
+ ASSERT_NE(nullptr, events->gpuCompositionDoneFence);
+ ASSERT_NE(nullptr, events->displayPresentFence);
+ ASSERT_NE(nullptr, events->releaseFence);
+
+ // we should also have gotten the initial values for the next frame
+ events = history.getFrame(2);
+ ASSERT_NE(nullptr, events);
+ ASSERT_EQ(2, events->frameNumber);
+ ASSERT_EQ(requestedPresentTimeB, events->requestedPresentTime);
+ ASSERT_GE(events->postedTime, postedTimeB);
+}
+
} // namespace android
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 43909ac00d..69bb86649c 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -32,6 +32,7 @@
#include <inttypes.h>
#include <private/gui/ComposerService.h>
#include <ui/BufferQueueDefs.h>
+#include <ui/DisplayMode.h>
#include <ui/Rect.h>
#include <utils/String8.h>
@@ -734,10 +735,11 @@ public:
}
void setPowerMode(const sp<IBinder>& /*display*/, int /*mode*/) override {}
- status_t getDisplayInfo(const sp<IBinder>& /*display*/, DisplayInfo*) override {
+ status_t getStaticDisplayInfo(const sp<IBinder>& /*display*/, ui::StaticDisplayInfo*) override {
return NO_ERROR;
}
- status_t getDisplayModes(const sp<IBinder>& /*display*/, Vector<ui::DisplayMode>*) override {
+ status_t getDynamicDisplayInfo(const sp<IBinder>& /*display*/,
+ ui::DynamicDisplayInfo*) override {
return NO_ERROR;
}
status_t getDisplayState(const sp<IBinder>& /*display*/, ui::DisplayState*) override {
@@ -745,34 +747,17 @@ public:
}
status_t getDisplayStats(const sp<IBinder>& /*display*/,
DisplayStatInfo* /*stats*/) override { return NO_ERROR; }
- int getActiveDisplayModeId(const sp<IBinder>& /*display*/) override { return 0; }
- status_t getDisplayColorModes(const sp<IBinder>& /*display*/,
- Vector<ColorMode>* /*outColorModes*/) override {
- return NO_ERROR;
- }
status_t getDisplayNativePrimaries(const sp<IBinder>& /*display*/,
ui::DisplayPrimaries& /*primaries*/) override {
return NO_ERROR;
}
- ColorMode getActiveColorMode(const sp<IBinder>& /*display*/)
- override {
- return ColorMode::NATIVE;
- }
status_t setActiveColorMode(const sp<IBinder>& /*display*/,
ColorMode /*colorMode*/) override { return NO_ERROR; }
status_t captureDisplay(const DisplayCaptureArgs& /* captureArgs */,
const sp<IScreenCaptureListener>& /* captureListener */) override {
return NO_ERROR;
}
- status_t getAutoLowLatencyModeSupport(const sp<IBinder>& /*display*/,
- bool* /*outSupport*/) const override {
- return NO_ERROR;
- }
void setAutoLowLatencyMode(const sp<IBinder>& /*display*/, bool /*on*/) override {}
- status_t getGameContentTypeSupport(const sp<IBinder>& /*display*/,
- bool* /*outSupport*/) const override {
- return NO_ERROR;
- }
void setGameContentType(const sp<IBinder>& /*display*/, bool /*on*/) override {}
status_t captureDisplay(uint64_t /*displayOrLayerStack*/,
const sp<IScreenCaptureListener>& /* captureListener */) override {
@@ -787,10 +772,6 @@ public:
status_t getAnimationFrameStats(FrameStats* /*outStats*/) const override {
return NO_ERROR;
}
- status_t getHdrCapabilities(const sp<IBinder>& /*display*/,
- HdrCapabilities* /*outCapabilities*/) const override {
- return NO_ERROR;
- }
status_t enableVSyncInjections(bool /*enable*/) override {
return NO_ERROR;
}
@@ -843,7 +824,8 @@ public:
const sp<IRegionSamplingListener>& /*listener*/) override {
return NO_ERROR;
}
- status_t setDesiredDisplayModeSpecs(const sp<IBinder>& /*displayToken*/, size_t /*defaultMode*/,
+ status_t setDesiredDisplayModeSpecs(const sp<IBinder>& /*displayToken*/,
+ ui::DisplayModeId /*defaultMode*/,
bool /*allowGroupSwitching*/,
float /*primaryRefreshRateMin*/,
float /*primaryRefreshRateMax*/,
@@ -852,7 +834,7 @@ public:
return NO_ERROR;
}
status_t getDesiredDisplayModeSpecs(const sp<IBinder>& /*displayToken*/,
- size_t* /*outDefaultMode*/,
+ ui::DisplayModeId* /*outDefaultMode*/,
bool* /*outAllowGroupSwitching*/,
float* /*outPrimaryRefreshRateMin*/,
float* /*outPrimaryRefreshRateMax*/,
diff --git a/libs/incidentcompanion/Android.bp b/libs/incidentcompanion/Android.bp
index 63411b9698..ef7f52318b 100644
--- a/libs/incidentcompanion/Android.bp
+++ b/libs/incidentcompanion/Android.bp
@@ -14,6 +14,15 @@
* limitations under the License.
*/
+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"],
+}
+
filegroup {
name: "incidentcompanion_aidl",
srcs: [
@@ -49,4 +58,3 @@ cc_library_static {
"-Wunused-parameter",
],
}
-
diff --git a/libs/input/Android.bp b/libs/input/Android.bp
index fce3000a0f..425361004c 100644
--- a/libs/input/Android.bp
+++ b/libs/input/Android.bp
@@ -14,6 +14,15 @@
// libinput is partially built for the host (used by build time keymap validation tool)
+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"],
+}
+
filegroup {
name: "inputconstants_aidl",
srcs: [
diff --git a/libs/input/InputDevice.cpp b/libs/input/InputDevice.cpp
index 698cf6eebc..ffcc1cd93a 100644
--- a/libs/input/InputDevice.cpp
+++ b/libs/input/InputDevice.cpp
@@ -170,7 +170,8 @@ InputDeviceInfo::InputDeviceInfo(const InputDeviceInfo& other)
mHasButtonUnderPad(other.mHasButtonUnderPad),
mHasSensor(other.mHasSensor),
mMotionRanges(other.mMotionRanges),
- mSensors(other.mSensors) {}
+ mSensors(other.mSensors),
+ mLights(other.mLights) {}
InputDeviceInfo::~InputDeviceInfo() {
}
@@ -193,6 +194,7 @@ void InputDeviceInfo::initialize(int32_t id, int32_t generation, int32_t control
mHasSensor = false;
mMotionRanges.clear();
mSensors.clear();
+ mLights.clear();
}
const InputDeviceInfo::MotionRange* InputDeviceInfo::getMotionRange(
@@ -229,6 +231,13 @@ void InputDeviceInfo::addSensorInfo(const InputDeviceSensorInfo& info) {
mSensors.insert_or_assign(info.type, info);
}
+void InputDeviceInfo::addLightInfo(const InputDeviceLightInfo& info) {
+ if (mLights.find(info.id) != mLights.end()) {
+ ALOGW("Light id %d already exists, will be replaced by new light added.", info.id);
+ }
+ mLights.insert_or_assign(info.id, info);
+}
+
const std::vector<InputDeviceSensorType> InputDeviceInfo::getSensorTypes() {
std::vector<InputDeviceSensorType> types;
for (const auto& [type, info] : mSensors) {
@@ -245,4 +254,20 @@ const InputDeviceSensorInfo* InputDeviceInfo::getSensorInfo(InputDeviceSensorTyp
return &it->second;
}
+const std::vector<int32_t> InputDeviceInfo::getLightIds() {
+ std::vector<int32_t> ids;
+ for (const auto& [id, info] : mLights) {
+ ids.push_back(id);
+ }
+ return ids;
+}
+
+const InputDeviceLightInfo* InputDeviceInfo::getLightInfo(int32_t id) {
+ auto it = mLights.find(id);
+ if (it == mLights.end()) {
+ return nullptr;
+ }
+ return &it->second;
+}
+
} // namespace android
diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp
index acea473242..6218fdcac1 100644
--- a/libs/input/InputTransport.cpp
+++ b/libs/input/InputTransport.cpp
@@ -234,6 +234,7 @@ void InputMessage::getSanitizedCopy(InputMessage* msg) const {
}
case InputMessage::Type::FINISHED: {
msg->body.finished.handled = body.finished.handled;
+ msg->body.finished.consumeTime = body.finished.consumeTime;
break;
}
case InputMessage::Type::FOCUS: {
@@ -597,7 +598,8 @@ status_t InputPublisher::publishCaptureEvent(uint32_t seq, int32_t eventId,
return mChannel->sendMessage(&msg);
}
-status_t InputPublisher::receiveFinishedSignal(uint32_t* outSeq, bool* outHandled) {
+status_t InputPublisher::receiveFinishedSignal(
+ const std::function<void(uint32_t seq, bool handled, nsecs_t consumeTime)>& callback) {
if (DEBUG_TRANSPORT_ACTIONS) {
ALOGD("channel '%s' publisher ~ receiveFinishedSignal", mChannel->getName().c_str());
}
@@ -605,8 +607,6 @@ status_t InputPublisher::receiveFinishedSignal(uint32_t* outSeq, bool* outHandle
InputMessage msg;
status_t result = mChannel->receiveMessage(&msg);
if (result) {
- *outSeq = 0;
- *outHandled = false;
return result;
}
if (msg.header.type != InputMessage::Type::FINISHED) {
@@ -614,8 +614,7 @@ status_t InputPublisher::receiveFinishedSignal(uint32_t* outSeq, bool* outHandle
mChannel->getName().c_str(), msg.header.type);
return UNKNOWN_ERROR;
}
- *outSeq = msg.header.seq;
- *outHandled = msg.body.finished.handled == 1;
+ callback(msg.header.seq, msg.body.finished.handled == 1, msg.body.finished.consumeTime);
return OK;
}
@@ -651,6 +650,9 @@ status_t InputConsumer::consume(InputEventFactoryInterface* factory, bool consum
} else {
// Receive a fresh message.
status_t result = mChannel->receiveMessage(&mMsg);
+ if (result == OK) {
+ mConsumeTimes.emplace(mMsg.header.seq, systemTime(SYSTEM_TIME_MONOTONIC));
+ }
if (result) {
// Consume the next batched event unless batches are being held for later.
if (consumeBatches || result != WOULD_BLOCK) {
@@ -1147,12 +1149,33 @@ status_t InputConsumer::sendFinishedSignal(uint32_t seq, bool handled) {
return sendUnchainedFinishedSignal(seq, handled);
}
+nsecs_t InputConsumer::getConsumeTime(uint32_t seq) const {
+ auto it = mConsumeTimes.find(seq);
+ // Consume time will be missing if either 'finishInputEvent' is called twice, or if it was
+ // called for the wrong (synthetic?) input event. Either way, it is a bug that should be fixed.
+ LOG_ALWAYS_FATAL_IF(it == mConsumeTimes.end(), "Could not find consume time for seq=%" PRIu32,
+ seq);
+ return it->second;
+}
+
+void InputConsumer::popConsumeTime(uint32_t seq) {
+ mConsumeTimes.erase(seq);
+}
+
status_t InputConsumer::sendUnchainedFinishedSignal(uint32_t seq, bool handled) {
InputMessage msg;
msg.header.type = InputMessage::Type::FINISHED;
msg.header.seq = seq;
msg.body.finished.handled = handled ? 1 : 0;
- return mChannel->sendMessage(&msg);
+ msg.body.finished.consumeTime = getConsumeTime(seq);
+ status_t result = mChannel->sendMessage(&msg);
+ if (result == OK) {
+ // Remove the consume time if the socket write succeeded. We will not need to ack this
+ // message anymore. If the socket write did not succeed, we will try again and will still
+ // need consume time.
+ popConsumeTime(seq);
+ }
+ return result;
}
bool InputConsumer::hasDeferredEvent() const {
@@ -1304,8 +1327,9 @@ std::string InputConsumer::dump() const {
break;
}
case InputMessage::Type::FINISHED: {
- out += android::base::StringPrintf("handled=%s",
- toString(msg.body.finished.handled));
+ out += android::base::StringPrintf("handled=%s, consumeTime=%" PRId64,
+ toString(msg.body.finished.handled),
+ msg.body.finished.consumeTime);
break;
}
case InputMessage::Type::FOCUS: {
@@ -1335,6 +1359,14 @@ std::string InputConsumer::dump() const {
if (mSeqChains.empty()) {
out += " <empty>\n";
}
+ out += "mConsumeTimes:\n";
+ for (const auto& [seq, consumeTime] : mConsumeTimes) {
+ out += android::base::StringPrintf(" seq = %" PRIu32 " consumeTime = %" PRId64, seq,
+ consumeTime);
+ }
+ if (mConsumeTimes.empty()) {
+ out += " <empty>\n";
+ }
return out;
}
diff --git a/libs/input/tests/Android.bp b/libs/input/tests/Android.bp
index b23aaded78..fe8a5677d9 100644
--- a/libs/input/tests/Android.bp
+++ b/libs/input/tests/Android.bp
@@ -1,4 +1,13 @@
// Build the unit tests.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_test {
name: "libinput_tests",
srcs: [
diff --git a/libs/input/tests/InputPublisherAndConsumer_test.cpp b/libs/input/tests/InputPublisherAndConsumer_test.cpp
index 9da7b69b19..e7e566dde6 100644
--- a/libs/input/tests/InputPublisherAndConsumer_test.cpp
+++ b/libs/input/tests/InputPublisherAndConsumer_test.cpp
@@ -82,6 +82,7 @@ void InputPublisherAndConsumerTest::PublishAndConsumeKeyEvent() {
constexpr int32_t repeatCount = 1;
constexpr nsecs_t downTime = 3;
constexpr nsecs_t eventTime = 4;
+ const nsecs_t publishTime = systemTime(SYSTEM_TIME_MONOTONIC);
status = mPublisher->publishKeyEvent(seq, eventId, deviceId, source, displayId, hmac, action,
flags, keyCode, scanCode, metaState, repeatCount, downTime,
@@ -122,13 +123,22 @@ void InputPublisherAndConsumerTest::PublishAndConsumeKeyEvent() {
uint32_t finishedSeq = 0;
bool handled = false;
- status = mPublisher->receiveFinishedSignal(&finishedSeq, &handled);
+ nsecs_t consumeTime;
+ status = mPublisher->receiveFinishedSignal(
+ [&finishedSeq, &handled, &consumeTime](uint32_t inSeq, bool inHandled,
+ nsecs_t inConsumeTime) -> void {
+ finishedSeq = inSeq;
+ handled = inHandled;
+ consumeTime = inConsumeTime;
+ });
ASSERT_EQ(OK, status)
<< "publisher receiveFinishedSignal should return OK";
ASSERT_EQ(seq, finishedSeq)
<< "publisher receiveFinishedSignal should have returned the original sequence number";
ASSERT_TRUE(handled)
<< "publisher receiveFinishedSignal should have set handled to consumer's reply";
+ ASSERT_GE(consumeTime, publishTime)
+ << "finished signal's consume time should be greater than publish time";
}
void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent() {
@@ -160,6 +170,7 @@ void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent() {
constexpr nsecs_t downTime = 3;
constexpr size_t pointerCount = 3;
constexpr nsecs_t eventTime = 4;
+ const nsecs_t publishTime = systemTime(SYSTEM_TIME_MONOTONIC);
PointerProperties pointerProperties[pointerCount];
PointerCoords pointerCoords[pointerCount];
for (size_t i = 0; i < pointerCount; i++) {
@@ -262,13 +273,22 @@ void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent() {
uint32_t finishedSeq = 0;
bool handled = true;
- status = mPublisher->receiveFinishedSignal(&finishedSeq, &handled);
+ nsecs_t consumeTime;
+ status = mPublisher->receiveFinishedSignal(
+ [&finishedSeq, &handled, &consumeTime](uint32_t inSeq, bool inHandled,
+ nsecs_t inConsumeTime) -> void {
+ finishedSeq = inSeq;
+ handled = inHandled;
+ consumeTime = inConsumeTime;
+ });
ASSERT_EQ(OK, status)
<< "publisher receiveFinishedSignal should return OK";
ASSERT_EQ(seq, finishedSeq)
<< "publisher receiveFinishedSignal should have returned the original sequence number";
ASSERT_FALSE(handled)
<< "publisher receiveFinishedSignal should have set handled to consumer's reply";
+ ASSERT_GE(consumeTime, publishTime)
+ << "finished signal's consume time should be greater than publish time";
}
void InputPublisherAndConsumerTest::PublishAndConsumeFocusEvent() {
@@ -278,6 +298,7 @@ void InputPublisherAndConsumerTest::PublishAndConsumeFocusEvent() {
int32_t eventId = InputEvent::nextId();
constexpr bool hasFocus = true;
constexpr bool inTouchMode = true;
+ const nsecs_t publishTime = systemTime(SYSTEM_TIME_MONOTONIC);
status = mPublisher->publishFocusEvent(seq, eventId, hasFocus, inTouchMode);
ASSERT_EQ(OK, status) << "publisher publishKeyEvent should return OK";
@@ -302,12 +323,21 @@ void InputPublisherAndConsumerTest::PublishAndConsumeFocusEvent() {
uint32_t finishedSeq = 0;
bool handled = false;
- status = mPublisher->receiveFinishedSignal(&finishedSeq, &handled);
+ nsecs_t consumeTime;
+ status = mPublisher->receiveFinishedSignal(
+ [&finishedSeq, &handled, &consumeTime](uint32_t inSeq, bool inHandled,
+ nsecs_t inConsumeTime) -> void {
+ finishedSeq = inSeq;
+ handled = inHandled;
+ consumeTime = inConsumeTime;
+ });
ASSERT_EQ(OK, status) << "publisher receiveFinishedSignal should return OK";
ASSERT_EQ(seq, finishedSeq)
<< "publisher receiveFinishedSignal should have returned the original sequence number";
ASSERT_TRUE(handled)
<< "publisher receiveFinishedSignal should have set handled to consumer's reply";
+ ASSERT_GE(consumeTime, publishTime)
+ << "finished signal's consume time should be greater than publish time";
}
void InputPublisherAndConsumerTest::PublishAndConsumeCaptureEvent() {
@@ -316,6 +346,7 @@ void InputPublisherAndConsumerTest::PublishAndConsumeCaptureEvent() {
constexpr uint32_t seq = 42;
int32_t eventId = InputEvent::nextId();
constexpr bool captureEnabled = true;
+ const nsecs_t publishTime = systemTime(SYSTEM_TIME_MONOTONIC);
status = mPublisher->publishCaptureEvent(seq, eventId, captureEnabled);
ASSERT_EQ(OK, status) << "publisher publishKeyEvent should return OK";
@@ -339,12 +370,21 @@ void InputPublisherAndConsumerTest::PublishAndConsumeCaptureEvent() {
uint32_t finishedSeq = 0;
bool handled = false;
- status = mPublisher->receiveFinishedSignal(&finishedSeq, &handled);
+ nsecs_t consumeTime;
+ status = mPublisher->receiveFinishedSignal(
+ [&finishedSeq, &handled, &consumeTime](uint32_t inSeq, bool inHandled,
+ nsecs_t inConsumeTime) -> void {
+ finishedSeq = inSeq;
+ handled = inHandled;
+ consumeTime = inConsumeTime;
+ });
ASSERT_EQ(OK, status) << "publisher receiveFinishedSignal should return OK";
ASSERT_EQ(seq, finishedSeq)
<< "publisher receiveFinishedSignal should have returned the original sequence number";
ASSERT_TRUE(handled)
<< "publisher receiveFinishedSignal should have set handled to consumer's reply";
+ ASSERT_GE(consumeTime, publishTime)
+ << "finished signal's consume time should be greater than publish time";
}
TEST_F(InputPublisherAndConsumerTest, PublishKeyEvent_EndToEnd) {
diff --git a/libs/input/tests/StructLayout_test.cpp b/libs/input/tests/StructLayout_test.cpp
index 4107d61eb2..a8865858d3 100644
--- a/libs/input/tests/StructLayout_test.cpp
+++ b/libs/input/tests/StructLayout_test.cpp
@@ -83,6 +83,7 @@ void TestInputMessageAlignment() {
CHECK_OFFSET(InputMessage::Body::Capture, pointerCaptureEnabled, 4);
CHECK_OFFSET(InputMessage::Body::Finished, handled, 4);
+ CHECK_OFFSET(InputMessage::Body::Finished, consumeTime, 8);
}
void TestHeaderSize() {
@@ -100,7 +101,7 @@ void TestBodySize() {
static_assert(sizeof(InputMessage::Body::Motion) ==
offsetof(InputMessage::Body::Motion, pointers) +
sizeof(InputMessage::Body::Motion::Pointer) * MAX_POINTERS);
- static_assert(sizeof(InputMessage::Body::Finished) == 8);
+ static_assert(sizeof(InputMessage::Body::Finished) == 16);
static_assert(sizeof(InputMessage::Body::Focus) == 8);
static_assert(sizeof(InputMessage::Body::Capture) == 8);
}
diff --git a/libs/math/Android.bp b/libs/math/Android.bp
index ab969504b1..907eb67e9a 100644
--- a/libs/math/Android.bp
+++ b/libs/math/Android.bp
@@ -12,6 +12,23 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ default_applicable_licenses: ["frameworks_native_libs_math_license"],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+ name: "frameworks_native_libs_math_license",
+ visibility: [":__subpackages__"],
+ license_kinds: [
+ "SPDX-license-identifier-Apache-2.0",
+ ],
+ license_text: [
+ "NOTICE",
+ ],
+}
+
cc_library_static {
name: "libmath",
host_supported: true,
diff --git a/libs/math/tests/Android.bp b/libs/math/tests/Android.bp
index 472d3379f7..14fb72af78 100644
--- a/libs/math/tests/Android.bp
+++ b/libs/math/tests/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+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_libs_math_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_libs_math_license"],
+}
+
cc_test {
name: "vec_test",
srcs: ["vec_test.cpp"],
diff --git a/libs/nativebase/Android.bp b/libs/nativebase/Android.bp
index 8399e8ce0a..1a4729c610 100644
--- a/libs/nativebase/Android.bp
+++ b/libs/nativebase/Android.bp
@@ -12,6 +12,23 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ default_applicable_licenses: ["frameworks_native_libs_nativebase_license"],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+ name: "frameworks_native_libs_nativebase_license",
+ visibility: [":__subpackages__"],
+ license_kinds: [
+ "SPDX-license-identifier-Apache-2.0",
+ ],
+ license_text: [
+ "NOTICE",
+ ],
+}
+
cc_library_headers {
name: "libnativebase_headers",
vendor_available: true,
diff --git a/libs/nativedisplay/ADisplay.cpp b/libs/nativedisplay/ADisplay.cpp
index c595aa6309..6288194714 100644
--- a/libs/nativedisplay/ADisplay.cpp
+++ b/libs/nativedisplay/ADisplay.cpp
@@ -16,10 +16,11 @@
#include <apex/display.h>
#include <gui/SurfaceComposerClient.h>
-#include <ui/DisplayInfo.h>
#include <ui/DisplayMode.h>
+#include <ui/DynamicDisplayInfo.h>
#include <ui/GraphicTypes.h>
#include <ui/PixelFormat.h>
+#include <ui/StaticDisplayInfo.h>
#include <algorithm>
#include <optional>
@@ -33,6 +34,11 @@ namespace android::display::impl {
*/
struct DisplayConfigImpl {
/**
+ * The ID of the display configuration.
+ */
+ size_t id;
+
+ /**
* The width in pixels of the display configuration.
*/
int32_t width{0};
@@ -139,17 +145,19 @@ int ADisplay_acquirePhysicalDisplays(ADisplay*** outDisplays) {
for (int i = 0; i < size; ++i) {
const sp<IBinder> token = SurfaceComposerClient::getPhysicalDisplayToken(ids[i]);
- DisplayInfo info;
- if (const status_t status = SurfaceComposerClient::getDisplayInfo(token, &info);
+ ui::StaticDisplayInfo staticInfo;
+ if (const status_t status = SurfaceComposerClient::getStaticDisplayInfo(token, &staticInfo);
status != OK) {
return status;
}
- Vector<ui::DisplayMode> modes;
- if (const status_t status = SurfaceComposerClient::getDisplayModes(token, &modes);
+ ui::DynamicDisplayInfo dynamicInfo;
+ if (const status_t status =
+ SurfaceComposerClient::getDynamicDisplayInfo(token, &dynamicInfo);
status != OK) {
return status;
}
+ const auto& modes = dynamicInfo.supportedDisplayModes;
if (modes.empty()) {
return NO_INIT;
}
@@ -159,9 +167,9 @@ int ADisplay_acquirePhysicalDisplays(ADisplay*** outDisplays) {
for (int j = 0; j < modes.size(); ++j) {
const ui::DisplayMode& mode = modes[j];
modesPerDisplay[i].emplace_back(
- DisplayConfigImpl{mode.resolution.getWidth(), mode.resolution.getHeight(),
- info.density, mode.refreshRate, mode.sfVsyncOffset,
- mode.appVsyncOffset});
+ DisplayConfigImpl{static_cast<size_t>(mode.id), mode.resolution.getWidth(),
+ mode.resolution.getHeight(), staticInfo.density,
+ mode.refreshRate, mode.sfVsyncOffset, mode.appVsyncOffset});
}
}
@@ -257,15 +265,22 @@ int ADisplay_getCurrentConfig(ADisplay* display, ADisplayConfig** outConfig) {
CHECK_NOT_NULL(display);
sp<IBinder> token = getToken(display);
- const int index = SurfaceComposerClient::getActiveDisplayModeId(token);
- if (index < 0) {
- return index;
+ ui::DynamicDisplayInfo info;
+ if (const auto status = SurfaceComposerClient::getDynamicDisplayInfo(token, &info);
+ status != OK) {
+ return status;
}
DisplayImpl* impl = reinterpret_cast<DisplayImpl*>(display);
+ for (size_t i = 0; i < impl->numConfigs; i++) {
+ auto* config = impl->configs + i;
+ if (config->id == info.activeDisplayModeId) {
+ *outConfig = reinterpret_cast<ADisplayConfig*>(config);
+ return OK;
+ }
+ }
- *outConfig = reinterpret_cast<ADisplayConfig*>(impl->configs + index);
- return OK;
+ return NAME_NOT_FOUND;
}
float ADisplayConfig_getDensity(ADisplayConfig* config) {
diff --git a/libs/nativedisplay/Android.bp b/libs/nativedisplay/Android.bp
index 6574ae64f7..ed728dcb45 100644
--- a/libs/nativedisplay/Android.bp
+++ b/libs/nativedisplay/Android.bp
@@ -12,6 +12,25 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ default_applicable_licenses: [
+ "frameworks_native_libs_nativedisplay_license",
+ ],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+ name: "frameworks_native_libs_nativedisplay_license",
+ visibility: [":__subpackages__"],
+ license_kinds: [
+ "SPDX-license-identifier-Apache-2.0",
+ ],
+ license_text: [
+ "NOTICE",
+ ],
+}
+
cc_library_headers {
name: "libnativedisplay_headers",
export_include_dirs: ["include",],
diff --git a/libs/nativedisplay/include/apex/display.h b/libs/nativedisplay/include/apex/display.h
index a7eaf87b9e..bd94b5523e 100644
--- a/libs/nativedisplay/include/apex/display.h
+++ b/libs/nativedisplay/include/apex/display.h
@@ -97,6 +97,11 @@ void ADisplay_getPreferredWideColorFormat(ADisplay* display, ADataSpace* outData
* such an update is observed, then this method should be recalled to get the
* new current configuration.
*
+ * After a subsequent hotplug "connected" event the supported display configs
+ * may change. Then the preloaded display configs will be stale and the
+ * call for current config may return NAME_NOT_FOUND. In this case the client
+ * should release and re-acquire the display handle.
+ *
* Returns OK on success, -errno on failure.
*/
int ADisplay_getCurrentConfig(ADisplay* display, ADisplayConfig** outConfig);
diff --git a/libs/nativewindow/Android.bp b/libs/nativewindow/Android.bp
index 3011dccf1e..8675439938 100644
--- a/libs/nativewindow/Android.bp
+++ b/libs/nativewindow/Android.bp
@@ -12,6 +12,25 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ default_applicable_licenses: [
+ "frameworks_native_libs_nativewindow_license",
+ ],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+ name: "frameworks_native_libs_nativewindow_license",
+ visibility: [":__subpackages__"],
+ license_kinds: [
+ "SPDX-license-identifier-Apache-2.0",
+ ],
+ license_text: [
+ "NOTICE",
+ ],
+}
+
ndk_headers {
name: "libnativewindow_ndk_headers",
from: "include/android",
diff --git a/libs/nativewindow/tests/Android.bp b/libs/nativewindow/tests/Android.bp
index 2e4bd991e0..30737c1bf6 100644
--- a/libs/nativewindow/tests/Android.bp
+++ b/libs/nativewindow/tests/Android.bp
@@ -14,6 +14,17 @@
// limitations under the License.
//
+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_libs_nativewindow_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: [
+ "frameworks_native_libs_nativewindow_license",
+ ],
+}
+
cc_test {
name: "libnativewindow_test",
test_suites: [
diff --git a/libs/renderengine/Android.bp b/libs/renderengine/Android.bp
index d69c7aea30..eb3b434935 100644
--- a/libs/renderengine/Android.bp
+++ b/libs/renderengine/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_defaults {
name: "renderengine_defaults",
cflags: [
@@ -31,10 +40,6 @@ cc_defaults {
"libui",
"libutils",
],
- include_dirs: [
- "external/skia/src/gpu",
- ],
- whole_static_libs: ["libskia"],
local_include_dirs: ["include"],
export_include_dirs: ["include"],
}
@@ -106,6 +111,10 @@ cc_library_static {
":librenderengine_threaded_sources",
":librenderengine_skia_sources",
],
+ include_dirs: [
+ "external/skia/src/gpu",
+ ],
+ whole_static_libs: ["libskia"],
lto: {
thin: true,
},
diff --git a/libs/renderengine/OWNERS b/libs/renderengine/OWNERS
index 08cf2de7f9..c4785060cb 100644
--- a/libs/renderengine/OWNERS
+++ b/libs/renderengine/OWNERS
@@ -1,3 +1,5 @@
alecmouri@google.com
+djsollen@google.com
jreck@google.com
lpy@google.com
+scroggo@google.com
diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h
index 64d6c6bdd7..7496b74ba5 100644
--- a/libs/renderengine/gl/GLESRenderEngine.h
+++ b/libs/renderengine/gl/GLESRenderEngine.h
@@ -72,6 +72,7 @@ public:
base::unique_fd&& bufferFence, base::unique_fd* drawFence) override;
bool cleanupPostRender(CleanupMode mode) override;
int getContextPriority() override;
+ bool supportsBackgroundBlur() override { return mBlurFilter != nullptr; }
EGLDisplay getEGLDisplay() const { return mEGLDisplay; }
// Creates an output image for rendering to
diff --git a/libs/renderengine/gl/filters/BlurFilter.cpp b/libs/renderengine/gl/filters/BlurFilter.cpp
index 19f18c0a7f..3455e08cfe 100644
--- a/libs/renderengine/gl/filters/BlurFilter.cpp
+++ b/libs/renderengine/gl/filters/BlurFilter.cpp
@@ -207,7 +207,7 @@ status_t BlurFilter::render(bool multiPass) {
}
string BlurFilter::getVertexShader() const {
- return R"SHADER(#version 310 es
+ return R"SHADER(#version 300 es
precision mediump float;
in vec2 aPosition;
@@ -222,7 +222,7 @@ string BlurFilter::getVertexShader() const {
}
string BlurFilter::getFragmentShader() const {
- return R"SHADER(#version 310 es
+ return R"SHADER(#version 300 es
precision mediump float;
uniform sampler2D uTexture;
@@ -244,7 +244,7 @@ string BlurFilter::getFragmentShader() const {
}
string BlurFilter::getMixFragShader() const {
- string shader = R"SHADER(#version 310 es
+ string shader = R"SHADER(#version 300 es
precision mediump float;
in highp vec2 vUV;
diff --git a/libs/renderengine/include/renderengine/LayerSettings.h b/libs/renderengine/include/renderengine/LayerSettings.h
index 3a727c9caf..7661233967 100644
--- a/libs/renderengine/include/renderengine/LayerSettings.h
+++ b/libs/renderengine/include/renderengine/LayerSettings.h
@@ -28,6 +28,7 @@
#include <ui/GraphicTypes.h>
#include <ui/Rect.h>
#include <ui/Region.h>
+#include <ui/StretchEffect.h>
#include <ui/Transform.h>
namespace android {
@@ -155,6 +156,8 @@ struct LayerSettings {
std::vector<BlurRegion> blurRegions;
+ StretchEffect stretchEffect;
+
// Name associated with the layer for debugging purposes.
std::string name;
};
diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h
index 506f81ecc2..163a163fb2 100644
--- a/libs/renderengine/include/renderengine/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/RenderEngine.h
@@ -188,6 +188,10 @@ public:
// number of contexts that can be created at a specific priority level in the system.
virtual int getContextPriority() = 0;
+ // Returns true if blur was requested in the RenderEngineCreationArgs and the implementation
+ // also supports background blur. If false, no blur will be applied when drawing layers.
+ virtual bool supportsBackgroundBlur() = 0;
+
protected:
friend class threaded::RenderEngineThreaded;
};
diff --git a/libs/renderengine/include/renderengine/mock/RenderEngine.h b/libs/renderengine/include/renderengine/mock/RenderEngine.h
index 2c34da40f8..895ba3fe85 100644
--- a/libs/renderengine/include/renderengine/mock/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/mock/RenderEngine.h
@@ -54,6 +54,7 @@ public:
base::unique_fd*));
MOCK_METHOD0(cleanFramebufferCache, void());
MOCK_METHOD0(getContextPriority, int());
+ MOCK_METHOD0(supportsBackgroundBlur, bool());
};
} // namespace mock
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
index dd26b17eb4..327b04c699 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
@@ -286,6 +286,7 @@ SkiaGLRenderEngine::SkiaGLRenderEngine(const RenderEngineCreationArgs& args, EGL
}
if (args.supportsBackgroundBlur) {
+ ALOGD("Background Blurs Enabled");
mBlurFilter = new BlurFilter();
}
mCapture = std::make_unique<SkiaCapture>();
@@ -336,7 +337,7 @@ bool SkiaGLRenderEngine::useProtectedContext(bool useProtectedContext) {
if (useProtectedContext == mInProtectedContext) {
return true;
}
- if (useProtectedContext && supportsProtectedContent()) {
+ if (useProtectedContext && !supportsProtectedContent()) {
return false;
}
const EGLSurface surface =
@@ -491,6 +492,9 @@ sk_sp<SkShader> SkiaGLRenderEngine::createRuntimeEffectShader(sk_sp<SkShader> sh
const LayerSettings* layer,
const DisplaySettings& display,
bool undoPremultipliedAlpha) {
+ if (layer->stretchEffect.hasEffect()) {
+ // TODO: Implement
+ }
if (mUseColorManagement &&
needsLinearEffect(layer->colorTransform, layer->sourceDataspace, display.outputDataspace)) {
LinearEffect effect = LinearEffect{.inputDataspace = layer->sourceDataspace,
@@ -513,6 +517,45 @@ sk_sp<SkShader> SkiaGLRenderEngine::createRuntimeEffectShader(sk_sp<SkShader> sh
return shader;
}
+void SkiaGLRenderEngine::initCanvas(SkCanvas* canvas, const DisplaySettings& display) {
+ if (CC_UNLIKELY(mCapture->isCaptureRunning())) {
+ // Record display settings when capture is running.
+ std::stringstream displaySettings;
+ PrintTo(display, &displaySettings);
+ // Store the DisplaySettings in additional information.
+ canvas->drawAnnotation(SkRect::MakeEmpty(), "DisplaySettings",
+ SkData::MakeWithCString(displaySettings.str().c_str()));
+ }
+
+ // Before doing any drawing, let's make sure that we'll start at the origin of the display.
+ // Some displays don't start at 0,0 for example when we're mirroring the screen. Also, virtual
+ // displays might have different scaling when compared to the physical screen.
+
+ canvas->clipRect(getSkRect(display.physicalDisplay));
+ canvas->translate(display.physicalDisplay.left, display.physicalDisplay.top);
+
+ const auto clipWidth = display.clip.width();
+ const auto clipHeight = display.clip.height();
+ auto rotatedClipWidth = clipWidth;
+ auto rotatedClipHeight = clipHeight;
+ // Scale is contingent on the rotation result.
+ if (display.orientation & ui::Transform::ROT_90) {
+ std::swap(rotatedClipWidth, rotatedClipHeight);
+ }
+ const auto scaleX = static_cast<SkScalar>(display.physicalDisplay.width()) /
+ static_cast<SkScalar>(rotatedClipWidth);
+ const auto scaleY = static_cast<SkScalar>(display.physicalDisplay.height()) /
+ static_cast<SkScalar>(rotatedClipHeight);
+ canvas->scale(scaleX, scaleY);
+
+ // Canvas rotation is done by centering the clip window at the origin, rotating, translating
+ // back so that the top left corner of the clip is at (0, 0).
+ canvas->translate(rotatedClipWidth / 2, rotatedClipHeight / 2);
+ canvas->rotate(toDegrees(display.orientation));
+ canvas->translate(-clipWidth / 2, -clipHeight / 2);
+ canvas->translate(-display.clip.left, -display.clip.top);
+}
+
status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display,
const std::vector<const LayerSettings*>& layers,
const sp<GraphicBuffer>& buffer,
@@ -567,57 +610,50 @@ status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display,
}
}
- sk_sp<SkSurface> surface =
+ sk_sp<SkSurface> dstSurface =
surfaceTextureRef->getTexture()->getOrCreateSurface(mUseColorManagement
? display.outputDataspace
: ui::Dataspace::UNKNOWN,
grContext.get());
- SkCanvas* canvas = mCapture->tryCapture(surface.get());
- if (canvas == nullptr) {
+ SkCanvas* dstCanvas = mCapture->tryCapture(dstSurface.get());
+ if (dstCanvas == nullptr) {
ALOGE("Cannot acquire canvas from Skia.");
return BAD_VALUE;
}
- // Clear the entire canvas with a transparent black to prevent ghost images.
- canvas->clear(SK_ColorTRANSPARENT);
- canvas->save();
- if (mCapture->isCaptureRunning()) {
- // Record display settings when capture is running.
- std::stringstream displaySettings;
- PrintTo(display, &displaySettings);
- // Store the DisplaySettings in additional information.
- canvas->drawAnnotation(SkRect::MakeEmpty(), "DisplaySettings",
- SkData::MakeWithCString(displaySettings.str().c_str()));
- }
-
- // Before doing any drawing, let's make sure that we'll start at the origin of the display.
- // Some displays don't start at 0,0 for example when we're mirroring the screen. Also, virtual
- // displays might have different scaling when compared to the physical screen.
-
- canvas->clipRect(getSkRect(display.physicalDisplay));
- canvas->translate(display.physicalDisplay.left, display.physicalDisplay.top);
-
- const auto clipWidth = display.clip.width();
- const auto clipHeight = display.clip.height();
- auto rotatedClipWidth = clipWidth;
- auto rotatedClipHeight = clipHeight;
- // Scale is contingent on the rotation result.
- if (display.orientation & ui::Transform::ROT_90) {
- std::swap(rotatedClipWidth, rotatedClipHeight);
+ // Find if any layers have requested blur, we'll use that info to decide when to render to an
+ // offscreen buffer and when to render to the native buffer.
+ sk_sp<SkSurface> activeSurface(dstSurface);
+ SkCanvas* canvas = dstCanvas;
+ SkiaCapture::OffscreenState offscreenCaptureState;
+ const LayerSettings* blurCompositionLayer = nullptr;
+ if (mBlurFilter) {
+ bool requiresCompositionLayer = false;
+ for (const auto& layer : layers) {
+ if (layer->backgroundBlurRadius > 0) {
+ // when skbug.com/11208 and b/176903027 are resolved we can add the additional
+ // restriction for layer->backgroundBlurRadius < BlurFilter::kMaxCrossFadeRadius
+ requiresCompositionLayer = true;
+ }
+ for (auto region : layer->blurRegions) {
+ if (region.blurRadius < BlurFilter::kMaxCrossFadeRadius) {
+ requiresCompositionLayer = true;
+ }
+ }
+ if (requiresCompositionLayer) {
+ activeSurface = dstSurface->makeSurface(dstSurface->imageInfo());
+ canvas = mCapture->tryOffscreenCapture(activeSurface.get(), &offscreenCaptureState);
+ blurCompositionLayer = layer;
+ break;
+ }
+ }
}
- const auto scaleX = static_cast<SkScalar>(display.physicalDisplay.width()) /
- static_cast<SkScalar>(rotatedClipWidth);
- const auto scaleY = static_cast<SkScalar>(display.physicalDisplay.height()) /
- static_cast<SkScalar>(rotatedClipHeight);
- canvas->scale(scaleX, scaleY);
- // Canvas rotation is done by centering the clip window at the origin, rotating, translating
- // back so that the top left corner of the clip is at (0, 0).
- canvas->translate(rotatedClipWidth / 2, rotatedClipHeight / 2);
- canvas->rotate(toDegrees(display.orientation));
- canvas->translate(-clipWidth / 2, -clipHeight / 2);
- canvas->translate(-display.clip.left, -display.clip.top);
+ canvas->save();
+ // Clear the entire canvas with a transparent black to prevent ghost images.
+ canvas->clear(SK_ColorTRANSPARENT);
+ initCanvas(canvas, display);
// TODO: clearRegion was required for SurfaceView when a buffer is not yet available but the
// view is still on-screen. The clear region could be re-specified as a black color layer,
@@ -644,9 +680,45 @@ status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display,
for (const auto& layer : layers) {
ATRACE_NAME("DrawLayer");
- canvas->save();
- if (mCapture->isCaptureRunning()) {
+ sk_sp<SkImage> blurInput;
+ if (blurCompositionLayer == layer) {
+ LOG_ALWAYS_FATAL_IF(activeSurface == dstSurface);
+ LOG_ALWAYS_FATAL_IF(canvas == dstCanvas);
+
+ // save a snapshot of the activeSurface to use as input to the blur shaders
+ blurInput = activeSurface->makeImageSnapshot();
+
+ // TODO we could skip this step if we know the blur will cover the entire image
+ // blit the offscreen framebuffer into the destination AHB
+ SkPaint paint;
+ paint.setBlendMode(SkBlendMode::kSrc);
+ if (CC_UNLIKELY(mCapture->isCaptureRunning())) {
+ uint64_t id = mCapture->endOffscreenCapture(&offscreenCaptureState);
+ dstCanvas->drawAnnotation(SkRect::Make(dstCanvas->imageInfo().dimensions()),
+ String8::format("SurfaceID|%" PRId64, id).c_str(),
+ nullptr);
+ dstCanvas->drawImage(blurInput, 0, 0, SkSamplingOptions(), &paint);
+ } else {
+ activeSurface->draw(dstCanvas, 0, 0, SkSamplingOptions(), &paint);
+ }
+
+ // assign dstCanvas to canvas and ensure that the canvas state is up to date
+ canvas = dstCanvas;
+ canvas->save();
+ initCanvas(canvas, display);
+
+ LOG_ALWAYS_FATAL_IF(activeSurface->getCanvas()->getSaveCount() !=
+ dstSurface->getCanvas()->getSaveCount());
+ LOG_ALWAYS_FATAL_IF(activeSurface->getCanvas()->getTotalMatrix() !=
+ dstSurface->getCanvas()->getTotalMatrix());
+
+ // assign dstSurface to activeSurface
+ activeSurface = dstSurface;
+ }
+
+ canvas->save();
+ if (CC_UNLIKELY(mCapture->isCaptureRunning())) {
// Record the name of the layer if the capture is running.
std::stringstream layerSettings;
PrintTo(*layer, &layerSettings);
@@ -654,34 +726,42 @@ status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display,
canvas->drawAnnotation(SkRect::MakeEmpty(), layer->name.c_str(),
SkData::MakeWithCString(layerSettings.str().c_str()));
}
-
// Layers have a local transform that should be applied to them
canvas->concat(getSkM44(layer->geometry.positionTransform).asM33());
- SkPaint paint;
- const auto& bounds = layer->geometry.boundaries;
- const auto dest = getSkRect(bounds);
- const auto layerRect = canvas->getTotalMatrix().mapRect(dest);
- std::unordered_map<uint32_t, sk_sp<SkImage>> cachedBlurs;
- if (mBlurFilter) {
+ const auto bounds = getSkRect(layer->geometry.boundaries);
+ if (mBlurFilter && layerHasBlur(layer)) {
+ std::unordered_map<uint32_t, sk_sp<SkImage>> cachedBlurs;
+
+ // if multiple layers have blur, then we need to take a snapshot now because
+ // only the lowest layer will have blurImage populated earlier
+ if (!blurInput) {
+ blurInput = activeSurface->makeImageSnapshot();
+ }
+ // rect to be blurred in the coordinate space of blurInput
+ const auto blurRect = canvas->getTotalMatrix().mapRect(bounds);
+
if (layer->backgroundBlurRadius > 0) {
ATRACE_NAME("BackgroundBlur");
- auto blurredSurface = mBlurFilter->generate(canvas, surface,
- layer->backgroundBlurRadius, layerRect);
- cachedBlurs[layer->backgroundBlurRadius] = blurredSurface;
+ auto blurredImage =
+ mBlurFilter->generate(grContext.get(), layer->backgroundBlurRadius,
+ blurInput, blurRect);
- drawBlurRegion(canvas, getBlurRegion(layer), layerRect, blurredSurface);
+ cachedBlurs[layer->backgroundBlurRadius] = blurredImage;
+
+ mBlurFilter->drawBlurRegion(canvas, getBlurRegion(layer), blurRect, blurredImage,
+ blurInput);
}
- if (layer->blurRegions.size() > 0) {
- for (auto region : layer->blurRegions) {
- if (cachedBlurs[region.blurRadius]) {
- continue;
- }
+ for (auto region : layer->blurRegions) {
+ if (cachedBlurs[region.blurRadius] == nullptr) {
ATRACE_NAME("BlurRegion");
- auto blurredSurface =
- mBlurFilter->generate(canvas, surface, region.blurRadius, layerRect);
- cachedBlurs[region.blurRadius] = blurredSurface;
+ cachedBlurs[region.blurRadius] =
+ mBlurFilter->generate(grContext.get(), region.blurRadius, blurInput,
+ blurRect);
}
+
+ mBlurFilter->drawBlurRegion(canvas, region, blurRect,
+ cachedBlurs[region.blurRadius], blurInput);
}
}
@@ -695,6 +775,7 @@ status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display,
: layer->sourceDataspace)
: ui::Dataspace::UNKNOWN;
+ SkPaint paint;
if (layer->source.buffer.buffer) {
ATRACE_NAME("DrawImage");
const auto& item = layer->source.buffer;
@@ -721,7 +802,7 @@ status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display,
// textureTansform was intended to be passed directly into a shader, so when
// building the total matrix with the textureTransform we need to first
// normalize it, then apply the textureTransform, then scale back up.
- texMatrix.preScale(1.0f / bounds.getWidth(), 1.0f / bounds.getHeight());
+ texMatrix.preScale(1.0f / bounds.width(), 1.0f / bounds.height());
texMatrix.postScale(image->width(), image->height());
SkMatrix matrix;
@@ -791,14 +872,10 @@ status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display,
paint.setColorFilter(filter);
- for (const auto effectRegion : layer->blurRegions) {
- drawBlurRegion(canvas, effectRegion, layerRect, cachedBlurs[effectRegion.blurRadius]);
- }
-
if (layer->shadow.length > 0) {
const auto rect = layer->geometry.roundedCornersRadius > 0
? getSkRect(layer->geometry.roundedCornersCrop)
- : dest;
+ : bounds;
drawShadow(canvas, rect, layer->geometry.roundedCornersRadius, layer->shadow);
} else {
// Shadows are assumed to live only on their own layer - it's not valid
@@ -809,7 +886,7 @@ status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display,
if (layer->geometry.roundedCornersRadius > 0) {
canvas->clipRRect(getRoundedRect(layer), true);
}
- canvas->drawRect(dest, paint);
+ canvas->drawRect(bounds, paint);
}
canvas->restore();
}
@@ -817,7 +894,8 @@ status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display,
mCapture->endCapture();
{
ATRACE_NAME("flush surface");
- surface->flush();
+ LOG_ALWAYS_FATAL_IF(activeSurface != dstSurface);
+ activeSurface->flush();
}
if (drawFence != nullptr) {
@@ -874,6 +952,10 @@ inline BlurRegion SkiaGLRenderEngine::getBlurRegion(const LayerSettings* layer)
.bottom = static_cast<int>(rect.fBottom)};
}
+inline bool SkiaGLRenderEngine::layerHasBlur(const LayerSettings* layer) {
+ return layer->backgroundBlurRadius > 0 || layer->blurRegions.size();
+}
+
inline SkColor SkiaGLRenderEngine::getSkColor(const vec4& color) {
return SkColorSetARGB(color.a * 255, color.r * 255, color.g * 255, color.b * 255);
}
@@ -913,53 +995,6 @@ void SkiaGLRenderEngine::drawShadow(SkCanvas* canvas, const SkRect& casterRect,
flags);
}
-void SkiaGLRenderEngine::drawBlurRegion(SkCanvas* canvas, const BlurRegion& effectRegion,
- const SkRect& layerRect, sk_sp<SkImage> blurredImage) {
- ATRACE_CALL();
-
- SkPaint paint;
- paint.setAlpha(static_cast<int>(effectRegion.alpha * 255));
- const auto matrix = getBlurShaderTransform(canvas, layerRect);
- SkSamplingOptions linearSampling(SkFilterMode::kLinear, SkMipmapMode::kNone);
- paint.setShader(blurredImage->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, linearSampling,
- &matrix));
-
- auto rect = SkRect::MakeLTRB(effectRegion.left, effectRegion.top, effectRegion.right,
- effectRegion.bottom);
-
- if (effectRegion.cornerRadiusTL > 0 || effectRegion.cornerRadiusTR > 0 ||
- effectRegion.cornerRadiusBL > 0 || effectRegion.cornerRadiusBR > 0) {
- const SkVector radii[4] =
- {SkVector::Make(effectRegion.cornerRadiusTL, effectRegion.cornerRadiusTL),
- SkVector::Make(effectRegion.cornerRadiusTR, effectRegion.cornerRadiusTR),
- SkVector::Make(effectRegion.cornerRadiusBL, effectRegion.cornerRadiusBL),
- SkVector::Make(effectRegion.cornerRadiusBR, effectRegion.cornerRadiusBR)};
- SkRRect roundedRect;
- roundedRect.setRectRadii(rect, radii);
- canvas->drawRRect(roundedRect, paint);
- } else {
- canvas->drawRect(rect, paint);
- }
-}
-
-SkMatrix SkiaGLRenderEngine::getBlurShaderTransform(const SkCanvas* canvas,
- const SkRect& layerRect) {
- // 1. Apply the blur shader matrix, which scales up the blured surface to its real size
- auto matrix = mBlurFilter->getShaderMatrix();
- // 2. Since the blurred surface has the size of the layer, we align it with the
- // top left corner of the layer position.
- matrix.postConcat(SkMatrix::Translate(layerRect.fLeft, layerRect.fTop));
- // 3. Finally, apply the inverse canvas matrix. The snapshot made in the BlurFilter is in the
- // original surface orientation. The inverse matrix has to be applied to align the blur
- // surface with the current orientation/position of the canvas.
- SkMatrix drawInverse;
- if (canvas->getTotalMatrix().invert(&drawInverse)) {
- matrix.postConcat(drawInverse);
- }
-
- return matrix;
-}
-
EGLContext SkiaGLRenderEngine::createEglContext(EGLDisplay display, EGLConfig config,
EGLContext shareContext,
std::optional<ContextPriority> contextPriority,
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.h b/libs/renderengine/skia/SkiaGLRenderEngine.h
index 810fc2ae8f..5779ae679b 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.h
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.h
@@ -61,6 +61,7 @@ public:
bool isProtected() const override { return mInProtectedContext; }
bool supportsProtectedContent() const override;
bool useProtectedContext(bool useProtectedContext) override;
+ bool supportsBackgroundBlur() override { return mBlurFilter != nullptr; }
protected:
void dump(std::string& result) override;
@@ -81,17 +82,16 @@ private:
inline SkRect getSkRect(const Rect& layer);
inline SkRRect getRoundedRect(const LayerSettings* layer);
inline BlurRegion getBlurRegion(const LayerSettings* layer);
+ inline bool layerHasBlur(const LayerSettings* layer);
inline SkColor getSkColor(const vec4& color);
inline SkM44 getSkM44(const mat4& matrix);
inline SkPoint3 getSkPoint3(const vec3& vector);
base::unique_fd flush();
bool waitFence(base::unique_fd fenceFd);
+ void initCanvas(SkCanvas* canvas, const DisplaySettings& display);
void drawShadow(SkCanvas* canvas, const SkRect& casterRect, float casterCornerRadius,
const ShadowSettings& shadowSettings);
- void drawBlurRegion(SkCanvas* canvas, const BlurRegion& blurRegion, const SkRect& layerRect,
- sk_sp<SkImage> blurredImage);
- SkMatrix getBlurShaderTransform(const SkCanvas* canvas, const SkRect& layerRect);
// If mUseColorManagement is correct and layer needsLinearEffect, it returns a linear runtime
// shader. Otherwise it returns the input shader.
sk_sp<SkShader> createRuntimeEffectShader(sk_sp<SkShader> shader, const LayerSettings* layer,
diff --git a/libs/renderengine/skia/debug/SkiaCapture.cpp b/libs/renderengine/skia/debug/SkiaCapture.cpp
index e9cfead8b6..40f5cf299d 100644
--- a/libs/renderengine/skia/debug/SkiaCapture.cpp
+++ b/libs/renderengine/skia/debug/SkiaCapture.cpp
@@ -41,11 +41,11 @@ SkiaCapture::~SkiaCapture() {
mTimer.stop();
}
-SkCanvas* SkiaCapture::tryCapture(SkSurface* surface) {
+SkCanvas* SkiaCapture::tryCapture(SkSurface* surface) NO_THREAD_SAFETY_ANALYSIS {
ATRACE_CALL();
// If we are not running yet, set up.
- if (!mCaptureRunning) {
+ if (CC_LIKELY(!mCaptureRunning)) {
mTimerInterval = std::chrono::milliseconds(
base::GetIntProperty(PROPERTY_DEBUG_RENDERENGINE_CAPTURE_SKIA_MS, 0));
// Set up the multi-frame capture. If we fail to set it up, then just return canvas.
@@ -56,7 +56,8 @@ SkCanvas* SkiaCapture::tryCapture(SkSurface* surface) {
// Start the new timer. When timer expires, write to file.
mTimer.setTimeout(
[this] {
- endCapture();
+ const std::scoped_lock lock(mMutex);
+ LOG_ALWAYS_FATAL_IF(mCurrentPageCanvas != nullptr);
writeToFile();
// To avoid going in circles, set the flag to 0. This way the capture can be
// restarted just by setting the flag and without restarting the process.
@@ -65,29 +66,82 @@ SkCanvas* SkiaCapture::tryCapture(SkSurface* surface) {
mTimerInterval);
}
+ mMutex.lock();
+
// Create a canvas pointer, fill it.
- SkCanvas* pictureCanvas = mMultiPic->beginPage(surface->width(), surface->height());
+ mCurrentPageCanvas = mMultiPic->beginPage(surface->width(), surface->height());
// Setting up an nway canvas is common to any kind of capture.
mNwayCanvas = std::make_unique<SkNWayCanvas>(surface->width(), surface->height());
mNwayCanvas->addCanvas(surface->getCanvas());
- mNwayCanvas->addCanvas(pictureCanvas);
+ mNwayCanvas->addCanvas(mCurrentPageCanvas);
return mNwayCanvas.get();
}
-void SkiaCapture::endCapture() {
+void SkiaCapture::endCapture() NO_THREAD_SAFETY_ANALYSIS {
ATRACE_CALL();
// Don't end anything if we are not running.
- if (!mCaptureRunning) {
+ if (CC_LIKELY(!mCaptureRunning)) {
return;
}
// Reset the canvas pointer.
+ mCurrentPageCanvas = nullptr;
mNwayCanvas.reset();
// End page.
if (mMultiPic) {
mMultiPic->endPage();
}
+ mMutex.unlock();
+}
+
+SkCanvas* SkiaCapture::tryOffscreenCapture(SkSurface* surface, OffscreenState* state) {
+ ATRACE_CALL();
+ // Don't start anything if we are not running.
+ if (CC_LIKELY(!mCaptureRunning)) {
+ return surface->getCanvas();
+ }
+
+ // Create a canvas pointer, fill it.
+ state->offscreenRecorder = std::make_unique<SkPictureRecorder>();
+ SkCanvas* pictureCanvas =
+ state->offscreenRecorder->beginRecording(surface->width(), surface->height());
+
+ // Setting up an nway canvas is common to any kind of capture.
+ state->offscreenCanvas = std::make_unique<SkNWayCanvas>(surface->width(), surface->height());
+ state->offscreenCanvas->addCanvas(surface->getCanvas());
+ state->offscreenCanvas->addCanvas(pictureCanvas);
+
+ return state->offscreenCanvas.get();
+}
+
+uint64_t SkiaCapture::endOffscreenCapture(OffscreenState* state) {
+ ATRACE_CALL();
+ // Don't end anything if we are not running.
+ if (CC_LIKELY(!mCaptureRunning)) {
+ return 0;
+ }
+
+ // compute the uniqueID for this capture
+ static std::atomic<uint64_t> nextID{1};
+ const uint64_t uniqueID = nextID.fetch_add(1, std::memory_order_relaxed);
+
+ // Reset the canvas pointer as we are no longer drawing into it
+ state->offscreenCanvas.reset();
+
+ // Record the offscreen as a picture in the currently active page.
+ SkRect bounds =
+ SkRect::Make(state->offscreenRecorder->getRecordingCanvas()->imageInfo().dimensions());
+ mCurrentPageCanvas
+ ->drawAnnotation(bounds,
+ String8::format("OffscreenLayerDraw|%" PRId64, uniqueID).c_str(),
+ nullptr);
+ mCurrentPageCanvas->drawPicture(state->offscreenRecorder->finishRecordingAsPicture());
+
+ // Reset the offscreen picture recorder
+ state->offscreenRecorder.reset();
+
+ return uniqueID;
}
void SkiaCapture::writeToFile() {
diff --git a/libs/renderengine/skia/debug/SkiaCapture.h b/libs/renderengine/skia/debug/SkiaCapture.h
index eaaf598bd0..5e18e60f93 100644
--- a/libs/renderengine/skia/debug/SkiaCapture.h
+++ b/libs/renderengine/skia/debug/SkiaCapture.h
@@ -18,8 +18,12 @@
#include <SkDocument.h>
#include <SkNWayCanvas.h>
+#include <SkPictureRecorder.h>
#include <SkSurface.h>
+
#include <chrono>
+#include <mutex>
+
#include "CaptureTimer.h"
#include "tools/SkSharingProc.h"
@@ -48,6 +52,16 @@ public:
// Returns whether the capture is running.
bool isCaptureRunning() { return mCaptureRunning; }
+ // Offscreen state member variables are private to SkiaCapture, but the allocation
+ // and lifetime is managed by the caller. This enables nested offscreen
+ // captures to occur.
+ struct OffscreenState {
+ std::unique_ptr<SkPictureRecorder> offscreenRecorder;
+ std::unique_ptr<SkNWayCanvas> offscreenCanvas;
+ };
+ SkCanvas* tryOffscreenCapture(SkSurface* surface, OffscreenState* state);
+ uint64_t endOffscreenCapture(OffscreenState* state);
+
private:
// Performs the first-frame work of a multi frame SKP capture. Returns true if successful.
bool setupMultiFrameCapture();
@@ -61,10 +75,16 @@ private:
std::unique_ptr<SkSharingSerialContext> mSerialContext;
std::unique_ptr<SkNWayCanvas> mNwayCanvas;
+ SkCanvas* mCurrentPageCanvas = nullptr;
+
// Capturing and interval control.
bool mCaptureRunning = false;
CaptureTimer mTimer;
Interval mTimerInterval = 0ms;
+
+ // Mutex to ensure that a frame in progress when the timer fires is allowed to run to
+ // completion before we write the file to disk.
+ std::mutex mMutex;
};
} // namespace skia
diff --git a/libs/renderengine/skia/filters/BlurFilter.cpp b/libs/renderengine/skia/filters/BlurFilter.cpp
index 87b1a7c8f7..5960e48f7b 100644
--- a/libs/renderengine/skia/filters/BlurFilter.cpp
+++ b/libs/renderengine/skia/filters/BlurFilter.cpp
@@ -20,6 +20,7 @@
#include <SkCanvas.h>
#include <SkData.h>
#include <SkPaint.h>
+#include <SkRRect.h>
#include <SkRuntimeEffect.h>
#include <SkSize.h>
#include <SkString.h>
@@ -34,17 +35,14 @@ namespace skia {
BlurFilter::BlurFilter() {
SkString blurString(R"(
in shader input;
- uniform float in_inverseScale;
uniform float2 in_blurOffset;
half4 main(float2 xy) {
- float2 scaled_xy = float2(xy.x * in_inverseScale, xy.y * in_inverseScale);
-
- half4 c = sample(input, scaled_xy);
- c += sample(input, scaled_xy + float2( in_blurOffset.x, in_blurOffset.y));
- c += sample(input, scaled_xy + float2( in_blurOffset.x, -in_blurOffset.y));
- c += sample(input, scaled_xy + float2(-in_blurOffset.x, in_blurOffset.y));
- c += sample(input, scaled_xy + float2(-in_blurOffset.x, -in_blurOffset.y));
+ half4 c = sample(input, xy);
+ c += sample(input, xy + float2( in_blurOffset.x, in_blurOffset.y));
+ c += sample(input, xy + float2( in_blurOffset.x, -in_blurOffset.y));
+ c += sample(input, xy + float2(-in_blurOffset.x, in_blurOffset.y));
+ c += sample(input, xy + float2(-in_blurOffset.x, -in_blurOffset.y));
return half4(c.rgb * 0.2, 1.0);
}
@@ -55,10 +53,26 @@ BlurFilter::BlurFilter() {
LOG_ALWAYS_FATAL("RuntimeShader error: %s", error.c_str());
}
mBlurEffect = std::move(blurEffect);
+
+ SkString mixString(R"(
+ in shader blurredInput;
+ in shader originalInput;
+ uniform float mixFactor;
+
+ half4 main(float2 xy) {
+ return half4(mix(sample(originalInput), sample(blurredInput), mixFactor));
+ }
+ )");
+
+ auto [mixEffect, mixError] = SkRuntimeEffect::Make(mixString);
+ if (!mixEffect) {
+ LOG_ALWAYS_FATAL("RuntimeShader error: %s", mixError.c_str());
+ }
+ mMixEffect = std::move(mixEffect);
}
-sk_sp<SkImage> BlurFilter::generate(SkCanvas* canvas, const sk_sp<SkSurface> input,
- const uint32_t blurRadius, SkRect rect) const {
+sk_sp<SkImage> BlurFilter::generate(GrRecordingContext* context, const uint32_t blurRadius,
+ const sk_sp<SkImage> input, const SkRect& blurRect) const {
// Kawase is an approximation of Gaussian, but it behaves differently from it.
// A radius transformation is required for approximating them, and also to introduce
// non-integer steps, necessary to smoothly interpolate large radii.
@@ -66,40 +80,110 @@ sk_sp<SkImage> BlurFilter::generate(SkCanvas* canvas, const sk_sp<SkSurface> inp
float numberOfPasses = std::min(kMaxPasses, (uint32_t)ceil(tmpRadius));
float radiusByPasses = tmpRadius / (float)numberOfPasses;
- SkImageInfo scaledInfo = SkImageInfo::MakeN32Premul((float)rect.width() * kInputScale,
- (float)rect.height() * kInputScale);
+ // create blur surface with the bit depth and colorspace of the original surface
+ SkImageInfo scaledInfo = input->imageInfo().makeWH(blurRect.width() * kInputScale,
+ blurRect.height() * kInputScale);
const float stepX = radiusByPasses;
const float stepY = radiusByPasses;
- // start by drawing and downscaling and doing the first blur pass
+ // For sampling Skia's API expects the inverse of what logically seems appropriate. In this
+ // case you might expect Translate(blurRect.fLeft, blurRect.fTop) X Scale(kInverseInputScale)
+ // but instead we must do the inverse.
+ SkMatrix blurMatrix = SkMatrix::Translate(-blurRect.fLeft, -blurRect.fTop);
+ blurMatrix.postScale(kInputScale, kInputScale);
+
+ // start by downscaling and doing the first blur pass
SkSamplingOptions linear(SkFilterMode::kLinear, SkMipmapMode::kNone);
SkRuntimeShaderBuilder blurBuilder(mBlurEffect);
blurBuilder.child("input") =
- input->makeImageSnapshot(rect.round())
- ->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, linear);
- blurBuilder.uniform("in_inverseScale") = kInverseInputScale;
- blurBuilder.uniform("in_blurOffset") =
- SkV2{stepX * kInverseInputScale, stepY * kInverseInputScale};
+ input->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, linear, blurMatrix);
+ blurBuilder.uniform("in_blurOffset") = SkV2{stepX * kInputScale, stepY * kInputScale};
- sk_sp<SkImage> tmpBlur(
- blurBuilder.makeImage(canvas->recordingContext(), nullptr, scaledInfo, false));
+ sk_sp<SkImage> tmpBlur(blurBuilder.makeImage(context, nullptr, scaledInfo, false));
// And now we'll build our chain of scaled blur stages
- blurBuilder.uniform("in_inverseScale") = 1.0f;
for (auto i = 1; i < numberOfPasses; i++) {
const float stepScale = (float)i * kInputScale;
blurBuilder.child("input") =
tmpBlur->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, linear);
blurBuilder.uniform("in_blurOffset") = SkV2{stepX * stepScale, stepY * stepScale};
- tmpBlur = blurBuilder.makeImage(canvas->recordingContext(), nullptr, scaledInfo, false);
+ tmpBlur = blurBuilder.makeImage(context, nullptr, scaledInfo, false);
}
return tmpBlur;
}
-SkMatrix BlurFilter::getShaderMatrix() const {
- return SkMatrix::Scale(kInverseInputScale, kInverseInputScale);
+static SkMatrix getShaderTransform(const SkCanvas* canvas, const SkRect& blurRect, float scale) {
+ // 1. Apply the blur shader matrix, which scales up the blured surface to its real size
+ auto matrix = SkMatrix::Scale(scale, scale);
+ // 2. Since the blurred surface has the size of the layer, we align it with the
+ // top left corner of the layer position.
+ matrix.postConcat(SkMatrix::Translate(blurRect.fLeft, blurRect.fTop));
+ // 3. Finally, apply the inverse canvas matrix. The snapshot made in the BlurFilter is in the
+ // original surface orientation. The inverse matrix has to be applied to align the blur
+ // surface with the current orientation/position of the canvas.
+ SkMatrix drawInverse;
+ if (canvas != nullptr && canvas->getTotalMatrix().invert(&drawInverse)) {
+ matrix.postConcat(drawInverse);
+ }
+ return matrix;
+}
+
+void BlurFilter::drawBlurRegion(SkCanvas* canvas, const BlurRegion& effectRegion,
+ const SkRect& blurRect, sk_sp<SkImage> blurredImage,
+ sk_sp<SkImage> input) {
+ ATRACE_CALL();
+
+ SkPaint paint;
+ paint.setAlphaf(effectRegion.alpha);
+ if (effectRegion.alpha == 1.0f) {
+ paint.setBlendMode(SkBlendMode::kSrc);
+ }
+
+ const auto blurMatrix = getShaderTransform(canvas, blurRect, kInverseInputScale);
+ SkSamplingOptions linearSampling(SkFilterMode::kLinear, SkMipmapMode::kNone);
+ const auto blurShader = blurredImage->makeShader(SkTileMode::kClamp, SkTileMode::kClamp,
+ linearSampling, &blurMatrix);
+
+ if (effectRegion.blurRadius < kMaxCrossFadeRadius) {
+ // For sampling Skia's API expects the inverse of what logically seems appropriate. In this
+ // case you might expect the matrix to simply be the canvas matrix.
+ SkMatrix inputMatrix;
+ if (!canvas->getTotalMatrix().invert(&inputMatrix)) {
+ ALOGE("matrix was unable to be inverted");
+ }
+
+ SkRuntimeShaderBuilder blurBuilder(mMixEffect);
+ blurBuilder.child("blurredInput") = blurShader;
+ blurBuilder.child("originalInput") =
+ input->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, linearSampling,
+ inputMatrix);
+ blurBuilder.uniform("mixFactor") = effectRegion.blurRadius / kMaxCrossFadeRadius;
+
+ paint.setShader(blurBuilder.makeShader(nullptr, true));
+ } else {
+ paint.setShader(blurShader);
+ }
+
+ // TODO we should AA at least the drawRoundRect which would mean no SRC blending
+ // TODO this round rect calculation doesn't match the one used to draw in RenderEngine
+ auto rect = SkRect::MakeLTRB(effectRegion.left, effectRegion.top, effectRegion.right,
+ effectRegion.bottom);
+
+ if (effectRegion.cornerRadiusTL > 0 || effectRegion.cornerRadiusTR > 0 ||
+ effectRegion.cornerRadiusBL > 0 || effectRegion.cornerRadiusBR > 0) {
+ const SkVector radii[4] =
+ {SkVector::Make(effectRegion.cornerRadiusTL, effectRegion.cornerRadiusTL),
+ SkVector::Make(effectRegion.cornerRadiusTR, effectRegion.cornerRadiusTR),
+ SkVector::Make(effectRegion.cornerRadiusBL, effectRegion.cornerRadiusBL),
+ SkVector::Make(effectRegion.cornerRadiusBR, effectRegion.cornerRadiusBR)};
+ SkRRect roundedRect;
+ roundedRect.setRectRadii(rect, radii);
+ canvas->drawRRect(roundedRect, paint);
+ } else {
+ canvas->drawRect(rect, paint);
+ }
}
} // namespace skia
diff --git a/libs/renderengine/skia/filters/BlurFilter.h b/libs/renderengine/skia/filters/BlurFilter.h
index 08641c913d..731ba11483 100644
--- a/libs/renderengine/skia/filters/BlurFilter.h
+++ b/libs/renderengine/skia/filters/BlurFilter.h
@@ -20,6 +20,7 @@
#include <SkImage.h>
#include <SkRuntimeEffect.h>
#include <SkSurface.h>
+#include <ui/BlurRegion.h>
using namespace std;
@@ -48,13 +49,15 @@ public:
virtual ~BlurFilter(){};
// Execute blur, saving it to a texture
- sk_sp<SkImage> generate(SkCanvas* canvas, const sk_sp<SkSurface> input, const uint32_t radius,
- SkRect rect) const;
- // Returns a matrix that should be applied to the blur shader
- SkMatrix getShaderMatrix() const;
+ sk_sp<SkImage> generate(GrRecordingContext* context, const uint32_t radius,
+ const sk_sp<SkImage> blurInput, const SkRect& blurRect) const;
+
+ void drawBlurRegion(SkCanvas* canvas, const BlurRegion& blurRegion, const SkRect& blurRect,
+ sk_sp<SkImage> blurredImage, sk_sp<SkImage> input);
private:
sk_sp<SkRuntimeEffect> mBlurEffect;
+ sk_sp<SkRuntimeEffect> mMixEffect;
};
} // namespace skia
diff --git a/libs/renderengine/tests/Android.bp b/libs/renderengine/tests/Android.bp
index 51c702884b..d0e19dd4e2 100644
--- a/libs/renderengine/tests/Android.bp
+++ b/libs/renderengine/tests/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_test {
name: "librenderengine_test",
defaults: ["skia_deps", "surfaceflinger_defaults"],
diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp
index 58afe6ee75..500a90b6ef 100644
--- a/libs/renderengine/tests/RenderEngineTest.cpp
+++ b/libs/renderengine/tests/RenderEngineTest.cpp
@@ -914,13 +914,6 @@ void RenderEngineTest::fillBufferWithRoundedCorners() {
template <typename SourceVariant>
void RenderEngineTest::fillBufferAndBlurBackground() {
- char value[PROPERTY_VALUE_MAX];
- property_get("ro.surface_flinger.supports_background_blur", value, "0");
- if (!atoi(value)) {
- // This device doesn't support blurs, no-op.
- return;
- }
-
auto blurRadius = 50;
auto center = DEFAULT_DISPLAY_WIDTH / 2;
@@ -950,15 +943,20 @@ void RenderEngineTest::fillBufferAndBlurBackground() {
blurLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR;
blurLayer.geometry.boundaries = fullscreenRect().toFloatRect();
blurLayer.backgroundBlurRadius = blurRadius;
+ SourceVariant::fillColor(blurLayer, 0.0f, 0.0f, 1.0f, this);
blurLayer.alpha = 0;
layers.push_back(&blurLayer);
invokeDraw(settings, layers);
- expectBufferColor(Rect(center - 1, center - 5, center, center + 5), 150, 150, 0, 255,
- 50 /* tolerance */);
- expectBufferColor(Rect(center, center - 5, center + 1, center + 5), 150, 150, 0, 255,
- 50 /* tolerance */);
+ // solid color
+ expectBufferColor(Rect(0, 0, 1, 1), 255, 0, 0, 255, 0 /* tolerance */);
+
+ if (mRE->supportsBackgroundBlur()) {
+ // blurred color (downsampling should result in the center color being close to 128)
+ expectBufferColor(Rect(center - 1, center - 5, center + 1, center + 5), 128, 128, 0, 255,
+ 10 /* tolerance */);
+ }
}
template <typename SourceVariant>
diff --git a/libs/renderengine/tests/RenderEngineThreadedTest.cpp b/libs/renderengine/tests/RenderEngineThreadedTest.cpp
index 02ff06f393..08b672a99f 100644
--- a/libs/renderengine/tests/RenderEngineThreadedTest.cpp
+++ b/libs/renderengine/tests/RenderEngineThreadedTest.cpp
@@ -144,6 +144,17 @@ TEST_F(RenderEngineThreadedTest, cleanupPostRender_returnsTrue) {
ASSERT_EQ(true, result);
}
+TEST_F(RenderEngineThreadedTest, supportsBackgroundBlur_returnsFalse) {
+ EXPECT_CALL(*mRenderEngine, supportsBackgroundBlur()).WillOnce(Return(false));
+ status_t result = mThreadedRE->supportsBackgroundBlur();
+ ASSERT_EQ(false, result);
+}
+
+TEST_F(RenderEngineThreadedTest, supportsBackgroundBlur_returnsTrue) {
+ EXPECT_CALL(*mRenderEngine, supportsBackgroundBlur()).WillOnce(Return(true));
+ status_t result = mThreadedRE->supportsBackgroundBlur();
+ ASSERT_EQ(true, result);
+}
TEST_F(RenderEngineThreadedTest, drawLayers) {
renderengine::DisplaySettings settings;
std::vector<const renderengine::LayerSettings*> layers;
diff --git a/libs/renderengine/threaded/RenderEngineThreaded.cpp b/libs/renderengine/threaded/RenderEngineThreaded.cpp
index 3b97f5659e..f4481358cf 100644
--- a/libs/renderengine/threaded/RenderEngineThreaded.cpp
+++ b/libs/renderengine/threaded/RenderEngineThreaded.cpp
@@ -315,6 +315,21 @@ int RenderEngineThreaded::getContextPriority() {
return resultFuture.get();
}
+bool RenderEngineThreaded::supportsBackgroundBlur() {
+ std::promise<bool> resultPromise;
+ std::future<bool> resultFuture = resultPromise.get_future();
+ {
+ std::lock_guard lock(mThreadMutex);
+ mFunctionCalls.push([&resultPromise](renderengine::RenderEngine& instance) {
+ ATRACE_NAME("REThreaded::supportsBackgroundBlur");
+ bool returnValue = instance.supportsBackgroundBlur();
+ resultPromise.set_value(returnValue);
+ });
+ }
+ mCondition.notify_one();
+ return resultFuture.get();
+}
+
} // namespace threaded
} // namespace renderengine
} // namespace android
diff --git a/libs/renderengine/threaded/RenderEngineThreaded.h b/libs/renderengine/threaded/RenderEngineThreaded.h
index 8b1e2dec5a..8279cbcd09 100644
--- a/libs/renderengine/threaded/RenderEngineThreaded.h
+++ b/libs/renderengine/threaded/RenderEngineThreaded.h
@@ -64,6 +64,7 @@ public:
void cleanFramebufferCache() override;
int getContextPriority() override;
+ bool supportsBackgroundBlur() override;
private:
void threadMain(CreateInstanceFactory factory);
diff --git a/libs/sensor/Android.bp b/libs/sensor/Android.bp
index e8154a6931..497c33c386 100644
--- a/libs/sensor/Android.bp
+++ b/libs/sensor/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library_shared {
name: "libsensor",
diff --git a/libs/sensor/ISensorServer.cpp b/libs/sensor/ISensorServer.cpp
index a6b0aaf0b5..a6cacad374 100644
--- a/libs/sensor/ISensorServer.cpp
+++ b/libs/sensor/ISensorServer.cpp
@@ -91,13 +91,14 @@ public:
}
virtual sp<ISensorEventConnection> createSensorEventConnection(const String8& packageName,
- int mode, const String16& opPackageName)
+ int mode, const String16& opPackageName, const String16& attributionTag)
{
Parcel data, reply;
data.writeInterfaceToken(ISensorServer::getInterfaceDescriptor());
data.writeString8(packageName);
data.writeInt32(mode);
data.writeString16(opPackageName);
+ data.writeString16(attributionTag);
remote()->transact(CREATE_SENSOR_EVENT_CONNECTION, data, &reply);
return interface_cast<ISensorEventConnection>(reply.readStrongBinder());
}
@@ -170,8 +171,9 @@ status_t BnSensorServer::onTransact(
String8 packageName = data.readString8();
int32_t mode = data.readInt32();
const String16& opPackageName = data.readString16();
+ const String16& attributionTag = data.readString16();
sp<ISensorEventConnection> connection(createSensorEventConnection(packageName, mode,
- opPackageName));
+ opPackageName, attributionTag));
reply->writeStrongBinder(IInterface::asBinder(connection));
return NO_ERROR;
}
diff --git a/libs/sensor/Sensor.cpp b/libs/sensor/Sensor.cpp
index 9d817ae0bd..240738d42d 100644
--- a/libs/sensor/Sensor.cpp
+++ b/libs/sensor/Sensor.cpp
@@ -468,6 +468,19 @@ void Sensor::setId(int32_t id) {
mUuid.i64[1] = 0;
}
+void Sensor::capMinDelayMicros(int32_t cappedMinDelay) {
+ if (mMinDelay < cappedMinDelay) {
+ mMinDelay = cappedMinDelay;
+ }
+}
+
+void Sensor::capHighestDirectReportRateLevel(int32_t cappedRateLevel) {
+ if (cappedRateLevel < getHighestDirectReportRateLevel()) {
+ mFlags &= ~SENSOR_FLAG_MASK_DIRECT_REPORT;
+ mFlags |= cappedRateLevel << SENSOR_FLAG_SHIFT_DIRECT_REPORT;
+ }
+}
+
int32_t Sensor::getId() const {
return int32_t(mUuid.i64[0]);
}
diff --git a/libs/sensor/SensorManager.cpp b/libs/sensor/SensorManager.cpp
index a4a5d135c0..62f4b4e3e2 100644
--- a/libs/sensor/SensorManager.cpp
+++ b/libs/sensor/SensorManager.cpp
@@ -225,13 +225,14 @@ Sensor const* SensorManager::getDefaultSensor(int type)
return nullptr;
}
-sp<SensorEventQueue> SensorManager::createEventQueue(String8 packageName, int mode) {
+sp<SensorEventQueue> SensorManager::createEventQueue(
+ String8 packageName, int mode, String16 attributionTag) {
sp<SensorEventQueue> queue;
Mutex::Autolock _l(mLock);
while (assertStateLocked() == NO_ERROR) {
- sp<ISensorEventConnection> connection =
- mSensorServer->createSensorEventConnection(packageName, mode, mOpPackageName);
+ sp<ISensorEventConnection> connection = mSensorServer->createSensorEventConnection(
+ packageName, mode, mOpPackageName, attributionTag);
if (connection == nullptr) {
// SensorService just died or the app doesn't have required permissions.
ALOGE("createEventQueue: connection is NULL.");
diff --git a/libs/sensor/include/sensor/ISensorServer.h b/libs/sensor/include/sensor/ISensorServer.h
index 402678f0fd..ce5c672da0 100644
--- a/libs/sensor/include/sensor/ISensorServer.h
+++ b/libs/sensor/include/sensor/ISensorServer.h
@@ -45,7 +45,7 @@ public:
virtual Vector<Sensor> getDynamicSensorList(const String16& opPackageName) = 0;
virtual sp<ISensorEventConnection> createSensorEventConnection(const String8& packageName,
- int mode, const String16& opPackageName) = 0;
+ int mode, const String16& opPackageName, const String16& attributionTag) = 0;
virtual int32_t isDataInjectionEnabled() = 0;
virtual sp<ISensorEventConnection> createSensorDirectConnection(const String16& opPackageName,
diff --git a/libs/sensor/include/sensor/Sensor.h b/libs/sensor/include/sensor/Sensor.h
index 324d443106..374b68fab5 100644
--- a/libs/sensor/include/sensor/Sensor.h
+++ b/libs/sensor/include/sensor/Sensor.h
@@ -104,6 +104,9 @@ public:
int32_t getId() const;
void setId(int32_t id);
+ void capMinDelayMicros(int32_t cappedMinDelay);
+ void capHighestDirectReportRateLevel(int32_t cappedRateLevel);
+
// LightFlattenable protocol
inline bool isFixedSize() const { return false; }
size_t getFlattenedSize() const;
diff --git a/libs/sensor/include/sensor/SensorManager.h b/libs/sensor/include/sensor/SensorManager.h
index f09c9c67b4..09ac7edf27 100644
--- a/libs/sensor/include/sensor/SensorManager.h
+++ b/libs/sensor/include/sensor/SensorManager.h
@@ -59,7 +59,8 @@ public:
ssize_t getSensorList(Sensor const* const** list);
ssize_t getDynamicSensorList(Vector<Sensor>& list);
Sensor const* getDefaultSensor(int type);
- sp<SensorEventQueue> createEventQueue(String8 packageName = String8(""), int mode = 0);
+ sp<SensorEventQueue> createEventQueue(
+ String8 packageName = String8(""), int mode = 0, String16 attributionTag = String16(""));
bool isDataInjectionEnabled();
int createDirectChannel(size_t size, int channelType, const native_handle_t *channelData);
void destroyDirectChannel(int channelNativeHandle);
diff --git a/libs/sensor/tests/Android.bp b/libs/sensor/tests/Android.bp
index c9a7668563..8fdb003a5d 100644
--- a/libs/sensor/tests/Android.bp
+++ b/libs/sensor/tests/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_test {
name: "libsensor_test",
diff --git a/libs/sensorprivacy/Android.bp b/libs/sensorprivacy/Android.bp
index 4a606ffec2..00514c4417 100644
--- a/libs/sensorprivacy/Android.bp
+++ b/libs/sensorprivacy/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library_shared {
name: "libsensorprivacy",
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index a8d476250b..de2b9a406b 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -12,6 +12,23 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ default_applicable_licenses: ["frameworks_native_libs_ui_license"],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+ name: "frameworks_native_libs_ui_license",
+ visibility: [":__subpackages__"],
+ license_kinds: [
+ "SPDX-license-identifier-Apache-2.0",
+ ],
+ license_text: [
+ "NOTICE",
+ ],
+}
+
cc_defaults {
name: "libui-defaults",
clang: true,
@@ -77,7 +94,6 @@ cc_library_static {
"libarect",
"libmath",
],
-
}
cc_library_shared {
@@ -105,7 +121,8 @@ cc_library_shared {
srcs: [
"DebugUtils.cpp",
"DeviceProductInfo.cpp",
- "DisplayInfo.cpp",
+ "DisplayMode.cpp",
+ "DynamicDisplayInfo.cpp",
"Fence.cpp",
"FenceTime.cpp",
"FrameStats.cpp",
@@ -120,6 +137,7 @@ cc_library_shared {
"PixelFormat.cpp",
"PublicFormat.cpp",
"Size.cpp",
+ "StaticDisplayInfo.cpp",
],
include_dirs: [
diff --git a/libs/ui/DisplayMode.cpp b/libs/ui/DisplayMode.cpp
new file mode 100644
index 0000000000..cf05dbfb05
--- /dev/null
+++ b/libs/ui/DisplayMode.cpp
@@ -0,0 +1,69 @@
+/*
+ * 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 <ui/DisplayMode.h>
+
+#include <cstdint>
+
+#include <ui/FlattenableHelpers.h>
+
+#define RETURN_IF_ERROR(op) \
+ if (const status_t status = (op); status != OK) return status;
+
+namespace android::ui {
+
+size_t DisplayMode::getFlattenedSize() const {
+ return FlattenableHelpers::getFlattenedSize(id) +
+ FlattenableHelpers::getFlattenedSize(resolution) +
+ FlattenableHelpers::getFlattenedSize(xDpi) +
+ FlattenableHelpers::getFlattenedSize(yDpi) +
+ FlattenableHelpers::getFlattenedSize(refreshRate) +
+ FlattenableHelpers::getFlattenedSize(appVsyncOffset) +
+ FlattenableHelpers::getFlattenedSize(sfVsyncOffset) +
+ FlattenableHelpers::getFlattenedSize(presentationDeadline) +
+ FlattenableHelpers::getFlattenedSize(group);
+}
+
+status_t DisplayMode::flatten(void* buffer, size_t size) const {
+ if (size < getFlattenedSize()) {
+ return NO_MEMORY;
+ }
+ RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, id));
+ RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, resolution));
+ RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, xDpi));
+ RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, yDpi));
+ RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, refreshRate));
+ RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, appVsyncOffset));
+ RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, sfVsyncOffset));
+ RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, presentationDeadline));
+ RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, group));
+ return OK;
+}
+
+status_t DisplayMode::unflatten(const void* buffer, size_t size) {
+ RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &id));
+ RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &resolution));
+ RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &xDpi));
+ RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &yDpi));
+ RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &refreshRate));
+ RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &appVsyncOffset));
+ RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &sfVsyncOffset));
+ RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &presentationDeadline));
+ RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &group));
+ return OK;
+}
+
+} // namespace android::ui
diff --git a/libs/ui/DynamicDisplayInfo.cpp b/libs/ui/DynamicDisplayInfo.cpp
new file mode 100644
index 0000000000..d5c4ef0c17
--- /dev/null
+++ b/libs/ui/DynamicDisplayInfo.cpp
@@ -0,0 +1,72 @@
+/*
+ * 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 <ui/DynamicDisplayInfo.h>
+
+#include <cstdint>
+
+#include <ui/FlattenableHelpers.h>
+
+#define RETURN_IF_ERROR(op) \
+ if (const status_t status = (op); status != OK) return status;
+
+namespace android::ui {
+
+std::optional<ui::DisplayMode> DynamicDisplayInfo::getActiveDisplayMode() const {
+ for (const auto& currMode : supportedDisplayModes) {
+ if (currMode.id == activeDisplayModeId) {
+ return currMode;
+ }
+ }
+ return {};
+}
+
+size_t DynamicDisplayInfo::getFlattenedSize() const {
+ return FlattenableHelpers::getFlattenedSize(supportedDisplayModes) +
+ FlattenableHelpers::getFlattenedSize(activeDisplayModeId) +
+ FlattenableHelpers::getFlattenedSize(supportedColorModes) +
+ FlattenableHelpers::getFlattenedSize(activeColorMode) +
+ FlattenableHelpers::getFlattenedSize(hdrCapabilities) +
+ FlattenableHelpers::getFlattenedSize(autoLowLatencyModeSupported) +
+ FlattenableHelpers::getFlattenedSize(gameContentTypeSupported);
+}
+
+status_t DynamicDisplayInfo::flatten(void* buffer, size_t size) const {
+ if (size < getFlattenedSize()) {
+ return NO_MEMORY;
+ }
+ RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, supportedDisplayModes));
+ RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, activeDisplayModeId));
+ RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, supportedColorModes));
+ RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, activeColorMode));
+ RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, hdrCapabilities));
+ RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, autoLowLatencyModeSupported));
+ RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, gameContentTypeSupported));
+ return OK;
+}
+
+status_t DynamicDisplayInfo::unflatten(const void* buffer, size_t size) {
+ RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &supportedDisplayModes));
+ RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &activeDisplayModeId));
+ RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &supportedColorModes));
+ RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &activeColorMode));
+ RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &hdrCapabilities));
+ RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &autoLowLatencyModeSupported));
+ RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &gameContentTypeSupported));
+ return OK;
+}
+
+} // namespace android::ui
diff --git a/libs/ui/HdrCapabilities.cpp b/libs/ui/HdrCapabilities.cpp
index a5b3e89314..aec2fac780 100644
--- a/libs/ui/HdrCapabilities.cpp
+++ b/libs/ui/HdrCapabilities.cpp
@@ -23,10 +23,6 @@ namespace android {
#pragma clang diagnostic ignored "-Wundefined-reinterpret-cast"
#endif
-HdrCapabilities::~HdrCapabilities() = default;
-HdrCapabilities::HdrCapabilities(HdrCapabilities&& other) noexcept = default;
-HdrCapabilities& HdrCapabilities::operator=(HdrCapabilities&& other) noexcept = default;
-
size_t HdrCapabilities::getFlattenedSize() const {
return sizeof(mMaxLuminance) +
sizeof(mMaxAverageLuminance) +
diff --git a/libs/ui/DisplayInfo.cpp b/libs/ui/StaticDisplayInfo.cpp
index 73a78af186..b66b281394 100644
--- a/libs/ui/DisplayInfo.cpp
+++ b/libs/ui/StaticDisplayInfo.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include <ui/DisplayInfo.h>
+#include <ui/StaticDisplayInfo.h>
#include <cstdint>
@@ -23,16 +23,16 @@
#define RETURN_IF_ERROR(op) \
if (const status_t status = (op); status != OK) return status;
-namespace android {
+namespace android::ui {
-size_t DisplayInfo::getFlattenedSize() const {
+size_t StaticDisplayInfo::getFlattenedSize() const {
return FlattenableHelpers::getFlattenedSize(connectionType) +
FlattenableHelpers::getFlattenedSize(density) +
FlattenableHelpers::getFlattenedSize(secure) +
FlattenableHelpers::getFlattenedSize(deviceProductInfo);
}
-status_t DisplayInfo::flatten(void* buffer, size_t size) const {
+status_t StaticDisplayInfo::flatten(void* buffer, size_t size) const {
if (size < getFlattenedSize()) {
return NO_MEMORY;
}
@@ -43,7 +43,7 @@ status_t DisplayInfo::flatten(void* buffer, size_t size) const {
return OK;
}
-status_t DisplayInfo::unflatten(void const* buffer, size_t size) {
+status_t StaticDisplayInfo::unflatten(void const* buffer, size_t size) {
RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &connectionType));
RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &density));
RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &secure));
@@ -51,4 +51,4 @@ status_t DisplayInfo::unflatten(void const* buffer, size_t size) {
return OK;
}
-} // namespace android
+} // namespace android::ui
diff --git a/libs/ui/include/ui/DisplayMode.h b/libs/ui/include/ui/DisplayMode.h
index 145d7efd19..56f68e7bb2 100644
--- a/libs/ui/include/ui/DisplayMode.h
+++ b/libs/ui/include/ui/DisplayMode.h
@@ -16,15 +16,21 @@
#pragma once
+#include <cstdint>
#include <type_traits>
#include <ui/Size.h>
+#include <utils/Flattenable.h>
#include <utils/Timers.h>
namespace android::ui {
+// This value is going to be serialized over binder so we prefer a fixed width type.
+using DisplayModeId = int32_t;
+
// Mode supported by physical display.
-struct DisplayMode {
+struct DisplayMode : LightFlattenable<DisplayMode> {
+ DisplayModeId id;
ui::Size resolution;
float xDpi = 0;
float yDpi = 0;
@@ -33,9 +39,12 @@ struct DisplayMode {
nsecs_t appVsyncOffset = 0;
nsecs_t sfVsyncOffset = 0;
nsecs_t presentationDeadline = 0;
- int group = -1;
-};
+ int32_t group = -1;
-static_assert(std::is_trivially_copyable_v<DisplayMode>);
+ bool isFixedSize() const { return false; }
+ size_t getFlattenedSize() const;
+ status_t flatten(void* buffer, size_t size) const;
+ status_t unflatten(const void* buffer, size_t size);
+};
} // namespace android::ui
diff --git a/libs/ui/include/ui/DynamicDisplayInfo.h b/libs/ui/include/ui/DynamicDisplayInfo.h
new file mode 100644
index 0000000000..a4c2f71a4c
--- /dev/null
+++ b/libs/ui/include/ui/DynamicDisplayInfo.h
@@ -0,0 +1,60 @@
+/*
+ * 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 "DisplayMode.h"
+
+#include <cstdint>
+#include <optional>
+#include <vector>
+
+#include <ui/GraphicTypes.h>
+#include <ui/HdrCapabilities.h>
+#include <utils/Flattenable.h>
+
+namespace android::ui {
+
+// Information about a physical display which may change on hotplug reconnect.
+struct DynamicDisplayInfo : LightFlattenable<DynamicDisplayInfo> {
+ std::vector<ui::DisplayMode> supportedDisplayModes;
+
+ // This struct is going to be serialized over binder, so
+ // we can't use size_t because it may have different width
+ // in the client process.
+ int32_t activeDisplayModeId;
+
+ std::vector<ui::ColorMode> supportedColorModes;
+ ui::ColorMode activeColorMode;
+ HdrCapabilities hdrCapabilities;
+
+ // True if the display reports support for HDMI 2.1 Auto Low Latency Mode.
+ // For more information, see the HDMI 2.1 specification.
+ bool autoLowLatencyModeSupported;
+
+ // True if the display reports support for Game Content Type.
+ // For more information, see the HDMI 1.4 specification.
+ bool gameContentTypeSupported;
+
+ std::optional<ui::DisplayMode> getActiveDisplayMode() const;
+
+ bool isFixedSize() const { return false; }
+ size_t getFlattenedSize() const;
+ status_t flatten(void* buffer, size_t size) const;
+ status_t unflatten(const void* buffer, size_t size);
+};
+
+} // namespace android::ui
diff --git a/libs/ui/include/ui/FloatRect.h b/libs/ui/include/ui/FloatRect.h
index 69cadfe32e..4c9c7b7ef1 100644
--- a/libs/ui/include/ui/FloatRect.h
+++ b/libs/ui/include/ui/FloatRect.h
@@ -49,6 +49,8 @@ public:
float top = 0.0f;
float right = 0.0f;
float bottom = 0.0f;
+
+ constexpr bool isEmpty() const { return !(left < right && top < bottom); }
};
inline bool operator==(const FloatRect& a, const FloatRect& b) {
diff --git a/libs/ui/include/ui/HdrCapabilities.h b/libs/ui/include/ui/HdrCapabilities.h
index 65ac26cf7e..813addeca6 100644
--- a/libs/ui/include/ui/HdrCapabilities.h
+++ b/libs/ui/include/ui/HdrCapabilities.h
@@ -36,18 +36,12 @@ public:
mMaxAverageLuminance(maxAverageLuminance),
mMinLuminance(minLuminance) {}
- // Make this move-constructable and move-assignable
- HdrCapabilities(HdrCapabilities&& other) noexcept;
- HdrCapabilities& operator=(HdrCapabilities&& other) noexcept;
-
HdrCapabilities()
: mSupportedHdrTypes(),
mMaxLuminance(-1.0f),
mMaxAverageLuminance(-1.0f),
mMinLuminance(-1.0f) {}
- ~HdrCapabilities();
-
const std::vector<ui::Hdr>& getSupportedHdrTypes() const {
return mSupportedHdrTypes;
}
diff --git a/libs/ui/include/ui/DisplayInfo.h b/libs/ui/include/ui/StaticDisplayInfo.h
index 03e0a3886e..e86ca29a2a 100644
--- a/libs/ui/include/ui/DisplayInfo.h
+++ b/libs/ui/include/ui/StaticDisplayInfo.h
@@ -17,17 +17,16 @@
#pragma once
#include <optional>
-#include <type_traits>
#include <ui/DeviceProductInfo.h>
#include <utils/Flattenable.h>
-namespace android {
+namespace android::ui {
enum class DisplayConnectionType { Internal, External };
// Immutable information about physical display.
-struct DisplayInfo : LightFlattenable<DisplayInfo> {
+struct StaticDisplayInfo : LightFlattenable<StaticDisplayInfo> {
DisplayConnectionType connectionType = DisplayConnectionType::Internal;
float density = 0.f;
bool secure = false;
@@ -39,4 +38,4 @@ struct DisplayInfo : LightFlattenable<DisplayInfo> {
status_t unflatten(void const* buffer, size_t size);
};
-} // namespace android
+} // namespace android::ui
diff --git a/libs/ui/include/ui/StretchEffect.h b/libs/ui/include/ui/StretchEffect.h
new file mode 100644
index 0000000000..0803df3828
--- /dev/null
+++ b/libs/ui/include/ui/StretchEffect.h
@@ -0,0 +1,58 @@
+/*
+ * 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/Flattenable.h>
+#include "FloatRect.h"
+
+#include <math.h>
+#include <type_traits>
+
+namespace android {
+
+struct StretchEffect : public LightFlattenablePod<StretchEffect> {
+ FloatRect area = {0, 0, 0, 0};
+ float vectorX = 0;
+ float vectorY = 0;
+ float maxAmount = 0;
+
+ bool operator==(const StretchEffect& other) const {
+ return area == other.area && vectorX == other.vectorX && vectorY == other.vectorY &&
+ maxAmount == other.maxAmount;
+ }
+
+ static bool isZero(float value) {
+ constexpr float NON_ZERO_EPSILON = 0.001f;
+ return fabsf(value) <= NON_ZERO_EPSILON;
+ }
+
+ bool isNoOp() const { return isZero(vectorX) && isZero(vectorY); }
+
+ bool hasEffect() const { return !isNoOp(); }
+
+ void sanitize() {
+ // If the area is empty, or the max amount is zero, then reset back to defaults
+ if (area.isEmpty() || isZero(maxAmount)) {
+ *this = StretchEffect{};
+ }
+ }
+};
+
+static_assert(std::is_trivially_copyable<StretchEffect>::value,
+ "StretchEffect must be trivially copyable to be flattenable");
+
+} // namespace android \ No newline at end of file
diff --git a/libs/ui/include_private/ui/FlattenableHelpers.h b/libs/ui/include_private/ui/FlattenableHelpers.h
index 8e316d8ae0..378f37f077 100644
--- a/libs/ui/include_private/ui/FlattenableHelpers.h
+++ b/libs/ui/include_private/ui/FlattenableHelpers.h
@@ -29,20 +29,29 @@
namespace android {
struct FlattenableHelpers {
- // Helpers for reading and writing POD structures
- template <class T, typename = std::enable_if_t<std::is_trivially_copyable_v<T>>>
+ // Helpers for reading and writing POD structures which are not LightFlattenable.
+ template <class T,
+ typename = std::enable_if_t<
+ std::conjunction_v<std::is_trivially_copyable<T>,
+ std::negation<std::is_base_of<LightFlattenable<T>, T>>>>>
static constexpr size_t getFlattenedSize(const T&) {
return sizeof(T);
}
- template <class T, typename = std::enable_if_t<std::is_trivially_copyable_v<T>>>
+ template <class T,
+ typename = std::enable_if_t<
+ std::conjunction_v<std::is_trivially_copyable<T>,
+ std::negation<std::is_base_of<LightFlattenable<T>, T>>>>>
static status_t flatten(void** buffer, size_t* size, const T& value) {
if (*size < sizeof(T)) return NO_MEMORY;
FlattenableUtils::write(*buffer, *size, value);
return OK;
}
- template <class T, typename = std::enable_if_t<std::is_trivially_copyable_v<T>>>
+ template <class T,
+ typename = std::enable_if_t<
+ std::conjunction_v<std::is_trivially_copyable<T>,
+ std::negation<std::is_base_of<LightFlattenable<T>, T>>>>>
static status_t unflatten(const void** buffer, size_t* size, T* value) {
if (*size < sizeof(T)) return NO_MEMORY;
FlattenableUtils::read(*buffer, *size, *value);
diff --git a/libs/ui/include_vndk/ui/DisplayInfo.h b/libs/ui/include_vndk/ui/DisplayInfo.h
deleted file mode 120000
index 75f14cf66d..0000000000
--- a/libs/ui/include_vndk/ui/DisplayInfo.h
+++ /dev/null
@@ -1 +0,0 @@
-../../include/ui/DisplayInfo.h \ No newline at end of file
diff --git a/libs/ui/include_vndk/ui/StaticDisplayInfo.h b/libs/ui/include_vndk/ui/StaticDisplayInfo.h
new file mode 120000
index 0000000000..541a7a37b9
--- /dev/null
+++ b/libs/ui/include_vndk/ui/StaticDisplayInfo.h
@@ -0,0 +1 @@
+../../include/ui/StaticDisplayInfo.h \ No newline at end of file
diff --git a/libs/ui/tests/Android.bp b/libs/ui/tests/Android.bp
index d005ce8e23..516aad824e 100644
--- a/libs/ui/tests/Android.bp
+++ b/libs/ui/tests/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+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_libs_ui_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_libs_ui_license"],
+}
+
cc_test {
name: "Region_test",
shared_libs: ["libui"],
diff --git a/libs/ui/tests/FlattenableHelpers_test.cpp b/libs/ui/tests/FlattenableHelpers_test.cpp
index db32bc7596..44e20b504d 100644
--- a/libs/ui/tests/FlattenableHelpers_test.cpp
+++ b/libs/ui/tests/FlattenableHelpers_test.cpp
@@ -42,7 +42,7 @@ struct TestLightFlattenable : LightFlattenable<TestLightFlattenable> {
}
status_t unflatten(void const* buffer, size_t size) {
- int value;
+ int32_t value;
FlattenableUtils::read(buffer, size, value);
ptr = std::make_unique<int32_t>(value);
return OK;
@@ -132,5 +132,66 @@ TEST_F(FlattenableHelpersTest, NullOptionalOfLightFlattenable) {
ASSERT_FALSE(valueRead.has_value());
}
+// If a struct is both trivially copyable and light flattenable we should treat it
+// as LigthFlattenable.
+TEST_F(FlattenableHelpersTest, TriviallyCopyableAndLightFlattenableIsFlattenedAsLightFlattenable) {
+ static constexpr int32_t kSizeTag = 1234567;
+ static constexpr int32_t kFlattenTag = 987654;
+ static constexpr int32_t kUnflattenTag = 5926582;
+
+ struct LightFlattenableAndTriviallyCopyable
+ : LightFlattenable<LightFlattenableAndTriviallyCopyable> {
+ int32_t value;
+
+ bool isFixedSize() const { return true; }
+ size_t getFlattenedSize() const { return kSizeTag; }
+
+ status_t flatten(void* buffer, size_t size) const {
+ FlattenableUtils::write(buffer, size, kFlattenTag);
+ return OK;
+ }
+
+ status_t unflatten(void const*, size_t) {
+ value = kUnflattenTag;
+ return OK;
+ }
+ };
+
+ {
+ // Verify that getFlattenedSize uses the LightFlattenable overload
+ LightFlattenableAndTriviallyCopyable foo;
+ EXPECT_EQ(kSizeTag, FlattenableHelpers::getFlattenedSize(foo));
+ }
+
+ {
+ // Verify that flatten uses the LightFlattenable overload
+ std::vector<int8_t> buffer(sizeof(int32_t));
+ auto rawBuffer = reinterpret_cast<void*>(buffer.data());
+ size_t size = buffer.size();
+ LightFlattenableAndTriviallyCopyable foo;
+ ASSERT_EQ(OK, FlattenableHelpers::flatten(&rawBuffer, &size, foo));
+
+ auto rawReadBuffer = reinterpret_cast<const void*>(buffer.data());
+ int32_t value;
+ FlattenableHelpers::unflatten(&rawReadBuffer, &size, &value);
+ EXPECT_EQ(kFlattenTag, value);
+ }
+
+ {
+ // Verify that unflatten uses the LightFlattenable overload
+ std::vector<int8_t> buffer(sizeof(int32_t));
+ auto rawBuffer = reinterpret_cast<void*>(buffer.data());
+ size_t size = buffer.size();
+ int32_t value = 4;
+ ASSERT_EQ(OK, FlattenableHelpers::flatten(&rawBuffer, &size, value));
+
+ auto rawReadBuffer = reinterpret_cast<const void*>(buffer.data());
+
+ LightFlattenableAndTriviallyCopyable foo;
+ FlattenableHelpers::unflatten(&rawReadBuffer, &size, &foo);
+ EXPECT_EQ(kUnflattenTag, foo.value);
+ }
+}
+
} // namespace
} // namespace android
diff --git a/libs/ui/tools/Android.bp b/libs/ui/tools/Android.bp
index fb46c2b20c..c28c303c0c 100644
--- a/libs/ui/tools/Android.bp
+++ b/libs/ui/tools/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+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_libs_ui_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_libs_ui_license"],
+}
+
cc_defaults {
name: "libui_tools_default",
clang_cflags: [
diff --git a/libs/vibrator/Android.bp b/libs/vibrator/Android.bp
index 49bc6bf067..83c250a24f 100644
--- a/libs/vibrator/Android.bp
+++ b/libs/vibrator/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library {
name: "libvibrator",
vendor_available: true,
diff --git a/libs/vibrator/fuzzer/Android.bp b/libs/vibrator/fuzzer/Android.bp
index 802015180e..f2a313cb8a 100644
--- a/libs/vibrator/fuzzer/Android.bp
+++ b/libs/vibrator/fuzzer/Android.bp
@@ -17,6 +17,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"],
+}
+
cc_fuzz {
name: "vibrator_fuzzer",
diff --git a/libs/vr/Android.bp b/libs/vr/Android.bp
index e8176cf6b6..b308895faf 100644
--- a/libs/vr/Android.bp
+++ b/libs/vr/Android.bp
@@ -1,3 +1,14 @@
+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
+ // SPDX-license-identifier-BSD
+ // legacy_notice
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
subdirs = [
"*",
]
diff --git a/libs/vr/libbroadcastring/Android.bp b/libs/vr/libbroadcastring/Android.bp
index 13af470a26..2eb2f9f149 100644
--- a/libs/vr/libbroadcastring/Android.bp
+++ b/libs/vr/libbroadcastring/Android.bp
@@ -1,3 +1,14 @@
+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
+ // SPDX-license-identifier-MIT
+ // SPDX-license-identifier-Unicode-DFS
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library_static {
name: "libbroadcastring",
clang: true,
diff --git a/libs/vr/libbufferhub/Android.bp b/libs/vr/libbufferhub/Android.bp
index 37c19d43f7..45bdd35519 100644
--- a/libs/vr/libbufferhub/Android.bp
+++ b/libs/vr/libbufferhub/Android.bp
@@ -12,6 +12,17 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+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
+ // SPDX-license-identifier-MIT
+ // SPDX-license-identifier-Unicode-DFS
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library_headers {
name: "libbufferhub_headers",
export_include_dirs: ["include"],
diff --git a/libs/vr/libbufferhubqueue/Android.bp b/libs/vr/libbufferhubqueue/Android.bp
index 77c79112de..f372bd79c2 100644
--- a/libs/vr/libbufferhubqueue/Android.bp
+++ b/libs/vr/libbufferhubqueue/Android.bp
@@ -12,6 +12,17 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+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
+ // SPDX-license-identifier-MIT
+ // SPDX-license-identifier-Unicode-DFS
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
sourceFiles = [
"buffer_hub_queue_client.cpp",
"buffer_hub_queue_parcelable.cpp",
diff --git a/libs/vr/libbufferhubqueue/benchmarks/Android.bp b/libs/vr/libbufferhubqueue/benchmarks/Android.bp
index ef1eed6d0a..fc1f376a73 100644
--- a/libs/vr/libbufferhubqueue/benchmarks/Android.bp
+++ b/libs/vr/libbufferhubqueue/benchmarks/Android.bp
@@ -1,4 +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
+ // SPDX-license-identifier-MIT
+ // SPDX-license-identifier-Unicode-DFS
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_benchmark {
srcs: ["buffer_transport_benchmark.cpp"],
shared_libs: [
diff --git a/libs/vr/libbufferhubqueue/tests/Android.bp b/libs/vr/libbufferhubqueue/tests/Android.bp
index a33792177b..e883916f1a 100644
--- a/libs/vr/libbufferhubqueue/tests/Android.bp
+++ b/libs/vr/libbufferhubqueue/tests/Android.bp
@@ -1,4 +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
+ // SPDX-license-identifier-MIT
+ // SPDX-license-identifier-Unicode-DFS
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
header_libraries = [
"libdvr_headers",
]
diff --git a/libs/vr/libdisplay/Android.bp b/libs/vr/libdisplay/Android.bp
index 8c354fbc18..365a676bc4 100644
--- a/libs/vr/libdisplay/Android.bp
+++ b/libs/vr/libdisplay/Android.bp
@@ -12,6 +12,17 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+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
+ // SPDX-license-identifier-MIT
+ // SPDX-license-identifier-Unicode-DFS
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
sourceFiles = [
"display_client.cpp",
"display_manager_client.cpp",
diff --git a/libs/vr/libdvr/Android.bp b/libs/vr/libdvr/Android.bp
index d5a19d3e6c..83c30d7010 100644
--- a/libs/vr/libdvr/Android.bp
+++ b/libs/vr/libdvr/Android.bp
@@ -13,6 +13,17 @@
// limitations under the License.
+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
+ // SPDX-license-identifier-MIT
+ // SPDX-license-identifier-Unicode-DFS
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library_headers {
name: "libdvr_headers",
export_include_dirs: ["include"],
diff --git a/libs/vr/libdvr/tests/Android.bp b/libs/vr/libdvr/tests/Android.bp
index 3260447390..4ed80a4929 100644
--- a/libs/vr/libdvr/tests/Android.bp
+++ b/libs/vr/libdvr/tests/Android.bp
@@ -12,6 +12,17 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+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
+ // SPDX-license-identifier-MIT
+ // SPDX-license-identifier-Unicode-DFS
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_test {
srcs: [
"dvr_display_manager-test.cpp",
diff --git a/libs/vr/libdvrcommon/Android.bp b/libs/vr/libdvrcommon/Android.bp
index e75176846e..9e1e516724 100644
--- a/libs/vr/libdvrcommon/Android.bp
+++ b/libs/vr/libdvrcommon/Android.bp
@@ -12,6 +12,17 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+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
+ // SPDX-license-identifier-MIT
+ // SPDX-license-identifier-Unicode-DFS
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
localIncludeFiles = [
"include",
]
diff --git a/libs/vr/libpdx/Android.bp b/libs/vr/libpdx/Android.bp
index 24ba83048d..c1f6da3b10 100644
--- a/libs/vr/libpdx/Android.bp
+++ b/libs/vr/libpdx/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library_headers {
name: "libpdx_headers",
export_include_dirs: ["private"],
diff --git a/libs/vr/libpdx/fuzz/Android.bp b/libs/vr/libpdx/fuzz/Android.bp
index b36e0deea0..cc32b1822b 100644
--- a/libs/vr/libpdx/fuzz/Android.bp
+++ b/libs/vr/libpdx/fuzz/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_fuzz {
name: "libpdx_service_dispatcher_fuzzer",
clang: true,
diff --git a/libs/vr/libpdx_default_transport/Android.bp b/libs/vr/libpdx_default_transport/Android.bp
index b3534de101..ea73d7a9db 100644
--- a/libs/vr/libpdx_default_transport/Android.bp
+++ b/libs/vr/libpdx_default_transport/Android.bp
@@ -1,3 +1,14 @@
+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
+ // SPDX-license-identifier-MIT
+ // SPDX-license-identifier-Unicode-DFS
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_defaults {
name: "pdx_default_transport_compiler_defaults",
clang: true,
@@ -75,4 +86,3 @@ cc_binary {
"libpdx_default_transport",
],
}
-
diff --git a/libs/vr/libpdx_uds/Android.bp b/libs/vr/libpdx_uds/Android.bp
index 1d6eea29a6..532d1a767c 100644
--- a/libs/vr/libpdx_uds/Android.bp
+++ b/libs/vr/libpdx_uds/Android.bp
@@ -1,3 +1,14 @@
+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
+ // SPDX-license-identifier-MIT
+ // SPDX-license-identifier-Unicode-DFS
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library_static {
name: "libpdx_uds",
clang: true,
diff --git a/libs/vr/libperformance/Android.bp b/libs/vr/libperformance/Android.bp
index 35d3dea9de..5beee359b5 100644
--- a/libs/vr/libperformance/Android.bp
+++ b/libs/vr/libperformance/Android.bp
@@ -12,6 +12,17 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+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
+ // SPDX-license-identifier-MIT
+ // SPDX-license-identifier-Unicode-DFS
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
sourceFiles = [
"performance_client.cpp",
"performance_rpc.cpp",
diff --git a/libs/vr/libvr_manager/Android.bp b/libs/vr/libvr_manager/Android.bp
index 2cd6a28e2f..6f2ada4633 100644
--- a/libs/vr/libvr_manager/Android.bp
+++ b/libs/vr/libvr_manager/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library_static {
name: "libvr_manager",
srcs: [
diff --git a/libs/vr/libvrflinger/Android.bp b/libs/vr/libvrflinger/Android.bp
index abc64bde5a..8aca9a5adc 100644
--- a/libs/vr/libvrflinger/Android.bp
+++ b/libs/vr/libvrflinger/Android.bp
@@ -12,6 +12,17 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+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
+ // SPDX-license-identifier-MIT
+ // SPDX-license-identifier-Unicode-DFS
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
sourceFiles = [
"acquired_buffer.cpp",
"epoll_event_dispatcher.cpp",
diff --git a/libs/vr/libvrflinger/tests/Android.bp b/libs/vr/libvrflinger/tests/Android.bp
index 7fafd3bf50..dafd35454f 100644
--- a/libs/vr/libvrflinger/tests/Android.bp
+++ b/libs/vr/libvrflinger/tests/Android.bp
@@ -1,3 +1,14 @@
+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
+ // SPDX-license-identifier-MIT
+ // SPDX-license-identifier-Unicode-DFS
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
shared_libs = [
"android.hardware.configstore-utils",
"android.hardware.configstore@1.0",
diff --git a/libs/vr/libvrsensor/Android.bp b/libs/vr/libvrsensor/Android.bp
index 85427906f1..8f566a0a20 100644
--- a/libs/vr/libvrsensor/Android.bp
+++ b/libs/vr/libvrsensor/Android.bp
@@ -12,6 +12,17 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+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
+ // SPDX-license-identifier-MIT
+ // SPDX-license-identifier-Unicode-DFS
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
sourceFiles = [
"pose_client.cpp",
"latency_model.cpp",
@@ -52,4 +63,3 @@ cc_library {
header_libs: ["libdvr_headers"],
name: "libvrsensor",
}
-
diff --git a/opengl/Android.bp b/opengl/Android.bp
index 8b94f616c6..3878cb1899 100644
--- a/opengl/Android.bp
+++ b/opengl/Android.bp
@@ -12,6 +12,18 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+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
+ // SPDX-license-identifier-BSD
+ // SPDX-license-identifier-MIT
+ // legacy_notice
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
ndk_headers {
name: "libEGL_headers",
from: "include",
diff --git a/opengl/libs/Android.bp b/opengl/libs/Android.bp
index 5d17561248..7861d62311 100644
--- a/opengl/libs/Android.bp
+++ b/opengl/libs/Android.bp
@@ -1,4 +1,13 @@
// Build the ETC1 library
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library {
name: "libETC1",
srcs: ["ETC1/etc1.cpp"],
diff --git a/opengl/tests/Android.bp b/opengl/tests/Android.bp
index 639f351c69..da717bddf8 100644
--- a/opengl/tests/Android.bp
+++ b/opengl/tests/Android.bp
@@ -1,4 +1,16 @@
+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
+ // SPDX-license-identifier-BSD
+ // SPDX-license-identifier-MIT
+ // legacy_notice
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
subdirs = [
"angeles",
"configdump",
@@ -16,4 +28,3 @@ subdirs = [
"hwc",
"lib",
]
-
diff --git a/opengl/tests/EGLTest/Android.bp b/opengl/tests/EGLTest/Android.bp
index e3912a84e6..51c937614f 100644
--- a/opengl/tests/EGLTest/Android.bp
+++ b/opengl/tests/EGLTest/Android.bp
@@ -1,4 +1,13 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_test {
name: "EGL_test",
diff --git a/opengl/tests/angeles/Android.bp b/opengl/tests/angeles/Android.bp
index 5c398a6323..5b81501241 100644
--- a/opengl/tests/angeles/Android.bp
+++ b/opengl/tests/angeles/Android.bp
@@ -1,5 +1,50 @@
// Copyright 2006 The Android Open Source Project
+package {
+ default_applicable_licenses: [
+ "frameworks_native_opengl_tests_angeles_license",
+ ],
+}
+
+// Added automatically by a large-scale-change that took the approach of
+// 'apply every license found to every target'. While this makes sure we respect
+// every license restriction, it may not be entirely correct.
+//
+// e.g. GPL in an MIT project might only apply to the contrib/ directory.
+//
+// Please consider splitting the single license below into multiple licenses,
+// taking care not to lose any license_kind information, and overriding the
+// default license using the 'licenses: [...]' property on targets as needed.
+//
+// For unused files, consider creating a 'fileGroup' with "//visibility:private"
+// to attach the license to, and including a comment whether the files may be
+// used in the current project.
+//
+// large-scale-change included anything that looked like it might be a license
+// text as a license_text. e.g. LICENSE, NOTICE, COPYING etc.
+//
+// Please consider removing redundant or irrelevant files from 'license_text:'.
+//
+// large-scale-change filtered out the below license kinds as false-positives:
+// SPDX-license-identifier-LGPL
+// SPDX-license-identifier-LGPL-2.1
+// SPDX-license-identifier-LGPL-3.0
+// See: http://go/android-license-faq
+license {
+ name: "frameworks_native_opengl_tests_angeles_license",
+ visibility: [":__subpackages__"],
+ license_kinds: [
+ "SPDX-license-identifier-BSD",
+ "SPDX-license-identifier-MIT",
+ "legacy_notice",
+ ],
+ license_text: [
+ "license-BSD.txt",
+ "license-LGPL.txt",
+ "license.txt",
+ ],
+}
+
cc_test {
name: "angeles",
diff --git a/opengl/tests/configdump/Android.bp b/opengl/tests/configdump/Android.bp
index ee96797030..ffb0c1f0c4 100644
--- a/opengl/tests/configdump/Android.bp
+++ b/opengl/tests/configdump/Android.bp
@@ -1,3 +1,14 @@
+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
+ // SPDX-license-identifier-MIT
+ // SPDX-license-identifier-Unicode-DFS
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_test {
name: "test-opengl-configdump",
diff --git a/opengl/tests/fillrate/Android.bp b/opengl/tests/fillrate/Android.bp
index 689cee42d5..e4bff014fc 100644
--- a/opengl/tests/fillrate/Android.bp
+++ b/opengl/tests/fillrate/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_test {
name: "test-opengl-fillrate",
diff --git a/opengl/tests/filter/Android.bp b/opengl/tests/filter/Android.bp
index 23241e1116..3b92b37634 100644
--- a/opengl/tests/filter/Android.bp
+++ b/opengl/tests/filter/Android.bp
@@ -1,3 +1,14 @@
+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
+ // SPDX-license-identifier-MIT
+ // SPDX-license-identifier-Unicode-DFS
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_test {
name: "test-opengl-filter",
diff --git a/opengl/tests/finish/Android.bp b/opengl/tests/finish/Android.bp
index be20851e8f..c2dfbc35b9 100644
--- a/opengl/tests/finish/Android.bp
+++ b/opengl/tests/finish/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_test {
name: "test-opengl-finish",
diff --git a/opengl/tests/gl2_basic/Android.bp b/opengl/tests/gl2_basic/Android.bp
index f4538adb54..c54bdf335d 100644
--- a/opengl/tests/gl2_basic/Android.bp
+++ b/opengl/tests/gl2_basic/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_test {
name: "test-opengl-gl2_basic",
diff --git a/opengl/tests/gl2_cameraeye/Android.bp b/opengl/tests/gl2_cameraeye/Android.bp
index 00e00dfc91..6b8ee85d9c 100644
--- a/opengl/tests/gl2_cameraeye/Android.bp
+++ b/opengl/tests/gl2_cameraeye/Android.bp
@@ -1,3 +1,12 @@
+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"],
+}
+
android_app {
name: "GL2CameraEye",
// Only compile source java files in this apk.
diff --git a/opengl/tests/gl2_copyTexImage/Android.bp b/opengl/tests/gl2_copyTexImage/Android.bp
index 87fa7ea37d..0a84d254a5 100644
--- a/opengl/tests/gl2_copyTexImage/Android.bp
+++ b/opengl/tests/gl2_copyTexImage/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_test {
name: "test-opengl-gl2_copyTexImage",
diff --git a/opengl/tests/gl2_java/Android.bp b/opengl/tests/gl2_java/Android.bp
index a8e5d7d70b..a33075e3b7 100644
--- a/opengl/tests/gl2_java/Android.bp
+++ b/opengl/tests/gl2_java/Android.bp
@@ -1,6 +1,15 @@
//########################################################################
// OpenGL ES 2.0 Java sample
//########################################################################
+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"],
+}
+
android_app {
name: "GL2Java",
srcs: ["**/*.java"],
diff --git a/opengl/tests/gl2_jni/Android.bp b/opengl/tests/gl2_jni/Android.bp
index 8d4323f9ca..79773cb05f 100644
--- a/opengl/tests/gl2_jni/Android.bp
+++ b/opengl/tests/gl2_jni/Android.bp
@@ -3,6 +3,15 @@
// This makefile builds both an activity and a shared library.
//########################################################################
+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"],
+}
+
android_app {
name: "GL2JNI",
srcs: ["**/*.java"],
diff --git a/opengl/tests/gl2_yuvtex/Android.bp b/opengl/tests/gl2_yuvtex/Android.bp
index b64d94d320..fadf0e8fc5 100644
--- a/opengl/tests/gl2_yuvtex/Android.bp
+++ b/opengl/tests/gl2_yuvtex/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_test {
name: "test-opengl-gl2_yuvtex",
diff --git a/opengl/tests/gl_basic/Android.bp b/opengl/tests/gl_basic/Android.bp
index 5eed17e876..f777401b6f 100644
--- a/opengl/tests/gl_basic/Android.bp
+++ b/opengl/tests/gl_basic/Android.bp
@@ -1,3 +1,14 @@
+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
+ // SPDX-license-identifier-MIT
+ // SPDX-license-identifier-Unicode-DFS
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_test {
name: "test-opengl-gl_basic",
diff --git a/opengl/tests/gl_jni/Android.bp b/opengl/tests/gl_jni/Android.bp
index 0cb129a117..dc46483551 100644
--- a/opengl/tests/gl_jni/Android.bp
+++ b/opengl/tests/gl_jni/Android.bp
@@ -4,6 +4,15 @@
//########################################################################
// Build activity
+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"],
+}
+
android_app {
name: "GLJNI",
srcs: ["**/*.java"],
diff --git a/opengl/tests/gl_perf/Android.bp b/opengl/tests/gl_perf/Android.bp
index 25a317c3e3..ca0f7e8e33 100644
--- a/opengl/tests/gl_perf/Android.bp
+++ b/opengl/tests/gl_perf/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_test {
name: "test-opengl-gl2_perf",
diff --git a/opengl/tests/gl_perfapp/Android.bp b/opengl/tests/gl_perfapp/Android.bp
index 66afb6a82c..2f623462cf 100644
--- a/opengl/tests/gl_perfapp/Android.bp
+++ b/opengl/tests/gl_perfapp/Android.bp
@@ -2,6 +2,15 @@
// OpenGL ES Perf App
// This makefile builds both an activity and a shared library.
//########################################################################
+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"],
+}
+
android_app {
name: "GLPerf",
srcs: ["**/*.java"],
diff --git a/opengl/tests/gl_yuvtex/Android.bp b/opengl/tests/gl_yuvtex/Android.bp
index 9b4924ab82..784418679c 100644
--- a/opengl/tests/gl_yuvtex/Android.bp
+++ b/opengl/tests/gl_yuvtex/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_test {
name: "test-opengl-gl_yuvtex",
diff --git a/opengl/tests/gldual/Android.bp b/opengl/tests/gldual/Android.bp
index 1006d44e47..3d6e677f0d 100644
--- a/opengl/tests/gldual/Android.bp
+++ b/opengl/tests/gldual/Android.bp
@@ -4,6 +4,15 @@
//########################################################################
// Build activity
+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"],
+}
+
android_app {
name: "GLDual",
srcs: ["**/*.java"],
diff --git a/opengl/tests/gralloc/Android.bp b/opengl/tests/gralloc/Android.bp
index 33c3dbaa17..5fb4556697 100644
--- a/opengl/tests/gralloc/Android.bp
+++ b/opengl/tests/gralloc/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_test {
name: "test-opengl-gralloc",
diff --git a/opengl/tests/hwc/Android.bp b/opengl/tests/hwc/Android.bp
index 55f058f922..719eb114a1 100644
--- a/opengl/tests/hwc/Android.bp
+++ b/opengl/tests/hwc/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_defaults {
name: "hwc_tests_defaults",
diff --git a/opengl/tests/lib/Android.bp b/opengl/tests/lib/Android.bp
index 2f6095d8e7..05c9397dfa 100644
--- a/opengl/tests/lib/Android.bp
+++ b/opengl/tests/lib/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library_static {
name: "libglTest",
diff --git a/opengl/tests/lighting1709/Android.bp b/opengl/tests/lighting1709/Android.bp
index e734dd1d2c..79daa26096 100644
--- a/opengl/tests/lighting1709/Android.bp
+++ b/opengl/tests/lighting1709/Android.bp
@@ -1,3 +1,12 @@
+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"],
+}
+
android_test {
name: "LightingTest",
srcs: ["**/*.java"],
diff --git a/opengl/tests/linetex/Android.bp b/opengl/tests/linetex/Android.bp
index dbc2cdbd44..61976e599f 100644
--- a/opengl/tests/linetex/Android.bp
+++ b/opengl/tests/linetex/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_binary {
name: "test-opengl-linetex",
srcs: ["linetex.cpp"],
diff --git a/opengl/tests/swapinterval/Android.bp b/opengl/tests/swapinterval/Android.bp
index eed4dff3a5..a76f4cfb9a 100644
--- a/opengl/tests/swapinterval/Android.bp
+++ b/opengl/tests/swapinterval/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_binary {
name: "test-opengl-swapinterval",
srcs: ["swapinterval.cpp"],
diff --git a/opengl/tests/testFramerate/Android.bp b/opengl/tests/testFramerate/Android.bp
index 5aa83b0753..4334d88749 100644
--- a/opengl/tests/testFramerate/Android.bp
+++ b/opengl/tests/testFramerate/Android.bp
@@ -2,6 +2,15 @@
// Test framerate and look for hiccups
//########################################################################
+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"],
+}
+
android_app {
name: "TestFramerate",
srcs: ["**/*.java"],
diff --git a/opengl/tests/testLatency/Android.bp b/opengl/tests/testLatency/Android.bp
index c516dc3d17..473cb426cf 100644
--- a/opengl/tests/testLatency/Android.bp
+++ b/opengl/tests/testLatency/Android.bp
@@ -1,6 +1,15 @@
//########################################################################
// Test end-to-end latency.
//########################################################################
+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"],
+}
+
android_app {
name: "TestLatency",
sdk_version: "8",
diff --git a/opengl/tests/testPauseResume/Android.bp b/opengl/tests/testPauseResume/Android.bp
index 810e895ce2..8171e1fc8e 100644
--- a/opengl/tests/testPauseResume/Android.bp
+++ b/opengl/tests/testPauseResume/Android.bp
@@ -1,4 +1,13 @@
// OpenGL ES JNI sample
+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"],
+}
+
android_app {
name: "TestEGL",
srcs: ["**/*.java"],
diff --git a/opengl/tests/testViewport/Android.bp b/opengl/tests/testViewport/Android.bp
index 629b573a2a..13ce3ad481 100644
--- a/opengl/tests/testViewport/Android.bp
+++ b/opengl/tests/testViewport/Android.bp
@@ -2,6 +2,15 @@
// OpenGL ES JNI sample
// This makefile builds both an activity and a shared library.
//########################################################################
+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"],
+}
+
android_app {
name: "TestViewport",
srcs: ["**/*.java"],
diff --git a/opengl/tests/textures/Android.bp b/opengl/tests/textures/Android.bp
index 84adda2aa4..f113ff78d2 100644
--- a/opengl/tests/textures/Android.bp
+++ b/opengl/tests/textures/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_binary {
name: "test-opengl-textures",
srcs: ["textures.cpp"],
diff --git a/opengl/tests/tritex/Android.bp b/opengl/tests/tritex/Android.bp
index 390397b9da..759582cab6 100644
--- a/opengl/tests/tritex/Android.bp
+++ b/opengl/tests/tritex/Android.bp
@@ -1,3 +1,14 @@
+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
+ // SPDX-license-identifier-MIT
+ // SPDX-license-identifier-Unicode-DFS
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_binary {
name: "test-opengl-tritex",
srcs: ["tritex.cpp"],
diff --git a/services/audiomanager/Android.bp b/services/audiomanager/Android.bp
index 12ad47e15a..e6fb2c3660 100644
--- a/services/audiomanager/Android.bp
+++ b/services/audiomanager/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library_shared {
name: "libaudiomanager",
diff --git a/services/automotive/display/Android.bp b/services/automotive/display/Android.bp
index c3da216002..72bd29254d 100644
--- a/services/automotive/display/Android.bp
+++ b/services/automotive/display/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_binary {
name: "android.frameworks.automotive.display@1.0-service",
defaults: ["hidl_defaults"],
diff --git a/services/batteryservice/Android.bp b/services/batteryservice/Android.bp
index 66ee8ff55e..1e3799185e 100644
--- a/services/batteryservice/Android.bp
+++ b/services/batteryservice/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library_headers {
name: "libbatteryservice_headers",
vendor_available: true,
diff --git a/services/displayservice/Android.bp b/services/displayservice/Android.bp
index 4d2d87352b..8681784405 100644
--- a/services/displayservice/Android.bp
+++ b/services/displayservice/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library_shared {
name: "libdisplayservicehidl",
diff --git a/services/gpuservice/Android.bp b/services/gpuservice/Android.bp
index 9a9bca1478..b9b6a19606 100644
--- a/services/gpuservice/Android.bp
+++ b/services/gpuservice/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_defaults {
name: "gpuservice_defaults",
cflags: [
diff --git a/services/gpuservice/bpfprogs/Android.bp b/services/gpuservice/bpfprogs/Android.bp
index b8758146cc..9842ed7c3c 100644
--- a/services/gpuservice/bpfprogs/Android.bp
+++ b/services/gpuservice/bpfprogs/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+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"],
+}
+
bpf {
name: "gpu_mem.o",
srcs: ["gpu_mem.c"],
diff --git a/services/gpuservice/gpumem/Android.bp b/services/gpuservice/gpumem/Android.bp
index b2230b6c01..830e53d534 100644
--- a/services/gpuservice/gpumem/Android.bp
+++ b/services/gpuservice/gpumem/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library_shared {
name: "libgpumem",
srcs: [
diff --git a/services/gpuservice/gpustats/Android.bp b/services/gpuservice/gpustats/Android.bp
index f52602ab78..54291ad6c6 100644
--- a/services/gpuservice/gpustats/Android.bp
+++ b/services/gpuservice/gpustats/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library_shared {
name: "libgfxstats",
srcs: [
diff --git a/services/gpuservice/tests/unittests/Android.bp b/services/gpuservice/tests/unittests/Android.bp
index 9606daacec..6d87c45921 100644
--- a/services/gpuservice/tests/unittests/Android.bp
+++ b/services/gpuservice/tests/unittests/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_test {
name: "gpuservice_unittest",
test_suites: ["device-tests"],
diff --git a/services/gpuservice/tracing/Android.bp b/services/gpuservice/tracing/Android.bp
index 919fed3cec..a1bc1edad8 100644
--- a/services/gpuservice/tracing/Android.bp
+++ b/services/gpuservice/tracing/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library_shared {
name: "libgpumemtracer",
srcs: [
diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp
index b640e9c761..9b98a17b4d 100644
--- a/services/inputflinger/Android.bp
+++ b/services/inputflinger/Android.bp
@@ -13,6 +13,15 @@
// limitations under the License.
// Default flags to be used throughout all libraries in inputflinger.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_defaults {
name: "inputflinger_defaults",
cflags: [
diff --git a/services/inputflinger/benchmarks/Android.bp b/services/inputflinger/benchmarks/Android.bp
index bd275a76c1..ea37f4d424 100644
--- a/services/inputflinger/benchmarks/Android.bp
+++ b/services/inputflinger/benchmarks/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_benchmark {
name: "inputflinger_benchmarks",
srcs: [
diff --git a/services/inputflinger/dispatcher/Android.bp b/services/inputflinger/dispatcher/Android.bp
index e5b131e95e..393f649746 100644
--- a/services/inputflinger/dispatcher/Android.bp
+++ b/services/inputflinger/dispatcher/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library_headers {
name: "libinputdispatcher_headers",
export_include_dirs: [
diff --git a/services/inputflinger/dispatcher/Entry.h b/services/inputflinger/dispatcher/Entry.h
index 499f42e962..45a007ba6e 100644
--- a/services/inputflinger/dispatcher/Entry.h
+++ b/services/inputflinger/dispatcher/Entry.h
@@ -272,6 +272,7 @@ struct CommandEntry {
std::string obscuringPackage;
bool enabled;
int32_t pid;
+ nsecs_t consumeTime; // time when the event was consumed by InputConsumer
};
} // namespace android::inputdispatcher
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 290993935a..9898e9d820 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -1673,9 +1673,7 @@ bool InputDispatcher::shouldWaitToSendKeyLocked(nsecs_t currentTime,
if (!mKeyIsWaitingForEventsTimeout.has_value()) {
// Start the timer
- ALOGD("Waiting to send key to %s because there are unprocessed events that may cause "
- "focus to change",
- focusedWindowName);
+ // Wait to send key because there are unprocessed events that may cause focus to change
mKeyIsWaitingForEventsTimeout = currentTime +
std::chrono::duration_cast<std::chrono::nanoseconds>(KEY_WAITING_FOR_EVENTS_TIMEOUT)
.count();
@@ -2834,10 +2832,6 @@ void InputDispatcher::enqueueDispatchEntryLocked(const sp<Connection>& connectio
* This includes situations like the soft BACK button key. When the user releases (lifts up the
* finger) the back button, then navigation bar will inject KEYCODE_BACK with ACTION_UP.
* Both of those ACTION_UP events would not be logged
- * Monitors (both gesture and global): any gesture monitors or global monitors receiving events
- * will not be logged. This is omitted to reduce the amount of data printed.
- * If you see <none>, it's likely that one of the gesture monitors pilfered the event, and therefore
- * gesture monitor is the only connection receiving the remainder of the gesture.
*/
void InputDispatcher::updateInteractionTokensLocked(const EventEntry& entry,
const std::vector<InputTarget>& targets) {
@@ -2867,8 +2861,8 @@ void InputDispatcher::updateInteractionTokensLocked(const EventEntry& entry,
sp<IBinder> token = target.inputChannel->getConnectionToken();
sp<Connection> connection = getConnectionLocked(token);
- if (connection == nullptr || connection->monitor) {
- continue; // We only need to keep track of the non-monitor connections.
+ if (connection == nullptr) {
+ continue;
}
newConnectionTokens.insert(std::move(token));
newConnections.emplace_back(connection);
@@ -2878,12 +2872,12 @@ void InputDispatcher::updateInteractionTokensLocked(const EventEntry& entry,
}
mInteractionConnectionTokens = newConnectionTokens;
- std::string windowList;
+ std::string targetList;
for (const sp<Connection>& connection : newConnections) {
- windowList += connection->getWindowName() + ", ";
+ targetList += connection->getWindowName() + ", ";
}
- std::string message = "Interaction with windows: " + windowList;
- if (windowList.empty()) {
+ std::string message = "Interaction with: " + targetList;
+ if (targetList.empty()) {
message += "<none>";
}
android_log_event_list(LOGTAG_INPUT_INTERACTION) << message << LOG_ID_EVENTS;
@@ -3113,7 +3107,7 @@ const std::array<uint8_t, 32> InputDispatcher::getSignature(
void InputDispatcher::finishDispatchCycleLocked(nsecs_t currentTime,
const sp<Connection>& connection, uint32_t seq,
- bool handled) {
+ bool handled, nsecs_t consumeTime) {
#if DEBUG_DISPATCH_CYCLE
ALOGD("channel '%s' ~ finishDispatchCycle - seq=%u, handled=%s",
connection->getInputChannelName().c_str(), seq, toString(handled));
@@ -3125,7 +3119,7 @@ void InputDispatcher::finishDispatchCycleLocked(nsecs_t currentTime,
}
// Notify other system components and prepare to start the next dispatch cycle.
- onDispatchCycleFinishedLocked(currentTime, connection, seq, handled);
+ onDispatchCycleFinishedLocked(currentTime, connection, seq, handled, consumeTime);
}
void InputDispatcher::abortBrokenDispatchCycleLocked(nsecs_t currentTime,
@@ -3196,13 +3190,15 @@ int InputDispatcher::handleReceiveCallback(int fd, int events, void* data) {
bool gotOne = false;
status_t status;
for (;;) {
- uint32_t seq;
- bool handled;
- status = connection->inputPublisher.receiveFinishedSignal(&seq, &handled);
+ std::function<void(uint32_t seq, bool handled, nsecs_t consumeTime)> callback =
+ std::bind(&InputDispatcher::finishDispatchCycleLocked, d, currentTime,
+ connection, std::placeholders::_1, std::placeholders::_2,
+ std::placeholders::_3);
+
+ status = connection->inputPublisher.receiveFinishedSignal(callback);
if (status) {
break;
}
- d->finishDispatchCycleLocked(currentTime, connection, seq, handled);
gotOne = true;
}
if (gotOne) {
@@ -3219,8 +3215,7 @@ int InputDispatcher::handleReceiveCallback(int fd, int events, void* data) {
}
} else {
// Monitor channels are never explicitly unregistered.
- // We do it automatically when the remote endpoint is closed so don't warn
- // about them.
+ // We do it automatically when the remote endpoint is closed so don't warn about them.
const bool stillHaveWindowHandle =
d->getWindowHandleLocked(connection->inputChannel->getConnectionToken()) !=
nullptr;
@@ -4976,7 +4971,7 @@ status_t InputDispatcher::removeInputChannelLocked(const sp<IBinder>& connection
bool notify) {
sp<Connection> connection = getConnectionLocked(connectionToken);
if (connection == nullptr) {
- ALOGW("Attempted to unregister already unregistered input channel");
+ // Connection can be removed via socket hang up or an explicit call to 'removeInputChannel'
return BAD_VALUE;
}
@@ -5040,9 +5035,11 @@ status_t InputDispatcher::pilferPointers(const sp<IBinder>& token) {
}
TouchState& state = stateIt->second;
+ std::shared_ptr<InputChannel> requestingChannel;
std::optional<int32_t> foundDeviceId;
for (const TouchedMonitor& touchedMonitor : state.gestureMonitors) {
if (touchedMonitor.monitor.inputChannel->getConnectionToken() == token) {
+ requestingChannel = touchedMonitor.monitor.inputChannel;
foundDeviceId = state.deviceId;
}
}
@@ -5058,13 +5055,19 @@ status_t InputDispatcher::pilferPointers(const sp<IBinder>& token) {
"gesture monitor stole pointer stream");
options.deviceId = deviceId;
options.displayId = displayId;
+ std::string canceledWindows = "[";
for (const TouchedWindow& window : state.windows) {
std::shared_ptr<InputChannel> channel =
getInputChannelLocked(window.windowHandle->getToken());
if (channel != nullptr) {
synthesizeCancelationEventsForInputChannelLocked(channel, options);
+ canceledWindows += channel->getName() + ", ";
}
}
+ canceledWindows += "]";
+ ALOGI("Monitor %s is stealing touch from %s", requestingChannel->getName().c_str(),
+ canceledWindows.c_str());
+
// Then clear the current touch state so we stop dispatching to them as well.
state.filterNonMonitors();
}
@@ -5154,13 +5157,14 @@ void InputDispatcher::removeConnectionLocked(const sp<Connection>& connection) {
void InputDispatcher::onDispatchCycleFinishedLocked(nsecs_t currentTime,
const sp<Connection>& connection, uint32_t seq,
- bool handled) {
+ bool handled, nsecs_t consumeTime) {
std::unique_ptr<CommandEntry> commandEntry = std::make_unique<CommandEntry>(
&InputDispatcher::doDispatchCycleFinishedLockedInterruptible);
commandEntry->connection = connection;
commandEntry->eventTime = currentTime;
commandEntry->seq = seq;
commandEntry->handled = handled;
+ commandEntry->consumeTime = consumeTime;
postCommandLocked(std::move(commandEntry));
}
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index c93d74eb90..83094c20ba 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -528,7 +528,7 @@ private:
void startDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection)
REQUIRES(mLock);
void finishDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection,
- uint32_t seq, bool handled) REQUIRES(mLock);
+ uint32_t seq, bool handled, nsecs_t consumeTime) REQUIRES(mLock);
void abortBrokenDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection,
bool notify) REQUIRES(mLock);
void drainDispatchQueue(std::deque<DispatchEntry*>& queue);
@@ -578,7 +578,8 @@ private:
// Interesting events that we might like to log or tell the framework about.
void onDispatchCycleFinishedLocked(nsecs_t currentTime, const sp<Connection>& connection,
- uint32_t seq, bool handled) REQUIRES(mLock);
+ uint32_t seq, bool handled, nsecs_t consumeTime)
+ REQUIRES(mLock);
void onDispatchCycleBrokenLocked(nsecs_t currentTime, const sp<Connection>& connection)
REQUIRES(mLock);
void onFocusChangedLocked(const FocusResolver::FocusChanges& changes) REQUIRES(mLock);
diff --git a/services/inputflinger/host/Android.bp b/services/inputflinger/host/Android.bp
index 9e797e4862..18d0226818 100644
--- a/services/inputflinger/host/Android.bp
+++ b/services/inputflinger/host/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library_shared {
name: "libinputflingerhost",
diff --git a/services/inputflinger/include/InputReaderBase.h b/services/inputflinger/include/InputReaderBase.h
index 69aea84cd0..3bf212a51b 100644
--- a/services/inputflinger/include/InputReaderBase.h
+++ b/services/inputflinger/include/InputReaderBase.h
@@ -113,6 +113,10 @@ public:
/* Get battery status of a particular input device. */
virtual std::optional<int32_t> getBatteryStatus(int32_t deviceId) = 0;
+ virtual std::vector<int32_t> getLightIds(int32_t deviceId) = 0;
+
+ virtual const InputDeviceLightInfo* getLightInfo(int32_t deviceId, int32_t lightId) = 0;
+
/* Return true if the device can send input events to the specified display. */
virtual bool canDispatchToDisplay(int32_t deviceId, int32_t displayId) = 0;
@@ -126,6 +130,15 @@ public:
/* Flush sensor data in input reader mapper. */
virtual void flushSensor(int32_t deviceId, InputDeviceSensorType sensorType) = 0;
+
+ /* Set color for the light */
+ virtual bool setLightColor(int32_t deviceId, int32_t lightId, int32_t color) = 0;
+ /* Set player ID for the light */
+ virtual bool setLightPlayerId(int32_t deviceId, int32_t lightId, int32_t playerId) = 0;
+ /* Get light color */
+ virtual std::optional<int32_t> getLightColor(int32_t deviceId, int32_t lightId) = 0;
+ /* Get light player ID */
+ virtual std::optional<int32_t> getLightPlayerId(int32_t deviceId, int32_t lightId) = 0;
};
// --- InputReaderConfiguration ---
diff --git a/services/inputflinger/reader/Android.bp b/services/inputflinger/reader/Android.bp
index 7f979f2bd3..8a2828c1b4 100644
--- a/services/inputflinger/reader/Android.bp
+++ b/services/inputflinger/reader/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library_headers {
name: "libinputreader_headers",
export_include_dirs: [
@@ -36,6 +45,7 @@ filegroup {
"mapper/InputMapper.cpp",
"mapper/JoystickInputMapper.cpp",
"mapper/KeyboardInputMapper.cpp",
+ "mapper/LightInputMapper.cpp",
"mapper/MultiTouchInputMapper.cpp",
"mapper/RotaryEncoderInputMapper.cpp",
"mapper/SensorInputMapper.cpp",
diff --git a/services/inputflinger/reader/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp
index 8f8c0513b2..e939d1cb91 100644
--- a/services/inputflinger/reader/EventHub.cpp
+++ b/services/inputflinger/reader/EventHub.cpp
@@ -48,6 +48,7 @@
#include <utils/Timers.h>
#include <filesystem>
+#include <regex>
#include "EventHub.h"
@@ -84,6 +85,30 @@ static const std::unordered_map<std::string, int32_t> BATTERY_LEVEL = {{"Critica
{"Full", 100},
{"Unknown", 50}};
+// Mapping for input led class node names lookup.
+// https://www.kernel.org/doc/html/latest/leds/leds-class.html
+static const std::unordered_map<std::string, InputLightClass> LIGHT_CLASSES =
+ {{"red", InputLightClass::RED},
+ {"green", InputLightClass::GREEN},
+ {"blue", InputLightClass::BLUE},
+ {"global", InputLightClass::GLOBAL},
+ {"brightness", InputLightClass::BRIGHTNESS},
+ {"multi_index", InputLightClass::MULTI_INDEX},
+ {"multi_intensity", InputLightClass::MULTI_INTENSITY},
+ {"max_brightness", InputLightClass::MAX_BRIGHTNESS}};
+
+// Mapping for input multicolor led class node names.
+// https://www.kernel.org/doc/html/latest/leds/leds-class-multicolor.html
+static const std::unordered_map<InputLightClass, std::string> LIGHT_NODES =
+ {{InputLightClass::BRIGHTNESS, "brightness"},
+ {InputLightClass::MULTI_INDEX, "multi_index"},
+ {InputLightClass::MULTI_INTENSITY, "multi_intensity"}};
+
+// Mapping for light color name and the light color
+const std::unordered_map<std::string, LightColor> LIGHT_COLORS = {{"red", LightColor::RED},
+ {"green", LightColor::GREEN},
+ {"blue", LightColor::BLUE}};
+
static inline const char* toString(bool value) {
return value ? "true" : "false";
}
@@ -151,14 +176,14 @@ static nsecs_t processEventTimestamp(const struct input_event& event) {
* Returns the sysfs root path of the input device
*
*/
-static std::filesystem::path getSysfsRootPath(const char* devicePath) {
+static std::optional<std::filesystem::path> getSysfsRootPath(const char* devicePath) {
std::error_code errorCode;
// Stat the device path to get the major and minor number of the character file
struct stat statbuf;
if (stat(devicePath, &statbuf) == -1) {
ALOGE("Could not stat device %s due to error: %s.", devicePath, std::strerror(errno));
- return std::filesystem::path();
+ return std::nullopt;
}
unsigned int major_num = major(statbuf.st_rdev);
@@ -173,7 +198,7 @@ static std::filesystem::path getSysfsRootPath(const char* devicePath) {
if (errorCode) {
ALOGW("Could not run filesystem::canonical() due to error %d : %s.", errorCode.value(),
errorCode.message().c_str());
- return std::filesystem::path();
+ return std::nullopt;
}
// Continue to go up a directory until we reach a directory named "input"
@@ -192,26 +217,68 @@ static std::filesystem::path getSysfsRootPath(const char* devicePath) {
}
// Not found
- return std::filesystem::path();
+ return std::nullopt;
}
return sysfsPath;
}
/**
- * Returns the power supply node in sys fs
- *
+ * Returns the list of files under a specified path.
*/
-static std::filesystem::path findPowerSupplyNode(const std::filesystem::path& sysfsRootPath) {
- for (auto path = sysfsRootPath; path != "/"; path = path.parent_path()) {
- std::error_code errorCode;
- auto iter = std::filesystem::directory_iterator(path / "power_supply", errorCode);
- if (!errorCode && iter != std::filesystem::directory_iterator()) {
- return iter->path();
+static std::vector<std::filesystem::path> allFilesInPath(const std::filesystem::path& path) {
+ std::vector<std::filesystem::path> nodes;
+ std::error_code errorCode;
+ auto iter = std::filesystem::directory_iterator(path, errorCode);
+ while (!errorCode && iter != std::filesystem::directory_iterator()) {
+ nodes.push_back(iter->path());
+ iter++;
+ }
+ return nodes;
+}
+
+/**
+ * Returns the list of files under a specified directory in a sysfs path.
+ * Example:
+ * findSysfsNodes(sysfsRootPath, SysfsClass::LEDS) will return all led nodes under "leds" directory
+ * in the sysfs path.
+ */
+static std::vector<std::filesystem::path> findSysfsNodes(const std::filesystem::path& sysfsRoot,
+ SysfsClass clazz) {
+ std::string nodeStr = NamedEnum::string(clazz);
+ std::for_each(nodeStr.begin(), nodeStr.end(),
+ [](char& c) { c = std::tolower(static_cast<unsigned char>(c)); });
+ std::vector<std::filesystem::path> nodes;
+ for (auto path = sysfsRoot; path != "/" && nodes.empty(); path = path.parent_path()) {
+ nodes = allFilesInPath(path / nodeStr);
+ }
+ return nodes;
+}
+
+static std::optional<std::array<LightColor, COLOR_NUM>> getColorIndexArray(
+ std::filesystem::path path) {
+ std::string indexStr;
+ if (!base::ReadFileToString(path, &indexStr)) {
+ return std::nullopt;
+ }
+
+ // Parse the multi color LED index file, refer to kernel docs
+ // leds/leds-class-multicolor.html
+ std::regex indexPattern("(red|green|blue)\\s(red|green|blue)\\s(red|green|blue)[\\n]");
+ std::smatch results;
+ std::array<LightColor, COLOR_NUM> colors;
+ if (!std::regex_match(indexStr, results, indexPattern)) {
+ return std::nullopt;
+ }
+
+ for (size_t i = 1; i < results.size(); i++) {
+ const auto it = LIGHT_COLORS.find(results[i].str());
+ if (it != LIGHT_COLORS.end()) {
+ // intensities.emplace(it->second, 0);
+ colors[i - 1] = it->second;
}
}
- // Not found
- return std::filesystem::path();
+ return colors;
}
// --- Global Functions ---
@@ -280,6 +347,7 @@ EventHub::Device::Device(int fd, int32_t id, const std::string& path,
virtualKeyMap(nullptr),
ffEffectPlaying(false),
ffEffectId(-1),
+ nextLightId(0),
controllerNumber(0),
enabled(true),
isVirtual(fd < 0) {}
@@ -469,6 +537,70 @@ status_t EventHub::Device::mapLed(int32_t led, int32_t* outScanCode) const {
return NAME_NOT_FOUND;
}
+// Check the sysfs path for any input device batteries, returns true if battery found.
+bool EventHub::Device::configureBatteryLocked() {
+ if (!sysfsRootPath.has_value()) {
+ return false;
+ }
+ // Check if device has any batteries.
+ std::vector<std::filesystem::path> batteryPaths =
+ findSysfsNodes(sysfsRootPath.value(), SysfsClass::POWER_SUPPLY);
+ // We only support single battery for an input device, if multiple batteries exist only the
+ // first one is supported.
+ if (batteryPaths.empty()) {
+ // Set path to be empty
+ sysfsBatteryPath = std::nullopt;
+ return false;
+ }
+ // If a battery exists
+ sysfsBatteryPath = batteryPaths[0];
+ return true;
+}
+
+// Check the sysfs path for any input device lights, returns true if lights found.
+bool EventHub::Device::configureLightsLocked() {
+ if (!sysfsRootPath.has_value()) {
+ return false;
+ }
+ // Check if device has any lights.
+ const auto& paths = findSysfsNodes(sysfsRootPath.value(), SysfsClass::LEDS);
+ for (const auto& nodePath : paths) {
+ RawLightInfo info;
+ info.id = ++nextLightId;
+ info.path = nodePath;
+ info.name = nodePath.filename();
+ info.maxBrightness = std::nullopt;
+ size_t nameStart = info.name.rfind(":");
+ if (nameStart != std::string::npos) {
+ // Trim the name to color name
+ info.name = info.name.substr(nameStart + 1);
+ // Set InputLightClass flag for colors
+ const auto it = LIGHT_CLASSES.find(info.name);
+ if (it != LIGHT_CLASSES.end()) {
+ info.flags |= it->second;
+ }
+ }
+ // Scan the path for all the files
+ // Refer to https://www.kernel.org/doc/Documentation/leds/leds-class.txt
+ const auto& files = allFilesInPath(nodePath);
+ for (const auto& file : files) {
+ const auto it = LIGHT_CLASSES.find(file.filename().string());
+ if (it != LIGHT_CLASSES.end()) {
+ info.flags |= it->second;
+ // If the node has maximum brightness, read it
+ if (it->second == InputLightClass::MAX_BRIGHTNESS) {
+ std::string str;
+ if (base::ReadFileToString(file, &str)) {
+ info.maxBrightness = std::stoi(str);
+ }
+ }
+ }
+ }
+ lightInfos.insert_or_assign(info.id, info);
+ }
+ return !lightInfos.empty();
+}
+
/**
* Get the capabilities for the current process.
* Crashes the system if unable to create / check / destroy the capabilities object.
@@ -829,6 +961,161 @@ base::Result<std::pair<InputDeviceSensorType, int32_t>> EventHub::mapSensor(int3
return Errorf("Device not found or device has no key layout.");
}
+const std::vector<int32_t> EventHub::getRawLightIds(int32_t deviceId) {
+ std::scoped_lock _l(mLock);
+ Device* device = getDeviceLocked(deviceId);
+ std::vector<int32_t> lightIds;
+
+ if (device != nullptr) {
+ for (const auto [id, info] : device->lightInfos) {
+ lightIds.push_back(id);
+ }
+ }
+ return lightIds;
+}
+
+std::optional<RawLightInfo> EventHub::getRawLightInfo(int32_t deviceId, int32_t lightId) {
+ std::scoped_lock _l(mLock);
+ Device* device = getDeviceLocked(deviceId);
+
+ if (device != nullptr) {
+ auto it = device->lightInfos.find(lightId);
+ if (it != device->lightInfos.end()) {
+ return it->second;
+ }
+ }
+ return std::nullopt;
+}
+
+std::optional<int32_t> EventHub::getLightBrightness(int32_t deviceId, int32_t lightId) {
+ std::scoped_lock _l(mLock);
+
+ Device* device = getDeviceLocked(deviceId);
+ if (device == nullptr) {
+ return std::nullopt;
+ }
+
+ auto it = device->lightInfos.find(lightId);
+ if (it == device->lightInfos.end()) {
+ return std::nullopt;
+ }
+ std::string buffer;
+ if (!base::ReadFileToString(it->second.path / LIGHT_NODES.at(InputLightClass::BRIGHTNESS),
+ &buffer)) {
+ return std::nullopt;
+ }
+ return std::stoi(buffer);
+}
+
+std::optional<std::unordered_map<LightColor, int32_t>> EventHub::getLightIntensities(
+ int32_t deviceId, int32_t lightId) {
+ std::scoped_lock _l(mLock);
+
+ Device* device = getDeviceLocked(deviceId);
+ if (device == nullptr) {
+ return std::nullopt;
+ }
+
+ auto lightIt = device->lightInfos.find(lightId);
+ if (lightIt == device->lightInfos.end()) {
+ return std::nullopt;
+ }
+
+ auto ret =
+ getColorIndexArray(lightIt->second.path / LIGHT_NODES.at(InputLightClass::MULTI_INDEX));
+
+ if (!ret.has_value()) {
+ return std::nullopt;
+ }
+ std::array<LightColor, COLOR_NUM> colors = ret.value();
+
+ std::string intensityStr;
+ if (!base::ReadFileToString(lightIt->second.path /
+ LIGHT_NODES.at(InputLightClass::MULTI_INTENSITY),
+ &intensityStr)) {
+ return std::nullopt;
+ }
+
+ // Intensity node outputs 3 color values
+ std::regex intensityPattern("([0-9]+)\\s([0-9]+)\\s([0-9]+)[\\n]");
+ std::smatch results;
+
+ if (!std::regex_match(intensityStr, results, intensityPattern)) {
+ return std::nullopt;
+ }
+ std::unordered_map<LightColor, int32_t> intensities;
+ for (size_t i = 1; i < results.size(); i++) {
+ int value = std::stoi(results[i].str());
+ intensities.emplace(colors[i - 1], value);
+ }
+ return intensities;
+}
+
+void EventHub::setLightBrightness(int32_t deviceId, int32_t lightId, int32_t brightness) {
+ std::scoped_lock _l(mLock);
+
+ Device* device = getDeviceLocked(deviceId);
+ if (device == nullptr) {
+ ALOGE("Device Id %d does not exist", deviceId);
+ return;
+ }
+ auto lightIt = device->lightInfos.find(lightId);
+ if (lightIt == device->lightInfos.end()) {
+ ALOGE("Light Id %d does not exist.", lightId);
+ return;
+ }
+
+ if (!base::WriteStringToFile(std::to_string(brightness),
+ lightIt->second.path /
+ LIGHT_NODES.at(InputLightClass::BRIGHTNESS))) {
+ ALOGE("Can not write to file, error: %s", strerror(errno));
+ }
+}
+
+void EventHub::setLightIntensities(int32_t deviceId, int32_t lightId,
+ std::unordered_map<LightColor, int32_t> intensities) {
+ std::scoped_lock _l(mLock);
+
+ Device* device = getDeviceLocked(deviceId);
+ if (device == nullptr) {
+ ALOGE("Device Id %d does not exist", deviceId);
+ return;
+ }
+ auto lightIt = device->lightInfos.find(lightId);
+ if (lightIt == device->lightInfos.end()) {
+ ALOGE("Light Id %d does not exist.", lightId);
+ return;
+ }
+
+ auto ret =
+ getColorIndexArray(lightIt->second.path / LIGHT_NODES.at(InputLightClass::MULTI_INDEX));
+
+ if (!ret.has_value()) {
+ return;
+ }
+ std::array<LightColor, COLOR_NUM> colors = ret.value();
+
+ std::string rgbStr;
+ for (size_t i = 0; i < COLOR_NUM; i++) {
+ auto it = intensities.find(colors[i]);
+ if (it != intensities.end()) {
+ rgbStr += std::to_string(it->second);
+ // Insert space between colors
+ if (i < COLOR_NUM - 1) {
+ rgbStr += " ";
+ }
+ }
+ }
+ // Append new line
+ rgbStr += "\n";
+
+ if (!base::WriteStringToFile(rgbStr,
+ lightIt->second.path /
+ LIGHT_NODES.at(InputLightClass::MULTI_INTENSITY))) {
+ ALOGE("Can not write to file, error: %s", strerror(errno));
+ }
+}
+
void EventHub::setExcludedDevices(const std::vector<std::string>& devices) {
std::scoped_lock _l(mLock);
@@ -1068,18 +1355,18 @@ std::optional<int32_t> EventHub::getBatteryCapacity(int32_t deviceId) const {
Device* device = getDeviceLocked(deviceId);
std::string buffer;
- if (!device || (device->sysfsBatteryPath.empty())) {
+ if (device == nullptr || !device->sysfsBatteryPath.has_value()) {
return std::nullopt;
}
// Some devices report battery capacity as an integer through the "capacity" file
- if (base::ReadFileToString(device->sysfsBatteryPath / "capacity", &buffer)) {
+ if (base::ReadFileToString(device->sysfsBatteryPath.value() / "capacity", &buffer)) {
return std::stoi(buffer);
}
// Other devices report capacity as an enum value POWER_SUPPLY_CAPACITY_LEVEL_XXX
// These values are taken from kernel source code include/linux/power_supply.h
- if (base::ReadFileToString(device->sysfsBatteryPath / "capacity_level", &buffer)) {
+ if (base::ReadFileToString(device->sysfsBatteryPath.value() / "capacity_level", &buffer)) {
const auto it = BATTERY_LEVEL.find(buffer);
if (it != BATTERY_LEVEL.end()) {
return it->second;
@@ -1093,11 +1380,11 @@ std::optional<int32_t> EventHub::getBatteryStatus(int32_t deviceId) const {
Device* device = getDeviceLocked(deviceId);
std::string buffer;
- if (!device || (device->sysfsBatteryPath.empty())) {
+ if (device == nullptr || !device->sysfsBatteryPath.has_value()) {
return std::nullopt;
}
- if (!base::ReadFileToString(device->sysfsBatteryPath / "status", &buffer)) {
+ if (!base::ReadFileToString(device->sysfsBatteryPath.value() / "status", &buffer)) {
ALOGE("Failed to read sysfs battery info: %s", strerror(errno));
return std::nullopt;
}
@@ -1572,6 +1859,12 @@ status_t EventHub::openDeviceLocked(const std::string& devicePath) {
// Load the configuration file for the device.
device->loadConfigurationLocked();
+ // Grab the device's sysfs path
+ device->sysfsRootPath = getSysfsRootPath(devicePath.c_str());
+ // find related components
+ bool hasBattery = device->configureBatteryLocked();
+ bool hasLights = device->configureLightsLocked();
+
// Figure out the kinds of events the device reports.
device->readDeviceBitMask(EVIOCGBIT(EV_KEY, 0), device->keyBitmask);
device->readDeviceBitMask(EVIOCGBIT(EV_ABS, 0), device->absBitmask);
@@ -1721,16 +2014,14 @@ status_t EventHub::openDeviceLocked(const std::string& devicePath) {
return -1;
}
- // Grab the device's sysfs path
- device->sysfsRootPath = getSysfsRootPath(devicePath.c_str());
-
- if (!device->sysfsRootPath.empty()) {
- device->sysfsBatteryPath = findPowerSupplyNode(device->sysfsRootPath);
+ // Classify InputDeviceClass::BATTERY.
+ if (hasBattery) {
+ device->classes |= InputDeviceClass::BATTERY;
+ }
- // Check if a battery exists
- if (!device->sysfsBatteryPath.empty()) {
- device->classes |= InputDeviceClass::BATTERY;
- }
+ // Classify InputDeviceClass::LIGHT.
+ if (hasLights) {
+ device->classes |= InputDeviceClass::LIGHT;
}
// Determine whether the device has a mic.
diff --git a/services/inputflinger/reader/InputDevice.cpp b/services/inputflinger/reader/InputDevice.cpp
index 8fc6f4a701..cbf3b69f29 100644
--- a/services/inputflinger/reader/InputDevice.cpp
+++ b/services/inputflinger/reader/InputDevice.cpp
@@ -27,6 +27,7 @@
#include "InputReaderContext.h"
#include "JoystickInputMapper.h"
#include "KeyboardInputMapper.h"
+#include "LightInputMapper.h"
#include "MultiTouchInputMapper.h"
#include "RotaryEncoderInputMapper.h"
#include "SensorInputMapper.h"
@@ -161,9 +162,22 @@ void InputDevice::addEventHubDevice(int32_t eventHubId, bool populateMappers) {
mappers.push_back(std::make_unique<VibratorInputMapper>(*contextPtr));
}
- // Battery-like devices.
+ // Battery-like devices. Only one battery mapper for each EventHub device.
if (classes.test(InputDeviceClass::BATTERY)) {
- mappers.push_back(std::make_unique<BatteryInputMapper>(*contextPtr));
+ InputDeviceInfo deviceInfo;
+ getDeviceInfo(&deviceInfo);
+ if (!deviceInfo.hasBattery()) {
+ mappers.push_back(std::make_unique<BatteryInputMapper>(*contextPtr));
+ }
+ }
+
+ // Light-containing devices. Only one light mapper for each EventHub device.
+ if (classes.test(InputDeviceClass::LIGHT)) {
+ InputDeviceInfo deviceInfo;
+ getDeviceInfo(&deviceInfo);
+ if (deviceInfo.getLightIds().empty()) {
+ mappers.push_back(std::make_unique<LightInputMapper>(*contextPtr));
+ }
}
// Keyboard-like devices.
@@ -505,6 +519,32 @@ std::optional<int32_t> InputDevice::getBatteryStatus() {
return first_in_mappers<int32_t>([](InputMapper& mapper) { return mapper.getBatteryStatus(); });
}
+bool InputDevice::setLightColor(int32_t lightId, int32_t color) {
+ bool success = true;
+ for_each_mapper([&success, lightId, color](InputMapper& mapper) {
+ success &= mapper.setLightColor(lightId, color);
+ });
+ return success;
+}
+
+bool InputDevice::setLightPlayerId(int32_t lightId, int32_t playerId) {
+ bool success = true;
+ for_each_mapper([&success, lightId, playerId](InputMapper& mapper) {
+ success &= mapper.setLightPlayerId(lightId, playerId);
+ });
+ return success;
+}
+
+std::optional<int32_t> InputDevice::getLightColor(int32_t lightId) {
+ return first_in_mappers<int32_t>(
+ [lightId](InputMapper& mapper) { return mapper.getLightColor(lightId); });
+}
+
+std::optional<int32_t> InputDevice::getLightPlayerId(int32_t lightId) {
+ return first_in_mappers<int32_t>(
+ [lightId](InputMapper& mapper) { return mapper.getLightPlayerId(lightId); });
+}
+
int32_t InputDevice::getMetaState() {
int32_t result = 0;
for_each_mapper([&result](InputMapper& mapper) { result |= mapper.getMetaState(); });
@@ -520,7 +560,8 @@ void InputDevice::bumpGeneration() {
}
void InputDevice::notifyReset(nsecs_t when) {
- mContext->notifyDeviceReset(when, mId);
+ NotifyDeviceResetArgs args(mContext->getNextId(), when, mId);
+ mContext->getListener()->notifyDeviceReset(&args);
}
std::optional<int32_t> InputDevice::getAssociatedDisplayId() {
diff --git a/services/inputflinger/reader/InputReader.cpp b/services/inputflinger/reader/InputReader.cpp
index c044393c9e..2d0fdf7958 100644
--- a/services/inputflinger/reader/InputReader.cpp
+++ b/services/inputflinger/reader/InputReader.cpp
@@ -339,7 +339,8 @@ void InputReader::handleConfigurationChangedLocked(nsecs_t when) {
updateGlobalMetaStateLocked();
// Enqueue configuration changed.
- mContext.notifyConfigurationChanged(when);
+ NotifyConfigurationChangedArgs args(mContext.getNextId(), when);
+ mQueuedListener->notifyConfigurationChanged(&args);
}
void InputReader::refreshConfigurationLocked(uint32_t changes) {
@@ -366,7 +367,9 @@ void InputReader::refreshConfigurationLocked(uint32_t changes) {
}
if (changes & InputReaderConfiguration::CHANGE_POINTER_CAPTURE) {
- mContext.notifyPointerCaptureChanged(now, mConfig.pointerCapture);
+ const NotifyPointerCaptureChangedArgs args(mContext.getNextId(), now,
+ mConfig.pointerCapture);
+ mQueuedListener->notifyPointerCaptureChanged(&args);
}
}
@@ -693,6 +696,70 @@ std::optional<int32_t> InputReader::getBatteryStatus(int32_t deviceId) {
return std::nullopt;
}
+std::vector<int32_t> InputReader::getLightIds(int32_t deviceId) {
+ std::scoped_lock _l(mLock);
+
+ InputDevice* device = findInputDeviceLocked(deviceId);
+ if (device) {
+ InputDeviceInfo info;
+ device->getDeviceInfo(&info);
+ return info.getLightIds();
+ }
+ return {};
+}
+
+const InputDeviceLightInfo* InputReader::getLightInfo(int32_t deviceId, int32_t lightId) {
+ std::scoped_lock _l(mLock);
+
+ InputDevice* device = findInputDeviceLocked(deviceId);
+ if (device) {
+ InputDeviceInfo info;
+ device->getDeviceInfo(&info);
+ return info.getLightInfo(lightId);
+ }
+ return nullptr;
+}
+
+bool InputReader::setLightColor(int32_t deviceId, int32_t lightId, int32_t color) {
+ std::scoped_lock _l(mLock);
+
+ InputDevice* device = findInputDeviceLocked(deviceId);
+ if (device) {
+ return device->setLightColor(lightId, color);
+ }
+ return false;
+}
+
+bool InputReader::setLightPlayerId(int32_t deviceId, int32_t lightId, int32_t playerId) {
+ std::scoped_lock _l(mLock);
+
+ InputDevice* device = findInputDeviceLocked(deviceId);
+ if (device) {
+ return device->setLightPlayerId(lightId, playerId);
+ }
+ return false;
+}
+
+std::optional<int32_t> InputReader::getLightColor(int32_t deviceId, int32_t lightId) {
+ std::scoped_lock _l(mLock);
+
+ InputDevice* device = findInputDeviceLocked(deviceId);
+ if (device) {
+ return device->getLightColor(lightId);
+ }
+ return std::nullopt;
+}
+
+std::optional<int32_t> InputReader::getLightPlayerId(int32_t deviceId, int32_t lightId) {
+ std::scoped_lock _l(mLock);
+
+ InputDevice* device = findInputDeviceLocked(deviceId);
+ if (device) {
+ return device->getLightPlayerId(lightId);
+ }
+ return std::nullopt;
+}
+
bool InputReader::isInputDeviceEnabled(int32_t deviceId) {
std::scoped_lock _l(mLock);
@@ -885,69 +952,16 @@ InputReaderPolicyInterface* InputReader::ContextImpl::getPolicy() {
return mReader->mPolicy.get();
}
-EventHubInterface* InputReader::ContextImpl::getEventHub() {
- return mReader->mEventHub.get();
-}
-
-void InputReader::ContextImpl::notifyConfigurationChanged(nsecs_t when) {
- NotifyConfigurationChangedArgs args(mIdGenerator.nextId(), when);
- mReader->mQueuedListener->notifyConfigurationChanged(&args);
+InputListenerInterface* InputReader::ContextImpl::getListener() {
+ return mReader->mQueuedListener.get();
}
-void InputReader::ContextImpl::notifyKey(nsecs_t eventTime, int32_t deviceId, uint32_t source,
- int32_t displayId, uint32_t policyFlags, int32_t action,
- int32_t flags, int32_t keyCode, int32_t scanCode,
- int32_t metaState, nsecs_t downTime) {
- NotifyKeyArgs args(mIdGenerator.nextId(), eventTime, deviceId, source, displayId, policyFlags,
- action, flags, keyCode, scanCode, metaState, downTime);
- mReader->mQueuedListener->notifyKey(&args);
-}
-void InputReader::ContextImpl::notifyMotion(
- nsecs_t eventTime, int32_t deviceId, uint32_t source, int32_t displayId,
- uint32_t policyFlags, int32_t action, int32_t actionButton, int32_t flags,
- int32_t metaState, int32_t buttonState, MotionClassification classification,
- int32_t edgeFlags, uint32_t pointerCount, const PointerProperties* pointerProperties,
- const PointerCoords* pointerCoords, float xPrecision, float yPrecision,
- float xCursorPosition, float yCursorPosition, nsecs_t downTime,
- const std::vector<TouchVideoFrame>& videoFrames) {
- NotifyMotionArgs args(mIdGenerator.nextId(), eventTime, deviceId, source, displayId,
- policyFlags, action, actionButton, flags, metaState, buttonState,
- classification, edgeFlags, pointerCount, pointerProperties, pointerCoords,
- xPrecision, yPrecision, xCursorPosition, yCursorPosition, downTime,
- videoFrames);
- mReader->mQueuedListener->notifyMotion(&args);
-}
-
-void InputReader::ContextImpl::notifySensor(nsecs_t when, int32_t deviceId,
- InputDeviceSensorType sensorType,
- InputDeviceSensorAccuracy accuracy,
- bool accuracyChanged, nsecs_t timestamp,
- std::vector<float> values) {
- NotifySensorArgs args(mIdGenerator.nextId(), when, deviceId, AINPUT_SOURCE_SENSOR, sensorType,
- accuracy, accuracyChanged, timestamp, std::move(values));
- mReader->mQueuedListener->notifySensor(&args);
-}
-
-void InputReader::ContextImpl::notifyVibratorState(nsecs_t when, int32_t deviceId, bool isOn) {
- NotifyVibratorStateArgs args(mIdGenerator.nextId(), when, deviceId, isOn);
- mReader->mQueuedListener->notifyVibratorState(&args);
-}
-
-void InputReader::ContextImpl::notifySwitch(nsecs_t eventTime, uint32_t switchValues,
- uint32_t switchMask) {
- NotifySwitchArgs args(mIdGenerator.nextId(), eventTime, 0 /*policyFlags*/, switchValues,
- switchMask);
- mReader->mQueuedListener->notifySwitch(&args);
-}
-
-void InputReader::ContextImpl::notifyDeviceReset(nsecs_t when, int32_t deviceId) {
- NotifyDeviceResetArgs args(mIdGenerator.nextId(), when, deviceId);
- mReader->mQueuedListener->notifyDeviceReset(&args);
+EventHubInterface* InputReader::ContextImpl::getEventHub() {
+ return mReader->mEventHub.get();
}
-void InputReader::ContextImpl::notifyPointerCaptureChanged(nsecs_t when, bool hasCapture) {
- const NotifyPointerCaptureChangedArgs args(mIdGenerator.nextId(), when, hasCapture);
- mReader->mQueuedListener->notifyPointerCaptureChanged(&args);
+int32_t InputReader::ContextImpl::getNextId() {
+ return mIdGenerator.nextId();
}
} // namespace android
diff --git a/services/inputflinger/reader/include/EventHub.h b/services/inputflinger/reader/include/EventHub.h
index 30967dfdf2..e6164d38d4 100644
--- a/services/inputflinger/reader/include/EventHub.h
+++ b/services/inputflinger/reader/include/EventHub.h
@@ -47,6 +47,8 @@
namespace android {
+/* Number of colors : {red, green, blue} */
+static constexpr size_t COLOR_NUM = 3;
/*
* A raw event as retrieved from the EventHub.
*/
@@ -127,6 +129,9 @@ enum class InputDeviceClass : uint32_t {
/* The input device has a battery */
BATTERY = 0x00004000,
+ /* The input device has sysfs controllable lights */
+ LIGHT = 0x00008000,
+
/* The input device is virtual (not a real device, not part of UI configuration). */
VIRTUAL = 0x40000000,
@@ -134,6 +139,46 @@ enum class InputDeviceClass : uint32_t {
EXTERNAL = 0x80000000,
};
+enum class SysfsClass : uint32_t {
+ POWER_SUPPLY = 0,
+ LEDS = 1,
+};
+
+enum class LightColor : uint32_t {
+ RED = 0,
+ GREEN = 1,
+ BLUE = 2,
+};
+
+enum class InputLightClass : uint32_t {
+ /* The input light has brightness node. */
+ BRIGHTNESS = 0x00000001,
+ /* The input light has red name. */
+ RED = 0x00000002,
+ /* The input light has green name. */
+ GREEN = 0x00000004,
+ /* The input light has blue name. */
+ BLUE = 0x00000008,
+ /* The input light has global name. */
+ GLOBAL = 0x00000010,
+ /* The input light has multi index node. */
+ MULTI_INDEX = 0x00000020,
+ /* The input light has multi intensity node. */
+ MULTI_INTENSITY = 0x00000040,
+ /* The input light has max brightness node. */
+ MAX_BRIGHTNESS = 0x00000080,
+};
+
+/* Describes a raw light. */
+struct RawLightInfo {
+ int32_t id;
+ std::string name;
+ std::optional<int32_t> maxBrightness;
+ Flags<InputLightClass> flags;
+ std::array<int32_t, COLOR_NUM> rgbIndex;
+ std::filesystem::path path;
+};
+
/*
* Gets the class that owns an axis, in cases where multiple classes might claim
* the same axis for different purposes.
@@ -214,7 +259,16 @@ public:
virtual std::vector<TouchVideoFrame> getVideoFrames(int32_t deviceId) = 0;
virtual base::Result<std::pair<InputDeviceSensorType, int32_t>> mapSensor(int32_t deviceId,
int32_t absCode) = 0;
-
+ // Raw lights are sysfs led light nodes we found from the EventHub device sysfs node,
+ // containing the raw info of the sysfs node structure.
+ virtual const std::vector<int32_t> getRawLightIds(int32_t deviceId) = 0;
+ virtual std::optional<RawLightInfo> getRawLightInfo(int32_t deviceId, int32_t lightId) = 0;
+ virtual std::optional<int32_t> getLightBrightness(int32_t deviceId, int32_t lightId) = 0;
+ virtual void setLightBrightness(int32_t deviceId, int32_t lightId, int32_t brightness) = 0;
+ virtual std::optional<std::unordered_map<LightColor, int32_t>> getLightIntensities(
+ int32_t deviceId, int32_t lightId) = 0;
+ virtual void setLightIntensities(int32_t deviceId, int32_t lightId,
+ std::unordered_map<LightColor, int32_t> intensities) = 0;
/*
* Query current input state.
*/
@@ -377,6 +431,17 @@ public:
base::Result<std::pair<InputDeviceSensorType, int32_t>> mapSensor(
int32_t deviceId, int32_t absCode) override final;
+ const std::vector<int32_t> getRawLightIds(int32_t deviceId) override final;
+
+ std::optional<RawLightInfo> getRawLightInfo(int32_t deviceId, int32_t lightId) override final;
+
+ std::optional<int32_t> getLightBrightness(int32_t deviceId, int32_t lightId) override final;
+ void setLightBrightness(int32_t deviceId, int32_t lightId, int32_t brightness) override final;
+ std::optional<std::unordered_map<LightColor, int32_t>> getLightIntensities(
+ int32_t deviceId, int32_t lightId) override final;
+ void setLightIntensities(int32_t deviceId, int32_t lightId,
+ std::unordered_map<LightColor, int32_t> intensities) override final;
+
void setExcludedDevices(const std::vector<std::string>& devices) override final;
int32_t getScanCodeState(int32_t deviceId, int32_t scanCode) const override final;
@@ -458,9 +523,12 @@ private:
bool ffEffectPlaying;
int16_t ffEffectId; // initially -1
- // The paths are invalid when .empty() returns true
- std::filesystem::path sysfsRootPath;
- std::filesystem::path sysfsBatteryPath;
+ // The paths are invalid when they're std::nullopt
+ std::optional<std::filesystem::path> sysfsRootPath;
+ std::optional<std::filesystem::path> sysfsBatteryPath;
+ // maps from light id to light info
+ std::unordered_map<int32_t, RawLightInfo> lightInfos;
+ int32_t nextLightId;
int32_t controllerNumber;
@@ -491,6 +559,8 @@ private:
void setLedForControllerLocked();
status_t mapLed(int32_t led, int32_t* outScanCode) const;
void setLedStateLocked(int32_t led, bool on);
+ bool configureBatteryLocked();
+ bool configureLightsLocked();
};
status_t openDeviceLocked(const std::string& devicePath);
diff --git a/services/inputflinger/reader/include/InputDevice.h b/services/inputflinger/reader/include/InputDevice.h
index e4186c86cd..34c330b89c 100644
--- a/services/inputflinger/reader/include/InputDevice.h
+++ b/services/inputflinger/reader/include/InputDevice.h
@@ -95,6 +95,11 @@ public:
std::optional<int32_t> getBatteryCapacity();
std::optional<int32_t> getBatteryStatus();
+ bool setLightColor(int32_t lightId, int32_t color);
+ bool setLightPlayerId(int32_t lightId, int32_t playerId);
+ std::optional<int32_t> getLightColor(int32_t lightId);
+ std::optional<int32_t> getLightPlayerId(int32_t lightId);
+
int32_t getMetaState();
void updateMetaState(int32_t keyCode);
@@ -254,6 +259,30 @@ public:
return mEventHub->mapSensor(mId, absCode);
}
+ inline const std::vector<int32_t> getRawLightIds() { return mEventHub->getRawLightIds(mId); }
+
+ inline std::optional<RawLightInfo> getRawLightInfo(int32_t lightId) {
+ return mEventHub->getRawLightInfo(mId, lightId);
+ }
+
+ inline std::optional<int32_t> getLightBrightness(int32_t lightId) {
+ return mEventHub->getLightBrightness(mId, lightId);
+ }
+
+ inline void setLightBrightness(int32_t lightId, int32_t brightness) {
+ return mEventHub->setLightBrightness(mId, lightId, brightness);
+ }
+
+ inline std::optional<std::unordered_map<LightColor, int32_t>> getLightIntensities(
+ int32_t lightId) {
+ return mEventHub->getLightIntensities(mId, lightId);
+ }
+
+ inline void setLightIntensities(int32_t lightId,
+ std::unordered_map<LightColor, int32_t> intensities) {
+ return mEventHub->setLightIntensities(mId, lightId, intensities);
+ }
+
inline std::vector<TouchVideoFrame> getVideoFrames() { return mEventHub->getVideoFrames(mId); }
inline int32_t getScanCodeState(int32_t scanCode) const {
return mEventHub->getScanCodeState(mId, scanCode);
diff --git a/services/inputflinger/reader/include/InputReader.h b/services/inputflinger/reader/include/InputReader.h
index 5f78149d57..1405671a50 100644
--- a/services/inputflinger/reader/include/InputReader.h
+++ b/services/inputflinger/reader/include/InputReader.h
@@ -99,6 +99,18 @@ public:
std::optional<int32_t> getBatteryStatus(int32_t deviceId) override;
+ std::vector<int32_t> getLightIds(int32_t deviceId) override;
+
+ const InputDeviceLightInfo* getLightInfo(int32_t deviceId, int32_t lightId) override;
+
+ bool setLightColor(int32_t deviceId, int32_t lightId, int32_t color) override;
+
+ bool setLightPlayerId(int32_t deviceId, int32_t lightId, int32_t playerId) override;
+
+ std::optional<int32_t> getLightColor(int32_t deviceId, int32_t lightId) override;
+
+ std::optional<int32_t> getLightPlayerId(int32_t deviceId, int32_t lightId) override;
+
protected:
// These members are protected so they can be instrumented by test cases.
virtual std::shared_ptr<InputDevice> createDeviceLocked(int32_t deviceId,
@@ -131,31 +143,11 @@ protected:
void dispatchExternalStylusState(const StylusState& outState)
NO_THREAD_SAFETY_ANALYSIS override;
InputReaderPolicyInterface* getPolicy() NO_THREAD_SAFETY_ANALYSIS override;
+ InputListenerInterface* getListener() NO_THREAD_SAFETY_ANALYSIS override;
EventHubInterface* getEventHub() NO_THREAD_SAFETY_ANALYSIS override;
+ int32_t getNextId() NO_THREAD_SAFETY_ANALYSIS override;
void updateLedMetaState(int32_t metaState) NO_THREAD_SAFETY_ANALYSIS override;
int32_t getLedMetaState() NO_THREAD_SAFETY_ANALYSIS override;
-
- // Send events to InputListener interface
- void notifyConfigurationChanged(nsecs_t when) override;
- void notifyKey(nsecs_t eventTime, int32_t deviceId, uint32_t source, int32_t displayId,
- uint32_t policyFlags, int32_t action, int32_t flags, int32_t keyCode,
- int32_t scanCode, int32_t metaState, nsecs_t downTime) override;
- void notifyMotion(nsecs_t eventTime, int32_t deviceId, uint32_t source, int32_t displayId,
- uint32_t policyFlags, int32_t action, int32_t actionButton, int32_t flags,
- int32_t metaState, int32_t buttonState,
- MotionClassification classification, int32_t edgeFlags,
- uint32_t pointerCount, const PointerProperties* pointerProperties,
- const PointerCoords* pointerCoords, float xPrecision, float yPrecision,
- float xCursorPosition, float yCursorPosition, nsecs_t downTime,
- const std::vector<TouchVideoFrame>& videoFrames) override;
- void notifySwitch(nsecs_t eventTime, uint32_t switchValues, uint32_t switchMask) override;
- void notifySensor(nsecs_t when, int32_t deviceId, InputDeviceSensorType sensorType,
- InputDeviceSensorAccuracy accuracy, bool accuracyChanged,
- nsecs_t timestamp, std::vector<float> values) override;
- void notifyVibratorState(nsecs_t when, int32_t deviceId, bool isOn) override;
- void notifyDeviceReset(nsecs_t when, int32_t deviceId) override;
- void notifyPointerCaptureChanged(nsecs_t when, bool hasCapture) override;
-
} mContext;
friend class ContextImpl;
diff --git a/services/inputflinger/reader/include/InputReaderContext.h b/services/inputflinger/reader/include/InputReaderContext.h
index e6ea523c4f..dc807f7886 100644
--- a/services/inputflinger/reader/include/InputReaderContext.h
+++ b/services/inputflinger/reader/include/InputReaderContext.h
@@ -55,34 +55,13 @@ public:
virtual void dispatchExternalStylusState(const StylusState& outState) = 0;
virtual InputReaderPolicyInterface* getPolicy() = 0;
+ virtual InputListenerInterface* getListener() = 0;
virtual EventHubInterface* getEventHub() = 0;
+ virtual int32_t getNextId() = 0;
+
virtual void updateLedMetaState(int32_t metaState) = 0;
virtual int32_t getLedMetaState() = 0;
-
- // Send events to InputListener interface
-
- virtual void notifyConfigurationChanged(nsecs_t when) = 0;
- virtual void notifyKey(nsecs_t eventTime, int32_t deviceId, uint32_t source, int32_t displayId,
- uint32_t policyFlags, int32_t action, int32_t flags, int32_t keyCode,
- int32_t scanCode, int32_t metaState, nsecs_t downTime) = 0;
- virtual void notifyMotion(nsecs_t eventTime, int32_t deviceId, uint32_t source,
- int32_t displayId, uint32_t policyFlags, int32_t action,
- int32_t actionButton, int32_t flags, int32_t metaState,
- int32_t buttonState, MotionClassification classification,
- int32_t edgeFlags, uint32_t pointerCount,
- const PointerProperties* pointerProperties,
- const PointerCoords* pointerCoords, float xPrecision,
- float yPrecision, float xCursorPosition, float yCursorPosition,
- nsecs_t downTime,
- const std::vector<TouchVideoFrame>& videoFrames) = 0;
- virtual void notifySwitch(nsecs_t eventTime, uint32_t switchValues, uint32_t switchMask) = 0;
- virtual void notifySensor(nsecs_t when, int32_t deviceId, InputDeviceSensorType sensorType,
- InputDeviceSensorAccuracy accuracy, bool accuracyChanged,
- nsecs_t timestamp, std::vector<float> values) = 0;
- virtual void notifyVibratorState(nsecs_t when, int32_t deviceId, bool isOn) = 0;
- virtual void notifyDeviceReset(nsecs_t when, int32_t deviceId) = 0;
- virtual void notifyPointerCaptureChanged(nsecs_t when, bool hasCapture) = 0;
};
} // namespace android
diff --git a/services/inputflinger/reader/mapper/BatteryInputMapper.cpp b/services/inputflinger/reader/mapper/BatteryInputMapper.cpp
index afdc5abdc2..e4fb3a6c9f 100644
--- a/services/inputflinger/reader/mapper/BatteryInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/BatteryInputMapper.cpp
@@ -24,7 +24,7 @@ BatteryInputMapper::BatteryInputMapper(InputDeviceContext& deviceContext)
: InputMapper(deviceContext) {}
uint32_t BatteryInputMapper::getSources() {
- return 0;
+ return AINPUT_SOURCE_UNKNOWN;
}
void BatteryInputMapper::populateDeviceInfo(InputDeviceInfo* info) {
diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.cpp b/services/inputflinger/reader/mapper/CursorInputMapper.cpp
index 7f7b33cc3e..254b64b4d9 100644
--- a/services/inputflinger/reader/mapper/CursorInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/CursorInputMapper.cpp
@@ -175,7 +175,8 @@ void CursorInputMapper::configure(nsecs_t when, const InputReaderConfiguration*
}
bumpGeneration();
if (changes) {
- getContext()->notifyDeviceReset(when, getDeviceId());
+ NotifyDeviceResetArgs args(getContext()->getNextId(), when, getDeviceId());
+ getListener()->notifyDeviceReset(&args);
}
}
@@ -382,35 +383,40 @@ void CursorInputMapper::sync(nsecs_t when) {
while (!released.isEmpty()) {
int32_t actionButton = BitSet32::valueForBit(released.clearFirstMarkedBit());
buttonState &= ~actionButton;
- getContext()->notifyMotion(when, getDeviceId(), mSource, displayId, policyFlags,
- AMOTION_EVENT_ACTION_BUTTON_RELEASE, actionButton, 0,
- metaState, buttonState, MotionClassification::NONE,
- AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
- &pointerCoords, mXPrecision, mYPrecision,
- xCursorPosition, yCursorPosition, downTime,
- /* videoFrames */ {});
+ NotifyMotionArgs releaseArgs(getContext()->getNextId(), when, getDeviceId(),
+ mSource, displayId, policyFlags,
+ AMOTION_EVENT_ACTION_BUTTON_RELEASE, actionButton, 0,
+ metaState, buttonState, MotionClassification::NONE,
+ AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
+ &pointerCoords, mXPrecision, mYPrecision,
+ xCursorPosition, yCursorPosition, downTime,
+ /* videoFrames */ {});
+ getListener()->notifyMotion(&releaseArgs);
}
}
- getContext()->notifyMotion(when, getDeviceId(), mSource, displayId, policyFlags,
- motionEventAction, 0, 0, metaState, currentButtonState,
- MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1,
- &pointerProperties, &pointerCoords, mXPrecision, mYPrecision,
- xCursorPosition, yCursorPosition, downTime,
- /* videoFrames */ {});
+ NotifyMotionArgs args(getContext()->getNextId(), when, getDeviceId(), mSource, displayId,
+ policyFlags, motionEventAction, 0, 0, metaState, currentButtonState,
+ MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1,
+ &pointerProperties, &pointerCoords, mXPrecision, mYPrecision,
+ xCursorPosition, yCursorPosition, downTime,
+ /* videoFrames */ {});
+ getListener()->notifyMotion(&args);
if (buttonsPressed) {
BitSet32 pressed(buttonsPressed);
while (!pressed.isEmpty()) {
int32_t actionButton = BitSet32::valueForBit(pressed.clearFirstMarkedBit());
buttonState |= actionButton;
- getContext()->notifyMotion(when, getDeviceId(), mSource, displayId, policyFlags,
+ NotifyMotionArgs pressArgs(getContext()->getNextId(), when, getDeviceId(), mSource,
+ displayId, policyFlags,
AMOTION_EVENT_ACTION_BUTTON_PRESS, actionButton, 0,
metaState, buttonState, MotionClassification::NONE,
AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
&pointerCoords, mXPrecision, mYPrecision,
xCursorPosition, yCursorPosition, downTime,
/* videoFrames */ {});
+ getListener()->notifyMotion(&pressArgs);
}
}
@@ -418,12 +424,13 @@ void CursorInputMapper::sync(nsecs_t when) {
// Send hover move after UP to tell the application that the mouse is hovering now.
if (motionEventAction == AMOTION_EVENT_ACTION_UP && (mSource == AINPUT_SOURCE_MOUSE)) {
- getContext()->notifyMotion(when, getDeviceId(), mSource, displayId, policyFlags,
- AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState,
- currentButtonState, MotionClassification::NONE,
+ NotifyMotionArgs hoverArgs(getContext()->getNextId(), when, getDeviceId(), mSource,
+ displayId, policyFlags, AMOTION_EVENT_ACTION_HOVER_MOVE, 0,
+ 0, metaState, currentButtonState, MotionClassification::NONE,
AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
&pointerCoords, mXPrecision, mYPrecision, xCursorPosition,
yCursorPosition, downTime, /* videoFrames */ {});
+ getListener()->notifyMotion(&hoverArgs);
}
// Send scroll events.
@@ -431,12 +438,13 @@ void CursorInputMapper::sync(nsecs_t when) {
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_VSCROLL, vscroll);
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll);
- getContext()->notifyMotion(when, getDeviceId(), mSource, displayId, policyFlags,
- AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState,
- currentButtonState, MotionClassification::NONE,
- AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
- &pointerCoords, mXPrecision, mYPrecision, xCursorPosition,
- yCursorPosition, downTime, /* videoFrames */ {});
+ NotifyMotionArgs scrollArgs(getContext()->getNextId(), when, getDeviceId(), mSource,
+ displayId, policyFlags, AMOTION_EVENT_ACTION_SCROLL, 0, 0,
+ metaState, currentButtonState, MotionClassification::NONE,
+ AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
+ &pointerCoords, mXPrecision, mYPrecision, xCursorPosition,
+ yCursorPosition, downTime, /* videoFrames */ {});
+ getListener()->notifyMotion(&scrollArgs);
}
}
diff --git a/services/inputflinger/reader/mapper/InputMapper.h b/services/inputflinger/reader/mapper/InputMapper.h
index 44af998693..bd543e5798 100644
--- a/services/inputflinger/reader/mapper/InputMapper.h
+++ b/services/inputflinger/reader/mapper/InputMapper.h
@@ -19,6 +19,7 @@
#include "EventHub.h"
#include "InputDevice.h"
+#include "InputListener.h"
#include "InputReaderContext.h"
#include "StylusState.h"
#include "VibrationElement.h"
@@ -47,6 +48,7 @@ public:
inline const std::string getDeviceName() { return mDeviceContext.getName(); }
inline InputReaderContext* getContext() { return mDeviceContext.getContext(); }
inline InputReaderPolicyInterface* getPolicy() { return getContext()->getPolicy(); }
+ inline InputListenerInterface* getListener() { return getContext()->getListener(); }
virtual uint32_t getSources() = 0;
virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo);
@@ -75,6 +77,11 @@ public:
virtual std::optional<int32_t> getBatteryCapacity() { return std::nullopt; }
virtual std::optional<int32_t> getBatteryStatus() { return std::nullopt; }
+ virtual bool setLightColor(int32_t lightId, int32_t color) { return true; }
+ virtual bool setLightPlayerId(int32_t lightId, int32_t playerId) { return true; }
+ virtual std::optional<int32_t> getLightColor(int32_t lightId) { return std::nullopt; }
+ virtual std::optional<int32_t> getLightPlayerId(int32_t lightId) { return std::nullopt; }
+
virtual int32_t getMetaState();
virtual void updateMetaState(int32_t keyCode);
diff --git a/services/inputflinger/reader/mapper/JoystickInputMapper.cpp b/services/inputflinger/reader/mapper/JoystickInputMapper.cpp
index 28f29e0a0a..37aa140c16 100644
--- a/services/inputflinger/reader/mapper/JoystickInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/JoystickInputMapper.cpp
@@ -337,12 +337,13 @@ void JoystickInputMapper::sync(nsecs_t when, bool force) {
// TODO: Use the input device configuration to control this behavior more finely.
uint32_t policyFlags = 0;
- getContext()->notifyMotion(when, getDeviceId(), AINPUT_SOURCE_JOYSTICK, ADISPLAY_ID_NONE,
- policyFlags, AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState,
- MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1,
- &pointerProperties, &pointerCoords, 0, 0,
- AMOTION_EVENT_INVALID_CURSOR_POSITION,
- AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, /* videoFrames */ {});
+ NotifyMotionArgs args(getContext()->getNextId(), when, getDeviceId(), AINPUT_SOURCE_JOYSTICK,
+ ADISPLAY_ID_NONE, policyFlags, AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState,
+ buttonState, MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1,
+ &pointerProperties, &pointerCoords, 0, 0,
+ AMOTION_EVENT_INVALID_CURSOR_POSITION,
+ AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, /* videoFrames */ {});
+ getListener()->notifyMotion(&args);
}
void JoystickInputMapper::setPointerCoordsAxisValue(PointerCoords* pointerCoords, int32_t axis,
diff --git a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
index 03d740529f..8b9f235438 100644
--- a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
@@ -350,9 +350,10 @@ void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t scanCode,
policyFlags |= POLICY_FLAG_DISABLE_KEY_REPEAT;
}
- getContext()->notifyKey(when, getDeviceId(), mSource, getDisplayId(), policyFlags,
- down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP,
- AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, keyMetaState, downTime);
+ NotifyKeyArgs args(getContext()->getNextId(), when, getDeviceId(), mSource, getDisplayId(),
+ policyFlags, down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP,
+ AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, keyMetaState, downTime);
+ getListener()->notifyKey(&args);
}
ssize_t KeyboardInputMapper::findKeyDown(int32_t scanCode) {
diff --git a/services/inputflinger/reader/mapper/LightInputMapper.cpp b/services/inputflinger/reader/mapper/LightInputMapper.cpp
new file mode 100644
index 0000000000..be1f722e2e
--- /dev/null
+++ b/services/inputflinger/reader/mapper/LightInputMapper.cpp
@@ -0,0 +1,478 @@
+/*
+ * 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 <locale>
+#include <regex>
+
+#include "../Macros.h"
+
+#include "LightInputMapper.h"
+#include "input/NamedEnum.h"
+
+// Log detailed debug messages about input device lights.
+static constexpr bool DEBUG_LIGHT_DETAILS = false;
+
+namespace android {
+
+static inline int32_t getAlpha(int32_t color) {
+ return (color >> 24) & 0xff;
+}
+
+static inline int32_t getRed(int32_t color) {
+ return (color >> 16) & 0xff;
+}
+
+static inline int32_t getGreen(int32_t color) {
+ return (color >> 8) & 0xff;
+}
+
+static inline int32_t getBlue(int32_t color) {
+ return color & 0xff;
+}
+
+static inline int32_t toArgb(int32_t brightness, int32_t red, int32_t green, int32_t blue) {
+ return (brightness & 0xff) << 24 | (red & 0xff) << 16 | (green & 0xff) << 8 | (blue & 0xff);
+}
+
+/**
+ * Light input mapper owned by InputReader device, implements the native API for querying input
+ * lights, getting and setting the lights brightness and color, by interacting with EventHub
+ * devices.
+ * TODO b/180342233: Reconsider the inputflinger design to accommodate the device class
+ * like lights and battery.
+ */
+LightInputMapper::LightInputMapper(InputDeviceContext& deviceContext)
+ : InputMapper(deviceContext) {}
+
+LightInputMapper::~LightInputMapper() {}
+
+std::optional<std::int32_t> LightInputMapper::Light::getRawLightBrightness(int32_t rawLightId) {
+ std::optional<RawLightInfo> rawInfo = context.getRawLightInfo(rawLightId);
+ std::optional<int32_t> ret = context.getLightBrightness(rawLightId);
+ if (!rawInfo.has_value() || !ret.has_value()) {
+ return std::nullopt;
+ }
+ int brightness = ret.value();
+
+ // If the light node doesn't have max brightness, use the default max brightness.
+ int rawMaxBrightness = rawInfo->maxBrightness.value_or(MAX_BRIGHTNESS);
+ float ratio = MAX_BRIGHTNESS / rawMaxBrightness;
+ // Scale the returned brightness in [0, rawMaxBrightness] to [0, 255]
+ if (rawMaxBrightness != MAX_BRIGHTNESS) {
+ brightness = brightness * ratio;
+ }
+ if (DEBUG_LIGHT_DETAILS) {
+ ALOGD("getRawLightBrightness rawLightId %d brightness 0x%x ratio %.2f", rawLightId,
+ brightness, ratio);
+ }
+ return brightness;
+}
+
+void LightInputMapper::Light::setRawLightBrightness(int32_t rawLightId, int32_t brightness) {
+ std::optional<RawLightInfo> rawInfo = context.getRawLightInfo(rawLightId);
+ if (!rawInfo.has_value()) {
+ return;
+ }
+ // If the light node doesn't have max brightness, use the default max brightness.
+ int rawMaxBrightness = rawInfo->maxBrightness.value_or(MAX_BRIGHTNESS);
+ float ratio = MAX_BRIGHTNESS / rawMaxBrightness;
+ // Scale the requested brightness in [0, 255] to [0, rawMaxBrightness]
+ if (rawMaxBrightness != MAX_BRIGHTNESS) {
+ brightness = ceil(brightness / ratio);
+ }
+ if (DEBUG_LIGHT_DETAILS) {
+ ALOGD("setRawLightBrightness rawLightId %d brightness 0x%x ratio %.2f", rawLightId,
+ brightness, ratio);
+ }
+ context.setLightBrightness(rawLightId, brightness);
+}
+
+bool LightInputMapper::SingleLight::setLightColor(int32_t color) {
+ int32_t brightness = getAlpha(color);
+ setRawLightBrightness(rawId, brightness);
+
+ return true;
+}
+
+bool LightInputMapper::RgbLight::setLightColor(int32_t color) {
+ // Compose color value as per:
+ // https://developer.android.com/reference/android/graphics/Color?hl=en
+ // int color = (A & 0xff) << 24 | (R & 0xff) << 16 | (G & 0xff) << 8 | (B & 0xff);
+ // The alpha component is used to scale the R,G,B leds brightness, with the ratio to
+ // MAX_BRIGHTNESS.
+ brightness = getAlpha(color);
+ int32_t red = 0;
+ int32_t green = 0;
+ int32_t blue = 0;
+ if (brightness > 0) {
+ float ratio = MAX_BRIGHTNESS / brightness;
+ red = ceil(getRed(color) / ratio);
+ green = ceil(getGreen(color) / ratio);
+ blue = ceil(getBlue(color) / ratio);
+ }
+ setRawLightBrightness(rawRgbIds.at(LightColor::RED), red);
+ setRawLightBrightness(rawRgbIds.at(LightColor::GREEN), green);
+ setRawLightBrightness(rawRgbIds.at(LightColor::BLUE), blue);
+ if (rawGlobalId.has_value()) {
+ setRawLightBrightness(rawGlobalId.value(), brightness);
+ }
+
+ return true;
+}
+
+bool LightInputMapper::MultiColorLight::setLightColor(int32_t color) {
+ std::unordered_map<LightColor, int32_t> intensities;
+ intensities.emplace(LightColor::RED, getRed(color));
+ intensities.emplace(LightColor::GREEN, getGreen(color));
+ intensities.emplace(LightColor::BLUE, getBlue(color));
+
+ context.setLightIntensities(rawId, intensities);
+ setRawLightBrightness(rawId, getAlpha(color));
+ return true;
+}
+
+std::optional<int32_t> LightInputMapper::SingleLight::getLightColor() {
+ std::optional<int32_t> brightness = getRawLightBrightness(rawId);
+ if (!brightness.has_value()) {
+ return std::nullopt;
+ }
+
+ return toArgb(brightness.value(), 0 /* red */, 0 /* green */, 0 /* blue */);
+}
+
+std::optional<int32_t> LightInputMapper::RgbLight::getLightColor() {
+ // If the Alpha component is zero, then return color 0.
+ if (brightness == 0) {
+ return 0;
+ }
+ // Compose color value as per:
+ // https://developer.android.com/reference/android/graphics/Color?hl=en
+ // int color = (A & 0xff) << 24 | (R & 0xff) << 16 | (G & 0xff) << 8 | (B & 0xff);
+ std::optional<int32_t> redOr = getRawLightBrightness(rawRgbIds.at(LightColor::RED));
+ std::optional<int32_t> greenOr = getRawLightBrightness(rawRgbIds.at(LightColor::GREEN));
+ std::optional<int32_t> blueOr = getRawLightBrightness(rawRgbIds.at(LightColor::BLUE));
+ // If we can't get brightness for any of the RGB light
+ if (!redOr.has_value() || !greenOr.has_value() || !blueOr.has_value()) {
+ return std::nullopt;
+ }
+
+ // Compose the ARGB format color. As the R,G,B color led brightness is scaled by Alpha
+ // value, scale it back to return the nominal color value.
+ float ratio = MAX_BRIGHTNESS / brightness;
+ int32_t red = round(redOr.value() * ratio);
+ int32_t green = round(greenOr.value() * ratio);
+ int32_t blue = round(blueOr.value() * ratio);
+
+ if (red > MAX_BRIGHTNESS || green > MAX_BRIGHTNESS || blue > MAX_BRIGHTNESS) {
+ // Previously stored brightness isn't valid for current LED values, so just reset to max
+ // brightness since an app couldn't have provided these values in the first place.
+ red = redOr.value();
+ green = greenOr.value();
+ blue = blueOr.value();
+ brightness = MAX_BRIGHTNESS;
+ }
+
+ return toArgb(brightness, red, green, blue);
+}
+
+std::optional<int32_t> LightInputMapper::MultiColorLight::getLightColor() {
+ auto ret = context.getLightIntensities(rawId);
+ if (!ret.has_value()) {
+ return std::nullopt;
+ }
+ std::unordered_map<LightColor, int32_t> intensities = ret.value();
+ // Get red, green, blue colors
+ int32_t color = toArgb(0 /* brightness */, intensities.at(LightColor::RED) /* red */,
+ intensities.at(LightColor::GREEN) /* green */,
+ intensities.at(LightColor::BLUE) /* blue */);
+ // Get brightness
+ std::optional<int32_t> brightness = getRawLightBrightness(rawId);
+ if (brightness.has_value()) {
+ return toArgb(brightness.value() /* A */, 0, 0, 0) | color;
+ }
+ return std::nullopt;
+}
+
+bool LightInputMapper::PlayerIdLight::setLightPlayerId(int32_t playerId) {
+ if (rawLightIds.find(playerId) == rawLightIds.end()) {
+ return false;
+ }
+ for (const auto& [id, rawId] : rawLightIds) {
+ if (playerId == id) {
+ setRawLightBrightness(rawId, MAX_BRIGHTNESS);
+ } else {
+ setRawLightBrightness(rawId, 0);
+ }
+ }
+ return true;
+}
+
+std::optional<int32_t> LightInputMapper::PlayerIdLight::getLightPlayerId() {
+ for (const auto& [id, rawId] : rawLightIds) {
+ std::optional<int32_t> brightness = getRawLightBrightness(rawId);
+ if (brightness.has_value() && brightness.value() > 0) {
+ return id;
+ }
+ }
+ return std::nullopt;
+}
+
+void LightInputMapper::SingleLight::dump(std::string& dump) {
+ dump += StringPrintf(INDENT4 "Color: 0x%x\n", getLightColor().value_or(0));
+}
+
+void LightInputMapper::PlayerIdLight::dump(std::string& dump) {
+ dump += StringPrintf(INDENT4 "PlayerId: %d\n", getLightPlayerId().value_or(-1));
+ dump += StringPrintf(INDENT4 "Raw Player ID LEDs:");
+ for (const auto& [id, rawId] : rawLightIds) {
+ dump += StringPrintf("id %d -> %d ", id, rawId);
+ }
+ dump += "\n";
+}
+
+void LightInputMapper::RgbLight::dump(std::string& dump) {
+ dump += StringPrintf(INDENT4 "Color: 0x%x\n", getLightColor().value_or(0));
+ dump += StringPrintf(INDENT4 "Raw RGB LEDs: [%d, %d, %d] ", rawRgbIds.at(LightColor::RED),
+ rawRgbIds.at(LightColor::GREEN), rawRgbIds.at(LightColor::BLUE));
+ if (rawGlobalId.has_value()) {
+ dump += StringPrintf(INDENT4 "Raw Global LED: [%d] ", rawGlobalId.value());
+ }
+ dump += "\n";
+}
+
+void LightInputMapper::MultiColorLight::dump(std::string& dump) {
+ dump += StringPrintf(INDENT4 "Color: 0x%x\n", getLightColor().value_or(0));
+}
+
+uint32_t LightInputMapper::getSources() {
+ return AINPUT_SOURCE_UNKNOWN;
+}
+
+void LightInputMapper::populateDeviceInfo(InputDeviceInfo* info) {
+ InputMapper::populateDeviceInfo(info);
+
+ for (const auto& [lightId, light] : mLights) {
+ // Input device light doesn't support ordinal, always pass 1.
+ InputDeviceLightInfo lightInfo(light->name, light->id, light->type, 1 /* ordinal */);
+ info->addLightInfo(lightInfo);
+ }
+}
+
+void LightInputMapper::dump(std::string& dump) {
+ dump += INDENT2 "Light Input Mapper:\n";
+ dump += INDENT3 "Lights:\n";
+ for (const auto& [lightId, light] : mLights) {
+ dump += StringPrintf(INDENT4 "Id: %d", lightId);
+ dump += StringPrintf(INDENT4 "Name: %s", light->name.c_str());
+ dump += StringPrintf(INDENT4 "Type: %s", NamedEnum::string(light->type).c_str());
+ light->dump(dump);
+ }
+ // Dump raw lights
+ dump += INDENT3 "RawLights:\n";
+ dump += INDENT4 "Id:\t Name:\t Flags:\t Max brightness:\t Brightness\n";
+ const std::vector<int32_t> rawLightIds = getDeviceContext().getRawLightIds();
+ // Map from raw light id to raw light info
+ std::unordered_map<int32_t, RawLightInfo> rawInfos;
+ for (const auto& rawId : rawLightIds) {
+ std::optional<RawLightInfo> rawInfo = getDeviceContext().getRawLightInfo(rawId);
+ if (!rawInfo.has_value()) {
+ continue;
+ }
+ dump += StringPrintf(INDENT4 "%d", rawId);
+ dump += StringPrintf(INDENT4 "%s", rawInfo->name.c_str());
+ dump += StringPrintf(INDENT4 "%s", rawInfo->flags.string().c_str());
+ dump += StringPrintf(INDENT4 "%d", rawInfo->maxBrightness.value_or(MAX_BRIGHTNESS));
+ dump += StringPrintf(INDENT4 "%d\n",
+ getDeviceContext().getLightBrightness(rawId).value_or(-1));
+ }
+}
+
+void LightInputMapper::configure(nsecs_t when, const InputReaderConfiguration* config,
+ uint32_t changes) {
+ InputMapper::configure(when, config, changes);
+
+ if (!changes) { // first time only
+ bool hasRedLed = false;
+ bool hasGreenLed = false;
+ bool hasBlueLed = false;
+ std::optional<int32_t> rawGlobalId = std::nullopt;
+ // Player ID light common name string
+ std::string playerIdName;
+ // Raw RGB color to raw light ID
+ std::unordered_map<LightColor, int32_t /* rawLightId */> rawRgbIds;
+ // Map from player Id to raw light Id
+ std::unordered_map<int32_t, int32_t> playerIdLightIds;
+ mLights.clear();
+
+ // Check raw lights
+ const std::vector<int32_t> rawLightIds = getDeviceContext().getRawLightIds();
+ // Map from raw light id to raw light info
+ std::unordered_map<int32_t, RawLightInfo> rawInfos;
+ for (const auto& rawId : rawLightIds) {
+ std::optional<RawLightInfo> rawInfo = getDeviceContext().getRawLightInfo(rawId);
+ if (!rawInfo.has_value()) {
+ continue;
+ }
+ rawInfos.insert_or_assign(rawId, rawInfo.value());
+ // Check if this is a group LEDs for player ID
+ std::regex lightPattern("([a-z]+)([0-9]+)");
+ std::smatch results;
+ if (std::regex_match(rawInfo->name, results, lightPattern)) {
+ std::string commonName = results[1].str();
+ int32_t playerId = std::stoi(results[2]);
+ if (playerIdLightIds.empty()) {
+ playerIdName = commonName;
+ playerIdLightIds.insert_or_assign(playerId, rawId);
+ } else {
+ // Make sure the player ID leds have common string name
+ if (playerIdName.compare(commonName) == 0 &&
+ playerIdLightIds.find(playerId) == playerIdLightIds.end()) {
+ playerIdLightIds.insert_or_assign(playerId, rawId);
+ }
+ }
+ }
+ // Check if this is an LED of RGB light
+ if (rawInfo->flags.test(InputLightClass::RED)) {
+ hasRedLed = true;
+ rawRgbIds.emplace(LightColor::RED, rawId);
+ }
+ if (rawInfo->flags.test(InputLightClass::GREEN)) {
+ hasGreenLed = true;
+ rawRgbIds.emplace(LightColor::GREEN, rawId);
+ }
+ if (rawInfo->flags.test(InputLightClass::BLUE)) {
+ hasBlueLed = true;
+ rawRgbIds.emplace(LightColor::BLUE, rawId);
+ }
+ if (rawInfo->flags.test(InputLightClass::GLOBAL)) {
+ rawGlobalId = rawId;
+ }
+ if (DEBUG_LIGHT_DETAILS) {
+ ALOGD("Light rawId %d name %s max %d flags %s \n", rawInfo->id,
+ rawInfo->name.c_str(), rawInfo->maxBrightness.value_or(MAX_BRIGHTNESS),
+ rawInfo->flags.string().c_str());
+ }
+ }
+
+ // Construct a player ID light
+ if (playerIdLightIds.size() > 1) {
+ std::unique_ptr<Light> light =
+ std::make_unique<PlayerIdLight>(getDeviceContext(), playerIdName, ++mNextId,
+ playerIdLightIds);
+ mLights.insert_or_assign(light->id, std::move(light));
+ // Remove these raw lights from raw light info as they've been used to compose a
+ // Player ID light, so we do not expose these raw lights as single lights.
+ for (const auto& [playerId, rawId] : playerIdLightIds) {
+ rawInfos.erase(rawId);
+ }
+ }
+ // Construct a RGB light for composed RGB light
+ if (hasRedLed && hasGreenLed && hasBlueLed) {
+ if (DEBUG_LIGHT_DETAILS) {
+ ALOGD("Rgb light ids [%d, %d, %d] \n", rawRgbIds.at(LightColor::RED),
+ rawRgbIds.at(LightColor::GREEN), rawRgbIds.at(LightColor::BLUE));
+ }
+ std::unique_ptr<Light> light = std::make_unique<RgbLight>(getDeviceContext(), ++mNextId,
+ rawRgbIds, rawGlobalId);
+ mLights.insert_or_assign(light->id, std::move(light));
+ // Remove from raw light info as they've been composed a RBG light.
+ rawInfos.erase(rawRgbIds.at(LightColor::RED));
+ rawInfos.erase(rawRgbIds.at(LightColor::GREEN));
+ rawInfos.erase(rawRgbIds.at(LightColor::BLUE));
+ if (rawGlobalId.has_value()) {
+ rawInfos.erase(rawGlobalId.value());
+ }
+ }
+
+ // Check the rest of raw light infos
+ for (const auto& [rawId, rawInfo] : rawInfos) {
+ // If the node is multi-color led, construct a MULTI_COLOR light
+ if (rawInfo.flags.test(InputLightClass::MULTI_INDEX) &&
+ rawInfo.flags.test(InputLightClass::MULTI_INTENSITY)) {
+ if (DEBUG_LIGHT_DETAILS) {
+ ALOGD("Multicolor light Id %d name %s \n", rawInfo.id, rawInfo.name.c_str());
+ }
+ std::unique_ptr<Light> light =
+ std::make_unique<MultiColorLight>(getDeviceContext(), rawInfo.name,
+ ++mNextId, rawInfo.id);
+ mLights.insert_or_assign(light->id, std::move(light));
+ continue;
+ }
+ // Construct a single LED light
+ if (DEBUG_LIGHT_DETAILS) {
+ ALOGD("Single light Id %d name %s \n", rawInfo.id, rawInfo.name.c_str());
+ }
+ std::unique_ptr<Light> light =
+ std::make_unique<SingleLight>(getDeviceContext(), rawInfo.name, ++mNextId,
+ rawInfo.id);
+
+ mLights.insert_or_assign(light->id, std::move(light));
+ }
+ }
+}
+
+void LightInputMapper::reset(nsecs_t when) {
+ InputMapper::reset(when);
+}
+
+void LightInputMapper::process(const RawEvent* rawEvent) {}
+
+bool LightInputMapper::setLightColor(int32_t lightId, int32_t color) {
+ auto it = mLights.find(lightId);
+ if (it == mLights.end()) {
+ return false;
+ }
+ auto& light = it->second;
+ if (DEBUG_LIGHT_DETAILS) {
+ ALOGD("setLightColor lightId %d type %s color 0x%x", lightId,
+ NamedEnum::string(light->type).c_str(), color);
+ }
+ return light->setLightColor(color);
+}
+
+std::optional<int32_t> LightInputMapper::getLightColor(int32_t lightId) {
+ auto it = mLights.find(lightId);
+ if (it == mLights.end()) {
+ return std::nullopt;
+ }
+ auto& light = it->second;
+ std::optional<int32_t> color = light->getLightColor();
+ if (DEBUG_LIGHT_DETAILS) {
+ ALOGD("getLightColor lightId %d type %s color 0x%x", lightId,
+ NamedEnum::string(light->type).c_str(), color.value_or(0));
+ }
+ return color;
+}
+
+bool LightInputMapper::setLightPlayerId(int32_t lightId, int32_t playerId) {
+ auto it = mLights.find(lightId);
+ if (it == mLights.end()) {
+ return false;
+ }
+ auto& light = it->second;
+ return light->setLightPlayerId(playerId);
+}
+
+std::optional<int32_t> LightInputMapper::getLightPlayerId(int32_t lightId) {
+ auto it = mLights.find(lightId);
+ if (it == mLights.end()) {
+ return std::nullopt;
+ }
+ auto& light = it->second;
+ return light->getLightPlayerId();
+}
+
+} // namespace android
diff --git a/services/inputflinger/reader/mapper/LightInputMapper.h b/services/inputflinger/reader/mapper/LightInputMapper.h
new file mode 100644
index 0000000000..9254720385
--- /dev/null
+++ b/services/inputflinger/reader/mapper/LightInputMapper.h
@@ -0,0 +1,135 @@
+/*
+ * 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.
+ */
+
+#ifndef _UI_INPUTREADER_LIGHT_INPUT_MAPPER_H
+#define _UI_INPUTREADER_LIGHT_INPUT_MAPPER_H
+
+#include "InputMapper.h"
+
+namespace android {
+
+class LightInputMapper : public InputMapper {
+ // Refer to https://developer.android.com/reference/kotlin/android/graphics/Color
+ /* Number of colors : {red, green, blue} */
+ static constexpr size_t COLOR_NUM = 3;
+ static constexpr int32_t MAX_BRIGHTNESS = 0xff;
+
+public:
+ explicit LightInputMapper(InputDeviceContext& deviceContext);
+ ~LightInputMapper() override;
+
+ uint32_t getSources() override;
+ void populateDeviceInfo(InputDeviceInfo* deviceInfo) override;
+ void dump(std::string& dump) override;
+ void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes) override;
+ void reset(nsecs_t when) override;
+ void process(const RawEvent* rawEvent) override;
+ bool setLightColor(int32_t lightId, int32_t color) override;
+ bool setLightPlayerId(int32_t lightId, int32_t playerId) override;
+ std::optional<int32_t> getLightColor(int32_t lightId) override;
+ std::optional<int32_t> getLightPlayerId(int32_t lightId) override;
+
+private:
+ struct Light {
+ explicit Light(InputDeviceContext& context, std::string name, int32_t id,
+ InputDeviceLightType type)
+ : context(context), name(name), id(id), type(type) {}
+ virtual ~Light() {}
+ InputDeviceContext& context;
+ std::string name;
+ int32_t id;
+ InputDeviceLightType type;
+
+ virtual bool setLightColor(int32_t color) { return false; }
+ virtual std::optional<int32_t> getLightColor() { return std::nullopt; }
+ virtual bool setLightPlayerId(int32_t playerId) { return false; }
+ virtual std::optional<int32_t> getLightPlayerId() { return std::nullopt; }
+
+ virtual void dump(std::string& dump) {}
+
+ std::optional<std::int32_t> getRawLightBrightness(int32_t rawLightId);
+ void setRawLightBrightness(int32_t rawLightId, int32_t brightness);
+ };
+
+ struct SingleLight : public Light {
+ explicit SingleLight(InputDeviceContext& context, std::string name, int32_t id,
+ int32_t rawId)
+ : Light(context, name, id, InputDeviceLightType::SINGLE), rawId(rawId) {}
+ int32_t rawId;
+
+ bool setLightColor(int32_t color) override;
+ std::optional<int32_t> getLightColor() override;
+ void dump(std::string& dump) override;
+ };
+
+ struct RgbLight : public Light {
+ explicit RgbLight(InputDeviceContext& context, int32_t id,
+ std::unordered_map<LightColor, int32_t> rawRgbIds,
+ std::optional<int32_t> rawGlobalId)
+ : Light(context, "RGB", id, InputDeviceLightType::RGB),
+ rawRgbIds(rawRgbIds),
+ rawGlobalId(rawGlobalId) {
+ brightness = rawGlobalId.has_value()
+ ? getRawLightBrightness(rawGlobalId.value()).value_or(MAX_BRIGHTNESS)
+ : MAX_BRIGHTNESS;
+ }
+ // Map from color to raw light id.
+ std::unordered_map<LightColor, int32_t /* rawLightId */> rawRgbIds;
+ // Optional global control raw light id.
+ std::optional<int32_t> rawGlobalId;
+ int32_t brightness;
+
+ bool setLightColor(int32_t color) override;
+ std::optional<int32_t> getLightColor() override;
+ void dump(std::string& dump) override;
+ };
+
+ struct MultiColorLight : public Light {
+ explicit MultiColorLight(InputDeviceContext& context, std::string name, int32_t id,
+ int32_t rawId)
+ : Light(context, name, id, InputDeviceLightType::MULTI_COLOR), rawId(rawId) {}
+ int32_t rawId;
+
+ bool setLightColor(int32_t color) override;
+ std::optional<int32_t> getLightColor() override;
+ void dump(std::string& dump) override;
+ };
+
+ struct PlayerIdLight : public Light {
+ explicit PlayerIdLight(InputDeviceContext& context, std::string name, int32_t id,
+ std::unordered_map<int32_t, int32_t> rawLightIds)
+ : Light(context, name, id, InputDeviceLightType::PLAYER_ID),
+ rawLightIds(rawLightIds) {}
+ // Map from player Id to raw light Id
+ std::unordered_map<int32_t, int32_t> rawLightIds;
+
+ bool setLightPlayerId(int32_t palyerId) override;
+ std::optional<int32_t> getLightPlayerId() override;
+ void dump(std::string& dump) override;
+ };
+
+ int32_t mNextId = 0;
+
+ // Light color map from light color to the color index.
+ static const std::unordered_map<std::string, size_t> LIGHT_COLORS;
+
+ // Light map from light ID to Light
+ std::unordered_map<int32_t, std::unique_ptr<Light>> mLights;
+};
+
+} // namespace android
+
+#endif // _UI_INPUTREADER_LIGHT_INPUT_MAPPER_H \ No newline at end of file
diff --git a/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp b/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp
index 3f8a36433f..594ff42f87 100644
--- a/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp
@@ -121,12 +121,13 @@ void RotaryEncoderInputMapper::sync(nsecs_t when) {
int32_t metaState = getContext()->getGlobalMetaState();
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_SCROLL, scroll * mScalingFactor);
- getContext()->notifyMotion(when, getDeviceId(), mSource, displayId, policyFlags,
- AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState,
- /* buttonState */ 0, MotionClassification::NONE,
- AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
- &pointerCoords, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
- AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, /* videoFrames */ {});
+ NotifyMotionArgs scrollArgs(getContext()->getNextId(), when, getDeviceId(), mSource,
+ displayId, policyFlags, AMOTION_EVENT_ACTION_SCROLL, 0, 0,
+ metaState, /* buttonState */ 0, MotionClassification::NONE,
+ AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
+ &pointerCoords, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
+ AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, /* videoFrames */ {});
+ getListener()->notifyMotion(&scrollArgs);
}
mRotaryEncoderScrollAccumulator.finishSync();
diff --git a/services/inputflinger/reader/mapper/SensorInputMapper.cpp b/services/inputflinger/reader/mapper/SensorInputMapper.cpp
index 68c1e40357..7ac2dec895 100644
--- a/services/inputflinger/reader/mapper/SensorInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/SensorInputMapper.cpp
@@ -405,10 +405,13 @@ void SensorInputMapper::sync(nsecs_t when, bool force) {
// Convert to Android unit
convertFromLinuxToAndroid(values, sensorType);
// Notify dispatcher for sensor event
- getContext()->notifySensor(when, getDeviceId(), sensorType, sensor.sensorInfo.accuracy,
- sensor.accuracy !=
- sensor.sensorInfo.accuracy /* accuracyChanged */,
- timestamp /* hwTimestamp */, std::move(values));
+ NotifySensorArgs args(getContext()->getNextId(), when, getDeviceId(),
+ AINPUT_SOURCE_SENSOR, sensorType, sensor.sensorInfo.accuracy,
+ sensor.accuracy !=
+ sensor.sensorInfo.accuracy /* accuracyChanged */,
+ timestamp /* hwTimestamp */, values);
+
+ getListener()->notifySensor(&args);
sensor.lastSampleTimeNs = timestamp;
sensor.accuracy = sensor.sensorInfo.accuracy;
}
diff --git a/services/inputflinger/reader/mapper/SwitchInputMapper.cpp b/services/inputflinger/reader/mapper/SwitchInputMapper.cpp
index 07de244c31..4f736810bc 100644
--- a/services/inputflinger/reader/mapper/SwitchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/SwitchInputMapper.cpp
@@ -56,7 +56,10 @@ void SwitchInputMapper::processSwitch(int32_t switchCode, int32_t switchValue) {
void SwitchInputMapper::sync(nsecs_t when) {
if (mUpdatedSwitchMask) {
uint32_t updatedSwitchValues = mSwitchValues & mUpdatedSwitchMask;
- getContext()->notifySwitch(when, updatedSwitchValues, mUpdatedSwitchMask);
+ NotifySwitchArgs args(getContext()->getNextId(), when, 0 /*policyFlags*/,
+ updatedSwitchValues, mUpdatedSwitchMask);
+ getListener()->notifySwitch(&args);
+
mUpdatedSwitchMask = 0;
}
}
diff --git a/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h b/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h
index ff6341fbdb..a86443dee1 100644
--- a/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h
+++ b/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h
@@ -66,8 +66,9 @@ static void synthesizeButtonKey(InputReaderContext* context, int32_t action, nse
(currentButtonState & buttonState)) ||
(action == AKEY_EVENT_ACTION_UP && (lastButtonState & buttonState) &&
!(currentButtonState & buttonState))) {
- context->notifyKey(when, deviceId, source, displayId, policyFlags, action, 0 /*flags*/,
- keyCode, 0 /*scanCode*/, context->getGlobalMetaState(), when);
+ NotifyKeyArgs args(context->getNextId(), when, deviceId, source, displayId, policyFlags,
+ action, 0, keyCode, 0, context->getGlobalMetaState(), when);
+ context->getListener()->notifyKey(&args);
}
}
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
index 1a17bef399..d1df37b686 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
@@ -397,7 +397,8 @@ void TouchInputMapper::configure(nsecs_t when, const InputReaderConfiguration* c
if (changes && resetNeeded) {
// Send reset, unless this is the first time the device has been configured,
// in which case the reader will call reset itself after all mappers are ready.
- getContext()->notifyDeviceReset(when, getDeviceId());
+ NotifyDeviceResetArgs args(getContext()->getNextId(), when, getDeviceId());
+ getListener()->notifyDeviceReset(&args);
}
}
@@ -1845,9 +1846,10 @@ void TouchInputMapper::dispatchVirtualKey(nsecs_t when, uint32_t policyFlags,
int32_t metaState = getContext()->getGlobalMetaState();
policyFlags |= POLICY_FLAG_VIRTUAL;
- getContext()->notifyKey(when, getDeviceId(), AINPUT_SOURCE_KEYBOARD, mViewport.displayId,
- policyFlags, keyEventAction, keyEventFlags, keyCode, scanCode,
- metaState, downTime);
+ NotifyKeyArgs args(getContext()->getNextId(), when, getDeviceId(), AINPUT_SOURCE_KEYBOARD,
+ mViewport.displayId, policyFlags, keyEventAction, keyEventFlags, keyCode,
+ scanCode, metaState, downTime);
+ getListener()->notifyKey(&args);
}
void TouchInputMapper::abortTouches(nsecs_t when, uint32_t policyFlags) {
@@ -2526,11 +2528,12 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlag
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y);
const int32_t displayId = mPointerController->getDisplayId();
- getContext()->notifyMotion(when, getDeviceId(), mSource, displayId, policyFlags,
- AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState, buttonState,
- MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1,
- &pointerProperties, &pointerCoords, 0, 0, x, y,
- mPointerGesture.downTime, /* videoFrames */ {});
+ NotifyMotionArgs args(getContext()->getNextId(), when, getDeviceId(), mSource, displayId,
+ policyFlags, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState,
+ buttonState, MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE,
+ 1, &pointerProperties, &pointerCoords, 0, 0, x, y,
+ mPointerGesture.downTime, /* videoFrames */ {});
+ getListener()->notifyMotion(&args);
}
// Update state.
@@ -3445,28 +3448,28 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags,
mPointerSimple.down = false;
// Send up.
- getContext()->notifyMotion(when, getDeviceId(), mSource, displayId, policyFlags,
- AMOTION_EVENT_ACTION_UP, 0, 0, metaState,
- mLastRawState.buttonState, MotionClassification::NONE,
- AMOTION_EVENT_EDGE_FLAG_NONE, 1, &mPointerSimple.lastProperties,
- &mPointerSimple.lastCoords, mOrientedXPrecision,
- mOrientedYPrecision, xCursorPosition, yCursorPosition,
- mPointerSimple.downTime,
- /* videoFrames */ {});
+ NotifyMotionArgs args(getContext()->getNextId(), when, getDeviceId(), mSource, displayId,
+ policyFlags, AMOTION_EVENT_ACTION_UP, 0, 0, metaState,
+ mLastRawState.buttonState, MotionClassification::NONE,
+ AMOTION_EVENT_EDGE_FLAG_NONE, 1, &mPointerSimple.lastProperties,
+ &mPointerSimple.lastCoords, mOrientedXPrecision, mOrientedYPrecision,
+ xCursorPosition, yCursorPosition, mPointerSimple.downTime,
+ /* videoFrames */ {});
+ getListener()->notifyMotion(&args);
}
if (mPointerSimple.hovering && !hovering) {
mPointerSimple.hovering = false;
// Send hover exit.
- getContext()->notifyMotion(when, getDeviceId(), mSource, displayId, policyFlags,
- AMOTION_EVENT_ACTION_HOVER_EXIT, 0, 0, metaState,
- mLastRawState.buttonState, MotionClassification::NONE,
- AMOTION_EVENT_EDGE_FLAG_NONE, 1, &mPointerSimple.lastProperties,
- &mPointerSimple.lastCoords, mOrientedXPrecision,
- mOrientedYPrecision, xCursorPosition, yCursorPosition,
- mPointerSimple.downTime,
- /* videoFrames */ {});
+ NotifyMotionArgs args(getContext()->getNextId(), when, getDeviceId(), mSource, displayId,
+ policyFlags, AMOTION_EVENT_ACTION_HOVER_EXIT, 0, 0, metaState,
+ mLastRawState.buttonState, MotionClassification::NONE,
+ AMOTION_EVENT_EDGE_FLAG_NONE, 1, &mPointerSimple.lastProperties,
+ &mPointerSimple.lastCoords, mOrientedXPrecision, mOrientedYPrecision,
+ xCursorPosition, yCursorPosition, mPointerSimple.downTime,
+ /* videoFrames */ {});
+ getListener()->notifyMotion(&args);
}
if (down) {
@@ -3475,24 +3478,25 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags,
mPointerSimple.downTime = when;
// Send down.
- getContext()->notifyMotion(when, getDeviceId(), mSource, displayId, policyFlags,
- AMOTION_EVENT_ACTION_DOWN, 0, 0, metaState,
- mCurrentRawState.buttonState, MotionClassification::NONE,
- AMOTION_EVENT_EDGE_FLAG_NONE, 1,
- &mPointerSimple.currentProperties,
- &mPointerSimple.currentCoords, mOrientedXPrecision,
- mOrientedYPrecision, xCursorPosition, yCursorPosition,
- mPointerSimple.downTime, /* videoFrames */ {});
+ NotifyMotionArgs args(getContext()->getNextId(), when, getDeviceId(), mSource,
+ displayId, policyFlags, AMOTION_EVENT_ACTION_DOWN, 0, 0,
+ metaState, mCurrentRawState.buttonState,
+ MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1,
+ &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
+ mOrientedXPrecision, mOrientedYPrecision, xCursorPosition,
+ yCursorPosition, mPointerSimple.downTime, /* videoFrames */ {});
+ getListener()->notifyMotion(&args);
}
// Send move.
- getContext()->notifyMotion(when, getDeviceId(), mSource, displayId, policyFlags,
- AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState,
- mCurrentRawState.buttonState, MotionClassification::NONE,
- AMOTION_EVENT_EDGE_FLAG_NONE, 1,
- &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
- mOrientedXPrecision, mOrientedYPrecision, xCursorPosition,
- yCursorPosition, mPointerSimple.downTime, /* videoFrames */ {});
+ NotifyMotionArgs args(getContext()->getNextId(), when, getDeviceId(), mSource, displayId,
+ policyFlags, AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState,
+ mCurrentRawState.buttonState, MotionClassification::NONE,
+ AMOTION_EVENT_EDGE_FLAG_NONE, 1, &mPointerSimple.currentProperties,
+ &mPointerSimple.currentCoords, mOrientedXPrecision,
+ mOrientedYPrecision, xCursorPosition, yCursorPosition,
+ mPointerSimple.downTime, /* videoFrames */ {});
+ getListener()->notifyMotion(&args);
}
if (hovering) {
@@ -3500,24 +3504,25 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags,
mPointerSimple.hovering = true;
// Send hover enter.
- getContext()->notifyMotion(when, getDeviceId(), mSource, displayId, policyFlags,
- AMOTION_EVENT_ACTION_HOVER_ENTER, 0, 0, metaState,
- mCurrentRawState.buttonState, MotionClassification::NONE,
- AMOTION_EVENT_EDGE_FLAG_NONE, 1,
- &mPointerSimple.currentProperties,
- &mPointerSimple.currentCoords, mOrientedXPrecision,
- mOrientedYPrecision, xCursorPosition, yCursorPosition,
- mPointerSimple.downTime, /* videoFrames */ {});
+ NotifyMotionArgs args(getContext()->getNextId(), when, getDeviceId(), mSource,
+ displayId, policyFlags, AMOTION_EVENT_ACTION_HOVER_ENTER, 0, 0,
+ metaState, mCurrentRawState.buttonState,
+ MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1,
+ &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
+ mOrientedXPrecision, mOrientedYPrecision, xCursorPosition,
+ yCursorPosition, mPointerSimple.downTime, /* videoFrames */ {});
+ getListener()->notifyMotion(&args);
}
// Send hover move.
- getContext()->notifyMotion(when, getDeviceId(), mSource, displayId, policyFlags,
- AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState,
- mCurrentRawState.buttonState, MotionClassification::NONE,
- AMOTION_EVENT_EDGE_FLAG_NONE, 1,
- &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
- mOrientedXPrecision, mOrientedYPrecision, xCursorPosition,
- yCursorPosition, mPointerSimple.downTime, /* videoFrames */ {});
+ NotifyMotionArgs args(getContext()->getNextId(), when, getDeviceId(), mSource, displayId,
+ policyFlags, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState,
+ mCurrentRawState.buttonState, MotionClassification::NONE,
+ AMOTION_EVENT_EDGE_FLAG_NONE, 1, &mPointerSimple.currentProperties,
+ &mPointerSimple.currentCoords, mOrientedXPrecision,
+ mOrientedYPrecision, xCursorPosition, yCursorPosition,
+ mPointerSimple.downTime, /* videoFrames */ {});
+ getListener()->notifyMotion(&args);
}
if (mCurrentRawState.rawVScroll || mCurrentRawState.rawHScroll) {
@@ -3532,14 +3537,14 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags,
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_VSCROLL, vscroll);
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll);
- getContext()->notifyMotion(when, getDeviceId(), mSource, displayId, policyFlags,
- AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState,
- mCurrentRawState.buttonState, MotionClassification::NONE,
- AMOTION_EVENT_EDGE_FLAG_NONE, 1,
- &mPointerSimple.currentProperties, &pointerCoords,
- mOrientedXPrecision, mOrientedYPrecision, xCursorPosition,
- yCursorPosition, mPointerSimple.downTime,
- /* videoFrames */ {});
+ NotifyMotionArgs args(getContext()->getNextId(), when, getDeviceId(), mSource, displayId,
+ policyFlags, AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState,
+ mCurrentRawState.buttonState, MotionClassification::NONE,
+ AMOTION_EVENT_EDGE_FLAG_NONE, 1, &mPointerSimple.currentProperties,
+ &pointerCoords, mOrientedXPrecision, mOrientedYPrecision,
+ xCursorPosition, yCursorPosition, mPointerSimple.downTime,
+ /* videoFrames */ {});
+ getListener()->notifyMotion(&args);
}
// Save state.
@@ -3610,11 +3615,12 @@ void TouchInputMapper::dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32
std::vector<TouchVideoFrame> frames = getDeviceContext().getVideoFrames();
std::for_each(frames.begin(), frames.end(),
[this](TouchVideoFrame& frame) { frame.rotate(this->mSurfaceOrientation); });
- getContext()->notifyMotion(when, deviceId, source, displayId, policyFlags, action, actionButton,
- flags, metaState, buttonState, MotionClassification::NONE, edgeFlags,
- pointerCount, pointerProperties, pointerCoords, xPrecision,
- yPrecision, xCursorPosition, yCursorPosition, downTime,
- std::move(frames));
+ NotifyMotionArgs args(getContext()->getNextId(), when, deviceId, source, displayId, policyFlags,
+ action, actionButton, flags, metaState, buttonState,
+ MotionClassification::NONE, edgeFlags, pointerCount, pointerProperties,
+ pointerCoords, xPrecision, yPrecision, xCursorPosition, yCursorPosition,
+ downTime, std::move(frames));
+ getListener()->notifyMotion(&args);
}
bool TouchInputMapper::updateMovedPointers(const PointerProperties* inProperties,
diff --git a/services/inputflinger/reader/mapper/VibratorInputMapper.cpp b/services/inputflinger/reader/mapper/VibratorInputMapper.cpp
index 2e4ab45b35..3df6f36db5 100644
--- a/services/inputflinger/reader/mapper/VibratorInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/VibratorInputMapper.cpp
@@ -53,7 +53,8 @@ void VibratorInputMapper::vibrate(const VibrationSequence& sequence, ssize_t rep
mIndex = -1;
// Request InputReader to notify InputManagerService for vibration started.
- getContext()->notifyVibratorState(systemTime(), getDeviceId(), true);
+ NotifyVibratorStateArgs args(getContext()->getNextId(), systemTime(), getDeviceId(), true);
+ getListener()->notifyVibratorState(&args);
nextStep();
}
@@ -131,7 +132,8 @@ void VibratorInputMapper::stopVibrating() {
getDeviceContext().cancelVibrate();
// Request InputReader to notify InputManagerService for vibration complete.
- getContext()->notifyVibratorState(systemTime(), getDeviceId(), false);
+ NotifyVibratorStateArgs args(getContext()->getNextId(), systemTime(), getDeviceId(), false);
+ getListener()->notifyVibratorState(&args);
}
void VibratorInputMapper::dump(std::string& dump) {
diff --git a/services/inputflinger/reporter/Android.bp b/services/inputflinger/reporter/Android.bp
index fbc51dadc0..74307310c5 100644
--- a/services/inputflinger/reporter/Android.bp
+++ b/services/inputflinger/reporter/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library_headers {
name: "libinputreporter_headers",
export_include_dirs: ["."],
@@ -46,4 +55,3 @@ cc_library_shared {
"libinputreporter_headers",
],
}
-
diff --git a/services/inputflinger/tests/Android.bp b/services/inputflinger/tests/Android.bp
index 959dadc9ef..42b54c75b6 100644
--- a/services/inputflinger/tests/Android.bp
+++ b/services/inputflinger/tests/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_test {
name: "inputflinger_tests",
defaults: [
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 01945dbbf1..209639c880 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -31,6 +31,7 @@
using android::base::StringPrintf;
using android::os::InputEventInjectionResult;
using android::os::InputEventInjectionSync;
+using android::os::TouchOcclusionMode;
using namespace android::flag_operators;
namespace android::inputdispatcher {
@@ -727,8 +728,9 @@ public:
ASSERT_EQ(OK, status) << mName.c_str() << ": consumer sendFinishedSignal should return OK.";
}
- void consumeEvent(int32_t expectedEventType, int32_t expectedAction, int32_t expectedDisplayId,
- int32_t expectedFlags) {
+ void consumeEvent(int32_t expectedEventType, int32_t expectedAction,
+ std::optional<int32_t> expectedDisplayId,
+ std::optional<int32_t> expectedFlags) {
InputEvent* event = consume();
ASSERT_NE(nullptr, event) << mName.c_str()
@@ -737,19 +739,25 @@ public:
<< mName.c_str() << " expected " << inputEventTypeToString(expectedEventType)
<< " event, got " << inputEventTypeToString(event->getType()) << " event";
- EXPECT_EQ(expectedDisplayId, event->getDisplayId());
+ if (expectedDisplayId.has_value()) {
+ EXPECT_EQ(expectedDisplayId, event->getDisplayId());
+ }
switch (expectedEventType) {
case AINPUT_EVENT_TYPE_KEY: {
const KeyEvent& keyEvent = static_cast<const KeyEvent&>(*event);
EXPECT_EQ(expectedAction, keyEvent.getAction());
- EXPECT_EQ(expectedFlags, keyEvent.getFlags());
+ if (expectedFlags.has_value()) {
+ EXPECT_EQ(expectedFlags.value(), keyEvent.getFlags());
+ }
break;
}
case AINPUT_EVENT_TYPE_MOTION: {
const MotionEvent& motionEvent = static_cast<const MotionEvent&>(*event);
EXPECT_EQ(expectedAction, motionEvent.getAction());
- EXPECT_EQ(expectedFlags, motionEvent.getFlags());
+ if (expectedFlags.has_value()) {
+ EXPECT_EQ(expectedFlags.value(), motionEvent.getFlags());
+ }
break;
}
case AINPUT_EVENT_TYPE_FOCUS: {
@@ -854,6 +862,7 @@ public:
mInfo.name = name;
mInfo.type = InputWindowInfo::Type::APPLICATION;
mInfo.dispatchingTimeout = DISPATCHING_TIMEOUT;
+ mInfo.alpha = 1.0;
mInfo.frameLeft = 0;
mInfo.frameTop = 0;
mInfo.frameRight = WIDTH;
@@ -883,6 +892,12 @@ public:
void setPaused(bool paused) { mInfo.paused = paused; }
+ void setAlpha(float alpha) { mInfo.alpha = alpha; }
+
+ void setTouchOcclusionMode(android::os::TouchOcclusionMode mode) {
+ mInfo.touchOcclusionMode = mode;
+ }
+
void setFrame(const Rect& frame) {
mInfo.frameLeft = frame.left;
mInfo.frameTop = frame.top;
@@ -928,6 +943,11 @@ public:
void consumeMotionDown(int32_t expectedDisplayId = ADISPLAY_ID_DEFAULT,
int32_t expectedFlags = 0) {
+ consumeAnyMotionDown(expectedDisplayId, expectedFlags);
+ }
+
+ void consumeAnyMotionDown(std::optional<int32_t> expectedDisplayId = std::nullopt,
+ std::optional<int32_t> expectedFlags = std::nullopt) {
consumeEvent(AINPUT_EVENT_TYPE_MOTION, AMOTION_EVENT_ACTION_DOWN, expectedDisplayId,
expectedFlags);
}
@@ -971,8 +991,9 @@ public:
mInputReceiver->consumeCaptureEvent(hasCapture);
}
- void consumeEvent(int32_t expectedEventType, int32_t expectedAction, int32_t expectedDisplayId,
- int32_t expectedFlags) {
+ void consumeEvent(int32_t expectedEventType, int32_t expectedAction,
+ std::optional<int32_t> expectedDisplayId,
+ std::optional<int32_t> expectedFlags) {
ASSERT_NE(mInputReceiver, nullptr) << "Invalid consume event on window with no receiver";
mInputReceiver->consumeEvent(expectedEventType, expectedAction, expectedDisplayId,
expectedFlags);
@@ -4240,4 +4261,264 @@ TEST_F(InputDispatcherPointerCaptureTests, OutOfOrderRequests) {
mSecondWindow->consumeCaptureEvent(true);
}
+class InputDispatcherUntrustedTouchesTest : public InputDispatcherTest {
+protected:
+ constexpr static const float MAXIMUM_OBSCURING_OPACITY = 0.8;
+ static const int32_t TOUCHED_APP_UID = 10001;
+ static const int32_t APP_B_UID = 10002;
+ static const int32_t APP_C_UID = 10003;
+
+ sp<FakeWindowHandle> mTouchWindow;
+
+ virtual void SetUp() override {
+ InputDispatcherTest::SetUp();
+ mTouchWindow = getWindow(TOUCHED_APP_UID, "Touched");
+ mDispatcher->setBlockUntrustedTouchesMode(android::os::BlockUntrustedTouchesMode::BLOCK);
+ mDispatcher->setMaximumObscuringOpacityForTouch(MAXIMUM_OBSCURING_OPACITY);
+ }
+
+ virtual void TearDown() override {
+ InputDispatcherTest::TearDown();
+ mTouchWindow.clear();
+ }
+
+ sp<FakeWindowHandle> getOccludingWindow(int32_t uid, std::string name,
+ os::TouchOcclusionMode mode, float alpha = 1.0f) {
+ sp<FakeWindowHandle> window = getWindow(uid, name);
+ window->setFlags(InputWindowInfo::Flag::NOT_TOUCHABLE);
+ window->setTouchOcclusionMode(mode);
+ window->setAlpha(alpha);
+ return window;
+ }
+
+ sp<FakeWindowHandle> getWindow(int32_t uid, std::string name) {
+ std::shared_ptr<FakeApplicationHandle> app = std::make_shared<FakeApplicationHandle>();
+ sp<FakeWindowHandle> window =
+ new FakeWindowHandle(app, mDispatcher, name, ADISPLAY_ID_DEFAULT);
+ // Generate an arbitrary PID based on the UID
+ window->setOwnerInfo(1777 + (uid % 10000), uid);
+ return window;
+ }
+
+ void touch(const std::vector<PointF>& points = {PointF{100, 200}}) {
+ NotifyMotionArgs args =
+ generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
+ ADISPLAY_ID_DEFAULT, points);
+ mDispatcher->notifyMotion(&args);
+ }
+};
+
+TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithBlockUntrustedOcclusionMode_BlocksTouch) {
+ const sp<FakeWindowHandle>& w =
+ getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w, mTouchWindow}}});
+
+ touch();
+
+ mTouchWindow->assertNoEvents();
+}
+
+TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithAllowOcclusionMode_AllowsTouch) {
+ const sp<FakeWindowHandle>& w = getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::ALLOW);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w, mTouchWindow}}});
+
+ touch();
+
+ mTouchWindow->consumeAnyMotionDown();
+}
+
+TEST_F(InputDispatcherUntrustedTouchesTest, TouchOutsideOccludingWindow_AllowsTouch) {
+ const sp<FakeWindowHandle>& w =
+ getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED);
+ w->setFrame(Rect(0, 0, 50, 50));
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w, mTouchWindow}}});
+
+ touch({PointF{100, 100}});
+
+ mTouchWindow->consumeAnyMotionDown();
+}
+
+TEST_F(InputDispatcherUntrustedTouchesTest, WindowFromSameUid_AllowsTouch) {
+ const sp<FakeWindowHandle>& w =
+ getOccludingWindow(TOUCHED_APP_UID, "A", TouchOcclusionMode::BLOCK_UNTRUSTED);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w, mTouchWindow}}});
+
+ touch();
+
+ mTouchWindow->consumeAnyMotionDown();
+}
+
+TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithZeroOpacity_AllowsTouch) {
+ const sp<FakeWindowHandle>& w =
+ getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, 0.0f);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w, mTouchWindow}}});
+
+ touch();
+
+ mTouchWindow->consumeAnyMotionDown();
+}
+
+TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithOpacityBelowThreshold_AllowsTouch) {
+ const sp<FakeWindowHandle>& w =
+ getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY, 0.7f);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w, mTouchWindow}}});
+
+ touch();
+
+ mTouchWindow->consumeAnyMotionDown();
+}
+
+TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithOpacityAtThreshold_AllowsTouch) {
+ const sp<FakeWindowHandle>& w =
+ getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
+ MAXIMUM_OBSCURING_OPACITY);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w, mTouchWindow}}});
+
+ touch();
+
+ mTouchWindow->consumeAnyMotionDown();
+}
+
+TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithOpacityAboveThreshold_BlocksTouch) {
+ const sp<FakeWindowHandle>& w =
+ getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY, 0.9f);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w, mTouchWindow}}});
+
+ touch();
+
+ mTouchWindow->assertNoEvents();
+}
+
+TEST_F(InputDispatcherUntrustedTouchesTest, WindowsWithCombinedOpacityAboveThreshold_BlocksTouch) {
+ // Resulting opacity = 1 - (1 - 0.7)*(1 - 0.7) = .91
+ const sp<FakeWindowHandle>& w1 =
+ getOccludingWindow(APP_B_UID, "B1", TouchOcclusionMode::USE_OPACITY, 0.7f);
+ const sp<FakeWindowHandle>& w2 =
+ getOccludingWindow(APP_B_UID, "B2", TouchOcclusionMode::USE_OPACITY, 0.7f);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w1, w2, mTouchWindow}}});
+
+ touch();
+
+ mTouchWindow->assertNoEvents();
+}
+
+TEST_F(InputDispatcherUntrustedTouchesTest, WindowsWithCombinedOpacityBelowThreshold_AllowsTouch) {
+ // Resulting opacity = 1 - (1 - 0.5)*(1 - 0.5) = .75
+ const sp<FakeWindowHandle>& w1 =
+ getOccludingWindow(APP_B_UID, "B1", TouchOcclusionMode::USE_OPACITY, 0.5f);
+ const sp<FakeWindowHandle>& w2 =
+ getOccludingWindow(APP_B_UID, "B2", TouchOcclusionMode::USE_OPACITY, 0.5f);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w1, w2, mTouchWindow}}});
+
+ touch();
+
+ mTouchWindow->consumeAnyMotionDown();
+}
+
+TEST_F(InputDispatcherUntrustedTouchesTest,
+ WindowsFromDifferentAppsEachBelowThreshold_AllowsTouch) {
+ const sp<FakeWindowHandle>& wB =
+ getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY, 0.7f);
+ const sp<FakeWindowHandle>& wC =
+ getOccludingWindow(APP_C_UID, "C", TouchOcclusionMode::USE_OPACITY, 0.7f);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {wB, wC, mTouchWindow}}});
+
+ touch();
+
+ mTouchWindow->consumeAnyMotionDown();
+}
+
+TEST_F(InputDispatcherUntrustedTouchesTest, WindowsFromDifferentAppsOneAboveThreshold_BlocksTouch) {
+ const sp<FakeWindowHandle>& wB =
+ getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY, 0.7f);
+ const sp<FakeWindowHandle>& wC =
+ getOccludingWindow(APP_C_UID, "C", TouchOcclusionMode::USE_OPACITY, 0.9f);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {wB, wC, mTouchWindow}}});
+
+ touch();
+
+ mTouchWindow->assertNoEvents();
+}
+
+TEST_F(InputDispatcherUntrustedTouchesTest,
+ WindowWithOpacityAboveThresholdAndSelfWindow_BlocksTouch) {
+ const sp<FakeWindowHandle>& wA =
+ getOccludingWindow(TOUCHED_APP_UID, "T", TouchOcclusionMode::USE_OPACITY, 0.7f);
+ const sp<FakeWindowHandle>& wB =
+ getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY, 0.9f);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {wA, wB, mTouchWindow}}});
+
+ touch();
+
+ mTouchWindow->assertNoEvents();
+}
+
+TEST_F(InputDispatcherUntrustedTouchesTest,
+ WindowWithOpacityBelowThresholdAndSelfWindow_AllowsTouch) {
+ const sp<FakeWindowHandle>& wA =
+ getOccludingWindow(TOUCHED_APP_UID, "T", TouchOcclusionMode::USE_OPACITY, 0.9f);
+ const sp<FakeWindowHandle>& wB =
+ getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY, 0.7f);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {wA, wB, mTouchWindow}}});
+
+ touch();
+
+ mTouchWindow->consumeAnyMotionDown();
+}
+
+TEST_F(InputDispatcherUntrustedTouchesTest, SelfWindowWithOpacityAboveThreshold_AllowsTouch) {
+ const sp<FakeWindowHandle>& w =
+ getOccludingWindow(TOUCHED_APP_UID, "T", TouchOcclusionMode::USE_OPACITY, 0.9f);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w, mTouchWindow}}});
+
+ touch();
+
+ mTouchWindow->consumeAnyMotionDown();
+}
+
+TEST_F(InputDispatcherUntrustedTouchesTest, SelfWindowWithBlockUntrustedMode_AllowsTouch) {
+ const sp<FakeWindowHandle>& w =
+ getOccludingWindow(TOUCHED_APP_UID, "T", TouchOcclusionMode::BLOCK_UNTRUSTED);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w, mTouchWindow}}});
+
+ touch();
+
+ mTouchWindow->consumeAnyMotionDown();
+}
+
+TEST_F(InputDispatcherUntrustedTouchesTest,
+ OpacityThresholdIs0AndWindowAboveThreshold_BlocksTouch) {
+ mDispatcher->setMaximumObscuringOpacityForTouch(0.0f);
+ const sp<FakeWindowHandle>& w =
+ getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY, 0.1f);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w, mTouchWindow}}});
+
+ touch();
+
+ mTouchWindow->assertNoEvents();
+}
+
+TEST_F(InputDispatcherUntrustedTouchesTest, OpacityThresholdIs0AndWindowAtThreshold_AllowsTouch) {
+ mDispatcher->setMaximumObscuringOpacityForTouch(0.0f);
+ const sp<FakeWindowHandle>& w =
+ getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY, 0.0f);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w, mTouchWindow}}});
+
+ touch();
+
+ mTouchWindow->consumeAnyMotionDown();
+}
+
+TEST_F(InputDispatcherUntrustedTouchesTest,
+ OpacityThresholdIs1AndWindowBelowThreshold_AllowsTouch) {
+ mDispatcher->setMaximumObscuringOpacityForTouch(1.0f);
+ const sp<FakeWindowHandle>& w =
+ getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY, 0.9f);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w, mTouchWindow}}});
+
+ touch();
+
+ mTouchWindow->consumeAnyMotionDown();
+}
+
} // namespace android::inputdispatcher
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 409c62a0e2..2836516a41 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -22,6 +22,7 @@
#include <InputReaderBase.h>
#include <InputReaderFactory.h>
#include <KeyboardInputMapper.h>
+#include <LightInputMapper.h>
#include <MultiTouchInputMapper.h>
#include <SensorInputMapper.h>
#include <SingleTouchInputMapper.h>
@@ -36,6 +37,7 @@
#include <math.h>
#include <memory>
+#include <regex>
#include "input/DisplayViewport.h"
#include "input/Input.h"
@@ -70,6 +72,9 @@ static constexpr int32_t SECOND_TRACKING_ID = 1;
static constexpr int32_t THIRD_TRACKING_ID = 2;
static constexpr int32_t BATTERY_STATUS = 4;
static constexpr int32_t BATTERY_CAPACITY = 66;
+static constexpr int32_t LIGHT_BRIGHTNESS = 0x55000000;
+static constexpr int32_t LIGHT_COLOR = 0x7F448866;
+static constexpr int32_t LIGHT_PLAYER_ID = 2;
// Error tolerance for floating point assertions.
static const float EPSILON = 0.001f;
@@ -83,6 +88,10 @@ static inline float avg(float x, float y) {
return (x + y) / 2;
}
+// Mapping for light color name and the light color
+const std::unordered_map<std::string, LightColor> LIGHT_COLORS = {{"red", LightColor::RED},
+ {"green", LightColor::GREEN},
+ {"blue", LightColor::BLUE}};
// --- FakePointerController ---
@@ -412,6 +421,12 @@ class FakeEventHub : public EventHubInterface {
std::vector<RawEvent> mEvents GUARDED_BY(mLock);
std::unordered_map<int32_t /*deviceId*/, std::vector<TouchVideoFrame>> mVideoFrames;
std::vector<int32_t> mVibrators = {0, 1};
+ std::unordered_map<int32_t, RawLightInfo> mRawLightInfos;
+ // Simulates a device light brightness, from light id to light brightness.
+ std::unordered_map<int32_t /* lightId */, int32_t /* brightness*/> mLightBrightness;
+ // Simulates a device light intensities, from light id to light intensities map.
+ std::unordered_map<int32_t /* lightId */, std::unordered_map<LightColor, int32_t>>
+ mLightIntensities;
public:
virtual ~FakeEventHub() {
@@ -562,6 +577,19 @@ public:
device->mscBitmask.loadFromBuffer(buffer);
}
+ void addRawLightInfo(int32_t rawId, RawLightInfo&& info) {
+ mRawLightInfos.emplace(rawId, std::move(info));
+ }
+
+ void fakeLightBrightness(int32_t rawId, int32_t brightness) {
+ mLightBrightness.emplace(rawId, brightness);
+ }
+
+ void fakeLightIntensities(int32_t rawId,
+ const std::unordered_map<LightColor, int32_t> intensities) {
+ mLightIntensities.emplace(rawId, std::move(intensities));
+ }
+
bool getLedState(int32_t deviceId, int32_t led) {
Device* device = getDevice(deviceId);
return device->leds.valueFor(led);
@@ -869,6 +897,48 @@ private:
std::optional<int32_t> getBatteryStatus(int32_t) const override { return BATTERY_STATUS; }
+ const std::vector<int32_t> getRawLightIds(int32_t deviceId) override {
+ std::vector<int32_t> ids;
+ for (const auto& [rawId, info] : mRawLightInfos) {
+ ids.push_back(rawId);
+ }
+ return ids;
+ }
+
+ std::optional<RawLightInfo> getRawLightInfo(int32_t deviceId, int32_t lightId) override {
+ auto it = mRawLightInfos.find(lightId);
+ if (it == mRawLightInfos.end()) {
+ return std::nullopt;
+ }
+ return it->second;
+ }
+
+ void setLightBrightness(int32_t deviceId, int32_t lightId, int32_t brightness) override {
+ mLightBrightness.emplace(lightId, brightness);
+ }
+
+ void setLightIntensities(int32_t deviceId, int32_t lightId,
+ std::unordered_map<LightColor, int32_t> intensities) override {
+ mLightIntensities.emplace(lightId, intensities);
+ };
+
+ std::optional<int32_t> getLightBrightness(int32_t deviceId, int32_t lightId) override {
+ auto lightIt = mLightBrightness.find(lightId);
+ if (lightIt == mLightBrightness.end()) {
+ return std::nullopt;
+ }
+ return lightIt->second;
+ }
+
+ std::optional<std::unordered_map<LightColor, int32_t>> getLightIntensities(
+ int32_t deviceId, int32_t lightId) override {
+ auto lightIt = mLightIntensities.find(lightId);
+ if (lightIt == mLightIntensities.end()) {
+ return std::nullopt;
+ }
+ return lightIt->second;
+ };
+
virtual bool isExternal(int32_t) const {
return false;
}
@@ -1976,6 +2046,49 @@ TEST_F(InputReaderTest, BatteryGetStatus) {
ASSERT_EQ(mReader->getBatteryStatus(deviceId), BATTERY_STATUS);
}
+class FakeLightInputMapper : public FakeInputMapper {
+public:
+ FakeLightInputMapper(InputDeviceContext& deviceContext, uint32_t sources)
+ : FakeInputMapper(deviceContext, sources) {}
+
+ bool setLightColor(int32_t lightId, int32_t color) override {
+ getDeviceContext().setLightBrightness(lightId, color >> 24);
+ return true;
+ }
+
+ std::optional<int32_t> getLightColor(int32_t lightId) override {
+ std::optional<int32_t> result = getDeviceContext().getLightBrightness(lightId);
+ if (!result.has_value()) {
+ return std::nullopt;
+ }
+ return result.value() << 24;
+ }
+};
+
+TEST_F(InputReaderTest, LightGetColor) {
+ constexpr int32_t deviceId = END_RESERVED_ID + 1000;
+ Flags<InputDeviceClass> deviceClass = InputDeviceClass::KEYBOARD | InputDeviceClass::LIGHT;
+ constexpr int32_t eventHubId = 1;
+ const char* DEVICE_LOCATION = "BLUETOOTH";
+ std::shared_ptr<InputDevice> device = mReader->newDevice(deviceId, "fake", DEVICE_LOCATION);
+ FakeLightInputMapper& mapper =
+ device->addMapper<FakeLightInputMapper>(eventHubId, AINPUT_SOURCE_KEYBOARD);
+ mReader->pushNextDevice(device);
+ RawLightInfo info = {.id = 1,
+ .name = "Mono",
+ .maxBrightness = 255,
+ .flags = InputLightClass::BRIGHTNESS,
+ .path = ""};
+ mFakeEventHub->addRawLightInfo(1 /* rawId */, std::move(info));
+ mFakeEventHub->fakeLightBrightness(1 /* rawId */, 0x55);
+
+ ASSERT_NO_FATAL_FAILURE(addDevice(eventHubId, "fake", deviceClass, nullptr));
+ ASSERT_NO_FATAL_FAILURE(mapper.assertConfigureWasCalled());
+
+ ASSERT_TRUE(mReader->setLightColor(deviceId, 1 /* lightId */, LIGHT_BRIGHTNESS));
+ ASSERT_EQ(mReader->getLightColor(deviceId, 1 /* lightId */), LIGHT_BRIGHTNESS);
+}
+
// --- InputReaderIntegrationTest ---
// These tests create and interact with the InputReader only through its interface.
@@ -2883,14 +2996,136 @@ TEST_F(BatteryInputMapperTest, GetBatteryCapacity) {
BatteryInputMapper& mapper = addMapperAndConfigure<BatteryInputMapper>();
ASSERT_TRUE(mapper.getBatteryCapacity());
- ASSERT_EQ(*mapper.getBatteryCapacity(), BATTERY_CAPACITY);
+ ASSERT_EQ(mapper.getBatteryCapacity().value_or(-1), BATTERY_CAPACITY);
}
TEST_F(BatteryInputMapperTest, GetBatteryStatus) {
BatteryInputMapper& mapper = addMapperAndConfigure<BatteryInputMapper>();
ASSERT_TRUE(mapper.getBatteryStatus());
- ASSERT_EQ(*mapper.getBatteryStatus(), BATTERY_STATUS);
+ ASSERT_EQ(mapper.getBatteryStatus().value_or(-1), BATTERY_STATUS);
+}
+
+// --- LightInputMapperTest ---
+class LightInputMapperTest : public InputMapperTest {
+protected:
+ void SetUp() override { InputMapperTest::SetUp(DEVICE_CLASSES | InputDeviceClass::LIGHT); }
+};
+
+TEST_F(LightInputMapperTest, GetSources) {
+ LightInputMapper& mapper = addMapperAndConfigure<LightInputMapper>();
+
+ ASSERT_EQ(AINPUT_SOURCE_UNKNOWN, mapper.getSources());
+}
+
+TEST_F(LightInputMapperTest, SingleLight) {
+ RawLightInfo infoSingle = {.id = 1,
+ .name = "Mono",
+ .maxBrightness = 255,
+ .flags = InputLightClass::BRIGHTNESS,
+ .path = ""};
+ mFakeEventHub->addRawLightInfo(infoSingle.id, std::move(infoSingle));
+
+ LightInputMapper& mapper = addMapperAndConfigure<LightInputMapper>();
+ InputDeviceInfo info;
+ mapper.populateDeviceInfo(&info);
+ const auto& ids = info.getLightIds();
+ ASSERT_EQ(1UL, ids.size());
+ ASSERT_EQ(InputDeviceLightType::SINGLE, info.getLightInfo(ids[0])->type);
+
+ ASSERT_TRUE(mapper.setLightColor(ids[0], LIGHT_BRIGHTNESS));
+ ASSERT_EQ(mapper.getLightColor(ids[0]).value_or(-1), LIGHT_BRIGHTNESS);
+}
+
+TEST_F(LightInputMapperTest, RGBLight) {
+ RawLightInfo infoRed = {.id = 1,
+ .name = "red",
+ .maxBrightness = 255,
+ .flags = InputLightClass::BRIGHTNESS | InputLightClass::RED,
+ .path = ""};
+ RawLightInfo infoGreen = {.id = 2,
+ .name = "green",
+ .maxBrightness = 255,
+ .flags = InputLightClass::BRIGHTNESS | InputLightClass::GREEN,
+ .path = ""};
+ RawLightInfo infoBlue = {.id = 3,
+ .name = "blue",
+ .maxBrightness = 255,
+ .flags = InputLightClass::BRIGHTNESS | InputLightClass::BLUE,
+ .path = ""};
+ mFakeEventHub->addRawLightInfo(infoRed.id, std::move(infoRed));
+ mFakeEventHub->addRawLightInfo(infoGreen.id, std::move(infoGreen));
+ mFakeEventHub->addRawLightInfo(infoBlue.id, std::move(infoBlue));
+
+ LightInputMapper& mapper = addMapperAndConfigure<LightInputMapper>();
+ InputDeviceInfo info;
+ mapper.populateDeviceInfo(&info);
+ const auto& ids = info.getLightIds();
+ ASSERT_EQ(1UL, ids.size());
+ ASSERT_EQ(InputDeviceLightType::RGB, info.getLightInfo(ids[0])->type);
+
+ ASSERT_TRUE(mapper.setLightColor(ids[0], LIGHT_COLOR));
+ ASSERT_EQ(mapper.getLightColor(ids[0]).value_or(-1), LIGHT_COLOR);
+}
+
+TEST_F(LightInputMapperTest, MultiColorRGBLight) {
+ RawLightInfo infoColor = {.id = 1,
+ .name = "red",
+ .maxBrightness = 255,
+ .flags = InputLightClass::BRIGHTNESS |
+ InputLightClass::MULTI_INTENSITY |
+ InputLightClass::MULTI_INDEX,
+ .path = ""};
+
+ mFakeEventHub->addRawLightInfo(infoColor.id, std::move(infoColor));
+
+ LightInputMapper& mapper = addMapperAndConfigure<LightInputMapper>();
+ InputDeviceInfo info;
+ mapper.populateDeviceInfo(&info);
+ const auto& ids = info.getLightIds();
+ ASSERT_EQ(1UL, ids.size());
+ ASSERT_EQ(InputDeviceLightType::MULTI_COLOR, info.getLightInfo(ids[0])->type);
+
+ ASSERT_TRUE(mapper.setLightColor(ids[0], LIGHT_COLOR));
+ ASSERT_EQ(mapper.getLightColor(ids[0]).value_or(-1), LIGHT_COLOR);
+}
+
+TEST_F(LightInputMapperTest, PlayerIdLight) {
+ RawLightInfo info1 = {.id = 1,
+ .name = "player1",
+ .maxBrightness = 255,
+ .flags = InputLightClass::BRIGHTNESS,
+ .path = ""};
+ RawLightInfo info2 = {.id = 2,
+ .name = "player2",
+ .maxBrightness = 255,
+ .flags = InputLightClass::BRIGHTNESS,
+ .path = ""};
+ RawLightInfo info3 = {.id = 3,
+ .name = "player3",
+ .maxBrightness = 255,
+ .flags = InputLightClass::BRIGHTNESS,
+ .path = ""};
+ RawLightInfo info4 = {.id = 4,
+ .name = "player4",
+ .maxBrightness = 255,
+ .flags = InputLightClass::BRIGHTNESS,
+ .path = ""};
+ mFakeEventHub->addRawLightInfo(info1.id, std::move(info1));
+ mFakeEventHub->addRawLightInfo(info2.id, std::move(info2));
+ mFakeEventHub->addRawLightInfo(info3.id, std::move(info3));
+ mFakeEventHub->addRawLightInfo(info4.id, std::move(info4));
+
+ LightInputMapper& mapper = addMapperAndConfigure<LightInputMapper>();
+ InputDeviceInfo info;
+ mapper.populateDeviceInfo(&info);
+ const auto& ids = info.getLightIds();
+ ASSERT_EQ(1UL, ids.size());
+ ASSERT_EQ(InputDeviceLightType::PLAYER_ID, info.getLightInfo(ids[0])->type);
+
+ ASSERT_FALSE(mapper.setLightColor(ids[0], LIGHT_COLOR));
+ ASSERT_TRUE(mapper.setLightPlayerId(ids[0], LIGHT_PLAYER_ID));
+ ASSERT_EQ(mapper.getLightPlayerId(ids[0]).value_or(-1), LIGHT_PLAYER_ID);
}
// --- KeyboardInputMapperTest ---
diff --git a/services/powermanager/Android.bp b/services/powermanager/Android.bp
index 68f4f283ee..1d3e5b53fa 100644
--- a/services/powermanager/Android.bp
+++ b/services/powermanager/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library_shared {
name: "libpowermanager",
diff --git a/services/schedulerservice/Android.bp b/services/schedulerservice/Android.bp
index 73802dbc9f..4ef72d0c83 100644
--- a/services/schedulerservice/Android.bp
+++ b/services/schedulerservice/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library_shared {
name: "libschedulerservicehidl",
srcs: [
diff --git a/services/sensorservice/Android.bp b/services/sensorservice/Android.bp
index 532a2e5a13..ca9ff7c8c3 100644
--- a/services/sensorservice/Android.bp
+++ b/services/sensorservice/Android.bp
@@ -1,3 +1,12 @@
+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"],
+}
+
subdirs = [
"hidl"
]
diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp
index 2810bffdd3..23893ea1fd 100644
--- a/services/sensorservice/SensorDevice.cpp
+++ b/services/sensorservice/SensorDevice.cpp
@@ -914,6 +914,21 @@ bool SensorDevice::isSensorActive(int handle) const {
return mActivationCount.valueAt(activationIndex).numActiveClients() > 0;
}
+void SensorDevice::onMicSensorAccessChanged(void* ident, int handle, nsecs_t samplingPeriodNs) {
+ Mutex::Autolock _l(mLock);
+ ssize_t activationIndex = mActivationCount.indexOfKey(handle);
+ if (activationIndex < 0) {
+ ALOGW("Handle %d cannot be found in activation record", handle);
+ return;
+ }
+ Info& info(mActivationCount.editValueAt(activationIndex));
+ if (info.hasBatchParamsForIdent(ident)) {
+ ssize_t index = info.batchParams.indexOfKey(ident);
+ BatchParams& params = info.batchParams.editValueAt(index);
+ params.mTSample = samplingPeriodNs;
+ }
+}
+
void SensorDevice::enableAllSensors() {
if (mSensors == nullptr) return;
Mutex::Autolock _l(mLock);
diff --git a/services/sensorservice/SensorDevice.h b/services/sensorservice/SensorDevice.h
index 5e7d3da398..75da7bb0a1 100644
--- a/services/sensorservice/SensorDevice.h
+++ b/services/sensorservice/SensorDevice.h
@@ -125,6 +125,10 @@ public:
bool isSensorActive(int handle) const;
+ // To update the BatchParams of a SensorEventConnection when the mic toggle changes its state
+ // while the Sensors Off toggle is on.
+ void onMicSensorAccessChanged(void* ident, int handle, nsecs_t samplingPeriodNs);
+
// Dumpable
virtual std::string dump() const override;
virtual void dump(util::ProtoOutputStream* proto) const override;
diff --git a/services/sensorservice/SensorDirectConnection.cpp b/services/sensorservice/SensorDirectConnection.cpp
index e4c33dafcb..af86d09784 100644
--- a/services/sensorservice/SensorDirectConnection.cpp
+++ b/services/sensorservice/SensorDirectConnection.cpp
@@ -32,6 +32,8 @@ SensorService::SensorDirectConnection::SensorDirectConnection(const sp<SensorSer
: mService(service), mUid(uid), mMem(*mem),
mHalChannelHandle(halChannelHandle),
mOpPackageName(opPackageName), mDestroyed(false) {
+ mIsRateCappedBasedOnPermission = mService->isRateCappedBasedOnPermission(mOpPackageName);
+ mUserId = multiuser_get_user_id(mUid);
ALOGD_IF(DEBUG_CONNECTIONS, "Created SensorDirectConnection");
}
@@ -101,6 +103,14 @@ void SensorService::SensorDirectConnection::onSensorAccessChanged(bool hasAccess
}
}
+void SensorService::SensorDirectConnection::onMicSensorAccessChanged(bool isMicToggleOn) {
+ if (isMicToggleOn) {
+ capRates();
+ } else {
+ uncapRates();
+ }
+}
+
bool SensorService::SensorDirectConnection::hasSensorAccess() const {
return mService->hasSensorAccess(mUid, mOpPackageName);
}
@@ -134,6 +144,7 @@ int32_t SensorService::SensorDirectConnection::configureChannel(int handle, int
if (handle == -1 && rateLevel == SENSOR_DIRECT_RATE_STOP) {
stopAll();
+ mMicRateBackup.clear();
return NO_ERROR;
}
@@ -157,6 +168,14 @@ int32_t SensorService::SensorDirectConnection::configureChannel(int handle, int
return INVALID_OPERATION;
}
+ int requestedRateLevel = rateLevel;
+ if (mService->isSensorInCappedSet(s.getType()) && rateLevel != SENSOR_DIRECT_RATE_STOP) {
+ status_t err = mService->adjustRateLevelBasedOnMicAndPermission(&rateLevel, mOpPackageName);
+ if (err != OK) {
+ return err;
+ }
+ }
+
struct sensors_direct_cfg_t config = {
.rate_level = rateLevel
};
@@ -168,18 +187,100 @@ int32_t SensorService::SensorDirectConnection::configureChannel(int handle, int
if (rateLevel == SENSOR_DIRECT_RATE_STOP) {
if (ret == NO_ERROR) {
mActivated.erase(handle);
+ mMicRateBackup.erase(handle);
} else if (ret > 0) {
ret = UNKNOWN_ERROR;
}
} else {
if (ret > 0) {
mActivated[handle] = rateLevel;
+ if (mService->isSensorInCappedSet(s.getType())) {
+ // Back up the rates that the app is allowed to have if the mic toggle is off
+ // This is used in the uncapRates() function.
+ if (!mIsRateCappedBasedOnPermission ||
+ requestedRateLevel <= SENSOR_SERVICE_CAPPED_SAMPLING_RATE_LEVEL) {
+ mMicRateBackup[handle] = requestedRateLevel;
+ } else {
+ mMicRateBackup[handle] = SENSOR_SERVICE_CAPPED_SAMPLING_RATE_LEVEL;
+ }
+ }
}
}
return ret;
}
+void SensorService::SensorDirectConnection::capRates() {
+ Mutex::Autolock _l(mConnectionLock);
+ const struct sensors_direct_cfg_t capConfig = {
+ .rate_level = SENSOR_SERVICE_CAPPED_SAMPLING_RATE_LEVEL
+ };
+
+ const struct sensors_direct_cfg_t stopConfig = {
+ .rate_level = SENSOR_DIRECT_RATE_STOP
+ };
+
+ // If our requests are in the backup, then we shouldn't activate sensors from here
+ bool temporarilyStopped = mActivated.empty() && !mActivatedBackup.empty();
+ std::unordered_map<int, int>& existingConnections =
+ (!temporarilyStopped) ? mActivated : mActivatedBackup;
+
+ SensorDevice& dev(SensorDevice::getInstance());
+ for (auto &i : existingConnections) {
+ int handle = i.first;
+ int rateLevel = i.second;
+ sp<SensorInterface> si = mService->getSensorInterfaceFromHandle(handle);
+ if (si != nullptr) {
+ const Sensor& s = si->getSensor();
+ if (mService->isSensorInCappedSet(s.getType()) &&
+ rateLevel > SENSOR_SERVICE_CAPPED_SAMPLING_RATE_LEVEL) {
+ mMicRateBackup[handle] = rateLevel;
+ // Modify the rate kept by the existing map
+ existingConnections[handle] = SENSOR_SERVICE_CAPPED_SAMPLING_RATE_LEVEL;
+ // Only reconfigure the channel if it's ongoing
+ if (!temporarilyStopped) {
+ // Stopping before reconfiguring is the well-tested path in CTS
+ dev.configureDirectChannel(handle, getHalChannelHandle(), &stopConfig);
+ dev.configureDirectChannel(handle, getHalChannelHandle(), &capConfig);
+ }
+ }
+ }
+ }
+}
+
+void SensorService::SensorDirectConnection::uncapRates() {
+ Mutex::Autolock _l(mConnectionLock);
+
+ // If our requests are in the backup, then we shouldn't activate sensors from here
+ bool temporarilyStopped = mActivated.empty() && !mActivatedBackup.empty();
+ std::unordered_map<int, int>& existingConnections =
+ (!temporarilyStopped) ? mActivated : mActivatedBackup;
+
+ const struct sensors_direct_cfg_t stopConfig = {
+ .rate_level = SENSOR_DIRECT_RATE_STOP
+ };
+ SensorDevice& dev(SensorDevice::getInstance());
+ for (auto &i : mMicRateBackup) {
+ int handle = i.first;
+ int rateLevel = i.second;
+
+ const struct sensors_direct_cfg_t config = {
+ .rate_level = rateLevel
+ };
+
+ // Modify the rate kept by the existing map
+ existingConnections[handle] = rateLevel;
+
+ // Only reconfigure the channel if it's ongoing
+ if (!temporarilyStopped) {
+ // Stopping before reconfiguring is the well-tested path in CTS
+ dev.configureDirectChannel(handle, getHalChannelHandle(), &stopConfig);
+ dev.configureDirectChannel(handle, getHalChannelHandle(), &config);
+ }
+ }
+ mMicRateBackup.clear();
+}
+
void SensorService::SensorDirectConnection::stopAll(bool backupRecord) {
Mutex::Autolock _l(mConnectionLock);
stopAllLocked(backupRecord);
diff --git a/services/sensorservice/SensorDirectConnection.h b/services/sensorservice/SensorDirectConnection.h
index 4181b65b7d..a3f348b668 100644
--- a/services/sensorservice/SensorDirectConnection.h
+++ b/services/sensorservice/SensorDirectConnection.h
@@ -50,6 +50,8 @@ public:
// regained due to changes in the sensor restricted/privacy mode or the
// app changed to idle/active status.
void onSensorAccessChanged(bool hasAccess);
+ void onMicSensorAccessChanged(bool isMicToggleOn);
+ userid_t getUserId() const { return mUserId; }
protected:
virtual ~SensorDirectConnection();
@@ -82,6 +84,11 @@ private:
// If no requests are backed up by stopAll(), this method is no-op.
void recoverAll();
+ // Limits all active sensor direct report requests when the mic toggle is flipped to on.
+ void capRates();
+ // Recover sensor requests previously capped by capRates().
+ void uncapRates();
+
const sp<SensorService> mService;
const uid_t mUid;
const sensors_direct_mem_t mMem;
@@ -91,9 +98,12 @@ private:
mutable Mutex mConnectionLock;
std::unordered_map<int, int> mActivated;
std::unordered_map<int, int> mActivatedBackup;
+ std::unordered_map<int, int> mMicRateBackup;
+ std::atomic_bool mIsRateCappedBasedOnPermission;
mutable Mutex mDestroyLock;
bool mDestroyed;
+ userid_t mUserId;
};
} // namepsace android
diff --git a/services/sensorservice/SensorEventConnection.cpp b/services/sensorservice/SensorEventConnection.cpp
index 6810c1b781..5225dd7a64 100644
--- a/services/sensorservice/SensorEventConnection.cpp
+++ b/services/sensorservice/SensorEventConnection.cpp
@@ -38,12 +38,14 @@ constexpr int kTargetSdkUnknown = 0;
SensorService::SensorEventConnection::SensorEventConnection(
const sp<SensorService>& service, uid_t uid, String8 packageName, bool isDataInjectionMode,
- const String16& opPackageName)
+ const String16& opPackageName, const String16& attributionTag)
: mService(service), mUid(uid), mWakeLockRefCount(0), mHasLooperCallbacks(false),
mDead(false), mDataInjectionMode(isDataInjectionMode), mEventCache(nullptr),
mCacheSize(0), mMaxCacheSize(0), mTimeOfLastEventDrop(0), mEventsDropped(0),
- mPackageName(packageName), mOpPackageName(opPackageName), mTargetSdk(kTargetSdkUnknown),
- mDestroyed(false) {
+ mPackageName(packageName), mOpPackageName(opPackageName), mAttributionTag(attributionTag),
+ mTargetSdk(kTargetSdkUnknown), mDestroyed(false) {
+ mIsRateCappedBasedOnPermission = mService->isRateCappedBasedOnPermission(mOpPackageName);
+ mUserId = multiuser_get_user_id(mUid);
mChannel = new BitTube(mService->mSocketBufferSize);
#if DEBUG_CONNECTIONS
mEventsReceived = mEventsSentFromCache = mEventsSent = 0;
@@ -285,6 +287,29 @@ bool SensorService::SensorEventConnection::incrementPendingFlushCountIfHasAccess
}
}
+// TODO(b/179649922): A better algorithm to guarantee that capped connections will get a sampling
+// rate close to 200 Hz. With the current algorithm, apps might be punished unfairly: E.g.,two apps
+// make requests to the sensor service at the same time, one is not capped and uses 250 Hz, and one
+//is capped, the capped connection will only get 125 Hz.
+void SensorService::SensorEventConnection::addSensorEventsToBuffer(bool shouldResample,
+ const sensors_event_t& sensorEvent, sensors_event_t* buffer, int* index) {
+ if (!shouldResample || !mService->isSensorInCappedSet(sensorEvent.type)) {
+ buffer[(*index)++] = sensorEvent;
+ } else {
+ int64_t lastTimestamp = -1;
+ auto entry = mSensorLastTimestamp.find(sensorEvent.sensor);
+ if (entry != mSensorLastTimestamp.end()) {
+ lastTimestamp = entry->second;
+ }
+ // Allow 10% headroom here because the clocks are not perfect.
+ if (lastTimestamp == -1 || sensorEvent.timestamp - lastTimestamp
+ >= 0.9 * SENSOR_SERVICE_CAPPED_SAMPLING_PERIOD_NS) {
+ mSensorLastTimestamp[sensorEvent.sensor] = sensorEvent.timestamp;
+ buffer[(*index)++] = sensorEvent;
+ }
+ }
+}
+
status_t SensorService::SensorEventConnection::sendEvents(
sensors_event_t const* buffer, size_t numEvents,
sensors_event_t* scratch,
@@ -293,6 +318,8 @@ status_t SensorService::SensorEventConnection::sendEvents(
std::unique_ptr<sensors_event_t[]> sanitizedBuffer;
+ bool shouldResample = mService->isMicSensorPrivacyEnabledForUid(mUid) ||
+ mIsRateCappedBasedOnPermission;
int count = 0;
Mutex::Autolock _l(mConnectionLock);
if (scratch) {
@@ -346,7 +373,7 @@ status_t SensorService::SensorEventConnection::sendEvents(
// Regular sensor event, just copy it to the scratch buffer after checking
// the AppOp.
if (hasSensorAccess() && noteOpIfRequired(buffer[i])) {
- scratch[count++] = buffer[i];
+ addSensorEventsToBuffer(shouldResample, buffer[i], scratch, &count);
}
}
i++;
@@ -356,12 +383,13 @@ status_t SensorService::SensorEventConnection::sendEvents(
buffer[i].meta_data.sensor == sensor_handle)));
}
} else {
+ sanitizedBuffer.reset(new sensors_event_t[numEvents]);
+ scratch = sanitizedBuffer.get();
if (hasSensorAccess()) {
- scratch = const_cast<sensors_event_t *>(buffer);
- count = numEvents;
+ for (size_t i = 0; i < numEvents; i++) {
+ addSensorEventsToBuffer(shouldResample, buffer[i], scratch, &count);
+ }
} else {
- sanitizedBuffer.reset(new sensors_event_t[numEvents]);
- scratch = sanitizedBuffer.get();
for (size_t i = 0; i < numEvents; i++) {
if (buffer[i].type == SENSOR_TYPE_META_DATA) {
scratch[count++] = buffer[i++];
@@ -465,7 +493,8 @@ bool SensorService::SensorEventConnection::noteOpIfRequired(const sensors_event_
noteMsg.append(String16(mService->getSensorStringType(sensorHandle)));
noteMsg.append(String16(")"));
int32_t appOpMode = mService->sAppOpsManager.noteOp(iter->second, mUid,
- mOpPackageName, {}, noteMsg);
+ mOpPackageName, mAttributionTag,
+ noteMsg);
success = (appOpMode == AppOpsManager::MODE_ALLOWED);
}
}
@@ -684,24 +713,118 @@ status_t SensorService::SensorEventConnection::enableDisable(
status_t err;
if (enabled) {
+ nsecs_t requestedSamplingPeriodNs = samplingPeriodNs;
+ bool isSensorCapped = false;
+ sp<SensorInterface> si = mService->getSensorInterfaceFromHandle(handle);
+ if (si != nullptr) {
+ const Sensor& s = si->getSensor();
+ if (mService->isSensorInCappedSet(s.getType())) {
+ isSensorCapped = true;
+ }
+ }
+ if (isSensorCapped) {
+ err = mService->adjustSamplingPeriodBasedOnMicAndPermission(&samplingPeriodNs,
+ String16(mOpPackageName));
+ if (err != OK) {
+ return err;
+ }
+ }
err = mService->enable(this, handle, samplingPeriodNs, maxBatchReportLatencyNs,
reservedFlags, mOpPackageName);
+ if (err == OK && isSensorCapped) {
+ if (!mIsRateCappedBasedOnPermission ||
+ requestedSamplingPeriodNs >= SENSOR_SERVICE_CAPPED_SAMPLING_PERIOD_NS) {
+ mMicSamplingPeriodBackup[handle] = requestedSamplingPeriodNs;
+ } else {
+ mMicSamplingPeriodBackup[handle] = SENSOR_SERVICE_CAPPED_SAMPLING_PERIOD_NS;
+ }
+ }
} else {
err = mService->disable(this, handle);
+ mMicSamplingPeriodBackup.erase(handle);
}
return err;
}
-status_t SensorService::SensorEventConnection::setEventRate(
- int handle, nsecs_t samplingPeriodNs)
-{
+status_t SensorService::SensorEventConnection::setEventRate(int handle, nsecs_t samplingPeriodNs) {
if (mDestroyed) {
android_errorWriteLog(0x534e4554, "168211968");
return DEAD_OBJECT;
}
- return mService->setEventRate(this, handle, samplingPeriodNs, mOpPackageName);
+ nsecs_t requestedSamplingPeriodNs = samplingPeriodNs;
+ bool isSensorCapped = false;
+ sp<SensorInterface> si = mService->getSensorInterfaceFromHandle(handle);
+ if (si != nullptr) {
+ const Sensor& s = si->getSensor();
+ if (mService->isSensorInCappedSet(s.getType())) {
+ isSensorCapped = true;
+ }
+ }
+ if (isSensorCapped) {
+ status_t err = mService->adjustSamplingPeriodBasedOnMicAndPermission(&samplingPeriodNs,
+ String16(mOpPackageName));
+ if (err != OK) {
+ return err;
+ }
+ }
+ status_t ret = mService->setEventRate(this, handle, samplingPeriodNs, mOpPackageName);
+ if (ret == OK && isSensorCapped) {
+ if (!mIsRateCappedBasedOnPermission ||
+ requestedSamplingPeriodNs >= SENSOR_SERVICE_CAPPED_SAMPLING_PERIOD_NS) {
+ mMicSamplingPeriodBackup[handle] = requestedSamplingPeriodNs;
+ } else {
+ mMicSamplingPeriodBackup[handle] = SENSOR_SERVICE_CAPPED_SAMPLING_PERIOD_NS;
+ }
+ }
+ return ret;
+}
+
+void SensorService::SensorEventConnection::onMicSensorAccessChanged(bool isMicToggleOn) {
+ if (isMicToggleOn) {
+ capRates();
+ } else {
+ uncapRates();
+ }
+}
+
+void SensorService::SensorEventConnection::capRates() {
+ Mutex::Autolock _l(mConnectionLock);
+ SensorDevice& dev(SensorDevice::getInstance());
+ for (auto &i : mMicSamplingPeriodBackup) {
+ int handle = i.first;
+ nsecs_t samplingPeriodNs = i.second;
+ if (samplingPeriodNs < SENSOR_SERVICE_CAPPED_SAMPLING_PERIOD_NS) {
+ if (hasSensorAccess()) {
+ mService->setEventRate(this, handle, SENSOR_SERVICE_CAPPED_SAMPLING_PERIOD_NS,
+ mOpPackageName);
+ } else {
+ // Update SensorDevice with the capped rate so that when sensor access is restored,
+ // the correct event rate is used.
+ dev.onMicSensorAccessChanged(this, handle,
+ SENSOR_SERVICE_CAPPED_SAMPLING_PERIOD_NS);
+ }
+ }
+ }
+}
+
+void SensorService::SensorEventConnection::uncapRates() {
+ Mutex::Autolock _l(mConnectionLock);
+ SensorDevice& dev(SensorDevice::getInstance());
+ for (auto &i : mMicSamplingPeriodBackup) {
+ int handle = i.first;
+ nsecs_t samplingPeriodNs = i.second;
+ if (samplingPeriodNs < SENSOR_SERVICE_CAPPED_SAMPLING_PERIOD_NS) {
+ if (hasSensorAccess()) {
+ mService->setEventRate(this, handle, samplingPeriodNs, mOpPackageName);
+ } else {
+ // Update SensorDevice with the uncapped rate so that when sensor access is
+ // restored, the correct event rate is used.
+ dev.onMicSensorAccessChanged(this, handle, samplingPeriodNs);
+ }
+ }
+ }
}
status_t SensorService::SensorEventConnection::flush() {
diff --git a/services/sensorservice/SensorEventConnection.h b/services/sensorservice/SensorEventConnection.h
index 9487a39a92..4e3f120ccc 100644
--- a/services/sensorservice/SensorEventConnection.h
+++ b/services/sensorservice/SensorEventConnection.h
@@ -50,7 +50,8 @@ class SensorService::SensorEventConnection:
public:
SensorEventConnection(const sp<SensorService>& service, uid_t uid, String8 packageName,
- bool isDataInjectionMode, const String16& opPackageName);
+ bool isDataInjectionMode, const String16& opPackageName,
+ const String16& attributionTag);
status_t sendEvents(sensors_event_t const* buffer, size_t count, sensors_event_t* scratch,
wp<const SensorEventConnection> const * mapFlushEventsToConnections = nullptr);
@@ -68,6 +69,9 @@ public:
String8 getPackageName() const;
uid_t getUid() const { return mUid; }
+ // cap/uncap existing connection depending on the state of the mic toggle.
+ void onMicSensorAccessChanged(bool isMicToggleOn);
+ userid_t getUserId() const { return mUserId; }
private:
virtual ~SensorEventConnection();
@@ -137,10 +141,20 @@ private:
// Call noteOp for the sensor if the sensor requires a permission
bool noteOpIfRequired(const sensors_event_t& event);
-
+ // Limits all active connections when the mic toggle is flipped to on.
+ void capRates();
+ // Recover sensor connection previously capped by capRates().
+ void uncapRates();
+
+ // Add sensorEvent to buffer at position index if the sensorEvent satisfies throttling rules.
+ void addSensorEventsToBuffer(bool shouldResample, const sensors_event_t& sensorEvent,
+ sensors_event_t* buffer, int* index);
sp<SensorService> const mService;
sp<BitTube> mChannel;
uid_t mUid;
+ std::atomic_bool mIsRateCappedBasedOnPermission;
+ // Store a mapping of sensor to the timestamp of their last sensor event.
+ std::unordered_map<int, int64_t> mSensorLastTimestamp;
mutable Mutex mConnectionLock;
// Number of events from wake up sensors which are still pending and haven't been delivered to
// the corresponding application. It is incremented by one unit for each write to the socket.
@@ -177,6 +191,7 @@ private:
int mEventsDropped;
String8 mPackageName;
const String16 mOpPackageName;
+ const String16 mAttributionTag;
int mTargetSdk;
#if DEBUG_CONNECTIONS
int mEventsReceived, mEventsSent, mEventsSentFromCache;
@@ -189,6 +204,9 @@ private:
// Store a mapping of sensor handles to required AppOp for a sensor. This map only contains a
// valid mapping for sensors that require a permission in order to reduce the lookup time.
std::unordered_map<int32_t, int32_t> mHandleToAppOp;
+ // Mapping of sensor handles to its rate before being capped by the mic toggle.
+ std::unordered_map<int, nsecs_t> mMicSamplingPeriodBackup;
+ userid_t mUserId;
};
} // namepsace android
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index 8f25bdba4f..942b7ae76a 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+#include <android-base/strings.h>
#include <android/content/pm/IPackageManagerNative.h>
#include <android/util/ProtoOutputStream.h>
#include <frameworks/base/core/proto/android/service/sensor_service.proto.h>
@@ -88,6 +89,8 @@ AppOpsManager SensorService::sAppOpsManager;
#define SENSOR_SERVICE_SCHED_FIFO_PRIORITY 10
// Permissions.
+static const String16 sAccessHighSensorSamplingRatePermission(
+ "android.permission.HIGH_SAMPLING_RATE_SENSORS");
static const String16 sDumpPermission("android.permission.DUMP");
static const String16 sLocationHardwarePermission("android.permission.LOCATION_HARDWARE");
static const String16 sManageSensorsPermission("android.permission.MANAGE_SENSORS");
@@ -366,6 +369,9 @@ SensorService::~SensorService() {
}
mUidPolicy->unregisterSelf();
mSensorPrivacyPolicy->unregisterSelf();
+ for (auto const& [userId, policy] : mMicSensorPrivacyPolicies) {
+ policy->unregisterSelf();
+ }
}
status_t SensorService::dump(int fd, const Vector<String16>& args) {
@@ -695,6 +701,35 @@ void SensorService::enableAllSensorsLocked(ConnectionSafeAutolock* connLock) {
}
}
+void SensorService::capRates(userid_t userId) {
+ ConnectionSafeAutolock connLock = mConnectionHolder.lock(mLock);
+ for (const sp<SensorDirectConnection>& conn : connLock.getDirectConnections()) {
+ if (conn->getUserId() == userId) {
+ conn->onMicSensorAccessChanged(true);
+ }
+ }
+
+ for (const sp<SensorEventConnection>& conn : connLock.getActiveConnections()) {
+ if (conn->getUserId() == userId) {
+ conn->onMicSensorAccessChanged(true);
+ }
+ }
+}
+
+void SensorService::uncapRates(userid_t userId) {
+ ConnectionSafeAutolock connLock = mConnectionHolder.lock(mLock);
+ for (const sp<SensorDirectConnection>& conn : connLock.getDirectConnections()) {
+ if (conn->getUserId() == userId) {
+ conn->onMicSensorAccessChanged(false);
+ }
+ }
+
+ for (const sp<SensorEventConnection>& conn : connLock.getActiveConnections()) {
+ if (conn->getUserId() == userId) {
+ conn->onMicSensorAccessChanged(false);
+ }
+ }
+}
// NOTE: This is a remote API - make sure all args are validated
status_t SensorService::shellCommand(int in, int out, int err, Vector<String16>& args) {
@@ -1209,14 +1244,20 @@ void SensorService::makeUuidsIntoIdsForSensorList(Vector<Sensor> &sensorList) co
}
}
-Vector<Sensor> SensorService::getSensorList(const String16& /* opPackageName */) {
+Vector<Sensor> SensorService::getSensorList(const String16& opPackageName) {
char value[PROPERTY_VALUE_MAX];
property_get("debug.sensors", value, "0");
const Vector<Sensor>& initialSensorList = (atoi(value)) ?
mSensors.getUserDebugSensors() : mSensors.getUserSensors();
Vector<Sensor> accessibleSensorList;
+
+ bool isCapped = isRateCappedBasedOnPermission(opPackageName);
for (size_t i = 0; i < initialSensorList.size(); i++) {
Sensor sensor = initialSensorList[i];
+ if (isCapped && isSensorInCappedSet(sensor.getType())) {
+ sensor.capMinDelayMicros(SENSOR_SERVICE_CAPPED_SAMPLING_PERIOD_NS / 1000);
+ sensor.capHighestDirectReportRateLevel(SENSOR_SERVICE_CAPPED_SAMPLING_RATE_LEVEL);
+ }
accessibleSensorList.add(sensor);
}
makeUuidsIntoIdsForSensorList(accessibleSensorList);
@@ -1244,7 +1285,7 @@ Vector<Sensor> SensorService::getDynamicSensorList(const String16& opPackageName
}
sp<ISensorEventConnection> SensorService::createSensorEventConnection(const String8& packageName,
- int requestedMode, const String16& opPackageName) {
+ int requestedMode, const String16& opPackageName, const String16& attributionTag) {
// Only 2 modes supported for a SensorEventConnection ... NORMAL and DATA_INJECTION.
if (requestedMode != NORMAL && requestedMode != DATA_INJECTION) {
return nullptr;
@@ -1266,7 +1307,7 @@ sp<ISensorEventConnection> SensorService::createSensorEventConnection(const Stri
String16 connOpPackageName =
(opPackageName == String16("")) ? String16(connPackageName) : opPackageName;
sp<SensorEventConnection> result(new SensorEventConnection(this, uid, connPackageName,
- requestedMode == DATA_INJECTION, connOpPackageName));
+ requestedMode == DATA_INJECTION, connOpPackageName, attributionTag));
if (requestedMode == DATA_INJECTION) {
mConnectionHolder.addEventConnectionIfNotPresent(result);
// Add the associated file descriptor to the Looper for polling whenever there is data to
@@ -2024,6 +2065,69 @@ bool SensorService::isUidActive(uid_t uid) {
return mUidPolicy->isUidActive(uid);
}
+bool SensorService::isRateCappedBasedOnPermission(const String16& opPackageName) {
+ int targetSdk = getTargetSdkVersion(opPackageName);
+ bool hasSamplingRatePermission = PermissionCache::checkCallingPermission(
+ sAccessHighSensorSamplingRatePermission);
+ if (targetSdk < __ANDROID_API_S__ ||
+ (targetSdk >= __ANDROID_API_S__ && hasSamplingRatePermission)) {
+ return false;
+ }
+ return true;
+}
+
+bool SensorService::isSensorInCappedSet(int sensorType) {
+ return (sensorType == SENSOR_TYPE_ACCELEROMETER
+ || sensorType == SENSOR_TYPE_ACCELEROMETER_UNCALIBRATED
+ || sensorType == SENSOR_TYPE_GYROSCOPE
+ || sensorType == SENSOR_TYPE_GYROSCOPE_UNCALIBRATED
+ || sensorType == SENSOR_TYPE_MAGNETIC_FIELD
+ || sensorType == SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED);
+}
+
+status_t SensorService::adjustSamplingPeriodBasedOnMicAndPermission(nsecs_t* requestedPeriodNs,
+ const String16& opPackageName) {
+ uid_t uid = IPCThreadState::self()->getCallingUid();
+ bool shouldCapBasedOnPermission = isRateCappedBasedOnPermission(opPackageName);
+ if (*requestedPeriodNs >= SENSOR_SERVICE_CAPPED_SAMPLING_PERIOD_NS) {
+ return OK;
+ }
+ if (shouldCapBasedOnPermission) {
+ *requestedPeriodNs = SENSOR_SERVICE_CAPPED_SAMPLING_PERIOD_NS;
+ if (isPackageDebuggable(opPackageName)) {
+ return PERMISSION_DENIED;
+ }
+ return OK;
+ }
+ if (isMicSensorPrivacyEnabledForUid(uid)) {
+ *requestedPeriodNs = SENSOR_SERVICE_CAPPED_SAMPLING_PERIOD_NS;
+ return OK;
+ }
+ return OK;
+}
+
+status_t SensorService::adjustRateLevelBasedOnMicAndPermission(int* requestedRateLevel,
+ const String16& opPackageName) {
+ uid_t uid = IPCThreadState::self()->getCallingUid();
+ bool shouldCapBasedOnPermission = isRateCappedBasedOnPermission(opPackageName);
+
+ if (*requestedRateLevel <= SENSOR_SERVICE_CAPPED_SAMPLING_RATE_LEVEL) {
+ return OK;
+ }
+ if (shouldCapBasedOnPermission) {
+ *requestedRateLevel = SENSOR_SERVICE_CAPPED_SAMPLING_RATE_LEVEL;
+ if (isPackageDebuggable(opPackageName)) {
+ return PERMISSION_DENIED;
+ }
+ return OK;
+ }
+ if (isMicSensorPrivacyEnabledForUid(uid)) {
+ *requestedRateLevel = SENSOR_SERVICE_CAPPED_SAMPLING_RATE_LEVEL;
+ return OK;
+ }
+ return OK;
+}
+
void SensorService::SensorPrivacyPolicy::registerSelf() {
SensorPrivacyManager spm;
mSensorPrivacyEnabled = spm.isSensorPrivacyEnabled();
@@ -2042,16 +2146,56 @@ bool SensorService::SensorPrivacyPolicy::isSensorPrivacyEnabled() {
binder::Status SensorService::SensorPrivacyPolicy::onSensorPrivacyChanged(bool enabled) {
mSensorPrivacyEnabled = enabled;
sp<SensorService> service = mService.promote();
+
if (service != nullptr) {
- if (enabled) {
- service->disableAllSensors();
+ if (mIsIndividualMic) {
+ if (enabled) {
+ service->capRates(mUserId);
+ } else {
+ service->uncapRates(mUserId);
+ }
} else {
- service->enableAllSensors();
+ if (enabled) {
+ service->disableAllSensors();
+ } else {
+ service->enableAllSensors();
+ }
}
}
return binder::Status::ok();
}
+status_t SensorService::SensorPrivacyPolicy::registerSelfForIndividual(int userId) {
+ Mutex::Autolock _l(mSensorPrivacyLock);
+
+ SensorPrivacyManager spm;
+ status_t err = spm.addIndividualSensorPrivacyListener(userId,
+ SensorPrivacyManager::INDIVIDUAL_SENSOR_MICROPHONE, this);
+
+ if (err != OK) {
+ ALOGE("Cannot register a mic listener.");
+ return err;
+ }
+ mSensorPrivacyEnabled = spm.isIndividualSensorPrivacyEnabled(userId,
+ SensorPrivacyManager::INDIVIDUAL_SENSOR_MICROPHONE);
+
+ mIsIndividualMic = true;
+ mUserId = userId;
+ return OK;
+}
+
+bool SensorService::isMicSensorPrivacyEnabledForUid(uid_t uid) {
+ userid_t userId = multiuser_get_user_id(uid);
+ if (mMicSensorPrivacyPolicies.find(userId) == mMicSensorPrivacyPolicies.end()) {
+ sp<SensorPrivacyPolicy> userPolicy = new SensorPrivacyPolicy(this);
+ if (userPolicy->registerSelfForIndividual(userId) != OK) {
+ return false;
+ }
+ mMicSensorPrivacyPolicies[userId] = userPolicy;
+ }
+ return mMicSensorPrivacyPolicies[userId]->isSensorPrivacyEnabled();
+}
+
SensorService::ConnectionSafeAutolock::ConnectionSafeAutolock(
SensorService::SensorConnectionHolder& holder, Mutex& mutex)
: mConnectionHolder(holder), mAutolock(mutex) {}
@@ -2109,4 +2253,17 @@ SensorService::ConnectionSafeAutolock SensorService::SensorConnectionHolder::loc
return ConnectionSafeAutolock(*this, mutex);
}
+bool SensorService::isPackageDebuggable(const String16& opPackageName) {
+ bool debugMode = false;
+ sp<IBinder> binder = defaultServiceManager()->getService(String16("package_native"));
+ if (binder != nullptr) {
+ sp<content::pm::IPackageManagerNative> packageManager =
+ interface_cast<content::pm::IPackageManagerNative>(binder);
+ if (packageManager != nullptr) {
+ binder::Status status = packageManager->isPackageDebuggable(
+ opPackageName, &debugMode);
+ }
+ }
+ return debugMode;
+}
} // namespace android
diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h
index 50c7c2f383..9c5060a577 100644
--- a/services/sensorservice/SensorService.h
+++ b/services/sensorservice/SensorService.h
@@ -61,6 +61,15 @@
#define SENSOR_REGISTRATIONS_BUF_SIZE 200
+// Apps that targets S+ and do not have HIGH_SAMPLING_RATE_SENSORS permission will be capped
+// at 200 Hz. The cap also applies to all requests when the mic toggle is flipped to on, regardless
+// of their target SDKs and permission.
+// Capped sampling periods for apps that have non-direct sensor connections.
+#define SENSOR_SERVICE_CAPPED_SAMPLING_PERIOD_NS (5 * 1000 * 1000)
+// Capped sampling rate level for apps that have direct sensor connections.
+// The enum SENSOR_DIRECT_RATE_NORMAL corresponds to a rate value of at most 110 Hz.
+#define SENSOR_SERVICE_CAPPED_SAMPLING_RATE_LEVEL SENSOR_DIRECT_RATE_NORMAL
+
namespace android {
// ---------------------------------------------------------------------------
class SensorInterface;
@@ -95,6 +104,8 @@ public:
status_t flushSensor(const sp<SensorEventConnection>& connection,
const String16& opPackageName);
+ // Returns true if a sensor should be throttled according to our rate-throttling rules.
+ static bool isSensorInCappedSet(int sensorType);
virtual status_t shellCommand(int in, int out, int err, Vector<String16>& args);
@@ -212,17 +223,23 @@ private:
// connections will be allowed again.
class SensorPrivacyPolicy : public hardware::BnSensorPrivacyListener {
public:
- explicit SensorPrivacyPolicy(wp<SensorService> service) : mService(service) {}
+ explicit SensorPrivacyPolicy(wp<SensorService> service)
+ : mService(service), mIsIndividualMic(false), mUserId(0) {}
void registerSelf();
void unregisterSelf();
+ status_t registerSelfForIndividual(int userId);
+
bool isSensorPrivacyEnabled();
binder::Status onSensorPrivacyChanged(bool enabled);
private:
wp<SensorService> mService;
+ Mutex mSensorPrivacyLock;
std::atomic_bool mSensorPrivacyEnabled;
+ bool mIsIndividualMic;
+ userid_t mUserId;
};
enum Mode {
@@ -286,7 +303,7 @@ private:
virtual Vector<Sensor> getDynamicSensorList(const String16& opPackageName);
virtual sp<ISensorEventConnection> createSensorEventConnection(
const String8& packageName,
- int requestedMode, const String16& opPackageName);
+ int requestedMode, const String16& opPackageName, const String16& attributionTag);
virtual int isDataInjectionEnabled();
virtual sp<ISensorEventConnection> createSensorDirectConnection(const String16& opPackageName,
uint32_t size, int32_t type, int32_t format, const native_handle *resource);
@@ -346,6 +363,13 @@ private:
// whitelisted). mLock must be held to invoke this method.
bool isOperationRestrictedLocked(const String16& opPackageName);
+ status_t adjustSamplingPeriodBasedOnMicAndPermission(nsecs_t* requestedPeriodNs,
+ const String16& opPackageName);
+ status_t adjustRateLevelBasedOnMicAndPermission(int* requestedRateLevel,
+ const String16& opPackageName);
+ bool isRateCappedBasedOnPermission(const String16& opPackageName);
+ bool isPackageDebuggable(const String16& opPackageName);
+
// Reset the state of SensorService to NORMAL mode.
status_t resetToNormalMode();
status_t resetToNormalModeLocked();
@@ -385,6 +409,11 @@ private:
void enableAllSensors();
void enableAllSensorsLocked(ConnectionSafeAutolock* connLock);
+ // Caps active direct connections (when the mic toggle is flipped to on)
+ void capRates(userid_t userId);
+ // Removes the capped rate on active direct connections (when the mic toggle is flipped to off)
+ void uncapRates(userid_t userId);
+
static uint8_t sHmacGlobalKey[128];
static bool sHmacGlobalKeyIsValid;
@@ -426,6 +455,11 @@ private:
static std::map<String16, int> sPackageTargetVersion;
static Mutex sPackageTargetVersionLock;
static String16 sSensorInterfaceDescriptorPrefix;
+
+ // Map from user to SensorPrivacyPolicy
+ std::map<userid_t, sp<SensorPrivacyPolicy>> mMicSensorPrivacyPolicies;
+ // Checks if the mic sensor privacy is enabled for the uid
+ bool isMicSensorPrivacyEnabledForUid(uid_t uid);
};
} // namespace android
diff --git a/services/sensorservice/hidl/Android.bp b/services/sensorservice/hidl/Android.bp
index 0e1af595f0..9bafb3cf95 100644
--- a/services/sensorservice/hidl/Android.bp
+++ b/services/sensorservice/hidl/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library_shared {
name: "libsensorservicehidl",
srcs: [
diff --git a/services/sensorservice/tests/Android.bp b/services/sensorservice/tests/Android.bp
index d33c0ca59d..ddc03a17e1 100644
--- a/services/sensorservice/tests/Android.bp
+++ b/services/sensorservice/tests/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_binary {
name: "test-sensorservice",
srcs: ["sensorservicetest.cpp"],
diff --git a/services/stats/Android.bp b/services/stats/Android.bp
index 1ce0524299..a472c5f38b 100644
--- a/services/stats/Android.bp
+++ b/services/stats/Android.bp
@@ -1,11 +1,23 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library_shared {
name: "libstatshidl",
srcs: [
+ "StatsAidl.cpp",
"StatsHal.cpp",
],
cflags: ["-Wall", "-Werror"],
shared_libs: [
"android.frameworks.stats@1.0",
+ "android.frameworks.stats-V1-ndk_platform",
+ "libbinder_ndk",
"libhidlbase",
"liblog",
"libstatslog",
@@ -13,7 +25,11 @@ cc_library_shared {
"libutils",
],
export_include_dirs: [
- "include/",
+ "include/",
+ ],
+ export_shared_lib_headers: [
+ "android.frameworks.stats@1.0",
+ "android.frameworks.stats-V1-ndk_platform",
],
local_include_dirs: [
"include/stats",
diff --git a/services/stats/StatsAidl.cpp b/services/stats/StatsAidl.cpp
new file mode 100644
index 0000000000..a3b68f1dab
--- /dev/null
+++ b/services/stats/StatsAidl.cpp
@@ -0,0 +1,79 @@
+/*
+ * 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.
+ */
+
+#define DEBUG false // STOPSHIP if true
+#define LOG_TAG "StatsAidl"
+
+#include <log/log.h>
+#include <statslog.h>
+
+#include "StatsAidl.h"
+
+namespace aidl {
+namespace android {
+namespace frameworks {
+namespace stats {
+
+StatsHal::StatsHal() {}
+
+ndk::ScopedAStatus StatsHal::reportVendorAtom(const VendorAtom& vendorAtom) {
+ std::string reverseDomainName = (std::string) vendorAtom.reverseDomainName;
+ if (vendorAtom.atomId < 100000 || vendorAtom.atomId >= 200000) {
+ ALOGE("Atom ID %ld is not a valid vendor atom ID", (long) vendorAtom.atomId);
+ return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
+ -1, "Not a valid vendor atom ID");
+ }
+ if (reverseDomainName.length() > 50) {
+ ALOGE("Vendor atom reverse domain name %s is too long.", reverseDomainName.c_str());
+ return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
+ -1, "Vendor atom reverse domain name is too long");
+ }
+ AStatsEvent* event = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(event, vendorAtom.atomId);
+ AStatsEvent_writeString(event, vendorAtom.reverseDomainName.c_str());
+ for (const auto& atomValue : vendorAtom.values) {
+ switch (atomValue.getTag()) {
+ case VendorAtomValue::intValue:
+ AStatsEvent_writeInt32(event,
+ atomValue.get<VendorAtomValue::intValue>());
+ break;
+ case VendorAtomValue::longValue:
+ AStatsEvent_writeInt64(event,
+ atomValue.get<VendorAtomValue::longValue>());
+ break;
+ case VendorAtomValue::floatValue:
+ AStatsEvent_writeFloat(event,
+ atomValue.get<VendorAtomValue::floatValue>());
+ break;
+ case VendorAtomValue::stringValue:
+ AStatsEvent_writeString(event,
+ atomValue.get<VendorAtomValue::stringValue>().c_str());
+ break;
+ }
+ }
+ AStatsEvent_build(event);
+ const int ret = AStatsEvent_write(event);
+ AStatsEvent_release(event);
+
+ return ret <= 0 ?
+ ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(ret, "report atom failed") :
+ ndk::ScopedAStatus::ok();
+}
+
+} // namespace stats
+} // namespace frameworks
+} // namespace android
+} // namespace aidl
diff --git a/services/stats/android.frameworks.stats@1.0-service.xml b/services/stats/android.frameworks.stats@1.0-service.xml
index bb02f66a28..5fd361c57d 100644
--- a/services/stats/android.frameworks.stats@1.0-service.xml
+++ b/services/stats/android.frameworks.stats@1.0-service.xml
@@ -8,4 +8,10 @@
<instance>default</instance>
</interface>
</hal>
+
+ <hal format="aidl">
+ <name>android.frameworks.stats</name>
+ <version>1</version>
+ <fqname>IStats/default</fqname>
+ </hal>
</manifest>
diff --git a/services/stats/include/stats/StatsAidl.h b/services/stats/include/stats/StatsAidl.h
new file mode 100644
index 0000000000..219e71e7b0
--- /dev/null
+++ b/services/stats/include/stats/StatsAidl.h
@@ -0,0 +1,38 @@
+/*
+ * 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 <aidl/android/frameworks/stats/BnStats.h>
+
+namespace aidl {
+namespace android {
+namespace frameworks {
+namespace stats {
+
+class StatsHal : public BnStats {
+public:
+ StatsHal();
+
+ /**
+ * Binder call to get vendor atom.
+ */
+ virtual ndk::ScopedAStatus reportVendorAtom(
+ const VendorAtom& in_vendorAtom) override;
+};
+
+} // namespace stats
+} // namespace frameworks
+} // namespace android
+} // namespace aidl
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index 8d1258a713..625f315b00 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_defaults {
name: "surfaceflinger_defaults",
cflags: [
@@ -106,6 +115,10 @@ cc_defaults {
thin: true,
},
whole_program_vtables: true, // Requires ThinLTO
+ pgo: {
+ sampling: true,
+ profile_file: "surfaceflinger/surfaceflinger.profdata",
+ },
// TODO(b/131771163): Fix broken fuzzer support with LTO.
sanitize: {
fuzzer: false,
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index ec81ff7b14..097f7de891 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -366,8 +366,11 @@ 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);
+ mFlinger->mTimeStats->setPresentFence(layerId, mCurrentFrameNumber, presentFence,
+ refreshRate, renderRate);
mFlinger->mFrameTracer->traceFence(layerId, getCurrentBufferId(), mCurrentFrameNumber,
presentFence, FrameTracer::FrameEvent::PRESENT_FENCE);
mFrameTracker.setActualPresentFence(std::shared_ptr<FenceTime>(presentFence));
@@ -378,7 +381,8 @@ bool BufferLayer::onPostComposition(const DisplayDevice* display,
// 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);
+ mFlinger->mTimeStats->setPresentTime(layerId, mCurrentFrameNumber, actualPresentTime,
+ refreshRate, renderRate);
mFlinger->mFrameTracer->traceTimestamp(layerId, getCurrentBufferId(), mCurrentFrameNumber,
actualPresentTime,
FrameTracer::FrameEvent::PRESENT_FENCE);
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index cf87f62745..f30e1eb1c3 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -35,6 +35,7 @@
#include <renderengine/Image.h>
#include "EffectLayer.h"
+#include "FrameTracer/FrameTracer.h"
#include "TimeStats/TimeStats.h"
namespace android {
@@ -235,10 +236,6 @@ void BufferStateLayer::pushPendingState() {
bool BufferStateLayer::applyPendingStates(Layer::State* stateToCommit) {
mCurrentStateModified = mCurrentState.modified;
bool stateUpdateAvailable = Layer::applyPendingStates(stateToCommit);
- if (stateUpdateAvailable && mCallbackHandleAcquireTime != -1) {
- // Update the acquire fence time if we have a buffer
- mSurfaceFrame->setAcquireFenceTime(mCallbackHandleAcquireTime);
- }
mCurrentStateModified = stateUpdateAvailable && mCurrentStateModified;
mCurrentState.modified = false;
return stateUpdateAvailable;
@@ -337,7 +334,7 @@ bool BufferStateLayer::addFrameEvent(const sp<Fence>& acquireFence, nsecs_t post
bool BufferStateLayer::setBuffer(const sp<GraphicBuffer>& buffer, const sp<Fence>& acquireFence,
nsecs_t postTime, nsecs_t desiredPresentTime, bool isAutoTimestamp,
const client_cache_t& clientCacheId, uint64_t frameNumber,
- std::optional<nsecs_t> /* dequeueTime */,
+ std::optional<nsecs_t> dequeueTime,
const FrameTimelineInfo& info) {
ATRACE_CALL();
@@ -377,6 +374,14 @@ bool BufferStateLayer::setBuffer(const sp<GraphicBuffer>& buffer, const sp<Fence
setFrameTimelineVsyncForBufferTransaction(info, postTime);
}
+ if (dequeueTime && *dequeueTime != 0) {
+ const uint64_t bufferId = buffer->getId();
+ mFlinger->mFrameTracer->traceNewLayer(layerId, getName().c_str());
+ mFlinger->mFrameTracer->traceTimestamp(layerId, bufferId, frameNumber, *dequeueTime,
+ FrameTracer::FrameEvent::DEQUEUE);
+ mFlinger->mFrameTracer->traceTimestamp(layerId, bufferId, frameNumber, postTime,
+ FrameTracer::FrameEvent::QUEUE);
+ }
return true;
}
@@ -452,6 +457,7 @@ bool BufferStateLayer::setTransactionCompletedListeners(
if (willPresent) {
// If this transaction set an acquire fence on this layer, set its acquire time
handle->acquireTime = mCallbackHandleAcquireTime;
+ handle->frameNumber = mCurrentState.frameNumber;
// Notify the transaction completed thread that there is a pending latched callback
// handle
@@ -602,11 +608,12 @@ bool BufferStateLayer::hasFrameUpdate() const {
}
std::optional<nsecs_t> BufferStateLayer::nextPredictedPresentTime() const {
- if (!getDrawingState().isAutoTimestamp || !mSurfaceFrame) {
+ const State& drawingState(getDrawingState());
+ if (!drawingState.isAutoTimestamp || !drawingState.bufferSurfaceFrameTX) {
return std::nullopt;
}
- return mSurfaceFrame->getPredictions().presentTime;
+ return drawingState.bufferSurfaceFrameTX->getPredictions().presentTime;
}
status_t BufferStateLayer::updateTexImage(bool& /*recomputeVisibleRegions*/, nsecs_t latchTime,
@@ -623,14 +630,22 @@ status_t BufferStateLayer::updateTexImage(bool& /*recomputeVisibleRegions*/, nse
}
for (auto& handle : mDrawingState.callbackHandles) {
- handle->latchTime = latchTime;
- handle->frameNumber = mDrawingState.frameNumber;
+ if (handle->frameNumber == mDrawingState.frameNumber) {
+ handle->latchTime = latchTime;
+ }
}
const int32_t layerId = getSequence();
- mFlinger->mTimeStats->setAcquireFence(layerId, mDrawingState.frameNumber,
- std::make_shared<FenceTime>(mDrawingState.acquireFence));
- mFlinger->mTimeStats->setLatchTime(layerId, mDrawingState.frameNumber, latchTime);
+ const uint64_t bufferId = mDrawingState.buffer->getId();
+ const uint64_t frameNumber = mDrawingState.frameNumber;
+ const auto acquireFence = std::make_shared<FenceTime>(mDrawingState.acquireFence);
+ mFlinger->mTimeStats->setAcquireFence(layerId, frameNumber, acquireFence);
+ mFlinger->mTimeStats->setLatchTime(layerId, frameNumber, latchTime);
+
+ mFlinger->mFrameTracer->traceFence(layerId, bufferId, frameNumber, acquireFence,
+ FrameTracer::FrameEvent::ACQUIRE_FENCE);
+ mFlinger->mFrameTracer->traceTimestamp(layerId, bufferId, frameNumber, latchTime,
+ FrameTracer::FrameEvent::LATCH);
auto& bufferSurfaceFrame = mDrawingState.bufferSurfaceFrameTX;
if (bufferSurfaceFrame != nullptr &&
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index ea832a2078..175a40b80e 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -124,6 +124,7 @@ protected:
private:
friend class SlotGenerationTest;
+ friend class TransactionFrameTracerTest;
friend class TransactionSurfaceFrameTest;
inline void tracePendingBufferCount();
diff --git a/services/surfaceflinger/ClientCache.cpp b/services/surfaceflinger/ClientCache.cpp
index a5be01c75c..2ae49fa6bb 100644
--- a/services/surfaceflinger/ClientCache.cpp
+++ b/services/surfaceflinger/ClientCache.cpp
@@ -25,6 +25,8 @@
namespace android {
+using base::StringAppendF;
+
ANDROID_SINGLETON_STATIC_INSTANCE(ClientCache);
ClientCache::ClientCache() : mDeathRecipient(new CacheDeathRecipient) {}
@@ -203,4 +205,18 @@ void ClientCache::CacheDeathRecipient::binderDied(const wp<IBinder>& who) {
ClientCache::getInstance().removeProcess(who);
}
+void ClientCache::dump(std::string& result) {
+ std::lock_guard lock(mMutex);
+ for (auto i : mBuffers) {
+ const sp<IBinder>& cacheOwner = i.second.first;
+ StringAppendF(&result," Cache owner: %p\n", cacheOwner.get());
+ auto &buffers = i.second.second;
+ for (auto& [id, clientCacheBuffer] : buffers) {
+ StringAppendF(&result, "\t ID: %d, Width/Height: %d,%d\n", (int)id,
+ (int)clientCacheBuffer.buffer->getWidth(),
+ (int)clientCacheBuffer.buffer->getHeight());
+ }
+ }
+}
+
}; // namespace android
diff --git a/services/surfaceflinger/ClientCache.h b/services/surfaceflinger/ClientCache.h
index d7af7c0e97..0d597c8e05 100644
--- a/services/surfaceflinger/ClientCache.h
+++ b/services/surfaceflinger/ClientCache.h
@@ -53,6 +53,8 @@ public:
void unregisterErasedRecipient(const client_cache_t& cacheId,
const wp<ErasedRecipient>& recipient);
+ void dump(std::string& result);
+
private:
std::mutex mMutex;
diff --git a/services/surfaceflinger/CompositionEngine/Android.bp b/services/surfaceflinger/CompositionEngine/Android.bp
index 57dc60bbac..50bc5edfc6 100644
--- a/services/surfaceflinger/CompositionEngine/Android.bp
+++ b/services/surfaceflinger/CompositionEngine/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_defaults {
name: "libcompositionengine_defaults",
defaults: ["surfaceflinger_defaults"],
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h
index 95ba9f0429..633668e1c2 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h
@@ -21,9 +21,9 @@
#include <string>
#include <ui/DisplayId.h>
-#include <ui/DisplayInfo.h>
#include <ui/PixelFormat.h>
#include <ui/Size.h>
+#include <ui/StaticDisplayInfo.h>
#include "DisplayHardware/DisplayIdentification.h"
#include "DisplayHardware/PowerAdvisor.h"
@@ -39,7 +39,7 @@ class CompositionEngine;
struct DisplayCreationArgs {
struct Physical {
DisplayId id;
- DisplayConnectionType type;
+ ui::DisplayConnectionType type;
};
// Required for physical displays. Gives the HWC display id for the existing
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
index c445d5b615..8402149c57 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
@@ -34,6 +34,7 @@
#include <gui/BufferQueue.h>
#include <ui/GraphicBuffer.h>
#include <ui/GraphicTypes.h>
+#include <ui/StretchEffect.h>
#include "DisplayHardware/Hal.h"
@@ -123,6 +124,8 @@ struct LayerFECompositionState {
// List of regions that require blur
std::vector<BlurRegion> blurRegions;
+ StretchEffect stretchEffect;
+
/*
* Geometry state
*/
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DumpHelpers.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DumpHelpers.h
index 782c8d772f..6b9597b2d5 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DumpHelpers.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DumpHelpers.h
@@ -24,6 +24,7 @@
#include <ui/FloatRect.h>
#include <ui/Rect.h>
#include <ui/Region.h>
+#include <ui/StretchEffect.h>
#include <ui/Transform.h>
namespace android::compositionengine::impl {
@@ -58,5 +59,6 @@ void dumpVal(std::string& out, const char* name, const ui::Transform&);
void dumpVal(std::string& out, const char* name, const ui::Size&);
void dumpVal(std::string& out, const char* name, const mat4& tr);
+void dumpVal(std::string& out, const char* name, const StretchEffect&);
} // namespace android::compositionengine::impl
diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp
index 0b0b8d5e9c..a605fe1dc3 100644
--- a/services/surfaceflinger/CompositionEngine/src/Display.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp
@@ -55,7 +55,8 @@ void Display::setConfiguration(const compositionengine::DisplayCreationArgs& arg
editState().isSecure = args.isSecure;
editState().displaySpace.bounds = Rect(args.pixels);
setLayerStackFilter(args.layerStackId,
- args.physical && args.physical->type == DisplayConnectionType::Internal);
+ args.physical &&
+ args.physical->type == ui::DisplayConnectionType::Internal);
setName(args.name);
mGpuVirtualDisplayIdGenerator = args.gpuVirtualDisplayIdGenerator;
diff --git a/services/surfaceflinger/CompositionEngine/src/DumpHelpers.cpp b/services/surfaceflinger/CompositionEngine/src/DumpHelpers.cpp
index 9d1bb02e7c..0cc2c6e637 100644
--- a/services/surfaceflinger/CompositionEngine/src/DumpHelpers.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/DumpHelpers.cpp
@@ -100,4 +100,10 @@ void dumpVal(std::string& out, const char* name, const mat4& tr) {
); /* clang-format on */
}
+void dumpVal(std::string& out, const char* name, const StretchEffect& effect) {
+ StringAppendF(&out, "%s={ area=[%f, %f, %f, %f], vec=(%f, %f), max=%f } ", name,
+ effect.area.left, effect.area.top, effect.area.right, effect.area.bottom,
+ effect.vectorX, effect.vectorY, effect.maxAmount);
+}
+
} // namespace android::compositionengine::impl
diff --git a/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp
index 1338538861..430945ab4c 100644
--- a/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp
@@ -74,6 +74,9 @@ void LayerFECompositionState::dump(std::string& out) const {
dumpVal(out, "blend", toString(blendMode), blendMode);
dumpVal(out, "alpha", alpha);
dumpVal(out, "backgroundBlurRadius", backgroundBlurRadius);
+ if (stretchEffect.hasEffect()) {
+ dumpVal(out, "stretchEffect", stretchEffect);
+ }
if (!metadata.empty()) {
out.append("\n metadata {");
diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
index 348ec398ae..8a83639ce5 100644
--- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
@@ -35,8 +35,8 @@
#include <compositionengine/mock/RenderSurface.h>
#include <gtest/gtest.h>
#include <renderengine/mock/RenderEngine.h>
-#include <ui/DisplayInfo.h>
#include <ui/Rect.h>
+#include <ui/StaticDisplayInfo.h>
#include "MockHWC2.h"
#include "MockHWComposer.h"
@@ -169,7 +169,7 @@ struct DisplayTestCommon : public testing::Test {
DisplayCreationArgs getDisplayCreationArgsForPhysicalHWCDisplay() {
return DisplayCreationArgsBuilder()
- .setPhysical({DEFAULT_DISPLAY_ID, DisplayConnectionType::Internal})
+ .setPhysical({DEFAULT_DISPLAY_ID, ui::DisplayConnectionType::Internal})
.setPixels({DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT})
.setPixelFormat(static_cast<ui::PixelFormat>(PIXEL_FORMAT_RGBA_8888))
.setIsSecure(true)
@@ -265,7 +265,7 @@ TEST_F(DisplaySetConfigurationTest, configuresInternalSecurePhysicalDisplay) {
mDisplay->setConfiguration(
DisplayCreationArgsBuilder()
.setUseHwcVirtualDisplays(true)
- .setPhysical({DEFAULT_DISPLAY_ID, DisplayConnectionType::Internal})
+ .setPhysical({DEFAULT_DISPLAY_ID, ui::DisplayConnectionType::Internal})
.setPixels(ui::Size(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_WIDTH))
.setPixelFormat(static_cast<ui::PixelFormat>(PIXEL_FORMAT_RGBA_8888))
.setIsSecure(true)
@@ -286,7 +286,7 @@ TEST_F(DisplaySetConfigurationTest, configuresExternalInsecurePhysicalDisplay) {
mDisplay->setConfiguration(
DisplayCreationArgsBuilder()
.setUseHwcVirtualDisplays(true)
- .setPhysical({DEFAULT_DISPLAY_ID, DisplayConnectionType::External})
+ .setPhysical({DEFAULT_DISPLAY_ID, ui::DisplayConnectionType::External})
.setPixels(ui::Size(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_WIDTH))
.setPixelFormat(static_cast<ui::PixelFormat>(PIXEL_FORMAT_RGBA_8888))
.setIsSecure(false)
@@ -1018,7 +1018,7 @@ struct DisplayFunctionalTest : public testing::Test {
std::shared_ptr<Display> mDisplay = impl::createDisplayTemplated<
Display>(mCompositionEngine,
DisplayCreationArgsBuilder()
- .setPhysical({DEFAULT_DISPLAY_ID, DisplayConnectionType::Internal})
+ .setPhysical({DEFAULT_DISPLAY_ID, ui::DisplayConnectionType::Internal})
.setPixels({DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT})
.setPixelFormat(static_cast<ui::PixelFormat>(PIXEL_FORMAT_RGBA_8888))
.setIsSecure(true)
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
index ab003852de..bac894a6dc 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
@@ -91,7 +91,7 @@ public:
MOCK_CONST_METHOD1(getColorModes, std::vector<ui::ColorMode>(PhysicalDisplayId));
MOCK_METHOD3(setActiveColorMode, status_t(PhysicalDisplayId, ui::ColorMode, ui::RenderIntent));
MOCK_CONST_METHOD0(isUsingVrComposer, bool());
- MOCK_CONST_METHOD1(getDisplayConnectionType, DisplayConnectionType(PhysicalDisplayId));
+ MOCK_CONST_METHOD1(getDisplayConnectionType, ui::DisplayConnectionType(PhysicalDisplayId));
MOCK_CONST_METHOD1(isVsyncPeriodSwitchSupported, bool(PhysicalDisplayId));
MOCK_CONST_METHOD2(getDisplayVsyncPeriod, status_t(PhysicalDisplayId, nsecs_t*));
MOCK_METHOD4(setActiveModeWithConstraints,
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index a785968515..36c4c4d5ba 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -173,7 +173,7 @@ const DisplayModes& DisplayDevice::getSupportedModes() const {
DisplayModePtr DisplayDevice::getMode(DisplayModeId modeId) const {
const auto id = modeId.value();
- if (id < mSupportedModes.size()) {
+ if (static_cast<size_t>(id) < mSupportedModes.size()) {
return mSupportedModes[id];
}
return nullptr;
@@ -254,7 +254,7 @@ ui::Transform::RotationFlags DisplayDevice::getPrimaryDisplayRotationFlags() {
std::string DisplayDevice::getDebugName() const {
const char* type = "virtual";
if (mConnectionType) {
- type = *mConnectionType == DisplayConnectionType::Internal ? "internal" : "external";
+ type = *mConnectionType == ui::DisplayConnectionType::Internal ? "internal" : "external";
}
return base::StringPrintf("DisplayDevice{%s, %s%s, \"%s\"}", to_string(getId()).c_str(), type,
@@ -265,7 +265,8 @@ void DisplayDevice::dump(std::string& result) const {
StringAppendF(&result, "+ %s\n", getDebugName().c_str());
StringAppendF(&result, " powerMode=%s (%d)\n", to_string(mPowerMode).c_str(),
static_cast<int32_t>(mPowerMode));
- StringAppendF(&result, " activeMode=%s\n", to_string(*getActiveMode()).c_str());
+ StringAppendF(&result, " activeMode=%s\n",
+ mSupportedModes.size() ? to_string(*getActiveMode()).c_str() : "none");
result.append(" supportedModes=\n");
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index b4db933e19..a94bfa269d 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -28,11 +28,11 @@
#include <renderengine/RenderEngine.h>
#include <system/window.h>
#include <ui/DisplayId.h>
-#include <ui/DisplayInfo.h>
#include <ui/DisplayState.h>
#include <ui/GraphicTypes.h>
#include <ui/HdrCapabilities.h>
#include <ui/Region.h>
+#include <ui/StaticDisplayInfo.h>
#include <ui/Transform.h>
#include <utils/Errors.h>
#include <utils/Mutex.h>
@@ -74,7 +74,7 @@ public:
return mCompositionDisplay;
}
- std::optional<DisplayConnectionType> getConnectionType() const { return mConnectionType; }
+ std::optional<ui::DisplayConnectionType> getConnectionType() const { return mConnectionType; }
bool isVirtual() const { return !mConnectionType; }
bool isPrimary() const { return mIsPrimary; }
@@ -195,7 +195,7 @@ private:
HWComposer& mHwComposer;
const wp<IBinder> mDisplayToken;
const int32_t mSequenceId;
- const std::optional<DisplayConnectionType> mConnectionType;
+ const std::optional<ui::DisplayConnectionType> mConnectionType;
const std::shared_ptr<compositionengine::Display> mCompositionDisplay;
@@ -222,7 +222,7 @@ private:
struct DisplayDeviceState {
struct Physical {
PhysicalDisplayId id;
- DisplayConnectionType type;
+ ui::DisplayConnectionType type;
hardware::graphics::composer::hal::HWDisplayId hwcDisplayId;
std::optional<DeviceProductInfo> deviceProductInfo;
DisplayModes supportedModes;
@@ -263,7 +263,7 @@ struct DisplayDeviceCreationArgs {
const std::shared_ptr<compositionengine::Display> compositionDisplay;
int32_t sequenceId{0};
- std::optional<DisplayConnectionType> connectionType;
+ std::optional<ui::DisplayConnectionType> connectionType;
bool isSecure{false};
sp<ANativeWindow> nativeWindow;
sp<compositionengine::DisplaySurface> displaySurface;
diff --git a/services/surfaceflinger/DisplayHardware/DisplayMode.h b/services/surfaceflinger/DisplayHardware/DisplayMode.h
index 1f0f3c3c33..853c05b244 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/DisplayMode.h>
#include <ui/Size.h>
#include <utils/Timers.h>
@@ -36,7 +37,7 @@ namespace hal = android::hardware::graphics::composer::hal;
class DisplayMode;
using DisplayModePtr = std::shared_ptr<const DisplayMode>;
using DisplayModes = std::vector<DisplayModePtr>;
-using DisplayModeId = StrongTyping<size_t, struct DisplayModeIdTag, Compare, Hash>;
+using DisplayModeId = StrongTyping<ui::DisplayModeId, struct DisplayModeIdTag, Compare, Hash>;
class DisplayMode {
public:
@@ -139,7 +140,7 @@ private:
};
inline std::string to_string(const DisplayMode& mode) {
- return base::StringPrintf("{id=%zu, hwcId=%d, width=%d, height=%d, refreshRate=%s, "
+ return base::StringPrintf("{id=%d, hwcId=%d, width=%d, height=%d, refreshRate=%s, "
"dpiX=%.2f, dpiY=%.2f, group=%d}",
mode.getId().value(), mode.getHwcId(), mode.getWidth(),
mode.getHeight(), to_string(mode.getFps()).c_str(), mode.getDpiX(),
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index 71a3276d1b..d04b5f7316 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -264,7 +264,7 @@ Error Display::getRequests(HWC2::DisplayRequest* outDisplayRequests,
return Error::NONE;
}
-Error Display::getConnectionType(android::DisplayConnectionType* outType) const {
+Error Display::getConnectionType(ui::DisplayConnectionType* outType) const {
if (mType != DisplayType::PHYSICAL) return Error::BAD_DISPLAY;
using ConnectionType = Hwc2::IComposerClient::DisplayConnectionType;
@@ -274,9 +274,8 @@ Error Display::getConnectionType(android::DisplayConnectionType* outType) const
return error;
}
- *outType = connectionType == ConnectionType::INTERNAL
- ? android::DisplayConnectionType::Internal
- : android::DisplayConnectionType::External;
+ *outType = connectionType == ConnectionType::INTERNAL ? ui::DisplayConnectionType::Internal
+ : ui::DisplayConnectionType::External;
return Error::NONE;
}
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index 4c7f28412d..e7bf286d08 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -18,9 +18,9 @@
#include <gui/HdrMetadata.h>
#include <math/mat4.h>
-#include <ui/DisplayInfo.h>
#include <ui/HdrCapabilities.h>
#include <ui/Region.h>
+#include <ui/StaticDisplayInfo.h>
#include <utils/Log.h>
#include <utils/StrongPointer.h>
#include <utils/Timers.h>
@@ -104,7 +104,7 @@ public:
hal::DisplayRequest* outDisplayRequests,
std::unordered_map<Layer*, hal::LayerRequest>* outLayerRequests) = 0;
[[clang::warn_unused_result]] virtual hal::Error getConnectionType(
- android::DisplayConnectionType*) const = 0;
+ ui::DisplayConnectionType*) const = 0;
[[clang::warn_unused_result]] virtual hal::Error supportsDoze(bool* outSupport) const = 0;
[[clang::warn_unused_result]] virtual hal::Error getHdrCapabilities(
android::HdrCapabilities* outCapabilities) const = 0;
@@ -175,7 +175,7 @@ public:
hal::Error getRequests(
hal::DisplayRequest* outDisplayRequests,
std::unordered_map<Layer*, hal::LayerRequest>* outLayerRequests) override;
- hal::Error getConnectionType(android::DisplayConnectionType*) const override;
+ hal::Error getConnectionType(ui::DisplayConnectionType*) const override;
hal::Error supportsDoze(bool* outSupport) const override;
hal::Error getHdrCapabilities(android::HdrCapabilities* outCapabilities) const override;
hal::Error getDisplayedContentSamplingAttributes(hal::PixelFormat* outFormat,
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index b9a8e4be37..ccfaa76374 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -369,16 +369,16 @@ std::optional<hal::HWConfigId> HWComposer::getActiveMode(PhysicalDisplayId displ
// Composer 2.4
-DisplayConnectionType HWComposer::getDisplayConnectionType(PhysicalDisplayId displayId) const {
- RETURN_IF_INVALID_DISPLAY(displayId, DisplayConnectionType::Internal);
+ui::DisplayConnectionType HWComposer::getDisplayConnectionType(PhysicalDisplayId displayId) const {
+ RETURN_IF_INVALID_DISPLAY(displayId, ui::DisplayConnectionType::Internal);
const auto& hwcDisplay = mDisplayData.at(displayId).hwcDisplay;
- DisplayConnectionType type;
+ ui::DisplayConnectionType type;
const auto error = hwcDisplay->getConnectionType(&type);
const auto FALLBACK_TYPE = hwcDisplay->getId() == mInternalHwcDisplayId
- ? DisplayConnectionType::Internal
- : DisplayConnectionType::External;
+ ? ui::DisplayConnectionType::Internal
+ : ui::DisplayConnectionType::External;
RETURN_IF_HWC_ERROR(error, displayId, FALLBACK_TYPE);
return type;
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index f9c8e2efef..cf6bc68897 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -204,7 +204,7 @@ public:
ui::RenderIntent) = 0;
// Composer 2.4
- virtual DisplayConnectionType getDisplayConnectionType(PhysicalDisplayId) const = 0;
+ virtual ui::DisplayConnectionType getDisplayConnectionType(PhysicalDisplayId) const = 0;
virtual bool isVsyncPeriodSwitchSupported(PhysicalDisplayId) const = 0;
virtual status_t getDisplayVsyncPeriod(PhysicalDisplayId displayId,
nsecs_t* outVsyncPeriod) const = 0;
@@ -335,7 +335,7 @@ public:
status_t setActiveColorMode(PhysicalDisplayId, ui::ColorMode, ui::RenderIntent) override;
// Composer 2.4
- DisplayConnectionType getDisplayConnectionType(PhysicalDisplayId) const override;
+ ui::DisplayConnectionType getDisplayConnectionType(PhysicalDisplayId) const override;
bool isVsyncPeriodSwitchSupported(PhysicalDisplayId) const override;
status_t getDisplayVsyncPeriod(PhysicalDisplayId displayId,
nsecs_t* outVsyncPeriod) const override;
diff --git a/services/surfaceflinger/Fps.h b/services/surfaceflinger/Fps.h
index 38a9af0149..e9f06e5519 100644
--- a/services/surfaceflinger/Fps.h
+++ b/services/surfaceflinger/Fps.h
@@ -27,7 +27,7 @@ namespace android {
// Value which represents "frames per second". This class is a wrapper around
// float, providing some useful utilities, such as comparisons with tolerance
-// and converting between period duruation and frequency.
+// and converting between period duration and frequency.
class Fps {
public:
static constexpr Fps fromPeriodNsecs(nsecs_t period) { return Fps(1e9f / period, period); }
diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
index 3f833f4890..da04202ef2 100644
--- a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
+++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
@@ -30,6 +30,7 @@ namespace android::frametimeline {
using base::StringAppendF;
using FrameTimelineEvent = perfetto::protos::pbzero::FrameTimelineEvent;
+using FrameTimelineDataSource = impl::FrameTimeline::FrameTimelineDataSource;
void dumpTable(std::string& result, TimelineItem predictions, TimelineItem actuals,
const std::string& indent, PredictionState predictionState, nsecs_t baseTime) {
@@ -305,11 +306,17 @@ void SurfaceFrame::setActualQueueTime(nsecs_t actualQueueTime) {
std::scoped_lock lock(mMutex);
mActualQueueTime = actualQueueTime;
}
+
void SurfaceFrame::setAcquireFenceTime(nsecs_t acquireFenceTime) {
std::scoped_lock lock(mMutex);
mActuals.endTime = std::max(acquireFenceTime, mActualQueueTime);
}
+void SurfaceFrame::setDropTime(nsecs_t dropTime) {
+ std::scoped_lock lock(mMutex);
+ mDropTime = dropTime;
+}
+
void SurfaceFrame::setPresentState(PresentState presentState, nsecs_t lastLatchTime) {
std::scoped_lock lock(mMutex);
LOG_ALWAYS_FATAL_IF(mPresentState != PresentState::Unknown,
@@ -320,9 +327,19 @@ void SurfaceFrame::setPresentState(PresentState presentState, nsecs_t lastLatchT
mLastLatchTime = lastLatchTime;
}
+void SurfaceFrame::setRenderRate(Fps renderRate) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ mRenderRate = renderRate;
+}
+
std::optional<int32_t> SurfaceFrame::getJankType() const {
std::scoped_lock lock(mMutex);
+ if (mPresentState == PresentState::Dropped) {
+ // Return no jank if it's a dropped frame since we cannot attribute a jank to a it.
+ return JankType::None;
+ }
if (mActuals.presentTime == 0) {
+ // Frame hasn't been presented yet.
return std::nullopt;
}
return mJankType;
@@ -338,6 +355,11 @@ TimelineItem SurfaceFrame::getActuals() const {
return mActuals;
}
+PredictionState SurfaceFrame::getPredictionState() const {
+ std::scoped_lock lock(mMutex);
+ return mPredictionState;
+}
+
SurfaceFrame::PresentState SurfaceFrame::getPresentState() const {
std::scoped_lock lock(mMutex);
return mPresentState;
@@ -353,6 +375,11 @@ FrameReadyMetadata SurfaceFrame::getFrameReadyMetadata() const {
return mFrameReadyMetadata;
}
+nsecs_t SurfaceFrame::getDropTime() const {
+ std::scoped_lock lock(mMutex);
+ return mDropTime;
+}
+
void SurfaceFrame::dump(std::string& result, const std::string& indent, nsecs_t baseTime) const {
std::scoped_lock lock(mMutex);
StringAppendF(&result, "%s", indent.c_str());
@@ -367,8 +394,17 @@ void SurfaceFrame::dump(std::string& result, const std::string& indent, nsecs_t
StringAppendF(&result, "%s", indent.c_str());
StringAppendF(&result, "Owner Pid : %d\n", mOwnerPid);
StringAppendF(&result, "%s", indent.c_str());
+ StringAppendF(&result, "Scheduled rendering rate: %d fps\n",
+ mRenderRate ? mRenderRate->getIntValue() : 0);
+ StringAppendF(&result, "%s", indent.c_str());
StringAppendF(&result, "Present State : %s\n", toString(mPresentState).c_str());
StringAppendF(&result, "%s", indent.c_str());
+ if (mPresentState == PresentState::Dropped) {
+ std::chrono::nanoseconds dropTime(mDropTime - baseTime);
+ StringAppendF(&result, "Drop time : %10f\n",
+ std::chrono::duration<double, std::milli>(dropTime).count());
+ StringAppendF(&result, "%s", indent.c_str());
+ }
StringAppendF(&result, "Prediction State : %s\n", toString(mPredictionState).c_str());
StringAppendF(&result, "%s", indent.c_str());
StringAppendF(&result, "Jank Type : %s\n", jankTypeBitmaskToString(mJankType).c_str());
@@ -391,9 +427,10 @@ void SurfaceFrame::dump(std::string& result, const std::string& indent, nsecs_t
dumpTable(result, mPredictions, mActuals, indent, mPredictionState, baseTime);
}
-void SurfaceFrame::onPresent(nsecs_t presentTime, int32_t displayFrameJankType,
- nsecs_t vsyncPeriod) {
+void SurfaceFrame::onPresent(nsecs_t presentTime, int32_t displayFrameJankType, Fps refreshRate,
+ nsecs_t displayDeadlineDelta, nsecs_t displayPresentDelta) {
std::scoped_lock lock(mMutex);
+
if (mPresentState != PresentState::Presented) {
// No need to update dropped buffers
return;
@@ -412,13 +449,16 @@ void SurfaceFrame::onPresent(nsecs_t presentTime, int32_t displayFrameJankType,
mJankType = JankType::Unknown;
mFramePresentMetadata = FramePresentMetadata::UnknownPresent;
mFrameReadyMetadata = FrameReadyMetadata::UnknownFinish;
- mTimeStats->incrementJankyFrames(mOwnerUid, mLayerName, mJankType);
+ const constexpr nsecs_t kAppDeadlineDelta = -1;
+ mTimeStats->incrementJankyFrames({refreshRate, mRenderRate, mOwnerUid, mLayerName,
+ mJankType, displayDeadlineDelta, displayPresentDelta,
+ kAppDeadlineDelta});
return;
}
const nsecs_t presentDelta = mActuals.presentTime - mPredictions.presentTime;
const nsecs_t deadlineDelta = mActuals.endTime - mPredictions.endTime;
- const nsecs_t deltaToVsync = std::abs(presentDelta) % vsyncPeriod;
+ const nsecs_t deltaToVsync = std::abs(presentDelta) % refreshRate.getPeriodNsecs();
if (deadlineDelta > mJankClassificationThresholds.deadlineThreshold) {
mFrameReadyMetadata = FrameReadyMetadata::LateFinish;
@@ -440,7 +480,8 @@ void SurfaceFrame::onPresent(nsecs_t presentTime, int32_t displayFrameJankType,
if (mFrameReadyMetadata == FrameReadyMetadata::OnTimeFinish) {
// Finish on time, Present early
if (deltaToVsync < mJankClassificationThresholds.presentThreshold ||
- deltaToVsync >= vsyncPeriod - mJankClassificationThresholds.presentThreshold) {
+ deltaToVsync >= refreshRate.getPeriodNsecs() -
+ mJankClassificationThresholds.presentThreshold) {
// Delta factor of vsync
mJankType = JankType::SurfaceFlingerScheduling;
} else {
@@ -463,7 +504,8 @@ void SurfaceFrame::onPresent(nsecs_t presentTime, int32_t displayFrameJankType,
mJankType |= displayFrameJankType;
} else {
if (deltaToVsync < mJankClassificationThresholds.presentThreshold ||
- deltaToVsync >= vsyncPeriod - mJankClassificationThresholds.presentThreshold) {
+ deltaToVsync >= refreshRate.getPeriodNsecs() -
+ mJankClassificationThresholds.presentThreshold) {
// Delta factor of vsync
mJankType |= JankType::SurfaceFlingerScheduling;
} else {
@@ -482,30 +524,16 @@ void SurfaceFrame::onPresent(nsecs_t presentTime, int32_t displayFrameJankType,
}
}
}
- mTimeStats->incrementJankyFrames(mOwnerUid, mLayerName, mJankType);
+ mTimeStats->incrementJankyFrames({refreshRate, mRenderRate, mOwnerUid, mLayerName, mJankType,
+ displayDeadlineDelta, displayPresentDelta, deadlineDelta});
}
-/**
- * TODO(b/178637512): add inputEventId to the perfetto trace.
- */
-void SurfaceFrame::trace(int64_t displayFrameToken) {
- using FrameTimelineDataSource = impl::FrameTimeline::FrameTimelineDataSource;
-
+void SurfaceFrame::tracePredictions(int64_t displayFrameToken) const {
int64_t expectedTimelineCookie = mTraceCookieCounter.getCookieForTracing();
- bool missingToken = false;
+
// Expected timeline start
FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) {
std::scoped_lock lock(mMutex);
- if (mToken == FrameTimelineInfo::INVALID_VSYNC_ID) {
- ALOGD("Cannot trace SurfaceFrame - %s with invalid token", mLayerName.c_str());
- missingToken = true;
- return;
- } else if (displayFrameToken == FrameTimelineInfo::INVALID_VSYNC_ID) {
- ALOGD("Cannot trace SurfaceFrame - %s with invalid displayFrameToken",
- mLayerName.c_str());
- missingToken = true;
- return;
- }
auto packet = ctx.NewTracePacket();
packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_MONOTONIC);
packet->set_timestamp(static_cast<uint64_t>(mPredictions.startTime));
@@ -522,12 +550,6 @@ void SurfaceFrame::trace(int64_t displayFrameToken) {
expectedSurfaceFrameStartEvent->set_layer_name(mDebugName);
});
- if (missingToken) {
- // If one packet can't be traced because of missing token, then no packets can be traced.
- // Exit early in this case.
- return;
- }
-
// Expected timeline end
FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) {
std::scoped_lock lock(mMutex);
@@ -540,15 +562,26 @@ void SurfaceFrame::trace(int64_t displayFrameToken) {
expectedSurfaceFrameEndEvent->set_cookie(expectedTimelineCookie);
});
+}
+void SurfaceFrame::traceActuals(int64_t displayFrameToken) const {
int64_t actualTimelineCookie = mTraceCookieCounter.getCookieForTracing();
+
// Actual timeline start
FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) {
std::scoped_lock lock(mMutex);
auto packet = ctx.NewTracePacket();
packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_MONOTONIC);
// Actual start time is not yet available, so use expected start instead
- packet->set_timestamp(static_cast<uint64_t>(mPredictions.startTime));
+ if (mPredictionState == PredictionState::Expired) {
+ // If prediction is expired, we can't use the predicted start time. Instead, just use a
+ // start time a little earlier than the end time so that we have some info about this
+ // frame in the trace.
+ packet->set_timestamp(
+ static_cast<uint64_t>(mActuals.endTime - kPredictionExpiredStartTimeDelta));
+ } else {
+ packet->set_timestamp(static_cast<uint64_t>(mPredictions.startTime));
+ }
auto* event = packet->set_frame_timeline_event();
auto* actualSurfaceFrameStartEvent = event->set_actual_surface_frame_start();
@@ -573,12 +606,17 @@ void SurfaceFrame::trace(int64_t displayFrameToken) {
actualSurfaceFrameStartEvent->set_gpu_composition(mGpuComposition);
actualSurfaceFrameStartEvent->set_jank_type(jankTypeBitmaskToProto(mJankType));
});
+
// Actual timeline end
FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) {
std::scoped_lock lock(mMutex);
auto packet = ctx.NewTracePacket();
packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_MONOTONIC);
- packet->set_timestamp(static_cast<uint64_t>(mActuals.endTime));
+ if (mPresentState == PresentState::Dropped) {
+ packet->set_timestamp(static_cast<uint64_t>(mDropTime));
+ } else {
+ packet->set_timestamp(static_cast<uint64_t>(mActuals.endTime));
+ }
auto* event = packet->set_frame_timeline_event();
auto* actualSurfaceFrameEndEvent = event->set_frame_end();
@@ -587,6 +625,23 @@ void SurfaceFrame::trace(int64_t displayFrameToken) {
});
}
+/**
+ * TODO(b/178637512): add inputEventId to the perfetto trace.
+ */
+void SurfaceFrame::trace(int64_t displayFrameToken) const {
+ if (mToken == FrameTimelineInfo::INVALID_VSYNC_ID ||
+ displayFrameToken == FrameTimelineInfo::INVALID_VSYNC_ID) {
+ // No packets can be traced with a missing token.
+ return;
+ }
+ if (getPredictionState() != PredictionState::Expired) {
+ // Expired predictions have zeroed timestamps. This cannot be used in any meaningful way in
+ // a trace.
+ tracePredictions(displayFrameToken);
+ }
+ traceActuals(displayFrameToken);
+}
+
namespace impl {
int64_t TokenManager::generateTokenForPredictions(TimelineItem&& predictions) {
@@ -684,10 +739,10 @@ void FrameTimeline::addSurfaceFrame(std::shared_ptr<SurfaceFrame> surfaceFrame)
mCurrentDisplayFrame->addSurfaceFrame(surfaceFrame);
}
-void FrameTimeline::setSfWakeUp(int64_t token, nsecs_t wakeUpTime, nsecs_t vsyncPeriod) {
+void FrameTimeline::setSfWakeUp(int64_t token, nsecs_t wakeUpTime, Fps refreshRate) {
ATRACE_CALL();
std::scoped_lock lock(mMutex);
- mCurrentDisplayFrame->onSfWakeUp(token, vsyncPeriod,
+ mCurrentDisplayFrame->onSfWakeUp(token, refreshRate,
mTokenManager.getPredictionsForToken(token), wakeUpTime);
}
@@ -705,11 +760,11 @@ void FrameTimeline::DisplayFrame::addSurfaceFrame(std::shared_ptr<SurfaceFrame>
mSurfaceFrames.push_back(surfaceFrame);
}
-void FrameTimeline::DisplayFrame::onSfWakeUp(int64_t token, nsecs_t vsyncPeriod,
+void FrameTimeline::DisplayFrame::onSfWakeUp(int64_t token, Fps refreshRate,
std::optional<TimelineItem> predictions,
nsecs_t wakeUpTime) {
mToken = token;
- mVsyncPeriod = vsyncPeriod;
+ mRefreshRate = refreshRate;
if (!predictions) {
mPredictionState = PredictionState::Expired;
} else {
@@ -719,11 +774,6 @@ void FrameTimeline::DisplayFrame::onSfWakeUp(int64_t token, nsecs_t vsyncPeriod,
mSurfaceFlingerActuals.startTime = wakeUpTime;
}
-void FrameTimeline::DisplayFrame::setTokenAndVsyncPeriod(int64_t token, nsecs_t vsyncPeriod) {
- mToken = token;
- mVsyncPeriod = vsyncPeriod;
-}
-
void FrameTimeline::DisplayFrame::setPredictions(PredictionState predictionState,
TimelineItem predictions) {
mPredictionState = predictionState;
@@ -740,14 +790,21 @@ void FrameTimeline::DisplayFrame::setActualEndTime(nsecs_t actualEndTime) {
void FrameTimeline::DisplayFrame::onPresent(nsecs_t signalTime) {
mSurfaceFlingerActuals.presentTime = signalTime;
- int32_t totalJankReasons = JankType::None;
+ if (mPredictionState == PredictionState::Expired) {
+ // Cannot do jank classification with expired predictions
+ mJankType = JankType::Unknown;
+ return;
+ }
// Delta between the expected present and the actual present
const nsecs_t presentDelta =
mSurfaceFlingerActuals.presentTime - mSurfaceFlingerPredictions.presentTime;
+ const nsecs_t deadlineDelta =
+ mSurfaceFlingerActuals.endTime - mSurfaceFlingerPredictions.endTime;
+
// How far off was the presentDelta when compared to the vsyncPeriod. Used in checking if there
// was a prediction error or not.
- nsecs_t deltaToVsync = std::abs(presentDelta) % mVsyncPeriod;
+ nsecs_t deltaToVsync = std::abs(presentDelta) % mRefreshRate.getPeriodNsecs();
if (std::abs(presentDelta) > mJankClassificationThresholds.presentThreshold) {
mFramePresentMetadata = presentDelta > 0 ? FramePresentMetadata::LatePresent
: FramePresentMetadata::EarlyPresent;
@@ -776,8 +833,8 @@ void FrameTimeline::DisplayFrame::onPresent(nsecs_t signalTime) {
if (mFrameReadyMetadata == FrameReadyMetadata::OnTimeFinish) {
// Finish on time, Present early
if (deltaToVsync < mJankClassificationThresholds.presentThreshold ||
- deltaToVsync >=
- (mVsyncPeriod - mJankClassificationThresholds.presentThreshold)) {
+ deltaToVsync >= (mRefreshRate.getPeriodNsecs() -
+ mJankClassificationThresholds.presentThreshold)) {
// Delta is a factor of vsync if its within the presentTheshold on either side
// of the vsyncPeriod. Example: 0-2ms and 9-11ms are both within the threshold
// of the vsyncPeriod if the threshold was 2ms and the vsyncPeriod was 11ms.
@@ -797,8 +854,8 @@ void FrameTimeline::DisplayFrame::onPresent(nsecs_t signalTime) {
if (mFrameReadyMetadata == FrameReadyMetadata::OnTimeFinish) {
// Finish on time, Present late
if (deltaToVsync < mJankClassificationThresholds.presentThreshold ||
- deltaToVsync >=
- (mVsyncPeriod - mJankClassificationThresholds.presentThreshold)) {
+ deltaToVsync >= (mRefreshRate.getPeriodNsecs() -
+ mJankClassificationThresholds.presentThreshold)) {
// Delta is a factor of vsync if its within the presentTheshold on either side
// of the vsyncPeriod. Example: 0-2ms and 9-11ms are both within the threshold
// of the vsyncPeriod if the threshold was 2ms and the vsyncPeriod was 11ms.
@@ -819,29 +876,17 @@ void FrameTimeline::DisplayFrame::onPresent(nsecs_t signalTime) {
mJankType = JankType::Unknown;
}
}
- totalJankReasons |= mJankType;
-
for (auto& surfaceFrame : mSurfaceFrames) {
- surfaceFrame->onPresent(signalTime, mJankType, mVsyncPeriod);
- auto surfaceFrameJankType = surfaceFrame->getJankType();
- if (surfaceFrameJankType != std::nullopt) {
- totalJankReasons |= *surfaceFrameJankType;
- }
+ surfaceFrame->onPresent(signalTime, mJankType, mRefreshRate, deadlineDelta, deltaToVsync);
}
- mTimeStats->incrementJankyFrames(totalJankReasons);
}
-void FrameTimeline::DisplayFrame::trace(pid_t surfaceFlingerPid) const {
+void FrameTimeline::DisplayFrame::tracePredictions(pid_t surfaceFlingerPid) const {
int64_t expectedTimelineCookie = mTraceCookieCounter.getCookieForTracing();
- bool missingToken = false;
+
// Expected timeline start
FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) {
auto packet = ctx.NewTracePacket();
- if (mToken == FrameTimelineInfo::INVALID_VSYNC_ID) {
- ALOGD("Cannot trace DisplayFrame with invalid token");
- missingToken = true;
- return;
- }
packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_MONOTONIC);
packet->set_timestamp(static_cast<uint64_t>(mSurfaceFlingerPredictions.startTime));
@@ -854,12 +899,6 @@ void FrameTimeline::DisplayFrame::trace(pid_t surfaceFlingerPid) const {
expectedDisplayFrameStartEvent->set_pid(surfaceFlingerPid);
});
- if (missingToken) {
- // If one packet can't be traced because of missing token, then no packets can be traced.
- // Exit early in this case.
- return;
- }
-
// Expected timeline end
FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) {
auto packet = ctx.NewTracePacket();
@@ -871,9 +910,12 @@ void FrameTimeline::DisplayFrame::trace(pid_t surfaceFlingerPid) const {
expectedDisplayFrameEndEvent->set_cookie(expectedTimelineCookie);
});
+}
+void FrameTimeline::DisplayFrame::traceActuals(pid_t surfaceFlingerPid) const {
int64_t actualTimelineCookie = mTraceCookieCounter.getCookieForTracing();
- // Expected timeline start
+
+ // Actual timeline start
FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) {
auto packet = ctx.NewTracePacket();
packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_MONOTONIC);
@@ -893,7 +935,8 @@ void FrameTimeline::DisplayFrame::trace(pid_t surfaceFlingerPid) const {
actualDisplayFrameStartEvent->set_gpu_composition(mGpuComposition);
actualDisplayFrameStartEvent->set_jank_type(jankTypeBitmaskToProto(mJankType));
});
- // Expected timeline end
+
+ // Actual timeline end
FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) {
auto packet = ctx.NewTracePacket();
packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_MONOTONIC);
@@ -904,6 +947,21 @@ void FrameTimeline::DisplayFrame::trace(pid_t surfaceFlingerPid) const {
actualDisplayFrameEndEvent->set_cookie(actualTimelineCookie);
});
+}
+
+void FrameTimeline::DisplayFrame::trace(pid_t surfaceFlingerPid) const {
+ if (mToken == FrameTimelineInfo::INVALID_VSYNC_ID) {
+ // DisplayFrame should not have an invalid token.
+ ALOGE("Cannot trace DisplayFrame with invalid token");
+ return;
+ }
+
+ if (mPredictionState == PredictionState::Valid) {
+ // Expired and unknown predictions have zeroed timestamps. This cannot be used in any
+ // meaningful way in a trace.
+ tracePredictions(surfaceFlingerPid);
+ }
+ traceActuals(surfaceFlingerPid);
for (auto& surfaceFrame : mSurfaceFrames) {
surfaceFrame->trace(mToken);
@@ -988,7 +1046,7 @@ void FrameTimeline::DisplayFrame::dump(std::string& result, nsecs_t baseTime) co
StringAppendF(&result, "Present Metadata : %s\n", toString(mFramePresentMetadata).c_str());
StringAppendF(&result, "Finish Metadata: %s\n", toString(mFrameReadyMetadata).c_str());
StringAppendF(&result, "Start Metadata: %s\n", toString(mFrameStartMetadata).c_str());
- std::chrono::nanoseconds vsyncPeriod(mVsyncPeriod);
+ std::chrono::nanoseconds vsyncPeriod(mRefreshRate.getPeriodNsecs());
StringAppendF(&result, "Vsync Period: %10f\n",
std::chrono::duration<double, std::milli>(vsyncPeriod).count());
nsecs_t presentDelta =
@@ -996,7 +1054,7 @@ void FrameTimeline::DisplayFrame::dump(std::string& result, nsecs_t baseTime) co
std::chrono::nanoseconds presentDeltaNs(std::abs(presentDelta));
StringAppendF(&result, "Present delta: %10f\n",
std::chrono::duration<double, std::milli>(presentDeltaNs).count());
- std::chrono::nanoseconds deltaToVsync(std::abs(presentDelta) % mVsyncPeriod);
+ std::chrono::nanoseconds deltaToVsync(std::abs(presentDelta) % mRefreshRate.getPeriodNsecs());
StringAppendF(&result, "Present delta %% refreshrate: %10f\n",
std::chrono::duration<double, std::milli>(deltaToVsync).count());
dumpTable(result, mSurfaceFlingerPredictions, mSurfaceFlingerActuals, "", mPredictionState,
diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.h b/services/surfaceflinger/FrameTimeline/FrameTimeline.h
index 54e8efbc92..8f3157d80c 100644
--- a/services/surfaceflinger/FrameTimeline/FrameTimeline.h
+++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.h
@@ -16,6 +16,7 @@
#pragma once
+#include <../Fps.h>
#include <../TimeStats/TimeStats.h>
#include <gui/ISurfaceComposer.h>
#include <gui/JankInfo.h>
@@ -170,34 +171,50 @@ public:
TimelineItem getPredictions() const { return mPredictions; };
// Actual timestamps of the app are set individually at different functions.
// Start time (if the app provides) and Queue time are accessible after queueing the frame,
- // whereas Acquire Fence time is available only during latch.
+ // whereas Acquire Fence time is available only during latch. Drop time is available at the time
+ // the buffer was dropped.
void setActualStartTime(nsecs_t actualStartTime);
void setActualQueueTime(nsecs_t actualQueueTime);
void setAcquireFenceTime(nsecs_t acquireFenceTime);
+ void setDropTime(nsecs_t dropTime);
void setPresentState(PresentState presentState, nsecs_t lastLatchTime = 0);
+ void setRenderRate(Fps renderRate);
// Functions called by FrameTimeline
// BaseTime is the smallest timestamp in this SurfaceFrame.
// Used for dumping all timestamps relative to the oldest, making it easy to read.
nsecs_t getBaseTime() const;
// Sets the actual present time, appropriate metadata and classifies the jank.
- void onPresent(nsecs_t presentTime, int32_t displayFrameJankType, nsecs_t vsyncPeriod);
+ // displayRefreshRate, displayDeadlineDelta, and displayPresentDelta are propagated from the
+ // display frame.
+ void onPresent(nsecs_t presentTime, int32_t displayFrameJankType, Fps refreshRate,
+ nsecs_t displayDeadlineDelta, nsecs_t displayPresentDelta);
// All the timestamps are dumped relative to the baseTime
void dump(std::string& result, const std::string& indent, nsecs_t baseTime) const;
// Emits a packet for perfetto tracing. The function body will be executed only if tracing is
// enabled. The displayFrameToken is needed to link the SurfaceFrame to the corresponding
// DisplayFrame at the trace processor side.
- void trace(int64_t displayFrameToken);
+ void trace(int64_t displayFrameToken) const;
- // Getter functions used only by FrameTimelineTests
+ // Getter functions used only by FrameTimelineTests and SurfaceFrame internally
TimelineItem getActuals() const;
pid_t getOwnerPid() const { return mOwnerPid; };
- PredictionState getPredictionState() const { return mPredictionState; };
+ PredictionState getPredictionState() const;
PresentState getPresentState() const;
FrameReadyMetadata getFrameReadyMetadata() const;
FramePresentMetadata getFramePresentMetadata() const;
+ nsecs_t getDropTime() const;
+
+ // For prediction expired frames, this delta is subtracted from the actual end time to get a
+ // start time decent enough to see in traces.
+ // TODO(b/172587309): Remove this when we have actual start times.
+ static constexpr nsecs_t kPredictionExpiredStartTimeDelta =
+ std::chrono::duration_cast<std::chrono::nanoseconds>(2ms).count();
private:
+ void tracePredictions(int64_t displayFrameToken) const;
+ void traceActuals(int64_t displayFrameToken) const;
+
const int64_t mToken;
const int32_t mInputEventId;
const pid_t mOwnerPid;
@@ -211,11 +228,14 @@ private:
std::shared_ptr<TimeStats> mTimeStats;
const JankClassificationThresholds mJankClassificationThresholds;
nsecs_t mActualQueueTime GUARDED_BY(mMutex) = 0;
+ nsecs_t mDropTime GUARDED_BY(mMutex) = 0;
mutable std::mutex mMutex;
// Bitmask for the type of jank
int32_t mJankType GUARDED_BY(mMutex) = JankType::None;
// Indicates if this frame was composited by the GPU or not
bool mGpuComposition GUARDED_BY(mMutex) = false;
+ // Rendering rate for this frame.
+ std::optional<Fps> mRenderRate GUARDED_BY(mMutex);
// Enum for the type of present
FramePresentMetadata mFramePresentMetadata GUARDED_BY(mMutex) =
FramePresentMetadata::UnknownPresent;
@@ -255,7 +275,7 @@ public:
// The first function called by SF for the current DisplayFrame. Fetches SF predictions based on
// the token and sets the actualSfWakeTime for the current DisplayFrame.
- virtual void setSfWakeUp(int64_t token, nsecs_t wakeupTime, nsecs_t vsyncPeriod) = 0;
+ virtual void setSfWakeUp(int64_t token, nsecs_t wakeupTime, Fps refreshRate) = 0;
// Sets the sfPresentTime and finalizes the current DisplayFrame. Tracks the given present fence
// until it's signaled, and updates the present timestamps of all presented SurfaceFrames in
@@ -325,14 +345,13 @@ public:
// is enabled.
void trace(pid_t surfaceFlingerPid) const;
// Sets the token, vsyncPeriod, predictions and SF start time.
- void onSfWakeUp(int64_t token, nsecs_t vsyncPeriod, std::optional<TimelineItem> predictions,
+ void onSfWakeUp(int64_t token, Fps refreshRate, std::optional<TimelineItem> predictions,
nsecs_t wakeUpTime);
// Sets the appropriate metadata, classifies the jank and returns the classified jankType.
void onPresent(nsecs_t signalTime);
// Adds the provided SurfaceFrame to the current display frame.
void addSurfaceFrame(std::shared_ptr<SurfaceFrame> surfaceFrame);
- void setTokenAndVsyncPeriod(int64_t token, nsecs_t vsyncPeriod);
void setPredictions(PredictionState predictionState, TimelineItem predictions);
void setActualStartTime(nsecs_t actualStartTime);
void setActualEndTime(nsecs_t actualEndTime);
@@ -353,6 +372,8 @@ public:
private:
void dump(std::string& result, nsecs_t baseTime) const;
+ void tracePredictions(pid_t surfaceFlingerPid) const;
+ void traceActuals(pid_t surfaceFlingerPid) const;
int64_t mToken = FrameTimelineInfo::INVALID_VSYNC_ID;
@@ -382,7 +403,7 @@ public:
FrameStartMetadata mFrameStartMetadata = FrameStartMetadata::UnknownStart;
// The refresh rate (vsync period) in nanoseconds as seen by SF during this DisplayFrame's
// timeline
- nsecs_t mVsyncPeriod = 0;
+ Fps mRefreshRate;
// TraceCookieCounter is used to obtain the cookie for sendig trace packets to perfetto.
// Using a reference here because the counter is owned by FrameTimeline, which outlives
// DisplayFrame.
@@ -398,7 +419,7 @@ public:
const FrameTimelineInfo& frameTimelineInfo, pid_t ownerPid, uid_t ownerUid,
std::string layerName, std::string debugName) override;
void addSurfaceFrame(std::shared_ptr<frametimeline::SurfaceFrame> surfaceFrame) override;
- void setSfWakeUp(int64_t token, nsecs_t wakeupTime, nsecs_t vsyncPeriod) override;
+ void setSfWakeUp(int64_t token, nsecs_t wakeupTime, Fps refreshRate) override;
void setSfPresent(nsecs_t sfPresentTime,
const std::shared_ptr<FenceTime>& presentFence) override;
void parseArgs(const Vector<String16>& args, std::string& result) override;
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index df14003c75..141a112af1 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -25,6 +25,7 @@
#include "Layer.h"
+#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <android/native_window.h>
#include <binder/IPCThreadState.h>
@@ -488,6 +489,7 @@ void Layer::prepareBasicGeometryCompositionState() {
compositionState->alpha = alpha;
compositionState->backgroundBlurRadius = drawingState.backgroundBlurRadius;
compositionState->blurRegions = drawingState.blurRegions;
+ compositionState->stretchEffect = getStretchEffect();
}
void Layer::prepareGeometryCompositionState() {
@@ -556,8 +558,8 @@ void Layer::preparePerFrameCompositionState() {
isOpaque(drawingState) && !usesRoundedCorners && getAlpha() == 1.0_hf;
// Force client composition for special cases known only to the front-end.
- if (isHdrY410() || usesRoundedCorners || drawShadows() ||
- getDrawingState().blurRegions.size() > 0) {
+ if (isHdrY410() || usesRoundedCorners || drawShadows() || drawingState.blurRegions.size() > 0 ||
+ compositionState->stretchEffect.hasEffect()) {
compositionState->forceClientComposition = true;
}
}
@@ -656,6 +658,7 @@ std::optional<compositionengine::LayerFE::LayerSettings> Layer::prepareClientCom
layerSettings.backgroundBlurRadius = getBackgroundBlurRadius();
layerSettings.blurRegions = getBlurRegions();
}
+ layerSettings.stretchEffect = getDrawingState().stretchEffect;
// Record the name of the layer for debugging further down the stack.
layerSettings.name = getName();
return layerSettings;
@@ -867,9 +870,7 @@ void Layer::mergeSurfaceFrames(State& source, State& target) {
void Layer::popPendingState(State* stateToCommit) {
ATRACE_CALL();
- if (stateToCommit != nullptr) {
- mergeSurfaceFrames(*stateToCommit, mPendingStates[0]);
- }
+ mergeSurfaceFrames(*stateToCommit, mPendingStates[0]);
*stateToCommit = mPendingStates[0];
mPendingStates.pop_front();
ATRACE_INT(mTransactionName.c_str(), mPendingStates.size());
@@ -1423,6 +1424,35 @@ bool Layer::setFixedTransformHint(ui::Transform::RotationFlags fixedTransformHin
return true;
}
+bool Layer::setStretchEffect(const StretchEffect& effect) {
+ StretchEffect temp = effect;
+ temp.sanitize();
+ if (mCurrentState.stretchEffect == temp) {
+ return false;
+ }
+ mCurrentState.sequence++;
+ mCurrentState.stretchEffect = temp;
+ mCurrentState.modified = true;
+ setTransactionFlags(eTransactionNeeded);
+ return true;
+}
+
+StretchEffect Layer::getStretchEffect() const {
+ if (mDrawingState.stretchEffect.hasEffect()) {
+ return mDrawingState.stretchEffect;
+ }
+
+ sp<Layer> parent = getParent();
+ if (parent != nullptr) {
+ auto effect = parent->getStretchEffect();
+ if (effect.hasEffect()) {
+ // TODO(b/179047472): Map it? Or do we make the effect be in global space?
+ return effect;
+ }
+ }
+ return StretchEffect{};
+}
+
void Layer::updateTreeHasFrameRateVote() {
const auto traverseTree = [&](const LayerVector::Visitor& visitor) {
auto parent = getParent();
@@ -1438,7 +1468,7 @@ void Layer::updateTreeHasFrameRateVote() {
// First traverse the tree and count how many layers has votes. In addition
// activate the layers in Scheduler's LayerHistory for it to check for changes
int layersWithVote = 0;
- traverseTree([&layersWithVote, this](Layer* layer) {
+ traverseTree([&layersWithVote](Layer* layer) {
const auto layerVotedWithDefaultCompatibility =
layer->mCurrentState.frameRate.rate.isValid() &&
layer->mCurrentState.frameRate.type == FrameRateCompatibility::Default;
@@ -1454,20 +1484,21 @@ void Layer::updateTreeHasFrameRateVote() {
layerVotedWithExactCompatibility) {
layersWithVote++;
}
-
- mFlinger->mScheduler->recordLayerHistory(layer, systemTime(),
- LayerHistory::LayerUpdateType::SetFrameRate);
});
// Now update the other layers
bool transactionNeeded = false;
- traverseTree([layersWithVote, &transactionNeeded](Layer* layer) {
- if (layer->mCurrentState.treeHasFrameRateVote != layersWithVote > 0) {
+ traverseTree([layersWithVote, &transactionNeeded, this](Layer* layer) {
+ const bool treeHasFrameRateVote = layersWithVote > 0;
+ if (layer->mCurrentState.treeHasFrameRateVote != treeHasFrameRateVote) {
layer->mCurrentState.sequence++;
- layer->mCurrentState.treeHasFrameRateVote = layersWithVote > 0;
+ layer->mCurrentState.treeHasFrameRateVote = treeHasFrameRateVote;
layer->mCurrentState.modified = true;
layer->setTransactionFlags(eTransactionNeeded);
transactionNeeded = true;
+
+ mFlinger->mScheduler->recordLayerHistory(layer, systemTime(),
+ LayerHistory::LayerUpdateType::SetFrameRate);
}
});
@@ -1547,6 +1578,7 @@ void Layer::setFrameTimelineVsyncForBufferlessTransaction(const FrameTimelineInf
void Layer::addSurfaceFrameDroppedForBuffer(
std::shared_ptr<frametimeline::SurfaceFrame>& surfaceFrame) {
+ surfaceFrame->setDropTime(systemTime());
surfaceFrame->setPresentState(PresentState::Dropped);
mFlinger->mFrameTimeline->addSurfaceFrame(surfaceFrame);
}
@@ -1568,6 +1600,10 @@ std::shared_ptr<frametimeline::SurfaceFrame> Layer::createSurfaceFrameForTransac
// For Transactions, the post time is considered to be both queue and acquire fence time.
surfaceFrame->setActualQueueTime(postTime);
surfaceFrame->setAcquireFenceTime(postTime);
+ const auto fps = mFlinger->mScheduler->getFrameRateOverride(getOwnerUid());
+ if (fps) {
+ surfaceFrame->setRenderRate(*fps);
+ }
onSurfaceFrameCreated(surfaceFrame);
return surfaceFrame;
}
@@ -1579,6 +1615,10 @@ std::shared_ptr<frametimeline::SurfaceFrame> Layer::createSurfaceFrameForBuffer(
debugName);
// For buffers, acquire fence time will set during latch.
surfaceFrame->setActualQueueTime(queueTime);
+ const auto fps = mFlinger->mScheduler->getFrameRateOverride(getOwnerUid());
+ if (fps) {
+ surfaceFrame->setRenderRate(*fps);
+ }
// TODO(b/178542907): Implement onSurfaceFrameCreated for BQLayer as well.
onSurfaceFrameCreated(surfaceFrame);
return surfaceFrame;
@@ -1719,6 +1759,7 @@ LayerDebugInfo Layer::getLayerDebugInfo(const DisplayDevice* display) const {
info.mRefreshPending = isBufferLatched();
info.mIsOpaque = isOpaque(ds);
info.mContentDirty = contentDirty;
+ info.mStretchEffect = getStretchEffect();
return info;
}
@@ -2459,7 +2500,7 @@ void Layer::writeToProtoCommonState(LayerProto* layerInfo, LayerVector::StateSet
if (traceFlags & SurfaceTracing::TRACE_INPUT) {
InputWindowInfo info;
if (useDrawing) {
- info = fillInputInfo();
+ info = fillInputInfo({nullptr});
} else {
info = state.inputInfo;
}
@@ -2480,7 +2521,7 @@ bool Layer::isRemovedFromCurrentState() const {
return mRemovedFromCurrentState;
}
-void Layer::fillInputFrameInfo(InputWindowInfo& info) {
+void Layer::fillInputFrameInfo(InputWindowInfo& info, const ui::Transform& toPhysicalDisplay) {
// 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
@@ -2500,9 +2541,13 @@ void Layer::fillInputFrameInfo(InputWindowInfo& info) {
return;
}
- ui::Transform t = getTransform();
+ ui::Transform layerToDisplay = getTransform();
+ // Transform that takes window coordinates to unrotated display coordinates
+ ui::Transform t = toPhysicalDisplay * layerToDisplay;
int32_t xSurfaceInset = info.surfaceInset;
int32_t ySurfaceInset = info.surfaceInset;
+ // Bring screenBounds into unrotated space
+ Rect screenBounds = toPhysicalDisplay.transform(Rect{mScreenBounds});
const float xScale = t.getScaleX();
const float yScale = t.getScaleY();
@@ -2560,7 +2605,6 @@ void Layer::fillInputFrameInfo(InputWindowInfo& info) {
// We need to send the layer bounds cropped to the screenbounds since the layer can be cropped.
// The frame should be the area the user sees on screen since it's used for occlusion
// detection.
- Rect screenBounds = Rect{mScreenBounds};
transformedLayerBounds.intersect(screenBounds, &transformedLayerBounds);
info.frameLeft = transformedLayerBounds.left;
info.frameTop = transformedLayerBounds.top;
@@ -2572,7 +2616,7 @@ void Layer::fillInputFrameInfo(InputWindowInfo& info) {
info.touchableRegion = inputTransform.transform(info.touchableRegion);
}
-InputWindowInfo Layer::fillInputInfo() {
+InputWindowInfo Layer::fillInputInfo(const sp<DisplayDevice>& display) {
if (!hasInputInfo()) {
mDrawingState.inputInfo.name = getName();
mDrawingState.inputInfo.ownerUid = mOwnerUid;
@@ -2589,7 +2633,13 @@ InputWindowInfo Layer::fillInputInfo() {
info.displayId = getLayerStack();
}
- fillInputFrameInfo(info);
+ // Transform that goes from "logical(rotated)" display to physical/unrotated display.
+ // This is for when inputflinger operates in physical display-space.
+ ui::Transform toPhysicalDisplay;
+ if (display) {
+ toPhysicalDisplay = display->getTransform();
+ }
+ fillInputFrameInfo(info, toPhysicalDisplay);
// For compatibility reasons we let layers which can receive input
// receive input before they have actually submitted a buffer. Because
@@ -2605,12 +2655,14 @@ InputWindowInfo Layer::fillInputInfo() {
auto cropLayer = mDrawingState.touchableRegionCrop.promote();
if (info.replaceTouchableRegionWithCrop) {
if (cropLayer == nullptr) {
- info.touchableRegion = Region(Rect{mScreenBounds});
+ info.touchableRegion = Region(toPhysicalDisplay.transform(Rect{mScreenBounds}));
} else {
- info.touchableRegion = Region(Rect{cropLayer->mScreenBounds});
+ info.touchableRegion =
+ Region(toPhysicalDisplay.transform(Rect{cropLayer->mScreenBounds}));
}
} else if (cropLayer != nullptr) {
- info.touchableRegion = info.touchableRegion.intersect(Rect{cropLayer->mScreenBounds});
+ info.touchableRegion = info.touchableRegion.intersect(
+ toPhysicalDisplay.transform(Rect{cropLayer->mScreenBounds}));
}
// If the layer is a clone, we need to crop the input region to cloned root to prevent
@@ -2618,7 +2670,7 @@ InputWindowInfo Layer::fillInputInfo() {
if (isClone()) {
sp<Layer> clonedRoot = getClonedRoot();
if (clonedRoot != nullptr) {
- Rect rect(clonedRoot->mScreenBounds);
+ Rect rect = toPhysicalDisplay.transform(Rect{clonedRoot->mScreenBounds});
info.touchableRegion = info.touchableRegion.intersect(rect);
}
}
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 36ae19cb46..14bb5b71ac 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -32,6 +32,7 @@
#include <ui/GraphicBuffer.h>
#include <ui/PixelFormat.h>
#include <ui/Region.h>
+#include <ui/StretchEffect.h>
#include <ui/Transform.h>
#include <utils/RefBase.h>
#include <utils/Timers.h>
@@ -323,6 +324,9 @@ public:
// An arbitrary threshold for the number of BufferlessSurfaceFrames in the state. Used to
// trigger a warning if the number of SurfaceFrames crosses the threshold.
static constexpr uint32_t kStateSurfaceFramesThreshold = 25;
+
+ // Stretch effect to apply to this layer
+ StretchEffect stretchEffect;
};
/*
@@ -909,7 +913,7 @@ public:
bool getPremultipledAlpha() const;
void setInputInfo(const InputWindowInfo& info);
- InputWindowInfo fillInputInfo();
+ InputWindowInfo fillInputInfo(const sp<DisplayDevice>& display);
/**
* Returns whether this layer has an explicitly set input-info.
*/
@@ -938,6 +942,9 @@ public:
bool backpressureEnabled() { return mDrawingState.flags & layer_state_t::eEnableBackpressure; }
+ bool setStretchEffect(const StretchEffect& effect);
+ StretchEffect getStretchEffect() const;
+
protected:
class SyncPoint {
public:
@@ -1004,6 +1011,7 @@ protected:
friend class TestableSurfaceFlinger;
friend class RefreshRateSelectionTest;
friend class SetFrameRateTest;
+ friend class TransactionFrameTracerTest;
friend class TransactionSurfaceFrameTest;
virtual void setInitialValuesForClone(const sp<Layer>& clonedFrom);
@@ -1138,9 +1146,6 @@ protected:
// Window types from WindowManager.LayoutParams
const InputWindowInfo::Type mWindowType;
- // Can only be accessed with the SF state lock held.
- std::shared_ptr<frametimeline::SurfaceFrame> mSurfaceFrame;
-
// 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.
uid_t mOwnerUid;
@@ -1189,7 +1194,7 @@ private:
sp<Layer> getRootLayer();
// Fills in the frame and transform info for the InputWindowInfo
- void fillInputFrameInfo(InputWindowInfo& info);
+ void fillInputFrameInfo(InputWindowInfo& info, const ui::Transform& toPhysicalDisplay);
// Cached properties computed from drawing state
// Effective transform taking into account parent transforms and any parent scaling, which is
diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp
index 49ffc81359..b29c624d00 100644
--- a/services/surfaceflinger/RefreshRateOverlay.cpp
+++ b/services/surfaceflinger/RefreshRateOverlay.cpp
@@ -125,6 +125,9 @@ std::vector<sp<GraphicBuffer>> RefreshRateOverlay::SevenSegmentDrawer::drawNumbe
GRALLOC_USAGE_SW_WRITE_RARELY | GRALLOC_USAGE_HW_COMPOSER |
GRALLOC_USAGE_HW_TEXTURE,
"RefreshRateOverlayBuffer");
+ const status_t bufferStatus = buffer->initCheck();
+ LOG_ALWAYS_FATAL_IF(bufferStatus != OK, "RefreshRateOverlay: Buffer failed to allocate: %d",
+ bufferStatus);
uint8_t* pixels;
buffer->lock(GRALLOC_USAGE_SW_WRITE_RARELY, reinterpret_cast<void**>(&pixels));
// Clear buffer content
diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp
index 9186538c0a..09615f920d 100644
--- a/services/surfaceflinger/RegionSamplingThread.cpp
+++ b/services/surfaceflinger/RegionSamplingThread.cpp
@@ -447,6 +447,9 @@ void RegionSamplingThread::captureSample() {
GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE;
buffer = new GraphicBuffer(sampledBounds.getWidth(), sampledBounds.getHeight(),
PIXEL_FORMAT_RGBA_8888, 1, usage, "RegionSamplingThread");
+ const status_t bufferStatus = buffer->initCheck();
+ LOG_ALWAYS_FATAL_IF(bufferStatus != OK, "captureSample: Buffer failed to allocate: %d",
+ bufferStatus);
}
const sp<SyncScreenCaptureListener> captureListener = new SyncScreenCaptureListener();
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
index e7a44a70d5..de11c16f64 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
@@ -64,7 +64,7 @@ using AllRefreshRatesMapType = RefreshRateConfigs::AllRefreshRatesMapType;
using RefreshRate = RefreshRateConfigs::RefreshRate;
std::string RefreshRate::toString() const {
- return base::StringPrintf("{id=%zu, hwcId=%d, fps=%.2f, width=%d, height=%d group=%d}",
+ return base::StringPrintf("{id=%d, hwcId=%d, fps=%.2f, width=%d, height=%d group=%d}",
getModeId().value(), mode->getHwcId(), getFps().getValue(),
mode->getWidth(), mode->getHeight(), getModeGroup());
}
@@ -89,7 +89,7 @@ std::string RefreshRateConfigs::layerVoteTypeString(LayerVoteType vote) {
}
std::string RefreshRateConfigs::Policy::toString() const {
- return base::StringPrintf("default mode ID: %zu, allowGroupSwitching = %d"
+ return base::StringPrintf("default mode ID: %d, allowGroupSwitching = %d"
", primary range: %s, app request range: %s",
defaultMode.value(), allowGroupSwitching,
primaryRange.toString().c_str(), appRequestRange.toString().c_str());
@@ -627,6 +627,8 @@ void RefreshRateConfigs::updateDisplayModes(const DisplayModes& modes,
std::vector<const RefreshRate*> sortedModes;
getSortedRefreshRateListLocked([](const RefreshRate&) { return true; }, &sortedModes);
+ // Reset the policy because the old one may no longer be valid.
+ mDisplayManagerPolicy = {};
mDisplayManagerPolicy.defaultMode = currentModeId;
mMinSupportedRefreshRate = sortedModes.front();
mMaxSupportedRefreshRate = sortedModes.back();
@@ -722,7 +724,7 @@ void RefreshRateConfigs::getSortedRefreshRateListLocked(
outRefreshRates->reserve(mRefreshRates.size());
for (const auto& [type, refreshRate] : mRefreshRates) {
if (shouldAddRefreshRate(*refreshRate)) {
- ALOGV("getSortedRefreshRateListLocked: mode %zu added to list policy",
+ ALOGV("getSortedRefreshRateListLocked: mode %d added to list policy",
refreshRate->modeId.value());
outRefreshRates->push_back(refreshRate.get());
}
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 5237516f17..0e9eba731a 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -174,6 +174,8 @@ public:
// Stores the preferred refresh rate that an app should run at.
// FrameRateOverride.refreshRateHz == 0 means no preference.
void setPreferredRefreshRateForUid(FrameRateOverride) EXCLUDES(mFrameRateOverridesMutex);
+ // Retrieves the overridden refresh rate for a given uid.
+ std::optional<Fps> getFrameRateOverride(uid_t uid) const EXCLUDES(mFrameRateOverridesMutex);
private:
friend class TestableScheduler;
@@ -236,7 +238,6 @@ private:
Fps displayRefreshRate) REQUIRES(mFeatureStateLock)
EXCLUDES(mFrameRateOverridesMutex);
- std::optional<Fps> getFrameRateOverride(uid_t uid) const EXCLUDES(mFrameRateOverridesMutex);
impl::EventThread::ThrottleVsyncCallback makeThrottleVsyncCallback() const;
// Stores EventThread associated with a given VSyncSource, and an initial EventThreadConnection.
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 04e9a6d3ff..472dee2d34 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -68,12 +68,13 @@
#include <ui/ColorSpace.h>
#include <ui/DebugUtils.h>
#include <ui/DisplayId.h>
-#include <ui/DisplayInfo.h>
#include <ui/DisplayMode.h>
#include <ui/DisplayStatInfo.h>
#include <ui/DisplayState.h>
+#include <ui/DynamicDisplayInfo.h>
#include <ui/GraphicBufferAllocator.h>
#include <ui/PixelFormat.h>
+#include <ui/StaticDisplayInfo.h>
#include <utils/StopWatch.h>
#include <utils/String16.h>
#include <utils/String8.h>
@@ -854,7 +855,8 @@ status_t SurfaceFlinger::getDisplayState(const sp<IBinder>& displayToken, ui::Di
return NO_ERROR;
}
-status_t SurfaceFlinger::getDisplayInfo(const sp<IBinder>& displayToken, DisplayInfo* info) {
+status_t SurfaceFlinger::getStaticDisplayInfo(const sp<IBinder>& displayToken,
+ ui::StaticDisplayInfo* info) {
if (!displayToken || !info) {
return BAD_VALUE;
}
@@ -875,7 +877,7 @@ status_t SurfaceFlinger::getDisplayInfo(const sp<IBinder>& displayToken, Display
if (mEmulatedDisplayDensity) {
info->density = mEmulatedDisplayDensity;
} else {
- info->density = info->connectionType == DisplayConnectionType::Internal
+ info->density = info->connectionType == ui::DisplayConnectionType::Internal
? mInternalDisplayDensity
: FALLBACK_DENSITY;
}
@@ -887,9 +889,9 @@ status_t SurfaceFlinger::getDisplayInfo(const sp<IBinder>& displayToken, Display
return NO_ERROR;
}
-status_t SurfaceFlinger::getDisplayModes(const sp<IBinder>& displayToken,
- Vector<ui::DisplayMode>* modes) {
- if (!displayToken || !modes) {
+status_t SurfaceFlinger::getDynamicDisplayInfo(const sp<IBinder>& displayToken,
+ ui::DynamicDisplayInfo* info) {
+ if (!displayToken || !info) {
return BAD_VALUE;
}
@@ -900,16 +902,25 @@ status_t SurfaceFlinger::getDisplayModes(const sp<IBinder>& displayToken,
return NAME_NOT_FOUND;
}
- modes->clear();
+ info->activeDisplayModeId = static_cast<int32_t>(display->getActiveMode()->getId().value());
+ if (display->isPrimary()) {
+ if (const auto mode = getDesiredActiveMode()) {
+ info->activeDisplayModeId = static_cast<int32_t>(mode->modeId.value());
+ }
+ }
- for (const auto& supportedMode : display->getSupportedModes()) {
- ui::DisplayMode mode;
+ const auto& supportedModes = display->getSupportedModes();
+ info->supportedDisplayModes.clear();
+ info->supportedDisplayModes.reserve(supportedModes.size());
+ for (const auto& mode : supportedModes) {
+ ui::DisplayMode outMode;
+ outMode.id = static_cast<int32_t>(mode->getId().value());
- auto width = supportedMode->getWidth();
- auto height = supportedMode->getHeight();
+ auto width = mode->getWidth();
+ auto height = mode->getHeight();
- auto xDpi = supportedMode->getDpiX();
- auto yDpi = supportedMode->getDpiY();
+ auto xDpi = mode->getDpiX();
+ auto yDpi = mode->getDpiY();
if (display->isPrimary() &&
(internalDisplayOrientation == ui::ROTATION_90 ||
@@ -918,24 +929,24 @@ status_t SurfaceFlinger::getDisplayModes(const sp<IBinder>& displayToken,
std::swap(xDpi, yDpi);
}
- mode.resolution = ui::Size(width, height);
+ outMode.resolution = ui::Size(width, height);
if (mEmulatedDisplayDensity) {
- mode.xDpi = mEmulatedDisplayDensity;
- mode.yDpi = mEmulatedDisplayDensity;
+ outMode.xDpi = mEmulatedDisplayDensity;
+ outMode.yDpi = mEmulatedDisplayDensity;
} else {
- mode.xDpi = xDpi;
- mode.yDpi = yDpi;
+ outMode.xDpi = xDpi;
+ outMode.yDpi = yDpi;
}
- const nsecs_t period = supportedMode->getVsyncPeriod();
- mode.refreshRate = Fps::fromPeriodNsecs(period).getValue();
+ const nsecs_t period = mode->getVsyncPeriod();
+ outMode.refreshRate = Fps::fromPeriodNsecs(period).getValue();
const auto vsyncConfigSet =
- mVsyncConfiguration->getConfigsForRefreshRate(Fps(mode.refreshRate));
- mode.appVsyncOffset = vsyncConfigSet.late.appOffset;
- mode.sfVsyncOffset = vsyncConfigSet.late.sfOffset;
- mode.group = supportedMode->getGroup();
+ mVsyncConfiguration->getConfigsForRefreshRate(Fps(outMode.refreshRate));
+ outMode.appVsyncOffset = vsyncConfigSet.late.appOffset;
+ outMode.sfVsyncOffset = vsyncConfigSet.late.sfOffset;
+ outMode.group = mode->getGroup();
// This is how far in advance a buffer must be queued for
// presentation at a given time. If you want a buffer to appear
@@ -949,11 +960,24 @@ status_t SurfaceFlinger::getDisplayModes(const sp<IBinder>& displayToken,
//
// We add an additional 1ms to allow for processing time and
// differences between the ideal and actual refresh rate.
- mode.presentationDeadline = period - mode.sfVsyncOffset + 1000000;
+ outMode.presentationDeadline = period - outMode.sfVsyncOffset + 1000000;
- modes->push_back(mode);
+ info->supportedDisplayModes.push_back(outMode);
}
+ info->activeColorMode = display->getCompositionDisplay()->getState().colorMode;
+ const auto displayId = display->getPhysicalId();
+ info->supportedColorModes = getDisplayColorModes(displayId);
+
+ info->hdrCapabilities = display->getHdrCapabilities();
+ info->autoLowLatencyModeSupported =
+ getHwComposer().hasDisplayCapability(displayId,
+ hal::DisplayCapability::AUTO_LOW_LATENCY_MODE);
+ std::vector<hal::ContentType> types;
+ getHwComposer().getSupportedContentTypes(displayId, &types);
+ info->gameContentTypeSupported = std::any_of(types.begin(), types.end(), [](auto type) {
+ return type == hal::ContentType::GAME;
+ });
return NO_ERROR;
}
@@ -966,31 +990,6 @@ status_t SurfaceFlinger::getDisplayStats(const sp<IBinder>&, DisplayStatInfo* st
return NO_ERROR;
}
-int SurfaceFlinger::getActiveDisplayModeId(const sp<IBinder>& displayToken) {
- int activeMode;
- bool isPrimary;
-
- {
- Mutex::Autolock lock(mStateLock);
-
- if (const auto display = getDisplayDeviceLocked(displayToken)) {
- activeMode = display->getActiveMode()->getId().value();
- isPrimary = display->isPrimary();
- } else {
- ALOGE("%s: Invalid display token %p", __FUNCTION__, displayToken.get());
- return NAME_NOT_FOUND;
- }
- }
-
- if (isPrimary) {
- if (const auto mode = getDesiredActiveMode()) {
- return mode->modeId.value();
- }
- }
-
- return activeMode;
-}
-
void SurfaceFlinger::setDesiredActiveMode(const ActiveModeInfo& info) {
ATRACE_CALL();
auto refreshRate = mRefreshRateConfigs->getRefreshRateFromModeId(info.modeId);
@@ -1082,7 +1081,7 @@ void SurfaceFlinger::setActiveModeInternal() {
const auto upcomingMode = display->getMode(mUpcomingActiveMode.modeId);
if (!upcomingMode) {
- ALOGW("Upcoming active mode is no longer supported. Mode ID = %zu",
+ 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.
@@ -1142,13 +1141,13 @@ void SurfaceFlinger::performSetActiveMode() {
const auto display = getDefaultDisplayDeviceLocked();
const auto desiredMode = display->getMode(desiredActiveMode->modeId);
if (!desiredMode) {
- ALOGW("Desired display mode is no longer supported. Mode ID = %zu",
+ 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 %zu(%s)", __FUNCTION__, desiredMode->getId().value(),
+ ALOGV("%s changing active mode to %d(%s)", __FUNCTION__, desiredMode->getId().value(),
to_string(refreshRate).c_str());
if (!display || display->getActiveMode()->getId() == desiredActiveMode->modeId) {
@@ -1190,39 +1189,20 @@ void SurfaceFlinger::performSetActiveMode() {
mSetActiveModePending = true;
}
-status_t SurfaceFlinger::getDisplayColorModes(const sp<IBinder>& displayToken,
- Vector<ColorMode>* outColorModes) {
- if (!displayToken || !outColorModes) {
- return BAD_VALUE;
- }
-
- std::vector<ColorMode> modes;
- bool isInternalDisplay = false;
- {
- ConditionalLock lock(mStateLock, std::this_thread::get_id() != mMainThreadId);
-
- const auto displayId = getPhysicalDisplayIdLocked(displayToken);
- if (!displayId) {
- return NAME_NOT_FOUND;
- }
-
- modes = getHwComposer().getColorModes(*displayId);
- isInternalDisplay = displayId == getInternalDisplayIdLocked();
- }
- outColorModes->clear();
+std::vector<ColorMode> SurfaceFlinger::getDisplayColorModes(PhysicalDisplayId displayId) {
+ auto modes = getHwComposer().getColorModes(displayId);
+ bool isInternalDisplay = displayId == getInternalDisplayIdLocked();
// If it's built-in display and the configuration claims it's not wide color capable,
// filter out all wide color modes. The typical reason why this happens is that the
// hardware is not good enough to support GPU composition of wide color, and thus the
// OEMs choose to disable this capability.
if (isInternalDisplay && !hasWideColorDisplay) {
- std::remove_copy_if(modes.cbegin(), modes.cend(), std::back_inserter(*outColorModes),
- isWideColorMode);
- } else {
- std::copy(modes.cbegin(), modes.cend(), std::back_inserter(*outColorModes));
+ const auto newEnd = std::remove_if(modes.begin(), modes.end(), isWideColorMode);
+ modes.erase(newEnd, modes.end());
}
- return NO_ERROR;
+ return modes;
}
status_t SurfaceFlinger::getDisplayNativePrimaries(const sp<IBinder>& displayToken,
@@ -1240,19 +1220,14 @@ status_t SurfaceFlinger::getDisplayNativePrimaries(const sp<IBinder>& displayTok
return NO_ERROR;
}
-ColorMode SurfaceFlinger::getActiveColorMode(const sp<IBinder>& displayToken) {
- Mutex::Autolock lock(mStateLock);
-
- if (const auto display = getDisplayDeviceLocked(displayToken)) {
- return display->getCompositionDisplay()->getState().colorMode;
- }
- return static_cast<ColorMode>(BAD_VALUE);
-}
-
status_t SurfaceFlinger::setActiveColorMode(const sp<IBinder>& displayToken, ColorMode mode) {
schedule([=]() MAIN_THREAD {
- Vector<ColorMode> modes;
- getDisplayColorModes(displayToken, &modes);
+ const auto displayId = getPhysicalDisplayIdLocked(displayToken);
+ if (!displayId) {
+ ALOGE("Invalid display token %p", displayToken.get());
+ return;
+ }
+ const auto modes = getDisplayColorModes(*displayId);
bool exists = std::find(std::begin(modes), std::end(modes), mode) != std::end(modes);
if (mode < ColorMode::NATIVE || !exists) {
ALOGE("Attempt to set invalid active color mode %s (%d) for display token %p",
@@ -1277,24 +1252,6 @@ status_t SurfaceFlinger::setActiveColorMode(const sp<IBinder>& displayToken, Col
return NO_ERROR;
}
-status_t SurfaceFlinger::getAutoLowLatencyModeSupport(const sp<IBinder>& displayToken,
- bool* outSupport) const {
- if (!displayToken) {
- return BAD_VALUE;
- }
-
- Mutex::Autolock lock(mStateLock);
-
- const auto displayId = getPhysicalDisplayIdLocked(displayToken);
- if (!displayId) {
- return NAME_NOT_FOUND;
- }
- *outSupport =
- getHwComposer().hasDisplayCapability(*displayId,
- hal::DisplayCapability::AUTO_LOW_LATENCY_MODE);
- return NO_ERROR;
-}
-
void SurfaceFlinger::setAutoLowLatencyMode(const sp<IBinder>& displayToken, bool on) {
static_cast<void>(schedule([=]() MAIN_THREAD {
if (const auto displayId = getPhysicalDisplayIdLocked(displayToken)) {
@@ -1305,27 +1262,6 @@ void SurfaceFlinger::setAutoLowLatencyMode(const sp<IBinder>& displayToken, bool
}));
}
-status_t SurfaceFlinger::getGameContentTypeSupport(const sp<IBinder>& displayToken,
- bool* outSupport) const {
- if (!displayToken) {
- return BAD_VALUE;
- }
-
- Mutex::Autolock lock(mStateLock);
-
- const auto displayId = getPhysicalDisplayIdLocked(displayToken);
- if (!displayId) {
- return NAME_NOT_FOUND;
- }
-
- std::vector<hal::ContentType> types;
- getHwComposer().getSupportedContentTypes(*displayId, &types);
-
- *outSupport = std::any_of(types.begin(), types.end(),
- [](auto type) { return type == hal::ContentType::GAME; });
- return NO_ERROR;
-}
-
void SurfaceFlinger::setGameContentType(const sp<IBinder>& displayToken, bool on) {
static_cast<void>(schedule([=]() MAIN_THREAD {
if (const auto displayId = getPhysicalDisplayIdLocked(displayToken)) {
@@ -1349,28 +1285,6 @@ status_t SurfaceFlinger::getAnimationFrameStats(FrameStats* outStats) const {
return NO_ERROR;
}
-status_t SurfaceFlinger::getHdrCapabilities(const sp<IBinder>& displayToken,
- HdrCapabilities* outCapabilities) const {
- Mutex::Autolock lock(mStateLock);
-
- const auto display = getDisplayDeviceLocked(displayToken);
- if (!display) {
- ALOGE("%s: Invalid display token %p", __FUNCTION__, displayToken.get());
- return NAME_NOT_FOUND;
- }
-
- // At this point the DisplayDevice should already be set up,
- // meaning the luminance information is already queried from
- // hardware composer and stored properly.
- const HdrCapabilities& capabilities = display->getHdrCapabilities();
- *outCapabilities = HdrCapabilities(capabilities.getSupportedHdrTypes(),
- capabilities.getDesiredMaxLuminance(),
- capabilities.getDesiredMaxAverageLuminance(),
- capabilities.getDesiredMinLuminance());
-
- return NO_ERROR;
-}
-
status_t SurfaceFlinger::getDisplayedContentSamplingAttributes(const sp<IBinder>& displayToken,
ui::PixelFormat* outFormat,
ui::Dataspace* outDataspace,
@@ -1640,7 +1554,7 @@ void SurfaceFlinger::changeRefreshRateLocked(const RefreshRate& refreshRate,
// Don't do any updating if the current fps is the same as the new one.
if (!isDisplayModeAllowed(refreshRate.getModeId())) {
- ALOGV("Skipping mode %zu as it is not part of allowed modes",
+ ALOGV("Skipping mode %d as it is not part of allowed modes",
refreshRate.getModeId().value());
return;
}
@@ -1899,7 +1813,7 @@ void SurfaceFlinger::onMessageInvalidate(int64_t vsyncId, nsecs_t expectedVSyncT
const bool tracePreComposition = mTracingEnabled && !mTracePostComposition;
ConditionalLockGuard<std::mutex> lock(mTracingLock, tracePreComposition);
- mFrameTimeline->setSfWakeUp(vsyncId, frameStart, stats.vsyncPeriod);
+ mFrameTimeline->setSfWakeUp(vsyncId, frameStart, Fps::fromPeriodNsecs(stats.vsyncPeriod));
refreshNeeded = handleMessageTransaction();
refreshNeeded |= handleMessageInvalidate();
@@ -2360,7 +2274,7 @@ void SurfaceFlinger::handleTransaction(uint32_t transactionFlags) {
DisplayModes SurfaceFlinger::loadSupportedDisplayModes(PhysicalDisplayId displayId) const {
const auto hwcModes = getHwComposer().getModes(displayId);
DisplayModes modes;
- size_t nextModeId = 0;
+ int32_t nextModeId = 0;
for (const auto& hwcMode : hwcModes) {
modes.push_back(DisplayMode::Builder(hwcMode.hwcId)
.setId(DisplayModeId{nextModeId++})
@@ -2906,15 +2820,32 @@ void SurfaceFlinger::updateInputFlinger() {
mInputWindowCommands.clear();
}
+bool enablePerWindowInputRotation() {
+ static bool value =
+ android::base::GetBoolProperty("persist.debug.per_window_input_rotation", false);
+ return value;
+}
+
void SurfaceFlinger::updateInputWindowInfo() {
std::vector<InputWindowInfo> inputInfos;
mDrawingState.traverseInReverseZOrder([&](Layer* layer) {
- if (layer->needsInputInfo()) {
- // When calculating the screen bounds we ignore the transparent region since it may
- // result in an unwanted offset.
- inputInfos.push_back(layer->fillInputInfo());
+ 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;
+ }
}
+ // When calculating the screen bounds we ignore the transparent region since it may
+ // result in an unwanted offset.
+ inputInfos.push_back(layer->fillInputInfo(display));
});
mInputFlinger->setInputWindows(inputInfos,
@@ -3950,6 +3881,11 @@ uint32_t SurfaceFlinger::setClientStateLocked(
if (what & layer_state_t::eAutoRefreshChanged) {
layer->setAutoRefresh(s.autoRefresh);
}
+ if (what & layer_state_t::eStretchChanged) {
+ if (layer->setStretchEffect(s.stretchEffect)) {
+ flags |= eTraversalNeeded;
+ }
+ }
// 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
@@ -4846,6 +4782,8 @@ void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, std::string& result) co
getRenderEngine().dump(result);
+ result.append("ClientCache state:\n");
+ ClientCache::getInstance().dump(result);
DebugEGLImageTracker::getInstance()->dump(result);
if (const auto display = getDefaultDisplayDeviceLocked()) {
@@ -5008,7 +4946,8 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) {
case GET_PHYSICAL_DISPLAY_TOKEN:
case GET_DISPLAY_COLOR_MODES:
case GET_DISPLAY_NATIVE_PRIMARIES:
- case GET_DISPLAY_INFO:
+ case GET_STATIC_DISPLAY_INFO:
+ case GET_DYNAMIC_DISPLAY_INFO:
case GET_DISPLAY_MODES:
case GET_DISPLAY_STATE:
case GET_DISPLAY_STATS:
@@ -5846,6 +5785,10 @@ status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture,
getFactory().createGraphicBuffer(bufferSize.getWidth(), bufferSize.getHeight(),
static_cast<android_pixel_format>(reqPixelFormat),
1 /* layerCount */, usage, "screenshot");
+
+ const status_t bufferStatus = buffer->initCheck();
+ LOG_ALWAYS_FATAL_IF(bufferStatus != OK, "captureScreenCommon: Buffer failed to allocate: %d",
+ bufferStatus);
return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, buffer,
false /* regionSampling */, grayscale, captureListener);
}
@@ -6136,27 +6079,25 @@ status_t SurfaceFlinger::setDesiredDisplayModeSpecsInternal(
? 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 %zu (%s)",
+ ALOGV("trying to switch to Scheduler preferred mode %d (%s)",
preferredRefreshRate.getModeId().value(), preferredRefreshRate.getName().c_str());
if (isDisplayModeAllowed(preferredRefreshRate.getModeId())) {
- ALOGV("switching to Scheduler preferred display mode %zu",
+ ALOGV("switching to Scheduler preferred display mode %d",
preferredRefreshRate.getModeId().value());
setDesiredActiveMode({preferredRefreshRate.getModeId(), Scheduler::ModeEvent::Changed});
} else {
- LOG_ALWAYS_FATAL("Desired display mode not allowed: %zu",
+ LOG_ALWAYS_FATAL("Desired display mode not allowed: %d",
preferredRefreshRate.getModeId().value());
}
return NO_ERROR;
}
-status_t SurfaceFlinger::setDesiredDisplayModeSpecs(const sp<IBinder>& displayToken,
- size_t defaultMode, bool allowGroupSwitching,
- float primaryRefreshRateMin,
- float primaryRefreshRateMax,
- float appRequestRefreshRateMin,
- float appRequestRefreshRateMax) {
+status_t SurfaceFlinger::setDesiredDisplayModeSpecs(
+ const sp<IBinder>& displayToken, ui::DisplayModeId defaultMode, bool allowGroupSwitching,
+ float primaryRefreshRateMin, float primaryRefreshRateMax, float appRequestRefreshRateMin,
+ float appRequestRefreshRateMax) {
ATRACE_CALL();
if (!displayToken) {
@@ -6187,10 +6128,13 @@ status_t SurfaceFlinger::setDesiredDisplayModeSpecs(const sp<IBinder>& displayTo
return future.get();
}
-status_t SurfaceFlinger::getDesiredDisplayModeSpecs(
- const sp<IBinder>& displayToken, size_t* outDefaultMode, bool* outAllowGroupSwitching,
- float* outPrimaryRefreshRateMin, float* outPrimaryRefreshRateMax,
- float* outAppRequestRefreshRateMin, float* outAppRequestRefreshRateMax) {
+status_t SurfaceFlinger::getDesiredDisplayModeSpecs(const sp<IBinder>& displayToken,
+ ui::DisplayModeId* outDefaultMode,
+ bool* outAllowGroupSwitching,
+ float* outPrimaryRefreshRateMin,
+ float* outPrimaryRefreshRateMax,
+ float* outAppRequestRefreshRateMin,
+ float* outAppRequestRefreshRateMax) {
ATRACE_CALL();
if (!displayToken || !outDefaultMode || !outPrimaryRefreshRateMin ||
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index a62d0b9a95..d9af7509a1 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -552,26 +552,20 @@ private:
const sp<IScreenCaptureListener>& captureListener) override;
status_t getDisplayStats(const sp<IBinder>& displayToken, DisplayStatInfo* stats) override;
- status_t getDisplayState(const sp<IBinder>& displayToken, ui::DisplayState*) override;
- status_t getDisplayInfo(const sp<IBinder>& displayToken, DisplayInfo*) override;
- status_t getDisplayModes(const sp<IBinder>& displayToken, Vector<ui::DisplayMode>*) override;
- int getActiveDisplayModeId(const sp<IBinder>& displayToken) override;
- status_t getDisplayColorModes(const sp<IBinder>& displayToken, Vector<ui::ColorMode>*) override;
+ status_t getDisplayState(const sp<IBinder>& displayToken, ui::DisplayState*)
+ EXCLUDES(mStateLock) override;
+ status_t getStaticDisplayInfo(const sp<IBinder>& displayToken, ui::StaticDisplayInfo*)
+ EXCLUDES(mStateLock) override;
+ status_t getDynamicDisplayInfo(const sp<IBinder>& displayToken, ui::DynamicDisplayInfo*)
+ EXCLUDES(mStateLock) override;
status_t getDisplayNativePrimaries(const sp<IBinder>& displayToken,
ui::DisplayPrimaries&) override;
- ui::ColorMode getActiveColorMode(const sp<IBinder>& displayToken) override;
status_t setActiveColorMode(const sp<IBinder>& displayToken, ui::ColorMode colorMode) override;
- status_t getAutoLowLatencyModeSupport(const sp<IBinder>& displayToken,
- bool* outSupported) const override;
void setAutoLowLatencyMode(const sp<IBinder>& displayToken, bool on) override;
- status_t getGameContentTypeSupport(const sp<IBinder>& displayToken,
- bool* outSupported) const override;
void setGameContentType(const sp<IBinder>& displayToken, bool on) override;
void setPowerMode(const sp<IBinder>& displayToken, int mode) override;
status_t clearAnimationFrameStats() override;
status_t getAnimationFrameStats(FrameStats* outStats) const override;
- status_t getHdrCapabilities(const sp<IBinder>& displayToken,
- HdrCapabilities* outCapabilities) const override;
status_t enableVSyncInjections(bool enable) override;
status_t injectVSync(nsecs_t when) override;
status_t getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) override;
@@ -594,11 +588,13 @@ private:
status_t addRegionSamplingListener(const Rect& samplingArea, const sp<IBinder>& stopLayerHandle,
const sp<IRegionSamplingListener>& listener) override;
status_t removeRegionSamplingListener(const sp<IRegionSamplingListener>& listener) override;
- status_t setDesiredDisplayModeSpecs(const sp<IBinder>& displayToken, size_t displayModeId,
- bool allowGroupSwitching, float primaryRefreshRateMin,
- float primaryRefreshRateMax, float appRequestRefreshRateMin,
+ status_t setDesiredDisplayModeSpecs(const sp<IBinder>& displayToken,
+ ui::DisplayModeId displayModeId, bool allowGroupSwitching,
+ float primaryRefreshRateMin, float primaryRefreshRateMax,
+ float appRequestRefreshRateMin,
float appRequestRefreshRateMax) override;
- status_t getDesiredDisplayModeSpecs(const sp<IBinder>& displayToken, size_t* outDefaultMode,
+ status_t getDesiredDisplayModeSpecs(const sp<IBinder>& displayToken,
+ ui::DisplayModeId* outDefaultMode,
bool* outAllowGroupSwitching,
float* outPrimaryRefreshRateMin,
float* outPrimaryRefreshRateMax,
@@ -1054,6 +1050,9 @@ private:
return std::nullopt;
}
+ std::vector<ui::ColorMode> getDisplayColorModes(PhysicalDisplayId displayId)
+ REQUIRES(mStateLock);
+
static int calculateExtraBufferCount(Fps maxSupportedRefreshRate,
std::chrono::nanoseconds presentLatency);
diff --git a/services/surfaceflinger/SurfaceInterceptor.cpp b/services/surfaceflinger/SurfaceInterceptor.cpp
index 61005c92df..b0413f1c92 100644
--- a/services/surfaceflinger/SurfaceInterceptor.cpp
+++ b/services/surfaceflinger/SurfaceInterceptor.cpp
@@ -499,6 +499,9 @@ void SurfaceInterceptor::addSurfaceChangesLocked(Transaction* transaction,
if (state.what & layer_state_t::eShadowRadiusChanged) {
addShadowRadiusLocked(transaction, layerId, state.shadowRadius);
}
+ if (state.what & layer_state_t::eStretchChanged) {
+ ALOGW("SurfaceInterceptor not implemented for eStretchChanged");
+ }
}
void SurfaceInterceptor::addDisplayChangesLocked(Transaction* transaction,
diff --git a/services/surfaceflinger/SurfaceTracing.cpp b/services/surfaceflinger/SurfaceTracing.cpp
index 1d1f0c5cf6..b4d8a9adce 100644
--- a/services/surfaceflinger/SurfaceTracing.cpp
+++ b/services/surfaceflinger/SurfaceTracing.cpp
@@ -71,12 +71,14 @@ status_t SurfaceTracing::writeToFile() {
}
void SurfaceTracing::notify(const char* where) {
+ std::scoped_lock lock(mTraceLock);
if (mEnabled) {
runner->notify(where);
}
}
void SurfaceTracing::notifyLocked(const char* where) {
+ std::scoped_lock lock(mTraceLock);
if (mEnabled) {
runner->notifyLocked(where);
}
diff --git a/services/surfaceflinger/SurfaceTracing.h b/services/surfaceflinger/SurfaceTracing.h
index 497ebd3c50..15a503d834 100644
--- a/services/surfaceflinger/SurfaceTracing.h
+++ b/services/surfaceflinger/SurfaceTracing.h
@@ -81,8 +81,8 @@ private:
SurfaceFlinger& mFlinger;
mutable std::mutex mTraceLock;
- bool mEnabled = false;
- std::unique_ptr<Runner> runner;
+ bool mEnabled GUARDED_BY(mTraceLock) = false;
+ std::unique_ptr<Runner> runner GUARDED_BY(mTraceLock);
struct Config {
uint32_t flags = TRACE_CRITICAL | TRACE_INPUT | TRACE_SYNC;
diff --git a/services/surfaceflinger/TimeStats/Android.bp b/services/surfaceflinger/TimeStats/Android.bp
index 0a23da2e9c..62fddb4f47 100644
--- a/services/surfaceflinger/TimeStats/Android.bp
+++ b/services/surfaceflinger/TimeStats/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library {
name: "libtimestats",
srcs: [
diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp
index 5d387d68e8..100354adac 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.cpp
+++ b/services/surfaceflinger/TimeStats/TimeStats.cpp
@@ -105,53 +105,64 @@ std::string frameRateVoteToProtoByteString(float refreshRate, int frameRateCompa
AStatsManager_PullAtomCallbackReturn TimeStats::populateGlobalAtom(AStatsEventList* data) {
std::lock_guard<std::mutex> lock(mMutex);
- if (mTimeStats.statsStart == 0) {
+ if (mTimeStats.statsStartLegacy == 0) {
return AStatsManager_PULL_SKIP;
}
flushPowerTimeLocked();
- AStatsEvent* event = mStatsDelegate->addStatsEventToPullData(data);
- mStatsDelegate->statsEventSetAtomId(event, android::util::SURFACEFLINGER_STATS_GLOBAL_INFO);
- mStatsDelegate->statsEventWriteInt64(event, mTimeStats.totalFrames);
- mStatsDelegate->statsEventWriteInt64(event, mTimeStats.missedFrames);
- mStatsDelegate->statsEventWriteInt64(event, mTimeStats.clientCompositionFrames);
- mStatsDelegate->statsEventWriteInt64(event, mTimeStats.displayOnTime);
- mStatsDelegate->statsEventWriteInt64(event, mTimeStats.presentToPresent.totalTime());
- mStatsDelegate->statsEventWriteInt32(event, mTimeStats.displayEventConnectionsCount);
- std::string frameDurationBytes =
- histogramToProtoByteString(mTimeStats.frameDuration.hist, mMaxPulledHistogramBuckets);
- mStatsDelegate->statsEventWriteByteArray(event, (const uint8_t*)frameDurationBytes.c_str(),
- frameDurationBytes.size());
- std::string renderEngineTimingBytes =
- histogramToProtoByteString(mTimeStats.renderEngineTiming.hist,
- mMaxPulledHistogramBuckets);
- mStatsDelegate->statsEventWriteByteArray(event, (const uint8_t*)renderEngineTimingBytes.c_str(),
- renderEngineTimingBytes.size());
-
- mStatsDelegate->statsEventWriteInt32(event, mTimeStats.jankPayload.totalFrames);
- mStatsDelegate->statsEventWriteInt32(event, mTimeStats.jankPayload.totalJankyFrames);
- mStatsDelegate->statsEventWriteInt32(event, mTimeStats.jankPayload.totalSFLongCpu);
- mStatsDelegate->statsEventWriteInt32(event, mTimeStats.jankPayload.totalSFLongGpu);
- mStatsDelegate->statsEventWriteInt32(event, mTimeStats.jankPayload.totalSFUnattributed);
- mStatsDelegate->statsEventWriteInt32(event, mTimeStats.jankPayload.totalAppUnattributed);
-
- // TODO: populate these with real values
- mStatsDelegate->statsEventWriteInt32(event, 0); // total_janky_frames_sf_scheduling
- mStatsDelegate->statsEventWriteInt32(event, 0); // total_jank_frames_sf_prediction_error
- mStatsDelegate->statsEventWriteInt32(event, 0); // total_jank_frames_app_buffer_stuffing
- mStatsDelegate->statsEventWriteInt32(event, 0); // display_refresh_rate_bucket
- std::string sfDeadlineMissedBytes =
- histogramToProtoByteString(std::unordered_map<int32_t, int32_t>(),
- mMaxPulledHistogramBuckets);
- mStatsDelegate->statsEventWriteByteArray(event, (const uint8_t*)sfDeadlineMissedBytes.c_str(),
- sfDeadlineMissedBytes.size()); // sf_deadline_misses
- std::string sfPredictionErrorBytes =
- histogramToProtoByteString(std::unordered_map<int32_t, int32_t>(),
- mMaxPulledHistogramBuckets);
- mStatsDelegate->statsEventWriteByteArray(event, (const uint8_t*)sfPredictionErrorBytes.c_str(),
- sfPredictionErrorBytes.size()); // sf_prediction_errors
- mStatsDelegate->statsEventWriteInt32(event, 0); // render_rate_bucket
- mStatsDelegate->statsEventBuild(event);
+ for (const auto& globalSlice : mTimeStats.stats) {
+ AStatsEvent* event = mStatsDelegate->addStatsEventToPullData(data);
+ mStatsDelegate->statsEventSetAtomId(event, android::util::SURFACEFLINGER_STATS_GLOBAL_INFO);
+ mStatsDelegate->statsEventWriteInt64(event, mTimeStats.totalFramesLegacy);
+ mStatsDelegate->statsEventWriteInt64(event, mTimeStats.missedFramesLegacy);
+ mStatsDelegate->statsEventWriteInt64(event, mTimeStats.clientCompositionFramesLegacy);
+ mStatsDelegate->statsEventWriteInt64(event, mTimeStats.displayOnTimeLegacy);
+ mStatsDelegate->statsEventWriteInt64(event, mTimeStats.presentToPresentLegacy.totalTime());
+ mStatsDelegate->statsEventWriteInt32(event, mTimeStats.displayEventConnectionsCountLegacy);
+ std::string frameDurationBytes =
+ histogramToProtoByteString(mTimeStats.frameDurationLegacy.hist,
+ mMaxPulledHistogramBuckets);
+ mStatsDelegate->statsEventWriteByteArray(event, (const uint8_t*)frameDurationBytes.c_str(),
+ frameDurationBytes.size());
+ std::string renderEngineTimingBytes =
+ histogramToProtoByteString(mTimeStats.renderEngineTimingLegacy.hist,
+ mMaxPulledHistogramBuckets);
+ mStatsDelegate->statsEventWriteByteArray(event,
+ (const uint8_t*)renderEngineTimingBytes.c_str(),
+ renderEngineTimingBytes.size());
+
+ mStatsDelegate->statsEventWriteInt32(event, globalSlice.second.jankPayload.totalFrames);
+ mStatsDelegate->statsEventWriteInt32(event,
+ globalSlice.second.jankPayload.totalJankyFrames);
+ mStatsDelegate->statsEventWriteInt32(event, globalSlice.second.jankPayload.totalSFLongCpu);
+ mStatsDelegate->statsEventWriteInt32(event, globalSlice.second.jankPayload.totalSFLongGpu);
+ mStatsDelegate->statsEventWriteInt32(event,
+ globalSlice.second.jankPayload.totalSFUnattributed);
+ mStatsDelegate->statsEventWriteInt32(event,
+ globalSlice.second.jankPayload.totalAppUnattributed);
+ mStatsDelegate->statsEventWriteInt32(event,
+ globalSlice.second.jankPayload.totalSFScheduling);
+ mStatsDelegate->statsEventWriteInt32(event,
+ globalSlice.second.jankPayload.totalSFPredictionError);
+ mStatsDelegate->statsEventWriteInt32(event,
+ globalSlice.second.jankPayload.totalAppBufferStuffing);
+ mStatsDelegate->statsEventWriteInt32(event, globalSlice.first.displayRefreshRateBucket);
+ std::string sfDeadlineMissedBytes =
+ histogramToProtoByteString(globalSlice.second.displayDeadlineDeltas.hist,
+ mMaxPulledHistogramBuckets);
+ mStatsDelegate->statsEventWriteByteArray(event,
+ (const uint8_t*)sfDeadlineMissedBytes.c_str(),
+ sfDeadlineMissedBytes.size());
+ std::string sfPredictionErrorBytes =
+ histogramToProtoByteString(globalSlice.second.displayPresentDeltas.hist,
+ mMaxPulledHistogramBuckets);
+ mStatsDelegate->statsEventWriteByteArray(event,
+ (const uint8_t*)sfPredictionErrorBytes.c_str(),
+ sfPredictionErrorBytes.size());
+ mStatsDelegate->statsEventWriteInt32(event, globalSlice.first.renderRateBucket);
+ mStatsDelegate->statsEventBuild(event);
+ }
+
clearGlobalLocked();
return AStatsManager_PULL_SUCCESS;
@@ -160,9 +171,18 @@ AStatsManager_PullAtomCallbackReturn TimeStats::populateGlobalAtom(AStatsEventLi
AStatsManager_PullAtomCallbackReturn TimeStats::populateLayerAtom(AStatsEventList* data) {
std::lock_guard<std::mutex> lock(mMutex);
- std::vector<TimeStatsHelper::TimeStatsLayer const*> dumpStats;
- for (const auto& ele : mTimeStats.stats) {
- dumpStats.push_back(&ele.second);
+ std::vector<TimeStatsHelper::TimeStatsLayer*> dumpStats;
+ uint32_t numLayers = 0;
+ for (const auto& globalSlice : mTimeStats.stats) {
+ numLayers += globalSlice.second.stats.size();
+ }
+
+ dumpStats.reserve(numLayers);
+
+ for (auto& globalSlice : mTimeStats.stats) {
+ for (auto& layerSlice : globalSlice.second.stats) {
+ dumpStats.push_back(&layerSlice.second);
+ }
}
std::sort(dumpStats.begin(), dumpStats.end(),
@@ -175,7 +195,7 @@ AStatsManager_PullAtomCallbackReturn TimeStats::populateLayerAtom(AStatsEventLis
dumpStats.resize(mMaxPulledLayers);
}
- for (const auto& layer : dumpStats) {
+ for (auto& layer : dumpStats) {
AStatsEvent* event = mStatsDelegate->addStatsEventToPullData(data);
mStatsDelegate->statsEventSetAtomId(event, android::util::SURFACEFLINGER_STATS_LAYER_INFO);
mStatsDelegate->statsEventWriteString8(event, layer->layerName.c_str());
@@ -203,22 +223,21 @@ AStatsManager_PullAtomCallbackReturn TimeStats::populateLayerAtom(AStatsEventLis
mStatsDelegate->statsEventWriteInt32(event, layer->jankPayload.totalSFLongGpu);
mStatsDelegate->statsEventWriteInt32(event, layer->jankPayload.totalSFUnattributed);
mStatsDelegate->statsEventWriteInt32(event, layer->jankPayload.totalAppUnattributed);
-
- // TODO: populate these with real values
- mStatsDelegate->statsEventWriteInt32(event, 0); // total_janky_frames_sf_scheduling
- mStatsDelegate->statsEventWriteInt32(event, 0); // total_jank_frames_sf_prediction_error
- mStatsDelegate->statsEventWriteInt32(event, 0); // total_jank_frames_app_buffer_stuffing
- mStatsDelegate->statsEventWriteInt32(event, 0); // display_refresh_rate_bucket
- mStatsDelegate->statsEventWriteInt32(event, 0); // render_rate_bucket
+ mStatsDelegate->statsEventWriteInt32(event, layer->jankPayload.totalSFScheduling);
+ mStatsDelegate->statsEventWriteInt32(event, layer->jankPayload.totalSFPredictionError);
+ mStatsDelegate->statsEventWriteInt32(event, layer->jankPayload.totalAppBufferStuffing);
+ mStatsDelegate->statsEventWriteInt32(
+ event, layer->displayRefreshRateBucket); // display_refresh_rate_bucket
+ mStatsDelegate->statsEventWriteInt32(event, layer->renderRateBucket); // render_rate_bucket
std::string frameRateVoteBytes = frameRateVoteToProtoByteString(0.0, 0, 0);
mStatsDelegate->statsEventWriteByteArray(event, (const uint8_t*)frameRateVoteBytes.c_str(),
frameRateVoteBytes.size()); // set_frame_rate_vote
std::string appDeadlineMissedBytes =
- histogramToProtoByteString(std::unordered_map<int32_t, int32_t>(),
+ histogramToProtoByteString(layer->deltas["appDeadlineDeltas"].hist,
mMaxPulledHistogramBuckets);
- mStatsDelegate
- ->statsEventWriteByteArray(event, (const uint8_t*)appDeadlineMissedBytes.c_str(),
- appDeadlineMissedBytes.size()); // app_deadline_misses
+ mStatsDelegate->statsEventWriteByteArray(event,
+ (const uint8_t*)appDeadlineMissedBytes.c_str(),
+ appDeadlineMissedBytes.size());
mStatsDelegate->statsEventBuild(event);
}
@@ -310,7 +329,7 @@ void TimeStats::incrementTotalFrames() {
ATRACE_CALL();
std::lock_guard<std::mutex> lock(mMutex);
- mTimeStats.totalFrames++;
+ mTimeStats.totalFramesLegacy++;
}
void TimeStats::incrementMissedFrames() {
@@ -319,7 +338,7 @@ void TimeStats::incrementMissedFrames() {
ATRACE_CALL();
std::lock_guard<std::mutex> lock(mMutex);
- mTimeStats.missedFrames++;
+ mTimeStats.missedFramesLegacy++;
}
void TimeStats::incrementClientCompositionFrames() {
@@ -328,7 +347,7 @@ void TimeStats::incrementClientCompositionFrames() {
ATRACE_CALL();
std::lock_guard<std::mutex> lock(mMutex);
- mTimeStats.clientCompositionFrames++;
+ mTimeStats.clientCompositionFramesLegacy++;
}
void TimeStats::incrementClientCompositionReusedFrames() {
@@ -337,7 +356,7 @@ void TimeStats::incrementClientCompositionReusedFrames() {
ATRACE_CALL();
std::lock_guard<std::mutex> lock(mMutex);
- mTimeStats.clientCompositionReusedFrames++;
+ mTimeStats.clientCompositionReusedFramesLegacy++;
}
void TimeStats::incrementRefreshRateSwitches() {
@@ -346,7 +365,7 @@ void TimeStats::incrementRefreshRateSwitches() {
ATRACE_CALL();
std::lock_guard<std::mutex> lock(mMutex);
- mTimeStats.refreshRateSwitches++;
+ mTimeStats.refreshRateSwitchesLegacy++;
}
void TimeStats::incrementCompositionStrategyChanges() {
@@ -355,7 +374,7 @@ void TimeStats::incrementCompositionStrategyChanges() {
ATRACE_CALL();
std::lock_guard<std::mutex> lock(mMutex);
- mTimeStats.compositionStrategyChanges++;
+ mTimeStats.compositionStrategyChangesLegacy++;
}
void TimeStats::recordDisplayEventConnectionCount(int32_t count) {
@@ -364,8 +383,8 @@ void TimeStats::recordDisplayEventConnectionCount(int32_t count) {
ATRACE_CALL();
std::lock_guard<std::mutex> lock(mMutex);
- mTimeStats.displayEventConnectionsCount =
- std::max(mTimeStats.displayEventConnectionsCount, count);
+ mTimeStats.displayEventConnectionsCountLegacy =
+ std::max(mTimeStats.displayEventConnectionsCountLegacy, count);
}
static int32_t msBetween(nsecs_t start, nsecs_t end) {
@@ -381,7 +400,7 @@ void TimeStats::recordFrameDuration(nsecs_t startTime, nsecs_t endTime) {
std::lock_guard<std::mutex> lock(mMutex);
if (mPowerTime.powerMode == PowerMode::ON) {
- mTimeStats.frameDuration.insert(msBetween(startTime, endTime));
+ mTimeStats.frameDurationLegacy.insert(msBetween(startTime, endTime));
}
}
@@ -444,12 +463,22 @@ bool TimeStats::recordReadyLocked(int32_t layerId, TimeRecord* timeRecord) {
return true;
}
-void TimeStats::flushAvailableRecordsToStatsLocked(int32_t layerId) {
+static int32_t clampToSmallestBucket(Fps fps, size_t bucketWidth) {
+ return (fps.getIntValue() / bucketWidth) * bucketWidth;
+}
+
+void TimeStats::flushAvailableRecordsToStatsLocked(int32_t layerId, Fps displayRefreshRate,
+ std::optional<Fps> renderRate) {
ATRACE_CALL();
LayerRecord& layerRecord = mTimeStatsTracker[layerId];
TimeRecord& prevTimeRecord = layerRecord.prevTimeRecord;
std::deque<TimeRecord>& timeRecords = layerRecord.timeRecords;
+ const int32_t refreshRateBucket =
+ clampToSmallestBucket(displayRefreshRate, REFRESH_RATE_BUCKET_WIDTH);
+ const int32_t renderRateBucket =
+ clampToSmallestBucket(renderRate ? *renderRate : displayRefreshRate,
+ RENDER_RATE_BUCKET_WIDTH);
while (!timeRecords.empty()) {
if (!recordReadyLocked(layerId, &timeRecords[0])) break;
ALOGV("[%d]-[%" PRIu64 "]-presentFenceTime[%" PRId64 "]", layerId,
@@ -458,11 +487,21 @@ void TimeStats::flushAvailableRecordsToStatsLocked(int32_t layerId) {
if (prevTimeRecord.ready) {
uid_t uid = layerRecord.uid;
const std::string& layerName = layerRecord.layerName;
- if (!mTimeStats.stats.count({uid, layerName})) {
- mTimeStats.stats[{uid, layerName}].uid = uid;
- mTimeStats.stats[{uid, layerName}].layerName = layerName;
+ TimeStatsHelper::TimelineStatsKey timelineKey = {refreshRateBucket, renderRateBucket};
+ if (!mTimeStats.stats.count(timelineKey)) {
+ mTimeStats.stats[timelineKey].key = timelineKey;
}
- TimeStatsHelper::TimeStatsLayer& timeStatsLayer = mTimeStats.stats[{uid, layerName}];
+
+ TimeStatsHelper::TimelineStats& displayStats = mTimeStats.stats[timelineKey];
+
+ TimeStatsHelper::LayerStatsKey layerKey = {uid, layerName};
+ if (!displayStats.stats.count(layerKey)) {
+ displayStats.stats[layerKey].displayRefreshRateBucket = refreshRateBucket;
+ displayStats.stats[layerKey].renderRateBucket = renderRateBucket;
+ displayStats.stats[layerKey].uid = uid;
+ displayStats.stats[layerKey].layerName = layerName;
+ }
+ TimeStatsHelper::TimeStatsLayer& timeStatsLayer = displayStats.stats[layerKey];
timeStatsLayer.totalFrames++;
timeStatsLayer.droppedFrames += layerRecord.droppedFrames;
timeStatsLayer.lateAcquireFrames += layerRecord.lateAcquireFrames;
@@ -524,8 +563,16 @@ static bool layerNameIsValid(const std::string& layerName) {
}
bool TimeStats::canAddNewAggregatedStats(uid_t uid, const std::string& layerName) {
- return mTimeStats.stats.count({uid, layerName}) > 0 ||
- mTimeStats.stats.size() < MAX_NUM_LAYER_STATS;
+ uint32_t layerRecords = 0;
+ for (const auto& record : mTimeStats.stats) {
+ if (record.second.stats.count({uid, layerName}) > 0) {
+ return true;
+ }
+
+ layerRecords += record.second.stats.size();
+ }
+
+ return mTimeStats.stats.size() < MAX_NUM_LAYER_STATS;
}
void TimeStats::setPostTime(int32_t layerId, uint64_t frameNumber, const std::string& layerName,
@@ -676,7 +723,8 @@ void TimeStats::setAcquireFence(int32_t layerId, uint64_t frameNumber,
}
}
-void TimeStats::setPresentTime(int32_t layerId, uint64_t frameNumber, nsecs_t presentTime) {
+void TimeStats::setPresentTime(int32_t layerId, uint64_t frameNumber, nsecs_t presentTime,
+ Fps displayRefreshRate, std::optional<Fps> renderRate) {
if (!mEnabled.load()) return;
ATRACE_CALL();
@@ -695,11 +743,12 @@ void TimeStats::setPresentTime(int32_t layerId, uint64_t frameNumber, nsecs_t pr
layerRecord.waitData++;
}
- flushAvailableRecordsToStatsLocked(layerId);
+ flushAvailableRecordsToStatsLocked(layerId, displayRefreshRate, renderRate);
}
void TimeStats::setPresentFence(int32_t layerId, uint64_t frameNumber,
- const std::shared_ptr<FenceTime>& presentFence) {
+ const std::shared_ptr<FenceTime>& presentFence,
+ Fps displayRefreshRate, std::optional<Fps> renderRate) {
if (!mEnabled.load()) return;
ATRACE_CALL();
@@ -719,16 +768,18 @@ void TimeStats::setPresentFence(int32_t layerId, uint64_t frameNumber,
layerRecord.waitData++;
}
- flushAvailableRecordsToStatsLocked(layerId);
+ flushAvailableRecordsToStatsLocked(layerId, displayRefreshRate, renderRate);
}
+static const constexpr int32_t kValidJankyReason = JankType::DisplayHAL |
+ JankType::SurfaceFlingerCpuDeadlineMissed | JankType::SurfaceFlingerGpuDeadlineMissed |
+ JankType::AppDeadlineMissed | JankType::PredictionError |
+ JankType::SurfaceFlingerScheduling | JankType::BufferStuffing;
+
template <class T>
static void updateJankPayload(T& t, int32_t reasons) {
t.jankPayload.totalFrames++;
- static const constexpr int32_t kValidJankyReason = JankType::SurfaceFlingerCpuDeadlineMissed |
- JankType::SurfaceFlingerGpuDeadlineMissed | JankType::AppDeadlineMissed |
- JankType::DisplayHAL;
if (reasons & kValidJankyReason) {
t.jankPayload.totalJankyFrames++;
if ((reasons & JankType::SurfaceFlingerCpuDeadlineMissed) != 0) {
@@ -743,19 +794,19 @@ static void updateJankPayload(T& t, int32_t reasons) {
if ((reasons & JankType::AppDeadlineMissed) != 0) {
t.jankPayload.totalAppUnattributed++;
}
+ if ((reasons & JankType::PredictionError) != 0) {
+ t.jankPayload.totalSFPredictionError++;
+ }
+ if ((reasons & JankType::SurfaceFlingerScheduling) != 0) {
+ t.jankPayload.totalSFScheduling++;
+ }
+ if ((reasons & JankType::BufferStuffing) != 0) {
+ t.jankPayload.totalAppBufferStuffing++;
+ }
}
}
-void TimeStats::incrementJankyFrames(int32_t reasons) {
- if (!mEnabled.load()) return;
-
- ATRACE_CALL();
- std::lock_guard<std::mutex> lock(mMutex);
-
- updateJankPayload<TimeStatsHelper::TimeStatsGlobal>(mTimeStats, reasons);
-}
-
-void TimeStats::incrementJankyFrames(uid_t uid, const std::string& layerName, int32_t reasons) {
+void TimeStats::incrementJankyFrames(const JankyFramesInfo& info) {
if (!mEnabled.load()) return;
ATRACE_CALL();
@@ -772,17 +823,44 @@ void TimeStats::incrementJankyFrames(uid_t uid, const std::string& layerName, in
// TimeStats will flush the first present fence for a layer *before* FrameTimeline does so that
// the first jank record is not dropped.
- bool useDefaultLayerKey = false;
static const std::string kDefaultLayerName = "none";
- if (!mTimeStats.stats.count({uid, layerName})) {
- mTimeStats.stats[{uid, kDefaultLayerName}].uid = uid;
- mTimeStats.stats[{uid, kDefaultLayerName}].layerName = kDefaultLayerName;
- useDefaultLayerKey = true;
+
+ const int32_t refreshRateBucket =
+ clampToSmallestBucket(info.refreshRate, REFRESH_RATE_BUCKET_WIDTH);
+ const int32_t renderRateBucket =
+ clampToSmallestBucket(info.renderRate ? *info.renderRate : info.refreshRate,
+ RENDER_RATE_BUCKET_WIDTH);
+ const TimeStatsHelper::TimelineStatsKey timelineKey = {refreshRateBucket, renderRateBucket};
+
+ if (!mTimeStats.stats.count(timelineKey)) {
+ mTimeStats.stats[timelineKey].key = timelineKey;
}
- TimeStatsHelper::TimeStatsLayer& timeStatsLayer =
- mTimeStats.stats[{uid, useDefaultLayerKey ? kDefaultLayerName : layerName}];
- updateJankPayload<TimeStatsHelper::TimeStatsLayer>(timeStatsLayer, reasons);
+ TimeStatsHelper::TimelineStats& timelineStats = mTimeStats.stats[timelineKey];
+
+ updateJankPayload<TimeStatsHelper::TimelineStats>(timelineStats, info.reasons);
+
+ TimeStatsHelper::LayerStatsKey layerKey = {info.uid, info.layerName};
+ if (!timelineStats.stats.count(layerKey)) {
+ layerKey = {info.uid, kDefaultLayerName};
+ timelineStats.stats[layerKey].displayRefreshRateBucket = refreshRateBucket;
+ timelineStats.stats[layerKey].renderRateBucket = renderRateBucket;
+ timelineStats.stats[layerKey].uid = info.uid;
+ timelineStats.stats[layerKey].layerName = kDefaultLayerName;
+ }
+
+ TimeStatsHelper::TimeStatsLayer& timeStatsLayer = timelineStats.stats[layerKey];
+ updateJankPayload<TimeStatsHelper::TimeStatsLayer>(timeStatsLayer, info.reasons);
+
+ if (info.reasons & kValidJankyReason) {
+ // TimeStats Histograms only retain positive values, so we don't need to check if these
+ // deadlines were really missed if we know that the frame had jank, since deadlines
+ // that were met will be dropped.
+ timelineStats.displayDeadlineDeltas.insert(static_cast<int32_t>(info.displayDeadlineDelta));
+ timelineStats.displayPresentDeltas.insert(static_cast<int32_t>(info.displayPresentJitter));
+ timeStatsLayer.deltas["appDeadlineDeltas"].insert(
+ static_cast<int32_t>(info.appDeadlineDelta));
+ }
}
void TimeStats::onDestroy(int32_t layerId) {
@@ -823,7 +901,7 @@ void TimeStats::flushPowerTimeLocked() {
switch (mPowerTime.powerMode) {
case PowerMode::ON:
- mTimeStats.displayOnTime += elapsedTime;
+ mTimeStats.displayOnTimeLegacy += elapsedTime;
break;
case PowerMode::OFF:
case PowerMode::DOZE:
@@ -852,10 +930,10 @@ void TimeStats::setPowerMode(PowerMode powerMode) {
void TimeStats::recordRefreshRate(uint32_t fps, nsecs_t duration) {
std::lock_guard<std::mutex> lock(mMutex);
- if (mTimeStats.refreshRateStats.count(fps)) {
- mTimeStats.refreshRateStats[fps] += duration;
+ if (mTimeStats.refreshRateStatsLegacy.count(fps)) {
+ mTimeStats.refreshRateStatsLegacy[fps] += duration;
} else {
- mTimeStats.refreshRateStats.insert({fps, duration});
+ mTimeStats.refreshRateStatsLegacy.insert({fps, duration});
}
}
@@ -881,7 +959,7 @@ void TimeStats::flushAvailableGlobalRecordsToStatsLocked() {
msBetween(mGlobalRecord.prevPresentTime, curPresentTime);
ALOGV("Global present2present[%d] prev[%" PRId64 "] curr[%" PRId64 "]",
presentToPresentMs, mGlobalRecord.prevPresentTime, curPresentTime);
- mTimeStats.presentToPresent.insert(presentToPresentMs);
+ mTimeStats.presentToPresentLegacy.insert(presentToPresentMs);
}
mGlobalRecord.prevPresentTime = curPresentTime;
@@ -908,7 +986,7 @@ void TimeStats::flushAvailableGlobalRecordsToStatsLocked() {
}
const int32_t renderEngineMs = msBetween(duration.startTime, endNs);
- mTimeStats.renderEngineTiming.insert(renderEngineMs);
+ mTimeStats.renderEngineTimingLegacy.insert(renderEngineMs);
mGlobalRecord.renderEngineDurations.pop_front();
}
@@ -951,7 +1029,7 @@ void TimeStats::enable() {
std::lock_guard<std::mutex> lock(mMutex);
mEnabled.store(true);
- mTimeStats.statsStart = static_cast<int64_t>(std::time(0));
+ mTimeStats.statsStartLegacy = static_cast<int64_t>(std::time(0));
mPowerTime.prevTime = systemTime();
ALOGD("Enabled");
}
@@ -964,7 +1042,7 @@ void TimeStats::disable() {
std::lock_guard<std::mutex> lock(mMutex);
flushPowerTimeLocked();
mEnabled.store(false);
- mTimeStats.statsEnd = static_cast<int64_t>(std::time(0));
+ mTimeStats.statsEndLegacy = static_cast<int64_t>(std::time(0));
ALOGD("Disabled");
}
@@ -977,21 +1055,20 @@ void TimeStats::clearAll() {
void TimeStats::clearGlobalLocked() {
ATRACE_CALL();
- mTimeStats.statsStart = (mEnabled.load() ? static_cast<int64_t>(std::time(0)) : 0);
- mTimeStats.statsEnd = 0;
- mTimeStats.totalFrames = 0;
- mTimeStats.missedFrames = 0;
- mTimeStats.clientCompositionFrames = 0;
- mTimeStats.clientCompositionReusedFrames = 0;
- mTimeStats.refreshRateSwitches = 0;
- mTimeStats.compositionStrategyChanges = 0;
- mTimeStats.displayEventConnectionsCount = 0;
- mTimeStats.displayOnTime = 0;
- mTimeStats.presentToPresent.hist.clear();
- mTimeStats.frameDuration.hist.clear();
- mTimeStats.renderEngineTiming.hist.clear();
- mTimeStats.jankPayload = TimeStatsHelper::JankPayload();
- mTimeStats.refreshRateStats.clear();
+ mTimeStats.statsStartLegacy = (mEnabled.load() ? static_cast<int64_t>(std::time(0)) : 0);
+ mTimeStats.statsEndLegacy = 0;
+ mTimeStats.totalFramesLegacy = 0;
+ mTimeStats.missedFramesLegacy = 0;
+ mTimeStats.clientCompositionFramesLegacy = 0;
+ mTimeStats.clientCompositionReusedFramesLegacy = 0;
+ mTimeStats.refreshRateSwitchesLegacy = 0;
+ mTimeStats.compositionStrategyChangesLegacy = 0;
+ mTimeStats.displayEventConnectionsCountLegacy = 0;
+ mTimeStats.displayOnTimeLegacy = 0;
+ mTimeStats.presentToPresentLegacy.hist.clear();
+ mTimeStats.frameDurationLegacy.hist.clear();
+ mTimeStats.renderEngineTimingLegacy.hist.clear();
+ mTimeStats.refreshRateStatsLegacy.clear();
mPowerTime.prevTime = systemTime();
mGlobalRecord.prevPresentTime = 0;
mGlobalRecord.presentFences.clear();
@@ -1014,11 +1091,11 @@ void TimeStats::dump(bool asProto, std::optional<uint32_t> maxLayers, std::strin
ATRACE_CALL();
std::lock_guard<std::mutex> lock(mMutex);
- if (mTimeStats.statsStart == 0) {
+ if (mTimeStats.statsStartLegacy == 0) {
return;
}
- mTimeStats.statsEnd = static_cast<int64_t>(std::time(0));
+ mTimeStats.statsEndLegacy = static_cast<int64_t>(std::time(0));
flushPowerTimeLocked();
diff --git a/services/surfaceflinger/TimeStats/TimeStats.h b/services/surfaceflinger/TimeStats/TimeStats.h
index df40ef6933..fd112b95b0 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.h
+++ b/services/surfaceflinger/TimeStats/TimeStats.h
@@ -27,12 +27,13 @@
// TODO(b/129481165): remove the #pragma below and fix conversion issues
#pragma clang diagnostic pop // ignored "-Wconversion -Wextra"
+#include <../Fps.h>
+#include <gui/JankInfo.h>
#include <stats_event.h>
#include <stats_pull_atom_callback.h>
#include <statslog.h>
#include <timestatsproto/TimeStatsHelper.h>
#include <timestatsproto/TimeStatsProtoHeader.h>
-#include <gui/JankInfo.h>
#include <ui/FenceTime.h>
#include <utils/String16.h>
#include <utils/Vector.h>
@@ -108,23 +109,60 @@ public:
const std::shared_ptr<FenceTime>& acquireFence) = 0;
// SetPresent{Time, Fence} are not expected to be called in the critical
// rendering path, as they flush prior fences if those fences have fired.
- virtual void setPresentTime(int32_t layerId, uint64_t frameNumber, nsecs_t presentTime) = 0;
+ virtual void setPresentTime(int32_t layerId, uint64_t frameNumber, nsecs_t presentTime,
+ Fps displayRefreshRate, std::optional<Fps> renderRate) = 0;
virtual void setPresentFence(int32_t layerId, uint64_t frameNumber,
- const std::shared_ptr<FenceTime>& presentFence) = 0;
-
- // Increments janky frames, tracked globally. Because FrameTimeline is the infrastructure
- // responsible for computing jank in the system, this is expected to be called from
- // FrameTimeline, rather than directly from SurfaceFlinger or individual layers. If there are no
- // jank reasons, then total frames are incremented but jank is not, for accurate accounting of
- // janky frames.
- virtual void incrementJankyFrames(int32_t reasons) = 0;
- // Increments janky frames, blamed to the provided {uid, layerName} key, with JankMetadata as
- // supplementary reasons for the jank. Because FrameTimeline is the infrastructure responsible
- // for computing jank in the system, this is expected to be called from FrameTimeline, rather
- // than directly from SurfaceFlinger or individual layers.
- // If there are no jank reasons, then total frames are incremented but jank is not, for accurate
+ const std::shared_ptr<FenceTime>& presentFence,
+ Fps displayRefreshRate, std::optional<Fps> renderRate) = 0;
+
+ // Increments janky frames, blamed to the provided {refreshRate, renderRate, uid, layerName}
+ // key, with JankMetadata as supplementary reasons for the jank. Because FrameTimeline is the
+ // infrastructure responsible for computing jank in the system, this is expected to be called
+ // from FrameTimeline, rather than directly from SurfaceFlinger or individual layers. If there
+ // are no jank reasons, then total frames are incremented but jank is not, for accurate
// accounting of janky frames.
- virtual void incrementJankyFrames(uid_t uid, const std::string& layerName, int32_t reasons) = 0;
+ // displayDeadlineDelta, displayPresentJitter, and appDeadlineDelta are also provided in order
+ // to provide contextual information about a janky frame. These values may only be uploaded if
+ // there was an associated valid jank reason, and they must be positive. When these frame counts
+ // are incremented, these are also aggregated into a global reporting packet to help with data
+ // validation and assessing of overall device health.
+ struct JankyFramesInfo {
+ Fps refreshRate;
+ std::optional<Fps> renderRate;
+ uid_t uid = 0;
+ std::string layerName;
+ int32_t reasons = 0;
+ nsecs_t displayDeadlineDelta = 0;
+ nsecs_t displayPresentJitter = 0;
+ nsecs_t appDeadlineDelta = 0;
+
+ bool operator==(const JankyFramesInfo& o) const {
+ return Fps::EqualsInBuckets{}(refreshRate, o.refreshRate) &&
+ ((renderRate == std::nullopt && o.renderRate == std::nullopt) ||
+ (renderRate != std::nullopt && o.renderRate != std::nullopt &&
+ Fps::EqualsInBuckets{}(*renderRate, *o.renderRate))) &&
+ uid == o.uid && layerName == o.layerName && reasons == o.reasons &&
+ displayDeadlineDelta == o.displayDeadlineDelta &&
+ displayPresentJitter == o.displayPresentJitter &&
+ appDeadlineDelta == o.appDeadlineDelta;
+ }
+
+ friend std::ostream& operator<<(std::ostream& os, const JankyFramesInfo& info) {
+ os << "JankyFramesInfo {";
+ os << "\n .refreshRate = " << info.refreshRate;
+ os << "\n .renderRate = "
+ << (info.renderRate ? to_string(*info.renderRate) : "nullopt");
+ os << "\n .uid = " << info.uid;
+ os << "\n .layerName = " << info.layerName;
+ os << "\n .reasons = " << info.reasons;
+ os << "\n .displayDeadlineDelta = " << info.displayDeadlineDelta;
+ os << "\n .displayPresentJitter = " << info.displayPresentJitter;
+ os << "\n .appDeadlineDelta = " << info.appDeadlineDelta;
+ return os << "\n}";
+ }
+ };
+
+ virtual void incrementJankyFrames(const JankyFramesInfo& info) = 0;
// Clean up the layer record
virtual void onDestroy(int32_t layerId) = 0;
// If SF skips or rejects a buffer, remove the corresponding TimeRecord.
@@ -268,11 +306,13 @@ public:
void setAcquireTime(int32_t layerId, uint64_t frameNumber, nsecs_t acquireTime) override;
void setAcquireFence(int32_t layerId, uint64_t frameNumber,
const std::shared_ptr<FenceTime>& acquireFence) override;
- void setPresentTime(int32_t layerId, uint64_t frameNumber, nsecs_t presentTime) override;
+ void setPresentTime(int32_t layerId, uint64_t frameNumber, nsecs_t presentTime,
+ Fps displayRefreshRate, std::optional<Fps> renderRate) override;
void setPresentFence(int32_t layerId, uint64_t frameNumber,
- const std::shared_ptr<FenceTime>& presentFence) override;
- void incrementJankyFrames(int32_t reasons) override;
- void incrementJankyFrames(uid_t uid, const std::string& layerName, int32_t reasons) override;
+ const std::shared_ptr<FenceTime>& presentFence, Fps displayRefreshRate,
+ std::optional<Fps> renderRate) override;
+
+ void incrementJankyFrames(const JankyFramesInfo& info) override;
// Clean up the layer record
void onDestroy(int32_t layerId) override;
// If SF skips or rejects a buffer, remove the corresponding TimeRecord.
@@ -293,7 +333,8 @@ private:
AStatsManager_PullAtomCallbackReturn populateGlobalAtom(AStatsEventList* data);
AStatsManager_PullAtomCallbackReturn populateLayerAtom(AStatsEventList* data);
bool recordReadyLocked(int32_t layerId, TimeRecord* timeRecord);
- void flushAvailableRecordsToStatsLocked(int32_t layerId);
+ void flushAvailableRecordsToStatsLocked(int32_t layerId, Fps displayRefreshRate,
+ std::optional<Fps> renderRate);
void flushPowerTimeLocked();
void flushAvailableGlobalRecordsToStatsLocked();
bool canAddNewAggregatedStats(uid_t uid, const std::string& layerName);
@@ -314,6 +355,9 @@ private:
GlobalRecord mGlobalRecord;
static const size_t MAX_NUM_LAYER_RECORDS = 200;
+
+ static const size_t REFRESH_RATE_BUCKET_WIDTH = 30;
+ static const size_t RENDER_RATE_BUCKET_WIDTH = REFRESH_RATE_BUCKET_WIDTH;
static const size_t MAX_NUM_LAYER_STATS = 200;
static const size_t MAX_NUM_PULLED_LAYERS = MAX_NUM_LAYER_STATS;
std::unique_ptr<StatsEventDelegate> mStatsDelegate = std::make_unique<StatsEventDelegate>();
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/Android.bp b/services/surfaceflinger/TimeStats/timestatsproto/Android.bp
index 9481cac34d..972edaa30b 100644
--- a/services/surfaceflinger/TimeStats/timestatsproto/Android.bp
+++ b/services/surfaceflinger/TimeStats/timestatsproto/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library {
name: "libtimestats_proto",
export_include_dirs: ["include"],
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
index 0fb748f1a6..d116b02d11 100644
--- a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
+++ b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
@@ -41,7 +41,7 @@ void TimeStatsHelper::Histogram::insert(int32_t delta) {
if (delta < 0) return;
// std::lower_bound won't work on out of range values
if (delta > histogramConfig[HISTOGRAM_SIZE - 1]) {
- hist[histogramConfig[HISTOGRAM_SIZE - 1]] += delta / histogramConfig[HISTOGRAM_SIZE - 1];
+ hist[histogramConfig[HISTOGRAM_SIZE - 1]]++;
return;
}
auto iter = std::lower_bound(histogramConfig.begin(), histogramConfig.end(), delta);
@@ -83,13 +83,18 @@ std::string TimeStatsHelper::JankPayload::toString() const {
StringAppendF(&result, "jankyFrames = %d\n", totalJankyFrames);
StringAppendF(&result, "sfLongCpuJankyFrames = %d\n", totalSFLongCpu);
StringAppendF(&result, "sfLongGpuJankyFrames = %d\n", totalSFLongGpu);
- StringAppendF(&result, "sfUnattributedJankyFrame = %d\n", totalSFUnattributed);
- StringAppendF(&result, "appUnattributedJankyFrame = %d\n", totalAppUnattributed);
+ StringAppendF(&result, "sfUnattributedJankyFrames = %d\n", totalSFUnattributed);
+ StringAppendF(&result, "appUnattributedJankyFrames = %d\n", totalAppUnattributed);
+ StringAppendF(&result, "sfSchedulingJankyFrames = %d\n", totalSFScheduling);
+ StringAppendF(&result, "sfPredictionErrorJankyFrames = %d\n", totalSFPredictionError);
+ StringAppendF(&result, "appBufferStuffingJankyFrames = %d\n", totalAppBufferStuffing);
return result;
}
std::string TimeStatsHelper::TimeStatsLayer::toString() const {
std::string result = "\n";
+ StringAppendF(&result, "displayRefreshRate = %d fps\n", displayRefreshRateBucket);
+ StringAppendF(&result, "renderRate = %d fps\n", renderRateBucket);
StringAppendF(&result, "uid = %d\n", uid);
StringAppendF(&result, "layerName = %s\n", layerName.c_str());
StringAppendF(&result, "packageName = %s\n", packageName.c_str());
@@ -115,35 +120,49 @@ std::string TimeStatsHelper::TimeStatsLayer::toString() const {
std::string TimeStatsHelper::TimeStatsGlobal::toString(std::optional<uint32_t> maxLayers) const {
std::string result = "SurfaceFlinger TimeStats:\n";
- StringAppendF(&result, "statsStart = %" PRId64 "\n", statsStart);
- StringAppendF(&result, "statsEnd = %" PRId64 "\n", statsEnd);
- StringAppendF(&result, "totalFrames = %d\n", totalFrames);
- StringAppendF(&result, "missedFrames = %d\n", missedFrames);
- StringAppendF(&result, "clientCompositionFrames = %d\n", clientCompositionFrames);
- StringAppendF(&result, "clientCompositionReusedFrames = %d\n", clientCompositionReusedFrames);
- StringAppendF(&result, "refreshRateSwitches = %d\n", refreshRateSwitches);
- StringAppendF(&result, "compositionStrategyChanges = %d\n", compositionStrategyChanges);
- StringAppendF(&result, "displayOnTime = %" PRId64 " ms\n", displayOnTime);
- result.append("Global aggregated jank payload:\n");
- result.append(jankPayload.toString());
+ result.append("Legacy stats are as follows:\n");
+ StringAppendF(&result, "statsStart = %" PRId64 "\n", statsStartLegacy);
+ StringAppendF(&result, "statsEnd = %" PRId64 "\n", statsEndLegacy);
+ StringAppendF(&result, "totalFrames = %d\n", totalFramesLegacy);
+ StringAppendF(&result, "missedFrames = %d\n", missedFramesLegacy);
+ StringAppendF(&result, "clientCompositionFrames = %d\n", clientCompositionFramesLegacy);
+ StringAppendF(&result, "clientCompositionReusedFrames = %d\n",
+ clientCompositionReusedFramesLegacy);
+ StringAppendF(&result, "refreshRateSwitches = %d\n", refreshRateSwitchesLegacy);
+ StringAppendF(&result, "compositionStrategyChanges = %d\n", compositionStrategyChangesLegacy);
+ StringAppendF(&result, "displayOnTime = %" PRId64 " ms\n", displayOnTimeLegacy);
StringAppendF(&result, "displayConfigStats is as below:\n");
- for (const auto& [fps, duration] : refreshRateStats) {
+ for (const auto& [fps, duration] : refreshRateStatsLegacy) {
StringAppendF(&result, "%dfps = %ldms\n", fps, ns2ms(duration));
}
result.back() = '\n';
- StringAppendF(&result, "totalP2PTime = %" PRId64 " ms\n", presentToPresent.totalTime());
+ StringAppendF(&result, "totalP2PTime = %" PRId64 " ms\n", presentToPresentLegacy.totalTime());
StringAppendF(&result, "presentToPresent histogram is as below:\n");
- result.append(presentToPresent.toString());
- const float averageFrameDuration = frameDuration.averageTime();
+ result.append(presentToPresentLegacy.toString());
+ const float averageFrameDuration = frameDurationLegacy.averageTime();
StringAppendF(&result, "averageFrameDuration = %.3f ms\n",
std::isnan(averageFrameDuration) ? 0.0f : averageFrameDuration);
StringAppendF(&result, "frameDuration histogram is as below:\n");
- result.append(frameDuration.toString());
- const float averageRenderEngineTiming = renderEngineTiming.averageTime();
+ result.append(frameDurationLegacy.toString());
+ const float averageRenderEngineTiming = renderEngineTimingLegacy.averageTime();
StringAppendF(&result, "averageRenderEngineTiming = %.3f ms\n",
std::isnan(averageRenderEngineTiming) ? 0.0f : averageRenderEngineTiming);
StringAppendF(&result, "renderEngineTiming histogram is as below:\n");
- result.append(renderEngineTiming.toString());
+ result.append(renderEngineTimingLegacy.toString());
+
+ result.append("\nGlobal aggregated jank payload (Timeline stats):");
+ for (const auto& ele : stats) {
+ result.append("\n");
+ StringAppendF(&result, "displayRefreshRate = %d fps\n",
+ ele.second.key.displayRefreshRateBucket);
+ StringAppendF(&result, "renderRate = %d fps\n", ele.second.key.renderRateBucket);
+ result.append(ele.second.jankPayload.toString());
+ StringAppendF(&result, "sfDeadlineMisses histogram is as below:\n");
+ result.append(ele.second.displayDeadlineDeltas.toString());
+ StringAppendF(&result, "sfPredictionErrors histogram is as below:\n");
+ result.append(ele.second.displayPresentDeltas.toString());
+ }
+
const auto dumpStats = generateDumpStats(maxLayers);
for (const auto& ele : dumpStats) {
result.append(ele->toString());
@@ -173,30 +192,30 @@ SFTimeStatsLayerProto TimeStatsHelper::TimeStatsLayer::toProto() const {
SFTimeStatsGlobalProto TimeStatsHelper::TimeStatsGlobal::toProto(
std::optional<uint32_t> maxLayers) const {
SFTimeStatsGlobalProto globalProto;
- globalProto.set_stats_start(statsStart);
- globalProto.set_stats_end(statsEnd);
- globalProto.set_total_frames(totalFrames);
- globalProto.set_missed_frames(missedFrames);
- globalProto.set_client_composition_frames(clientCompositionFrames);
- globalProto.set_display_on_time(displayOnTime);
- for (const auto& ele : refreshRateStats) {
+ globalProto.set_stats_start(statsStartLegacy);
+ globalProto.set_stats_end(statsEndLegacy);
+ globalProto.set_total_frames(totalFramesLegacy);
+ globalProto.set_missed_frames(missedFramesLegacy);
+ globalProto.set_client_composition_frames(clientCompositionFramesLegacy);
+ globalProto.set_display_on_time(displayOnTimeLegacy);
+ for (const auto& ele : refreshRateStatsLegacy) {
SFTimeStatsDisplayConfigBucketProto* configBucketProto =
globalProto.add_display_config_stats();
SFTimeStatsDisplayConfigProto* configProto = configBucketProto->mutable_config();
configProto->set_fps(ele.first);
configBucketProto->set_duration_millis(ns2ms(ele.second));
}
- for (const auto& histEle : presentToPresent.hist) {
+ for (const auto& histEle : presentToPresentLegacy.hist) {
SFTimeStatsHistogramBucketProto* histProto = globalProto.add_present_to_present();
histProto->set_time_millis(histEle.first);
histProto->set_frame_count(histEle.second);
}
- for (const auto& histEle : frameDuration.hist) {
+ for (const auto& histEle : frameDurationLegacy.hist) {
SFTimeStatsHistogramBucketProto* histProto = globalProto.add_frame_duration();
histProto->set_time_millis(histEle.first);
histProto->set_frame_count(histEle.second);
}
- for (const auto& histEle : renderEngineTiming.hist) {
+ for (const auto& histEle : renderEngineTimingLegacy.hist) {
SFTimeStatsHistogramBucketProto* histProto = globalProto.add_render_engine_timing();
histProto->set_time_millis(histEle.first);
histProto->set_frame_count(histEle.second);
@@ -212,8 +231,18 @@ SFTimeStatsGlobalProto TimeStatsHelper::TimeStatsGlobal::toProto(
std::vector<TimeStatsHelper::TimeStatsLayer const*>
TimeStatsHelper::TimeStatsGlobal::generateDumpStats(std::optional<uint32_t> maxLayers) const {
std::vector<TimeStatsLayer const*> dumpStats;
+
+ int numLayers = 0;
+ for (const auto& ele : stats) {
+ numLayers += ele.second.stats.size();
+ }
+
+ dumpStats.reserve(numLayers);
+
for (const auto& ele : stats) {
- dumpStats.push_back(&ele.second);
+ for (const auto& layerEle : ele.second.stats) {
+ dumpStats.push_back(&layerEle.second);
+ }
}
std::sort(dumpStats.begin(), dumpStats.end(),
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
index 033eb5dcd9..4556badf7b 100644
--- a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
+++ b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
@@ -48,6 +48,9 @@ public:
int32_t totalSFLongGpu = 0;
int32_t totalSFUnattributed = 0;
int32_t totalAppUnattributed = 0;
+ int32_t totalSFScheduling = 0;
+ int32_t totalSFPredictionError = 0;
+ int32_t totalAppBufferStuffing = 0;
std::string toString() const;
};
@@ -57,6 +60,8 @@ public:
uid_t uid;
std::string layerName;
std::string packageName;
+ int32_t displayRefreshRateBucket = 0;
+ int32_t renderRateBucket = 0;
int32_t totalFrames = 0;
int32_t droppedFrames = 0;
int32_t lateAcquireFrames = 0;
@@ -68,32 +73,84 @@ public:
SFTimeStatsLayerProto toProto() const;
};
- class TimeStatsGlobal {
- public:
- int64_t statsStart = 0;
- int64_t statsEnd = 0;
- int32_t totalFrames = 0;
- int32_t missedFrames = 0;
- int32_t clientCompositionFrames = 0;
- int32_t clientCompositionReusedFrames = 0;
- int32_t refreshRateSwitches = 0;
- int32_t compositionStrategyChanges = 0;
- int32_t displayEventConnectionsCount = 0;
- int64_t displayOnTime = 0;
- Histogram presentToPresent;
- Histogram frameDuration;
- Histogram renderEngineTiming;
-
- struct StatsHasher {
- size_t operator()(const std::pair<uid_t, std::string>& p) const {
- // Normally this isn't a very good hash function due to symmetry reasons,
- // but these are distinct types so this should be good enough
- return std::hash<uid_t>{}(p.first) ^ std::hash<std::string>{}(p.second);
+ // Lifted from SkiaGLRenderEngine's LinearEffect class.
+ // Which in turn was inspired by art/runtime/class_linker.cc
+ // Also this is what boost:hash_combine does so this is a pretty good hash.
+ static size_t HashCombine(size_t seed, size_t val) {
+ return seed ^ (val + 0x9e3779b9 + (seed << 6) + (seed >> 2));
+ }
+
+ struct TimelineStatsKey {
+ int32_t displayRefreshRateBucket = 0;
+ int32_t renderRateBucket = 0;
+
+ struct Hasher {
+ size_t operator()(const TimelineStatsKey& key) const {
+ size_t result = std::hash<int32_t>{}(key.displayRefreshRateBucket);
+ return HashCombine(result, std::hash<int32_t>{}(key.renderRateBucket));
+ }
+ };
+
+ bool operator==(const TimelineStatsKey& o) const {
+ return displayRefreshRateBucket == o.displayRefreshRateBucket &&
+ renderRateBucket == o.renderRateBucket;
+ }
+ };
+
+ struct LayerStatsKey {
+ uid_t uid = 0;
+ std::string layerName;
+
+ struct Hasher {
+ size_t operator()(const LayerStatsKey& key) const {
+ size_t result = std::hash<uid_t>{}(key.uid);
+ return HashCombine(result, std::hash<std::string>{}(key.layerName));
}
};
- std::unordered_map<std::pair<uid_t, std::string>, TimeStatsLayer, StatsHasher> stats;
- std::unordered_map<uint32_t, nsecs_t> refreshRateStats;
+
+ bool operator==(const LayerStatsKey& o) const {
+ return uid == o.uid && layerName == o.layerName;
+ }
+ };
+
+ struct LayerStatsHasher {
+ size_t operator()(const std::pair<uid_t, std::string>& p) const {
+ // Normally this isn't a very good hash function due to symmetry reasons,
+ // but these are distinct types so this should be good enough
+ return std::hash<uid_t>{}(p.first) ^ std::hash<std::string>{}(p.second);
+ }
+ };
+
+ struct TimelineStats {
+ TimelineStatsKey key;
JankPayload jankPayload;
+ Histogram displayDeadlineDeltas;
+ Histogram displayPresentDeltas;
+ std::unordered_map<LayerStatsKey, TimeStatsLayer, LayerStatsKey::Hasher> stats;
+ };
+
+ class TimeStatsGlobal {
+ public:
+ // Note: these are all legacy statistics, we're keeping these around because a variety of
+ // systems and form-factors find these useful when comparing with older releases. However,
+ // the current recommendation is that the new timeline-based metrics are used, and the old
+ // ones are deprecated.
+ int64_t statsStartLegacy = 0;
+ int64_t statsEndLegacy = 0;
+ int32_t totalFramesLegacy = 0;
+ int32_t missedFramesLegacy = 0;
+ int32_t clientCompositionFramesLegacy = 0;
+ int32_t clientCompositionReusedFramesLegacy = 0;
+ int32_t refreshRateSwitchesLegacy = 0;
+ int32_t compositionStrategyChangesLegacy = 0;
+ int32_t displayEventConnectionsCountLegacy = 0;
+ int64_t displayOnTimeLegacy = 0;
+ Histogram presentToPresentLegacy;
+ Histogram frameDurationLegacy;
+ Histogram renderEngineTimingLegacy;
+ std::unordered_map<uint32_t, nsecs_t> refreshRateStatsLegacy;
+
+ std::unordered_map<TimelineStatsKey, TimelineStats, TimelineStatsKey::Hasher> stats;
std::string toString(std::optional<uint32_t> maxLayers) const;
SFTimeStatsGlobalProto toProto(std::optional<uint32_t> maxLayers) const;
diff --git a/services/surfaceflinger/layerproto/Android.bp b/services/surfaceflinger/layerproto/Android.bp
index e2a28a2ae5..c8a2b5eed6 100644
--- a/services/surfaceflinger/layerproto/Android.bp
+++ b/services/surfaceflinger/layerproto/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library {
name: "liblayers_proto",
export_include_dirs: ["include"],
diff --git a/services/surfaceflinger/sysprop/Android.bp b/services/surfaceflinger/sysprop/Android.bp
index 7721d7d2b7..f5791195db 100644
--- a/services/surfaceflinger/sysprop/Android.bp
+++ b/services/surfaceflinger/sysprop/Android.bp
@@ -1,3 +1,12 @@
+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: "SurfaceFlingerProperties",
srcs: ["*.sysprop"],
diff --git a/services/surfaceflinger/tests/Android.bp b/services/surfaceflinger/tests/Android.bp
index 8142aad382..78187f7e9d 100644
--- a/services/surfaceflinger/tests/Android.bp
+++ b/services/surfaceflinger/tests/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_test {
name: "SurfaceFlinger_test",
defaults: ["surfaceflinger_defaults"],
diff --git a/services/surfaceflinger/tests/Credentials_test.cpp b/services/surfaceflinger/tests/Credentials_test.cpp
index 53e37d874e..6246321fab 100644
--- a/services/surfaceflinger/tests/Credentials_test.cpp
+++ b/services/surfaceflinger/tests/Credentials_test.cpp
@@ -26,6 +26,7 @@
#include <private/android_filesystem_config.h>
#include <private/gui/ComposerService.h>
#include <ui/DisplayMode.h>
+#include <ui/DynamicDisplayInfo.h>
#include <utils/String8.h>
#include <functional>
#include "utils/ScreenshotUtils.h"
@@ -188,19 +189,15 @@ TEST_F(CredentialsTest, AllowedGetterMethodsTest) {
ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayMode(display, &mode));
Vector<ui::DisplayMode> modes;
- ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayModes(display, &modes));
-
- ASSERT_TRUE(SurfaceComposerClient::getActiveDisplayModeId(display) >= 0);
-
- ASSERT_NE(static_cast<ui::ColorMode>(BAD_VALUE),
- SurfaceComposerClient::getActiveColorMode(display));
+ ui::DynamicDisplayInfo info;
+ ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDynamicDisplayInfo(display, &info));
}
-TEST_F(CredentialsTest, GetDisplayColorModesTest) {
+TEST_F(CredentialsTest, GetDynamicDisplayInfoTest) {
const auto display = SurfaceComposerClient::getInternalDisplayToken();
std::function<status_t()> condition = [=]() {
- Vector<ui::ColorMode> outColorModes;
- return SurfaceComposerClient::getDisplayColorModes(display, &outColorModes);
+ ui::DynamicDisplayInfo info;
+ return SurfaceComposerClient::getDynamicDisplayInfo(display, &info);
};
ASSERT_NO_FATAL_FAILURE(checkWithPrivileges<status_t>(condition, NO_ERROR, NO_ERROR));
}
@@ -216,7 +213,7 @@ TEST_F(CredentialsTest, GetDisplayNativePrimariesTest) {
TEST_F(CredentialsTest, SetDesiredDisplayConfigsTest) {
const auto display = SurfaceComposerClient::getInternalDisplayToken();
- size_t defaultMode;
+ ui::DisplayModeId defaultMode;
bool allowGroupSwitching;
float primaryFpsMin;
float primaryFpsMax;
@@ -355,8 +352,9 @@ TEST_F(CredentialsTest, IsWideColorDisplayBasicCorrectness) {
status_t error = SurfaceComposerClient::isWideColorDisplay(display, &result);
ASSERT_EQ(NO_ERROR, error);
bool hasWideColorMode = false;
- Vector<ColorMode> colorModes;
- SurfaceComposerClient::getDisplayColorModes(display, &colorModes);
+ ui::DynamicDisplayInfo info;
+ SurfaceComposerClient::getDynamicDisplayInfo(display, &info);
+ const auto& colorModes = info.supportedColorModes;
for (ColorMode colorMode : colorModes) {
switch (colorMode) {
case ColorMode::DISPLAY_P3:
@@ -384,7 +382,9 @@ TEST_F(CredentialsTest, IsWideColorDisplayWithPrivileges) {
TEST_F(CredentialsTest, GetActiveColorModeBasicCorrectness) {
const auto display = SurfaceComposerClient::getInternalDisplayToken();
ASSERT_FALSE(display == nullptr);
- ColorMode colorMode = SurfaceComposerClient::getActiveColorMode(display);
+ ui::DynamicDisplayInfo info;
+ SurfaceComposerClient::getDynamicDisplayInfo(display, &info);
+ ColorMode colorMode = info.activeColorMode;
ASSERT_NE(static_cast<ColorMode>(BAD_VALUE), colorMode);
}
diff --git a/services/surfaceflinger/tests/DisplayConfigs_test.cpp b/services/surfaceflinger/tests/DisplayConfigs_test.cpp
index 9f025a6aaa..2dc96b8511 100644
--- a/services/surfaceflinger/tests/DisplayConfigs_test.cpp
+++ b/services/surfaceflinger/tests/DisplayConfigs_test.cpp
@@ -23,6 +23,7 @@
#include <gui/SurfaceComposerClient.h>
#include <private/gui/ComposerService.h>
#include <ui/DisplayMode.h>
+#include <ui/DynamicDisplayInfo.h>
#include <utils/Errors.h>
#include <utils/Vector.h>
@@ -38,7 +39,7 @@ namespace android {
*/
class RefreshRateRangeTest : public ::testing::Test {
private:
- size_t initialDefaultMode;
+ ui::DisplayModeId initialDefaultMode;
bool initialAllowGroupSwitching;
float initialPrimaryMin;
float initialPrimaryMax;
@@ -76,20 +77,21 @@ protected:
};
TEST_F(RefreshRateRangeTest, setAllConfigs) {
- Vector<ui::DisplayMode> modes;
- status_t res = SurfaceComposerClient::getDisplayModes(mDisplayToken, &modes);
+ ui::DynamicDisplayInfo info;
+ status_t res = SurfaceComposerClient::getDynamicDisplayInfo(mDisplayToken, &info);
+ const auto& modes = info.supportedDisplayModes;
ASSERT_EQ(res, NO_ERROR);
ASSERT_GT(modes.size(), 0);
for (size_t i = 0; i < modes.size(); i++) {
- res = SurfaceComposerClient::setDesiredDisplayModeSpecs(mDisplayToken, i, false,
+ res = SurfaceComposerClient::setDesiredDisplayModeSpecs(mDisplayToken, modes[i].id, false,
modes[i].refreshRate,
modes[i].refreshRate,
modes[i].refreshRate,
modes[i].refreshRate);
ASSERT_EQ(res, NO_ERROR);
- size_t defaultConfig;
+ ui::DisplayModeId defaultConfig;
bool allowGroupSwitching;
float primaryRefreshRateMin;
float primaryRefreshRateMax;
@@ -116,7 +118,7 @@ void RefreshRateRangeTest::testSetAllowGroupSwitching(bool allowGroupSwitching)
SurfaceComposerClient::setDesiredDisplayModeSpecs(mDisplayToken, 0, allowGroupSwitching,
0.f, 90.f, 0.f, 90.f);
ASSERT_EQ(res, NO_ERROR);
- size_t defaultConfig;
+ ui::DisplayModeId defaultConfig;
bool newAllowGroupSwitching;
float primaryRefreshRateMin;
float primaryRefreshRateMax;
diff --git a/services/surfaceflinger/tests/fakehwc/Android.bp b/services/surfaceflinger/tests/fakehwc/Android.bp
index 3535fbb1b4..2551a19b71 100644
--- a/services/surfaceflinger/tests/fakehwc/Android.bp
+++ b/services/surfaceflinger/tests/fakehwc/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_test {
name: "sffakehwc_test",
defaults: ["surfaceflinger_defaults"],
diff --git a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
index 56e1ae90c3..11bd9ebbb8 100644
--- a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
+++ b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
@@ -44,6 +44,7 @@
#include <log/log.h>
#include <private/gui/ComposerService.h>
#include <ui/DisplayMode.h>
+#include <ui/DynamicDisplayInfo.h>
#include <utils/Looper.h>
#include <gmock/gmock.h>
@@ -432,8 +433,9 @@ protected:
}
}
- Vector<ui::DisplayMode> modes;
- EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayModes(display, &modes));
+ ui::DynamicDisplayInfo info;
+ EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getDynamicDisplayInfo(display, &info));
+ const auto& modes = info.supportedDisplayModes;
EXPECT_EQ(modes.size(), 2);
// change active mode
@@ -539,8 +541,9 @@ protected:
}
}
- Vector<ui::DisplayMode> modes;
- EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayModes(display, &modes));
+ ui::DynamicDisplayInfo info;
+ EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getDynamicDisplayInfo(display, &info));
+ const auto& modes = info.supportedDisplayModes;
EXPECT_EQ(modes.size(), 2);
// change active mode
@@ -655,8 +658,9 @@ protected:
}
}
- Vector<ui::DisplayMode> modes;
- EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayModes(display, &modes));
+ ui::DynamicDisplayInfo info;
+ EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getDynamicDisplayInfo(display, &info));
+ const auto& modes = info.supportedDisplayModes;
EXPECT_EQ(modes.size(), 4);
// change active mode to 800x1600@90Hz
@@ -884,8 +888,9 @@ protected:
EXPECT_EQ(ui::Size(800, 1600), mode.resolution);
EXPECT_EQ(1e9f / 11'111'111, mode.refreshRate);
- Vector<ui::DisplayMode> modes;
- EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayModes(display, &modes));
+ ui::DynamicDisplayInfo info;
+ EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getDynamicDisplayInfo(display, &info));
+ const auto& modes = info.supportedDisplayModes;
EXPECT_EQ(modes.size(), 1);
}
@@ -923,8 +928,9 @@ protected:
EXPECT_EQ(1e9f / 16'666'666, mode.refreshRate);
}
- Vector<ui::DisplayMode> modes;
- EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayModes(display, &modes));
+ ui::DynamicDisplayInfo info;
+ EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getDynamicDisplayInfo(display, &info));
+ const auto& modes = info.supportedDisplayModes;
EXPECT_EQ(modes.size(), 3);
EXPECT_EQ(ui::Size(800, 1600), modes[0].resolution);
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index 17928a0d61..2ac6b092b5 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_test {
name: "libsurfaceflinger_unittest",
defaults: ["surfaceflinger_defaults"],
@@ -73,6 +82,7 @@ cc_test {
"FrameTracerTest.cpp",
"TimerTest.cpp",
"TransactionApplicationTest.cpp",
+ "TransactionFrameTracerTest.cpp",
"TransactionSurfaceFrameTest.cpp",
"StrongTypingTest.cpp",
"VSyncDispatchTimerQueueTest.cpp",
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index b696a6d51b..256be27b2d 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -286,7 +286,7 @@ struct BaseDisplayVariant {
auto ceDisplayArgs =
compositionengine::DisplayCreationArgsBuilder()
- .setPhysical({DEFAULT_DISPLAY_ID, DisplayConnectionType::Internal})
+ .setPhysical({DEFAULT_DISPLAY_ID, ui::DisplayConnectionType::Internal})
.setPixels({DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT})
.setIsSecure(Derived::IS_SECURE)
.setLayerStackId(DEFAULT_LAYER_STACK)
@@ -300,7 +300,7 @@ struct BaseDisplayVariant {
ceDisplayArgs);
test->mDisplay = FakeDisplayDeviceInjector(test->mFlinger, compositionDisplay,
- DisplayConnectionType::Internal, HWC_DISPLAY,
+ ui::DisplayConnectionType::Internal, HWC_DISPLAY,
true /* isPrimary */)
.setDisplaySurface(test->mDisplaySurface)
.setNativeWindow(test->mNativeWindow)
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index 90692003ef..a3e810871c 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -139,14 +139,14 @@ sp<DisplayDevice> DisplayTransactionTest::injectDefaultInternalDisplay(
createDisplay(mFlinger.getCompositionEngine(),
compositionengine::DisplayCreationArgsBuilder()
.setPhysical(
- {DEFAULT_DISPLAY_ID, DisplayConnectionType::Internal})
+ {DEFAULT_DISPLAY_ID, ui::DisplayConnectionType::Internal})
.setPixels({DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT})
.setPowerAdvisor(&mPowerAdvisor)
.build());
- auto injector =
- FakeDisplayDeviceInjector(mFlinger, compositionDisplay, DisplayConnectionType::Internal,
- DEFAULT_DISPLAY_HWC_DISPLAY_ID, true /* isPrimary */);
+ auto injector = FakeDisplayDeviceInjector(mFlinger, compositionDisplay,
+ ui::DisplayConnectionType::Internal,
+ DEFAULT_DISPLAY_HWC_DISPLAY_ID, true /* isPrimary */);
injector.setNativeWindow(mNativeWindow);
if (injectExtra) {
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
index 166430193d..d68fff6345 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
@@ -202,12 +202,13 @@ struct DisplayIdGetter<GpuVirtualDisplayIdType> {
template <typename>
struct DisplayConnectionTypeGetter {
- static constexpr std::optional<DisplayConnectionType> value;
+ static constexpr std::optional<ui::DisplayConnectionType> value;
};
template <typename PhysicalDisplay>
struct DisplayConnectionTypeGetter<PhysicalDisplayIdType<PhysicalDisplay>> {
- static constexpr std::optional<DisplayConnectionType> value = PhysicalDisplay::CONNECTION_TYPE;
+ static constexpr std::optional<ui::DisplayConnectionType> value =
+ PhysicalDisplay::CONNECTION_TYPE;
};
template <typename>
@@ -263,7 +264,7 @@ struct DisplayVariant {
static auto makeFakeExistingDisplayInjector(DisplayTransactionTest* test) {
auto ceDisplayArgs = compositionengine::DisplayCreationArgsBuilder();
if (auto displayId = PhysicalDisplayId::tryCast(DISPLAY_ID::get())) {
- ceDisplayArgs.setPhysical({*displayId, DisplayConnectionType::Internal});
+ ceDisplayArgs.setPhysical({*displayId, ui::DisplayConnectionType::Internal});
} else {
// We turn off the use of HwcVirtualDisplays, to prevent Composition Engine
// from calling into HWComposer. This way all virtual displays will get
@@ -457,7 +458,7 @@ struct HwcDisplayVariant {
static void setupHwcHotplugCallExpectations(DisplayTransactionTest* test) {
constexpr auto CONNECTION_TYPE =
- PhysicalDisplay::CONNECTION_TYPE == DisplayConnectionType::Internal
+ PhysicalDisplay::CONNECTION_TYPE == ui::DisplayConnectionType::Internal
? IComposerClient::DisplayConnectionType::INTERNAL
: IComposerClient::DisplayConnectionType::EXTERNAL;
@@ -504,7 +505,7 @@ struct PhysicalDisplayVariant
template <bool hasIdentificationData>
struct PrimaryDisplay {
- static constexpr auto CONNECTION_TYPE = DisplayConnectionType::Internal;
+ static constexpr auto CONNECTION_TYPE = ui::DisplayConnectionType::Internal;
static constexpr Primary PRIMARY = Primary::TRUE;
static constexpr uint8_t PORT = 255;
static constexpr HWDisplayId HWC_DISPLAY_ID = 1001;
@@ -514,7 +515,7 @@ struct PrimaryDisplay {
template <bool hasIdentificationData>
struct ExternalDisplay {
- static constexpr auto CONNECTION_TYPE = DisplayConnectionType::External;
+ static constexpr auto CONNECTION_TYPE = ui::DisplayConnectionType::External;
static constexpr Primary PRIMARY = Primary::FALSE;
static constexpr uint8_t PORT = 254;
static constexpr HWDisplayId HWC_DISPLAY_ID = 1002;
diff --git a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
index 6e9f09bdaa..b8c1607562 100644
--- a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
+++ b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
@@ -27,6 +27,7 @@
#include <cinttypes>
using namespace std::chrono_literals;
+using testing::_;
using testing::AtLeast;
using testing::Contains;
using FrameTimelineEvent = perfetto::protos::FrameTimelineEvent;
@@ -40,10 +41,6 @@ using ProtoFrameEnd = perfetto::protos::FrameTimelineEvent_FrameEnd;
using ProtoPresentType = perfetto::protos::FrameTimelineEvent_PresentType;
using ProtoJankType = perfetto::protos::FrameTimelineEvent_JankType;
-MATCHER_P(HasBit, bit, "") {
- return (arg & bit) != 0;
-}
-
namespace android::frametimeline {
class FrameTimelineTest : public testing::Test {
@@ -109,6 +106,7 @@ public:
void addEmptyDisplayFrame() {
auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+ // Trigger a flushPresentFence by calling setSfPresent for the next frame
mFrameTimeline->setSfPresent(2500, presentFence1);
}
@@ -158,12 +156,9 @@ public:
uint32_t* maxDisplayFrames;
nsecs_t maxTokenRetentionTime;
static constexpr pid_t kSurfaceFlingerPid = 666;
- static constexpr nsecs_t kPresentThreshold =
- std::chrono::duration_cast<std::chrono::nanoseconds>(2ns).count();
- static constexpr nsecs_t kDeadlineThreshold =
- std::chrono::duration_cast<std::chrono::nanoseconds>(2ns).count();
- static constexpr nsecs_t kStartThreshold =
- std::chrono::duration_cast<std::chrono::nanoseconds>(2ns).count();
+ static constexpr nsecs_t kPresentThreshold = std::chrono::nanoseconds(2ns).count();
+ static constexpr nsecs_t kDeadlineThreshold = std::chrono::nanoseconds(2ns).count();
+ static constexpr nsecs_t kStartThreshold = std::chrono::nanoseconds(2ns).count();
static constexpr JankClassificationThresholds kTestThresholds{kPresentThreshold,
kDeadlineThreshold,
kStartThreshold};
@@ -237,50 +232,42 @@ TEST_F(FrameTimelineTest, createSurfaceFrameForToken_validInputEventId) {
}
TEST_F(FrameTimelineTest, presentFenceSignaled_droppedFramesNotUpdated) {
- // Global increment
- EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_));
auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
- auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
-
int64_t token1 = mTokenManager->generateTokenForPredictions({10, 20, 30});
- int64_t token2 = mTokenManager->generateTokenForPredictions({40, 50, 60});
auto surfaceFrame1 =
mFrameTimeline->createSurfaceFrameForToken({token1, sInputEventId}, sPidOne, sUidOne,
sLayerNameOne, sLayerNameOne);
// Set up the display frame
- mFrameTimeline->setSfWakeUp(token1, 20, 11);
+ mFrameTimeline->setSfWakeUp(token1, 20, Fps::fromPeriodNsecs(11));
+ surfaceFrame1->setDropTime(12);
surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Dropped);
mFrameTimeline->addSurfaceFrame(surfaceFrame1);
mFrameTimeline->setSfPresent(25, presentFence1);
presentFence1->signalForTest(30);
- // Trigger a flush by calling setSfPresent for the next frame
- mFrameTimeline->setSfWakeUp(token2, 50, 11);
- mFrameTimeline->setSfPresent(55, presentFence2);
+ addEmptyDisplayFrame();
auto& droppedSurfaceFrame = getSurfaceFrame(0, 0);
EXPECT_EQ(droppedSurfaceFrame.getPresentState(), SurfaceFrame::PresentState::Dropped);
+ EXPECT_EQ(0u, droppedSurfaceFrame.getActuals().endTime);
+ EXPECT_EQ(12u, droppedSurfaceFrame.getDropTime());
EXPECT_EQ(droppedSurfaceFrame.getActuals().presentTime, 0);
}
TEST_F(FrameTimelineTest, presentFenceSignaled_presentedFramesUpdated) {
- // Global increment
- EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_));
// Layer specific increment
- EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_, testing::_, testing::_)).Times(2);
+ EXPECT_CALL(*mTimeStats, incrementJankyFrames(_)).Times(2);
auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({10, 20, 30});
- int64_t surfaceFrameToken2 = mTokenManager->generateTokenForPredictions({40, 50, 60});
int64_t sfToken1 = mTokenManager->generateTokenForPredictions({22, 26, 30});
- int64_t sfToken2 = mTokenManager->generateTokenForPredictions({52, 56, 60});
auto surfaceFrame1 =
mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
sUidOne, sLayerNameOne, sLayerNameOne);
auto surfaceFrame2 =
mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
sUidOne, sLayerNameTwo, sLayerNameTwo);
- mFrameTimeline->setSfWakeUp(sfToken1, 22, 11);
+ mFrameTimeline->setSfWakeUp(sfToken1, 22, Fps::fromPeriodNsecs(11));
surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
mFrameTimeline->addSurfaceFrame(surfaceFrame1);
surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented);
@@ -296,16 +283,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_presentedFramesUpdated) {
EXPECT_EQ(presentedSurfaceFrame1.getActuals().presentTime, 0);
EXPECT_EQ(presentedSurfaceFrame2.getActuals().presentTime, 0);
- // Trigger a flush by finalizing the next DisplayFrame
- auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
- auto surfaceFrame3 =
- mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken2, sInputEventId}, sPidOne,
- sUidOne, sLayerNameOne, sLayerNameOne);
- mFrameTimeline->setSfWakeUp(sfToken2, 52, 11);
- surfaceFrame3->setPresentState(SurfaceFrame::PresentState::Dropped);
- mFrameTimeline->addSurfaceFrame(surfaceFrame3);
- mFrameTimeline->setSfPresent(56, presentFence2);
- displayFrame = getDisplayFrame(0);
+ addEmptyDisplayFrame();
// Fences have flushed, so the present timestamps should be updated
EXPECT_EQ(displayFrame->getActuals().presentTime, 42);
@@ -318,11 +296,8 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_presentedFramesUpdated) {
TEST_F(FrameTimelineTest, displayFramesSlidingWindowMovesAfterLimit) {
// Insert kMaxDisplayFrames' count of DisplayFrames to fill the deque
int frameTimeFactor = 0;
- // Global increment
- EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_))
- .Times(static_cast<int32_t>(*maxDisplayFrames));
// Layer specific increment
- EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_, testing::_, testing::_))
+ EXPECT_CALL(*mTimeStats, incrementJankyFrames(_))
.Times(static_cast<int32_t>(*maxDisplayFrames));
for (size_t i = 0; i < *maxDisplayFrames; i++) {
auto presentFence = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
@@ -334,7 +309,7 @@ TEST_F(FrameTimelineTest, displayFramesSlidingWindowMovesAfterLimit) {
mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, sInputEventId},
sPidOne, sUidOne, sLayerNameOne,
sLayerNameOne);
- mFrameTimeline->setSfWakeUp(sfToken, 22 + frameTimeFactor, 11);
+ mFrameTimeline->setSfWakeUp(sfToken, 22 + frameTimeFactor, Fps::fromPeriodNsecs(11));
surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented);
mFrameTimeline->addSurfaceFrame(surfaceFrame);
mFrameTimeline->setSfPresent(27 + frameTimeFactor, presentFence);
@@ -355,7 +330,7 @@ TEST_F(FrameTimelineTest, displayFramesSlidingWindowMovesAfterLimit) {
auto surfaceFrame =
mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, sInputEventId}, sPidOne,
sUidOne, sLayerNameOne, sLayerNameOne);
- mFrameTimeline->setSfWakeUp(sfToken, 22 + frameTimeFactor, 11);
+ mFrameTimeline->setSfWakeUp(sfToken, 22 + frameTimeFactor, Fps::fromPeriodNsecs(11));
surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented);
mFrameTimeline->addSurfaceFrame(surfaceFrame);
mFrameTimeline->setSfPresent(27 + frameTimeFactor, presentFence);
@@ -386,9 +361,6 @@ TEST_F(FrameTimelineTest, surfaceFrameEndTimeAcquireFenceBeforeQueue) {
}
TEST_F(FrameTimelineTest, setMaxDisplayFramesSetsSizeProperly) {
- // Global increment
- EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_))
- .Times(static_cast<int32_t>(*maxDisplayFrames + 10));
auto presentFence = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
presentFence->signalForTest(2);
@@ -398,7 +370,7 @@ TEST_F(FrameTimelineTest, setMaxDisplayFramesSetsSizeProperly) {
mFrameTimeline->createSurfaceFrameForToken({}, sPidOne, sUidOne, sLayerNameOne,
sLayerNameOne);
int64_t sfToken = mTokenManager->generateTokenForPredictions({22, 26, 30});
- mFrameTimeline->setSfWakeUp(sfToken, 22, 11);
+ mFrameTimeline->setSfWakeUp(sfToken, 22, Fps::fromPeriodNsecs(11));
surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented);
mFrameTimeline->addSurfaceFrame(surfaceFrame);
mFrameTimeline->setSfPresent(27, presentFence);
@@ -408,16 +380,13 @@ TEST_F(FrameTimelineTest, setMaxDisplayFramesSetsSizeProperly) {
// Increase the size to 256
mFrameTimeline->setMaxDisplayFrames(256);
EXPECT_EQ(*maxDisplayFrames, 256u);
- // Global increment
- EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_))
- .Times(static_cast<int32_t>(*maxDisplayFrames + 10));
for (size_t i = 0; i < *maxDisplayFrames + 10; i++) {
auto surfaceFrame =
mFrameTimeline->createSurfaceFrameForToken({}, sPidOne, sUidOne, sLayerNameOne,
sLayerNameOne);
int64_t sfToken = mTokenManager->generateTokenForPredictions({22, 26, 30});
- mFrameTimeline->setSfWakeUp(sfToken, 22, 11);
+ mFrameTimeline->setSfWakeUp(sfToken, 22, Fps::fromPeriodNsecs(11));
surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented);
mFrameTimeline->addSurfaceFrame(surfaceFrame);
mFrameTimeline->setSfPresent(27, presentFence);
@@ -427,16 +396,13 @@ TEST_F(FrameTimelineTest, setMaxDisplayFramesSetsSizeProperly) {
// Shrink the size to 128
mFrameTimeline->setMaxDisplayFrames(128);
EXPECT_EQ(*maxDisplayFrames, 128u);
- // Global increment
- EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_))
- .Times(static_cast<int32_t>(*maxDisplayFrames + 10));
for (size_t i = 0; i < *maxDisplayFrames + 10; i++) {
auto surfaceFrame =
mFrameTimeline->createSurfaceFrameForToken({}, sPidOne, sUidOne, sLayerNameOne,
sLayerNameOne);
int64_t sfToken = mTokenManager->generateTokenForPredictions({22, 26, 30});
- mFrameTimeline->setSfWakeUp(sfToken, 22, 11);
+ mFrameTimeline->setSfWakeUp(sfToken, 22, Fps::fromPeriodNsecs(11));
surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented);
mFrameTimeline->addSurfaceFrame(surfaceFrame);
mFrameTimeline->setSfPresent(27, presentFence);
@@ -446,93 +412,217 @@ TEST_F(FrameTimelineTest, setMaxDisplayFramesSetsSizeProperly) {
// Tests related to TimeStats
TEST_F(FrameTimelineTest, presentFenceSignaled_reportsLongSfCpu) {
+ Fps refreshRate = Fps(11);
EXPECT_CALL(*mTimeStats,
- incrementJankyFrames(sUidOne, sLayerNameOne,
- HasBit(JankType::SurfaceFlingerCpuDeadlineMissed)));
- EXPECT_CALL(*mTimeStats,
- incrementJankyFrames(HasBit(JankType::SurfaceFlingerCpuDeadlineMissed)));
+ incrementJankyFrames(
+ TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne,
+ sLayerNameOne,
+ JankType::SurfaceFlingerCpuDeadlineMissed,
+ std::chrono::duration_cast<
+ std::chrono::nanoseconds>(3ms)
+ .count(),
+ std::chrono::duration_cast<
+ std::chrono::nanoseconds>(10ms)
+ .count(),
+ 0}));
auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions(
- {std::chrono::duration_cast<std::chrono::nanoseconds>(10ms).count(),
- std::chrono::duration_cast<std::chrono::nanoseconds>(20ms).count(),
- std::chrono::duration_cast<std::chrono::nanoseconds>(60ms).count()});
+ {std::chrono::nanoseconds(10ms).count(), std::chrono::nanoseconds(20ms).count(),
+ std::chrono::nanoseconds(60ms).count()});
int64_t sfToken1 = mTokenManager->generateTokenForPredictions(
- {std::chrono::duration_cast<std::chrono::nanoseconds>(52ms).count(),
- std::chrono::duration_cast<std::chrono::nanoseconds>(56ms).count(),
- std::chrono::duration_cast<std::chrono::nanoseconds>(60ms).count()});
+ {std::chrono::nanoseconds(52ms).count(), std::chrono::nanoseconds(56ms).count(),
+ std::chrono::nanoseconds(60ms).count()});
auto surfaceFrame1 =
mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
sUidOne, sLayerNameOne, sLayerNameOne);
- mFrameTimeline->setSfWakeUp(sfToken1,
- std::chrono::duration_cast<std::chrono::nanoseconds>(52ms).count(),
- 11);
+ mFrameTimeline->setSfWakeUp(sfToken1, std::chrono::nanoseconds(52ms).count(), refreshRate);
+ surfaceFrame1->setAcquireFenceTime(std::chrono::nanoseconds(20ms).count());
surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
mFrameTimeline->addSurfaceFrame(surfaceFrame1);
- presentFence1->signalForTest(
- std::chrono::duration_cast<std::chrono::nanoseconds>(70ms).count());
+ presentFence1->signalForTest(std::chrono::nanoseconds(70ms).count());
- mFrameTimeline->setSfPresent(std::chrono::duration_cast<std::chrono::nanoseconds>(59ms).count(),
- presentFence1);
+ mFrameTimeline->setSfPresent(std::chrono::nanoseconds(59ms).count(), presentFence1);
}
TEST_F(FrameTimelineTest, presentFenceSignaled_reportsDisplayMiss) {
+ Fps refreshRate = Fps::fromPeriodNsecs(30);
EXPECT_CALL(*mTimeStats,
- incrementJankyFrames(sUidOne, sLayerNameOne, HasBit(JankType::DisplayHAL)));
- EXPECT_CALL(*mTimeStats, incrementJankyFrames(HasBit(JankType::DisplayHAL)));
+ incrementJankyFrames(TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne,
+ sLayerNameOne, JankType::DisplayHAL,
+ 0, 0, 0}));
auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions(
- {std::chrono::duration_cast<std::chrono::nanoseconds>(10ms).count(),
- std::chrono::duration_cast<std::chrono::nanoseconds>(20ms).count(),
- std::chrono::duration_cast<std::chrono::nanoseconds>(60ms).count()});
+ {std::chrono::nanoseconds(10ms).count(), std::chrono::nanoseconds(20ms).count(),
+ std::chrono::nanoseconds(60ms).count()});
int64_t sfToken1 = mTokenManager->generateTokenForPredictions(
- {std::chrono::duration_cast<std::chrono::nanoseconds>(52ms).count(),
- std::chrono::duration_cast<std::chrono::nanoseconds>(56ms).count(),
- std::chrono::duration_cast<std::chrono::nanoseconds>(60ms).count()});
+ {std::chrono::nanoseconds(52ms).count(), std::chrono::nanoseconds(56ms).count(),
+ std::chrono::nanoseconds(60ms).count()});
auto surfaceFrame1 =
mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
sUidOne, sLayerNameOne, sLayerNameOne);
- mFrameTimeline->setSfWakeUp(sfToken1,
- std::chrono::duration_cast<std::chrono::nanoseconds>(52ms).count(),
- 30);
+ mFrameTimeline->setSfWakeUp(sfToken1, std::chrono::nanoseconds(52ms).count(), refreshRate);
surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
+ surfaceFrame1->setAcquireFenceTime(std::chrono::nanoseconds(20ms).count());
mFrameTimeline->addSurfaceFrame(surfaceFrame1);
- presentFence1->signalForTest(
- std::chrono::duration_cast<std::chrono::nanoseconds>(90ms).count());
- mFrameTimeline->setSfPresent(std::chrono::duration_cast<std::chrono::nanoseconds>(56ms).count(),
- presentFence1);
+ presentFence1->signalForTest(std::chrono::nanoseconds(90ms).count());
+ mFrameTimeline->setSfPresent(std::chrono::nanoseconds(56ms).count(), presentFence1);
EXPECT_EQ(surfaceFrame1->getJankType(), JankType::DisplayHAL);
}
TEST_F(FrameTimelineTest, presentFenceSignaled_reportsAppMiss) {
+ Fps refreshRate = Fps(11.0);
EXPECT_CALL(*mTimeStats,
- incrementJankyFrames(sUidOne, sLayerNameOne,
- HasBit(JankType::AppDeadlineMissed)));
- EXPECT_CALL(*mTimeStats, incrementJankyFrames(HasBit(JankType::AppDeadlineMissed)));
+ incrementJankyFrames(
+ TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne,
+ sLayerNameOne, JankType::AppDeadlineMissed, 0, 0,
+ std::chrono::duration_cast<
+ std::chrono::nanoseconds>(25ms)
+ .count()}));
auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions(
- {std::chrono::duration_cast<std::chrono::nanoseconds>(10ms).count(),
- std::chrono::duration_cast<std::chrono::nanoseconds>(20ms).count(),
- std::chrono::duration_cast<std::chrono::nanoseconds>(60ms).count()});
+ {std::chrono::nanoseconds(10ms).count(), std::chrono::nanoseconds(20ms).count(),
+ std::chrono::nanoseconds(60ms).count()});
int64_t sfToken1 = mTokenManager->generateTokenForPredictions(
- {std::chrono::duration_cast<std::chrono::nanoseconds>(82ms).count(),
- std::chrono::duration_cast<std::chrono::nanoseconds>(86ms).count(),
- std::chrono::duration_cast<std::chrono::nanoseconds>(90ms).count()});
+ {std::chrono::nanoseconds(82ms).count(), std::chrono::nanoseconds(86ms).count(),
+ std::chrono::nanoseconds(90ms).count()});
auto surfaceFrame1 =
mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
sUidOne, sLayerNameOne, sLayerNameOne);
- surfaceFrame1->setAcquireFenceTime(
- std::chrono::duration_cast<std::chrono::nanoseconds>(45ms).count());
- mFrameTimeline->setSfWakeUp(sfToken1,
- std::chrono::duration_cast<std::chrono::nanoseconds>(52ms).count(),
- 11);
+ surfaceFrame1->setAcquireFenceTime(std::chrono::nanoseconds(45ms).count());
+ mFrameTimeline->setSfWakeUp(sfToken1, std::chrono::nanoseconds(52ms).count(), refreshRate);
surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
mFrameTimeline->addSurfaceFrame(surfaceFrame1);
- presentFence1->signalForTest(
- std::chrono::duration_cast<std::chrono::nanoseconds>(90ms).count());
- mFrameTimeline->setSfPresent(std::chrono::duration_cast<std::chrono::nanoseconds>(86ms).count(),
- presentFence1);
+ presentFence1->signalForTest(std::chrono::nanoseconds(90ms).count());
+ mFrameTimeline->setSfPresent(std::chrono::nanoseconds(86ms).count(), presentFence1);
+
+ EXPECT_EQ(surfaceFrame1->getJankType(), JankType::AppDeadlineMissed);
+}
+
+TEST_F(FrameTimelineTest, presentFenceSignaled_reportsSfScheduling) {
+ Fps refreshRate = Fps::fromPeriodNsecs(std::chrono::nanoseconds(32ms).count());
+ EXPECT_CALL(*mTimeStats,
+ incrementJankyFrames(
+ TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne,
+ sLayerNameOne,
+ JankType::SurfaceFlingerScheduling, 0, 0,
+ std::chrono::duration_cast<
+ std::chrono::nanoseconds>(-10ms)
+ .count()}));
+ auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+ int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions(
+ {std::chrono::nanoseconds(40ms).count(), std::chrono::nanoseconds(60ms).count(),
+ std::chrono::nanoseconds(92ms).count()});
+ int64_t sfToken1 = mTokenManager->generateTokenForPredictions(
+ {std::chrono::nanoseconds(52ms).count(), std::chrono::nanoseconds(56ms).count(),
+ std::chrono::nanoseconds(60ms).count()});
+ auto surfaceFrame1 =
+ mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
+ sUidOne, sLayerNameOne, sLayerNameOne);
+ surfaceFrame1->setAcquireFenceTime(std::chrono::nanoseconds(50ms).count());
+ mFrameTimeline->setSfWakeUp(sfToken1, std::chrono::nanoseconds(52ms).count(), refreshRate);
+
+ surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
+ mFrameTimeline->addSurfaceFrame(surfaceFrame1);
+ presentFence1->signalForTest(std::chrono::nanoseconds(60ms).count());
+ mFrameTimeline->setSfPresent(std::chrono::nanoseconds(56ms).count(), presentFence1);
+
+ EXPECT_EQ(surfaceFrame1->getJankType(), JankType::SurfaceFlingerScheduling);
+}
+
+TEST_F(FrameTimelineTest, presentFenceSignaled_reportsSfPredictionError) {
+ Fps refreshRate = Fps(16.66f);
+ EXPECT_CALL(*mTimeStats,
+ incrementJankyFrames(
+ TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne,
+ sLayerNameOne, JankType::PredictionError, 0,
+ std::chrono::duration_cast<
+ std::chrono::nanoseconds>(5ms)
+ .count(),
+ 0}));
+ auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+ int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions(
+ {std::chrono::nanoseconds(30ms).count(), std::chrono::nanoseconds(40ms).count(),
+ std::chrono::nanoseconds(60ms).count()});
+ int64_t sfToken1 = mTokenManager->generateTokenForPredictions(
+ {std::chrono::nanoseconds(52ms).count(), std::chrono::nanoseconds(56ms).count(),
+ std::chrono::nanoseconds(60ms).count()});
+ auto surfaceFrame1 =
+ mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
+ sUidOne, sLayerNameOne, sLayerNameOne);
+ surfaceFrame1->setAcquireFenceTime(std::chrono::nanoseconds(40ms).count());
+ mFrameTimeline->setSfWakeUp(sfToken1, std::chrono::nanoseconds(52ms).count(), refreshRate);
+
+ surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
+ mFrameTimeline->addSurfaceFrame(surfaceFrame1);
+ presentFence1->signalForTest(std::chrono::nanoseconds(65ms).count());
+ mFrameTimeline->setSfPresent(std::chrono::nanoseconds(56ms).count(), presentFence1);
+
+ EXPECT_EQ(surfaceFrame1->getJankType(), JankType::PredictionError);
+}
+
+TEST_F(FrameTimelineTest, presentFenceSignaled_reportsAppBufferStuffing) {
+ Fps refreshRate = Fps::fromPeriodNsecs(std::chrono::nanoseconds(32ms).count());
+ EXPECT_CALL(*mTimeStats,
+ incrementJankyFrames(
+ TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne,
+ sLayerNameOne,
+ JankType::BufferStuffing |
+ JankType::SurfaceFlingerScheduling,
+ 0, 0, 0}));
+ auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+ int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions(
+ {std::chrono::nanoseconds(30ms).count(), std::chrono::nanoseconds(40ms).count(),
+ std::chrono::nanoseconds(58ms).count()});
+ int64_t sfToken1 = mTokenManager->generateTokenForPredictions(
+ {std::chrono::nanoseconds(82ms).count(), std::chrono::nanoseconds(86ms).count(),
+ std::chrono::nanoseconds(90ms).count()});
+ auto surfaceFrame1 =
+ mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
+ sUidOne, sLayerNameOne, sLayerNameOne);
+ surfaceFrame1->setAcquireFenceTime(std::chrono::nanoseconds(40ms).count());
+ mFrameTimeline->setSfWakeUp(sfToken1, std::chrono::nanoseconds(82ms).count(), refreshRate);
+
+ surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented,
+ /*previousLatchTime*/
+ std::chrono::nanoseconds(56ms).count());
+ mFrameTimeline->addSurfaceFrame(surfaceFrame1);
+ presentFence1->signalForTest(std::chrono::nanoseconds(90ms).count());
+ mFrameTimeline->setSfPresent(std::chrono::nanoseconds(86ms).count(), presentFence1);
+
+ EXPECT_EQ(surfaceFrame1->getJankType(),
+ JankType::BufferStuffing | JankType::SurfaceFlingerScheduling);
+}
+
+TEST_F(FrameTimelineTest, presentFenceSignaled_reportsAppMissWithRenderRate) {
+ Fps refreshRate = Fps(11.0);
+ Fps renderRate = Fps(30.0);
+ EXPECT_CALL(*mTimeStats,
+ incrementJankyFrames(
+ TimeStats::JankyFramesInfo{refreshRate, renderRate, sUidOne, sLayerNameOne,
+ JankType::AppDeadlineMissed, 0, 0,
+ std::chrono::duration_cast<
+ std::chrono::nanoseconds>(25ms)
+ .count()}));
+ auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+ int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions(
+ {std::chrono::nanoseconds(10ms).count(), std::chrono::nanoseconds(20ms).count(),
+ std::chrono::nanoseconds(60ms).count()});
+ int64_t sfToken1 = mTokenManager->generateTokenForPredictions(
+ {std::chrono::nanoseconds(82ms).count(), std::chrono::nanoseconds(86ms).count(),
+ std::chrono::nanoseconds(90ms).count()});
+ auto surfaceFrame1 =
+ mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
+ sUidOne, sLayerNameOne, sLayerNameOne);
+ surfaceFrame1->setAcquireFenceTime(std::chrono::nanoseconds(45ms).count());
+ mFrameTimeline->setSfWakeUp(sfToken1, std::chrono::nanoseconds(52ms).count(), refreshRate);
+
+ surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
+ surfaceFrame1->setRenderRate(renderRate);
+ mFrameTimeline->addSurfaceFrame(surfaceFrame1);
+ presentFence1->signalForTest(std::chrono::nanoseconds(90ms).count());
+ mFrameTimeline->setSfPresent(std::chrono::nanoseconds(86ms).count(), presentFence1);
EXPECT_EQ(surfaceFrame1->getJankType(), JankType::AppDeadlineMissed);
}
@@ -547,28 +637,20 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsAppMiss) {
*/
TEST_F(FrameTimelineTest, tracing_noPacketsSentWithoutTraceStart) {
auto tracingSession = getTracingSessionForTest();
- // Global increment
- EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_));
auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
- auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
-
int64_t token1 = mTokenManager->generateTokenForPredictions({10, 20, 30});
- int64_t token2 = mTokenManager->generateTokenForPredictions({40, 50, 60});
auto surfaceFrame1 =
mFrameTimeline->createSurfaceFrameForToken({token1, sInputEventId}, sPidOne, sUidOne,
sLayerNameOne, sLayerNameOne);
// Set up the display frame
- mFrameTimeline->setSfWakeUp(token1, 20, 11);
+ mFrameTimeline->setSfWakeUp(token1, 20, Fps::fromPeriodNsecs(11));
surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Dropped);
mFrameTimeline->addSurfaceFrame(surfaceFrame1);
mFrameTimeline->setSfPresent(25, presentFence1);
presentFence1->signalForTest(30);
- // Trigger a flushPresentFence (which will call trace function) by calling setSfPresent for the
- // next frame
- mFrameTimeline->setSfWakeUp(token2, 50, 11);
- mFrameTimeline->setSfPresent(55, presentFence2);
+ addEmptyDisplayFrame();
auto packets = readFrameTimelinePacketsBlocking(tracingSession.get());
EXPECT_EQ(packets.size(), 0u);
@@ -576,12 +658,9 @@ TEST_F(FrameTimelineTest, tracing_noPacketsSentWithoutTraceStart) {
TEST_F(FrameTimelineTest, tracing_sanityTest) {
auto tracingSession = getTracingSessionForTest();
- // Global increment
- EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_));
// Layer specific increment
- EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_, testing::_, testing::_));
+ EXPECT_CALL(*mTimeStats, incrementJankyFrames(_));
auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
- auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
tracingSession->StartBlocking();
int64_t token1 = mTokenManager->generateTokenForPredictions({10, 20, 30});
@@ -591,18 +670,13 @@ TEST_F(FrameTimelineTest, tracing_sanityTest) {
sLayerNameOne, sLayerNameOne);
// Set up the display frame
- mFrameTimeline->setSfWakeUp(token2, 20, 11);
+ mFrameTimeline->setSfWakeUp(token2, 20, Fps::fromPeriodNsecs(11));
surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
mFrameTimeline->addSurfaceFrame(surfaceFrame1);
mFrameTimeline->setSfPresent(25, presentFence1);
presentFence1->signalForTest(30);
- // Trigger a flushPresentFence (which will call trace function) by calling setSfPresent for the
- // next frame
- mFrameTimeline->setSfWakeUp(token2, 50, 11);
- mFrameTimeline->setSfPresent(55, presentFence2);
- presentFence2->signalForTest(55);
-
+ addEmptyDisplayFrame();
flushTrace();
tracingSession->StopBlocking();
@@ -613,25 +687,16 @@ TEST_F(FrameTimelineTest, tracing_sanityTest) {
TEST_F(FrameTimelineTest, traceDisplayFrame_invalidTokenDoesNotEmitTracePacket) {
auto tracingSession = getTracingSessionForTest();
- // Global increment
- EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_));
auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
- auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
tracingSession->StartBlocking();
- int64_t token1 = mTokenManager->generateTokenForPredictions({10, 20, 30});
// Set up the display frame
- mFrameTimeline->setSfWakeUp(-1, 20, 11);
+ mFrameTimeline->setSfWakeUp(-1, 20, Fps::fromPeriodNsecs(11));
mFrameTimeline->setSfPresent(25, presentFence1);
presentFence1->signalForTest(30);
- // Trigger a flushPresentFence (which will call trace function) by calling setSfPresent for the
- // next frame
- mFrameTimeline->setSfWakeUp(token1, 50, 11);
- mFrameTimeline->setSfPresent(55, presentFence2);
- presentFence2->signalForTest(60);
-
+ addEmptyDisplayFrame();
flushTrace();
tracingSession->StopBlocking();
@@ -641,30 +706,21 @@ TEST_F(FrameTimelineTest, traceDisplayFrame_invalidTokenDoesNotEmitTracePacket)
TEST_F(FrameTimelineTest, traceSurfaceFrame_invalidTokenDoesNotEmitTracePacket) {
auto tracingSession = getTracingSessionForTest();
- // Global increment
- EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_));
auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
- auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
tracingSession->StartBlocking();
int64_t token1 = mTokenManager->generateTokenForPredictions({10, 20, 30});
- int64_t token2 = mTokenManager->generateTokenForPredictions({40, 50, 60});
auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken({}, sPidOne, sUidOne,
sLayerNameOne, sLayerNameOne);
// Set up the display frame
- mFrameTimeline->setSfWakeUp(token1, 20, 11);
+ mFrameTimeline->setSfWakeUp(token1, 20, Fps::fromPeriodNsecs(11));
surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Dropped);
mFrameTimeline->addSurfaceFrame(surfaceFrame1);
mFrameTimeline->setSfPresent(25, presentFence1);
presentFence1->signalForTest(30);
- // Trigger a flushPresentFence (which will call trace function) by calling setSfPresent for the
- // next frame
- mFrameTimeline->setSfWakeUp(token2, 50, 11);
- mFrameTimeline->setSfPresent(55, presentFence2);
- presentFence2->signalForTest(60);
-
+ addEmptyDisplayFrame();
flushTrace();
tracingSession->StopBlocking();
@@ -674,6 +730,65 @@ TEST_F(FrameTimelineTest, traceSurfaceFrame_invalidTokenDoesNotEmitTracePacket)
EXPECT_EQ(packets.size(), 4u);
}
+ProtoExpectedDisplayFrameStart createProtoExpectedDisplayFrameStart(int64_t cookie, int64_t token,
+ pid_t pid) {
+ ProtoExpectedDisplayFrameStart proto;
+ proto.set_cookie(cookie);
+ proto.set_token(token);
+ proto.set_pid(pid);
+ return proto;
+}
+
+ProtoActualDisplayFrameStart createProtoActualDisplayFrameStart(
+ int64_t cookie, int64_t token, pid_t pid, ProtoPresentType presentType, bool onTimeFinish,
+ bool gpuComposition, ProtoJankType jankType) {
+ ProtoActualDisplayFrameStart proto;
+ proto.set_cookie(cookie);
+ proto.set_token(token);
+ proto.set_pid(pid);
+ proto.set_present_type(presentType);
+ proto.set_on_time_finish(onTimeFinish);
+ proto.set_gpu_composition(gpuComposition);
+ proto.set_jank_type(jankType);
+ return proto;
+}
+
+ProtoExpectedSurfaceFrameStart createProtoExpectedSurfaceFrameStart(int64_t cookie, int64_t token,
+ int64_t displayFrameToken,
+ pid_t pid,
+ std::string layerName) {
+ ProtoExpectedSurfaceFrameStart proto;
+ proto.set_cookie(cookie);
+ proto.set_token(token);
+ proto.set_display_frame_token(displayFrameToken);
+ proto.set_pid(pid);
+ proto.set_layer_name(layerName);
+ return proto;
+}
+
+ProtoActualSurfaceFrameStart createProtoActualSurfaceFrameStart(
+ int64_t cookie, int64_t token, int64_t displayFrameToken, pid_t pid, std::string layerName,
+ ProtoPresentType presentType, bool onTimeFinish, bool gpuComposition,
+ ProtoJankType jankType) {
+ ProtoActualSurfaceFrameStart proto;
+ proto.set_cookie(cookie);
+ proto.set_token(token);
+ proto.set_display_frame_token(displayFrameToken);
+ proto.set_pid(pid);
+ proto.set_layer_name(layerName);
+ proto.set_present_type(presentType);
+ proto.set_on_time_finish(onTimeFinish);
+ proto.set_gpu_composition(gpuComposition);
+ proto.set_jank_type(jankType);
+ return proto;
+}
+
+ProtoFrameEnd createProtoFrameEnd(int64_t cookie) {
+ ProtoFrameEnd proto;
+ proto.set_cookie(cookie);
+ return proto;
+}
+
void validateTraceEvent(const ProtoExpectedDisplayFrameStart& received,
const ProtoExpectedDisplayFrameStart& source) {
ASSERT_TRUE(received.has_cookie());
@@ -759,48 +874,29 @@ void validateTraceEvent(const ProtoFrameEnd& received, const ProtoFrameEnd& sour
TEST_F(FrameTimelineTest, traceDisplayFrame_emitsValidTracePacket) {
auto tracingSession = getTracingSessionForTest();
- // Global increment
- EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_));
auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
- auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
tracingSession->StartBlocking();
int64_t displayFrameToken1 = mTokenManager->generateTokenForPredictions({10, 25, 30});
- int64_t displayFrameToken2 = mTokenManager->generateTokenForPredictions({40, 50, 60});
// Set up the display frame
- mFrameTimeline->setSfWakeUp(displayFrameToken1, 20, 11);
+ mFrameTimeline->setSfWakeUp(displayFrameToken1, 20, Fps::fromPeriodNsecs(11));
mFrameTimeline->setSfPresent(26, presentFence1);
presentFence1->signalForTest(31);
int64_t traceCookie = snoopCurrentTraceCookie();
- ProtoExpectedDisplayFrameStart protoExpectedDisplayFrameStart;
- protoExpectedDisplayFrameStart.set_cookie(traceCookie + 1);
- protoExpectedDisplayFrameStart.set_token(displayFrameToken1);
- protoExpectedDisplayFrameStart.set_pid(kSurfaceFlingerPid);
-
- ProtoFrameEnd protoExpectedDisplayFrameEnd;
- protoExpectedDisplayFrameEnd.set_cookie(traceCookie + 1);
-
- ProtoActualDisplayFrameStart protoActualDisplayFrameStart;
- protoActualDisplayFrameStart.set_cookie(traceCookie + 2);
- protoActualDisplayFrameStart.set_token(displayFrameToken1);
- protoActualDisplayFrameStart.set_pid(kSurfaceFlingerPid);
- protoActualDisplayFrameStart.set_present_type(
- ProtoPresentType(FrameTimelineEvent::PRESENT_ON_TIME));
- protoActualDisplayFrameStart.set_on_time_finish(true);
- protoActualDisplayFrameStart.set_gpu_composition(false);
- protoActualDisplayFrameStart.set_jank_type(ProtoJankType(FrameTimelineEvent::JANK_NONE));
-
- ProtoFrameEnd protoActualDisplayFrameEnd;
- protoActualDisplayFrameEnd.set_cookie(traceCookie + 2);
-
- // Trigger a flushPresentFence (which will call trace function) by calling setSfPresent for the
- // next frame
- mFrameTimeline->setSfWakeUp(displayFrameToken2, 50, 11);
- mFrameTimeline->setSfPresent(55, presentFence2);
- presentFence2->signalForTest(55);
+ auto protoExpectedDisplayFrameStart =
+ createProtoExpectedDisplayFrameStart(traceCookie + 1, displayFrameToken1,
+ kSurfaceFlingerPid);
+ auto protoExpectedDisplayFrameEnd = createProtoFrameEnd(traceCookie + 1);
+ auto protoActualDisplayFrameStart =
+ createProtoActualDisplayFrameStart(traceCookie + 2, displayFrameToken1,
+ kSurfaceFlingerPid,
+ FrameTimelineEvent::PRESENT_ON_TIME, true, false,
+ FrameTimelineEvent::JANK_NONE);
+ auto protoActualDisplayFrameEnd = createProtoFrameEnd(traceCookie + 2);
+ addEmptyDisplayFrame();
flushTrace();
tracingSession->StopBlocking();
@@ -852,75 +948,126 @@ TEST_F(FrameTimelineTest, traceDisplayFrame_emitsValidTracePacket) {
validateTraceEvent(actualDisplayFrameEnd, protoActualDisplayFrameEnd);
}
+TEST_F(FrameTimelineTest, traceDisplayFrame_predictionExpiredDoesNotTraceExpectedTimeline) {
+ auto tracingSession = getTracingSessionForTest();
+ auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+
+ tracingSession->StartBlocking();
+ int64_t displayFrameToken1 = mTokenManager->generateTokenForPredictions({10, 25, 30});
+ // Flush the token so that it would expire
+ flushTokens(systemTime() + maxTokenRetentionTime);
+
+ // Set up the display frame
+ mFrameTimeline->setSfWakeUp(displayFrameToken1, 20, Fps::fromPeriodNsecs(11));
+ mFrameTimeline->setSfPresent(26, presentFence1);
+ presentFence1->signalForTest(31);
+
+ int64_t traceCookie = snoopCurrentTraceCookie();
+
+ auto protoActualDisplayFrameStart =
+ createProtoActualDisplayFrameStart(traceCookie + 1, displayFrameToken1,
+ kSurfaceFlingerPid,
+ FrameTimelineEvent::PRESENT_UNSPECIFIED, false,
+ false, FrameTimelineEvent::JANK_UNKNOWN);
+ auto protoActualDisplayFrameEnd = createProtoFrameEnd(traceCookie + 1);
+
+ addEmptyDisplayFrame();
+ flushTrace();
+ tracingSession->StopBlocking();
+
+ auto packets = readFrameTimelinePacketsBlocking(tracingSession.get());
+ // Only actual timeline packets should be in the trace
+ EXPECT_EQ(packets.size(), 2u);
+
+ // Packet - 0 : ActualDisplayFrameStart
+ const auto& packet0 = packets[0];
+ ASSERT_TRUE(packet0.has_timestamp());
+ EXPECT_EQ(packet0.timestamp(), 20u);
+ ASSERT_TRUE(packet0.has_frame_timeline_event());
+
+ const auto& event0 = packet0.frame_timeline_event();
+ ASSERT_TRUE(event0.has_actual_display_frame_start());
+ const auto& actualDisplayFrameStart = event0.actual_display_frame_start();
+ validateTraceEvent(actualDisplayFrameStart, protoActualDisplayFrameStart);
+
+ // Packet - 1 : FrameEnd (ActualDisplayFrame)
+ const auto& packet1 = packets[1];
+ ASSERT_TRUE(packet1.has_timestamp());
+ EXPECT_EQ(packet1.timestamp(), 26u);
+ ASSERT_TRUE(packet1.has_frame_timeline_event());
+
+ const auto& event1 = packet1.frame_timeline_event();
+ ASSERT_TRUE(event1.has_frame_end());
+ const auto& actualDisplayFrameEnd = event1.frame_end();
+ validateTraceEvent(actualDisplayFrameEnd, protoActualDisplayFrameEnd);
+}
+
TEST_F(FrameTimelineTest, traceSurfaceFrame_emitsValidTracePacket) {
auto tracingSession = getTracingSessionForTest();
- // Global increment
- EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_));
// Layer specific increment
- EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_, testing::_, testing::_));
+ EXPECT_CALL(*mTimeStats, incrementJankyFrames(_));
auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
tracingSession->StartBlocking();
int64_t surfaceFrameToken = mTokenManager->generateTokenForPredictions({10, 25, 40});
int64_t displayFrameToken1 = mTokenManager->generateTokenForPredictions({30, 35, 40});
- int64_t displayFrameToken2 = mTokenManager->generateTokenForPredictions({40, 50, 60});
auto surfaceFrame1 =
mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, sInputEventId}, sPidOne,
sUidOne, sLayerNameOne, sLayerNameOne);
- surfaceFrame1->setActualStartTime(0);
- surfaceFrame1->setActualQueueTime(15);
- surfaceFrame1->setAcquireFenceTime(20);
+ auto surfaceFrame2 =
+ mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, sInputEventId}, sPidOne,
+ sUidOne, sLayerNameOne, sLayerNameOne);
+ surfaceFrame1->setActualQueueTime(10);
+ surfaceFrame1->setDropTime(15);
+
+ surfaceFrame2->setActualQueueTime(15);
+ surfaceFrame2->setAcquireFenceTime(20);
// First 2 cookies will be used by the DisplayFrame
int64_t traceCookie = snoopCurrentTraceCookie() + 2;
- ProtoExpectedSurfaceFrameStart protoExpectedSurfaceFrameStart;
- protoExpectedSurfaceFrameStart.set_cookie(traceCookie + 1);
- protoExpectedSurfaceFrameStart.set_token(surfaceFrameToken);
- protoExpectedSurfaceFrameStart.set_display_frame_token(displayFrameToken1);
- protoExpectedSurfaceFrameStart.set_pid(sPidOne);
- protoExpectedSurfaceFrameStart.set_layer_name(sLayerNameOne);
-
- ProtoFrameEnd protoExpectedSurfaceFrameEnd;
- protoExpectedSurfaceFrameEnd.set_cookie(traceCookie + 1);
-
- ProtoActualSurfaceFrameStart protoActualSurfaceFrameStart;
- protoActualSurfaceFrameStart.set_cookie(traceCookie + 2);
- protoActualSurfaceFrameStart.set_token(surfaceFrameToken);
- protoActualSurfaceFrameStart.set_display_frame_token(displayFrameToken1);
- protoActualSurfaceFrameStart.set_pid(sPidOne);
- protoActualSurfaceFrameStart.set_layer_name(sLayerNameOne);
- protoActualSurfaceFrameStart.set_present_type(
- ProtoPresentType(FrameTimelineEvent::PRESENT_ON_TIME));
- protoActualSurfaceFrameStart.set_on_time_finish(true);
- protoActualSurfaceFrameStart.set_gpu_composition(false);
- protoActualSurfaceFrameStart.set_jank_type(ProtoJankType(FrameTimelineEvent::JANK_NONE));
-
- ProtoFrameEnd protoActualSurfaceFrameEnd;
- protoActualSurfaceFrameEnd.set_cookie(traceCookie + 2);
+ auto protoDroppedSurfaceFrameExpectedStart =
+ createProtoExpectedSurfaceFrameStart(traceCookie + 1, surfaceFrameToken,
+ displayFrameToken1, sPidOne, sLayerNameOne);
+ auto protoDroppedSurfaceFrameExpectedEnd = createProtoFrameEnd(traceCookie + 1);
+ auto protoDroppedSurfaceFrameActualStart =
+ createProtoActualSurfaceFrameStart(traceCookie + 2, surfaceFrameToken,
+ displayFrameToken1, sPidOne, sLayerNameOne,
+ FrameTimelineEvent::PRESENT_DROPPED, false, false,
+ FrameTimelineEvent::JANK_NONE);
+ auto protoDroppedSurfaceFrameActualEnd = createProtoFrameEnd(traceCookie + 2);
+
+ auto protoPresentedSurfaceFrameExpectedStart =
+ createProtoExpectedSurfaceFrameStart(traceCookie + 3, surfaceFrameToken,
+ displayFrameToken1, sPidOne, sLayerNameOne);
+ auto protoPresentedSurfaceFrameExpectedEnd = createProtoFrameEnd(traceCookie + 3);
+ auto protoPresentedSurfaceFrameActualStart =
+ createProtoActualSurfaceFrameStart(traceCookie + 4, surfaceFrameToken,
+ displayFrameToken1, sPidOne, sLayerNameOne,
+ FrameTimelineEvent::PRESENT_ON_TIME, true, false,
+ FrameTimelineEvent::JANK_NONE);
+ auto protoPresentedSurfaceFrameActualEnd = createProtoFrameEnd(traceCookie + 4);
// Set up the display frame
- mFrameTimeline->setSfWakeUp(displayFrameToken1, 20, 11);
- surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
+ mFrameTimeline->setSfWakeUp(displayFrameToken1, 20, Fps::fromPeriodNsecs(11));
+ surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Dropped);
+ surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented);
mFrameTimeline->addSurfaceFrame(surfaceFrame1);
+ mFrameTimeline->addSurfaceFrame(surfaceFrame2);
mFrameTimeline->setSfPresent(26, presentFence1);
presentFence1->signalForTest(40);
- // Trigger a flushPresentFence (which will call trace function) by calling setSfPresent for the
- // next frame
- mFrameTimeline->setSfWakeUp(displayFrameToken2, 50, 11);
- mFrameTimeline->setSfPresent(55, presentFence2);
- presentFence2->signalForTest(55);
-
+ addEmptyDisplayFrame();
flushTrace();
tracingSession->StopBlocking();
auto packets = readFrameTimelinePacketsBlocking(tracingSession.get());
- EXPECT_EQ(packets.size(), 8u);
+ // 4 DisplayFrame + 4 DroppedSurfaceFrame + 4 PresentedSurfaceFrame
+ EXPECT_EQ(packets.size(), 12u);
- // Packet - 4 : ExpectedSurfaceFrameStart
+ // Packet - 4 : ExpectedSurfaceFrameStart1
const auto& packet4 = packets[4];
ASSERT_TRUE(packet4.has_timestamp());
EXPECT_EQ(packet4.timestamp(), 10u);
@@ -928,10 +1075,10 @@ TEST_F(FrameTimelineTest, traceSurfaceFrame_emitsValidTracePacket) {
const auto& event4 = packet4.frame_timeline_event();
ASSERT_TRUE(event4.has_expected_surface_frame_start());
- const auto& expectedSurfaceFrameStart = event4.expected_surface_frame_start();
- validateTraceEvent(expectedSurfaceFrameStart, protoExpectedSurfaceFrameStart);
+ const auto& expectedSurfaceFrameStart1 = event4.expected_surface_frame_start();
+ validateTraceEvent(expectedSurfaceFrameStart1, protoDroppedSurfaceFrameExpectedStart);
- // Packet - 5 : FrameEnd (ExpectedSurfaceFrame)
+ // Packet - 5 : FrameEnd (ExpectedSurfaceFrame1)
const auto& packet5 = packets[5];
ASSERT_TRUE(packet5.has_timestamp());
EXPECT_EQ(packet5.timestamp(), 25u);
@@ -939,10 +1086,10 @@ TEST_F(FrameTimelineTest, traceSurfaceFrame_emitsValidTracePacket) {
const auto& event5 = packet5.frame_timeline_event();
ASSERT_TRUE(event5.has_frame_end());
- const auto& expectedSurfaceFrameEnd = event5.frame_end();
- validateTraceEvent(expectedSurfaceFrameEnd, protoExpectedSurfaceFrameEnd);
+ const auto& expectedSurfaceFrameEnd1 = event5.frame_end();
+ validateTraceEvent(expectedSurfaceFrameEnd1, protoDroppedSurfaceFrameExpectedEnd);
- // Packet - 6 : ActualSurfaceFrameStart
+ // Packet - 6 : ActualSurfaceFrameStart1
const auto& packet6 = packets[6];
ASSERT_TRUE(packet6.has_timestamp());
EXPECT_EQ(packet6.timestamp(), 10u);
@@ -950,34 +1097,157 @@ TEST_F(FrameTimelineTest, traceSurfaceFrame_emitsValidTracePacket) {
const auto& event6 = packet6.frame_timeline_event();
ASSERT_TRUE(event6.has_actual_surface_frame_start());
- const auto& actualSurfaceFrameStart = event6.actual_surface_frame_start();
- validateTraceEvent(actualSurfaceFrameStart, protoActualSurfaceFrameStart);
+ const auto& actualSurfaceFrameStart1 = event6.actual_surface_frame_start();
+ validateTraceEvent(actualSurfaceFrameStart1, protoDroppedSurfaceFrameActualStart);
- // Packet - 7 : FrameEnd (ActualSurfaceFrame)
+ // Packet - 7 : FrameEnd (ActualSurfaceFrame1)
const auto& packet7 = packets[7];
ASSERT_TRUE(packet7.has_timestamp());
- EXPECT_EQ(packet7.timestamp(), 20u);
+ EXPECT_EQ(packet7.timestamp(), 15u);
ASSERT_TRUE(packet7.has_frame_timeline_event());
const auto& event7 = packet7.frame_timeline_event();
ASSERT_TRUE(event7.has_frame_end());
- const auto& actualSurfaceFrameEnd = event7.frame_end();
+ const auto& actualSurfaceFrameEnd1 = event7.frame_end();
+ validateTraceEvent(actualSurfaceFrameEnd1, protoDroppedSurfaceFrameActualEnd);
+
+ // Packet - 8 : ExpectedSurfaceFrameStart2
+ const auto& packet8 = packets[8];
+ ASSERT_TRUE(packet8.has_timestamp());
+ EXPECT_EQ(packet8.timestamp(), 10u);
+ ASSERT_TRUE(packet8.has_frame_timeline_event());
+
+ const auto& event8 = packet8.frame_timeline_event();
+ ASSERT_TRUE(event8.has_expected_surface_frame_start());
+ const auto& expectedSurfaceFrameStart2 = event8.expected_surface_frame_start();
+ validateTraceEvent(expectedSurfaceFrameStart2, protoPresentedSurfaceFrameExpectedStart);
+
+ // Packet - 9 : FrameEnd (ExpectedSurfaceFrame2)
+ const auto& packet9 = packets[9];
+ ASSERT_TRUE(packet9.has_timestamp());
+ EXPECT_EQ(packet9.timestamp(), 25u);
+ ASSERT_TRUE(packet9.has_frame_timeline_event());
+
+ const auto& event9 = packet9.frame_timeline_event();
+ ASSERT_TRUE(event9.has_frame_end());
+ const auto& expectedSurfaceFrameEnd2 = event9.frame_end();
+ validateTraceEvent(expectedSurfaceFrameEnd2, protoPresentedSurfaceFrameExpectedEnd);
+
+ // Packet - 10 : ActualSurfaceFrameStart2
+ const auto& packet10 = packets[10];
+ ASSERT_TRUE(packet10.has_timestamp());
+ EXPECT_EQ(packet10.timestamp(), 10u);
+ ASSERT_TRUE(packet10.has_frame_timeline_event());
+
+ const auto& event10 = packet10.frame_timeline_event();
+ ASSERT_TRUE(event10.has_actual_surface_frame_start());
+ const auto& actualSurfaceFrameStart2 = event10.actual_surface_frame_start();
+ validateTraceEvent(actualSurfaceFrameStart2, protoPresentedSurfaceFrameActualStart);
+
+ // Packet - 11 : FrameEnd (ActualSurfaceFrame2)
+ const auto& packet11 = packets[11];
+ ASSERT_TRUE(packet11.has_timestamp());
+ EXPECT_EQ(packet11.timestamp(), 20u);
+ ASSERT_TRUE(packet11.has_frame_timeline_event());
+
+ const auto& event11 = packet11.frame_timeline_event();
+ ASSERT_TRUE(event11.has_frame_end());
+ const auto& actualSurfaceFrameEnd2 = event11.frame_end();
+ validateTraceEvent(actualSurfaceFrameEnd2, protoPresentedSurfaceFrameActualEnd);
+}
+
+TEST_F(FrameTimelineTest, traceSurfaceFrame_predictionExpiredDoesNotTraceExpectedTimeline) {
+ auto tracingSession = getTracingSessionForTest();
+ auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+
+ tracingSession->StartBlocking();
+ constexpr nsecs_t appStartTime =
+ std::chrono::duration_cast<std::chrono::nanoseconds>(10ms).count();
+ constexpr nsecs_t appEndTime =
+ std::chrono::duration_cast<std::chrono::nanoseconds>(20ms).count();
+ constexpr nsecs_t appPresentTime =
+ std::chrono::duration_cast<std::chrono::nanoseconds>(30ms).count();
+ int64_t surfaceFrameToken =
+ mTokenManager->generateTokenForPredictions({appStartTime, appEndTime, appPresentTime});
+
+ // Flush the token so that it would expire
+ flushTokens(systemTime() + maxTokenRetentionTime);
+ auto surfaceFrame1 =
+ mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, /*inputEventId*/ 0},
+ sPidOne, sUidOne, sLayerNameOne,
+ sLayerNameOne);
+ surfaceFrame1->setActualQueueTime(appEndTime);
+ surfaceFrame1->setAcquireFenceTime(appEndTime);
+
+ constexpr nsecs_t sfStartTime =
+ std::chrono::duration_cast<std::chrono::nanoseconds>(20ms).count();
+ constexpr nsecs_t sfEndTime =
+ std::chrono::duration_cast<std::chrono::nanoseconds>(30ms).count();
+ constexpr nsecs_t sfPresentTime =
+ std::chrono::duration_cast<std::chrono::nanoseconds>(30ms).count();
+ int64_t displayFrameToken =
+ mTokenManager->generateTokenForPredictions({sfStartTime, sfEndTime, sfPresentTime});
+
+ // First 2 cookies will be used by the DisplayFrame
+ int64_t traceCookie = snoopCurrentTraceCookie() + 2;
+
+ auto protoActualSurfaceFrameStart =
+ createProtoActualSurfaceFrameStart(traceCookie + 1, surfaceFrameToken,
+ displayFrameToken, sPidOne, sLayerNameOne,
+ FrameTimelineEvent::PRESENT_UNSPECIFIED, false,
+ false, FrameTimelineEvent::JANK_UNKNOWN);
+ auto protoActualSurfaceFrameEnd = createProtoFrameEnd(traceCookie + 1);
+
+ // Set up the display frame
+ mFrameTimeline->setSfWakeUp(displayFrameToken, sfStartTime, Fps::fromPeriodNsecs(11));
+ surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
+ mFrameTimeline->addSurfaceFrame(surfaceFrame1);
+ mFrameTimeline->setSfPresent(sfEndTime, presentFence1);
+ presentFence1->signalForTest(sfPresentTime);
+
+ addEmptyDisplayFrame();
+ flushTrace();
+ tracingSession->StopBlocking();
+
+ auto packets = readFrameTimelinePacketsBlocking(tracingSession.get());
+ // Display Frame 4 packets + SurfaceFrame 2 packets
+ ASSERT_EQ(packets.size(), 6u);
+
+ // Packet - 4 : ActualSurfaceFrameStart
+ const auto& packet4 = packets[4];
+ ASSERT_TRUE(packet4.has_timestamp());
+ EXPECT_EQ(packet4.timestamp(),
+ static_cast<uint64_t>(appEndTime - SurfaceFrame::kPredictionExpiredStartTimeDelta));
+ ASSERT_TRUE(packet4.has_frame_timeline_event());
+
+ const auto& event4 = packet4.frame_timeline_event();
+ ASSERT_TRUE(event4.has_actual_surface_frame_start());
+ const auto& actualSurfaceFrameStart = event4.actual_surface_frame_start();
+ validateTraceEvent(actualSurfaceFrameStart, protoActualSurfaceFrameStart);
+
+ // Packet - 5 : FrameEnd (ActualSurfaceFrame)
+ const auto& packet5 = packets[5];
+ ASSERT_TRUE(packet5.has_timestamp());
+ EXPECT_EQ(packet5.timestamp(), static_cast<uint64_t>(appEndTime));
+ ASSERT_TRUE(packet5.has_frame_timeline_event());
+
+ const auto& event5 = packet5.frame_timeline_event();
+ ASSERT_TRUE(event5.has_frame_end());
+ const auto& actualSurfaceFrameEnd = event5.frame_end();
validateTraceEvent(actualSurfaceFrameEnd, protoActualSurfaceFrameEnd);
}
// Tests for Jank classification
TEST_F(FrameTimelineTest, jankClassification_presentOnTimeDoesNotClassify) {
- // Global increment
- EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_));
// Layer specific increment
- EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_, testing::_, testing::_));
+ EXPECT_CALL(*mTimeStats, incrementJankyFrames(_));
auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
int64_t surfaceFrameToken = mTokenManager->generateTokenForPredictions({10, 20, 30});
int64_t sfToken1 = mTokenManager->generateTokenForPredictions({22, 26, 30});
auto surfaceFrame =
mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, sInputEventId}, sPidOne,
sUidOne, sLayerNameOne, sLayerNameOne);
- mFrameTimeline->setSfWakeUp(sfToken1, 22, 11);
+ mFrameTimeline->setSfWakeUp(sfToken1, 22, Fps::fromPeriodNsecs(11));
surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented);
mFrameTimeline->addSurfaceFrame(surfaceFrame);
mFrameTimeline->setSfPresent(26, presentFence1);
@@ -1001,12 +1271,11 @@ TEST_F(FrameTimelineTest, jankClassification_presentOnTimeDoesNotClassify) {
}
TEST_F(FrameTimelineTest, jankClassification_displayFrameOnTimeFinishEarlyPresent) {
- // Global increment
- EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_)).Times(2);
+ Fps vsyncRate = Fps::fromPeriodNsecs(11);
auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
int64_t sfToken1 = mTokenManager->generateTokenForPredictions({22, 26, 40});
int64_t sfToken2 = mTokenManager->generateTokenForPredictions({52, 56, 70});
- mFrameTimeline->setSfWakeUp(sfToken1, 22, 11);
+ mFrameTimeline->setSfWakeUp(sfToken1, 22, vsyncRate);
mFrameTimeline->setSfPresent(26, presentFence1);
auto displayFrame = getDisplayFrame(0);
presentFence1->signalForTest(30);
@@ -1016,7 +1285,7 @@ TEST_F(FrameTimelineTest, jankClassification_displayFrameOnTimeFinishEarlyPresen
// Trigger a flush by finalizing the next DisplayFrame
auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
- mFrameTimeline->setSfWakeUp(sfToken2, 52, 11);
+ mFrameTimeline->setSfWakeUp(sfToken2, 52, vsyncRate);
mFrameTimeline->setSfPresent(56, presentFence2);
displayFrame = getDisplayFrame(0);
@@ -1030,7 +1299,6 @@ TEST_F(FrameTimelineTest, jankClassification_displayFrameOnTimeFinishEarlyPresen
auto displayFrame2 = getDisplayFrame(1);
presentFence2->signalForTest(65);
EXPECT_EQ(displayFrame2->getActuals().presentTime, 0);
-
addEmptyDisplayFrame();
displayFrame2 = getDisplayFrame(1);
@@ -1042,12 +1310,11 @@ TEST_F(FrameTimelineTest, jankClassification_displayFrameOnTimeFinishEarlyPresen
}
TEST_F(FrameTimelineTest, jankClassification_displayFrameOnTimeFinishLatePresent) {
- // Global increment
- EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_)).Times(2);
+ Fps vsyncRate = Fps::fromPeriodNsecs(11);
auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
int64_t sfToken1 = mTokenManager->generateTokenForPredictions({22, 26, 40});
int64_t sfToken2 = mTokenManager->generateTokenForPredictions({52, 56, 70});
- mFrameTimeline->setSfWakeUp(sfToken1, 22, 11);
+ mFrameTimeline->setSfWakeUp(sfToken1, 22, vsyncRate);
mFrameTimeline->setSfPresent(26, presentFence1);
auto displayFrame = getDisplayFrame(0);
presentFence1->signalForTest(50);
@@ -1057,7 +1324,7 @@ TEST_F(FrameTimelineTest, jankClassification_displayFrameOnTimeFinishLatePresent
// Trigger a flush by finalizing the next DisplayFrame
auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
- mFrameTimeline->setSfWakeUp(sfToken2, 52, 11);
+ mFrameTimeline->setSfWakeUp(sfToken2, 52, vsyncRate);
mFrameTimeline->setSfPresent(56, presentFence2);
displayFrame = getDisplayFrame(0);
@@ -1083,11 +1350,9 @@ TEST_F(FrameTimelineTest, jankClassification_displayFrameOnTimeFinishLatePresent
}
TEST_F(FrameTimelineTest, jankClassification_displayFrameLateFinishEarlyPresent) {
- // Global increment
- EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_));
auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
int64_t sfToken1 = mTokenManager->generateTokenForPredictions({12, 18, 40});
- mFrameTimeline->setSfWakeUp(sfToken1, 12, 11);
+ mFrameTimeline->setSfWakeUp(sfToken1, 12, Fps::fromPeriodNsecs(11));
mFrameTimeline->setSfPresent(22, presentFence1);
auto displayFrame = getDisplayFrame(0);
@@ -1107,11 +1372,9 @@ TEST_F(FrameTimelineTest, jankClassification_displayFrameLateFinishEarlyPresent)
}
TEST_F(FrameTimelineTest, jankClassification_displayFrameLateFinishLatePresent) {
- // Global increment
- EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_));
auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
int64_t sfToken1 = mTokenManager->generateTokenForPredictions({22, 26, 40});
- mFrameTimeline->setSfWakeUp(sfToken1, 12, 11);
+ mFrameTimeline->setSfWakeUp(sfToken1, 12, Fps::fromPeriodNsecs(11));
mFrameTimeline->setSfPresent(36, presentFence1);
auto displayFrame = getDisplayFrame(0);
presentFence1->signalForTest(52);
@@ -1130,10 +1393,7 @@ TEST_F(FrameTimelineTest, jankClassification_displayFrameLateFinishLatePresent)
}
TEST_F(FrameTimelineTest, jankClassification_surfaceFrameOnTimeFinishEarlyPresent) {
- // Global increment
- EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_)).Times(2);
- // Layer specific increment
- EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_, testing::_, testing::_)).Times(2);
+ EXPECT_CALL(*mTimeStats, incrementJankyFrames(_));
auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
int64_t sfToken1 = mTokenManager->generateTokenForPredictions({22, 26, 40});
int64_t sfToken2 = mTokenManager->generateTokenForPredictions({52, 56, 70});
@@ -1143,7 +1403,7 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameOnTimeFinishEarlyPresen
mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
sUidOne, sLayerNameOne, sLayerNameOne);
surfaceFrame1->setAcquireFenceTime(16);
- mFrameTimeline->setSfWakeUp(sfToken1, 22, 11);
+ mFrameTimeline->setSfWakeUp(sfToken1, 22, Fps::fromPeriodNsecs(11));
surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
mFrameTimeline->addSurfaceFrame(surfaceFrame1);
mFrameTimeline->setSfPresent(26, presentFence1);
@@ -1162,7 +1422,7 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameOnTimeFinishEarlyPresen
mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken2, sInputEventId}, sPidOne,
sUidOne, sLayerNameOne, sLayerNameOne);
surfaceFrame2->setAcquireFenceTime(36);
- mFrameTimeline->setSfWakeUp(sfToken2, 52, 11);
+ mFrameTimeline->setSfWakeUp(sfToken2, 52, Fps::fromPeriodNsecs(11));
surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented);
mFrameTimeline->addSurfaceFrame(surfaceFrame2);
mFrameTimeline->setSfPresent(56, presentFence2);
@@ -1187,6 +1447,14 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameOnTimeFinishEarlyPresen
auto actuals2 = presentedSurfaceFrame2.getActuals();
EXPECT_EQ(actuals2.presentTime, 0);
+ ::testing::Mock::VerifyAndClearExpectations(mTimeStats.get());
+
+ EXPECT_CALL(*mTimeStats,
+ incrementJankyFrames(
+ TimeStats::JankyFramesInfo{Fps::fromPeriodNsecs(11), std::nullopt, sUidOne,
+ sLayerNameOne, JankType::PredictionError, 0, 5,
+ 0}));
+
addEmptyDisplayFrame();
// Fences for the second frame have flushed, so the present timestamps should be updated
@@ -1203,10 +1471,7 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameOnTimeFinishEarlyPresen
}
TEST_F(FrameTimelineTest, jankClassification_surfaceFrameOnTimeFinishLatePresent) {
- // Global increment
- EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_)).Times(2);
- // Layer specific increment
- EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_, testing::_, testing::_)).Times(2);
+ EXPECT_CALL(*mTimeStats, incrementJankyFrames(_));
auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
int64_t sfToken1 = mTokenManager->generateTokenForPredictions({22, 26, 40});
int64_t sfToken2 = mTokenManager->generateTokenForPredictions({52, 56, 70});
@@ -1216,7 +1481,7 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameOnTimeFinishLatePresent
mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
sUidOne, sLayerNameOne, sLayerNameOne);
surfaceFrame1->setAcquireFenceTime(16);
- mFrameTimeline->setSfWakeUp(sfToken1, 22, 11);
+ mFrameTimeline->setSfWakeUp(sfToken1, 22, Fps::fromPeriodNsecs(11));
surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
mFrameTimeline->addSurfaceFrame(surfaceFrame1);
mFrameTimeline->setSfPresent(26, presentFence1);
@@ -1235,7 +1500,7 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameOnTimeFinishLatePresent
mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken2, sInputEventId}, sPidOne,
sUidOne, sLayerNameOne, sLayerNameOne);
surfaceFrame2->setAcquireFenceTime(36);
- mFrameTimeline->setSfWakeUp(sfToken2, 52, 11);
+ mFrameTimeline->setSfWakeUp(sfToken2, 52, Fps::fromPeriodNsecs(11));
surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented);
mFrameTimeline->addSurfaceFrame(surfaceFrame2);
mFrameTimeline->setSfPresent(56, presentFence2);
@@ -1260,6 +1525,14 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameOnTimeFinishLatePresent
auto actuals2 = presentedSurfaceFrame2.getActuals();
EXPECT_EQ(actuals2.presentTime, 0);
+ ::testing::Mock::VerifyAndClearExpectations(mTimeStats.get());
+
+ EXPECT_CALL(*mTimeStats,
+ incrementJankyFrames(
+ TimeStats::JankyFramesInfo{Fps::fromPeriodNsecs(11), std::nullopt, sUidOne,
+ sLayerNameOne, JankType::PredictionError, 0, 5,
+ 0}));
+
addEmptyDisplayFrame();
// Fences for the second frame have flushed, so the present timestamps should be updated
@@ -1276,10 +1549,8 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameOnTimeFinishLatePresent
}
TEST_F(FrameTimelineTest, jankClassification_surfaceFrameLateFinishEarlyPresent) {
- // Global increment
- EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_));
- // Layer specific increment
- EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_, testing::_, testing::_));
+ EXPECT_CALL(*mTimeStats, incrementJankyFrames(_));
+
auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
int64_t sfToken1 = mTokenManager->generateTokenForPredictions({42, 46, 50});
int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({5, 26, 60});
@@ -1287,7 +1558,7 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameLateFinishEarlyPresent)
mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
sUidOne, sLayerNameOne, sLayerNameOne);
surfaceFrame1->setAcquireFenceTime(40);
- mFrameTimeline->setSfWakeUp(sfToken1, 42, 11);
+ mFrameTimeline->setSfWakeUp(sfToken1, 42, Fps::fromPeriodNsecs(11));
surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
mFrameTimeline->addSurfaceFrame(surfaceFrame1);
mFrameTimeline->setSfPresent(46, presentFence1);
@@ -1320,10 +1591,7 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameLateFinishLatePresent)
// AppDeadlineMissed. Second frame - DisplayFrame is janky. This should propagate DisplayFrame's
// jank to the SurfaceFrame.
- // Global increment
- EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_)).Times(2);
- // Layer specific increment
- EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_, testing::_, testing::_)).Times(2);
+ EXPECT_CALL(*mTimeStats, incrementJankyFrames(_)).Times(2);
auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
int64_t sfToken1 = mTokenManager->generateTokenForPredictions({32, 36, 40});
int64_t sfToken2 = mTokenManager->generateTokenForPredictions({42, 46, 50});
@@ -1333,7 +1601,7 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameLateFinishLatePresent)
mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
sUidOne, sLayerNameOne, sLayerNameOne);
surfaceFrame1->setAcquireFenceTime(26);
- mFrameTimeline->setSfWakeUp(sfToken1, 32, 11);
+ mFrameTimeline->setSfWakeUp(sfToken1, 32, Fps::fromPeriodNsecs(11));
surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
mFrameTimeline->addSurfaceFrame(surfaceFrame1);
mFrameTimeline->setSfPresent(36, presentFence1);
@@ -1352,7 +1620,7 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameLateFinishLatePresent)
mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken2, sInputEventId}, sPidOne,
sUidOne, sLayerNameOne, sLayerNameOne);
surfaceFrame2->setAcquireFenceTime(40);
- mFrameTimeline->setSfWakeUp(sfToken2, 43, 11);
+ mFrameTimeline->setSfWakeUp(sfToken2, 43, Fps::fromPeriodNsecs(11));
surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented);
mFrameTimeline->addSurfaceFrame(surfaceFrame2);
mFrameTimeline->setSfPresent(56, presentFence2);
@@ -1393,10 +1661,8 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameLateFinishLatePresent)
}
TEST_F(FrameTimelineTest, jankClassification_multiJankBufferStuffingAndAppDeadlineMissed) {
- // Global increment
- EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_)).Times(2);
// Layer specific increment
- EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_, testing::_, testing::_)).Times(2);
+ EXPECT_CALL(*mTimeStats, incrementJankyFrames(_)).Times(2);
auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({10, 20, 30});
int64_t surfaceFrameToken2 = mTokenManager->generateTokenForPredictions({40, 50, 60});
@@ -1407,7 +1673,7 @@ TEST_F(FrameTimelineTest, jankClassification_multiJankBufferStuffingAndAppDeadli
mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
sUidOne, sLayerNameOne, sLayerNameOne);
surfaceFrame1->setAcquireFenceTime(50);
- mFrameTimeline->setSfWakeUp(sfToken1, 52, 30);
+ mFrameTimeline->setSfWakeUp(sfToken1, 52, Fps::fromPeriodNsecs(30));
surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
mFrameTimeline->addSurfaceFrame(surfaceFrame1);
mFrameTimeline->setSfPresent(56, presentFence1);
@@ -1426,7 +1692,7 @@ TEST_F(FrameTimelineTest, jankClassification_multiJankBufferStuffingAndAppDeadli
mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken2, sInputEventId}, sPidOne,
sUidOne, sLayerNameOne, sLayerNameOne);
surfaceFrame2->setAcquireFenceTime(84);
- mFrameTimeline->setSfWakeUp(sfToken2, 112, 30);
+ mFrameTimeline->setSfWakeUp(sfToken2, 112, Fps::fromPeriodNsecs(30));
surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented, 54);
mFrameTimeline->addSurfaceFrame(surfaceFrame2);
mFrameTimeline->setSfPresent(116, presentFence2);
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
index 376995f79e..06f2036615 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
@@ -1792,6 +1792,26 @@ 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/SetFrameRateTest.cpp b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
index a6d07d00ee..5c8c2d888c 100644
--- a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
@@ -81,7 +81,7 @@ public:
std::string name() override { return "BufferStateLayer"; }
sp<Layer> createLayer(TestableSurfaceFlinger& flinger) override {
sp<Client> client;
- LayerCreationArgs args(flinger.flinger(), client, "buffer-queue-layer", WIDTH, HEIGHT,
+ LayerCreationArgs args(flinger.flinger(), client, "buffer-state-layer", WIDTH, HEIGHT,
LAYER_FLAGS, LayerMetadata());
return new BufferStateLayer(args);
}
@@ -188,7 +188,8 @@ void SetFrameRateTest::setupScheduler() {
.WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD));
EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0));
mFlinger.setupScheduler(std::move(vsyncController), std::move(vsyncTracker),
- std::move(eventThread), std::move(sfEventThread));
+ std::move(eventThread), std::move(sfEventThread), /*callback*/ nullptr,
+ /*hasMultipleModes*/ true);
}
void SetFrameRateTest::setupComposer(uint32_t virtualDisplayCount) {
@@ -488,5 +489,28 @@ TEST_F(SetFrameRateTest, ValidateFrameRate) {
EXPECT_FALSE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_EXACT, ""));
}
+TEST_P(SetFrameRateTest, SetOnParentActivatesTree) {
+ const auto& layerFactory = GetParam();
+
+ auto parent = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+ if (!parent->isVisible()) {
+ // This is a hack as all the test layers except EffectLayer are not visible,
+ // but since the logic is unified in Layer, it should be fine.
+ return;
+ }
+
+ auto child = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+ addChild(parent, child);
+
+ parent->setFrameRate(FRAME_RATE_VOTE1);
+ commitTransaction();
+
+ const auto layerHistorySummary =
+ mFlinger.mutableScheduler().mutableLayerHistory()->summarize(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));
+}
+
} // namespace
} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index ce2bfefc44..63baf7dee2 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -246,6 +246,8 @@ public:
void resetScheduler(Scheduler* scheduler) { mFlinger->mScheduler.reset(scheduler); }
+ TestableScheduler& mutableScheduler() const { return *mScheduler; }
+
using CreateBufferQueueFunction = surfaceflinger::test::Factory::CreateBufferQueueFunction;
void setCreateBufferQueueFunction(CreateBufferQueueFunction f) {
mFactory.mCreateBufferQueue = f;
@@ -410,6 +412,10 @@ public:
const auto& getCompositorTiming() const { return mFlinger->getBE().mCompositorTiming; }
+ mock::FrameTracer* getFrameTracer() const {
+ return static_cast<mock::FrameTracer*>(mFlinger->mFrameTracer.get());
+ }
+
/* ------------------------------------------------------------------------
* Read-write access to private data to set up preconditions and assert
* post-conditions.
@@ -630,7 +636,7 @@ public:
public:
FakeDisplayDeviceInjector(TestableSurfaceFlinger& flinger,
std::shared_ptr<compositionengine::Display> compositionDisplay,
- std::optional<DisplayConnectionType> connectionType,
+ std::optional<ui::DisplayConnectionType> connectionType,
std::optional<hal::HWDisplayId> hwcDisplayId, bool isPrimary)
: mFlinger(flinger),
mCreationArgs(flinger.mFlinger.get(), flinger.mFlinger->getHwComposer(),
diff --git a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
index df4464ef52..e90366448c 100644
--- a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
@@ -55,14 +55,21 @@ using testing::UnorderedElementsAre;
using PowerMode = hardware::graphics::composer::V2_4::IComposerClient::PowerMode;
// clang-format off
-#define FMT_PROTO true
-#define FMT_STRING false
-#define LAYER_ID_0 0
-#define LAYER_ID_1 1
-#define UID_0 123
-#define LAYER_ID_INVALID -1
-#define NUM_LAYERS 1
-#define NUM_LAYERS_INVALID "INVALID"
+#define FMT_PROTO true
+#define FMT_STRING false
+#define LAYER_ID_0 0
+#define LAYER_ID_1 1
+#define UID_0 123
+#define REFRESH_RATE_0 61
+#define RENDER_RATE_0 31
+#define REFRESH_RATE_BUCKET_0 60
+#define RENDER_RATE_BUCKET_0 30
+#define LAYER_ID_INVALID -1
+#define NUM_LAYERS 1
+#define NUM_LAYERS_INVALID "INVALID"
+
+const constexpr Fps kRefreshRate0 = Fps(static_cast<float>(REFRESH_RATE_0));
+const constexpr Fps kRenderRate0 = Fps(static_cast<float>(RENDER_RATE_0));
enum InputCommand : int32_t {
ENABLE = 0,
@@ -246,11 +253,13 @@ void TimeStatsTest::setTimeStamp(TimeStamp type, int32_t id, uint64_t frameNumbe
ASSERT_NO_FATAL_FAILURE(mTimeStats->setDesiredTime(id, frameNumber, ts));
break;
case TimeStamp::PRESENT:
- ASSERT_NO_FATAL_FAILURE(mTimeStats->setPresentTime(id, frameNumber, ts));
+ ASSERT_NO_FATAL_FAILURE(
+ mTimeStats->setPresentTime(id, frameNumber, ts, kRefreshRate0, kRenderRate0));
break;
case TimeStamp::PRESENT_FENCE:
- ASSERT_NO_FATAL_FAILURE(
- mTimeStats->setPresentFence(id, frameNumber, std::make_shared<FenceTime>(ts)));
+ ASSERT_NO_FATAL_FAILURE(mTimeStats->setPresentFence(id, frameNumber,
+ std::make_shared<FenceTime>(ts),
+ kRefreshRate0, kRenderRate0));
break;
default:
ALOGD("Invalid timestamp type");
@@ -352,58 +361,52 @@ TEST_F(TimeStatsTest, canIncreaseBadDesiredPresent) {
EXPECT_THAT(result, HasSubstr(expectedResult));
}
-TEST_F(TimeStatsTest, canIncreaseJankyFrames) {
+TEST_F(TimeStatsTest, canIncreaseJankyFramesForLayer) {
// this stat is not in the proto so verify by checking the string dump
EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
- mTimeStats->incrementJankyFrames(JankType::SurfaceFlingerCpuDeadlineMissed);
- mTimeStats->incrementJankyFrames(JankType::SurfaceFlingerGpuDeadlineMissed);
- mTimeStats->incrementJankyFrames(JankType::DisplayHAL);
- mTimeStats->incrementJankyFrames(JankType::AppDeadlineMissed);
- mTimeStats->incrementJankyFrames(JankType::None);
+ mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+ JankType::SurfaceFlingerCpuDeadlineMissed, 1, 2, 3});
+ mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+ JankType::SurfaceFlingerGpuDeadlineMissed, 1, 2, 3});
+ mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+ JankType::DisplayHAL, 1, 2, 3});
+ mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+ JankType::AppDeadlineMissed, 1, 2, 3});
+ mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+ JankType::SurfaceFlingerScheduling, 1, 2, 3});
+ mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+ JankType::PredictionError, 1, 2, 3});
+ mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+ JankType::AppDeadlineMissed | JankType::BufferStuffing, 1, 2,
+ 3});
+ mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+ JankType::None, 1, 2, 3});
const std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING));
- std::string expectedResult = "totalTimelineFrames = " + std::to_string(5);
+ std::string expectedResult =
+ "displayRefreshRate = " + std::to_string(REFRESH_RATE_BUCKET_0) + " fps";
EXPECT_THAT(result, HasSubstr(expectedResult));
- expectedResult = "jankyFrames = " + std::to_string(4);
+ expectedResult = "renderRate = " + std::to_string(RENDER_RATE_BUCKET_0) + " fps";
EXPECT_THAT(result, HasSubstr(expectedResult));
- expectedResult = "sfLongCpuJankyFrames = " + std::to_string(1);
+ expectedResult = "totalTimelineFrames = " + std::to_string(8);
EXPECT_THAT(result, HasSubstr(expectedResult));
- expectedResult = "sfLongGpuJankyFrames = " + std::to_string(1);
- EXPECT_THAT(result, HasSubstr(expectedResult));
- expectedResult = "sfUnattributedJankyFrame = " + std::to_string(1);
+ expectedResult = "jankyFrames = " + std::to_string(7);
EXPECT_THAT(result, HasSubstr(expectedResult));
- expectedResult = "appUnattributedJankyFrame = " + std::to_string(1);
+ expectedResult = "sfLongCpuJankyFrames = " + std::to_string(1);
EXPECT_THAT(result, HasSubstr(expectedResult));
-}
-
-TEST_F(TimeStatsTest, canIncreaseJankyFramesForLayer) {
- // this stat is not in the proto so verify by checking the string dump
- EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
-
- insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
- mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0),
- JankType::SurfaceFlingerCpuDeadlineMissed);
- mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0),
- JankType::SurfaceFlingerGpuDeadlineMissed);
- mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0), JankType::DisplayHAL);
- mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0),
- JankType::AppDeadlineMissed);
- mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0), JankType::None);
-
- const std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING));
- std::string expectedResult = "totalTimelineFrames = " + std::to_string(5);
+ expectedResult = "sfLongGpuJankyFrames = " + std::to_string(1);
EXPECT_THAT(result, HasSubstr(expectedResult));
- expectedResult = "jankyFrames = " + std::to_string(4);
+ expectedResult = "sfUnattributedJankyFrames = " + std::to_string(1);
EXPECT_THAT(result, HasSubstr(expectedResult));
- expectedResult = "sfLongCpuJankyFrames = " + std::to_string(1);
+ expectedResult = "appUnattributedJankyFrames = " + std::to_string(2);
EXPECT_THAT(result, HasSubstr(expectedResult));
- expectedResult = "sfLongGpuJankyFrames = " + std::to_string(1);
+ expectedResult = "sfSchedulingJankyFrames = " + std::to_string(1);
EXPECT_THAT(result, HasSubstr(expectedResult));
- expectedResult = "sfUnattributedJankyFrame = " + std::to_string(1);
+ expectedResult = "sfPredictionErrorJankyFrames = " + std::to_string(1);
EXPECT_THAT(result, HasSubstr(expectedResult));
- expectedResult = "appUnattributedJankyFrame = " + std::to_string(1);
+ expectedResult = "appBufferStuffingJankyFrames = " + std::to_string(1);
EXPECT_THAT(result, HasSubstr(expectedResult));
}
@@ -455,14 +458,10 @@ TEST_F(TimeStatsTest, canIncreaseCompositionStrategyChanges) {
TEST_F(TimeStatsTest, canAverageFrameDuration) {
EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
mTimeStats->setPowerMode(PowerMode::ON);
- mTimeStats
- ->recordFrameDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(1ms).count(),
- std::chrono::duration_cast<std::chrono::nanoseconds>(6ms)
- .count());
- mTimeStats
- ->recordFrameDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(1ms).count(),
- std::chrono::duration_cast<std::chrono::nanoseconds>(16ms)
- .count());
+ mTimeStats->recordFrameDuration(std::chrono::nanoseconds(1ms).count(),
+ std::chrono::nanoseconds(6ms).count());
+ mTimeStats->recordFrameDuration(std::chrono::nanoseconds(1ms).count(),
+ std::chrono::nanoseconds(16ms).count());
const std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING));
EXPECT_THAT(result, HasSubstr("averageFrameDuration = 10.000 ms"));
@@ -470,22 +469,19 @@ TEST_F(TimeStatsTest, canAverageFrameDuration) {
TEST_F(TimeStatsTest, canAverageRenderEngineTimings) {
EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
- mTimeStats->recordRenderEngineDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(1ms)
- .count(),
+ mTimeStats->recordRenderEngineDuration(std::chrono::nanoseconds(1ms).count(),
std::make_shared<FenceTime>(
std::chrono::duration_cast<
std::chrono::nanoseconds>(3ms)
.count()));
- mTimeStats->recordRenderEngineDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(4ms)
- .count(),
- std::chrono::duration_cast<std::chrono::nanoseconds>(8ms)
- .count());
+ mTimeStats->recordRenderEngineDuration(std::chrono::nanoseconds(4ms).count(),
+ std::chrono::nanoseconds(8ms).count());
// Push a fake present fence to trigger flushing the RenderEngine timings.
mTimeStats->setPowerMode(PowerMode::ON);
- mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(
- std::chrono::duration_cast<std::chrono::nanoseconds>(1ms).count()));
+ mTimeStats->setPresentFenceGlobal(
+ std::make_shared<FenceTime>(std::chrono::nanoseconds(1ms).count()));
const std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING));
EXPECT_THAT(result, HasSubstr("averageRenderEngineTiming = 3.000 ms"));
@@ -524,15 +520,11 @@ TEST_F(TimeStatsTest, canInsertGlobalFrameDuration) {
EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
mTimeStats->setPowerMode(PowerMode::OFF);
- mTimeStats
- ->recordFrameDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(1ms).count(),
- std::chrono::duration_cast<std::chrono::nanoseconds>(5ms)
- .count());
+ mTimeStats->recordFrameDuration(std::chrono::nanoseconds(1ms).count(),
+ std::chrono::nanoseconds(5ms).count());
mTimeStats->setPowerMode(PowerMode::ON);
- mTimeStats
- ->recordFrameDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(3ms).count(),
- std::chrono::duration_cast<std::chrono::nanoseconds>(6ms)
- .count());
+ mTimeStats->recordFrameDuration(std::chrono::nanoseconds(3ms).count(),
+ std::chrono::nanoseconds(6ms).count());
SFTimeStatsGlobalProto globalProto;
ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
@@ -546,17 +538,14 @@ TEST_F(TimeStatsTest, canInsertGlobalFrameDuration) {
TEST_F(TimeStatsTest, canInsertGlobalRenderEngineTiming) {
EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
- mTimeStats->recordRenderEngineDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(1ms)
- .count(),
+ mTimeStats->recordRenderEngineDuration(std::chrono::nanoseconds(1ms).count(),
std::make_shared<FenceTime>(
std::chrono::duration_cast<
std::chrono::nanoseconds>(3ms)
.count()));
- mTimeStats->recordRenderEngineDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(4ms)
- .count(),
- std::chrono::duration_cast<std::chrono::nanoseconds>(6ms)
- .count());
+ mTimeStats->recordRenderEngineDuration(std::chrono::nanoseconds(4ms).count(),
+ std::chrono::nanoseconds(6ms).count());
// First verify that flushing RenderEngine durations did not occur yet.
SFTimeStatsGlobalProto preFlushProto;
@@ -565,8 +554,8 @@ TEST_F(TimeStatsTest, canInsertGlobalRenderEngineTiming) {
// Push a fake present fence to trigger flushing the RenderEngine timings.
mTimeStats->setPowerMode(PowerMode::ON);
- mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(
- std::chrono::duration_cast<std::chrono::nanoseconds>(1ms).count()));
+ mTimeStats->setPresentFenceGlobal(
+ std::make_shared<FenceTime>(std::chrono::nanoseconds(1ms).count()));
// Now we can verify that RenderEngine durations were flushed now.
SFTimeStatsGlobalProto postFlushProto;
@@ -801,14 +790,10 @@ TEST_F(TimeStatsTest, canClearTimeStats) {
ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementClientCompositionFrames());
ASSERT_NO_FATAL_FAILURE(mTimeStats->setPowerMode(PowerMode::ON));
- mTimeStats
- ->recordFrameDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(3ms).count(),
- std::chrono::duration_cast<std::chrono::nanoseconds>(6ms)
- .count());
- mTimeStats->recordRenderEngineDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(4ms)
- .count(),
- std::chrono::duration_cast<std::chrono::nanoseconds>(6ms)
- .count());
+ mTimeStats->recordFrameDuration(std::chrono::nanoseconds(3ms).count(),
+ std::chrono::nanoseconds(6ms).count());
+ mTimeStats->recordRenderEngineDuration(std::chrono::nanoseconds(4ms).count(),
+ std::chrono::nanoseconds(6ms).count());
ASSERT_NO_FATAL_FAILURE(
mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(1000000)));
ASSERT_NO_FATAL_FAILURE(
@@ -837,25 +822,30 @@ TEST_F(TimeStatsTest, canClearDumpOnlyTimeStats) {
ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementRefreshRateSwitches());
ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementCompositionStrategyChanges());
mTimeStats->setPowerMode(PowerMode::ON);
- mTimeStats
- ->recordFrameDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(1ms).count(),
- std::chrono::duration_cast<std::chrono::nanoseconds>(5ms)
- .count());
- mTimeStats->recordRenderEngineDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(4ms)
- .count(),
- std::chrono::duration_cast<std::chrono::nanoseconds>(6ms)
- .count());
- mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(
- std::chrono::duration_cast<std::chrono::nanoseconds>(1ms).count()));
-
- mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0),
- JankType::SurfaceFlingerCpuDeadlineMissed);
- mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0),
- JankType::SurfaceFlingerGpuDeadlineMissed);
- mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0), JankType::DisplayHAL);
- mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0),
- JankType::AppDeadlineMissed);
- mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0), JankType::None);
+ mTimeStats->recordFrameDuration(std::chrono::nanoseconds(1ms).count(),
+ std::chrono::nanoseconds(5ms).count());
+ mTimeStats->recordRenderEngineDuration(std::chrono::nanoseconds(4ms).count(),
+ std::chrono::nanoseconds(6ms).count());
+ mTimeStats->setPresentFenceGlobal(
+ std::make_shared<FenceTime>(std::chrono::nanoseconds(1ms).count()));
+
+ mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+ JankType::SurfaceFlingerCpuDeadlineMissed, 1, 2, 3});
+ mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+ JankType::SurfaceFlingerGpuDeadlineMissed, 1, 2, 3});
+ mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+ JankType::DisplayHAL, 1, 2, 3});
+ mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+ JankType::AppDeadlineMissed, 1, 2, 3});
+ mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+ JankType::SurfaceFlingerScheduling, 1, 2, 3});
+ mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+ JankType::PredictionError, 1, 2, 3});
+ mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+ JankType::AppDeadlineMissed | JankType::BufferStuffing, 1, 2,
+ 3});
+ mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+ JankType::None, 1, 2, 3});
EXPECT_TRUE(inputCommand(InputCommand::CLEAR, FMT_STRING).empty());
@@ -865,11 +855,6 @@ TEST_F(TimeStatsTest, canClearDumpOnlyTimeStats) {
EXPECT_THAT(result, HasSubstr("compositionStrategyChanges = 0"));
EXPECT_THAT(result, HasSubstr("averageFrameDuration = 0.000 ms"));
EXPECT_THAT(result, HasSubstr("averageRenderEngineTiming = 0.000 ms"));
- EXPECT_THAT(result, HasSubstr("jankyFrames = 0"));
- EXPECT_THAT(result, HasSubstr("sfLongCpuJankyFrames = 0"));
- EXPECT_THAT(result, HasSubstr("sfLongGpuJankyFrames = 0"));
- EXPECT_THAT(result, HasSubstr("sfUnattributedJankyFrame = 0"));
- EXPECT_THAT(result, HasSubstr("appUnattributedJankyFrame = 0"));
}
TEST_F(TimeStatsTest, canDumpWithMaxLayers) {
@@ -1000,11 +985,23 @@ TEST_F(TimeStatsTest, globalStatsCallback) {
mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(3000000));
mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(5000000));
- mTimeStats->incrementJankyFrames(JankType::SurfaceFlingerCpuDeadlineMissed);
- mTimeStats->incrementJankyFrames(JankType::SurfaceFlingerGpuDeadlineMissed);
- mTimeStats->incrementJankyFrames(JankType::DisplayHAL);
- mTimeStats->incrementJankyFrames(JankType::AppDeadlineMissed);
- mTimeStats->incrementJankyFrames(JankType::None);
+ mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+ JankType::SurfaceFlingerCpuDeadlineMissed, 1, 2, 3});
+ mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+ JankType::SurfaceFlingerGpuDeadlineMissed, 1, 2, 3});
+ mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+ JankType::DisplayHAL, 1, 2, 3});
+ mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+ JankType::AppDeadlineMissed, 1, 2, 3});
+ mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+ JankType::SurfaceFlingerScheduling, 1, 2, 3});
+ mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+ JankType::PredictionError, 1, 2, 3});
+ mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+ JankType::AppDeadlineMissed | JankType::BufferStuffing, 1, 2,
+ 3});
+ mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+ JankType::None, 1, 2, 3});
EXPECT_THAT(mDelegate->mAtomTags,
UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
@@ -1015,6 +1012,8 @@ TEST_F(TimeStatsTest, globalStatsCallback) {
std::string expectedFrameDuration = buildExpectedHistogramBytestring({2}, {1});
std::string expectedRenderEngineTiming = buildExpectedHistogramBytestring({1, 2}, {1, 1});
std::string expectedEmptyHistogram = buildExpectedHistogramBytestring({}, {});
+ std::string expectedSfDeadlineMissed = buildExpectedHistogramBytestring({1}, {7});
+ std::string expectedSfPredictionErrors = buildExpectedHistogramBytestring({2}, {7});
{
InSequence seq;
@@ -1038,27 +1037,29 @@ TEST_F(TimeStatsTest, globalStatsCallback) {
expectedRenderEngineTiming.c_str(),
expectedRenderEngineTiming.size()),
expectedRenderEngineTiming.size()));
- EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 5));
- EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 4));
+ EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 8));
+ EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 7));
+ EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 1));
+ EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 1));
EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 1));
+ EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 2));
EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 1));
EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 1));
EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 1));
- EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 0));
- EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 0));
- EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 0));
- EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 0));
+ EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, REFRESH_RATE_BUCKET_0));
EXPECT_CALL(*mDelegate,
statsEventWriteByteArray(mDelegate->mEvent,
- BytesEq((const uint8_t*)expectedEmptyHistogram.c_str(),
- expectedEmptyHistogram.size()),
- expectedEmptyHistogram.size()));
+ BytesEq((const uint8_t*)
+ expectedSfDeadlineMissed.c_str(),
+ expectedSfDeadlineMissed.size()),
+ expectedSfDeadlineMissed.size()));
EXPECT_CALL(*mDelegate,
statsEventWriteByteArray(mDelegate->mEvent,
- BytesEq((const uint8_t*)expectedEmptyHistogram.c_str(),
- expectedEmptyHistogram.size()),
- expectedEmptyHistogram.size()));
- EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 0));
+ BytesEq((const uint8_t*)
+ expectedSfPredictionErrors.c_str(),
+ expectedSfPredictionErrors.size()),
+ expectedSfPredictionErrors.size()));
+ EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, RENDER_RATE_BUCKET_0));
EXPECT_CALL(*mDelegate, statsEventBuild(mDelegate->mEvent));
}
@@ -1091,14 +1092,23 @@ TEST_F(TimeStatsTest, layerStatsCallback_pullsAllAndClears) {
}
insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000);
- mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0),
- JankType::SurfaceFlingerCpuDeadlineMissed);
- mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0),
- JankType::SurfaceFlingerGpuDeadlineMissed);
- mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0), JankType::DisplayHAL);
- mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0),
- JankType::AppDeadlineMissed);
- mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0), JankType::None);
+ mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+ JankType::SurfaceFlingerCpuDeadlineMissed, 1, 2, 3});
+ mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+ JankType::SurfaceFlingerGpuDeadlineMissed, 1, 2, 3});
+ mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+ JankType::DisplayHAL, 1, 2, 3});
+ mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+ JankType::AppDeadlineMissed, 1, 2, 3});
+ mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+ JankType::SurfaceFlingerScheduling, 1, 2, 2});
+ mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+ JankType::PredictionError, 1, 2, 2});
+ mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+ JankType::AppDeadlineMissed | JankType::BufferStuffing, 1, 2,
+ 2});
+ mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+ JankType::None, 1, 2, 3});
EXPECT_THAT(mDelegate->mAtomTags,
UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
@@ -1113,7 +1123,7 @@ TEST_F(TimeStatsTest, layerStatsCallback_pullsAllAndClears) {
std::string expectedDesiredToPresent = buildExpectedHistogramBytestring({1}, {1});
std::string expectedPostToAcquire = buildExpectedHistogramBytestring({1}, {1});
std::string expectedFrameRateOverride = frameRateVoteToProtoByteString(0.0, 0, 0);
- std::string expectedEmptyHistogram = buildExpectedHistogramBytestring({}, {});
+ std::string expectedAppDeadlineMissed = buildExpectedHistogramBytestring({3, 2}, {4, 3});
{
InSequence seq;
EXPECT_CALL(*mDelegate,
@@ -1161,17 +1171,17 @@ TEST_F(TimeStatsTest, layerStatsCallback_pullsAllAndClears) {
EXPECT_CALL(*mDelegate,
statsEventWriteInt64(mDelegate->mEvent, BAD_DESIRED_PRESENT_FRAMES));
EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, UID_0));
- EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 5));
- EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 4));
+ EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 8));
+ EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 7));
EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 1));
EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 1));
EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 1));
+ EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 2));
EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 1));
- EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 0));
- EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 0));
- EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 0));
- EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 0));
- EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 0));
+ EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 1));
+ EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 1));
+ EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, REFRESH_RATE_BUCKET_0));
+ EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, RENDER_RATE_BUCKET_0));
EXPECT_CALL(*mDelegate,
statsEventWriteByteArray(mDelegate->mEvent,
BytesEq((const uint8_t*)
@@ -1180,9 +1190,10 @@ TEST_F(TimeStatsTest, layerStatsCallback_pullsAllAndClears) {
expectedFrameRateOverride.size()));
EXPECT_CALL(*mDelegate,
statsEventWriteByteArray(mDelegate->mEvent,
- BytesEq((const uint8_t*)expectedEmptyHistogram.c_str(),
- expectedEmptyHistogram.size()),
- expectedEmptyHistogram.size()));
+ BytesEq((const uint8_t*)
+ expectedAppDeadlineMissed.c_str(),
+ expectedAppDeadlineMissed.size()),
+ expectedAppDeadlineMissed.size()));
EXPECT_CALL(*mDelegate, statsEventBuild(mDelegate->mEvent));
}
diff --git a/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp b/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp
new file mode 100644
index 0000000000..dbadf75d44
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "LibSurfaceFlingerUnittests"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <gui/SurfaceComposerClient.h>
+#include <log/log.h>
+#include <utils/String8.h>
+
+#include "TestableSurfaceFlinger.h"
+#include "mock/DisplayHardware/MockComposer.h"
+#include "mock/MockEventThread.h"
+#include "mock/MockVsyncController.h"
+
+namespace android {
+
+using testing::_;
+using testing::Mock;
+using testing::Return;
+using FakeHwcDisplayInjector = TestableSurfaceFlinger::FakeHwcDisplayInjector;
+using PresentState = frametimeline::SurfaceFrame::PresentState;
+
+class TransactionFrameTracerTest : public testing::Test {
+public:
+ TransactionFrameTracerTest() {
+ 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());
+ setupScheduler();
+ setupComposer(0);
+ }
+
+ ~TransactionFrameTracerTest() {
+ const ::testing::TestInfo* const test_info =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+ ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
+ }
+
+ sp<BufferStateLayer> createBufferStateLayer() {
+ sp<Client> client;
+ LayerCreationArgs args(mFlinger.flinger(), client, "buffer-state-layer", 100, 100, 0,
+ LayerMetadata());
+ return new BufferStateLayer(args);
+ }
+
+ void commitTransaction(Layer* layer) {
+ layer->pushPendingState();
+ auto c = layer->getCurrentState();
+ if (layer->applyPendingStates(&c)) {
+ layer->commitTransaction(c);
+ }
+ }
+
+ void setupScheduler() {
+ auto eventThread = std::make_unique<mock::EventThread>();
+ auto sfEventThread = std::make_unique<mock::EventThread>();
+
+ EXPECT_CALL(*eventThread, registerDisplayEventConnection(_));
+ EXPECT_CALL(*eventThread, createEventConnection(_, _))
+ .WillOnce(Return(new EventThreadConnection(eventThread.get(), /*callingUid=*/0,
+ ResyncCallback())));
+
+ EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_));
+ EXPECT_CALL(*sfEventThread, createEventConnection(_, _))
+ .WillOnce(Return(new EventThreadConnection(sfEventThread.get(), /*callingUid=*/0,
+ ResyncCallback())));
+
+ auto vsyncController = std::make_unique<mock::VsyncController>();
+ auto vsyncTracker = std::make_unique<mock::VSyncTracker>();
+
+ EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0));
+ EXPECT_CALL(*vsyncTracker, currentPeriod())
+ .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD));
+ EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0));
+ mFlinger.setupScheduler(std::move(vsyncController), std::move(vsyncTracker),
+ std::move(eventThread), std::move(sfEventThread));
+ }
+
+ void setupComposer(uint32_t virtualDisplayCount) {
+ mComposer = new Hwc2::mock::Composer();
+ EXPECT_CALL(*mComposer, getMaxVirtualDisplayCount()).WillOnce(Return(virtualDisplayCount));
+ mFlinger.setupComposer(std::unique_ptr<Hwc2::Composer>(mComposer));
+
+ Mock::VerifyAndClear(mComposer);
+ }
+
+ TestableSurfaceFlinger mFlinger;
+ Hwc2::mock::Composer* mComposer = nullptr;
+ FenceToFenceTimeMap fenceFactory;
+ client_cache_t mClientCache;
+
+ void BLASTTransactionSendsFrameTracerEvents() {
+ sp<BufferStateLayer> layer = createBufferStateLayer();
+
+ sp<Fence> fence(new Fence());
+ sp<GraphicBuffer> buffer{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)};
+ int32_t layerId = layer->getSequence();
+ uint64_t bufferId = buffer->getId();
+ uint64_t frameNumber = 5;
+ nsecs_t dequeueTime = 10;
+ nsecs_t postTime = 20;
+ EXPECT_CALL(*mFlinger.getFrameTracer(), traceNewLayer(layerId, "buffer-state-layer"));
+ EXPECT_CALL(*mFlinger.getFrameTracer(),
+ traceTimestamp(layerId, bufferId, frameNumber, dequeueTime,
+ FrameTracer::FrameEvent::DEQUEUE, /*duration*/ 0));
+ EXPECT_CALL(*mFlinger.getFrameTracer(),
+ traceTimestamp(layerId, bufferId, frameNumber, postTime,
+ FrameTracer::FrameEvent::QUEUE, /*duration*/ 0));
+ layer->setBuffer(buffer, fence, postTime, /*desiredPresentTime*/ 30, false, mClientCache,
+ frameNumber, dequeueTime, FrameTimelineInfo{});
+
+ commitTransaction(layer.get());
+ bool computeVisisbleRegions;
+ nsecs_t latchTime = 25;
+ EXPECT_CALL(*mFlinger.getFrameTracer(),
+ traceFence(layerId, bufferId, frameNumber, _,
+ FrameTracer::FrameEvent::ACQUIRE_FENCE, /*startTime*/ 0));
+ EXPECT_CALL(*mFlinger.getFrameTracer(),
+ traceTimestamp(layerId, bufferId, frameNumber, latchTime,
+ FrameTracer::FrameEvent::LATCH, /*duration*/ 0));
+ layer->updateTexImage(computeVisisbleRegions, latchTime, /*expectedPresentTime*/ 0);
+
+ auto glDoneFence = fenceFactory.createFenceTimeForTest(fence);
+ auto presentFence = fenceFactory.createFenceTimeForTest(fence);
+ CompositorTiming compositorTiming;
+ EXPECT_CALL(*mFlinger.getFrameTracer(),
+ traceFence(layerId, bufferId, frameNumber, presentFence,
+ FrameTracer::FrameEvent::PRESENT_FENCE, /*startTime*/ 0));
+ layer->onPostComposition(nullptr, glDoneFence, presentFence, compositorTiming);
+ }
+};
+
+TEST_F(TransactionFrameTracerTest, BLASTTransactionSendsFrameTracerEvents) {
+ BLASTTransactionSendsFrameTracerEvents();
+}
+
+} // namespace android \ No newline at end of file
diff --git a/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp b/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp
index aa6798d84c..bf9ec39c35 100644
--- a/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp
@@ -157,8 +157,10 @@ public:
sp<Fence> fence2(new Fence());
auto acquireFence2 = fenceFactory.createFenceTimeForTest(fence2);
sp<GraphicBuffer> buffer2{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)};
+ nsecs_t start = systemTime();
layer->setBuffer(buffer2, fence2, 10, 20, false, mClientCache, 1, std::nullopt,
{/*vsyncId*/ 1, /*inputEventId*/ 0});
+ nsecs_t end = systemTime();
acquireFence2->signalForTest(12);
EXPECT_EQ(0u, layer->mCurrentState.bufferlessSurfaceFramesTX.size());
@@ -171,6 +173,9 @@ public:
EXPECT_EQ(1, droppedSurfaceFrame->getToken());
EXPECT_EQ(PresentState::Dropped, droppedSurfaceFrame->getPresentState());
+ EXPECT_EQ(0u, droppedSurfaceFrame->getActuals().endTime);
+ auto dropTime = droppedSurfaceFrame->getDropTime();
+ EXPECT_TRUE(dropTime > start && dropTime < end);
EXPECT_EQ(1, presentedSurfaceFrame->getToken());
EXPECT_EQ(PresentState::Presented, presentedSurfaceFrame->getPresentState());
@@ -328,6 +333,41 @@ public:
EXPECT_EQ(PresentState::Presented, bufferlessSurfaceFrame2->getPresentState());
EXPECT_EQ(12, bufferlessSurfaceFrame2->getActuals().endTime);
}
+
+ void PendingSurfaceFramesRemovedAfterClassification() {
+ sp<BufferStateLayer> layer = createBufferStateLayer();
+
+ sp<Fence> fence1(new Fence());
+ auto acquireFence1 = fenceFactory.createFenceTimeForTest(fence1);
+ sp<GraphicBuffer> buffer1{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)};
+ layer->setBuffer(buffer1, fence1, 10, 20, false, mClientCache, 1, std::nullopt,
+ {/*vsyncId*/ 1, /*inputEventId*/ 0});
+ ASSERT_NE(nullptr, layer->mCurrentState.bufferSurfaceFrameTX);
+ const auto droppedSurfaceFrame = layer->mCurrentState.bufferSurfaceFrameTX;
+
+ sp<Fence> fence2(new Fence());
+ auto acquireFence2 = fenceFactory.createFenceTimeForTest(fence2);
+ sp<GraphicBuffer> buffer2{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)};
+ layer->setBuffer(buffer2, fence2, 10, 20, false, mClientCache, 1, std::nullopt,
+ {/*vsyncId*/ 1, /*inputEventId*/ 0});
+ acquireFence2->signalForTest(12);
+
+ ASSERT_NE(nullptr, layer->mCurrentState.bufferSurfaceFrameTX);
+ auto& presentedSurfaceFrame = layer->mCurrentState.bufferSurfaceFrameTX;
+
+ commitTransaction(layer.get());
+ bool computeVisisbleRegions;
+ layer->updateTexImage(computeVisisbleRegions, 15, 0);
+
+ // Both the droppedSurfaceFrame and presentedSurfaceFrame should be in
+ // pendingJankClassifications.
+ EXPECT_EQ(2u, layer->mPendingJankClassifications.size());
+ presentedSurfaceFrame->onPresent(20, JankType::None, Fps::fromPeriodNsecs(11),
+ /*displayDeadlineDelta*/ 0, /*displayPresentDelta*/ 0);
+ layer->releasePendingBuffer(25);
+
+ EXPECT_EQ(0u, layer->mPendingJankClassifications.size());
+ }
};
TEST_F(TransactionSurfaceFrameTest, PresentedBufferlessSurfaceFrame) {
@@ -364,4 +404,7 @@ TEST_F(TransactionSurfaceFrameTest,
MergePendingStates_BufferlessSurfaceFramesWithOverlappingToken();
}
+TEST_F(TransactionSurfaceFrameTest, PendingSurfaceFramesRemovedAfterClassification) {
+ PendingSurfaceFramesRemovedAfterClassification();
+}
} // namespace android \ No newline at end of file
diff --git a/services/surfaceflinger/tests/unittests/mock/MockFrameTimeline.h b/services/surfaceflinger/tests/unittests/mock/MockFrameTimeline.h
index 0a6a9f4550..44b9b73fd4 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockFrameTimeline.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockFrameTimeline.h
@@ -31,7 +31,7 @@ public:
MOCK_METHOD0(onBootFinished, void());
MOCK_METHOD1(addSurfaceFrame, void(std::shared_ptr<frametimeline::SurfaceFrame>));
- MOCK_METHOD3(setSfWakeUp, void(int64_t, nsecs_t, nsecs_t));
+ MOCK_METHOD3(setSfWakeUp, void(int64_t, nsecs_t, Fps));
MOCK_METHOD2(setSfPresent, void(nsecs_t, const std::shared_ptr<FenceTime>&));
};
diff --git a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
index 99ec353095..3e4a0b8c09 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
@@ -48,10 +48,11 @@ public:
MOCK_METHOD3(setDesiredTime, void(int32_t, uint64_t, nsecs_t));
MOCK_METHOD3(setAcquireTime, void(int32_t, uint64_t, nsecs_t));
MOCK_METHOD3(setAcquireFence, void(int32_t, uint64_t, const std::shared_ptr<FenceTime>&));
- MOCK_METHOD3(setPresentTime, void(int32_t, uint64_t, nsecs_t));
- MOCK_METHOD3(setPresentFence, void(int32_t, uint64_t, const std::shared_ptr<FenceTime>&));
- MOCK_METHOD1(incrementJankyFrames, void(int32_t));
- MOCK_METHOD3(incrementJankyFrames, void(uid_t, const std::string&, int32_t));
+ MOCK_METHOD5(setPresentTime, void(int32_t, uint64_t, nsecs_t, Fps, std::optional<Fps>));
+ MOCK_METHOD5(setPresentFence,
+ void(int32_t, uint64_t, const std::shared_ptr<FenceTime>&, Fps,
+ std::optional<Fps>));
+ MOCK_METHOD1(incrementJankyFrames, void(const JankyFramesInfo&));
MOCK_METHOD1(onDestroy, void(int32_t));
MOCK_METHOD2(removeTimeRecord, void(int32_t, uint64_t));
MOCK_METHOD1(setPowerMode,
diff --git a/services/surfaceflinger/tests/vsync/Android.bp b/services/surfaceflinger/tests/vsync/Android.bp
index 6a89945a92..bae9796598 100644
--- a/services/surfaceflinger/tests/vsync/Android.bp
+++ b/services/surfaceflinger/tests/vsync/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_binary {
name: "test-vsync-events",
defaults: ["surfaceflinger_defaults"],
diff --git a/services/surfaceflinger/tests/waitforvsync/Android.bp b/services/surfaceflinger/tests/waitforvsync/Android.bp
index cb6d0fde0d..ffed4d77c7 100644
--- a/services/surfaceflinger/tests/waitforvsync/Android.bp
+++ b/services/surfaceflinger/tests/waitforvsync/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_binary {
name: "test-waitforvsync",
cflags: [
diff --git a/services/utils/Android.bp b/services/utils/Android.bp
index f3d2bc9766..81e1232e2c 100644
--- a/services/utils/Android.bp
+++ b/services/utils/Android.bp
@@ -15,6 +15,15 @@
//
// Static library used in testing and executables
//
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library_static {
name: "libserviceutils",
diff --git a/services/utils/tests/Android.bp b/services/utils/tests/Android.bp
index f21254cd7d..54cf5b7404 100644
--- a/services/utils/tests/Android.bp
+++ b/services/utils/tests/Android.bp
@@ -14,6 +14,15 @@
// Build unit tests.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_test {
name: "prioritydumper_test",
test_suites: ["device-tests"],
diff --git a/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp b/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp
index 96b76ba2fe..f85fa10e0d 100644
--- a/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp
+++ b/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp
@@ -77,6 +77,8 @@ public:
MOCK_METHOD(Status, getSupportedAlwaysOnEffects, (std::vector<Effect> * ret), (override));
MOCK_METHOD(Status, alwaysOnEnable, (int32_t id, Effect e, EffectStrength s), (override));
MOCK_METHOD(Status, alwaysOnDisable, (int32_t id), (override));
+ MOCK_METHOD(Status, getQFactor, (float * ret), (override));
+ MOCK_METHOD(Status, getResonantFrequency, (float * ret), (override));
MOCK_METHOD(int32_t, getInterfaceVersion, (), (override));
MOCK_METHOD(std::string, getInterfaceHash, (), (override));
MOCK_METHOD(IBinder*, onAsBinder, (), (override));
diff --git a/services/vibratorservice/test/VibratorManagerHalWrapperAidlTest.cpp b/services/vibratorservice/test/VibratorManagerHalWrapperAidlTest.cpp
index dd71a6a525..bcfd15d4b2 100644
--- a/services/vibratorservice/test/VibratorManagerHalWrapperAidlTest.cpp
+++ b/services/vibratorservice/test/VibratorManagerHalWrapperAidlTest.cpp
@@ -71,6 +71,8 @@ public:
MOCK_METHOD(Status, getSupportedAlwaysOnEffects, (std::vector<Effect> * ret), (override));
MOCK_METHOD(Status, alwaysOnEnable, (int32_t id, Effect e, EffectStrength s), (override));
MOCK_METHOD(Status, alwaysOnDisable, (int32_t id), (override));
+ MOCK_METHOD(Status, getQFactor, (float * ret), (override));
+ MOCK_METHOD(Status, getResonantFrequency, (float * ret), (override));
MOCK_METHOD(int32_t, getInterfaceVersion, (), (override));
MOCK_METHOD(std::string, getInterfaceHash, (), (override));
MOCK_METHOD(IBinder*, onAsBinder, (), (override));
diff --git a/services/vr/Android.bp b/services/vr/Android.bp
index 80df479e8d..980dcf4616 100644
--- a/services/vr/Android.bp
+++ b/services/vr/Android.bp
@@ -1,3 +1,13 @@
+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
+ // SPDX-license-identifier-MIT
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
subdirs = [
"*",
]
diff --git a/services/vr/bufferhubd/Android.bp b/services/vr/bufferhubd/Android.bp
index 7097e7a8cc..8523bb205f 100644
--- a/services/vr/bufferhubd/Android.bp
+++ b/services/vr/bufferhubd/Android.bp
@@ -12,6 +12,17 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+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
+ // SPDX-license-identifier-MIT
+ // SPDX-license-identifier-Unicode-DFS
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
sharedLibraries = [
"libbase",
"libcutils",
diff --git a/services/vr/hardware_composer/Android.bp b/services/vr/hardware_composer/Android.bp
index 372873149d..866007e188 100644
--- a/services/vr/hardware_composer/Android.bp
+++ b/services/vr/hardware_composer/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library_shared {
name: "libvr_hwc-hal",
diff --git a/services/vr/hardware_composer/aidl/Android.bp b/services/vr/hardware_composer/aidl/Android.bp
index a1d5392071..98afdec517 100644
--- a/services/vr/hardware_composer/aidl/Android.bp
+++ b/services/vr/hardware_composer/aidl/Android.bp
@@ -1,3 +1,14 @@
+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
+ // SPDX-license-identifier-MIT
+ // SPDX-license-identifier-Unicode-DFS
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library_static {
name: "libvr_hwc-binder",
srcs: [
diff --git a/services/vr/performanced/Android.bp b/services/vr/performanced/Android.bp
index 0ef8cc4762..5eca88b1f9 100644
--- a/services/vr/performanced/Android.bp
+++ b/services/vr/performanced/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+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-MIT
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_defaults {
name: "performanced_defaults",
static_libs: [
diff --git a/services/vr/virtual_touchpad/Android.bp b/services/vr/virtual_touchpad/Android.bp
index 9cf4905b68..f2ec5a42b1 100644
--- a/services/vr/virtual_touchpad/Android.bp
+++ b/services/vr/virtual_touchpad/Android.bp
@@ -2,6 +2,15 @@
// Touchpad implementation.
+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"],
+}
+
src = [
"EvdevInjector.cpp",
"VirtualTouchpadEvdev.cpp",
diff --git a/vulkan/Android.bp b/vulkan/Android.bp
index 4934970aaa..33599ea35b 100644
--- a/vulkan/Android.bp
+++ b/vulkan/Android.bp
@@ -14,6 +14,16 @@
// This module makes the Vulkan libhardware HAL headers available, for
// the loader and for HAL/driver implementations.
+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
+ // SPDX-license-identifier-MIT
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library_headers {
name: "hwvulkan_headers",
vendor_available: true,
diff --git a/vulkan/libvulkan/Android.bp b/vulkan/libvulkan/Android.bp
index 1d29bab355..67cd8754a3 100644
--- a/vulkan/libvulkan/Android.bp
+++ b/vulkan/libvulkan/Android.bp
@@ -13,6 +13,15 @@
// limitations under the License.
// Headers module is in external/vulkan-headers/Android.bp.
+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"],
+}
+
ndk_library {
name: "libvulkan",
symbol_file: "libvulkan.map.txt",
diff --git a/vulkan/nulldrv/Android.bp b/vulkan/nulldrv/Android.bp
index ba025046fa..0daad9c634 100644
--- a/vulkan/nulldrv/Android.bp
+++ b/vulkan/nulldrv/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library_shared {
// Real drivers would set this to vulkan.$(TARGET_BOARD_PLATFORM)
name: "vulkan.default",
diff --git a/vulkan/vkjson/Android.bp b/vulkan/vkjson/Android.bp
index 8528898f3d..fa0258bc06 100644
--- a/vulkan/vkjson/Android.bp
+++ b/vulkan/vkjson/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library_shared {
name: "libvkjson",
srcs: [