summaryrefslogtreecommitdiff
path: root/libs
diff options
context:
space:
mode:
Diffstat (limited to 'libs')
-rw-r--r--libs/arect/Android.bp1
-rw-r--r--libs/battery/MultiStateCounter.h16
-rw-r--r--libs/binder/Parcel.cpp5
-rw-r--r--libs/binder/tests/parcel_fuzzer/binder.cpp8
-rw-r--r--libs/bufferqueueconverter/Android.bp1
-rw-r--r--libs/bufferstreams/Android.bp2
-rw-r--r--libs/bufferstreams/aconfig/bufferstreams_flags.aconfig1
-rw-r--r--libs/bufferstreams/aidl/Android.bp43
-rw-r--r--libs/bufferstreams/aidl/android/graphics/bufferstreams/BufferAttachment.aidl32
-rw-r--r--libs/bufferstreams/aidl/android/graphics/bufferstreams/BufferCacheUpdate.aidl38
-rw-r--r--libs/bufferstreams/aidl/android/graphics/bufferstreams/Frame.aidl30
-rw-r--r--libs/bufferstreams/aidl/android/graphics/bufferstreams/IBufferOwner.aidl25
-rw-r--r--libs/bufferstreams/aidl/android/graphics/bufferstreams/IBufferSubscriber.aidl47
-rw-r--r--libs/bufferstreams/aidl/android/graphics/bufferstreams/IBufferSubscription.aidl26
-rw-r--r--libs/bufferstreams/examples/app/Android.bp5
-rw-r--r--libs/bufferstreams/examples/app/jni/Android.bp5
-rw-r--r--libs/bufferstreams/rust/Android.bp5
-rw-r--r--libs/bufferstreams/rust/src/buffers/buffer_owner.rs2
-rw-r--r--libs/bufferstreams/rust/src/lib.rs25
-rw-r--r--libs/bufferstreams/rust/src/publishers/buffer_pool_publisher.rs6
-rw-r--r--libs/ftl/Android.bp5
-rw-r--r--libs/ftl/expected_test.cpp77
-rw-r--r--libs/ftl/future_test.cpp38
-rw-r--r--libs/ftl/small_map_test.cpp55
-rw-r--r--libs/gralloc/types/Android.bp1
-rw-r--r--libs/gralloc/types/fuzzer/Android.bp1
-rw-r--r--libs/gralloc/types/tests/Android.bp6
-rw-r--r--libs/gui/Android.bp2
-rw-r--r--libs/gui/BufferQueueProducer.cpp28
-rw-r--r--libs/gui/Choreographer.cpp53
-rw-r--r--libs/gui/DisplayEventDispatcher.cpp5
-rw-r--r--libs/gui/FrameRateUtils.cpp1
-rw-r--r--libs/gui/LayerState.cpp13
-rw-r--r--libs/gui/Surface.cpp25
-rw-r--r--libs/gui/SurfaceComposerClient.cpp28
-rw-r--r--libs/gui/WindowInfo.cpp29
-rw-r--r--libs/gui/aidl/android/gui/ISurfaceComposer.aidl11
-rw-r--r--libs/gui/fuzzer/Android.bp146
-rw-r--r--libs/gui/fuzzer/README.md219
-rw-r--r--libs/gui/fuzzer/libgui_bufferQueue_fuzzer.cpp392
-rw-r--r--libs/gui/fuzzer/libgui_consumer_fuzzer.cpp82
-rw-r--r--libs/gui/fuzzer/libgui_displayEvent_fuzzer.cpp107
-rw-r--r--libs/gui/fuzzer/libgui_fuzzer_utils.h329
-rw-r--r--libs/gui/fuzzer/libgui_parcelable_fuzzer.cpp175
-rw-r--r--libs/gui/fuzzer/libgui_surfaceComposerClient_fuzzer.cpp328
-rw-r--r--libs/gui/fuzzer/libgui_surfaceComposer_fuzzer.cpp41
-rw-r--r--libs/gui/include/gui/Choreographer.h12
-rw-r--r--libs/gui/include/gui/DisplayEventDispatcher.h3
-rw-r--r--libs/gui/include/gui/DisplayEventReceiver.h12
-rw-r--r--libs/gui/include/gui/LayerState.h33
-rw-r--r--libs/gui/include/gui/SurfaceComposerClient.h4
-rw-r--r--libs/gui/include/gui/WindowInfo.h8
-rw-r--r--libs/gui/libgui_flags.aconfig1
-rw-r--r--libs/gui/sysprop/Android.bp1
-rw-r--r--libs/gui/tests/Android.bp2
-rw-r--r--libs/gui/tests/Choreographer_test.cpp88
-rw-r--r--libs/gui/tests/EndToEndNativeInputTest.cpp61
-rw-r--r--libs/gui/tests/FrameRateUtilsTest.cpp2
-rw-r--r--libs/gui/tests/Surface_test.cpp4
-rw-r--r--libs/input/AccelerationCurve.cpp63
-rw-r--r--libs/input/Android.bp37
-rw-r--r--libs/input/Input.cpp152
-rw-r--r--libs/input/InputDevice.cpp7
-rw-r--r--libs/input/InputEventLabels.cpp4
-rw-r--r--libs/input/InputTransport.cpp321
-rw-r--r--libs/input/KeyLayoutMap.cpp4
-rw-r--r--libs/input/MotionPredictorMetricsManager.cpp69
-rw-r--r--libs/input/VelocityControl.cpp210
-rw-r--r--libs/input/VirtualInputDevice.cpp124
-rw-r--r--libs/input/android/os/IInputFlinger.aidl5
-rw-r--r--libs/input/android/os/InputChannelCore.aidl (renamed from libs/input/android/InputChannel.aidl)14
-rw-r--r--libs/input/android/os/InputConfig.aidl7
-rw-r--r--libs/input/input_flags.aconfig44
-rw-r--r--libs/input/tests/Android.bp2
-rw-r--r--libs/input/tests/BlockingQueue_test.cpp154
-rw-r--r--libs/input/tests/InputChannel_test.cpp120
-rw-r--r--libs/input/tests/InputEvent_test.cpp170
-rw-r--r--libs/input/tests/InputPublisherAndConsumer_test.cpp404
-rw-r--r--libs/input/tests/MotionPredictorMetricsManager_test.cpp81
-rw-r--r--libs/input/tests/TestHelpers.h81
-rw-r--r--libs/input/tests/TouchResampling_test.cpp2
-rw-r--r--libs/input/tests/VelocityControl_test.cpp129
-rw-r--r--libs/nativedisplay/AChoreographer.cpp12
-rw-r--r--libs/nativedisplay/Android.bp7
-rw-r--r--libs/nativewindow/AHardwareBuffer.cpp91
-rw-r--r--libs/nativewindow/ANativeWindow.cpp75
-rw-r--r--libs/nativewindow/Android.bp6
-rw-r--r--libs/nativewindow/include-private/private/android/AHardwareBufferHelpers.h9
-rw-r--r--libs/nativewindow/include/android/data_space.h140
-rw-r--r--libs/nativewindow/include/android/hardware_buffer.h7
-rw-r--r--libs/nativewindow/include/system/window.h11
-rw-r--r--libs/nativewindow/include/vndk/hardware_buffer.h71
-rw-r--r--libs/nativewindow/libnativewindow.map.txt3
-rw-r--r--libs/nativewindow/rust/Android.bp1
-rw-r--r--libs/nativewindow/tests/AHardwareBufferTest.cpp86
-rw-r--r--libs/nativewindow/tests/Android.bp7
-rw-r--r--libs/nativewindow/tests/benchmark/Android.bp5
-rw-r--r--libs/renderengine/Android.bp10
-rw-r--r--libs/renderengine/RenderEngine.cpp36
-rw-r--r--libs/renderengine/benchmark/Android.bp3
-rw-r--r--libs/renderengine/benchmark/RenderEngineBench.cpp56
-rw-r--r--libs/renderengine/include/renderengine/RenderEngine.h49
-rw-r--r--libs/renderengine/skia/AutoBackendTexture.cpp6
-rw-r--r--libs/renderengine/skia/SkiaGLRenderEngine.cpp10
-rw-r--r--libs/renderengine/skia/SkiaRenderEngine.cpp22
-rw-r--r--libs/renderengine/skia/SkiaRenderEngine.h2
-rw-r--r--libs/renderengine/skia/SkiaVkRenderEngine.cpp598
-rw-r--r--libs/renderengine/skia/SkiaVkRenderEngine.h39
-rw-r--r--libs/renderengine/skia/VulkanInterface.cpp582
-rw-r--r--libs/renderengine/skia/VulkanInterface.h95
-rw-r--r--libs/renderengine/skia/filters/KawaseBlurFilter.cpp2
-rw-r--r--libs/renderengine/tests/Android.bp3
-rw-r--r--libs/renderengine/tests/RenderEngineTest.cpp256
-rw-r--r--libs/renderengine/tests/RenderEngineThreadedTest.cpp3
-rw-r--r--libs/renderengine/threaded/RenderEngineThreaded.cpp15
-rw-r--r--libs/renderengine/threaded/RenderEngineThreaded.h7
-rw-r--r--libs/sensor/Android.bp16
-rw-r--r--libs/sensor/SensorManager.cpp92
-rw-r--r--libs/sensor/include/sensor/SensorManager.h1
-rw-r--r--libs/sensor/libsensor_flags.aconfig9
-rw-r--r--libs/sensorprivacy/SensorPrivacyManager.cpp34
-rw-r--r--libs/sensorprivacy/aidl/android/hardware/ISensorPrivacyListener.aidl1
-rw-r--r--libs/sensorprivacy/aidl/android/hardware/ISensorPrivacyManager.aidl11
-rw-r--r--libs/sensorprivacy/include/sensorprivacy/SensorPrivacyManager.h15
-rw-r--r--libs/shaders/Android.bp1
-rw-r--r--libs/shaders/tests/Android.bp1
-rw-r--r--libs/tonemap/Android.bp1
-rw-r--r--libs/tonemap/tests/Android.bp1
-rw-r--r--libs/tracing_perfetto/.clang-format12
-rw-r--r--libs/tracing_perfetto/Android.bp49
-rw-r--r--libs/tracing_perfetto/OWNERS2
-rw-r--r--libs/tracing_perfetto/include/trace_categories.h65
-rw-r--r--libs/tracing_perfetto/include/trace_result.h30
-rw-r--r--libs/tracing_perfetto/include/tracing_perfetto.h53
-rw-r--r--libs/tracing_perfetto/tests/Android.bp45
-rw-r--r--libs/tracing_perfetto/tests/tracing_perfetto_test.cpp111
-rw-r--r--libs/tracing_perfetto/tests/utils.cpp219
-rw-r--r--libs/tracing_perfetto/tests/utils.h452
-rw-r--r--libs/tracing_perfetto/tracing_perfetto.cpp141
-rw-r--r--libs/tracing_perfetto/tracing_perfetto_internal.cpp229
-rw-r--r--libs/tracing_perfetto/tracing_perfetto_internal.h65
-rw-r--r--libs/ui/Android.bp1
-rw-r--r--libs/ui/Gralloc2.cpp6
-rw-r--r--libs/ui/Gralloc3.cpp4
-rw-r--r--libs/ui/Gralloc4.cpp37
-rw-r--r--libs/ui/Gralloc5.cpp124
-rw-r--r--libs/ui/GraphicBuffer.cpp126
-rw-r--r--libs/ui/GraphicBufferAllocator.cpp75
-rw-r--r--libs/ui/GraphicBufferMapper.cpp124
-rw-r--r--libs/ui/include/ui/Gralloc.h9
-rw-r--r--libs/ui/include/ui/Gralloc2.h5
-rw-r--r--libs/ui/include/ui/Gralloc3.h5
-rw-r--r--libs/ui/include/ui/Gralloc4.h5
-rw-r--r--libs/ui/include/ui/Gralloc5.h6
-rw-r--r--libs/ui/include/ui/GraphicBuffer.h5
-rw-r--r--libs/ui/include/ui/GraphicBufferAllocator.h30
-rw-r--r--libs/ui/include/ui/GraphicBufferMapper.h50
-rw-r--r--libs/ui/include/ui/Result.h121
-rw-r--r--libs/ui/tests/Android.bp12
-rw-r--r--libs/ui/tests/GraphicBufferAllocator_test.cpp2
-rw-r--r--libs/ui/tests/mock/MockGrallocAllocator.h2
-rw-r--r--libs/ui/tools/Android.bp1
-rw-r--r--libs/vibrator/ExternalVibration.cpp48
-rw-r--r--libs/vibrator/ExternalVibrationUtils.cpp63
-rw-r--r--libs/vibrator/include/vibrator/ExternalVibration.h6
-rw-r--r--libs/vibrator/include/vibrator/ExternalVibrationUtils.h37
166 files changed, 6093 insertions, 3747 deletions
diff --git a/libs/arect/Android.bp b/libs/arect/Android.bp
index 1a9766d72e..319716ec81 100644
--- a/libs/arect/Android.bp
+++ b/libs/arect/Android.bp
@@ -14,6 +14,7 @@
package {
default_applicable_licenses: ["frameworks_native_libs_arect_license"],
+ default_team: "trendy_team_android_core_graphics_stack",
}
// Added automatically by a large-scale-change
diff --git a/libs/battery/MultiStateCounter.h b/libs/battery/MultiStateCounter.h
index ce9cd1cebe..7da8d51ccd 100644
--- a/libs/battery/MultiStateCounter.h
+++ b/libs/battery/MultiStateCounter.h
@@ -31,6 +31,8 @@
namespace android {
namespace battery {
+#define REPORTED_INVALID_TIMESTAMP_DELTA_MS 60000
+
typedef uint16_t state_t;
template <class T>
@@ -171,8 +173,12 @@ void MultiStateCounter<T>::setState(state_t state, time_t timestamp) {
if (timestamp >= lastStateChangeTimestamp) {
states[currentState].timeInStateSinceUpdate += timestamp - lastStateChangeTimestamp;
} else {
- ALOGE("setState is called with an earlier timestamp: %lu, previous timestamp: %lu\n",
- (unsigned long)timestamp, (unsigned long)lastStateChangeTimestamp);
+ if (timestamp < lastStateChangeTimestamp - REPORTED_INVALID_TIMESTAMP_DELTA_MS) {
+ ALOGE("setState is called with an earlier timestamp: %lu, "
+ "previous timestamp: %lu\n",
+ (unsigned long)timestamp, (unsigned long)lastStateChangeTimestamp);
+ }
+
// The accumulated durations have become unreliable. For example, if the timestamp
// sequence was 1000, 2000, 1000, 3000, if we accumulated the positive deltas,
// we would get 4000, which is greater than (last - first). This could lead to
@@ -232,8 +238,10 @@ const T& MultiStateCounter<T>::updateValue(const T& value, time_t timestamp) {
}
}
} else if (timestamp < lastUpdateTimestamp) {
- ALOGE("updateValue is called with an earlier timestamp: %lu, previous: %lu\n",
- (unsigned long)timestamp, (unsigned long)lastUpdateTimestamp);
+ if (timestamp < lastUpdateTimestamp - REPORTED_INVALID_TIMESTAMP_DELTA_MS) {
+ ALOGE("updateValue is called with an earlier timestamp: %lu, previous: %lu\n",
+ (unsigned long)timestamp, (unsigned long)lastUpdateTimestamp);
+ }
for (int i = 0; i < stateCount; i++) {
states[i].timeInStateSinceUpdate = 0;
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 2dd310e9ca..1ffdad50e3 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -2976,14 +2976,15 @@ status_t Parcel::restartWrite(size_t desired)
return continueWrite(desired);
}
+ releaseObjects();
+
uint8_t* data = reallocZeroFree(mData, mDataCapacity, desired, mDeallocZero);
if (!data && desired > mDataCapacity) {
+ LOG_ALWAYS_FATAL("out of memory");
mError = NO_MEMORY;
return NO_MEMORY;
}
- releaseObjects();
-
if (data || desired == 0) {
LOG_ALLOC("Parcel %p: restart from %zu to %zu capacity", this, mDataCapacity, desired);
if (mDataCapacity > desired) {
diff --git a/libs/binder/tests/parcel_fuzzer/binder.cpp b/libs/binder/tests/parcel_fuzzer/binder.cpp
index 5c280f4b2c..e378b864f7 100644
--- a/libs/binder/tests/parcel_fuzzer/binder.cpp
+++ b/libs/binder/tests/parcel_fuzzer/binder.cpp
@@ -115,6 +115,14 @@ std::vector<ParcelRead<::android::Parcel>> BINDER_PARCEL_READ_FUNCTIONS {
p.setDataPosition(pos);
FUZZ_LOG() << "setDataPosition done";
},
+ [] (const ::android::Parcel& p, FuzzedDataProvider& provider) {
+ size_t len = provider.ConsumeIntegralInRange<size_t>(0, 1024);
+ std::vector<uint8_t> bytes = provider.ConsumeBytes<uint8_t>(len);
+ FUZZ_LOG() << "about to setData: " <<(bytes.data() ? HexString(bytes.data(), bytes.size()) : "null");
+ // TODO: allow all read and write operations
+ (*const_cast<::android::Parcel*>(&p)).setData(bytes.data(), bytes.size());
+ FUZZ_LOG() << "setData done";
+ },
PARCEL_READ_NO_STATUS(size_t, allowFds),
PARCEL_READ_NO_STATUS(size_t, hasFileDescriptors),
PARCEL_READ_NO_STATUS(std::vector<android::sp<android::IBinder>>, debugReadAllStrongBinders),
diff --git a/libs/bufferqueueconverter/Android.bp b/libs/bufferqueueconverter/Android.bp
index 3fe71cefce..3c8c41fdc8 100644
--- a/libs/bufferqueueconverter/Android.bp
+++ b/libs/bufferqueueconverter/Android.bp
@@ -5,6 +5,7 @@ package {
// to get the below license kinds:
// SPDX-license-identifier-Apache-2.0
default_applicable_licenses: ["frameworks_native_license"],
+ default_team: "trendy_team_android_core_graphics_stack",
}
cc_library_headers {
diff --git a/libs/bufferstreams/Android.bp b/libs/bufferstreams/Android.bp
index 365fc457d1..03ab31e318 100644
--- a/libs/bufferstreams/Android.bp
+++ b/libs/bufferstreams/Android.bp
@@ -14,11 +14,13 @@
package {
default_applicable_licenses: ["frameworks_native_license"],
+ default_team: "trendy_team_android_core_graphics_stack",
}
aconfig_declarations {
name: "bufferstreams_flags",
package: "com.android.graphics.bufferstreams.flags",
+ container: "system",
srcs: [
"aconfig/bufferstreams_flags.aconfig",
],
diff --git a/libs/bufferstreams/aconfig/bufferstreams_flags.aconfig b/libs/bufferstreams/aconfig/bufferstreams_flags.aconfig
index e258725e3d..d0f7812d21 100644
--- a/libs/bufferstreams/aconfig/bufferstreams_flags.aconfig
+++ b/libs/bufferstreams/aconfig/bufferstreams_flags.aconfig
@@ -1,4 +1,5 @@
package: "com.android.graphics.bufferstreams.flags"
+container: "system"
flag {
name: "bufferstreams_steel_thread"
diff --git a/libs/bufferstreams/aidl/Android.bp b/libs/bufferstreams/aidl/Android.bp
new file mode 100644
index 0000000000..3f1fa4e532
--- /dev/null
+++ b/libs/bufferstreams/aidl/Android.bp
@@ -0,0 +1,43 @@
+// Copyright (C) 2024 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.
+
+aidl_interface {
+ name: "android.graphics.bufferstreams",
+ unstable: true,
+ flags: ["-Werror"],
+ srcs: ["android/graphics/bufferstreams/*.aidl"],
+ headers: [
+ "HardwareBuffer_aidl",
+ ],
+ imports: [
+ "android.hardware.common-V2",
+ ],
+ backend: {
+ cpp: {
+ enabled: false,
+ },
+ java: {
+ enabled: false,
+ },
+ ndk: {
+ enabled: false,
+ },
+ rust: {
+ enabled: true,
+ additional_rustlibs: [
+ "libnativewindow_rs",
+ ],
+ },
+ },
+}
diff --git a/libs/bufferstreams/aidl/android/graphics/bufferstreams/BufferAttachment.aidl b/libs/bufferstreams/aidl/android/graphics/bufferstreams/BufferAttachment.aidl
new file mode 100644
index 0000000000..5c905b1d17
--- /dev/null
+++ b/libs/bufferstreams/aidl/android/graphics/bufferstreams/BufferAttachment.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2024 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.graphics.bufferstreams;
+
+import android.graphics.bufferstreams.IBufferOwner;
+import android.hardware.HardwareBuffer;
+
+// Single mapping between a buffer reference and heavy-weight data (like the
+// buffer itself) and data that is stable between frames.
+parcelable BufferAttachment {
+ // The HardwareBuffer itself.
+ //
+ // This field is @nullable for codegen, since HardwareBuffer doesn't implement Default in Rust.
+ // In practice, it should never be null.
+ @nullable HardwareBuffer buffer;
+ // The buffer owner to which this buffer should be returned.
+ IBufferOwner owner;
+}
diff --git a/libs/bufferstreams/aidl/android/graphics/bufferstreams/BufferCacheUpdate.aidl b/libs/bufferstreams/aidl/android/graphics/bufferstreams/BufferCacheUpdate.aidl
new file mode 100644
index 0000000000..75041196a8
--- /dev/null
+++ b/libs/bufferstreams/aidl/android/graphics/bufferstreams/BufferCacheUpdate.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2024 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.graphics.bufferstreams;
+
+import android.graphics.bufferstreams.BufferAttachment;
+
+// A event that changes the state downstream buffer caches. Clients are responsible for forwarding
+// these messages to their clients.
+union BufferCacheUpdate {
+ // Event requiring downstream caches to add new entries.
+ CacheBuffers cacheBuffers;
+ // Event requiring downstream caches to remove entries.
+ ForgetBuffers forgetBuffers;
+
+ parcelable CacheBuffers {
+ // Attachments to add.
+ List<BufferAttachment> attachments;
+ }
+
+ parcelable ForgetBuffers {
+ // References to remove.
+ long[] bufferIds;
+ }
+}
diff --git a/libs/bufferstreams/aidl/android/graphics/bufferstreams/Frame.aidl b/libs/bufferstreams/aidl/android/graphics/bufferstreams/Frame.aidl
new file mode 100644
index 0000000000..1e0ec3b5db
--- /dev/null
+++ b/libs/bufferstreams/aidl/android/graphics/bufferstreams/Frame.aidl
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2024 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.graphics.bufferstreams;
+
+import android.os.ParcelFileDescriptor;
+
+// A Frame represents a single buffer passing through the stream.
+parcelable Frame {
+ // The service must have provided an associated BufferAttachment and the client is required to
+ // maintain a cache between the two.
+ long bufferId;
+ // The expected present time of this frame, or -1 if immediate.
+ long presentTimeNs;
+ // The acquire fence of the buffer for this frame.
+ @nullable ParcelFileDescriptor fence;
+}
diff --git a/libs/bufferstreams/aidl/android/graphics/bufferstreams/IBufferOwner.aidl b/libs/bufferstreams/aidl/android/graphics/bufferstreams/IBufferOwner.aidl
new file mode 100644
index 0000000000..8b25a6298e
--- /dev/null
+++ b/libs/bufferstreams/aidl/android/graphics/bufferstreams/IBufferOwner.aidl
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2024 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.graphics.bufferstreams;
+
+import android.os.ParcelFileDescriptor;
+
+// Interface from a client back to the owner of a buffer.
+interface IBufferOwner {
+ // Called when the buffer is done being processed by the stream to return its owner.
+ oneway void onBufferReleased(in long bufferId, in @nullable ParcelFileDescriptor releaseFence);
+}
diff --git a/libs/bufferstreams/aidl/android/graphics/bufferstreams/IBufferSubscriber.aidl b/libs/bufferstreams/aidl/android/graphics/bufferstreams/IBufferSubscriber.aidl
new file mode 100644
index 0000000000..52e8216e60
--- /dev/null
+++ b/libs/bufferstreams/aidl/android/graphics/bufferstreams/IBufferSubscriber.aidl
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2024 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.graphics.bufferstreams;
+
+import android.graphics.bufferstreams.BufferCacheUpdate;
+import android.graphics.bufferstreams.IBufferSubscription;
+import android.graphics.bufferstreams.Frame;
+
+// Interface provided by clients to a service, mirroring the non-IPC interface.
+//
+// Clients are required to maintain a local cache of Buffer IDs to BufferAttachments.
+interface IBufferSubscriber {
+ // Provide a BufferSubscription object which the client can use to request frames.
+ oneway void onSubscribe(in IBufferSubscription subscription);
+
+ // Notifies the client to update its local caches.
+ oneway void onBufferCacheUpdate(in BufferCacheUpdate update);
+
+ // Notifies the client that a requested frame is available.
+ oneway void onNext(in Frame frame);
+
+ // Notifies the client that a fatal error has occurred. No subsequent on_next events will be
+ // sent by the service.
+ //
+ // Clients must empty their caches.
+ oneway void onError();
+
+ // Notifies the client that no further on_next events will be sent by the service in response
+ // to it cancelling the subscription.
+ //
+ // Clients must empty their caches.
+ oneway void onComplete();
+}
diff --git a/libs/bufferstreams/aidl/android/graphics/bufferstreams/IBufferSubscription.aidl b/libs/bufferstreams/aidl/android/graphics/bufferstreams/IBufferSubscription.aidl
new file mode 100644
index 0000000000..c37f4e68ea
--- /dev/null
+++ b/libs/bufferstreams/aidl/android/graphics/bufferstreams/IBufferSubscription.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2024 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.graphics.bufferstreams;
+
+// Interface provided to a IBufferSubscriber to request frames or gracefully cancel their
+// subscription.
+interface IBufferSubscription {
+ // Request n more frames.
+ oneway void request(long n);
+ // Cancel the subscription. Requested frames may continue to arrive.
+ oneway void cancel();
+}
diff --git a/libs/bufferstreams/examples/app/Android.bp b/libs/bufferstreams/examples/app/Android.bp
index bb573c596c..5b3ec30bd5 100644
--- a/libs/bufferstreams/examples/app/Android.bp
+++ b/libs/bufferstreams/examples/app/Android.bp
@@ -12,6 +12,11 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ default_applicable_licenses: ["frameworks_native_license"],
+ default_team: "trendy_team_android_core_graphics_stack",
+}
+
android_app {
name: "BufferStreamsDemoApp",
srcs: ["java/**/*.kt"],
diff --git a/libs/bufferstreams/examples/app/jni/Android.bp b/libs/bufferstreams/examples/app/jni/Android.bp
index 67910a1c4d..003f4ed2ad 100644
--- a/libs/bufferstreams/examples/app/jni/Android.bp
+++ b/libs/bufferstreams/examples/app/jni/Android.bp
@@ -12,6 +12,11 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ default_applicable_licenses: ["frameworks_native_license"],
+ default_team: "trendy_team_android_core_graphics_stack",
+}
+
cc_library_shared {
name: "libbufferstreamdemoapp",
cflags: [
diff --git a/libs/bufferstreams/rust/Android.bp b/libs/bufferstreams/rust/Android.bp
index 7fcb222085..34feb5d2a5 100644
--- a/libs/bufferstreams/rust/Android.bp
+++ b/libs/bufferstreams/rust/Android.bp
@@ -12,6 +12,11 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ default_applicable_licenses: ["frameworks_native_license"],
+ default_team: "trendy_team_android_core_graphics_stack",
+}
+
rust_defaults {
name: "libbufferstreams_defaults",
srcs: ["src/lib.rs"],
diff --git a/libs/bufferstreams/rust/src/buffers/buffer_owner.rs b/libs/bufferstreams/rust/src/buffers/buffer_owner.rs
index a4abb9d3b7..155a8bf238 100644
--- a/libs/bufferstreams/rust/src/buffers/buffer_owner.rs
+++ b/libs/bufferstreams/rust/src/buffers/buffer_owner.rs
@@ -16,7 +16,7 @@ use super::Buffer;
/// Trait that represents an owner of a buffer that might need to handle events such as a buffer
/// being dropped.
-pub trait BufferOwner {
+pub trait BufferOwner: Send + Sync {
/// Called when a buffer is dropped.
fn on_return(&self, buffer: &Buffer);
}
diff --git a/libs/bufferstreams/rust/src/lib.rs b/libs/bufferstreams/rust/src/lib.rs
index be1525d41f..17d4d8767f 100644
--- a/libs/bufferstreams/rust/src/lib.rs
+++ b/libs/bufferstreams/rust/src/lib.rs
@@ -23,8 +23,6 @@ pub mod subscriptions;
use buffers::Buffer;
pub use stream_config::*;
-use std::time::Instant;
-
/// This function will print Hello World.
#[no_mangle]
pub extern "C" fn hello() -> bool {
@@ -106,7 +104,8 @@ pub trait BufferSubscriber {
/// BufferSubscriptions serve as the bridge between BufferPublishers and
/// BufferSubscribers. BufferSubscribers receive a BufferSubscription when they
/// subscribe to a BufferPublisher via on_subscribe.
-/// This object is to be used by the BufferSubscriber to cancel its subscription
+///
+/// This object is used by the BufferSubscriber to cancel its subscription
/// or request more buffers.
///
/// BufferSubcriptions are required to adhere to the following, based on the
@@ -147,7 +146,7 @@ pub trait BufferSubscriber {
/// no other Subscription exists at this point.
/// * Calling Subscription.cancel MUST return normally.
/// * Calling Subscription.request MUST return normally.
-pub trait BufferSubscription {
+pub trait BufferSubscription: Send + Sync + 'static {
/// request
fn request(&self, n: u64);
/// cancel
@@ -161,8 +160,8 @@ pub type BufferError = anyhow::Error;
pub struct Frame {
/// A buffer to be used this frame.
pub buffer: Buffer,
- /// The time at which the buffer was dispatched.
- pub present_time: Instant,
+ /// The time at which this buffer is expected to be displayed.
+ pub present_time: i64,
/// A fence used for reading/writing safely.
pub fence: i32,
}
@@ -175,14 +174,12 @@ mod test {
use anyhow::anyhow;
use buffers::Buffer;
use nativewindow::{AHardwareBuffer_Format, AHardwareBuffer_UsageFlags};
- use std::borrow::BorrowMut;
- use std::error::Error;
- use std::ops::Add;
- use std::sync::Arc;
- use std::time::Duration;
+ use std::{borrow::BorrowMut, error::Error, ops::Add, sync::Arc};
- use crate::publishers::testing::*;
- use crate::subscribers::{testing::*, SharedSubscriber};
+ use crate::{
+ publishers::testing::*,
+ subscribers::{testing::*, SharedSubscriber},
+ };
const STREAM_CONFIG: StreamConfig = StreamConfig {
width: 1,
@@ -200,7 +197,7 @@ mod test {
.create_hardware_buffer()
.expect("Unable to create hardware buffer for test"),
),
- present_time: Instant::now() + Duration::from_secs(1),
+ present_time: 1,
fence: 0,
}
}
diff --git a/libs/bufferstreams/rust/src/publishers/buffer_pool_publisher.rs b/libs/bufferstreams/rust/src/publishers/buffer_pool_publisher.rs
index 846105dacd..73a15be897 100644
--- a/libs/bufferstreams/rust/src/publishers/buffer_pool_publisher.rs
+++ b/libs/bufferstreams/rust/src/publishers/buffer_pool_publisher.rs
@@ -14,8 +14,6 @@
//!
-use std::time::Instant;
-
use crate::{
buffers::BufferPool, subscriptions::SharedBufferSubscription, BufferPublisher,
BufferSubscriber, Frame, StreamConfig,
@@ -43,7 +41,7 @@ impl BufferPoolPublisher {
/// If the [SharedBufferSubscription] is ready for a [Frame], a buffer will be requested from
/// [BufferPool] and sent over to the [BufferSubscriber].
- pub fn send_next_frame(&mut self, present_time: Instant) -> bool {
+ pub fn send_next_frame(&mut self, present_time: i64) -> bool {
if let Some(subscriber) = self.subscriber.as_mut() {
if self.subscription.take_request() {
if let Some(buffer) = self.buffer_pool.next_buffer() {
@@ -103,7 +101,7 @@ mod test {
subscriber.map_inner(|s| s.request(1));
- assert!(buffer_pool_publisher.send_next_frame(Instant::now()));
+ assert!(buffer_pool_publisher.send_next_frame(1));
let events = subscriber.map_inner_mut(|s| s.take_events());
assert!(matches!(events.last().unwrap(), TestingSubscriberEvent::Next(_)));
diff --git a/libs/ftl/Android.bp b/libs/ftl/Android.bp
index 918680d6a7..32b2b68b4d 100644
--- a/libs/ftl/Android.bp
+++ b/libs/ftl/Android.bp
@@ -5,16 +5,21 @@ package {
// to get the below license kinds:
// SPDX-license-identifier-Apache-2.0
default_applicable_licenses: ["frameworks_native_license"],
+ default_team: "trendy_team_android_core_graphics_stack",
}
cc_test {
name: "ftl_test",
test_suites: ["device-tests"],
+ header_libs: [
+ "libbase_headers",
+ ],
srcs: [
"algorithm_test.cpp",
"cast_test.cpp",
"concat_test.cpp",
"enum_test.cpp",
+ "expected_test.cpp",
"fake_guard_test.cpp",
"flags_test.cpp",
"function_test.cpp",
diff --git a/libs/ftl/expected_test.cpp b/libs/ftl/expected_test.cpp
new file mode 100644
index 0000000000..8cb07e4696
--- /dev/null
+++ b/libs/ftl/expected_test.cpp
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2024 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 <ftl/expected.h>
+#include <gtest/gtest.h>
+
+#include <string>
+#include <system_error>
+
+namespace android::test {
+
+using IntExp = ftl::Expected<int, std::errc>;
+using StringExp = ftl::Expected<std::string, std::errc>;
+
+using namespace std::string_literals;
+
+TEST(Expected, Construct) {
+ // Default value.
+ EXPECT_TRUE(IntExp().has_value());
+ EXPECT_EQ(IntExp(), IntExp(0));
+
+ EXPECT_TRUE(StringExp().has_value());
+ EXPECT_EQ(StringExp(), StringExp(""));
+
+ // Value.
+ ASSERT_TRUE(IntExp(42).has_value());
+ EXPECT_EQ(42, IntExp(42).value());
+
+ ASSERT_TRUE(StringExp("test").has_value());
+ EXPECT_EQ("test"s, StringExp("test").value());
+
+ // Error.
+ const auto exp = StringExp(ftl::Unexpected(std::errc::invalid_argument));
+ ASSERT_FALSE(exp.has_value());
+ EXPECT_EQ(std::errc::invalid_argument, exp.error());
+}
+
+TEST(Expected, HasError) {
+ EXPECT_FALSE(IntExp(123).has_error([](auto) { return true; }));
+ EXPECT_FALSE(IntExp(ftl::Unexpected(std::errc::io_error)).has_error([](auto) { return false; }));
+
+ EXPECT_TRUE(StringExp(ftl::Unexpected(std::errc::permission_denied)).has_error([](auto e) {
+ return e == std::errc::permission_denied;
+ }));
+}
+
+TEST(Expected, ValueOpt) {
+ EXPECT_EQ(ftl::Optional(-1), IntExp(-1).value_opt());
+ EXPECT_EQ(std::nullopt, IntExp(ftl::Unexpected(std::errc::broken_pipe)).value_opt());
+
+ {
+ const StringExp exp("foo"s);
+ EXPECT_EQ(ftl::Optional('f'),
+ exp.value_opt().transform([](const auto& s) { return s.front(); }));
+ EXPECT_EQ("foo"s, exp.value());
+ }
+ {
+ StringExp exp("foobar"s);
+ EXPECT_EQ(ftl::Optional(6), std::move(exp).value_opt().transform(&std::string::length));
+ EXPECT_TRUE(exp.value().empty());
+ }
+}
+
+} // namespace android::test
diff --git a/libs/ftl/future_test.cpp b/libs/ftl/future_test.cpp
index 5a245b681c..1140639c87 100644
--- a/libs/ftl/future_test.cpp
+++ b/libs/ftl/future_test.cpp
@@ -102,4 +102,42 @@ TEST(Future, Chain) {
decrement_thread.join();
}
+TEST(Future, WaitFor) {
+ using namespace std::chrono_literals;
+ {
+ auto future = ftl::yield(42);
+ // Check that we can wait_for multiple times without invalidating the future
+ EXPECT_EQ(future.wait_for(1s), std::future_status::ready);
+ EXPECT_EQ(future.wait_for(1s), std::future_status::ready);
+ EXPECT_EQ(future.get(), 42);
+ }
+
+ {
+ std::condition_variable cv;
+ std::mutex m;
+ bool ready = false;
+
+ std::packaged_task<int32_t()> get_int([&] {
+ std::unique_lock lk(m);
+ cv.wait(lk, [&] { return ready; });
+ return 24;
+ });
+
+ auto get_future = ftl::Future(get_int.get_future());
+ std::thread get_thread(std::move(get_int));
+
+ EXPECT_EQ(get_future.wait_for(0s), std::future_status::timeout);
+ {
+ std::unique_lock lk(m);
+ ready = true;
+ }
+ cv.notify_one();
+
+ EXPECT_EQ(get_future.wait_for(1s), std::future_status::ready);
+ EXPECT_EQ(get_future.get(), 24);
+
+ get_thread.join();
+ }
+}
+
} // namespace android::test
diff --git a/libs/ftl/small_map_test.cpp b/libs/ftl/small_map_test.cpp
index 634877f672..e96d70d8ad 100644
--- a/libs/ftl/small_map_test.cpp
+++ b/libs/ftl/small_map_test.cpp
@@ -189,9 +189,20 @@ TEST(SmallMap, Get) {
}
}
-TEST(SmallMap, TryEmplace) {
- SmallMap<int, std::string, 3> map;
- using Pair = decltype(map)::value_type;
+template <typename Capacity>
+struct SmallMapTest : testing::Test {
+ static constexpr std::size_t kCapacity = Capacity{}();
+};
+
+template <std::size_t N>
+using Capacity = std::integral_constant<std::size_t, N>;
+
+using Capacities = testing::Types<Capacity<3>, Capacity<0>>;
+TYPED_TEST_SUITE(SmallMapTest, Capacities, );
+
+TYPED_TEST(SmallMapTest, TryEmplace) {
+ SmallMap<int, std::string, TestFixture::kCapacity> map;
+ using Pair = typename decltype(map)::value_type;
{
const auto [it, ok] = map.try_emplace(123, "abc");
@@ -207,14 +218,22 @@ TEST(SmallMap, TryEmplace) {
const auto [it, ok] = map.try_emplace(-1);
ASSERT_TRUE(ok);
EXPECT_EQ(*it, Pair(-1, std::string()));
- EXPECT_FALSE(map.dynamic());
+ if constexpr (map.static_capacity() > 0) {
+ EXPECT_FALSE(map.dynamic());
+ } else {
+ EXPECT_TRUE(map.dynamic());
+ }
}
{
// Insertion fails if mapping exists.
const auto [it, ok] = map.try_emplace(42, "!!!");
EXPECT_FALSE(ok);
EXPECT_EQ(*it, Pair(42, "???"));
- EXPECT_FALSE(map.dynamic());
+ if constexpr (map.static_capacity() > 0) {
+ EXPECT_FALSE(map.dynamic());
+ } else {
+ EXPECT_TRUE(map.dynamic());
+ }
}
{
// Insertion at capacity promotes the map.
@@ -240,9 +259,9 @@ struct String {
} // namespace
-TEST(SmallMap, TryReplace) {
- SmallMap<int, String, 3> map = ftl::init::map(1, "a")(2, "B");
- using Pair = decltype(map)::value_type;
+TYPED_TEST(SmallMapTest, TryReplace) {
+ SmallMap<int, String, TestFixture::kCapacity> map = ftl::init::map(1, "a")(2, "B");
+ using Pair = typename decltype(map)::value_type;
{
// Replacing fails unless mapping exists.
@@ -260,7 +279,12 @@ TEST(SmallMap, TryReplace) {
EXPECT_EQ(*it, Pair(2, "b"));
}
- EXPECT_FALSE(map.dynamic());
+ if constexpr (map.static_capacity() > 0) {
+ EXPECT_FALSE(map.dynamic());
+ } else {
+ EXPECT_TRUE(map.dynamic());
+ }
+
EXPECT_TRUE(map.try_emplace(3, "abc").second);
EXPECT_TRUE(map.try_emplace(4, "d").second);
EXPECT_TRUE(map.dynamic());
@@ -284,9 +308,9 @@ TEST(SmallMap, TryReplace) {
EXPECT_EQ(map, SmallMap(ftl::init::map(4, "d"s)(3, "c"s)(2, "b"s)(1, "a"s)));
}
-TEST(SmallMap, EmplaceOrReplace) {
- SmallMap<int, String, 3> map = ftl::init::map(1, "a")(2, "B");
- using Pair = decltype(map)::value_type;
+TYPED_TEST(SmallMapTest, EmplaceOrReplace) {
+ SmallMap<int, String, TestFixture::kCapacity> map = ftl::init::map(1, "a")(2, "B");
+ using Pair = typename decltype(map)::value_type;
{
// New mapping is emplaced.
@@ -305,7 +329,12 @@ TEST(SmallMap, EmplaceOrReplace) {
EXPECT_EQ(*it, Pair(2, "b"));
}
- EXPECT_FALSE(map.dynamic());
+ if constexpr (map.static_capacity() > 0) {
+ EXPECT_FALSE(map.dynamic());
+ } else {
+ EXPECT_TRUE(map.dynamic());
+ }
+
EXPECT_FALSE(map.emplace_or_replace(3, "abc").second); // Replace.
EXPECT_TRUE(map.emplace_or_replace(4, "d").second); // Emplace.
EXPECT_TRUE(map.dynamic());
diff --git a/libs/gralloc/types/Android.bp b/libs/gralloc/types/Android.bp
index aab1276b47..f300da57d8 100644
--- a/libs/gralloc/types/Android.bp
+++ b/libs/gralloc/types/Android.bp
@@ -19,6 +19,7 @@ package {
// to get the below license kinds:
// SPDX-license-identifier-Apache-2.0
default_applicable_licenses: ["frameworks_native_license"],
+ default_team: "trendy_team_android_core_graphics_stack",
}
cc_library {
diff --git a/libs/gralloc/types/fuzzer/Android.bp b/libs/gralloc/types/fuzzer/Android.bp
index 3c3b6af670..833718213a 100644
--- a/libs/gralloc/types/fuzzer/Android.bp
+++ b/libs/gralloc/types/fuzzer/Android.bp
@@ -5,6 +5,7 @@ package {
// to get the below license kinds:
// SPDX-license-identifier-Apache-2.0
default_applicable_licenses: ["frameworks_native_license"],
+ default_team: "trendy_team_android_core_graphics_stack",
}
cc_fuzz {
diff --git a/libs/gralloc/types/tests/Android.bp b/libs/gralloc/types/tests/Android.bp
index 66eb0aa2fe..b796c03d6a 100644
--- a/libs/gralloc/types/tests/Android.bp
+++ b/libs/gralloc/types/tests/Android.bp
@@ -21,6 +21,7 @@ package {
// to get the below license kinds:
// SPDX-license-identifier-Apache-2.0
default_applicable_licenses: ["frameworks_native_license"],
+ default_team: "trendy_team_android_core_graphics_stack",
}
cc_test {
@@ -30,5 +31,8 @@ cc_test {
"libhidlbase",
],
srcs: ["Gralloc4_test.cpp"],
- cflags: ["-Wall", "-Werror"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
}
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index eb4d3df21d..70cb36bad3 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -18,11 +18,13 @@ package {
// to get the below license kinds:
// SPDX-license-identifier-Apache-2.0
default_applicable_licenses: ["frameworks_native_license"],
+ default_team: "trendy_team_android_core_graphics_stack",
}
aconfig_declarations {
name: "libgui_flags",
package: "com.android.graphics.libgui.flags",
+ container: "system",
srcs: ["libgui_flags.aconfig"],
}
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index 19693e37cf..fb69fda32d 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -887,6 +887,9 @@ status_t BufferQueueProducer::queueBuffer(int slot,
int callbackTicket = 0;
uint64_t currentFrameNumber = 0;
BufferItem item;
+ int connectedApi;
+ sp<Fence> lastQueuedFence;
+
{ // Autolock scope
std::lock_guard<std::mutex> lock(mCore->mMutex);
@@ -1056,6 +1059,13 @@ status_t BufferQueueProducer::queueBuffer(int slot,
callbackTicket = mNextCallbackTicket++;
VALIDATE_CONSISTENCY();
+
+ connectedApi = mCore->mConnectedApi;
+ lastQueuedFence = std::move(mLastQueueBufferFence);
+
+ mLastQueueBufferFence = std::move(acquireFence);
+ mLastQueuedCrop = item.mCrop;
+ mLastQueuedTransform = item.mTransform;
} // Autolock scope
// It is okay not to clear the GraphicBuffer when the consumer is SurfaceFlinger because
@@ -1079,9 +1089,6 @@ status_t BufferQueueProducer::queueBuffer(int slot,
// Call back without the main BufferQueue lock held, but with the callback
// lock held so we can ensure that callbacks occur in order
- int connectedApi;
- sp<Fence> lastQueuedFence;
-
{ // scope for the lock
std::unique_lock<std::mutex> lock(mCallbackMutex);
while (callbackTicket != mCurrentCallbackTicket) {
@@ -1094,13 +1101,6 @@ status_t BufferQueueProducer::queueBuffer(int slot,
frameReplacedListener->onFrameReplaced(item);
}
- connectedApi = mCore->mConnectedApi;
- lastQueuedFence = std::move(mLastQueueBufferFence);
-
- mLastQueueBufferFence = std::move(acquireFence);
- mLastQueuedCrop = item.mCrop;
- mLastQueuedTransform = item.mTransform;
-
++mCurrentCallbackTicket;
mCallbackCondition.notify_all();
}
@@ -1653,9 +1653,10 @@ status_t BufferQueueProducer::setLegacyBufferDrop(bool drop) {
status_t BufferQueueProducer::getLastQueuedBuffer(sp<GraphicBuffer>* outBuffer,
sp<Fence>* outFence, float outTransformMatrix[16]) {
ATRACE_CALL();
- BQ_LOGV("getLastQueuedBuffer");
std::lock_guard<std::mutex> lock(mCore->mMutex);
+ BQ_LOGV("getLastQueuedBuffer, slot=%d", mCore->mLastQueuedSlot);
+
if (mCore->mLastQueuedSlot == BufferItem::INVALID_BUFFER_SLOT) {
*outBuffer = nullptr;
*outFence = Fence::NO_FENCE;
@@ -1679,10 +1680,11 @@ status_t BufferQueueProducer::getLastQueuedBuffer(sp<GraphicBuffer>* outBuffer,
status_t BufferQueueProducer::getLastQueuedBuffer(sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence,
Rect* outRect, uint32_t* outTransform) {
ATRACE_CALL();
- BQ_LOGV("getLastQueuedBuffer");
std::lock_guard<std::mutex> lock(mCore->mMutex);
- if (mCore->mLastQueuedSlot == BufferItem::INVALID_BUFFER_SLOT) {
+ BQ_LOGV("getLastQueuedBuffer, slot=%d", mCore->mLastQueuedSlot);
+ if (mCore->mLastQueuedSlot == BufferItem::INVALID_BUFFER_SLOT ||
+ mSlots[mCore->mLastQueuedSlot].mBufferState.isDequeued()) {
*outBuffer = nullptr;
*outFence = Fence::NO_FENCE;
return NO_ERROR;
diff --git a/libs/gui/Choreographer.cpp b/libs/gui/Choreographer.cpp
index 79c5fd1006..54290cd629 100644
--- a/libs/gui/Choreographer.cpp
+++ b/libs/gui/Choreographer.cpp
@@ -143,9 +143,9 @@ Choreographer::~Choreographer() {
void Choreographer::postFrameCallbackDelayed(AChoreographer_frameCallback cb,
AChoreographer_frameCallback64 cb64,
AChoreographer_vsyncCallback vsyncCallback, void* data,
- nsecs_t delay) {
+ nsecs_t delay, CallbackType callbackType) {
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
- FrameCallback callback{cb, cb64, vsyncCallback, data, now + delay};
+ FrameCallback callback{cb, cb64, vsyncCallback, data, now + delay, callbackType};
{
std::lock_guard<std::mutex> _l{mLock};
mFrameCallbacks.push(callback);
@@ -285,18 +285,8 @@ void Choreographer::handleRefreshRateUpdates() {
}
}
-void Choreographer::dispatchVsync(nsecs_t timestamp, PhysicalDisplayId, uint32_t,
- VsyncEventData vsyncEventData) {
- std::vector<FrameCallback> callbacks{};
- {
- std::lock_guard<std::mutex> _l{mLock};
- nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
- while (!mFrameCallbacks.empty() && mFrameCallbacks.top().dueTime < now) {
- callbacks.push_back(mFrameCallbacks.top());
- mFrameCallbacks.pop();
- }
- }
- mLastVsyncEventData = vsyncEventData;
+void Choreographer::dispatchCallbacks(const std::vector<FrameCallback>& callbacks,
+ VsyncEventData vsyncEventData, nsecs_t timestamp) {
for (const auto& cb : callbacks) {
if (cb.vsyncCallback != nullptr) {
ATRACE_FORMAT("AChoreographer_vsyncCallback %" PRId64,
@@ -319,6 +309,34 @@ void Choreographer::dispatchVsync(nsecs_t timestamp, PhysicalDisplayId, uint32_t
}
}
+void Choreographer::dispatchVsync(nsecs_t timestamp, PhysicalDisplayId, uint32_t,
+ VsyncEventData vsyncEventData) {
+ std::vector<FrameCallback> animationCallbacks{};
+ std::vector<FrameCallback> inputCallbacks{};
+ {
+ std::lock_guard<std::mutex> _l{mLock};
+ nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
+ while (!mFrameCallbacks.empty() && mFrameCallbacks.top().dueTime < now) {
+ if (mFrameCallbacks.top().callbackType == CALLBACK_INPUT) {
+ inputCallbacks.push_back(mFrameCallbacks.top());
+ } else {
+ animationCallbacks.push_back(mFrameCallbacks.top());
+ }
+ mFrameCallbacks.pop();
+ }
+ }
+ mLastVsyncEventData = vsyncEventData;
+ // Callbacks with type CALLBACK_INPUT should always run first
+ {
+ ATRACE_FORMAT("CALLBACK_INPUT");
+ dispatchCallbacks(inputCallbacks, vsyncEventData, timestamp);
+ }
+ {
+ ATRACE_FORMAT("CALLBACK_ANIMATION");
+ dispatchCallbacks(animationCallbacks, vsyncEventData, timestamp);
+ }
+}
+
void Choreographer::dispatchHotplug(nsecs_t, PhysicalDisplayId displayId, bool connected) {
ALOGV("choreographer %p ~ received hotplug event (displayId=%s, connected=%s), ignoring.", this,
to_string(displayId).c_str(), toString(connected));
@@ -344,6 +362,13 @@ void Choreographer::dispatchNullEvent(nsecs_t, PhysicalDisplayId) {
handleRefreshRateUpdates();
}
+void Choreographer::dispatchHdcpLevelsChanged(PhysicalDisplayId displayId, int32_t connectedLevel,
+ int32_t maxLevel) {
+ ALOGV("choreographer %p ~ received hdcp levels change event (displayId=%s, connectedLevel=%d, "
+ "maxLevel=%d), ignoring.",
+ this, to_string(displayId).c_str(), connectedLevel, maxLevel);
+}
+
void Choreographer::handleMessage(const Message& message) {
switch (message.what) {
case MSG_SCHEDULE_CALLBACKS:
diff --git a/libs/gui/DisplayEventDispatcher.cpp b/libs/gui/DisplayEventDispatcher.cpp
index 5dd058cf9f..f3de96d2cd 100644
--- a/libs/gui/DisplayEventDispatcher.cpp
+++ b/libs/gui/DisplayEventDispatcher.cpp
@@ -195,6 +195,11 @@ bool DisplayEventDispatcher::processPendingEvents(nsecs_t* outTimestamp,
dispatchFrameRateOverrides(ev.header.timestamp, ev.header.displayId,
std::move(mFrameRateOverrides));
break;
+ case DisplayEventReceiver::DISPLAY_EVENT_HDCP_LEVELS_CHANGE:
+ dispatchHdcpLevelsChanged(ev.header.displayId,
+ ev.hdcpLevelsChange.connectedLevel,
+ ev.hdcpLevelsChange.maxLevel);
+ break;
default:
ALOGW("dispatcher %p ~ ignoring unknown event type %#x", this, ev.header.type);
break;
diff --git a/libs/gui/FrameRateUtils.cpp b/libs/gui/FrameRateUtils.cpp
index 11524e2b51..01aa7ed43c 100644
--- a/libs/gui/FrameRateUtils.cpp
+++ b/libs/gui/FrameRateUtils.cpp
@@ -42,6 +42,7 @@ bool ValidateFrameRate(float frameRate, int8_t compatibility, int8_t changeFrame
if (compatibility != ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT &&
compatibility != ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE &&
+ compatibility != ANATIVEWINDOW_FRAME_RATE_GTE &&
(!privileged ||
(compatibility != ANATIVEWINDOW_FRAME_RATE_EXACT &&
compatibility != ANATIVEWINDOW_FRAME_RATE_NO_VOTE))) {
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 38fab9cdaa..1e0aacddab 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -199,7 +199,7 @@ status_t layer_state_t::write(Parcel& output) const
SAFE_PARCEL(output.writeParcelable, trustedPresentationListener);
SAFE_PARCEL(output.writeFloat, currentHdrSdrRatio);
SAFE_PARCEL(output.writeFloat, desiredHdrSdrRatio);
- SAFE_PARCEL(output.writeInt32, static_cast<int32_t>(cachingHint))
+ SAFE_PARCEL(output.writeInt32, static_cast<int32_t>(cachingHint));
return NO_ERROR;
}
@@ -484,6 +484,12 @@ void layer_state_t::sanitize(int32_t permissions) {
flags &= ~eLayerIsDisplayDecoration;
ALOGE("Stripped attempt to set LayerIsDisplayDecoration in sanitize");
}
+ if ((mask & eCanOccludePresentation) &&
+ !(permissions & Permission::ACCESS_SURFACE_FLINGER)) {
+ flags &= ~eCanOccludePresentation;
+ mask &= ~eCanOccludePresentation;
+ ALOGE("Stripped attempt to set eCanOccludePresentation in sanitize");
+ }
}
if (what & layer_state_t::eInputInfoChanged) {
@@ -605,6 +611,10 @@ void layer_state_t::merge(const layer_state_t& other) {
desiredHdrSdrRatio = other.desiredHdrSdrRatio;
currentHdrSdrRatio = other.currentHdrSdrRatio;
}
+ if (other.what & eDesiredHdrHeadroomChanged) {
+ what |= eDesiredHdrHeadroomChanged;
+ desiredHdrSdrRatio = other.desiredHdrSdrRatio;
+ }
if (other.what & eCachingHintChanged) {
what |= eCachingHintChanged;
cachingHint = other.cachingHint;
@@ -768,6 +778,7 @@ uint64_t layer_state_t::diff(const layer_state_t& other) const {
CHECK_DIFF(diff, eDataspaceChanged, other, dataspace);
CHECK_DIFF2(diff, eExtendedRangeBrightnessChanged, other, currentHdrSdrRatio,
desiredHdrSdrRatio);
+ CHECK_DIFF(diff, eDesiredHdrHeadroomChanged, other, desiredHdrSdrRatio);
CHECK_DIFF(diff, eCachingHintChanged, other, cachingHint);
CHECK_DIFF(diff, eHdrMetadataChanged, other, hdrMetadata);
if (other.what & eSurfaceDamageRegionChanged &&
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 07a0cfed63..086544e48a 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -342,12 +342,23 @@ status_t Surface::getFrameTimestamps(uint64_t frameNumber,
getFrameTimestamp(outRequestedPresentTime, events->requestedPresentTime);
getFrameTimestamp(outLatchTime, events->latchTime);
- getFrameTimestamp(outFirstRefreshStartTime, events->firstRefreshStartTime);
+
+ nsecs_t firstRefreshStartTime = NATIVE_WINDOW_TIMESTAMP_INVALID;
+ getFrameTimestamp(&firstRefreshStartTime, events->firstRefreshStartTime);
+ if (outFirstRefreshStartTime) {
+ *outFirstRefreshStartTime = firstRefreshStartTime;
+ }
+
getFrameTimestamp(outLastRefreshStartTime, events->lastRefreshStartTime);
getFrameTimestamp(outDequeueReadyTime, events->dequeueReadyTime);
- getFrameTimestampFence(outAcquireTime, events->acquireFence,
+ nsecs_t acquireTime = NATIVE_WINDOW_TIMESTAMP_INVALID;
+ getFrameTimestampFence(&acquireTime, events->acquireFence,
events->hasAcquireInfo());
+ if (outAcquireTime != nullptr) {
+ *outAcquireTime = acquireTime;
+ }
+
getFrameTimestampFence(outGpuCompositionDoneTime,
events->gpuCompositionDoneFence,
events->hasGpuCompositionDoneInfo());
@@ -356,6 +367,16 @@ status_t Surface::getFrameTimestamps(uint64_t frameNumber,
getFrameTimestampFence(outReleaseTime, events->releaseFence,
events->hasReleaseInfo());
+ // Fix up the GPU completion fence at this layer -- eglGetFrameTimestampsANDROID() expects
+ // that EGL_FIRST_COMPOSITION_GPU_FINISHED_TIME_ANDROID > EGL_RENDERING_COMPLETE_TIME_ANDROID.
+ // This is typically true, but SurfaceFlinger may opt to cache prior GPU composition results,
+ // which breaks that assumption, so zero out GPU composition time.
+ if (outGpuCompositionDoneTime != nullptr
+ && *outGpuCompositionDoneTime > 0 && (acquireTime > 0 || firstRefreshStartTime > 0)
+ && *outGpuCompositionDoneTime <= std::max(acquireTime, firstRefreshStartTime)) {
+ *outGpuCompositionDoneTime = 0;
+ }
+
return NO_ERROR;
}
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 8b6f2023dc..4f1356bebb 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -56,6 +56,7 @@
#include <android-base/thread_annotations.h>
#include <gui/LayerStatePermissions.h>
+#include <gui/ScreenCaptureResults.h>
#include <private/gui/ComposerService.h>
#include <private/gui/ComposerServiceAIDL.h>
@@ -1807,6 +1808,20 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setExten
return *this;
}
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setDesiredHdrHeadroom(
+ const sp<SurfaceControl>& sc, float desiredRatio) {
+ layer_state_t* s = getLayerState(sc);
+ if (!s) {
+ mStatus = BAD_INDEX;
+ return *this;
+ }
+ s->what |= layer_state_t::eDesiredHdrHeadroomChanged;
+ s->desiredHdrSdrRatio = desiredRatio;
+
+ registerSurfaceControlForCallback(sc);
+ return *this;
+}
+
SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setCachingHint(
const sp<SurfaceControl>& sc, gui::CachingHint cachingHint) {
layer_state_t* s = getLayerState(sc);
@@ -3117,7 +3132,6 @@ status_t SurfaceComposerClient::removeWindowInfosListener(
->removeWindowInfosListener(windowInfosListener,
ComposerServiceAIDL::getComposerService());
}
-
// ----------------------------------------------------------------------------
status_t ScreenshotClient::captureDisplay(const DisplayCaptureArgs& captureArgs,
@@ -3139,11 +3153,19 @@ status_t ScreenshotClient::captureDisplay(DisplayId displayId, const gui::Captur
}
status_t ScreenshotClient::captureLayers(const LayerCaptureArgs& captureArgs,
- const sp<IScreenCaptureListener>& captureListener) {
+ const sp<IScreenCaptureListener>& captureListener,
+ bool sync) {
sp<gui::ISurfaceComposer> s(ComposerServiceAIDL::getComposerService());
if (s == nullptr) return NO_INIT;
- binder::Status status = s->captureLayers(captureArgs, captureListener);
+ binder::Status status;
+ if (sync) {
+ gui::ScreenCaptureResults captureResults;
+ status = s->captureLayersSync(captureArgs, &captureResults);
+ captureListener->onScreenCaptureCompleted(captureResults);
+ } else {
+ status = s->captureLayers(captureArgs, captureListener);
+ }
return statusTFromBinderStatus(status);
}
diff --git a/libs/gui/WindowInfo.cpp b/libs/gui/WindowInfo.cpp
index ba1d196e9c..86bf0ee745 100644
--- a/libs/gui/WindowInfo.cpp
+++ b/libs/gui/WindowInfo.cpp
@@ -109,7 +109,8 @@ bool WindowInfo::operator==(const WindowInfo& info) const {
info.inputConfig == inputConfig && info.displayId == displayId &&
info.replaceTouchableRegionWithCrop == replaceTouchableRegionWithCrop &&
info.applicationInfo == applicationInfo && info.layoutParamsType == layoutParamsType &&
- info.layoutParamsFlags == layoutParamsFlags;
+ info.layoutParamsFlags == layoutParamsFlags &&
+ info.canOccludePresentation == canOccludePresentation;
}
status_t WindowInfo::writeToParcel(android::Parcel* parcel) const {
@@ -158,8 +159,9 @@ status_t WindowInfo::writeToParcel(android::Parcel* parcel) const {
parcel->write(touchableRegion) ?:
parcel->writeBool(replaceTouchableRegionWithCrop) ?:
parcel->writeStrongBinder(touchableRegionCropHandle.promote()) ?:
- parcel->writeStrongBinder(windowToken);
- parcel->writeStrongBinder(focusTransferTarget);
+ parcel->writeStrongBinder(windowToken) ?:
+ parcel->writeStrongBinder(focusTransferTarget) ?:
+ parcel->writeBool(canOccludePresentation);
// clang-format on
return status;
}
@@ -210,7 +212,8 @@ status_t WindowInfo::readFromParcel(const android::Parcel* parcel) {
parcel->readBool(&replaceTouchableRegionWithCrop) ?:
parcel->readNullableStrongBinder(&touchableRegionCropHandleSp) ?:
parcel->readNullableStrongBinder(&windowToken) ?:
- parcel->readNullableStrongBinder(&focusTransferTarget);
+ parcel->readNullableStrongBinder(&focusTransferTarget) ?:
+ parcel->readBool(&canOccludePresentation);
// clang-format on
@@ -258,10 +261,7 @@ void WindowInfoHandle::updateFrom(sp<WindowInfoHandle> handle) {
mInfo = handle->mInfo;
}
-std::ostream& operator<<(std::ostream& out, const WindowInfoHandle& window) {
- const WindowInfo& info = *window.getInfo();
- std::string transform;
- info.transform.dump(transform, "transform", " ");
+std::ostream& operator<<(std::ostream& out, const WindowInfo& info) {
out << "name=" << info.name << ", id=" << info.id << ", displayId=" << info.displayId
<< ", inputConfig=" << info.inputConfig.string() << ", alpha=" << info.alpha << ", frame=["
<< info.frame.left << "," << info.frame.top << "][" << info.frame.right << ","
@@ -272,8 +272,17 @@ std::ostream& operator<<(std::ostream& out, const WindowInfoHandle& window) {
<< ", ownerUid=" << info.ownerUid.toString() << ", dispatchingTimeout="
<< std::chrono::duration_cast<std::chrono::milliseconds>(info.dispatchingTimeout).count()
<< "ms, token=" << info.token.get()
- << ", touchOcclusionMode=" << ftl::enum_string(info.touchOcclusionMode) << "\n"
- << transform;
+ << ", touchOcclusionMode=" << ftl::enum_string(info.touchOcclusionMode);
+ if (info.canOccludePresentation) out << ", canOccludePresentation";
+ std::string transform;
+ info.transform.dump(transform, "transform", " ");
+ out << "\n" << transform;
+ return out;
+}
+
+std::ostream& operator<<(std::ostream& out, const WindowInfoHandle& window) {
+ const WindowInfo& info = *window.getInfo();
+ out << info;
return out;
}
diff --git a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl
index e3122bc300..51e01930d3 100644
--- a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl
+++ b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl
@@ -46,6 +46,7 @@ import android.gui.LayerCaptureArgs;
import android.gui.LayerDebugInfo;
import android.gui.OverlayProperties;
import android.gui.PullAtomData;
+import android.gui.ScreenCaptureResults;
import android.gui.ARect;
import android.gui.SchedulingPolicy;
import android.gui.StalledTransactionInfo;
@@ -245,6 +246,16 @@ interface ISurfaceComposer {
/**
* Capture a subtree of the layer hierarchy, potentially ignoring the root node.
* This requires READ_FRAME_BUFFER permission. This function will fail if there
+ * is a secure window on screen. This is a blocking call and will return the
+ * ScreenCaptureResults, including the captured buffer. Because this is blocking, the
+ * caller doesn't care about the fence and the binder thread in SurfaceFlinger will wait
+ * on the fence to fire before returning the results.
+ */
+ ScreenCaptureResults captureLayersSync(in LayerCaptureArgs args);
+
+ /**
+ * Capture a subtree of the layer hierarchy, potentially ignoring the root node.
+ * This requires READ_FRAME_BUFFER permission. This function will fail if there
* is a secure window on screen
*/
oneway void captureLayers(in LayerCaptureArgs args, IScreenCaptureListener listener);
diff --git a/libs/gui/fuzzer/Android.bp b/libs/gui/fuzzer/Android.bp
deleted file mode 100644
index cd738acde2..0000000000
--- a/libs/gui/fuzzer/Android.bp
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * 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 {
- // 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: "libgui_fuzzer_defaults",
- defaults: ["android.hardware.power-ndk_shared"],
- static_libs: [
- "android.hidl.token@1.0-utils",
- "libbinder_random_parcel",
- "libgui_aidl_static",
- "libgui_window_info_static",
- "libpdx",
- "libgmock",
- "libgui_mocks",
- "libgmock_ndk",
- "libgmock_main",
- "libgtest_ndk_c++",
- "libgmock_main_ndk",
- "librenderengine_mocks",
- "perfetto_trace_protos",
- "libcompositionengine_mocks",
- "perfetto_trace_protos",
- ],
- shared_libs: [
- "android.hardware.configstore@1.0",
- "android.hardware.configstore-utils",
- "android.hardware.graphics.bufferqueue@1.0",
- "android.hardware.graphics.bufferqueue@2.0",
- "android.hidl.token@1.0",
- "libSurfaceFlingerProp",
- "libgui",
- "libbase",
- "liblog",
- "libEGL",
- "libGLESv2",
- "libbinder",
- "libcutils",
- "libhidlbase",
- "libinput",
- "libui",
- "libutils",
- "libnativewindow",
- "libvndksupport",
- ],
- header_libs: [
- "libdvr_headers",
- "libui_fuzzableDataspaces_headers",
- ],
- fuzz_config: {
- cc: [
- "android-media-fuzzing-reports@google.com",
- ],
- componentid: 155276,
- hotlists: [
- "4593311",
- ],
- description: "The fuzzer targets the APIs of libgui library",
- vector: "local_no_privileges_required",
- service_privilege: "privileged",
- users: "multi_user",
- fuzzed_code_usage: "shipped",
- },
-}
-
-cc_fuzz {
- name: "libgui_surfaceComposer_fuzzer",
- srcs: [
- "libgui_surfaceComposer_fuzzer.cpp",
- ],
- defaults: [
- "libgui_fuzzer_defaults",
- "service_fuzzer_defaults",
- ],
-}
-
-cc_fuzz {
- name: "libgui_surfaceComposerClient_fuzzer",
- srcs: [
- "libgui_surfaceComposerClient_fuzzer.cpp",
- ],
- defaults: [
- "libgui_fuzzer_defaults",
- "service_fuzzer_defaults",
- ],
-}
-
-cc_fuzz {
- name: "libgui_parcelable_fuzzer",
- srcs: [
- "libgui_parcelable_fuzzer.cpp",
- ],
- defaults: [
- "libgui_fuzzer_defaults",
- ],
-}
-
-cc_fuzz {
- name: "libgui_bufferQueue_fuzzer",
- srcs: [
- "libgui_bufferQueue_fuzzer.cpp",
- ],
- defaults: [
- "libgui_fuzzer_defaults",
- ],
-}
-
-cc_fuzz {
- name: "libgui_consumer_fuzzer",
- srcs: [
- "libgui_consumer_fuzzer.cpp",
- ],
- defaults: [
- "libgui_fuzzer_defaults",
- ],
-}
-
-cc_fuzz {
- name: "libgui_displayEvent_fuzzer",
- srcs: [
- "libgui_displayEvent_fuzzer.cpp",
- ],
- defaults: [
- "libgui_fuzzer_defaults",
- ],
-}
diff --git a/libs/gui/fuzzer/README.md b/libs/gui/fuzzer/README.md
deleted file mode 100644
index 96e27c989f..0000000000
--- a/libs/gui/fuzzer/README.md
+++ /dev/null
@@ -1,219 +0,0 @@
-# Fuzzers for Libgui
-
-## Table of contents
-+ [libgui_surfaceComposer_fuzzer](#SurfaceComposer)
-+ [libgui_surfaceComposerClient_fuzzer](#SurfaceComposerClient)
-+ [libgui_parcelable_fuzzer](#Libgui_Parcelable)
-+ [libgui_bufferQueue_fuzzer](#BufferQueue)
-+ [libgui_consumer_fuzzer](#Libgui_Consumer)
-+ [libgui_displayEvent_fuzzer](#LibGui_DisplayEvent)
-
-# <a name="libgui_surfaceComposer_fuzzer"></a> Fuzzer for SurfaceComposer
-
-SurfaceComposer supports the following parameters:
-1. SurfaceWidth (parameter name:`width`)
-2. SurfaceHeight (parameter name:`height`)
-3. TransactionStateFlags (parameter name:`flags`)
-4. TransformHint (parameter name:`outTransformHint`)
-5. SurfacePixelFormat (parameter name:`format`)
-6. LayerId (parameter name:`outLayerId`)
-7. SurfaceComposerTags (parameter name:`surfaceTag`)
-8. PowerBoostID (parameter name:`boostId`)
-9. VsyncSource (parameter name:`vsyncSource`)
-10. EventRegistrationFlags (parameter name:`eventRegistration`)
-11. FrameRateCompatibility (parameter name:`frameRateCompatibility`)
-12. ChangeFrameRateStrategy (parameter name:`changeFrameRateStrategy`)
-13. HdrTypes (parameter name:`hdrTypes`)
-
-| Parameter| Valid Values| Configured Value|
-|------------- |-------------| ----- |
-|`surfaceTag` | 0.`BnSurfaceComposer::BOOT_FINISHED`, 1.`BnSurfaceComposer::CREATE_CONNECTION`, 2.`BnSurfaceComposer::GET_STATIC_DISPLAY_INFO`, 3.`BnSurfaceComposer::CREATE_DISPLAY_EVENT_CONNECTION`, 4.`BnSurfaceComposer::CREATE_DISPLAY`, 5.`BnSurfaceComposer::DESTROY_DISPLAY`, 6.`BnSurfaceComposer::GET_PHYSICAL_DISPLAY_TOKEN`, 7.`BnSurfaceComposer::SET_TRANSACTION_STATE`, 8.`BnSurfaceComposer::AUTHENTICATE_SURFACE`, 9.`BnSurfaceComposer::GET_SUPPORTED_FRAME_TIMESTAMPS`, 10.`BnSurfaceComposer::GET_DISPLAY_STATE`, 11.`BnSurfaceComposer::CAPTURE_DISPLAY`, 12.`BnSurfaceComposer::CAPTURE_LAYERS`, 13.`BnSurfaceComposer::CLEAR_ANIMATION_FRAME_STATS`, 14.`BnSurfaceComposer::GET_ANIMATION_FRAME_STATS`, 15.`BnSurfaceComposer::SET_POWER_MODE`, 16.`BnSurfaceComposer::GET_DISPLAY_STATS`, 17.`BnSurfaceComposer::SET_ACTIVE_COLOR_MODE`, 18.`BnSurfaceComposer::ENABLE_VSYNC_INJECTIONS`, 19.`BnSurfaceComposer::INJECT_VSYNC`, 20.`BnSurfaceComposer::GET_LAYER_DEBUG_INFO`, 21.`BnSurfaceComposer::GET_COMPOSITION_PREFERENCE`, 22.`BnSurfaceComposer::GET_COLOR_MANAGEMENT`, 23.`BnSurfaceComposer::GET_DISPLAYED_CONTENT_SAMPLING_ATTRIBUTES`, 24.`BnSurfaceComposer::SET_DISPLAY_CONTENT_SAMPLING_ENABLED`, 25.`BnSurfaceComposer::GET_DISPLAYED_CONTENT_SAMPLE`, 26.`BnSurfaceComposer::GET_PROTECTED_CONTENT_SUPPORT`, 27.`BnSurfaceComposer::IS_WIDE_COLOR_DISPLAY`, 28.`BnSurfaceComposer::GET_DISPLAY_NATIVE_PRIMARIES`, 29.`BnSurfaceComposer::GET_PHYSICAL_DISPLAY_IDS`, 30.`BnSurfaceComposer::ADD_REGION_SAMPLING_LISTENER`, 31.`BnSurfaceComposer::REMOVE_REGION_SAMPLING_LISTENER`, 32.`BnSurfaceComposer::SET_DESIRED_DISPLAY_MODE_SPECS`, 33.`BnSurfaceComposer::GET_DESIRED_DISPLAY_MODE_SPECS`, 34.`BnSurfaceComposer::GET_DISPLAY_BRIGHTNESS_SUPPORT`, 35.`BnSurfaceComposer::SET_DISPLAY_BRIGHTNESS`, 36.`BnSurfaceComposer::CAPTURE_DISPLAY_BY_ID`, 37.`BnSurfaceComposer::NOTIFY_POWER_BOOST`, 38.`BnSurfaceComposer::SET_GLOBAL_SHADOW_SETTINGS`, 39.`BnSurfaceComposer::SET_AUTO_LOW_LATENCY_MODE`, 40.`BnSurfaceComposer::SET_GAME_CONTENT_TYPE`, 41.`BnSurfaceComposer::SET_FRAME_RATE`, 42.`BnSurfaceComposer::ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN`, 43.`BnSurfaceComposer::SET_FRAME_TIMELINE_INFO`, 44.`BnSurfaceComposer::ADD_TRANSACTION_TRACE_LISTENER`, 45.`BnSurfaceComposer::GET_GPU_CONTEXT_PRIORITY`, 46.`BnSurfaceComposer::GET_MAX_ACQUIRED_BUFFER_COUNT`, 47.`BnSurfaceComposer::GET_DYNAMIC_DISPLAY_INFO`, 48.`BnSurfaceComposer::ADD_FPS_LISTENER`, 49.`BnSurfaceComposer::REMOVE_FPS_LISTENER`, 50.`BnSurfaceComposer::OVERRIDE_HDR_TYPES`, 51.`BnSurfaceComposer::ADD_HDR_LAYER_INFO_LISTENER`, 52.`BnSurfaceComposer::REMOVE_HDR_LAYER_INFO_LISTENER`, 53.`BnSurfaceComposer::ON_PULL_ATOM`, 54.`BnSurfaceComposer::ADD_TUNNEL_MODE_ENABLED_LISTENER`, 55.`BnSurfaceComposer::REMOVE_TUNNEL_MODE_ENABLED_LISTENER` | Value obtained from FuzzedDataProvider|
-|`boostId`| 0.`hardware::power::Boost::INTERACTION`, 1.`hardware::power::Boost::DISPLAY_UPDATE_IMMINENT`, 2.`hardware::power::Boost::ML_ACC`, 3.`hardware::power::Boost::AUDIO_LAUNCH`, 4.`hardware::power::Boost::CAMERA_LAUNCH`, 5.`hardware::power::Boost::CAMERA_SHOT` |Value obtained from FuzzedDataProvider|
-|`vsyncSource`| 0.`ISurfaceComposer::eVsyncSourceApp`, 1.`ISurfaceComposer::eVsyncSourceSurfaceFlinger`, |Value obtained from FuzzedDataProvider|
-|`eventRegistration`| 0.`ISurfaceComposer::EventRegistration::modeChanged`, 1.`ISurfaceComposer::EventRegistration::frameRateOverride` |Value obtained from FuzzedDataProvider|
-|`frameRateCompatibility`| 0.`ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT`, 1.`ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE` |Value obtained from FuzzedDataProvider|
-|`changeFrameRateStrategy`| 0.`ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS`, 1.`ANATIVEWINDOW_CHANGE_FRAME_RATE_ALWAYS` |Value obtained from FuzzedDataProvider|
-|`hdrTypes`| 0.`ui::Hdr::DOLBY_VISION`, 1.`ui::Hdr::HDR10`, 2.`ui::Hdr::HLG`, 3.`ui::Hdr::HDR10_PLUS` |Value obtained from FuzzedDataProvider|
-
-#### Steps to run
-1. Build the fuzzer
-```
- $ mm -j$(nproc) libgui_surfaceComposer_fuzzer
-```
-2. Run on device
-```
- $ adb sync data
- $ adb shell /data/fuzz/arm64/libgui_surfaceComposer_fuzzer/libgui_surfaceComposer_fuzzer
-```
-
-# <a name="libgui_surfaceComposerClient_fuzzer"></a> Fuzzer for SurfaceComposerClient
-
-SurfaceComposerClient supports the following data sources:
-1. SurfaceWidth (parameter name:`width`)
-2. SurfaceHeight (parameter name:`height`)
-3. TransactionStateFlags (parameter name:`flags`)
-4. TransformHint (parameter name:`outTransformHint`)
-5. SurfacePixelFormat (parameter name:`format`)
-6. LayerId (parameter name:`outLayerId`)
-7. SurfaceComposerClientTags (parameter name:`surfaceTag`)
-8. DefaultMode (parameter name:`defaultMode`)
-9. PrimaryRefreshRateMin (parameter name:`primaryRefreshRateMin`)
-10. PrimaryRefreshRateMax (parameter name:`primaryRefreshRateMax`)
-11. AppRefreshRateMin (parameter name:`appRefreshRateMin`)
-12. AppRefreshRateMax (parameter name:`appRefreshRateMax`)
-13. DisplayPowerMode (parameter name:`mode`)
-14. CacheId (parameter name:`cacheId`)
-15. DisplayBrightness (parameter name:`brightness`)
-16. PowerBoostID (parameter name:`boostId`)
-17. AtomId (parameter name:`atomId`)
-18. ComponentMask (parameter name:`componentMask`)
-19. MaxFrames (parameter name:`maxFrames`)
-20. TaskId (parameter name:`taskId`)
-21. Alpha (parameter name:`aplha`)
-22. CornerRadius (parameter name:`cornerRadius`)
-23. BackgroundBlurRadius (parameter name:`backgroundBlurRadius`)
-24. Half3Color (parameter name:`color`)
-25. LayerStack (parameter name:`layerStack`)
-26. Dataspace (parameter name:`dataspace`)
-27. Api (parameter name:`api`)
-28. Priority (parameter name:`priority`)
-29. TouchableRegionPointX (parameter name:`pointX`)
-30. TouchableRegionPointY (parameter name:`pointY`)
-31. ColorMode (parameter name:`colorMode`)
-32. WindowInfoFlags (parameter name:`flags`)
-33. WindowInfoTransformOrientation (parameter name:`transform`)
-
-| Parameter| Valid Values| Configured Value|
-|------------- |-------------| ----- |
-|`surfaceTag`| 0.`Tag::CREATE_SURFACE`, 1.`Tag::CREATE_WITH_SURFACE_PARENT`, 2.`Tag::CLEAR_LAYER_FRAME_STATS`, 3.`Tag::GET_LAYER_FRAME_STATS`, 4.`Tag::MIRROR_SURFACE`, 5.`Tag::LAST` |Value obtained from FuzzedDataProvider|
-|`mode`| 0.`gui::TouchOcclusionMode::BLOCK_UNTRUSTED`, 1.`gui::TouchOcclusionMode::USE_OPACITY`, 2.`gui::TouchOcclusionMode::ALLOW` |Value obtained from FuzzedDataProvider|
-|`boostId`| 0.`hardware::power::Boost::INTERACTION`, 1.`hardware::power::Boost::DISPLAY_UPDATE_IMMINENT`, 2.`hardware::power::Boost::ML_ACC`, 3.`hardware::power::Boost::AUDIO_LAUNCH`, 4.`hardware::power::Boost::CAMERA_LAUNCH`, 5.`hardware::power::Boost::CAMERA_SHOT` |Value obtained from FuzzedDataProvider|
-|`colorMode`|0.`ui::ColorMode::NATIVE`, 1.`ui::ColorMode::STANDARD_BT601_625`, 2.`ui::ColorMode::STANDARD_BT601_625_UNADJUSTED`, 3.`ui::ColorMode::STANDARD_BT601_525`, 4.`ui::ColorMode::STANDARD_BT601_525_UNADJUSTED`, 5.`ui::ColorMode::STANDARD_BT709`, 6.`ui::ColorMode::DCI_P3`, 7.`ui::ColorMode::SRGB`, 8.`ui::ColorMode::ADOBE_RGB`, 9.`ui::ColorMode::DISPLAY_P3`, 10.`ui::ColorMode::BT2020`, 11.`ui::ColorMode::BT2100_PQ`, 12.`ui::ColorMode::BT2100_HLG`, 13.`ui::ColorMode::DISPLAY_BT2020` |Value obtained from FuzzedDataProvider|
-|`flags`|0 .`gui::WindowInfo::Flag::ALLOW_LOCK_WHILE_SCREEN_ON`, 1.`gui::WindowInfo::Flag::DIM_BEHIND`, 2.`gui::WindowInfo::Flag::BLUR_BEHIND`, 3.`gui::WindowInfo::Flag::NOT_FOCUSABLE`, 4.`gui::WindowInfo::Flag::NOT_TOUCHABLE`, 5.`gui::WindowInfo::Flag::NOT_TOUCH_MODAL`, 6.`gui::WindowInfo::Flag::TOUCHABLE_WHEN_WAKING`, 7.`gui::WindowInfo::Flag::KEEP_SCREEN_ON`, 8.`gui::WindowInfo::Flag::LAYOUT_IN_SCREEN`, 9.`gui::WindowInfo::Flag::LAYOUT_NO_LIMITS`, 10.`gui::WindowInfo::Flag::FULLSCREEN`, 11.`gui::WindowInfo::Flag::FORCE_NOT_FULLSCREEN`, 12.`gui::WindowInfo::Flag::DITHER`, 13.`gui::WindowInfo::Flag::SECURE`, 14.`gui::WindowInfo::Flag::SCALED`, 15.`gui::WindowInfo::Flag::IGNORE_CHEEK_PRESSES`, 16.`gui::WindowInfo::Flag::LAYOUT_INSET_DECOR`, 17.`gui::WindowInfo::Flag::ALT_FOCUSABLE_IM`, 18.`gui::WindowInfo::Flag::WATCH_OUTSIDE_TOUCH`, 19.`gui::WindowInfo::Flag::SHOW_WHEN_LOCKED`, 20.`gui::WindowInfo::Flag::SHOW_WALLPAPER`, 21.`gui::WindowInfo::Flag::TURN_SCREEN_ON`, 22.`gui::WindowInfo::Flag::DISMISS_KEYGUARD`, 23.`gui::WindowInfo::Flag::SPLIT_TOUCH`, 24.`gui::WindowInfo::Flag::HARDWARE_ACCELERATED`, 25.`gui::WindowInfo::Flag::LAYOUT_IN_OVERSCAN`, 26.`gui::WindowInfo::Flag::TRANSLUCENT_STATUS`, 27.`gui::WindowInfo::Flag::TRANSLUCENT_NAVIGATION`, 28.`gui::WindowInfo::Flag::LOCAL_FOCUS_MODE`, 29.`gui::WindowInfo::Flag::SLIPPERY`, 30.`gui::WindowInfo::Flag::LAYOUT_ATTACHED_IN_DECOR`, 31.`gui::WindowInfo::Flag::DRAWS_SYSTEM_BAR_BACKGROUNDS`, |Value obtained from FuzzedDataProvider|
-|`dataspace`| 0.`ui::Dataspace::UNKNOWN`, 1.`ui::Dataspace::ARBITRARY`, 2.`ui::Dataspace::STANDARD_SHIFT`, 3.`ui::Dataspace::STANDARD_MASK`, 4.`ui::Dataspace::STANDARD_UNSPECIFIED`, 5.`ui::Dataspace::STANDARD_BT709`, 6.`ui::Dataspace::STANDARD_BT601_625`, 7.`ui::Dataspace::STANDARD_BT601_625_UNADJUSTED`, 8.`ui::Dataspace::STANDARD_BT601_525`, 9.`ui::Dataspace::STANDARD_BT601_525_UNADJUSTED`, 10.`ui::Dataspace::STANDARD_BT2020`, 11.`ui::Dataspace::STANDARD_BT2020_CONSTANT_LUMINANCE`, 12.`ui::Dataspace::STANDARD_BT470M`, 13.`ui::Dataspace::STANDARD_FILM`, 14.`ui::Dataspace::STANDARD_DCI_P3`, 15.`ui::Dataspace::STANDARD_ADOBE_RGB`, 16.`ui::Dataspace::TRANSFER_SHIFT`, 17.`ui::Dataspace::TRANSFER_MASK`, 18.`ui::Dataspace::TRANSFER_UNSPECIFIED`, 19.`ui::Dataspace::TRANSFER_LINEAR`, 20.`ui::Dataspace::TRANSFER_SRGB`, 21.`ui::Dataspace::TRANSFER_SMPTE_170M`, 22.`ui::Dataspace::TRANSFER_GAMMA2_2`, 23.`ui::Dataspace::TRANSFER_GAMMA2_6`, 24.`ui::Dataspace::TRANSFER_GAMMA2_8`, 25.`ui::Dataspace::TRANSFER_ST2084`, 26.`ui::Dataspace::TRANSFER_HLG`, 27.`ui::Dataspace::RANGE_SHIFT`, 28.`ui::Dataspace::RANGE_MASK`, 29.`ui::Dataspace::RANGE_UNSPECIFIED`, 30.`ui::Dataspace::RANGE_FULL`, 31.`ui::Dataspace::RANGE_LIMITED`, 32.`ui::Dataspace::RANGE_EXTENDED`, 33.`ui::Dataspace::SRGB_LINEAR`, 34.`ui::Dataspace::V0_SRGB_LINEAR`, 35.`ui::Dataspace::V0_SCRGB_LINEAR`, 36.`ui::Dataspace::SRGB`, 37.`ui::Dataspace::V0_SRGB`, 38.`ui::Dataspace::V0_SCRGB`, 39.`ui::Dataspace::JFIF`, 40.`ui::Dataspace::V0_JFIF`, 41.`ui::Dataspace::BT601_625`, 42.`ui::Dataspace::V0_BT601_625`, 43.`ui::Dataspace::BT601_525`, 44.`ui::Dataspace::V0_BT601_525`, 45.`ui::Dataspace::BT709`, 46.`ui::Dataspace::V0_BT709`, 47.`ui::Dataspace::DCI_P3_LINEAR`, 48.`ui::Dataspace::DCI_P3`, 49.`ui::Dataspace::DISPLAY_P3_LINEAR`, 50.`ui::Dataspace::DISPLAY_P3`, 51.`ui::Dataspace::ADOBE_RGB`, 52.`ui::Dataspace::BT2020_LINEAR`, 53.`ui::Dataspace::BT2020`, 54.`ui::Dataspace::BT2020_PQ`, 55.`ui::Dataspace::DEPTH`, 56.`ui::Dataspace::SENSOR`, 57.`ui::Dataspace::BT2020_ITU`, 58.`ui::Dataspace::BT2020_ITU_PQ`, 59.`ui::Dataspace::BT2020_ITU_HLG`, 60.`ui::Dataspace::BT2020_HLG`, 61.`ui::Dataspace::DISPLAY_BT2020`, 62.`ui::Dataspace::DYNAMIC_DEPTH`, 63.`ui::Dataspace::JPEG_APP_SEGMENTS`, 64.`ui::Dataspace::HEIF`, |Value obtained from FuzzedDataProvider|
-|`transform`| 0.`ui::Transform::ROT_0`, 1.`ui::Transform::FLIP_H`, 2.`ui::Transform::FLIP_V`, 3.`ui::Transform::ROT_90`, 4.`ui::Transform::ROT_180`, 5.`ui::Transform::ROT_270` |Value obtained from FuzzedDataProvider|
-
-#### Steps to run
-1. Build the fuzzer
-```
- $ mm -j$(nproc) libgui_surfaceComposerClient_fuzzer
-```
-2. To run on device
-```
- $ adb sync data
- $ adb shell /data/fuzz/arm64/libgui_surfaceComposerClient_fuzzer/libgui_surfaceComposerClient_fuzzer
-```
-
-# <a name="libgui_parcelable_fuzzer"></a> Fuzzer for Libgui_Parcelable
-
-Libgui_Parcelable supports the following parameters:
-1. LayerMetadataKey (parameter name:`key`)
-2. Dataspace (parameter name:`mDataspace`)
-
-| Parameter| Valid Values| Configured Value|
-|------------- |-------------| ----- |
-|`key`| 0.`view::LayerMetadataKey::METADATA_OWNER_UID`, 1.`view::LayerMetadataKey::METADATA_WINDOW_TYPE`, 2.`view::LayerMetadataKey::METADATA_TASK_ID`, 3.`view::LayerMetadataKey::METADATA_MOUSE_CURSOR`, 4.`view::LayerMetadataKey::METADATA_ACCESSIBILITY_ID`, 5.`view::LayerMetadataKey::METADATA_OWNER_PID`, 6.`view::LayerMetadataKey::METADATA_DEQUEUE_TIME`, 7.`view::LayerMetadataKey::METADATA_GAME_MODE`, |Value obtained from FuzzedDataProvider|
-|`mDataSpace`| 0.`ui::Dataspace::UNKNOWN`, 1.`ui::Dataspace::ARBITRARY`, 2.`ui::Dataspace::STANDARD_SHIFT`, 3.`ui::Dataspace::STANDARD_MASK`, 4.`ui::Dataspace::STANDARD_UNSPECIFIED`, 5.`ui::Dataspace::STANDARD_BT709`, 6.`ui::Dataspace::STANDARD_BT601_625`, 7.`ui::Dataspace::STANDARD_BT601_625_UNADJUSTED`, 8.`ui::Dataspace::STANDARD_BT601_525`, 9.`ui::Dataspace::STANDARD_BT601_525_UNADJUSTED`, 10.`ui::Dataspace::STANDARD_BT2020`, 11.`ui::Dataspace::STANDARD_BT2020_CONSTANT_LUMINANCE`, 12.`ui::Dataspace::STANDARD_BT470M`, 13.`ui::Dataspace::STANDARD_FILM`, 14.`ui::Dataspace::STANDARD_DCI_P3`, 15.`ui::Dataspace::STANDARD_ADOBE_RGB`, 16.`ui::Dataspace::TRANSFER_SHIFT`, 17.`ui::Dataspace::TRANSFER_MASK`, 18.`ui::Dataspace::TRANSFER_UNSPECIFIED`, 19.`ui::Dataspace::TRANSFER_LINEAR`, 20.`ui::Dataspace::TRANSFER_SRGB`, 21.`ui::Dataspace::TRANSFER_SMPTE_170M`, 22.`ui::Dataspace::TRANSFER_GAMMA2_2`, 23.`ui::Dataspace::TRANSFER_GAMMA2_6`, 24.`ui::Dataspace::TRANSFER_GAMMA2_8`, 25.`ui::Dataspace::TRANSFER_ST2084`, 26.`ui::Dataspace::TRANSFER_HLG`, 27.`ui::Dataspace::RANGE_SHIFT`, 28.`ui::Dataspace::RANGE_MASK`, 29.`ui::Dataspace::RANGE_UNSPECIFIED`, 30.`ui::Dataspace::RANGE_FULL`, 31.`ui::Dataspace::RANGE_LIMITED`, 32.`ui::Dataspace::RANGE_EXTENDED`, 33.`ui::Dataspace::SRGB_LINEAR`, 34.`ui::Dataspace::V0_SRGB_LINEAR`, 35.`ui::Dataspace::V0_SCRGB_LINEAR`, 36.`ui::Dataspace::SRGB`, 37.`ui::Dataspace::V0_SRGB`, 38.`ui::Dataspace::V0_SCRGB`, 39.`ui::Dataspace::JFIF`, 40.`ui::Dataspace::V0_JFIF`, 41.`ui::Dataspace::BT601_625`, 42.`ui::Dataspace::V0_BT601_625`, 43.`ui::Dataspace::BT601_525`, 44.`ui::Dataspace::V0_BT601_525`, 45.`ui::Dataspace::BT709`, 46.`ui::Dataspace::V0_BT709`, 47.`ui::Dataspace::DCI_P3_LINEAR`, 48.`ui::Dataspace::DCI_P3`, 49.`ui::Dataspace::DISPLAY_P3_LINEAR`, 50.`ui::Dataspace::DISPLAY_P3`, 51.`ui::Dataspace::ADOBE_RGB`, 52.`ui::Dataspace::BT2020_LINEAR`, 53.`ui::Dataspace::BT2020`, 54.`ui::Dataspace::BT2020_PQ`, 55.`ui::Dataspace::DEPTH`, 56.`ui::Dataspace::SENSOR`, 57.`ui::Dataspace::BT2020_ITU`, 58.`ui::Dataspace::BT2020_ITU_PQ`, 59.`ui::Dataspace::BT2020_ITU_HLG`, 60.`ui::Dataspace::BT2020_HLG`, 61.`ui::Dataspace::DISPLAY_BT2020`, 62.`ui::Dataspace::DYNAMIC_DEPTH`, 63.`ui::Dataspace::JPEG_APP_SEGMENTS`, 64.`ui::Dataspace::HEIF`, |Value obtained from FuzzedDataProvider|
-
-#### Steps to run
-1. Build the fuzzer
-```
- $ mm -j$(nproc) libgui_fuzzer
-```
-2. Run on device
-```
- $ adb sync data
- $ adb shell /data/fuzz/arm64/libgui_fuzzer/libgui_fuzzer
-```
-
-# <a name="libgui_bufferQueue_fuzzer"></a> Fuzzer for BufferQueue
-
-BufferQueue supports the following parameters:
-1. SurfaceWidth (parameter name:`width`)
-2. SurfaceHeight (parameter name:`height`)
-3. TransactionStateFlags (parameter name:`flags`)
-4. TransformHint (parameter name:`outTransformHint`)
-5. SurfacePixelFormat (parameter name:`format`)
-6. LayerId (parameter name:`layerId`)
-7. BufferId (parameter name:`bufferId`)
-8. FrameNumber (parameter name:`frameNumber`)
-9. FrameRate (parameter name:`frameRate`)
-10. Compatability (parameter name:`compatability`)
-11. LatchTime (parameter name:`latchTime`)
-12. AcquireTime (parameter name:`acquireTime`)
-13. RefreshTime (parameter name:`refreshTime`)
-14. DequeueTime (parameter name:`dequeueTime`)
-15. Slot (parameter name:`slot`)
-16. MaxBuffers (parameter name:`maxBuffers`)
-17. GenerationNumber (parameter name:`generationNumber`)
-18. Api (parameter name:`api`)
-19. Usage (parameter name:`usage`)
-20. MaxFrameNumber (parameter name:`maxFrameNumber`)
-21. BufferCount (parameter name:`bufferCount`)
-22. MaxAcquredBufferCount (parameter name:`maxAcquredBufferCount`)
-23. Status (parameter name:`status`)
-24. ApiConnection (parameter name:`apiConnection`)
-25. Dataspace (parameter name:`dataspace`)
-
-| Parameter| Valid Values| Configured Value|
-|------------- |-------------| ----- |
-|`status`| 0.`OK`, 1.`NO_MEMORY`, 2.`NO_INIT`, 3.`BAD_VALUE`, 4.`DEAD_OBJECT`, 5.`INVALID_OPERATION`, 6.`TIMED_OUT`, 7.`WOULD_BLOCK`, 8.`UNKNOWN_ERROR`, 9.`ALREADY_EXISTS`, |Value obtained from FuzzedDataProvider|
-|`apiConnection`| 0.`BufferQueueCore::CURRENTLY_CONNECTED_API`, 1.`BufferQueueCore::NO_CONNECTED_API`, 2.`NATIVE_WINDOW_API_EGL`, 3.`NATIVE_WINDOW_API_CPU`, 4.`NATIVE_WINDOW_API_MEDIA`, 5.`NATIVE_WINDOW_API_CAMERA`, |Value obtained from FuzzedDataProvider|
-|`dataspace`| 0.`ui::Dataspace::UNKNOWN`, 1.`ui::Dataspace::ARBITRARY`, 2.`ui::Dataspace::STANDARD_SHIFT`, 3.`ui::Dataspace::STANDARD_MASK`, 4.`ui::Dataspace::STANDARD_UNSPECIFIED`, 5.`ui::Dataspace::STANDARD_BT709`, 6.`ui::Dataspace::STANDARD_BT601_625`, 7.`ui::Dataspace::STANDARD_BT601_625_UNADJUSTED`, 8.`ui::Dataspace::STANDARD_BT601_525`, 9.`ui::Dataspace::STANDARD_BT601_525_UNADJUSTED`, 10.`ui::Dataspace::STANDARD_BT2020`, 11.`ui::Dataspace::STANDARD_BT2020_CONSTANT_LUMINANCE`, 12.`ui::Dataspace::STANDARD_BT470M`, 13.`ui::Dataspace::STANDARD_FILM`, 14.`ui::Dataspace::STANDARD_DCI_P3`, 15.`ui::Dataspace::STANDARD_ADOBE_RGB`, 16.`ui::Dataspace::TRANSFER_SHIFT`, 17.`ui::Dataspace::TRANSFER_MASK`, 18.`ui::Dataspace::TRANSFER_UNSPECIFIED`, 19.`ui::Dataspace::TRANSFER_LINEAR`, 20.`ui::Dataspace::TRANSFER_SRGB`, 21.`ui::Dataspace::TRANSFER_SMPTE_170M`, 22.`ui::Dataspace::TRANSFER_GAMMA2_2`, 23.`ui::Dataspace::TRANSFER_GAMMA2_6`, 24.`ui::Dataspace::TRANSFER_GAMMA2_8`, 25.`ui::Dataspace::TRANSFER_ST2084`, 26.`ui::Dataspace::TRANSFER_HLG`, 27.`ui::Dataspace::RANGE_SHIFT`, 28.`ui::Dataspace::RANGE_MASK`, 29.`ui::Dataspace::RANGE_UNSPECIFIED`, 30.`ui::Dataspace::RANGE_FULL`, 31.`ui::Dataspace::RANGE_LIMITED`, 32.`ui::Dataspace::RANGE_EXTENDED`, 33.`ui::Dataspace::SRGB_LINEAR`, 34.`ui::Dataspace::V0_SRGB_LINEAR`, 35.`ui::Dataspace::V0_SCRGB_LINEAR`, 36.`ui::Dataspace::SRGB`, 37.`ui::Dataspace::V0_SRGB`, 38.`ui::Dataspace::V0_SCRGB`, 39.`ui::Dataspace::JFIF`, 40.`ui::Dataspace::V0_JFIF`, 41.`ui::Dataspace::BT601_625`, 42.`ui::Dataspace::V0_BT601_625`, 43.`ui::Dataspace::BT601_525`, 44.`ui::Dataspace::V0_BT601_525`, 45.`ui::Dataspace::BT709`, 46.`ui::Dataspace::V0_BT709`, 47.`ui::Dataspace::DCI_P3_LINEAR`, 48.`ui::Dataspace::DCI_P3`, 49.`ui::Dataspace::DISPLAY_P3_LINEAR`, 50.`ui::Dataspace::DISPLAY_P3`, 51.`ui::Dataspace::ADOBE_RGB`, 52.`ui::Dataspace::BT2020_LINEAR`, 53.`ui::Dataspace::BT2020`, 54.`ui::Dataspace::BT2020_PQ`, 55.`ui::Dataspace::DEPTH`, 56.`ui::Dataspace::SENSOR`, 57.`ui::Dataspace::BT2020_ITU`, 58.`ui::Dataspace::BT2020_ITU_PQ`, 59.`ui::Dataspace::BT2020_ITU_HLG`, 60.`ui::Dataspace::BT2020_HLG`, 61.`ui::Dataspace::DISPLAY_BT2020`, 62.`ui::Dataspace::DYNAMIC_DEPTH`, 63.`ui::Dataspace::JPEG_APP_SEGMENTS`, 64.`ui::Dataspace::HEIF`, |Value obtained from FuzzedDataProvider|
-
-#### Steps to run
-1. Build the fuzzer
-```
- $ mm -j$(nproc) libgui_bufferQueue_fuzzer
-```
-2. To run on device
-```
- $ adb sync data
- $ adb shell /data/fuzz/arm64/libgui_bufferQueue_fuzzer/libgui_bufferQueue_fuzzer
-```
-
-# <a name="libgui_consumer_fuzzer"></a> Fuzzer for Libgui_Consumer
-
-Libgui_Consumer supports the following parameters:
-1. GraphicWidth (parameter name:`graphicWidth`)
-2. GraphicHeight (parameter name:`graphicHeight`)
-4. TransformHint (parameter name:`outTransformHint`)
-5. GraphicPixelFormat (parameter name:`format`)
-6. Usage (parameter name:`usage`)
-
-#### Steps to run
-1. Build the fuzzer
-```
- $ mm -j$(nproc) libgui_consumer_fuzzer
-```
-2. Run on device
-```
- $ adb sync data
- $ adb shell /data/fuzz/arm64/libgui_consumer_fuzzer/libgui_consumer_fuzzer
-```
-
-# <a name="libgui_displayEvent_fuzzer"></a> Fuzzer for LibGui_DisplayEvent
-
-LibGui_DisplayEvent supports the following parameters:
-1. DisplayEventType (parameter name:`type`)
-2. Events (parameter name:`events`)
-3. VsyncSource (parameter name:`vsyncSource`)
-4. EventRegistrationFlags (parameter name:`flags`)
-
-| Parameter| Valid Values| Configured Value|
-|------------- |-------------| ----- |
-|`vsyncSource`| 0.`ISurfaceComposer::eVsyncSourceApp`, 1.`ISurfaceComposer::eVsyncSourceSurfaceFlinger`, |Value obtained from FuzzedDataProvider|
-|`flags`| 0.`ISurfaceComposer::EventRegistration::modeChanged`, 1.`ISurfaceComposer::EventRegistration::frameRateOverride`, |Value obtained from FuzzedDataProvider|
-|`type`| 0.`DisplayEventReceiver::DISPLAY_EVENT_NULL`, 1.`DisplayEventReceiver::DISPLAY_EVENT_VSYNC`, 2.`DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG`, 3.`DisplayEventReceiver::DISPLAY_EVENT_MODE_CHANGE`, 4.`DisplayEventReceiver::DISPLAY_EVENT_FRAME_RATE_OVERRIDE`, 5.`DisplayEventReceiver::DISPLAY_EVENT_FRAME_RATE_OVERRIDE_FLUSH`, |Value obtained from FuzzedDataProvider|
-|`events`| 0.`Looper::EVENT_INPUT`, 1.`Looper::EVENT_OUTPUT`, 2.`Looper::EVENT_ERROR`, 3.`Looper::EVENT_HANGUP`, 4.`Looper::EVENT_INVALID`, |Value obtained from FuzzedDataProvider|
-
-#### Steps to run
-1. Build the fuzzer
-```
- $ mm -j$(nproc) libgui_displayEvent_fuzzer
-```
-2. Run on device
-```
- $ adb sync data
- $ adb shell /data/fuzz/arm64/libgui_displayEvent_fuzzer/libgui_displayEvent_fuzzer
-```
diff --git a/libs/gui/fuzzer/libgui_bufferQueue_fuzzer.cpp b/libs/gui/fuzzer/libgui_bufferQueue_fuzzer.cpp
deleted file mode 100644
index 2e270b721f..0000000000
--- a/libs/gui/fuzzer/libgui_bufferQueue_fuzzer.cpp
+++ /dev/null
@@ -1,392 +0,0 @@
-/*
- * Copyright 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include <android-base/stringprintf.h>
-#include <gui/BufferQueueConsumer.h>
-#include <gui/BufferQueueCore.h>
-#include <gui/BufferQueueProducer.h>
-#include <gui/bufferqueue/2.0/types.h>
-#include <system/window.h>
-
-#include <libgui_fuzzer_utils.h>
-
-using namespace android;
-using namespace hardware::graphics::bufferqueue;
-using namespace V1_0::utils;
-using namespace V2_0::utils;
-
-constexpr int32_t kMaxBytes = 256;
-
-constexpr int32_t kError[] = {
- OK, NO_MEMORY, NO_INIT, BAD_VALUE, DEAD_OBJECT, INVALID_OPERATION,
- TIMED_OUT, WOULD_BLOCK, UNKNOWN_ERROR, ALREADY_EXISTS,
-};
-
-constexpr int32_t kAPIConnection[] = {
- BufferQueueCore::CURRENTLY_CONNECTED_API,
- BufferQueueCore::NO_CONNECTED_API,
- NATIVE_WINDOW_API_EGL,
- NATIVE_WINDOW_API_CPU,
- NATIVE_WINDOW_API_MEDIA,
- NATIVE_WINDOW_API_CAMERA,
-};
-
-class BufferQueueFuzzer {
-public:
- BufferQueueFuzzer(const uint8_t* data, size_t size) : mFdp(data, size){};
- void process();
-
-private:
- void invokeTypes();
- void invokeH2BGraphicBufferV1();
- void invokeH2BGraphicBufferV2();
- void invokeBufferQueueConsumer();
- void invokeBufferQueueProducer();
- void invokeBlastBufferQueue();
- void invokeQuery(sp<BufferQueueProducer>);
- void invokeQuery(sp<V1_0::utils::H2BGraphicBufferProducer>);
- void invokeQuery(sp<V2_0::utils::H2BGraphicBufferProducer>);
- void invokeAcquireBuffer(sp<BufferQueueConsumer>);
- void invokeOccupancyTracker(sp<BufferQueueConsumer>);
- sp<SurfaceControl> makeSurfaceControl();
- sp<BLASTBufferQueue> makeBLASTBufferQueue(sp<SurfaceControl>);
-
- FuzzedDataProvider mFdp;
-};
-
-class ManageResourceHandle {
-public:
- ManageResourceHandle(FuzzedDataProvider* fdp) {
- mNativeHandle = native_handle_create(0 /*numFds*/, 1 /*numInts*/);
- mShouldOwn = fdp->ConsumeBool();
- mStream = NativeHandle::create(mNativeHandle, mShouldOwn);
- }
- ~ManageResourceHandle() {
- if (!mShouldOwn) {
- native_handle_close(mNativeHandle);
- native_handle_delete(mNativeHandle);
- }
- }
- sp<NativeHandle> getStream() { return mStream; }
-
-private:
- bool mShouldOwn;
- sp<NativeHandle> mStream;
- native_handle_t* mNativeHandle;
-};
-
-sp<SurfaceControl> BufferQueueFuzzer::makeSurfaceControl() {
- sp<IBinder> handle;
- const sp<FakeBnSurfaceComposerClient> testClient(new FakeBnSurfaceComposerClient());
- sp<SurfaceComposerClient> client = new SurfaceComposerClient(testClient);
- sp<BnGraphicBufferProducer> producer;
- uint32_t layerId = mFdp.ConsumeIntegral<uint32_t>();
- std::string layerName = base::StringPrintf("#%d", layerId);
- return sp<SurfaceControl>::make(client, handle, layerId, layerName,
- mFdp.ConsumeIntegral<int32_t>(),
- mFdp.ConsumeIntegral<uint32_t>(),
- mFdp.ConsumeIntegral<int32_t>(),
- mFdp.ConsumeIntegral<uint32_t>(),
- mFdp.ConsumeIntegral<uint32_t>());
-}
-
-sp<BLASTBufferQueue> BufferQueueFuzzer::makeBLASTBufferQueue(sp<SurfaceControl> surface) {
- return sp<BLASTBufferQueue>::make(mFdp.ConsumeRandomLengthString(kMaxBytes), surface,
- mFdp.ConsumeIntegral<uint32_t>(),
- mFdp.ConsumeIntegral<uint32_t>(),
- mFdp.ConsumeIntegral<int32_t>());
-}
-
-void BufferQueueFuzzer::invokeBlastBufferQueue() {
- sp<SurfaceControl> surface = makeSurfaceControl();
- sp<BLASTBufferQueue> queue = makeBLASTBufferQueue(surface);
-
- BufferItem item;
- queue->onFrameAvailable(item);
- queue->onFrameReplaced(item);
- uint64_t bufferId = mFdp.ConsumeIntegral<uint64_t>();
- queue->onFrameDequeued(bufferId);
- queue->onFrameCancelled(bufferId);
-
- SurfaceComposerClient::Transaction next;
- uint64_t frameNumber = mFdp.ConsumeIntegral<uint64_t>();
- queue->mergeWithNextTransaction(&next, frameNumber);
- queue->applyPendingTransactions(frameNumber);
-
- queue->update(surface, mFdp.ConsumeIntegral<uint32_t>(), mFdp.ConsumeIntegral<uint32_t>(),
- mFdp.ConsumeIntegral<int32_t>());
- queue->setFrameRate(mFdp.ConsumeFloatingPoint<float>(), mFdp.ConsumeIntegral<int8_t>(),
- mFdp.ConsumeBool() /*shouldBeSeamless*/);
- FrameTimelineInfo info;
- queue->setFrameTimelineInfo(mFdp.ConsumeIntegral<uint64_t>(), info);
-
- ManageResourceHandle handle(&mFdp);
- queue->setSidebandStream(handle.getStream());
-
- queue->getLastTransformHint();
- queue->getLastAcquiredFrameNum();
-
- CompositorTiming compTiming;
- sp<Fence> previousFence = new Fence(memfd_create("pfd", MFD_ALLOW_SEALING));
- sp<Fence> gpuFence = new Fence(memfd_create("gfd", MFD_ALLOW_SEALING));
- FrameEventHistoryStats frameStats(frameNumber, mFdp.ConsumeIntegral<uint64_t>(), gpuFence,
- compTiming, mFdp.ConsumeIntegral<int64_t>(),
- mFdp.ConsumeIntegral<int64_t>());
- std::vector<SurfaceControlStats> stats;
- sp<Fence> presentFence = new Fence(memfd_create("fd", MFD_ALLOW_SEALING));
- SurfaceControlStats controlStats(surface, mFdp.ConsumeIntegral<int64_t>(),
- mFdp.ConsumeIntegral<int64_t>(), presentFence, previousFence,
- mFdp.ConsumeIntegral<uint32_t>(), frameStats,
- mFdp.ConsumeIntegral<uint32_t>());
- stats.push_back(controlStats);
-}
-
-void BufferQueueFuzzer::invokeQuery(sp<BufferQueueProducer> producer) {
- int32_t value;
- producer->query(mFdp.ConsumeIntegral<int32_t>(), &value);
-}
-
-void BufferQueueFuzzer::invokeQuery(sp<V1_0::utils::H2BGraphicBufferProducer> producer) {
- int32_t value;
- producer->query(mFdp.ConsumeIntegral<int32_t>(), &value);
-}
-
-void BufferQueueFuzzer::invokeQuery(sp<V2_0::utils::H2BGraphicBufferProducer> producer) {
- int32_t value;
- producer->query(mFdp.ConsumeIntegral<int32_t>(), &value);
-}
-
-void BufferQueueFuzzer::invokeBufferQueueProducer() {
- sp<BufferQueueCore> core(new BufferQueueCore());
- sp<BufferQueueProducer> producer(new BufferQueueProducer(core));
- const sp<android::IProducerListener> listener;
- android::IGraphicBufferProducer::QueueBufferOutput output;
- uint32_t api = mFdp.ConsumeIntegral<uint32_t>();
- producer->connect(listener, api, mFdp.ConsumeBool() /*producerControlledByApp*/, &output);
-
- sp<GraphicBuffer> buffer;
- int32_t slot = mFdp.ConsumeIntegral<int32_t>();
- uint32_t maxBuffers = mFdp.ConsumeIntegral<uint32_t>();
- producer->requestBuffer(slot, &buffer);
- producer->setMaxDequeuedBufferCount(maxBuffers);
- producer->setAsyncMode(mFdp.ConsumeBool() /*async*/);
-
- android::IGraphicBufferProducer::QueueBufferInput input;
- producer->attachBuffer(&slot, buffer);
- producer->queueBuffer(slot, input, &output);
-
- int32_t format = mFdp.ConsumeIntegral<int32_t>();
- uint32_t width = mFdp.ConsumeIntegral<uint32_t>();
- uint32_t height = mFdp.ConsumeIntegral<uint32_t>();
- uint64_t usage = mFdp.ConsumeIntegral<uint64_t>();
- uint64_t outBufferAge;
- FrameEventHistoryDelta outTimestamps;
- sp<android::Fence> fence;
- producer->dequeueBuffer(&slot, &fence, width, height, format, usage, &outBufferAge,
- &outTimestamps);
- producer->detachBuffer(slot);
- producer->detachNextBuffer(&buffer, &fence);
- producer->cancelBuffer(slot, fence);
-
- invokeQuery(producer);
-
- ManageResourceHandle handle(&mFdp);
- producer->setSidebandStream(handle.getStream());
-
- producer->allocateBuffers(width, height, format, usage);
- producer->allowAllocation(mFdp.ConsumeBool() /*allow*/);
- producer->setSharedBufferMode(mFdp.ConsumeBool() /*sharedBufferMode*/);
- producer->setAutoRefresh(mFdp.ConsumeBool() /*autoRefresh*/);
- producer->setLegacyBufferDrop(mFdp.ConsumeBool() /*drop*/);
- producer->setAutoPrerotation(mFdp.ConsumeBool() /*autoPrerotation*/);
-
- producer->setGenerationNumber(mFdp.ConsumeIntegral<uint32_t>());
- producer->setDequeueTimeout(mFdp.ConsumeIntegral<uint32_t>());
- producer->disconnect(api);
-}
-
-void BufferQueueFuzzer::invokeAcquireBuffer(sp<BufferQueueConsumer> consumer) {
- BufferItem item;
- consumer->acquireBuffer(&item, mFdp.ConsumeIntegral<uint32_t>(),
- mFdp.ConsumeIntegral<uint64_t>());
-}
-
-void BufferQueueFuzzer::invokeOccupancyTracker(sp<BufferQueueConsumer> consumer) {
- String8 outResult;
- String8 prefix((mFdp.ConsumeRandomLengthString(kMaxBytes)).c_str());
- consumer->dumpState(prefix, &outResult);
-
- std::vector<OccupancyTracker::Segment> outHistory;
- consumer->getOccupancyHistory(mFdp.ConsumeBool() /*forceFlush*/, &outHistory);
-}
-
-void BufferQueueFuzzer::invokeBufferQueueConsumer() {
- sp<BufferQueueCore> core(new BufferQueueCore());
- sp<BufferQueueConsumer> consumer(new BufferQueueConsumer(core));
- sp<android::IConsumerListener> listener;
- consumer->consumerConnect(listener, mFdp.ConsumeBool() /*controlledByApp*/);
- invokeAcquireBuffer(consumer);
-
- int32_t slot = mFdp.ConsumeIntegral<int32_t>();
- sp<GraphicBuffer> buffer =
- new GraphicBuffer(mFdp.ConsumeIntegral<uint32_t>(), mFdp.ConsumeIntegral<uint32_t>(),
- mFdp.ConsumeIntegral<int32_t>(), mFdp.ConsumeIntegral<uint32_t>(),
- mFdp.ConsumeIntegral<uint64_t>());
- consumer->attachBuffer(&slot, buffer);
- consumer->detachBuffer(slot);
-
- consumer->setDefaultBufferSize(mFdp.ConsumeIntegral<uint32_t>(),
- mFdp.ConsumeIntegral<uint32_t>());
- consumer->setMaxBufferCount(mFdp.ConsumeIntegral<int32_t>());
- consumer->setMaxAcquiredBufferCount(mFdp.ConsumeIntegral<int32_t>());
-
- String8 name((mFdp.ConsumeRandomLengthString(kMaxBytes)).c_str());
- consumer->setConsumerName(name);
- consumer->setDefaultBufferFormat(mFdp.ConsumeIntegral<int32_t>());
- android_dataspace dataspace =
- static_cast<android_dataspace>(mFdp.PickValueInArray(kDataspaces));
- consumer->setDefaultBufferDataSpace(dataspace);
-
- consumer->setTransformHint(mFdp.ConsumeIntegral<uint32_t>());
- consumer->setConsumerUsageBits(mFdp.ConsumeIntegral<uint64_t>());
- consumer->setConsumerIsProtected(mFdp.ConsumeBool() /*isProtected*/);
- invokeOccupancyTracker(consumer);
-
- sp<Fence> releaseFence = new Fence(memfd_create("fd", MFD_ALLOW_SEALING));
- consumer->releaseBuffer(mFdp.ConsumeIntegral<int32_t>(), mFdp.ConsumeIntegral<uint64_t>(),
- EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, releaseFence);
- consumer->consumerDisconnect();
-}
-
-void BufferQueueFuzzer::invokeTypes() {
- HStatus hStatus;
- int32_t status = mFdp.PickValueInArray(kError);
- bool bufferNeedsReallocation = mFdp.ConsumeBool();
- bool releaseAllBuffers = mFdp.ConsumeBool();
- b2h(status, &hStatus, &bufferNeedsReallocation, &releaseAllBuffers);
- h2b(hStatus, &status);
-
- HConnectionType type;
- int32_t apiConnection = mFdp.PickValueInArray(kAPIConnection);
- b2h(apiConnection, &type);
- h2b(type, &apiConnection);
-}
-
-void BufferQueueFuzzer::invokeH2BGraphicBufferV1() {
- sp<V1_0::utils::H2BGraphicBufferProducer> producer(
- new V1_0::utils::H2BGraphicBufferProducer(new FakeGraphicBufferProducerV1()));
- const sp<android::IProducerListener> listener;
- android::IGraphicBufferProducer::QueueBufferOutput output;
- uint32_t api = mFdp.ConsumeIntegral<uint32_t>();
- producer->connect(listener, api, mFdp.ConsumeBool() /*producerControlledByApp*/, &output);
-
- sp<GraphicBuffer> buffer;
- int32_t slot = mFdp.ConsumeIntegral<int32_t>();
- producer->requestBuffer(slot, &buffer);
- producer->setMaxDequeuedBufferCount(mFdp.ConsumeIntegral<int32_t>());
- producer->setAsyncMode(mFdp.ConsumeBool());
-
- android::IGraphicBufferProducer::QueueBufferInput input;
- input.fence = new Fence(memfd_create("ffd", MFD_ALLOW_SEALING));
- producer->attachBuffer(&slot, buffer);
- producer->queueBuffer(slot, input, &output);
-
- int32_t format = mFdp.ConsumeIntegral<int32_t>();
- uint32_t width = mFdp.ConsumeIntegral<uint32_t>();
- uint32_t height = mFdp.ConsumeIntegral<uint32_t>();
- uint64_t usage = mFdp.ConsumeIntegral<uint64_t>();
- uint64_t outBufferAge;
- FrameEventHistoryDelta outTimestamps;
- sp<android::Fence> fence;
- producer->dequeueBuffer(&slot, &fence, width, height, format, usage, &outBufferAge,
- &outTimestamps);
- producer->detachBuffer(slot);
- producer->cancelBuffer(slot, fence);
-
- invokeQuery(producer);
-
- ManageResourceHandle handle(&mFdp);
- producer->setSidebandStream(handle.getStream());
-
- producer->allocateBuffers(width, height, format, usage);
- producer->allowAllocation(mFdp.ConsumeBool() /*allow*/);
- producer->setSharedBufferMode(mFdp.ConsumeBool() /*sharedBufferMode*/);
- producer->setAutoRefresh(mFdp.ConsumeBool() /*autoRefresh*/);
-
- producer->setGenerationNumber(mFdp.ConsumeIntegral<uint32_t>());
- producer->setDequeueTimeout(mFdp.ConsumeIntegral<uint32_t>());
- producer->disconnect(api);
-}
-
-void BufferQueueFuzzer::invokeH2BGraphicBufferV2() {
- sp<V2_0::utils::H2BGraphicBufferProducer> producer(
- new V2_0::utils::H2BGraphicBufferProducer(new FakeGraphicBufferProducerV2()));
- const sp<android::IProducerListener> listener;
- android::IGraphicBufferProducer::QueueBufferOutput output;
- uint32_t api = mFdp.ConsumeIntegral<uint32_t>();
- producer->connect(listener, api, mFdp.ConsumeBool() /*producerControlledByApp*/, &output);
-
- sp<GraphicBuffer> buffer;
- int32_t slot = mFdp.ConsumeIntegral<int32_t>();
- producer->requestBuffer(slot, &buffer);
- producer->setMaxDequeuedBufferCount(mFdp.ConsumeIntegral<uint32_t>());
- producer->setAsyncMode(mFdp.ConsumeBool());
-
- android::IGraphicBufferProducer::QueueBufferInput input;
- input.fence = new Fence(memfd_create("ffd", MFD_ALLOW_SEALING));
- producer->attachBuffer(&slot, buffer);
- producer->queueBuffer(slot, input, &output);
-
- int32_t format = mFdp.ConsumeIntegral<int32_t>();
- uint32_t width = mFdp.ConsumeIntegral<uint32_t>();
- uint32_t height = mFdp.ConsumeIntegral<uint32_t>();
- uint64_t usage = mFdp.ConsumeIntegral<uint64_t>();
- uint64_t outBufferAge;
- FrameEventHistoryDelta outTimestamps;
- sp<android::Fence> fence;
- producer->dequeueBuffer(&slot, &fence, width, height, format, usage, &outBufferAge,
- &outTimestamps);
- producer->detachBuffer(slot);
- producer->cancelBuffer(slot, fence);
-
- invokeQuery(producer);
-
- ManageResourceHandle handle(&mFdp);
- producer->setSidebandStream(handle.getStream());
-
- producer->allocateBuffers(width, height, format, usage);
- producer->allowAllocation(mFdp.ConsumeBool() /*allow*/);
- producer->setSharedBufferMode(mFdp.ConsumeBool() /*sharedBufferMode*/);
- producer->setAutoRefresh(mFdp.ConsumeBool() /*autoRefresh*/);
-
- producer->setGenerationNumber(mFdp.ConsumeIntegral<uint32_t>());
- producer->setDequeueTimeout(mFdp.ConsumeIntegral<uint32_t>());
- producer->disconnect(api);
-}
-
-void BufferQueueFuzzer::process() {
- invokeBlastBufferQueue();
- invokeH2BGraphicBufferV1();
- invokeH2BGraphicBufferV2();
- invokeTypes();
- invokeBufferQueueConsumer();
- invokeBufferQueueProducer();
-}
-
-extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
- BufferQueueFuzzer bufferQueueFuzzer(data, size);
- bufferQueueFuzzer.process();
- return 0;
-}
diff --git a/libs/gui/fuzzer/libgui_consumer_fuzzer.cpp b/libs/gui/fuzzer/libgui_consumer_fuzzer.cpp
deleted file mode 100644
index 24a046d3a9..0000000000
--- a/libs/gui/fuzzer/libgui_consumer_fuzzer.cpp
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include <gui/BufferQueueConsumer.h>
-#include <gui/BufferQueueCore.h>
-#include <gui/BufferQueueProducer.h>
-#include <gui/GLConsumer.h>
-#include <libgui_fuzzer_utils.h>
-
-using namespace android;
-
-constexpr int32_t kMinBuffer = 0;
-constexpr int32_t kMaxBuffer = 100000;
-
-class ConsumerFuzzer {
-public:
- ConsumerFuzzer(const uint8_t* data, size_t size) : mFdp(data, size){};
- void process();
-
-private:
- FuzzedDataProvider mFdp;
-};
-
-void ConsumerFuzzer::process() {
- sp<BufferQueueCore> core(new BufferQueueCore());
- sp<IGraphicBufferConsumer> consumer(new BufferQueueConsumer(core));
-
- uint64_t maxBuffers = mFdp.ConsumeIntegralInRange<uint64_t>(kMinBuffer, kMaxBuffer);
- sp<CpuConsumer> cpu(
- new CpuConsumer(consumer, maxBuffers, mFdp.ConsumeBool() /*controlledByApp*/));
- CpuConsumer::LockedBuffer lockBuffer;
- cpu->lockNextBuffer(&lockBuffer);
- cpu->unlockBuffer(lockBuffer);
- cpu->abandon();
-
- uint32_t tex = mFdp.ConsumeIntegral<uint32_t>();
- sp<GLConsumer> glComsumer(new GLConsumer(consumer, tex, GLConsumer::TEXTURE_EXTERNAL,
- mFdp.ConsumeBool() /*useFenceSync*/,
- mFdp.ConsumeBool() /*isControlledByApp*/));
- sp<Fence> releaseFence = new Fence(memfd_create("rfd", MFD_ALLOW_SEALING));
- glComsumer->setReleaseFence(releaseFence);
- glComsumer->updateTexImage();
- glComsumer->releaseTexImage();
-
- sp<GraphicBuffer> buffer =
- new GraphicBuffer(mFdp.ConsumeIntegral<uint32_t>(), mFdp.ConsumeIntegral<uint32_t>(),
- mFdp.ConsumeIntegral<int32_t>(), mFdp.ConsumeIntegral<uint32_t>(),
- mFdp.ConsumeIntegral<uint64_t>());
- float mtx[16];
- glComsumer->getTransformMatrix(mtx);
- glComsumer->computeTransformMatrix(mtx, buffer, getRect(&mFdp),
- mFdp.ConsumeIntegral<uint32_t>(),
- mFdp.ConsumeBool() /*filtering*/);
- glComsumer->scaleDownCrop(getRect(&mFdp), mFdp.ConsumeIntegral<uint32_t>(),
- mFdp.ConsumeIntegral<uint32_t>());
-
- glComsumer->setDefaultBufferSize(mFdp.ConsumeIntegral<uint32_t>(),
- mFdp.ConsumeIntegral<uint32_t>());
- glComsumer->setFilteringEnabled(mFdp.ConsumeBool() /*enabled*/);
-
- glComsumer->setConsumerUsageBits(mFdp.ConsumeIntegral<uint64_t>());
- glComsumer->attachToContext(tex);
- glComsumer->abandon();
-}
-
-extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
- ConsumerFuzzer consumerFuzzer(data, size);
- consumerFuzzer.process();
- return 0;
-}
diff --git a/libs/gui/fuzzer/libgui_displayEvent_fuzzer.cpp b/libs/gui/fuzzer/libgui_displayEvent_fuzzer.cpp
deleted file mode 100644
index 0d2a52b576..0000000000
--- a/libs/gui/fuzzer/libgui_displayEvent_fuzzer.cpp
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <android/gui/ISurfaceComposer.h>
-
-#include <libgui_fuzzer_utils.h>
-
-using namespace android;
-
-constexpr gui::ISurfaceComposer::VsyncSource kVsyncSource[] = {
- gui::ISurfaceComposer::VsyncSource::eVsyncSourceApp,
- gui::ISurfaceComposer::VsyncSource::eVsyncSourceSurfaceFlinger,
-};
-
-constexpr gui::ISurfaceComposer::EventRegistration kEventRegistration[] = {
- gui::ISurfaceComposer::EventRegistration::modeChanged,
- gui::ISurfaceComposer::EventRegistration::frameRateOverride,
-};
-
-constexpr uint32_t kDisplayEvent[] = {
- DisplayEventReceiver::DISPLAY_EVENT_NULL,
- DisplayEventReceiver::DISPLAY_EVENT_VSYNC,
- DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG,
- DisplayEventReceiver::DISPLAY_EVENT_MODE_CHANGE,
- DisplayEventReceiver::DISPLAY_EVENT_FRAME_RATE_OVERRIDE,
- DisplayEventReceiver::DISPLAY_EVENT_FRAME_RATE_OVERRIDE_FLUSH,
-};
-
-constexpr int32_t kEvents[] = {
- Looper::EVENT_INPUT, Looper::EVENT_OUTPUT, Looper::EVENT_ERROR,
- Looper::EVENT_HANGUP, Looper::EVENT_INVALID,
-};
-
-DisplayEventReceiver::Event buildDisplayEvent(FuzzedDataProvider* fdp, uint32_t type,
- DisplayEventReceiver::Event event) {
- switch (type) {
- case DisplayEventReceiver::DISPLAY_EVENT_VSYNC: {
- event.vsync.count = fdp->ConsumeIntegral<uint32_t>();
- event.vsync.vsyncData.frameInterval = fdp->ConsumeIntegral<uint64_t>();
- event.vsync.vsyncData.preferredFrameTimelineIndex = fdp->ConsumeIntegral<uint32_t>();
- for (size_t idx = 0; idx < gui::VsyncEventData::kFrameTimelinesCapacity; ++idx) {
- event.vsync.vsyncData.frameTimelines[idx].vsyncId = fdp->ConsumeIntegral<int64_t>();
- event.vsync.vsyncData.frameTimelines[idx].deadlineTimestamp =
- fdp->ConsumeIntegral<uint64_t>();
- event.vsync.vsyncData.frameTimelines[idx].expectedPresentationTime =
- fdp->ConsumeIntegral<uint64_t>();
- }
- break;
-
- }
- case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG: {
- event.hotplug =
- DisplayEventReceiver::Event::Hotplug{fdp->ConsumeBool() /*connected*/,
- fdp->ConsumeIntegral<
- int32_t>() /*connectionError*/};
- break;
- }
- case DisplayEventReceiver::DISPLAY_EVENT_MODE_CHANGE: {
- event.modeChange =
- DisplayEventReceiver::Event::ModeChange{fdp->ConsumeIntegral<int32_t>(),
- fdp->ConsumeIntegral<int64_t>()};
- break;
- }
- case DisplayEventReceiver::DISPLAY_EVENT_FRAME_RATE_OVERRIDE:
- case DisplayEventReceiver::DISPLAY_EVENT_FRAME_RATE_OVERRIDE_FLUSH: {
- event.frameRateOverride =
- DisplayEventReceiver::Event::FrameRateOverride{fdp->ConsumeIntegral<uint32_t>(),
- fdp->ConsumeFloatingPoint<
- float>()};
- break;
- }
- }
- return event;
-}
-
-extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
- FuzzedDataProvider fdp(data, size);
- sp<Looper> looper;
- sp<FakeDisplayEventDispatcher> dispatcher(
- new FakeDisplayEventDispatcher(looper, fdp.PickValueInArray(kVsyncSource),
- fdp.PickValueInArray(kEventRegistration)));
-
- dispatcher->initialize();
- DisplayEventReceiver::Event event;
- uint32_t type = fdp.PickValueInArray(kDisplayEvent);
- PhysicalDisplayId displayId;
- event.header =
- DisplayEventReceiver::Event::Header{type, displayId, fdp.ConsumeIntegral<int64_t>()};
- event = buildDisplayEvent(&fdp, type, event);
-
- dispatcher->injectEvent(event);
- dispatcher->handleEvent(0, fdp.PickValueInArray(kEvents), nullptr);
- return 0;
-}
diff --git a/libs/gui/fuzzer/libgui_fuzzer_utils.h b/libs/gui/fuzzer/libgui_fuzzer_utils.h
deleted file mode 100644
index 9933680c4b..0000000000
--- a/libs/gui/fuzzer/libgui_fuzzer_utils.h
+++ /dev/null
@@ -1,329 +0,0 @@
-/*
- * 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 <android/gui/BnRegionSamplingListener.h>
-#include <android/gui/BnSurfaceComposer.h>
-#include <android/gui/BnSurfaceComposerClient.h>
-#include <android/gui/IDisplayEventConnection.h>
-#include <android/gui/ISurfaceComposerClient.h>
-#include <fuzzer/FuzzedDataProvider.h>
-#include <gmock/gmock.h>
-#include <gui/BLASTBufferQueue.h>
-#include <gui/DisplayEventDispatcher.h>
-#include <gui/IGraphicBufferProducer.h>
-#include <gui/LayerDebugInfo.h>
-#include <gui/LayerState.h>
-#include <gui/bufferqueue/1.0/H2BGraphicBufferProducer.h>
-#include <gui/bufferqueue/2.0/H2BGraphicBufferProducer.h>
-#include <ui/fuzzer/FuzzableDataspaces.h>
-
-namespace android {
-
-constexpr uint32_t kOrientation[] = {
- ui::Transform::ROT_0, ui::Transform::FLIP_H, ui::Transform::FLIP_V,
- ui::Transform::ROT_90, ui::Transform::ROT_180, ui::Transform::ROT_270,
-};
-
-Rect getRect(FuzzedDataProvider* fdp) {
- const int32_t left = fdp->ConsumeIntegral<int32_t>();
- const int32_t top = fdp->ConsumeIntegral<int32_t>();
- const int32_t right = fdp->ConsumeIntegral<int32_t>();
- const int32_t bottom = fdp->ConsumeIntegral<int32_t>();
- return Rect(left, top, right, bottom);
-}
-
-gui::DisplayBrightness getBrightness(FuzzedDataProvider* fdp) {
- static constexpr float kMinBrightness = 0;
- static constexpr float kMaxBrightness = 1;
- gui::DisplayBrightness brightness;
- brightness.sdrWhitePoint =
- fdp->ConsumeFloatingPointInRange<float>(kMinBrightness, kMaxBrightness);
- brightness.sdrWhitePointNits =
- fdp->ConsumeFloatingPointInRange<float>(kMinBrightness, kMaxBrightness);
- brightness.displayBrightness =
- fdp->ConsumeFloatingPointInRange<float>(kMinBrightness, kMaxBrightness);
- brightness.displayBrightnessNits =
- fdp->ConsumeFloatingPointInRange<float>(kMinBrightness, kMaxBrightness);
- return brightness;
-}
-
-class FakeBnSurfaceComposer : public gui::BnSurfaceComposer {
-public:
- MOCK_METHOD(binder::Status, bootFinished, (), (override));
- MOCK_METHOD(binder::Status, createDisplayEventConnection,
- (gui::ISurfaceComposer::VsyncSource, gui::ISurfaceComposer::EventRegistration,
- const sp<IBinder>& /*layerHandle*/, sp<gui::IDisplayEventConnection>*),
- (override));
- MOCK_METHOD(binder::Status, createConnection, (sp<gui::ISurfaceComposerClient>*), (override));
- MOCK_METHOD(binder::Status, createDisplay, (const std::string&, bool, float, sp<IBinder>*),
- (override));
- MOCK_METHOD(binder::Status, destroyDisplay, (const sp<IBinder>&), (override));
- MOCK_METHOD(binder::Status, getPhysicalDisplayIds, (std::vector<int64_t>*), (override));
- MOCK_METHOD(binder::Status, getPhysicalDisplayToken, (int64_t, sp<IBinder>*), (override));
- MOCK_METHOD(binder::Status, setPowerMode, (const sp<IBinder>&, int), (override));
- MOCK_METHOD(binder::Status, getSupportedFrameTimestamps, (std::vector<FrameEvent>*),
- (override));
- MOCK_METHOD(binder::Status, getDisplayStats, (const sp<IBinder>&, gui::DisplayStatInfo*),
- (override));
- MOCK_METHOD(binder::Status, getDisplayState, (const sp<IBinder>&, gui::DisplayState*),
- (override));
- MOCK_METHOD(binder::Status, getStaticDisplayInfo, (int64_t, gui::StaticDisplayInfo*),
- (override));
- MOCK_METHOD(binder::Status, getDynamicDisplayInfoFromId, (int64_t, gui::DynamicDisplayInfo*),
- (override));
- MOCK_METHOD(binder::Status, getDynamicDisplayInfoFromToken,
- (const sp<IBinder>&, gui::DynamicDisplayInfo*), (override));
- MOCK_METHOD(binder::Status, getDisplayNativePrimaries,
- (const sp<IBinder>&, gui::DisplayPrimaries*), (override));
- MOCK_METHOD(binder::Status, setActiveColorMode, (const sp<IBinder>&, int), (override));
- MOCK_METHOD(binder::Status, setBootDisplayMode, (const sp<IBinder>&, int), (override));
- MOCK_METHOD(binder::Status, clearBootDisplayMode, (const sp<IBinder>&), (override));
- MOCK_METHOD(binder::Status, getBootDisplayModeSupport, (bool*), (override));
- MOCK_METHOD(binder::Status, getHdrConversionCapabilities,
- (std::vector<gui::HdrConversionCapability>*), (override));
- MOCK_METHOD(binder::Status, setHdrConversionStrategy,
- (const gui::HdrConversionStrategy&, int32_t*), (override));
- MOCK_METHOD(binder::Status, getHdrOutputConversionSupport, (bool*), (override));
- MOCK_METHOD(binder::Status, setAutoLowLatencyMode, (const sp<IBinder>&, bool), (override));
- MOCK_METHOD(binder::Status, setGameContentType, (const sp<IBinder>&, bool), (override));
- MOCK_METHOD(binder::Status, captureDisplay,
- (const DisplayCaptureArgs&, const sp<IScreenCaptureListener>&), (override));
- MOCK_METHOD(binder::Status, captureDisplayById,
- (int64_t, const gui::CaptureArgs&, const sp<IScreenCaptureListener>&), (override));
- MOCK_METHOD(binder::Status, captureLayers,
- (const LayerCaptureArgs&, const sp<IScreenCaptureListener>&), (override));
- MOCK_METHOD(binder::Status, clearAnimationFrameStats, (), (override));
- MOCK_METHOD(binder::Status, getAnimationFrameStats, (gui::FrameStats*), (override));
- MOCK_METHOD(binder::Status, overrideHdrTypes, (const sp<IBinder>&, const std::vector<int32_t>&),
- (override));
- MOCK_METHOD(binder::Status, onPullAtom, (int32_t, gui::PullAtomData*), (override));
- MOCK_METHOD(binder::Status, getLayerDebugInfo, (std::vector<gui::LayerDebugInfo>*), (override));
- MOCK_METHOD(binder::Status, getCompositionPreference, (gui::CompositionPreference*),
- (override));
- MOCK_METHOD(binder::Status, getDisplayedContentSamplingAttributes,
- (const sp<IBinder>&, gui::ContentSamplingAttributes*), (override));
- MOCK_METHOD(binder::Status, setDisplayContentSamplingEnabled,
- (const sp<IBinder>&, bool, int8_t, int64_t), (override));
- MOCK_METHOD(binder::Status, getDisplayedContentSample,
- (const sp<IBinder>&, int64_t, int64_t, gui::DisplayedFrameStats*), (override));
- MOCK_METHOD(binder::Status, getProtectedContentSupport, (bool*), (override));
- MOCK_METHOD(binder::Status, isWideColorDisplay, (const sp<IBinder>&, bool*), (override));
- MOCK_METHOD(binder::Status, addRegionSamplingListener,
- (const gui::ARect&, const sp<IBinder>&, const sp<gui::IRegionSamplingListener>&),
- (override));
- MOCK_METHOD(binder::Status, removeRegionSamplingListener,
- (const sp<gui::IRegionSamplingListener>&), (override));
- MOCK_METHOD(binder::Status, addFpsListener, (int32_t, const sp<gui::IFpsListener>&),
- (override));
- MOCK_METHOD(binder::Status, removeFpsListener, (const sp<gui::IFpsListener>&), (override));
- MOCK_METHOD(binder::Status, addTunnelModeEnabledListener,
- (const sp<gui::ITunnelModeEnabledListener>&), (override));
- MOCK_METHOD(binder::Status, removeTunnelModeEnabledListener,
- (const sp<gui::ITunnelModeEnabledListener>&), (override));
- MOCK_METHOD(binder::Status, setDesiredDisplayModeSpecs,
- (const sp<IBinder>&, const gui::DisplayModeSpecs&), (override));
- MOCK_METHOD(binder::Status, getDesiredDisplayModeSpecs,
- (const sp<IBinder>&, gui::DisplayModeSpecs*), (override));
- MOCK_METHOD(binder::Status, getDisplayBrightnessSupport, (const sp<IBinder>&, bool*),
- (override));
- MOCK_METHOD(binder::Status, setDisplayBrightness,
- (const sp<IBinder>&, const gui::DisplayBrightness&), (override));
- MOCK_METHOD(binder::Status, addHdrLayerInfoListener,
- (const sp<IBinder>&, const sp<gui::IHdrLayerInfoListener>&), (override));
- MOCK_METHOD(binder::Status, removeHdrLayerInfoListener,
- (const sp<IBinder>&, const sp<gui::IHdrLayerInfoListener>&), (override));
- MOCK_METHOD(binder::Status, notifyPowerBoost, (int), (override));
- MOCK_METHOD(binder::Status, setGlobalShadowSettings,
- (const gui::Color&, const gui::Color&, float, float, float), (override));
- MOCK_METHOD(binder::Status, getDisplayDecorationSupport,
- (const sp<IBinder>&, std::optional<gui::DisplayDecorationSupport>*), (override));
- MOCK_METHOD(binder::Status, setGameModeFrameRateOverride, (int32_t, float), (override));
- MOCK_METHOD(binder::Status, setGameDefaultFrameRateOverride, (int32_t, float), (override));
- MOCK_METHOD(binder::Status, enableRefreshRateOverlay, (bool), (override));
- MOCK_METHOD(binder::Status, setDebugFlash, (int), (override));
- MOCK_METHOD(binder::Status, scheduleComposite, (), (override));
- MOCK_METHOD(binder::Status, scheduleCommit, (), (override));
- MOCK_METHOD(binder::Status, forceClientComposition, (bool), (override));
- MOCK_METHOD(binder::Status, updateSmallAreaDetection,
- (const std::vector<int32_t>&, const std::vector<float>&), (override));
- MOCK_METHOD(binder::Status, setSmallAreaDetectionThreshold, (int32_t, float), (override));
- MOCK_METHOD(binder::Status, getGpuContextPriority, (int32_t*), (override));
- MOCK_METHOD(binder::Status, getMaxAcquiredBufferCount, (int32_t*), (override));
- MOCK_METHOD(binder::Status, addWindowInfosListener,
- (const sp<gui::IWindowInfosListener>&, gui::WindowInfosListenerInfo*), (override));
- MOCK_METHOD(binder::Status, removeWindowInfosListener, (const sp<gui::IWindowInfosListener>&),
- (override));
- MOCK_METHOD(binder::Status, getOverlaySupport, (gui::OverlayProperties*), (override));
- MOCK_METHOD(binder::Status, getStalledTransactionInfo,
- (int32_t, std::optional<gui::StalledTransactionInfo>*), (override));
- MOCK_METHOD(binder::Status, getSchedulingPolicy, (gui::SchedulingPolicy*), (override));
-};
-
-class FakeBnSurfaceComposerClient : public gui::BnSurfaceComposerClient {
-public:
- MOCK_METHOD(binder::Status, createSurface,
- (const std::string& name, int32_t flags, const sp<IBinder>& parent,
- const gui::LayerMetadata& metadata, gui::CreateSurfaceResult* outResult),
- (override));
-
- MOCK_METHOD(binder::Status, clearLayerFrameStats, (const sp<IBinder>& handle), (override));
-
- MOCK_METHOD(binder::Status, getLayerFrameStats,
- (const sp<IBinder>& handle, gui::FrameStats* outStats), (override));
-
- MOCK_METHOD(binder::Status, mirrorSurface,
- (const sp<IBinder>& mirrorFromHandle, gui::CreateSurfaceResult* outResult),
- (override));
-
- MOCK_METHOD(binder::Status, mirrorDisplay,
- (int64_t displayId, gui::CreateSurfaceResult* outResult), (override));
-
- MOCK_METHOD(binder::Status, getSchedulingPolicy, (gui::SchedulingPolicy*), (override));
-};
-
-class FakeDisplayEventDispatcher : public DisplayEventDispatcher {
-public:
- FakeDisplayEventDispatcher(const sp<Looper>& looper,
- gui::ISurfaceComposer::VsyncSource vsyncSource,
- gui::ISurfaceComposer::EventRegistration eventRegistration)
- : DisplayEventDispatcher(looper, vsyncSource, eventRegistration){};
-
- MOCK_METHOD4(dispatchVsync, void(nsecs_t, PhysicalDisplayId, uint32_t, VsyncEventData));
- MOCK_METHOD3(dispatchHotplug, void(nsecs_t, PhysicalDisplayId, bool));
- MOCK_METHOD2(dispatchHotplugConnectionError, void(nsecs_t, int32_t));
- MOCK_METHOD4(dispatchModeChanged, void(nsecs_t, PhysicalDisplayId, int32_t, nsecs_t));
- MOCK_METHOD2(dispatchNullEvent, void(nsecs_t, PhysicalDisplayId));
- MOCK_METHOD3(dispatchFrameRateOverrides,
- void(nsecs_t, PhysicalDisplayId, std::vector<FrameRateOverride>));
-};
-
-} // namespace android
-
-namespace android::hardware {
-
-namespace graphics::bufferqueue::V1_0::utils {
-
-class FakeGraphicBufferProducerV1 : public HGraphicBufferProducer {
-public:
- FakeGraphicBufferProducerV1() {
- ON_CALL(*this, setMaxDequeuedBufferCount).WillByDefault([]() { return 0; });
- ON_CALL(*this, setAsyncMode).WillByDefault([]() { return 0; });
- ON_CALL(*this, detachBuffer).WillByDefault([]() { return 0; });
- ON_CALL(*this, cancelBuffer).WillByDefault([]() { return 0; });
- ON_CALL(*this, disconnect).WillByDefault([]() { return 0; });
- ON_CALL(*this, setSidebandStream).WillByDefault([]() { return 0; });
- ON_CALL(*this, allowAllocation).WillByDefault([]() { return 0; });
- ON_CALL(*this, setGenerationNumber).WillByDefault([]() { return 0; });
- ON_CALL(*this, setSharedBufferMode).WillByDefault([]() { return 0; });
- ON_CALL(*this, setAutoRefresh).WillByDefault([]() { return 0; });
- ON_CALL(*this, setDequeueTimeout).WillByDefault([]() { return 0; });
- ON_CALL(*this, setLegacyBufferDrop).WillByDefault([]() { return 0; });
- };
- MOCK_METHOD2(requestBuffer, Return<void>(int, requestBuffer_cb));
- MOCK_METHOD1(setMaxDequeuedBufferCount, Return<int32_t>(int32_t));
- MOCK_METHOD1(setAsyncMode, Return<int32_t>(bool));
- MOCK_METHOD6(dequeueBuffer,
- Return<void>(uint32_t, uint32_t, graphics::common::V1_0::PixelFormat, uint32_t,
- bool, dequeueBuffer_cb));
- MOCK_METHOD1(detachBuffer, Return<int32_t>(int));
- MOCK_METHOD1(detachNextBuffer, Return<void>(detachNextBuffer_cb));
- MOCK_METHOD2(attachBuffer, Return<void>(const media::V1_0::AnwBuffer&, attachBuffer_cb));
- MOCK_METHOD3(
- queueBuffer,
- Return<void>(
- int,
- const graphics::bufferqueue::V1_0::IGraphicBufferProducer::QueueBufferInput&,
- queueBuffer_cb));
- MOCK_METHOD2(cancelBuffer, Return<int32_t>(int, const hidl_handle&));
- MOCK_METHOD2(query, Return<void>(int32_t, query_cb));
- MOCK_METHOD4(connect,
- Return<void>(const sp<graphics::bufferqueue::V1_0::IProducerListener>&, int32_t,
- bool, connect_cb));
- MOCK_METHOD2(disconnect,
- Return<int32_t>(
- int, graphics::bufferqueue::V1_0::IGraphicBufferProducer::DisconnectMode));
- MOCK_METHOD1(setSidebandStream, Return<int32_t>(const hidl_handle&));
- MOCK_METHOD4(allocateBuffers,
- Return<void>(uint32_t, uint32_t, graphics::common::V1_0::PixelFormat, uint32_t));
- MOCK_METHOD1(allowAllocation, Return<int32_t>(bool));
- MOCK_METHOD1(setGenerationNumber, Return<int32_t>(uint32_t));
- MOCK_METHOD1(getConsumerName, Return<void>(getConsumerName_cb));
- MOCK_METHOD1(setSharedBufferMode, Return<int32_t>(bool));
- MOCK_METHOD1(setAutoRefresh, Return<int32_t>(bool));
- MOCK_METHOD1(setDequeueTimeout, Return<int32_t>(nsecs_t));
- MOCK_METHOD1(setLegacyBufferDrop, Return<int32_t>(bool));
- MOCK_METHOD1(getLastQueuedBuffer, Return<void>(getLastQueuedBuffer_cb));
- MOCK_METHOD1(getFrameTimestamps, Return<void>(getFrameTimestamps_cb));
- MOCK_METHOD1(getUniqueId, Return<void>(getUniqueId_cb));
-};
-
-}; // namespace graphics::bufferqueue::V1_0::utils
-
-namespace graphics::bufferqueue::V2_0::utils {
-
-class FakeGraphicBufferProducerV2 : public HGraphicBufferProducer {
-public:
- FakeGraphicBufferProducerV2() {
- ON_CALL(*this, setMaxDequeuedBufferCount).WillByDefault([]() { return Status::OK; });
- ON_CALL(*this, setAsyncMode).WillByDefault([]() { return Status::OK; });
- ON_CALL(*this, detachBuffer).WillByDefault([]() { return Status::OK; });
- ON_CALL(*this, cancelBuffer).WillByDefault([]() { return Status::OK; });
- ON_CALL(*this, disconnect).WillByDefault([]() { return Status::OK; });
- ON_CALL(*this, allocateBuffers).WillByDefault([]() { return Status::OK; });
- ON_CALL(*this, allowAllocation).WillByDefault([]() { return Status::OK; });
- ON_CALL(*this, setGenerationNumber).WillByDefault([]() { return Status::OK; });
- ON_CALL(*this, setDequeueTimeout).WillByDefault([]() { return Status::OK; });
- ON_CALL(*this, getUniqueId).WillByDefault([]() { return 0; });
- };
- MOCK_METHOD2(requestBuffer, Return<void>(int, requestBuffer_cb));
- MOCK_METHOD1(setMaxDequeuedBufferCount, Return<graphics::bufferqueue::V2_0::Status>(int));
- MOCK_METHOD1(setAsyncMode, Return<graphics::bufferqueue::V2_0::Status>(bool));
- MOCK_METHOD2(
- dequeueBuffer,
- Return<void>(
- const graphics::bufferqueue::V2_0::IGraphicBufferProducer::DequeueBufferInput&,
- dequeueBuffer_cb));
- MOCK_METHOD1(detachBuffer, Return<graphics::bufferqueue::V2_0::Status>(int));
- MOCK_METHOD1(detachNextBuffer, Return<void>(detachNextBuffer_cb));
- MOCK_METHOD3(attachBuffer,
- Return<void>(const graphics::common::V1_2::HardwareBuffer&, uint32_t,
- attachBuffer_cb));
- MOCK_METHOD3(
- queueBuffer,
- Return<void>(
- int,
- const graphics::bufferqueue::V2_0::IGraphicBufferProducer::QueueBufferInput&,
- queueBuffer_cb));
- MOCK_METHOD2(cancelBuffer,
- Return<graphics::bufferqueue::V2_0::Status>(int, const hidl_handle&));
- MOCK_METHOD2(query, Return<void>(int32_t, query_cb));
- MOCK_METHOD4(connect,
- Return<void>(const sp<graphics::bufferqueue::V2_0::IProducerListener>&,
- graphics::bufferqueue::V2_0::ConnectionType, bool, connect_cb));
- MOCK_METHOD1(disconnect,
- Return<graphics::bufferqueue::V2_0::Status>(
- graphics::bufferqueue::V2_0::ConnectionType));
- MOCK_METHOD4(allocateBuffers,
- Return<graphics::bufferqueue::V2_0::Status>(uint32_t, uint32_t, uint32_t,
- uint64_t));
- MOCK_METHOD1(allowAllocation, Return<graphics::bufferqueue::V2_0::Status>(bool));
- MOCK_METHOD1(setGenerationNumber, Return<graphics::bufferqueue::V2_0::Status>(uint32_t));
- MOCK_METHOD1(getConsumerName, Return<void>(getConsumerName_cb));
- MOCK_METHOD1(setDequeueTimeout, Return<graphics::bufferqueue::V2_0::Status>(int64_t));
- MOCK_METHOD0(getUniqueId, Return<uint64_t>());
-};
-
-}; // namespace graphics::bufferqueue::V2_0::utils
-}; // namespace android::hardware
diff --git a/libs/gui/fuzzer/libgui_parcelable_fuzzer.cpp b/libs/gui/fuzzer/libgui_parcelable_fuzzer.cpp
deleted file mode 100644
index 9f0f6cac19..0000000000
--- a/libs/gui/fuzzer/libgui_parcelable_fuzzer.cpp
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * Copyright 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include <gui/BufferQueueConsumer.h>
-#include <gui/BufferQueueCore.h>
-#include <gui/BufferQueueProducer.h>
-#include <gui/LayerMetadata.h>
-#include <gui/OccupancyTracker.h>
-#include <gui/StreamSplitter.h>
-#include <gui/Surface.h>
-#include <gui/SurfaceControl.h>
-#include <gui/view/Surface.h>
-#include <libgui_fuzzer_utils.h>
-#include "android/view/LayerMetadataKey.h"
-
-using namespace android;
-
-constexpr int32_t kMaxBytes = 256;
-constexpr int32_t kMatrixSize = 4;
-constexpr int32_t kLayerMetadataKeyCount = 8;
-
-constexpr uint32_t kMetadataKey[] = {
- (uint32_t)view::LayerMetadataKey::METADATA_OWNER_UID,
- (uint32_t)view::LayerMetadataKey::METADATA_WINDOW_TYPE,
- (uint32_t)view::LayerMetadataKey::METADATA_TASK_ID,
- (uint32_t)view::LayerMetadataKey::METADATA_MOUSE_CURSOR,
- (uint32_t)view::LayerMetadataKey::METADATA_ACCESSIBILITY_ID,
- (uint32_t)view::LayerMetadataKey::METADATA_OWNER_PID,
- (uint32_t)view::LayerMetadataKey::METADATA_DEQUEUE_TIME,
- (uint32_t)view::LayerMetadataKey::METADATA_GAME_MODE,
-};
-
-class ParcelableFuzzer {
-public:
- ParcelableFuzzer(const uint8_t* data, size_t size) : mFdp(data, size){};
- void process();
-
-private:
- void invokeStreamSplitter();
- void invokeOccupancyTracker();
- void invokeLayerDebugInfo();
- void invokeLayerMetadata();
- void invokeViewSurface();
-
- FuzzedDataProvider mFdp;
-};
-
-void ParcelableFuzzer::invokeViewSurface() {
- view::Surface surface;
- surface.name = String16((mFdp.ConsumeRandomLengthString(kMaxBytes)).c_str());
- Parcel parcel;
- surface.writeToParcel(&parcel);
- parcel.setDataPosition(0);
- surface.readFromParcel(&parcel);
- bool nameAlreadyWritten = mFdp.ConsumeBool();
- surface.writeToParcel(&parcel, nameAlreadyWritten);
- parcel.setDataPosition(0);
- surface.readFromParcel(&parcel, mFdp.ConsumeBool());
-}
-
-void ParcelableFuzzer::invokeLayerMetadata() {
- std::unordered_map<uint32_t, std::vector<uint8_t>> map;
- for (size_t idx = 0; idx < kLayerMetadataKeyCount; ++idx) {
- std::vector<uint8_t> data;
- for (size_t idx1 = 0; idx1 < mFdp.ConsumeIntegral<uint32_t>(); ++idx1) {
- data.push_back(mFdp.ConsumeIntegral<uint8_t>());
- }
- map[kMetadataKey[idx]] = data;
- }
- LayerMetadata metadata(map);
- uint32_t key = mFdp.PickValueInArray(kMetadataKey);
- metadata.setInt32(key, mFdp.ConsumeIntegral<int32_t>());
- metadata.itemToString(key, (mFdp.ConsumeRandomLengthString(kMaxBytes)).c_str());
-
- Parcel parcel;
- metadata.writeToParcel(&parcel);
- parcel.setDataPosition(0);
- metadata.readFromParcel(&parcel);
-}
-
-void ParcelableFuzzer::invokeLayerDebugInfo() {
- gui::LayerDebugInfo info;
- info.mName = mFdp.ConsumeRandomLengthString(kMaxBytes);
- info.mParentName = mFdp.ConsumeRandomLengthString(kMaxBytes);
- info.mType = mFdp.ConsumeRandomLengthString(kMaxBytes);
- info.mLayerStack = mFdp.ConsumeIntegral<uint32_t>();
- info.mX = mFdp.ConsumeFloatingPoint<float>();
- info.mY = mFdp.ConsumeFloatingPoint<float>();
- info.mZ = mFdp.ConsumeIntegral<uint32_t>();
- info.mWidth = mFdp.ConsumeIntegral<int32_t>();
- info.mHeight = mFdp.ConsumeIntegral<int32_t>();
- info.mActiveBufferWidth = mFdp.ConsumeIntegral<int32_t>();
- info.mActiveBufferHeight = mFdp.ConsumeIntegral<int32_t>();
- info.mActiveBufferStride = mFdp.ConsumeIntegral<int32_t>();
- info.mActiveBufferFormat = mFdp.ConsumeIntegral<int32_t>();
- info.mNumQueuedFrames = mFdp.ConsumeIntegral<int32_t>();
-
- info.mFlags = mFdp.ConsumeIntegral<uint32_t>();
- info.mPixelFormat = mFdp.ConsumeIntegral<int32_t>();
- info.mTransparentRegion = Region(getRect(&mFdp));
- info.mVisibleRegion = Region(getRect(&mFdp));
- info.mSurfaceDamageRegion = Region(getRect(&mFdp));
- info.mCrop = getRect(&mFdp);
- info.mDataSpace = static_cast<android_dataspace>(mFdp.PickValueInArray(kDataspaces));
- info.mColor = half4(mFdp.ConsumeFloatingPoint<float>(), mFdp.ConsumeFloatingPoint<float>(),
- mFdp.ConsumeFloatingPoint<float>(), mFdp.ConsumeFloatingPoint<float>());
- for (size_t idx = 0; idx < kMatrixSize; ++idx) {
- info.mMatrix[idx / 2][idx % 2] = mFdp.ConsumeFloatingPoint<float>();
- }
- info.mIsOpaque = mFdp.ConsumeBool();
- info.mContentDirty = mFdp.ConsumeBool();
- info.mStretchEffect.width = mFdp.ConsumeFloatingPoint<float>();
- info.mStretchEffect.height = mFdp.ConsumeFloatingPoint<float>();
- info.mStretchEffect.vectorX = mFdp.ConsumeFloatingPoint<float>();
- info.mStretchEffect.vectorY = mFdp.ConsumeFloatingPoint<float>();
- info.mStretchEffect.maxAmountX = mFdp.ConsumeFloatingPoint<float>();
- info.mStretchEffect.maxAmountY = mFdp.ConsumeFloatingPoint<float>();
- info.mStretchEffect.mappedChildBounds =
- FloatRect(mFdp.ConsumeFloatingPoint<float>(), mFdp.ConsumeFloatingPoint<float>(),
- mFdp.ConsumeFloatingPoint<float>(), mFdp.ConsumeFloatingPoint<float>());
-
- Parcel parcel;
- info.writeToParcel(&parcel);
- parcel.setDataPosition(0);
- info.readFromParcel(&parcel);
-}
-
-void ParcelableFuzzer::invokeOccupancyTracker() {
- nsecs_t totalTime = mFdp.ConsumeIntegral<uint32_t>();
- size_t numFrames = mFdp.ConsumeIntegral<size_t>();
- float occupancyAverage = mFdp.ConsumeFloatingPoint<float>();
- OccupancyTracker::Segment segment(totalTime, numFrames, occupancyAverage,
- mFdp.ConsumeBool() /*usedThirdBuffer*/);
- Parcel parcel;
- segment.writeToParcel(&parcel);
- parcel.setDataPosition(0);
- segment.readFromParcel(&parcel);
-}
-
-void ParcelableFuzzer::invokeStreamSplitter() {
- sp<IGraphicBufferProducer> producer;
- sp<IGraphicBufferConsumer> consumer;
- BufferQueue::createBufferQueue(&producer, &consumer);
- sp<StreamSplitter> splitter;
- StreamSplitter::createSplitter(consumer, &splitter);
- splitter->addOutput(producer);
- std::string name = mFdp.ConsumeRandomLengthString(kMaxBytes);
- splitter->setName(String8(name.c_str()));
-}
-
-void ParcelableFuzzer::process() {
- invokeStreamSplitter();
- invokeOccupancyTracker();
- invokeLayerDebugInfo();
- invokeLayerMetadata();
- invokeViewSurface();
-}
-
-extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
- ParcelableFuzzer libGuiFuzzer(data, size);
- libGuiFuzzer.process();
- return 0;
-}
diff --git a/libs/gui/fuzzer/libgui_surfaceComposerClient_fuzzer.cpp b/libs/gui/fuzzer/libgui_surfaceComposerClient_fuzzer.cpp
deleted file mode 100644
index 4daa3be36f..0000000000
--- a/libs/gui/fuzzer/libgui_surfaceComposerClient_fuzzer.cpp
+++ /dev/null
@@ -1,328 +0,0 @@
-/*
- * Copyright 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include <aidl/android/hardware/power/Boost.h>
-#include <fuzzbinder/libbinder_driver.h>
-#include <gui/Surface.h>
-#include <gui/SurfaceComposerClient.h>
-#include <libgui_fuzzer_utils.h>
-#include "android-base/stringprintf.h"
-
-using namespace android;
-
-constexpr int32_t kRandomStringMaxBytes = 256;
-
-constexpr ui::ColorMode kColormodes[] = {ui::ColorMode::NATIVE,
- ui::ColorMode::STANDARD_BT601_625,
- ui::ColorMode::STANDARD_BT601_625_UNADJUSTED,
- ui::ColorMode::STANDARD_BT601_525,
- ui::ColorMode::STANDARD_BT601_525_UNADJUSTED,
- ui::ColorMode::STANDARD_BT709,
- ui::ColorMode::DCI_P3,
- ui::ColorMode::SRGB,
- ui::ColorMode::ADOBE_RGB,
- ui::ColorMode::DISPLAY_P3,
- ui::ColorMode::BT2020,
- ui::ColorMode::BT2100_PQ,
- ui::ColorMode::BT2100_HLG,
- ui::ColorMode::DISPLAY_BT2020};
-
-constexpr aidl::android::hardware::power::Boost kBoost[] = {
- aidl::android::hardware::power::Boost::INTERACTION,
- aidl::android::hardware::power::Boost::DISPLAY_UPDATE_IMMINENT,
- aidl::android::hardware::power::Boost::ML_ACC,
- aidl::android::hardware::power::Boost::AUDIO_LAUNCH,
- aidl::android::hardware::power::Boost::CAMERA_LAUNCH,
- aidl::android::hardware::power::Boost::CAMERA_SHOT,
-};
-
-constexpr gui::TouchOcclusionMode kMode[] = {
- gui::TouchOcclusionMode::BLOCK_UNTRUSTED,
- gui::TouchOcclusionMode::USE_OPACITY,
- gui::TouchOcclusionMode::ALLOW,
-};
-
-constexpr gui::WindowInfo::Flag kFlags[] = {
- gui::WindowInfo::Flag::ALLOW_LOCK_WHILE_SCREEN_ON,
- gui::WindowInfo::Flag::DIM_BEHIND,
- gui::WindowInfo::Flag::BLUR_BEHIND,
- gui::WindowInfo::Flag::NOT_FOCUSABLE,
- gui::WindowInfo::Flag::NOT_TOUCHABLE,
- gui::WindowInfo::Flag::NOT_TOUCH_MODAL,
- gui::WindowInfo::Flag::TOUCHABLE_WHEN_WAKING,
- gui::WindowInfo::Flag::KEEP_SCREEN_ON,
- gui::WindowInfo::Flag::LAYOUT_IN_SCREEN,
- gui::WindowInfo::Flag::LAYOUT_NO_LIMITS,
- gui::WindowInfo::Flag::FULLSCREEN,
- gui::WindowInfo::Flag::FORCE_NOT_FULLSCREEN,
- gui::WindowInfo::Flag::DITHER,
- gui::WindowInfo::Flag::SECURE,
- gui::WindowInfo::Flag::SCALED,
- gui::WindowInfo::Flag::IGNORE_CHEEK_PRESSES,
- gui::WindowInfo::Flag::LAYOUT_INSET_DECOR,
- gui::WindowInfo::Flag::ALT_FOCUSABLE_IM,
- gui::WindowInfo::Flag::WATCH_OUTSIDE_TOUCH,
- gui::WindowInfo::Flag::SHOW_WHEN_LOCKED,
- gui::WindowInfo::Flag::SHOW_WALLPAPER,
- gui::WindowInfo::Flag::TURN_SCREEN_ON,
- gui::WindowInfo::Flag::DISMISS_KEYGUARD,
- gui::WindowInfo::Flag::SPLIT_TOUCH,
- gui::WindowInfo::Flag::HARDWARE_ACCELERATED,
- gui::WindowInfo::Flag::LAYOUT_IN_OVERSCAN,
- gui::WindowInfo::Flag::TRANSLUCENT_STATUS,
- gui::WindowInfo::Flag::TRANSLUCENT_NAVIGATION,
- gui::WindowInfo::Flag::LOCAL_FOCUS_MODE,
- gui::WindowInfo::Flag::SLIPPERY,
- gui::WindowInfo::Flag::LAYOUT_ATTACHED_IN_DECOR,
- gui::WindowInfo::Flag::DRAWS_SYSTEM_BAR_BACKGROUNDS,
-};
-
-constexpr gui::WindowInfo::Type kType[] = {
- gui::WindowInfo::Type::UNKNOWN,
- gui::WindowInfo::Type::FIRST_APPLICATION_WINDOW,
- gui::WindowInfo::Type::BASE_APPLICATION,
- gui::WindowInfo::Type::APPLICATION,
- gui::WindowInfo::Type::APPLICATION_STARTING,
- gui::WindowInfo::Type::LAST_APPLICATION_WINDOW,
- gui::WindowInfo::Type::FIRST_SUB_WINDOW,
- gui::WindowInfo::Type::APPLICATION_PANEL,
- gui::WindowInfo::Type::APPLICATION_MEDIA,
- gui::WindowInfo::Type::APPLICATION_SUB_PANEL,
- gui::WindowInfo::Type::APPLICATION_ATTACHED_DIALOG,
- gui::WindowInfo::Type::APPLICATION_MEDIA_OVERLAY,
-};
-
-constexpr gui::WindowInfo::InputConfig kFeatures[] = {
- gui::WindowInfo::InputConfig::NO_INPUT_CHANNEL,
- gui::WindowInfo::InputConfig::DISABLE_USER_ACTIVITY,
- gui::WindowInfo::InputConfig::DROP_INPUT,
- gui::WindowInfo::InputConfig::DROP_INPUT_IF_OBSCURED,
- gui::WindowInfo::InputConfig::SPY,
- gui::WindowInfo::InputConfig::INTERCEPTS_STYLUS,
-};
-
-class SurfaceComposerClientFuzzer {
-public:
- SurfaceComposerClientFuzzer(const uint8_t* data, size_t size) : mFdp(data, size){};
- void process();
-
-private:
- void invokeSurfaceComposerClient();
- void invokeSurfaceComposerClientBinder();
- void invokeSurfaceComposerTransaction();
- void getWindowInfo(gui::WindowInfo*);
- sp<SurfaceControl> makeSurfaceControl();
- BlurRegion getBlurRegion();
- void fuzzOnPullAtom();
- gui::DisplayModeSpecs getDisplayModeSpecs();
-
- FuzzedDataProvider mFdp;
-};
-
-gui::DisplayModeSpecs SurfaceComposerClientFuzzer::getDisplayModeSpecs() {
- const auto getRefreshRateRange = [&] {
- gui::DisplayModeSpecs::RefreshRateRanges::RefreshRateRange range;
- range.min = mFdp.ConsumeFloatingPoint<float>();
- range.max = mFdp.ConsumeFloatingPoint<float>();
- return range;
- };
-
- const auto getRefreshRateRanges = [&] {
- gui::DisplayModeSpecs::RefreshRateRanges ranges;
- ranges.physical = getRefreshRateRange();
- ranges.render = getRefreshRateRange();
- return ranges;
- };
-
- String8 displayName((mFdp.ConsumeRandomLengthString(kRandomStringMaxBytes)).c_str());
- sp<IBinder> displayToken =
- SurfaceComposerClient::createDisplay(displayName, mFdp.ConsumeBool() /*secure*/);
- gui::DisplayModeSpecs specs;
- specs.defaultMode = mFdp.ConsumeIntegral<int32_t>();
- specs.allowGroupSwitching = mFdp.ConsumeBool();
- specs.primaryRanges = getRefreshRateRanges();
- specs.appRequestRanges = getRefreshRateRanges();
- return specs;
-}
-
-BlurRegion SurfaceComposerClientFuzzer::getBlurRegion() {
- int32_t left = mFdp.ConsumeIntegral<int32_t>();
- int32_t right = mFdp.ConsumeIntegral<int32_t>();
- int32_t top = mFdp.ConsumeIntegral<int32_t>();
- int32_t bottom = mFdp.ConsumeIntegral<int32_t>();
- uint32_t blurRadius = mFdp.ConsumeIntegral<uint32_t>();
- float alpha = mFdp.ConsumeFloatingPoint<float>();
- float cornerRadiusTL = mFdp.ConsumeFloatingPoint<float>();
- float cornerRadiusTR = mFdp.ConsumeFloatingPoint<float>();
- float cornerRadiusBL = mFdp.ConsumeFloatingPoint<float>();
- float cornerRadiusBR = mFdp.ConsumeFloatingPoint<float>();
- return BlurRegion{blurRadius, cornerRadiusTL, cornerRadiusTR, cornerRadiusBL,
- cornerRadiusBR, alpha, left, top,
- right, bottom};
-}
-
-void SurfaceComposerClientFuzzer::getWindowInfo(gui::WindowInfo* windowInfo) {
- windowInfo->id = mFdp.ConsumeIntegral<int32_t>();
- windowInfo->name = mFdp.ConsumeRandomLengthString(kRandomStringMaxBytes);
- windowInfo->layoutParamsFlags = mFdp.PickValueInArray(kFlags);
- windowInfo->layoutParamsType = mFdp.PickValueInArray(kType);
- windowInfo->frame = Rect(mFdp.ConsumeIntegral<int32_t>(), mFdp.ConsumeIntegral<int32_t>(),
- mFdp.ConsumeIntegral<int32_t>(), mFdp.ConsumeIntegral<int32_t>());
- windowInfo->surfaceInset = mFdp.ConsumeIntegral<int32_t>();
- windowInfo->alpha = mFdp.ConsumeFloatingPointInRange<float>(0, 1);
- ui::Transform transform(mFdp.PickValueInArray(kOrientation));
- windowInfo->transform = transform;
- windowInfo->touchableRegion = Region(getRect(&mFdp));
- windowInfo->replaceTouchableRegionWithCrop = mFdp.ConsumeBool();
- windowInfo->touchOcclusionMode = mFdp.PickValueInArray(kMode);
- windowInfo->ownerPid = gui::Pid{mFdp.ConsumeIntegral<pid_t>()};
- windowInfo->ownerUid = gui::Uid{mFdp.ConsumeIntegral<uid_t>()};
- windowInfo->packageName = mFdp.ConsumeRandomLengthString(kRandomStringMaxBytes);
- windowInfo->inputConfig = mFdp.PickValueInArray(kFeatures);
-}
-
-sp<SurfaceControl> SurfaceComposerClientFuzzer::makeSurfaceControl() {
- sp<IBinder> handle;
- const sp<FakeBnSurfaceComposerClient> testClient(new FakeBnSurfaceComposerClient());
- sp<SurfaceComposerClient> client = new SurfaceComposerClient(testClient);
- sp<BnGraphicBufferProducer> producer;
- uint32_t width = mFdp.ConsumeIntegral<uint32_t>();
- uint32_t height = mFdp.ConsumeIntegral<uint32_t>();
- uint32_t transformHint = mFdp.ConsumeIntegral<uint32_t>();
- uint32_t flags = mFdp.ConsumeIntegral<uint32_t>();
- int32_t format = mFdp.ConsumeIntegral<int32_t>();
- int32_t layerId = mFdp.ConsumeIntegral<int32_t>();
- std::string layerName = base::StringPrintf("#%d", layerId);
- return new SurfaceControl(client, handle, layerId, layerName, width, height, format,
- transformHint, flags);
-}
-
-void SurfaceComposerClientFuzzer::invokeSurfaceComposerTransaction() {
- sp<SurfaceControl> surface = makeSurfaceControl();
-
- SurfaceComposerClient::Transaction transaction;
- int32_t layer = mFdp.ConsumeIntegral<int32_t>();
- transaction.setLayer(surface, layer);
-
- sp<SurfaceControl> relativeSurface = makeSurfaceControl();
- transaction.setRelativeLayer(surface, relativeSurface, layer);
-
- Region transparentRegion(getRect(&mFdp));
- transaction.setTransparentRegionHint(surface, transparentRegion);
- transaction.setAlpha(surface, mFdp.ConsumeFloatingPoint<float>());
-
- transaction.setCornerRadius(surface, mFdp.ConsumeFloatingPoint<float>());
- transaction.setBackgroundBlurRadius(surface, mFdp.ConsumeFloatingPoint<float>());
- std::vector<BlurRegion> regions;
- uint32_t vectorSize = mFdp.ConsumeIntegralInRange<uint32_t>(0, 100);
- regions.resize(vectorSize);
- for (size_t idx = 0; idx < vectorSize; ++idx) {
- regions.push_back(getBlurRegion());
- }
- transaction.setBlurRegions(surface, regions);
-
- transaction.setLayerStack(surface, {mFdp.ConsumeIntegral<uint32_t>()});
- half3 color = {mFdp.ConsumeIntegral<uint32_t>(), mFdp.ConsumeIntegral<uint32_t>(),
- mFdp.ConsumeIntegral<uint32_t>()};
- transaction.setColor(surface, color);
- transaction.setBackgroundColor(surface, color, mFdp.ConsumeFloatingPoint<float>(),
- mFdp.PickValueInArray(kDataspaces));
-
- transaction.setApi(surface, mFdp.ConsumeIntegral<int32_t>());
- transaction.setFrameRateSelectionPriority(surface, mFdp.ConsumeIntegral<int32_t>());
- transaction.setColorSpaceAgnostic(surface, mFdp.ConsumeBool() /*agnostic*/);
-
- gui::WindowInfo windowInfo;
- getWindowInfo(&windowInfo);
- transaction.setInputWindowInfo(surface, windowInfo);
- Parcel windowParcel;
- windowInfo.writeToParcel(&windowParcel);
- windowParcel.setDataPosition(0);
- windowInfo.readFromParcel(&windowParcel);
-
- windowInfo.addTouchableRegion(getRect(&mFdp));
- int32_t pointX = mFdp.ConsumeIntegral<int32_t>();
- int32_t pointY = mFdp.ConsumeIntegral<int32_t>();
- windowInfo.touchableRegionContainsPoint(pointX, pointY);
- windowInfo.frameContainsPoint(pointX, pointY);
-
- Parcel transactionParcel;
- transaction.writeToParcel(&transactionParcel);
- transactionParcel.setDataPosition(0);
- transaction.readFromParcel(&transactionParcel);
- SurfaceComposerClient::Transaction::createFromParcel(&transactionParcel);
-}
-
-void SurfaceComposerClientFuzzer::fuzzOnPullAtom() {
- std::string outData;
- bool success;
- SurfaceComposerClient::onPullAtom(mFdp.ConsumeIntegral<int32_t>(), &outData, &success);
-}
-
-void SurfaceComposerClientFuzzer::invokeSurfaceComposerClient() {
- String8 displayName((mFdp.ConsumeRandomLengthString(kRandomStringMaxBytes)).c_str());
- sp<IBinder> displayToken =
- SurfaceComposerClient::createDisplay(displayName, mFdp.ConsumeBool() /*secure*/);
- SurfaceComposerClient::setDesiredDisplayModeSpecs(displayToken, getDisplayModeSpecs());
-
- ui::ColorMode colorMode = mFdp.PickValueInArray(kColormodes);
- SurfaceComposerClient::setActiveColorMode(displayToken, colorMode);
- SurfaceComposerClient::setAutoLowLatencyMode(displayToken, mFdp.ConsumeBool() /*on*/);
- SurfaceComposerClient::setGameContentType(displayToken, mFdp.ConsumeBool() /*on*/);
- SurfaceComposerClient::setDisplayPowerMode(displayToken, mFdp.ConsumeIntegral<int32_t>());
- SurfaceComposerClient::doUncacheBufferTransaction(mFdp.ConsumeIntegral<uint64_t>());
-
- SurfaceComposerClient::setDisplayBrightness(displayToken, getBrightness(&mFdp));
- aidl::android::hardware::power::Boost boostId = mFdp.PickValueInArray(kBoost);
- SurfaceComposerClient::notifyPowerBoost((int32_t)boostId);
-
- String8 surfaceName((mFdp.ConsumeRandomLengthString(kRandomStringMaxBytes)).c_str());
- sp<BBinder> handle(new BBinder());
- sp<BnGraphicBufferProducer> producer;
- sp<Surface> surfaceParent(
- new Surface(producer, mFdp.ConsumeBool() /*controlledByApp*/, handle));
-
- fuzzOnPullAtom();
- SurfaceComposerClient::setDisplayContentSamplingEnabled(displayToken,
- mFdp.ConsumeBool() /*enable*/,
- mFdp.ConsumeIntegral<uint8_t>(),
- mFdp.ConsumeIntegral<uint64_t>());
-
- sp<IBinder> stopLayerHandle;
- sp<gui::IRegionSamplingListener> listener = sp<gui::IRegionSamplingListenerDefault>::make();
- sp<gui::IRegionSamplingListenerDelegator> sampleListener =
- new gui::IRegionSamplingListenerDelegator(listener);
- SurfaceComposerClient::addRegionSamplingListener(getRect(&mFdp), stopLayerHandle,
- sampleListener);
- sp<gui::IFpsListenerDefault> fpsListener;
- SurfaceComposerClient::addFpsListener(mFdp.ConsumeIntegral<int32_t>(), fpsListener);
-}
-
-void SurfaceComposerClientFuzzer::invokeSurfaceComposerClientBinder() {
- sp<FakeBnSurfaceComposerClient> client(new FakeBnSurfaceComposerClient());
- fuzzService(client.get(), std::move(mFdp));
-}
-
-void SurfaceComposerClientFuzzer::process() {
- invokeSurfaceComposerClient();
- invokeSurfaceComposerTransaction();
- invokeSurfaceComposerClientBinder();
-}
-
-extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
- SurfaceComposerClientFuzzer surfaceComposerClientFuzzer(data, size);
- surfaceComposerClientFuzzer.process();
- return 0;
-}
diff --git a/libs/gui/fuzzer/libgui_surfaceComposer_fuzzer.cpp b/libs/gui/fuzzer/libgui_surfaceComposer_fuzzer.cpp
deleted file mode 100644
index 6d5427bc9e..0000000000
--- a/libs/gui/fuzzer/libgui_surfaceComposer_fuzzer.cpp
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * 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 <fuzzbinder/libbinder_driver.h>
-#include <fuzzer/FuzzedDataProvider.h>
-#include <libgui_fuzzer_utils.h>
-
-using namespace android;
-
-class SurfaceComposerFuzzer {
-public:
- SurfaceComposerFuzzer(const uint8_t* data, size_t size) : mFdp(data, size){};
- void process();
-
-private:
- FuzzedDataProvider mFdp;
-};
-
-void SurfaceComposerFuzzer::process() {
- sp<FakeBnSurfaceComposer> composer(new FakeBnSurfaceComposer());
- fuzzService(composer.get(), std::move(mFdp));
-}
-
-extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
- SurfaceComposerFuzzer surfaceComposerFuzzer(data, size);
- surfaceComposerFuzzer.process();
- return 0;
-}
diff --git a/libs/gui/include/gui/Choreographer.h b/libs/gui/include/gui/Choreographer.h
index 9fef512b64..fc79b03c23 100644
--- a/libs/gui/include/gui/Choreographer.h
+++ b/libs/gui/include/gui/Choreographer.h
@@ -28,12 +28,18 @@
namespace android {
using gui::VsyncEventData;
+enum CallbackType : int8_t {
+ CALLBACK_INPUT,
+ CALLBACK_ANIMATION,
+};
+
struct FrameCallback {
AChoreographer_frameCallback callback;
AChoreographer_frameCallback64 callback64;
AChoreographer_vsyncCallback vsyncCallback;
void* data;
nsecs_t dueTime;
+ CallbackType callbackType;
inline bool operator<(const FrameCallback& rhs) const {
// Note that this is intentionally flipped because we want callbacks due sooner to be at
@@ -78,7 +84,7 @@ public:
void postFrameCallbackDelayed(AChoreographer_frameCallback cb,
AChoreographer_frameCallback64 cb64,
AChoreographer_vsyncCallback vsyncCallback, void* data,
- nsecs_t delay);
+ nsecs_t delay, CallbackType callbackType);
void registerRefreshRateCallback(AChoreographer_refreshRateCallback cb, void* data)
EXCLUDES(gChoreographers.lock);
void unregisterRefreshRateCallback(AChoreographer_refreshRateCallback cb, void* data);
@@ -109,6 +115,8 @@ private:
void dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId, uint32_t count,
VsyncEventData vsyncEventData) override;
+ void dispatchCallbacks(const std::vector<FrameCallback>&, VsyncEventData vsyncEventData,
+ nsecs_t timestamp);
void dispatchHotplug(nsecs_t timestamp, PhysicalDisplayId displayId, bool connected) override;
void dispatchHotplugConnectionError(nsecs_t timestamp, int32_t connectionError) override;
void dispatchModeChanged(nsecs_t timestamp, PhysicalDisplayId displayId, int32_t modeId,
@@ -116,6 +124,8 @@ private:
void dispatchNullEvent(nsecs_t, PhysicalDisplayId) override;
void dispatchFrameRateOverrides(nsecs_t timestamp, PhysicalDisplayId displayId,
std::vector<FrameRateOverride> overrides) override;
+ void dispatchHdcpLevelsChanged(PhysicalDisplayId displayId, int32_t connectedLevel,
+ int32_t maxLevel) override;
void scheduleCallbacks();
diff --git a/libs/gui/include/gui/DisplayEventDispatcher.h b/libs/gui/include/gui/DisplayEventDispatcher.h
index fe2dd206ed..82cd50c7bd 100644
--- a/libs/gui/include/gui/DisplayEventDispatcher.h
+++ b/libs/gui/include/gui/DisplayEventDispatcher.h
@@ -65,6 +65,9 @@ private:
virtual void dispatchFrameRateOverrides(nsecs_t timestamp, PhysicalDisplayId displayId,
std::vector<FrameRateOverride> overrides) = 0;
+ virtual void dispatchHdcpLevelsChanged(PhysicalDisplayId displayId, int32_t connectedLevel,
+ int32_t maxLevel) = 0;
+
bool processPendingEvents(nsecs_t* outTimestamp, PhysicalDisplayId* outDisplayId,
uint32_t* outCount, VsyncEventData* outVsyncEventData);
diff --git a/libs/gui/include/gui/DisplayEventReceiver.h b/libs/gui/include/gui/DisplayEventReceiver.h
index 79582ce685..8c1103bfc2 100644
--- a/libs/gui/include/gui/DisplayEventReceiver.h
+++ b/libs/gui/include/gui/DisplayEventReceiver.h
@@ -58,7 +58,6 @@ static inline constexpr uint32_t fourcc(char c1, char c2, char c3, char c4) {
// ----------------------------------------------------------------------------
class DisplayEventReceiver {
public:
-
enum {
DISPLAY_EVENT_VSYNC = fourcc('v', 's', 'y', 'n'),
DISPLAY_EVENT_HOTPLUG = fourcc('p', 'l', 'u', 'g'),
@@ -66,6 +65,7 @@ public:
DISPLAY_EVENT_NULL = fourcc('n', 'u', 'l', 'l'),
DISPLAY_EVENT_FRAME_RATE_OVERRIDE = fourcc('r', 'a', 't', 'e'),
DISPLAY_EVENT_FRAME_RATE_OVERRIDE_FLUSH = fourcc('f', 'l', 's', 'h'),
+ DISPLAY_EVENT_HDCP_LEVELS_CHANGE = fourcc('h', 'd', 'c', 'p'),
};
struct Event {
@@ -101,12 +101,22 @@ public:
float frameRateHz __attribute__((aligned(8)));
};
+ /*
+ * The values are defined in aidl:
+ * hardware/interfaces/drm/aidl/android/hardware/drm/HdcpLevel.aidl
+ */
+ struct HdcpLevelsChange {
+ int32_t connectedLevel;
+ int32_t maxLevel;
+ };
+
Header header;
union {
VSync vsync;
Hotplug hotplug;
ModeChange modeChange;
FrameRateOverride frameRateOverride;
+ HdcpLevelsChange hdcpLevelsChange;
};
};
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index e1dc7911a1..0fedea7b9e 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -161,6 +161,9 @@ struct layer_state_t {
// See SurfaceView scaling behavior for more details.
eIgnoreDestinationFrame = 0x400,
eLayerIsRefreshRateIndicator = 0x800, // REFRESH_RATE_INDICATOR
+ // Sets a property on this layer indicating that its visible region should be considered
+ // when computing TrustedPresentation Thresholds.
+ eCanOccludePresentation = 0x1000,
};
enum {
@@ -206,7 +209,7 @@ struct layer_state_t {
eBackgroundBlurRadiusChanged = 0x80'00000000,
eProducerDisconnect = 0x100'00000000,
eFixedTransformHintChanged = 0x200'00000000,
- /* unused 0x400'00000000, */
+ eDesiredHdrHeadroomChanged = 0x400'00000000,
eBlurRegionsChanged = 0x800'00000000,
eAutoRefreshChanged = 0x1000'00000000,
eStretchChanged = 0x2000'00000000,
@@ -245,7 +248,8 @@ struct layer_state_t {
layer_state_t::eSidebandStreamChanged | layer_state_t::eSurfaceDamageRegionChanged |
layer_state_t::eTransformToDisplayInverseChanged |
layer_state_t::eTransparentRegionChanged |
- layer_state_t::eExtendedRangeBrightnessChanged;
+ layer_state_t::eExtendedRangeBrightnessChanged |
+ layer_state_t::eDesiredHdrHeadroomChanged;
// Content updates.
static constexpr uint64_t CONTENT_CHANGES = layer_state_t::BUFFER_CHANGES |
@@ -416,26 +420,36 @@ public:
};
struct DisplayState {
- enum {
+ enum : uint32_t {
eSurfaceChanged = 0x01,
eLayerStackChanged = 0x02,
eDisplayProjectionChanged = 0x04,
eDisplaySizeChanged = 0x08,
- eFlagsChanged = 0x10
+ eFlagsChanged = 0x10,
+
+ eAllChanged = ~0u
};
+ // Not for direct use. Prefer constructor below for new displays.
DisplayState();
+
+ DisplayState(sp<IBinder> token, ui::LayerStack layerStack)
+ : what(eAllChanged),
+ token(std::move(token)),
+ layerStack(layerStack),
+ layerStackSpaceRect(Rect::INVALID_RECT),
+ orientedDisplaySpaceRect(Rect::INVALID_RECT) {}
+
void merge(const DisplayState& other);
void sanitize(int32_t permissions);
uint32_t what = 0;
uint32_t flags = 0;
sp<IBinder> token;
- sp<IGraphicBufferProducer> surface;
ui::LayerStack layerStack = ui::DEFAULT_LAYER_STACK;
- // These states define how layers are projected onto the physical display.
+ // These states define how layers are projected onto the physical or virtual display.
//
// Layers are first clipped to `layerStackSpaceRect'. They are then translated and
// scaled from `layerStackSpaceRect' to `orientedDisplaySpaceRect'. Finally, they are rotated
@@ -446,10 +460,17 @@ struct DisplayState {
// will be scaled by a factor of 2 and translated by (20, 10). When orientation is 1, layers
// will be additionally rotated by 90 degrees around the origin clockwise and translated by (W,
// 0).
+ //
+ // Rect::INVALID_RECT sizes the space to the active resolution of the physical display, or the
+ // default dimensions of the virtual display surface.
+ //
ui::Rotation orientation = ui::ROTATION_0;
Rect layerStackSpaceRect = Rect::EMPTY_RECT;
Rect orientedDisplaySpaceRect = Rect::EMPTY_RECT;
+ // Exclusive to virtual displays: The sink surface into which the virtual display is rendered,
+ // and an optional resolution that overrides its default dimensions.
+ sp<IGraphicBufferProducer> surface;
uint32_t width = 0;
uint32_t height = 0;
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 14e3dd583e..288882695a 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -594,6 +594,7 @@ public:
Transaction& setDataspace(const sp<SurfaceControl>& sc, ui::Dataspace dataspace);
Transaction& setExtendedRangeBrightness(const sp<SurfaceControl>& sc,
float currentBufferRatio, float desiredRatio);
+ Transaction& setDesiredHdrHeadroom(const sp<SurfaceControl>& sc, float desiredRatio);
Transaction& setCachingHint(const sp<SurfaceControl>& sc, gui::CachingHint cachingHint);
Transaction& setHdrMetadata(const sp<SurfaceControl>& sc, const HdrMetadata& hdrMetadata);
Transaction& setSurfaceDamageRegion(const sp<SurfaceControl>& sc,
@@ -849,7 +850,8 @@ public:
static status_t captureDisplay(const DisplayCaptureArgs&, const sp<IScreenCaptureListener>&);
static status_t captureDisplay(DisplayId, const gui::CaptureArgs&,
const sp<IScreenCaptureListener>&);
- static status_t captureLayers(const LayerCaptureArgs&, const sp<IScreenCaptureListener>&);
+ static status_t captureLayers(const LayerCaptureArgs&, const sp<IScreenCaptureListener>&,
+ bool sync);
[[deprecated]] static status_t captureDisplay(DisplayId id,
const sp<IScreenCaptureListener>& listener) {
diff --git a/libs/gui/include/gui/WindowInfo.h b/libs/gui/include/gui/WindowInfo.h
index 4d4c5e4394..32d60be612 100644
--- a/libs/gui/include/gui/WindowInfo.h
+++ b/libs/gui/include/gui/WindowInfo.h
@@ -176,6 +176,8 @@ struct WindowInfo : public Parcelable {
static_cast<uint32_t>(os::InputConfig::INTERCEPTS_STYLUS),
CLONE =
static_cast<uint32_t>(os::InputConfig::CLONE),
+ GLOBAL_STYLUS_BLOCKS_TOUCH =
+ static_cast<uint32_t>(os::InputConfig::GLOBAL_STYLUS_BLOCKS_TOUCH),
// clang-format on
};
@@ -244,6 +246,10 @@ struct WindowInfo : public Parcelable {
// any other window.
sp<IBinder> focusTransferTarget;
+ // Sets a property on this window indicating that its visible region should be considered when
+ // computing TrustedPresentation Thresholds.
+ bool canOccludePresentation = false;
+
void setInputConfig(ftl::Flags<InputConfig> config, bool value);
void addTouchableRegion(const Rect& region);
@@ -267,6 +273,8 @@ struct WindowInfo : public Parcelable {
status_t readFromParcel(const android::Parcel* parcel) override;
};
+std::ostream& operator<<(std::ostream& out, const WindowInfo& window);
+
/*
* Handle for a window that can receive input.
*
diff --git a/libs/gui/libgui_flags.aconfig b/libs/gui/libgui_flags.aconfig
index b081030c9f..38646992da 100644
--- a/libs/gui/libgui_flags.aconfig
+++ b/libs/gui/libgui_flags.aconfig
@@ -1,4 +1,5 @@
package: "com.android.graphics.libgui.flags"
+container: "system"
flag {
name: "bq_setframerate"
diff --git a/libs/gui/sysprop/Android.bp b/libs/gui/sysprop/Android.bp
index cc33e4c27d..386767ba9e 100644
--- a/libs/gui/sysprop/Android.bp
+++ b/libs/gui/sysprop/Android.bp
@@ -5,6 +5,7 @@ package {
// to get the below license kinds:
// SPDX-license-identifier-Apache-2.0
default_applicable_licenses: ["frameworks_native_license"],
+ default_team: "trendy_team_android_core_graphics_stack",
}
sysprop_library {
diff --git a/libs/gui/tests/Android.bp b/libs/gui/tests/Android.bp
index e606b9941e..0f16f714dc 100644
--- a/libs/gui/tests/Android.bp
+++ b/libs/gui/tests/Android.bp
@@ -30,6 +30,7 @@ cc_test {
"BLASTBufferQueue_test.cpp",
"BufferItemConsumer_test.cpp",
"BufferQueue_test.cpp",
+ "Choreographer_test.cpp",
"CompositorTiming_test.cpp",
"CpuConsumer_test.cpp",
"EndToEndNativeInputTest.cpp",
@@ -61,6 +62,7 @@ cc_test {
"libSurfaceFlingerProp",
"libGLESv1_CM",
"libinput",
+ "libnativedisplay",
],
static_libs: [
diff --git a/libs/gui/tests/Choreographer_test.cpp b/libs/gui/tests/Choreographer_test.cpp
new file mode 100644
index 0000000000..2ac2550f07
--- /dev/null
+++ b/libs/gui/tests/Choreographer_test.cpp
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2024 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 LOG_TAG "Choreographer_test"
+
+#include <android-base/stringprintf.h>
+#include <android/choreographer.h>
+#include <gtest/gtest.h>
+#include <gui/Choreographer.h>
+#include <utils/Looper.h>
+#include <chrono>
+#include <future>
+#include <string>
+
+namespace android {
+class ChoreographerTest : public ::testing::Test {};
+
+struct VsyncCallback {
+ std::atomic<bool> completePromise{false};
+ std::chrono::nanoseconds frameTime{0LL};
+ std::chrono::nanoseconds receivedCallbackTime{0LL};
+
+ void onVsyncCallback(const AChoreographerFrameCallbackData* callbackData) {
+ frameTime = std::chrono::nanoseconds{
+ AChoreographerFrameCallbackData_getFrameTimeNanos(callbackData)};
+ receivedCallbackTime = std::chrono::nanoseconds{systemTime(SYSTEM_TIME_MONOTONIC)};
+ completePromise.store(true);
+ }
+
+ bool callbackReceived() { return completePromise.load(); }
+};
+
+static void vsyncCallback(const AChoreographerFrameCallbackData* callbackData, void* data) {
+ VsyncCallback* cb = static_cast<VsyncCallback*>(data);
+ cb->onVsyncCallback(callbackData);
+}
+
+TEST_F(ChoreographerTest, InputCallbackBeforeAnimation) {
+ sp<Looper> looper = Looper::prepare(0);
+ Choreographer* choreographer = Choreographer::getForThread();
+ VsyncCallback animationCb;
+ VsyncCallback inputCb;
+
+ choreographer->postFrameCallbackDelayed(nullptr, nullptr, vsyncCallback, &animationCb, 0,
+ CALLBACK_ANIMATION);
+ choreographer->postFrameCallbackDelayed(nullptr, nullptr, vsyncCallback, &inputCb, 0,
+ CALLBACK_INPUT);
+
+ nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t currTime;
+ int pollResult;
+ do {
+ pollResult = looper->pollOnce(16);
+ currTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ } while (!(inputCb.callbackReceived() && animationCb.callbackReceived()) &&
+ (pollResult != Looper::POLL_TIMEOUT && pollResult != Looper::POLL_ERROR) &&
+ (currTime - startTime < 3000));
+
+ ASSERT_TRUE(inputCb.callbackReceived()) << "did not receive input callback";
+ ASSERT_TRUE(animationCb.callbackReceived()) << "did not receive animation callback";
+
+ ASSERT_EQ(inputCb.frameTime, animationCb.frameTime)
+ << android::base::StringPrintf("input and animation callback frame times don't match. "
+ "inputFrameTime=%lld animationFrameTime=%lld",
+ inputCb.frameTime.count(),
+ animationCb.frameTime.count());
+
+ ASSERT_LT(inputCb.receivedCallbackTime, animationCb.receivedCallbackTime)
+ << android::base::StringPrintf("input callback was not called first. "
+ "inputCallbackTime=%lld animationCallbackTime=%lld",
+ inputCb.frameTime.count(),
+ animationCb.frameTime.count());
+}
+
+} // namespace android \ No newline at end of file
diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp
index d4b8dbeeb9..a9d6e8d3bf 100644
--- a/libs/gui/tests/EndToEndNativeInputTest.cpp
+++ b/libs/gui/tests/EndToEndNativeInputTest.cpp
@@ -63,8 +63,7 @@ namespace android::test {
using Transaction = SurfaceComposerClient::Transaction;
sp<IInputFlinger> getInputFlinger() {
- sp<IBinder> input(defaultServiceManager()->getService(
- String16("inputflinger")));
+ sp<IBinder> input(defaultServiceManager()->waitForService(String16("inputflinger")));
if (input == nullptr) {
ALOGE("Failed to link to input service");
} else { ALOGE("Linked to input"); }
@@ -104,8 +103,13 @@ public:
if (noInputChannel) {
mInputInfo.setInputConfig(WindowInfo::InputConfig::NO_INPUT_CHANNEL, true);
} else {
- mClientChannel = std::make_shared<InputChannel>();
- mInputFlinger->createInputChannel("testchannels", mClientChannel.get());
+ android::os::InputChannelCore tempChannel;
+ android::binder::Status result =
+ mInputFlinger->createInputChannel("testchannels", &tempChannel);
+ if (!result.isOk()) {
+ ADD_FAILURE() << "binder call to createInputChannel failed";
+ }
+ mClientChannel = InputChannel::create(std::move(tempChannel));
mInputInfo.token = mClientChannel->getConnectionToken();
mInputConsumer = new InputConsumer(mClientChannel);
}
@@ -168,8 +172,8 @@ public:
return std::make_unique<InputSurface>(surfaceControl, width, height);
}
- InputEvent *consumeEvent(int timeoutMs = 3000) {
- waitForEventAvailable(timeoutMs);
+ InputEvent* consumeEvent(std::chrono::milliseconds timeout = 3000ms) {
+ mClientChannel->waitForMessage(timeout);
InputEvent *ev;
uint32_t seqId;
@@ -302,15 +306,6 @@ public:
t.apply(true);
}
-private:
- void waitForEventAvailable(int timeoutMs) {
- struct pollfd fd;
-
- fd.fd = mClientChannel->getFd();
- fd.events = POLLIN;
- poll(&fd, 1, timeoutMs);
- }
-
public:
sp<SurfaceControl> mSurfaceControl;
std::shared_ptr<InputChannel> mClientChannel;
@@ -615,7 +610,7 @@ TEST_F(InputSurfacesTest, touchable_region) {
// A tap within the surface but outside the touchable region should not be sent to the surface.
injectTap(20, 30);
- EXPECT_EQ(surface->consumeEvent(200 /*timeoutMs*/), nullptr);
+ EXPECT_EQ(surface->consumeEvent(/*timeout=*/200ms), nullptr);
injectTap(31, 52);
surface->expectTap(20, 30);
@@ -981,12 +976,12 @@ TEST_F(InputSurfacesTest, strict_unobscured_input_obscured_window) {
obscuringSurface->mInputInfo.ownerUid = gui::Uid{22222};
obscuringSurface->showAt(100, 100);
injectTap(101, 101);
- EXPECT_EQ(surface->consumeEvent(100), nullptr);
+ EXPECT_EQ(surface->consumeEvent(/*timeout=*/100ms), nullptr);
surface->requestFocus();
surface->assertFocusChange(true);
injectKey(AKEYCODE_V);
- EXPECT_EQ(surface->consumeEvent(100), nullptr);
+ EXPECT_EQ(surface->consumeEvent(/*timeout=*/100ms), nullptr);
}
TEST_F(InputSurfacesTest, strict_unobscured_input_partially_obscured_window) {
@@ -1002,12 +997,12 @@ TEST_F(InputSurfacesTest, strict_unobscured_input_partially_obscured_window) {
injectTap(101, 101);
- EXPECT_EQ(surface->consumeEvent(100), nullptr);
+ EXPECT_EQ(surface->consumeEvent(/*timeout=*/100ms), nullptr);
surface->requestFocus();
surface->assertFocusChange(true);
injectKey(AKEYCODE_V);
- EXPECT_EQ(surface->consumeEvent(100), nullptr);
+ EXPECT_EQ(surface->consumeEvent(/*timeout=*/100ms), nullptr);
}
TEST_F(InputSurfacesTest, strict_unobscured_input_alpha_window) {
@@ -1024,12 +1019,12 @@ TEST_F(InputSurfacesTest, strict_unobscured_input_alpha_window) {
injectTap(101, 101);
- EXPECT_EQ(surface->consumeEvent(100), nullptr);
+ EXPECT_EQ(surface->consumeEvent(/*timeout=*/100ms), nullptr);
surface->requestFocus();
surface->assertFocusChange(true);
injectKey(AKEYCODE_V);
- EXPECT_EQ(surface->consumeEvent(100), nullptr);
+ EXPECT_EQ(surface->consumeEvent(/*timeout=*/100ms), nullptr);
}
TEST_F(InputSurfacesTest, strict_unobscured_input_cropped_window) {
@@ -1046,12 +1041,12 @@ TEST_F(InputSurfacesTest, strict_unobscured_input_cropped_window) {
injectTap(111, 111);
- EXPECT_EQ(surface->consumeEvent(100), nullptr);
+ EXPECT_EQ(surface->consumeEvent(/*timeout=*/100ms), nullptr);
surface->requestFocus();
surface->assertFocusChange(true);
injectKey(AKEYCODE_V);
- EXPECT_EQ(surface->consumeEvent(100), nullptr);
+ EXPECT_EQ(surface->consumeEvent(/*timeout=*/100ms), nullptr);
}
TEST_F(InputSurfacesTest, ignore_touch_region_with_zero_sized_blast) {
@@ -1076,12 +1071,12 @@ TEST_F(InputSurfacesTest, drop_input_policy) {
injectTap(101, 101);
- EXPECT_EQ(surface->consumeEvent(100), nullptr);
+ EXPECT_EQ(surface->consumeEvent(/*timeout=*/100ms), nullptr);
surface->requestFocus();
surface->assertFocusChange(true);
injectKey(AKEYCODE_V);
- EXPECT_EQ(surface->consumeEvent(100), nullptr);
+ EXPECT_EQ(surface->consumeEvent(/*timeout=*/100ms), nullptr);
}
TEST_F(InputSurfacesTest, layer_with_valid_crop_can_be_focused) {
@@ -1116,7 +1111,7 @@ TEST_F(InputSurfacesTest, cropped_container_replaces_touchable_region_with_null_
// Does not receive events outside its crop
injectTap(26, 26);
- EXPECT_EQ(containerSurface->consumeEvent(100), nullptr);
+ EXPECT_EQ(containerSurface->consumeEvent(/*timeout=*/100ms), nullptr);
}
/**
@@ -1141,7 +1136,7 @@ TEST_F(InputSurfacesTest, uncropped_container_replaces_touchable_region_with_nul
// Does not receive events outside parent bounds
injectTap(31, 31);
- EXPECT_EQ(containerSurface->consumeEvent(100), nullptr);
+ EXPECT_EQ(containerSurface->consumeEvent(/*timeout=*/100ms), nullptr);
}
/**
@@ -1167,7 +1162,7 @@ TEST_F(InputSurfacesTest, replace_touchable_region_with_crop) {
// Does not receive events outside crop layer bounds
injectTap(21, 21);
injectTap(71, 71);
- EXPECT_EQ(containerSurface->consumeEvent(100), nullptr);
+ EXPECT_EQ(containerSurface->consumeEvent(/*timeout=*/100ms), nullptr);
}
TEST_F(InputSurfacesTest, child_container_with_no_input_channel_blocks_parent) {
@@ -1184,7 +1179,7 @@ TEST_F(InputSurfacesTest, child_container_with_no_input_channel_blocks_parent) {
[&](auto &t, auto &sc) { t.reparent(sc, parent->mSurfaceControl); });
injectTap(101, 101);
- EXPECT_EQ(parent->consumeEvent(100), nullptr);
+ EXPECT_EQ(parent->consumeEvent(/*timeout=*/100ms), nullptr);
}
class MultiDisplayTests : public InputSurfacesTest {
@@ -1233,7 +1228,7 @@ TEST_F(MultiDisplayTests, drop_touch_if_layer_on_invalid_display) {
// Touches should be dropped if the layer is on an invalid display.
injectTapOnDisplay(101, 101, layerStack.id);
- EXPECT_EQ(surface->consumeEvent(100), nullptr);
+ EXPECT_EQ(surface->consumeEvent(/*timeout=*/100ms), nullptr);
// However, we still let the window be focused and receive keys.
surface->requestFocus(layerStack.id);
@@ -1271,12 +1266,12 @@ TEST_F(MultiDisplayTests, drop_input_for_secure_layer_on_nonsecure_display) {
injectTapOnDisplay(101, 101, layerStack.id);
- EXPECT_EQ(surface->consumeEvent(100), nullptr);
+ EXPECT_EQ(surface->consumeEvent(/*timeout=*/100ms), nullptr);
surface->requestFocus(layerStack.id);
surface->assertFocusChange(true);
injectKeyOnDisplay(AKEYCODE_V, layerStack.id);
- EXPECT_EQ(surface->consumeEvent(100), nullptr);
+ EXPECT_EQ(surface->consumeEvent(/*timeout=*/100ms), nullptr);
}
TEST_F(MultiDisplayTests, dont_drop_input_for_secure_layer_on_secure_display) {
diff --git a/libs/gui/tests/FrameRateUtilsTest.cpp b/libs/gui/tests/FrameRateUtilsTest.cpp
index 5fe22b05f9..04bfb28f65 100644
--- a/libs/gui/tests/FrameRateUtilsTest.cpp
+++ b/libs/gui/tests/FrameRateUtilsTest.cpp
@@ -34,6 +34,8 @@ TEST(FrameRateUtilsTest, ValidateFrameRate) {
ANATIVEWINDOW_CHANGE_FRAME_RATE_ALWAYS, ""));
EXPECT_TRUE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE,
ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, ""));
+ EXPECT_TRUE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_GTE,
+ ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, ""));
// Privileged APIs.
EXPECT_FALSE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_EXACT,
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index c6ea317949..577d2394c6 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -791,6 +791,10 @@ public:
return binder::Status::ok();
}
+ binder::Status captureLayersSync(const LayerCaptureArgs&, ScreenCaptureResults*) override {
+ return binder::Status::ok();
+ }
+
binder::Status captureLayers(const LayerCaptureArgs&,
const sp<IScreenCaptureListener>&) override {
return binder::Status::ok();
diff --git a/libs/input/AccelerationCurve.cpp b/libs/input/AccelerationCurve.cpp
new file mode 100644
index 0000000000..0a92a71596
--- /dev/null
+++ b/libs/input/AccelerationCurve.cpp
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2024 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 <input/AccelerationCurve.h>
+
+#include <array>
+#include <limits>
+
+#include <log/log_main.h>
+
+#define LOG_TAG "AccelerationCurve"
+
+namespace android {
+
+namespace {
+
+// The last segment must have an infinite maximum speed, so that all speeds are covered.
+constexpr std::array<AccelerationCurveSegment, 4> kSegments = {{
+ {32.002, 3.19, 0},
+ {52.83, 4.79, -51.254},
+ {119.124, 7.28, -182.737},
+ {std::numeric_limits<double>::infinity(), 15.04, -1107.556},
+}};
+
+static_assert(kSegments.back().maxPointerSpeedMmPerS == std::numeric_limits<double>::infinity());
+
+constexpr std::array<double, 15> kSensitivityFactors = {1, 2, 4, 6, 7, 8, 9, 10,
+ 11, 12, 13, 14, 16, 18, 20};
+
+} // namespace
+
+std::vector<AccelerationCurveSegment> createAccelerationCurveForPointerSensitivity(
+ int32_t sensitivity) {
+ LOG_ALWAYS_FATAL_IF(sensitivity < -7 || sensitivity > 7, "Invalid pointer sensitivity value");
+ std::vector<AccelerationCurveSegment> output;
+ output.reserve(kSegments.size());
+
+ // The curves we want to produce for different sensitivity values are actually the same curve,
+ // just scaled in the Y (gain) axis by a sensitivity factor and a couple of constants.
+ double commonFactor = 0.64 * kSensitivityFactors[sensitivity + 7] / 10;
+ for (AccelerationCurveSegment seg : kSegments) {
+ output.push_back(AccelerationCurveSegment{seg.maxPointerSpeedMmPerS,
+ commonFactor * seg.baseGain,
+ commonFactor * seg.reciprocal});
+ }
+
+ return output;
+}
+
+} // namespace android \ No newline at end of file
diff --git a/libs/input/Android.bp b/libs/input/Android.bp
index 252040d1b0..6b8bc01c24 100644
--- a/libs/input/Android.bp
+++ b/libs/input/Android.bp
@@ -39,6 +39,7 @@ filegroup {
aconfig_declarations {
name: "com.android.input.flags-aconfig",
package: "com.android.input.flags",
+ container: "system",
srcs: ["input_flags.aconfig"],
}
@@ -134,6 +135,29 @@ rust_bindgen {
],
}
+cc_library_static {
+ name: "iinputflinger_aidl_lib_static",
+ host_supported: true,
+ srcs: [
+ "android/os/IInputFlinger.aidl",
+ "android/os/InputChannelCore.aidl",
+ ],
+ shared_libs: [
+ "libbinder",
+ ],
+ whole_static_libs: [
+ "libgui_window_info_static",
+ ],
+ aidl: {
+ export_aidl_headers: true,
+ local_include_dirs: ["."],
+ include_dirs: [
+ "frameworks/native/libs/gui",
+ "frameworks/native/libs/input",
+ ],
+ },
+}
+
// Contains methods to help access C++ code from rust
cc_library_static {
name: "libinput_from_rust_to_cpp",
@@ -178,7 +202,7 @@ cc_library {
"-DANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION",
],
srcs: [
- "android/os/IInputFlinger.aidl",
+ "AccelerationCurve.cpp",
"Input.cpp",
"InputDevice.cpp",
"InputEventLabels.cpp",
@@ -240,7 +264,6 @@ cc_library {
static_libs: [
"inputconstants-cpp",
- "libgui_window_info_static",
"libui-types",
"libtflite_static",
"libkernelconfigs",
@@ -249,10 +272,10 @@ cc_library {
whole_static_libs: [
"com.android.input.flags-aconfig-cc",
"libinput_rust_ffi",
+ "iinputflinger_aidl_lib_static",
],
export_static_lib_headers: [
- "libgui_window_info_static",
"libui-types",
],
@@ -286,14 +309,6 @@ cc_library {
],
},
},
-
- aidl: {
- local_include_dirs: ["."],
- export_aidl_headers: true,
- include_dirs: [
- "frameworks/native/libs/gui",
- ],
- },
}
// Use bootstrap version of stats logging library.
diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp
index bd5b67b1d0..61a964ece9 100644
--- a/libs/input/Input.cpp
+++ b/libs/input/Input.cpp
@@ -60,6 +60,45 @@ bool shouldDisregardOffset(uint32_t source) {
return !isFromSource(source, AINPUT_SOURCE_CLASS_POINTER);
}
+int32_t resolveActionForSplitMotionEvent(
+ int32_t action, int32_t flags, const std::vector<PointerProperties>& pointerProperties,
+ const std::vector<PointerProperties>& splitPointerProperties) {
+ LOG_ALWAYS_FATAL_IF(splitPointerProperties.empty());
+ const auto maskedAction = MotionEvent::getActionMasked(action);
+ if (maskedAction != AMOTION_EVENT_ACTION_POINTER_DOWN &&
+ maskedAction != AMOTION_EVENT_ACTION_POINTER_UP) {
+ // The action is unaffected by splitting this motion event.
+ return action;
+ }
+ const auto actionIndex = MotionEvent::getActionIndex(action);
+ if (CC_UNLIKELY(actionIndex >= pointerProperties.size())) {
+ LOG(FATAL) << "Action index is out of bounds, index: " << actionIndex;
+ }
+
+ const auto affectedPointerId = pointerProperties[actionIndex].id;
+ std::optional<uint32_t> splitActionIndex;
+ for (uint32_t i = 0; i < splitPointerProperties.size(); i++) {
+ if (affectedPointerId == splitPointerProperties[i].id) {
+ splitActionIndex = i;
+ break;
+ }
+ }
+ if (!splitActionIndex.has_value()) {
+ // The affected pointer is not part of the split motion event.
+ return AMOTION_EVENT_ACTION_MOVE;
+ }
+
+ if (splitPointerProperties.size() > 1) {
+ return maskedAction | (*splitActionIndex << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
+ }
+
+ if (maskedAction == AMOTION_EVENT_ACTION_POINTER_UP) {
+ return ((flags & AMOTION_EVENT_FLAG_CANCELED) != 0) ? AMOTION_EVENT_ACTION_CANCEL
+ : AMOTION_EVENT_ACTION_UP;
+ }
+ return AMOTION_EVENT_ACTION_DOWN;
+}
+
} // namespace
const char* motionClassificationToString(MotionClassification classification) {
@@ -374,11 +413,16 @@ std::ostream& operator<<(std::ostream& out, const KeyEvent& event) {
out << ", deviceId=" << event.getDeviceId();
out << ", source=" << inputEventSourceToString(event.getSource());
out << ", displayId=" << event.getDisplayId();
- out << ", eventId=" << event.getId();
+ out << ", eventId=0x" << std::hex << event.getId() << std::dec;
out << "}";
return out;
}
+std::ostream& operator<<(std::ostream& out, const PointerProperties& properties) {
+ out << "Pointer(id=" << properties.id << ", " << ftl::enum_string(properties.toolType) << ")";
+ return out;
+}
+
// --- PointerCoords ---
float PointerCoords::getAxisValue(int32_t axis) const {
@@ -579,6 +623,28 @@ void MotionEvent::copyFrom(const MotionEvent* other, bool keepHistory) {
}
}
+void MotionEvent::splitFrom(const android::MotionEvent& other,
+ std::bitset<MAX_POINTER_ID + 1> splitPointerIds, int32_t newEventId) {
+ // TODO(b/327503168): The down time should be a parameter to the split function, because only
+ // the caller can know when the first event went down on the target.
+ const nsecs_t splitDownTime = other.mDownTime;
+
+ auto [action, pointerProperties, pointerCoords] =
+ split(other.getAction(), other.getFlags(), other.getHistorySize(),
+ other.mPointerProperties, other.mSamplePointerCoords, splitPointerIds);
+
+ // Initialize the event with zero pointers, and manually set the split pointers.
+ initialize(newEventId, other.mDeviceId, other.mSource, other.mDisplayId, /*hmac=*/{}, action,
+ other.mActionButton, other.mFlags, other.mEdgeFlags, other.mMetaState,
+ other.mButtonState, other.mClassification, other.mTransform, other.mXPrecision,
+ other.mYPrecision, other.mRawXCursorPosition, other.mRawYCursorPosition,
+ other.mRawTransform, splitDownTime, other.getEventTime(), /*pointerCount=*/0,
+ pointerProperties.data(), pointerCoords.data());
+ mPointerProperties = std::move(pointerProperties);
+ mSamplePointerCoords = std::move(pointerCoords);
+ mSampleEventTimes = other.mSampleEventTimes;
+}
+
void MotionEvent::addSample(
int64_t eventTime,
const PointerCoords* pointerCoords) {
@@ -685,6 +751,18 @@ void MotionEvent::offsetLocation(float xOffset, float yOffset) {
mTransform.set(currXOffset + xOffset, currYOffset + yOffset);
}
+float MotionEvent::getRawXOffset() const {
+ // This is equivalent to the x-coordinate of the point that the origin of the raw coordinate
+ // space maps to.
+ return (mTransform * mRawTransform.inverse()).tx();
+}
+
+float MotionEvent::getRawYOffset() const {
+ // This is equivalent to the y-coordinate of the point that the origin of the raw coordinate
+ // space maps to.
+ return (mTransform * mRawTransform.inverse()).ty();
+}
+
void MotionEvent::scale(float globalScaleFactor) {
mTransform.set(mTransform.tx() * globalScaleFactor, mTransform.ty() * globalScaleFactor);
mRawTransform.set(mRawTransform.tx() * globalScaleFactor,
@@ -929,6 +1007,46 @@ std::string MotionEvent::actionToString(int32_t action) {
return android::base::StringPrintf("%" PRId32, action);
}
+std::tuple<int32_t, std::vector<PointerProperties>, std::vector<PointerCoords>> MotionEvent::split(
+ int32_t action, int32_t flags, int32_t historySize,
+ const std::vector<PointerProperties>& pointerProperties,
+ const std::vector<PointerCoords>& pointerCoords,
+ std::bitset<MAX_POINTER_ID + 1> splitPointerIds) {
+ LOG_ALWAYS_FATAL_IF(!splitPointerIds.any());
+ const auto pointerCount = pointerProperties.size();
+ LOG_ALWAYS_FATAL_IF(pointerCoords.size() != (pointerCount * (historySize + 1)));
+ const auto splitCount = splitPointerIds.count();
+
+ std::vector<PointerProperties> splitPointerProperties;
+ std::vector<PointerCoords> splitPointerCoords;
+
+ for (uint32_t i = 0; i < pointerCount; i++) {
+ if (splitPointerIds.test(pointerProperties[i].id)) {
+ splitPointerProperties.emplace_back(pointerProperties[i]);
+ }
+ }
+ for (uint32_t i = 0; i < pointerCoords.size(); i++) {
+ if (splitPointerIds.test(pointerProperties[i % pointerCount].id)) {
+ splitPointerCoords.emplace_back(pointerCoords[i]);
+ }
+ }
+ LOG_ALWAYS_FATAL_IF(splitPointerCoords.size() !=
+ (splitPointerProperties.size() * (historySize + 1)));
+
+ if (CC_UNLIKELY(splitPointerProperties.size() != splitCount)) {
+ // TODO(b/329107108): Promote this to a fatal check once bugs in the caller are resolved.
+ LOG(ERROR) << "Cannot split MotionEvent: Requested splitting " << splitCount
+ << " pointers from the original event, but the original event only contained "
+ << splitPointerProperties.size() << " of those pointers.";
+ }
+
+ // TODO(b/327503168): Verify the splitDownTime here once it is used correctly.
+
+ const auto splitAction = resolveActionForSplitMotionEvent(action, flags, pointerProperties,
+ splitPointerProperties);
+ return {splitAction, splitPointerProperties, splitPointerCoords};
+}
+
// Apply the given transformation to the point without checking whether the entire transform
// should be disregarded altogether for the provided source.
static inline vec2 calculateTransformedXYUnchecked(uint32_t source, const ui::Transform& transform,
@@ -1002,6 +1120,33 @@ PointerCoords MotionEvent::calculateTransformedCoords(uint32_t source,
return out;
}
+bool MotionEvent::operator==(const android::MotionEvent& o) const {
+ // We use NaN values to represent invalid cursor positions. Since NaN values are not equal
+ // to themselves according to IEEE 754, we cannot use the default equality operator to compare
+ // MotionEvents. Therefore we define a custom equality operator with special handling for NaNs.
+ // clang-format off
+ return InputEvent::operator==(static_cast<const InputEvent&>(o)) &&
+ mAction == o.mAction &&
+ mActionButton == o.mActionButton &&
+ mFlags == o.mFlags &&
+ mEdgeFlags == o.mEdgeFlags &&
+ mMetaState == o.mMetaState &&
+ mButtonState == o.mButtonState &&
+ mClassification == o.mClassification &&
+ mTransform == o.mTransform &&
+ mXPrecision == o.mXPrecision &&
+ mYPrecision == o.mYPrecision &&
+ ((std::isnan(mRawXCursorPosition) && std::isnan(o.mRawXCursorPosition)) ||
+ mRawXCursorPosition == o.mRawXCursorPosition) &&
+ ((std::isnan(mRawYCursorPosition) && std::isnan(o.mRawYCursorPosition)) ||
+ mRawYCursorPosition == o.mRawYCursorPosition) &&
+ mRawTransform == o.mRawTransform && mDownTime == o.mDownTime &&
+ mPointerProperties == o.mPointerProperties &&
+ mSampleEventTimes == o.mSampleEventTimes &&
+ mSamplePointerCoords == o.mSamplePointerCoords;
+ // clang-format on
+}
+
std::ostream& operator<<(std::ostream& out, const MotionEvent& event) {
out << "MotionEvent { action=" << MotionEvent::actionToString(event.getAction());
if (event.getActionButton() != 0) {
@@ -1032,6 +1177,9 @@ std::ostream& operator<<(std::ostream& out, const MotionEvent& event) {
if (event.getMetaState() != 0) {
out << ", metaState=" << event.getMetaState();
}
+ if (event.getFlags() != 0) {
+ out << ", flags=0x" << std::hex << event.getFlags() << std::dec;
+ }
if (event.getEdgeFlags() != 0) {
out << ", edgeFlags=" << event.getEdgeFlags();
}
@@ -1046,7 +1194,7 @@ std::ostream& operator<<(std::ostream& out, const MotionEvent& event) {
out << ", deviceId=" << event.getDeviceId();
out << ", source=" << inputEventSourceToString(event.getSource());
out << ", displayId=" << event.getDisplayId();
- out << ", eventId=" << event.getId();
+ out << ", eventId=0x" << std::hex << event.getId() << std::dec;
out << "}";
return out;
}
diff --git a/libs/input/InputDevice.cpp b/libs/input/InputDevice.cpp
index ccc83231fa..c348833747 100644
--- a/libs/input/InputDevice.cpp
+++ b/libs/input/InputDevice.cpp
@@ -193,14 +193,16 @@ InputDeviceInfo::InputDeviceInfo(const InputDeviceInfo& other)
mHasSensor(other.mHasSensor),
mMotionRanges(other.mMotionRanges),
mSensors(other.mSensors),
- mLights(other.mLights) {}
+ mLights(other.mLights),
+ mViewBehavior(other.mViewBehavior) {}
InputDeviceInfo::~InputDeviceInfo() {
}
void InputDeviceInfo::initialize(int32_t id, int32_t generation, int32_t controllerNumber,
const InputDeviceIdentifier& identifier, const std::string& alias,
- bool isExternal, bool hasMic, int32_t associatedDisplayId) {
+ bool isExternal, bool hasMic, int32_t associatedDisplayId,
+ InputDeviceViewBehavior viewBehavior) {
mId = id;
mGeneration = generation;
mControllerNumber = controllerNumber;
@@ -215,6 +217,7 @@ void InputDeviceInfo::initialize(int32_t id, int32_t generation, int32_t control
mHasBattery = false;
mHasButtonUnderPad = false;
mHasSensor = false;
+ mViewBehavior = viewBehavior;
mUsiVersion.reset();
mMotionRanges.clear();
mSensors.clear();
diff --git a/libs/input/InputEventLabels.cpp b/libs/input/InputEventLabels.cpp
index 0e627e56fd..8db0ca588b 100644
--- a/libs/input/InputEventLabels.cpp
+++ b/libs/input/InputEventLabels.cpp
@@ -348,7 +348,9 @@ namespace android {
DEFINE_KEYCODE(MACRO_1), \
DEFINE_KEYCODE(MACRO_2), \
DEFINE_KEYCODE(MACRO_3), \
- DEFINE_KEYCODE(MACRO_4)
+ DEFINE_KEYCODE(MACRO_4), \
+ DEFINE_KEYCODE(EMOJI_PICKER), \
+ DEFINE_KEYCODE(SCREENSHOT)
// NOTE: If you add a new axis here you must also add it to several other files.
// Refer to frameworks/base/core/java/android/view/MotionEvent.java for the full list.
diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp
index 09e98d0515..b3a36ebf5a 100644
--- a/libs/input/InputTransport.cpp
+++ b/libs/input/InputTransport.cpp
@@ -10,6 +10,7 @@
#include <fcntl.h>
#include <inttypes.h>
#include <math.h>
+#include <poll.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
@@ -25,10 +26,13 @@
#include <com_android_input_flags.h>
#include <input/InputTransport.h>
+#include <input/PrintTools.h>
#include <input/TraceTools.h>
namespace input_flags = com::android::input::flags;
+namespace android {
+
namespace {
/**
@@ -94,21 +98,91 @@ bool debugResampling() {
return __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "Resampling", ANDROID_LOG_INFO);
}
-} // namespace
+android::base::unique_fd dupChannelFd(int fd) {
+ android::base::unique_fd newFd(::dup(fd));
+ if (!newFd.ok()) {
+ ALOGE("Could not duplicate fd %i : %s", fd, strerror(errno));
+ const bool hitFdLimit = errno == EMFILE || errno == ENFILE;
+ // If this process is out of file descriptors, then throwing that might end up exploding
+ // on the other side of a binder call, which isn't really helpful.
+ // Better to just crash here and hope that the FD leak is slow.
+ // Other failures could be client errors, so we still propagate those back to the caller.
+ LOG_ALWAYS_FATAL_IF(hitFdLimit, "Too many open files, could not duplicate input channel");
+ return {};
+ }
+ return newFd;
+}
-using android::base::Result;
-using android::base::StringPrintf;
+void initializeKeyEvent(KeyEvent& event, const InputMessage& msg) {
+ event.initialize(msg.body.key.eventId, msg.body.key.deviceId, msg.body.key.source,
+ msg.body.key.displayId, msg.body.key.hmac, msg.body.key.action,
+ msg.body.key.flags, msg.body.key.keyCode, msg.body.key.scanCode,
+ msg.body.key.metaState, msg.body.key.repeatCount, msg.body.key.downTime,
+ msg.body.key.eventTime);
+}
-namespace android {
+void initializeFocusEvent(FocusEvent& event, const InputMessage& msg) {
+ event.initialize(msg.body.focus.eventId, msg.body.focus.hasFocus);
+}
+
+void initializeCaptureEvent(CaptureEvent& event, const InputMessage& msg) {
+ event.initialize(msg.body.capture.eventId, msg.body.capture.pointerCaptureEnabled);
+}
+
+void initializeDragEvent(DragEvent& event, const InputMessage& msg) {
+ event.initialize(msg.body.drag.eventId, msg.body.drag.x, msg.body.drag.y,
+ msg.body.drag.isExiting);
+}
+
+void initializeMotionEvent(MotionEvent& event, const InputMessage& msg) {
+ uint32_t pointerCount = msg.body.motion.pointerCount;
+ PointerProperties pointerProperties[pointerCount];
+ PointerCoords pointerCoords[pointerCount];
+ for (uint32_t i = 0; i < pointerCount; i++) {
+ pointerProperties[i] = msg.body.motion.pointers[i].properties;
+ pointerCoords[i] = msg.body.motion.pointers[i].coords;
+ }
+
+ ui::Transform transform;
+ transform.set({msg.body.motion.dsdx, msg.body.motion.dtdx, msg.body.motion.tx,
+ msg.body.motion.dtdy, msg.body.motion.dsdy, msg.body.motion.ty, 0, 0, 1});
+ ui::Transform displayTransform;
+ displayTransform.set({msg.body.motion.dsdxRaw, msg.body.motion.dtdxRaw, msg.body.motion.txRaw,
+ msg.body.motion.dtdyRaw, msg.body.motion.dsdyRaw, msg.body.motion.tyRaw,
+ 0, 0, 1});
+ event.initialize(msg.body.motion.eventId, msg.body.motion.deviceId, msg.body.motion.source,
+ msg.body.motion.displayId, msg.body.motion.hmac, msg.body.motion.action,
+ msg.body.motion.actionButton, msg.body.motion.flags, msg.body.motion.edgeFlags,
+ msg.body.motion.metaState, msg.body.motion.buttonState,
+ msg.body.motion.classification, transform, msg.body.motion.xPrecision,
+ msg.body.motion.yPrecision, msg.body.motion.xCursorPosition,
+ msg.body.motion.yCursorPosition, displayTransform, msg.body.motion.downTime,
+ msg.body.motion.eventTime, pointerCount, pointerProperties, pointerCoords);
+}
+
+void addSample(MotionEvent& event, const InputMessage& msg) {
+ uint32_t pointerCount = msg.body.motion.pointerCount;
+ PointerCoords pointerCoords[pointerCount];
+ for (uint32_t i = 0; i < pointerCount; i++) {
+ pointerCoords[i] = msg.body.motion.pointers[i].coords;
+ }
+
+ event.setMetaState(event.getMetaState() | msg.body.motion.metaState);
+ event.addSample(msg.body.motion.eventTime, pointerCoords);
+}
+
+void initializeTouchModeEvent(TouchModeEvent& event, const InputMessage& msg) {
+ event.initialize(msg.body.touchMode.eventId, msg.body.touchMode.isInTouchMode);
+}
// Socket buffer size. The default is typically about 128KB, which is much larger than
// we really need. So we make it smaller. It just needs to be big enough to hold
// a few dozen large multi-finger motion events in the case where an application gets
// behind processing touches.
-static const size_t SOCKET_BUFFER_SIZE = 32 * 1024;
+static constexpr size_t SOCKET_BUFFER_SIZE = 32 * 1024;
// Nanoseconds per milliseconds.
-static const nsecs_t NANOS_PER_MS = 1000000;
+static constexpr nsecs_t NANOS_PER_MS = 1000000;
// Latency added during resampling. A few milliseconds doesn't hurt much but
// reduces the impact of mispredicted touch positions.
@@ -141,32 +215,28 @@ static const char* PROPERTY_RESAMPLING_ENABLED = "ro.input.resampling";
* Crash if the events that are getting sent to the InputPublisher are inconsistent.
* Enable this via "adb shell setprop log.tag.InputTransportVerifyEvents DEBUG"
*/
-static bool verifyEvents() {
+bool verifyEvents() {
return input_flags::enable_outbound_event_verification() ||
__android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "VerifyEvents", ANDROID_LOG_INFO);
}
-template<typename T>
-inline static T min(const T& a, const T& b) {
- return a < b ? a : b;
-}
-
-inline static float lerp(float a, float b, float alpha) {
+inline float lerp(float a, float b, float alpha) {
return a + alpha * (b - a);
}
-inline static bool isPointerEvent(int32_t source) {
+inline bool isPointerEvent(int32_t source) {
return (source & AINPUT_SOURCE_CLASS_POINTER) == AINPUT_SOURCE_CLASS_POINTER;
}
-inline static const char* toString(bool value) {
- return value ? "true" : "false";
-}
-
-static bool shouldResampleTool(ToolType toolType) {
+bool shouldResampleTool(ToolType toolType) {
return toolType == ToolType::FINGER || toolType == ToolType::UNKNOWN;
}
+} // namespace
+
+using android::base::Result;
+using android::base::StringPrintf;
+
// --- InputMessage ---
bool InputMessage::isValid(size_t actualSize) const {
@@ -394,15 +464,23 @@ std::unique_ptr<InputChannel> InputChannel::create(const std::string& name,
return std::unique_ptr<InputChannel>(new InputChannel(name, std::move(fd), token));
}
-InputChannel::InputChannel(const std::string name, android::base::unique_fd fd, sp<IBinder> token)
- : mName(std::move(name)), mFd(std::move(fd)), mToken(std::move(token)) {
+std::unique_ptr<InputChannel> InputChannel::create(
+ android::os::InputChannelCore&& parceledChannel) {
+ return InputChannel::create(parceledChannel.name, parceledChannel.fd.release(),
+ parceledChannel.token);
+}
+
+InputChannel::InputChannel(const std::string name, android::base::unique_fd fd, sp<IBinder> token) {
+ this->name = std::move(name);
+ this->fd.reset(std::move(fd));
+ this->token = std::move(token);
ALOGD_IF(DEBUG_CHANNEL_LIFECYCLE, "Input channel constructed: name='%s', fd=%d",
- getName().c_str(), getFd().get());
+ getName().c_str(), getFd());
}
InputChannel::~InputChannel() {
ALOGD_IF(DEBUG_CHANNEL_LIFECYCLE, "Input channel destroyed: name='%s', fd=%d",
- getName().c_str(), getFd().get());
+ getName().c_str(), getFd());
}
status_t InputChannel::openInputChannelPair(const std::string& name,
@@ -440,19 +518,19 @@ status_t InputChannel::sendMessage(const InputMessage* msg) {
ATRACE_NAME_IF(ATRACE_ENABLED(),
StringPrintf("sendMessage(inputChannel=%s, seq=0x%" PRIx32 ", type=0x%" PRIx32
")",
- mName.c_str(), msg->header.seq, msg->header.type));
+ name.c_str(), msg->header.seq, msg->header.type));
const size_t msgLength = msg->size();
InputMessage cleanMsg;
msg->getSanitizedCopy(&cleanMsg);
ssize_t nWrite;
do {
- nWrite = ::send(getFd().get(), &cleanMsg, msgLength, MSG_DONTWAIT | MSG_NOSIGNAL);
+ nWrite = ::send(getFd(), &cleanMsg, msgLength, MSG_DONTWAIT | MSG_NOSIGNAL);
} while (nWrite == -1 && errno == EINTR);
if (nWrite < 0) {
int error = errno;
ALOGD_IF(DEBUG_CHANNEL_MESSAGES, "channel '%s' ~ error sending message of type %s, %s",
- mName.c_str(), ftl::enum_string(msg->header.type).c_str(), strerror(error));
+ name.c_str(), ftl::enum_string(msg->header.type).c_str(), strerror(error));
if (error == EAGAIN || error == EWOULDBLOCK) {
return WOULD_BLOCK;
}
@@ -464,12 +542,12 @@ status_t InputChannel::sendMessage(const InputMessage* msg) {
if (size_t(nWrite) != msgLength) {
ALOGD_IF(DEBUG_CHANNEL_MESSAGES,
- "channel '%s' ~ error sending message type %s, send was incomplete", mName.c_str(),
+ "channel '%s' ~ error sending message type %s, send was incomplete", name.c_str(),
ftl::enum_string(msg->header.type).c_str());
return DEAD_OBJECT;
}
- ALOGD_IF(DEBUG_CHANNEL_MESSAGES, "channel '%s' ~ sent message of type %s", mName.c_str(),
+ ALOGD_IF(DEBUG_CHANNEL_MESSAGES, "channel '%s' ~ sent message of type %s", name.c_str(),
ftl::enum_string(msg->header.type).c_str());
return OK;
@@ -478,13 +556,13 @@ status_t InputChannel::sendMessage(const InputMessage* msg) {
status_t InputChannel::receiveMessage(InputMessage* msg) {
ssize_t nRead;
do {
- nRead = ::recv(getFd().get(), msg, sizeof(InputMessage), MSG_DONTWAIT);
+ nRead = ::recv(getFd(), msg, sizeof(InputMessage), MSG_DONTWAIT);
} while (nRead == -1 && errno == EINTR);
if (nRead < 0) {
int error = errno;
ALOGD_IF(DEBUG_CHANNEL_MESSAGES, "channel '%s' ~ receive message failed, errno=%d",
- mName.c_str(), errno);
+ name.c_str(), errno);
if (error == EAGAIN || error == EWOULDBLOCK) {
return WOULD_BLOCK;
}
@@ -496,81 +574,85 @@ status_t InputChannel::receiveMessage(InputMessage* msg) {
if (nRead == 0) { // check for EOF
ALOGD_IF(DEBUG_CHANNEL_MESSAGES,
- "channel '%s' ~ receive message failed because peer was closed", mName.c_str());
+ "channel '%s' ~ receive message failed because peer was closed", name.c_str());
return DEAD_OBJECT;
}
if (!msg->isValid(nRead)) {
- ALOGE("channel '%s' ~ received invalid message of size %zd", mName.c_str(), nRead);
+ ALOGE("channel '%s' ~ received invalid message of size %zd", name.c_str(), nRead);
return BAD_VALUE;
}
- ALOGD_IF(DEBUG_CHANNEL_MESSAGES, "channel '%s' ~ received message of type %s", mName.c_str(),
+ ALOGD_IF(DEBUG_CHANNEL_MESSAGES, "channel '%s' ~ received message of type %s", name.c_str(),
ftl::enum_string(msg->header.type).c_str());
if (ATRACE_ENABLED()) {
// Add an additional trace point to include data about the received message.
std::string message = StringPrintf("receiveMessage(inputChannel=%s, seq=0x%" PRIx32
", type=0x%" PRIx32 ")",
- mName.c_str(), msg->header.seq, msg->header.type);
+ name.c_str(), msg->header.seq, msg->header.type);
ATRACE_NAME(message.c_str());
}
return OK;
}
-std::unique_ptr<InputChannel> InputChannel::dup() const {
- base::unique_fd newFd(dupFd());
- return InputChannel::create(getName(), std::move(newFd), getConnectionToken());
+bool InputChannel::probablyHasInput() const {
+ struct pollfd pfds = {.fd = fd.get(), .events = POLLIN};
+ if (::poll(&pfds, /*nfds=*/1, /*timeout=*/0) <= 0) {
+ // This can be a false negative because EINTR and ENOMEM are not handled. The latter should
+ // be extremely rare. The EINTR is also unlikely because it happens only when the signal
+ // arrives while the syscall is executed, and the syscall is quick. Hitting EINTR too often
+ // would be a sign of having too many signals, which is a bigger performance problem. A
+ // common tradition is to repeat the syscall on each EINTR, but it is not necessary here.
+ // In other words, the missing one liner is replaced by a multiline explanation.
+ return false;
+ }
+ // From poll(2): The bits returned in |revents| can include any of those specified in |events|,
+ // or one of the values POLLERR, POLLHUP, or POLLNVAL.
+ return (pfds.revents & POLLIN) != 0;
}
-void InputChannel::copyTo(InputChannel& outChannel) const {
- outChannel.mName = getName();
- outChannel.mFd = dupFd();
- outChannel.mToken = getConnectionToken();
+void InputChannel::waitForMessage(std::chrono::milliseconds timeout) const {
+ if (timeout < 0ms) {
+ LOG(FATAL) << "Timeout cannot be negative, received " << timeout.count();
+ }
+ struct pollfd pfds = {.fd = fd.get(), .events = POLLIN};
+ int ret;
+ std::chrono::time_point<std::chrono::steady_clock> stopTime =
+ std::chrono::steady_clock::now() + timeout;
+ std::chrono::milliseconds remaining = timeout;
+ do {
+ ret = ::poll(&pfds, /*nfds=*/1, /*timeout=*/remaining.count());
+ remaining = std::chrono::duration_cast<std::chrono::milliseconds>(
+ stopTime - std::chrono::steady_clock::now());
+ } while (ret == -1 && errno == EINTR && remaining > 0ms);
}
-status_t InputChannel::writeToParcel(android::Parcel* parcel) const {
- if (parcel == nullptr) {
- ALOGE("%s: Null parcel", __func__);
- return BAD_VALUE;
- }
- return parcel->writeStrongBinder(mToken)
- ?: parcel->writeUtf8AsUtf16(mName) ?: parcel->writeUniqueFileDescriptor(mFd);
+std::unique_ptr<InputChannel> InputChannel::dup() const {
+ base::unique_fd newFd(dupChannelFd(fd.get()));
+ return InputChannel::create(getName(), std::move(newFd), getConnectionToken());
}
-status_t InputChannel::readFromParcel(const android::Parcel* parcel) {
- if (parcel == nullptr) {
- ALOGE("%s: Null parcel", __func__);
- return BAD_VALUE;
- }
- mToken = parcel->readStrongBinder();
- return parcel->readUtf8FromUtf16(&mName) ?: parcel->readUniqueFileDescriptor(&mFd);
+void InputChannel::copyTo(android::os::InputChannelCore& outChannel) const {
+ outChannel.name = getName();
+ outChannel.fd.reset(dupChannelFd(fd.get()));
+ outChannel.token = getConnectionToken();
}
-sp<IBinder> InputChannel::getConnectionToken() const {
- return mToken;
+void InputChannel::moveChannel(std::unique_ptr<InputChannel> from,
+ android::os::InputChannelCore& outChannel) {
+ outChannel.name = from->getName();
+ outChannel.fd = android::os::ParcelFileDescriptor(std::move(from->fd));
+ outChannel.token = from->getConnectionToken();
}
-base::unique_fd InputChannel::dupFd() const {
- base::unique_fd newFd(::dup(getFd().get()));
- if (!newFd.ok()) {
- ALOGE("Could not duplicate fd %i for channel %s: %s", getFd().get(), getName().c_str(),
- strerror(errno));
- const bool hitFdLimit = errno == EMFILE || errno == ENFILE;
- // If this process is out of file descriptors, then throwing that might end up exploding
- // on the other side of a binder call, which isn't really helpful.
- // Better to just crash here and hope that the FD leak is slow.
- // Other failures could be client errors, so we still propagate those back to the caller.
- LOG_ALWAYS_FATAL_IF(hitFdLimit, "Too many open files, could not duplicate input channel %s",
- getName().c_str());
- return {};
- }
- return newFd;
+sp<IBinder> InputChannel::getConnectionToken() const {
+ return token;
}
// --- InputPublisher ---
InputPublisher::InputPublisher(const std::shared_ptr<InputChannel>& channel)
- : mChannel(channel), mInputVerifier(channel->getName()) {}
+ : mChannel(channel), mInputVerifier(mChannel->getName()) {}
InputPublisher::~InputPublisher() {
}
@@ -646,7 +728,7 @@ status_t InputPublisher::publishMotionEvent(
"action=%s, actionButton=0x%08x, flags=0x%x, edgeFlags=0x%x, "
"metaState=0x%x, buttonState=0x%x, classification=%s,"
"xPrecision=%f, yPrecision=%f, downTime=%" PRId64 ", eventTime=%" PRId64 ", "
- "pointerCount=%" PRIu32 " \n%s",
+ "pointerCount=%" PRIu32 "\n%s",
mChannel->getName().c_str(), __func__, seq, eventId, deviceId,
inputEventSourceToString(source).c_str(), displayId,
MotionEvent::actionToString(action).c_str(), actionButton, flags, edgeFlags,
@@ -850,6 +932,9 @@ status_t InputConsumer::consume(InputEventFactoryInterface* factory, bool consum
mConsumeTimes.emplace(mMsg.header.seq, systemTime(SYSTEM_TIME_MONOTONIC));
LOG_ALWAYS_FATAL_IF(!inserted, "Already have a consume time for seq=%" PRIu32,
mMsg.header.seq);
+
+ // Trace the event processing timeline - event was just read from the socket
+ ATRACE_ASYNC_BEGIN("InputConsumer processing", /*cookie=*/mMsg.header.seq);
}
if (result) {
// Consume the next batched event unless batches are being held for later.
@@ -871,7 +956,7 @@ status_t InputConsumer::consume(InputEventFactoryInterface* factory, bool consum
KeyEvent* keyEvent = factory->createKeyEvent();
if (!keyEvent) return NO_MEMORY;
- initializeKeyEvent(keyEvent, &mMsg);
+ initializeKeyEvent(*keyEvent, mMsg);
*outSeq = mMsg.header.seq;
*outEvent = keyEvent;
ALOGD_IF(DEBUG_TRANSPORT_CONSUMER,
@@ -934,7 +1019,7 @@ status_t InputConsumer::consume(InputEventFactoryInterface* factory, bool consum
if (!motionEvent) return NO_MEMORY;
updateTouchState(mMsg);
- initializeMotionEvent(motionEvent, &mMsg);
+ initializeMotionEvent(*motionEvent, mMsg);
*outSeq = mMsg.header.seq;
*outEvent = motionEvent;
@@ -956,7 +1041,7 @@ status_t InputConsumer::consume(InputEventFactoryInterface* factory, bool consum
FocusEvent* focusEvent = factory->createFocusEvent();
if (!focusEvent) return NO_MEMORY;
- initializeFocusEvent(focusEvent, &mMsg);
+ initializeFocusEvent(*focusEvent, mMsg);
*outSeq = mMsg.header.seq;
*outEvent = focusEvent;
break;
@@ -966,7 +1051,7 @@ status_t InputConsumer::consume(InputEventFactoryInterface* factory, bool consum
CaptureEvent* captureEvent = factory->createCaptureEvent();
if (!captureEvent) return NO_MEMORY;
- initializeCaptureEvent(captureEvent, &mMsg);
+ initializeCaptureEvent(*captureEvent, mMsg);
*outSeq = mMsg.header.seq;
*outEvent = captureEvent;
break;
@@ -976,7 +1061,7 @@ status_t InputConsumer::consume(InputEventFactoryInterface* factory, bool consum
DragEvent* dragEvent = factory->createDragEvent();
if (!dragEvent) return NO_MEMORY;
- initializeDragEvent(dragEvent, &mMsg);
+ initializeDragEvent(*dragEvent, mMsg);
*outSeq = mMsg.header.seq;
*outEvent = dragEvent;
break;
@@ -986,7 +1071,7 @@ status_t InputConsumer::consume(InputEventFactoryInterface* factory, bool consum
TouchModeEvent* touchModeEvent = factory->createTouchModeEvent();
if (!touchModeEvent) return NO_MEMORY;
- initializeTouchModeEvent(touchModeEvent, &mMsg);
+ initializeTouchModeEvent(*touchModeEvent, mMsg);
*outSeq = mMsg.header.seq;
*outEvent = touchModeEvent;
break;
@@ -1048,9 +1133,9 @@ status_t InputConsumer::consumeSamples(InputEventFactoryInterface* factory,
seqChain.seq = msg.header.seq;
seqChain.chain = chain;
mSeqChains.push_back(seqChain);
- addSample(motionEvent, &msg);
+ addSample(*motionEvent, msg);
} else {
- initializeMotionEvent(motionEvent, &msg);
+ initializeMotionEvent(*motionEvent, msg);
}
chain = msg.header.seq;
}
@@ -1231,7 +1316,7 @@ void InputConsumer::resampleTouchState(nsecs_t sampleTime, MotionEvent* event,
delta);
return;
}
- nsecs_t maxPredict = current->eventTime + min(delta / 2, RESAMPLE_MAX_PREDICTION);
+ nsecs_t maxPredict = current->eventTime + std::min(delta / 2, RESAMPLE_MAX_PREDICTION);
if (sampleTime > maxPredict) {
ALOGD_IF(debugResampling(),
"Sample time is too far in the future, adjusting prediction "
@@ -1388,6 +1473,9 @@ status_t InputConsumer::sendUnchainedFinishedSignal(uint32_t seq, bool handled)
// message anymore. If the socket write did not succeed, we will try again and will still
// need consume time.
popConsumeTime(seq);
+
+ // Trace the event processing timeline - event was just finished
+ ATRACE_ASYNC_END("InputConsumer processing", /*cookie=*/seq);
}
return result;
}
@@ -1406,6 +1494,10 @@ int32_t InputConsumer::getPendingBatchSource() const {
return head.body.motion.source;
}
+bool InputConsumer::probablyHasInput() const {
+ return hasPendingBatch() || mChannel->probablyHasInput();
+}
+
ssize_t InputConsumer::findBatch(int32_t deviceId, int32_t source) const {
for (size_t i = 0; i < mBatches.size(); i++) {
const Batch& batch = mBatches[i];
@@ -1427,69 +1519,6 @@ ssize_t InputConsumer::findTouchState(int32_t deviceId, int32_t source) const {
return -1;
}
-void InputConsumer::initializeKeyEvent(KeyEvent* event, const InputMessage* msg) {
- event->initialize(msg->body.key.eventId, msg->body.key.deviceId, msg->body.key.source,
- msg->body.key.displayId, msg->body.key.hmac, msg->body.key.action,
- msg->body.key.flags, msg->body.key.keyCode, msg->body.key.scanCode,
- msg->body.key.metaState, msg->body.key.repeatCount, msg->body.key.downTime,
- msg->body.key.eventTime);
-}
-
-void InputConsumer::initializeFocusEvent(FocusEvent* event, const InputMessage* msg) {
- event->initialize(msg->body.focus.eventId, msg->body.focus.hasFocus);
-}
-
-void InputConsumer::initializeCaptureEvent(CaptureEvent* event, const InputMessage* msg) {
- event->initialize(msg->body.capture.eventId, msg->body.capture.pointerCaptureEnabled);
-}
-
-void InputConsumer::initializeDragEvent(DragEvent* event, const InputMessage* msg) {
- event->initialize(msg->body.drag.eventId, msg->body.drag.x, msg->body.drag.y,
- msg->body.drag.isExiting);
-}
-
-void InputConsumer::initializeMotionEvent(MotionEvent* event, const InputMessage* msg) {
- uint32_t pointerCount = msg->body.motion.pointerCount;
- PointerProperties pointerProperties[pointerCount];
- PointerCoords pointerCoords[pointerCount];
- for (uint32_t i = 0; i < pointerCount; i++) {
- pointerProperties[i] = msg->body.motion.pointers[i].properties;
- pointerCoords[i] = msg->body.motion.pointers[i].coords;
- }
-
- ui::Transform transform;
- transform.set({msg->body.motion.dsdx, msg->body.motion.dtdx, msg->body.motion.tx,
- msg->body.motion.dtdy, msg->body.motion.dsdy, msg->body.motion.ty, 0, 0, 1});
- ui::Transform displayTransform;
- displayTransform.set({msg->body.motion.dsdxRaw, msg->body.motion.dtdxRaw,
- msg->body.motion.txRaw, msg->body.motion.dtdyRaw,
- msg->body.motion.dsdyRaw, msg->body.motion.tyRaw, 0, 0, 1});
- event->initialize(msg->body.motion.eventId, msg->body.motion.deviceId, msg->body.motion.source,
- msg->body.motion.displayId, msg->body.motion.hmac, msg->body.motion.action,
- msg->body.motion.actionButton, msg->body.motion.flags,
- msg->body.motion.edgeFlags, msg->body.motion.metaState,
- msg->body.motion.buttonState, msg->body.motion.classification, transform,
- msg->body.motion.xPrecision, msg->body.motion.yPrecision,
- msg->body.motion.xCursorPosition, msg->body.motion.yCursorPosition,
- displayTransform, msg->body.motion.downTime, msg->body.motion.eventTime,
- pointerCount, pointerProperties, pointerCoords);
-}
-
-void InputConsumer::initializeTouchModeEvent(TouchModeEvent* event, const InputMessage* msg) {
- event->initialize(msg->body.touchMode.eventId, msg->body.touchMode.isInTouchMode);
-}
-
-void InputConsumer::addSample(MotionEvent* event, const InputMessage* msg) {
- uint32_t pointerCount = msg->body.motion.pointerCount;
- PointerCoords pointerCoords[pointerCount];
- for (uint32_t i = 0; i < pointerCount; i++) {
- pointerCoords[i] = msg->body.motion.pointers[i].coords;
- }
-
- event->setMetaState(event->getMetaState() | msg->body.motion.metaState);
- event->addSample(msg->body.motion.eventTime, pointerCoords);
-}
-
bool InputConsumer::canAddSample(const Batch& batch, const InputMessage *msg) {
const InputMessage& head = batch.samples[0];
uint32_t pointerCount = msg->body.motion.pointerCount;
diff --git a/libs/input/KeyLayoutMap.cpp b/libs/input/KeyLayoutMap.cpp
index ab8c341b15..508818852e 100644
--- a/libs/input/KeyLayoutMap.cpp
+++ b/libs/input/KeyLayoutMap.cpp
@@ -97,6 +97,10 @@ static const std::unordered_map<std::string_view, InputDeviceSensorType> SENSOR_
bool kernelConfigsArePresent(const std::set<std::string>& configs) {
#if defined(__ANDROID__)
+ if (configs.empty()) {
+ return true;
+ }
+
std::map<std::string, std::string> kernelConfigs;
const status_t result = android::kernelconfigs::LoadKernelConfigs(&kernelConfigs);
LOG_ALWAYS_FATAL_IF(result != OK, "Kernel configs could not be fetched");
diff --git a/libs/input/MotionPredictorMetricsManager.cpp b/libs/input/MotionPredictorMetricsManager.cpp
index 0412d08181..6872af2aa5 100644
--- a/libs/input/MotionPredictorMetricsManager.cpp
+++ b/libs/input/MotionPredictorMetricsManager.cpp
@@ -113,7 +113,12 @@ void MotionPredictorMetricsManager::onRecord(const MotionEvent& inputEvent) {
// Adds new predictions to mRecentPredictions and maintains the invariant that elements are
// sorted in ascending order of targetTimestamp.
void MotionPredictorMetricsManager::onPredict(const MotionEvent& predictionEvent) {
- for (size_t i = 0; i < predictionEvent.getHistorySize() + 1; ++i) {
+ const size_t numPredictions = predictionEvent.getHistorySize() + 1;
+ if (numPredictions > mMaxNumPredictions) {
+ LOG(WARNING) << "numPredictions (" << numPredictions << ") > mMaxNumPredictions ("
+ << mMaxNumPredictions << "). Ignoring extra predictions in metrics.";
+ }
+ for (size_t i = 0; (i < numPredictions) && (i < mMaxNumPredictions); ++i) {
// Convert MotionEvent to PredictionPoint.
const PointerCoords* coords =
predictionEvent.getHistoricalRawPointerCoords(/*pointerIndex=*/0, i);
@@ -325,42 +330,44 @@ void MotionPredictorMetricsManager::computeAtomFields() {
mAtomFields[i].highVelocityOffTrajectoryRmse =
static_cast<int>(offTrajectoryRmse * 1000);
}
+ }
- // Scale-invariant errors: reported only for the last time bucket, where the values
- // represent an average across all time buckets.
- if (i + 1 == mMaxNumPredictions) {
- // Compute error averages.
- float alongTrajectoryRmseSum = 0;
- float offTrajectoryRmseSum = 0;
- for (size_t j = 0; j < mAggregatedMetrics.size(); ++j) {
- // If we have general errors (checked above), we should always also have
- // scale-invariant errors.
- LOG_ALWAYS_FATAL_IF(mAggregatedMetrics[j].scaleInvariantErrorsCount == 0,
- "mAggregatedMetrics[%zu].scaleInvariantErrorsCount is 0", j);
-
- LOG_ALWAYS_FATAL_IF(mAggregatedMetrics[j].scaleInvariantAlongTrajectorySse < 0,
- "mAggregatedMetrics[%zu].scaleInvariantAlongTrajectorySse = %f "
- "should not be negative",
- j, mAggregatedMetrics[j].scaleInvariantAlongTrajectorySse);
- alongTrajectoryRmseSum +=
- std::sqrt(mAggregatedMetrics[j].scaleInvariantAlongTrajectorySse /
- mAggregatedMetrics[j].scaleInvariantErrorsCount);
-
- LOG_ALWAYS_FATAL_IF(mAggregatedMetrics[j].scaleInvariantOffTrajectorySse < 0,
- "mAggregatedMetrics[%zu].scaleInvariantOffTrajectorySse = %f "
- "should not be negative",
- j, mAggregatedMetrics[j].scaleInvariantOffTrajectorySse);
- offTrajectoryRmseSum +=
- std::sqrt(mAggregatedMetrics[j].scaleInvariantOffTrajectorySse /
- mAggregatedMetrics[j].scaleInvariantErrorsCount);
+ // Scale-invariant errors: the average scale-invariant error across all time buckets
+ // is reported in the last time bucket.
+ {
+ // Compute error averages.
+ float alongTrajectoryRmseSum = 0;
+ float offTrajectoryRmseSum = 0;
+ int bucket_count = 0;
+ for (size_t j = 0; j < mAggregatedMetrics.size(); ++j) {
+ if (mAggregatedMetrics[j].scaleInvariantErrorsCount == 0) {
+ continue;
}
- const float averageAlongTrajectoryRmse =
- alongTrajectoryRmseSum / mAggregatedMetrics.size();
+ LOG_ALWAYS_FATAL_IF(mAggregatedMetrics[j].scaleInvariantAlongTrajectorySse < 0,
+ "mAggregatedMetrics[%zu].scaleInvariantAlongTrajectorySse = %f "
+ "should not be negative",
+ j, mAggregatedMetrics[j].scaleInvariantAlongTrajectorySse);
+ alongTrajectoryRmseSum +=
+ std::sqrt(mAggregatedMetrics[j].scaleInvariantAlongTrajectorySse /
+ mAggregatedMetrics[j].scaleInvariantErrorsCount);
+
+ LOG_ALWAYS_FATAL_IF(mAggregatedMetrics[j].scaleInvariantOffTrajectorySse < 0,
+ "mAggregatedMetrics[%zu].scaleInvariantOffTrajectorySse = %f "
+ "should not be negative",
+ j, mAggregatedMetrics[j].scaleInvariantOffTrajectorySse);
+ offTrajectoryRmseSum += std::sqrt(mAggregatedMetrics[j].scaleInvariantOffTrajectorySse /
+ mAggregatedMetrics[j].scaleInvariantErrorsCount);
+
+ ++bucket_count;
+ }
+
+ if (bucket_count > 0) {
+ const float averageAlongTrajectoryRmse = alongTrajectoryRmseSum / bucket_count;
mAtomFields.back().scaleInvariantAlongTrajectoryRmse =
static_cast<int>(averageAlongTrajectoryRmse * 1000);
- const float averageOffTrajectoryRmse = offTrajectoryRmseSum / mAggregatedMetrics.size();
+ const float averageOffTrajectoryRmse = offTrajectoryRmseSum / bucket_count;
mAtomFields.back().scaleInvariantOffTrajectoryRmse =
static_cast<int>(averageOffTrajectoryRmse * 1000);
}
diff --git a/libs/input/VelocityControl.cpp b/libs/input/VelocityControl.cpp
index c835a081a5..edd31e91d3 100644
--- a/libs/input/VelocityControl.cpp
+++ b/libs/input/VelocityControl.cpp
@@ -15,7 +15,6 @@
*/
#define LOG_TAG "VelocityControl"
-//#define LOG_NDEBUG 0
// Log debug messages about acceleration.
static constexpr bool DEBUG_ACCELERATION = false;
@@ -23,6 +22,7 @@ static constexpr bool DEBUG_ACCELERATION = false;
#include <math.h>
#include <limits.h>
+#include <android-base/logging.h>
#include <input/VelocityControl.h>
#include <utils/BitSet.h>
#include <utils/Timers.h>
@@ -37,15 +37,6 @@ VelocityControl::VelocityControl() {
reset();
}
-const VelocityControlParameters& VelocityControl::getParameters() const{
- return mParameters;
-}
-
-void VelocityControl::setParameters(const VelocityControlParameters& parameters) {
- mParameters = parameters;
- reset();
-}
-
void VelocityControl::reset() {
mLastMovementTime = LLONG_MIN;
mRawPositionX = 0;
@@ -54,65 +45,156 @@ void VelocityControl::reset() {
}
void VelocityControl::move(nsecs_t eventTime, float* deltaX, float* deltaY) {
- if ((deltaX && *deltaX) || (deltaY && *deltaY)) {
- if (eventTime >= mLastMovementTime + STOP_TIME) {
- if (DEBUG_ACCELERATION && mLastMovementTime != LLONG_MIN) {
- ALOGD("VelocityControl: stopped, last movement was %0.3fms ago",
- (eventTime - mLastMovementTime) * 0.000001f);
- }
- reset();
- }
+ if ((deltaX == nullptr || *deltaX == 0) && (deltaY == nullptr || *deltaY == 0)) {
+ return;
+ }
+ if (eventTime >= mLastMovementTime + STOP_TIME) {
+ ALOGD_IF(DEBUG_ACCELERATION && mLastMovementTime != LLONG_MIN,
+ "VelocityControl: stopped, last movement was %0.3fms ago",
+ (eventTime - mLastMovementTime) * 0.000001f);
+ reset();
+ }
- mLastMovementTime = eventTime;
- if (deltaX) {
- mRawPositionX += *deltaX;
- }
- if (deltaY) {
- mRawPositionY += *deltaY;
- }
- mVelocityTracker.addMovement(eventTime, /*pointerId=*/0, AMOTION_EVENT_AXIS_X,
- mRawPositionX);
- mVelocityTracker.addMovement(eventTime, /*pointerId=*/0, AMOTION_EVENT_AXIS_Y,
- mRawPositionY);
-
- std::optional<float> vx = mVelocityTracker.getVelocity(AMOTION_EVENT_AXIS_X, 0);
- std::optional<float> vy = mVelocityTracker.getVelocity(AMOTION_EVENT_AXIS_Y, 0);
- float scale = mParameters.scale;
- if (vx && vy) {
- float speed = hypotf(*vx, *vy) * scale;
- if (speed >= mParameters.highThreshold) {
- // Apply full acceleration above the high speed threshold.
- scale *= mParameters.acceleration;
- } else if (speed > mParameters.lowThreshold) {
- // Linearly interpolate the acceleration to apply between the low and high
- // speed thresholds.
- scale *= 1 + (speed - mParameters.lowThreshold)
- / (mParameters.highThreshold - mParameters.lowThreshold)
- * (mParameters.acceleration - 1);
- }
-
- if (DEBUG_ACCELERATION) {
- ALOGD("VelocityControl(%0.3f, %0.3f, %0.3f, %0.3f): "
- "vx=%0.3f, vy=%0.3f, speed=%0.3f, accel=%0.3f",
- mParameters.scale, mParameters.lowThreshold, mParameters.highThreshold,
- mParameters.acceleration, *vx, *vy, speed, scale / mParameters.scale);
- }
-
- } else {
- if (DEBUG_ACCELERATION) {
- ALOGD("VelocityControl(%0.3f, %0.3f, %0.3f, %0.3f): unknown velocity",
- mParameters.scale, mParameters.lowThreshold, mParameters.highThreshold,
- mParameters.acceleration);
- }
- }
+ mLastMovementTime = eventTime;
+ if (deltaX) {
+ mRawPositionX += *deltaX;
+ }
+ if (deltaY) {
+ mRawPositionY += *deltaY;
+ }
+ mVelocityTracker.addMovement(eventTime, /*pointerId=*/0, AMOTION_EVENT_AXIS_X, mRawPositionX);
+ mVelocityTracker.addMovement(eventTime, /*pointerId=*/0, AMOTION_EVENT_AXIS_Y, mRawPositionY);
+ scaleDeltas(deltaX, deltaY);
+}
+
+// --- SimpleVelocityControl ---
+
+const VelocityControlParameters& SimpleVelocityControl::getParameters() const {
+ return mParameters;
+}
- if (deltaX) {
- *deltaX *= scale;
+void SimpleVelocityControl::setParameters(const VelocityControlParameters& parameters) {
+ mParameters = parameters;
+ reset();
+}
+
+void SimpleVelocityControl::scaleDeltas(float* deltaX, float* deltaY) {
+ std::optional<float> vx = mVelocityTracker.getVelocity(AMOTION_EVENT_AXIS_X, 0);
+ std::optional<float> vy = mVelocityTracker.getVelocity(AMOTION_EVENT_AXIS_Y, 0);
+ float scale = mParameters.scale;
+ if (vx.has_value() && vy.has_value()) {
+ float speed = hypotf(*vx, *vy) * scale;
+ if (speed >= mParameters.highThreshold) {
+ // Apply full acceleration above the high speed threshold.
+ scale *= mParameters.acceleration;
+ } else if (speed > mParameters.lowThreshold) {
+ // Linearly interpolate the acceleration to apply between the low and high
+ // speed thresholds.
+ scale *= 1 +
+ (speed - mParameters.lowThreshold) /
+ (mParameters.highThreshold - mParameters.lowThreshold) *
+ (mParameters.acceleration - 1);
}
- if (deltaY) {
- *deltaY *= scale;
+
+ ALOGD_IF(DEBUG_ACCELERATION,
+ "SimpleVelocityControl(%0.3f, %0.3f, %0.3f, %0.3f): "
+ "vx=%0.3f, vy=%0.3f, speed=%0.3f, accel=%0.3f",
+ mParameters.scale, mParameters.lowThreshold, mParameters.highThreshold,
+ mParameters.acceleration, *vx, *vy, speed, scale / mParameters.scale);
+
+ } else {
+ ALOGD_IF(DEBUG_ACCELERATION,
+ "SimpleVelocityControl(%0.3f, %0.3f, %0.3f, %0.3f): unknown velocity",
+ mParameters.scale, mParameters.lowThreshold, mParameters.highThreshold,
+ mParameters.acceleration);
+ }
+
+ if (deltaX != nullptr) {
+ *deltaX *= scale;
+ }
+ if (deltaY != nullptr) {
+ *deltaY *= scale;
+ }
+}
+
+// --- CurvedVelocityControl ---
+
+namespace {
+
+/**
+ * The resolution that we assume a mouse to have, in counts per inch.
+ *
+ * Mouse resolutions vary wildly, but 800 CPI is probably the most common. There should be enough
+ * range in the available sensitivity settings to accommodate users of mice with other resolutions.
+ */
+constexpr int32_t MOUSE_CPI = 800;
+
+float countsToMm(float counts) {
+ return counts / MOUSE_CPI * 25.4;
+}
+
+} // namespace
+
+CurvedVelocityControl::CurvedVelocityControl()
+ : mCurveSegments(createAccelerationCurveForPointerSensitivity(0)) {}
+
+void CurvedVelocityControl::setCurve(const std::vector<AccelerationCurveSegment>& curve) {
+ mCurveSegments = curve;
+}
+
+void CurvedVelocityControl::setAccelerationEnabled(bool enabled) {
+ mAccelerationEnabled = enabled;
+}
+
+void CurvedVelocityControl::scaleDeltas(float* deltaX, float* deltaY) {
+ if (!mAccelerationEnabled) {
+ ALOGD_IF(DEBUG_ACCELERATION, "CurvedVelocityControl: acceleration disabled");
+ return;
+ }
+
+ std::optional<float> vx = mVelocityTracker.getVelocity(AMOTION_EVENT_AXIS_X, 0);
+ std::optional<float> vy = mVelocityTracker.getVelocity(AMOTION_EVENT_AXIS_Y, 0);
+
+ float ratio;
+ if (vx.has_value() && vy.has_value()) {
+ float vxMmPerS = countsToMm(*vx);
+ float vyMmPerS = countsToMm(*vy);
+ float speedMmPerS = sqrtf(vxMmPerS * vxMmPerS + vyMmPerS * vyMmPerS);
+
+ const AccelerationCurveSegment& seg = segmentForSpeed(speedMmPerS);
+ ratio = seg.baseGain + seg.reciprocal / speedMmPerS;
+ ALOGD_IF(DEBUG_ACCELERATION,
+ "CurvedVelocityControl: velocities (%0.3f, %0.3f) → speed %0.3f → ratio %0.3f",
+ vxMmPerS, vyMmPerS, speedMmPerS, ratio);
+ } else {
+ // We don't have enough data to compute a velocity yet. This happens early in the movement,
+ // when the speed is presumably low, so use the base gain of the first segment of the curve.
+ // (This would behave oddly for curves with a reciprocal term on the first segment, but we
+ // don't have any of those, and they'd be very strange at velocities close to zero anyway.)
+ ratio = mCurveSegments[0].baseGain;
+ ALOGD_IF(DEBUG_ACCELERATION,
+ "CurvedVelocityControl: unknown velocity, using base gain of first segment (%.3f)",
+ ratio);
+ }
+
+ if (deltaX != nullptr) {
+ *deltaX *= ratio;
+ }
+ if (deltaY != nullptr) {
+ *deltaY *= ratio;
+ }
+}
+
+const AccelerationCurveSegment& CurvedVelocityControl::segmentForSpeed(float speedMmPerS) {
+ for (const AccelerationCurveSegment& seg : mCurveSegments) {
+ if (speedMmPerS <= seg.maxPointerSpeedMmPerS) {
+ return seg;
}
}
+ ALOGE("CurvedVelocityControl: No segment found for speed %.3f; last segment should always have "
+ "a max speed of infinity.",
+ speedMmPerS);
+ return mCurveSegments.back();
}
} // namespace android
diff --git a/libs/input/VirtualInputDevice.cpp b/libs/input/VirtualInputDevice.cpp
index db7031ab03..eea06f1720 100644
--- a/libs/input/VirtualInputDevice.cpp
+++ b/libs/input/VirtualInputDevice.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2023 The Android Open Source Project
+ * Copyright 2023 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.
@@ -39,7 +39,9 @@ static bool isDebug() {
}
namespace android {
+
VirtualInputDevice::VirtualInputDevice(unique_fd fd) : mFd(std::move(fd)) {}
+
VirtualInputDevice::~VirtualInputDevice() {
ioctl(mFd, UI_DEV_DESTROY);
}
@@ -56,7 +58,7 @@ bool VirtualInputDevice::writeInputEvent(uint16_t type, uint16_t code, int32_t v
return TEMP_FAILURE_RETRY(write(mFd, &ev, sizeof(struct input_event))) == sizeof(ev);
}
-/** Utility method to write keyboard key events or mouse button events. */
+/** Utility method to write keyboard key events or mouse/stylus button events. */
bool VirtualInputDevice::writeEvKeyEvent(int32_t androidCode, int32_t androidAction,
const std::map<int, int>& evKeyCodeMapping,
const std::map<int, UinputAction>& actionMapping,
@@ -68,13 +70,17 @@ bool VirtualInputDevice::writeEvKeyEvent(int32_t androidCode, int32_t androidAct
}
auto actionIterator = actionMapping.find(androidAction);
if (actionIterator == actionMapping.end()) {
+ ALOGE("Unsupported native action for android action %d", androidAction);
return false;
}
- if (!writeInputEvent(EV_KEY, static_cast<uint16_t>(evKeyCodeIterator->second),
- static_cast<int32_t>(actionIterator->second), eventTime)) {
+ int32_t action = static_cast<int32_t>(actionIterator->second);
+ uint16_t evKeyCode = static_cast<uint16_t>(evKeyCodeIterator->second);
+ if (!writeInputEvent(EV_KEY, evKeyCode, action, eventTime)) {
+ ALOGE("Failed to write native action %d and EV keycode %u.", action, evKeyCode);
return false;
}
if (!writeInputEvent(EV_SYN, SYN_REPORT, 0, eventTime)) {
+ ALOGE("Failed to write SYN_REPORT for EV_KEY event.");
return false;
}
return true;
@@ -85,6 +91,7 @@ const std::map<int, UinputAction> VirtualKeyboard::KEY_ACTION_MAPPING = {
{AKEY_EVENT_ACTION_DOWN, UinputAction::PRESS},
{AKEY_EVENT_ACTION_UP, UinputAction::RELEASE},
};
+
// Keycode mapping from https://source.android.com/devices/input/keyboard-devices
const std::map<int, int> VirtualKeyboard::KEY_CODE_MAPPING = {
{AKEYCODE_0, KEY_0},
@@ -195,7 +202,9 @@ const std::map<int, int> VirtualKeyboard::KEY_CODE_MAPPING = {
{AKEYCODE_NUMPAD_COMMA, KEY_KPCOMMA},
{AKEYCODE_LANGUAGE_SWITCH, KEY_LANGUAGE},
};
+
VirtualKeyboard::VirtualKeyboard(unique_fd fd) : VirtualInputDevice(std::move(fd)) {}
+
VirtualKeyboard::~VirtualKeyboard() {}
bool VirtualKeyboard::writeKeyEvent(int32_t androidKeyCode, int32_t androidAction,
@@ -275,6 +284,7 @@ const std::map<int, UinputAction> VirtualTouchscreen::TOUCH_ACTION_MAPPING = {
{AMOTION_EVENT_ACTION_MOVE, UinputAction::MOVE},
{AMOTION_EVENT_ACTION_CANCEL, UinputAction::CANCEL},
};
+
// Tool type mapping from https://source.android.com/devices/input/touch-devices
const std::map<int, int> VirtualTouchscreen::TOOL_TYPE_MAPPING = {
{AMOTION_EVENT_TOOL_TYPE_FINGER, MT_TOOL_FINGER},
@@ -393,4 +403,110 @@ bool VirtualTouchscreen::handleTouchDown(int32_t pointerId, std::chrono::nanosec
return true;
}
+// --- VirtualStylus ---
+const std::map<int, int> VirtualStylus::TOOL_TYPE_MAPPING = {
+ {AMOTION_EVENT_TOOL_TYPE_STYLUS, BTN_TOOL_PEN},
+ {AMOTION_EVENT_TOOL_TYPE_ERASER, BTN_TOOL_RUBBER},
+};
+
+// Button code mapping from https://source.android.com/devices/input/touch-devices
+const std::map<int, int> VirtualStylus::BUTTON_CODE_MAPPING = {
+ {AMOTION_EVENT_BUTTON_STYLUS_PRIMARY, BTN_STYLUS},
+ {AMOTION_EVENT_BUTTON_STYLUS_SECONDARY, BTN_STYLUS2},
+};
+
+VirtualStylus::VirtualStylus(unique_fd fd)
+ : VirtualInputDevice(std::move(fd)), mIsStylusDown(false) {}
+
+VirtualStylus::~VirtualStylus() {}
+
+bool VirtualStylus::writeMotionEvent(int32_t toolType, int32_t action, int32_t locationX,
+ int32_t locationY, int32_t pressure, int32_t tiltX,
+ int32_t tiltY, std::chrono::nanoseconds eventTime) {
+ auto actionIterator = VirtualTouchscreen::TOUCH_ACTION_MAPPING.find(action);
+ if (actionIterator == VirtualTouchscreen::TOUCH_ACTION_MAPPING.end()) {
+ ALOGE("Unsupported action passed for stylus: %d.", action);
+ return false;
+ }
+ UinputAction uinputAction = actionIterator->second;
+ auto toolTypeIterator = TOOL_TYPE_MAPPING.find(toolType);
+ if (toolTypeIterator == TOOL_TYPE_MAPPING.end()) {
+ ALOGE("Unsupported tool type passed for stylus: %d.", toolType);
+ return false;
+ }
+ uint16_t tool = static_cast<uint16_t>(toolTypeIterator->second);
+ if (uinputAction == UinputAction::PRESS && !handleStylusDown(tool, eventTime)) {
+ return false;
+ }
+ if (!mIsStylusDown) {
+ ALOGE("Action UP or MOVE received with no prior action DOWN for stylus %d.", mFd.get());
+ return false;
+ }
+ if (uinputAction == UinputAction::RELEASE && !handleStylusUp(tool, eventTime)) {
+ return false;
+ }
+ if (!writeInputEvent(EV_ABS, ABS_X, locationX, eventTime)) {
+ ALOGE("Unsupported x-axis location passed for stylus: %d.", locationX);
+ return false;
+ }
+ if (!writeInputEvent(EV_ABS, ABS_Y, locationY, eventTime)) {
+ ALOGE("Unsupported y-axis location passed for stylus: %d.", locationY);
+ return false;
+ }
+ if (!writeInputEvent(EV_ABS, ABS_TILT_X, tiltX, eventTime)) {
+ ALOGE("Unsupported x-axis tilt passed for stylus: %d.", tiltX);
+ return false;
+ }
+ if (!writeInputEvent(EV_ABS, ABS_TILT_Y, tiltY, eventTime)) {
+ ALOGE("Unsupported y-axis tilt passed for stylus: %d.", tiltY);
+ return false;
+ }
+ if (!writeInputEvent(EV_ABS, ABS_PRESSURE, pressure, eventTime)) {
+ ALOGE("Unsupported pressure passed for stylus: %d.", pressure);
+ return false;
+ }
+ if (!writeInputEvent(EV_SYN, SYN_REPORT, 0, eventTime)) {
+ ALOGE("Failed to write SYN_REPORT for stylus motion event.");
+ return false;
+ }
+ return true;
+}
+
+bool VirtualStylus::writeButtonEvent(int32_t androidButtonCode, int32_t androidAction,
+ std::chrono::nanoseconds eventTime) {
+ return writeEvKeyEvent(androidButtonCode, androidAction, BUTTON_CODE_MAPPING,
+ VirtualMouse::BUTTON_ACTION_MAPPING, eventTime);
+}
+
+bool VirtualStylus::handleStylusDown(uint16_t tool, std::chrono::nanoseconds eventTime) {
+ if (mIsStylusDown) {
+ ALOGE("Repetitive action DOWN event received for a stylus that is already down.");
+ return false;
+ }
+ if (!writeInputEvent(EV_KEY, tool, static_cast<int32_t>(UinputAction::PRESS), eventTime)) {
+ ALOGE("Failed to write EV_KEY for stylus tool type: %u.", tool);
+ return false;
+ }
+ if (!writeInputEvent(EV_KEY, BTN_TOUCH, static_cast<int32_t>(UinputAction::PRESS), eventTime)) {
+ ALOGE("Failed to write BTN_TOUCH for stylus press.");
+ return false;
+ }
+ mIsStylusDown = true;
+ return true;
+}
+
+bool VirtualStylus::handleStylusUp(uint16_t tool, std::chrono::nanoseconds eventTime) {
+ if (!writeInputEvent(EV_KEY, tool, static_cast<int32_t>(UinputAction::RELEASE), eventTime)) {
+ ALOGE("Failed to write EV_KEY for stylus tool type: %u.", tool);
+ return false;
+ }
+ if (!writeInputEvent(EV_KEY, BTN_TOUCH, static_cast<int32_t>(UinputAction::RELEASE),
+ eventTime)) {
+ ALOGE("Failed to write BTN_TOUCH for stylus release.");
+ return false;
+ }
+ mIsStylusDown = false;
+ return true;
+}
+
} // namespace android
diff --git a/libs/input/android/os/IInputFlinger.aidl b/libs/input/android/os/IInputFlinger.aidl
index 00ebd4d34f..c1aacfbc53 100644
--- a/libs/input/android/os/IInputFlinger.aidl
+++ b/libs/input/android/os/IInputFlinger.aidl
@@ -16,14 +16,13 @@
package android.os;
-import android.InputChannel;
+import android.os.InputChannelCore;
import android.gui.FocusRequest;
-import android.gui.WindowInfo;
/** @hide */
interface IInputFlinger
{
- InputChannel createInputChannel(in @utf8InCpp String name);
+ InputChannelCore createInputChannel(in @utf8InCpp String name);
void removeInputChannel(in IBinder connectionToken);
/**
* Sets focus to the window identified by the token. This must be called
diff --git a/libs/input/android/InputChannel.aidl b/libs/input/android/os/InputChannelCore.aidl
index c2d1112dd3..888a553268 100644
--- a/libs/input/android/InputChannel.aidl
+++ b/libs/input/android/os/InputChannelCore.aidl
@@ -15,6 +15,16 @@
** limitations under the License.
*/
-package android;
+package android.os;
-parcelable InputChannel cpp_header "input/InputTransport.h";
+import android.os.ParcelFileDescriptor;
+
+/**
+ * Input channel struct for sending InputChannel between processes.
+ * @hide
+ */
+parcelable InputChannelCore {
+ @utf8InCpp String name;
+ ParcelFileDescriptor fd;
+ IBinder token;
+}
diff --git a/libs/input/android/os/InputConfig.aidl b/libs/input/android/os/InputConfig.aidl
index 4e644fff06..5d391551c2 100644
--- a/libs/input/android/os/InputConfig.aidl
+++ b/libs/input/android/os/InputConfig.aidl
@@ -150,4 +150,11 @@ enum InputConfig {
* likely a duplicate window with the same client token, but different bounds.
*/
CLONE = 1 << 16,
+
+ /**
+ * If the stylus is currently down *anywhere* on the screen, new touches will not be delivered
+ * to the window with this flag. This helps prevent unexpected clicks on some system windows,
+ * like StatusBar and TaskBar.
+ */
+ GLOBAL_STYLUS_BLOCKS_TOUCH = 1 << 17,
}
diff --git a/libs/input/input_flags.aconfig b/libs/input/input_flags.aconfig
index 54eeb39935..bdec5c33cd 100644
--- a/libs/input/input_flags.aconfig
+++ b/libs/input/input_flags.aconfig
@@ -1,4 +1,5 @@
package: "com.android.input.flags"
+container: "system"
flag {
name: "enable_outbound_event_verification"
@@ -26,6 +27,13 @@ flag {
namespace: "input"
description: "Set to true to enable timer support for the touchpad Gestures library"
bug: "297192727"
+ }
+
+ flag {
+ name: "enable_input_event_tracing"
+ namespace: "input"
+ description: "Set to true to enable input event tracing, including always-on tracing on non-user builds"
+ bug: "210460522"
}
flag {
@@ -52,15 +60,15 @@ flag {
flag {
name: "enable_touchpad_typing_palm_rejection"
namespace: "input"
- description: "Enable additional palm rejection on touchpad while typing"
+ description: "Enabling additional touchpad palm rejection will disable the tap to click while the user is typing on a physical keyboard"
bug: "301055381"
}
flag {
- name: "remove_app_switch_drops"
+ name: "enable_v2_touchpad_typing_palm_rejection"
namespace: "input"
- description: "Remove the logic of dropping events due to pending app switch"
- bug: "284808102"
+ description: "In addition to touchpad palm rejection v1, v2 will also cancel ongoing move gestures while typing and add delay in re-enabling the tap to click."
+ bug: "301055381"
}
flag {
@@ -90,3 +98,31 @@ flag {
description: "Remove pointer event tracking in WM after the Pointer Icon Refactor"
bug: "315321016"
}
+
+flag {
+ name: "enable_new_mouse_pointer_ballistics"
+ namespace: "input"
+ description: "Change the acceleration curves for mouse pointer movements to match the touchpad ones"
+ bug: "315313622"
+}
+
+flag {
+ name: "rate_limit_user_activity_poke_in_dispatcher"
+ namespace: "input"
+ description: "Move user-activity poke rate-limiting from PowerManagerService to InputDispatcher."
+ bug: "320499729"
+}
+
+flag {
+ name: "input_device_view_behavior_api"
+ namespace: "input"
+ description: "Controls the API to provide InputDevice view behavior."
+ bug: "246946631"
+}
+
+flag {
+ name: "enable_touchpad_fling_stop"
+ namespace: "input"
+ description: "Enable fling scrolling to be stopped by putting a finger on the touchpad again"
+ bug: "281106755"
+}
diff --git a/libs/input/tests/Android.bp b/libs/input/tests/Android.bp
index 13cfb491b5..93af4c2066 100644
--- a/libs/input/tests/Android.bp
+++ b/libs/input/tests/Android.bp
@@ -13,6 +13,7 @@ cc_test {
cpp_std: "c++20",
host_supported: true,
srcs: [
+ "BlockingQueue_test.cpp",
"IdGenerator_test.cpp",
"InputChannel_test.cpp",
"InputDevice_test.cpp",
@@ -25,6 +26,7 @@ cc_test {
"TfLiteMotionPredictor_test.cpp",
"TouchResampling_test.cpp",
"TouchVideoFrame_test.cpp",
+ "VelocityControl_test.cpp",
"VelocityTracker_test.cpp",
"VerifiedInputEvent_test.cpp",
],
diff --git a/libs/input/tests/BlockingQueue_test.cpp b/libs/input/tests/BlockingQueue_test.cpp
new file mode 100644
index 0000000000..924b937080
--- /dev/null
+++ b/libs/input/tests/BlockingQueue_test.cpp
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2019 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 <input/BlockingQueue.h>
+
+#include <gtest/gtest.h>
+#include <thread>
+
+namespace android {
+
+using std::chrono_literals::operator""ns;
+
+// --- BlockingQueueTest ---
+
+/**
+ * Validate basic pop and push operation.
+ */
+TEST(BlockingQueueTest, Queue_AddAndRemove) {
+ constexpr size_t capacity = 10;
+ BlockingQueue<int> queue(capacity);
+
+ ASSERT_TRUE(queue.push(1));
+ ASSERT_EQ(queue.pop(), 1);
+
+ ASSERT_TRUE(queue.emplace(2));
+ ASSERT_EQ(queue.popWithTimeout(0ns), 2);
+
+ ASSERT_TRUE(queue.push(3));
+ ASSERT_EQ(queue.popWithTimeout(100ns), 3);
+
+ ASSERT_EQ(std::nullopt, queue.popWithTimeout(0ns));
+}
+
+/**
+ * Make sure the queue has strict capacity limits.
+ */
+TEST(BlockingQueueTest, Queue_ReachesCapacity) {
+ constexpr size_t capacity = 3;
+ BlockingQueue<int> queue(capacity);
+
+ // First 3 elements should be added successfully
+ ASSERT_TRUE(queue.push(1));
+ ASSERT_TRUE(queue.push(2));
+ ASSERT_TRUE(queue.push(3));
+ ASSERT_FALSE(queue.push(4)) << "Queue should reach capacity at size " << capacity;
+}
+
+/**
+ * Make sure the queue maintains FIFO order.
+ * Add elements and remove them, and check the order.
+ */
+TEST(BlockingQueueTest, Queue_isFIFO) {
+ constexpr size_t capacity = 10;
+ BlockingQueue<int> queue(capacity);
+
+ for (size_t i = 0; i < capacity; i++) {
+ ASSERT_TRUE(queue.push(static_cast<int>(i)));
+ }
+ for (size_t i = 0; i < capacity; i++) {
+ ASSERT_EQ(queue.pop(), static_cast<int>(i));
+ }
+}
+
+TEST(BlockingQueueTest, Queue_Clears) {
+ constexpr size_t capacity = 2;
+ BlockingQueue<int> queue(capacity);
+
+ queue.push(1);
+ queue.push(2);
+ queue.clear();
+ queue.push(3);
+ // Should no longer receive elements 1 and 2
+ ASSERT_EQ(3, queue.pop());
+}
+
+TEST(BlockingQueueTest, Queue_Erases) {
+ constexpr size_t capacity = 4;
+ BlockingQueue<int> queue(capacity);
+
+ queue.push(1);
+ queue.push(2);
+ queue.push(3);
+ queue.push(4);
+ // Erase elements 2 and 4
+ queue.erase_if([](int element) { return element == 2 || element == 4; });
+ // Should no longer receive elements 2 and 4
+ ASSERT_EQ(1, queue.pop());
+ ASSERT_EQ(3, queue.pop());
+}
+
+// --- BlockingQueueTest - Multiple threads ---
+
+TEST(BlockingQueueTest, Queue_AllowsMultipleThreads) {
+ constexpr size_t capacity = 100; // large capacity to increase likelihood that threads overlap
+ BlockingQueue<int> queue(capacity);
+
+ // Fill queue from a different thread
+ std::thread fillQueue([&queue]() {
+ for (size_t i = 0; i < capacity; i++) {
+ ASSERT_TRUE(queue.push(static_cast<int>(i)));
+ }
+ });
+
+ // Make sure all elements are received in correct order
+ for (size_t i = 0; i < capacity; i++) {
+ ASSERT_EQ(queue.pop(), static_cast<int>(i));
+ }
+
+ fillQueue.join();
+}
+
+/**
+ * When the queue has no elements, and pop is called, it should block
+ * the current thread until an element is added to the queue (from another thread).
+ * Here we create a separate thread and call pop on an empty queue. Next,
+ * we check that the thread is blocked.
+ */
+TEST(BlockingQueueTest, Queue_BlocksWhileWaitingForElements) {
+ constexpr size_t capacity = 1;
+ BlockingQueue<int> queue(capacity);
+
+ std::atomic_bool hasReceivedElement = false;
+
+ // fill queue from a different thread
+ std::thread waitUntilHasElements([&queue, &hasReceivedElement]() {
+ queue.pop(); // This should block until an element has been added
+ hasReceivedElement = true;
+ });
+
+ ASSERT_FALSE(hasReceivedElement);
+ queue.push(1);
+ waitUntilHasElements.join();
+ ASSERT_TRUE(hasReceivedElement);
+}
+
+TEST(BlockingQueueTest, Queue_TimesOut) {
+ BlockingQueue<int> queue;
+ ASSERT_EQ(std::nullopt, queue.popWithTimeout(1ns));
+}
+
+} // namespace android
diff --git a/libs/input/tests/InputChannel_test.cpp b/libs/input/tests/InputChannel_test.cpp
index 0661261003..02d4c07bfa 100644
--- a/libs/input/tests/InputChannel_test.cpp
+++ b/libs/input/tests/InputChannel_test.cpp
@@ -16,8 +16,6 @@
#include <array>
-#include "TestHelpers.h"
-
#include <unistd.h>
#include <time.h>
#include <errno.h>
@@ -32,37 +30,31 @@
namespace android {
+namespace {
+bool operator==(const InputChannel& left, const InputChannel& right) {
+ struct stat lhs, rhs;
+ if (fstat(left.getFd(), &lhs) != 0) {
+ return false;
+ }
+ if (fstat(right.getFd(), &rhs) != 0) {
+ return false;
+ }
+ // If file descriptors are pointing to same inode they are duplicated fds.
+ return left.getName() == right.getName() &&
+ left.getConnectionToken() == right.getConnectionToken() && lhs.st_ino == rhs.st_ino;
+}
+} // namespace
+
class InputChannelTest : public testing::Test {
};
+TEST_F(InputChannelTest, ClientAndServerTokensMatch) {
+ std::unique_ptr<InputChannel> serverChannel, clientChannel;
-TEST_F(InputChannelTest, ConstructorAndDestructor_TakesOwnershipOfFileDescriptors) {
- // Our purpose here is to verify that the input channel destructor closes the
- // file descriptor provided to it. One easy way is to provide it with one end
- // of a pipe and to check for EPIPE on the other end after the channel is destroyed.
- Pipe pipe;
-
- android::base::unique_fd sendFd(pipe.sendFd);
-
- std::unique_ptr<InputChannel> inputChannel =
- InputChannel::create("channel name", std::move(sendFd), new BBinder());
-
- EXPECT_NE(inputChannel, nullptr) << "channel should be successfully created";
- EXPECT_STREQ("channel name", inputChannel->getName().c_str())
- << "channel should have provided name";
- EXPECT_NE(-1, inputChannel->getFd()) << "channel should have valid fd";
-
- // InputChannel should be the owner of the file descriptor now
- ASSERT_FALSE(sendFd.ok());
-}
-
-TEST_F(InputChannelTest, SetAndGetToken) {
- Pipe pipe;
- sp<IBinder> token = new BBinder();
- std::unique_ptr<InputChannel> channel =
- InputChannel::create("test channel", android::base::unique_fd(pipe.sendFd), token);
-
- EXPECT_EQ(token, channel->getConnectionToken());
+ status_t result =
+ InputChannel::openInputChannelPair("channel name", serverChannel, clientChannel);
+ ASSERT_EQ(OK, result) << "should have successfully opened a channel pair";
+ EXPECT_EQ(serverChannel->getConnectionToken(), clientChannel->getConnectionToken());
}
TEST_F(InputChannelTest, OpenInputChannelPair_ReturnsAPairOfConnectedChannels) {
@@ -71,8 +63,7 @@ TEST_F(InputChannelTest, OpenInputChannelPair_ReturnsAPairOfConnectedChannels) {
status_t result = InputChannel::openInputChannelPair("channel name",
serverChannel, clientChannel);
- ASSERT_EQ(OK, result)
- << "should have successfully opened a channel pair";
+ ASSERT_EQ(OK, result) << "should have successfully opened a channel pair";
// Name
EXPECT_STREQ("channel name (server)", serverChannel->getName().c_str())
@@ -81,8 +72,7 @@ TEST_F(InputChannelTest, OpenInputChannelPair_ReturnsAPairOfConnectedChannels) {
<< "client channel should have suffixed name";
// Server->Client communication
- InputMessage serverMsg;
- memset(&serverMsg, 0, sizeof(InputMessage));
+ InputMessage serverMsg = {};
serverMsg.header.type = InputMessage::Type::KEY;
serverMsg.body.key.action = AKEY_EVENT_ACTION_DOWN;
EXPECT_EQ(OK, serverChannel->sendMessage(&serverMsg))
@@ -97,8 +87,7 @@ TEST_F(InputChannelTest, OpenInputChannelPair_ReturnsAPairOfConnectedChannels) {
<< "client channel should receive the correct message from server channel";
// Client->Server communication
- InputMessage clientReply;
- memset(&clientReply, 0, sizeof(InputMessage));
+ InputMessage clientReply = {};
clientReply.header.type = InputMessage::Type::FINISHED;
clientReply.header.seq = 0x11223344;
clientReply.body.finished.handled = true;
@@ -116,6 +105,48 @@ TEST_F(InputChannelTest, OpenInputChannelPair_ReturnsAPairOfConnectedChannels) {
<< "server channel should receive the correct message from client channel";
}
+TEST_F(InputChannelTest, ProbablyHasInput) {
+ std::unique_ptr<InputChannel> senderChannel, receiverChannel;
+
+ // Open a pair of channels.
+ status_t result =
+ InputChannel::openInputChannelPair("channel name", senderChannel, receiverChannel);
+ ASSERT_EQ(OK, result) << "should have successfully opened a channel pair";
+
+ ASSERT_FALSE(receiverChannel->probablyHasInput());
+
+ // Send one message.
+ InputMessage serverMsg = {};
+ serverMsg.header.type = InputMessage::Type::KEY;
+ serverMsg.body.key.action = AKEY_EVENT_ACTION_DOWN;
+ EXPECT_EQ(OK, senderChannel->sendMessage(&serverMsg))
+ << "server channel should be able to send message to client channel";
+
+ // Verify input is available.
+ bool hasInput = false;
+ do {
+ // The probablyHasInput() can return false positive under rare circumstances uncontrollable
+ // by the tests. Re-request the availability in this case. Returning |false| for a long
+ // time is not intended, and would cause a test timeout.
+ hasInput = receiverChannel->probablyHasInput();
+ } while (!hasInput);
+ EXPECT_TRUE(hasInput)
+ << "client channel should observe that message is available before receiving it";
+
+ // Receive (consume) the message.
+ InputMessage clientMsg;
+ EXPECT_EQ(OK, receiverChannel->receiveMessage(&clientMsg))
+ << "client channel should be able to receive message from server channel";
+ EXPECT_EQ(serverMsg.header.type, clientMsg.header.type)
+ << "client channel should receive the correct message from server channel";
+ EXPECT_EQ(serverMsg.body.key.action, clientMsg.body.key.action)
+ << "client channel should receive the correct message from server channel";
+
+ // Verify input is not available.
+ EXPECT_FALSE(receiverChannel->probablyHasInput())
+ << "client should not observe any more messages after receiving the single one";
+}
+
TEST_F(InputChannelTest, ReceiveSignal_WhenNoSignalPresent_ReturnsAnError) {
std::unique_ptr<InputChannel> serverChannel, clientChannel;
@@ -195,25 +226,6 @@ TEST_F(InputChannelTest, SendAndReceive_MotionClassification) {
}
}
-TEST_F(InputChannelTest, InputChannelParcelAndUnparcel) {
- std::unique_ptr<InputChannel> serverChannel, clientChannel;
-
- status_t result =
- InputChannel::openInputChannelPair("channel parceling", serverChannel, clientChannel);
-
- ASSERT_EQ(OK, result) << "should have successfully opened a channel pair";
-
- InputChannel chan;
- Parcel parcel;
- ASSERT_EQ(OK, serverChannel->writeToParcel(&parcel));
- parcel.setDataPosition(0);
- chan.readFromParcel(&parcel);
-
- EXPECT_EQ(chan == *serverChannel, true)
- << "inputchannel should be equal after parceling and unparceling.\n"
- << "name " << chan.getName() << " name " << serverChannel->getName();
-}
-
TEST_F(InputChannelTest, DuplicateChannelAndAssertEqual) {
std::unique_ptr<InputChannel> serverChannel, clientChannel;
diff --git a/libs/input/tests/InputEvent_test.cpp b/libs/input/tests/InputEvent_test.cpp
index a9655730fc..0df06b790e 100644
--- a/libs/input/tests/InputEvent_test.cpp
+++ b/libs/input/tests/InputEvent_test.cpp
@@ -23,6 +23,7 @@
#include <gtest/gtest.h>
#include <gui/constants.h>
#include <input/Input.h>
+#include <input/InputEventBuilders.h>
namespace android {
@@ -31,6 +32,18 @@ static constexpr int32_t DISPLAY_ID = ADISPLAY_ID_DEFAULT;
static constexpr float EPSILON = MotionEvent::ROUNDING_PRECISION;
+static constexpr auto POINTER_0_DOWN =
+ AMOTION_EVENT_ACTION_POINTER_DOWN | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
+
+static constexpr auto POINTER_1_DOWN =
+ AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
+
+static constexpr auto POINTER_0_UP =
+ AMOTION_EVENT_ACTION_POINTER_UP | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
+
+static constexpr auto POINTER_1_UP =
+ AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
+
class BaseTest : public testing::Test {
protected:
static constexpr std::array<uint8_t, 32> HMAC = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
@@ -358,8 +371,10 @@ void MotionEventTest::assertEqualsEventWithHistory(const MotionEvent* event) {
ASSERT_EQ(AMOTION_EVENT_BUTTON_PRIMARY, event->getButtonState());
ASSERT_EQ(MotionClassification::NONE, event->getClassification());
EXPECT_EQ(mTransform, event->getTransform());
- ASSERT_EQ(X_OFFSET, event->getXOffset());
- ASSERT_EQ(Y_OFFSET, event->getYOffset());
+ ASSERT_NEAR((-RAW_X_OFFSET / RAW_X_SCALE) * X_SCALE + X_OFFSET, event->getRawXOffset(),
+ EPSILON);
+ ASSERT_NEAR((-RAW_Y_OFFSET / RAW_Y_SCALE) * Y_SCALE + Y_OFFSET, event->getRawYOffset(),
+ EPSILON);
ASSERT_EQ(2.0f, event->getXPrecision());
ASSERT_EQ(2.1f, event->getYPrecision());
ASSERT_EQ(ARBITRARY_DOWN_TIME, event->getDownTime());
@@ -554,25 +569,168 @@ TEST_F(MotionEventTest, CopyFrom_DoNotKeepHistory) {
ASSERT_EQ(event.getX(0), copy.getX(0));
}
+TEST_F(MotionEventTest, SplitPointerDown) {
+ MotionEvent event = MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
+ .downTime(ARBITRARY_DOWN_TIME)
+ .pointer(PointerBuilder(/*id=*/4, ToolType::FINGER).x(4).y(4))
+ .pointer(PointerBuilder(/*id=*/6, ToolType::FINGER).x(6).y(6))
+ .pointer(PointerBuilder(/*id=*/8, ToolType::FINGER).x(8).y(8))
+ .build();
+
+ MotionEvent splitDown;
+ std::bitset<MAX_POINTER_ID + 1> splitDownIds{};
+ splitDownIds.set(6, true);
+ splitDown.splitFrom(event, splitDownIds, /*eventId=*/42);
+ ASSERT_EQ(splitDown.getAction(), AMOTION_EVENT_ACTION_DOWN);
+ ASSERT_EQ(splitDown.getPointerCount(), 1u);
+ ASSERT_EQ(splitDown.getPointerId(0), 6);
+ ASSERT_EQ(splitDown.getX(0), 6);
+ ASSERT_EQ(splitDown.getY(0), 6);
+
+ MotionEvent splitPointerDown;
+ std::bitset<MAX_POINTER_ID + 1> splitPointerDownIds{};
+ splitPointerDownIds.set(6, true);
+ splitPointerDownIds.set(8, true);
+ splitPointerDown.splitFrom(event, splitPointerDownIds, /*eventId=*/42);
+ ASSERT_EQ(splitPointerDown.getAction(), POINTER_0_DOWN);
+ ASSERT_EQ(splitPointerDown.getPointerCount(), 2u);
+ ASSERT_EQ(splitPointerDown.getPointerId(0), 6);
+ ASSERT_EQ(splitPointerDown.getX(0), 6);
+ ASSERT_EQ(splitPointerDown.getY(0), 6);
+ ASSERT_EQ(splitPointerDown.getPointerId(1), 8);
+ ASSERT_EQ(splitPointerDown.getX(1), 8);
+ ASSERT_EQ(splitPointerDown.getY(1), 8);
+
+ MotionEvent splitMove;
+ std::bitset<MAX_POINTER_ID + 1> splitMoveIds{};
+ splitMoveIds.set(4, true);
+ splitMove.splitFrom(event, splitMoveIds, /*eventId=*/43);
+ ASSERT_EQ(splitMove.getAction(), AMOTION_EVENT_ACTION_MOVE);
+ ASSERT_EQ(splitMove.getPointerCount(), 1u);
+ ASSERT_EQ(splitMove.getPointerId(0), 4);
+ ASSERT_EQ(splitMove.getX(0), 4);
+ ASSERT_EQ(splitMove.getY(0), 4);
+}
+
+TEST_F(MotionEventTest, SplitPointerUp) {
+ MotionEvent event = MotionEventBuilder(POINTER_0_UP, AINPUT_SOURCE_TOUCHSCREEN)
+ .downTime(ARBITRARY_DOWN_TIME)
+ .pointer(PointerBuilder(/*id=*/4, ToolType::FINGER).x(4).y(4))
+ .pointer(PointerBuilder(/*id=*/6, ToolType::FINGER).x(6).y(6))
+ .pointer(PointerBuilder(/*id=*/8, ToolType::FINGER).x(8).y(8))
+ .build();
+
+ MotionEvent splitUp;
+ std::bitset<MAX_POINTER_ID + 1> splitUpIds{};
+ splitUpIds.set(4, true);
+ splitUp.splitFrom(event, splitUpIds, /*eventId=*/42);
+ ASSERT_EQ(splitUp.getAction(), AMOTION_EVENT_ACTION_UP);
+ ASSERT_EQ(splitUp.getPointerCount(), 1u);
+ ASSERT_EQ(splitUp.getPointerId(0), 4);
+ ASSERT_EQ(splitUp.getX(0), 4);
+ ASSERT_EQ(splitUp.getY(0), 4);
+
+ MotionEvent splitPointerUp;
+ std::bitset<MAX_POINTER_ID + 1> splitPointerUpIds{};
+ splitPointerUpIds.set(4, true);
+ splitPointerUpIds.set(8, true);
+ splitPointerUp.splitFrom(event, splitPointerUpIds, /*eventId=*/42);
+ ASSERT_EQ(splitPointerUp.getAction(), POINTER_0_UP);
+ ASSERT_EQ(splitPointerUp.getPointerCount(), 2u);
+ ASSERT_EQ(splitPointerUp.getPointerId(0), 4);
+ ASSERT_EQ(splitPointerUp.getX(0), 4);
+ ASSERT_EQ(splitPointerUp.getY(0), 4);
+ ASSERT_EQ(splitPointerUp.getPointerId(1), 8);
+ ASSERT_EQ(splitPointerUp.getX(1), 8);
+ ASSERT_EQ(splitPointerUp.getY(1), 8);
+
+ MotionEvent splitMove;
+ std::bitset<MAX_POINTER_ID + 1> splitMoveIds{};
+ splitMoveIds.set(6, true);
+ splitMoveIds.set(8, true);
+ splitMove.splitFrom(event, splitMoveIds, /*eventId=*/43);
+ ASSERT_EQ(splitMove.getAction(), AMOTION_EVENT_ACTION_MOVE);
+ ASSERT_EQ(splitMove.getPointerCount(), 2u);
+ ASSERT_EQ(splitMove.getPointerId(0), 6);
+ ASSERT_EQ(splitMove.getX(0), 6);
+ ASSERT_EQ(splitMove.getY(0), 6);
+ ASSERT_EQ(splitMove.getPointerId(1), 8);
+ ASSERT_EQ(splitMove.getX(1), 8);
+ ASSERT_EQ(splitMove.getY(1), 8);
+}
+
+TEST_F(MotionEventTest, SplitPointerUpCancel) {
+ MotionEvent event = MotionEventBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN)
+ .downTime(ARBITRARY_DOWN_TIME)
+ .pointer(PointerBuilder(/*id=*/4, ToolType::FINGER).x(4).y(4))
+ .pointer(PointerBuilder(/*id=*/6, ToolType::FINGER).x(6).y(6))
+ .pointer(PointerBuilder(/*id=*/8, ToolType::FINGER).x(8).y(8))
+ .addFlag(AMOTION_EVENT_FLAG_CANCELED)
+ .build();
+
+ MotionEvent splitUp;
+ std::bitset<MAX_POINTER_ID + 1> splitUpIds{};
+ splitUpIds.set(6, true);
+ splitUp.splitFrom(event, splitUpIds, /*eventId=*/42);
+ ASSERT_EQ(splitUp.getAction(), AMOTION_EVENT_ACTION_CANCEL);
+ ASSERT_EQ(splitUp.getPointerCount(), 1u);
+ ASSERT_EQ(splitUp.getPointerId(0), 6);
+ ASSERT_EQ(splitUp.getX(0), 6);
+ ASSERT_EQ(splitUp.getY(0), 6);
+}
+
+TEST_F(MotionEventTest, SplitPointerMove) {
+ MotionEvent event = MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
+ .downTime(ARBITRARY_DOWN_TIME)
+ .pointer(PointerBuilder(/*id=*/4, ToolType::FINGER).x(4).y(4))
+ .pointer(PointerBuilder(/*id=*/6, ToolType::FINGER).x(6).y(6))
+ .pointer(PointerBuilder(/*id=*/8, ToolType::FINGER).x(8).y(8))
+ .transform(ui::Transform(ui::Transform::ROT_90, 100, 100))
+ .rawTransform(ui::Transform(ui::Transform::FLIP_H, 50, 50))
+ .build();
+
+ MotionEvent splitMove;
+ std::bitset<MAX_POINTER_ID + 1> splitMoveIds{};
+ splitMoveIds.set(4, true);
+ splitMoveIds.set(8, true);
+ splitMove.splitFrom(event, splitMoveIds, /*eventId=*/42);
+ ASSERT_EQ(splitMove.getAction(), AMOTION_EVENT_ACTION_MOVE);
+ ASSERT_EQ(splitMove.getPointerCount(), 2u);
+ ASSERT_EQ(splitMove.getPointerId(0), 4);
+ ASSERT_EQ(splitMove.getX(0), event.getX(0));
+ ASSERT_EQ(splitMove.getY(0), event.getY(0));
+ ASSERT_EQ(splitMove.getRawX(0), event.getRawX(0));
+ ASSERT_EQ(splitMove.getRawY(0), event.getRawY(0));
+ ASSERT_EQ(splitMove.getPointerId(1), 8);
+ ASSERT_EQ(splitMove.getX(1), event.getX(2));
+ ASSERT_EQ(splitMove.getY(1), event.getY(2));
+ ASSERT_EQ(splitMove.getRawX(1), event.getRawX(2));
+ ASSERT_EQ(splitMove.getRawY(1), event.getRawY(2));
+}
+
TEST_F(MotionEventTest, OffsetLocation) {
MotionEvent event;
initializeEventWithHistory(&event);
+ const float xOffset = event.getRawXOffset();
+ const float yOffset = event.getRawYOffset();
event.offsetLocation(5.0f, -2.0f);
- ASSERT_EQ(X_OFFSET + 5.0f, event.getXOffset());
- ASSERT_EQ(Y_OFFSET - 2.0f, event.getYOffset());
+ ASSERT_EQ(xOffset + 5.0f, event.getRawXOffset());
+ ASSERT_EQ(yOffset - 2.0f, event.getRawYOffset());
}
TEST_F(MotionEventTest, Scale) {
MotionEvent event;
initializeEventWithHistory(&event);
const float unscaledOrientation = event.getOrientation(0);
+ const float unscaledXOffset = event.getRawXOffset();
+ const float unscaledYOffset = event.getRawYOffset();
event.scale(2.0f);
- ASSERT_EQ(X_OFFSET * 2, event.getXOffset());
- ASSERT_EQ(Y_OFFSET * 2, event.getYOffset());
+ ASSERT_EQ(unscaledXOffset * 2, event.getRawXOffset());
+ ASSERT_EQ(unscaledYOffset * 2, event.getRawYOffset());
ASSERT_NEAR((RAW_X_OFFSET + 210 * RAW_X_SCALE) * 2, event.getRawX(0), EPSILON);
ASSERT_NEAR((RAW_Y_OFFSET + 211 * RAW_Y_SCALE) * 2, event.getRawY(0), EPSILON);
diff --git a/libs/input/tests/InputPublisherAndConsumer_test.cpp b/libs/input/tests/InputPublisherAndConsumer_test.cpp
index 06b841be0d..b5fab496e2 100644
--- a/libs/input/tests/InputPublisherAndConsumer_test.cpp
+++ b/libs/input/tests/InputPublisherAndConsumer_test.cpp
@@ -14,8 +14,6 @@
* limitations under the License.
*/
-#include "TestHelpers.h"
-
#include <attestation/HmacKeyManager.h>
#include <gtest/gtest.h>
#include <gui/constants.h>
@@ -40,11 +38,188 @@ struct Pointer {
bool isResampled = false;
};
+// A collection of arguments to be sent as publishMotionEvent(). The saved members of this struct
+// allow to check the expectations against the event acquired from the InputReceiver. To help
+// simplify expectation checking it carries members not present in MotionEvent, like |rawXScale|.
+struct PublishMotionArgs {
+ const int32_t action;
+ const nsecs_t downTime;
+ const uint32_t seq;
+ const int32_t eventId;
+ const int32_t deviceId = 1;
+ const uint32_t source = AINPUT_SOURCE_TOUCHSCREEN;
+ const int32_t displayId = ADISPLAY_ID_DEFAULT;
+ const int32_t actionButton = 0;
+ const int32_t edgeFlags = AMOTION_EVENT_EDGE_FLAG_TOP;
+ const int32_t metaState = AMETA_ALT_LEFT_ON | AMETA_ALT_ON;
+ const int32_t buttonState = AMOTION_EVENT_BUTTON_PRIMARY;
+ const MotionClassification classification = MotionClassification::AMBIGUOUS_GESTURE;
+ const float xScale = 2;
+ const float yScale = 3;
+ const float xOffset = -10;
+ const float yOffset = -20;
+ const float rawXScale = 4;
+ const float rawYScale = -5;
+ const float rawXOffset = -11;
+ const float rawYOffset = 42;
+ const float xPrecision = 0.25;
+ const float yPrecision = 0.5;
+ const float xCursorPosition = 1.3;
+ const float yCursorPosition = 50.6;
+ std::array<uint8_t, 32> hmac;
+ int32_t flags;
+ ui::Transform transform;
+ ui::Transform rawTransform;
+ const nsecs_t eventTime;
+ size_t pointerCount;
+ std::vector<PointerProperties> pointerProperties;
+ std::vector<PointerCoords> pointerCoords;
+
+ PublishMotionArgs(int32_t action, nsecs_t downTime, const std::vector<Pointer>& pointers,
+ const uint32_t seq);
+};
+
+PublishMotionArgs::PublishMotionArgs(int32_t inAction, nsecs_t inDownTime,
+ const std::vector<Pointer>& pointers, const uint32_t inSeq)
+ : action(inAction),
+ downTime(inDownTime),
+ seq(inSeq),
+ eventId(InputEvent::nextId()),
+ eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) {
+ hmac = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
+
+ flags = AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED;
+ if (action == AMOTION_EVENT_ACTION_CANCEL) {
+ flags |= AMOTION_EVENT_FLAG_CANCELED;
+ }
+ pointerCount = pointers.size();
+ for (size_t i = 0; i < pointerCount; i++) {
+ pointerProperties.push_back({});
+ pointerProperties[i].clear();
+ pointerProperties[i].id = pointers[i].id;
+ pointerProperties[i].toolType = ToolType::FINGER;
+
+ pointerCoords.push_back({});
+ pointerCoords[i].clear();
+ pointerCoords[i].isResampled = pointers[i].isResampled;
+ pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_X, pointers[i].x);
+ pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_Y, pointers[i].y);
+ pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 0.5 * i);
+ pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_SIZE, 0.7 * i);
+ pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, 1.5 * i);
+ pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, 1.7 * i);
+ pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 2.5 * i);
+ pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 2.7 * i);
+ pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 3.5 * i);
+ }
+ transform.set({xScale, 0, xOffset, 0, yScale, yOffset, 0, 0, 1});
+ rawTransform.set({rawXScale, 0, rawXOffset, 0, rawYScale, rawYOffset, 0, 0, 1});
+}
+
+// Checks expectations against |motionEvent| acquired from an InputConsumer. Floating point
+// comparisons limit precision to EPSILON.
+void verifyArgsEqualToEvent(const PublishMotionArgs& args, const MotionEvent& motionEvent) {
+ EXPECT_EQ(args.eventId, motionEvent.getId());
+ EXPECT_EQ(args.deviceId, motionEvent.getDeviceId());
+ EXPECT_EQ(args.source, motionEvent.getSource());
+ EXPECT_EQ(args.displayId, motionEvent.getDisplayId());
+ EXPECT_EQ(args.hmac, motionEvent.getHmac());
+ EXPECT_EQ(args.action, motionEvent.getAction());
+ EXPECT_EQ(args.downTime, motionEvent.getDownTime());
+ EXPECT_EQ(args.flags, motionEvent.getFlags());
+ EXPECT_EQ(args.edgeFlags, motionEvent.getEdgeFlags());
+ EXPECT_EQ(args.metaState, motionEvent.getMetaState());
+ EXPECT_EQ(args.buttonState, motionEvent.getButtonState());
+ EXPECT_EQ(args.classification, motionEvent.getClassification());
+ EXPECT_EQ(args.transform, motionEvent.getTransform());
+ EXPECT_NEAR((-args.rawXOffset / args.rawXScale) * args.xScale + args.xOffset,
+ motionEvent.getRawXOffset(), EPSILON);
+ EXPECT_NEAR((-args.rawYOffset / args.rawYScale) * args.yScale + args.yOffset,
+ motionEvent.getRawYOffset(), EPSILON);
+ EXPECT_EQ(args.xPrecision, motionEvent.getXPrecision());
+ EXPECT_EQ(args.yPrecision, motionEvent.getYPrecision());
+ EXPECT_NEAR(args.xCursorPosition, motionEvent.getRawXCursorPosition(), EPSILON);
+ EXPECT_NEAR(args.yCursorPosition, motionEvent.getRawYCursorPosition(), EPSILON);
+ EXPECT_NEAR(args.xCursorPosition * args.xScale + args.xOffset, motionEvent.getXCursorPosition(),
+ EPSILON);
+ EXPECT_NEAR(args.yCursorPosition * args.yScale + args.yOffset, motionEvent.getYCursorPosition(),
+ EPSILON);
+ EXPECT_EQ(args.rawTransform, motionEvent.getRawTransform());
+ EXPECT_EQ(args.eventTime, motionEvent.getEventTime());
+ EXPECT_EQ(args.pointerCount, motionEvent.getPointerCount());
+ EXPECT_EQ(0U, motionEvent.getHistorySize());
+
+ for (size_t i = 0; i < args.pointerCount; i++) {
+ SCOPED_TRACE(i);
+ EXPECT_EQ(args.pointerProperties[i].id, motionEvent.getPointerId(i));
+ EXPECT_EQ(args.pointerProperties[i].toolType, motionEvent.getToolType(i));
+
+ const auto& pc = args.pointerCoords[i];
+ EXPECT_EQ(pc, motionEvent.getSamplePointerCoords()[i]);
+
+ EXPECT_NEAR(pc.getX() * args.rawXScale + args.rawXOffset, motionEvent.getRawX(i), EPSILON);
+ EXPECT_NEAR(pc.getY() * args.rawYScale + args.rawYOffset, motionEvent.getRawY(i), EPSILON);
+ EXPECT_NEAR(pc.getX() * args.xScale + args.xOffset, motionEvent.getX(i), EPSILON);
+ EXPECT_NEAR(pc.getY() * args.yScale + args.yOffset, motionEvent.getY(i), EPSILON);
+ EXPECT_EQ(pc.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE), motionEvent.getPressure(i));
+ EXPECT_EQ(pc.getAxisValue(AMOTION_EVENT_AXIS_SIZE), motionEvent.getSize(i));
+ EXPECT_EQ(pc.getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR), motionEvent.getTouchMajor(i));
+ EXPECT_EQ(pc.getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR), motionEvent.getTouchMinor(i));
+ EXPECT_EQ(pc.getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR), motionEvent.getToolMajor(i));
+ EXPECT_EQ(pc.getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR), motionEvent.getToolMinor(i));
+
+ // Calculate the orientation after scaling, keeping in mind that an orientation of 0 is
+ // "up", and the positive y direction is "down".
+ const float unscaledOrientation = pc.getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION);
+ const float x = sinf(unscaledOrientation) * args.xScale;
+ const float y = -cosf(unscaledOrientation) * args.yScale;
+ EXPECT_EQ(atan2f(x, -y), motionEvent.getOrientation(i));
+ }
+}
+
+void publishMotionEvent(InputPublisher& publisher, const PublishMotionArgs& a) {
+ status_t status =
+ publisher.publishMotionEvent(a.seq, a.eventId, a.deviceId, a.source, a.displayId,
+ a.hmac, a.action, a.actionButton, a.flags, a.edgeFlags,
+ a.metaState, a.buttonState, a.classification, a.transform,
+ a.xPrecision, a.yPrecision, a.xCursorPosition,
+ a.yCursorPosition, a.rawTransform, a.downTime, a.eventTime,
+ a.pointerCount, a.pointerProperties.data(),
+ a.pointerCoords.data());
+ ASSERT_EQ(OK, status) << "publisher publishMotionEvent should return OK";
+}
+
+void sendAndVerifyFinishedSignal(InputConsumer& consumer, InputPublisher& publisher, uint32_t seq,
+ nsecs_t publishTime) {
+ status_t status = consumer.sendFinishedSignal(seq, false);
+ ASSERT_EQ(OK, status) << "consumer sendFinishedSignal should return OK";
+ Result<InputPublisher::ConsumerResponse> result = publisher.receiveConsumerResponse();
+ ASSERT_TRUE(result.ok()) << "receiveConsumerResponse should return OK";
+ ASSERT_TRUE(std::holds_alternative<InputPublisher::Finished>(*result));
+ const InputPublisher::Finished& finish = std::get<InputPublisher::Finished>(*result);
+ ASSERT_EQ(seq, finish.seq)
+ << "receiveConsumerResponse should have returned the original sequence number";
+ ASSERT_FALSE(finish.handled)
+ << "receiveConsumerResponse should have set handled to consumer's reply";
+ ASSERT_GE(finish.consumeTime, publishTime)
+ << "finished signal's consume time should be greater than publish time";
+}
+
+void waitUntilInputAvailable(const InputConsumer& inputConsumer) {
+ bool hasInput;
+ do {
+ // The probablyHasInput() can return false positive under rare circumstances uncontrollable
+ // by the tests. Re-request the availability in this case. Returning |false| for a long
+ // time is not intended, and would cause a test timeout.
+ hasInput = inputConsumer.probablyHasInput();
+ } while (!hasInput);
+}
+
} // namespace
class InputPublisherAndConsumerTest : public testing::Test {
protected:
- std::shared_ptr<InputChannel> mServerChannel, mClientChannel;
std::unique_ptr<InputPublisher> mPublisher;
std::unique_ptr<InputConsumer> mConsumer;
PreallocatedInputEventFactory mEventFactory;
@@ -54,15 +229,15 @@ protected:
status_t result = InputChannel::openInputChannelPair("channel name",
serverChannel, clientChannel);
ASSERT_EQ(OK, result);
- mServerChannel = std::move(serverChannel);
- mClientChannel = std::move(clientChannel);
- mPublisher = std::make_unique<InputPublisher>(mServerChannel);
- mConsumer = std::make_unique<InputConsumer>(mClientChannel);
+ mPublisher = std::make_unique<InputPublisher>(std::move(serverChannel));
+ mConsumer = std::make_unique<InputConsumer>(std::move(clientChannel));
}
void publishAndConsumeKeyEvent();
void publishAndConsumeMotionStream();
+ void publishAndConsumeMotionDown(nsecs_t downTime);
+ void publishAndConsumeBatchedMotionMove(nsecs_t downTime);
void publishAndConsumeFocusEvent();
void publishAndConsumeCaptureEvent();
void publishAndConsumeDragEvent();
@@ -73,24 +248,10 @@ protected:
private:
// The sequence number to use when publishing the next event
uint32_t mSeq = 1;
-
- void publishAndConsumeMotionEvent(
- int32_t deviceId, uint32_t source, int32_t displayId, std::array<uint8_t, 32> hmac,
- int32_t action, int32_t actionButton, int32_t flags, int32_t edgeFlags,
- int32_t metaState, int32_t buttonState, MotionClassification classification,
- float xScale, float yScale, float xOffset, float yOffset, float xPrecision,
- float yPrecision, float xCursorPosition, float yCursorPosition, float rawXScale,
- float rawYScale, float rawXOffset, float rawYOffset, nsecs_t downTime,
- nsecs_t eventTime, const std::vector<PointerProperties>& pointerProperties,
- const std::vector<PointerCoords>& pointerCoords);
};
TEST_F(InputPublisherAndConsumerTest, GetChannel_ReturnsTheChannel) {
- ASSERT_NE(nullptr, mPublisher->getChannel());
- ASSERT_NE(nullptr, mConsumer->getChannel());
- EXPECT_EQ(mServerChannel.get(), mPublisher->getChannel().get());
- EXPECT_EQ(mClientChannel.get(), mConsumer->getChannel().get());
- ASSERT_EQ(mPublisher->getChannel()->getConnectionToken(),
+ ASSERT_EQ(mPublisher->getChannel().getConnectionToken(),
mConsumer->getChannel()->getConnectionToken());
}
@@ -121,11 +282,14 @@ void InputPublisherAndConsumerTest::publishAndConsumeKeyEvent() {
ASSERT_EQ(OK, status)
<< "publisher publishKeyEvent should return OK";
+ waitUntilInputAvailable(*mConsumer);
uint32_t consumeSeq;
InputEvent* event;
status = mConsumer->consume(&mEventFactory, /*consumeBatches=*/true, -1, &consumeSeq, &event);
ASSERT_EQ(OK, status)
<< "consumer consume should return OK";
+ EXPECT_FALSE(mConsumer->probablyHasInput())
+ << "no events should be waiting after being consumed";
ASSERT_TRUE(event != nullptr)
<< "consumer should have returned non-NULL event";
@@ -185,176 +349,51 @@ void InputPublisherAndConsumerTest::publishAndConsumeMotionStream() {
Pointer{.id = 2, .x = 300, .y = 400}});
}
-void InputPublisherAndConsumerTest::publishAndConsumeMotionEvent(
- int32_t action, nsecs_t downTime, const std::vector<Pointer>& pointers) {
- constexpr int32_t deviceId = 1;
- constexpr uint32_t source = AINPUT_SOURCE_TOUCHSCREEN;
- constexpr int32_t displayId = ADISPLAY_ID_DEFAULT;
- constexpr std::array<uint8_t, 32> hmac = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
- 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
- 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
- constexpr int32_t actionButton = 0;
- int32_t flags = AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED;
-
- if (action == AMOTION_EVENT_ACTION_CANCEL) {
- flags |= AMOTION_EVENT_FLAG_CANCELED;
- }
- const size_t pointerCount = pointers.size();
- constexpr int32_t edgeFlags = AMOTION_EVENT_EDGE_FLAG_TOP;
- constexpr int32_t metaState = AMETA_ALT_LEFT_ON | AMETA_ALT_ON;
- constexpr int32_t buttonState = AMOTION_EVENT_BUTTON_PRIMARY;
- constexpr MotionClassification classification = MotionClassification::AMBIGUOUS_GESTURE;
- constexpr float xScale = 2;
- constexpr float yScale = 3;
- constexpr float xOffset = -10;
- constexpr float yOffset = -20;
- constexpr float rawXScale = 4;
- constexpr float rawYScale = -5;
- constexpr float rawXOffset = -11;
- constexpr float rawYOffset = 42;
- constexpr float xPrecision = 0.25;
- constexpr float yPrecision = 0.5;
- constexpr float xCursorPosition = 1.3;
- constexpr float yCursorPosition = 50.6;
-
- const nsecs_t eventTime = systemTime(SYSTEM_TIME_MONOTONIC);
- std::vector<PointerProperties> pointerProperties;
- std::vector<PointerCoords> pointerCoords;
- for (size_t i = 0; i < pointerCount; i++) {
- pointerProperties.push_back({});
- pointerProperties[i].clear();
- pointerProperties[i].id = pointers[i].id;
- pointerProperties[i].toolType = ToolType::FINGER;
+void InputPublisherAndConsumerTest::publishAndConsumeMotionDown(nsecs_t downTime) {
+ publishAndConsumeMotionEvent(AMOTION_EVENT_ACTION_DOWN, downTime,
+ {Pointer{.id = 0, .x = 20, .y = 30}});
+}
- pointerCoords.push_back({});
- pointerCoords[i].clear();
- pointerCoords[i].isResampled = pointers[i].isResampled;
- pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_X, pointers[i].x);
- pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_Y, pointers[i].y);
- pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 0.5 * i);
- pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_SIZE, 0.7 * i);
- pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, 1.5 * i);
- pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, 1.7 * i);
- pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 2.5 * i);
- pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 2.7 * i);
- pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 3.5 * i);
- }
+void InputPublisherAndConsumerTest::publishAndConsumeBatchedMotionMove(nsecs_t downTime) {
+ uint32_t seq = mSeq++;
+ const std::vector<Pointer> pointers = {Pointer{.id = 0, .x = 20, .y = 30}};
+ PublishMotionArgs args(AMOTION_EVENT_ACTION_MOVE, downTime, pointers, seq);
+ const nsecs_t publishTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ publishMotionEvent(*mPublisher, args);
- publishAndConsumeMotionEvent(deviceId, source, displayId, hmac, action, actionButton, flags,
- edgeFlags, metaState, buttonState, classification, xScale, yScale,
- xOffset, yOffset, xPrecision, yPrecision, xCursorPosition,
- yCursorPosition, rawXScale, rawYScale, rawXOffset, rawYOffset,
- downTime, eventTime, pointerProperties, pointerCoords);
+ // Consume leaving a batch behind.
+ uint32_t consumeSeq;
+ InputEvent* event;
+ status_t status = mConsumer->consume(&mEventFactory,
+ /*consumeBatches=*/false, -1, &consumeSeq, &event);
+ ASSERT_EQ(WOULD_BLOCK, status)
+ << "consumer consume should return WOULD_BLOCK when a new batch is started";
+ ASSERT_TRUE(mConsumer->hasPendingBatch()) << "consume should have created a batch";
+ EXPECT_TRUE(mConsumer->probablyHasInput())
+ << "should deterministically have input because there is a batch";
+ sendAndVerifyFinishedSignal(*mConsumer, *mPublisher, seq, publishTime);
}
void InputPublisherAndConsumerTest::publishAndConsumeMotionEvent(
- int32_t deviceId, uint32_t source, int32_t displayId, std::array<uint8_t, 32> hmac,
- int32_t action, int32_t actionButton, int32_t flags, int32_t edgeFlags, int32_t metaState,
- int32_t buttonState, MotionClassification classification, float xScale, float yScale,
- float xOffset, float yOffset, float xPrecision, float yPrecision, float xCursorPosition,
- float yCursorPosition, float rawXScale, float rawYScale, float rawXOffset, float rawYOffset,
- nsecs_t downTime, nsecs_t eventTime,
- const std::vector<PointerProperties>& pointerProperties,
- const std::vector<PointerCoords>& pointerCoords) {
- const uint32_t seq = mSeq++;
- const int32_t eventId = InputEvent::nextId();
- ui::Transform transform;
- transform.set({xScale, 0, xOffset, 0, yScale, yOffset, 0, 0, 1});
- ui::Transform rawTransform;
- rawTransform.set({rawXScale, 0, rawXOffset, 0, rawYScale, rawYOffset, 0, 0, 1});
-
- status_t status;
- ASSERT_EQ(pointerProperties.size(), pointerCoords.size());
- const size_t pointerCount = pointerProperties.size();
- const nsecs_t publishTime = systemTime(SYSTEM_TIME_MONOTONIC);
- status = mPublisher->publishMotionEvent(seq, eventId, deviceId, source, displayId, hmac, action,
- actionButton, flags, edgeFlags, metaState, buttonState,
- classification, transform, xPrecision, yPrecision,
- xCursorPosition, yCursorPosition, rawTransform,
- downTime, eventTime, pointerCount,
- pointerProperties.data(), pointerCoords.data());
- ASSERT_EQ(OK, status) << "publisher publishMotionEvent should return OK";
+ int32_t action, nsecs_t downTime, const std::vector<Pointer>& pointers) {
+ uint32_t seq = mSeq++;
+ PublishMotionArgs args(action, downTime, pointers, seq);
+ nsecs_t publishTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ publishMotionEvent(*mPublisher, args);
uint32_t consumeSeq;
InputEvent* event;
- status = mConsumer->consume(&mEventFactory, /*consumeBatches=*/true, -1, &consumeSeq, &event);
- ASSERT_EQ(OK, status)
- << "consumer consume should return OK";
-
+ status_t status =
+ mConsumer->consume(&mEventFactory, /*consumeBatches=*/true, -1, &consumeSeq, &event);
+ ASSERT_EQ(OK, status) << "consumer consume should return OK";
ASSERT_TRUE(event != nullptr)
<< "consumer should have returned non-NULL event";
ASSERT_EQ(InputEventType::MOTION, event->getType())
<< "consumer should have returned a motion event";
-
- MotionEvent* motionEvent = static_cast<MotionEvent*>(event);
EXPECT_EQ(seq, consumeSeq);
- EXPECT_EQ(eventId, motionEvent->getId());
- EXPECT_EQ(deviceId, motionEvent->getDeviceId());
- EXPECT_EQ(source, motionEvent->getSource());
- EXPECT_EQ(displayId, motionEvent->getDisplayId());
- EXPECT_EQ(hmac, motionEvent->getHmac());
- EXPECT_EQ(action, motionEvent->getAction());
- EXPECT_EQ(flags, motionEvent->getFlags());
- EXPECT_EQ(edgeFlags, motionEvent->getEdgeFlags());
- EXPECT_EQ(metaState, motionEvent->getMetaState());
- EXPECT_EQ(buttonState, motionEvent->getButtonState());
- EXPECT_EQ(classification, motionEvent->getClassification());
- EXPECT_EQ(transform, motionEvent->getTransform());
- EXPECT_EQ(xOffset, motionEvent->getXOffset());
- EXPECT_EQ(yOffset, motionEvent->getYOffset());
- EXPECT_EQ(xPrecision, motionEvent->getXPrecision());
- EXPECT_EQ(yPrecision, motionEvent->getYPrecision());
- EXPECT_NEAR(xCursorPosition, motionEvent->getRawXCursorPosition(), EPSILON);
- EXPECT_NEAR(yCursorPosition, motionEvent->getRawYCursorPosition(), EPSILON);
- EXPECT_NEAR(xCursorPosition * xScale + xOffset, motionEvent->getXCursorPosition(), EPSILON);
- EXPECT_NEAR(yCursorPosition * yScale + yOffset, motionEvent->getYCursorPosition(), EPSILON);
- EXPECT_EQ(rawTransform, motionEvent->getRawTransform());
- EXPECT_EQ(downTime, motionEvent->getDownTime());
- EXPECT_EQ(eventTime, motionEvent->getEventTime());
- EXPECT_EQ(pointerCount, motionEvent->getPointerCount());
- EXPECT_EQ(0U, motionEvent->getHistorySize());
-
- for (size_t i = 0; i < pointerCount; i++) {
- SCOPED_TRACE(i);
- EXPECT_EQ(pointerProperties[i].id, motionEvent->getPointerId(i));
- EXPECT_EQ(pointerProperties[i].toolType, motionEvent->getToolType(i));
-
- const auto& pc = pointerCoords[i];
- EXPECT_EQ(pc, motionEvent->getSamplePointerCoords()[i]);
-
- EXPECT_NEAR(pc.getX() * rawXScale + rawXOffset, motionEvent->getRawX(i), EPSILON);
- EXPECT_NEAR(pc.getY() * rawYScale + rawYOffset, motionEvent->getRawY(i), EPSILON);
- EXPECT_NEAR(pc.getX() * xScale + xOffset, motionEvent->getX(i), EPSILON);
- EXPECT_NEAR(pc.getY() * yScale + yOffset, motionEvent->getY(i), EPSILON);
- EXPECT_EQ(pc.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE), motionEvent->getPressure(i));
- EXPECT_EQ(pc.getAxisValue(AMOTION_EVENT_AXIS_SIZE), motionEvent->getSize(i));
- EXPECT_EQ(pc.getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR), motionEvent->getTouchMajor(i));
- EXPECT_EQ(pc.getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR), motionEvent->getTouchMinor(i));
- EXPECT_EQ(pc.getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR), motionEvent->getToolMajor(i));
- EXPECT_EQ(pc.getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR), motionEvent->getToolMinor(i));
-
- // Calculate the orientation after scaling, keeping in mind that an orientation of 0 is
- // "up", and the positive y direction is "down".
- const float unscaledOrientation = pc.getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION);
- const float x = sinf(unscaledOrientation) * xScale;
- const float y = -cosf(unscaledOrientation) * yScale;
- EXPECT_EQ(atan2f(x, -y), motionEvent->getOrientation(i));
- }
- status = mConsumer->sendFinishedSignal(seq, false);
- ASSERT_EQ(OK, status)
- << "consumer sendFinishedSignal should return OK";
-
- Result<InputPublisher::ConsumerResponse> result = mPublisher->receiveConsumerResponse();
- ASSERT_TRUE(result.ok()) << "receiveConsumerResponse should return OK";
- ASSERT_TRUE(std::holds_alternative<InputPublisher::Finished>(*result));
- const InputPublisher::Finished& finish = std::get<InputPublisher::Finished>(*result);
- ASSERT_EQ(seq, finish.seq)
- << "receiveConsumerResponse should have returned the original sequence number";
- ASSERT_FALSE(finish.handled)
- << "receiveConsumerResponse should have set handled to consumer's reply";
- ASSERT_GE(finish.consumeTime, publishTime)
- << "finished signal's consume time should be greater than publish time";
+ verifyArgsEqualToEvent(args, static_cast<const MotionEvent&>(*event));
+ sendAndVerifyFinishedSignal(*mConsumer, *mPublisher, seq, publishTime);
}
void InputPublisherAndConsumerTest::publishAndConsumeFocusEvent() {
@@ -546,6 +585,15 @@ TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_EndToEnd) {
ASSERT_NO_FATAL_FAILURE(publishAndConsumeMotionStream());
}
+TEST_F(InputPublisherAndConsumerTest, PublishMotionMoveEvent_EndToEnd) {
+ // Publish a DOWN event before MOVE to pass the InputVerifier checks.
+ const nsecs_t downTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ ASSERT_NO_FATAL_FAILURE(publishAndConsumeMotionDown(downTime));
+
+ // Publish the MOVE event and check expectations.
+ ASSERT_NO_FATAL_FAILURE(publishAndConsumeBatchedMotionMove(downTime));
+}
+
TEST_F(InputPublisherAndConsumerTest, PublishFocusEvent_EndToEnd) {
ASSERT_NO_FATAL_FAILURE(publishAndConsumeFocusEvent());
}
diff --git a/libs/input/tests/MotionPredictorMetricsManager_test.cpp b/libs/input/tests/MotionPredictorMetricsManager_test.cpp
index 31cc1459fc..cc41eeb5e7 100644
--- a/libs/input/tests/MotionPredictorMetricsManager_test.cpp
+++ b/libs/input/tests/MotionPredictorMetricsManager_test.cpp
@@ -238,14 +238,17 @@ TEST(MakeMotionEventTest, MakeLiftMotionEvent) {
// --- Ground-truth-generation helper functions. ---
+// Generates numPoints ground truth points with values equal to those of the given
+// GroundTruthPoint, and with consecutive timestamps separated by the given inputInterval.
std::vector<GroundTruthPoint> generateConstantGroundTruthPoints(
- const GroundTruthPoint& groundTruthPoint, size_t numPoints) {
+ const GroundTruthPoint& groundTruthPoint, size_t numPoints,
+ nsecs_t inputInterval = TEST_PREDICTION_INTERVAL_NANOS) {
std::vector<GroundTruthPoint> groundTruthPoints;
nsecs_t timestamp = groundTruthPoint.timestamp;
for (size_t i = 0; i < numPoints; ++i) {
groundTruthPoints.emplace_back(groundTruthPoint);
groundTruthPoints.back().timestamp = timestamp;
- timestamp += TEST_PREDICTION_INTERVAL_NANOS;
+ timestamp += inputInterval;
}
return groundTruthPoints;
}
@@ -280,7 +283,8 @@ TEST(GenerateConstantGroundTruthPointsTest, BasicTest) {
const GroundTruthPoint groundTruthPoint{{.position = Eigen::Vector2f(10, 20), .pressure = 0.3f},
.timestamp = TEST_INITIAL_TIMESTAMP};
const std::vector<GroundTruthPoint> groundTruthPoints =
- generateConstantGroundTruthPoints(groundTruthPoint, /*numPoints=*/3);
+ generateConstantGroundTruthPoints(groundTruthPoint, /*numPoints=*/3,
+ /*inputInterval=*/10);
ASSERT_EQ(3u, groundTruthPoints.size());
// First point.
@@ -290,11 +294,11 @@ TEST(GenerateConstantGroundTruthPointsTest, BasicTest) {
// Second point.
EXPECT_EQ(groundTruthPoints[1].position, groundTruthPoint.position);
EXPECT_EQ(groundTruthPoints[1].pressure, groundTruthPoint.pressure);
- EXPECT_GT(groundTruthPoints[1].timestamp, groundTruthPoints[0].timestamp);
+ EXPECT_EQ(groundTruthPoints[1].timestamp, groundTruthPoint.timestamp + 10);
// Third point.
EXPECT_EQ(groundTruthPoints[2].position, groundTruthPoint.position);
EXPECT_EQ(groundTruthPoints[2].pressure, groundTruthPoint.pressure);
- EXPECT_GT(groundTruthPoints[2].timestamp, groundTruthPoints[1].timestamp);
+ EXPECT_EQ(groundTruthPoints[2].timestamp, groundTruthPoint.timestamp + 20);
}
TEST(GenerateCircularArcGroundTruthTest, StraightLineUpwards) {
@@ -333,16 +337,19 @@ TEST(GenerateCircularArcGroundTruthTest, CounterclockwiseSquare) {
// --- Prediction-generation helper functions. ---
-// Creates a sequence of predictions with values equal to those of the given GroundTruthPoint.
-std::vector<PredictionPoint> generateConstantPredictions(const GroundTruthPoint& groundTruthPoint) {
+// Generates TEST_MAX_NUM_PREDICTIONS predictions with values equal to those of the given
+// GroundTruthPoint, and with consecutive timestamps separated by the given predictionInterval.
+std::vector<PredictionPoint> generateConstantPredictions(
+ const GroundTruthPoint& groundTruthPoint,
+ nsecs_t predictionInterval = TEST_PREDICTION_INTERVAL_NANOS) {
std::vector<PredictionPoint> predictions;
- nsecs_t predictionTimestamp = groundTruthPoint.timestamp + TEST_PREDICTION_INTERVAL_NANOS;
+ nsecs_t predictionTimestamp = groundTruthPoint.timestamp + predictionInterval;
for (size_t j = 0; j < TEST_MAX_NUM_PREDICTIONS; ++j) {
predictions.push_back(PredictionPoint{{.position = groundTruthPoint.position,
.pressure = groundTruthPoint.pressure},
.originTimestamp = groundTruthPoint.timestamp,
.targetTimestamp = predictionTimestamp});
- predictionTimestamp += TEST_PREDICTION_INTERVAL_NANOS;
+ predictionTimestamp += predictionInterval;
}
return predictions;
}
@@ -375,8 +382,9 @@ std::vector<PredictionPoint> generatePredictionsByLinearExtrapolation(
TEST(GeneratePredictionsTest, GenerateConstantPredictions) {
const GroundTruthPoint groundTruthPoint{{.position = Eigen::Vector2f(10, 20), .pressure = 0.3f},
.timestamp = TEST_INITIAL_TIMESTAMP};
+ const nsecs_t predictionInterval = 10;
const std::vector<PredictionPoint> predictionPoints =
- generateConstantPredictions(groundTruthPoint);
+ generateConstantPredictions(groundTruthPoint, predictionInterval);
ASSERT_EQ(TEST_MAX_NUM_PREDICTIONS, predictionPoints.size());
for (size_t i = 0; i < predictionPoints.size(); ++i) {
@@ -385,8 +393,7 @@ TEST(GeneratePredictionsTest, GenerateConstantPredictions) {
EXPECT_THAT(predictionPoints[i].pressure, FloatNear(groundTruthPoint.pressure, 1e-6));
EXPECT_EQ(predictionPoints[i].originTimestamp, groundTruthPoint.timestamp);
EXPECT_EQ(predictionPoints[i].targetTimestamp,
- groundTruthPoint.timestamp +
- static_cast<nsecs_t>(i + 1) * TEST_PREDICTION_INTERVAL_NANOS);
+ TEST_INITIAL_TIMESTAMP + static_cast<nsecs_t>(i + 1) * predictionInterval);
}
}
@@ -678,12 +685,9 @@ ReportAtomFunction createMockReportAtomFunction(std::vector<AtomFields>& reporte
// • groundTruthPoints: chronologically-ordered ground truth points, with at least 2 elements.
// • predictionPoints: the first index points to a vector of predictions corresponding to the
// source ground truth point with the same index.
-// - The first element should be empty, because there are not expected to be predictions until
-// we have received 2 ground truth points.
-// - The last element may be empty, because there will be no future ground truth points to
-// associate with those predictions (if not empty, it will be ignored).
+// - For empty prediction vectors, MetricsManager::onPredict will not be called.
// - To test all prediction buckets, there should be at least TEST_MAX_NUM_PREDICTIONS non-empty
-// prediction sets (that is, excluding the first and last). Thus, groundTruthPoints and
+// prediction vectors (that is, excluding the first and last). Thus, groundTruthPoints and
// predictionPoints should have size at least TEST_MAX_NUM_PREDICTIONS + 2.
//
// When the function returns, outReportedAtomFields will contain the reported AtomFields.
@@ -697,19 +701,12 @@ void runMetricsManager(const std::vector<GroundTruthPoint>& groundTruthPoints,
createMockReportAtomFunction(
outReportedAtomFields));
- // Validate structure of groundTruthPoints and predictionPoints.
- ASSERT_EQ(predictionPoints.size(), groundTruthPoints.size());
ASSERT_GE(groundTruthPoints.size(), 2u);
- ASSERT_EQ(predictionPoints[0].size(), 0u);
- for (size_t i = 1; i + 1 < predictionPoints.size(); ++i) {
- SCOPED_TRACE(testing::Message() << "i = " << i);
- ASSERT_EQ(predictionPoints[i].size(), TEST_MAX_NUM_PREDICTIONS);
- }
+ ASSERT_EQ(predictionPoints.size(), groundTruthPoints.size());
- // Pass ground truth points and predictions (for all except first and last ground truth).
for (size_t i = 0; i < groundTruthPoints.size(); ++i) {
metricsManager.onRecord(makeMotionEvent(groundTruthPoints[i]));
- if ((i > 0) && (i + 1 < predictionPoints.size())) {
+ if (!predictionPoints[i].empty()) {
metricsManager.onPredict(makeMotionEvent(predictionPoints[i]));
}
}
@@ -738,7 +735,7 @@ TEST(MotionPredictorMetricsManagerTest, NoPredictions) {
// Perfect predictions test:
// • Input: constant input events, perfect predictions matching the input events.
// • Expectation: all error metrics should be zero, or NO_DATA_SENTINEL for "unreported" metrics.
-// (For example, scale-invariant errors are only reported for the final time bucket.)
+// (For example, scale-invariant errors are only reported for the last time bucket.)
TEST(MotionPredictorMetricsManagerTest, ConstantGroundTruthPerfectPredictions) {
GroundTruthPoint groundTruthPoint{{.position = Eigen::Vector2f(10.0f, 20.0f), .pressure = 0.6f},
.timestamp = TEST_INITIAL_TIMESTAMP};
@@ -977,5 +974,35 @@ TEST(MotionPredictorMetricsManagerTest, CounterclockwiseOctagonGroundTruthLinear
}
}
+// Robustness test:
+// • Input: input events separated by a significantly greater time interval than the interval
+// between predictions.
+// • Expectation: the MetricsManager should not crash in this case. (No assertions are made about
+// the resulting metrics.)
+//
+// In practice, this scenario could arise either if the input and prediction intervals are
+// mismatched, or if input events are missing (dropped or skipped for some reason).
+TEST(MotionPredictorMetricsManagerTest, MismatchedInputAndPredictionInterval) {
+ // Create two ground truth points separated by MAX_NUM_PREDICTIONS * PREDICTION_INTERVAL,
+ // so that the second ground truth point corresponds to the last prediction bucket. This
+ // ensures that the scale-invariant error codepath will be run, giving full code coverage.
+ GroundTruthPoint groundTruthPoint{{.position = Eigen::Vector2f(0.0f, 0.0f), .pressure = 0.5f},
+ .timestamp = TEST_INITIAL_TIMESTAMP};
+ const nsecs_t inputInterval = TEST_MAX_NUM_PREDICTIONS * TEST_PREDICTION_INTERVAL_NANOS;
+ const std::vector<GroundTruthPoint> groundTruthPoints =
+ generateConstantGroundTruthPoints(groundTruthPoint, /*numPoints=*/2, inputInterval);
+
+ // Create predictions separated by the prediction interval.
+ std::vector<std::vector<PredictionPoint>> predictionPoints;
+ for (size_t i = 0; i < groundTruthPoints.size(); ++i) {
+ predictionPoints.push_back(
+ generateConstantPredictions(groundTruthPoints[i], TEST_PREDICTION_INTERVAL_NANOS));
+ }
+
+ // Test that we can run the MetricsManager without crashing.
+ std::vector<AtomFields> reportedAtomFields;
+ runMetricsManager(groundTruthPoints, predictionPoints, reportedAtomFields);
+}
+
} // namespace
} // namespace android
diff --git a/libs/input/tests/TestHelpers.h b/libs/input/tests/TestHelpers.h
deleted file mode 100644
index 343d81f917..0000000000
--- a/libs/input/tests/TestHelpers.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (C) 2010 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 TESTHELPERS_H
-#define TESTHELPERS_H
-
-#include <unistd.h>
-
-#include <utils/threads.h>
-
-namespace android {
-
-class Pipe {
-public:
- int sendFd;
- int receiveFd;
-
- Pipe() {
- int fds[2];
- ::pipe(fds);
-
- receiveFd = fds[0];
- sendFd = fds[1];
- }
-
- ~Pipe() {
- if (sendFd != -1) {
- ::close(sendFd);
- }
-
- if (receiveFd != -1) {
- ::close(receiveFd);
- }
- }
-
- status_t writeSignal() {
- ssize_t nWritten = ::write(sendFd, "*", 1);
- return nWritten == 1 ? 0 : -errno;
- }
-
- status_t readSignal() {
- char buf[1];
- ssize_t nRead = ::read(receiveFd, buf, 1);
- return nRead == 1 ? 0 : nRead == 0 ? -EPIPE : -errno;
- }
-};
-
-class DelayedTask : public Thread {
- int mDelayMillis;
-
-public:
- explicit DelayedTask(int delayMillis) : mDelayMillis(delayMillis) { }
-
-protected:
- virtual ~DelayedTask() { }
-
- virtual void doTask() = 0;
-
- virtual bool threadLoop() {
- usleep(mDelayMillis * 1000);
- doTask();
- return false;
- }
-};
-
-} // namespace android
-
-#endif // TESTHELPERS_H
diff --git a/libs/input/tests/TouchResampling_test.cpp b/libs/input/tests/TouchResampling_test.cpp
index 1cb7f7ba8c..0b0bb63a81 100644
--- a/libs/input/tests/TouchResampling_test.cpp
+++ b/libs/input/tests/TouchResampling_test.cpp
@@ -14,8 +14,6 @@
* limitations under the License.
*/
-#include "TestHelpers.h"
-
#include <chrono>
#include <vector>
diff --git a/libs/input/tests/VelocityControl_test.cpp b/libs/input/tests/VelocityControl_test.cpp
new file mode 100644
index 0000000000..63d64c6048
--- /dev/null
+++ b/libs/input/tests/VelocityControl_test.cpp
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2024 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 <input/VelocityControl.h>
+
+#include <limits>
+
+#include <gtest/gtest.h>
+#include <input/AccelerationCurve.h>
+#include <utils/Timers.h>
+
+namespace android {
+
+namespace {
+
+constexpr float EPSILON = 0.001;
+constexpr float COUNTS_PER_MM = 800 / 25.4;
+
+} // namespace
+
+class CurvedVelocityControlTest : public testing::Test {
+protected:
+ CurvedVelocityControl mCtrl;
+
+ void moveWithoutCheckingResult(nsecs_t eventTime, float deltaX, float deltaY) {
+ mCtrl.move(eventTime, &deltaX, &deltaY);
+ }
+
+ void moveAndCheckRatio(nsecs_t eventTime, const float deltaX, const float deltaY,
+ float expectedRatio) {
+ float newDeltaX = deltaX, newDeltaY = deltaY;
+ mCtrl.move(eventTime, &newDeltaX, &newDeltaY);
+ ASSERT_NEAR(expectedRatio * deltaX, newDeltaX, EPSILON)
+ << "Expected ratio of " << expectedRatio << " in X, but actual ratio was "
+ << newDeltaX / deltaX;
+ ASSERT_NEAR(expectedRatio * deltaY, newDeltaY, EPSILON)
+ << "Expected ratio of " << expectedRatio << " in Y, but actual ratio was "
+ << newDeltaY / deltaY;
+ }
+};
+
+TEST_F(CurvedVelocityControlTest, SegmentSelection) {
+ // To make the maths simple, use a "curve" that's actually just a sequence of steps.
+ mCtrl.setCurve({
+ {10, 2, 0},
+ {20, 3, 0},
+ {30, 4, 0},
+ {std::numeric_limits<double>::infinity(), 5, 0},
+ });
+
+ // Establish a velocity of 16 mm/s.
+ moveWithoutCheckingResult(0, 0, 0);
+ moveWithoutCheckingResult(10'000'000, 0.16 * COUNTS_PER_MM, 0);
+ moveWithoutCheckingResult(20'000'000, 0.16 * COUNTS_PER_MM, 0);
+ moveWithoutCheckingResult(30'000'000, 0.16 * COUNTS_PER_MM, 0);
+ ASSERT_NO_FATAL_FAILURE(
+ moveAndCheckRatio(40'000'000, 0.16 * COUNTS_PER_MM, 0, /*expectedRatio=*/3));
+
+ // Establish a velocity of 50 mm/s.
+ mCtrl.reset();
+ moveWithoutCheckingResult(100'000'000, 0, 0);
+ moveWithoutCheckingResult(110'000'000, 0.50 * COUNTS_PER_MM, 0);
+ moveWithoutCheckingResult(120'000'000, 0.50 * COUNTS_PER_MM, 0);
+ moveWithoutCheckingResult(130'000'000, 0.50 * COUNTS_PER_MM, 0);
+ ASSERT_NO_FATAL_FAILURE(
+ moveAndCheckRatio(140'000'000, 0.50 * COUNTS_PER_MM, 0, /*expectedRatio=*/5));
+}
+
+TEST_F(CurvedVelocityControlTest, RatioDefaultsToFirstSegmentWhenVelocityIsUnknown) {
+ mCtrl.setCurve({
+ {10, 3, 0},
+ {20, 2, 0},
+ {std::numeric_limits<double>::infinity(), 4, 0},
+ });
+
+ // Only send two moves, which won't be enough for VelocityTracker to calculate a velocity from.
+ moveWithoutCheckingResult(0, 0, 0);
+ ASSERT_NO_FATAL_FAILURE(
+ moveAndCheckRatio(10'000'000, 0.25 * COUNTS_PER_MM, 0, /*expectedRatio=*/3));
+}
+
+TEST_F(CurvedVelocityControlTest, VelocityCalculatedUsingBothAxes) {
+ mCtrl.setCurve({
+ {8.0, 3, 0},
+ {8.1, 2, 0},
+ {std::numeric_limits<double>::infinity(), 4, 0},
+ });
+
+ // Establish a velocity of 8.06 (= √65 = √(7²+4²)) mm/s between the two axes.
+ moveWithoutCheckingResult(0, 0, 0);
+ moveWithoutCheckingResult(10'000'000, 0.07 * COUNTS_PER_MM, 0.04 * COUNTS_PER_MM);
+ moveWithoutCheckingResult(20'000'000, 0.07 * COUNTS_PER_MM, 0.04 * COUNTS_PER_MM);
+ moveWithoutCheckingResult(30'000'000, 0.07 * COUNTS_PER_MM, 0.04 * COUNTS_PER_MM);
+ ASSERT_NO_FATAL_FAILURE(moveAndCheckRatio(40'000'000, 0.07 * COUNTS_PER_MM,
+ 0.04 * COUNTS_PER_MM,
+ /*expectedRatio=*/2));
+}
+
+TEST_F(CurvedVelocityControlTest, ReciprocalTerm) {
+ mCtrl.setCurve({
+ {10, 2, 0},
+ {20, 3, -10},
+ {std::numeric_limits<double>::infinity(), 3, 0},
+ });
+
+ // Establish a velocity of 15 mm/s.
+ moveWithoutCheckingResult(0, 0, 0);
+ moveWithoutCheckingResult(10'000'000, 0, 0.15 * COUNTS_PER_MM);
+ moveWithoutCheckingResult(20'000'000, 0, 0.15 * COUNTS_PER_MM);
+ moveWithoutCheckingResult(30'000'000, 0, 0.15 * COUNTS_PER_MM);
+ // Expected ratio is 3 - 10 / 15 = 2.33333...
+ ASSERT_NO_FATAL_FAILURE(
+ moveAndCheckRatio(40'000'000, 0, 0.15 * COUNTS_PER_MM, /*expectedRatio=*/2.33333));
+}
+
+} // namespace android \ No newline at end of file
diff --git a/libs/nativedisplay/AChoreographer.cpp b/libs/nativedisplay/AChoreographer.cpp
index 8f005a56f8..bed31e27a8 100644
--- a/libs/nativedisplay/AChoreographer.cpp
+++ b/libs/nativedisplay/AChoreographer.cpp
@@ -148,29 +148,31 @@ AChoreographer* AChoreographer_getInstance() {
void AChoreographer_postFrameCallback(AChoreographer* choreographer,
AChoreographer_frameCallback callback, void* data) {
AChoreographer_to_Choreographer(choreographer)
- ->postFrameCallbackDelayed(callback, nullptr, nullptr, data, 0);
+ ->postFrameCallbackDelayed(callback, nullptr, nullptr, data, 0, CALLBACK_ANIMATION);
}
void AChoreographer_postFrameCallbackDelayed(AChoreographer* choreographer,
AChoreographer_frameCallback callback, void* data,
long delayMillis) {
AChoreographer_to_Choreographer(choreographer)
- ->postFrameCallbackDelayed(callback, nullptr, nullptr, data, ms2ns(delayMillis));
+ ->postFrameCallbackDelayed(callback, nullptr, nullptr, data, ms2ns(delayMillis),
+ CALLBACK_ANIMATION);
}
void AChoreographer_postVsyncCallback(AChoreographer* choreographer,
AChoreographer_vsyncCallback callback, void* data) {
AChoreographer_to_Choreographer(choreographer)
- ->postFrameCallbackDelayed(nullptr, nullptr, callback, data, 0);
+ ->postFrameCallbackDelayed(nullptr, nullptr, callback, data, 0, CALLBACK_ANIMATION);
}
void AChoreographer_postFrameCallback64(AChoreographer* choreographer,
AChoreographer_frameCallback64 callback, void* data) {
AChoreographer_to_Choreographer(choreographer)
- ->postFrameCallbackDelayed(nullptr, callback, nullptr, data, 0);
+ ->postFrameCallbackDelayed(nullptr, callback, nullptr, data, 0, CALLBACK_ANIMATION);
}
void AChoreographer_postFrameCallbackDelayed64(AChoreographer* choreographer,
AChoreographer_frameCallback64 callback, void* data,
uint32_t delayMillis) {
AChoreographer_to_Choreographer(choreographer)
- ->postFrameCallbackDelayed(nullptr, callback, nullptr, data, ms2ns(delayMillis));
+ ->postFrameCallbackDelayed(nullptr, callback, nullptr, data, ms2ns(delayMillis),
+ CALLBACK_ANIMATION);
}
void AChoreographer_registerRefreshRateCallback(AChoreographer* choreographer,
AChoreographer_refreshRateCallback callback,
diff --git a/libs/nativedisplay/Android.bp b/libs/nativedisplay/Android.bp
index 342f5de337..03f4f399d0 100644
--- a/libs/nativedisplay/Android.bp
+++ b/libs/nativedisplay/Android.bp
@@ -16,6 +16,7 @@ package {
default_applicable_licenses: [
"frameworks_native_libs_nativedisplay_license",
],
+ default_team: "trendy_team_android_core_graphics_stack",
}
// Added automatically by a large-scale-change
@@ -33,7 +34,13 @@ license {
cc_library_headers {
name: "libnativedisplay_headers",
+ host_supported: true,
export_include_dirs: ["include"],
+ target: {
+ windows: {
+ enabled: true,
+ },
+ },
}
cc_library_shared {
diff --git a/libs/nativewindow/AHardwareBuffer.cpp b/libs/nativewindow/AHardwareBuffer.cpp
index e7b2195056..52612870ab 100644
--- a/libs/nativewindow/AHardwareBuffer.cpp
+++ b/libs/nativewindow/AHardwareBuffer.cpp
@@ -113,6 +113,22 @@ static_assert(
AHARDWAREBUFFER_FORMAT_R10G10B10A10_UNORM,
"HAL and AHardwareBuffer pixel format don't match");
+static enum AHardwareBufferStatus filterStatus(status_t status) {
+ switch (status) {
+ case STATUS_OK:
+ return AHARDWAREBUFFER_STATUS_OK;
+ case STATUS_NO_MEMORY:
+ return AHARDWAREBUFFER_STATUS_NO_MEMORY;
+ case STATUS_BAD_VALUE:
+ return AHARDWAREBUFFER_STATUS_BAD_VALUE;
+ case STATUS_UNKNOWN_TRANSACTION:
+ case STATUS_INVALID_OPERATION:
+ return AHARDWAREBUFFER_STATUS_UNSUPPORTED;
+ default:
+ return AHARDWAREBUFFER_STATUS_UNKNOWN_ERROR;
+ }
+}
+
// ----------------------------------------------------------------------------
// Public functions
// ----------------------------------------------------------------------------
@@ -511,6 +527,24 @@ binder_status_t AHardwareBuffer_writeToParcel(const AHardwareBuffer* _Nonnull bu
return AParcel_viewPlatformParcel(parcel)->write(*gb);
}
+ADataSpace AHardwareBuffer_getDataSpace(const AHardwareBuffer* _Nonnull buffer) {
+ const GraphicBuffer* gb = AHardwareBuffer_to_GraphicBuffer(buffer);
+ if (!gb) return ADATASPACE_UNKNOWN;
+ ui::Dataspace dataspace = ui::Dataspace::UNKNOWN;
+ status_t status = gb->getDataspace(&dataspace);
+ if (status != OK) {
+ return ADATASPACE_UNKNOWN;
+ }
+ return static_cast<ADataSpace>(dataspace);
+}
+
+enum AHardwareBufferStatus AHardwareBuffer_setDataSpace(AHardwareBuffer* buffer,
+ ADataSpace dataspace) {
+ GraphicBuffer* gb = AHardwareBuffer_to_GraphicBuffer(buffer);
+ auto& mapper = GraphicBufferMapper::get();
+ return filterStatus(mapper.setDataspace(gb->handle, static_cast<ui::Dataspace>(dataspace)));
+}
+
// ----------------------------------------------------------------------------
// VNDK functions
// ----------------------------------------------------------------------------
@@ -552,6 +586,56 @@ int AHardwareBuffer_createFromHandle(const AHardwareBuffer_Desc* desc,
return NO_ERROR;
}
+enum AHardwareBufferStatus AHardwareBuffer_allocateWithOptions(
+ const AHardwareBuffer_Desc* desc, const AHardwareBufferLongOptions* additionalOptions,
+ size_t additionalOptionsSize, AHardwareBuffer** outBuffer) {
+ (void)additionalOptions;
+ (void)additionalOptionsSize;
+ if (!outBuffer || !desc) return AHARDWAREBUFFER_STATUS_BAD_VALUE;
+ if (!AHardwareBuffer_isValidDescription(desc, /*log=*/true)) {
+ return AHARDWAREBUFFER_STATUS_BAD_VALUE;
+ }
+
+ int format = AHardwareBuffer_convertToPixelFormat(desc->format);
+ uint64_t usage = AHardwareBuffer_convertToGrallocUsageBits(desc->usage);
+
+ std::vector<GraphicBufferAllocator::AdditionalOptions> extras;
+ extras.reserve(additionalOptionsSize);
+ for (size_t i = 0; i < additionalOptionsSize; i++) {
+ extras.push_back(GraphicBufferAllocator::AdditionalOptions{additionalOptions[i].name,
+ additionalOptions[i].value});
+ }
+
+ const auto extrasCount = extras.size();
+ auto gbuffer = sp<GraphicBuffer>::make(GraphicBufferAllocator::AllocationRequest{
+ .importBuffer = true,
+ .width = desc->width,
+ .height = desc->height,
+ .format = format,
+ .layerCount = desc->layers,
+ .usage = usage,
+ .requestorName = std::string("AHardwareBuffer pid [") + std::to_string(getpid()) + "]",
+ .extras = std::move(extras),
+ });
+
+ status_t err = gbuffer->initCheck();
+ if (err != 0 || gbuffer->handle == nullptr) {
+ if (err == NO_MEMORY) {
+ GraphicBuffer::dumpAllocationsToSystemLog();
+ }
+ ALOGE("GraphicBuffer(w=%u, h=%u, lc=%u, extrasCount=%zd) failed (%s), handle=%p",
+ desc->width, desc->height, desc->layers, extrasCount, strerror(-err),
+ gbuffer->handle);
+ return filterStatus(err == 0 ? UNKNOWN_ERROR : err);
+ }
+
+ *outBuffer = AHardwareBuffer_from_GraphicBuffer(gbuffer.get());
+
+ // Ensure the buffer doesn't get destroyed when the sp<> goes away.
+ AHardwareBuffer_acquire(*outBuffer);
+ return AHARDWAREBUFFER_STATUS_OK;
+}
+
// ----------------------------------------------------------------------------
// Helpers implementation
// ----------------------------------------------------------------------------
@@ -652,12 +736,9 @@ uint32_t AHardwareBuffer_convertToPixelFormat(uint32_t ahardwarebuffer_format) {
return ahardwarebuffer_format;
}
+// TODO: Remove, this is just to make an overly aggressive ABI checker happy
int32_t AHardwareBuffer_getDataSpace(AHardwareBuffer* buffer) {
- GraphicBuffer* gb = AHardwareBuffer_to_GraphicBuffer(buffer);
- auto& mapper = GraphicBufferMapper::get();
- ui::Dataspace dataspace = ui::Dataspace::UNKNOWN;
- mapper.getDataspace(gb->handle, &dataspace);
- return static_cast<int32_t>(dataspace);
+ return ::AHardwareBuffer_getDataSpace(buffer);
}
uint64_t AHardwareBuffer_convertToGrallocUsageBits(uint64_t usage) {
diff --git a/libs/nativewindow/ANativeWindow.cpp b/libs/nativewindow/ANativeWindow.cpp
index dd5958de28..f97eed5db3 100644
--- a/libs/nativewindow/ANativeWindow.cpp
+++ b/libs/nativewindow/ANativeWindow.cpp
@@ -152,31 +152,56 @@ int32_t ANativeWindow_setBuffersTransform(ANativeWindow* window, int32_t transfo
int32_t ANativeWindow_setBuffersDataSpace(ANativeWindow* window, int32_t dataSpace) {
static_assert(static_cast<int>(ADATASPACE_UNKNOWN) == static_cast<int>(HAL_DATASPACE_UNKNOWN));
- static_assert(static_cast<int>(STANDARD_MASK) == static_cast<int>(HAL_DATASPACE_STANDARD_MASK));
- static_assert(static_cast<int>(STANDARD_UNSPECIFIED) == static_cast<int>(HAL_DATASPACE_STANDARD_UNSPECIFIED));
- static_assert(static_cast<int>(STANDARD_BT709) == static_cast<int>(HAL_DATASPACE_STANDARD_BT709));
- static_assert(static_cast<int>(STANDARD_BT601_625) == static_cast<int>(HAL_DATASPACE_STANDARD_BT601_625));
- static_assert(static_cast<int>(STANDARD_BT601_625_UNADJUSTED) == static_cast<int>(HAL_DATASPACE_STANDARD_BT601_625_UNADJUSTED));
- static_assert(static_cast<int>(STANDARD_BT601_525) == static_cast<int>(HAL_DATASPACE_STANDARD_BT601_525));
- static_assert(static_cast<int>(STANDARD_BT601_525_UNADJUSTED) == static_cast<int>(HAL_DATASPACE_STANDARD_BT601_525_UNADJUSTED));
- static_assert(static_cast<int>(STANDARD_BT470M) == static_cast<int>(HAL_DATASPACE_STANDARD_BT470M));
- static_assert(static_cast<int>(STANDARD_FILM) == static_cast<int>(HAL_DATASPACE_STANDARD_FILM));
- static_assert(static_cast<int>(STANDARD_DCI_P3) == static_cast<int>(HAL_DATASPACE_STANDARD_DCI_P3));
- static_assert(static_cast<int>(STANDARD_ADOBE_RGB) == static_cast<int>(HAL_DATASPACE_STANDARD_ADOBE_RGB));
- static_assert(static_cast<int>(TRANSFER_MASK) == static_cast<int>(HAL_DATASPACE_TRANSFER_MASK));
- static_assert(static_cast<int>(TRANSFER_UNSPECIFIED) == static_cast<int>(HAL_DATASPACE_TRANSFER_UNSPECIFIED));
- static_assert(static_cast<int>(TRANSFER_LINEAR) == static_cast<int>(HAL_DATASPACE_TRANSFER_LINEAR));
- static_assert(static_cast<int>(TRANSFER_SMPTE_170M) == static_cast<int>(HAL_DATASPACE_TRANSFER_SMPTE_170M));
- static_assert(static_cast<int>(TRANSFER_GAMMA2_2) == static_cast<int>(HAL_DATASPACE_TRANSFER_GAMMA2_2));
- static_assert(static_cast<int>(TRANSFER_GAMMA2_6) == static_cast<int>(HAL_DATASPACE_TRANSFER_GAMMA2_6));
- static_assert(static_cast<int>(TRANSFER_GAMMA2_8) == static_cast<int>(HAL_DATASPACE_TRANSFER_GAMMA2_8));
- static_assert(static_cast<int>(TRANSFER_ST2084) == static_cast<int>(HAL_DATASPACE_TRANSFER_ST2084));
- static_assert(static_cast<int>(TRANSFER_HLG) == static_cast<int>(HAL_DATASPACE_TRANSFER_HLG));
- static_assert(static_cast<int>(RANGE_MASK) == static_cast<int>(HAL_DATASPACE_RANGE_MASK));
- static_assert(static_cast<int>(RANGE_UNSPECIFIED) == static_cast<int>(HAL_DATASPACE_RANGE_UNSPECIFIED));
- static_assert(static_cast<int>(RANGE_FULL) == static_cast<int>(HAL_DATASPACE_RANGE_FULL));
- static_assert(static_cast<int>(RANGE_LIMITED) == static_cast<int>(HAL_DATASPACE_RANGE_LIMITED));
- static_assert(static_cast<int>(RANGE_EXTENDED) == static_cast<int>(HAL_DATASPACE_RANGE_EXTENDED));
+ static_assert(static_cast<int>(ADATASPACE_STANDARD_MASK) ==
+ static_cast<int>(HAL_DATASPACE_STANDARD_MASK));
+ static_assert(static_cast<int>(ADATASPACE_STANDARD_UNSPECIFIED) ==
+ static_cast<int>(HAL_DATASPACE_STANDARD_UNSPECIFIED));
+ static_assert(static_cast<int>(ADATASPACE_STANDARD_BT709) ==
+ static_cast<int>(HAL_DATASPACE_STANDARD_BT709));
+ static_assert(static_cast<int>(ADATASPACE_STANDARD_BT601_625) ==
+ static_cast<int>(HAL_DATASPACE_STANDARD_BT601_625));
+ static_assert(static_cast<int>(ADATASPACE_STANDARD_BT601_625_UNADJUSTED) ==
+ static_cast<int>(HAL_DATASPACE_STANDARD_BT601_625_UNADJUSTED));
+ static_assert(static_cast<int>(ADATASPACE_STANDARD_BT601_525) ==
+ static_cast<int>(HAL_DATASPACE_STANDARD_BT601_525));
+ static_assert(static_cast<int>(ADATASPACE_STANDARD_BT601_525_UNADJUSTED) ==
+ static_cast<int>(HAL_DATASPACE_STANDARD_BT601_525_UNADJUSTED));
+ static_assert(static_cast<int>(ADATASPACE_STANDARD_BT470M) ==
+ static_cast<int>(HAL_DATASPACE_STANDARD_BT470M));
+ static_assert(static_cast<int>(ADATASPACE_STANDARD_FILM) ==
+ static_cast<int>(HAL_DATASPACE_STANDARD_FILM));
+ static_assert(static_cast<int>(ADATASPACE_STANDARD_DCI_P3) ==
+ static_cast<int>(HAL_DATASPACE_STANDARD_DCI_P3));
+ static_assert(static_cast<int>(ADATASPACE_STANDARD_ADOBE_RGB) ==
+ static_cast<int>(HAL_DATASPACE_STANDARD_ADOBE_RGB));
+ static_assert(static_cast<int>(ADATASPACE_TRANSFER_MASK) ==
+ static_cast<int>(HAL_DATASPACE_TRANSFER_MASK));
+ static_assert(static_cast<int>(ADATASPACE_TRANSFER_UNSPECIFIED) ==
+ static_cast<int>(HAL_DATASPACE_TRANSFER_UNSPECIFIED));
+ static_assert(static_cast<int>(ADATASPACE_TRANSFER_LINEAR) ==
+ static_cast<int>(HAL_DATASPACE_TRANSFER_LINEAR));
+ static_assert(static_cast<int>(ADATASPACE_TRANSFER_SMPTE_170M) ==
+ static_cast<int>(HAL_DATASPACE_TRANSFER_SMPTE_170M));
+ static_assert(static_cast<int>(ADATASPACE_TRANSFER_GAMMA2_2) ==
+ static_cast<int>(HAL_DATASPACE_TRANSFER_GAMMA2_2));
+ static_assert(static_cast<int>(ADATASPACE_TRANSFER_GAMMA2_6) ==
+ static_cast<int>(HAL_DATASPACE_TRANSFER_GAMMA2_6));
+ static_assert(static_cast<int>(ADATASPACE_TRANSFER_GAMMA2_8) ==
+ static_cast<int>(HAL_DATASPACE_TRANSFER_GAMMA2_8));
+ static_assert(static_cast<int>(ADATASPACE_TRANSFER_ST2084) ==
+ static_cast<int>(HAL_DATASPACE_TRANSFER_ST2084));
+ static_assert(static_cast<int>(ADATASPACE_TRANSFER_HLG) ==
+ static_cast<int>(HAL_DATASPACE_TRANSFER_HLG));
+ static_assert(static_cast<int>(ADATASPACE_RANGE_MASK) ==
+ static_cast<int>(HAL_DATASPACE_RANGE_MASK));
+ static_assert(static_cast<int>(ADATASPACE_RANGE_UNSPECIFIED) ==
+ static_cast<int>(HAL_DATASPACE_RANGE_UNSPECIFIED));
+ static_assert(static_cast<int>(ADATASPACE_RANGE_FULL) ==
+ static_cast<int>(HAL_DATASPACE_RANGE_FULL));
+ static_assert(static_cast<int>(ADATASPACE_RANGE_LIMITED) ==
+ static_cast<int>(HAL_DATASPACE_RANGE_LIMITED));
+ static_assert(static_cast<int>(ADATASPACE_RANGE_EXTENDED) ==
+ static_cast<int>(HAL_DATASPACE_RANGE_EXTENDED));
static_assert(static_cast<int>(ADATASPACE_SRGB) == static_cast<int>(HAL_DATASPACE_V0_SRGB));
static_assert(static_cast<int>(ADATASPACE_SCRGB) == static_cast<int>(HAL_DATASPACE_V0_SCRGB));
static_assert(static_cast<int>(ADATASPACE_DISPLAY_P3) == static_cast<int>(HAL_DATASPACE_DISPLAY_P3));
diff --git a/libs/nativewindow/Android.bp b/libs/nativewindow/Android.bp
index bc0bfc52d5..855807472e 100644
--- a/libs/nativewindow/Android.bp
+++ b/libs/nativewindow/Android.bp
@@ -16,6 +16,7 @@ package {
default_applicable_licenses: [
"frameworks_native_libs_nativewindow_license",
],
+ default_team: "trendy_team_android_core_graphics_stack",
}
// Added automatically by a large-scale-change
@@ -53,6 +54,11 @@ cc_library_headers {
"test_com.android.media.swcodec",
],
host_supported: true,
+ target: {
+ windows: {
+ enabled: true,
+ },
+ },
}
ndk_library {
diff --git a/libs/nativewindow/include-private/private/android/AHardwareBufferHelpers.h b/libs/nativewindow/include-private/private/android/AHardwareBufferHelpers.h
index 880c694934..f145a2f7c2 100644
--- a/libs/nativewindow/include-private/private/android/AHardwareBufferHelpers.h
+++ b/libs/nativewindow/include-private/private/android/AHardwareBufferHelpers.h
@@ -27,8 +27,8 @@
#include <stdint.h>
-struct AHardwareBuffer;
-struct AHardwareBuffer_Desc;
+#include <vndk/hardware_buffer.h>
+
struct ANativeWindowBuffer;
namespace android {
@@ -46,11 +46,6 @@ uint32_t AHardwareBuffer_convertFromPixelFormat(uint32_t format);
// convert HAL format to AHardwareBuffer format (note: this is a no-op)
uint32_t AHardwareBuffer_convertToPixelFormat(uint32_t format);
-// retrieves a dataspace from the AHardwareBuffer metadata, if the device
-// support gralloc metadata. Returns UNKNOWN if gralloc metadata is not
-// supported.
-int32_t AHardwareBuffer_getDataSpace(AHardwareBuffer* buffer);
-
// convert AHardwareBuffer usage bits to HAL usage bits (note: this is a no-op)
uint64_t AHardwareBuffer_convertFromGrallocUsageBits(uint64_t usage);
diff --git a/libs/nativewindow/include/android/data_space.h b/libs/nativewindow/include/android/data_space.h
index 9f8ae863db..8056d9ac4f 100644
--- a/libs/nativewindow/include/android/data_space.h
+++ b/libs/nativewindow/include/android/data_space.h
@@ -64,7 +64,7 @@ enum ADataSpace : int32_t {
* Defines the chromaticity coordinates of the source primaries in terms of
* the CIE 1931 definition of x and y specified in ISO 11664-1.
*/
- STANDARD_MASK = 63 << 16,
+ ADATASPACE_STANDARD_MASK = 63 << 16,
/**
* Chromacity coordinates are unknown or are determined by the application.
@@ -79,7 +79,7 @@ enum ADataSpace : int32_t {
* For all other formats standard is undefined, and implementations should use
* an appropriate standard for the data represented.
*/
- STANDARD_UNSPECIFIED = 0 << 16,
+ ADATASPACE_STANDARD_UNSPECIFIED = 0 << 16,
/**
* <pre>
@@ -92,7 +92,7 @@ enum ADataSpace : int32_t {
* Use the unadjusted KR = 0.2126, KB = 0.0722 luminance interpretation
* for RGB conversion.
*/
- STANDARD_BT709 = 1 << 16,
+ ADATASPACE_STANDARD_BT709 = 1 << 16,
/**
* <pre>
@@ -107,7 +107,7 @@ enum ADataSpace : int32_t {
* to minimize the color shift into RGB space that uses BT.709
* primaries.
*/
- STANDARD_BT601_625 = 2 << 16,
+ ADATASPACE_STANDARD_BT601_625 = 2 << 16,
/**
* <pre>
@@ -120,7 +120,7 @@ enum ADataSpace : int32_t {
* Use the unadjusted KR = 0.222, KB = 0.071 luminance interpretation
* for RGB conversion.
*/
- STANDARD_BT601_625_UNADJUSTED = 3 << 16,
+ ADATASPACE_STANDARD_BT601_625_UNADJUSTED = 3 << 16,
/**
* <pre>
@@ -135,7 +135,7 @@ enum ADataSpace : int32_t {
* to minimize the color shift into RGB space that uses BT.709
* primaries.
*/
- STANDARD_BT601_525 = 4 << 16,
+ ADATASPACE_STANDARD_BT601_525 = 4 << 16,
/**
* <pre>
@@ -148,7 +148,7 @@ enum ADataSpace : int32_t {
* Use the unadjusted KR = 0.212, KB = 0.087 luminance interpretation
* for RGB conversion (as in SMPTE 240M).
*/
- STANDARD_BT601_525_UNADJUSTED = 5 << 16,
+ ADATASPACE_STANDARD_BT601_525_UNADJUSTED = 5 << 16,
/**
* <pre>
@@ -161,7 +161,7 @@ enum ADataSpace : int32_t {
* Use the unadjusted KR = 0.2627, KB = 0.0593 luminance interpretation
* for RGB conversion.
*/
- STANDARD_BT2020 = 6 << 16,
+ ADATASPACE_STANDARD_BT2020 = 6 << 16,
/**
* <pre>
@@ -174,7 +174,7 @@ enum ADataSpace : int32_t {
* Use the unadjusted KR = 0.2627, KB = 0.0593 luminance interpretation
* for RGB conversion using the linear domain.
*/
- STANDARD_BT2020_CONSTANT_LUMINANCE = 7 << 16,
+ ADATASPACE_STANDARD_BT2020_CONSTANT_LUMINANCE = 7 << 16,
/**
* <pre>
@@ -187,7 +187,7 @@ enum ADataSpace : int32_t {
* Use the unadjusted KR = 0.30, KB = 0.11 luminance interpretation
* for RGB conversion.
*/
- STANDARD_BT470M = 8 << 16,
+ ADATASPACE_STANDARD_BT470M = 8 << 16,
/**
* <pre>
@@ -200,7 +200,7 @@ enum ADataSpace : int32_t {
* Use the unadjusted KR = 0.254, KB = 0.068 luminance interpretation
* for RGB conversion.
*/
- STANDARD_FILM = 9 << 16,
+ ADATASPACE_STANDARD_FILM = 9 << 16,
/**
* SMPTE EG 432-1 and SMPTE RP 431-2. (DCI-P3)
@@ -211,7 +211,7 @@ enum ADataSpace : int32_t {
* red 0.680 0.320
* white (D65) 0.3127 0.3290</pre>
*/
- STANDARD_DCI_P3 = 10 << 16,
+ ADATASPACE_STANDARD_DCI_P3 = 10 << 16,
/**
* Adobe RGB
@@ -222,7 +222,7 @@ enum ADataSpace : int32_t {
* red 0.640 0.330
* white (D65) 0.3127 0.3290</pre>
*/
- STANDARD_ADOBE_RGB = 11 << 16,
+ ADATASPACE_STANDARD_ADOBE_RGB = 11 << 16,
/**
* Transfer aspect
@@ -237,7 +237,7 @@ enum ADataSpace : int32_t {
* component. Implementation may apply the transfer function in RGB space
* for all pixel formats if desired.
*/
- TRANSFER_MASK = 31 << 22,
+ ADATASPACE_TRANSFER_MASK = 31 << 22,
/**
* Transfer characteristics are unknown or are determined by the
@@ -245,13 +245,13 @@ enum ADataSpace : int32_t {
*
* Implementations should use the following transfer functions:
*
- * For YCbCr formats: use TRANSFER_SMPTE_170M
- * For RGB formats: use TRANSFER_SRGB
+ * For YCbCr formats: use ADATASPACE_TRANSFER_SMPTE_170M
+ * For RGB formats: use ADATASPACE_TRANSFER_SRGB
*
* For all other formats transfer function is undefined, and implementations
* should use an appropriate standard for the data represented.
*/
- TRANSFER_UNSPECIFIED = 0 << 22,
+ ADATASPACE_TRANSFER_UNSPECIFIED = 0 << 22,
/**
* Linear transfer.
@@ -261,7 +261,7 @@ enum ADataSpace : int32_t {
* L - luminance of image 0 <= L <= 1 for conventional colorimetry
* E - corresponding electrical signal</pre>
*/
- TRANSFER_LINEAR = 1 << 22,
+ ADATASPACE_TRANSFER_LINEAR = 1 << 22,
/**
* sRGB transfer.
@@ -272,7 +272,7 @@ enum ADataSpace : int32_t {
* L - luminance of image 0 <= L <= 1 for conventional colorimetry
* E - corresponding electrical signal</pre>
*/
- TRANSFER_SRGB = 2 << 22,
+ ADATASPACE_TRANSFER_SRGB = 2 << 22,
/**
* SMPTE 170M transfer.
@@ -283,7 +283,7 @@ enum ADataSpace : int32_t {
* L - luminance of image 0 <= L <= 1 for conventional colorimetry
* E - corresponding electrical signal</pre>
*/
- TRANSFER_SMPTE_170M = 3 << 22,
+ ADATASPACE_TRANSFER_SMPTE_170M = 3 << 22,
/**
* Display gamma 2.2.
@@ -293,7 +293,7 @@ enum ADataSpace : int32_t {
* L - luminance of image 0 <= L <= 1 for conventional colorimetry
* E - corresponding electrical signal</pre>
*/
- TRANSFER_GAMMA2_2 = 4 << 22,
+ ADATASPACE_TRANSFER_GAMMA2_2 = 4 << 22,
/**
* Display gamma 2.6.
@@ -303,7 +303,7 @@ enum ADataSpace : int32_t {
* L - luminance of image 0 <= L <= 1 for conventional colorimetry
* E - corresponding electrical signal</pre>
*/
- TRANSFER_GAMMA2_6 = 5 << 22,
+ ADATASPACE_TRANSFER_GAMMA2_6 = 5 << 22,
/**
* Display gamma 2.8.
@@ -313,7 +313,7 @@ enum ADataSpace : int32_t {
* L - luminance of image 0 <= L <= 1 for conventional colorimetry
* E - corresponding electrical signal</pre>
*/
- TRANSFER_GAMMA2_8 = 6 << 22,
+ ADATASPACE_TRANSFER_GAMMA2_8 = 6 << 22,
/**
* SMPTE ST 2084 (Dolby Perceptual Quantizer).
@@ -329,7 +329,7 @@ enum ADataSpace : int32_t {
* L = 1 corresponds to 10000 cd/m2
* E - corresponding electrical signal</pre>
*/
- TRANSFER_ST2084 = 7 << 22,
+ ADATASPACE_TRANSFER_ST2084 = 7 << 22,
/**
* ARIB STD-B67 Hybrid Log Gamma.
@@ -345,7 +345,7 @@ enum ADataSpace : int32_t {
* to reference white level of 100 cd/m2
* E - corresponding electrical signal</pre>
*/
- TRANSFER_HLG = 8 << 22,
+ ADATASPACE_TRANSFER_HLG = 8 << 22,
/**
* Range aspect
@@ -353,7 +353,7 @@ enum ADataSpace : int32_t {
* Defines the range of values corresponding to the unit range of 0-1.
* This is defined for YCbCr only, but can be expanded to RGB space.
*/
- RANGE_MASK = 7 << 27,
+ ADATASPACE_RANGE_MASK = 7 << 27,
/**
* Range is unknown or are determined by the application. Implementations
@@ -366,13 +366,13 @@ enum ADataSpace : int32_t {
* For all other formats range is undefined, and implementations should use
* an appropriate range for the data represented.
*/
- RANGE_UNSPECIFIED = 0 << 27,
+ ADATASPACE_RANGE_UNSPECIFIED = 0 << 27,
/**
* Full range uses all values for Y, Cb and Cr from
* 0 to 2^b-1, where b is the bit depth of the color format.
*/
- RANGE_FULL = 1 << 27,
+ ADATASPACE_RANGE_FULL = 1 << 27,
/**
* Limited range uses values 16/256*2^b to 235/256*2^b for Y, and
@@ -387,7 +387,7 @@ enum ADataSpace : int32_t {
* Luma (Y) samples should range from 64 to 940, inclusive
* Chroma (Cb, Cr) samples should range from 64 to 960, inclusive
*/
- RANGE_LIMITED = 2 << 27,
+ ADATASPACE_RANGE_LIMITED = 2 << 27,
/**
* Extended range is used for scRGB. Intended for use with
@@ -396,7 +396,7 @@ enum ADataSpace : int32_t {
* color outside the sRGB gamut.
* Used to blend / merge multiple dataspaces on a single display.
*/
- RANGE_EXTENDED = 3 << 27,
+ ADATASPACE_RANGE_EXTENDED = 3 << 27,
/**
* scRGB linear encoding
@@ -411,7 +411,8 @@ enum ADataSpace : int32_t {
*
* Uses extended range, linear transfer and BT.709 standard.
*/
- ADATASPACE_SCRGB_LINEAR = 406913024, // STANDARD_BT709 | TRANSFER_LINEAR | RANGE_EXTENDED
+ ADATASPACE_SCRGB_LINEAR = 406913024, // ADATASPACE_STANDARD_BT709 | ADATASPACE_TRANSFER_LINEAR |
+ // ADATASPACE_RANGE_EXTENDED
/**
* sRGB gamma encoding
@@ -426,7 +427,8 @@ enum ADataSpace : int32_t {
*
* Uses full range, sRGB transfer BT.709 standard.
*/
- ADATASPACE_SRGB = 142671872, // STANDARD_BT709 | TRANSFER_SRGB | RANGE_FULL
+ ADATASPACE_SRGB = 142671872, // ADATASPACE_STANDARD_BT709 | ADATASPACE_TRANSFER_SRGB |
+ // ADATASPACE_RANGE_FULL
/**
* scRGB
@@ -441,14 +443,16 @@ enum ADataSpace : int32_t {
*
* Uses extended range, sRGB transfer and BT.709 standard.
*/
- ADATASPACE_SCRGB = 411107328, // STANDARD_BT709 | TRANSFER_SRGB | RANGE_EXTENDED
+ ADATASPACE_SCRGB = 411107328, // ADATASPACE_STANDARD_BT709 | ADATASPACE_TRANSFER_SRGB |
+ // ADATASPACE_RANGE_EXTENDED
/**
* Display P3
*
* Uses full range, sRGB transfer and D65 DCI-P3 standard.
*/
- ADATASPACE_DISPLAY_P3 = 143261696, // STANDARD_DCI_P3 | TRANSFER_SRGB | RANGE_FULL
+ ADATASPACE_DISPLAY_P3 = 143261696, // ADATASPACE_STANDARD_DCI_P3 | ADATASPACE_TRANSFER_SRGB |
+ // ADATASPACE_RANGE_FULL
/**
* ITU-R Recommendation 2020 (BT.2020)
@@ -457,7 +461,8 @@ enum ADataSpace : int32_t {
*
* Uses full range, SMPTE 2084 (PQ) transfer and BT2020 standard.
*/
- ADATASPACE_BT2020_PQ = 163971072, // STANDARD_BT2020 | TRANSFER_ST2084 | RANGE_FULL
+ ADATASPACE_BT2020_PQ = 163971072, // ADATASPACE_STANDARD_BT2020 | ADATASPACE_TRANSFER_ST2084 |
+ // ADATASPACE_RANGE_FULL
/**
* ITU-R Recommendation 2020 (BT.2020)
@@ -466,7 +471,8 @@ enum ADataSpace : int32_t {
*
* Uses limited range, SMPTE 2084 (PQ) transfer and BT2020 standard.
*/
- ADATASPACE_BT2020_ITU_PQ = 298188800, // STANDARD_BT2020 | TRANSFER_ST2084 | RANGE_LIMITED
+ ADATASPACE_BT2020_ITU_PQ = 298188800, // ADATASPACE_STANDARD_BT2020 | ADATASPACE_TRANSFER_ST2084
+ // | ADATASPACE_RANGE_LIMITED
/**
* Adobe RGB
@@ -476,7 +482,8 @@ enum ADataSpace : int32_t {
* Note: Application is responsible for gamma encoding the data as
* a 2.2 gamma encoding is not supported in HW.
*/
- ADATASPACE_ADOBE_RGB = 151715840, // STANDARD_ADOBE_RGB | TRANSFER_GAMMA2_2 | RANGE_FULL
+ ADATASPACE_ADOBE_RGB = 151715840, // ADATASPACE_STANDARD_ADOBE_RGB |
+ // ADATASPACE_TRANSFER_GAMMA2_2 | ADATASPACE_RANGE_FULL
/**
* JPEG File Interchange Format (JFIF)
@@ -485,7 +492,8 @@ enum ADataSpace : int32_t {
*
* Uses full range, SMPTE 170M transfer and BT.601_625 standard.
*/
- ADATASPACE_JFIF = 146931712, // STANDARD_BT601_625 | TRANSFER_SMPTE_170M | RANGE_FULL
+ ADATASPACE_JFIF = 146931712, // ADATASPACE_STANDARD_BT601_625 | ADATASPACE_TRANSFER_SMPTE_170M |
+ // ADATASPACE_RANGE_FULL
/**
* ITU-R Recommendation 601 (BT.601) - 625-line
@@ -494,7 +502,8 @@ enum ADataSpace : int32_t {
*
* Uses limited range, SMPTE 170M transfer and BT.601_625 standard.
*/
- ADATASPACE_BT601_625 = 281149440, // STANDARD_BT601_625 | TRANSFER_SMPTE_170M | RANGE_LIMITED
+ ADATASPACE_BT601_625 = 281149440, // ADATASPACE_STANDARD_BT601_625 |
+ // ADATASPACE_TRANSFER_SMPTE_170M | ADATASPACE_RANGE_LIMITED
/**
* ITU-R Recommendation 601 (BT.601) - 525-line
@@ -503,7 +512,8 @@ enum ADataSpace : int32_t {
*
* Uses limited range, SMPTE 170M transfer and BT.601_525 standard.
*/
- ADATASPACE_BT601_525 = 281280512, // STANDARD_BT601_525 | TRANSFER_SMPTE_170M | RANGE_LIMITED
+ ADATASPACE_BT601_525 = 281280512, // ADATASPACE_STANDARD_BT601_525 |
+ // ADATASPACE_TRANSFER_SMPTE_170M | ADATASPACE_RANGE_LIMITED
/**
* ITU-R Recommendation 2020 (BT.2020)
@@ -512,7 +522,8 @@ enum ADataSpace : int32_t {
*
* Uses full range, SMPTE 170M transfer and BT2020 standard.
*/
- ADATASPACE_BT2020 = 147193856, // STANDARD_BT2020 | TRANSFER_SMPTE_170M | RANGE_FULL
+ ADATASPACE_BT2020 = 147193856, // ADATASPACE_STANDARD_BT2020 | ADATASPACE_TRANSFER_SMPTE_170M |
+ // ADATASPACE_RANGE_FULL
/**
* ITU-R Recommendation 709 (BT.709)
@@ -521,7 +532,8 @@ enum ADataSpace : int32_t {
*
* Uses limited range, SMPTE 170M transfer and BT.709 standard.
*/
- ADATASPACE_BT709 = 281083904, // STANDARD_BT709 | TRANSFER_SMPTE_170M | RANGE_LIMITED
+ ADATASPACE_BT709 = 281083904, // ADATASPACE_STANDARD_BT709 | ADATASPACE_TRANSFER_SMPTE_170M |
+ // ADATASPACE_RANGE_LIMITED
/**
* SMPTE EG 432-1 and SMPTE RP 431-2
@@ -533,7 +545,8 @@ enum ADataSpace : int32_t {
* Note: Application is responsible for gamma encoding the data as
* a 2.6 gamma encoding is not supported in HW.
*/
- ADATASPACE_DCI_P3 = 155844608, // STANDARD_DCI_P3 | TRANSFER_GAMMA2_6 | RANGE_FULL
+ ADATASPACE_DCI_P3 = 155844608, // ADATASPACE_STANDARD_DCI_P3 | ADATASPACE_TRANSFER_GAMMA2_6 |
+ // ADATASPACE_RANGE_FULL
/**
* sRGB linear encoding
@@ -547,21 +560,24 @@ enum ADataSpace : int32_t {
*
* Uses full range, linear transfer and BT.709 standard.
*/
- ADATASPACE_SRGB_LINEAR = 138477568, // STANDARD_BT709 | TRANSFER_LINEAR | RANGE_FULL
+ ADATASPACE_SRGB_LINEAR = 138477568, // ADATASPACE_STANDARD_BT709 | ADATASPACE_TRANSFER_LINEAR |
+ // ADATASPACE_RANGE_FULL
/**
* Hybrid Log Gamma encoding
*
* Uses full range, hybrid log gamma transfer and BT2020 standard.
*/
- ADATASPACE_BT2020_HLG = 168165376, // STANDARD_BT2020 | TRANSFER_HLG | RANGE_FULL
+ ADATASPACE_BT2020_HLG = 168165376, // ADATASPACE_STANDARD_BT2020 | ADATASPACE_TRANSFER_HLG |
+ // ADATASPACE_RANGE_FULL
/**
* ITU Hybrid Log Gamma encoding
*
* Uses limited range, hybrid log gamma transfer and BT2020 standard.
*/
- ADATASPACE_BT2020_ITU_HLG = 302383104, // STANDARD_BT2020 | TRANSFER_HLG | RANGE_LIMITED
+ ADATASPACE_BT2020_ITU_HLG = 302383104, // ADATASPACE_STANDARD_BT2020 | ADATASPACE_TRANSFER_HLG |
+ // ADATASPACE_RANGE_LIMITED
/**
* Depth
@@ -575,7 +591,37 @@ enum ADataSpace : int32_t {
*
* Embedded depth metadata following the dynamic depth specification.
*/
- ADATASPACE_DYNAMIC_DEPTH = 4098
+ ADATASPACE_DYNAMIC_DEPTH = 4098,
+
+#ifndef ADATASPACE_SKIP_LEGACY_DEFINES
+ STANDARD_MASK = ADATASPACE_STANDARD_MASK,
+ STANDARD_UNSPECIFIED = ADATASPACE_STANDARD_UNSPECIFIED,
+ STANDARD_BT709 = ADATASPACE_STANDARD_BT709,
+ STANDARD_BT601_625 = ADATASPACE_STANDARD_BT601_625,
+ STANDARD_BT601_625_UNADJUSTED = ADATASPACE_STANDARD_BT601_625_UNADJUSTED,
+ STANDARD_BT601_525 = ADATASPACE_STANDARD_BT601_525,
+ STANDARD_BT601_525_UNADJUSTED = ADATASPACE_STANDARD_BT601_525_UNADJUSTED,
+ STANDARD_BT470M = ADATASPACE_STANDARD_BT470M,
+ STANDARD_BT2020 = ADATASPACE_STANDARD_BT2020,
+ STANDARD_FILM = ADATASPACE_STANDARD_FILM,
+ STANDARD_DCI_P3 = ADATASPACE_STANDARD_DCI_P3,
+ STANDARD_ADOBE_RGB = ADATASPACE_STANDARD_ADOBE_RGB,
+ TRANSFER_MASK = ADATASPACE_TRANSFER_MASK,
+ TRANSFER_UNSPECIFIED = ADATASPACE_TRANSFER_UNSPECIFIED,
+ TRANSFER_LINEAR = ADATASPACE_TRANSFER_LINEAR,
+ TRANSFER_SMPTE_170M = ADATASPACE_TRANSFER_SMPTE_170M,
+ TRANSFER_GAMMA2_2 = ADATASPACE_TRANSFER_GAMMA2_2,
+ TRANSFER_GAMMA2_6 = ADATASPACE_TRANSFER_GAMMA2_6,
+ TRANSFER_GAMMA2_8 = ADATASPACE_TRANSFER_GAMMA2_8,
+ TRANSFER_SRGB = ADATASPACE_TRANSFER_SRGB,
+ TRANSFER_ST2084 = ADATASPACE_TRANSFER_ST2084,
+ TRANSFER_HLG = ADATASPACE_TRANSFER_HLG,
+ RANGE_MASK = ADATASPACE_RANGE_MASK,
+ RANGE_UNSPECIFIED = ADATASPACE_RANGE_UNSPECIFIED,
+ RANGE_FULL = ADATASPACE_RANGE_FULL,
+ RANGE_LIMITED = ADATASPACE_RANGE_LIMITED,
+ RANGE_EXTENDED = ADATASPACE_RANGE_EXTENDED,
+#endif
};
__END_DECLS
diff --git a/libs/nativewindow/include/android/hardware_buffer.h b/libs/nativewindow/include/android/hardware_buffer.h
index 21798d0e29..6fcb3a4842 100644
--- a/libs/nativewindow/include/android/hardware_buffer.h
+++ b/libs/nativewindow/include/android/hardware_buffer.h
@@ -46,9 +46,16 @@
#define ANDROID_HARDWARE_BUFFER_H
#include <android/rect.h>
+#define ADATASPACE_SKIP_LEGACY_DEFINES
+#include <android/data_space.h>
+#undef ADATASPACE_SKIP_LEGACY_DEFINES
#include <inttypes.h>
#include <sys/cdefs.h>
+#if !defined(__INTRODUCED_IN)
+#define __INTRODUCED_IN(__api_level) /* nothing */
+#endif
+
__BEGIN_DECLS
// clang-format off
diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h
index a98ea86073..969a5cff05 100644
--- a/libs/nativewindow/include/system/window.h
+++ b/libs/nativewindow/include/system/window.h
@@ -1095,10 +1095,19 @@ enum {
ANATIVEWINDOW_FRAME_RATE_CATEGORY_NORMAL = 3,
/**
+ * Indicates that, as a result of a user interaction, an animation is likely to start.
+ * This category is a signal that a user interaction heuristic determined the need of a
+ * high refresh rate, and is not an explicit request from the app.
+ * As opposed to FRAME_RATE_CATEGORY_HIGH, this vote may be ignored in favor of
+ * more explicit votes.
+ */
+ ANATIVEWINDOW_FRAME_RATE_CATEGORY_HIGH_HINT = 4,
+
+ /**
* Indicates a frame rate suitable for animations that require a high frame rate, which may
* increase smoothness but may also increase power usage.
*/
- ANATIVEWINDOW_FRAME_RATE_CATEGORY_HIGH = 4
+ ANATIVEWINDOW_FRAME_RATE_CATEGORY_HIGH = 5
};
/*
diff --git a/libs/nativewindow/include/vndk/hardware_buffer.h b/libs/nativewindow/include/vndk/hardware_buffer.h
index 21931bb553..48fb02f69d 100644
--- a/libs/nativewindow/include/vndk/hardware_buffer.h
+++ b/libs/nativewindow/include/vndk/hardware_buffer.h
@@ -21,6 +21,7 @@
#include <android/hardware_buffer.h>
#include <cutils/native_handle.h>
+#include <errno.h>
__BEGIN_DECLS
@@ -105,6 +106,76 @@ enum {
AHARDWAREBUFFER_USAGE_CAMERA_MASK = 6UL << 16,
};
+/**
+ * Additional options for AHardwareBuffer_allocateWithOptions. These correspond to
+ * android.hardware.graphics.common.ExtendableType
+ */
+typedef struct {
+ const char* _Nonnull name;
+ int64_t value;
+} AHardwareBufferLongOptions;
+
+enum AHardwareBufferStatus : int32_t {
+ /* Success, no error */
+ AHARDWAREBUFFER_STATUS_OK = 0,
+ /* There's insufficient memory to satisfy the request */
+ AHARDWAREBUFFER_STATUS_NO_MEMORY = -ENOMEM,
+ /* The given argument is invalid */
+ AHARDWAREBUFFER_STATUS_BAD_VALUE = -EINVAL,
+ /* The requested operation is not supported by the device */
+ AHARDWAREBUFFER_STATUS_UNSUPPORTED = -ENOSYS,
+ /* An unknown error occurred */
+ AHARDWAREBUFFER_STATUS_UNKNOWN_ERROR = (-2147483647 - 1),
+};
+
+/**
+ * Allocates a buffer that matches the passed AHardwareBuffer_Desc with additional options
+ *
+ * If allocation succeeds, the buffer can be used according to the
+ * usage flags specified in its description. If a buffer is used in ways
+ * not compatible with its usage flags, the results are undefined and
+ * may include program termination.
+ *
+ * @param desc The AHardwareBuffer_Desc that describes the allocation to request. Note that `stride`
+ * is ignored.
+ * @param additionalOptions A pointer to an array of AHardwareBufferLongOptions with additional
+ * string key + long value options that may be specified. May be null if
+ * `additionalOptionsSize` is 0
+ * @param additionalOptionsSize The number of additional options to pass
+ * @param outBuffer The resulting buffer allocation
+ * @return AHARDWAREBUFFER_STATUS_OK on success
+ * AHARDWAREBUFFER_STATUS_NO_MEMORY if there's insufficient resources for the allocation
+ * AHARDWAREBUFFER_STATUS_BAD_VALUE if the provided description & options are not supported
+ * by the device
+ * AHARDWAREBUFFER_STATUS_UNKNOWN_ERROR for any other error
+ * any reason. The returned buffer has a reference count of 1.
+ */
+enum AHardwareBufferStatus AHardwareBuffer_allocateWithOptions(
+ const AHardwareBuffer_Desc* _Nonnull desc,
+ const AHardwareBufferLongOptions* _Nullable additionalOptions, size_t additionalOptionsSize,
+ AHardwareBuffer* _Nullable* _Nonnull outBuffer) __INTRODUCED_IN(__ANDROID_API_V__);
+
+/**
+ * Queries the dataspace of the given AHardwareBuffer.
+ *
+ * @param buffer The non-null buffer for which to query the Dataspace
+ * @return The dataspace of the buffer, or ADATASPACE_UNKNOWN if one hasn't been set
+ */
+enum ADataSpace AHardwareBuffer_getDataSpace(const AHardwareBuffer* _Nonnull buffer)
+ __INTRODUCED_IN(__ANDROID_API_V__);
+
+/**
+ * Sets the dataspace of the given AHardwareBuffer
+ * @param buffer The non-null buffer for which to set the dataspace
+ * @param dataSpace The dataspace to set
+ * @return AHARDWAREBUFFER_STATUS_OK on success,
+ * AHARDWAREBUFFER_STATUS_UNSUPPORTED if the device doesn't support setting the dataspace,
+ * AHARDWAREBUFFER_STATUS_UNKNOWN_ERROR for any other failure.
+ */
+enum AHardwareBufferStatus AHardwareBuffer_setDataSpace(AHardwareBuffer* _Nonnull buffer,
+ enum ADataSpace dataSpace)
+ __INTRODUCED_IN(__ANDROID_API_V__);
+
__END_DECLS
#endif /* ANDROID_VNDK_NATIVEWINDOW_AHARDWAREBUFFER_H */
diff --git a/libs/nativewindow/libnativewindow.map.txt b/libs/nativewindow/libnativewindow.map.txt
index 95fc920da1..e29d5a6bb4 100644
--- a/libs/nativewindow/libnativewindow.map.txt
+++ b/libs/nativewindow/libnativewindow.map.txt
@@ -2,6 +2,7 @@ LIBNATIVEWINDOW {
global:
AHardwareBuffer_acquire;
AHardwareBuffer_allocate;
+ AHardwareBuffer_allocateWithOptions; # llndk systemapi
AHardwareBuffer_createFromHandle; # llndk systemapi
AHardwareBuffer_describe;
AHardwareBuffer_getId; # introduced=31
@@ -16,6 +17,8 @@ LIBNATIVEWINDOW {
AHardwareBuffer_unlock;
AHardwareBuffer_readFromParcel; # introduced=34
AHardwareBuffer_writeToParcel; # introduced=34
+ AHardwareBuffer_getDataSpace; # llndk systemapi
+ AHardwareBuffer_setDataSpace; # llndk systemapi
ANativeWindowBuffer_getHardwareBuffer; # llndk
ANativeWindow_OemStorageGet; # llndk
ANativeWindow_OemStorageSet; # llndk
diff --git a/libs/nativewindow/rust/Android.bp b/libs/nativewindow/rust/Android.bp
index 90d0a8e400..a3df4820ba 100644
--- a/libs/nativewindow/rust/Android.bp
+++ b/libs/nativewindow/rust/Android.bp
@@ -16,6 +16,7 @@ package {
default_applicable_licenses: [
"frameworks_native_libs_nativewindow_license",
],
+ default_team: "trendy_team_android_core_graphics_stack",
}
rust_bindgen {
diff --git a/libs/nativewindow/tests/AHardwareBufferTest.cpp b/libs/nativewindow/tests/AHardwareBufferTest.cpp
index ef863b6d67..136395aac0 100644
--- a/libs/nativewindow/tests/AHardwareBufferTest.cpp
+++ b/libs/nativewindow/tests/AHardwareBufferTest.cpp
@@ -17,6 +17,8 @@
#define LOG_TAG "AHardwareBuffer_test"
//#define LOG_NDEBUG 0
+#include <android-base/properties.h>
+#include <android/data_space.h>
#include <android/hardware/graphics/common/1.0/types.h>
#include <gtest/gtest.h>
#include <private/android/AHardwareBufferHelpers.h>
@@ -26,6 +28,10 @@
using namespace android;
using android::hardware::graphics::common::V1_0::BufferUsage;
+static bool IsCuttlefish() {
+ return ::android::base::GetProperty("ro.product.board", "") == "cutf";
+}
+
static ::testing::AssertionResult BuildHexFailureMessage(uint64_t expected,
uint64_t actual, const char* type) {
std::ostringstream ss;
@@ -170,3 +176,83 @@ TEST(AHardwareBufferTest, GetIdTest) {
EXPECT_NE(id1, id2);
}
+
+TEST(AHardwareBufferTest, Allocate2NoExtras) {
+ AHardwareBuffer_Desc desc{
+ .width = 64,
+ .height = 1,
+ .layers = 1,
+ .format = AHARDWAREBUFFER_FORMAT_BLOB,
+ .usage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN | AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN,
+ .stride = 0,
+ };
+
+ AHardwareBuffer* buffer = nullptr;
+ ASSERT_EQ(0, AHardwareBuffer_allocateWithOptions(&desc, nullptr, 0, &buffer));
+ uint64_t id = 0;
+ EXPECT_EQ(0, AHardwareBuffer_getId(buffer, &id));
+ EXPECT_NE(0, id);
+ AHardwareBuffer_Desc desc2{};
+ AHardwareBuffer_describe(buffer, &desc2);
+ EXPECT_EQ(desc.width, desc2.width);
+ EXPECT_EQ(desc.height, desc2.height);
+ EXPECT_GE(desc2.stride, desc2.width);
+
+ AHardwareBuffer_release(buffer);
+}
+
+TEST(AHardwareBufferTest, Allocate2WithExtras) {
+ if (!IsCuttlefish()) {
+ GTEST_SKIP() << "Unknown gralloc HAL, cannot test extras";
+ }
+
+ AHardwareBuffer_Desc desc{
+ .width = 64,
+ .height = 48,
+ .layers = 1,
+ .format = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
+ .usage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN | AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN,
+ .stride = 0,
+ };
+
+ AHardwareBuffer* buffer = nullptr;
+ std::array<AHardwareBufferLongOptions, 1> extras = {{
+ {.name = "android.hardware.graphics.common.Dataspace", ADATASPACE_DISPLAY_P3},
+ }};
+ ASSERT_EQ(0, AHardwareBuffer_allocateWithOptions(&desc, extras.data(), extras.size(), &buffer));
+ uint64_t id = 0;
+ EXPECT_EQ(0, AHardwareBuffer_getId(buffer, &id));
+ EXPECT_NE(0, id);
+ AHardwareBuffer_Desc desc2{};
+ AHardwareBuffer_describe(buffer, &desc2);
+ EXPECT_EQ(desc.width, desc2.width);
+ EXPECT_EQ(desc.height, desc2.height);
+ EXPECT_GE(desc2.stride, desc2.width);
+
+ EXPECT_EQ(ADATASPACE_DISPLAY_P3, AHardwareBuffer_getDataSpace(buffer));
+
+ AHardwareBuffer_release(buffer);
+}
+
+TEST(AHardwareBufferTest, GetSetDataspace) {
+ AHardwareBuffer_Desc desc{
+ .width = 64,
+ .height = 48,
+ .layers = 1,
+ .format = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
+ .usage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN | AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN,
+ .stride = 0,
+ };
+
+ AHardwareBuffer* buffer = nullptr;
+ ASSERT_EQ(0, AHardwareBuffer_allocate(&desc, &buffer));
+
+ EXPECT_EQ(ADATASPACE_UNKNOWN, AHardwareBuffer_getDataSpace(buffer));
+ AHardwareBufferStatus status = AHardwareBuffer_setDataSpace(buffer, ADATASPACE_DISPLAY_P3);
+ if (status != AHARDWAREBUFFER_STATUS_UNSUPPORTED) {
+ EXPECT_EQ(0, status);
+ EXPECT_EQ(ADATASPACE_DISPLAY_P3, AHardwareBuffer_getDataSpace(buffer));
+ }
+
+ AHardwareBuffer_release(buffer);
+} \ No newline at end of file
diff --git a/libs/nativewindow/tests/Android.bp b/libs/nativewindow/tests/Android.bp
index 30737c1bf6..a4ebcaca0e 100644
--- a/libs/nativewindow/tests/Android.bp
+++ b/libs/nativewindow/tests/Android.bp
@@ -23,6 +23,7 @@ package {
default_applicable_licenses: [
"frameworks_native_libs_nativewindow_license",
],
+ default_team: "trendy_team_android_core_graphics_stack",
}
cc_test {
@@ -31,6 +32,7 @@ cc_test {
"device-tests",
],
shared_libs: [
+ "libbase",
"libgui",
"liblog",
"libnativewindow",
@@ -44,5 +46,8 @@ cc_test {
"ANativeWindowTest.cpp",
"c_compatibility.c",
],
- cflags: ["-Wall", "-Werror"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
}
diff --git a/libs/nativewindow/tests/benchmark/Android.bp b/libs/nativewindow/tests/benchmark/Android.bp
index 6f844cf864..b815d80142 100644
--- a/libs/nativewindow/tests/benchmark/Android.bp
+++ b/libs/nativewindow/tests/benchmark/Android.bp
@@ -12,6 +12,11 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ default_applicable_licenses: ["frameworks_native_license"],
+ default_team: "trendy_team_android_core_graphics_stack",
+}
+
cc_defaults {
name: "nativewindow_benchmark_defaults_cc",
shared_libs: ["libnativewindow"],
diff --git a/libs/renderengine/Android.bp b/libs/renderengine/Android.bp
index ba2eb7d224..09d7cb5d3f 100644
--- a/libs/renderengine/Android.bp
+++ b/libs/renderengine/Android.bp
@@ -5,6 +5,7 @@ package {
// to get the below license kinds:
// SPDX-license-identifier-Apache-2.0
default_applicable_licenses: ["frameworks_native_license"],
+ default_team: "trendy_team_android_core_graphics_stack",
}
cc_defaults {
@@ -48,11 +49,19 @@ cc_defaults {
static_libs: [
"libshaders",
"libtonemap",
+ "libsurfaceflinger_common",
],
local_include_dirs: ["include"],
export_include_dirs: ["include"],
}
+// Needed by FlagManager to access a #define.
+cc_library_static {
+ name: "librenderengine_includes",
+ local_include_dirs: ["include"],
+ export_include_dirs: ["include"],
+}
+
filegroup {
name: "librenderengine_sources",
srcs: [
@@ -78,6 +87,7 @@ filegroup {
"skia/SkiaRenderEngine.cpp",
"skia/SkiaGLRenderEngine.cpp",
"skia/SkiaVkRenderEngine.cpp",
+ "skia/VulkanInterface.cpp",
"skia/debug/CaptureTimer.cpp",
"skia/debug/CommonPool.cpp",
"skia/debug/SkiaCapture.cpp",
diff --git a/libs/renderengine/RenderEngine.cpp b/libs/renderengine/RenderEngine.cpp
index 3e1ac33d57..233134d2db 100644
--- a/libs/renderengine/RenderEngine.cpp
+++ b/libs/renderengine/RenderEngine.cpp
@@ -28,28 +28,28 @@ namespace android {
namespace renderengine {
std::unique_ptr<RenderEngine> RenderEngine::create(const RenderEngineCreationArgs& args) {
- switch (args.renderEngineType) {
- case RenderEngineType::SKIA_GL:
+ if (args.threaded == Threaded::YES) {
+ switch (args.graphicsApi) {
+ case GraphicsApi::GL:
+ ALOGD("Threaded RenderEngine with SkiaGL Backend");
+ return renderengine::threaded::RenderEngineThreaded::create([args]() {
+ return android::renderengine::skia::SkiaGLRenderEngine::create(args);
+ });
+ case GraphicsApi::VK:
+ ALOGD("Threaded RenderEngine with SkiaVK Backend");
+ return renderengine::threaded::RenderEngineThreaded::create([args]() {
+ return android::renderengine::skia::SkiaVkRenderEngine::create(args);
+ });
+ }
+ }
+
+ switch (args.graphicsApi) {
+ case GraphicsApi::GL:
ALOGD("RenderEngine with SkiaGL Backend");
return renderengine::skia::SkiaGLRenderEngine::create(args);
- case RenderEngineType::SKIA_VK:
+ case GraphicsApi::VK:
ALOGD("RenderEngine with SkiaVK Backend");
return renderengine::skia::SkiaVkRenderEngine::create(args);
- case RenderEngineType::SKIA_GL_THREADED: {
- ALOGD("Threaded RenderEngine with SkiaGL Backend");
- return renderengine::threaded::RenderEngineThreaded::create(
- [args]() {
- return android::renderengine::skia::SkiaGLRenderEngine::create(args);
- },
- args.renderEngineType);
- }
- case RenderEngineType::SKIA_VK_THREADED:
- ALOGD("Threaded RenderEngine with SkiaVK Backend");
- return renderengine::threaded::RenderEngineThreaded::create(
- [args]() {
- return android::renderengine::skia::SkiaVkRenderEngine::create(args);
- },
- args.renderEngineType);
}
}
diff --git a/libs/renderengine/benchmark/Android.bp b/libs/renderengine/benchmark/Android.bp
index 55c34cd059..e1a6f6af0d 100644
--- a/libs/renderengine/benchmark/Android.bp
+++ b/libs/renderengine/benchmark/Android.bp
@@ -19,6 +19,7 @@ package {
// to get the below license kinds:
// SPDX-license-identifier-Apache-2.0
default_applicable_licenses: ["frameworks_native_license"],
+ default_team: "trendy_team_android_core_graphics_stack",
}
cc_benchmark {
@@ -37,6 +38,7 @@ cc_benchmark {
static_libs: [
"librenderengine",
"libshaders",
+ "libsurfaceflinger_common",
"libtonemap",
],
cflags: [
@@ -54,6 +56,7 @@ cc_benchmark {
"libsync",
"libui",
"libutils",
+ "server_configurable_flags",
],
data: ["resources/*"],
diff --git a/libs/renderengine/benchmark/RenderEngineBench.cpp b/libs/renderengine/benchmark/RenderEngineBench.cpp
index a7f1df9a9b..101f519e55 100644
--- a/libs/renderengine/benchmark/RenderEngineBench.cpp
+++ b/libs/renderengine/benchmark/RenderEngineBench.cpp
@@ -30,46 +30,6 @@ using namespace android;
using namespace android::renderengine;
///////////////////////////////////////////////////////////////////////////////
-// Helpers for Benchmark::Apply
-///////////////////////////////////////////////////////////////////////////////
-
-std::string RenderEngineTypeName(RenderEngine::RenderEngineType type) {
- switch (type) {
- case RenderEngine::RenderEngineType::SKIA_GL_THREADED:
- return "skiaglthreaded";
- case RenderEngine::RenderEngineType::SKIA_GL:
- return "skiagl";
- case RenderEngine::RenderEngineType::SKIA_VK:
- return "skiavk";
- case RenderEngine::RenderEngineType::SKIA_VK_THREADED:
- return "skiavkthreaded";
- }
-}
-
-/**
- * Passed (indirectly - see RunSkiaGLThreaded) to Benchmark::Apply to create a
- * Benchmark which specifies which RenderEngineType it uses.
- *
- * This simplifies calling ->Arg(type)->Arg(type) and provides strings to make
- * it obvious which version is being run.
- *
- * @param b The benchmark family
- * @param type The type of RenderEngine to use.
- */
-static void AddRenderEngineType(benchmark::internal::Benchmark* b,
- RenderEngine::RenderEngineType type) {
- b->Arg(static_cast<int64_t>(type));
- b->ArgName(RenderEngineTypeName(type));
-}
-
-/**
- * Run a benchmark once using SKIA_GL_THREADED.
- */
-static void RunSkiaGLThreaded(benchmark::internal::Benchmark* b) {
- AddRenderEngineType(b, RenderEngine::RenderEngineType::SKIA_GL_THREADED);
-}
-
-///////////////////////////////////////////////////////////////////////////////
// Helpers for calling drawLayers
///////////////////////////////////////////////////////////////////////////////
@@ -104,7 +64,8 @@ std::pair<uint32_t, uint32_t> getDisplaySize() {
return std::pair<uint32_t, uint32_t>(width, height);
}
-static std::unique_ptr<RenderEngine> createRenderEngine(RenderEngine::RenderEngineType type) {
+static std::unique_ptr<RenderEngine> createRenderEngine(RenderEngine::Threaded threaded,
+ RenderEngine::GraphicsApi graphicsApi) {
auto args = RenderEngineCreationArgs::Builder()
.setPixelFormat(static_cast<int>(ui::PixelFormat::RGBA_8888))
.setImageCacheSize(1)
@@ -112,7 +73,8 @@ static std::unique_ptr<RenderEngine> createRenderEngine(RenderEngine::RenderEngi
.setPrecacheToneMapperShaderOnly(false)
.setSupportsBackgroundBlur(true)
.setContextPriority(RenderEngine::ContextPriority::REALTIME)
- .setRenderEngineType(type)
+ .setThreaded(threaded)
+ .setGraphicsApi(graphicsApi)
.build();
return RenderEngine::create(args);
}
@@ -214,8 +176,11 @@ static void benchDrawLayers(RenderEngine& re, const std::vector<LayerSettings>&
// Benchmarks
///////////////////////////////////////////////////////////////////////////////
-void BM_blur(benchmark::State& benchState) {
- auto re = createRenderEngine(static_cast<RenderEngine::RenderEngineType>(benchState.range()));
+template <class... Args>
+void BM_blur(benchmark::State& benchState, Args&&... args) {
+ auto args_tuple = std::make_tuple(std::move(args)...);
+ auto re = createRenderEngine(static_cast<RenderEngine::Threaded>(std::get<0>(args_tuple)),
+ static_cast<RenderEngine::GraphicsApi>(std::get<1>(args_tuple)));
// Initially use cpu access so we can decode into it with AImageDecoder.
auto [width, height] = getDisplaySize();
@@ -259,4 +224,5 @@ void BM_blur(benchmark::State& benchState) {
benchDrawLayers(*re, layers, benchState, "blurred");
}
-BENCHMARK(BM_blur)->Apply(RunSkiaGLThreaded);
+BENCHMARK_CAPTURE(BM_blur, SkiaGLThreaded, RenderEngine::Threaded::YES,
+ RenderEngine::GraphicsApi::GL);
diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h
index 818d0350c0..de05268a67 100644
--- a/libs/renderengine/include/renderengine/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/RenderEngine.h
@@ -33,7 +33,7 @@
#include <memory>
/**
- * Allows to set RenderEngine backend to GLES (default) or SkiaGL (NOT yet supported).
+ * Allows to override the RenderEngine backend.
*/
#define PROPERTY_DEBUG_RENDERENGINE_BACKEND "debug.renderengine.backend"
@@ -92,15 +92,20 @@ public:
REALTIME = 4,
};
- enum class RenderEngineType {
- SKIA_GL = 3,
- SKIA_GL_THREADED = 4,
- SKIA_VK = 5,
- SKIA_VK_THREADED = 6,
+ enum class Threaded {
+ NO,
+ YES,
+ };
+
+ enum class GraphicsApi {
+ GL,
+ VK,
};
static std::unique_ptr<RenderEngine> create(const RenderEngineCreationArgs& args);
+ static bool canSupport(GraphicsApi);
+
virtual ~RenderEngine() = 0;
// ----- BEGIN DEPRECATED INTERFACE -----
@@ -176,10 +181,9 @@ public:
// query is required to be thread safe.
virtual bool supportsBackgroundBlur() = 0;
- // Returns the current type of RenderEngine instance that was created.
// TODO(b/180767535): This is only implemented to allow for backend-specific behavior, which
// we should not allow in general, so remove this.
- RenderEngineType getRenderEngineType() const { return mRenderEngineType; }
+ bool isThreaded() const { return mThreaded == Threaded::YES; }
static void validateInputBufferUsage(const sp<GraphicBuffer>&);
static void validateOutputBufferUsage(const sp<GraphicBuffer>&);
@@ -191,9 +195,9 @@ public:
virtual void setEnableTracing(bool /*tracingEnabled*/) {}
protected:
- RenderEngine() : RenderEngine(RenderEngineType::SKIA_GL) {}
+ RenderEngine() : RenderEngine(Threaded::NO) {}
- RenderEngine(RenderEngineType type) : mRenderEngineType(type) {}
+ RenderEngine(Threaded threaded) : mThreaded(threaded) {}
// Maps GPU resources for this buffer.
// Note that work may be deferred to an additional thread, i.e. this call
@@ -228,7 +232,7 @@ protected:
friend class impl::ExternalTexture;
friend class threaded::RenderEngineThreaded;
friend class RenderEngineTest_cleanupPostRender_cleansUpOnce_Test;
- const RenderEngineType mRenderEngineType;
+ const Threaded mThreaded;
// Update protectedContext mode depending on whether or not any layer has a protected buffer.
void updateProtectedContext(const std::vector<LayerSettings>&,
@@ -251,7 +255,8 @@ struct RenderEngineCreationArgs {
bool precacheToneMapperShaderOnly;
bool supportsBackgroundBlur;
RenderEngine::ContextPriority contextPriority;
- RenderEngine::RenderEngineType renderEngineType;
+ RenderEngine::Threaded threaded;
+ RenderEngine::GraphicsApi graphicsApi;
struct Builder;
@@ -261,14 +266,16 @@ private:
bool _enableProtectedContext, bool _precacheToneMapperShaderOnly,
bool _supportsBackgroundBlur,
RenderEngine::ContextPriority _contextPriority,
- RenderEngine::RenderEngineType _renderEngineType)
+ RenderEngine::Threaded _threaded,
+ RenderEngine::GraphicsApi _graphicsApi)
: pixelFormat(_pixelFormat),
imageCacheSize(_imageCacheSize),
enableProtectedContext(_enableProtectedContext),
precacheToneMapperShaderOnly(_precacheToneMapperShaderOnly),
supportsBackgroundBlur(_supportsBackgroundBlur),
contextPriority(_contextPriority),
- renderEngineType(_renderEngineType) {}
+ threaded(_threaded),
+ graphicsApi(_graphicsApi) {}
RenderEngineCreationArgs() = delete;
};
@@ -299,14 +306,18 @@ struct RenderEngineCreationArgs::Builder {
this->contextPriority = contextPriority;
return *this;
}
- Builder& setRenderEngineType(RenderEngine::RenderEngineType renderEngineType) {
- this->renderEngineType = renderEngineType;
+ Builder& setThreaded(RenderEngine::Threaded threaded) {
+ this->threaded = threaded;
+ return *this;
+ }
+ Builder& setGraphicsApi(RenderEngine::GraphicsApi graphicsApi) {
+ this->graphicsApi = graphicsApi;
return *this;
}
RenderEngineCreationArgs build() const {
return RenderEngineCreationArgs(pixelFormat, imageCacheSize, enableProtectedContext,
precacheToneMapperShaderOnly, supportsBackgroundBlur,
- contextPriority, renderEngineType);
+ contextPriority, threaded, graphicsApi);
}
private:
@@ -317,8 +328,8 @@ private:
bool precacheToneMapperShaderOnly = false;
bool supportsBackgroundBlur = false;
RenderEngine::ContextPriority contextPriority = RenderEngine::ContextPriority::MEDIUM;
- RenderEngine::RenderEngineType renderEngineType =
- RenderEngine::RenderEngineType::SKIA_GL_THREADED;
+ RenderEngine::Threaded threaded = RenderEngine::Threaded::YES;
+ RenderEngine::GraphicsApi graphicsApi = RenderEngine::GraphicsApi::GL;
};
} // namespace renderengine
diff --git a/libs/renderengine/skia/AutoBackendTexture.cpp b/libs/renderengine/skia/AutoBackendTexture.cpp
index 92fe4c0b47..ee95e59d90 100644
--- a/libs/renderengine/skia/AutoBackendTexture.cpp
+++ b/libs/renderengine/skia/AutoBackendTexture.cpp
@@ -77,7 +77,7 @@ AutoBackendTexture::AutoBackendTexture(GrDirectContext* context, AHardwareBuffer
backendFormat,
isOutputBuffer);
} else {
- LOG_ALWAYS_FATAL("Unexpected backend %d", backend);
+ LOG_ALWAYS_FATAL("Unexpected backend %u", static_cast<unsigned>(backend));
}
mColorType = GrAHardwareBufferUtils::GetSkColorTypeFromBufferFormat(desc.format);
@@ -145,8 +145,8 @@ void logFatalTexture(const char* msg, const GrBackendTexture& tex, ui::Dataspace
"\n\tGrBackendTexture: (%i x %i) hasMipmaps: %i isProtected: %i "
"texType: %i\n\t\tVkImageInfo: success: %i fFormat: %i "
"fSampleCount: %u fLevelCount: %u colorType %i",
- msg, tex.isValid(), dataspace, tex.width(), tex.height(),
- tex.hasMipmaps(), tex.isProtected(),
+ msg, tex.isValid(), static_cast<int32_t>(dataspace), tex.width(),
+ tex.height(), tex.hasMipmaps(), tex.isProtected(),
static_cast<int>(tex.textureType()), retrievedImageInfo,
imageInfo.fFormat, imageInfo.fSampleCount, imageInfo.fLevelCount,
colorType);
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
index 2053c6a34f..fea4129ec0 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
@@ -236,7 +236,13 @@ EGLConfig SkiaGLRenderEngine::chooseEglConfig(EGLDisplay display, int format, bo
err = selectEGLConfig(display, format, 0, &config);
if (err != NO_ERROR) {
// this EGL is too lame for android
- LOG_ALWAYS_FATAL("no suitable EGLConfig found, giving up");
+ LOG_ALWAYS_FATAL("no suitable EGLConfig found, giving up"
+ " (format: %d, vendor: %s, version: %s, extensions: %s, Client"
+ " API: %s)",
+ format, eglQueryString(display, EGL_VENDOR),
+ eglQueryString(display, EGL_VERSION),
+ eglQueryString(display, EGL_EXTENSIONS),
+ eglQueryString(display, EGL_CLIENT_APIS) ?: "Not Supported");
}
}
}
@@ -262,7 +268,7 @@ EGLConfig SkiaGLRenderEngine::chooseEglConfig(EGLDisplay display, int format, bo
SkiaGLRenderEngine::SkiaGLRenderEngine(const RenderEngineCreationArgs& args, EGLDisplay display,
EGLContext ctxt, EGLSurface placeholder,
EGLContext protectedContext, EGLSurface protectedPlaceholder)
- : SkiaRenderEngine(args.renderEngineType, static_cast<PixelFormat>(args.pixelFormat),
+ : SkiaRenderEngine(args.threaded, static_cast<PixelFormat>(args.pixelFormat),
args.supportsBackgroundBlur),
mEGLDisplay(display),
mEGLContext(ctxt),
diff --git a/libs/renderengine/skia/SkiaRenderEngine.cpp b/libs/renderengine/skia/SkiaRenderEngine.cpp
index 88326e77d7..6e393f03fa 100644
--- a/libs/renderengine/skia/SkiaRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaRenderEngine.cpp
@@ -53,6 +53,7 @@
#include <SkSurface.h>
#include <SkTileMode.h>
#include <android-base/stringprintf.h>
+#include <common/FlagManager.h>
#include <gui/FenceMonitor.h>
#include <gui/TraceUtils.h>
#include <include/gpu/ganesh/SkSurfaceGanesh.h>
@@ -269,9 +270,9 @@ void SkiaRenderEngine::setEnableTracing(bool tracingEnabled) {
SkAndroidFrameworkTraceUtil::setEnableTracing(tracingEnabled);
}
-SkiaRenderEngine::SkiaRenderEngine(RenderEngineType type, PixelFormat pixelFormat,
+SkiaRenderEngine::SkiaRenderEngine(Threaded threaded, PixelFormat pixelFormat,
bool supportsBackgroundBlur)
- : RenderEngine(type), mDefaultPixelFormat(pixelFormat) {
+ : RenderEngine(threaded), mDefaultPixelFormat(pixelFormat) {
if (supportsBackgroundBlur) {
ALOGD("Background Blurs Enabled");
mBlurFilter = new KawaseBlurFilter();
@@ -389,10 +390,9 @@ void SkiaRenderEngine::ensureGrContextsCreated() {
void SkiaRenderEngine::mapExternalTextureBuffer(const sp<GraphicBuffer>& buffer,
bool isRenderable) {
// Only run this if RE is running on its own thread. This
- // way the access to GL operations is guaranteed to be happening on the
+ // way the access to GL/VK operations is guaranteed to be happening on the
// same thread.
- if (mRenderEngineType != RenderEngineType::SKIA_GL_THREADED &&
- mRenderEngineType != RenderEngineType::SKIA_VK_THREADED) {
+ if (!isThreaded()) {
return;
}
// We don't attempt to map a buffer if the buffer contains protected content. In GL this is
@@ -420,6 +420,9 @@ void SkiaRenderEngine::mapExternalTextureBuffer(const sp<GraphicBuffer>& buffer,
mGraphicBufferExternalRefs[buffer->getId()]++;
if (const auto& iter = cache.find(buffer->getId()); iter == cache.end()) {
+ if (FlagManager::getInstance().renderable_buffer_usage()) {
+ isRenderable = buffer->getUsage() & GRALLOC_USAGE_HW_RENDER;
+ }
std::shared_ptr<AutoBackendTexture::LocalRef> imageTextureRef =
std::make_shared<AutoBackendTexture::LocalRef>(grContext,
buffer->toAHardwareBuffer(),
@@ -761,10 +764,11 @@ void SkiaRenderEngine::drawLayersInternal(
// save a snapshot of the activeSurface to use as input to the blur shaders
blurInput = activeSurface->makeImageSnapshot();
- // blit the offscreen framebuffer into the destination AHB, but only
- // if there are blur regions. backgroundBlurRadius blurs the entire
- // image below, so it can skip this step.
- if (layer.blurRegions.size()) {
+ // blit the offscreen framebuffer into the destination AHB. This ensures that
+ // even if the blurred image does not cover the screen (for example, during
+ // a rotation animation, or if blur regions are used), the entire screen is
+ // initialized.
+ if (layer.blurRegions.size() || FlagManager::getInstance().restore_blur_step()) {
SkPaint paint;
paint.setBlendMode(SkBlendMode::kSrc);
if (CC_UNLIKELY(mCapture->isCaptureRunning())) {
diff --git a/libs/renderengine/skia/SkiaRenderEngine.h b/libs/renderengine/skia/SkiaRenderEngine.h
index ac134afa64..e88d44cca6 100644
--- a/libs/renderengine/skia/SkiaRenderEngine.h
+++ b/libs/renderengine/skia/SkiaRenderEngine.h
@@ -59,7 +59,7 @@ class BlurFilter;
class SkiaRenderEngine : public RenderEngine {
public:
static std::unique_ptr<SkiaRenderEngine> create(const RenderEngineCreationArgs& args);
- SkiaRenderEngine(RenderEngineType type, PixelFormat pixelFormat, bool supportsBackgroundBlur);
+ SkiaRenderEngine(Threaded, PixelFormat pixelFormat, bool supportsBackgroundBlur);
~SkiaRenderEngine() override;
std::future<void> primeCache(bool shouldPrimeUltraHDR) override final;
diff --git a/libs/renderengine/skia/SkiaVkRenderEngine.cpp b/libs/renderengine/skia/SkiaVkRenderEngine.cpp
index ba20d1f223..f2f1b5d0ca 100644
--- a/libs/renderengine/skia/SkiaVkRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaVkRenderEngine.cpp
@@ -25,6 +25,7 @@
#include <GrContextOptions.h>
#include <vk/GrVkExtensions.h>
#include <vk/GrVkTypes.h>
+#include <include/gpu/ganesh/vk/GrVkBackendSemaphore.h>
#include <include/gpu/ganesh/vk/GrVkDirectContext.h>
#include <android-base/stringprintf.h>
@@ -32,9 +33,8 @@
#include <sync/sync.h>
#include <utils/Trace.h>
-#include <cstdint>
#include <memory>
-#include <vector>
+#include <string>
#include <vulkan/vulkan.h>
#include "log/log_main.h"
@@ -42,549 +42,49 @@
namespace android {
namespace renderengine {
-struct VulkanFuncs {
- PFN_vkCreateSemaphore vkCreateSemaphore = nullptr;
- PFN_vkImportSemaphoreFdKHR vkImportSemaphoreFdKHR = nullptr;
- PFN_vkGetSemaphoreFdKHR vkGetSemaphoreFdKHR = nullptr;
- PFN_vkDestroySemaphore vkDestroySemaphore = nullptr;
-
- PFN_vkDeviceWaitIdle vkDeviceWaitIdle = nullptr;
- PFN_vkDestroyDevice vkDestroyDevice = nullptr;
- PFN_vkDestroyInstance vkDestroyInstance = nullptr;
-};
-
-// Ref-Count a semaphore
-struct DestroySemaphoreInfo {
- VkSemaphore mSemaphore;
- // We need to make sure we don't delete the VkSemaphore until it is done being used by both Skia
- // (including by the GPU) and inside SkiaVkRenderEngine. So we always start with two refs, one
- // owned by Skia and one owned by the SkiaVkRenderEngine. The refs are decremented each time
- // delete_semaphore* is called with this object. Skia will call destroy_semaphore* once it is
- // done with the semaphore and the GPU has finished work on the semaphore. SkiaVkRenderEngine
- // calls delete_semaphore* after sending the semaphore to Skia and exporting it if need be.
- int mRefs = 2;
-
- DestroySemaphoreInfo(VkSemaphore semaphore) : mSemaphore(semaphore) {}
-};
-
-struct VulkanInterface {
- bool initialized = false;
- VkInstance instance;
- VkPhysicalDevice physicalDevice;
- VkDevice device;
- VkQueue queue;
- int queueIndex;
- uint32_t apiVersion;
- GrVkExtensions grExtensions;
- VkPhysicalDeviceFeatures2* physicalDeviceFeatures2 = nullptr;
- VkPhysicalDeviceSamplerYcbcrConversionFeatures* samplerYcbcrConversionFeatures = nullptr;
- VkPhysicalDeviceProtectedMemoryFeatures* protectedMemoryFeatures = nullptr;
- GrVkGetProc grGetProc;
- bool isProtected;
- bool isRealtimePriority;
-
- VulkanFuncs funcs;
-
- std::vector<std::string> instanceExtensionNames;
- std::vector<std::string> deviceExtensionNames;
-
- GrVkBackendContext getBackendContext() {
- GrVkBackendContext backendContext;
- backendContext.fInstance = instance;
- backendContext.fPhysicalDevice = physicalDevice;
- backendContext.fDevice = device;
- backendContext.fQueue = queue;
- backendContext.fGraphicsQueueIndex = queueIndex;
- backendContext.fMaxAPIVersion = apiVersion;
- backendContext.fVkExtensions = &grExtensions;
- backendContext.fDeviceFeatures2 = physicalDeviceFeatures2;
- backendContext.fGetProc = grGetProc;
- backendContext.fProtectedContext = isProtected ? GrProtected::kYes : GrProtected::kNo;
- return backendContext;
- };
-
- VkSemaphore createExportableSemaphore() {
- VkExportSemaphoreCreateInfo exportInfo;
- exportInfo.sType = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO;
- exportInfo.pNext = nullptr;
- exportInfo.handleTypes = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
-
- VkSemaphoreCreateInfo semaphoreInfo;
- semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
- semaphoreInfo.pNext = &exportInfo;
- semaphoreInfo.flags = 0;
-
- VkSemaphore semaphore;
- VkResult err = funcs.vkCreateSemaphore(device, &semaphoreInfo, nullptr, &semaphore);
- if (VK_SUCCESS != err) {
- ALOGE("%s: failed to create semaphore. err %d\n", __func__, err);
- return VK_NULL_HANDLE;
- }
-
- return semaphore;
- }
-
- // syncFd cannot be <= 0
- VkSemaphore importSemaphoreFromSyncFd(int syncFd) {
- VkSemaphoreCreateInfo semaphoreInfo;
- semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
- semaphoreInfo.pNext = nullptr;
- semaphoreInfo.flags = 0;
-
- VkSemaphore semaphore;
- VkResult err = funcs.vkCreateSemaphore(device, &semaphoreInfo, nullptr, &semaphore);
- if (VK_SUCCESS != err) {
- ALOGE("%s: failed to create import semaphore", __func__);
- return VK_NULL_HANDLE;
- }
-
- VkImportSemaphoreFdInfoKHR importInfo;
- importInfo.sType = VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHR;
- importInfo.pNext = nullptr;
- importInfo.semaphore = semaphore;
- importInfo.flags = VK_SEMAPHORE_IMPORT_TEMPORARY_BIT;
- importInfo.handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
- importInfo.fd = syncFd;
-
- err = funcs.vkImportSemaphoreFdKHR(device, &importInfo);
- if (VK_SUCCESS != err) {
- funcs.vkDestroySemaphore(device, semaphore, nullptr);
- ALOGE("%s: failed to import semaphore", __func__);
- return VK_NULL_HANDLE;
- }
-
- return semaphore;
- }
-
- int exportSemaphoreSyncFd(VkSemaphore semaphore) {
- int res;
-
- VkSemaphoreGetFdInfoKHR getFdInfo;
- getFdInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR;
- getFdInfo.pNext = nullptr;
- getFdInfo.semaphore = semaphore;
- getFdInfo.handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
-
- VkResult err = funcs.vkGetSemaphoreFdKHR(device, &getFdInfo, &res);
- if (VK_SUCCESS != err) {
- ALOGE("%s: failed to export semaphore, err: %d", __func__, err);
- return -1;
- }
- return res;
- }
-
- void destroySemaphore(VkSemaphore semaphore) {
- funcs.vkDestroySemaphore(device, semaphore, nullptr);
- }
-};
-
-static GrVkGetProc sGetProc = [](const char* proc_name, VkInstance instance, VkDevice device) {
- if (device != VK_NULL_HANDLE) {
- return vkGetDeviceProcAddr(device, proc_name);
- }
- return vkGetInstanceProcAddr(instance, proc_name);
-};
-
-#define BAIL(fmt, ...) \
- { \
- ALOGE("%s: " fmt ", bailing", __func__, ##__VA_ARGS__); \
- return interface; \
- }
-
-#define CHECK_NONNULL(expr) \
- if ((expr) == nullptr) { \
- BAIL("[%s] null", #expr); \
- }
-
-#define VK_CHECK(expr) \
- if ((expr) != VK_SUCCESS) { \
- BAIL("[%s] failed. err = %d", #expr, expr); \
- return interface; \
- }
-
-#define VK_GET_PROC(F) \
- PFN_vk##F vk##F = (PFN_vk##F)vkGetInstanceProcAddr(VK_NULL_HANDLE, "vk" #F); \
- CHECK_NONNULL(vk##F)
-#define VK_GET_INST_PROC(instance, F) \
- PFN_vk##F vk##F = (PFN_vk##F)vkGetInstanceProcAddr(instance, "vk" #F); \
- CHECK_NONNULL(vk##F)
-#define VK_GET_DEV_PROC(device, F) \
- PFN_vk##F vk##F = (PFN_vk##F)vkGetDeviceProcAddr(device, "vk" #F); \
- CHECK_NONNULL(vk##F)
-
-VulkanInterface initVulkanInterface(bool protectedContent = false) {
- VulkanInterface interface;
-
- VK_GET_PROC(EnumerateInstanceVersion);
- uint32_t instanceVersion;
- VK_CHECK(vkEnumerateInstanceVersion(&instanceVersion));
-
- if (instanceVersion < VK_MAKE_VERSION(1, 1, 0)) {
- return interface;
- }
-
- const VkApplicationInfo appInfo = {
- VK_STRUCTURE_TYPE_APPLICATION_INFO, nullptr, "surfaceflinger", 0, "android platform", 0,
- VK_MAKE_VERSION(1, 1, 0),
- };
-
- VK_GET_PROC(EnumerateInstanceExtensionProperties);
-
- uint32_t extensionCount = 0;
- VK_CHECK(vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr));
- std::vector<VkExtensionProperties> instanceExtensions(extensionCount);
- VK_CHECK(vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount,
- instanceExtensions.data()));
- std::vector<const char*> enabledInstanceExtensionNames;
- enabledInstanceExtensionNames.reserve(instanceExtensions.size());
- interface.instanceExtensionNames.reserve(instanceExtensions.size());
- for (const auto& instExt : instanceExtensions) {
- enabledInstanceExtensionNames.push_back(instExt.extensionName);
- interface.instanceExtensionNames.push_back(instExt.extensionName);
- }
-
- const VkInstanceCreateInfo instanceCreateInfo = {
- VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
- nullptr,
- 0,
- &appInfo,
- 0,
- nullptr,
- (uint32_t)enabledInstanceExtensionNames.size(),
- enabledInstanceExtensionNames.data(),
- };
-
- VK_GET_PROC(CreateInstance);
- VkInstance instance;
- VK_CHECK(vkCreateInstance(&instanceCreateInfo, nullptr, &instance));
-
- VK_GET_INST_PROC(instance, DestroyInstance);
- interface.funcs.vkDestroyInstance = vkDestroyInstance;
- VK_GET_INST_PROC(instance, EnumeratePhysicalDevices);
- VK_GET_INST_PROC(instance, EnumerateDeviceExtensionProperties);
- VK_GET_INST_PROC(instance, GetPhysicalDeviceProperties2);
- VK_GET_INST_PROC(instance, GetPhysicalDeviceExternalSemaphoreProperties);
- VK_GET_INST_PROC(instance, GetPhysicalDeviceQueueFamilyProperties2);
- VK_GET_INST_PROC(instance, GetPhysicalDeviceFeatures2);
- VK_GET_INST_PROC(instance, CreateDevice);
-
- uint32_t physdevCount;
- VK_CHECK(vkEnumeratePhysicalDevices(instance, &physdevCount, nullptr));
- if (physdevCount == 0) {
- BAIL("Could not find any physical devices");
- }
-
- physdevCount = 1;
- VkPhysicalDevice physicalDevice;
- VkResult enumeratePhysDevsErr =
- vkEnumeratePhysicalDevices(instance, &physdevCount, &physicalDevice);
- if (enumeratePhysDevsErr != VK_SUCCESS && VK_INCOMPLETE != enumeratePhysDevsErr) {
- BAIL("vkEnumeratePhysicalDevices failed with non-VK_INCOMPLETE error: %d",
- enumeratePhysDevsErr);
- }
-
- VkPhysicalDeviceProperties2 physDevProps = {
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2,
- 0,
- {},
- };
- VkPhysicalDeviceProtectedMemoryProperties protMemProps = {
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_PROPERTIES,
- 0,
- {},
- };
-
- if (protectedContent) {
- physDevProps.pNext = &protMemProps;
- }
-
- vkGetPhysicalDeviceProperties2(physicalDevice, &physDevProps);
- if (physDevProps.properties.apiVersion < VK_MAKE_VERSION(1, 1, 0)) {
- BAIL("Could not find a Vulkan 1.1+ physical device");
- }
-
- // Check for syncfd support. Bail if we cannot both import and export them.
- VkPhysicalDeviceExternalSemaphoreInfo semInfo = {
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO,
- nullptr,
- VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT,
- };
- VkExternalSemaphoreProperties semProps = {
- VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES, nullptr, 0, 0, 0,
- };
- vkGetPhysicalDeviceExternalSemaphoreProperties(physicalDevice, &semInfo, &semProps);
-
- bool sufficientSemaphoreSyncFdSupport = (semProps.exportFromImportedHandleTypes &
- VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT) &&
- (semProps.compatibleHandleTypes & VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT) &&
- (semProps.externalSemaphoreFeatures & VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT) &&
- (semProps.externalSemaphoreFeatures & VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT);
-
- if (!sufficientSemaphoreSyncFdSupport) {
- BAIL("Vulkan device does not support sufficient external semaphore sync fd features. "
- "exportFromImportedHandleTypes 0x%x (needed 0x%x) "
- "compatibleHandleTypes 0x%x (needed 0x%x) "
- "externalSemaphoreFeatures 0x%x (needed 0x%x) ",
- semProps.exportFromImportedHandleTypes, VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT,
- semProps.compatibleHandleTypes, VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT,
- semProps.externalSemaphoreFeatures,
- VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT |
- VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT);
- } else {
- ALOGD("Vulkan device supports sufficient external semaphore sync fd features. "
- "exportFromImportedHandleTypes 0x%x (needed 0x%x) "
- "compatibleHandleTypes 0x%x (needed 0x%x) "
- "externalSemaphoreFeatures 0x%x (needed 0x%x) ",
- semProps.exportFromImportedHandleTypes, VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT,
- semProps.compatibleHandleTypes, VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT,
- semProps.externalSemaphoreFeatures,
- VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT |
- VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT);
- }
-
- uint32_t queueCount;
- vkGetPhysicalDeviceQueueFamilyProperties2(physicalDevice, &queueCount, nullptr);
- if (queueCount == 0) {
- BAIL("Could not find queues for physical device");
- }
-
- std::vector<VkQueueFamilyProperties2> queueProps(queueCount);
- std::vector<VkQueueFamilyGlobalPriorityPropertiesEXT> queuePriorityProps(queueCount);
- VkQueueGlobalPriorityKHR queuePriority = VK_QUEUE_GLOBAL_PRIORITY_MEDIUM_KHR;
- // Even though we don't yet know if the VK_EXT_global_priority extension is available,
- // we can safely add the request to the pNext chain, and if the extension is not
- // available, it will be ignored.
- for (uint32_t i = 0; i < queueCount; ++i) {
- queuePriorityProps[i].sType = VK_STRUCTURE_TYPE_QUEUE_FAMILY_GLOBAL_PRIORITY_PROPERTIES_EXT;
- queuePriorityProps[i].pNext = nullptr;
- queueProps[i].pNext = &queuePriorityProps[i];
- }
- vkGetPhysicalDeviceQueueFamilyProperties2(physicalDevice, &queueCount, queueProps.data());
-
- int graphicsQueueIndex = -1;
- for (uint32_t i = 0; i < queueCount; ++i) {
- // Look at potential answers to the VK_EXT_global_priority query. If answers were
- // provided, we may adjust the queuePriority.
- if (queueProps[i].queueFamilyProperties.queueFlags & VK_QUEUE_GRAPHICS_BIT) {
- for (uint32_t j = 0; j < queuePriorityProps[i].priorityCount; j++) {
- if (queuePriorityProps[i].priorities[j] > queuePriority) {
- queuePriority = queuePriorityProps[i].priorities[j];
- }
- }
- if (queuePriority == VK_QUEUE_GLOBAL_PRIORITY_REALTIME_KHR) {
- interface.isRealtimePriority = true;
- }
- graphicsQueueIndex = i;
- break;
- }
- }
-
- if (graphicsQueueIndex == -1) {
- BAIL("Could not find a graphics queue family");
- }
-
- uint32_t deviceExtensionCount;
- VK_CHECK(vkEnumerateDeviceExtensionProperties(physicalDevice, nullptr, &deviceExtensionCount,
- nullptr));
- std::vector<VkExtensionProperties> deviceExtensions(deviceExtensionCount);
- VK_CHECK(vkEnumerateDeviceExtensionProperties(physicalDevice, nullptr, &deviceExtensionCount,
- deviceExtensions.data()));
-
- std::vector<const char*> enabledDeviceExtensionNames;
- enabledDeviceExtensionNames.reserve(deviceExtensions.size());
- interface.deviceExtensionNames.reserve(deviceExtensions.size());
- for (const auto& devExt : deviceExtensions) {
- enabledDeviceExtensionNames.push_back(devExt.extensionName);
- interface.deviceExtensionNames.push_back(devExt.extensionName);
- }
-
- interface.grExtensions.init(sGetProc, instance, physicalDevice,
- enabledInstanceExtensionNames.size(),
- enabledInstanceExtensionNames.data(),
- enabledDeviceExtensionNames.size(),
- enabledDeviceExtensionNames.data());
-
- if (!interface.grExtensions.hasExtension(VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME, 1)) {
- BAIL("Vulkan driver doesn't support external semaphore fd");
- }
-
- interface.physicalDeviceFeatures2 = new VkPhysicalDeviceFeatures2;
- interface.physicalDeviceFeatures2->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
- interface.physicalDeviceFeatures2->pNext = nullptr;
-
- interface.samplerYcbcrConversionFeatures = new VkPhysicalDeviceSamplerYcbcrConversionFeatures;
- interface.samplerYcbcrConversionFeatures->sType =
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES;
- interface.samplerYcbcrConversionFeatures->pNext = nullptr;
-
- interface.physicalDeviceFeatures2->pNext = interface.samplerYcbcrConversionFeatures;
- void** tailPnext = &interface.samplerYcbcrConversionFeatures->pNext;
-
- if (protectedContent) {
- interface.protectedMemoryFeatures = new VkPhysicalDeviceProtectedMemoryFeatures;
- interface.protectedMemoryFeatures->sType =
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES;
- interface.protectedMemoryFeatures->pNext = nullptr;
- *tailPnext = interface.protectedMemoryFeatures;
- tailPnext = &interface.protectedMemoryFeatures->pNext;
- }
-
- vkGetPhysicalDeviceFeatures2(physicalDevice, interface.physicalDeviceFeatures2);
- // Looks like this would slow things down and we can't depend on it on all platforms
- interface.physicalDeviceFeatures2->features.robustBufferAccess = VK_FALSE;
-
- if (protectedContent && !interface.protectedMemoryFeatures->protectedMemory) {
- BAIL("Protected memory not supported");
- }
-
- float queuePriorities[1] = {0.0f};
- void* queueNextPtr = nullptr;
-
- VkDeviceQueueGlobalPriorityCreateInfoEXT queuePriorityCreateInfo = {
- VK_STRUCTURE_TYPE_DEVICE_QUEUE_GLOBAL_PRIORITY_CREATE_INFO_EXT,
- nullptr,
- // If queue priority is supported, RE should always have realtime priority.
- queuePriority,
- };
-
- if (interface.grExtensions.hasExtension(VK_EXT_GLOBAL_PRIORITY_EXTENSION_NAME, 2)) {
- queueNextPtr = &queuePriorityCreateInfo;
- }
-
- VkDeviceQueueCreateFlags deviceQueueCreateFlags =
- (VkDeviceQueueCreateFlags)(protectedContent ? VK_DEVICE_QUEUE_CREATE_PROTECTED_BIT : 0);
-
- const VkDeviceQueueCreateInfo queueInfo = {
- VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
- queueNextPtr,
- deviceQueueCreateFlags,
- (uint32_t)graphicsQueueIndex,
- 1,
- queuePriorities,
- };
-
- const VkDeviceCreateInfo deviceInfo = {
- VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
- interface.physicalDeviceFeatures2,
- 0,
- 1,
- &queueInfo,
- 0,
- nullptr,
- (uint32_t)enabledDeviceExtensionNames.size(),
- enabledDeviceExtensionNames.data(),
- nullptr,
- };
-
- ALOGD("Trying to create Vk device with protectedContent=%d", protectedContent);
- VkDevice device;
- VK_CHECK(vkCreateDevice(physicalDevice, &deviceInfo, nullptr, &device));
- ALOGD("Trying to create Vk device with protectedContent=%d (success)", protectedContent);
-
- VkQueue graphicsQueue;
- VK_GET_DEV_PROC(device, GetDeviceQueue2);
- const VkDeviceQueueInfo2 deviceQueueInfo2 = {VK_STRUCTURE_TYPE_DEVICE_QUEUE_INFO_2, nullptr,
- deviceQueueCreateFlags,
- (uint32_t)graphicsQueueIndex, 0};
- vkGetDeviceQueue2(device, &deviceQueueInfo2, &graphicsQueue);
-
- VK_GET_DEV_PROC(device, DeviceWaitIdle);
- VK_GET_DEV_PROC(device, DestroyDevice);
- interface.funcs.vkDeviceWaitIdle = vkDeviceWaitIdle;
- interface.funcs.vkDestroyDevice = vkDestroyDevice;
-
- VK_GET_DEV_PROC(device, CreateSemaphore);
- VK_GET_DEV_PROC(device, ImportSemaphoreFdKHR);
- VK_GET_DEV_PROC(device, GetSemaphoreFdKHR);
- VK_GET_DEV_PROC(device, DestroySemaphore);
- interface.funcs.vkCreateSemaphore = vkCreateSemaphore;
- interface.funcs.vkImportSemaphoreFdKHR = vkImportSemaphoreFdKHR;
- interface.funcs.vkGetSemaphoreFdKHR = vkGetSemaphoreFdKHR;
- interface.funcs.vkDestroySemaphore = vkDestroySemaphore;
-
- // At this point, everything's succeeded and we can continue
- interface.initialized = true;
- interface.instance = instance;
- interface.physicalDevice = physicalDevice;
- interface.device = device;
- interface.queue = graphicsQueue;
- interface.queueIndex = graphicsQueueIndex;
- interface.apiVersion = physDevProps.properties.apiVersion;
- // grExtensions already constructed
- // feature pointers already constructed
- interface.grGetProc = sGetProc;
- interface.isProtected = protectedContent;
- // funcs already initialized
-
- ALOGD("%s: Success init Vulkan interface", __func__);
- return interface;
-}
-
-void teardownVulkanInterface(VulkanInterface* interface) {
- interface->initialized = false;
-
- if (interface->device != VK_NULL_HANDLE) {
- interface->funcs.vkDeviceWaitIdle(interface->device);
- interface->funcs.vkDestroyDevice(interface->device, nullptr);
- interface->device = VK_NULL_HANDLE;
- }
- if (interface->instance != VK_NULL_HANDLE) {
- interface->funcs.vkDestroyInstance(interface->instance, nullptr);
- interface->instance = VK_NULL_HANDLE;
- }
-
- if (interface->protectedMemoryFeatures) {
- delete interface->protectedMemoryFeatures;
- }
-
- if (interface->samplerYcbcrConversionFeatures) {
- delete interface->samplerYcbcrConversionFeatures;
- }
-
- if (interface->physicalDeviceFeatures2) {
- delete interface->physicalDeviceFeatures2;
- }
-
- interface->samplerYcbcrConversionFeatures = nullptr;
- interface->physicalDeviceFeatures2 = nullptr;
- interface->protectedMemoryFeatures = nullptr;
-}
-
-static VulkanInterface sVulkanInterface;
-static VulkanInterface sProtectedContentVulkanInterface;
+static skia::VulkanInterface sVulkanInterface;
+static skia::VulkanInterface sProtectedContentVulkanInterface;
static void sSetupVulkanInterface() {
- if (!sVulkanInterface.initialized) {
- sVulkanInterface = initVulkanInterface(false /* no protected content */);
+ if (!sVulkanInterface.isInitialized()) {
+ sVulkanInterface.init(false /* no protected content */);
// We will have to abort if non-protected VkDevice creation fails (then nothing works).
- LOG_ALWAYS_FATAL_IF(!sVulkanInterface.initialized,
+ LOG_ALWAYS_FATAL_IF(!sVulkanInterface.isInitialized(),
"Could not initialize Vulkan RenderEngine!");
}
- if (!sProtectedContentVulkanInterface.initialized) {
- sProtectedContentVulkanInterface = initVulkanInterface(true /* protected content */);
- if (!sProtectedContentVulkanInterface.initialized) {
+ if (!sProtectedContentVulkanInterface.isInitialized()) {
+ sProtectedContentVulkanInterface.init(true /* protected content */);
+ if (!sProtectedContentVulkanInterface.isInitialized()) {
ALOGE("Could not initialize protected content Vulkan RenderEngine.");
}
}
}
+bool RenderEngine::canSupport(GraphicsApi graphicsApi) {
+ switch (graphicsApi) {
+ case GraphicsApi::GL:
+ return true;
+ case GraphicsApi::VK: {
+ if (!sVulkanInterface.isInitialized()) {
+ sVulkanInterface.init(false /* no protected content */);
+ ALOGD("%s: initialized == %s.", __func__,
+ sVulkanInterface.isInitialized() ? "true" : "false");
+ }
+ return sVulkanInterface.isInitialized();
+ }
+ }
+}
+
namespace skia {
using base::StringAppendF;
-bool SkiaVkRenderEngine::canSupportSkiaVkRenderEngine() {
- VulkanInterface temp = initVulkanInterface(false /* no protected content */);
- ALOGD("SkiaVkRenderEngine::canSupportSkiaVkRenderEngine(): initialized == %s.",
- temp.initialized ? "true" : "false");
- return temp.initialized;
-}
-
std::unique_ptr<SkiaVkRenderEngine> SkiaVkRenderEngine::create(
const RenderEngineCreationArgs& args) {
std::unique_ptr<SkiaVkRenderEngine> engine(new SkiaVkRenderEngine(args));
engine->ensureGrContextsCreated();
- if (sVulkanInterface.initialized) {
+ if (sVulkanInterface.isInitialized()) {
ALOGD("SkiaVkRenderEngine::%s: successfully initialized SkiaVkRenderEngine", __func__);
return engine;
} else {
@@ -596,7 +96,7 @@ std::unique_ptr<SkiaVkRenderEngine> SkiaVkRenderEngine::create(
}
SkiaVkRenderEngine::SkiaVkRenderEngine(const RenderEngineCreationArgs& args)
- : SkiaRenderEngine(args.renderEngineType, static_cast<PixelFormat>(args.pixelFormat),
+ : SkiaRenderEngine(args.threaded, static_cast<PixelFormat>(args.pixelFormat),
args.supportsBackgroundBlur) {}
SkiaVkRenderEngine::~SkiaVkRenderEngine() {
@@ -619,29 +119,17 @@ SkiaRenderEngine::Contexts SkiaVkRenderEngine::createDirectContexts(
}
bool SkiaVkRenderEngine::supportsProtectedContentImpl() const {
- return sProtectedContentVulkanInterface.initialized;
+ return sProtectedContentVulkanInterface.isInitialized();
}
bool SkiaVkRenderEngine::useProtectedContextImpl(GrProtected) {
return true;
}
-static void delete_semaphore(void* semaphore) {
- DestroySemaphoreInfo* info = reinterpret_cast<DestroySemaphoreInfo*>(semaphore);
- --info->mRefs;
- if (!info->mRefs) {
- sVulkanInterface.destroySemaphore(info->mSemaphore);
- delete info;
- }
-}
-
-static void delete_semaphore_protected(void* semaphore) {
- DestroySemaphoreInfo* info = reinterpret_cast<DestroySemaphoreInfo*>(semaphore);
- --info->mRefs;
- if (!info->mRefs) {
- sProtectedContentVulkanInterface.destroySemaphore(info->mSemaphore);
- delete info;
- }
+static void unref_semaphore(void* semaphore) {
+ SkiaVkRenderEngine::DestroySemaphoreInfo* info =
+ reinterpret_cast<SkiaVkRenderEngine::DestroySemaphoreInfo*>(semaphore);
+ info->unref();
}
static VulkanInterface& getVulkanInterface(bool protectedContext) {
@@ -664,8 +152,7 @@ void SkiaVkRenderEngine::waitFence(GrDirectContext* grContext, base::borrowed_fd
base::unique_fd fenceDup(dupedFd);
VkSemaphore waitSemaphore =
getVulkanInterface(isProtected()).importSemaphoreFromSyncFd(fenceDup.release());
- GrBackendSemaphore beSemaphore;
- beSemaphore.initVulkan(waitSemaphore);
+ GrBackendSemaphore beSemaphore = GrBackendSemaphores::MakeVk(waitSemaphore);
grContext->wait(1, &beSemaphore, true /* delete after wait */);
}
@@ -673,16 +160,15 @@ base::unique_fd SkiaVkRenderEngine::flushAndSubmit(GrDirectContext* grContext) {
VulkanInterface& vi = getVulkanInterface(isProtected());
VkSemaphore semaphore = vi.createExportableSemaphore();
- GrBackendSemaphore backendSemaphore;
- backendSemaphore.initVulkan(semaphore);
+ GrBackendSemaphore backendSemaphore = GrBackendSemaphores::MakeVk(semaphore);
GrFlushInfo flushInfo;
DestroySemaphoreInfo* destroySemaphoreInfo = nullptr;
if (semaphore != VK_NULL_HANDLE) {
- destroySemaphoreInfo = new DestroySemaphoreInfo(semaphore);
+ destroySemaphoreInfo = new DestroySemaphoreInfo(vi, semaphore);
flushInfo.fNumSemaphores = 1;
flushInfo.fSignalSemaphores = &backendSemaphore;
- flushInfo.fFinishedProc = isProtected() ? delete_semaphore_protected : delete_semaphore;
+ flushInfo.fFinishedProc = unref_semaphore;
flushInfo.fFinishedContext = destroySemaphoreInfo;
}
GrSemaphoresSubmitted submitted = grContext->flush(flushInfo);
@@ -702,7 +188,7 @@ base::unique_fd SkiaVkRenderEngine::flushAndSubmit(GrDirectContext* grContext) {
int SkiaVkRenderEngine::getContextPriority() {
// EGL_CONTEXT_PRIORITY_REALTIME_NV
constexpr int kRealtimePriority = 0x3357;
- if (getVulkanInterface(isProtected()).isRealtimePriority) {
+ if (getVulkanInterface(isProtected()).isRealtimePriority()) {
return kRealtimePriority;
} else {
return 0;
@@ -711,21 +197,21 @@ int SkiaVkRenderEngine::getContextPriority() {
void SkiaVkRenderEngine::appendBackendSpecificInfoToDump(std::string& result) {
StringAppendF(&result, "\n ------------RE Vulkan----------\n");
- StringAppendF(&result, "\n Vulkan device initialized: %d\n", sVulkanInterface.initialized);
+ StringAppendF(&result, "\n Vulkan device initialized: %d\n", sVulkanInterface.isInitialized());
StringAppendF(&result, "\n Vulkan protected device initialized: %d\n",
- sProtectedContentVulkanInterface.initialized);
+ sProtectedContentVulkanInterface.isInitialized());
- if (!sVulkanInterface.initialized) {
+ if (!sVulkanInterface.isInitialized()) {
return;
}
StringAppendF(&result, "\n Instance extensions:\n");
- for (const auto& name : sVulkanInterface.instanceExtensionNames) {
+ for (const auto& name : sVulkanInterface.getInstanceExtensionNames()) {
StringAppendF(&result, "\n %s\n", name.c_str());
}
StringAppendF(&result, "\n Device extensions:\n");
- for (const auto& name : sVulkanInterface.deviceExtensionNames) {
+ for (const auto& name : sVulkanInterface.getDeviceExtensionNames()) {
StringAppendF(&result, "\n %s\n", name.c_str());
}
}
diff --git a/libs/renderengine/skia/SkiaVkRenderEngine.h b/libs/renderengine/skia/SkiaVkRenderEngine.h
index 2e0cf45220..ca0dcbf4ae 100644
--- a/libs/renderengine/skia/SkiaVkRenderEngine.h
+++ b/libs/renderengine/skia/SkiaVkRenderEngine.h
@@ -20,6 +20,7 @@
#include <vk/GrVkBackendContext.h>
#include "SkiaRenderEngine.h"
+#include "VulkanInterface.h"
namespace android {
namespace renderengine {
@@ -27,13 +28,47 @@ namespace skia {
class SkiaVkRenderEngine : public SkiaRenderEngine {
public:
- // Returns false if Vulkan implementation can't support SkiaVkRenderEngine.
- static bool canSupportSkiaVkRenderEngine();
static std::unique_ptr<SkiaVkRenderEngine> create(const RenderEngineCreationArgs& args);
~SkiaVkRenderEngine() override;
int getContextPriority() override;
+ class DestroySemaphoreInfo {
+ public:
+ DestroySemaphoreInfo() = delete;
+ DestroySemaphoreInfo(const DestroySemaphoreInfo&) = delete;
+ DestroySemaphoreInfo& operator=(const DestroySemaphoreInfo&) = delete;
+ DestroySemaphoreInfo& operator=(DestroySemaphoreInfo&&) = delete;
+
+ DestroySemaphoreInfo(VulkanInterface& vulkanInterface, std::vector<VkSemaphore> semaphores)
+ : mVulkanInterface(vulkanInterface), mSemaphores(std::move(semaphores)) {}
+ DestroySemaphoreInfo(VulkanInterface& vulkanInterface, VkSemaphore semaphore)
+ : DestroySemaphoreInfo(vulkanInterface, std::vector<VkSemaphore>(1, semaphore)) {}
+
+ void unref() {
+ --mRefs;
+ if (!mRefs) {
+ for (VkSemaphore semaphore : mSemaphores) {
+ mVulkanInterface.destroySemaphore(semaphore);
+ }
+ delete this;
+ }
+ }
+
+ private:
+ ~DestroySemaphoreInfo() = default;
+
+ VulkanInterface& mVulkanInterface;
+ std::vector<VkSemaphore> mSemaphores;
+ // We need to make sure we don't delete the VkSemaphore until it is done being used by both
+ // Skia (including by the GPU) and inside SkiaVkRenderEngine. So we always start with two
+ // refs, one owned by Skia and one owned by the SkiaVkRenderEngine. The refs are decremented
+ // each time unref() is called on this object. Skia will call unref() once it is done with
+ // the semaphore and the GPU has finished work on the semaphore. SkiaVkRenderEngine calls
+ // unref() after sending the semaphore to Skia and exporting it if need be.
+ int mRefs = 2;
+ };
+
protected:
// Implementations of abstract SkiaRenderEngine functions specific to
// rendering backend
diff --git a/libs/renderengine/skia/VulkanInterface.cpp b/libs/renderengine/skia/VulkanInterface.cpp
new file mode 100644
index 0000000000..453cdc1196
--- /dev/null
+++ b/libs/renderengine/skia/VulkanInterface.cpp
@@ -0,0 +1,582 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "RenderEngine"
+
+#include "VulkanInterface.h"
+
+#include <include/gpu/GpuTypes.h>
+#include <log/log_main.h>
+#include <utils/Timers.h>
+
+#include <cinttypes>
+#include <sstream>
+
+namespace android {
+namespace renderengine {
+namespace skia {
+
+GrVkBackendContext VulkanInterface::getBackendContext() {
+ GrVkBackendContext backendContext;
+ backendContext.fInstance = mInstance;
+ backendContext.fPhysicalDevice = mPhysicalDevice;
+ backendContext.fDevice = mDevice;
+ backendContext.fQueue = mQueue;
+ backendContext.fGraphicsQueueIndex = mQueueIndex;
+ backendContext.fMaxAPIVersion = mApiVersion;
+ backendContext.fVkExtensions = &mGrExtensions;
+ backendContext.fDeviceFeatures2 = mPhysicalDeviceFeatures2;
+ backendContext.fGetProc = mGrGetProc;
+ backendContext.fProtectedContext = mIsProtected ? Protected::kYes : Protected::kNo;
+ backendContext.fDeviceLostContext = this; // VulkanInterface is long-lived
+ backendContext.fDeviceLostProc = onVkDeviceFault;
+ return backendContext;
+};
+
+VkSemaphore VulkanInterface::createExportableSemaphore() {
+ VkExportSemaphoreCreateInfo exportInfo;
+ exportInfo.sType = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO;
+ exportInfo.pNext = nullptr;
+ exportInfo.handleTypes = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
+
+ VkSemaphoreCreateInfo semaphoreInfo;
+ semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
+ semaphoreInfo.pNext = &exportInfo;
+ semaphoreInfo.flags = 0;
+
+ VkSemaphore semaphore;
+ VkResult err = mFuncs.vkCreateSemaphore(mDevice, &semaphoreInfo, nullptr, &semaphore);
+ if (VK_SUCCESS != err) {
+ ALOGE("%s: failed to create semaphore. err %d\n", __func__, err);
+ return VK_NULL_HANDLE;
+ }
+
+ return semaphore;
+}
+
+// syncFd cannot be <= 0
+VkSemaphore VulkanInterface::importSemaphoreFromSyncFd(int syncFd) {
+ VkSemaphoreCreateInfo semaphoreInfo;
+ semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
+ semaphoreInfo.pNext = nullptr;
+ semaphoreInfo.flags = 0;
+
+ VkSemaphore semaphore;
+ VkResult err = mFuncs.vkCreateSemaphore(mDevice, &semaphoreInfo, nullptr, &semaphore);
+ if (VK_SUCCESS != err) {
+ ALOGE("%s: failed to create import semaphore", __func__);
+ return VK_NULL_HANDLE;
+ }
+
+ VkImportSemaphoreFdInfoKHR importInfo;
+ importInfo.sType = VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHR;
+ importInfo.pNext = nullptr;
+ importInfo.semaphore = semaphore;
+ importInfo.flags = VK_SEMAPHORE_IMPORT_TEMPORARY_BIT;
+ importInfo.handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
+ importInfo.fd = syncFd;
+
+ err = mFuncs.vkImportSemaphoreFdKHR(mDevice, &importInfo);
+ if (VK_SUCCESS != err) {
+ mFuncs.vkDestroySemaphore(mDevice, semaphore, nullptr);
+ ALOGE("%s: failed to import semaphore", __func__);
+ return VK_NULL_HANDLE;
+ }
+
+ return semaphore;
+}
+
+int VulkanInterface::exportSemaphoreSyncFd(VkSemaphore semaphore) {
+ int res;
+
+ VkSemaphoreGetFdInfoKHR getFdInfo;
+ getFdInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR;
+ getFdInfo.pNext = nullptr;
+ getFdInfo.semaphore = semaphore;
+ getFdInfo.handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
+ VkResult err = mFuncs.vkGetSemaphoreFdKHR(mDevice, &getFdInfo, &res);
+ if (VK_SUCCESS != err) {
+ ALOGE("%s: failed to export semaphore, err: %d", __func__, err);
+ return -1;
+ }
+ return res;
+}
+
+void VulkanInterface::destroySemaphore(VkSemaphore semaphore) {
+ mFuncs.vkDestroySemaphore(mDevice, semaphore, nullptr);
+}
+
+void VulkanInterface::onVkDeviceFault(void* callbackContext, const std::string& description,
+ const std::vector<VkDeviceFaultAddressInfoEXT>& addressInfos,
+ const std::vector<VkDeviceFaultVendorInfoEXT>& vendorInfos,
+ const std::vector<std::byte>& vendorBinaryData) {
+ VulkanInterface* interface = static_cast<VulkanInterface*>(callbackContext);
+ const std::string protectedStr = interface->mIsProtected ? "protected" : "non-protected";
+ // The final crash string should contain as much differentiating info as possible, up to 1024
+ // bytes. As this final message is constructed, the same information is also dumped to the logs
+ // but in a more verbose format. Building the crash string is unsightly, so the clearer logging
+ // statement is always placed first to give context.
+ ALOGE("VK_ERROR_DEVICE_LOST (%s context): %s", protectedStr.c_str(), description.c_str());
+ std::stringstream crashMsg;
+ crashMsg << "VK_ERROR_DEVICE_LOST (" << protectedStr;
+
+ if (!addressInfos.empty()) {
+ ALOGE("%zu VkDeviceFaultAddressInfoEXT:", addressInfos.size());
+ crashMsg << ", " << addressInfos.size() << " address info (";
+ for (VkDeviceFaultAddressInfoEXT addressInfo : addressInfos) {
+ ALOGE(" addressType: %d", (int)addressInfo.addressType);
+ ALOGE(" reportedAddress: %" PRIu64, addressInfo.reportedAddress);
+ ALOGE(" addressPrecision: %" PRIu64, addressInfo.addressPrecision);
+ crashMsg << addressInfo.addressType << ":" << addressInfo.reportedAddress << ":"
+ << addressInfo.addressPrecision << ", ";
+ }
+ crashMsg.seekp(-2, crashMsg.cur); // Move back to overwrite trailing ", "
+ crashMsg << ")";
+ }
+
+ if (!vendorInfos.empty()) {
+ ALOGE("%zu VkDeviceFaultVendorInfoEXT:", vendorInfos.size());
+ crashMsg << ", " << vendorInfos.size() << " vendor info (";
+ for (VkDeviceFaultVendorInfoEXT vendorInfo : vendorInfos) {
+ ALOGE(" description: %s", vendorInfo.description);
+ ALOGE(" vendorFaultCode: %" PRIu64, vendorInfo.vendorFaultCode);
+ ALOGE(" vendorFaultData: %" PRIu64, vendorInfo.vendorFaultData);
+ // Omit descriptions for individual vendor info structs in the crash string, as the
+ // fault code and fault data fields should be enough for clustering, and the verbosity
+ // isn't worth it. Additionally, vendors may just set the general description field of
+ // the overall fault to the description of the first element in this list, and that
+ // overall description will be placed at the end of the crash string.
+ crashMsg << vendorInfo.vendorFaultCode << ":" << vendorInfo.vendorFaultData << ", ";
+ }
+ crashMsg.seekp(-2, crashMsg.cur); // Move back to overwrite trailing ", "
+ crashMsg << ")";
+ }
+
+ if (!vendorBinaryData.empty()) {
+ // TODO: b/322830575 - Log in base64, or dump directly to a file that gets put in bugreports
+ ALOGE("%zu bytes of vendor-specific binary data (please notify Android's Core Graphics"
+ " Stack team if you observe this message).",
+ vendorBinaryData.size());
+ crashMsg << ", " << vendorBinaryData.size() << " bytes binary";
+ }
+
+ crashMsg << "): " << description;
+ LOG_ALWAYS_FATAL("%s", crashMsg.str().c_str());
+};
+
+static GrVkGetProc sGetProc = [](const char* proc_name, VkInstance instance, VkDevice device) {
+ if (device != VK_NULL_HANDLE) {
+ return vkGetDeviceProcAddr(device, proc_name);
+ }
+ return vkGetInstanceProcAddr(instance, proc_name);
+};
+
+#define BAIL(fmt, ...) \
+ { \
+ ALOGE("%s: " fmt ", bailing", __func__, ##__VA_ARGS__); \
+ return; \
+ }
+
+#define CHECK_NONNULL(expr) \
+ if ((expr) == nullptr) { \
+ BAIL("[%s] null", #expr); \
+ }
+
+#define VK_CHECK(expr) \
+ if ((expr) != VK_SUCCESS) { \
+ BAIL("[%s] failed. err = %d", #expr, expr); \
+ return; \
+ }
+
+#define VK_GET_PROC(F) \
+ PFN_vk##F vk##F = (PFN_vk##F)vkGetInstanceProcAddr(VK_NULL_HANDLE, "vk" #F); \
+ CHECK_NONNULL(vk##F)
+#define VK_GET_INST_PROC(instance, F) \
+ PFN_vk##F vk##F = (PFN_vk##F)vkGetInstanceProcAddr(instance, "vk" #F); \
+ CHECK_NONNULL(vk##F)
+#define VK_GET_DEV_PROC(device, F) \
+ PFN_vk##F vk##F = (PFN_vk##F)vkGetDeviceProcAddr(device, "vk" #F); \
+ CHECK_NONNULL(vk##F)
+
+void VulkanInterface::init(bool protectedContent) {
+ if (isInitialized()) {
+ ALOGW("Called init on already initialized VulkanInterface");
+ return;
+ }
+
+ const nsecs_t timeBefore = systemTime();
+
+ VK_GET_PROC(EnumerateInstanceVersion);
+ uint32_t instanceVersion;
+ VK_CHECK(vkEnumerateInstanceVersion(&instanceVersion));
+
+ if (instanceVersion < VK_MAKE_VERSION(1, 1, 0)) {
+ return;
+ }
+
+ const VkApplicationInfo appInfo = {
+ VK_STRUCTURE_TYPE_APPLICATION_INFO, nullptr, "surfaceflinger", 0, "android platform", 0,
+ VK_MAKE_VERSION(1, 1, 0),
+ };
+
+ VK_GET_PROC(EnumerateInstanceExtensionProperties);
+
+ uint32_t extensionCount = 0;
+ VK_CHECK(vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr));
+ std::vector<VkExtensionProperties> instanceExtensions(extensionCount);
+ VK_CHECK(vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount,
+ instanceExtensions.data()));
+ std::vector<const char*> enabledInstanceExtensionNames;
+ enabledInstanceExtensionNames.reserve(instanceExtensions.size());
+ mInstanceExtensionNames.reserve(instanceExtensions.size());
+ for (const auto& instExt : instanceExtensions) {
+ enabledInstanceExtensionNames.push_back(instExt.extensionName);
+ mInstanceExtensionNames.push_back(instExt.extensionName);
+ }
+
+ const VkInstanceCreateInfo instanceCreateInfo = {
+ VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
+ nullptr,
+ 0,
+ &appInfo,
+ 0,
+ nullptr,
+ (uint32_t)enabledInstanceExtensionNames.size(),
+ enabledInstanceExtensionNames.data(),
+ };
+
+ VK_GET_PROC(CreateInstance);
+ VkInstance instance;
+ VK_CHECK(vkCreateInstance(&instanceCreateInfo, nullptr, &instance));
+
+ VK_GET_INST_PROC(instance, DestroyInstance);
+ mFuncs.vkDestroyInstance = vkDestroyInstance;
+ VK_GET_INST_PROC(instance, EnumeratePhysicalDevices);
+ VK_GET_INST_PROC(instance, EnumerateDeviceExtensionProperties);
+ VK_GET_INST_PROC(instance, GetPhysicalDeviceProperties2);
+ VK_GET_INST_PROC(instance, GetPhysicalDeviceExternalSemaphoreProperties);
+ VK_GET_INST_PROC(instance, GetPhysicalDeviceQueueFamilyProperties2);
+ VK_GET_INST_PROC(instance, GetPhysicalDeviceFeatures2);
+ VK_GET_INST_PROC(instance, CreateDevice);
+
+ uint32_t physdevCount;
+ VK_CHECK(vkEnumeratePhysicalDevices(instance, &physdevCount, nullptr));
+ if (physdevCount == 0) {
+ BAIL("Could not find any physical devices");
+ }
+
+ physdevCount = 1;
+ VkPhysicalDevice physicalDevice;
+ VkResult enumeratePhysDevsErr =
+ vkEnumeratePhysicalDevices(instance, &physdevCount, &physicalDevice);
+ if (enumeratePhysDevsErr != VK_SUCCESS && VK_INCOMPLETE != enumeratePhysDevsErr) {
+ BAIL("vkEnumeratePhysicalDevices failed with non-VK_INCOMPLETE error: %d",
+ enumeratePhysDevsErr);
+ }
+
+ VkPhysicalDeviceProperties2 physDevProps = {
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2,
+ 0,
+ {},
+ };
+ VkPhysicalDeviceProtectedMemoryProperties protMemProps = {
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_PROPERTIES,
+ 0,
+ {},
+ };
+
+ if (protectedContent) {
+ physDevProps.pNext = &protMemProps;
+ }
+
+ vkGetPhysicalDeviceProperties2(physicalDevice, &physDevProps);
+ if (physDevProps.properties.apiVersion < VK_MAKE_VERSION(1, 1, 0)) {
+ BAIL("Could not find a Vulkan 1.1+ physical device");
+ }
+
+ if (physDevProps.properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_CPU) {
+ // TODO: b/326633110 - SkiaVK is not working correctly on swiftshader path.
+ BAIL("CPU implementations of Vulkan is not supported");
+ }
+
+ // Check for syncfd support. Bail if we cannot both import and export them.
+ VkPhysicalDeviceExternalSemaphoreInfo semInfo = {
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO,
+ nullptr,
+ VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT,
+ };
+ VkExternalSemaphoreProperties semProps = {
+ VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES, nullptr, 0, 0, 0,
+ };
+ vkGetPhysicalDeviceExternalSemaphoreProperties(physicalDevice, &semInfo, &semProps);
+
+ bool sufficientSemaphoreSyncFdSupport = (semProps.exportFromImportedHandleTypes &
+ VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT) &&
+ (semProps.compatibleHandleTypes & VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT) &&
+ (semProps.externalSemaphoreFeatures & VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT) &&
+ (semProps.externalSemaphoreFeatures & VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT);
+
+ if (!sufficientSemaphoreSyncFdSupport) {
+ BAIL("Vulkan device does not support sufficient external semaphore sync fd features. "
+ "exportFromImportedHandleTypes 0x%x (needed 0x%x) "
+ "compatibleHandleTypes 0x%x (needed 0x%x) "
+ "externalSemaphoreFeatures 0x%x (needed 0x%x) ",
+ semProps.exportFromImportedHandleTypes, VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT,
+ semProps.compatibleHandleTypes, VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT,
+ semProps.externalSemaphoreFeatures,
+ VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT |
+ VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT);
+ } else {
+ ALOGD("Vulkan device supports sufficient external semaphore sync fd features. "
+ "exportFromImportedHandleTypes 0x%x (needed 0x%x) "
+ "compatibleHandleTypes 0x%x (needed 0x%x) "
+ "externalSemaphoreFeatures 0x%x (needed 0x%x) ",
+ semProps.exportFromImportedHandleTypes, VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT,
+ semProps.compatibleHandleTypes, VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT,
+ semProps.externalSemaphoreFeatures,
+ VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT |
+ VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT);
+ }
+
+ uint32_t queueCount;
+ vkGetPhysicalDeviceQueueFamilyProperties2(physicalDevice, &queueCount, nullptr);
+ if (queueCount == 0) {
+ BAIL("Could not find queues for physical device");
+ }
+
+ std::vector<VkQueueFamilyProperties2> queueProps(queueCount);
+ std::vector<VkQueueFamilyGlobalPriorityPropertiesEXT> queuePriorityProps(queueCount);
+ VkQueueGlobalPriorityKHR queuePriority = VK_QUEUE_GLOBAL_PRIORITY_MEDIUM_KHR;
+ // Even though we don't yet know if the VK_EXT_global_priority extension is available,
+ // we can safely add the request to the pNext chain, and if the extension is not
+ // available, it will be ignored.
+ for (uint32_t i = 0; i < queueCount; ++i) {
+ queuePriorityProps[i].sType = VK_STRUCTURE_TYPE_QUEUE_FAMILY_GLOBAL_PRIORITY_PROPERTIES_EXT;
+ queuePriorityProps[i].pNext = nullptr;
+ queueProps[i].pNext = &queuePriorityProps[i];
+ }
+ vkGetPhysicalDeviceQueueFamilyProperties2(physicalDevice, &queueCount, queueProps.data());
+
+ int graphicsQueueIndex = -1;
+ for (uint32_t i = 0; i < queueCount; ++i) {
+ // Look at potential answers to the VK_EXT_global_priority query. If answers were
+ // provided, we may adjust the queuePriority.
+ if (queueProps[i].queueFamilyProperties.queueFlags & VK_QUEUE_GRAPHICS_BIT) {
+ for (uint32_t j = 0; j < queuePriorityProps[i].priorityCount; j++) {
+ if (queuePriorityProps[i].priorities[j] > queuePriority) {
+ queuePriority = queuePriorityProps[i].priorities[j];
+ }
+ }
+ if (queuePriority == VK_QUEUE_GLOBAL_PRIORITY_REALTIME_KHR) {
+ mIsRealtimePriority = true;
+ }
+ graphicsQueueIndex = i;
+ break;
+ }
+ }
+
+ if (graphicsQueueIndex == -1) {
+ BAIL("Could not find a graphics queue family");
+ }
+
+ uint32_t deviceExtensionCount;
+ VK_CHECK(vkEnumerateDeviceExtensionProperties(physicalDevice, nullptr, &deviceExtensionCount,
+ nullptr));
+ std::vector<VkExtensionProperties> deviceExtensions(deviceExtensionCount);
+ VK_CHECK(vkEnumerateDeviceExtensionProperties(physicalDevice, nullptr, &deviceExtensionCount,
+ deviceExtensions.data()));
+
+ std::vector<const char*> enabledDeviceExtensionNames;
+ enabledDeviceExtensionNames.reserve(deviceExtensions.size());
+ mDeviceExtensionNames.reserve(deviceExtensions.size());
+ for (const auto& devExt : deviceExtensions) {
+ enabledDeviceExtensionNames.push_back(devExt.extensionName);
+ mDeviceExtensionNames.push_back(devExt.extensionName);
+ }
+
+ mGrExtensions.init(sGetProc, instance, physicalDevice, enabledInstanceExtensionNames.size(),
+ enabledInstanceExtensionNames.data(), enabledDeviceExtensionNames.size(),
+ enabledDeviceExtensionNames.data());
+
+ if (!mGrExtensions.hasExtension(VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME, 1)) {
+ BAIL("Vulkan driver doesn't support external semaphore fd");
+ }
+
+ mPhysicalDeviceFeatures2 = new VkPhysicalDeviceFeatures2;
+ mPhysicalDeviceFeatures2->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
+ mPhysicalDeviceFeatures2->pNext = nullptr;
+
+ mSamplerYcbcrConversionFeatures = new VkPhysicalDeviceSamplerYcbcrConversionFeatures;
+ mSamplerYcbcrConversionFeatures->sType =
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES;
+ mSamplerYcbcrConversionFeatures->pNext = nullptr;
+
+ mPhysicalDeviceFeatures2->pNext = mSamplerYcbcrConversionFeatures;
+ void** tailPnext = &mSamplerYcbcrConversionFeatures->pNext;
+
+ if (protectedContent) {
+ mProtectedMemoryFeatures = new VkPhysicalDeviceProtectedMemoryFeatures;
+ mProtectedMemoryFeatures->sType =
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES;
+ mProtectedMemoryFeatures->pNext = nullptr;
+ *tailPnext = mProtectedMemoryFeatures;
+ tailPnext = &mProtectedMemoryFeatures->pNext;
+ }
+
+ if (mGrExtensions.hasExtension(VK_EXT_DEVICE_FAULT_EXTENSION_NAME, 1)) {
+ mDeviceFaultFeatures = new VkPhysicalDeviceFaultFeaturesEXT;
+ mDeviceFaultFeatures->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FAULT_FEATURES_EXT;
+ mDeviceFaultFeatures->pNext = nullptr;
+ *tailPnext = mDeviceFaultFeatures;
+ tailPnext = &mDeviceFaultFeatures->pNext;
+ }
+
+ vkGetPhysicalDeviceFeatures2(physicalDevice, mPhysicalDeviceFeatures2);
+ // Looks like this would slow things down and we can't depend on it on all platforms
+ mPhysicalDeviceFeatures2->features.robustBufferAccess = VK_FALSE;
+
+ if (protectedContent && !mProtectedMemoryFeatures->protectedMemory) {
+ BAIL("Protected memory not supported");
+ }
+
+ float queuePriorities[1] = {0.0f};
+ void* queueNextPtr = nullptr;
+
+ VkDeviceQueueGlobalPriorityCreateInfoEXT queuePriorityCreateInfo = {
+ VK_STRUCTURE_TYPE_DEVICE_QUEUE_GLOBAL_PRIORITY_CREATE_INFO_EXT,
+ nullptr,
+ // If queue priority is supported, RE should always have realtime priority.
+ queuePriority,
+ };
+
+ if (mGrExtensions.hasExtension(VK_EXT_GLOBAL_PRIORITY_EXTENSION_NAME, 2)) {
+ queueNextPtr = &queuePriorityCreateInfo;
+ }
+
+ VkDeviceQueueCreateFlags deviceQueueCreateFlags =
+ (VkDeviceQueueCreateFlags)(protectedContent ? VK_DEVICE_QUEUE_CREATE_PROTECTED_BIT : 0);
+
+ const VkDeviceQueueCreateInfo queueInfo = {
+ VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
+ queueNextPtr,
+ deviceQueueCreateFlags,
+ (uint32_t)graphicsQueueIndex,
+ 1,
+ queuePriorities,
+ };
+
+ const VkDeviceCreateInfo deviceInfo = {
+ VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
+ mPhysicalDeviceFeatures2,
+ 0,
+ 1,
+ &queueInfo,
+ 0,
+ nullptr,
+ (uint32_t)enabledDeviceExtensionNames.size(),
+ enabledDeviceExtensionNames.data(),
+ nullptr,
+ };
+
+ ALOGD("Trying to create Vk device with protectedContent=%d", protectedContent);
+ VkDevice device;
+ VK_CHECK(vkCreateDevice(physicalDevice, &deviceInfo, nullptr, &device));
+ ALOGD("Trying to create Vk device with protectedContent=%d (success)", protectedContent);
+
+ VkQueue graphicsQueue;
+ VK_GET_DEV_PROC(device, GetDeviceQueue2);
+ const VkDeviceQueueInfo2 deviceQueueInfo2 = {VK_STRUCTURE_TYPE_DEVICE_QUEUE_INFO_2, nullptr,
+ deviceQueueCreateFlags,
+ (uint32_t)graphicsQueueIndex, 0};
+ vkGetDeviceQueue2(device, &deviceQueueInfo2, &graphicsQueue);
+
+ VK_GET_DEV_PROC(device, DeviceWaitIdle);
+ VK_GET_DEV_PROC(device, DestroyDevice);
+ mFuncs.vkDeviceWaitIdle = vkDeviceWaitIdle;
+ mFuncs.vkDestroyDevice = vkDestroyDevice;
+
+ VK_GET_DEV_PROC(device, CreateSemaphore);
+ VK_GET_DEV_PROC(device, ImportSemaphoreFdKHR);
+ VK_GET_DEV_PROC(device, GetSemaphoreFdKHR);
+ VK_GET_DEV_PROC(device, DestroySemaphore);
+ mFuncs.vkCreateSemaphore = vkCreateSemaphore;
+ mFuncs.vkImportSemaphoreFdKHR = vkImportSemaphoreFdKHR;
+ mFuncs.vkGetSemaphoreFdKHR = vkGetSemaphoreFdKHR;
+ mFuncs.vkDestroySemaphore = vkDestroySemaphore;
+
+ // At this point, everything's succeeded and we can continue
+ mInitialized = true;
+ mInstance = instance;
+ mPhysicalDevice = physicalDevice;
+ mDevice = device;
+ mQueue = graphicsQueue;
+ mQueueIndex = graphicsQueueIndex;
+ mApiVersion = physDevProps.properties.apiVersion;
+ // grExtensions already constructed
+ // feature pointers already constructed
+ mGrGetProc = sGetProc;
+ mIsProtected = protectedContent;
+ // mIsRealtimePriority already initialized by constructor
+ // funcs already initialized
+
+ const nsecs_t timeAfter = systemTime();
+ const float initTimeMs = static_cast<float>(timeAfter - timeBefore) / 1.0E6;
+ ALOGD("%s: Success init Vulkan interface in %f ms", __func__, initTimeMs);
+}
+
+// TODO: b/293371537 - Iterate on this.
+// Currently unused, but copied over from its original location for potential future use. This
+// should likely be improved to walk the pNext chain of mPhysicalDeviceFeatures2 and free everything
+// like HWUI's VulkanManager. Also, not all fields are being reset.
+void VulkanInterface::teardown() {
+ mInitialized = false;
+
+ if (mDevice != VK_NULL_HANDLE) {
+ mFuncs.vkDeviceWaitIdle(mDevice);
+ mFuncs.vkDestroyDevice(mDevice, nullptr);
+ mDevice = VK_NULL_HANDLE;
+ }
+ if (mInstance != VK_NULL_HANDLE) {
+ mFuncs.vkDestroyInstance(mInstance, nullptr);
+ mInstance = VK_NULL_HANDLE;
+ }
+
+ if (mProtectedMemoryFeatures) {
+ delete mProtectedMemoryFeatures;
+ }
+
+ if (mSamplerYcbcrConversionFeatures) {
+ delete mSamplerYcbcrConversionFeatures;
+ }
+
+ if (mPhysicalDeviceFeatures2) {
+ delete mPhysicalDeviceFeatures2;
+ }
+
+ if (mDeviceFaultFeatures) {
+ delete mDeviceFaultFeatures;
+ }
+
+ mSamplerYcbcrConversionFeatures = nullptr;
+ mPhysicalDeviceFeatures2 = nullptr;
+ mProtectedMemoryFeatures = nullptr;
+ mDeviceFaultFeatures = nullptr;
+}
+
+} // namespace skia
+} // namespace renderengine
+} // namespace android
diff --git a/libs/renderengine/skia/VulkanInterface.h b/libs/renderengine/skia/VulkanInterface.h
new file mode 100644
index 0000000000..c3936d9869
--- /dev/null
+++ b/libs/renderengine/skia/VulkanInterface.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2024 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 <include/gpu/vk/GrVkBackendContext.h>
+#include <include/gpu/vk/GrVkExtensions.h>
+
+#include <vulkan/vulkan.h>
+
+using namespace skgpu;
+
+namespace android {
+namespace renderengine {
+namespace skia {
+
+class VulkanInterface {
+public:
+ // Create an uninitialized interface. Initialize with `init`.
+ VulkanInterface() = default;
+ ~VulkanInterface() = default;
+ VulkanInterface(const VulkanInterface&) = delete;
+ VulkanInterface& operator=(const VulkanInterface&) = delete;
+ VulkanInterface& operator=(VulkanInterface&&) = delete;
+
+ void init(bool protectedContent = false);
+ void teardown();
+
+ // TODO: b/293371537 - Graphite variant (external/skia/include/gpu/vk/VulkanBackendContext.h)
+ GrVkBackendContext getBackendContext();
+ VkSemaphore createExportableSemaphore();
+ VkSemaphore importSemaphoreFromSyncFd(int syncFd);
+ int exportSemaphoreSyncFd(VkSemaphore semaphore);
+ void destroySemaphore(VkSemaphore semaphore);
+
+ bool isInitialized() const { return mInitialized; }
+ bool isRealtimePriority() const { return mIsRealtimePriority; }
+ const std::vector<std::string>& getInstanceExtensionNames() { return mInstanceExtensionNames; }
+ const std::vector<std::string>& getDeviceExtensionNames() { return mDeviceExtensionNames; }
+
+private:
+ struct VulkanFuncs {
+ PFN_vkCreateSemaphore vkCreateSemaphore = nullptr;
+ PFN_vkImportSemaphoreFdKHR vkImportSemaphoreFdKHR = nullptr;
+ PFN_vkGetSemaphoreFdKHR vkGetSemaphoreFdKHR = nullptr;
+ PFN_vkDestroySemaphore vkDestroySemaphore = nullptr;
+
+ PFN_vkDeviceWaitIdle vkDeviceWaitIdle = nullptr;
+ PFN_vkDestroyDevice vkDestroyDevice = nullptr;
+ PFN_vkDestroyInstance vkDestroyInstance = nullptr;
+ };
+
+ static void onVkDeviceFault(void* callbackContext, const std::string& description,
+ const std::vector<VkDeviceFaultAddressInfoEXT>& addressInfos,
+ const std::vector<VkDeviceFaultVendorInfoEXT>& vendorInfos,
+ const std::vector<std::byte>& vendorBinaryData);
+
+ bool mInitialized = false;
+ VkInstance mInstance = VK_NULL_HANDLE;
+ VkPhysicalDevice mPhysicalDevice = VK_NULL_HANDLE;
+ VkDevice mDevice = VK_NULL_HANDLE;
+ VkQueue mQueue = VK_NULL_HANDLE;
+ int mQueueIndex = 0;
+ uint32_t mApiVersion = 0;
+ GrVkExtensions mGrExtensions;
+ VkPhysicalDeviceFeatures2* mPhysicalDeviceFeatures2 = nullptr;
+ VkPhysicalDeviceSamplerYcbcrConversionFeatures* mSamplerYcbcrConversionFeatures = nullptr;
+ VkPhysicalDeviceProtectedMemoryFeatures* mProtectedMemoryFeatures = nullptr;
+ VkPhysicalDeviceFaultFeaturesEXT* mDeviceFaultFeatures = nullptr;
+ GrVkGetProc mGrGetProc = nullptr;
+ bool mIsProtected = false;
+ bool mIsRealtimePriority = false;
+
+ VulkanFuncs mFuncs;
+
+ std::vector<std::string> mInstanceExtensionNames;
+ std::vector<std::string> mDeviceExtensionNames;
+};
+
+} // namespace skia
+} // namespace renderengine
+} // namespace android
diff --git a/libs/renderengine/skia/filters/KawaseBlurFilter.cpp b/libs/renderengine/skia/filters/KawaseBlurFilter.cpp
index 5c9820cdc5..09f09a697a 100644
--- a/libs/renderengine/skia/filters/KawaseBlurFilter.cpp
+++ b/libs/renderengine/skia/filters/KawaseBlurFilter.cpp
@@ -111,7 +111,7 @@ sk_sp<SkImage> KawaseBlurFilter::generate(GrRecordingContext* context,
constexpr int kSampleCount = 1;
constexpr bool kMipmapped = false;
constexpr SkSurfaceProps* kProps = nullptr;
- sk_sp<SkSurface> surface = SkSurfaces::RenderTarget(context, skgpu::Budgeted::kYes, scaledInfo,
+ sk_sp<SkSurface> surface = SkSurfaces::RenderTarget(context, skgpu::Budgeted::kNo, scaledInfo,
kSampleCount, kTopLeft_GrSurfaceOrigin,
kProps, kMipmapped, input->isProtected());
LOG_ALWAYS_FATAL_IF(!surface, "%s: Failed to create surface for blurring!", __func__);
diff --git a/libs/renderengine/tests/Android.bp b/libs/renderengine/tests/Android.bp
index 50e166d2a7..0eea187407 100644
--- a/libs/renderengine/tests/Android.bp
+++ b/libs/renderengine/tests/Android.bp
@@ -19,6 +19,7 @@ package {
// to get the below license kinds:
// SPDX-license-identifier-Apache-2.0
default_applicable_licenses: ["frameworks_native_license"],
+ default_team: "trendy_team_android_core_graphics_stack",
}
cc_test {
@@ -44,6 +45,7 @@ cc_test {
"librenderengine_mocks",
"libshaders",
"libtonemap",
+ "libsurfaceflinger_common",
],
header_libs: [
"libtonemap_headers",
@@ -61,5 +63,6 @@ cc_test {
"libsync",
"libui",
"libutils",
+ "server_configurable_flags",
],
}
diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp
index 11d4fdebdc..7b8eb8470f 100644
--- a/libs/renderengine/tests/RenderEngineTest.cpp
+++ b/libs/renderengine/tests/RenderEngineTest.cpp
@@ -106,25 +106,9 @@ public:
virtual ~RenderEngineFactory() = default;
virtual std::string name() = 0;
- virtual renderengine::RenderEngine::RenderEngineType type() = 0;
- virtual std::unique_ptr<renderengine::RenderEngine> createRenderEngine() = 0;
- virtual bool typeSupported() = 0;
-};
-
-class SkiaVkRenderEngineFactory : public RenderEngineFactory {
-public:
- std::string name() override { return "SkiaVkRenderEngineFactory"; }
-
- renderengine::RenderEngine::RenderEngineType type() {
- return renderengine::RenderEngine::RenderEngineType::SKIA_VK;
- }
-
- std::unique_ptr<renderengine::RenderEngine> createRenderEngine() override {
- std::unique_ptr<renderengine::RenderEngine> re = createSkiaVkRenderEngine();
- return re;
- }
-
- std::unique_ptr<renderengine::skia::SkiaVkRenderEngine> createSkiaVkRenderEngine() {
+ virtual renderengine::RenderEngine::GraphicsApi graphicsApi() = 0;
+ bool apiSupported() { return renderengine::RenderEngine::canSupport(graphicsApi()); }
+ std::unique_ptr<renderengine::RenderEngine> createRenderEngine() {
renderengine::RenderEngineCreationArgs reCreationArgs =
renderengine::RenderEngineCreationArgs::Builder()
.setPixelFormat(static_cast<int>(ui::PixelFormat::RGBA_8888))
@@ -133,65 +117,29 @@ public:
.setPrecacheToneMapperShaderOnly(false)
.setSupportsBackgroundBlur(true)
.setContextPriority(renderengine::RenderEngine::ContextPriority::MEDIUM)
- .setRenderEngineType(type())
+ .setThreaded(renderengine::RenderEngine::Threaded::NO)
+ .setGraphicsApi(graphicsApi())
.build();
- return renderengine::skia::SkiaVkRenderEngine::create(reCreationArgs);
+ return renderengine::RenderEngine::create(reCreationArgs);
}
-
- bool typeSupported() override {
- return skia::SkiaVkRenderEngine::canSupportSkiaVkRenderEngine();
- }
- void skip() { GTEST_SKIP(); }
};
-class SkiaGLESRenderEngineFactory : public RenderEngineFactory {
+class SkiaVkRenderEngineFactory : public RenderEngineFactory {
public:
- std::string name() override { return "SkiaGLRenderEngineFactory"; }
-
- renderengine::RenderEngine::RenderEngineType type() {
- return renderengine::RenderEngine::RenderEngineType::SKIA_GL;
- }
+ std::string name() override { return "SkiaVkRenderEngineFactory"; }
- std::unique_ptr<renderengine::RenderEngine> createRenderEngine() override {
- renderengine::RenderEngineCreationArgs reCreationArgs =
- renderengine::RenderEngineCreationArgs::Builder()
- .setPixelFormat(static_cast<int>(ui::PixelFormat::RGBA_8888))
- .setImageCacheSize(1)
- .setEnableProtectedContext(false)
- .setPrecacheToneMapperShaderOnly(false)
- .setSupportsBackgroundBlur(true)
- .setContextPriority(renderengine::RenderEngine::ContextPriority::MEDIUM)
- .setRenderEngineType(type())
- .build();
- return renderengine::skia::SkiaGLRenderEngine::create(reCreationArgs);
+ renderengine::RenderEngine::GraphicsApi graphicsApi() override {
+ return renderengine::RenderEngine::GraphicsApi::VK;
}
-
- bool typeSupported() override { return true; }
};
-class SkiaGLESCMRenderEngineFactory : public RenderEngineFactory {
+class SkiaGLESRenderEngineFactory : public RenderEngineFactory {
public:
- std::string name() override { return "SkiaGLCMRenderEngineFactory"; }
+ std::string name() override { return "SkiaGLRenderEngineFactory"; }
- renderengine::RenderEngine::RenderEngineType type() {
- return renderengine::RenderEngine::RenderEngineType::SKIA_GL;
+ renderengine::RenderEngine::GraphicsApi graphicsApi() {
+ return renderengine::RenderEngine::GraphicsApi::GL;
}
-
- std::unique_ptr<renderengine::RenderEngine> createRenderEngine() override {
- renderengine::RenderEngineCreationArgs reCreationArgs =
- renderengine::RenderEngineCreationArgs::Builder()
- .setPixelFormat(static_cast<int>(ui::PixelFormat::RGBA_8888))
- .setImageCacheSize(1)
- .setEnableProtectedContext(false)
- .setPrecacheToneMapperShaderOnly(false)
- .setSupportsBackgroundBlur(true)
- .setContextPriority(renderengine::RenderEngine::ContextPriority::MEDIUM)
- .setRenderEngineType(type())
- .build();
- return renderengine::skia::SkiaGLRenderEngine::create(reCreationArgs);
- }
-
- bool typeSupported() override { return true; }
};
class RenderEngineTest : public ::testing::TestWithParam<std::shared_ptr<RenderEngineFactory>> {
@@ -1526,7 +1474,7 @@ INSTANTIATE_TEST_SUITE_P(PerRenderEngineType, RenderEngineTest,
std::make_shared<SkiaVkRenderEngineFactory>()));
TEST_P(RenderEngineTest, drawLayers_noLayersToDraw) {
- if (!GetParam()->typeSupported()) {
+ if (!GetParam()->apiSupported()) {
GTEST_SKIP();
}
initializeRenderEngine();
@@ -1534,7 +1482,7 @@ TEST_P(RenderEngineTest, drawLayers_noLayersToDraw) {
}
TEST_P(RenderEngineTest, drawLayers_fillRedBufferAndEmptyBuffer) {
- if (!GetParam()->typeSupported()) {
+ if (!GetParam()->apiSupported()) {
GTEST_SKIP();
}
initializeRenderEngine();
@@ -1561,7 +1509,7 @@ TEST_P(RenderEngineTest, drawLayers_fillRedBufferAndEmptyBuffer) {
}
TEST_P(RenderEngineTest, drawLayers_withoutBuffers_withColorTransform) {
- if (!GetParam()->typeSupported()) {
+ if (!GetParam()->apiSupported()) {
GTEST_SKIP();
}
initializeRenderEngine();
@@ -1595,7 +1543,7 @@ TEST_P(RenderEngineTest, drawLayers_withoutBuffers_withColorTransform) {
}
TEST_P(RenderEngineTest, drawLayers_nullOutputBuffer) {
- if (!GetParam()->typeSupported()) {
+ if (!GetParam()->apiSupported()) {
GTEST_SKIP();
}
initializeRenderEngine();
@@ -1616,7 +1564,7 @@ TEST_P(RenderEngineTest, drawLayers_nullOutputBuffer) {
}
TEST_P(RenderEngineTest, drawLayers_fillRedBuffer_colorSource) {
- if (!GetParam()->typeSupported()) {
+ if (!GetParam()->apiSupported()) {
GTEST_SKIP();
}
initializeRenderEngine();
@@ -1624,7 +1572,7 @@ TEST_P(RenderEngineTest, drawLayers_fillRedBuffer_colorSource) {
}
TEST_P(RenderEngineTest, drawLayers_fillGreenBuffer_colorSource) {
- if (!GetParam()->typeSupported()) {
+ if (!GetParam()->apiSupported()) {
GTEST_SKIP();
}
initializeRenderEngine();
@@ -1632,7 +1580,7 @@ TEST_P(RenderEngineTest, drawLayers_fillGreenBuffer_colorSource) {
}
TEST_P(RenderEngineTest, drawLayers_fillBlueBuffer_colorSource) {
- if (!GetParam()->typeSupported()) {
+ if (!GetParam()->apiSupported()) {
GTEST_SKIP();
}
initializeRenderEngine();
@@ -1640,7 +1588,7 @@ TEST_P(RenderEngineTest, drawLayers_fillBlueBuffer_colorSource) {
}
TEST_P(RenderEngineTest, drawLayers_fillRedTransparentBuffer_colorSource) {
- if (!GetParam()->typeSupported()) {
+ if (!GetParam()->apiSupported()) {
GTEST_SKIP();
}
initializeRenderEngine();
@@ -1648,7 +1596,7 @@ TEST_P(RenderEngineTest, drawLayers_fillRedTransparentBuffer_colorSource) {
}
TEST_P(RenderEngineTest, drawLayers_fillBufferPhysicalOffset_colorSource) {
- if (!GetParam()->typeSupported()) {
+ if (!GetParam()->apiSupported()) {
GTEST_SKIP();
}
initializeRenderEngine();
@@ -1656,7 +1604,7 @@ TEST_P(RenderEngineTest, drawLayers_fillBufferPhysicalOffset_colorSource) {
}
TEST_P(RenderEngineTest, drawLayers_fillBufferCheckersRotate0_colorSource) {
- if (!GetParam()->typeSupported()) {
+ if (!GetParam()->apiSupported()) {
GTEST_SKIP();
}
initializeRenderEngine();
@@ -1664,7 +1612,7 @@ TEST_P(RenderEngineTest, drawLayers_fillBufferCheckersRotate0_colorSource) {
}
TEST_P(RenderEngineTest, drawLayers_fillBufferCheckersRotate90_colorSource) {
- if (!GetParam()->typeSupported()) {
+ if (!GetParam()->apiSupported()) {
GTEST_SKIP();
}
initializeRenderEngine();
@@ -1672,7 +1620,7 @@ TEST_P(RenderEngineTest, drawLayers_fillBufferCheckersRotate90_colorSource) {
}
TEST_P(RenderEngineTest, drawLayers_fillBufferCheckersRotate180_colorSource) {
- if (!GetParam()->typeSupported()) {
+ if (!GetParam()->apiSupported()) {
GTEST_SKIP();
}
initializeRenderEngine();
@@ -1680,7 +1628,7 @@ TEST_P(RenderEngineTest, drawLayers_fillBufferCheckersRotate180_colorSource) {
}
TEST_P(RenderEngineTest, drawLayers_fillBufferCheckersRotate270_colorSource) {
- if (!GetParam()->typeSupported()) {
+ if (!GetParam()->apiSupported()) {
GTEST_SKIP();
}
initializeRenderEngine();
@@ -1688,7 +1636,7 @@ TEST_P(RenderEngineTest, drawLayers_fillBufferCheckersRotate270_colorSource) {
}
TEST_P(RenderEngineTest, drawLayers_fillBufferLayerTransform_colorSource) {
- if (!GetParam()->typeSupported()) {
+ if (!GetParam()->apiSupported()) {
GTEST_SKIP();
}
initializeRenderEngine();
@@ -1696,7 +1644,7 @@ TEST_P(RenderEngineTest, drawLayers_fillBufferLayerTransform_colorSource) {
}
TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransform_colorSource) {
- if (!GetParam()->typeSupported()) {
+ if (!GetParam()->apiSupported()) {
GTEST_SKIP();
}
initializeRenderEngine();
@@ -1706,7 +1654,7 @@ TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransform_colorSource) {
TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransform_sourceDataspace) {
const auto& renderEngineFactory = GetParam();
// skip for non color management
- if (!renderEngineFactory->typeSupported()) {
+ if (!renderEngineFactory->apiSupported()) {
GTEST_SKIP();
}
@@ -1717,7 +1665,7 @@ TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransform_sourceDataspace) {
TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransform_outputDataspace) {
const auto& renderEngineFactory = GetParam();
// skip for non color management
- if (!renderEngineFactory->typeSupported()) {
+ if (!renderEngineFactory->apiSupported()) {
GTEST_SKIP();
}
@@ -1726,7 +1674,7 @@ TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransform_outputDataspace) {
}
TEST_P(RenderEngineTest, drawLayers_fillBufferRoundedCorners_colorSource) {
- if (!GetParam()->typeSupported()) {
+ if (!GetParam()->apiSupported()) {
GTEST_SKIP();
}
initializeRenderEngine();
@@ -1734,7 +1682,7 @@ TEST_P(RenderEngineTest, drawLayers_fillBufferRoundedCorners_colorSource) {
}
TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransformZeroLayerAlpha_colorSource) {
- if (!GetParam()->typeSupported()) {
+ if (!GetParam()->apiSupported()) {
GTEST_SKIP();
}
initializeRenderEngine();
@@ -1742,7 +1690,7 @@ TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransformZeroLayerAlpha_color
}
TEST_P(RenderEngineTest, drawLayers_fillBufferAndBlurBackground_colorSource) {
- if (!GetParam()->typeSupported()) {
+ if (!GetParam()->apiSupported()) {
GTEST_SKIP();
}
initializeRenderEngine();
@@ -1750,7 +1698,7 @@ TEST_P(RenderEngineTest, drawLayers_fillBufferAndBlurBackground_colorSource) {
}
TEST_P(RenderEngineTest, drawLayers_fillSmallLayerAndBlurBackground_colorSource) {
- if (!GetParam()->typeSupported()) {
+ if (!GetParam()->apiSupported()) {
GTEST_SKIP();
}
initializeRenderEngine();
@@ -1758,7 +1706,7 @@ TEST_P(RenderEngineTest, drawLayers_fillSmallLayerAndBlurBackground_colorSource)
}
TEST_P(RenderEngineTest, drawLayers_overlayCorners_colorSource) {
- if (!GetParam()->typeSupported()) {
+ if (!GetParam()->apiSupported()) {
GTEST_SKIP();
}
initializeRenderEngine();
@@ -1766,7 +1714,7 @@ TEST_P(RenderEngineTest, drawLayers_overlayCorners_colorSource) {
}
TEST_P(RenderEngineTest, drawLayers_fillRedBuffer_opaqueBufferSource) {
- if (!GetParam()->typeSupported()) {
+ if (!GetParam()->apiSupported()) {
GTEST_SKIP();
}
initializeRenderEngine();
@@ -1774,7 +1722,7 @@ TEST_P(RenderEngineTest, drawLayers_fillRedBuffer_opaqueBufferSource) {
}
TEST_P(RenderEngineTest, drawLayers_fillGreenBuffer_opaqueBufferSource) {
- if (!GetParam()->typeSupported()) {
+ if (!GetParam()->apiSupported()) {
GTEST_SKIP();
}
initializeRenderEngine();
@@ -1782,7 +1730,7 @@ TEST_P(RenderEngineTest, drawLayers_fillGreenBuffer_opaqueBufferSource) {
}
TEST_P(RenderEngineTest, drawLayers_fillBlueBuffer_opaqueBufferSource) {
- if (!GetParam()->typeSupported()) {
+ if (!GetParam()->apiSupported()) {
GTEST_SKIP();
}
initializeRenderEngine();
@@ -1790,7 +1738,7 @@ TEST_P(RenderEngineTest, drawLayers_fillBlueBuffer_opaqueBufferSource) {
}
TEST_P(RenderEngineTest, drawLayers_fillRedTransparentBuffer_opaqueBufferSource) {
- if (!GetParam()->typeSupported()) {
+ if (!GetParam()->apiSupported()) {
GTEST_SKIP();
}
initializeRenderEngine();
@@ -1798,7 +1746,7 @@ TEST_P(RenderEngineTest, drawLayers_fillRedTransparentBuffer_opaqueBufferSource)
}
TEST_P(RenderEngineTest, drawLayers_fillBufferPhysicalOffset_opaqueBufferSource) {
- if (!GetParam()->typeSupported()) {
+ if (!GetParam()->apiSupported()) {
GTEST_SKIP();
}
initializeRenderEngine();
@@ -1806,7 +1754,7 @@ TEST_P(RenderEngineTest, drawLayers_fillBufferPhysicalOffset_opaqueBufferSource)
}
TEST_P(RenderEngineTest, drawLayers_fillBufferCheckersRotate0_opaqueBufferSource) {
- if (!GetParam()->typeSupported()) {
+ if (!GetParam()->apiSupported()) {
GTEST_SKIP();
}
initializeRenderEngine();
@@ -1814,7 +1762,7 @@ TEST_P(RenderEngineTest, drawLayers_fillBufferCheckersRotate0_opaqueBufferSource
}
TEST_P(RenderEngineTest, drawLayers_fillBufferCheckersRotate90_opaqueBufferSource) {
- if (!GetParam()->typeSupported()) {
+ if (!GetParam()->apiSupported()) {
GTEST_SKIP();
}
initializeRenderEngine();
@@ -1822,7 +1770,7 @@ TEST_P(RenderEngineTest, drawLayers_fillBufferCheckersRotate90_opaqueBufferSourc
}
TEST_P(RenderEngineTest, drawLayers_fillBufferCheckersRotate180_opaqueBufferSource) {
- if (!GetParam()->typeSupported()) {
+ if (!GetParam()->apiSupported()) {
GTEST_SKIP();
}
initializeRenderEngine();
@@ -1830,7 +1778,7 @@ TEST_P(RenderEngineTest, drawLayers_fillBufferCheckersRotate180_opaqueBufferSour
}
TEST_P(RenderEngineTest, drawLayers_fillBufferCheckersRotate270_opaqueBufferSource) {
- if (!GetParam()->typeSupported()) {
+ if (!GetParam()->apiSupported()) {
GTEST_SKIP();
}
initializeRenderEngine();
@@ -1838,7 +1786,7 @@ TEST_P(RenderEngineTest, drawLayers_fillBufferCheckersRotate270_opaqueBufferSour
}
TEST_P(RenderEngineTest, drawLayers_fillBufferLayerTransform_opaqueBufferSource) {
- if (!GetParam()->typeSupported()) {
+ if (!GetParam()->apiSupported()) {
GTEST_SKIP();
}
initializeRenderEngine();
@@ -1846,7 +1794,7 @@ TEST_P(RenderEngineTest, drawLayers_fillBufferLayerTransform_opaqueBufferSource)
}
TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransform_opaqueBufferSource) {
- if (!GetParam()->typeSupported()) {
+ if (!GetParam()->apiSupported()) {
GTEST_SKIP();
}
initializeRenderEngine();
@@ -1856,7 +1804,7 @@ TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransform_opaqueBufferSource)
TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransformAndSourceDataspace_opaqueBufferSource) {
const auto& renderEngineFactory = GetParam();
// skip for non color management
- if (!renderEngineFactory->typeSupported()) {
+ if (!renderEngineFactory->apiSupported()) {
GTEST_SKIP();
}
@@ -1867,7 +1815,7 @@ TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransformAndSourceDataspace_o
TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransformAndOutputDataspace_opaqueBufferSource) {
const auto& renderEngineFactory = GetParam();
// skip for non color management
- if (!renderEngineFactory->typeSupported()) {
+ if (!renderEngineFactory->apiSupported()) {
GTEST_SKIP();
}
@@ -1876,7 +1824,7 @@ TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransformAndOutputDataspace_o
}
TEST_P(RenderEngineTest, drawLayers_fillBufferRoundedCorners_opaqueBufferSource) {
- if (!GetParam()->typeSupported()) {
+ if (!GetParam()->apiSupported()) {
GTEST_SKIP();
}
initializeRenderEngine();
@@ -1884,7 +1832,7 @@ TEST_P(RenderEngineTest, drawLayers_fillBufferRoundedCorners_opaqueBufferSource)
}
TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransformZeroLayerAlpha_opaqueBufferSource) {
- if (!GetParam()->typeSupported()) {
+ if (!GetParam()->apiSupported()) {
GTEST_SKIP();
}
initializeRenderEngine();
@@ -1892,7 +1840,7 @@ TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransformZeroLayerAlpha_opaqu
}
TEST_P(RenderEngineTest, drawLayers_fillBufferAndBlurBackground_opaqueBufferSource) {
- if (!GetParam()->typeSupported()) {
+ if (!GetParam()->apiSupported()) {
GTEST_SKIP();
}
initializeRenderEngine();
@@ -1900,7 +1848,7 @@ TEST_P(RenderEngineTest, drawLayers_fillBufferAndBlurBackground_opaqueBufferSour
}
TEST_P(RenderEngineTest, drawLayers_fillSmallLayerAndBlurBackground_opaqueBufferSource) {
- if (!GetParam()->typeSupported()) {
+ if (!GetParam()->apiSupported()) {
GTEST_SKIP();
}
initializeRenderEngine();
@@ -1908,7 +1856,7 @@ TEST_P(RenderEngineTest, drawLayers_fillSmallLayerAndBlurBackground_opaqueBuffer
}
TEST_P(RenderEngineTest, drawLayers_overlayCorners_opaqueBufferSource) {
- if (!GetParam()->typeSupported()) {
+ if (!GetParam()->apiSupported()) {
GTEST_SKIP();
}
initializeRenderEngine();
@@ -1916,7 +1864,7 @@ TEST_P(RenderEngineTest, drawLayers_overlayCorners_opaqueBufferSource) {
}
TEST_P(RenderEngineTest, drawLayers_fillRedBuffer_bufferSource) {
- if (!GetParam()->typeSupported()) {
+ if (!GetParam()->apiSupported()) {
GTEST_SKIP();
}
initializeRenderEngine();
@@ -1924,7 +1872,7 @@ TEST_P(RenderEngineTest, drawLayers_fillRedBuffer_bufferSource) {
}
TEST_P(RenderEngineTest, drawLayers_fillGreenBuffer_bufferSource) {
- if (!GetParam()->typeSupported()) {
+ if (!GetParam()->apiSupported()) {
GTEST_SKIP();
}
initializeRenderEngine();
@@ -1932,7 +1880,7 @@ TEST_P(RenderEngineTest, drawLayers_fillGreenBuffer_bufferSource) {
}
TEST_P(RenderEngineTest, drawLayers_fillBlueBuffer_bufferSource) {
- if (!GetParam()->typeSupported()) {
+ if (!GetParam()->apiSupported()) {
GTEST_SKIP();
}
initializeRenderEngine();
@@ -1940,7 +1888,7 @@ TEST_P(RenderEngineTest, drawLayers_fillBlueBuffer_bufferSource) {
}
TEST_P(RenderEngineTest, drawLayers_fillRedTransparentBuffer_bufferSource) {
- if (!GetParam()->typeSupported()) {
+ if (!GetParam()->apiSupported()) {
GTEST_SKIP();
}
initializeRenderEngine();
@@ -1948,7 +1896,7 @@ TEST_P(RenderEngineTest, drawLayers_fillRedTransparentBuffer_bufferSource) {
}
TEST_P(RenderEngineTest, drawLayers_fillBufferPhysicalOffset_bufferSource) {
- if (!GetParam()->typeSupported()) {
+ if (!GetParam()->apiSupported()) {
GTEST_SKIP();
}
initializeRenderEngine();
@@ -1956,7 +1904,7 @@ TEST_P(RenderEngineTest, drawLayers_fillBufferPhysicalOffset_bufferSource) {
}
TEST_P(RenderEngineTest, drawLayers_fillBufferCheckersRotate0_bufferSource) {
- if (!GetParam()->typeSupported()) {
+ if (!GetParam()->apiSupported()) {
GTEST_SKIP();
}
initializeRenderEngine();
@@ -1964,7 +1912,7 @@ TEST_P(RenderEngineTest, drawLayers_fillBufferCheckersRotate0_bufferSource) {
}
TEST_P(RenderEngineTest, drawLayers_fillBufferCheckersRotate90_bufferSource) {
- if (!GetParam()->typeSupported()) {
+ if (!GetParam()->apiSupported()) {
GTEST_SKIP();
}
initializeRenderEngine();
@@ -1972,7 +1920,7 @@ TEST_P(RenderEngineTest, drawLayers_fillBufferCheckersRotate90_bufferSource) {
}
TEST_P(RenderEngineTest, drawLayers_fillBufferCheckersRotate180_bufferSource) {
- if (!GetParam()->typeSupported()) {
+ if (!GetParam()->apiSupported()) {
GTEST_SKIP();
}
initializeRenderEngine();
@@ -1980,7 +1928,7 @@ TEST_P(RenderEngineTest, drawLayers_fillBufferCheckersRotate180_bufferSource) {
}
TEST_P(RenderEngineTest, drawLayers_fillBufferCheckersRotate270_bufferSource) {
- if (!GetParam()->typeSupported()) {
+ if (!GetParam()->apiSupported()) {
GTEST_SKIP();
}
initializeRenderEngine();
@@ -1988,7 +1936,7 @@ TEST_P(RenderEngineTest, drawLayers_fillBufferCheckersRotate270_bufferSource) {
}
TEST_P(RenderEngineTest, drawLayers_fillBufferLayerTransform_bufferSource) {
- if (!GetParam()->typeSupported()) {
+ if (!GetParam()->apiSupported()) {
GTEST_SKIP();
}
initializeRenderEngine();
@@ -1996,7 +1944,7 @@ TEST_P(RenderEngineTest, drawLayers_fillBufferLayerTransform_bufferSource) {
}
TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransform_bufferSource) {
- if (!GetParam()->typeSupported()) {
+ if (!GetParam()->apiSupported()) {
GTEST_SKIP();
}
initializeRenderEngine();
@@ -2006,7 +1954,7 @@ TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransform_bufferSource) {
TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransformAndSourceDataspace_bufferSource) {
const auto& renderEngineFactory = GetParam();
// skip for non color management
- if (!renderEngineFactory->typeSupported()) {
+ if (!renderEngineFactory->apiSupported()) {
GTEST_SKIP();
}
@@ -2017,7 +1965,7 @@ TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransformAndSourceDataspace_b
TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransformAndOutputDataspace_bufferSource) {
const auto& renderEngineFactory = GetParam();
// skip for non color management
- if (!renderEngineFactory->typeSupported()) {
+ if (!renderEngineFactory->apiSupported()) {
GTEST_SKIP();
}
@@ -2026,7 +1974,7 @@ TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransformAndOutputDataspace_b
}
TEST_P(RenderEngineTest, drawLayers_fillBufferRoundedCorners_bufferSource) {
- if (!GetParam()->typeSupported()) {
+ if (!GetParam()->apiSupported()) {
GTEST_SKIP();
}
initializeRenderEngine();
@@ -2034,7 +1982,7 @@ TEST_P(RenderEngineTest, drawLayers_fillBufferRoundedCorners_bufferSource) {
}
TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransformZeroLayerAlpha_bufferSource) {
- if (!GetParam()->typeSupported()) {
+ if (!GetParam()->apiSupported()) {
GTEST_SKIP();
}
initializeRenderEngine();
@@ -2042,7 +1990,7 @@ TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransformZeroLayerAlpha_buffe
}
TEST_P(RenderEngineTest, drawLayers_fillBufferAndBlurBackground_bufferSource) {
- if (!GetParam()->typeSupported()) {
+ if (!GetParam()->apiSupported()) {
GTEST_SKIP();
}
initializeRenderEngine();
@@ -2050,7 +1998,7 @@ TEST_P(RenderEngineTest, drawLayers_fillBufferAndBlurBackground_bufferSource) {
}
TEST_P(RenderEngineTest, drawLayers_fillSmallLayerAndBlurBackground_bufferSource) {
- if (!GetParam()->typeSupported()) {
+ if (!GetParam()->apiSupported()) {
GTEST_SKIP();
}
initializeRenderEngine();
@@ -2058,7 +2006,7 @@ TEST_P(RenderEngineTest, drawLayers_fillSmallLayerAndBlurBackground_bufferSource
}
TEST_P(RenderEngineTest, drawLayers_overlayCorners_bufferSource) {
- if (!GetParam()->typeSupported()) {
+ if (!GetParam()->apiSupported()) {
GTEST_SKIP();
}
initializeRenderEngine();
@@ -2066,7 +2014,7 @@ TEST_P(RenderEngineTest, drawLayers_overlayCorners_bufferSource) {
}
TEST_P(RenderEngineTest, drawLayers_fillBufferTextureTransform) {
- if (!GetParam()->typeSupported()) {
+ if (!GetParam()->apiSupported()) {
GTEST_SKIP();
}
initializeRenderEngine();
@@ -2074,7 +2022,7 @@ TEST_P(RenderEngineTest, drawLayers_fillBufferTextureTransform) {
}
TEST_P(RenderEngineTest, drawLayers_fillBuffer_premultipliesAlpha) {
- if (!GetParam()->typeSupported()) {
+ if (!GetParam()->apiSupported()) {
GTEST_SKIP();
}
initializeRenderEngine();
@@ -2082,7 +2030,7 @@ TEST_P(RenderEngineTest, drawLayers_fillBuffer_premultipliesAlpha) {
}
TEST_P(RenderEngineTest, drawLayers_fillBuffer_withoutPremultiplyingAlpha) {
- if (!GetParam()->typeSupported()) {
+ if (!GetParam()->apiSupported()) {
GTEST_SKIP();
}
initializeRenderEngine();
@@ -2090,7 +2038,7 @@ TEST_P(RenderEngineTest, drawLayers_fillBuffer_withoutPremultiplyingAlpha) {
}
TEST_P(RenderEngineTest, drawLayers_fillShadow_castsWithoutCasterLayer) {
- if (!GetParam()->typeSupported()) {
+ if (!GetParam()->apiSupported()) {
GTEST_SKIP();
}
initializeRenderEngine();
@@ -2108,7 +2056,7 @@ TEST_P(RenderEngineTest, drawLayers_fillShadow_castsWithoutCasterLayer) {
}
TEST_P(RenderEngineTest, drawLayers_fillShadow_casterLayerMinSize) {
- if (!GetParam()->typeSupported()) {
+ if (!GetParam()->apiSupported()) {
GTEST_SKIP();
}
initializeRenderEngine();
@@ -2131,7 +2079,7 @@ TEST_P(RenderEngineTest, drawLayers_fillShadow_casterLayerMinSize) {
}
TEST_P(RenderEngineTest, drawLayers_fillShadow_casterColorLayer) {
- if (!GetParam()->typeSupported()) {
+ if (!GetParam()->apiSupported()) {
GTEST_SKIP();
}
initializeRenderEngine();
@@ -2155,7 +2103,7 @@ TEST_P(RenderEngineTest, drawLayers_fillShadow_casterColorLayer) {
}
TEST_P(RenderEngineTest, drawLayers_fillShadow_casterOpaqueBufferLayer) {
- if (!GetParam()->typeSupported()) {
+ if (!GetParam()->apiSupported()) {
GTEST_SKIP();
}
initializeRenderEngine();
@@ -2180,7 +2128,7 @@ TEST_P(RenderEngineTest, drawLayers_fillShadow_casterOpaqueBufferLayer) {
}
TEST_P(RenderEngineTest, drawLayers_fillShadow_casterWithRoundedCorner) {
- if (!GetParam()->typeSupported()) {
+ if (!GetParam()->apiSupported()) {
GTEST_SKIP();
}
initializeRenderEngine();
@@ -2206,7 +2154,7 @@ TEST_P(RenderEngineTest, drawLayers_fillShadow_casterWithRoundedCorner) {
}
TEST_P(RenderEngineTest, drawLayers_fillShadow_translucentCasterWithAlpha) {
- if (!GetParam()->typeSupported()) {
+ if (!GetParam()->apiSupported()) {
GTEST_SKIP();
}
initializeRenderEngine();
@@ -2235,7 +2183,7 @@ TEST_P(RenderEngineTest, drawLayers_fillShadow_translucentCasterWithAlpha) {
}
TEST_P(RenderEngineTest, cleanupPostRender_cleansUpOnce) {
- if (!GetParam()->typeSupported()) {
+ if (!GetParam()->apiSupported()) {
GTEST_SKIP();
}
initializeRenderEngine();
@@ -2271,7 +2219,7 @@ TEST_P(RenderEngineTest, cleanupPostRender_cleansUpOnce) {
if (mRE->canSkipPostRenderCleanup()) {
// Skia's Vk backend may keep the texture alive beyond drawLayersInternal, so
// it never gets added to the cleanup list. In those cases, we can skip.
- EXPECT_TRUE(GetParam()->type() == renderengine::RenderEngine::RenderEngineType::SKIA_VK);
+ EXPECT_TRUE(GetParam()->graphicsApi() == renderengine::RenderEngine::GraphicsApi::VK);
} else {
mRE->cleanupPostRender();
EXPECT_TRUE(mRE->canSkipPostRenderCleanup());
@@ -2279,7 +2227,7 @@ TEST_P(RenderEngineTest, cleanupPostRender_cleansUpOnce) {
}
TEST_P(RenderEngineTest, testRoundedCornersCrop) {
- if (!GetParam()->typeSupported()) {
+ if (!GetParam()->apiSupported()) {
GTEST_SKIP();
}
initializeRenderEngine();
@@ -2332,7 +2280,7 @@ TEST_P(RenderEngineTest, testRoundedCornersCrop) {
}
TEST_P(RenderEngineTest, testRoundedCornersParentCrop) {
- if (!GetParam()->typeSupported()) {
+ if (!GetParam()->apiSupported()) {
GTEST_SKIP();
}
initializeRenderEngine();
@@ -2380,7 +2328,7 @@ TEST_P(RenderEngineTest, testRoundedCornersParentCrop) {
}
TEST_P(RenderEngineTest, testRoundedCornersParentCropSmallBounds) {
- if (!GetParam()->typeSupported()) {
+ if (!GetParam()->apiSupported()) {
GTEST_SKIP();
}
initializeRenderEngine();
@@ -2417,7 +2365,7 @@ TEST_P(RenderEngineTest, testRoundedCornersParentCropSmallBounds) {
}
TEST_P(RenderEngineTest, testRoundedCornersXY) {
- if (GetParam()->type() != renderengine::RenderEngine::RenderEngineType::SKIA_GL) {
+ if (!GetParam()->apiSupported()) {
GTEST_SKIP();
}
@@ -2460,7 +2408,7 @@ TEST_P(RenderEngineTest, testRoundedCornersXY) {
}
TEST_P(RenderEngineTest, testClear) {
- if (!GetParam()->typeSupported()) {
+ if (!GetParam()->apiSupported()) {
GTEST_SKIP();
}
initializeRenderEngine();
@@ -2492,7 +2440,7 @@ TEST_P(RenderEngineTest, testClear) {
}
TEST_P(RenderEngineTest, testDisableBlendingBuffer) {
- if (!GetParam()->typeSupported()) {
+ if (!GetParam()->apiSupported()) {
GTEST_SKIP();
}
initializeRenderEngine();
@@ -2543,7 +2491,7 @@ TEST_P(RenderEngineTest, testDisableBlendingBuffer) {
}
TEST_P(RenderEngineTest, testBorder) {
- if (GetParam()->type() != renderengine::RenderEngine::RenderEngineType::SKIA_GL) {
+ if (!GetParam()->apiSupported()) {
GTEST_SKIP();
}
@@ -2588,7 +2536,7 @@ TEST_P(RenderEngineTest, testBorder) {
}
TEST_P(RenderEngineTest, testDimming) {
- if (!GetParam()->typeSupported()) {
+ if (!GetParam()->apiSupported()) {
GTEST_SKIP();
}
initializeRenderEngine();
@@ -2663,7 +2611,7 @@ TEST_P(RenderEngineTest, testDimming) {
}
TEST_P(RenderEngineTest, testDimming_inGammaSpace) {
- if (!GetParam()->typeSupported()) {
+ if (!GetParam()->apiSupported()) {
GTEST_SKIP();
}
initializeRenderEngine();
@@ -2741,7 +2689,7 @@ TEST_P(RenderEngineTest, testDimming_inGammaSpace) {
}
TEST_P(RenderEngineTest, testDimming_inGammaSpace_withDisplayColorTransform) {
- if (!GetParam()->typeSupported()) {
+ if (!GetParam()->apiSupported()) {
GTEST_SKIP();
}
initializeRenderEngine();
@@ -2804,7 +2752,7 @@ TEST_P(RenderEngineTest, testDimming_inGammaSpace_withDisplayColorTransform) {
}
TEST_P(RenderEngineTest, testDimming_inGammaSpace_withDisplayColorTransform_deviceHandles) {
- if (!GetParam()->typeSupported()) {
+ if (!GetParam()->apiSupported()) {
GTEST_SKIP();
}
initializeRenderEngine();
@@ -2868,7 +2816,7 @@ TEST_P(RenderEngineTest, testDimming_inGammaSpace_withDisplayColorTransform_devi
}
TEST_P(RenderEngineTest, testDimming_withoutTargetLuminance) {
- if (!GetParam()->typeSupported()) {
+ if (!GetParam()->apiSupported()) {
GTEST_SKIP();
}
initializeRenderEngine();
@@ -2922,7 +2870,7 @@ TEST_P(RenderEngineTest, testDimming_withoutTargetLuminance) {
}
TEST_P(RenderEngineTest, test_isOpaque) {
- if (!GetParam()->typeSupported()) {
+ if (!GetParam()->apiSupported()) {
GTEST_SKIP();
}
initializeRenderEngine();
@@ -2972,7 +2920,7 @@ TEST_P(RenderEngineTest, test_isOpaque) {
}
TEST_P(RenderEngineTest, test_tonemapPQMatches) {
- if (!GetParam()->typeSupported()) {
+ if (!GetParam()->apiSupported()) {
GTEST_SKIP();
}
@@ -2989,7 +2937,7 @@ TEST_P(RenderEngineTest, test_tonemapPQMatches) {
}
TEST_P(RenderEngineTest, test_tonemapHLGMatches) {
- if (!GetParam()->typeSupported()) {
+ if (!GetParam()->apiSupported()) {
GTEST_SKIP();
}
@@ -3006,7 +2954,7 @@ TEST_P(RenderEngineTest, test_tonemapHLGMatches) {
}
TEST_P(RenderEngineTest, r8_behaves_as_mask) {
- if (!GetParam()->typeSupported()) {
+ if (!GetParam()->apiSupported()) {
GTEST_SKIP();
}
initializeRenderEngine();
@@ -3066,7 +3014,7 @@ TEST_P(RenderEngineTest, r8_behaves_as_mask) {
}
TEST_P(RenderEngineTest, r8_respects_color_transform) {
- if (!GetParam()->typeSupported()) {
+ if (!GetParam()->apiSupported()) {
GTEST_SKIP();
}
initializeRenderEngine();
@@ -3131,7 +3079,7 @@ TEST_P(RenderEngineTest, r8_respects_color_transform) {
}
TEST_P(RenderEngineTest, r8_respects_color_transform_when_device_handles) {
- if (!GetParam()->typeSupported()) {
+ if (!GetParam()->apiSupported()) {
GTEST_SKIP();
}
initializeRenderEngine();
@@ -3199,7 +3147,7 @@ TEST_P(RenderEngineTest, r8_respects_color_transform_when_device_handles) {
}
TEST_P(RenderEngineTest, primeShaderCache) {
- if (!GetParam()->typeSupported()) {
+ if (!GetParam()->apiSupported()) {
GTEST_SKIP();
}
initializeRenderEngine();
diff --git a/libs/renderengine/tests/RenderEngineThreadedTest.cpp b/libs/renderengine/tests/RenderEngineThreadedTest.cpp
index 1b9adba063..d56dbb2a7b 100644
--- a/libs/renderengine/tests/RenderEngineThreadedTest.cpp
+++ b/libs/renderengine/tests/RenderEngineThreadedTest.cpp
@@ -35,8 +35,7 @@ struct RenderEngineThreadedTest : public ::testing::Test {
void SetUp() override {
mThreadedRE = renderengine::threaded::RenderEngineThreaded::create(
- [this]() { return std::unique_ptr<renderengine::RenderEngine>(mRenderEngine); },
- renderengine::RenderEngine::RenderEngineType::SKIA_GL_THREADED);
+ [this]() { return std::unique_ptr<renderengine::RenderEngine>(mRenderEngine); });
}
std::unique_ptr<renderengine::threaded::RenderEngineThreaded> mThreadedRE;
diff --git a/libs/renderengine/threaded/RenderEngineThreaded.cpp b/libs/renderengine/threaded/RenderEngineThreaded.cpp
index 367bee89f9..f4cebc05ec 100644
--- a/libs/renderengine/threaded/RenderEngineThreaded.cpp
+++ b/libs/renderengine/threaded/RenderEngineThreaded.cpp
@@ -33,13 +33,12 @@ namespace android {
namespace renderengine {
namespace threaded {
-std::unique_ptr<RenderEngineThreaded> RenderEngineThreaded::create(CreateInstanceFactory factory,
- RenderEngineType type) {
- return std::make_unique<RenderEngineThreaded>(std::move(factory), type);
+std::unique_ptr<RenderEngineThreaded> RenderEngineThreaded::create(CreateInstanceFactory factory) {
+ return std::make_unique<RenderEngineThreaded>(std::move(factory));
}
-RenderEngineThreaded::RenderEngineThreaded(CreateInstanceFactory factory, RenderEngineType type)
- : RenderEngine(type) {
+RenderEngineThreaded::RenderEngineThreaded(CreateInstanceFactory factory)
+ : RenderEngine(Threaded::YES) {
ATRACE_CALL();
std::lock_guard lockThread(mThreadMutex);
@@ -125,8 +124,10 @@ void RenderEngineThreaded::threadMain(CreateInstanceFactory factory) NO_THREAD_S
}
void RenderEngineThreaded::waitUntilInitialized() const {
- std::unique_lock<std::mutex> lock(mInitializedMutex);
- mInitializedCondition.wait(lock, [=] { return mIsInitialized; });
+ if (!mIsInitialized) {
+ std::unique_lock<std::mutex> lock(mInitializedMutex);
+ mInitializedCondition.wait(lock, [this] { return mIsInitialized.load(); });
+ }
}
std::future<void> RenderEngineThreaded::primeCache(bool shouldPrimeUltraHDR) {
diff --git a/libs/renderengine/threaded/RenderEngineThreaded.h b/libs/renderengine/threaded/RenderEngineThreaded.h
index 74af2bd776..d440c961e7 100644
--- a/libs/renderengine/threaded/RenderEngineThreaded.h
+++ b/libs/renderengine/threaded/RenderEngineThreaded.h
@@ -37,10 +37,9 @@ using CreateInstanceFactory = std::function<std::unique_ptr<renderengine::Render
*/
class RenderEngineThreaded : public RenderEngine {
public:
- static std::unique_ptr<RenderEngineThreaded> create(CreateInstanceFactory factory,
- RenderEngineType type);
+ static std::unique_ptr<RenderEngineThreaded> create(CreateInstanceFactory factory);
- RenderEngineThreaded(CreateInstanceFactory factory, RenderEngineType type);
+ RenderEngineThreaded(CreateInstanceFactory factory);
~RenderEngineThreaded() override;
std::future<void> primeCache(bool shouldPrimeUltraHDR) override;
@@ -97,7 +96,7 @@ private:
// Used to allow select thread safe methods to be accessed without requiring the
// method to be invoked on the RenderEngine thread
- bool mIsInitialized = false;
+ std::atomic_bool mIsInitialized = false;
mutable std::mutex mInitializedMutex;
mutable std::condition_variable mInitializedCondition;
diff --git a/libs/sensor/Android.bp b/libs/sensor/Android.bp
index d992aa5105..cc92bc30a0 100644
--- a/libs/sensor/Android.bp
+++ b/libs/sensor/Android.bp
@@ -21,6 +21,18 @@ package {
default_applicable_licenses: ["frameworks_native_license"],
}
+aconfig_declarations {
+ name: "libsensor_flags",
+ package: "com.android.hardware.libsensor.flags",
+ srcs: ["libsensor_flags.aconfig"],
+}
+
+cc_aconfig_library {
+ name: "libsensor_flags_c_lib",
+ host_supported: true,
+ aconfig_declarations: "libsensor_flags",
+}
+
cc_library {
name: "libsensor",
@@ -52,6 +64,10 @@ cc_library {
"android.companion.virtual.virtualdevice_aidl-cpp",
],
+ static_libs: [
+ "libsensor_flags_c_lib",
+ ],
+
export_include_dirs: ["include"],
export_shared_lib_headers: [
diff --git a/libs/sensor/SensorManager.cpp b/libs/sensor/SensorManager.cpp
index d112a1265c..9411e204e9 100644
--- a/libs/sensor/SensorManager.cpp
+++ b/libs/sensor/SensorManager.cpp
@@ -37,6 +37,8 @@
#include <sensor/Sensor.h>
#include <sensor/SensorEventQueue.h>
+#include <com_android_hardware_libsensor_flags.h>
+
// ----------------------------------------------------------------------------
namespace android {
// ----------------------------------------------------------------------------
@@ -88,49 +90,51 @@ SensorManager& SensorManager::getInstanceForPackage(const String16& packageName)
SensorManager* sensorManager;
auto iterator = sPackageInstances.find(packageName);
+ const uid_t uid = IPCThreadState::self()->getCallingUid();
+ const int deviceId = getDeviceIdForUid(uid);
+
+ // Return the cached instance if the device association of the package has not changed.
if (iterator != sPackageInstances.end()) {
sensorManager = iterator->second;
- } else {
- String16 opPackageName = packageName;
- const uid_t uid = IPCThreadState::self()->getCallingUid();
-
- // It is possible that the calling code has no access to the package name.
- // In this case we will get the packages for the calling UID and pick the
- // first one for attributing the app op. This will work correctly for
- // runtime permissions as for legacy apps we will toggle the app op for
- // all packages in the UID. The caveat is that the operation may be attributed
- // to the wrong package and stats based on app ops may be slightly off.
- if (opPackageName.size() <= 0) {
- sp<IBinder> binder = defaultServiceManager()->getService(String16("permission"));
- if (binder != nullptr) {
- Vector<String16> packages;
- interface_cast<IPermissionController>(binder)->getPackagesForUid(uid, packages);
- if (!packages.isEmpty()) {
- opPackageName = packages[0];
- } else {
- ALOGE("No packages for calling UID");
- }
+ if (sensorManager->mDeviceId == deviceId) {
+ return *sensorManager;
+ }
+ }
+
+ // It is possible that the calling code has no access to the package name.
+ // In this case we will get the packages for the calling UID and pick the
+ // first one for attributing the app op. This will work correctly for
+ // runtime permissions as for legacy apps we will toggle the app op for
+ // all packages in the UID. The caveat is that the operation may be attributed
+ // to the wrong package and stats based on app ops may be slightly off.
+ String16 opPackageName = packageName;
+ if (opPackageName.size() <= 0) {
+ sp<IBinder> binder = defaultServiceManager()->getService(String16("permission"));
+ if (binder != nullptr) {
+ Vector<String16> packages;
+ interface_cast<IPermissionController>(binder)->getPackagesForUid(uid, packages);
+ if (!packages.isEmpty()) {
+ opPackageName = packages[0];
} else {
- ALOGE("Cannot get permission service");
+ ALOGE("No packages for calling UID");
}
+ } else {
+ ALOGE("Cannot get permission service");
}
+ }
- // Check if the calling UID is observed on a virtual device. If so, provide that device's
- // sensors by default instead of the default device's sensors.
- const int deviceId = getDeviceIdForUid(uid);
- sensorManager = new SensorManager(opPackageName, deviceId);
-
- // If we had no package name, we looked it up from the UID and the sensor
- // manager instance we created should also be mapped to the empty package
- // name, to avoid looking up the packages for a UID and get the same result.
- if (packageName.size() <= 0) {
- sPackageInstances.insert(std::make_pair(String16(), sensorManager));
- }
+ sensorManager = new SensorManager(opPackageName, deviceId);
- // Stash the per package sensor manager.
- sPackageInstances.insert(std::make_pair(opPackageName, sensorManager));
+ // If we had no package name, we looked it up from the UID and the sensor
+ // manager instance we created should also be mapped to the empty package
+ // name, to avoid looking up the packages for a UID and get the same result.
+ if (packageName.size() <= 0) {
+ sPackageInstances.insert(std::make_pair(String16(), sensorManager));
}
+ // Stash the per package sensor manager.
+ sPackageInstances.insert(std::make_pair(opPackageName, sensorManager));
+
return *sensorManager;
}
@@ -190,6 +194,9 @@ void SensorManager::sensorManagerDied() {
}
status_t SensorManager::assertStateLocked() {
+#if COM_ANDROID_HARDWARE_LIBSENSOR_FLAGS(SENSORMANAGER_PING_BINDER)
+ if (mSensorServer == nullptr) {
+#else
bool initSensorManager = false;
if (mSensorServer == nullptr) {
initSensorManager = true;
@@ -201,6 +208,7 @@ status_t SensorManager::assertStateLocked() {
}
}
if (initSensorManager) {
+#endif
waitForSensorService(&mSensorServer);
LOG_ALWAYS_FATAL_IF(mSensorServer == nullptr, "getService(SensorService) NULL");
@@ -248,6 +256,22 @@ ssize_t SensorManager::getSensorList(Sensor const* const** list) {
return static_cast<ssize_t>(mSensors.size());
}
+ssize_t SensorManager::getDefaultDeviceSensorList(Vector<Sensor> & list) {
+ Mutex::Autolock _l(mLock);
+ status_t err = assertStateLocked();
+ if (err < 0) {
+ return static_cast<ssize_t>(err);
+ }
+
+ if (mDeviceId == DEVICE_ID_DEFAULT) {
+ list = mSensors;
+ } else {
+ list = mSensorServer->getSensorList(mOpPackageName);
+ }
+
+ return static_cast<ssize_t>(list.size());
+}
+
ssize_t SensorManager::getDynamicSensorList(Vector<Sensor> & dynamicSensors) {
Mutex::Autolock _l(mLock);
status_t err = assertStateLocked();
diff --git a/libs/sensor/include/sensor/SensorManager.h b/libs/sensor/include/sensor/SensorManager.h
index e67fac7617..49f050a0ac 100644
--- a/libs/sensor/include/sensor/SensorManager.h
+++ b/libs/sensor/include/sensor/SensorManager.h
@@ -58,6 +58,7 @@ public:
~SensorManager();
ssize_t getSensorList(Sensor const* const** list);
+ ssize_t getDefaultDeviceSensorList(Vector<Sensor> & list);
ssize_t getDynamicSensorList(Vector<Sensor>& list);
ssize_t getDynamicSensorList(Sensor const* const** list);
ssize_t getRuntimeSensorList(int deviceId, Vector<Sensor>& list);
diff --git a/libs/sensor/libsensor_flags.aconfig b/libs/sensor/libsensor_flags.aconfig
new file mode 100644
index 0000000000..ef4d7370b5
--- /dev/null
+++ b/libs/sensor/libsensor_flags.aconfig
@@ -0,0 +1,9 @@
+package: "com.android.hardware.libsensor.flags"
+
+flag {
+ name: "sensormanager_ping_binder"
+ namespace: "sensors"
+ description: "Whether to pingBinder on SensorManager init"
+ bug: "322228259"
+ is_fixed_read_only: true
+} \ No newline at end of file
diff --git a/libs/sensorprivacy/SensorPrivacyManager.cpp b/libs/sensorprivacy/SensorPrivacyManager.cpp
index 57c74ee565..3f3ad9343c 100644
--- a/libs/sensorprivacy/SensorPrivacyManager.cpp
+++ b/libs/sensorprivacy/SensorPrivacyManager.cpp
@@ -108,7 +108,7 @@ bool SensorPrivacyManager::isSensorPrivacyEnabled()
bool SensorPrivacyManager::isToggleSensorPrivacyEnabled(int sensor)
{
- sp<hardware::ISensorPrivacyManager> service = getService();
+ sp<hardware::ISensorPrivacyManager> service = getService();
if (service != nullptr) {
bool result;
service->isCombinedToggleSensorPrivacyEnabled(sensor, &result);
@@ -143,6 +143,38 @@ status_t SensorPrivacyManager::isToggleSensorPrivacyEnabled(int toggleType, int
return UNKNOWN_ERROR;
}
+int SensorPrivacyManager::getToggleSensorPrivacyState(int toggleType, int sensor)
+{
+ sp<hardware::ISensorPrivacyManager> service = getService();
+ if (service != nullptr) {
+ int result;
+ service->getToggleSensorPrivacyState(toggleType, sensor, &result);
+ return result;
+ }
+ // if the SensorPrivacyManager is not available then assume sensor privacy is disabled
+ return DISABLED;
+}
+
+std::vector<String16> SensorPrivacyManager::getCameraPrivacyAllowlist(){
+ sp<hardware::ISensorPrivacyManager> service = getService();
+ std::vector<String16> result;
+ if (service != nullptr) {
+ service->getCameraPrivacyAllowlist(&result);
+ return result;
+ }
+ return result;
+}
+
+bool SensorPrivacyManager::isCameraPrivacyEnabled(String16 packageName){
+ sp<hardware::ISensorPrivacyManager> service = getService();
+ if (service != nullptr) {
+ bool result;
+ service->isCameraPrivacyEnabled(packageName, &result);
+ return result;
+ }
+ return false;
+}
+
status_t SensorPrivacyManager::linkToDeath(const sp<IBinder::DeathRecipient>& recipient)
{
sp<hardware::ISensorPrivacyManager> service = getService();
diff --git a/libs/sensorprivacy/aidl/android/hardware/ISensorPrivacyListener.aidl b/libs/sensorprivacy/aidl/android/hardware/ISensorPrivacyListener.aidl
index eccd54c3eb..694af00a87 100644
--- a/libs/sensorprivacy/aidl/android/hardware/ISensorPrivacyListener.aidl
+++ b/libs/sensorprivacy/aidl/android/hardware/ISensorPrivacyListener.aidl
@@ -21,4 +21,5 @@ package android.hardware;
*/
oneway interface ISensorPrivacyListener {
void onSensorPrivacyChanged(int toggleType, int sensor, boolean enabled);
+ void onSensorPrivacyStateChanged(int toggleType, int sensor, int state);
}
diff --git a/libs/sensorprivacy/aidl/android/hardware/ISensorPrivacyManager.aidl b/libs/sensorprivacy/aidl/android/hardware/ISensorPrivacyManager.aidl
index 49a1e1ea05..f7071872bf 100644
--- a/libs/sensorprivacy/aidl/android/hardware/ISensorPrivacyManager.aidl
+++ b/libs/sensorprivacy/aidl/android/hardware/ISensorPrivacyManager.aidl
@@ -41,4 +41,15 @@ interface ISensorPrivacyManager {
void setToggleSensorPrivacy(int userId, int source, int sensor, boolean enable);
void setToggleSensorPrivacyForProfileGroup(int userId, int source, int sensor, boolean enable);
+
+ List<String> getCameraPrivacyAllowlist();
+
+ int getToggleSensorPrivacyState(int toggleType, int sensor);
+
+ void setToggleSensorPrivacyState(int userId, int source, int sensor, int state);
+
+ void setToggleSensorPrivacyStateForProfileGroup(int userId, int source, int sensor, int state);
+
+ boolean isCameraPrivacyEnabled(String packageName);
+
}
diff --git a/libs/sensorprivacy/include/sensorprivacy/SensorPrivacyManager.h b/libs/sensorprivacy/include/sensorprivacy/SensorPrivacyManager.h
index fc5fdf7900..8935b76adc 100644
--- a/libs/sensorprivacy/include/sensorprivacy/SensorPrivacyManager.h
+++ b/libs/sensorprivacy/include/sensorprivacy/SensorPrivacyManager.h
@@ -32,12 +32,20 @@ class SensorPrivacyManager
public:
enum {
TOGGLE_SENSOR_MICROPHONE = 1,
- TOGGLE_SENSOR_CAMERA = 2
+ TOGGLE_SENSOR_CAMERA = 2,
+ TOGGLE_SENSOR_UNKNOWN = -1
};
enum {
TOGGLE_TYPE_SOFTWARE = 1,
- TOGGLE_TYPE_HARDWARE = 2
+ TOGGLE_TYPE_HARDWARE = 2,
+ TOGGLE_TYPE_UNKNOWN = -1
+ };
+
+ enum {
+ ENABLED = 1,
+ DISABLED = 2,
+ ENABLED_EXCEPT_ALLOWLISTED_APPS = 3
};
SensorPrivacyManager();
@@ -51,6 +59,9 @@ public:
bool isToggleSensorPrivacyEnabled(int sensor);
bool isToggleSensorPrivacyEnabled(int toggleType, int sensor);
status_t isToggleSensorPrivacyEnabled(int toggleType, int sensor, bool &result);
+ int getToggleSensorPrivacyState(int toggleType, int sensor);
+ std::vector<String16> getCameraPrivacyAllowlist();
+ bool isCameraPrivacyEnabled(String16 packageName);
status_t linkToDeath(const sp<IBinder::DeathRecipient>& recipient);
status_t unlinkToDeath(const sp<IBinder::DeathRecipient>& recipient);
diff --git a/libs/shaders/Android.bp b/libs/shaders/Android.bp
index 960f845488..82fbfda0da 100644
--- a/libs/shaders/Android.bp
+++ b/libs/shaders/Android.bp
@@ -19,6 +19,7 @@ package {
// to get the below license kinds:
// SPDX-license-identifier-Apache-2.0
default_applicable_licenses: ["frameworks_native_license"],
+ default_team: "trendy_team_android_core_graphics_stack",
}
cc_library_static {
diff --git a/libs/shaders/tests/Android.bp b/libs/shaders/tests/Android.bp
index 5639d744df..2103679efe 100644
--- a/libs/shaders/tests/Android.bp
+++ b/libs/shaders/tests/Android.bp
@@ -19,6 +19,7 @@ package {
// to get the below license kinds:
// SPDX-license-identifier-Apache-2.0
default_applicable_licenses: ["frameworks_native_license"],
+ default_team: "trendy_team_android_core_graphics_stack",
}
cc_test {
diff --git a/libs/tonemap/Android.bp b/libs/tonemap/Android.bp
index 8c8815d0e4..d569ac3ba6 100644
--- a/libs/tonemap/Android.bp
+++ b/libs/tonemap/Android.bp
@@ -19,6 +19,7 @@ package {
// to get the below license kinds:
// SPDX-license-identifier-Apache-2.0
default_applicable_licenses: ["frameworks_native_license"],
+ default_team: "trendy_team_android_core_graphics_stack",
}
cc_library_static {
diff --git a/libs/tonemap/tests/Android.bp b/libs/tonemap/tests/Android.bp
index 5c5fc6c8b3..79ee7c2de9 100644
--- a/libs/tonemap/tests/Android.bp
+++ b/libs/tonemap/tests/Android.bp
@@ -19,6 +19,7 @@ package {
// to get the below license kinds:
// SPDX-license-identifier-Apache-2.0
default_applicable_licenses: ["frameworks_native_license"],
+ default_team: "trendy_team_android_core_graphics_stack",
}
cc_test {
diff --git a/libs/tracing_perfetto/.clang-format b/libs/tracing_perfetto/.clang-format
new file mode 100644
index 0000000000..f3974548f6
--- /dev/null
+++ b/libs/tracing_perfetto/.clang-format
@@ -0,0 +1,12 @@
+BasedOnStyle: Google
+AllowShortBlocksOnASingleLine: false
+AllowShortFunctionsOnASingleLine: false
+
+ColumnLimit: 80
+ContinuationIndentWidth: 4
+CommentPragmas: NOLINT:.*
+DerivePointerAlignment: false
+IndentWidth: 2
+PointerAlignment: Left
+UseTab: Never
+PenaltyExcessCharacter: 32 \ No newline at end of file
diff --git a/libs/tracing_perfetto/Android.bp b/libs/tracing_perfetto/Android.bp
new file mode 100644
index 0000000000..3a4c869e46
--- /dev/null
+++ b/libs/tracing_perfetto/Android.bp
@@ -0,0 +1,49 @@
+// Copyright 2024 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 {
+ // 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: "libtracing_perfetto",
+ export_include_dirs: [
+ "include",
+ ],
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wno-enum-compare",
+ "-Wno-unused-function",
+ ],
+
+ srcs: [
+ "tracing_perfetto.cpp",
+ "tracing_perfetto_internal.cpp",
+ ],
+
+ shared_libs: [
+ "libcutils",
+ "libperfetto_c",
+ "android.os.flags-aconfig-cc-host",
+ ],
+
+ host_supported: true,
+}
diff --git a/libs/tracing_perfetto/OWNERS b/libs/tracing_perfetto/OWNERS
new file mode 100644
index 0000000000..e2d4b4636a
--- /dev/null
+++ b/libs/tracing_perfetto/OWNERS
@@ -0,0 +1,2 @@
+zezeozue@google.com
+biswarupp@google.com \ No newline at end of file
diff --git a/libs/tracing_perfetto/include/trace_categories.h b/libs/tracing_perfetto/include/trace_categories.h
new file mode 100644
index 0000000000..6d4168b772
--- /dev/null
+++ b/libs/tracing_perfetto/include/trace_categories.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2024 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 TRACE_CATEGORIES_H
+#define TRACE_CATEGORIES_H
+
+/**
+ * Keep these in sync with frameworks/base/core/java/android/os/Trace.java.
+ */
+#define TRACE_CATEGORY_ALWAYS (1 << 0)
+#define TRACE_CATEGORY_GRAPHICS (1 << 1)
+#define TRACE_CATEGORY_INPUT (1 << 2)
+#define TRACE_CATEGORY_VIEW (1 << 3)
+#define TRACE_CATEGORY_WEBVIEW (1 << 4)
+#define TRACE_CATEGORY_WINDOW_MANAGER (1 << 5)
+#define TRACE_CATEGORY_ACTIVITY_MANAGER (1 << 6)
+#define TRACE_CATEGORY_SYNC_MANAGER (1 << 7)
+#define TRACE_CATEGORY_AUDIO (1 << 8)
+#define TRACE_CATEGORY_VIDEO (1 << 9)
+#define TRACE_CATEGORY_CAMERA (1 << 10)
+#define TRACE_CATEGORY_HAL (1 << 11)
+#define TRACE_CATEGORY_APP (1 << 12)
+#define TRACE_CATEGORY_RESOURCES (1 << 13)
+#define TRACE_CATEGORY_DALVIK (1 << 14)
+#define TRACE_CATEGORY_RS (1 << 15)
+#define TRACE_CATEGORY_BIONIC (1 << 16)
+#define TRACE_CATEGORY_POWER (1 << 17)
+#define TRACE_CATEGORY_PACKAGE_MANAGER (1 << 18)
+#define TRACE_CATEGORY_SYSTEM_SERVER (1 << 19)
+#define TRACE_CATEGORY_DATABASE (1 << 20)
+#define TRACE_CATEGORY_NETWORK (1 << 21)
+#define TRACE_CATEGORY_ADB (1 << 22)
+#define TRACE_CATEGORY_VIBRATOR (1 << 23)
+#define TRACE_CATEGORY_AIDL (1 << 24)
+#define TRACE_CATEGORY_NNAPI (1 << 25)
+#define TRACE_CATEGORY_RRO (1 << 26)
+#define TRACE_CATEGORY_THERMAL (1 << 27)
+
+// Allow all categories except TRACE_CATEGORY_APP
+#define TRACE_CATEGORIES \
+ TRACE_CATEGORY_ALWAYS | TRACE_CATEGORY_GRAPHICS | TRACE_CATEGORY_INPUT | \
+ TRACE_CATEGORY_VIEW | TRACE_CATEGORY_WEBVIEW | \
+ TRACE_CATEGORY_WINDOW_MANAGER | TRACE_CATEGORY_ACTIVITY_MANAGER | \
+ TRACE_CATEGORY_SYNC_MANAGER | TRACE_CATEGORY_AUDIO | \
+ TRACE_CATEGORY_VIDEO | TRACE_CATEGORY_CAMERA | TRACE_CATEGORY_HAL | \
+ TRACE_CATEGORY_RESOURCES | TRACE_CATEGORY_DALVIK | TRACE_CATEGORY_RS | \
+ TRACE_CATEGORY_BIONIC | TRACE_CATEGORY_POWER | \
+ TRACE_CATEGORY_PACKAGE_MANAGER | TRACE_CATEGORY_SYSTEM_SERVER | \
+ TRACE_CATEGORY_DATABASE | TRACE_CATEGORY_NETWORK | TRACE_CATEGORY_ADB | \
+ TRACE_CATEGORY_VIBRATOR | TRACE_CATEGORY_AIDL | TRACE_CATEGORY_NNAPI | \
+ TRACE_CATEGORY_RRO | TRACE_CATEGORY_THERMAL
+#endif // TRACE_CATEGORIES_H
diff --git a/libs/tracing_perfetto/include/trace_result.h b/libs/tracing_perfetto/include/trace_result.h
new file mode 100644
index 0000000000..f7581fc0fb
--- /dev/null
+++ b/libs/tracing_perfetto/include/trace_result.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2024 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 TRACE_RESULT_H
+#define TRACE_RESULT_H
+
+namespace tracing_perfetto {
+
+enum class Result {
+ SUCCESS,
+ NOT_SUPPORTED,
+ INVALID_INPUT,
+};
+
+}
+
+#endif // TRACE_RESULT_H
diff --git a/libs/tracing_perfetto/include/tracing_perfetto.h b/libs/tracing_perfetto/include/tracing_perfetto.h
new file mode 100644
index 0000000000..4e3c83fca3
--- /dev/null
+++ b/libs/tracing_perfetto/include/tracing_perfetto.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2024 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 TRACING_PERFETTO_H
+#define TRACING_PERFETTO_H
+
+#include <stdint.h>
+
+#include "trace_result.h"
+
+namespace tracing_perfetto {
+
+void registerWithPerfetto(bool test = false);
+
+Result traceBegin(uint64_t category, const char* name);
+
+Result traceEnd(uint64_t category);
+
+Result traceAsyncBegin(uint64_t category, const char* name, int32_t cookie);
+
+Result traceAsyncEnd(uint64_t category, const char* name, int32_t cookie);
+
+Result traceAsyncBeginForTrack(uint64_t category, const char* name,
+ const char* trackName, int32_t cookie);
+
+Result traceAsyncEndForTrack(uint64_t category, const char* trackName,
+ int32_t cookie);
+
+Result traceInstant(uint64_t category, const char* name);
+
+Result traceInstantForTrack(uint64_t category, const char* trackName,
+ const char* name);
+
+Result traceCounter(uint64_t category, const char* name, int64_t value);
+
+uint64_t getEnabledCategories();
+
+} // namespace tracing_perfetto
+
+#endif // TRACING_PERFETTO_H
diff --git a/libs/tracing_perfetto/tests/Android.bp b/libs/tracing_perfetto/tests/Android.bp
new file mode 100644
index 0000000000..a35b0e0c83
--- /dev/null
+++ b/libs/tracing_perfetto/tests/Android.bp
@@ -0,0 +1,45 @@
+// Copyright 2024 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 {
+ // 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: "libtracing_perfetto_tests",
+ static_libs: [
+ "libflagtest",
+ "libgmock",
+ ],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+ shared_libs: [
+ "android.os.flags-aconfig-cc-host",
+ "libbase",
+ "libperfetto_c",
+ "libtracing_perfetto",
+ ],
+ srcs: [
+ "tracing_perfetto_test.cpp",
+ "utils.cpp",
+ ],
+ test_suites: ["device-tests"],
+}
diff --git a/libs/tracing_perfetto/tests/tracing_perfetto_test.cpp b/libs/tracing_perfetto/tests/tracing_perfetto_test.cpp
new file mode 100644
index 0000000000..7716b9a316
--- /dev/null
+++ b/libs/tracing_perfetto/tests/tracing_perfetto_test.cpp
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2024 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 "tracing_perfetto.h"
+
+#include <thread>
+
+#include <android_os.h>
+#include <flag_macros.h>
+
+#include "gtest/gtest.h"
+#include "perfetto/public/abi/data_source_abi.h"
+#include "perfetto/public/abi/heap_buffer.h"
+#include "perfetto/public/abi/pb_decoder_abi.h"
+#include "perfetto/public/abi/tracing_session_abi.h"
+#include "perfetto/public/abi/track_event_abi.h"
+#include "perfetto/public/data_source.h"
+#include "perfetto/public/pb_decoder.h"
+#include "perfetto/public/producer.h"
+#include "perfetto/public/protos/config/trace_config.pzc.h"
+#include "perfetto/public/protos/trace/interned_data/interned_data.pzc.h"
+#include "perfetto/public/protos/trace/test_event.pzc.h"
+#include "perfetto/public/protos/trace/trace.pzc.h"
+#include "perfetto/public/protos/trace/trace_packet.pzc.h"
+#include "perfetto/public/protos/trace/track_event/debug_annotation.pzc.h"
+#include "perfetto/public/protos/trace/track_event/track_descriptor.pzc.h"
+#include "perfetto/public/protos/trace/track_event/track_event.pzc.h"
+#include "perfetto/public/protos/trace/trigger.pzc.h"
+#include "perfetto/public/te_category_macros.h"
+#include "perfetto/public/te_macros.h"
+#include "perfetto/public/track_event.h"
+#include "trace_categories.h"
+#include "utils.h"
+
+namespace tracing_perfetto {
+
+using ::perfetto::shlib::test_utils::AllFieldsWithId;
+using ::perfetto::shlib::test_utils::FieldView;
+using ::perfetto::shlib::test_utils::IdFieldView;
+using ::perfetto::shlib::test_utils::MsgField;
+using ::perfetto::shlib::test_utils::PbField;
+using ::perfetto::shlib::test_utils::StringField;
+using ::perfetto::shlib::test_utils::TracingSession;
+using ::perfetto::shlib::test_utils::VarIntField;
+using ::testing::_;
+using ::testing::ElementsAre;
+using ::testing::UnorderedElementsAre;
+
+const auto PERFETTO_SDK_TRACING = ACONFIG_FLAG(android::os, perfetto_sdk_tracing);
+
+class TracingPerfettoTest : public testing::Test {
+ protected:
+ void SetUp() override {
+ tracing_perfetto::registerWithPerfetto(true /* test */);
+ }
+};
+
+// TODO(b/303199244): Add tests for all the library functions.
+
+TEST_F_WITH_FLAGS(TracingPerfettoTest, traceInstant,
+ REQUIRES_FLAGS_ENABLED(PERFETTO_SDK_TRACING)) {
+ TracingSession tracing_session =
+ TracingSession::Builder().set_data_source_name("track_event").Build();
+ tracing_perfetto::traceInstant(TRACE_CATEGORY_INPUT, "");
+
+ tracing_session.StopBlocking();
+ std::vector<uint8_t> data = tracing_session.ReadBlocking();
+ bool found = false;
+ for (struct PerfettoPbDecoderField trace_field : FieldView(data)) {
+ ASSERT_THAT(trace_field, PbField(perfetto_protos_Trace_packet_field_number,
+ MsgField(_)));
+ IdFieldView track_event(
+ trace_field, perfetto_protos_TracePacket_track_event_field_number);
+ if (track_event.size() == 0) {
+ continue;
+ }
+ found = true;
+ IdFieldView cat_iid_fields(
+ track_event.front(),
+ perfetto_protos_TrackEvent_category_iids_field_number);
+ ASSERT_THAT(cat_iid_fields, ElementsAre(VarIntField(_)));
+ uint64_t cat_iid = cat_iid_fields.front().value.integer64;
+ EXPECT_THAT(
+ trace_field,
+ AllFieldsWithId(
+ perfetto_protos_TracePacket_interned_data_field_number,
+ ElementsAre(AllFieldsWithId(
+ perfetto_protos_InternedData_event_categories_field_number,
+ ElementsAre(MsgField(UnorderedElementsAre(
+ PbField(perfetto_protos_EventCategory_iid_field_number,
+ VarIntField(cat_iid)),
+ PbField(perfetto_protos_EventCategory_name_field_number,
+ StringField("input")))))))));
+ }
+ EXPECT_TRUE(found);
+}
+
+} // namespace tracing_perfetto \ No newline at end of file
diff --git a/libs/tracing_perfetto/tests/utils.cpp b/libs/tracing_perfetto/tests/utils.cpp
new file mode 100644
index 0000000000..9c4202808a
--- /dev/null
+++ b/libs/tracing_perfetto/tests/utils.cpp
@@ -0,0 +1,219 @@
+/*
+ * Copyright 2024 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.
+ */
+
+// Copied from //external/perfetto/src/shared_lib/test/utils.cc
+
+#include "utils.h"
+
+#include "perfetto/public/abi/heap_buffer.h"
+#include "perfetto/public/pb_msg.h"
+#include "perfetto/public/pb_utils.h"
+#include "perfetto/public/protos/config/data_source_config.pzc.h"
+#include "perfetto/public/protos/config/trace_config.pzc.h"
+#include "perfetto/public/protos/config/track_event/track_event_config.pzc.h"
+#include "perfetto/public/tracing_session.h"
+
+namespace perfetto {
+namespace shlib {
+namespace test_utils {
+namespace {
+
+std::string ToHexChars(uint8_t val) {
+ std::string ret;
+ uint8_t high_nibble = (val & 0xF0) >> 4;
+ uint8_t low_nibble = (val & 0xF);
+ static const char hex_chars[] = "0123456789ABCDEF";
+ ret.push_back(hex_chars[high_nibble]);
+ ret.push_back(hex_chars[low_nibble]);
+ return ret;
+}
+
+} // namespace
+
+TracingSession TracingSession::Builder::Build() {
+ struct PerfettoPbMsgWriter writer;
+ struct PerfettoHeapBuffer* hb = PerfettoHeapBufferCreate(&writer.writer);
+
+ struct perfetto_protos_TraceConfig cfg;
+ PerfettoPbMsgInit(&cfg.msg, &writer);
+
+ {
+ struct perfetto_protos_TraceConfig_BufferConfig buffers;
+ perfetto_protos_TraceConfig_begin_buffers(&cfg, &buffers);
+
+ perfetto_protos_TraceConfig_BufferConfig_set_size_kb(&buffers, 1024);
+
+ perfetto_protos_TraceConfig_end_buffers(&cfg, &buffers);
+ }
+
+ {
+ struct perfetto_protos_TraceConfig_DataSource data_sources;
+ perfetto_protos_TraceConfig_begin_data_sources(&cfg, &data_sources);
+
+ {
+ struct perfetto_protos_DataSourceConfig ds_cfg;
+ perfetto_protos_TraceConfig_DataSource_begin_config(&data_sources,
+ &ds_cfg);
+
+ perfetto_protos_DataSourceConfig_set_cstr_name(&ds_cfg,
+ data_source_name_.c_str());
+ if (!enabled_categories_.empty() && !disabled_categories_.empty()) {
+ perfetto_protos_TrackEventConfig te_cfg;
+ perfetto_protos_DataSourceConfig_begin_track_event_config(&ds_cfg,
+ &te_cfg);
+ for (const std::string& cat : enabled_categories_) {
+ perfetto_protos_TrackEventConfig_set_enabled_categories(
+ &te_cfg, cat.data(), cat.size());
+ }
+ for (const std::string& cat : disabled_categories_) {
+ perfetto_protos_TrackEventConfig_set_disabled_categories(
+ &te_cfg, cat.data(), cat.size());
+ }
+ perfetto_protos_DataSourceConfig_end_track_event_config(&ds_cfg,
+ &te_cfg);
+ }
+
+ perfetto_protos_TraceConfig_DataSource_end_config(&data_sources, &ds_cfg);
+ }
+
+ perfetto_protos_TraceConfig_end_data_sources(&cfg, &data_sources);
+ }
+ size_t cfg_size = PerfettoStreamWriterGetWrittenSize(&writer.writer);
+ std::unique_ptr<uint8_t[]> ser(new uint8_t[cfg_size]);
+ PerfettoHeapBufferCopyInto(hb, &writer.writer, ser.get(), cfg_size);
+ PerfettoHeapBufferDestroy(hb, &writer.writer);
+
+ struct PerfettoTracingSessionImpl* ts =
+ PerfettoTracingSessionCreate(PERFETTO_BACKEND_IN_PROCESS);
+
+ PerfettoTracingSessionSetup(ts, ser.get(), cfg_size);
+
+ PerfettoTracingSessionStartBlocking(ts);
+
+ return TracingSession::Adopt(ts);
+}
+
+TracingSession TracingSession::Adopt(struct PerfettoTracingSessionImpl* session) {
+ TracingSession ret;
+ ret.session_ = session;
+ ret.stopped_ = std::make_unique<WaitableEvent>();
+ PerfettoTracingSessionSetStopCb(
+ ret.session_,
+ [](struct PerfettoTracingSessionImpl*, void* arg) {
+ static_cast<WaitableEvent*>(arg)->Notify();
+ },
+ ret.stopped_.get());
+ return ret;
+}
+
+TracingSession::TracingSession(TracingSession&& other) noexcept {
+ session_ = other.session_;
+ other.session_ = nullptr;
+ stopped_ = std::move(other.stopped_);
+ other.stopped_ = nullptr;
+}
+
+TracingSession::~TracingSession() {
+ if (!session_) {
+ return;
+ }
+ if (!stopped_->IsNotified()) {
+ PerfettoTracingSessionStopBlocking(session_);
+ stopped_->WaitForNotification();
+ }
+ PerfettoTracingSessionDestroy(session_);
+}
+
+bool TracingSession::FlushBlocking(uint32_t timeout_ms) {
+ WaitableEvent notification;
+ bool result;
+ auto* cb = new std::function<void(bool)>([&](bool success) {
+ result = success;
+ notification.Notify();
+ });
+ PerfettoTracingSessionFlushAsync(
+ session_, timeout_ms,
+ [](PerfettoTracingSessionImpl*, bool success, void* user_arg) {
+ auto* f = reinterpret_cast<std::function<void(bool)>*>(user_arg);
+ (*f)(success);
+ delete f;
+ },
+ cb);
+ notification.WaitForNotification();
+ return result;
+}
+
+void TracingSession::WaitForStopped() {
+ stopped_->WaitForNotification();
+}
+
+void TracingSession::StopBlocking() {
+ PerfettoTracingSessionStopBlocking(session_);
+}
+
+std::vector<uint8_t> TracingSession::ReadBlocking() {
+ std::vector<uint8_t> data;
+ PerfettoTracingSessionReadTraceBlocking(
+ session_,
+ [](struct PerfettoTracingSessionImpl*, const void* trace_data,
+ size_t size, bool, void* user_arg) {
+ auto& dst = *static_cast<std::vector<uint8_t>*>(user_arg);
+ auto* src = static_cast<const uint8_t*>(trace_data);
+ dst.insert(dst.end(), src, src + size);
+ },
+ &data);
+ return data;
+}
+
+} // namespace test_utils
+} // namespace shlib
+} // namespace perfetto
+
+void PrintTo(const PerfettoPbDecoderField& field, std::ostream* pos) {
+ std::ostream& os = *pos;
+ PerfettoPbDecoderStatus status =
+ static_cast<PerfettoPbDecoderStatus>(field.status);
+ switch (status) {
+ case PERFETTO_PB_DECODER_ERROR:
+ os << "MALFORMED PROTOBUF";
+ break;
+ case PERFETTO_PB_DECODER_DONE:
+ os << "DECODER DONE";
+ break;
+ case PERFETTO_PB_DECODER_OK:
+ switch (field.wire_type) {
+ case PERFETTO_PB_WIRE_TYPE_DELIMITED:
+ os << "\"";
+ for (size_t i = 0; i < field.value.delimited.len; i++) {
+ os << perfetto::shlib::test_utils::ToHexChars(
+ field.value.delimited.start[i])
+ << " ";
+ }
+ os << "\"";
+ break;
+ case PERFETTO_PB_WIRE_TYPE_VARINT:
+ os << "varint: " << field.value.integer64;
+ break;
+ case PERFETTO_PB_WIRE_TYPE_FIXED32:
+ os << "fixed32: " << field.value.integer32;
+ break;
+ case PERFETTO_PB_WIRE_TYPE_FIXED64:
+ os << "fixed64: " << field.value.integer64;
+ break;
+ }
+ break;
+ }
+}
diff --git a/libs/tracing_perfetto/tests/utils.h b/libs/tracing_perfetto/tests/utils.h
new file mode 100644
index 0000000000..4353554963
--- /dev/null
+++ b/libs/tracing_perfetto/tests/utils.h
@@ -0,0 +1,452 @@
+/*
+ * Copyright 2024 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.
+ */
+
+// Copied from //external/perfetto/src/shared_lib/test/utils.h
+
+#ifndef UTILS_H
+#define UTILS_H
+
+#include <cassert>
+#include <condition_variable>
+#include <cstdint>
+#include <functional>
+#include <iterator>
+#include <memory>
+#include <mutex>
+#include <ostream>
+#include <string>
+#include <vector>
+
+#include "gmock/gmock-matchers.h"
+#include "gmock/gmock-more-matchers.h"
+#include "gtest/gtest-matchers.h"
+#include "gtest/gtest.h"
+#include "perfetto/public/abi/pb_decoder_abi.h"
+#include "perfetto/public/pb_utils.h"
+#include "perfetto/public/tracing_session.h"
+
+// Pretty printer for gtest
+void PrintTo(const PerfettoPbDecoderField& field, std::ostream*);
+
+namespace perfetto {
+namespace shlib {
+namespace test_utils {
+
+class WaitableEvent {
+ public:
+ WaitableEvent() = default;
+ void Notify() {
+ std::unique_lock<std::mutex> lock(m_);
+ notified_ = true;
+ cv_.notify_one();
+ }
+ bool WaitForNotification() {
+ std::unique_lock<std::mutex> lock(m_);
+ cv_.wait(lock, [this] { return notified_; });
+ return notified_;
+ }
+ bool IsNotified() {
+ std::unique_lock<std::mutex> lock(m_);
+ return notified_;
+ }
+
+ private:
+ std::mutex m_;
+ std::condition_variable cv_;
+ bool notified_ = false;
+};
+
+class TracingSession {
+ public:
+ class Builder {
+ public:
+ Builder() = default;
+ Builder& set_data_source_name(std::string data_source_name) {
+ data_source_name_ = std::move(data_source_name);
+ return *this;
+ }
+ Builder& add_enabled_category(std::string category) {
+ enabled_categories_.push_back(std::move(category));
+ return *this;
+ }
+ Builder& add_disabled_category(std::string category) {
+ disabled_categories_.push_back(std::move(category));
+ return *this;
+ }
+ TracingSession Build();
+
+ private:
+ std::string data_source_name_;
+ std::vector<std::string> enabled_categories_;
+ std::vector<std::string> disabled_categories_;
+ };
+
+ static TracingSession Adopt(struct PerfettoTracingSessionImpl*);
+
+ TracingSession(TracingSession&&) noexcept;
+
+ ~TracingSession();
+
+ struct PerfettoTracingSessionImpl* session() const {
+ return session_;
+ }
+
+ bool FlushBlocking(uint32_t timeout_ms);
+ void WaitForStopped();
+ void StopBlocking();
+ std::vector<uint8_t> ReadBlocking();
+
+ private:
+ TracingSession() = default;
+ struct PerfettoTracingSessionImpl* session_;
+ std::unique_ptr<WaitableEvent> stopped_;
+};
+
+template <typename FieldSkipper>
+class FieldViewBase {
+ public:
+ class Iterator {
+ public:
+ using iterator_category = std::input_iterator_tag;
+ using value_type = const PerfettoPbDecoderField;
+ using pointer = value_type;
+ using reference = value_type;
+ reference operator*() const {
+ struct PerfettoPbDecoder decoder;
+ decoder.read_ptr = read_ptr_;
+ decoder.end_ptr = end_ptr_;
+ struct PerfettoPbDecoderField field;
+ do {
+ field = PerfettoPbDecoderParseField(&decoder);
+ } while (field.status == PERFETTO_PB_DECODER_OK &&
+ skipper_.ShouldSkip(field));
+ return field;
+ }
+ Iterator& operator++() {
+ struct PerfettoPbDecoder decoder;
+ decoder.read_ptr = read_ptr_;
+ decoder.end_ptr = end_ptr_;
+ PerfettoPbDecoderSkipField(&decoder);
+ read_ptr_ = decoder.read_ptr;
+ AdvanceToFirstInterestingField();
+ return *this;
+ }
+ Iterator operator++(int) {
+ Iterator tmp = *this;
+ ++(*this);
+ return tmp;
+ }
+
+ friend bool operator==(const Iterator& a, const Iterator& b) {
+ return a.read_ptr_ == b.read_ptr_;
+ }
+ friend bool operator!=(const Iterator& a, const Iterator& b) {
+ return a.read_ptr_ != b.read_ptr_;
+ }
+
+ private:
+ Iterator(const uint8_t* read_ptr, const uint8_t* end_ptr,
+ const FieldSkipper& skipper)
+ : read_ptr_(read_ptr), end_ptr_(end_ptr), skipper_(skipper) {
+ AdvanceToFirstInterestingField();
+ }
+ void AdvanceToFirstInterestingField() {
+ struct PerfettoPbDecoder decoder;
+ decoder.read_ptr = read_ptr_;
+ decoder.end_ptr = end_ptr_;
+ struct PerfettoPbDecoderField field;
+ const uint8_t* prev_read_ptr;
+ do {
+ prev_read_ptr = decoder.read_ptr;
+ field = PerfettoPbDecoderParseField(&decoder);
+ } while (field.status == PERFETTO_PB_DECODER_OK &&
+ skipper_.ShouldSkip(field));
+ if (field.status == PERFETTO_PB_DECODER_OK) {
+ read_ptr_ = prev_read_ptr;
+ } else {
+ read_ptr_ = decoder.read_ptr;
+ }
+ }
+ friend class FieldViewBase<FieldSkipper>;
+ const uint8_t* read_ptr_;
+ const uint8_t* end_ptr_;
+ const FieldSkipper& skipper_;
+ };
+ using value_type = const PerfettoPbDecoderField;
+ using const_iterator = Iterator;
+ template <typename... Args>
+ explicit FieldViewBase(const uint8_t* begin, const uint8_t* end, Args... args)
+ : begin_(begin), end_(end), s_(args...) {
+ }
+ template <typename... Args>
+ explicit FieldViewBase(const std::vector<uint8_t>& data, Args... args)
+ : FieldViewBase(data.data(), data.data() + data.size(), args...) {
+ }
+ template <typename... Args>
+ explicit FieldViewBase(const struct PerfettoPbDecoderField& field,
+ Args... args)
+ : s_(args...) {
+ if (field.wire_type != PERFETTO_PB_WIRE_TYPE_DELIMITED) {
+ abort();
+ }
+ begin_ = field.value.delimited.start;
+ end_ = begin_ + field.value.delimited.len;
+ }
+ Iterator begin() const {
+ return Iterator(begin_, end_, s_);
+ }
+ Iterator end() const {
+ return Iterator(end_, end_, s_);
+ }
+ PerfettoPbDecoderField front() const {
+ return *begin();
+ }
+
+ size_t size() const {
+ size_t count = 0;
+ for (auto field : *this) {
+ (void)field;
+ count++;
+ }
+ return count;
+ }
+
+ bool ok() const {
+ for (auto field : *this) {
+ if (field.status != PERFETTO_PB_DECODER_OK) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private:
+ const uint8_t* begin_;
+ const uint8_t* end_;
+ FieldSkipper s_;
+};
+
+// Pretty printer for gtest
+template <typename FieldSkipper>
+void PrintTo(const FieldViewBase<FieldSkipper>& field_view, std::ostream* pos) {
+ std::ostream& os = *pos;
+ os << "{";
+ for (PerfettoPbDecoderField f : field_view) {
+ PrintTo(f, pos);
+ os << ", ";
+ }
+ os << "}";
+}
+
+class IdFieldSkipper {
+ public:
+ explicit IdFieldSkipper(uint32_t id) : id_(id) {
+ }
+ explicit IdFieldSkipper(int32_t id) : id_(static_cast<uint32_t>(id)) {
+ }
+ bool ShouldSkip(const struct PerfettoPbDecoderField& field) const {
+ return field.id != id_;
+ }
+
+ private:
+ uint32_t id_;
+};
+
+class NoFieldSkipper {
+ public:
+ NoFieldSkipper() = default;
+ bool ShouldSkip(const struct PerfettoPbDecoderField&) const {
+ return false;
+ }
+};
+
+// View over all the fields of a contiguous serialized protobuf message.
+//
+// Examples:
+//
+// for (struct PerfettoPbDecoderField field : FieldView(msg_begin, msg_end)) {
+// //...
+// }
+// FieldView fields2(/*PerfettoPbDecoderField*/ nested_field);
+// FieldView fields3(/*std::vector<uint8_t>*/ data);
+// size_t num = fields1.size(); // The number of fields.
+// bool ok = fields1.ok(); // Checks that the message is not malformed.
+using FieldView = FieldViewBase<NoFieldSkipper>;
+
+// Like `FieldView`, but only considers fields with a specific id.
+//
+// Examples:
+//
+// IdFieldView fields(msg_begin, msg_end, id)
+using IdFieldView = FieldViewBase<IdFieldSkipper>;
+
+// Matches a PerfettoPbDecoderField with the specified id. Accepts another
+// matcher to match the contents of the field.
+//
+// Example:
+// PerfettoPbDecoderField field = ...
+// EXPECT_THAT(field, PbField(900, VarIntField(5)));
+template <typename M>
+auto PbField(int32_t id, M m) {
+ return testing::AllOf(
+ testing::Field(&PerfettoPbDecoderField::status, PERFETTO_PB_DECODER_OK),
+ testing::Field(&PerfettoPbDecoderField::id, id), m);
+}
+
+// Matches a PerfettoPbDecoderField submessage field. Accepts a container
+// matcher for the subfields.
+//
+// Example:
+// PerfettoPbDecoderField field = ...
+// EXPECT_THAT(field, MsgField(ElementsAre(...)));
+template <typename M>
+auto MsgField(M m) {
+ auto f = [](const PerfettoPbDecoderField& field) { return FieldView(field); };
+ return testing::AllOf(
+ testing::Field(&PerfettoPbDecoderField::status, PERFETTO_PB_DECODER_OK),
+ testing::Field(&PerfettoPbDecoderField::wire_type,
+ PERFETTO_PB_WIRE_TYPE_DELIMITED),
+ testing::ResultOf(f, m));
+}
+
+// Matches a PerfettoPbDecoderField length delimited field. Accepts a string
+// matcher.
+//
+// Example:
+// PerfettoPbDecoderField field = ...
+// EXPECT_THAT(field, StringField("string"));
+template <typename M>
+auto StringField(M m) {
+ auto f = [](const PerfettoPbDecoderField& field) {
+ return std::string(
+ reinterpret_cast<const char*>(field.value.delimited.start),
+ field.value.delimited.len);
+ };
+ return testing::AllOf(
+ testing::Field(&PerfettoPbDecoderField::status, PERFETTO_PB_DECODER_OK),
+ testing::Field(&PerfettoPbDecoderField::wire_type,
+ PERFETTO_PB_WIRE_TYPE_DELIMITED),
+ testing::ResultOf(f, m));
+}
+
+// Matches a PerfettoPbDecoderField VarInt field. Accepts an integer matcher
+//
+// Example:
+// PerfettoPbDecoderField field = ...
+// EXPECT_THAT(field, VarIntField(1)));
+template <typename M>
+auto VarIntField(M m) {
+ auto f = [](const PerfettoPbDecoderField& field) {
+ return field.value.integer64;
+ };
+ return testing::AllOf(
+ testing::Field(&PerfettoPbDecoderField::status, PERFETTO_PB_DECODER_OK),
+ testing::Field(&PerfettoPbDecoderField::wire_type,
+ PERFETTO_PB_WIRE_TYPE_VARINT),
+ testing::ResultOf(f, m));
+}
+
+// Matches a PerfettoPbDecoderField fixed64 field. Accepts an integer matcher
+//
+// Example:
+// PerfettoPbDecoderField field = ...
+// EXPECT_THAT(field, Fixed64Field(1)));
+template <typename M>
+auto Fixed64Field(M m) {
+ auto f = [](const PerfettoPbDecoderField& field) {
+ return field.value.integer64;
+ };
+ return testing::AllOf(
+ testing::Field(&PerfettoPbDecoderField::status, PERFETTO_PB_DECODER_OK),
+ testing::Field(&PerfettoPbDecoderField::wire_type,
+ PERFETTO_PB_WIRE_TYPE_FIXED64),
+ testing::ResultOf(f, m));
+}
+
+// Matches a PerfettoPbDecoderField fixed32 field. Accepts an integer matcher
+//
+// Example:
+// PerfettoPbDecoderField field = ...
+// EXPECT_THAT(field, Fixed32Field(1)));
+template <typename M>
+auto Fixed32Field(M m) {
+ auto f = [](const PerfettoPbDecoderField& field) {
+ return field.value.integer32;
+ };
+ return testing::AllOf(
+ testing::Field(&PerfettoPbDecoderField::status, PERFETTO_PB_DECODER_OK),
+ testing::Field(&PerfettoPbDecoderField::wire_type,
+ PERFETTO_PB_WIRE_TYPE_FIXED32),
+ testing::ResultOf(f, m));
+}
+
+// Matches a PerfettoPbDecoderField double field. Accepts a double matcher
+//
+// Example:
+// PerfettoPbDecoderField field = ...
+// EXPECT_THAT(field, DoubleField(1.0)));
+template <typename M>
+auto DoubleField(M m) {
+ auto f = [](const PerfettoPbDecoderField& field) {
+ return field.value.double_val;
+ };
+ return testing::AllOf(
+ testing::Field(&PerfettoPbDecoderField::status, PERFETTO_PB_DECODER_OK),
+ testing::Field(&PerfettoPbDecoderField::wire_type,
+ PERFETTO_PB_WIRE_TYPE_FIXED64),
+ testing::ResultOf(f, m));
+}
+
+// Matches a PerfettoPbDecoderField float field. Accepts a float matcher
+//
+// Example:
+// PerfettoPbDecoderField field = ...
+// EXPECT_THAT(field, FloatField(1.0)));
+template <typename M>
+auto FloatField(M m) {
+ auto f = [](const PerfettoPbDecoderField& field) {
+ return field.value.float_val;
+ };
+ return testing::AllOf(
+ testing::Field(&PerfettoPbDecoderField::status, PERFETTO_PB_DECODER_OK),
+ testing::Field(&PerfettoPbDecoderField::wire_type,
+ PERFETTO_PB_WIRE_TYPE_FIXED32),
+ testing::ResultOf(f, m));
+}
+
+// Matches a PerfettoPbDecoderField submessage field. Accepts a container
+// matcher for the subfields.
+//
+// Example:
+// PerfettoPbDecoderField field = ...
+// EXPECT_THAT(field, AllFieldsWithId(900, ElementsAre(...)));
+template <typename M>
+auto AllFieldsWithId(int32_t id, M m) {
+ auto f = [id](const PerfettoPbDecoderField& field) {
+ return IdFieldView(field, id);
+ };
+ return testing::AllOf(
+ testing::Field(&PerfettoPbDecoderField::status, PERFETTO_PB_DECODER_OK),
+ testing::Field(&PerfettoPbDecoderField::wire_type,
+ PERFETTO_PB_WIRE_TYPE_DELIMITED),
+ testing::ResultOf(f, m));
+}
+
+} // namespace test_utils
+} // namespace shlib
+} // namespace perfetto
+
+#endif // UTILS_H
diff --git a/libs/tracing_perfetto/tracing_perfetto.cpp b/libs/tracing_perfetto/tracing_perfetto.cpp
new file mode 100644
index 0000000000..c7fb8bd9a8
--- /dev/null
+++ b/libs/tracing_perfetto/tracing_perfetto.cpp
@@ -0,0 +1,141 @@
+/*
+ * Copyright 2024 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 "tracing_perfetto.h"
+
+#include <cutils/trace.h>
+
+#include "perfetto/public/te_category_macros.h"
+#include "trace_categories.h"
+#include "tracing_perfetto_internal.h"
+
+namespace tracing_perfetto {
+
+void registerWithPerfetto(bool test) {
+ internal::registerWithPerfetto(test);
+}
+
+Result traceBegin(uint64_t category, const char* name) {
+ struct PerfettoTeCategory* perfettoTeCategory =
+ internal::toPerfettoCategory(category);
+ if (perfettoTeCategory != nullptr) {
+ return internal::perfettoTraceBegin(*perfettoTeCategory, name);
+ } else {
+ atrace_begin(category, name);
+ return Result::SUCCESS;
+ }
+}
+
+Result traceEnd(uint64_t category) {
+ struct PerfettoTeCategory* perfettoTeCategory =
+ internal::toPerfettoCategory(category);
+ if (perfettoTeCategory != nullptr) {
+ return internal::perfettoTraceEnd(*perfettoTeCategory);
+ } else {
+ atrace_end(category);
+ return Result::SUCCESS;
+ }
+}
+
+Result traceAsyncBegin(uint64_t category, const char* name, int32_t cookie) {
+ struct PerfettoTeCategory* perfettoTeCategory =
+ internal::toPerfettoCategory(category);
+ if (perfettoTeCategory != nullptr) {
+ return internal::perfettoTraceAsyncBegin(*perfettoTeCategory, name, cookie);
+ } else {
+ atrace_async_begin(category, name, cookie);
+ return Result::SUCCESS;
+ }
+}
+
+Result traceAsyncEnd(uint64_t category, const char* name, int32_t cookie) {
+ struct PerfettoTeCategory* perfettoTeCategory =
+ internal::toPerfettoCategory(category);
+ if (perfettoTeCategory != nullptr) {
+ return internal::perfettoTraceAsyncEnd(*perfettoTeCategory, name, cookie);
+ } else {
+ atrace_async_end(category, name, cookie);
+ return Result::SUCCESS;
+ }
+}
+
+Result traceAsyncBeginForTrack(uint64_t category, const char* name,
+ const char* trackName, int32_t cookie) {
+ struct PerfettoTeCategory* perfettoTeCategory =
+ internal::toPerfettoCategory(category);
+ if (perfettoTeCategory != nullptr) {
+ return internal::perfettoTraceAsyncBeginForTrack(*perfettoTeCategory, name, trackName, cookie);
+ } else {
+ atrace_async_for_track_begin(category, trackName, name, cookie);
+ return Result::SUCCESS;
+ }
+}
+
+Result traceAsyncEndForTrack(uint64_t category, const char* trackName,
+ int32_t cookie) {
+ struct PerfettoTeCategory* perfettoTeCategory =
+ internal::toPerfettoCategory(category);
+ if (perfettoTeCategory != nullptr) {
+ return internal::perfettoTraceAsyncEndForTrack(*perfettoTeCategory, trackName, cookie);
+ } else {
+ atrace_async_for_track_end(category, trackName, cookie);
+ return Result::SUCCESS;
+ }
+}
+
+Result traceInstant(uint64_t category, const char* name) {
+ struct PerfettoTeCategory* perfettoTeCategory =
+ internal::toPerfettoCategory(category);
+ if (perfettoTeCategory != nullptr) {
+ return internal::perfettoTraceInstant(*perfettoTeCategory, name);
+ } else {
+ atrace_instant(category, name);
+ return Result::SUCCESS;
+ }
+}
+
+Result traceInstantForTrack(uint64_t category, const char* trackName,
+ const char* name) {
+ struct PerfettoTeCategory* perfettoTeCategory =
+ internal::toPerfettoCategory(category);
+ if (perfettoTeCategory != nullptr) {
+ return internal::perfettoTraceInstantForTrack(*perfettoTeCategory, trackName, name);
+ } else {
+ atrace_instant_for_track(category, trackName, name);
+ return Result::SUCCESS;
+ }
+}
+
+Result traceCounter(uint64_t category, const char* name, int64_t value) {
+ struct PerfettoTeCategory* perfettoTeCategory =
+ internal::toPerfettoCategory(category);
+ if (perfettoTeCategory != nullptr) {
+ return internal::perfettoTraceCounter(*perfettoTeCategory, name, value);
+ } else {
+ atrace_int64(category, name, value);
+ return Result::SUCCESS;
+ }
+}
+
+uint64_t getEnabledCategories() {
+ if (internal::isPerfettoSdkTracingEnabled()) {
+ return internal::getDefaultCategories();
+ } else {
+ return atrace_get_enabled_tags();
+ }
+}
+
+} // namespace tracing_perfetto
diff --git a/libs/tracing_perfetto/tracing_perfetto_internal.cpp b/libs/tracing_perfetto/tracing_perfetto_internal.cpp
new file mode 100644
index 0000000000..58ba428610
--- /dev/null
+++ b/libs/tracing_perfetto/tracing_perfetto_internal.cpp
@@ -0,0 +1,229 @@
+/*
+ * Copyright 2024 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 FRAMEWORK_CATEGORIES(C) \
+ C(always, "always", "Always category") \
+ C(graphics, "graphics", "Graphics category") \
+ C(input, "input", "Input category") \
+ C(view, "view", "View category") \
+ C(webview, "webview", "WebView category") \
+ C(windowmanager, "wm", "WindowManager category") \
+ C(activitymanager, "am", "ActivityManager category") \
+ C(syncmanager, "syncmanager", "SyncManager category") \
+ C(audio, "audio", "Audio category") \
+ C(video, "video", "Video category") \
+ C(camera, "camera", "Camera category") \
+ C(hal, "hal", "HAL category") \
+ C(app, "app", "App category") \
+ C(resources, "res", "Resources category") \
+ C(dalvik, "dalvik", "Dalvik category") \
+ C(rs, "rs", "RS category") \
+ C(bionic, "bionic", "Bionic category") \
+ C(power, "power", "Power category") \
+ C(packagemanager, "packagemanager", "PackageManager category") \
+ C(systemserver, "ss", "System Server category") \
+ C(database, "database", "Database category") \
+ C(network, "network", "Network category") \
+ C(adb, "adb", "ADB category") \
+ C(vibrator, "vibrator", "Vibrator category") \
+ C(aidl, "aidl", "AIDL category") \
+ C(nnapi, "nnapi", "NNAPI category") \
+ C(rro, "rro", "RRO category") \
+ C(thermal, "thermal", "Thermal category")
+
+#include "tracing_perfetto_internal.h"
+
+#include <inttypes.h>
+
+#include <mutex>
+
+#include <android_os.h>
+
+#include "perfetto/public/compiler.h"
+#include "perfetto/public/producer.h"
+#include "perfetto/public/te_category_macros.h"
+#include "perfetto/public/te_macros.h"
+#include "perfetto/public/track_event.h"
+#include "trace_categories.h"
+#include "trace_result.h"
+
+namespace tracing_perfetto {
+
+namespace internal {
+
+namespace {
+
+PERFETTO_TE_CATEGORIES_DECLARE(FRAMEWORK_CATEGORIES);
+
+PERFETTO_TE_CATEGORIES_DEFINE(FRAMEWORK_CATEGORIES);
+
+struct PerfettoTeCategory* toCategory(uint64_t inCategory) {
+ switch (inCategory) {
+ case TRACE_CATEGORY_ALWAYS:
+ return &always;
+ case TRACE_CATEGORY_GRAPHICS:
+ return &graphics;
+ case TRACE_CATEGORY_INPUT:
+ return &input;
+ case TRACE_CATEGORY_VIEW:
+ return &view;
+ case TRACE_CATEGORY_WEBVIEW:
+ return &webview;
+ case TRACE_CATEGORY_WINDOW_MANAGER:
+ return &windowmanager;
+ case TRACE_CATEGORY_ACTIVITY_MANAGER:
+ return &activitymanager;
+ case TRACE_CATEGORY_SYNC_MANAGER:
+ return &syncmanager;
+ case TRACE_CATEGORY_AUDIO:
+ return &audio;
+ case TRACE_CATEGORY_VIDEO:
+ return &video;
+ case TRACE_CATEGORY_CAMERA:
+ return &camera;
+ case TRACE_CATEGORY_HAL:
+ return &hal;
+ case TRACE_CATEGORY_APP:
+ return &app;
+ case TRACE_CATEGORY_RESOURCES:
+ return &resources;
+ case TRACE_CATEGORY_DALVIK:
+ return &dalvik;
+ case TRACE_CATEGORY_RS:
+ return &rs;
+ case TRACE_CATEGORY_BIONIC:
+ return &bionic;
+ case TRACE_CATEGORY_POWER:
+ return &power;
+ case TRACE_CATEGORY_PACKAGE_MANAGER:
+ return &packagemanager;
+ case TRACE_CATEGORY_SYSTEM_SERVER:
+ return &systemserver;
+ case TRACE_CATEGORY_DATABASE:
+ return &database;
+ case TRACE_CATEGORY_NETWORK:
+ return &network;
+ case TRACE_CATEGORY_ADB:
+ return &adb;
+ case TRACE_CATEGORY_VIBRATOR:
+ return &vibrator;
+ case TRACE_CATEGORY_AIDL:
+ return &aidl;
+ case TRACE_CATEGORY_NNAPI:
+ return &nnapi;
+ case TRACE_CATEGORY_RRO:
+ return &rro;
+ case TRACE_CATEGORY_THERMAL:
+ return &thermal;
+ default:
+ return nullptr;
+ }
+}
+
+} // namespace
+
+bool isPerfettoSdkTracingEnabled() {
+ return android::os::perfetto_sdk_tracing();
+}
+
+struct PerfettoTeCategory* toPerfettoCategory(uint64_t category) {
+ if (!isPerfettoSdkTracingEnabled()) {
+ return nullptr;
+ }
+
+ struct PerfettoTeCategory* perfettoCategory = toCategory(category);
+ bool enabled = PERFETTO_UNLIKELY(PERFETTO_ATOMIC_LOAD_EXPLICIT(
+ (*perfettoCategory).enabled, PERFETTO_MEMORY_ORDER_RELAXED));
+ return enabled ? perfettoCategory : nullptr;
+}
+
+void registerWithPerfetto(bool test) {
+ if (!isPerfettoSdkTracingEnabled()) {
+ return;
+ }
+ static std::once_flag registration;
+ std::call_once(registration, [test]() {
+ struct PerfettoProducerInitArgs args = PERFETTO_PRODUCER_INIT_ARGS_INIT();
+ args.backends = test ? PERFETTO_BACKEND_IN_PROCESS : PERFETTO_BACKEND_SYSTEM;
+ PerfettoProducerInit(args);
+ PerfettoTeInit();
+ PERFETTO_TE_REGISTER_CATEGORIES(FRAMEWORK_CATEGORIES);
+ });
+}
+
+Result perfettoTraceBegin(const struct PerfettoTeCategory& category, const char* name) {
+ PERFETTO_TE(category, PERFETTO_TE_SLICE_BEGIN(name));
+ return Result::SUCCESS;
+}
+
+Result perfettoTraceEnd(const struct PerfettoTeCategory& category) {
+ PERFETTO_TE(category, PERFETTO_TE_SLICE_END());
+ return Result::SUCCESS;
+}
+
+Result perfettoTraceAsyncBeginForTrack(const struct PerfettoTeCategory& category, const char* name,
+ const char* trackName, uint64_t cookie) {
+ PERFETTO_TE(
+ category, PERFETTO_TE_SLICE_BEGIN(name),
+ PERFETTO_TE_NAMED_TRACK(trackName, cookie, PerfettoTeProcessTrackUuid()));
+ return Result::SUCCESS;
+}
+
+Result perfettoTraceAsyncEndForTrack(const struct PerfettoTeCategory& category,
+ const char* trackName, uint64_t cookie) {
+ PERFETTO_TE(
+ category, PERFETTO_TE_SLICE_END(),
+ PERFETTO_TE_NAMED_TRACK(trackName, cookie, PerfettoTeProcessTrackUuid()));
+ return Result::SUCCESS;
+}
+
+Result perfettoTraceAsyncBegin(const struct PerfettoTeCategory& category, const char* name,
+ uint64_t cookie) {
+ return perfettoTraceAsyncBeginForTrack(category, name, name, cookie);
+}
+
+Result perfettoTraceAsyncEnd(const struct PerfettoTeCategory& category, const char* name,
+ uint64_t cookie) {
+ return perfettoTraceAsyncEndForTrack(category, name, cookie);
+}
+
+Result perfettoTraceInstant(const struct PerfettoTeCategory& category, const char* name) {
+ PERFETTO_TE(category, PERFETTO_TE_INSTANT(name));
+ return Result::SUCCESS;
+}
+
+Result perfettoTraceInstantForTrack(const struct PerfettoTeCategory& category,
+ const char* trackName, const char* name) {
+ PERFETTO_TE(
+ category, PERFETTO_TE_INSTANT(name),
+ PERFETTO_TE_NAMED_TRACK(trackName, 1, PerfettoTeProcessTrackUuid()));
+ return Result::SUCCESS;
+}
+
+Result perfettoTraceCounter(const struct PerfettoTeCategory& category,
+ [[maybe_unused]] const char* name, int64_t value) {
+ PERFETTO_TE(category, PERFETTO_TE_COUNTER(),
+ PERFETTO_TE_INT_COUNTER(value));
+ return Result::SUCCESS;
+}
+
+uint64_t getDefaultCategories() {
+ return TRACE_CATEGORIES;
+}
+
+} // namespace internal
+
+} // namespace tracing_perfetto
diff --git a/libs/tracing_perfetto/tracing_perfetto_internal.h b/libs/tracing_perfetto/tracing_perfetto_internal.h
new file mode 100644
index 0000000000..9a579f162a
--- /dev/null
+++ b/libs/tracing_perfetto/tracing_perfetto_internal.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2024 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 TRACING_PERFETTO_INTERNAL_H
+#define TRACING_PERFETTO_INTERNAL_H
+
+#include <stdint.h>
+
+#include "include/trace_result.h"
+#include "perfetto/public/te_category_macros.h"
+
+namespace tracing_perfetto {
+
+namespace internal {
+
+bool isPerfettoSdkTracingEnabled();
+
+struct PerfettoTeCategory* toPerfettoCategory(uint64_t category);
+
+void registerWithPerfetto(bool test = false);
+
+Result perfettoTraceBegin(const struct PerfettoTeCategory& category, const char* name);
+
+Result perfettoTraceEnd(const struct PerfettoTeCategory& category);
+
+Result perfettoTraceAsyncBegin(const struct PerfettoTeCategory& category, const char* name,
+ uint64_t cookie);
+
+Result perfettoTraceAsyncEnd(const struct PerfettoTeCategory& category, const char* name,
+ uint64_t cookie);
+
+Result perfettoTraceAsyncBeginForTrack(const struct PerfettoTeCategory& category, const char* name,
+ const char* trackName, uint64_t cookie);
+
+Result perfettoTraceAsyncEndForTrack(const struct PerfettoTeCategory& category,
+ const char* trackName, uint64_t cookie);
+
+Result perfettoTraceInstant(const struct PerfettoTeCategory& category, const char* name);
+
+Result perfettoTraceInstantForTrack(const struct PerfettoTeCategory& category,
+ const char* trackName, const char* name);
+
+Result perfettoTraceCounter(const struct PerfettoTeCategory& category, const char* name,
+ int64_t value);
+
+uint64_t getDefaultCategories();
+
+} // namespace internal
+
+} // namespace tracing_perfetto
+
+#endif // TRACING_PERFETTO_INTERNAL_H
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index ec0ab4e464..9cb298a132 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -14,6 +14,7 @@
package {
default_applicable_licenses: ["frameworks_native_libs_ui_license"],
+ default_team: "trendy_team_android_core_graphics_stack",
}
// Added automatically by a large-scale-change
diff --git a/libs/ui/Gralloc2.cpp b/libs/ui/Gralloc2.cpp
index e9b5decee8..a5aca9912f 100644
--- a/libs/ui/Gralloc2.cpp
+++ b/libs/ui/Gralloc2.cpp
@@ -384,8 +384,8 @@ std::string Gralloc2Allocator::dumpDebugInfo(bool /*less*/) const {
status_t Gralloc2Allocator::allocate(std::string /*requestorName*/, uint32_t width, uint32_t height,
PixelFormat format, uint32_t layerCount, uint64_t usage,
- uint32_t bufferCount, uint32_t* outStride,
- buffer_handle_t* outBufferHandles, bool importBuffers) const {
+ uint32_t* outStride, buffer_handle_t* outBufferHandles,
+ bool importBuffers) const {
IMapper::BufferDescriptorInfo descriptorInfo = {};
descriptorInfo.width = width;
descriptorInfo.height = height;
@@ -400,6 +400,8 @@ status_t Gralloc2Allocator::allocate(std::string /*requestorName*/, uint32_t wid
return error;
}
+ constexpr auto bufferCount = 1;
+
auto ret = mAllocator->allocate(descriptor, bufferCount,
[&](const auto& tmpError, const auto& tmpStride,
const auto& tmpBuffers) {
diff --git a/libs/ui/Gralloc3.cpp b/libs/ui/Gralloc3.cpp
index 474d381dbb..152b35a505 100644
--- a/libs/ui/Gralloc3.cpp
+++ b/libs/ui/Gralloc3.cpp
@@ -371,7 +371,7 @@ std::string Gralloc3Allocator::dumpDebugInfo(bool /*less*/) const {
status_t Gralloc3Allocator::allocate(std::string /*requestorName*/, uint32_t width, uint32_t height,
android::PixelFormat format, uint32_t layerCount,
- uint64_t usage, uint32_t bufferCount, uint32_t* outStride,
+ uint64_t usage, uint32_t* outStride,
buffer_handle_t* outBufferHandles, bool importBuffers) const {
IMapper::BufferDescriptorInfo descriptorInfo;
sBufferDescriptorInfo(width, height, format, layerCount, usage, &descriptorInfo);
@@ -383,6 +383,8 @@ status_t Gralloc3Allocator::allocate(std::string /*requestorName*/, uint32_t wid
return error;
}
+ constexpr auto bufferCount = 1;
+
auto ret = mAllocator->allocate(descriptor, bufferCount,
[&](const auto& tmpError, const auto& tmpStride,
const auto& tmpBuffers) {
diff --git a/libs/ui/Gralloc4.cpp b/libs/ui/Gralloc4.cpp
index 03ff58a76c..2a607308d1 100644
--- a/libs/ui/Gralloc4.cpp
+++ b/libs/ui/Gralloc4.cpp
@@ -262,37 +262,8 @@ void Gralloc4Mapper::getTransportSize(buffer_handle_t bufferHandle, uint32_t* ou
status_t Gralloc4Mapper::lock(buffer_handle_t bufferHandle, uint64_t usage, const Rect& bounds,
int acquireFence, void** outData, int32_t* outBytesPerPixel,
int32_t* outBytesPerStride) const {
- std::vector<ui::PlaneLayout> planeLayouts;
- status_t err = getPlaneLayouts(bufferHandle, &planeLayouts);
-
- if (err == NO_ERROR && !planeLayouts.empty()) {
- if (outBytesPerPixel) {
- int32_t bitsPerPixel = planeLayouts.front().sampleIncrementInBits;
- for (const auto& planeLayout : planeLayouts) {
- if (bitsPerPixel != planeLayout.sampleIncrementInBits) {
- bitsPerPixel = -1;
- }
- }
- if (bitsPerPixel >= 0 && bitsPerPixel % 8 == 0) {
- *outBytesPerPixel = bitsPerPixel / 8;
- } else {
- *outBytesPerPixel = -1;
- }
- }
- if (outBytesPerStride) {
- int32_t bytesPerStride = planeLayouts.front().strideInBytes;
- for (const auto& planeLayout : planeLayouts) {
- if (bytesPerStride != planeLayout.strideInBytes) {
- bytesPerStride = -1;
- }
- }
- if (bytesPerStride >= 0) {
- *outBytesPerStride = bytesPerStride;
- } else {
- *outBytesPerStride = -1;
- }
- }
- }
+ if (outBytesPerPixel) *outBytesPerPixel = -1;
+ if (outBytesPerStride) *outBytesPerStride = -1;
auto buffer = const_cast<native_handle_t*>(bufferHandle);
@@ -1069,7 +1040,7 @@ std::string Gralloc4Allocator::dumpDebugInfo(bool less) const {
status_t Gralloc4Allocator::allocate(std::string requestorName, uint32_t width, uint32_t height,
android::PixelFormat format, uint32_t layerCount,
- uint64_t usage, uint32_t bufferCount, uint32_t* outStride,
+ uint64_t usage, uint32_t* outStride,
buffer_handle_t* outBufferHandles, bool importBuffers) const {
IMapper::BufferDescriptorInfo descriptorInfo;
if (auto error = sBufferDescriptorInfo(requestorName, width, height, format, layerCount, usage,
@@ -1084,6 +1055,8 @@ status_t Gralloc4Allocator::allocate(std::string requestorName, uint32_t width,
return error;
}
+ constexpr auto bufferCount = 1;
+
if (mAidlAllocator) {
AllocationResult result;
#pragma clang diagnostic push
diff --git a/libs/ui/Gralloc5.cpp b/libs/ui/Gralloc5.cpp
index 25850f71cb..11064ae7fc 100644
--- a/libs/ui/Gralloc5.cpp
+++ b/libs/ui/Gralloc5.cpp
@@ -19,6 +19,7 @@
#include <ui/Gralloc5.h>
+#include <aidl/android/hardware/graphics/allocator/AllocationError.h>
#include <aidlcommonsupport/NativeHandle.h>
#include <android/binder_manager.h>
#include <android/hardware/graphics/mapper/utils/IMapperMetadataTypes.h>
@@ -223,55 +224,75 @@ std::string Gralloc5Allocator::dumpDebugInfo(bool less) const {
status_t Gralloc5Allocator::allocate(std::string requestorName, uint32_t width, uint32_t height,
android::PixelFormat format, uint32_t layerCount,
- uint64_t usage, uint32_t bufferCount, uint32_t *outStride,
- buffer_handle_t *outBufferHandles, bool importBuffers) const {
- auto descriptorInfo = makeDescriptor(requestorName, width, height, format, layerCount, usage);
+ uint64_t usage, uint32_t* outStride,
+ buffer_handle_t* outBufferHandles, bool importBuffers) const {
+ auto result = allocate(GraphicBufferAllocator::AllocationRequest{
+ .importBuffer = importBuffers,
+ .width = width,
+ .height = height,
+ .format = format,
+ .layerCount = layerCount,
+ .usage = usage,
+ .requestorName = requestorName,
+ });
+
+ *outStride = result.stride;
+ outBufferHandles[0] = result.handle;
+ return result.status;
+}
+
+GraphicBufferAllocator::AllocationResult Gralloc5Allocator::allocate(
+ const GraphicBufferAllocator::AllocationRequest& request) const {
+ auto descriptorInfo = makeDescriptor(request.requestorName, request.width, request.height,
+ request.format, request.layerCount, request.usage);
if (!descriptorInfo) {
- return BAD_VALUE;
+ return GraphicBufferAllocator::AllocationResult{BAD_VALUE};
+ }
+
+ descriptorInfo->additionalOptions.reserve(request.extras.size());
+ for (const auto& option : request.extras) {
+ ExtendableType type;
+ type.name = option.name;
+ type.value = option.value;
+ descriptorInfo->additionalOptions.push_back(std::move(type));
}
AllocationResult result;
- auto status = mAllocator->allocate2(*descriptorInfo, bufferCount, &result);
+ auto status = mAllocator->allocate2(*descriptorInfo, 1, &result);
if (!status.isOk()) {
auto error = status.getExceptionCode();
if (error == EX_SERVICE_SPECIFIC) {
- error = status.getServiceSpecificError();
- }
- if (error == OK) {
- error = UNKNOWN_ERROR;
+ switch (static_cast<AllocationError>(status.getServiceSpecificError())) {
+ case AllocationError::BAD_DESCRIPTOR:
+ error = BAD_VALUE;
+ break;
+ case AllocationError::NO_RESOURCES:
+ error = NO_MEMORY;
+ break;
+ default:
+ error = UNKNOWN_ERROR;
+ break;
+ }
}
- return error;
+ return GraphicBufferAllocator::AllocationResult{error};
}
- if (importBuffers) {
- for (uint32_t i = 0; i < bufferCount; i++) {
- auto handle = makeFromAidl(result.buffers[i]);
- auto error = mMapper.importBuffer(handle, &outBufferHandles[i]);
- native_handle_delete(handle);
- if (error != NO_ERROR) {
- for (uint32_t j = 0; j < i; j++) {
- mMapper.freeBuffer(outBufferHandles[j]);
- outBufferHandles[j] = nullptr;
- }
- return error;
- }
+ GraphicBufferAllocator::AllocationResult ret{OK};
+ if (request.importBuffer) {
+ auto handle = makeFromAidl(result.buffers[0]);
+ auto error = mMapper.importBuffer(handle, &ret.handle);
+ native_handle_delete(handle);
+ if (error != NO_ERROR) {
+ return GraphicBufferAllocator::AllocationResult{error};
}
} else {
- for (uint32_t i = 0; i < bufferCount; i++) {
- outBufferHandles[i] = dupFromAidl(result.buffers[i]);
- if (!outBufferHandles[i]) {
- for (uint32_t j = 0; j < i; j++) {
- auto buffer = const_cast<native_handle_t *>(outBufferHandles[j]);
- native_handle_close(buffer);
- native_handle_delete(buffer);
- outBufferHandles[j] = nullptr;
- }
- return NO_MEMORY;
- }
+ ret.handle = dupFromAidl(result.buffers[0]);
+ if (!ret.handle) {
+ return GraphicBufferAllocator::AllocationResult{NO_MEMORY};
}
}
- *outStride = result.stride;
+ ret.stride = result.stride;
// Release all the resources held by AllocationResult (specifically any remaining FDs)
result = {};
@@ -280,7 +301,7 @@ status_t Gralloc5Allocator::allocate(std::string requestorName, uint32_t width,
// is marked apex_available (b/214400477) and libbinder isn't (which of course is correct)
// IPCThreadState::self()->flushCommands();
- return OK;
+ return ret;
}
void Gralloc5Mapper::preload() {
@@ -576,37 +597,8 @@ void Gralloc5Mapper::getTransportSize(buffer_handle_t bufferHandle, uint32_t *ou
status_t Gralloc5Mapper::lock(buffer_handle_t bufferHandle, uint64_t usage, const Rect &bounds,
int acquireFence, void **outData, int32_t *outBytesPerPixel,
int32_t *outBytesPerStride) const {
- std::vector<ui::PlaneLayout> planeLayouts;
- status_t err = getPlaneLayouts(bufferHandle, &planeLayouts);
-
- if (err == NO_ERROR && !planeLayouts.empty()) {
- if (outBytesPerPixel) {
- int32_t bitsPerPixel = planeLayouts.front().sampleIncrementInBits;
- for (const auto &planeLayout : planeLayouts) {
- if (bitsPerPixel != planeLayout.sampleIncrementInBits) {
- bitsPerPixel = -1;
- }
- }
- if (bitsPerPixel >= 0 && bitsPerPixel % 8 == 0) {
- *outBytesPerPixel = bitsPerPixel / 8;
- } else {
- *outBytesPerPixel = -1;
- }
- }
- if (outBytesPerStride) {
- int32_t bytesPerStride = planeLayouts.front().strideInBytes;
- for (const auto &planeLayout : planeLayouts) {
- if (bytesPerStride != planeLayout.strideInBytes) {
- bytesPerStride = -1;
- }
- }
- if (bytesPerStride >= 0) {
- *outBytesPerStride = bytesPerStride;
- } else {
- *outBytesPerStride = -1;
- }
- }
- }
+ if (outBytesPerPixel) *outBytesPerPixel = -1;
+ if (outBytesPerStride) *outBytesPerStride = -1;
auto status = mMapper->v5.lock(bufferHandle, usage, bounds, acquireFence, outData);
diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp
index 429760ffe0..ffb6cdb6ef 100644
--- a/libs/ui/GraphicBuffer.cpp
+++ b/libs/ui/GraphicBuffer.cpp
@@ -22,7 +22,7 @@
#include <cutils/atomic.h>
#include <grallocusage/GrallocUsageConversion.h>
-
+#include <sync/sync.h>
#include <ui/GraphicBufferAllocator.h>
#include <ui/GraphicBufferMapper.h>
#include <utils/Trace.h>
@@ -40,6 +40,38 @@ static uint64_t getUniqueId() {
return id;
}
+static void resolveLegacyByteLayoutFromPlaneLayout(const std::vector<ui::PlaneLayout>& planeLayouts,
+ int32_t* outBytesPerPixel,
+ int32_t* outBytesPerStride) {
+ if (planeLayouts.empty()) return;
+ if (outBytesPerPixel) {
+ int32_t bitsPerPixel = planeLayouts.front().sampleIncrementInBits;
+ for (const auto& planeLayout : planeLayouts) {
+ if (bitsPerPixel != planeLayout.sampleIncrementInBits) {
+ bitsPerPixel = -1;
+ }
+ }
+ if (bitsPerPixel >= 0 && bitsPerPixel % 8 == 0) {
+ *outBytesPerPixel = bitsPerPixel / 8;
+ } else {
+ *outBytesPerPixel = -1;
+ }
+ }
+ if (outBytesPerStride) {
+ int32_t bytesPerStride = planeLayouts.front().strideInBytes;
+ for (const auto& planeLayout : planeLayouts) {
+ if (bytesPerStride != planeLayout.strideInBytes) {
+ bytesPerStride = -1;
+ }
+ }
+ if (bytesPerStride >= 0) {
+ *outBytesPerStride = bytesPerStride;
+ } else {
+ *outBytesPerStride = -1;
+ }
+ }
+}
+
sp<GraphicBuffer> GraphicBuffer::from(ANativeWindowBuffer* anwb) {
return static_cast<GraphicBuffer *>(anwb);
}
@@ -106,6 +138,26 @@ GraphicBuffer::GraphicBuffer(const native_handle_t* inHandle, HandleWrapMethod m
inUsage, inStride);
}
+GraphicBuffer::GraphicBuffer(const GraphicBufferAllocator::AllocationRequest& request)
+ : GraphicBuffer() {
+ GraphicBufferAllocator& allocator = GraphicBufferAllocator::get();
+ auto result = allocator.allocate(request);
+ mInitCheck = result.status;
+ if (result.status == NO_ERROR) {
+ handle = result.handle;
+ stride = result.stride;
+
+ mBufferMapper.getTransportSize(handle, &mTransportNumFds, &mTransportNumInts);
+
+ width = static_cast<int>(request.width);
+ height = static_cast<int>(request.height);
+ format = request.format;
+ layerCount = request.layerCount;
+ usage = request.usage;
+ usage_deprecated = int(usage);
+ }
+}
+
GraphicBuffer::~GraphicBuffer()
{
ATRACE_CALL();
@@ -143,6 +195,10 @@ ANativeWindowBuffer* GraphicBuffer::getNativeBuffer() const
const_cast<GraphicBuffer*>(this));
}
+status_t GraphicBuffer::getDataspace(ui::Dataspace* outDataspace) const {
+ return mBufferMapper.getDataspace(handle, outDataspace);
+}
+
status_t GraphicBuffer::reallocate(uint32_t inWidth, uint32_t inHeight,
PixelFormat inFormat, uint32_t inLayerCount, uint64_t inUsage)
{
@@ -255,10 +311,7 @@ status_t GraphicBuffer::lock(uint32_t inUsage, const Rect& rect, void** vaddr,
return BAD_VALUE;
}
- status_t res = getBufferMapper().lock(handle, inUsage, rect, vaddr, outBytesPerPixel,
- outBytesPerStride);
-
- return res;
+ return lockAsync(inUsage, rect, vaddr, -1, outBytesPerPixel, outBytesPerStride);
}
status_t GraphicBuffer::lockYCbCr(uint32_t inUsage, android_ycbcr* ycbcr)
@@ -278,14 +331,12 @@ status_t GraphicBuffer::lockYCbCr(uint32_t inUsage, const Rect& rect,
width, height);
return BAD_VALUE;
}
- status_t res = getBufferMapper().lockYCbCr(handle, inUsage, rect, ycbcr);
- return res;
+ return lockAsyncYCbCr(inUsage, rect, ycbcr, -1);
}
status_t GraphicBuffer::unlock()
{
- status_t res = getBufferMapper().unlock(handle);
- return res;
+ return unlockAsync(nullptr);
}
status_t GraphicBuffer::lockAsync(uint32_t inUsage, void** vaddr, int fenceFd,
@@ -312,10 +363,49 @@ status_t GraphicBuffer::lockAsync(uint64_t inProducerUsage, uint64_t inConsumerU
return BAD_VALUE;
}
- status_t res = getBufferMapper().lockAsync(handle, inProducerUsage, inConsumerUsage, rect,
- vaddr, fenceFd, outBytesPerPixel, outBytesPerStride);
+ // Resolve the bpp & bps before doing a lock in case this fails we don't have to worry about
+ // doing an unlock
+ int32_t legacyBpp = -1, legacyBps = -1;
+ if (outBytesPerPixel || outBytesPerStride) {
+ const auto mapperVersion = getBufferMapperVersion();
+ // For gralloc2 we need to guess at the bpp & bps
+ // For gralloc3 the lock() call will return it
+ // For gralloc4 & later the PlaneLayout metadata query is vastly superior and we
+ // resolve bpp & bps just for compatibility
+
+ // TODO: See if we can't just remove gralloc2 support.
+ if (mapperVersion == GraphicBufferMapper::GRALLOC_2) {
+ legacyBpp = bytesPerPixel(format);
+ if (legacyBpp > 0) {
+ legacyBps = stride * legacyBpp;
+ } else {
+ legacyBpp = -1;
+ }
+ } else if (mapperVersion >= GraphicBufferMapper::GRALLOC_4) {
+ auto planeLayout = getBufferMapper().getPlaneLayouts(handle);
+ if (!planeLayout.has_value()) return planeLayout.asStatus();
+ resolveLegacyByteLayoutFromPlaneLayout(planeLayout.value(), &legacyBpp, &legacyBps);
+ }
+ }
- return res;
+ const uint64_t usage = static_cast<uint64_t>(
+ android_convertGralloc1To0Usage(inProducerUsage, inConsumerUsage));
+
+ auto result = getBufferMapper().lock(handle, usage, rect, base::unique_fd{fenceFd});
+
+ if (!result.has_value()) {
+ return result.error().asStatus();
+ }
+ auto value = result.value();
+ *vaddr = value.address;
+
+ if (outBytesPerPixel) {
+ *outBytesPerPixel = legacyBpp != -1 ? legacyBpp : value.bytesPerPixel;
+ }
+ if (outBytesPerStride) {
+ *outBytesPerStride = legacyBps != -1 ? legacyBps : value.bytesPerStride;
+ }
+ return OK;
}
status_t GraphicBuffer::lockAsyncYCbCr(uint32_t inUsage, android_ycbcr* ycbcr,
@@ -336,14 +426,18 @@ status_t GraphicBuffer::lockAsyncYCbCr(uint32_t inUsage, const Rect& rect,
width, height);
return BAD_VALUE;
}
- status_t res = getBufferMapper().lockAsyncYCbCr(handle, inUsage, rect, ycbcr, fenceFd);
- return res;
+ auto result = getBufferMapper().lockYCbCr(handle, static_cast<int64_t>(inUsage), rect,
+ base::unique_fd{fenceFd});
+ if (!result.has_value()) {
+ return result.error().asStatus();
+ }
+ *ycbcr = result.value();
+ return OK;
}
status_t GraphicBuffer::unlockAsync(int *fenceFd)
{
- status_t res = getBufferMapper().unlockAsync(handle, fenceFd);
- return res;
+ return getBufferMapper().unlockAsync(handle, fenceFd);
}
status_t GraphicBuffer::isSupported(uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat,
diff --git a/libs/ui/GraphicBufferAllocator.cpp b/libs/ui/GraphicBufferAllocator.cpp
index eb0bd4ed0a..98082fb81e 100644
--- a/libs/ui/GraphicBufferAllocator.cpp
+++ b/libs/ui/GraphicBufferAllocator.cpp
@@ -113,6 +113,79 @@ void GraphicBufferAllocator::dumpToSystemLog(bool less) {
ALOGD("%s", s.c_str());
}
+auto GraphicBufferAllocator::allocate(const AllocationRequest& request) -> AllocationResult {
+ ATRACE_CALL();
+ if (!request.width || !request.height) {
+ return AllocationResult(BAD_VALUE);
+ }
+
+ const auto width = request.width;
+ const auto height = request.height;
+
+ const uint32_t bpp = bytesPerPixel(request.format);
+ if (std::numeric_limits<size_t>::max() / width / height < static_cast<size_t>(bpp)) {
+ ALOGE("Failed to allocate (%u x %u) layerCount %u format %d "
+ "usage %" PRIx64 ": Requesting too large a buffer size",
+ request.width, request.height, request.layerCount, request.format, request.usage);
+ return AllocationResult(BAD_VALUE);
+ }
+
+ if (request.layerCount < 1) {
+ return AllocationResult(BAD_VALUE);
+ }
+
+ auto result = mAllocator->allocate(request);
+ if (result.status == UNKNOWN_TRANSACTION) {
+ if (!request.extras.empty()) {
+ ALOGE("Failed to allocate with additional options, allocator version mis-match? "
+ "gralloc version = %d",
+ (int)mMapper.getMapperVersion());
+ return result;
+ }
+ // If there's no additional options, fall back to previous allocate version
+ result.status = mAllocator->allocate(request.requestorName, request.width, request.height,
+ request.format, request.layerCount, request.usage,
+ &result.stride, &result.handle, request.importBuffer);
+ }
+
+ if (result.status != NO_ERROR) {
+ ALOGE("Failed to allocate (%u x %u) layerCount %u format %d "
+ "usage %" PRIx64 ": %d",
+ request.width, request.height, request.layerCount, request.format, request.usage,
+ result.status);
+ return result;
+ }
+
+ if (!request.importBuffer) {
+ return result;
+ }
+ size_t bufSize;
+
+ // if stride has no meaning or is too large,
+ // approximate size with the input width instead
+ if ((result.stride) != 0 &&
+ std::numeric_limits<size_t>::max() / height / (result.stride) < static_cast<size_t>(bpp)) {
+ bufSize = static_cast<size_t>(width) * height * bpp;
+ } else {
+ bufSize = static_cast<size_t>((result.stride)) * height * bpp;
+ }
+
+ Mutex::Autolock _l(sLock);
+ KeyedVector<buffer_handle_t, alloc_rec_t>& list(sAllocList);
+ alloc_rec_t rec;
+ rec.width = width;
+ rec.height = height;
+ rec.stride = result.stride;
+ rec.format = request.format;
+ rec.layerCount = request.layerCount;
+ rec.usage = request.usage;
+ rec.size = bufSize;
+ rec.requestorName = request.requestorName;
+ list.add(result.handle, rec);
+
+ return result;
+}
+
status_t GraphicBufferAllocator::allocateHelper(uint32_t width, uint32_t height, PixelFormat format,
uint32_t layerCount, uint64_t usage,
buffer_handle_t* handle, uint32_t* stride,
@@ -141,7 +214,7 @@ status_t GraphicBufferAllocator::allocateHelper(uint32_t width, uint32_t height,
usage &= ~static_cast<uint64_t>((1 << 10) | (1 << 13));
status_t error = mAllocator->allocate(requestorName, width, height, format, layerCount, usage,
- 1, stride, handle, importBuffer);
+ stride, handle, importBuffer);
if (error != NO_ERROR) {
ALOGE("Failed to allocate (%u x %u) layerCount %u format %d "
"usage %" PRIx64 ": %d",
diff --git a/libs/ui/GraphicBufferMapper.cpp b/libs/ui/GraphicBufferMapper.cpp
index 7086e0470c..b6ab2f5a47 100644
--- a/libs/ui/GraphicBufferMapper.cpp
+++ b/libs/ui/GraphicBufferMapper.cpp
@@ -41,9 +41,13 @@
#include <system/graphics.h>
+using unique_fd = ::android::base::unique_fd;
+
namespace android {
// ---------------------------------------------------------------------------
+using LockResult = GraphicBufferMapper::LockResult;
+
ANDROID_SINGLETON_STATIC_INSTANCE( GraphicBufferMapper )
void GraphicBufferMapper::preloadHal() {
@@ -135,63 +139,86 @@ status_t GraphicBufferMapper::freeBuffer(buffer_handle_t handle)
return NO_ERROR;
}
-status_t GraphicBufferMapper::lock(buffer_handle_t handle, uint32_t usage, const Rect& bounds,
- void** vaddr, int32_t* outBytesPerPixel,
- int32_t* outBytesPerStride) {
- return lockAsync(handle, usage, bounds, vaddr, -1, outBytesPerPixel, outBytesPerStride);
-}
-
-status_t GraphicBufferMapper::lockYCbCr(buffer_handle_t handle, uint32_t usage,
- const Rect& bounds, android_ycbcr *ycbcr)
-{
- return lockAsyncYCbCr(handle, usage, bounds, ycbcr, -1);
-}
+ui::Result<LockResult> GraphicBufferMapper::lock(buffer_handle_t handle, int64_t usage,
+ const Rect& bounds, unique_fd&& acquireFence) {
+ ATRACE_CALL();
-status_t GraphicBufferMapper::unlock(buffer_handle_t handle)
-{
- int32_t fenceFd = -1;
- status_t error = unlockAsync(handle, &fenceFd);
- if (error == NO_ERROR && fenceFd >= 0) {
- sync_wait(fenceFd, -1);
- close(fenceFd);
+ LockResult result;
+ status_t status = mMapper->lock(handle, usage, bounds, acquireFence.release(), &result.address,
+ &result.bytesPerPixel, &result.bytesPerStride);
+ if (status != OK) {
+ return base::unexpected(ui::Error::statusToCode(status));
+ } else {
+ return result;
}
- return error;
-}
-
-status_t GraphicBufferMapper::lockAsync(buffer_handle_t handle, uint32_t usage, const Rect& bounds,
- void** vaddr, int fenceFd, int32_t* outBytesPerPixel,
- int32_t* outBytesPerStride) {
- return lockAsync(handle, usage, usage, bounds, vaddr, fenceFd, outBytesPerPixel,
- outBytesPerStride);
}
-status_t GraphicBufferMapper::lockAsync(buffer_handle_t handle, uint64_t producerUsage,
- uint64_t consumerUsage, const Rect& bounds, void** vaddr,
- int fenceFd, int32_t* outBytesPerPixel,
- int32_t* outBytesPerStride) {
+ui::Result<android_ycbcr> GraphicBufferMapper::lockYCbCr(buffer_handle_t handle, int64_t usage,
+ const Rect& bounds,
+ base::unique_fd&& acquireFence) {
ATRACE_CALL();
- const uint64_t usage = static_cast<uint64_t>(
- android_convertGralloc1To0Usage(producerUsage, consumerUsage));
- return mMapper->lock(handle, usage, bounds, fenceFd, vaddr, outBytesPerPixel,
- outBytesPerStride);
+ android_ycbcr result = {};
+ status_t status = mMapper->lock(handle, usage, bounds, acquireFence.release(), &result);
+ if (status != OK) {
+ return base::unexpected(ui::Error::statusToCode(status));
+ } else {
+ return result;
+ }
}
-status_t GraphicBufferMapper::lockAsyncYCbCr(buffer_handle_t handle,
- uint32_t usage, const Rect& bounds, android_ycbcr *ycbcr, int fenceFd)
-{
+status_t GraphicBufferMapper::unlock(buffer_handle_t handle, base::unique_fd* outFence) {
ATRACE_CALL();
+ int fence = mMapper->unlock(handle);
+ if (outFence) {
+ *outFence = unique_fd{fence};
+ } else {
+ sync_wait(fence, -1);
+ close(fence);
+ }
+ return OK;
+}
- return mMapper->lock(handle, usage, bounds, fenceFd, ycbcr);
+status_t GraphicBufferMapper::lock(buffer_handle_t handle, uint32_t usage, const Rect& bounds,
+ void** vaddr) {
+ auto result = lock(handle, static_cast<int64_t>(usage), bounds);
+ if (!result.has_value()) return result.asStatus();
+ auto val = result.value();
+ *vaddr = val.address;
+ return OK;
}
-status_t GraphicBufferMapper::unlockAsync(buffer_handle_t handle, int *fenceFd)
-{
- ATRACE_CALL();
+status_t GraphicBufferMapper::lockYCbCr(buffer_handle_t handle, uint32_t usage, const Rect& bounds,
+ android_ycbcr* ycbcr) {
+ auto result = lockYCbCr(handle, static_cast<int64_t>(usage), bounds);
+ if (!result.has_value()) return result.asStatus();
+ *ycbcr = result.value();
+ return OK;
+}
+
+status_t GraphicBufferMapper::lockAsync(buffer_handle_t handle, uint32_t usage, const Rect& bounds,
+ void** vaddr, int fenceFd) {
+ auto result = lock(handle, static_cast<int64_t>(usage), bounds, unique_fd{fenceFd});
+ if (!result.has_value()) return result.asStatus();
+ auto val = result.value();
+ *vaddr = val.address;
+ return OK;
+}
- *fenceFd = mMapper->unlock(handle);
+status_t GraphicBufferMapper::lockAsync(buffer_handle_t handle, uint64_t producerUsage,
+ uint64_t consumerUsage, const Rect& bounds, void** vaddr,
+ int fenceFd) {
+ return lockAsync(handle, android_convertGralloc1To0Usage(producerUsage, consumerUsage), bounds,
+ vaddr, fenceFd);
+}
- return NO_ERROR;
+status_t GraphicBufferMapper::lockAsyncYCbCr(buffer_handle_t handle, uint32_t usage,
+ const Rect& bounds, android_ycbcr* ycbcr,
+ int fenceFd) {
+ auto result = lockYCbCr(handle, static_cast<int64_t>(usage), bounds, unique_fd{fenceFd});
+ if (!result.has_value()) return result.asStatus();
+ *ycbcr = result.value();
+ return OK;
}
status_t GraphicBufferMapper::isSupported(uint32_t width, uint32_t height,
@@ -287,6 +314,17 @@ status_t GraphicBufferMapper::getPlaneLayouts(buffer_handle_t bufferHandle,
return mMapper->getPlaneLayouts(bufferHandle, outPlaneLayouts);
}
+ui::Result<std::vector<ui::PlaneLayout>> GraphicBufferMapper::getPlaneLayouts(
+ buffer_handle_t bufferHandle) {
+ std::vector<ui::PlaneLayout> temp;
+ status_t status = mMapper->getPlaneLayouts(bufferHandle, &temp);
+ if (status == OK) {
+ return std::move(temp);
+ } else {
+ return base::unexpected(ui::Error::statusToCode(status));
+ }
+}
+
status_t GraphicBufferMapper::getDataspace(buffer_handle_t bufferHandle,
ui::Dataspace* outDataspace) {
return mMapper->getDataspace(bufferHandle, outDataspace);
diff --git a/libs/ui/include/ui/Gralloc.h b/libs/ui/include/ui/Gralloc.h
index 496ba57789..e6015e0b5e 100644
--- a/libs/ui/include/ui/Gralloc.h
+++ b/libs/ui/include/ui/Gralloc.h
@@ -23,6 +23,7 @@
#include <ui/PixelFormat.h>
#include <ui/Rect.h>
#include <utils/StrongPointer.h>
+#include "GraphicBufferAllocator.h"
#include <string>
@@ -218,9 +219,13 @@ public:
*/
virtual status_t allocate(std::string requestorName, uint32_t width, uint32_t height,
PixelFormat format, uint32_t layerCount, uint64_t usage,
- uint32_t bufferCount, uint32_t* outStride,
- buffer_handle_t* outBufferHandles,
+ uint32_t* outStride, buffer_handle_t* outBufferHandles,
bool importBuffers = true) const = 0;
+
+ virtual GraphicBufferAllocator::AllocationResult allocate(
+ const GraphicBufferAllocator::AllocationRequest&) const {
+ return GraphicBufferAllocator::AllocationResult(UNKNOWN_TRANSACTION);
+ }
};
} // namespace android
diff --git a/libs/ui/include/ui/Gralloc2.h b/libs/ui/include/ui/Gralloc2.h
index a7b6f49206..e50bb3af3e 100644
--- a/libs/ui/include/ui/Gralloc2.h
+++ b/libs/ui/include/ui/Gralloc2.h
@@ -81,9 +81,8 @@ public:
std::string dumpDebugInfo(bool less = true) const override;
status_t allocate(std::string requestorName, uint32_t width, uint32_t height,
- PixelFormat format, uint32_t layerCount, uint64_t usage, uint32_t bufferCount,
- uint32_t* outStride, buffer_handle_t* outBufferHandles,
- bool importBuffers = true) const override;
+ PixelFormat format, uint32_t layerCount, uint64_t usage, uint32_t* outStride,
+ buffer_handle_t* outBufferHandles, bool importBuffers = true) const override;
private:
const Gralloc2Mapper& mMapper;
diff --git a/libs/ui/include/ui/Gralloc3.h b/libs/ui/include/ui/Gralloc3.h
index 7367549964..035684abcd 100644
--- a/libs/ui/include/ui/Gralloc3.h
+++ b/libs/ui/include/ui/Gralloc3.h
@@ -82,9 +82,8 @@ public:
std::string dumpDebugInfo(bool less = true) const override;
status_t allocate(std::string requestorName, uint32_t width, uint32_t height,
- PixelFormat format, uint32_t layerCount, uint64_t usage, uint32_t bufferCount,
- uint32_t* outStride, buffer_handle_t* outBufferHandles,
- bool importBuffers = true) const override;
+ PixelFormat format, uint32_t layerCount, uint64_t usage, uint32_t* outStride,
+ buffer_handle_t* outBufferHandles, bool importBuffers = true) const override;
private:
const Gralloc3Mapper& mMapper;
diff --git a/libs/ui/include/ui/Gralloc4.h b/libs/ui/include/ui/Gralloc4.h
index df43be87cd..0f469c0b7e 100644
--- a/libs/ui/include/ui/Gralloc4.h
+++ b/libs/ui/include/ui/Gralloc4.h
@@ -174,9 +174,8 @@ public:
std::string dumpDebugInfo(bool less = true) const override;
status_t allocate(std::string requestorName, uint32_t width, uint32_t height,
- PixelFormat format, uint32_t layerCount, uint64_t usage, uint32_t bufferCount,
- uint32_t* outStride, buffer_handle_t* outBufferHandles,
- bool importBuffers = true) const override;
+ PixelFormat format, uint32_t layerCount, uint64_t usage, uint32_t* outStride,
+ buffer_handle_t* outBufferHandles, bool importBuffers = true) const override;
private:
const Gralloc4Mapper& mMapper;
diff --git a/libs/ui/include/ui/Gralloc5.h b/libs/ui/include/ui/Gralloc5.h
index 44b97d1a6f..f9e8f5e9fd 100644
--- a/libs/ui/include/ui/Gralloc5.h
+++ b/libs/ui/include/ui/Gralloc5.h
@@ -172,10 +172,12 @@ public:
[[nodiscard]] status_t allocate(std::string requestorName, uint32_t width, uint32_t height,
PixelFormat format, uint32_t layerCount, uint64_t usage,
- uint32_t bufferCount, uint32_t *outStride,
- buffer_handle_t *outBufferHandles,
+ uint32_t* outStride, buffer_handle_t* outBufferHandles,
bool importBuffers) const override;
+ [[nodiscard]] GraphicBufferAllocator::AllocationResult allocate(
+ const GraphicBufferAllocator::AllocationRequest&) const override;
+
private:
const Gralloc5Mapper &mMapper;
std::shared_ptr<aidl::android::hardware::graphics::allocator::IAllocator> mAllocator;
diff --git a/libs/ui/include/ui/GraphicBuffer.h b/libs/ui/include/ui/GraphicBuffer.h
index f859848b0c..652d8ba709 100644
--- a/libs/ui/include/ui/GraphicBuffer.h
+++ b/libs/ui/include/ui/GraphicBuffer.h
@@ -26,6 +26,7 @@
#include <android/hardware_buffer.h>
#include <ui/ANativeObjectBase.h>
+#include <ui/GraphicBufferAllocator.h>
#include <ui/GraphicBufferMapper.h>
#include <ui/PixelFormat.h>
#include <ui/Rect.h>
@@ -103,6 +104,8 @@ public:
uint32_t inLayerCount, uint64_t inUsage,
std::string requestorName = "<Unknown>");
+ GraphicBuffer(const GraphicBufferAllocator::AllocationRequest&);
+
// Create a GraphicBuffer from an existing handle.
enum HandleWrapMethod : uint8_t {
// Wrap and use the handle directly. It assumes the handle has been
@@ -169,6 +172,8 @@ public:
mGenerationNumber = generation;
}
+ status_t getDataspace(ui::Dataspace* outDataspace) const;
+
// This function is privileged. It requires access to the allocator
// device or service, which usually involves adding suitable selinux
// rules.
diff --git a/libs/ui/include/ui/GraphicBufferAllocator.h b/libs/ui/include/ui/GraphicBufferAllocator.h
index 3ed988c4c2..8f461e193b 100644
--- a/libs/ui/include/ui/GraphicBufferAllocator.h
+++ b/libs/ui/include/ui/GraphicBufferAllocator.h
@@ -22,6 +22,7 @@
#include <memory>
#include <string>
+#include <vector>
#include <cutils/native_handle.h>
@@ -42,6 +43,35 @@ class GraphicBufferAllocator : public Singleton<GraphicBufferAllocator>
public:
static inline GraphicBufferAllocator& get() { return getInstance(); }
+ struct AdditionalOptions {
+ const char* name;
+ int64_t value;
+ };
+
+ struct AllocationRequest {
+ bool importBuffer;
+ uint32_t width;
+ uint32_t height;
+ PixelFormat format;
+ uint32_t layerCount;
+ uint64_t usage;
+ std::string requestorName;
+ std::vector<AdditionalOptions> extras;
+ };
+
+ struct AllocationResult {
+ status_t status;
+ buffer_handle_t handle = nullptr;
+ uint32_t stride = 0;
+
+ explicit AllocationResult(status_t status) : status(status) {}
+
+ explicit AllocationResult(buffer_handle_t handle, uint32_t stride)
+ : status(OK), handle(handle), stride(stride) {}
+ };
+
+ AllocationResult allocate(const AllocationRequest&);
+
/**
* Allocates and imports a gralloc buffer.
*
diff --git a/libs/ui/include/ui/GraphicBufferMapper.h b/libs/ui/include/ui/GraphicBufferMapper.h
index 3a5167ab25..9da1447aed 100644
--- a/libs/ui/include/ui/GraphicBufferMapper.h
+++ b/libs/ui/include/ui/GraphicBufferMapper.h
@@ -22,9 +22,11 @@
#include <memory>
+#include <android-base/unique_fd.h>
#include <ui/GraphicTypes.h>
#include <ui/PixelFormat.h>
#include <ui/Rect.h>
+#include <ui/Result.h>
#include <utils/Singleton.h>
// Needed by code that still uses the GRALLOC_USAGE_* constants.
@@ -38,6 +40,12 @@ namespace android {
class GrallocMapper;
+/**
+ * This class is a thin wrapper over the various gralloc HALs. It is a "raw" wrapper, having
+ * version-specific behaviors & features. It is not recommend for general use. It is instead
+ * strongly recommended to use AHardwareBuffer or ui::GraphicBuffer which will provide stronger
+ * API compatibility & consistency behaviors.
+ */
class GraphicBufferMapper : public Singleton<GraphicBufferMapper>
{
public:
@@ -66,27 +74,50 @@ public:
void getTransportSize(buffer_handle_t handle,
uint32_t* outTransportNumFds, uint32_t* outTransportNumInts);
- status_t lock(buffer_handle_t handle, uint32_t usage, const Rect& bounds, void** vaddr,
- int32_t* outBytesPerPixel = nullptr, int32_t* outBytesPerStride = nullptr);
+ struct LockResult {
+ void* address = nullptr;
+ /**
+ * Note: bytesPerPixel is only populated if version is gralloc 3
+ * Gralloc 4 & later should use instead getPlaneLayout()
+ */
+ int32_t bytesPerPixel = -1;
+ /**
+ * Note: bytesPerPixel is only populated if version is gralloc 3
+ * Gralloc 4 & later should use instead getPlaneLayout()
+ */
+ int32_t bytesPerStride = -1;
+ };
+
+ ui::Result<LockResult> lock(buffer_handle_t handle, int64_t usage, const Rect& bounds,
+ base::unique_fd&& acquireFence = {});
+
+ ui::Result<android_ycbcr> lockYCbCr(buffer_handle_t handle, int64_t usage, const Rect& bounds,
+ base::unique_fd&& acquireFence = {});
+
+ status_t lock(buffer_handle_t handle, uint32_t usage, const Rect& bounds, void** vaddr);
status_t lockYCbCr(buffer_handle_t handle,
uint32_t usage, const Rect& bounds, android_ycbcr *ycbcr);
- status_t unlock(buffer_handle_t handle);
-
status_t lockAsync(buffer_handle_t handle, uint32_t usage, const Rect& bounds, void** vaddr,
- int fenceFd, int32_t* outBytesPerPixel = nullptr,
- int32_t* outBytesPerStride = nullptr);
+ int fenceFd);
status_t lockAsync(buffer_handle_t handle, uint64_t producerUsage, uint64_t consumerUsage,
- const Rect& bounds, void** vaddr, int fenceFd,
- int32_t* outBytesPerPixel = nullptr, int32_t* outBytesPerStride = nullptr);
+ const Rect& bounds, void** vaddr, int fenceFd);
status_t lockAsyncYCbCr(buffer_handle_t handle,
uint32_t usage, const Rect& bounds, android_ycbcr *ycbcr,
int fenceFd);
- status_t unlockAsync(buffer_handle_t handle, int *fenceFd);
+ status_t unlock(buffer_handle_t handle, base::unique_fd* outFence = nullptr);
+ status_t unlockAsync(buffer_handle_t handle, int* fenceFd) {
+ base::unique_fd temp;
+ status_t result = unlock(handle, fenceFd ? &temp : nullptr);
+ if (fenceFd) {
+ *fenceFd = temp.release();
+ }
+ return result;
+ }
status_t isSupported(uint32_t width, uint32_t height, android::PixelFormat format,
uint32_t layerCount, uint64_t usage, bool* outSupported);
@@ -122,6 +153,7 @@ public:
status_t getChromaSiting(buffer_handle_t bufferHandle, ui::ChromaSiting* outChromaSiting);
status_t getPlaneLayouts(buffer_handle_t bufferHandle,
std::vector<ui::PlaneLayout>* outPlaneLayouts);
+ ui::Result<std::vector<ui::PlaneLayout>> getPlaneLayouts(buffer_handle_t bufferHandle);
status_t getDataspace(buffer_handle_t bufferHandle, ui::Dataspace* outDataspace);
status_t setDataspace(buffer_handle_t bufferHandle, ui::Dataspace dataspace);
status_t getBlendMode(buffer_handle_t bufferHandle, ui::BlendMode* outBlendMode);
diff --git a/libs/ui/include/ui/Result.h b/libs/ui/include/ui/Result.h
new file mode 100644
index 0000000000..d73c3e23b7
--- /dev/null
+++ b/libs/ui/include/ui/Result.h
@@ -0,0 +1,121 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android-base/expected.h>
+#include <utils/Errors.h>
+
+namespace android::ui {
+
+enum class ErrorCode : int32_t {
+ /**
+ * No error.
+ */
+ None = 0,
+ /**
+ * Invalid BufferDescriptor.
+ */
+ BadDescriptor = 1,
+ /**
+ * Invalid buffer handle.
+ */
+ BadBuffer = 2,
+ /**
+ * Invalid HardwareBufferDescription.
+ */
+ BadValue = 3,
+ /**
+ * Resource unavailable.
+ */
+ NoResources = 5,
+ /**
+ * Permanent failure.
+ */
+ Unsupported = 7,
+};
+
+class Error {
+public:
+ Error(ErrorCode err) : mCode(err) {}
+
+ Error(ErrorCode err, std::string&& message) : mCode(err), mMessage(std::move(message)) {}
+ Error(ErrorCode err, const std::string_view& message) : mCode(err), mMessage(message) {}
+
+ static constexpr status_t codeToStatus(ErrorCode code) {
+ switch (code) {
+ case ErrorCode::None:
+ return OK;
+ case ErrorCode::BadDescriptor:
+ return BAD_VALUE;
+ case ErrorCode::BadValue:
+ return BAD_VALUE;
+ case ErrorCode::BadBuffer:
+ return BAD_TYPE;
+ case ErrorCode::NoResources:
+ return NO_MEMORY;
+ case ErrorCode::Unsupported:
+ return INVALID_OPERATION;
+ default:
+ return UNKNOWN_ERROR;
+ }
+ }
+
+ static constexpr ErrorCode statusToCode(status_t status) {
+ switch (status) {
+ case OK:
+ return ErrorCode::None;
+ case BAD_VALUE:
+ return ErrorCode::BadValue;
+ case BAD_TYPE:
+ return ErrorCode::BadBuffer;
+ case NO_MEMORY:
+ return ErrorCode::NoResources;
+ case INVALID_OPERATION:
+ return ErrorCode::Unsupported;
+ default:
+ return ErrorCode::Unsupported;
+ }
+ }
+
+ constexpr status_t asStatus() const { return codeToStatus(mCode); }
+
+ ErrorCode code() const { return mCode; }
+
+ const std::string& message() const { return mMessage; }
+
+ bool operator==(const ErrorCode code) { return mCode == code; }
+
+private:
+ ErrorCode mCode;
+ std::string mMessage;
+};
+
+template <typename T>
+class Result : public base::expected<T, Error> {
+public:
+ using base::expected<T, Error>::expected;
+
+ [[nodiscard]] constexpr status_t asStatus() const {
+ return this->has_value() ? OK : this->error().asStatus();
+ }
+
+ [[nodiscard]] constexpr ErrorCode errorCode() const {
+ return this->has_value() ? ErrorCode::None : this->error().code();
+ }
+};
+
+} // namespace android::ui
diff --git a/libs/ui/tests/Android.bp b/libs/ui/tests/Android.bp
index 8ce017d7a3..2d8a1e326c 100644
--- a/libs/ui/tests/Android.bp
+++ b/libs/ui/tests/Android.bp
@@ -21,6 +21,7 @@ package {
// to get the below license kinds:
// SPDX-license-identifier-Apache-2.0
default_applicable_licenses: ["frameworks_native_libs_ui_license"],
+ default_team: "trendy_team_android_core_graphics_stack",
}
cc_test {
@@ -54,6 +55,17 @@ cc_test {
}
cc_test {
+ name: "DisplayIdentification_test",
+ shared_libs: ["libui"],
+ static_libs: ["libgmock"],
+ srcs: ["DisplayIdentification_test.cpp"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+}
+
+cc_test {
name: "FlattenableHelpers_test",
shared_libs: ["libui"],
srcs: ["FlattenableHelpers_test.cpp"],
diff --git a/libs/ui/tests/GraphicBufferAllocator_test.cpp b/libs/ui/tests/GraphicBufferAllocator_test.cpp
index f4c0afa71b..efca083e6e 100644
--- a/libs/ui/tests/GraphicBufferAllocator_test.cpp
+++ b/libs/ui/tests/GraphicBufferAllocator_test.cpp
@@ -51,7 +51,7 @@ public:
std::cout << "Setting expected stride to " << stride << std::endl;
EXPECT_CALL(*(reinterpret_cast<const mock::MockGrallocAllocator*>(mAllocator.get())),
allocate)
- .WillOnce(DoAll(SetArgPointee<7>(stride), Return(err)));
+ .WillOnce(DoAll(SetArgPointee<6>(stride), Return(err)));
}
std::unique_ptr<const GrallocAllocator>& getAllocator() { return mAllocator; }
};
diff --git a/libs/ui/tests/mock/MockGrallocAllocator.h b/libs/ui/tests/mock/MockGrallocAllocator.h
index d62e3e2192..d02b3873e0 100644
--- a/libs/ui/tests/mock/MockGrallocAllocator.h
+++ b/libs/ui/tests/mock/MockGrallocAllocator.h
@@ -35,7 +35,7 @@ public:
MOCK_METHOD(std::string, dumpDebugInfo, (bool less), (const, override));
MOCK_METHOD(status_t, allocate,
(std::string requestorName, uint32_t width, uint32_t height, PixelFormat format,
- uint32_t layerCount, uint64_t usage, uint32_t bufferCount, uint32_t* outStride,
+ uint32_t layerCount, uint64_t usage, uint32_t* outStride,
buffer_handle_t* outBufferHandles, bool less),
(const, override));
};
diff --git a/libs/ui/tools/Android.bp b/libs/ui/tools/Android.bp
index 5d6070cf95..cc233b917b 100644
--- a/libs/ui/tools/Android.bp
+++ b/libs/ui/tools/Android.bp
@@ -21,6 +21,7 @@ package {
// to get the below license kinds:
// SPDX-license-identifier-Apache-2.0
default_applicable_licenses: ["frameworks_native_libs_ui_license"],
+ default_team: "trendy_team_android_core_graphics_stack",
}
cc_defaults {
diff --git a/libs/vibrator/ExternalVibration.cpp b/libs/vibrator/ExternalVibration.cpp
index 80e911c65d..c97e496083 100644
--- a/libs/vibrator/ExternalVibration.cpp
+++ b/libs/vibrator/ExternalVibration.cpp
@@ -17,7 +17,7 @@
#include <vibrator/ExternalVibration.h>
#include <vibrator/ExternalVibrationUtils.h>
-#include <android/os/IExternalVibratorService.h>
+#include <android/os/ExternalVibrationScale.h>
#include <binder/Parcel.h>
#include <log/log.h>
#include <utils/Errors.h>
@@ -65,24 +65,36 @@ inline bool ExternalVibration::operator==(const ExternalVibration& rhs) const {
return mToken == rhs.mToken;
}
-os::HapticScale ExternalVibration::externalVibrationScaleToHapticScale(int externalVibrationScale) {
- switch (externalVibrationScale) {
- case IExternalVibratorService::SCALE_MUTE:
- return os::HapticScale::MUTE;
- case IExternalVibratorService::SCALE_VERY_LOW:
- return os::HapticScale::VERY_LOW;
- case IExternalVibratorService::SCALE_LOW:
- return os::HapticScale::LOW;
- case IExternalVibratorService::SCALE_NONE:
- return os::HapticScale::NONE;
- case IExternalVibratorService::SCALE_HIGH:
- return os::HapticScale::HIGH;
- case IExternalVibratorService::SCALE_VERY_HIGH:
- return os::HapticScale::VERY_HIGH;
+os::HapticScale ExternalVibration::externalVibrationScaleToHapticScale(
+ os::ExternalVibrationScale externalVibrationScale) {
+ os::HapticLevel scaleLevel = os::HapticLevel::NONE;
+
+ switch (externalVibrationScale.scaleLevel) {
+ case os::ExternalVibrationScale::ScaleLevel::SCALE_MUTE:
+ scaleLevel = os::HapticLevel::MUTE;
+ break;
+ case os::ExternalVibrationScale::ScaleLevel::SCALE_VERY_LOW:
+ scaleLevel = os::HapticLevel::VERY_LOW;
+ break;
+ case os::ExternalVibrationScale::ScaleLevel::SCALE_LOW:
+ scaleLevel = os::HapticLevel::LOW;
+ break;
+ case os::ExternalVibrationScale::ScaleLevel::SCALE_NONE:
+ scaleLevel = os::HapticLevel::NONE;
+ break;
+ case os::ExternalVibrationScale::ScaleLevel::SCALE_HIGH:
+ scaleLevel = os::HapticLevel::HIGH;
+ break;
+ case os::ExternalVibrationScale::ScaleLevel::SCALE_VERY_HIGH:
+ scaleLevel = os::HapticLevel::VERY_HIGH;
+ break;
default:
- ALOGE("Unknown ExternalVibrationScale %d, not applying scaling", externalVibrationScale);
- return os::HapticScale::NONE;
- }
+ ALOGE("Unknown ExternalVibrationScale %d, not applying scaling",
+ externalVibrationScale.scaleLevel);
+ }
+
+ return {/*level=*/scaleLevel, /*adaptiveScaleFactor=*/
+ externalVibrationScale.adaptiveHapticsScale};
}
} // namespace os
diff --git a/libs/vibrator/ExternalVibrationUtils.cpp b/libs/vibrator/ExternalVibrationUtils.cpp
index 980b08ba36..761ac1bf3b 100644
--- a/libs/vibrator/ExternalVibrationUtils.cpp
+++ b/libs/vibrator/ExternalVibrationUtils.cpp
@@ -26,30 +26,30 @@ static constexpr float HAPTIC_SCALE_VERY_LOW_RATIO = 2.0f / 3.0f;
static constexpr float HAPTIC_SCALE_LOW_RATIO = 3.0f / 4.0f;
static constexpr float HAPTIC_MAX_AMPLITUDE_FLOAT = 1.0f;
-float getHapticScaleGamma(HapticScale scale) {
- switch (scale) {
- case HapticScale::VERY_LOW:
+float getHapticScaleGamma(HapticLevel level) {
+ switch (level) {
+ case HapticLevel::VERY_LOW:
return 2.0f;
- case HapticScale::LOW:
+ case HapticLevel::LOW:
return 1.5f;
- case HapticScale::HIGH:
+ case HapticLevel::HIGH:
return 0.5f;
- case HapticScale::VERY_HIGH:
+ case HapticLevel::VERY_HIGH:
return 0.25f;
default:
return 1.0f;
}
}
-float getHapticMaxAmplitudeRatio(HapticScale scale) {
- switch (scale) {
- case HapticScale::VERY_LOW:
+float getHapticMaxAmplitudeRatio(HapticLevel level) {
+ switch (level) {
+ case HapticLevel::VERY_LOW:
return HAPTIC_SCALE_VERY_LOW_RATIO;
- case HapticScale::LOW:
+ case HapticLevel::LOW:
return HAPTIC_SCALE_LOW_RATIO;
- case HapticScale::NONE:
- case HapticScale::HIGH:
- case HapticScale::VERY_HIGH:
+ case HapticLevel::NONE:
+ case HapticLevel::HIGH:
+ case HapticLevel::VERY_HIGH:
return 1.0f;
default:
return 0.0f;
@@ -57,19 +57,28 @@ float getHapticMaxAmplitudeRatio(HapticScale scale) {
}
void applyHapticScale(float* buffer, size_t length, HapticScale scale) {
- if (scale == HapticScale::MUTE) {
+ if (scale.isScaleMute()) {
memset(buffer, 0, length * sizeof(float));
return;
}
- if (scale == HapticScale::NONE) {
+ if (scale.isScaleNone()) {
return;
}
- float gamma = getHapticScaleGamma(scale);
- float maxAmplitudeRatio = getHapticMaxAmplitudeRatio(scale);
+ HapticLevel hapticLevel = scale.getLevel();
+ float adaptiveScaleFactor = scale.getAdaptiveScaleFactor();
+ float gamma = getHapticScaleGamma(hapticLevel);
+ float maxAmplitudeRatio = getHapticMaxAmplitudeRatio(hapticLevel);
+
for (size_t i = 0; i < length; i++) {
- float sign = buffer[i] >= 0 ? 1.0 : -1.0;
- buffer[i] = powf(fabsf(buffer[i] / HAPTIC_MAX_AMPLITUDE_FLOAT), gamma)
- * maxAmplitudeRatio * HAPTIC_MAX_AMPLITUDE_FLOAT * sign;
+ if (hapticLevel != HapticLevel::NONE) {
+ float sign = buffer[i] >= 0 ? 1.0 : -1.0;
+ buffer[i] = powf(fabsf(buffer[i] / HAPTIC_MAX_AMPLITUDE_FLOAT), gamma)
+ * maxAmplitudeRatio * HAPTIC_MAX_AMPLITUDE_FLOAT * sign;
+ }
+
+ if (adaptiveScaleFactor != 1.0f) {
+ buffer[i] *= adaptiveScaleFactor;
+ }
}
}
@@ -89,13 +98,13 @@ void clipHapticData(float* buffer, size_t length, float limit) {
} // namespace
bool isValidHapticScale(HapticScale scale) {
- switch (scale) {
- case HapticScale::MUTE:
- case HapticScale::VERY_LOW:
- case HapticScale::LOW:
- case HapticScale::NONE:
- case HapticScale::HIGH:
- case HapticScale::VERY_HIGH:
+ switch (scale.getLevel()) {
+ case HapticLevel::MUTE:
+ case HapticLevel::VERY_LOW:
+ case HapticLevel::LOW:
+ case HapticLevel::NONE:
+ case HapticLevel::HIGH:
+ case HapticLevel::VERY_HIGH:
return true;
}
return false;
diff --git a/libs/vibrator/include/vibrator/ExternalVibration.h b/libs/vibrator/include/vibrator/ExternalVibration.h
index 00cd3cd256..ac2767e17e 100644
--- a/libs/vibrator/include/vibrator/ExternalVibration.h
+++ b/libs/vibrator/include/vibrator/ExternalVibration.h
@@ -24,6 +24,7 @@
#include <system/audio.h>
#include <utils/RefBase.h>
#include <vibrator/ExternalVibrationUtils.h>
+#include <android/os/ExternalVibrationScale.h>
namespace android {
namespace os {
@@ -45,10 +46,11 @@ public :
audio_attributes_t getAudioAttributes() const { return mAttrs; }
sp<IExternalVibrationController> getController() { return mController; }
- /* Converts the scale from non-public ExternalVibrationService into the HapticScale
+ /* Converts the scale from non-public ExternalVibrationService into the HapticScaleLevel
* used by the utils.
*/
- static os::HapticScale externalVibrationScaleToHapticScale(int externalVibrationScale);
+ static os::HapticScale externalVibrationScaleToHapticScale(
+ os::ExternalVibrationScale externalVibrationScale);
private:
int32_t mUid;
diff --git a/libs/vibrator/include/vibrator/ExternalVibrationUtils.h b/libs/vibrator/include/vibrator/ExternalVibrationUtils.h
index ca219d3cbf..d9a2b81ddf 100644
--- a/libs/vibrator/include/vibrator/ExternalVibrationUtils.h
+++ b/libs/vibrator/include/vibrator/ExternalVibrationUtils.h
@@ -19,7 +19,7 @@
namespace android::os {
-enum class HapticScale {
+enum class HapticLevel {
MUTE = -100,
VERY_LOW = -2,
LOW = -1,
@@ -28,10 +28,41 @@ enum class HapticScale {
VERY_HIGH = 2,
};
+class HapticScale {
+private:
+HapticLevel mLevel = HapticLevel::NONE;
+float mAdaptiveScaleFactor = 1.0f;
+
+public:
+constexpr HapticScale(HapticLevel level, float adaptiveScaleFactor)
+ : mLevel(level), mAdaptiveScaleFactor(adaptiveScaleFactor) {}
+constexpr HapticScale(HapticLevel level) : mLevel(level) {}
+constexpr HapticScale() {}
+
+HapticLevel getLevel() const { return mLevel; }
+float getAdaptiveScaleFactor() const { return mAdaptiveScaleFactor; }
+
+bool operator==(const HapticScale& other) const {
+ return mLevel == other.mLevel && mAdaptiveScaleFactor == other.mAdaptiveScaleFactor;
+}
+
+bool isScaleNone() const {
+ return mLevel == HapticLevel::NONE && mAdaptiveScaleFactor == 1.0f;
+}
+
+bool isScaleMute() const {
+ return mLevel == HapticLevel::MUTE;
+}
+
+static HapticScale mute() {
+ return {/*level=*/os::HapticLevel::MUTE};
+}
+};
+
bool isValidHapticScale(HapticScale scale);
-/* Scales the haptic data in given buffer using the selected HapticScale and ensuring no absolute
- * value will be larger than the absolute of given limit.
+/* Scales the haptic data in given buffer using the selected HapticScaleLevel and ensuring no
+ * absolute value will be larger than the absolute of given limit.
* The limit will be ignored if it is NaN or zero.
*/
void scaleHapticData(float* buffer, size_t length, HapticScale scale, float limit);